亲宝软件园·资讯

展开

【自制操作系统11】中场休息之细节是魔鬼

闪客sun 人气:1

如果你有幸看到这一章,那么恭喜你,你已经完成了整个操作系统的一多半了,而且如果你前面的东西都完全掌握了,那后面无非就是顺水推舟的事情了。本章不做继续的讲解,而是将之前的知识进行回顾,并把相似的知识点做对比。同时我也将到目前为止最大的感悟 细节是魔鬼 分享给大家。

一、到目前为止的程序流程图

为了让大家清楚目前的程序进度,画了到目前为止的程序流程图,如下。其实就是截至到内存管理这一块

 二、回顾一下我们都做了些什么

 这里列出整个系列到目前为止的目录,刚好也可以作为索引方便大家阅读了

  • 【自制操作系统01】硬核讲解计算机的启动过程
  • 【自制操作系统02】环境准备与启动区实现
  • 【自制操作系统03】读取硬盘中的数据
  • 【自制操作系统04】从实模式到保护模式
  • 【自制操作系统05】开启内存分页机制
  • 【自制操作系统06】终于开始用 C 语言了,第一行内核代码!
  • 【自制操作系统07】深入浅出特权级
  • 【自制操作系统08】中断
  • 【自制操作系统09】中断的代码实现
  • 【自制操作系统10】内存管理系统

  第 01 和 02 部分没有实质性的代码,但却是学习一个新东西的必要开始,也就是解除困惑,梳理流程。它告诉了我们 计算机的启动过程,也就是计算机按下开机键之后,初始的程序计数器 IP 的值指向了哪里,初始执行的 BIOS 中写死的程序做了什么,又跳转到了哪里。这让我们至少拥有了能够写出一个让电脑按下开机键之后不报错并成功跳转到我们所写的代码的程序。之后的代码,就是在这两部分所创造的基本框架中添油加醋完成的。

  第 03 部分是 读取硬盘中的数据。我们所写的程序肯定是放在硬盘里的,需要加载到内存中才能被 CPU 一条一条取指令并执行。虽然 BIOS 帮我们完成了启动区的加载任务,但这只是很小的一部分,我们不能及期望于将操作系统所有代码都写到启动区这 512 字节中,所以启动区里的代码需要实现把更多在硬盘中的程序加载到内存中,这样一个关键任务。

  第 04 部分是 实模式到保护模式,这也是第一次 CPU 厂商和操作系统 打配合。我们只需要按照 CPU 要求的,比如 写好段描述符结构、加载 gdt、将 cr0 的 pe 位置 1 等,就可以顺利开启 CPU 的保护模式,利用其保护模式的特征了。

  第 05 部分是 开启内存分页机制,这又是一次 CPU 厂商和操作系统打配合的案例,也是按照 CPU 要求的步骤,把该有的数据结构(页目录表和页表)写好,就可以开启分页机制,利用其提供的分页特征了,由于打配合的案例越来越多,一会我单独总结。

  第 06 部分是我们 第一次使用 C 语言 来做事,也可以看出,之前用汇编语言把那些 杂事 都处理干净了,真正写内核主代码时,再把 C 语言请过来。我们学高级语言的人,包括我自己,都是认为越底层的语言越高端。不过从我们这个系列的角度看,汇编做的都是杂事,或者 C 语言不屑于做的事情,而 C 语言做的,才是“高大上”的事。所以学习这个系列,包括我自己写这个系列,也是让我从两个角度来审视这个问题了,也再也不会去争论到底高级语言高级,还是低级语言高级的事情了。

  第 07 部分是 深入浅出特权级,这部分也是没有代码。这部分就提到了我们常说的 内核态、用户态,只不过是从细节入手,讲述了特权级是怎么进行 保护、以及怎么进行 跳转 的。至于保护,自然有一套公式规则来判断,至于跳转,也是有一套跳转规则,也就是什么特权级,在什么情况下,能跳到什么特权级下。当然这只是简单的描述,实际情况要复杂得多。

  第 08 和 09 部分是 中断,从硬件讲到了软件,同时也指出了一个重要的思想,就是 操作系统是个死循环,是靠中断驱动 的,我们的操作系统就是随时等待着各种中断进来,然后执行相应的中断处理程序,为整个操作系统的运行方式做了个思想准备。

  第 10 部分是 内存管理系统,我们实现了简单的四个 内存池 的管理,并最终实现了一个 申请内核内存空间 的函数,该函数自动在内核的虚拟内存池中和物理内存池中找到可用的内存页,并将其映射到页表中。这让我们对内存管理有了个初步的认识。这块就不再需要更多的 CPU 配合操作系统的部分了(当然基础的都是需要的,我是说不再需要额外的),有点 纯软件设计 的感觉了,之前的部分或多或少都有跟硬件打交道的部分。我们慢慢地,将与硬件打交道的部分完善好,最后便只剩下软件的天下了,也是我们软件工程师越来越熟悉的部分。

  这也慢慢地,与我们的已有的知识接轨,什么时候全串起来了,你就是高手了。技术领域的高手,不是看的高望得远,而是基础扎实,但要扎实到随便把自己已有的知识进行关联,就能得出一个很深刻的结论。

