MdePkg: Introduce basic Tdx functions in BaseLib

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

Introduce basic Tdx functions in BaseLib:
 - TdCall ()
 - TdVmCall ()
 - TdIsEnabled ()

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>
This commit is contained in:
Min Xu 2021-11-10 09:00:41 +08:00 committed by mergify[bot]
parent 77228269e7
commit 818bc9596d
6 changed files with 446 additions and 0 deletions

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,83 @@
/** @file
Null stub of TdxLib
Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Library/BaseLib.h>
#include <Uefi/UefiBaseType.h>
/**
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 <https://software.intel.com/content/
www/us/en/develop/articles/intel-trust-domain-extensions.html>
@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;
}

View File

@ -0,0 +1,85 @@
;------------------------------------------------------------------------------
;*
;* Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
;* 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

View File

@ -0,0 +1,63 @@
/** @file
Copyright (c) 2020-2021, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Library/BaseLib.h>
#include <Register/Intel/Cpuid.h>
/**
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;
}

View File

@ -0,0 +1,145 @@
;------------------------------------------------------------------------------
;*
;* Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
;* 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