bootloader主要做四件事,1.开启A20地址线;2.探测内存,把内存相关信息告诉内核;3.初始化全局描述符表,开启分段机制,进入保护模式;4.把操作系统内核从磁盘加载到内存指定位置,跳转到内核,执行内核代码。
1.开启A20地址线,把内存寻址扩展到4GB。
enable20.1:
inb $0x64, %al
testb $0x2, %al
jnz enable20.1
movb $0xd1, %al
outb %al, $0x64
enable20.2:
inb $0x64, %al
testb $0x2, %al
jnz enable20.2
movb $0xdf, %al
2.探测内存,主要就是获取内存大小,和类型,比如是否可用,保留等,下面给出bios 0x15中断获取内存信息,命令字0xe820.
movl $0, 0x6000
xorl %ebx, %ebx
movw $0x6004, %di
start_probe:
movl $0xE820, %eax
movl $20, %ecx
movl $0x534d4150, %edx
int $0x15
jnc cont
movw $12345, 0x6000
jmp finish_probe
cont:
addw $20, %di
incl 0x6000
cmpl $0, %ebx
jnz start_probe
3.初始化全局描述符表,开启保护模式,这个阶段要进入32位模式,主要开启了分段机制,保护模式下的分段机制是,虚拟地址通过分段机制转换为线性地址,如果没开启分页模式则线性地址就是物理地址,这里使用了对等映射,也就是段基址是0,则虚拟地址就是线性地址也就是物理地址。分段寻址模式,(1)指令寻址: cs寄存器包含了当前段在全局描述符表中的偏移和rpl请求特权级,通过cs找到段描述符,从段描述符取出基地址+ip寄存器的偏移量,得到线性地址。(2)数据寻址:通过ds ss es寄存器找到全局描述符表中的段描述符,然后拼接地址。
伪代码:
lgdt gdtr寄存器的内容地址 //装载gdtr寄存器
movl %cr0, %eax
orl $0x1, %eax //把cr0寄存其的第0位置1,开启分段机制,进入保护模式
movl %eax, %cr0
4.从磁盘读取内核,加载到内存,跳转到内核,至此bootloader阶段完成,内核开始接管计算机