在开机上电的一瞬间,CPU的cs:ip寄存器被强制初始化为0xF000:0xFFF0,开机的时候处于实模式,实模式下段基址乘以16加上偏移地址就得到物理地址,即0xFFFF0,这也就是BIOS的入口地址,系统开机后第一个运行的软件就是我们的BIOS。
BIOS也是在实模式下运行,实模式下只能访问1MB的空间(Intel 8086地址线是20位),而BIOS的入口地址是0xFFFF0,距离1MB的终点(0xFFFFF)只剩下16字节了,这么小的空间不可能放下整个BIOS的代码。实际上,0xFFFF0地址处只是一条跳转指令(jmpf f000:e05b),即跳转到0xFE05B,也就是BIOS代码真正开始的地方。
BIOS由于代码空间有限,只会对一些系统基本且必要的硬件进行检测和初始化,如检测内存、显卡,并建立中断向量表(BIOS中断)。BIOS的最后一项工作是将系统控制权交给下一棒软件,即主引导记录MBR。
MBR位于磁盘最开始的那个扇区(CHS方法是0盘0道1扇区;LBA方法是0盘0道0扇区),该扇区约定必须以0x55和0xaa结尾。BIOS首先校验启动盘第一个扇区的内容,主要是校验结尾字符是否符合要求,然后并将该扇区的内容从磁盘加载物理内存的0x7c00处,然后跳转到该处执行(jmp 0:0x7c00)。
关于为什么是0x7c00,有其历史原因,MBR程序本身只有512字节,但运行时需要栈空间,实际所用内存空间是大于512字节的,不过一般1KB够用了,最早的BIOS是按照最小内存32KB开发的,为了防止MBR被覆盖(MBR会记载OS Loader,为了让其不覆盖自己,保证自己能执行完,加载MBR到内存的位置是需要考量的),MBR只能放在32KB的末尾,32KB(0x8000)减去1KB,就是0x7c00。
下面参考《操作系统真象还原》一书,给出一个简单的MBR及其运行过程:
简单MBR代码:
---------------------------------------------------mbr1.s start------------------------------------------------------------
;vstart告诉编译器,本程序编译后起始地址编译为0x7c00
SECTION MBR vstart=0x7c00
;用cs寄存器的值初始化其它寄存器,由于CPU不能直接通过立即数对段寄存器赋值,通
;过其他寄存器来中转,即ax
;BIOS通过jmp 0:0x7c00跳转到MBR,此时cs以及初始化的各个段寄存器实际为0
mov ax,cs
mov ds,ax
mov es,ax
mov ss,ax
mov fs,ax
;初始化栈指针,0x7c00以下暂时是安全区域
mov sp,0x7c00
;通过BIOS中断0x10清屏,即把BIOS的输出先清掉,可以清楚看到MBR的打印
mov ax,0x600
mov bx,0x700
mov cx,0
mov dx,0x184f
int 0x10
;打印前的工作,先获取光标位置
mov ah,3
mov bh,0
int 0x10
;在光标位置处打印字符message
mov ax,message
mov bp,ax
mov cx,9
mov ax,0x1301
mov bx,0x2
int 0x10
;$表示本行地址,jmp $实际是个死循环,代码在此处停住
jmp $
;打印的字符串message
message db "Hello MBR"
;$表示本行地址,$$标识本section起始地址,$-$$表示本行到本section的偏移量,510减去该偏移量,将剩余的填充为0,MBR扇区最后必须以0x55和0xaa结尾,刚好占用512字节
times 510-($-$$) db 0
db 0x55,0xaa
---------------------------------------------------mbr1.s end------------------------------------------------------------
编译该代码:
# nasm -o mbr1.bin mbr1.S
使用bochs的bximage工具创建一个虚拟硬盘hd100M.img,通过dd磁盘操作工具将编译出来的mbr1.bin写入到虚拟硬盘的第一个扇区中:
然后在bochs虚拟机中运行效果如下(BIOS启动MBR后,打印了Hello MBR字符串):
推荐您阅读更多有关于“ 操作系统 ”的文章
请填写你的在线分享代码
评论列表: