操作系统实践之加载程序

来源:互联网 发布:linux压缩文件命令 zip 编辑:程序博客网 时间:2024/05/24 00:49

 Loader程序主要作用是加载Kernel.bin到内存中,这一步与引导程序加载Loader.bin进入内存是类似的,Kernel.bin是在Linux下编译的,是ELF格式的。因此,Kernel.bin加载内存后,需要将其中的代码段拷贝到

相应的位置,这个位置由Kernel.bin编译时指令的入口地址决定,这些是由InitKernel完成的。Loader还做了一些事情,就是设置GDT,进入保护模式,启动分页机制,在这些事情完成后将控制权交给Kernel,Kernel程序在执行时已经处于保护模式下了。Loader的部分源代码如下:

org  0100h            
BaseOfStack equ    0100h    
jmp short LABEL_START
nop
%include "fat12hdr.inc"
%include "pm.inc"
%include "load.inc"
LABEL_GDT: Descriptor 0, 0, 0
LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW|DA_DPL3//显存地址空间
LABEL_DESC_FLAT_C: Descriptor 0, 0fffffh, DA_C+DA_32+DA_LIMIT_4K
LABEL_DESC_FLAT_RW: Descriptor 0, 0fffffh, DA_DRW+DA_32+DA_LIMIT_4K

GdtLen equ LABEL_GDT;GDT长度
GdtPtr dw GdtLen 1
       dd BaseOfLoaderPhyAddr LABEL_GDT ;//GDT物理地址

;GDT选择子 
SelectorVideo equ  LABEL_DESC_VIDEO LABEL_GDT+SA_RPL3;显存选择子
SelectorFlatC equ LABEL_DESC_FLAT_C LABEL_GDT;
SelectorFlatRW equ LABEL_DESC_FLAT_RW LABEL_GDT;
;Loader入口
LABEL_START:
mov axcs
mov dsax
mov esax
mov ssax
mov spBaseOfStack


; 省略将软盘中的Kernel.bin加载到内存中的代码
;LABEL_FILE_LOADED:
  mov dh1
  call DispStrRealMode
  ;加载gdtr
  lgdt [GdtPtr]
  cli;关中断
  in al92h
  or al,00000010b
  out 92h, al
  mov eaxcr0
  or eax1
  mov cr0eax
  ;进入保护模式
  jmp dword SelectorFlatC: (BaseOfLoaderPhyAddr+LABEL_PM_START)

[SECTION .s32]
ALIGN 32
[BITS 32]
LABEL_PM_START:
  mov axSelectorVideo
  mov gsax
  mov axSelectorFlatRW
  mov dsax
  mov esax
  mov fsax
  mov ssax
  mov espTopOfStack
  
  push szMemChkTitle
  call DispStr
  add  esp4
  call DispMemInfo ;打印内存信息
  call SetupPaging ;启动分页机制
   
  mov ah0Fh
  mov al'P'
  mov [gs:((80*0 39)*2)], ax
  
  call InitKernel;重新放置内核代码
  jmp SelectorFlatC: KernelEntryPointPhyAddr

%include    "lib.inc"

;打印内存信息,现在处于保护模式下
DispMemInfo:
  push esi
  push edi
  push ecx
  mov esiMemChkBuf
  mov ecx[dwMCRNumber]
.loop:
  mov edx5;每个地址范围描述符结构分5个部分,每个部分是32位
  mov ediARDStruct
.1:
  push dword [esi]
  call DispInt
  pop eax
  stosd ;将eax中的内容存到es: edi中,同时edi+4
  add esi4//地址范围的下一个部分
  dec edx
  cmp edx0
  jne .1
  call DispReturn回车
  cmp dword [dwType], 1
  jne .2
  mov eax[dwBaseAddrLow]
  add eax[dwLengthLow]
  cmp eax[dwMemSize]
  jb .2
  mov [dwMemSize], eax ;可用的最大内存范围
.2:
  loop .loop 
  call DispReturn
  push szRAMSize
  call DispStr
  add esp4
  push dword [dwMemSize]
  call DispInt
  add esp4
  pop ecx
  pop edi
  pop esi
  ret

;启动分页机制,并设置页目录表和页表的内容
SetupPaging:
  ;根据内存大小计算需要多少PDE和页表
  xor edxedx
  mov eax[dwMemSize]
  mov ebx400000h
  div ebx
  mov ecxeax
  test edxedx
  jz .no_remainder
  inc ecx
