予焦啦!附录:那些作业系统的巨人们与参考资料

没有人是一座孤岛,而技术与软件亦然。早在 Hoddarla 抵达系列文本篇最後的基本命令列功能之前、甚至在任何笔者的疯狂构想之前,就早已有无数的资讯科技如坚固的地壳一般:历史久远、深厚坚固,而又富有强大的动能。

不予以浏览的话,只能说是一种傲慢。可惜的是,由於笔者不是专职於研究之身,没有办法遍览群籍,只能够诚惶诚恐地提出本篇,分享笔者有意识到的相关主题。其中大部份与 Golang 或 RISC-V 有关系。

Golang 篇

GopherCon 2020 AMA 活动当中,Golang 管理者 Sameer Ajmani 如此表示:「在 CNCF(云端原生计算基金会)里面,3/4 的专案是使用 Golang 实作的……这与社群的动能有关、与想要分享知识与建立关系的人们有关,他们想要建立一个美好未来,人们将可以开发基础架构等级的软件。Golang,我承认我们很幸运,因为社群选择了我们。但我们被选择是因为我们适合人们所欲完成之事,而且形成了动能。」

而後,Golang 基础架构团队的 Carmen Andoh 也提到一些 Golang 可以取经的其他专案:Rust 能够静态的避免资料竞赛的问题;作业系统在调解资源竞争上有很强的分离机制。

面对 Golang 兼具效能与强大的执行期特徵,应该除了笔者之外也有很多人会联想到作业系统吧。然而,也因为语言本身已经非常仰赖了执行期环境,以至於这语言本身很难成为开发作业系统的首选。

OSDev Wiki 上的相关材料

OSDev 有个 Golang 的页面,很简略的描述选择 Golang 开发作业系统的优劣。一来,它有颇为庞大的执行期;二来,在 Golang 里面很难做直接的型别转换,尤其是整数和指标之间的互换,偏偏这对於低抽象层的设计又至关重要。

文章中并且附上一篇 2017 年的演讲投影片,据我所知,关於 Golang 开发作业系统这个超级偏门的兴趣,这是最早的一篇文献。

Achilleas Anagnostopoulos 先生的演讲

A.A. 氏是 Geckoboard 的资深工程师。这间公司提供一个 SaaS 资料图表视觉化方案。看起来相当不错。

与笔者一开始强调 RISC-V 的机器模式类似,A.A. 氏也从 x86 的 Ring-0 切入,以澄清基本定义:所谓使用 Golang 写作业系统核心,其实就是在最低或是比使用者层级还低的权限等级运行 Golang 程序的意思。

理想上,这麽做的好处是能够省略一些不需要的抽象层(效能考量),还有独占一些资源。接下来探讨适合与否的部份,他也提到,垃圾回收和执行期可能都是大型路障,但理想上 Golang 的丰富工具链应该能够带来一些开发的便利性。

再来他开始针对 x86 进行开发。使用 Grub2 当作 bootloader 在 VirtualBox 上运作。他好不容易打通了一些初期的 runtime.g0 相关设定(使上一点 Golang 黑技),之後,就一头撞上了更多问题。因为 A.A. 氏这里没有如笔者在 Hoddarla 里面先做虚拟记忆体的处理,导致他没有记忆体配置可以用,那就当然所有进阶的 Golang 功能都没有了。

所以他的结论是:当然可以考虑使用 Golang 开发作业系统核心!但是显然与其他语言、更适合的语言相比困难很多。而且应该要在早期阶段避免记忆体配置。当记忆体配置 OK 之後,事情就会比较简单了。

後来他也持续维护了一阵子的 PoC 在他的 github 上,但已经三年没有更新了。无论如何,这个专案有 2.3K 个星星,是蛮了不起的成就。

与之相比,Hoddarla 才刚起步,年龄上还无法与之相比,但是专案结构上,我们与执行期之间的关系让笔者得以使用滚动式维护,至今维持了一年多,要比较维护的容易程度的话,应该是不遑多让。又,我们从最一开始的执行期初始化就已经先打通了虚拟记忆体的部份,显然是比较好的一种作法。

还有一个洁癖理由,笔者特地打通了 opensbi/riscv64 系统组合,但他们都还只是寄生在 GOOS=linux 底下,不太漂亮。

