本文详细记录在 Ubuntu 24.10
系统上编译 Linux
内核、创建最小化运行环境,并添加自定义内核模块的全过程。所有操作均在 VMware
虚拟机环境下验证通过。
使用的系统镜像是 ubuntu-24.10-desktop-amd64.iso
一、环境准备与内核编译
首先第一步是在桌面创建一个文件夹,这里我就取名为 linux
,在 linux
文件夹中打开终端
接着我们需要获取内核的源码,去 官网 https://kernel.org 下载最新的稳定版,这里我们就下载 stable:6.13.8 ,复制 tarball
的链接后,到前面在linux文件夹中打开的终端,输入:
1 2
| wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.13.8.tar.xz
|
在下载完成之后我们需要对文件夹进行解压缩,输入:
1 2
| tar -xf linux-6.13.8.tar.xz
|
解压完成后进入该文件夹,输入:
此时内核的源代码中已经有 Makefile
,因此可以直接 make
这里我们使用默认配置,输入:
接着就开始内核的编译,因为我的虚拟机就两核因此使用双线程,大家可以根据自己的配置进行调整,输入:
接着就是漫长的等待,编译完成后会生成 arch/x86/boot/bzImage
内核文件
二、最小化环境测试
接着我们使用 QEMU
这个模拟器进行内核功能的测试,输入:
1
| qemu-system-x86_64 -kernel arch/x86/boot/bzImage
|
但是只有内核本身是跑不起来的,此时我们要返回 linux
文件夹,并在 linux
文件夹内创建 shell
文件夹,然后在 shell
文件夹内创建 shell.c
文件,输入:
1 2 3 4 5 6 7
| cd .. mkdir shell cd shell
vim shell.c
|
接着可以编写一个简单的 c
程序试验一下,输入:
1 2 3 4 5 6 7 8 9 10 11 12
| #include<stdio.h> int main() { char a; while(1) { printf("Are you OK?"); scanf("%c",&a); } return 0; }
|
接着编译并运行,输入:
现在已经可以顺利运行该 shell.c
文件了,为了使编译生成的文件不被动态地链接到其他无关的库,则在编译时使用 -static
,输入:
接着将可运行文件重命名为 init
,这是 linux
内核默认搜索的一个文件名,输入:
然后再将其打包成一个 cpio
格式的压缩包,输入:
1 2
| echo "init" | cpio -H newc -o > init.cpio
|
在文件压缩成功之后再使用 qemu
尝试启动,输入:
1 2
| qemu-system-x86_64 -kernel ../linux-6.13.8/arch/x86/boot/bzImage -initrd init.cpio
|
运行后输出是:

此时 QEMU
已成功启动自定义内核,编译内核至此已经完成了,接下来将是添加内核模块
三、添加内核模块
此时的目录结构应为:
1 2 3 4 5 6
| ~/桌面/linux/ ├── linux-6.13.8/ ├── shell/ │ ├── init │ ├── init.cpio │ └── shell.c
|
接着开始编写内核模块,在 shell/
目录下新建文件 hello.c
,编写模块的源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h>
MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("A simple Linux kernel module");
static int __init hello_init(void) { printk(KERN_INFO "Hello, Kernel Module loaded!\n"); return 0; }
static void __exit hello_exit(void) { printk(KERN_INFO "Goodbye, Kernel Module unloaded.\n"); }
module_init(hello_init); module_exit(hello_exit);
|
然后是编写模块的 Makefile
,在同一目录下创建 Makefile
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| obj-m := hello.o
KDIR := ~/桌面/linux/linux-6.13.8
PWD := $(shell pwd)
all: make -C $(KDIR) M=$(PWD) modules
clean: make -C $(KDIR) M=$(PWD) clean
|
接着开始编译内核模块,进入shell/
目录并编译,输入:
1 2 3 4
| cd ~/桌面/linux/shell
make
|
此时若成功则会输出:
1 2 3 4 5
| make -C ~/桌面/linux/linux-6.13.8 M=~/桌面/linux/shell modules CC [M] ~/桌面/linux/shell/hello.o MODPOST 1 modules CC ~/桌面/linux/shell/hello.mod.o LD [M] ~/桌面/linux/shell/hello.ko
|
检查模块信息,应包含许可证、作者等信息,输入:
四、集成与完整测试
修改用户态 init
程序,更新 shell.c
,使其加载内核模块并交互:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| #include <stdio.h> #include <stdlib.h> #include <unistd.h>
int main() { printf("=== My Minimal Shell ===\n"); system("insmod /hello.ko"); printf("Kernel module loaded. Check dmesg.\n");
int input; while (1) { printf("Enter '0' to exit: "); scanf("%d", &input); if (input == 0) break; }
system("rmmod hello"); printf("Kernel module unloaded.\n");
return 0; }
|
接着编译并打包新的 initramfs
,输入:
1 2 3 4 5 6 7 8 9 10
| gcc -static shell.c -o init
chmod +x init
cd ~/桌面/linux/shell
echo -e "init\nhello.ko" | cpio -o -H newc > init.cpio
|
最后是通过 QEMU
启动完整测试,输入:
1 2 3 4 5
| qemu-system-x86_64 \ -kernel ~/桌面/linux/linux-6.13.8/arch/x86/boot/bzImage \ -initrd ~/桌面/linux/shell/init.cpio \ -nographic -append "console=ttyS0"
|
输出:
1 2 3
| === My Minimal Shell === Kernel module loaded. Check dmesg. Enter '0' to exit:
|
输入 0
退出程序后,检查卸载日志,输入:
输出:
1
| Goodbye, Kernel Module unloaded.
|
运行后的输出是:

通过以上步骤,即可完成从内核编译到模块开发的完整流程。
但是目前仍存在部分小问题,等待后续学习修正。