编译 Linux 内核:详细教程与 Kthreads 入门结合
我们将学习如何编译 Linux 内核,同时结合 Kthreads 的知识来理解各个步骤的目的。对于虚拟环境下的开发环境配置,本文将为你提供逐步指导。
1. 下载内核源代码
首先,我们需要从官方或国内镜像站下载 Linux 内核源代码:
-
官方网址:http://www.kernel.org
-
清华大学开源镜像站:https://mirror.tuna.tsinghua.edu.cn/kernel/v5.x/
为什么要下载源代码呢?这是因为我们需要对内核进行自定义,添加我们的内核线程(Kthread)相关功能。内核线程是 Linux 中一个强大的工具,它可以让你创建、管理并行任务,非常适合需要实时处理的系统功能。
-
在主机上下载内核源代码:首先从网站下载你需要的内核版本,例如最新的稳定版本 6.11.2。
-
将下载的文件移至 Vagrant 虚拟机:
- 可以通过共享文件夹的方式,将下载的
.tar.xz
文件从主机系统移至虚拟机中。 - 或者使用
scp
命令从主机传输到虚拟机。
- 可以通过共享文件夹的方式,将下载的
-
在虚拟机中解压和编译:
- 将文件复制到你的工作目录,比如
/home/seed/work
。mv /home/vagrant/csc3150/linux-5.15.10 /home/seed/work
- 然后解压、配置、编译和安装内核。
- 将文件复制到你的工作目录,比如
共享文件夹的挂载和使用需要在 Vagrant 配置文件(Vagrantfile
)中进行配置,比如:
config.vm.synced_folder "path/to/your/local/folder", "/vagrant"
2. 安装依赖和开发工具
在编译内核之前,需要安装必要的依赖包和开发工具。这些工具将帮助我们顺利完成编译过程。
sudo apt-get install libncurses-dev gawk flex bison openssl libssl-dev dkms libelf-dev libudev- dev libpci-dev libiberty-dev autoconf llvm dwarves
这些工具中的每一个都有特定用途:
-
libncurses-dev:用于支持终端用户界面(TUI),例如菜单配置。
-
flex 和 bison:是词法分析器和语法分析器生成工具,用于构建和解析内核配置。
-
openssl 和 libssl-dev:用于加密功能,确保内核中数据的安全性。
这些工具的安装是内核编译的基础,因为内核编译涉及到大量复杂的配置和依赖,少了其中任何一个都会导致编译失败。
3. 解压内核源代码
将下载的内核源代码解压到工作目录:
cp KERNEL_FILE.tar.xz /home/seed/work
cd /home/seed/work
$sudo tar xvf KERNEL_FILE.tar.xz
在这里,我们将源代码解压到 /home/seed/work
,这是为了确保我们的工作环境干净且可控,避免对系统的其他部分产生影响。
4. 复制配置文件
从 /boot
目录中复制系统当前的配置文件,以作为内核编译的基础配置:Copy config from /boot to /home/seed/work/KERNEL_FILE
这个步骤的目的是使用现有内核的配置,确保我们在编译过程中不会遗漏关键的选项。
§Login root account and go to kernel source directory
$sudo su
$cd /home/seed/work /KERNEL_FILE
5. 开始配置和编译内核
清理之前的设置并重新配置
make mrproper
make clean
make menuconfig
-
make mrproper:清除之前编译留下的临时文件。
-
make clean:删除编译生成的对象文件,确保干净的编译环境。
-
make menuconfig:进入内核配置界面,可以在这里添加我们的模块,例如 Kthreads
-
save the config and exit
对于 Kthreads 入门,我们需要确保内核支持内核线程的调度和管理。因此,在 menuconfig
中检查线程相关的配置非常重要。
6. 编译内核和模块
使用 make bzImage
和 make modules
来分别编译内核镜像和模块。-j$(nproc)
表示使用所有可用的 CPU 内核来加快编译速度。
make bzImage -j$(nproc)
make modules -j$(nproc)
make –j$(nproc)
这个步骤可能需要较长时间,因为内核编译涉及大量代码。如果你对 Kthreads 有了解,这部分的内容实际上就是内核如何将各个线程(包括我们创建的内核线程)组织到内核模块中。
7. 安装模块和内核
编译完成后,安装模块和内核:
make modules_install
make install
这些命令会把编译好的内核和模块安装到系统中,以便在重启时加载新的内核版本。
8. 重启并选择新内核
重启系统并选择新编译的内核版本:
reboot
在重启过程中,你需要在引导菜单中选择新编译的内核版本,以确保加载我们新加入的 Kthreads 模块。
9. 验证内核版本
验证当前运行的内核版本:
uname -r
这样可以确认我们是否成功运行了刚刚编译的内核。
编译过程中常见问题
-
文件或目录不存在:
-
确保在 Linux 环境中解压源代码,而不是在 Windows 或 macOS 中解压。不同的操作系统可能对文件名大小写敏感性处理不同,可能导致文件找不到。
-
-
磁盘空间不足:
-
内核源代码较大,编译过程需要大量的磁盘空间,建议将源代码移动到有足够空间的目录下再继续编译。
-
-
共享文件夹的问题:
-
如果你使用虚拟机进行开发,确保共享文件夹正确挂载,避免由于共享文件夹的问题导致编译失败。
-
EXPORT_SYMBOL 的使用
在实现 Kthreads 的过程中,我们可能需要使用一些内核函数,这些函数需要通过 EXPORT_SYMBOL()
导出,才能被其他模块使用。例如,do_wait()
函数是用于等待子进程结束的常用函数,需要先在源码中进行导出。
代码示例
编译内核的完整命令流程
-
下载并解压内核源代码
-
复制配置文件
-
清理设置并开始配置
-
编译内核镜像和模块
-
安装内核模块和内核
-
重启系统并选择新内核
-
验证内核版本
构建内核对象
在进行内核模块的加载和测试时,我们还需要构建内核对象。以下是一个构建内核对象的 Makefile 示例:
-
KM
是内核对象的名称。 -
使用
make
命令来构建内核对象。 -
使用
make clean
命令可以清除所有构建文件,只保留原始的.c
文件和 Makefile。
当你在虚拟环境中进行开发时,使用这些命令来构建和清理内核模块可以帮助你保持代码的整洁,并确保每次构建都是从干净的环境开始。
插入和移除内核模块
在构建内核对象之后,我们需要将其插入内核进行测试,并在不需要时将其移除。
插入内核模块
在插入内核对象之前,你需要以 root 用户身份登录:
然后使用以下命令插入内核模块:
列出插入的模块
要列出当前插入的模块,可以使用以下命令:
这样可以确认我们的模块是否已经成功插入内核。
移除内核模块
在不需要使用模块时,记得将其移除:
这可以释放系统资源,确保内核的稳定性。