Linux模块编写

Linux模块基础、带参数模块、内核模块符号导出

驱动模块基础格式:

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

static int __init helloworld_init(void){
    printk(KERN_EMERG "helloworld init!\r\n");
    return 0;
}

static void __exit helloworld_exit(void){
    printk(KERN__EMERG "helloworld exit\r\n");
}

module_init(helloworld_init);
module_exit(helloworld_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("LYT");

编写Makefile

export ARCH=arm64					#设置ARCH变量为arm64
export CROSS_COMPILE=aarch64-linux-gnu-		#设置交叉编译器前缀
obj -m += helloworld.o				#helloworld要与.c文件名称一致,将文件以模块形式编译
KDIR :=/home/lishu/rk3568/kernel   #内核源码所在虚拟机ubuntu的实际路径
PWD ?= $(shelll pwd)				#获取当前目录的变量
all:
	make -C $(KDIR) M=$(PWD) modules #make操作  #进入内核源码路径,把当前路径下的代码编译成模块
clean:
	make -C $(KDIR) M=$(PWD) clean   #make clean操作

最终生成helloworld.ko文件。

模块加载与卸载

insmod helloworld.ko

rmmod helloworld

lsmod

带参驱动模块:

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

static int number;
static char *name;
static int pra[8];
static char strl[10];
static int n_para;
module_para(number,int,S_IRUGO);
module_param(name,charp,S_IRUGO);
module_param_array(para,int ,&n_para,S_IRUGO);
module_param_string(str,str1,sizeof(str1),S_IRUGO);

static int __init parameter_init(void){
	static int i;
	printk(KERN_EMERG "%d\n",number);
	printk(KERN_EMERG "%s\n",name);
	for(i=0;i<n_para;i++)
	{
		printk(KERN_EMERG "para[%d] : %d \n",i,para[i]);
	}
	printk(KERN_EMERG "%s\n",str1);
	retrun 0;
}

static void __exit parameter_exit)(void)
{
	printk(KERN_EMERG "parameter_exit\n");
}

