ACPIとは: firmwareがGPIOをトグルして電源を切ってはいけない理由

なぜfirmwareがGPIOをトグルして電源を落としてはいけないのか。ACPIはfirmwareが書きOSが読む契約: テーブル、AML、電力状態、壊れたスリープ/ウェイクのデバッグ。

更新 3 分で読めます
Đọc bằng 日本語 Tiếng Việt English
BIOS / UEFI cover

最初の疑問: なぜ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はその記述です。

01 DXE

firmwareがハードウェアを初期化

firmwareがチップセット、デバイス、ポリシー、プラットフォームリソースを設定する

02 ACPI

ACPIテーブルをpublish

firmwareがDSDT、SSDT、FADT、MADTおよび関連テーブルをinstallする

03 EBS

ExitBootServices

firmwareがブート時の制御をOSに引き渡す

04 OS

OSがACPIを読む

OSがRSDPからwalkし、DSDT/SSDTを読み、AMLをinterpretする

05 Runtime

OSがACPIメソッドを呼ぶ

デバイスプローブ、スリープ、ウェイク、電源ボタンはすべてACPIモデルを通じる

ACPIは契約: firmwareがpublishし、OSが必要に応じてAMLメソッドを読んで実行する

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_TYPSLP_ENを書き込んでチップセットにS5への移行を要求します。

言い換えると: firmwareが契約を書き、OSが契約を読んで電力遷移を制御します。

01 Firmware

ACPIテーブルをpublish

FADT、DSDT/SSDT、_S5、_PTS、_WAK、デバイスメソッド

02 OS/OSPM

ACPIを読む

OSがデバイス、リソース、ウェイクソース、スリープステートを理解する

03 準備

電力遷移を準備

I/Oをフラッシュし、ドライバーに通知し、必要なACPIメソッドを実行する

04 PM制御

SLP_TYP + SLP_EN

OSがACPI specに従ってチップセットにスリープ/オフステートへの移行を要求する

05 チップセット

電力遷移

プラットフォームが適切なACPIフローに従ってS5に移行する

通常のACPIシャットダウン: firmwareが記述し、OSが判断して電力遷移を要求する

これが本当の熱的緊急事態であれば、プラットフォームは通常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エンジニアにとって最も重要なテーブル:

主要なACPIテーブル
テーブル 正式名称 デバッグでの関連性
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のグローバルシステムステートを定義します。

ACPIグローバルシステムステート
ステート 意味 デバッグメモ
S0 動作中 — システムが動いている S0ix / Modern StandbyもS0内に位置する
S3 Suspend to RAM DRAMがデータを保持、デバイス/レールがオフ、高速レジューム
S4 ハイバネート ストレージにステートを保存、システムはほぼ完全にオフ
S5 ソフトオフ ソフト電源オフ、ウェイクロジックと電源ボタンのみ残る
G3 メカニカルオフ 完全な電源断 — S0-S5と同じ意味ではないS状態

OSがスリープしたいとき——例えばS3に移行するとき——ただ画面をオフにするだけではありません。準備シーケンスが必要です。

  1. _PTS (Prepare To Sleep)を呼ぶ — firmwareがプラットフォームを準備する
  2. 各デバイスの_PS3を通じてデバイスを一つずつ電源オフ
  3. プラットフォームが記述していればpower resourceを無効化するメソッドを呼ぶ
  4. PMコントロールレジスターに書き込んでチップセットをスリープステートに移行
  5. ウェイクイベントが発生すると、firmwareが起動シーケンスの一部を再実行
  6. OSが_WAKを呼ぶ — firmwareが必要なステートを復元
  7. _PS0を通じてデバイスを電源オン

これが、通常のフローで「単一のGPIO経由で直接電源オフ」すべきでない理由です。ACPIの電力遷移の各ステップには理由があります。あるデバイスの_PS3をスキップすると、次回の電源オン後にそのデバイスが未定義状態になる可能性があります。_PTSをスキップすると、ECが次のスリープ状態について通知を受けないことがあります。

ブートフローのどこでfirmwareがACPIを書くか

ACPIテーブルはDXEフェーズで、BDSがOSをロードする前に作成・publishされます。

01 DXE

プラットフォームDXEモジュール

Setupオプション、ボード設定、SKU、ポリシーを読む

02 パッチ

DSDT/SSDTをパッチ

実際の設定に基づいてACPIテーブルを作成または変更する

03 Install

InstallAcpiTable()

EFI_ACPI_TABLE_PROTOCOL->InstallAcpiTable()を呼ぶ

04 BDS

OSをロード

BDSがOSローダーをロードする

05 OS

ACPIを読む

OSがRSDPを通じてテーブルを読み、AMLをinterpretする

ACPIテーブルはOSが動く前のDXEでfirmwareが作成/publishする

重要なこと: ACPIテーブルはSetupオプションを反映します。 ユーザーがBIOS Setupで機能を無効にすると、firmwareはそのデバイスの_STAメソッドが0x00を返すようにパッチし、ハードウェアがボード上に物理的に存在していてもデバイスがOSから消えます。

これが多くの説明しにくいバグの原因です: 測定すると電力はあるのにデバイスマネージャーにデバイスが出てこない。OSドライバーの問題ではなく、何かSetupオプションがそれを無効にしているために_STA0x00を返しています。

実際のシナリオ: BIOSアップデート後にスリープ/ウェイクが壊れた

BIOSの作業でよく見るパターン:

症状: マシンはスリープできるが、レジューム後にタッチパッド/USBが消える

正しいデバッグアプローチはOSドライバーを再インストールすることではありません。ACPIに従います。

ステップ1: レジューム後に消えるデバイスを特定

デバイスマネージャー、またはLinuxのlspcilsusbdmesgが警告があるデバイスやレジューム後に戻ってこないデバイスを特定するのに役立ちます。

ステップ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_TYPSLP_ENを通じてチップセットにS5への移行を要求します。

本当の熱的緊急事態では、プラットフォームは通常独自の保護パスを持ちます: EC、PMIC、チップセットのサーマルトリップ、ボード固有のセーフティロジック。それは緊急保護メカニズムであり、通常のACPIシャットダウンフローではありません。

まとめ

  • ACPIはfirmwareが書きOSが読む契約で、ハードウェア、電力状態、control methodを記述する
  • AMLはDSDT/SSDT内のバイトコード。OSのインタープリターが必要なときにランタイムで実行する
  • 電力状態 (S0-S5)はACPIが定義し、OSが決定し、firmwareがテーブルとメソッドで記述してサポートする
  • firmwareはGPIOをトグルして電源を落としてはいけない — 通常のフローでは電力シーケンスをバイパスし、ポータブルでなく、所有権が間違っている
  • デバイスの消失やスリープ/ウェイクの不具合のデバッグはACPIから始める: テーブルをダンプし、AMLをdecompileし、メソッドをチェックする

参考資料

次に読む

この記事は役に立ちましたか?

ファームウェア、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.

Đọ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.