:: commit ea41baaf7500b25c0dbe9f8cf8a74944f2c39143

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

parents: 0a2fec6ac6

protos/limine: Implement base revision 5

diff --git a/bootstrap b/bootstrap
index 704d83fc..9fd1cbe9 100755
--- a/bootstrap
+++ b/bootstrap
@@ -85,7 +85,7 @@ if ! test -f version; then
     clone_repo_commit \
         https://codeberg.org/Limine/limine-protocol.git \
         limine-protocol \
-        42e836e30242c2c14f889fd76c6f9a57b0c18ec2
+        c76af54a01663d89a74c35b725f79d8af77eb811
 
     clone_repo_commit \
         https://codeberg.org/PicoEFI/PicoEFI.git \
diff --git a/common/lib/acpi.c b/common/lib/acpi.c
index abb9cccf..32e9c655 100644
--- a/common/lib/acpi.c
+++ b/common/lib/acpi.c
@@ -301,7 +301,7 @@ static void map_single_table(uint64_t addr, uint32_t len) {
     uint64_t memmap_type = pmm_check_type(addr);
 
     if (memmap_type != MEMMAP_ACPI_RECLAIMABLE && memmap_type != MEMMAP_ACPI_NVS) {
-        memmap_alloc_range(aligned_base, aligned_top - aligned_base, MEMMAP_ACPI_TABLES, 0, true, false, true);
+        memmap_alloc_range(aligned_base, aligned_top - aligned_base, MEMMAP_RESERVED_MAPPED, 0, true, false, true);
     }
 }
 
@@ -401,3 +401,75 @@ no_rsdt:;
         }
     }
 }
+
+void smbios_map_tables(void) {
+    void *smbios32_ptr = NULL, *smbios64_ptr = NULL;
+    acpi_get_smbios(&smbios32_ptr, &smbios64_ptr);
+
+    if (smbios32_ptr != NULL) {
+        struct smbios_entry_point_32 *smbios32 = smbios32_ptr;
+        map_single_table((uintptr_t)smbios32, smbios32->length);
+        if (smbios32->table_address != 0) {
+            map_single_table(smbios32->table_address, smbios32->table_length);
+        }
+    }
+
+    if (smbios64_ptr != NULL) {
+        struct smbios_entry_point_64 *smbios64 = smbios64_ptr;
+        map_single_table((uintptr_t)smbios64, smbios64->length);
+        if (smbios64->table_address != 0) {
+            map_single_table(smbios64->table_address, smbios64->table_maximum_size);
+        }
+    }
+}
+
+#if defined (UEFI)
+void efi_map_runtime_entries(void) {
+    size_t entry_count = efi_mmap_size / efi_desc_size;
+
+    for (size_t i = 0; i < entry_count; i++) {
+        EFI_MEMORY_DESCRIPTOR *entry = (void *)efi_mmap + i * efi_desc_size;
+
+        if (entry->Type != EfiRuntimeServicesCode
+         && entry->Type != EfiRuntimeServicesData) {
+            continue;
+        }
+
+        uint64_t base = entry->PhysicalStart;
+        uint64_t length;
+        if (__builtin_mul_overflow(entry->NumberOfPages, (uint64_t)4096, &length)) {
+            continue;
+        }
+
+        memmap_alloc_range(base, length, MEMMAP_RESERVED_MAPPED, 0, true, false, true);
+    }
+
+    // Explicitly map the EFI system table and the data it references.
+    // The UEFI spec does not guarantee these reside in EfiRuntimeServicesData,
+    // so we map them separately to ensure they are always accessible via HHDM.
+    map_single_table((uintptr_t)gST, sizeof(*gST));
+
+    if (gST->RuntimeServices != NULL) {
+        map_single_table((uintptr_t)gST->RuntimeServices,
+                         sizeof(*gST->RuntimeServices));
+    }
+
+    if (gST->ConfigurationTable != NULL && gST->NumberOfTableEntries > 0) {
+        uint64_t ct_size;
+        if (!__builtin_mul_overflow(gST->NumberOfTableEntries,
+                (uint64_t)sizeof(EFI_CONFIGURATION_TABLE), &ct_size)
+         && ct_size <= UINT32_MAX) {
+            map_single_table((uintptr_t)gST->ConfigurationTable, (uint32_t)ct_size);
+        }
+    }
+
+    if (gST->FirmwareVendor != NULL) {
+        size_t len = 0;
+        while (gST->FirmwareVendor[len] != 0) {
+            len++;
+        }
+        map_single_table((uintptr_t)gST->FirmwareVendor,
+                         (len + 1) * sizeof(*gST->FirmwareVendor));
+    }
+}
+#endif
diff --git a/common/lib/acpi.h b/common/lib/acpi.h
index d0e68031..89dd158d 100644
--- a/common/lib/acpi.h
+++ b/common/lib/acpi.h
@@ -138,6 +138,21 @@ struct madt_io_apic {
     uint32_t gsib;
 } __attribute__((packed));
 
