「ゼロからのOS自作入門」を Rust でやる (第17章)

いつの間にかこのシリーズも10記事を超えていました。 本記事で11記事目です。 難所をいくつも越え、なんとか最終章まで続けられそうな気がしてきました。 頑張っていきましょう。

第17章

FATファイルシステムを扱えるようにする章です。 この章ではFATファイルシステムのルートディレクトリのファイル一覧を出力できるようにします。

FAT ファイルシステムをカーネルから参照できるようにする (day17a)

「ゼロからのOS自作入門」ではファイルシステムの実装にあたり、ブロックデバイスからの読み書きはサポートしていません。 代わりに、メモリの一部分をブロックデバイスと見なし、メモリ上にファイルシステムを構築します。

C++ 版実装では UEFI のブロックデバイス読み取り機能を使い、 OS のブートイメージの先頭部分をメモリ上にコピーすることでメモリ上にファイルシステムを構築していました。

Rust 版実装では、ブートローダーは bootloader クレートを利用しているため UEFI に手を入れるのは面倒です (bootloader クレートを fork しないといけない)。 今回は、build.rs で必要なファイルを含んだFATイメージファイルを作成し、バイナリデータとしてカーネル本体にリンクするようにしました。 カーネルのバイナリサイズが16MiB増加しますが、許容範囲でしょう。

github.com

build.rs の処理の流れは以下の通りです。

  1. FAT ファイルシステムのイメージファイルを作成
  2. llvm-objcopy で上記イメージファイルの内容を含むオブジェクトファイルを作成 (_binary_fs_fat_start というシンボルでファイルシステムにアクセスできるようにする)
  3. llvm-ar で上記オブジェクトファイルを含む静的ライブラリを作成し、成果物にリンクするよう cargo に指示する

当初は16Mi要素のバイト配列を定義した Rust ソースコードを出力し、カーネル側ソースコードから include!() する方式を試していましたが、カーネルのコンパイルが終わらなくなってしまったため、静的ライブラリをリンクする方式に変更しました。

FAT ファイルシステムの作成には fatfs クレート を利用しました。 「ゼロからのOS自作入門」で紹介されていた mkfs.fat や mount. を使う方法と異なり、root 権限が不要になるのが良いですね。

ルートディレクトリのファイルを一覧する (day17b)

前節で追加したファイルシステムからルートディレクトリのファイル一覧を取得し表示するコマンド ls を追加します。

github.com

C++版と同じように実装すれば良いかと思いきや、結構引っかかりました。 というのも、「ゼロからのOS自作入門」ではファイルシステムが FAT32 であることを前提としたいたのですが、 今回 Rust 版でカーネルにリンクされたファイルシステムは FAT16 であったため、構造体メンバのアクセス方法などが大きく異なっていたためです。 FAT の仕様上 FAT32 にできるのはボリュームサイズが 32MiB 以上の場合のみで、今回作成した 16MiB のファイルシステムは FAT12 か FAT16 にせざるを得なかったようです。

仕方がないので、 FAT12/FAT16/FAT32 に対応できるようにしました。 実装にあたり、以下のサイトを大いに参考にさせて頂きました。

ファイルシステムの詳細はできるだけ fat モジュールに閉じるようにして、 terminal モジュールからは詳細をあまり意識しなくて良いようにしようとしています。 まだ抽象化は十分ではない感じなので、これから機能を追加しながら綺麗にしていけたらなあと思います。

まとめ

比較的短い章でしたが、 FAT12/16 でのファイルアクセス方法を調べながらコーディングする必要がありなかなか大変でした。 次章はついにアプリケーションが実行できるようになります。 ユーザーランドのプログラムも rust で書きたいものですが、果たしてうまくいくのでしょうか? 次章もお楽しみに。