30日OS自作入門19日目(Win10)
はじめに
章を見た感じ、今回はアプリケーションを実装するまでの下地作りを行うようです。
目次
アプリケーション
Typeコマンド(harib16a)
Windows版catコマンド的な奴ですね。
まずバイナリエディタを確認し、データのありかを確認して、構造体FILEINFOのデータと比較することで、ファイルのありかとセクタ番号からデータあるアドレスを逆算しています。
次に、ファイルを指定するのでstrcmp関数が使用できなくなるようです(文字列も比較するため)。そこでANDを使用した判定をしています。
else if (cmdline[0] == 't' && cmdline[1] == 'y' && cmdline[2] == 'p' && cmdline[3] == 'e' && cmdline[4] == ' ')
そして、ファイルを判定する方法は配列であるsにデータを格納しています(小文字なら大文字に変換)。その後、構造体FILEINFOの名前データと1文字ずつ比較して判定しています。
もし、ファイルが見つかった場合は構造体FILEINFOのサイズをカウンタにして1文字ずつ中身を出力していくようです。
実行すると
30日自作OS本(harib16a)
— 猫(1010) (@Wagahaiha_toto) 2020年2月3日
なかなか時間かかったけど、ファイルデータがどこにあるかを調べる方法が面白かった。 pic.twitter.com/ddPa5nbIPu
Catコマンドにしてみた
入力方法を変えただけのcatコマンド、なんかharibote.sysの最後の表示位置がtypeコマンドと違うので不安。 pic.twitter.com/R0xoOHFZWt
— 猫(1010) (@Wagahaiha_toto) 2020年2月3日
haribote.sysだけ最後の表示がずれているけど、別にバグではないと信じたい
typeコマンド改良(harib16b)
前の章では、表示したデータがぐちゃぐちゃでしたが、これは改行コードと文字コードの処理ができていないからという結論になっていました。そこで、改行コード等に対応するように書き直すようです。
まず各種Tabや改行の文字コードは以下のようになっているようです。
0x09:タブであり、xが4で割り切れるところまでスペースを表示する 0x0a:改行する 0x0d:復帰であり、文字表示が左端に戻る
Tabに関しては、こんな考え方で接したことはなかったですね…行をそろえるためだったか…
その後、文字列の量でも比較のできるstrncmp
関数を利用してtypeコマンドを認識させているようです。また、Tabの処理に関しては1文字が8ドットなので、一文字表示するごとに32倍ずつずれていっています。そこで、2進数の特徴を利用し&を使って割り切れる数を出しているようです。
後は、条件分岐で各種の改行コードに対応させ実行を行うと
30日自作OS本(harib16b)
— 猫(1010) (@Wagahaiha_toto) 2020年2月4日
キレイにアセンブリコードが見れるようになった。 pic.twitter.com/ftP6rlnhWf
FATに対応(harib16c)
ファイルシステム第一の壁(個人差あり)のFATさんじゃないっすかぁ!
Windowsでのディスク管理方法であるFATでは、1セクタである512バイトより大きいファイルをディスクに入れるときに、次のセクタでない場所へ書き込むことがあるようです。しかし、どこに書き込まれるかの情報はしっかりと記録されており、それをFAT(File allocation table)と呼ぶようです。書き込まれている箇所は、ディスクイメージの0x000200~0x0013ff
に書き込まれているようです。また、そのデータは圧縮されているらしく、書籍のP387とP391 に説明があります。
その後、そのデータを確保したメモリの領域にすべて正しく並べることで、参照可能にしているようです。
その際に並べ替える関数は以下の関数みたいです。
void file_readfat(int *fat, unsigned char *img) /* ディスクイメージ内のFATの圧縮をとく */ { int i, j = 0; /* カウンタ */ for (i = 0; i < 2880; i += 2) { /* 2880=全セクタ数 */ fat[i + 0] = (img[j + 0] | img[j + 1] << 8) & 0xfff; /* データを並べ直し */ fat[i + 1] = (img[j + 1] >> 4 | img[j + 2] << 4) & 0xfff; /* 並べ方は書籍P388を参照 */ j += 3; /* 圧縮される側のデータのカウンタを進める */ } return; } void file_loadfile(int clustno, int size, char *buf, int *fat, char *img) { /* 引数の情報を元にメモリ上に正しく並べる */ int i; for (;;) { if (size <= 512) { /* 最後のセクタのロード */ for (i = 0; i < size; i++) { /* データをロード */ buf[i] = img[clustno * 512 + i]; } break; /* 無限ループから出る */ } for (i = 0; i < 512; i++) { /* 2以上のセクタのロード */ buf[i] = img[clustno * 512 + i]; } size -= 512; buf += 512; clustno = fat[clustno]; /* アドレスを私てる */ } return; }
実行すると
実行できているので、たぶん大丈夫ですね。
コラムを見た感じ、圧縮されているデータの差は1つのセクタ番号を表すのに2バイトいるか、1.5バイトで済むかの差みたいですね。
ソースの整理(harib16d)
新規に作ったファイルはconsole.cとwindow.c、file.cになるみたいです。修正箇所は新規ファイルを除くと、bootpack.c・bootpack.h・Makefileでした。基本的にコピペで済みます。
ついに初アプリ(harib16e)
ファイルも読めるようになったから、アプリを作って後、組み込んで実行できるだろうということで作るようです。
アプリケーションのプログラムを認識するためにコマンド入力を受け付けるのは、いままでのコマンド入力判定のようにstrcmp関数を使用して判定をしているようです。また、NASKでアセンブルした時に拡張子を、はりぼてOSオリジナルの.hrbに変換するようになっています。
また、コードを書いて作られたアプリケーションというのは、どこのアドレスから始まるのかを考えられておらず、ORG 0
から動くものという前提のアセンブル、またはコンパイルがされています。そこでセグメントを割り振ることにより、アドレスがどこから始まるかを気にすることなく始めることができるということみたいです。そのあとは、用意したセグメントへ、farjmp()してプログラムを実行すればいいということになるようです。
そういえば書籍では、hlt.hrbは3バイトの命令になっていると書いてあります。が、実際にどうなっているかというと…
こんな感じになっています。本当に3倍ですね。
実行すると
30日自作OS(harib16e)
— 猫(1010) (@Wagahaiha_toto) 2020年2月4日
魔法名『hlt』
コンソールはフリーズした。 pic.twitter.com/ZPAS7UwM3T
メモ
・最初の方でFAT12フォーマットにしているのはBIOSに読ませるとかでなくて、ただ単に採用しただけ。そのおかげで空き領域に適当なファイルを入れることができるし、Windowsから中身を見ることも簡単にできる。なんで気づかなかったんだ…
最後
今回も面白い内容でしたね。いかにして、取り込んだファイルを実行に移すかの手綱使いが見れました。