文件系统FAT表查询,读取

学习自狄泰软件

1 CX DX寄存器是16位的 分别用 ch dh cl dl 代表高低八位数据

2 $ 表示当前指令行地址,$$表示当前汇编段起始地址

3 cmp si di
如果 si > di 走 ja
如果 si<=ji 走jna
如果 si < di 走 jb
如果 si >= di 走 jnb

4 mul 乘法,被乘数放在 AL 寄存器,乘数放到通用寄存器或内存,结果放在AX寄存器

5 and 按位与

6 shl 左移

7 shr 右移

8 拷贝操作注意 空间重叠

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

避免src数据被破坏
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
简单点说: FAT表每一个FAT表项 由1.5个字节组成:
如偶数FAT表偶数下标表项: FAT表 第i+1字节的 低四位,和 第i字节 组成。其中FAT表 第i+1字节的 低四位 作为组成表项的高四位

扫描二维码关注公众号,回复: 13277022 查看本文章

在这里插入图片描述
在这里插入图片描述
boot.asm

org 0x7c00

jmp short start
nop

define:
    BaseOfStack      equ 0x7c00
	;加载 FAT表 到该地址之前的空间 addr < 0x9000
	;将目标程序加载到 该内存
    BaseOfLoader     equ 0x9000
    RootEntryOffset  equ 19
    RootEntryLength  equ 14
	;
    EntryItemLength  equ 32
	;FAT表起始逻辑扇区号 1
    FatEntryOffset   equ 1
	;FAT表 长度 9个扇区
    FatEntryLength   equ 9

header:
    BS_OEMName     db "D.T.Soft"
	;每个扇区大小
    BPB_BytsPerSec dw 512
    BPB_SecPerClus db 1
    BPB_RsvdSecCnt dw 1
    BPB_NumFATs    db 2
    BPB_RootEntCnt dw 224
    BPB_TotSec16   dw 2880
    BPB_Media      db 0xF0
    BPB_FATSz16    dw 9
    BPB_SecPerTrk  dw 18
    BPB_NumHeads   dw 2
    BPB_HiddSec    dd 0
    BPB_TotSec32   dd 0
    BS_DrvNum      db 0
    BS_Reserved1   db 0
    BS_BootSig     db 0x29
    BS_VolID       dd 0
    BS_VolLab      db "D.T.OS-0.01"
    BS_FileSysType db "FAT12   "

start:
    mov ax, cs
	mov ss, ax
	mov ds, ax
	mov es, ax
	;定义栈顶
	mov sp, BaseOfStack
	
	;根目录区 偏移地址  逻辑扇区号
	mov ax, RootEntryOffset
	;根目录区长度 需要连续读取多少个扇区
	mov cx, RootEntryLength
	;将根目录区 数据 读取到 Buf地址
	mov bx, Buf
	
;读取软驱数据 中的 根目录区数据(起19扇区,共14个扇区) 到 Buf地址
	call ReadSector
	
	
	;起始地址 bx 根目录区数据已经拷贝到 buf
	;需要查找的目标 字符串 "LOADER     "
	mov si, Target
	;字符串长度
	mov cx, TarLen
	mov dx, 0
;在根目录区查找 字符串 == "LOADER     ", 查到目标字符串在 bx 寄存器保存的地址所在的 根目录项
	call FindEntry
	
	;cmp dx, 0
	;jz output
	
	;内存拷贝 
	mov si, bx
	;目标文件的目录项信息的入口地址
	mov di, EntryItem
	mov cx, EntryItemLength
