仮想ファイルシステム
はりぼてOSには FDドライバーがありません。じゃあ、どうやってフロッピーからファイルを読み込むかというと、起動時に BIOS を使ってまとめて読み込んでいます。FAT12 の情報も含めて単純にごそっと読み込むため、あとでメモリーにアクセスするだけでフロッピーにあったファイルを読み出すことができます。要はメモリー上の仮想ファイルシステムです。これだと FAT 解析ロジックだけを作ればよく、CD-ROM ブート時(El Torito)も無修正で対応できます。
一方、Mona も起動時に BIOS を使ってファイルを読み込みますが、FAT12 を解析して、カーネルだけを読み込むます。Mona のほうが賢いと思うかもしれませんが、この方法だと FD ドライバーを作らなければいけないし、CD-ROM ブートに対応させようと思ったら ISO-9660 解析ロジックも必要です。Mona のカーネルが小さそうに見えて、実は必須サーバーをあわせると 400KB 近くあるのはそのせいです。
理想的には、はりぼてOS の IPL → はりぼて OS のセカンドローダ → 自作カーネル というシーケンスにしたいのですが、Mona の IPL → Mona のセカンドローダ → 自作カーネル というシーケンスになっています。次善の策として、自作カーネルの後ろに必要なファイルをまとめた tar ボールをつけるという方法を思いつきました。FAT12 上は1つのファイルで、この tar ボールを仮想ファイルシステムに見立てるという方法です。tar は無駄が多いので Waba プロジェクトで使っていた wrp だとなおいい感じです。
さっそく実行してみました。仮想ファイルシステムなので、ディレクトリやロングファイルネームをサポートしても、驚くほど小さいソースコードでできました。
http://www.wabasoft.com/spec_warp.shtml
file.h
#ifndef _FILE_H_ #define _FILE_H_ #include "types.h" #define MAX_FILES 32 #define get_word(b) (word)( ((b)[0]<<8)|(b)[1] ) #define get_dword(b) (dword)( (dword)((b)[0])<<24 | (dword)((b)[1])<<16 | (dword)((b)[2])<<8 | (dword)((b)[3]) ) class File { public: static dword file_system_start; static int number_of_files; static dword* file_offset_list; static dword* file_size_list; public: static void init(); static byte* load(char* file_path, dword* read_size); }; #endif
file.cpp
#include "file.h" #include "string.h" #include "stdarg.h" #include "memory.h" #include "screen.h" dword File::file_system_start = 0; int File::number_of_files = 0; dword* File::file_offset_list = NULL; dword* File::file_size_list = NULL; void File::init() { File::file_system_start = 0; File::file_offset_list = new dword[MAX_FILES]; File::file_size_list = new dword[MAX_FILES]; /* カーネルの後ろについている Warp ファイルを検索 */ /* 0x2200 + 20KB 付近からマジック文字列を適当に探す */ for (int i = 0x2200 + 0x5000; i < 0x80000; i++) { char* p = (char *)i; if (strncmp(p, "Wrp1", 4) == 0) { file_system_start = i; break; } } if (file_system_start == 0) return; /* ファイルデータのオフセットリストを生成する */ byte* fp = (byte *)file_system_start; number_of_files = get_dword(fp + 4); for (int i = 0 ; i < number_of_files; i++) { file_offset_list[i] = get_dword(fp + 8 + 4 * i); file_size_list[i] = get_dword(fp + 12 + 4 * i) - file_offset_list[i]; } } byte* File::load(char* file_path, dword* read_size) { if (file_system_start == 0) { *read_size = 0; return NULL; } /* Warp ファイルの中からファイルを検索する */ byte* fp = (byte *)file_system_start; for (int i = 0; i < number_of_files; i++) { if (strncmp(file_path, (char *)(fp + file_offset_list[i] + 2), strlen(file_path)) == 0) { int nameLen = get_word(fp + file_offset_list[i]); *read_size = file_size_list[i] - nameLen - 2; return (fp + file_offset_list[i] + 2 + nameLen); } } *read_size = 0; return NULL; }