Linux如何加载内核模块(.ko)?

Linux内核模块(Kernel Object,后缀为.ko)是Linux系统中实现动态扩展内核功能的核心机制,允许在不重新编译内核的情况下添加驱动程序、文件系统支持或系统调用等功能,加载.ko模块是系统管理员和开发者常见的操作,其过程涉及模块编译、依赖管理、参数传递及内核交互等多个环节,以下将详细阐述Linux加载.ko模块的完整流程、关键命令及注意事项。

linux如何加载ko

内核模块的基础概念

Linux内核采用宏内核架构,但通过模块机制实现了“内核核心功能+动态扩展”的灵活设计,模块本质上是编译后的目标文件(.ko),包含初始化函数(在模块加载时执行)和清理函数(在模块卸载时执行),与内核核心通过符号表(导出/导入函数和变量)交互,模块加载后,其代码和数据会集成到内核空间,成为内核的一部分,因此需确保模块来源可靠,避免系统不稳定。

模块的编译与准备

加载.ko模块的前提是正确编译出符合当前内核版本的模块文件,编译过程需依赖内核头文件(kernel headers)和构建工具(如make、gcc)。

安装依赖工具

以Ubuntu/Debian为例,需安装以下包:

sudo apt install build-essential linux-headers-$(uname -r)

linux-headers-$(uname -r)提供了当前内核版本的头文件,确保模块与内核兼容。

编写模块代码与Makefile

