UEFI返回内存映射与QEMU配置不符,是哪方问题?
问题分析与解决
一、内存映射获取代码存在逻辑错误
你的memory_map函数处理EFI_BUFFER_TOO_SMALL的方式不符合UEFI规范:
- UEFI明确规定,当
BS->GetMemoryMap()返回EFI_BUFFER_TOO_SMALL时,会自动将*map_size更新为所需的最小缓冲区大小,无需手动计算增量。 - 你当前每次仅增加单个描述符大小的逻辑,可能导致多次无效循环,甚至在某些场景下无法获取完整的内存映射。
修正后的代码如下:
static efi_status_t memory_map(efi_memory_descriptor_t **map_buf, uintn_t *map_size, uintn_t *desc_size) { *map_size = 0; // 初始设为0,让BIOS返回所需大小 efi_status_t ret; uintn_t key; uint32_t version; get_map: // 释放之前的缓冲区(首次循环时map_buf为NULL,FreePool会安全处理) if (*map_buf != NULL) { BS->FreePool((void*)*map_buf); *map_buf = NULL; } ret = BS->AllocatePool(EfiLoaderData, *map_size, (void**)map_buf); if (ret != EFI_SUCCESS) { ST->ConOut->OutputString(ST->ConOut, L"ERROR: Failed to allocate pool for memory map\n\r"); return ret; } ret = BS->GetMemoryMap(map_size, *map_buf, &key, desc_size, &version); if (ret == EFI_BUFFER_TOO_SMALL) { goto get_map; } else if (ret != EFI_SUCCESS) { ST->ConOut->OutputString(ST->ConOut, L"ERROR: Failed to get memory map\n\r"); BS->FreePool((void*)*map_buf); *map_buf = NULL; } return ret; }
二、QEMU -m 100M的实际含义与统计误区
你看到的350M并非QEMU异常,而是对内存映射的统计逻辑有误:
-m 100M是分配给虚拟机的物理内存总容量,但UEFI固件(如OVMF)会占用一部分内存,同时还要为PCI设备、ACPI表、固件保留区等预留空间。- 你大概率是累加了所有类型的内存描述符大小,其中包含大量不可用区域:
EfiReservedMemoryType(固件保留内存)EfiMemoryMappedIO(设备IO内存)EfiACPIReclaimMemory(ACPI可回收内存)- 只有
EfiConventionalMemory才是可供引导程序/操作系统使用的常规内存,这部分大小才会接近你设置的100M(扣除固件占用后)。
三、验证与排查方法
- 遍历内存映射时,仅统计
EfiConventionalMemory类型的内存:
uint64_t total_conventional = 0; efi_memory_descriptor_t *desc = *map_buf; for (uintn_t i = 0; i < (*map_size / *desc_size); i++) { if (desc->Type == EfiConventionalMemory) { total_conventional += desc->NumberOfPages * EFI_PAGE_SIZE; } desc = (efi_memory_descriptor_t*)((uint8_t*)desc + *desc_size); } // 输出total_conventional,结果应接近100M(扣除固件占用部分)
- 检查OVMF固件配置:部分OVMF镜像默认启用了SMRAM等额外内存映射,可尝试使用精简版OVMF镜像测试。
内容的提问来源于stack exchange,提问作者Miazite
相关产品推荐
相关产品推荐

