从开机加电到main函数执行(1)
启动BIOS,准备中断
BIOS的任务是将硬盘中的操作系统加载到内存中。
BIOS加载中断处理程序
BIOS的启动由硬件完成。8086系列在加电时进入16位实模式,将CS置为0xFFFF,IP置为0x0000, CS:IP指向0xFFFF0,指向了BIOS对应的地址。
CS是代码段寄存器,IP是指令指针寄存器,两者组合形成的地址是要执行的指令的内存地址,在实模式下是绝对地址
如果这个位置没有可执行代码会就此死机。有代码的话就会执行。BIOS会执行自检程序,检查显卡、内存,并建立中断向量表和中断服务程序。
BIOS在内存最开始的地方建立中断向量表(0x00000~0x003ff),在下面的256字节的内存构建BIOS数据区(0x00400~0x004FF),在56KB之后的内存中加载8KB左右的中断向量表对应的中断服务程序。
中断向量表中一共有256个中断向量,每个中断向量4个字节,每个中断向量对应一个中断处理程序。
加载内核程序
下面要进行的boot操作是把操作系统加载到内存,对于Linux而言,分三次将操作系统加载到内存中,第一批由BIOS中断int服务加载操作系统的bootsect,第二批和第三批由bootsect加载。
第一批bootsect
BIOS结束自检之后,执行一个int中断,对应启动加载服务程序。任务是找到硬盘并加载第一扇区,拷贝到0x07c00处。这个扇区中的内容是bootsect.s。
第二批setup
bootsect首先做的工作是规划内存。在实模式下,最大寻址空间是1MB,bootsect设计了如下的分布:
名字 | 含义 | 地址 |
---|---|---|
SETUPLEN | setup程序的扇区数 | 4 |
BOOTSEG | 启动扇区被BIOS加载的位置 | 0x07c0 |
INITSEG | 将要移动到的新位置 | 0x9000 |
SETUPSEG | setup程序加载到的位置 | 0x9020 |
SYSSEG | 内核加载的位置 | 0x1000 |
ENDSEG | 内核的末尾位置 |
接下来,bootsect会将他自身(512B内容)从BOOTSEG位置复制到INITSEG位置。复制之后CS从BOOTSEG位置跳转到INITSEG位置。
然后bootsect初始化寄存器,将数据段寄存器(DS),附加段寄存器(ES),栈基址寄存器(SS)设置成CS的位置,将栈顶sp指向0xFF00处,如下图:
下面,bootsec程序将setup加载到内存中。
第三批system
由bootsect模块将系统模块载入内存,加载的扇区大小是240,加载到SYSSEG后面。
最后加载完成之后确定根设备号,将根设备号保存在root_dev中。
根文件系统设备:文件系统管理方式。要求系统有一个根文件系统,其他文件挂载在根文件上。Linux的启动需要两部分数据,内核镜像和根文件系统。(格式化好的设备)
bootsect的任务到此结束。下面进行setup程序。
setup的第一件事情是利用BIOS的中断服务从设备上提取及其系统数据,包括光标位置和显示页面等数据,并从0x41和0x46两个向量的内存地址处获得硬盘参数表,将这些数据加载到0x90000~0x901FC