制作真正的IPL
IPL(Initial Program Loader,启动程序装载器)。
磁盘最初的512字节是启动区,所以要装载下一个512字节的内容。
; haribote-ipl
; TAB=4
ORG 0x7c00 ; 指明程序的装在地址
; 以下的记述用于标记FAT12格式的软盘
JMP entry
DB 0x90
DB "HARIBOTE" ; 启动区的名称可以是任意是字符串(8字节)
DW 512 ; 每个扇区(sector)的大小(必须为512字节)
DB 1 ; 簇(cluster)的大小(必须为1个扇区)
DW 1 ; FAT的起试位置(一般从第一个扇区开始)
DB 2 ; FAT的个数(必须为2)
DW 224 ; 根目录的大小(一般设置成224项)
DW 2880 ; 该磁盘的大小(必须是2880扇区)
DB 0xf0 ; 磁盘的种类(必须是0xf0)
DW 9 ; FAT的长度(必须是9扇区)
DW 18 ; 1个磁道(track)有几个扇区(必须是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
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加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-$ ;填写0x00,直到0x001fe
DB 0x55, 0xaa
JC(如果进位标志是1的化,就跳转)
‘INT 0x13’调用BIOS0x13号函数。
进位标志是一个只能存储1位信息的寄存器。CPU还又其他几个1位寄存器,1位寄存器我们称为标志。标志在英文中位flag(旗帜)。开关就像升旗降旗的状态一样。
这次CF的作用是报告BIOS函数调用是否有错的。
CH,CL,DH,DL分别是柱面号、扇区号、磁头号、驱动器号
缓冲地址:这是个内存地址,表明要把从软盘上读出的数据装载到内存的哪个位置。当时为了寻址,设计了起辅助作用的段寄存器(segment register)在指定内存地址的时候,可以使用这个段寄存器。
ES:BX 这种方式来表示地址,写成MOV AL,[ES:BX], 他代表ES×16+BX的内存地址。
不管要指定内存的什么地址,都必须同时指定段寄存器这是规定。一般如果是省略的话,就会把'DS:'作为默认的段寄存器。
‘MOV CX,[1234]’其实是‘MOV CX,[DS: 1234]’的意思。在汇编语言中,可以省略默认的段寄存器DS
因为有这样的规则,所以DS必须预先指定位0,否则地址的值就要加上这个数的16倍,就会读写到其他地方,引起混乱。
试错
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加1
CMP SI,5 ; 比较SI与5
JAE error ; SI >= 5 跳转到error
MOV AH,0x00
MOV DL,0x00 ; A驱动器
INT 0x13 ; 重置驱动器
JMP retry
JNC是另外一个条件跳转指令'jump if not carry'的缩写。也就是说进位标志是0的话就跳转。JAE也是条件跳转指令,‘Jump if above or equal’,意思是大于或等于时跳转。
读到18扇区
; haribote-ipl
; TAB=4
ORG 0x7c00 ; 指明程序的装在地址
; 以下的记述用于标记FAT12格式的软盘
JMP entry
DB 0x90
DB "HARIBOTE" ; 启动区的名称可以是任意是字符串(8字节)
DW 512 ; 每个扇区(sector)的大小(必须为512字节)
DB 1 ; 簇(cluster)的大小(必须为1个扇区)
DW 1 ; FAT的起试位置(一般从第一个扇区开始)
DB 2 ; FAT的个数(必须为2)
DW 224 ; 根目录的大小(一般设置成224项)
DW 2880 ; 该磁盘的大小(必须是2880扇区)
DB 0xf0 ; 磁盘的种类(必须是0xf0)
DW 9 ; FAT的长度(必须是9扇区)
DW 18 ; 1个磁道(track)有几个扇区(必须是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
; 虽然读完了,但是因为没有要做的事情所以睡眠
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 ; 换行两行
DB "load error"
DB 0x0a ; 换行
DB 0
RESB 0x7dfe-$ ; 以0x00填充到0x7dfe为止的命令
DB 0x55, 0xaa
JBE条件跳转指令,是“Jump if below or equal”的缩写,小于等于则跳转。
叨叨几句... NOTHING