第7课 - 突破512字节的限制(中)

Posted dua677

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第7课 - 突破512字节的限制(中)相关的知识,希望对你有一定的参考价值。

突破限制的预备工作

    技术分享图片技术分享图片

整体思路

    技术分享图片技术分享图片

如何在根目录区中查找目标文件?

通过根目录项的前11个字节进行判断

    技术分享图片技术分享图片

内存比较

    指定源起始地址(DS:SI)
    指定目标起始地址(ES:DI)
    判断在期望长度(CX)内每一个字节是否相等
    技术分享图片技术分享图片

汇编小贴士

    汇编中的比较与跳转
        比较:
            cmp cx, 0    ;比较cx的值是否为0,并把结果记录到标志寄存器
        跳转:
            jz equal          ; 如果比较为真(根据标志寄存器的值)就跳转到equal
    技术分享图片  技术分享图片
    访问栈空间中的栈顶数据
        不能使用sp直接访问栈顶数据
        通过其它通用寄存器间接访问栈顶数据
  技术分享图片

查找根目录区是否存在目标文件

技术分享图片
  技术分享图片

加载根目录区

    技术分享图片技术分享图片

小结

    可通过查找根目录区判断是否存在目标文件
        加载根目录区至内存中(ReadSector
        遍历根目录区中的每一项(FindEntry
        通过每一项的前11个字节进行判断(MemCmp
        当目标不存在时,打印错误信息(print

代码

  boot.asm

  1 org 0x7c00                            ; 从0x7c00处开始存储代码
  2  
  3 jmp short start                        ; BS_JmpBoot;短跳指令,jmp指令占用1字节,地址占用1字节;下面的nop空指令占用1字节;共3字节
  4 nop
  5  
  6 define:
  7     BaseOfStack     equ 0x7c00        ; 定义栈的起始地址,注意栈是从高到低增长的,先加后入栈,先出后减
  8     RootEntryOffset equ 19            ; 文件数据从19逻辑扇区开始
  9     RootEntryLenght equ 14            ; 目录文件项共14扇区
 10  
 11 ; ##############################################################################
 12 header:
 13     BS_OEMName        db "D.T.Soft"    ; OEM字符,8个,不足以空格填充
 14     BPB_BytsPerSec    dw 512            ; 每扇区字节数
 15     BPB_SecPerClus    db 1            ; 每簇占用扇区数
 16     BPB_RsvdSecCnt    dw 1            ; Boot占用的扇区数
 17     BPB_NumFATs        db 2            ; FAT表的记录数
 18     BPB_RootEntCnt    dw 224            ; 最大根目录文件数
 19     BPB_TotSec16    dw 2880            ; 逻辑扇区总数
 20     BPB_Media        db 0xF0            ; 媒体描述符
 21     BPB_FATSz16        dw 9            ; 每个FAT占用扇区数
 22     BPB_SecPerTrk    dw 18            ; 每个磁道扇区数
 23     BPB_NumHeads    dw 2            ; 磁头数
 24     BPB_HiddSec        dd 0            ; 隐藏扇区数
 25     BPB_TotSec32    dd 0            ; 如果BPB_TotSec16是0,则在这里记录扇区总数
 26     BS_DrvNum        db 0            ; 中断13的驱动器号
 27     BS_Reserved1    db 0            ; 未使用
 28     BS_BootSig        db 0x29            ; 扩展引导标志
 29     BS_VolID        dd 0            ; 卷序列号
 30     BS_VolLab        db "D.T.OS-0.01"; 卷标,必须11个字符,不足以空格填充
 31     BS_FileSysType    db "FAT12   "    ; 文件系统类型,必须使8个字符,不足填充空格
 32  
 33 ; ##############################################################################
 34 start:                                ; 汇编起始标号,类似于main()函数
 35     mov ax, cs                        ; 设置相关的段寄存器
 36     mov ss, ax
 37     mov ds, ax
 38     mov es, ax
 39     mov sp, BaseOfStack                ; 设置函数调用栈
 40  
 41     ;mov ax, 59                        ; 文件数据起始于59扇区
 42     ;mov cx, 1                        ; 读取1个扇区
 43     ;mov bx, Buf                    ; 数据写入的地址
 44  
 45     ;call ReadSector                ; 调用读扇区函数(数据保存到ES:BX)
 46     
 47     ;mov si, MsgStr
 48     ;mov di, DEST
 49     ;mov cx, MsgLen
 50     mov ax, RootEntryOffset            ; 记录数据起始扇区
 51     mov cx, RootEntryLenght            ; 记录数据占用扇区数
 52     mov bx, Buf                        ; 读取的数据存放处
 53  
 54     call ReadSector                    ; 读取指定扇区数据到Buf缓存
 55     mov si, Target                    ; 要查找的文件名
 56     mov cx, TarLen                    ; 文件名长度
 57     mov dx, 0        ; 设置默认返回值
 58  
 59     call FindEntry                    ; 查找文件
 60  
 61     cmp dx, 0                        ; 如果没有找到文件就输出提示,否則跳到last死循環
 62     jz output
 63     jmp last
 64  
 65     ;call MemCmp
 66  
 67     ;cmp cx, 0
 68     ;jz output
 69     ;jmp last
 70  
 71     ;mov bp, Buf                    ; 字符串段的偏移地址,相对于ES; mov bp, MsgStr    ; 输出Hello, DTOS!
 72     ;mov cx, 29                        ; 字符串长度    ; mov cx, MsgLen    ; Test file for virtual floppy.
 73 output:
 74     mov bp, MsgStr
 75     mov cx, MsgLen
 76     call Print                        ; 调用字符串打印函数
 77  
 78 last:                                ; 死循环
 79     hlt
 80     jmp last
 81  
 82 ; ##############################################################################
 83 ; es:bx --> root entry offset address
 84 ; ds:si --> target string
 85 ; cx    --> target length
 86 ;
 87 ; return:
 88 ;        (dx != 0) ? exist : noexist
 89 ;            exist --> bx is the target entry
 90 FindEntry:                            ; 查找根目录文件
 91     push di
 92     push bp
 93     push cx
 94  
 95     mov dx, [BPB_RootEntCnt]        ; 最大根目录文件数
 96     mov bp, sp                        ; 栈地址,不能直接将sp栈顶指针赋值给通用寄存器
 97  
 98 find:
 99     cmp dx, 0                        ; 如果没有文件就跳转到noexist结束
100     jz noexist
101     mov di, bx                        ; bx==Buf缓存;ReadSector()已经读取数据到Buf缓存
102     mov cx, [bp]                    ; 借助中间寄存器获取栈顶指针,此时的bp栈顶指针指向最后入栈的cx寄存器
103     call MemCmp                        ; 内存匹配查找(文件查找)
104     cmp cx, 0                        ; 如果还有文件就继续,否则匹配失败跳转到exist结束
105     jz exist
106     add bx, 32                        ; Buf缓存地址加32,每个目录项占用32字节
107     dec dx                            ; dx-1,文件数减1
108     jmp find
109  
110 exist:
111 noexist:
112     pop cx
113     pop bp
114     pop di
115  
116     ret
117  
118 ; ##############################################################################
119 ; ds:si --> source
120 ; es:di --> destination
121 ; cx    --> length
122 ;
123 ; return:
124 ;        (cx == 0) ? equal : noequeal
125 MemCmp:                                ; 内存数据对比
126     push si
127     push di
128     push ax
129  
130 compare:
131     cmp cx, 0                        ; 到末尾(文件名结束符)就跳转到equal
132     jz equal
133     mov al, [si]                    ; si源(要查找的文件名)
134     cmp al, byte [di]                ; di目标(根目录区的文件名)
135     jz goon                            ; 匹配一个字节就跳转到goon继续循环判断
136     jmp noequal                        ; 不匹配就跳转到noequal,函数返回以便查找下一个文件
137 goon:
138     inc si                            ; 源和目标+1递增
139     inc di
140     dec cx                            ; 剩余次数-1递减
141     jmp compare                        ; 跳转到compare继续循环
142  
143 equal:
144 noequal:
145     pop ax
146     pop di
147     pop si
148  
149     ret
150  
151 ; ##############################################################################
152 ; es:bp --> string address
153 ; cx    --> string length
154 Print:                                ; 字符串打印函数
155     mov ax, 0x1301                    ; ah=13,在Teletype电传打字机模式下输出;al=01,字符串只含字符,启用BL属性,改变光标
156     mov bx, 0x0007                    ; bh页码,bl前景色;bl=07,80×25字符的2色文本
157     int 0x10                        ; 打印中断
158     ret                                ; 函数返回
159  
160 ; ##############################################################################
161 ; no parameter
162 ResetFloppy:                        ; 重置软盘段
163     push ax
164     push dx
165  
166     mov ah, 0x00                    ; 磁盘系统复位
167     mov dl, [BS_DrvNum]                ; 驱动器号(0x00~0x7F软盘,0x80~0x0FF硬盘)
168     int 0x13                        ; 读取磁盘的中断
169     
170     pop dx
171     pop ax
172  
173     ret
174  
175 ; ax    --> logic sector number
176 ; cx    --> number of sector
177 ; es:bx    --> target address
178 ReadSector:                            ; 读扇区段(函数)
179     push bx                            ; 保存相关寄存器
180     push cx
181     push dx
182     push ax
183     
184     call ResetFloppy                ; 重置软盘
185     
186     push bx
187     push cx
188  
189     mov bl, [BPB_SecPerTrk]            ; 每柱面(磁道)扇区数;本段代码用于计算柱面、磁头和扇区号以及设置驱动器号
190     div bl                            ; 除法,被除数在AX(或者DX高位+AX地位),商在AL,余数在AH
191     mov cl, ah                        ; 余数,cl记录起始扇区;FAT的扇区从0开始,软盘的扇区从1开始,所以下面+1
192     add cl, 1
193     mov ch, al                        ; 商(逻辑柱面或磁道数),ch记录起始柱面(磁道)
194     shr ch, 1                        ; 右移一位表示除以2(当前软盘只有2个磁头),因为扇区编号是由两面的柱面(磁道)组合的,然后再从外往内增大;shr移位大于1时需要借助cl寄存器;
195     mov dh, al                        ; 商,dh记录起始磁头
196     and dh, 1                        ; 如果逻辑柱面(磁道)号是偶数就在0磁头,否则就是1磁头(目前只有2个磁头)
197     mov dl, [BS_DrvNum]                ; 设置驱动器号
198  
199     pop ax                            ; 还原要读取的扇区数,相当于原来的cx,因为cx是最后入栈的,这里是最先出栈
200     pop bx                            ; bx已设置为指向Buf
201  
202     mov ah, 0x02                    ; 0x02读扇区
203  
204 read:
205     int 0x13                        ; 读取磁盘的中断
206     jc read                            ; 若进位位(CF)被置位,表示调用失败,需要重新读取
207  
208     pop ax
209     pop dx
210     pop cx
211     pop bx
212  
213     ret
214  
215 ; ##############################################################################
216 ;MsgStr db "Hello, DTOS!"            ; 定义字符串,上面43行注释使用
217 MsgStr db "No LOADER  "                ; 定义字符串,上面43行注释使用
218 MsgLen equ ($-MsgStr)                ; 定义上面字符串长度标号
219 ;DEST db "Hello, DTOS!"                ; 測試目標文件
220 Target db "LOADER"                    ; 要查栈的文件名
221 TarLen equ ($-Target)                ; 要查找的文件名长度
222 Buf:                                ; Buf缓存,数据的读取和写入空间;下面两行代码是为mbr准备的,其它读写无用无害
223     times 510-($-$$) db 0x00
224     db 0x55, 0xaa

输出

    找到了文件(LOADER)
    技术分享图片  技术分享图片

 

    没有找到文件(LiOADER)
    技术分享图片  技术分享图片
 

以上是关于第7课 - 突破512字节的限制(中)的主要内容,如果未能解决你的问题,请参考以下文章

第5课 - 主引导程序的扩展(下)

6.突破512字节的限制(上)

操作系统--突破512字节的限制

第七课 突破512字节限制--中

第六课 突破512字节的限制 上

第八课 突破512字节的限制--下