docs: AGENTS.md + strategy doc — U-Boot é obrigatório, GDB stub mandatório em todos os testes
AGENTS.md: - Rule 2 strengthened: U-Boot é compromisso firme com lista de tasks - New Rule 10: GDB/GDB stub obrigatório em todos os testes (QEMU + HW) - Architecture Reality Check: added ESP32+U-Boot entry - Verification Workflow: completo com comandos GDB para cada target docs/esp32-mcuboot-uboot-strategy.md: - Chain B (U-Boot) agora é MANDATÓRIA para todos os targets - Chain A é stepping stone de desenvolvimento apenas - Chain C (bootstub) será eliminada - Open decisions marcadas como resolvidas - Tabela de viabilidade: Xtensa passou de 🔴 risky para 🟡 commitment
This commit is contained in:
parent
533f794dae
commit
b5b29759af
2 changed files with 102 additions and 38 deletions
61
AGENTS.md
61
AGENTS.md
|
|
@ -34,6 +34,18 @@ Safety-critical type-1 hypervisor (ARMv7 primary, AArch64/RISC-V in progress) im
|
|||
|
||||
2. **A cadeia de boot do ESP32 é ROM Boot → MCUboot (1st stage) → U-Boot (2nd stage) → UniversalisOS µ-kernel.** NÃO removas o U-Boot desta cadeia. NÃO saltes etapas. NÃO mudes o flash layout. Se algo não funciona, investiga PORQUÊ dentro da cadeia existente — não a contornes.
|
||||
|
||||
**Compromisso firme com U-Boot:** Estamos a PORTAR o U-Boot para Xtensa ESP32 (não-mainline). Isto inclui:
|
||||
- Fix da consola (UART DM_SERIAL, garbled output)
|
||||
- Fix dos exception vectors (discarded no linker)
|
||||
- Fix da cache/MMU (init não pode resetar as mappings do MCUboot)
|
||||
- Driver SPI flash, partition table parser, env backend, WDT, GPIO, timer (CCOMPARE0)
|
||||
- Suporte IROM (flash-XIP) com mapeamento DROM para l32r
|
||||
- ESP32 partition table parser (formato 0x50AA)
|
||||
- bootelf para carregar UOS images
|
||||
- Device Tree (DTS para ESP32)
|
||||
|
||||
Este é um fork não-mainline — todo o trabalho fica em `portugalfuturista/universalis-uboot`. Ver `docs/esp32-mcuboot-uboot-strategy.md` para o plano detalhado.
|
||||
|
||||
3. **O ESP32 usa o ESP HAL da Espressif.** Não substitutes por raw registers sem autorização. O HAL está em `rtos_ref/hal_espressif/`.
|
||||
|
||||
4. **Antes de mudar qualquer ficheiro, pergunta: "Este ficheiro faz parte explícita da tarefa?"** Se não, não o touches. Drive-by refactors são proibidos.
|
||||
|
|
@ -48,6 +60,14 @@ Safety-critical type-1 hypervisor (ARMv7 primary, AArch64/RISC-V in progress) im
|
|||
|
||||
9. **Se o utilizador disser PARA, PÁRA.** Não faças mais mudanças. Não "fixes" sem permissão. Espera instruções.
|
||||
|
||||
10. **GDB/GDB STUB É OBRIGATÓRIO EM TODOS OS TESTES.** Sempre que correres QEMU ou testes em hardware (especialmente ESP32), deves usar GDB com GDB stubs. Isto aplica-se a:
|
||||
- **QEMU:** `qemu-system-* -s -S` (GDB stub na porta 1234). O GDB attach é feito com `target remote :1234`.
|
||||
- **ESP32 hardware:** O GDB stub integrado (em `microkernel/ports/esp32/uos_gdbstub.c`) é ativado pelo `break 0,0` em `_start`. Comunicação via UART0 a 115200 usando o protocolo RSP (Remote Serial Protocol).
|
||||
- **Bootloader bring-up:** Usar GDB para single-step, ler registos, e verificar estado em cada etapa da cadeia de boot.
|
||||
- **Exceções e crashes:** Use GDB para inspecionar o estado no momento da falha — não confies apenas em output UART.
|
||||
- A GDB stub deve estar sempre compilada (`-DUOS_GDBSTUB=1` já está no Makefile para TARGET=esp32).
|
||||
- O ficheiro `microkernel/gdb-connect.sh` contém o comando GDB para attach.
|
||||
|
||||
## Critical Build Gotchas
|
||||
|
||||
- **Default build target is RISC-V**, not ARM. The Makefile defaults to `ARCH=riscv PLATFORM=polarfire`.
|
||||
|
|
@ -131,6 +151,7 @@ qemu-system-riscv64 -machine microchip-icicle-kit -smp 5 -m 2G -nographic \
|
|||
- **ARMv7 + qemu-arm-virt**: Boots, produces UART output, runs scheduler/IPC/HM demos end-to-end. This is the target you should test against.
|
||||
- **AArch64 + qemu-aarch64-virt**: EL2 hypervisor track. Builds clean (0 linker warnings) and boots to a full banner at EL2 — but **only** when QEMU is run with `virtualization=on` (see gotcha above). MP0 bring-up reaches the scheduler, `eret` into the first task works, and **timer-driven preemption is live** (the former U3 open item is resolved): the HV tick uses the EL2 **physical** timer CNTHP on **PPI 26** (`timer.cpp` → `gicv3_irq_enable(QEMU_TIMER_EL2_PHYS_PPI)`), `el2_irq_handler` (el2_trap.cpp) acks INTID 26 / re-arms CNTHP_CVAL / EOIs / runs `sched_tick()`, and `el2_irq_entry` (exceptions.S) performs the deferred preemptive switch via `g_need_reschedule` + the cur/next trap-frame pointers. Verified by boot: A/B tasks interleave in runs of 1–3 ticks at ~50/50. (PPI 27 enabled on MP1 is the *guest's* virtual timer via the vGIC — intentional, not the HV tick.)
|
||||
- **RISC-V + polarfire (Icicle Kit)**: Self-contained S-mode port under `kernel/src/arch/riscv/`. Builds clean (`make ARCH=riscv PLATFORM=polarfire`) and boots to banner + `Partition 0/1 says hello!` for `-smp 2..5` (QEMU rejects `-smp 1`: min 2 CPUs; `-bios none` is BSP-only regardless of `-smp`). Two boot modes: `-bios none` (M-mode trampoline, BSP only — verifiable today) and the HSS-payload firmware path (`UOS_BOOT=firmware` + `config/icicle_hss_payload.yaml`, releases all 5 harts + SBI timer/IPI/HSM — needs Microchip `hss-payload-generator`). Timer is gated on `__uos_has_sbi`: SBI `set_timer` under firmware, direct CLINT under `-bios none`. `-bios none` is BSP-only by construction (secondaries held in reset; `riscv_cpu_wake_secondary()` is a no-op when `__uos_has_sbi==0`); the HSS path is the intended route to real SMP + preemptive ticks.
|
||||
- **ESP32 + U-Boot (em curso)**: Boot chain ROM → MCUboot @ 0x1000 → U-Boot @ slot0 → UOS. MCUboot funciona e carrega U-Boot. U-Boot inicia mas consola está garbled. Estamos a portar drivers ESP32 (cache, UART, SPI flash, partition table, timer, GPIO, WDT) e a fixar os exception vectors para o fork Xtensa. Ver `docs/esp32-boot-chain-design.md` e `docs/esp32-master-plan.md` para o plano completo de 5 fases.
|
||||
|
||||
When making changes, **build and boot ARMv7** to verify. Do not assume changes to shared headers compile on all three arches unless you test each.
|
||||
|
||||
|
|
@ -167,10 +188,44 @@ Do **not** mix Universalisos work with other PortugalFuturista projects (DocSpac
|
|||
|
||||
## Verification Workflow
|
||||
|
||||
### Always use GDB/GDB stub
|
||||
|
||||
Every test — QEMU or hardware — must be run with GDB attached:
|
||||
|
||||
**QEMU targets (ARMv7, AArch64, RISC-V):**
|
||||
```bash
|
||||
# Terminal 1: start QEMU with GDB stub
|
||||
qemu-system-arm -M virt -cpu cortex-a15 -m 512M \
|
||||
-nographic -s -S -kernel build/armv7/qemu-arm-virt/universalisos.elf
|
||||
|
||||
# Terminal 2: attach GDB
|
||||
gdb-multiarch -ex "target remote :1234" \
|
||||
-ex "hb _start" -ex "c" \
|
||||
build/armv7/qemu-arm-virt/universalisos.elf
|
||||
```
|
||||
|
||||
**ESP32 hardware (via UART GDB stub):**
|
||||
```bash
|
||||
# ESP32 boots, break 0,0 fires, GDB stub sends T05 on UART
|
||||
# Attach with xtensa-esp32-elf-gdb:
|
||||
xtensa-esp32-elf-gdb -ex "target remote /dev/ttyACM0" \
|
||||
-ex "set serial baud 115200" \
|
||||
microkernel/build/esp32/universalisos.elf
|
||||
```
|
||||
|
||||
**ESP32 hardware (via JTAG, future):**
|
||||
```bash
|
||||
openocd -f interface/esp_usb_jtag.cfg -f target/esp32.cfg &
|
||||
xtensa-esp32-elf-gdb -ex "target remote :3333" microkernel/build/esp32/universalisos.elf
|
||||
```
|
||||
|
||||
### Build verification
|
||||
|
||||
There is no unit-test framework, linter, or typechecker. Verification is:
|
||||
|
||||
1. `make ARCH=armv7 PLATFORM=qemu-arm-virt` — must compile clean.
|
||||
2. Boot in QEMU — must reach UART banner and complete demo sequence (scheduler slots, IPC, shared memory, health monitoring, preemption).
|
||||
3. Check for unexpected hangs or missing demo sections in output.
|
||||
2. Boot in QEMU with GDB attached — must reach UART banner and complete demo sequence (scheduler slots, IPC, shared memory, health monitoring, preemption).
|
||||
3. Verify via GDB that all expected symbols are at correct addresses.
|
||||
4. Check for unexpected hangs or missing demo sections in output.
|
||||
|
||||
If a change touches shared headers, verify it does not break `ARCH=aarch64` or `ARCH=riscv` builds as well.
|
||||
If a change touches shared headers, verify it does not break `ARCH=aarch64` or `ARCH=riscv` or `TARGET=esp32` builds as well.
|
||||
|
|
|
|||
|
|
@ -14,12 +14,14 @@
|
|||
This is the single fact that shapes the whole design.
|
||||
|
||||
| SoC family | Arch | U-Boot support | Viability as a loader |
|
||||
|---|---|---|---|
|
||||
||---|---|---|---|
|
||||
| ESP32 / ESP32-S2 / ESP32-S3 | Xtensa LX6/LX7 | **Experimental, not mainline** | 🟡 commitment: estamos a portar |
|
||||
| ESP32-C3 / C6 / H2 | RISC-V | **Mainline** (since ~2023) | ✅ real |
|
||||
| ESP32-P4 | RISC-V | Partial / under review | 🟡 |
|
||||
| ESP32 / ESP32-S2 / ESP32-S3 | Xtensa LX6/LX7 | **Experimental, not mainline** | 🔴 risky |
|
||||
| ESP32-C5 | RISC-V | not upstream | 🔴 |
|
||||
|
||||
**Decisão do Maestro Fabio:** U-Boot em Xtensa ESP32 é uma realidade — não saltamos, não simplificamos. Estamos a fazer um fork Xtensa do U-Boot. Isto significa portar drivers, fixar cache/MMU, excepções, e todo o ecossistema (partition table, spi flash, env, GPIO, timer, WDT). O trabalho vive em `portugalfuturista/universalis-uboot`.
|
||||
|
||||
MCUboot, by contrast, **supports every Espressif target** (Xtensa + RISC-V) via `boot/espressif`. So:
|
||||
|
||||
- **"MCUboot only" works on ALL targets** — it is the proven Zephyr path.
|
||||
|
|
@ -32,23 +34,26 @@ MCUboot, by contrast, **supports every Espressif target** (Xtensa + RISC-V) via
|
|||
## 2. The three candidate chains
|
||||
|
||||
```
|
||||
CHAIN A — Zephyr-proven, RECOMMENDED (all targets)
|
||||
CHAIN A — MCUboot → UOS (development/test stepping stone, Xtensa only)
|
||||
ROM (mask, fixed)
|
||||
→ MCUboot @ 0x1000 (2nd-stage, esptool elf2image 0xE9 format)
|
||||
validates signature, swap/scratch, picks primary
|
||||
→ UOS app @ slot0 (mcuboot-signed, esp_image_load_header 0xace637d3)
|
||||
esp_loader.c copies IRAM/DRAM segs, jumps to entry
|
||||
*** Use Chain A for GDB stub bring-up and µ-kernel development only ***
|
||||
*** Chain B is the FINAL target for all Espressif targets ***
|
||||
|
||||
CHAIN B — MCUboot + U-Boot (RISC-V only: C3/C6/H2)
|
||||
CHAIN B — MCUboot → U-Boot → UOS (MANDATORY, ALL ESPRESSIF TARGETS)
|
||||
ROM → MCUboot @ 0x1000 → U-Boot @ slot0 → UOS (loaded by U-Boot)
|
||||
U-Boot = the mcuboot "application image"; UOS = a payload U-Boot chainloads.
|
||||
Adds a full U-Boot build + a UOS load command. Heavy; only for dev/debug richness.
|
||||
No shortcuts. No skipping U-Boot. Full boot chain verification required.
|
||||
- Xtensa: fork não-mainline em porting (consola, cache, vectors, drivers)
|
||||
- RISC-V: mainline, mais fácil — fazer depois do Xtensa
|
||||
|
||||
CHAIN C — our in-tree bootstub (already QEMU-proven, Xtensa)
|
||||
CHAIN C — in-tree bootstub (QEMU-only debugging, NOT for HW)
|
||||
ROM → bootstub @ 0x1000 (own minimal 2nd-stage, watches-off + MMU map)
|
||||
→ UOS app @ 0x10000 (plain 0xE9 image, mcuboot-style bounds-checked loader)
|
||||
Simplest. No signature/OTA. Good for bring-up; lacks secure boot + DFU.
|
||||
```
|
||||
*** QEMU only. Never flash to hardware. ***
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -148,31 +153,33 @@ RISC-V U-Boot port + a UOS load command.
|
|||
|
||||
---
|
||||
|
||||
## 7. Recommended strategy (phased)
|
||||
## 7. Estratégia (mandatada por Maestro Fabio)
|
||||
|
||||
**Phase 0 — Pin the layout (do first, blocks real HW).**
|
||||
**Fase 0 — Pin the layout (do first, blocks real HW).**
|
||||
- Pick ONE partition scheme. Generate it with `esp_genpartition.py` for the
|
||||
target flash size; record `slot0` offset. Keep Zephyr-compatible offsets so
|
||||
we can cross-check against a known-good `west build --sysbuild` if needed.
|
||||
target flash size; record `slot0` offset.
|
||||
|
||||
**Phase 1 — Lock Chain A for ALL targets (secure-boot baseline).**
|
||||
- Build `mcuboot/boot/espressif` for the target (`-DMCUBOOT_TARGET=esp32[c3|s3|…]`).
|
||||
- Package with `esptool elf2image` → `mcuboot.bin @ 0x1000`.
|
||||
- Build UOS app; sign with `imgtool` + prepend `esp_image_load_header`
|
||||
(`0xace637d3`); flash at slot0.
|
||||
- Verify on QEMU (esp32/esp32s3) then real HW. Add secure-boot + flash-enc
|
||||
Kconfig once baseline boots.
|
||||
**Fase 1 — Chain A funcional (MCUboot → UOS, stepping stone).**
|
||||
- Build MCUboot/boot/espressif for the target.
|
||||
- Build UOS app; sign with imgtool + prepend `esp_image_load_header`.
|
||||
- Flash at slot0. Verify in QEMU + HW.
|
||||
- **GDB stub mandatório em todos os testes** (break 0,0 → T05 via UART).
|
||||
|
||||
**Phase 2 — Keep Chain C (bootstub) as the fast QEMU/dev path.**
|
||||
- It already works. Keep it for iteration; do not flash it to secure-boot HW.
|
||||
**Fase 2 — Chain B (MCUboot → U-Boot → UOS, OBRIGATÓRIO).**
|
||||
- Portar U-Boot para Xtensa ESP32 no fork `universalis-uboot`.
|
||||
- Fix consola garbled (Phase 1 do master plan: UART DM_SERIAL, cache/MMU, vectors).
|
||||
- ESP32 drivers (SPI flash, partition table, env, GPIO, timer, WDT).
|
||||
- bootelf / load command para carregar UOS image.
|
||||
- Auto-boot via CONFIG_BOOTCOMMAND.
|
||||
- Chain A continua a existir como GDB-stub development path.
|
||||
|
||||
**Phase 3 — Chain B (MCUboot → U-Boot → UOS) ONLY for RISC-V (C3/C6/H2).**
|
||||
- Only if a U-Boot pre-OS shell is actually wanted (debug/ provisioning).
|
||||
- Otherwise skip — U-Boot adds ~200 KB + a second image format for no HV gain.
|
||||
**Fase 3 — Chain C (bootstub) eliminated.**
|
||||
- Bootstub era para QEMU. Com Chain A funcional, não precisamos de bootstub.
|
||||
- Remover `microkernel/ports/esp32/bootstub*` após Chain A+B estarem estáveis.
|
||||
|
||||
**Phase 4 — SMP / APP-CPU bring-up.**
|
||||
- Reuse `CONFIG_ESP_MULTI_PROCESSOR_BOOT` path (`start_cpu1_image`) — already
|
||||
present in both mcuboot and our `uos_loader.h` weak hook.
|
||||
**Fase 4 — SMP / APP-CPU bring-up (MCUboot + U-Boot).**
|
||||
- Reuse `CONFIG_ESP_MULTI_PROCESSOR_BOOT` path (`start_cpu1_image`) no MCUboot.
|
||||
- U-Boot eventualmente carrega as duas CPUs.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -188,15 +195,17 @@ RISC-V U-Boot port + a UOS load command.
|
|||
|
||||
---
|
||||
|
||||
## 9. Open decision (blocks Phase 1/3)
|
||||
## 9. Open decisions (resolvidas)
|
||||
|
||||
1. **Target SoC(s)** — Xtensa (ESP32/S3) and/or RISC-V (C3/C6/H2)? This decides
|
||||
whether Chain B (U-Boot) is even on the table.
|
||||
2. **Is U-Boot actually required**, or was "mcuboot+uboot" shorthand for
|
||||
"a proper verified boot chain"? If the latter, Chain A alone satisfies it
|
||||
and is the Zephyr-proven path.
|
||||
3. **Secure boot / flash encryption** needed at first boot, or bring-up first
|
||||
then enable?
|
||||
1. **Target SoC(s)** — Xtensa (ESP32/S3) é o alvo primário. RISC-V (C3/C6/H2)
|
||||
depois do Xtensa. Chain B (U-Boot) para TODOS.
|
||||
2. **U-Boot é obrigatório, não opcional.** "mcuboot+uboot" não era shorthand —
|
||||
é a arquitetura de boot final. Chain A (MCUboot → UOS) é stepping stone
|
||||
de desenvolvimento apenas.
|
||||
3. **Secure boot / flash encryption** — primeiro bring-up das cadeias,
|
||||
depois ativar segurança.
|
||||
|
||||
Ver docs/esp32-master-plan.md para o plano detalhado de 5 fases do U-Boot.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue