三十天自制操作系统-day1

BIOS主导

BIOS —— 基本输入输出系统
计算机启动过程: BIOS按照“启动顺序”,把控制权转交给排在第一位的存储设备:硬盘。然后在硬盘里寻找主引导记录的分区,这个分区告诉电脑操作系统在哪里,并把操作系统被加载到内存中,然后你就能看到经典的启动界面了,这个开机过程也就完成了。

内存映射

利用内存映射文件技术,系统可以在内存空间中为文件保留一部分空间,并将文件映射到这块保留空间,一旦文件被映射后,操作系统将管理页映射缓冲以及高速缓冲等任务,而不需要调用分配、释放内存块和文件输入/输出的API函数,也不需要自己提供任何缓冲算法

实模式下的内存分布实模式下的内存分布

从BIOS程序开始执行

BIOS 里的信息被映射到了内存 0xC0000 - 0xFFFFF (BIOS自有空间)位置,其中最为关键的系统 BIOS 被映射到了 0xF0000 - 0xFFFFF 位置。那么为什么一开机就执行了这一段,而非从头执行?

CPU 从内存的PC 寄存器中取出地址值并执行 。BIOS 程序的入口地址也就是开始地址是 0xFFFF0(人家就那么写的),也就是开机键一按下,一定有一个神奇的力量,将 pc 寄存器中的值变成 0xFFFF0,然后 CPU 就开始马不停蹄地跑了起来。没错,接下来这句话,可能就是你找了很久的答案,请做好准备:

在你开机的一瞬间,CPU 的 PC 寄存器被强制初始化为 0xFFFF0。如果再说具体些,CPU 将段基址寄存器 cs 初始化为 0xF000,将偏移地址寄存器 IP 初始化为 0xFFF0,根据实模式下的最终地址计算规则,将段基址左移 4 位,加上偏移地址,得到最终的物理地址也就是抽象出来的 PC 寄存器地址为 0xFFFF0。

BIOS中的程序

BIOS 程序里到底写了啥?

我们分析一些主要的。入口地址是 0xFFFF0,实模式下内存的下边界就是 0xFFFFF。入口地址处是个跳转指令,跳到一个更大范围的空间去执行自己的任务。0xFFFF0 处存储的机器指令,翻译成汇编语言是:jmp far f000:e05b ,意思是跳转到物理地址 0xfe05b 处开始执行

地址 0xfe05b 处开始,便是 BIOS 真正发挥作用的代码了,这块代码会检测一些外设信息,并初始化好硬件,建立中断向量表并填写中断例程。这里的部分不要展开,这只是一段写死的程序而已,而且对理解开机启动过程无帮助,我们看后面精彩的部分,也就是 BIOS 的最后一项工作:加载启动区。

0x7c00

加载在计算机领域就是指,把某设备上(比如硬盘)的程序复制到内存中的过程。加载启动区则是BIOS 程序把启动区的内容复制到了内存中的某个区域。

什么是启动区呢?即使你不知道,你也应该能够猜到,一定是符合某种特征的一块区域,于是人们把它就叫做启动区了,那要符合什么特征呢?先不急,不知道你有没有过设置 BIOS 启动顺序的经历,通常有 U 盘启动、硬盘启动、软盘启动、光盘启动等等,BIOS 会按照顺序,读取这些启动盘中位于 0 盘 0 道 1 扇区的内容

至于磁盘格式的划分,本篇不做讲解,总之对于磁盘,我们需要给出磁头、柱面、扇区这三个信息才能定位某个位置的数据,用于描述位置。

接着说, 这 0 盘 0 道 1 扇区的内容一共有 512 个字节,如果末尾的两个字节分别是 0x55 和 0xaa,那么 BIOS 就会认为它是个启动区。如果不是,那么按顺序继续向下个设备中寻找位于 0 盘 0 道 1 扇区的内容。如果最后发现都没找到符合条件的,那直接报出一个无启动区的错误。

BIOS 找到了这个启动区之后把这 512 个字节的内容全部复制到内存的 0x7c00 这个位置。怎么复制的?当然是指令啦。哪些指令呢?这里我只能简单说指令集中是有 in 和 out 的,用来将外设中的数据复制到内存,或者将内存中的数据复制到外设,用这两个指令,以及外设给我们提供的读取方式,就能做到这一点啦。

启动区内容此时已经被 BIOS 程序复制到了内存的 0x7c00 这个位置,然后呢?这个其实也不难猜测,启动区的内容就是我们自己写的代码了,复制到这里之后,就开始执行呗,之后我们的程序就接管了接下来的流程,BIOS 的使命也就结束啦。所以复制完之后,接下来应该是一个跳转指令吧!没错,正是这样,PC 寄存器的值变为 0x7c00,指令开始从这里执行。

咦?不知道你有没有发现,我们似乎不知不觉又把之前的一句魔法语言翻译成人话了,开头我们说:

BIOS 把控制权转交给排在第一位的存储设备。

