打开电源,计算机执行的第一条指令是什么
对于 X86 PC
来说,执行以下几步:
- X86 PC刚开机时 CPU处于实模式
- 开机时,CS =
0xFFFF
; IP =0x0000
- 寻址
0xFFFF0
(ROM BIOS映射区) - 检查ROM, 键盘,显示器,软硬磁盘
- 将磁道0磁道0扇区读入
0x7cc处
- 设置 cs =
0x07c0
, ip =0x0000
0x7c00处存放的代码:
- 就是从磁盘引导扇区(0磁道0扇区)读入的512个字节
- 引导扇区就是启动设备的第一个扇区
- 启动设备信息被设置在
CMOS
(用来存储时钟和硬件配置信息)中 - 磁盘第一个扇区上存放着开机后执行的第一段我们可以控制的程序
主引导扇区代码(bootstrap)
首先将 0x7c0:0x000处的512个字节的内容移动到0x9000:0x0000处,然后跳转到go标号处继续执行;
jmpi go, INITSEG
读入setup模块后: ok_load_setup
read_it //读入system模块
这里boot扇区代码的执行完毕了,开始setup的四个扇区代码的执行
setup模块的执行
setup模块,即setup.s
用来读取内存等信息,便于后续操作系统建立数据结构进行管理
将system模块移动到零地址处
初始化GDT表
- 建立一个GDT表,进行初始化,便于保护模式的地址转换
保护模式下地址翻译和中断处理
- 此时的CS叫做选择子
将CPU切换到保护模式
1 | mov ax, #0x0001 |
这两行代码切换到保护模式
CX=8进行查表
总结setup做了什么
- 读取硬件参数,为了建立操作系统打下基础
- 将system模块挪动到0地址处,将来操作系统核心代码一直存在那里
- 启动了保护模式
- 运用32位汇编指令
jmpl 0, 8
跳转到0x0000
处地址执行
system模块执行
- system模块(目标代码)中的第一部分代码? head.s
- system模块由很多文件编译而成,为什么是
head.s
?
makefile文件如下
编译出来后顺序:bootstrap -> setup -> head.s -> main.c -> ….
head.s
一段在保护模式下运行的代码
- 又一次初始化了
gdt
表和idt
表(之前是临时建立的gdt
表为了执行jmpi 0, 8
)- 开启20号地址线,可以访问4G内存了
- 设置系统栈
- ……
三种汇编
after_page_tables(设置了页表之后)
看了这段太巧妙了叭,模拟函数调用原理,正常函数调用时候,会先将参数从后往前依次入栈,然后将下一条指令的地址入栈,当
ret
返回时,直接进入之前下一条指令的地址。当set_paging
结束时直接跳转到main函数
执行,如果main
函数意外返回,将进入L6
处执行死循环。