osdev-jpでは、OS開発に有用な情報を収集し公開しています

View My GitHub Profile

From http://wiki.osdev.org/UEFI (25 November 2015, at 09:40.)


(U)EFIもしくは(Unified) Extensible Firmware Interfaceは、x86や x86-64、 ARM、 Itaniumプラットフォームにおいて、OSとファームウエア間のインターフェイスを定義する規格です。元々となったEFIは、1990年代中頃にIntelによって、Itaniumプラットフォームのために開発されたものでした。2005年に、Intelはこの規格をUnified EFI Forumと呼ばれる、AMDやMicrosoft、Apple、そしてIntel自身を含むワーキンググループに移しました。現代的なPCはすべてUEFIファームウエアを含んでおり、またUEFIは商用・オープンソースいずれのOSでも広くサポートされています。またUEFIには、過去のOSのために後方互換性があります。

UEFIの基礎

UEFIと過去のBIOS

UEFIがBIOSを置き換えてしまうものである、というのはよくある思い違いです。実際のところ、旧来のマザーボードとUEFIベースのものはどちらも、BIOS ROMを持っており、そこには電源投入時のシステム初期化を行ったり、第三者のコードを読み込んでそれに制御を移すようなコードが含まれています。旧来のBIOSとUEFIの違いは、それらがブートローダーをどこから探してくるのかと、どのようにシステムを初期化するか、そしてどのような便利機能をそれらが提供するか、という3点です。

プラットフォームの初期化

旧来のシステムでは、通常のプラットフォーム初期化はすべてBIOSが行っていました。(メモリコントローラの設定やPCIバスの設定、BARのマッピング、グラフィックカードの初期化等々。) しかし、それらの設定が終わると、後方互換性のためにリアルモードに戻ってしまいます。 そのためブートローダーは、A20ゲートを有効にし、GDTとIDTを設定して、保護モードに切り替え、そしてx86-64CPUにおいては、ページングを設定して32ビットモードに切り替えなければなりませんでした。

UEFIはこれらを同様の手順で行いますが、加えてフラットなセグメント割り付けで保護モードを準備し、仮想アドレスと物理アドレスが同じになるようにページングを設定して32ビットモードへの移行も行います。A20ゲートも同様に有効にしてくれます。

また、UEFIによるプラットフォーム初期化は標準化されているため、ベンダに依存しない形でUEFIが拡張できるようになっています。

起動のしくみ

旧来のBIOSは、ブートデバイスのMBRから512バイト分のバイナリを読み込み、物理アドレス0x7c00に配置して、そこにジャンプしていました。ブートローダーは、BIOSに処理を戻すことはできませんでした。 一方UEFIは、任意の大きさのUEFIアプリケーション(リロケータブルなPEバイナリ)を、起動デバイスのGPTパーティション上のFATパーティションから読み込み、実行時に選択されたどこかのアドレスに配置します。そして、そのアプリケーションのメイン・エントリポイントをcallします。アプリケーションはUEFIに処理を戻すことができるため、ほかの起動デバイスを探し続けたり、診断メニューを起動したりできます。

システムの探索

旧来のブートローダーは、EBDA(Extended BIOS Data Area)やSMBIOS(System Management BIOS)、そしてACPIテーブルを探すために、メモリをスキャンしていました。また、ルートPCIコントローラとのやりとりと、PCIバスの読み込みのために、PIOモードを使用していました。そのため、ブートローダーが冗長なテーブルを読みに行ってしまう可能性がありました。(たとえば、SMBIOSのMP Tableには、ACPI DSDTに含まれているデータも入っています。)

UEFIファームウエアがUEFIアプリケーションを呼び出す際には、システムのACPIテーブルやメモリマップ、その他OSに関連する情報すべてへのポインタが含まれている、「システムテーブル」構造体を渡します。SMBIOSのような旧来のテーブルは、これに含められません。

便利な関数群

旧来のBIOSでは、ディスクや画面といったシステムリソースにブートローダーがアクセスできるよう、様々な種類の割り込みをフックしていました。これらの割り込みは、歴史的慣習のあるもの以外は標準化されておらず、それぞれの割り込みは異なる呼び出し規約を使用していました。

UEFIは呼び出し可能な数多くの関数をメモリ上に用意しており、それらは「プロトコル」と呼ばれるセットでグループ化され、システムテーブルを通して参照可能になっています。それぞれn関数の振る舞いは規格によって定義されています。UEFIアプリケーションは独自のプロトコルを定義でき、ほかのUEFIアプリケーションが利用できるよう、それらをメモリ上に残しておくことができます。これらの関数は、多くのCコンパイラで利用可能な、現代的かつ標準化された呼び出し規約に基づいて呼び出されます。

開発環境

