On this page

Kernel Modules and no_std

std depends on the operating system (threads, file I/O, heap allocation), which bare-metal systems and kernel modules do not have. #![no_std] removes std, keeping only the OS-independent core crate, but alloc (heap allocation) and panic_handler (what to do on panic) must be provided manually. Rust-for-Linux runs Rust code in the Linux kernel by relying on no_std + the kernel-provided alloc implementation.

Removing std: The no_std Environment

std depends on the operating system—threads, file I/O, networking, heap allocation—all of which assume the presence of an OS. Bare-metal systems, embedded systems, and kernel modules do not have these. #![no_std] removes std, keeping only the OS-independent core crate:

#![no_std]
#![no_main]

extern crate alloc;                  // Optional: include when heap allocation is needed

use core::panic::PanicInfo;
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
    loop {}                          // Cannot print, cannot unwind
}

core includes: Option, Result, Iterator, Clone, Copy, and basic macros (format_args!, but you need to provide your own write_str implementation to use format!). The alloc crate becomes available once GlobalAlloc is implemented—providing Box, Vec, String, Rc, Arc, HashMap.

Rust-for-Linux (Linux Kernel)

Linux 6.1+ supports Rust kernel modules. Key abstractions:

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) }
}

// Implement file operations
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())
    }
}

The #[vtable] macro generates code for a C-compatible function pointer table for traits—interfacing with the file_operations struct in the kernel's C code. Rust in the kernel has more restrictions than userspace:

  • Custom allocator: You cannot use #[global_allocator] in the kernel; you must use the kernel's allocator (kmalloc/kfree)—accessible via kernel::alloc.
  • Custom synchronization primitives: kernel::sync::Mutex is a Rust wrapper around the kernel mutex (struct mutex), not std::sync::Mutex.
  • Custom error types: kernel::error::Error maps to Linux errno.
  • Panic = BUG(): The kernel cannot unwind—panic_handler calls BUG() (prints stack trace + stops the kernel).

References

  • 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