详解linux驱动框架(开篇)

该系列博客只是个人记录,笔者本人也是菜鸟,如果出现大量错误,欢迎留言评论,请不要进行人身攻击等行为。

让我们先从drivers/input/input.c入手,让我们想一想,当我们modprobe input1.ko时,内核会按时间顺序从1开始分配对应的位号,如果你一直重复modprobe xx.ko然后又rm掉它,那么位号的大小会一直增加,让我们来细究一下底层原理。

当我们使用modprobe命令时,可以看出,shell使用了pr_info打印了相关信息,比如设备的name和路径,以及分配的位号:

9dd9a74f7bbc41e3a3134b8d294b94ae.png

跳转到input.c文件:

fea2b16867b94050a2d5095af763377a.png

与上文进行对比,可以看出,这里的pr_info正是modprobe加载后打印的内核日志。

可以看出,本质上还是在使用device_add进行设备的添加,也就是说,最终还是要归类到kobject_add函数:

28179dc53ed64f8b8f05e1a2d52394a6.png

下面的device_create_file等函数主要是创建对应的目录及文件,我们的目的是寻找引用计数的相关flags。

365786b60e9b431786e246cd9315cc35.png

参考书籍:linux设备驱动程序

在linux内核中,kobject被用来统一描述内核对象模型,设备对象也不例外。

通过函数形参,我们要明白我们追踪的参数是kobj。

跳转到kobject_add函数:

e506396fd0344a2db7058bb75d071d85.png

再按f12继续追踪:

caa5918bd93f4223a2d5812950a2516c.png

此时我们已经离真相非常接近了。

继续跳转到kobject_add_internal(),我们终于找到了kobject_get函数,当被调用时,它会发生递增:

09b7dbf310a14980a51378a222899220.png

8e07dac3943543e5b9305e970b6194b4.png

kobject_add_internal函数会先判断kobject是否存在父对象,然后设置父对象,之后创建sysfs目录。

其实到这里已经够了,但还是让我们研究一下kobject_get函数:

36264347fe864f5c98187e84b75ab1cc.png

现在,我们终于找到了它:kref。它才是真正负责引用计数的flag。

086da46f8dd840e4acaca1cab78db05a.png

在linux内核中存在一个kref数据结构,它被用来负责引用计数,

简单理解就是这样:

af1f7a8c8deb47f58643f006925b5eff.png

现在,我们来到了这里:

9a959a8d01bc42f691c30cdf42fdaa45.png

经过跳转,我们会发现丢失了方向,因为这里充满了c语言的高级用法:

3fbedb6aab734d3abf7971b8826e92e8.png

进行跳转,我们会发现光标移动到了ATOMIC_OPS这个函数这里,这里的c让笔者这个菜鸟大感震惊:宏函数,静态内联汇编等形成原子操作。

笔者个人理解,在linux kernel中,虽然全局变量被避免了,但是对应统一的对象描述结构来说,时常会受到多方的控制,使用宏是为了模拟高级语言的模板,也就是元编程思想,使用内联汇编是为了完成原子操作,防止被其他对象打断。

ps:笔者从未想过在gnu c中还有如此高级的用法。

简单介绍一下这里的宏:通过#define ATOMIC_OP_RETURN(op),生成一个名为 atomic_##op##_return 的静态内联函数,## 运算符用于在宏展开时连接多个符号。在这里,##op## 将 op 参数插入到 atomic_ 和 _return 之间,形成函数名字,这非常像高级语言中的元编程。

static inline 关键字组合用于定义内联函数,这意味着编译器会尝试将函数内联展开,而不是通过调用来执行代码。

__asm是内联汇编的用法,volatile的作用是为了确保数据的有效性,随便一提,不要小看c语言中的关键字,这个关键字的详细用法如下:

防止编译器优化:编译器在优化代码时,会对变量的读取和写入进行重排或者去掉一些看似不必要的读写操作。对于被声明为 volatile 的变量,编译器必须确保每次访问该变量时都从内存中读取值,而不是使用寄存器中的缓存值。

多线程或中断处理:在多线程或中断处理环境中,变量的值可能会在不同的上下文中被修改,这时候使用 volatile 可以确保正确地获取最新的值。

硬件映射:在嵌入式系统中,通常会将硬件寄存器映射到内存中作为变量来访问,这些寄存器的值可能会在硬件操作之外发生变化,因此需要使用 volatile 来确保对这些寄存器的正确访问。

汇编代码的具体解释:

