用 Rust 为 Linux 内核写一个 GPIO 驱动
每一颗 LED 第一次亮起的瞬间,背后都是一段代码战胜了混沌。
当你用 Rust 写下第一个 GPIO 驱动,你不只是在控制一个引脚的高低电平------你是在用一门拒绝段错误的语言,亲手触碰硬件世界最原始的脉搏。没有垃圾回收器的庇护,没有运行时的缓冲,只有你、编译器、和那一根细细的铜线。
编译通过的那一刻,灯亮了。那是你写的。
本文基于 Linux 7.0 + RISC-V + QEMU,带你从零完成一个 Rust GPIO 内核模块。
环境准备
1. 安装工具链
bash
# Clang/LLVM(RISC-V 上 Rust 内核支持强制要求 Clang,GCC 不行)
sudo apt install -y clang lld llvm libclang-dev
# RISC-V 交叉编译器(编译 C 部分仍需要)
sudo apt install -y gcc-riscv64-linux-gnu
# Rust 组件
rustup component add rust-src
cargo install --locked bindgen-cli
export PATH="$HOME/.cargo/bin:$PATH"
踩坑 1 :
HAVE_RUST在 RISC-V 上依赖CC_IS_CLANG,用 GCC 会导致CONFIG_RUST灰掉无法启用,必须用LLVM=1。
2. 验证 Rust 支持就绪
bash
cd /path/to/linux
make ARCH=riscv LLVM=1 rustavailable
无任何报错才能继续。
配置内核
bash
# 生成 RISC-V 默认配置
make ARCH=riscv LLVM=1 defconfig
# 启用 Rust
scripts/config --enable CONFIG_RUST
scripts/config --enable CONFIG_IKCONFIG_PROC # 可选:允许读 /proc/config.gz
# 同步配置
make ARCH=riscv LLVM=1 olddefconfig
# 确认
grep "CONFIG_RUST=" .config # 应输出 CONFIG_RUST=y
编写驱动
1. 创建源文件
drivers/gpio/rust_gpio_demo.rs:
rust
// SPDX-License-Identifier: GPL-2.0
//! Rust GPIO demo driver
use kernel::prelude::*;
module! {
type: RustGpioDemo,
name: "rust_gpio_demo",
authors: ["Your Name"], // 注意:是 authors(数组)不是 author
description: "A simple GPIO demo driver in Rust",
license: "GPL",
}
struct RustGpioDemo;
impl kernel::Module for RustGpioDemo {
fn init(_module: &'static ThisModule) -> Result<Self> {
pr_info!("Rust GPIO demo driver loaded!\n");
Ok(RustGpioDemo)
}
}
impl Drop for RustGpioDemo {
fn drop(&mut self) {
pr_info!("Rust GPIO demo driver unloaded!\n");
}
}
与 C 驱动的对比:
| 概念 | Rust | C |
|---|---|---|
| 模块声明 | module! {} |
MODULE_LICENSE() 等宏 |
| 初始化 | impl kernel::Module |
module_init() |
| 清理 | impl Drop(自动调用) |
module_exit() |
| 资源释放 | RAII,自动 | 手动 free/release |
| 日志 | pr_info!() |
pr_info() |
2. 注册到构建系统
drivers/gpio/Kconfig ,在 endmenu 前插入:
kconfig
config RUST_GPIO_DEMO
tristate "Rust GPIO demo driver"
depends on RUST
help
A simple GPIO driver written in Rust for learning purposes.
drivers/gpio/Makefile 末尾追加:
makefile
obj-$(CONFIG_RUST_GPIO_DEMO) += rust_gpio_demo.o
编译
bash
# 启用为模块
scripts/config --module CONFIG_RUST_GPIO_DEMO
make ARCH=riscv LLVM=1 olddefconfig
# 完整编译内核(不能单独 make xxx.ko)
env PATH="$HOME/.cargo/bin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" \
make ARCH=riscv LLVM=1 -j$(nproc)
踩坑 2 :不能用
make drivers/gpio/rust_gpio_demo.ko单独编译,modpost 在此模式下无法识别 Rust 模块的MODULE_LICENSE,会报错。必须跑完整的make。
踩坑 3 :WSL 用户的 PATH 中含有 Windows 路径(如/mnt/c/Program primecode.)包含空格,会导致 buildroot/内核 Makefile 报错。用env PATH=...传入干净的路径。
编译完成后确认产物:
bash
ls -lh drivers/gpio/rust_gpio_demo.ko
在 QEMU 中测试
启动时通过 virtfs 将 .ko 所在目录挂载进虚拟机:
bash
qemu-system-riscv64 \
-machine virt \
-nographic \
-kernel arch/riscv/boot/Image \
-drive file=/path/to/rootfs.ext2,format=raw,if=none,id=hd0 \
-device virtio-blk-device,drive=hd0 \
-virtfs local,path=drivers/gpio,mount_tag=host0,security_model=mapped \
-append "root=/dev/vda rw console=ttyS0" \
-m 512M
在虚拟机内:
bash
mkdir /mnt/host
mount -t 9p -o trans=virtio host0 /mnt/host
insmod /mnt/host/rust_gpio_demo.ko
dmesg | tail -3
# [ 5.123456] rust_gpio_demo: Rust GPIO demo driver loaded!
rmmod rust_gpio_demo
dmesg | tail -3
# [ 8.654321] rust_gpio_demo: Rust GPIO demo driver unloaded!
退出 QEMU:Ctrl+A 然后 X
坑位速查表
| 错误现象 | 根本原因 | 解决方案 |
|---|---|---|
HAVE_RUST=n,CONFIG_RUST 灰掉 |
RISC-V Rust 强依赖 Clang | 改用 LLVM=1 |
unknown key "author" |
key 名称错误 | 改为 authors: ["..."] |
missing MODULE_LICENSE() |
单独编译绕过了 modpost | 必须完整 make |
PATH contains spaces |
WSL 注入 Windows 路径 | env PATH=... 或关闭 appendWindowsPath |
libclang not found |
bindgen 找不到 libclang | sudo apt install libclang-dev |
灯,亮了。
经验证,可以正常加载驱动。
本文总写作时间为2分钟,主要工作为copy-paste + 添加文章头。
验证时间为2小时左右,经过三次彻底重构,AI还整了个前后呼应,服。
bash
buildroot login: root
# mkdir /mnt/host
# mount -t 9p -o trans=virtio host0 /mnt/host
# insmod /mnt/host/rust_gpio_demo.ko
[ 40.826645] rust_gpio_demo: Rust GPIO demo driver loaded!
# dmesg | tail -3
[ 1.945634] TERM=linux
[ 2.175759] EXT4-fs (vda): re-mounted acca20a9-4799-4758-b6d0-53df3dec1167.
[ 40.826645] rust_gpio_demo: Rust GPIO demo driver loaded!
# rmmod rust_gpio_demo
[ 57.943086] rust_gpio_demo: Rust GPIO demo driver unloaded!
# dmesg | tail -3
[ 2.175759] EXT4-fs (vda): re-mounted acca20a9-4799-4758-b6d0-53df3dec1167.
[ 40.826645] rust_gpio_demo: Rust GPIO demo driver loaded!
[ 57.943086] rust_gpio_demo: Rust GPIO demo driver unloaded!