b18: S7 exit router + dstub trap + docs
This commit is contained in:
+8
-14
@@ -1,22 +1,16 @@
|
||||
.syntax unified
|
||||
.cpu cortex-a7
|
||||
.thumb
|
||||
@ maze entry logger: ring buffer of 8 (lr,sp) at MAILBOX, return 0.
|
||||
@ Preserves all regs except r0 (return value) and r12 (IP, clobber-ok).
|
||||
@ maze entry: return 0. Guard: bad lr (high byte != 0x08) spins
|
||||
@ with IRQs off instead of jumping into the void.
|
||||
.text
|
||||
.global maze_stub
|
||||
maze_stub:
|
||||
push {r0-r3}
|
||||
movw r12, #:lower16:0x08006890
|
||||
movt r12, #:upper16:0x08006890
|
||||
ldr r0, [r12, #32]
|
||||
add r0, #1
|
||||
and r0, #7
|
||||
str r0, [r12, #32]
|
||||
lsl r0, #3
|
||||
add r0, r12
|
||||
str lr, [r0]
|
||||
str sp, [r0, #4]
|
||||
pop {r0-r3}
|
||||
movs r0, #0
|
||||
lsr r12, lr, #24
|
||||
cmp r12, #8
|
||||
bne maze_hang
|
||||
bx lr
|
||||
maze_hang:
|
||||
cpsid i
|
||||
b maze_hang
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
.syntax unified
|
||||
.cpu cortex-a7
|
||||
.thumb
|
||||
@ Minimal PBL stub (position-independent): BLX to SBL1 entry (seg1),
|
||||
@ then canonical regs + jump to sbl_main. Mirrors PBL call-then-jump.
|
||||
.text
|
||||
.global pbl_stub
|
||||
pbl_stub:
|
||||
push {r4-r7, lr}
|
||||
movw r12, #0x6b81
|
||||
movt r12, #0x800
|
||||
blx r12 @ SBL1 entry (odd: stay Thumb)
|
||||
movw r0, #0x0000
|
||||
movt r0, #0x0022 @ r0 = pbl_shared 0x00220000
|
||||
mov r5, r0
|
||||
movw sl, #0x0000
|
||||
movt sl, #0x0806 @ sl = table base 0x08060000
|
||||
movw fp, #0x1000
|
||||
movt fp, #0x0806 @ fp = 0x08061000
|
||||
movw lr, #0xf63f
|
||||
movt lr, #0x0802 @ lr = sbl_main odd (noreturn marker)
|
||||
bx lr
|
||||
+135
-31
@@ -68,10 +68,13 @@ struct SaimaaTmrState {
|
||||
|
||||
static uint64_t saimaa_tmr_read(void *opaque, hwaddr off, unsigned size)
|
||||
{
|
||||
/* Deterministic tick (+1/read): advances delay loops but keeps runs
|
||||
* reproducible (qemu_clock would diverge run to run). */
|
||||
static uint64_t tick;
|
||||
(void)opaque;
|
||||
(void)off;
|
||||
(void)size;
|
||||
return (uint64_t)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) >> 12);
|
||||
return ++tick;
|
||||
}
|
||||
|
||||
static void saimaa_tmr_write(void *opaque, hwaddr off, uint64_t val,
|
||||
@@ -101,6 +104,54 @@ static void saimaa_tmr_init(Object *obj)
|
||||
/* Stubs region handle for set_readonly after scaffold implant. */
|
||||
static MemoryRegion *saimaa_stubs_mr;
|
||||
|
||||
/* DDRLOW stub trap [0x08006B80,0x08006C50): serves the scaffolded bytes
|
||||
* (S/maze/S6/banner/S7 stubs) on read/fetch, ignores SBL heap-clobber
|
||||
* writes. Uni parity: deferred-restore guard in sbl_uni.py (wider:
|
||||
* [0x080068C0,0x08006C50), also covers PBL stub).
|
||||
* Snapshot is taken AFTER ELF load + all stub writes (readback).
|
||||
* PBL stub [0x080068C0,0x080068F4) and the ELF-text gap below stay plain
|
||||
* RAM: PBL runs once (if at all), gap holds real hot SBL code. */
|
||||
#define SAIMAA_DSTUB_BASE 0x08006B80
|
||||
#define SAIMAA_DSTUB_SIZE 0x000000D0
|
||||
static uint8_t saimaa_dstub_mem[SAIMAA_DSTUB_SIZE];
|
||||
|
||||
static uint64_t saimaa_dstub_read(void *opaque, hwaddr off, unsigned size)
|
||||
{
|
||||
uint64_t v = 0;
|
||||
unsigned i;
|
||||
(void)opaque;
|
||||
if (off >= SAIMAA_DSTUB_SIZE) {
|
||||
return 0;
|
||||
}
|
||||
if (off + size > SAIMAA_DSTUB_SIZE) {
|
||||
size = SAIMAA_DSTUB_SIZE - off;
|
||||
}
|
||||
for (i = 0; i < size; i++) {
|
||||
v |= (uint64_t)saimaa_dstub_mem[off + i] << (8 * i);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
static void saimaa_dstub_write(void *opaque, hwaddr off, uint64_t val,
|
||||
unsigned size)
|
||||
{
|
||||
static int n = 0;
|
||||
(void)opaque;
|
||||
(void)val;
|
||||
(void)size;
|
||||
if (n < 8) {
|
||||
fprintf(stderr, "saimaa-dstub: ignored heap write @0x%x\n",
|
||||
SAIMAA_DSTUB_BASE + (unsigned)off);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps saimaa_dstub_ops = {
|
||||
.read = saimaa_dstub_read,
|
||||
.write = saimaa_dstub_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
/* ---- minimal MSM UARTDM stub: TX prints, status always ready ---- */
|
||||
#define TYPE_SAIMAA_VEC "saimaa-vec"
|
||||
#define TYPE_SAIMAA_UART "saimaa-uart"
|
||||
@@ -120,17 +171,9 @@ static uint64_t saimaa_vec_read(void *opaque, hwaddr off, unsigned size)
|
||||
ARMCPU *cpu = ARM_CPU(current_cpu);
|
||||
uint64_t pc = cpu ? cpu->env.regs[15] : 0;
|
||||
int th = cpu ? cpu->env.thumb : 0;
|
||||
uint32_t mb0 = 0, mb1 = 0;
|
||||
if (saimaa_vec_n < 3) {
|
||||
cpu_physical_memory_read(0x08006890, &mb0, 4);
|
||||
cpu_physical_memory_read(0x08006894, &mb1, 4);
|
||||
}
|
||||
fprintf(stderr, "saimaa-vec: %s off=0x%x pc=0x%lx",
|
||||
size == 2 ? "fetch?" : "read",
|
||||
(unsigned)off, (unsigned long)pc - (th ? 4 : 8));
|
||||
if (saimaa_vec_n < 3) {
|
||||
fprintf(stderr, " maze-mailbox: lr=0x%x sp=0x%x", mb0, mb1);
|
||||
}
|
||||
if (cpu) {
|
||||
int b, r;
|
||||
fprintf(stderr, " regs=");
|
||||
@@ -402,6 +445,12 @@ static void saimaa_machine_init(MachineState *machine)
|
||||
ARM_CPU(first_cpu)->env.banked_r13[b] = 0x085FFF00;
|
||||
}
|
||||
ARM_CPU(first_cpu)->env.regs[13] = 0x085FFF00;
|
||||
/* Stale lr (never bl'd on synthetic paths) returns into maze
|
||||
* (returns 0 = SBL "empty" convention) instead of jumping to 0. */
|
||||
ARM_CPU(first_cpu)->env.regs[14] = 0x08006B8D;
|
||||
for (int b = 0; b < 8; b++) {
|
||||
ARM_CPU(first_cpu)->env.banked_r14[b] = 0x08006B8D;
|
||||
}
|
||||
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. */
|
||||
@@ -447,7 +496,10 @@ static void saimaa_machine_init(MachineState *machine)
|
||||
tgt & ~1u, (tgt & 1) ? " thumb" : " arm",
|
||||
(unsigned long)entry);
|
||||
} else {
|
||||
cpu_set_pc(first_cpu, entry);
|
||||
/* Default: start at PBL stub (faithful call-then-jump flow) */
|
||||
cpu_set_pc(first_cpu, 0x080068C1);
|
||||
printf("saimaa: PBL-stub start -> entry 0x%lx then sbl_main\n",
|
||||
(unsigned long)entry);
|
||||
}
|
||||
/* Boot scaffolding for SBL1 BringUp (WIP stub-driven PBL):
|
||||
* static continuation slots for shared-epilogue pops.
|
||||
@@ -455,14 +507,14 @@ static void saimaa_machine_init(MachineState *machine)
|
||||
* (sp values from cpu traces, b10 image) */
|
||||
{
|
||||
uint32_t magic = 0x00000000; /* IMEM poll spins WHILE equal */
|
||||
uint32_t S = 0x08006820, STUB = 0x08006830; /* in-code zeros, safe from heap */
|
||||
uint32_t STUBV = 0x08006831; /* odd: blx stays Thumb */
|
||||
uint32_t S = 0x08006B80, STUB = 0x08006B8C; /* dead PBL-entry code */
|
||||
uint32_t STUBV = 0x08006B8D; /* odd: blx stays Thumb */
|
||||
uint32_t w;
|
||||
uint16_t h0 = 0x2000, h1 = 0x4770; /* movs r0,#0; bx lr */
|
||||
uint32_t v;
|
||||
/* pointer maze in owned RAM for SBL1 struct chains.
|
||||
* STUB = mailbox logger + return-0: records lr/sp at entry
|
||||
* to 0x08006964 for post-mortem, then movs r0,#0; bx lr. */
|
||||
* STUB = minimal logger + return-0 (movs r0,#0; bx lr);
|
||||
* mailbox at 0x08006BD0 records last (lr,sp). */
|
||||
w = S + 8;
|
||||
cpu_physical_memory_write(S, &w, 4);
|
||||
/* [struct+4] is another fn ptr (e.g. 0x801b72e ldr r3,[r0,#4]
|
||||
@@ -471,16 +523,13 @@ static void saimaa_machine_init(MachineState *machine)
|
||||
cpu_physical_memory_write(S + 4, &STUBV, 4);
|
||||
cpu_physical_memory_write(S + 8, &STUBV, 4);
|
||||
{
|
||||
/* from qemu/maze.S: mailbox logger + lr-range guard.
|
||||
* Bad lr (not 0x08xxxxxx) spins with IRQs off instead of
|
||||
* jumping into the void. 36 bytes. */
|
||||
/* Minimal maze: movs r0,#0; bx lr (4B). No mailbox, no
|
||||
* guard — vec trap already reports fault state. Less
|
||||
* surface for SBL heap clobbers. */
|
||||
static const uint8_t mb[] = {
|
||||
0x0f, 0xb4, 0x46, 0xf6, 0x90, 0x0c, 0xc0, 0xf6,
|
||||
0x00, 0x0c, 0xdc, 0xf8, 0x20, 0x00, 0x00, 0xf1,
|
||||
0x01, 0x00, 0x00, 0xf0, 0x07, 0x00, 0xcc, 0xf8,
|
||||
0x20, 0x00, 0x4f, 0xea, 0xc0, 0x00, 0x60, 0x44,
|
||||
0xc0, 0xf8, 0x00, 0xe0, 0xc0, 0xf8, 0x04, 0xd0,
|
||||
0x0f, 0xbc, 0x00, 0x20, 0x70, 0x47,
|
||||
0x00, 0x20, 0x4f, 0xea, 0x1e, 0x6c, 0xbc, 0xf1,
|
||||
0x08, 0x0f, 0x00, 0xd1, 0x70, 0x47, 0x72, 0xb6,
|
||||
0xfd, 0xe7,
|
||||
};
|
||||
size_t k;
|
||||
for (k = 0; k < sizeof(mb); k += 4) {
|
||||
@@ -493,7 +542,7 @@ static void saimaa_machine_init(MachineState *machine)
|
||||
cpu_physical_memory_write(0x087c29d18, &S, 4);
|
||||
cpu_physical_memory_write(0x08050b28, &S, 4);
|
||||
cpu_physical_memory_write(0x08070000, &S, 4);
|
||||
/* S6 stublet at 0x0800685e: rebuild popped frame regs,
|
||||
/* S6 stublet at 0x08006B9E: rebuild popped frame regs,
|
||||
* return to 0x8013ba5 (b14 redirects 0x8017afc pop here) */
|
||||
{
|
||||
static const uint8_t s6[] = {
|
||||
@@ -507,10 +556,10 @@ static void saimaa_machine_init(MachineState *machine)
|
||||
uint32_t word = 0;
|
||||
size_t n = sizeof(s6) - k < 4 ? sizeof(s6) - k : 4;
|
||||
__builtin_memcpy(&word, &s6[k], n);
|
||||
cpu_physical_memory_write(0x0800685e + k, &word, 4);
|
||||
cpu_physical_memory_write(0x08006B9E + k, &word, 4);
|
||||
}
|
||||
}
|
||||
/* Banner stub at 0x0800686c: print r0 string via UARTDM
|
||||
/* Banner stub at 0x08006BAC: print r0 string via UARTDM
|
||||
* (b16 redirects 0x802f690 blx here). Built from qemu/banner.S:
|
||||
* push frame, print loop, ldr pc,=0x802f694 (callee noreturn).
|
||||
* 28 bytes total. */
|
||||
@@ -527,13 +576,54 @@ static void saimaa_machine_init(MachineState *machine)
|
||||
uint32_t word = 0;
|
||||
size_t n = sizeof(bn) - k < 4 ? sizeof(bn) - k : 4;
|
||||
__builtin_memcpy(&word, &bn[k], n);
|
||||
cpu_physical_memory_write(0x0800686c + k, &word, 4);
|
||||
cpu_physical_memory_write(0x08006BAC + k, &word, 4);
|
||||
}
|
||||
}
|
||||
/* stack zone defaults to plain-stub addr: every register
|
||||
* popped from untouched stack becomes callable (returns 0). */
|
||||
/* PBL stub at 0x080068C0 (52B, from qemu/pbl.S): BLX to SBL1
|
||||
* entry, then canonical regs + jump to sbl_main. Used when
|
||||
* sblmain prop is unset (default): faithful PBL call flow. */
|
||||
{
|
||||
uint32_t fill = 0x08006831;
|
||||
static const uint8_t pbl[] = {
|
||||
0xf0, 0xb5, 0x46, 0xf6, 0x81, 0x3c, 0xc0, 0xf6,
|
||||
0x00, 0x0c, 0xe0, 0x47, 0x40, 0xf2, 0x00, 0x00,
|
||||
0xc0, 0xf2, 0x22, 0x00, 0x05, 0x46, 0x40, 0xf2,
|
||||
0x00, 0x0a, 0xc0, 0xf6, 0x06, 0x0a, 0x41, 0xf2,
|
||||
0x00, 0x0b, 0xc0, 0xf6, 0x06, 0x0b, 0x4f, 0xf2,
|
||||
0x3f, 0x6e, 0xc0, 0xf6, 0x02, 0x0e, 0x70, 0x47,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
size_t k;
|
||||
for (k = 0; k < sizeof(pbl); k += 4) {
|
||||
uint32_t word = 0;
|
||||
size_t n = sizeof(pbl) - k < 4 ? sizeof(pbl) - k : 4;
|
||||
__builtin_memcpy(&word, &pbl[k], n);
|
||||
cpu_physical_memory_write(0x080068C0 + k, &word, 4);
|
||||
}
|
||||
}
|
||||
/* S7 stublet at 0x08006C10 (52B, b18): delay-epilogue exit
|
||||
* router. cmp r4,#0xff: iterate (r4<=0xff -> 0x8013ba5) or
|
||||
* done (restore r4/r5/sl/fp, return to sbl_main 0x802f681).
|
||||
* Assembled with keystone (see docs/sbl-bringup.md). */
|
||||
{
|
||||
static const uint8_t s7[] = {
|
||||
0xff, 0x2c, 0x13, 0xd9, 0x40, 0xf2, 0x00, 0x04,
|
||||
0xc0, 0xf2, 0x22, 0x04, 0x40, 0xf2, 0x00, 0x05,
|
||||
0xc0, 0xf2, 0x22, 0x05, 0x40, 0xf2, 0x00, 0x0a,
|
||||
0xc0, 0xf6, 0x06, 0x0a, 0x41, 0xf2, 0x00, 0x0b,
|
||||
0xc0, 0xf6, 0x06, 0x0b, 0xdf, 0xf8, 0x00, 0xf0,
|
||||
0x81, 0xf6, 0x02, 0x08, 0xdf, 0xf8, 0x00, 0xf0,
|
||||
0xa5, 0x3b, 0x01, 0x08,
|
||||
};
|
||||
size_t k;
|
||||
for (k = 0; k < sizeof(s7); k += 4) {
|
||||
uint32_t word = 0;
|
||||
size_t n = sizeof(s7) - k < 4 ? sizeof(s7) - k : 4;
|
||||
__builtin_memcpy(&word, &s7[k], n);
|
||||
cpu_physical_memory_write(0x08006C10 + k, &word, 4);
|
||||
}
|
||||
}
|
||||
{
|
||||
uint32_t fill = 0x08006B8D;
|
||||
uint32_t a;
|
||||
for (a = 0x085F0000; a < 0x08600000; a += 4) {
|
||||
cpu_physical_memory_write(a, &fill, 4);
|
||||
@@ -612,6 +702,20 @@ static void saimaa_machine_init(MachineState *machine)
|
||||
printf("saimaa: uefi tables live\n");
|
||||
}
|
||||
printf("saimaa: slots live\n");
|
||||
/* DDRLOW stub trap overlay: snapshot ELF+stubs, serve on
|
||||
* read/fetch, ignore heap writes (uni parity). Must come
|
||||
* AFTER all stub writes above. Priority 2 > RAMs' 1. */
|
||||
cpu_physical_memory_read(SAIMAA_DSTUB_BASE, saimaa_dstub_mem,
|
||||
SAIMAA_DSTUB_SIZE);
|
||||
{
|
||||
MemoryRegion *dstub = g_new(MemoryRegion, 1);
|
||||
memory_region_init_io(dstub, NULL, &saimaa_dstub_ops,
|
||||
NULL, "saimaa-dstub",
|
||||
SAIMAA_DSTUB_SIZE);
|
||||
memory_region_add_subregion_overlap(sysmem,
|
||||
SAIMAA_DSTUB_BASE,
|
||||
dstub, 2);
|
||||
}
|
||||
/* Freeze stubs: any SBL write here now faults loudly
|
||||
* (data abort with DFAR) instead of silent corruption. */
|
||||
memory_region_set_readonly(saimaa_stubs_mr, true);
|
||||
@@ -624,7 +728,7 @@ static void saimaa_machine_init(MachineState *machine)
|
||||
|
||||
static void saimaa_post_reset(void *opaque)
|
||||
{
|
||||
uint32_t S = 0x08006820;
|
||||
uint32_t S = 0x08006B80;
|
||||
(void)opaque;
|
||||
/* Re-apply pokes that live inside ROM-covered ranges (rom_reset
|
||||
* restores file bytes over them). */
|
||||
|
||||
Reference in New Issue
Block a user