其余连结

  • bare-metal-gophers:也是 A.A. 氏的专案,但已经疏於维护了。
  • EggOS:404。
  • Goose, mykernel:都是一些最小型的尝试。

TamaGo

严格来说这并不宣称自己是一个作业系统专案,但仍然笔者认为这个专案的出现,很需要放在文献回顾章节之中。F-secure 公司制造一些 SoC 产品,而这些硬体上面可以直接运行 TamaGo 框架。

TamaGo 使用一套修改过的 Golang 工具链,支援 GOOS=tamago,笔者猜想这部份仅就所支援的系统组合的工夫应该与本系列第一章差不多,但其他如何直接裸机(bare-metal)支援他们的硬体,就是紮实功夫了。

之所以要做得这麽激进,核心概念是

  • 编出来的 Golang 程序直接运行在硬体上,无须其他作业系统协助。所有的驱动程序与执行期也都使用 Golang 写成。
  • 硬体支援时,可以自动载入,无须其他启动载入器(bootloader)协助。
  • 这间公司企图移除所有非 Golang 的相依性。

其余的概念以及提出的修正,都在内部架构页面描述。确实是 Hoddarla 的标竿。

Hoddarla 与这个专案本身,或许目前看起来相同之处还大於相异之处也说不定。但是我期待 Hoddarla 可以成为所有 RISC-V 机器的 Hoddarla,但 TamaGo 目前看起来,从 ARM 的生态系与厂商做事情的方法来看,应该也不太可能成为 ARM SoC 的 TamaGo 了。

biscuit

MIT 的博士 Cody 作为毕业论文题目的一个作业系统专案,他的目的是检验 Golang 撰写作业系统的可行性,并提出效能量测的数据。最後的成品是一个支援 x86-64 且相容於 POSIX 标准的小型作业系统。专案页面列出的特徵有:

  • 多核心系统支援
  • 多执行绪
  • TCP/IP
  • 虚拟记忆体支援写时复制(copy on write)、分页等功能
  • 有日志功能的档案系统且支援多项非同步功能
  • 支援 SATA 硬碟
  • 支援网路卡

程序码本身基於 Golang 1.10,现在已经两年没有更新,疏於维护了。不过论文在 2018 年获得 OSDI 期刊接受,其中提供了许多资讯,是笔者开发 Hoddarla 至今的此时还无法完全理解的;接下来分为数个段落,很大略地介绍论文中的诸多洞见。

使用高阶语言撰写 POSIX 核心的优势与成本

这是论文原主题(The benefits and costs of writing a POSIX kernel in a high-level language)的译名。作者以评估的角度出发,所呈现的 Biscuit 作业系统则只是评估的副产品,比较对象是 C 语言写成的 Linux。摘要也简单翻译如下:

这篇论文的目的是探讨一个问题:使用比 C 语言更高阶的语言来实作作业系统核心是否合理?比较的标准包含额外效能成本、实作上的挑战、程序是否易写(programmability)以及安全性的优势。也就是说本篇论文即是使用附带垃圾回收机制的高阶语言实作单一(monolithic)POSIX 核心之後的评估报告。

这篇论文贡献了 Biscuit,一个使用 Golang 实作了足够多的 POSIX 功能的核心,其中包含:虚拟记忆体、记忆体映射(mmap)、TCP/IP socket、
附有纪录的档案系统(logging file system)以及非同步轮询(poll)。`Biscuit` 使用了大量的 Golang 功能如闭包(closure)、频道(channel)、对照表(maps)、介面(interface)、垃圾回收的 heap。主观上,这使得实作变得简单许多。最具挑战的课题则是,如何处理核心过量使用 heap 的问题,但 Biscuit 得益於 Golang 的可分析性以处理这个问题。

在两项(nginx 与 redis)大量需要核心功能的基准测试(benchmark)之下,Biscuit 核心占用的 CPU 时间比到达 13%;nginx 活动造成的最长的垃圾回收时间为 600 微秒;比较 Golang 与 C 版本的 Biscuit 的几乎相同的系统呼叫、页面缺失错误、上下文交换,Golang 版本慢了 5% 到 15%。

