I. Transfer master boot program control
首先需要了解的是BootLoader内存布局,在嵌入式操作系统中,BootLoader是在操作系统内核运行之前运行。可以初始化硬件设备、建立内存空间映射图,从而将系统的软硬件环境带到一个合适状态,以便为最终调用操作系统内核准备好正确的环境。在嵌入式系统中,通常并没有像BIOS那样的固件程序(注,有的嵌入式CPU也会内嵌一段短小的启动程序),因此整个系统的加载启动任务就完全由BootLoader来完成。在一个基于ARM7TDMI core的嵌入式系统中,系统在上电或复位时通常都从地址0x00000000处开始执行,而在这个地址处安排的通常就是系统的BootLoader程序。
0x7c00 start address of the master boot program, prior to the stack space, primarily a function call. Final master boot program from the boot program to jump is 0x9000loader, the intermediate portion of Fat Table 4 bytes
1. Load the contents of the file by the FAT table - a flowchart
Experimental Procedure
1. Create a greater volume in the virtual floppy disk text file (loader)
2. content loaded into the loader BaseOfLoader address
text 3. Print loader (decision whether fully loaded)
org 0x7c00
jmp short start
nop
define:
BaseOfStack equ 0x7c00
BaseOfLoader equ 0x9000
RootEntryOffset equ 19
RootEntryLength equ 14
EntryItemLength equ 32
FatEntryOffset equ 1
FatEntryLength equ 9
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
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 ax, FatEntryOffset
mov cx, FatEntryLength
call ReadSector
mov cx, [EntryItem + 0x1A]
mov si, BaseOfLoader
loading:
mov ax, dx
add ax, 31
mov cx, 1
push dx
push bx
mov bx, si
call ReadSector
pop bx
pop cx
call FatVec
cmp dx, 0xFF7
jnb BaseOfLoader
add si, 512
jmp loading
output:
mov bp, MsgStr
mov cx, MsgLen
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: ; FatVec[j] = ( (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: ; FatVec[j+1] = (Fat[i+2] << 4) | ( (Fat[i+1] >> 4) & 0x0F );
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]
shr cl, 4
and cl, 0x0F
mov ch, 0
or dx, cx
return:
ret
; ds:si --> source
; es:di --> destination
; cx --> length
MemCpy:
push si
push di
push cx
push ax
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:
pop ax
pop cx
pop di
pop si
ret
; es:bx --> root entry offset address
; ds:si --> target string
; cx --> target length
;
; return:
; (dx !=0 ) ? exist : noexist
; exist --> bx is the target entry
FindEntry:
push di
push bp
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
exist:
noexist:
pop cx
pop bp
pop di
ret
; ds:si --> source
; es:di --> destination
; cx --> length
;
; return:
; (cx == 0) ? equal : noequal
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
; es:bp --> string address
; cx --> string length
Print:
mov dx, 0
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 bx
mov ah, 0x02
read:
int 0x13
jc read
pop ax
pop dx
pop cx
pop bx
ret
MsgStr db "No LOADER ..."
MsgLen equ ($-MsgStr)
Target db "LOADER "
TarLen equ ($-Target)
EntryItem times EntryItemLength db 0x00
Buf:
times 510-($-$$) db 0x00
db 0x55, 0xaa
The results of this run make
can be seen from this result, the TIME value is negative, indicating the size of the master boot program is greater than 512, we need to be reduced, and the stack before the stack unimportant for operation deleted, so as not to take up space, so why do we do it before? Order to comply assembly code convention, has a value related to the operation will be carried out register stack operation of the stack. So we have this memory is not enough, so there is no need for this to operate. We will be following push and pop operations to delete, but you want to keep a stack cx register stack operation in FindEntry this function, the following reason is constantly changing the value of the cx register. We find operation, before and after the operation it is necessary to call MemCmp plus si push the register stack operation
to make the corrections and the results achieved in the bochs to print the contents of a string of loader
B. a first program loader
1. The start address 0x9000
2. print on the screen by int0x10
a Zero flag - determination calculation result is 0, when the operation result is 0, the ZF bit is 1
B represents a command while jxx family, is adjusted according to the function flag.
Jo when the OF is 1 jump, jc is a jump when the CF, jns when SF is not a jump, jz when the ZF is a jump, je jump if the comparison result is equal
loader.asm code for
org 0x9000
begin:
mov si, msg
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
msg:
db 0x0a, 0x0a
db "Hello, D.T.OS!"
db 0x0a, 0x0a
db 0x00
The loader.asm results obtained decompile
can see here jz corresponding command is loader.asm in je
Next loader copied to the floppy disk to go, then jump from Boot loader to be implemented, we will virtual floppy first to mount in linux, and then copy, and finally runs
can be seen from the results of printing, control has been transferred from the boot loader to the program
will be modified to see the results of their print on the implementation of the results are also bochs changed
in the makefile here we need to be modified to ensure easy running late
.PHONY : all clean rebuild
BOOT_SRC := boot.asm
BOOT_OUT := boot
LOADER_SRC := loader.asm
LOADER_OUT := loader
IMG := data.img
IMG_PATH := /mnt/hgfs
RM := rm -fr
all : $(IMG) $(BOOT_OUT) $(LOADER_OUT)
@echo "Build Success ==> D.T.OS!"
$(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
Finally data.img practiced window
summary
1.Boot reconstruct required to ensure completion in 512 byte
2. assembler function calls try to ensure that the state change before and after the general-purpose register
after successfully loaded Loader 3.Boot control transfer
4.Loader program codes no limit on the volume of