Linux0.11源码阅读
1. 进入操作系统内核
1. 流程
1. 固件程序 BIOS启动
即为开机启动项,计算机开机后CPU需要执行的第一个程序。BIOS会将磁盘启动区的512个bytes,复制到0x7c00的位置,并跳转CPU至该地址执行。操作系统的启动代码即位于该512个bytes中。
操作系统启动代码的数据地址可以通过设置ds寄存器实现自动的设置基地址,不需要额外去考虑加载到内存后的地址偏移(比如操作系统中数据为一个地址,加载到内存之后这个地址需要根据内存地址修改,实现方式即为ds寄存器)。
1 |
|
2. 复制启动区至0x90000并跳转
1 |
|
rep movm复制cx个字,从ds:si 处复制到 es:di 处。即将将内存地址 0x7c00 处开始往后的 512 字节的数据,原封不动复制到 0x90000 处。并跳转至[INITSEG:go]处执行(go的地址是这个标签在文件内的偏移地址),即执行mov ax,cs。
在BIOS执行启动区命令的同时,复制至0x90000并跳转执行。
3. 内存的初步规划
配置数据段寄存器 ds 和代码段寄存器 cs为0x9000,栈顶地址被设置为了 0x9FF00,具体表现为栈段寄存器 ss 为 0x9000,栈基址寄存器 sp 为 0xFF00。
1 |
|

4. 加载操作系统其他部分
通过调用BIOS的0x13号中断程序,从磁盘中加载setup,head至内存中。并跳转至setup的内容开始执行。
1 |
|
1 |
|
5. 运行setup,获取系统数据
通过调用BIOS中断,系统数据被存储至0x90000-0x901FF,原先存放boot的代码被覆盖。
内存地址 | 长度(字节) | 名称 |
---|---|---|
0x90000 | 2 | 光标位置 |
0x90002 | 2 | 扩展内存数 |
0x90004 | 2 | 显示页面 |
0x90006 | 1 | 显示模式 |
0x90007 | 1 | 字符列数 |
0x90008 | 2 | 未知 |
0x9000A | 1 | 显示内存 |
0x9000B | 1 | 显示状态 |
0x9000C | 2 | 显卡特性参数 |
0x9000E | 1 | 屏幕行数 |
0x9000F | 1 | 屏幕列数 |
0x90080 | 16 | 硬盘1参数表 |
0x90090 | 16 | 硬盘2参数表 |
0x901FC | 2 | 根设备号 |
后关闭BIOS中断,并将操作系统代码移动至0x0地址。
2. CPU寄存器

ds寄存器
data segment,数据段寄存器。用于在内存寻址时充当段基址的作用。在汇编语言写一个内存地址,只需要写出偏移地址即可。真正的地址为[ds:shift address]
1 |
|
由于 x86 为了让自己在 16 位这个实模式下能访问到 20 位的地址线这个历史因素),所以段基址要先左移四位。即ds的实际值为0x07c0
cs 寄存器
code segment,代码段寄存器,CPU 当前正在执行的代码在内存中的位置,就是由 cs:ip 这组寄存器配合指向的,其中 cs 是基址,ip 是偏移地址。
执行jmpi go,0x9000后, cs 寄存器里的值就是 0x9000,ip 寄存器里的值是 go 这个标签的偏移地址。
ss寄存器
stack segment, 栈段寄存器,配合栈基址寄存器 sp 来表示此时的栈顶地址。栈顶地址为 ss:sp
sp寄存器
stack pointer, 栈基址寄存器
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!