一些重要的宏和数据结构

这两个宏用于为Kernel标识模块初始化和模块清除阶段的函数
__init:会在初始化内核模块后被丢弃,将内存分配给其他用途
__exit:如果模块未被配置为可卸载模块的情况下会直接被丢弃

很重要的内核API定义头文件:#include <linux/sched.h>,在该头文件中可以获取到指向task_struct的指针current来获取到当前执行的进程。
可以通过:
current->pid:访问当前进程的ID
current->comm:访问当前进程的命令名

为驱动传递参数

驱动参数

在安装驱动的时候可以为驱动传递参数,需要包含头文件#include <linux/moduleparam.h>主要通过以下的宏进行:
module_param(variable, type, perm)

例如可以通过module_param(howmany,int,S_IRUGO)定义一个int类型的howmany参数

module_param支持:bool、invbool、charp、int、long、short、uint、ulong、ushort

所以可以编写如下代码来接受安装驱动程序时候的参数:

#include <linux/module.h>
#include <linux/init.h>
#include <asm/current.h>
#include <linux/sched.h>

static char *whom = "world";
static int howmany = 1;
module_param(howmany, int, S_IRUGO);
module_param(whom, charp, S_IRUGO);

static int __init test_init(void){
    printk(KERN_ALERT "The process is \"%s\" (pid %i)\n", current->comm, current->pid);
    for(int i = 0; i < howmany; i++){
        printk(KERN_ALERT "%s", whom);
    }
    return 0;
}

static void __exit test_exit(void){
    printk(KERN_ALERT "Goodbye Kernel\n");
}

module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");

module_param中perm字段用来控制谁能够访问sysfs中对模块参数的描述,如果perm被设置为0,就不会有对应的sysfs的入口项。如果对应S_IRUGO代表任何人都可以读取该参数但是不能修改

我们可以使用sudo insmod hello.ko howmany=10 whom="Mom"来带着参数安装该内核模块,之后在dmesg中可以看到Mom被输出了10次
image.png

因为我们将perm字段设置为了任何人可以读取参数,那么我们可以在sysfs中查看到当前内核模块的参数以及现在的值,如果perm被设置为了可写,那么可以直接操作sysfs中的项来更改内核模块中的数据:
image.png

环境配置的问题

直接复制上述代码到vscode中会报KBUILD_MODULE找不到定义的错误,这个变量是在Makefile的时候才生成的,可以在define数组中加入MODULE定义即可修复该问题

还有个问题是current指针无法自动提示task_struct的成员,这里可以设置配置中的browse来开启代码提示:

"browse": {
    "path": [
         "${workspaceFolder}",
         "/usr/src/linux/include",
         "/usr/src/linux/mm",
         "/usr/src/linux/fs",
         "/usr/src/linux/kernel"
     ],
     "limitSymbolsToIncludedHeaders": true,
     "databaseFilename": ""
}

此问题可以在github的issue中找到:https://github.com/microsoft/vscode-cpptools/issues/5588

完整的config文件:

{
    "configurations": [
        {
            "name": "Linux Kernel Module",
            "includePath": [
                "${workspaceFolder}/**",
                "/usr/src/linux/include",
                "/usr/src/linux/include/uapi",
                "/usr/src/linux/include/generated",
                "/usr/src/linux/arch/x86/include",
                "/usr/src/linux/arch/x86/include/uapi",
                "/usr/src/linux/arch/x86/include/generated"
            ],
            "defines": [
                "KBUILD_MODNAME=\"dummyname\"",
                "__GNUC__",
                "__KERNEL__",
                "MODULE"
            ],
            "compilerPath": "/usr/bin/gcc",
            "cStandard": "gnu17",
            "cppStandard": "gnu++17",
            "intelliSenseMode": "linux-gcc-x64",
            "configurationProvider": "ms-vscode.makefile-tools",
            "browse": {
                "path": [
                    "${workspaceFolder}",
                    "/usr/src/linux/include",
                    "/usr/src/linux/mm",
                    "/usr/src/linux/fs",
                    "/usr/src/linux/kernel"
                ],
                "limitSymbolsToIncludedHeaders": true,
                "databaseFilename": ""
            }
        }
    ],
    "version": 4
}