"1:    %0 = memw_locked(%1);\n": 从内存中读取 v->counter 的值到 output 中,memw_locked 表示使用加锁的内存访问。
"    %0 = "#op "(%0,%2);\n": 执行具体的原子操作,#op 会被宏展开成不同的操作符(如 add、sub 等)。
"    memw_locked(%1,P3)=%0;\n": 将计算后的结果存回到 v->counter 中,同样使用了加锁的内存访问。
"    if !P3 jump 1b;\n": 如果加锁失败,则跳转到标签 1 处重新尝试执行操作。

"%0", "%1", "%2": 这些是占位符,分别用来引用汇编代码中操作数的位置。
"=&r" (output): 输出操作数约束,表示 output 变量被当作寄存器且是输出的,& 表示这是一个写入操作。
"r" (&v->counter), "r" (i): 输入操作数约束,&v->counter 是 v->counter 的地址,i 是函数参数 i 的值。
"memory", "p3": 附加的内存和寄存器约束,确保内存操作的正确性和可见性。

笔者的简单解释:

"    %0 = "#op "(%0,%2);\n",这里的op被替换成add,也就是:"    %0 = "#add "(%0,%2);\n",表示两个参数相加,回到之前:

9a959a8d01bc42f691c30cdf42fdaa45.png

其实就是加1而已。不得不说在linux内核中加1也是如此的麻烦,只能感慨操作系统是多么的庞大与复杂,一个小小的操作必须要被层层保护。

到此,笔者勉强理清了添加设备时引用计数的逻辑,但是input1文件的递增,关于文件及位号的具体逻辑还没讲,笔者接下来将会研究input子系统的文件及位号关系。

387c8e3891934b2cbaf9c0837bee8002.png

先放张图,避免我忘了下次从哪里开始讲。

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/800800.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JuiceFS、Ceph 和 MinIO 结合使用

1. 流程图 将 JuiceFS、Ceph 和 MinIO 结合使用,可以充分利用 Ceph 的分布式存储能力、JuiceFS 的高性能文件系统特性,以及 MinIO 提供的对象存储接口。以下是一个方案,介绍如何配置和部署 JuiceFS 使用 Ceph 作为其底层存储,并通…

量化投资基础(三)之Fama-French 三因子模型(2)

点赞、关注,养成良好习惯 Life is short, U need Python 量化投资基础系列,不断更新中 1. 前言 Sharp(1964),Lintner(1965),Black(1972)的资本资产定价模型&…

【异常解决】Unable to start embedded Tomcat Nacos 启动报错

Unable to start embedded Tomcat Nacos 启动报错解决方案 一、背景描述二、原因分析三、解决方案 一、背景描述 Windows 本地启动 Nacos(2.2.0) 服务,控制台报错 Unable to start embedded Tomcat。 报错信息:Unable to start …

解决UniGUI中动态创建控件时,控件不按序显示的问题。

这两天遇到一个问题:我在UNIGUI中多批次动态创建控件,但是这些控件在显示时并没有按我想要的顺序排列。比如动态创建UnimContainerPanel面板,这个面板上放一些其它控件用于显示数据。在手机中从上到下按顺序显示出来,当第一批次时…

LabVIEW工业设备姿态监测系统

开发了一种基于LabVIEW的工业设备姿态监测系统,针对现有监测设备在适应性和反应时间上的不足,采用了LabVIEW软件和STM32微控制器,通过高精度姿态传感器实现了对设备姿态的快速准确监测,大大提高了工业作业的安全与效率。 项目背景…

Unable to obtain driver using Selenium Manager: Selenium Manager failed解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

jmeter-beanshell学习10-字符串补齐位数

每天都遇到新问题,今天又一个场景,一个字符串,如果不足11位,则左边补0,补够11位。 先要获取字符串长度,然后计算差多少位,补齐。今天又发现一个Object类型,这个类型有点厉害&#x…

【持续集成_05课_Linux部署SonarQube及结合开发项目部署】

一、Linux下安装SonarQube 1、安装sonarQube 前置条件:sonarQube不能使用root账号进行启动,所以需要创建普通用户及 其用户组 1)创建组 2)添加用户、组名、密码 3)CMD上传qube文件-不能传到home路径下哦 4&#xff09…

探索Nuxt.js的useFetch:高效数据获取与处理指南

title: 探索Nuxt.js的useFetch:高效数据获取与处理指南 date: 2024/7/15 updated: 2024/7/15 author: cmdragon excerpt: 摘要:“探索Nuxt.js的useFetch:高效数据获取与处理指南”详述了Nuxt.js中useFetch函数的使用,包括基本用…

