JackOS开发日记 2:最近的进度以及操作系统启动流程


本文是JackOS开发日记的第2篇,记录了最近几日的开发情况,并且介绍了操作系统的启动流程

JackOS开发日记的第2篇

JackOS开发日记 2:最近的进度以及操作系统启动流程

分页是真的绕呀

1. 最近的进度

从广州回来之后,在学校的隔离酒店隔离了三天,总算是出来了。上一次写出来了MBR的程序,算是达到了一个小的milestone。接下来要写的,就是BootLoader了。BootLoader说白了,其实就是放在磁盘的一段程序,和我们写的HelloWord没啥区别。只不过相比于HelloWord被操作系统加载内存中,BootLoader这个程序由MBR中的程序加载到内存中。BootLoader运行结束之后,就是操作系统开始运行,所以BootLoader的主要任务就是为操作系统准备环境。因此,BootLoader中要完成一系列任务。

所以启动的流程其实就是一个接力的过程,CPU上电初始化之后,CS:IP被强制初始化去运行BIOS,BIOS运行结束后会运行MBR中的程序,而MBR中的程序由于只能放在第一个MBR扇区中,所以MBR中的程序的大小是有限制的,没法完成所有的操作系统运行前的准备。所以MBR的主要任务就是读取磁盘中的操作系统到内存,并且为操作系统准备运行环境,这个程序一般称为BootLoader。

因为我最终的目标就是具有分段、分页机制的、运行在32位保护模式下的操作系统,所以BootLoader中要干的事就包括:16位实模式切换到32位保护模式、准备GDT、开启分段机制、准备页表、开启分页、加载操作系统内核到内存,最后再跳转到操作系统内核。

所以BootLoader其实挺复杂,主要原因就是因为操作系统本身是运行在32位保护模式下的,操作系统本身没有办法实现诸如模式切换这类需要汇编才能实现的功能。

所以这几天的主要就是把第一版的BootLoader写出来了。主要是分页的代码部分的代码实在是太绕了,因为是二级页表,所以真的难写。关于内存分页和分段的机制,未来一定要写博客记录一下,因为真心挺绕的,尤其是二级页表下的分页。

BootLoader中开启内存分段的部分

BootLoader中开启内存分页的部分

2. 操作系统启动流程

操作系统的启动目前有两种方式,第一种传统的MBR启动,第二种是UEFI启动。

1. MBR启动

上面其实已经大概说过了MBR启动。MBR启动操作系统的流程是一个接力的过程,流程如下:

  • CPU上电初始化之后,CS:IP被强制初始化到1M内存的最后16字节处。最后16字节其实是一个绝对跳转指令jmp far,跳转的目的地是主板BIOS的起始地址。这一流程由硬件完成
  • jmp far跳转到主板BIOS,此后CPU开始执行主板BIOS程序。
    • BIOS程序首先会检查计算机的硬件系统。如果缺少内存这样至关重要的硬件,那么计算机无法启动,计算机就会结束运行。
    • 在检查完硬件之后,主板BIOS程序会扫描主板上其他硬件的BIOS。注意,BIOS程序并不是只有主板有,每个硬件上都会有一个ROM芯片,而硬件的ROM芯片上就存放着硬件的BIOS程序。硬件的BIOS程序和硬件电路紧密结合,提供了基础硬件的访问功能。因此,主板BIOS会扫描硬件的BIOS程序,而后把硬件的BIOS程序的地址加载到中断向量表IVT中,从而为后续的程序提供了硬件访问能力。
    • 最后,主板BIOS会以此检查磁盘,并读取磁盘的第一个扇区,即以此检查每个磁盘的MBR扇区,以检查其中是否有可以运行的程序。如果在某个磁盘上找到了可以运行的程序,那么BIOS就会把该磁盘的第一个扇区(MBR扇区)完全读取到内存中来,而后使用jmp far跳转到MBR程序运行。
  • MBR程序的主要任务是读取磁盘中的操作系统到内存中,并且为操作系统准备运行环境。
    • 操作系统启动的英文单词是boot,起源于bootstrap这个单词。bootstrap的本意是鞋带。bootstrap这个单词有一句谚语:pull oneself up by one's bootstraps。字面意思是拽着鞋带把自己拉起来,这当然是不可能的事情。最早的时候,工程师们用它来比喻,因为计算机启动是一个很矛盾的过程:必须先运行程序(为操作系统准备环境),然后计算机才能启动,但是计算机不启动就无法运行程序!早期真的是这样,因此工程师想出了一个办法,就是把一小段程序装进内存用来引导操作系统(即为操作系统准备运行环境),然后计算机才能正常运行。所以,工程师们把这个过程叫做”拉鞋带”,久而久之就简称为boot了。因此,开机的过程
    • MBR的主要工作就是为操作系统运行准备环境,而我们的操作系统运行在32位保护模式下,以段页式方式管理内存。因此我们的MBR具体需要完成以下的任务:
      • 16位实模式切换到32位保护模式
      • 准备GDT、开启分段机制
      • 准备页表、开启分页、
      • 加载操作系统内核到内存
      • 跳转到操作系统内核
  • 最后,接下来的事,就完全是操作系统的事了。包括线程的创建、管理,内存的管理,所以此后,我们就正式开启了操作系统的开发。

2. UEFI启动

传统的MBR启动的缺点就是MBR分区中只能放446字节的启动代码来加载BootLoader,这个在硬件越来越复杂的当下显然是没法很好的满足我们的需求。于是几个大厂(Google,微软……)联合在一起,就提出了操作系统新的启动流程,即UEFI启动。

以MBR方式启动知道加载操作系统内核前都需要写汇编代码,这个难度就很高了,非常不方便修改。一直到操作系统内核才开始用C语言开发。因此为了尽早使用C语言进行开发,UEFI在CPU的L1、L2、L3缓存上为C语言运行准备运行环境,而后使用C语言开发。

我对UEFI其实并不是很了解,只能说这么多。不过和MBR简单直接相比,UEFI来完成操作系统开机的开发可就难了不少,因此我这次初次开发操作系统,还是怎么简单怎么来,直接利用MBR来完成操作系统启动。

终于,现在距离开发操作系统只有一步之遥~


文章作者: Jack Wang
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Jack Wang !
 上一篇
Paper阅读笔记 0: 初心 Paper阅读笔记 0: 初心
本文作为Paper阅读笔记的第0篇,记录了我为什么要写Paper阅读笔记专栏,以及未来这一专栏文章的组织形式
下一篇 
JackOS开发日记 1:最近的进度以及开发工具链和目标成果 JackOS开发日记 1:最近的进度以及开发工具链和目标成果
本文是JackOS开发日记的第1篇,记录了最近几日的开发情况,并且介绍了开发工具链,以及JackOS预期达到的目标
  目录