笔者博士念到被退学,所以实在是忍不住羡慕这个拟题与摘要的策略。这分明就是自干作业系统的新奇专案,但只要包装得当,也能够让顶尖期刊认可贡献与新颖度。第一段先打新颖牌,因为虽然网路上大家常常战语言,但是认真写文章做实验战到期刊去的可不多;第二段是第一张贡献牌,就是彰显作者团队有能力做出这麽大份量的 POSIX 核心;第三段是第二张贡献牌,代表这个实验有留下客观数据供参考。

鸡蛋里挑骨头

真的要挑的话也还有得挑。第一段提的四个评估目标,第一个客观点由第三段涵括,第二、三是主观点,则在第二段提出。但主观的部份就比较可以质疑了,怎样算是比较好写?追溯 github 开发史(当然,同侪审查时可能无法检验这个 repo),他们这个专案从开始到论文发出,花了四年的时间,这样算是好写吗?当初 Linux 0.01 版张贴出来的时候,时值大学三年级的 Linus Torvalds 花了多少时间写成类 Unix 核心释出?

第一笔 commit 不能直接从底部捞,因为这个是分岔出来的 Golang 历史。找寻作者 Cody Cutler:

commit e603656259d82de6159afa9cef2a3c0814080aaa
Author: Cody Cutler <[email protected]>
Date:   Wed Nov 26 00:28:53 2014 -0500

    initial commit
    
    JOS bootloader. everything is in C. ha!
    
    probably only compiles on OpenBSD

实作上的挑战,怎样算是挑战?占多少总开发时间?第二或第三的挑战不存在吗?第四个评估目标,安全性,更是没有提及,我猜想作者实验室没有办法支援更多人力来做攻击平面(attack surface)的评估。

客观的评估点也不是没得挑。作者描述的 C 版本 Biscuit 并没有公开。

Introduction、Related Work 与 Motivation

作者先强调 C 在作业系统领域的绝对地位,然後描述定义高阶语言(HLL)不被领域专家青睐、相关实作不完整亦不多的事实,之後再顺势提出,正因为如此我们才应该好好评估一下。

其实 HLL 本身实在像是稻草人一样的概念。引用的文献是 Linus Torvalds 飙骂 C++。但除了本篇作者之外,有谁把 C++ 和 Golang 放在一起然後描述他们是高阶语言?比较主流的高阶语言定义,历史上来讲,是 Fortran 和 C 这个世代的语言。

於是带出 Biscuit。之後的前人文献考察(Related Work)与切出来的动机(Motivation)一节,列举了一些高阶的系统语言,并且特别描述内建垃圾回收代表的正面意义(减低设计者的认知负担,比较少记忆体相关的 bug)与负面意义(效能损耗,设计者可考虑的选项遭到限缩)。

架构 Overview

+-------+ +-------+
| nginx | | redis |
+-------+ +-------+
===================
+-----------------+
|     Biscuit     |
+-----------------+
|   Go runtime    |
+-----------------+
|    Shim layer   |
+-----------------+

完全没有 C 语言,只有 Golang 和组合语言。Shim 层是为了支援 Golang 执行期所需要的一些原本由核心服务的东西,以组合语言写成。事实上,这就是采用既有系统组合便宜行事的不得不为;Biscuit 因此缺乏一些系统相依或是架构相依的档案可以堂而皇之地加入自己真正需要的东西,如我们稍早替换 SysAllocnewosproc 里面的系统呼叫一样。

此外,作者也浏览了以下课题,并提出重点问题:

  • 排程:核心内使用 Goroutine 管理使用者行程
  • 中断:要小心 Goroutine 的上下文交换
  • 多核心同步:大部分使用 Golang 内部机制,少数则额外实作 read-lock-free 同步锁
  • 虚拟记忆体:Biscuit 应该是自行管理,而非如 Hoddarla/ethanol 这样子仰赖 Golang 竞技场
  • 档案系统:档案系统相关的系统呼叫像是一笔一笔的交易且有日志系统,并有不同功能的快取
  • 网路堆叠:POSIX socket API

