You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UEFI环境下GPT硬盘格式化与文件读取问题求助(C语言实现)

UEFI环境下GPT分区、FAT32格式化与文件读取问题解决方案

问题1:EFI_FILE_IO_PROTOCOL Read函数读取失败的解决

核心排查与修复步骤

  • 确保文件打开时使用正确模式:必须指定EFI_FILE_MODE_READ,避免与写入模式冲突;区分目录与文件的打开逻辑。
  • 验证文件句柄有效性:打开文件后必须检查返回值是否为EFI_SUCCESS,同时确认句柄非空。
  • 正确处理Read函数参数:BufferSize为输入输出参数,传入预期读取字节数,返回实际读取量;缓冲区需提前分配足够内存。

EDK II C语言示例代码

#include <Uefi.h>
#include <Protocol/SimpleFileSystem.h>

EFI_STATUS ReadEfiFile(EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FsProtocol, CHAR16 *FilePath, VOID **OutBuffer, UINTN *OutSize) {
    EFI_STATUS Status;
    EFI_FILE_PROTOCOL *RootDir = NULL;
    EFI_FILE_PROTOCOL *File = NULL;
    UINT64 FileSize = 0;
    UINTN BufferSize;

    // 打开根目录
    Status = FsProtocol->OpenVolume(FsProtocol, &RootDir);
    if (EFI_ERROR(Status)) return Status;

    // 以只读模式打开目标文件
    Status = RootDir->Open(RootDir, &File, FilePath, EFI_FILE_MODE_READ, 0);
    if (EFI_ERROR(Status)) {
        RootDir->Close(RootDir);
        return Status;
    }

    // 获取文件大小
    Status = File->GetInfo(File, &gEfiFileInfoGuid, &BufferSize, NULL);
    if (Status == EFI_BUFFER_TOO_SMALL) {
        *OutBuffer = AllocatePool(BufferSize);
        if (*OutBuffer == NULL) {
            File->Close(File);
            RootDir->Close(RootDir);
            return EFI_OUT_OF_RESOURCES;
        }
        Status = File->GetInfo(File, &gEfiFileInfoGuid, &BufferSize, *OutBuffer);
        if (!EFI_ERROR(Status)) {
            FileSize = ((EFI_FILE_INFO*)*OutBuffer)->FileSize;
            FreePool(*OutBuffer);
        }
    }
    if (EFI_ERROR(Status)) {
        File->Close(File);
        RootDir->Close(RootDir);
        return Status;
    }

    // 分配缓冲区并读取文件内容
    *OutSize = (UINTN)FileSize;
    *OutBuffer = AllocatePool(*OutSize);
    if (*OutBuffer == NULL) {
        File->Close(File);
        RootDir->Close(RootDir);
        return EFI_OUT_OF_RESOURCES;
    }
    BufferSize = *OutSize;
    Status = File->Read(File, &BufferSize, *OutBuffer);

    // 清理资源
    File->Close(File);
    RootDir->Close(RootDir);
    return Status;
}

问题2:UEFI环境下格式化FAT32分区的解决方案

UEFI原生API未提供直接的FAT32格式化功能,需手动实现分区格式化逻辑,核心步骤包括初始化GPT分区、构建FAT32引导扇区、初始化FAT表与根目录。

EDK II C语言核心实现框架

#include <Uefi.h>
#include <Protocol/DiskIo.h>
#include <Protocol/DevicePath.h>

// FAT32引导扇区结构定义
typedef struct {
    UINT8   BootJump[3];
    UINT8   OemName[8];
    UINT16  BytesPerSector;
    UINT8   SectorsPerCluster;
    UINT16  ReservedSectors;
    UINT8   FatCount;
    UINT16  RootDirEntries;
    UINT16  TotalSectors16;
    UINT8   MediaType;
    UINT16  SectorsPerFat16;
    UINT16  SectorsPerTrack;
    UINT16  Heads;
    UINT32  HiddenSectors;
    UINT32  TotalSectors32;
    UINT32  SectorsPerFat32;
    UINT16  ExtFlags;
    UINT16  FatVersion;
    UINT32  RootCluster;
    UINT16  FSInfoSector;
    UINT16  BackupBootSector;
    UINT8   Reserved[12];
    UINT8   DriveNumber;
    UINT8   Reserved1;
    UINT8   BootSignature;
    UINT32  VolumeId;
    UINT8   VolumeLabel[11];
    UINT8   FileSystemType[8];
    UINT8   BootCode[420];
    UINT16  BootSectorSignature;
} FAT32_BOOT_SECTOR;

EFI_STATUS FormatFat32Partition(EFI_DISK_IO_PROTOCOL *DiskIo, UINT64 StartLba, UINT64 SectorCount) {
    EFI_STATUS Status;
    FAT32_BOOT_SECTOR Bpb = {0};
    UINTN BufferSize = sizeof(FAT32_BOOT_SECTOR);
    UINT32 TotalClusters;

    // 初始化BPB参数(需根据实际磁盘参数调整)
    Bpb.BytesPerSector = 512;
    Bpb.SectorsPerCluster = 8;
    Bpb.ReservedSectors = 32;
    Bpb.FatCount = 2;
    Bpb.MediaType = 0xF8;
    Bpb.TotalSectors32 = (UINT32)SectorCount;
    TotalClusters = (Bpb.TotalSectors32 - Bpb.ReservedSectors - (Bpb.FatCount * Bpb.SectorsPerFat32)) / Bpb.SectorsPerCluster;
    // 计算符合FAT32规范的每个FAT的扇区数
    Bpb.SectorsPerFat32 = (TotalClusters + 0xFFF) / 0x1000;
    Bpb.RootCluster = 2;
    Bpb.FSInfoSector = 1;
    Bpb.BackupBootSector = 6;
    Bpb.DriveNumber = 0x80;
    Bpb.BootSignature = 0x29;
    CopyMem(Bpb.VolumeLabel, "UEFI_SYSTEM", 11);
    CopyMem(Bpb.FileSystemType, "FAT32   ", 8);
    Bpb.BootSectorSignature = 0xAA55;

    // 写入引导扇区到磁盘
    Status = DiskIo->WriteDisk(DiskIo, 0, StartLba, BufferSize, &Bpb);
    if (EFI_ERROR(Status)) return Status;

    // 初始化FSInfo扇区(需填充FSInfo结构,此处省略具体实现)
    // 初始化FAT表:写入根目录起始簇的结束标记(0x0FFFFFFF)
    // 初始化根目录(省略具体实现)

    return EFI_SUCCESS;
}

注意事项

  • 格式化前需通过EFI_DISK_IO_PROTOCOL验证磁盘可写权限,确保目标分区未被挂载。
  • GPT分区创建需使用EFI_PARTITION_PROTOCOL,将分区类型GUID设置为gEfiSystemPartitionGuid(EFI系统分区专用)。

内容的提问来源于stack exchange,提问作者user24150775

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 07:45:14