Files
2026-09-14 00:34:52 +00:00

209 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SBL1 BringUp — статус (2026-09-07)
Цель: выполнить оригинальный SBL1 (RM-1127) в QEMU до баннера `SBL1, Start` на UART.
## Что работает
- Машина `saimaa` (`qemu/saimaa.c`, QEMU 8.2.2 на zern): Cortex-A7×4,
DDRLOW/OCIMEM/IMEM/SMEM/RPM/mystrom, UARTDM-стаб, SDHCI+eMMC 8GiB,
VFP/NEON вкл (CPACR+NSACR+FPEXC), null-page trap, fault-tolerant векторы.
- eMMC-образ с реальной GPT RM-1127 (33 раздела, `tools/mkimage.py`).
- FFU-разбор (`tools/ffu_parse.py`, RKH/MSM/OEM/PlatformID, GPT33).
- `.edp`-нарезка ELF (`tools/edp_carve.py`, 10 образов, `fw/sbl/` в .gitignore).
- `tools/sbl_patch.py` — воспроизводимо генерирует img0_bl..b10.elf из img0.elf.
- Стаблеты компенсации pop (`qemu/stublets.S` → 0x08062000): чинят SP,
повторы попадают в те же слоты. Слоты в `saimaa_machine_init`.
- Указательный maze (`0x08062100`) + scratch (`0x08070000`) для struct-цепочек.
- Трассировка: `-d in_asm,cpu,guest_errors,int` + GDB (только чтение! `continue`
в batch виснет — использовать `interrupt`+`detach`).
## Найденное
- `sbl_main` (Thumb) = `0x802f63e`, баннер `SBL1, Start` зовётся из `0x802f6ae`
через `bl 0x8016320`. Poll IMEM `0x08600944` != `0x53444247` (выходит при 0).
- В `.edp`-копии вызовы `blx imm` ведут в Thumb-код (на HW тоже; QEMU уходит
в ARM → патчим в `bl`, см. sbl_patch.py). Часть вызовов off-by-2/4
(таблица `0x8013aa8`, `bl 0x8018a78``0x8018a7c`).
- FFU-копия SBL1 — другая сборка тех же исходников (структура та же, `bl`
вместо `blx`, полные фреймы). Используется как эталон.
- PBL-контекст (r4-r12) фабрикуется машиной; таблицы собираются частично.
- Текущий фронтир (b10 + canonical scaffold): ~20 уровней init, падеж
в районе `0x80079xx` (див switch по мусорным флагам) — см. свежий трейс.
## Запуск
```
./tools/sbl_patch.py fw/sbl/img0.elf /tmp/p
~/qemu-src/qemu-8.2.2/build/qemu-system-arm \
-M saimaa,sbl1=/tmp/p/img0_b10.elf,sblmain=0x802f63f -m 512 \
-display none -monitor none -serial file:/tmp/uart.log \
-drive file=/tmp/emmc-test.img,if=sd,format=raw
```
## TODO
1. Добить баннер (см. свежий in_asm-хвост).
2. Заменить стаблеты настоящим PBL (нужны дампы с живого тела!).
3. UEFI (img3, EDK2) — отдельный фронт после SBL1.
## b18: S7 и цикл delay-helper (2026-09-12)
Механизм зацикливания (b17, доказан Unicorn-harness `tools/sbl_uni.py`):
- sbl_main → delay-функция `0x8013B78` (256-итераций table-walk, `bl 0x8017AF4`
каждую итерацию) → b14 (`0x8017AFC: b.w 0x8005B9E`) → helper `0x8005BB0`
→ выход `ldr pc,[sp],#0x14` (0x8005BCA) → S3-слот (0x8013BA5, рестарт).
- Эпилог delay (`0x8013BAC: pop {r3-r7,pc}`) снимает 0x18 без push; каждый
S3-рестарт съедает 0x18 живого стека. Маршрут: слоты → fill (STUBV →
pop pc = maze) → pristine IMEM (нули → null-jump → hook_null → maze →
stale lr) → переполнение IMEM (0x8610008).
- Heap SBL (stm в 0x8006684) затирает maze/S6/banner (0, 0x7a, STUBV).
QEMU: dstub-overlay `[0x08006B80,0x08006C50)` (read = снапшот ELF+стабы,
write = игнор). Uni: deferred-restore guard (MEM_WRITE-хук срабатывает
ДО записи, restore надо делать в hook_code!).
- Maze-blob: `movs r0,#0; lsr ip,lr,#24; cmp #8; bne hang; bx lr`
(возврат 0 только для lr из DDRLOW 0x08..., иначе hang).
Фикс b18: патч BAC (`f8bd0a4a``f3f730b8`, `b.w S7`) + S7-стаблет
(52B @ 0x08006C10): `cmp r4,#0xff` → iterate (`0x8013BA5`) или done
(restore r4/r5/sl/fp, возврат в sbl_main `0x802f681`). BAE-путь
(`[r7]==2`) принесён в жертву (r7=0, недостижим).
Фронтир b18: sbl_main возвращается, новый код `0x801Bxxx`
(`strb [r7,#2]`-паттерн, b17-NOP на 0x801B71E), падеж pop'ом пустого
стека у верха IMEM — следующий фронт.
## b18 parity (QEMU == uni, 2026-09-12)
- QEMU поправлен до паритета: dstub-overlay + vec-maze для Thumb
(null-fetch исполняет maze и возвращается) + убран висячий префикс
bl (bogus odd store -> alignment fault, DFAR=0x8006B8D).
- QEMU b18 доходит до того же фронтира, что uni b18 (38961 инстр.):
`0x801Bxxx`, r1=0x80522A4, r2/r3=STUBV, lr=0x801B73F, sp марширует
к верху IMEM. Смерти чуть различаются по таймингу (uni: read
0x8610000; QEMU: null-jump → maze-hang c lr-top 0x80), регион тот же.
- Следующий фронт (оба): лабиринт `0x801B6xx` (логгер, r7=0/r4=0,
pop пустого стека). Кандидаты: S8-стаблет, таблица логгера.
## b21-b23: логгер, S9, S10, rollback (2026-09-12)
- Логгер `0x8034810` = голый `pop.w 0x28` без push (жрал стек) → S8:
вход → `bx lr` (b21). Возврат игнорируется (callers ставят r0=0).
- Лабиринт `0x801B6A0`: счётчик `[r4]++` + `pop.w` на пустых фреймах
(r4/r7=STUBV из fill) → S9 (b22): `[sp+0x14]` ненулевой → исходный
pop; ноль → restore r0/r4/r5/sl/fp + **reset sp=0x085FFF00** +
прыжок в sbl_main `0x802f69d` через ip (без литералов).
- Rollback `boot_rollback_version.c:580` (query всегда `0x302E`) → NOP NOP
(b22, возврат игнорируется). Query зовёт `*table[0x080528D0]` (нули) →
фабрикация: poke STUBV (maze вернёт 0 = версии OK) (b23).
- Rollback выходил боком в helper-mid (`pop{r4,pc}` без push) → S10 (b23):
`movw/movt ip + bx ip` в sbl_main `0x802f6a3`.
- b23: 2M инстр. без падений (sp здоров), sbl_main идёт дальше
(`0x80164C4`-subtree → прыжок в OCIMEM-нули `0x222F84` — фронт PBL-данных).
QEMU-паритет: R15=0x223000, sp=0x85FFF00, lr=0x80164CB — там же.
## b24: world-switch stub, clock S11 (2026-09-12)
- Диспетчер (`0x80164C4`-subtree) зовёт ARM jump-table `0x8007158`
(`ldr pc`), та — в OCIMEM-трамплин world-switch `0x221EF8`
(ARM: save regs, `cps MON`, `mrc`, `ldr sp/pc` из PBL-таблиц
`[0x221F6C]=0x223620`/`[0x221F70]=0x223930` → вызов TZ; TZ не загружен).
Вход получается в Thumb → b24-стаб (4B `movs r0,#0; bx lr`):
возврат 0 в диспетчер (TZ deferred). Перезаписывает голову ARM'а
(восстановимо из ELF).
- Дальше: clock-fn `0x800E960` (udiv-подсчёты) с голым выходом
`pop{r4,pc}` (без push, tail-chain через NOP-идиому) → S11 (b24):
вход → `bx lr` (lr = брошенный-но-валидный `0x80076CD`).
- Poll `[0x73A100]` (lsls#29+bpl = проверка bit2!): SBL только читает →
фабрикация bit2=1 (b24 scaffold, обе стороны).
- `blx #0x8006964` в файловые нули паддинга (PBL scratch) → S12v2 (b25
scaffold, ARM! т.к. blx-imm на чётный): preset ip=S16 + ACK bit1
`[0x73A100]` (side effect для poll#2) + `bx lr`. Литерал `[0x8006980]`.
- Helper-pop `0x8007B66` читает scratch (счётчики 0-4 вместо pushed lr,
фреймы съедены null-циклами) → S16v2 (b25 smart): B66 (`pop``bx ip`,
2B) → S16 проверяет ip (odd + top 8 = legit pushed-lr → `bx ip`;
иначе default: restore r7, прыжок `0x8007779`). S12v3 грузит ip из
`[sp+4]` (pushed lr) + ACK bit1. B66-патч в ELF (b25), S12/S16 в scaffold.
## b26: S17 safe-logger (2026-09-13)
- S8 (`bx lr`) гасил весь init-лог (UART пуст by design) вслепую.
S17 (50B @0x08006CF0): печать r1-строки в UARTDM-TF, только если r1
в rodata `[0x804B800,0x8058000)` (wild-указатели скипаются), затем
pop-return (без leak'а, возврат игнорируется). Логгер `0x8034810`
(`pop.w` 4B) → `b.w S17`. Видимость прогресса вместо счёта инстр.
## b27: poll re-init skip (2026-09-13)
- Poll-fn `0x8007748`: `cbz r6` (r6=2 константа caller'а, никогда 0) →
вечный re-init (`movs r4,#0`, table loop) вместо poll#2-direct.
Патч 2B→2B в `b`. Биты 0,1,2 `[0x73A100]` pref-set (scaffold).
- S16v3: `add sp,#8` перед `bx ip` (снимает helper-фрейм, пропущенный
B66 — un-leak стека вниз).
- S16v4: отбраковка `ip==STUBV` (fill/maze — никогда legit return) →
default вместо возврата в maze (разрыв maze-B66 петли).
- S12v4 (scaffold, без ELF): smart dispatcher в самом S12 (проверка
pushed-lr + ACK + возврат) — S16 больше не нужен в цепочке (остаётся
как fallback).
- S12v5: +restore r7 (peripheral base, S16 dormant) прямо в S12.
## b28: poll-epilogue march kill (2026-09-13)
- Poll-fn входит mid-way (без prologue-push), выходит через
`add sp,#0x1C + pop.w 0x14` (+0x30/проход, пушей нет) → марш вверх
через fill в IMEM-нули → fault на верху. `add sp` → NOP (2B, b28).
Pop читает helper-фреймы (pushed-lr, валидные возвраты).
## b29: S18 poll-epilogue router (2026-09-13)
- b28-NOP убрал только +0x1C; `pop.w 0x14` без пушей всё равно марширует.
S18 (10B @0x08006D22): слепой прыжок в sbl_main `0x802F6A9`
(post-dispatcher). Эпилог `pop.w` (4B) → `b.w S18`.
## b30: epilogue blx (2026-09-13)
- sbl_main дошёл до `0x8016320` (logger-ish, грузит магию "SBL1"),
тот зовёт shared-эпилог `0x8007280` (Thumb!) через `blx`-imm
(чётный → ARM → fault на coprocessor-мусоре). Патч в глобальной
BLX2BL (`blx``bl`, как остальные). r7="SBL1", r0=SMEM — читает
настоящие таблицы!
## b31: logger-epilogue NOP (2026-09-13)
- `0x8016320` зовёт эпилог `0x8007280`, чей pop читает fill/STUBV →
maze → stale-lr в logger-mid → снова blx эпилог (голая взаимная
рекурсия). Вызов скипается (NOP NOP); sbl_main идёт дальше
`0x802F6B0` в свежий код.
## b32: logger-tail b.w (2026-09-13)
- 9-й вызывающий shared-эпилога (`0x8016342 blx`, пропущен статикой):
точный `b.w` (флип съезжает +2). r7="SBL1" магика из настоящих таблиц.
## b33: partition wrap-check (2026-09-13)
- Валидатор партиций (`adds; blo success`, line 0x1FD) ассёртит:
r0+r4 не враппаются (PBL-таблицы нулевые, r4 stale). `blo``b`
(2B). TODO(MainOS): настоящие PBL/SMEM partition tables.
## b34: hang neutralize (2026-09-13)
- Assert-hang `0x8018458` (`b .`) достигается напрямую через
maze-stale-lr (мимо патченного wrap-check). `b .``b success`
(2B, в success-путь).
## b35: sbl_mc hangs (2026-09-13)
- Мёртвая assert-fn `sbl_mc.c:320` (`0x802F9A0-b.`, `0x802F9B2-b.`)
достигается accident'ом (pop-garbage). Оба hang'а → S19
(рестарт post-logger init, bounded table work). 4B `b.w` каждый.
- Урок: полный IMEM-poison ломает IMEM-стек (счётчики читают
0xFFFFFFFF вместо свежих нулей → underflow → wild-pop). Только
tripwire 4B на входе дрейфа `[0x8600000,0x8600004)`.
## b36: assert-entry to S19 (2026-09-13)
- sbl_mc assert-fn входит mid-way (`0x802F9A2`), минуя S19-hang'и.
Вход тоже в S19 (ест ldr + половину movw).
## b37: S20 clock-dispatcher router (2026-09-13)
- Голый clock-диспетчер (`0x800EB80`, без пушей) снимает `pop.w 0x30`
за проход → марш sp к верху IMEM. S20 (34B @0x08006D38):
`[sp+0x2C]` валиден → исходный pop; иначе r0=sl + re-run
(идемпотентная математика). Эпилог `pop.w` (4B) → `b.w S20`.
## b38: S21 table-walker router (2026-09-13)
- Голый table-walker (`0x8007916`, mid-входы без пушей) снимает
`pop.w 0x28`, читает saved-FP (`0x85FFEB0`) как pc → ARM fill-дрейф
(STM-clobbers!). S21 (32B @0x08006D5A): `[sp+0x24]` валиден →
исходный pop; иначе `b.w S19`. Эпилог `pop.w` (4B) → `b.w S21`.
## b37: S20 clock-dispatcher router (2026-09-13)
- Голый clock-диспетчер (`0x800EB80`, без пушей) снимает `pop.w 0x30`
за проход → марш sp к верху IMEM. S20 (34B @0x08006D38):
`[sp+0x2C]` валиден → исходный pop; иначе r0=sl + re-run
(идемпотентная математика). Эпилог `pop.w` (4B) → `b.w S20`.
## maze v2 (2026-09-13)
- Maze с чётным lr уходил в ARM-дрейф (STM-clobbers + IMEM fault).
Maze v2 (24B): возврат только при odd Thumb lr из DDR, иначе hang
громко. Залез на голову S6 (`[B9E,BA4)`, S6 dormant). Vec-maze тоже v2.