:: commit ab5936bd5833b9ba7c3d89a1f7077e55bcd79289

Mintsuki <mintsuki@protonmail.com> — 2026-02-24 20:31

parents: bfde2899fc

sys/lapic: Preserve LVT entries with SMI/INIT/reserved delivery modes

diff --git a/common/sys/lapic.c b/common/sys/lapic.c
index ddaa7f10..0efc1213 100644
--- a/common/sys/lapic.c
+++ b/common/sys/lapic.c
@@ -20,8 +20,8 @@
 #define LAPIC_REG_TPR         0x080
 #define LAPIC_REG_VERSION     0x030
 
-static uint32_t pending_lint0 = 0x00010000; // masked
-static uint32_t pending_lint1 = 0x00010000; // masked
+static uint32_t pending_lint0 = UINT32_MAX; // no override
+static uint32_t pending_lint1 = UINT32_MAX; // no override
 
 static uint32_t lapic_madt_nmi_flags_to_lvt(uint16_t flags) {
     uint32_t lvt = 0x10400; // masked + NMI delivery mode
@@ -43,14 +43,9 @@ static uint32_t lapic_madt_nmi_flags_to_lvt(uint16_t flags) {
     return lvt;
 }
 
-void lapic_prep_lint(struct madt *madt, uint32_t acpi_uid, bool is_bsp, bool x2apic) {
-    // Set defaults
-    if (is_bsp) {
-        pending_lint0 = 0x00010700; // ExtINT delivery mode, masked
-    } else {
-        pending_lint0 = 0x00010000; // masked
-    }
-    pending_lint1 = 0x00010000; // masked
+void lapic_prep_lint(struct madt *madt, uint32_t acpi_uid, bool x2apic) {
+    pending_lint0 = UINT32_MAX; // no override
+    pending_lint1 = UINT32_MAX; // no override
 
     // Walk MADT entries looking for NMI entries
     for (uint8_t *madt_ptr = (uint8_t *)madt->madt_entries_begin;
@@ -109,6 +104,18 @@ void lapic_prep_lint(struct madt *madt, uint32_t acpi_uid, bool is_bsp, bool x2a
     }
 }
 
+static bool lvt_should_mask(uint32_t lvt) {
+    switch ((lvt >> 8) & 7) {
+        case 0b000: // Fixed
+        case 0b001: // Lowest Priority
+        case 0b100: // NMI
+        case 0b111: // ExtINT
+            return true;
+        default:    // SMI, INIT, Reserved
+            return false;
+    }
+}
+
 void lapic_configure_handoff_state(void) {
     bool is_x2 = !!(rdmsr(0x1b) & (1 << 10));
 
@@ -119,38 +126,82 @@ void lapic_configure_handoff_state(void) {
         max_lvt = (lapic_read(LAPIC_REG_VERSION) >> 16) & 0xff;
     }
 
+    uint32_t lvt;
+
     if (is_x2) {
         x2apic_write(LAPIC_REG_SVR, 0x1ff);
         x2apic_write(LAPIC_REG_TPR, 0);
         if (max_lvt >= 6) {
-            x2apic_write(LAPIC_REG_LVT_CMCI, 0x00010000);
+            lvt = x2apic_read(LAPIC_REG_LVT_CMCI);
+            if (lvt_should_mask(lvt)) {
+                x2apic_write(LAPIC_REG_LVT_CMCI, lvt | (1 << 16));
+            }
+        }
+        lvt = x2apic_read(LAPIC_REG_LVT_TIMER);
+        if (lvt_should_mask(lvt)) {
+            x2apic_write(LAPIC_REG_LVT_TIMER, lvt | (1 << 16));
         }
-        x2apic_write(LAPIC_REG_LVT_TIMER, 0x00010000);
         if (max_lvt >= 5) {
-            x2apic_write(LAPIC_REG_LVT_THERMAL, 0x00010000);
+            lvt = x2apic_read(LAPIC_REG_LVT_THERMAL);
+            if (lvt_should_mask(lvt)) {
+                x2apic_write(LAPIC_REG_LVT_THERMAL, lvt | (1 << 16));
+            }
         }
         if (max_lvt >= 4) {
-            x2apic_write(LAPIC_REG_LVT_PMC, 0x00010000);
+            lvt = x2apic_read(LAPIC_REG_LVT_PMC);
+            if (lvt_should_mask(lvt)) {
+                x2apic_write(LAPIC_REG_LVT_PMC, lvt | (1 << 16));
+            }
+        }
+        lvt = x2apic_read(LAPIC_REG_LVT_ERROR);
+        if (lvt_should_mask(lvt)) {
+            x2apic_write(LAPIC_REG_LVT_ERROR, lvt | (1 << 16));
+        }
+        lvt = x2apic_read(LAPIC_REG_LVT_LINT0);
+        if (lvt_should_mask(lvt)) {
+            x2apic_write(LAPIC_REG_LVT_LINT0, pending_lint0 != UINT32_MAX ? pending_lint0 : lvt | (1 << 16));
+        }
+        lvt = x2apic_read(LAPIC_REG_LVT_LINT1);
+        if (lvt_should_mask(lvt)) {
+            x2apic_write(LAPIC_REG_LVT_LINT1, pending_lint1 != UINT32_MAX ? pending_lint1 : lvt | (1 << 16));
         }
-        x2apic_write(LAPIC_REG_LVT_ERROR, 0x00010000);
-        x2apic_write(LAPIC_REG_LVT_LINT0, pending_lint0);
-        x2apic_write(LAPIC_REG_LVT_LINT1, pending_lint1);
     } else {
         lapic_write(LAPIC_REG_SVR, 0x1ff);
         lapic_write(LAPIC_REG_TPR, 0);
         if (max_lvt >= 6) {
-            lapic_write(LAPIC_REG_LVT_CMCI, 0x00010000);
+            lvt = lapic_read(LAPIC_REG_LVT_CMCI);
+            if (lvt_should_mask(lvt)) {
+                lapic_write(LAPIC_REG_LVT_CMCI, lvt | (1 << 16));
+            }
+        }
+        lvt = lapic_read(LAPIC_REG_LVT_TIMER);
+        if (lvt_should_mask(lvt)) {
+            lapic_write(LAPIC_REG_LVT_TIMER, lvt | (1 << 16));
         }
-        lapic_write(LAPIC_REG_LVT_TIMER, 0x00010000);
         if (max_lvt >= 5) {
-            lapic_write(LAPIC_REG_LVT_THERMAL, 0x00010000);
+            lvt = lapic_read(LAPIC_REG_LVT_THERMAL);
+            if (lvt_should_mask(lvt)) {
+                lapic_write(LAPIC_REG_LVT_THERMAL, lvt | (1 << 16));
+            }
         }
         if (max_lvt >= 4) {
-            lapic_write(LAPIC_REG_LVT_PMC, 0x00010000);
+            lvt = lapic_read(LAPIC_REG_LVT_PMC);
+            if (lvt_should_mask(lvt)) {
+                lapic_write(LAPIC_REG_LVT_PMC, lvt | (1 << 16));
+            }
+        }
+        lvt = lapic_read(LAPIC_REG_LVT_ERROR);
+        if (lvt_should_mask(lvt)) {
+            lapic_write(LAPIC_REG_LVT_ERROR, lvt | (1 << 16));
+        }
+        lvt = lapic_read(LAPIC_REG_LVT_LINT0);
+        if (lvt_should_mask(lvt)) {
+            lapic_write(LAPIC_REG_LVT_LINT0, pending_lint0 != UINT32_MAX ? pending_lint0 : lvt | (1 << 16));
+        }
+        lvt = lapic_read(LAPIC_REG_LVT_LINT1);
+        if (lvt_should_mask(lvt)) {
+            lapic_write(LAPIC_REG_LVT_LINT1, pending_lint1 != UINT32_MAX ? pending_lint1 : lvt | (1 << 16));
         }
-        lapic_write(LAPIC_REG_LVT_ERROR, 0x00010000);
-        lapic_write(LAPIC_REG_LVT_LINT0, pending_lint0);
-        lapic_write(LAPIC_REG_LVT_LINT1, pending_lint1);
     }
 }
 
@@ -209,7 +260,7 @@ void lapic_configure_bsp(void) {
     }
 
 found:
-    lapic_prep_lint(madt, bsp_acpi_uid, true, is_x2);
+    lapic_prep_lint(madt, bsp_acpi_uid, is_x2);
     lapic_configure_handoff_state();
 }
 
diff --git a/common/sys/lapic.h b/common/sys/lapic.h
index 9edcfd69..876cc05c 100644
--- a/common/sys/lapic.h
+++ b/common/sys/lapic.h
@@ -26,7 +26,7 @@ uint64_t x2apic_read(uint32_t reg);
 void x2apic_write(uint32_t reg, uint64_t data);
 
 void lapic_configure_bsp(void);
-void lapic_prep_lint(struct madt *madt, uint32_t acpi_uid, bool is_bsp, bool x2apic);
+void lapic_prep_lint(struct madt *madt, uint32_t acpi_uid, bool x2apic);
 void lapic_configure_handoff_state(void);
 
 void init_io_apics(void);
diff --git a/common/sys/smp.c b/common/sys/smp.c
index 4ecc3049..403957c8 100644
--- a/common/sys/smp.c
+++ b/common/sys/smp.c
@@ -252,7 +252,7 @@ struct limine_mp_info *init_smp(size_t   *cpu_count,
 
                 // Set up per-AP LINT values before starting
                 if (smp_configure_apic) {
-                    lapic_prep_lint(madt, lapic->acpi_processor_uid, false, x2apic);
+                    lapic_prep_lint(madt, lapic->acpi_processor_uid, x2apic);
                 }
 
                 // Try to start the AP
@@ -297,7 +297,7 @@ struct limine_mp_info *init_smp(size_t   *cpu_count,
 
                 // Set up per-AP LINT values before starting
                 if (smp_configure_apic) {
-                    lapic_prep_lint(madt, x2lapic->acpi_processor_uid, false, true);
+                    lapic_prep_lint(madt, x2lapic->acpi_processor_uid, true);
                 }
 
                 // Try to start the AP
tab: 248 wrap: offon