GPD Pocketでの動作。
GPD Pocketでは横倒しになるのをなんとかしたい

先月発売された『ゼロからのOS自作入門』(通称みかん本)を読みながら、Rustで実装してみている。途中まではrmikanと呼んでいたけれど、自分のやる気を出すためにLaranjaOSと名付けた。laranjaはポルトガル語でオレンジの意味だ。

3月22日の発売日によみはじめて、ほぼ4週間でようやく5章相当のところまでできた。Consoleの実装を行い、printマクロも実装した。MikanOSに合わせてtagをつけているが、試行錯誤が含まれているし、「Makefileを使ってみる」のような部分は飛ばしている。

以下、ここまで実装する上での試行錯誤をメモしておく。

UEFIアプリケーション

みかん本2章ではEDKⅡを使ってUEFIのアプリケーションをCで実装する。私はRustのUEFI API wrapperであるuefi-rsを利用した。これを使えば、UEFIアプリを書くこと自体はかなり簡単になる。ただ、みかん本2.6「メモリマップのファイルへの保存」で出てくるOpenProtocolがuefi-rsには実装されておらず、UEFIなにも知らないのでそこでしばらく引っかかった。uefi-rsではLocateProtocolが実装されているので、それが利用できた。

kernelのビルドで停滞

3章からは別途ビルドしたkernelを読み込むところから始まる。これにかなりハマった。

image-baseの設定ができないなど、リンカ設定ができない

そもそもldにどうやって渡せるかわからないところからのスタートだった。ここにずいぶん時間を使ったが、LLVM 11のld.lldを使うことで、macOSでもLinuxでも動作するようになった。最終的には全ての設定をカスタムターゲットに入れた。

呼び出せない

asm!("hlt")だけのkernelもUEFIアプリから呼び出せない。ここにもかなり時間を使って、途中で投げ出しそうになった。が、わかってしまえば簡単だった。targetがx86_64-unknown-uefiだと、extern "C"がUEFIのABI(= WindowsのABI)になってしまう。このため、普通にextern "C"にしたカーネルのentryが呼び出せない。extern "sysv64"にするか、kernelのentry pointをextern "efiabi"にすると動く。私はextern "sysv64"にしている。

kernelが動くようになってから

placement new (配置new)

みかん本4.3「C++の機能を使って書き直す」ではピクセル書き込みのクラスを、配置newを使ってstaticな領域に置く。この時点では必ずしも必要ないので私は実装せずに済ませていたが、printマクロ実装時にはstaticなstructが必要になった。しかし、Rustには配置newに相当するものはない。

当初は[u8; size_of::<TheStruct>]static mutな変数にコピーしていたが、Mastodonで教えてもらったMaybeUninitを使うように変更した

sprintfは実装していない

みかん本5.4「文字列描画とsprintf()」のsprintfは現時点では実装していない。Stringが使える環境ならwriteln!を使えば済むが、nostdでアロケータもないのでStringが存在しない。現時点では、文字の位置や色を指定したWriterをwriteln!で使うか、Consoleクラスを使ったprintln!は実装しているが、文字列にフォーマットして書き込むものはない。

フォント

みかん本5.3「フォントを増やそう」では、ASCIIのビットマップのテキストファイルからオブジェクトファイルを生成してリンクする方法をとっている。私は元のビットマップを描いたテキストファイルをsedなどで変形した上でRustのコードに変換して、それを使っている。

これから

みかん本6章は「マウス入力とPCI」。ここのUSBドライバは、著者提供のものをそのまま使うことになっているが、フルRustでやるつもりならそれはイチから書く必要がある。さすがにそれはキツそうだ…と思ったら、先人がすでにいた。参考書として挙げられていた『USB3.0ホストドライバ自作入門』は、みかん本著者による技術同人誌だ。私も自分で書く努力をしてみるつもりだ。rust-osdevのxhciクレートも利用できるかもしれない。

Rust + nostd環境だと厳しい話が他にも出てきそうだけれども、可能な限り自力でやっていこうと思っている。