03_主引导程序加载FAT12文件内容

写在前面

本文主要是介绍如何编码实现在主引导扇区读取FAT12文件系统中的指定文件(hello)的内容,具体步骤如下:

  1. 标准流程图
  2. 知识点:磁盘数据寻址方式、用到的基础汇编指令
  3. 代码结构图
  4. 代码:带详细注释的汇编、Makefile编译文件、运行截图
  5. 思考:描述写此代码时的步骤与思考

知识点

一、磁盘数据寻址方式

存储设备支持CHS和LBA两种寻址方式,CHS多为老设备使用,需要磁头号、柱面号、扇区号确定位置。LBA是新设备常用的线性寻址方式。

  1. CHS --> LBA
    LBA = [(柱面编号 << 1) + (磁头编号 & 0x1)] * 18 + (扇区编号 - 1)

  2. LBA --> CHS
    2.1 两个盘面,80个柱面/盘面,18个扇区/柱面,512字节/扇区
    2.2 存储大小:2 x 80 x 18 x 512 = 1440 KB
    2.3 逻辑扇区号转化为磁盘物理位置:磁头号、柱面号、扇区号
    image
    柱面扇区号:在上一篇文档中有介绍,是主引导扇区结构中的BPB_SecPerTrk参数FAT12文件系统
    逻辑扇区号:如下图所示,找到内存地址0x4800就是想要输出的数据首地址,将其转化成扇区号(0x4800/0x200)
    image

二、基础汇编指令

功能 参数 中断号
软驱复位 AH=0x00 DL=驱动器号 int 0x13
从磁盘将数据 写入ES:BX指向的内存中 AH=0x02 AL=长度(扇区) CH=柱面号 CL=起始扇区号 DH=磁头号 DL=驱动器号 ES:BX=目标地址 int 0x13
打印字符串 AX BX=打印样式 es:bp=字符串地址 cx=字符串长度 int 0x10
加法 结果赋值给被加数寄存器 add 被加数,加数
减法 结果赋值给被减数寄存器 sub 被减数,减数
乘法 eax=被乘数 eax=积 edx=结果溢出数据 mul 乘数
除法 ax=被除数 al=商 ah=余数 div 除数
32位下除法 edx:eax=被除数 eax=商 edx=余数 div 除数
与运算 结果赋值给操作数1 and 操作数1,操作数2
逻辑右移 结果赋值给操作数1 shr 操作数1,操作数2
逻辑左移 结果赋值给操作数1 shl 操作数1,操作数2
常量定义 不占内存宏定义,类似#define Const XXX Const equ XXX
自增 inc 寄存器
自减 des 寄存器
跳转 jmp 目的地址
判断跳转 jz xxx 满足cmp条件跳转
大于 ja xxx cmp si, di si > di即跳转
小于等于 jna xxx cmp si, di si <= di即跳转
小于 jb xxx cmp si, di si < di即跳转
大于等于 jnb xxx cmp si, di si >= di即跳转

三、反汇编调试

ndisasm -o 0x7c00 boot.bin > boot.txt

代码

org 0x7c00

jmp short start
nop

define:
    BaseOfStack equ 0x7c00
    BaseOfLoader equ 0x9000
    RootEntryOffset equ 19
    RootEntryLength equ 14
    EntryItemLength equ 32
    FatEntryOffset equ 1
    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
    mov bx, Buf
    call ReadSector

    mov si, Target
    mov cx, TarLen
    mov dx, 0

    call FindEntry

    cmp dx, 0
    jz output

    mov si, bx
    mov di, EntryItem
    mov cx, EntryItemLength

    call MemCpy

    mov ax, FatEntryLength
    mov cx, [BPB_BytsPerSec]
    mul cx
    mov bx, BaseOfLoader
    sub bx, ax

    mov ax, FatEntryOffset
    mov cx, FatEntryLength

    call ReadSector

    mov cx, [EntryItem + 0x1A]
    call FatVec

    jmp last

output:
    mov bp, Target
    mov cx, TarLen
    call Print

last:
    hlt
    jmp last

; cx --> index
; bx --> fat table address
;
; return:
;     dx --> fat[index]
FatVec:
    mov ax, cx
    mov cl, 2
    div cl
    
    push ax
    
    mov ah, 0
    mov cx, 3
    mul cx
    mov cx, ax
    
    pop ax
    
    cmp ah, 0
    jz even
    jmp odd

even:    ; FatVec[j] = ( (Fat[i+1] & 0x0F) << 8 ) | Fat[i];
    mov dx, cx
    add dx, 1
    add dx, bx
    mov bp, dx
    mov dl, byte [bp]
    and dl, 0x0F
    shl dx, 8
    add cx, bx
    mov bp, cx
    or  dl, byte [bp]
    jmp return
    
odd:     ; FatVec[j+1] = (Fat[i+2] << 4) | ( (Fat[i+1] >> 4) & 0x0F );
    mov dx, cx
    add dx, 2
    add dx, bx
    mov bp, dx
    mov dl, byte [bp]
    mov dh, 0
    shl dx, 4
    add cx, 1
    add cx, bx
    mov bp, cx
    mov cl, byte [bp]
    shr cl, 4
    and cl, 0x0F
    mov ch, 0
    or  dx, cx

return: 
    ret

; es:bp --> string address
; cx    --> string len
Print:
    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 ax
    push cx
    push dx

    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 dx
    pop cx
    pop ax
    ret

; ds:si --> source
; es:di --> destination
; cx    --> length
MemCpy:
    push si
    push di
    push cx
    push ax

    cmp si, di
    ja btoe
    add si, cx
    add di, cx
    dec si
    dec di
    jmp etob
btoe:
    cmp cx, 0
    jz done
    mov al, [si]
    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

; 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: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

MsgStr db  "Hello, not exist"
MsgLen equ ($-MsgStr)
Target db  "HELLO      "
TarLen equ  ($-Target)
EntryItem times EntryItemLength db 0x80
Buf:
    times 510-($-$$) db 0x00
    db 0x55, 0xaa
posted @   Qing-Huan  阅读(43)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
点击右上角即可分享
微信分享提示