開源專案:使用 Rust 寫一個相容 Linux 的核心
關注「 Rust程式設計指北 」,一起學習 Rust,給未來投資
大家好,我是螃蟹哥。
前些時間,Linus 表示不排斥 Linux 開發使用 Rust。今天為大家帶來一篇介紹 Rust 寫 Linux 核心的文章。
注意,用 Rust 寫一個相容 Linux 的核心,目的不是取代 Linux,而是為了好玩、學習和練習。
近幾個月來,我一直在研究一個新的作業系統核心 Kerla [1] ,這是一個使用 Rust 從零開始實現的,希望在 ABI 級別相容 Linux。換句話說, 支援執行未經修改的 Linux 二進位制檔案 !
開源專案地址:http://github.com/nuta/kerla
我已經實現了基本功能: fork(2)
and execve(2)
,檔案操作, initramfs,TCP/UDP sockets, 訊號, tty/pty, 管道, poll 等。
你可以通過 ssh 進入 Kerla,它執行在臨時建立的 Firecracker 微 VM 上,這是專門問你建立並啟動的。(你本地也可以通過以下命令進入)
$ ssh [email protected]
在這篇文章中,我將分享我在作業系統核心中使用 Rust 的第一印象。
01 Rust 在業務領域的成功
Rust 是一門 深受使用者喜愛的 [2] 程式語言,使用它,你可以高效開發出可靠且效能好的軟體。
Rust 的所有權概念和型別系統可以讓你專注於修復邏輯錯誤,而不是痛苦的記憶 error 和 race。 enum
強制你處理所有可能的 input/ouput 模式。此外,它的構建系統( cargo
)和 IDE 支援( rust-analyzer [3] )真的很棒。
生產環境慢慢有使用 Rust 的案例: AWS 的輕量級 VMM [4] , npm registry 的部分模組 [5] 以及 許多其他公司 [6] 。Rust 無疑是 C/C++ 之外一個很好的選擇(但並不一定是替代 C/C++)。
02 Rust 在核心領域
近年來,用 Rust 重寫現有軟體一直受到關注。
Bryan Cantrill 在 《是時候用 Rust 重寫作業系統了嗎?》 [7] 的演示中,建議採用混合方法:
因此,一種混合方法是,你保留現有的基於 C/assmbly 的核心,就像我們多年來一直採用的方式一致。然後,你允許開發基於 Rust 的東西、基於 Rust 的驅動程式、基於 Rust 的檔案系統、基於 Rust 的核心軟體。
這就是在 Rust for Linux [8] 工作的人的情況。你可能聽說過最近 LKML 上建議的 補丁 [9] 。
我完全同意,重寫現有的,龐大的,功能豐富,健壯的作業系統核心不是一個好主意。然而,我想到了一個問題:從零開始,用 Rust 寫一個類 UNIX 的實用作業系統核心的利弊是什麼?它看起來像什麼?這就是我開始這個專案的原因。
為了探索 Rust 在核心領域的長處和短處,我決定開發一個實用的、特定的,與 Linux 相容的核心,可用作虛擬計算機上的[" Faas"](http://en.wikipedia.org/wiki/Function_as_a_service "" Faas"")執行環境。為此,你只需要很少的裝置驅動程式(例如 virtio [10] ),我們就不必支援高階 Linux 功能(如 eBPF)。此外,與其他長期執行的工作負載相比,核心崩潰不會是一個關鍵問題。
03 核心領域使用 Rust 有好處嗎?
在我看來,有!
核心有一點特別: panic!
會導致系統崩潰,記憶體分配故障應處理而不是 panicking,隱藏控制流和隱藏分配通常不能接受。
Rust 的優勢也適用核心領域。我最喜歡的例子是無空指標處理問題:如果指標是無效的(即 Option<NonNull<T>>
),你不能解引用它,直到你明確處理空( None
)情況!此外,使用 新型別習語 [11] ,你可以區分核心和使用者指標。
但是,我們在核心領域使用 Rust 時仍然存在一些問題:
分配失敗會 panic!
這個問題在 Linus Torvalds on the Linux kernel's Rust support patch [12] 中提到的。
我們來看看 Arc::new() [13] 的定義,一個建立執行緒安全參考計數指標的構造器:
pub fn new(data: T) -> Arc<T>
看起來超級直觀,對吧?然而,它有一個隱含的 panic 情況:內部緩衝分配失敗。
處理分配故障很無聊。當我開始一個 C 專案時,第一步是寫我自己的 xmalloc(3) [14] ,這樣我不需要檢查結果是否是 NULL。如果它耗盡了記憶體, 直接 crash 即可,沒什麼大不了的。我只需要生成一個新的有更多記憶體的 VM 或或在亞馬遜上購買新的記憶體。
然而,在核心空間中, kernel panic
是一件大事。我們應該設法從低記憶體狀態中恢復過來,以保持系統的工作狀態。沒人想看藍屏。
在我的專案中,為了利用現有的便利 crates,我決定走目前的 Rust 路:允許因分配失敗而 panic。這就是說,在不久的將來,我確實認為需要使用(或編寫我們自己的)動態分配容器的可故障版本。
更大的二進位制大小
Resea [15] ,一個基於微核心的作業系統,使用 C 編寫的,僅僅 845KiB,包括使用者地應用程式, 如 TCP/IP 伺服器,英特爾基於 hypervisor 的 VT-x 和 Linux ABI 模擬支援。
相比之下,Kerla 映象需要大約 1.1 MiB,不包括 initramf。雖然極簡的微核心和單片核心有著相反的理念,但在我看來,Rust 實現往往大於 C 實現。
雖然有 一些大小優化方法 [16] 可用,但在極其受限的裝置(例如 1 類裝置 [17] )中,這可能是一個問題。
make menuconfig 丟失
作業系統核心有許多引數。在 Linux 核心中,可以使用配置工具進行配置,如 make menuconfig
和 make xconfig
。在 Rust 中,我們有 特性標誌 [18] ,可啟用/禁用 crate 中的特性。但是,如果你想要更改硬編碼引數(如心跳間隔),該怎麼辦?你是否通過環境變數和 env! [19] 巨集來配置它?不, 它只接受一個字串。
我們可能需要一個功能豐富的構建配置機制,就像 Cargo 中的 Kconfig [20] 一樣。
這些問題遲早會解決!
我要強調,這些問題並非源於語言設計。
Rust 正在不斷改善。關於分配失敗,人們已經開始著手處理它(見 跟蹤問題 [21] )。此外,你不必使用 liballoc
, heapless crate [22] 將是一個很好的選擇。
04 Rust 在核心領域的優點
儘管有我上面提到的問題,但我覺得用 Rust 寫核心一定是富有成效的。Rust 用在核心領域我最喜歡的優點:
-
Rust 讓我有信心:其型別系統和所有權、生命週期概念使我意識到,我的實現編譯不通過,因為它違反了共享的 XOR 可變規則,例如,一旦編譯通過,能正常執行就一點都不奇怪(如沒有討厭的資料競爭和危險的空指標)。
-
強制處理所有的 input 模式 :
enum
和模式匹配 (match
) 讓你可以處理所有可能的情況,不會有漏掉的情況。 -
它具備寫核心的特性: packed struct [23] , raw pointers [24] , 改進的內聯彙編語法 [25] , embedding assembly files [26] 等等。
-
便利的
no_std
(獨立) crates 可用 : bitflags 操作庫 [27] , 基於陣列的 vector 和字串實現 [28] , 多生產者和多消費者佇列 [29] 等等。 -
內建單元測試:在 Rust 中編寫和執行單元測試非常簡單。此外,由於 custom_test_frameworks [30] 功能,你可以在 QEMU 或真實機器上執行單元測試。
-
開發者友好的超棒工具鏈: linter [31] 幫助你編寫友好的 Rust 程式碼, 交叉編譯 [32] 很容易,而 rust-analyzer [33] 可以把你喜歡的編輯器變成類似 IntelliJ IDEA 這樣的 Rust IDE。
05 期待你的參與
這個核心還處於非常早期的階段。一些關鍵功能,如 futex、epoll、UNIX 域 socket 等尚未實現。換句話說,程式碼仍然簡單易懂!如果你有興趣在 Rust 中編寫作業系統核心,歡迎參與。
— written by Seiya Nuta CC BY 4.0
原文連結:http://seiya.me/writing-linux-clone-in-rust
參考資料
Kerla: http://github.com/nuta/kerla
深受使用者喜愛的: http://insights.stackoverflow.com/survey/2020#technology-most-loved-dreaded-and-wanted-languages
rust-analyzer: http://rust-analyzer.github.io/
AWS 的輕量級 VMM: http://aws.amazon.com/blogs/opensource/why-aws-loves-rust-and-how-wed-like-to-help/
npm registry 的部分模組: http://www.rust-lang.org/static/pdfs/Rust-npm-Whitepaper.pdf
許多其他公司: http://www.rust-lang.org/production/users
《是時候用 Rust 重寫作業系統了嗎?》: http://www.infoq.com/presentations/os-rust/
Rust for Linux: http://github.com/Rust-for-Linux/linux
補丁: http://lkml.org/lkml/2021/4/14/1023
virtio: http://wiki.osdev.org/Virtio
新型別習語: http://doc.rust-lang.org/rust-by-example/generics/new_types.html
Linus Torvalds on the Linux kernel's Rust support patch: http://lkml.org/lkml/2021/4/14/1099
Arc::new(): http://doc.rust-lang.org/alloc/sync/struct.Arc.html#method.new
xmalloc(3): http://www.freebsd.org/cgi/man.cgi?query=xmalloc&apropos=0
Resea: http://resea.org/
一些大小優化方法: http://github.com/johnthagen/min-sized-rust
1 類裝置: http://tools.ietf.org/html/rfc7228
特性標誌: http://doc.rust-lang.org/cargo/reference/features.html
env!: http://doc.rust-lang.org/std/macro.env.html
Kconfig: http://www.kernel.org/doc/html/latest/kbuild/kconfig-language.html
跟蹤問題: http://github.com/rust-lang/rust/issues/32838
heapless crate: http://docs.rs/heapless/
packed struct: http://doc.rust-lang.org/nomicon/other-reprs.html#reprpacked
raw pointers: http://doc.rust-lang.org/std/primitive.pointer.html
改進的內聯彙編語法: http://blog.rust-lang.org/inside-rust/2020/06/08/new-inline-asm.html
embedding assembly files: http://doc.rust-lang.org/unstable-book/library-features/global-asm.html
bitflags 操作庫: http://docs.rs/bitflags/1.2.1/bitflags/
基於陣列的 vector 和字串實現: http://docs.rs/arrayvec/0.7.0/arrayvec/
多生產者和多消費者佇列: http://docs.rs/crossbeam/0.8.0/crossbeam/queue/struct.ArrayQueue.html
custom_test_frameworks: http://rust-lang.github.io/rfcs/2318-custom-test-frameworks.html
linter: http://github.com/rust-lang/rust-clippy
交叉編譯: http://rust-lang.github.io/rustup/cross-compilation.html
rust-analyzer: http://rust-analyzer.github.io/
推薦閱讀
覺得不錯,點個贊吧
掃碼關注「 Rust程式設計指北 」
- Node.js 開發者的 Rust 入門指南
- 厭倦 JavaScript,開發者用 Rust 開啟替換潮?
- 喜歡 Rust 的 5 大理由,你認可嗎?
- System76 基於 Rust 的新桌面環境
- 那些彎道超車的號主們
- Rust 與 C 的速度比較
- 你一定不能錯過的 Rust 記憶體安全指南
- Rust 會成為 JavaScript 基礎設施的未來嗎?
- Rust VS Python:為什麼越來越流行,取代 Python?
- 超乾貨!大型 Rust 專案經驗分享
- Rust 中這樣操作字串竟然是錯的
- 詳解 Rust 如何 Mock HTTP 服務
- 實戰:用 Rust 從頭實現一個 CLI 應用(2)
- Rust 專案實戰:從頭構建一個筆記命令列程式(1)
- Rust 版 Memcached 來了
- Rust 中的高階型別
- 據說 Rust 愛好者都喜歡的號主
- 我的 Rust GUI 開發之旅
- Rust 和 C 排序演算法效能對比
- Rust:什麼是非同步執行時?有哪些可用?