即使引导加载程序正常工作,也不执行内核

问题描述 投票:0回答:1

我正在尝试构建一个简单的引导加载程序和内核。引导加载程序位于 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检查图像文件时,一切都位于正确的位置。 十六进制转储输出

它打印“正在加载内核...”,但随后它就卡住了并且不执行任何操作。 输出

我正在尝试构建一个简单的引导加载程序和内核。我期待“正在加载内核...”和“来自内核的你好!”作为输出。仅打印“正在加载内核...”。

assembly linux-kernel operating-system kernel bootloader
1个回答
0
投票

案例
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
指令以正确的方向运行(升序地址)。

© www.soinside.com 2019 - 2024. All rights reserved.