From 3571fc906f7462556881f6ee153565b3595cee10 Mon Sep 17 00:00:00 2001 From: Min Xu Date: Fri, 22 Oct 2021 14:03:23 +0800 Subject: [PATCH] MdePkg: Support IoRead/IoWrite for Tdx guest in BaseIoLibIntrinsic RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3429 This commit supports IoRead/IoWrite for SEV/TDX/Legacy guest in one binary. It checks the guest type in runtime and then call corresponding functions. Cc: Michael D Kinney Cc: Liming Gao Cc: Zhiguang Liu Cc: Brijesh Singh Cc: Erdem Aktas Cc: James Bottomley Cc: Jiewen Yao Cc: Tom Lendacky Cc: Gerd Hoffmann Acked-by: Gerd Hoffmann Reviewed-by: Liming Gao Reviewed-by: Jiewen Yao Signed-off-by: Min Xu --- MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c | 51 ++++++++++++-- MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c | 73 +++++++++++++++----- 2 files changed, 99 insertions(+), 25 deletions(-) diff --git a/MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c b/MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c index 5c791289c4..05a7390859 100644 --- a/MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c +++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibGcc.c @@ -16,6 +16,7 @@ **/ #include "BaseIoLibIntrinsicInternal.h" +#include "IoLibTdx.h" /** Reads an 8-bit I/O port. @@ -24,7 +25,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. @@ -42,7 +45,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); @@ -94,6 +107,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. @@ -112,7 +127,11 @@ IoRead16 ( Flag = FilterBeforeIoRead (FilterWidth16, Port, &Data); if (Flag) { - __asm__ __volatile__ ("inw %w1,%w0" : "=a" (Data) : "d" ((UINT16)Port)); + if (IsTdxGuest ()) { + Data = TdIoRead16 (Port); + } else { + __asm__ __volatile__ ("inw %w1,%w0" : "=a" (Data) : "d" ((UINT16)Port)); + } } FilterAfterIoRead (FilterWidth16, Port, &Data); @@ -130,6 +149,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. @@ -149,7 +170,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); @@ -167,6 +192,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. @@ -185,7 +212,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); @@ -203,6 +234,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. @@ -222,7 +255,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/IoLibMsc.c b/MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c index 9f225a6b5d..f1b7d51a72 100644 --- a/MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c +++ b/MdePkg/Library/BaseIoLibIntrinsic/IoLibMsc.c @@ -14,6 +14,7 @@ **/ #include "BaseIoLibIntrinsicInternal.h" +#include "IoLibTdx.h" // // Microsoft Visual Studio 7.1 Function Prototypes for I/O Intrinsics. @@ -82,6 +83,8 @@ _ReadWriteBarrier ( 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. @@ -98,9 +101,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); @@ -117,6 +124,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. @@ -134,9 +143,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); @@ -154,6 +167,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. @@ -172,9 +187,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); @@ -192,6 +211,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. @@ -211,9 +232,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); @@ -231,6 +256,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. @@ -249,9 +276,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); @@ -269,6 +300,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. @@ -288,9 +321,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); -- 2.39.5