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 机器语言’ 文件 (.aml) 或十六进制表格 (.hex)。要将文件合并到您的 Arch 安装中,您需要获取已编译的 .aml 文件 — 无论是自己编译还是信任互联网上的陌生人,都由您自行决定。如果您确实从万维网上下载文件,它很可能是一个压缩的 .asl 文件。因此,您需要解压缩并编译它。这样做的好处是您不必自己研究特定的代码修复。
与您使用相同型号笔记本电脑的 Arch 用户:少数中的少数中的少数。尝试浏览其他发行版/Linux 论坛,寻找关于相同型号的讨论。他们很可能遇到相同的问题,并且要么是因为他们人数众多,要么是因为他们精通技术 — 那里有人已经制作了可用的 DSDT,甚至可能提供预编译版本(同样,风险自负)。搜索引擎是您最好的工具。尝试保持简短:“型号名称” + “dsdt” 可能会产生结果。
自行重新编译
在这项工作中,您最好的资源将是ACPI 规范主页和Linux ACPI 项目[死链 2023-09-16 ⓘ],它取代了 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 头文件以插入内核源代码。如果没有错误且没有警告,您应该可以继续了。
使用修改后的代码
至少有两种方法可以使用自定义 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 软件包为真)。有关详细信息,请参阅 [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 归档。例如,使用 Systemd-boot,/boot/loader/entries/arch.conf
可能如下所示
title Arch Linux linux /vmlinuz-linux initrd /acpi_override initrd /initramfs-linux.img options root=PARTUUID=ec9d5998-a9db-4bd8-8ea0-35a45df04701 resume=PARTUUID=58d0aa86-d39b-4fe1-81cf-45e7add275a0 ...
现在剩下要做的就是重启并验证结果。
编译进内核
您需要熟悉编译您自己的内核。最直接的方法是使用“传统”方法。编译 DSDT 后,iasl 会生成两个文件:dsdt.hex
和 dsdt.aml
。
使用 menuconfig
- 禁用 “仅选择不需要编译时外部固件的驱动程序”。位于 “Device Drivers -> Generic Driver Options” 中。
- 启用 “Include Custom DSDT” 并指定您的修复后的 DSDT 文件的绝对路径(
dsdt.hex
,而不是dsdt.aml
)。位于 “Power management and ACPI options -> ACPI (Advanced Configuration and Power Interface) Support” 中。
使用 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)