在研究黑苹果驱动时,经常会看到修改Info.plist中的IOPCIMatch字段。需要研究一下相关内容。
PCI是一种外设部件互连标准总线,和USB总线差不多,可以将不同类型的设备连接到同一条总线上。
常见的PCI设备有显卡,网卡,声卡,IDE控制器,AHCI控制器,USB控制器等。
符合PCI标准的设备,都必须有一个VID和DID,在Windows设备管理器中,可以很方便地查看设备的硬件ID。
下图以网卡为例:
设备ID以PCI开头,表示这是PCI设备,VEN_10EC&DEV_8168,表示设备的VID=0x10EC,DID=0x8168。
VID是标识厂商的唯一代码,不同厂商是不同的,由一个神秘组织维护这些VID。知道VID就知道厂商名称。
比如0x10EC是RealTek,0x10DE是Nvidia,0x8086是Intel。
DID是标识不同的设备代码,相同厂商有不同和设备,需要用DID来区分。
比如这里的0x8168就是Realtek的以太网卡设备,Realtek还有声卡等其它设备,具有不同的DID。
一般情况下用VID和DID就可以匹配设备驱动程序了。
除此之外,还有Subsystem ID和Revision ID和Class Code。
Subsystem ID是次要的设备识别码,作用与VID和DID相同,长度为4字节。
Revision ID是版本号,长度为1字节。
Class Code是设备类型代码,由神秘组织定义的设备类型代码,长度为3字节。
关于设备类型代码,在这里有说明:http://pci-ids.ucw.cz/read/PD
================================================
大概了解了PCI设备的知识后,再来看看Windows驱动程序,Windows驱动一般由一个sys文件和inf文件组成。
inf描述了设备驱动程序的安装过程,以及对应的设备ID。
我找来了刚才的网卡驱动,找到里面关于设备ID的字段如下(部分内容):
;8168B
%RTL8168.DeviceDesc% = RTL8168.ndi, PCI\VEN_10EC&DEV_8168&REV_01
%RTL8168.DeviceDesc% = RTL8168.ndi, PCI\VEN_10EC&DEV_8168&SUBSYS_816810EC&REV_01
;8112
%RTL8112.DeviceDesc% = RTL8168.ndi, PCI\VEN_10EC&DEV_8168&SUBSYS_83851043&REV_01
;8168D
%RTL8168D.DeviceDesc% = RTL8168D.ndi, PCI\VEN_10EC&DEV_8168&REV_03
%RTL8168D.DeviceDesc% = RTL8168D.ndi, PCI\VEN_10EC&DEV_8168&SUBSYS_816810EC&REV_03
;8112L
%RTL8112L.DeviceDesc% = RTL8168D.ndi, PCI\VEN_10EC&DEV_8168&SUBSYS_83A31043&REV_03
;8168E
%RTL8168E.DeviceDesc% = RTL8168E.ndi, PCI\VEN_10EC&DEV_8168&REV_06
%RTL8168E.DeviceDesc% = RTL8168E.ndi, PCI\VEN_10EC&DEV_8168&SUBSYS_816810EC&REV_06
从这里可以看出来,当设备的VID和DID是相同的时候,还需要由SUBSYS和REV来区分不同的版本。
Windows安装驱动程序的时候,会检测到我的网卡ID符合下面这条内容:
%RTL8168E.DeviceDesc% = RTL8168E.ndi, PCI\VEN_10EC&DEV_8168&REV_06
因此会为我的网卡安装这个驱动程序。
========================================================
那么再看看Mac OS X系统下面的驱动程序:
一个Mac系统的驱动程序是一个后缀为.kext的文件夹,里面有Content和Info.plist。
关于设备描述的内容在Info.plist里面,如何匹配设备标识,先看一下开发者文档吧。
苹果开发者文档里更具体的描述:https://developer.apple.com/documentation/kernel/iopcidevice?language=objc
IOPCIMatch:匹配设备VID和DID,或者子系统ID
IOPCIPrimaryMatch:匹配VID和DID
IOPCISecondaryMatch:匹配子系统ID
IOPCIClassMatch:匹配设备类型代码,默认掩码0xFFFFFF00
IONameMatch:匹配设备名称
我找来了几个驱动为参照:
<key>IOPCIMatch</key>
<string>0x10EA8086 0x10EB8086 0x10EF8086 0x10F08086 0x15028086 0x15038086 0x153A8086 0x153B8086 0x155A8086 0x15598086 0x15A08086 0x15A18086 0x15A28086 0x15A38086 0x156F8086 0x15708086 0x15B78086 0x15B88086 0x15D78086 0x15D88086 0x15E38086 0x15D68086 0x15BD8086 0x15BE8086 0x15BB8086 0x15BC8086 0x15DF8086 0x15E08086 0x15E18086 0x15E28086</string>
这里是IOPCIMatch方式,这个驱动支持的设备ID不止一个。
其中0x10EA8086表示VID=0x8060,DID=0x10EA的设备。
再来看这个AppleHDA驱动里的:
<key>IOClass</key>
<string>AppleHDAController</string>
<key>IOPCIClassMatch</key>
<string>0x04020000&0xFFFE0000</string>
IOPCIClassMatch匹配设备类型值:0x04020000&0xFFFE0000
表示掩码0xFFFE000表示用你的PCI设备类型值“按位与”计算出的结果等于0x04020000则匹配成功。
注意:0x0402&0xFFFE和0x0403&0xFFFE结果都是0x0402,所以这个HDA驱动对类型为0x0402和0x0403都有效。
从类型值表查到0x04表示多媒体设备,0x02/0x03表示Computer telephony device/Audio device
再来看设备名称匹配,比如这样的:
<key>IONameMatch</key>
<array>
<string>EHC1</string>
<string>EHC2</string>
</array>
这里的ECH1和EHC2就是表示USB 2.0控制器设备,这个名字从哪里来的呢?
我猜是DSDT吧,因为从导出的DSDT文件里有EHC1这个名字,还有对应的设备地址等信息。
除此之外还有这样匹配设备名的,看上去像VID和DID号:
<key>IOClass</key>
<string>BCM5701Enet</string>
<key>IOMatchCategory</key>
<string>IODefaultMatchCategory</string>
<key>IONameMatch</key>
<array>
<string>pci14e4,1641</string>
<string>pci14e4,1642</string>
<string>pci14e4,1643</string>
<string>pci14e4,1644</string>
<string>pci14e4,1645</string>
</array>
kext驱动文件有两个标准目录一个是/L/E,另一个是/S/L/E,
/L/E目录是第三方驱动的存放路径,建议自己的驱动都放这里。
/S/L/E是苹果原生驱动的路径。
安装方法是把kext复制到/L/E目录,然后修复权限,参考命令如下:
sudo cp -R demo.kext /Library/Extensions/
sudo chown -R root:wheel /Library/Extensions/demo.kext
sudo touch /Library/Extensions/