基本概念

(1)模块本身不被编译入内核映像,从而控制了内核镜像的大小。模块一旦insmod,它就和内核中的其他部分完全一样

(2)内核中已加载模块的信息也存在于/sys/module目录下;内核中将包含/sys/module/test_mod目录

(3)modprobe在加载某模块时,会同时加载该模块所依赖的其他模块。使用modprobe命令加载的模块若以“modprobe -r filename”的方式卸载,将同时卸载其依赖的模块

加载函数

(1)Linux内核模块加载函数一般以__init标识声明,它返回整型值;若初始化成功,应返回0。而在初始化失败时,应该返回错误编码

(2)在Linux中,所有标识为__init的函数如果直接编译进入内核,成为内核镜像的一部分,在连接的时候都会放在.init.text这个区段内--#define _ _init _ _attribute_ _ ((_ _section_ _ (".init.text")))

(3)所有的__init函数在区段.initcall.init中还保存了一份函数指针,在初始化时内核会通过这些函数指针调用这些__init函数,并在初始化完成后,释放init区段(包括.init.text、.initcall.init等)的内存

(4)数据也可以被定义为__initdata,对于只是初始化阶段需要的数据,内核在初始化完后,也可以释放它们占用的内存

(5)在Linux内核中,可以使用request_module(const char*fmt,…)函数加载内核模块

static int hello_data __initdata = 1;
static int __init hello_init(void)
{
    printk(KERN_INFO "Hello, world %d\n", hello_data);
    return 0;
}
module_init(hello_init);

卸载函数

Linux内核模块加载函数一般以__exit标识声明,在模块卸载的时候执行,而不返回任何值;只是退出阶段采用的数据也可以用__exitdata来形容

static void _ _exit hello_exit(void)
{
 /* 释放代码 */
}
module_exit(hello_exit);

模块参数

(1)可以用“module_param(参数名,参数类型,参数读/写权限)”为模块定义一个参数,参数类型可以是byte、short、ushort、int、uint、long、ulong、charp(字符指针)

(2)也可以拥有参数数组,形式为“module_param_array(数组名,数组类型,数组长,参数读/写权限,使用逗号分隔输入的数组元素;在/sys目录下,也可以看到某模块的参数

(3)在装载内核模块时,用户可以向模块传递参数,形式为“insmode(或modprobe)模块名参数名=参数值”,如果不传递,参数将使用模块内定义的缺省值

(4)如果模块被内置,无法insmod了,bootloader可以通过在bootargs里设置“模块名.参数名=值”的形式给该内置的模块传递参数

static char *pig_name = "Peppa";
module_param(pif_name, charp, S_IRUGO);
static int pig_age = 4000;
module_param(pig_age, int, S_IRUGO);

导出符号

Linux的“/proc/kallsyms”文件对应着内核符号表,它记录了符号以及符号所在的内存地址;经过下面接口导出到/proc/kallsyms的符号就可以被其他模块使用

EXPORT_SYMBOL(sym_name);
EXPORT_SYMBOL_GPL(sym_name);

模块声明

可以用MODULE_AUTHOR、MODULE_DESCRIPTION、MODULE_VERSION、MODULE_DEVICE_TABLE、MODULE_ALIAS分别声明模块的作者、描述、版本、设备表和别名

MODULE_AUTHOR(author);
MODULE_DESCRIPTION(description);
MODULE_VERSION(version_string);
MODULE_DEVICE_TABLE(table_info);
MODULE_ALIAS(alternate_name);

模块示例

示例代码

#include <linux/module.h>
#include <linux/kernel.h>

static int __init test_mod_init(void){
    printk("test_mod init!\n");
    return 0;
}

static void __exit test_mod_exit(void){
    printk("test_mod exit\n");
}

module_init(test_mod_init);
module_exit(test_mod_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("LYT");

示例Makefile

export STAGING_DIR=交叉编译工具绝对路径
CROSS_COMPILE:= 交叉编译工具绝对路径/arm-openwrt-linux-muslgnueabi-
ARCH:= arm
#CC:= $(CROSS_COMPILE)gcc
#LD:= $(CROSS_COMPILE)ld

obj-m:=test_mod.o

KDIR:=内核根目录绝对路径
PWD:=$(shell pwd)

default:
        $(MAKE) -C $(KDIR) M=$(PWD) modules ARCH=$(ARCH)

clean:
        $(MAKE) -C $(KDIR) M=$(PWD) clean
        $(RM) Module.markers modules.order
        $(RM) $(PWD)/src/modules/kmod/client/kmod/Module.markers
        $(RM) $(PWD)/src/modules/kmod/client/kmod/modules.order

打印

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部