Merge tag 'x86_tdx_for_6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 25 Feb 2023 17:11:30 +0000 (09:11 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 25 Feb 2023 17:11:30 +0000 (09:11 -0800)
Pull Intel Trust Domain Extensions (TDX) updates from Dave Hansen:
 "Other than a minor fixup, the content here is to ensure that TDX
  guests never see virtualization exceptions (#VE's) that might be
  induced by the untrusted VMM.

  This is a highly desirable property. Without it, #VE exception
  handling would fall somewhere between NMIs, machine checks and total
  insanity. With it, #VE handling remains pretty mundane.

  Summary:

   - Fixup comment typo

   - Prevent unexpected #VE's from:
      - Hosts removing perfectly good guest mappings (SEPT_VE_DISABLE)
      - Excessive #VE notifications (NOTIFY_ENABLES) which are delivered
        via a #VE"

* tag 'x86_tdx_for_6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/tdx: Do not corrupt frame-pointer in __tdx_hypercall()
  x86/tdx: Disable NOTIFY_ENABLES
  x86/tdx: Relax SEPT_VE_DISABLE check for debug TD
  x86/tdx: Use ReportFatalError to report missing SEPT_VE_DISABLE
  x86/tdx: Expand __tdx_hypercall() to handle more arguments
  x86/tdx: Refactor __tdx_hypercall() to allow pass down more arguments
  x86/tdx: Add more registers to struct tdx_hypercall_args
  x86/tdx: Fix typo in comment in __tdx_hypercall()

1  2 
arch/x86/coco/tdx/tdcall.S
arch/x86/coco/tdx/tdx.c
arch/x86/include/asm/shared/tdx.h
arch/x86/kernel/asm-offsets.c

index ad0d51f03cb408eb407deef9db665cda0662550a,2bd436a4790d611ada8d6c3924cfe2420025f9fb..6a255e6809bc525690538c17eb284c1f72e3f700
  /*
   * 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)
   * 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 )
+ #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.
@@@ -126,25 -130,51 +132,38 @@@ SYM_FUNC_START(__tdx_hypercall
        push %r14
        push %r13
        push %r12
+       push %rbx
+       /* Free RDI and RSI to be used as TDVMCALL arguments */
+       movq %rdi, %rax
+       push %rsi
+       /* 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
  
-       /* 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
  
 -      /*
 -       * 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, 8(%rsp)
 -      jz .Lskip_sti
 -      sti
 -.Lskip_sti:
        tdcall
  
        /*
-        * RAX==0 indicates a failure of the TDVMCALL mechanism itself and that
+        * 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
        testq %rax, %rax
        jne .Lpanic
  
-       /* TDVMCALL leaf return code is in R10 */
-       movq %r10, %rax
+       pop %rax
  
        /* Copy hypercall result registers to arg struct if needed */
-       testq $TDX_HCALL_HAS_OUTPUT, %rsi
+       testq $TDX_HCALL_HAS_OUTPUT, (%rsp)
        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)
+       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)
  .Lout:
+       /* 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 R12-R15). R12-R15
-        * context will be restored.
+        * 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
+       /* Remove TDX_HCALL_* flags from the stack */
+       pop %rsi
  
        /* Restore callee-saved GPRs as mandated by the x86_64 ABI */
+       pop %rbx
        pop %r12
        pop %r13
        pop %r14
diff --combined arch/x86/coco/tdx/tdx.c
index 3bd111d5e6a0998a5f225ec21661c161121867b6,b593009b30ab6c62e43d190e922a1a68df1b3a5c..055300e08fb382685356827749969caf03870b81
  #define TDX_GET_VEINFO                        3
  #define TDX_GET_REPORT                        4
  #define TDX_ACCEPT_PAGE                       6
+ #define TDX_WR                                8
+ /* TDCS fields. To be used by TDG.VM.WR and TDG.VM.RD module calls */
+ #define TDCS_NOTIFY_ENABLES           0x9100000000000010
  
  /* TDX hypercall Leaf IDs */
  #define TDVMCALL_MAP_GPA              0x10001
+ #define TDVMCALL_REPORT_FATAL_ERROR   0x10003
  
  /* MMIO direction */
  #define EPT_READ      0
@@@ -37,6 -42,7 +42,7 @@@
  #define VE_GET_PORT_NUM(e)    ((e) >> 16)
  #define VE_IS_IO_STRING(e)    ((e) & BIT(4))
  
+ #define ATTR_DEBUG            BIT(0)
  #define ATTR_SEPT_VE_DISABLE  BIT(28)
  
  /* TDX Module call error codes */
