diff --git a/MdePkg/Include/Library/BaseLib.h b/MdePkg/Include/Library/BaseLib.h index 6aa0d97218..9d58a7c4ad 100644 --- a/MdePkg/Include/Library/BaseLib.h +++ b/MdePkg/Include/Library/BaseLib.h @@ -4759,6 +4759,72 @@ SpeculationBarrier ( VOID ); +#if defined (MDE_CPU_X64) || defined (MDE_CPU_IA32) + +/** + The TDCALL instruction causes a VM exit to the Intel TDX module. It is + used to call guest-side Intel TDX functions, either local or a TD exit + to the host VMM, as selected by Leaf. + + @param[in] Leaf Leaf number of TDCALL instruction + @param[in] Arg1 Arg1 + @param[in] Arg2 Arg2 + @param[in] Arg3 Arg3 + @param[in,out] Results Returned result of the Leaf function + + @return 0 A successful call + @return Other See individual leaf functions +**/ +UINTN +EFIAPI +TdCall ( + IN UINT64 Leaf, + IN UINT64 Arg1, + IN UINT64 Arg2, + IN UINT64 Arg3, + IN OUT VOID *Results + ); + +/** + TDVMALL is a leaf function 0 for TDCALL. It helps invoke services from the + host VMM to pass/receive information. + + @param[in] Leaf Number of sub-functions + @param[in] Arg1 Arg1 + @param[in] Arg2 Arg2 + @param[in] Arg3 Arg3 + @param[in] Arg4 Arg4 + @param[in,out] Results Returned result of the sub-function + + @return 0 A successful call + @return Other See individual sub-functions + +**/ +UINTN +EFIAPI +TdVmCall ( + IN UINT64 Leaf, + IN UINT64 Arg1, + IN UINT64 Arg2, + IN UINT64 Arg3, + IN UINT64 Arg4, + IN OUT VOID *Results + ); + +/** + Probe if TD is enabled. + + @return TRUE TD is enabled. + @return FALSE TD is not enabled. +**/ +BOOLEAN +EFIAPI +TdIsEnabled ( + VOID + ); + +#endif + #if defined (MDE_CPU_X64) // // The page size for the PVALIDATE instruction diff --git a/MdePkg/Library/BaseLib/BaseLib.inf b/MdePkg/Library/BaseLib/BaseLib.inf index cebda3b210..16b7ac3917 100644 --- a/MdePkg/Library/BaseLib/BaseLib.inf +++ b/MdePkg/Library/BaseLib/BaseLib.inf @@ -210,6 +210,7 @@ X86RdRand.c X86PatchInstruction.c X86SpeculationBarrier.c + IntelTdxNull.c [Sources.X64] X64/Thunk16.nasm @@ -293,6 +294,9 @@ X64/ReadCr0.nasm| MSFT X64/ReadEflags.nasm| MSFT + X64/TdCall.nasm + X64/TdVmcall.nasm + X64/TdProbe.c X64/Non-existing.c Math64.c diff --git a/MdePkg/Library/BaseLib/IntelTdxNull.c b/MdePkg/Library/BaseLib/IntelTdxNull.c new file mode 100644 index 0000000000..ec95470bd4 --- /dev/null +++ b/MdePkg/Library/BaseLib/IntelTdxNull.c @@ -0,0 +1,83 @@ +/** @file + + Null stub of TdxLib + + Copyright (c) 2021, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include + +/** + The TDCALL instruction causes a VM exit to the Intel TDX module. It is + used to call guest-side Intel TDX functions, either local or a TD exit + to the host VMM, as selected by Leaf. + Leaf functions are described at + + @param[in] Leaf Leaf number of TDCALL instruction + @param[in] Arg1 Arg1 + @param[in] Arg2 Arg2 + @param[in] Arg3 Arg3 + @param[in,out] Results Returned result of the Leaf function + + @return EFI_SUCCESS + @return Other See individual leaf functions +**/ +UINTN +EFIAPI +TdCall ( + IN UINT64 Leaf, + IN UINT64 Arg1, + IN UINT64 Arg2, + IN UINT64 Arg3, + IN OUT VOID *Results + ) +{ + return EFI_UNSUPPORTED; +} + +/** + TDVMALL is a leaf function 0 for TDCALL. It helps invoke services from the + host VMM to pass/receive information. + + @param[in] Leaf Number of sub-functions + @param[in] Arg1 Arg1 + @param[in] Arg2 Arg2 + @param[in] Arg3 Arg3 + @param[in] Arg4 Arg4 + @param[in,out] Results Returned result of the sub-function + + @return EFI_SUCCESS + @return Other See individual sub-functions + +**/ +UINTN +EFIAPI +TdVmCall ( + IN UINT64 Leaf, + IN UINT64 Arg1, + IN UINT64 Arg2, + IN UINT64 Arg3, + IN UINT64 Arg4, + IN OUT VOID *Results + ) +{ + return EFI_UNSUPPORTED; +} + +/** + Probe if TD is enabled. + + @return TRUE TD is enabled. + @return FALSE TD is not enabled. +**/ +BOOLEAN +EFIAPI +TdIsEnabled ( + ) +{ + return FALSE; +} diff --git a/MdePkg/Library/BaseLib/X64/TdCall.nasm b/MdePkg/Library/BaseLib/X64/TdCall.nasm new file mode 100644 index 0000000000..e8a094b0eb --- /dev/null +++ b/MdePkg/Library/BaseLib/X64/TdCall.nasm @@ -0,0 +1,85 @@ +;------------------------------------------------------------------------------ +;* +;* Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.
+;* SPDX-License-Identifier: BSD-2-Clause-Patent +;* +;* +;------------------------------------------------------------------------------ + +DEFAULT REL +SECTION .text + +%macro tdcall 0 + db 0x66,0x0f,0x01,0xcc +%endmacro + +%macro tdcall_push_regs 0 + push rbp + mov rbp, rsp + push r15 + push r14 + push r13 + push r12 + push rbx + push rsi + push rdi +%endmacro + +%macro tdcall_pop_regs 0 + pop rdi + pop rsi + pop rbx + pop r12 + pop r13 + pop r14 + pop r15 + pop rbp +%endmacro + +%define number_of_regs_pushed 8 +%define number_of_parameters 4 + +; +; Keep these in sync for push_regs/pop_regs, code below +; uses them to find 5th or greater parameters +; +%define first_variable_on_stack_offset \ + ((number_of_regs_pushed * 8) + (number_of_parameters * 8) + 8) +%define second_variable_on_stack_offset \ + ((first_variable_on_stack_offset) + 8) + +; TdCall ( +; UINT64 Leaf, // Rcx +; UINT64 P1, // Rdx +; UINT64 P2, // R8 +; UINT64 P3, // R9 +; UINT64 Results, // rsp + 0x28 +; ) +global ASM_PFX(TdCall) +ASM_PFX(TdCall): + tdcall_push_regs + + mov rax, rcx + mov rcx, rdx + mov rdx, r8 + mov r8, r9 + + tdcall + + ; exit if tdcall reports failure. + test rax, rax + jnz .exit + + ; test if caller wanted results + mov r12, [rsp + first_variable_on_stack_offset ] + test r12, r12 + jz .exit + mov [r12 + 0 ], rcx + mov [r12 + 8 ], rdx + mov [r12 + 16], r8 + mov [r12 + 24], r9 + mov [r12 + 32], r10 + mov [r12 + 40], r11 +.exit: + tdcall_pop_regs + ret diff --git a/MdePkg/Library/BaseLib/X64/TdProbe.c b/MdePkg/Library/BaseLib/X64/TdProbe.c new file mode 100644 index 0000000000..b893c0a004 --- /dev/null +++ b/MdePkg/Library/BaseLib/X64/TdProbe.c @@ -0,0 +1,63 @@ +/** @file + + Copyright (c) 2020-2021, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include + +/** + Probe if TD is enabled. + + @return TRUE TD is enabled. + @return FALSE TD is not enabled. +**/ +BOOLEAN +EFIAPI +TdIsEnabled ( + ) +{ + UINT32 Eax; + UINT32 Ebx; + UINT32 Ecx; + UINT32 Edx; + UINT32 LargestEax; + BOOLEAN TdEnabled; + CPUID_VERSION_INFO_ECX CpuIdVersionInfoEcx; + + TdEnabled = FALSE; + + do { + AsmCpuid (CPUID_SIGNATURE, &LargestEax, &Ebx, &Ecx, &Edx); + + if ( (Ebx != CPUID_SIGNATURE_GENUINE_INTEL_EBX) + || (Edx != CPUID_SIGNATURE_GENUINE_INTEL_EDX) + || (Ecx != CPUID_SIGNATURE_GENUINE_INTEL_ECX)) + { + break; + } + + AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, &CpuIdVersionInfoEcx.Uint32, NULL); + if (CpuIdVersionInfoEcx.Bits.ParaVirtualized == 0) { + break; + } + + if (LargestEax < CPUID_GUESTTD_RUNTIME_ENVIRONMENT) { + break; + } + + AsmCpuidEx (CPUID_GUESTTD_RUNTIME_ENVIRONMENT, 0, &Eax, &Ebx, &Ecx, &Edx); + if ( (Ebx != CPUID_GUESTTD_SIGNATURE_GENUINE_INTEL_EBX) + || (Edx != CPUID_GUESTTD_SIGNATURE_GENUINE_INTEL_EDX) + || (Ecx != CPUID_GUESTTD_SIGNATURE_GENUINE_INTEL_ECX)) + { + break; + } + + TdEnabled = TRUE; + } while (FALSE); + + return TdEnabled; +} diff --git a/MdePkg/Library/BaseLib/X64/TdVmcall.nasm b/MdePkg/Library/BaseLib/X64/TdVmcall.nasm new file mode 100644 index 0000000000..5ecc10b171 --- /dev/null +++ b/MdePkg/Library/BaseLib/X64/TdVmcall.nasm @@ -0,0 +1,145 @@ +;------------------------------------------------------------------------------ +;* +;* Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.
+;* SPDX-License-Identifier: BSD-2-Clause-Patent +;* +;* +;------------------------------------------------------------------------------ + +DEFAULT REL +SECTION .text + +%define TDVMCALL_EXPOSE_REGS_MASK 0xffec +%define TDVMCALL 0x0 + +%macro tdcall 0 + db 0x66,0x0f,0x01,0xcc +%endmacro + +%macro tdcall_push_regs 0 + push rbp + mov rbp, rsp + push r15 + push r14 + push r13 + push r12 + push rbx + push rsi + push rdi +%endmacro + +%macro tdcall_pop_regs 0 + pop rdi + pop rsi + pop rbx + pop r12 + pop r13 + pop r14 + pop r15 + pop rbp +%endmacro + +%define number_of_regs_pushed 8 +%define number_of_parameters 4 + +; +; Keep these in sync for push_regs/pop_regs, code below +; uses them to find 5th or greater parameters +; +%define first_variable_on_stack_offset \ + ((number_of_regs_pushed * 8) + (number_of_parameters * 8) + 8) +%define second_variable_on_stack_offset \ + ((first_variable_on_stack_offset) + 8) + +%macro tdcall_regs_preamble 2 + mov rax, %1 + + xor rcx, rcx + mov ecx, %2 + + ; R10 = 0 (standard TDVMCALL) + + xor r10d, r10d + + ; Zero out unused (for standard TDVMCALL) registers to avoid leaking + ; secrets to the VMM. + + xor ebx, ebx + xor esi, esi + xor edi, edi + + xor edx, edx + xor ebp, ebp + xor r8d, r8d + xor r9d, r9d +%endmacro + +%macro tdcall_regs_postamble 0 + xor ebx, ebx + xor esi, esi + xor edi, edi + + xor ecx, ecx + xor edx, edx + xor r8d, r8d + xor r9d, r9d + xor r10d, r10d + xor r11d, r11d +%endmacro + +;------------------------------------------------------------------------------ +; 0 => RAX = TDCALL leaf +; M => RCX = TDVMCALL register behavior +; 1 => R10 = standard vs. vendor +; RDI => R11 = TDVMCALL function / nr +; RSI = R12 = p1 +; RDX => R13 = p2 +; RCX => R14 = p3 +; R8 => R15 = p4 + +; UINT64 +; EFIAPI +; TdVmCall ( +; UINT64 Leaf, // Rcx +; UINT64 P1, // Rdx +; UINT64 P2, // R8 +; UINT64 P3, // R9 +; UINT64 P4, // rsp + 0x28 +; UINT64 *Val // rsp + 0x30 +; ) +global ASM_PFX(TdVmCall) +ASM_PFX(TdVmCall): + tdcall_push_regs + + mov r11, rcx + mov r12, rdx + mov r13, r8 + mov r14, r9 + mov r15, [rsp + first_variable_on_stack_offset ] + + tdcall_regs_preamble TDVMCALL, TDVMCALL_EXPOSE_REGS_MASK + + tdcall + + ; ignore return dataif TDCALL reports failure. + test rax, rax + jnz .no_return_data + + ; Propagate TDVMCALL success/failure to return value. + mov rax, r10 + + ; Retrieve the Val pointer. + mov r9, [rsp + second_variable_on_stack_offset ] + test r9, r9 + jz .no_return_data + + ; On success, propagate TDVMCALL output value to output param + test rax, rax + jnz .no_return_data + mov [r9], r11 +.no_return_data: + tdcall_regs_postamble + + tdcall_pop_regs + + ret