第6章 内核模块符号导出实验(iTOP-RK3568开发板驱动开发指南 )
在上一小节中,给大家讲解了驱动模块传参实验,使用insmod命令加载驱动时可以进行参数的传递,但是每一个内核模块之间是相互独立的,那模块间的符号传递要怎样进行呢,让我们带着疑问来进行本章节的学习吧!
6.1 内核模块符号导出简介
驱动程序编译生成的ko文件是相互独立的,即模块之间变量或者函数在正常情况下无法进行互相访问。而一些复杂的驱动模块需要分层进行设计,这时候就需要用到内核模块符号导出。
内核符号导出指的是在内核模块中导出相应的函数和变量,在加载模块时被记录在公共内核符号表中,以供其他模块调用。符号导出所使用的宏为EXPORT_SYMBOL(sym)和EXPORT_SYMBOL_GPL(sym)。它们定义在 “内核源码/include/linux/export.h”文件中(在module.h文件中已经对export.h进行引用,所以不需要单独引用export.h文件),详细定义如下(图6-1)所示:
#define EXPORT_SYMBOL(sym) \
__EXPORT_SYMBOL(sym, "")#define EXPORT_SYMBOL_GPL(sym) \__EXPORT_SYMBOL(sym, "_gpl")
EXPORT_SYMBOL(sym)和EXPORT_SYMBOL_GPL(sym)两个宏使用方法相同,而EXPORT_SYMBOL_GPL(sym)导出的模块只能被 GPL 许可的模块使用,所以绝大多数的情况都使用EXPORT_SYMBOL(sym)进行符号导出。sym为函数的唯一参数,表示要导出的函数或变量名称。
至此,关于内核模块符号导出函数就讲解完成了,在下一小节中将会编写两个驱动代码来进行内核模块符号导出实验。
6.2 实验程序的编写
本实验对应的网盘路径为:iTOP-RK3568开发板【底板V1.7版本】\03_【iTOP-RK3568开发板】指南教程\02_Linux驱动配套资料\04_Linux驱动例程\03。
本章实验将编写Linux下的内核模块符号导出实例代码,总共有两个驱动程序,第一个驱动文件名为mathmodule.c,用来定义参数num和函数add(a,b),第二个驱动文件名为hello.c,会引用mathmodule.c驱动程序中的参数num和数学函数add(a,b),并将相应的参数值和函数返回值打印到串口终端上。
编写完成的mathmodule.c代码如下(图6-2)所示
#include <linux/init.h>
#include <linux/module.h>
int num = 10;//定义参数num
EXPORT_SYMBOL(num);//导出参数numint add(int a, int b)//定义数学函数add(),用来实现加法
{return a + b;
}
EXPORT_SYMBOL(add);//导出数学函数add()static int __init math_init(void)//驱动入口函数
{printk("math_moudle 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_AUTHOR("topeet");//作者信息
图6-2
以上代码定义了一个int类型的num变量和add()数学函数,并使用EXPORT_SYMBOL宏进行导出。
编写完成的hello.c代码如下(图6-3)所示:
#include <linux/init.h>
#include <linux/module.h>
extern int num;//导入int类型变量num
extern int add(int a, int b);//导入函数add
static int __init hello_init(void)//驱动入口函数
{static int sum;printk("num = %d\n", num);//打印num值sum = add(3, 4);//使用add函数进行3+4的运算 printk("sum = %d\n", sum);//打印add函数的运算值return 0;
}static void __exit hello_exit(void)//驱动出口函数
{printk("Goodbye hello module\n");
}module_init(hello_init);//注册入口函数
module_exit(hello_exit);//注册出口函数MODULE_LICENSE("GPL");//同意GPL开源协议
MODULE_AUTHOR("topeet");//作者信息
图6-3
程序导入了int类型的变量num和add()函数,并在驱动入口函数中打印相应了num的参数值并对add()函数进行了调用。
至此两个驱动代码就编写完成了,代码较为简单,实现了内核模块符号的导出和导出符号的使用,具体的驱动加载运行测试会在下个小节进行。
6.3 运行测试
6.3.1 编译驱动程序
在mathmodule.c和hello.c的同一目录下创建Makefile文件,Makefile文件内容如下(图6-4)所示:
export ARCH=arm64#设置平台架构
export CROSS_COMPILE=aarch64-linux-gnu-#交叉编译器前缀
obj-m := mathmodule.o
obj-m += hello.oKDIR :=/home/topeet/Linux/linux_sdk/kernel #这里是你的内核目录
PWD ?= $(shell pwd)
all:make -C $(KDIR) M=$(PWD) modules #make操作
clean:make -C $(KDIR) M=$(PWD) clean #make clean操作
图6-4
对于Makefile的内容注释已在上图进行添加,这里要注意的是在hello.c代码中使用了mathmodule.c所导出的符号,所以mathmodule.c要在hello.c之前进行编译,即第3行和第4行顺序不能交换。保存退出之后,来到相应的文件目录下,如下图(图6-5)所示:
图6-5
然后使用命令“make”进行驱动的编译,编译完成如下图(图6-6)所示:
图6-6
编译完后会生成hello.ko和mathmodule.ko目标文件,如下图(图6-7)所示:
图6-7
至此我们的驱动模块就编译成功了,下面进行驱动的加载运行测试。
6.3.2 运行测试
这里要注意的是,由于 hello.ko依赖于mathmodule.ko,所以mathmodule.ko需要先加载,分别使用以下命令进行模块的加载(加载顺序不能变),如下(图6-8)所示:
insmod mathmodule.koinsmod hello.ko
图6-8
可以看到 hello.ko驱动加载的时候,mathmodule.ko模块中定义的num参数值和调用sum()函数的后正确的返回值都被打印了出来。至此内核模块符号导出实验就完成了。
最后可以输入以下命令进行驱动的卸载,如下图(图6-9)所示:
rmmod hello.kormmod mathmodule.ko
图6-9
注意:由于hello.ko文件使用了mathmodule.ko导出的符号,所以要先卸载hello.ko,卸载完成之后再卸载mathmodule.ko。
【最新驱动资料(文档+例程)】
链接 https://pan.baidu.com/s/1M4smUG2vw_hnn0Hye-tkog
提取码:hbh6
【B 站配套视频】
https://b23.tv/XqYa6Hm
【RK3568 购买链接】
https://item.taobao.com/item.htm?spm=a1z10.5-c-s.w4002-2245
链接 https://pan.baidu.com/s/1M4smUG2vw_hnn0Hye-tkog
提取码:hbh6
【B 站配套视频】
https://b23.tv/XqYa6Hm
【RK3568 购买链接】
https://item.taobao.com/item.htm?spm=a1z10.5-c-s.w4002-2245
2452613.11.2fec74a6elWNeA&id=669939423234
相关文章:

第6章 内核模块符号导出实验(iTOP-RK3568开发板驱动开发指南 )
在上一小节中,给大家讲解了驱动模块传参实验,使用insmod命令加载驱动时可以进行参数的传递,但是每一个内核模块之间是相互独立的,那模块间的符号传递要怎样进行呢,让我们带着疑问来进行本章节的学习吧! 6.…...
Android12.0首次开机默认授予app运行时权限(去掉运行时授权弹窗)第二种方法
1.概述 在12.0的系统产品开发中,在6.0以后对于权限的申请,都需要动态申请,所以会在系统首次启动后,在app的首次运行时,会弹出授权窗口,会让用户手动授予app运行时权限,在由于系统产品开发需要要求默认授予app运行时权限,不需要用户默认授予运行时弹窗,所以需要在首次开…...

conda和Python的虚拟环境如何结合使用,以及二者之间到底有什么区别?
问题描述 今天在复现streamlit的代码时(参考Streamlit 讲解专栏(一):安装以及初步应用),根据这篇博文指导,要先用以下指令创建一个虚拟环境: # 创建虚拟环境(使用venv&a…...

宇凡微YE09合封芯片,集成高性能32位mcu和2.4G芯片
合封芯片是指将主控芯片和外部器件合并封装的芯片,能大幅降低开发成本、采购成本、减少pcb面积等等。宇凡微YE09合封芯片,将技术领域推向新的高度。这款高度创新性的芯片融合了32位MCU和2.4G芯片,为各种应用场景提供卓越的功能和性能。 32位M…...

使用perf_analyzer和model-analyzer测试tritonserver的模型性能超详细完整版
导读 当我们在使用tritonserver部署模型之后,通常需要测试一下模型的服务QPS的能力,也就是1s我们的模型能处理多少的请求,也被称为吞吐量。 测试tritonserver模型服务的QPS通常有两种方法,一种是使用perf_analyzer 来测试&#…...

docker 部署springboot(成功、截图)
1.新建sringboot工程并打包 2.编写Dockerfile文件 # 基础镜像使用java FROM openjdk:8 # 作者 MAINTAINER feng # VOLUME 指定了临时文件目录为/tmp。 # 其效果是在主机 /var/lib/docker 目录下创建了一个临时文件,并链接到容器的/tmp VOLUME /tmp # 将jar包添加…...

VMware ubuntu空间越用越大
前言 用Ubuntu 1604编译了RK3399的SDK,之后删了一些多余的文件,df - h 已用21G,但window硬盘上还总用了185GB,采用了碎片整理,压缩无法解决 1 启动Ubuntu后, 安装 VMware Tools(T) 、 2 打开ubuntu终端,压…...

stm32 学习笔记:GPIO输出
一、GPIO简介 引脚电平 0-3.3V,部分可容忍5V,对输出而言最大只能输出3.3V, 只要可以用高低电平来控制的地方,都可以用GPIO来完成,如果控制的功率比较大的设备,只需加入驱动电路即可 GPIO 通用输入输出口,可配置为 8种 …...

css换行
强制显示一行,超出... .box{white-space: nowrap; /* 强制显示一行 */overflow: hidden;text-overflow: ellipsis; /* 超出... */ } 自动换行 一般默认制动换行 .box1{word-wrap:break-word; } 显示2行,超出... .box2 {overflow: hidden;display: -…...

面试算法-常用数据结构
文章目录 数据结构数组链表 栈队列双端队列树 1)算法和数据结构 2)判断候选人的标准 算法能力能够准确辨别一个程序员的功底是否扎实 数据结构 数组 链表 优点: 1)O(1)时间删除或者添加 灵活分配内存空间 缺点: 2&…...

