#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
, lld
,rustup
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
...
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于