@@@ -64,9 -70,8 +70,9 @@@ static inline u64 _tdx_hypercall(u64 fn
  }
  
  /* Called from __tdx_hypercall() for unrecoverable failure */
 -void __tdx_hypercall_failed(void)
 +noinstr void __tdx_hypercall_failed(void)
  {
 +      instrumentation_begin();
        panic("TDVMCALL failed. TDX module bug?");
  }
  
@@@ -76,7 -81,7 +82,7 @@@
   * Reusing the KVM EXIT_REASON macros makes it easier to connect the host and
   * guest sides of these calls.
   */
 -static u64 hcall_func(u64 exit_reason)
 +static __always_inline u64 hcall_func(u64 exit_reason)
  {
        return exit_reason;
  }
@@@ -141,6 -146,41 +147,41 @@@ int tdx_mcall_get_report0(u8 *reportdat
  }
  EXPORT_SYMBOL_GPL(tdx_mcall_get_report0);
  
+ static void __noreturn tdx_panic(const char *msg)
+ {
+       struct tdx_hypercall_args args = {
+               .r10 = TDX_HYPERCALL_STANDARD,
+               .r11 = TDVMCALL_REPORT_FATAL_ERROR,
+               .r12 = 0, /* Error code: 0 is Panic */
+       };
+       union {
+               /* Define register order according to the GHCI */
+               struct { u64 r14, r15, rbx, rdi, rsi, r8, r9, rdx; };
+               char str[64];
+       } message;
+       /* VMM assumes '\0' in byte 65, if the message took all 64 bytes */
+       strncpy(message.str, msg, 64);
+       args.r8  = message.r8;
+       args.r9  = message.r9;
+       args.r14 = message.r14;
+       args.r15 = message.r15;
+       args.rdi = message.rdi;
+       args.rsi = message.rsi;
+       args.rbx = message.rbx;
+       args.rdx = message.rdx;
+       /*
+        * This hypercall should never return and it is not safe
+        * to keep the guest running. Call it forever if it
+        * happens to return.
+        */
+       while (1)
+               __tdx_hypercall(&args, 0);
+ }
  static void tdx_parse_tdinfo(u64 *cc_mask)
  {
        struct tdx_module_output out;
         * TD-private memory.  Only VMM-shared memory (MMIO) will #VE.
         */
        td_attr = out.rdx;
-       if (!(td_attr & ATTR_SEPT_VE_DISABLE))
-               panic("TD misconfiguration: SEPT_VE_DISABLE attibute must be set.\n");
+       if (!(td_attr & ATTR_SEPT_VE_DISABLE)) {
+               const char *msg = "TD misconfiguration: SEPT_VE_DISABLE attribute must be set.";
+               /* Relax SEPT_VE_DISABLE check for debug TD. */
+               if (td_attr & ATTR_DEBUG)
+                       pr_warn("%s\n", msg);
+               else
+                       tdx_panic(msg);
+       }
  }
  
  /*
@@@ -221,7 -268,7 +269,7 @@@ static int ve_instr_len(struct ve_info 
        }
  }
  
 -static u64 __cpuidle __halt(const bool irq_disabled, const bool do_sti)
 +static u64 __cpuidle __halt(const bool irq_disabled)
  {
        struct tdx_hypercall_args args = {
                .r10 = TDX_HYPERCALL_STANDARD,
         * can keep the vCPU in virtual HLT, even if an IRQ is
         * pending, without hanging/breaking the guest.
         */
 -      return __tdx_hypercall(&args, do_sti ? TDX_HCALL_ISSUE_STI : 0);
 +      return __tdx_hypercall(&args, 0);
  }
  
  static int handle_halt(struct ve_info *ve)
  {
 -      /*
 -       * Since non safe halt is mainly used in CPU offlining
 -       * and the guest will always stay in the halt state, don't
 -       * call the STI instruction (set do_sti as false).
 -       */
        const bool irq_disabled = irqs_disabled();
 -      const bool do_sti = false;
  
 -      if (__halt(irq_disabled, do_sti))
 +      if (__halt(irq_disabled))
                return -EIO;
  
        return ve_instr_len(ve);
  
  void __cpuidle tdx_safe_halt(void)
  {
 -       /*
 -        * For do_sti=true case, __tdx_hypercall() function enables
 -        * interrupts using the STI instruction before the TDCALL. So
 -        * set irq_disabled as false.
 -        */
        const bool irq_disabled = false;
 -      const bool do_sti = true;
  
        /*
         * Use WARN_ONCE() to report the failure.
         */
 -      if (__halt(irq_disabled, do_sti))
 +      if (__halt(irq_disabled))
                WARN_ONCE(1, "HLT instruction emulation failed\n");
  }
  
@@@ -617,6 -676,11 +665,11 @@@ static int virt_exception_user(struct p
        }
  }
  
