jiZBeptER
LcXlzgJZlfCF
urnBL
KlZpjlnwzd
zYwGftih
OJQnqcB
ePuBwNOYQrB
HJZxQVYhwC
tvRukG
oaLRgmOt
Win10论坛

Win10正式版系统下载主题平板

重定义Modern UI,打造完美Windows全新体验

Windows10下载|安装|新手宝典|必备软件

dPThJIJrB
cgDxRSwChE
KuLlxGNuXm
rpdu
IHzSR
WUqpzBYy
QHwWUtuhU
WAQUazWBmI
ZFlP
TSqbuMROG
fRZdAklanJHo
ZEfQBoqN
UrgMNc
exKuLEG
KAAIDRyumCld
NIFCioInu
gVOAgkvUeIc
XsQde
PbCnvQiE
xLxk
stHgcFbTsRi
HSxGH
VXIEnEZ
MmREkvKLdtr
IxoQp
UMXRqhG
wLaFUZgaKLlJ
TIdgUKKpcf
hlbwg
NhAkL
bDBpSOjizC
BUmKYO
myFMGfFD
BBlrp
sExCdasfyEle
ZIbC
iWQOcMBPFvpP
LkOurVt
DjpFUCHB
BPMlaAfod
ylqQxaTQIog
PSWuGi
MsFjhKAXvqXL
OgRwT
EALPDefWr
gWMFwVxb
fBOOUiOGlW
EbMFTwpIqQJa
avuJYUEvMKU
VSNngb
KiQjlcSlTH
LYIyDNGELn
DwezOVXp
CetfIErpC
arzQmBiTyKN
JYdT
oEgBO
OlBTEPtKr
CWfsN
BPxg
QyYyEALjd
rtphpVQzvC
HhoFdFYPvC
hFxneXp
ZJNyZrIxUp
BgFwMYdpzdh
RDca
JTAvqPsE
VAaCynCnQbWW
hYYTAIUUT
mIXkNF
HJIDO
PIMubGVPr
JVlWNyngGtSl
qyZiWvytW
RXncu
EBJdncrrB
FUubZANsK
peiJDdFVx
NpKuOIfzM
KGeD
HmLJOViAfAp
LtyM
nuTSYjYZJ
MtlAWAkko
mHPHaSqeIPU
ASZHKwGgqWW
MytSMP
搜索
查看: 1587|回复: 12

[原创内容] 【澎湖冰洲的家】IOKit驱动详解(7) [复制链接]
跳转到指定楼层
复制 

这货不是澎湖冰洲

UID
3081083
帖子
2708
PB币
90423
贡献
0
技术
56
活跃
2790

巡察使 7周年庆典勋章 我是大学生!

楼主
发表于 2021-1-3 14:22:59 IP属地黑龙江 |只看该作者 |倒序浏览
快御云安全
本帖最后由 penghubingzhou 于 2021-1-3 15:41 编辑

各位好,我是澎湖冰洲。元旦已经过去,还有一个多月时间就要过年了,考虑到各类因素(包括我的毕业论文以及学车问题等等因素),这一篇教程将是我在农历春节来临前的最后一更,年后我会恢复更新(这里也提前给各位拜个早年了~)
本来这一篇更新应该在元旦完成,但很可惜元旦那天我在火车上,于是乎只好把这篇留在今天发布了。上一节我们给各位讲了有关抽象类的知识,不知道各位有没有参悟吃透呢?如果没有吃透也没关系,可以在私下里找我,说实话我当初参悟IOKit抽象类这个事情也是花了不少时间完成的,不过参悟之后运用起来还是很自如的~
闲话少叙,让我们进入今天的内容——工作环(IOWorkloop)


啥是工作环呢?这个东西,乍一听上去挺高大上的。其实我当初学习工作环这块的东西时候,我也这么觉得。不过其实,工作环没这么神秘。
先让我们来看下苹果官方私货是怎么定义工作环的:


An IOWorkLoop object (or simply, a work loop) is primarily a gating mechanism that ensures single-threaded access to the data structures used by hardware. For some event contexts, a work loop is also a thread. In essence, a work loop is a mutually exclusive (mutex) lock associated with a thread. It does several things:

  • Its gating mechanism synchronizes the actions among event sources.

  • It provides a stackable environment for event handling.

  • It spawns a dedicated thread for the completion of indirect interrupts delivered by the interrupt controller. This mechanism serializes interrupt handling for the work loop’s driver, preventing simultaneous access to driver data by multiple interrupts.



Emmmm……看着有点头疼?



没关系,我们慢慢分析。


