前几节我们介绍了FAT12文件系统,制作了虚拟软盘文件a.img,并在Qt Creater中进行了文件内容的读取实验。那些读取都是使用外部的程序实现的,实际应用中,我们需要用主引导程序来实现文件的读写,主引导程序存在于主引导扇区MBR中,也就是说程序和文件是存在一张盘上的,而且这些主引导程序需要使用汇编语言实现。接下来,我们就来实现具有读取功能的主引导程序。
为了验证文件读取的正确性,我们需要在主引导程序中先实现一个字符串打印函数。BIOS已经将中断向量写到了内存的指定位置处,这其中就有能实现字符串打印的函数,我们需要做的就是配置一些参数,需要配置的参数和配置步骤如下:
1、指定打印参数(AX=0x1301 , BX = 0x0007)
2、指定字符串的内存地址(ES:BP = 字符串地址)
3、指定字符串的长度(CX = 字符串长度)
4、中断调用(int 0x10)
示例如下:
需要用到的汇编语言的知识点如下:
下面直接给出打印字符串的汇编程序:
1 org 0x7c00 2 3 jmp short start 4 nop 5 6 define: 7 BaseOfStack equ 0x7c00 8 9 header: 10 BS_OEMName db "D.T.Soft" 11 BPB_BytsPerSec dw 512 12 BPB_SecPerClus db 1 13 BPB_RsvdSecCnt dw 1 14 BPB_NumFATs db 2 15 BPB_RootEntCnt dw 224 16 BPB_TotSec16 dw 2880 17 BPB_Media db 0xF0 18 BPB_FATSz16 dw 9 19 BPB_SecPerTrk dw 18 20 BPB_NumHeads dw 2 21 BPB_HiddSec dd 0 22 BPB_TotSec32 dd 0 23 BS_DrvNum db 0 24 BS_Reserved1 db 0 25 BS_BootSig db 0x29 26 BS_VolID dd 0 27 BS_VolLab db "D.T.OS-0.01" 28 BS_FileSysType db "FAT12 " 29 30 start: 31 mov ax, cs 32 mov ss, ax 33 mov ds, ax 34 mov es, ax 35 mov sp, BaseOfStack 36 37 mov ax, MsgStr 38 mov bp, ax 39 40 mov ax, ds 41 mov es, ax 42 43 mov cx, 6 44 call Print 45 46 last: 47 hlt 48 jmp last 49 50 ; es:bp --> string address 51 ; cx --> string length 52 Print: 53 mov ax, 0x1301 54 mov bx, 0x0007 55 int 0x10 56 ret 57 58 MsgStr db "Hello, DTOS!" 59 MsgLen equ ($-MsgStr) 60 Buf: 61 times 510-($-$$) db 0x00 62 db 0x55, 0xaa
我们的虚拟软盘文件a.img已经格式化好了,现在要修改的只是第一个扇区即主引导扇区,所以我们要按照FAT12的格式来填充第一个扇区,因此,上面的程序中,第10到28行是FAT12的引导扇区的信息,它前面还有三个字节,其中前两个字节是跳转指令jmp short start,第三个字节为空指令nop。从start开始是我们的可执行程序,BaseOfStack是定义的栈底地址。
汇编程序我们需要编译成二进制可执行程序,然后写入a.img虚拟软盘的第一个扇区中,每次都执行这个过程很麻烦,我们将这个过程写成makefile,如下所示:
1 .PHONY : all clean rebuild 2 3 SRC := boot.asm 4 OUT := boot.bin 5 IMG := a.img 6 7 RM := rm -fr 8 9 all : $(OUT) $(IMG) 10 dd if=$(OUT) of=$(IMG) bs=512 count=1 conv=notrunc 11 @echo "Success!" 12 13 $(IMG) : 14 bximage $@ -q -fd -size=1.44 15 16 $(OUT) : $(SRC) 17 nasm $^ -o $@ 18 19 clean : 20 $(RM) $(IMG) $(OUT) 21 22 rebuild : 23 @$(MAKE) clean 24 @$(MAKE) all 25
bochs的启动文件修改成如下内容:
1 ############################################################### 2 # Configuration file for Bochs 3 ############################################################### 4 5 # how much memory the emulated machine will have 6 megs: 32 7 8 # filename of ROM images 9 romimage: file=/usr/share/bochs/BIOS-bochs-latest 10 vgaromimage: file=/usr/share/vgabios/vgabios.bin 11 12 # what disk images will be used 13 floppya: 1_44=a.img, status=inserted 14 # choose the boot disk. 15 boot: a 16 17 # where do we send log messages? 18 # log: bochsout.txt 19 20 # disable the mouse 21 mouse: enabled=0 22 23 # enable key mapping, using US layout as default. 24 keyboard_mapping: enabled=1, map=/usr/share/bochs/keymaps/x11-pc-us.map
启动bochs,即可得到运行结果,如下所示:
可见,hello已经成功打印出来了。
接下来,我们开始读取文件,假如我们知道了数据所在的扇区,那么怎么将它读出来呢?先来看一下软盘的构造,如下所示:
3.5寸软盘的特性如下:
根据逻辑扇区号计算磁头号、柱面号、物理扇区号的方法如下:
软盘复位和软驱数据读取的参数如下:
整体的读取流程如下:
需要用到的汇编知识点如下:
下面直接给出汇编程序:
1 org 0x7c00 2 3 jmp short start 4 nop 5 6 define: 7 BaseOfStack equ 0x7c00 8 9 header: 10 BS_OEMName db "D.T.Soft" 11 BPB_BytsPerSec dw 512 12 BPB_SecPerClus db 1 13 BPB_RsvdSecCnt dw 1 14 BPB_NumFATs db 2 15 BPB_RootEntCnt dw 224 16 BPB_TotSec16 dw 2880 17 BPB_Media db 0xF0 18 BPB_FATSz16 dw 9 19 BPB_SecPerTrk dw 18 20 BPB_NumHeads dw 2 21 BPB_HiddSec dd 0 22 BPB_TotSec32 dd 0 23 BS_DrvNum db 0 24 BS_Reserved1 db 0 25 BS_BootSig db 0x29 26 BS_VolID dd 0 27 BS_VolLab db "D.T.OS-0.01" 28 BS_FileSysType db "FAT12 " 29 30 start: 31 mov ax, cs 32 mov ss, ax 33 mov ds, ax 34 mov es, ax 35 mov sp, BaseOfStack 36 37 mov ax, 34 38 mov cx, 1 39 mov bx, Buf 40 41 call ReadSector 42 43 mov bp, Buf 44 mov cx, 24 45 46 call Print 47 48 last: 49 hlt 50 jmp last 51 52 ; es:bp --> string address 53 ; cx --> string length 54 Print: 55 mov ax, 0x1301 56 mov bx, 0x0007 57 int 0x10 58 ret 59 60 ; no parameter 61 ResetFloppy: 62 push ax 63 push dx 64 65 mov ah, 0x00 66 mov dl, [BS_DrvNum] 67 int 0x13 68 69 pop dx 70 pop ax 71 72 ret 73 74 ; ax --> logic sector number 75 ; cx --> number of sector 76 ; es:bx --> target address 77 ReadSector: 78 push bx 79 push cx 80 push dx 81 push ax 82 83 call ResetFloppy 84 85 push bx 86 push cx 87 88 mov bl, [BPB_SecPerTrk] 89 div bl 90 mov cl, ah 91 add cl, 1 92 mov ch, al 93 shr ch, 1 94 mov dh, al 95 and dh, 1 96 mov dl, [BS_DrvNum] 97 98 pop ax 99 pop bx 100 101 mov ah, 0x02 102 103 read: 104 int 0x13 105 jc read 106 107 pop ax 108 pop dx 109 pop cx 110 pop bx 111 112 ret 113 114 MsgStr db "Hello, DTOS!" 115 MsgLen equ ($-MsgStr) 116 Buf: 117 times 510-($-$$) db 0x00 118 db 0x55, 0xaa
我们将虚拟软盘文件a.img用VS2013打开,查看其中的内容,截取片段如下:
可以看到,a.txt文件的起始地址为0x4400,也就是第34个扇区开始,而内容的大小为24字节,这两个参数分别体现在汇编程序中的第37和44行。下面,启动bochs,运行结果如下:
打印出了this is a floppy file.,我们成功读取了指定扇区的数据。
参考狄泰软件学院操作系统教程