实验内容
完成一个能够切换到x86的保护模式并显示字符的bootloader
注意事项
Bootloader可以让CPU进入保护模式, 读磁盘并加载ELF执行文件格式, 并显示字符
OS只是一个可以处理时钟中断和显示字符的幼儿园级别OS
重点
连续内存的管理
中断的管理
练习1
一个被系统认为是符合规范的硬盘主引导扇区的特征是什么?
tools/sign.c
中完成了特征的标记
1 | // tools/sign.c |
练习2
- lab1-mon
lab1_result的Makefile中:
1 | lab1-mon: $(UCOREIMG) |
- lab1init
lab1init内容(gdb可以识别的一些命令)
1 | file bin/kernel |
说明:
- lab1init中是gdb能识别的一些命令
- 第一条指令: 加载bin/kernel
- 第二条指令: 与qemu通过TRP连接
- 最后一条指令打印指令指针寄存器(pc/eip)的内容(当前正在执行的指令的地址)
计算机启动流程(从计算机上电到进入ucore)
计算机上电, 运行第一条长跳转指令(CS和EIP都会更新)到BIOS代码中执行
BIOS执行其功能, 同时加载存储设备的第一个扇区的512字节到内存的0x7c00处, 然后跳转到这里开始执行
bootloader关闭中断, 清除方向标志, 确保内存地址由小到大增加
ds, es, ss 段寄存器置零
准备开启A20, 首先等待8042键盘控制器不忙(检查0x64端口或P2端口), 写入0xd1; 再次等待不忙, 写入0xdf到0x60端口; 由此完成了打开A20的操作
初始化gdt表, gdt表在这512个字节中的24个字节, 一共3个表项
将cr0就寄存器PE位(即最低位)置1, 从而进入保护模式
通过一个长跳转(段间跳转), 更新cs的基地址, 同时进入32位保护模式的代码部分
将保护模式下的数据段选择子, 放入ds, es, fs, gs, ss 段寄存器
设置ebp和esp寄存器初值
进入bootmain函数(进入c代码部分)
读取存储设备的八个扇区(8个512字节), 到内存中, 读取elf文件的头部
检查elf头部的幻数, 验证elf文件是否合法
读取elf头部的描述表(描述了elf文件应加载到内存什么位置)
按照描述表将elf文件中数据载入内存
根据elf头部存储的入口信息, 找到内核入口, 并进入
BIOS的向后兼容
Intel的CPU具有很好的向后兼容性。在16位的8086 CPU时代,内存限制在1MB范围内,且BIOS的代码固化在EPROM中。在基于Intel的8086 CPU的PC机中的EPROM被编址在1MB内存地址空间的最高64KB中。PC加电后,CS寄存器初始化为0xF000,IP寄存器初始化为0xFFF0,所以CPU要执行的第一条指令的地址为CS:IP=0xF000:0XFFF0(Segment:Offset 表示)=0xFFFF0(Linear表示)。这个地址位于被固化EPROM中,指令是一个长跳转指令JMP F000:E05B。这样就开启了BIOS的执行过程。
到了32位的80386 CPU时代,内存空间扩大到了4G,多了段机制和页机制,但Intel依然很好地保证了80386向后兼容8086。地址空间的变化导致无法直接采用8086的启动约定。如果把BIOS启动固件编址在0xF000起始的64KB内存地址空间内,就会把整个物理内存地址空间隔离成不连续的两段,一段是0xF000以前的地址,一段是1MB以后的地址,这很不协调。为此,intel采用了一个折中的方案:默认将执行BIOS ROM编址在32位内存地址空间的最高端,即位于4GB地址的最后一个64KB内。在PC系统开机复位时,CPU进入实模式,并将CS寄存器设置成0xF000,将它的shadow register的Base值初始化设置为0xFFFF0000,EIP寄存器初始化设置为0x0000FFF0。所以机器执行的第一条指令的物理地址是0xFFFFFFF0。80386的BIOS代码也要和以前8086的BIOS代码兼容,故地址0xFFFFFFF0处的指令还是一条长跳转指令
jmp F000:E05B
。注意,这个长跳转指令会触发更新CS寄存器和它的shadow register,即执行jmp F000 : E05B
后,CS将被更新成0xF000。表面上看CS其实没有变化,但CS的shadow register被更新为另外一个值了,它的Base域被更新成0x000F0000,此时形成的物理地址为Base+EIP=0x000FE05B,这就是CPU执行的第二条指令的地址。此时这条指令的地址已经是1M以内了,且此地址不再位于BIOS ROM中,而是位于RAM空间中。由于Intel设计了一种映射机制,将内存高端的BIOS ROM映射到1MB以内的RAM空间里,并且可以使这一段被映射的RAM空间具有与ROM类似的只读属性。所以PC机启动时将开启这种映射机制,让4GB地址空间的最高一个64KB的内容等同于1MB地址空间的最高一个64K的内容,从而使得执行了长跳转指令后,其实是回到了早期的8086 CPU初始化控制流,保证了向下兼容。
BIOS中A20的设置
参考https://zhidao.baidu.com/question/24524472.html