制作真正的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的地方。