BIOS Setupとは: クラシックな青い画面からHIIと現代のNVRAMまで

現代のBIOS SetupはHII上に構築されている: VFR、VarStore、NVRAM。structの途中にフィールドを追加するとなぜシステムが壊れるのか、そして保存されない設定のデバッグ方法。

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

「BIOSに入る」とはfirmwareのSetupに入ること

2000年代以前のコンピュータで育った人なら、あの画面を覚えているでしょう。電源を入れた直後にDelF2を押すと、白いテキストが並んだ青や灰色の画面が出てくる。矢印キーで移動、Enterで選択、+/-で値を変える。マウスなし、グラフィックなし、何もモダンなものはない。

それがLegacy BIOS Setup ——AMI BIOS、Award BIOS、Phoenix BIOSでした。その時代には十分に機能しましたが、UIの柔軟性、多言語サポート、拡張性において厳しい制限がありました。

今日、最新のラップトップやサーバーの「BIOS」に入ると何が見えるでしょうか?マウスサポートがある多彩なグラフィカルインターフェース、検索ボックス、時にはベンダーロゴまで。複数の言語に対応。タブと構造化されたサブメニューで整理されている。

多くの人はまだこれを「BIOSに入る」と呼んでいて、機能的には同じことをするという意味では完全に間違いではありません。しかし内部的にはHII (Human Interface Infrastructure)と呼ばれるまったく異なるアーキテクチャで構築されています。

Setupへの入り方、そして「BIOS」という名前が残り続けた理由

UEFI Setupに入る一般的な方法:

  • DelF2 — 最も一般的、ほとんどのPCとラップトップで動作
  • F10 — HPで一般的
  • F1 — 伝統的なIBM/Lenovo ThinkPad
  • Esc — 一部のAsusやSonyのラップトップ

一部の最新システムではブートウィンドウが速すぎてキーストロークを挟めません。Windowsから: 設定 → 回復 → 詳細な起動 → 今すぐ再起動 → トラブルシューティング → UEFIファームウェアの設定。

HII: 洗練されたUIの背後にあるアーキテクチャ

Legacy BIOS Setupが画面に直接描画するモノリシックなCコードだとすれば、UEFI HIIはデータインターフェースストレージを明確に分離した構造化されたパイプラインです。

HII (Human Interface Infrastructure)は以下から構成されます。

VFRソース    → フォーム、クエスチョン、表示条件を記述する
.UNIファイル  → 多言語表示文字列 (英語、日本語、ベトナム語...)
ビルドツール  → VFRをIFRバイナリにコンパイル、UNIを文字列パッケージに
DXEドライバー → パッケージをHII Databaseにinstallする
Setup Browser → IFRを読み取り、UIをレンダリングし、入力を処理する
VarStore     → 各クエスチョンの値のバッキングストレージ
Config Access → 保存/検証/通知のドライバーコールバック
NVRAM         → データが最終的に永続化される場所

このアーキテクチャの優れた点: 各DXEドライバーはBrowserのコードを変更せずに独自のフォームをSetupに追加できます。BrowserはHII Databaseを読み取ってレンダリングするだけで、何個のドライバーがフォームを提供しているかを知る必要がありません。

これが現代のサーバーのSetupメニューが複雑なサブメニューにわたって何百ものオプションを持ちながら、コードベースは明確な構造を保てる理由です。

VFR: Setup UIのソースコード

開発者は画面描画コードを書きません。フォーム、クエスチョン、表示条件を記述する言語であるVFR (Visual Forms Representation)を書きます。

varstore SETUP_DATA,
  varid = Setup,
  name  = Setup,
  guid  = SETUP_GUID;

