使用mkfs.fat -F32创建分区后FAT32 BPB字段为空问题
自制Bootloader读取FAT32分区BPB异常问题修复
核心问题定位
你的问题根源是ATA PIO驱动的LBA地址写入逻辑错误,导致读取扇区的地址偏移错误,无法正确获取FAT32专属BPB字段;同时LBA48模式的地址写入不完整,进一步加剧了读取异常。
具体修复方案
1. 修复LBA28模式地址写入错误
原LBA28分支中,错误使用outw操作8位寄存器,且移位取位逻辑完全错误:
// 错误代码 outb(d->bus+LBAlo,(uint8_t)LBA & 0xFF); outw(d->bus+LBAmid,(uint8_t)(LBA << 8) & 0xFF); outw(d->bus+LBAhi, (uint8_t)(LBA << 16) & 0xFF);
修复后:
// 正确写入LBA28的8位分段地址 outb(d->bus+LBAlo, (uint8_t)(LBA & 0xFF)); // LBA低8位([7:0]) outb(d->bus+LBAmid, (uint8_t)((LBA >> 8) & 0xFF)); // LBA中8位([15:8]) outb(d->bus+LBAhi, (uint8_t)((LBA >> 16) & 0xFF)); // LBA高8位([23:16])
注意:LBAmid和LBAhi是8位寄存器,必须用
outb而非outw,同时要正确提取对应位段。
2. 补全LBA48模式地址写入
原LBA48分支仅写入了低32位地址,遗漏了高16位,导致超过32位的LBA地址解析错误:
// 修复后的LBA48地址写入逻辑 if(d->LBA48 == 1) { outb(d->bus+DRIVE, d->dev == MASTER_DRIVE ? 0x40 : 0x50); while(((inb(d->bus) >> 7) & 1) != 0); outw(d->bus+SECTOR_COUNT_REGISTER, num); // 16位扇区计数 outw(d->bus+LBAlo, (uint16_t)(LBA & 0xFFFF)); // LBA[15:0] outw(d->bus+LBAmid, (uint16_t)((LBA >> 16) & 0xFFFF));// LBA[31:16] outw(d->bus+LBAhi, (uint16_t)((LBA >> 32) & 0xFFFF));// LBA[47:32] outb(d->bus+COMMAND, READ_LBA48); }
移除原代码中多余的
if(LBAmiddle > 0)判断,必须完整写入所有3个16位地址段,哪怕值为0。
3. 增强扇区读取的健壮性
在读取数据前,需确保驱动器处于数据就绪状态,避免读取无效数据:
// 读取数据循环添加DRQ状态检查 uint16_t *data = (uint16_t*)addr; for(int i = 0; i < (256*num);i++) { // 等待驱动器发出数据就绪信号(DRQ位为1) while(!(inb(d->bus + 0x07) & 0x08)); data[i] = inw(d->bus+DATA_REGISTER); }
0x07是ATA状态寄存器地址,0x08是DRQ(数据请求)位的掩码。
4. BPB结构体验证
你的BPB/FAT32 BPB结构体定义正确(已用#pragma pack(1)消除对齐问题),且x86架构为小端字节序,与FAT32的字段存储格式匹配,无需额外修改。
验证步骤
- 修复驱动代码后,重新编译Bootloader
- 读取EFI分区的引导扇区到内存
- 打印
BPB_FAT32中的SectorsPerFat、ClusterNumberRootDir等专属字段 - 与
mkfs.fat -v输出的分区信息对比,确认字段值一致
内容的提问来源于stack exchange,提问作者Honzasko
相关产品推荐
相关产品推荐

