]> git.proxmox.com Git - mirror_edk2.git/commitdiff
OvmfPkg/QemuFwCfgLib: Use BusMasterCommonBuffer to map FW_CFG_DMA_ACCESS
authorBrijesh Singh <brijesh.singh@amd.com>
Wed, 2 Aug 2017 22:12:48 +0000 (18:12 -0400)
committerLaszlo Ersek <lersek@redhat.com>
Sat, 5 Aug 2017 00:54:33 +0000 (02:54 +0200)
Commit 09719a01b11b (OvmfPkg/QemuFwCfgLib: Implement SEV internal function
for Dxe phase) uses IOMMU protocol to allocate and free FW_CFG_DMA_ACCESS
buffer when SEV is active. During initial commits we made assumption that
IOMMU.AllocateBuffer() will provide PlainTextAddress (i.e C-bit cleared).
This assumption was wrong, the AllocateBuffer() protocol member is not
expected to produce a buffer that is immediatly usable, and client is
required to call Map() uncondtionally with BusMasterCommonBuffer[64] to
get a mapping which is accessable by both host and device.

The patch refactors code a bit and add the support to Map()
FW_CFG_DMA_ACCESS buffer using BusMasterCommonBuffer operation after
allocation and Unamp() before free.

The complete discussion about this and recommendation from Laszlo can be
found here [1]

[1] https://lists.01.org/pipermail/edk2-devel/2017-July/012652.html

Suggested-by: Laszlo Ersek <lersek@redhat.com>
Cc: Jordan Justen <jordan.l.justen@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
[lersek@redhat.com: convert pointers to UINTN before converting to UINT64]
[lersek@redhat.com: fix argument indentation in multi-line function call]
[lersek@redhat.com: explicitly compare pointers to NULL]
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Regression-tested-by: Laszlo Ersek <lersek@redhat.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgDxe.c
OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLib.c
OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibInternal.h
OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgPei.c
OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgSec.c

index f8eb03bc3a9a4d7188f5aa110086b0651c831f04..8b98208591e6191b52b171c43dcf9f200073e876 100644 (file)
@@ -20,6 +20,7 @@
 #include <Protocol/IoMmu.h>\r
 \r
 #include <Library/BaseLib.h>\r
+#include <Library/IoLib.h>\r
 #include <Library/DebugLib.h>\r
 #include <Library/QemuFwCfgLib.h>\r
 #include <Library/UefiBootServicesTableLib.h>\r
@@ -31,20 +32,6 @@ STATIC BOOLEAN mQemuFwCfgSupported = FALSE;
 STATIC BOOLEAN mQemuFwCfgDmaSupported;\r
 \r
 STATIC EDKII_IOMMU_PROTOCOL        *mIoMmuProtocol;\r
-/**\r
-\r
- Returns a boolean indicating whether SEV is enabled\r
-\r
- @retval    TRUE    SEV is enabled\r
- @retval    FALSE   SEV is disabled\r
-**/\r
-BOOLEAN\r
-InternalQemuFwCfgSevIsEnabled (\r
-  VOID\r
-  )\r
-{\r
-  return MemEncryptSevIsEnabled ();\r
-}\r
 \r
 /**\r
   Returns a boolean indicating if the firmware configuration interface\r
@@ -110,7 +97,8 @@ QemuFwCfgInitialize (
     // IoMmuDxe driver must have installed the IOMMU protocol. If we are not\r
     // able to locate the protocol then something must have gone wrong.\r
     //\r
-    Status = gBS->LocateProtocol (&gEdkiiIoMmuProtocolGuid, NULL, (VOID **)&mIoMmuProtocol);\r
+    Status = gBS->LocateProtocol (&gEdkiiIoMmuProtocolGuid, NULL,\r
+                    (VOID **)&mIoMmuProtocol);\r
     if (EFI_ERROR (Status)) {\r
       DEBUG ((DEBUG_ERROR,\r
         "QemuFwCfgSevDma %a:%a Failed to locate IOMMU protocol.\n",\r
@@ -157,74 +145,308 @@ InternalQemuFwCfgDmaIsAvailable (
 }\r
 \r
 /**\r
- Allocate a bounce buffer for SEV DMA.\r
-\r
-  @param[in]     NumPage  Number of pages.\r
-  @param[out]    Buffer   Allocated DMA Buffer pointer\r
+  Function is used for allocating a bi-directional FW_CFG_DMA_ACCESS used\r
+  between Host and device to exchange the information. The buffer must be free'd\r
+  using FreeFwCfgDmaAccessBuffer ().\r
 \r
 **/\r