旧来のブートローダーは、フラットなバイナリイメージを出力できるあらゆる開発環境(nasmやgccなど)で開発することができました。 UEFIアプリケーションは、PE実行バイナリを生成し、UEFIファームウエアの呼び出し規約をサポートしているあらゆる言語で開発可能です。 慣例的には、インテルのTianoCore EDK2か、GNU-EFIを利用します。

TianoCoreは、独自のビルドシステムをもった巨大で複雑な開発環境です。GCCやMinFW、Microsoft VisualC++などを、クロスコンパイラとして利用するよう設定可能です。また、UEFIアプリケーションをコンパイルするだけでなく、BIOS ROMに焼き込むUEFIファームウエアをコンパイルすることもできます。

GNU-EFIは、環境ネイティブのGCCを用いて、UEFIアプリケーションをコンパイルするための、ライブラリとヘッダファイルのセットです。これは、UEFIファームウエアをコンパイルする目的には使えません。UEFIアプリケーションがリンクできるライブラリはほんのわずかしかないので、TianoCoreよりも簡単に使えます。

エミュレーション

Bochsは、オープンソースのレガシーBIOSをデフォルトで含んでいます。さらに、有名なオープンソースのレガシーBIOSである、SeaBIOSが、BochsとQEMU両方の仮想マシン向けに提供されています。これらのBIOSはどちらも、皆さんが期待しているようなレガシーBIOSの機能の多くを実装しています。しかしながら、実機で使われている商用のBIOSに関してはまだまだ進行中です。

OVMFと呼ばれる、有名なオープンソースUEFIファームウエアが、QEMU向けに提供されています。(Bochs向けはありません。)このファームウエアはUEFI規格を実装しているために、商用のUEFIファームウエアと非常に近い動作をします。(OVMFそれ自身はTianoCoreでコンパイルされていますが、すでにビルド済みのイメージが利用可能です。)

旧来のブートローダーとUEFIアプリケーション

もしUEFIが利用可能でない旧来のシステムを対象にしているならば、旧来のブートローダーを開発するべきでしょう。そのためには、x86もしくはx86-64CPUにおける、16ビットアドレッシングと後方互換性についての詳細な知識が必要となります。

もし現代的なシステムを対象にしているならば、UEFIアプリケーションで開発するべきでしょう。多くのUEFIファームウエアは、旧来のBIOSをエミュレーションするよう設定することが可能ですが、それによってエミュレーションされる環境については、実機のBIOSよりも多様なバリエーションがあります。

UEFI開発環境やシステムテーブル、UEFIが提供する関数群の使い方の習得は、緩やかな学習曲線を描く一方、すぐに陳腐化してしまう実機上のバリエーション豊かなBIOSと互換性を保とうとすることに比べて、混乱することは格段に少なくなっています。UEFIは現代的なPCすべての標準なのです。

UEFIクラス0から3と、CSMについて

PCはUEFIクラス0から3のいずれかに分類されます。 UEFIクラス0のPCは、旧来のBIOSを積んだ旧来のシステムであり、全くもってUEFIシステムではありません。

クラス1のマシンは、互換性サポートモジュール(CSM)内でのみ、UEFIシステムが動作するというものです。CSMは、UEFIが旧来のBIOSをどのようにエミュレートするかを定めたものです。CSMモードにあるUEFIファームウエアは、旧来のブートローダーを読み込みます。クラス1のUEFIシステムは、ブートローダーに対して開かれていないため、UEFIサポートを全く提供しない可能性があります。これはつまり、BIOSの中でのみ動くUEFIということです。

クラス2のマシンは、UEFIアプリケーションを起動することもできますし、そうでなくてCSMモードで動作するという選択肢もあるというUEFIシステムです。現代的なPCの大多数は、このUEFIクラス2のマシンです。UEFIアプリケーションを走らせるか、CMSモードで動作するかの選択は、BIOSの設定で選択できる場合もありますし、そうでない場合にはBIOSが、起動デバイスを選択後に旧来のブートローダーがあるのか、UEFIアプリケーションがあるのかをチェックする場合もあります。

クラス3のマシンは、CSMモードをサポートしないUEFIシステムです。UEFIクラス3のマシンは、UEFIアプリケーションのみを動作させることができ、旧来のブートローダーに対する後方互換性を提供するCSMモードを実装していません。

セキュアブート

セキュアブートは、以下の4つからなる、UEFIアプリケーションのためのデジタル署名体系です。

セキュアブートをサポートするUEFIファームウエアは、常に以下の3状態のうちの一つにあります。

セットアップモードでは、あらゆるUEFIアプリケーションが、PKやKEK・db・dbxのエントリを追加・削除することができます。

ユーザーモードでは、セキュアブートのON、OFFに関わらず、