| /* 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) |