You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

16位x86自制OS问题:Bootloader无法将内核加载至RAM

16位x86 Bootloader无法加载内核至RAM(INT 0x13调用失败)

问题现象

制作简易16位x86操作系统时,Bootloader执行到INT 0x13指令后触发错误,跳转到read_kernel_error分支,提示内核加载失败。内核仅实现打印"Hello World"功能,调整load_kernel段寄存器值后问题仍未解决。

相关代码

Bootloader代码(boot.asm)

; boot.asm

BITS 16
ORG 0x7C00

%define ENDL 0x0D, 0x0A

entry:
    jmp main

main:
    mov si, msg_booting
    call prints

    mov si, dbug0
    call prints

    jmp load_kernel

prints:
    lodsb

    cmp al, 0
    je return

    mov ah, 0x0E
    mov bh, 0x00
    mov bl, 0x07

    int 0x10
    jmp prints
 
load_kernel:
    mov ax, 0x0000
    mov bx, 0x1000
    mov cx, 0x0001
    mov dx, 0x00
    mov ah, 0x02
    int 0x13        ; error appears to be here
    jc read_kernel_error

    jmp 0x1000

read_kernel_error:
    mov si, dbug1
    call prints

    jmp done

return:
    ret

done:
    hlt

msg_booting db "Booting...", ENDL, 0
dbug0 db "Jumping to 'load_kernel'...", ENDL, 0
dbug1 db "Kernel could not be loaded correctly", ENDL, 0

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

内核代码(kernel.asm)

; kernel.asm

BITS 16
ORG 0x1000

main:
    mov si, msg_hw
    call prints
    jmp done

prints:
    lodsb

    cmp al, 0
    je return

    mov ah, 0x0E
    mov bh, 0x00
    mov bl, 0x07

    int 0x10
    jmp prints

return:
    ret

done:
    hlt

msg_hw db "Hello World", 0x0D, 0x0A, 0

编译与运行步骤

编译命令

nasm -f bin -o boot.bin boot.asm
nasm -f bin -o kernel.bin kernel.asm

制作软盘镜像

dd if=/dev/zero of=floppy.img bs=512 count=2880
dd if=boot.bin of=floppy.img bs=512 count=1 conv=notrunc
dd if=kernel.bin of=floppy.img bs=512 seek=1 conv=notrunc

运行命令

qemu-system-i386 -drive format=raw,file=floppy.img

问题分析与修复方案

核心错误点

  1. INT 0x13参数错误:
    • 未设置AL寄存器(读取扇区数量),默认值为0,尝试读取0个扇区直接触发错误。
    • 扇区号指定错误:内核被写入软盘的0-based第1扇区(对应dd seek=1),而INT 0x13使用1-based扇区号,正确扇区号应为2,但代码中CX=0x0001指定的是扇区1(读bootloader自身)。
    • 未明确设置驱动器号DL,部分BIOS会使用错误值导致读取失败。
  2. 段寄存器未初始化:
    • BIOS启动时仅保证CS=0x0000、IP=0x7C00,DS、ES值未定义,导致字符串打印(依赖DS:SI)和内存地址指向(ES:BX)存在未定义行为。
  3. 跳转地址不明确:jmp 0x1000依赖当前CS值,未明确指定段地址,存在歧义。

修复后的Bootloader关键代码

1. 初始化段寄存器(main函数开头)

main:
    ; 初始化段寄存器,匹配ORG 0x7C00的地址映射
    mov ax, 0x7C00
    mov ds, ax
    mov es, ax

    mov si, msg_booting
    call prints
    ; ... 后续代码

2. 修正load_kernel函数

load_kernel:
    ; 设置目标地址ES:BX = 0x0000:0x1000,匹配内核ORG 0x1000
    mov ax, 0x0000
    mov es, ax
    mov bx, 0x1000

    ; 配置INT 0x13读扇区参数
    mov ah, 0x02        ; 功能号:磁盘读扇区
    mov al, 0x01        ; 读取1个扇区(内核大小小于512字节)
    mov ch, 0x00        ; 柱面号:0
    mov cl, 0x02        ; 扇区号:2(1-based,对应dd seek=1的0-based扇区)
    mov dh, 0x00        ; 磁头号:0
    mov dl, 0x00        ; 驱动器号:0x00表示软盘A:
    int 0x13
    jc read_kernel_error

    ; 明确跳转至内核入口(0x0000:0x1000)
    jmp 0x0000:0x1000

验证修复

修改代码后重新执行编译、制作镜像、运行步骤,Bootloader将成功加载内核并打印"Hello World"。

内容的提问来源于stack exchange,提问作者Felix Hötzendorfer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 09:37:05