From 11facdfb45777e51f62befbf2938768514df24c0 Mon Sep 17 00:00:00 2001 From: SashegDev Date: Mon, 7 Sep 2026 11:40:31 +0000 Subject: [PATCH 1/3] saimaa: direct sbl_main start, SMEM, null-page trap; sbl analysis tools; sbl_main=0x802f63e --- qemu/saimaa.c | 320 +++++++++++++++++++++++++++++++++++++++++++++ tools/sbl_adr.py | 52 ++++++++ tools/sbl_mains.py | 36 +++++ tools/sbl_refs.py | 38 ++++++ 4 files changed, 446 insertions(+) create mode 100644 qemu/saimaa.c create mode 100644 tools/sbl_adr.py create mode 100644 tools/sbl_mains.py create mode 100644 tools/sbl_refs.py diff --git a/qemu/saimaa.c b/qemu/saimaa.c new file mode 100644 index 0000000..11f6994 --- /dev/null +++ b/qemu/saimaa.c @@ -0,0 +1,320 @@ +/* + * Nokia Lumia 550 (Saimaa, MSM8909) emulation — WIP. + * Boots real SBL1 (img0.elf from Emergency Payload) on Cortex-A7. + * Most peripherals are trace-stubs; UART prints to stdio. + */ +#include "qemu/osdep.h" +#include "qemu/units.h" +#include "qapi/error.h" +#include "hw/arm/boot.h" +#include "hw/boards.h" +#include "hw/loader.h" +#include "hw/sysbus.h" +#include "hw/sd/sdhci.h" +#include "hw/sd/sd.h" +#include "hw/char/serial.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-properties-system.h" +#include "elf.h" +#include "qom/object.h" +#include "cpu.h" +#include "qemu/error-report.h" +#include "qemu/log.h" + +/* Real MSM8909 map (subset) */ +#define SAIMAA_OCIMEM_BASE 0x00200000 +#define SAIMAA_OCIMEM_SIZE 0x00100000 +#define SAIMAA_DDRLOW_BASE 0x08000000 +#define SAIMAA_DDRLOW_SIZE 0x00600000 +#define SAIMAA_IMEM_BASE 0x08600000 +#define SAIMAA_IMEM_SIZE 0x00010000 +#define SAIMAA_DDRHIGH_BASE 0x80000000 +#define SAIMAA_DDRHIGH_SIZE 0x20000000 +#define SAIMAA_UART_BASE 0x078AF000 +#define SAIMAA_SDHCI_BASE 0x07824900 +#define SAIMAA_GICD_BASE 0x0B000000 +#define SAIMAA_GICC_BASE 0x0B002000 +#define SAIMAA_NCPUS 4 +#define SAIMAA_SMEM_BASE 0x87C00000 +#define SAIMAA_SMEM_SIZE 0x00800000 + +/* ---- minimal MSM UARTDM stub: TX prints, status always ready ---- */ +#define TYPE_SAIMAA_VEC "saimaa-vec" +#define TYPE_SAIMAA_UART "saimaa-uart" +OBJECT_DECLARE_SIMPLE_TYPE(SaimaaUartState, SAIMAA_UART) + +struct SaimaaUartState { + SysBusDevice parent_obj; + MemoryRegion iomem; + /* WIP: plain host stdout, no chardev dance */ +}; + +/* Low vectors / null-page trap: log faulting PC, return 0. */ +static int saimaa_vec_n; +static uint64_t saimaa_vec_read(void *opaque, hwaddr off, unsigned size) +{ + if (saimaa_vec_n < 24) { + ARMCPU *cpu = ARM_CPU(current_cpu); + uint64_t pc = cpu ? cpu->env.regs[15] : 0; + int th = cpu ? cpu->env.thumb : 0; + fprintf(stderr, "saimaa-vec: %s off=0x%x pc=0x%lx\n", + size == 2 ? "fetch?" : "read", + (unsigned)off, (unsigned long)pc - (th ? 4 : 8)); + saimaa_vec_n++; + } + return 0; +} + +static void saimaa_vec_write(void *opaque, hwaddr off, uint64_t val, + unsigned size) +{ +} + +static const MemoryRegionOps saimaa_vec_ops = { + .read = saimaa_vec_read, + .write = saimaa_vec_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static uint64_t saimaa_uart_read(void *opaque, hwaddr off, unsigned size) +{ + switch (off) { + case 0x08: /* UARTDM_SR: pretend TX ready + empty */ + return 0x000000A0; + case 0x70: /* UARTDM_TF: read returns 0 */ + return 0; + default: + qemu_log_mask(LOG_GUEST_ERROR, + "saimaa-uart: unimp read @0x%x\n", (unsigned)off); + return 0; + } +} + +static void saimaa_uart_write(void *opaque, hwaddr off, uint64_t val, + unsigned size) +{ + SaimaaUartState *s = SAIMAA_UART(opaque); + (void)s; + if (off == 0x70) { /* UARTDM_TF */ + putchar(val & 0xff); + fflush(stdout); + return; + } + qemu_log_mask(LOG_GUEST_ERROR, + "saimaa-uart: unimp write @0x%x = 0x%x\n", + (unsigned)off, (unsigned)val); +} + +static const MemoryRegionOps saimaa_uart_ops = { + .read = saimaa_uart_read, + .write = saimaa_uart_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void saimaa_uart_init(Object *obj) +{ + SaimaaUartState *s = SAIMAA_UART(obj); + SysBusDevice *dev = SYS_BUS_DEVICE(obj); + memory_region_init_io(&s->iomem, obj, &saimaa_uart_ops, s, + "saimaa-uart", 0x1000); + sysbus_init_mmio(dev, &s->iomem); +} + +static void saimaa_uart_realize(DeviceState *dev, Error **errp) +{ + /* backend wired directly in machine init; nothing to check */ +} + +/* ---- machine ---- */ +struct SaimaaMachineState { + MachineState parent_obj; + char *sbl1; + char *emmc; + char *sblmain; /* hex: popped-PC override for PBL trampoline */ +}; +typedef struct SaimaaMachineState SaimaaMachineState; + +#define TYPE_SAIMAA_MACHINE MACHINE_TYPE_NAME("saimaa") +OBJECT_DECLARE_SIMPLE_TYPE(SaimaaMachineState, SAIMAA_MACHINE) + +static void saimaa_machine_init(MachineState *machine) +{ + SaimaaMachineState *sms = SAIMAA_MACHINE(machine); + MemoryRegion *sysmem = get_system_memory(); + int i; + + /* RAM map */ + const struct { const char *n; hwaddr b; hwaddr s; } rams[] = { + { "saimaa.ocimem", SAIMAA_OCIMEM_BASE, SAIMAA_OCIMEM_SIZE }, + { "saimaa.ddrlow", SAIMAA_DDRLOW_BASE, SAIMAA_DDRLOW_SIZE }, + { "saimaa.imem", SAIMAA_IMEM_BASE, SAIMAA_IMEM_SIZE }, + { "saimaa.ddrhigh", SAIMAA_DDRHIGH_BASE, SAIMAA_DDRHIGH_SIZE }, + { "saimaa.smem", SAIMAA_SMEM_BASE, SAIMAA_SMEM_SIZE }, + }; + for (i = 0; i < 5; i++) { + MemoryRegion *ram = g_new(MemoryRegion, 1); + memory_region_init_ram(ram, NULL, rams[i].n, rams[i].s, + &error_fatal); + memory_region_add_subregion(sysmem, rams[i].b, ram); + } + + /* CPUs: 4x Cortex-A7, only cpu0 boots */ + for (i = 0; i < SAIMAA_NCPUS; i++) { + Object *cpuobj = object_new("cortex-a7-" TYPE_ARM_CPU); + object_property_set_int(cpuobj, "mp-affinity", i, &error_fatal); + if (i > 0) { + object_property_set_bool(cpuobj, "start-powered-off", true, + &error_fatal); + } + object_property_set_bool(cpuobj, "realized", true, &error_fatal); + } + + /* GICv2 (minimal: dist + cpuif, IRQs wired later) */ + DeviceState *gic = qdev_new("arm_gic"); + qdev_prop_set_uint32(gic, "num-cpu", SAIMAA_NCPUS); + qdev_prop_set_uint32(gic, "num-irq", 160); + sysbus_realize(SYS_BUS_DEVICE(gic), &error_fatal); + sysbus_mmio_map(SYS_BUS_DEVICE(gic), 0, SAIMAA_GICD_BASE); + sysbus_mmio_map(SYS_BUS_DEVICE(gic), 1, SAIMAA_GICC_BASE); + + /* UART at MSM address */ + DeviceState *uart = qdev_new(TYPE_SAIMAA_UART); + sysbus_realize(SYS_BUS_DEVICE(uart), &error_fatal); + sysbus_mmio_map(SYS_BUS_DEVICE(uart), 0, SAIMAA_UART_BASE); + + /* Null-page trap at 0x0 (vectors live here; PBL normally maps ROM) */ + { + MemoryRegion *vec = g_new(MemoryRegion, 1); + memory_region_init_io(vec, NULL, &saimaa_vec_ops, NULL, + "saimaa-vec", 0x1000); + memory_region_add_subregion(sysmem, 0x0, vec); + } + + /* SDHCI + eMMC image */ + DeviceState *sdhci = qdev_new(TYPE_SYSBUS_SDHCI); + sysbus_realize(SYS_BUS_DEVICE(sdhci), &error_fatal); + sysbus_mmio_map(SYS_BUS_DEVICE(sdhci), 0, SAIMAA_SDHCI_BASE); + DriveInfo *di = drive_get(IF_SD, 0, 0); + if (di) { + DeviceState *card = qdev_new(TYPE_SD_CARD); + qdev_prop_set_drive(card, "drive", blk_by_legacy_dinfo(di)); + qdev_realize_and_unref(card, qdev_get_child_bus(sdhci, "sd-bus"), + &error_fatal); + } + + /* Load real SBL1 ELF, jump to entry */ + if (sms->sbl1) { + uint64_t entry = 0; + uint32_t pflags = 0; + ssize_t sz = load_elf(sms->sbl1, NULL, NULL, NULL, &entry, NULL, + NULL, &pflags, 0, EM_ARM, 1, 0); + if (sz < 0) { + error_report("saimaa: cannot load SBL1 %s: %s", sms->sbl1, + load_elf_strerror(sz)); + exit(1); + } + if (sms->sblmain) { + /* + * Direct start at sbl_main: skip the PBL trampoline at + * entry (it BLs into zero padding and pop-zeroes r0-r12). + * Odd address = Thumb code -> set env.thumb (CPSR T). + */ + uint32_t tgt = strtoul(sms->sblmain, NULL, 0); + /* NOTE: pass bit0 through: arm_cpu_set_pc() sets + * regs[15]=tgt&~1 and env.thumb=tgt&1 itself. */ + cpu_set_pc(first_cpu, tgt); + printf("saimaa: direct start -> 0x%x%s (entry 0x%lx skipped)\n", + tgt & ~1u, (tgt & 1) ? " thumb" : " arm", + (unsigned long)entry); + } else { + cpu_set_pc(first_cpu, entry); + } + /* PBL normally sets up SBL stack + r0=pbl_shared; fake it. + * All banked SPs: reset lands in SVC, regs[13] alone is USR. */ + for (int b = 0; b < 8; b++) { + ARM_CPU(first_cpu)->env.banked_r13[b] = 0x085FFF00; + } + ARM_CPU(first_cpu)->env.regs[13] = 0x085FFF00; + ARM_CPU(first_cpu)->env.regs[0] = 0x00220000; /* fake pbl_shared */ + /* sbl_main expects r5 = mem-table pointer (PBL trampoline does + * mov r5, r0 before jumping here); point it at pbl_shared too. */ + ARM_CPU(first_cpu)->env.regs[5] = 0x00220000; + /* (direct-start handled above; no stack override needed) */ + printf("saimaa: SBL1 %s loaded (%zd bytes), entry 0x%lx\n", + sms->sbl1, sz, (unsigned long)entry); + } +} + +static void saimaa_uart_class_init(ObjectClass *oc, void *data) +{ + (void)oc; + (void)data; +} + +static char *saimaa_get_sbl1(Object *obj, Error **errp) +{ + return g_strdup(SAIMAA_MACHINE(obj)->sbl1); +} + +static void saimaa_set_sbl1(Object *obj, const char *value, Error **errp) +{ + SaimaaMachineState *sms = SAIMAA_MACHINE(obj); + g_free(sms->sbl1); + sms->sbl1 = g_strdup(value); +} + +static char *saimaa_get_sblmain(Object *obj, Error **errp) +{ + return g_strdup(SAIMAA_MACHINE(obj)->sblmain); +} + +static void saimaa_set_sblmain(Object *obj, const char *value, Error **errp) +{ + SaimaaMachineState *sms = SAIMAA_MACHINE(obj); + g_free(sms->sblmain); + sms->sblmain = g_strdup(value); +} + +static void saimaa_machine_instance_init(Object *obj) +{ + SaimaaMachineState *sms = SAIMAA_MACHINE(obj); + sms->sbl1 = NULL; + sms->emmc = NULL; + sms->sblmain = NULL; + object_property_add_str(obj, "sbl1", saimaa_get_sbl1, saimaa_set_sbl1); + object_property_add_str(obj, "sblmain", saimaa_get_sblmain, + saimaa_set_sblmain); +} + +static void saimaa_machine_class_init(ObjectClass *oc, void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + mc->desc = "Nokia Lumia 550 Saimaa (MSM8909) WIP"; + mc->init = saimaa_machine_init; + mc->max_cpus = SAIMAA_NCPUS; + mc->default_cpus = SAIMAA_NCPUS; + mc->default_ram_size = 512 * MiB; /* only for -m accounting */ +} + +static const TypeInfo saimaa_machine_info = { + .name = TYPE_SAIMAA_MACHINE, + .parent = TYPE_MACHINE, + .instance_size = sizeof(SaimaaMachineState), + .instance_init = saimaa_machine_instance_init, + .class_init = saimaa_machine_class_init, +}; + +static const TypeInfo saimaa_uart_info = { + .name = TYPE_SAIMAA_UART, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SaimaaUartState), + .instance_init = saimaa_uart_init, + .class_init = saimaa_uart_class_init, +}; + +static void saimaa_register_types(void) +{ + type_register_static(&saimaa_machine_info); + type_register_static(&saimaa_uart_info); +} +type_init(saimaa_register_types) diff --git a/tools/sbl_adr.py b/tools/sbl_adr.py new file mode 100644 index 0000000..b9fc817 --- /dev/null +++ b/tools/sbl_adr.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python3 +"""sbl_adr.py — поиск ADR (ADD/SUB pc) ссылок на интересные строки SBL1. +Использование: ./tools/sbl_adr.py fw/sbl/img0.elf +""" +import struct +import sys + +d = open(sys.argv[1], "rb").read() +STRINGS = [b"SBL1, Start", b"SBL1, End", b"SBL1, Delta", + b"Sahara: Hello pkt sent", b"bl_power_on", b"sbl1_main"] +svas = {} +for s in STRINGS: + i = d.find(s) + if i < 0: + continue + # find which segment contains it + phoff = struct.unpack("> 7 + imm = ((imm >> rot) | (imm << (32 - rot))) & 0xFFFFFFFF if rot else imm + tgt = (v + j + 8 + (imm if (x & 0x400000) else -imm)) & 0xFFFFFFFF + if abs(tgt - va) < 0x100: + print(" ", hex(v + j), "->", hex(tgt)) + n += 1 + if n > 6: + break diff --git a/tools/sbl_mains.py b/tools/sbl_mains.py new file mode 100644 index 0000000..52d4644 --- /dev/null +++ b/tools/sbl_mains.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +"""sbl_mains.py — кандидаты в sbl_main: плотность BL + близость строк boot-лога. +Использование: ./tools/sbl_mains.py fw/sbl/img0.elf +""" +import struct +import sys + +d = open(sys.argv[1], "rb").read() +phoff = struct.unpack("> 25) == 0b101 and (y & 0x01000000): + bls += 1 + if bls >= 8: + cands.append((bls, v + j)) +cands.sort(reverse=True) +print("top candidates (bl-count, addr):") +for bls, a in cands[:15]: + print(f" {bls:3d} {a:#x}") diff --git a/tools/sbl_refs.py b/tools/sbl_refs.py new file mode 100644 index 0000000..3d215e8 --- /dev/null +++ b/tools/sbl_refs.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +"""sbl_refs.py — поиск кодовых ссылок на строку в SBL1 (img0.elf, seg 0x8005800). +Использование: ./tools/sbl_refs.py fw/sbl/img0.elf 'SBL1, Start' +""" +import struct +import sys + +path, needle = sys.argv[1], sys.argv[2].encode() +d = open(path, "rb").read() +i = d.find(needle) +print("str fileoff:", hex(i)) +SEG_OFF, SEG_VA, SEG_SZ = 0x3000, 0x8005800, 0x33A54 +va = SEG_VA + (i - SEG_OFF) +print("str VA:", hex(va)) +# search ALL segments for pc-relative loads to it +import re + +def segs(d): + phoff = struct.unpack("> 12) & 15), "->", hex(tgt)) From c7e95b41949a2fc23b7336c4dcb676e1a69494da Mon Sep 17 00:00:00 2001 From: SashegDev Date: Mon, 7 Sep 2026 13:10:38 +0000 Subject: [PATCH 2/3] sbl bringup: stublets, slots, maze, ffu-ref, b10 chain, docs --- docs/sbl-bringup.md | 43 +++++++++++++++++ qemu/saimaa.c | 110 ++++++++++++++++++++++++++++++++++++++++-- qemu/stublets.S | 50 +++++++++++++++++++ tools/edp_carve.py | 52 ++++++++++++++++++++ tools/sbl_patch.py | 114 ++++++++++++++++++++++++++++++++++++++++++++ tools/scaffold.py | 65 +++++++++++++++++++++++++ 6 files changed, 430 insertions(+), 4 deletions(-) create mode 100644 docs/sbl-bringup.md create mode 100644 qemu/stublets.S create mode 100644 tools/edp_carve.py create mode 100644 tools/sbl_patch.py create mode 100644 tools/scaffold.py diff --git a/docs/sbl-bringup.md b/docs/sbl-bringup.md new file mode 100644 index 0000000..2af41a1 --- /dev/null +++ b/docs/sbl-bringup.md @@ -0,0 +1,43 @@ +# 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. diff --git a/qemu/saimaa.c b/qemu/saimaa.c index 11f6994..dd21e7c 100644 --- a/qemu/saimaa.c +++ b/qemu/saimaa.c @@ -22,6 +22,8 @@ #include "qemu/log.h" /* Real MSM8909 map (subset) */ +#define SAIMAA_RPM_BASE 0x00400000 +#define SAIMAA_RPM_SIZE 0x07C00000 /* 0x00400000..0x08000000 heap-ish */ #define SAIMAA_OCIMEM_BASE 0x00200000 #define SAIMAA_OCIMEM_SIZE 0x00100000 #define SAIMAA_DDRLOW_BASE 0x08000000 @@ -35,6 +37,8 @@ #define SAIMAA_GICD_BASE 0x0B000000 #define SAIMAA_GICC_BASE 0x0B002000 #define SAIMAA_NCPUS 4 +#define SAIMAA_MYSTROM_BASE 0x69000000 +#define SAIMAA_MYSTROM_SIZE 0x00100000 #define SAIMAA_SMEM_BASE 0x87C00000 #define SAIMAA_SMEM_SIZE 0x00800000 @@ -131,6 +135,7 @@ struct SaimaaMachineState { char *sbl1; char *emmc; char *sblmain; /* hex: popped-PC override for PBL trampoline */ + char *regs; /* PBL reg overrides: N=V,N=V (N=r1,r4,r6-r9,sl,fp) */ }; typedef struct SaimaaMachineState SaimaaMachineState; @@ -145,17 +150,28 @@ static void saimaa_machine_init(MachineState *machine) /* RAM map */ const struct { const char *n; hwaddr b; hwaddr s; } rams[] = { + { "saimaa.rpm", SAIMAA_RPM_BASE, SAIMAA_RPM_SIZE }, { "saimaa.ocimem", SAIMAA_OCIMEM_BASE, SAIMAA_OCIMEM_SIZE }, { "saimaa.ddrlow", SAIMAA_DDRLOW_BASE, SAIMAA_DDRLOW_SIZE }, { "saimaa.imem", SAIMAA_IMEM_BASE, SAIMAA_IMEM_SIZE }, { "saimaa.ddrhigh", SAIMAA_DDRHIGH_BASE, SAIMAA_DDRHIGH_SIZE }, + { "saimaa.mystrom", SAIMAA_MYSTROM_BASE, SAIMAA_MYSTROM_SIZE }, { "saimaa.smem", SAIMAA_SMEM_BASE, SAIMAA_SMEM_SIZE }, }; - for (i = 0; i < 5; i++) { + for (i = 0; i < 7; i++) { MemoryRegion *ram = g_new(MemoryRegion, 1); memory_region_init_ram(ram, NULL, rams[i].n, rams[i].s, &error_fatal); - memory_region_add_subregion(sysmem, rams[i].b, ram); + memory_region_add_subregion(sysmem, rams[i].b, ram); + if (!strcmp(rams[i].n, "saimaa.mystrom")) { + /* Mystery handler ROM: ARM mov r0,#0; bx lr repeating, + * so unknown blx targets return 0 instead of faulting. */ + uint32_t *p = memory_region_get_ram_ptr(ram); + size_t k, n = SAIMAA_MYSTROM_SIZE / 4; + for (k = 0; k < n; k++) { + p[k] = 0xe12fff1e; /* bx lr: any 4-aligned entry returns */ + } + } } /* CPUs: 4x Cortex-A7, only cpu0 boots */ @@ -182,7 +198,9 @@ static void saimaa_machine_init(MachineState *machine) sysbus_realize(SYS_BUS_DEVICE(uart), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(uart), 0, SAIMAA_UART_BASE); - /* Null-page trap at 0x0 (vectors live here; PBL normally maps ROM) */ + /* Null-page trap at 0x0 (vectors live here; PBL normally maps ROM). + * Returns 0 for reads (data-0 invariant for SBL1 probing), logs the + * first faulting PCs for diagnosis. */ { MemoryRegion *vec = g_new(MemoryRegion, 1); memory_region_init_io(vec, NULL, &saimaa_vec_ops, NULL, @@ -239,7 +257,76 @@ static void saimaa_machine_init(MachineState *machine) /* sbl_main expects r5 = mem-table pointer (PBL trampoline does * mov r5, r0 before jumping here); point it at pbl_shared too. */ ARM_CPU(first_cpu)->env.regs[5] = 0x00220000; - /* (direct-start handled above; no stack override needed) */ + + /* sl/fp = SBL1 table bases (PBL trampoline would pop these from its + * frame); point at free DDRLOW RAM so helper-built tables persist + * instead of vanishing into the null-page trap. */ + ARM_CPU(first_cpu)->env.regs[10] = 0x08060000; /* sl */ + ARM_CPU(first_cpu)->env.regs[11] = 0x08061000; /* fp */ + if (sms->regs) { + char comma = 59; + char delims[2]; + char *spec, *tok, *save = NULL; + delims[0] = comma; + delims[1] = 0; + spec = g_strdup(sms->regs); + for (tok = strtok_r(spec, delims, &save); tok; + tok = strtok_r(NULL, delims, &save)) { + char *eq = strchr(tok, 61); + if (eq) { + int n = strtoul(tok, NULL, 0); + *eq = 0; + eq++; + if (n >= 0 && n < 16) { + ARM_CPU(first_cpu)->env.regs[n] = + strtoul(eq, NULL, 0); + } + } + } + g_free(spec); + } + /* PBL enables VFP/NEON (CPACR CP10+CP11, FPEXC.EN) before SBL1. */ + ARM_CPU(first_cpu)->env.cp15.cpacr_el1 = 0x00f00000; + ARM_CPU(first_cpu)->env.cp15.nsacr |= (3u << 10); + ARM_CPU(first_cpu)->env.vfp.xregs[ARM_VFP_FPEXC] |= (1u << 30); + /* Boot scaffolding for SBL1 BringUp (WIP stub-driven PBL): + * pop-compensation stublets at 0x08062000 pin sp and route onward, + * so repeated pops always hit valid slots. */ + { + static const unsigned char stub_blob[] = { 0xf0, 0xb4, 0x2d, 0xe9, 0x00, 0x5f, 0xdf, 0xf8, 0x6c, 0xc0, 0xcd, 0xf8, 0x24, 0xc0, 0xdf, 0xf8, 0x68, 0xf0, 0x30, 0xb4, 0xdf, 0xf8, 0x64, 0xc0, 0xcd, 0xf8, 0x04, 0xc0, 0xdf, 0xf8, 0x60, 0xf0, 0xf0, 0xb4, 0x2d, 0xe9, 0x00, 0x5f, 0xdf, 0xf8, 0x5c, 0xc0, 0xcd, 0xf8, 0x24, 0xc0, 0xdf, 0xf8, 0x58, 0xf0, 0xf0, 0xb5, 0x01, 0xb4, 0xdf, 0xf8, 0x54, 0xc0, 0xcd, 0xf8, 0x14, 0xc0, 0xdf, 0xf8, 0x50, 0xf0, 0xf0, 0xb4, 0x2d, 0xe9, 0x00, 0x5f, 0xdf, 0xf8, 0x48, 0xc0, 0xcd, 0xf8, 0x24, 0xc0, 0xdf, 0xf8, 0x44, 0xf0, 0xf0, 0xb5, 0x01, 0xb4, 0xdf, 0xf8, 0x40, 0xc0, 0xcd, 0xf8, 0x14, 0xc0, 0xdf, 0xf8, 0x3c, 0xf0, 0xf0, 0xb5, 0x07, 0xb4, 0xdf, 0xf8, 0x38, 0xc0, 0xcd, 0xf8, 0x1c, 0xc0, 0xdf, 0xf8, 0x34, 0xf0, 0x01, 0x20, 0x06, 0x08, 0x5d, 0xf6, 0x02, 0x08, 0x13, 0x20, 0x06, 0x08, 0x65, 0xf6, 0x02, 0x08, 0x21, 0x20, 0x06, 0x08, 0xa5, 0x3b, 0x01, 0x08, 0x43, 0x20, 0x06, 0x08, 0x81, 0xf6, 0x02, 0x08, 0x33, 0x20, 0x06, 0x08, 0x83, 0x61, 0x01, 0x08, 0x55, 0x20, 0x06, 0x08, 0x8d, 0x8a, 0x01, 0x08, 0x65, 0x20, 0x06, 0x08, 0x7d, 0xf6, 0x02, 0x08 }; + uint32_t magic = 0x00000000; /* IMEM poll spins WHILE equal */ + uint32_t S = 0x08062100, STUB = 0x08062120; + uint32_t w; + uint16_t h0 = 0x2000, h1 = 0x4770; /* movs r0,#0; bx lr */ + size_t k; + uint32_t v; + for (k = 0; k < sizeof(stub_blob); k += 4) { + uint32_t word; + __builtin_memcpy(&word, &stub_blob[k], 4); + cpu_physical_memory_write(0x08062000 + k, &word, 4); + } + /* pointer maze in owned RAM for SBL1 struct chains */ + w = S + 8; + cpu_physical_memory_write(S, &w, 4); + cpu_physical_memory_write(S + 8, &STUB, 4); + cpu_physical_memory_write(STUB, &h0, 2); + cpu_physical_memory_write(STUB + 2, &h1, 2); + cpu_physical_memory_write(0x087c29d18, &S, 4); + cpu_physical_memory_write(0x08050b28, &S, 4); + cpu_physical_memory_write(0x08070000, &S, 4); + /* pop-site slots -> stublets (sp values from cpu traces) */ + v = 0x08062001; /* S1 pop10 */ + cpu_physical_memory_write(0x085FFF14, &v, 4); + v = 0x08062013; /* S2 pop2 */ + cpu_physical_memory_write(0x085FFF1C, &v, 4); + v = 0x08062021; /* S3 pop10 */ + cpu_physical_memory_write(0x085FFF44, &v, 4); + cpu_physical_memory_write(0x085FFF7C, &v, 4); + v = 0x08062033; /* S4 pop6 (stublet chains S5) */ + cpu_physical_memory_write(0x085FFF34, &v, 4); + cpu_physical_memory_write(0x08600944, &magic, 4); + printf("saimaa: stub-scaffold live\n"); + } printf("saimaa: SBL1 %s loaded (%zd bytes), entry 0x%lx\n", sms->sbl1, sz, (unsigned long)entry); } @@ -268,6 +355,18 @@ static char *saimaa_get_sblmain(Object *obj, Error **errp) return g_strdup(SAIMAA_MACHINE(obj)->sblmain); } +static char *saimaa_get_regs(Object *obj, Error **errp) +{ + return g_strdup(SAIMAA_MACHINE(obj)->regs); +} + +static void saimaa_set_regs(Object *obj, const char *value, Error **errp) +{ + SaimaaMachineState *sms = SAIMAA_MACHINE(obj); + g_free(sms->regs); + sms->regs = g_strdup(value); +} + static void saimaa_set_sblmain(Object *obj, const char *value, Error **errp) { SaimaaMachineState *sms = SAIMAA_MACHINE(obj); @@ -281,7 +380,10 @@ static void saimaa_machine_instance_init(Object *obj) sms->sbl1 = NULL; sms->emmc = NULL; sms->sblmain = NULL; + sms->regs = NULL; object_property_add_str(obj, "sbl1", saimaa_get_sbl1, saimaa_set_sbl1); + object_property_add_str(obj, "regs", saimaa_get_regs, + saimaa_set_regs); object_property_add_str(obj, "sblmain", saimaa_get_sblmain, saimaa_set_sblmain); } diff --git a/qemu/stublets.S b/qemu/stublets.S new file mode 100644 index 0000000..7f287be --- /dev/null +++ b/qemu/stublets.S @@ -0,0 +1,50 @@ +.syntax unified +.cpu cortex-a7 +.thumb +@ SBL1 pop-compensation stublets for saimaa (v3: slots hold STUBLET +@ addresses, never raw CONTS; S4<->S5 ping-pong stage each other). +.text +.global stub10_a, stub2, stub10_b, stub6_a, stub10_c, stub6_b, stub8 +stub10_a: @ N=10, jump CONT=0x802f65d + push {r4-r7} + push {r8-r11,ip,lr} + ldr ip, =stub10_a + str ip, [sp, #36] + ldr pc, =0x802f65d +stub2: @ N=2, jump CONT=0x802f665 + push {r4-r5} + ldr ip, =stub2 + str ip, [sp, #4] + ldr pc, =0x802f665 +stub10_b: @ N=10, jump CONT=0x8013ba5 + push {r4-r7} + push {r8-r11,ip,lr} + ldr ip, =stub10_b + str ip, [sp, #36] + ldr pc, =0x8013ba5 +stub6_a: @ N=6, jump CONT=0x802f681, + @ stage stub10_c for upcoming S5 + push {r4-r7,lr} + push {r0} + ldr ip, =stub10_c + str ip, [sp, #20] + ldr pc, =0x802f681 +stub10_c: @ N=10, jump CONT=0x8016183, + @ restage stub6_a for future S4 + push {r4-r7} + push {r8-r11,ip,lr} + ldr ip, =stub6_a + str ip, [sp, #36] + ldr pc, =0x8016183 +stub6_b: @ N=6, jump CONT=0x8018a8d + push {r4-r7,lr} + push {r0} + ldr ip, =stub6_b + str ip, [sp, #20] + ldr pc, =0x8018a8d +stub8: @ N=8, jump CONT=0x802f67d + push {r4-r7,lr} + push {r0-r2} + ldr ip, =stub8 + str ip, [sp, #28] + ldr pc, =0x802f67d diff --git a/tools/edp_carve.py b/tools/edp_carve.py new file mode 100644 index 0000000..8c06375 --- /dev/null +++ b/tools/edp_carve.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python3 +"""edp_carve.py — точная нарезка ELF из Emergency Payload (.edp) по program headers. +Использование: ./tools/edp_carve.py fw/dl/edp-archorg-1127.edp out-dir/ +""" +import os +import struct +import sys + + +def elf_span(d, off): + assert d[off:off + 4] == b"\x7fELF", "not ELF" + entry = struct.unpack(" bl (stay Thumb): set bit12 of 2nd halfword + 0x802F658: ('d8f7c2ed', 'd8f7c2fd'), + 0x802F660: ('d8f702ec', 'd8f702fc'), +} +NOPS = { # call -> NOP NOP (skip unmodellable init/assert; r0/r5 ignored) + 0x802F664: 'e4f77efc', # bl walker (result ignored by caller) + 0x802F672: 'e6f7bbfa', # bl 0x8015bec (assert-hang) + 0x802F678: None, # bl 0x8018a78, see REDIRECT (installer runs!) + 0x801B71E: '9847fee7', # blx r3 + b.n self (terminal assert, 4B) + 0x8016184: 'fdf790fc', # bl 0x8013aa8 (subtree nopped, see b8) +} +REDIRECT = { + # bl target off-by-N fixes (verified by disasm + QEMU traces): + 0x8013AA8: ('07f026be', '07f027be'), # jump-table case0: +2 + 0x802F678: ('e9f7fef9', 'e9f700fa'), # bl 0x8018a78 -> 0x8018a7c (+4) +} +POOLS = { + # literal pool words redirected to owned scratch (orig struct garbage): + 0x801B76C: ('280b0508', '00000708'), # -> 0x08070000 +} + + +def off(va): + return SEG_OFF + (va - SEG_VA) + + +def hx(d, va, n=4): + return d[off(va):off(va) + n].hex() + + +def set4(d, va, hexbytes): + d[off(va):off(va) + 4] = bytes.fromhex(hexbytes) + + +def main(): + src, outdir = sys.argv[1], sys.argv[2] + os.makedirs(outdir, exist_ok=True) + base = bytearray(open(src, 'rb').read()) + + def save(d, name): + p = os.path.join(outdir, name) + open(p, 'wb').write(bytes(d)) + print('wrote', p, len(d)) + + d = bytearray(base) + for va, (a, b) in BLX2BL.items(): + assert hx(d, va) == a, (hex(va), hx(d, va)) + set4(d, va, b) + save(d, 'img0_bl.elf') + + # b2 = bl + walker NOP + o = off(0x802F664) + assert d[o:o + 4].hex() == 'e4f77efc' + d[o:o + 4] = bytes.fromhex('c046c046') + save(d, 'img0_b2.elf') + # b3 = b2 + 0x8015bec NOP + o = off(0x802F672) + assert d[o:o + 4].hex() == 'e6f7bbfa', hx(d, 0x802F672) + d[o:o + 4] = bytes.fromhex('c046c046') + save(d, 'img0_b3.elf') + # b4 = b3 + 0x8018a78 NOP + o = off(0x802F678) + assert d[o:o + 4].hex() == 'e9f7fef9', hx(d, 0x802F678) + d[o:o + 4] = bytes.fromhex('c046c046') + save(d, 'img0_b4.elf') + # b5 = b4 + jump-table +2 + o = off(0x8013AA8) + assert d[o:o + 4].hex() == '07f026be' + d[o:o + 4] = bytes.fromhex('07f027be') + save(d, 'img0_b5.elf') + # b6 = b5 + terminal assert NOP (4B) + o = off(0x801B71E) + assert d[o:o + 4].hex() == '9847fee7' + d[o:o + 4] = bytes.fromhex('c046c046') + save(d, 'img0_b6.elf') + # b7 = b6 + redirect bl to installer entry (undoes b4 NOP) + o = off(0x802F678) + assert d[o:o + 4].hex() == 'c046c046' + d[o:o + 4] = bytes.fromhex('e9f700fa') + save(d, 'img0_b7.elf') + # b8 = b7 + subtree NOP + pool redirect + o = off(0x8016184) + assert d[o:o + 4].hex() == 'fdf790fc', hx(d, 0x8016184) + d[o:o + 4] = bytes.fromhex('c046c046') + o = off(0x801B76C) + assert d[o:o + 4].hex() == '280b0508' + d[o:o + 4] = bytes.fromhex('00000708') + save(d, 'img0_b8.elf') + # b9 = b8 + hole-call NOP (EDL-dead padding slide at 0x80068FC) + o = off(0x8008396) + assert d[o:o + 4].hex() == 'fef780f9', hx(d, 0x8008396) + d[o:o + 4] = bytes.fromhex('c046c046') + save(d, 'img0_b9.elf') + # b10 = b9 with installer-bl reverted to NOP (S2 lands mid-NOPs safely, + # falls into the 0x8013b7c call; installer skipped, structs via maze) + o = off(0x802F678) + assert d[o:o + 4].hex() == 'e9f700fa', hx(d, 0x802F678) + d[o:o + 4] = bytes.fromhex('c046c046') + save(d, 'img0_b10.elf') + + +if __name__ == '__main__': + main() diff --git a/tools/scaffold.py b/tools/scaffold.py new file mode 100644 index 0000000..832c2eb --- /dev/null +++ b/tools/scaffold.py @@ -0,0 +1,65 @@ +import struct + +M = '/root/qemu-src/qemu-8.2.2/hw/arm/saimaa.c' +src = open(M).read() + +start = src.find(' /* Boot scaffolding for SBL1 BringUp') +assert start > 0, 'scaffold start not found' +end_marker = 'printf("saimaa: SBL1 %s loaded' +end = src.find(end_marker, start) +assert end > 0, 'scaffold end not found' +line_start = src.rfind('\n', 0, end) + 1 + +blob = open('/tmp/stubs3.bin', 'rb').read() +print('stub blob len', len(blob)) +c_array = ', '.join('0x%02x' % b for b in blob) + +S10_A = '0x08062001' +S2 = '0x08062013' +S10_B = '0x08062021' +S6_A = '0x08062033' + +new_block = ''' /* Boot scaffolding for SBL1 BringUp (WIP stub-driven PBL): + * pop-compensation stublets at 0x08062000 pin sp and route onward, + * so repeated pops always hit valid slots. */ + { + static const unsigned char stub_blob[] = { %s }; + uint32_t magic = 0x00000000; /* IMEM poll spins WHILE equal */ + uint32_t S = 0x08062100, STUB = 0x08062120; + uint32_t w; + uint16_t h0 = 0x2000, h1 = 0x4770; /* movs r0,#0; bx lr */ + size_t k; + uint32_t v; + for (k = 0; k < sizeof(stub_blob); k += 4) { + uint32_t word; + __builtin_memcpy(&word, &stub_blob[k], 4); + cpu_physical_memory_write(0x08062000 + k, &word, 4); + } + /* pointer maze in owned RAM for SBL1 struct chains */ + w = S + 8; + cpu_physical_memory_write(S, &w, 4); + cpu_physical_memory_write(S + 8, &STUB, 4); + cpu_physical_memory_write(STUB, &h0, 2); + cpu_physical_memory_write(STUB + 2, &h1, 2); + cpu_physical_memory_write(0x087c29d18, &S, 4); + cpu_physical_memory_write(0x08050b28, &S, 4); + cpu_physical_memory_write(0x08070000, &S, 4); + /* pop-site slots -> stublets (sp values from cpu traces) */ + v = %s; /* S1 pop10 */ + cpu_physical_memory_write(0x085FFF14, &v, 4); + v = %s; /* S2 pop2 */ + cpu_physical_memory_write(0x085FFF1C, &v, 4); + v = %s; /* S3 pop10 */ + cpu_physical_memory_write(0x085FFF44, &v, 4); + cpu_physical_memory_write(0x085FFF7C, &v, 4); + v = %s; /* S4 pop6 (stublet chains S5) */ + cpu_physical_memory_write(0x085FFF34, &v, 4); + cpu_physical_memory_write(0x08600944, &magic, 4); + printf("saimaa: stub-scaffold live\\n"); + } + { +''' % (c_array, S10_A, S2, S10_B, S6_A) + +src = src[:start] + new_block + src[line_start:] +open(M, 'w').write(src) +print('CANONICAL SCAFFOLD v2 OK') From 7d57f138a527a74f8ef5c5d059ff5ff002fd3b26 Mon Sep 17 00:00:00 2001 From: SashegDev Date: Mon, 7 Sep 2026 13:35:39 +0000 Subject: [PATCH 3/3] sbl: b12 chain, slots, maze, stubs, docs current --- qemu/saimaa.c | 48 ++++++++++++++++++++++++++++++---------------- tools/sbl_patch.py | 25 ++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 16 deletions(-) diff --git a/qemu/saimaa.c b/qemu/saimaa.c index dd21e7c..abcaa95 100644 --- a/qemu/saimaa.c +++ b/qemu/saimaa.c @@ -290,42 +290,58 @@ static void saimaa_machine_init(MachineState *machine) ARM_CPU(first_cpu)->env.cp15.nsacr |= (3u << 10); ARM_CPU(first_cpu)->env.vfp.xregs[ARM_VFP_FPEXC] |= (1u << 30); /* Boot scaffolding for SBL1 BringUp (WIP stub-driven PBL): - * pop-compensation stublets at 0x08062000 pin sp and route onward, - * so repeated pops always hit valid slots. */ + * static continuation slots for shared-epilogue pops. + * sp advances linearly (no compensation); one slot per pop site. + * (sp values from cpu traces, b10 image) */ { - static const unsigned char stub_blob[] = { 0xf0, 0xb4, 0x2d, 0xe9, 0x00, 0x5f, 0xdf, 0xf8, 0x6c, 0xc0, 0xcd, 0xf8, 0x24, 0xc0, 0xdf, 0xf8, 0x68, 0xf0, 0x30, 0xb4, 0xdf, 0xf8, 0x64, 0xc0, 0xcd, 0xf8, 0x04, 0xc0, 0xdf, 0xf8, 0x60, 0xf0, 0xf0, 0xb4, 0x2d, 0xe9, 0x00, 0x5f, 0xdf, 0xf8, 0x5c, 0xc0, 0xcd, 0xf8, 0x24, 0xc0, 0xdf, 0xf8, 0x58, 0xf0, 0xf0, 0xb5, 0x01, 0xb4, 0xdf, 0xf8, 0x54, 0xc0, 0xcd, 0xf8, 0x14, 0xc0, 0xdf, 0xf8, 0x50, 0xf0, 0xf0, 0xb4, 0x2d, 0xe9, 0x00, 0x5f, 0xdf, 0xf8, 0x48, 0xc0, 0xcd, 0xf8, 0x24, 0xc0, 0xdf, 0xf8, 0x44, 0xf0, 0xf0, 0xb5, 0x01, 0xb4, 0xdf, 0xf8, 0x40, 0xc0, 0xcd, 0xf8, 0x14, 0xc0, 0xdf, 0xf8, 0x3c, 0xf0, 0xf0, 0xb5, 0x07, 0xb4, 0xdf, 0xf8, 0x38, 0xc0, 0xcd, 0xf8, 0x1c, 0xc0, 0xdf, 0xf8, 0x34, 0xf0, 0x01, 0x20, 0x06, 0x08, 0x5d, 0xf6, 0x02, 0x08, 0x13, 0x20, 0x06, 0x08, 0x65, 0xf6, 0x02, 0x08, 0x21, 0x20, 0x06, 0x08, 0xa5, 0x3b, 0x01, 0x08, 0x43, 0x20, 0x06, 0x08, 0x81, 0xf6, 0x02, 0x08, 0x33, 0x20, 0x06, 0x08, 0x83, 0x61, 0x01, 0x08, 0x55, 0x20, 0x06, 0x08, 0x8d, 0x8a, 0x01, 0x08, 0x65, 0x20, 0x06, 0x08, 0x7d, 0xf6, 0x02, 0x08 }; uint32_t magic = 0x00000000; /* IMEM poll spins WHILE equal */ uint32_t S = 0x08062100, STUB = 0x08062120; uint32_t w; uint16_t h0 = 0x2000, h1 = 0x4770; /* movs r0,#0; bx lr */ - size_t k; uint32_t v; - for (k = 0; k < sizeof(stub_blob); k += 4) { - uint32_t word; - __builtin_memcpy(&word, &stub_blob[k], 4); - cpu_physical_memory_write(0x08062000 + k, &word, 4); - } /* pointer maze in owned RAM for SBL1 struct chains */ w = S + 8; cpu_physical_memory_write(S, &w, 4); cpu_physical_memory_write(S + 8, &STUB, 4); cpu_physical_memory_write(STUB, &h0, 2); cpu_physical_memory_write(STUB + 2, &h1, 2); + cpu_physical_memory_write(STUB + 4, &STUB, 4); cpu_physical_memory_write(0x087c29d18, &S, 4); cpu_physical_memory_write(0x08050b28, &S, 4); cpu_physical_memory_write(0x08070000, &S, 4); + /* stack zone defaults to plain-stub addr: every register + * popped from untouched stack becomes callable (returns 0). */ + { + uint32_t fill = 0x08062121; + uint32_t a; + for (a = 0x085F0000; a < 0x08600000; a += 4) { + cpu_physical_memory_write(a, &fill, 4); + } + } /* pop-site slots -> stublets (sp values from cpu traces) */ - v = 0x08062001; /* S1 pop10 */ + v = 0x802f65d; /* S1 pop10 @fef0: resume sbl_main */ cpu_physical_memory_write(0x085FFF14, &v, 4); - v = 0x08062013; /* S2 pop2 */ + v = 0x802f665; /* S2 pop2 @ff18: walker site (NOP) */ cpu_physical_memory_write(0x085FFF1C, &v, 4); - v = 0x08062021; /* S3 pop10 */ + v = 0x8013ba5; /* S3 pop10 @ff20: 0x8013b7c loop */ cpu_physical_memory_write(0x085FFF44, &v, 4); - cpu_physical_memory_write(0x085FFF7C, &v, 4); - v = 0x08062033; /* S4 pop6 (stublet chains S5) */ - cpu_physical_memory_write(0x085FFF34, &v, 4); + v = 0x802f681; /* S4 pop6 @ff48: back to sbl_main */ + cpu_physical_memory_write(0x085FFF5C, &v, 4); + v = 0x8016183; /* S5 pop10 @ff50: 0x8013ae4 caller */ + cpu_physical_memory_write(0x085FFF74, &v, 4); + { /* words that popped regs must read as 0 (not stub-fill) */ + uint32_t z = 0; + cpu_physical_memory_write(0x085FFF58, &z, 4); /* r7 src */ + } + { /* installer-path slots + zero words */ + uint32_t z = 0; + uint32_t z2 = 0; + cpu_physical_memory_write(0x085FFF34, &z2, 4); /* S3 r7 */ + cpu_physical_memory_write(0x085FFF54, &z2, 4); + cpu_physical_memory_write(0x085FFF6C, &z, 4); /* r7 src */ + } cpu_physical_memory_write(0x08600944, &magic, 4); - printf("saimaa: stub-scaffold live\n"); + printf("saimaa: slots live\n"); } printf("saimaa: SBL1 %s loaded (%zd bytes), entry 0x%lx\n", sms->sbl1, sz, (unsigned long)entry); diff --git a/tools/sbl_patch.py b/tools/sbl_patch.py index e6bd74d..233bbf6 100644 --- a/tools/sbl_patch.py +++ b/tools/sbl_patch.py @@ -108,6 +108,31 @@ def main(): assert d[o:o + 4].hex() == 'e9f700fa', hx(d, 0x802F678) d[o:o + 4] = bytes.fromhex('c046c046') save(d, 'img0_b10.elf') + # b11 = b10 with installer-bl restored (redirect, installer runs again) + o = off(0x802F678) + assert d[o:o + 4].hex() == 'c046c046' + d[o:o + 4] = bytes.fromhex('e9f700fa') + save(d, 'img0_b11.elf') + # b12: b10-variant with jump-table entry0 NOP (fall into entry1/case-1); + # rebuilt from b10 base (installer stays skipped) + d = bytearray(base) + for va, (a, b) in BLX2BL.items(): + set4(d, va, b) + for va, exp, new in [ + (0x802F664, 'e4f77efc', 'c046c046'), + (0x802F672, 'e6f7bbfa', 'c046c046'), + (0x802F678, 'e9f7fef9', 'c046c046'), + (0x801B71E, '9847fee7', 'c046c046'), + (0x8008396, 'fef780f9', 'c046c046'), + (0x8016184, 'fdf790fc', 'c046c046'), + (0x801B76C, '280b0508', '00000708'), + ]: + assert hx(d, va) == exp, (hex(va), hx(d, va)) + set4(d, va, new) + o = off(0x8013AA8) + assert d[o:o + 4].hex() == '07f026be', hx(d, 0x8013AA8) + d[o:o + 4] = bytes.fromhex('c046c046') + save(d, 'img0_b12.elf') if __name__ == '__main__':