Step to UEFI Shell (5)—-获得Shell下内存分配状况

在Shell下面可以使用 memmap 命令查看到当前的内存状况:

step51

UEFI下面没有了E820 Table。取而代之的是GetMemoryMap()。UEFI spec Version 2.4 中 P143有如下的描述,实际上是一个长得和E820很像的东西。

step52

在网上可以搜索到一个示例[参考1],原文是用Toolkit 写成的,经过一些改造成为可以直接在EDK2下面的编译的代码。

GetMap.c:

#include <Uefi.h>
#include <Library/PcdLib.h>
#include <Library/UefiLib.h>
#include <Library/UefiApplicationEntryPoint.h>

#define PAGE_SIZE 4096 

const CHAR16 *memory_types[] = { 
    L"EfiReservedMemoryType", 
    L"EfiLoaderCode", 
    L"EfiLoaderData", 
    L"EfiBootServicesCode", 
    L"EfiBootServicesData", 
    L"EfiRuntimeServicesCode", 
    L"EfiRuntimeServicesData", 
    L"EfiConventionalMemory", 
    L"EfiUnusableMemory", 
    L"EfiACPIReclaimMemory", 
    L"EfiACPIMemoryNVS", 
    L"EfiMemoryMappedIO", 
    L"EfiMemoryMappedIOPortSpace", 
    L"EfiPalCode", 
    L"EfiMaxMemoryType"
}; 

EFI_BOOT_SERVICES *gBS;  
const CHAR16 * 
memory_type_to_str(UINT32 type) 
{ 
    if (type > sizeof(memory_types)/sizeof(CHAR16 *)) 
        return L"Unknown"; 

    return memory_types[type]; 
} 

EFI_STATUS 
memory_map(EFI_MEMORY_DESCRIPTOR **map_buf, UINTN *map_size, 
           UINTN *map_key, UINTN *desc_size, UINT32 *desc_version) 
{ 
    EFI_STATUS err = EFI_SUCCESS; 

    *map_size = sizeof(**map_buf) * 31; 

get_map: 
    *map_size += sizeof(**map_buf); 

    err = gBS->AllocatePool(EfiLoaderData, *map_size, (void **)map_buf); 
    if (err != EFI_SUCCESS) { 
        Print(L"ERROR: Failed to allocate pool for memory map"); 
        return err; 
    } 

    err = gBS->GetMemoryMap(map_size, *map_buf, map_key, desc_size, desc_version); 
    if (err != EFI_SUCCESS) { 
        if (err == EFI_BUFFER_TOO_SMALL) { 
            gBS->FreePool((void *)*map_buf); 
            goto get_map; 
        } 
        Print(L"ERROR: Failed to get memory map"); 
    } 
    return err; 
} 

GetMap.inf

[Defines]
  INF_VERSION                    = 0x00010005
  BASE_NAME                      = GetMap
  FILE_GUID                      = 6987936E-ED34-44db-AE97-1FA5E4ED2318
  MODULE_TYPE                    = UEFI_APPLICATION
  VERSION_STRING                 = 1.0
  ENTRY_POINT                    = UefiMain

#
# The following information is for reference only and not required by the build tools.
#
#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC
#

[Sources]
  GetMap.c

[Packages]
  MdePkg/MdePkg.dec
  ShellPkg/ShellPkg.dec
  MdeModulePkg/MdeModulePkg.dec

[LibraryClasses]
  UefiApplicationEntryPoint
  UefiLib
  PcdLib
  ShellCEntryLib
  ShellLib

[FeaturePcd]
  gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintEnable

[Pcd]
  gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintString || gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintEnable  ## Valid when gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintEnable
  gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintTimes  || gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintEnable  ## Valid when gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintEnable

EFI_STATUS  
print_memory_map(void) 
{ 
    EFI_MEMORY_DESCRIPTOR *buf; 
    UINTN desc_size; 
    UINT32 desc_version; 
    UINTN size, map_key, mapping_size; 
    EFI_MEMORY_DESCRIPTOR *desc; 
    EFI_STATUS err = EFI_SUCCESS; 
    int i = 0; 

    err = memory_map(&buf, &size, &map_key, &desc_size, &desc_version); 
    if (err != EFI_SUCCESS) 
        return err; 

    Print(L"Memory Map Size: %d\n", size); 
    Print(L"Map Key: %d\n", map_key); 
    Print(L"Descriptor Version: %d\n", desc_version); 
    Print(L"Descriptor Size: %d\n\n", desc_size); 
    Print(L"Descriptor Size: %d\n\n", sizeof(EFI_MEMORY_DESCRIPTOR)); 

    desc = buf; 
    while ((UINT8 *)desc <  (UINT8 *)buf + size) { 
        mapping_size =(UINTN) desc->NumberOfPages * PAGE_SIZE; 

        Print(L"[#%02d] Type: %s  Attr: 0x%x\n", i, memory_type_to_str(desc->Type), desc->Attribute); 
        Print(L"      Phys: %016llx-%016llx\n", desc->PhysicalStart, desc->PhysicalStart + mapping_size -1 ); 

        desc = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)desc + desc_size); 
        i++; 
    } 

    gBS->FreePool (buf); 
    return err; 
} 

EFI_STATUS 
EFIAPI
UefiMain(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab) 
{ 

    print_memory_map(); 

    return EFI_SUCCESS; 
}

 

运行结果如下:

step53

我们使用 GetMap >> result.txt 得到完整的输出结果如下:

Memory Map Size: 960
Map Key: 2841
Descriptor Version: 1
Descriptor Size: 48

Descriptor Size: 40

[#00] Type: EfiBootServicesData Attr: 0xF
Phys: 0000000000CB0000-0000000000CCFFFF
[#01] Type: EfiConventionalMemory Attr: 0xF
Phys: 0000000000CD0000-000000000383FFFF
[#02] Type: EfiLoaderData Attr: 0xF
Phys: 0000000003840000-0000000003841FFF
[#03] Type: EfiLoaderCode Attr: 0xF
Phys: 0000000003842000-0000000003848FFF
[#04] Type: EfiLoaderData Attr: 0xF
Phys: 0000000003849000-000000000385EFFF
[#05] Type: EfiLoaderCode Attr: 0xF
Phys: 000000000385F000-00000000038ABFFF
[#06] Type: EfiConventionalMemory Attr: 0xF
Phys: 00000000038AC000-0000000003B09FFF
[#07] Type: EfiBootServicesData Attr: 0xF
Phys: 0000000003B0A000-0000000003B56FFF
[#08] Type: EfiConventionalMemory Attr: 0xF
Phys: 0000000003B57000-0000000003B74FFF
[#09] Type: EfiBootServicesData Attr: 0xF
Phys: 0000000003B75000-0000000003B75FFF
[#10] Type: EfiConventionalMemory Attr: 0xF
Phys: 0000000003B76000-0000000003B76FFF
[#11] Type: EfiBootServicesData Attr: 0xF
Phys: 0000000003B77000-00000000048ABFFF
[#12] Type: EfiConventionalMemory Attr: 0xF
Phys: 00000000048AC000-0000000004990FFF
[#13] Type: EfiBootServicesCode Attr: 0xF
Phys: 0000000004991000-0000000004BABFFF
[#14] Type: EfiRuntimeServicesData Attr: 0xF
Phys: 0000000004BAC000-0000000004BEBFFF
[#15] Type: EfiRuntimeServicesCode Attr: 0xF
Phys: 0000000004BEC000-0000000004C2BFFF
[#16] Type: EfiReservedMemoryType Attr: 0xF
Phys: 0000000004C2C000-0000000004C2FFFF
[#17] Type: EfiBootServicesData Attr: 0xF
Phys: 0000000004C30000-0000000004CAFFFF
[#18] Type: EfiConventionalMemory Attr: 0xF
Phys: 0000000004CB0000-0000000008CAFFFF
[#19] Type: EfiMemoryMappedIO Attr: 0x0
Phys: 0000000000BE0000-0000000000BEBFFF

和直接使用memmap取得的结果相同。需要注意的是:

1. 返回的Descriptor Size 并不是 sizeof(EFI_MEMORY_DESCRIPTOR)
2. 不知道EFI_VIRTUAL_ADDRESS VirtualStart; 是干什么用的

GetMap

参考:
1. http://blog.fpmurphy.com/2012/08/uefi-memory-v-e820-memory.html
可以在附件中找到该网页。它使用的是EFI_Toolkit 我没有编译过

发表评论

电子邮件地址不会被公开。 必填项已用*标注