【动态规划刷题 10】等差数列划分 最长湍流子数组
413. 等差数列划分 链接: 413. 等差数列划分 如果一个数列 至少有三个元素 ,并且任意两个相邻元素之差相同,则称该数列为等差数列。 例如,[1,3,5,7,9]、[7,7,7,7] 和 [3,-1,-5,-9] 都是等差数列。 给你一个整数数组 nums ,返回…...

redis 配置与优化
目录 一、关系数据库和非关系型数据库 二、关系型数据库和非关系型数据库区别 三、非关系型数据库产生背景 四、redis 1、概念 2、redis的优点 3、redis为什么这么快 五、redis安装与配置 一、关系数据库和非关系型数据库 关系型数据库:关系型数据库是一个结…...

数据结构例题代码及其讲解-递归与树
树 树的很多题目中都包含递归的思想 递归 递归包括递归边界以及递归式 即:往下递,往上归 递归写法的特点:写起来代码较短,但是时间复杂度较高 01 利用递归求解 n 的阶乘。 int Func(int n) {if (n 0) {return 1;}else …...
Jenkins | 流水线构建使用expect免密交互时卡住,直接退出
注意: expect 脚本必须以 interact 或 expect eof 结束。 原因: interact:使用interact会保持在终端而不会退回到原终端,所以就卡在这里。 expect eof:expect脚本默认的是等待10s,当执行完命令后,自动切回…...

git修改默认分支
git checkout 分支 切换到当前分支 git branch --set-upstream-toorigin/complete(远程分支名) 设置当前分支的上游分支为远程分支complete git branch --unset-upstream master 取消master上游分支的身份 现在,使用git commit,git push 命令可以直接…...

Android Studio开发入门教程:如何更改APP的图标?
更改APP的图标(安卓系统) 环境:Windows10、Android Studio版本如下图、雷电模拟器。 推荐图标库 默认APP图标 将新图标拉进src/main/res/mipmap-hdpi文件夹(一般app的icon图标是存放在mipmap打头的文件夹下的) 更改sr…...
MATLAB/Python的编程教程: 匹配滤波器的实现
MATLAB/Python的编程教程: 匹配滤波器的实现 注1:本文系“MATLAB/Python的编程教程”系列之一,致力于使用Python和Matlab实现特定的功能。本次要实现的功能是:匹配滤波器的实现。 匹配滤波器,这是一个在信号处理领域常见的主题,主要用于增强特定信号的检测性能,特别是在噪…...

java八股文面试[数据库]——JOIN优化
JOIN 是 MySQL 用来进行联表操作的,用来匹配两个表的数据,筛选并合并出符合我们要求的结果集。 JOIN 操作有多种方式,取决于最终数据的合并效果。常用连接方式的有以下几种: 什么是驱动表 ? 多表关联查询时,第一个被处理的表就是驱动表,使用…...

Java语法中一些需要注意的点(仅用于个人学习)
1.当字符串和其他类型相加时,基本都是字符串,这与运算顺序有关。 2.Java中用ctrl d 来结束循环输入。 3.nextLine() 遇到空格不会结束。 4.方法重载 4.1. 方法名必须相同 4.2. 参数列表必须不同(参数的个数不同、参数的类型不同、类型的次序必须不…...
golang 线程 定时器 --chatGPT
问:线程函数write(ch,timer),功能为启动一个线程,循环执行打印,打印条件为触发ch chane 或 timer定时器每隔一段时间会触发 GPT:以下是一个示例Golang代码,其中有一个名为 write 的线程函数,它会在触发ch通道或每隔一…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...

Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

【Java_EE】Spring MVC
目录 Spring Web MVC 编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 编辑参数重命名 RequestParam 编辑编辑传递集合 RequestParam 传递JSON数据 编辑RequestBody …...

让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...

STM32标准库-ADC数模转换器
文章目录 一、ADC1.1简介1. 2逐次逼近型ADC1.3ADC框图1.4ADC基本结构1.4.1 信号 “上车点”:输入模块(GPIO、温度、V_REFINT)1.4.2 信号 “调度站”:多路开关1.4.3 信号 “加工厂”:ADC 转换器(规则组 注入…...

解决MybatisPlus使用Druid1.2.11连接池查询PG数据库报Merge sql error的一种办法
目录 前言 一、问题重现 1、环境说明 2、重现步骤 3、错误信息 二、关于LATERAL 1、Lateral作用场景 2、在四至场景中使用 三、问题解决之道 1、源码追踪 2、关闭sql合并 3、改写处理SQL 四、总结 前言 在博客:【写在创作纪念日】基于SpringBoot和PostG…...

Xcode 16.2 版本 pod init 报错
Xcode 版本升级到 16.2 后,项目执行 pod init 报错; ### Error RuntimeError - PBXGroup attempted to initialize an object with unknown ISA PBXFileSystemSynchronizedRootGroup from attributes: {"isa">"PBXFileSystemSynchron…...

【docker】Windows安装docker
环境及工具(点击下载) Docker Desktop Installer.exe (windows 环境下运行docker的一款产品) wsl_update_x64 (Linux 内核包) 前期准备 系统要求2: Windows 11:64 位系统&am…...
Vue-github 用户搜索案例
一、前言 在 Vue 开发中,与后端或第三方 API 接口进行交互是非常常见的需求。GitHub 提供了开放的 RESTful API,非常适合用来练习 Vue 的异步请求和数据绑定功能。 本文将带你一步步实现一个完整的 GitHub 用户搜索系统,包括: …...