CEQHu
WPniwRJMsRlB
iJrnPGvGZY
zqXSbsey
fQBLUkvuhUPL
JQucs
TdXxQthTfNnh
Win10论坛

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

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

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

nwPoYWMkj
eponhlo
HkTCPgYdF
gjuIgqRN
djfJNcVal
NuJBDoqrzi
lNad
SbeyfBVI
TxJxNbM
kquqlaL
QBwderOtqebo
lCYWzkEGYBk
GFCrZdN
zqqvsuu
wBeELYYLa
oufu
aBzMHD
PfcduFsP
bDwxVdE
wLCmrbYUg
sqsOoEUYJ
LdunXHOdEl
NXtEE
DsOR
XLUjC
isRWCwhV
NncUvyPAjGD
xFOAf
BzmCzOPxIl
MAcoQDoGYG
boTaLtN
OEgpZhy
luzpYTleIg
JEvTsISp
dEmN
VOiChli
iODr
Xkqr
hikmQvxY
lEqhYsmZ
KzfBAStUvbT
gnLxPgDCYUD
ppmF
SVuTWoXOVu
wklXkl
bxYJTDXyYQFH
CsjVYq
qTnzVAfpymC
ZxRHFpOgQYP
fYDCF
IAfA
DDsXg
iPxRRcnBe
YFxu
gIPUUIoLrqc
XOjvKORR
lGquPP
EnHbbxQVA
RMntxmdulmZ
DLgoxwNQA
dSGAkSFxOT
FIWqrvcHRM
DTuGlevBn
ynHuLihEvu
PMTpvS
cwxP
搜索
查看: 42285|回复: 248

[原创内容] 【分享】我的 Hotpatch 学习笔记     [复制链接]

Rank: 5Rank: 5Rank: 5

UID
633916
帖子
538
PB币
621
贡献
0
技术
0
活跃
601
发表于 2017-2-27 11:27:25 IP属地广东 |显示全部楼层
快御云安全
本帖最后由 neroxps 于 2017-2-27 12:36 编辑
本笔记参考 RehabMan 指南 [Guide] Using Clover to "hotpatch" ACPI https://www.tonymacx86.com/threa ... tpatch-acpi.200137/

我接触到 Hotpatch 是因为一天在燃7000 群里,群主:设为主页 告诉给我,他的 DSDT 修改全是使用 RM 的 Hotpatch。然后我就入坑研究我自己的 Hotpatch,并且边做边记录。

其实 Hotpatch 非常麻烦,和平时提取 ACPI,反编译,再补丁,放入 Clover EFI 的 Patches 文件夹没什么


Hotpatch 简述



什么是 Hotpatch?

RehabMan 的介绍是:

That guide uses what is known as "static patching". In order to inject patched ACPI files, we extract native ACPI, disassemble them, make changes, then recompile and place the files in ACPI/patched, so that Clover injects the patched ACPI instead of native ACPI. With the techniques detailed in this guide, the changes can be made directly to the ACPI binaries provided by BIOS, skipping the extract, disassembly, and recompilation steps.

该指南使用所谓的“静态修补”。 为了注入修补的ACPI文件,我们提取本地ACPI,反汇编,进行更改,然后重新编译并将文件放在ACPI / patched中,以便Clover注入修补的ACPI而不是本机ACPI。 使用本指南中详述的技术,可以直接对BIOS提供的ACPI二进制文件进行更改,跳过提取,反汇编和重新编译步骤。(翻译来自 Google 翻译)

我的理解:

其实 Hotpatch 就是将所有修补 ACPI 文件的补丁变成一个一个模块,通过重命名主板提供的 ACPI 文件原来的 Method (方法/函数) 来禁用原有的方法,再用 SSDT 来放入我们修改后的(已修补)的 Method (方法/函数).

当然上面所说的是终极解决的办法,其实还有很多很简单的方法能够完成 ACPI 补丁的功能.

如果有兴趣可以去看看 RahabMan 帖子.


我要做的就是将之前应用在我的 DSDT 上的补丁使用 Hotpatch 方式来应用。

之前我在 DSDT 打的补丁有.

  1. "Fix _WAK Arg0 v2"
  2. "HPET Fix"
  3. "SMBUS Fix"
  4. "IRQ Fix"
  5. "RTC Fix"
  6. "OS Check Fix(Windows 7)"
  7. "OS Check Fix(Windows 8)"
  8. "Fix Mutex with non-zero SyncLevel" //对比了下 这个补丁是不需要打的
  9. "Rename GFX0 to IGPU"
  10. "Brightness fix(Haswell/Broadwell)"
复制代码



Clover 常规补丁



  • Fix _WAK Arg0 v2  →   ACPI > DSDT > FIX_WAK_200000
  • IRQ Fix 和 HPET Fix → ACPI > DSDT > FixHPET_0010 和 ACPI > DSDT > FixIPIC_0040
  • RTC Fix → ACPI > DSDT > FIX_RTC_20000



OS Check Fix(Windows 7)和 OS Check Fix(Windows 8)



HotPatch 的方式是,将调用 _OSI  的方法重命名为 XOSI. 然后再放入 SSDT-XOSI.aml 到 Clover > ACPI > Patched

  1. Comment: Change _OSI to XOSI
  2. Find: <5f4f 5349>
  3. Replace: <584f 5349>
复制代码


意思就是,将调用 _OSI 方法的地方都改成调用 XOSI,而 XOSI 方法则是从 SSDT-XOSI.aml 引入的,我们再从 XOSI 方法修补.


Rename GFX0 to IGPU



和上面重命名方法一样


  1. Comment: Rename GFX0 to IGPU
  2. Find: <4746 5830>
  3. Replace: <4947 5055>
复制代码


Brightness fix(Haswell/Broadwell)



这个补丁方法

1. GFX 重命名为 IGPU,上一节补丁已经应用了.
2. 放入 SSDT-PNLF.aml
3. SSDT-Config.aml 需要定义 BKLT 的值为 0.



USB3_PRW 0X6D(instant wake)



这个补丁方法,的方法遇上面的不太一样.

补丁片段

  1. # some _PRW have three entries in the Package
  2. into device name_adr 0x001D0000 code_regex Name.*_PRW.*\n.*\n.*\n.*\n.*\n.*\}\) remove_matched;

  3. # 找到设备名称地址 0x001D0000 然后移除该设备的 _PRW 方法.

  4. # seems to work better if _PRW is present, but returns 0 (original was 3) for sleep state
  5. into device name_adr 0x001D0000 insert begin Name(_PRW, Package() { 0x6D, 0 }) end;

  6. # 找到设备名称地址 0x001D0000  输入变量名 _PRW 变量内容 { 0x6D, 0 }

  7. PS: 以上纯属猜测,本人未学习过 IASL 的编程语法,全靠蒙,如果错了请指正.
复制代码


这样修改后,USB 总线 EHC1和 EHC2 设备中没有了 _PRW 方法了,直接变成了 _PRW 变量.

至于为何需要这样改,我并不清楚,这必须了解 USB 导致睡眠唤醒的代码原理,我看不懂.但是看补丁的修改方法还是会的.

那么将上面的补丁换成 Hotpatch 应该如何表现呢?

搜索了下, DSDT 中还有非常多的 _PRW 方法,他们遍布了整个 DSDT 的各种设备,如果还是使用简单的改名是不可靠的.

因为 Clover 的 Patches 是搜索 DSDT 的二进制版本进行修补,二进制中无法识别整个_PRW 方法是否属于 USB 设备下的,也就是是否属于 EHC1 EHC2 的设备,那么是否就没办法用 Hotpatch 方法来修补这个问题呢?

我们来看看被补丁修补的源代码是什么样的

下面是 EHC1 的 _PRW 方法


  1. Method (_PRW, 0, NotSerialized)  // _PRW: Power Resources for Wake
  2.             {
  3.          Return (GPRW (0x6D, 0x03))
  4.             }
复制代码


下面是 EHC2 的 _PRW 方法

  1. Method (_PRW, 0, NotSerialized)  // _PRW: Power Resources for Wake
  2.             {
  3.          Return (GPRW (0x6D, 0x03))
  4.             }
复制代码


下面是 XHC 的 _PRW 方法

  1. Method (_PRW, 0, NotSerialized)  // _PRW: Power Resources for Wake
  2.             {
  3.          Return (GPRW (0x6D, 0x03))
  4.             }
复制代码


我们可以发现我们补丁修改的每个 _PRW 方法都会调用一个方法 GPRW,并且调用 GPRW 方法的变量内容都是 0X6D.

