内核调试信息无法显示在屏幕上的问题排查求助
内核调试信息无法显示的排查与修复
问题背景
自行编写汇编引导加载程序(未使用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
相关产品推荐
相关产品推荐

