241 lines
14 KiB
Markdown
241 lines
14 KiB
Markdown
# UniversalisOS RISC-V S-mode Paravirtualized Hypervisor — PikeOS 5.0 Parity Plan
|
|
|
|
**Date:** 2026-07-09
|
|
**Scope:** Port UniversalisOS S-mode paravirtualized hypervisor to RISC-V (RV64) on the PolarFire SoC Icicle Kit and align functionality with PikeOS 5.0, using Jailhouse, seL4, and Bao as reference implementations.
|
|
**Primary reference:** PikeOS 5.0 ukernel sources (ARMv7hf) under `src/sources/ukernel-arm_v7hf/`.
|
|
**PikeOS source location:** `/home/fabiorafaelcoutada/portugalfuturista/universalisos/src` (PikeOS 5.0 distribution).
|
|
**Important:** The Icicle Kit U54 cores do **not** implement the RISC-V H-extension. The hypervisor therefore runs in **S-mode** and guests run in **U-mode**, with privileged operations mediated by `ecall` hypercalls. This is a **paravirtualized** design, not a hardware-virtualized (type-1) design.
|
|
|
|
---
|
|
|
|
## 1. Reference Codebase Assessment
|
|
|
|
### 1.1 PikeOS 5.0 (`universalisos/src`)
|
|
- **Status in source drop:** ARMv7/ARMv8, PowerPC e500/e500mc/e5500, x86-64 ukernels are present.
|
|
- **RISC-V status:** Only toolchain/RPM target macros exist (`config/rpm/targets/riscv_rv64-linux`); **no ukernel source tree for RISC-V** in this drop.
|
|
- **Hypervisor model:** ARM-centric (`p4hwvirt` headers, `hwvirt-linux` guest drivers, HVC protocol).
|
|
- **What we reuse for RISC-V (S-mode paravirtualized):**
|
|
- Partition/resource model (`respart.c`, `sys_respart.c`).
|
|
- Scheduling concepts (time partitioning + preemptive priority in `sched.c`, `tps.c`).
|
|
- Memory API shape (`p4map.h`, `p4mm.h`).
|
|
- Health monitoring / safety patterns (`hm.c`).
|
|
- KDEV device framework shape.
|
|
- **Note:** PikeOS H-extension / VS-mode concepts do not apply. We map PikeOS "task" to our "partition" and PikeOS "thread" to our "task" (schedulable entity).
|
|
|
|
### 1.2 Bao Hypervisor (reference for H-extension platforms)
|
|
- **Strengths:** Complete RISC-V H-extension type-1 static partitioning hypervisor; clean separation of portable core and arch code.
|
|
- **Mechanisms we adopt where applicable:**
|
|
- Sv39 page-table allocator and TLB management.
|
|
- SBI ecall proxy for guest OS compatibility.
|
|
- PLIC interrupt handling.
|
|
- 1:1 vCPU-to-pCPU assignment with static scheduling.
|
|
- **Not applicable:** `hstatus`, `hedeleg`, `hideleg`, `hgatp`, `hvip`, VS-mode CSRs, two-stage translation, vPLIC / APLIC / AIA, RISC-V IOMMU — the Icicle Kit lacks the H-extension.
|
|
|
|
### 1.3 Jailhouse
|
|
- **Strengths:** Static partitioning, cell abstraction, comm regions, PCI pass-through, IVSHMEM.
|
|
- **RISC-V status:** No RISC-V support.
|
|
- **Mechanisms we adopt:**
|
|
- Cell-based static partitioning config.
|
|
- Per-cell comm region / hypercall ABI.
|
|
- Device assignment and IOMMU integration patterns.
|
|
- Memory region flags and loadable region semantics.
|
|
|
|
### 1.4 seL4
|
|
- **Strengths:** Verified microkernel, RISC-V S-mode support, capability-based security.
|
|
- **Hypervisor status:** No RISC-V H-extension; guest virtualization would be userland VMM.
|
|
- **Mechanisms we adopt:**
|
|
- Capability-based access control (already present in `cap/`).
|
|
- ASID management and TLB invalidation patterns.
|
|
- Trap entry/exit assembly discipline.
|
|
|
|
---
|
|
|
|
## 2. PikeOS 5.0 → RISC-V S-mode Paravirtualized Feature Parity Map
|
|
|
|
| PikeOS 5.0 Feature | UniversalisOS ARM Status | RISC-V Target | Reference Files | Priority |
|
|
|---|---|---|---|---|
|
|
| S-mode bare-metal boot | ✅ Working | M-mode trampoline → S-mode (firmware=none) | `boot.S`, `trap.S` | P0 |
|
|
| Exception/trap handling | ✅ Framework | S-mode trap vector + U-mode ecall hypercall | `trap.S`, `exceptions.cpp` | P0 |
|
|
| UART console (NS16550a) | ✅ PL011 | NS16550a (Icicle MMUART0) | `uart.cpp` | P0 |
|
|
| MMU / page tables | ✅ Section map | Sv39 identity + per-partition page tables | `page_table.cpp` | P0 |
|
|
| Address-space isolation | ✅ PoC | Per-partition SATP (no VMID/ASID needed) | `vm.cpp`, `memory.cpp` | P0 |
|
|
| Interrupt controller | ✅ GICv2 | Physical PLIC + paravirtualized IRQ routing | `plic.cpp` | P0 |
|
|
| Timer tick | ✅ Generic Timer | CLINT mtimecmp (1 MHz) | `timer.cpp` | P0 |
|
|
| Context switch | ⚠️ Partial | Task trap-frame save/restore + `sret` to U-mode | `context_switch_asm.S` | P0 |
|
|
| Guest virtual time | ⚠️ Framework | `virtual_time` + `virtual_timer_deadline` per partition | `vm.cpp`, `hypercall.cpp` | P1 |
|
|
| Guest OS boot | ⚠️ Framework | Load raw image, set a0/a1, `sret` to U-mode | `guest_loader.cpp`, `vm.cpp` | P1 |
|
|
| Device pass-through | ⚠️ Framework | MMIO mapped into guest SATP (no emulation) | `vm.cpp` | P1 |
|
|
| Scheduling (RMS/DMS/ARINC 653) | ⚠️ Framework | PikeOS-style time-partition + priority scheduler | `task_sched.cpp` | P1 |
|
|
| Inter-partition communication | ⚠️ Stub | Shared memory + doorbell IRQ (future) | — | P2 |
|
|
| Safety monitoring / HM | ⚠️ Stub | Health monitor events/actions | `hm.cpp` | P2 |
|
|
| PikeOS API (`p4_*` / `uos_*`) | ⚠️ Stub | Map to RISC-V `ecall` hypercalls | `hypercall.cpp` | P2 |
|
|
| Tooling / XSD codegen | ⚠️ Stub | Extend manifest generator for RISC-V | PikeOS `xsdgen/` | P3 |
|
|
|
|
---
|
|
|
|
## 3. RISC-V Architecture Strategy
|
|
|
|
### 3.1 Privilege Mode
|
|
- Hypervisor runs in **RISC-V S-mode** (Supervisor mode).
|
|
- Previous boot stage is either OpenSBI in M-mode (firmware path) or direct QEMU entry in M-mode (`firmware=none`).
|
|
- In the M-mode case, a tiny trampoline sets PMP, delegates exceptions/interrupts to S-mode, and `sret`s to `_start_smode`.
|
|
- Guests run in **U-mode** (User mode) with their own `satp` page tables.
|
|
- **No H-extension:** All privileged operations are mediated by `ecall` hypercalls.
|
|
|
|
### 3.2 Required RISC-V Extensions
|
|
- `rv64imac` base (U54 cores do not implement F/D).
|
|
- **H-extension NOT available** on Icicle Kit U54 cores.
|
|
- `Zicsr`, `Zifencei`.
|
|
- Optional: `Sstc` (per-hart timer), `Svpbmt` (PMA in PTEs) — not present on U54.
|
|
|
|
### 3.3 Memory Layout (Icicle Kit)
|
|
- Hypervisor loaded at `0x8020_0000`.
|
|
- RAM: `0x8000_0000` — `0xBFFF_FFFF` (1 GiB low DDR).
|
|
- PLIC: `0x0C00_0000`.
|
|
- CLINT: `0x0200_0000`.
|
|
- MMUART0 (NS16550a): `0x2000_0000`.
|
|
|
|
### 3.4 Address-Space Isolation
|
|
- Hypervisor uses `satp` with Sv39 identity map (`_boot_l1_pt`).
|
|
- Each guest partition uses its own `satp` with a private Sv39 root page table.
|
|
- No two-stage translation (no `hgatp`). Guest physical = host physical for mapped regions.
|
|
|
|
---
|
|
|
|
## 4. Implementation Roadmap
|
|
|
|
### Phase A — RISC-V S-mode Paravirtualized Foundation ✅ COMPLETE
|
|
- [x] Reference analysis (PikeOS, Bao, Jailhouse, seL4).
|
|
- [x] M-mode trampoline → S-mode boot (`arch/riscv/boot.S`).
|
|
- [x] NS16550a UART driver (`arch/riscv/uart.cpp`).
|
|
- [x] Sv39 page-table allocator (`arch/riscv/page_table.cpp`).
|
|
- [x] S-mode trap vector (`arch/riscv/trap.S`) and C handler (`arch/riscv/exceptions.cpp`).
|
|
- [x] CLINT timer (`arch/riscv/timer.cpp`) + PLIC skeleton (`arch/riscv/plic.cpp`).
|
|
- [x] Task context structure (`arch/riscv/vm.h`) and assembly save/restore (`arch/riscv/context_switch_asm.S`).
|
|
- [x] Makefile `ARCH=riscv` target.
|
|
- [x] Per-hart kernel stack in trap frame (`kernel_sp` field).
|
|
- [x] Scheduler ready-queue fix (`in_ready_queue` flag).
|
|
- [x] Guest virtual time / timer hypercall.
|
|
- [x] Paravirtualized IRQ routing (`riscv_plic_route_irq`).
|
|
- [x] Console hypercall with guest-VA translation.
|
|
- [x] Memory map/unmap hypercalls.
|
|
- [x] Partition reset / yield / IPI hypercalls.
|
|
- [x] Multi-partition scheduling (time-partition windows).
|
|
|
|
### Phase B — PikeOS Parity Core 🔄 IN PROGRESS
|
|
- [x] PikeOS-style scheduler with time partitions / windows (`arch/riscv/task_sched.cpp/h`).
|
|
- [x] PikeOS-style memory map API (`arch/riscv/memory.cpp/h`).
|
|
- [x] Health monitoring hooks (`arch/riscv/hm.cpp/h`).
|
|
- [x] Guest image loading / boot (`arch/riscv/guest_loader.cpp/h`).
|
|
- [x] Paravirtualized PLIC IRQ routing to guests.
|
|
- [ ] Guest device tree generation (not needed for paravirtualized guests).
|
|
- [ ] Port partition lifecycle (`partition.c`) — mapped to `vm.cpp`.
|
|
- [ ] PikeOS API syscall mapping on RISC-V `ecall` — partial in `hypercall.cpp`.
|
|
|
|
---
|
|
|
|
## 5. Files Added / Modified in This Session
|
|
|
|
### New files
|
|
- `kernel/src/arch/riscv/csr.h`
|
|
- `kernel/src/arch/riscv/page_table.h`
|
|
- `kernel/src/arch/riscv/page_table.cpp`
|
|
- `kernel/src/arch/riscv/trap.S`
|
|
- `kernel/src/arch/riscv/cpu.h`
|
|
- `kernel/src/arch/riscv/cpu.cpp`
|
|
- `kernel/src/arch/riscv/vm.h`
|
|
- `kernel/src/arch/riscv/vm.cpp`
|
|
- `kernel/src/arch/riscv/context_switch_asm.S`
|
|
- `kernel/src/arch/riscv/context_switch.cpp`
|
|
- `kernel/src/arch/riscv/timer.h`
|
|
- `kernel/src/arch/riscv/timer.cpp`
|
|
- `kernel/src/arch/riscv/plic.h`
|
|
- `kernel/src/arch/riscv/plic.cpp`
|
|
- `kernel/src/arch/riscv/sbi.h`
|
|
- `kernel/src/arch/riscv/sbi.cpp`
|
|
- `kernel/src/arch/riscv/task_sched.h`
|
|
- `kernel/src/arch/riscv/task_sched.cpp`
|
|
- `kernel/src/arch/riscv/memory.h`
|
|
- `kernel/src/arch/riscv/memory.cpp`
|
|
- `kernel/src/arch/riscv/hm.h`
|
|
- `kernel/src/arch/riscv/hm.cpp`
|
|
- `kernel/src/arch/riscv/guest_loader.h`
|
|
- `kernel/src/arch/riscv/guest_loader.cpp`
|
|
- `kernel/src/arch/riscv/hypercall.h`
|
|
- `kernel/src/arch/riscv/hypercall.cpp`
|
|
- `kernel/src/arch/riscv/exceptions.h`
|
|
- `kernel/src/arch/riscv/exceptions.cpp`
|
|
- `kernel/src/arch/riscv/smp.h`
|
|
- `kernel/src/arch/riscv/smp.cpp`
|
|
- `kernel/src/arch/riscv/boot.S`
|
|
- `kernel/src/arch/riscv/linker_polarfire.ld`
|
|
- `kernel/src/arch/riscv/uart.h`
|
|
- `kernel/src/arch/riscv/uart.cpp`
|
|
- `kernel/src/arch/riscv/board_icicle.h`
|
|
- `kernel/src/arch/riscv/kernel.cpp`
|
|
|
|
### Renamed files (old → new)
|
|
- `kernel_riscv.cpp` → `kernel.cpp`
|
|
- `sched_pikeos.cpp` → `task_sched.cpp`
|
|
- `sched_pikeos.h` → `task_sched.h`
|
|
- `mem_pikeos.cpp` → `memory.cpp`
|
|
- `mem_pikeos.h` → `memory.h`
|
|
- `guest_boot.cpp` → `guest_loader.cpp`
|
|
- `guest_boot.h` → `guest_loader.h`
|
|
- `hcall.cpp` → `hypercall.cpp`
|
|
- `hcall.h` → `hypercall.h`
|
|
|
|
---
|
|
|
|
## 6. Notes & Risks
|
|
|
|
1. **S-mode paravirtualized design:** The Icicle Kit U54 cores lack the H-extension. The hypervisor runs in S-mode, guests in U-mode, and all privileged operations are mediated by `ecall`. This is a different architecture from the HS-mode / VS-mode design originally planned.
|
|
2. **No RISC-V toolchain in current environment:** `riscv64-unknown-elf-g++` / `qemu-system-riscv64` are not installed in this environment. Code is written for cross-compilation on a host with the toolchain; syntax correctness has not been verified locally.
|
|
3. **PikeOS RISC-V source absent:** We cannot copy PikeOS RISC-V code; we implement equivalent behavior using PikeOS ARM ukernel patterns and align data structures with PikeOS semantics.
|
|
4. **QEMU firmware=none path:** The M-mode trampoline in `boot.S` handles direct QEMU entry. When using OpenSBI, the firmware path skips the trampoline and enters directly in S-mode.
|
|
5. **Secondary harts:** Currently parked in `wfi` loops. Per-hart scheduler state and SMP scheduling are future work.
|
|
|
|
|
|
## 7. File-Level PikeOS → RISC-V S-mode Mapping
|
|
|
|
| PikeOS 5.0 Source (ARM ukernel) | RISC-V UniversalisOS Equivalent | Notes |
|
|
|----------------------------------|----------------------------------|-------|
|
|
| `sources/ukernel-arm_v7hf/src/main.c` | `arch/riscv/kernel.cpp` | Bare-metal entry, subsystem init. |
|
|
| `sources/ukernel-arm_v7hf/arch/arm/src/aexcpt.S` | `arch/riscv/trap.S` | Trap entry/exit (S-mode). |
|
|
| `sources/ukernel-arm_v7hf/arch/arm/src/cexcpt.c` | `arch/riscv/exceptions.cpp` | C trap dispatch (U-mode ecall → hypercall). |
|
|
| `sources/ukernel-arm_v7hf/arch/arm/src/mmu.c` | `arch/riscv/page_table.cpp` | Sv39 page tables (no G-stage). |
|
|
| `sources/ukernel-arm_v7hf/src/sched.c` / `tps.c` | `arch/riscv/task_sched.cpp` | Time partitioning + priority scheduler. |
|
|
| `sources/ukernel-arm_v7hf/src/int.c` | `arch/riscv/plic.cpp` | Physical PLIC + paravirtualized IRQ routing. |
|
|
| `sources/ukernel-arm_v7hf/src/task.c` / `thread.c` | `arch/riscv/vm.cpp` | Partition / task lifecycle. |
|
|
| `sources/ukernel-arm_v7hf/src/respart.c` | `respart.cpp` (future) | Physical partition allocator (architecture-neutral). |
|
|
| `sources/ukernel-arm_v7hf/src/uos_kdev_*.c` | TBD | Kernel device framework. |
|
|
| `sources/ukernel-arm_v7hf/src/hm.c` | `arch/riscv/hm.cpp` | Health monitoring / safety. |
|
|
|
|
## 8. Build & Run Commands
|
|
|
|
```bash
|
|
# ARM build (default, verified working)
|
|
cd /home/fabiorafaelcoutada/portugalfuturista/universalisos/kernel
|
|
make ARCH=arm clean && make ARCH=arm
|
|
|
|
# RISC-V build (requires riscv64-unknown-elf-g++ and qemu-system-riscv64)
|
|
make ARCH=riscv clean && make ARCH=riscv
|
|
make ARCH=riscv run
|
|
```
|
|
|
|
## 9. Known Limitations of This Session
|
|
|
|
1. **No RISC-V toolchain in this environment:** The code is written against the RISC-V ISA and has not been compiled or executed here. Syntax/semantics errors may exist.
|
|
2. **Guest execution is not yet exercised:** `riscv_task_run()` sets up `satp` and enters U-mode via `sret`, but a real guest image and MMIO emulation path are still TODO.
|
|
3. **Device pass-through is skeletal:** Only the PLIC and UART drivers are present; IOMMU, virtio, and PCI are not implemented.
|
|
4. **PikeOS API parity is partial:** Only the capability and resource-partition foundations are shared with the ARM build; the full `uos_*`/`p4_*` API surface is still being mapped.
|
|
5. **SMP is not active for RISC-V:** Secondary harts park; per-hart scheduler state and SMP scheduling are future work.
|
|
6. **No H-extension:** The Icicle Kit U54 cores do not implement the RISC-V H-extension. The design is S-mode paravirtualized, not type-1 hardware-virtualized.
|
|
|
|
## 10. Next Immediate Steps
|
|
|
|
1. Install/obtain `riscv64-unknown-elf-g++` and `qemu-system-riscv64` and fix any compile errors.
|
|
2. Provide a minimal guest image (e.g., a tiny bare-metal RV64 binary) and test `riscv_task_run()`.
|
|
3. Implement paravirtualized virtio-console or block device so guests can perform I/O.
|
|
4. Port the PikeOS `p4_*` API surface to RISC-V `ecall` hypercalls.
|
|
5. Map PikeOS `respart.c`, `task.c`, and `hm.c` semantics onto the RISC-V S-mode paravirtualized model.
|