130 lines
8.4 KiB
Markdown
130 lines
8.4 KiB
Markdown
# AGENTS.md — Universalisos
|
||
|
||
Safety-critical type-1 hypervisor (ARMv7 primary, AArch64/RISC-V in progress) implementing PikeOS 5.0 patterns.
|
||
|
||
## Critical Build Gotchas
|
||
|
||
- **Default build target is RISC-V**, not ARM. The Makefile defaults to `ARCH=riscv PLATFORM=polarfire`.
|
||
- **To build the working ARMv7 target**, you must explicitly pass:
|
||
```bash
|
||
cd kernel
|
||
make ARCH=armv7 PLATFORM=qemu-arm-virt
|
||
```
|
||
- Output lands at `build/<arch>/<platform>/universalisos.elf`, not `kernel.elf`.
|
||
- `make clean` only cleans the current `ARCH/PLATFORM` combo. Use `make clean-all` to wipe all build trees.
|
||
- The old commands `make -C kernel/arch/arm` and the driver script `.claude/skills/run-universalisos/driver.sh` reference the **obsolete** pre-Bao build system and are broken. Ignore them.
|
||
|
||
## Verified Boot Command (ARMv7)
|
||
|
||
```bash
|
||
cd kernel
|
||
qemu-system-arm -M virt -cpu cortex-a15 -m 512M \
|
||
-nographic -kernel build/armv7/qemu-arm-virt/universalisos.elf
|
||
```
|
||
|
||
Press `Ctrl+A` then `X` to exit QEMU.
|
||
|
||
## Verified Boot Command (AArch64)
|
||
|
||
```bash
|
||
cd kernel
|
||
qemu-system-aarch64 -M virt,gic-version=3,virtualization=on -cpu cortex-a53 -m 512M \
|
||
-smp 4 -nographic -kernel build/aarch64/qemu-aarch64-virt/universalisos.elf
|
||
```
|
||
|
||
> **Gotcha:** `virtualization=on` is mandatory. Without it QEMU hands the `-kernel`
|
||
> payload EL1 (not EL2); the EL2 hypervisor then traps on its first EL2
|
||
> system-register write (`msr vbar_el2, …`) and hangs silently with **no UART output**
|
||
> and no logged guest error. `boot.S` now halts cleanly (`wfe` loop) if entered below
|
||
> EL2 instead of falling into the EL2 register writes.
|
||
|
||
## Verified Boot Command (RISC-V / Icicle Kit)
|
||
|
||
Bare-metal smoke test (BSP only, `-bios none`):
|
||
|
||
```bash
|
||
cd kernel
|
||
make ARCH=riscv PLATFORM=polarfire # default arch/platform
|
||
# or: make run-qemu
|
||
qemu-system-riscv64 -machine microchip-icicle-kit -smp 5 -m 2G \
|
||
-nographic -bios none -kernel build/riscv/polarfire/universalisos.elf
|
||
```
|
||
|
||
Firmware / HSS-payload boot (releases all 5 harts into S-mode, SBI live —
|
||
this is the tear-de-silicio `polarstar-fpga` flow retargeted at UniversalisOS):
|
||
|
||
```bash
|
||
cd kernel
|
||
# 1. Build the S-mode-entry image (byte @0x80200000 = _start_firmware).
|
||
make ARCH=riscv PLATFORM=polarfire UOS_BOOT=firmware bin
|
||
# 2. Wrap it as an HSS payload (needs Microchip's hss-payload-generator).
|
||
hss-payload-generator -c config/icicle_hss_payload.yaml \
|
||
build/riscv/polarfire/universalisos.bin build/riscv/polarfire/payload.bin
|
||
# (or just: make hss-payload — it prints the exact command if the tool is absent)
|
||
# 3. Boot it as the machine BIOS, all harts released at 0x80200000 in S-mode.
|
||
make run-qemu-firmware FIRMWARE=build/riscv/polarfire/payload.bin
|
||
# equivalent:
|
||
qemu-system-riscv64 -machine microchip-icicle-kit -smp 5 -m 2G -nographic \
|
||
-bios build/riscv/polarfire/payload.bin \
|
||
-device loader,file=build/riscv/polarfire/universalisos.elf,addr=0x80200000
|
||
```
|
||
|
||
> **Why two images.** `-bios none` enters in M-mode and runs the `_start`
|
||
> trampoline (delegates + `mret` to S-mode, leaves `__uos_has_sbi=0`). The
|
||
> firmware image puts `_start_firmware` at `0x80200000`; it sets
|
||
> `__uos_has_sbi=1` so the timer goes through SBI `set_timer` and secondary
|
||
> bring-up goes through SBI HSM — the only way to get preemptive ticks and
|
||
> live SMP on the Icicle Kit, since the CLINT `mtimecmp` is M-mode-only and QEMU
|
||
> holds harts 0/2/3/4 in reset under `-bios none`. `riscv_cpu_wake_secondary()`
|
||
> is a deliberate no-op when `__uos_has_sbi==0`.
|
||
> OpenSBI generic firmware still does **not** chain on `microchip-icicle-kit`
|
||
> (MROM overlap at `0x20220000`); the HSS payload is the working firmware path.
|
||
|
||
## Architecture Reality Check
|
||
|
||
- **ARMv7 + qemu-arm-virt**: Boots, produces UART output, runs scheduler/IPC/HM demos end-to-end. This is the target you should test against.
|
||
- **AArch64 + qemu-aarch64-virt**: EL2 hypervisor track. Builds clean (0 linker warnings) and boots to a full banner at EL2 — but **only** when QEMU is run with `virtualization=on` (see gotcha above). MP0 bring-up reaches the scheduler, `eret` into the first task works, and **timer-driven preemption is live** (the former U3 open item is resolved): the HV tick uses the EL2 **physical** timer CNTHP on **PPI 26** (`timer.cpp` → `gicv3_irq_enable(QEMU_TIMER_EL2_PHYS_PPI)`), `el2_irq_handler` (el2_trap.cpp) acks INTID 26 / re-arms CNTHP_CVAL / EOIs / runs `sched_tick()`, and `el2_irq_entry` (exceptions.S) performs the deferred preemptive switch via `g_need_reschedule` + the cur/next trap-frame pointers. Verified by boot: A/B tasks interleave in runs of 1–3 ticks at ~50/50. (PPI 27 enabled on MP1 is the *guest's* virtual timer via the vGIC — intentional, not the HV tick.)
|
||
- **RISC-V + polarfire (Icicle Kit)**: Self-contained S-mode port under `kernel/src/arch/riscv/`. Builds clean (`make ARCH=riscv PLATFORM=polarfire`) and boots to banner + `Partition 0/1 says hello!` for `-smp 2..5` (QEMU rejects `-smp 1`: min 2 CPUs; `-bios none` is BSP-only regardless of `-smp`). Two boot modes: `-bios none` (M-mode trampoline, BSP only — verifiable today) and the HSS-payload firmware path (`UOS_BOOT=firmware` + `config/icicle_hss_payload.yaml`, releases all 5 harts + SBI timer/IPI/HSM — needs Microchip `hss-payload-generator`). Timer is gated on `__uos_has_sbi`: SBI `set_timer` under firmware, direct CLINT under `-bios none`. `-bios none` is BSP-only by construction (secondaries held in reset; `riscv_cpu_wake_secondary()` is a no-op when `__uos_has_sbi==0`); the HSS path is the intended route to real SMP + preemptive ticks.
|
||
|
||
When making changes, **build and boot ARMv7** to verify. Do not assume changes to shared headers compile on all three arches unless you test each.
|
||
|
||
## Code Conventions
|
||
|
||
- Use `uos_` prefix for new APIs (not PikeOS `p4_`/`UOS_PART_`).
|
||
- MMU is **enabled** (PikeOS-style flat 4GB 1MB-section identity map, all RAM cacheable, I/O strongly-ordered). Device MMIO reads/writes work.
|
||
- No dynamic memory allocation; static/compile-time only.
|
||
- No exceptions, no RTTI (`-fno-exceptions -fno-rtti`).
|
||
- Freestanding environment: provide `__aeabi_uidiv`/`__aeabi_uldivmod` in `aeabi_runtime.cpp` when needed.
|
||
|
||
## Known Hardware/Emulation Quirks
|
||
|
||
- **QEMU 32-bit ARM virt PCIe ECAM deadlocks**: Reads at `0x3f000000` hang inside QEMU's device model (independent of MMU state). The PCI core ships with a safe framework transport as default; ECAM transport is ready for real hardware or AArch64 virt.
|
||
- **SPI demo is intentionally NOT called at boot**: A write to `spi_controllers` (last 32 bytes of BSS, at the BSS/SVC-stack boundary) triggers a fault due to a latent kernel memory/exception issue. The SPI driver itself is compiled-in and correct.
|
||
|
||
## Project Boundaries
|
||
|
||
- `kernel/src/arch/armv7/` — ARMv7-specific boot, exceptions, context switch, UART, MMU walk, adspace, scheduling asm.
|
||
- `kernel/src/arch/aarch64/` — AArch64 EL2 hypervisor (separate, self-contained).
|
||
- `kernel/src/arch/riscv/` — RISC-V port (separate, self-contained; does NOT pull ARM-centric core files).
|
||
- `kernel/src/core/` — Shared hypervisor core: scheduler, IPC, memory, device framework, guest boot, UOS API, capability MDB, health monitoring. **ARMv7 compiles all of these**; AArch64/RISC-V are self-contained and do not pull from `core/`.
|
||
- `kernel/src/platform/drivers/` — Shared device drivers (block, GPIO, I2C, SPI, network, PCI, USB, fbcon, timer, UART). Platforms opt in via `drv-objs-y`.
|
||
- `kernel/src/platform/<name>/` — Board/platform specifics (linker script, config, optional driver substitutions via `cpu-skip-y`).
|
||
|
||
## Primary Reference Documents
|
||
|
||
- `UNIVERSALISOS_VS_PIKEOS_5.0.md` — Roadmap, feature-by-feature gap analysis, and implementation priorities.
|
||
- `kernel/README.md` — **Stale**: claims "Stage 1" is current. Ignore stage labels; treat this as historical context only.
|
||
|
||
## Context Isolation Rule
|
||
|
||
Do **not** mix Universalisos work with other PortugalFuturista projects (DocSpace, Aurelio Web, mycelium, etc.). When working in this repo, focus **only** on the hypervisor implementation.
|
||
|
||
## Verification Workflow
|
||
|
||
There is no unit-test framework, linter, or typechecker. Verification is:
|
||
|
||
1. `make ARCH=armv7 PLATFORM=qemu-arm-virt` — must compile clean.
|
||
2. Boot in QEMU — must reach UART banner and complete demo sequence (scheduler slots, IPC, shared memory, health monitoring, preemption).
|
||
3. Check for unexpected hangs or missing demo sections in output.
|
||
|
||
If a change touches shared headers, verify it does not break `ARCH=aarch64` or `ARCH=riscv` builds as well.
|