【Linux驱动开发100问】什么是模块?如何编写和使用模块?

在这里插入图片描述

🥇今日学习目标:什么是Linux内核?
🤵‍♂️ 创作者:JamesBin
⏰预计时间:10分钟
🎉个人主页:嵌入式悦翔园个人主页
🍁专栏介绍:Linux驱动开发100问

一、什么是模块

在 Linux 内核中,模块是一种动态加载和卸载的可执行文件,它可以在运行时向内核添加新的功能和驱动。 与编译进内核的代码相比,模块的使用可以减少内核的体积和启动时间,并且可以让内核更加灵活,根据需要动态地添加或删除功能。

模块可以是设备驱动、文件系统、网络协议、安全模块等,通过内核提供的模块管理接口,可以动态地插入和删除模块。模块的代码通常是以源码形式提供,需要编译成二进制文件才能加载到内核中运行。模块也可以被其他模块所依赖,形成模块之间的依赖关系。

模块的使用可以帮助我们解决很多问题,例如:

  1. 节省内存空间:模块可以按需加载,不需要一直占用内存,从而节省内存空间。
  2. 扩展内核功能:模块可以添加新的设备驱动程序、文件系统、网络协议等内核功能。
  3. 提高系统安全性:模块可以对内核进行功能增强,从而提高系统的安全性。

总之,模块是Linux内核中一个非常重要的组成部分,可以让内核变得更加灵活、可扩展和可维护。

Linux模块可以是驱动,也可以是其他功能模块。模块和驱动之间存在一定的关系,因为驱动通常也是作为模块的形式存在于内核中的。

在Linux内核中,模块可以被动态地插入和卸载,因此模块通常被用来扩展内核的功能。而驱动则是一种特殊的模块,用于管理硬件设备,控制硬件设备的操作。在Linux中,驱动通常也以模块的形式存在于内核中,从而使得内核可以支持更多的硬件设备。因此,可以说驱动是模块的一种特殊形式。

二、如何编写模块

编写Linux内核模块需要遵循以下步骤:

1、包含必要的头文件

在C文件的开头,需要包含一些头文件,比如<linux/module.h><linux/init.h>等,这些头文件包含了模块开发所需的函数和宏等。

2、编写模块初始化和退出函数

模块初始化函数是模块载入时调用的函数,模块退出函数是模块被卸载时调用的函数。模块初始化函数需要使用宏module_init进行定义,模块退出函数需要使用宏module_exit进行定义。

3、定义模块许可证

Linux内核模块的代码需要遵循一定的许可证,这可以在模块代码中使用宏MODULE_LICENSE进行定义。

4、编写模块代码

这是编写模块最主要的部分。模块代码需要定义模块的功能,并提供接口以便其他程序可以使用这些功能。

下面是一个简单的Linux内核模块代码示例:

#include <linux/module.h>  // 模块头文件
#include <linux/init.h>    // 初始化函数头文件

static int __init hello_init(void) // 初始化函数
{
    printk(KERN_ALERT "Hello, world!\n");  // 打印信息
    return 0;
}

static void __exit hello_exit(void) // 退出函数
{
    printk(KERN_ALERT "Goodbye, cruel world!\n"); // 打印信息
}

MODULE_LICENSE("Dual BSD/GPL"); // 定义许可证

module_init(hello_init); // 定义初始化函数
module_exit(hello_exit); // 定义退出函数

三、如何编译模块

编译 Linux 模块可以使用 make 工具来完成,需要使用内核源码目录中的 Makefile 文件。下面是具体步骤:

进入 Linux 内核源码目录,并切换到要编译的内核版本分支。

运行命令 make modules_prepare,该命令会生成 Module.symvers 文件,该文件包含了内核中所有可导出符号的信息,包括符号名、地址和版本等。

进入模块源码所在的目录,并创建一个名为 Makefile 的文件。

在 Makefile 文件中添加以下内容:

