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)
示例如下:
需要用到的汇编语言的知识点如下:
下面直接给出打印字符串的汇编程序:
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,即可得到运行结果,如下所示:
可见,hello已经成功打印出来了。
接下来,我们开始读取文件,假如我们知道了数据所在的扇区,那么怎么将它读出来呢?先来看一下软盘的构造,如下所示:
3.5寸软盘的特性如下:
根据逻辑扇区号计算磁头号、柱面号、物理扇区号的方法如下:
软盘复位和软驱数据读取的参数如下:
整体的读取流程如下:
需要用到的汇编知识点如下:
下面直接给出汇编程序:
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打开,查看其中的内容,截取片段如下:
可以看到,a.txt文件的起始地址为0x4400,也就是第34个扇区开始,而内容的大小为24字节,这两个参数分别体现在汇编程序中的第37和44行。下面,启动bochs,运行结果如下:
打印出了this is a floppy file.,我们成功读取了指定扇区的数据。
若有问题,可以使用bochs环境进行汇编代码调试,具体通过反汇编,结合运行地址和断点调试来进行,可以观察指令执行情况
及相关寄存器的值,可参考相关教程。
小结
1.当汇编代码中定义了函数,那么需要定义栈空间
2.读取数据前,逻辑扇区号需要转化为磁盘的物理位置
3.物理软盘上的数据位置由磁头号,柱面号,扇区唯一确定
4.软盘数据以扇区512为单位进行读取