+STATIC\r
 VOID\r
-InternalQemuFwCfgSevDmaAllocateBuffer (\r
-  OUT    VOID     **Buffer,\r
-  IN     UINT32   NumPages\r
+AllocFwCfgDmaAccessBuffer (\r
+  OUT   VOID     **Access,\r
+  OUT   VOID     **MapInfo\r
   )\r
 {\r
-  EFI_STATUS    Status;\r
+  UINTN                 Size;\r
+  UINTN                 NumPages;\r
+  EFI_STATUS            Status;\r
+  VOID                  *HostAddress;\r
+  EFI_PHYSICAL_ADDRESS  DmaAddress;\r
+  VOID                  *Mapping;\r
 \r
-  ASSERT (mIoMmuProtocol != NULL);\r
+  Size = sizeof (FW_CFG_DMA_ACCESS);\r
+  NumPages = EFI_SIZE_TO_PAGES (Size);\r
 \r
+  //\r
+  // As per UEFI spec, in order to map a host address with\r
+  // BusMasterCommomBuffer64, the buffer must be allocated using the IOMMU\r
+  // AllocateBuffer()\r
+  //\r
   Status = mIoMmuProtocol->AllocateBuffer (\r
-                            mIoMmuProtocol,\r
-                            0,\r
-                            EfiBootServicesData,\r
-                            NumPages,\r
-                            Buffer,\r
-                            EDKII_IOMMU_ATTRIBUTE_MEMORY_CACHED\r
-                          );\r
+                             mIoMmuProtocol,\r
+                             AllocateAnyPages,\r
+                             EfiBootServicesData,\r
+                             NumPages,\r
+                             &HostAddress,\r
+                             EDKII_IOMMU_ATTRIBUTE_DUAL_ADDRESS_CYCLE\r
+                             );\r
   if (EFI_ERROR (Status)) {\r
     DEBUG ((DEBUG_ERROR,\r
-      "%a:%a failed to allocate %u pages\n", gEfiCallerBaseName, __FUNCTION__,\r
-      NumPages));\r
+      "%a:%a failed to allocate FW_CFG_DMA_ACCESS\n", gEfiCallerBaseName,\r
+      __FUNCTION__));\r
     ASSERT (FALSE);\r
     CpuDeadLoop ();\r
   }\r
 \r
-  DEBUG ((DEBUG_VERBOSE,\r
-    "%a:%a buffer 0x%Lx Pages %u\n", gEfiCallerBaseName, __FUNCTION__,\r
-    (UINT64)(UINTN)Buffer, NumPages));\r
+  //\r
+  // Map the host buffer with BusMasterCommonBuffer64\r
+  //\r
+  Status = mIoMmuProtocol->Map (\r
+                             mIoMmuProtocol,\r
+                             EdkiiIoMmuOperationBusMasterCommonBuffer64,\r
+                             HostAddress,\r
+                             &Size,\r
+                             &DmaAddress,\r
+                             &Mapping\r
+                             );\r
+  if (EFI_ERROR (Status)) {\r
+    mIoMmuProtocol->FreeBuffer (mIoMmuProtocol, NumPages, HostAddress);\r
+    DEBUG ((DEBUG_ERROR,\r
+      "%a:%a failed to Map() FW_CFG_DMA_ACCESS\n", gEfiCallerBaseName,\r
+      __FUNCTION__));\r
+    ASSERT (FALSE);\r
+    CpuDeadLoop ();\r
+  }\r
+\r
+  if (Size < sizeof (FW_CFG_DMA_ACCESS)) {\r
+    mIoMmuProtocol->Unmap (mIoMmuProtocol, Mapping);\r
+    mIoMmuProtocol->FreeBuffer (mIoMmuProtocol, NumPages, HostAddress);\r
+    DEBUG ((DEBUG_ERROR,\r
+      "%a:%a failed to Map() - requested 0x%Lx got 0x%Lx\n", gEfiCallerBaseName,\r
+      __FUNCTION__, (UINT64)sizeof (FW_CFG_DMA_ACCESS), (UINT64)Size));\r
+    ASSERT (FALSE);\r
+    CpuDeadLoop ();\r
+  }\r
+\r
+  *Access = HostAddress;\r
+  *MapInfo = Mapping;\r
 }\r
 \r
 /**\r
- Free the DMA buffer allocated using InternalQemuFwCfgSevDmaAllocateBuffer\r
+  Function is to used for freeing the Access buffer allocated using\r
+  AllocFwCfgDmaAccessBuffer()\r
+\r
+**/\r
+STATIC\r
+VOID\r
+FreeFwCfgDmaAccessBuffer (\r
+  IN  VOID    *Access,\r
+  IN  VOID    *Mapping\r
+  )\r
+{\r
+  UINTN       NumPages;\r
+  EFI_STATUS  Status;\r
+\r
+  NumPages = EFI_SIZE_TO_PAGES (sizeof (FW_CFG_DMA_ACCESS));\r
 \r
-  @param[in]     NumPage  Number of pages.\r
-  @param[in]     Buffer   DMA Buffer pointer\r
+  Status = mIoMmuProtocol->Unmap (mIoMmuProtocol, Mapping);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR,\r
+      "%a:%a failed to UnMap() Mapping 0x%Lx\n", gEfiCallerBaseName,\r
+      __FUNCTION__, (UINT64)(UINTN)Mapping));\r
+    ASSERT (FALSE);\r
+    CpuDeadLoop ();\r
+  }\r
+\r
+  Status = mIoMmuProtocol->FreeBuffer (mIoMmuProtocol, NumPages, Access);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR,\r
+      "%a:%a failed to Free() 0x%Lx\n", gEfiCallerBaseName, __FUNCTION__,\r
+      (UINT64)(UINTN)Access));\r
+    ASSERT (FALSE);\r
+    CpuDeadLoop ();\r
+  }\r
+}\r
+\r
+/**\r
+  Function is used for mapping host address to device address. The buffer must\r
+  be unmapped with UnmapDmaDataBuffer ().\r
 \r
 **/\r
