ATA驱动卡在DRQ等待循环,Grub引导自制OS故障排查
ATA驱动在Grub引导下卡在等待DRQ的问题
我编写了一个超简易操作系统,改用Grub引导后,ATA驱动无法正常工作,卡在等待DRQ的环节。该驱动在旧Bootloader下可正常工作,因此问题大概率和Grub引导有关。目前IDT沿用旧Bootloader的,GDT采用某视频中的配置,中断功能正常(除零异常、键盘输入均无问题),仅ATA驱动出现故障。
相关代码
错误的DRQ等待函数
void ATA_wait_DRQ() // Wait fot drq to be 1 { while (!(insb(0x1F7) & STATUS_RDY)) ; }
扇区读取函数
int disk_read_sector(int lba, void *buf) { ATA_wait_BSY(); print("f1"); ATA_wait_DRQ(); // estes dois nao estavam aqui antes pus so pq no write tive de por print("f2"); lba = lba + OS_SECTORS + HEADER_SECTORS; outb(0x1F6, (lba >> 24) | 0xE0); outb(0x1F2, 1); outb(0x1F3, (unsigned char)(lba & 0xff)); outb(0x1F4, (unsigned char)(lba >> 8)); outb(0x1F5, (unsigned char)(lba >> 16)); outb(0x1F7, 0x20); unsigned short *ptr = (unsigned short *)buf; ATA_wait_BSY(); ATA_wait_DRQ(); for (int i = 0; i < 256; i++) { *ptr = insw(0x1F0); ptr++; } return 0; }
状态检查函数及现象
void checkPort() { char a = insb(0x1F7); a = a + 48; write_char_pos(5, 5, a, 0x00ff00); if (a == '0') { char b = insb(0x1F1); b = b + 48; write_char_pos(6, 6, a, 0x00ff00); } }
执行该函数后,(5,5)和(6,6)位置均输出'0',判断磁盘控制器出现错误。
问题分析与修复方案
DRQ等待函数逻辑错误
函数注释是等待DRQ置位,但实际判断的是STATUS_RDY(就绪位,第6位0x40),而DRQ对应的是状态寄存器的第3位(0x08)。修正后的函数:#define STATUS_DRQ 0x08 void ATA_wait_DRQ() // 等待DRQ置位 { while (!(insb(0x1F7) & STATUS_DRQ)) ; }错误的等待时机
发送读取命令前调用ATA_wait_DRQ完全不合理——DRQ位只有磁盘准备好传输数据时才会置位,应该在发送读取命令后再等待DRQ。去掉发送命令前的ATA_wait_DRQ调用即可。LBA地址验证
检查OS_SECTORS和HEADER_SECTORS的偏移值在Grub引导环境下是否依然正确,错误的LBA地址会导致磁盘控制器无法定位扇区,进而触发错误状态。控制器状态确认
Grub可能已初始化过ATA控制器,导致其状态与旧Bootloader环境不同。可以在驱动初始化时重新重置控制器,确保进入正确的PIO工作模式。
内容的提问来源于stack exchange,提问作者Rabyt
相关产品推荐
相关产品推荐

