IoMmuFreeBuffer,\r
};\r
\r
+/**\r
+ Notification function that is queued when gBS->ExitBootServices() signals the\r
+ EFI_EVENT_GROUP_EXIT_BOOT_SERVICES event group. This function signals another\r
+ event, received as Context, and returns.\r
+\r
+ Signaling an event in this context is safe. The UEFI spec allows\r
+ gBS->SignalEvent() to return EFI_SUCCESS only; EFI_OUT_OF_RESOURCES is not\r
+ listed, hence memory is not allocated. The edk2 implementation also does not\r
+ release memory (and we only have to care about the edk2 implementation\r
+ because EDKII_IOMMU_PROTOCOL is edk2-specific anyway).\r
+\r
+ @param[in] Event Event whose notification function is being invoked.\r
+ Event is permitted to request the queueing of this\r
+ function at TPL_CALLBACK or TPL_NOTIFY task\r
+ priority level.\r
+\r
+ @param[in] EventToSignal Identifies the EFI_EVENT to signal. EventToSignal\r
+ is permitted to request the queueing of its\r
+ notification function only at TPL_CALLBACK level.\r
+**/\r
+STATIC\r
+VOID\r
+EFIAPI\r
+AmdSevExitBoot (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *EventToSignal\r
+ )\r
+{\r
+ //\r
+ // (1) The NotifyFunctions of all the events in\r
+ // EFI_EVENT_GROUP_EXIT_BOOT_SERVICES will have been queued before\r
+ // AmdSevExitBoot() is entered.\r
+ //\r
+ // (2) AmdSevExitBoot() is executing minimally at TPL_CALLBACK.\r
+ //\r
+ // (3) AmdSevExitBoot() has been queued in unspecified order relative to the\r
+ // NotifyFunctions of all the other events in\r
+ // EFI_EVENT_GROUP_EXIT_BOOT_SERVICES whose NotifyTpl is the same as\r
+ // Event's.\r
+ //\r
+ // Consequences:\r
+ //\r
+ // - If Event's NotifyTpl is TPL_CALLBACK, then some other NotifyFunctions\r
+ // queued at TPL_CALLBACK may be invoked after AmdSevExitBoot() returns.\r
+ //\r
+ // - If Event's NotifyTpl is TPL_NOTIFY, then some other NotifyFunctions\r
+ // queued at TPL_NOTIFY may be invoked after AmdSevExitBoot() returns; plus\r
+ // *all* NotifyFunctions queued at TPL_CALLBACK will be invoked strictly\r
+ // after all NotifyFunctions queued at TPL_NOTIFY, including\r
+ // AmdSevExitBoot(), have been invoked.\r
+ //\r
+ // - By signaling EventToSignal here, whose NotifyTpl is TPL_CALLBACK, we\r
+ // queue EventToSignal's NotifyFunction after the NotifyFunctions of *all*\r
+ // events in EFI_EVENT_GROUP_EXIT_BOOT_SERVICES.\r
+ //\r
+ DEBUG ((DEBUG_VERBOSE, "%a\n", __FUNCTION__));\r
+ gBS->SignalEvent (EventToSignal);\r
+}\r
+\r
+/**\r
+ Notification function that is queued after the notification functions of all\r
+ events in the EFI_EVENT_GROUP_EXIT_BOOT_SERVICES event group. The same memory\r
+ map restrictions apply.\r
+\r
+ This function unmaps all currently existing IOMMU mappings.\r
+\r
+ @param[in] Event Event whose notification function is being invoked. Event\r
+ is permitted to request the queueing of this function\r
+ only at TPL_CALLBACK task priority level.\r
+\r
+ @param[in] Context Ignored.\r
+**/\r
+STATIC\r
+VOID\r
+EFIAPI\r
+AmdSevUnmapAllMappings (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ LIST_ENTRY *Node;\r
+ LIST_ENTRY *NextNode;\r
+ MAP_INFO *MapInfo;\r
+\r
+ DEBUG ((DEBUG_VERBOSE, "%a\n", __FUNCTION__));\r
+\r
+ //\r
+ // All drivers that had set up IOMMU mappings have halted their respective\r
+ // controllers by now; tear down the mappings.\r
+ //\r
+ for (Node = GetFirstNode (&mMapInfos); Node != &mMapInfos; Node = NextNode) {\r
+ NextNode = GetNextNode (&mMapInfos, Node);\r
+ MapInfo = CR (Node, MAP_INFO, Link, MAP_INFO_SIG);\r
+ IoMmuUnmapWorker (\r
+ &mAmdSev, // This\r
+ MapInfo, // Mapping\r
+ TRUE // MemoryMapLocked\r
+ );\r
+ }\r
+}\r
+\r
/**\r
Initialize Iommu Protocol.\r
\r
)\r
{\r
EFI_STATUS Status;\r
+ EFI_EVENT UnmapAllMappingsEvent;\r
+ EFI_EVENT ExitBootEvent;\r
EFI_HANDLE Handle;\r
\r
+ //\r
+ // Create the "late" event whose notification function will tear down all\r
+ // left-over IOMMU mappings.\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL, // Type\r
+ TPL_CALLBACK, // NotifyTpl\r
+ AmdSevUnmapAllMappings, // NotifyFunction\r
+ NULL, // NotifyContext\r
+ &UnmapAllMappingsEvent // Event\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Create the event whose notification function will be queued by\r
+ // gBS->ExitBootServices() and will signal the event created above.\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_SIGNAL_EXIT_BOOT_SERVICES, // Type\r
+ TPL_CALLBACK, // NotifyTpl\r
+ AmdSevExitBoot, // NotifyFunction\r
+ UnmapAllMappingsEvent, // NotifyContext\r
+ &ExitBootEvent // Event\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto CloseUnmapAllMappingsEvent;\r
+ }\r
+\r
Handle = NULL;\r
Status = gBS->InstallMultipleProtocolInterfaces (\r
&Handle,\r
&gEdkiiIoMmuProtocolGuid, &mAmdSev,\r
NULL\r
);\r
+ if (EFI_ERROR (Status)) {\r
+ goto CloseExitBootEvent;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+\r
+CloseExitBootEvent:\r
+ gBS->CloseEvent (ExitBootEvent);\r
+\r
+CloseUnmapAllMappingsEvent:\r
+ gBS->CloseEvent (UnmapAllMappingsEvent);\r
+\r
return Status;\r
}\r