溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

操作系統(tǒng)--主引導程序控制權(quán)的轉(zhuǎn)移

發(fā)布時間:2020-07-12 11:38:04 來源:網(wǎng)絡(luò) 閱讀:252 作者:淡淡_小孩 欄目:系統(tǒng)運維

一.主引導程序控制權(quán)的轉(zhuǎn)移

首先需要了解的是BootLoader內(nèi)存布局,在嵌入式操作系統(tǒng)中,BootLoader是在操作系統(tǒng)內(nèi)核運行之前運行??梢猿跏蓟布O(shè)備、建立內(nèi)存空間映射圖,從而將系統(tǒng)的軟硬件環(huán)境帶到一個合適狀態(tài),以便為最終調(diào)用操作系統(tǒng)內(nèi)核準備好正確的環(huán)境。在嵌入式系統(tǒng)中,通常并沒有像BIOS那樣的固件程序(注,有的嵌入式CPU也會內(nèi)嵌一段短小的啟動程序),因此整個系統(tǒng)的加載啟動任務(wù)就完全由BootLoader來完成。在一個基于ARM7TDMI core的嵌入式系統(tǒng)中,系統(tǒng)在上電或復位時通常都從地址0x00000000處開始執(zhí)行,而在這個地址處安排的通常就是系統(tǒng)的BootLoader程序。

操作系統(tǒng)--主引導程序控制權(quán)的轉(zhuǎn)移
0x7c00主引導程序的起始地址,之前為??臻g,主要是函數(shù)調(diào)用。,最終主引導程序是從boot程序跳轉(zhuǎn)到0x9000loader,中間部分為Fat表,占用4個字節(jié)
1.通過FAT表加載文件內(nèi)容--流程圖
操作系統(tǒng)--主引導程序控制權(quán)的轉(zhuǎn)移
實驗步驟
1.在虛擬軟盤中創(chuàng)建體積較大的文本文件(Loader)
2.將Loader的內(nèi)容加載到BaseOfLoader地址處
3.打印Loader中的文本(判斷加載是否完全)

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

對此進行make的結(jié)果
操作系統(tǒng)--主引導程序控制權(quán)的轉(zhuǎn)移
從該結(jié)果可以看出,TIME的值為負數(shù)了,說明主引導程序的大小大于了512,我們需要將其減小,將之前不重要的入棧與出棧的操作進行刪除,以免占用空間,那么我們之前為何要這樣做呢?是為了遵守匯編代碼的約定,有操作相關(guān)寄存器的值就要進行入棧出棧操作。那么我們這塊內(nèi)存已經(jīng)不夠,因此沒必要進行這個操作了。我們將下面的入棧出棧操作進行刪除,但是要在 FindEntry 這個函數(shù)保留 cx 寄存器的入棧出棧的操作,原因是下面不停在改變 cx 寄存器的值。我們在 find 操作中,call MemCmp 操作前后有必要再加上 si 寄存器的入棧出棧操作
將其改正后的make以及在bochs上實現(xiàn)的結(jié)果為會打印loader中的字符串內(nèi)容
操作系統(tǒng)--主引導程序控制權(quán)的轉(zhuǎn)移

B.第一個loader程序
1.起始地址0x9000
2.通過int0x10在屏幕上打印字符串

操作系統(tǒng)--主引導程序控制權(quán)的轉(zhuǎn)移
a.零標志位--判斷運算的結(jié)果是否為0,當運算結(jié)果為0時,ZF位的值為1
b.同時jxx代表了一個指令族,功能是根據(jù)標志位進行調(diào)整
jo當OF為1則跳轉(zhuǎn),jc當CF為1則跳轉(zhuǎn),jns當SF不為1則跳轉(zhuǎn),jz當ZF為1則跳轉(zhuǎn),je比較結(jié)果為相等則跳轉(zhuǎn)
loader.asm代碼實現(xiàn)

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

將loader.asm進行反編譯得出的結(jié)果
操作系統(tǒng)--主引導程序控制權(quán)的轉(zhuǎn)移
可以看到在這里的jz對應(yīng)的是loader.asm中的je命令
接下來將loader拷貝到軟盤中去,然后從Boot跳轉(zhuǎn)到loader進行執(zhí)行,我們將虛擬軟盤先在linux中進行掛載,然后進行拷貝,最后進行運行
操作系統(tǒng)--主引導程序控制權(quán)的轉(zhuǎn)移操作系統(tǒng)--主引導程序控制權(quán)的轉(zhuǎn)移
從打印的結(jié)果可以看出,控制權(quán)從boot已經(jīng)轉(zhuǎn)移到loader程序了
將其打印結(jié)果進行修改看在bochs上的實現(xiàn)結(jié)果是否也修改了
操作系統(tǒng)--主引導程序控制權(quán)的轉(zhuǎn)移操作系統(tǒng)--主引導程序控制權(quán)的轉(zhuǎn)移
在這里我們需要將makefile文件進行修改保證后期的運行簡便


.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

最后將data.img在window下實現(xiàn)
操作系統(tǒng)--主引導程序控制權(quán)的轉(zhuǎn)移
小結(jié)
1.Boot需要進行重構(gòu)保證在512字節(jié)內(nèi)完成功能
2.在匯編程序中盡量確保函數(shù)調(diào)用前后通用寄存器的狀態(tài)不變
3.Boot成功加載Loader后將控制權(quán)轉(zhuǎn)移
4.Loader程序沒有代碼體積上的限制

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI