そしていよいよIPLが読み込むプログラム本体の話が始まる。簡単なOS本体プログラムを書いて、それがフロッピーのどこに保存されるか?をディスクイメージとしてバイナリレベルで確認する、という話。

ディスクイメージってのは、HD上に置くファイルはHDのルールに従ってデータ保存されてしまうので、フロッピー特有のシリンダとかそうした情報を意識出来なくなってしまう点を解決するため、「フロッピーとして保存するならこんな感じになるよ」という事を確認できるようにするもの、とかそんな感じなんだろうか? 深く考え出すとハマりそうなので、今のところは流しておくことにしよう。。

で、「フロッピー上でファイル名を格納するスペースと、ファイル本体が格納されるスペースは別々に分かれているんだよーファイルが格納される場所は0x004200以降だよー」という説明が続く。ファイル自身がファイル名を保持していないのは知ってたけど、実際にどう解決してるのか?は初めて知った。相変わらずDeepだ。。

OS自身を置くとしたらドコに入るのか?が分かった後は、ブートセクタ側で実際に読み込みに行く場所を指定すれば良い。それが上手く出来ているか?を確認する為に、実際にブートセクタから何か動作するプログラムを読み、実行させてみる事に。いきなり難しいプログラムを書くのも大変なので、先ずはVRAMを制御して画面を真っ黒にしてみるところからスタート。またBIOSか。こういう情報がないところから始めていたら大変なんだろうなぁ、、、と、毎度の事ながら先人の苦労に感謝しつつ読み進める。

32ビットモード始まる。


そしていよいよ、CPUを32ビットで使おう、という話題へ。OS本体は、管理できるメモリサイズの制限等が大幅に改善される32ビットモードで使えるようにすべく、その準備の話から。OS自身は出来るだけC言語で書こう、というのが本書のテーマでもあるので、そろそろアセンブラとはお別れの気配。

32ビットモードではBIOSが使えなくなってしまうので、移行前にBIOSから欲しい情報をもらってしまえ、という事でそこまではアセンブラでガシガシやる。VRAMって言っても画面モード毎に別々のメモリが確保されている、って説明は分かりやすいな。だから、今自分がどれを使っているのか?を常に意識する必要がある、と。

C言語いよいよ登場


C言語で書いた部分を呼び出すためにアセンブラ側でどんな事をしているか?の説明はひとまず置いておいて、C言語でOS本体を記述していこう、という話題へ。うーん、アセンブラも嫌いじゃなかったから少し寂しいなぁ、などと感じつつ読み進める。

C言語の作法は基本的に理解しているので、新たな発見という意味でメモする事はないが、マシン語に変換するまでの過程をしっかり説明していたのは良かった。分かったつもりになっていた部分も、より明確になった。

覚える事を増やしすぎるとイカン、という配慮だろう。最後は、C言語がシステム機能を利用する為の関数をアセンブラで用意する、という方法と、その利用法について解説し、3日目が終了。今の状態だと画面に文字表示すら出来ないので、4日目以降からコツコツと自作関数を作る事になるものと予想。まだアセンブラとお別れする必要は無さそうだ。




「なんだ、やっぱり3日坊主かー」と思った人もいるかも知れない。だがちょっと待って欲しい。クリスマス前である。休暇をとって帰国したら、日付が変わってしまったのだ。そんなワケで、1日あいてしまったが寝る前に更新しておこう。時差ぼけのおかげで、一応まだ頭は冴えている。

フロッピーを知れ


ついにIPLがIPLとして動く時がやってきたようだ。ブートセクタから他の領域(OSが格納されている部分)を読み込む為の枠組み作りから3日目はスタートする。というワケでアセンブラを使ってフロッピーにアクセスする方法の学習がスタートする。ふむふむ、BIOSで規定されているルールに従って、必要なレジスタの値をセットした後で、割り込み命令を使って、利用したい基本機能を実際にCallする、という順番でやるわけですな。ドコに何を設定するのか?について覚える気にはちょっとなれないので、参照すべき箇所 だけを覚えておくことにしよう。そして、ディスク読み出しで何らかエラーがあった場合とかには、BIOS側が親切に教えてくれる事になっていて、その情報はキャリーフラグというところに格納される、と。

