当前位置:   article > 正文

boot/loader.asm_asm booloader

asm booloader
Code:
  1. ;By Marcus Xing   
  2. ;boot/loader.asm   
  3. ;加载原始KERNEL.BIN,在保护模式下分析ELF把各   
  4. ;段转移到对应的虚拟地址上,并把控制权交给KERNEL   
  5.   
  6. org 0100h   
  7.   
  8. %include "pm.inc"   
  9.   
  10. ;-------------------------------------------------------------------------宏信息   
  11.     Base_Of_Loader          equ 9000h   ;加载LOADER的段地址   
  12.     Offset_Of_Loader        equ 0100h   ;加载LOADER的偏移地址   
  13.        
  14.     Base_Of_Kernel          equ 8000h   ;加载KERNEL的段地址   
  15.     Offset_Of_Kernel        equ 0h      ;加载KERNEL的偏移地址   
  16.        
  17.     Base_Of_Page_Dir        equ 200000h ;页目录表的首址   
  18.     Base_Of_Page_Tbl        equ 201000h ;页表的首址   
  19.        
  20.     Base_Of_Loader_Phy_Addr equ Base_Of_Loader * 10h    ;加载LOADER的物理基地址   
  21.     Base_Of_Kernel_Phy_Addr equ Base_Of_Kernel * 10h    ;加载原始KERNEL的物理基地址   
  22.        
  23.     Root_Dir_Begin_Sector   equ 19      ;根目录区的逻辑起始逻辑扇区   
  24.        
  25.     Kernel_Entry_Point_Phy_Addr equ 30400h  ;内核的入口地址   
  26.        
  27. ;-------------------------------------------------------------------CODE_SEGMENT   
  28. [section .code16]   
  29. [bits 16]   
  30. LABEL_START:   
  31.     mov ax,cs   
  32.     mov ds,ax   
  33.     mov ax,3000h   
  34.     mov ss,ax   
  35.     mov sp,0100h       
  36.        
  37.     ;取得内存信息存入缓冲区   
  38.     ;进入保护模式后显示出来   
  39.     ;BIOS int 15h   
  40.     xor ebx,ebx                             ;后续值,不用程序员关注,初始为0   
  41.     mov di,_Memory_Info_Buffer              ;es:di指向缓冲区   
  42.        
  43. .l:   
  44.     mov ecx,20                              ;每个ARDStruct为20字节   
  45.     mov edx,0534d4150h                      ;edx='SMAP'  
  46.     mov eax,0e820h                          ;功能号   
  47.     int 15h   
  48.     jc  .fail                               ;如果CF为1,则出错,置ARDStruct变量为0   
  49.     add di,20                               ;es:di指向下一段缓冲区   
  50.     inc dword   [_d_ARDStruct_Num]          ;ARDStruct变量自增1   
  51.     cmp ebx,0                               ;判断ebx是否为0,为0则读取结束,否则继续读取   
  52.     jne .l   
  53.     jmp .done   
  54.        
  55. .fail:   
  56.     mov dword   [_d_ARDStruct_Num],0   
  57. .done:   
  58.        
  59.     ;回车   
  60.     push    _sz_Return   
  61.     call    Disp_Str_In_Real_Mode   
  62.     add sp,2   
  63.        
  64.     ;显示字符串Loading   
  65.     push    _sz_Loading_Message   
  66.     call    Disp_Str_In_Real_Mode   
  67.     add sp,2   
  68.        
  69.     ;es指向缓冲区的段地址   
  70.     mov ax,Base_Of_Kernel   
  71.     mov es,ax   
  72.        
  73. LABEL_READ_NEXT_SECTOR:   
  74.     mov bx,Offset_Of_Kernel                     ;bx指向缓冲区的偏移地址   
  75.     cmp word [_w_Root_Dir_Search_For_Loop],0    ;比较循环变量是否为0   
  76.     je  LABEL_NO_FOUND                          ;为0代表没找到,跳转到相应的标号处理   
  77.     dec word [_w_Root_Dir_Search_For_Loop]      ;尚未为0,循环变量自减1   
  78.        
  79.     ;读取当前根目录区扇区至缓冲区   
  80.     push    1   
  81.     push    word [_w_Root_Dir_Sector_No]   
  82.     call    Read_Sector   
  83.     add sp,4   
  84.        
  85.     inc word [_w_Root_Dir_Sector_No]            ;定位到下一个根目录扇区,为下一次读做准备   
  86.     mov dx,16                                   ;一个扇区有16个FCB,要循环16次   
  87.        
  88. LABEL_GO_ON_NEXT_DIR_ITEM:   
  89.     cmp dx,0                                    ;判断是否为0   
  90.     je  LABEL_READ_NEXT_SECTOR                  ;为0就读下一个根目录扇区   
  91.     dec dx                                      ;dx自减1   
  92.        
  93.     mov cx,11                                   ;FCB中的文件名字段有11位,故循环变量为11   
  94.     mov si,_s_Name_Of_Kernel                    ;si定位到要比较的字符串偏移处   
  95.        
  96. LABEL_GO_ON_CMP:   
  97.     cmp cx,0                                    ;判断比较计数器是否为0,为0表示比较成功   
  98.     je  LABEL_FOUNDED                           ;即找到KERNEL.BIN,跳转到相应标号处理   
  99.     dec cx                                      ;cx自减1   
  100.        
  101.     mov al,[si]                                 ;ds:si指向比较字符串,赋给al   
  102.     cmp al,[es:bx]                              ;es:bx指向当前FCB的文件名字段,比较两者   
  103.     je  LABEL_CMP_OK                            ;比较成功则进行下一次比较   
  104.     and bx,0ffe0h                               ;不成功则把bx的低5位清零,因为一个FCB为32   
  105.     add bx,32                                   ;字节,再加32则定位到下一个FCB的文件名处   
  106.     jmp LABEL_GO_ON_NEXT_DIR_ITEM               ;跳转,比较下一个FCB   
  107.        
  108. LABEL_CMP_OK:   
  109.     ;两个串的定位器都自增1   
  110.     inc si                                                                                 
  111.     inc bx   
  112.     jmp LABEL_GO_ON_CMP                         ;跳转下一次比较   
  113.        
  114.     ;没找到KERNEL,跳转到这儿,显示完相应信息后死循环   
  115. LABEL_NO_FOUND:    
  116.     push    _sz_No_Kernel_Message   
  117.     call    Disp_Str_In_Real_Mode   
  118.     add sp,2   
  119.     jmp $   
  120.   
  121.     ;找到了KERNEL,跳转到这儿   
  122. LABEL_FOUNDED:   
  123.     and bx,0ffe0h                               ;使es:bx指向找到的KERNEL的FCB的起始处   
  124.     mov cx,[es:bx + 1ah]                        ;取得KERNEL的相对于数据区的偏移扇区号   
  125.                                                 ;注意:2为数据区的第一个扇区   
  126.                                                                                                    
  127.     mov ax,cx                                                                              
  128.     mov bx,Offset_Of_Kernel                     ;es:bx=8000h:0000h,准备读入一个数据扇区   
  129.        
  130. LABEL_GO_ON_LOADING:   
  131.     ;每从数据区读一个扇区则显示一个点   
  132.     push    _sz_Dot   
  133.     call    Disp_Str_In_Real_Mode   
  134.     add sp,2   
  135.   
  136.     add ax,31                                   ;得到要读取的数据扇区的逻辑地址   
  137.        
  138.     ;读一个数据扇区   
  139.     push    1   
  140.     push    ax   
  141.     call    Read_Sector   
  142.     add sp,4   
  143.        
  144.     ;得到当前数据扇区在FAT中的值   
  145.     push    cx   
  146.     call    Get_FAT_Entry   
  147.     add sp,2   
  148.        
  149.     ;判断有没有下一个扇区,有则根据得到的下一个数据相对扇区号继续读   
  150.     ;没有则可以分析KERNEL.BIN的ELF格式了   
  151.     cmp ax,0fffh   
  152.     je  LABEL_START_LOADING   
  153.        
  154.     add bx,512                                  ;定位KERNEL的加载偏移地址   
  155.     mov cx,ax   
  156.     jmp LABEL_GO_ON_LOADING                     ;跳转回去进行相应处理   
  157.        
  158.     ;KERNEL数据全部加载完毕后跳转到此   
  159. LABEL_START_LOADING:   
  160.     ;打印准备信息   
  161.     push    _sz_Ready_Message   
  162.     call    Disp_Str_In_Real_Mode   
  163.     add sp,2   
  164.        
  165.     ;回车   
  166.     push    _sz_Return   
  167.     call    Disp_Str_In_Real_Mode   
  168.     add sp,2   
  169.        
  170.   ;下一步准备跳入保护模式   
  171.      
  172.   call  Kill_Motor                              ;关闭软驱马达   
  173.        
  174.     lgdt    [GDT_Ptr]                           ;加载GDT信息到GDTR   
  175.     cli                                         ;关中断   
  176.        
  177.     ;打开A20,可以寻址到1M开外   
  178.     in  al,92h   
  179.     or  al,00000010b   
  180.     out 92h,al   
  181.        
  182.     ;CR0最低位置1,使CPU处于保护模式   
  183.     mov eax,cr0   
  184.     or  al,1   
  185.     mov cr0,eax   
  186.   
  187.     ;跳转到32位代码段中   
  188.     jmp dword   Selector_Flat_C:(Base_Of_Loader_Phy_Addr + LABEL_SEG_CODE32)   
  189.        
  190. ;--------------------------------------------------------------PM_CODE32_SECTION   
  191. [section .code32]   
  192. [bits 32]   
  193. LABEL_SEG_CODE32:   
  194.        
  195.     ;ds,es,ss,fs都指向4G读写平坦段   
  196.     mov ax,Selector_Flat_RW   
  197.     mov ds,ax   
  198.     mov es,ax   
  199.     mov fs,ax   
  200.        
  201.     ;设置好堆栈,1K空间   
  202.     mov ss,ax   
  203.     mov esp,Stack32_Len   
  204.   
  205.     ;gs指向显存段   
  206.     mov ax,Selector_Video   
  207.     mov gs,ax   
  208.        
  209. ;-------------------------------------------------------------------显示内存信息   
  210.     ;显示内存头信息   
  211.     push    sz_Memory_Info_Title   
  212.     call    Disp_Str   
  213.     add esp,4   
  214.        
  215.     ;回车   
  216.     push    sz_Return   
  217.     call    Disp_Str   
  218.     add esp,4   
  219.        
  220.     mov ecx,[d_ARDStruct_Num]               ;ecx<-ADRStruct个数,控制外层循环   
  221.     mov esi,Memory_Info_Buffer              ;ds:esi指向内存信息缓冲区   
  222.   
  223. .1:   
  224.     mov edx,5                               ;控制内层循环,因为1个ARDStruct有5个字段   
  225.     mov edi,d_Base_Addr_Low                 ;es:edi指向ARDStruct缓冲区   
  226.        
  227. .2:   
  228.     cmp edx,0                               ;判断edx是否为0   
  229.     je  .3                                  ;是的话跳转到.3   
  230.     dec edx    
  231.     lodsd                                   ;eax<-ds:esi,add    esi,4   
  232.     ;显示出来   
  233.     push    eax                                                        
  234.     call    Disp_Int   
  235.     pop eax   
  236.     stosd                                   ;es:edi<-eax,add    edi,4   
  237.     ;打印2个空格   
  238.     call    Disp_Space   
  239.     call    Disp_Space   
  240.     jmp .2                                  ;继续内层循环   
  241.        
  242. .3:   
  243.     cmp dword [d_Type],1                    ;判断类型字段是否为1,即是否可被我们的OS使用   
  244.     jne .4                                  ;不是就跳转到4,显示下一个ARDStruct   
  245.        
  246.     ;判断当前ARDStruct地址范围   
  247.     ;跟当前内存范围大小,当前内存   
  248.     ;范围小则更新之   
  249.     mov eax,[d_Base_Addr_Low]   
  250.     add eax,[d_Length_Low]   
  251.     cmp [d_Memory_Size],eax   
  252.     ja  .3   
  253.     mov [d_Memory_Size],eax   
  254.   
  255. .4:   
  256.     ;回车   
  257.     push    sz_Return   
  258.     call    Disp_Str   
  259.     add esp,4   
  260.     loop    .1                              ;执行外层循环   
  261.        
  262.     ;显示内存范围字符串   
  263.     push    sz_Memory_Size   
  264.     call    Disp_Str   
  265.     add esp,4   
  266.        
  267.     ;显示内存范围数值   
  268.     push    dword [d_Memory_Size]   
  269.     call    Disp_Int   
  270.     add esp,4   
  271.        
  272.     ;回车   
  273.     push    sz_Return   
  274.     call    Disp_Str   
  275.     add esp,4   
  276.        
  277. ;--------------------------------------------------------------分页设置(一一对应)   
  278.     mov eax,[d_Memory_Size]   
  279.     mov ebx,1024 * 1024 * 4                 ;一个页目录项对应4M物理内存   
  280.     div ebx                                 ;eax<-页目录表个数   
  281.     cmp edx,0                                                          
  282.     je  .11   
  283.     inc eax                                 ;余数不为0页目录加1   
  284.        
  285. .11:   
  286.     push    eax                             ;暂存页目录个数   
  287.     mov ecx,eax                             ;循环次数   
  288.     mov eax,Base_Of_Page_Tbl | 1b | 10b | 100b  ;指向页表,每个页目录可读可写,用户级,存在   
  289.     mov edi,Base_Of_Page_Dir                ;es:edi指向页目录表地址   
  290.        
  291. .22:   
  292.     stosd      
  293.     add eax,4096   
  294.     loop    .22   
  295.        
  296.     pop eax                                 ;恢复页目录个数   
  297.     mov ebx,1024                            ;每个页目录项对应1024个页表项   
  298.     mul ebx                                
  299.     mov ecx,eax                             ;ecx<-页目录项个数   
  300.     mov eax,0 | 1b | 10b | 100b             ;一一映射,每个页表项可读可写,用户级,存在   
  301.     mov edi,Base_Of_Page_Tbl                ;es:edi指向页表地址   
  302.        
  303. .33:   
  304.     stosd   
  305.     add eax,4096   
  306.     loop    .33   
  307.        
  308.     ;cr3<-页目录地址   
  309.     mov eax,Base_Of_Page_Dir                           
  310.     mov cr3,eax   
  311.        
  312.     ;置cr0最高位为1,打开分页   
  313.     mov eax,cr0   
  314.     or  eax,80000000h   
  315.     mov cr0,eax   
  316.        
  317. ;------------------------------------------------------把ELF格式的KERNEL读入内存       
  318. ;KERNEL.BIN原始文件位于8000h:0h处   
  319.     mov cx,[Base_Of_Kernel_Phy_Addr + 44]   ;取得PROGRAM HEADER的个数   
  320.     and ecx,0ffffh                          ;ecx高16位清零   
  321.     mov esi,[Base_Of_Kernel_Phy_Addr + 28]  ;取得PROGRAM HEADER TABLE相对文件偏移   
  322.     add esi,Base_Of_Kernel_Phy_Addr         ;ds:esi指向PROGRAM HEADER TABLE的第一项   
  323.        
  324. .s:   
  325.     cmp dword [esi + 0],0                   ;判断当前PROGRAM HEADER的TYPE是否为0   
  326.     je  .next                               ;为0直接跳过处理下一项   
  327.     push    dword [esi + 16]                ;当前PROGRAM HEADER的长度入栈   
  328.     push    dword [esi + 8]                 ;当前PROGRAM HEADER的虚拟地址入栈   
  329.     mov eax,[esi + 4]                                                          
  330.     add eax,Base_Of_Kernel_Phy_Addr         ;eax<-当前PROGRAM HEADER的内容地址   
  331.     push    eax   
  332.     call    Memory_Copy                     ;复制之   
  333.     add esp,12   
  334.        
  335. .next:   
  336.     add esi,32                              ;ds:esi指向下一个项,一个项32字节   
  337.     loop    .s   
  338.   
  339.     push    dword [d_Disp_Pos_In_PM]        ;进入内核前把显示位置入栈供内核使用   
  340.        
  341.     ;********************************************************************   
  342.     jmp Selector_Flat_C:Kernel_Entry_Point_Phy_Addr ;****正式进入内核****   
  343.     ;********************************************************************   
  344.        
  345. ;-------------------------------------------------------------PM_STACK32_SECTION   
  346. [section .stack32]   
  347. [bits 32]   
  348.     times   1024    db  0   
  349. Stack32_Len equ Base_Of_Loader_Phy_Addr + $   
  350.   
  351. ;-------------------------------------------------------------------DATA_SECTION   
  352. LABEL_DATA:   
  353.     _w_Root_Dir_Sector_No       dw  Root_Dir_Begin_Sector       ;根目录区起始逻辑扇区   
  354.     _w_Root_Dir_Search_For_Loop dw  14                          ;找LOADER循环次数,就   
  355.                                                                                                                     ;是根目录区扇区个数   
  356.                                                                                                                        
  357.     _b_Is_Odd                       db  0                       ;FAT ENTRY逻辑地址的奇或偶   
  358.     _w_Disp_Pos_In_RM               dw  0                       ;实模式显示地址   
  359.     _d_Disp_Pos_In_PM               dd  320                     ;保护模式显示地址,从第3行开始   
  360.        
  361.        
  362.     ;一些用到的串   
  363.     _sz_Loading_Message             db  'Loading',0                        
  364.     _sz_Ready_Message               db  'Ready',0   
  365.     _sz_No_Kernel_Message           db  'No Kernel',0   
  366.     _sz_Dot                         db  '.',0   
  367.     _sz_Return                      db  0ah,0   
  368.     _sz_Space                       db  20h,0   
  369.     _sz_PM_Message                  db  'HELLO!',0   
  370.   
  371.     _s_Name_Of_Kernel               db  'KERNEL  BIN'   
  372.     _sz_Memory_Info_Title           db  'BaseAddrL  BaseAddrH  LengthLow  LengthHigh  Type',0   
  373.     _sz_Memory_Size                 db  'Memory Size:',0   
  374.        
  375.     _Memory_Info_Buffer:            ;内存信息缓冲区,能存放12个ARDStruct,   
  376.         times   256 db  0           ;如果内存太大可能不够用                                                   
  377.                                            
  378.     _d_ARDStruct_Num                dd  0       ;ARDStruct的个数   
  379.        
  380.     ;一个ARDStructd的缓冲区   
  381.     _d_Base_Addr_Low                dd  0       ;基址低32位   
  382.     _d_Base_Addr_High               dd  0       ;基址高32位   
  383.     _d_Length_Low                   dd  0       ;长度低32位   
  384.     _d_Length_High                  dd  0       ;长度高32位   
  385.     _d_Type                         dd  0       ;类型   
  386.        
  387.     _d_Memory_Size                  dd  0       ;可用内存长度   
  388.        
  389.        
  390.     ;保护模式下用到得标号(偏移)   
  391.     d_Disp_Pos_In_PM                equ Base_Of_Loader_Phy_Addr + _d_Disp_Pos_In_PM   
  392.     sz_PM_Message                   equ Base_Of_Loader_Phy_Addr + _sz_PM_Message   
  393.     sz_Return                       equ Base_Of_Loader_Phy_Addr + _sz_Return   
  394.     sz_Space                        equ Base_Of_Loader_Phy_Addr + _sz_Space   
  395.     sz_Memory_Info_Title            equ Base_Of_Loader_Phy_Addr + _sz_Memory_Info_Title   
  396.     sz_Memory_Size                  equ Base_Of_Loader_Phy_Addr + _sz_Memory_Size   
  397.        
  398.     Memory_Info_Buffer              equ Base_Of_Loader_Phy_Addr + _Memory_Info_Buffer   
  399.        
  400.     d_ARDStruct_Num                 equ Base_Of_Loader_Phy_Addr + _d_ARDStruct_Num   
  401.     d_Base_Addr_Low                 equ Base_Of_Loader_Phy_Addr + _d_Base_Addr_Low   
  402.     d_Base_Addr_High                equ Base_Of_Loader_Phy_Addr + _d_Base_Addr_High   
  403.     d_Length_Low                    equ Base_Of_Loader_Phy_Addr + _d_Length_Low   
  404.     d_Length_High                   equ Base_Of_Loader_Phy_Addr + _d_Length_High   
  405.     d_Type                          equ Base_Of_Loader_Phy_Addr + _d_Type   
  406.     d_Memory_Size                   equ Base_Of_Loader_Phy_Addr + _d_Memory_Size   
  407.   
  408. ;----------------------------------------------------------------------------GDT   
  409. [section .gdt]   
  410. ;GDT开始   
  411. LABEL_GDT:   
  412. LABEL_DESC_DUMMY:   
  413.     Descriptor  0,0,0   
  414. LABEL_DESC_FLAT_RW:   
  415.     Descriptor  0,0fffffh,DA_DRW + DA_32 + DA_LIMIT_4K      ;读写4G平坦段   
  416. LABEL_DESC_FLAT_C:   
  417.     Descriptor  0,0fffffh,DA_CR + DA_32 + DA_LIMIT_4K       ;4G可执行段   
  418. LABEL_DESC_VIDEO:   
  419.     Descriptor  0b8000h,0ffffh,DA_DRW   + DA_DPL3           ;指向显存首址段,DPL为3   
  420.                                                             ;为之后的进程准备   
  421.        
  422. ;选择子   
  423.     Selector_Flat_RW    equ LABEL_DESC_FLAT_RW - LABEL_GDT   
  424.     Selector_Flat_C     equ LABEL_DESC_FLAT_C  - LABEL_GDT   
  425.     Selector_Video      equ LABEL_DESC_VIDEO - LABEL_GDT + SA_RPL3   
  426.     ;RPL为3,为之后的进程准备   
  427.        
  428. GDT_Len equ $ - LABEL_GDT           ;GDT长度宏   
  429.   
  430. GDT_Ptr:                            ;准备加载进GDTR的6字节数据结构   
  431.     dw  GDT_Len - 1   
  432.     dd  Base_Of_Loader_Phy_Addr + LABEL_GDT   
  433.   
  434. ;------------------------------------------------------------lib_in_protect_mode   
  435. [section .lib_in_protect_mode]   
  436. [bits 32]   
  437.     %include "lib_in_protect_mode.inc"   
  438.   
  439. ;---------------------------------------------------------------lib_in_real_mode   
  440. [section .lib_in_real_mode]   
  441. [bits 16]   
  442.     %include "lib_in_real_mode.inc"  
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/346632
推荐阅读
相关标签
  

闽ICP备14008679号