- 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
229 lines
11 KiB
Markdown
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
|