FAT用のマスタブートローダが
できましたので、カーネルを読み込める環境が整ったことになります。
しかし、カーネルを作っても、FAT形式の
ディスクイメージを作らなければ実際に使うことはできません。
そこで、
FAT用のディスクイメージ作成ツールを作っておくことにします。
準備が多いような気がしますが、根気強く耐えることにしましょう。
FAT の構造については以前に書きました。
最初にマスタブートローダを書き出し、
次に同じ管理テーブルを2つ書き出し、
最後にルートディレクトリ、ファイルの順で書き出せば、
ディスクイメージが完成します。
ここでは簡単のため、
対象メディアを1.44MB FDとし、
ファイルの保存先をルートディレクトリに限定して
作ることにしました。
注意すべきポイントは、ファイル名が基本名8文字、拡張子3文字で、
大文字でなければならない点です。
以下のコードでは簡単のために、
タイムスタンプに0を設定し、エラー処理は省いています。
また、日本語ファイル名も考慮していません。
本格的なイメージ化ツールを作成するのであれば、これらを
手直ししたほうが良いでしょう。
このへんは単純作業です。
書き捨てツールということでコードに愛が
感じられないかもしれませんが、まあ良いでしょう。
これを使いセクタ0が正しく動作することを確認すれば、
ようやくカーネル作りに取りかかれます。
int bytestosector(int len)
{
return (len+511)/512;
}
int filesize(const char * pname)
{
FILE *fp;
int len;
fp = fopen(pname,"rb");
fseek(fp,0L,SEEK_END);
len=ftell(fp);
fclose(fp);
return len;
}
void seccopy(FILE *fo,const char * pname,int len)
{
int sec;
FILE *fp;
unsigned char buf[512];
fp = fopen(pname,"rb");
sec = bytestosector(len);
while(sec-->0){
memset(buf,0,sizeof(buf));
fread(buf,1,512,fp);
fwrite(buf,1,512,fo);
}
fclose(fp);
}
void secpad(FILE *fo)
{
unsigned char buf[512];
memset(buf,0,sizeof(buf));
fwrite(buf,1,512,fo);
}
const char *basename( const char *pname )
{
const char *pcur = pname;
const char *pret = pname;
while (1) {
if ( *pcur == 0 ) break;
if ( *pcur == '/' ) {
pret = pcur+1;
}
++ pcur;
}
return pret;
}
int main( int argc, char ** argv )
{
unsigned char fat[512*9];
unsigned char dirent[14*16*32];
unsigned char *pdirent_cur;
unsigned fatsec_cur;
unsigned fatsec_top;
unsigned fatsec_next;
const char *pfilename_cur;
FILE *fp = NULL;
int argidx;
int filelen;
int filesecsize;
int charidx;
bool dotflag;
if ( argc < 3 ) {
printf("usage: %s outfile.img bootsect.bin [file1 file2 ...]",argv[0]);
exit(1);
}
fp = fopen(argv[1],"wb");
seccopy(fp,argv[2],512);
memset(fat,0,sizeof(fat));
fat[0]=0xf0;
fat[1]=0xff;
fat[2]=0xff;
memset(dirent,0,sizeof(dirent));
fwrite(fat,1,sizeof(fat),fp);
fwrite(fat,1,sizeof(fat),fp);
fwrite(dirent,1,sizeof(dirent),fp);
pdirent_cur = &dirent[0];
fatsec_cur = 2;
for ( argidx = 3; argidx < argc; ++argidx ) {
fatsec_top = fatsec_cur;
filelen = filesize(argv[argidx]);
filesecsize = bytestosector(filelen);
while ( filesecsize-- > 0 ) {
fatsec_next = (filesecsize > 0) ? (fatsec_cur + 1) : 0xfff;
if(fatsec_cur & 1) {
fat[fatsec_cur+(fatsec_cur>>1)+0] |= (fatsec_next << 4) & 0xf0;
fat[fatsec_cur+(fatsec_cur>>1)+1] = fatsec_next >> 4;
}else{
fat[fatsec_cur+(fatsec_cur>>1)+0] = fatsec_next & 0xff;
fat[fatsec_cur+(fatsec_cur>>1)+1] |= fatsec_next >> 8;
}
fatsec_cur++;
}
memset(pdirent_cur,0x20,11);
pfilename_cur = basename( argv[argidx] );
if ( *pfilename_cur == '.' ) {
fatal("invalid FAT filename - %s",argv[argidx]);
exit(1);
}
charidx = 0;
dotflag = false;
while (1) {
if ( *pfilename_cur == '\0' ) {
break;
} else if ( *pfilename_cur == '.' ) {
if ( dotflag ) {
fatal("invalid FAT filename - %s",argv[argidx]);
exit(1);
}
dotflag = true;
charidx = 8;
} else {
if ( charidx >= 11 ) {
fatal("invalid FAT filename - %s",argv[argidx]);
exit(1);
}
if ( charidx == 8 && (!dotflag) ) {
fatal("invalid FAT filename - %s",argv[argidx]);
exit(1);
}
pdirent_cur[charidx++] = toupper(*pfilename_cur);
}
++ pfilename_cur;
}
pdirent_cur[11]=0x20;//attr
pdirent_cur[0x1a]=fatsec_top & 0xff;
pdirent_cur[0x1b]=fatsec_top >> 8;
pdirent_cur[0x1c]=filelen & 0xff;
pdirent_cur[0x1d]=(filelen >> 8) & 0xff;
pdirent_cur[0x1e]=(filelen >> 16) & 0xff;
pdirent_cur[0x1f]=(filelen >> 24) & 0xff;
pdirent_cur += 0x20;
seccopy(fp,argv[argidx],filelen);
}
while(1){
int outlen=ftell(fp);
if(outlen<0||outlen>=1440*1024)break;
secpad(fp);
}
fseek(fp,512L,SEEK_SET);
fwrite(fat,1,sizeof(fat),fp);
fwrite(fat,1,sizeof(fat),fp);
fwrite(dirent,1,sizeof(dirent),fp);
fclose(fp);
return 0;
}