总结一下DSDT定制中的一些技巧
玩儿黑苹果,免不了和ACPI打交道,也就是大家常说的DSDT和SSDT,在这里我总结一下我在编辑ssdt中的一些经验和技巧一、系统判断
这个是大家都知道的,就是我们在编写ssdt时都会有这样一段代码
If (_OSI ("Darwin"))
这个代码的作用就是做系统判断,让代码只在黑苹果上生效,不会影响win系统。
一般的,这样判断,都会写在函数里,请看下面代码
DefinitionBlock ("", "SSDT", 2, "OCLT", "MCHC", 0)
{
External (_SB.PCI0, DeviceObj)
Scope (_SB.PCI0)
{
Device (MCHC)
{
Name (_ADR, Zero)
Method (_STA, 0, NotSerialized)
{
If (_OSI ("Darwin"))
{
Return (0x0F)
}
Else
{
Return (Zero)
}
}
}
}
}
但是呢,我会这样写:请看我的代码
DefinitionBlock ("", "SSDT", 2, "OCLT", "MCHC", 0x00000000){
External (_SB_.PCI0, DeviceObj)
If (_OSI ("Darwin"))
{
Scope (_SB.PCI0)
{
Device (MCHC)
{
Name (_ADR, Zero)// _ADR: Address
Name (_STA, 0x0F)// _STA: Status
}
}
}
}
我用的方法是将系统判断直接放在代码的最外面,
这样能最大程度的减少代码对win的影响,而且能够简化代码,使代码阅读更清晰
这里还有一个技巧,将函数直接定义为变量,
下面的代码
Method (_PRW, 0, NotSerialized)// _PRW: Power Resources for Wake
{
Return (Package (0x02)
{
0x19,
0x04
})
}
可以写成
Name (_PRW, Package (0x02)
{
0x19,
0x04
})
二、用Ioreg来验证ssdt是否生效
编写ssdt,好多时候我们是为了仿冒设备,那你怎么知道你仿冒的设备是否有用?一般在苹果系统中必要的设备都会加载相应的Kext,
IOreg的全称是IORegistryExplorer
他的功能是查看系统 I/O 信息以及驱动和设备的附属关系
如果你仿冒的设备被成功加载,那么该设备名下是有相应的子项存在的,并且在该设备的右面是有你定义的设备属性的
三、利用Hackintool的计算器来给设备改名
有些时候,DSDT中的设备需要改名,改成MacOS系统中常用的设备名
有些时候,我们还需要对系统保留的带_开头的函数进行重新命名使它失效,进而加载我们重新编写的函数,比如_PTS、_PRW、_DSM等
需要注意的是DSDT中设备和函数的命名都是四个字节,比如XHC实际上是XHC_
这里我们利用Hackintool可以很方便的就能计算出相关的设备名或函数名的十六进制代码,可以很方便的通过打ACPI补丁的方式就可以实现对设备或函数的重新命名
三、利用Hex Fiend活用noop来直接修改部分dsdt
在ssdt编写中,noop这个关键字没有任何作用他的作用就是补齐代码
某个设备,有这样一段代码
Device(GTTY)
Name (_STA,0x0F)// _STA: Status
我需要让它返回Zero
但是_STA是多个设备都拥有的函数,每个设备的_STA都不一样,如果贸然使用改名的方法,需要对所有设备的_STA函数重写,牵涉巨大,那么应该怎么做呢?我只需要对这个GTTY设备的_STA函数打补丁,那么我们扩大查找范围把GTTY和_STA都包含进去,那么不就唯一了吗?这样这块补丁不就精确的打到了它应该存在的位置上了吗?
但是还有一个问题
在二进制代码中Zero和0x0F的长度是不一样的为了补齐长度我会把它变成
或
Name (_STA,Zero)// _STA: Status
noop
上面的代码很简单,很好修补是不是?但是下面这段代码
Method (_STA, 0, NotSerialized)// _STA: Status
{
If ((UM00 == 0x03))
{
If ((UP00 == 0x02))
{
UP00 = UAPG (UM00, UP00, UC00)
}
Return (0x0F)
}
Return (0x03)
}
我需要它返回Zero该怎么办呢?
我会把它单独复制出来做成一个aml
DefinitionBlock ("", "SSDT", 2, "WDOC", "DEVICE", 0x00000000)
{
Method (_STA, 0, NotSerialized)// _STA: Status
{
If ((UM00 == 0x03))
{
If ((UP00 == 0x02))
{
UP00 = UAPG (UM00, UP00, UC00)
}
Return (0x0F)
}
Return (0x03)
}
}
当然这样编译肯定是不通过啦
所以我要修正这段代码缺失的部分,很显然不通过,是因为存在UM00、UP00、UC00三个变量和UAPG一个函数,
DefinitionBlock ("", "SSDT", 2, "WDOC", "DEVICE", 0x00000000)
{
External (UM00, IntObj)
External (UP00, IntObj)
External (UC00, IntObj)
Method (UAPG, 3, NotSerialized)
{
Return (Zero)
}
Method (_STA, 0, NotSerialized)// _STA: Status
{
If ((UM00 == 0x03))
{
If ((UP00 == 0x02))
{
UP00 = UAPG (UM00, UP00, UC00)
}
Return (0x0F)
}
Return (0x03)
}
}
OK,这样不就编译通过了吗?我这样做的目的就是为了获得函数_STA的二进制代码,编译为AML,命名为1.AML
接下来我把这个AML另存为一个副本,这个副本命名为2.AML,打开这个副本修改为
DefinitionBlock ("", "SSDT", 2, "WDOC", "DEVICE", 0x00000000)
{
External (UM00, IntObj)
External (UP00, IntObj)
External (UC00, IntObj)
Method (UAPG, 3, NotSerialized)
{
Return (Zero)
}
Method (_STA, 0, NotSerialized)// _STA: Status
{
noop
若干个noop
noop
Return (Zero)
}
}
然后保存后,用Hex find这个软件打开,直到你填充的noop后这个副本和之前的原本长度一致
然后分别在两个AML中查找_STA,从_STA开始到结尾的代码,在1.AML中就是你要查找的代码,而在2.AML中就是你要替换的代码,这样加上这段补丁,就实现了对DSDT的修改
字都认识,意思呢也都明白,就是不会操作。 大佬这返回的0x19 0x04这是怎么得来的呢 本拉登他爹 发表于 2023-3-18 13:54 https://bbs.pcbeta.com/static/image/common/back.gif
大佬这返回的0x19 0x04这是怎么得来的呢
一般是返回GPRW(0x19,0x04),然后你在看看GPRW函数的操作返回什么,经过各种判断和运算,最终,还是0x19 0x04 为了让大家更明白,我给大家逐步演示
二、用Ioreg来验证ssdt中的设备加载情况,没有ssdt补丁,打开roreg我的设备是这样的
这表示HPET设备没有加载
出现了PCIXXXX,XXXX@X说明设备没有按照苹果的规范来命名
而且用hackintool也能查看到诸如PCIXXXX,XXXX@X的设备
同时,我的硬盘是橙色外置硬盘,这是因为GPP6下的设备PCI1e4b,1202@0没有正确的命名所导致的,虽然IONVMe控制器加载了,但我们仍然需要对它进行命名(命名和重命名的区别:命名是指设备没有名字,我们需要给他命名,一般用ssdt。重命名是设备有名字但是不是macos的命名方式,导致系统不识别不加载相应的驱动,我们需要给它改名字,也就是重命名,一般用补丁改名)
命名的ssdt很简单,只需要对照白果的ioreg找到正确的名字,然后将_ADR给定一个正确的地址就行了,(有的是仿冒不存在的设备,按照标准的地址即可),那么这个地址哪里来?(@后面的就是地址)
比如pci1e4b,1202@0他的地址就是GPP6下的Zero!
因此我做了如下的SSDT
If (_OSI ("Darwin"))
{
Name (HPET._CRS, ResourceTemplate ()// _CRS: Current Resource Settings
{
IRQNoFlags ()
{0,8,11}
Memory32Fixed (ReadWrite,
0xFED00000, // Address Base
0x00000400, // Address Length
)
})
Scope (_SB.PCI0)
{
Device (GPP2.GIGE) //对应GPP2下的ethernet(这也是没有命名)
{
Name (_ADR, Zero)// _ADR: Address
}
Device (GPP3.ARPT) // 对应pci14e4,43a0@0
{
Name (_ADR, Zero)// _ADR: Address
}
Device (GPP6.DEV0)//pci1e4b,1202@0
{
Name (_ADR, Zero)// _ADR: Address
}
Device (GPP6.DEV1) //实际上GPP6下存在两个硬盘,只有插了另一块时才能显示pci1e4b,1202@1
{
Name (_ADR, One)// _ADR: Address
}
Device (LPCB.PMCR) //这个是节能五项的设备,不懂可一看一下oc-little
{
Name (_HID, EisaId ("APP9876"))// _HID: Hardware ID
Name (_CRS, ResourceTemplate ()// _CRS: Current Resource Settings
{
Memory32Fixed (ReadWrite,
0xFE000000, // Address Base
0x00010000, // Address Length
)
})
}
Device (SBUS.BUS0) //加载SM总线的固定格式,没什么好说的,照做就行
{
Name (_CID, "smbus")// _CID: Compatible ID
Name (_ADR, Zero)// _ADR: Address
Device (DVL0)
{
Name (_ADR, 0x57)// _ADR: Address
Name (_CID, "diagsvault")// _CID: Compatible ID
Method (_DSM, 4, NotSerialized)// _DSM: Device-Specific Method
{
If (!Arg2)
{
Return (Buffer (One)
{
0x03 // .
})
}
Return (Package (0x02)
{
"address",
0x57
})
}
}
}
}
}
接下来,加载,加载完成后就会变成下面这样
下面这些是对设备的重命名
在我的机器里,AMD的APU和独显6600都被命名为了VGA,我需要把APU命名为IGPU,而独显命名为GFX0,由于二者都被命名为VGA,所以我要根据路径和所在打了多个补丁前三个是使用了路径,而后面的两个补丁包含了_ADR关键字,因为只有
Device ()
name (_ADR
这里才会单独使用VGA命名,为了区分
然后这个命名的ssdt加载后,IOReg就变成了这样
HPET设备正确加载,加载了AppleHPET驱动
设备命名正确实现内建
无线网卡设备命名正确实现内建
Nvme硬盘控制器命名正确,磁盘不再是橙色的外置磁盘,实现了内建
SM总线实现了加载
PCMR实现了加载AppleACPIPMC,节能出现五项
可见,当设备被正确命名后,要么会加载相关的KEXT,要么实现设备的内建,要么在该设备的ioreg属性栏中出现修正后的正确属性
比如USBX属性加载
Device (USBX)
{
Name (_ADR, Zero)// _ADR: Address
Method (_DSM, 4, NotSerialized)// _DSM: Device-Specific Method
{
If ((Arg2 == Zero))
{
Return (Buffer (One)
{
0x03 // .
})
}
Return (Package (0x08)
{
"kUSBSleepPowerSupply",
0x13EC,
"kUSBSleepPortCurrentLimit",
0x0834,
"kUSBWakePowerSupply",
0x13EC,
"kUSBWakePortCurrentLimit",
0x0834
})
}
}
正确加载后ioreg的AppleUSBHostResources属性中会出现相关属性
不明觉厉,还需要学习。。。
字都认识,意思呢也都明白,就是不会操作。 谢谢楼主的分享 不明觉厉,还需要学习。。。 感谢分享,学习了 感谢分享,学习了 这是技术的东西了。 本帖最后由 Dynamix 于 2023-3-19 10:26 编辑
本拉登他爹 发表于 2023-3-18 13:54 https://bbs.pcbeta.com/static/image/common/back.gif
大佬这返回的0x19 0x04这是怎么得来的呢
看DSDT 你要处理那个设备的原始_PRW 返回值, _PRW 返回的是一个两个整数的对象数组 索引0 是GPEInfo 索引1 是 Lowest Sleep State ,
GpeInfo是固件里就定义好的 为设备的GPIO_SCI分配的一个事件号 用于管理设备的电源事件 例如 Intel平台 PCI设备通用目的事件号有两类 0x6D 和 0x69 分别对应PCH集成设备 和 PCIe Root Port 设备唤醒需要由ACPI通知 OSPM , Notify对应的设备对象则通过 GPEInfo可以在 \_GPE 下找到 管理 PCH集成设备的叫 _L6D 管理 PCIe Root Port的则叫 _L69 而 Lowest Sleep State则表示设备可以提供唤醒能力的最低睡眠等级 0/1/2/3/4 分别对应 _S1、_S2、_S3、_S4 Dynamix 发表于 2023-3-19 10:25 https://bbs.pcbeta.com/static/image/common/back.gif
看DSDT 你要处理那个设备的原始_PRW 返回值, _PRW 返回的是一个两个整数的对象数组 索引0 是GPEInfo 索引 ...
大佬,这方面的知识您多讲讲呗,有关睡眠唤醒和PCH等一些知识 wangdongfreesky 发表于 2023-3-18 16:51 https://bbs.pcbeta.com/static/image/common/back.gif
为了让大家更明白,我给大家逐步演示
二、用Ioreg来验证ssdt中的设备加载情况,没有ssdt补丁,打开roreg我 ...
你的呢是AMD平台 我有个疑问 其实对于 AppleHPET个AppleACPIPMC 并不是为了加载而加载 你确定AMD平台 HPET的内存范围是_BAS FED00000h 吗, 你看一下DSDT里 HPET 资源模板的定义吧,还有 PMCR 他的资源模板写的可是 ReadWrite 驱动可以读写指定内存范围 你确定 AMD的 PWRM内存起始和Intel一样都是 FE000000h吗 如果 FE000000h 是常驻内存里面有重要数据映射被 驱动错误更改是否会导致更严重的问题出现? 还有个方法 其实ACPI Patch查找替换如果在 自定义SSDT中没有做回调势必会影响Windows 其实macOS 对于 _STA 方法支持结果覆写 就像那些在DSDT中的部分设备 _STA 没有返回 0的条件你可以用SSDT直接覆盖掉它的 _STA 的结果 在SSDT中把对应设备的 Method (_STA) 引用为 IntObj或者 UnknownObj 直接用赋值语法 比如直接
_STA = 0
直接禁用设备也不会产生ACPI Error 也不用 ACPI Patch 查找替换 Dynamix 发表于 2023-3-19 10:35 https://bbs.pcbeta.com/static/image/common/back.gif
你的呢是AMD平台 我有个疑问 其实对于 AppleHPET个AppleACPIPMC 并不是为了加载而加载 你确定AMD平台 HPE ...
这个hpet是ssdttime生成的,就是irq补丁而加载的,实际不加载貌似没什么影响,