06 突破512字节的限制 上

https://www.cnblogs.com/wanmeishenghuo/tag/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/

https://blog.51cto.com/13475106/category6.html

及狄泰软件相关课程

 

前几节我们介绍了FAT12文件系统,制作了虚拟软盘文件a.img,并在Qt Creater中进行了文件内容的读取实验。那些读取都是使用外部的程序实现的,实际应用中,我们需要用主引导程序来实现文件的读写,主引导程序存在于主引导扇区MBR中,也就是说程序和文件是存在一张盘上的,而且这些主引导程序需要使用汇编语言实现。接下来,我们就来实现具有读取功能的主引导程序。

  为了验证文件读取的正确性,我们需要在主引导程序中先实现一个字符串打印函数。BIOS已经将中断向量写到了内存的指定位置处,这其中就有能实现字符串打印的函数,我们需要做的就是配置一些参数,需要配置的参数和配置步骤如下:

  1、指定打印参数(AX=0x1301 , BX = 0x0007)

  2、指定字符串的内存地址(ES:BP  = 字符串地址)

  3、指定字符串的长度(CX = 字符串长度)

  4、中断调用(int 0x10)

示例如下:

06 突破512字节的限制 上

  需要用到的汇编语言的知识点如下:

                  06 突破512字节的限制 上              06 突破512字节的限制 上

  下面直接给出打印字符串的汇编程序:

org 0x7c00

jmp short start
nop

define:
    BaseOfStack equ 0x7c00

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, MsgStr
       mov bp, ax

       mov ax, ds
       mov es, ax

       mov cx, 6
    call Print

last:
    hlt
    jmp last

; es:bp --> string address
; cx    --> string length
Print:
    mov ax, 0x1301
    mov bx, 0x0007
    int 0x10
    ret

MsgStr db  "Hello, DTOS!"
MsgLen equ ($-MsgStr)
Buf:
    times 510-($-$$) db 0x00
    db 0x55, 0xaa

我们的虚拟软盘文件a.img已经格式化好了,现在要修改的只是第一个扇区即主引导扇区,所以我们要按照FAT12的格式来填充第一个扇区,因此,上面的程序中,第10到28行是FAT12的引导扇区的信息,它前面还有三个字节,其中前两个字节是跳转指令jmp short start,第三个字节为空指令nop。从start开始是我们的可执行程序,BaseOfStack是定义的栈底地址。

  汇编程序我们需要编译成二进制可执行程序,然后写入a.img虚拟软盘的第一个扇区中,每次都执行这个过程很麻烦,我们将这个过程写成makefile,如下所示:

.PHONY : all clean rebuild

SRC := boot.asm
OUT := boot.bin
IMG := a.img

RM := rm -fr

all : $(OUT) $(IMG)
    dd if=$(OUT) of=$(IMG) bs=512 count=1 conv=notrunc
    @echo "Success!"

$(IMG) :
    bximage $@ -q -fd -size=1.44

$(OUT) : $(SRC)
    nasm $^ -o $@

clean :
    $(RM) $(IMG) $(OUT)

rebuild :
    @$(MAKE) clean
    @$(MAKE) all

bochs的启动文件修改成如下内容:

###############################################################
# Configuration file for Bochs
###############################################################

# how much memory the emulated machine will have
megs: 32

# filename of ROM images
romimage: file=/usr/share/bochs/BIOS-bochs-latest
vgaromimage: file=/usr/share/vgabios/vgabios.bin

# what disk images will be used
floppya: 1_44=a.img, status=inserted
# choose the boot disk.
boot: a

# where do we send log messages?
# log: bochsout.txt

# disable the mouse
mouse: enabled=0

# enable key mapping, using US layout as default.
keyboard_mapping: enabled=1, map=/usr/share/bochs/keymaps/x11-pc-us.map

启动bochs,即可得到运行结果,如下所示:

06 突破512字节的限制 上

 

  可见,hello已经成功打印出来了。

   接下来,我们开始读取文件,假如我们知道了数据所在的扇区,那么怎么将它读出来呢?先来看一下软盘的构造,如下所示:

06 突破512字节的限制 上

  3.5寸软盘的特性如下:

06 突破512字节的限制 上

  根据逻辑扇区号计算磁头号、柱面号、物理扇区号的方法如下:

06 突破512字节的限制 上

  软盘复位和软驱数据读取的参数如下:

06 突破512字节的限制 上

 

  整体的读取流程如下:

06 突破512字节的限制 上

  需要用到的汇编知识点如下:

06 突破512字节的限制 上

  

 下面直接给出汇编程序:

org 0x7c00

jmp short start
nop

define:
    BaseOfStack equ 0x7c00

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, 34
    mov cx, 1
    mov bx, Buf

    call ReadSector

    mov bp, Buf
    mov cx, 24

    call Print

last:
    hlt
    jmp last

; es:bp --> string address
; cx    --> string length
Print:
    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  "Hello, DTOS!"
MsgLen equ ($-MsgStr)
Buf:
    times 510-($-$$) db 0x00
    db 0x55, 0xaa

我们将虚拟软盘文件a.img用VS2013打开,查看其中的内容,截取片段如下:

06 突破512字节的限制 上

  可以看到,a.txt文件的起始地址为0x4400,也就是第34个扇区开始,而内容的大小为24字节,这两个参数分别体现在汇编程序中的第37和44行。下面,启动bochs,运行结果如下:

06 突破512字节的限制 上

打印出了this is a floppy file.,我们成功读取了指定扇区的数据。

 

      若有问题,可以使用bochs环境进行汇编代码调试,具体通过反汇编,结合运行地址和断点调试来进行,可以观察指令执行情况

及相关寄存器的值,可参考相关教程。

 

小结
1.当汇编代码中定义了函数,那么需要定义栈空间
2.读取数据前,逻辑扇区号需要转化为磁盘的物理位置
3.物理软盘上的数据位置由磁头号,柱面号,扇区唯一确定
4.软盘数据以扇区512为单位进行读取

 

 

  

  

  

  

上一篇:Ubuntu挂载新的硬盘


下一篇:过渡到高级格式化 4K 扇区硬盘