フロッピーディスクから読み込みできるようになったが、未だFatFsの移植に至らず、、、 — 自作OS

FATファイルシステムは既に、Linuxで当たり前に使えるし、フリーのソースファイルもいくつかある。それと、LNF(長いファイル名)はMSの特許があって、ライセンス料を払う必要がある、、、かと思ったら、ライセンスはもう期限切れだという情報があった。Linuxのvfatは長いファイル名を使えるのはそれが理由なのかもしれない。とにかく、自前で作るのは最初から諦めて、FatFsという日本人が開発したモジュールを移植することにしていた。

そのために、FDD関連の低レベルI/Oを操作するアセンブラプログラムのソースファイルFDD_IO.sを追加したら、ブートセクターがブートモニタープログラムをロードした後、ブートモニタープログラムへ制御が移らなくなった。FDD_IO.sを削除すると、うまくいく。Makefileを調べてみたが、おかしい所はない。make cleanでまっさらにして、作り直しても、FDD_IO.sがあるとイメージファイルは問題なく構築するが、実行時にブートモニターへのljmpの先から動かなくなる。数時間、悩んだ末、makeした時の、リンカーldのオブジェクトの並びを見ていて、ブートモニターのメインルーチンのオブジェクトの前に、FDD_IO.oが割り込んでいることに気付いた。試しにファイル名を小文字に変えてみたら、アスキーコード順のソートの影響か、メインルーチンのオブジェクトが最初にリンクされるようになって、うまくいった。
これはmakefileでの指定で回避できるのか、例えば@をメインルーチンの名前に入れたりすることで回避できるのか、あるいはリンカーの設定ファイルで指定すれば発生することがないのか、よく分からなかった。とりあえず、今は時間がないので、Makefileのリンカーの設定を、「${TARGET}.o ${filter-out ${TARGET}.o,${filter %.o,$^}}」という感じでオブジェクトファイルを展開するようにしたら、先頭にメインルーチンのオブジェクトがくるようになった。取り合えず、これでやり過ごすことにした。

FDD関連の回路の初期化で、PICの割り込みのIRQ6を許可し、初期化処理でドライブAをリセット。FatFsの低レベルレイヤーとして、3つの関数を作成しなければならない。DMA転送のために、0xf000をバッファとして使うことにし、DMA回路のレジスタの設定をしたところ、思わぬ不具合が起こった。ブートモニターが思わぬところで止まってしまう現象だった。ブートモニターのロジックをあれこれ修正しても駄目だった。
不意に思い付いて、ブートモニターのバイナリのサイズを調べてみたら、いつの間にか、ブートプログラムのサイズが16K-byteを越えていた。ブートセクターでは機械的に16K-byte分、フロッピーからブートモニターのプログラムを0x7c00へロードしていたのだが、プログラムの途中までしかロードされず、実行時に暴走していたらしい。C言語などの高級言語で作成する際の典型的な失敗で、グローバル変数や参照用のテーブル情報を何も考えずに作成していたら、大して長くもないプログラムでも、データサイズだけが肥大化してしまうのだ。ローカル変数を多用する場合も同様で、スタック領域を大きめに取らないとオーバーフローして、解析の難しい実行時の不具合が発生することになる。取り敢えず、自作OSは実用性より「動くこと」を優先することにして、ロードサイズを32K-byteに増やすことで対応した。

それからずっと、FDDアクセスが全くできない状態が続いた。FDDの初期化処理でFDコントローラーをリセットすると、バッファクリアなどしてモーターを有効にした後、割り込みIRQ6が発生するはずなのだが、どうしてもIRQ6の割り込みハンドラーのプログラムを実行してくれない。VMwareでためしてみたが、タイムアウトが発生するタイミングは違うが、やはりエラーとなる。FDDとは直接関係ないPICの処理が不十分で、IRQ6が発生していないのではないか、それで、無限ループでストップするか、タイムアウトでエラーになるということではないか、確証はないが、現象的には間違いないように思って、PICの設定を試行錯誤で変えてみた。しかし、どうしてもIRQ6の割り込みハンドラーが実行されない。この問題で一週間以上、悩み続けた。
原因は単純なことだった。PICやキーボードコントローラーやフロッピーディスクコントローラーはメインルーチンの冒頭で、ハードウェア初期化処理をそれぞれ行うのだが、回路への設定中に意図しない動作や割り込みが発生しないように、CLIで割り込みマスクをした状態でI/Oアクセスをしなければならない。ところが、フロッピーディスクコントローラーは初期化処理のシーケンスの中で回路リセットを行った時に、IRQ6の割り込みを発生させ、プログラム側はそれを待たなければならない。つまり、CLIの状態で割り込みが起こっても、割り込みハンドラーは起動されないので、リセットしても無限ループかカウンターを付けてもタイムアウトでエラーとなってしまっていた。FDDコントローラーの初期化ルーチン内で一時的にSTIで割り込みを許可し、ルーチンを抜けるときにまたCLIを実行するようにしたら、無事に割り込みハンドラーの処理が行われるようになった。これに気付いたときは、身体から力が抜けて溜息が出た。

それにしても、ディスクアクセスの操作は、レジスタの設定やコマンド転送待ちや、割込み処理、ドライブの機械動作の考慮などが入り乱れて、馬鹿みたいに複雑だ。フロッピーの発展の歴史的経緯もあるかもしれないが、どうやっても正解がなく、試行錯誤でターゲットマシンで動作するように調整しながら作成するしかない気がする。私の場合は、FDDの実行ファイルをメモリにロードして実行制御を移すまでしか、ブートモニターを機能を持たせることは考えていないが、ディスク操作の実装で挫折した人が多いのではないかと思う。

