saimaa: direct sbl_main start, SMEM, null-page trap; sbl analysis tools; sbl_main=0x802f63e
This commit is contained in:
+320
@@ -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)
|
||||
@@ -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("<I", d[28:32])[0]
|
||||
phnum = struct.unpack("<H", d[44:46])[0]
|
||||
for k in range(phnum):
|
||||
p = d[phoff + k * 32:phoff + (k + 1) * 32]
|
||||
t, off, v, pa, fsz, msz, fl, al = struct.unpack("<IIIIIIII", p)
|
||||
if t == 1 and off <= i < off + fsz:
|
||||
svas[s] = v + (i - off)
|
||||
for s, va in svas.items():
|
||||
print(s.decode(), "VA:", hex(va))
|
||||
|
||||
phoff = struct.unpack("<I", d[28:32])[0]
|
||||
phnum = struct.unpack("<H", d[44:46])[0]
|
||||
segs = []
|
||||
for k in range(phnum):
|
||||
p = d[phoff + k * 32:phoff + (k + 1) * 32]
|
||||
t, off, v, pa, fsz, msz, fl, al = struct.unpack("<IIIIIIII", p)
|
||||
if t == 1 and fsz and (fl & 1 or True):
|
||||
segs.append((off, v, fsz))
|
||||
for s, va in svas.items():
|
||||
print("--- refs to", s.decode(), hex(va))
|
||||
n = 0
|
||||
for off, v, sz in segs:
|
||||
code = d[off:off + sz]
|
||||
for j in range(0, len(code) - 4, 4):
|
||||
x = struct.unpack("<I", code[j:j + 4])[0]
|
||||
# ADD Rd,pc,#imm12 rotated; SUB Rd,pc,#imm
|
||||
if (x & 0x0FFF0000) in (0x028F0000, 0x024F0000):
|
||||
imm = x & 0xFFF
|
||||
rot = (x & 0xF00) >> 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
|
||||
@@ -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("<I", d[28:32])[0]
|
||||
phnum = struct.unpack("<H", d[44:46])[0]
|
||||
segs = []
|
||||
for k in range(phnum):
|
||||
p = d[phoff + k * 32:phoff + (k + 1) * 32]
|
||||
t, off, v, pa, fsz, msz, fl, al = struct.unpack("<IIIIIIII", p)
|
||||
if t == 1 and fsz:
|
||||
segs.append((off, v, fsz))
|
||||
|
||||
# prologues: STMDB sp!,{...,lr} (bit11 set)
|
||||
cands = []
|
||||
for off, v, sz in segs:
|
||||
code = d[off:off + sz]
|
||||
for j in range(0, len(code) - 4, 4):
|
||||
x = struct.unpack("<I", code[j:j + 4])[0]
|
||||
if (x & 0xFFFF0000) == 0xE92D0000: # push ... r11?/lr frame
|
||||
# count BLs in next 2KB
|
||||
bls = 0
|
||||
for q in range(j, min(j + 2048, len(code) - 4), 4):
|
||||
y = struct.unpack("<I", code[q:q + 4])[0]
|
||||
if (y >> 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}")
|
||||
@@ -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("<I", d[28:32])[0]
|
||||
phnum = struct.unpack("<H", d[44:46])[0]
|
||||
out = []
|
||||
for k in range(phnum):
|
||||
p = d[phoff + k * 32:phoff + (k + 1) * 32]
|
||||
t, off, v, pa, fsz, msz, fl, al = struct.unpack("<IIIIIIII", p)
|
||||
if t == 1 and fsz:
|
||||
out.append((off, v, fsz))
|
||||
return out
|
||||
|
||||
for soff, v, sz in segs(d):
|
||||
code = d[soff:soff + sz]
|
||||
for j in range(0, len(code) - 4, 4):
|
||||
x = struct.unpack("<I", code[j:j + 4])[0]
|
||||
# LDR Rd,[pc,#imm] (0x059Fxxxx) or LDR Rd,[pc,#-imm] (0x051Fxxxx)
|
||||
if (x & 0x0FF00000) in (0x05900000, 0x05100000) and (x & 0xF0000) == 0xF0000:
|
||||
o = x & 0xFFF
|
||||
tgt = v + j + 8 + (-o if x & 0x800000 == 0 else o)
|
||||
if abs(tgt - va) < 0x200:
|
||||
print(hex(v + j), "LDR r%d" % ((x >> 12) & 15), "->", hex(tgt))
|
||||
Reference in New Issue
Block a user