DSDT
DSDT(Differentiated System Description Table,差异化系统描述表)是ACPI规范的一部分。它提供了关于给定系统支持的电源事件的信息。ACPI表由制造商通过固件提供。Linux的一个常见问题是缺少ACPI功能,例如:风扇不转、合上盖子屏幕不关闭等。这可能源于DSDT是专门为Windows设计的,可以在安装后进行修补。本文的目标是分析和重建一个错误的DSDT,以便内核可以覆盖默认的DSDT。
基本上,DSDT表是在ACPI(电源管理)事件上运行的代码。
开始之前
硬件制造商可能已经发布了更新的固件,修复了与ACPI相关的问题。安装更新的固件通常比此方法更可取,因为它避免了重复工作。
此过程确实会干扰您安装中的一些相当基础的代码。您将需要对所做的更改绝对确定。您也可以考虑事先克隆您的磁盘。
即使在尝试自行修复DSDT之前,您也可以尝试几种不同的快捷方式。
让内核报告一个Windows版本
使用变量acpi_os_name作为内核参数。例如:
acpi_os_name="Microsoft Windows NT"
要添加一个已识别的操作系统接口,请使用变量acpi_osi。
acpi_osi="Linux"
要仅使用一个操作系统接口,请添加acpi_osi=!。这会告诉固件只有一个支持的操作系统,因此这通常是推荐的解决方案。
acpi_osi=! acpi_osi="Windows 2022"
要删除一个接口,请在字符串的开头使用感叹号。
acpi_osi="!Windows 2012"
其他要测试的字符串
- "Microsoft Windows XP"
- "Microsoft Windows 2000"
- "Microsoft Windows 2000.1"
- "Microsoft Windows ME: Millennium Edition"
- "Microsoft WindowsME: Millennium Edition"
- "Windows 2001"
- "Windows 2006"
- "Windows 2009"
- "Windows 2012"
- "Windows 2015"
- "Windows 2020"
出于好奇,您可以按照以下步骤提取您的DSDT并搜索.dsl文件。只需grep "Windows"看看有什么结果。
寻找一个已修复的DSDT
DSDT文件最初是用ACPI源语言(.asl/.dsl文件)编写的。使用编译器,它可以生成一个'ACPI Machine Language'文件(.aml)或一个十六进制表(.hex)。要将该文件集成到您的Arch安装中,您需要获取一个已编译的.aml文件 — 这意味着是自行编译还是信任互联网上的陌生人,由您自行决定。如果您确实从互联网上下载了一个文件,它很可能是一个压缩的.asl文件。因此,您需要解压缩它并进行编译。这样做的好处是您不必自己研究特定的代码修复。
拥有与您相同笔记本电脑的Arch用户:他们是极少数中的极少数。尝试浏览其他发行版/Linux论坛,了解关于同一型号的讨论。他们很可能遇到了相同的问题,并且因为用户数量多,或者因为他们技术娴熟 — 有人已经制作了一个可用的DSDT,甚至可能提供预编译的版本(再次声明,使用风险自负)。搜索引擎是您最好的工具。尝试保持简短:'型号名称' + 'dsdt' 可能会产生结果。
自行重新编译
您在此过程中最好的资源将是ACPI Spec主页和Linux ACPI Project[失效链接 2023-09-16—HTTP 404],它取代了acpi.sourceforge.net上发生的活动。简而言之,您可以使用Intel的ASL编译器将系统的DSDT表转换为源代码,定位/修复错误,然后重新编译。
您需要安装acpica来修改代码。
原始代码是用什么编译的? 检查您的系统DSDT是使用Intel还是Microsoft编译器编译的。
# dmesg | grep DSDT
ACPI: DSDT 00000000bf7e5000 0A35F (v02 Intel CALPELLA 06040000 INTL 20060912) ACPI: EC: Look up EC in DSDT
如果使用的是Microsoft的编译器,缩写INTL将是MSFT。在示例中,反编译/重新编译DSDT时有5个错误。经过一些谷歌搜索和深入研究ACPI规范后,其中两个很容易修复。三个错误是由于编译器版本不同造成的,而且后来发现,ACPICA在启动时会处理这些问题。内核的ACPICA组件可以处理编译DSDT时出现的大多数微小错误。所以,如果您的系统正常工作,请不要为编译错误而烦恼。
提取二进制ACPI表
# cat /sys/firmware/acpi/tables/DSDT > dsdt.dat
将ACPI表反汇编为.dsl文件
$ iasl -d dsdt.dat
尝试从.dsl文件创建一个十六进制AML表(用C语言)
$ iasl -tc dsdt.dsl
检查创建十六进制AML表时输出的任何错误并修复它们。例如:
dsdt.dsl 6727: Name (_PLD, Buffer (0x10) Error 4105 - Invalid object type for reserved name ^ (found BUFFER, requires Package)
在发生错误的位置(第6727行)修改文件。
(_PLD, Package(1) {Buffer (0x10)
{
...
}})
增加OEM版本。否则,内核将不会应用修改后的ACPI表。例如,在增加OEM版本之前:
DefinitionBlock ("DSDT.aml", "DSDT", 2, "INTEL ", "TEMPLATE", 0x00000000)
增加OEM版本之后:
DefinitionBlock ("DSDT.aml", "DSDT", 2, "INTEL ", "TEMPLATE", 0x00000001)
修复所有错误并增加OEM版本后,再次创建十六进制AML表。
$ iasl -tc dsdt.dsl
您可能想尝试选项-ic,用于C include文件以插入内核源代码。如果没有错误和警告,您就可以开始了。
使用修改后的代码
至少有两种方法可以使用自定义DSDT:
- 创建一个未压缩的CPIO归档,该归档在启动早期由内核加载。
- 将其编译到内核中。
使用mkinitcpio的acpi_override钩子
mkinitcpio提供了一个acpi_override钩子,它会获取在/usr/initcpio/acpi_override/和/etc/initcpio/acpi_override/中找到的所有.aml文件,并将它们放入/kernel/firmware/acpi/目录下的早期未压缩CPIO归档中。这避免了手动创建单独的CPIO归档或更改引导加载程序配置的需要,因为mkinitcpio将未压缩的CPIO归档与主initramfs映像一起打包成一个文件。
首先,创建/etc/initcpio/acpi_override目录并将所有需要的.aml文件复制到其中。例如:
# mkdir /etc/initcpio/acpi_override # cp dsdt.aml /etc/initcpio/acpi_override/
将acpi_override添加到/etc/mkinitcpio.conf中的HOOKS数组。
/etc/mkinitcpio.conf
HOOKS=(... acpi_override)
最后,重新生成initramfs并重新启动。
使用CPIO归档
这种方法的优点是您无需重新编译内核,并且更新内核也不会导致需要重复这些步骤。
此方法要求启用ACPI_TABLE_UPGRADE=y内核配置(对于linux软件包为true)。有关详细信息,请参阅[1]。
首先,创建以下文件夹结构:
$ mkdir -p kernel/firmware/acpi
将已修复的ACPI表复制到刚创建的kernel/firmware/acpi文件夹中,例如:
$ cp dsdt.aml ssdt1.aml kernel/firmware/acpi
在包含新创建的kernel/文件夹的同一目录下运行:
$ find kernel | cpio -H newc --create > acpi_override
这将创建包含已修复ACPI表的CPIO归档。将归档复制到boot目录。
# cp acpi_override /boot
最后,配置引导加载程序以加载您的CPIO归档,例如Microcode#Microcode in a separate initramfs file中的示例。
现在只剩下重新启动并验证结果了。
编译到内核中
您需要熟悉编译自己的内核。最直接的方法是使用“传统”方法。编译DSDT后,iasl会生成两个文件:dsdt.hex和dsdt.aml。
使用menuconfig
- 禁用“仅选择不需要编译时外部固件的驱动程序”。位于“设备驱动程序 -> 通用驱动程序选项”。
- 启用“包含自定义DSDT”并指定已修复DSDT文件的绝对路径(
dsdt.hex,而不是dsdt.aml)。位于“电源管理和ACPI选项 -> ACPI(高级配置和电源接口)支持”。
使用GRUB加载AML
如果您使用GRUB,您可以使用一个更简单的方法。将上面创建的.aml文件复制到您的启动分区。
# cp dsdt_patch.aml /boot
然后在您的GRUB配置中添加以下行:
acpi /dsdt_patch.aml
例如,您可以将此添加到/etc/grub.d/40_custom,不要忘记之后生成您的GRUB配置。
使用dracut加载AML
如果您使用Dracut,您可以简单地将上面创建的.aml文件复制到一个指定的位置。必须创建一个相应的配置文件/etc/dracut.conf.d/acpi-fix.conf:
acpi_override="yes" acpi_table_dir="/usr/local/lib/firmware/acpi"
验证覆盖是否成功
查找确认覆盖的消息,例如:
# dmesg | grep ACPI
[ 0.000000] ACPI: Override [DSDT- A M I], this is unsafe: tainting kernel [ 0.000000] ACPI: DSDT 00000000be9b1190 Logical table override, new table: ffffffff81865af0 [ 0.000000] ACPI: DSDT ffffffff81865af0 0BBA3 (v02 ALASKA A M I 000000F3 INTL 20130517)