diff --git a/lib/bootsector.asm b/lib/bootsector.asm new file mode 100644 index 0000000..9c626b8 --- /dev/null +++ b/lib/bootsector.asm @@ -0,0 +1,152 @@ +;;; IPL program (ipl.asm) +;;; For x86 Architecture +;;; @author k-masatany + + ORG 0x7c00 + + ;; #define + cyls equ 0x0a ; 何シリンダ目まで読み込むかの設定 + +START: + jmp INIT ; 3 byte code(naskだと2バイトになるので注意) + + ;; FAT12BPB +FAT12: + db "rusternel" ; OS名 + dw 512 ; 1セクタあたりのバイト数 + db 1 ; 1クラスあたりのセクタ数 + dw 1 ; 予約セクタ + db 2 ; FATのテーブルの数 + dw 224 ; ルートディレクトリの長さ + dw 2880 ; 全セクタ数 + db 0xF0 ; メディアの種類 + dw 9 ; FAT1つの長さ(セクタ単位) + dw 18 ; 1トラックあたりのセクタの数 + dw 2 ; ドライブのヘッドの数 + dd 0 ; 他のパーティションのブートセクタの位置(0ならなし) + dd 2880 ; 全セクタ数(2880か0を指定) + db 0 ; ドライブ番号 + db 0 ; 予約(WindowsNTで使用) + db 0x29 ; 以下の3項目があることを示す + + dd 0xffffffff ; ボリュームシリアル番号 + db 'rusternel ' ; ボリュームラベル + db 'FAT12 ' ; ファイルシステム名 + times 18 db 0 ; 18バイト空けておく + + ;; 一連の初期化処理 +INIT: + ;; セグメントレジスタを初期化(全て0x0000 = csに設定 ) + mov ax,cs + mov ds,ax ; データセグメント初期化 + mov es,ax ; エクストラセグメン初期化 + mov ss,ax ; スタックセグメント初期化 + + ;; スタックポインタ初期化(0x7c00に設定) + ;; SPは0x7c00にしないと正常に動かない(原因は調査中) + mov sp,0x7c00 + + ;; ディスク読み込みの初期化 +DISK_INI: + mov si,loadimg + call PRINT + + mov ax,0x0820 ; 読み込んだデータをセグメントアドレス0x0820に展開 + mov es,ax + mov ch,0 ; シリンダ0 + mov dh,0 ; ヘッド0 + mov cl,2 ; セクタ2 + mov dl,0x00 ; Aドライブ + mov bx,0x0000 ; オフセットアドレスを0に設定 + +READLOOP: + mov si,0 ; 失敗回数を数えるレジスタsiを初期化 + +RETRY: + mov ah,0x02 + mov al,1 ; 1セクタ読み込み + int 0x13 ; ディスク関連ファンクション呼出 + jnc NEXT ; cf=0(エラー未発生)ならNEXTへ + + ;; 失敗した場合 + add si,1 + cmp si,5 + jae ERROR ; 5回失敗したら、エラー + + ;; ドライブのリセット + mov ah,0x00 + int 0x13 + jmp RETRY + +NEXT: + ;; セグメントアドレスを0x200(512バイト)進める + mov ax,es + add ax,0x0020 + mov es,ax + + add cl,1 ; セクタを1進める + + ;; 18セクタ読み込んだか + cmp cl,18 + jbe READLOOP + + add dh,1 ; ヘッド1へ + mov cl,1 ; セクタ1から読み込み + + ;;裏表読み込んだか + cmp dh,2 + jb READLOOP + + + add ch,1 ; シリンダを1進める + mov dh,0 ; ヘッド0から読み込み + + ;; 10シリンダ目まで読み込んだか + cmp ch,cyls + jb READLOOP + +READ_SETUP: + mov ax,0x0000 + mov es,ax ; もう一度esを初期化(もとの状態にもどす) + + mov si,complete + call PRINT + + mov [0x0ff0],ch ; 何シリンダ目まで読み込んだかメモ + + jmp 0xc200 + + jmp FIN ; ジャンプに失敗したとき用 + +ERROR: + mov si,error_mes + call PRINT + +FIN: + HLT + jmp FIN + + ;; 文字出力ルーチン +PRINT: + lodsb ; siで指定されたアドレスから1バイト取り出しalに格納 + cmp al,0 + je PRINTED ; 文末まで来たらPRINTEDへ + + mov ah,0x0e ; 1文字書き込みモード + mov bx,0x0007 + int 0x10 + + jmp PRINT + +PRINTED: + ret ; 呼出し元へ戻る + + ;; 文字データ +STRING_DATA: + loadimg db 'Loading image...', 0x0d,0x0a,0x00 ; 最後は、CR+LF+NULL + complete db 'Loading complete!', 0x0d,0x0a,0x00 + error_mes db 'Loading error.', 0x0d,0x0a,0x00 + + times 512 - 2 - ($-$$) db 0 ; 残りのバイトを0で埋める + + dw 0xAA55 ; ブートシグニチャ diff --git a/lib/bootsector.bin b/lib/bootsector.bin new file mode 100644 index 0000000..732ca9c Binary files /dev/null and b/lib/bootsector.bin differ diff --git a/lib/secondboot.asm b/lib/secondboot.asm new file mode 100644 index 0000000..89e02fa --- /dev/null +++ b/lib/secondboot.asm @@ -0,0 +1,142 @@ +;;; For x86 Architecture +;;; @author k-masatany + + org 0xc200 + +INITOS EQU 0x00280000 ; OS本体部分の転送アドレス +DSKCAC EQU 0x00100000 ; キャッシュのアドレス +DSKCAC0 EQU 0x00008000 ; キャッシュのアドレス(iplが転送したもの) +VRAM EQU 0x000B8000 ; グラフィックバッファ(テキストモード)の開始番地 + +;;; BOOTINFO関連 +CYLS EQU 0x0ff0 ; 読み込んだシリンダ数を記録(iplが書き込んだ) +LEDS EQU 0x0ff1 + +; テキストモード固定 + mov al, 0x03 + mov ah, 0x00 + int 0x10 + +keystatus: + ;; キーボードの状態を取得 + mov ah,0x02 + int 0x16 + mov [LEDS],al ; LED点灯状態をメモ + + ;; PICが一切の割り込みを受け付けないようにする + mov al,0xff + out 0x21,al ; io出力 + nop ; out命令を連続させるとうまくいかない機種があるため + cli ; CPUレベルでも割り込み禁止 + + ;; A20GATE信号線をONにする(1MB以上のメモリにアクセスするため) + call waitkbdout ; 制御命令を受けられるまで待つ + mov al,0xd1 ; 0xd1 = キーボードコントローラのおまけ出力ポートに出力 + out 0x64,al ; 0x64 = PORT_KEYCMD + + call waitkbdout ; 制御命令を受けられるまで待つ + mov al,0x1f ; 0x1f : A20信号線をONにするための設定 + out 0x60,al ; 0x60 = PORT_KEYDAT + + call waitkbdout ; A20GATEの設定が終わるまで待つ + + ;; プロテクトモードに移行 + + lgdt [GDTR0] ; 暫定GDTを設定 + + mov eax,cr0 + and eax,0x7fffffff ; bit31を0にする(ページングを禁止するため) + or eax,0x00000001 ; bit0を1にする(プロテクトモードへ移行) + mov cr0,eax + + jmp pipelineflush ; パイプラインに先読みした命令をリセット + +pipelineflush: + ;; セグメントレジスタの値を設定しなおす(0x0008に設定) + mov ax,1*8 ; 2つ目のセグメント(gdt + 1) = 0x0000 + 1 * 8 + mov ds,ax + mov es,ax + mov fs,ax + mov gs,ax + mov ss,ax + + ;; os本体の転送 + mov esi,initOS ; 転送元 + mov edi,INITOS ; 転送先 + mov ecx,512*1024/4 ; 512キロバイト(512*1024)を4で割る(ダブルワード単位なので) + call memcpy + + ;; ディスクデータを転送 + ;; まずはipl部分の転送 + mov esi,0x7c00 ; 転送元 + mov edi,DSKCAC ; 転送先 + mov ecx,512/4 ; 512バイト転送 + call memcpy + + ;; 残りのディスクキャッシュを転送 + mov esi,DSKCAC0+512 ; 転送元 + mov edi,DSKCAC+512 ; 転送先 + mov ecx,0 + mov cl,BYTE [CYLS] ; シリンダ数を読み込み + IMUL ecx,512*18*2/4 ; 1シリンダ分の大きさ(512バイト*18セクタ*2ヘッド分)*10シリンダ(ecxに格納) + sub ecx,512/4 ; iplの分だけ引く + call memcpy + + ;; .dataの領域を確保 + mov ebx,INITOS + mov ecx,[ebx+16] ; .dataセクションのサイズを代入 + add ecx,3 ; ecx += 3 + shr ecx,2 ; ecx /= 4(右に2桁シフト->1桁シフトで半分になる)=>転送するサイズ + jz skip ; .dataセクションの有無を確認(セクションがあれば.data領域を確保) + mov esi,[ebx+20] ; .dataセクションのファイル内の相対アドレス + add esi,ebx ; 転送元(ファイルから転送されたructiss.sysの.dataセクション) + mov edi,[ebx+12] ; 転送先(.data転送先とスタック領域の境目) + call memcpy + +skip: + ;; initOSに制御を移す + mov esp,[ebx+12] ; スタックポインタを設定(.data転送先とスタック領域の境目) + jmp DWORD 2*8:0x0000001b ; .sysのヘッダのjmp命令のある場所へジャンプ(2番目のセグメントの0x001bへジャンプ) + +fin: + hlt + jmp fin + +;;; サブルーチン関係 +waitkbdout: + in al,0x64 ; 装置番号0x64から読み込み + and al,0x02 ; 下から2ビット目の以外はマスク + in al,0x60 ; から読みして受信バッファからキーボードに溜ってるデータを出す + jnz waitkbdout ; 下から2ビット目が0 + ret + +memcpy: + mov eax,[esi] + add esi,4 + + mov [edi],eax + add edi,4 + + sub ecx,1 + jnz memcpy + + ret + + ALIGNB 16,DB 0 ; GDT0のラベルのアドレスが8の倍数になるように、キリのよいところまでDB 0で埋める + +;;; 定数 +GDT0: + times 8 DB 0 ; ヌルセレクタ(gdtの0番) + DW 0xffff,0x0000,0x9200,0x00cf ; 1番(asmhead用,読み書き可能セグメント) + DW 0xffff,0x0000,0x9a28,0x0047 ; 2番(osmain用,実行可能セグメント) + + DW 0 + +GDTR0: + DW 8*3-1 ; lgdt命令でレジスタに転送されるGDTのテーブルサイズ + DD GDT0 ; lgdt命令でレジスタに転送されるGDTの先頭アドレス + + ALIGNB 16,DB 0 + +;;; os本体へのラベル +initOS: diff --git a/lib/secondboot.bin b/lib/secondboot.bin new file mode 100644 index 0000000..ddef4ff Binary files /dev/null and b/lib/secondboot.bin differ diff --git a/src/devices/keyboard.rs b/src/devices/keyboard.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/devices/mod.rs b/src/devices/mod.rs index 5c9e0da..876d372 100644 --- a/src/devices/mod.rs +++ b/src/devices/mod.rs @@ -1 +1,2 @@ -pub mod crt; \ No newline at end of file +pub mod crt; +pub mod keyboard; \ No newline at end of file