obj-m := module_name.o

其中 module_name 表示模块的名称,.o 表示编译后生成的目标文件格式。

运行命令

make -C /lib/modules/$(uname -r)/build M=$(pwd) modules

-C 选项指定内核源码目录,$(uname -r) 表示当前系统运行的内核版本号。
M 选项指定模块源码目录。

如果编译成功,将会生成一个名为 module_name.ko 的文件,该文件即为编译后的模块文件。

四、如何挂载和卸载模块

我们上一步骤通过make命令编译出来的.ko文件即为在最终的模块文件,如果想要使用该模块文件还需要使用 insmod 命令加载模块,例如:

$ sudo insmod module_name.ko

如果需要卸载模块,可以使用 rmmod 命令,例如:

$ sudo rmmod module_name

注意,在加载和卸载模块时需要拥有管理员权限。

为什么要挂载和卸载模块?

在Linux内核中,模块是可以被动态加载和卸载的。当内核启动时,并不会将所有的模块都加载进来,而是按需加载,这样可以提高系统的启动速度和节省内存空间。

当需要使用某个模块时,就需要将它挂载到内核中,使得内核能够调用模块中的功能。而当不再需要某个模块时,可以将其从内核中卸载,释放内存空间。因此,模块的挂载和卸载是为了方便动态管理模块的加载和卸载,提高系统的效率和稳定性。

五、如何使用模块

假设我们已经编写好了一个名为hello_module的内核模块,现在需要编写一个测试程序来调用该模块。下面是一个简单的测试程序代码示例:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
    int fd = open("/dev/hello", O_RDWR);
    if (fd < 0) {
        perror("Failed to open device /dev/hello");
        exit(1);
    }

    char buf[32];
    int ret = read(fd, buf, sizeof(buf));
    if (ret < 0) {
        perror("Failed to read from device /dev/hello");
        close(fd);
        exit(1);
    }

    printf("Read from /dev/hello: %s\n", buf);

    close(fd);
    return 0;
}

该测试程序的作用是打开内核模块创建的设备文件/dev/hello,然后从设备文件中读取数据并打印到控制台。接下来,我们需要编译和运行这个测试程序。

首先,我们需要将测试程序的源代码保存为一个名为test.c的文件。我们可以使用gcc编译器来编译该程序:

$ gcc -o test test.c

这将生成一个名为test的可执行文件。接下来,需要将该可执行文件拷贝到Linux系统中运行。可以通过SSH等方式将文件传输到Linux系统中。在运行测试程序之前需要为测试程序添加可执行权限:

$ chmod +x test

现在,我们就可以运行测试程序了:

$ ./test

运行程序后,应该能够看到从/dev/hello设备文件中读取的数据被打印到控制台上。

模块内打印的信息可以通过dmesg命令进行打印,可以看到测试程序调用模块的过程。

六、相关知识

除了如何编写、编译和使用模块之外,还需要了解以下知识:

  1. 模块的依赖关系:在编写和使用模块时,需要考虑模块之间的依赖关系。如果一个模块依赖于另一个模块,则必须在前者之前将后者加载。否则,前者将无法正确运行。

  2. 模块的参数传递:有些模块需要在加载时传递参数。这些参数可以用于配置模块的行为或传递信息给模块。模块参数的传递方式有很多种,包括命令行参数、环境变量、配置文件等。

  3. 模块的版本管理:内核版本更新时,模块也需要相应更新。因此,需要了解如何为不同版本的内核编写适配的模块。

  4. 模块的调试:在开发模块时,可能会遇到各种各样的问题。因此,需要了解如何调试模块,例如使用 printk() 输出调试信息、使用 gdb 调试等。

  5. 模块的安全性:模块可以在内核空间执行,因此需要确保模块的安全性。内核提供了各种安全机制,例如模块签名验证、模块加载限制等。

👇点击下方公众号卡片获取资料👇
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值