以简单的“Hello World”模块为例,创建hello.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
static int __init hello_init(void) {
    printk(KERN_INFO "Hello, Linux module!n");
    return 0;
}
static void __exit hello_exit(void) {
    printk(KERN_INFO "Goodbye, Linux module!n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");  // 许可证声明(避免内核taint警告)
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple Hello World module");

创建Makefile(与hello.c同目录):

obj-m += hello.o
all:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

执行make编译后,生成hello.ko文件。

模块加载的常用方法

加载.ko模块主要有三种方式:insmod(直接加载)、modprobe(智能加载,处理依赖)和通过配置文件自动加载(系统启动时加载)。

使用insmod命令直接加载

insmod是最基础的加载命令,需指定模块的绝对路径,不处理模块依赖关系,适用于无依赖的简单模块。

语法

sudo insmod /path/to/module.ko [param=value ...]

示例

sudo insmod ./hello.ko

特点

  • 需手动解决依赖问题(若模块依赖其他未加载模块,会失败)。
  • 加载时可通过命令行传递参数(需模块代码中定义参数,如module_param(name, int, 0644))。

使用modprobe命令智能加载

modprobe是更推荐的加载工具,属于module-init-toolskmod包,功能包括:

linux如何加载ko

  • 自动解析模块依赖关系(通过modules.dep文件),按顺序加载依赖模块;
  • 支持模块别名(alias),可通过别名加载模块;
  • 支持从/lib/modules/$(uname -r)/kernel/目录查找模块(无需绝对路径)。

语法

sudo modprobe [module_name] [param=value ...]

示例

sudo modprobe hello  # 假设hello.ko已复制到/lib/modules/$(uname -r)/kernel/misc/或/etc/modprobe.d/配置的路径

依赖管理
modprobe依赖/lib/modules/$(uname -r)/modules.dep文件,该文件由depmod命令生成,若新增模块或更新内核,需运行:

sudo depmod -A  # 更新依赖关系

通过配置文件自动加载

若需系统启动时自动加载模块,可通过以下方式配置:

(1) /etc/modules-load.d/目录

在该目录下创建.conf文件(如my_module.conf),写入模块名(每行一个):

echo "hello" | sudo tee /etc/modules-load.d/my_module.conf

系统启动时,systemd会读取此文件并自动加载模块。

(2) /etc/modprobe.d/目录(配置模块参数

若需指定模块参数,可在此目录下创建配置文件(如hello.conf):

options hello debug=1  # 设置模块参数

参数会在模块加载时自动生效。

模块加载的验证与管理

加载模块后,需验证加载状态、查看日志及管理模块生命周期。

验证模块是否加载

  • lsmod命令:列出已加载的模块,显示模块大小、依赖关系等。

    lsmod | grep hello

    输出示例:

    hello 16384 0 - Live 0xffffffc000800000 (POE)
  • /proc/modules文件:内核内部模块信息表,内容与lsmod一致,可直接查看:

    cat /proc/modules | grep hello
  • dmesg命令:查看内核日志,模块加载时会打印printk输出:

    linux如何加载ko

    dmesg | tail -n 5  # 查看最近5条日志

    若模块加载成功,会看到“Hello, Linux module!”的日志。

查看模块信息

使用modinfo命令查看模块的详细信息,包括作者、描述、参数、许可证等:

modinfo hello.ko

输出示例:

filename:       /path/to/hello.ko
license:        GPL
author:         Your Name
description:    A simple Hello World module
srcversion:     XXXXXXXXXX
depends:        
retpoline:      Y
name:           hello
vermagic:       5.15.0-88-generic SMP mod_unload modversions

模块参数传递

模块可通过module_param宏定义参数,加载时通过insmodmodprobe传递,若模块代码中定义:

static int debug_level = 0;
module_param(debug_level, int, 0644);

加载时可指定参数:

sudo modprobe hello debug_level=2

参数也可在运行时通过/sys文件系统修改:

echo 3 | sudo tee /sys/module/hello/parameters/debug_level

模块的卸载

使用rmmod命令卸载

rmmod用于卸载已加载的模块,需指定模块名(不含.ko后缀):

sudo rmmod hello

若模块被其他程序或内核功能占用,卸载会失败,可通过lsmod查看依赖关系。

使用modprobe -r卸载

modprobe -r可卸载模块及其依赖(需确保依赖模块无其他使用者):

sudo modprobe -r hello

加载失败的常见问题排查

问题现象 可能原因 解决方案
模块版本与内核不匹配 编译模块使用的内核头文件与运行内核不一致 重新安装对应内核版本的linux-headers并编译模块
依赖模块未加载 模块依赖的其他模块未加载 使用modprobe加载依赖模块,或手动insmod依赖模块
模块签名验证失败 内核开启模块签名验证(CONFIG_MODULE_SIG) 禁用签名验证(临时:sudo echo 0 > /proc/sys/kernel/modules/signature)或为模块签名
参数类型或值错误 传递的参数与模块定义的类型不匹配 检查模块代码中参数定义(如intcharp),确保参数值合法

相关问答FAQs

Q1: 加载模块时提示“Invalid module format”怎么办?
A: 通常是因为模块编译时使用的内核头文件版本与当前运行内核版本不一致,解决方法:安装当前内核对应的头文件包(如linux-headers-$(uname -r)),然后重新编译模块,若问题仍存在,检查内核是否开启了特定配置(如CONFIG_MODVERSIONS),确保编译时启用-DMODVERSIONS选项并包含linux/version.h

Q2: 如何查看模块被哪些进程或功能占用?
A: 若rmmod提示“Module is in use”,可通过以下方式排查占用者:

  1. 查看/proc/modules中模块的Usecount字段(非0表示被占用);
  2. 使用lsof命令查找占用模块的文件(如lsof | grep module_name);
  3. 对于内核模块,可通过grep -r "module_name" /proc/*/maps查看哪个进程映射了模块内存;
  4. 若为驱动模块,可检查/sys/module/module_name/holders目录,显示持有模块的设备实例。

原创文章,发布者:酷番叔,转转请注明出处:https://cloud.kd.cn/ask/30970.html

(0)
酷番叔酷番叔
上一篇 2025年9月26日 22:25
下一篇 2025年9月26日 22:44

相关推荐

  • Linux开发板终端如何打开?

    在Linux环境下打开开发板终端是嵌入式开发中的基础操作,通常通过串口、网络(如SSH)或专用调试工具(如J-Link、ST-Link)实现,以下是具体操作步骤和注意事项,涵盖常见开发板类型(如树莓派、STM32、BeagleBone等)和连接方式,准备工作:硬件连接与工具安装在打开终端前,需确保硬件连接正确……

    2025年9月28日
    1100
  • Linux系统如何进入修改模式?

    Linux系统中的“修改模式”通常指进入特殊运行状态以进行系统配置修复、密码重置或内核参数调整等操作,根据不同场景,可通过GRUB引导菜单、systemd目标切换或命令行工具进入,以下是具体操作方法和适用场景说明,通过GRUB引导菜单进入修改模式GRUB(Grand Unified Bootloader)是Li……

    2025年9月26日
    2000
  • Linux启动过程是怎样的?

    启动阶段:从硬件到内核固件初始化(BIOS/UEFI)当计算机通电时,首先由主板上的固件(BIOS 或 UEFI)执行硬件自检(POST),检测 CPU、内存、硬盘等关键组件,UEFI 作为现代标准,支持更快的启动和安全验证(如 Secure Boot),引导加载程序(Boot Loader)固件将控制权交给引……

    2025年7月6日
    5000
  • Linux端口如何开启?

    开放端口前的准备确认需要开放的端口号HTTP服务:80/TCPHTTPS服务:443/TCPSSH服务:22/TCP自定义服务:如3000/TCP检查端口是否已被监听运行命令查看当前监听端口的服务:sudo ss -tuln | grep LISTEN# 或使用传统命令sudo netstat -tuln……

    2025年7月10日
    5200
  • 如何安全删除Linux用户的系统文件夹?

    在Linux系统中删除文件夹是一项需要谨慎操作的任务,尤其是涉及系统关键目录或用户重要数据时,错误的删除操作可能导致数据丢失、程序异常甚至系统崩溃,本文将详细介绍删除Linux系统文件夹的正确方法、常用命令、安全注意事项及常见问题处理,帮助用户安全高效地完成文件夹删除操作,删除前的准备工作在执行删除操作前,必须……

    2025年9月13日
    2600

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们

400-880-8834

在线咨询: QQ交谈

邮件:HI@E.KD.CN

关注微信