簡體   English   中英

程序集Bootloader沒有跳轉到內核

[英]Assembly Bootloader Not Jumping to Kernel

我正在嘗試在匯編中編寫引導加載程序和內核以用於學習目的。 當我組裝代碼並使用它啟動虛擬機時,引導加載程序似乎正常工作,但內核永遠不會啟動。 我想我正在跳錯了指令,但不知道我需要做些什么更正才能解決我的問題。 還有可能我試圖使軟盤不正確,但我認為這不是問題。 當我在十六進制編輯器中查看圖像文件時,似乎它們被正確附加。 另一個原因可能是從軟盤讀取錯誤的扇區。 我正試圖讓內核在引導加載程序之后立即進入扇區。

要構建和運行此代碼,我在Windows Vista x64中執行以下操作:

nasm bootloader_2.asm -f bin -o bootloader_2.bin 
nasm kernel_2.asm -f bin -o kernel.bin 
partcopy bootloader_2.bin bootloader_2.img 0d 511d 
partcopy kernel_2.bin kernel_2.img 0d 511d 
copy bootloader.img /b + kernel.img POS_2.img

然后我使用Oracle VM Virtual Box將POS_2.img掛載為軟盤驅動器,並在來賓系統上運行它。

結果是

帕特里克的Bootloader開始了。 軟盤已重置。 讀取內核扇區內核扇區

內核永遠不會啟動。

這是我的代碼

bootloader_2.asm

bits 16
org 0x7C00
boot: jmp loader

; OEM Parameter block / BIOS Parameter block (wtf is this for?)
times 0Bh-$+boot DB 0
bpbBytesPerSector:        DW 512
bpbSectorsPerCluster:    DB 1
bpbReservedSectors:        DW 1
bpbNumberOfFATs:        DB 2
bpbRootEntries:            DW 224
bpbTotalSectors:        DW 2880
bpbMedia:                DB 0xF0
bpbSectorsPerFAT:        DW 9
bpbSectorsPerTrack:        DW 18
bpbHeadsPerCylinder:    DW 2
bpbHiddenSectors:        DD 0
bpbTotalSectorsBig:        DD 0
bsDriveNumber:            DB 0
bsUnused:                DB 0
bsExtBootSignature:        DB 0x29
bsSerialNumber:            DD 0xa0a1a2a3
bsVolumeLabel:            DB "MOS FLOPPY"
bsFileSystem:            DB "FAT12"
; END PARAMETER BLOCK

; ----- Variables -----

started db "Patrick's Bootloader Started...", 0x0D, 0x0A, 0
floppy_reset_done db "Floppy has been reset.", 0x0D, 0x0A, 0
loading_msg db "Reading Kernel Sector", 0x0D, 0x0A, 0
loading_sucess db "Kernel Sector Loaded", 0x0D, 0x0A, 0
done db "Bootloader Done.", 0x0D, 0x0A, 0

; ----- End Variables -----

; ----- Calls -----

reset_floppy:
    mov ah, 0
    mov dl, 0
    int 0x13
    jc reset_floppy
    mov si, floppy_reset_done
    call print_string
    ret

read_kernel:
    mov si, loading_msg
    call print_string
    mov si, 0x0

    mov ax, 0x1000    ; setting up the address to read into
    mov es, ax        ; moving the value in to es
    xor bx, bx        ; clearing bx
    mov ah, 0x02    ; floppy function
    mov al, 1        ; read 1 sector
    mov ch, 1        ; track
    mov cl, 2        ; sector to read
    mov dh, 0        ; head number
    mov dl, 0        ; drive number

    int 0x13        ; BIOS Interrupt Call

    jc read_kernel

    mov si, loading_sucess
    call print_string

    ret

print_string:
    lodsb
    or al, al
    jz .done
    mov ah, 0x0E
    int 0x10
    jmp print_string
.done:
    ret

; input is ax, cx is destroyed    
print_hex:
    mov cx, 4
    .next_digit:
        push cx
        mov cl, 4
        rol ax, cl
        push ax
        and al, 0x0F
        add al, '0'
        cmp al, '9'
        jle .not_a_leter
        add al, 'A'-'9'-1
    .not_a_leter:
        mov ah, 0x0E
        int 0x10
        pop ax
        pop cx
        loop .next_digit
    ret

; ----- End of Calls -----

; ===== Bootloader Main =====

loader:
    mov si, started
    call print_string
    call reset_floppy
    call read_kernel

    jmp 0x1000:0x0

    mov si, done        ; never reached. Intentional for debugging
    call print_string    ; these lines failure to produce a result tell us that the jmp was attempted

; ===== End of Bootloader Main =====

times 510-($-$$) db 0
dw 0xAA55

kernel_2.asm

kernel:
    jmp k_main

welcome_msg db "Welcome to Patrick's Operating System!", 0x0D, 0x0A, 0

print_string:
    lodsb
    or al, al
    jz .done
    mov ah, 0x0E
    int 0x10
    jmp print_string
.done:
    ret

k_main:

    mov si, welcome_msg
    call print_string

    .k_main_loop:

    jmp .k_main_loop

cli
hlt

times 512-($-$$) db 0

冒着指出明顯的風險,您的腳本不會復制正確的文件。 在某些地方你指的是kernel.bin和其他的kernel_2.bin 試試這個:

nasm bootloader_2.asm -f bin -o bootloader_2.bin 
nasm kernel_2.asm -f bin -o kernel_2.bin 
partcopy bootloader_2.bin bootloader_2.img 0d 511d 
partcopy kernel_2.bin kernel_2.img 0d 511d 
copy bootloader.img /b + kernel_2.img POS_2.img

您可能還會發現使用dd更容易使用dd 它可以作為Cygwin的一部分使用,並且具有可以寫入文件或物理設備(如真正的軟盤)的優點。

此外,您應該考慮使用Makefile而不是腳本。 當您進一步擴展項目時,它將有所幫助。

也就是說,代碼有三個基本問題。 首先,要加載的下一個扇區是在柱面0上,而不是柱面1.其次,代碼不能簡單地安全地ret內核 - 你必須明確地跳轉到那里。 那部分代碼將如下所示:

read_kernel:
    mov si, loading_msg
    call print_string
    mov si, 0x0

    mov ax, 0x1000   ; setting up the address to read into
    mov es, ax       ; moving the value in to es
    xor bx, bx       ; clearing bx
    mov ah, 0x02     ; floppy function
    mov al, 1        ; read 1 sector
    mov ch, 0        ; cylinder
    mov cl, 2        ; sector to read
    mov dh, 0        ; head number
    mov dl, 0        ; drive number

    int 0x13         ; BIOS Interrupt Call

    jc read_kernel
    push es          ; either push the address and retf or use far jmp
    push bx          ;

    mov si, loading_sucess
    call print_string

    ; jmp  0x1000:0  ; alternative to push/retf is simple long jump

    retf

第三個問題是內核。 您還沒有將DS寄存器更改為指向新的偏移量,因此即使您獲得該代碼,它也不會打印您想要的字符串。 將代碼更改為以下內容:

k_main:
    push cs          ; save the cs reg
    pop  ds          ; use as ds also

    mov si, welcome_msg
    call print_string

    .k_main_loop:

    jmp .k_main_loop

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM