x86/traps: Add sysvec_install() to install a system interrupt handler
authorXin Li <xin3.li@intel.com>
Tue, 5 Dec 2023 10:50:16 +0000 (02:50 -0800)
committerBorislav Petkov (AMD) <bp@alien8.de>
Wed, 31 Jan 2024 21:02:36 +0000 (22:02 +0100)
Add sysvec_install() to install a system interrupt handler into the IDT
or the FRED system interrupt handler table.

Signed-off-by: Xin Li <xin3.li@intel.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Tested-by: Shan Kang <shan.kang@intel.com>
Link: https://lore.kernel.org/r/20231205105030.8698-28-xin3.li@intel.com
arch/x86/entry/entry_fred.c
arch/x86/include/asm/desc.h
arch/x86/include/asm/idtentry.h
arch/x86/kernel/cpu/acrn.c
arch/x86/kernel/cpu/mshyperv.c
arch/x86/kernel/idt.c
arch/x86/kernel/kvm.c
drivers/xen/events/events_base.c

index 125b62311b31f904b9149f2c4c660ba79c5f6b81..3be0269bc0d465857da3b95308a78b3854ac03d9 100644 (file)
@@ -119,6 +119,20 @@ static idtentry_t sysvec_table[NR_SYSTEM_VECTORS] __ro_after_init = {
        SYSVEC(POSTED_INTR_NESTED_VECTOR,       kvm_posted_intr_nested_ipi),
 };
 
+static bool fred_setup_done __initdata;
+
+void __init fred_install_sysvec(unsigned int sysvec, idtentry_t handler)
+{
+       if (WARN_ON_ONCE(sysvec < FIRST_SYSTEM_VECTOR))
+               return;
+
+       if (WARN_ON_ONCE(fred_setup_done))
+               return;
+
+       if (!WARN_ON_ONCE(sysvec_table[sysvec - FIRST_SYSTEM_VECTOR]))
+                sysvec_table[sysvec - FIRST_SYSTEM_VECTOR] = handler;
+}
+
 static noinstr void fred_extint(struct pt_regs *regs)
 {
        unsigned int vector = regs->fred_ss.vector;
index ab97b22ac04a263ab78782a9d00f2237c98e0f20..ec95fe44fa3a03a1708bc0d8474595258db6027f 100644 (file)
@@ -402,8 +402,6 @@ static inline void set_desc_limit(struct desc_struct *desc, unsigned long limit)
        desc->limit1 = (limit >> 16) & 0xf;
 }
 
-void alloc_intr_gate(unsigned int n, const void *addr);
-
 static inline void init_idt_data(struct idt_data *data, unsigned int n,
                                 const void *addr)
 {
index 570f286ca7ddae23214c90d0ef39d23cea164953..47d4c04d103df4eb824fef8297f0b77c39dee1c1 100644 (file)
@@ -459,6 +459,21 @@ __visible noinstr void func(struct pt_regs *regs,                  \
 #define DEFINE_FREDENTRY_DEBUG         DEFINE_FREDENTRY_RAW
 #endif
 
+void idt_install_sysvec(unsigned int n, const void *function);
+
+#ifdef CONFIG_X86_FRED
+void fred_install_sysvec(unsigned int vector, const idtentry_t function);
+#else
+static inline void fred_install_sysvec(unsigned int vector, const idtentry_t function) { }
+#endif
+
+#define sysvec_install(vector, function) {                             \
+       if (cpu_feature_enabled(X86_FEATURE_FRED))                      \
+               fred_install_sysvec(vector, function);                  \
+       else                                                            \
+               idt_install_sysvec(vector, asm_##function);             \
+}
+
 #else /* !__ASSEMBLY__ */
 
 /*
index bfeb18fad63f154ef8357ef75eec1b941b6b46dd..2c5b51aad91a03f0cc2b302087c383f0f882dbb4 100644 (file)
@@ -26,8 +26,8 @@ static u32 __init acrn_detect(void)
 
 static void __init acrn_init_platform(void)
 {
-       /* Setup the IDT for ACRN hypervisor callback */
-       alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, asm_sysvec_acrn_hv_callback);
+       /* Install system interrupt handler for ACRN hypervisor callback */
+       sysvec_install(HYPERVISOR_CALLBACK_VECTOR, sysvec_acrn_hv_callback);
 
        x86_platform.calibrate_tsc = acrn_get_tsc_khz;
        x86_platform.calibrate_cpu = acrn_get_tsc_khz;
index 01fa06dd06b66c9324c670e4847c0d503dbd5691..45e0e70e238cf31a0e51024d0f88505b6a6ce9c4 100644 (file)
@@ -539,19 +539,18 @@ static void __init ms_hyperv_init_platform(void)
         */
        x86_platform.apic_post_init = hyperv_init;
        hyperv_setup_mmu_ops();
-       /* Setup the IDT for hypervisor callback */
-       alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, asm_sysvec_hyperv_callback);
 
