OS側で正しくエスケープシーケンスを解釈・実行できていれば、シリアルコンソール上とOSのスクリーン上で同等な表示の変化が起こると考えられる。太字のフォントも利用したかったので、ビットマップフォントを扱えるようにすることに。環境にも適したクレートが既に存在するのでこれを活用することに。今回はab_glyphを用いた。得られた出力をOS上で流してみると、シリアルコンソールとOSのスクリーン上で同じような表示が得られるようになった。2021/10/21デバッグ用に非常に単純なシェルを実装する。入力欄の表示は上で実装したエスケープシーケンスを使うことで簡単に実装できる。入力を受け取るループで実装できる。USBメモリなどのブロックデバイスとデータを読み書きできる必要がある。リアルな世界では、ブロックデバイス側の高速化、それを活かすための接続規格の変化に伴ってホストコンロローラとの通信規格も変化していったようだ。x86版のxv6ではIDEという規格のドライバを実装しているが、現在はAHCI、NVMeと変化している。USBメモリであればUSBドライバとSCSIプロトコルスタックを実装する必要がある。いずれにしても、これら現代的な規格へのドライバを書くのは大変とのこと。Protocolを用いるブロックデバイスをOSが直接制御することは諦め、ブロックデバイスのデータをまとめてメモリ上に読み出すとしている。ブロックデバイスをサポートする形になっていた。実機で動かすモチベは特に無いのと、これなら実装が300行程度で移植を試みやすいのでやってみることにした。実際にはSpecificationをよく読み込んで頑張って実装することになり、機械的な移植とはならなかった。Managerの設定を調整するとすんなりと起動する。2021/10/29上の変更と順番が前後するが、VirtIOブロックデバイスをどこから見つけるか考える。上のどちらもサポートしてない仮想マシン向けxv6のRISC-V版ではMMIOを用いている。Busで実装することにした。Interrupts)https://zenn.dev/link/comments/65e92f406a3b5aMSIについてはMikanOS本の7章で出てきていたが、USBをサポートしなかった関係でPCIも活用していなかったのでここで初めて利用することになる。SDMに記載があるので、これらを必要に応じて読んで黙々と実装を進めていく。以下のブログ記事も非常に参考になった。2021/10/29に更新VirtIOではMSI-Xをサポートしているので、MSI-Xの設定を行えるようにする。APIC上の割り込みベクトル番号への対応付けがなされている。(GitHubにある自作OSの一つ)特にハイパーバイザの作り方の11章は、PCIのおさらい、VirtIOの動機・概要がまとまっていてわかりやすい。Configuration。出来上がった実装だけ見ると、ひたすら所定の操作をやるという感想になってしまう...今回は結局仕様書をひたすら読み込んで実装したので、仕様書との対応でメモしておく。実装がこれに対応する。Configuration構造を通した実装となっている。Configuration構造は、MSI-Xが有効か否かによってレジスタが増えてオフセットが変わったりする点で注意が必要だった。レジスタはMSI-Xを有効にしている場合は使用しない。今回は、xv6-riscvで無効にされているものはorsでも無効にする方向で進めることで考えることを減らした。2021/10/29に更新https://github.com/yubrot/ors/blob/main/ors-kernel/src/devices/virtio/queue.rsVirtqueueの実装。VirtIOではデータの転送にゲスト(ドライバを実装するOS)上のメモリ空間をキューとして用いる。このリングバッファの先頭を示すインデックス値からなるからなる。キューのサイズは初期化後は固定長で、それぞれの領域も以下のように定まる。queue_size初期化のコードは以下のような手続きになる。Configurationを指す。Notification)デバイスからドライバへのデータ転送の受け取りVirtqueueはドライバ側のメモリ空間を使用するため、デバイスからのデータ転送がいきなり始まることはない。Ringの先頭(index)に使用済みのDescriptorのインデックスをセット、indexをインクリメントすることでドライバ側にDescriptorを返却する。別途保持できるようにしている。ためのデータを与える。して、ブロックデバイスへの読み書きの完了通知に使用している。2021/10/29https://github.com/yubrot/ors/blob/main/ors-kernel/src/devices/virtio/block.rsブロックデバイスの実装。なり、やり取りするデータも比較的単純なもので済む。2022/01/12に更新ファイルシステムについて考える前にパーティションについて。(論理ブロックアドレス)LBAとは、ストレージ(外部記憶装置)の記憶メディア上の個々の記憶単位(セクタ)の位置を表す方法の一つで、すべてのセクタに通し番号を付けて先頭からのセクタ数で位置を識別する方式。sectorがそのままLBA値となる。48bitで128PiBまで扱える。フォーマットしていたが、パーティショニングを行う場合はFATのようなファイルシステムはディスクの特定のパーティションに置かれる。Partitionを認識してUEFIアプリケーションを起動する。GPTパーティションを読み取ってそれぞれをブロックデバイスとして上位のレイヤーに提供する等が必要となりそうだ。(パーティションをサポートしない)。2022/01/15またずいぶんと間が空いてしまった...FATの仕様はこのページが詳しい。ファイルシステムFATファイルシステムのコアのデザインは非常にシンプルだと感じた。細部を見ると、互換性の維持などのためにしんどい仕様などを含むが、コアはその名の通りファイルの割り当てを記録するテーブルがあるだけだ。FAT32の実装をベースにFAT12/16に対応する実装も特に問題なく行えるかと思う。実装はors-kernal/src/fs/fat.rsに行った。ボリュームのレイアウトFATはボリュームを「予約領域」「FAT領域」「データ領域」に分ける。「予約領域」にはファイルシステムの重要な情報が集約されている。Tableが格納される。Tableは、単にFATエントリ(後述、32bitの数値)の配列で表現される。[1]「データ領域」はファイルやディレクトリなどのデータ本体が格納される。データは「クラスタ」という単位で分割されている。セクタを束ねたものになっている。4なら、クラスタは連続した4セクタで2048バイト長となる。どのクラスタが未使用かどうかはFATエントリに記録される。各FATエントリは各クラスタと1:1で対応している。なければ、そのFATエントリNに対応するクラスタNは使用中となる。使用有無だけの表現を目的とするならFATエントリに32bitも必要ないはずだ。収まらない場合がある。