製作真正的IPL
1.helloos.nas文件及註解
; hello-os
; TAB=4
; 以下是一段是標準的fat12格式軟盤專用的代碼
DB 0xeb, 0x4e, 0x90
DB "HELLOIPL" ;啓動區的名稱可以使任意的字符串
DW 512 ;每個扇區的大小(必?512)
DB 1 ; 簇的大小
DW 1 ; fat的起始位置
DB 2 ; fat的個數
DW 224 ; 根目錄的大小(一般設置成224)
DW 2880 ; 該磁盤的大小(必須是2880扇區)
DB 0xf0 ;磁盤的種類(必須是0xf0)
DW 9 ;fat的長度(必須是9扇區)
DW 18 ; 1個磁道有幾個扇區(必須是18)
DW 2 ; 磁頭數
DD 0 ; 不使用分區,必須是0
DD 2880 ; 重寫一次磁盤大小(必須是2880)
DB 0,0,0x29 ;意義不明,固定
DD 0xffffffff ; (可能是)卷標號碼
DB "HELLO-OS " ; 磁盤的名稱
DB "FAT12 " ;磁盤格式名稱
RESB 18 ;先空出18字節
; 程序主體
DB 0xb8, 0x00, 0x00, 0x8e, 0xd0, 0xbc, 0x00, 0x7c
DB 0x8e, 0xd8, 0x8e, 0xc0, 0xbe, 0x74, 0x7c, 0x8a
DB 0x04, 0x83, 0xc6, 0x01, 0x3c, 0x00, 0x74, 0x09
DB 0xb4, 0x0e, 0xbb, 0x0f, 0x00, 0xcd, 0x10, 0xeb
DB 0xee, 0xf4, 0xeb, 0xfd
;信息顯示部分
DB 0x0a, 0x0a ; 改行
DB "hello, world"
DB 0x0a ; 改行
DB 0
RESB 0x1fe-$ ;
DB 0x55, 0xaa
; 以下是啓動區意外部分的輸出
DB 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
RESB 4600
DB 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
RESB 1469432
- ipl.nas
; haribote-ipl
; TAB=4
ORG 0x7c00 ; 啓動區入口
; 以下是一段是標準的fat12格式軟盤專用的代碼
JMP entry
DB 0x90
DB "HELLOIPL" ;啓動區的名稱可以使任意的字符串
DW 512 ;每個扇區的大小(必?512)
DB 1 ; 簇的大小
DW 1 ; fat的起始位置
DB 2 ; fat的個數
DW 224 ; 根目錄的大小(一般設置成224)
DW 2880 ; 該磁盤的大小(必須是2880扇區)
DB 0xf0 ;磁盤的種類(必須是0xf0)
DW 9 ;fat的長度(必須是9扇區)
DW 18 ; 1個磁道有幾個扇區(必須是18)
DW 2 ; 磁頭數
DD 0 ; 不使用分區,必須是0
DD 2880 ; 重寫一次磁盤大小(必須是2880)
DB 0,0,0x29 ;意義不明,固定
DD 0xffffffff ; (可能是)卷標號碼
DB "HELLO-OS " ; 磁盤的名稱
DB "FAT12 " ;磁盤格式名稱
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
MOV AH,0x02 ; AH=0x02 : 讀盤
MOV AL,1 ; 1個磁區
MOV BX,0
MOV DL,0x00 ; A驅動器
INT 0x13 ; 調用磁盤BIOS
JC error
fin:
HLT ; 讓CPU停止;等待指令
JMP fin ; 無限循環
error:
MOV SI,msg
putloop:
MOV AL,[SI]
ADD SI,1 ;給si加一
CMP AL,0
JE fin
MOV AH,0x0e ; 顯示一個文字
MOV BX,15 ; 指定字符顏色
INT 0x10 ; 調用顯卡BIOS
JMP putloop
msg:
DB 0x0a, 0x0a ;換行兩次
DB "load error"
DB 0x0a ; 改行
DB 0
RESB 0x7dfe-$
DB 0x55, 0xaa
1張軟盤有80個柱面,2個磁頭,18個扇區,每個扇區有512個字節。所以一張軟盤的容量爲80*2*18*512=1440kb
試錯
軟盤有可能發生不能讀數據的錯誤情況,所以決定利用循環重試5次。
添加的代碼如下:
;讀磁盤
MOV AX,0x0820
MOV ES,AX
MOV CH,0 ;柱面0
MOV DH,0 ; 磁頭0
MOV CL,2 ; 扇區2
MOV SI,0 ; 記錄失敗次數的寄存器
retry:
MOV AH,0x02 ; AH=0x02 : 讀入磁盤
MOV AL,1 ; 1個扇區
MOV BX,0
MOV DL,0x00 ;A驅動器
INT 0x13 ; 調用磁盤BIOS
JNC fin ; 沒錯的話跳入fin
ADD SI,1 ; 否則si加一
CMP SI,5 ; SI與5比較
JAE error ; SI >= 5 跳轉到error
MOV AH,0x00
MOV DL,0x00 ; A驅動器
INT 0x13 ; 充值驅動器
JMP retry
出錯後的處理:重新讀盤之前,做了如下處理:
AH=0x00,DL=0x00,INT=0x13。這些代碼的作用是系統復位,復位軟盤狀態。
3.讀到18扇區
本次添加的代碼:
; 讀磁盤
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 ; 沒錯的話跳入fin
ADD SI,1 ; 否則si加一
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
要讀下一個扇區,只需要將cl加一,ES加上0x20就行了。cl爲扇區號,es爲讀入的地址。es加上20相當於bx加上512.
4.讀入10個柱面
本次添加的代碼如下:
;讀磁盤
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 ; 沒錯的話跳入fin
ADD SI,1 ; 否則si加一
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
注意在程序的開頭用瞭如下代碼:CYLS EQU 10意思是CYLS=10
現在把軟盤最初的10*2*18*512=184320byte=180kb裝載到內存中去了。填在內存0x08200~0x34fff的地方。