+STATIC\r
 VOID\r
-InternalQemuFwCfgSevDmaFreeBuffer (\r
-  IN     VOID     *Buffer,\r
-  IN     UINT32   NumPages\r
+MapFwCfgDmaDataBuffer (\r
+  IN  BOOLEAN               IsWrite,\r
+  IN  VOID                  *HostAddress,\r
+  IN  UINT32                Size,\r
+  OUT EFI_PHYSICAL_ADDRESS  *DeviceAddress,\r
+  OUT VOID                  **MapInfo\r
   )\r
 {\r
-  EFI_STATUS    Status;\r
+  EFI_STATUS              Status;\r
+  UINTN                   NumberOfBytes;\r
+  VOID                    *Mapping;\r
+  EFI_PHYSICAL_ADDRESS    PhysicalAddress;\r
+\r
+  NumberOfBytes = Size;\r
+  Status = mIoMmuProtocol->Map (\r
+                             mIoMmuProtocol,\r
+                             (IsWrite ?\r
+                              EdkiiIoMmuOperationBusMasterRead64 :\r
+                              EdkiiIoMmuOperationBusMasterWrite64),\r
+                             HostAddress,\r
+                             &NumberOfBytes,\r
+                             &PhysicalAddress,\r
+                             &Mapping\r
+                             );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR,\r
+      "%a:%a failed to Map() Address 0x%Lx Size 0x%Lx\n", gEfiCallerBaseName,\r
+      __FUNCTION__, (UINT64)(UINTN)HostAddress, (UINT64)Size));\r
+    ASSERT (FALSE);\r
+    CpuDeadLoop ();\r
+  }\r
 \r
-  ASSERT (mIoMmuProtocol != NULL);\r
+  if (NumberOfBytes < Size) {\r
+    mIoMmuProtocol->Unmap (mIoMmuProtocol, Mapping);\r
+    DEBUG ((DEBUG_ERROR,\r
+      "%a:%a failed to Map() - requested 0x%x got 0x%Lx\n", gEfiCallerBaseName,\r
+      __FUNCTION__, Size, (UINT64)NumberOfBytes));\r
+    ASSERT (FALSE);\r
+    CpuDeadLoop ();\r
+  }\r
 \r
-  Status = mIoMmuProtocol->FreeBuffer (\r
-                            mIoMmuProtocol,\r
-                            NumPages,\r
-                            Buffer\r
-                          );\r
+  *DeviceAddress = PhysicalAddress;\r
+  *MapInfo = Mapping;\r
+}\r
+\r
+STATIC\r
+VOID\r
+UnmapFwCfgDmaDataBuffer (\r
+  IN  VOID  *Mapping\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  Status = mIoMmuProtocol->Unmap (mIoMmuProtocol, Mapping);\r
   if (EFI_ERROR (Status)) {\r
     DEBUG ((DEBUG_ERROR,\r
-      "%a:%a failed to free buffer 0x%Lx pages %u\n", gEfiCallerBaseName,\r
-      __FUNCTION__, (UINT64)(UINTN)Buffer, NumPages));\r
+      "%a:%a failed to UnMap() Mapping 0x%Lx\n", gEfiCallerBaseName,\r
+      __FUNCTION__, (UINT64)(UINTN)Mapping));\r
     ASSERT (FALSE);\r
     CpuDeadLoop ();\r
   }\r
