从零开始的 rust 内核开发(一)

本贴最后更新于 300 天前,其中的信息可能已经时过境迁

#rustkernel#

经过之前的步骤,现在需要来构建一个真正的 linux 内核。其实有点问题,一个是 rustc 在 1.62 版本中存在一些 bug。

如果想要编写后续的 rust 内核模块,你不能移动你的内核目录文件夹。

也就是假如我们在/a/b/c/linux 目录中编译了内核,后续我们需要指定 kernel 的源码目录,这个目录必须是/a/b/c/linux。假如我觉得这个目录是个临时目录,或者打包了目录到/usr/src/linux 目录下,那不好意思,rustc 无法编译内核模块。现在最新的内核是 6.3.8 还在用的是 rustc 1.62.0,这个 bug 会在 linux 6.5 中修复。因为 6.5 升级了 rustc 到 1.68.6。6.5 预计八月底发布吧。(残念

配置 rust 环境

安装 rustup

Rocky Linux 9 的默认 rust 的版本是 1.66,这个显然太高了。有关 rust 的版本查看可以在下载源码后,确认 scripts/min-tool-version.sh 这个文件的内容。6.3.8 的内核中里面记录的 rust 版本是 1.62.0。

那这个时候就不用系统自带的 rust 版本。用 rustup 管理 rust 版本,可以去 rust 官网下一个,或者自己打包一个 rustup。说老实话十分震惊,你们 redhat 人不用 rustup 吗,竟然全网没找到 rustup 的打包记录,后来我用 gpt4 把 archlinux 的 rustup 转成了 rpm 的版本。点这里访问

把 Readme 的内容复制粘贴就好了。

这一步不是必须的~~(因为依赖是可以忽略的)~~,因为其实在官网下一个现成的也可以,但是我需要用 elrepo 的 rpm 包,因为里面有现成的脚本与内核 config。我想要完整的依赖关系。所以选择打包了一个 rustup。

首先要给国内环境加速一下

export RUSTUP_DIST_SERVER=https://mirrors.ustc.edu.cn/rust-static
export RUSTUP_UPDATE_ROOT=https://mirrors.ustc.edu.cn/rust-static/rustup

剩下的复制粘贴就好了

git clone https://github.com/ssfdust/rustup-rpm
sudo dnf install -y rpm-build rpmdevtools
sudo dnf build-dep -y rustup.spec
spectool -g -R rustup.spec
cp rustup-profile.sh ~/rpmbuild/SOURCES
rpmbuild -ba rustup.spec
sudo dnf install --allowerasing -y ~/rpmbuild/RPMS/x86_64/rustup*.rpm
export PATH=~/.cargo/bin:$PATH

配置内核

下载内核与配置项目

sudo dnf install -y aria2
aria2c --no-conf -s 10 -x 10 -c https://www.kernel.org/pub/linux/kernel/v6.x/linux-6.3.8.tar.xz
tar -xvf linux-6.3.8.tar.xz -C ~

初始化必要的 rust + LLVM 环境

cd ~/linux-6.3.8
sudo dnf install -y llvm lld
rustup override set $(scripts/min-tool-version.sh rustc)
rustup component add rust-src
cargo install --locked --version $(scripts/min-tool-version.sh bindgen) bindgen

检查一下

make LLVM=1 rustavailable
Rust is available!

配置基本编译依赖

这里是为了 kernel 配置一些 debug info 与支持静态编译的内容。看上去貌似和 BPF 有关系(CONFIG_PAHOLE_HAS_BTF_TAG,CONFIG_PAHOLE_HAS_SPLIT_BTF 以及 CONFIG_PAHOLE_HAS_LANG_EXCLUDE),有没有大佬来讲解一下。

sudo dnf install -y dwarves glibc-static

配置 menuconfig

cp ~/rpmbuild/SOURCES/config-6.3.8-x86_64 .config
make LLVM=1 menuconfig
取消 BTF 内容

kernel hacking --> Compile-time checks and compiler options --> Generate BTF typeinfo

取消模块版本支持

Enable loadable module support --> Module versioning support

这两步是为了能开启 CONFIG_RUST 的配置项目。

开启 Rust 支持

现在回到 General setup,就能看到最后一行 Rust support

选中 Rust support,开启 Rust 支持。

取消冲突驱动

Device Drivers -> Network device support -> Ethernet driver support -> Myson MTD-8xx PCI Ethernet support

开启/proc/config.gz 支持

这个选项默认是关掉的,开起来

General setup --> Kernel .config support --> Enable access to .config through /proc/config.gz

保存 config

结束后,save 到.config,重命名到 config-6.3.8-rust-x86_64,并复制到 rpmbuild 目录下

cp .config ~/rpmbuild/SOURCES/config-6.3.8-rust-x86_64

配置内核 Spec 文件

安装依赖

sudo dnf build-dep -y ~/rpmbuild/SPECS/kernel-ml-6.3.spec

修改 spec

拷贝一份 spec 出来

cp ~/rpmbuild/SPECS/kernel-ml-6.3.spec ~/rpmbuild/SPECS/kernel-ml-llvm-rust-6.3.spec

添加新依赖

BuildRequires 中加上 llvm 的依赖。llvm, llvm-static, clang, lldrustup

BuildRequires: bash, bc, binutils, bison, bzip2, coreutils, diffutils, dwarves, elfutils-devel
BuildRequires: findutils, flex, gawk, gcc, gcc-c++, gcc-plugin-devel, git-core, glibc-static
BuildRequires: gzip, hmaccalc, hostname, kernel-rpm-macros >= 185-9, kmod, m4, make, net-tools
BuildRequires: patch, perl-Carp, perl-devel, perl-generators, perl-interpreter, python3-devel
BuildRequires: redhat-rpm-config, tar, which, xz, llvm, llvm-static, clang, lld, rustup

替换内核 config 文件,添加 rust 支持

  Source2: config-%{version}-x86_64
  Source4: config-%{version}-aarch64
+ Source5: config-%{version}-rust-x86_64
  ...
  cp -a %{SOURCE2} .
  cp -a %{SOURCE4} .
+ cp -a %{SOURCE5} .

替换所有 config-%{version}-%{_target_cpu}config-%{version}-rust-%{_target_cpu}

添加 LLVM 参数

之后,给所有的 make 命令加上 LLVM=1 的参数。以 %{__make} 为关键字搜索。

新增 Rust 初始化

找到 %setup 代码块,插入 rust 初始化代码

  %setup -q -n %{name}-%{version} -c
  mv linux-%{LKAver} linux-%{KVERREL}
  
  pushd linux-%{KVERREL} > /dev/null
  
  # Purge the source tree of all unrequired dot-files.
  find . -name '.*' -type f -delete
  
+ # Setup rust
+ rustup override set $(scripts/min-tool-version.sh rustc)
+ rustup component add rust-src
+ cargo install --locked --version $(scripts/min-tool-version.sh bindgen) bindgen

解决 BPF 冲突问题打包 rust 资源

  cp --parents tools/build/Build $RPM_BUILD_ROOT/lib/modules/%{KVERREL}/build
  cp --parents tools/build/fixdep.c $RPM_BUILD_ROOT/lib/modules/%{KVERREL}/build
  cp --parents tools/objtool/sync-check.sh $RPM_BUILD_ROOT/lib/modules/%{KVERREL}/build
- cp --parents tools/bpf/resolve_btfids $RPM_BUILD_ROOT/lib/modules/%{KVERREL}/build
+ cp --parents rust/*.rmeta $RPM_BUILD_ROOT/lib/modules/%{KVERREL}/build
+ cp --parents rust/*.so $RPM_BUILD_ROOT/lib/modules/%{KVERREL}/build
  
  cp --parents security/selinux/include/policycap_names.h $RPM_BUILD_ROOT/lib/modules/%{KVERREL}/build
  cp --parents security/selinux/include/policycap.h $RPM_BUILD_ROOT/lib/modules/%{KVERREL}/build

因为不会生成 btfids,所以需要取消这个部分的复制,剩下的是把 rust 的静态内容 *.rmeta 数据与 *.so 复制到 build 目录下。

编译内核并安装

mv linux-6.3.8.tar.xz ~/rpmbuild/SOURCES/
rpmbuild --without bpftool -ba ~/rpmbuild/SPECS/kernel-ml-llvm-rust-6.3.spec

报错了

clang-15: error: argument unused during compilation: '-specs=/usr/lib/rpm/redhat/redhat-hardened-cc1' [-Werror,-Wunused-command-line-argument]

修改 kernel-ml-llvm-rust-6.3.spec 中的 HOSTCFLAGS 变量,新增一个参数 -Wno-unused-command-line-argument

%global make %{__make} LLVM=1 -s HOSTCFLAGS="%{?build_cflags} -Wno-unused-command-line-argument" HOSTLDFLAGS="%{?build_ldflags}"

然后重新编译

安装

sudo dnf install -y kernel-ml-core-6.3.8-1.el9.x86_64.rpm \
   kernel-ml-modules-6.3.8-1.el9.x86_64.rpm \
   kernel-ml-6.3.8-1.el9.x86_64.rpm \
   kernel-ml-devel-6.3.8-1.el9.x86_64.rpm

然后重启。

验证

gzip -k -d /proc/config.gz -c | grep -iP _rust[c]?_
CONFIG_RUST_IS_AVAILABLE=y
CONFIG_RUSTC_VERSION_TEXT="rustc 1.62.0 (a8314ef7d 2022-06-27)"
# CONFIG_RUST_DEBUG_ASSERTIONS is not set
CONFIG_RUST_OVERFLOW_CHECKS=y
# CONFIG_RUST_BUILD_ASSERT_ALLOW is not set

uname -a
Linux rocky9.localdomain 6.3.8-1.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Sun Jun 18 10:29:42 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux

编译 rust-out-of-tree-module

git clone https://github.com/Rust-for-Linux/rust-out-of-tree-module.git
cd rust-out-of-tree-module
make KDIR=~/rpmbuild/BUILD/kernel-ml-6.3.8/linux-6.3.8-1.el9.x86_64 LLVM=1

测试模块

sudo insmod rust_out_of_tree.ko

sudo dmesg | grep -i rust_
[  418.801829] rust_out_of_tree: loading out-of-tree module taints kernel.
[  418.803958] rust_out_of_tree: Rust out-of-tree sample (init)

sudo rmmod rust_out_of_tree

sudo dmesg | grep -i rust_
[  418.801829] rust_out_of_tree: loading out-of-tree module taints kernel.
[  418.803958] rust_out_of_tree: Rust out-of-tree sample (init)
[  474.561172] rust_out_of_tree: My numbers are [72, 108, 200]
[  474.562286] rust_out_of_tree: Rust out-of-tree sample (exit)

好,大功告成。

番外

复现一下 bug

cd rust-out-of-tree-module
git clean -xdf
make KDIR=/usr/src/kernels/6.3.8-1.el9.x86_64/ LLVM=1
[vagrant@rocky9 rust-out-of-tree-module]$ make KDIR=/usr/src/kernels/6.3.8-1.el9.x86_64/ LLVM=1
make -C /usr/src/kernels/6.3.8-1.el9.x86_64/ M=$PWD
make[1]: Entering directory '/usr/src/kernels/6.3.8-1.el9.x86_64'
  RUSTC [M] /home/vagrant/workspace/rust-out-of-tree-module/rust_out_of_tree.o
error[E0461]: couldn't find crate `core` with expected target triple target-12651001632755738518
  |
  = note: the following crate versions were found:
          crate `core`, target triple target-4060368401698419050: /usr/src/kernels/6.3.8-1.el9.x86_64/rust/libcore.rmeta
                                                                                                                                                                                   
error[E0461]: couldn't find crate `compiler_builtins` with expected target triple target-12651001632755738518
  |
  = note: the following crate versions were found:
          crate `compiler_builtins`, target triple target-4060368401698419050: /usr/src/kernels/6.3.8-1.el9.x86_64/rust/libcompiler_builtins.rmeta
                                                                                                                                                                                   
error[E0461]: couldn't find crate `kernel` with expected target triple target-12651001632755738518
...
  • Rust

    Rust 是一门赋予每个人构建可靠且高效软件能力的语言。Rust 由 Mozilla 开发,最早发布于 2014 年 9 月。

    57 引用 • 22 回帖 • 5 关注
  • kernel
    6 引用 • 2 回帖
  • 内核
    10 引用 • 14 回帖
4 操作
ssfdust 在 2023-07-02 19:43:36 更新了该帖
ssfdust 在 2023-07-02 19:42:45 更新了该帖
ssfdust 在 2023-06-20 23:53:17 更新了该帖
ssfdust 在 2023-06-20 23:15:18 更新了该帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • porka 1

    博主,有专门的连载地址吗 ,ld 帖子太分散还是不太方便追更

    1 回复
  • ssfdust

    有个公众号,叫正觉矩阵。同步更新的