diff --git a/OvmfPkg/IoMmuDxe/AmdSevIoMmu.c b/OvmfPkg/IoMmuDxe/AmdSevIoMmu.c index 452d5c4775..ec625166f4 100644 --- a/OvmfPkg/IoMmuDxe/AmdSevIoMmu.c +++ b/OvmfPkg/IoMmuDxe/AmdSevIoMmu.c @@ -20,7 +20,11 @@ #include "AmdSevIoMmu.h" +#define MAP_INFO_SIG SIGNATURE_64 ('M', 'A', 'P', '_', 'I', 'N', 'F', 'O') + typedef struct { + UINT64 Signature; + LIST_ENTRY Link; EDKII_IOMMU_OPERATION Operation; UINTN NumberOfBytes; UINTN NumberOfPages; @@ -28,6 +32,16 @@ typedef struct { EFI_PHYSICAL_ADDRESS PlainTextAddress; } MAP_INFO; +// +// List of MAP_INFO structures recycled by Unmap(). +// +// Recycled MAP_INFO structures are equally good for future recycling and +// freeing. +// +STATIC LIST_ENTRY mRecycledMapInfos = INITIALIZE_LIST_HEAD_VARIABLE ( + mRecycledMapInfos + ); + #define COMMON_BUFFER_SIG SIGNATURE_64 ('C', 'M', 'N', 'B', 'U', 'F', 'F', 'R') // @@ -96,6 +110,7 @@ IoMmuMap ( ) { EFI_STATUS Status; + LIST_ENTRY *RecycledMapInfo; MAP_INFO *MapInfo; EFI_ALLOCATE_TYPE AllocateType; COMMON_BUFFER_HEADER *CommonBufferHeader; @@ -110,15 +125,26 @@ IoMmuMap ( // Allocate a MAP_INFO structure to remember the mapping when Unmap() is // called later. // - MapInfo = AllocatePool (sizeof (MAP_INFO)); - if (MapInfo == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto Failed; + RecycledMapInfo = GetFirstNode (&mRecycledMapInfos); + if (RecycledMapInfo == &mRecycledMapInfos) { + // + // No recycled MAP_INFO structure, allocate a new one. + // + MapInfo = AllocatePool (sizeof (MAP_INFO)); + if (MapInfo == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Failed; + } + } else { + MapInfo = CR (RecycledMapInfo, MAP_INFO, Link, MAP_INFO_SIG); + RemoveEntryList (RecycledMapInfo); } // // Initialize the MAP_INFO structure, except the PlainTextAddress field // + ZeroMem (&MapInfo->Link, sizeof MapInfo->Link); + MapInfo->Signature = MAP_INFO_SIG; MapInfo->Operation = Operation; MapInfo->NumberOfBytes = *NumberOfBytes; MapInfo->NumberOfPages = EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes); @@ -387,18 +413,24 @@ IoMmuUnmap ( CommonBufferHeader->StashBuffer, MapInfo->NumberOfBytes ); + + // + // Recycle the MAP_INFO structure. + // + InsertTailList (&mRecycledMapInfos, &MapInfo->Link); } else { ZeroMem ( (VOID *)(UINTN)MapInfo->PlainTextAddress, EFI_PAGES_TO_SIZE (MapInfo->NumberOfPages) ); gBS->FreePages (MapInfo->PlainTextAddress, MapInfo->NumberOfPages); + + // + // Free the MAP_INFO structure. + // + FreePool (MapInfo); } - // - // Free the MAP_INFO structure. - // - FreePool (Mapping); return EFI_SUCCESS; }