x86/tdx: Add __tdx_module_call() and __tdx_hypercall() helper functions
Guests communicate with VMMs with hypercalls. Historically, these
are implemented using instructions that are known to cause VMEXITs
like VMCALL, VMLAUNCH, etc. However, with TDX, VMEXITs no longer
expose the guest state to the host. This prevents the old hypercall
mechanisms from working. So, to communicate with VMM, TDX
specification defines a new instruction called TDCALL.
In a TDX based VM, since the VMM is an untrusted entity, an intermediary
layer -- TDX module -- facilitates secure communication between the host
and the guest. TDX module is loaded like a firmware into a special CPU
mode called SEAM. TDX guests communicate with the TDX module using the
TDCALL instruction.
A guest uses TDCALL to communicate with both the TDX module and VMM.
The value of the RAX register when executing the TDCALL instruction is
used to determine the TDCALL type. A leaf of TDCALL used to communicate
with the VMM is called TDVMCALL.
Add generic interfaces to communicate with the TDX module and VMM
(using the TDCALL instruction).
__tdx_module_call() - Used to communicate with the TDX module (via
TDCALL instruction).
__tdx_hypercall() - Used by the guest to request services from
the VMM (via TDVMCALL leaf of TDCALL).
Also define an additional wrapper _tdx_hypercall(), which adds error
handling support for the TDCALL failure.
The __tdx_module_call() and __tdx_hypercall() helper functions are
implemented in assembly in a .S file. The TDCALL ABI requires
shuffling arguments in and out of registers, which proved to be
awkward with inline assembly.
Just like syscalls, not all TDVMCALL use cases need to use the same
number of argument registers. The implementation here picks the current
worst-case scenario for TDCALL (4 registers). For TDCALLs with fewer
than 4 arguments, there will end up being a few superfluous (cheap)
instructions. But, this approach maximizes code reuse.
For registers used by the TDCALL instruction, please check TDX GHCI
specification, the section titled "TDCALL instruction" and "TDG.VP.VMCALL
Interface".
Based on previous patch by Sean Christopherson.
Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Tony Luck <tony.luck@intel.com>
Reviewed-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Borislav Petkov <bp@suse.de>
Link: https://lkml.kernel.org/r/20220405232939.73860-4-kirill.shutemov@linux.intel.com
2022-04-06 02:29:12 +03:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0 */
|
|
|
|
|
#include <asm/asm-offsets.h>
|
|
|
|
|
#include <asm/asm.h>
|
|
|
|
|
#include <asm/frame.h>
|
|
|
|
|
#include <asm/unwind_hints.h>
|
|
|
|
|
|
|
|
|
|
#include <linux/linkage.h>
|
|
|
|
|
#include <linux/bits.h>
|
|
|
|
|
#include <linux/errno.h>
|
|
|
|
|
|
|
|
|
|
#include "../../virt/vmx/tdx/tdxcall.S"
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Bitmasks of exposed registers (with VMM).
|
|
|
|
|
*/
|
|
|
|
|
#define TDX_R10 BIT(10)
|
|
|
|
|
#define TDX_R11 BIT(11)
|
|
|
|
|
#define TDX_R12 BIT(12)
|
|
|
|
|
#define TDX_R13 BIT(13)
|
|
|
|
|
#define TDX_R14 BIT(14)
|
|
|
|
|
#define TDX_R15 BIT(15)
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* These registers are clobbered to hold arguments for each
|
|
|
|
|
* TDVMCALL. They are safe to expose to the VMM.
|
|
|
|
|
* Each bit in this mask represents a register ID. Bit field
|
|
|
|
|
* details can be found in TDX GHCI specification, section
|
|
|
|
|
* titled "TDCALL [TDG.VP.VMCALL] leaf".
|
|
|
|
|
*/
|
|
|
|
|
#define TDVMCALL_EXPOSE_REGS_MASK ( TDX_R10 | TDX_R11 | \
|
|
|
|
|
TDX_R12 | TDX_R13 | \
|
|
|
|
|
TDX_R14 | TDX_R15 )
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* __tdx_module_call() - Used by TDX guests to request services from
|
|
|
|
|
* the TDX module (does not include VMM services) using TDCALL instruction.
|
|
|
|
|
*
|
|
|
|
|
* Transforms function call register arguments into the TDCALL register ABI.
|
|
|
|
|
* After TDCALL operation, TDX module output is saved in @out (if it is
|
|
|
|
|
* provided by the user).
|
|
|
|
|
*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
* TDCALL ABI:
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
* Input Registers:
|
|
|
|
|
*
|
|
|
|
|
* RAX - TDCALL Leaf number.
|
|
|
|
|
* RCX,RDX,R8-R9 - TDCALL Leaf specific input registers.
|
|
|
|
|
*
|
|
|
|
|
* Output Registers:
|
|
|
|
|
*
|
|
|
|
|
* RAX - TDCALL instruction error code.
|
|
|
|
|
* RCX,RDX,R8-R11 - TDCALL Leaf specific output registers.
|
|
|
|
|
*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* __tdx_module_call() function ABI:
|
|
|
|
|
*
|
|
|
|
|
* @fn (RDI) - TDCALL Leaf ID, moved to RAX
|
|
|
|
|
* @rcx (RSI) - Input parameter 1, moved to RCX
|
|
|
|
|
* @rdx (RDX) - Input parameter 2, moved to RDX
|
|
|
|
|
* @r8 (RCX) - Input parameter 3, moved to R8
|
|
|
|
|
* @r9 (R8) - Input parameter 4, moved to R9
|
|
|
|
|
*
|
|
|
|
|
* @out (R9) - struct tdx_module_output pointer
|
|
|
|
|
* stored temporarily in R12 (not
|
|
|
|
|
* shared with the TDX module). It
|
|
|
|
|
* can be NULL.
|
|
|
|
|
*
|
|
|
|
|
* Return status of TDCALL via RAX.
|
|
|
|
|
*/
|
|
|
|
|
SYM_FUNC_START(__tdx_module_call)
|
|
|
|
|
FRAME_BEGIN
|
|
|
|
|
TDX_MODULE_CALL host=0
|
|
|
|
|
FRAME_END
|
2022-05-20 10:38:39 +02:00
|
|
|
RET
|
x86/tdx: Add __tdx_module_call() and __tdx_hypercall() helper functions
Guests communicate with VMMs with hypercalls. Historically, these
are implemented using instructions that are known to cause VMEXITs
like VMCALL, VMLAUNCH, etc. However, with TDX, VMEXITs no longer
expose the guest state to the host. This prevents the old hypercall
mechanisms from working. So, to communicate with VMM, TDX
specification defines a new instruction called TDCALL.
In a TDX based VM, since the VMM is an untrusted entity, an intermediary
layer -- TDX module -- facilitates secure communication between the host
and the guest. TDX module is loaded like a firmware into a special CPU
mode called SEAM. TDX guests communicate with the TDX module using the
TDCALL instruction.
A guest uses TDCALL to communicate with both the TDX module and VMM.
The value of the RAX register when executing the TDCALL instruction is
used to determine the TDCALL type. A leaf of TDCALL used to communicate
with the VMM is called TDVMCALL.
Add generic interfaces to communicate with the TDX module and VMM
(using the TDCALL instruction).
__tdx_module_call() - Used to communicate with the TDX module (via
TDCALL instruction).
__tdx_hypercall() - Used by the guest to request services from
the VMM (via TDVMCALL leaf of TDCALL).
Also define an additional wrapper _tdx_hypercall(), which adds error
handling support for the TDCALL failure.
The __tdx_module_call() and __tdx_hypercall() helper functions are
implemented in assembly in a .S file. The TDCALL ABI requires
shuffling arguments in and out of registers, which proved to be
awkward with inline assembly.
Just like syscalls, not all TDVMCALL use cases need to use the same
number of argument registers. The implementation here picks the current
worst-case scenario for TDCALL (4 registers). For TDCALLs with fewer
than 4 arguments, there will end up being a few superfluous (cheap)
instructions. But, this approach maximizes code reuse.
For registers used by the TDCALL instruction, please check TDX GHCI
specification, the section titled "TDCALL instruction" and "TDG.VP.VMCALL
Interface".
Based on previous patch by Sean Christopherson.
Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Tony Luck <tony.luck@intel.com>
Reviewed-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Borislav Petkov <bp@suse.de>
Link: https://lkml.kernel.org/r/20220405232939.73860-4-kirill.shutemov@linux.intel.com
2022-04-06 02:29:12 +03:00
|
|
|
SYM_FUNC_END(__tdx_module_call)
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* __tdx_hypercall() - Make hypercalls to a TDX VMM using TDVMCALL leaf
|
|
|
|
|
* of TDCALL instruction
|
|
|
|
|
*
|
|
|
|
|
* Transforms values in function call argument struct tdx_hypercall_args @args
|
|
|
|
|
* into the TDCALL register ABI. After TDCALL operation, VMM output is saved
|
|
|
|
|
* back in @args.
|
|
|
|
|
*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
* TD VMCALL ABI:
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* Input Registers:
|
|
|
|
|
*
|
|
|
|
|
* RAX - TDCALL instruction leaf number (0 - TDG.VP.VMCALL)
|
|
|
|
|
* RCX - BITMAP which controls which part of TD Guest GPR
|
|
|
|
|
* is passed as-is to the VMM and back.
|
|
|
|
|
* R10 - Set 0 to indicate TDCALL follows standard TDX ABI
|
|
|
|
|
* specification. Non zero value indicates vendor
|
|
|
|
|
* specific ABI.
|
|
|
|
|
* R11 - VMCALL sub function number
|
|
|
|
|
* RBX, RBP, RDI, RSI - Used to pass VMCALL sub function specific arguments.
|
|
|
|
|
* R8-R9, R12-R15 - Same as above.
|
|
|
|
|
*
|
|
|
|
|
* Output Registers:
|
|
|
|
|
*
|
|
|
|
|
* RAX - TDCALL instruction status (Not related to hypercall
|
|
|
|
|
* output).
|
|
|
|
|
* R10 - Hypercall output error code.
|
|
|
|
|
* R11-R15 - Hypercall sub function specific output values.
|
|
|
|
|
*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* __tdx_hypercall() function ABI:
|
|
|
|
|
*
|
|
|
|
|
* @args (RDI) - struct tdx_hypercall_args for input and output
|
|
|
|
|
* @flags (RSI) - TDX_HCALL_* flags
|
|
|
|
|
*
|
|
|
|
|
* On successful completion, return the hypercall error code.
|
|
|
|
|
*/
|
|
|
|
|
SYM_FUNC_START(__tdx_hypercall)
|
|
|
|
|
FRAME_BEGIN
|
|
|
|
|
|
|
|
|
|
/* Save callee-saved GPRs as mandated by the x86_64 ABI */
|
|
|
|
|
push %r15
|
|
|
|
|
push %r14
|
|
|
|
|
push %r13
|
|
|
|
|
push %r12
|
|
|
|
|
|
|
|
|
|
/* Mangle function call ABI into TDCALL ABI: */
|
|
|
|
|
/* Set TDCALL leaf ID (TDVMCALL (0)) in RAX */
|
|
|
|
|
xor %eax, %eax
|
|
|
|
|
|
|
|
|
|
/* Copy hypercall registers from arg struct: */
|
|
|
|
|
movq TDX_HYPERCALL_r10(%rdi), %r10
|
|
|
|
|
movq TDX_HYPERCALL_r11(%rdi), %r11
|
|
|
|
|
movq TDX_HYPERCALL_r12(%rdi), %r12
|
|
|
|
|
movq TDX_HYPERCALL_r13(%rdi), %r13
|
|
|
|
|
movq TDX_HYPERCALL_r14(%rdi), %r14
|
|
|
|
|
movq TDX_HYPERCALL_r15(%rdi), %r15
|
|
|
|
|
|
|
|
|
|
movl $TDVMCALL_EXPOSE_REGS_MASK, %ecx
|
|
|
|
|
|
x86/tdx: Add HLT support for TDX guests
The HLT instruction is a privileged instruction, executing it stops
instruction execution and places the processor in a HALT state. It
is used in kernel for cases like reboot, idle loop and exception fixup
handlers. For the idle case, interrupts will be enabled (using STI)
before the HLT instruction (this is also called safe_halt()).
To support the HLT instruction in TDX guests, it needs to be emulated
using TDVMCALL (hypercall to VMM). More details about it can be found
in Intel Trust Domain Extensions (Intel TDX) Guest-Host-Communication
Interface (GHCI) specification, section TDVMCALL[Instruction.HLT].
In TDX guests, executing HLT instruction will generate a #VE, which is
used to emulate the HLT instruction. But #VE based emulation will not
work for the safe_halt() flavor, because it requires STI instruction to
be executed just before the TDCALL. Since idle loop is the only user of
safe_halt() variant, handle it as a special case.
To avoid *safe_halt() call in the idle function, define the
tdx_guest_idle() and use it to override the "x86_idle" function pointer
for a valid TDX guest.
Alternative choices like PV ops have been considered for adding
safe_halt() support. But it was rejected because HLT paravirt calls
only exist under PARAVIRT_XXL, and enabling it in TDX guest just for
safe_halt() use case is not worth the cost.
Co-developed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Andi Kleen <ak@linux.intel.com>
Reviewed-by: Tony Luck <tony.luck@intel.com>
Reviewed-by: Dave Hansen <dave.hansen@linux.intel.com>
Link: https://lkml.kernel.org/r/20220405232939.73860-9-kirill.shutemov@linux.intel.com
2022-04-06 02:29:17 +03:00
|
|
|
/*
|
|
|
|
|
* For the idle loop STI needs to be called directly before the TDCALL
|
|
|
|
|
* that enters idle (EXIT_REASON_HLT case). STI instruction enables
|
|
|
|
|
* interrupts only one instruction later. If there is a window between
|
|
|
|
|
* STI and the instruction that emulates the HALT state, there is a
|
|
|
|
|
* chance for interrupts to happen in this window, which can delay the
|
|
|
|
|
* HLT operation indefinitely. Since this is the not the desired
|
|
|
|
|
* result, conditionally call STI before TDCALL.
|
|
|
|
|
*/
|
|
|
|
|
testq $TDX_HCALL_ISSUE_STI, %rsi
|
|
|
|
|
jz .Lskip_sti
|
|
|
|
|
sti
|
|
|
|
|
.Lskip_sti:
|
x86/tdx: Add __tdx_module_call() and __tdx_hypercall() helper functions
Guests communicate with VMMs with hypercalls. Historically, these
are implemented using instructions that are known to cause VMEXITs
like VMCALL, VMLAUNCH, etc. However, with TDX, VMEXITs no longer
expose the guest state to the host. This prevents the old hypercall
mechanisms from working. So, to communicate with VMM, TDX
specification defines a new instruction called TDCALL.
In a TDX based VM, since the VMM is an untrusted entity, an intermediary
layer -- TDX module -- facilitates secure communication between the host
and the guest. TDX module is loaded like a firmware into a special CPU
mode called SEAM. TDX guests communicate with the TDX module using the
TDCALL instruction.
A guest uses TDCALL to communicate with both the TDX module and VMM.
The value of the RAX register when executing the TDCALL instruction is
used to determine the TDCALL type. A leaf of TDCALL used to communicate
with the VMM is called TDVMCALL.
Add generic interfaces to communicate with the TDX module and VMM
(using the TDCALL instruction).
__tdx_module_call() - Used to communicate with the TDX module (via
TDCALL instruction).
__tdx_hypercall() - Used by the guest to request services from
the VMM (via TDVMCALL leaf of TDCALL).
Also define an additional wrapper _tdx_hypercall(), which adds error
handling support for the TDCALL failure.
The __tdx_module_call() and __tdx_hypercall() helper functions are
implemented in assembly in a .S file. The TDCALL ABI requires
shuffling arguments in and out of registers, which proved to be
awkward with inline assembly.
Just like syscalls, not all TDVMCALL use cases need to use the same
number of argument registers. The implementation here picks the current
worst-case scenario for TDCALL (4 registers). For TDCALLs with fewer
than 4 arguments, there will end up being a few superfluous (cheap)
instructions. But, this approach maximizes code reuse.
For registers used by the TDCALL instruction, please check TDX GHCI
specification, the section titled "TDCALL instruction" and "TDG.VP.VMCALL
Interface".
Based on previous patch by Sean Christopherson.
Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Tony Luck <tony.luck@intel.com>
Reviewed-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Borislav Petkov <bp@suse.de>
Link: https://lkml.kernel.org/r/20220405232939.73860-4-kirill.shutemov@linux.intel.com
2022-04-06 02:29:12 +03:00
|
|
|
tdcall
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* RAX==0 indicates a failure of the TDVMCALL mechanism itself and that
|
|
|
|
|
* something has gone horribly wrong with the TDX module.
|
|
|
|
|
*
|
|
|
|
|
* The return status of the hypercall operation is in a separate
|
|
|
|
|
* register (in R10). Hypercall errors are a part of normal operation
|
|
|
|
|
* and are handled by callers.
|
|
|
|
|
*/
|
|
|
|
|
testq %rax, %rax
|
|
|
|
|
jne .Lpanic
|
|
|
|
|
|
|
|
|
|
/* TDVMCALL leaf return code is in R10 */
|
|
|
|
|
movq %r10, %rax
|
|
|
|
|
|
|
|
|
|
/* Copy hypercall result registers to arg struct if needed */
|
|
|
|
|
testq $TDX_HCALL_HAS_OUTPUT, %rsi
|
|
|
|
|
jz .Lout
|
|
|
|
|
|
|
|
|
|
movq %r10, TDX_HYPERCALL_r10(%rdi)
|
|
|
|
|
movq %r11, TDX_HYPERCALL_r11(%rdi)
|
|
|
|
|
movq %r12, TDX_HYPERCALL_r12(%rdi)
|
|
|
|
|
movq %r13, TDX_HYPERCALL_r13(%rdi)
|
|
|
|
|
movq %r14, TDX_HYPERCALL_r14(%rdi)
|
|
|
|
|
movq %r15, TDX_HYPERCALL_r15(%rdi)
|
|
|
|
|
.Lout:
|
|
|
|
|
/*
|
|
|
|
|
* Zero out registers exposed to the VMM to avoid speculative execution
|
|
|
|
|
* with VMM-controlled values. This needs to include all registers
|
|
|
|
|
* present in TDVMCALL_EXPOSE_REGS_MASK (except R12-R15). R12-R15
|
|
|
|
|
* context will be restored.
|
|
|
|
|
*/
|
|
|
|
|
xor %r10d, %r10d
|
|
|
|
|
xor %r11d, %r11d
|
|
|
|
|
|
|
|
|
|
/* Restore callee-saved GPRs as mandated by the x86_64 ABI */
|
|
|
|
|
pop %r12
|
|
|
|
|
pop %r13
|
|
|
|
|
pop %r14
|
|
|
|
|
pop %r15
|
|
|
|
|
|
|
|
|
|
FRAME_END
|
|
|
|
|
|
2022-05-20 10:38:39 +02:00
|
|
|
RET
|
x86/tdx: Add __tdx_module_call() and __tdx_hypercall() helper functions
Guests communicate with VMMs with hypercalls. Historically, these
are implemented using instructions that are known to cause VMEXITs
like VMCALL, VMLAUNCH, etc. However, with TDX, VMEXITs no longer
expose the guest state to the host. This prevents the old hypercall
mechanisms from working. So, to communicate with VMM, TDX
specification defines a new instruction called TDCALL.
In a TDX based VM, since the VMM is an untrusted entity, an intermediary
layer -- TDX module -- facilitates secure communication between the host
and the guest. TDX module is loaded like a firmware into a special CPU
mode called SEAM. TDX guests communicate with the TDX module using the
TDCALL instruction.
A guest uses TDCALL to communicate with both the TDX module and VMM.
The value of the RAX register when executing the TDCALL instruction is
used to determine the TDCALL type. A leaf of TDCALL used to communicate
with the VMM is called TDVMCALL.
Add generic interfaces to communicate with the TDX module and VMM
(using the TDCALL instruction).
__tdx_module_call() - Used to communicate with the TDX module (via
TDCALL instruction).
__tdx_hypercall() - Used by the guest to request services from
the VMM (via TDVMCALL leaf of TDCALL).
Also define an additional wrapper _tdx_hypercall(), which adds error
handling support for the TDCALL failure.
The __tdx_module_call() and __tdx_hypercall() helper functions are
implemented in assembly in a .S file. The TDCALL ABI requires
shuffling arguments in and out of registers, which proved to be
awkward with inline assembly.
Just like syscalls, not all TDVMCALL use cases need to use the same
number of argument registers. The implementation here picks the current
worst-case scenario for TDCALL (4 registers). For TDCALLs with fewer
than 4 arguments, there will end up being a few superfluous (cheap)
instructions. But, this approach maximizes code reuse.
For registers used by the TDCALL instruction, please check TDX GHCI
specification, the section titled "TDCALL instruction" and "TDG.VP.VMCALL
Interface".
Based on previous patch by Sean Christopherson.
Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Tony Luck <tony.luck@intel.com>
Reviewed-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Borislav Petkov <bp@suse.de>
Link: https://lkml.kernel.org/r/20220405232939.73860-4-kirill.shutemov@linux.intel.com
2022-04-06 02:29:12 +03:00
|
|
|
.Lpanic:
|
|
|
|
|
call __tdx_hypercall_failed
|
|
|
|
|
/* __tdx_hypercall_failed never returns */
|
2022-04-20 13:45:49 +02:00
|
|
|
REACHABLE
|
x86/tdx: Add __tdx_module_call() and __tdx_hypercall() helper functions
Guests communicate with VMMs with hypercalls. Historically, these
are implemented using instructions that are known to cause VMEXITs
like VMCALL, VMLAUNCH, etc. However, with TDX, VMEXITs no longer
expose the guest state to the host. This prevents the old hypercall
mechanisms from working. So, to communicate with VMM, TDX
specification defines a new instruction called TDCALL.
In a TDX based VM, since the VMM is an untrusted entity, an intermediary
layer -- TDX module -- facilitates secure communication between the host
and the guest. TDX module is loaded like a firmware into a special CPU
mode called SEAM. TDX guests communicate with the TDX module using the
TDCALL instruction.
A guest uses TDCALL to communicate with both the TDX module and VMM.
The value of the RAX register when executing the TDCALL instruction is
used to determine the TDCALL type. A leaf of TDCALL used to communicate
with the VMM is called TDVMCALL.
Add generic interfaces to communicate with the TDX module and VMM
(using the TDCALL instruction).
__tdx_module_call() - Used to communicate with the TDX module (via
TDCALL instruction).
__tdx_hypercall() - Used by the guest to request services from
the VMM (via TDVMCALL leaf of TDCALL).
Also define an additional wrapper _tdx_hypercall(), which adds error
handling support for the TDCALL failure.
The __tdx_module_call() and __tdx_hypercall() helper functions are
implemented in assembly in a .S file. The TDCALL ABI requires
shuffling arguments in and out of registers, which proved to be
awkward with inline assembly.
Just like syscalls, not all TDVMCALL use cases need to use the same
number of argument registers. The implementation here picks the current
worst-case scenario for TDCALL (4 registers). For TDCALLs with fewer
than 4 arguments, there will end up being a few superfluous (cheap)
instructions. But, this approach maximizes code reuse.
For registers used by the TDCALL instruction, please check TDX GHCI
specification, the section titled "TDCALL instruction" and "TDG.VP.VMCALL
Interface".
Based on previous patch by Sean Christopherson.
Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Tony Luck <tony.luck@intel.com>
Reviewed-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Borislav Petkov <bp@suse.de>
Link: https://lkml.kernel.org/r/20220405232939.73860-4-kirill.shutemov@linux.intel.com
2022-04-06 02:29:12 +03:00
|
|
|
jmp .Lpanic
|
|
|
|
|
SYM_FUNC_END(__tdx_hypercall)
|