module_init(parameter_init);
module_exit(parameter_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("LYT");

insmod parameter.ko number=100 name=“lyt” para=0,1,2,3,4,5,6,7 str=“itop”

内核提供的传参宏:

#define module_param(name,type,perm)	module_param_named(name,name,type,perm)
#define module_param_array(name,type,nump,perm) 
#define module_param_string(name,string,len,perm) 	
  • name:模块参数的名称;外部传入的参数名,即加载模块时的传入值
  • type:模块参数的数据类型
  • perm:模块参数的访问权限
  • nump:传递数组元素的个数
  • string:内部的变量名,即程序内定义的参数名
  • len:以string命名的buffer大小(可以小于buffer的大小,但是没意义)
type可以取以下值:
boot:布尔型
inbool:布尔反值
charp:字符指针 (相当于char* ,不超过1024字节的字符串)
short:短整型
ushort:无符号短整型
int:整型
uint:无符号整型
long:长整型
ulong:无符号长整型
    
perm表示该参数所对应的文件节点的属性,可以用宏定义 or 数字
#define S_IRUSR 00400	/*文件所有者可读*/
#define S_IWUSR 00200	/*文件所有者可写*/
#define S_IXUSR	00100	/*文件所有者可执行*/
#define S_IRGRP	00040	/*与文件所有者同组的用户可读*/
#define S_IWGRP	00020	/*与文件所有者同组的用户可写*/
#define S_IXGRP	00010	/*与文件所有者同组的用户可执行*/
#define S_IROTH	00004	/*与文件所有者不同组的用户可读*/
#define S_IWOTH	00002	/*与文件所有者不同组的用户可写*/
#define S_IXOTH	00001	/*与文件所有者不同组的用户可执行*/

内核模块符号导出:

调用其他模块中的函数、变量。

calculate.c

#include <linux/init.h>
#include <linux/module.h>
static int c;
static int d;
module_param(c,int,S_IRUGO);//驱动模块传参
module_param(d,int S_IRUGO);

extern int num;		//导入int类型变量num
extern int add(int a,int b); //导入函数add
static int __init calculate_init(void)//驱动入口函数
{
    static int sum;
    printk("num = %d\n",num);//打印num值
    sum = add(c,d);//使用add函数进行3+4的运算
    printk("sum = %d\n",sum);//打印add函数的运算值
    return 0;
}

static void __exit calculate_exit(void)//驱动出口函数
{
    printk("Goodbye hello module\n");
}

module_init(hello_init);//注册入口函数
module_exit(hello_exit);//注册出口函数

MODULE_LICENSE("GPL");//同意GPL开源协议
MODULE_AUTHOR("lyt");//作者信息

mathmodule.c

#include <linux/init.h>
#include <linux/module.h>
int num = 10;//定义参数num
EXPORT_SYMBOL(num);//导出参数num

int add(int a,int b)//定义数学函数add
{
    return a+b;
}
EXPORT_SYMBOL(add);//导出数学函数add

static int __init math_init(void)//驱动入口函数
{
    printk("math_module init\n");
    return 0;
}

static void __exit math_exit(void)//驱动出口函数
{
    printk("math_module exit\n");
}

module_init(math_init);//注册入口函数
module_exit(math_exit);//注册出口函数

MODULE_LICENSE("GPL");//同意GPL开源协议
MODULE_ATHOR("lyt");//作者信息

Makefile

export ARCH=arm64						#设置平台架构
export CROSS_COMPILE=aarch64-linux-gnu-	#交叉编译器前缀
obj-m := mathmodule.o
obj-m += calaulate.o
    
KDIR := /home/lishu/rk3568/kernel		#内核目录
PWD ?= $(shell pwd)
all:
	make -C $(KDIR) M=$(PWD) modules	#make操作
clean:
	make -C $(KDIR) M=$(PWD) clean		#make clean操作

insmod mathmodule.ko

insmod calaulate.ko c=2 d=3

  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Linux内核模块编写是指在Linux操作系统中编写可动态加载和卸载的内核模块,以扩展操作系统的功能或添加新的设备驱动程序。内核模块编写需要掌握C语言编程技能和Linux内核的基本知识,包括内核数据结构、系统调用、进程管理、内存管理、设备驱动等。编写内核模块需要遵循一定的规范和流程,包括编写Makefile文件、定义模块参数、注册模块、实现模块功能、编写模块文档等。内核模块编写对于Linux系统的开发和维护非常重要,可以为系统添加新的功能和设备支持,提高系统的可靠性和性能。 ### 回答2: Linux内核模块是一段能够扩展或增强Linux内核功能的代码,它可以动态地加载或卸载到内核中运行。Linux内核模块编写需要遵循一定的规范和步骤,下面是详细介绍。 一、编写和编译内核模块 1、编写内核模块源代码,通常以.c或.cpp文件为扩展名。 2、生成一个Makefile文件,编写编译和链接内核模块所需的命令。 3、进入内核源代码目录,运行make命令编译内核模块,生成模块的.ko文件。 二、加载和卸载内核模块 1、运行insmod命令加载内核模块到内核中,在加载模块时需要指定模块的路径和名称。 2、运行rmmod命令从内核中卸载内核模块,在卸载模块时需要指定模块的名称。 三、接口函数 内核模块需要实现init和exit函数,分别用于模块的初始化和卸载。例如: ``` static int __init my_module_init(void) { /* 模块初始化代码 */ return 0; } static void __exit my_module_exit(void) { /* 模块卸载代码 */ } module_init(my_module_init); module_exit(my_module_exit); ``` 四、模块参数 内核模块可以接受一些通过命令行传递的参数,在模块加载时指定。例如: ``` static char *my_string = "hello"; module_param(my_string, charp, 0); ``` 这段代码定义了一个名为my_string的字符串类型参数,初始值为"hello",模块加载时可以使用如下命令指定: ``` insmod my_module.ko my_string="world" ``` 五、调试技巧 1、使用pr_info、pr_err等宏函数输出调试信息。 2、使用printk_ratelimit限制调试信息的输出频率。 3、使用gdb对内核模块进行调试。 以上就是Linux内核模块编写的基本流程和注意事项,需要注意的是内核模块编写需要具备一定的Linux内核编程基础和相关知识。 ### 回答3: 在Linux操作系统中,内核模块一个可以动态加载或卸载的程序。内核模块可以扩展操作系统的功能,例如添加新的设备驱动程序、实现新的系统调用、修改内核运行时行为等。而内核模块编写就是指为Linux内核添加新功能的过程。 内核模块编写可以分为以下几个步骤: 1. 准备开发环境:向Linux内核开发组申请开发账户,并下载内核源代码。编译好内核源代码,并安装相关的开发工具。 2. 编写代码:根据需求编写内核模块的源代码。在Linux内核中编写模块需要使用C语言,并按照内核代码风格格式要求来编写编写的代码最终会成为一个称之为内核对象文件的二进制文件。 3. 编译内核模块:使用内核源代码目录下的Makefile文件来编译内核模块。Makefile文件主要是用来控制编译过程的,其中包含了编译规则、库文件、头文件、链接文件等重要的指令。使用“make”命令可以执行Makefile文件中的编译规则,生成一个后缀名为.ko的内核模块二进制文件。 4. 加载内核模块:使用insmod命令来加载内核模块。加载成功后,内核会告知用户已经成功注册了一个新的驱动程序。可以使用lsmod命令来查看当前系统中已经加载的内核模块。 5. 卸载内核模块:使用rmmod命令来卸载已加载的内核模块。卸载内核模块后,内核会告知用户已经成功注销了一个驱动程序。 总之,内核模块编写是操作系统内核开发的一部分,需要开发者具备扎实的C语言技能,并了解操作系统与内核模块相关的底层知识。内核模块编写能够使我们更加深入地了解Linux内核,并扩展操作系统的功能。在编写内核模块时要格外小心,因为内核模块代码是运行在内核空间中的,不当操作可能会导致系统崩溃,因此需要十分谨慎。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值