-       /* Setup the IDT for reenlightenment notifications */
+       /* Install system interrupt handler for hypervisor callback */
+       sysvec_install(HYPERVISOR_CALLBACK_VECTOR, sysvec_hyperv_callback);
+
+       /* Install system interrupt handler for reenlightenment notifications */
        if (ms_hyperv.features & HV_ACCESS_REENLIGHTENMENT) {
-               alloc_intr_gate(HYPERV_REENLIGHTENMENT_VECTOR,
-                               asm_sysvec_hyperv_reenlightenment);
+               sysvec_install(HYPERV_REENLIGHTENMENT_VECTOR, sysvec_hyperv_reenlightenment);
        }
 
-       /* Setup the IDT for stimer0 */
+       /* Install system interrupt handler for stimer0 */
        if (ms_hyperv.misc_features & HV_STIMER_DIRECT_MODE_AVAILABLE) {
-               alloc_intr_gate(HYPERV_STIMER0_VECTOR,
-                               asm_sysvec_hyperv_stimer0);
+               sysvec_install(HYPERV_STIMER0_VECTOR, sysvec_hyperv_stimer0);
        }
 
 # ifdef CONFIG_SMP
index 660b601f1d6c33e9ad62ec2d12d860e92d4ea420..0cd53fa8c65d1d63ed4a11a7a2f7c88ba4122d51 100644 (file)
@@ -337,7 +337,7 @@ void idt_invalidate(void)
        load_idt(&idt);
 }
 
-void __init alloc_intr_gate(unsigned int n, const void *addr)
+void __init idt_install_sysvec(unsigned int n, const void *function)
 {
        if (WARN_ON(n < FIRST_SYSTEM_VECTOR))
                return;
@@ -346,5 +346,5 @@ void __init alloc_intr_gate(unsigned int n, const void *addr)
                return;
 
        if (!WARN_ON(test_and_set_bit(n, system_vectors)))
-               set_intr_gate(n, addr);
+               set_intr_gate(n, function);
 }
index dfe9945b9becee7f6d0ca89d00fd3c1eb4e496c5..b05557918ae20a5be2541e0ea1bc51fcdae5c5a9 100644 (file)
@@ -829,7 +829,7 @@ static void __init kvm_guest_init(void)
 
        if (kvm_para_has_feature(KVM_FEATURE_ASYNC_PF_INT) && kvmapf) {
                static_branch_enable(&kvm_async_pf_enabled);
-               alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, asm_sysvec_kvm_asyncpf_interrupt);
+               sysvec_install(HYPERVISOR_CALLBACK_VECTOR, sysvec_kvm_asyncpf_interrupt);
        }
 
 #ifdef CONFIG_SMP
index b8cfea7812d6b61110cc5e42fe4249d4578dc721..e2813bac92d40c7b39879caec22b3267ee95dd2c 100644 (file)
@@ -2216,7 +2216,7 @@ static __init void xen_alloc_callback_vector(void)
                return;
 
        pr_info("Xen HVM callback vector for event delivery is enabled\n");
-       alloc_intr_gate(HYPERVISOR_CALLBACK_VECTOR, asm_sysvec_xen_hvm_callback);
+       sysvec_install(HYPERVISOR_CALLBACK_VECTOR, sysvec_xen_hvm_callback);
 }
 #else
 void xen_setup_callback_vector(void) {}