+}\r
 \r
-  DEBUG ((DEBUG_VERBOSE,\r
-    "%a:%a buffer 0x%Lx Pages %u\n", gEfiCallerBaseName,__FUNCTION__,\r
-    (UINT64)(UINTN)Buffer, NumPages));\r
+/**\r
+  Transfer an array of bytes, or skip a number of bytes, using the DMA\r
+  interface.\r
+\r
+  @param[in]     Size     Size in bytes to transfer or skip.\r
+\r
+  @param[in,out] Buffer   Buffer to read data into or write data from. Ignored,\r
+                          and may be NULL, if Size is zero, or Control is\r
+                          FW_CFG_DMA_CTL_SKIP.\r
+\r
+  @param[in]     Control  One of the following:\r
+                          FW_CFG_DMA_CTL_WRITE - write to fw_cfg from Buffer.\r
+                          FW_CFG_DMA_CTL_READ  - read from fw_cfg into Buffer.\r
+                          FW_CFG_DMA_CTL_SKIP  - skip bytes in fw_cfg.\r
+**/\r
+VOID\r
+InternalQemuFwCfgDmaBytes (\r
+  IN     UINT32   Size,\r
+  IN OUT VOID     *Buffer OPTIONAL,\r
+  IN     UINT32   Control\r
+  )\r
+{\r
+  volatile FW_CFG_DMA_ACCESS LocalAccess;\r
+  volatile FW_CFG_DMA_ACCESS *Access;\r
+  UINT32                     AccessHigh, AccessLow;\r
+  UINT32                     Status;\r
+  VOID                       *AccessMapping, *DataMapping;\r
+  VOID                       *DataBuffer;\r
+\r
+  ASSERT (Control == FW_CFG_DMA_CTL_WRITE || Control == FW_CFG_DMA_CTL_READ ||\r
+    Control == FW_CFG_DMA_CTL_SKIP);\r
+\r
+  if (Size == 0) {\r
+    return;\r
+  }\r
+\r
+  Access = &LocalAccess;\r
+  AccessMapping = NULL;\r
+  DataMapping = NULL;\r
+  DataBuffer = Buffer;\r
+\r
+  //\r
+  // When SEV is enabled, map Buffer to DMA address before issuing the DMA\r
+  // request\r
+  //\r
+  if (MemEncryptSevIsEnabled ()) {\r
+    VOID                  *AccessBuffer;\r
+    EFI_PHYSICAL_ADDRESS  DataBufferAddress;\r
+\r
+    //\r
+    // Allocate DMA Access buffer\r
+    //\r
+    AllocFwCfgDmaAccessBuffer (&AccessBuffer, &AccessMapping);\r
+\r
+    Access = AccessBuffer;\r
+\r
+    //\r
+    // Map actual data buffer\r
+    //\r
+    if (Control != FW_CFG_DMA_CTL_SKIP) {\r
+      MapFwCfgDmaDataBuffer (\r
+        Control == FW_CFG_DMA_CTL_WRITE,\r
+        Buffer,\r
+        Size,\r
+        &DataBufferAddress,\r
+        &DataMapping\r
+        );\r
+\r
+      DataBuffer = (VOID *) (UINTN) DataBufferAddress;\r
+    }\r
+  }\r
+\r
+  Access->Control = SwapBytes32 (Control);\r
+  Access->Length  = SwapBytes32 (Size);\r
+  Access->Address = SwapBytes64 ((UINTN)DataBuffer);\r
+\r
+  //\r
+  // Delimit the transfer from (a) modifications to Access, (b) in case of a\r
+  // write, from writes to Buffer by the caller.\r
+  //\r
+  MemoryFence ();\r
+\r
+  //\r
+  // Start the transfer.\r
+  //\r
+  AccessHigh = (UINT32)RShiftU64 ((UINTN)Access, 32);\r
+  AccessLow  = (UINT32)(UINTN)Access;\r
+  IoWrite32 (FW_CFG_IO_DMA_ADDRESS,     SwapBytes32 (AccessHigh));\r
+  IoWrite32 (FW_CFG_IO_DMA_ADDRESS + 4, SwapBytes32 (AccessLow));\r
+\r
+  //\r
+  // Don't look at Access.Control before starting the transfer.\r
+  //\r
+  MemoryFence ();\r
+\r
+  //\r
+  // Wait for the transfer to complete.\r
+  //\r
+  do {\r
+    Status = SwapBytes32 (Access->Control);\r
+    ASSERT ((Status & FW_CFG_DMA_CTL_ERROR) == 0);\r
+  } while (Status != 0);\r
+\r
+  //\r
+  // After a read, the caller will want to use Buffer.\r
+  //\r
+  MemoryFence ();\r
+\r
+  //\r
+  // If Access buffer was dynamically allocated then free it.\r
+  //\r
+  if (AccessMapping != NULL) {\r
+    FreeFwCfgDmaAccessBuffer ((VOID *)Access, AccessMapping);\r
+  }\r
+\r
+  //\r
+  // If DataBuffer was mapped then unmap it.\r
+  //\r
+  if (DataMapping != NULL) {\r
+    UnmapFwCfgDmaDataBuffer (DataMapping);\r
+  }\r
 }\r
