universalisos/docs/T8-1.2f_QEMU_FINDINGS.md

3.1 KiB

T8-1.2f QEMU Runtime Test — Findings (2026-07-11)

What Works

  1. Kernel builds with PERSONALITY_BOOT=1make ARCH=aarch64 PLATFORM=qemu-aarch64-virt PERSONALITY_BOOT=1 produces a valid ELF.
  2. QEMU boots the EL2 hypervisor — MP0 initializes UART, MMU, GICv3, timer, scheduler.
  3. Personality binary loads via QEMU -device loaderMP1: personality binary @ 0x0000000050000000 (loaded by QEMU).
  4. Personality starts executing — the gate test banner T8-1.2f: hardened_malloc GATE TEST prints, and Test 1: malloc(64) ... starts.

What Fails

The personality's svc #0 syscalls (POSIX_SVC_MMAP, etc.) are not handled by the EL2 hypervisor. The hypervisor's el2_guest_sync_handler only handles EC_HVC_AA64 (hypercalls via hvc #0), but the personality uses svc #0 (supervisor calls, EC_SVC_AA64 = 0x15).

Result: malloc(64) returns NULL (the svc #0 traps to EL2, which doesn't recognize it, and the return value is garbage/0).

Root Cause

The musl personality is designed as a native UOS task using the POSIX_SVC_* ABI (svc #0, x8=syscall number). But the current aarch64 kernel architecture runs all payloads as EL1 guests under the EL2 hypervisor, which expects hvc #0 (UOS_HV_* ABI).

The personality loader (personality_loader.cpp) creates a task_context_t and sets up the task, but the current boot path (kernel_aarch64.cpp) doesn't use it — it uses the vCPU/EL1 guest path instead.

Two Paths Forward

Path A: Run personality as native UOS task (correct long-term)

Modify kernel_aarch64.cpp to:

  1. Use personality_loader_create() + personality_loader_load_elf() + personality_loader_boot() instead of the vCPU guest path
  2. Add a svc #0 handler in the EL2 trap handler that routes POSIX_SVC_* calls to the appropriate kernel services
  3. The personality runs at EL1 (or EL0) as a native task, not as a virtualized guest

Path B: Add SVC handling to EL2 guest trap (quick fix)

Add EC_SVC_AA64 handling to el2_guest_sync_handler:

  1. Decode x8 as the POSIX_SVC_* number
  2. Route POSIX_SVC_MMAP to a Stage-2 memory allocator
  3. Route POSIX_SVC_MPROTECT to Stage-2 page table updates
  4. etc.

This is a stopgap — the personality would still be a virtualized guest, not a native personality.

Recommendation

Path A is the correct architecture for a musl POSIX personality. The personality should be a first-class UOS citizen, not a virtualized guest. This requires:

  • Wiring the personality loader into the boot path
  • Adding a POSIX syscall handler in the kernel
  • Setting up the personality's address space via the UOS MMU (not Stage-2)

Files Changed for This Test

  • kernel/Makefile — added run-personality target, PERSONALITY_BOOT=1 flag
  • kernel/src/arch/aarch64/kernel_aarch64.cpp — added UOS_PERSONALITY_BOOT path (skips embedded payload, uses QEMU-loaded binary, entry=0x50000390)

Verification

  • Build: PASS (kernel builds with PERSONALITY_BOOT=1)
  • Boot: PASS (QEMU boots, personality loads)
  • Execution: PARTIAL (personality starts but syscalls fail)
  • Gate tests: FAIL (malloc returns NULL due to unhandled svc #0)