3 The protocol provides support to allocate, free, map and umap a DMA buffer
4 for bus master (e.g PciHostBridge). When SEV or TDX is enabled, the DMA
5 operations must be performed on unencrypted buffer hence we use a bounce
6 buffer to map the guest buffer into an unencrypted DMA buffer.
8 Copyright (c) 2017, AMD Inc. All rights reserved.<BR>
9 Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
11 SPDX-License-Identifier: BSD-2-Clause-Patent
15 #include <Library/PcdLib.h>
16 #include <ConfidentialComputingGuestAttr.h>
17 #include "AmdSevIoMmu.h"
19 #define MAP_INFO_SIG SIGNATURE_64 ('M', 'A', 'P', '_', 'I', 'N', 'F', 'O')
24 EDKII_IOMMU_OPERATION Operation
;
27 EFI_PHYSICAL_ADDRESS CryptedAddress
;
28 EFI_PHYSICAL_ADDRESS PlainTextAddress
;
32 // List of the MAP_INFO structures that have been set up by IoMmuMap() and not
33 // yet torn down by IoMmuUnmap(). The list represents the full set of mappings
34 // currently in effect.
36 STATIC LIST_ENTRY mMapInfos
= INITIALIZE_LIST_HEAD_VARIABLE (mMapInfos
);
38 #define COMMON_BUFFER_SIG SIGNATURE_64 ('C', 'M', 'N', 'B', 'U', 'F', 'F', 'R')
41 // ASCII names for EDKII_IOMMU_OPERATION constants, for debug logging.
43 STATIC CONST CHAR8
*CONST
44 mBusMasterOperationName
[EdkiiIoMmuOperationMaximum
] = {
54 // The following structure enables Map() and Unmap() to perform in-place
55 // decryption and encryption, respectively, for BusMasterCommonBuffer[64]
56 // operations, without dynamic memory allocation or release.
58 // Both COMMON_BUFFER_HEADER and COMMON_BUFFER_HEADER.StashBuffer are allocated
59 // by AllocateBuffer() and released by FreeBuffer().
66 // Always allocated from EfiBootServicesData type memory, and always
72 // Followed by the actual common buffer, starting at the next page.
74 } COMMON_BUFFER_HEADER
;
78 Provides the controller-specific addresses required to access system memory
79 from a DMA bus master. On SEV/TDX guest, the DMA operations must be performed on
80 shared buffer hence we allocate a bounce buffer to map the HostAddress to a
81 DeviceAddress. The Encryption attribute is removed from the DeviceAddress
84 @param This The protocol instance pointer.
85 @param Operation Indicates if the bus master is going to read or
86 write to system memory.
87 @param HostAddress The system memory address to map to the PCI
89 @param NumberOfBytes On input the number of bytes to map. On output
90 the number of bytes that were mapped.
91 @param DeviceAddress The resulting map address for the bus master
92 PCI controller to use to access the hosts
94 @param Mapping A resulting value to pass to Unmap().
96 @retval EFI_SUCCESS The range was mapped for the returned
98 @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common
100 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
101 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
103 @retval EFI_DEVICE_ERROR The system hardware could not map the requested
110 IN EDKII_IOMMU_PROTOCOL
*This
,
111 IN EDKII_IOMMU_OPERATION Operation
,
112 IN VOID
*HostAddress
,
113 IN OUT UINTN
*NumberOfBytes
,
114 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
120 EFI_ALLOCATE_TYPE AllocateType
;
121 COMMON_BUFFER_HEADER
*CommonBufferHeader
;
122 VOID
*DecryptionSource
;
126 "%a: Operation=%a Host=0x%p Bytes=0x%Lx\n",
129 Operation
< ARRAY_SIZE (mBusMasterOperationName
)) ?
130 mBusMasterOperationName
[Operation
] :
133 (UINT64
)((NumberOfBytes
== NULL
) ? 0 : *NumberOfBytes
)
136 if ((HostAddress
== NULL
) || (NumberOfBytes
== NULL
) || (DeviceAddress
== NULL
) ||
139 return EFI_INVALID_PARAMETER
;
143 // Allocate a MAP_INFO structure to remember the mapping when Unmap() is
146 MapInfo
= AllocatePool (sizeof (MAP_INFO
));
147 if (MapInfo
== NULL
) {
148 Status
= EFI_OUT_OF_RESOURCES
;
153 // Initialize the MAP_INFO structure, except the PlainTextAddress field
155 ZeroMem (&MapInfo
->Link
, sizeof MapInfo
->Link
);
156 MapInfo
->Signature
= MAP_INFO_SIG
;
157 MapInfo
->Operation
= Operation
;
158 MapInfo
->NumberOfBytes
= *NumberOfBytes
;
159 MapInfo
->NumberOfPages
= EFI_SIZE_TO_PAGES (MapInfo
->NumberOfBytes
);
160 MapInfo
->CryptedAddress
= (UINTN
)HostAddress
;
163 // In the switch statement below, we point "MapInfo->PlainTextAddress" to the
164 // plaintext buffer, according to Operation. We also set "DecryptionSource".
166 MapInfo
->PlainTextAddress
= MAX_ADDRESS
;
167 AllocateType
= AllocateAnyPages
;
168 DecryptionSource
= (VOID
*)(UINTN
)MapInfo
->CryptedAddress
;
171 // For BusMasterRead[64] and BusMasterWrite[64] operations, a bounce buffer
172 // is necessary regardless of whether the original (crypted) buffer crosses
173 // the 4GB limit or not -- we have to allocate a separate plaintext buffer.
174 // The only variable is whether the plaintext buffer should be under 4GB.
176 case EdkiiIoMmuOperationBusMasterRead
:
177 case EdkiiIoMmuOperationBusMasterWrite
:
178 MapInfo
->PlainTextAddress
= BASE_4GB
- 1;
179 AllocateType
= AllocateMaxAddress
;
183 case EdkiiIoMmuOperationBusMasterRead64
:
184 case EdkiiIoMmuOperationBusMasterWrite64
:
186 // Allocate the implicit plaintext bounce buffer.
188 Status
= gBS
->AllocatePages (
191 MapInfo
->NumberOfPages
,
192 &MapInfo
->PlainTextAddress
194 if (EFI_ERROR (Status
)) {
201 // For BusMasterCommonBuffer[64] operations, a to-be-plaintext buffer and a
202 // stash buffer (for in-place decryption) have been allocated already, with
203 // AllocateBuffer(). We only check whether the address of the to-be-plaintext
204 // buffer is low enough for the requested operation.
206 case EdkiiIoMmuOperationBusMasterCommonBuffer
:
207 if ((MapInfo
->CryptedAddress
> BASE_4GB
) ||
208 (EFI_PAGES_TO_SIZE (MapInfo
->NumberOfPages
) >
209 BASE_4GB
- MapInfo
->CryptedAddress
))
212 // CommonBuffer operations cannot be remapped. If the common buffer is
213 // above 4GB, then it is not possible to generate a mapping, so return an
216 Status
= EFI_UNSUPPORTED
;
223 case EdkiiIoMmuOperationBusMasterCommonBuffer64
:
225 // The buffer at MapInfo->CryptedAddress comes from AllocateBuffer().
227 MapInfo
->PlainTextAddress
= MapInfo
->CryptedAddress
;
229 // Stash the crypted data.
231 CommonBufferHeader
= (COMMON_BUFFER_HEADER
*)(
232 (UINTN
)MapInfo
->CryptedAddress
- EFI_PAGE_SIZE
234 ASSERT (CommonBufferHeader
->Signature
== COMMON_BUFFER_SIG
);
236 CommonBufferHeader
->StashBuffer
,
237 (VOID
*)(UINTN
)MapInfo
->CryptedAddress
,
238 MapInfo
->NumberOfBytes
241 // Point "DecryptionSource" to the stash buffer so that we decrypt
242 // it to the original location, after the switch statement.
244 DecryptionSource
= CommonBufferHeader
->StashBuffer
;
249 // Operation is invalid
251 Status
= EFI_INVALID_PARAMETER
;
255 if (CC_GUEST_IS_SEV (PcdGet64 (PcdConfidentialComputingGuestAttr
))) {
257 // Clear the memory encryption mask on the plaintext buffer.
259 Status
= MemEncryptSevClearPageEncMask (
261 MapInfo
->PlainTextAddress
,
262 MapInfo
->NumberOfPages
264 } else if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr
))) {
266 // Set the memory shared bit.
268 Status
= MemEncryptTdxSetPageSharedBit (
270 MapInfo
->PlainTextAddress
,
271 MapInfo
->NumberOfPages
277 ASSERT_EFI_ERROR (Status
);
278 if (EFI_ERROR (Status
)) {
283 // If this is a read operation from the Bus Master's point of view,
284 // then copy the contents of the real buffer into the mapped buffer
285 // so the Bus Master can read the contents of the real buffer.
287 // For BusMasterCommonBuffer[64] operations, the CopyMem() below will decrypt
288 // the original data (from the stash buffer) back to the original location.
290 if ((Operation
== EdkiiIoMmuOperationBusMasterRead
) ||
291 (Operation
== EdkiiIoMmuOperationBusMasterRead64
) ||
292 (Operation
== EdkiiIoMmuOperationBusMasterCommonBuffer
) ||
293 (Operation
== EdkiiIoMmuOperationBusMasterCommonBuffer64
))
296 (VOID
*)(UINTN
)MapInfo
->PlainTextAddress
,
298 MapInfo
->NumberOfBytes
303 // Track all MAP_INFO structures.
305 InsertHeadList (&mMapInfos
, &MapInfo
->Link
);
307 // Populate output parameters.
309 *DeviceAddress
= MapInfo
->PlainTextAddress
;
314 "%a: Mapping=0x%p Device(PlainText)=0x%Lx Crypted=0x%Lx Pages=0x%Lx\n",
317 MapInfo
->PlainTextAddress
,
318 MapInfo
->CryptedAddress
,
319 (UINT64
)MapInfo
->NumberOfPages
333 Completes the Map() operation and releases any corresponding resources.
335 This is an internal worker function that only extends the Map() API with
336 the MemoryMapLocked parameter.
338 @param This The protocol instance pointer.
339 @param Mapping The mapping value returned from Map().
340 @param MemoryMapLocked The function is executing on the stack of
341 gBS->ExitBootServices(); changes to the UEFI
342 memory map are forbidden.
344 @retval EFI_SUCCESS The range was unmapped.
345 @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by
347 @retval EFI_DEVICE_ERROR The data was not committed to the target system
354 IN EDKII_IOMMU_PROTOCOL
*This
,
356 IN BOOLEAN MemoryMapLocked
361 COMMON_BUFFER_HEADER
*CommonBufferHeader
;
362 VOID
*EncryptionTarget
;
366 "%a: Mapping=0x%p MemoryMapLocked=%d\n",
372 if (Mapping
== NULL
) {
373 return EFI_INVALID_PARAMETER
;
376 MapInfo
= (MAP_INFO
*)Mapping
;
377 Status
= EFI_SUCCESS
;
379 // set CommonBufferHeader to suppress incorrect compiler/analyzer warnings
381 CommonBufferHeader
= NULL
;
384 // For BusMasterWrite[64] operations and BusMasterCommonBuffer[64] operations
385 // we have to encrypt the results, ultimately to the original place (i.e.,
386 // "MapInfo->CryptedAddress").
388 // For BusMasterCommonBuffer[64] operations however, this encryption has to
389 // land in-place, so divert the encryption to the stash buffer first.
391 EncryptionTarget
= (VOID
*)(UINTN
)MapInfo
->CryptedAddress
;
393 switch (MapInfo
->Operation
) {
394 case EdkiiIoMmuOperationBusMasterCommonBuffer
:
395 case EdkiiIoMmuOperationBusMasterCommonBuffer64
:
396 ASSERT (MapInfo
->PlainTextAddress
== MapInfo
->CryptedAddress
);
398 CommonBufferHeader
= (COMMON_BUFFER_HEADER
*)(
399 (UINTN
)MapInfo
->PlainTextAddress
- EFI_PAGE_SIZE
401 ASSERT (CommonBufferHeader
->Signature
== COMMON_BUFFER_SIG
);
402 EncryptionTarget
= CommonBufferHeader
->StashBuffer
;
407 case EdkiiIoMmuOperationBusMasterWrite
:
408 case EdkiiIoMmuOperationBusMasterWrite64
:
411 (VOID
*)(UINTN
)MapInfo
->PlainTextAddress
,
412 MapInfo
->NumberOfBytes
418 // nothing to encrypt after BusMasterRead[64] operations
423 if (CC_GUEST_IS_SEV (PcdGet64 (PcdConfidentialComputingGuestAttr
))) {
425 // Restore the memory encryption mask on the area we used to hold the
428 Status
= MemEncryptSevSetPageEncMask (
430 MapInfo
->PlainTextAddress
,
431 MapInfo
->NumberOfPages
433 } else if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr
))) {
435 // Restore the memory shared bit mask on the area we used to hold the
438 Status
= MemEncryptTdxClearPageSharedBit (
440 MapInfo
->PlainTextAddress
,
441 MapInfo
->NumberOfPages
447 ASSERT_EFI_ERROR (Status
);
448 if (EFI_ERROR (Status
)) {
453 // For BusMasterCommonBuffer[64] operations, copy the stashed data to the
454 // original (now encrypted) location.
456 // For all other operations, fill the late bounce buffer (which existed as
457 // plaintext at some point) with zeros, and then release it (unless the UEFI
458 // memory map is locked).
460 if ((MapInfo
->Operation
== EdkiiIoMmuOperationBusMasterCommonBuffer
) ||
461 (MapInfo
->Operation
== EdkiiIoMmuOperationBusMasterCommonBuffer64
))
464 (VOID
*)(UINTN
)MapInfo
->CryptedAddress
,
465 CommonBufferHeader
->StashBuffer
,
466 MapInfo
->NumberOfBytes
470 (VOID
*)(UINTN
)MapInfo
->PlainTextAddress
,
471 EFI_PAGES_TO_SIZE (MapInfo
->NumberOfPages
)
473 if (!MemoryMapLocked
) {
474 gBS
->FreePages (MapInfo
->PlainTextAddress
, MapInfo
->NumberOfPages
);
479 // Forget the MAP_INFO structure, then free it (unless the UEFI memory map is
482 RemoveEntryList (&MapInfo
->Link
);
483 if (!MemoryMapLocked
) {
491 Completes the Map() operation and releases any corresponding resources.
493 @param This The protocol instance pointer.
494 @param Mapping The mapping value returned from Map().
496 @retval EFI_SUCCESS The range was unmapped.
497 @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by
499 @retval EFI_DEVICE_ERROR The data was not committed to the target system
505 IN EDKII_IOMMU_PROTOCOL
*This
,
509 return IoMmuUnmapWorker (
512 FALSE
// MemoryMapLocked
517 Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
518 OperationBusMasterCommonBuffer64 mapping.
520 @param This The protocol instance pointer.
521 @param Type This parameter is not used and must be ignored.
522 @param MemoryType The type of memory to allocate,
523 EfiBootServicesData or EfiRuntimeServicesData.
524 @param Pages The number of pages to allocate.
525 @param HostAddress A pointer to store the base system memory
526 address of the allocated range.
527 @param Attributes The requested bit mask of attributes for the
530 @retval EFI_SUCCESS The requested memory pages were allocated.
531 @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal
532 attribute bits are MEMORY_WRITE_COMBINE and
534 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
535 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
540 IoMmuAllocateBuffer (
541 IN EDKII_IOMMU_PROTOCOL
*This
,
542 IN EFI_ALLOCATE_TYPE Type
,
543 IN EFI_MEMORY_TYPE MemoryType
,
545 IN OUT VOID
**HostAddress
,
550 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
552 UINTN CommonBufferPages
;
553 COMMON_BUFFER_HEADER
*CommonBufferHeader
;
557 "%a: MemoryType=%u Pages=0x%Lx Attributes=0x%Lx\n",
565 // Validate Attributes
567 if ((Attributes
& EDKII_IOMMU_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER
) != 0) {
568 return EFI_UNSUPPORTED
;
572 // Check for invalid inputs
574 if (HostAddress
== NULL
) {
575 return EFI_INVALID_PARAMETER
;
579 // The only valid memory types are EfiBootServicesData and
580 // EfiRuntimeServicesData
582 if ((MemoryType
!= EfiBootServicesData
) &&
583 (MemoryType
!= EfiRuntimeServicesData
))
585 return EFI_INVALID_PARAMETER
;
589 // We'll need a header page for the COMMON_BUFFER_HEADER structure.
591 if (Pages
> MAX_UINTN
- 1) {
592 return EFI_OUT_OF_RESOURCES
;
595 CommonBufferPages
= Pages
+ 1;
598 // Allocate the stash in EfiBootServicesData type memory.
600 // Map() will temporarily save encrypted data in the stash for
601 // BusMasterCommonBuffer[64] operations, so the data can be decrypted to the
602 // original location.
604 // Unmap() will temporarily save plaintext data in the stash for
605 // BusMasterCommonBuffer[64] operations, so the data can be encrypted to the
606 // original location.
608 // StashBuffer always resides in encrypted memory.
610 StashBuffer
= AllocatePages (Pages
);
611 if (StashBuffer
== NULL
) {
612 return EFI_OUT_OF_RESOURCES
;
615 PhysicalAddress
= (UINTN
)-1;
616 if ((Attributes
& EDKII_IOMMU_ATTRIBUTE_DUAL_ADDRESS_CYCLE
) == 0) {
618 // Limit allocations to memory below 4GB
620 PhysicalAddress
= SIZE_4GB
- 1;
623 Status
= gBS
->AllocatePages (
629 if (EFI_ERROR (Status
)) {
630 goto FreeStashBuffer
;
633 CommonBufferHeader
= (VOID
*)(UINTN
)PhysicalAddress
;
634 PhysicalAddress
+= EFI_PAGE_SIZE
;
636 CommonBufferHeader
->Signature
= COMMON_BUFFER_SIG
;
637 CommonBufferHeader
->StashBuffer
= StashBuffer
;
639 *HostAddress
= (VOID
*)(UINTN
)PhysicalAddress
;
643 "%a: Host=0x%Lx Stash=0x%p\n",
651 FreePages (StashBuffer
, Pages
);
656 Frees memory that was allocated with AllocateBuffer().
658 @param This The protocol instance pointer.
659 @param Pages The number of pages to free.
660 @param HostAddress The base system memory address of the allocated
663 @retval EFI_SUCCESS The requested memory pages were freed.
664 @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and
665 Pages was not allocated with AllocateBuffer().
671 IN EDKII_IOMMU_PROTOCOL
*This
,
676 UINTN CommonBufferPages
;
677 COMMON_BUFFER_HEADER
*CommonBufferHeader
;
681 "%a: Host=0x%p Pages=0x%Lx\n",
687 CommonBufferPages
= Pages
+ 1;
688 CommonBufferHeader
= (COMMON_BUFFER_HEADER
*)(
689 (UINTN
)HostAddress
- EFI_PAGE_SIZE
693 // Check the signature.
695 ASSERT (CommonBufferHeader
->Signature
== COMMON_BUFFER_SIG
);
696 if (CommonBufferHeader
->Signature
!= COMMON_BUFFER_SIG
) {
697 return EFI_INVALID_PARAMETER
;
701 // Free the stash buffer. This buffer was always encrypted, so no need to
704 FreePages (CommonBufferHeader
->StashBuffer
, Pages
);
707 // Release the common buffer itself. Unmap() has re-encrypted it in-place, so
708 // no need to zero it.
710 return gBS
->FreePages ((UINTN
)CommonBufferHeader
, CommonBufferPages
);
714 Set IOMMU attribute for a system memory.
716 If the IOMMU protocol exists, the system memory cannot be used
719 When a device requests a DMA access for a system memory,
720 the device driver need use SetAttribute() to update the IOMMU
721 attribute to request DMA access (read and/or write).
723 The DeviceHandle is used to identify which device submits the request.
724 The IOMMU implementation need translate the device path to an IOMMU device
725 ID, and set IOMMU hardware register accordingly.
726 1) DeviceHandle can be a standard PCI device.
727 The memory for BusMasterRead need set EDKII_IOMMU_ACCESS_READ.
728 The memory for BusMasterWrite need set EDKII_IOMMU_ACCESS_WRITE.
729 The memory for BusMasterCommonBuffer need set
730 EDKII_IOMMU_ACCESS_READ|EDKII_IOMMU_ACCESS_WRITE.
731 After the memory is used, the memory need set 0 to keep it being
733 2) DeviceHandle can be an ACPI device (ISA, I2C, SPI, etc).
734 The memory for DMA access need set EDKII_IOMMU_ACCESS_READ and/or
735 EDKII_IOMMU_ACCESS_WRITE.
737 @param[in] This The protocol instance pointer.
738 @param[in] DeviceHandle The device who initiates the DMA access
740 @param[in] Mapping The mapping value returned from Map().
741 @param[in] IoMmuAccess The IOMMU access.
743 @retval EFI_SUCCESS The IoMmuAccess is set for the memory range
744 specified by DeviceAddress and Length.
745 @retval EFI_INVALID_PARAMETER DeviceHandle is an invalid handle.
746 @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by
748 @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination
750 @retval EFI_UNSUPPORTED DeviceHandle is unknown by the IOMMU.
751 @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not supported
753 @retval EFI_UNSUPPORTED The IOMMU does not support the memory range
754 specified by Mapping.
755 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to
756 modify the IOMMU access.
757 @retval EFI_DEVICE_ERROR The IOMMU device reported an error while
758 attempting the operation.
764 IN EDKII_IOMMU_PROTOCOL
*This
,
765 IN EFI_HANDLE DeviceHandle
,
767 IN UINT64 IoMmuAccess
770 return EFI_UNSUPPORTED
;
773 EDKII_IOMMU_PROTOCOL mIoMmu
= {
774 EDKII_IOMMU_PROTOCOL_REVISION
,
783 Notification function that is queued when gBS->ExitBootServices() signals the
784 EFI_EVENT_GROUP_EXIT_BOOT_SERVICES event group. This function signals another
785 event, received as Context, and returns.
787 Signaling an event in this context is safe. The UEFI spec allows
788 gBS->SignalEvent() to return EFI_SUCCESS only; EFI_OUT_OF_RESOURCES is not
789 listed, hence memory is not allocated. The edk2 implementation also does not
790 release memory (and we only have to care about the edk2 implementation
791 because EDKII_IOMMU_PROTOCOL is edk2-specific anyway).
793 @param[in] Event Event whose notification function is being invoked.
794 Event is permitted to request the queueing of this
795 function at TPL_CALLBACK or TPL_NOTIFY task
798 @param[in] EventToSignal Identifies the EFI_EVENT to signal. EventToSignal
799 is permitted to request the queueing of its
800 notification function only at TPL_CALLBACK level.
807 IN VOID
*EventToSignal
811 // (1) The NotifyFunctions of all the events in
812 // EFI_EVENT_GROUP_EXIT_BOOT_SERVICES will have been queued before
813 // IoMmuExitBoot() is entered.
815 // (2) IoMmuExitBoot() is executing minimally at TPL_CALLBACK.
817 // (3) IoMmuExitBoot() has been queued in unspecified order relative to the
818 // NotifyFunctions of all the other events in
819 // EFI_EVENT_GROUP_EXIT_BOOT_SERVICES whose NotifyTpl is the same as
824 // - If Event's NotifyTpl is TPL_CALLBACK, then some other NotifyFunctions
825 // queued at TPL_CALLBACK may be invoked after IoMmuExitBoot() returns.
827 // - If Event's NotifyTpl is TPL_NOTIFY, then some other NotifyFunctions
828 // queued at TPL_NOTIFY may be invoked after IoMmuExitBoot() returns; plus
829 // *all* NotifyFunctions queued at TPL_CALLBACK will be invoked strictly
830 // after all NotifyFunctions queued at TPL_NOTIFY, including
831 // IoMmuExitBoot(), have been invoked.
833 // - By signaling EventToSignal here, whose NotifyTpl is TPL_CALLBACK, we
834 // queue EventToSignal's NotifyFunction after the NotifyFunctions of *all*
835 // events in EFI_EVENT_GROUP_EXIT_BOOT_SERVICES.
837 DEBUG ((DEBUG_VERBOSE
, "%a\n", __FUNCTION__
));
838 gBS
->SignalEvent (EventToSignal
);
842 Notification function that is queued after the notification functions of all
843 events in the EFI_EVENT_GROUP_EXIT_BOOT_SERVICES event group. The same memory
844 map restrictions apply.
846 This function unmaps all currently existing IOMMU mappings.
848 @param[in] Event Event whose notification function is being invoked. Event
849 is permitted to request the queueing of this function
850 only at TPL_CALLBACK task priority level.
852 @param[in] Context Ignored.
857 IoMmuUnmapAllMappings (
863 LIST_ENTRY
*NextNode
;
866 DEBUG ((DEBUG_VERBOSE
, "%a\n", __FUNCTION__
));
869 // All drivers that had set up IOMMU mappings have halted their respective
870 // controllers by now; tear down the mappings.
872 for (Node
= GetFirstNode (&mMapInfos
); Node
!= &mMapInfos
; Node
= NextNode
) {
873 NextNode
= GetNextNode (&mMapInfos
, Node
);
874 MapInfo
= CR (Node
, MAP_INFO
, Link
, MAP_INFO_SIG
);
878 TRUE
// MemoryMapLocked
884 Initialize Iommu Protocol.
889 InstallIoMmuProtocol (
894 EFI_EVENT UnmapAllMappingsEvent
;
895 EFI_EVENT ExitBootEvent
;
899 // Create the "late" event whose notification function will tear down all
900 // left-over IOMMU mappings.
902 Status
= gBS
->CreateEvent (
903 EVT_NOTIFY_SIGNAL
, // Type
904 TPL_CALLBACK
, // NotifyTpl
905 IoMmuUnmapAllMappings
, // NotifyFunction
906 NULL
, // NotifyContext
907 &UnmapAllMappingsEvent
// Event
909 if (EFI_ERROR (Status
)) {
914 // Create the event whose notification function will be queued by
915 // gBS->ExitBootServices() and will signal the event created above.
917 Status
= gBS
->CreateEvent (
918 EVT_SIGNAL_EXIT_BOOT_SERVICES
, // Type
919 TPL_CALLBACK
, // NotifyTpl
920 IoMmuExitBoot
, // NotifyFunction
921 UnmapAllMappingsEvent
, // NotifyContext
922 &ExitBootEvent
// Event
924 if (EFI_ERROR (Status
)) {
925 goto CloseUnmapAllMappingsEvent
;
929 Status
= gBS
->InstallMultipleProtocolInterfaces (
931 &gEdkiiIoMmuProtocolGuid
,
935 if (EFI_ERROR (Status
)) {
936 goto CloseExitBootEvent
;
942 gBS
->CloseEvent (ExitBootEvent
);
944 CloseUnmapAllMappingsEvent
:
945 gBS
->CloseEvent (UnmapAllMappingsEvent
);