0、前言:
这是一篇以问题为导向,的技术贴!探究linux内核中的 内核模块 如何编译生成;
基础概念库:
1、linux内核源码:
tar -zxvf linux-4.14.21.tar.gz 解压的是 Linux 内核的源码包,它不是一个完整的 Linux 系统,而是 Linux 内核的源代码集合。解压后会生成一个名为 linux-4.14.21 的目录,里面包含了 Linux 内核 4.14.21 版本的所有源代码文件:
内核核心代码(如 kernel/、fs/、net/ 目录);硬件驱动代码(如 drivers/ 目录);编译配置文件(如 Makefile、.config 模板);文档和工具脚本等。这些文件的作用是供开发者编译、定制或研究 Linux 内核。
一个完整的 Linux 系统需要包含:
内核:即你解压的 linux-4.14.21 编译后的可执行程序(如 vmlinuz);用户态组件:包括 Shell(如 bash)、系统工具(如 ls、cd)、库文件(如 libc)、应用程序等;文件系统:包含系统配置、用户数据、启动脚本等。
linux-4.14.21.tar.gz 仅提供了内核的源代码,需要经过编译、配置后,才能生成可运行的内核。
2、在内核文件编译前,设置make menuconfig 后出现的三种内核文件编译选择模式的解释:
make menuconfig 中这三种选择对应内核组件的不同编译和加载方式,核心逻辑就是“按需决定组件是否编译、以及如何集成到系统中”。
三种选择的具体含义:
选 M (Module,模块模式)
编译结果:生成独立的 .ko 模块文件(如 hello.ko ),不直接打包进内核镜像。加载时机:系统启动后,通过 insmod / modprobe 手动加载,不需要时用 rmmod 卸载,实现“动态按需加载”。适用场景:硬件驱动(如USB、网卡驱动)、测试组件等,避免内核镜像过大。
选 * (Built-in,内置模式)
编译结果:组件代码直接编译进内核镜像(如 vmlinuz ),成为内核的一部分。加载时机:系统启动时随内核一起加载,无需手动操作,重启后仍生效。适用场景:内核核心功能(如进程管理、内存管理)、必须随系统启动的组件(如根文件系统驱动)。
什么都不选(空,Disable,禁用模式)
编译结果:组件代码完全不参与编译,既不会生成 .ko 文件,也不会进入内核镜像。适用场景:确定不需要的功能(如特定架构的驱动、冷门文件系统),减少编译时间和内核/模块体积。
具体问题解决:
案例1、在内核中构建测试系统模块
如果遇到 linux 虚拟机内存不够,可以通过 https://www.cnblogs.com/yongdaimi/p/9050155.html 指导方案扩容;
1.1、基础处理
在tar -zxvf linux-4.14.21.tar.gz 的解压文件中新建 hello 模块将系统文件(.tar.gz)拷入虚拟机的linux中桌面路径当中;用tar -zxvf linux-4.14.21.tar.gz解压;
1.2、创建hello内核模块
在linux-4.14.12/drivers/下新建目录hello;在hello/下新建hello.c、Makefile、Kconfig三个文件,内容按照文档内容复制;
#include <linux/module.h> //所有模块都需要的头文件
#include <linux/init.h> // init&exit相关宏
#include <linux/kernel.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("baoli");
MODULE_DESCRIPTION("hello world module");
static int __init hello_init(void)
{
printk("hello world.
");
return 0;
}
static void __exit hello_exit(void)
{
printk("hello exit!
");
}
module_init(hello_init);
module_exit(hello_exit);
makefile中的内容:
obj-$(CONFIG_HELLO) += hello.o
Kconfig中的内容:
menu "HELLO TEST Driver "
comment "HELLO TEST Driver Config"
config HELLO
tristate "hello module test"
default m
help
This is the hello test driver --by Spark.Hao.
endmenu
修改上一级目录的Kconfig和Makefile;
进入linux-4.14-12/drivers/编辑Makefile,在后面添加一行:obj-$(CONFIG_HELLO) += hello/编辑Kconfig,在后面添加一行:source “drivers/hello/Kconfig”
1.3、编译hello内核模块
切到linux-4.14.12/目录(源码根目录),执行make menuconfig,如果报错未下载的话执行sudo apt-get install ncurses-dev,目的是打开make menuconfig图形化界面;

在make menuconfig中配置hello为【M】模式;【可以选择 ,分别为编译成内核模块、编译进内核、不编译】
编译 hello 模块,linux-4.14.12/目录(源码根目录)执行make modules,在drivers的hello文件下生成hello.ko【执行时间长,会把所有M模块都编译一次】

将hello.ko移动到板载根文件目录的中【~/nfs/rootfs/test1】

用secureCRT连接板子,待板子启动linux程序后,可以切换到对应路径下,执行hello.ko【insmod hello.ko】
sudo insmod hello.ko 会将模块加载到内核,此时模块成为内核的一部分,初始化函数(hello_init)被执行,模块信息会被记录在内核的模块管理列表中。
sudo rmmod hello 是手动卸载模块的标准命令,会触发退出函数(hello_exit),释放模块占用的资源,并从内核模块列表中移除。
重启后,所有动态加载的内核模块都会被清空,需要重新用 insmod 加载。
如果模块被其他模块依赖,rmmod 会拒绝卸载(需先卸载依赖它的模块);但内核在某些极端情况下(如模块崩溃)可能强制移除模块(非常见情况)。日常使用中,insmod 是加载模块的主要方式,rmmod 是手动卸载的唯一常规方式,其他移除场景(如重启)属于系统级操作,而非主动卸载。
1.4、总结:
整个流程就是相当于体验了linux内核源码中如何创建内核模块,内核模块,相当于linux系统的动态文件,在linux运行需要时加载;在虚拟机的linux系统中没法用insmod hello.ko调用,因为这个内核模块是linux-4.14编译出来的,我的虚拟机当中的linux系统版本是5.15.0,所以需要在开发板上电后,在开发板上才能运行;
















暂无评论内容