【前端4】表单 编辑模式、只读模式:HTML的`readonly`、el-input的v-if=“isEdit“

【前端】表单 编辑模式、只读模式 写在最前面一、什么是编辑模式与只读模式&#xff1f;应用场景编辑模式只读模式 二、编辑模式的实现例子只读模式的实现动态切换模式使用HTML的readonly属性使用Vue.js的v-if指令 三、前后端交互 <template>代码块两个字段独立是否直接与…

bash: ip: command not found

输入&#xff1a; ip addr 报错&#xff1a; bash: ip: command not found 报错解释&#xff1a; 这个错误表明在Docker容器中尝试执行ip addr命令时&#xff0c;找不到ip命令。这通常意味着iproute2包没有在容器的Linux发行版中安装或者没有正确地设置在容器的环境变量PA…

HackQuest介绍 web3 学习平台

HackQuest 官网地址&#xff1a; https://www.hackquest.io/zh HackQuest是一个专注于Web3技术教育的在线学习平台&#xff0c;旨在帮助全球开发者掌握区块链、加密货币和去中心化应用&#xff08;DApps&#xff09;领域的最新技能。该平台汇聚了超过14000名活跃开发者&#…

PyMongo Sort 操作:提升你的数据查询效率

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

通过Bugly上报的日志查找崩溃闪退原因

第一步&#xff0c;解析堆栈信息 在bugly上收集到的信息是这样的 0x000000010542e46c 0x0000000104db4000 6792300 OS应用发生崩溃时&#xff0c;系统会生成一份崩溃日志&#xff0c;这份日志中包含了崩溃时的堆栈信息&#xff0c;但这些堆栈信息并非直接指向源代码&#x…

1143 多少个Fibonacci数

首先&#xff0c;我们需要生成一个Fibonacci数列&#xff0c;直到其值超过10^100。由于Fibonacci数列的性质&#xff0c;我们知道这个数列的长度不会超过500。 然后&#xff0c;对于每一对输入的a和b&#xff0c;我们在生成的Fibonacci数列中查找在a和b之间的数的个数。这可以…

JVM 内存介绍

本文主要介绍&#xff1a; JVM 内存分哪几个区&#xff0c;每个区的作用是什么 备注: 橙色:堆 和 方法区 &#xff0c;属于jvm公有部分,可以进行调优 灰色:java栈,本地方法栈和计数器 属于jvm的私有部分,不可进行调优 一个对象从创建到被回收的过程是怎样的? Personpnew Perso…

SpringBoot系列:通过AOP+注解优雅实现操作日志记录

文章目录 前言一、简介1.1 操作日志在企业应用中的重要性1.2 使用AOP和注解实现操作日志记录的好处 二、开发环境三、准备工作3.1 创建操作日志记录表3.2 创建系统日志实体类 四、代码实现4.1 创建业务枚举类4.2 创建日志注解4.3 创建操作状态枚举类4.4 创建IP工具类4.5 创建切…

jvm常用密令、jvm性能优化、jvm性能检测、Java jstat密令使用、Java自带工具、Java jmap使用

1.jps是Java虚拟机的进程状态工具&#xff0c;用于列出正在运行的Java进程 jps命令的使用&#xff1a;cmd打开直接jps 1.1不带参数&#xff1a; jps 默认情况下&#xff0c;列出所有正在运行的 Java 进程的进程 ID 和主类名。 1.2 -l&#xff1a;显示完整的主类名或 JAR 文件…

增值税进项税额转出6大知识点柯桥学会计会计实操做账手把手教学

什么情况下需要进项转出&#xff1f; 转多少&#xff1f; 怎么填报&#xff1f; 小编梳理了一些 关于增值税进项税额转出的常见问题 快来学习吧&#xff01; 哪些情况下进项税额不得从销项税额中抵扣&#xff1f; 1.用于简易计税方法计税项目、免征增值税项目、集体福利或…

ARM 虚拟机FVP环境搭建

ARM Fixed Virtual Platforms (FVPs) 是由 ARM 提供的一系列虚拟化硬件模拟器&#xff0c;用于在物理硬件可用之前开发和测试软件。FVP 模型非常适用于软件开发、验证和性能分析&#xff0c;涵盖了从裸机到操作系统和复杂 SoC 系统的各种应用。 这里以Cortex-M55为例&#xff0…