Phase 25
SMP
Boot all available CPU cores, give each its own Local APIC timer, and run the scheduler across all cores simultaneously. Two processes should be able to execute truly in parallel.
Learning goal
Understand the AP startup sequence: why a 16-bit real-mode trampoline is needed.
Category
foundations
Components touched
Builds on
Unlocked by this phase
Why this phase matters
Boot all available CPU cores, give each its own Local APIC timer, and run the scheduler across all cores simultaneously. Two processes should be able to execute truly in parallel.
How it works in m3OS
Phase 25 adds multi-core support to m3OS. All Application Processors (APs) discovered in the ACPI MADT are brought online via the INIT-SIPI IPI sequence. Each core has its own GDT, TSS, kernel stack, double-fault stack, LAPIC timer, and scheduler loop. Inter-processor interrupts (IPIs) provide reschedule and TLB shootdown mechanisms.
How it builds on earlier phases
This phase builds on Persistent Storage and turns that foundation into SMP.
Implementation outline
- Determine AP count and APIC IDs from the MADT parsed in Phase 15.
- Allocate a 4 KB trampoline page at a sub-1 MB physical address; write the 16-bit startup stub.
- For each AP: send INIT IPI, wait 10 ms, send two SIPI IPIs with the trampoline physical page number.
- In the trampoline: enable protected mode, set up a temporary GDT, enable long mode, jump to a Rust
ap_entryfunction. - In
ap_entry: initialize the per-core GDT, TSS, LAPIC, and kernel stack; signal the BSP that this AP is alive; enter the scheduler loop. - Split the global run queue into per-core queues; add a work-stealing path.
- Implement
send_ipiusing LAPIC ICR registers. - Add TLB shootdown IPI handler.
Task progress snapshot
No checklist tasks were discovered for this phase yet.
Documentation targets
- Documentation deliverables have not been listed yet.
Deferred follow-on work
- NUMA-aware memory allocation
- CPU affinity (
sched_setaffinity) - real-time scheduling classes
- CPU frequency scaling (P-states)
- CPU hotplug
- per-core page allocator (SLUB/slab style)
Source materials
Important code
Code spotlight cards
Key files
How real OSes differ
- Production kernels use NUMA-aware memory allocation (allocating from the NUMA node local to each core), per-core page allocators to avoid cross-core lock contention, and sophisticated load-balancing heuristics.
- Linux's scheduler (CFS) tracks CPU utilization, task affinity, cache topology, and energy efficiency.
- This phase uses the simplest correct implementation: equal-weight round-robin with naive work stealing.
Success criteria
- All cores reported in the MADT appear in the boot log as online.
- Two CPU-bound tasks run simultaneously with no corruption of shared kernel state.
- A TLB shootdown triggered by `munmap` in one process does not leave stale mappings on another core.
- The system remains stable under a workload that context-switches rapidly across multiple cores.
Related phases
Keep exploring the roadmap
Phase 24
CompletePersistent Storage
Give m3OS a persistent block device so that files written during one boot session survive into the next. A virtio-blk driver (the simplest PCI virtio device in QEMU) handles raw sector I/O; a partition parser finds the FAT32 data partition; the existing `fat_server` gains a write path that flushes directly to disk. After this phase, writing a file to `/data` and rebooting leaves the file visible on the next boot (and on the host via `losetup` or similar).
Phase 26
CompleteText Editor
A usable text editor runs inside the OS. Users can create, edit, and save files from the shell. This is the foundational tool that makes all subsequent "do real work inside the OS" phases possible — you cannot write code, configuration files, or documents without an editor.