开源项目:使用 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:什么是异步运行时?有哪些可用?