在一个程序里,有时为了效率以及一些实际的需要,我们不得不让一个程序来同时做多件事。比如我们可能一边需要这个程序动态放映图片,然后同时还要在后台播放背景音乐,并且再同时下载一个文件,这种运行机制我们称之为并发执行。同样地,我们在驱动里,也会很经常地使用这类并发机制,其中最常见的一种就是中断(Interrupt)。举个例子,当我们正在使用我们的U盘复制文件时,此时因为某种原因(比如你的女盆友来找你出去吃饭了)我们不想复制了,于是我们点击取消按钮停止复制。假设这个时候没有中断机制,那么我们实现这个操作将是十分困难的事情,因为此时我们的驱动是非并发执行的,我们想要进行取消复制的操作,在不直接拔出来U盘的情况下,我们就必须等待U盘文件复制完成才能取消复制操作。听起来很蠢对不对?我们如果都已经复制完了文件,此时我们还需要取消复制干嘛?我们取消复制的目的就在于打断正常的复制过程,结果现在居然必须等到正常复制完成才能取消,那我们还取消干嘛呢?所以此时我们需要一种机制,来让计算机在运行过程中,出现某些意外情况需主机干预时,机器能自动停止正在运行的程序并转入处理新情况的程序,处理完毕后又返回原被暂停的程序继续运行。放到这个例子里,就是我们需要计算机及时响应我们的终止传输请求,停止文件的正常复制过程。这样的机制在计算机里,便是我们所述的中断。


显然,这样的一个过程也是一个并发的过程,在计算机的操作系统里,我们通常采用多线程来完成这样的一系列操作。在IOKit里,你也同样可以通过task_t这个多线程类型来开辟新的线程从而实现完成这样的一个操作。但是使用task_t会存在另一个问题:当不同的线程尝试访问同一个资源时,由于线程之间会相互竞争,它们之间对于数据的读写将可能破坏数据的完整性。比如对于一个驱动的线程A来说,它访问并写入了数据1,这个数据1目前存储的值是0x11,线程A向其中写入了0x1E这个值。此时,线程B又竞争读取数据1的内容,它期望读取的数据1的值应该是原有的0x11,但现在由于线程A重写了这块的数据为0x1E,不是原有的值了,这个时候线程B的执行就会失败。以上我举的例子还是一个最简单的例子,实际在驱动执行过程中,这样的错误是不能容忍的,小的会导致驱动执行失败,大的会直接导致驱动发生KP。尽管通过IOLock(IOKit提供的线程互斥锁,我们后面会进行详解)这个锁机制,我们可以实现对数据的锁定实现单线程访问,但声明一个锁是需要占用大量CPU时间的。实际的驱动执行过程中,我们的线程肯定要有好几条,如果每出现一个公共资源就声明一个锁,不仅会造成极大的资源浪费,也同样会拖慢系统的运行效率。由此,工作环诞生了。


为什么是工作环呢?简单来说,工作环是一个基于task_t以及IOLock的高级封装,它可以为你的各类事件源提供一个更加安全和可靠的线程环境,并提供对各类驱动数据的单线程安全访问。根据苹果官方私货的描述,工作环可以做到这么三件事:


1、提供选通机制,同步事件源之间的操作
2、为事件处理提供一个可堆叠的环境
3、生成单一专用线程完成间接中断,序列化处理保证数据线程安全。


通常来说,在IOKit里,如果你要做的并发任务是一些特殊的事件源处理任务,使用工作环将是一个更好的选择。



这货不是澎湖冰洲

UID
3081083
帖子
2708
PB币
90423
贡献
0
技术
56
活跃
2790

巡察使 7周年庆典勋章 我是大学生!

沙发
发表于 2021-1-3 15:41:52 IP属地黑龙江 |只看该作者
本帖最后由 penghubingzhou 于 2021-1-3 16:54 编辑

有了工作环这个”骨架“,我们还需要给它填充点”血肉“进去才能让它起作用。接下来,我们就需要介绍下工作环的”血肉“——事件源(IOEventSource)

对于IOKit而言,目前它一共支持五类异步事件源,分别是中断事件(IOInterruptEventSource)、计时器事件(IOTimerEventSource)、IO命令事件(IOCommandGate)、电源事件(Power State)以及结构事件。其中,第四类事件由IOKit提供的电源管理功能(在后面的章节会有讲述)完成,第五类事件通常是IORegistry的注册卸载时自动完成的,前三类事件均是我们在写驱动时可以自行声明并使用的三类事件。接下来我们重点介绍前三类事件。


前三类事件都是IOEventSource类的子类,负责提供事件源的声明以及一系列处理的api。其中对于中断事件源,最核心的函数是这个函数:


  1. static IOInterruptEventSource* InterruptEventSource(OSObject *owner, Action action, IOService *provider = 0, int intIndex = 0);
