DSDT

出自 Arch Linux 中文维基

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

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

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

在你開始之前[編輯 | 編輯原始碼]

  • 很有可能硬件製造商已經發佈了一個固件更新,修復了ACPI相關問題。安裝一個升級後的固件通常是一個更好的選擇,因為這會避免重複的工作。
  • 這個過程會篡改你系統上一些相當基礎的代碼。你要對你將做出的改動相當清楚。你可能還會想在行動之前先備份你的硬盤
  • 即使在你嘗試你自行修復你的DSDT之前,你也可以嘗試一些不同的捷徑:

讓內核報告一個Windows版本[編輯 | 編輯原始碼]

使用變量acpi_os_name作為一個內核參數。例如:

 acpi_os_name="Microsoft Windows NT"

或者

 acpi_osi="!Windows2012"

添加在grub配置文件中的kernel一行。

其他用來測試的字符串:

  • "Microsoft Windows XP"
  • "Microsoft Windows 2000"
  • "Microsoft Windows 2000.1"
  • "Microsoft Windows ME: Millennium Edition"
  • "Windows 2001"
  • "Windows 2006"
  • "Windows 2009"
  • "Windows 2012"
  • 當這些都失敗時,你可以嘗試"Linux"

出於好奇,你可以執行下面的步驟來提取你的DSDT並找到.dsl文件。你只需grep Windows然後看看出現了什麼。

找一個已被修復的DSDT[編輯 | 編輯原始碼]

一個DSDT文件最初是用ACPI源語言(.asl/.dsl文件)寫的。藉助一個編譯器,這樣的文件可以被編譯成一個「ACPI機器語言」文件(.aml)或者一個十六進制表(.hex)。為了將這個文件包含在你的Arch裡,你將需要找到一個編譯過的.aml文件——這到底意味這自己編譯它還是相信網上的一個陌生人是由你自己決定的。如果你從網上下載一個文件,它很有可能是一個壓縮的.asl文件。I所以你將會需要解壓並編譯它。這樣做的好處就是你將不用自己研究具體的修復代碼。

像你一樣使用同一種筆記本的Arch用戶是少數中的少數中的少數。嘗試瀏覽其他發行版的論壇來尋找關於相同的型號的討論。很有可能他們也有相同的問題。由於他們的用戶可能比較多或是比較精通技術,有可能有人已經給出了預編譯的版本(再強調一次,要自己承擔風險)。 搜尋引擎是你最好的工具。儘量讓搜索的內容保持簡短:『型號 + dsdt』很有可能會搜到結果。

自己重新編譯[編輯 | 編輯原始碼]

在這個過程中你的最好的資源將會是ACPI Spec homepage[失效連結 2022-09-17 ⓘ],和Linux ACPI Project[失效連結 2022-09-17 ⓘ],這些將會替代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:

  • 創建一個會被bootloader加載的CPIO文檔
  • 把它編譯進內核

使用一個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.hexdsdt.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"。

確認覆蓋成功[編輯 | 編輯原始碼]

  1. 運行dmesg | grep ACPI.
  2. 查找表明已經覆蓋的提示,例如:
[    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)

參見[編輯 | 編輯原始碼]