一、前置知识:
1.内存是存储数据的地方,给出一个指令信号,内存可以返回该地址对应的数据。
2.CPU 的运行方式就是不断从内存中取指令,并执行。
3.寄存器从决定CPU从内存哪个地方取指令,这个值会不断进行+1操作,或者由某条跳转指令指定其值是多少。
二、内存映射
CPU地址总线的宽度决定了可访问的内存大小。一些外设也会通过总线的方式访问。在地址中划出一些区域给一些外设使用,比如显存、硬盘等等。可以理解为内存中的这块位置就是显存,那块位置就是硬盘控制器。我们在相应的位置上读取或者写入,就相当于在显存等外设的相应位置上读取或者写入,就好像这些外设的存储区域,被映射到了内存中的某一片区域一样。这样我们就不用管那些外设了,关注点仍然是一个简简单单的内存。这就是内存映射
三、实模式下的内存分布
四、为什么从BISO开始执行程序
CPU 将段基址寄存器 cs 初始化为 0xF000,将偏移地址寄存器 IP 初始化为 0xFFF0,根据实模式下的最终地址计算规则,将段基址左移 4 位,加上偏移地址,得到最终的物理地址也就是抽象出来的 PC 寄存器地址为 0xFFFF0。也就是CPU 的 PC 寄存器被强制初始化为 0xFFFF0。也就是IOS 被映射到了内存的某个位置,并且开机一瞬间 CPU 强制将自己的 pc 寄存器初始化为 BIOS 程序的入口地址,从这里开始 CPU 马不停蹄地向前跑了起来。
五、BIOS内的程序
它是一条跳转指令
jmp far f000:e05b
意思是跳转到物理地址 0xfe05b 处开始执行(联系实模式下的地址计算方式)
地址 0xfe05b 处开始,便是 BIOS 真正发挥作用的代码了,这块代码会检测一些外设信息,并初始化好硬件,建立中断向量表并填写中断例程。从这以后也就是 BIOS 的最后一项工作:加载启动区。
六、什么是0x7c00
了解加载:加载是指把某设备上(比如硬盘)的程序复制到内存中的过程。翻译过来就是:BIOS 程序把启动区的内容复制到了内存中的某个区域。
了解启动区:BIOS 会按照顺序,读取这些启动盘中位于 0 盘 0 道 1 扇区的内容。(对于内存,我们给出一个数字地址就能获取到该地址的数据,而对于磁盘,我们需要给出磁头、柱面、扇区这三个信息才能定位某个位置的数据,都是描述位置的一种方式)
这 0 盘 0 道 1 扇区的内容一共有 512 个字节,如果末尾的两个字节分别是 0x55 和 0xaa,那么 BIOS 就会认为它是个启动区。如果不是,那么按顺序继续向下个设备中寻找位于 0 盘 0 道 1 扇区的内容。如果最后发现都没找到符合条件的,那直接报出一个无启动区的错误。
BIOS找到启动区后把这512个字节的内容全部(以指令的方式 eg.in,out)复制到内存的0x7c00这个位置。复制完之后程序就接管了接下来的流程,BIOS的使命就此结束。后面操作系统就开始跑了。所以复制完以后接下来是一个跳转指令,正是这样,PC 寄存器的值变为 0x7c00,指令开始从这里执行。
总结来说就是: BIOS 把启动区的 512 字节复制到内存的 0x7c00 位置,并且用一条跳转指令将 pc 寄存器的值指向 0x7c00。
BIOS 负责加载了启动区,而启动区又负责加载真正的操作系统内核
回顾:
- 按下开机键,CPU 将 PC 寄存器的值强制初始化为 0xffff0,这个位置是 BIOS 程序的入口地址(一跳)
- 该入口地址处是一个跳转指令,跳转到 0xfe05b 位置,开始执行(二跳)
- 执行了一些硬件检测工作后,最后一步将启动区内容加载到内存 0x7c00,并跳转到这里(三跳)
- 启动区代码主要是加载操作系统内核,并跳转到加载处(四跳)