三、CPU 与操作系统打配合

我们不只一次提到了 CPU 与操作系统打配合的地方,现在我们就一起来串一串,把之前这种配合写在一起对比一下。 

配合项 操作步骤1 操作步骤2 操作步骤3
开启保护模式  打开 A20 加载 gdt 将 cr0 的 pe 位置 1
加载 gdt 内存某位置初始化全局描述符表 gdt lgdt 指令将 GDT 起始地址存入 gdtr 寄存器 将 cr0 的 pe 位置 1
开启分页 内存某位置初始化页表 pde、pte 将页目录起始地址存入 cr3 寄存器 将 cr0 的 pg 位置 1
开启中断 内存某位置初始化中断描述符表 idt,并初始化 pic lidt 指令将 idt 起始地址存入 idtr 寄存器  
特权级      

请自己默默体会其中的相似之处。

步骤相似,必然也存在着结构相似,下面我把到目前为止用到的结构列出

  至于后面的内存管理池的结构,那是我们软件自己定义的,而上面列出的这些,是硬件定义的,也就是说作为程序员的我们,必须接受。

四、谈谈自己的理解与感悟

  这里我没有说谈谈自己对操作系统的理解,因为我觉得这里谈的可能超出了操作系统范畴。另外,我所谈的真的是 到目前为止 的理解与感悟,并不是我已经把后面的知识学完了再来补的,可能都学完了再回忆自己在这个时候的感悟,已经不准确了。

  高级语言与低级语言没有高下之分。我们普遍有个印象,就是外行人认为高级语言更高级,低级语言更低级,而内行人则相反。但我现在到觉得,它们根本没有高下之分,只是不同角度罢了。如果从功能上说,低级语言能完成高级语言做不了的事情,也可以解释高级语言无法解释的原理,从这点看,低级语言显得更高级。但如果从实际做的事情来看呢?本操作系统中,低级语言(也就是汇编)只是做了一些进入内核之前的杂事(当然一部分原因也是因为 c 语言做不了),一旦进入内核,只要能用 c 语言完成的,就绝对不用汇编了。从这个角度看,高级语言做的事情又比低级语言更高端一些。所以我的感悟就是,再也不去争论谁高谁低了,而只是说什么事情更适合什么语言来做而已。我觉得就单单是这个感悟,对我目前的 Java 语言帮助就很大,我不再觉得 Java 比 C 语言或是汇编语言更 low 了。

  细节是魔鬼。这真的是我最大的感悟,没有之一。我起初学习操作系统的时候,总是想尽快,想着有些东西只要理解就可以了,没必要去扣太多的细节。其实这是错误的,正确的做法是,先把细节扣得死死的,之后回过头看的时候就再也不看细节了,开始注重总结与理解。而不是先就不扣细节,想着总结与理解。第一点是因为,细节掌握得足够了,你会发现其他的好多知识点是通用的,根本不用看就可以理解了,比如 加载 gdt、加载 idt、以及加载分页,如果你不是在看加载 gdt 这个部分时把细节吃透,后面两个知识点你每个都要重新理解一遍,而且理解得还不一定透彻,所花的总时间,还不如你去花大量时间把第一个吃透,而后面两个非常快速地就可以理解到很深入的地步。

  越简单越透彻,越透彻越简单。这里的每一个知识点,我一开始都觉得比天都难,而在真正理解之后,却变得很简单,甚至有点无聊。你可能觉得这是废话,但有的时候,有些知识点我理解的糊里糊涂,理解得也很复杂,跟别人也说不明白,当时我觉得是知识点就很复杂,给被人讲肯定是讲不明白的,得人家自己去理解。但后来我发现,无论多复杂的事,只要你真正掌握并且抓到本质了,是真的很简单,甚至你可以给一个不搞技术的人讲明白(这个明白当然不是真正的懂哈)。就比如说内存管理这一块,我看的时候甚至一度要放弃,但后来经过对每一行代码,每一个结构都扣出来剖析之后,我竟然觉得这块简单得不要不要的,无非就是取一个虚拟地址,取一个物理地址,再把它们加到页表中对应起来。不过这块也同时说明了 细节是魔鬼。倘若你一开始就看到这句话,比如从某个一分钟搞懂操作系统的软文,你的理解就是“取一个虚拟地址,取一个物理地址,再把它们加到页表中对应起来”,和我扣完细节之后的理解一样,但你觉得这是真正的一样么?所以,不是因为它简单所以你理解的透彻,而是因为你理解的透彻,它就变得简单起来了。

   所以,细节真的是魔鬼,千万不要企图一篇文章就搞懂操作系统这种事,我也可以把这篇文章改编成一个类似的文章,但如果你不去花时间扣细节,你今后一定会把更多的时间耽误在这里的,这个账总会有一天找到你的头上。

