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

内核调试信息无法显示在屏幕上的问题排查求助

内核调试信息无法显示的排查与修复

问题背景

自行编写汇编引导加载程序(未使用GRUB),将内核加载到实模式下的0x0000:0x1000地址,但内核中的调试信息始终无法显示在屏幕上。

内核核心代码

kernel_entry:
    cli

    mov ax, 0x1000
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax

    mov si, DEBUG_MSG
    call print_string

    mov ax, 0x1000
    mov ss, ax
    mov sp, 0x9000

    mov si, DEBUG_MSG
    call print_string

    call load_memory_map

    mov si, DEBUG_MSG
    call print_string

    jmp $

print_string:
.next_char:
    mov al, [si]
    cmp al, 0
    je .done

    mov ah, 0x0E
    int 0x10
    inc si
    jmp .next_char
.done:
    ret

DEBUG_MSG db "debug", 13, 10, 0

引导加载程序代码

start:
    push cs
    pop ds

    mov si, boot_title 
    call print_string

    mov si, option_1
    call print_string

    mov si, option_2
    call print_string

    jmp wait_for_input

wait_for_input:
    mov ah, 0x00
    int 0x16

    cmp al, '1'
    je boot_KetOS

    cmp al, '2'
    je reboot

    jmp wait_for_input

boot_KetOS:
    mov si, boot_msg
    call print_string

    jmp load_kernel

load_kernel:
    cli

    mov [BOOT_DRIVE], dl

    mov bx, 0x1000
    mov ax, 0x0000
    mov es, ax

    mov ah, 0x02
    mov al, 16
    mov ch, 0
    mov cl, 2
    mov dh, 0x00

    mov dl, byte [cs:BOOT_DRIVE]

    int 0x13
    jc disk_error

    jmp 0x0000:0x1000


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

排查与修复要点

1. 段寄存器寻址错误

内核入口后立刻将ds设置为0x1000,但DEBUG_MSG是和内核代码一起加载到0x0000:0x1000(物理地址0x1000)处的。此时ds=0x1000,[si]指向的物理地址是0x1000*16 + DEBUG_MSG偏移,这会偏离内核实际加载的位置,导致读取到无效数据(大概率是0),print_string会直接退出。

修复方法:

  • 先打印调试信息,再修改段寄存器:
kernel_entry:
    cli

    ; 先打印,此时ds继承自引导程序的0x0000,寻址正确
    mov si, DEBUG_MSG
    call print_string

    mov ax, 0x1000
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax

    ; 后续代码...
  • 或者保持ds=0x0000,仅调整ss到0x1000段,避免寻址混乱。

2. 磁盘加载不完整或失败

引导加载程序用int 0x13加载16个扇区,但存在两个隐患:

  • 若内核编译后大小超过8192字节(16*512),会导致部分代码/数据未加载,print_string或DEBUG_MSG可能不在内存中。
  • disk_error函数未实现,加载失败后会直接跳转到内核地址,此时内存中是无效数据,无法执行打印逻辑。

修复方法:

  • 实现disk_error函数,加载失败时打印提示并挂起:
disk_error:
    mov si, disk_err_msg
    call print_string
    jmp $
disk_err_msg db "Disk load error!", 13, 10, 0
  • 查看内核二进制文件大小,调整al寄存器的值为实际需要加载的扇区数。

3. 栈地址有效性问题

内核设置ss=0x1000、sp=0x9000,对应物理地址0x19000,虽然处于实模式可用内存范围,但如果后续栈操作超出可用区域,会导致函数ret指令出错,程序崩溃。

修复方法:

  • 临时将栈设置到更安全的低内存区域,比如:
mov ax, 0x0000
mov ss, ax
mov sp, 0xFFFE
  • 确认0x19000地址未被其他数据占用后再使用原栈设置。

4. 中断状态干扰

虽然cli仅屏蔽硬件中断,不影响软中断int 0x10,但可以尝试在调用print_string前执行sti开启中断,排除潜在的中断状态影响。

内容的提问来源于stack exchange,提问作者GoofyKetchup

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.02 01:44:50