Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002 #include <asm/asm-offsets.h>
0003 #include <asm/asm.h>
0004 #include <asm/frame.h>
0005 #include <asm/unwind_hints.h>
0006 
0007 #include <linux/linkage.h>
0008 #include <linux/bits.h>
0009 #include <linux/errno.h>
0010 
0011 #include "../../virt/vmx/tdx/tdxcall.S"
0012 
0013 /*
0014  * Bitmasks of exposed registers (with VMM).
0015  */
0016 #define TDX_R10     BIT(10)
0017 #define TDX_R11     BIT(11)
0018 #define TDX_R12     BIT(12)
0019 #define TDX_R13     BIT(13)
0020 #define TDX_R14     BIT(14)
0021 #define TDX_R15     BIT(15)
0022 
0023 /*
0024  * These registers are clobbered to hold arguments for each
0025  * TDVMCALL. They are safe to expose to the VMM.
0026  * Each bit in this mask represents a register ID. Bit field
0027  * details can be found in TDX GHCI specification, section
0028  * titled "TDCALL [TDG.VP.VMCALL] leaf".
0029  */
0030 #define TDVMCALL_EXPOSE_REGS_MASK   ( TDX_R10 | TDX_R11 | \
0031                       TDX_R12 | TDX_R13 | \
0032                       TDX_R14 | TDX_R15 )
0033 
0034 /*
0035  * __tdx_module_call()  - Used by TDX guests to request services from
0036  * the TDX module (does not include VMM services) using TDCALL instruction.
0037  *
0038  * Transforms function call register arguments into the TDCALL register ABI.
0039  * After TDCALL operation, TDX module output is saved in @out (if it is
0040  * provided by the user).
0041  *
0042  *-------------------------------------------------------------------------
0043  * TDCALL ABI:
0044  *-------------------------------------------------------------------------
0045  * Input Registers:
0046  *
0047  * RAX                 - TDCALL Leaf number.
0048  * RCX,RDX,R8-R9       - TDCALL Leaf specific input registers.
0049  *
0050  * Output Registers:
0051  *
0052  * RAX                 - TDCALL instruction error code.
0053  * RCX,RDX,R8-R11      - TDCALL Leaf specific output registers.
0054  *
0055  *-------------------------------------------------------------------------
0056  *
0057  * __tdx_module_call() function ABI:
0058  *
0059  * @fn  (RDI)          - TDCALL Leaf ID,    moved to RAX
0060  * @rcx (RSI)          - Input parameter 1, moved to RCX
0061  * @rdx (RDX)          - Input parameter 2, moved to RDX
0062  * @r8  (RCX)          - Input parameter 3, moved to R8
0063  * @r9  (R8)           - Input parameter 4, moved to R9
0064  *
0065  * @out (R9)           - struct tdx_module_output pointer
0066  *                       stored temporarily in R12 (not
0067  *                       shared with the TDX module). It
0068  *                       can be NULL.
0069  *
0070  * Return status of TDCALL via RAX.
0071  */
0072 SYM_FUNC_START(__tdx_module_call)
0073     FRAME_BEGIN
0074     TDX_MODULE_CALL host=0
0075     FRAME_END
0076     RET
0077 SYM_FUNC_END(__tdx_module_call)
0078 
0079 /*
0080  * __tdx_hypercall() - Make hypercalls to a TDX VMM using TDVMCALL leaf
0081  * of TDCALL instruction
0082  *
0083  * Transforms values in  function call argument struct tdx_hypercall_args @args
0084  * into the TDCALL register ABI. After TDCALL operation, VMM output is saved
0085  * back in @args.
0086  *
0087  *-------------------------------------------------------------------------
0088  * TD VMCALL ABI:
0089  *-------------------------------------------------------------------------
0090  *
0091  * Input Registers:
0092  *
0093  * RAX                 - TDCALL instruction leaf number (0 - TDG.VP.VMCALL)
0094  * RCX                 - BITMAP which controls which part of TD Guest GPR
0095  *                       is passed as-is to the VMM and back.
0096  * R10                 - Set 0 to indicate TDCALL follows standard TDX ABI
0097  *                       specification. Non zero value indicates vendor
0098  *                       specific ABI.
0099  * R11                 - VMCALL sub function number
0100  * RBX, RBP, RDI, RSI  - Used to pass VMCALL sub function specific arguments.
0101  * R8-R9, R12-R15      - Same as above.
0102  *
0103  * Output Registers:
0104  *
0105  * RAX                 - TDCALL instruction status (Not related to hypercall
0106  *                        output).
0107  * R10                 - Hypercall output error code.
0108  * R11-R15             - Hypercall sub function specific output values.
0109  *
0110  *-------------------------------------------------------------------------
0111  *
0112  * __tdx_hypercall() function ABI:
0113  *
0114  * @args  (RDI)        - struct tdx_hypercall_args for input and output
0115  * @flags (RSI)        - TDX_HCALL_* flags
0116  *
0117  * On successful completion, return the hypercall error code.
0118  */
0119 SYM_FUNC_START(__tdx_hypercall)
0120     FRAME_BEGIN
0121 
0122     /* Save callee-saved GPRs as mandated by the x86_64 ABI */
0123     push %r15
0124     push %r14
0125     push %r13
0126     push %r12
0127 
0128     /* Mangle function call ABI into TDCALL ABI: */
0129     /* Set TDCALL leaf ID (TDVMCALL (0)) in RAX */
0130     xor %eax, %eax
0131 
0132     /* Copy hypercall registers from arg struct: */
0133     movq TDX_HYPERCALL_r10(%rdi), %r10
0134     movq TDX_HYPERCALL_r11(%rdi), %r11
0135     movq TDX_HYPERCALL_r12(%rdi), %r12
0136     movq TDX_HYPERCALL_r13(%rdi), %r13
0137     movq TDX_HYPERCALL_r14(%rdi), %r14
0138     movq TDX_HYPERCALL_r15(%rdi), %r15
0139 
0140     movl $TDVMCALL_EXPOSE_REGS_MASK, %ecx
0141 
0142     /*
0143      * For the idle loop STI needs to be called directly before the TDCALL
0144      * that enters idle (EXIT_REASON_HLT case). STI instruction enables
0145      * interrupts only one instruction later. If there is a window between
0146      * STI and the instruction that emulates the HALT state, there is a
0147      * chance for interrupts to happen in this window, which can delay the
0148      * HLT operation indefinitely. Since this is the not the desired
0149      * result, conditionally call STI before TDCALL.
0150      */
0151     testq $TDX_HCALL_ISSUE_STI, %rsi
0152     jz .Lskip_sti
0153     sti
0154 .Lskip_sti:
0155     tdcall
0156 
0157     /*
0158      * RAX==0 indicates a failure of the TDVMCALL mechanism itself and that
0159      * something has gone horribly wrong with the TDX module.
0160      *
0161      * The return status of the hypercall operation is in a separate
0162      * register (in R10). Hypercall errors are a part of normal operation
0163      * and are handled by callers.
0164      */
0165     testq %rax, %rax
0166     jne .Lpanic
0167 
0168     /* TDVMCALL leaf return code is in R10 */
0169     movq %r10, %rax
0170 
0171     /* Copy hypercall result registers to arg struct if needed */
0172     testq $TDX_HCALL_HAS_OUTPUT, %rsi
0173     jz .Lout
0174 
0175     movq %r10, TDX_HYPERCALL_r10(%rdi)
0176     movq %r11, TDX_HYPERCALL_r11(%rdi)
0177     movq %r12, TDX_HYPERCALL_r12(%rdi)
0178     movq %r13, TDX_HYPERCALL_r13(%rdi)
0179     movq %r14, TDX_HYPERCALL_r14(%rdi)
0180     movq %r15, TDX_HYPERCALL_r15(%rdi)
0181 .Lout:
0182     /*
0183      * Zero out registers exposed to the VMM to avoid speculative execution
0184      * with VMM-controlled values. This needs to include all registers
0185      * present in TDVMCALL_EXPOSE_REGS_MASK (except R12-R15). R12-R15
0186      * context will be restored.
0187      */
0188     xor %r10d, %r10d
0189     xor %r11d, %r11d
0190 
0191     /* Restore callee-saved GPRs as mandated by the x86_64 ABI */
0192     pop %r12
0193     pop %r13
0194     pop %r14
0195     pop %r15
0196 
0197     FRAME_END
0198 
0199     RET
0200 .Lpanic:
0201     call __tdx_hypercall_failed
0202     /* __tdx_hypercall_failed never returns */
0203     REACHABLE
0204     jmp .Lpanic
0205 SYM_FUNC_END(__tdx_hypercall)