キャリーフラグについては、何やらフラグ(0か1か)という1ビットの情報を格納する為のレジスタ群が既出レジスタ以外に存在しているらしく、その1個らしい、という事だけをこの時点では理解していれば良さそうだ。ならば、今は深くは探るまい。

ポイントとしては

① フロッピーは表と裏が使えるので、読み出す時にもどっち側かを意識すべし
② フロッピーの片面は、80個のシリンダという同心円の集合によって構成されているので、読み出す際には、シリンダ番号の指定が必要
③ というか、実は1つのシリンダは、18個のセクタに分割されるので、さらにセクタ番号も指定しないと駄目

というあたりになるか。

で、前日学習したとおり、CPUが持っている記憶容量としてのレジスタの規模はたかが知れているので、フロッピーから読み出されたデータは、メモリ上に読み込む必要がある。そんなワケでそれを指定する時に使うのが「バッファアドレス」となる。

しかし、メモリ上のアドレスを指定するのはレジスタに格納される値という事になる。でも、16ビットのレジスタを使っている限り、64KBまでしか使えないじゃん!どーすんの?!EBXみたいな、32ビットレジスタは使えないのにー!

という事で桁数を増やす為の暫定措置として使われるのが、昨日スルーした隠れキャラ、「セグメントレジスタ」である、と。32ビットレジスタは存在するし、仕えるんだけど、それを使おうとするとBIOSの力を借りれなくなっちゃう、という悲しい宿命があるゆえ、選択肢には入れられないようだ。ここら辺が、「IPLが直接OSをロードするんじゃなくて、実はOSロード用のプチプログラムをロードするだけ。いわゆる多段階ロケット式」というケースが多い所以でもあるんだろう。そう、セグメントレジスタが桁数を増やしてくれるといっても、劇的に増やしてはくれないのだ。(具体的には、「セグメントレジスタの値×16+BXレジスタの値」という形で解釈される。ドウでも良いが、フランス人の数字の数え方 を思い出してしまった)

そんなワケで読み込めるデータサイズは、現時点では1MBが上限になる、と。ところで、ブートセクタが読み込まれる領域はメモリマップ上で規定されており、且つ、実際にそこに読み込まれているにも関わらず、ディスクデータとしては結局ブートセクタ部分も含めてメモリに読み込むって事がサラリと書いてあるのだが、何だか同じものを別の場所に2重に格納するなんて!と、無駄な気がしてしまうのは自分だけだろうか? 後日謎が解ける事を祈りつつスルーしてしまおう。

Makefileでは簡単な変数が使える、という点については、ツールの使い方に属するような話なので「ああ、修正が楽で便利ですな」くらいで流しておこう。

で、フロッピーの読み出しエラーって実はままある事らしく、一度の失敗くらいでメゲないように、という事でループをさせてみよう、というチャレンジの中で新命令JNC(jump if not carry)が、指定したセクタまで連続して読み込むチャレンジの中でJBE(jump if below or equal)という新命令が登場。JB(jump if below)も後で出てくる。C言語でいうところのIF文もアセンブラレベルでは別々の命令を作る必要があるワケですな。

で、豆知識に属する部類だと思うが、ディスクBIOSでALにセクタ数を指定できるようにはなっているものの、怪しい制限があるっぽいので、基本的にはやらん方が良い、とのアドバイス。うーん、先人達は本当に色々試しているんだなぁ、、と頭が下がる思い。

それから、定数を宣言する為の命令、EQU(equal)が紹介される。プログラムの可読性が高まるし、修正も楽なのでこういう機能があるのは有難い。NASK偉い!(それともアセンブラでは常識なのだろうか?)

後半へ続く


世の中にはちょっと変わった人たちもいるようで、Nintendo DSの上でLinuxを動かしちゃっているプロジェクト があるようだ。Nintendo DSもそういえば巷の情報 を見る限り、ARMを使っている(正確にはARM7とARM9のデュアル)みたいだし、最新の携帯電話機と比べればやや劣るものの、ディスプレイからタッチパネルまで揃った高機能デバイスである事は確か。変な評価ボードとか高いお金を払って買うよりも、意外と楽にデモプログラムなんかが動かせてしまうのでは?なんて事を考えてしまった。

実に良い世の中になって来たものだ 笑

でも、OS自作入門を読破するまでは、ここら辺の興味は封印しておく事にしよう。。。