雅乐网

计算机技术、学习成长

计算机 » 操作系统 » Linux0.11操作系统启动bootsect.s, setup.s, head.s, main.c

Linux0.11操作系统启动bootsect.s, setup.s, head.s, main.c

本文解释8086机器开机后的过程,和linux0.11中的相关源代码文件:linux-0.11\boot 目录下的 bootsect.s, setup.s 和 head.s

开机后BIOS的工作

80×86结构的计算机打开电源后,CPU自动进入实模式,并从地址0xFFFF0处执行代码。这个地址正是ROM-BIOS的地址。BIOS会完成系统的检测的相关动作,并在地址0处初始化BIOS中断向量。然后,它会把可启动设备的引导扇区(第一个扇区,512字节)读入内存绝对地址0x7C00处,然后跳转到这个地方并执行此处的代码。

bootsect.s

bootsect.s也就是引导程序,它位于磁盘的第一个扇区512字节中。在磁盘中它的后面是setup.s编译后的setup模块,在后面是system模块

在BIOS把bootsect模块加载到0x7C00处后,CPU会从此处执行。bootsect完成的主要功能为

1. 把自己从内存中0x7C00处移动到0x90000处,同时CPU跳转到挪动后的位置继续执行

2. 使用BIOS 0x13中断,把setup模块读入内存0x90200处

3. 使用BIOS 0x10中断,在屏幕上显示”Loading system…”

4. 使用BIOS 0x13中断, 把system模块读入内存0x10000处

1. 移动到0x90000

此段代码把内存 0x7C00处的512字节内容移动到内存0x90000处

ds = 0x07c0 , es = 0x9000, si = 0, di = 0

rep movw 的作用是 将 DS:SI 的内容送至 ES:DI ,每次移动1个字(2字节),移动cx=256次

注意寻址方式, ds:si 实际的地址是ds左移4位,加上si,正好是0x07c00

复制过后,jmpi语句跳转过去,正好接着执行go处的语句

2. 加载setup模块

跳转过来后,cs = 0x9000 ,首先把这个段地址赋值给ds, es 和ss,设置 sp=0xFF00,也就是堆栈地址从ss:sp = 0x9ff00处开始。

load_setup完成读setup的工作,使用BIOS 0x13号中断,之前设置寄存器ax, bx, cx, dx作为传入的参数:

寄存器 说明
AH 2 功能号,2表示读取扇区功能
AL SETUPLEN=4 需要读取的扇区数量
CH 0 磁道号的低8位
CL 2 0-5位是从哪个扇区开始读,6-7位是磁道号的高2位
DH 0 磁头号
DL 0 驱动器号
ES:BX 9000:0200 把扇区的内容读到ES:BX(90200)的位置

 

如果出错,标志寄存器CF置位,AH中存放出错码

如果出错要0x13中断的0号功能复位驱动器

寄存器 说明
AH 0 功能号,0表示复位驱动器
DL 0 需要复位的驱动器编号

3. 显示Loading文字

用到0x10中断的两个功能 0x03功能读光标位置,0x13功能显示字符串

AH = 0x03 读光标, bh=0表示页号,返回值CH=光标起始行,DH=行,DL=列

AH 0x13 显示字符,参数:

AL 显示模式
BH 视频页
BL 属性值,当AL=0和1时有用
CX 字符串长度
DH,DL 屏幕上显示起始位置行,列
ES:BP 字符串的地址

显示模式(AL):

0x00:字符串只包含字符码,显示之后不更新光标位置,属性值在BL中

0x01:字符串只包含字符码,显示之后更新光标位置,属性值在BL中

0x02:字符串包含字符码及属性值,显示之后不更新光标位置

0x03:字符串包含字符码及属性值,显示之后更新光标位置

4. 加载system,跳转到setup

setup.s

1. 通过 BOIS 获取系统数据,保存到0x90000开始的位置,供后续system模块使用

2. 把system模块从0x10000的移到0x0000开始的地方

3. 加载中断描述符表寄存器和全局描述符表寄存器,开启A20地址线

4. 重新设置两个中断控制芯片

5. 设置CPU的CR0寄存器,进入32位保护模式,并且跳转到system模块最前面部分的head.s程序运行

1. 获取系统数据

通过一些BIOS功能调用读取硬件参数,放入0x90000处:

内存地址 长度 名称
0x90000 2 光标位置
0x90002 2 扩展内存数
0x901FC 2 跟设备号

2. 移动system模块

把system从0x10000处移动到 0 地址处。

3. 设置临时的GDT表和LDT表

此处设置GDT表,为了后面jmpi 0,8 指令可以正确跳转到物理0地址

4. 设置中断控制芯片

5. 进入保护模式,跳转到head.s

lmsw会设置cr0寄存器的值,cr0的第1位为PE位,设置为1启动保护模式。

jmpi 0,8 就成了保护模式下的跳转, 8其实成了段选择符,要用二进制来理解:

是选择GDT的第1个表项,GDT表在第3步中设置了内容:

第0项

.word 0,0,0,0 ! dummy

第1项

.word 0x07FF ! 8Mb – limit=2047 (2048*4096=8Mb)
.word 0x0000 ! base address=0
.word 0x9A00 ! code read/exec
.word 0x00C0 ! granularity=4096, 386

 

head.s

head.s在system的最开始处,完成保护模式的一些初始化工作,然后调用main.c中的main函数

1. 初始化

2. 跳转到main函数

init/main.c

 

如果文章对你有帮助,欢迎点赞或打赏(金额不限)。你的打赏将全部用于支付网站服务器费用和提高网站文章质量,谢谢支持。

版权声明:

本文由 原创,商业转载请联系作者获得授权。
非商业转载请注明作者 雅乐网 ,并附带本文链接:
http://www.yalewoo.com/linux0-11_bootsect-s-setup-s_head-s.html

上一篇:

下一篇:

我要评论

验证码*: 7 + 0 =