文章目录

  • 前言
  • 一、BIOS引导程序
  • 二、 解读setup模块
  • 三、 system模块代码
  • 1. head.s是system中的第一个模块。
  • 2. main.s模块
  • 四、 总结



前言

根据BIOS中的程序看操作系统的启动过程。通用计算机的运行思路是读取一个程序,该程序规定了计算机的运行规范,随后当计算机有不同的输入时,其可根据这套规范产生不同的输出。


一、BIOS引导程序

BIOS源程序 bios启动程序_系统程序

计算机会根据CS:IP组合成的地址,读取ROM中的BIOS(基本输入输出系统)程序,该程序会检查RAM、键盘、显示器、软硬磁盘等硬件,若这些都正常,则开始读取操作系统。从磁盘0磁头0磁道1扇区读取512个字节放入内存的0x7c00处,该扇区内存放操作系统的引导程序。该引导程序的目的是将操作系统程序全部读入内存。

BIOS源程序 bios启动程序_操作系统_02

操作系统的引导程序为bootsect.s,首先该引导程序将自己从0x7c00处挪动到0x90300处,腾出一块空间来,接着跳转到go标号代表的代码段中。

BIOS源程序 bios启动程序_操作系统_03


在go代码段中,继续读取操作系统程序setup。使用读磁盘扇区的中断,从第二个扇区开始连续读4个扇区,放在0x90200处(0x200为512),也即bootsect程序的后面。读完之后跳转到ok_load_setup处。

BIOS源程序 bios启动程序_操作系统_04


在ok_load_setup代码段中,用0x10中断显示字符,bp表示显示的字符在内存中的位置,即在显示器上的光标处显示“Loading system…”。显示完字符后开始读入system模块。

读完system模块后,跳转到setup模块,至此bootsect程序执行完毕。

总结一下,bootsect程序一开始将setup模块读入内存,接着显示开机画面,然后将system模块读入内存,最后跳转到setup模块,将控制权交给setup。

二、 解读setup模块

BIOS源程序 bios启动程序_BIOS源程序_05


首先用0x15号中断获取内存的大小,得到的值存在ax中,随后将ax中的值放入0x90002处。由于intel PC机在首次出现时内存为1MB,因而扩展内存为大于1MB的内存。

操作系统要管理内存,需知道此台计算机的内存大小。setup的作用在于获得计算机硬件的基础信息,从而能让操作系统对计算机硬件建立一种表来进行管理,比如让操作系统对内存的管理初始化,在之后能知道内存的某个位置放了什么东西。

随后移动操作系统,从代码实现来看,每次移动2B,每轮重复0x8000次,0x8000*2=0x10000B=64KB,所以共移动8轮。

操作系统起初放置在0x10000-0x8ffff内,现将其移动到0x00000~0x7ffff内,由此可见一开始bootsect将自己移动到0x90300处的原因。

setup初始化操作系统,并挪动了操作系统后,会退出并将控制权给操作系统程序。

  • 寻址方式改变

下述代码是setup模块最后做的事,改变寻址方式。

mov ax, #0x0001
mov cr0, ax
jmpi 0, 8
  1. 由于cs和ip均为16位寄存器,依靠cs<<4 + ip的寻址方式只能寻址1MB空间,显然不能满足现代计算机的寻址需要。接下来要从16位机模式切换到32位模式,也即保护模式。
  2. 16位机和32位机的本质区别在于cpu的解释程序不一样,对于cs和ip所代表的地址不在以“cs<<4 + ip”方式解释。将cr0的第一位置为1即可将cpu切换电路,切换到保护模式。此时cs和ip均为32位寄存器。

BIOS源程序 bios启动程序_操作系统_06

  • 此时cpu的解释方式为gdt。gdt是一张表,称作全局描述表。 gdt表会在setup中初始化,每一个表项有64位。
  • CS被称作选择子,CS中存放着表的下标,而表中存放着基址。此例中为CS存放8,即表的8号位置。从表的8号位置读出基址,与ip的偏移量相加得到存储地址。
  • 中断入口地址也要根据idt来查表。

BIOS源程序 bios启动程序_初始化_07


根据gdt表中的内容查找得到段基址为0x0000,与ip的偏移量0x0000相加跳到0地址处。

三、 system模块代码

有之前的引导程序可知,程序必须按一定的次序执行才能使计算机正常开机,system模块也是一样。为了确保system模块是按规定好的次序执行,要用makefile。

使用makefile,将操作系统源码变成Image(镜像),该镜像指示了操作系统源码的执行次序。将镜像放到0磁头0磁道1扇区。

Image是树状结构,父结点依赖子节点,只有当子结点全部建立好,整棵树才建立好。

1. head.s是system中的第一个模块。

  • head.s中有如下代码
call setup_idt
call setup_gdt

head.s会重新初始化gdt和idt,因为之前的gdt和idt是为了跳转使用。此外head.s中使用的汇编语言会有变化,会使用32位的汇编代码。

  • head.s最后会跳转到main.c
    如何从汇编跳转到c?

BIOS源程序 bios启动程序_初始化_08


c会编译成汇编执行,因而从汇编跳转到c较为容易。将main最后入栈,在head.s执行完设置页表后ret指令会将main弹出,程序跳转到main执行。main是一个永远不会返回的程序。

2. main.s模块

main的工作就是为内存、中断、设备、cpu、时钟等内容的初始化。

  • 以men_init.c为例

此初始化程序初始化了称为men_map的表格,操作系统通过该表格实现对内存的管理,表格中的0代表未使用。初始化过程为将内存一页一页的置为0(存疑),end_men为存放在0x90002处的内存大小。内存最前面放置操作系统。

四、 总结

bootsect、setup、head、main完成了将操作系统读入内存并初始化操作系统。初始化的原因是操作系统是管理硬件的软件,要实现对硬件的管理需要对各个硬件建立一个数据结构。