index d3bf75498d60f0f684e6b0ccbb792f78157df503..7f42f38d1c05cca65225e962b5d530dd01a1daed 100644 (file)
@@ -45,136 +45,6 @@ QemuFwCfgSelectItem (
   IoWrite16 (FW_CFG_IO_SELECTOR, (UINT16)(UINTN) QemuFwCfgItem);\r
 }\r
 \r
-\r
-/**\r
-  Transfer an array of bytes, or skip a number of bytes, using the DMA\r
-  interface.\r
-\r
-  @param[in]     Size     Size in bytes to transfer or skip.\r
-\r
-  @param[in,out] Buffer   Buffer to read data into or write data from. Ignored,\r
-                          and may be NULL, if Size is zero, or Control is\r
-                          FW_CFG_DMA_CTL_SKIP.\r
-\r
-  @param[in]     Control  One of the following:\r
-                          FW_CFG_DMA_CTL_WRITE - write to fw_cfg from Buffer.\r
-                          FW_CFG_DMA_CTL_READ  - read from fw_cfg into Buffer.\r
-                          FW_CFG_DMA_CTL_SKIP  - skip bytes in fw_cfg.\r
-**/\r
-VOID\r
-InternalQemuFwCfgDmaBytes (\r
-  IN     UINT32   Size,\r
-  IN OUT VOID     *Buffer OPTIONAL,\r
-  IN     UINT32   Control\r
-  )\r
-{\r
-  volatile FW_CFG_DMA_ACCESS LocalAccess;\r
-  volatile FW_CFG_DMA_ACCESS *Access;\r
-  UINT32                     AccessHigh, AccessLow;\r
-  UINT32                     Status;\r
-  UINT32                     NumPages;\r
-  VOID                       *DmaBuffer, *BounceBuffer;\r
-\r
-  ASSERT (Control == FW_CFG_DMA_CTL_WRITE || Control == FW_CFG_DMA_CTL_READ ||\r
-    Control == FW_CFG_DMA_CTL_SKIP);\r
-\r
-  if (Size == 0) {\r
-    return;\r
-  }\r
-\r
-  //\r
-  // set NumPages to suppress incorrect compiler/analyzer warnings\r
-  //\r
-  NumPages = 0;\r
-\r
-  //\r
-  // When SEV is enabled then allocate DMA bounce buffer\r
-  //\r
-  if (InternalQemuFwCfgSevIsEnabled ()) {\r
-    UINTN  TotalSize;\r
-\r
-    TotalSize = sizeof (*Access);\r
-    //\r
-    // Skip operation does not need buffer\r
-    //\r
-    if (Control != FW_CFG_DMA_CTL_SKIP) {\r
-      TotalSize += Size;\r
-    }\r
-\r
-    //\r
-    // Allocate SEV DMA buffer\r
-    //\r
-    NumPages = (UINT32)EFI_SIZE_TO_PAGES (TotalSize);\r
-    InternalQemuFwCfgSevDmaAllocateBuffer (&BounceBuffer, NumPages);\r
-\r
-    Access = BounceBuffer;\r
-    DmaBuffer = (UINT8*)BounceBuffer + sizeof (*Access);\r
-\r
-    //\r
-    //  Decrypt data from encrypted guest buffer into DMA buffer\r
-    //\r
-    if (Control == FW_CFG_DMA_CTL_WRITE) {\r
-      CopyMem (DmaBuffer, Buffer, Size);\r
-    }\r
-  } else {\r
-    Access = &LocalAccess;\r
-    DmaBuffer = Buffer;\r
-    BounceBuffer = NULL;\r
-  }\r
-\r
-  Access->Control = SwapBytes32 (Control);\r
-  Access->Length  = SwapBytes32 (Size);\r
-  Access->Address = SwapBytes64 ((UINTN)DmaBuffer);\r
-\r
-  //\r
-  // Delimit the transfer from (a) modifications to Access, (b) in case of a\r
-  // write, from writes to Buffer by the caller.\r
-  //\r
-  MemoryFence ();\r
-\r
-  //\r
-  // Start the transfer.\r
-  //\r
-  AccessHigh = (UINT32)RShiftU64 ((UINTN)Access, 32);\r
-  AccessLow  = (UINT32)(UINTN)Access;\r
-  IoWrite32 (FW_CFG_IO_DMA_ADDRESS,     SwapBytes32 (AccessHigh));\r
-  IoWrite32 (FW_CFG_IO_DMA_ADDRESS + 4, SwapBytes32 (AccessLow));\r
-\r
-  //\r
-  // Don't look at Access.Control before starting the transfer.\r
-  //\r
-  MemoryFence ();\r
-\r
-  //\r
-  // Wait for the transfer to complete.\r
-  //\r
-  do {\r
-    Status = SwapBytes32 (Access->Control);\r
-    ASSERT ((Status & FW_CFG_DMA_CTL_ERROR) == 0);\r
-  } while (Status != 0);\r
-\r
-  //\r
-  // After a read, the caller will want to use Buffer.\r
-  //\r
-  MemoryFence ();\r
-\r
-  //\r
-  // If Bounce buffer was allocated then copy the data into guest buffer and\r
-  // free the bounce buffer\r
-  //\r
-  if (BounceBuffer != NULL) {\r
-    //\r
-    //  Encrypt the data from DMA buffer into guest buffer\r
-    //\r
-    if (Control == FW_CFG_DMA_CTL_READ) {\r
-      CopyMem (Buffer, DmaBuffer, Size);\r
-    }\r
-\r
-    InternalQemuFwCfgSevDmaFreeBuffer (BounceBuffer, NumPages);\r
-  }\r
-}\r
-\r
-\r
 /**\r
   Reads firmware configuration bytes into a buffer\r
 \r
index 8cfa7913ffaeeebf61bb33acfb3731bfb2a97051..327f1d37e17d7bddd539988d2cad09cbc4d7e78f 100644 (file)
@@ -45,39 +45,25 @@ InternalQemuFwCfgDmaIsAvailable (
   );\r
 \r
 /**\r
- Returns a boolean indicating whether SEV support is enabled\r
+  Transfer an array of bytes, or skip a number of bytes, using the DMA\r
+  interface.\r
 \r
- @retval    TRUE    SEV is enabled\r
- @retval    FALSE   SEV is disabled\r
-**/\r
-BOOLEAN\r
-InternalQemuFwCfgSevIsEnabled (\r
-  VOID\r
-  );\r
-\r
-/**\r
- Allocate a bounce buffer for SEV DMA.\r
+  @param[in]     Size     Size in bytes to transfer or skip.\r
 \r
-  @param[out]    Buffer   Allocated DMA Buffer pointer\r
-  @param[in]     NumPage  Number of pages.\r
+  @param[in,out] Buffer   Buffer to read data into or write data from. Ignored,\r
+                          and may be NULL, if Size is zero, or Control is\r
+                          FW_CFG_DMA_CTL_SKIP.\r
 \r
+  @param[in]     Control  One of the following:\r
+                          FW_CFG_DMA_CTL_WRITE - write to fw_cfg from Buffer.\r
+                          FW_CFG_DMA_CTL_READ  - read from fw_cfg into Buffer.\r
+                          FW_CFG_DMA_CTL_SKIP  - skip bytes in fw_cfg.\r
 **/\r
 VOID\r
