USB启动IPL开发问题:读取扇区时LBA操作CF置1报错
排查USB启动IPL的LBA读扇区失败问题
针对你遇到的USB启动IPL在QEMU中LBA功能失效、CF始终置1并返回"load error"的问题,我整理了几个核心排查方向,你可以逐一验证:
1. 确认USB启动的BIOS调用规范
传统软盘/硬盘启动的INT 13h CHS模式调用,在USB设备上大概率不适用。你需要使用INT 13h扩展功能(AH=42h的LBA读),而且调用前必须做两件事:
- 先检测BIOS是否支持扩展INT 13h:调用
INT 13h, AH=41h, BX=55AAh,如果返回AX=AA55h且CF=0,说明支持;否则你的BIOS(或QEMU模拟的BIOS)不支持USB设备的扩展读功能。 - 不要硬编码设备号(比如0x80或0x00):USB设备的设备号由BIOS在启动时通过DL寄存器传递给IPL,直接使用这个DL值即可,不要自行修改。
2. 检查DAP(磁盘地址包)的正确性
使用AH=42h读扇区时,DS:SI必须指向一个正确的DAP结构,常见的错误点包括:
- DAP的字节长度是否设为0x10(16字节),这是标准DAP的长度;
- 扇区数字段(第2字节)是否设为你需要的360?注意这里是单字节,360超过了255,所以你需要分多次读取(比如每次读255扇区,分两次),或者使用扩展DAP(长度0x18);
- LBA起始地址是8字节的小端序,不要搞反字节顺序;
- 内存缓冲区的段:偏移是否正确,比如如果你的缓冲区在0x8000:0000,要确保DS和SI的设置对应这个地址。
3. 修正QEMU的启动命令
你当前的命令qemu-system-i386 -usb ipl.bin存在问题:QEMU的-usb只是启用USB控制器,但直接加载单个IPL二进制文件无法被识别为合法的USB启动盘。正确的做法是:
- 创建一个符合USB启动格式的镜像文件,比如360KB的软盘镜像:
dd if=/dev/zero of=usb.img bs=512 count=360 - 将你的ipl.bin写入镜像的第一个扇区:
dd if=ipl.bin of=usb.img bs=512 count=1 conv=notrunc - 用以下命令启动QEMU:
qemu-system-i386 -usb -drive file=usb.img,format=raw,media=disk
这样QEMU会把usb.img识别为USB软盘/硬盘设备,BIOS才能正确加载IPL。
4. 调试CF置1的具体错误原因
当INT 13h返回CF=1时,AX寄存器会携带错误码,你可以在调试时打印AX的值,快速定位问题:
- AX=01h:无效的命令(比如用了不支持的AH值)
- AX=02h:磁盘地址找不到(设备号错误或DAP参数错误)
- AX=04h:请求的扇区不存在(LBA地址超出设备容量)
- AX=0Dh:无效的设备类型(比如把USB设备当成了软盘)
你可以用QEMU的-d int选项跟踪中断调用日志,或者用GDB调试(启动时加-s -S参数,然后用gdb连接到localhost:1234),设置断点查看寄存器值。
5. 确认IPL的段寄存器设置
USB启动时,BIOS通常还是会把IPL加载到0x7C00地址,但你需要确保段寄存器(DS、ES、SS等)设置正确:
- 比如DS应该设为0x0000,这样DS:SI指向的DAP地址才是0x0000:7Cxx(假设DAP存在IPL代码中);
- 内存缓冲区的段设置也要对应,比如如果缓冲区在0x0800:0000,要确保ES=0x0800,BX=0x0000。
内容的提问来源于stack exchange,提问作者石原秀一




