DSDT

出自 ArchWiki

DSDT (Differentiated System Description Table,差异化系统描述表) 是 ACPI 规范的一部分。它提供关于给定系统中支持的电源事件的信息。ACPI 表格由制造商在固件中提供。一个常见的 Linux 问题是缺少 ACPI 功能,例如:风扇不转动,合上盖子时屏幕不关闭等等。这可能是由于 DSDT 专门为 Windows 而制作,可以在安装后进行修补。本文的目标是分析和重建有故障的 DSDT,以便内核可以覆盖默认的 DSDT。

基本上,DSDT 表格是在 ACPI(电源管理)事件上运行的代码。

注意: Linux ACPI[死链 2023-09-16 ⓘ] 项目的目标是让 Linux 能够在未修改的固件上工作。如果您仍然发现这种类型的权宜之计在现代内核上是必要的,那么您应该考虑提交错误报告

开始之前

硬件制造商可能已经发布了更新的固件,其中修复了与 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"
提示: 虽然不推荐,但您可以尝试 “Linux”。

出于好奇,您可以按照以下步骤提取您的 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 头文件以插入内核源代码。如果没有错误且没有警告,您应该可以继续了。

使用修改后的代码

警告: 每次 BIOS 更新后,您都需要再次修复 DSDT 并重复这些步骤!

至少有两种方法可以使用自定义 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.hexdsdt.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)

参见