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

livaの雑記帳

OSとか作ってみたい

multibootカーネルにおける画面描画

multiboot specification(このブログでは全てv2を指す)に則ってカーネルを作るとブートローダ周りの諸々を手抜きできるのだけど、今回は特に画面描画辺りのHowToを軽くまとめておく。

 

最初にmultiboot specificationのおさらいをしておくと、

 

  • elfでカーネルを書ける
  • 仕様書に規定されている様々なハードウェア情報を勝手にブートローダが集めてくれる
  • 最初からモジュールをメモリに読み込ませたりできる(ディスクドライバがない状態でもモジュールがロードできる)

 

まあ最近はUEFIのお陰でブートローダは凄く書きやすくなったそうなのだけど、それでもmultiboot specificationは良くできているので、余程の事がないかぎりはこれで十分かなーというのが個人的な印象。

multiboot specficationをサポートしたgrubという素晴らしいブートローダがあるので、下周りは全てこいつに任せる事ができる。grubを使えば、BIOSUEFIファームウェアの差を吸収してくれるので、どのような環境でも等しく動くOSが作れる。特にBIOS環境下ではとても便利。

 

さて、multiboot specificationにはframebuffer info(仕様書3.6.12 Framebuffer info)というのが規定されており、画面描画のためのフレームバッファの情報を取得できる。取得できるのは、アドレスと解像度で、下の描画インターフェースがVBEだろうとGOPだろうとUGAだろうと同じように扱える。(描画インターフェースのサポートはgrub側の仕事なのだけど、どれもきちんと動く)

 

f:id:liva_h:20170506165924p:plain

ちゃんと公式のサンプルコードもあるよ。

kernel.c\doc - grub.git - GNU GRUB

 

で、問題はここから。

フレームバッファの情報が取れるのは良いのだけど、ブートローダ側がフレームバッファを使う準備をしない事にはフレームバッファに関する情報が得られない。その辺の設定が抜けていると時間が溶ける。

 

ブートローダはもうgrub2固定で説明する。

まずはgrub.cfgの設定。

 

insmod efi_gop

insmod efi_uga

insmod vbe

insmod vga

 

描画インターフェースのモジュール(つまりデバドラ)をgrubに読み込ませる必要がある。上2つはUEFI環境用、下2つはBIOS環境用。

 

次に、multiboot headerにframebuffer tagを置く。(参考:仕様書の3.1.10 The framebuffer tag of Multiboot2 header)multiboot headerというのは、elfカーネル内に埋め込む、カーネルからブートローダに情報を渡すための仕組み。シグネチャの直後とかに書けばよろし。

f:id:liva_h:20170506171100p:plain

 

これも公式サンプルにある。

boot.S\doc - grub.git - GNU GRUB

解像度は1024x768x32がたぶん無難。もっとデッカイ解像度が良い場合は数字を変えれば良いのだけど、必ずこの数値が使われるわけではないので、注意。(ブートローダの気まぐれとか、インターフェースのサポート状況とかによって低解像度に格下げされる)

この設定を埋め込まないと、ブートローダが勝手にデフォルトの解像度に設定してしまう。UEFIだと一応フレームバッファ(ただし解像度800x600x32)になるのだけど、BIOSだと80x25のテキストコンソールになると思う。

ただまあぶっちゃけテキストコンソールの方が便利だとは思う。UEFIではこれが削除されてしまって、自力でテキスト描画しなければならなくてちょっと不便。

 

ちなみに、自分でフォントを画面描画するなら、grubのpf2フォントを使うのが便利。普通にインストールすると /boot/grub/fonts/unicode.pf2 というのがあるはずなので、こいつをmoduleとして読み込んで、解析すればよろし。

raphine.hatenablog.com

 

こんな感じで描画される。

 

 

最後に、参考までに僕の自作OSのgrub.cfgを載せておく。

github.com