软盘结构:
简写格式
C0-H0-S1用来存放引导区,如果最后两个字节是0x55,0xaa(DW 0xAA55),BIOS就把这512字节读出来执行。
名称开始字节长度内容DIR_Name00xB文件名8字节,扩展名3字节DIR_Attr0xB1文件属性保留位0xC10保留DIR_WrtTime0x162最后一次写入的时间DIR_WrtDate0x182最后一次写入的日期DIR_FstClus0x1A2此文件在数据区和FAT表中的开始簇号DIR_FileSize0x1C4文件大小
;%define _BOOT_DEBUG_ ; 做Boot Sector时把这行注释掉
; 启用这行就用nasm Boot.asm -o Boot.com生成.com文件用于调试
%ifdef _BOOT_DEBUG_
org 0100h
%else
org 07c00h
%endif
CYLS EQU 10
; 把软盘按Fat12格式填充
JMP init ; 跳转指令
DB 0x90 ; 空 DB,DD用来写单字节
DB "NotOneOS" ; 厂商名,8字节,DB用来写双字节
DW 512 ; 每个扇区大小512字节,DW用来写4字节
DB 1 ; 每个簇的扇区数
DW 1 ; Boot占的扇区
DB 2 ; 有2个FAT表
DW 224 ; 根目录大小224
DW 2880 ; 磁盘扇区总数 2880
DB 0xf0 ; 介质描述符,磁盘种类必须为0xf0
DW 9 ; 每个FAT扇区数
DW 18 ; 每个磁道18个扇区
DW 2 ; 2个磁头
DD 0 ; 隐藏扇区数
DD 2880 ; 同上,磁盘大小
DB 0, 0, 0x29 ; 0x29 扩展引用标记
DD 0xffffffff ; 无意义,固定这么写
DB "NotOneOS " ; 磁盘名(卷标),11字节
DB "FAT12 " ; 磁盘格式名,8字节
RESB 18 ; 空18个字节,填充0x00
init:
MOV AX,0
MOV SS,AX
MOV SP,0x7c00 ; 堆栈空间,从0x7c00向前
MOV DS,AX
MOV AX,0x0820 ; 把磁盘数据加载到内存0x0820处。 0x8000~0x81ff的512字节给启动区用的,所以从0x0820开始
MOV ES,AX ; 初始化磁盘接口
MOV CH,0 ; 柱面 0
MOV DH,0 ; 磁头 0
MOV CL,2 ; 扇区 2
readloop:
MOV SI,0 ; 记录失败次数
retry:
MOV AH,0x02 ; 0x02 读磁盘
MOV AL,1 ; 读1个扇区
MOV BX,0
MOV DL,0x00 ; A驱动器
INT 0x13 ; BIOS 读磁盘功能
JNC next ; 成功跳转
ADD SI,1 ; 失败加一次
CMP SI,5 ; 到5次就跳到error
JAE error
MOV AH,0x00 ; 复位磁盘功能
MOV DL,0x00
INT 0x13 ; 重置磁盘驱动器
JMP retry ; 重试
next:
MOV AX,ES ; 内存地址向后移动0x0020
ADD AX,0x0020
MOV ES,AX ; 通过AX给ES加0x0020
ADD CL,1 ; 扇区+1
CMP CL,18 ; 有没有到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
JMP success
print:
MOV AL, [SI]
ADD SI, 1
CMP AL, 0
JE end
MOV AH, 0x0e
MOV BX, 15
INT 0x10
JMP print
end:
HLT
JMP end ; 无限循环
error: ; 打印错误信息
MOV SI, error_msg
JMP print
success:
MOV SI, success_msg
JMP print
BootMessage:
DB "Hello, MY OS!" ; 想要开机后在屏幕上显示的字符串
DB 0
success_msg:
DB "Success" ; 成功
DB 0
error_msg:
DB "Error" ; 失败
DB 0
times 510-($-$$) db 0 ; 填充剩下的空间,使生成的二进制代码恰好为512字节 $$表示一个section的开始处汇编后地址
DW 0xaa55 ; 结束标志
; 继续按Fat12填充磁盘剩余空间
DB 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
RESB 4600
DB 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
RESB 1469432
使用BIOS中断 int 13h,参数:
知道扇区号的时候,要计算int 13h的参数:
设扇区号/每磁道扇区数(18) = 商 Q,余数R ,则:
下面使用VirtualBox读入磁盘镜像,并写入一个文件。(新建虚拟机并加虚拟磁盘的方法前面章节有提到。)
使用VsCode打开磁盘镜像,可以看到存储区域已经有了变化:
这里使用的是笨方法保存文件,也可以使用edimg.exe程序来做。
后面章节来看如何让程序加载NotOneOS.sys里的代码。
本章代码与编译运行方法已放到gitee:
gitee.com/xundh/learn-os