;内存拷贝 ,将 bx保存的 根目录项数据  拷贝到 EntryItem,即拷贝完成后 EntryItem代表目标文件的目录项信息的入口地址
	call MemCpy
	
	;加载 FAT表 到指定内存地址
	;计算目标空间地址
	;FAT表 长度 9个扇区
	mov ax, FatEntryLength
	;每个扇区大小 
	mov cx, [BPB_BytsPerSec]
	; 计算FAT表所占用内存字节数,乘法 被乘数放在 AL 寄存器,乘数放到通用寄存器或内存(这里是cx),结果放在 AX 寄存器
	mul cx
	;需要拷贝到的目标地址 0x9000 前的一块空间
	mov bx, BaseOfLoader
	;减去 FAT表占用的内存字节数,结果存放在bx, 即FAT表在内存中的起始位置,得到目标空间地址
	sub bx, ax
	
	;FAT表起始逻辑扇区号 1   逻辑扇区号
	mov ax, FatEntryOffset
	;FAT表 长度 9个扇区  需要连续读取多少个扇区
	mov cx, FatEntryLength
;加载FAT表,将FAT表数据 加载到 bx 寄存器值指向的空间,即 0x9000 前的一块空间
	call ReadSector
	
	;获取目标文件 起始簇(该文件数据起始FAT表下标),  根目录区中 指定 文件目录项地址 + 0x1a == 目标文件开始的簇号
	mov cx, [EntryItem + 0x1A]
	;bx 寄存器  保存FAT表项在内存的起始位置
	
;查FAT表, 查询 cx寄存器中保存的值所对应的FAT表项是什么 对应的簇号
	call FatVec
	
	jmp last
	
output:	
    mov bp, MsgStr
    mov cx, MsgLen
	call Print
	
last:
	;使程序停止运行,处理器进入暂停状态,不执行任何操作,使 CPU 进入这么一个状态:既不取指令,也不读写数据
    hlt
	jmp last	

;读 FAT表
; cx --> index FAT表项下标 逻辑下标
; bx --> fat table address  FAT表项在内存的起始位置,基地址
;
; return:
;     dx --> fat[index] 返回FAT表项值
FatVec:
	;根据FAT表项下标 计算对应的内存地址
	; 判断下标奇偶 FAT逻辑下标*3/2 == 起始字节
    mov ax, cx
    mov cl, 2
	;被除数放在AX寄存器,除数放在通用寄存器或内存中。商位于 AL 寄存器,余数位于AH寄存器
    div cl
    ;保存商和余数
    push ax
    
	; 计算表项在内存的起始字节数
	;al * 3
    mov ah, 0
    mov cx, 3
	;乘法,被乘数放在 AL 寄存器,乘数放到通用寄存器或内存,结果放在AX寄存器
	; al * 3 
    mul cx
    mov cx, ax
    
    pop ax
    
	;余数为0 偶数 否则是奇数
    cmp ah, 0
    jz even
    jmp odd

even:    ; 偶数下标  FatVec[j] = ( (Fat[i+1] & 0x0F) << 8 ) | Fat[i];
    mov dx, cx
	;Fat[i+1]
    add dx, 1
	;Fat[i+1]地址 --> dx
    add dx, bx
	;借助bp寄存器,取该地址一个字节数据 到 dl 寄存器
    mov bp, dx
    mov dl, byte [bp]
	;按位与 取 Fat[i+1] 低四位
    and dl, 0x0F
	;左移8位
    shl dx, 8
	;Fat[i]地址 放到 bp寄存器
    add cx, bx
    mov bp, cx
	; 或运算  ( (Fat[i+1] & 0x0F) << 8 ) | Fat[i]  最终结果放在dl
    or  dl, byte [bp]
    jmp return
    
odd:     ; FatVec[j+1] = (Fat[i+2] << 4) | ( (Fat[i+1] >> 4) & 0x0F );
    mov dx, cx
	;Fat[i+2]
    add dx, 2
	;Fat[i+2]地址
    add dx, bx
	;借助bp寄存器
    mov bp, dx
	;取 bp 寄存器中的一个字节值到 dl寄存器
    mov dl, byte [bp]
    mov dh, 0
	;dx 值左移4位  (Fat[i+2] << 4)
    shl dx, 4
	;Fat[i+1]
    add cx, 1
	;Fat[i+1]地址
    add cx, bx
	;借助bp寄存器
    mov bp, cx
	;取 bp 寄存器中的一个字节值到 cl寄存器
    mov cl, byte [bp]
	;右移4位 (Fat[i+1] >> 4)
    shr cl, 4
	;(Fat[i+1] >> 4) & 0x0F
    and cl, 0x0F
    mov ch, 0
	; (Fat[i+2] << 4) | 
    or  dx, cx

