我们都知道,北航的 MOS 操作系统是从 MIT JOS
移植过来的。(如果你还不知道这一点,说明你既没有认真读过指导书、宣发页等官方资料,也没有认真看过知乎等非官方资料;甚至没有认真参与水群,因为水群里会有学长提到这一点。)
但是我们都不知道的是:MOS 到底是衍生自 JOS
哪一年的版本?毕竟指导书里没有写,学长也没有说。我曾问过高阶助教,高阶说他也不知道,具体年份已经不可考了。他还说,要是发现了
MOS
的问题,大家就一起讨论,然后把它改掉。除非涉及到核心问题,不然考证完全没有必要。
那么我为什么要去问高阶,又要费大力气去考证这个呢?原因如下:
缘起
为什么我会想到考证 MOS
的历史呢?这还要从我重做课下任务说起。我去年做实验的时候,被代码和指导书的各种问题折磨,吃了不少苦;今年做助教的时候,自然希望能改掉实验课的诸多问题——但当时想要改掉的问题已经被我忘光光了。于是我认为,要想发现实验课的不足,就要设身处地,重做一遍课下任务。可惜的是,许多助教并不看重这一点,他们认为,既然去年吃了一遍苦,今年又何必再吃呢?于是他们就没有重做课下,自然也就少了很多发现。
这不,在我重做课下的过程中,由于我对 MOS
理解的加深,越来越多的疑惑逐渐浮出水面。下面我举两个例子:
对于操作系统实验这门课来说,GitHub
上最有价值的并不是指导书,而是学长们的代码!大多数同学在完成实验的时候,或多或少都参考过学长的代码。值得一提的是,考虑到大家课下大量借鉴学长的代码,课下题目约等于送分,加上部分学长代码有
bug,会在课上考试时爆雷;因此课程组在今年开源了 MOS
操作系统代码(含答案)(GitHub • Gitee),大家终于可以参考 100%
正确的官方代码了!
大家在参考学长代码的时候,肯定是越新越好。因为 MOS
每年都有一些小改动,太旧的代码可能没有办法正常工作。但我的目的是考古,所以代码肯定是越旧越好。就这样,在花费了一些时间翻找后,我居然找到了一份
2015 年的 MOS
源码!源码仓库的作者也是旧版指导书仓库的作者,他叫 SivilTaram,根据仓库中遗留的线索推断,应该就是大事表中所说的刘乾学长。下面让我们来好好研究一下这个仓库:
首先,仓库的名字叫做 Jos-mips,说明当时还没有 MOS 这个名字。
仓库的结构和现在的 MOS 很像,但也有一些不同:比如说,当时并没有
kern 目录,那内核代码应该放在哪里呢?
多个 Makefile 中都有 Zhu Like 的版权声明,时间为 2007
年,根据大事表推断,应该是参与 MIPS 移植工作的朱沥可学长。
mips_init() 函数已经成形了。
现在的 vprintfmt() 函数,当时叫做
lp_Print(),意义不明。
使用 github.dev 预览旧版代码
这一天是 2025 年 4 月 8
日,找到这个仓库为我的考证工作打下了坚实的基础。
【内部资料】指导书与代码提交记录
由于我有幸担任了 2025
年操作系统实验助教,因此可以接触到内部资料:指导书和 MOS
两个仓库的提交记录。这些内部资料为考证工作带来了方便,但没有它们也能得出下文的结论。
接下来,让我介绍一下 MIT 的操作系统课程。首先,建议阅读一下 CS
自学指南(csdiy.wiki) 对 MIT 6.S081(原名
6.828)这门课程的介绍。
由于我并不是 MIT
的学生(笑),所以只能通过翻阅官网的方式了解这门课程的历史。幸好官网对校外是完全开放的,我不仅能查阅课程资料,还可以下载各个
Lab 的代码。
在春季学期到暑假的这段时间,我将之前下载的各种资料整理了一下,准备上传到
Internet Archive。由于资料还没有整理完成,所以分了几批上传。但是
IA
的网页上传工具实在是太难用了,上传时不能新建文件夹,只能上传后再移动,在此过程中系统自动生成的文件也删不掉,于是我只好新建了一个
GitHub 仓库来暂存各种资料,并不定期同步到
IA。你可以前往 Internet
Archive 或 GitHub
来查阅我整理的资料。我还请求第三方为它们做了备份,所以有了双重保险,不用怕它们丢失了。
diff -ru 2006/lab4/kern/kclock.c 2007/lab4/kern/kclock.c --- 2006/lab4/kern/kclock.c 2006-10-12 03:56:25.000000000 +0800 +++ 2007/lab4/kern/kclock.c 2007-10-09 23:32:52.000000000 +0800 @@ -1,7 +1,9 @@ /* See COPYRIGHT for copyright information. */ -/* The Run Time Clock and other NVRAM access functions that go with it. */ -/* The run time clock is hard-wired to IRQ8. */ +/* Support for two time-related hardware gadgets: 1) the run time + * clock with its NVRAM access functions; 2) the 8253 timer, which + * generates interrupts on IRQ 0. + */ #include <inc/x86.h> #include <inc/stdio.h>
// translates from physical address to kernel virtual address #define KADDR(pa) \ ({ \ u_long ppn = PPN(pa); \ if (ppn >= npage) \ panic("KADDR called with invalid pa %08lx", (u_long)pa);\ (pa) + KERNBASE; \ })
很显然 JOS 也没有做类型转换。但他们在 2004
年版中加上了(此时这一定义移动到了 kern/pmap.h)。
1 2 3 4 5 6 7 8 9
// translates from physical address to kernel virtual address #define KADDR(pa) \ ({ \ u_long __m_pa = (pa); \ u_long __m_ppn = PPN(__m_pa); \ if (__m_ppn >= npage) \ panic("KADDR called with invalid pa %08lx", __m_pa);\ __m_pa + KERNBASE; \ })
这说明他们很可能是忘记了,后来经过同学提醒加上了。
我觉得这个补丁完全可以 backport(向后移植)给 MOS。
为什么 va2pa()
最后没有加上页偏移?
让我们看看 JOS 的写法(所属文件 kern/pmap.c):
1 2 3 4 5 6 7 8 9
// // Checks that the kernel part of virtual address space // has been setup roughly correctly(by i386_vm_init()). // // This function doesn't test every corner case, // in fact it doesn't test the permission bits at all, // but it is a pretty good sanity check. // static u_long va2pa(Pde *pgdir, u_long va);
// // Checks that the kernel part of virtual address space // has been setup roughly correctly(by i386_vm_init()). // // This function doesn't test every corner case, // in fact it doesn't test the permission bits at all, // but it is a pretty good sanity check. // staticphysaddr_tcheck_va2pa(pde_t *pgdir, uintptr_t va);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
// This function returns the physical address of the page containing 'va', // defined by the page directory 'pgdir'. The hardware normally performs // this functionality for us! We define our own version to help check // the check_boot_pgdir() function; it shouldn't be used elsewhere.
其次,在我“重新发现”JOS
以后,我们需要来一次“重新移植”。虽然大家都知道 MOS 移植自
JOS,但当年的助教们没有保存好关于 JOS 的资料,以至于 JOS
的源代码和资料都没有传下来。后来的助教们只能按照自己的想法,为 MOS
打上各种补丁。考虑到助教们的水平有限(S.T.A.R.
助教全部为本科生),代码质量劣化是在所难免的事。加上 2022 年以前 MOS
的代码没有使用 Git 管理,导致现在连打补丁的历史也几乎不存了。
既然现在已经找到了当年移植所参考的 JOS 源码,那么我们就可以挑选出 JOS
中闪光的地方,“重新移植”到 MOS
已经腐烂的地方上。代码质量不能再劣化下去了,最好能从现在开始有所改观。
最后,考虑到 2003 年版 JOS 漏洞较多,我们可以研究更新版本的
JOS,取其精华 backport 到 MOS,给 MOS
来一次“升级”。考虑到 2004 和 2005 年版不完整,我们可以将 OCW 2006
年版设置为下一个目标。MIT 的操作系统课用 JOS 一直用到了 2018
年,所以理论上来说可以一直“升级”到 2018
年版。当然实际操作起来大概率是到不了的。
我的助教生涯已经结束了。希望后面的助教可以学习一下 MIT 6.828
2003,然后对 MOS 进行改进。
感想
写到这里,回顾我这一学期以来的考证工作,不由得感慨万千。我打算把我的这些感想都留在这里。
操作系统课每年都要培养五百多名学生。这五百多人中,有多少人曾经对 MOS
的历史产生过好奇呢?操作系统课每年都要招收约二十名助教。这二十人中,有多少人对
MOS 的代码质量产生过疑惑呢?
二十年前的助教们学习 MIT JOS,并把它移植到 MIPS
平台上。十年前的助教们照着 MIT
的指导书编写北航自己的指导书,激昂文字,别管看不看得懂,反正激昂就对了。——那些历史已经离我们远去了。那些历史材料没有保存好,是学长们的失误,我们也无法挽回了。
着眼现在。我知道许多同学对 MOS
有所不满,对操作系统这门课程有所不满,乃至对计院、软院的培养方案也有所不满。这并没有什么问题,一方面,上一轮课程改革已是十年以前,经过十年的时间,你
6
系引以为傲的体系结构课已经僵化了。另一方面,考虑到这些年的内卷情况逐渐加重,助教们不得不更加关注自己的保研加分,课程改革缺乏动力。现在体系结构课程已经开始削减助教预算和人数了,未来甚至有取消保研加分的风险。改革已成为了遥遥无期的事情。
修电脑的人脸白白的,看着面善,穿了一件花色衬衫,平易近人的样子。他看了电脑的症状,又看了电脑的型号(Lenovo
Legion R9000K2021H),得出了一个骇人的结论:要换
CPU。他说,拯救者的一系列型号用的都是 AMD 的
CPU,所以都有接触不良的问题。他先让我们摸键盘的中心位置,室友摸到那里有温度,他说是
CPU 在发热;接着,他用手掌按压那里,同时按下电源键——他说他是在试着把 CPU
压回去。不过,他的尝试失败了。
然后他开出了价钱:换 CPU 要
1900。紧接着他用微信联系了一个自称是联想客服的人,问对方换主板需要多少钱,对方答
10000+。我的室友吓了一大跳。
至于我嘛,我是不太信他这一通操作的,想去联想售后先看看。那个人也没阻拦我们,直接告诉我们南门就有官方维修店。我也在高德上查到了,可惜马上就关门了。室友说他不着急用电脑(现在他拿
Mac
当生产力,这台电脑只用来打游戏),于是我想明天先去售后看看。虽然电脑已经过了保修期,但咨询应该是免费的。于是室友听从了我的建议。
我一开始以为是半夜着凉了,但是半夜没有开窗户。后来我猜测,可能是当天早上为了上体育课,穿少了,出门被吹了。总之上完体育课,流鼻涕就变得严重起来。周二周三连流了两天鼻涕,用了好多抽纸。感冒上课精神涣散,容易走神;上机头脑不清,智商下线。周二晚上流着鼻涕写完研讨课的
PPT,周三晚上迷迷糊糊写完 OS 课下。
那么这两位同学是怎么学 OS
的呢?首先是理论课——他们不听理论课。因为理论课太无聊了,让人犯困,所以他们选择不听(好消息是,不听就不会犯困)。另外如果早上起不来,那就干脆不去了。这样做的结果就是作业写不出来,期中考试也一塌糊涂。我和他们聊天的时候,有人还在为信号量的作业焦头烂额。他说自己先尝试补课,如果还是不会再抄学长的博客(结局是哪条道路可想而知)。
两次重启之后,黑白的终端和闪烁的光标并没有如期出现;取而代之的是一幅五彩斑斓的桌面。——KDE!屏幕中央的窗口上写着“Welcome
to KDE Plasma”,正是对我安装成功最好的祝福。但是……这行字太小了。预装的
Windows 的缩放比例被设置成了 250%,而 KDE 对这一点全然无知。默认的 100%
缩放比例,让这个窗口显得如此渺小。
INFO Could not detect the display scale (hDPI). If you are using a high resolution monitor, you can set the insaller scale factor like this: export XINSTALLER_SCALE=2 setenv XINSTALLER_SCALE 2
######## Execution of Pre/Post Installation Tasks Failed ######## Warning: AMD software was installed successfully, but an unexpected status was returned from the following post installation task(s) /tools/Xilinx/Vivado/2023.2/bin/unwrapped/lnx64.o/vivado: error while loading shared libraries: libcrypt.so.1: cannot open shared object file: No such file or directory /tools/Xilinx/Vivado/2023.2/bin/unwrapped/lnx64.o/vivado: error while loading shared libraries: libcrypt.so.1: cannot open shared object file: No such file or directory
运行 Vivado 时同样产生了报错。
1
$ /tools/Xilinx/Vivado/2023.2/bin/vivado
1
/tools/Xilinx/Vivado/2023.2/bin/unwrapped/lnx64.o/vivado: error while loading shared libraries: libcrypt.so.1: cannot open shared object file: No such file or directory
application-specific initialization failed: couldn't load file "librdi_commontasks.so": libtinfo.so.5: cannot open shared object file: No such file or directory
《联合仿真》中说要安装 libtinfo5,但是 Arch Linux 中没有
libtinfo5,应该安装的是——ncurses5-compat-libsAUR!
[Vivado 12-23673] compile_simlib failed to compile for vcs_mx with error in 28 libraries (cxl_error.log, Number of error(s) = 122)
仿真的时候卡住了,点击取消无用,向控制台发送 Ctrl +
C 后仿真中止,并弹出如下报错:
1
[SIM-utils-79] Incompatible GCC compiled simulation library found! Library '/home/triplecamera/Documents/Vivado_lib_VCS' is compiled with GCC version '13.2.1', expected version is '9.2.0'. Please recompile the simulation library or set the correct compiled library path for '9.2.0'.
唯一的解决方法是安装旧版 gcc,我之后会尝试一下。
声音(2.19)
自从装上 KDE
开始右下角的声音图标一直是静音的,今天想把这个问题修好。按照 ArchWiki ALSA
页面中的提示安装了 alsa-utils包,但是在解除静音时失败了。搜了论坛才发现那个页面后面提到了需要安装
sof-firmware包,安装并重启后问题解决。
if loadfont $font; then - set gfxmode=auto + set gfxmode=800x600x32,auto insmod gfxterm # Set the language for boot menu prompt, e.g., en_US, zh_TW... set lang=en_US terminal_output gfxterm fi
转眼到了 P6。我从周六晚上开始写
P6,一直写到凌晨两点;第二天起床接着写,一直写到快要吃晚饭才写完。当时测试样例过了,但是弱测没过。眼看着时间快不够了,我三两下吃完了晚饭,然后就蹬着单车直接去找助教了。(其实助教推荐的做法是自己构造测试数据,然后通过官方的
Analyzer 来评判测试数据的强度,从而不断改进测试数据,最终找出 CPU 中的
bug。)
助教帮我从八点 de 到九点,de
出了两个特别低级的错误。一是我将转发信号常量(常量写在
constants.v
里)从两位扩展到了三位,但是相应的接口都还是两位。于是在作比较的时候发生了隐式转换,最高位被裁掉了。二是我的
DM
有一个接口没有接线,当时预留了接口却没有准备好有关的信号,等到准备好信号之后却把接线的事情忘了。出人意料的是,仿真时
ISE 没有报一个警告。
当助教帮我 de 完 bug
的时候,教室里就剩一两个人了,助教们要收工了。看助教忙到这么晚,我感觉有些对不起助教。于是我问助教如何才能让
ISE
的语法检查更严一些。助教告诉我,可以试试综合。于是我试着点了一下综合,结果五彩斑斓的调试信息夹杂着花式警告顿时喷涌而出。但是呢,综合的缺点是耗时比较长,所以助教建议在
P8 以前不要综合。