SSブログ

UNIX V6 のカーネルローダーをCで実装してみる

UNIX V6のinode、ファイルシステムの勉強がてらカーネルローダーを自作してみた。
やってることはfsboot.sとほぼ同じで、PDP-11(simh)のrk05ディスクドライブから、カーネルのバイナリを探してロードして起動する。
とりあえず方針として、
・できるだけC言語で実装する
・高速化は考えない(シンプルに実装する)
・カーネルファイル名は"unix"で探す
とした。以下ソース。




"ld.scr"
ENTRY(start)
SECTIONS
{
  . = 24*2048-512;
  .text : {
    *(.text)
    *(.rodata)
  }
  .data : {
    *(.data)
  }
  .bss :  {
    *(.bss)
  }
  end = .;
}



"start.S" .GLOBAL _cstart STACK = 24*2048-514 .text .even .globl start start: mov $STACK, sp jsr pc, _cstart mov $start,-(sp) clr pc .end
"inod.h" typedef unsigned int uint16_t; typedef int int16_t; struct inode { uint16_t i_mode; char i_nlink; char i_uid; char i_gid; char i_size0; uint16_t i_size1; uint16_t i_addr[8]; int16_t i_atime[2]; int16_t i_mtime[2]; }; typedef struct inode inode_t; /* modes */ #define IALLOC 0100000 #define IFMT 060000 #define IFDIR 040000 #define IFCHR 020000 #define IFBLK 060000 #define ILARG 010000 #define ISUID 04000 #define ISGID 02000 #define ISVTX 01000 #define IREAD 0400 #define IWRITE 0200 #define IEXEC 0100
"main.c" #include "ino.h" #define RK11_CTL_REG_ADDR (0177400) #define CODE_ADDR (((unsigned int)24*2048)-512) #define INODE_BUF_ADDR (CODE_ADDR-1024) #define RKRDY (1<<7) struct dir_info { uint16_t ino; char name[14]; }; struct rk11 { uint16_t rkds; // 0177400 uint16_t rker; // 0177402 uint16_t rkcs; // 0177404 uint16_t rkwc; // 0177406 uint16_t rkba; // 0177410 uint16_t rkda; // 0177412 }; static volatile struct rk11 *rk11_p = (struct rk11*)RK11_CTL_REG_ADDR; static volatile inode_t *inod = (inode_t*)INODE_BUF_ADDR; static volatile int *buf = (int*)INODE_BUF_ADDR+sizeof(inode_t); /*---------------------------------- -----------------------------------*/ void memcpy(volatile void *dst, volatile void *src, int n) { while(n--) *(char*)dst++ = *(char*)src++; } int streq(char *src, char *dst) { while(*src != 0 && *dst != 0) if(*src++ != *dst++) return 0; return 1; } void read_blk(volatile void *buf, int blk_no) { unsigned int cylnd = (blk_no/12)>>1; unsigned int plane = (blk_no/12)&1; unsigned int sect = (blk_no%12); rk11_p->rkda = (cylnd<<5)|(plane<<4)|sect; rk11_p->rkba = (uint16_t)buf; rk11_p->rkwc = -256; rk11_p->rkcs = 5; // READ & GO while(!(rk11_p->rkcs & RKRDY)) ; } void iget(int ino) { int blk_no = (31+ino)/16; int i_offset = 32*((31+ino)%16); read_blk(buf, blk_no); memcpy(inod, buf+i_offset, 32); } int cstart() { static volatile void *zero_adr = 0; struct dir_info *dir_p; int i; // get root's inode info iget(1); read_blk(buf, inod->i_addr[0]); // get kernel inode info dir_p = (struct dir_info*)buf; for(i = 0; i < 512/16 && dir_p->name[0] != 0; i++, dir_p++) { if(streq(dir_p->name, "unix")) { iget(dir_p->ino); break; } } // read kernel binary file to address zero read_blk(buf, inod->i_addr[0]); for(i = 0; i < 256 && buf[i]!=0; i++) { read_blk(zero_adr+i*512, buf[i]); } if( *(int*)zero_adr == 0407) { memcpy(zero_adr, zero_adr+020, inod->i_size1); } return 0; }







バイナリファイルのサイズが512 byteに収まらなかった・・・。(771 byte)
gccの-Oオプションをつけると、実行に失敗するし。(pdp11のgccのバグかしら) 
まじめに収めようとすると、やはりアセンブラで組まないといかんかな。 


nice!(0)  コメント(0)  トラックバック(0) 

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。