前言
这个教程,是基于宪武大神的口述,加上博主的亲身实践并精心整理而成的,且发布已经得到宪武大神的授权,任何其他形式的转载请注明出处!!!教程并不一定适用于所有情况,只是给各位提供一个比较基础的思路。如果中间有任何问题,欢迎反馈给我,好让我及时更新教程。
我为什么要修改
修改这个的意义,实际就是热补丁的意义。尽管我已经在我的另一篇教程里面说过了热补丁的好处,我还是乐意在这里再复述一遍。
热补丁的编辑更加高效。使用热补丁,你不需要去修改其他的无关代码,也不需要你去联合反编译DSDT然后除错,更是大大节省了你的工程量。
热补丁更加安全。如果热补丁导致你的启动出现问题,你只需要还原对应的热补丁修改(删除热补丁)即可,既快捷又方便,并且也无需备份什么。而如果是DSDT,在改动前你必须备份原有DSDT,而且出了问题时排除代码是个很让人头疼的问题。
热补丁管理方便。每个功能可以写一个热补丁,无论是配置文件里还是SSDT,都方便管理与添加;并且由于热补丁的动态注入特性,在部分情况下可以实现直接修改DSDT报错而不能完成的修改。
热补丁与平台无关。由于这一点,有些修改的热补丁可以跨平台使用,大大提高了黑果的移植度以及修改工程量。尤其是,当你发现某些机型的DSDT不能通用但是却具有高度相似的修改时,热补丁的优势将尤其明显(比如潮7000 13寸与14寸,以及潮5000关于触摸板的部分)
基于上述这几点,我们也显然可以看到了电池热补丁的优势:跨平台、易修改、易参考、高度可移植。
阅读预备
正如我一直跟黑果进阶的同学反复强调的那样,热补丁是DSDT的延伸,因此,基于这一点,以下情况,我不推荐您阅读此教程:
- 没有良好的DSDT基础
- 电池尚未用DSDT补丁修改好
在阅读本教程之前,建议先去阅读下这篇帖子:修改dsdt实现电量显示方法(整理修改已有帖子),了解下基础的字节以及补丁工作原理,然后再来阅读下本教程。
原理
电池热补丁的原理,本质就是热补丁的原理以及电池的字节拆分原理,在此我不再赘述,有兴趣的请自己去百度相关教程。不过涉及到一些这二者协调部分的原理,在这里我有必要解释一下:
我们知道,在DSDT的电池补丁里,电池的各种变量,存在一个变量的字节位占用问题,如果将变量字节位搞错,将会导致打补丁后的DSDT无法正常显示电池信息。而热补丁本质就是DSDT的延伸,因此,我们在热补丁中动态修补电池字节数据的时候,也必须保留对原有字节位的占用,而不能随意错位。电池的数据一般存储在一个大的OperationRegion块中。懂热补丁的都知道,显然OperationRegion方法是不允许直接注入的。因此,我们通常想到的就是直接将电池设备改名,重新注入数据。这种方法经过本人测试,存在很大问题,其中之一就是数据无法正确注入修改后的电池数据(OperationRegion)到DSDT中,会报错。另外这样书写的热补丁代码量太大,需要处理的引用与方法交叉十分多。
所幸宪武大神给出了一个折中的方法:新建一个OperationRegion块,在这个新块里动态注入所有的拆分字节数据;同时,对原有的未拆分字节保留空位,从而在保证位移量正确的情况下正确注入并引用新的数据。如此,电池就可以以热补丁的形式注入字节数据并被修改为正确信息。
当然,这种方法也有其弊端在里面:由于二次调用数据,这样的热补丁执行效率会有点低,但是对于现在的机子而言,这个效率的影响微乎其微。
基于这样的一个思路,我们接下来就可以开始制作电池的热补丁。
开始制作
分析补丁
在开始制作之前,我们首先就需要对我们的电池DSDT补丁进行分析,来确定哪些数据是我们接下来需要使用到的。比如以潮7000 13寸的电池热补丁来说,是这样的:
1 | 1. |
看起来这个补丁代码确实很复杂,但是仔细分析下,我们修改这个热补丁,无非需要以下这些数据:
- 电池的设备位置
- 额外添加的方法
- 拆分的字节数据
- 引用修改字节的方法(Method)
通过对于IOReg等的分析,我们得知电池设备为H_EC.BAT0;而对此字节补丁进行分析,我们发现,它实际上修改了这些字节数据:
1 | BML0 → B1B2 (ML00, ML01) |
这些字节数据全部位于H_EC下的ECF2这个OperationRegion中。随后,对这些拆分的字节添加的语句进行分析,我们也找到了我们需要添加的额外方法:RECB、RE1B、B1B2、B1B4
接下来 ,我们前去阅读潮7000 13修改好电池后的DSDT(样本点击这里下载),通过反复查找对比我们前面找到的额外方法,我们可以发现,这些方法在以下这些DSDT方法中出现(也即引用修改字节的方法):
1 | _SB.PCI0.LPCB.H_EC.VPC0下: |
由此,我们确定了我们需要修改的所有地方,接下来我们就需要把这些修改注入到我们的热补丁中。
数据插入
接下来,我们就需要进行插入操作了。打开Maciasl软件(相关下载可在我博客的资源页面获取),新建一个文件,插入以下这段代码,使其声明为一个热补丁文件;然后保存为DSL文本文件(文件名随意起,只要保证以”SSDT-“开头就好了):
1 | DefinitionBlock ("", "SSDT", 2, "hack", "xxxx", 0x00000000) |
这里的XXXX为你前面找到的电池设备名称,比如我的是BAT0,那这里就写为BAT0。
然后,复制DSDT中的电池字节OperationRegion到这个热补丁中,就像这样:
然后,我们将额外添加的方法与**引用修改字节的方法(Method)**同时插入到这个DSDT里面:
注意:在插入的时候,在同一个设备下面的方法一定要放到一块!比如_BIF
与_BST
同为BAT0
设备下面的方法,在插入时就要放到一块。这样做的目的,是为了后面修改时方便修改,减少代码的书写以及使代码层次分明。
添加位置代码
到这里,我们并未完全完成代码的插入。我们需要BIOS知道我们插入的这些方法都是动态注入修补到哪些位置的方法,这需要我们添加位置代码。
比如,比如_BIF
与_BST
同为BAT0
设备下面的方法,而BAT0
位于_SB.PCI0.LPCB.H_EC
。因此,我们需要在 Method (_BIF, 0, NotSerialized)
前插入Scope
位置代码,在_BST
方法结束位置插入结束代码”}”。它看起来的效果应该像这样:
1 | Scope (_SB.PCI0.LPCB.H_EC.BAT0) |
同样地,对于ECF2
这个OperationRegion,它的位置在_SB.PCI0.LPCB.H_EC
,因此,应该像这样在ECF2
下插入位置代码:
1 | Scope (_SB.PCI0.LPCB.H_EC) |
而对于RECB、RE1B、B1B2、B1B4这三个方法,由于其本身就在根设备下,因此不需要再额外添加位置代码,保留原有层级结构即可。
对所有我们刚才插入进来的代码进行位置代码插入,最终修改后,我们可以在左侧的窗格看到类似的层级结构:
在图里我们看到,所有方法,除了OperationRegion外,在层层展开下均能看见,并且位置正确,层级结构不错位;同时进行一下编译,也看不到任何与”}”有关的错误:
添加外部引用
如果以上步骤皆操作正确,那么接下来你所看到的错误,将全部与添加外部引用有关,就像上图你看到的那样。这一部分的步骤主要就是添加外部引用。
首先注意下,我们的位置代码那里,有三个设备被引用,分别是_SB.PCI0.LPCB.H_EC
、_SB.PCI0.LPCB.H_EC.BAT0
和_SB.PCI0.LPCB.H_EC.VPC0
。由于它们以Scope形式引用,必须要有设备声明,因此,我们需要添加这三个设备的外部引用到第2行下面,就像这样:
1 | DefinitionBlock ("", "SSDT", 2, "hack", "BAT0", 0x00000000) |
其中DeviceObj
表示这是一个ACPI设备。
编辑好后,我们再次编译,可以看到相关的报错全都消失了:
接下来,我们根据报错,继续在DSDT里搜索其他的报错代码,并添加相关引用。
比如对于BASC
,我们在DSDT搜索:
可以看到,这是BAT0
下的一个Name
变量,对应IntObj
,添加外部引用如下:
1 | DefinitionBlock ("", "SSDT", 2, "hack", "BAT0", 0x00000000) |
再次编译一下,会发现所有与BASC
相关的报错全部消失:
又比如,_SB.PCI0.LPCB.H_EC
下的ECMT
是Mutex
变量,则对应MutexObj
,添加:
1 | External (_SB_.PCI0.LPCB.H_EC.ECMT, MutexObj) |
B1ST
则是:
1 | External (_SB_.PCI0.LPCB.H_EC.B1ST, FieldUnitObj) |
MAMW
则是:
1 | External (_SB_.PCI0.LPCB.H_EC.MAMW, MethodObj) |
……
通过这一系列外部引用添加,当你最后编译发现不再报错时,外部引用的添加就算结束。
重命名/清空字节
在上面的步骤完成之后,我们实际已经得到了一个基本成型的热补丁,但是这个热补丁到这还尚未修改完成,我们仍然需要两步来完成这个热补丁的修改。
首先,我们要把ECF2
这个字节存放区域更名为一个与原来不一样的名字,比如ECFX
。利用查找替换功能,我们可以很轻松完成这个步骤。
接下来,我们需要把所有不拆分的字节数据段名字去掉,只保留空位。以我的为例,它就像这样:
1 | Scope (_SB.PCI0.LPCB.H_EC) |
这里面的修改有几个要点:
- 只清空不拆分的字节
对于未拆分的字节数据,就需要清空变量名,后面的数据保持不动。
比如:
1 | ACST, 1, |
这一行,清空变量名,就是:
1 | , 1, |
而那些拆分的字节数据,则不要去动,跳过去。
- 删除无拆分的offset块
如果两个offset
块之间,没有任何拆分的字节数据,则这个块可以删除。比如对于我的而言:
1 | ... |
从Offset (0xC6),
到Offset (0xF1)
中间,再也没有任何拆分的字节数据,因此,我们可以抛弃这块的变量,只保留Offset (0xC6)
,修改为:
1 | ... |
这一块修改完成后,进行编译。如无报错,则将文件保存编译为aml文件。至此,我们的电池热补丁制作完成。
添加改名补丁
接下来的过程,就与其他热补丁的改名过程无异了,我们需要生成并在Clover配置文件中添加引用修改字节的方法(需要注入Tgtbridge)。关于如何生成并添加这一补丁,我在我的触摸板教程第二版中有详细描述,不明白的可以点击这里查看参考。对于潮7000 13寸来说,需要添加的是这些改名补丁:
1 | Name: change MHIF to XHIF in VPC0 |
接下来,保存修改后的配置文件,将新配置文件与热补丁放入对应位置,删除DSDT,重启测试。如果修改没有问题,那么电池应该会如在DSDT下一般正常工作了。祝你好运!
本教程所涉及的配置文件、热补丁与电池DSDT打包可以点击这里下载。