BIOS
实模式下1MB内存布局
Intel 8086 有 20 条地址线,故其可以访问山西的内存空间,即 2 的 20 次方=1048576=1MB,地址范围若按16进制来表示是0x00000
到0xFFFFF
,该1MB内存布局如下图所示:
其中内存地址
0x00000
~
x9FFFF
的空间范围是 640KB,这片地址对应到了 DRAM,也就是插在主板 上的内存条。顶部的
0xF0000
~
0xFFFFF
,这 64KB的地址对应的是
ROM
,该
ROM
里面存的就是 BIOS 的代码。BIOS 的主要工作是检测、初始化硬件,硬件自己提 供了一些初始化的功能调用, BIOS 直接调用即可。此外BIOS 还建立了中断向量表,这样 就可以通过
int 中断号
来实现相关的硬件调用。
BIOS是如何被执行的?
在开机的一瞬间,也就是接电的一瞬间, CPU 的 CS: ip
寄存器被强制初始化为 OxFOOO: OxFFFO
,由于开机的时候处于实模式,实模式下段基址乘以16(即二进制下左移4位,16进制下”左移”一位)即得到物理地址,也就是在开机的一瞬间,CPU会跳转到物理地址(0xF000*16+0xFFF0=
)0xFFFF0
处执行,而结合实模式下内存布局我们知道地址0xFFFF0
处就是BIOS
的入口地址。而地址范围0xFFFF0~0xFFFFF
处的内容是一条跳转指令jmp far f000: e05b
,该跳转指令强制将CS:ip
寄存器的值设为0xF000:0xE05B
,即CPU会跳转到地址(0xF000
左移四位+0xE05B
=)0xFE05B
处执行,结合实模式下1MB内存布局图,我们知道地址0xFE05B
处是BIOS真正的地址,也就是接下来CPU才是执行真正的BIOS程序,BIOS检测内存、显卡等外设信息,当检测通过,并初始化硬件后,开始在内存0x000~0x3FF
建立数据结构、中断向量表IVT并填写中断例程。
BIOS如何加载MBR?
BIOS的最后一项工作是检测硬盘中位于0磁盘0磁道1扇区大小为512字节的最后2个字节是否为0x55
和0xaa
,如果是的话便认为该扇区中存在可执行程序,并将该扇区(512字节大小)内容加载到内存物理地址0x7C00
处,然后执行jmp 0:0x7c00
指令,CPU跳转到地址(0x0
左移四位+0x7c00
=)0x7c00
处执行MBR程序。
编写MBR程序,向屏幕输出内容
如下所示为演示的MBR程序,代码路径为Myos/chapter1/boot/mbr.S
:
;Myos/chapter1/boot/mbr.S
;主引导程序
;BIOS刚跳转到MBR时,CS:ip寄存器值为0x0:0x7c00
;
SECTION MBR vstart=0x7c00 ;告诉编译器,把这段程序的起始地址编译为0x7c00,将来BIOS会将这段程序加载到物理地址0x7c00处
mov ax,cs ;将ds,es,fs初始化为0
mov ds,ax
mov es,ax
mov fs,ax
mov sp,0x7c00 ;MBR被加载到0x7c00地址处,0x7c00地址往下的内存空间可以作为MBR运行时所需要的栈空间(栈顶指针往下增长)
mov ax,0xb800 ;借助ax寄存器设置显存段基址
mov gs,ax
;清屏
;利用0x06号功能,上卷全部行,即可清屏
;---------------------------------------------------------------
;INT 0x10 功能号:0x06 功能描述:上卷窗口
;---------------------------------------------------------------
;输入:
;AH 功能号= 0x06
;AL = 上卷的行数(如果为0,表示全部)
;BH = 上卷行的属性
;(CL,CH) = 窗口左上角的(X,Y)的位置
;(DL,DH) = 窗口右下角的(X,Y)的位置
;无返回值:
mov ax, 0600h
mov bx, 0700h
mov cx, 0 ; 左上角(0,0)
mov dx, 184fh ; 右下角(80,25)
; VGA文本模式中,一行只能容纳80个字符,共25行,
; 下标从0开始,所以0x18=24,0x4f=79
int 10h ; 调用0x10中断例程
;输出背景色绿色,前景色红色,并且跳动的字符串"1 MBR"
mov byte [gs:0x00], '1' ; 从显存地址 0xb8000 开始,每两个字节为一组,低字节保存数据内容,即字符的ASCII值
mov byte [gs:0x01], 0xA4 ; 高字节保存显示的属性,低四位控制前景色,高四位控制背景色
mov byte [gs:0x02], ' '
mov byte [gs:0x03], 0xA4
mov byte [gs:0x04], 'M'
mov byte [gs:0x05], 0xA4
mov byte [gs:0x06], 'B'
mov byte [gs:0x07], 0xA4
mov byte [gs:0x08], 'R'
mov byte [gs:0x09], 0xA4
jmp $ ; 通过死循环使程序停止在这个位置
times 510-($-$$) db 0 ; 用0填充0磁盘0磁道1扇区512字节剩下的空间,$是当前行的位置,$$是文件起始
db 0x55, 0xaa ; 512字节的MBR最后两字节是0x55和0xaa
从实模式下1MB内存布局得知,地址范围0xb8000~0xb8ffff
是文本模式下显示适配器的地址,即文本模式下显存的地址空间,往该地址空间写入数据的ASCII值就会向屏幕输出对应的字符串,每两个字节为一组,低字节保存字符的ASCII值,高字节保存显示的属性,这两字节的各位信息如下图所示:
编译代码:
nasm -o mbr.bin mbr.S
用dd命令将编译好的mbr.bin
写入虚拟硬盘:
dd if=./mbr.bin of=~/MySoft/bochs2.6/hd60M.img bs=512 count=1 conv=notrunc
到bochs安装目录启动bochs:
bin/bochs -f bochsrc
运行结果如下所示: