Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 152 additions & 0 deletions lib/bootsector.asm
Original file line number Diff line number Diff line change
@@ -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 ; ブートシグニチャ
Binary file added lib/bootsector.bin
Binary file not shown.
142 changes: 142 additions & 0 deletions lib/secondboot.asm
Original file line number Diff line number Diff line change
@@ -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:
Binary file added lib/secondboot.bin
Binary file not shown.
Empty file added src/devices/keyboard.rs
Empty file.
3 changes: 2 additions & 1 deletion src/devices/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pub mod crt;
pub mod crt;
pub mod keyboard;