それからまた、フロッピーからRAMへ1セクターだけロードするコンソールコマンドを作成しようとしたが、ディスク操作は、コマンド送信フェーズ、実行フェーズ、結果フェーズの三段階の手順が必要であり、データをリードする時は、8bit I/oレジスタへ9バイトのコマンドとパラメーターを書き込んで、IRQ6の割り込みをウェイトし、ステータスの6バイトを8bit I/Oレジスタから読み出して多項目のエラーチェックをしなければならない。作成するだけで、一週間以上かかった。
しかし、何とかIRQ6の割り込み待ちをして、正常終了するまで辿り着いたのに、フロッピーのデータが0xf000のバッファへどうしてもロードされない。DMAは発生しているらしいが、RAMへ書き込まれていないように見えた。試行錯誤を繰り返し、思いつくことを全て試してみたところ、参考にしているホームページで、「利用しない場合は特に関係ない」と書かれていた拡張ページアドレスレジスタへ、ダミーで0x00を書き込んだところ、RAMへフロッピーのセクターのデータを書き込んでくれた。
参考にしたホームページでは、0x00000000から0x0000ffffまでの64kバイト以下のDMA転送のサンプルで、ベースアドレスレジスターとベースワードカウントレジスターだけ設定していたので、私も同じことをやっていて、拡張ページアドレスレジスターへのアクセスは意味がないと思いこんでいた。もう止めようかと考えていたところでもあり、びっくりした。このためにまた一週間は浪費してしまった。この一ヵ月近くは、まさに信じる者は自分しかないという、悪戦苦闘だった。挫折の記録として、残しておく。

カテゴリー: Linux, VirtualBox, 自作OS | コメントする

コマンドラインでのコマンド実行。echoとmemdmp — 自作OS

コマンドラインに文字を入力できるようになったので、今度は入力文字列を解析して、簡単なコマンドを実行できるようにした。その時、文字列を区切ったり比較するstrtokとstrcmpがないことに気付き、慌てて処理関数を作成した。その過程で、strlenも作ることになった。それほど難しくはないが、細かい部分で色々と配慮しなければならないことが多く、当たり前に使っていた関数が、どんなロジックを持っているのか考えさせられて、先人の知恵に感心した。コマンドを切り出して、コマンド文字列を確認し、対応する関数のポインタで関数を実行するC言語特有のテクニックを使ってみた。コマンドはコマンド文字列と実行関数を配列のテーブルとして設定しておいた。

echoは引数の文字列をそのまま画面表示させるだけなのですぐ完成した。memdmpは先頭アドレスだけ指定して、16バイト*16行だけ表示するようにした。80列x25行のテキストモード画面では、それ以上表示させようとすると、画面から上へはみ出てしまうためだ。無制限に表示させるには、画面表示を高機能に作り直して、スクロールバックの機能を実装しなければならないが、ブートモニターでは、そこまでするつもりはない。

(2022/12/09 追記)コマンドラインで「?」を入力すると、内部コマンドを一覧表示する機能を付け加えた。コマンドの配列テーブルを順番に、コマンド名を表示するだけなので簡単だ。

今回は三日ほどで、作ることができ、順調だ。次は、FATFSというフリーのファイルシステムを移植しようと思っている。これができれば、フロッピーディスクから実行プログラムファイルを読み込んで、実行することができるだろう。(厳密なメモリ管理をせずに、小さいプログラムを一つだけ実行するだけ。現状はシングルタスクなので、複数のプログラムをRAMへロードする必要はない)

カテゴリー: Linux, VirtualBox, パソコン, 自作OS | コメントする

システムイベントFIFOとスキャンコードの文字変換ルーチンを作成した。 — 自作OS

キーボードやタイマー、マウス操作などの割り込みハンドラで入力されてくる情報を、システムイベントという概念で一括りにして、全てを一つのFIFOに登録していき、メイン関数で区別して処理することにした。マルチタスクではないので、FIFOへ登録された順序で一つずつ処理していく。

キーボードのハード的な機構は、どうも昔からほとんど進歩してないようで、キーボードコントローラーの8042回路の状態が一々コマンドを書き込めるかをポーリングでチェックしてからになり、アセンブラで作ると、簡単な内容の割にかなり長いプログラムになってしまい、PS/2キーボードコントローラーの仕様が変に複雑で理解するのが大変で、初期化ルーチンを作るのに数日かかってしまった。
理由としては、readとwriteになぜか0x60と0x64の二つIOアドレスがあり、コマンドを書き込む時や、データを読む時にどちらのIOアドレスへアクセスすればよいか、理屈が全く分からなかった。断片的なサンプルを見て、推測して何とか動いているが、本当に正しいロジックなのか今も自信が持てない。特に、キーボードコントローラーへコマンドを書き込んだ後に、ACK(0xFA)がアウトプットポートへ返ってくるのだが、ネット上のサンプルプログラムには、ACKを待たないものもあり、おそらくそのままでは正しく動作しないと思う。意図的なのか、気付いてないのかは分からない。私自身のアセンブラプログラムでは、インプットポートへコマンドを書いたら、必ずアウトプットポート(0x60)をチェックして、0xFAが返ってくるのをチェックするようにしている。しかし問題は、ACKが返ってこない場合があって、制御バイトを読み出す要求コマンドの場合は、ACKではなく、制御バイトの設定情報がすぐに戻ってくる。つまり、どんなコマンドを書き込むかによって、操作シーケンスが変わってしまうので、自分で一つ一つ確認しながらプログラミングしなければならなかった。「マニュアルや仕様書には間違いや嘘が書いてあるから、最後に頼れるのは自分の判断力だけ」という黎明期のプログラマーの格言は今も生きているようだ。
また、モニタープログラムの初期処理で、キーボードコントローラーをリセットして、キーボードコントローラーの内部バッファをクリアしておかないと、ゴミデータをポートから受信してしまう可能性もある。それなのに、ネット上のサンプルはそんなことを全く考慮していない。まあ、参考情報なので文句は言えないが、簡単なことなのに、キーボード回路の初期化処理と、割り込みハンドラ、システムイベントFIFOも含めて、一週間以上かかった。

キーボード入力は、ブートモニター(OS)側でキーボードの状態遷移を常に把握して、大文字と小文字の判別、BSキーのカーソル移動、Shiftキーの状態変更などをしなければならなかった。キーボード回路から現在のCaps-lock状態などを読み取ることができないためだ。過去の経緯でこのような作りになっているのだろうが、これらの処理はキーボードを少し高機能化して、Caps lockとかNum lockとかの状態通知と、直接に文字コードを伝達してくれればいいのにと思う。取り敢えず、BOOT_INFOのキーボード状態を参照して、C言語のメインルーチンで、caps-lockがされたとか、shiftが押された状態を保持して、モニターのプログラム側でコントロールするしかない。これもキーボード側で状態通知をしてくれれば、かなり楽になると思うのだが、昔からの互換性の問題があって難しいのだろう。

不思議な現象にも悩まされた。エンターキーを押すと、スキャンコード以外に、0xE0というデータがキーボード割込みで入力されてきて、これはスキャンコード一覧にも載ってない。仕方がないから、無視して読み捨てにしているが、自分が何か間違った設定でもしているのではないかと、心配ではある。

それと、作り始めてから気付いたが、キーボードにも種類があり、今はVH-AD3S proのノートパソコン用で作成しているが、ノートパソコンは84キー型、デスクトップパソコンでは109キー型などで、所謂キーマップを別々に用意して、初期化処理で切り替えるようにしておかなければならない。現段階では必要ないが、拡張できるようなデータ構造とプログラミングをしておいた。また、フォントが対応してないので、表示はできないが、「かな」の入力にも対応できるようにした。

とにかくこれで、コマンドラインでの文字入力ができるようになったので、メモリダンプとか、デバッグに役立つような実行コマンドを作成しようと思っている。

カテゴリー: Linux, VirtualBox, パソコン, 自作OS | コメントする

テキストモードのコンソールへキーボード入力(スキャンコード)を表示するようになった。– 自作OS

ブートモニター側で、ブートセクターで設定したテキストモードの画面をそのまま引き継いで、文字列表示や入力コンソール位置を操作するモジュールを作成した。そのためにブートセクターから設定値を伝えてもらうBOOT_INFO領域を確保し、VRAMアドレスや行数などのハード的な情報を得られるようにした。その時にドツボに嵌ったのが、文字のアトリビュートの設定で、文字色は4bit、背景色は3bit、文字の点滅(ブリンク)は1bitで指定するのだが、文字色と背景色でビット数が違うのは変に思っていたのだが、カーソル表示で文字を反転表示で点滅させようとして、文字色は黒、背景色は明るいグレー、ブリンク=ONで設定していたが、点滅をしないどころか、反転表示にもならず、四角い白になってしまった。いろいろプログラムの仕方や条件を変えて試したところ、ブリンクと背景色の設定は両立しないらしいという結論になった。ネット上のどこにもそれを明確に書いた情報はなかったが、条件を変えて試した限りでは、そうなっている。私の誤解なのかもしれないが、現時点ではブリンクを諦め、白黒反転させるようにした。これの試行錯誤だけで四日も掛かってしまった。

次はキーボード入力をFIFOへデータ格納していって、Enterキーでコンソール実行ルーチンを呼び出す、という感じに作成してみることにした。これが良いとか効率的とかいうわけではなく、ただ、こんな感じ? みたいな思い付きのままに作成している。学びながら遊ぶ感じだ。

キーボード入力を可能にするには、プロテクトモードのためBIOSが使えず、割り込み処理ハンドラーとそれに対応するIDTを作成する必要がある。また、外部割込みのため、PICの設定をするのだが、書籍やネットでもPS/2キーボード入力となっていて、今時、PS/2キーボードとかPS/2マウスとか誰も使ってないと思うが、USBドライバを実装しないといけないのだろうか? と心配になったが、互換性のためにマザーボード内で、エミュレーションしてくれる、と書籍の余り目立たない所に、書いてあった。

PICにPS/2キーボードの割り込み設定をして、試してみたが、IDTのキーボード割り込みハンドラーのディスクリプタの設定ができず、またドツボへ嵌ってしまった。
割り込みハンドラーのアドレスは、上位2バイトと下位2バイトを分離して、別々のフィールドの情報としてディスクリプタへ設定しないといけない。ほとんど全てのサンプルはC言語で記述しているが、私は軽い気持ちでGNUアセンブラで記述したのだが、「invalid operand: (中略)”>>”」と同じく「invalid operand: (中略)”&”」、というエラーが出て、原因が全く分からなかった。問題となっていた個所は、割り込み処理ハンドラーのラベルから上位アドレスと下位アドレスを計算している個所で、「ivt_adr_H=.>>16」と「ivt_adr_L=.&0x0000ffff」だった。二日試行錯誤して悩んだ挙句、「ivt_adr_H=./(0x10000)」と「ivt_adr_L=.」に変更したら、アセンブルエラーが出なくなった。明確な原因は分からないが、C言語で普通に何気なく記述する算術式は、アセンブラでは同じようにはサポートされてないようだった。右ビットシフトは2で割るのと同じだから、2の16乗の値で割るという代替案だ。上位ビットをゼロマスクする代替方法は思いつかなかったので、.wordで2バイト領域に設定する時、自動で下位2バイトだけ格納してくれるのでは? と思ってそうしたが、思ったようにはアドレスをIDTへ格納してくれなかった。
ラベルはアセンブルの時点では値が不定で、リンカーで計算する。アセンブルの時点で値が決定できている場合にしか”&”とか”>>”は使えないらしい。しかし、上記のように除算”/”はできる(後になって分かったが、エラーにならないだけで除算した値は設定されなかった)のだから、一貫性がないようにも思えるのだが、仕方ない。ネット上のサンプルプログラムや書籍もC言語(あるいは、nasm)で記述しているのは、GNUアセンブラの機能が貧弱というか、C言語なら簡単にできることができないという制限があるからではないかと思う。
仕方がないから、固定値部分だけ設定してアドレスは0x0000のIDTの領域だけ確保し、わざわざアセンブラのサブルーチンを作って、ラベルアドレスのLowとHighをそれぞれ下位2バイト、次にshrl $16で右シフトした値を、IDTディスクリプタに書き込むようにした。

