]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/IoMmuDxe/AmdSevIoMmu.c
OvmfPkg/IoMmuDxe: rework setup of "MapInfo->PlainTextAddress" in Map()
[mirror_edk2.git] / OvmfPkg / IoMmuDxe / AmdSevIoMmu.c
index d899b0ab9e4105a6f0d4168dcc4f5aad4958d568..0a85ee6559e799a1b8cb1a4c235f86239da7a281 100644 (file)
@@ -72,9 +72,7 @@ IoMmuMap (
   )\r
 {\r
   EFI_STATUS                                        Status;\r
-  EFI_PHYSICAL_ADDRESS                              PhysicalAddress;\r
   MAP_INFO                                          *MapInfo;\r
-  EFI_PHYSICAL_ADDRESS                              DmaMemoryTop;\r
   EFI_ALLOCATE_TYPE                                 AllocateType;\r
 \r
   if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress == NULL ||\r
@@ -82,88 +80,105 @@ IoMmuMap (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  //\r
-  // Make sure that Operation is valid\r
-  //\r
-  if ((UINT32) Operation >= EdkiiIoMmuOperationMaximum) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-  PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;\r
-\r
-  DmaMemoryTop = (UINTN)-1;\r
-  AllocateType = AllocateAnyPages;\r
-\r
-  if (((Operation != EdkiiIoMmuOperationBusMasterRead64 &&\r
-        Operation != EdkiiIoMmuOperationBusMasterWrite64 &&\r
-        Operation != EdkiiIoMmuOperationBusMasterCommonBuffer64)) &&\r
-      ((PhysicalAddress + *NumberOfBytes) > SIZE_4GB)) {\r
-    //\r
-    // If the root bridge or the device cannot handle performing DMA above\r
-    // 4GB but any part of the DMA transfer being mapped is above 4GB, then\r
-    // map the DMA transfer to a buffer below 4GB.\r
-    //\r
-    DmaMemoryTop = SIZE_4GB - 1;\r
-    AllocateType = AllocateMaxAddress;\r
-\r
-    if (Operation == EdkiiIoMmuOperationBusMasterCommonBuffer ||\r
-        Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64) {\r
-        //\r
-        // Common Buffer operations can not be remapped.  If the common buffer\r
-        // if above 4GB, then it is not possible to generate a mapping, so\r
-        // return an error.\r
-        //\r
-        return EFI_UNSUPPORTED;\r
-    }\r
-  }\r
-\r
-  //\r
-  // CommandBuffer was allocated by us (AllocateBuffer) and is already in\r
-  // unencryted buffer so no need to create bounce buffer\r
-  //\r
-  if (Operation == EdkiiIoMmuOperationBusMasterCommonBuffer ||\r
-      Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64) {\r
-    *Mapping = NO_MAPPING;\r
-    *DeviceAddress = PhysicalAddress;\r
-\r
-    return EFI_SUCCESS;\r
-  }\r
-\r
   //\r
   // Allocate a MAP_INFO structure to remember the mapping when Unmap() is\r
   // called later.\r
   //\r
   MapInfo = AllocatePool (sizeof (MAP_INFO));\r
   if (MapInfo == NULL) {\r
-    *NumberOfBytes = 0;\r
-    return EFI_OUT_OF_RESOURCES;\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Failed;\r
   }\r
 \r
   //\r
-  // Initialize the MAP_INFO structure\r
+  // Initialize the MAP_INFO structure, except the PlainTextAddress field\r
   //\r
   MapInfo->Operation         = Operation;\r
   MapInfo->NumberOfBytes     = *NumberOfBytes;\r
   MapInfo->NumberOfPages     = EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes);\r
-  MapInfo->CryptedAddress    = PhysicalAddress;\r
-  MapInfo->PlainTextAddress  = DmaMemoryTop;\r
+  MapInfo->CryptedAddress    = (UINTN)HostAddress;\r
 \r
   //\r
-  // Allocate a buffer to map the transfer to.\r
+  // In the switch statement below, we point "MapInfo->PlainTextAddress" to the\r
+  // plaintext buffer, according to Operation.\r
   //\r
-  Status = gBS->AllocatePages (\r
-                  AllocateType,\r
-                  EfiBootServicesData,\r
-                  MapInfo->NumberOfPages,\r
-                  &MapInfo->PlainTextAddress\r
-                  );\r
-  if (EFI_ERROR (Status)) {\r
+  MapInfo->PlainTextAddress = MAX_ADDRESS;\r
+  AllocateType = AllocateAnyPages;\r
+  switch (Operation) {\r
+  //\r
+  // For BusMasterRead[64] and BusMasterWrite[64] operations, a bounce buffer\r
+  // is necessary regardless of whether the original (crypted) buffer crosses\r
+  // the 4GB limit or not -- we have to allocate a separate plaintext buffer.\r
+  // The only variable is whether the plaintext buffer should be under 4GB.\r
+  //\r
+  case EdkiiIoMmuOperationBusMasterRead:\r
+  case EdkiiIoMmuOperationBusMasterWrite:\r
+    MapInfo->PlainTextAddress = BASE_4GB - 1;\r
+    AllocateType = AllocateMaxAddress;\r
+    //\r
+    // fall through\r
+    //\r
+  case EdkiiIoMmuOperationBusMasterRead64:\r
+  case EdkiiIoMmuOperationBusMasterWrite64:\r
+    //\r
+    // Allocate the implicit plaintext bounce buffer.\r
+    //\r
+    Status = gBS->AllocatePages (\r
+                    AllocateType,\r
+                    EfiBootServicesData,\r
+                    MapInfo->NumberOfPages,\r
+                    &MapInfo->PlainTextAddress\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      goto FreeMapInfo;\r
+    }\r
+    break;\r
+\r
+  //\r
+  // For BusMasterCommonBuffer[64] operations, a plaintext buffer has been\r
+  // allocated already, with AllocateBuffer(). We only check whether the\r
+  // address is low enough for the requested operation.\r
+  //\r
+  case EdkiiIoMmuOperationBusMasterCommonBuffer:\r
+    if ((MapInfo->CryptedAddress > BASE_4GB) ||\r
+        (EFI_PAGES_TO_SIZE (MapInfo->NumberOfPages) >\r
+         BASE_4GB - MapInfo->CryptedAddress)) {\r
+      //\r
+      // CommonBuffer operations cannot be remapped. If the common buffer is\r
+      // above 4GB, then it is not possible to generate a mapping, so return an\r
+      // error.\r
+      //\r
+      Status = EFI_UNSUPPORTED;\r
+      goto FreeMapInfo;\r
+    }\r
+    //\r
+    // fall through\r
+    //\r
+  case EdkiiIoMmuOperationBusMasterCommonBuffer64:\r
+    //\r
+    // The buffer at MapInfo->CryptedAddress comes from AllocateBuffer(),\r
+    // and it is already decrypted.\r
+    //\r
+    MapInfo->PlainTextAddress = MapInfo->CryptedAddress;\r
+\r
+    //\r
+    // Therefore no mapping is necessary.\r
+    //\r
+    *DeviceAddress = MapInfo->PlainTextAddress;\r
+    *Mapping       = NO_MAPPING;\r
     FreePool (MapInfo);\r
-    *NumberOfBytes = 0;\r
-    return Status;\r
+    return EFI_SUCCESS;\r
+\r
+  default:\r
+    //\r
+    // Operation is invalid\r
+    //\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto FreeMapInfo;\r
   }\r
 \r
   //\r
-  // Clear the memory encryption mask from the device buffer\r
+  // Clear the memory encryption mask on the plaintext buffer.\r
   //\r
   Status = MemEncryptSevClearPageEncMask (\r
              0,\r
@@ -188,13 +203,9 @@ IoMmuMap (
   }\r
 \r
   //\r
-  // The DeviceAddress is the address of the maped buffer below 4GB\r
+  // Populate output parameters.\r
   //\r
   *DeviceAddress = MapInfo->PlainTextAddress;\r
-\r
-  //\r
-  // Return a pointer to the MAP_INFO structure in Mapping\r
-  //\r
   *Mapping       = MapInfo;\r
 \r
   DEBUG ((\r
@@ -208,6 +219,13 @@ IoMmuMap (
     ));\r
 \r
   return EFI_SUCCESS;\r
+\r
+FreeMapInfo:\r
+  FreePool (MapInfo);\r
+\r
+Failed:\r
+  *NumberOfBytes = 0;\r
+  return Status;\r
 }\r
 \r
 /**\r