form formid = FORM_BOOT_MAIN,
  title = STRING_TOKEN(STR_BOOT_FORM);

  oneof varid   = Setup.SataMode,
        prompt  = STRING_TOKEN(STR_SATA_MODE),
        help    = STRING_TOKEN(STR_SATA_MODE_HELP),
        questionid = QUESTION_ID_SATA_MODE;
    option text = STRING_TOKEN(STR_AHCI),  value = 0, flags = DEFAULT;
    option text = STRING_TOKEN(STR_RAID),  value = 1;
  endoneof;

  checkbox varid   = Setup.FastBoot,
           prompt  = STRING_TOKEN(STR_FAST_BOOT),
           help    = STRING_TOKEN(STR_FAST_BOOT_HELP),
           questionid = QUESTION_ID_FAST_BOOT;
  endcheckbox;
endform;

VFRはバイナリバイトコードであるIFR (Internal Forms Representation)にコンパイルされます。Setup BrowserはVFRソースではなくIFRを読みます。これはデバッグに重要な意味を持ちます: IFR Extractorがあれば、ソースコードなしにBIOSイメージからSetupフォームの構造を逆読みできます。

VarStoreとstruct: データが実際に住む場所

VFR内の各クエスチョンにはVarStore——値を読み書きするバッキングストレージ——が必要です。

最も一般的なタイプはC structに直接マップするBuffer VarStoreです。

// ヘッダーファイルで定義
typedef struct {
    UINT8  FastBoot;        // オフセット 0x00
    UINT8  SataMode;        // オフセット 0x01
    UINT8  NetworkStack;    // オフセット 0x02
    UINT8  Reserved;        // オフセット 0x03、アラインメントパディング
    UINT16 BootTimeout;     // オフセット 0x04
    UINT8  TpmDevice;       // オフセット 0x06
    UINT8  SecureBootUi;    // オフセット 0x07
} SETUP_DATA;

ユーザーが「SATAモード」をRAIDに切り替えて保存すると、firmwareはこのバッファのオフセット0x01に値1を書き込みます。次のブート時に、PEIまたはDXEドライバーがバッファを読み戻し、Setup.SataModeを読み、それに応じてストレージコントローラーを設定します。

オフセットの問題: なぜ小さな変更がシステムを壊すのか

これは私が一度やって長い時間をかけて理解したタイプのバグです。POSのfirmwareに新機能のフラグを追加していました——単なるUINT8で、「きれいに見える」という理由でstructの途中に挿入しました。ビルドして、フラッシュして、テストマシンで起動: ハードドライブが見えない。シリアルログは特に問題なし。ケーブルを確認、SATAコントローラーを確認、DXEドライバーを確認——すべて問題なし。

NVRAMをダンプして新しいstructと各バイトのフィールドオフセットを比較することを思いつくのに半日近くかかりました。1バイトずれていました。SataModeが隣のフィールドの値を読んでいました。

なぜこうなるかを説明します。SETUP_DATAに新しいフィールドを追加する必要があるとします。途中に挿入します。

// フィールドを追加する前
typedef struct {
    UINT8  FastBoot;        // オフセット 0x00
    UINT8  SataMode;        // オフセット 0x01
    UINT8  NetworkStack;    // オフセット 0x02
    UINT8  Reserved;        // オフセット 0x03
    UINT16 BootTimeout;     // オフセット 0x04
} SETUP_DATA;

// 途中にフィールドを追加した後
typedef struct {
    UINT8  FastBoot;        // オフセット 0x00
    UINT8  NewFeature;      // オフセット 0x01、ここに追加
    UINT8  SataMode;        // オフセット 0x02、ずれた
    UINT8  NetworkStack;    // オフセット 0x03
    UINT8  Reserved;        // オフセット 0x04
    UINT16 BootTimeout;     // オフセット 0x05、ずれた
} SETUP_DATA;

C structは変わりました。しかしNVRAMは古いレイアウトでデータを保持したままです。新しいfirmwareが起動してSetup.SataModeをオフセット0x02で読むとき、実際には古いレイアウトのNetworkStackだった値を読んでいます。

結果: SATAモードが間違い、ストレージコントローラーがドライブを認識しない、マシンが起動しない。あるいはさらに悪く、TPMのようなセキュリティ関連のフィールドが誤読されて連鎖的なデバッグしにくい結果につながります。

