«操作系统真像还原» 第二章 编写MBR主引导记录

实模式寻址

8086 开机后,CS(代码段寄存器)和 IP(指令指针寄存器)的初始值不是由软件设置的,而是由 CPU 的硬件电路强制指定的,固定为CS=0xF000,IP=0xFFF0

0xF000 * 16 +0xFFF0 = 0xFFFF0

8086CPU的寄存器是16位的(最多只能存储0x0000~0xFFFF的数值),但它的地址线是20位的(20位地址线,能访问的物理内存范围是0x00000~0xFFFFF,共1MB,这也是实模式的最大内存寻址能力

为了解决16位寄存器寻址20位物理地址的矛盾,8086设计了段式寻址规则(仅实模式有效,保护模式会用更复杂的寻址方式):物理内存地址 = 段地址 × 16 + 偏移地址

MBR主引导记录

0xFFFF0处存放着一条跳转指令,用于跳转到BIOS程序,BIOS程序会对0盘0道1扇区的最后两个字节进行校验查看是否存放的是MBR主引导记录,如果是0x55,0xaa,就会将改扇区的512字节加载到内存0x7C00处

接下来我们会来写一个简单的MBR:

逻辑:

1.指定起始地址为0x7C00

2.调用bios中断进行清屏操作

3.调用bios中断获取光标所在位置

4.调用bios中断在光标位置出打印字符串

5.进入死循环然后将最后两个字节设置为0x55,0xaa,然后在其余地方补0以达到512字节大小

代码

复制代码
SECTION MBR vstart=0x7c00
    mov ax, cs
    mov ss, ax
    mov ax, 0x7c00
    mov sp, ax

                                ; 清屏利用0x06号功能,上卷全部行,即可清屏。
                                ; INT 0x10  功能号:0x06  功能描述:上卷窗口
                                ; 输入:
                                ; AH = 功能号= 0x06
                                ; AL = 上卷的行数(如果为0,表示全部)
                                ; BH = 上卷行属性
                                ; (CL,CH) = 窗口左上角的(X,Y)位置
                                ; (DL,DH) = 窗口右下角的(X,Y)位置
                                ; 无返回值
    mov ax, 0x0600              ; 左上角: (0,0)
    mov bx, 0x0700              ; 右下角: (24,79)
    mov cx, 0x0000              ; VGA文本模式下,一行只能容纳80个字符,共25行。
    mov dx, 0x184f              ; 下标从0开始,所以dx=18=24,0x4f=79
    int 0x10                    ; int 0x10

                                ;;;;;;;;;;;;;;; 下面这三行代码获取光标位置 ;;;;;;;;;;;;;;;
                                ; INT 0x10 获取当前光标位置,在光标位置处打印字符串
                                ; 输入:
                                ; AH = 3 子功能号是获取光标位置,要存入ah寄存器
                                ; BH = 存储字符的页号(此处是第0页)
                                ; 输出:
                                ; CH=光标开始行,CL=光标结束行
                                ; DH=光标所在行,DL=光标所在列
    mov ah, 3
    mov bh, 0
    int 0x10
;;;;;;;;;;;;;;; 获取光标位置结束 ;;;;;;;;;;;;;;;;;;;;;;

                                ;;;;;;;;;;;;;;; 打印字符串 ;;;;;;;;;;;;;;;;;;;;;;;;;;;
                                ; 还是用10h中断,不过这次调用13号子功能打印字符串
                                ; 输入:
                                ; AH = 13 子功能号是显示字符及属性,要存入ah寄存器
                                ; AL = 设置显示字符方式,AL=01:显示字符串,光标跟随移动
                                ; BH = 存储要显示的页号,此处是第0页
                                ; BL = 字符属性,属性黑底绿字(bl= 02h)
                                ; CX = 字符串长度,不包括结束符0的字符个数
                                ; DH = 字符串要显示的行
                                ; DL = 字符串要显示的列
                                ; ES:BP = 字符串的段:偏移地址
    mov ax, message             ; es:bp 为串地址,此时同cs一致,
    mov bp, ax                  ; 开头时已经为es初始化
                                ; 光标位置要用dx寄存器中内容,cx中的光标位置可忽略
    mov cx, 5                   ; cx 为串长度,不包括结束符0的字符个数
    mov ax, 0x1301              ; ah设置显示字符方式=01:显示字符串,光标跟随移动
    mov bx, 0x02                ; bh存储要显示的页号,此处是第0页
                                ; bl 中是字符属性,属性黑底绿字(bl= 02h)
    int 0x10                    ; 执行 BIOS 0x10 号中断
;;;;;;;;;;;;;;; 打印字符串结束 ;;;;;;;;;;;;;;;;;;;;;;

jmp $                           ;使程序悬浮在此
message db "1 MBR"
times 510 - ($ - $$) db 0
db 0x55,0xaa

代码解析

SECTION MBR vstart=0x7c00 ;告诉编译器将起始地址编译为0x7c00


mov ax, cs ;cs刚开始时为0,此时将ax也设置为0

mov ss, ax ;将ss段寄存器设置为0

mov ax, 0x7c00 ;将ax设置为0x7c00来间接给段寄存器赋值

mov sp, ax ;将sp栈指针寄存器指向MBR起始地址


我们通过int 0x10,功能号为0x06 来调用上卷窗口的操作

mov ax, 0x0600 ;将AH功能号设置为0x06,AL=0x00

mov bx, 0x0700 ;BH存放上卷行属性,设置为0x07为黑底白字

mov cx, 0x0000 ;(CL,CH) = 窗口左上角的(X,Y)位置,此处为(0,0)

mov dx, 0x184f ;(DL,DH) = 窗口右下角的(X,Y)位置,0x18=24,0x4f=79,下标从0开始, 所以是第25行,一行80字符

int 0x10 ;调用中断


mov ah, 3 ;ah存放功能号

mov bh, 0 ;bh寄存器存储的是待获取光标的页号

int 0x10


mov ax, message ;message存放的是"1 MBR"字符串的偏移地址

mov bp, ax ;es:bp是字符串的首地址

mov cx, 5 ; cx 为字符串长度,不包括结束符0的字符个数

mov ax, 0x1301 ; ah子功能号0x13是显示字符及属性,al=0x01:显示字符串

mov bx, 0x02 ; bh存储要显示的页号,此处是第0页,bl中是字符属性,属性黑底 绿字(bl = 02h,07是黑底白字)


jmp ;使程序悬浮在此,是获取当前指令所在地址

message db "1 MBR" ;按字节存储"1 MBR"的ASCII码,message标签绑定

times 510 - ( - ) db 0 ;是当前指令地址,$$是程序开头地址,此处会将不足510字节的内容填 充0知道足够510字节

db 0x55,0xaa ;定义最后两个字节是0x55,0xaa

编译

nasm -o mbr mbr.s

用dd命令写入虚拟硬盘

dd if=/home/chipfesen/bochs/mbr of=/home/chipfesen/bochs/hd60M.img bs=512 count=1 conv=notrunc

if是要写的文件路径,of是被写入的文件路径,bs是块大小,此处是512字节,count是块数量,conv是如何转换文件,notrunc是不转换

启动

使用bin/bochs -f bochsrc.disk来启动

按下回车后输入c再回车

启动后会显示绿色的1 MBR

相关推荐
UP_Continue2 小时前
Linux--进程控制
linux·运维·服务器
188号安全攻城狮2 小时前
【PWN】HappyNewYearCTF_8_ret2csu
linux·汇编·安全·网络安全·系统安全
Yana.nice4 小时前
openssl将证书从p7b转换为crt格式
java·linux
AI逐月4 小时前
tmux 常用命令总结:从入门到稳定使用的一篇实战博客
linux·服务器·ssh·php
小白跃升坊4 小时前
基于1Panel的AI运维
linux·运维·人工智能·ai大模型·教学·ai agent
跃渊Yuey4 小时前
【Linux】线程同步与互斥
linux·笔记
舰长1154 小时前
linux 实现文件共享的实现方式比较
linux·服务器·网络
zmjjdank1ng5 小时前
Linux 输出重定向
linux·运维
路由侠内网穿透.5 小时前
本地部署智能家居集成解决方案 ESPHome 并实现外部访问( Linux 版本)
linux·运维·服务器·网络协议·智能家居