第二章 编写MBR主引导记录

主引导记录(MBR,Master Boot Record)是采用MBR分区表的硬盘的第一个扇区,即C/H/S地址的0柱面0磁头1扇区,也叫做MBR扇区

计算机的启动过程

为什么程序要载入内存
CPU的硬件电路被设计成只能运行处于内存中的程序,一来内存比较快且容量大,二是为了方式的统一。

什么是载入内存
在这里插入图片描述

BIOS

从按下主机上的power键后,第一个运行的软件就是BIOS(Base Input & Output System,基本输入输出系统)

实模式下的1MB内存布局

Intel8086 有20条地址线,故其可以访问1MB的内存空间,即2的20次方=1MB,地址范围若按十六进制来表示,是0x00000-0xfffff。
在这里插入图片描述
0-0x9FFFF 640KB DRAM(动态随机访问内存),动态指此种存储介质由于本身电气元件的性质,需要定期地刷新(补充电,掉电后数据会消失)物理内存
0xF0000-0xFFFFF 64KB ROM 存放BIOS代码
BIOS 的主要工作是检测、初始化硬件,建立中断向量表,BIOS建立的这些功能就是对硬件的IO操作,也就是输入输出

在CPU眼里,为什么我们插在主板上的物理内存不是它眼里“全部的内存”
地址总线宽度决定了可以访问的内存空间大小,由于还有一些外设同样需要通过地址总线来访问,需要在地址总线上提前预留出一些地址空间给这些外设用。
地址总线是决定我们访问哪里、访问什么,以及访问范围的关键。CPU能够访问一个地址,这是地址总线给做的映射,相当于给该地址分配了一个存储单元,而该存储单元要么落在某个ROM中,要么落到了某个外设的内存中,要么落到了物理内存条上。
在这里插入图片描述

BIOS是如何苏醒的

在这里插入图片描述
实模式只能访问1MB空间,而地址0xFFFF0距1MB只有16字节,超过就会溢出。说明这里的代码只是各跳转指令,跳转到下一条待执行指令的地址。段基址0xf000左移4位+0xe05b,即跳向了0xfe05b处,这是BIOS代码真正开始的地方。
在这里插入图片描述

为什么是0x7c00

BIOS最后一项工作校验启动盘中位于0盘0道1扇区(磁盘上最开始的那个扇区)的内容。如果此扇区末尾的两个字节分别是魔数0x55和0xaa,BIOS便认为此扇区中确实存在可执行的程序,便加载到物理地址0x7c00,随后跳转到此地址,继续执行。在这里插入图片描述

在这里插入图片描述
为什么是0盘0道1扇区的内容
这是磁盘的第一个扇区,离BIOS近,好找
为什么是物理地址0x7c00
BIOS规范
加载MBR的位置取决于操作系统本身所占内存大小和内存布局。

在这里插入图片描述

编写MBR

MBR的大小必须是512字节(每个扇区大小是512字节),这是为了保证0x55和0xaa这两个魔数恰好出现在该扇区的最后两个字节处,即第510字节处和511字节处,这是按起始偏移为0 算起的。由于bochs模拟的是x86平台,所以是小端字节序,故其最后两个字节内容是0xaa55。

$ , $$, section

在这里插入图片描述

$ 属于“隐式地”藏在本行代码前的标号,也就是编译器给当前行安排的地址。
$$指代本section的起始地址,此地址同样是编译器给安排的。
在默认情况下,它们的值是相对于本文件开头的偏移量。如果该section用来vstart=xxxx修饰, $ $的值则是此section的虚拟起始地址xxxx。 $的值是以xxxx为起始地址的顺延。如果没有定义section,nasm默认全部代码同为一个section,起始地址为0。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

section是给开发人员逻辑上规划代码用的,只起到思路清晰的作用,最终还是在编译阶段由nasm在物理上的规划说了算。

NASM 简单用法

nasm的基本用法格式如下,-f是用来指定输出可执行文件的格式,-o是指定输出可执行文件的名称,nasm -hf可以查看有效格式,bin是默认输出格式(不需要用-f)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

MBR

代码功能:在屏幕上打印字符串“1 MBR”,背景色为黑色,前景色为绿色

设置程序起始地址,BIOS通过跳转到地址0x7c00

SECTION MBR vstart=0x7c00

用cs寄存器的值去初始化其他寄存器,cs的值赋值给ax,ax赋值给其他寄存器(CPU不能直接给它们赋值),此时cs=0

mov ax,cs
mov ds,ax
mov es,ax
mov ss,ax
mov fs,ax

初始化栈指针

mov sp,0x7c00

清屏。先把BIOS的输出清掉

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 寄存器存储的是待获取光标的页号,第0int 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: 显示字符串,光标跟随移动
;1)al=0,显示字符串,并且光标返回起始位置。
;2)al=1,显示字符串,并且光标跟随到新位置。
;3)al=2,显示字符串及其属性,并且光标返回起始位置。
;4)al=3,显示字符串及其属性,光标跟随到新位置。
mov bx, 0x2 ; bh 存储要显示的页号,此处是第 0,
; bl 中是字符属性,属性黑底绿字(bl = 02h)
int 0x10 ; 执行 BIOS 0x10 号中断

死循环。$是本行执行指令地址, $是jmp自己的地址,一直跳自己的地址,死循环

jmp $ ; 使程序悬停在此

定义打印的字符串

message db "1 MBR"

用0将本扇区剩余空间填满
$ $是指本section的起始地址, $- $ $是本行到本section的偏移量。由于MBR最后两个字节是固定内容,分别是0x55和0xaa,要预留出2个字节,故本扇区内前512-2=510字节要填满,用510字节减去上面得到的偏移量,其结果便是本扇区内的剩余量,也就是要填充的字节。

times 510-($-$$) db 0
;主引导程序
;------------------------------------------------------------
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: 显示字符串,光标跟随移动
;1)al=0,显示字符串,并且光标返回起始位置。
;2)al=1,显示字符串,并且光标跟随到新位置。
;3)al=2,显示字符串及其属性,并且光标返回起始位置。
;4)al=3,显示字符串及其属性,光标跟随到新位置。
mov bx, 0x2 ; bh 存储要显示的页号,此处是第 0,
; bl 中是字符属性,属性黑底绿字(bl = 02h)
int 0x10 ; 执行 BIOS 0x10 号中断
;;;;;;;;; 打字字符串结束 ;;;;;;;;;;;;;;;

jmp $ ; 使程序悬停在此

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

本段关于“打印显示”的操作都利用BIOS给我们建立好的例程,0x10号中断就是负责有关打印的例程。
0x10中断是最为强大的BIOS中断,调用的方法是把功能号送入ah寄存器,其他参数按照BIOS中断手册要求放在适当的寄存器中,随后执行int 0x10即可。

编译汇编代码

nasm mbr.S -ombr.bin

查看刚才编译好的mbr.bin
正好是512字节

ls -lb mbr.bin

在这里插入图片描述

Linux命令:dd。用于磁盘操作的命令。

在这里插入图片描述

将MBR文件写入0盘0道1扇区

sudo rm -f hd60M.img.lock

dd if=mbr.bin of=hd60M.img ibs=512 count=1 conv=notrunc

在这里插入图片描述
在这里插入图片描述
启动bochs

bochs -f bochsrc

在这里插入图片描述

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值