PICはIBM-PC互換機のマザーボード内部でエミュレートしていることが分かり、キーボードとマウスについては、昔ながらのレジスタ操作で問題なく設定できるはずなのだが、ここでかなり思考がこんがらがり、悪戦苦闘した。その結果、私はPICの設定とキーボードコントローラーの操作を繋がりのあるハード操作だと思い込んでいたことに気付いた。それで、PIC回路のプログラミングとキーボード回路のプログラミングは完全に別のこととして割り切って、それぞれで理解と作り込みをすることにした。書籍でもネットでもPICとキーボードコントローラーの説明が入れ替わりに交互に絡み合い、それが、私の場合、理解の妨げになった。
一旦、時間をおいて、まずPICの初期化処理を作りIRQ1だけ許可し、割り込みハンドラはhltしてIRETするだけのもので、IDTを作成し、CPUへ再設定(lidt)した。この時点で、それまで作っていた画面への文字表示の後、hltで停止した状態で、何かキーを押すと、回復不可能なエラーでクラッシュしたが、とりあえずキーを押すと割込みが発生することだけは確認できた。IDTや割込みハンドラの間違いをチェックして、割込みハンドラ内でhltするようにしたら、とりあえずクラッシュしなくなった。次にキーボードからの入力(スキャンコード)を画面への文字表示をさせるために、バイナリを16進数文字列へ変換するサブルーチンを作成し、テキスト画面へ文字表示するようにした。キーを押すごとに16進文字列が表示されたので、少なくともPICと割り込みハンドラーの処理は正しいことは確認できた。
ちなみに、PICの設定でIRQ1だけ許可したら、初期化処理中にクラッシュした。思い付きで、カスケード接続されているIRQ2も許可したら、クラッシュしなかった。理由は不明だが、PS/2マウスはスレーブ(IRQ2)へ接続されているので、その関連の仕様で、過去の負のレガシーみたいなものかもしれない。

ここまでで十日間近く掛かっているので、一休みして、FIFOへスキャンコードを入力していって、メイン関数でアスキーコードの文字列に変換してから、テキスト画面へ表示するようにする予定だ。その先は、FIFOからの文字列から、コマンド解析を行って、コマンドの実行を行う機能を作ることになる。テスト的にechoコマンドの実行ルーチンを作ってみようと思う。

カテゴリー: Linux, VirtualBox, パソコン, 自作OS | コメントする

C言語の組み込みで、ブートモニターのオブジェクトのリンクエラーに悩まされた。 — Manjaro Linuxにi686-elf-gccをビルドした。

gccのオプションに-cと-m32を入れて、C言語の簡単なテストプログラムをブートモニターへ組み込んで、オブジェクトを作成したのだが、アセンブラのオブジェクトとldでリンクすると、i386:x86-64と互換性がない、というエラーとなった。いろいろ調べてみたが、32bitプロテクトモードでコンパイルすると何をやってもエラーになるようだ。確かに今はもう64bitが当たり前の世の中なので、32bitモードなどに拘る必要はないのだが、私のように初心者が学習の第一段階で正しくCPUモードを切り替えられるか確認しながら、プログラミングを進める時には必要だと思う。それに、私のやり方はバイナリでターゲットを作成するので、リンカーで無用にシンボルやコードのチェックをしてもらう必要もない。gccはあらゆるCPUのあらゆるモードに対応してきたため、古い仕様はメンテナンスされず、今回のような不整合が起こっているのだろうか?(後になって分かったことだが、この問題はManjaro Linux(64bit)の標準gccツールチェーンをそのまま利用していたためで、標準gccは64bitのアプリケーションプログラムを作成することに最適化されている。組み込み開発では、基本的にgccやbinutilなどのソースをダウンロードしてクロスコンパイル環境を構築しなければならない)何にしても、きちんと標準化された開発環境が整ってないと、初心者にはハードルが高い。しかし、これ以上拘っても時間の無駄なので、アセンブラで64bitロングモードに切り替えてからC言語の関数を呼ぶことにした。そのためには、仮想メモリをMMUで使うため、パージングのセットアップをしなければならなかった。

ネット上の情報やサンプルプログラムを真似て、ページテーブルを設定してみたが、結局、数えきれないくらい失敗し、その理由さえ分からず、64bitロングモードはあきらめざるを得なかった。32bitモードでなぜリンクできないのか、いろいろ調べて、標準gccツールチェーンだからではないか、と思い付き、Manjaro Linuxのパッケージマネージャでi686で検索すると、i686-elf-binutilとi686-elf-gccがAURリポジトリにあり、ダメ元でビルドしてみた。PGP鍵エラーになったが、何かわからないが、誰かの鍵を信用しますか? とメッセージが出て、信用する、にしたら、コンパイルとビルドが行われた。一時間程ビルドが続いたが、/usr/bin/に実行プログラムが作られていて、Makefileでi686用のアセンブラやリンカ、コンパイラーを使うよう修正し、改めて32bitプロテクトモードでC言語関数を呼び出したが、リンクエラーとなった。リンカースクリプトを修正するのを忘れていた。OUTPUT_FILEをi386:x86-64からi386(i686では駄目だった)へ修正すると、makeに成功した。FDディスクイメージをVirtualBoxで実行すると、見事、C言語の内部から文字列を画面に表示してくれた。この問題の解決に一週間もかかってしまった。まあ、これも勉強だと思うしかない。

ページングの設定は、マルチタスクOSを作るレベルになったら、改めて挑戦することにして、しばらくはベタなシステムで開発を続けるつもりだ。C言語が使えるようになったので、フリーで公開されているモジュールの移植もできるだろうし、開発効率が上がるはずだ。これからは画面モードの切り替えとスクリーン表示、キーボード入力のルーチンを作っていって、コマンド入力画面っぽい体裁を整えようと思っている。

カテゴリー: Linux, VirtualBox, パソコン, 自作OS | コメントする

Makefileの落とし穴に嵌った ${wildcard *.h}

