]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdx.c
MdePkg: Add helper functions for Tdx guest in BaseIoLibIntrinsic
[mirror_edk2.git] / MdePkg / Library / BaseIoLibIntrinsic / IoLibInternalTdx.c
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdx.c b/MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdx.c
new file mode 100644 (file)
index 0000000..1e539db
--- /dev/null
@@ -0,0 +1,674 @@
+/** @file\r
+  TDX I/O Library routines.\r
+\r
+  Copyright (c) 2020-2021, Intel Corporation. All rights reserved.<BR>\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+#include "BaseIoLibIntrinsicInternal.h"\r
+#include <Uefi/UefiBaseType.h>\r
+#include <Include/IndustryStandard/Tdx.h>\r
+#include <Library/TdxLib.h>\r
+#include <Register/Intel/Cpuid.h>\r
+#include "IoLibTdx.h"\r
+\r
+// Size of TDVMCALL Access, including IO and MMIO\r
+#define TDVMCALL_ACCESS_SIZE_1  1\r
+#define TDVMCALL_ACCESS_SIZE_2  2\r
+#define TDVMCALL_ACCESS_SIZE_4  4\r
+#define TDVMCALL_ACCESS_SIZE_8  8\r
+\r
+// Direction of TDVMCALL Access, including IO and MMIO\r
+#define TDVMCALL_ACCESS_READ   0\r
+#define TDVMCALL_ACCESS_WRITE  1\r
+\r
+BOOLEAN  mTdxEnabled = FALSE;\r
+BOOLEAN  mTdxProbed  = FALSE;\r
+\r
+/**\r
+  Check if it is Tdx guest.\r
+\r
+  @return TRUE    It is Tdx guest\r
+  @return FALSE   It is not Tdx guest\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+IsTdxGuest (\r
+  VOID\r
+  )\r
+{\r
+  if (mTdxProbed) {\r
+    return mTdxEnabled;\r
+  }\r
+\r
+  mTdxEnabled = TdIsEnabled ();\r
+  mTdxProbed  = TRUE;\r
+\r
+  return mTdxEnabled;\r
+}\r
+\r
+/**\r
+  Reads an 8-bit I/O port.\r
+\r
+  TDVMCALL_IO is invoked to read I/O port.\r
+\r
+  @param  Port  The I/O port to read.\r
+\r
+  @return The value read.\r
+\r
+**/\r
+UINT8\r
+EFIAPI\r
+TdIoRead8 (\r
+  IN      UINTN  Port\r
+  )\r
+{\r
+  UINT64  Status;\r
+  UINT64  Val;\r
+\r
+  Status = TdVmCall (TDVMCALL_IO, TDVMCALL_ACCESS_SIZE_1, TDVMCALL_ACCESS_READ, Port, 0, &Val);\r
+  if (Status != 0) {\r
+    TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);\r
+  }\r
+\r
+  return (UINT8)Val;\r
+}\r
+\r
+/**\r
+  Reads a 16-bit I/O port.\r
+\r
+  TDVMCALL_IO is invoked to write I/O port.\r
+\r
+  @param  Port  The I/O port to read.\r
+\r
+  @return The value read.\r
+\r
+**/\r
+UINT16\r
+EFIAPI\r
+TdIoRead16 (\r
+  IN      UINTN  Port\r
+  )\r
+{\r
+  UINT64  Status;\r
+  UINT64  Val;\r
+\r
+  ASSERT ((Port & 1) == 0);\r
+\r
+  Status = TdVmCall (TDVMCALL_IO, TDVMCALL_ACCESS_SIZE_2, TDVMCALL_ACCESS_READ, Port, 0, &Val);\r
+  if (Status != 0) {\r
+    TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);\r
+  }\r
+\r
+  return (UINT16)Val;\r
+}\r
+\r
+/**\r
+  Reads a 32-bit I/O port.\r
+\r
+  TDVMCALL_IO is invoked to read I/O port.\r
+\r
+  @param  Port  The I/O port to read.\r
+\r
+  @return The value read.\r
+\r
+**/\r
+UINT32\r
+EFIAPI\r
+TdIoRead32 (\r
+  IN      UINTN  Port\r
+  )\r
+{\r
+  UINT64  Status;\r
+  UINT64  Val;\r
+\r
+  ASSERT ((Port & 3) == 0);\r
+\r
+  Status = TdVmCall (TDVMCALL_IO, TDVMCALL_ACCESS_SIZE_4, TDVMCALL_ACCESS_READ, Port, 0, &Val);\r
+  if (Status != 0) {\r
+    TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);\r
+  }\r
+\r
+  return (UINT32)Val;\r
+}\r
+\r
+/**\r
+  Writes an 8-bit I/O port.\r
+\r
+  TDVMCALL_IO is invoked to write I/O port.\r
+\r
+  @param  Port  The I/O port to write.\r
+  @param  Value The value to write to the I/O port.\r
+\r
+  @return The value written the I/O port.\r
+\r
+**/\r
+UINT8\r
+EFIAPI\r
+TdIoWrite8 (\r
+  IN      UINTN  Port,\r
+  IN      UINT8  Value\r
+  )\r
+{\r
+  UINT64  Status;\r
+  UINT64  Val;\r
+\r
+  Val    = Value;\r
+  Status = TdVmCall (TDVMCALL_IO, TDVMCALL_ACCESS_SIZE_1, TDVMCALL_ACCESS_WRITE, Port, Val, 0);\r
+  if (Status != 0) {\r
+    TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);\r
+  }\r
+\r
+  return Value;\r
+}\r
+\r
+/**\r
+  Writes a 16-bit I/O port.\r
+\r
+  TDVMCALL_IO is invoked to write I/O port.\r
+\r
+  @param  Port  The I/O port to write.\r
+  @param  Value The value to write to the I/O port.\r
+\r
+  @return The value written the I/O port.\r
+\r
+**/\r
+UINT16\r
+EFIAPI\r
+TdIoWrite16 (\r
+  IN      UINTN   Port,\r
+  IN      UINT16  Value\r
+  )\r
+{\r
+  UINT64  Status;\r
+  UINT64  Val;\r
+\r
+  ASSERT ((Port & 1) == 0);\r
+  Val    = Value;\r
+  Status = TdVmCall (TDVMCALL_IO, TDVMCALL_ACCESS_SIZE_2, TDVMCALL_ACCESS_WRITE, Port, Val, 0);\r
+  if (Status != 0) {\r
+    TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);\r
+  }\r
+\r
+  return Value;\r
+}\r
+\r
+/**\r
+  Writes a 32-bit I/O port.\r
+\r
+  TDVMCALL_IO is invoked to write I/O port.\r
+\r
+  @param  Port  The I/O port to write.\r
+  @param  Value The value to write to the I/O port.\r
+\r
+  @return The value written the I/O port.\r
+\r
+**/\r
+UINT32\r
+EFIAPI\r
+TdIoWrite32 (\r
+  IN      UINTN   Port,\r
+  IN      UINT32  Value\r
+  )\r
+{\r
+  UINT64  Status;\r
+  UINT64  Val;\r
+\r
+  ASSERT ((Port & 3) == 0);\r
+  Val    = Value;\r
+  Status = TdVmCall (TDVMCALL_IO, TDVMCALL_ACCESS_SIZE_4, TDVMCALL_ACCESS_WRITE, Port, Val, 0);\r
+  if (Status != 0) {\r
+    TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);\r
+  }\r
+\r
+  return Value;\r
+}\r
+\r
+/**\r
+  Reads an 8-bit MMIO register.\r
+\r
+  TDVMCALL_MMIO is invoked to read MMIO registers.\r
+\r
+  @param  Address The MMIO register to read.\r
+\r
+  @return The value read.\r
+\r
+**/\r
+UINT8\r
+EFIAPI\r
+TdMmioRead8 (\r
+  IN      UINTN  Address\r
+  )\r
+{\r
+  UINT64  Value;\r
+  UINT64  Status;\r
+\r
+  Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_1, TDVMCALL_ACCESS_READ, Address | TdSharedPageMask (), 0, &Value);\r
+  if (Status != 0) {\r
+    Value = *(volatile UINT64 *)Address;\r
+  }\r
+\r
+  return (UINT8)Value;\r
+}\r
+\r
+/**\r
+  Writes an 8-bit MMIO register.\r
+\r
+  TDVMCALL_MMIO is invoked to read write registers.\r
+\r
+  @param  Address The MMIO register to write.\r
+  @param  Value   The value to write to the MMIO register.\r
+\r
+  @return Value.\r
+\r
+**/\r
+UINT8\r
+EFIAPI\r
+TdMmioWrite8 (\r
+  IN      UINTN  Address,\r
+  IN      UINT8  Value\r
+  )\r
+{\r
+  UINT64  Val;\r
+  UINT64  Status;\r
+\r
+  Val    = Value;\r
+  Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_1, TDVMCALL_ACCESS_WRITE, Address | TdSharedPageMask (), Val, 0);\r
+  if (Status != 0) {\r
+    *(volatile UINT8 *)Address = Value;\r
+  }\r
+\r
+  return Value;\r
+}\r
+\r
+/**\r
+  Reads a 16-bit MMIO register.\r
+\r
+  TDVMCALL_MMIO is invoked to read MMIO registers.\r
+\r
+  @param  Address The MMIO register to read.\r
+\r
+  @return The value read.\r
+\r
+**/\r
+UINT16\r
+EFIAPI\r
+TdMmioRead16 (\r
+  IN      UINTN  Address\r
+  )\r
+{\r
+  UINT64  Value;\r
+  UINT64  Status;\r
+\r
+  Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_2, TDVMCALL_ACCESS_READ, Address | TdSharedPageMask (), 0, &Value);\r
+  if (Status != 0) {\r
+    Value = *(volatile UINT64 *)Address;\r
+  }\r
+\r
+  return (UINT16)Value;\r
+}\r
+\r
+/**\r
+  Writes a 16-bit MMIO register.\r
+\r
+  TDVMCALL_MMIO is invoked to write MMIO registers.\r
+\r
+  @param  Address The MMIO register to write.\r
+  @param  Value   The value to write to the MMIO register.\r
+\r
+  @return Value.\r
+\r
+**/\r
+UINT16\r
+EFIAPI\r
+TdMmioWrite16 (\r
+  IN      UINTN   Address,\r
+  IN      UINT16  Value\r
+  )\r
+{\r
+  UINT64  Val;\r
+  UINT64  Status;\r
+\r
+  ASSERT ((Address & 1) == 0);\r
+\r
+  Val    = Value;\r
+  Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_2, TDVMCALL_ACCESS_WRITE, Address | TdSharedPageMask (), Val, 0);\r
+  if (Status != 0) {\r
+    *(volatile UINT16 *)Address = Value;\r
+  }\r
+\r
+  return Value;\r
+}\r
+\r
+/**\r
+  Reads a 32-bit MMIO register.\r
+\r
+  TDVMCALL_MMIO is invoked to read MMIO registers.\r
+\r
+  @param  Address The MMIO register to read.\r
+\r
+  @return The value read.\r
+\r
+**/\r
+UINT32\r
+EFIAPI\r
+TdMmioRead32 (\r
+  IN      UINTN  Address\r
+  )\r
+{\r
+  UINT64  Value;\r
+  UINT64  Status;\r
+\r
+  Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_4, TDVMCALL_ACCESS_READ, Address | TdSharedPageMask (), 0, &Value);\r
+  if (Status != 0) {\r
+    Value = *(volatile UINT64 *)Address;\r
+  }\r
+\r
+  return (UINT32)Value;\r
+}\r
+\r
+/**\r
+  Writes a 32-bit MMIO register.\r
+\r
+  TDVMCALL_MMIO is invoked to write MMIO registers.\r
+\r
+  @param  Address The MMIO register to write.\r
+  @param  Value   The value to write to the MMIO register.\r
+\r
+  @return Value.\r
+\r
+**/\r
+UINT32\r
+EFIAPI\r
+TdMmioWrite32 (\r
+  IN      UINTN   Address,\r
+  IN      UINT32  Value\r
+  )\r
+{\r
+  UINT64  Val;\r
+  UINT64  Status;\r
+\r
+  ASSERT ((Address & 3) == 0);\r
+\r
+  Val    = Value;\r
+  Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_4, TDVMCALL_ACCESS_WRITE, Address | TdSharedPageMask (), Val, 0);\r
+  if (Status != 0) {\r
+    *(volatile UINT32 *)Address = Value;\r
+  }\r
+\r
+  return Value;\r
+}\r
+\r
+/**\r
+  Reads a 64-bit MMIO register.\r
+\r
+  TDVMCALL_MMIO is invoked to read MMIO registers.\r
+\r
+  @param  Address The MMIO register to read.\r
+\r
+  @return The value read.\r
+\r
+**/\r
+UINT64\r
+EFIAPI\r
+TdMmioRead64 (\r
+  IN      UINTN  Address\r
+  )\r
+{\r
+  UINT64  Value;\r
+  UINT64  Status;\r
+\r
+  Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_8, TDVMCALL_ACCESS_READ, Address | TdSharedPageMask (), 0, &Value);\r
+  if (Status != 0) {\r
+    Value = *(volatile UINT64 *)Address;\r
+  }\r
+\r
+  return Value;\r
+}\r
+\r
+/**\r
+  Writes a 64-bit MMIO register.\r
+\r
+  TDVMCALL_MMIO is invoked to write MMIO registers.\r
+\r
+  @param  Address The MMIO register to write.\r
+  @param  Value   The value to write to the MMIO register.\r
+\r
+**/\r
+UINT64\r
+EFIAPI\r
+TdMmioWrite64 (\r
+  IN      UINTN   Address,\r
+  IN      UINT64  Value\r
+  )\r
+{\r
+  UINT64  Status;\r
+  UINT64  Val;\r
+\r
+  ASSERT ((Address & 7) == 0);\r
+\r
+  Val    = Value;\r
+  Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_8, TDVMCALL_ACCESS_WRITE, Address | TdSharedPageMask (), Val, 0);\r
+  if (Status != 0) {\r
+    *(volatile UINT64 *)Address = Value;\r
+  }\r
+\r
+  return Value;\r
+}\r
+\r
+/**\r
+  Reads an 8-bit I/O port fifo into a block of memory.\r
+\r
+  Reads the 8-bit I/O fifo port specified by Port.\r
+  The port is read Count times, and the read data is\r
+  stored in the provided Buffer.\r
+\r
+  This function must guarantee that all I/O read and write operations are\r
+  serialized.\r
+\r
+  If 8-bit I/O port operations are not supported, then ASSERT().\r
+\r
+  In TDX a serial of TdIoRead8 is invoked to read the I/O port fifo.\r
+\r
+  @param  Port    The I/O port to read.\r
+  @param  Count   The number of times to read I/O port.\r
+  @param  Buffer  The buffer to store the read data into.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+TdIoReadFifo8 (\r
+  IN      UINTN  Port,\r
+  IN      UINTN  Count,\r
+  OUT     VOID   *Buffer\r
+  )\r
+{\r
+  UINT8  *Buf8;\r
+  UINTN  Index;\r
+\r
+  Buf8 = (UINT8 *)Buffer;\r
+  for (Index = 0; Index < Count; Index++) {\r
+    Buf8[Index] = TdIoRead8 (Port);\r
+  }\r
+}\r
+\r
+/**\r
+  Writes a block of memory into an 8-bit I/O port fifo.\r
+\r
+  Writes the 8-bit I/O fifo port specified by Port.\r
+  The port is written Count times, and the write data is\r
+  retrieved from the provided Buffer.\r
+\r
+  This function must guarantee that all I/O write and write operations are\r
+  serialized.\r
+\r
+  If 8-bit I/O port operations are not supported, then ASSERT().\r
+\r
+  In TDX a serial of TdIoWrite8 is invoked to write data to the I/O port.\r
+\r
+  @param  Port    The I/O port to write.\r
+  @param  Count   The number of times to write I/O port.\r
+  @param  Buffer  The buffer to retrieve the write data from.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+TdIoWriteFifo8 (\r
+  IN      UINTN  Port,\r
+  IN      UINTN  Count,\r
+  IN      VOID   *Buffer\r
+  )\r
+{\r
+  UINT8  *Buf8;\r
+  UINTN  Index;\r
+\r
+  Buf8 = (UINT8 *)Buffer;\r
+  for (Index = 0; Index < Count; Index++) {\r
+    TdIoWrite8 (Port, Buf8[Index]);\r
+  }\r
+}\r
+\r
+/**\r
+  Reads a 16-bit I/O port fifo into a block of memory.\r
+\r
+  Reads the 16-bit I/O fifo port specified by Port.\r
+  The port is read Count times, and the read data is\r
+  stored in the provided Buffer.\r
+\r
+  This function must guarantee that all I/O read and write operations are\r
+  serialized.\r
+\r
+  If 16-bit I/O port operations are not supported, then ASSERT().\r
+\r
+  In TDX a serial of TdIoRead16 is invoked to read data from the I/O port.\r
+\r
+  @param  Port    The I/O port to read.\r
+  @param  Count   The number of times to read I/O port.\r
+  @param  Buffer  The buffer to store the read data into.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+TdIoReadFifo16 (\r
+  IN      UINTN  Port,\r
+  IN      UINTN  Count,\r
+  OUT     VOID   *Buffer\r
+  )\r
+{\r
+  UINT16  *Buf16;\r
+  UINTN   Index;\r
+\r
+  Buf16 = (UINT16 *)Buffer;\r
+  for (Index = 0; Index < Count; Index++) {\r
+    Buf16[Index] = TdIoRead16 (Port);\r
+  }\r
+}\r
+\r
+/**\r
+  Writes a block of memory into a 16-bit I/O port fifo.\r
+\r
+  Writes the 16-bit I/O fifo port specified by Port.\r
+  The port is written Count times, and the write data is\r
+  retrieved from the provided Buffer.\r
+\r
+  This function must guarantee that all I/O write and write operations are\r
+  serialized.\r
+\r
+  If 16-bit I/O port operations are not supported, then ASSERT().\r
+\r
+  In TDX a serial of TdIoWrite16 is invoked to write data to the I/O port.\r
+\r
+  @param  Port    The I/O port to write.\r
+  @param  Count   The number of times to write I/O port.\r
+  @param  Buffer  The buffer to retrieve the write data from.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+TdIoWriteFifo16 (\r
+  IN      UINTN  Port,\r
+  IN      UINTN  Count,\r
+  IN      VOID   *Buffer\r
+  )\r
+{\r
+  UINT16  *Buf16;\r
+  UINTN   Index;\r
+\r
+  Buf16 = (UINT16 *)Buffer;\r
+  for (Index = 0; Index < Count; Index++) {\r
+    TdIoWrite16 (Port, Buf16[Index]);\r
+  }\r
+}\r
+\r
+/**\r
+  Reads a 32-bit I/O port fifo into a block of memory.\r
+\r
+  Reads the 32-bit I/O fifo port specified by Port.\r
+  The port is read Count times, and the read data is\r
+  stored in the provided Buffer.\r
+\r
+  This function must guarantee that all I/O read and write operations are\r
+  serialized.\r
+\r
+  If 32-bit I/O port operations are not supported, then ASSERT().\r
+\r
+  In TDX a serial of TdIoRead32 is invoked to read data from the I/O port.\r
+\r
+  @param  Port    The I/O port to read.\r
+  @param  Count   The number of times to read I/O port.\r
+  @param  Buffer  The buffer to store the read data into.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+TdIoReadFifo32 (\r
+  IN      UINTN  Port,\r
+  IN      UINTN  Count,\r
+  OUT     VOID   *Buffer\r
+  )\r
+{\r
+  UINT32  *Buf32;\r
+  UINTN   Index;\r
+\r
+  Buf32 = (UINT32 *)Buffer;\r
+  for (Index = 0; Index < Count; Index++) {\r
+    Buf32[Index] = TdIoRead32 (Port);\r
+  }\r
+}\r
+\r
+/**\r
+  Writes a block of memory into a 32-bit I/O port fifo.\r
+\r
+  Writes the 32-bit I/O fifo port specified by Port.\r
+  The port is written Count times, and the write data is\r
+  retrieved from the provided Buffer.\r
+\r
+  This function must guarantee that all I/O write and write operations are\r
+  serialized.\r
+\r
+  If 32-bit I/O port operations are not supported, then ASSERT().\r
+\r
+  In TDX a serial of TdIoWrite32 is invoked to write data to the I/O port.\r
+\r
+  @param  Port    The I/O port to write.\r
+  @param  Count   The number of times to write I/O port.\r
+  @param  Buffer  The buffer to retrieve the write data from.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+TdIoWriteFifo32 (\r
+  IN      UINTN  Port,\r
+  IN      UINTN  Count,\r
+  IN      VOID   *Buffer\r
+  )\r
+{\r
+  UINT32  *Buf32;\r
+  UINTN   Index;\r
+\r
+  Buf32 = (UINT32 *)Buffer;\r
+  for (Index = 0; Index < Count; Index++) {\r
+    TdIoWrite32 (Port, Buf32[Index]);\r
+  }\r
+}\r