提及的限制包含:

  • 虽然可以运行大部分的 C 语言程序,但许多功能仍然没有实作(这应该是指一些系统呼叫没有实作)
  • 没有优先权的排程,因为仰赖 Golang 执行期的 goroutine 排程
  • 不能运行太多核心或是 NUMA
  • 虚拟记忆体无法 swap 到硬碟上
  • 没有使用者权限控制、档案存取控制
  • 没有乱数位址配置

略过後续篇章的结论、讨论与未来工作

之後的篇章就开始陆续填入血肉,整个 Biscuit 的实作样貌也就越显清晰。作者总共实作了 58 个系统呼叫,好让使用者空间能够运行 nginx 和 redis,以及除此之外的其它微型测试。大致上来说可以作到仅比 Linux 慢 10%,理论上是演算法最佳化可以触及的范围,而不是语言之差造成的决定性差距。

作者们强调这篇论文希望帮上忙的是,让人们可以多一些资料来决定,应该使用高阶语言或是 C 来撰写作业系统核心。如果 CPU 执行效率或是记忆体利用率是至高考量,那麽 C 都是首选;只有在其它因素加入进来之後,高阶语言的使用才比较合理。主观上来说,作者使用愉快(pleasant)这个字眼形容他们开发 Biscuit 的感觉。Golang 生态圈内也有工具能够静态分析原始码,使得一些 heap 使用问题可以更容易被侦测出来。

说到未来工作就比较尴尬一点了,显然也是讲场面话。想要更好地处理 heap、想要修改 Golang 执行期以更符合 Biscuit 的需求、想要扩张到更多核心去,最後一项则是想要看看 heap 保留机制是否能够作为参考,回头改良 C 语言的核心。

也许他们实验室有其它後续吧,但 Biscuit 专案本身已经没有动静了。笔者曾经送交一个 commit 修补当时的文件,关於 QEMU 启动所需要的步骤。确实使用起来很震撼,毕竟笔者的想法(RISC-V 与 Golang 作业系统)在 2017 初期刚萌芽,结果在 2018 年就看到这篇来自 MIT 博士的论文,不得不说有点泄气,但若是没有这些强者的背影可以参照,人只会以为自己很厉害而已。

Biscuit 小结

以 Golang 撰写作业系统核心的尝试而言,Biscuit 绝对是现在历史上的最高峰。但笔者觉得一座山,高者高之,要跟它在同一立足点竞争,却是未必。可以让 Hoddarla 参考的部份有之,Hoddarla 想要刻意回避的部份有之。这一点就等明日的结论再整理吧。

RISC-V 篇

与前篇不同的是,不限定开发语言而改为限定计算机架构的话,那这个部份就是非常典型的 RISC-V 作业系统回顾了。笔者不敢说自己看过很多,只能分享一些有玩过或是曾经碰巧看到过的作业系统专案。

Linux

Linux 这个作业系统核心专案实在是不需要笔者再多说了,基本上所有最新的改动都发生在这里。在 2017 年由 Palmer Dabbelt 作为 RISC-V 核心分支的维护者,於 4.17 版本开始,RISC-V 这个架构堂堂正正的加入了 Linux 所支援的众多计算机架构中的其中之一。

顺带一题,我们晶心科技的前一世代 CPU nds32,也在这个版本附近加入 Linux 上游。回首看看当初公司决定加入 RISC-V 阵营,陆续打造出本世代的 25/27、45 系列,当初真的是充满勇气且成功的决策。

把玩 Linux 最简单的方法是透过已有支援的发行版,如:

或是使用建置系统(build system)生成可用的系统映像:

有监於 Linux 绝对是有史以来最成功的作业系统之一,笔者实在没有什麽好评论的。然而它在後 Intel 时代是否也能够持续维持这麽庞大的存在感呢?笔者不否认很期待看到帝国陨落,但短期内无论如何是不可能的。事实上,笔者曾在 2016 年的 ContainerCon Japan 最後的座谈提出一个比较科幻的问题:再强大的帝国都有陨落的一天,与座的各位社群先进(当时最大咖的应该是 Greg K.H.),觉得 Linux 的历史是否能够延续到人类文明之外呢?当时充满了小人物的兴奋心情的笔者,光是问出问题就很紧张了,其实也没有太有印象讲者的回应为何;依稀记得是有一位举证说 Linux 已经抵达地球之外了,所以时间上,佐以 AI 的强大功能,发达之後也未可知。

