ACPIとは: firmwareがGPIOをトグルして電源を切ってはいけない理由
なぜfirmwareがGPIOをトグルして電源を落としてはいけないのか。ACPIはfirmwareが書きOSが読む契約: テーブル、AML、電力状態、壊れたスリープ/ウェイクのデバッグ。
最初の疑問: なぜfirmwareはGPIOをトグルして電源を落としてはいけないのか
SMMを使い始めた頃、熱帯地方に設置されたPOS端末のような熱い環境で温度がしきい値を超えたときの緊急シャットダウンロジックを実装する必要がありました。最初の直感は至極自然なものでした: SMMは非常に高い特権で動いている、OSは一切介入できない、だからGPIOピンをトグルして電源を落とせばいい。
同僚がドラフトコードを見て一言聞きました: 「どのGPIO?ボードが違えば全部違う。ハードコードするつもり?」
この質問がここに書き留めたい一連の説明を開きました: firmwareがGPIOをトグルして電源を落としてはいけない理由と、ACPIがそのギャップをどのように埋めるのか。
短い答え: 電源に関係するGPIOピンはプラットフォーム固有のものです。SMMハンドラーやfirmwareルーティンにハードコードすると、コードが特定のボードに縛られます。さらに重要なのは、通常のシャットダウンフローでは、電力遷移はSMMだけの決断ではないということです。ACPIとOSの電力管理の一部です。
長い答えはfirmwareとOSがハードウェアの制御をどのように分担するかを理解することが必要で、それがまさにACPIが存在する理由です。
firmwareとOSはハードウェアを違う目で見る
ExitBootServices()が呼ばれた後、OSはプラットフォームを所有します。しかしOSはハードウェア固有の詳細を知りません: どのGPIOピンが電源ボタンか、どのECレジスターがファンを制御するか、スリープ時にどのレールをどの順序で落とすか。
firmwareはこれらすべてを知っています。firmwareこそがハードウェアをゼロから初期化したものだからです。しかしfirmwareはOSに「口頭で説明」することができません。標準化された記述を残さなければなりません。
ACPIはその記述です。
firmwareがハードウェアを初期化
firmwareがチップセット、デバイス、ポリシー、プラットフォームリソースを設定する
ACPIテーブルをpublish
firmwareがDSDT、SSDT、FADT、MADTおよび関連テーブルをinstallする
ExitBootServices
firmwareがブート時の制御をOSに引き渡す
OSがACPIを読む
OSがRSDPからwalkし、DSDT/SSDTを読み、AMLをinterpretする
OSがACPIメソッドを呼ぶ
デバイスプローブ、スリープ、ウェイク、電源ボタンはすべてACPIモデルを通じる
ACPIはOSとfirmware間の直接的な関数呼び出しAPIではありません。データとcontrol methodの契約です: firmwareがテーブルとAMLバイトコードをpublishし、OSがテーブルを読んで必要なときにAMLメソッドを実行します。OSが動いている間のすべての電力管理操作はこの契約を通じます。
最初の疑問に戻る: なぜSMMでGPIOをトグルしてはいけないのか
SMMでは技術的にはハードウェアレジスターに直接アクセスできます。しかし通常のフローでそれを使って電源を落とすといくつかの問題が生じます。
第一に、ACPIの電力シーケンスをバイパスします。OSはディスクをフラッシュし、ファイルハンドルをクローズし、ドライバーのクリーンアップを通知し、電源が切れる前にデバイスを準備する機会がありません。結果はファイルシステムの破損や、次回起動後にデバイスが未定義状態に陥ることです。
第二に、ポータブルではありません。どのGPIOピン、どのレジスター、どのECコマンドが電源に関係するかはボード固有、シリコン固有です。SMMハンドラーにハードコードするとfirmwareが特定のプラットフォームに縛られます。
第三に、所有権の問題があります。SMMは小さなfirmwareサービスの処理、リソースの保護、セキュリティポリシーの強制のために存在します。OSを置き換えて大局的な電力管理を行うものではありません。通常のシャットダウンでは、OS/OSPMが電力遷移を調整する側です。
通常のACPIフローでは、OSが動き始めた後にfirmwareが自分の判断で電源を落とすことはありません。firmwareはFADT、DSDT/SSDT、_S5を含むACPIテーブルを提供します。OS/OSPMはこれを読み、デバイスを準備し、ファイルシステムをフラッシュし、必要なACPIメソッドを呼び出し、それからSLP_TYPとSLP_ENを書き込んでチップセットにS5への移行を要求します。
言い換えると: firmwareが契約を書き、OSが契約を読んで電力遷移を制御します。
ACPIテーブルをpublish
FADT、DSDT/SSDT、_S5、_PTS、_WAK、デバイスメソッド
ACPIを読む
OSがデバイス、リソース、ウェイクソース、スリープステートを理解する
電力遷移を準備
I/Oをフラッシュし、ドライバーに通知し、必要なACPIメソッドを実行する
SLP_TYP + SLP_EN
OSがACPI specに従ってチップセットにスリープ/オフステートへの移行を要求する
電力遷移
プラットフォームが適切なACPIフローに従ってS5に移行する
これが本当の熱的緊急事態であれば、プラットフォームは通常EC、PMIC、チップセットのサーマルトリップ、ボード固有のセーフティロジックなど独自のハードウェア保護パスを持ちます。しかしそれは緊急保護メカニズムであり、通常のOS制御のシャットダウンフローではありません。これら二つを混在させるべきではありません。
ACPIとは: firmwareエンジニアの視点から
ACPI (Advanced Configuration and Power Interface)は単なる「設定テーブル」ではありません。2つの主要な部分があります。
1. 静的テーブル ——ブート時にfirmwareがpublishするデータ。
2. AMLコード ——OSのインタープリターが必要なときにランタイムで実行するバイトコード。
多くの人が見落とすのはここです: ACPIはブート時に一度読まれて終わりではありません。OSはデバイスがプローブされるとき、システムがスリープするとき、デバイスが電源を失うとき、ユーザーが電源ボタンを押すとき——ライフタイム全体を通じて継続的にACPIメソッドを呼び続けます。
ACPIテーブルの構造
firmwareはテーブルのツリーをpublishします。OSはRSDP (Root System Description Pointer)を通じてエントリーポイントを見つけ、そこから他のテーブルへとwalkします。
RSDP → XSDT
├─ FADT → DSDT (メインAML)
├─ SSDT (補足AML)
├─ MADT (割り込みコントローラー)
├─ MCFG (PCIe ECMAMベース)
└─ ... (プラットフォーム固有の他のテーブル)
firmwareエンジニアにとって最も重要なテーブル:
| テーブル | 正式名称 | デバッグでの関連性 |
|---|---|---|
| FADT | Fixed ACPI Description Table | PMレジスター情報、ACPIフラグ、DSDTへのポインターを含む |
| DSDT | Differentiated System Description Table | プラットフォームのメインAML。_STA、_CRS、_PS0、_PRWなどのデバイスネームスペースとcontrol methodを含む |
| SSDT | Secondary System Description Table | CPU、デバイス、SKU、またはSetupオプションによってネームスペースを補足する |
| MADT | Multiple APIC Description Table | APICと割り込みルーティングを記述する。ここのエラーは通常SMPや割り込みの障害を引き起こす |
| MCFG | PCI ECAM Table | ECMAMを通じてPCI config spaceにアクセスするためのベースアドレスをOSに伝える |
AML: OS内部で動く言語
ACPIで最も興味深く、最も複雑な部分はAML (ACPI Machine Language)です。
firmwareエンジニアはASL (ACPI Source Language)を書きます。コンパイラーがASLをAMLバイナリに変換し、AMLはDSDT/SSDTに埋め込まれます。OSはこのAMLをランタイムに実行するインタープリターを持っています。
// ASLソース — firmwareエンジニアが書くもの
Device (PWRB) { // 電源ボタンデバイス
Name (_HID, "PNP0C0C")
Method (_STA, 0) {
Return (0x0F) // 存在、有効、表示、機能中
}
}
Device (SLPB) { // スリープボタン
Name (_HID, "PNP0C0E")
Method (_PRW, 0) { // ウェイクのためのPower Resource
Return (Package() { 0x1D, 0x04 }) // GPE 0x1D、S4からウェイク
}
}
OSが電源ボタンが機能しているかを知りたいとき、_STAを呼びます。スリープボタンがS4からウェイクできるかを知りたいとき、_PRWを呼びます。firmwareはOSがいつ尋ねるかを知る必要はありません——これらのメソッドを正しく実装するだけです。
電力状態: ACPIが定義し、OSが決定し、firmwareが記述する
ACPIはS0からS5のグローバルシステムステートを定義します。
| ステート | 意味 | デバッグメモ |
|---|---|---|
| S0 | 動作中 — システムが動いている | S0ix / Modern StandbyもS0内に位置する |
| S3 | Suspend to RAM | DRAMがデータを保持、デバイス/レールがオフ、高速レジューム |
| S4 | ハイバネート | ストレージにステートを保存、システムはほぼ完全にオフ |
| S5 | ソフトオフ | ソフト電源オフ、ウェイクロジックと電源ボタンのみ残る |
| G3 | メカニカルオフ | 完全な電源断 — S0-S5と同じ意味ではないS状態 |
OSがスリープしたいとき——例えばS3に移行するとき——ただ画面をオフにするだけではありません。準備シーケンスが必要です。
_PTS(Prepare To Sleep)を呼ぶ — firmwareがプラットフォームを準備する- 各デバイスの
_PS3を通じてデバイスを一つずつ電源オフ - プラットフォームが記述していればpower resourceを無効化するメソッドを呼ぶ
- PMコントロールレジスターに書き込んでチップセットをスリープステートに移行
- ウェイクイベントが発生すると、firmwareが起動シーケンスの一部を再実行
- OSが
_WAKを呼ぶ — firmwareが必要なステートを復元 _PS0を通じてデバイスを電源オン
これが、通常のフローで「単一のGPIO経由で直接電源オフ」すべきでない理由です。ACPIの電力遷移の各ステップには理由があります。あるデバイスの_PS3をスキップすると、次回の電源オン後にそのデバイスが未定義状態になる可能性があります。_PTSをスキップすると、ECが次のスリープ状態について通知を受けないことがあります。
ブートフローのどこでfirmwareがACPIを書くか
ACPIテーブルはDXEフェーズで、BDSがOSをロードする前に作成・publishされます。
プラットフォームDXEモジュール
Setupオプション、ボード設定、SKU、ポリシーを読む
DSDT/SSDTをパッチ
実際の設定に基づいてACPIテーブルを作成または変更する
InstallAcpiTable()
EFI_ACPI_TABLE_PROTOCOL->InstallAcpiTable()を呼ぶ
OSをロード
BDSがOSローダーをロードする
ACPIを読む
OSがRSDPを通じてテーブルを読み、AMLをinterpretする
重要なこと: ACPIテーブルはSetupオプションを反映します。 ユーザーがBIOS Setupで機能を無効にすると、firmwareはそのデバイスの_STAメソッドが0x00を返すようにパッチし、ハードウェアがボード上に物理的に存在していてもデバイスがOSから消えます。
これが多くの説明しにくいバグの原因です: 測定すると電力はあるのにデバイスマネージャーにデバイスが出てこない。OSドライバーの問題ではなく、何かSetupオプションがそれを無効にしているために_STAが0x00を返しています。
実際のシナリオ: BIOSアップデート後にスリープ/ウェイクが壊れた
BIOSの作業でよく見るパターン:
症状: マシンはスリープできるが、レジューム後にタッチパッド/USBが消える
正しいデバッグアプローチはOSドライバーを再インストールすることではありません。ACPIに従います。
ステップ1: レジューム後に消えるデバイスを特定
デバイスマネージャー、またはLinuxのlspci、lsusb、dmesgが警告があるデバイスやレジューム後に戻ってこないデバイスを特定するのに役立ちます。
ステップ2: ACPIテーブルをダンプ
# Linux
sudo acpidump -o acpi.dat
acpixtract acpi.dat
iasl -d DSDT.dat SSDT*.dat
ステップ3: そのデバイスに関連するメソッドを探す
decompileされたAMLで対象デバイスの_PS0と_PS3を検索します。確認すること:
- 電力シーケンス: レール → ディレイ → クロック → リセット、の順序が正しいか
- レジューム後にGPIOのステートが正しく復元されるか
- レジューム後にECコマンドが再送信されるか
ステップ4: デバイスの_PRWを確認
// 誤った _PRW はインスタントウェイクを引き起こす可能性がある
Method (_PRW, 0) {
Return (Package() { 0x1D, 0x03 }) // GPE、スリープステート
}
_PRWのGPEがスリープ前にすでにアクティブであれば、スリープに入った直後にマシンがウェイクします。
スリープ/ウェイクとACPIのデバッグチェックリスト
SMMとACPI: 2つの別レイヤー、競合ではない
最初の疑問を締めくくるために: SMMとACPIは競合しません。異なる役割を持っています。
SMMは小さな隔離されたfirmwareサービスを処理し、リソースを保護し、OSが知るべきでないイベントを処理します。速く動き、通常の電力状態管理のような大きな責任を負うべきではありません。
ACPIはすべてのハードウェア記述と電力管理についてfirmwareとOSの間の契約です。電力状態、デバイスenumeration、スリープ/ウェイクに関係するすべてはACPIモデルを通じなければなりません。
通常のシャットダウンでは、OS/OSPMが_S5を読み、システムを準備し、SLP_TYPとSLP_ENを通じてチップセットにS5への移行を要求します。
本当の熱的緊急事態では、プラットフォームは通常独自の保護パスを持ちます: EC、PMIC、チップセットのサーマルトリップ、ボード固有のセーフティロジック。それは緊急保護メカニズムであり、通常のACPIシャットダウンフローではありません。
まとめ
- ACPIはfirmwareが書きOSが読む契約で、ハードウェア、電力状態、control methodを記述する
- AMLはDSDT/SSDT内のバイトコード。OSのインタープリターが必要なときにランタイムで実行する
- 電力状態 (S0-S5)はACPIが定義し、OSが決定し、firmwareがテーブルとメソッドで記述してサポートする
- firmwareはGPIOをトグルして電源を落としてはいけない — 通常のフローでは電力シーケンスをバイパスし、ポータブルでなく、所有権が間違っている
- デバイスの消失やスリープ/ウェイクの不具合のデバッグはACPIから始める: テーブルをダンプし、AMLをdecompileし、メソッドをチェックする
参考資料
- ACPI Specification, uefi.org — 公式のACPI spec、無料ダウンロード
- iasl compiler, acpica.org — AMLをASLにdecompileするツール、クロスプラットフォーム
- ACPICA Project, GitHub — リファレンスインタープリターとツール、オープンソース
- EDK II ACPI modules, GitHub — ACPI DXEドライバーリファレンス
次に読む
この記事は役に立ちましたか?
ファームウェア、BIOS/UEFI、組み込みシステムを学んでいる人に共有できます。
Nội dung liên quan
Một số bài viết, ghi chú hoặc project có liên quan đến nội dung bạn vừa đọc.
DSDT vs SSDTの違いとは?
BIOS/UEFIおよびembedded firmware学習者向けにDSDT vs SSDTを説明するクイックノート。
AMLとは?
BIOS/UEFIおよびembedded firmware学習者向けにAMLを説明するクイックノート。
DXEフェーズ: ドライバー、Protocolと何も動かないときのログの読み方
DXEの深掘り: dispatcher、DEPEX、Driver Binding、protocolデータベース。シリアルログ、POST code、UEFI Shellを使って実際の障害をデバッグする方法。
Đọc thêm về BIOS/UEFI
Khám phá các bài viết về BIOS/UEFI, embedded firmware, debugging và system-level thinking.