return: 
    ret
	
;内存拷贝函数
; ds:si --> source  
; es:di --> destination
; cx    --> length
MemCpy:
    push si
    push di
    push cx
    push ax
    ;比较 src des 地址 以判断是否需要调整拷贝方式
    cmp si, di
    ;如果 si > di 则从前向后拷贝
    ja btoe
    
	;从后向前拷贝的准备工作
	;指向原内存和 目标内存的尾部
    add si, cx
    add di, cx
	;指向尾部最后一个有效字节
    dec si
    dec di
    ;si <= di 跳转到 etob标签 开始从后向前拷贝
    jmp etob
   
;从头向尾进行拷贝   
btoe:
	;直到拷贝了 cx 长度
    cmp cx, 0
    jz done
    mov al, [si]
	;将 al 寄存器中的值 放到 di所指向的内存单元中
    mov byte [di], al
	;拷贝下一个字节 ++
    inc si
    inc di
    dec cx
    jmp btoe
   
;从尾向头进行拷贝   
etob: 
    cmp cx, 0
    jz done
    mov al, [si]
    mov byte [di], al
    dec si
    dec di
    dec cx
    jmp etob

done:   
    pop ax
    pop cx
    pop di
    pop si
    ret

; es:bx --> root entry offset address
; ds:si --> target string
; cx    --> target length
;
; return:
;     (dx !=0 ) ? exist : noexist
;        exist --> bx is the target entry
FindEntry:
    push di
    push bp
    push cx
    
    mov dx, [BPB_RootEntCnt]
    mov bp, sp
    
find:
    cmp dx, 0
    jz noexist
    mov di, bx
    mov cx, [bp]
    call MemCmp
    cmp cx, 0
    jz exist
    add bx, 32
    dec dx
    jmp find

exist:
noexist: 
    pop cx
    pop bp
    pop di
       
    ret

; ds:si --> source
; es:di --> destination
; cx    --> length
;
; return:
;        (cx == 0) ? equal : noequal
MemCmp:
    push si
    push di
    push ax
    
compare:
    cmp cx, 0
    jz equal
    mov al, [si]
    cmp al, byte [di]
    jz goon
    jmp noequal
goon:
    inc si
    inc di
    dec cx
    jmp compare
    
equal: 
noequal:   
    pop ax
    pop di
    pop si
    
    ret

; es:bp --> string address
; cx    --> string length
Print:
	;mov dx, 0 将目标字符串打印到 坐标 0,0 的地方 左上角
    mov dx, 0
    mov ax, 0x1301
	mov bx, 0x0007
	int 0x10
    ret

; no parameter
ResetFloppy:
    push ax
    push dx
    
    mov ah, 0x00
    mov dl, [BS_DrvNum]
    int 0x13
    
    pop dx
    pop ax
    
    ret

; ax    --> logic sector number
; cx    --> number of sector
; es:bx --> target address
ReadSector:
    push bx
    push cx
    push dx
    push ax
    
    call ResetFloppy
    
    push bx
    push cx
    
    mov bl, [BPB_SecPerTrk]
    div bl
    mov cl, ah
    add cl, 1
    mov ch, al
    shr ch, 1
    mov dh, al
    and dh, 1
    mov dl, [BS_DrvNum]
    
    pop ax
    pop bx
    
    mov ah, 0x02

read:    
    int 0x13
    jc read
    
    pop ax
    pop dx
    pop cx
    pop bx
    
    ret

MsgStr db  "No LOADER ..."	
MsgLen equ ($-MsgStr)
Target db  "LOADER     "
TarLen equ ($-Target)
EntryItem times EntryItemLength db 0x00
Buf:
	times 510-($-$$) db 0x00
	db 0x55, 0xaa

猜你喜欢

转载自blog.csdn.net/LinuxArmbiggod/article/details/120606496