ESP32 也能跑 Linux 了
大家好,我是写代码的篮球球痴。
乐鑫最近放了个东西出来,我刷到的时候愣了一下——ESP32 竟然能跑 Linux 了。
那岂不是最便宜的 可量产的Linux系统了?

是乐鑫官方自己出的 BSP,冲着 ESP32-S31 来的,一颗双核 RISC-V 芯片。
——先讲它怎么跑?
ESP32 从 ESP8266 一路迭代到现在,定位一直是 Wi-Fi、蓝牙加 FreeRTOS 的物联网 MCU。控制几个传感器、驱动电机、连个云,好使得很,便宜、省电、上手快。
但你要说跑 Linux,以前基本没戏。
不是芯片性能不够,是差两样东西。
一样是 CPU 架构。
老 ESP32、ESP32-S2、S3 用的都是 Xtensa 核,这个核主线 Linux 不认。
后来乐鑫上了 RISC-V,ESP32-C3、C6、H2 都是 RISC-V 核了,架构这关是过了。
但另一样东西一直没有——MMU,内存管理单元。
Linux 从出生那天起就离不开 MMU。
它要给每个进程一个独立的地址空间,进程 A 以为自己独占整块内存,进程 B 也这么以为,中间靠 MMU 做翻译,把假的虚拟地址映射到真的物理地址上。
这样谁也不能随便踩谁的内存,多进程、多用户、权限隔离才玩得转。
没有 MMU,你就只能跑 µClinux 那种阉割版,能用,但软件生态和开发体验差一大截。

MMU 把虚拟地址翻译成物理地址
ESP32-S31 这次把 MMU 加上了,再配 16MB PSRAM,硬件这关才算真正迈过去。
——16MB 内存,怎么把 Linux 塞进去?
你想想,16MB 的 PSRAM,放桌面电脑上屁都不是,装个内核都不够。
正常电脑跑 Linux,是把内核从硬盘加载到 RAM 里解压再执行,树莓派 1GB、2GB 的内存,不在乎这点占用。
但 ESP32-S31 不行。
官方那个完整镜像 s31_full_flash.bin 有 13.8MB,你要是照老办法把内核全搬进 RAM,16MB 扣掉内核,剩一两兆给你跑应用,还玩个毛?
所以乐鑫用了一招:XIP,就地执行(execute in place),这在全志的芯片上也搞过的技术,,,。
一句话,代码不搬进 RAM,留在 Flash 上,CPU 通过 cache 直接去 Flash 里取指令执行。
ESP32 这套机制搞嵌入式的都熟——你平时烧的那几百 KB 固件,很大一部分就是 map 在 Flash 上跑的,不占片内 RAM。
现在把这套思路往上推了一层,推到 Linux 内核头上。
内存划分大概是这么个结构:
位置 | 放什么 | 为什么 |
|---|---|---|
Flash(16MB) | bootloader、OpenSBI、XIP 内核、cramfs 根文件系统 | 代码和只读数据就地执行,不占 RAM |
PSRAM(16MB) | Linux 运行时内存:页表、堆、栈、可写数据段 | 可写的东西必须在 RAM |
三样大头都是"就地在 Flash 上待着":
内核
是 xipImage,直接在 Flash 上执行,不搬进 PSRAM;
根文件系统
用 cramfs,一种压缩过的只读文件系统,留在 Flash 上,要用哪个文件就读哪个,不整体解压;
OpenSBI
也一样,代码留 Flash,只有它那点可写数据(.data/.bss/栈)搬到 PSRAM 顶部。

