X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=OvmfPkg%2FIoMmuDxe%2FAmdSevIoMmu.c;h=49ffa24488110f9b41987058b8fe59b437d7f0d5;hb=b26f0cf9ee09a180c91a4beeeb1b149e7f92afed;hp=0a85ee6559e799a1b8cb1a4c235f86239da7a281;hpb=e130229c0aea069f44fc942e585733b435680a35;p=mirror_edk2.git diff --git a/OvmfPkg/IoMmuDxe/AmdSevIoMmu.c b/OvmfPkg/IoMmuDxe/AmdSevIoMmu.c index 0a85ee6559..49ffa24488 100644 --- a/OvmfPkg/IoMmuDxe/AmdSevIoMmu.c +++ b/OvmfPkg/IoMmuDxe/AmdSevIoMmu.c @@ -8,19 +8,17 @@ Copyright (c) 2017, AMD Inc. All rights reserved.
Copyright (c) 2017, Intel Corporation. All rights reserved.
- This program and the accompanying materials are licensed and made available - under the terms and conditions of the BSD License which accompanies this - distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + SPDX-License-Identifier: BSD-2-Clause-Patent **/ #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,7 +26,51 @@ typedef struct { EFI_PHYSICAL_ADDRESS PlainTextAddress; } MAP_INFO; -#define NO_MAPPING (VOID *) (UINTN) -1 +// +// List of the MAP_INFO structures that have been set up by IoMmuMap() and not +// yet torn down by IoMmuUnmap(). The list represents the full set of mappings +// currently in effect. +// +STATIC LIST_ENTRY mMapInfos = INITIALIZE_LIST_HEAD_VARIABLE (mMapInfos); + +#define COMMON_BUFFER_SIG SIGNATURE_64 ('C', 'M', 'N', 'B', 'U', 'F', 'F', 'R') + +// +// ASCII names for EDKII_IOMMU_OPERATION constants, for debug logging. +// +STATIC CONST CHAR8 * CONST +mBusMasterOperationName[EdkiiIoMmuOperationMaximum] = { + "Read", + "Write", + "CommonBuffer", + "Read64", + "Write64", + "CommonBuffer64" +}; + +// +// The following structure enables Map() and Unmap() to perform in-place +// decryption and encryption, respectively, for BusMasterCommonBuffer[64] +// operations, without dynamic memory allocation or release. +// +// Both COMMON_BUFFER_HEADER and COMMON_BUFFER_HEADER.StashBuffer are allocated +// by AllocateBuffer() and released by FreeBuffer(). +// +#pragma pack (1) +typedef struct { + UINT64 Signature; + + // + // Always allocated from EfiBootServicesData type memory, and always + // encrypted. + // + VOID *StashBuffer; + + // + // Followed by the actual common buffer, starting at the next page. + // +} COMMON_BUFFER_HEADER; +#pragma pack () /** Provides the controller-specific addresses required to access system memory @@ -74,6 +116,20 @@ IoMmuMap ( EFI_STATUS Status; MAP_INFO *MapInfo; EFI_ALLOCATE_TYPE AllocateType; + COMMON_BUFFER_HEADER *CommonBufferHeader; + VOID *DecryptionSource; + + DEBUG (( + DEBUG_VERBOSE, + "%a: Operation=%a Host=0x%p Bytes=0x%Lx\n", + __FUNCTION__, + ((Operation >= 0 && + Operation < ARRAY_SIZE (mBusMasterOperationName)) ? + mBusMasterOperationName[Operation] : + "Invalid"), + HostAddress, + (UINT64)((NumberOfBytes == NULL) ? 0 : *NumberOfBytes) + )); if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress == NULL || Mapping == NULL) { @@ -93,6 +149,8 @@ IoMmuMap ( // // 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); @@ -100,10 +158,11 @@ IoMmuMap ( // // In the switch statement below, we point "MapInfo->PlainTextAddress" to the - // plaintext buffer, according to Operation. + // plaintext buffer, according to Operation. We also set "DecryptionSource". // MapInfo->PlainTextAddress = MAX_ADDRESS; AllocateType = AllocateAnyPages; + DecryptionSource = (VOID *)(UINTN)MapInfo->CryptedAddress; switch (Operation) { // // For BusMasterRead[64] and BusMasterWrite[64] operations, a bounce buffer @@ -135,9 +194,10 @@ IoMmuMap ( break; // - // For BusMasterCommonBuffer[64] operations, a plaintext buffer has been - // allocated already, with AllocateBuffer(). We only check whether the - // address is low enough for the requested operation. + // For BusMasterCommonBuffer[64] operations, a to-be-plaintext buffer and a + // stash buffer (for in-place decryption) have been allocated already, with + // AllocateBuffer(). We only check whether the address of the to-be-plaintext + // buffer is low enough for the requested operation. // case EdkiiIoMmuOperationBusMasterCommonBuffer: if ((MapInfo->CryptedAddress > BASE_4GB) || @@ -156,18 +216,27 @@ IoMmuMap ( // case EdkiiIoMmuOperationBusMasterCommonBuffer64: // - // The buffer at MapInfo->CryptedAddress comes from AllocateBuffer(), - // and it is already decrypted. + // The buffer at MapInfo->CryptedAddress comes from AllocateBuffer(). // MapInfo->PlainTextAddress = MapInfo->CryptedAddress; - // - // Therefore no mapping is necessary. + // Stash the crypted data. // - *DeviceAddress = MapInfo->PlainTextAddress; - *Mapping = NO_MAPPING; - FreePool (MapInfo); - return EFI_SUCCESS; + CommonBufferHeader = (COMMON_BUFFER_HEADER *)( + (UINTN)MapInfo->CryptedAddress - EFI_PAGE_SIZE + ); + ASSERT (CommonBufferHeader->Signature == COMMON_BUFFER_SIG); + CopyMem ( + CommonBufferHeader->StashBuffer, + (VOID *)(UINTN)MapInfo->CryptedAddress, + MapInfo->NumberOfBytes + ); + // + // Point "DecryptionSource" to the stash buffer so that we decrypt + // it to the original location, after the switch statement. + // + DecryptionSource = CommonBufferHeader->StashBuffer; + break; default: // @@ -186,22 +255,34 @@ IoMmuMap ( MapInfo->NumberOfPages, TRUE ); - ASSERT_EFI_ERROR(Status); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + CpuDeadLoop (); + } // // If this is a read operation from the Bus Master's point of view, // then copy the contents of the real buffer into the mapped buffer // so the Bus Master can read the contents of the real buffer. // + // For BusMasterCommonBuffer[64] operations, the CopyMem() below will decrypt + // the original data (from the stash buffer) back to the original location. + // if (Operation == EdkiiIoMmuOperationBusMasterRead || - Operation == EdkiiIoMmuOperationBusMasterRead64) { + Operation == EdkiiIoMmuOperationBusMasterRead64 || + Operation == EdkiiIoMmuOperationBusMasterCommonBuffer || + Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64) { CopyMem ( (VOID *) (UINTN) MapInfo->PlainTextAddress, - (VOID *) (UINTN) MapInfo->CryptedAddress, + DecryptionSource, MapInfo->NumberOfBytes ); } + // + // Track all MAP_INFO structures. + // + InsertHeadList (&mMapInfos, &MapInfo->Link); // // Populate output parameters. // @@ -210,12 +291,12 @@ IoMmuMap ( DEBUG (( DEBUG_VERBOSE, - "%a PlainText 0x%Lx Crypted 0x%Lx Pages 0x%Lx Bytes 0x%Lx\n", + "%a: Mapping=0x%p Device(PlainText)=0x%Lx Crypted=0x%Lx Pages=0x%Lx\n", __FUNCTION__, + MapInfo, MapInfo->PlainTextAddress, MapInfo->CryptedAddress, - (UINT64)MapInfo->NumberOfPages, - (UINT64)MapInfo->NumberOfBytes + (UINT64)MapInfo->NumberOfPages )); return EFI_SUCCESS; @@ -231,8 +312,14 @@ Failed: /** Completes the Map() operation and releases any corresponding resources. + This is an internal worker function that only extends the Map() API with + the MemoryMapLocked parameter. + @param This The protocol instance pointer. @param Mapping The mapping value returned from Map(). + @param MemoryMapLocked The function is executing on the stack of + gBS->ExitBootServices(); changes to the UEFI + memory map are forbidden. @retval EFI_SUCCESS The range was unmapped. @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by @@ -240,56 +327,82 @@ Failed: @retval EFI_DEVICE_ERROR The data was not committed to the target system memory. **/ +STATIC EFI_STATUS EFIAPI -IoMmuUnmap ( +IoMmuUnmapWorker ( IN EDKII_IOMMU_PROTOCOL *This, - IN VOID *Mapping + IN VOID *Mapping, + IN BOOLEAN MemoryMapLocked ) { MAP_INFO *MapInfo; EFI_STATUS Status; + COMMON_BUFFER_HEADER *CommonBufferHeader; + VOID *EncryptionTarget; + + DEBUG (( + DEBUG_VERBOSE, + "%a: Mapping=0x%p MemoryMapLocked=%d\n", + __FUNCTION__, + Mapping, + MemoryMapLocked + )); if (Mapping == NULL) { return EFI_INVALID_PARAMETER; } + MapInfo = (MAP_INFO *)Mapping; + // - // See if the Map() operation associated with this Unmap() required a mapping - // buffer. If a mapping buffer was not required, then this function simply - // buffer. If a mapping buffer was not required, then this function simply + // set CommonBufferHeader to suppress incorrect compiler/analyzer warnings // - if (Mapping == NO_MAPPING) { - return EFI_SUCCESS; - } - - MapInfo = (MAP_INFO *)Mapping; + CommonBufferHeader = NULL; // - // If this is a write operation from the Bus Master's point of view, - // then copy the contents of the mapped buffer into the real buffer - // so the processor can read the contents of the real buffer. + // For BusMasterWrite[64] operations and BusMasterCommonBuffer[64] operations + // we have to encrypt the results, ultimately to the original place (i.e., + // "MapInfo->CryptedAddress"). + // + // For BusMasterCommonBuffer[64] operations however, this encryption has to + // land in-place, so divert the encryption to the stash buffer first. // - if (MapInfo->Operation == EdkiiIoMmuOperationBusMasterWrite || - MapInfo->Operation == EdkiiIoMmuOperationBusMasterWrite64) { + EncryptionTarget = (VOID *)(UINTN)MapInfo->CryptedAddress; + + switch (MapInfo->Operation) { + case EdkiiIoMmuOperationBusMasterCommonBuffer: + case EdkiiIoMmuOperationBusMasterCommonBuffer64: + ASSERT (MapInfo->PlainTextAddress == MapInfo->CryptedAddress); + + CommonBufferHeader = (COMMON_BUFFER_HEADER *)( + (UINTN)MapInfo->PlainTextAddress - EFI_PAGE_SIZE + ); + ASSERT (CommonBufferHeader->Signature == COMMON_BUFFER_SIG); + EncryptionTarget = CommonBufferHeader->StashBuffer; + // + // fall through + // + + case EdkiiIoMmuOperationBusMasterWrite: + case EdkiiIoMmuOperationBusMasterWrite64: CopyMem ( - (VOID *) (UINTN) MapInfo->CryptedAddress, + EncryptionTarget, (VOID *) (UINTN) MapInfo->PlainTextAddress, MapInfo->NumberOfBytes ); + break; + + default: + // + // nothing to encrypt after BusMasterRead[64] operations + // + break; } - DEBUG (( - DEBUG_VERBOSE, - "%a PlainText 0x%Lx Crypted 0x%Lx Pages 0x%Lx Bytes 0x%Lx\n", - __FUNCTION__, - MapInfo->PlainTextAddress, - MapInfo->CryptedAddress, - (UINT64)MapInfo->NumberOfPages, - (UINT64)MapInfo->NumberOfBytes - )); // - // Restore the memory encryption mask + // Restore the memory encryption mask on the area we used to hold the + // plaintext. // Status = MemEncryptSevSetPageEncMask ( 0, @@ -297,20 +410,74 @@ IoMmuUnmap ( MapInfo->NumberOfPages, TRUE ); - ASSERT_EFI_ERROR(Status); - ZeroMem ( - (VOID*)(UINTN)MapInfo->PlainTextAddress, - EFI_PAGES_TO_SIZE (MapInfo->NumberOfPages) - ); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + CpuDeadLoop (); + } + + // + // For BusMasterCommonBuffer[64] operations, copy the stashed data to the + // original (now encrypted) location. + // + // For all other operations, fill the late bounce buffer (which existed as + // plaintext at some point) with zeros, and then release it (unless the UEFI + // memory map is locked). + // + if (MapInfo->Operation == EdkiiIoMmuOperationBusMasterCommonBuffer || + MapInfo->Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64) { + CopyMem ( + (VOID *)(UINTN)MapInfo->CryptedAddress, + CommonBufferHeader->StashBuffer, + MapInfo->NumberOfBytes + ); + } else { + ZeroMem ( + (VOID *)(UINTN)MapInfo->PlainTextAddress, + EFI_PAGES_TO_SIZE (MapInfo->NumberOfPages) + ); + if (!MemoryMapLocked) { + gBS->FreePages (MapInfo->PlainTextAddress, MapInfo->NumberOfPages); + } + } // - // Free the mapped buffer and the MAP_INFO structure. + // Forget the MAP_INFO structure, then free it (unless the UEFI memory map is + // locked). // - gBS->FreePages (MapInfo->PlainTextAddress, MapInfo->NumberOfPages); - FreePool (Mapping); + RemoveEntryList (&MapInfo->Link); + if (!MemoryMapLocked) { + FreePool (MapInfo); + } + return EFI_SUCCESS; } +/** + Completes the Map() operation and releases any corresponding resources. + + @param This The protocol instance pointer. + @param Mapping The mapping value returned from Map(). + + @retval EFI_SUCCESS The range was unmapped. + @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by + Map(). + @retval EFI_DEVICE_ERROR The data was not committed to the target system + memory. +**/ +EFI_STATUS +EFIAPI +IoMmuUnmap ( + IN EDKII_IOMMU_PROTOCOL *This, + IN VOID *Mapping + ) +{ + return IoMmuUnmapWorker ( + This, + Mapping, + FALSE // MemoryMapLocked + ); +} + /** Allocates pages that are suitable for an OperationBusMasterCommonBuffer or OperationBusMasterCommonBuffer64 mapping. @@ -346,6 +513,18 @@ IoMmuAllocateBuffer ( { EFI_STATUS Status; EFI_PHYSICAL_ADDRESS PhysicalAddress; + VOID *StashBuffer; + UINTN CommonBufferPages; + COMMON_BUFFER_HEADER *CommonBufferHeader; + + DEBUG (( + DEBUG_VERBOSE, + "%a: MemoryType=%u Pages=0x%Lx Attributes=0x%Lx\n", + __FUNCTION__, + (UINT32)MemoryType, + (UINT64)Pages, + Attributes + )); // // Validate Attributes @@ -370,6 +549,32 @@ IoMmuAllocateBuffer ( return EFI_INVALID_PARAMETER; } + // + // We'll need a header page for the COMMON_BUFFER_HEADER structure. + // + if (Pages > MAX_UINTN - 1) { + return EFI_OUT_OF_RESOURCES; + } + CommonBufferPages = Pages + 1; + + // + // Allocate the stash in EfiBootServicesData type memory. + // + // Map() will temporarily save encrypted data in the stash for + // BusMasterCommonBuffer[64] operations, so the data can be decrypted to the + // original location. + // + // Unmap() will temporarily save plaintext data in the stash for + // BusMasterCommonBuffer[64] operations, so the data can be encrypted to the + // original location. + // + // StashBuffer always resides in encrypted memory. + // + StashBuffer = AllocatePages (Pages); + if (StashBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + PhysicalAddress = (UINTN)-1; if ((Attributes & EDKII_IOMMU_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0) { // @@ -380,26 +585,32 @@ IoMmuAllocateBuffer ( Status = gBS->AllocatePages ( AllocateMaxAddress, MemoryType, - Pages, + CommonBufferPages, &PhysicalAddress ); - if (!EFI_ERROR (Status)) { - *HostAddress = (VOID *) (UINTN) PhysicalAddress; - - // - // Clear memory encryption mask - // - Status = MemEncryptSevClearPageEncMask (0, PhysicalAddress, Pages, TRUE); - ASSERT_EFI_ERROR(Status); + if (EFI_ERROR (Status)) { + goto FreeStashBuffer; } + CommonBufferHeader = (VOID *)(UINTN)PhysicalAddress; + PhysicalAddress += EFI_PAGE_SIZE; + + CommonBufferHeader->Signature = COMMON_BUFFER_SIG; + CommonBufferHeader->StashBuffer = StashBuffer; + + *HostAddress = (VOID *)(UINTN)PhysicalAddress; + DEBUG (( DEBUG_VERBOSE, - "%a Address 0x%Lx Pages 0x%Lx\n", + "%a: Host=0x%Lx Stash=0x%p\n", __FUNCTION__, PhysicalAddress, - (UINT64)Pages + StashBuffer )); + return EFI_SUCCESS; + +FreeStashBuffer: + FreePages (StashBuffer, Pages); return Status; } @@ -424,28 +635,41 @@ IoMmuFreeBuffer ( IN VOID *HostAddress ) { - EFI_STATUS Status; - - // - // Set memory encryption mask - // - Status = MemEncryptSevSetPageEncMask ( - 0, - (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress, - Pages, - TRUE - ); - ASSERT_EFI_ERROR(Status); - ZeroMem (HostAddress, EFI_PAGES_TO_SIZE (Pages)); + UINTN CommonBufferPages; + COMMON_BUFFER_HEADER *CommonBufferHeader; DEBUG (( DEBUG_VERBOSE, - "%a Address 0x%Lx Pages 0x%Lx\n", + "%a: Host=0x%p Pages=0x%Lx\n", __FUNCTION__, - (UINT64)(UINTN)HostAddress, + HostAddress, (UINT64)Pages )); - return gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress, Pages); + + CommonBufferPages = Pages + 1; + CommonBufferHeader = (COMMON_BUFFER_HEADER *)( + (UINTN)HostAddress - EFI_PAGE_SIZE + ); + + // + // Check the signature. + // + ASSERT (CommonBufferHeader->Signature == COMMON_BUFFER_SIG); + if (CommonBufferHeader->Signature != COMMON_BUFFER_SIG) { + return EFI_INVALID_PARAMETER; + } + + // + // Free the stash buffer. This buffer was always encrypted, so no need to + // zero it. + // + FreePages (CommonBufferHeader->StashBuffer, Pages); + + // + // Release the common buffer itself. Unmap() has re-encrypted it in-place, so + // no need to zero it. + // + return gBS->FreePages ((UINTN)CommonBufferHeader, CommonBufferPages); } @@ -518,6 +742,107 @@ EDKII_IOMMU_PROTOCOL mAmdSev = { IoMmuFreeBuffer, }; +/** + Notification function that is queued when gBS->ExitBootServices() signals the + EFI_EVENT_GROUP_EXIT_BOOT_SERVICES event group. This function signals another + event, received as Context, and returns. + + Signaling an event in this context is safe. The UEFI spec allows + gBS->SignalEvent() to return EFI_SUCCESS only; EFI_OUT_OF_RESOURCES is not + listed, hence memory is not allocated. The edk2 implementation also does not + release memory (and we only have to care about the edk2 implementation + because EDKII_IOMMU_PROTOCOL is edk2-specific anyway). + + @param[in] Event Event whose notification function is being invoked. + Event is permitted to request the queueing of this + function at TPL_CALLBACK or TPL_NOTIFY task + priority level. + + @param[in] EventToSignal Identifies the EFI_EVENT to signal. EventToSignal + is permitted to request the queueing of its + notification function only at TPL_CALLBACK level. +**/ +STATIC +VOID +EFIAPI +AmdSevExitBoot ( + IN EFI_EVENT Event, + IN VOID *EventToSignal + ) +{ + // + // (1) The NotifyFunctions of all the events in + // EFI_EVENT_GROUP_EXIT_BOOT_SERVICES will have been queued before + // AmdSevExitBoot() is entered. + // + // (2) AmdSevExitBoot() is executing minimally at TPL_CALLBACK. + // + // (3) AmdSevExitBoot() has been queued in unspecified order relative to the + // NotifyFunctions of all the other events in + // EFI_EVENT_GROUP_EXIT_BOOT_SERVICES whose NotifyTpl is the same as + // Event's. + // + // Consequences: + // + // - If Event's NotifyTpl is TPL_CALLBACK, then some other NotifyFunctions + // queued at TPL_CALLBACK may be invoked after AmdSevExitBoot() returns. + // + // - If Event's NotifyTpl is TPL_NOTIFY, then some other NotifyFunctions + // queued at TPL_NOTIFY may be invoked after AmdSevExitBoot() returns; plus + // *all* NotifyFunctions queued at TPL_CALLBACK will be invoked strictly + // after all NotifyFunctions queued at TPL_NOTIFY, including + // AmdSevExitBoot(), have been invoked. + // + // - By signaling EventToSignal here, whose NotifyTpl is TPL_CALLBACK, we + // queue EventToSignal's NotifyFunction after the NotifyFunctions of *all* + // events in EFI_EVENT_GROUP_EXIT_BOOT_SERVICES. + // + DEBUG ((DEBUG_VERBOSE, "%a\n", __FUNCTION__)); + gBS->SignalEvent (EventToSignal); +} + +/** + Notification function that is queued after the notification functions of all + events in the EFI_EVENT_GROUP_EXIT_BOOT_SERVICES event group. The same memory + map restrictions apply. + + This function unmaps all currently existing IOMMU mappings. + + @param[in] Event Event whose notification function is being invoked. Event + is permitted to request the queueing of this function + only at TPL_CALLBACK task priority level. + + @param[in] Context Ignored. +**/ +STATIC +VOID +EFIAPI +AmdSevUnmapAllMappings ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + LIST_ENTRY *Node; + LIST_ENTRY *NextNode; + MAP_INFO *MapInfo; + + DEBUG ((DEBUG_VERBOSE, "%a\n", __FUNCTION__)); + + // + // All drivers that had set up IOMMU mappings have halted their respective + // controllers by now; tear down the mappings. + // + for (Node = GetFirstNode (&mMapInfos); Node != &mMapInfos; Node = NextNode) { + NextNode = GetNextNode (&mMapInfos, Node); + MapInfo = CR (Node, MAP_INFO, Link, MAP_INFO_SIG); + IoMmuUnmapWorker ( + &mAmdSev, // This + MapInfo, // Mapping + TRUE // MemoryMapLocked + ); + } +} + /** Initialize Iommu Protocol. @@ -529,13 +854,57 @@ AmdSevInstallIoMmuProtocol ( ) { EFI_STATUS Status; + EFI_EVENT UnmapAllMappingsEvent; + EFI_EVENT ExitBootEvent; EFI_HANDLE Handle; + // + // Create the "late" event whose notification function will tear down all + // left-over IOMMU mappings. + // + Status = gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, // Type + TPL_CALLBACK, // NotifyTpl + AmdSevUnmapAllMappings, // NotifyFunction + NULL, // NotifyContext + &UnmapAllMappingsEvent // Event + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Create the event whose notification function will be queued by + // gBS->ExitBootServices() and will signal the event created above. + // + Status = gBS->CreateEvent ( + EVT_SIGNAL_EXIT_BOOT_SERVICES, // Type + TPL_CALLBACK, // NotifyTpl + AmdSevExitBoot, // NotifyFunction + UnmapAllMappingsEvent, // NotifyContext + &ExitBootEvent // Event + ); + if (EFI_ERROR (Status)) { + goto CloseUnmapAllMappingsEvent; + } + Handle = NULL; Status = gBS->InstallMultipleProtocolInterfaces ( &Handle, &gEdkiiIoMmuProtocolGuid, &mAmdSev, NULL ); + if (EFI_ERROR (Status)) { + goto CloseExitBootEvent; + } + + return EFI_SUCCESS; + +CloseExitBootEvent: + gBS->CloseEvent (ExitBootEvent); + +CloseUnmapAllMappingsEvent: + gBS->CloseEvent (UnmapAllMappingsEvent); + return Status; }