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>
18 #include "IoMmuInternal.h"
21 // List of the MAP_INFO structures that have been set up by IoMmuMap() and not
22 // yet torn down by IoMmuUnmap(). The list represents the full set of mappings
23 // currently in effect.
25 STATIC LIST_ENTRY mMapInfos
= INITIALIZE_LIST_HEAD_VARIABLE (mMapInfos
);
28 // Indicate if the feature of reserved memory is supported in DMA operation.
30 BOOLEAN mReservedSharedMemSupported
= FALSE
;
33 // ASCII names for EDKII_IOMMU_OPERATION constants, for debug logging.
35 STATIC CONST CHAR8
*CONST
36 mBusMasterOperationName
[EdkiiIoMmuOperationMaximum
] = {
46 Provides the controller-specific addresses required to access system memory
47 from a DMA bus master. On SEV/TDX guest, the DMA operations must be performed on
48 shared buffer hence we allocate a bounce buffer to map the HostAddress to a
49 DeviceAddress. The Encryption attribute is removed from the DeviceAddress
52 @param This The protocol instance pointer.
53 @param Operation Indicates if the bus master is going to read or
54 write to system memory.
55 @param HostAddress The system memory address to map to the PCI
57 @param NumberOfBytes On input the number of bytes to map. On output
58 the number of bytes that were mapped.
59 @param DeviceAddress The resulting map address for the bus master
60 PCI controller to use to access the hosts
62 @param Mapping A resulting value to pass to Unmap().
64 @retval EFI_SUCCESS The range was mapped for the returned
66 @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common
68 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
69 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
71 @retval EFI_DEVICE_ERROR The system hardware could not map the requested
78 IN EDKII_IOMMU_PROTOCOL
*This
,
79 IN EDKII_IOMMU_OPERATION Operation
,
81 IN OUT UINTN
*NumberOfBytes
,
82 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
88 EFI_ALLOCATE_TYPE AllocateType
;
89 COMMON_BUFFER_HEADER
*CommonBufferHeader
;
90 VOID
*DecryptionSource
;
94 "%a: Operation=%a Host=0x%p Bytes=0x%Lx\n",
97 Operation
< ARRAY_SIZE (mBusMasterOperationName
)) ?
98 mBusMasterOperationName
[Operation
] :
101 (UINT64
)((NumberOfBytes
== NULL
) ? 0 : *NumberOfBytes
)
104 if ((HostAddress
== NULL
) || (NumberOfBytes
== NULL
) || (DeviceAddress
== NULL
) ||
107 return EFI_INVALID_PARAMETER
;
110 Status
= EFI_SUCCESS
;
113 // Allocate a MAP_INFO structure to remember the mapping when Unmap() is
116 MapInfo
= AllocatePool (sizeof (MAP_INFO
));
117 if (MapInfo
== NULL
) {
118 Status
= EFI_OUT_OF_RESOURCES
;
123 // Initialize the MAP_INFO structure, except the PlainTextAddress field
125 ZeroMem (&MapInfo
->Link
, sizeof MapInfo
->Link
);
126 MapInfo
->Signature
= MAP_INFO_SIG
;
127 MapInfo
->Operation
= Operation
;
128 MapInfo
->NumberOfBytes
= *NumberOfBytes
;
129 MapInfo
->NumberOfPages
= EFI_SIZE_TO_PAGES (MapInfo
->NumberOfBytes
);
130 MapInfo
->CryptedAddress
= (UINTN
)HostAddress
;
131 MapInfo
->ReservedMemBitmap
= 0;
134 // In the switch statement below, we point "MapInfo->PlainTextAddress" to the
135 // plaintext buffer, according to Operation. We also set "DecryptionSource".
137 MapInfo
->PlainTextAddress
= MAX_ADDRESS
;
138 AllocateType
= AllocateAnyPages
;
139 DecryptionSource
= (VOID
*)(UINTN
)MapInfo
->CryptedAddress
;
142 // For BusMasterRead[64] and BusMasterWrite[64] operations, a bounce buffer
143 // is necessary regardless of whether the original (crypted) buffer crosses
144 // the 4GB limit or not -- we have to allocate a separate plaintext buffer.
145 // The only variable is whether the plaintext buffer should be under 4GB.
147 case EdkiiIoMmuOperationBusMasterRead
:
148 case EdkiiIoMmuOperationBusMasterWrite
:
149 MapInfo
->PlainTextAddress
= BASE_4GB
- 1;
150 AllocateType
= AllocateMaxAddress
;
154 case EdkiiIoMmuOperationBusMasterRead64
:
155 case EdkiiIoMmuOperationBusMasterWrite64
:
157 // Allocate the implicit plaintext bounce buffer.
159 Status
= IoMmuAllocateBounceBuffer (
164 if (EFI_ERROR (Status
)) {
171 // For BusMasterCommonBuffer[64] operations, a to-be-plaintext buffer and a
172 // stash buffer (for in-place decryption) have been allocated already, with
173 // AllocateBuffer(). We only check whether the address of the to-be-plaintext
174 // buffer is low enough for the requested operation.
176 case EdkiiIoMmuOperationBusMasterCommonBuffer
:
177 if ((MapInfo
->CryptedAddress
> BASE_4GB
) ||
178 (EFI_PAGES_TO_SIZE (MapInfo
->NumberOfPages
) >
179 BASE_4GB
- MapInfo
->CryptedAddress
))
182 // CommonBuffer operations cannot be remapped. If the common buffer is
183 // above 4GB, then it is not possible to generate a mapping, so return an
186 Status
= EFI_UNSUPPORTED
;
193 case EdkiiIoMmuOperationBusMasterCommonBuffer64
:
195 // The buffer at MapInfo->CryptedAddress comes from AllocateBuffer().
197 MapInfo
->PlainTextAddress
= MapInfo
->CryptedAddress
;
199 // Stash the crypted data.
201 CommonBufferHeader
= (COMMON_BUFFER_HEADER
*)(
202 (UINTN
)MapInfo
->CryptedAddress
- EFI_PAGE_SIZE
204 ASSERT (CommonBufferHeader
->Signature
== COMMON_BUFFER_SIG
);
206 CommonBufferHeader
->StashBuffer
,
207 (VOID
*)(UINTN
)MapInfo
->CryptedAddress
,
208 MapInfo
->NumberOfBytes
211 // Point "DecryptionSource" to the stash buffer so that we decrypt
212 // it to the original location, after the switch statement.
214 DecryptionSource
= CommonBufferHeader
->StashBuffer
;
215 MapInfo
->ReservedMemBitmap
= CommonBufferHeader
->ReservedMemBitmap
;
220 // Operation is invalid
222 Status
= EFI_INVALID_PARAMETER
;
226 if (MapInfo
->ReservedMemBitmap
== 0) {
228 // If MapInfo->ReservedMemBitmap is 0, it means the bounce buffer is not allocated
229 // from the pre-allocated shared memory, so it must be converted to shared memory here.
231 if (CC_GUEST_IS_SEV (PcdGet64 (PcdConfidentialComputingGuestAttr
))) {
233 // Clear the memory encryption mask on the plaintext buffer.
235 Status
= MemEncryptSevClearPageEncMask (
237 MapInfo
->PlainTextAddress
,
238 MapInfo
->NumberOfPages
240 } else if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr
))) {
242 // Set the memory shared bit.
244 Status
= MemEncryptTdxSetPageSharedBit (
246 MapInfo
->PlainTextAddress
,
247 MapInfo
->NumberOfPages
254 ASSERT_EFI_ERROR (Status
);
255 if (EFI_ERROR (Status
)) {
260 // If this is a read operation from the Bus Master's point of view,
261 // then copy the contents of the real buffer into the mapped buffer
262 // so the Bus Master can read the contents of the real buffer.
264 // For BusMasterCommonBuffer[64] operations, the CopyMem() below will decrypt
265 // the original data (from the stash buffer) back to the original location.
267 if ((Operation
== EdkiiIoMmuOperationBusMasterRead
) ||
268 (Operation
== EdkiiIoMmuOperationBusMasterRead64
) ||
269 (Operation
== EdkiiIoMmuOperationBusMasterCommonBuffer
) ||
270 (Operation
== EdkiiIoMmuOperationBusMasterCommonBuffer64
))
273 (VOID
*)(UINTN
)MapInfo
->PlainTextAddress
,
275 MapInfo
->NumberOfBytes
280 // Track all MAP_INFO structures.
282 InsertHeadList (&mMapInfos
, &MapInfo
->Link
);
284 // Populate output parameters.
286 *DeviceAddress
= MapInfo
->PlainTextAddress
;
291 "%a: Mapping=0x%p Device(PlainText)=0x%Lx Crypted=0x%Lx Pages=0x%Lx, ReservedMemBitmap=0x%Lx\n",
294 MapInfo
->PlainTextAddress
,
295 MapInfo
->CryptedAddress
,
296 (UINT64
)MapInfo
->NumberOfPages
,
297 MapInfo
->ReservedMemBitmap
311 Completes the Map() operation and releases any corresponding resources.
313 This is an internal worker function that only extends the Map() API with
314 the MemoryMapLocked parameter.
316 @param This The protocol instance pointer.
317 @param Mapping The mapping value returned from Map().
318 @param MemoryMapLocked The function is executing on the stack of
319 gBS->ExitBootServices(); changes to the UEFI
320 memory map are forbidden.
322 @retval EFI_SUCCESS The range was unmapped.
323 @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by
325 @retval EFI_DEVICE_ERROR The data was not committed to the target system
332 IN EDKII_IOMMU_PROTOCOL
*This
,
334 IN BOOLEAN MemoryMapLocked
339 COMMON_BUFFER_HEADER
*CommonBufferHeader
;
340 VOID
*EncryptionTarget
;
344 "%a: Mapping=0x%p MemoryMapLocked=%d\n",
350 if (Mapping
== NULL
) {
351 return EFI_INVALID_PARAMETER
;
354 MapInfo
= (MAP_INFO
*)Mapping
;
355 Status
= EFI_SUCCESS
;
357 // set CommonBufferHeader to suppress incorrect compiler/analyzer warnings
359 CommonBufferHeader
= NULL
;
362 // For BusMasterWrite[64] operations and BusMasterCommonBuffer[64] operations
363 // we have to encrypt the results, ultimately to the original place (i.e.,
364 // "MapInfo->CryptedAddress").
366 // For BusMasterCommonBuffer[64] operations however, this encryption has to
367 // land in-place, so divert the encryption to the stash buffer first.
369 EncryptionTarget
= (VOID
*)(UINTN
)MapInfo
->CryptedAddress
;
371 switch (MapInfo
->Operation
) {
372 case EdkiiIoMmuOperationBusMasterCommonBuffer
:
373 case EdkiiIoMmuOperationBusMasterCommonBuffer64
:
374 ASSERT (MapInfo
->PlainTextAddress
== MapInfo
->CryptedAddress
);
376 CommonBufferHeader
= (COMMON_BUFFER_HEADER
*)(
377 (UINTN
)MapInfo
->PlainTextAddress
- EFI_PAGE_SIZE
379 ASSERT (CommonBufferHeader
->Signature
== COMMON_BUFFER_SIG
);
380 EncryptionTarget
= CommonBufferHeader
->StashBuffer
;
385 case EdkiiIoMmuOperationBusMasterWrite
:
386 case EdkiiIoMmuOperationBusMasterWrite64
:
389 (VOID
*)(UINTN
)MapInfo
->PlainTextAddress
,
390 MapInfo
->NumberOfBytes
396 // nothing to encrypt after BusMasterRead[64] operations
401 if (MapInfo
->ReservedMemBitmap
== 0) {
402 if (CC_GUEST_IS_SEV (PcdGet64 (PcdConfidentialComputingGuestAttr
))) {
404 // Restore the memory encryption mask on the area we used to hold the
407 Status
= MemEncryptSevSetPageEncMask (
409 MapInfo
->PlainTextAddress
,
410 MapInfo
->NumberOfPages
412 } else if (CC_GUEST_IS_TDX (PcdGet64 (PcdConfidentialComputingGuestAttr
))) {
414 // Restore the memory shared bit mask on the area we used to hold the
417 Status
= MemEncryptTdxClearPageSharedBit (
419 MapInfo
->PlainTextAddress
,
420 MapInfo
->NumberOfPages
427 ASSERT_EFI_ERROR (Status
);
428 if (EFI_ERROR (Status
)) {
433 // For BusMasterCommonBuffer[64] operations, copy the stashed data to the
434 // original (now encrypted) location.
436 // For all other operations, fill the late bounce buffer (which existed as
437 // plaintext at some point) with zeros, and then release it (unless the UEFI
438 // memory map is locked).
440 if ((MapInfo
->Operation
== EdkiiIoMmuOperationBusMasterCommonBuffer
) ||
441 (MapInfo
->Operation
== EdkiiIoMmuOperationBusMasterCommonBuffer64
))
444 (VOID
*)(UINTN
)MapInfo
->CryptedAddress
,
445 CommonBufferHeader
->StashBuffer
,
446 MapInfo
->NumberOfBytes
450 (VOID
*)(UINTN
)MapInfo
->PlainTextAddress
,
451 EFI_PAGES_TO_SIZE (MapInfo
->NumberOfPages
)
454 if (!MemoryMapLocked
) {
455 IoMmuFreeBounceBuffer (MapInfo
);
460 // Forget the MAP_INFO structure, then free it (unless the UEFI memory map is
463 RemoveEntryList (&MapInfo
->Link
);
464 if (!MemoryMapLocked
) {
472 Completes the Map() operation and releases any corresponding resources.
474 @param This The protocol instance pointer.
475 @param Mapping The mapping value returned from Map().
477 @retval EFI_SUCCESS The range was unmapped.
478 @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by
480 @retval EFI_DEVICE_ERROR The data was not committed to the target system
486 IN EDKII_IOMMU_PROTOCOL
*This
,
490 return IoMmuUnmapWorker (
493 FALSE
// MemoryMapLocked
498 Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
499 OperationBusMasterCommonBuffer64 mapping.
501 @param This The protocol instance pointer.
502 @param Type This parameter is not used and must be ignored.
503 @param MemoryType The type of memory to allocate,
504 EfiBootServicesData or EfiRuntimeServicesData.
505 @param Pages The number of pages to allocate.
506 @param HostAddress A pointer to store the base system memory
507 address of the allocated range.
508 @param Attributes The requested bit mask of attributes for the
511 @retval EFI_SUCCESS The requested memory pages were allocated.
512 @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal
513 attribute bits are MEMORY_WRITE_COMBINE and
515 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
516 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
521 IoMmuAllocateBuffer (
522 IN EDKII_IOMMU_PROTOCOL
*This
,
523 IN EFI_ALLOCATE_TYPE Type
,
524 IN EFI_MEMORY_TYPE MemoryType
,
526 IN OUT VOID
**HostAddress
,
531 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
533 UINTN CommonBufferPages
;
534 COMMON_BUFFER_HEADER
*CommonBufferHeader
;
535 UINT32 ReservedMemBitmap
;
539 "%a: MemoryType=%u Pages=0x%Lx Attributes=0x%Lx\n",
547 // Validate Attributes
549 if ((Attributes
& EDKII_IOMMU_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER
) != 0) {
550 return EFI_UNSUPPORTED
;
554 // Check for invalid inputs
556 if (HostAddress
== NULL
) {
557 return EFI_INVALID_PARAMETER
;
561 // The only valid memory types are EfiBootServicesData and
562 // EfiRuntimeServicesData
564 if ((MemoryType
!= EfiBootServicesData
) &&
565 (MemoryType
!= EfiRuntimeServicesData
))
567 return EFI_INVALID_PARAMETER
;
571 // We'll need a header page for the COMMON_BUFFER_HEADER structure.
573 if (Pages
> MAX_UINTN
- 1) {
574 return EFI_OUT_OF_RESOURCES
;
577 CommonBufferPages
= Pages
+ 1;
580 // Allocate the stash in EfiBootServicesData type memory.
582 // Map() will temporarily save encrypted data in the stash for
583 // BusMasterCommonBuffer[64] operations, so the data can be decrypted to the
584 // original location.
586 // Unmap() will temporarily save plaintext data in the stash for
587 // BusMasterCommonBuffer[64] operations, so the data can be encrypted to the
588 // original location.
590 // StashBuffer always resides in encrypted memory.
592 StashBuffer
= AllocatePages (Pages
);
593 if (StashBuffer
== NULL
) {
594 return EFI_OUT_OF_RESOURCES
;
597 PhysicalAddress
= (UINTN
)-1;
598 if ((Attributes
& EDKII_IOMMU_ATTRIBUTE_DUAL_ADDRESS_CYCLE
) == 0) {
600 // Limit allocations to memory below 4GB
602 PhysicalAddress
= SIZE_4GB
- 1;
605 Status
= IoMmuAllocateCommonBuffer (
612 if (EFI_ERROR (Status
)) {
613 goto FreeStashBuffer
;
616 CommonBufferHeader
= (VOID
*)(UINTN
)PhysicalAddress
;
617 PhysicalAddress
+= EFI_PAGE_SIZE
;
619 CommonBufferHeader
->Signature
= COMMON_BUFFER_SIG
;
620 CommonBufferHeader
->StashBuffer
= StashBuffer
;
621 CommonBufferHeader
->ReservedMemBitmap
= ReservedMemBitmap
;
623 *HostAddress
= (VOID
*)(UINTN
)PhysicalAddress
;
627 "%a: Host=0x%Lx Stash=0x%p\n",
635 FreePages (StashBuffer
, Pages
);
640 Frees memory that was allocated with AllocateBuffer().
642 @param This The protocol instance pointer.
643 @param Pages The number of pages to free.
644 @param HostAddress The base system memory address of the allocated
647 @retval EFI_SUCCESS The requested memory pages were freed.
648 @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and
649 Pages was not allocated with AllocateBuffer().
655 IN EDKII_IOMMU_PROTOCOL
*This
,
660 UINTN CommonBufferPages
;
661 COMMON_BUFFER_HEADER
*CommonBufferHeader
;
665 "%a: Host=0x%p Pages=0x%Lx\n",
671 CommonBufferPages
= Pages
+ 1;
672 CommonBufferHeader
= (COMMON_BUFFER_HEADER
*)(
673 (UINTN
)HostAddress
- EFI_PAGE_SIZE
677 // Check the signature.
679 ASSERT (CommonBufferHeader
->Signature
== COMMON_BUFFER_SIG
);
680 if (CommonBufferHeader
->Signature
!= COMMON_BUFFER_SIG
) {
681 return EFI_INVALID_PARAMETER
;
685 // Free the stash buffer. This buffer was always encrypted, so no need to
688 FreePages (CommonBufferHeader
->StashBuffer
, Pages
);
691 // Release the common buffer itself. Unmap() has re-encrypted it in-place, so
692 // no need to zero it.
694 return IoMmuFreeCommonBuffer (CommonBufferHeader
, CommonBufferPages
);
698 Set IOMMU attribute for a system memory.
700 If the IOMMU protocol exists, the system memory cannot be used
703 When a device requests a DMA access for a system memory,
704 the device driver need use SetAttribute() to update the IOMMU
705 attribute to request DMA access (read and/or write).
707 The DeviceHandle is used to identify which device submits the request.
708 The IOMMU implementation need translate the device path to an IOMMU device
709 ID, and set IOMMU hardware register accordingly.
710 1) DeviceHandle can be a standard PCI device.
711 The memory for BusMasterRead need set EDKII_IOMMU_ACCESS_READ.
712 The memory for BusMasterWrite need set EDKII_IOMMU_ACCESS_WRITE.
713 The memory for BusMasterCommonBuffer need set
714 EDKII_IOMMU_ACCESS_READ|EDKII_IOMMU_ACCESS_WRITE.
715 After the memory is used, the memory need set 0 to keep it being
717 2) DeviceHandle can be an ACPI device (ISA, I2C, SPI, etc).
718 The memory for DMA access need set EDKII_IOMMU_ACCESS_READ and/or
719 EDKII_IOMMU_ACCESS_WRITE.
721 @param[in] This The protocol instance pointer.
722 @param[in] DeviceHandle The device who initiates the DMA access
724 @param[in] Mapping The mapping value returned from Map().
725 @param[in] IoMmuAccess The IOMMU access.
727 @retval EFI_SUCCESS The IoMmuAccess is set for the memory range
728 specified by DeviceAddress and Length.
729 @retval EFI_INVALID_PARAMETER DeviceHandle is an invalid handle.
730 @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by
732 @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination
734 @retval EFI_UNSUPPORTED DeviceHandle is unknown by the IOMMU.
735 @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not supported
737 @retval EFI_UNSUPPORTED The IOMMU does not support the memory range
738 specified by Mapping.
739 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to
740 modify the IOMMU access.
741 @retval EFI_DEVICE_ERROR The IOMMU device reported an error while
742 attempting the operation.
748 IN EDKII_IOMMU_PROTOCOL
*This
,
749 IN EFI_HANDLE DeviceHandle
,
751 IN UINT64 IoMmuAccess
754 return EFI_UNSUPPORTED
;
757 EDKII_IOMMU_PROTOCOL mIoMmu
= {
758 EDKII_IOMMU_PROTOCOL_REVISION
,
767 Notification function that is queued when gBS->ExitBootServices() signals the
768 EFI_EVENT_GROUP_EXIT_BOOT_SERVICES event group. This function signals another
769 event, received as Context, and returns.
771 Signaling an event in this context is safe. The UEFI spec allows
772 gBS->SignalEvent() to return EFI_SUCCESS only; EFI_OUT_OF_RESOURCES is not
773 listed, hence memory is not allocated. The edk2 implementation also does not
774 release memory (and we only have to care about the edk2 implementation
775 because EDKII_IOMMU_PROTOCOL is edk2-specific anyway).
777 @param[in] Event Event whose notification function is being invoked.
778 Event is permitted to request the queueing of this
779 function at TPL_CALLBACK or TPL_NOTIFY task
782 @param[in] EventToSignal Identifies the EFI_EVENT to signal. EventToSignal
783 is permitted to request the queueing of its
784 notification function only at TPL_CALLBACK level.
791 IN VOID
*EventToSignal
795 // (1) The NotifyFunctions of all the events in
796 // EFI_EVENT_GROUP_EXIT_BOOT_SERVICES will have been queued before
797 // IoMmuExitBoot() is entered.
799 // (2) IoMmuExitBoot() is executing minimally at TPL_CALLBACK.
801 // (3) IoMmuExitBoot() has been queued in unspecified order relative to the
802 // NotifyFunctions of all the other events in
803 // EFI_EVENT_GROUP_EXIT_BOOT_SERVICES whose NotifyTpl is the same as
808 // - If Event's NotifyTpl is TPL_CALLBACK, then some other NotifyFunctions
809 // queued at TPL_CALLBACK may be invoked after IoMmuExitBoot() returns.
811 // - If Event's NotifyTpl is TPL_NOTIFY, then some other NotifyFunctions
812 // queued at TPL_NOTIFY may be invoked after IoMmuExitBoot() returns; plus
813 // *all* NotifyFunctions queued at TPL_CALLBACK will be invoked strictly
814 // after all NotifyFunctions queued at TPL_NOTIFY, including
815 // IoMmuExitBoot(), have been invoked.
817 // - By signaling EventToSignal here, whose NotifyTpl is TPL_CALLBACK, we
818 // queue EventToSignal's NotifyFunction after the NotifyFunctions of *all*
819 // events in EFI_EVENT_GROUP_EXIT_BOOT_SERVICES.
821 DEBUG ((DEBUG_VERBOSE
, "%a\n", __FUNCTION__
));
822 gBS
->SignalEvent (EventToSignal
);
826 Notification function that is queued after the notification functions of all
827 events in the EFI_EVENT_GROUP_EXIT_BOOT_SERVICES event group. The same memory
828 map restrictions apply.
830 This function unmaps all currently existing IOMMU mappings.
832 @param[in] Event Event whose notification function is being invoked. Event
833 is permitted to request the queueing of this function
834 only at TPL_CALLBACK task priority level.
836 @param[in] Context Ignored.
841 IoMmuUnmapAllMappings (
847 LIST_ENTRY
*NextNode
;
850 DEBUG ((DEBUG_VERBOSE
, "%a\n", __FUNCTION__
));
853 // All drivers that had set up IOMMU mappings have halted their respective
854 // controllers by now; tear down the mappings.
856 for (Node
= GetFirstNode (&mMapInfos
); Node
!= &mMapInfos
; Node
= NextNode
) {
857 NextNode
= GetNextNode (&mMapInfos
, Node
);
858 MapInfo
= CR (Node
, MAP_INFO
, Link
, MAP_INFO_SIG
);
862 TRUE
// MemoryMapLocked
867 // Release the reserved shared memory as well.
869 IoMmuReleaseReservedSharedMem (TRUE
);
873 Initialize Iommu Protocol.
878 InstallIoMmuProtocol (
883 EFI_EVENT UnmapAllMappingsEvent
;
884 EFI_EVENT ExitBootEvent
;
888 // Create the "late" event whose notification function will tear down all
889 // left-over IOMMU mappings.
891 Status
= gBS
->CreateEvent (
892 EVT_NOTIFY_SIGNAL
, // Type
893 TPL_CALLBACK
, // NotifyTpl
894 IoMmuUnmapAllMappings
, // NotifyFunction
895 NULL
, // NotifyContext
896 &UnmapAllMappingsEvent
// Event
898 if (EFI_ERROR (Status
)) {
903 // Create the event whose notification function will be queued by
904 // gBS->ExitBootServices() and will signal the event created above.
906 Status
= gBS
->CreateEvent (
907 EVT_SIGNAL_EXIT_BOOT_SERVICES
, // Type
908 TPL_CALLBACK
, // NotifyTpl
909 IoMmuExitBoot
, // NotifyFunction
910 UnmapAllMappingsEvent
, // NotifyContext
911 &ExitBootEvent
// Event
913 if (EFI_ERROR (Status
)) {
914 goto CloseUnmapAllMappingsEvent
;
918 Status
= gBS
->InstallMultipleProtocolInterfaces (
920 &gEdkiiIoMmuProtocolGuid
,
924 if (EFI_ERROR (Status
)) {
925 goto CloseExitBootEvent
;
929 // For CC guests, use reserved shared memory for DMA operation.
931 mReservedSharedMemSupported
= TRUE
;
932 Status
= IoMmuInitReservedSharedMem ();
933 if (EFI_ERROR (Status
)) {
934 mReservedSharedMemSupported
= FALSE
;
936 DEBUG ((DEBUG_INFO
, "%a: Feature of reserved memory for DMA is supported.\n", __FUNCTION__
));
942 gBS
->CloseEvent (ExitBootEvent
);
944 CloseUnmapAllMappingsEvent
:
945 gBS
->CloseEvent (UnmapAllMappingsEvent
);