|
1 | | -# Wiki |
| 1 | +# Rust for Linux Wiki |
| 2 | + |
| 3 | +在本项目的 Wiki 的整个栏目中,主要聚焦于 Rust for Linux 的所有代码实现。同时,Wiki 栏目会着重介绍 Rust for Linux 当前每一个模块的功能并随着版本实时更新。 |
| 4 | + |
| 5 | +在这之前,我们需要准备一个能够运行 Rust for Linux 代码的环境。在正式开始之前,这里统一介绍笔者当前的系统环境: |
| 6 | + |
| 7 | +``` bash |
| 8 | +OS: Fedora 42 (Server Edition) |
| 9 | +Gcc: gcc version 15.2.1 20251022 (Red Hat 15.2.1-3) (GCC) |
| 10 | +Clang: clang version 20.1.8 (Fedora 20.1.8-4.fc42) |
| 11 | +Rust: rustc 1.91.0 (f8297e351 2025-10-28) |
| 12 | +LLVM: LLVM version 20.1.8 |
| 13 | +LLD: LLD 20.1.8 (compatible with GNU linkers) |
| 14 | +``` |
| 15 | + |
| 16 | +## Rust for Linux 环境搭建 |
| 17 | + |
| 18 | +我们需要搭建一个 Rust for Linux 环境,我们就需要编译内核,然后通过 QEMU 运行所编译的内核镜像。为了方便起见,除了 QEMU 和 Linux 镜像文件,其余文件均采用已经处理好的网络资源文件(rootfs和disk image)。 |
| 19 | + |
| 20 | +### 安装 Rust |
| 21 | + |
| 22 | +在 Rust for Linux 的[官方文档](https://docs.kernel.org/rust/quick-start.html)中,Rust 的安装是通过各自发行版本的包管理器进行统一安装,但笔者是通过 Rust 官方安装脚本进行安装,**只需要保证 \\( rust \ version \ge 1.80 \\) 即可**。 |
| 23 | + |
| 24 | +因此,此处仅提供通过 Rust 官方安装脚本的方式: |
| 25 | + |
| 26 | +> 对于国内用户,可以采用[rsproxy](https://rsproxy.cn/)更换镜像源后进行安装 |
| 27 | +
|
| 28 | +``` bash |
| 29 | +curl --proto '=https' --tlsv1.2 -sSf https://rsproxy.cn/rustup-init.sh | sh |
| 30 | +``` |
| 31 | + |
| 32 | +安装完成后,查看安装信息以确保 Rust 版本大于`1.80`版本。 |
| 33 | + |
| 34 | +``` bash |
| 35 | +rustc --version |
| 36 | +rustc 1.91.0 (f8297e351 2025-10-28) |
| 37 | +``` |
| 38 | + |
| 39 | +当然,你可以可以通过如下代码进行简单验证: |
| 40 | + |
| 41 | +``` rust |
| 42 | +# fn main() { |
| 43 | + println!("Hello Rust Version Done! Verison: {:?}", std::env::var("CARGO_PKG_VERSION")) |
| 44 | +# } |
| 45 | +``` |
| 46 | + |
| 47 | +通过官方安装脚本安装时,通常也会安装`rustfmt`和`rust-clippy`。为了确认是否安装成功,请使用如下命令进行检测: |
| 48 | + |
| 49 | +``` bash |
| 50 | +rustfmt --version |
| 51 | +rustfmt 1.8.0-stable (f8297e351a 2025-10-28) |
| 52 | + |
| 53 | +cargo clippy --version |
| 54 | +clippy 0.1.91 (f8297e351a 2025-10-28) |
| 55 | +``` |
| 56 | + |
| 57 | +如若没有安装,请通过如下指令进行安装: |
| 58 | + |
| 59 | +``` bash |
| 60 | +rustup component add rust-src rustfmt clippy |
| 61 | +``` |
| 62 | + |
| 63 | +针对于 Rust for Linux 开发,还需要额外安装`bindgen`,这用于 Rust 与 C语言之间的通信。 |
| 64 | + |
| 65 | +``` bash |
| 66 | +cargo install --locked bindgen-cli |
| 67 | +``` |
| 68 | + |
| 69 | +### 安装 QEMU |
| 70 | + |
| 71 | +在后续的启动中,我们通过 Qemu 进行启动对应的镜像文件,因此需要提前准备 Qemu 可执行程序。 |
| 72 | + |
| 73 | +对于 Qemu 的安装而言,通常分为两种方式:包管理安装和手动编译。笔者通常喜欢手动编译,但下方会给出两种安装方式,读者可以自行选择其中一种进行安装。 |
| 74 | + |
| 75 | +#### 包管理安装 |
| 76 | + |
| 77 | +包管理安装可以直接通过各自的系统命令进行安装,下方给出两种常见发行版本安装命令: |
| 78 | + |
| 79 | +- Ubuntu/Debian(全量安装) |
| 80 | + |
| 81 | +``` bash |
| 82 | +sudo apt install qemu -y |
| 83 | +``` |
| 84 | + |
| 85 | +- Ubuntu/Debian(精简安装) |
| 86 | + |
| 87 | +``` bash |
| 88 | +sudo apt install qemu-system-x86 -y |
| 89 | +``` |
| 90 | + |
| 91 | +- Fedora/Rocky(全量安装) |
| 92 | + |
| 93 | +``` bash |
| 94 | +sudo dnf install qemu -y |
| 95 | +``` |
| 96 | + |
| 97 | +- Fedora/Rocky(精简安装) |
| 98 | + |
| 99 | +``` bash |
| 100 | +sudo dnf install qemu-system-x86 -y |
| 101 | +``` |
| 102 | + |
| 103 | +#### 源码编译安装 |
| 104 | + |
| 105 | +这里简单阐述一下为什么选择源码编译,因为源码编译可以自行选择安装版本,避免版本过久问题。 |
| 106 | + |
| 107 | +首先安装所需的依赖包: |
| 108 | + |
| 109 | +``` bash |
| 110 | +sudo dnf in ninja-build python3-sphinx python3-sphinx_rtd_theme glib2-devel libslirp-devel -y |
| 111 | +``` |
| 112 | + |
| 113 | +然后下载对应的源码并解压: |
| 114 | + |
| 115 | +``` bash |
| 116 | +wget https://download.qemu.org/qemu-10.1.2.tar.xz |
| 117 | +tar Jxvf qemu-10.1.2.tar.xz |
| 118 | +``` |
| 119 | + |
| 120 | +进入对应的目录进行配置: |
| 121 | + |
| 122 | +``` bash |
| 123 | +./configure --prefix=/opt/qemu --enable-kvm --enable-debug |
| 124 | +make -j$(nproc) |
| 125 | +``` |
| 126 | + |
| 127 | +> 精简安装:本教程主要在`x86`环境上进行操作,因此如果读者的资源有限或认为全量编译过慢,可以通过下方指令进行精简编译 |
| 128 | +> ``` bash |
| 129 | +> ./configure --prefix=/opt/qemu --target-list=x86_64-softmmu --enable-kvm |
| 130 | +> ``` |
| 131 | +
|
| 132 | +编译完成后,安装到指定目录,并配置环境变量;然后进行验证: |
| 133 | +
|
| 134 | +``` bash |
| 135 | +sudo make install |
| 136 | +echo "export PATH=$PATH:/opt/qemu/bin" >> $HOME/.bashrc |
| 137 | +source $HOME/.bashrc |
| 138 | +
|
| 139 | +qemu-system-x86_64 --version |
| 140 | +QEMU emulator version 10.1.2 |
| 141 | +Copyright (c) 2003-2025 Fabrice Bellard and the QEMU Project developers |
| 142 | +``` |
| 143 | +
|
| 144 | +### 构建 Linux 镜像 |
| 145 | + |
| 146 | +提前准备好 Linux 编译所需要的依赖包: |
| 147 | + |
| 148 | +``` bash |
| 149 | +sudo dnf in gcc clang clang-tools-extra llvm lld gpg2 git gzip make openssl perl rsync binutils ncurses-devel flex bison openssl-devel elfutils-libelf-devel rpm-build |
| 150 | +``` |
| 151 | + |
| 152 | +准备好 Rust 环境后,我们就需要通过编译内核源码获取 Linux 镜像文件。首先,我们直接克隆 Rust for Linux 主线分支(**Linux内核主线源码也是可行的,只是相较于 Rust for Linux 主线分支支持的特性稍微少一些**)。 |
| 153 | + |
| 154 | +``` bash |
| 155 | +git clone https://github.com/Rust-for-Linux/linux.git rust-for-linux --depth=1 |
| 156 | +``` |
| 157 | + |
| 158 | +进入到`rust-for-linux`目录中(这里将 Rust for Linux 主线代码重命名为`rust-for-linux`这是为了避免与`linux`内核主线重名)。然后通过如下命令检查 Rust 依赖和版本是否正确。 |
| 159 | + |
| 160 | +> **极其要注意的是,对于 Rust for Linux 的编译,LLVM 工具链的版本必须要 \\( \ge 15.0.0 \\)** |
| 161 | +
|
| 162 | +``` bash |
| 163 | +make LLVM=1 rustavailable |
| 164 | +Rust is available! |
| 165 | +``` |
| 166 | + |
| 167 | +只有输出结果为`Rust is available!`时,才证明当前主机环境能够正常通过 Rust 编译内核。现在,我们就可以开始编译 Rust for Linux 的内核源码。 |
| 168 | + |
| 169 | +``` bash |
| 170 | +make LLVM=1 defconfig |
| 171 | +make LLVM=1 menuconfig |
| 172 | +``` |
| 173 | + |
| 174 | +首先通过`defconfig`命令生成默认配置文件,然后通过`menuconfig`启用`RUST`和`SAMPLES_RUST`,其参数选择位置参考下方: |
| 175 | + |
| 176 | + |
| 177 | +``` bash |
| 178 | +config RUST |
| 179 | +Location: |
| 180 | + -> General setup |
| 181 | + -> Rust support (RUST [=y]) |
| 182 | + |
| 183 | +config SAMPLES_RUST |
| 184 | +Location: |
| 185 | + -> Kernel hacking |
| 186 | + -> Sample kernel code (SAMPLES [=y]) |
| 187 | + -> Rust samples (SAMPLES_RUST [=y]) |
| 188 | +``` |
| 189 | + |
| 190 | +配置完成后,就能够正常启用 Rust 进行编译内核,然后开始编译。 |
| 191 | + |
| 192 | +``` bash |
| 193 | +make LLVM=1 -j$(nproc) |
| 194 | +``` |
| 195 | + |
| 196 | +在编译时,可以通过编译的日志查看到一些 Rust 编译信息: |
| 197 | + |
| 198 | +``` bash |
| 199 | + RUSTC L rust/core.o |
| 200 | + BINDGEN rust/bindings/bindings_generated.rs |
| 201 | + BINDGEN rust/bindings/bindings_helpers_generated.rs |
| 202 | + CC rust/helpers/helpers.o |
| 203 | + RUSTC P rust/libpin_init_internal.so |
| 204 | + RUSTC P rust/libmacros.so |
| 205 | +``` |
| 206 | + |
| 207 | +> **对于 Rust 是必须开启 `LLVM=1` 选项的,因此不能够省略,如果想要省略,可以在编译配置千使用如下命令**: |
| 208 | +> ``` bash |
| 209 | +> export LLVM=1 |
| 210 | +> ``` |
| 211 | +
|
| 212 | +编译完成后,读者可以在当前目录下查看到对应的生成镜像文件,我们所需要使用的则是 `vmlinux`。然后我们进入下一步,准备启动环境。 |
| 213 | +
|
| 214 | +### 运行 Rust for Linux 镜像 |
| 215 | +
|
| 216 | +之前提到,为了简化流程,我们会直接从网络上下载已有镜像进行运行,因此需要运行如下命令: |
| 217 | +
|
| 218 | +``` bash |
| 219 | +wget https://cdimage.debian.org/images/cloud/bookworm/20250316-2053/debian-12-nocloud-amd64-20250316-2053.qcow2 -o debian-12.qcow2 |
| 220 | +``` |
| 221 | +
|
| 222 | +> 如果想要下载其他架构,请参考最下方的参考链接中的 Rust Exercises Ferrous System |
| 223 | +
|
| 224 | +为了简化下载的方便,所下载的镜像的大小不会太大,因此内部的空间不足以让我们后续替换内核镜像和加载内核模块。所以在启动之前需要进行扩容,启动后在内部修改磁盘大小以支持镜像更换。 |
| 225 | + |
| 226 | +``` bash |
| 227 | +(host-machine) qemu-img resize debian-12.qcow2 +32G |
| 228 | +``` |
| 229 | + |
| 230 | +至此,前期的准备工作均准备完毕,运行如下命令启动镜像: |
| 231 | + |
| 232 | +``` bash |
| 233 | +(host-machine) qemu-system-x86_64 -m 8G -M q35 -accel kvm -smp 8 \ |
| 234 | + -hda debian-12.qcow2 \ |
| 235 | + -device e1000,netdev=net0 \ |
| 236 | + -netdev user,id=net0,hostfwd=tcp:127.0.0.1:5555-:22 \ |
| 237 | + -nographic \ |
| 238 | + -serial telnet:localhost:4321,server,wait |
| 239 | +``` |
| 240 | + |
| 241 | +此时,该终端会一直挂起,读者需要另起一个新终端,通过 `telnet` 命令进行连接: |
| 242 | + |
| 243 | +``` bash |
| 244 | +telnet localhost 4321 |
| 245 | +[ OK ] Finished systemd-user-sess…ervice - Permit User Sessions. |
| 246 | +[ OK ] Started [email protected] - Getty on tty1. |
| 247 | +[ OK ] Started serial-getty@ttyS0…rvice - Serial Getty on ttyS0. |
| 248 | +[ OK ] Reached target getty.target - Login Prompts. |
| 249 | +[ OK ] Started dbus.service - D-Bus System Message Bus. |
| 250 | +[ OK ] Started systemd-logind.service - User Login Management. |
| 251 | +[ OK ] Started unattended-upgrade…0m - Unattended Upgrades Shutdown. |
| 252 | +[ OK ] Finished e2scrub_reap.serv…ine ext4 Metadata Check Snapshots. |
| 253 | +[ OK ] Reached target multi-user.target - Multi-User System. |
| 254 | +[ OK ] Reached target graphical.target - Graphical Interface. |
| 255 | + Starting systemd-update-ut… Record Runlevel Change in UTMP... |
| 256 | +[ OK ] Finished systemd-update-ut… - Record Runlevel Change in UTMP. |
| 257 | + |
| 258 | +Debian GNU/Linux 12 localhost ttyS0 |
| 259 | + |
| 260 | +localhost login: |
| 261 | +``` |
| 262 | + |
| 263 | +此时,就启动了对应的内核镜像,通过 `root` 用户登录(无密码)。当前启动的内核是自带内核,因此需要更换内核镜像。在这之前,我们还需要进行扩容操作,并且需要配置好 `ssh` 以方便将内核镜像传入到虚拟机中。 |
| 264 | + |
| 265 | +``` bash |
| 266 | +(virt-machine) uname -a |
| 267 | +Linux localhost 6.1.0-32-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.129-1 (2025-03-06) x86_64 GNU/Linux |
| 268 | + |
| 269 | +(virt-machine) apt update |
| 270 | +(virt-machine) apt install fdisk |
| 271 | +(virt-machine) cfdisk /dev/*da |
| 272 | +``` |
| 273 | + |
| 274 | + |
| 275 | + |
| 276 | +执行上述命令后,可以看到如上所示的界面。首先选择 `Sort`,此时你会发现 `Linux root` 往下移动,与 `Free space` 近邻,然后如下所示,选择 `Linux root` 对应的磁盘,并且选择 `Resize` 选项。 |
| 277 | + |
| 278 | + |
| 279 | + |
| 280 | +然后键入两次回车,发现 `Linux root` 的大小更改后,选择 `Write` 选项,然后键入 `yes` 确定修改,如下所示: |
| 281 | + |
| 282 | + |
| 283 | + |
| 284 | +至此,选择 `Quit` 选项即可,使用 `reboot` 重启虚拟机,查看是否更改成功: |
| 285 | + |
| 286 | +``` bash |
| 287 | +(virt-machine) reboot |
| 288 | + |
| 289 | +(virt-machine) df -h |
| 290 | +Filesystem Size Used Avail Use% Mounted on |
| 291 | +... |
| 292 | +/dev/sda3 38G 1.2G 35G 4% / |
| 293 | +... |
| 294 | +``` |
| 295 | + |
| 296 | +修改完成后,接下来需要配置 `ssh`: |
| 297 | + |
| 298 | +``` bash |
| 299 | +(virt-machine) apt install openssh-server |
| 300 | +``` |
| 301 | + |
| 302 | +并将主机的 `ssh` 公钥复制到虚拟机中的 `.ssh/authorized_keys` 文件中。接着将上方我们编译的内核传入到虚拟机中: |
| 303 | + |
| 304 | +``` bash |
| 305 | +(host-machine) scp -P 5555 rust-for-linux/vmlinux root@localhost:/root |
| 306 | +``` |
| 307 | + |
| 308 | +此时,能够在虚拟机中发现对应的文件,将其添加可执行文件权限,并移动到 `/boot` 下 |
| 309 | + |
| 310 | +``` bash |
| 311 | +(virt-machine) chmod +x vmlinux |
| 312 | +(virt-machine) cp /boot/vmlinuz-6.1.0-32-amd64 /boot/vmlinuz-6.1.0-32-amd64-bak |
| 313 | +(virt-machine) cp vmlinux /boot/vmlinuz-6.1.0-32-amd64 |
| 314 | +(virt-machine) reboot |
| 315 | +``` |
| 316 | + |
| 317 | +重启后,如无任何报错信息,则更换内核完毕,通过如下命令查看: |
| 318 | + |
| 319 | +``` bash |
| 320 | +(virt-machine) uname -a |
| 321 | +``` |
| 322 | + |
| 323 | +至此,启动一个 Rust for Linux 编译的内核镜像就成功完成了。 |
| 324 | + |
| 325 | +--- |
| 326 | + |
| 327 | +参考链接 |
| 328 | + |
| 329 | +- [Rust Exercises Ferrous System](https://rust-exercises.ferrous-systems.com/latest/book/building-linux-kernel-driver) |
| 330 | +- [Rust for Linux Quick Start](https://docs.kernel.org/rust/quick-start.html) |
0 commit comments