[edk2-devel] [PATCH 07/23] MdePkg: Update BaseIoLibIntrinsicSev to support Tdx

Min Xu min.m.xu at intel.com
Thu Aug 12 11:56:46 UTC 2021


RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429

Intel TDX architecture does not prescribe a specific software convention
to perform I/O from the guest TD. Guest TD providers have many choices to
provide I/O to the guest. The common I/O models are emulated devices,
para-virtualized devices, SRIOV devices and Direct Device assignments.

TDVF chooses para-virtualized I/O (Choice-A) which use the TDG.VP.VMCALL
function to invoke the funtions provided by the host VMM to perform I/O.
Another choice (Choice-B) is the emulation performed by the #VE handler.

There are 2 benefits of para-virtualized I/O:
1. Performance.
   VMEXIT/VMENTRY is skipped so that the performance is better than #VE
   handler.
2. De-couple with #VE handler.
   Choice-B depends on the #VE handler which means I/O is not available
   until #VE handler is installed. For example, in PEI phase #VE handler
   is installed in CpuMpPei, while communication with Qemu (via I/O port)
   happen earlier than it.

BaseIoLibIntrinsicSev.inf is the IoLib used by OvmfPkg. TDVF updates
BaseIoLibIntrinsicSev to support I/O in Td guest. Below files are updated
to support I/O in Td guest.
 - IoLib.c
 - IoLibGcc.c
 - IoLibMsc.c
 - X64/IoFifoSev.nasm

In the I/O functions of above files, if IsTdxGuest() returns TRUE, then
Td I/O routine is called, otherwise the legacy I/O routine is called.
Td I/O routines are declared in IoLibTdx.h and implemented in
IoLibInternalTdx.c.

BaseIoLibIntrinsic.inf is the IoLib used by other packages. It will not
support I/O in Td guest. But some files are shared between
BaseIoLibIntrinsic and BaseIoLibIntrinsicSev (IoLib.c is the example). So
IoLibInternalTdxNull.c is created which holds the null stub of the Td I/O
routines. IoLibInternalTdxNull.c is included in BaseIoLibIntrinsic.inf.
BaseIoLibIntrinsic.inf doesn't import TdxProbeLib/TdxLib so that the Pkgs
which include BaseIoLibIntrinsic.inf need not include TdxProbeLib/TdxLib.

BaseIoLibIntrinsicArmVirt.inf is not touched because it shares no files
with BaseIoLibIntrinsicSev.

Cc: Michael D Kinney <michael.d.kinney at intel.com>
Cc: Liming Gao <gaoliming at byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu at intel.com>
Cc: Brijesh Singh <brijesh.singh at amd.com>
Cc: Erdem Aktas <erdemaktas at google.com>
Cc: James Bottomley <jejb at linux.ibm.com>
Cc: Jiewen Yao <jiewen.yao at intel.com>
Cc: Tom Lendacky <thomas.lendacky at amd.com>
Signed-off-by: Min Xu <min.m.xu at intel.com>
---
 .../BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf |   2 +
 .../BaseIoLibIntrinsicSev.inf                 |   6 +-
 MdePkg/Library/BaseIoLibIntrinsic/IoLib.c     |  97 ++-
 MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c  |  49 +-
 .../BaseIoLibIntrinsic/IoLibInternalTdx.c     | 690 ++++++++++++++++++
 .../BaseIoLibIntrinsic/IoLibInternalTdxNull.c | 499 +++++++++++++
 MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c  |  73 +-
 MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h  | 411 +++++++++++
 .../BaseIoLibIntrinsic/X64/IoFifoSev.nasm     | 133 ++++
 9 files changed, 1911 insertions(+), 49 deletions(-)
 create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdx.c
 create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdxNull.c
 create mode 100644 MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h

diff --git a/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf b/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
index 97eeada0656e..27b15d9ae256 100644
--- a/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
+++ b/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
@@ -34,6 +34,8 @@
   IoLibMmioBuffer.c
   BaseIoLibIntrinsicInternal.h
   IoHighLevel.c
+  IoLibInternalTdxNull.c
+  IoLibTdx.h
 
 [Sources.IA32]
   IoLibGcc.c    | GCC
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf b/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf
index 34f9d1d1062f..53ff8d6fd37d 100644
--- a/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf
+++ b/MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsicSev.inf
@@ -30,17 +30,20 @@
   IoLibMmioBuffer.c
   BaseIoLibIntrinsicInternal.h
   IoHighLevel.c
+  IoLibTdx.h
 
 [Sources.IA32]
   IoLibGcc.c    | GCC
   IoLibMsc.c    | MSFT
   IoLib.c
+  IoLibInternalTdxNull.c
   Ia32/IoFifoSev.nasm
 
 [Sources.X64]
   IoLibGcc.c    | GCC
   IoLibMsc.c    | MSFT
   IoLib.c
+  IoLibInternalTdx.c
   X64/IoFifoSev.nasm
 
 [Packages]
@@ -50,4 +53,5 @@
   DebugLib
   BaseLib
   RegisterFilterLib
-
+  TdxLib
+  TdxProbeLib
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLib.c b/MdePkg/Library/BaseIoLibIntrinsic/IoLib.c
index d0d7044f0901..68298749ee56 100644
--- a/MdePkg/Library/BaseIoLibIntrinsic/IoLib.c
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLib.c
@@ -7,6 +7,7 @@
 **/
 
 #include "BaseIoLibIntrinsicInternal.h"
