feat: Fase 7 — ACPI MADT parser + SMP AP bootstrap (INIT-SIPI-SIPI)
New files:
- include/arch/x86/acpi.h — ACPI RSDP/RSDT/MADT structures and API
- include/arch/x86/smp.h — SMP per-CPU info and bootstrap API
- src/arch/x86/acpi.c — ACPI table parser: find RSDP in EBDA/BIOS ROM,
parse RSDT, extract MADT entries (LAPIC, IOAPIC, ISO). Uses temporary
VMM mappings for tables above the 16MB identity-mapped range.
- src/arch/x86/smp.c — SMP bootstrap: copy 16-bit trampoline to 0x8000,
patch GDT/CR3/stack/entry, send INIT-SIPI-SIPI per AP, wait for ready.
- src/arch/x86/ap_trampoline.S — 16-bit real-mode AP entry point:
load GDT, enable protected mode, far-jump to 32-bit, load CR3,
enable paging, jump to C ap_entry().
Changes:
- include/arch/x86/lapic.h: Add lapic_send_ipi(), rdmsr(), wrmsr() decls
- src/arch/x86/lapic.c: Implement lapic_send_ipi() using ICR_HI/ICR_LO
with delivery-status polling. Make rdmsr/wrmsr non-static.
- include/arch/x86/gdt.h: Export struct gdt_ptr and gp variable
- src/arch/x86/gdt.c: Make gp non-static for AP trampoline access
- src/arch/x86/linker.ld: Include .ap_trampoline section in .rodata
- src/arch/x86/arch_platform.c: Call acpi_init() then smp_init() after
LAPIC/IOAPIC setup
- src/arch/x86/idt.c: Move IRQ EOI before handler callback (critical fix:
schedule() in timer handler context-switches away, blocking LAPIC if
EOI is deferred). Add IDT gate + ISR stub for spurious vector 255.
- src/arch/x86/interrupts.S: Add ISR_NOERRCODE 255 stub
Key design decisions:
- Trampoline at fixed phys 0x8000, data area at 0x8F00
- APs share BSP's page directory (same CR3)
- APs enable their own LAPIC and halt (idle loop for now)
- ACPI tables mapped via temporary VMM window at 0xC0202000
- Each AP gets a 4KB kernel stack from static array
Tested: -smp 1 (single CPU, all init tests OK)
-smp 4 (4 CPUs started, all init tests OK)
Passes: make, cppcheck, QEMU smoke test