【发布时间】:2014-10-24 07:53:43
【问题描述】:
出于学习目的,我正在尝试用汇编语言编写引导加载程序和内核。当我组装我的代码并用它启动虚拟机时,引导加载程序似乎工作正常,但内核永远不会启动。我在想我跳到了错误的指令,但不知道我需要做哪些更正来解决我的问题。我也有可能试图错误地制作软盘,但我认为这不是问题。当我在十六进制编辑器中查看图像文件时,它们似乎已正确附加。另一个原因可能是从软盘中读取了错误的扇区。我正在尝试让内核在引导加载程序之后立即进入该扇区并从中读取。
要构建和运行此代码,我在 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 挂载为软盘驱动器,并在来宾系统上运行它。
结果是
Patrick 的引导加载程序已启动。 软盘已重置。 读取内核扇区 内核扇区加载
。而且内核永远不会启动。
这是我的代码
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
【问题讨论】:
-
您是否尝试在跳转到内核之前插入断点以确保正确的数据已加载到正确的地址?
-
我尝试了其他可能提供更多信息的方法。我重写了引导加载程序以使其更加模块化,并在我进行 int 0x13 调用后包含一个打印出 AH 寄存器的调用。这样做还会在中断调用之后,但在跳转到内核之前,在混合中添加更多指令。尝试读取内核扇区后出现 0Eh 错误。你知道这意味着什么吗?我确实改变了为此构建它的方式。我正在填充内核文件,并通过一个包含引导加载程序和内核的文件使用 NASM,然后以 1023d 的限制进行部分复制。
-
在开始编写操作系统之前,您可能需要熟悉一些调试工具。
标签: assembly operating-system kernel bootloader