代码留在 Flash,PSRAM 只放运行时数据
这样一来,16MB 的 PSRAM 基本全留给 Linux 当运行时内存了。
启动日志里 free -h 一跑,看到的是 13.6M total,剩下那点被 OpenSBI 的可写段和预留区吃掉了。
这就是为什么一颗只有 16MB PSRAM 的芯片,能把一整条 Linux 启动链跑起来——核心不是内存够大,是代码压根不占内存。
——两颗核,还分工
这里还有个窍门,不搞嵌入式的不容易注意到。
ESP32-S31 是双核,但跑 Linux 的时候,它没做成 SMP(对称多处理,两颗核一起跑 Linux),而是一个核一个活:
Hart 0 继续跑 ESP-IDF 的 FreeRTOS,管着 Wi-Fi、蓝牙;
Hart 1 专门跑 Linux。
为啥不两颗核一起跑 Linux?
原因是——乐鑫那套射频固件是闭源的,只能跑在 FreeRTOS 框架里,你没法把它搬到 Linux 下去驱动。所以干脆让 Hart 0 守着老本行干无线,Linux 占 Hart 1。
但这也埋了个雷——Wi-Fi 恰恰成了现在最悬的外设。
射频在 Hart 0,Linux 在 Hart 1,中间隔着核,数据得通过共享内存和中断门铃来回搬。这套跨核通信的驱动,官方文档到现在没给个准话。
这也是为什么说,别急着拿它做产品。

——官方 BSP
乐鑫这次放出来的东西挺全乎,不是丢给你一个内核让你自己点。
镜像布局和打包在 esp-linux-bsp 这个仓库
github.com/espressif/esp-linux-bsp
最后生成一个 s31_full_flash.bin,直接烧进去就能跑。
真正的 Buildroot 配置在 esp-buildroot-external 仓库
github.com/espressif/esp-buildroot-external
基于 Buildroot 2025.02,32 位 RISC-V musl 工具链。里面这几个组件:
OpenSBI 1.6 的乐鑫分支
U-Boot 2024.07 的乐鑫分支
Linux 6.18 的 ESP32-S31 分支
镜像打包工具
——启动链是
SPL → OpenSBI → U-Boot → Linux 内核 → 根文件系统 → root shell。
这不是单独把内核"点亮"给你看个 logo,这是一整条完整的 Linux 启动链,从 bootloader 一路跑到能登录。
——编译烧录走一遍
光看 BSP 列表还是虚的。我顺着 CNX Software 那篇实测往下撸了一遍流程,把关键步骤拎出来。
CNX 作者自己没板子,只跑了到生成镜像这一步,但编译链路是通的,烧录到板子上命令也是同一套。
第一步,esptool 升版本。这是个坑——ESP32-S31 要求 esptool 5.3.0 以上,老版本会直接报错。Ubuntu 自带的多半是 4.x,得手动装:
sudo apt purge esptool sudo apt install pipx pipx ensurepath pipx install esptool esptool version跑完应该看到 esptool v5.3.1。
第二步,拉代码。Buildroot 主线和乐鑫的外部配置各一个仓库,分开拉:
git clone --branch 2025.02 --depth 1 https://gitlab.com/buildroot.org/buildroot.git esp-buildroot注意 esp-linux-bsp 这个镜像打包仓库不用单独拉,Buildroot 会自动拽下来。
第三步,配 defconfig。乐鑫给了一个默认配置,省事:
make -C esp-buildroot \ BR2_EXTERNAL=~/edev/sandbox/esp-buildroot-external \ O=~/edev/sandbox/esp32-s31-linux \ espressif_esp32s31_function_core_board_nor_defconfig看到 configuration written to .../.config 就说明配置成功了。
第四步,开编。这步最熬人,CNX 实测一个多小时:
ESP_ESPTOOL=$(which esptool)编完到 images/ 目录下看一眼,关键产物是这些:
$ ls esp32-s31-linux/images/s31_full_flash.bin 就是最后要烧的那个总镜像,13.8MB,把 bootloader、OpenSBI、U-Boot、内核、根文件系统全打包好了。
xipImage 是裸内核镜像,rootfs.cramfs 是只读根文件系统,前面那套 XIP 内存划分就是靠这两个货实现的。
第五步,烧录。接上板子,确认串口号,然后:
esptool --chip esp32s31 --port <serial-port> --baud 1152000 write-flash 0x0 <path-to-output-directory>/images/s31_full_flash.bin波特率用的是 1.5M,115200 是烧完后看 Linux 串口控制台用的。
整条链路就这五步。
Buildroot 第一次编要把 32 位 RISC-V musl 工具链、各种依赖全下载下来,等于从头搭一套小 Linux 发行版,所以慢。
第二次编就快了,增量编译。
——但是,先别急着拿它做产品
我得泼盆冷水。
这次发的是 Developer Preview,开发者预览版,不是稳定版。乐鑫自己在项目说明里写得很实在:
现在只支持 ESP32-S31
没有固定更新周期
后面改动可能破坏兼容性
不保证 API 和 ABI 稳定
Bug 只在资源允许的时候修
再叠上前面的 Wi-Fi 悬案,现在最适合干的,是拿块板子体验下启动流程,看看外设支持到什么程度,评估下 Linux 在 16MB 内存里到底能跑成啥样。
真要往量产方案里写,还早着了。。。。。。
——那 ESP32 跑 Linux,到底有啥用?
这问题得说清楚。
如果你就是控制几个传感器、驱动电机、定时传点数据,FreeRTOS 更省资源、启动更快,硬上 Linux 纯属自找麻烦。
但换个场景就反过来了。比如你要用现成的网络工具、文件系统、Shell 脚本、一堆开源程序,Linux 生态里现成的东西一大把,你在 FreeRTOS 里得一个驱动一个驱动地抠。
再比如你团队本来就熟 Linux 开发,招人、交接、维护都顺。
ESP32-S31 可能就此站到一个以前够不着的位置:比普通 MCU 更接近通用操作系统,又比传统 Linux SoC 更轻、更便宜。
现在说它要改变哪个市场,还太早。
更实在的问题是,乐鑫接下来能不能把无线和常用外设的驱动补齐,能不能让这个 BSP 稳定地维护下去。等这些都有了,ESP32-S31 才算真正迈过 Linux 设备的门槛。
——
还有个背景值得一提。
官方 BSP 出来之前,社区已经抢跑了。
早就有大佬在给 ESP32-S31-Korvo-1 开发板移植 Linux,有的基于 Linux 6.12(github.com/GrieferPig/esp32-s31-linux),能稳定跑 Buildroot 根文件系统和重启,但关机还没做,Wi-Fi、蓝牙双模、双核支持都是实验状态;还有的在试 Linux 7.1 和 OpenSBI 1.9(github.com/annoyedmilk/esp32-s31-linux),基础启动成了,但 LCD、microSD、USB Host、WLAN Modem 这些外设都还没启用。
直接看 GrieferPig 那边跑出来的实际启动日志——Linux 6.12 内核,Buildroot 根文件系统,登录 root,跑个 CoreMark 测了下性能(1083 iterations/sec),然后 free -h 一看,16MB PSRAM 跑起来后剩 13.6M total:

GrieferPig 在 ESP32-S31 上跑 Linux 6.12 的实际启动日志
注意一行 Starting network: Cannot find device "eth0" FAIL,网络驱动还没接上,这跟官方 BSP 的 Wi-Fi 悬案是一个问题:射频基带锁在 FreeRTOS 那颗核上,Linux 核暂时够不着。
这说明两件事:
一是 ESP32-S31 的硬件确实扛得住 Linux,
二是驱动和外设适配才是后面最磨人的部分。内核能启动,只是第一关。
这篇文章先写到这。
乐鑫还是有点东西,我挺期待他们把 Wi-Fi 驱动补齐的那天。
到那时候,可能很多以前得用 A 系列芯片干的活,一颗几块钱的 ESP32 就能接了。
那画面,想想挺爽,全志,瑞芯微的不知道会不会发抖,,。
---
参考:
原文(strongerHuang 转发):https://mp.weixin.qq.com/s/M8IiGetPHlyPmzU8KDA8sw
CNX Software 编译实测:https://www.cnx-software.com/2026/08/22/espressif-systems-releases-a-linux-bsp-developer-preview-for-esp32-s31-risc-v-microprocessor
官方 BSP:https://github.com/espressif/esp-linux-bsp
Buildroot 配置:https://github.com/espressif/esp-buildroot-external
乐鑫 Linux 6.18 内核 fork:https://github.com/espressif/linux
乐鑫 ESP32-S31 外部 RAM 文档:https://docs.espressif.com/projects/esp-idf/en/latest/esp32s31/api-guides/external-ram.html
GrieferPig 的 Linux 6.12 移植:https://github.com/GrieferPig/esp32-s31-linux
Marco 的 Linux 7.1 + OpenSBI 1.9 移植:https://github.com/annoyedmilk/esp32-s31-linux