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

分配EfiMemoryMappedIO内存时AllocatePages返回EFI_NOT_FOUND的问题排查

问题描述

尝试分配EfiMemoryMappedIO类型内存页供Windows驱动访问,定义了以下启动内存区域:

#define EFI_BOOT_MEMORY_REGIONS_LOW 0x90000, 0x88000, 0x80000
#define EFI_BOOT_MEMORY_REGIONS_HIGH \
0x100000, 0x200000, 0x300000, 0x400000, 0x500000, 0x600000, 0x700000, 0x800000, \
0x900000, 0xA00000, 0xB00000, 0xC00000, 0xD00000, 0xE00000, 0xF00000, 0x1000000

#define EFI_BOOT_MEMORY_REGIONS EFI_BOOT_MEMORY_REGIONS_LOW, EFI_BOOT_MEMORY_REGIONS_HIGH

遍历这些地址调用AllocatePages尝试分配,代码实现如下:

static EFI_STATUS
PrepareMemory(
       IN UINTN    Address,
       IN UINTN    Len,
       OUT VOID**  ppMemory)
{
    EFI_PHYSICAL_ADDRESS PhysAddr;
    UINTN Pages = 0;
    VOID* pAllocatedMemory = NULL;
    EFI_STATUS Status = EFI_SUCCESS;
    PhysAddr = Address & ~0x0fff; // set alignment to page size (for x86, x86-64 page size if 0x1000)
    Pages = ((Len & ~0x0fff) + 0x1000) >> 12;
    Status = BS->AllocatePages(AllocateAddress, EfiMemoryMappedIO, Pages, &PhysAddr);
    if (EFI_ERROR(Status))
    {
        LOG_ERROR_FN(L"!!! ERROR: Failed to prepare memory 0x%x (status = %d)", (UINTN)PhysAddr, Status);
        DbgEfiPrint((L"!!! ERROR: Failed to prepare memory 0x%x (status = %d)\n", (UINTN)PhysAddr, Status));
        DbgEfiPressAnyKey();
        return Status;
    }
    pAllocatedMemory = (void*)(UINTN)PhysAddr;
    SetMem(pAllocatedMemory, Pages << 12, 0);
    *ppMemory = pAllocatedMemory;
    return Status;
}
EFI_STATUS
copy_into_boot_memory_region()
{
    LOG_INFO_FN(L"enter");
    UINTN BootMemoryRegions[] = { EFI_BOOT_MEMORY_REGIONS };
    UINTN BootMemoryRegionIndex = 0;
    UINT8* pMemoryRegion = NULL;
    EFI_STATUS Status = EFI_NOT_FOUND;
    for (BootMemoryRegionIndex = 0; BootMemoryRegionIndex < sizeof(BootMemoryRegions) / sizeof(BootMemoryRegions[1]);
         ++BootMemoryRegionIndex)
    {
        Status = PrepareMemory(BootMemoryRegions[BootMemoryRegionIndex], 1024, (void**)&pMemoryRegion);
        if (!EFI_ERROR(Status))
        {
            LOG_ERROR_FN(L"Copy into boot memory region: 0x%x", (UINTN)pMemoryRegion);
            DbgEfiPrint((L"Copy into boot memory region: 0x%x\n", (UINTN)pMemoryRegion));
            DbgEfiPressAnyKey();
            gBS->CopyMem(pMemoryRegion, (UINT8*) ADDRESS, 1024);
            break;
        }
        else
        {
            LOG_ERROR_FN(L"PrepareMemory() for boot memory region [%lu] failed with status = 0x%llX!", BootMemoryRegions[BootMemoryRegionIndex], Status);
        }
    }
    if (EFI_ERROR(Status))
    {
        LOG_ERROR_FN(L"Failed to copy into boot memory region, status = 0x%llX!", Status);
    }
    LOG_INFO_FN(L"leave");
    return Status;
}

该逻辑取自VeraCryptLib,但目前所有区域调用AllocatePages均返回EFI_NOT_FOUND错误,需解答:

  1. 问题可能原因是什么?
  2. 是否可以添加更多地址扩大区域列表?若可以,哪些地址可用于分配EfiMemoryMappedIO页?
  3. 是否有其他方式通过内存将数据从UEFI传递到OS?

问题解答

一、EFI_NOT_FOUND错误的可能原因

  • 目标地址已被占用:指定的内存区域可能已被UEFI固件、其他启动加载项或硬件预留使用,无法再以EfiMemoryMappedIO类型分配。
  • 内存类型不匹配:AllocatePages的AllocateAddress模式要求目标地址所在区域原本属于可分配的EfiMemoryMappedIO类型,若该区域实际是EfiBootServicesCode、EfiReserved等其他类型,分配会失败。
  • 页范围跨类型:即使做了页对齐,若目标地址对应的物理页范围跨越不同内存类型的区域,也会导致分配失败。
  • 固件权限限制:部分UEFI固件会限制特定内存区域的分配权限,即使地址看似空闲,也不允许用户代码修改其类型或分配。

二、是否可扩大区域列表及可选地址

可以扩大区域列表,需选择符合以下条件的地址:

  • 查询UEFI内存映射:调用gBS->GetMemoryMap获取系统内存映射,筛选类型为EfiMemoryMappedIO且状态为EfiFree的区域,这些是合法的可分配目标。
  • 传统空闲区域参考:
    • 低端内存:0x60000到0x9FFFF之间(避开BIOS数据区0x400-0x4FF、VGA显存0xA0000-0xBFFFF)
    • 高端内存:1MB到16MB之间未被硬件占用的区域,部分系统在0x100000-0x1000000区间存在空闲MMIO区域
  • 规避硬件冲突:避开显卡、PCI设备等硬件的MMIO范围,这类区域通常在内存映射中标记为EfiReserved或已占用的EfiMemoryMappedIO。

三、UEFI到OS的其他内存数据传递方式

  • EfiReserved类型内存:分配EfiReserved类型内存页,UEFI会保留该区域不被OS回收,Windows驱动可通过物理地址映射访问。
  • UEFI配置表:将数据结构注册到UEFI配置表中,OS启动后可通过查询配置表获取数据指针,这是标准的UEFI数据传递方式。
  • ACPI表注入:自定义ACPI表并注入系统,Windows会解析ACPI表,驱动可从中读取预留的内存地址或数据。
  • 启动参数传递:修改UEFI启动项参数,将数据地址或内容作为参数传递给OS,OS启动后驱动可从启动参数中提取数据。

内容的提问来源于stack exchange,提问作者Wolf Team FC

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 09:11:53