本文基于郑纲的《操作系统还原》,仅为个人学习笔记,前期的虚拟机配置等不再详细记录,其中不理解或者出错的地方还望提出意见!
MBR
MBR 的大小必须是 512 字节,主要作用是,告诉计算机到硬盘的哪一个位置去找操作系统。
主引导记录由三个部分组成:
(1) 第1-446字节:调用操作系统的机器码。
(2) 第447-510字节:分区表(Partition table)。
(3) 第511-512字节:主引导记录签名(0x55和0xAA)。
其中,第二部分"分区表"的作用,是将硬盘分成若干个区。
代码
代码功能:在屏幕上打印字符串“1 MBR”,背景色为黑色,前景色为绿色,打印显示是利用BIOS中断完成。
0x10中断传送门
; 主引导程序
SECTION MBR vstart=0x7c00 ; 起始地址编译为0x7c00
mov ax,cs ; cs寄存器初始化其他寄存器,
mov ds,ax ; BIOS 通过 jmp 0: 0x7c00 跳转到 MBR,cs此时为 0
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 ; 剩余空间填充0,并保留最后两字节存放0x55,0xaa
db 0x55,0xaa
KaTeX parse error: Can't use function '$' in math mode at position 17: …指本section的起始地址,$̲是本行所在的地址,故$-是本行到本 section
的偏移量。
Makefile
接下来需要对代码进行
1)编译 : build
2)将编译文件存储到0盘0道1扇区成为MBR:burn
.PHONY:build burn clean
mbr_target = mbr.bin
mbr_source = mbr.s
hard_disk = ../hd60M.img
build:
nasm $(mbr_source) -o $(mbr_target)
burn:
@make build
dd if=$(mbr_target) of=$(hard_disk) bs=512 count=1 conv=notrunc
clean:
rm *.bin
运行结果
以下是运行结果
关于Bochs的运行等问题不再详细记录。