-InternalQemuFwCfgSevDmaAllocateBuffer (\r
-  OUT    VOID     **Buffer,\r
-  IN     UINT32   NumPages\r
+InternalQemuFwCfgDmaBytes (\r
+  IN     UINT32   Size,\r
+  IN OUT VOID     *Buffer OPTIONAL,\r
+  IN     UINT32   Control\r
   );\r
 \r
-/**\r
- Free the DMA buffer allocated using InternalQemuFwCfgSevDmaAllocateBuffer\r
-\r
-  @param[in]     NumPage  Number of pages.\r
-  @param[in]     Buffer   DMA Buffer pointer\r
-\r
-**/\r
-VOID\r
-InternalQemuFwCfgSevDmaFreeBuffer (\r
-  IN     VOID     *Buffer,\r
-  IN     UINT32   NumPages\r
-  );\r
 #endif\r
index 40f89c3b53e2bf0c4c8c455a972a5c24249e02f4..471ab0335e64001234aa14ebab499f265efa6e23 100644 (file)
@@ -16,6 +16,7 @@
 **/\r
 \r
 #include <Library/BaseLib.h>\r
+#include <Library/IoLib.h>\r
 #include <Library/DebugLib.h>\r
 #include <Library/QemuFwCfgLib.h>\r
 #include <Library/MemEncryptSevLib.h>\r
@@ -85,7 +86,7 @@ QemuFwCfgInitialize (
     // (which need to allocate dynamic memory and allocating a PAGE size'd\r
     // buffer can be challenge in PEI phase)\r
     //\r
-    if (InternalQemuFwCfgSevIsEnabled ()) {\r
+    if (MemEncryptSevIsEnabled ()) {\r
       DEBUG ((DEBUG_INFO, "SEV: QemuFwCfg fallback to IO Port interface.\n"));\r
     } else {\r
       mQemuFwCfgDmaSupported = TRUE;\r
@@ -129,56 +130,78 @@ InternalQemuFwCfgDmaIsAvailable (
 }\r
 \r
 /**\r
+  Transfer an array of bytes, or skip a number of bytes, using the DMA\r
+  interface.\r
 \r
- Returns a boolean indicating whether SEV is enabled\r
+  @param[in]     Size     Size in bytes to transfer or skip.\r
 \r
- @retval    TRUE    SEV is enabled\r
- @retval    FALSE   SEV is disabled\r
+  @param[in,out] Buffer   Buffer to read data into or write data from. Ignored,\r
+                          and may be NULL, if Size is zero, or Control is\r
+                          FW_CFG_DMA_CTL_SKIP.\r
+\r
+  @param[in]     Control  One of the following:\r
+                          FW_CFG_DMA_CTL_WRITE - write to fw_cfg from Buffer.\r
+                          FW_CFG_DMA_CTL_READ  - read from fw_cfg into Buffer.\r
+                          FW_CFG_DMA_CTL_SKIP  - skip bytes in fw_cfg.\r
 **/\r
-BOOLEAN\r
-InternalQemuFwCfgSevIsEnabled (\r
-  VOID\r
+VOID\r
+InternalQemuFwCfgDmaBytes (\r
+  IN     UINT32   Size,\r
+  IN OUT VOID     *Buffer OPTIONAL,\r
+  IN     UINT32   Control\r
   )\r
 {\r
-  return MemEncryptSevIsEnabled ();\r
-}\r
+  volatile FW_CFG_DMA_ACCESS Access;\r
+  UINT32                     AccessHigh, AccessLow;\r
+  UINT32                     Status;\r
 \r
-/**\r
- Allocate a bounce buffer for SEV DMA.\r
+  ASSERT (Control == FW_CFG_DMA_CTL_WRITE || Control == FW_CFG_DMA_CTL_READ ||\r
+    Control == FW_CFG_DMA_CTL_SKIP);\r
 \r
-  @param[in]     NumPage  Number of pages.\r
-  @param[out]    Buffer   Allocated DMA Buffer pointer\r
+  if (Size == 0) {\r
+    return;\r
+  }\r
 \r
-**/\r
-VOID\r
-InternalQemuFwCfgSevDmaAllocateBuffer (\r
-  OUT    VOID     **Buffer,\r
-  IN     UINT32   NumPages\r
-  )\r
-{\r
   //\r
-  // We should never reach here\r
+  // SEV does not support DMA operations in PEI stage, we should\r
+  // not have reached here.\r
   //\r
-  ASSERT (FALSE);\r
-  CpuDeadLoop ();\r
-}\r
+  ASSERT (!MemEncryptSevIsEnabled ());\r
 \r
-/**\r
- Free the DMA buffer allocated using InternalQemuFwCfgSevDmaAllocateBuffer\r
+  Access.Control = SwapBytes32 (Control);\r
+  Access.Length  = SwapBytes32 (Size);\r
+  Access.Address = SwapBytes64 ((UINTN)Buffer);\r
 \r
-  @param[in]     NumPage  Number of pages.\r
-  @param[in]     Buffer   DMA Buffer pointer\r
+  //\r
+  // Delimit the transfer from (a) modifications to Access, (b) in case of a\r
+  // write, from writes to Buffer by the caller.\r
+  //\r
+  MemoryFence ();\r
+\r
+  //\r
+  // Start the transfer.\r
+  //\r
+  AccessHigh = (UINT32)RShiftU64 ((UINTN)&Access, 32);\r
+  AccessLow  = (UINT32)(UINTN)&Access;\r
+  IoWrite32 (FW_CFG_IO_DMA_ADDRESS,     SwapBytes32 (AccessHigh));\r
+  IoWrite32 (FW_CFG_IO_DMA_ADDRESS + 4, SwapBytes32 (AccessLow));\r
 \r
-**/\r
-VOID\r
-InternalQemuFwCfgSevDmaFreeBuffer (\r
-  IN     VOID     *Buffer,\r
-  IN     UINT32   NumPages\r
-  )\r
-{\r
   //\r
-  // We should never reach here\r
+  // Don't look at Access.Control before starting the transfer.\r
   //\r
-  ASSERT (FALSE);\r
-  CpuDeadLoop ();\r
+  MemoryFence ();\r
+\r
+  //\r
+  // Wait for the transfer to complete.\r
+  //\r
+  do {\r
+    Status = SwapBytes32 (Access.Control);\r
+    ASSERT ((Status & FW_CFG_DMA_CTL_ERROR) == 0);\r
+  } while (Status != 0);\r
+\r
+  //\r
+  // After a read, the caller will want to use Buffer.\r
+  //\r
+  MemoryFence ();\r
 }\r
+\r
index 071b8d9b91d499f182482a6e6caa5d9788259359..1eadba99e1b323dd310a2c330c5f6050eada6f3b 100644 (file)
@@ -17,6 +17,7 @@
   WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
 **/\r
 \r
+#include <Library/BaseLib.h>\r
 #include <Library/DebugLib.h>\r
 #include <Library/QemuFwCfgLib.h>\r
 \r
@@ -97,57 +98,30 @@ InternalQemuFwCfgDmaIsAvailable (
 }\r
 \r
 /**\r
+  Transfer an array of bytes, or skip a number of bytes, using the DMA\r
+  interface.\r
 \r
- Returns a boolean indicating whether SEV is enabled\r
+  @param[in]     Size     Size in bytes to transfer or skip.\r
 \r
- @retval    TRUE    SEV is enabled\r
- @retval    FALSE   SEV is disabled\r
-**/\r
-BOOLEAN\r
-InternalQemuFwCfgSevIsEnabled (\r
-  VOID\r
-  )\r
-{\r
-  //\r
-  // DMA is not supported in SEC phase hence SEV support is irrelevant\r
-  //\r
-  return FALSE;\r
-}\r
-\r
-/**\r
- Allocate a bounce buffer for SEV DMA.\r
-\r
-  @param[in]     NumPage  Number of pages.\r
-  @param[out]    Buffer   Allocated DMA Buffer pointer\r
-\r
-**/\r
-VOID\r
-InternalQemuFwCfgSevDmaAllocateBuffer (\r
-  OUT    VOID     **Buffer,\r
-  IN     UINT32   NumPages\r
-  )\r
-{\r
-  //\r
-  // We should never reach here\r
-  //\r
-  ASSERT (FALSE);\r
-}\r
-\r
-/**\r
- Free the DMA buffer allocated using InternalQemuFwCfgSevDmaAllocateBuffer\r
-\r
-  @param[in]     NumPage  Number of pages.\r
-  @param[in]     Buffer   DMA Buffer pointer\r
+  @param[in,out] Buffer   Buffer to read data into or write data from. Ignored,\r
+                          and may be NULL, if Size is zero, or Control is\r
+                          FW_CFG_DMA_CTL_SKIP.\r
 \r
+  @param[in]     Control  One of the following:\r
+                          FW_CFG_DMA_CTL_WRITE - write to fw_cfg from Buffer.\r
+                          FW_CFG_DMA_CTL_READ  - read from fw_cfg into Buffer.\r
+                          FW_CFG_DMA_CTL_SKIP  - skip bytes in fw_cfg.\r
 **/\r
 VOID\r
-InternalQemuFwCfgSevDmaFreeBuffer (\r
-  IN     VOID     *Buffer,\r
-  IN     UINT32   NumPages\r
+InternalQemuFwCfgDmaBytes (\r
+  IN     UINT32   Size,\r
+  IN OUT VOID     *Buffer OPTIONAL,\r
+  IN     UINT32   Control\r
   )\r
 {\r
   //\r
   // We should never reach here\r
   //\r
   ASSERT (FALSE);\r
+  CpuDeadLoop ();\r
 }\r