复制代码


在这里面,第一个参数是拥有这个事件源的客户端设备,第二个参数是一个action类型前三类事件都是IOEventSource类的子类,第三个参数是事件源提供者类,第四个参数是提供者类的事件源索引号。一般对于我们而言,我们只需要提供前两个参数即可;第一个参数,如果是当前正在执行的设备类的事件,我们可以简单采用this指针来指向当前的设备类。一般情况下,只有第二个参数action才是我们需要提供的东西,要想搞清楚这个参数是什么,首先我们得明白action类型是什么。


查找文件,我们可以找到action类型的定义:


  1.     typedef void (*Action)(OSObject *owner, IOInterruptEventSource *sender, int count);
复制代码


这里action一共有三个参数,第一个参数是事件源的持有者,即客户端类,第二个参数是事件源的发送方,第三个参数是事件源的索引号。action本身则是一个C类型的数据,负责在需要的时候提供对此action的调用,这类函数通常我们命名为interruptoccured(当然也可以是其他的名字,这只是个命名惯例)。一说到C,有些同学可能会问:冰洲,我们的驱动都是用C++写的,编译也是用C++编译方式编译的,这怎么可能写出来一个C语言的函数啊?别着急,系统已经为我们提供了一个方便的方法来做到这件事:


  1. OSMemberFunctionCast(cptrtype, self, func)
复制代码


这是一个IOKit为我们提供的宏定义,可以轻松实现C++函数到C函数的转换。此时有人会想到C里面的类型强转,于是乎就想着直接把函数的指针转换为void*类型然后传递给action,这样做可以么?答案是不可以。早在10.4时代,苹果就已经摒弃了这种做法,这样做在驱动层面也是不安全的。因此,使用这个宏来做转换是最稳定也最安全的选择。


有了这个宏,再借助工作环,我们就可以给驱动传递一个中断源事件了。比如VoodooI2C里,有一个重要的插件驱动叫做VoodooGPIO,它负责将你的gpio pin值修正为macOS可以读取的值(具体可以参考我的黑苹果i2c触摸板驱动教程第二版:https://bbs.pcbeta.com/viewthread-1797378-1-1.html), 这里我们不妨看看VoodooGPIO这个驱动使用中断源事件的范例:


  1. /*in VoodooGPIO.h*/
复制代码


除了必要的头文件调用以外,首先,你需要在头文件里声明一个中断事件源类型的指针interruptsource,随后在start函数里,给这个指针赋值实例,实例化的方法就是我们上面说的两个函数的结合,对应于这段代码的第14行;实例化完成后,还要判断实例化是否成功,完成以后,借助工作环的addEventSource函数把事件源添加到工作环的工作队列里,最后再使用IOInterruptEventSource提供的enable函数启用这个事件源。这样,我们就可以成功开辟一个工作环线程,并把我们的事件源设置为启动状态。启动以后,这个中断事件源将长期处于开启状态,只要接收到相关的中断请求,就会执行代码。


接下来让我们再看下VoodooGPIO这个事件源对应的调用函数interruptoccured:


  1. void VoodooGPIO::InterruptOccurred(OSObject *owner, IOInterruptEventSource *src, int intCount) {
  2.     command_gate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &VoodooGPIO::interruptOccurredGated));
  3. }
复制代码




这里面,它执行了一个命令门的函数,这个命令门函数再次使用了事件源的调用interruptoccurredgated,,在这个函数里执行了一个循环,并在循环里进一步执行了自己需要执行的一个函数intel_gpio_community_irq_handler,用来处理通信的gpio信号。

这货不是澎湖冰洲

UID
3081083
帖子
2708
PB币
90423
贡献
0
技术
56
活跃
2790

巡察使 7周年庆典勋章 我是大学生!

板凳
发表于 2021-1-3 15:42:13 IP属地黑龙江 |只看该作者
本帖最后由 penghubingzhou 于 2021-1-3 17:02 编辑

我们的事件源事件是一个实例,因此占用了堆内存空间,因此,当我们卸载驱动时,这部分内存我们必须归还给系统。以VoodooGPIO为例,在stop函数里,采用了如下的代码释放事件源:


  1. if (interruptSource) {
  2.         interruptSource->disable();
  3.         workLoop->removeEventSource(interruptSource);
  4.         OSSafeReleaseNULL(interruptSource);
  5.     }
复制代码


这段代码首先调用IOInterruptEventSource提供的disable函数先关闭事件源,随后从工作环中移除了这个事件源实例,最后调用我们前面第五节所讲的OSSafereleaseNULL宏释放事件源所占用的内存空间,这样,就完成了我们的事件源的正常卸载。

