Bootloader在0x13中断处停滞,内核加载及跳转异常求助
Bootloader 0x13中断及跳转异常排查指南
一、0x13中断停滞/加载失败的常见原因
- 磁盘参数错误:
int 0x13的AH功能号(读扇区为0x02)、DL驱动器号(软盘0x00/硬盘0x80)、CHS参数(柱面/磁头/扇区,扇区编号从1开始而非0)是否与实际镜像匹配。 - 内存地址冲突:内核加载目标地址是否被Bootloader自身占用(Bootloader通常在0x7c00,内核建议加载到0x1000及以上地址)。
- 中断返回状态未检查:执行
int 0x13后未检测CF标志位,出错后无处理逻辑直接停滞。 - 磁盘镜像格式问题:Makefile生成镜像的
dd命令参数错误,未生成可引导的软盘/硬盘镜像。
二、三种异常情况的具体排查
1. 显示内核加载成功但无法跳转
- 内核入口地址不匹配:检查链接脚本的
ENTRY指定入口(如_start)是否与Bootloader跳转地址一致,链接脚本的基地址设置需和加载地址对应(如Bootloader跳转到0x100000,链接脚本需设BASE_ADDRESS = 0x100000)。 - 跳转指令错误:实模式下需使用远跳转指令
ljmp而非近跳转jmp,段地址计算需遵循物理地址=段地址*16+偏移的规则,比如ljmp 0x1000:0x0000需确保段寄存器设置正确。 - 内核初始化错误:若Bootloader在实模式跳转,内核是否直接进入保护模式而未做实模式初始化,导致执行崩溃。
2. 无任何反应
- Bootloader未正确引导:确认Bootloader末尾存在
0xAA55引导标志,Makefile中是否用dd将Bootloader写入镜像第一个扇区(如dd if=bootloader.bin of=disk.img bs=512 count=1 conv=notrunc)。 - 段寄存器初始化错误:
int 0x13要求ES:BX指向目标缓冲区,若DS、ES未初始化会导致写入错误地址,后续代码执行混乱。 - 屏幕输出逻辑错误:使用
int 0x10输出字符时,AH功能号(0x0E为电传输出)、AL的ASCII码、BH页号(设为0)是否正确,输出代码异常会导致无提示。
3. 提示内核加载失败
- 扇区数量计算错误:内核二进制文件大小对应的扇区数需准确(如1024字节需2个扇区),扇区数不足会导致加载不完整触发错误。
- 驱动器号硬编码错误:BIOS启动时会将驱动器号存入DL,应直接使用该值而非硬编码,避免虚拟机/真机环境差异导致错误。
- 内核写入镜像位置错误:Makefile中
dd的seek参数需正确(如内核写入第2个扇区需seek=1),位置错误会导致Bootloader读取不到内核。
三、代码层面关键检查点
Bootloader汇编代码
- 正确设置
int 0x13参数并检查返回状态:mov ah, 0x02 ; 读扇区功能 mov al, 2 ; 加载扇区数(根据内核大小调整) mov ch, 0 ; 柱面号 mov dh, 0 ; 磁头号 mov cl, 2 ; 扇区号(从第2个扇区开始读) mov dl, [boot_drive] ; 使用BIOS传入的驱动器号 mov bx, 0x1000 ; ES:BX指向内核加载地址 mov es, bx xor bx, bx int 0x13 jc load_error ; CF置位则跳转至错误处理 - 正确跳转至内核:
mov ax, 0x1000 mov ds, ax mov es, ax ljmp 0x1000:0x0000 ; 远跳转到内核入口 - 确保引导标志存在:
times 510-($-$$) db 0 dw 0xaa55
Bootloader Makefile
- 编译与镜像生成命令示例:
bootloader.bin: bootloader.asm nasm -f bin bootloader.asm -o bootloader.bin disk.img: bootloader.bin kernel.bin dd if=/dev/zero of=disk.img bs=1M count=1 dd if=bootloader.bin of=disk.img bs=512 count=1 conv=notrunc dd if=kernel.bin of=disk.img bs=512 seek=1 conv=notrunc
内核链接脚本
- 确保入口与加载地址正确:
ENTRY(_start) SECTIONS { . = 0x100000; # 内核加载到1MB地址 .text : { *(.text) } .data : { *(.data) } .bss : { *(.bss) } }
内核 Makefile
- 32位无依赖编译示例:
kernel.bin: kernel.o ld -m elf_i386 -T link.ld kernel.o -o kernel.bin kernel.o: kernel.c gcc -m32 -ffreestanding -c kernel.c -o kernel.o
内容的提问来源于stack exchange,提问作者fabx
相关产品推荐
相关产品推荐