写在最后:开源项目和课程规划

如果你对自制一个操作系统感兴趣,不妨跟随这个系列课程看下去,甚至加入我们,一起来开发。

参考书籍

《操作系统真相还原》这本书真的赞!强烈推荐

项目开源

项目开源地址:https://gitee.com/sunym1993/flashos

当你看到该文章时,代码可能已经比文章中的又多写了一些部分了。你可以通过提交记录历史来查看历史的代码,我会慢慢梳理提交历史以及项目说明文档,争取给每一课都准备一个可执行的代码。当然文章中的代码也是全的,采用复制粘贴的方式也是完全可以的。

如果你有兴趣加入这个自制操作系统的大军,也可以在留言区留下您的联系方式,或者在 gitee 私信我您的联系方式。

课程规划

本课程打算出系列课程,我写到哪觉得可以写成一篇文章了就写出来分享给大家,最终会完成一个功能全面的操作系统,我觉得这是最好的学习操作系统的方式了。所以中间遇到的各种坎也会写进去,如果你能持续跟进,跟着我一块写,必然会有很好的收货。即使没有,交个朋友也是好的哈哈。

目前的系列包括

  • 【自制操作系统01】硬核讲解计算机的启动过程
  • 【自制操作系统02】环境准备与启动区实现
  • 【自制操作系统03】读取硬盘中的数据
  • 【自制操作系统04】从实模式到保护模式
  • 【自制操作系统05】开启内存分页机制
  • 【自制操作系统06】终于开始用 C 语言了,第一行内核代码!
  • 【自制操作系统07】深入浅出特权级
  • 【自制操作系统08】中断
  • 【自制操作系统09】中断的代码实现
  • 【自制操作系统10】内存管理系统

 微信公众号

  我要去阿里(woyaoquali)

加载全部内容

相关教程
猜你喜欢
用户评论