📄 复件 fat32.asm
字号:
dd 0x44
dd 0x45
dd 0x46
BeginSecend:
mov si, OtherInfo+1
mov bx, Reg_IP_Base+0x400 ;BX=7c00+400=8000(Hex)
;跳过前2扇区内存区域
movzx di, [OtherInfo] ;取扇区数
push di
LoadOther:
lodsd
inc cx ;读一扇区
call Read_Disk
jc OtherError
dec di
jnz LoadOther ;未读完,继续
pop cx ;CX=[OtherInfo]
mov bx, SectorFlag+1
;==================================================================================
;标志检测
;该标志为 Fans Bootsector 的固有标志,总共4字节,其值必须为46,61,55,AA
;仅检测中间2字节,即:61,55
;==================================================================================
ScanFlag:
add bx, 0x200
mov ax, 0x5561
cmp ax, [bx]
jnz OtherError
loop ScanFlag
jmp near BeginOther
OtherError:
mov si, ERR_DSK
mov bp, disk_dot
push word BootFail
;==================================================================================
; PrintCh 功能 显示字符串
; 入口: cs:si=字符串地址
; cs:bp=点阵信息(char>128)
; 出口: ds=cs
; es=cs
;可能改变的寄存器: eax,ebx,ecx,edx,esi,ebp,ds,es
;未改变的寄存器有: edi,esp,ss
;特别说明:该过程使用 BIOS INT 0x10 第11号子功能。更详细的说明参看
; 罗云彬所发表的《文本模式下图形字符的显示》一文
; 文章出处: http://asm.yeah.net
;==================================================================================
proc PrintCh:
push cs
pop ds
push cs
pop es
cld
.Nextp:
lodsb
cmp al, 0x80
jb .Display ; AL<0x80为 ASCII字符
push ax
movzx dx, al
mov ax, 0x1100 ; Bios int0x10 第11号功能
; 设置字符点阵
mov bx, 0x1000
mov cx, 1
int 0x10
add bp, 0x10
pop ax
.Display:
mov ah, 0x0e
int 0x10
cmp al, '!'
jnz .Nextp
ret
endp
DISKERRMSGDOT
;==================================================================================
times Flag_Offset+0x200-($-$$) db 0
SectorFlag dw 'Fa'
dw Flag_BootSect
;==================================================================================
%define StartFat BP-4
%define StartRoot BP-8
%define StartData BP-12
%define RootSectors BP-16
;==================================================================================
;计算磁盘参数
BeginOther:
movzx esi, word [bp+ResaveSect-Reg_IP_Base]
; 保留扇区数
add esi, [bp+HidSectors-Reg_IP_Base]
;隐含扇区数
push esi ; [BP-04] = FAT 表区域的起
; 始扇区号
movzx eax, byte [bp+FatOfDisk-Reg_IP_Base]
;FAT 表个数
mov bx, [bp+SectPreFat-Reg_IP_Base]
; 每个 FAT占用扇区数
mul bx
add esi, eax
push esi ; [BP-08] = 根目录区域的起
; 始扇区号
movzx eax, word [bp+FileOfRoot-Reg_IP_Base]
; 根目录文件数
mov bx, word [bp+SectSize-Reg_IP_Base]
; 每扇区字节数
shr bx, 5 ; BX = BX/ 32
; 每目录登记项长度 32 字节
cwd
div bx ; EAX=根目录占用扇区数
add esi, eax
push esi ; [BP-12] = 磁盘数据区起始
; 地址
push eax ; [BP-16] = EAX = 根目录占
; 用扇区数
;==================================================================================
;以下部分代码为读根目录表并且查找文件
mov eax, [StartRoot] ; 根目录起始扇区号
mov cx, [RootSectors] ; 根目录占用扇区数
push word Seg_CS_Boot
pop es ; ES:BX = Seg_CS_Boot:0000
xor bx, bx
call Read_Disk
jc Error_Read
mov si, FileSystemDrv
call ScanFile ; 查找文件
jc Error_Drv
push eax ; [BP-20] = FS.DRV 的首簇号
mov si, BootFilename
call ScanFile
jc Error_Kernel
;==================================================================================
;取文件FAT扇区信息到堆栈
push es ; ES=Seg_CS_Boot
pop ds ; 将DS置为缓冲区段
push eax
mov si, -24 ; [BP+SI]=[BP-24]
; =KERNEL.SYS的首簇号
call SaveFat ; 存FAT信息到堆栈
jc Error_Kernel ; 错误处理
mov si, -20 ; [BP-20]=FS.DRV的首簇号
call SaveFat
jc Error_Drv
mov si, [bp-24] ; 准备装载 KERNEL.SYS
xor bx, bx
push ss ; SS=0000
pop ds
mov byte [bp+3],0xfe ; [BH+3]=-2, 文件计数器
; 表示读2个文件
;==================================================================================
;装载文件到内存
Load_Kernel:
std
lodsd
mov cl, [bp+SectOfCurs-Reg_IP_Base]
; 每簇扇区数
or ax, ax
jz Load_NF ; 装载下一个文件
call Read_Disk
jnc Load_Kernel ; 无错误,继续读
Error_Read:
mov bp, disk_dot ; 磁盘错误
mov si, ERR_DSK
jmp short ErrCall
Load_NF:
xor bx, bx
push word Seg_FS_Boot ; 读第2个文件到
pop es ; Seg_FS_Boot:0000
inc byte [bp+3] ; 文件计数器+1
jnz Load_Kernel
db 0xea
dw 0, Seg_CS_Boot+0x20
Error_Drv:
mov si, ERR_DRV ; FAT16.DRV出错
jmp short ErrLeaDot
Error_Kernel:
mov si, ERR_KNL ; KERNEL.SYS出错
ErrLeaDot:
mov bp, Other_dot ; 错误信息的字模指针
ErrCall:
call PrintCh
jmp BootFail
;==================================================================================
; SaveFat 功能 保存文件的FAT信息
; 入口: [BP+SI]=文件首簇号
; 出口: CF=0 成功 [BP+SI]=文件簇链表指针
; CF=1 失败
; 说明: 使用 SS 寻址
;保存文件的FAT信息
;该过程使用堆栈作为缓冲区,将文件的每一簇起始位置的绝对扇区号保存到缓冲区
;堆栈:
; | Stack |
; |----------------|<<<<<<< stack low address
; DI---> | 父过程地址 | ret; [ss:sp]-->IP;SP+=2
; |----------------|
; | 0x00000000 |
; |----------------|
; | FAT16.DRV |
; |----------------|
; | 0x00000000 |Buffer NULL
; |----------------|
; | ... | \
; | ... | \
; | Buffer | |-> KERNEL.SYS
;IF pop di & mov ebx,sp & dec bx| Buffer | /
;dec bx Then BX=Offset Buffer-->| 父过程地址 | / ----> DI //pop di;
; 该地址在执行后变成文\ |----------------|
; | ----> | KERNEL.SYS |\ ---->low word
; 件簇连表缓冲区首指针/ |----- && -----| |---> EAX //mov eax,[bp+si]
; | 首簇号 |/ ---->high word
; 该地址在执行后变成文\ |----------------|
; | ----> | FAT16.DRV |\ ---->low word
; 件簇连表缓冲区首指针/ |----- && -----| |---> EAX //mov eax,[bp+si]
; | 首簇号 |/ ---->high word
; |----------------|<<<<<<< stack high address
; | OtherBuffer |
;==================================================================================
proc SaveFat:
mov eax, [bp+si] ; [bp+si]=文件首簇号指针
movzx ebx, sp
pop di
dec bx
dec bx ; 计算指针首地址
mov [bp+si], bx ; 存首地址
inc ax
.next:
dec ax
push eax
cdq
dec ax
dec ax
mov dl, [bp+SectOfCurs-Reg_IP_Base]
; edx=每簇扇区数
mul edx ; eax=该簇的DOS扇区号
add eax, [StartData] ; eax=该簇的绝对磁盘扇区号
mov edx, eax
pop eax
push edx ; 保存绝对扇区号
cdq
shl eax, 1 ; eax=簇的偏移地址=簇号*2
mov si, [bp+SectSize-Reg_IP_Base]
; ecx=每扇区字节数
div esi ; eax=DOS扇区号
add eax, [bp-4] ; eax=下一簇号的绝对扇区号
mov esi, edx ; esi=下一簇号在扇区中的偏移地址
mov bx, cx ; cx=0
inc cx
call Read_Disk
jc .Error
lodsw
inc ax
jnz .next
push eax ; 置结束标志,eax=0
clc
.Error:
push di
ret
endp
;==================================================================================
; ScanFile 功能 扫描根目录区的文件并将 es:si所指文件
; 的首簇号放在 eax中
; 入口: ds:si=文件名
; es:0=缓冲区地址
; 出口: CF=0 成功, eax=文件首簇号
; CF=1 失败
;==================================================================================
proc ScanFile:
xor di, di
cld
.nextScan:
push si
push di
mov cx, fNameSize ;CX=11
repe cmpsb ;IF ZR THEN REP
pop di
pop si
clc
jz .ScanDown ;所有字符比较均相等
add di, 32 ;每文件登记项长度为32
sub byte [es:di],0
jnz .nextScan
stc
.ScanDown
movzx eax, word [es:di+0x1a]
ret
endp
;==================================================================================
times Flag_Offset+0x400-($-$$) db 0
dw 'Fa'
dw Flag_BootSect
;==================================================================================
;ERRORMESSAGEDOT在".\language\*.inc"已有定义
ERRORMESSAGEDOT
times Flag_Offset+0x600-($-$$) db 0
dw 'Fa'
dw Flag_BootSect
;==================================================================================
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -