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 原始碼