+#include "IoLibTdx.h"
 
 /**
   Reads a 64-bit I/O port.
@@ -70,6 +71,8 @@ IoWrite64 (
 
   If 8-bit MMIO register operations are not supported, then ASSERT().
 
+  For Td guest TDVMCALL_MMIO is invoked to read MMIO registers.
+
   @param  Address The MMIO register to read.
 
   @return The value read.
@@ -86,9 +89,13 @@ MmioRead8 (
 
   Flag = FilterBeforeMmIoRead (FilterWidth8, Address, &Value);
   if (Flag) {
-    MemoryFence ();
-    Value = *(volatile UINT8*)Address;
-    MemoryFence ();
+    if (IsTdxGuest ()) {
+      Value = TdMmioRead8 (Address);
+    } else {
+      MemoryFence ();
+      Value = *(volatile UINT8*)Address;
+      MemoryFence ();
+    }
   }
   FilterAfterMmIoRead (FilterWidth8, Address, &Value);
 
@@ -104,6 +111,8 @@ MmioRead8 (
 
   If 8-bit MMIO register operations are not supported, then ASSERT().
 
+  For Td guest TDVMCALL_MMIO is invoked to write MMIO registers.
+
   @param  Address The MMIO register to write.
   @param  Value   The value to write to the MMIO register.
 
@@ -121,9 +130,13 @@ MmioWrite8 (
 
   Flag = FilterBeforeMmIoWrite (FilterWidth8, Address, &Value);
   if (Flag) {
-    MemoryFence ();
-    *(volatile UINT8*)Address = Value;
-    MemoryFence ();
+    if (IsTdxGuest ()) {
+      TdMmioWrite8 (Address, Value);
+    } else {
+      MemoryFence ();
+      *(volatile UINT8*)Address = Value;
+      MemoryFence ();
+    }
   }
   FilterAfterMmIoWrite (FilterWidth8, Address, &Value);
 
@@ -140,6 +153,8 @@ MmioWrite8 (
   If 16-bit MMIO register operations are not supported, then ASSERT().
   If Address is not aligned on a 16-bit boundary, then ASSERT().
 
+  For Td guest TDVMCALL_MMIO is invoked to read MMIO registers.
+
   @param  Address The MMIO register to read.
 
   @return The value read.
@@ -157,9 +172,13 @@ MmioRead16 (
   ASSERT ((Address & 1) == 0);
   Flag = FilterBeforeMmIoRead (FilterWidth16, Address, &Value);
   if (Flag) {
-    MemoryFence ();
-    Value = *(volatile UINT16*)Address;
-    MemoryFence ();
+    if (IsTdxGuest ()) {
+      Value = TdMmioRead16 (Address);
+    } else {
+      MemoryFence ();
+      Value = *(volatile UINT16*)Address;
+      MemoryFence ();
+    }
   }
   FilterAfterMmIoRead (FilterWidth16, Address, &Value);
 
@@ -176,6 +195,8 @@ MmioRead16 (
   If 16-bit MMIO register operations are not supported, then ASSERT().
   If Address is not aligned on a 16-bit boundary, then ASSERT().
 
+  For Td guest TDVMCALL_MMIO is invoked to write MMIO registers.
+
   @param  Address The MMIO register to write.
   @param  Value   The value to write to the MMIO register.
 
@@ -195,9 +216,13 @@ MmioWrite16 (
 
   Flag = FilterBeforeMmIoWrite (FilterWidth16, Address, &Value);
   if (Flag) {
-    MemoryFence ();
-    *(volatile UINT16*)Address = Value;
-    MemoryFence ();
+    if (IsTdxGuest ()) {
+      TdMmioWrite16 (Address, Value);
+    } else {
+      MemoryFence ();
+      *(volatile UINT16*)Address = Value;
+      MemoryFence ();
+    }
   }
   FilterAfterMmIoWrite (FilterWidth16, Address, &Value);
 
@@ -214,6 +239,8 @@ MmioWrite16 (
   If 32-bit MMIO register operations are not supported, then ASSERT().
   If Address is not aligned on a 32-bit boundary, then ASSERT().
 
+  For Td guest TDVMCALL_MMIO is invoked to read MMIO registers.
+
   @param  Address The MMIO register to read.
 
   @return The value read.
@@ -232,9 +259,13 @@ MmioRead32 (
 
   Flag = FilterBeforeMmIoRead (FilterWidth32, Address, &Value);
   if (Flag) {
-    MemoryFence ();
-    Value = *(volatile UINT32*)Address;
-    MemoryFence ();
+    if (IsTdxGuest ()) {
+      Value = TdMmioRead32 (Address);
+    } else {
+      MemoryFence ();
+      Value = *(volatile UINT32*)Address;
+      MemoryFence ();
+    }
   }
   FilterAfterMmIoRead (FilterWidth32, Address, &Value);
 
@@ -251,6 +282,8 @@ MmioRead32 (
   If 32-bit MMIO register operations are not supported, then ASSERT().
   If Address is not aligned on a 32-bit boundary, then ASSERT().
 
+  For Td guest TDVMCALL_MMIO is invoked to write MMIO registers.
+
   @param  Address The MMIO register to write.
   @param  Value   The value to write to the MMIO register.
 
@@ -270,9 +303,13 @@ MmioWrite32 (
 
   Flag = FilterBeforeMmIoWrite (FilterWidth32, Address, &Value);
   if (Flag) {
-    MemoryFence ();
-    *(volatile UINT32*)Address = Value;
-    MemoryFence ();
+    if (IsTdxGuest ()) {
+      TdMmioWrite32 (Address, Value);
+    } else {
+      MemoryFence ();
+      *(volatile UINT32*)Address = Value;
+      MemoryFence ();
+    }
   }
   FilterAfterMmIoWrite (FilterWidth32, Address, &Value);
 
@@ -289,6 +326,8 @@ MmioWrite32 (
   If 64-bit MMIO register operations are not supported, then ASSERT().
   If Address is not aligned on a 64-bit boundary, then ASSERT().
 
+  For Td guest TDVMCALL_MMIO is invoked to read MMIO registers.
+
   @param  Address The MMIO register to read.
 
   @return The value read.
@@ -307,9 +346,13 @@ MmioRead64 (
 
   Flag = FilterBeforeMmIoRead (FilterWidth64, Address, &Value);
   if (Flag) {
-    MemoryFence ();
-    Value = *(volatile UINT64*)Address;
-    MemoryFence ();
+    if (IsTdxGuest ()) {
+      Value = TdMmioRead64 (Address);
+    } else {
+      MemoryFence ();
+      Value = *(volatile UINT64*)Address;
+      MemoryFence ();
+    }
   }
   FilterAfterMmIoRead (FilterWidth64, Address, &Value);
 
@@ -326,6 +369,8 @@ MmioRead64 (
   If 64-bit MMIO register operations are not supported, then ASSERT().
   If Address is not aligned on a 64-bit boundary, then ASSERT().
 
+  For Td guest TDVMCALL_MMIO is invoked to write MMIO registers.
+
   @param  Address The MMIO register to write.
   @param  Value   The value to write to the MMIO register.
 
@@ -343,9 +388,13 @@ MmioWrite64 (
 
   Flag = FilterBeforeMmIoWrite (FilterWidth64, Address, &Value);
   if (Flag) {
-    MemoryFence ();
-    *(volatile UINT64*)Address = Value;
-    MemoryFence ();
+    if (IsTdxGuest ()) {
+      TdMmioWrite64 (Address, Value);
+    } else {
+      MemoryFence ();
+      *(volatile UINT64*)Address = Value;
+      MemoryFence ();
+    }
   }
   FilterAfterMmIoWrite (FilterWidth64, Address, &Value);
 
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c b/MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c
index ecf9ed61911f..42b5d5743a4f 100644
--- a/MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c
@@ -17,6 +17,7 @@
 
 
 #include "BaseIoLibIntrinsicInternal.h"
+#include "IoLibTdx.h"
 
 /**
   Reads an 8-bit I/O port.
@@ -25,7 +26,9 @@
   This function must guarantee that all I/O read and write operations are
   serialized.
 
-  If 8-bit I/O port operations are not supported, then ASSERT().
+  If 8-bit I/O port operations are not supported, then ASSERT()
+
+  For Td guest TDVMCALL_IO is invoked to read I/O port.
 
   @param  Port  The I/O port to read.
 
@@ -43,7 +46,11 @@ IoRead8 (
 
   Flag = FilterBeforeIoRead (FilterWidth8, Port, &Data);
   if (Flag) {
-    __asm__ __volatile__ ("inb %w1,%b0" : "=a" (Data) : "d" ((UINT16)Port));
+    if (IsTdxGuest ()) {
+      Data = TdIoRead8 (Port);
+    } else {
+      __asm__ __volatile__ ("inb %w1,%b0" : "=a" (Data) : "d" ((UINT16)Port));
+    }
   }
   FilterAfterIoRead (FilterWidth8, Port, &Data);
 
@@ -59,6 +66,8 @@ IoRead8 (
 
   If 8-bit I/O port operations are not supported, then ASSERT().
 
+  For Td guest TDVMCALL_IO is invoked to write I/O port.
+
   @param  Port  The I/O port to write.
   @param  Value The value to write to the I/O port.
 
@@ -76,7 +85,11 @@ IoWrite8 (
 
   Flag = FilterBeforeIoWrite (FilterWidth8, Port, &Value);
   if (Flag) {
-    __asm__ __volatile__ ("outb %b0,%w1" : : "a" (Value), "d" ((UINT16)Port));
+    if (IsTdxGuest ()) {
+      TdIoWrite8 (Port, Value);
+    } else {
+      __asm__ __volatile__ ("outb %b0,%w1" : : "a" (Value), "d" ((UINT16)Port));
+    }
   }
   FilterAfterIoWrite (FilterWidth8, Port, &Value);
 
@@ -93,6 +106,8 @@ IoWrite8 (
   If 16-bit I/O port operations are not supported, then ASSERT().
   If Port is not aligned on a 16-bit boundary, then ASSERT().
 
+  For Td guest TDVMCALL_IO is invoked to read I/O port.
+
   @param  Port  The I/O port to read.
 
   @return The value read.
@@ -111,7 +126,11 @@ IoRead16 (
 
   Flag = FilterBeforeIoRead (FilterWidth16, Port, &Data);
   if (Flag) {
+    if (IsTdxGuest ()) {
+      Data = TdIoRead16 (Port);
+    } else {
      __asm__ __volatile__ ("inw %w1,%w0" : "=a" (Data) : "d" ((UINT16)Port));
+    }
   }
   FilterAfterIoRead (FilterWidth16, Port, &Data);
 
@@ -128,6 +147,8 @@ IoRead16 (
   If 16-bit I/O port operations are not supported, then ASSERT().
   If Port is not aligned on a 16-bit boundary, then ASSERT().
 
+  For Td guest TDVMCALL_IO is invoked to write I/O port.
+
   @param  Port  The I/O port to write.
   @param  Value The value to write to the I/O port.
 
@@ -148,7 +169,11 @@ IoWrite16 (
 
   Flag = FilterBeforeIoWrite (FilterWidth16, Port, &Value);
   if (Flag) {
-    __asm__ __volatile__ ("outw %w0,%w1" : : "a" (Value), "d" ((UINT16)Port));
+    if (IsTdxGuest ()) {
+      TdIoWrite16 (Port, Value);
+    } else {
+      __asm__ __volatile__ ("outw %w0,%w1" : : "a" (Value), "d" ((UINT16)Port));
+    }
   }
   FilterAfterIoWrite (FilterWidth16, Port, &Value);
 
@@ -165,6 +190,8 @@ IoWrite16 (
   If 32-bit I/O port operations are not supported, then ASSERT().
   If Port is not aligned on a 32-bit boundary, then ASSERT().
 
+  For Td guest TDVMCALL_IO is invoked to read I/O port.
+
   @param  Port  The I/O port to read.
 
   @return The value read.
@@ -183,7 +210,11 @@ IoRead32 (
 
   Flag = FilterBeforeIoRead (FilterWidth32, Port, &Data);
   if (Flag) {
-    __asm__ __volatile__ ("inl %w1,%0" : "=a" (Data) : "d" ((UINT16)Port));
+    if (IsTdxGuest ()) {
+      Data = TdIoRead32 (Port);
+    } else {
+      __asm__ __volatile__ ("inl %w1,%0" : "=a" (Data) : "d" ((UINT16)Port));
+    }
   }
   FilterAfterIoRead (FilterWidth32, Port, &Data);
 
@@ -200,6 +231,8 @@ IoRead32 (
   If 32-bit I/O port operations are not supported, then ASSERT().
   If Port is not aligned on a 32-bit boundary, then ASSERT().
 
+  For Td guest TDVMCALL_IO is invoked to write I/O port.
+
   @param  Port  The I/O port to write.
   @param  Value The value to write to the I/O port.
 
@@ -219,7 +252,11 @@ IoWrite32 (
 
   Flag = FilterBeforeIoWrite (FilterWidth32, Port, &Value);
   if (Flag) {
-    __asm__ __volatile__ ("outl %0,%w1" : : "a" (Value), "d" ((UINT16)Port));
+    if (IsTdxGuest ()) {
+      TdIoWrite32 (Port, Value);
+    } else {
+      __asm__ __volatile__ ("outl %0,%w1" : : "a" (Value), "d" ((UINT16)Port));
+    }
   }
   FilterAfterIoWrite (FilterWidth32, Port, &Value);
 
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdx.c b/MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdx.c
new file mode 100644
index 000000000000..4c342f6d3873
--- /dev/null
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdx.c
@@ -0,0 +1,690 @@
+/** @file
+  TDX I/O Library routines.
+
+  Copyright (c) 2020-2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include "BaseIoLibIntrinsicInternal.h"
+#include <Include/IndustryStandard/Tdx.h>
+#include <Library/TdxLib.h>
+#include <Library/TdxProbeLib.h>
+#include "IoLibTdx.h"
+
+// Size of TDVMCALL Access, including IO and MMIO
+#define TDVMCALL_ACCESS_SIZE_1      1
+#define TDVMCALL_ACCESS_SIZE_2      2
+#define TDVMCALL_ACCESS_SIZE_4      4
+#define TDVMCALL_ACCESS_SIZE_8      8
+
+// Direction of TDVMCALL Access, including IO and MMIO
+#define TDVMCALL_ACCESS_READ        0
+#define TDVMCALL_ACCESS_WRITE       1
+
+/**
+  Check if it is Tdx guest.
+
+  @return TRUE    It is Tdx guest
+  @return FALSE   It is not Tdx guest
+
+**/
+BOOLEAN
+EFIAPI
+IsTdxGuest (
+  VOID
+  )
+{
+  return TdxIsEnabled ();
+}
+
+
+/**
+  Reads an 8-bit I/O port.
+
+  TDVMCALL_IO is invoked to read I/O port.
+
+  @param  Port  The I/O port to read.
+
+  @return The value read.
+
+**/
+UINT8
+EFIAPI
+TdIoRead8 (
+  IN      UINTN                     Port
+  )
+{
+  UINT64 Status;
+  UINT64 Val;
+
+  Status = TdVmCall (TDVMCALL_IO, TDVMCALL_ACCESS_SIZE_1, TDVMCALL_ACCESS_READ, Port, 0, &Val);
+  if (Status != 0) {
+    TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+  }
+  return (UINT8) Val;
+}
+
+/**
+  Reads a 16-bit I/O port.
+
+  TDVMCALL_IO is invoked to write I/O port.
+
+  @param  Port  The I/O port to read.
+
+  @return The value read.
+
+**/
+UINT16
+EFIAPI
+TdIoRead16 (
+  IN      UINTN                     Port
+  )
+{
+  UINT64 Status;
+  UINT64 Val;
+
+  ASSERT ((Port & 1) == 0);
+
+  Status = TdVmCall (TDVMCALL_IO, TDVMCALL_ACCESS_SIZE_2, TDVMCALL_ACCESS_READ, Port, 0, &Val);
+  if (Status != 0) {
+    TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+  }
+  return (UINT16) Val;
+}
+
+/**
+  Reads a 32-bit I/O port.
+
+  TDVMCALL_IO is invoked to read I/O port.
+
+  @param  Port  The I/O port to read.
+
+  @return The value read.
+
+**/
+UINT32
+EFIAPI
+TdIoRead32 (
+  IN      UINTN                     Port
+  )
+{
+  UINT64 Status;
+  UINT64 Val;
+
+  ASSERT ((Port & 3) == 0);
+
+  Status = TdVmCall (TDVMCALL_IO, TDVMCALL_ACCESS_SIZE_4, TDVMCALL_ACCESS_READ, Port, 0, &Val);
+  if (Status != 0) {
+    TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+  }
+  return (UINT32) Val;
+}
+
+/**
+  Writes an 8-bit I/O port.
+
+  TDVMCALL_IO is invoked to write I/O port.
+
+  @param  Port  The I/O port to write.
+  @param  Value The value to write to the I/O port.
+
+  @return The value written the I/O port.
+
+**/
+UINT8
+EFIAPI
+TdIoWrite8 (
+  IN      UINTN                     Port,
+  IN      UINT8                     Value
+  )
+{
+  UINT64 Status;
+  UINT64 Val;
+
+  Val = Value;
+  Status = TdVmCall (TDVMCALL_IO, TDVMCALL_ACCESS_SIZE_1, TDVMCALL_ACCESS_WRITE, Port, Val, 0);
+  if (Status != 0) {
+    TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+  }
+  return Value;
+}
+
+/**
+  Writes a 16-bit I/O port.
+
+  TDVMCALL_IO is invoked to write I/O port.
+
+  @param  Port  The I/O port to write.
+  @param  Value The value to write to the I/O port.
+
+  @return The value written the I/O port.
+
+**/
+UINT16
+EFIAPI
+TdIoWrite16 (
+  IN      UINTN                     Port,
+  IN      UINT16                    Value
+  )
+{
+  UINT64 Status;
+  UINT64 Val;
+
+  ASSERT ((Port & 1) == 0);
+  Val = Value;
+  Status = TdVmCall (TDVMCALL_IO, TDVMCALL_ACCESS_SIZE_2, TDVMCALL_ACCESS_WRITE, Port, Val, 0);
+  if (Status != 0) {
+    TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+  }
+  return Value;
+}
+
+/**
+  Writes a 32-bit I/O port.
+
+  TDVMCALL_IO is invoked to write I/O port.
+
+  @param  Port  The I/O port to write.
+  @param  Value The value to write to the I/O port.
+
+  @return The value written the I/O port.
+
+**/
+UINT32
+EFIAPI
+TdIoWrite32 (
+  IN      UINTN                     Port,
+  IN      UINT32                    Value
+  )
+{
+  UINT64 Status;
+  UINT64 Val;
+
+  ASSERT ((Port & 3) == 0);
+  Val = Value;
+  Status = TdVmCall (TDVMCALL_IO, TDVMCALL_ACCESS_SIZE_4, TDVMCALL_ACCESS_WRITE, Port, Val, 0);
+  if (Status != 0) {
+    TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
+  }
+  return Value;
+}
+
+/**
+  Reads an 8-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to read MMIO registers.
+
+  @param  Address The MMIO register to read.
+
+  @return The value read.
+
+**/
+UINT8
+EFIAPI
+TdMmioRead8 (
+  IN      UINTN                     Address
+  )
+{
+  UINT64                             Value;
+  UINT64                             Status;
+
+  Address |= TdSharedPageMask ();
+
+  MemoryFence ();
+  Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_1, TDVMCALL_ACCESS_READ, Address, 0, &Value);
+  if (Status != 0) {
+    Value = *(volatile UINT64*) Address;
+  }
+  MemoryFence ();
+
+  return (UINT8) Value;
+}
+
+/**
+  Writes an 8-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to read write registers.
+
+  @param  Address The MMIO register to write.
+  @param  Value   The value to write to the MMIO register.
+
+  @return Value.
+
+**/
+UINT8
+EFIAPI
+TdMmioWrite8 (
+  IN      UINTN                     Address,
+  IN      UINT8                     Value
+  )
+{
+  UINT64                             Val;
+  UINT64                             Status;
+
+  Address |= TdSharedPageMask ();
+
+  MemoryFence ();
+  Val = Value;
+  Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_1, TDVMCALL_ACCESS_WRITE, Address, Val, 0);
+  if (Status != 0) {
+    *(volatile UINT8*) Address = Value;
+  }
+  MemoryFence ();
+
+  return Value;
+}
+
+/**
+  Reads a 16-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to read MMIO registers.
+
+  @param  Address The MMIO register to read.
+
+  @return The value read.
+
+**/
+UINT16
+EFIAPI
+TdMmioRead16 (
+  IN      UINTN                     Address
+  )
+{
+  UINT64                             Value;
+  UINT64                             Status;
+
+  Address |= TdSharedPageMask ();
+
+  MemoryFence ();
+  Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_2, TDVMCALL_ACCESS_READ, Address, 0, &Value);
+  if (Status != 0) {
+    Value = *(volatile UINT64*) Address;
+  }
+  MemoryFence ();
+
+  return (UINT16) Value;
+}
+
+/**
+  Writes a 16-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to write MMIO registers.
+
+  @param  Address The MMIO register to write.
+  @param  Value   The value to write to the MMIO register.
+
+  @return Value.
+
+**/
+UINT16
+EFIAPI
+TdMmioWrite16 (
+  IN      UINTN                     Address,
+  IN      UINT16                    Value
+  )
+{
+  UINT64                             Val;
+  UINT64                             Status;
+
+  ASSERT ((Address & 1) == 0);
+
+  Address |= TdSharedPageMask ();
+
+  MemoryFence ();
+  Val = Value;
+  Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_2, TDVMCALL_ACCESS_WRITE, Address, Val, 0);
+  if (Status != 0) {
+    *(volatile UINT16*) Address = Value;
+  }
+  MemoryFence ();
+
+  return Value;
+}
+
+/**
+  Reads a 32-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to read MMIO registers.
+
+  @param  Address The MMIO register to read.
+
+  @return The value read.
+
+**/
+UINT32
+EFIAPI
+TdMmioRead32 (
+  IN      UINTN                     Address
+  )
+{
+  UINT64                             Value;
+  UINT64                             Status;
+
+  Address |= TdSharedPageMask ();
+
+  MemoryFence ();
+  Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_4, TDVMCALL_ACCESS_READ, Address, 0, &Value);
+  if (Status != 0) {
+    Value = *(volatile UINT64*)Address;
+  }
+  MemoryFence ();
+
+  return (UINT32)Value;
+}
+
+/**
+  Writes a 32-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to write MMIO registers.
+
+  @param  Address The MMIO register to write.
+  @param  Value   The value to write to the MMIO register.
+
+  @return Value.
+
+**/
+UINT32
+EFIAPI
+TdMmioWrite32 (
+  IN      UINTN                     Address,
+  IN      UINT32                    Value
+  )
+{
+  UINT64                             Val;
+  UINT64                             Status;
+
+  ASSERT ((Address & 3) == 0);
+
+  Address |= TdSharedPageMask ();
+
+  MemoryFence ();
+  Val = Value;
+  Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_4, TDVMCALL_ACCESS_WRITE, Address, Val, 0);
+  if (Status != 0) {
+    *(volatile UINT32*)Address = Value;
+  }
+  MemoryFence ();
+
+  return Value;
+}
+
+/**
+  Reads a 64-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to read MMIO registers.
+
+  @param  Address The MMIO register to read.
+
+  @return The value read.
+
+**/
+UINT64
+EFIAPI
+TdMmioRead64 (
+  IN      UINTN                     Address
+  )
+{
+  UINT64                             Value;
+  UINT64                             Status;
+
+  Address |= TdSharedPageMask ();
+
+  MemoryFence ();
+  Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_8, TDVMCALL_ACCESS_READ, Address, 0, &Value);
+  if (Status != 0) {
+    Value = *(volatile UINT64*)Address;
+  }
+  MemoryFence ();
+
+  return Value;
+}
+
+/**
+  Writes a 64-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to write MMIO registers.
+
+  @param  Address The MMIO register to write.
+  @param  Value   The value to write to the MMIO register.
+
+**/
+UINT64
+EFIAPI
+TdMmioWrite64 (
+  IN      UINTN                     Address,
+  IN      UINT64                    Value
+  )
+{
+  UINT64          Status;
+  UINT64          Val;
+
+  ASSERT ((Address & 7) == 0);
+
+  Address |= TdSharedPageMask ();
+
+  MemoryFence ();
+  Val = Value;
+  Status = TdVmCall (TDVMCALL_MMIO, TDVMCALL_ACCESS_SIZE_8, TDVMCALL_ACCESS_WRITE, Address, Val, 0);
+  if (Status != 0) {
+    *(volatile UINT64*)Address = Value;
+  }
+  MemoryFence ();
+  return Value;
+}
+
+/**
+  Reads an 8-bit I/O port fifo into a block of memory.
+
+  Reads the 8-bit I/O fifo port specified by Port.
+  The port is read Count times, and the read data is
+  stored in the provided Buffer.
+
+  This function must guarantee that all I/O read and write operations are
+  serialized.
+
+  If 8-bit I/O port operations are not supported, then ASSERT().
+
+  In TDX a serial of TdIoRead8 is invoked to read the I/O port fifo.
+
+  @param  Port    The I/O port to read.
+  @param  Count   The number of times to read I/O port.
+  @param  Buffer  The buffer to store the read data into.
+
+**/
+VOID
+EFIAPI
+TdIoReadFifo8 (
+  IN      UINTN                     Port,
+  IN      UINTN                     Count,
+  OUT     VOID                      *Buffer
+  )
+{
+  UINT8   *Buf8;
+  UINTN   Index;
+
+  Buf8 = (UINT8 *) Buffer;
+  for (Index = 0; Index < Count; Index++) {
+    Buf8[Index] = TdIoRead8 (Port);
+  }
+}
+
+/**
+  Writes a block of memory into an 8-bit I/O port fifo.
+
+  Writes the 8-bit I/O fifo port specified by Port.
+  The port is written Count times, and the write data is
+  retrieved from the provided Buffer.
+
+  This function must guarantee that all I/O write and write operations are
+  serialized.
+
+  If 8-bit I/O port operations are not supported, then ASSERT().
+
+  In TDX a serial of TdIoWrite8 is invoked to write data to the I/O port.
+
+  @param  Port    The I/O port to write.
+  @param  Count   The number of times to write I/O port.
+  @param  Buffer  The buffer to retrieve the write data from.
+
+**/
+VOID
+EFIAPI
+TdIoWriteFifo8 (
+  IN      UINTN                     Port,
+  IN      UINTN                     Count,
+  IN      VOID                      *Buffer
+  )
+{
+  UINT8   *Buf8;
+  UINTN   Index;
+
+  Buf8 = (UINT8 *) Buffer;
+  for (Index = 0; Index < Count; Index++) {
+    TdIoWrite8 (Port, Buf8[Index]);
+  }
+}
+
+/**
+  Reads a 16-bit I/O port fifo into a block of memory.
+
+  Reads the 16-bit I/O fifo port specified by Port.
+  The port is read Count times, and the read data is
+  stored in the provided Buffer.
+
+  This function must guarantee that all I/O read and write operations are
+  serialized.
+
+  If 16-bit I/O port operations are not supported, then ASSERT().
+
+  In TDX a serial of TdIoRead16 is invoked to read data from the I/O port.
+
+  @param  Port    The I/O port to read.
+  @param  Count   The number of times to read I/O port.
+  @param  Buffer  The buffer to store the read data into.
+
+**/
+VOID
+EFIAPI
+TdIoReadFifo16 (
+  IN      UINTN                     Port,
+  IN      UINTN                     Count,
+  OUT     VOID                      *Buffer
+  )
+{
+  UINT16      *Buf16;
+  UINTN       Index;
+
+  Buf16 = (UINT16 *) Buffer;
+  for (Index = 0; Index < Count; Index++) {
+    Buf16[Index] = TdIoRead16 (Port);
+  }
+}
+
+/**
+  Writes a block of memory into a 16-bit I/O port fifo.
+
+  Writes the 16-bit I/O fifo port specified by Port.
+  The port is written Count times, and the write data is
+  retrieved from the provided Buffer.
+
+  This function must guarantee that all I/O write and write operations are
+  serialized.
+
+  If 16-bit I/O port operations are not supported, then ASSERT().
+
+  In TDX a serial of TdIoWrite16 is invoked to write data to the I/O port.
+
+  @param  Port    The I/O port to write.
+  @param  Count   The number of times to write I/O port.
+  @param  Buffer  The buffer to retrieve the write data from.
+
+**/
+VOID
+EFIAPI
+TdIoWriteFifo16 (
+  IN      UINTN                     Port,
+  IN      UINTN                     Count,
+  IN      VOID                      *Buffer
+  )
+{
+  UINT16   *Buf16;
+  UINTN    Index;
+
+  Buf16 = (UINT16 *) Buffer;
+  for (Index = 0; Index < Count; Index++) {
+    TdIoWrite16 (Port, Buf16[Index]);
+  }
+}
+
+/**
+  Reads a 32-bit I/O port fifo into a block of memory.
+
+  Reads the 32-bit I/O fifo port specified by Port.
+  The port is read Count times, and the read data is
+  stored in the provided Buffer.
+
+  This function must guarantee that all I/O read and write operations are
+  serialized.
+
+  If 32-bit I/O port operations are not supported, then ASSERT().
+
+  In TDX a serial of TdIoRead32 is invoked to read data from the I/O port.
+
+  @param  Port    The I/O port to read.
+  @param  Count   The number of times to read I/O port.
+  @param  Buffer  The buffer to store the read data into.
+
+**/
+VOID
+EFIAPI
+TdIoReadFifo32 (
+  IN      UINTN                     Port,
+  IN      UINTN                     Count,
+  OUT     VOID                      *Buffer
+  )
+{
+  UINT32      *Buf32;
+  UINTN       Index;
+
+  Buf32 = (UINT32 *) Buffer;
+  for (Index = 0; Index < Count; Index++) {
+    Buf32[Index] = TdIoRead32 (Port);
+  }
+}
+
+/**
+  Writes a block of memory into a 32-bit I/O port fifo.
+
+  Writes the 32-bit I/O fifo port specified by Port.
+  The port is written Count times, and the write data is
+  retrieved from the provided Buffer.
+
+  This function must guarantee that all I/O write and write operations are
+  serialized.
+
+  If 32-bit I/O port operations are not supported, then ASSERT().
+
+  In TDX a serial of TdIoWrite32 is invoked to write data to the I/O port.
+
+  @param  Port    The I/O port to write.
+  @param  Count   The number of times to write I/O port.
+  @param  Buffer  The buffer to retrieve the write data from.
+
+**/
+VOID
+EFIAPI
+TdIoWriteFifo32 (
+  IN      UINTN                     Port,
+  IN      UINTN                     Count,
+  IN      VOID                      *Buffer
+  )
+{
+  UINT32   *Buf32;
+  UINTN    Index;
+
+  Buf32 = (UINT32 *) Buffer;
+  for (Index = 0; Index < Count; Index++) {
+    TdIoWrite32 (Port, Buf32[Index]);
+  }
+}
+
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdxNull.c b/MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdxNull.c
new file mode 100644
index 000000000000..f518d8ffd825
--- /dev/null
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibInternalTdxNull.c
@@ -0,0 +1,499 @@
+/** @file
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include <Library/BaseLib.h>
+#include "BaseIoLibIntrinsicInternal.h"
+#include "IoLibTdx.h"
+
+/**
+  Check if it is Tdx guest.
+
+  @return TRUE    It is Tdx guest
+  @return FALSE   It is not Tdx guest
+
+**/
+BOOLEAN
+EFIAPI
+IsTdxGuest (
+  VOID
+  )
+{
+  return FALSE;
+}
+
+
+/**
+  Reads an 8-bit I/O port.
+
+  TDVMCALL_IO is invoked to read I/O port.
+
+  @param  Port  The I/O port to read.
+
+  @return The value read.
+
+**/
+UINT8
+EFIAPI
+TdIoRead8 (
+  IN      UINTN                     Port
+  )
+{
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Reads a 16-bit I/O port.
+
+  TDVMCALL_IO is invoked to write I/O port.
+
+  @param  Port  The I/O port to read.
+
+  @return The value read.
+
+**/
+UINT16
+EFIAPI
+TdIoRead16 (
+  IN      UINTN                     Port
+  )
+{
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Reads a 32-bit I/O port.
+
+  TDVMCALL_IO is invoked to read I/O port.
+
+  @param  Port  The I/O port to read.
+
+  @return The value read.
+
+**/
+UINT32
+EFIAPI
+TdIoRead32 (
+  IN      UINTN                     Port
+  )
+{
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Writes an 8-bit I/O port.
+
+  TDVMCALL_IO is invoked to write I/O port.
+
+  @param  Port  The I/O port to write.
+  @param  Value The value to write to the I/O port.
+
+  @return The value written the I/O port.
+
+**/
+UINT8
+EFIAPI
+TdIoWrite8 (
+  IN      UINTN                     Port,
+  IN      UINT8                     Value
+  )
+{
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Writes a 16-bit I/O port.
+
+  TDVMCALL_IO is invoked to write I/O port.
+
+  @param  Port  The I/O port to write.
+  @param  Value The value to write to the I/O port.
+
+  @return The value written the I/O port.
+
+**/
+UINT16
+EFIAPI
+TdIoWrite16 (
+  IN      UINTN                     Port,
+  IN      UINT16                    Value
+  )
+{
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Writes a 32-bit I/O port.
+
+  TDVMCALL_IO is invoked to write I/O port.
+
+  @param  Port  The I/O port to write.
+  @param  Value The value to write to the I/O port.
+
+  @return The value written the I/O port.
+
+**/
+UINT32
+EFIAPI
+TdIoWrite32 (
+  IN      UINTN                     Port,
+  IN      UINT32                    Value
+  )
+{
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Reads an 8-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to read MMIO registers.
+
+  @param  Address The MMIO register to read.
+
+  @return The value read.
+
+**/
+UINT8
+EFIAPI
+TdMmioRead8 (
+  IN      UINTN                     Address
+  )
+{
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Writes an 8-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to read write registers.
+
+  @param  Address The MMIO register to write.
+  @param  Value   The value to write to the MMIO register.
+
+  @return Value.
+
+**/
+UINT8
+EFIAPI
+TdMmioWrite8 (
+  IN      UINTN                     Address,
+  IN      UINT8                     Val
+  )
+{
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Reads a 16-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to read MMIO registers.
+
+  @param  Address The MMIO register to read.
+
+  @return The value read.
+
+**/
+UINT16
+EFIAPI
+TdMmioRead16 (
+  IN      UINTN                     Address
+  )
+{
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Writes a 16-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to write MMIO registers.
+
+  @param  Address The MMIO register to write.
+  @param  Value   The value to write to the MMIO register.
+
+  @return Value.
+
+**/
+UINT16
+EFIAPI
+TdMmioWrite16 (
+  IN      UINTN                     Address,
+  IN      UINT16                    Val
+  )
+{
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Reads a 32-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to read MMIO registers.
+
+  @param  Address The MMIO register to read.
+
+  @return The value read.
+
+**/
+UINT32
+EFIAPI
+TdMmioRead32 (
+  IN      UINTN                     Address
+  )
+{
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Writes a 32-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to write MMIO registers.
+
+  @param  Address The MMIO register to write.
+  @param  Value   The value to write to the MMIO register.
+
+  @return Value.
+
+**/
+UINT32
+EFIAPI
+TdMmioWrite32 (
+  IN      UINTN                     Address,
+  IN      UINT32                    Val
+  )
+{
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Reads a 64-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to read MMIO registers.
+
+  @param  Address The MMIO register to read.
+
+  @return The value read.
+
+**/
+UINT64
+EFIAPI
+TdMmioRead64 (
+  IN      UINTN                     Address
+  )
+{
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Writes a 64-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to write MMIO registers.
+
+  @param  Address The MMIO register to write.
+  @param  Value   The value to write to the MMIO register.
+
+**/
+UINT64
+EFIAPI
+TdMmioWrite64 (
+  IN      UINTN                     Address,
+  IN      UINT64                    Value
+  )
+{
+  ASSERT (FALSE);
+  return 0;
+}
+
+/**
+  Reads an 8-bit I/O port fifo into a block of memory.
+
+  Reads the 8-bit I/O fifo port specified by Port.
+  The port is read Count times, and the read data is
+  stored in the provided Buffer.
+
+  This function must guarantee that all I/O read and write operations are
+  serialized.
+
+  If 8-bit I/O port operations are not supported, then ASSERT().
+
+  In TDX a serial of TdIoRead8 is invoked to read the I/O port fifo.
+
+  @param  Port    The I/O port to read.
+  @param  Count   The number of times to read I/O port.
+  @param  Buffer  The buffer to store the read data into.
+
+**/
+VOID
+EFIAPI
+TdIoReadFifo8 (
+  IN      UINTN                     Port,
+  IN      UINTN                     Count,
+  OUT     VOID                      *Buffer
+  )
+{
+  ASSERT (FALSE);
+}
+
+/**
+  Writes a block of memory into an 8-bit I/O port fifo.
+
+  Writes the 8-bit I/O fifo port specified by Port.
+  The port is written Count times, and the write data is
+  retrieved from the provided Buffer.
+
+  This function must guarantee that all I/O write and write operations are
+  serialized.
+
+  If 8-bit I/O port operations are not supported, then ASSERT().
+
+  In TDX a serial of TdIoWrite8 is invoked to write data to the I/O port.
+
+  @param  Port    The I/O port to write.
+  @param  Count   The number of times to write I/O port.
+  @param  Buffer  The buffer to retrieve the write data from.
+
+**/
+VOID
+EFIAPI
+TdIoWriteFifo8 (
+  IN      UINTN                     Port,
+  IN      UINTN                     Count,
+  IN      VOID                      *Buffer
+  )
+{
+  ASSERT (FALSE);
+}
+
+/**
+  Reads a 16-bit I/O port fifo into a block of memory.
+
+  Reads the 16-bit I/O fifo port specified by Port.
+  The port is read Count times, and the read data is
+  stored in the provided Buffer.
+
+  This function must guarantee that all I/O read and write operations are
+  serialized.
+
+  If 16-bit I/O port operations are not supported, then ASSERT().
+
+  In TDX a serial of TdIoRead16 is invoked to read data from the I/O port.
+
+  @param  Port    The I/O port to read.
+  @param  Count   The number of times to read I/O port.
+  @param  Buffer  The buffer to store the read data into.
+
+**/
+VOID
+EFIAPI
+TdIoReadFifo16 (
+  IN      UINTN                     Port,
+  IN      UINTN                     Count,
+  OUT     VOID                      *Buffer
+  )
+{
+  ASSERT (FALSE);
+}
+
+/**
+  Writes a block of memory into a 16-bit I/O port fifo.
+
+  Writes the 16-bit I/O fifo port specified by Port.
+  The port is written Count times, and the write data is
+  retrieved from the provided Buffer.
+
+  This function must guarantee that all I/O write and write operations are
+  serialized.
+
+  If 16-bit I/O port operations are not supported, then ASSERT().
+
+  In TDX a serial of TdIoWrite16 is invoked to write data to the I/O port.
+
+  @param  Port    The I/O port to write.
+  @param  Count   The number of times to write I/O port.
+  @param  Buffer  The buffer to retrieve the write data from.
+
+**/
+VOID
+EFIAPI
+TdIoWriteFifo16 (
+  IN      UINTN                     Port,
+  IN      UINTN                     Count,
+  IN      VOID                      *Buffer
+  )
+{
+  ASSERT (FALSE);
+}
+
+/**
+  Reads a 32-bit I/O port fifo into a block of memory.
+
+  Reads the 32-bit I/O fifo port specified by Port.
+  The port is read Count times, and the read data is
+  stored in the provided Buffer.
+
+  This function must guarantee that all I/O read and write operations are
+  serialized.
+
+  If 32-bit I/O port operations are not supported, then ASSERT().
+
+  In TDX a serial of TdIoRead32 is invoked to read data from the I/O port.
+
+  @param  Port    The I/O port to read.
+  @param  Count   The number of times to read I/O port.
+  @param  Buffer  The buffer to store the read data into.
+
+**/
+VOID
+EFIAPI
+TdIoReadFifo32 (
+  IN      UINTN                     Port,
+  IN      UINTN                     Count,
+  OUT     VOID                      *Buffer
+  )
+{
+  ASSERT (FALSE);
+}
+
+/**
+  Writes a block of memory into a 32-bit I/O port fifo.
+
+  Writes the 32-bit I/O fifo port specified by Port.
+  The port is written Count times, and the write data is
+  retrieved from the provided Buffer.
+
+  This function must guarantee that all I/O write and write operations are
+  serialized.
+
+  If 32-bit I/O port operations are not supported, then ASSERT().
+
+  In TDX a serial of TdIoWrite32 is invoked to write data to the I/O port.
+
+  @param  Port    The I/O port to write.
+  @param  Count   The number of times to write I/O port.
+  @param  Buffer  The buffer to retrieve the write data from.
+
+**/
+VOID
+EFIAPI
+TdIoWriteFifo32 (
+  IN      UINTN                     Port,
+  IN      UINTN                     Count,
+  IN      VOID                      *Buffer
+  )
+{
+  ASSERT (FALSE);
+}
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c b/MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c
index d2bc5f527cf6..4d7945ae496f 100644
--- a/MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c
@@ -16,6 +16,7 @@
 
 
 #include "BaseIoLibIntrinsicInternal.h"
+#include "IoLibTdx.h"
 
 //
 // Microsoft Visual Studio 7.1 Function Prototypes for I/O Intrinsics.
@@ -54,6 +55,8 @@ void          _ReadWriteBarrier (void);
 
   If 8-bit I/O port operations are not supported, then ASSERT().
 
+  For Td guest TDVMCALL_IO is invoked to read I/O port.
+
   @param  Port  The I/O port to read.
 
   @return The value read.
@@ -70,9 +73,13 @@ IoRead8 (
 
   Flag = FilterBeforeIoRead (FilterWidth8, Port, &Value);
   if (Flag) {
-    _ReadWriteBarrier ();
-    Value = (UINT8)_inp ((UINT16)Port);
-    _ReadWriteBarrier ();
+    if (IsTdxGuest ()) {
+      Value = TdIoRead8 (Port);
+    } else {
+      _ReadWriteBarrier ();
+      Value = (UINT8)_inp ((UINT16)Port);
+      _ReadWriteBarrier ();
+    }
   }
   FilterAfterIoRead (FilterWidth8, Port, &Value);
 
@@ -88,6 +95,8 @@ IoRead8 (
 
   If 8-bit I/O port operations are not supported, then ASSERT().
 
+  For Td guest TDVMCALL_IO is invoked to write I/O port.
+
   @param  Port  The I/O port to write.
   @param  Value The value to write to the I/O port.
 
@@ -105,9 +114,13 @@ IoWrite8 (
 
   Flag = FilterBeforeIoWrite(FilterWidth8, Port, &Value);
   if (Flag) {
-    _ReadWriteBarrier ();
-    (UINT8)_outp ((UINT16)Port, Value);
-    _ReadWriteBarrier ();
+    if (IsTdxGuest ()) {
+      TdIoWrite8 (Port, Value);
+    } else {
+      _ReadWriteBarrier ();
+      (UINT8)_outp ((UINT16)Port, Value);
+      _ReadWriteBarrier ();
+    }
   }
   FilterAfterIoWrite (FilterWidth8, Port, &Value);
 
@@ -124,6 +137,8 @@ IoWrite8 (
   If 16-bit I/O port operations are not supported, then ASSERT().
   If Port is not aligned on a 16-bit boundary, then ASSERT().
 
+  For Td guest TDVMCALL_IO is invoked to read I/O port.
+
   @param  Port  The I/O port to read.
 
   @return The value read.
@@ -142,9 +157,13 @@ IoRead16 (
 
   Flag = FilterBeforeIoRead (FilterWidth16, Port, &Value);
   if (Flag) {
-    _ReadWriteBarrier ();
-    Value = _inpw ((UINT16)Port);
-    _ReadWriteBarrier ();
+    if (IsTdxGuest ()) {
+      Value = TdIoRead16 (Port);
+    } else {
+      _ReadWriteBarrier ();
+      Value = _inpw ((UINT16)Port);
+      _ReadWriteBarrier ();
+    }
   }
   FilterBeforeIoRead (FilterWidth16, Port, &Value);
 
@@ -161,6 +180,8 @@ IoRead16 (
   If 16-bit I/O port operations are not supported, then ASSERT().
   If Port is not aligned on a 16-bit boundary, then ASSERT().
 
+  For Td guest TDVMCALL_IO is invoked to write I/O port.
+
   @param  Port  The I/O port to write.
   @param  Value The value to write to the I/O port.
 
@@ -180,9 +201,13 @@ IoWrite16 (
 
   Flag = FilterBeforeIoWrite(FilterWidth16, Port, &Value);
   if (Flag) {
-    _ReadWriteBarrier ();
-    _outpw ((UINT16)Port, Value);
-    _ReadWriteBarrier ();
+    if (IsTdxGuest ()) {
+      TdIoWrite16 (Port, Value);
+    } else {
+      _ReadWriteBarrier ();
+      _outpw ((UINT16)Port, Value);
+      _ReadWriteBarrier ();
+    }
   }
   FilterAfterIoWrite (FilterWidth16, Port, &Value);
 
@@ -199,6 +224,8 @@ IoWrite16 (
   If 32-bit I/O port operations are not supported, then ASSERT().
   If Port is not aligned on a 32-bit boundary, then ASSERT().
 
+  For Td guest TDVMCALL_IO is invoked to read I/O port.
+
   @param  Port  The I/O port to read.
 
   @return The value read.
@@ -217,9 +244,13 @@ IoRead32 (
 
   Flag = FilterBeforeIoRead(FilterWidth32, Port, &Value);
   if (Flag) {
-    _ReadWriteBarrier ();
-    Value = _inpd ((UINT16)Port);
-    _ReadWriteBarrier ();
+    if (IsTdxGuest ()) {
+      Value = TdIoRead32 (Port);
+    } else {
+      _ReadWriteBarrier ();
+      Value = _inpd ((UINT16)Port);
+      _ReadWriteBarrier ();
+    }
   }
   FilterAfterIoRead (FilterWidth32, Port, &Value);
 
@@ -236,6 +267,8 @@ IoRead32 (
   If 32-bit I/O port operations are not supported, then ASSERT().
   If Port is not aligned on a 32-bit boundary, then ASSERT().
 
+  For Td guest TDVMCALL_IO is invoked to write I/O port.
+
   @param  Port  The I/O port to write.
   @param  Value The value to write to the I/O port.
 
@@ -255,9 +288,13 @@ IoWrite32 (
 
   Flag = FilterBeforeIoWrite(FilterWidth32, Port, &Value);
   if (Flag) {
-    _ReadWriteBarrier ();
-    _outpd ((UINT16)Port, Value);
-    _ReadWriteBarrier ();
+    if (IsTdxGuest ()) {
+      TdIoWrite32 (Port, Value);
+    } else {
+      _ReadWriteBarrier ();
+      _outpd ((UINT16)Port, Value);
+      _ReadWriteBarrier ();
+    }
   }
   FilterAfterIoWrite (FilterWidth32, Port, &Value);
 
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h b/MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h
new file mode 100644
index 000000000000..3aad197d3b39
--- /dev/null
+++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibTdx.h
@@ -0,0 +1,411 @@
+/** @file
+  Header file for Tdx IO library.
+
+  Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
+   SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef IOLIB_TDX_H_
+#define IOLIB_TDX_H_
+
+/**
+  Check if it is Tdx guest.
+
+  @return TRUE    It is Tdx guest
+  @return FALSE   It is not Tdx guest
+
+**/
+BOOLEAN
+EFIAPI
+IsTdxGuest (
+  VOID
+  );
+
+
+/**
+  Reads an 8-bit I/O port.
+
+  TDVMCALL_IO is invoked to read I/O port.
+
+  @param  Port  The I/O port to read.
+
+  @return The value read.
+
+**/
+UINT8
+EFIAPI
+TdIoRead8 (
+  IN      UINTN                     Port
+  );
+
+/**
+  Reads a 16-bit I/O port.
+
+  TDVMCALL_IO is invoked to write I/O port.
+
+  @param  Port  The I/O port to read.
+
+  @return The value read.
+
+**/
+UINT16
+EFIAPI
+TdIoRead16 (
+  IN      UINTN                     Port
+  );
+
+/**
+  Reads a 32-bit I/O port.
+
+  TDVMCALL_IO is invoked to read I/O port.
+
+  @param  Port  The I/O port to read.
+
+  @return The value read.
+
+**/
+UINT32
+EFIAPI
+TdIoRead32 (
+  IN      UINTN                     Port
+  );
+
+/**
+  Writes an 8-bit I/O port.
+
+  TDVMCALL_IO is invoked to write I/O port.
+
+  @param  Port  The I/O port to write.
+  @param  Value The value to write to the I/O port.
+
+  @return The value written the I/O port.
+
+**/
+UINT8
+EFIAPI
+TdIoWrite8 (
+  IN      UINTN                     Port,
+  IN      UINT8                     Value
+  );
+
+/**
+  Writes a 16-bit I/O port.
+
+  TDVMCALL_IO is invoked to write I/O port.
+
+  @param  Port  The I/O port to write.
+  @param  Value The value to write to the I/O port.
+
+  @return The value written the I/O port.
+
+**/
+UINT16
+EFIAPI
+TdIoWrite16 (
+  IN      UINTN                     Port,
+  IN      UINT16                    Value
+  );
+
+/**
+  Writes a 32-bit I/O port.
+
+  TDVMCALL_IO is invoked to write I/O port.
+
+  @param  Port  The I/O port to write.
+  @param  Value The value to write to the I/O port.
+
+  @return The value written the I/O port.
+
+**/
+UINT32
+EFIAPI
+TdIoWrite32 (
+  IN      UINTN                     Port,
+  IN      UINT32                    Value
+  );
+
+/**
+  Reads an 8-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to read MMIO registers.
+
+  @param  Address The MMIO register to read.
+
+  @return The value read.
+
+**/
+UINT8
+EFIAPI
+TdMmioRead8 (
+  IN      UINTN                     Address
+  );
+
+/**
+  Writes an 8-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to read write registers.
+
+  @param  Address The MMIO register to write.
+  @param  Value   The value to write to the MMIO register.
+
+  @return Value.
+
+**/
+UINT8
+EFIAPI
+TdMmioWrite8 (
+  IN      UINTN                     Address,
+  IN      UINT8                     Val
+  );
+
+/**
+  Reads a 16-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to read MMIO registers.
+
+  @param  Address The MMIO register to read.
+
+  @return The value read.
+
+**/
+UINT16
+EFIAPI
+TdMmioRead16 (
+  IN      UINTN                     Address
+  );
+
+/**
+  Writes a 16-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to write MMIO registers.
+
+  @param  Address The MMIO register to write.
+  @param  Value   The value to write to the MMIO register.
+
+  @return Value.
+
+**/
+UINT16
+EFIAPI
+TdMmioWrite16 (
+  IN      UINTN                     Address,
+  IN      UINT16                    Val
+  );
+
+/**
+  Reads a 32-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to read MMIO registers.
+
+  @param  Address The MMIO register to read.
+
+  @return The value read.
+
+**/
+UINT32
+EFIAPI
+TdMmioRead32 (
+  IN      UINTN                     Address
+  );
+
+/**
+  Writes a 32-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to write MMIO registers.
+
+  @param  Address The MMIO register to write.
+  @param  Value   The value to write to the MMIO register.
+
+  @return Value.
+
+**/
+UINT32
+EFIAPI
+TdMmioWrite32 (
+  IN      UINTN                     Address,
+  IN      UINT32                    Val
+  );
+
+/**
+  Reads a 64-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to read MMIO registers.
+
+  @param  Address The MMIO register to read.
+
+  @return The value read.
+
+**/
+UINT64
+EFIAPI
+TdMmioRead64 (
+  IN      UINTN                     Address
+  );
+
+/**
+  Writes a 64-bit MMIO register.
+
+  TDVMCALL_MMIO is invoked to write MMIO registers.
+
+  @param  Address The MMIO register to write.
+  @param  Value   The value to write to the MMIO register.
+
+**/
+UINT64
+EFIAPI
+TdMmioWrite64 (
+  IN      UINTN                     Address,
+  IN      UINT64                    Value
+  );
+
+/**
+  Reads an 8-bit I/O port fifo into a block of memory in Tdx.
+
+  Reads the 8-bit I/O fifo port specified by Port.
+  The port is read Count times, and the read data is
+  stored in the provided Buffer.
+
+  This function must guarantee that all I/O read and write operations are
+  serialized.
+
+  If 8-bit I/O port operations are not supported, then ASSERT().
+
+  @param  Port    The I/O port to read.
+  @param  Count   The number of times to read I/O port.
+  @param  Buffer  The buffer to store the read data into.
+
+**/
+VOID
+EFIAPI
+TdIoReadFifo8 (
+  IN      UINTN                     Port,
+  IN      UINTN                     Count,
+  OUT     VOID                      *Buffer
+  );
+
+/**
+  Writes a block of memory into an 8-bit I/O port fifo in Tdx.
+
+  Writes the 8-bit I/O fifo port specified by Port.
+  The port is written Count times, and the write data is
+  retrieved from the provided Buffer.
+
+  This function must guarantee that all I/O write and write operations are
+  serialized.
+
+  If 8-bit I/O port operations are not supported, then ASSERT().
+
+  @param  Port    The I/O port to write.
+  @param  Count   The number of times to write I/O port.
+  @param  Buffer  The buffer to retrieve the write data from.
+
+**/
+VOID
+EFIAPI
+TdIoWriteFifo8 (
+  IN      UINTN                     Port,
+  IN      UINTN                     Count,
+  IN      VOID                      *Buffer
+  );
+
+/**
+  Reads a 16-bit I/O port fifo into a block of memory in Tdx.
+
+  Reads the 16-bit I/O fifo port specified by Port.
+  The port is read Count times, and the read data is
+  stored in the provided Buffer.
+
+  This function must guarantee that all I/O read and write operations are
+  serialized.
+
+  If 16-bit I/O port operations are not supported, then ASSERT().
+
+  @param  Port    The I/O port to read.
+  @param  Count   The number of times to read I/O port.
+  @param  Buffer  The buffer to store the read data into.
+
+**/
+VOID
+EFIAPI
+TdIoReadFifo16 (
+  IN      UINTN                     Port,
+  IN      UINTN                     Count,
+  OUT     VOID                      *Buffer
+  );
+
+/**
+  Writes a block of memory into a 16-bit I/O port fifo in Tdx.
+
+  Writes the 16-bit I/O fifo port specified by Port.
+  The port is written Count times, and the write data is
+  retrieved from the provided Buffer.
+
+  This function must guarantee that all I/O write and write operations are
+  serialized.
+
+  If 16-bit I/O port operations are not supported, then ASSERT().
+
+  @param  Port    The I/O port to write.
+  @param  Count   The number of times to write I/O port.
+  @param  Buffer  The buffer to retrieve the write data from.
+
+**/
+VOID
+EFIAPI
+TdIoWriteFifo16 (
+  IN      UINTN                     Port,
+  IN      UINTN                     Count,
+  IN      VOID                      *Buffer
+  );
+
+/**
+  Reads a 32-bit I/O port fifo into a block of memory in Tdx.
+
+  Reads the 32-bit I/O fifo port specified by Port.
+  The port is read Count times, and the read data is
+  stored in the provided Buffer.
+
+  This function must guarantee that all I/O read and write operations are
+  serialized.
+
+  If 32-bit I/O port operations are not supported, then ASSERT().
+
+  @param  Port    The I/O port to read.
+  @param  Count   The number of times to read I/O port.
+  @param  Buffer  The buffer to store the read data into.
+
+**/
+VOID
+EFIAPI
+TdIoReadFifo32 (
+  IN      UINTN                     Port,
+  IN      UINTN                     Count,
+  OUT     VOID                      *Buffer
+  );
+
+/**
+  Writes a block of memory into a 32-bit I/O port fifo in Tdx.
+
+  Writes the 32-bit I/O fifo port specified by Port.
+  The port is written Count times, and the write data is
+  retrieved from the provided Buffer.
+
+  This function must guarantee that all I/O write and write operations are
+  serialized.
+
+  If 32-bit I/O port operations are not supported, then ASSERT().
+
+  @param  Port    The I/O port to write.
+  @param  Count   The number of times to write I/O port.
+  @param  Buffer  The buffer to retrieve the write data from.
+
+**/
+VOID
+EFIAPI
+TdIoWriteFifo32 (
+  IN      UINTN                     Port,
+  IN      UINTN                     Count,
+  IN      VOID                      *Buffer
+  );
+
+#endif
diff --git a/MdePkg/Library/BaseIoLibIntrinsic/X64/IoFifoSev.nasm b/MdePkg/Library/BaseIoLibIntrinsic/X64/IoFifoSev.nasm
index 106f8881c55c..7f426495bbe3 100644
--- a/MdePkg/Library/BaseIoLibIntrinsic/X64/IoFifoSev.nasm
+++ b/MdePkg/Library/BaseIoLibIntrinsic/X64/IoFifoSev.nasm
@@ -10,6 +10,79 @@
     DEFAULT REL
     SECTION .text
 
+extern ASM_PFX(TdIoReadFifo8)
+extern ASM_PFX(TdIoReadFifo16)
+extern ASM_PFX(TdIoReadFifo32)
+extern ASM_PFX(TdIoWriteFifo8)
+extern ASM_PFX(TdIoWriteFifo16)
+extern ASM_PFX(TdIoWriteFifo32)
+
+;------------------------------------------------------------------------------
+; Check whether we need to unroll the String I/O in Tdx guest
+;
+; Return // eax   (1 - unroll, 0 - no unroll)
+;------------------------------------------------------------------------------
+global ASM_PFX(TdxNoRepIo)
+ASM_PFX(TdxNoRepIo):
+  ; CPUID clobbers ebx, ecx and edx
+  push      rbx
+  push      rcx
+  push      rdx
+
+  ;
+  ; CPUID (0)
+  ;
+  mov     eax, 0
+  cpuid
+  cmp     ebx, 0x756e6547  ; "Genu"
+  jne     @NoTdx
+  cmp     edx, 0x49656e69  ; "ineI"
+  jne     @NoTdx
+  cmp     ecx, 0x6c65746e  ; "ntel"
+  jne     @NoTdx
+
+  ;
+  ; CPUID (1)
+  ;
+  mov     eax, 1
+  cpuid
+  test    ecx, 0x80000000
+  jz      @NoTdx
+
+  ;
+  ; CPUID[0].EAX >= 0x21?
+  ;
+  mov     eax, 0
+  cpuid
+  cmp     eax, 0x21
+  jl      @NoTdx
+
+  ;
+  ; CPUID (0x21,0)
+  ;
+  mov     eax, 0x21
+  mov     ecx, 0
+  cpuid
+
+  cmp     ebx, 0x65746E49   ; "Inte"
+  jne     @NoTdx
+  cmp     edx, 0x5844546C   ; "lTDX"
+  jne     @NoTdx
+  cmp     ecx, 0x20202020   ; "    "
+  jne     @NoTdx
+
+  mov     rax, 1
+  jmp     @ExitTdxNoRepIo
+
+ at NoTdx:
+  mov     rax, 0
+
+ at ExitTdxNoRepIo:
+  pop     rdx
+  pop     rcx
+  pop     rbx
+  ret
+
 ;------------------------------------------------------------------------------
 ; Check whether we need to unroll the String I/O in SEV guest
 ;
@@ -75,6 +148,16 @@ ASM_PFX(SevNoRepIo):
 ;------------------------------------------------------------------------------
 global ASM_PFX(IoReadFifo8)
 ASM_PFX(IoReadFifo8):
+    call    ASM_PFX(TdxNoRepIo)
+    test    rax, rax
+    jz      @NonTd_IoReadFifo8
+
+    sub     rsp, 020h
+    call    TdIoReadFifo8
+    add     rsp, 020h
+    ret
+
+ at NonTd_IoReadFifo8:
     xchg    rcx, rdx
     xchg    rdi, r8             ; rdi: buffer address; r8: save rdi
 
@@ -111,6 +194,16 @@ ASM_PFX(IoReadFifo8):
 ;------------------------------------------------------------------------------
 global ASM_PFX(IoReadFifo16)
 ASM_PFX(IoReadFifo16):
+    call    ASM_PFX(TdxNoRepIo)
+    test    rax, rax
+    jz      @NonTd_IoReadFifo16
+
+    sub     rsp, 020h
+    call    TdIoReadFifo16
+    add     rsp, 020h
+    ret
+
+ at NonTd_IoReadFifo16:
     xchg    rcx, rdx
     xchg    rdi, r8             ; rdi: buffer address; r8: save rdi
 
@@ -147,6 +240,16 @@ ASM_PFX(IoReadFifo16):
 ;------------------------------------------------------------------------------
 global ASM_PFX(IoReadFifo32)
 ASM_PFX(IoReadFifo32):
+    call    ASM_PFX(TdxNoRepIo)
+    test    rax, rax
+    jz      @NonTd_IoReadFifo32
+
+    sub     rsp, 020h
+    call    TdIoReadFifo32
+    add     rsp, 020h
+    ret
+
+ at NonTd_IoReadFifo32:
     xchg    rcx, rdx
     xchg    rdi, r8             ; rdi: buffer address; r8: save rdi
 
@@ -183,6 +286,16 @@ ASM_PFX(IoReadFifo32):
 ;------------------------------------------------------------------------------
 global ASM_PFX(IoWriteFifo8)
 ASM_PFX(IoWriteFifo8):
+    call    ASM_PFX(TdxNoRepIo)
+    test    rax, rax
+    jz      @NonTd_IoWriteFifo8
+
+    sub     rsp, 020h
+    call    TdIoWriteFifo8
+    add     rsp, 020h
+    ret
+
+ at NonTd_IoWriteFifo8:
     xchg    rcx, rdx
     xchg    rsi, r8             ; rsi: buffer address; r8: save rsi
 
@@ -219,6 +332,16 @@ ASM_PFX(IoWriteFifo8):
 ;------------------------------------------------------------------------------
 global ASM_PFX(IoWriteFifo16)
 ASM_PFX(IoWriteFifo16):
+    call    ASM_PFX(TdxNoRepIo)
+    test    rax, rax
+    jz      @NonTd_IoWriteFifo16
+
+    sub     rsp, 020h
+    call    TdIoWriteFifo16
+    add     rsp, 020h
+    ret
+
+ at NonTd_IoWriteFifo16:
     xchg    rcx, rdx
     xchg    rsi, r8             ; rsi: buffer address; r8: save rsi
 
@@ -255,6 +378,16 @@ ASM_PFX(IoWriteFifo16):
 ;------------------------------------------------------------------------------
 global ASM_PFX(IoWriteFifo32)
 ASM_PFX(IoWriteFifo32):
+    call    ASM_PFX(TdxNoRepIo)
+    test    rax, rax
+    jz      @NonTd_IoWriteFifo32
+
+    sub     rsp, 020h
+    call    TdIoWriteFifo32
+    add     rsp, 020h
+    ret
+
+ at NonTd_IoWriteFifo32:
     xchg    rcx, rdx
     xchg    rsi, r8             ; rsi: buffer address; r8: save rsi
 
-- 
2.29.2.windows.2



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#79163): https://edk2.groups.io/g/devel/message/79163
Mute This Topic: https://groups.io/mt/84837896/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-





More information about the edk2-devel-archive mailing list