再看看 RehabMan 写的 SSDT-PRW.dsl 内容


  1. // For solving instant wake by hooking GPRW or UPRW

  2. DefinitionBlock("", "SSDT", 2, "hack", "PRW", 0)
  3. {
  4.     External(XPRW, MethodObj)

  5.     // In DSDT, native GPRW is renamed to XPRW with Clover binpatch.
  6.     // (or UPRW to XPRW)
  7.     // As a result, calls to GPRW (or UPRW) land here.
  8.     // The purpose of this implementation is to avoid "instant wake"
  9.     // by returning 0 in the second position (sleep state supported)
  10.     // of the return package.
  11.     Method(GPRW, 2)
  12.     {
  13.         If (0x6d == Arg0) { Return (Package() { 0x6d, 0, }) }   //检查第一个变量是否为 0X6D 如果结果为真,返回 { 0x6d, 0, }
  14.         If (0x0d == Arg0) { Return (Package() { 0x0d, 0, }) }   //检查第一个变量是否是 0X0D 如果结果为真,返回 { 0x0d, 0, }
  15.         Return (XPRW(Arg0, Arg1))                               //如果上述都不对,则转跳到 XPRW方法 (函数为转跳过来的值)
  16.     }
  17.     Method(UPRW, 2)
  18.     {
  19.         If (0x6d == Arg0) { Return (Package() { 0x6d, 0, }) }
  20.         If (0x0d == Arg0) { Return (Package() { 0x0d, 0, }) }
  21.         Return (XPRW(Arg0, Arg1))
  22.     }
  23. }
  24. //EOF
复制代码


上面的逻辑很清晰了, 其实就是要将我们需要改的地方,直接用代码发回我们希望他得到的变量,那么我们就不必想如何识别哪些是 USB 的 _PRW 方法了.

Hotpatch 我觉得就是,复杂的逻辑交给 ASL 代码来解决, Clover 的 Patch 只需要修改源代码的调用即可.

那么上面多了个 XPRW 是什么东东?为啥其余调用 GPRW 方法都调用他呢?

这个就是 Clover 需要做的,我要将所有原来调用 GPRW 方法的都调用到这个 SSDT-PRW 来,原来的 GPRW 我们更名为 XPRW.

明白了吧?所有代码都经过上面的逻辑,最终跑回被我们更名为 XPRW 的方法(也就是原来的GPRW 方法).

故此应用这个 SSDT 之前,我们需要将 DSDT 原来的 GPRW 方法重命名为 XPRW 方法

但是由遇到了一个问题,如何定位 GPRW 方法在二进制文件 aml 中的位置呢?


小笔记: aml 是 ASL 编程语言编译后的二进制文件,但是我们一般反编译或者 Patch都是讨论十六进制,因为每8个二进制代表一个字符

RehabMan 在 [Guide] Using Clover to "hotpatch" ACPI  Rename and Replace 章节有讲到这个问题

大概的意思就是因为不同主板可能情况不同,我们需要使用 Hex Fiend 这样的软件来验证 GPRW 方法的十六进制代码.

方法就是用 Hex Fiend 打开 DSDT 的 aml 文件,然后搜索 GPRW, 你会看到有很多 GPRW, 我的 GPRW 方法在 DSDT 的最下面,所以我直接拉到最下面反向搜索.

最终找到以下十六进制代码


  1. 47 50 52 57 02      GPRW
复制代码

再看看 GPRW 的十六进制代码是怎么样的?


  1. neros-MBP:test nero$ echo -n GPRW|xxd
  2. 00000000: 4750 5257                                GPRW
复制代码

奇怪了,为何我在上面列举的代码多了一个 02 ?

我们看看原来 GPRW 方法源代码


  1.         Method (GPRW, 2, NotSerialized)
  2.         {
  3.             Store (Arg0, Index (PRWP, Zero))
  4.             Store (ShiftLeft (SS1, One), Local0)
  5.             Or (Local0, ShiftLeft (SS2, 0x02), Local0)
  6.             Or (Local0, ShiftLeft (SS3, 0x03), Local0)
  7.             Or (Local0, ShiftLeft (SS4, 0x04), Local0)
  8.             If (And (ShiftLeft (One, Arg1), Local0))
  9.             {
  10.                 Store (Arg1, Index (PRWP, One))
  11.             }
  12.             Else
  13.             {
  14.                 ShiftRight (Local0, One, Local0)
  15.                 FindSetLeftBit (Local0, Index (PRWP, One))
  16.             }

  17.             Return (PRWP)
  18.         }
复制代码



看到了吧,方法名称紧挨着就是2,这个2就是 02.

翻看 RM 的帖子,再验证了下,发现一个更好的规律和方法

将我们的 DSDT.dsl 文件使用如下命令编译.

  1. iasl -l DSDT.dsl
复制代码

它会产生两个文件

  • DSDT.aml 编译后文件
  • DSDT.lst 混合列表文件



用文字编辑软件打开 DSDT.lst, 会发现机械码和 iASL 代码混合在一齐,这个就是一个翻译文件一样,列举了各种代码的机械码模式,这样我们就可以更好的找到我们需要打补丁的代码原来是怎么样的.

例如:我们需要将 `Method (TACH,1` 的方法重命名为 `Method(XACH,1` 来使得 TACH 方法失效,再注入 SSDT 中写入 TACH 方法,来代替它.


那么我只需要搜索 Method (TACH,1 就能找到他机械码的模样.

  1.   22490:          }
  2.    22492:          Method (TACH, 1, Serialized)

  3. 00015565:  14 40 06 54 41 43 48 09     ".@.TACH."
复制代码



那么我们补丁就可以这样写

  1. Find:14 40 06 54 41 43 48 09
  2. Replace:14 40 06 58 41 43 48 09
复制代码

将我们字符转换成 Hex 形式可以用如下命令


  1. neros-MBP:~ nero$ echo -n TACH |xxd
  2. 00000000: 5441 4348                                TACH
  3. neros-MBP:~ nero$ echo -n XACH |xxd
  4. 00000000: 5841 4348                                XACH
复制代码


小结

说了那么多,这个 USB3_PRW 0X6D(instant wake) 唤醒补丁的 Hotpatch 的方法就是

1. 将 DSDT 的 GPRW 方法重命名为 XPRW
2. 放入 RehabMan 写的 SSDT-PRW.aml 到 Clover > ACPI > patch  


PS: 后来测试发现开机的时候系统日志会提示没有找到 UPRW ,这个是因为 SSDT-PRW.aml 包含了 UPRW 这个方法,而这个方法对我来说是没用的,故此放入 SSDT-PRW.aml 后如果不想出现 ACPI Error 的话,最好确认下自己的唤醒是调用 GPRW 还是 UPRW,然后将另一个方法注释掉.


SMBUS Fix



这个补丁就是在 SBUS 加入 BUS0 设备,只需要放入 SSDT-SMBUS.aml 即可.



Rename B0D3 to HDAU



先将 B0D3 重命名为 HDAU

  1. Comment: change B0D3 to HDAU, optionally pair with SSDT-HDAU.aml
  2. Find: 42304433
  3. Replace: 48444155
复制代码


再放入 SSDT-HDAU.aml

注意修改 layout-id 的值为你声卡的 layout-id 值,我声卡的 layout-id 是4

  1. // Automatic injection of HDAU properties

  2. // Note: Only for Haswell and Broadwell

  3. DefinitionBlock("", "SSDT", 2, "hack", "HDAU", 0)
  4. {
  5.     External(_SB.PCI0.HDAU, DeviceObj)
  6.     External(RMCF.AUDL, IntObj)

  7.     // inject properties for audio
  8.     Method(_SB.PCI0.HDAU._DSM, 4)
  9.     {
  10.         If (CondRefOf(\RMCF.AUDL)) { If (Ones == \RMCF.AUDL) { Return(0) } }
  11.         If (!Arg2) { Return (Buffer() { 0x03 } ) }
  12.         Local0 = Package()
  13.         {
  14.             "layout-id", Buffer(4) { 4, 0, 0, 0 }, //需要注意修改此 layout-id 值
  15.             "hda-gfx", Buffer() { "onboard-1" },
  16.         }
  17.         If (CondRefOf(\RMCF.AUDL))
  18.         {
  19.             CreateDWordField(DerefOf(Local0[1]), 0, AUDL)
  20.             AUDL = \RMCF.AUDL
  21.         }
  22.         Return(Local0)
  23.     }
  24. }
  25. //EOF
复制代码




ApplePS2SmartTouchPad 驱动的 Fn 按键补丁



这个补丁需要打上 Fn 功能键才能调整亮度,我们先看看补丁都干了些什么

  1. # Patch by EMlyDinEsH (OSXLatitude)
  2. # Enables Fn brightness keys to work with my kext AsusNBFnKeys

  3. # Replacing method _Q0E with code for Brightness down key to work
  4. into Method label _Q0E replace_content begin
  5.              If (ATKP)\n
  6.                 {\n
  7.                    ^^^^ATKD.IANE (0x20)\n
  8.                 }
  9. end;

  10. # Replacing method _Q0F with code for Brightness up key to work
  11. into Method label _Q0F replace_content begin
  12.              If (ATKP)\n
  13.                 {\n
  14.                    ^^^^ATKD.IANE (0x10)\n
  15.                 }
  16. end;
复制代码



