第二章 编写MBR,开始进入系统的世界

本文最后更新于:1 年前

第二章 编写MBR,开始进入系统的世界

写在前面

今天是7月6日,这一章涉及了汇编语言,阅读开始变得吃力,加上书中排版密密麻麻的文字,很容易心生退意,相信在开发的过程中一定会有些许乐趣等待挖掘,借此博客督促自己加强学习。

Let`s go! BIOS!

首先说明了计算机启动后第一个运行的程序是我们常见的BIOS,然后为了说明BIOS加载的一系列问题,作者列出了实模式下内存布局的一张表用以说明CPU提交地址后会进行一个地址映射,分配给对应的物理设备。

然后就是BIOS的启动,在接电的瞬间,CPU中的cs:ip寄存器会被初始化为0xF000:0xFFF0(关于寄存器的一些概念涉及到汇编语言,这里不再赘述,我也是边读边学的),这段地址正好对应BIOS的入口地址。需要注意的是,这块地址只起到一个指引的作用,计算机执行它时需要跳转到BIOS的真正地址。

在BIOS里的最后一项工作时校验启动盘0盘0道1扇区(第一个扇区)的内容,如果该扇区末尾的两个字节分别是魔数0x55和0xaa,BIOS便会跳转到物理地址0x7c00,执行MBR(主引导记录)。

我还想了下魔数是什么,一开始以为是计算机固定写死的某些程序,搜了一下才知道它是像魔法一样神奇的数。。。

MBR

MBR的大小是512字节,因为x86平台是小端字节序,所以为了保证最后两个字节(即510字节和511字节)为0x55和0xaa,其内容应为0xaa55。然后提到了NASM的两个关键字$和$$,它们用来表示当前行和本section的地址,起到标号的作用。

终于来到了MBR的编程,这一程序目前实现了一个在屏幕上打印字符串“1 MBR”的功能,其背景色为黑色,前景色为绿色。在打印字符串之前,还包含了不少代码,其功能不再解释。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
; mbr.S

; 主引导程序
; --------------------------------------------------

SECTION MBR vstart=0x7c00 ; 把起始地址编译为 0x7c00
mov ax, cs ; cs 代码段寄存器
mov ds, ax ; dx 数据段寄存器
mov es, ax ; es 附加段寄存器
mov ss, ax ; ss 堆栈段寄存器
mov fs, ax ; fs 80386 后添加的寄存器,无全称
mov sp, 0x7c00 ; sp 堆栈指针寄存器

; 清屏
; --------------------------------------------------
; 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
mov dx, 0x184f ; 右下角: (80, 25)
; VGA 文本模式种,一行只能容纳 80 个字符,共 25 行
; 下标从 0 开始,所以 0x18=24, 0x4f=79

int 0x10 ; int 0x10

;;;;;;;;;;;;;下面这三行代码获取光标位置;;;;;;;;;;;;;;;;

; .get_cursor 获取当前光标位置,在光标处打印字符
mov ah, 3 ; 3 号子功能
mov bh, 0 ; 待获取光标的页号

int 0x10 ; 输出:
; ch = 光标开始行,cl = 光标结束行
; dh = 光标所在行号,dl = 光标所在列号

; 打印字符串
mov ax, message
mov bp, ax ; es:bp 为串首地址

mov cx, 5 ; cx 为串长度,不包括结束符 '\0'
mov ax, 0x1301 ; 13 号子功能
; ah = 13
; al = 01: 写字符方式,显式字符串,光标跟随移动
mov bx, 0x2 ; bh = 0,要显示的页号
; bl = 02,字符属性,黑底绿字

int 0x10
;;;;;;;;;;;;;;;;;;;;;;打印字符串结束;;;;;;;;;;;;;;;;
jmp $; 程序悬停在此

message db "1 MBR"
times 510-($-$$) db 0
db 0x55,0xaa

之后我们利用dd命令(用于磁盘操作的命令)将mbr.bin输出到第一章我们创建的虚拟硬盘hd60M.img,记得按照作者提示,将块大小指定为512字节,只操作1块。

运行bochs,界面是我们预想的输出一串字符串,大功告成!

后记

这一章总体内容并不是很多,主要集中在一些概念的描述,如果没有一定的知识储备读起来会很生涩,但是到了实际操作的时候就会发现基础必不可少。总体来说有一种学到的知识马上就能用到的感觉,比之前读ostep时总感觉有一层纱布隔着的感觉有很大不同,接下来还是争取做到每天一更。