本篇内容介绍BIOS和MBR是什么,并实现一个简单的MBR程序并运行
BIOS是什么?
BIOS(Basic Input & Output System):基本输入输出系统
在计算机的启动过程中,BIOS是系统运行的第一个软件,BIOS的主要工作是检测、初始化硬件,初始化则是通过硬件提供的初始化功能的调用实现,除此之外,BIOS还做了一件事,建立中断向量表,这样就可以通过int中断了。
BIOS的这些操作也就是对硬件的IO操作,BIOS的空间只有F0000~FFFFF:64KB大小,所以只能做那些保证计算机正常运行的基本IO操作,所以BIOS称为
基本
输入输出系统。
关于在计算机中的地址访问,并不是只有内存条(DRAM)通过地址总线进行访问,还有一些外设同样是通过地址总线进行访问的,所以地址总线会预留出一部分连续的空间来给外设用,留够了以后,再把剩下的空间分给DRAM。(这就是为什么电脑8G内存,实际可用内存只有7.8G)
关于物理内存,物理内存多大主要看地址总线的宽度和设计,地址总线决定访问哪里,访问什么,访问范围。
BIOS是怎么执行的?
BIOS是计算机运行的第一个软件
,由硬件(ROM)加载运行,通常BIOS的代码是不变的,ROM也是块内存,ROM被映射在低端1MB内存的顶端,也就是F0000~FFFFF处,既然BIOS是一个程序,只要知道入口地址就能去执行,入口地址则是0xFFFF0
那么既然知道入口地址在哪里了,CPU要如何执行呢?
在实模式下,CPU访问内存是用段地址+偏移地址实现的,段地址左移4位后与偏移地址相加,就是物理地址,CPU就可以拿来用了,在开机的时候,CPU的cs:ip
寄存器会被强制初始化为0xF000:0xFFF0,cs和ip寄存器指向下一条要执行的指令的地址,则这里指向的是0xFFFF0,也就是BIOS的入口地址,由于实模式可访问地址范围只有1MB,从0xFFFF0到1M只有16位大小,这里的指令之能是跳转指令,会跳转到真正的BIOS程序的地址去执行。
实模式是16位CPU的运行模式,32位CPU兼容16位实模式,64位也是
下图是Bochs虚拟机启动系统的那一刻的寄存器的信息:
在Bochs虚拟机中,BIOS是现成写好的
接下来BIOS会进行检测内存、检测外设等,检测通过后,会初始化好硬件,开始在内存0x000~0x3FF中建立数据结构,中断向量表IVT并填写中断例程。
0x7C00是什么?
BIOS程序的最后一项工作是校验启动盘0盘0道1扇区(CHS方法)的内容,0盘0道1扇区指的是硬盘上最开始的扇区。
盘:指的是磁头,每个盘面都有对应一个磁头,所以用磁头Header表示盘面
道:指的是柱面,柱面指的是所有磁盘上编号相同的磁道的集合
扇区:将磁道等距离划分成一段段的小区间,划分的区域是扇形,所以叫扇区
如果扇区末尾的两个字节分别是0x55,0xaa,BIOS便认为这个扇区中存在MBR程序,便加载到物理地址0x7C00,随后跳转到此地址继续执行。
为什么偏偏是0x7C00的位置呢?有人调查过,原因不在Intel手册里,不是CPU的规范,而是BIOS规范,0x7C00最早出现在IBM PC 5150电脑上,操作系统是DOS 1.0,要求最小内存是32KB,此版本的BIOS按照32KB来研发的。
MBR存放的位置也是有要求的,不能覆盖已有数据,不能过早的被覆盖。MBR的工作是加载内核到指定位置并把控制权交给内核,完成工作后,MBR就没用了,可以覆盖了。
DOS 1.0要求内存为32k,MBR放在内存末尾最方便,所以32K内存换算成十六进制0x8000减去MBR所需要的空间1M--0x400,就等于0x7C00了,加载MBR的位置取决于OS本身所占大小和内存布局。
MBR是什么?
MBR:主引导记录,MBR大小为512B,但需要的空间会大一些,所以留1M的空间给MBR
MBR前446B是启动引导程序GRUB,后64B是分区表,最后2B是结束标识
MBR位于硬盘的0盘0道1扇区的位置
每一个文件系统里都有一个扇区,都有一个启动引导,可以保障我们能在一个主机内安装多个操作系统
第一个MBR程序
这里编写MBR程序用到BIOS的功能调用来实现功能:
;主引导程序
;-----------------------------------------------------
SECTION MBR vstart=0x7c00 ;告诉编译器,起始地址是0x7c00
mov ax,cs ;因为BIOS执行完毕后cs:ip为0x0:0x7c00,所以用cs初始化各寄存器(此时cs=0)
mov ds,ax ;ds、es、ss、fs不能给立即数初始化,需要用ax寄存器初始化
mov es,ax
mov ss,ax
mov fs,ax
mov sp,0x7c00 ;初始化堆栈指针,因为目前0x7c00以下的内存暂时可用
;清屏利用0x06号功能,上卷全部行,则可清屏
;-----------------------------------------------------
;INT 0x10 功能号:0x06 功能描述:上卷窗口
;-----------------------------------------------------
;输入:
;AH 功能号= 0x06
;AL = 上卷行数(如果为0,表示全部)
;BH = 上卷行属性
;(CL,CH) = 窗口左上角的(X,Y)位置
;(DL,DH) = 窗口右下角的(X,Y)位置
;无返回值:
mov ax,0x600 ;上卷行数:全部 功能号:06
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,11 ;cx为串长度,不包括结束符0的字符个数
mov ax,0x1301 ;子功能号13时显示字符及属性,要存入ah寄存器,
;al设置写字符串方式al=01:显示字符串,光标跟随移动
mov bx,0x2 ;bh存储要显示的页号,此处时第0页,
;bl中式字符属性,属性黑底绿字(bl = 02h)
int 0x10 ;执行BIOS 0x10 号中断
;;;;;;;; 打字字符串结束 ;;;;;;;;
jmp $ ;使用程序悬停在此
message db "hello world"
times 510-($-$$) db 0
db 0x55,0xaa
编译:
selph@selph-bochs:~/文档/OS_Study/boot$ nasm mbr.S -o mbr.bin
selph@selph-bochs:~/文档/OS_Study/boot$ ls -l
总用量 8
-rw-rw-r-- 1 selph selph 512 1月 8 02:25 mbr.bin
-rw-rw-r-- 1 selph selph 2530 1月 8 02:24 mbr.S
将MBR写入磁盘
selph@selph-bochs:~/文档/OS_Study$ dd if=./boot/mbr.bin of=./hd60M.img bs=512 count=1 conv=notrunc
记录了1+0 的读入
记录了1+0 的写出
512字节已复制,0.00402708 s,127 kB/s
dd命令参数介绍:
if:要读取的文件
of:要输出到的文件
count:拷贝的块数
bs:指定块的大小
seek:指定要跳过多少块
conv:如何转换文件,追加数据时用notrunc
运行Bochs
打开Bochs,输入c(continue)进入系统,此时,黑框框里显示出了我们打印的字符:
参考资料
- 《操作系统 真象还原》
- 操作系统--保护模式(五):https://www.cnblogs.com/hawkJW/p/13681477.html
- 《操作系统真象还原》读书笔记 第2章:https://blog.csdn.net/AlexSmoker/article/details/104080821
- 主引导记录:https://baike.baidu.com/item/%E4%B8%BB%E5%BC%95%E5%AF%BC%E8%AE%B0%E5%BD%95/7612638