操作系统真象还原 读书笔记02--初见MBR

selph
selph
发布于 2021-01-12 / 976 阅读
0
0

操作系统真象还原 读书笔记02--初见MBR

本篇内容介绍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虚拟机启动系统的那一刻的寄存器的信息:

image-20210108013236242

在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)进入系统,此时,黑框框里显示出了我们打印的字符:

image-20210108025035143

参考资料


评论