我正在尝试构建一个简单的引导加载程序和内核。引导加载程序位于 0x7C00,内核位于 0x1000。即使 jmp 到达正确的位置,内核也永远不会被执行。引导加载程序工作正常。
boot.asm
[BITS 16] ; We are in real mode (16-bit)
[ORG 0x7C00] ; Origin of the bootloader (BIOS loads it at 0x7C00)
start:
xor ax, ax ; Clear AX register (AX = 0)
mov ds, ax ; set DS to 0x0000 (needed for some instructions)
; Print bootloader message
mov si, bootloader_msg ; Load address of bootloader message
call print_string ; call the print string function
; Load the kernel into memory
mov ax, 0x1000 ; Load kernel at memory segment 0x1000
mov es, ax ; set ES to 0x1000, this is used by the interupt 0x13 to read the sector later
mov bx, 0x0000 ; Offset 0 in the segment
; Read 1 sector (512 bytes) from the disk into the memory (kernel sector)
mov ah, 0x02 ; BIOS function: Read sectors
mov al, 1 ; Read 1 (increase this number to read multiple sectors) sector
mov ch, 0 ; Cylinder/track number 0
mov dh, 0 ; Head number 0
mov cl,2 ; Sector number 2 (sector number 1 is bootloader)
int 0x13 ; BIOS interupt to read disk
jc error ; if carry flag is set then jump to error
; Jump to kernel entry point
jmp 0x1000:0000
; Print debug message
mov si, debug_msg ; Load address of debug message
call print_string ; call the print string function
error:
mov si, error_msg ; Load error message
call print_string ; Print error message
hlt ; Halt the CPU
print_string:
mov ah, 0x0E
print_loop:
lodsb
cmp al, 0
je done
int 0x10
jmp print_loop
done:
ret
bootloader_msg db 'Loading kernel...', 0
debug_msg db 'Not jumped to kernel...', 0
error_msg db 'Error loading Kenel...', 0
times 510-($-$$) db 0
dw 0xAA55
内核.asm:
[BITS 16] ; We are in real mode (16-bit)
[ORG 0x1000] ; Origin of the kernel (should match where it is loaded)
start:
; Set up segment registers
xor ax, ax ; Clear AX register
mov ds, ax ; Set DS to 0x0000
mov es, ax ; Set ES to 0x0000
; Print kernel message
mov si, kernel_msg ; Load address of kernel message
call print_string ; Call the print string function
hang:
jmp hang ; Infinite loop to prevent exit
print_string:
mov ah, 0x0E ; BIOS function to write character
print_loop:
lodsb ; Load byte at DS:SI into AL and increment SI
cmp al, 0 ; Check for null terminator
je done ; If zero, end of string
int 0x10 ; Call BIOS to print character
jmp print_loop ; Repeat for next character
done:
ret ; Return to caller
kernel_msg db 'Hello from the kernel!', 0 ; Message to print
; Fill the remaining space in the kernel to make it a full sector
times 512 - ($ - $$) db 0
我在 wsl 中使用 ubuntu 20.04。 我使用以下命令创建了一个 .img 文件:
dd if=/dev/zero of=floppy.img bs=512 count=2880
运行以下命令:
nasm -f bin boot.asm -o boot.bin
nasm -f bin kernel.asm -o kernel.bin
cat boot.bin kernel.bin > floppy.img
qemu-system-x86_64 -drive format=raw,file=floppy.img
使用hexdump检查图像文件时,一切都位于正确的位置。 十六进制转储输出
它打印“正在加载内核...”,但随后它就卡住了并且不执行任何操作。 输出
我正在尝试构建一个简单的引导加载程序和内核。我期待“正在加载内核...”和“来自内核的你好!”作为输出。仅打印“正在加载内核...”。
jmp 0x0000:0x1000
引导加载程序位于 0x7C00,内核位于 0x1000。
从这句话中大多数人会立即明白both这些值都是偏移量。事实上,这也是内核构建的目的(线性地址 4096)。但是引导加载程序需要进行以下更改:
xor ax, ax ; Load kernel at memory segment 0x0000
mov es, ax
mov bx, 0x1000 ; Offset 4096 in the segment
...
; Jump to kernel entry point
jmp 0x0000:0x1000
jmp 0x1000:0x0000
但是,如果您确实想要在段 0x1000(线性地址 65536)加载内核,那么更改必须转到 kernel.asm:
[ORG 0x0000]
start:
push cs ; CS == 0x1000 because of the `jmp 0x1000:0x0000`
pop ds ; that brought us here
在引导加载程序中包含一次性
cld
指令始终是一个好主意,以便您的 lodsb
指令以正确的方向运行(升序地址)。