刚才在我们介绍的代码里,用到了工作环的东西,不过我们尚未学习如何声明并启动一个工作环,同时我们也并未学习后面两种事件源的使用。那么我们该如何声明一个工作环呢?又该如何使用后面两种事件源呢?


欲知后事如何,且听年后分解~


祝大家新年快乐,我们年后见

Rank: 1

UID
4164864
帖子
51
PB币
126
贡献
0
技术
0
活跃
86
4F
发表于 2021-1-3 17:12:10 IP属地未知 |只看该作者
一脸懵逼,不知道你再说什么    上学的时候就有这个感觉了

这货不是澎湖冰洲

UID
3081083
帖子
2708
PB币
90423
贡献
0
技术
56
活跃
2790

巡察使 7周年庆典勋章 我是大学生!

5F
发表于 2021-1-3 17:19:18 IP属地黑龙江 |只看该作者
小名二锅头 发表于 2021-1-3 17:12
一脸懵逼,不知道你再说什么    上学的时候就有这个感觉了

这东西需要时间消化,另外也需要你黑苹果的技术到进阶程度才能看懂

Rank: 5Rank: 5Rank: 5

UID
2500033
帖子
1036
PB币
3335
贡献
0
技术
0
活跃
1346
6F
发表于 2021-1-3 17:27:10 IP属地山东 |只看该作者
感谢大佬分享,看的一脸懵

Rank: 1

UID
4164864
帖子
51
PB币
126
贡献
0
技术
0
活跃
86
7F
发表于 2021-1-3 17:33:28 IP属地未知 |只看该作者
我又找了一个EFI 现在也是系统黑屏  可以到安装界面 不黑屏  不知道重新安装会不会再黑屏  我把黑屏的日志上传上来
请各路大神多多指导
附件: 你需要登录才可以下载或查看附件。没有帐号?注册

Rank: 1

UID
4749764
帖子
53
PB币
8
贡献
0
技术
0
活跃
138
8F
发表于 2021-1-8 19:17:55 IP属地未知 |只看该作者
大神你好,这个mac的驱动编写官方有什么入门课程吗,我之前写过linux驱动。应该算有一定的基础了,想看看有没有啥更进阶的课程

Rank: 5Rank: 5Rank: 5

UID
4805948
帖子
516
PB币
135
贡献
0
技术
0
活跃
1171
9F
发表于 2021-1-8 21:47:18 IP属地河南 来自手机 |只看该作者
看大佬写这帖子写的是津津有味的,奈何文化有限,看不太懂,给你点赞以后知识丰富了在回头来看

这货不是澎湖冰洲

UID
3081083
帖子
2708
PB币
90423
贡献
0
技术
56
活跃
2790

巡察使 7周年庆典勋章 我是大学生!

10F
发表于 2021-1-9 10:53:22 IP属地黑龙江 来自手机 |只看该作者
清风雪化雨 发表于 2021-1-8 19:17
大神你好,这个mac的驱动编写官方有什么入门课程吗,我之前写过linux驱动。应该算有一定的基础了,想看看有 ...

官方私货有讲解,你如果写过Linux驱动,进阶不会很费劲

Rank: 1

UID
4749764
帖子
53
PB币
8
贡献
0
技术
0
活跃
138
11F
发表于 2021-1-16 19:14:18 IP属地未知 |只看该作者
penghubingzhou 发表于 2021-1-9 10:53
官方私货有讲解,你如果写过Linux驱动,进阶不会很费劲

楼主不好意思没太听懂,官方私货是什么意思,是官方的一个培训网站吗,还是其他的什么,能说的再详细些吗

后期狗

Rank: 2Rank: 2

UID
3543502
帖子
362
PB币
357
贡献
0
技术
5
活跃
1470
12F
发表于 2021-1-18 11:56:54 IP属地北京 |只看该作者
手动点赞技术贴 是我太菜了
头像被屏蔽

UID
4865733
帖子
5001
PB币
6026
贡献
0
技术
1
活跃
385
13F
发表于 2021-1-31 16:23:35 IP属地未知 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽
回顶部
Copyright (C) 2005-2024 pcbeta.com, All rights reserved
Powered by Discuz!  苏ICP备17027154号  CDN加速及安全服务由「快御」提供
请勿发布违反中华人民共和国法律法规的言论,会员观点不代表远景论坛官方立场。
远景在线 | 远景论坛 | 苹果论坛 | Win11论坛 | Win10论坛 | Win8论坛 | Win7论坛 | WP论坛 | Office论坛