--- /dev/null
+/** @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