笔者在这个系列中也参照过 Debian 系统;最後的外部中断篇,更是有一个从头打造的简单版 Linux。需要正规学习且能在工作派上用场的作业系统知识的话,从这个方向下手准没错。

BSD

BSD 系列比起 Linux 更能算是失落的 Unix 血脉的嫡传,但笔者也只有非常有限的经验。无论如何,也趁这次回顾的机会统整一下。

FreeBSD

FreeBSD 相当早期的阶段就由 Ruslan Bukin bootstrap,虽然是使用 GNU 工具链就是了。说是早期,因为差不多是 Palmer Dabbelt 正在准备 4.15 版本的 Linux 上游化工程的时候。 2017 年底,在台北北投的 BSDTW 研讨会上面,Ruslan 先生就曾经分享他的移植经验。当时应该有找他攀谈,但也不记得具体内容了,应该是有听说 FreeBSD 的动向并有些初期尝试失败,想直接跟他问出一些细节之类的;总之研讨会结束之後,有试着将他移植的 FreeBSD 运行在 QEMU 上,期间也跟他 Email 来回数次,不过最後还是因为跟笔者本身业务无关而没有真的玩过多少。

所以这里就来试试吧!

根据本节标题的连结不难取得预编的硬碟映像,

wget https://download.freebsd.org/ftp/snapshots/VM-IMAGES/14.0-CURRENT/riscv64/Latest/FreeBSD-14.0-CURRENT-riscv-riscv64.raw.xz
xz -d FreeBSD-14.0-CURRENT-riscv-riscv64.raw.xz

但问题是,连结中路径里的 OpenSBI 和 U-Boot 都是 FreeBSD 里面的套件管理员安装的路径,我们不太好取得。幸好,先前从 Debian container 里面拿到的 U-Boot 可以用,我们自己编的 OpenSBI 也能够使用,所以

qemu-system-riscv64 -machine virt -m 2048M -smp 2 -nographic -bios /home/noner/FOSS/hoddarla/Hoddarla/misc/opensbi-0.9/build/platform/generic/firmware/fw_jump.bin -kernel /home/noner/FOSS/aur/apt/artifacts/uboot.elf -drive file=FreeBSD-14.0-CURRENT-riscv-riscv64.raw,format=raw,id=hd0 -device virtio-blk-device,drive=hd0

...

FreeBSD/riscv (freebsd) (ttyu0)

login: root
Oct  6 06:15:29 freebsd login[614]: ROOT LOGIN (root) ON ttyu0
Last login: Wed Oct  6 06:06:13 on ttyu0
FreeBSD 14.0-CURRENT (GENERIC) #0 main-n249761-9aa29457d55: Thu Sep 30 06:13:25 UTC 2021

Welcome to FreeBSD!

Release Notes, Errata: https://www.FreeBSD.org/releases/
Security Advisories:   https://www.FreeBSD.org/security/
FreeBSD Handbook:      https://www.FreeBSD.org/handbook/
FreeBSD FAQ:           https://www.FreeBSD.org/faq/
Questions List: https://lists.FreeBSD.org/mailman/listinfo/freebsd-questions/
FreeBSD Forums:        https://forums.FreeBSD.org/

Documents installed with the system are in the /usr/local/share/doc/freebsd/
directory, or can be installed later with:  pkg install en-freebsd-doc
For other languages, replace "en" with a language code like de or fr.

Show the version of FreeBSD installed:  freebsd-version ; uname -a
Please include that output and any error messages when posting questions.
Introduction to manual pages:  man man
FreeBSD directory layout:      man hier

To change this login announcement, see motd(5).
root@freebsd:~ #

算是一偿夙愿了。

OpenBSD

这个笔者就没有什麽经验了,但看起来移植者更专注在实体板子的支援上。

Oberon RISC-V port

Oberon 专案是个教学型计画,里面涵盖模拟器、工具链与系统。笔者列出的连结是由 Rikke Solbjørg 移植的版本,他继承许多前人的 RISC-V 移植的尝试,并维护目前这个曾经上过 Hacker News 的 repo。使用方法非常简单如下:

