Merge tag 'x86_tdx_for_6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
[linux-block.git] / arch / x86 / coco / tdx / tdx.c
index 3bd111d5e6a0998a5f225ec21661c161121867b6..055300e08fb382685356827749969caf03870b81 100644 (file)
 #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 @@
 #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 */
@@ -141,6 +147,41 @@ int tdx_mcall_get_report0(u8 *reportdata, u8 *tdreport)
 }
 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;
@@ -172,8 +213,15 @@ static void tdx_parse_tdinfo(u64 *cc_mask)
         * 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);
+       }
 }
 
 /*
@@ -617,6 +665,11 @@ static int virt_exception_user(struct pt_regs *regs, struct ve_info *ve)
        }
 }
 
+static inline bool is_private_gpa(u64 gpa)
+{
+       return gpa == cc_mkenc(gpa);
+}
+
 /*
  * Handle the kernel #VE.
  *
@@ -635,6 +688,8 @@ static int virt_exception_kernel(struct pt_regs *regs, struct ve_info *ve)
        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 +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.