Skip to content
hikalium edited this page Jul 10, 2016 · 5 revisions

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でコンパイルされていますが、すでにビルド済みのイメージが利用可能です。)

Clone this wiki locally