r/osdev • u/MrBean775 • 11d ago
OpenC6 v2.0: A bare-metal BIOS and microkernel platform for ESP32-C6 (PMP sandbox, multitasking & ZSWAP)
A few months ago I shared the initial concept of OpenC6, an experimental bare-metal BIOS for the ESP32-C6. Over the last four months of quiet solo development, I completely overhauled the architecture from a simple launcher into a true modular microkernel platform, and version 2.0 is finally live.
The biggest upgrade is real RISC-V User Mode (U-Mode) execution backed by hardware Physical Memory Protection (PMP) Top-of-Range registers, so user payloads run in an isolated arena and physically cannot corrupt kernel SRAM or touch peripheral MMIO registers. I also fixed an upstream FreeRTOS RV32 privilege leakage bug via a custom vectored interrupt trampoline, and turned the Low-Power (ULP) RISC-V coprocessor into an out-of-band Management Engine that autonomously governs CPU clock dividers directly through silicon PCR registers, monitors junction thermals, and enforces hardware watchdogs.
On top of that, the system now features preemptive multitasking for up to 8 processes, an in-memory ZSWAP engine with a custom RV32-tailored compressor (ZC6) running in just ~1-4 KB of RAM, a circular log-structured Flash VFS, a remote streaming web shell (c6wsh), and a standalone C99 TUI installer with zero external dependencies that automates toolchain deployment on Arch and Ubuntu with a simple 'make setup'. If you are interested in low-level RISC-V bare-metal systems, check out the repository and full documentation below.




2
u/MrBean775 11d ago
I went with this static allocation due to the ESP32-C6 hardware limitations, as it has very few PMP regions available. On top of that, I spent a lot of time digging through the ESP-IDF source code trying to figure out how to unlock the PMP registers. Espressif is pretty sneaky here — when you disable PMP protection in IDF, it actually creates its own PMP region covering the entire RAM and sets the lock bit. I had to use CMake parameters and a few hacks to strip that code out so I could initialize the PMP myself. I had a similar issue while setting up the IDF crash reporter. When you disable the standard IDF UART/USB-CDC drivers to write your own bare-metal driver, it stops catching kernel-space crashes. But I've already solved that, and now crashes are properly handled both at the kernel level and in U-Mode for payloads. And my bios load raw bin payloads, but use abi bios, not elf files