积分 215 最后登录 2022-5-18 精华 0 阅读权限 30 主题 49 UID 633916 帖子 538 PB币 621 威望 0 贡献 0 技术 0 活跃 601
UID 633916 帖子 538 PB币 621 贡献 0 技术 0 活跃 601
发表于 2017-2-27 11:55:29
IP属地广东
| 显示全部楼层
本帖最后由 neroxps 于 2017-4-30 19:17 编辑
继续上一楼
电池补丁
方法分析
根据远景论坛的教学贴,我学会了编写自己笔记本的电池电量补丁.
以下是我 华硕 VM510LI 的电量补丁
#Maintained by: Nero for: Laptop Patches
#battery_ASUS-VM510LI.txt
# created by Nero 1/2017
#Create B1B2 Method
into method label B1B2 remove_entry;
into definitionblock code_regex . insert
begin
Method (B1B2, 2, NotSerialized)\n
{\n
Return(Or(Arg0, ShiftLeft(Arg1, 8)))\n
}\n
end;
# utility methods to read/write buffers from/to EC
into method label RE1B parent_label EC0 remove_entry;
into method label RECB parent_label EC0 remove_entry;
into device label EC0 insert
begin
Method (RE1B, 1, NotSerialized)\n
{\n
OperationRegion(ERAM, EmbeddedControl, Arg0, 1)\n
Field(ERAM, ByteAcc, NoLock, Preserve) { BYTE, 8 }\n
Return(BYTE)\n
}\n
Method (RECB, 2, Serialized)\n
{\n
ShiftRight(Arg1, 3, Arg1)\n
Name(TEMP, Buffer(Arg1) { })\n
Add(Arg0, Arg1, Arg1)\n
Store(0, Local0)\n
While (LLess(Arg0, Arg1))\n
{\n
Store(RE1B(Arg0), Index(TEMP, Local0))\n
Increment(Arg0)\n
Increment(Local0)\n
}\n
Return(TEMP)\n
}\n
end;
# utility method to write to EC buffers
into method label WE1B parent_label EC0 remove_entry;
into method label WECB parent_label EC0 remove_entry;
into device label EC0 insert
begin
Method (WE1B, 2, NotSerialized)\n
{\n
OperationRegion(ERAM, EmbeddedControl, Arg0, 1)\n
Field(ERAM, ByteAcc, NoLock, Preserve) { BYTE, 8 }\n
Store(Arg1, BYTE)\n
}\n
Method (WECB, 3, Serialized)\n
{\n
ShiftRight(Arg1, 3, Arg1)\n
Name(TEMP, Buffer(Arg1) { })\n
Store(Arg2, TEMP)\n
Add(Arg0, Arg1, Arg1)\n
Store(0, Local0)\n
While (LLess(Arg0, Arg1))\n
{\n
WE1B(Arg0, DerefOf(Index(TEMP, Local0)))\n
Increment(Arg0)\n
Increment(Local0)\n
}\n
}\n
end;
#Convert 16 bit to 8 bit registers
into device label EC0 code_regex TAH0,\s+16, replace_matched begin TA00,8,TA01,8, end;
into device label EC0 code_regex TAH1,\s+16, replace_matched begin TA20,8,TA21,8, end;
into device label EC0 code_regex B0C3,\s+16, replace_matched begin B001,8,B002,8, end;
into device label EC0 code_regex B0SN,\s+16, replace_matched begin B0S0,8,B0S1,8, end;
into device label EC0 code_regex B1SN,\s+16 replace_matched begin B1S0,8,B1S1,8 end;
into device label EC0 code_regex DT2B,\s+16 replace_matched begin DT01,8,DT02,8 end;
#Fix 16 bit registers
into method label TACH code_regex \(TAH0, replaceall_matched begin (B1B2(TA00,TA01), end;
into method label TACH code_regex \(TAH1, replaceall_matched begin (B1B2(TA20,TA21), end;
into method label _BIX code_regex \^\^LPCB.EC0.B0C3, replaceall_matched begin B1B2(^^LPCB.EC0.B001,^^LPCB.EC0.B002), end;
into method label BIFA code_regex \(B0SN, replaceall_matched begin (B1B2(B0S0,B0S1), end;
into method label BIFA code_regex \(B1SN, replaceall_matched begin (B1B2(B1S0,B1S1), end;
into method label SMBR code_regex \(DT2B, replaceall_matched begin (B1B2(DT01,DT02), end;
into method label SMBW code_regex Store\s\(Arg4,\sDT2B\) replaceall_matched begin Store (ShiftRight(Arg4,8),DT02)\nStore (Arg4,DT01) end;
#fix 256 bit registers
into method label SMBR code_regex Store\s+\((.*),\s+BDAT\) replaceall_matched begin WECB(0x1c,256,%1) end;
into method label SMBW code_regex Store\s+\((.*),\s+BDAT\) replaceall_matched begin WECB(0x1c,256,%1) end;
into method label ECSB code_regex Store\s+\((.*),\s+BDAT\) replaceall_matched begin WECB(0x1c,256,%1) end;
into method label ECSB code_regex Store\s+\((.*),\s+BDA2\) replaceall_matched begin WECB(0x44,256,%1) end;
into method label ECSB code_regex \(BDAT, replaceall_matched begin (RECB(0x1c,256), end;
into method label ECSB code_regex \(BDA2, replaceall_matched begin (RECB(0x44,256), end;
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 方式来修改变量是行不通的,因为例如
//拆分前TAH0,16 Hex: 54 41 48 30 10
//拆分后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 设备拆分后的代码
// battery status patched for Ausu VM510LI
DefinitionBlock ("", "SSDT", 2, "hack", "batt", 0)
{
External(\_SB.PCI0, DeviceObj)
External(\_SB.PCI0.LPCB, DeviceObj)
External(\_SB.PCI0.LPCB.EC0, DeviceObj)
Scope(\_SB.PCI0.LPCB.EC0)
{
// This is an override for battery methods that access EC fields
// larger than 8-bit.
OperationRegion (ECOR, EmbeddedControl, Zero, 0xFF)
Field (ECOR, ByteAcc, Lock, Preserve)
{
//Offset (0x04),
//CMD1, 8,
//...
Offset (0x93),
TA00,8,TA01,8,
TA20,8,TA21,8,
//...
Offset (0xBE),
, 16, //B0TM, 16
, 16, //B0C1, 16,
, 16, //B0C2, 16,
B001,8,B002,8,
//...
Offset (0xF4),
B0S0,8,B0S1,8,
//Offset (0xF8),
//Offset (0xFA),
Offset (0xFC),
B1S0,8,B1S1,8
}
OperationRegion (SMBX, EmbeddedControl, 0x18, 0x28)
Field (SMBX, ByteAcc, NoLock, Preserve)
{
Offset (0x04),
DT01,8,DT02,8
}
}
} 复制代码
其中 `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 添加以下补丁:
Comment:change ECOR to XCOR
Find:45434F52
Replace:58434F52
Comment:change SMBX to XMBX
Find:534D4258
Replace:584D4258 复制代码
将调用了以上变量的方法复制到 SSDT-BATT.dsl
从已经打了电量补丁的 DSDT 中找出上方调用这些变量的方法所在地,不要忘记了补丁中 #fix 256 bit registers 的方法,因为电量补丁中,大于32的变量无需拆分,只需要将调动变量的代码用 WECB 方法与 RECB 方法来更改代替即可.
- Method (TACH, 1, Serialized)
- TA00
- TA01
- TA20
- TA21
- Method (_BIX, 0, NotSerialized)
- B001
- B002
- Method (BIFA, 0, NotSerialized)
- B0S0
- B0S1
- B1S0
- B1S1
- Method (SMBR, 3, Serialized)
- WECB(0x1c,256,Zero)
- WECB(0x1c,256,Zero)
- WECB(0x1c,256,Arg4)
- Store (RECB(0x1c,256), Index (Local0, 0x02))
- Method (ECSB, 7, NotSerialized)
- WECB(0x1c,256,DerefOf (Index (Arg6, One)))
- WECB(0x44,256,DerefOf (Index (Arg6, One)))
- Store (RECB(0x1c,256), Index (Local1, 0x04))
- Store (RECB(0x44,256), Index (Local1, 0x04))
- Method (SMBW, 5, Serialized)
- Store (ShiftRight(Arg4,8),DT02)
- Store (Arg4,DT01) 复制代码
总共发现6个方法,我们将这6个方法一个一个从修不好电量补丁的 DSDT 中复制到 SSDT-BATT.dsl
TACH 方法
Method (TACH, 1, Serialized)
{
Name (_T_0, Zero) // _T_x: Emitted by ASL Compiler
If (ECAV ())
{
While (One)
{
Store (Arg0, _T_0)
If (LEqual (_T_0, Zero))
{
Store (B1B2(TA00,TA01), Local0)
Break
}
ElseIf (LEqual (_T_0, One))
{
Store (B1B2(TA20,TA21), Local0)
Break
}
Else
{
Return (Ones)
}
Break
}
Multiply (Local0, 0x02, Local0)
If (LNotEqual (Local0, Zero))
{
Divide (0x0041CDB4, Local0, Local1, Local0)
Return (Local0)
}
Else
{
Return (Ones)
}
}
Else
{
Return (Ones)
}
} 复制代码
当你复制这个方法到 SSDT-BATT.dsl 时候,编译时会遇到一个错误.(这里我已经将拆分需要的 B1B2,WE1B,WECB,RE1B,RECB 等方法放入 `Scope(\_SB.PCI0.LPCB.EC0)` 域里面)
49, 6084, Object does not exist (ECAV)
看看 ECAV 是哪行调用的.
Name (_T_0, Zero) // _T_x: Emitted by ASL Compiler
If (ECAV ())
{ 复制代码
这个是一个判断语句内嵌了一个方法的调用,初步判断 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 方法放在这个域里面
External(\_SB.PCI0, DeviceObj)
External(\_SB.PCI0.BAT0, DeviceObj)
Scope(\_SB.PCI0.BAT0)
{
Method (_BIX, 0, NotSerialized) // _BIX: Battery Information Extended
{
If (LNot (^^LPCB.EC0.BATP (Zero)))
{
Return (NBIX)
}
If (LEqual (^^LPCB.EC0.GBTT (Zero), 0xFF))
{
Return (NBIX)
}
_BIF ()
Store (DerefOf (Index (PBIF, Zero)), Index (BIXT, One))
Store (DerefOf (Index (PBIF, One)), Index (BIXT, 0x02))
Store (DerefOf (Index (PBIF, 0x02)), Index (BIXT, 0x03))
Store (DerefOf (Index (PBIF, 0x03)), Index (BIXT, 0x04))
Store (DerefOf (Index (PBIF, 0x04)), Index (BIXT, 0x05))
Store (DerefOf (Index (PBIF, 0x05)), Index (BIXT, 0x06))
Store (DerefOf (Index (PBIF, 0x06)), Index (BIXT, 0x07))
Store (DerefOf (Index (PBIF, 0x07)), Index (BIXT, 0x0E))
Store (DerefOf (Index (PBIF, 0x08)), Index (BIXT, 0x0F))
Store (DerefOf (Index (PBIF, 0x09)), Index (BIXT, 0x10))
Store (DerefOf (Index (PBIF, 0x0A)), Index (BIXT, 0x11))
Store (DerefOf (Index (PBIF, 0x0B)), Index (BIXT, 0x12))
Store (DerefOf (Index (PBIF, 0x0C)), Index (BIXT, 0x13))
If (LEqual (DerefOf (Index (BIXT, One)), One))
{
Store (Zero, Index (BIXT, One))
Store (DerefOf (Index (BIXT, 0x05)), Local0)
Multiply (DerefOf (Index (BIXT, 0x02)), Local0, Index (BIXT, 0x02))
Multiply (DerefOf (Index (BIXT, 0x03)), Local0, Index (BIXT, 0x03))
Multiply (DerefOf (Index (BIXT, 0x06)), Local0, Index (BIXT, 0x06))
Multiply (DerefOf (Index (BIXT, 0x07)), Local0, Index (BIXT, 0x07))
Multiply (DerefOf (Index (BIXT, 0x0E)), Local0, Index (BIXT, 0x0E))
Multiply (DerefOf (Index (BIXT, 0x0F)), Local0, Index (BIXT, 0x0F))
Divide (DerefOf (Index (BIXT, 0x02)), 0x03E8, Local0, Index (BIXT, 0x02))
Divide (DerefOf (Index (BIXT, 0x03)), 0x03E8, Local0, Index (BIXT, 0x03))
Divide (DerefOf (Index (BIXT, 0x06)), 0x03E8, Local0, Index (BIXT, 0x06))
Divide (DerefOf (Index (BIXT, 0x07)), 0x03E8, Local0, Index (BIXT, 0x07))
Divide (DerefOf (Index (BIXT, 0x0E)), 0x03E8, Local0, Index (BIXT, 0x0E))
Divide (DerefOf (Index (BIXT, 0x0F)), 0x03E8, Local0, Index (BIXT, 0x0F))
}
Store (B1B2(^^LPCB.EC0.B001,^^LPCB.EC0.B002), Index (BIXT, 0x08))
Store (0x0001869F, Index (BIXT, 0x09))
Return (BIXT)
}
} 复制代码
复制了之后,我们还有非常多的错误需要处理
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 下他是如何定义的.
Name (NBIX, Package (0x14)
{
Zero,
Zero,
0xFFFFFFFF,
0xFFFFFFFF,
One,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
Zero,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
0xFFFFFFFF,
"",
"",
"",
""
}) 复制代码
Name (NBIX, Package (0x14) 它是一个对象集,对象集引入的类型应当是 PkgObj
在头部外部引入部分加入 `External(\_SB.PCI0.BAT0.NBIX, PkgObj)`
剩下错误用同类的方法修补
最终复制完整个 SSDT-BATT.dsl 是这样的: (由于字数限制问题,例子可以查看上楼附件中的 SSDT-BATT-VM510LI.dsl)
好了,以上 SSDT 编译已经通过,那么我们进行最后一步,将上述复制过来的 Method 一一的重命名,使得原有的 Method 失效,这样我们注入的 SSDT 的新 Method 才能生效.
我们需要重命名的 Method 有
- Method (TACH, 1, Serialized)
- Method (_BIX, 0, NotSerialized)
- Method (BIFA, 0, NotSerialized)
- Method (SMBR, 3, Serialized)
- Method (ECSB, 7, NotSerialized)
- Method (SMBW, 5, Serialized) 复制代码
在 config.plist 中编写补丁 ACPI > DSDT > Patches
# TACH
Comment: change Method(TACH,1,N) to XACH, optionally pair with SSDT-BATT-VM510LI.aml
Find:14 40 06 54 41 43 48 09
Replace:14 40 06 58 41 43 48 09
# _BIX
Comment: change Method(_BIX,0,N) to XBIX, optionally pair with SSDT-BATT-VM510LI.aml
Find:14 49 26 5F 42 49 58 00
Replace:14 49 26 58 42 49 58 00
# BIFA
Comment: change Method(BIFA,0,N) to XIFA, optionally pair with SSDT-BATT-VM510LI.aml
Find:14 27 42 49 46 41 00
Replace:14 27 58 49 46 41 00
# SMBR
Comment: change Method(SMBR,3,N) to XMBR, optionally pair with SSDT-BATT-VM510LI.aml
Find:14 4B 13 53 4D 42 52 0B
Replace:14 4B 13 58 4D 42 52 0B
# ECSB
Comment: change Method(ECSB,7,N) to XCSB, optionally pair with SSDT-BATT-VM510LI.aml
Find:14 4F 1A 45 43 53 42 07
Replace:14 4F 1A 58 43 53 42 07
# SMBW
Comment: change Method(SMBW,5,N) to XMBW, optionally pair with SSDT-BATT-VM510LI.aml
Find:14 45 10 53 4D 42 57 0D
Replace:14 45 10 58 4D 42 57 0D 复制代码
提示,不放心自己找的代码,可以拿个从 Ubuntu 提取未修改过的 DSDT.aml, 用 Hex Fiend 来替换下,再反编译看看,反编译后无需修改,直接搜索我们修改的变量名,看是否已经改成 X 开头.
注入显卡 ID
将 GFX 更名为 IGPU 放入 SSDT-IGPU.aml 至 Clover > ACPI > patched
未完下楼续
展开阅读全文​