『ゼロからのOS自作入門』Rustで5章までやった記録
先月発売された『ゼロからの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環境だと厳しい話が他にも出てきそうだけれども、可能な限り自力でやっていこうと思っている。