読者です 読者をやめる 読者になる 読者になる

借り初めのひみつきち

仮ブログです。

640K ought to be enough for anybody

EFI 環境でレガシー OS を起動しようと企むときに特に致命的な、リアルメモリに空きがないとなぜ困るのかについて詳しく検証していきます。

リアルモードとコンベンショナルメモリ

EFI 採用前の BIOS で動作していた PC は、リアルモードというモードで起動します。 これはあらゆる OS に共通する PC の基本的なルールのひとつです。

リアルモードは高速な 8086 互換 CPU として動作するモードで、演算器の基本的なデータサイズは 16bit、アクセスできるメモリ空間の最大サイズは 1MB でした。

この 1MB のうちの前半 640KB はコンベンショナルメモリとも呼ばれ、リアルモードで動作するプログラムの通常使えるメインメモリ領域でした。

1MB の残りの後半の領域には VRAM、BIOS や拡張 ROM が配置され、この狭い 1MB の世界がリアルモードのプログラムにとっては世界のすべてでした。

BIOS から起動された OS もリアルモードの 1MB の世界で動くので、コンベンショナルメモリは OS にとって自由に使えるのが当然でした。

様々な理由*1によって実際にコンベンショナルメモリの 640KB すべてを自由に使える環境は存在しませんが、それでも 600KB 以上の連続した空きメモリ空間があるのが普通でした。*2

EFI とコンベンショナルメモリ

EFIBIOS やリアルモードの制約から解放されるために、16bit の世界にとらわれないように設計されました。リアルモードのメモリ空間という制約もなくなり、コンベンショナルメモリを開放しておく必要性がなくなりました。

EFI 環境ではコンベンショナルメモリがあった領域に謎の予約領域がある場合があります。 EFI が動作している間は EFI が全てのメモリを管理しているので、予約とマークされてる領域を他のプログラムが勝手に使うことはできません。

つまり、そのままではリアルモードの OS を動かすために十分な領域が空いているとは限りません。

ExitBootServices の罠

ExitBootServices API を呼び出せば EFI の管理下から外れますが、おそらくこの謎の予約領域は移動してはいけない予約属性になっています。

この領域が実際に何に使われているかは機種に依存するので、その機種専用なプログラムならともかく汎用的なプログラムで勝手に使うのは危険です。 この領域を避けるようにメモリをマッピングすることが可能な機種もありますが、十分な量のコンベンショナルメモリを確保できる確実な手段はありません。

そして、 ExitBootServices を呼び出した瞬間、 EFI のドライバは原則使えなくなります。

EFI 搭載機はレガシーフリーということを思い出してください。 PC の時代に当たり前のようにあった、キーボード、グラフィックス、ディスクといった基本的な I/O の多くは、そこに存在しません。

解決編

ひとつの解決方法に、 EFI ドライバで動く PC エミュレーターを作るという手段があります。 これならレガシーフリーの機種でも DOS 程度の OS なら起動します。

ただ、 EFI ドライバ自体 OS 起動するまでの最低限の動作ができればいいという感じの作りのものが多いので、実用に耐えるものを作るのは難しそうです。

*1:割り込みベクタテーブル、BIOS作業領域、ACPI予約領域等で少し持っていかれる

*2:ただし最初期の PC の搭載メモリはもっと少ない