Detecting Memory (x86): Difference between revisions

m
Added UEFI Memory Map code example
[unchecked revision][unchecked revision]
No edit summary
m (Added UEFI Memory Map code example)
Line 343:
 
== What about on UEFI? ==
On UEFI, you have 'BootServices->GetMemoryMap'. This function is easiersimilar to use then E820 and is the only solution on new UEFI machines. Basically, to use, first you call it once to get the size of the memory map. Then you allocate a buffer of that size, and then call again to get the map itself. ForWatch out, by allocating memory you could increase the size of the memory map. Considering that a new allocation can split a free memory area into two, you should add space for 2 additional memory descriptors. It returns an array of EFI_MEMORY_DESCRIPTORs. They have the following format (taken from GNU exampleEFI):
<source lang="c">
UINTN mapSize, mapKey, descSize, descVer = 0;
BS->GetMemoryMap(&mapSize, NULL, &mapKey, &descSize, (UINT32*)&descVer);
mapSize += 16 * sizeof(EFI_MEMORY_DESCRIPTOR);
QWORD memMap = (QWORD)AllocMem(mapSize);
BS->GetMemoryMap(&mapSize, (EFI_MEMORY_DESCRIPTOR*)memMap, &mapKey, &descSize, (UINT32*)&descVer);
</source>
It returns an array of EFI_MEMORY_DESCRIPTORs. They have the following format (taken from GNU EFI):
<source lang="c">
typedef struct {
UINT32 Type; // EFI_MEMORY_TYPE, Field size is 32 bits followed by 32 bit pad
UINT32 Pad;
EFI_PHYSICAL_ADDRESS PhysicalStart; // Field size is 64 bits
Line 362 ⟶ 354:
} EFI_MEMORY_DESCRIPTOR;
</source>
To traverse them, you can use the NEXT_MEMORY_DESCRITOR macro.
TODO: Explain types, and go into more detail about it.
 
Memory types are different to the E820 codes. For converting, see [https://github.com/tianocore/edk2/blob/70d5086c3274b1a5b099d642d546581070374e6e/OvmfPkg/Csm/LegacyBiosDxe/LegacyBootSupport.c#L1601 CSM E820 compatibility].
<source lang="c">
typedef enum {
EfiReservedMemoryType,
EfiLoaderCode,
EfiLoaderData,
EfiBootServicesCode,
EfiBootServicesData,
EfiRuntimeServicesCode,
EfiRuntimeServicesData,
EfiConventionalMemory,
EfiUnusableMemory,
EfiACPIReclaimMemory,
EfiACPIMemoryNVS,
EfiMemoryMappedIO,
EfiMemoryMappedIOPortSpace,
EfiPalCode,
EfiPersistentMemory,
EfiMaxMemoryType
} EFI_MEMORY_TYPE;
</source>
 
==Code Examples==
Line 509 ⟶ 523:
}
}
</source>
 
===Getting an UEFI Memory Map===
<source lang="c">
EFI_STATUS Status;
EFI_MEMORY_DESCRIPTOR *EfiMemoryMap;
UINTN EfiMemoryMapSize;
UINTN EfiMapKey;
UINTN EfiDescriptorSize;
UINT32 EfiDescriptorVersion;
 
//
// Get the EFI memory map.
//
EfiMemoryMapSize = 0;
EfiMemoryMap = NULL;
Status = gBS->GetMemoryMap (
&EfiMemoryMapSize,
EfiMemoryMap,
&EfiMapKey,
&EfiDescriptorSize,
&EfiDescriptorVersion
);
ASSERT (Status == EFI_BUFFER_TOO_SMALL);
 
//
// Use size returned for the AllocatePool.
//
EfiMemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (EfiMemoryMapSize + 2 * EfiDescriptorSize);
ASSERT (EfiMemoryMap != NULL);
Status = gBS->GetMemoryMap (
&EfiMemoryMapSize,
EfiMemoryMap,
&EfiMapKey,
&EfiDescriptorSize,
&EfiDescriptorVersion
);
if (EFI_ERROR (Status)) {
FreePool (EfiMemoryMap);
}
 
//
// Get descriptors
//
EFI_MEMORY_DESCRIPTOR *EfiEntry = EfiMemoryMap;
do {
// ... do something with EfiEntry ...
EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
} while((UINT8*)EfiEntry < (UINT8*)EfiMemoryMap + EfiMemoryMapSize);
</source>
 
Anonymous user