Files
volt-vmm/docs/phase3-smp-results.md
Karl Clinger 40ed108dd5 Volt VMM (Neutron Stardust): source-available under AGPSL v5.0
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
2026-03-21 01:04:35 -05:00

173 lines
6.4 KiB
Markdown

# 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 `mptable` module
- Exported `setup_mptable` function
### 3. Main VMM Integration (`vmm/src/main.rs`)
- Added `setup_mptable()` call in `load_kernel()` after `BootLoader::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:
1. Guest memory is already allocated and mapped
2. E820 memory map is already configured (including EBDA reservation at 0x9FC00)
3. 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