Linux op een ESP32-S3 — Native Linux die stabiel blijft
Wat is nieuw in versie 0.8
Versie 0.8 is de release waarin het board stopt met crashen. Sinds versie 0.7 vertoonde ongeveer één op de tien fabrieksboots een kernel-fout in de eerste seconden. Omdat de teststilte als een 'pass' werd geteld, bleef dit onopgemerkt. De oorzaak lag in de firmware: de ESP32-S3 heeft één flash-cache voor beide cores. Na elke schrijfactie die Linux uitvoerde naar jffs2, werd deze niet ongeldig gemaakt, waardoor de kernel verouderde pagina's bleef lezen, soms zelfs van zijn eigen code. Vier regels in de firmware lossen dit op. Vijfenvijftig opeenvolgende fabrieksboots verliepen foutloos op de herstelde firmware, gemeten door een runner die dmesg terugleest in plaats van te vertrouwen op een stille console. Dit bewijst niet dat het board nooit crasht, maar het toont aan dat de corruptie tijdens het vroege opstarten, die voorheen in één op de tien boots voorkwam, niet meer reproduceerbaar is.
Met dit probleem opgelost, blijkt dat de page-set exchange van de fork-backend — die eerder werd afgeschreven omdat het geheugen zou corrumperen — dit in werkelijkheid nooit deed. Deze functie is nu opgenomen, waardoor elk programma dat een fork uitvoert, de helft van het geheugen nodig heeft dat voorheen vereist was. make en jobq hebben geen extra geheugen nodig, omdat zij gebruikmaken van spawn. Het beschikbare geheugen (MemAvailable) na boot ging van 1,3 MB naar 3,7 MB.
Andere verbeteringen die opvallen:
wifi connectschrijft voor het eerst de configuratie weg.bootlog verbosezet de console weer aan zonder dat een rebuild nodig is.- Een update verwijdert niet langer het WiFi-wachtwoord.
- De klok overleeft een reboot.
- De vier dropbear-host-keys die elk board voorheen deelden, zitten niet langer in het image.
De changelog bevat de rest van de wijzigingen, inclusief de cijfers.
Let op: Fork is geen volledige MMU. Dit blijft NOMMU Linux, zonder hardwarematige geheugenbescherming voor processen. Het experiment met de schakelbare MMU-remap is een aparte runtime en geen loader voor willekeurige desktop-binaries. Zie de sectie 'Beperkingen' voor meer details.
RAM-gebruik: Voor en Na
Beide kolommen zijn uitgelezen van het board via /proc/meminfo en programbench: de kernel van 0.7 in het ene record, het image van 0.8 in het andere. build/plot-ram.py genereert de afbeeldingen op basis van deze data.
Het middelste paneel toont wat een programma kost voor de fork-backend bovenop het eigen geheugen: de shadow pages die ouder- en kindproces gescheiden houden. De exchange halveert dit, en omdat make en jobq spawnen in plaats van forken, kosten zij niets.
Het rechterpaneel toont de vloer: het laagste gemeten MemAvailable terwijl elk benchmark-programma draaide. Bij 0.7 zakte bash tot 248 kB, wat de oorzaak was van de melding fork: Cannot allocate memory.
De data voor de piek van de fork-shadow per programma (in kB) is als volgt:
| Programma | Versie 0.7 | Versie 0.8 |
|---|---|---|
| bash | 892 | 528 |
| micropython | 512 | 308 |
| dash | 560 | 280 |
| make | 432 | 0 |
| socat | 296 | 152 |
| jobq | 248 | 0 |
Hardware
- ESP32-S3 met 16 MB flash en 8 MB Octal PSRAM: een N16R8-module, zoals de bijbehorende DevKitC-1.
- Stroomvoorziening en een seriële/COM-verbinding voor het flashen en de console. Gebruik de eigen adapterpoort van uw board; er zijn geen extra randapparaten nodig.
De huidige versie verkrijgen
De map images/ bevat de 0.8 release. De snelste methode is om het image uit de repository te flashen:
./flash.sh -p /dev/ttyUSB0
Dit schrijft de volledige 16 MiB chip en vervangt /etc en /home. Om hetzelfde image vanuit de broncode te bouwen, volg dan de onderstaande instructies.
De geautomatiseerde methode
./run.sh bestuurt het gehele proces en is de kortste route. Zonder argumenten opent het een menu; elke stap is ook beschikbaar als vlag, zodat het onbeheerd kan werken:
git clone https://github.com/paulneja/Linux-on-esp32-S3.git
cd Linux-on-esp32-S3
./run.sh # opent het menu
./run.sh --all -y # controleert, bouwt, verifieert, flasht en test zonder prompts
Het build-proces geeft live output en meldt vooraf dat het ongeveer 40 minuten duurt en circa 21 GB schijfruimte vereist (-q stuurt deze output alleen naar de log). Het script controleert de omgeving voordat het proces start, zoekt naar een interpreter met pyserial, kiest een ongebruikte output-directory, waarschuwt voordat er gegevens van het board worden gewist, en biedt aan om een console die de seriële poort bezet houdt te sluiten. ./run.sh --help toont alle acties, inclusief --repro voor een vergelijking tussen twee builds en --recover om een board terug te zetten naar de fabrieksinstellingen van /etc en /home.
Handmatige stappen
1. Bouwen vanuit een clean checkout
Op een Linux-host met Git- en Docker-toegang, als normale gebruiker:
git clone https://github.com/paulneja/Linux-on-esp32-S3.git
cd Linux-on-esp32-S3
JOBS=8 bash build/reproduce.sh
Houd rekening met de tijd voor downloads en compilatie, en zorg voor voldoende vrije schijfruimte. De build gebruikt een eigen directory en overschrijft niet de bestaande toolchain of oudere committed images.
De output staat in build-output/reproduce.XXXXXX/artifacts/ (vervang XXXXXX door de directory die wordt geprint), met daarin het 16 MiB linux-esp32s3-native-full.bin, component-images, SHA256SUMS en build-manifest.json.
2. Het gebouwde image flashen
Installeer esptool op de host, sluit alle consoles die de COM-poort gebruiken en vervang /dev/ttyUSB0 door het juiste pad. Een volledige image-schrijfactie vervangt configuratie- en gebruikersbestanden, inclusief /etc en /home.
./flash.sh -p /dev/ttyUSB0 --images build-output/reproduce.XXXXXX/artifacts
Zonder de vlag --images leest het script de committed images/ map. Het equivalent via de command-line is:
esptool --chip esp32s3 --port /dev/ttyUSB0 --baud 460800 \
write_flash --flash_mode dio --flash_size 16MB --flash_freq 80m \
0x0 build-output/reproduce.XXXXXX/artifacts/linux-esp32s3-native-full.bin
3. Inloggen en verbinden
Open een seriële terminal op 115200 baud. Bijvoorbeeld:
screen /dev/ttyUSB0 115200
Log in als root met wachtwoord changeme123, en gebruik vervolgens passwd om het wachtwoord te wijzigen. Een fabrieksimage heeft geen WiFi-configuratie:
wifi
Het interactieve menu scant netwerken en laat u er een kiezen. Alternatief kunt u gebruiken: wifi connect "UW SSID" "UW WACHTWOORD".
Let op: Starting network (background): OK betekent alleen dat de opstartprocedure is gelanceerd, niet dat de WiFi-verbinding is geslaagd. Controleer /var/log/network.log voor het resultaat. NTP stelt de klok in zodra de netwerkverbinding tot stand is gekomen; tot die tijd kunnen HTTPS-certificaatcontroles mislukken omdat het board geen batterij-gebufferde klok heeft.
Telnet is standaard ingeschakeld en verstuurt inloggegevens in platte tekst. Gebruik een vertrouwde LAN en lees SECURITY.md voordat u verbinding maakt.
Dingen om te proberen
- Voer een script uit met
micropython /home/root/script.py. Dit is MicroPython, geen CPython; algemene pip-compatibiliteit is niet aanwezig. - Bewerk
/home/www/index.html, start de webserver metweb-server on, en open het IP-adres van het board in een browser. Gebruikweb-server offom deze uit te schakelen; de instelling overleeft een reboot. - Gebruik
crontab -eom taken voor uw gebruiker in te plannen. - Gebruik
session workom een lichtgewicht shell te maken of opnieuw te koppelen. Koppel los metCtrl-]en bekijk sessies metsession list. - Gebruik
nohup command > /tmp/job.log 2>&1 &voor een niet-interactieve taak die moet doorlopen na het sluiten van de console. Dit overleeft geen reboot of stroomuitval; zorg dat het sluiten van de terminal het board niet reset.
Functionaliteiten overgenomen uit versie 0.7
- Native
fork()via software-geheugenbanken. - Bash 5.2 als login-shell, BusyBox als
/bin/sh, Dash beschikbaar. - GNU Make, MicroPython met fork en IPC, socat en nc.
- Bewerkbare webpagina in
/home/wwwen private home-directories met Unix-permissies. - Per-user cron, session/dtach consoles en nohup.
jobqenprogrambenchvoor werken binnen 8 MiB.- Een clean-build pipeline met checksums, partitiecontroles en een board-suite gekoppeld aan één exact image.
Functionaliteiten overgenomen uit versie 0.6
- STA WiFi en BLE-provisioning. Verbind met een netwerk via de console of de Esp32-Linux BLE-service (zie
BLE.md). SoftAP is verwijderd; het board fungeert niet als WiFi-access point. nanoenLua.viverwijst naar nano in plaats van het uitgeschakelde BusyBox vi-applet.- Hardware RSA-acceleratie. De
rsa-esp32s3Linux Crypto API-driver heeft boot-time 512-bit en 2048-bit zelftests. - Optionele SSH- en HTTP-services. Dropbear wordt beheerd met
ssh-server on|off|status; HTTP metweb-server on|off|status. Bestanden kopiëren kan viascp -O(dropbear heeft geen SFTP-server). Beide staan standaard uit. SSH is traag op deze hardware; de RSA-driver versnelt de Curve25519-operaties niet. - NTP en
curl. Gewoon HTTP werkt. HTTPS gebruikt certificaatverificatie met een ingekorte CA-bundle en TLS 1.2, maar blijft experimenteel vanwege de RAM-beperkingen.
Build- en teststatus
De 0.8 board-suite werd uitgevoerd op een clean build van 8ea9011: een verse clone, run.sh --all, 36 tests, 0 fouten. Daarna volgden tien extra controles (10/10), tien fabrieksboots met dmesg- en taint-flag uitlezing (10 schoon), en het aansturen van het board vanaf een andere machine via WiFi (SSH, scp, webpagina).
De gepubliceerde image is gebouwd via de Image-workflow van 13c85d6. Tussen 8ea9011 en die commit veranderden de build-inputs alleen in commentaren en de wifi-connect fix. Twee onafhankelijke container-builds van de commit verschillen slechts in één bestand, /etc/shadow, door de willekeurige password salt.
De corruptie-fix is gemeten: 55 opeenvolgende fabrieksboots op de herstelde firmware waren allemaal schoon, tegenover 10 fouten in 17 boots daarvoor.
Beperkingen
- RAM-beperking: 8 MiB RAM is een strikte beperking.
forkkopieert privégeheugen direct; het is geen copy-on-write. De backend is alleen 'UP', weigert multithreaded fork en beperkt privégeheugen per fork tot 512 KiB. Meerdere Bash-sessies of grote pipelines kunnen het geheugen uitputten; detached sessies gebruiken standaard Dash. - Context Switch: Een context switch kan interrupts ongeveer 21 ms uitschakelen. De backend verplaatst het privégeheugen van een proces bij elke switch (tot het plafond van 512 KiB) met uitgeschakelde interrupts. Bij het maximale plafond is dit 21,5 ms, wat langer is dan de 10 ms tick. Copy-on-write is op deze chip niet mogelijk omdat een niet-toegestane schrijfactie een asynchrone interrupt veroorzaakt, waardoor er geen herstartbare fout is om een pagina te kopiëren en de store opnieuw te proberen.
/proc/meminforapporteertForkSwitchMaxenForkSwitchLast. - Binaries: Native binaries moeten gericht zijn op Xtensa/FDPIC. Willekeurige x86, ARM of desktop Linux binaries werken niet. CPython, Neovim, SQLite, sudo en doas zijn niet inbegrepen.
- Flash-snelheid: Beschrijfbare flash kan extreem traag worden.
/etcen/homegebruiken JFFS2. Grote schrijfacties en block reclaim zorgden in tests voor ernstige vertragingen. Startup-wijzigingen verzachten de impact bij het opstarten, maar lossen de schrijfsnelheid niet op. Vermijd zware herschrijfacties en maak back-ups van belangrijke data. - Beveiliging: Permissies zijn geen geheugenisolatie. Gebruik vertrouwde programma's en gebruikers. Dit is een onderzoeksproject, geen gehard productiesysteem.
- Rootfs: De rootfs is read-only XIP cramfs. Direct uitvoeren vanuit flash is essentieel om het systeem in het RAM te passen.
Documentatie
- Build pipeline: Clean builds, artifacts en board tests.
- Architecture: Gedeelde chip, boot flow en flash layout.
- Development: Patches, upstream bronnen en de legacy build.
- Userspace: Programma's, fork-implementatie en gemeten limieten.
- Overig: Troubleshooting, security, Bluetooth setup en changelog.
Geschiedenis, credits en licentie
De oorspronkelijke 0.1-aanpak emuleerde een RISC-V-machine. Het huidige project draait native Xtensa Linux; de oudere aanpak is bewaard in de Git-historie.
Gebouwd op het Xtensa Linux, Buildroot en esp-hosted werk van jcmvbkbc (Max Filippov), en op de firmware van Espressif. Zie NOTICE voor componenten en licenties van derden.
Dit project is gelicentieerd onder de GPLv3 (zie LICENSE). Kernelcode die hier is bijgedragen (drivers/crypto/esp32s3_rsa.c) is GPL-2.0-or-later.
Groetjes,