[英]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開始了。 軟盤已重置。 讀取內核扇區內核扇區
。 內核永遠不會啟動。
這是我的代碼
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:
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.