Running Linux on ESP32-S31: What the MMU Changes
ESP32-S31 now has an official Linux BSP Developer Preview. Here is a practical look at its MMU, Buildroot, U-Boot, Linux 6.18, build flow, and the limits that still matter.
Share

“Linux on ESP32” used to sound like either a very slow emulator or a demo that stopped at a shell prompt. This time the story is more substantial: ESP32-S31 has an MMU, and Espressif has published an official Linux BSP as a Developer Preview.
As of August 24, 2026, this is still lab material rather than a safe production platform. Even so, it is a meaningful sign that the line between an MCU and a small Linux SoC is getting thinner.
What makes S31 different?
ESP32-S31 has two 32-bit RISC-V cores running at up to 320 MHz and includes MMU support. The current ESP32-S31-Korvo-1 board uses a module with 16 MB of flash and 16 MB of PSRAM.
An MMU is not an absolute requirement for a Linux kernel to exist: ESP32-S3 already has native NOMMU Linux ports. Without an MMU, however, there is no familiar virtual-memory and process-isolation model, and software depending on normal fork() behavior becomes difficult or impossible to use. S31 lets Linux follow a more conventional memory model instead of forcing the whole userspace into NOMMU constraints.
| Platform | How Linux runs | Practical meaning |
|---|---|---|
| Xtensa ESP32-S3 | Native NOMMU Linux | Boots and provides a shell, but userspace is heavily constrained |
| Older ESP32 with an emulator | Emulated RISC-V or x86 | Educational, but extremely slow |
| RISC-V ESP32-S31 | Native Linux with an MMU | Closer to normal embedded Linux, while RAM and drivers remain limited |

Korvo-1 uses an ESP32-S31-WROOM-3 module with 16 MB flash and 16 MB PSRAM.
I still would not describe S31 as a tiny Raspberry Pi. Sixteen megabytes of PSRAM can hold a minimal Buildroot system, BusyBox, and a few small processes. It does not suddenly provide a desktop, a large package repository, or practical general-purpose containers.
What is in the official BSP?
Espressif explicitly labels the integration/v1.0-esp32s31 branch of esp-linux-bsp as a Developer Preview. The current stack includes:
- Buildroot 2025.02 for the toolchain and root filesystem.
- An Espressif Linux 6.18 fork for ESP32-S31.
- U-Boot SPL, OpenSBI, and a U-Boot FIT image in the boot chain.
- An XIP kernel executing from NOR flash to preserve PSRAM.
- A minimal
cramfsroot filesystem. - A merged
s31_full_flash.binimage written at offset0x0.

The BSP packages U-Boot SPL, OpenSBI, U-Boot, an XIP kernel, and cramfs into one image.
The short version of the boot flow is:
ESP ROM → U-Boot SPL → OpenSBI/U-Boot → XIP Linux → cramfs/BusyBox
The esp-linux-bsp repository mainly contains the image layout and packaging tools. Buildroot integration lives in esp-buildroot-external, while the kernel is in Espressif's Linux fork. That means several repositories are involved, but each layer can be inspected instead of relying on an opaque binary image.
Before you try it
The official defconfig currently targets the ESP32-S31 Function Core Board. Community ports commonly target ESP32-S31-Korvo-1. Their connectors and board layouts are different, so follow the hardware guide for the exact board on your desk.
On Korvo-1, the USB-C Power connector only supplies power. The USB-C UART connector is the one connected to the CP2102N bridge for flashing and console access. It is an easy detail to miss when both sockets look similar.
Before flashing:
- Use a module with 16 MB PSRAM and enough flash for the image.
- Use a USB data cable.
- Upgrade
esptoolto version 5.3.0 or newer. - Back up the board's existing firmware and data.
- Avoid experimenting on a Secure Boot or Flash Encryption device without a recovery plan.
The full image is written from 0x0, replacing the existing firmware, partition table, and stored data.
Build the official Linux image
I recommend a clean Linux environment because the flow is based on Buildroot. These commands follow the current external tree:
mkdir -p ~/esp32-s31-lab && cd ~/esp32-s31-lab
git clone --branch 2025.02 --depth 1 \
https://gitlab.com/buildroot.org/buildroot.git esp-buildroot
git clone --branch buildroot/v2025.02-esp32s31 \
https://github.com/espressif/esp-buildroot-external.git
Configure the Function Core Board for NOR boot:
make -C esp-buildroot \
BR2_EXTERNAL="$PWD/esp-buildroot-external" \
O="$PWD/esp32-s31-linux" \
espressif_esp32s31_function_core_board_nor_defconfig
Then build the image:
ESP_ESPTOOL="$(command -v esptool)" \
make -C esp-buildroot O="$PWD/esp32-s31-linux" -j"$(nproc)"
The first build can take over an hour because Buildroot downloads and compiles the toolchain, bootloader, kernel, and root filesystem. The main output is:
esp32-s31-linux/images/s31_full_flash.bin
Flash and open the console
Replace <serial-port> with the actual UART port, such as /dev/ttyUSB0 or /dev/cu.usbserial-*:
esptool --chip esp32s31 \
--port <serial-port> \
--baud 1152000 \
write-flash 0x0 esp32-s31-linux/images/s31_full_flash.bin
The Linux console runs at 115200 baud:
picocom -b 115200 <serial-port>
# or
screen <serial-port> 115200

