diff --git a/qemu/saimaa.c b/qemu/saimaa.c new file mode 100644 index 0000000..87cb428 --- /dev/null +++ b/qemu/saimaa.c @@ -0,0 +1,249 @@ +/* + * 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 "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 "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 + +/* ---- minimal MSM UARTDM stub: TX prints, status always ready ---- */ +#define TYPE_SAIMAA_UART "saimaa-uart" +OBJECT_DECLARE_SIMPLE_TYPE(SaimaaUartState, SAIMAA_UART) + +struct SaimaaUartState { + SysBusDevice parent_obj; + MemoryRegion iomem; + CharBackend chr; +}; + +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); + if (off == 0x70) { /* UARTDM_TF */ + uint8_t ch = val & 0xff; + qemu_chr_fe_write_all(&s->chr, &ch, 1); + 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) +{ + SaimaaUartState *s = SAIMAA_UART(dev); + if (!qemu_chr_fe_backend_connected(&s->chr)) { + error_setg(errp, "saimaa-uart: chardev property was not set"); + return; + } +} + +/* ---- machine ---- */ +struct SaimaaMachineState { + MachineState parent_obj; + char *sbl1; + char *emmc; +}; +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 }, + }; + for (i = 0; i < 4; 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(TYPE_ARM_CPU); + object_property_set_str(cpuobj, "cortex-a7", "model", + &error_fatal); + object_property_set_int(cpuobj, "mp-affinity", i, &error_fatal); + if (i > 0) { + object_property_set_bool(cpuobj, true, "start-powered-off", + &error_fatal); + } + object_property_set_bool(cpuobj, true, "realized", &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: stdio */ + DeviceState *uart = qdev_new(TYPE_SAIMAA_UART); + qdev_prop_set_chr(uart, "chardev", serial_hd(0)); + sysbus_realize(SYS_BUS_DEVICE(uart), &error_fatal); + sysbus_mmio_map(SYS_BUS_DEVICE(uart), 0, SAIMAA_UART_BASE); + + /* 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), + &error_fatal); + 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); + } + cpu_set_pc(first_cpu, entry); + printf("saimaa: SBL1 %s loaded (%zd bytes), entry 0x%lx\n", + sms->sbl1, sz, (unsigned long)entry); + } +} + +static Property saimaa_uart_props[] = { + DEFINE_PROP_CHR("chardev", SaimaaUartState, chr), + DEFINE_PROP_END_OF_LIST(), +}; + +static void saimaa_uart_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + dc->realize = saimaa_uart_realize; + device_class_set_props(dc, saimaa_uart_props); +} + +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 void saimaa_machine_instance_init(Object *obj) +{ + SaimaaMachineState *sms = SAIMAA_MACHINE(obj); + sms->sbl1 = NULL; + sms->emmc = NULL; + object_property_add_str(obj, "sbl1", saimaa_get_sbl1, saimaa_set_sbl1); +} + +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/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("