将之前的记得东西重新整理成笔记,去年10月份梳理了物理内存管理和虚拟内存管理。
1、CPU加电
CPU加电后,初始化CS与IP寄存器为约定的值,CS为0xf000,IP为0xfff0。为了兼容8086,此时CPU处于16位的实模式,所以寄存器为16位,通过代码段寄存器CS和指令指针寄存器IP,计算PC的值,计算方法为PC = CS<<4 +IP,这是一个20位的地址,所以实模式下CPU的寻址空间为1MB,计算得到的PC = 0xFFFF0,这就是CPU执行的第一条指令,该指令是一个长跳转指令,jmp F000:E05B,跳转到BIOS程序起始点,实际地址是Base+EIP = FFFF0000 + 0000FFF0 = FFFFFFF0。
2、BIOS
1、BIOS首先进行硬件自检
2、读取主引导记录(MBR)。当BIOS检查到硬件正常并与CMOS中的设置相符后,按照CMOS中对启动设备的设置顺序检测可用的启动设备。BIOS将相应启动设备的第一个扇区(主引导扇区)读入内存地址为0000:7C00H处。
3、BIOS检查MBR扇区的结束标志是不是0x55AA,若满足要求,则移交控制权给MBR。
系统的启动规范:
BIOS:BIOS-MBR、BIOS-GPT(全局唯一标识分区表)、PXE
UEFI:统一可扩展固件接口,比BIOS加入了堆引导记录的可信性进行了检查等
BIOS功能:(Basic Input Output System,即基本输入/输出系统)固话在主板上的程序
以中断调用的方式实现基本的I/O功能。
INT 10h:字符显示
INT 13h:磁盘扇区读写
INT 15h:检测内存大小
INT 16h;磁盘输入
(在intel的CPU中,BIOS只能在x86的实模式下工作)
Q1:为什么不在BIOS中直接加载操作系统?
磁盘存在文件系统,BIOS不可能识别所有文件系统,所以BIOS不管磁盘的文件系统的类型,直接从磁盘的第一个扇区读取加载程序,用加载程序识别磁盘的文件系统类型,将操作系统加载进内存
3、MBR主引导记录
MBR将自己复制到0000:0600H处,然后执行446字节(一共512字节)的启动代码
扫描磁盘分区表DPT,查找活动分区;
寻找活动分区的引导扇区;
将活动分区的引导扇区读到内存;
执行引导扇区的运行代码
主引导扇区位于整个硬盘的0磁头0柱面1扇区,包含主引导记录MBR、磁盘分区表DPT。
MBR作用:
检查DPT是否正确
确定哪个分区为引导扇区
将bootload载入内存
4、活动分区的引导扇区
活动分区的引导扇区第一条是跳转指令,跳转到引导代码,执行加载程序
(活动分区是指磁盘主分区的一种状态。标记分区为活动分区的目的是为了让操作系统由该区启动,所以通常将含有操作系统的分区标记为活动分区)
5、bootloader
1、开启A20
2、初始化GDT
3、使能保护模式(分段机制在保护模式下自动使能)
4、读取配置文件,从硬盘上读取kernel,并放到内存中的固定位置
5、跳转到kernel的入口点entry point执行
6、开启A20地址线
在i8086时代,CPU的地址总线为16位,数据总线为20位,最大寻址空间为1MB,但是到了i80286/i80386,CPU的地址总线变成了32位,寻址空间为4GB,但是为了兼容i8086,CPU在加电启动时仍然是20位寻址,此时为实模式,CPU通过A20地址线模块,在实模式下将第20位的地址线限制为0,这样CPU就不能访问超过1MB的空间了。bootloader要从实模式切换到保护模式,获得更大的寻址空间,就要开启A20地址线,获得高位地址线。事实上,A20就是第21根线,用来控制是否允许对 0x10FFEF 以上的实际内存寻址。称为A20 Gate。
7、初始化GDT(全局描述符表)
使能了A20地址线,有了更大的内存空间,就需要开启分段式内存管理。GDT表由bootloader创建,每一项为段描述符,段描述符中描述了该段的起始地址base和大小limit等数据。在没有启动页机制的情况下,线性地址等于物理地址
到了分段式内存,对内存的访问就需要知道在哪个段,以及偏移量。CS、SS等段寄存器保存的有段选择子,段选择子包含了该段在GDT中的下标,进而找到该段对应的段描述符,通过base加上偏移进行寻址。
8、使能保护模式
开启A20、初始化GDT后,需要使能保护模式,将CR0寄存器的PE位(bit0)置为1即可使能保护模式。
1 | movl %cr0, %eax |
9
进入保护模式,段寄存器CS 、DS、 ES、 FS、 GS、 SS 可见部分是16位,为段选择子,剩下80位不可见,来自GDT,CPU从通过段选择子从 GDT 表中取出对应的段描述符,经过分析后自动的填写的了段寄存器中。
描述符表有两个,全局描述符表GDT和局部描述符表LDT,GDT是一个段描述符数组,每个段描述符占8个字节,GDT的地址保存在GDTR寄存器中