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 ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, BaseOfStack
; 省略將軟盤中的Kernel.bin加載到內存中的代碼
;LABEL_FILE_LOADED:
mov dh, 1
call DispStrRealMode
;加載gdtr
lgdt [GdtPtr]
cli;關中斷
in al, 92h
or al,00000010b
out 92h, al
mov eax, cr0
or eax, 1
mov cr0, eax
;進入保護模式
jmp dword SelectorFlatC: (BaseOfLoaderPhyAddr+LABEL_PM_START)
[SECTION .s32]
ALIGN 32
[BITS 32]
LABEL_PM_START:
mov ax, SelectorVideo
mov gs, ax
mov ax, SelectorFlatRW
mov ds, ax
mov es, ax
mov fs, ax
mov ss, ax
mov esp, TopOfStack
push szMemChkTitle
call DispStr
add esp, 4
call DispMemInfo ;打印內存信息
call SetupPaging ;啓動分頁機制
mov ah, 0Fh
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 esi, MemChkBuf
mov ecx, [dwMCRNumber]
.loop:
mov edx, 5;每個地址範圍描述符結構分5個部分,每個部分是32位
mov edi, ARDStruct
.1:
push dword [esi]
call DispInt
pop eax
stosd ;將eax中的內容存到es: edi中,同時edi+4
add esi, 4; //地址範圍的下一個部分
dec edx
cmp edx, 0
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 esp, 4
push dword [dwMemSize]
call DispInt
add esp, 4
pop ecx
pop edi
pop esi