MayOS诞生记录

起因

  起初开始有写操作系统的冲动大概是在大二上学期的时候,在知乎上看到了一个问题:如何自己写一个操作系统。我在问题下面看到了谷月轩师傅的回答,当时觉得这也太帅了,一个人居然可以写出一个直接跑在裸机上的如此复杂而庞大的程序,谷月轩师傅当时在阿里长亭科技工作,以至于我非常想去长亭实习(后来真的如愿以偿2333)。我当时的情况是,成天打ctf逆向做pwn题,刚刚用verilog写完一个cpu,比较熟悉x86和MIPS的汇编,但是对底层的一些细节以及操作系统、编译原理几乎一无所知。于是我就在想,要不我也自己写一个试试,是不是写完了就贼🐂 🍺 ,直接就会Linux内核了?于是带着疑惑我开始了。

经过

  刚开始抱着《30天自制操作系统开始看》,跟着做了几章感觉不对劲,这都9102年了怎么还在用软盘做启动盘,我这好歹也得用u盘做启动盘吧,于是就放弃了,开始换另一本叫《Orange‘s 一个操作系统的诞生》的书看。这本书也不对劲,我跟着写了34章,汇编都快1千行了,怎么还在写汇编??? cry 然后随手往后翻了翻,怎么在内核里还是有一堆汇编写的东西?我当时意识到这本书用汇编做了太多东西,实际上可维护性很差,而且在细节上也没怎么讲清楚,于是就停止了。

  当时正好拿到了长亭的offer,于是这一拖就到了2020年3月。在家无聊,于是开始看清华的操作系统课程设计 ucore,这个项目可以说是相当出名了,本来打算从头跟到尾的,后来卡在了bootloader然后就停止了。但是这期间我看完了一本黑色经典书《操作系统-精髓与设计原理》,算是把基本概念给学了一边,但是对细节还是一头雾水,以为自己没有动手体验过,所以连提问都不知道怎么问。这时我的一个好朋友邢其正,超级牛逼的大佬,保研去北大了,他的毕设当时刚刚做完,大致内容是:用自己写的编译器编译用自己写的语言写的操作系统,然后跑在自己写的CPU上。对你没有看错,强的离谱,相当于手撸一遍整个计算机系统。我当时受到了强烈的震撼,当系统启动的时候,就感觉像是这机器活了过来,有了灵魂。后来我们一起参加了华为毕昇杯编译大赛,撸了一个C语言的编译器出来,拿了国二。为了把这些知识传承下来,我们在学校成立了一个组织叫OWL – OWL Wheel Lab,项目放在了这里ustb-owl,这个组织希望能吸引一些喜欢造轮子的同学,一起写一些fancy的代码,做一些硬核的项目,让我们重新造一个轮子。

  又一拖到了暑假,我滚去上海交大打工去了,认识了我的室友Happy师傅,happy师傅是西电的,强的离谱,他已经写过一个操作系统了,我听完之后十分激动,立刻向他请教心路历程,他说他读了《操作系统真相还原》和毛德操老爷子的《LINUX内核源代码情景分析》这本书,我惊了,毛德操老爷子这本书可以说是相当硬核,里面通篇代码,看了让人直想睡觉,不过至此,我真正下定决心,要亲手完成这个想法,于是开始了MayOS的旅程。

明确目标

由于之前尝试了好几次,我大概有了一些目标:

  1. 一定要用C语言写内核,尽量避免汇编,提高可维护性
  2. 一定要从bootloader开始写,不想用grub这些东西

关于第一点,我困惑了好久好久,我之前看的书里一直都是在用汇编写,一个bootloader几乎要把所有的东西给做完,明明可以用C写的东西也非要用汇编写。最终我在Bran‘s kernel这个文档里找到了答案。在我所看到的资料中,这个文档是唯一一个直接编译出一个纯binary的内核,其他的基本都是编译成ELF文件,然后用汇编去解析ELF。所以我现在只要能让bootloader加载内核到内存里,然后跳到main函数执行就算是成了。

引导

  操作系统就是一个跑在裸机上的程序,我们可以这样理解,CPU就是一个状态机,寄存器的值就是他的状态,我们可以通过设置寄存器的值来修改他的状态。机器在刚启动的时候,操作系统内核还在硬盘里,也就是外存,这显然是没有办法执行的,我们需要想个办法把它加载到内存里。于是前辈们便设计出了MBR和Bootloader。机器在启动的时候会把磁盘上第一扇区的512个字节的内容加载到内存的0x7c00这里,这是BIOS实现的,然后CPU就跳到这里来执行。这512个字节就叫主引导记录(Main Boot Record)即MBR。显然512个字节能做的事情太少了,不足以把内核加载到内存里,因此MBR的工作主要是将Bootloader加载到内存中,由Bootloader负责加载内核,以及做一些初始化操作。

  你在网上搜索写操作系统有关的中文资料,基本都是什么0x7c00,什么0xAA55这些,写个垃圾bootsector,但是这东西顶多算个汇编练习,看来大家都是浅尝辄止。