FatFsの移植(FD書き込みの挫折) — 自作OS

今度はFDDへの書き込みのためのdisk_write()、disk_ioctl()を作成する。
テストのために、フロッピーディスクイメージの空きセクタへ1セクター書き込むアセンブラのサブルーチンを作成し、writefdという簡易コマンドを作成して、バイナリエディターでフロッピーディスクイメージの指定したセクタへデータを書き込んでいるかテスト確認してから、FatFsへ移植することにした。

FDDへのDMA転送設定は、DMA回路のモードレジスターへの設定値を変えるだけなので、read用の関数をコピーし、5分で修正できた。
FDDへのWRITE-DATA(0x05)の制御コマンドのシーケンスもREAD-DATAと同じような流れで、IRQ6割り込み待ちとSENSE INTERRUPT STATUSコマンドの送信など、ほとんどコピーし、違いとしては、コマンド処理ステータスのST1のNW-bit(bit1)がフロッピーディスクが書き込み禁止であることを通知するためにONになるので、それをエラーチェックすることぐらいしかなかった。そんな風に、disk_write()は三時間ほどで簡単に作成できた。テスト用書き込みコマンドを作成し、指定したセクターへ設定したデータを書き込むことを確認した。
disk_ioctl()は、ドライブ情報得る時やフォーマット操作をする時など、ディスク操作関数の内部で使われるらしい。ブートモニターにはフォーマット機能をもたせる必要がない(起動ドライブの自分自身を消去することになる)ので、最低限の処理だけならドライブ情報を通知するだけで、簡単に作成できた。

作成中に思わぬコンパイルエラーが発生した。今まではFatFsをリードオンリーの最小構成でビルドしていたのが、リード/ライトに設定変更したら、stdarg.h、math.h、string.hのstrlen()が存在しないというエラーメッセージだった。math.hはf_printf()で浮動小数点処理を組み込むようになっていたからで、それを取り外した。strlen()は64bitサイズの変数を扱うためで、また新たに作成しても良かったがlonglong型を使うことはないので、これもffconf.hの設定を変更して、64bitサイズを組み込まないようにした。
問題はstdarg.hで、初めて見るヘッダファイルだが、va_listやらva_startやらva_argとかの関数を提供しているらしかった。調べてみるとprintf()やscanf()など引数の個数が可変の関数のためのマクロ定義だと分かった。gccの内部で対処できる事前定義された処理なので、ヘッダファイルをそのまま利用しても問題ないらしかった。念の為、/usr/lib/gcc/——-/stdarg.hを探し出して、中身の正味6行分をリライトして、pseudo_stdarg.hを作成した。それでコンパイルエラーは出なくなった。しかし、今度はリンクエラーが出るようになった。前にも経験した「relocation truncated to fit: R_386_16 against `.data’」で、オブジェクトのサイズが以前より10K-byte以上増えて、0xffffまでの16bitリアルモードのラベルシンボルの範囲に収まらなくなっていた。回避方法を模索してみたが、調べても何もわからず、f_printf()などの関数の動作確認は断念し、DMA書き込みルーチンの検証はできたので、FatFsをリードオンリー構成へ戻した。

メモリマップを見直してみたが、10K-byteを空けるのは難しく、何とか収めたとしても、プログラムの追加や修正をしたら、また同じエラーが出るのは目に見えている。スタック領域として使っている領域も、30K-byte程度しかなく、スタックへローカル変数を大量に確保する高級言語でのプログラミングでは少なめで、削るわけにもいかない。
さんざん考えた挙句、二段階ローディング(?)ともいうべき方法をとることにした。今のブートモニターはリードオンリーだけで機能拡張はせず、16bitモデルのシンボルを含まない32bitプロテクトモードの別個のモジュールバイナリをフロッピーイメージからRAMへロードして、制御をそちらへ全て移す。FatFsのモジュールなどは重複するが、現在の方法ではこれ以上、機能を拡張できないので、もう行き詰まっている。現在のブートモニターはステップローダー(仮称)という名前にして画面表示やコマンド実行などの不要な機能を削除し、32bitプロテクトモードへの変更とプログラムロード機能だけに特化し、0x00010000以降へFatFs(リードオンリー構成)で本番用ブートモニターをロードし、そこへジャンプする。本番用ブートモニターには制限がなくなるので、ステップローダーのメモリ領域も含めて、作業用に利用することができるはずだ。かなり大きな改修だが、自作OSという試行錯誤に必要な試練だと思うことにする。
しかし、8bitから続くx86系CPUは至るところでアーキテクチャーにツギハギ感がある。ARMやMIPSなどは、同じような問題は起こらないのだろうか? とちょっと興味を持った。

ステップローダー(仮称)を作成中に、gnuアセンブラの変なjmp命令の書き方を知った。本番用ブートモニターへジャンプ(ステップローダーへは戻らない)する時、0x00010000という絶対アドレスへジャンプするのだが、movl $0x00010000,%eaxでジャンプ先アドレスを設定して、jmp %eaxだとエラーになる。こういう場合、jmp *%eaxと書かなくてはいけない。ちゃんとgnuアセンブラが、’*’を付けるよう警告してくれる。癖のあるgnuアセンブラのよく意味の分からない古い記述、みたいな書き込みが英語のサイトにあった。まあ、滅多に使うことのない記述だが、覚え書きとして残しておく。

本番用ブートローダーは、16bitのプロテクトモード変更処理の部分だけ削除し、メモリ配置だけ修正して機能はそのままにした。ステップローダー(仮称)から自動でロードされ、最初に再度ハードウェア関連の初期化処理をして、コマンド入力の画面まで表示された、と思ったら、キーボード回路の初期化に失敗した。ステップモニター(仮称)の方でも必要ないのにキーボード回路の初期化をしていたので、そちらを削除したら、ブートモニターがキー入力を受け付けるようになった。何度初期化をしても問題ないと思っていたので、腑に落ちないが、時間がある時に原因を究明しようと思う。ブートモニターでもlsやcatなどのコマンドが正常に実行できた。やれやれだ。次はFatFsをリード/ライト構成にして、フロッピーディスクへファイルを作成しようと思う。

カテゴリー: Linux, VirtualBox, 自作OS パーマリンク

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です