blob: b193c0a1d8db38ab9d6a328c52770aa95ac8433e [file] [log] [blame]
/* 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_RDX BIT(2)
#define TDX_RBX BIT(3)
#define TDX_RSI BIT(6)
#define TDX_RDI BIT(7)
#define TDX_R8 BIT(8)
#define TDX_R9 BIT(9)
#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_RDX | TDX_RBX | TDX_RSI | TDX_RDI | TDX_R8 | TDX_R9 | \
TDX_R10 | TDX_R11 | TDX_R12 | TDX_R13 | TDX_R14 | TDX_R15 )
.section .noinstr.text, "ax"
/*
* __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
RET
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, if \ret is 1.
*
*-------------------------------------------------------------------------
* 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, RDX, 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).
* RBX, RDX, RDI, RSI - Hypercall sub function specific output values.
* R8-R15 - Same as above.
*
*/
.macro TDX_HYPERCALL ret:req
FRAME_BEGIN
/* Save callee-saved GPRs as mandated by the x86_64 ABI */
push %r15
push %r14
push %r13
push %r12
push %rbx
/* Free RDI to be used as TDVMCALL arguments */
movq %rdi, %rax
/* Copy hypercall registers from arg struct: */
movq TDX_HYPERCALL_r8(%rax), %r8
movq TDX_HYPERCALL_r9(%rax), %r9
movq TDX_HYPERCALL_r10(%rax), %r10
movq TDX_HYPERCALL_r11(%rax), %r11
movq TDX_HYPERCALL_r12(%rax), %r12
movq TDX_HYPERCALL_r13(%rax), %r13
movq TDX_HYPERCALL_r14(%rax), %r14
movq TDX_HYPERCALL_r15(%rax), %r15
movq TDX_HYPERCALL_rdi(%rax), %rdi
movq TDX_HYPERCALL_rsi(%rax), %rsi
movq TDX_HYPERCALL_rbx(%rax), %rbx
movq TDX_HYPERCALL_rdx(%rax), %rdx
push %rax
/* Mangle function call ABI into TDCALL ABI: */
/* Set TDCALL leaf ID (TDVMCALL (0)) in RAX */
xor %eax, %eax
movl $TDVMCALL_EXPOSE_REGS_MASK, %ecx
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\@
pop %rax
.if \ret
movq %r8, TDX_HYPERCALL_r8(%rax)
movq %r9, TDX_HYPERCALL_r9(%rax)
movq %r10, TDX_HYPERCALL_r10(%rax)
movq %r11, TDX_HYPERCALL_r11(%rax)
movq %r12, TDX_HYPERCALL_r12(%rax)
movq %r13, TDX_HYPERCALL_r13(%rax)
movq %r14, TDX_HYPERCALL_r14(%rax)
movq %r15, TDX_HYPERCALL_r15(%rax)
movq %rdi, TDX_HYPERCALL_rdi(%rax)
movq %rsi, TDX_HYPERCALL_rsi(%rax)
movq %rbx, TDX_HYPERCALL_rbx(%rax)
movq %rdx, TDX_HYPERCALL_rdx(%rax)
.endif
/* TDVMCALL leaf return code is in R10 */
movq %r10, %rax
/*
* 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 RBX, and R12-R15 which
* will be restored.
*/
xor %r8d, %r8d
xor %r9d, %r9d
xor %r10d, %r10d
xor %r11d, %r11d
xor %rdi, %rdi
xor %rdx, %rdx
/* Restore callee-saved GPRs as mandated by the x86_64 ABI */
pop %rbx
pop %r12
pop %r13
pop %r14
pop %r15
FRAME_END
RET
.Lpanic\@:
call __tdx_hypercall_failed
/* __tdx_hypercall_failed never returns */
REACHABLE
jmp .Lpanic\@
.endm
/*
*
* __tdx_hypercall() function ABI:
*
* @args (RDI) - struct tdx_hypercall_args for input
*
* On successful completion, return the hypercall error code.
*/
SYM_FUNC_START(__tdx_hypercall)
TDX_HYPERCALL ret=0
SYM_FUNC_END(__tdx_hypercall)
/*
*
* __tdx_hypercall_ret() function ABI:
*
* @args (RDI) - struct tdx_hypercall_args for input and output
*
* On successful completion, return the hypercall error code.
*/
SYM_FUNC_START(__tdx_hypercall_ret)
TDX_HYPERCALL ret=1
SYM_FUNC_END(__tdx_hypercall_ret)