universalisos/XTENSA_AUDIT.md
Fábio Coutada 059f96c948 docs: add safety-critical evaluation and implementation plans
- HARD_REALTIME_EVALUATION.md: full HRT audit
- MICROKERNEL_*.md: complete architecture targets and implementation plan
- PIKEOS_3LAYER_REPLICATION_PLAN.md: 3-layer replication strategy
- PIKEOS_POSIX_AUDIT.md: POSIX compliance audit
- RTOS_AUDIT.md: RTOS comparison
- XTENSA_AUDIT.md: Xtensa ISA audit
- BIBLIOGRAPHY_SAFETY_CRITICAL_HYPERVISOR.md: references
2026-07-15 15:32:05 +01:00

229 lines
11 KiB
Markdown

# Xtensa/ESP32 Integration Audit — UniversalisOS
## ESP-IDF Boot Sequence (Complete)
```
┌─────────────────────────────────────────────────────────────┐
│ 1. ROM Bootloader (0x40000400) │
│ - Reads flash header │
│ - Loads 2nd stage bootloader to IRAM │
│ - Jumps to 2nd stage entry (0x40080644) │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 2. 2nd Stage Bootloader (0x40080400) │
│ - Configures cache, clocks, flash │
│ - Reads partition table │
│ - Finds "factory" app at offset 0x10000 │
│ - Loads app segments to IRAM/DRAM │
│ - Jumps to app entry (0x40080000) │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 3. start_cpu0() — Entry Point │
│ - do_core_init() → core init handlers │
│ - __libc_init_array() → C constructors │
│ - do_secondary_init() → secondary handlers │
│ - esp_startup_start_app() → FreeRTOS │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 4. esp_startup_start_app() │
│ - esp_int_wdt_init() → interrupt watchdog │
│ - esp_crosscore_int_init() → cross-core interrupts │
│ - xTaskCreatePinnedToCore(main_task) → create main task │
│ - vTaskStartScheduler() → start FreeRTOS │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 5. xPortStartScheduler() — FreeRTOS Port │
│ - portDISABLE_INTERRUPTS() │
│ - _xt_coproc_init() → co-processor setup │
│ - vPortSetupTimer() → configure CCOUNT or SYSTIMER │
│ - port_xSchedulerRunning[core] = 1 │
│ - xthal_window_spill() → clear window registers │
│ - _frxt_dispatch → first context switch │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 6. First Task Execution │
│ - main_task() runs │
│ - User's main() is called │
└─────────────────────────────────────────────────────────────┘
```
## Xtensa Context Frame (XtExcFrame)
From `xtensa_context.h`:
```c
STRUCT_FIELD(long, 4, XT_STK_EXIT, exit) /* exit point for dispatch */
STRUCT_FIELD(long, 4, XT_STK_PC, pc) /* return PC */
STRUCT_FIELD(long, 4, XT_STK_PS, ps) /* return PS */
STRUCT_FIELD(long, 4, XT_STK_A0, a0)
STRUCT_FIELD(long, 4, XT_STK_A1, a1) /* stack pointer */
STRUCT_FIELD(long, 4, XT_STK_A2, a2)
STRUCT_FIELD(long, 4, XT_STK_A3, a3)
STRUCT_FIELD(long, 4, XT_STK_A4, a4)
STRUCT_FIELD(long, 4, XT_STK_A5, a5)
STRUCT_FIELD(long, 4, XT_STK_A6, a6)
STRUCT_FIELD(long, 4, XT_STK_A7, a7)
STRUCT_FIELD(long, 4, XT_STK_A8, a8)
STRUCT_FIELD(long, 4, XT_STK_A9, a9)
STRUCT_FIELD(long, 4, XT_STK_A10, a10)
STRUCT_FIELD(long, 4, XT_STK_A11, a11)
STRUCT_FIELD(long, 4, XT_STK_A12, a12)
STRUCT_FIELD(long, 4, XT_STK_A13, a13)
STRUCT_FIELD(long, 4, XT_STK_A14, a14)
STRUCT_FIELD(long, 4, XT_STK_A15, a15)
STRUCT_FIELD(long, 4, XT_STK_SAR, sar)
STRUCT_FIELD(long, 4, XT_STK_EXCCAUSE, exccause)
STRUCT_FIELD(long, 4, XT_STK_EXCVADDR, excvaddr)
/* For CALL0 ABI: exit = _xt_user_exit, PS = PS_UM | PS_EXCM */
```
## Stack Frame Layout (for CALL0 ABI)
```
HIGH ADDRESS
┌─────────────────────────┐
│ Extra Storage (CPSA) │ ← XT_STK_EXTRA
├─────────────────────────┤
│ XtExcFrame (interrupt │ ← Task's SP points here
│ frame on stack) │
│ [+0] exit = _xt_user_exit
│ [+4] pc = task entry
│ [+8] ps = PS_UM | PS_EXCM
│ [+12] a0 = 0
│ [+16] a1 = SP + XT_STK_FRMSZ
│ [+20] a2 = pvParameters
│ ...
│ [+76] a15
│ [+80] sar
│ [+84] exccause
│ [+88] excvaddr
├─────────────────────────┤
│ Base Save Area │
├─────────────────────────┤
│ Task Stack │
└─────────────────────────┘
LOW ADDRESS
```
## What We Got Wrong
### 1. Stack Frame Layout
**ESP-IDF uses `XtExcFrame` structure with `exit` field pointing to `_xt_user_exit`**
- `frame->exit = _xt_user_exit` (exception exit dispatcher)
- `frame->pc = task entry point`
- `frame->ps = PS_UM | PS_EXCM` (user mode, EXCM disabled)
- `frame->a1 = SP + XT_STK_FRMSZ` (top of stack frame)
- `frame->a2 = pvParameters` (task argument for CALL0)
**Our code uses simple 16-word frame without `exit` field**
### 2. Interrupt Handler Flow
**ESP-IDF flow:**
```
Hardware interrupt → _xt_int_enter → saves context →
calls C handler → _xt_int_exit → checks for reschedule →
restores context → rfe
```
**Our code:**
```
Hardware interrupt → saves context → calls handler →
restores context → rfe
```
Missing: `_xt_context_save/restore`, interrupt nesting tracking, reschedule check
### 3. First Dispatch
**ESP-IDF:** `xPortStartScheduler()``_frxt_dispatch` (assembly)
- Sets `port_xSchedulerRunning[core] = 1`
- Calls `_frxt_dispatch` which does the first context switch
**Our code:** `uos_sched_start()``uos_port_dispatch_first()` (C function)
- Simpler but missing: window spill, co-processor init, interrupt nesting
### 4. Timer Configuration
**ESP-IDF uses two options:**
1. **CCOUNT (core timer)**`CONFIG_FREERTOS_SYSTICK_USES_CCOUNT`
- Uses internal timer 0 or 1
- `_frxt_tick_timer_init()` sets up CCOMPARE0
- Interrupt at level 1
2. **SYSTIMER**`CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER`
- Uses SYSTIMER peripheral
- `SysTickIsrHandler()` handles the interrupt
- Periodic mode with alarm
**Our code:** Direct CCOUNT manipulation
- Missing: interrupt allocation via `esp_intr_alloc()`
- Missing: proper timer interrupt handler
## UniversalisOS Integration Strategy
### Replace Points
| ESP-IDF Component | Our Equivalent | Status |
|---|---|---|
| `app_startup.c` | `esp32_integration.c` | ✅ Created |
| `startup.c` | `startup.S` | ⚠️ Needs fix |
| `port.c` | `uos_port_context.S` | ⚠️ Needs fix |
| `portasm.S` | `esp32_vectors.S` | ⚠️ Needs fix |
| `port_systick.c` | `esp32_timer.c` | ❌ Not created |
### What Needs to Change
1. **Stack frame must include `exit` field** — This is how FreeRTOS returns from exception
2. **Interrupt handlers need `_xt_context_save/restore`** — Save/restore all registers properly
3. **Timer must use `esp_intr_alloc()`** — Proper interrupt allocation
4. **First dispatch must use `_frxt_dispatch`** — Assembly context switch, not C function
5. **VECBASE must be set early** — Before any interrupts fire
### Key Functions to Implement
```c
/* Our integration layer needs: */
void esp32_app_entry(void) {
/* 1. Set VECBASE (must be first!) */
/* 2. Disable WDT */
/* 3. Configure UART for debug */
/* 4. Init interrupt controller */
/* 5. Init timer (CCOUNT or SYSTIMER) */
/* 6. Call uos_init() */
/* 7. Create tasks */
/* 8. Start scheduler */
}
/* Context switch needs: */
void _frxt_dispatch(void); /* First dispatch — assembly */
void _frxt_int_enter(void); /* Interrupt entry — assembly */
void _frxt_int_exit(void); /* Interrupt exit — assembly */
/* Timer needs: */
void vPortSetupTimer(void); /* Configure CCOUNT/SYSTIMER */
void _frxt_tick_timer_init(void); /* CCOUNT timer init */
```
## Files to Study Further
1. `components/esp_system/startup.c` — Boot sequence ✅ Studied
2. `components/freertos/app_startup.c` — FreeRTOS startup ✅ Studied
3. `components/freertos/port_systick.c` — Timer config ✅ Studied
4. `components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c` — Port layer ✅ Studied
5. `components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/portasm.S` — Context switch ✅ Studied
6. `components/xtensa/include/xtensa_context.h` — Context frame ✅ Studied
7. `components/xtensa/` — Xtensa HAL and runtime
8. `components/bootloader/` — 2nd stage bootloader
## Next Steps
1. Fix stack frame to include `exit` field
2. Implement proper interrupt handlers with `_xt_context_save/restore`
3. Implement `_frxt_dispatch` for first context switch
4. Implement `vPortSetupTimer` for proper timer configuration
5. Test on ESP32 QEMU with flash image approach