自定义Bootloader与Kernel启动仅显示光标问题排查求助
自定义Bootloader+Kernel系统无输出问题排查指南
问题概述
开发的简易OS基于自定义Bootloader和汇编Kernel,启动后仅显示光标,无任何输出。已确认Bootloader将Kernel加载到指定内存,但调试输出无显示,需排查原因。
环境信息
- Bootloader(bootloader.asm):汇编编写,负责加载Kernel到内存
- Kernel(kernel.asm):汇编编写,包含初始化与UI交互逻辑
- 工具链:NASM汇编、LD链接
- 测试环境:物理硬件
已完成排查
- 验证内存地址内容,确认Kernel已被Bootloader正确加载
- 在Bootloader和Kernel中添加调试输出,无任何显示
代码片段
Bootloader代码
[BITS 16] [ORG 0x7C00] section bootloader jmp main main: ; Set up segment registers mov ax, 0x07C0 mov ds, ax mov es, ax ; Load the kernel into memory mov bx, 0x8000 ; Destination memory address mov ah, 0x02 ; Read sector function mov al, 1 ; Number of sectors to read mov dl, 0x80 ; Boot drive number mov ch, 0 ; Cylinder number mov dh, 0 ; Head number mov cl, 2 ; Sector number int 0x13 ; Disk interrupt ; Jump to the loaded kernel jmp 0x8000:0000 times 510 - ($ - $$) db 0 dw 0xAA55 ; Boot signature
Kernel代码
[BITS 16] [ORG 0x8000] section kernel start: mov ax, 0x07C0 ; Set up segment registers mov ds, ax mov es, ax ; Clear the screen mov ah, 0x00 ; Video BIOS - Set video mode mov al, 0x03 ; Mode 3 (Text mode: 80x25, 16 colors) int 0x10 ; Video interrupt ; Print the menu options mov si, menu call printString ; Wait for user input call readChar ; Process user input cmp al, '1' je option1 cmp al, '2' je option2 jmp invalidOption option1: mov si, msgOption1 call printString jmp end option2: mov si, msgOption2 call printString jmp end invalidOption: mov si, msgInvalid call printString end: ; Halt the system cli hlt printString: lodsb ; Load the next character from string test al, al ; Check if end of string jz done ; If yes, return mov ah, 0x0E ; Video BIOS - Teletype output mov bh, 0x00 ; Video page int 0x10 ; Video interrupt jmp printString ; Print next character done: ret readChar: mov ah, 0x00 ; BIOS - Wait for key press int 0x16 ; Keyboard interrupt ret menu db 'Welcome to aiOS!', 0x0D, 0x0A, 'Select an option:', 0x0D, 0x0A, '1. Option 1', 0x0D, 0x0A, '2. Option 2', 0x0D, 0x0A, 0x00 msgOption1 db 'You selected Option 1.', 0x0D, 0x0A, 0x00 msgOption2 db 'You selected Option 2.', 0x0D, 0x0A, 0x00 msgInvalid db 'Invalid option.', 0x0D, 0x0A, 0x00 times 510 - ($ - $$) db 0 dw 0xAA55 ; Boot signature
关键排查点与修复方案
1. 致命错误:Bootloader加载地址与跳转地址不匹配
Bootloader中:
- ES寄存器被设为
0x07C0,BX是0x8000,因此Kernel被加载到物理地址0x07C0 * 16 + 0x8000 = 0xF000 - 跳转指令
jmp 0x8000:0000指向的物理地址是0x8000 * 16 + 0 = 0x80000
两个地址完全不重叠,导致跳转到空内存区域,自然无输出。
修复方案二选一:
方案A:调整Bootloader的ES寄存器,让加载地址匹配跳转地址
修改Bootloader的段寄存器设置:
main: ; Set up segment registers mov ax, 0x0000 mov ds, ax mov es, ax ; ES设为0,此时ES:BX=0x0000:0x8000,对应物理地址0x8000 ; Load the kernel into memory mov bx, 0x8000 ; Destination memory address ; ... 其他磁盘读取代码不变 ; Jump to the loaded kernel jmp 0x0000:0x8000 ; 或直接jmp 0x8000,CS=0,IP=0x8000对应物理地址0x8000
同时修改Kernel的段寄存器设置:
start: mov ax, 0x0000 ; 与Bootloader的ES一致 mov ds, ax mov es, ax
方案B:调整跳转地址到实际加载的物理地址
Bootloader中Kernel加载到物理地址0xF000,对应段:偏移为0x0F00:0000,修改跳转指令:
; Jump to the loaded kernel jmp 0x0F00:0000
修改Kernel的ORG和段寄存器:
[BITS 16] [ORG 0x0000] ; 因为段地址是0x0F00,偏移从0开始 section kernel start: mov ax, 0x0F00 ; 对应加载的段地址 mov ds, ax mov es, ax
2. 移除Kernel中的冗余引导签名
Kernel不是引导扇区,不需要times 510 - ($ - $$) db 0和dw 0xAA55,这会强制Kernel大小对齐到512字节,可能截断代码或填充无效数据,直接删除这两行。
3. 添加磁盘读取错误处理
Bootloader调用int 0x13后未检查返回值,磁盘读取可能失败。添加错误判断逻辑:
int 0x13 jc disk_error ; CF位置位表示读取失败 ; ... 跳转Kernel代码 disk_error: mov ah, 0x0E mov al, 'E' mov bh, 0x00 int 0x10 ; 输出'E'提示读取失败 cli hlt
4. 验证BIOS中断可用性
在Bootloader中添加简单输出测试,确认BIOS中断正常工作:
main: mov ax, 0x0000 mov ds, ax mov es, ax ; 测试输出 mov ah, 0x0E mov al, 'B' mov bh, 0x00 int 0x10 ; 屏幕显示'B' ; ... 后续加载Kernel代码
如果能显示'B',说明BIOS中断正常,问题集中在Kernel段地址匹配上。
5. 物理硬件兼容性优化
部分现代硬件对CHS模式磁盘读取支持不佳,建议改用LBA模式读取:
; 替换原CHS读取代码为LBA模式 mov ah, 0x42 ; LBA读取功能号 mov dl, 0x80 ; 启动驱动器 mov si, dap ; DAP指针 int 0x13 jc disk_error ; DAP(磁盘地址包)定义 dap: db 0x10 ; DAP大小(固定16字节) db 0 ; 保留位 dw 1 ; 读取扇区数 dw 0x8000 ; 目标内存偏移 dw 0x0000 ; 目标内存段地址 dq 1 ; LBA扇区号(引导扇区是0,Kernel是1)
内容的提问来源于stack exchange,提问作者LevathonDeveloper
相关产品推荐
相关产品推荐

