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

借り初めのひみつきち

仮ブログです。

はりぼてOSをUEFIで起動する/総集編

UEFI haribote HALO

この記事は 自作OS Advent Calendar 2016 - Adventar の4日目の記事です。

BIOSUEFI

古きよきPCにはBIOSが搭載されていましたが、さいきんのPCにはBIOSの代わりにUEFIが搭載されています。

BIOSは初代IBM PCと一緒に生まれ、16bitコードで記述されていて、x86に強く依存し、使うにはアセンブリ言語の知識が必要でした。
さらに拡張のために様々な継ぎ接ぎをした結果、酷く扱いにくいものになってしまいました。

UEFIはIA64の開発時にIntelが設計したEFIが元になってて、x86の依存がほとんどなく、32bitや64bitのC言語から扱えます。
BIOSよりも豊富な機能を備え、拡張性もBIOSより柔軟に設計されています。

PCの歴史は互換性の歴史なので限界に近づきつつも仕方なくBIOSが使われ続けていましたが、HDDの容量が2TB超えてBIOSの仕組みではうまく扱えなくなってきた事などから次第にUEFIの移行が始まり、さいきんのコンピュータはほとんどがUEFIで動くようになりました。

ちなみに、UEFIBIOSと全く互換性がないので、CSMというモジュールを搭載してBIOS互換モードに切り替え可能な機種もあります。

はりぼてOS

はりぼてOS (http://hrb.osask.jp/) とは、「30日でできる! OS自作入門」という本で作られるはりぼて的なOSで、たった数十KBのカーネルGUIまで搭載しています。
これをもとに独自の改造をした自作OSがたくさんあります。

UEFIが一般的になる前に作られたものなのでUEFIには対応していません。

EDK と gnu-efi

UEFIで開発するには開発キットが必要になりますが、代表的な開発キットには標準のEDKや、Linux等で使えるgnu-efiがあります。

EDKのメリット

  • 標準で使われている
  • 標準のAPIを呼び出せる
デメリット
  • 環境構築が大変

gnu-efi のメリット

  • Linuxでは環境構築が簡単
デメリット
  • MSとGNUのABIが異なるため、変換のために uefi_call_wrapper というラッパーが必要になり、標準のAPI呼び出し方法が変わる
  • uefi_call_wrapper の仕組み上引数のチェックができない

筆者はEDKの環境構築に挫折してながらく UEFI の開発に取り掛かることができませんでしたが、 gnu-efi の存在を知って簡単に環境構築できたので以後 gnu-efi を使って開発しています。

はりぼてOSをUEFIで起動する

表題の件になりますが、結構簡単です。
はりぼてOSの起動に必要なbhsファイルとimgファイルを読み出して所定のアドレスに配置したらカーネル初期化コードを呼び出すだけです。
UEFIのお約束として カーネルを起動する直前に ExitBootServices という API を呼び出して UEFI が管理するハードウェアを OS の管理下に移す作業が必要です。
ここまでほぼすべてC言語で記述することができますが、UEFIははりぼてOSとは異なるCPUモードで動作しているのでカーネル起動の前にCPUモードを切り替えるためのアセンブリ関数があります。
あとはライブラリ関数のいくつかを自力で書く必要があったのでそれもアセンブリで記述しています。

bhsファイルというのははりぼてOS系のOSでOS切り替えをサポートするための特殊なカーネル形式で、初出は advance/osselect - hrb-wiki にあります。
実態はカーネルのビルド中にできる bootpack.hrb というファイル(またはそれに相当するファイル)、あるいはそれを tek 形式で圧縮したものをリネームしたものです。
今回作ったものは両方の形式に対応しています。

imgファイルはフロッピーディスクイメージです。ビルドでできたものをそのまま使います。

ここまでの作業でほとんどのはりぼてOS系OSの起動はできます、起動は。

gnu-efi の罠

gnu-efiAPI呼び出しにラッパーが必要になる仕組み上、コンパイラが引数をチェックできません。
一部の機種でどうしてもうまく動かない事があって詳しく調べてたら、一部のAPI呼び出しの引数が間違っていました。
しかし、なぜか問題なく動く機種もあったので発覚が遅れてしまいました。

グラフィックスモードの問題

UEFI は GOP というプロトコルを使ってグラフィックスを扱いますが、 GOP は 32bit カラーしかサポートしていません。 UEFI の仕様上は 32bit 以外の形式もサポートできそうな気がしますが、 WindowsUEFI 要件が 32bit BGR 形式を要求しているためほとんどの機種はそれに従っています。

一方、はりぼてOSのオリジナルは 8bit のパレットカラーしかサポートしていません。
亜種がたくさんあった時期には16bit カラーモードをサポートしているものが多数ありました。 advance/VESA - はりぼて友の会
VESA BIOSは 24bit カラーと 32bit カラーの扱いが微妙で対応が面倒だったこと、多くのケースでは16bitと32bitで体感できるほど品質の違いがなかった事などから32bitカラーに対応したものはほとんどありませんでした。

そのため、ほとんどのOSは起動はできても残念ながら画面が正常に描画されません。

レガシーフリーの問題

BIOSの時代は過去との互換性のせいで完全にレガシーフリーな機種というのはなく、つい最近まで物理的にPS/2ポートがなくなった機種でもPS/2エミュレーションがサポートされていました。

しかし、UEFI搭載を機にこの流れが変わろうとしています。
UEFIになって過去のOSが起動できなくなったことから、多くのレガシーサポートが切り捨てられています。

はりぼてOSの時代はPS/2ポートが存在するのが当たり前でしたが、現代のPCはPS/2をサポートしていない機種のほうが多いため、それらの機種では一切操作できません。
さらに、I/Oポート自体が存在しなくなっている機種もあり、PS/2ポートの応答待ちでフリーズしてしまいます。

更に過激なのがHyper-VUEFIモードで、なんとPICも存在していません。
そのため、起動中に割り込みがうまく処理できずに強制リセットされます。

ちなみに、一部のOSでBIOSを呼び出している高度なものがありましたが、UEFI環境では呼び出す先のBIOSがそもそも存在しないのでこれもうまく動作しません。

総評

起動自体はそんなに難しくなかったはりぼてOSでしたが、UEFIで環境が変わりすぎてそれに対応できてない部分が多く、実機で自作OSを動作するハードルは年々上がっているなぁと感じました。