]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/IoMmuDxe/AmdSevIoMmu.c
OvmfPkg/VirtioMmioDeviceLib: list "VirtioMmioDevice.h" in the INF file
[mirror_edk2.git] / OvmfPkg / IoMmuDxe / AmdSevIoMmu.c
index 34e1c6ee4a7434a3b698ebdb627e80b49370cf89..6b7df8d8aa3ddd5a2b866a34c765f4dec3a3ebef 100644 (file)
@@ -748,6 +748,107 @@ EDKII_IOMMU_PROTOCOL  mAmdSev = {
   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
@@ -759,13 +860,57 @@ AmdSevInstallIoMmuProtocol (
   )\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