IPLプログラムのファイル数が多くなってきたので、ブートセクタ部分とブートモニタ部分をサブディレクトリに分割し、Makefileもそれぞれのディレクトリで分割した。トップディレクトリのMakefileで一部でも修正があれば、そのプログラム(サブディレクトリ)だけ再構築するよう変更したのだが、単純な間違いに気付かず、何時間も時間を無駄にした。これからも同じ間違いをやりそうなので、覚え書きとして残す。

トップディレクトリのMakefile内で、ブートモニタのサブディレクトリ内(BOOTMON_DIR=./boot_monitorとして定義)のソースファイルの依存関係指定で、${BOOTMON_DIR}/bootmon: ${BOOTMON_DIR}/${wildcard *.h} (要点のみで省略)のような記述をしていた。
トップのディレクトリでmakeを実行したが、「boot_monitor/common.hをmakeするルールがみつかりません」というエラーが発生した。common.hはシステム全体の共通定義なので、トップディレクトリにしかない。もちろんブートモニターはそれに依存しているので、makeがそれをmakeしようとするのはいいのだが、common.hを修正してもいないのに、対象としようとするのは明らかにおかしい。何が悪いのかわからなかった。

結論から言うと、正しくは、${BOOTMON_DIR}/bootmon: ${wildcard ${BOOTMON_DIR}/*.h}
修正前の記述法だと、makeを実行しているのは、トップディレクトリで、${wildcard *.h}はカレントディレクトリの*.hのファイル(カレントディレクトリであるトップディレクトリに存在する.hのファイルは、common.hのみ)をMakefile内で文字列展開して、それにサブディレクトリ名${BOOTMON_DIR}を前にくっ付けて解釈していた。つまり、boot_monitor/common.hとしてファイル名を解釈し、それが存在しないからエラーとなっていたわけだ。

本当はワイルドカードなど使わず、cppの機能で依存関係を出力して、無駄のない設定をした方がいいのだろうが、そこまで手間をかける暇もないし、要求通り動いているので、とりあえず、このままとする。

カテゴリー: Linux, パソコン, 自作OS | コメントする

Virtualboxで、Hello World!! IPLプログラムを自作した。

Manjaro Linux上のVirtualBoxで、FD起動の単純なIPLプログラムを作ってみた。もう十五年くらい前に、CD起動でやろうとして、当時はVMwareやVirtualBoxのような仮想環境が手元になく、古いパソコンで試行錯誤したが、結局、何も動かずに諦めた。先日、VirtualBoxをいろいろ試していて、FDディスクイメージを作成したり、起動できることを知り、インターネットで調べたら、豊富に情報があり、定番のHello WorldをIPLプログラムで表示してみることにした。
アセンブラにIntel記法とAT&T記法があり、プログラムの記述にばらつきがあって混乱したが、Manjaro Linux標準のGNUアセンブラとリンカだけで、見事、VirtualBoxの実行画面に表示させることができた。参考にしたのは、以下の書籍。ロングセラーの定番らしい。

— 書籍 30日でできる! OS自作入門

ただし、この本では、naskとかいう独自アセンブラのIntel記法なので、Manjaro LinuxのGNUツールチェーンとは、かなり違っている。それで、GNUアセンブラのAT&T記法で自分で書き直しながら、インターネットのサンプルプログラムを盛り込んで、FDディスクイメージを作成した。

VirtualBoxの設定をして、恐る恐る起動したら、動作画面に”H”の文字が無限に表示されてしまった。プログラムを見直すと、ジャンプ判定が間違っていて、Intel記法のままだった。それを修正して、再度起動すると、見事に「Hello World!!」の文字が画面先頭に表示された。十五年前の挫折を克服した、という感慨と感動は、涙までは流しはしなかったが、言葉に言い表せない。それで気付いたのだが、私はRAM上のアドレスと、ディスクイメージ内のアドレスを混同していて、それが以前IPLプログラム作成に失敗した大きな理由だと分かった。上記の書籍でも、その区別を意識せずに読んでいると、いきなり「0xa000へ書き込む」とか書かれていて、あれ?メモリ上の0x8000へプログラムをロードするとか書いてなかったか?と意味不明に陥っていた。それは、インターネット上の情報でも同じで、書いた人は分かっているのだろうが、イメージ図をふんだんに使って、もっと明示的にどちらのアドレス指定なのか書いてくれないと、初めての人は混乱するのではないかと思った。

メッセージを表示して無限ループで停止するモニタープログラムを作って、フロッピーディスクイメージからロードさせることに挑戦した。
ディスクからセクターを読む指定には、CHS方式とLBA方式があるが、今回はフロッピーディスクのFAT12という前提で、それとブートセクターは512バイトしかないので複雑なプログラムを組めないこともあり、上記書籍を参考に、CHS方式をアセンブラでプログラミングして読み込こもうとしたが、プログラムを組んでいくうちに、それでは駄目だと思い始めた。
CHS方式はハードウェアとしてのドライブの構造に依存していて、シリンダーの数やヘッドやセクターの数を指定してBIOSで読み込むことになる。フロッピーでしか動かさないのであれば、それらの数を定数で決め打ちしてプログラムを作ることはできるが、それでも、ある程度大きなプログラムをロードしようとすると、ヘッダ番号やシリンダ番号を切り替えなければならない。(例:CHS方式では、先頭から19番目のセクターを読む時には、フロッピーディスクの片面のトラックにはセクターが18しかないので、ヘッダを切り替えて、シリンダー番号0-ヘッダ番号1のセクター1として指定する)ハードディスクドライブやSSDなどへ移植する場合は、またプログラムをそれぞれに合わせて書き換えることになり、それよりは、BIOSでドライブ情報(当該ドライブのシリンダー数、ヘッド数、セクター数)を取得して、アクセスしたいセクターを計算でCHS方式に変換する方が汎用性がある。また、LBA方式は論理的な順列のセクター番号なので、セクター番号0から順番に値を増やしていけるのでロジックの見通しがよい。ただディスクから読み込むときは、必ずCHS方式に変換し指定して、1セクターずつBIOSで読み出す必要がある。そこは複雑でもサブルーチンを作成するしかない。ディスクイメージの概念図では、記憶する領域がずっと一続きで連続しているようなイメージを持ちがちだが、実際はCHS方式のように、磁気ディスクの円盤の裏面へ移動したり、シリンダーを切り替えたりという物理的な形状の断絶があることをしっかり頭に叩き込まないと、なぜこんな複雑なプログラムを書かなければならないのか意味不明になって、理解が追い付かず、挫折するのではないかと思う。

LBAからCHSへの変換ルーチンの作成は時間がかかりそうなので、1セクタ分だけCHS[0,0,2](LBA方式ではLBA[1])から、メッセージ表示するだけのモニタープログラムを読み込んで、モニタープログラムへジャンプするようにした。これも何度目かのトライで、無事「Welcome to Monitor !!」が画面に表示された。
これから暇を見て、少しずつ拡張し、FreeDOS(?)のような、どこかの出来合いのフリーOSを移植しようと思っている。

(2022/11/3 追記) ブートセクターのIPLプログラムを作成する時、高級言語でやっていたように、エラーチェックとエラー処理、どんなエラーが発生したのか、すぐ分かるようにプログラミングしていたが、何と、いつの間にか512バイトをオーバーしてしまい、ブートセクターの中に納まらなくなっていた。プログラムの最後はエラー発生時のメッセージのアスキーコードなので、今まで気づかなかったが、本当にエラーが発生していたらプログラムが暴走していただろう。『30日でできる! OS自作入門』の中のプログラムが決め打ちで、プログラムを簡便化していた理由が分かった。IPLは本当にディスクからRAMへのロードだけしかできないのだ。
IPLプログラム全体を見直し、メッセージは長々とした英文ではなく、簡潔な単語だけに縮小し、先頭のFAT12の情報の後、18バイト領域を空けていたのを2バイトにし、サブルーチンの数を減らすために、BIOSのエラーコードの数値を文字に変換して出力するのを止め、LBAからCHSへの変換ルーチンもbpレジスタやdiレジスタ、siレジスタを作業用に使用するように改造し、push,popする回数を最小限に抑えた。何とかブートセクター内に収めたが、それでも40バイト程度しか空きがなく、もしハードディスクへインストールする場合、パーティション情報をブートセクターへ完全には格納するにはまだ足りない。メッセージの文字列をもっと省略して、「error 1」とかだけにすれば、ぎりぎり何とかなりそうだが、その時にまた考え直そうと思う。

(2022/11/7 追記) IPLプログラムのFDディスクイメージのセクター2以降へ、FAT12のフォーマット時のFAT情報を設定するように改造して、モニタープログラムをファイルとして書き込み、FD内の実際にファイル内容が書き込まれたセクターからRAMへ書き込むようにした。ファイルシステムなしで、ブートとロード専用で直接セクターへの読み書きすることもできるが、三十年以上前のパソコンとMS-DOSはフロッピーだけで動作していて、そんな感じに利用することを取り敢えずの目標とし、また、Manjaro Linuxのファイル操作機能を利用して開発の利便性を向上させることも考えた。
この時、ちょっとドツボに嵌った。Makefile内でターゲットのイメージを作成する時、vfat形式を指定して/mnt/へマウントし、cpコマンドでファイルを書き込んだ後、すぐアンマウントさせるだけの手順なのだが、mount、umount、cpコマンドはスーパーユーザーでのログインが必要だった。ネットで調べると、.bashrcへ環境変数を設定して、「sudo -S」で実行すれば自動でログインしてくれることが分かったが、パスワードを直に書いてしまうことになり、セキュリティ上問題がある。SSH暗号化を使用する方法もあったが、面倒臭いし、個人の遊びのシステムなので、.bashrcへ直に書くことで我慢した。
Makefileを書き直して問題なくイメージファイルが作成できたのだが、モニタープログラムが想定とは違うセクターへ書き込まれていた。FATのデータ領域は、LBA[33]から始まるのだが、初期化直後の状態でFAT管理情報を作成しているのにも関わらず、LBA[34]から書き込まれている。散々調べたが、その理由は分からなかった。データ領域の先頭クラスターは予約領域なのか、ボリューム情報か何かにでも使用しているのかもしれない。とにかく、IPLのロード開始位置を修正して、無事、モニタープログラムのロードと「Welcome Monitor!!」の表示が正常に行えた。
これからは、32bitプロテクトモードへの切り替えと、画面への文字表示をやっていこうと思っている。

(2022/12/10 追記) Windows10のVMware Player 17でも、仮想マシンにフロッピーディスクドライブのデバイス機能を追加して、起動時に読み込むとFDイメージを読み込むように設定したら、Virtualboxと同様に起動して、画面表示を行えた。

カテゴリー: Linux, VirtualBox, VMware, 自作OS | コメントする

Manjaro LinuxのVirtualBoxでAlter Linux 32bit LXDEを動かしてみた。

Manjaro Linuxの公式リポジトリに、Oracle VM VirtualBoxがあったので、試しに何か仮想環境でOSを動かしてみようと思った。私は、Windows上ではVMwareを愛用しているが、Linux用VMwareにはインストーラーがなく、VMware Toolsも手動インストールなので、トラブルが起きた時の調査と対処が、面倒臭く思った。

最初はWindowsXPをインストールしようかと思ったが、インストール用CDが見つからなかった。ハードを売った時、一緒に処分してしまったのかもしれない。VMware用の仮想ディスクファイルはあるのだが、、、、しばらく思案して、軽量32bit OSで日本語が最初から使えるというAlter Linux 32bit LXDEをインストールすることにした。Xfce版もあるが、VH-AD3S proの貧弱なハードでは、できるだけ軽いOSを選択しないと、動作が遅くなるはずだ。日本の学生達が作成した、というのも興味を持った。

まずは、VirtualBoxをパッケージマネージャからインストールする。その時に、Linuxカーネルに対応した追加パッケージを選択するよう要求されたので、急遽、設定マネージャでインストールされているLinuxカーネルのバージョンを確認することになった。インストール自体は比較的スムーズに終わった。メニューの「システム」のなかに「Oracle VM VirtualBox」ができるので、そこから起動したら、VirtualBoxの画面が表示された。

Alter Linux LXDE 32bitのISOファイルを公式ホームページからダウンロードして、新規作成で仮想マシンを作成した。その時悩んだのが、Alter LinuxのカーネルはLinux+Zenという改造(?)カーネルなので、種別が純粋なLinuxではないことだ。悩んだ末、「その他」の「その他」で作成して、インストール自体は正常に終了した。インストール用ISOファイルでAlter Linuxを起動したが、画面が変な風に全体が透明になって、メニューやボタンが見えず、操作できなかった。しばらく放置するとデスクトップ画面が表示されて安心したが、インストーラーの画面がまた透明になって、VH-AD3S proの背景画像が透けて見えてしまい、メニューやボタンがほとんど見えないため、仕方なく強制終了した。

半透明でゲストOSの裏の背景が透けて、メニューや設定画面が見えない、見えにくい。不思議な現象に戸惑った。Alter Linuxのウィンドウのルック&フィールの設定を変更しようとしたが、設定画面が透明で背景画像と混在して操作できない。
調べてみると、昔からあるVirtualBoxのバグらしく「env XLIB_SKIP_ARGB_VISUALS=1 VirtualBox」で起動すると、透明にならず、正常に表示されるようになった。Oracleが片手間の惰性でやっているOSSなので、改善される見込みはないだろう。Broadcomに買収されたVMwareが心配になってきた。

Alter Linuxについてだが、インストールが日本語で簡単にできたのは評価できる点だった。パッケージのアップデートを実行したら、最初に大量の更新があって時間がかかるのは、理解できる。しかし、何度やっても途中で「予期しないエラー」となって、アップデートが全くできない。対象パッケージのチェックを外して、少数ずつやってもエラーとなる。アップデートができないという障害はシステムとして致命的だ。仮想環境ではなく実機だと、もしかしたらできるかもしれないが、Windos10上でのVMwareへインストールして試しても、同じくアップデートで「予期しないエラー」となってしまう。アップデートの失敗は、仮想環境でのWindowsや、どのLinuxディストロでも経験したことがない。元々のシステムの品質が悪いのではないだろうか?
残念ながら学生のお遊び感覚と実力不足が露呈した結果としか考えられない。これで、寄付をお願いしているなんて信じられないレベルだ。期待感でパソコン素人を釣るのではなく、学生も数年すれば社会人になるのだから、それで生計を立てたいのならば、まず基本的な実力を示すべきだと思う。Alter Linuxはこれ以上何もできないので、削除した。

カテゴリー: Linux, VirtualBox, パソコン | コメントする

Manjaro Linuxの個人的設定 その4。Sambaの設定 — 半分だけ成功、後は保留。

前の記事からの続き。Manjaro Linuxの個人的な設定の覚え書きです。

LAN内のパソコンでファイル共有するために、まずは、Manjaro LinuxからWindows10上の共有フォルダ(Everyoneにフルコントロールの設定をWindows上で行う)へアクセスできるように設定しておく。本来はファイルサーバーとなるWindows10は固定IPにするのが望ましいのだが、DHCPの動的IPのままでホスト名を使用して設定をしてみることにした。
ちなみに、Manjaro Linuxを固定IPにする場合は、メニューの「設定」内の「高度なネットワーク設定」を起動して、「Ethernet」の中の利用する接続名を選択して、編集を行う。「IPv4設定」タブ内の「メソッド」を手動にして、「アドレス」に固定IP(例 : 192.168.0.7)、サブネットマスク値(例 : 24)、ゲートウェイ(例 : 192.168.0.1—-通常はルーターのアドレス)を追加する。「DNSサーバー」にも、DNSサーバーのアドレス(例 : 192.168.0.1—-通常はルーターのアドレス)を入力して保存する。ルーターのDHCP固定割り当て機能を使う方法もあるが、今回のようにWindows10とのデュアルブートをする場合、Windows10で起動した場合も、固定IPとなって影響を受けてしまう。

Manjaro Linux側では、パッケージマネージャでsambaがデフォルトでインストールされていることを確認し、次にmanjaro-settings-sambaをパッケージマネージャからインストールする。manjaro-settings-sambaは、smb.confとかの標準的な設定を作成してくれるらしい。それで、sambaの設定ファイルがあるはずのフォルダを確認すると、/etc/samba/smb.confが作成され、中身も実用的な設定がされているように見えた。後は、パッケージマネージャで、cifs-utilsがインストールされていることを確認する。ファイルマネージャのThunarで、「ネットワークを参照」をクリックすると、数分後に、「/ on が見つかりませんでした」というエラーメッセージがクリックした回数だけ(^_^;;;表示された。ネット情報を参考にして、ファイルマネージャThunar用のツール、thunar-shares-pluginをパッケージマネージャからインストールしたが、何も変わらなかった。

すべてのパソコンを固定IPにしようと考え始め、ダメ元で、アドレスバーで直接、smb://xxxxxx[<—コンピューター名]/yyyyyy[<—共有フォルダ名]のように入力したら、あっけなくアクセスに成功して、ログイン名とパスワードを要求された。当該Windows10のユーザー名とパスワードでログインしたら、フォルダが開かれ、「ネットワーク」の場所の項目に追加された。
IPアドレスではなく、コンピューター名でアクセスできたので、名前解決の処理ではコンピューター名を取得出来ているということだ。なんとなくなのだが、「ネットワークの参照」に関しては、Thunarにバグがあるようで、本来は「ネットワークを参照」をクリックしたらWindowsの「ネットワーク」と同じく、自動で同一ワークグループ内のコンピューターを探索して表示するのだろう。gvfs-backendsを追加する必要があるという情報もあったが、パッケージマネージャに存在せず、Arch wikiには、gvfs-smb(Manjaro Linuxはデフォルトでインストールされていた)にバックエンドの機能があるように書いてあったので、どこにも明言されていないが、gvfs-smbにgvfs-backendsの機能が統合されているように思えた。gvfs-backendsを追加するというのは、Ubuntu系のディストリビューションか、古いバージョンでの対処方法のようだ。Windows10の共有フォルダへのアクセスはできたので、いろいろ腑に落ちない点はあるが、これ以上の追求はしないことにする。

今度は、Manjaro LinuxでSambaサーバーを常時稼働させて、Manjaro Linux内の共有フォルダをWindows10からアクセスできるようにする。今度はファイルサーバーとなるManjaro Linuxに共有フォルダを用意する必要があるが、manjaro-settings-sambaをインストールした時に、/var/lib/samba/usershareが自動で作成され、smb.confもそこを共有する設定になっていた。設定を変更する場合は、管理者権限(sudo)で、/etc/smb.confを編集する必要がある。

ここで不思議な現象が発生した。VH-AD3L(Windows10)のネットワークではManjaro Linuxのコンピューター名とアイコンが表示されないのに、Lightning AH5のWindows10のネットワークでは表示されている。ただし、中身へのアクセスはエラーとなる。winsサーバーでの名前解決はできているのに、sambaの設定が悪いだけのようにも見える。しかし、VH-AD3LとLightning AH5は両方ともWindows10 Homeだし、ウィルス対策ソフトも同じで、設定に違いが見当たらない。しかし、名前解決ができているのだし、あと一歩、Manjaro Linux側のSambaのアクセス権限とか、Sambaの共有ユーザーの登録とかの問題の気がする。いろいろ試行錯誤したが、sambaユーザーを登録するコマンドのpdbeditを実行すると、データベースへアクセスできないというエラーが出るなど、理解できない現象が相次いだ。
Windows10のコントロールパネルの資格情報マネージャーでManjaro Linuxのホスト名とログインユーザー名、パスワードを作成してみたが、やはり、ネットワークパスが見つかりませんというエラーとなる。Manjaro-settings-sambaの標準のsmb.confにおかしな設定があるようには見えない。

ネット情報にあった、「sudo gpasswd sambashare -a your_username」でsambashareというグループに自分のユーザー名を登録してみたが、全く改善しない。

名前解決でwinsサーバーを参照できればコンピューター名でアクセスできるはずなのだが、どうしてもできない。gvfs-backendsはパッケージマネージャに存在しない。どのリポジトリにもない。不思議。ネットの情報も錯綜していて、よく分からない。
試しに、VMwareのLinux Mint20.3で試してみたら、gvf-backendsのパッケージがあり、winbindというパッケージもあり、インストールしただけで、Windows10側からアクセスできた。ただ、smb.confの共有フォルダの設定をしたが、ユーザー名とパスワードを問い合わせる画面が出てきたが、Sambaユーザーの設定をしてないためか、アクセスを拒否された。設定を見直せば、正常動作するかもしれないが、Manjaro Linuxには適用できないので、Manjaro LinuxのSambaの問題であると判断して、今回はManjaro LinuxへのWindows10からのアクセスは断念した。

こういう標準設定方法がなく、ディストリビューションやバージョンによって、状況が変わってしまうのがLinuxの大きな欠点。LANはWindowsやMacOSなども含めて共存するのだから、その設定方法くらいはLinuxディストリビューション全体で横断的に標準化して欲しいものだ。実用に不都合はないので、いつか頭を冷やして、時間がある時、また取り組みたいと思う。

カテゴリー: DIY/日曜大工, Linux, パソコン | コメントする

ドスパラ VH-AD3S proの裏蓋のカバーを留めるネジ

今回、Manjaro Linuxをインストールするために、VH-AD3S proを裏返しにして、SSD取り付け部の蓋を取るために、ネジを外して、SSDを取り付けたのだが、裏蓋のカバーを留める10個、SSDの蓋を留めるネジを含めると12個のうち、4個が脱落して、無くなっているのに気が付いた。ドスパラのレビューで、他の人もネジが脱落していたという書き込みがあったので、製造元の中国での作業がいい加減だったのだろう。

ネジの種類には、ミリネジとインチネジがあって、ピッチが異なるので、間違えるとネジの渦巻きの溝を削って、ネジ穴が使用できなくなってしまう。自作パソコンの初期の頃に痛い思いをした。ネットの写真と見比べて、ミリネジではないか、と確信はないが、当たりを付けた。ミリネジにはサイズや長さに規格があって、ノギスを持ってないので、物差しの目測でのおおよそのサイズは、上の皿の直径が4mmで厚みは1mm以下、軸の太さは1mmか1.2mmくらいの極細で、軸の長さは3mm、SSDの蓋を留める方は長さが4mmで種類が違っていた。SSDの蓋のネジは二つともあるので、裏蓋を留めるネジを買うことにした。サイズからすると、M1x3かM1.2×3の超低頭の小ネジになり、Amazonで検索したが、当てはまる商品がない。どうも一般のネジではなく、極小の特殊なネジのようだった。ホームセンターを何軒か見て回ったが、M2(軸の太さが2mm)以上のサイズしか商品が置かれていない。

Amazonにもないし、ホームセンターにもないので諦めかけたが、ダメ元で、試しにホームセンターの一番小さいネジを買ってみることにした。M2x4mmの超低頭小ねじ6本入りを166円で購入し、自宅でVH-AD3S proを裏返して、ネジが抜けたネジ溝へ恐る恐るドライバーで回してみたら、抵抗はあったがスムーズにネジ留めすることができた。逆回転で外してみたが、ネジ溝を削っている様子はない。上の皿は少し小さい(3.5mmくらい)が、仮留めのような感じに緩くネジ留めして、取り合えず、裏蓋が落ちないようになればよいのだ。ネジが脱落したら、また同じものを買って、一時しのぎをすればよい。

–YAHATA ピタッと浮きなし小ねじ M2 x 4mm ピッチ0.4 ドライバー0種 超低頭小ねじ(NI) 6本。 今回購入した商品は、Amazonにはないが、同じものと思われるネジはあった。

カテゴリー: DIY/日曜大工, PCパーツ, パソコン | コメントする