主引导程序控制权的转移

这一节,我们来真正的读取文件中的内容到内存中,首先来看一下内存布局是什么样的,如下所示:

Boot占用了512字节,Fat Table占用了4KB,而真正的文件中的内容,我们把它存在0x9000开始的内存地址处。

加载文件内容的过程如下:

实验步骤如下:

1、在虚拟软盘中创建体积较大的文本文件,使之内容大小超过一个扇区。

2、将文件的内容加载到BaseOfLoader地址处。

3、打印加载的内容,判断是否加载完全。

读取文件内容的代码如下所示

start:
	mov ax, cs
	mov ss, ax
	mov ds, ax
	mov es, ax
	mov sp, BaseOfStack

	mov ax, RootEntryOffest
	mov cx, RootEntryLength
	mov bx, Buf
    call ReadSection

	mov bx, Buf
	mov si, Target
	mov cx, TarLen
	call FindEntry

	cmp dx, 0
	jz Output
	
	mov si, bx
	mov di, EntryItem
	mov cx, EntryItemLength
	call MemCpy

	mov ax, FatEntryLength
	mov cx, [BPB_BytsPerSec]
	mul cx
	mov bx, BaseOfLoader
	sub bx, ax

	mov cx, FatEntryLength
	mov ax, FatEntryOffset
	call ReadSection

	mov dx, [EntryItem + 0x1a]
	mov si, BaseOfLoader

loading:
	mov ax, dx
	add ax, 31                                 # ax = 逻辑扇区号
	mov cx, 1
	push dx
	push bx
	mov bx, si
	call ReadSection
	pop bx
	pop cx                                      # cx = 文件扇区下标(数据区的扇区号)
	call FatVec
	cmp dx, 0xff7                             # 判断下一个文件扇区下标是否合法
	jnb Output
	add si, 512                                 # si = dest + 512
	jmp loading	

Output:
	mov bp, BaseOfLoader
	mov cx, [EntryItem + 0x1c]
	call Print

last:
	hlt
	jmp last

 我们在make时出现了一个错误

这个错误告诉我们已经使用的内存超出了512字节,所以我们就需要代码重构,删除一些不必要的代码,于是我们就把一些函数调用时不必要的入栈和出栈操作给删除了。

完整汇编代码如下所示 

org 0x7c00

define:
	BaseOfStack     equ 0x7c00	
	BaseOfLoader    equ 0x9000	
	RootEntryOffest equ 19
	RootEntryLength equ 14		
	EntryItemLength equ 32	
	FatEntryOffset  equ 1
	FatEntryLength  equ 9

jmp short start								
nop

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, RootEntryOffest
	mov cx, RootEntryLength
	mov bx, Buf
    call ReadSection

	mov bx, Buf
	mov si, Target
	mov cx, TarLen
	call FindEntry

	cmp dx, 0
	jz Output
	
	mov si, bx
	mov di, EntryItem
	mov cx, EntryItemLength
	call MemCpy

	mov ax, FatEntryLength
	mov cx, [BPB_BytsPerSec]
	mul cx
	mov bx, BaseOfLoader
	sub bx, ax

	mov cx, FatEntryLength
	mov ax, FatEntryOffset
	call ReadSection

	mov dx, [EntryItem + 0x1a]
	mov si, BaseOfLoader

loading:
	mov ax, dx
	add ax, 31
	mov cx, 1
	push dx
	push bx
	mov bx, si
	call ReadSection
	pop bx
	pop cx
	call FatVec
	cmp dx, 0xff7
	jnb Output
	add si, 512
	jmp loading	

Output:
	mov bp, BaseOfLoader
	mov cx, [EntryItem + 0x1c]
	call Print

last:
	hlt
	jmp last

; cx     --> index
; bx     --> fat table address
;
; return:
;    dx  --> fat[index]
FatVec:
	mov ax, cx
	mov cl, 2
	div cl

	push ax

	mov ah, 0
	mov cx, 3
	mul cx
	mov cx, ax

	pop ax

	cmp ah, 0
	jz even
	jmp odd

even:			; ((fat[i + 1] & 0x0f) << 8) | fat[i]
	mov dx, cx
	add dx, 1
	add dx, bx
	mov bp, dx
	mov dl, byte [bp]
	and dl, 0x0f
	shl dx, 8

	add cx, bx
	mov bp, cx
	or  dl, byte [bp]	
	jmp return

odd:		   ; (fat[i + 2] << 4) | ((fat[i + 1] & 0xf0) >> 4);
	mov dx, cx
	add dx, 2
	add dx, bx
	mov bp, dx
	mov dl, byte [bp]
	mov dh, 0
	shl dx, 4
	
	add cx, 1
	add cx, bx
	mov bp, cx
	mov cl, byte [bp]
	and cl, 0xf0
	mov ch, 0
	shr cx, 4
	or  dx, cx

