一、内存区域
1、启动区
地址范围:0x7C00~0x7DFF
特点:地址7DFE储存的值为0x55、7DFF储存的值为0xAA
2、Boot data/stack区(引导数据/堆栈)
地址范围:0x7E00~0x7FFF
3、启动区预留
因为把C0-H0-S2装载到了0x8200,等价于C0-H0-S1装载到了0x8000。
地址范围:0x8000~0x81FF
4、系统区
地址范围:0x8200~0x9FBFF
二、代码解析
1、Makefile
#变量定义
TOOLPATH = ../z_tools/
MAKE = $(TOOLPATH)make.exe -r
NASK = $(TOOLPATH)nask.exe
EDIMG = $(TOOLPATH)edimg.exe
IMGTOL = $(TOOLPATH)imgtol.com
COPY = copy
DEL = del
# 初始化动作,输入make时执行img编译
default :
$(MAKE) img
# 文件生成規則
# 检查文件是否齐全,然后实施制作
ipl10.bin : ipl10.nas Makefile
$(NASK) ipl10.nas ipl10.bin ipl10.lst
haribote.sys : haribote.nas Makefile
$(NASK) haribote.nas haribote.sys haribote.lst
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) ipl10.bin
-$(DEL) ipl10.lst
-$(DEL) haribote.sys
-$(DEL) haribote.lst
src_only :
$(MAKE) clean
-$(DEL) haribote.img
借助.bat启动make.exe,从而实施mafile文件。
..\z_tools\make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9
2、汇编代码
ipl代码的作用:
①、初始化寄存器
②、向软盘写数据(写到对应地址位置)
③、跳到系统区汇编代码地址
; haribote-ipl
; TAB=4
CYLS EQU 10 ; 10个柱面都要读入,这里是循环读入次数
ORG 0x7c00 ; ipl的起始地址是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 ; 段寄存器指定的地址=ES*16+BX
MOV DL,0x00 ; A驱动器
INT 0x13 ; 调用磁盘BIOS执行读取
JNC next ; 没出错的话,读下一个扇区(jump if not carry)
ADD SI,1 ; 出错了SI加1
CMP SI,5 ; SI和5比较
JAE error ; SI >= 5进入err
MOV AH,0x00
MOV DL,0x00 ; A驱动器
INT 0x13 ; 重置驱动器
JMP retry
next:
MOV AX,ES ; ES加0x20,地址后移0x20*16=0x200
ADD AX,0x0020 ; ES加0x20,地址后移0x20*16=0x200
MOV ES,AX ; ES加0x20,地址后移0x20*16=0x200
ADD CL,1 ; 扇区+1
CMP CL,18 ; 18个扇区,全部读取
JBE readloop ; CL <= 18 跳readloop读取(jump if below or equal)
MOV CL,1
ADD DH,1
CMP DH,2
JB readloop ; DH < 2 跳readloop读取(jump if below)
MOV DH,0
ADD CH,1
CMP CH,CYLS
JB readloop ; CH < 10 跳readloop读取(jump if below)
; 读完了10*2*18*512=184320字节=180kb
MOV [0x0ff0],CH ; 记下IPL读到了什么程度
JMP 0xc200 ; 跳到系统区首地址
error:
MOV SI,msg ; SI是源变址寄存器,这时储存的是msg的首地址
putloop: ; 初始化完成后,进入循环
MOV AL,[SI] ; 把地址为SI的值取出(msg的一个字符),赋值给AX寄存器的低8位AL
ADD SI,1 ; SI加1就是地址后移一个字节,指向msg的下一个字符的地址
CMP AL,0 ; 判断msg是否结束
JE fin ; 如果发现msg已经结束,跳转到结束,让CPU低功耗运行
MOV AH,0x0e ; msg有字符,设置单字显示功能
MOV BX,15 ; 设置字体颜色
INT 0x10 ; 在屏幕窗口显示
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
二、遇到的问题和解决办法
1、copy失败的问题
如果make run提示copy失败,可以把copy改为cp,亲测有效