+struct madt_lapic_nmi {
+    struct madt_header header;   // type=4, length=6
+    uint8_t  acpi_processor_uid; // 0xff = all processors
+    uint16_t flags;              // MPS INTI flags
+    uint8_t  lint;               // 0 or 1
+} __attribute__((packed));
+
+struct madt_x2apic_nmi {
+    struct madt_header header;   // type=0x0a, length=12
+    uint16_t flags;              // MPS INTI flags
+    uint32_t acpi_processor_uid; // 0xffffffff = all processors
+    uint8_t  lint;               // 0 or 1
+    uint8_t  reserved[3];
+} __attribute__((packed));
+
 struct madt_gicc {
     struct madt_header header;
     uint8_t  reserved1[2];
@@ -181,5 +196,10 @@ void   *acpi_get_table(const char *signature, int index);
 void    acpi_get_smbios(void **smbios32, void **smbios64);
 
 void acpi_map_tables(void);
+void smbios_map_tables(void);
+
+#if defined (UEFI)
+void efi_map_runtime_entries(void);
+#endif
 
 #endif
diff --git a/common/mm/pmm.h b/common/mm/pmm.h
index 27053e2a..e3bc4045 100644
--- a/common/mm/pmm.h
+++ b/common/mm/pmm.h
@@ -20,7 +20,7 @@ struct memmap_entry {
 #define MEMMAP_BOOTLOADER_RECLAIMABLE 0x1000
 #define MEMMAP_KERNEL_AND_MODULES     0x1001
 #define MEMMAP_FRAMEBUFFER            0x1002
-#define MEMMAP_ACPI_TABLES            0x1003
+#define MEMMAP_RESERVED_MAPPED        0x1003
 #define MEMMAP_EFI_RECLAIMABLE        0x2000
 
 struct meminfo {
diff --git a/common/mm/pmm.s2.c b/common/mm/pmm.s2.c
index d793436c..6cc74cb8 100644
--- a/common/mm/pmm.s2.c
+++ b/common/mm/pmm.s2.c
@@ -69,8 +69,8 @@ static const char *memmap_type(uint32_t type) {
             return "Usable RAM";
         case MEMMAP_RESERVED:
             return "Reserved";
-        case MEMMAP_ACPI_TABLES:
-            return "ACPI tables";
+        case MEMMAP_RESERVED_MAPPED:
+            return "Reserved (Mapped)";
         case MEMMAP_ACPI_RECLAIMABLE:
             return "ACPI reclaimable";
         case MEMMAP_ACPI_NVS:
@@ -219,10 +219,10 @@ del_mm1:
         m[p] = min_e;
     }
 
-    // Merge contiguous bootloader-reclaimable, ACPI tables, usable entries
+    // Merge contiguous bootloader-reclaimable, reserved (mapped), usable entries
     for (size_t i = 0; i + 1 < count; i++) {
         if (m[i].type != MEMMAP_BOOTLOADER_RECLAIMABLE
-         && m[i].type != MEMMAP_ACPI_TABLES
+         && m[i].type != MEMMAP_RESERVED_MAPPED
          && m[i].type != MEMMAP_USABLE)
             continue;
 
diff --git a/common/protos/limine.c b/common/protos/limine.c
index 0979430c..421c9c23 100644
--- a/common/protos/limine.c
+++ b/common/protos/limine.c
@@ -51,7 +51,7 @@ static enum executable_format detect_kernel_format(uint8_t *kernel, size_t kerne
     }
 }
 
-#define SUPPORTED_BASE_REVISION 4
+#define SUPPORTED_BASE_REVISION 5
 
 #define MAX_REQUESTS 128
 
@@ -1028,10 +1028,10 @@ FEAT_START
         ext_mem_alloc(sizeof(struct limine_smbios_response));
 
     if (smbios_entry_32) {
-        smbios_response->entry_32 = base_revision <= 2 ? reported_addr(smbios_entry_32) : (uintptr_t)smbios_entry_32;
+        smbios_response->entry_32 = (base_revision <= 2 || base_revision >= 5) ? reported_addr(smbios_entry_32) : (uintptr_t)smbios_entry_32;
     }
     if (smbios_entry_64) {
-        smbios_response->entry_64 = base_revision <= 2 ? reported_addr(smbios_entry_64) : (uintptr_t)smbios_entry_64;
+        smbios_response->entry_64 = (base_revision <= 2 || base_revision >= 5) ? reported_addr(smbios_entry_64) : (uintptr_t)smbios_entry_64;
     }
 
     smbios_request->response = reported_addr(smbios_response);
@@ -1048,7 +1048,7 @@ FEAT_START
     struct limine_efi_system_table_response *est_response =
         ext_mem_alloc(sizeof(struct limine_efi_system_table_response));
 
-    est_response->address = base_revision <= 2 ? reported_addr(gST) : (uintptr_t)gST;
+    est_response->address = (base_revision <= 2 || base_revision >= 5) ? reported_addr(gST) : (uintptr_t)gST;
 
     est_request->response = reported_addr(est_response);
 FEAT_END
@@ -1475,6 +1475,12 @@ FEAT_END
 
     if (base_revision >= 4) {
         acpi_map_tables();
+        if (base_revision >= 5) {
+            smbios_map_tables();
+#if defined (UEFI)
+            efi_map_runtime_entries();
+#endif
+        }
         pmm_sanitise_entries(memmap, &memmap_entries, true);
     }
 
@@ -1492,6 +1498,7 @@ FEAT_START
     struct limine_mp_info *mp_info;
     size_t cpu_count;
 #if defined (__x86_64__) || defined (__i386__)
+    smp_configure_apic = base_revision >= 5;
     uint32_t bsp_lapic_id;
     mp_info = init_smp(&cpu_count, &bsp_lapic_id,
                         paging_mode,
@@ -1610,8 +1617,8 @@ FEAT_START
             case MEMMAP_USABLE:
                 _memmap[i].type = LIMINE_MEMMAP_USABLE;
                 break;
-            case MEMMAP_ACPI_TABLES:
-                _memmap[i].type = LIMINE_MEMMAP_ACPI_TABLES;
+            case MEMMAP_RESERVED_MAPPED:
+                _memmap[i].type = LIMINE_MEMMAP_RESERVED_MAPPED;
                 break;
             case MEMMAP_ACPI_RECLAIMABLE:
                 _memmap[i].type = LIMINE_MEMMAP_ACPI_RECLAIMABLE;
@@ -1662,7 +1669,11 @@ FEAT_END
     iommu_disable_all();
 
     pic_mask_all();
-    io_apic_mask_all();
+    io_apic_mask_all(base_revision >= 5);
+
+    if (base_revision >= 5 && lapic_check()) {
+        lapic_configure_bsp();
+    }
 
     irq_flush_type = IRQ_PIC_APIC_FLUSH;
 
diff --git a/common/sys/lapic.c b/common/sys/lapic.c
index 39c688c3..e79abf51 100644
--- a/common/sys/lapic.c
+++ b/common/sys/lapic.c
@@ -9,6 +9,210 @@
 #include <lib/acpi.h>
 #include <mm/pmm.h>
 
+#define LAPIC_REG_LVT_CMCI    0x2f0
+#define LAPIC_REG_LVT_TIMER   0x320
+#define LAPIC_REG_LVT_THERMAL 0x330
+#define LAPIC_REG_LVT_PMC     0x340
+#define LAPIC_REG_LVT_LINT0   0x350
+#define LAPIC_REG_LVT_LINT1   0x360
+#define LAPIC_REG_LVT_ERROR   0x370
+#define LAPIC_REG_SVR         0x0f0
+#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 lapic_madt_nmi_flags_to_lvt(uint16_t flags) {
+    uint32_t lvt = 0x10400; // masked + NMI delivery mode
+
+    // Polarity: bits 1:0 of flags
+    uint8_t polarity = flags & 0x3;
+    if (polarity == 0x3) {
+        lvt |= (1 << 13); // active low
+    }
+    // 0b00 (conforms) and 0b01 (active high) leave bit 13 clear
+
+    // Trigger mode: bits 3:2 of flags
+    uint8_t trigger = (flags >> 2) & 0x3;
+    if (trigger == 0x3) {
+        lvt |= (1 << 15); // level triggered
+    }
+    // 0b00 (conforms) and 0b01 (edge) leave bit 15 clear
+
+    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
+
+    // Walk MADT entries looking for NMI entries
+    for (uint8_t *madt_ptr = (uint8_t *)madt->madt_entries_begin;
+      (uintptr_t)madt_ptr + 1 < (uintptr_t)madt + madt->header.length;
+      madt_ptr += *(madt_ptr + 1)) {
+        if (*(madt_ptr + 1) == 0) {
+            break;
+        }
+        switch (*madt_ptr) {
+            case 4: {
+                // Local APIC NMI
+                if (*(madt_ptr + 1) < sizeof(struct madt_lapic_nmi)) {
+                    continue;
+                }
+
+                struct madt_lapic_nmi *nmi = (void *)madt_ptr;
+
+                // Match all processors (0xff) or specific UID
+                if (nmi->acpi_processor_uid != 0xff && nmi->acpi_processor_uid != (uint8_t)acpi_uid) {
+                    continue;
+                }
+
+                uint32_t lvt = lapic_madt_nmi_flags_to_lvt(nmi->flags);
+                if (nmi->lint == 0) {
+                    pending_lint0 = lvt;
+                } else if (nmi->lint == 1) {
+                    pending_lint1 = lvt;
+                }
+                continue;
+            }
+            case 0x0a: {
+                // Local x2APIC NMI
+                if (!x2apic) {
+                    continue;
+                }
+                if (*(madt_ptr + 1) < sizeof(struct madt_x2apic_nmi)) {
+                    continue;
+                }
+
+                struct madt_x2apic_nmi *nmi = (void *)madt_ptr;
+
+                // Match all processors (0xffffffff) or specific UID
+                if (nmi->acpi_processor_uid != 0xffffffff && nmi->acpi_processor_uid != acpi_uid) {
+                    continue;
+                }
+
+                uint32_t lvt = lapic_madt_nmi_flags_to_lvt(nmi->flags);
+                if (nmi->lint == 0) {
+                    pending_lint0 = lvt;
+                } else if (nmi->lint == 1) {
+                    pending_lint1 = lvt;
+                }
+                continue;
+            }
+        }
+    }
+}
+
+void lapic_configure_handoff_state(void) {
+    bool is_x2 = !!(rdmsr(0x1b) & (1 << 10));
+
+    uint32_t max_lvt;
+    if (is_x2) {
+        max_lvt = (x2apic_read(LAPIC_REG_VERSION) >> 16) & 0xff;
+    } else {
+        max_lvt = (lapic_read(LAPIC_REG_VERSION) >> 16) & 0xff;
+    }
+
+    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);
+        }
+        x2apic_write(LAPIC_REG_LVT_TIMER, 0x00010000);
+        if (max_lvt >= 5) {
+            x2apic_write(LAPIC_REG_LVT_THERMAL, 0x00010000);
+        }
+        if (max_lvt >= 4) {
+            x2apic_write(LAPIC_REG_LVT_PMC, 0x00010000);
+        }
+        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);
+        }
+        lapic_write(LAPIC_REG_LVT_TIMER, 0x00010000);
+        if (max_lvt >= 5) {
+            lapic_write(LAPIC_REG_LVT_THERMAL, 0x00010000);
+        }
+        if (max_lvt >= 4) {
+            lapic_write(LAPIC_REG_LVT_PMC, 0x00010000);
+        }
+        lapic_write(LAPIC_REG_LVT_ERROR, 0x00010000);
+        lapic_write(LAPIC_REG_LVT_LINT0, pending_lint0);
+        lapic_write(LAPIC_REG_LVT_LINT1, pending_lint1);
+    }
+}
+
+void lapic_configure_bsp(void) {
+    struct madt *madt = acpi_get_table("APIC", 0);
+    if (madt == NULL) {
+        return;
+    }
+
+    // Detect x2APIC from MSR
+    bool is_x2 = !!(rdmsr(0x1b) & (1 << 10));
+
+    // Find the BSP entry by matching LAPIC ID
+    uint32_t bsp_lapic_id;
+    if (is_x2) {
+        bsp_lapic_id = x2apic_read(LAPIC_REG_ID);
+    } else {
+        bsp_lapic_id = lapic_read(LAPIC_REG_ID) >> 24;
+    }
+
+    uint32_t bsp_acpi_uid = 0;
+
+    for (uint8_t *madt_ptr = (uint8_t *)madt->madt_entries_begin;
+      (uintptr_t)madt_ptr + 1 < (uintptr_t)madt + madt->header.length;
+      madt_ptr += *(madt_ptr + 1)) {
+        if (*(madt_ptr + 1) == 0) {
+            break;
+        }
+        switch (*madt_ptr) {
+            case 0: {
+                if (*(madt_ptr + 1) < sizeof(struct madt_lapic)) {
+                    continue;
+                }
+                struct madt_lapic *lapic = (void *)madt_ptr;
+                if (lapic->lapic_id == bsp_lapic_id) {
+                    bsp_acpi_uid = lapic->acpi_processor_uid;
+                    goto found;
+                }
+                continue;
+            }
+            case 9: {
+                if (!is_x2) {
+                    continue;
+                }
+                if (*(madt_ptr + 1) < sizeof(struct madt_x2apic)) {
+                    continue;
+                }
+                struct madt_x2apic *x2lapic = (void *)madt_ptr;
+                if (x2lapic->x2apic_id == bsp_lapic_id) {
+                    bsp_acpi_uid = x2lapic->acpi_processor_uid;
+                    goto found;
+                }
+                continue;
+            }
+        }
+    }
+
+found:
+    lapic_prep_lint(madt, bsp_acpi_uid, true, is_x2);
+    lapic_configure_handoff_state();
+}
+
 struct dmar {
     struct sdt header;
     uint8_t host_address_width;
@@ -161,7 +365,7 @@ uint32_t io_apic_gsi_count(size_t io_apic) {
     return ((io_apic_read(io_apic, 1) & 0xff0000) >> 16) + 1;
 }
 
-void io_apic_mask_all(void) {
+void io_apic_mask_all(bool mask_nmi_and_extint) {
     for (size_t i = 0; i < max_io_apics; i++) {
         uint32_t gsi_count = io_apic_gsi_count(i);
         for (uint32_t j = 0; j < gsi_count; j++) {
@@ -170,6 +374,12 @@ void io_apic_mask_all(void) {
                 case 0b000: // Fixed
                 case 0b001: // Lowest Priority
                     break;
+                case 0b100: // NMI
+                case 0b111: // ExtINT
+                    if (!mask_nmi_and_extint) {
+                        continue;
+                    }
+                    break;
                 default:
                     continue;
             }
diff --git a/common/sys/lapic.h b/common/sys/lapic.h
index 17996752..3565f94f 100644
--- a/common/sys/lapic.h
+++ b/common/sys/lapic.h
@@ -5,6 +5,8 @@
 #include <stdint.h>
 #include <stdbool.h>
 
+struct madt;
+
 #define LAPIC_REG_ICR0     0x300
 #define LAPIC_REG_ICR1     0x310
 #define LAPIC_REG_SPURIOUS 0x0f0
@@ -21,10 +23,14 @@ bool x2apic_enable(void);
 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_configure_handoff_state(void);
+
 void init_io_apics(void);
 uint32_t io_apic_read(size_t io_apic, uint32_t reg);
 void io_apic_write(size_t io_apic, uint32_t reg, uint32_t value);
 uint32_t io_apic_gsi_count(size_t io_apic);
-void io_apic_mask_all(void);
+void io_apic_mask_all(bool mask_nmi_and_extint);
 
 #endif
diff --git a/common/sys/smp.c b/common/sys/smp.c
index 6c021b6c..9b123452 100644
--- a/common/sys/smp.c
+++ b/common/sys/smp.c
@@ -36,8 +36,11 @@ struct trampoline_passed_info {
     uint64_t smp_tpl_bsp_apic_addr_msr;
     uint64_t smp_tpl_mtrr_restore;
     uint64_t smp_tpl_temp_stack;
+    uint64_t smp_tpl_lapic_setup;
 } __attribute__((packed));
 
+bool smp_configure_apic = false;
+
 static bool smp_start_ap(uint32_t lapic_id, struct gdtr *gdtr,
                          struct limine_mp_info *info_struct,
                          int paging_mode, uint32_t pagemap,
@@ -72,6 +75,8 @@ static bool smp_start_ap(uint32_t lapic_id, struct gdtr *gdtr,
     passed_info->smp_tpl_bsp_apic_addr_msr = rdmsr(0x1b);
     passed_info->smp_tpl_mtrr_restore = (uint64_t)(uintptr_t)mtrr_restore;
     passed_info->smp_tpl_temp_stack = (uint64_t)(uintptr_t)temp_stack + 8192;
+    passed_info->smp_tpl_lapic_setup = smp_configure_apic
+        ? (uint64_t)(uintptr_t)lapic_configure_handoff_state : 0;
 
     asm volatile ("" ::: "memory");
 
@@ -234,6 +239,11 @@ struct limine_mp_info *init_smp(size_t   *cpu_count,
 
                 printv("smp: [xAPIC] Found candidate AP for bring-up. LAPIC ID: %u\n", lapic->lapic_id);
 
+                // Set up per-AP LINT values before starting
+                if (smp_configure_apic) {
+                    lapic_prep_lint(madt, lapic->acpi_processor_uid, false, x2apic);
+                }
+
                 // Try to start the AP
                 if (!smp_start_ap(lapic->lapic_id, &gdtr, info_struct,
                                   paging_mode, (uintptr_t)pagemap.top_level,
@@ -274,6 +284,11 @@ struct limine_mp_info *init_smp(size_t   *cpu_count,
 
                 printv("smp: [x2APIC] Found candidate AP for bring-up. LAPIC ID: %u\n", x2lapic->x2apic_id);
 
+                // Set up per-AP LINT values before starting
+                if (smp_configure_apic) {
+                    lapic_prep_lint(madt, x2lapic->acpi_processor_uid, false, true);
+                }
+
                 // Try to start the AP
                 if (!smp_start_ap(x2lapic->x2apic_id, &gdtr, info_struct,
                                   paging_mode, (uintptr_t)pagemap.top_level,
diff --git a/common/sys/smp.h b/common/sys/smp.h
index de45f08c..7cac37ca 100644
--- a/common/sys/smp.h
+++ b/common/sys/smp.h
@@ -10,6 +10,8 @@
 
 #if defined (__x86_64__) || defined (__i386__)
 
+extern bool smp_configure_apic;
+
 struct limine_mp_info *init_smp(size_t   *cpu_count,
                                  uint32_t *_bsp_lapic_id,
                                  int       paging_mode,
diff --git a/common/sys/smp_trampoline.asm_x86 b/common/sys/smp_trampoline.asm_x86
index d2b9f3bc..41ac841d 100644
--- a/common/sys/smp_trampoline.asm_x86
+++ b/common/sys/smp_trampoline.asm_x86
@@ -89,6 +89,13 @@ smp_trampoline_start:
 %ifdef IA32_TARGET
     ; Synchronise MTRRs with BSP
     call [ebx + (passed_info.mtrr_restore - smp_trampoline_start)]
+
+    ; Configure local APIC handoff state (if pointer is set)
+    mov eax, dword [ebx + (passed_info.lapic_setup - smp_trampoline_start)]
+    test eax, eax
+    jz .skip_lapic_setup32
+    call eax
+  .skip_lapic_setup32:
 %endif
 
     lea eax, [ebx + (.mode64 - smp_trampoline_start)]
@@ -138,6 +145,13 @@ parking64:
 %ifdef X86_64_TARGET
     ; Synchronise MTRRs with BSP
     call [rbx + (passed_info.mtrr_restore - smp_trampoline_start)]
+
+    ; Configure local APIC handoff state (if pointer is set)
+    mov rax, [rbx + (passed_info.lapic_setup - smp_trampoline_start)]
+    test rax, rax
+    jz .skip_lapic_setup64
+    call rax
+  .skip_lapic_setup64:
 %endif
 
     mov edi, dword [rbx + (passed_info.smp_info_struct - smp_trampoline_start)]
@@ -222,6 +236,8 @@ passed_info:
         dq 0
     .temp_stack:
         dq 0
+    .lapic_setup:
+        dq 0
 
 smp_trampoline_end:
 
diff --git a/test/limine.c b/test/limine.c
index 8254d5a0..b84e7b7e 100644
--- a/test/limine.c
+++ b/test/limine.c
@@ -7,7 +7,7 @@
 #include <flanterm_backends/fb.h>
 
 __attribute__((section(".limine_requests")))
-static volatile uint64_t limine_base_revision[] = LIMINE_BASE_REVISION(4);
+static volatile uint64_t limine_base_revision[] = LIMINE_BASE_REVISION(5);
 
 static void limine_main(void);
 
@@ -190,8 +190,8 @@ static char *get_memmap_type(uint64_t type) {
             return "Usable";
         case LIMINE_MEMMAP_RESERVED:
             return "Reserved";
-        case LIMINE_MEMMAP_ACPI_TABLES:
-            return "ACPI tables";
+        case LIMINE_MEMMAP_RESERVED_MAPPED:
+            return "Reserved (Mapped)";
         case LIMINE_MEMMAP_ACPI_RECLAIMABLE:
             return "ACPI reclaimable";
         case LIMINE_MEMMAP_ACPI_NVS:
tab: 248 wrap: offon