UART console is the clearest baseline; peripherals and networking remain commit-specific.
Once BusyBox appears, I start with a small set of checks:
uname -a
cat /proc/cpuinfo
cat /proc/meminfo
mount
df -h
dmesg | tail -n 30
The first goal is to verify the kernel, memory, root filesystem, and console. A shell prompt alone does not prove that Wi-Fi, USB, SD, or every peripheral is ready.
The three current S31 Linux paths
| Path | Kernel | Notable status |
|---|---|---|
| Espressif ESP Linux BSP | 6.18 fork | Official Buildroot/U-Boot preview; not recommended for production |
GrieferPig esp32-s31-linux | 6.12 | Rootfs and reboot marked stable; Wi-Fi and many drivers remain experimental |
annoyedmilk/esp32-s31-linux | 7.1 + OpenSBI 1.9 | LCD, microSD, USB HID, and Wi-Fi work in progress; many peripherals are still missing |
Wi-Fi is the easiest feature to overstate. GrieferPig lists ESP-Hosted as experimental. The Linux 7.1 project keeps firmware on one hart to own the radio, but its README currently both documents a wifi command and lists association as unfinished. The official BSP does not yet publish a sufficiently clear driver matrix. For now, UART console support is the clearest baseline; networking must be verified against the exact commit and board.
Two cores do not mean Linux owns both
Community ports commonly leave one HART running ESP-IDF/FreeRTOS and the proprietary radio firmware while Linux uses the other HART. This is a practical way to retain Wi-Fi and Bluetooth without reimplementing the entire radio stack in Linux.
It is fair to say that FreeRTOS and Linux can coexist in these experiments, but that does not yet imply a stable product API for sharing workloads. IPC, cache coherency, DMA, security boundaries, and lifecycle updates remain difficult engineering problems.
Containers are not a realistic target either. The MMU improves the process model, but 16 MB of PSRAM is still far too small for Docker and ordinary container images. The nearer-term value is BusyBox, small networking daemons, compact POSIX tools, and selective reuse of the embedded Linux ecosystem.
Should it go into a product?
Not yet. Espressif says the preview receives irregular updates, may introduce breaking changes without notice, provides no API or ABI guarantees, and is supported on a best-effort basis. Driver coverage, shutdown behavior, security, PSRAM performance, and recovery still need much more validation.
I would use it to study the RISC-V boot flow, experiment with Buildroot on an MMU-equipped MCU, and measure how small a useful Linux workload can become. ESP-IDF and FreeRTOS remain safer for products that need deterministic timing, fast boot, and mature peripheral drivers. If the application genuinely needs a broad Linux userspace and much more memory, a small MPU or SBC will still save significant engineering time.
The important part is not simply that “an ESP32 can run Linux” — S3 already proved that through NOMMU ports. The new part is the combination of S31's MMU, a vendor boot stack, and active community ports. It is a real step forward, but it still belongs on the lab bench rather than the production line.
References
- Espressif
esp-linux-bsp— ESP32-S31 Developer Preview - Espressif
esp-buildroot-external— Buildroot external tree - Espressif Linux kernel fork
- ESP32-S31 product overview and MMU specifications
- ESP32-S31-Korvo-1 V1.1 user guide
- ESP32-S31 mass-production announcement, July 27, 2026
- GrieferPig/esp32-s31-linux — Linux 6.12 MMU port
- annoyedmilk/esp32-s31-linux — Linux 7.1 and OpenSBI 1.9
- CNX Software — building the Developer Preview
- Facebook discussion shared by the reader
Share
Keep exploring
Read next
Related articles
TinyML on ESP32: Running AI on the Device
How I run a small person-detection model on ESP32 with TensorFlow Lite Micro and ESP-NN, from memory limits to testing Espressif's example.
Designing an Emotion State System for the Mochi Robot
Build a Mochi Robot emotion state machine for idle, listening, talking, happy, sad, thinking, and error states with replaceable animations.
Extending Battery Life in an ESP32 Robot with a Display
Analyze battery life for an ESP32 robot with a display: backlight, Wi-Fi, audio, peripherals, sleep modes, wake sources, and runtime.