これはまた、BIOSプロジェクトをメンテナンスのために引き継ぐとき、多くのエンジニアが最初にすることがすべてのNVRAM variableをダンプしてソースコード内のstructとフィールドオフセットを比較することである理由でもあります。1バイトずれただけですべてが間違って読まれます。

完全なフロー: ユーザーのクリックからブート時に使われる設定まで

ユーザーがSetupに入ってオプションを変更し保存するとき、実際には以下のことが起きています。

01 ユーザーが変更

Browserが一時保持

新しい値はブラウザーストレージに保持される。NVRAMにはすぐに書かない場合がある。ドライバーが登録していればコールバックが呼ばれる

02 Save & Exit

RouteConfig()が呼ばれる

BrowserがFormSetを所有するドライバーのRouteConfig()を呼ぶ。これが実際にデータをコミットするステップ

03 SetVariable

NVRAMに書き込む

ドライバーがSetVariableを呼ぶ。ここで失敗すると、UIは正しい値を表示するがリブート後に元に戻る

04 リセット

システムがリブート

マシンがSPI flash内の新しいデータで再起動する

05 Consumer

PEI/DXEが設定を読む

GetVariable → Setup.SataMode == 1 → コントローラーがRAIDモードで設定される

BIOS設定の保存フロー: Browserの一時保存 → RouteConfig → SetVariable → NVRAM → consumer

見落としやすいステップ: 多くの実装では、Setup BrowserはユーザーがオプションをA変更した瞬間にNVRAMを書き込みません。Save & ExitのときだけRouteConfig()が呼ばれ、Config Accessドライバーが実際のvariable storeに書き込みます。

SetVariable()がエラーを返した場合——例えばフラッシュ保護がすでに有効でEFI_WRITE_PROTECTEDが返る場合——UIは新しい値を表示しますがNVRAMには古い値のまま。リセット後、すべてが元に戻ります。

デバッグ: リブート後に保存されない設定

BIOSの作業で最も一般的なケース。アプローチ:

保存されない設定のデバッグ
ステップ 確認すること 失敗の意味
1 RouteConfigは実行されるか? されない場合、問題はFormSet GUIDかConfig Access Protocolの登録にある可能性がある
2 SetVariableは成功するか? 失敗する場合、EFI_WRITE_PROTECTEDまたはEFI_ACCESS_DENIEDなどのステータスを確認
3 リブート後のNVRAMは正しいか? オフセットがずれている場合、マイグレーションなしにstructレイアウトが変わった可能性がある
4 ConsumerはA正しいフィールドを読んでいるか? PEI/DXEモジュールが間違ったGUID、名前、またはオフセットを読んでいる可能性がある
5 デフォルト復元パスが上書きしていないか? CMOS clearまたはLoad Defaultがvariableを上書きする可能性がある

ツーリング

AMIやInsydeのようなベンダーは通常、Setupフォーム、variable、IFRコンテンツ、BIOSイメージを検査するツールを持っています——AMI Debug Rx、InsydeH2O variable editor、Lauterbachの UEFI awareness。これらは特にソースコードへの完全なアクセスがない場合に役立ちます。

しかしどのツールを使っても、デバッグする人はHIIパイプラインとVarStoreのレイアウトを理解する必要があります。ツールは「このオフセットがずれているかもしれない」とヒントを出せますが、それがなぜ危険で古いバージョンからのアップグレードパスを壊さずにどう修正するかは——技術的な基盤がなければ判断できません。

まとめ

  • **「BIOSに入る」**とは今日ではUEFI Setup: HIIアーキテクチャであり、Legacy BIOSではない
  • HIIはUI (VFR/IFR)、ストレージ (VarStore/NVRAM)、ロジック (Config Access/コールバック)を明確に分離する
  • VarStoreのオフセットは極めてデリケート——structの途中にフィールドを追加すると古いNVRAMデータが壊れる
  • 保存フローはBrowser → RouteConfig → SetVariable → NVRAM → consumerを経由する
  • デバッグは表示 → ストレージ → consumerの同じレイヤーをたどるべき

参考資料

次に読む

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

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