一,制作真正的IPL(啟動程式裝載器)
今天的目的是将昨天的啟動程式裝載器來裝載程式。
①:磁盤最初的512位元組是啟動區。為了裝載下一個512位元組内容的程式,對之前的程式進行修改,得到了今天的harib00a程式;
②:緩沖區位址 是記憶體位址。将磁盤裡面的程式加載到記憶體中
; haribote-ipl
; TAB=4
ORG 0x7c00 ; このプログラムがどこに読み込まれるのか
; 以下は標準的なFAT12フォーマットフロッピーディスクのための記述
JMP entry
DB 0x90
DB "HARIBOTE" ; ブートセクタの名前を自由に書いてよい(8バイト)
DW 512 ; 1セクタの大きさ(512にしなければいけない)
DB 1 ; クラスタの大きさ(1セクタにしなければいけない)
DW 1 ; FATがどこから始まるか(普通は1セクタ目からにする)
DB 2 ; FATの個數(2にしなければいけない)
DW 224 ; ルートディレクトリ領域の大きさ(普通は224エントリにする)
DW 2880 ; このドライブの大きさ(2880セクタにしなければいけない)
DB 0xf0 ; メディアのタイプ(0xf0にしなければいけない)
DW 9 ; FAT領域の長さ(9セクタにしなければいけない)
DW 18 ; 1トラックにいくつのセクタがあるか(18にしなければいけない)
DW 2 ; ヘッドの數(2にしなければいけない)
DD 0 ; パーティションを使ってないのでここは必ず0
DD 2880 ; このドライブ大きさをもう一度書く
DB 0,0,0x29 ; よくわからないけどこの値にしておくといいらしい
DD 0xffffffff ; たぶんボリュームシリアル番号
DB "HARIBOTEOS " ; ディスクの名前(11バイト)
DB "FAT12 " ; フォーマットの名前(8バイト)
RESB 18 ; とりあえず18バイトあけておく
; プログラム本體
entry:
MOV AX,0 ; レジスタ初期化
MOV SS,AX
MOV SP,0x7c00
MOV DS,AX
; ディスクを読む
; ===============================這次添加的内容START=================================
;這裡就開始了讀寫磁盤的方式,下面就會更具 驅動器 柱面 扇區 磁頭 确定最終讀取的位置
MOV AX,0x0820
MOV ES,AX
MOV CH,0 ; 柱面0 CH表示的是柱面号
MOV DH,0 ; 磁頭0 磁頭号
MOV CL,2 ; 扇區2 CL扇區号
MOV AH,0x02 ;AH=0x02 : 讀盤(0x03是寫磁盤)
MOV AL,1 ;1個扇區 AL處理對象的扇區數;(隻能同時處理連續的扇區)
MOV BX,0
MOV DL,0x00 ;A驅動器
INT 0x13 ;調用磁盤BIOS 注釋:調用BIOS磁盤0x13号函數。
JC error ;注釋:這次的新指令JC:大意是:如果進位标志是1的話,就跳轉。
;這裡特别解釋一下:通過上面一連串的配置,再執行INT 0x13 我們就會去讀磁盤内容(為什麼是讀,因為我們AH那個地方配置的0x02),如果讀磁盤成功了,那麼我們就傳回0,如果錯誤就會傳回1。
;我們這裡可以這樣了解,從 MOV AX,0x0820 這裡到 MOV DL,0x00 都是我們傳遞給INT 0x13函數的參數(C語言式了解),那麼JC error 就是對函數傳回值的判斷。
;那我們傳遞給函數的參數究竟什麼意思呢?主要是告訴這個函數我到底去哪個位置讀取我想要的資料呢? 畢竟磁盤大如海,想要知道具體去那一片資料還是不容易的。
;下面來看怎麼确定讀取磁盤想要的位置:①首先加入有多個驅動器,那麼我們要指定從哪個驅動器讀取,這就是DL幹的事;②然後00000
;======================================END===========================================
; 読み終わったけどとりあえずやることないので寝る
fin:
HLT ; 何かあるまでCPUを停止させる
JMP fin ; 無限ループ
error:
MOV SI,msg
putloop:
MOV AL,[SI]
ADD SI,1 ; SIに1を足す
CMP AL,0
JE fin
MOV AH,0x0e ; 一文字表示ファンクション
MOV BX,15 ; カラーコード
INT 0x10 ; ビデオBIOS呼び出し
JMP putloop
msg:
DB 0x0a, 0x0a ; 改行を2つ
DB "load error"
DB 0x0a ; 改行
DB 0
RESB 0x7dfe-$ ; 0x7dfeまでを0x00で埋める指令
DB 0x55, 0xaa
二:試錯
目的:就是為了防止再軟碟出現偶爾錯誤的時候,程式不會立即終止,仍然去嘗試再次讀取磁盤,才有了第二節的程式:
注釋:JNC:進位标志是0的話跳轉 JAE大于或等于時跳轉
; haribote-ipl
; TAB=4
ORG 0x7c00 ; このプログラムがどこに読み込まれるのか
; 以下は標準的なFAT12フォーマットフロッピーディスクのための記述
JMP entry
DB 0x90
DB "HARIBOTE" ; ブートセクタの名前を自由に書いてよい(8バイト)
DW 512 ; 1セクタの大きさ(512にしなければいけない)
DB 1 ; クラスタの大きさ(1セクタにしなければいけない)
DW 1 ; FATがどこから始まるか(普通は1セクタ目からにする)
DB 2 ; FATの個數(2にしなければいけない)
DW 224 ; ルートディレクトリ領域の大きさ(普通は224エントリにする)
DW 2880 ; このドライブの大きさ(2880セクタにしなければいけない)
DB 0xf0 ; メディアのタイプ(0xf0にしなければいけない)
DW 9 ; FAT領域の長さ(9セクタにしなければいけない)
DW 18 ; 1トラックにいくつのセクタがあるか(18にしなければいけない)
DW 2 ; ヘッドの數(2にしなければいけない)
DD 0 ; パーティションを使ってないのでここは必ず0
DD 2880 ; このドライブ大きさをもう一度書く
DB 0,0,0x29 ; よくわからないけどこの値にしておくといいらしい
DD 0xffffffff ; たぶんボリュームシリアル番号
DB "HARIBOTEOS " ; ディスクの名前(11バイト)
DB "FAT12 " ; フォーマットの名前(8バイト)
RESB 18 ; とりあえず18バイトあけておく
; プログラム本體
entry:
MOV AX,0 ; レジスタ初期化
MOV SS,AX
MOV SP,0x7c00
MOV DS,AX
; ディスクを読む
MOV AX,0x0820
MOV ES,AX
MOV CH,0 ; 柱面0 CH表示的是柱面号
MOV DH,0 ; 磁頭0 磁頭号
MOV CL,2 ; 扇區2 CL扇區号
;===============================這次添加的新内容START=================================
MOV SI,0 ; 記錄失敗次數的寄存器
retry:
MOV AH,0x02 ; 讀盤(0x03是寫磁盤) 注釋: 看來每次讀寫資料,都要進行AH寄存器的配置,不像上面CL,可以儲存,隻配置一次
MOV AL,1 ; 1扇區 注釋:這裡是讀寫扇區的數目,和上面的CL是不同的
MOV BX,0
MOV DL,0x00 ; A驅動器
INT 0x13 ; 調用磁盤BIOS
JNC fin ; 沒出錯的話,就跳轉到fine
ADD SI,1 ; 往SI+1
CMP SI,5 ; 比較SI與5
JAE error ; SI >= 5 大于5時跳轉到error
MOV AH,0x00
MOV DL,0x00 ; A驅動器
INT 0x13 ; 重置驅動器
JMP retry
;======================================END===========================================
; 読み終わったけどとりあえずやることないので寝る
fin:
HLT ; 何かあるまでCPUを停止させる
JMP fin ; 無限ループ
error:
MOV SI,msg
putloop:
MOV AL,[SI]
ADD SI,1 ; SIに1を足す
CMP AL,0
JE fin
MOV AH,0x0e ; 一文字表示ファンクション
MOV BX,15 ; カラーコード
INT 0x10 ; ビデオBIOS呼び出し
JMP putloop
msg:
DB 0x0a, 0x0a ; 改行を2つ
DB "load error"
DB 0x0a ; 改行
DB 0
RESB 0x7dfe-$ ; 0x7dfeまでを0x00で埋める指令
DB 0x55, 0xaa
本節新添加的代碼轉化成C語言,大緻如下(僅供參考,畢竟也是個菜雞)
ErrorHandling()
{
static int SI=0;
AH=0x002;
AL=1;
BX=0;
DL=0x00;
BOOL VAL=ExecutivDrive() ;
if(FALSE == VAL)
{
執行fine函數;
}
else
{
SI++;
}
if(SI >= 5)
{
執行error函數;
}
else
{
AH=0x00;
DL=0x00;
BOOL VAL =ExecutivDrive();//執行驅動器
if(TRUE == VAL)
{
ErrorHandling();
}
}
}
ExecutivDrive()
{
INT 0x13;
}
三,讀到18扇區
這節的目的主要就是教會我們怎麼利用循環讀寫其他扇區 柱面的内容。 同樣的下一屆的内容也就自然會了。
; haribote-ipl
; TAB=4
ORG 0x7c00 ; このプログラムがどこに読み込まれるのか
; 以下は標準的なFAT12フォーマットフロッピーディスクのための記述
JMP entry
DB 0x90
DB "HARIBOTE" ; ブートセクタの名前を自由に書いてよい(8バイト)
DW 512 ; 1セクタの大きさ(512にしなければいけない)
DB 1 ; クラスタの大きさ(1セクタにしなければいけない)
DW 1 ; FATがどこから始まるか(普通は1セクタ目からにする)
DB 2 ; FATの個數(2にしなければいけない)
DW 224 ; ルートディレクトリ領域の大きさ(普通は224エントリにする)
DW 2880 ; このドライブの大きさ(2880セクタにしなければいけない)
DB 0xf0 ; メディアのタイプ(0xf0にしなければいけない)
DW 9 ; FAT領域の長さ(9セクタにしなければいけない)
DW 18 ; 1トラックにいくつのセクタがあるか(18にしなければいけない)
DW 2 ; ヘッドの數(2にしなければいけない)
DD 0 ; パーティションを使ってないのでここは必ず0
DD 2880 ; このドライブ大きさをもう一度書く
DB 0,0,0x29 ; よくわからないけどこの値にしておくといいらしい
DD 0xffffffff ; たぶんボリュームシリアル番号
DB "HARIBOTEOS " ; ディスクの名前(11バイト)
DB "FAT12 " ; フォーマットの名前(8バイト)
RESB 18 ; とりあえず18バイトあけておく
; プログラム本體
entry:
MOV AX,0 ; レジスタ初期化
MOV SS,AX
MOV SP,0x7c00
MOV DS,AX
; ディスクを読む
MOV AX,0x0820
MOV ES,AX
MOV CH,0 ; シリンダ0
MOV DH,0 ; ヘッド0
MOV CL,2 ; セクタ2
readloop:
MOV SI,0 ; 失敗回數を數えるレジスタ
retry:
MOV AH,0x02 ; AH=0x02 : ディスク読み込み
MOV AL,1 ; 1セクタ
MOV BX,0
MOV DL,0x00 ; Aドライブ
INT 0x13 ; 調用磁盤BIOS
;===============================這次添加的新内容START=================================
JNC next ; 沒有出錯就跳轉到next
ADD SI,1 ; 往SI中+1 注釋:把他當作C語言中的臨時變量或者說靜态變量就好了
CMP SI,5 ; 比較SI與5
JAE error ; SI >= 5 だったらerrorへ
MOV AH,0x00
MOV DL,0x00 ; Aドライブ
INT 0x13 ; ドライブのリセット
JMP retry
next:
MOV AX,ES ; 把記憶體位址後移0x200
ADD AX,0x0020 ; 0x0020是十六進制下512除以16的結果。是以這裡的意思就是下一個512的地方。我們知道最開始的啟動區就是512,我們以512為一個扇區。
MOV ES,AX ; ADD ES,0x020 という指令がないのでこうしている
ADD CL,1 ; CL+1 注釋: 這裡的意思是當讀取一個扇區成功後緊接着讀下一個扇區。
CMP CL,18 ; 比較CL與18 注釋:是否18個扇區都讀完了
JBE readloop ; 如果CL <= 18 就跳轉到read loop 注釋:小于等于就跳轉
;這一段代碼主要是為了讀完18個扇區,這從最後的CL 與18的比較也能看出來。如果沒有讀完就傳回最上面,如果讀完了就繼續執行到下面fine中
;======================================END===========================================
; 読み終わったけどとりあえずやることないので寝る
fin:
HLT ; 何かあるまでCPUを停止させる
JMP fin ; 無限ループ
error:
MOV SI,msg
putloop:
MOV AL,[SI]
ADD SI,1 ; SIに1を足す
CMP AL,0
JE fin
MOV AH,0x0e ; 一文字表示ファンクション
MOV BX,15 ; カラーコード
INT 0x10 ; ビデオBIOS呼び出し
JMP putloop
msg:
DB 0x0a, 0x0a ; 改行を2つ
DB "load error"
DB 0x0a ; 改行
DB 0
RESB 0x7dfe-$ ; 0x7dfeまでを0x00で埋める指令
DB 0x55, 0xaa
四,10個柱面
注釋:C0-H0-S1(柱面0;磁頭0,扇區1的縮寫);上一節中每次王CL中+1,更改的就是扇區。這把要讀柱面。可以看出,在位看書的i情況下,先行猜測,是在上一節上,在加個循環。來個cmp小于等于10 就行了。(純屬猜測,也不行改了)
; haribote-ipl
; TAB=4
CYLS EQU 10 ; 相當于宏定義,将CYLS的值等于10
ORG 0x7c00 ; このプログラムがどこに読み込まれるのか
; 以下は標準的なFAT12フォーマットフロッピーディスクのための記述
JMP entry
DB 0x90
DB "HARIBOTE" ; ブートセクタの名前を自由に書いてよい(8バイト)
DW 512 ; 1セクタの大きさ(512にしなければいけない)
DB 1 ; クラスタの大きさ(1セクタにしなければいけない)
DW 1 ; FATがどこから始まるか(普通は1セクタ目からにする)
DB 2 ; FATの個數(2にしなければいけない)
DW 224 ; ルートディレクトリ領域の大きさ(普通は224エントリにする)
DW 2880 ; このドライブの大きさ(2880セクタにしなければいけない)
DB 0xf0 ; メディアのタイプ(0xf0にしなければいけない)
DW 9 ; FAT領域の長さ(9セクタにしなければいけない)
DW 18 ; 1トラックにいくつのセクタがあるか(18にしなければいけない)
DW 2 ; ヘッドの數(2にしなければいけない)
DD 0 ; パーティションを使ってないのでここは必ず0
DD 2880 ; このドライブ大きさをもう一度書く
DB 0,0,0x29 ; よくわからないけどこの値にしておくといいらしい
DD 0xffffffff ; たぶんボリュームシリアル番号
DB "HARIBOTEOS " ; ディスクの名前(11バイト)
DB "FAT12 " ; フォーマットの名前(8バイト)
RESB 18 ; とりあえず18バイトあけておく
; プログラム本體
entry:
MOV AX,0 ; レジスタ初期化
MOV SS,AX
MOV SP,0x7c00
MOV DS,AX
; ディスクを読む
MOV AX,0x0820
MOV ES,AX
MOV CH,0 ; シリンダ0
MOV DH,0 ; 磁頭0
MOV CL,2 ; 扇區2
readloop:
MOV SI,0 ; 記錄失敗次數的寄存器
retry:
MOV AH,0x02 ; AH=0x02 : ディスク読み込み
MOV AL,1 ; 1個扇區 注釋:這裡是讀寫扇區的數目,和上面的CL是不同的
MOV BX,0
MOV DL,0x00 ; Aドライブ
INT 0x13 ; ディスクBIOS呼び出し
JNC next ; エラーがおきなければnextへ
ADD SI,1 ; SIに1を足す
CMP SI,5 ; SIと5を比較
JAE error ; SI >= 5 だったらerrorへ
MOV AH,0x00
MOV DL,0x00 ; Aドライブ
INT 0x13 ; ドライブのリセット
JMP retry
next:
MOV AX,ES ; アドレスを0x200進める
ADD AX,0x0020
MOV ES,AX ; ADD ES,0x020 という指令がないのでこうしている
ADD CL,1 ; CLに1を足す
CMP CL,18 ; CLと18を比較
JBE readloop ; CL <= 18 だったらreadloopへ
;===============================這次添加的新内容START=================================
MOV CL,1 ;這裡為什麼讀完18個扇區後,讀下一個柱面的時候,CL先+1呢? 整個磁盤是一個循環。洗一個柱面從第一個扇區開始讀寫的。
ADD DH,1 ;有兩個磁頭,正反面,反正我是這樣了解的
CMP DH,2
JB readloop ; 如果DH < 2 就跳轉到readloop。
MOV DH,0 ;反面讀完了,那麼從正面在開始讀,磁頭便置零了
ADD CH,1 ;好了,柱面也開始+1了
CMP CH,CYLS ; 這裡還用了一個宏定義。代表10個柱面
JB readloop ; 如果CH < CYLS 就跳轉到readloop
;======================================END===========================================
; 読み終わったけどとりあえずやることないので寝る
fin:
HLT ; 何かあるまでCPUを停止させる
JMP fin ; 無限ループ
error:
MOV SI,msg
putloop:
MOV AL,[SI]
ADD SI,1 ; SIに1を足す
CMP AL,0
JE fin
MOV AH,0x0e ; 一文字表示ファンクション
MOV BX,15 ; カラーコード
INT 0x10 ; ビデオBIOS呼び出し
JMP putloop
msg:
DB 0x0a, 0x0a ; 改行を2つ
DB "load error"
DB 0x0a ; 改行
DB 0
RESB 0x7dfe-$ ; 0x7dfeまでを0x00で埋める指令
DB 0x55, 0xaa
到這裡是完成了啟動區的制作。其實到這裡回過頭來看下,作者隻是将10×2×18×512=184320byte=180KB内容完整無誤的裝在到記憶體裡面了。這裡有個疑問:裝載到類裡面然後幹啥? 我們的程式(C語言的main)就能運作了? 如果我的main不止這個數呢? 哦 這裡隻是啟動區,它可以接着調用main函數? 害這裡還是不了解,不能舉一反三,真特麼的垃圾,接着往後面看:
五,着手開發作業系統 好吧我覺的這節太扯了。表示其實沒有真的看懂,大緻知道怎麼回事。仔細想想又不知道具體是怎麼回事。
六,從啟動區執行作業系統
對ORG的應用。其他的在地五節已經講過了
; haribote-ipl
; TAB=4
CYLS EQU 10 ; どこまで読み込むか
ORG 0x7c00 ; このプログラムがどこに読み込まれるのか
; 以下は標準的なFAT12フォーマットフロッピーディスクのための記述
JMP entry
DB 0x90
DB "HARIBOTE" ; ブートセクタの名前を自由に書いてよい(8バイト)
DW 512 ; 1セクタの大きさ(512にしなければいけない)
DB 1 ; クラスタの大きさ(1セクタにしなければいけない)
DW 1 ; FATがどこから始まるか(普通は1セクタ目からにする)
DB 2 ; FATの個數(2にしなければいけない)
DW 224 ; ルートディレクトリ領域の大きさ(普通は224エントリにする)
DW 2880 ; このドライブの大きさ(2880セクタにしなければいけない)
DB 0xf0 ; メディアのタイプ(0xf0にしなければいけない)
DW 9 ; FAT領域の長さ(9セクタにしなければいけない)
DW 18 ; 1トラックにいくつのセクタがあるか(18にしなければいけない)
DW 2 ; ヘッドの數(2にしなければいけない)
DD 0 ; パーティションを使ってないのでここは必ず0
DD 2880 ; このドライブ大きさをもう一度書く
DB 0,0,0x29 ; よくわからないけどこの値にしておくといいらしい
DD 0xffffffff ; たぶんボリュームシリアル番号
DB "HARIBOTEOS " ; ディスクの名前(11バイト)
DB "FAT12 " ; フォーマットの名前(8バイト)
RESB 18 ; とりあえず18バイトあけておく
; プログラム本體
entry:
MOV AX,0 ; レジスタ初期化
MOV SS,AX
MOV SP,0x7c00
MOV DS,AX
; ディスクを読む
MOV AX,0x0820
MOV ES,AX
MOV CH,0 ; シリンダ0
MOV DH,0 ; ヘッド0
MOV CL,2 ; セクタ2
readloop:
MOV SI,0 ; 失敗回數を數えるレジスタ
retry:
MOV AH,0x02 ; AH=0x02 : ディスク読み込み
MOV AL,1 ; 1セクタ
MOV BX,0
MOV DL,0x00 ; Aドライブ
INT 0x13 ; ディスクBIOS呼び出し
JNC next ; エラーがおきなければnextへ
ADD SI,1 ; SIに1を足す
CMP SI,5 ; SIと5を比較
JAE error ; SI >= 5 だったらerrorへ
MOV AH,0x00
MOV DL,0x00 ; Aドライブ
INT 0x13 ; ドライブのリセット
JMP retry
next:
MOV AX,ES ; アドレスを0x200進める
ADD AX,0x0020
MOV ES,AX ; ADD ES,0x020 という指令がないのでこうしている
ADD CL,1 ; CLに1を足す
CMP CL,18 ; CLと18を比較
JBE readloop ; CL <= 18 だったらreadloopへ
MOV CL,1
ADD DH,1
CMP DH,2
JB readloop ; DH < 2 だったらreadloopへ
MOV DH,0
ADD CH,1
CMP CH,CYLS
JB readloop ; CH < CYLS だったらreadloopへ
; 読み終わったのでharibote.sysを実行だ!
;===============================這次添加的新内容START=================================
JMP 0xc200
;這裡就是,将之前說的180KB的内容裝進了記憶體中,并且我們知道了我們的程式在0xc200的位置
;是以前面做的隻是讀取,這裡有點犯迷糊。仔細想一想,之前是讀取磁盤的内容到一個記憶體中
;假設他們的位址從0~100,現在我們讀完之後,到自己的記憶體中c200的位置去執行。好吧反正我是覺得挺繞的。
;另外我們的磁盤大小就是180KB,我想知道如果程式不在這個180 中怎麼辦?或者180沒讀完怎麼辦?????
;======================================END===========================================
error:
MOV SI,msg
putloop:
MOV AL,[SI]
ADD SI,1 ; SIに1を足す
CMP AL,0
JE fin
MOV AH,0x0e ; 一文字表示ファンクション
MOV BX,15 ; カラーコード
INT 0x10 ; ビデオBIOS呼び出し
JMP putloop
fin:
HLT ; 何かあるまでCPUを停止させる
JMP fin ; 無限ループ
msg:
DB 0x0a, 0x0a ; 改行を2つ
DB "load error"
DB 0x0a ; 改行
DB 0
RESB 0x7dfe-$ ; 0x7dfeまでを0x00で埋める指令
DB 0x55, 0xaa
七,确認作業系統的執行情況
注釋:這節主要的目的是給顯示其以色彩。調用顯使能
; haribote-ipl
; TAB=4
CYLS EQU 10 ; どこまで読み込むか
ORG 0x7c00 ; このプログラムがどこに読み込まれるのか
; 以下は標準的なFAT12フォーマットフロッピーディスクのための記述
JMP entry
DB 0x90
DB "HARIBOTE" ; ブートセクタの名前を自由に書いてよい(8バイト)
DW 512 ; 1セクタの大きさ(512にしなければいけない)
DB 1 ; クラスタの大きさ(1セクタにしなければいけない)
DW 1 ; FATがどこから始まるか(普通は1セクタ目からにする)
DB 2 ; FATの個數(2にしなければいけない)
DW 224 ; ルートディレクトリ領域の大きさ(普通は224エントリにする)
DW 2880 ; このドライブの大きさ(2880セクタにしなければいけない)
DB 0xf0 ; メディアのタイプ(0xf0にしなければいけない)
DW 9 ; FAT領域の長さ(9セクタにしなければいけない)
DW 18 ; 1トラックにいくつのセクタがあるか(18にしなければいけない)
DW 2 ; ヘッドの數(2にしなければいけない)
DD 0 ; パーティションを使ってないのでここは必ず0
DD 2880 ; このドライブ大きさをもう一度書く
DB 0,0,0x29 ; よくわからないけどこの値にしておくといいらしい
DD 0xffffffff ; たぶんボリュームシリアル番号
DB "HARIBOTEOS " ; ディスクの名前(11バイト)
DB "FAT12 " ; フォーマットの名前(8バイト)
RESB 18 ; とりあえず18バイトあけておく
; プログラム本體
entry:
MOV AX,0 ; レジスタ初期化
MOV SS,AX
MOV SP,0x7c00
MOV DS,AX
; ディスクを読む
MOV AX,0x0820
MOV ES,AX
MOV CH,0 ; シリンダ0
MOV DH,0 ; ヘッド0
MOV CL,2 ; セクタ2
readloop:
MOV SI,0 ; 失敗回數を數えるレジスタ
retry:
MOV AH,0x02 ; AH=0x02 : ディスク読み込み
MOV AL,1 ; 1セクタ
MOV BX,0
MOV DL,0x00 ; Aドライブ
INT 0x13 ; ディスクBIOS呼び出し
JNC next ; エラーがおきなければnextへ
ADD SI,1 ; SIに1を足す
CMP SI,5 ; SIと5を比較
JAE error ; SI >= 5 だったらerrorへ
MOV AH,0x00
MOV DL,0x00 ; Aドライブ
INT 0x13 ; ドライブのリセット
JMP retry
next:
MOV AX,ES ; アドレスを0x200進める
ADD AX,0x0020
MOV ES,AX ; ADD ES,0x020 という指令がないのでこうしている
ADD CL,1 ; CLに1を足す
CMP CL,18 ; CLと18を比較
JBE readloop ; CL <= 18 だったらreadloopへ
MOV CL,1
ADD DH,1
CMP DH,2
JB readloop ; DH < 2 だったらreadloopへ
MOV DH,0
ADD CH,1
CMP CH,CYLS
JB readloop ; CH < CYLS だったらreadloopへ
; 読み終わったのでharibote.sysを実行だ!
;===============================這次添加的新内容START=================================
MOV [0x0ff0],CH ; 記下IPL讀到哪裡了。 注釋:咱也不知道這裡是幹啥用的,後面看看再說
;了解:大緻意思是我們目前在哪一個柱面
JMP 0xc200
;======================================END===========================================
error:
MOV SI,msg
putloop:
MOV AL,[SI]
ADD SI,1 ; SIに1を足す
CMP AL,0
JE fin
MOV AH,0x0e ; 一文字表示ファンクション
MOV BX,15 ; カラーコード
INT 0x10 ; ビデオBIOS呼び出し
JMP putloop
fin:
HLT ; 何かあるまでCPUを停止させる
JMP fin ; 無限ループ
msg:
DB 0x0a, 0x0a ; 改行を2つ
DB "load error"
DB 0x0a ; 改行
DB 0
RESB 0x7dfe-$ ; 0x7dfeまでを0x00で埋める指令
DB 0x55, 0xaa
;haribote.nas
; haribote-os
; TAB=4
;===============================這次添加的新内容START=================================
ORG 0xc200 ; 這個程式要被裝在到記憶體的什麼地方呢?
;這個意思就是說,我們的程式所有的最初的地方是從這個位址開始的
MOV AL,0x13 ; 這裡的AL和之前的啟動區的AL 和 AH不大一樣。注意區分!這裡是VGA顯示卡,320×200×8位彩色
MOV AH,0x00
INT 0x10 ;沒猜錯這裡的INT就是顯示卡的 那個BIOS,和之前的CPU的BIOS一樣的方式。先設定參數,在調用這裡。上面的AH應該就是參數了
;======================================END===========================================
fin:
HLT
JMP fin
解釋:
八,32位的前期準備
; haribote-os
; TAB=4
; BOOT_INFO関係
CYLS EQU 0x0ff0 ; 設定啟動區
LEDS EQU 0x0ff1
VMODE EQU 0x0ff2 ; 關于顔色數目的資訊。顔色的位數
SCRNX EQU 0x0ff4 ; 分辨率的X
SCRNY EQU 0x0ff6 ; 分辨率的Y
VRAM EQU 0x0ff8 ; 圖像緩沖區的開始位址 注釋:VRAM是顯示卡記憶體
ORG 0xc200 ; 這個程式要裝載到的記憶體的地方
MOV AL,0x13 ; VGA顯示卡,320x200x8位彩色
MOV AH,0x00
INT 0x10
MOV BYTE [VMODE],8 ; 記錄畫面模式
MOV WORD [SCRNX],320
MOV WORD [SCRNY],200
MOV DWORD [VRAM],0x000a0000
; 用BIOS取得鍵盤上各種LED訓示燈的狀态
MOV AH,0x02
INT 0x16 ; keyboard BIOS
MOV [LEDS],AL
fin:
HLT
JMP fin

