---
title: Kernel Modules and no_std
url: https://doc.liz6.com/en/rust/11-ffi-and-system-interaction/02-kernel-modules-and-no-std
locale: en
area: rust
tags:
- rust
- ffi-and-system-interaction
date: 2026-06-30
modified: 2026-07-16
description: 'std depends on the operating system (threads, files, heap allocation), which bare-metal 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.'
---

# 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:

```rust
#![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:

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

// 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*
