千家信息网

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

发表于:2025-01-31 作者:千家信息网编辑
千家信息网最后更新 2025年01月31日,一.在突破512字节Q:主引导程序中如何进行字符串打印?--直接打印A.BIOS中的字符串打印1.指定打印参数(AX=0x1301,BX=0x0007)--不借助循环2.指定字符串的内存地址(ES:B
千家信息网最后更新 2025年01月31日操作系统--突破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 rebuildSRC := boot.asmOUT := boot.binIMG := data.imgRM := rm -frall : $(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 0x7c00jmp short startnopstart:    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 0x10last:    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 0x7c00jmp short startnopdefine:    BaseOfStack equ 0x7c00header:    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 Printlast:    hlt    jmp last    ; es:bp --> string address; cx    --> string lengthPrint:    mov ax, 0x1301    mov bx, 0x0007    int 0x10    ret; no parameterResetFloppy://写入软驱    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 addressReadSector://读取软驱    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, 0x02read:        int 0x13    jc read//读取失败  再进行读取    pop ax    pop dx    pop cx    pop bx    retMsgStr 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 0x7c00jmp short startnopdefine:    BaseOfStack      equ 0x7c00    RootEntryOffset  equ 19    RootEntryLength  equ 14header:    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 lastoutput:        mov bp, MsgStr    mov cx, MsgLen    call Printlast:    hlt    jmp last    exist:noexist:    pop cx    pop bp    pop di    retMemCmp:    push si    push di    push axcompare://比较函数的实现    cmp cx, 0    jz equal    mov al, [si]    cmp al, byte [di]    jz goon    jmp noequalgoon:    inc si    inc di    dec cx    jmp compareequal:noequal:   //不相等时    pop ax    pop di    pop si    retPrint:    mov ax, 0x1301    mov bx, 0x0007    int 0x10    ret; no parameterResetFloppy:    push ax    push dx    mov ah, 0x00    mov dl, [BS_DrvNum]    int 0x13    pop dx    pop ax    retReadSector:    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, 0x02read:        int 0x13    jc read    pop ax    pop dx    pop cx    pop bx    retMsgStr db  "MyDTOS!"    MsgLen equ ($-MsgStr)Target db  "MyDTOS!"TarLen equ ($-Target)Buf:    times 510-($-$$) db 0x00    db 0x55, 0xaa


打印的结果

从打印结果可以知道调用了在前面的比较函数中的label下的print函数,由此可得cx寄存器为,可以得到两个寄存器的地址是相等的

0