本页目录

内核模块与 no_std

std 依赖操作系统(线程、文件、堆分配),裸机和内核模块没有这些。#![no_std] 去掉 std 只保留不依赖 OS 的 core crate,但 alloc(堆分配)和 panic_handler(panic 时做什么)需要自己提供。Rust-for-Linux 在 Linux 内核里跑 Rust 代码,靠的就是 no_std + 内核提供的 alloc 实现。

去掉 std: no_std 环境

std 依赖于操作系统——线程、文件 IO、网络、堆分配,这些都假设了 OS 的存在。裸机 (bare metal)、嵌入式系统、内核模块没有这些。#![no_std] 去掉 std,只保留不依赖 OS 的 core crate:

#![no_std]
#![no_main]

extern crate alloc;                  // 可选: 需要堆分配时引入

use core::panic::PanicInfo;
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
    loop {}                          // 不能打印, 不能 unwind
}

core 包含:Option, Result, Iterator, Clone, Copy, 基础宏(format_args! 但需要自己提供 write_str 实现才能用 format!),原子操作。alloc crate 在实现了 GlobalAlloc 后可用——提供 Box, Vec, String, Rc, Arc, HashMap。

Rust-for-Linux (Linux kernel)

Linux 6.1+ 支持 Rust 内核模块。关键抽象:

use kernel::prelude::*;

kernel::module! {
    type: MyModule,
    name: "my_module",
    license: "GPL",
}

struct MyModule;
impl kernel::Module for MyModule {
    fn init(_module: &'static ThisModule) -> Result<Self> { Ok(MyModule) }
}

// 实现文件操作
struct MyFile;
#[vtable]
impl kernel::file::Operations for MyFile {
    fn read(&self, _data: ()) -> Result<Vec<u8>> {
        Ok(b"Hello from Rust kernel module!\n".to_vec())
    }
}

#[vtable] 宏为 trait 生成兼容 C 函数指针表的代码——与内核 C 代码的 file_operations 结构体对接。内核中的 Rust 比 userspace 有更多限制:

  • 自己的 allocator:内核中不能用 #[global_allocator],必须用内核的分配器(kmalloc/kfree)——通过 kernel::alloc 访问
  • 自己的同步原语:kernel::sync::Mutex 是内核 mutex(struct mutex)的 Rust 包装,不是 std::sync::Mutex
  • 自己的错误类型:kernel::error::Error 映射到 Linux errno
  • Panic = BUG():内核不能 unwind——panic_handler 调用 BUG()(打印栈 + 停止内核)

参考

  • Rust-for-Linux: rust-for-linux.com
  • Embedded Rust Book: docs.rust-embedded.org
  • Phil Opp's blog: os.phil-opp.com

Keywords: no_std, core, alloc, panic_handler, kernel module, Rust-for-Linux, embedded, BUG