.no_remainder:
  mov [PageTableNumber], ecx;暂存页表个数
  push szPageTableCount
  call DispStr
  add esp4
  push ecx
  call DispInt
  add esp4
  Call DispReturn
  ;设置页目录表的内容
  mov axSelectorFlatRW
  mov esax
  mov ediPageDirBase
  xor eaxeax
  mov eaxPageTblBase|PG_P|PG_USU|PG_RWW
 .1:
  stosd
  add eax4096
  loop .1;
  ;设置页表的内容
  mov eax[PageTableNumber];页面个数
  mov ebx1024
  mul ebx ;页表项的个数
  mov ecxeax
  mov ediPageTblBase
  xor eaxeax
  mov eaxPG_P|PG_USU|PG_RWW
 .2:
  stosd
  add eax4096
  loop .2
  ;设置cr3
  mov eaxPageDirBase
  mov cr3eax
  ;设置cr0的PG位
  mov eaxcr0
  or eax80000000h
  mov cr0eax
  ret
;将Kernel.bin中的代码拷贝到需要的位置,
;这个位置由Kernel.bin编译时指令的入口
;地址决定
InitKernel:
  xor esiesi
  mov cxword [BaseOfKernelFilePhyAddr+2Ch];Program Header Table的条目个数
  movzx ecxcx
  mov esi[BaseOfKernelFilePhyAddr 1Ch];
  add esiBaseOfKernelFilePhyAddr;Program Header Table的内存地址
.Begin:
  mov eax[esi 0]
  cmp eax0
  jz .NoAction
  push dword [esi 010h];size
  mov eax[esi 04h];程序段在文件中的偏移
  add eaxBaseOfKernelFilePhyAddr;加上Kernel.bin的起始地址
  push eax ;src
  push dword [esi+08h];程序段在虚拟地址空间中的地址,dst 
  call MemCpy
  add esp12 ;清理堆栈
.NoAction:
  add esi020h ;20h是Program Header Table每个条目的大小
  dec ecx
  jnz .Begin
  ret
;堆栈空间
[SECTION .data1]
ALIGN 32
LABEL_DATA:
实模式下使用这些符号
字符串
_szMemChkTitle:            db    "BaseAddrL BaseAddrH LengthLow LengthHigh   Type"0Ah, 0
_szRAMSize:            db    "RAM size:"0
_szReturn:            db    0Ah, 0
;; 变量
_dwMCRNumber:            dd       Memory Check Result
_dwDispPos:            dd    (80 0)    屏幕第 行, 第 列。
_dwMemSize:            dd    0
_ARDStruct:            Address Range Descriptor Structure
    _dwBaseAddrLow:        dd    0
    _dwBaseAddrHigh:    dd    0
    _dwLengthLow:        dd    0
    _dwLengthHigh:        dd    0
    _dwType:        dd    0
_szPageTableCount:              db     "PageTableCount:";页表个数,即页目录表的项数
_PageTableNumber        dd    0
_MemChkBuf:    times    256    db    0
;
;; 保护模式下使用这些符号
szMemChkTitle        equ    BaseOfLoaderPhyAddr _szMemChkTitle
szRAMSize        equ    BaseOfLoaderPhyAddr _szRAMSize
szReturn        equ    BaseOfLoaderPhyAddr _szReturn
dwDispPos        equ    BaseOfLoaderPhyAddr _dwDispPos
dwMemSize        equ    BaseOfLoaderPhyAddr _dwMemSize
dwMCRNumber        equ    BaseOfLoaderPhyAddr _dwMCRNumber
ARDStruct        equ    BaseOfLoaderPhyAddr _ARDStruct
    dwBaseAddrLow    equ    BaseOfLoaderPhyAddr _dwBaseAddrLow
    dwBaseAddrHigh    equ    BaseOfLoaderPhyAddr _dwBaseAddrHigh
    dwLengthLow    equ    BaseOfLoaderPhyAddr _dwLengthLow
    dwLengthHigh    equ    BaseOfLoaderPhyAddr _dwLengthHigh
    dwType        equ    BaseOfLoaderPhyAddr _dwType
szPageTableCount        equ     BaseOfLoaderPhyAddr _szPageTableCount
PageTableNumber         equ     BaseOfLoaderPhyAddr _PageTableNumber
MemChkBuf        equ    BaseOfLoaderPhyAddr _MemChkBuf
StackSpace: times 1024 db 0
TopOfStack equ BaseOfLoaderPhyAddr 

0 0
原创粉丝点击