A small 32-bit VM with SMP support, MMIO devices, interrupts, and a custom ISA.
- VM boots and runs custom binaries (
--bin). - SMP core bring-up works (
STARTAP,CPUID,IPI). - Built-in selftests pass in current tree:
startap_cpuidipi
- Atomic ISA instructions are implemented with C11 atomic semantics on aligned 32-bit RAM words.
Assembler/toolchain project:
- https://github.com/glowingstone124/lampvm-toolchain
- https://github.com/glowingstone124/llvm-project (Custom LLVM backend)
- CMake >= 3.20
- C11 compiler
- SDL2
- pthreads (via
Threads::Threads)
cmake -S . -B build
cmake --build build -jNotes:
- On Apple Silicon, CMake is configured to build
arm64. - Linux links
libmand enables_POSIX_C_SOURCE=200809L.
./build/vm --bin bios/boot.bin --smp 1Arguments:
--bin <file>: program binary path (default:boot.bin)--smp <cores>: CPU worker thread count in[1, 64](default:1)--selftest: run built-in SMP tests and exit
Run selftests:
./build/vm --selftestCPU0is BSP and starts immediately.CPU1..N-1are APs and stay parked untilSTARTAP.- Each core has private architectural state:
regs/ip/flags- call/data/ISR stack pointers and interrupt context
- Cores share RAM/MMIO/IO/device model.
- Normal
LOAD/STORE/LOAD32/STORE32/...go through the VM memory API. - Shared VM state is serialized by a global VM lock.
Atomic instructions operate on aligned 32-bit RAM words using C11 atomics:
CASXADDXCHGLDAR(acquire load)STLR(release store)FENCE(SC fence)
Rules:
- Unaligned atomic addresses panic.
- Atomic ops on MMIO addresses panic.
atomic_thread_fenceis only used with atomic operations; normal memory is not implicitly upgraded to atomic by fences.
- Stacks are stored in VM RAM (not host-side arrays).
--smp 1: legacy fixed bases are used.--smp > 1: per-core stack regions are allocated near top of RAM.- VM checks image/stack pool overlap at startup.
Single binary format:
- 24-byte header (
u32little-endian x6) - Text section (
u64little-endian instructions) - Data section (raw bytes)
Header fields:
TEXT_BASETEXT_SIZE(bytes)DATA_BASEDATA_SIZE(bytes)BSS_BASEBSS_SIZE(bytes)
| Region | Start | End | Size | Purpose |
|---|---|---|---|---|
| IVT | 0x000000 |
0x0007FF |
2048 B | 256 vectors x 8B |
| CALL_STACK | 0x000800 |
0x000FFF |
2048 B | Call stack |
| DATA_STACK | 0x001000 |
0x0017FF |
2048 B | Data stack |
| ISR_STACK | 0x001800 |
0x001FFF |
2048 B | Interrupt stack |
| TIME MMIO | 0x002000 |
0x00201B |
28 B | time registers |
| PROGRAM | 0x00201C |
FB_BASE-1 |
variable | text/data/bss |
| FrameBuffer | FB_BASE |
FB_BASE+FB_SIZE-1 |
variable | video buffer |
Additional fixed MMIO regions:
| Region | Start | End | Size | Purpose |
|---|---|---|---|---|
| Legacy FrameBuffer Alias | 0x00620000 |
0x0074BFFF |
1228800 B | video buffer legacy mapping |
| SYSINFO MMIO | 0x0074C000 |
0x0074C05B |
92 B | firmware-style VM metadata |
Enable debug features:
cmake -S . -B build -DVM_DEBUG=ON
cmake --build build -jWhen enabled:
- instruction statistics
- alignment checks
- interactive step/breakpoint debugger
Runtime debug env vars:
VM_DEBUG_STEP=1orVM_STEP=1VM_DEBUG_PAUSE=1VM_BREAKPOINTS=0x201C,0x2024
See:
isa.mdbios.mdkernel.mddocs/posix.mdbios-build.md
It's time to develop a kernel for this platform.
Recommended start order:
- Bring up single-core kernel first (
--smp 1): boot, trap/interrupt entry, timer tick, syscall ABI. - Add scheduler and memory management in single-core mode.
- Enable SMP bring-up (
STARTAP), then add spinlocks and per-core data. - Use atomic ISA ops (
LDAR/STLR/CAS/XADD) for lock primitives.
Practical note:
- If you want fastest iteration, keep kernel bring-up on
--smp 1until trap path and basic drivers are stable, then turn on SMP.