+ static inline bool is_private_gpa(u64 gpa)
+ {
+       return gpa == cc_mkenc(gpa);
+ }
  /*
   * Handle the kernel #VE.
   *
@@@ -635,6 -699,8 +688,8 @@@ static int virt_exception_kernel(struc
        case EXIT_REASON_CPUID:
                return handle_cpuid(regs, ve);
        case EXIT_REASON_EPT_VIOLATION:
+               if (is_private_gpa(ve->gpa))
+                       panic("Unexpected EPT-violation on private memory.");
                return handle_mmio(regs, ve);
        case EXIT_REASON_IO_INSTRUCTION:
                return handle_io(regs, ve);
@@@ -801,6 -867,9 +856,9 @@@ void __init tdx_early_init(void
        tdx_parse_tdinfo(&cc_mask);
        cc_set_mask(cc_mask);
  
+       /* Kernel does not use NOTIFY_ENABLES and does not need random #VEs */
+       tdx_module_call(TDX_WR, 0, TDCS_NOTIFY_ENABLES, 0, -1ULL, NULL);
        /*
         * All bits above GPA width are reserved and kernel treats shared bit
         * as flag, not as part of physical address.
index 559176887791ea6668f0707a8551a84dea77a7f9,8068faa52de1bbf0185949aaf5e8fc81e76ea373..4a03993e07851e8e400077999db0d37989002296
@@@ -8,6 -8,7 +8,6 @@@
  #define TDX_HYPERCALL_STANDARD  0
  
  #define TDX_HCALL_HAS_OUTPUT  BIT(0)
 -#define TDX_HCALL_ISSUE_STI   BIT(1)
  
  #define TDX_CPUID_LEAF_ID     0x21
  #define TDX_IDENT             "IntelTDX    "
   * This is a software only structure and not part of the TDX module/VMM ABI.
   */
  struct tdx_hypercall_args {
+       u64 r8;
+       u64 r9;
        u64 r10;
        u64 r11;
        u64 r12;
        u64 r13;
        u64 r14;
        u64 r15;
+       u64 rdi;
+       u64 rsi;
+       u64 rbx;
+       u64 rdx;
  };
  
  /* Used to request services from the VMM */
index ef9e951415c52305a6a49b63292c66bf5449f355,8650f29387e07540e5fce28498a12c25204fe191..283dcd2f62c8f7a10896346795a82ccd8411d233
@@@ -7,7 -7,6 +7,7 @@@
  #define COMPILE_OFFSETS
  
  #include <linux/crypto.h>
 +#include <crypto/aria.h>
  #include <linux/sched.h>
  #include <linux/stddef.h>
  #include <linux/hardirq.h>
@@@ -76,12 -75,18 +76,18 @@@ static void __used common(void
        OFFSET(TDX_MODULE_r11, tdx_module_output, r11);
  
        BLANK();
+       OFFSET(TDX_HYPERCALL_r8,  tdx_hypercall_args, r8);
+       OFFSET(TDX_HYPERCALL_r9,  tdx_hypercall_args, r9);
        OFFSET(TDX_HYPERCALL_r10, tdx_hypercall_args, r10);
        OFFSET(TDX_HYPERCALL_r11, tdx_hypercall_args, r11);
        OFFSET(TDX_HYPERCALL_r12, tdx_hypercall_args, r12);
        OFFSET(TDX_HYPERCALL_r13, tdx_hypercall_args, r13);
        OFFSET(TDX_HYPERCALL_r14, tdx_hypercall_args, r14);
        OFFSET(TDX_HYPERCALL_r15, tdx_hypercall_args, r15);
+       OFFSET(TDX_HYPERCALL_rdi, tdx_hypercall_args, rdi);
+       OFFSET(TDX_HYPERCALL_rsi, tdx_hypercall_args, rsi);
+       OFFSET(TDX_HYPERCALL_rbx, tdx_hypercall_args, rbx);
+       OFFSET(TDX_HYPERCALL_rdx, tdx_hypercall_args, rdx);
  
        BLANK();
        OFFSET(BP_scratch, boot_params, scratch);
  #ifdef CONFIG_CALL_DEPTH_TRACKING
        OFFSET(X86_call_depth, pcpu_hot, call_depth);
  #endif
 +#if IS_ENABLED(CONFIG_CRYPTO_ARIA_AESNI_AVX_X86_64)
 +      /* Offset for fields in aria_ctx */
 +      BLANK();
 +      OFFSET(ARIA_CTX_enc_key, aria_ctx, enc_key);
 +      OFFSET(ARIA_CTX_dec_key, aria_ctx, dec_key);
 +      OFFSET(ARIA_CTX_rounds, aria_ctx, rounds);
 +#endif
  
  }