第2章 编写BIOS主引导记录,让我们开始掌权
第2章 编写BIOS主引导记录,让我们开始掌权
2.1计算机的启动过程
计算机执行程序启动两个步骤.
-
将程序加载到内存中。
-
cs:ip指向程序的首地址
在计算机启动时,第一个运行的程序就是BIOS。它也会有这两个步骤。后面将会介绍这两个步骤。
2.2软件接力第一棒,BIOS
BIOS全称 BASE INPUT & OUTPUT SYSTEM,即基本输入输出系统。
2.2.1实模式下的1MB内存布局
可以从低地址看,地址0-0X9FFFF处是DRAM。也就是动态随机访问内存,我们插在主板上的内存条所对应的内存。还有另外一部分是 ROM,BIOS就储存在这里。BIOS的主要工作是检测,初始化硬件。BIOS还建立了中断向量表。
嗯,这里还有个猜测,现在的内存大小都不是二进制的可能与这个有关,刚开始的时候因为CPU访问不到这部分内存所以内存的大小都是小于二进制大小的,后面因为内存有十进制可以省点钱就一直没有改回来。
2.2.2BIOS是如何苏醒的
BiOS本身是个程序,程序要执行,就要有个入口地址才行,此入口地址是0xFFFF0。
开机的一瞬间,CPU的cs:ip寄存器被强制初始化为0xF000:0xFFF0。由于开机的时候处于实模式,再重复一边加深形象,在实模式下的段基址要乘以16,也就是左移4位,于是0xF000:0xFFF0的等效地址将是0xFFFF0。不过这里只是存储了跳转指令,真正的代码不在这里。
BIOS在这里执行跳转指令,指向真正BIOS代码的位置。
2.2.3为什么是0x7c00
BIOS执行后的最后一项工作是校验启动盘中位于0盘0道1扇区的位置。这里因为1扇区就是0扇区的意思,只不过表示法称呼为1扇区。
校验一扇区的最后两字节是否是0x55和0xaa。是的话BIOS便认为此扇区是MBR,然后将内容加载到0x7c00,随后跳转到此地址,继续执行。
为什么是0盘0道1扇区和0x7c00在书上详细解释了。
2.3让MBR先飞一会儿
这里要确定一点,MBR的大小必须是512字节。为了保证0x55和0xaa这两个魔数恰好出现在该扇区的最好两个字节处。
2.3.1神奇好用的$和$$,令人迷惑的section
$和$$是编译器预留的关键字,用来表示当前行和本section的地址。这个是nasm提供的,是伪指令。
$属于"隐式地"藏在本行代码前的标号,也就是编译器给当前行安排的地址。
$$指代本section的起始地址,此地址同样是编译器给安排的。
2.3.2NASM的基本用法
NASM -f <format><filename> [-o output]
以上就是nasm的基本用法。-f 指定输出文件的格式。 -hf查看有哪些输出格式,默认为bin也就是二进制格式,还有一个可能会用到的是elf格式。
2.3.3MBR程序
;主引导程序
;------------------------------------------------------------------------------------------
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 功能描述:上卷窗口
;------------------------------------------------------------------------------------------
;输入
;AX 功能号=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, ox184f ;右上角;(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设置写字符方式,al=01:显示字符串,光标跟随移动
mov bx, 0x2 ;bh存储要显示的页号,此处是第0页,
;bl中是字符属性,属性黑底绿(bl =2h)
int 0x10 ;执行BIOS 0x10号中断
;;;;;;;;;;;;; 打字字符串结束 ;;;;;;;;;;;;;;;;;
jmp $ ;使程序悬停在此
message db "1 MBR"
times 510-($-$$) db 0
db 0x55, 0xaa
代码功能,在屏幕中打印字符串"1 MBR",背景色为黑色,前景色为绿色。
nasm -o mbr.bin mbr.S
编译文件成为二进制文件。
这时候需要将文件的内容写入虚拟磁盘,使用dd命令。
dd的使用。
参数 | 作用 |
---|---|
if=FILE | read from FILE instead of stdin |
of=FILE | write to FILE instead of stdout |
bs=BYTES | read and write BYTES bytes at a time(also see ibs=,obs=) |
count=BLOCKS | copy only BLOCKS obs-sized blocks at start of output |
conv=CONVS | convert the file as per the comma separated symbol list |
dd if = ./mbr.bin of=/your_path/c.img bs=512 count=1 conv=notrunc
写入成功会有如下显示
记录了1+0的输入
记录了1+0的写出
521字节(512B)已复制,0.001秒,1.1MB/秒。
成功以后运行dochs,没有问题。
结尾
后面我要准备、找实习、学习汇编,也不知道下一章要到什么时候才能写出来了。本来写这个就有点害怕版权问题,汇编markdown是真的不敢再发到网上了。