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