;asmhead.nas
; haribote-os boot asm
; TAB=4
BOTPAK EQU 0x00280000 ; bootpackのロード先
DSKCAC EQU 0x00100000 ; ディスクキャッシュの場所
DSKCAC0 EQU 0x00008000 ; ディスクキャッシュの場所(リアルモード)
; BOOT_INFO関係
CYLS EQU 0x0ff0 ; ブートセクタが設定する
LEDS EQU 0x0ff1
VMODE EQU 0x0ff2 ; 色數に関する情報。何ビットカラーか?
SCRNX EQU 0x0ff4 ; 解像度のX
SCRNY EQU 0x0ff6 ; 解像度のY
VRAM EQU 0x0ff8 ; グラフィックバッファの開始番地
ORG 0xc200 ; このプログラムがどこに読み込まれるのか
; 畫面モードを設定
MOV AL,0x13 ; VGAグラフィックス、320x200x8bitカラー
MOV AH,0x00
INT 0x10
MOV BYTE [VMODE],8 ; 畫面モードをメモする(C言語が參照する)
MOV WORD [SCRNX],320
MOV WORD [SCRNY],200
MOV DWORD [VRAM],0x000a0000
; キーボードのLED狀態をBIOSに教えてもらう
MOV AH,0x02
INT 0x16 ; keyboard BIOS
MOV [LEDS],AL
;===============================這次添加的新内容START=================================
;這裡就是為了系統能夠調用C語言做的準備,但是作者目前沒有說,期待之後的補充
; PICが一切の割り込みを受け付けないようにする
; AT互換機の仕様では、PICの初期化をするなら、
; こいつをCLI前にやっておかないと、たまにハングアップする
; PICの初期化はあとでやる
MOV AL,0xff
OUT 0x21,AL
NOP ; OUT指令を連続させるとうまくいかない機種があるらしいので
OUT 0xa1,AL
CLI ; さらにCPUレベルでも割り込み禁止
; CPUから1MB以上のメモリにアクセスできるように、A20GATEを設定
CALL waitkbdout
MOV AL,0xd1
OUT 0x64,AL
CALL waitkbdout
MOV AL,0xdf ; enable A20
OUT 0x60,AL
CALL waitkbdout
; プロテクトモード移行
[INSTRSET "i486p"] ; 486の指令まで使いたいという記述
LGDT [GDTR0] ; 暫定GDTを設定
MOV EAX,CR0
AND EAX,0x7fffffff ; bit31を0にする(ページング禁止のため)
OR EAX,0x00000001 ; bit0を1にする(プロテクトモード移行のため)
MOV CR0,EAX
JMP pipelineflush
pipelineflush:
MOV AX,1*8 ; 読み書き可能セグメント32bit
MOV DS,AX
MOV ES,AX
MOV FS,AX
MOV GS,AX
MOV SS,AX
; bootpackの転送
MOV ESI,bootpack ; 転送元
MOV EDI,BOTPAK ; 転送先
MOV ECX,512*1024/4
CALL memcpy
; ついでにディスクデータも本來の位置へ転送
; まずはブートセクタから
MOV ESI,0x7c00 ; 転送元
MOV EDI,DSKCAC ; 転送先
MOV ECX,512/4
CALL memcpy
; 殘り全部
MOV ESI,DSKCAC0+512 ; 転送元
MOV EDI,DSKCAC+512 ; 転送先
MOV ECX,0
MOV CL,BYTE [CYLS]
IMUL ECX,512*18*2/4 ; シリンダ數からバイト數/4に変換
SUB ECX,512/4 ; IPLの分だけ差し引く
CALL memcpy
; asmheadでしなければいけないことは全部し終わったので、
; あとはbootpackに任せる
; bootpackの起動
MOV EBX,BOTPAK
MOV ECX,[EBX+16]
ADD ECX,3 ; ECX += 3;
SHR ECX,2 ; ECX /= 4;
JZ skip ; 転送するべきものがない
MOV ESI,[EBX+20] ; 転送元
ADD ESI,EBX
MOV EDI,[EBX+12] ; 転送先
CALL memcpy
skip:
MOV ESP,[EBX+12] ; スタック初期値
JMP DWORD 2*8:0x0000001b
waitkbdout:
IN AL,0x64
AND AL,0x02
JNZ waitkbdout ; ANDの結果が0でなければwaitkbdoutへ
RET
memcpy:
MOV EAX,[ESI]
ADD ESI,4
MOV [EDI],EAX
ADD EDI,4
SUB ECX,1
JNZ memcpy ; 引き算した結果が0でなければmemcpyへ
RET
; memcpyはアドレスサイズプリフィクスを入れ忘れなければ、ストリング指令でも書ける
ALIGNB 16
GDT0:
RESB 8 ; ヌルセレクタ
DW 0xffff,0x0000,0x9200,0x00cf ; 読み書き可能セグメント32bit
DW 0xffff,0x0000,0x9a28,0x0047 ; 実行可能セグメント32bit(bootpack用)
DW 0
GDTR0:
DW 8*3-1
DD GDT0
ALIGNB 16
bootpack:
;======================================END===========================================
void HariMain(void)
{
fin:
/* ここにHLTを入れたいのだが、C言語ではHLTが使えない! */
goto fin;
}