git: 11f954b021a1 - main - x86: mask all LAPIC vectors early, before BSP interrupts are enabled

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Sun, 18 Jan 2026 19:49:21 UTC
The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=11f954b021a1aadde1d03d40ed5d6b529e14da98

commit 11f954b021a1aadde1d03d40ed5d6b529e14da98
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2025-12-09 02:18:21 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2026-01-18 19:47:26 +0000

    x86: mask all LAPIC vectors early, before BSP interrupts are enabled
    
    If APIC is left in somewhat bad state, with some source hot (not masked
    and active, e.g. timers after kexec or due to BIOS bug), we get the
    interrupt too early.
    
    Reported by:    jmg
    Reviewed by:    markj
    Tested by:      pho
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D54543
---
 sys/x86/x86/local_apic.c | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/sys/x86/x86/local_apic.c b/sys/x86/x86/local_apic.c
index aecad4cbd463..053d9814c14c 100644
--- a/sys/x86/x86/local_apic.c
+++ b/sys/x86/x86/local_apic.c
@@ -428,6 +428,7 @@ lapic_is_x2apic(void)
 	    (APICBASE_X2APIC | APICBASE_ENABLED));
 }
 
+static void	lapic_early_mask_vecs(void);
 static void	lapic_enable(void);
 static void	lapic_resume(struct pic *pic, bool suspend_cancelled);
 static void	lapic_timer_oneshot(struct lapic *);
@@ -553,6 +554,7 @@ lapic_init(vm_paddr_t addr)
 
 	/* Perform basic initialization of the BSP's local APIC. */
 	lapic_enable();
+	lapic_early_mask_vecs();
 
 	/* Set BSP's per-CPU local APIC ID. */
 	PCPU_SET(apic_id, lapic_id());
@@ -791,6 +793,32 @@ lapic_xapic_mode(void)
 	intr_restore(saveintr);
 }
 
+static void
+lapic_early_mask_vec(const struct lvt *l)
+{
+	uint32_t v;
+
+	if (l->lvt_masked != 0) {
+		v = lapic_read32(l->lvt_reg);
+		v |= APIC_LVT_M;
+		lapic_write32(l->lvt_reg, v);
+	}
+}
+
+/* Done on BSP only */
+static void
+lapic_early_mask_vecs(void)
+{
+	int elvt_count, i;
+
+	for (i = 0; i < APIC_LVT_MAX; i++)
+		lapic_early_mask_vec(&lvts[i]);
+
+	elvt_count = amd_read_elvt_count();
+	for (i = 0; i < elvt_count; i++)
+		lapic_early_mask_vec(&elvts[i]);
+}
+
 void
 lapic_setup(int boot)
 {