基于Qemu+SeaBIOS的x86自制OS:ATA读写后显示空白问题排查
问题背景
在M1 Mac的Qemu模拟器中,基于x86架构的SeaBIOS开发简易操作系统。执行ata_write(1, 1, data)写入磁盘数据后,调用ata_read(1, 1, buffer)读取数据,再将读取到的内容写入已设置0x0F黑底白字属性的VGA显存,但屏幕始终显示空白。
相关代码片段
ATA读写C代码
// 用户提供的ATA读写实现 #include <stdint.h> void ata_write(uint8_t drive, uint32_t lba, uint8_t* data) { // 具体寄存器配置与数据写入逻辑 // 示例框架:设置LBA地址、选择扇区数、写入数据等 } void ata_read(uint8_t drive, uint32_t lba, uint8_t* buffer) { // 具体寄存器配置与数据读取逻辑 // 示例框架:设置LBA地址、选择扇区数、读取数据等 }
主函数代码
#include <stdint.h> #define VGA_TEXT_BUFFER 0xB8000 #define VGA_ATTR_BLACK_WHITE 0x0F void main() { uint8_t test_data[] = "Test OS Output"; uint8_t read_buffer[32] = {0}; // 写入磁盘扇区 ata_write(1, 1, test_data); // 从磁盘扇区读取 ata_read(1, 1, read_buffer); // 写入VGA文本显存 uint16_t* vga_ptr = (uint16_t*)VGA_TEXT_BUFFER; for (int i = 0; read_buffer[i] != '\0'; i++) { vga_ptr[i] = (VGA_ATTR_BLACK_WHITE << 8) | read_buffer[i]; } // 死循环保持屏幕显示 while(1); }
磁盘操作汇编代码
; 用户提供的ATA端口读写汇编实现 global ata_outb global ata_inb ata_outb: mov dx, [esp+4] ; 端口地址 mov al, [esp+8] ; 要写入的数据 out dx, al ret ata_inb: mov dx, [esp+4] ; 端口地址 in al, dx ret
排查方向
- ATA设备与地址校验
- 检查drive参数:ATA主设备编号为0,从设备为1,若Qemu中挂载的是主盘,传入1会操作不存在的设备,导致读写无响应。建议改为
ata_write(0, 1, data)测试。 - 验证LBA地址有效性:LBA1属于MBR分区表区域,部分SeaBIOS配置下该区域可能受保护,改用LBA2及以后的空闲扇区测试,避免读写受限区域。
- 检查drive参数:ATA主设备编号为0,从设备为1,若Qemu中挂载的是主盘,传入1会操作不存在的设备,导致读写无响应。建议改为
- ATA操作时序与状态检查
- 读写前必须等待控制器就绪:操作ATA寄存器前,需循环读取端口0x1F7,直到BUSY位(第7位)为0,否则操作会被忽略。
- 写操作后等待完成:写入数据后,需等待状态寄存器的DRDY位(第6位)置位,确认设备完成写入再执行读操作。
- 增加错误检查:每次操作后读取状态寄存器的ERR位(第0位),若置位则输出错误信息(可直接写VGA显存),排查是否有读写错误。
- VGA输出验证
- 先跳过磁盘读写,直接将
test_data写入VGA显存,确认屏幕能正常显示,排除VGA写入逻辑的问题。 - 在ATA读操作后,直接将
read_buffer的前几个固定字节(比如0x48即'H')写入显存,验证缓冲区是否被正确填充。
- 先跳过磁盘读写,直接将
- Qemu环境配置
- 确认启动命令:必须使用
qemu-system-i386或qemu-system-x86_64指定x86架构,同时通过-hda your_disk.img挂载可读写的磁盘镜像。 - 检查磁盘镜像权限:确保磁盘镜像文件不是只读模式,否则
ata_write会失败,读回的数据全为0。
- 确认启动命令:必须使用
内容的提问来源于stack exchange,提问作者user7289922
相关产品推荐
相关产品推荐

