从0开始写内核(二)MBR小试
参考书籍:操作系统真相还原
源码:https://github.com/wutiaojian000/AFKernel.git
本文地址:https://www.cnblogs.com/angel-fish/p/18798903
0. 基础知识
这里只贴一张实模式下的内存布局供以后查看

1. MBR
1.1 代码
这里我就直接从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)
int 0x10
; 获取光标位置
mov ah, 3 ;3号子功能是获取光标位置
mov bh, 0 ;待获取光标的页号
int 0x10 ;输出:ch=光标开始行,cl=光标结束行,dh=光标所在行号,dl=光标所在列号
; 打印字符串 使用0x13功能号
mov ax, message
mov bp, ax
mov cx, 5 ;串长度,不包括'\0'
mov ax, 0x1301 ;0x13为功能号,0x01表示显示字符串,光标跟随移动
mov bx, 0x02 ;bh存储要显示的页号,这里是0,bl是字符属性,0x02表示黑底绿字
int 0x10
jmp $ ;程序悬停在这里
message db "1 MBR"
times 510-($-$$) db 0
db 0x55, 0xaa
像ds,es,fs,gs这些sreg,cpu是没有办法直接赋值的,需要通过通用寄存器来间接赋值。开头的位置使用cs来初始化了这些段寄存器。
mov sp, 0x7c00是初始化栈指针,mbr也是程序,当然也要有栈结构。0x7c00以下的地址可以看成是安全的。
然后是清屏和打印,打印需要先确定光标的位置,然后在光标的位置处打印(打印的位置可以不在光标位置上。。。)。
从代码中可以看到获取光标是有一个页的概念,在文本模式下默认一屏是80*25,2000个字符,每个字符一字节表示ASCII码,另一字节表示字符属性,所以一共4000字节,实际上分配给一屏的是4kb,这一屏就成为一页,0页是默认页。
打印字符的功能号0x13,al寄存器低2位才有意义:
(1)al=0,显示字符串,光标回到起始位置;
(2)al=1,显示字符串,光标追随到新位置;
(3)al=2,显示字符串及其属性,光标回到起始位置;
(4)al=3,显示字符串及其属性,光标追随到新位置。
jmp \(为跳转到当前指令所在地址,就是循环跳回到自己。
times 510-(\)-$$) db 0:(\(-\)\()是当前行到section的偏移,512 - 2 - (\)-$$)为本扇区需要填充的0的个数。
1.2 编译
(记得先安装nasm)
nasm -o mbr.bin mbr.S

确实是512字节。
1.3 写入扇区
这里需要用到dd指令
man dd
bs=BYTES
read and write up to BYTES bytes at a time (default: 512);
overrides ibs and obs
count=N
copy only N input blocks
conv=CONVS
convert the file as per the comma separated symbol list
if=FILE
read from FILE instead of stdin
of=FILE
write to FILE instead of stdout
seek=N skip N obs-sized blocks at start of output
append append mode (makes sense only for output; conv=notrunc sug‐
gested)
dd if=mbr.bin of=/home/zcm/bochs/hd60M.img bs=512 count=1 conv=notrunc

成功!

浙公网安备 33010602011771号