2.1 计算机的启动过程
载入内存:
(1) 程序被加载器(软件或硬件)加载到内存某个区域
(2)CPU 的 cs:ip 寄存器被指向这个程序的起始地址
2.2 软件接力第一棒,BIOS
2.2.1 实模式下的 1MB 内存布局
Intel 8086 有 20 条地址线,故其可以访问 1MB 的内存空间,即2的20次方=1048576=1MB。
实模式下的内存布局如下:
(1)在电脑未开机前,BIOS就被事先写入到内存的F0000~FFFFF中,此区域为ROM,这里面存的是 BIOS 的代码。BIOS的主要工作是检测、初始化硬件,建立中断向量表。
(2)除了内存条,还有一些外设同样是需要通过地址总线来访问。
2.2.2 BIOS 是如何苏醒的
在开机的一瞬间,CPU的cs:ip
寄存器被强制初始化为0xF000: 0xFFF0
,由于开机的时候处于实模式,按照实模式的寻址方式段基地址要乘以16,也就是左移4位,然后再加上段内偏移地址,则计算得这个实际的物理地址为0xFFFF0
,此地址便是BIOS程序的入口地址。而从地址0xFFFF0~0xFFFFF
只有16B的空间,这说明BIOS真正的执行脚本并不存储在这里,开机后执行的第一条语句一定是跳转语句jmp
,其实执行的第一条语句是:
bash
jmp far f000:e05b
跳转到了0xfe05b
处,说明这里才是BIOS代码真正开始的地方。接下来就是BIOS不断进行检测内存,显卡等外设信息,然后初始化硬件的过程了。
2.2.3 为什么是 0x7c00
BIOS 最后一项工作校验启动盘中位于0盘0道1扇区的内容。如果此扇区末尾的两个字节分别是魔数0x55
和0xaa
,BIOS便认为此扇区中确实存在可执行的程序,并把这个扇区的内容加载到物理地址0x7c00
的内存中。
2.3 实验
任务:
(1)完成mbr主引导记录的代码编写,并完成编译,完成的代码编译并非真正的MBR主引导程序,而是为了测试mbr程序是否会被加载到0x07c00处被正确执行。
(2)将编译生成的主引导记录内容刻录到我们的创建的启动硬盘中。
创建mbr.s文件:
(1)文件功能:在屏幕上打印字符串"1 MBR",背景色为黑色,前景色(字体颜色)为绿色.
(2)功能实现方式:借助BIOS建立好的例程0x10号中断,可将0x10号中断看做一个函数,这个函数不同的输入可实现不同的功能,因此要有一个参数表示要实现的功能,也就是接下来要说的功能号参数。
代码:
bash
; ~/d2los/src/mbr.S
; MBR主引导程序
;------------------------------------------------------------
SECTION MBR vstart=0x7c00
mov ax,cs
mov ds,ax
mov es,ax
mov ss,ax
mov fs,ax
mov sp,0x7c00
; 清屏利用 0x06号功能, 上卷全部行, 实现清屏
; -----------------------------------------------------------
; INT 0x10 功能号: 0x06 功能描述: 上卷窗口
; ------------------------------------------------------
; 输入:
; AH = 功能号 0x06
; AL = 上卷的行数(如果为0, 表示全部)
; BH = 上卷行属性
; (CL, CH) = 窗口左上角的(X, Y)位置
; (DL, DH) = 窗口右下角的(X, Y)位置
; 无返回值
mov ax, 0x600
mov bx, 0x700
mov cx, 0 ; 左上角: (0, 0)
mov dx, 0x184f ; 右下角: (80, 25),
; VGA文本模式中, 一行只能容纳80个字符, 共25行.
; 下标从0开始, 所以0x18=24, 0x4f=79
int 0x10 ; int 0x10
; 获取光标位置
; -----------------------------------------------------------
; .get_cursor 获取当前光标位置, 在光标位置处打印字符.
mov ah, 3 ; 输入: 3号子功能是获取光标位置, 需要存入ah寄存器
mov bh, 0 ; bh寄存器存储的是要获取光标的页号
int 0x10 ; 输出: ch=光标起始行, cl=光标结束行
; dh=光标所在行号, dl=光标所在列号
; 获取光标位置结束
; -----------------------------------------------------------
; 打印字符串
; -----------------------------------------------------------
; 还是用10h中断, 不过这次是调用13号子功能打印字符串
mov ax, message
mov bp, ax ; es:bp 为字符串起始地址, es此时同cs一致,
; 开始时已经为sreg初始化
; 光标位置要用到dx寄存器中的内容, cx中的光标位置可忽略
mov cx, 5 ; cx 为字符串长度, 不包括结束符0的字符个数
mov ax, 0x1301 ; 子功能号13是显示字符串及属性, 要存入ah寄存器,
; al设置显示字符方式 ah=01: 显示字符串,光标跟随移动
mov bx, 0x2 ; bh存储要显示的页号, 此时是第0页,
; bl中是字符属性, 属性黑底绿字(bl = 02h)
int 0x10 ; 执行BIOS 0x10 号中断
; 打印字符串结束
; -----------------------------------------------------------
jmp $ ; 使程序停在此处
message db "1 MBR"
times 510-($-$$) db 0
db 0x55,0xaa
编译mrb.S文件:
bash
nasm -o test mbr.s
将文件内容写入0盘0道1扇区:
bash
dd if=/home/abc/Desktop/Bochs/mbr.bin of=/home/abc/Desktop/Bochs/Seven.img bs=512 count=1 seek=0 conv=notrunc
启动bochs查看结果:
bash
bin/bochs -f bochsrc.disk
在 0x7c00
处打断点,可以看到将0x0000
的值移入cs中:
查看段寄存器: