RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429 TDVF access MMIO with TDG.VP.VMCALL to invoke VMM provided emulation functions. If the access to MMIO fails, it fall backs to the direct access. 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 (which holds the null stub of the Td I/O routines) is included in BaseIoLibIntrinsic.inf. BaseIoLibIntrinsic.inf doesn't import TdxLib so that the Pkgs which include BaseIoLibIntrinsic.inf need not include TdxLib. Cc: Michael D Kinney <michael.d.kinney@intel.com> Cc: Liming Gao <gaoliming@byosoft.com.cn> Cc: Zhiguang Liu <zhiguang.liu@intel.com> Cc: Brijesh Singh <brijesh.singh@amd.com> Cc: Erdem Aktas <erdemaktas@google.com> Cc: James Bottomley <jejb@linux.ibm.com> Cc: Jiewen Yao <jiewen.yao@intel.com> Cc: Tom Lendacky <thomas.lendacky@amd.com> Cc: Gerd Hoffmann <kraxel@redhat.com> Acked-by: Gerd Hoffmann <kraxel@redhat.com> Reviewed-by: Liming Gao <gaoliming@byosoft.com.cn> Reviewed-by: Jiewen Yao <jiewen.yao@intel.com> Signed-off-by: Min Xu <min.m.xu@intel.com>
		
			
				
	
	
		
			426 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			426 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Common I/O Library routines.
 | |
| 
 | |
|   Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>
 | |
|   SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "BaseIoLibIntrinsicInternal.h"
 | |
| #include "IoLibTdx.h"
 | |
| 
 | |
| /**
 | |
|   Reads a 64-bit I/O port.
 | |
| 
 | |
|   Reads the 64-bit I/O port specified by Port. The 64-bit read value is returned.
 | |
|   This function must guarantee that all I/O read and write operations are
 | |
|   serialized.
 | |
| 
 | |
|   If 64-bit I/O port operations are not supported, then ASSERT().
 | |
|   If Port is not aligned on a 64-bit boundary, then ASSERT().
 | |
| 
 | |
|   @param  Port  The I/O port to read.
 | |
| 
 | |
|   @return The value read.
 | |
| 
 | |
| **/
 | |
| UINT64
 | |
| EFIAPI
 | |
| IoRead64 (
 | |
|   IN      UINTN  Port
 | |
|   )
 | |
| {
 | |
|   ASSERT (FALSE);
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Writes a 64-bit I/O port.
 | |
| 
 | |
|   Writes the 64-bit I/O port specified by Port with the value specified by Value
 | |
|   and returns Value. This function must guarantee that all I/O read and write
 | |
|   operations are serialized.
 | |
| 
 | |
|   If 64-bit I/O port operations are not supported, then ASSERT().
 | |
|   If Port is not aligned on a 64-bit boundary, then ASSERT().
 | |
| 
 | |
|   @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.
 | |
| 
 | |
| **/
 | |
| UINT64
 | |
| EFIAPI
 | |
| IoWrite64 (
 | |
|   IN      UINTN   Port,
 | |
|   IN      UINT64  Value
 | |
|   )
 | |
| {
 | |
|   ASSERT (FALSE);
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Reads an 8-bit MMIO register.
 | |
| 
 | |
|   Reads the 8-bit MMIO register specified by Address. The 8-bit read value is
 | |
|   returned. This function must guarantee that all MMIO read and write
 | |
|   operations are serialized.
 | |
| 
 | |
|   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.
 | |
| 
 | |
| **/
 | |
| UINT8
 | |
| EFIAPI
 | |
| MmioRead8 (
 | |
|   IN      UINTN  Address
 | |
|   )
 | |
| {
 | |
|   UINT8    Value;
 | |
|   BOOLEAN  Flag;
 | |
| 
 | |
|   Flag = FilterBeforeMmIoRead (FilterWidth8, Address, &Value);
 | |
|   if (Flag) {
 | |
|     MemoryFence ();
 | |
| 
 | |
|     if (IsTdxGuest ()) {
 | |
|       Value = TdMmioRead8 (Address);
 | |
|     } else {
 | |
|       Value = *(volatile UINT8 *)Address;
 | |
|     }
 | |
| 
 | |
|     MemoryFence ();
 | |
|   }
 | |
| 
 | |
|   FilterAfterMmIoRead (FilterWidth8, Address, &Value);
 | |
| 
 | |
|   return Value;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Writes an 8-bit MMIO register.
 | |
| 
 | |
|   Writes the 8-bit MMIO register specified by Address with the value specified
 | |
|   by Value and returns Value. This function must guarantee that all MMIO read
 | |
|   and write operations are serialized.
 | |
| 
 | |
|   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.
 | |
| 
 | |
|   @return Value.
 | |
| 
 | |
| **/
 | |
| UINT8
 | |
| EFIAPI
 | |
| MmioWrite8 (
 | |
|   IN      UINTN  Address,
 | |
|   IN      UINT8  Value
 | |
|   )
 | |
| {
 | |
|   BOOLEAN  Flag;
 | |
| 
 | |
|   Flag = FilterBeforeMmIoWrite (FilterWidth8, Address, &Value);
 | |
|   if (Flag) {
 | |
|     MemoryFence ();
 | |
| 
 | |
|     if (IsTdxGuest ()) {
 | |
|       TdMmioWrite8 (Address, Value);
 | |
|     } else {
 | |
|       *(volatile UINT8 *)Address = Value;
 | |
|     }
 | |
| 
 | |
|     MemoryFence ();
 | |
|   }
 | |
| 
 | |
|   FilterAfterMmIoWrite (FilterWidth8, Address, &Value);
 | |
| 
 | |
|   return Value;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Reads a 16-bit MMIO register.
 | |
| 
 | |
|   Reads the 16-bit MMIO register specified by Address. The 16-bit read value is
 | |
|   returned. This function must guarantee that all MMIO read and write
 | |
|   operations are serialized.
 | |
| 
 | |
|   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.
 | |
| 
 | |
| **/
 | |
| UINT16
 | |
| EFIAPI
 | |
| MmioRead16 (
 | |
|   IN      UINTN  Address
 | |
|   )
 | |
| {
 | |
|   UINT16   Value;
 | |
|   BOOLEAN  Flag;
 | |
| 
 | |
|   ASSERT ((Address & 1) == 0);
 | |
|   Flag = FilterBeforeMmIoRead (FilterWidth16, Address, &Value);
 | |
|   if (Flag) {
 | |
|     MemoryFence ();
 | |
| 
 | |
|     if (IsTdxGuest ()) {
 | |
|       Value = TdMmioRead16 (Address);
 | |
|     } else {
 | |
|       Value = *(volatile UINT16 *)Address;
 | |
|     }
 | |
| 
 | |
|     MemoryFence ();
 | |
|   }
 | |
| 
 | |
|   FilterAfterMmIoRead (FilterWidth16, Address, &Value);
 | |
| 
 | |
|   return Value;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Writes a 16-bit MMIO register.
 | |
| 
 | |
|   Writes the 16-bit MMIO register specified by Address with the value specified
 | |
|   by Value and returns Value. This function must guarantee that all MMIO read
 | |
|   and write operations are serialized.
 | |
| 
 | |
|   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.
 | |
| 
 | |
|   @return Value.
 | |
| 
 | |
| **/
 | |
| UINT16
 | |
| EFIAPI
 | |
| MmioWrite16 (
 | |
|   IN      UINTN   Address,
 | |
|   IN      UINT16  Value
 | |
|   )
 | |
| {
 | |
|   BOOLEAN  Flag;
 | |
| 
 | |
|   ASSERT ((Address & 1) == 0);
 | |
| 
 | |
|   Flag = FilterBeforeMmIoWrite (FilterWidth16, Address, &Value);
 | |
|   if (Flag) {
 | |
|     MemoryFence ();
 | |
| 
 | |
|     if (IsTdxGuest ()) {
 | |
|       TdMmioWrite16 (Address, Value);
 | |
|     } else {
 | |
|       *(volatile UINT16 *)Address = Value;
 | |
|     }
 | |
| 
 | |
|     MemoryFence ();
 | |
|   }
 | |
| 
 | |
|   FilterAfterMmIoWrite (FilterWidth16, Address, &Value);
 | |
| 
 | |
|   return Value;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Reads a 32-bit MMIO register.
 | |
| 
 | |
|   Reads the 32-bit MMIO register specified by Address. The 32-bit read value is
 | |
|   returned. This function must guarantee that all MMIO read and write
 | |
|   operations are serialized.
 | |
| 
 | |
|   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.
 | |
| 
 | |
| **/
 | |
| UINT32
 | |
| EFIAPI
 | |
| MmioRead32 (
 | |
|   IN      UINTN  Address
 | |
|   )
 | |
| {
 | |
|   UINT32   Value;
 | |
|   BOOLEAN  Flag;
 | |
| 
 | |
|   ASSERT ((Address & 3) == 0);
 | |
| 
 | |
|   Flag = FilterBeforeMmIoRead (FilterWidth32, Address, &Value);
 | |
|   if (Flag) {
 | |
|     MemoryFence ();
 | |
| 
 | |
|     if (IsTdxGuest ()) {
 | |
|       Value = TdMmioRead32 (Address);
 | |
|     } else {
 | |
|       Value = *(volatile UINT32 *)Address;
 | |
|     }
 | |
| 
 | |
|     MemoryFence ();
 | |
|   }
 | |
| 
 | |
|   FilterAfterMmIoRead (FilterWidth32, Address, &Value);
 | |
| 
 | |
|   return Value;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Writes a 32-bit MMIO register.
 | |
| 
 | |
|   Writes the 32-bit MMIO register specified by Address with the value specified
 | |
|   by Value and returns Value. This function must guarantee that all MMIO read
 | |
|   and write operations are serialized.
 | |
| 
 | |
|   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.
 | |
| 
 | |
|   @return Value.
 | |
| 
 | |
| **/
 | |
| UINT32
 | |
| EFIAPI
 | |
| MmioWrite32 (
 | |
|   IN      UINTN   Address,
 | |
|   IN      UINT32  Value
 | |
|   )
 | |
| {
 | |
|   BOOLEAN  Flag;
 | |
| 
 | |
|   ASSERT ((Address & 3) == 0);
 | |
| 
 | |
|   Flag = FilterBeforeMmIoWrite (FilterWidth32, Address, &Value);
 | |
|   if (Flag) {
 | |
|     MemoryFence ();
 | |
| 
 | |
|     if (IsTdxGuest ()) {
 | |
|       TdMmioWrite32 (Address, Value);
 | |
|     } else {
 | |
|       *(volatile UINT32 *)Address = Value;
 | |
|     }
 | |
| 
 | |
|     MemoryFence ();
 | |
|   }
 | |
| 
 | |
|   FilterAfterMmIoWrite (FilterWidth32, Address, &Value);
 | |
| 
 | |
|   return Value;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Reads a 64-bit MMIO register.
 | |
| 
 | |
|   Reads the 64-bit MMIO register specified by Address. The 64-bit read value is
 | |
|   returned. This function must guarantee that all MMIO read and write
 | |
|   operations are serialized.
 | |
| 
 | |
|   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.
 | |
| 
 | |
| **/
 | |
| UINT64
 | |
| EFIAPI
 | |
| MmioRead64 (
 | |
|   IN      UINTN  Address
 | |
|   )
 | |
| {
 | |
|   UINT64   Value;
 | |
|   BOOLEAN  Flag;
 | |
| 
 | |
|   ASSERT ((Address & 7) == 0);
 | |
| 
 | |
|   Flag = FilterBeforeMmIoRead (FilterWidth64, Address, &Value);
 | |
|   if (Flag) {
 | |
|     MemoryFence ();
 | |
| 
 | |
|     if (IsTdxGuest ()) {
 | |
|       Value = TdMmioRead64 (Address);
 | |
|     } else {
 | |
|       Value = *(volatile UINT64 *)Address;
 | |
|     }
 | |
| 
 | |
|     MemoryFence ();
 | |
|   }
 | |
| 
 | |
|   FilterAfterMmIoRead (FilterWidth64, Address, &Value);
 | |
| 
 | |
|   return Value;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Writes a 64-bit MMIO register.
 | |
| 
 | |
|   Writes the 64-bit MMIO register specified by Address with the value specified
 | |
|   by Value and returns Value. This function must guarantee that all MMIO read
 | |
|   and write operations are serialized.
 | |
| 
 | |
|   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.
 | |
| 
 | |
| **/
 | |
| UINT64
 | |
| EFIAPI
 | |
| MmioWrite64 (
 | |
|   IN      UINTN   Address,
 | |
|   IN      UINT64  Value
 | |
|   )
 | |
| {
 | |
|   BOOLEAN  Flag;
 | |
| 
 | |
|   ASSERT ((Address & 7) == 0);
 | |
| 
 | |
|   Flag = FilterBeforeMmIoWrite (FilterWidth64, Address, &Value);
 | |
|   if (Flag) {
 | |
|     MemoryFence ();
 | |
| 
 | |
|     if (IsTdxGuest ()) {
 | |
|       TdMmioWrite64 (Address, Value);
 | |
|     } else {
 | |
|       *(volatile UINT64 *)Address = Value;
 | |
|     }
 | |
| 
 | |
|     MemoryFence ();
 | |
|   }
 | |
| 
 | |
|   FilterAfterMmIoWrite (FilterWidth64, Address, &Value);
 | |
| 
 | |
|   return Value;
 | |
| }
 |