所以这句话是什么意思呢?就是 BIOS 把启动区的 512 字节复制到内存的 0x7c00 位置,并且用一条跳转指令将 pc 寄存器的值指向 0x7c00。你看,这不是也没多几个字嘛,就把这个问题说得明明白白,简简单单。

哦,对了,现在似乎就剩下一个问题了,为什么非要是 0x7c00 呢?好问题,当然答案也很简单,那就是人家 BIOS 开发团队就是这样定的,之后也不好改了,不然不兼容。为什么不好改?我们看一个简单的启动区 512 字节的代码。

; hello-os
; TAB=4

		ORG		0x7c00			;程序加载到内存的 0x7c00 这个位置
		
; FAT12格式软盘专用

		JMP		entry
		DB		0x90	;
		DB		"HELLOIPL"		;启动区名称(8字节)
		DW		512				;每个扇区大小(必须为512字节)
		DB		1				;簇大小(必须为1个扇区)
		DW		1				;FAT的起始位置(一般从第一个扇区开始)
		DB		2				;FAT的个数(必须为2)
		DW		224				;根目录大小(一般为224项)
		DW		2880			;该磁盘的大小(必须为2880扇区)
		DB 		0xf0			;磁盘的种类(必须是0xf0)
		DW		9				;FAT的长度(必须是9扇区)
		DW		18				;1个磁道有几个扇区(必须为18)
		DW		2				;磁头数(必须是2)
		DD		0				;不使用分区,必须是0
		DD		2880			;重写一次磁盘大小
		DB		0,0,0x29		;意义不明,固定
		DD		0xffffffff		;卷标号码
		DB		"HELLO-OS   "	;磁盘的名称(11字节)
		DB		"FAT12   "		;磁盘格式名称(8字节)
		RESB 	18				;空出18个字节

;程序主体

entry:
		MOV		AX,0			;初始化寄存器
		MOV		SS,AX
		MOV		SP,0x7c00
		MOV		DS,AX			;段寄存器初始化为 0
		MOV		ES,AX
		MOV		SI,msg
putloop:
		MOV		AL,[SI]
		ADD		SI,1
		CMP		AL,0			;如果遇到 0 结尾的,就跳出循环不再打印新字符
		JE		fin
		MOV		AH,0x0e			;指定文字
		MOV		BX,15			;指定颜色
		INT		0x10			;调用 BIOS 显示字符函数
		JMP		putloop
fin:
		HLT
		JMP		fin
msg:
		DB		0x0a,0x0a		;换行、换行
		DB		"hello-os"
		DB		0x0a			;换行
		DB		0				;0 结尾
	
		RESB 0x7dfe-$			;填充0512字节
		DB	0x55, 0xaa			;可启动设备标识

我们可以看到`ORG 0x7c00就是启动区加载位置,这行汇编代码表示把下面的地址统统加上 0x7c00。正因为 BIOS 将启动区的代码加载到了这里,因此有了一个偏移量,所以所有写启动区代码的人就需要在开头写死一个这样的代码,不然全都串位了。正因为所有写操作系统的,启动区的第一行汇编代码都写死了这个数字,那 BIOS 开发者最初定的这个数字就不好改了。

再看最后一行:DB 0x55, 0xaa验证了我们之前说的这 512 字节的最后两个字节得是 0x55 0xaa,BIOS才会认为它是一个启动区,才会去加载它。

启动区中的代码

BIOS 用很少的代码就把 512 字节的启动区内容加载到了内存,并跳转过去开始执行。那这 512 字节的启动区代码,是不是也可以把更多磁盘中存储的操作系统程序,加载到内存的某个位置,然后跳转过去呢?

没错,BIOS 负责加载了启动区,而启动区又负责加载真正的操作系统内核。

由于用于启动盘的磁盘是人家写操作系统的厂商制作的,俗称制作启动盘,所以他也肯定知道操作系统的核心代码存储在磁盘的哪个扇区,因此启动区就把这个扇区,以及之后的好多好多扇区(具体取决于操作系统有多大)都读到内存中,然后跳转到开始的程序开始的位置。跳转到哪里呢?这个就不像 0x7c00 这个数那么经典了,不同的操作系统肯定也不一样,也不用事先规定好,反正写操作系统的人给自己定一个就好了,别覆盖其他关键设备用到的区域就好。

启动过程回顾

  1. 按下开机键,CPU 将 PC 寄存器的值强制初始化为 0xffff0,这个位置是 BIOS 程序的入口地址
  2. 该入口地址处是一个跳转指令,跳转到 0xfe05b 位置,开始执行
  3. 执行了一些硬件检测工作后,最后一步将启动区内容加载到内存 0x7c00,并跳转到这里
  4. 启动区代码主要是加载操作系统内核,并跳转到加载处

经过这连续的四次跳跃,终于来到了操作系统的世界了,剩下的内容,可以说是整个操作系统课程所讲述的原理

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值