ACPI & EC & Linux (一) -- ACPI 與 AML
What is ACPI?
古時候的電腦經常會有一個問題,作業系統中許多有關硬體的控制都相當的差。原因主要是當時所用的規範 APM (Advanced Power Management),將硬體的主要控制交給BIOS處理,OS只能做一些簡易的管理。
爾後,Intel & Microsoft & Toshiba 在1997年提出了 ACPI,讓OS可以更加進階的控制硬體。其中,最重要的部份就是 AML (ACPI Machine Language),他是類似於 Java 的 byte code,可以讓 kernel 執行其中的程式,對硬體的 register 進行操作。
簡而言之,AML 可以讓 kernel 需要切換裝置或是系統電源狀態時,提供特定的 function 讓 kernel 執行裡面的程式碼。如此一來,以往需要寫進 BIOS 的控制邏輯就可以全權交給 kernel 處理,也因此,就能夠脫離 BIOS 的限制,做到更精細的控制。畢竟 OS 比起 BIOS 更能了解整臺電腦的運作狀況,也讓 ACPI 逐漸成為今日電腦的必備功能之一。
無法在 Linux 正常運作的功能
其實筆者寫這系列文章的主要目的是紀錄我修復這臺 HP Pavilion Gaming 15 的一些與 ACPI 有關的問題。
Linux 的 ACPI 實作與 Windows 的總會有一些出入,尤其是 Windows 往往會在裡面偷加一些功能,這導致一些功能會無法在 Linux 上正常運作。
當時我遇到的問題如下:
- 接上/移除 AC 電源時,不會產生硬體的事件 (所以系統不會馬上知道,進而去調整螢幕亮度等)
- 螢幕亮度、媒體鍵等 Fn Key 按了完全沒有反應
這幾個問題自從我買了這臺電腦之後,就困擾了我2年多的時間。由於網路上的相關資源不多,且之前的功力不足,所以直到前陣子才發現問題。
不過就最後修復的結果來說,這並不是什麼 Windows 又藏了一手,而是 Linux 的鍋。這會在之後的文章陸續提到。
在 Linux 中取得 ACPI Table
若要分析 ACPI,最重要就是要取得 ACPI Table
安裝工具
sudo pacman -S acpica
這會安裝一系列有關 ACPI Table 的工具,包含編譯器及反編譯器。其中,也有擷取 ACPI Table 的工具。
取得 ACPI Tables
mkdir acpi
cd acpi/
sudo acpidump > acpi.info && acpixtract -a acpi.info
就會在目錄內生成所有的 ACPI Tables
acpi.info bgrt.dat dmar.dat facp.dat hpet.dat mcfg.dat ssdt2.dat ssdt5.dat ssdt8.dat ssdt11.dat ssdt14.dat ssdt17.dat ssdt20.dat ssdt23.dat uefi1.dat
apic.dat dbg2.dat dsdt.dat facs.dat ihis.dat msdm.dat ssdt3.dat ssdt6.dat ssdt9.dat ssdt12.dat ssdt15.dat ssdt18.dat ssdt21.dat ssdt24.dat uefi2.dat
asf!.dat dbgp.dat ecdt.dat fpdt.dat lpit.dat ssdt1.dat ssdt4.dat ssdt7.dat ssdt10.dat ssdt13.dat ssdt16.dat ssdt19.dat ssdt22.dat tpm2.dat wsmt.dat
註:除了透過工具,也可以在 /sys/firmware/acpi/tables
中找到所有的 Tables
一些 ACPI Tables 的意義
- ECDT:包含電腦上 EC (Embedded Controller) 的相關資訊
- DSDT:必須存在。包含主要硬體的定義、控制的 AML Code 等各種資訊,也是 ACPI debug 的主要目標之一。當作業系統需要取得資訊或控制裝置時,會執行對應的 method
- SSDT:附加在 DSDT 的 Tables。可以在 DSDT 之上新增裝置定義,但不能修改或刪除已有的裝置
反編譯 ACPI Tables
由於 AML 是類似於 Java Bytecode 那樣的中介語言,語言本身也比較屬於低階語言,因此反編譯相當的容易。
acpica 中有包含一個 Intel 的 AML 編譯/反編譯器,叫 iasl,用以下指令可以反編譯出 .dsl 的原始碼
iasl -d dsdt.dat
但是由於 DSDT 與 SSDT 往往會相互參照一些命名空間或裝置,因此只反編譯一個檔案經常會有找不到定義的警告發生。可以將全部的 SSDT 跟 DSDT 一起反編譯:
iasl -d dsdt.dat ssdt*.dat
或是引用參照的方式,只反編譯 dsdt.dat:
iasl -e ssdt*.dat -d dsdt.dat
完成後會得到對應名稱的 .dsl 檔案,裡面就會有你的電腦的 ACPI 原始碼