30天自制作業系統---第3天
阿新 • • 發佈:2021-02-23
一,製作真正的IPL(啟動程式裝載器)
今天的目的是將昨天的啟動程式裝載器來裝載程式。
①:磁碟最初的512位元組是啟動區。為了裝載下一個512位元組內容的程式,對之前的程式進行修改,得到了今天的harib00a程式;
②:緩衝區地址 是記憶體地址。將磁盤裡面的程式載入到記憶體中
二:試錯
目的:就是為了防止再軟盤出現偶爾錯誤的時候,程式不會立即終止,仍然去嘗試再次讀取磁碟,才有了第二節的程式:
註釋:JNC:進位標誌是0的話跳轉 JAE大於或等於時跳轉
五,著手開發作業系統 好吧我覺的這節太扯了。表示其實沒有真的看懂,大致知道怎麼回事。仔細想想又不知道具體是怎麼回事。 六,從啟動區執行作業系統 對ORG的應用。其他的在地五節已經講過了
; 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
; 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
九:開始匯入C語言
;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; }
&nbs