驱动开发1 概念、内核模块编程、内核消息打印函数printk函数的使用、内核模块传参、内核导出符号

编程入门 行业动态 更新时间:2024-10-21 16:05:57

驱动开发1 概念、<a href=https://www.elefans.com/category/jswz/34/1769575.html style=内核模块编程、内核消息打印函数printk函数的使用、内核模块传参、内核导出符号"/>

驱动开发1 概念、内核模块编程、内核消息打印函数printk函数的使用、内核模块传参、内核导出符号

1 驱动相关概念

2 内核模块编程

内核模块编写实例代码+注释

#include <linux/init.h>
#include <linux/module.h>//入口函数,安装内核模块时执行
static int __init mycdev_init(void)
{//static 修饰当前函数只能在本文件使用//int 函数的返回值类型,如果函数规定返回值但是没有加返回值,编译会报错//mycdev_init函数名,可以自己起名字//void表示函数无参数,当没有参数时void一定要加,不然报错//__init的作用是用来告诉编译器当前代码保存在.init.text段中//#define __init        __section(".init.text")  //linux内核也会有自己的链接脚本  vmlinux.lds,这个链接脚本里规定了不同的内容在//内存中的什么位置return 0;
}
//出口函数,卸载内核模块时执行
static void __exit mycdev_exit(void)
{//#define __exit        __section(".exit.text")//__exit指定出口函数保存在.exit.text段中}
//用于声明入口函数
module_init(mycdev_init);
//用于声明出口函数
module_exit(mycdev_exit);
//声明当前内核模块遵循GPL协议
MODULE_LICENSE("GPL");

内核模块编译(外部编译Makefile)

#保存UBUNTU内核源码路径
KERNELDIR := /lib/modules/$(shell uname -r)/build
#KERBELDIR保存开发板内核源码路径
#KERNELDIR := /home/ubuntu/linux-5.10.61/
#PWD保存当前内核模块的路径
PWD := $(shell pwd)
all:
#make modules是模块化编译命令
#make -C $(KERNLEDIR) 执行make之前先切换到KERNELDIR对应的路径
#M=$(PWD)表示进行模块化编译的路径是PWD保存的路径make -C $(KERNELDIR) M=$(PWD) modules
clean:
#编译清除make -C $(KERNELDIR) M=$(PWD) clean
#将obj-m保存的文件单独链接为内核模块
obj-m :=  demo.o

通用版本的Makefile

modname ?= demo
arch ?= arm
ifeq ($(arch),arm)  #通过命令行传过来的架构决定怎么编译
#KERBELDIR保存开发板内核源码路径
KERNELDIR := /home/ubuntu/linux-5.10.61/
else
#保存UBUNTU内核源码路径
KERNELDIR := /lib/modules/$(shell uname -r)/build
endif#PWD保存当前内核模块的路径
PWD := $(shell pwd)
all:
#make modules是模块化编译命令
#make -C $(KERNLEDIR) 执行make之前先切换到KERNELDIR对应的路径
#M=$(PWD)表示进行模块化编译的路径是PWD保存的路径make -C $(KERNELDIR) M=$(PWD) modules
clean:
#编译清除make -C $(KERNELDIR) M=$(PWD) clean
#将obj-m保存的文件单独链接为内核模块
obj-m :=  $(modname).o

3 内核消息打印函数printk函数的使用

代码示例

#include <linux/init.h>
#include <linux/module.h>// 入口函数,安装内核模块时执行
static int __init mycdev_init(void)
{// static 修饰当前函数只能在本文件使用// int 函数的返回值类型,如果函数规定返回值但是没有加返回值,编译会报错// mycdev_init函数名,可以自己起名字// void表示函数无参数,当没有参数时void一定要加,不然报错//__init的作用是用来告诉编译器当前代码保存在.init.text段中// #define __init       __section(".init.text")// linux内核也会有自己的链接脚本  vmlinux.lds,这个链接脚本里规定了不同的内容在// 内存中的什么位置printk(KERN_ERR "hello world\n");int a=10;printk(KERN_ERR "%d\n",a);return 0;
}
// 出口函数,卸载内核模块时执行
static void __exit mycdev_exit(void)
{// #define __exit       __section(".exit.text")//__exit指定出口函数保存在.exit.text段中
}
// 用于声明入口函数
module_init(mycdev_init);
// 用于声明出口函数
module_exit(mycdev_exit);
// 声明当前内核模块遵循GPL协议
MODULE_LICENSE("GPL");

4 内核模块传参

#include <linux/init.h>
#include <linux/module.h>
int a=10;
module_param(a,int,0664);//声明变量a可以进行命令行传参
MODULE_PARM_DESC(a,"this is a int value");//添加要传参的变量描述
static int __init mycdev_init(void)
{printk("a=%d\n",a);return 0;
}
static void __exit mycdev_exit(void)
{}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

5 内核导出符号

1 定义demo1.c,demo1.c中完成函数的定义

#include <linux/init.h>
#include <linux/module.h>
int add(int i,int j)
{return i+j;
}
//生成add的符号表文件
EXPORT_SYMBOL(add);
static int __init mycdev_init(void)
{return 0;
}
static void __exit mycdev_exit(void)
{}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

2 创建demo2.c,里面完成demo1.c里面函数的调用

#include <linux/init.h>
#include <linux/module.h>extern int add(int i,int j);
static int __init mycdev_init(void)
{printk("调用模块1函数执行结果为:%d",add(3,5));return 0;
}
static void __exit mycdev_exit(void)
{}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");

更多推荐

驱动开发1 概念、内核模块编程、内核消息打印函数printk函数的使用、内核模块传参、内核导出符号

本文发布于:2023-12-04 20:50:26,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1662162.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:内核   函数   模块   符号   概念

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!