@@ -12,6 +12,10 @@
#include <asm/insn.h>
#include <asm/insn-eval.h>
#include <asm/x86_init.h>
+#include <asm/apic.h>
+#include <asm/idtentry.h>
+#include <asm/irq_regs.h>
+#include <asm/desc.h>
/* TDX module Call Leaf IDs */
#define TDX_GET_INFO 1
@@ -49,6 +53,14 @@ static struct {
unsigned long attributes;
} td_info __ro_after_init;
+/*
+ * Currently it will be used only by the attestation
+ * driver. So, race condition with read/write operation
+ * is not considered.
+ */
+void (*tdx_event_notify_handler)(void);
+EXPORT_SYMBOL_GPL(tdx_event_notify_handler);
+
/*
* Wrapper for standard use of __tdx_hypercall with no output aside from
* return code.
@@ -91,6 +103,28 @@ static inline void tdx_module_call(u64 fn, u64 rcx, u64 rdx, u64 r8, u64 r9,
panic("TDCALL %lld failed (Buggy TDX module!)\n", fn);
}
+/* TDX guest event notification handler */
+DEFINE_IDTENTRY_SYSVEC(sysvec_tdx_event_notify)
+{
+ struct pt_regs *old_regs = set_irq_regs(regs);
+
+ inc_irq_stat(irq_tdx_event_notify_count);
+
+ if (tdx_event_notify_handler)
+ tdx_event_notify_handler();
+
+ /*
+ * The hypervisor requires that the APIC EOI should be acked.
+ * If the APIC EOI is not acked, the APIC ISR bit for the
+ * TDX_GUEST_EVENT_NOTIFY_VECTOR will not be cleared and then it
+ * will block the interrupt whose vector is lower than
+ * TDX_GUEST_EVENT_NOTIFY_VECTOR.
+ */
+ ack_APIC_irq();
+
+ set_irq_regs(old_regs);
+}
+
/*
* tdx_mcall_tdreport() - Generate TDREPORT_STRUCT using TDCALL.
*
@@ -727,5 +761,11 @@ void __init tdx_early_init(void)
swiotlb_force = SWIOTLB_FORCE;
+ alloc_intr_gate(TDX_GUEST_EVENT_NOTIFY_VECTOR,
+ asm_sysvec_tdx_event_notify);
+
+ if (tdx_hcall_set_notify_intr(TDX_GUEST_EVENT_NOTIFY_VECTOR))
+ pr_warn("Setting event notification interrupt failed\n");
+
pr_info("Guest detected\n");
}
@@ -44,6 +44,10 @@ typedef struct {
unsigned int irq_hv_reenlightenment_count;
unsigned int hyperv_stimer0_count;
#endif
+#if IS_ENABLED(CONFIG_INTEL_TDX_GUEST)
+ unsigned int tdx_ve_count;
+ unsigned int irq_tdx_event_notify_count;
+#endif
} ____cacheline_aligned irq_cpustat_t;
DECLARE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat);
@@ -693,6 +693,10 @@ DECLARE_IDTENTRY_SYSVEC(HYPERVISOR_CALLBACK_VECTOR, sysvec_xen_hvm_callback);
DECLARE_IDTENTRY_SYSVEC(HYPERVISOR_CALLBACK_VECTOR, sysvec_kvm_asyncpf_interrupt);
#endif
+#ifdef CONFIG_INTEL_TDX_GUEST
+DECLARE_IDTENTRY_SYSVEC(TDX_GUEST_EVENT_NOTIFY_VECTOR, sysvec_tdx_event_notify);
+#endif
+
#undef X86_TRAP_OTHER
#endif
@@ -104,7 +104,12 @@
#define HYPERV_STIMER0_VECTOR 0xed
#endif
-#define LOCAL_TIMER_VECTOR 0xec
+#if IS_ENABLED(CONFIG_INTEL_TDX_GUEST)
+/* Vector on which TDX Guest event notification is delivered */
+#define TDX_GUEST_EVENT_NOTIFY_VECTOR 0xec
+#endif
+
+#define LOCAL_TIMER_VECTOR 0xeb
#define NR_VECTORS 256
@@ -62,6 +62,7 @@ int tdx_mcall_tdreport(void *data, void *reportdata);
int tdx_hcall_get_quote(void *data);
+extern void (*tdx_event_notify_handler)(void);
#else
static inline void tdx_early_init(void) { };
@@ -181,6 +181,13 @@ int arch_show_interrupts(struct seq_file *p, int prec)
seq_printf(p, "%10u ",
irq_stats(j)->kvm_posted_intr_wakeup_ipis);
seq_puts(p, " Posted-interrupt wakeup event\n");
+#endif
+#if IS_ENABLED(CONFIG_INTEL_TDX_GUEST)
+ seq_printf(p, "%*s: ", prec, "TGN");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ",
+ irq_stats(j)->irq_tdx_event_notify_count);
+ seq_puts(p, " TDX Guest event notification\n");
#endif
return 0;
}