AH=0x02;(读盘)
AH=0x03;(写盘)
AH=0x04;(校验)
AH=0x0c;(寻道)
AL=处理对象的扇区数;(只能同时处理连续的扇区)
CH=柱面号 &0xff;
CL=扇区号(0-5位)|(柱面号&0x300)>>2;
DH=磁头号;
DL=驱动器号;
ES:BX=缓冲地址;(校验及寻道时不使用)
FLAGS.CF == 0; 没有错误,AH == 0
FLAGS.CF == 1; 有错误,错误号码存入AH内(与重置(reset)功能一样)
IPL
的启动区,位于C0-H0-S1
(柱面0,磁头0,扇区1的缩写),下一个扇区是C0-H0-S2
0~0xffff
,也就是0~65535
,最大64KMOV AL, [ES:BX]
:ES×16+BX
ES=0x0820
,BX=0
。所以软盘的数据将被装载到内存中0x8200
到0x83ff
的地方,0x8000
~0x81ff
这512字节是留给启动区的,要将启动区的内容读到那里。MOV AL, [SI]
相当于MOV AL, [DS:SI]
; haribote-ipl
; TAB=4
ORG 0x7c00 ; 指明程序的装载地址
; 以下的记述用于标准FAT12格式的软盘
JMP entry
DB 0x90
DB "HARIBOTE" ; 引导扇区的名称,随意写,8字节
DW 512 ; 每个扇区的大小,必须是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 ; 重写一次磁盘大小,4字节
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 ; 段寄存器初始化为0
; 僨傿僗僋傪撉傓
MOV AX,0x0820
MOV ES,AX ; 指定附加段地址寄存器的值0x0820
MOV CH,0 ; 柱面0
MOV DH,0 ; 磁头0
MOV CL,2 ; 扇区2
MOV AH,0x02 ; AH=0x02: 读盘
MOV AL,1 ; 1个扇区
MOV BX,0 ; 指定基址寄存器的值0
MOV DL,0x00 ; A驱动器
INT 0x13 ; 调用磁盘BIOS
JC error ; 如果进位标志是1的话,就跳转
; fin 中让CPU停止,进入等待模式,并不断循环
fin:
HLT ; 让CPU停止,等待指令
JMP fin ; 无限循环
error:
MOV SI,msg
; 不断累加SI中的地址,并从中读取内容。当内容不等于0时,调用中断显示字符,然后重复本步骤;
; 当内容为0时,跳转到fin
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
; haribote-ipl
; TAB=4
ORG 0x7c00 ; 指明程序的装载地址
; 以下的记述用于标准FAT12格式的软盘
JMP entry
DB 0x90
DB "HARIBOTE" ; 引导扇区的名称,随意写,8字节
DW 512 ; 每个扇区的大小,必须是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 ; 重写一次磁盘大小,4字节
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 ; 段寄存器初始化为0
; 僨傿僗僋傪撉傓
MOV AX,0x0820
MOV ES,AX ; 指定附加段地址寄存器的值0x0820
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 ; 指定基址寄存器的值0
MOV DL,0x00 ; A驱动器
INT 0x13 ; 调用磁盘BIOS
JNC fin ; 没出错的话跳转到fin,进位标志是0的话就跳转
ADD SI,1 ; 出错往SI加1
CMP SI,5 ; 比较SI和5
JAE error ; SI >= 5时,跳转到error;JAE大于或等于时跳转
MOV AH,0x00 ; 系统复位”。它的功能是复位软盘状态,再读一次。
MOV DL,0x00 ; A驱动器
INT 0x13 ; 重置驱动器
JMP retry
; fin 中让CPU停止,进入等待模式,并不断循环
fin:
HLT ; 让CPU停止,等待指令
JMP fin ; 无限循环
error:
MOV SI,msg
; 不断累加SI中的地址,并从中读取内容。当内容不等于0时,调用中断显示字符,然后重复本步骤;
; 当内容为0时,跳转到fin
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
; haribote-ipl
; TAB=4
ORG 0x7c00 ; 指明程序的装载地址
; 以下的记述用于标准FAT12格式的软盘
JMP entry
DB 0x90
DB "HARIBOTE" ; 引导扇区的名称,随意写,8字节
DW 512 ; 每个扇区的大小,必须是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 ; 重写一次磁盘大小,4字节
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 ; 段寄存器初始化为0
; 僨傿僗僋傪撉傓
MOV AX,0x0820
MOV ES,AX ; 指定附加段地址寄存器的值0x0820
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 ; 指定基址寄存器的值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 中让CPU停止,进入等待模式,并不断循环
fin:
HLT ; 让CPU停止,等待指令
JMP fin ; 无限循环
error:
MOV SI,msg
; 不断累加SI中的地址,并从中读取内容。当内容不等于0时,调用中断显示字符,然后重复本步骤;
; 当内容为0时,跳转到fin
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
MOV AL, [ES:BX]
:ES × 16 + BX = 512
,BX = 0
,ES = 512 / 16
;其实也可以写成BX + 512
。INT 0x13
的地方,只要将AL的值设置成17就行了。这样,程序一下子就能将扇区2~18
共17个扇区的数据完整的读进来。; haribote-ipl
; TAB=4
CYLS EQU 10 ; 相当于C语言的#define命令,用来声明常数,CYLS = 10。
ORG 0x7c00 ; 指明程序的装载地址
; 以下的记述用于标准FAT12格式的软盘
JMP entry
DB 0x90
DB "HARIBOTE" ; 引导扇区的名称,随意写,8字节
DW 512 ; 每个扇区的大小,必须是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 ; 重写一次磁盘大小,4字节
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 ; 段寄存器初始化为0
; 僨傿僗僋傪撉傓
MOV AX,0x0820
MOV ES,AX ; 指定附加段地址寄存器的值0x0820
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 ; 指定基址寄存器的值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 ; 将磁头的位置变为0
ADD CH,1 ; 跳到下一个柱面
CMP CH,CYLS ; 宏定义 CYLS = 10
JB readloop ; CH < CYLS 跳转到readloop
; fin 中让CPU停止,进入等待模式,并不断循环
fin:
HLT ; 让CPU停止,等待指令
JMP fin ; 无限循环
error:
MOV SI,msg
; 不断累加SI中的地址,并从中读取内容。当内容不等于0时,调用中断显示字符,然后重复本步骤;
; 当内容为0时,跳转到fin
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
haribote.nas
fin:
HLT
JMP fin
TOOLPATH = ../z_tools/
MAKE = $(TOOLPATH)make.exe -r
NASK = $(TOOLPATH)nask.exe
EDIMG = $(TOOLPATH)edimg.exe
IMGTOL = $(TOOLPATH)imgtol.com
COPY = copy
DEL = del
default :
$(MAKE) img
# 启动区文件
# ipl.nas —> ipl.bin
ipl.bin : ipl.nas Makefile
$(NASK) ipl.nas ipl.bin ipl.lst
# 操作系统本身的内容
# haribote.nas —> haribote.sys
haribote.sys : haribote.nas Makefile
$(NASK) haribote.nas haribote.sys haribote.lst
# 操作系统镜像文件
# ipl.bin & haribote.sys —> haribote.img
haribote.img : ipl.bin haribote.sys Makefile
$(EDIMG) imgin:../z_tools/fdimg0at.tek \
wbinimg src:ipl.bin len:512 from:0 to:0 \
copy from:haribote.sys to:@: \
imgout:haribote.img
# 僐儅儞僪
img :
$(MAKE) haribote.img
run :
$(MAKE) img
$(COPY) haribote.img ..\z_tools\qemu\fdimage0.bin
$(MAKE) -C ../z_tools/qemu
install :
$(MAKE) img
$(IMGTOL) w a: haribote.img
clean :
-$(DEL) ipl.bin
-$(DEL) ipl.lst
-$(DEL) haribote.sys
-$(DEL) haribote.lst
src_only :
$(MAKE) clean
-$(DEL) haribote.img
make run
0x8000
号地址,所以磁盘0x4200处的内容就应该位于内存0x8000+0x4200=0xc200
号地址haribote.nas
中加上ORG 0xc200
; haribote-os
; TAB=4
ORG 0xc200 ; 这个程序将要被装载到内存的什么地方
MOV AL,0x13 ; VAG显卡,320x200x8位色彩
MOV AH,0x00 ; 设定AH=0x00后,调用显卡的BIOS函数
INT 0x10
fin:
HLT
JMP fin
make run
haribote.nas
; haribote-os
; TAB=4
; 有关BOOT_INFO
CYLS EQU 0x0ff0 ; 设定启动区
LEDS EQU 0x0ff1
VMODE EQU 0x0ff2 ; 关于颜色数目的信息。颜色的位数
SCRNX EQU 0x0ff4 ; 分辨率X(screen x)
SCRNY EQU 0x0ff6 ; 分辨率Y(screen y)
VRAM EQU 0x0ff8 ; 图像缓冲区的开始地址
ORG 0xc200 ; 这个程序将要被装载到内存的什么地方
MOV AL,0x13 ; VGA显卡,320x200x8位色彩
INT 0x10
MOV BYTE [VMODE],8 ; 记录画面模式,把画面模式的信息保存在了内存里
MOV WORD [SCRNX],320
MOV WORD [SCRNY],200
MOV DWORD [VRAM],0x000a0000 ; VRAM指的是显卡内存,VRAM的各个地址都对应着画面上的象素,可以绘制出图案
; 不同画面模式的像素数/内存也不一样,所以需要预先把要使用的VRAM地址保存在BOOT_INFO里以备用
; 用BIOS取得键盘上各种LED指示灯的状态
MOV AH,0x02
INT 0x16 ; keyboard BIOS
MOV [LEDS],AL
fin:
HLT
JMP fin
haribote.nas
改为asmhead.nas
void HariMain(void) {
fin:
/* 这里想写上HLT,但C原因呢中不能用HLT */
// goto指令是新出现的,相当于汇编语言中的JMP,实际上也是被编译成JMP指令
goto fin;
}
TOOLPATH = ../z_tools/
INCPATH = ../z_tools/haribote/
MAKE = $(TOOLPATH)make.exe -r
NASK = $(TOOLPATH)nask.exe
CC1 = $(TOOLPATH)cc1.exe -I$(INCPATH) -Os -Wall -quiet
GAS2NASK = $(TOOLPATH)gas2nask.exe -a
OBJ2BIM = $(TOOLPATH)obj2bim.exe
BIM2HRB = $(TOOLPATH)bim2hrb.exe
RULEFILE = $(TOOLPATH)haribote/haribote.rul
EDIMG = $(TOOLPATH)edimg.exe
IMGTOL = $(TOOLPATH)imgtol.com
COPY = copy
DEL = del
default :
$(MAKE) img
# 僼傽僀儖惗惉婯懃
ipl10.bin : ipl10.nas Makefile
$(NASK) ipl10.nas ipl10.bin ipl10.lst
asmhead.bin : asmhead.nas Makefile
$(NASK) asmhead.nas asmhead.bin asmhead.lst
bootpack.gas : bootpack.c Makefile
$(CC1) -o bootpack.gas bootpack.c
bootpack.nas : bootpack.gas Makefile
$(GAS2NASK) bootpack.gas bootpack.nas
bootpack.obj : bootpack.nas Makefile
$(NASK) bootpack.nas bootpack.obj bootpack.lst
bootpack.bim : bootpack.obj Makefile
$(OBJ2BIM) @$(RULEFILE) out:bootpack.bim stack:3136k map:bootpack.map \
bootpack.obj
# 3MB+64KB=3136KB
bootpack.hrb : bootpack.bim Makefile
$(BIM2HRB) bootpack.bim bootpack.hrb 0
haribote.sys : asmhead.bin bootpack.hrb Makefile
copy /B asmhead.bin+bootpack.hrb haribote.sys
haribote.img : ipl10.bin haribote.sys Makefile
$(EDIMG) imgin:../z_tools/fdimg0at.tek \
wbinimg src:ipl10.bin len:512 from:0 to:0 \
copy from:haribote.sys to:@: \
imgout:haribote.img
# 僐儅儞僪
img :
$(MAKE) haribote.img
run :
$(MAKE) img
$(COPY) haribote.img ..\z_tools\qemu\fdimage0.bin
$(MAKE) -C ../z_tools/qemu
install :
$(MAKE) img
$(IMGTOL) w a: haribote.img
clean :
-$(DEL) *.bin
-$(DEL) *.lst
-$(DEL) *.gas
-$(DEL) *.obj
-$(DEL) bootpack.nas
-$(DEL) bootpack.map
-$(DEL) bootpack.bim
-$(DEL) bootpack.hrb
-$(DEL) haribote.sys
src_only :
$(MAKE) clean
-$(DEL) haribote.img
naskfunc.nas
bootpack.obj
链接,所以也需要编译成目标文件。因此将输出格式设定为WCOFF
模式。另外,还要设定成32位机器语言模式