git clone [email protected]:solbjorg/oberon-riscv.git
cd oberon-riscv
git clone [email protected]:solbjorg/oberon-riscv-emu.git
cd oberon-riscv-emu
make
make -C .. imagerv
./risc --fullscreen --led ../imagebuild/Oberon.dsk

有 SDL 的模拟桌面环境,虽然笔者搞不太懂该如何使用。值得尊敬。笔者之後若要持续发展 Hoddarla,应该会考虑借镜 Oberon 桌面系统的部份。因为其他的自干作业系统内容当中,通常不太会着墨於此。

除此之外,毕竟真的不太熟悉,笔者就没有什麽可以分享的了。

失落的 Unix 血脉?你把 xv6 放到哪里去了?

说老实话,这系列至今,笔者还真的没有参考过任何 xv6 的概念与程序码。也许之後再行参考。

Rust

所有这个圈子的人都知道,Rust 是作业系统界的明日之星,大有可为,Linux 也快要开始能够接受 Rust-based 的驱动程序了。但笔者不是 Rust 信徒,因为它与笔者心目中的简洁之美相去甚远。所以写作至今,笔者也是一行 Rust 都看不懂的状态。

但仍然姑且有两份已知的作业系统专案,一个是社群导向的 Redox,这个一直都还有积极在开发;另一个是非常富教育意义的部落格系列,该文作者非常谦卑的定标为作业系统之冒险

结论

笔者很庆幸,目前为止,在 RISC-V 与 Golang 这个交集内能够找到的作业系统专案并不多,Hoddarla 可算是一个非典型的怪异专案,当然也很有可能到头来只能成为不可数数量程序码当中的一小撮余烬。

这并不意味着 Hoddarla 享有任何先驱者优势,事实上正好相反:已经有太多作业系统专案远远走在前方,开拓着它们自己的时代与战场;笔者一直以来,真的是一直以来,除了看着它们的背影,试图循着它们开辟的道路跌跌撞撞地前进以外,都没有其它的选择。Hoddarla 现在开始偏离了历史已知的正道,准备走出自己的路,想必那也会像这个系列文呈现的轨迹一样,再怎麽想要抬头挺胸地走,仍然还是会歪七扭八的醉汉走路吧。

严格来说,如果一点也不想成为电脑的主人,那麽 Windows、Mac、Android、iOS 系统都提供了乌托邦。但有另外一群人,就像你我一样,会被 Jserv 的话语轻易地搧动,走上荆棘之路。

Jserv 老师毕竟也常常在 FB/Twitter/PTT 出没,所以也不能排除他本人看到这段话的可能性。我总是想像他的轻笑,「你们这个都还是鳗鱼饭里面的软刺,真正的荆棘还在後面咧!」压力就很大,但还是只能按照自己的步调走下去。

虽然今天就是铁人赛三十篇系列文的官方结束,但笔者的 Hoddarla 系列还有明後天最後两篇,分别是这一系列冲刺过後的 Hoddarla 本身的回顾与结论,另一篇则是关於整个铁人赛的心得分享。无论如何,各位读者,我们明天再会!


<<:  Day 27 : 模型解释 Shap

>>:  Day 24 : 插件篇 03 — 如何让 Obsidian 自动推荐关联笔记 (上)?使用 Breadcrumbs 查看有哪些相关笔记可以连结

Day 07 Style

第七天~ 我们昨天写了个 Hello World 出来, 但是这只是单单把字给秀出来而已, 假如我们...

就学时多参加企业实习,了解产业型态

这篇第30篇是IT邦帮忙铁人赛最後一篇发文,但系统在第29篇就恭喜我完赛,我当作是官方提醒我最後一小...

Day 19 Flask Cookie

讲完前端之後,就一定要说到 Cookie 跟 Session 这两个东西了,这两个是什麽东西呢?又能...

【Day 22】- 将朋朋的 Instagram 贴文全部按赞owo(实战 Selenium 自动点击 Instagram 好友贴文赞 2/2)

前情提要 前一篇带各位透过汇入 Session 达到不必输入帐号密码便可登入的目的。 开始之前 今天...

【Day09】Git 版本控制 - GitHub Repository

了解什麽是 GitHub 後,就来将先前新建好的 Local Repository 与 GitHub...