iT邦幫忙

2021 iThome 鐵人賽

DAY 30
4
Software Development

予焦啦!Hoddarla 專案起步:使用 Golang 撰寫 RISC-V 作業系統的初步探索系列 第 30

予焦啦!附錄:那些作業系統的巨人們與參考資料

沒有人是一座孤島,而技術與軟體亦然。早在 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 <ccutler@csail.mit.edu>
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 git@github.com:solbjorg/oberon-riscv.git
cd oberon-riscv
git clone git@github.com: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 本身的回顧與結論,另一篇則是關於整個鐵人賽的心得分享。無論如何,各位讀者,我們明天再會!


上一篇
予焦啦!附錄:詭異的時間中斷(timer interrupt)擱置位元(pending bit)
下一篇
予焦啦!結論與展望(一):Hoddarla 專案的過去、現在與未來
系列文
予焦啦!Hoddarla 專案起步:使用 Golang 撰寫 RISC-V 作業系統的初步探索32

尚未有邦友留言

立即登入留言