return:
	ret

; ds:si    --> src
; es:di    --> dest
; cx       --> length
MemCpy:

	cmp si, di
	ja btoe
	
	add si, cx
	add di, cx
	dec si
	dec di
	jmp etob

btoe:
	cmp cx, 0
	jz done
	mov al, [si]
	mov byte [di], al
	inc si
	inc di
	dec cx
	jmp btoe
	
etob:
	cmp cx, 0
	jz done
	mov al, [si]
	mov byte [di], al
	dec si
	dec di
	dec cx
	jmp etob	

done:

	ret

; es:bx   --> entry root offset address
; ds:si   --> target string
; cx      --> target length
;
; return
; 	    (dx != 0) ? exist : noexist;
;		exist  --> bx is target entry
FindEntry:

	push cx
	mov dx, [BPB_RootEntCnt]
	mov bp, sp

find:
	cmp dx, 0
	jz noexist
	mov di, bx
	mov cx, [bp]
	call MemCmp
	cmp cx, 0
	jz exist
	add bx, 32
	dec dx
	jmp find

noexist:

exist:
	pop cx

	ret


; ds:si    --> source address
; es:di    --> destination address
; cx       --> length
;
; return
; (cx == 0) ? equal : noequal
MemCmp:

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:

	ret


;es:bp --> string address
;cx    --> string length
Print:
	mov dx, 0
	mov ax, 0x1301
	mov bx, 0x007
	int 0x10
	ret

;no parameter
ResetFloppy:

	mov ah, 0x00
	mov dl, [BS_DrvNum]
	int 0x13

	ret

; ax	  --> logic sector number
; cx	  --> number of sector
; es:bx   --> target address
ReadSection:

	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


	ret

MsgStr db  "Not Exist! ..." 
MsgLen equ ($-MsgStr)
Target db "LOADER  BIN"
TarLen equ ($-Target)
EntryItem times EntryItemLength db 0x00

Buf:
    times 510-($-$$) db 0x00
    db 0x55, 0xaa

下面是程序的输出结果

输出结果打印了loader.bin这个文件的内容,正确地打印了文件的内容。此文件的大小不足512字节,为了验证该程序能否正常的打印大小大于512字节的文件,我们就需要修改loader.bin这个文件。

于是我们通过 sudo mount -o loop data.img /mnt/hgfs/ 命令,将这个软盘挂载到虚拟文件系统,我们来修改loader.bin这个文件的内容,把boot.asm的内容复制到此文件中。

boot.asm的大小为3960字节,大于了512字节,我们重新加载程序

 

正确打印了loader.bin的文件内容,两次正确的打印说明了该程序的正确性。

我们修改了主程序的第86行代码,当找到目标文件时,主引导程序将控制权转交给0x9000处的地址片段。

以下是我们的测试程序,该程序打印一个"hello, DTOS!",来验证主引导程序是否把控制权转交给0x9000处的地址片段

org 0x9000

begin:
	mov si, MsgStr

print:
	mov al, [si]
	add si, 1
	cmp al, 0x00
	je end
	mov ah, 0x0e
	mov bx, 0x0f
	int 0x10
	jmp print 

end:
	hlt
	jmp end

MsgStr:
	db 0x0a, 0x0a
	db "hello, DTOS!"
	db 0x0a, 0x0a
	db 0x00

 由于我们需要把上面的程序编译成可执行文件,并且需要把可执行文件拷贝到data.img这个软盘中,为了不每次进行重复的步骤,我们需要修改makefile,修改后的makefile如下所示

.PHONY : all clean rebuild

BOOT_SRC := boot.asm
BOOT_OUT := boot.bin
LOADER_SRC := loader.asm
LOADER_OUT := loader

IMG := data.img
IMG_PATH := /mnt/hgfs

RM := rm -fr

all : $(IMG) $(BOOT_OUT) $(LOADER_OUT)
	@echo "Success!"

$(IMG) :
	bximage $@ -q -fd -size=1.44

$(BOOT_OUT) : $(BOOT_SRC)
	nasm $^ -o $@
	dd if=$@ of=$(IMG) bs=512 count=1 conv=notrunc

$(LOADER_OUT) : $(LOADER_SRC)
	nasm $^ -o $@
	sudo mount -o loop $(IMG) $(IMG_PATH)
	sudo cp $@ $(IMG_PATH)/$@
	sudo umount $(IMG_PATH)

clean :
	$(RM) $(IMG) $(BOOT_OUT) $(LOADER_OUT)

rebuild :
	@$(MAKE) clean
	@$(MAKE) all
	

我们在bochs上运行data.img

程序运行结果如下

成功跳转到0x9000处去执行我们测试用的可执行程序,打印出了字符串。

我们把data.img复制到window上,去VMware上测试,测试结果如下

也打印出来相应的字符串,到此为止,我们已经突破了512字节的限制!!! 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值