KVM-based microVMM for the Volt platform: - Sub-second VM boot times - Minimal memory footprint - Landlock LSM + seccomp security - Virtio device support - Custom kernel management Copyright (c) Armored Gates LLC. All rights reserved. Licensed under AGPSL v5.0
6.4 KiB
Volt Phase 3 — SMP Support Results
Date: 2026-03-09
Status: ✅ Complete — All success criteria met
Summary
Implemented Intel MultiProcessor Specification (MPS v1.4) tables for Volt VMM, enabling guest kernels to discover and boot multiple vCPUs. VMs with 1, 2, and 4 vCPUs all boot successfully with the kernel reporting the correct number of processors.
What Was Implemented
1. MP Table Construction (vmm/src/boot/mptable.rs) — NEW FILE
Created a complete MP table builder that writes Intel MPS-compliant structures to guest memory at address 0x9FC00 (just below EBDA, a conventional location Linux scans during boot).
Table Layout:
0x9FC00: MP Floating Pointer Structure (16 bytes)
- Signature: "_MP_"
- Pointer to MP Config Table (0x9FC10)
- Spec revision: 1.4
- Feature byte 2: IMCR present (0x80)
- Two's-complement checksum
0x9FC10: MP Configuration Table Header (44 bytes)
- Signature: "PCMP"
- OEM ID: "NOVAFLAR"
- Product ID: "VOLT VM"
- Local APIC address: 0xFEE00000
- Entry count, checksum
0x9FC3C+: Processor Entries (20 bytes each)
- CPU 0: APIC ID=0, flags=EN|BP (Bootstrap Processor)
- CPU 1: APIC ID=1, flags=EN (Application Processor)
- CPU N: APIC ID=N, flags=EN
- CPU signature: Family 6, Model 15, Stepping 1
- Local APIC version: 0x14 (integrated)
After processors: Bus Entry (8 bytes)
- Bus ID=0, Type="ISA "
After bus: I/O APIC Entry (8 bytes)
- ID=num_cpus (first unused APIC ID)
- Version: 0x11
- Address: 0xFEC00000
After I/O APIC: 16 I/O Interrupt Entries (8 bytes each)
- IRQ 0: ExtINT → IOAPIC pin 0
- IRQs 1-15: INT → IOAPIC pins 1-15
Total sizes:
- 1 CPU: 224 bytes (19 entries)
- 2 CPUs: 244 bytes (20 entries)
- 4 CPUs: 284 bytes (22 entries)
All fit comfortably in the 1024-byte space between 0x9FC00 and 0xA0000.
2. Boot Module Integration (vmm/src/boot/mod.rs)
- Registered
mptablemodule - Exported
setup_mptablefunction
3. Main VMM Integration (vmm/src/main.rs)
- Added
setup_mptable()call inload_kernel()afterBootLoader::setup()completes - MP tables are written to guest memory before vCPU creation
- Works for any vCPU count (1-255)
4. CPUID Topology Updates (vmm/src/kvm/cpuid.rs)
- Leaf 0x1 (Feature Info): HTT bit (EDX bit 28) is now enabled when vcpu_count > 1, telling the kernel to parse APIC topology
- Leaf 0x1 EBX: Initial APIC ID set per-vCPU, logical processor count set to vcpu_count
- Leaf 0xB (Extended Topology): Properly reports SMT and Core topology levels:
- Subleaf 0 (SMT): 1 thread per core, level type = SMT
- Subleaf 1 (Core): N cores per package, level type = Core, correct bit shift for APIC ID
- Subleaf 2+: Invalid (terminates enumeration)
- Leaf 0x4 (Cache Topology): Reports correct max cores per package
Test Results
Build
✅ cargo build --release — 0 errors, 0 warnings
✅ cargo test --lib boot::mptable — 11/11 tests passed
VM Boot Tests
| Test | vCPUs | Kernel Reports | Status |
|---|---|---|---|
| 1 CPU | --cpus 1 |
Processors: 1, nr_cpu_ids:1 |
✅ Pass |
| 2 CPUs | --cpus 2 |
Processors: 2, Brought up 1 node, 2 CPUs |
✅ Pass |
| 4 CPUs | --cpus 4 |
Processors: 4, Brought up 1 node, 4 CPUs, Total of 4 processors activated |
✅ Pass |
Key Kernel Log Lines (4 CPU test)
found SMP MP-table at [mem 0x0009fc00-0x0009fc0f]
Intel MultiProcessor Specification v1.4
MPTABLE: OEM ID: NOVAFLAR
MPTABLE: Product ID: VOLT VM
MPTABLE: APIC at: 0xFEE00000
Processor #0 (Bootup-CPU)
Processor #1
Processor #2
Processor #3
IOAPIC[0]: apic_id 4, version 17, address 0xfec00000, GSI 0-23
Processors: 4
smpboot: Allowing 4 CPUs, 0 hotplug CPUs
...
smp: Bringing up secondary CPUs ...
x86: Booting SMP configuration:
.... node #0, CPUs: #1
smp: Brought up 1 node, 4 CPUs
smpboot: Total of 4 processors activated (19154.99 BogoMIPS)
Unit Tests
11 tests in vmm/src/boot/mptable.rs:
| Test | Description |
|---|---|
test_checksum |
Verifies two's-complement checksum arithmetic |
test_mp_floating_pointer_signature |
Checks "MP" signature at correct address |
test_mp_floating_pointer_checksum |
Validates FP structure checksum = 0 |
test_mp_config_table_checksum |
Validates config table checksum = 0 |
test_mp_config_table_signature |
Checks "PCMP" signature |
test_mp_table_1_cpu |
1 CPU: 19 entries (1 proc + bus + IOAPIC + 16 IRQs) |
test_mp_table_4_cpus |
4 CPUs: 22 entries |
test_mp_table_bsp_flag |
CPU 0 has BSP+EN flags, CPU 1 has EN only |
test_mp_table_ioapic |
IOAPIC ID and address are correct |
test_mp_table_zero_cpus_error |
0 CPUs correctly returns error |
test_mp_table_local_apic_addr |
Local APIC address = 0xFEE00000 |
Files Modified
| File | Change |
|---|---|
vmm/src/boot/mptable.rs |
NEW — MP table construction (340 lines) |
vmm/src/boot/mod.rs |
Added mptable module and setup_mptable export |
vmm/src/main.rs |
Added setup_mptable() call after boot loader setup |
vmm/src/kvm/cpuid.rs |
Fixed HTT bit, enhanced leaf 0xB topology reporting |
Architecture Notes
Why MP Tables (not ACPI MADT)?
MP tables are simpler (Intel MPS v1.4 is ~400 bytes of structures) and universally supported by Linux kernels from 2.6 onwards. ACPI MADT would require implementing RSDP, RSDT/XSDT, and MADT — significantly more complexity for no benefit with the kernel versions we target.
The 4.14 kernel used in testing immediately found and parsed the MP tables:
found SMP MP-table at [mem 0x0009fc00-0x0009fc0f]
Integration Point
MP tables are written in Vmm::load_kernel() immediately after BootLoader::setup() completes. This ensures:
- Guest memory is already allocated and mapped
- E820 memory map is already configured (including EBDA reservation at 0x9FC00)
- The MP table address doesn't conflict with page tables (0x1000-0xA000) or boot params (0x20000+)
CPUID Topology
The HTT bit in CPUID leaf 0x1 EDX is critical — without it, some kernels skip AP startup entirely because they believe the system is uniprocessor regardless of MP table content. We now enable it for multi-vCPU VMs.
Future Work
- ACPI MADT: For newer kernels (5.x+) that prefer ACPI, add RSDP/RSDT/MADT tables
- CPU hotplug: MP tables are static; ACPI would enable runtime CPU add/remove
- NUMA topology: For large VMs, SRAT/SLIT tables could improve memory locality