操作系统--突破512字节的限制
作者:互联网
一.在突破512字节
Q:主引导程序中如何进行字符串打印?--直接打印
A.BIOS中的字符串打印
1.指定打印参数(AX=0x1301,BX=0x0007)--不借助循环
2.指定字符串的内存地址(ES:BP=串地址)--通过段地址与段偏移来确定
3.指定字符串的长度(CX=串长度)
4.中断调用(int 0x10)
B.汇编小贴士
1.汇编中可以定义函数--函数名使用标签定义
call function;函数体的最后一条指令为ret
2.如果代码中定义了函数,那么需要定义栈空间
主要用于保存关键寄存器的值;栈顶地址通过sp寄存器保存
3.汇编中的"常量定义"--equ
用法是-Const equ 0x7c00;它同时与dx(db,dw,dd)有区别,区别主要在dx定义占用相应的内存空间,equ定义不会占用任何内存空间
C.实验-定义打印函数
a.首先可以利用makefile将主引导程序的创建以及二进制编译文件的创建过程简单化
.PHONY : all clean rebuild
SRC := boot.asm
OUT := boot.bin
IMG := data.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
从make的结果可以看出,运行成功,这样使得之后的修改编译过程变的简便
对boot.asm 文件进行设置
org 0x7c00
jmp short start
nop
start:
mov ax, cs
mov ss, ax
mov ds, ax
mov es, ax
mov sp, ax
mov ax, MsgStr//打印的汇编实现
mov cx, 6
mov bp, ax
mov ax, ds
mov es, ax
mov ax, 0x1301
mov bx, 0x0007
int 0x10
last:
hlt
jmp last
MsgStr db "MyDTOS ..." //打印的字符串
Buf:
times 510-($-$$) db 0x00
db 0x55, 0xaa
打印的字符串的结果
但是在设置的时候并没有打印函数,所以要在asm文件对汇编代码进行改进
在这里要进行三步--1.首先对打印函数进行了定义2.然后对栈空间进行定义--定义起始地址3.最后将sp栈顶指针寄存器指向定义栈的起始地址处
二.主引导程序中如何读取指定扇区处的数据?
A.软盘的构造
1.一个软盘有两个盘面,每个盘面对应一个磁头
2.每一个盘面被划分为若干个圆圈,成为柱面
3.每一个柱面被划分为若干个扇区,每个扇区512字节
软盘数据的读写--软盘数据一扇区512字节为单位进行读取,指定数据所在位置的磁头号,柱面号,扇区号。它的计算公式为
在BIOS中的软盘数据读取(int 0x13)
软盘数据的读写流程
在这里我们需要注意的是,汇编中的16为除法操作(div)--被除数放到AX寄存器,除数放到通用寄存器或内存单元(8位),结果是商位于AL,余数位于AH
1.先根据上面提到的知识对asm文件进行修改,以及对虚拟软盘进行查看
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//读取的为34扇区的原因是将data.img以二进制进行查看时 它是在34扇区 有29个字节
mov cx, 1
mov bx, Buf
call ReadSector
mov bp, Buf
mov cx, 29
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 bxa
mov ah, 0x02
read:
int 0x13
jc read//读取失败 再进行读取
pop ax
pop dx
pop cx
pop bx
ret
MsgStr db "MyDTOS!"
MsgLen equ ($-MsgStr)
Buf:
times 510-($-$$) db 0x00
db 0x55, 0xaa
2.对其进行验证,看其打印结果
小结
1.当汇编代码中定义了函数,那么需要定义栈空间
2.读取数据前,逻辑扇区号需要转化为磁盘的物理位置
3.物理软盘上的数据位置由磁头号,柱面号,扇区唯一确定
4.软盘数据以扇区512为单位进行读取
三.突破512字节下
在这里我们要做的是
整体进行的思路是
Q:现在的问题是如何在根目录中查找目标文件?
A.内存比较
1.指定源起始地址(DS:SI)
2.指定目标起始地址(ES:DI)
3.判断在期望长度(CX)内每一个字节是否都相等
汇编中比较和跳转命令
cmp cx,0--比较cx的值是否为0
jz equal--如果比较的结果为真,则跳转到equal标签处
B.需要一个内存比较函数,然后查找根目录区是否存在目标文件
org 0x7c00
jmp short start
nop
define:
BaseOfStack equ 0x7c00
RootEntryOffset equ 19
RootEntryLength equ 14
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
jmp last
output:
mov bp, MsgStr
mov cx, MsgLen
call Print
last:
hlt
jmp last
exist:
noexist:
pop cx
pop bp
pop di
ret
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
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
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 "MyDTOS!"
MsgLen equ ($-MsgStr)
Target db "MyDTOS!"
TarLen equ ($-Target)
Buf:
times 510-($-$$) db 0x00
db 0x55, 0xaa
打印的结果
从打印结果可以知道调用了在前面的比较函数中的label下的print函数,由此可得cx寄存器为,可以得到两个寄存器的地址是相等的
标签:BPB,字节,db,mov,pop,cx,ax,512,操作系统 来源: https://blog.51cto.com/13475106/2445861