DSDT - Arch Linux 中文维基

跳至內容

# DSDT

出自 Arch Linux 中文维基
翻譯狀態：

- 本文（或部分內容）譯自 DSDT，最近一次同步於 2025-04-09，若英文版本有所更改，則您可以幫助同步與翻譯更改的內容。
- 您可以在 ArchWiki 的對應頁面找到本文翻譯的原始修訂歷史。
- 本文可能與英文原文存在出入。

相關文章

- ACPI modules
- acpid

DSDT(Differentiated System Description Table)是ACPI規格的一部分。它提供了關於一個給定系統中受支持的電源事件的信息。ACPI表是由製造商在固件裡提供的。通常，Linux遇到的問題是某些ACPI功能的缺失，比如風扇不轉，蓋子合上時屏幕不熄滅等等。這些問題可以歸咎於DSDT是為Windows所定製的。安裝後可以打補丁來修復這些問題。這篇文章的目標是分析並且重建一個有錯誤的DSDT，這樣內核就會略過默認的DSDT。

基本上來說，一個DSDT表是運行在ACPI(電源管理)上的代碼。

注意：Linux ACPI[失效連結 2023-09-16 ⓘ]項目的目標讓Linux工作在未修改的固件上。如果你還是覺得這種方法在現代內核上是必要的，那麼你應該考慮一下報告bug。

## 在你開始之前

硬體製造商可能已經發布了更新的固件，修復了與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 Spec homepage，和Linux ACPI Project[失效連結 2023-09-16 ⓘ]，這些將會替代acpi.sourceforge.net。 簡而言之，你可以使用英特爾的ASL編譯器將你系統的DSDT錶轉換成原始碼，定位並修復錯誤，最後重新編譯。

你將會需要安裝acpica包來修改代碼。 什麼編譯器編譯了原始代碼？ 查看你系統的DSDT使用英特爾的還是微軟的編譯器編譯的：

     # dmesg | grep DSDT

    ACPI: DSDT 00000000bf7e5000 0A35F (v02 Intel  CALPELLA 06040000 INTL 20060912)
    ACPI: EC: Look up EC in DSDT

如果是微軟的編譯器，INTL將會變成MSFT。 在這個例子中，在反編譯/編譯的DSDT時共有五個錯誤，有兩個在谷歌一下和研究ACPI規範之後很容易解決。另外三個是由於使用了不同版本的編譯器。後來你會發現，它們三個會在啟動時被ACPICA處理。內核的ACPICA部分可以處理編譯DSDT時產生的的大部分不重要的錯誤.所以如果你的系統正在按照正常方式運行，請不要為了編譯錯誤煩惱。

1.) 提取ACPI表(作為超級用戶): `# cat /sys/firmware/acpi/tables/DSDT > dsdt.dat`

2.) 反編譯: `iasl -d dsdt.dat`

3.) 重新編譯: `iasl -tc dsdt.dsl`

4.) 檢查錯誤並修復。例如:

    dsdt.dsl   6727:                         Name (_PLD, Buffer (0x10)
    Error    4105 -          Invalid object type for reserved name ^  (found BUFFER, requires Package)

     nano +6727 dsdt.dsl

    (_PLD, Package(1) {Buffer (0x10)...

5.) 增添OEM版本，否則內核不會應用修改過的ACPI表。例如在修改前:

    DefinitionBlock ("DSDT.aml", "DSDT", 2, "INTEL ", "TEMPLATE", 0x00000000)

修改後:

    DefinitionBlock ("DSDT.aml", "DSDT", 2, "INTEL ", "TEMPLATE", 0x00000001)

6.) 編譯被修復過的代碼: `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包被設置為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

最後，配置bootloader來加載你的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`:

- 禁用"Select only drivers that don't need compile-time external firmware"。位於"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)

## 參見

- 通過 initrd 升級 ACPI 表
- 如何使用 _OSI 在 ACPI 中識別 Windows 版本
- 如何使用 dracut 覆蓋 ACPI 表

分類：​

- 啟動過程
- 內核
- 電源管理
- 包含失效連結的頁面

DSDT
新增話題