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
This commit is contained in:
172
docs/phase3-smp-results.md
Normal file
172
docs/phase3-smp-results.md
Normal file
@@ -0,0 +1,172 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user