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

14 KiB
Raw Permalink Blame History

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 0x8018a780x8018a7c).
  • 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 (f8bd0a4af3f730b8, 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 (popbx 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 (blxbl, как остальные). 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). blob (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.