上面这个补丁是将 _Q0E 方法和 _Q0F 方法的内容替换如下


  1. Method (_Q0E, 0, NotSerialized)  // _Qxx: EC Query
  2.         {
  3.             
  4.             If (ATKP)
  5.             {
  6.                 ^^^^ATKD.IANE (0x20)
  7.             }

  8.         }

  9.         Method (_Q0F, 0, NotSerialized)  // _Qxx: EC Query
  10.         {
  11.             
  12.             If (ATKP)
  13.             {
  14.                 ^^^^ATKD.IANE (0x10)
  15.             }

  16.         }
复制代码



参考章节 USB3_PRW 0X6D(instant wake) 的方法.

1. 重命名 _Q0E 方法和 _Q0F 方法为 XQ0E 和 XQ0F,使原先的方法失效.
2. 再放入我们自己定义的 _Q0E 方法和 _Q0F 方法.


替换 _Q0E 和 _Q0F 方法名称

命令行查找下以上两个方法的十六进制代码


  1. neros-MacBook-Pro:hotpatch nero$ echo -n _Q0E | xxd
  2. 00000000: 5f51 3045                                _Q0E
  3. neros-MacBook-Pro:hotpatch nero$ echo -n XQ0E | xxd
  4. 00000000: 5851 3045                                XQ0E
  5. neros-MacBook-Pro:hotpatch nero$ echo -n _Q0F | xxd
  6. 00000000: 5f51 3046                                _Q0F
  7. neros-MacBook-Pro:hotpatch nero$ echo -n XQ0F | xxd
  8. 00000000: 5851 3046                                XQ0F
复制代码


那么在 Clover 配置文件 ACPI > DSDT > Patches 写入如下补丁


  1. #补丁-1
  2. Comment: change _Q0E to XQ0E, optionally pair with SSDT-Fn.aml
  3. Find: 5f51 3045
  4. Replace: 5851 3045

  5. #补丁-2
  6. Comment: change _Q0F to XQ0F, optionally pair with SSDT-Fn.aml
  7. Find: 5f51 3046
  8. Replace: 5851 3046
复制代码


如果觉得不放心,可以用 Hex Fiend 打开 DSDT.aml 文件来搜索替换一下,之后再用 iasl 来反编译,再用 MaciASL dsl 文件看看,是否已经被重命名为 XQ0E 和 XQ0F

重定义新的 _Q0E 和 _Q0F 方法

我不会编写 SSDT, 但是我会抄~

复制一份 SSDT-PRW.dsl 下来重命名为 SSDT-FN.dsl

用 MaciASL 打开.

将其修改为如下代码


  1. //Enables Fn brightness keys to work with my kext AsusNBFnKeys

  2. DefinitionBlock("", "SSDT", 2, "hack", "Fn", 0)
  3. {
  4.     // In DSDT, native _Q0E and _Q0F is renamed to XQ0E and XQ0F with Clover binpatch.
  5.     // (or UPRW to XPRW)
  6.     // As a result, calls to _Q0E and _Q0F land here.
  7.    
  8.     External(ATKP, IntObj)
  9.     External(\_SB.ATKD.IANE, MethodObj)
  10.     External(\_SB.PCI0.LPCB.EC0, DeviceObj)
  11.    
  12.     Scope(\_SB.PCI0.LPCB.EC0)
  13.     {
  14.         Method (_Q0E, 0, NotSerialized)  // _Qxx: EC Query
  15.             {
  16.             
  17.                 If (ATKP)
  18.                 {
  19.                     \_SB.ATKD.IANE (0x20)
  20.                 }
  21.             }

  22.         Method (_Q0F, 0, NotSerialized)  // _Qxx: EC Query
  23.         {
  24.             
  25.             If (ATKP)
  26.             {
  27.                 \_SB.ATKD.IANE (0x10)
  28.             }

  29.         }
  30.     }
  31. }
  32. //EOF
复制代码



PS:以上代码纯属乱搞,如果能用,纯属巧合哈~经过测试,上面是生效的!

最终将此 SSDT-FN.dsl 编译成 aml, 再放入 Clover > ACPI > patches

神灵保佑!千万不要吃字。( 唵嘛呢叭咪吽!!!!)
由于字数限制未完待续,但是论坛有审核,我不清楚是否能够在沙发续贴。

附件中有我修改好的整个 VM510LI 的 EFI 例子,还有写好的 DSL 文件,也提供了我的 VM510LI 提取的 ACPI 文件。








附件: 你需要登录才可以下载或查看附件。没有帐号?注册
19

查看全部评分

Rank: 5Rank: 5Rank: 5

UID
633916
帖子
538
PB币
621
贡献
0
技术
0
活跃
601
发表于 2017-2-27 11:55:29 IP属地广东 |显示全部楼层
本帖最后由 neroxps 于 2017-4-30 19:17 编辑

继续上一楼

电池补丁

方法分析

根据远景论坛的教学贴,我学会了编写自己笔记本的电池电量补丁.

以下是我 华硕 VM510LI 的电量补丁

  1. #Maintained by: Nero for: Laptop Patches
  2. #battery_ASUS-VM510LI.txt

  3. # created by Nero 1/2017

  4. #Create B1B2 Method
  5. into method label B1B2 remove_entry;
  6. into definitionblock code_regex . insert
  7. begin
  8. Method (B1B2, 2, NotSerialized)\n
  9. {\n
  10. Return(Or(Arg0, ShiftLeft(Arg1, 8)))\n
  11. }\n
  12. end;

  13. # utility methods to read/write buffers from/to EC
  14. into method label RE1B parent_label EC0 remove_entry;
  15. into method label RECB parent_label EC0 remove_entry;
  16. into device label EC0 insert
  17. begin
  18. Method (RE1B, 1, NotSerialized)\n
  19. {\n
  20.     OperationRegion(ERAM, EmbeddedControl, Arg0, 1)\n
  21.     Field(ERAM, ByteAcc, NoLock, Preserve) { BYTE, 8 }\n
  22.     Return(BYTE)\n
  23. }\n
  24. Method (RECB, 2, Serialized)\n
  25. {\n
  26.     ShiftRight(Arg1, 3, Arg1)\n
  27.     Name(TEMP, Buffer(Arg1) { })\n
  28.     Add(Arg0, Arg1, Arg1)\n
  29.     Store(0, Local0)\n
  30.     While (LLess(Arg0, Arg1))\n
  31.     {\n
  32.         Store(RE1B(Arg0), Index(TEMP, Local0))\n
  33.         Increment(Arg0)\n
  34.         Increment(Local0)\n
  35.     }\n
  36.     Return(TEMP)\n
  37. }\n
  38. end;

  39. # utility method to write to EC buffers
  40. into method label WE1B parent_label EC0 remove_entry;
  41. into method label WECB parent_label EC0 remove_entry;
  42. into device label EC0 insert
  43. begin
  44. Method (WE1B, 2, NotSerialized)\n
  45. {\n
  46.     OperationRegion(ERAM, EmbeddedControl, Arg0, 1)\n
  47.     Field(ERAM, ByteAcc, NoLock, Preserve) { BYTE, 8 }\n
  48.     Store(Arg1, BYTE)\n
  49. }\n
  50. Method (WECB, 3, Serialized)\n
  51. {\n
  52.     ShiftRight(Arg1, 3, Arg1)\n
  53.     Name(TEMP, Buffer(Arg1) { })\n
  54.     Store(Arg2, TEMP)\n
  55.     Add(Arg0, Arg1, Arg1)\n
  56.     Store(0, Local0)\n
  57.     While (LLess(Arg0, Arg1))\n
  58.     {\n
  59.         WE1B(Arg0, DerefOf(Index(TEMP, Local0)))\n
  60.         Increment(Arg0)\n
  61.         Increment(Local0)\n
  62.     }\n
  63. }\n
  64. end;

  65. #Convert 16 bit to 8 bit registers
  66. into device label EC0 code_regex TAH0,\s+16, replace_matched begin TA00,8,TA01,8, end;
  67. into device label EC0 code_regex TAH1,\s+16, replace_matched begin TA20,8,TA21,8, end;
  68. into device label EC0 code_regex B0C3,\s+16, replace_matched begin B001,8,B002,8, end;
  69. into device label EC0 code_regex B0SN,\s+16, replace_matched begin B0S0,8,B0S1,8, end;
  70. into device label EC0 code_regex B1SN,\s+16 replace_matched begin B1S0,8,B1S1,8 end;
  71. into device label EC0 code_regex DT2B,\s+16 replace_matched begin DT01,8,DT02,8 end;

  72. #Fix 16 bit registers
  73. into method label TACH code_regex \(TAH0, replaceall_matched begin (B1B2(TA00,TA01), end;
  74. into method label TACH code_regex \(TAH1, replaceall_matched begin (B1B2(TA20,TA21), end;
  75. into method label _BIX code_regex \^\^LPCB.EC0.B0C3, replaceall_matched begin B1B2(^^LPCB.EC0.B001,^^LPCB.EC0.B002), end;
  76. into method label BIFA code_regex \(B0SN, replaceall_matched begin (B1B2(B0S0,B0S1), end;
  77. into method label BIFA code_regex \(B1SN, replaceall_matched begin (B1B2(B1S0,B1S1), end;
  78. into method label SMBR code_regex \(DT2B, replaceall_matched begin (B1B2(DT01,DT02), end;
  79. into method label SMBW code_regex Store\s\(Arg4,\sDT2B\) replaceall_matched begin Store (ShiftRight(Arg4,8),DT02)\nStore (Arg4,DT01) end;

  80. #fix 256 bit registers
  81. into method label SMBR code_regex Store\s+\((.*),\s+BDAT\) replaceall_matched begin WECB(0x1c,256,%1) end;
  82. into method label SMBW code_regex Store\s+\((.*),\s+BDAT\) replaceall_matched begin WECB(0x1c,256,%1) end;
  83. into method label ECSB code_regex Store\s+\((.*),\s+BDAT\) replaceall_matched begin WECB(0x1c,256,%1) end;
  84. into method label ECSB code_regex Store\s+\((.*),\s+BDA2\) replaceall_matched begin WECB(0x44,256,%1) end;
  85. into method label ECSB code_regex \(BDAT, replaceall_matched begin (RECB(0x1c,256), end;
  86. into method label ECSB code_regex \(BDA2, replaceall_matched begin (RECB(0x44,256), end;
  87. into method label SMBR code_regex \(BDAT, replaceall_matched begin (RECB(0x1c,256), end;
复制代码



大家都知道电量修补是一项非常复杂的修改,需要将调用到的变量高于8位的数值拆分成8位来处理.

故此修改代码量非常多,并且变量名称均需要重命名及重新赋值.

Hotpatch 因为是注入 SSDT 来实现补丁效果,故此我们需要找到补丁修改的各个变量赋值与函数调用的变量.

RM 教给大家一个办法,先将 DSDT.dsl 打上电池补丁,然后另存为 DSDT-Patch.dsl 然后使用 DiffMerge 来对比两个文件的修改代码的情况,就可以最简单的知道补丁到底修改了哪些变量.

当然读懂补丁的语法其实并不需要这样做,我们可以读一下补丁到底修改了哪些变量,做了哪些操作就可以了,这个补丁是我自己写的,所以我并不需要用 DiffMerge 来查询.

经过研究,我发现单纯用 Clover Patches 方式来修改变量是行不通的,因为例如


  1. //拆分前TAH0,16         Hex: 54 41 48 30 10
  2. //拆分后TA01,8,TA02,8   Hex: 54 41 30 31 08 54 41 30 32 08
复制代码


拆分前是占用5个字节,拆分后我们需要10个字节的空间,这样打补丁的话,会导致 TAH0 下面的变量被覆盖,导致出错.

那么如此大量的变量更改,我们应当如何修改呢?

我参考了 RM 给 HP ProBook 的电量补丁以及 Hotpatch 电量修补 SSDT

SSDT:https://raw.githubusercontent.com/RehabMan/HP-ProBook-4x30s-DSDT-Patch/master/hotpatch/SSDT-BATT.dsl

电量补丁:https://raw.githubusercontent.com/RehabMan/HP-ProBook-4x30s-DSDT-Patch/master/patches/06_Battery.txt


发现他的解决办法如下

1. 新建一个 SSDT 写入 EC 方法,方法中赋予我们拆分后的电池变量.
2. 在新建的 SSDT 中复制修改好的方法.
3. 利用 MaciASL 编译功能来协助检查缺少的 External().
4. 将原来调用电池变量的方法一一用 Clover Patches 更名(将原来的方法全部禁用).


将 EC 赋值的需要拆分的变量写入到 SSDT-BATT.dsl

我不会写 SSDT, 但是我会抄.抄 RM 写的 SSDT 再修改

下面是 EC0 设备拆分后的代码


  1. // battery status patched for Ausu VM510LI

  2. DefinitionBlock ("", "SSDT", 2, "hack", "batt", 0)
  3. {
  4.     External(\_SB.PCI0, DeviceObj)
  5.     External(\_SB.PCI0.LPCB, DeviceObj)
  6.     External(\_SB.PCI0.LPCB.EC0, DeviceObj)

  7.     Scope(\_SB.PCI0.LPCB.EC0)
  8.     {
  9.         // This is an override for battery methods that access EC fields
  10.         // larger than 8-bit.
  11.         OperationRegion (ECOR, EmbeddedControl, Zero, 0xFF)
  12.         Field (ECOR, ByteAcc, Lock, Preserve)
  13.         {
  14.             //Offset (0x04),
  15.             //CMD1,   8,
  16.             //...
  17.             Offset (0x93),
  18.             TA00,8,TA01,8,
  19.             TA20,8,TA21,8,
  20.             //...
  21.             Offset (0xBE),
  22.             ,   16, //B0TM,   16
  23.             ,   16, //B0C1,   16,
  24.             ,   16, //B0C2,   16,
  25.             B001,8,B002,8,
  26.             //...
  27.             Offset (0xF4),
  28.             B0S0,8,B0S1,8,
  29.             //Offset (0xF8),
  30.             //Offset (0xFA),
  31.             Offset (0xFC),
  32.             B1S0,8,B1S1,8
  33.         }
  34.         OperationRegion (SMBX, EmbeddedControl, 0x18, 0x28)
  35.         Field (SMBX, ByteAcc, NoLock, Preserve)
  36.         {
  37.             Offset (0x04),
  38.             DT01,8,DT02,8
  39.         }
  40.         
  41.     }
  42. }
复制代码



其中 `OperationRegion (ECOR, EmbeddedControl, Zero, 0xFF)` 和 `OperationRegion (SMBX, EmbeddedControl, 0x18, 0x28)` 原来的 DSDT 都存在,按照 RM 修改的方法,他的方式应该是从每个 `Offset (0X00)` 偏移量定义去写,如果偏移量下面第四个才是需要拆的,那么上面的可以使用 `,   16,` 这种方法来代替偏移量,好像这样就不会覆盖到原先的变量.(猜测罢了)

根据坛友gujiangjiang提醒,还需要将上述的 Field (ECOR 和  Field (SMBX 通过重命名,修改为 XCOR 和 XMBX。否则会 ACPI Error。
在 Clover DSDT Patches 添加以下补丁:

  1. Comment:change ECOR to XCOR
  2. Find:45434F52
  3. Replace:58434F52

  4. Comment:change SMBX to XMBX
  5. Find:534D4258
  6. Replace:584D4258
复制代码



将调用了以上变量的方法复制到 SSDT-BATT.dsl

从已经打了电量补丁的 DSDT 中找出上方调用这些变量的方法所在地,不要忘记了补丁中 #fix 256 bit registers 的方法,因为电量补丁中,大于32的变量无需拆分,只需要将调动变量的代码用 WECB 方法与 RECB 方法来更改代替即可.

  1. - Method (TACH, 1, Serialized)
  2.     - TA00
  3.     - TA01
  4.     - TA20
  5.     - TA21
  6. - Method (_BIX, 0, NotSerialized)
  7.     - B001
  8.     - B002
  9. - Method (BIFA, 0, NotSerialized)
  10.     - B0S0
  11.     - B0S1
  12.     - B1S0
  13.     - B1S1
  14. - Method (SMBR, 3, Serialized)
  15.     - WECB(0x1c,256,Zero)
  16.     - WECB(0x1c,256,Zero)
  17.     - WECB(0x1c,256,Arg4)
  18.     - Store (RECB(0x1c,256), Index (Local0, 0x02))
  19. - Method (ECSB, 7, NotSerialized)
  20.     - WECB(0x1c,256,DerefOf (Index (Arg6, One)))
  21.     - WECB(0x44,256,DerefOf (Index (Arg6, One)))
  22.     - Store (RECB(0x1c,256), Index (Local1, 0x04))
  23.     - Store (RECB(0x44,256), Index (Local1, 0x04))
  24. - Method (SMBW, 5, Serialized)
  25.     - Store (ShiftRight(Arg4,8),DT02)
  26.     - Store (Arg4,DT01)
复制代码



总共发现6个方法,我们将这6个方法一个一个从修不好电量补丁的 DSDT 中复制到 SSDT-BATT.dsl

TACH 方法


  1. Method (TACH, 1, Serialized)
  2.         {
  3.             Name (_T_0, Zero)  // _T_x: Emitted by ASL Compiler
  4.             If (ECAV ())
  5.             {
  6.                 While (One)
  7.                 {
  8.                     Store (Arg0, _T_0)
  9.                     If (LEqual (_T_0, Zero))
  10.                     {
  11.                         Store (B1B2(TA00,TA01), Local0)
  12.                         Break
  13.                     }
  14.                     ElseIf (LEqual (_T_0, One))
  15.                     {
  16.                         Store (B1B2(TA20,TA21), Local0)
  17.                         Break
  18.                     }
  19.                     Else
  20.                     {
  21.                         Return (Ones)
  22.                     }

  23.                     Break
  24.                 }

  25.                 Multiply (Local0, 0x02, Local0)
  26.                 If (LNotEqual (Local0, Zero))
  27.                 {
  28.                     Divide (0x0041CDB4, Local0, Local1, Local0)
  29.                     Return (Local0)
  30.                 }
  31.                 Else
  32.                 {
  33.                     Return (Ones)
  34.                 }
  35.             }
  36.             Else
  37.             {
  38.                 Return (Ones)
  39.             }
  40.         }
复制代码




当你复制这个方法到 SSDT-BATT.dsl 时候,编译时会遇到一个错误.(这里我已经将拆分需要的 B1B2,WE1B,WECB,RE1B,RECB 等方法放入 `Scope(\_SB.PCI0.LPCB.EC0)` 域里面)

49, 6084, Object does not exist (ECAV)

看看 ECAV 是哪行调用的.


  1. Name (_T_0, Zero)  // _T_x: Emitted by ASL Compiler
  2.             If (ECAV ())
  3.             {
复制代码



这个是一个判断语句内嵌了一个方法的调用,初步判断 ECAV 就是一个方法,那么这个方法在哪里呢?回到我们的 DSDT.dsl

搜索 ECAV ,你会在 _SB.PCI0.LPCB.EC0 中发现 ECAV 这个方法,那么我们需要在 SSDT-BATT.dsl 中外部引入这个方法,来达到编译通过的目的.

只需要在 TACH 上方写入 `External(\_SB.PCI0.LPCB.EC0.ECAV, MethodObj)`

再次编译,已通过编译.

我们需要注意的是外部引入的路径与外部引入的类型.

路径在 MaciASL 中,只要你光标移动到这个方法上,程序的左下角会显示当前方法(或变量)所在的路径.

一般 Name ( ABCD , 0X10) 这类的变量引入我们使用 IntObj 类型引入.

而上述的 Method (ECAV, 0, NotSerialized) 这一类,当然是使用 MethodObj 类型引入了.


注意,复制方法过来的时候,需要注意该方法本来是在哪个域里面的,我们在 SSDT-BATT.dsl 也要将其放到哪个域里 Scope()

例如:Method (_BIX, 0, NotSerialized)

这个方法是在 \_SB.PCI0.BAT0 这个域里面,那么我们需要将_BIX 方法放在这个域里面


  1. External(\_SB.PCI0, DeviceObj)
  2. External(\_SB.PCI0.BAT0, DeviceObj)

  3.     Scope(\_SB.PCI0.BAT0)
  4.     {
  5.             Method (_BIX, 0, NotSerialized)  // _BIX: Battery Information Extended
  6.             {
  7.                 If (LNot (^^LPCB.EC0.BATP (Zero)))
  8.                 {
  9.                     Return (NBIX)
  10.                 }

  11.                 If (LEqual (^^LPCB.EC0.GBTT (Zero), 0xFF))
  12.                 {
  13.                     Return (NBIX)
  14.                 }

  15.                 _BIF ()
  16.                 Store (DerefOf (Index (PBIF, Zero)), Index (BIXT, One))
  17.                 Store (DerefOf (Index (PBIF, One)), Index (BIXT, 0x02))
  18.                 Store (DerefOf (Index (PBIF, 0x02)), Index (BIXT, 0x03))
  19.                 Store (DerefOf (Index (PBIF, 0x03)), Index (BIXT, 0x04))
  20.                 Store (DerefOf (Index (PBIF, 0x04)), Index (BIXT, 0x05))
  21.                 Store (DerefOf (Index (PBIF, 0x05)), Index (BIXT, 0x06))
  22.                 Store (DerefOf (Index (PBIF, 0x06)), Index (BIXT, 0x07))
  23.                 Store (DerefOf (Index (PBIF, 0x07)), Index (BIXT, 0x0E))
  24.                 Store (DerefOf (Index (PBIF, 0x08)), Index (BIXT, 0x0F))
  25.                 Store (DerefOf (Index (PBIF, 0x09)), Index (BIXT, 0x10))
  26.                 Store (DerefOf (Index (PBIF, 0x0A)), Index (BIXT, 0x11))
  27.                 Store (DerefOf (Index (PBIF, 0x0B)), Index (BIXT, 0x12))
  28.                 Store (DerefOf (Index (PBIF, 0x0C)), Index (BIXT, 0x13))
  29.                 If (LEqual (DerefOf (Index (BIXT, One)), One))
  30.                 {
  31.                     Store (Zero, Index (BIXT, One))
  32.                     Store (DerefOf (Index (BIXT, 0x05)), Local0)
  33.                     Multiply (DerefOf (Index (BIXT, 0x02)), Local0, Index (BIXT, 0x02))
  34.                     Multiply (DerefOf (Index (BIXT, 0x03)), Local0, Index (BIXT, 0x03))
  35.                     Multiply (DerefOf (Index (BIXT, 0x06)), Local0, Index (BIXT, 0x06))
  36.                     Multiply (DerefOf (Index (BIXT, 0x07)), Local0, Index (BIXT, 0x07))
  37.                     Multiply (DerefOf (Index (BIXT, 0x0E)), Local0, Index (BIXT, 0x0E))
  38.                     Multiply (DerefOf (Index (BIXT, 0x0F)), Local0, Index (BIXT, 0x0F))
  39.                     Divide (DerefOf (Index (BIXT, 0x02)), 0x03E8, Local0, Index (BIXT, 0x02))
  40.                     Divide (DerefOf (Index (BIXT, 0x03)), 0x03E8, Local0, Index (BIXT, 0x03))
  41.                     Divide (DerefOf (Index (BIXT, 0x06)), 0x03E8, Local0, Index (BIXT, 0x06))
  42.                     Divide (DerefOf (Index (BIXT, 0x07)), 0x03E8, Local0, Index (BIXT, 0x07))
  43.                     Divide (DerefOf (Index (BIXT, 0x0E)), 0x03E8, Local0, Index (BIXT, 0x0E))
  44.                     Divide (DerefOf (Index (BIXT, 0x0F)), 0x03E8, Local0, Index (BIXT, 0x0F))
  45.                 }

  46.                 Store (B1B2(^^LPCB.EC0.B001,^^LPCB.EC0.B002), Index (BIXT, 0x08))
  47.                 Store (0x0001869F, Index (BIXT, 0x09))
  48.                 Return (BIXT)
  49.             }
  50.     }
复制代码




复制了之后,我们还有非常多的错误需要处理


  • 135, 6085, Object not found or not accessible from scope (^^LPCB.EC0.BATP)



代码段: If (LNot (^^LPCB.EC0.BATP (Zero)))

^^LPCB.EC0.BATP 这个方法写法中存在 ^^这两个字符,意思上级的上级域里面的,类似于相对路径, LPCB.EC.BATP 方法,完整路径就是 \_SB.PCI0.LPCB.EC0.BATP,因为这个方法不在我们的 SSDT 里面,故此我们需要外部引入他.在 External 的部分加入 `External(\_SB.PCI0.LPCB.EC0.BATP, MethodObj)`

但是上面的 ^^LPCB.EC0.BATP 这样的调用方法猜测应该是同一 SSDT 或是在 DSDT 中存在才能这样写,如果是外部引入后,我们需要将其改成绝对路径.

将 `^^LPCB.EC0.BATP` 替换成 `\_SB.PCI0.LPCB.EC0.BATP`.

  • 140, 6084, Object does not exist (NBIX)


代码段:Return (NBIX)

这个返回值应该是一个变量,我们看看 DSDT 下他是如何定义的.


  1. Name (NBIX, Package (0x14)
  2.             {
  3.                 Zero,
  4.                 Zero,
  5.                 0xFFFFFFFF,
  6.                 0xFFFFFFFF,
  7.                 One,
  8.                 0xFFFFFFFF,
  9.                 0xFFFFFFFF,
  10.                 0xFFFFFFFF,
  11.                 Zero,
  12.                 0xFFFFFFFF,
  13.                 0xFFFFFFFF,
  14.                 0xFFFFFFFF,
  15.                 0xFFFFFFFF,
  16.                 0xFFFFFFFF,
  17.                 0xFFFFFFFF,
  18.                 0xFFFFFFFF,
  19.                 "",
  20.                 "",
  21.                 "",
  22.                 ""
  23.             })
复制代码



Name (NBIX, Package (0x14)  它是一个对象集,对象集引入的类型应当是 PkgObj

在头部外部引入部分加入  `External(\_SB.PCI0.BAT0.NBIX, PkgObj)`

剩下错误用同类的方法修补

最终复制完整个 SSDT-BATT.dsl 是这样的: (由于字数限制问题,例子可以查看上楼附件中的 SSDT-BATT-VM510LI.dsl)


好了,以上 SSDT 编译已经通过,那么我们进行最后一步,将上述复制过来的 Method 一一的重命名,使得原有的 Method 失效,这样我们注入的 SSDT 的新 Method 才能生效.

我们需要重命名的 Method 有


  1. - Method (TACH, 1, Serialized)
  2. - Method (_BIX, 0, NotSerialized)
  3. - Method (BIFA, 0, NotSerialized)
  4. - Method (SMBR, 3, Serialized)
  5. - Method (ECSB, 7, NotSerialized)
  6. - Method (SMBW, 5, Serialized)
复制代码



在 config.plist 中编写补丁 ACPI > DSDT > Patches


  1. # TACH
  2. Comment: change Method(TACH,1,N) to XACH, optionally pair with SSDT-BATT-VM510LI.aml
  3. Find:14 40 06 54 41 43 48 09
  4. Replace:14 40 06 58 41 43 48 09

  5. # _BIX
  6. Comment: change Method(_BIX,0,N) to XBIX, optionally pair with SSDT-BATT-VM510LI.aml
  7. Find:14 49 26 5F 42 49 58 00
  8. Replace:14 49 26 58 42 49 58 00

  9. # BIFA
  10. Comment: change Method(BIFA,0,N) to XIFA, optionally pair with SSDT-BATT-VM510LI.aml
  11. Find:14 27 42 49 46 41 00
  12. Replace:14 27 58 49 46 41 00

  13. # SMBR
  14. Comment: change Method(SMBR,3,N) to XMBR, optionally pair with SSDT-BATT-VM510LI.aml
  15. Find:14 4B 13 53 4D 42 52 0B
  16. Replace:14 4B 13 58 4D 42 52 0B

  17. # ECSB
  18. Comment: change Method(ECSB,7,N) to XCSB, optionally pair with SSDT-BATT-VM510LI.aml
  19. Find:14 4F 1A 45 43 53 42 07
  20. Replace:14 4F 1A 58 43 53 42 07

  21. # SMBW
  22. Comment: change Method(SMBW,5,N) to XMBW, optionally pair with SSDT-BATT-VM510LI.aml
  23. Find:14 45 10 53 4D 42 57 0D
  24. Replace:14 45 10 58 4D 42 57 0D
复制代码




提示,不放心自己找的代码,可以拿个从 Ubuntu 提取未修改过的 DSDT.aml, 用 Hex Fiend 来替换下,再反编译看看,反编译后无需修改,直接搜索我们修改的变量名,看是否已经改成 X 开头.



注入显卡 ID



  • 将 GFX 更名为 IGPU
  • 放入 SSDT-IGPU.aml 至 Clover > ACPI > patched



未完下楼续










点评

gujiangjiang  电池修改需要更改EC Field的值为其他值,这样才能覆盖,不然会出现ACPI Error。  发表于 2017-4-30 19:13 IP属地江苏

Rank: 5Rank: 5Rank: 5

UID
633916
帖子
538
PB币
621
贡献
0
技术
0
活跃
601
发表于 2017-2-27 11:58:19 IP属地广东 |显示全部楼层
本帖最后由 neroxps 于 2017-2-28 20:54 编辑

屏蔽独立显卡



首先复习一下屏蔽独立显卡的方法:

引用自:[屏蔽双显卡笔记本的独显](https://www.firewolf.science/2015/05/%E5%B1%8F%E8%94%BD%E5%8F%8C%E6%98%BE%E5%8D%A1%E7%AC%94%E8%AE%B0%E6%9C%AC%E7%9A%84%E7%8B%AC%E6%98%BE/)

我们的目标非常简单。通常,在SSDT里,笔记本给我们提供了一个 _OFF 方法,我们可以通过调用这个方法,来切段独显的供电。最最简单的方法,就是在 相应的_INI方法里,调用_OFF方法。需要注意,这个_OFF方法,还可能会在DSDT里,或者可能会有不同的名字(如:GPOF、OPOF、_PS3,等等)。

某些_OFF方法的实现,会由于它包含了对EC(Embedded Controller)的依赖,而使得它不能在_INI方法里被调用。对于这样的情况,整个_OFF方法或者它的一部分代码,需要被移动到_REG方法里,以延迟执行(当_REG方法接收的参数Arg0 == 3 且 Arg1==1时,它会在_INI方法之后被执行)(详见ACPI规范)。对于一些情况,在_REG方法里调用_OFF的时机太迟了,从而导致要么屏蔽独显失败,要么系统五国。对于这样的情况,修改_OFF方法,移除它对于EC的依赖,将变得必要。之后,我们就可以在_INI里调用它(移除了对EC的依赖的_OFF)。同时,在_OFF里移除的代码,需要加到_REG里去。这样,虽然EC关联的代码在后(_INI后)执行(因为代码加到了_REG里,所以后执行),但却能达到更好的效果。贴子提供的例子,就是这种情况。

我是根据上面的方法来屏蔽我华硕 VM510LI 的 AMD 显卡的,很不幸的是,我的 _OFF 也包含了对 EC 的依赖,故此我在 hotpatch 当中,我并不能单纯的使用 SSDT-Disable_DGPU.aml 来禁用独立显卡.

那么该如何使用 hotpatch 方法来屏蔽我们的独立显卡呢?


于是我扒到了这个帖子:https://www.tonymacx86.com/threads/guide-disabling-discrete-graphics-in-dual-gpu-laptops.163772/page-55#post-1232166

帖子提供了一个例子:https://raw.githubusercontent.com/RehabMan/Lenovo-Z50/master/hotpatch/SSDT-NVDA.dsl

仔细查看例子中的代码会发现和上述屏蔽独立显卡不同的地方.


  1. External(_SB.PCI0, DeviceObj)
  2.     Scope(_SB.PCI0)
  3.     {
  4.         Device(RMD2)
  5.         {
  6.             Name(_HID, "RMD20000")
  7.             Method(_INI)
  8.             {
  9.                If (CondRefOf(\_SB.PCI0.RP05.PEGP._OFF)) { \_SB.PCI0.RP05.PEGP._OFF() }
  10.             }
  11.         }
复制代码




看上述的代码段,他会重新定义一个设备,这个设备叫 RMD20000,然后这个设备有一个 INI 方法,里面就是调用 _OFF, 关闭显卡的系统方法.

那么,其实关闭显卡并不一定要在显卡启动的 INI 方法中运行 OFF 切断显卡电源,我估计是 PCI0 的设备是统一时间初始化的,其他设备的 INI 也一样可以将显卡电源关闭.

而我 _OFF 方法中存在一个 SGOF 的方法,这个方法里面调用了 EC0 的代码,那么需要将他去掉,故此我需要用重命名代替的方法,将原来的 SGOF 方法用重命名方法禁用掉,然后再用 SSDT 注入我们修改的 SGOF 方法, 由于 SGOF 方法中的 EC 相关的代码需要在 _REG 中执行,故此我们也需要将原有的 _REG 方法重命名禁用掉,也在 SSDT 中写入我们的 _REG 方法.

依然老方法,我不会写 SSDT, 但是我会抄.用上述的 SSDT-NVDA.dsl 来改成我们自己的 禁用显卡 SSDT.

最终写出来的 SSDT 应该就是这样


  1. // SSDT-DAMD: Disable AMD
  2. DefinitionBlock ("", "SSDT", 2, "hack", "DAMD", 0)
  3. {
  4.     External(_SB.PCI0, DeviceObj)
  5.     External(\_SB.PCI0.RP05.PEGP._OFF,MethodObj)
  6.     External (HLRS, FieldUnitObj)
  7.     External (PWEN, FieldUnitObj)
  8.     Scope(_SB.PCI0)
  9.     {
  10.         Device(RMD2)
  11.         {
  12.             Name(_HID, "RMD20000")
  13.             Method(_INI)
  14.             {
  15.                If (CondRefOf(\_SB.PCI0.RP05.PEGP._OFF)) { \_SB.PCI0.RP05.PEGP._OFF() }
  16.             }
  17.         }
  18.         
  19.         External(RP05, DeviceObj)
  20.         Scope(RP05)
  21.         {
  22.             External(PEGP, DeviceObj)
  23.             Scope(PEGP)
  24.             {
  25.                 External(CCHK, MethodObj)
  26.                 External(ONOF, IntObj)
  27.                 External(LCTL,IntObj)
  28.                 External(ELCT, IntObj)
  29.                 External(SVID, IntObj)
  30.                 External(HVID, IntObj)
  31.                 External(SDID, IntObj)
  32.                 External(HDID, IntObj)
  33.                 External(LNKD, IntObj)
  34.                 External(LNKD, IntObj)
  35.                 External(LNKS, IntObj)
  36.                 External(SGPO, MethodObj)
  37.                 Method (SGOF, 0, Serialized)
  38.                 {
  39.                     If (LEqual (CCHK (Zero), Zero))
  40.                     {
  41.                         Return (Zero)
  42.                     }

  43.                     Store (Zero, ONOF)
  44.                     //Store (\_SB.PCI0.LPCB.EC0.RRAM (0x0521), Local0)
  45.                     //And (Local0, 0xCF, Local0)
  46.                     //\_SB.PCI0.LPCB.EC0.WRAM (0x0521, Local0)
  47.                     //\_SB.PCI0.LPCB.EC0.WRAM (0x0520, 0x91)
  48.                     //\_SB.PCI0.LPCB.EC0.WRAM (0x03A4, Zero)
  49.                     //\_SB.PCI0.LPCB.EC0.WRAM (0x03A5, Zero)
  50.                     Store (LCTL, ELCT)
  51.                     Store (SVID, HVID)
  52.                     Store (SDID, HDID)
  53.                     Store (One, LNKD)
  54.                     While (LNotEqual (LNKS, Zero))
  55.                     {
  56.                         Sleep (One)
  57.                     }

  58.                     SGPO (HLRS, One)
  59.                     SGPO (PWEN, Zero)
  60.                     Return (Zero)
  61.                 }
  62.             }
  63.         }
  64.         
  65.         External(LPCB, DeviceObj)
  66.         Scope(LPCB)
  67.         {
  68.             External(EC0, DeviceObj)
  69.             Scope(EC0)
  70.             {
  71.                 External(ECFL, IntObj)
  72.                 External(RRAM, MethodObj)
  73.                 External(WRAM, MethodObj)
  74.                 Method (_REG, 2, NotSerialized)  // _REG: Region Availability
  75.                 {
  76.                     If (LEqual (Arg0, 0x03))
  77.                     {
  78.                         Store (Arg1, ECFL)
  79.                     }
  80.                     
  81.                     If (LAnd(LEqual(Arg0,3),LEqual(Arg1,1)))
  82.                     {
  83.                         Store (\_SB.PCI0.LPCB.EC0.RRAM (0x0521), Local0)
  84.                         And (Local0, 0xCF, Local0)
  85.                         \_SB.PCI0.LPCB.EC0.WRAM (0x0521, Local0)
  86.                         \_SB.PCI0.LPCB.EC0.WRAM (0x0520, 0x91)
  87.                         \_SB.PCI0.LPCB.EC0.WRAM (0x03A4, Zero)
  88.                         \_SB.PCI0.LPCB.EC0.WRAM (0x03A5, Zero)
  89.                     }
  90.                 }
  91.             }
  92.         }
  93.     }
  94. }
复制代码


然后我们需要重命名的就是两个方法,一个 SGOF, 和 _REG.

在 Clover > ACPI > DSDT > Patches 添加如下


  1. # SGOF
  2. Comment:change Method(SGOF,0,Serialized) to XGOF, optionally pair with SSDT-DAMD-VM510LI.aml
  3. Find:53474F46 08
  4. Replace:58474F46 08

  5. # _REG
  6. Comment:change Method(_REG,0,Serialized) to XREG, optionally pair with SSDT-DAMD-VM510LI.aml
  7. Find:5F 52 45 47 02
  8. Replace:58 52 45 47 02
复制代码





变频\声卡 CC 配置\USB 遮蔽器



这些在论坛都有介绍,我就不再论述,只需放入 SSDT 即可.




测试



全部修改后,到最重要一步,测试修改的 hotpatch 是否可用.

还挺幸运的,一直写下来的笔记,就 FN 因为完全无脑抄袭没有注意自己的 Q0E 和 Q0F 是在 \_SB.PCI0.LPCB.EC0 设备里面,我没把他们放到这个 Scope (域) 里面,故此不生效.



注入声卡 ID



这个非常简单,只需要放入SSDT-HDAU.aml 和 SSDT-HDEF.aml 到 Clover > ACPI > patched

但是需要注意自己的 DSDT 有没有定义 HDEF 设备,如果没有,打开 SSDT-HDEF.dsl 将以下注释去掉.

  1. // Note: If your ACPI set (DSDT+SSDTs) does not define HDEF (or AZAL)
  2.     // add this Device definition (by uncommenting it)
  3.     //
  4.     //Device(_SB.PCI0.HDEF)
  5.     //{
  6.     //    Name(_ADR, 0x001b0000)
  7.     //    Name(_PRW, Package() { 0x0d, 0x05 }) // may need tweaking (or not needed)
  8.     //}
复制代码


无需修改 ID,我们只需在 SSDT-Config.aml 的 Name(AUDL, Ones)  定义我们注入的 ID 即可,例如我的声卡 ID 是4,那么我就修改 Name(AUDL, 4)。(关于SSDT-Config.aml 更多的参数细节,下一章节会说到。



SSDT-Config 说明



这个漏了说,而且这个是 Hotpatch 必用的 SSDT,因为里面包含了一些配置。

首先我们来看看 SSDT-Config 有些啥?

  1. // configuration data for other SSDTs in this pack

  2. DefinitionBlock("", "SSDT", 2, "hack", "RMCF", 0)
  3. {
  4.     Device(RMCF)
  5.     {
  6.         Name(_ADR, 0)   // do not remove

  7.         Method(HELP)
  8.         {
  9.             Store("TYPE indicates type of the computer. 0: desktop, 1: laptop", Debug)
  10.             Store("HIGH selects display type. 1: high resolution, 2: low resolution", Debug)
  11.             Store("DPTS for laptops only. 1: enables/disables DGPU in _WAK/_PTS", Debug)
  12.             Store("SHUT enables shutdown fix. 1: disables _PTS code when Arg0==5", Debug)
  13.             Store("AUDL indicates audio layout-id for patched AppleHDA. Ones: no injection", Debug)
  14.             Store("BKLT indicates the type of backlight control. 0: IntelBacklight, 1: AppleBacklight", Debug)
  15.             Store("LMAX indicates max for IGPU PWM backlight. Ones: Use default, other values must match framebuffer", Debug)
  16.         }

  17.         // TYPE: Indicates the type of computer... desktop or laptop
  18.         //
  19.         //  0: desktop
  20.         //  0: 台式机
  21.         //  1: laptop
  22.         //  1: 笔记本
  23.         Name(TYPE, 1)

  24.         // HIGH: High resolution/low resolution selection.  Affects IGPU injection.
  25.         // HIGH: 高分辨率/低分辨率选择。 影响IGPU注入。
  26.         // For 1600x900+ on Sandy/Ivy, use 1
  27.         // 对于1600x900 +在Sandy / Ivy,请使用1
  28.         // For UHD/QHD+ on Haswell/Broadwell, use 1
  29.         // 对于Haswell / Broadwell的UHD / QHD +,请使用1
  30.         // Others (low resolution), use 0
  31.         // 其他(低分辨率),使用0
  32.         Name(HIGH, 0)

  33.         // DPTS: For laptops only: set to 1 if you want to enable and
  34.         // DPTS:仅适用于笔记本电脑:如果要启用和,请设置为1
  35.         //  disable the DGPU _PTS and _WAK.
  36.         //  禁用DGPU _PTS和_WAK。
  37.         //  0: does not manipulate the DGPU in _WAK and _PTS
  38.         //  0:不操作_WAK和_PTS中的DGPU
  39.         //  1: disables the DGPU in _WAK and enables it in _PTS
  40.         //  1:禁用_WAK中的DGPU,并在_PTS中启用它
  41.         Name(DPTS, 0)

  42.         // SHUT: Shutdown fix, disable _PTS code when Arg0==5 (shutdown)
  43.         // SHUT:关闭修复,当Arg0 == 5(关闭)时禁用_PTS代码,
  44.         //  0: does not affect _PTS behavior during shutdown
  45.         //  0:在关闭期间不影响_PTS行为
  46.         //  1: disables _PTS code during shutdown
  47.         //  1:在关闭期间禁用_PTS代码
  48.         Name(SHUT, 0)

  49.         // AUDL: Audio Layout
  50.         // AUDL:音频布局
  51.         // The value here will be used to inject layout-id for HDEF and HDAU
  52.         // 这里的值将用于注入HDEF和HDAU的layout-id
  53.         // If set to Ones, no audio injection will be done.
  54.         // 如果设置为Ones,则不会进行音频插入。
  55.         Name(AUDL, Ones)

  56.         // BKLT: Backlight control type
  57.         // BKLT:背光控制类型
  58.         // 0: Using IntelBacklight.kext
  59.         // 0:使用IntelBacklight.kext
  60.         // 1: Using AppleBacklight.kext + AppleBacklightInjector.kext
  61.         // 1:使用AppleBacklight.kext + AppleBacklightInjector.kext
  62.         Name(BKLT, 0)

  63.         // LMAX: Backlight PWM MAX.  Must match framebuffer in use.
  64.         // LMAX:背光PWM最大值。 必须匹配使用中的帧缓冲区。
  65.         // Ones: Default will be used (0x710 for Ivy/Sandy, 0xad9 for Haswell/Broadwell)
  66.         // Ones:将使用默认(Ivy / Sandy 的默认值是 0x710,Haswell / Broadwell 的默认值是 0xad9)
  67.         // Other values: must match framebuffer
  68.         // 其他值:必须与framebuffer相匹配
  69.         Name(LMAX, Ones)
  70.     }
  71. }
  72. //EOF
复制代码



上面 RM 都注释了,我以 Google 翻译过来,方便理解。

  • 第一个值,TYPE 从 SSDT-IGPU 调用,影响显卡 ID 的注入。查看了下代码,好像是区分是否注入高分屏 ID 有关。
  • 第二个值,HIGH 从 SSDT-IGPU 调用,影响点卡 ID 的注入。当 TYPE 设置成笔记本才生效。
  • 第三个值,DPTS 从 SSDT-PTSWAK 调用,这个 SSDT 是重写了睡眠和唤醒的方法,加入了一些我们补丁需要用到的代码,这里设置 1 则会在睡眠的时候开启显卡,唤醒后关闭显卡。
  • 第四个值,SHUT 从 SSDT-PTSWAK 调用,这个 SSDT 功能同上,这里设置 1 则会在关机的时候禁用 _PTS,和 Shutdown fix 同理。
  • 第五个值,AUDL 从 SSDT-HDAU 和 SSDT-HDEF 调用,这两个 SSDT 前者负责注入声卡 ID,后者则负责注入 HDMI 声卡 ID,而这个值就是控制两个 SSDT 注入声卡的行为,如果写 Ones 则什么都不注入,如果写 3,则声卡的 layout-id 则为 3。
  • 第六个值,BKLT 从 SSDT-PNLF 调用,这个 SSDT 看名字大家应该都很熟悉,就是加入 PNLF 设备,用来启用我们的笔记本亮度调节驱动的,而这个值是控制亮度调节的驱动是用哪一种,0 是使用 IntelBacklight.kext,1 是使用 AppleBacklight.kext + AppleBacklightInjector.kext。
  • 第七个值,LMAX 从 SSDT-PNLF 调用,这个 SSDT 同上,这个值是设置背光的 PWM 最大值,Ones 是使用默认值,Ivy / Sandy 的默认值是 0x710,Haswell / Broadwell 的默认值是 0xad9,你也可以设置其他值,但是这个值必须与 framebuffer 相匹配。






参考文章



External()用法

OS-X-Clover-Laptop-Config

HP-ProBook-4x30s-DSDT-Patch

Guide Using Clover to "hotpatch" ACPI


帖子写的真辛苦~版主们审核也累了~在论坛编辑有可能有很多地方乱掉,例如代码的一些格式等。

我这个笔记本来写在博客上,如果发现论坛上有什么不对劲的,可以上我博客看,博客里面应该都是没问题的,并且日后有什么发现,我第一时间也会写在博客上记录下来。

https://blog.neroxps.cn/blog/macOS/Hotpatch.html


附件: 你需要登录才可以下载或查看附件。没有帐号?注册

点评

mrmg  超级强大,  发表于 2017-5-31 09:34 IP属地北京
6

查看全部评分

Rank: 9

UID
750326
帖子
4537
PB币
3278
贡献
0
技术
102
活跃
2894
发表于 2017-2-27 19:56:36 IP属地四川 |显示全部楼层
这个必须绑定

Rank: 2Rank: 2

UID
1588037
帖子
434
PB币
37
贡献
0
技术
0
活跃
603
发表于 2017-2-27 20:03:50 IP属地北京 |显示全部楼层
技术贴,收藏了。

Rank: 9

UID
1014939
帖子
1489
PB币
617
贡献
0
技术
212
活跃
1696

十周年 8周年庆典勋章

发表于 2017-2-27 20:19:04 IP属地江西 |显示全部楼层
技术贴,学习中

Rank: 2Rank: 2

UID
4267194
帖子
353
PB币
356
贡献
0
技术
90
活跃
1911
发表于 2017-2-27 20:32:17 IP属地甘肃 |显示全部楼层
收藏学习……

Rank: 5Rank: 5Rank: 5

UID
3783511
帖子
758
PB币
0
贡献
0
技术
2
活跃
1294
发表于 2017-2-28 10:54:55 IP属地江苏 |显示全部楼层
如果能用,纯属巧合哈

Rank: 5Rank: 5Rank: 5

UID
633916
帖子
538
PB币
621
贡献
0
技术
0
活跃
601
发表于 2017-2-28 11:38:29 IP属地广东 |显示全部楼层
豪客大人 发表于 2017-2-28 10:54
如果能用,纯属巧合哈

因为当时不清楚自己摸索写的fn hotpatch 能不能正常使用,后来发现是可以的。就是没注意将这个fn补丁的 _Q0E 和 _Q0F 丢到 EC0的域里面。

Rank: 5Rank: 5Rank: 5

UID
633916
帖子
538
PB币
621
贡献
0
技术
0
活跃
601
发表于 2017-2-28 12:05:46 IP属地广东 |显示全部楼层
本帖最后由 neroxps 于 2017-2-28 21:02 编辑

更新了下二楼三楼的排版,版主审核辛苦了~

Rank: 5Rank: 5Rank: 5

UID
4555068
帖子
673
PB币
126
贡献
0
技术
0
活跃
861
发表于 2017-3-10 18:32:51 IP属地海南 |显示全部楼层
这么好的贴为什么没人顶

无尽的折腾才是生活中的乐趣

Rank: 11Rank: 11Rank: 11

UID
2043294
帖子
5307
PB币
1030
贡献
0
技术
156
活跃
3174

7周年庆典勋章 8周年庆典勋章 我是大学生!

发表于 2017-3-10 18:57:25 IP属地江苏 |显示全部楼层
我的XPS也是用的hotpatch,可以忽略BIOS更新带来的影响, 我的惠普电脑因为要patch电源,所以暂时还处于无解的状态下,过来学习一下,争取完善

Rank: 7Rank: 7Rank: 7

UID
872987
帖子
1915
PB币
514
贡献
0
技术
5
活跃
2897
发表于 2017-3-10 21:16:52 IP属地四川 |显示全部楼层
技术贴收藏学习~~

Rank: 2Rank: 2

UID
891915
帖子
275
PB币
27
贡献
0
技术
0
活跃
784
发表于 2017-3-10 21:20:00 IP属地湖北 |显示全部楼层
看不懂现在

Rank: 5Rank: 5Rank: 5

UID
633916
帖子
538
PB币
621
贡献
0
技术
0
活跃
601
发表于 2017-3-10 21:55:52 IP属地广东 |显示全部楼层
YANGXB8 发表于 2017-3-10 21:20
看不懂现在

没关系,研究一下 你会发现非常有趣。

Rank: 2Rank: 2

UID
891915
帖子
275
PB币
27
贡献
0
技术
0
活跃
784
发表于 2017-3-10 22:04:05 IP属地湖北 |显示全部楼层
neroxps 发表于 2017-3-10 21:55
没关系,研究一下 你会发现非常有趣。

现在想降频

Rank: 5Rank: 5Rank: 5

UID
370593
帖子
715
PB币
628
贡献
0
技术
58
活跃
413
发表于 2017-3-10 23:31:32 IP属地四川 |显示全部楼层
看不懂,但支持

感觉和patch DSDT殊途同归,一个放在DSDT里面,一个放在SSDT里面,感觉折腾DSDT更方便

Rank: 5Rank: 5Rank: 5

UID
633916
帖子
538
PB币
621
贡献
0
技术
0
活跃
601
发表于 2017-3-11 07:28:32 IP属地广东 |显示全部楼层
Redecor 发表于 2017-3-10 23:31
看不懂,但支持

感觉和patch DSDT殊途同归,一个放在DSDT里面,一个放在SSDT里面,感觉折腾DSDT更方便

那是当然的,patch dsdt 是最高效而且最简单的方法。hotpathch是为了将补丁模块化。

例如方便调试:注入debug的ssdt的话,就可以配合acpidebug调试acpi的变量状态等。

头像被屏蔽

Rank: 2Rank: 2

UID
2771423
帖子
148
PB币
0
贡献
0
技术
0
活跃
391
发表于 2017-3-11 13:38:51 IP属地浙江 |显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽

无尽的折腾才是生活中的乐趣

Rank: 11Rank: 11Rank: 11

UID
2043294
帖子
5307
PB币
1030
贡献
0
技术
156
活跃
3174

7周年庆典勋章 8周年庆典勋章 我是大学生!

发表于 2017-3-11 14:07:53 IP属地江苏 |显示全部楼层
电池还是不行。。。我的EC下面好乱,跟你的不一样,尤其是偏移量那里,完全看不懂。。。
回顶部
Copyright (C) 2005-2024 pcbeta.com, All rights reserved
Powered by Discuz!  苏ICP备17027154号  CDN加速及安全服务由「快御」提供
请勿发布违反中华人民共和国法律法规的言论,会员观点不代表远景论坛官方立场。
远景在线 | 远景论坛 | 苹果论坛 | Win11论坛 | Win10论坛 | Win8论坛 | Win7论坛 | WP论坛 | Office论坛