@@ -46,6 +46,7 @@ typedef struct {
#endif
#if IS_ENABLED(CONFIG_INTEL_TDX_GUEST)
unsigned int tdg_ve_count;
+ unsigned int irq_tdg_event_notify_count;
#endif
} ____cacheline_aligned irq_cpustat_t;
@@ -702,6 +702,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_tdg_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
@@ -100,6 +100,8 @@ int tdx_mcall_tdreport(u64 data, u64 reportdata);
int tdx_hcall_get_quote(u64 data);
+extern void (*tdg_event_notify_handler)(void);
+
/*
* To support I/O port access in decompressor or early kernel init
* code, since #VE exception handler cannot be used, use paravirt
@@ -182,11 +182,18 @@ int arch_show_interrupts(struct seq_file *p, int prec)
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, "TGV");
for_each_online_cpu(j)
seq_printf(p, "%10u ", irq_stats(j)->tdg_ve_count);
seq_puts(p, " TDX Guest VE event\n");
+
+ seq_printf(p, "%*s: ", prec, "TGN");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ",
+ irq_stats(j)->irq_tdg_event_notify_count);
+ seq_puts(p, " TDX Guest event notification\n");
#endif
return 0;
}
@@ -11,6 +11,11 @@
#include <asm/tdx.h>
#include <asm/cmdline.h>
#include <asm/i8259.h>
+#include <asm/apic.h>
+#include <asm/idtentry.h>
+#include <asm/irq_regs.h>
+#include <asm/desc.h>
+#include <asm/idtentry.h>
#include <asm/vmx.h>
#include <asm/insn.h>
#include <asm/insn-eval.h>
@@ -52,6 +57,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 (*tdg_event_notify_handler)(void);
+EXPORT_SYMBOL_GPL(tdg_event_notify_handler);
+
/*
* Wrapper for standard use of __tdx_hypercall with BUG_ON() check
* for TDCALL error.
@@ -150,6 +163,28 @@ static bool tdg_perfmon_enabled(void)
return td_info.attributes & BIT(63);
}
+/* TDX guest event notification handler */
+DEFINE_IDTENTRY_SYSVEC(sysvec_tdg_event_notify)
+{
+ struct pt_regs *old_regs = set_irq_regs(regs);
+
+ inc_irq_stat(irq_tdg_event_notify_count);
+
+ if (tdg_event_notify_handler)
+ tdg_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.
*
@@ -712,5 +747,11 @@ void __init tdx_early_init(void)
lock_kernel_down("TDX guest init", lockdown_reason);
}
+ alloc_intr_gate(TDX_GUEST_EVENT_NOTIFY_VECTOR,
+ asm_sysvec_tdg_event_notify);
+
+ if (tdx_hcall_set_notify_intr(TDX_GUEST_EVENT_NOTIFY_VECTOR))
+ pr_warn("Setting event notification interrupt failed\n");
+
pr_info("Guest initialized\n");
}