From e01813b60ef42f21571362f705667fbd234ea580 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Fri, 23 Dec 2022 23:05:42 +0100 Subject: [PATCH 01/58] Started working on iPod Touch 2G --- configs/devices/arm-softmmu/default.mak | 1 + hw/arm/Kconfig | 4 + hw/arm/ipod_touch_2g.c | 162 ++++++++++++++++++++++++ hw/arm/ipod_touch_chipid.c | 51 ++++++++ hw/arm/ipod_touch_clock.c | 139 ++++++++++++++++++++ hw/arm/ipod_touch_gpio.c | 62 +++++++++ hw/arm/meson.build | 1 + include/hw/arm/ipod_touch_2g.h | 44 +++++++ include/hw/arm/ipod_touch_chipid.h | 19 +++ include/hw/arm/ipod_touch_clock.h | 68 ++++++++++ include/hw/arm/ipod_touch_gpio.h | 28 ++++ 11 files changed, 579 insertions(+) create mode 100644 hw/arm/ipod_touch_2g.c create mode 100644 hw/arm/ipod_touch_chipid.c create mode 100644 hw/arm/ipod_touch_clock.c create mode 100644 hw/arm/ipod_touch_gpio.c create mode 100644 include/hw/arm/ipod_touch_2g.h create mode 100644 include/hw/arm/ipod_touch_chipid.h create mode 100644 include/hw/arm/ipod_touch_clock.h create mode 100644 include/hw/arm/ipod_touch_gpio.h diff --git a/configs/devices/arm-softmmu/default.mak b/configs/devices/arm-softmmu/default.mak index 6985a25377a0..a336eb5c9a00 100644 --- a/configs/devices/arm-softmmu/default.mak +++ b/configs/devices/arm-softmmu/default.mak @@ -42,3 +42,4 @@ CONFIG_FSL_IMX6UL=y CONFIG_SEMIHOSTING=y CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y CONFIG_ALLWINNER_H3=y +CONFIG_IPOD_TOUCH_2G=y \ No newline at end of file diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index 17fcde8e1ccc..b856c493f4ca 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -568,3 +568,7 @@ config ARMSSE select UNIMP select SSE_COUNTER select SSE_TIMER + +config IPOD_TOUCH_2G + bool + select IPOD_TOUCH_2G \ No newline at end of file diff --git a/hw/arm/ipod_touch_2g.c b/hw/arm/ipod_touch_2g.c new file mode 100644 index 000000000000..6122623aae4e --- /dev/null +++ b/hw/arm/ipod_touch_2g.c @@ -0,0 +1,162 @@ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/arm/boot.h" +#include "exec/address-spaces.h" +#include "hw/misc/unimp.h" +#include "hw/irq.h" +#include "sysemu/sysemu.h" +#include "sysemu/reset.h" +#include "hw/platform-bus.h" +#include "hw/block/flash.h" +#include "hw/qdev-clock.h" +#include "hw/arm/ipod_touch_2g.h" +#include "target/arm/cpregs.h" + +#define VMSTATE_IT2G_CPREG(name) \ + VMSTATE_UINT64(IT2G_CPREG_VAR_NAME(name), IPodTouchMachineState) + +#define IT2G_CPREG_DEF(p_name, p_op0, p_op1, p_crn, p_crm, p_op2, p_access, p_reset) \ + { \ + .cp = 15, \ + .name = #p_name, .opc0 = p_op0, .crn = p_crn, .crm = p_crm, \ + .opc1 = p_op1, .opc2 = p_op2, .access = p_access, .resetvalue = p_reset, \ + .state = ARM_CP_STATE_AA32, .type = ARM_CP_OVERRIDE, \ + .fieldoffset = offsetof(IPodTouchMachineState, IT2G_CPREG_VAR_NAME(p_name)) \ + - offsetof(ARMCPU, env) \ + } + +static void allocate_ram(MemoryRegion *top, const char *name, uint32_t addr, uint32_t size) +{ + MemoryRegion *sec = g_new(MemoryRegion, 1); + memory_region_init_ram(sec, NULL, name, size, &error_fatal); + memory_region_add_subregion(top, addr, sec); +} + +static const ARMCPRegInfo it2g_cp_reginfo_tcg[] = { + IT2G_CPREG_DEF(REG0, 0, 0, 7, 6, 0, PL1_RW, 0), + IT2G_CPREG_DEF(REG1, 0, 0, 15, 2, 4, PL1_RW, 0), +}; + +static void ipod_touch_cpu_setup(MachineState *machine, MemoryRegion **sysmem, ARMCPU **cpu, AddressSpace **nsas) +{ + Object *cpuobj = object_new(machine->cpu_type); + *cpu = ARM_CPU(cpuobj); + CPUState *cs = CPU(*cpu); + + *sysmem = get_system_memory(); + + object_property_set_link(cpuobj, "memory", OBJECT(*sysmem), &error_abort); + + object_property_set_bool(cpuobj, "has_el3", false, NULL); + + object_property_set_bool(cpuobj, "has_el2", false, NULL); + + object_property_set_bool(cpuobj, "realized", true, &error_fatal); + + *nsas = cpu_get_address_space(cs, ARMASIdx_NS); + + define_arm_cp_regs(*cpu, it2g_cp_reginfo_tcg); + + object_unref(cpuobj); +} + +static void ipod_touch_cpu_reset(void *opaque) +{ + IPodTouchMachineState *nms = IPOD_TOUCH_MACHINE((MachineState *)opaque); + ARMCPU *cpu = nms->cpu; + CPUState *cs = CPU(cpu); + + cpu_reset(cs); + + //env->regs[0] = nms->kbootargs_pa; + //cpu_set_pc(CPU(cpu), 0xc00607ec); + cpu_set_pc(CPU(cpu), VROM_MEM_BASE); + //env->regs[0] = 0x9000000; + //cpu_set_pc(CPU(cpu), LLB_BASE + 0x100); + //cpu_set_pc(CPU(cpu), VROM_MEM_BASE); +} + +static void ipod_touch_memory_setup(MachineState *machine, MemoryRegion *sysmem, AddressSpace *nsas) +{ + IPodTouchMachineState *nms = IPOD_TOUCH_MACHINE(machine); + + allocate_ram(sysmem, "sram1", SRAM1_MEM_BASE, 0x100000); + + // load the bootrom (vrom) + uint8_t *file_data = NULL; + unsigned long fsize; + if (g_file_get_contents("/Users/martijndevos/Documents/ipod_touch_2g_emulation/bootrom_240_4", (char **)&file_data, &fsize, NULL)) { + allocate_ram(sysmem, "vrom", 0x0, 0x20000); + address_space_rw(nsas, VROM_MEM_BASE, MEMTXATTRS_UNSPECIFIED, (uint8_t *)file_data, fsize, 1); + } +} + +static void ipod_touch_instance_init(Object *obj) +{ + +} + +static void ipod_touch_machine_init(MachineState *machine) +{ + IPodTouchMachineState *nms = IPOD_TOUCH_MACHINE(machine); + MemoryRegion *sysmem; + AddressSpace *nsas; + ARMCPU *cpu; + + ipod_touch_cpu_setup(machine, &sysmem, &cpu, &nsas); + + nms->cpu = cpu; + + // init clock 0 + DeviceState *dev = qdev_new("ipodtouch.clock"); + IPodTouchClockState *clock0_state = IPOD_TOUCH_CLOCK(dev); + nms->clock0 = clock0_state; + memory_region_add_subregion(sysmem, CLOCK0_MEM_BASE, &clock0_state->iomem); + + // init clock 1 + dev = qdev_new("ipodtouch.clock"); + IPodTouchClockState *clock1_state = IPOD_TOUCH_CLOCK(dev); + nms->clock1 = clock1_state; + memory_region_add_subregion(sysmem, CLOCK1_MEM_BASE, &clock1_state->iomem); + + // init GPIO + dev = qdev_new("ipodtouch.gpio"); + IPodTouchGPIOState *gpio_state = IPOD_TOUCH_GPIO(dev); + nms->gpio_state = gpio_state; + memory_region_add_subregion(sysmem, GPIO_MEM_BASE, &gpio_state->iomem); + + // init the chip ID module + dev = qdev_new("ipodtouch.chipid"); + IPodTouchChipIDState *chipid_state = IPOD_TOUCH_CHIPID(dev); + nms->chipid_state = chipid_state; + memory_region_add_subregion(sysmem, CHIPID_MEM_BASE, &chipid_state->iomem); + + ipod_touch_memory_setup(machine, sysmem, nsas); + + qemu_register_reset(ipod_touch_cpu_reset, nms); +} + +static void ipod_touch_machine_class_init(ObjectClass *klass, void *data) +{ + MachineClass *mc = MACHINE_CLASS(klass); + mc->desc = "iPod Touch"; + mc->init = ipod_touch_machine_init; + mc->max_cpus = 1; + mc->default_cpu_type = ARM_CPU_TYPE_NAME("arm1176"); +} + +static const TypeInfo ipod_touch_machine_info = { + .name = TYPE_IPOD_TOUCH_MACHINE, + .parent = TYPE_MACHINE, + .instance_size = sizeof(IPodTouchMachineState), + .class_size = sizeof(IPodTouchMachineClass), + .class_init = ipod_touch_machine_class_init, + .instance_init = ipod_touch_instance_init, +}; + +static void ipod_touch_machine_types(void) +{ + type_register_static(&ipod_touch_machine_info); +} + +type_init(ipod_touch_machine_types) \ No newline at end of file diff --git a/hw/arm/ipod_touch_chipid.c b/hw/arm/ipod_touch_chipid.c new file mode 100644 index 000000000000..e7cbc5d31716 --- /dev/null +++ b/hw/arm/ipod_touch_chipid.c @@ -0,0 +1,51 @@ +#include "hw/arm/ipod_touch_chipid.h" + +static uint64_t ipod_touch_chipid_read(void *opaque, hwaddr addr, unsigned size) +{ + //fprintf(stderr, "%s: offset = 0x%08x\n", __func__, addr); + + switch (addr) { + case CHIPID_UNKNOWN1: + return 0; + case CHIPID_INFO: + return (0x8720 << 16) | 0x1; + default: + hw_error("%s: reading from unknown chip ID register 0x%08x\n", __func__, addr); + } + + return 0; +} + +static const MemoryRegionOps ipod_touch_chipid_ops = { + .read = ipod_touch_chipid_read, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void ipod_touch_chipid_init(Object *obj) +{ + IPodTouchChipIDState *s = IPOD_TOUCH_CHIPID(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &ipod_touch_chipid_ops, s, TYPE_IPOD_TOUCH_CHIPID, 0x10); + sysbus_init_mmio(sbd, &s->iomem); +} + +static void ipod_touch_chipid_class_init(ObjectClass *klass, void *data) +{ + +} + +static const TypeInfo ipod_touch_chipid_type_info = { + .name = TYPE_IPOD_TOUCH_CHIPID, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IPodTouchChipIDState), + .instance_init = ipod_touch_chipid_init, + .class_init = ipod_touch_chipid_class_init, +}; + +static void ipod_touch_chipid_register_types(void) +{ + type_register_static(&ipod_touch_chipid_type_info); +} + +type_init(ipod_touch_chipid_register_types) \ No newline at end of file diff --git a/hw/arm/ipod_touch_clock.c b/hw/arm/ipod_touch_clock.c new file mode 100644 index 000000000000..e9b9d2282168 --- /dev/null +++ b/hw/arm/ipod_touch_clock.c @@ -0,0 +1,139 @@ +#include "hw/arm/ipod_touch_clock.h" + +static void s5l8900_clock_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) +{ + IPodTouchClockState *s = (struct IPodTouchClockState *) opaque; + + switch (addr) { + case CLOCK_CONFIG0: + s->config0 = val; + break; + case CLOCK_CONFIG1: + s->config1 = val; + break; + case CLOCK_CONFIG2: + s->config2 = val; + break; + case CLOCK_CONFIG3: + s->config3 = val; + break; + case CLOCK_CONFIG4: + s->config4 = val; + break; + case CLOCK_CONFIG5: + s->config5 = val; + break; + + case CLOCK_PLL0CON: + s->pll0con = val; + break; + case CLOCK_PLL1CON: + s->pll1con = val; + break; + case CLOCK_PLL2CON: + s->pll2con = val; + break; + case CLOCK_PLL3CON: + s->pll3con = val; + break; + case CLOCK_PLL0LCNT: + s->pll0lcnt = val; + break; + case CLOCK_PLL1LCNT: + s->pll1lcnt = val; + break; + case CLOCK_PLL2LCNT: + s->pll2lcnt = val; + break; + case CLOCK_PLL3LCNT: + s->pll3lcnt = val; + break; + case CLOCK_PLLLOCK: + hw_error("%s: Forbidden write to PLLLOCK register 0x%08x\n", __func__, addr); + break; + case CLOCK_PLLMODE: + s->pllmode = val; + break; + case CLOCK_PWRCON0: + s->pwrcon0 = val; + break; + case CLOCK_PWRCON1: + s->pwrcon1 = val; + break; + case CLOCK_PWRCON2: + s->pwrcon2 = val; + break; + case CLOCK_PWRCON3: + s->pwrcon3 = val; + break; + case CLOCK_PWRCON4: + s->pwrcon4 = val; + break; + default: + hw_error("%s: writing value 0x%08x to unknown clock register 0x%08x\n", __func__, val, addr); + } +} + +static uint64_t s5l8900_clock_read(void *opaque, hwaddr addr, unsigned size) +{ + IPodTouchClockState *s = (struct IPodTouchClockState *) opaque; + + switch (addr) { + case CLOCK_CONFIG0: + return s->config0; + case CLOCK_CONFIG1: + return s->config1; + case CLOCK_CONFIG2: + return s->config2; + case CLOCK_PLL0CON: + return s->pll0con; + case CLOCK_PLL1CON: + return s->pll1con; + case CLOCK_PLL2CON: + return s->pll2con; + case CLOCK_PLL3CON: + return s->pll3con; + case CLOCK_PLLLOCK: + return (1 | 2 | 4 | 8); // all PLLs are locked + case CLOCK_PLLMODE: + return s->pllmode; + default: + hw_error("%s: reading from unknown clock register 0x%08x\n", __func__, addr); + } + return 0; +} + +static const MemoryRegionOps clock_ops = { + .read = s5l8900_clock_read, + .write = s5l8900_clock_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void s5l8900_clock_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(sbd); + IPodTouchClockState *s = IPOD_TOUCH_CLOCK(dev); + + memory_region_init_io(&s->iomem, obj, &clock_ops, s, "clock", 0x80); +} + +static void s5l8900_clock_class_init(ObjectClass *klass, void *data) +{ + +} + +static const TypeInfo ipod_touch_clock_info = { + .name = TYPE_IPOD_TOUCH_CLOCK, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IPodTouchClockState), + .instance_init = s5l8900_clock_init, + .class_init = s5l8900_clock_class_init, +}; + +static void ipod_touch_machine_types(void) +{ + type_register_static(&ipod_touch_clock_info); +} + +type_init(ipod_touch_machine_types) \ No newline at end of file diff --git a/hw/arm/ipod_touch_gpio.c b/hw/arm/ipod_touch_gpio.c new file mode 100644 index 000000000000..6cca0dddd6ef --- /dev/null +++ b/hw/arm/ipod_touch_gpio.c @@ -0,0 +1,62 @@ +#include "hw/arm/ipod_touch_gpio.h" + +static void s5l8900_gpio_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) +{ + //fprintf(stderr, "%s: writing 0x%08x to 0x%08x\n", __func__, value, addr); + IPodTouchGPIOState *s = (struct IPodTouchGPIOState *) opaque; + + switch(addr) { + default: + break; + } +} + +static uint64_t s5l8900_gpio_read(void *opaque, hwaddr addr, unsigned size) +{ + //fprintf(stderr, "%s: read from location 0x%08x\n", __func__, addr); + IPodTouchGPIOState *s = (struct IPodTouchGPIOState *) opaque; + + switch(addr) { + case 0x2c4: + return s->gpio_state; + default: + break; + } + + return 0; +} + +static const MemoryRegionOps gpio_ops = { + .read = s5l8900_gpio_read, + .write = s5l8900_gpio_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void s5l8900_gpio_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(sbd); + IPodTouchGPIOState *s = IPOD_TOUCH_GPIO(dev); + + memory_region_init_io(&s->iomem, obj, &gpio_ops, s, "gpio", 0x10000); +} + +static void s5l8900_gpio_class_init(ObjectClass *klass, void *data) +{ + +} + +static const TypeInfo ipod_touch_gpio_info = { + .name = TYPE_IPOD_TOUCH_GPIO, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IPodTouchGPIOState), + .instance_init = s5l8900_gpio_init, + .class_init = s5l8900_gpio_class_init, +}; + +static void ipod_touch_machine_types(void) +{ + type_register_static(&ipod_touch_gpio_info); +} + +type_init(ipod_touch_machine_types) \ No newline at end of file diff --git a/hw/arm/meson.build b/hw/arm/meson.build index 92f9f6e000ea..d3646277c4da 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -62,5 +62,6 @@ arm_ss.add(when: 'CONFIG_FSL_IMX7', if_true: files('fsl-imx7.c', 'mcimx7d-sabre. arm_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c', 'smmuv3.c')) arm_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c')) arm_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c')) +arm_ss.add(when: 'CONFIG_IPOD_TOUCH_2G', if_true: files('ipod_touch_2g.c', 'ipod_touch_clock.c', 'ipod_touch_chipid.c', 'ipod_touch_gpio.c')) hw_arch += {'arm': arm_ss} diff --git a/include/hw/arm/ipod_touch_2g.h b/include/hw/arm/ipod_touch_2g.h new file mode 100644 index 000000000000..011f85cb0f14 --- /dev/null +++ b/include/hw/arm/ipod_touch_2g.h @@ -0,0 +1,44 @@ +#ifndef HW_ARM_IPOD_TOUCH_H +#define HW_ARM_IPOD_TOUCH_H + +#include "exec/hwaddr.h" +#include "hw/boards.h" +#include "hw/arm/boot.h" +#include "cpu.h" +#include "hw/arm/ipod_touch_clock.h" +#include "hw/arm/ipod_touch_chipid.h" +#include "hw/arm/ipod_touch_gpio.h" + +#define TYPE_IPOD_TOUCH "iPod-Touch" + +#define IT2G_CPREG_VAR_NAME(name) cpreg_##name +#define IT2G_CPREG_VAR_DEF(name) uint64_t IT2G_CPREG_VAR_NAME(name) + +#define TYPE_IPOD_TOUCH_MACHINE MACHINE_TYPE_NAME(TYPE_IPOD_TOUCH) +#define IPOD_TOUCH_MACHINE(obj) \ + OBJECT_CHECK(IPodTouchMachineState, (obj), TYPE_IPOD_TOUCH_MACHINE) + +// memory addresses +#define VROM_MEM_BASE 0x0 +#define SRAM1_MEM_BASE 0x22020000 +#define CLOCK0_MEM_BASE 0x3C500000 +#define GPIO_MEM_BASE 0x3CF00000 +#define CHIPID_MEM_BASE 0x3D100000 +#define CLOCK1_MEM_BASE 0x3E000000 + +typedef struct { + MachineClass parent; +} IPodTouchMachineClass; + +typedef struct { + MachineState parent; + ARMCPU *cpu; + IPodTouchClockState *clock0; + IPodTouchClockState *clock1; + IPodTouchChipIDState *chipid_state; + IPodTouchGPIOState *gpio_state; + IT2G_CPREG_VAR_DEF(REG0); + IT2G_CPREG_VAR_DEF(REG1); +} IPodTouchMachineState; + +#endif \ No newline at end of file diff --git a/include/hw/arm/ipod_touch_chipid.h b/include/hw/arm/ipod_touch_chipid.h new file mode 100644 index 000000000000..c6755b9fcf0d --- /dev/null +++ b/include/hw/arm/ipod_touch_chipid.h @@ -0,0 +1,19 @@ +#ifndef HW_ARM_IPOD_TOUCH_CHIPID_H +#define HW_ARM_IPOD_TOUCH_CHIPID_H + +#include "qemu/osdep.h" +#include "hw/hw.h" +#include "hw/sysbus.h" + +#define TYPE_IPOD_TOUCH_CHIPID "ipodtouch.chipid" +OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchChipIDState, IPOD_TOUCH_CHIPID) + +#define CHIPID_UNKNOWN1 0x4 +#define CHIPID_INFO 0x8 + +typedef struct IPodTouchChipIDState { + SysBusDevice busdev; + MemoryRegion iomem; +} IPodTouchChipIDState; + +#endif \ No newline at end of file diff --git a/include/hw/arm/ipod_touch_clock.h b/include/hw/arm/ipod_touch_clock.h new file mode 100644 index 000000000000..194cdfb8a82d --- /dev/null +++ b/include/hw/arm/ipod_touch_clock.h @@ -0,0 +1,68 @@ +#ifndef IPOD_TOUCH_CLOCK_H +#define IPOD_TOUCH_CLOCK_H + +#include "qemu/osdep.h" +#include "qemu/module.h" +#include "qemu/timer.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/irq.h" +#include "hw/clock.h" + +#define TYPE_IPOD_TOUCH_CLOCK "ipodtouch.clock" +OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchClockState, IPOD_TOUCH_CLOCK) + +#define CLOCK_CONFIG0 0x0 +#define CLOCK_CONFIG1 0x4 +#define CLOCK_CONFIG2 0x8 +#define CLOCK_CONFIG3 0xC +#define CLOCK_CONFIG4 0x10 +#define CLOCK_CONFIG5 0x14 + +#define CLOCK_PLL0CON 0x20 +#define CLOCK_PLL1CON 0x24 +#define CLOCK_PLL2CON 0x28 +#define CLOCK_PLL3CON 0x2C +#define CLOCK_PLL0LCNT 0x30 +#define CLOCK_PLL1LCNT 0x34 +#define CLOCK_PLL2LCNT 0x38 +#define CLOCK_PLL3LCNT 0x3C +#define CLOCK_PLLLOCK 0x40 +#define CLOCK_PLLMODE 0x44 + +#define CLOCK_PWRCON0 0x48 +#define CLOCK_PWRCON1 0x4C +#define CLOCK_PWRCON2 0x58 +#define CLOCK_PWRCON3 0x68 +#define CLOCK_PWRCON4 0x6C + +typedef struct IPodTouchClockState +{ + SysBusDevice busdev; + MemoryRegion iomem; + uint32_t config0; + uint32_t config1; + uint32_t config2; + uint32_t config3; + uint32_t config4; + uint32_t config5; + + uint32_t pll0con; + uint32_t pll1con; + uint32_t pll2con; + uint32_t pll3con; + uint32_t pll0lcnt; + uint32_t pll1lcnt; + uint32_t pll2lcnt; + uint32_t pll3lcnt; + uint32_t pllmode; + + uint32_t pwrcon0; + uint32_t pwrcon1; + uint32_t pwrcon2; + uint32_t pwrcon3; + uint32_t pwrcon4; + +} IPodTouchClockState; + +#endif \ No newline at end of file diff --git a/include/hw/arm/ipod_touch_gpio.h b/include/hw/arm/ipod_touch_gpio.h new file mode 100644 index 000000000000..1707e39a76e8 --- /dev/null +++ b/include/hw/arm/ipod_touch_gpio.h @@ -0,0 +1,28 @@ +#ifndef IPOD_TOUCH_GPIO_H +#define IPOD_TOUCH_GPIO_H + +#include +#include "qemu/osdep.h" +#include "qemu/module.h" +#include "qemu/timer.h" +#include "hw/sysbus.h" + +#define TYPE_IPOD_TOUCH_GPIO "ipodtouch.gpio" +OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchGPIOState, IPOD_TOUCH_GPIO) + +#define GPIO_BUTTON_POWER 0x1605 +#define GPIO_BUTTON_HOME 0x1606 + +#define GPIO_BUTTON_POWER_IRQ 0x2D +#define GPIO_BUTTON_HOME_IRQ 0x2E + +#define NUM_GPIO_PINS 0x20 + +typedef struct IPodTouchGPIOState +{ + SysBusDevice parent_obj; + MemoryRegion iomem; + uint32_t gpio_state; +} IPodTouchGPIOState; + +#endif \ No newline at end of file From fefcf9020939d74acbf4231b5a29bb021c33e518 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Sat, 24 Dec 2022 15:59:19 +0100 Subject: [PATCH 02/58] More work on iPod Touch 2G emulation --- hw/arm/Kconfig | 3 +- hw/arm/ipod_touch_2g.c | 85 +++- hw/arm/ipod_touch_clock.c | 10 + hw/arm/ipod_touch_gpio.c | 2 +- hw/arm/ipod_touch_spi.c | 310 ++++++++++++++ hw/arm/ipod_touch_sysic.c | 129 ++++++ hw/arm/ipod_touch_timer.c | 143 +++++++ hw/arm/ipod_touch_usb_otg.c | 616 +++++++++++++++++++++++++++ hw/arm/ipod_touch_usb_phys.c | 84 ++++ hw/arm/meson.build | 2 +- hw/intc/Kconfig | 3 + hw/intc/meson.build | 1 + hw/intc/pl192.c | 439 +++++++++++++++++++ include/hw/arm/ipod_touch_2g.h | 36 ++ include/hw/arm/ipod_touch_spi.h | 82 ++++ include/hw/arm/ipod_touch_sysic.h | 43 ++ include/hw/arm/ipod_touch_timer.h | 52 +++ include/hw/arm/ipod_touch_usb_otg.h | 267 ++++++++++++ include/hw/arm/ipod_touch_usb_phys.h | 28 ++ include/hw/intc/pl192.h | 80 ++++ 20 files changed, 2411 insertions(+), 4 deletions(-) create mode 100644 hw/arm/ipod_touch_spi.c create mode 100644 hw/arm/ipod_touch_sysic.c create mode 100644 hw/arm/ipod_touch_timer.c create mode 100644 hw/arm/ipod_touch_usb_otg.c create mode 100644 hw/arm/ipod_touch_usb_phys.c create mode 100644 hw/intc/pl192.c create mode 100644 include/hw/arm/ipod_touch_spi.h create mode 100644 include/hw/arm/ipod_touch_sysic.h create mode 100644 include/hw/arm/ipod_touch_timer.h create mode 100644 include/hw/arm/ipod_touch_usb_otg.h create mode 100644 include/hw/arm/ipod_touch_usb_phys.h create mode 100644 include/hw/intc/pl192.h diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index b856c493f4ca..30ea9b616882 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -571,4 +571,5 @@ config ARMSSE config IPOD_TOUCH_2G bool - select IPOD_TOUCH_2G \ No newline at end of file + select IPOD_TOUCH_2G + select PL192 \ No newline at end of file diff --git a/hw/arm/ipod_touch_2g.c b/hw/arm/ipod_touch_2g.c index 6122623aae4e..6662f981f38f 100644 --- a/hw/arm/ipod_touch_2g.c +++ b/hw/arm/ipod_touch_2g.c @@ -80,6 +80,7 @@ static void ipod_touch_memory_setup(MachineState *machine, MemoryRegion *sysmem, { IPodTouchMachineState *nms = IPOD_TOUCH_MACHINE(machine); + allocate_ram(sysmem, "unknown", 0x22000000, 0x100000); allocate_ram(sysmem, "sram1", SRAM1_MEM_BASE, 0x100000); // load the bootrom (vrom) @@ -96,6 +97,18 @@ static void ipod_touch_instance_init(Object *obj) } +static inline qemu_irq s5l8900_get_irq(IPodTouchMachineState *s, int n) +{ + return s->irq[n / S5L8720_VIC_SIZE][n % S5L8720_VIC_SIZE]; +} + +static uint32_t s5l8720_usb_hwcfg[] = { + 0, + 0x7a8f60d0, + 0x082000e8, + 0x01f08024 +}; + static void ipod_touch_machine_init(MachineState *machine) { IPodTouchMachineState *nms = IPOD_TOUCH_MACHINE(machine); @@ -105,10 +118,33 @@ static void ipod_touch_machine_init(MachineState *machine) ipod_touch_cpu_setup(machine, &sysmem, &cpu, &nsas); + // setup clock + nms->sysclk = clock_new(OBJECT(machine), "SYSCLK"); + clock_set_hz(nms->sysclk, 12000000ULL); + nms->cpu = cpu; + // setup VICs + nms->irq = g_malloc0(sizeof(qemu_irq *) * 2); + DeviceState *dev = pl192_manual_init("vic0", qdev_get_gpio_in(DEVICE(nms->cpu), ARM_CPU_IRQ), qdev_get_gpio_in(DEVICE(nms->cpu), ARM_CPU_FIQ), NULL); + PL192State *s = PL192(dev); + nms->vic0 = s; + memory_region_add_subregion(sysmem, VIC0_MEM_BASE, &nms->vic0->iomem); + nms->irq[0] = g_malloc0(sizeof(qemu_irq) * 32); + for (int i = 0; i < 32; i++) { nms->irq[0][i] = qdev_get_gpio_in(dev, i); } + + dev = pl192_manual_init("vic1", NULL); + s = PL192(dev); + nms->vic1 = s; + memory_region_add_subregion(sysmem, VIC1_MEM_BASE, &nms->vic1->iomem); + nms->irq[1] = g_malloc0(sizeof(qemu_irq) * 32); + for (int i = 0; i < 32; i++) { nms->irq[1][i] = qdev_get_gpio_in(dev, i); } + + // // chain VICs together + nms->vic1->daisy = nms->vic0; + // init clock 0 - DeviceState *dev = qdev_new("ipodtouch.clock"); + dev = qdev_new("ipodtouch.clock"); IPodTouchClockState *clock0_state = IPOD_TOUCH_CLOCK(dev); nms->clock0 = clock0_state; memory_region_add_subregion(sysmem, CLOCK0_MEM_BASE, &clock0_state->iomem); @@ -119,18 +155,65 @@ static void ipod_touch_machine_init(MachineState *machine) nms->clock1 = clock1_state; memory_region_add_subregion(sysmem, CLOCK1_MEM_BASE, &clock1_state->iomem); + // init the timer + dev = qdev_new("ipodtouch.timer"); + IPodTouchTimerState *timer_state = IPOD_TOUCH_TIMER(dev); + nms->timer1 = timer_state; + memory_region_add_subregion(sysmem, TIMER1_MEM_BASE, &timer_state->iomem); + SysBusDevice *busdev = SYS_BUS_DEVICE(dev); + sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_TIMER1_IRQ)); + timer_state->sysclk = nms->sysclk; + + // init sysic + dev = qdev_new("ipodtouch.sysic"); + IPodTouchSYSICState *sysic_state = IPOD_TOUCH_SYSIC(dev); + nms->sysic = (IPodTouchSYSICState *) g_malloc0(sizeof(struct IPodTouchSYSICState)); + memory_region_add_subregion(sysmem, SYSIC_MEM_BASE, &sysic_state->iomem); + // busdev = SYS_BUS_DEVICE(dev); + // for(int grp = 0; grp < GPIO_NUMINTGROUPS; grp++) { + // sysbus_connect_irq(busdev, grp, s5l8900_get_irq(nms, S5L8900_GPIO_IRQS[grp])); + // } + // init GPIO dev = qdev_new("ipodtouch.gpio"); IPodTouchGPIOState *gpio_state = IPOD_TOUCH_GPIO(dev); nms->gpio_state = gpio_state; memory_region_add_subregion(sysmem, GPIO_MEM_BASE, &gpio_state->iomem); + // init spis + set_spi_base(0); + sysbus_create_simple("ipodtouch.spi", SPI0_MEM_BASE, s5l8900_get_irq(nms, S5L8720_SPI0_IRQ)); + + set_spi_base(1); + sysbus_create_simple("ipodtouch.spi", SPI1_MEM_BASE, s5l8900_get_irq(nms, S5L8720_SPI1_IRQ)); + + set_spi_base(2); + sysbus_create_simple("ipodtouch.spi", SPI2_MEM_BASE, s5l8900_get_irq(nms, S5L8720_SPI2_IRQ)); + + set_spi_base(3); + sysbus_create_simple("ipodtouch.spi", SPI3_MEM_BASE, s5l8900_get_irq(nms, S5L8720_SPI3_IRQ)); + + set_spi_base(4); + sysbus_create_simple("ipodtouch.spi", SPI4_MEM_BASE, s5l8900_get_irq(nms, S5L8720_SPI4_IRQ)); + // init the chip ID module dev = qdev_new("ipodtouch.chipid"); IPodTouchChipIDState *chipid_state = IPOD_TOUCH_CHIPID(dev); nms->chipid_state = chipid_state; memory_region_add_subregion(sysmem, CHIPID_MEM_BASE, &chipid_state->iomem); + // init USB OTG + dev = ipod_touch_init_usb_otg(s5l8900_get_irq(nms, S5L8720_USB_OTG_IRQ), s5l8720_usb_hwcfg); + synopsys_usb_state *usb_otg = S5L8900USBOTG(dev); + nms->usb_otg = usb_otg; + memory_region_add_subregion(sysmem, USBOTG_MEM_BASE, &nms->usb_otg->iomem); + + // init the chip ID module + dev = qdev_new("ipodtouch.usbphys"); + IPodTouchUSBPhysState *usb_phys_state = IPOD_TOUCH_USB_PHYS(dev); + nms->usb_phys_state = usb_phys_state; + memory_region_add_subregion(sysmem, USBPHYS_MEM_BASE, &usb_phys_state->iomem); + ipod_touch_memory_setup(machine, sysmem, nsas); qemu_register_reset(ipod_touch_cpu_reset, nms); diff --git a/hw/arm/ipod_touch_clock.c b/hw/arm/ipod_touch_clock.c index e9b9d2282168..3741af33aa53 100644 --- a/hw/arm/ipod_touch_clock.c +++ b/hw/arm/ipod_touch_clock.c @@ -97,6 +97,16 @@ static uint64_t s5l8900_clock_read(void *opaque, hwaddr addr, unsigned size) return (1 | 2 | 4 | 8); // all PLLs are locked case CLOCK_PLLMODE: return s->pllmode; + case CLOCK_PWRCON0: + return s->pwrcon0; + case CLOCK_PWRCON1: + return s->pwrcon1; + case CLOCK_PWRCON2: + return s->pwrcon2; + case CLOCK_PWRCON3: + return s->pwrcon3; + case CLOCK_PWRCON4: + return s->pwrcon4; default: hw_error("%s: reading from unknown clock register 0x%08x\n", __func__, addr); } diff --git a/hw/arm/ipod_touch_gpio.c b/hw/arm/ipod_touch_gpio.c index 6cca0dddd6ef..8941a505db49 100644 --- a/hw/arm/ipod_touch_gpio.c +++ b/hw/arm/ipod_touch_gpio.c @@ -18,7 +18,7 @@ static uint64_t s5l8900_gpio_read(void *opaque, hwaddr addr, unsigned size) switch(addr) { case 0x2c4: - return s->gpio_state; + return s->gpio_state; default: break; } diff --git a/hw/arm/ipod_touch_spi.c b/hw/arm/ipod_touch_spi.c new file mode 100644 index 000000000000..f27a188df9c7 --- /dev/null +++ b/hw/arm/ipod_touch_spi.c @@ -0,0 +1,310 @@ +/* + * S5L8900 SPI Emulation + * + * by cmw + */ + +#include "hw/arm/ipod_touch_spi.h" + +static int apple_spi_word_size(IPodTouchSPIState *s) +{ + switch (R_CFG_WORD_SIZE(REG(s, R_CFG))) { + case R_CFG_WORD_SIZE_8B: + return 1; + case R_CFG_WORD_SIZE_16B: + return 2; + case R_CFG_WORD_SIZE_32B: + return 4; + default: + break; + } + g_assert_not_reached(); +} + +static void apple_spi_update_xfer_tx(IPodTouchSPIState *s) +{ + if (fifo8_is_empty(&s->tx_fifo)) { + REG(s, R_STATUS) |= R_STATUS_TXEMPTY; + } +} + +static void apple_spi_update_xfer_rx(IPodTouchSPIState *s) +{ + if (!fifo8_is_empty(&s->rx_fifo)) { + REG(s, R_STATUS) |= R_STATUS_RXREADY; + } +} + +static void apple_spi_update_irq(IPodTouchSPIState *s) +{ + uint32_t irq = 0; + uint32_t mask = 0; + + if (REG(s, R_CFG) & R_CFG_IE_RXREADY) { + mask |= R_STATUS_RXREADY; + } + if (REG(s, R_CFG) & R_CFG_IE_TXEMPTY) { + mask |= R_STATUS_TXEMPTY; + } + if (REG(s, R_CFG) & R_CFG_IE_COMPLETE) { + mask |= R_STATUS_COMPLETE; + } + + if (REG(s, R_STATUS) & mask) { + irq = 1; + } + if (irq != s->last_irq) { + s->last_irq = irq; + qemu_set_irq(s->irq, irq); + } +} + +static void apple_spi_update_cs(IPodTouchSPIState *s) +{ + BusState *b = BUS(s->spi); + BusChild *kid = QTAILQ_FIRST(&b->children); + if (kid) { + // TODO GPIO not properly setup yet + //qemu_set_irq(qdev_get_gpio_in_named(kid->child, SSI_GPIO_CS, 0), (REG(s, R_PIN) & R_PIN_CS) != 0); + } +} + +static void apple_spi_cs_set(void *opaque, int pin, int level) +{ + IPodTouchSPIState *s = IPOD_TOUCH_SPI(opaque); + if (level) { + REG(s, R_PIN) |= R_PIN_CS; + } else { + REG(s, R_PIN) &= ~R_PIN_CS; + } + apple_spi_update_cs(s); +} + +static void apple_spi_run(IPodTouchSPIState *s) +{ + uint32_t tx; + uint32_t rx; + + if (!(REG(s, R_CTRL) & R_CTRL_RUN)) { + return; + } + + while (!fifo8_is_empty(&s->tx_fifo)) { + tx = (uint32_t)fifo8_pop(&s->tx_fifo); + rx = ssi_transfer(s->spi, tx); + apple_spi_update_xfer_tx(s); + if (REG(s, R_RXCNT) > 0) { + if (fifo8_is_full(&s->rx_fifo)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: rx overflow\n", __func__); + REG(s, R_STATUS) |= R_STATUS_RXOVERFLOW; + } else { + fifo8_push(&s->rx_fifo, (uint8_t)rx); + REG(s, R_RXCNT)--; + apple_spi_update_xfer_rx(s); + } + } + } + + // fetch the remaining bytes by sending sentinel bytes. + while (!fifo8_is_full(&s->rx_fifo) && (REG(s, R_RXCNT) > 0) && (REG(s, R_CFG) & R_CFG_AGD)) { + rx = ssi_transfer(s->spi, 0xff); + if (fifo8_is_full(&s->rx_fifo)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: rx overflow\n", __func__); + REG(s, R_STATUS) |= R_STATUS_RXOVERFLOW; + break; + } else { + fifo8_push(&s->rx_fifo, (uint8_t)rx); + REG(s, R_RXCNT)--; + apple_spi_update_xfer_rx(s); + } + } + if (REG(s, R_RXCNT) == 0 && fifo8_is_empty(&s->tx_fifo)) { + REG(s, R_STATUS) |= R_STATUS_COMPLETE; + REG(s, R_CTRL) &= ~R_CTRL_RUN; + } +} + +static uint64_t ipod_touch_spi_read(void *opaque, hwaddr addr, unsigned size) +{ + IPodTouchSPIState *s = IPOD_TOUCH_SPI(opaque); + //fprintf(stderr, "%s (base %d): read from location 0x%08x\n", __func__, s->base, addr); + + uint32_t r; + bool run = false; + + r = s->regs[addr >> 2]; + switch (addr) { + case R_RXDATA: { + const uint8_t *buf = NULL; + int word_size = apple_spi_word_size(s); + uint32_t num = 0; + if (fifo8_is_empty(&s->rx_fifo)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: rx underflow\n", __func__); + r = 0; + break; + } + buf = fifo8_pop_buf(&s->rx_fifo, word_size, &num); + memcpy(&r, buf, num); + if (fifo8_is_empty(&s->rx_fifo)) { + run = true; + } + break; + } + case R_STATUS: { + int val = 0; + val |= fifo8_num_used(&s->tx_fifo) << R_STATUS_TXFIFO_SHIFT; + val |= fifo8_num_used(&s->rx_fifo) << R_STATUS_RXFIFO_SHIFT; + val &= (R_STATUS_TXFIFO_MASK | R_STATUS_RXFIFO_MASK); + r &= ~(R_STATUS_TXFIFO_MASK | R_STATUS_RXFIFO_MASK); + r |= val; + break; + } + default: + break; + } + + if (run) { + apple_spi_run(s); + } + apple_spi_update_irq(s); + return r; +} + +static void ipod_touch_spi_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) +{ + IPodTouchSPIState *s = IPOD_TOUCH_SPI(opaque); + //fprintf(stderr, "%s (base %d): writing 0x%08x to 0x%08x\n", __func__, s->base, data, addr); + + uint32_t r = data; + uint32_t *mmio = ®(s, addr); + uint32_t old = *mmio; + bool cs_flg = false; + bool run = false; + + switch (addr) { + case R_CTRL: + if (r & R_CTRL_TX_RESET) { + fifo8_reset(&s->tx_fifo); + } + if (r & R_CTRL_RX_RESET) { + fifo8_reset(&s->rx_fifo); + } + if (r & R_CTRL_RUN && !fifo8_is_empty(&s->tx_fifo)) { + run = true; + } + break; + case R_STATUS: + r = old & (~r); + run = true; + break; + case R_PIN: + cs_flg = true; + break; + case R_TXDATA ... R_TXDATA + 3: { + int word_size = apple_spi_word_size(s); + if ((fifo8_is_full(&s->tx_fifo)) + || (fifo8_num_free(&s->tx_fifo) < word_size)) { + hw_error("OVERFLOW: %d\n", fifo8_num_free(&s->tx_fifo)); + qemu_log_mask(LOG_GUEST_ERROR, "%s: tx overflow\n", __func__); + r = 0; + break; + } + fifo8_push_all(&s->tx_fifo, (uint8_t *)&r, word_size); + break; + case R_CFG: + run = true; + break; + } + default: + break; + } + + *mmio = r; + if (cs_flg) { + apple_spi_update_cs(s); + } + if (run) { + apple_spi_run(s); + } + apple_spi_update_irq(s); +} + +static const MemoryRegionOps spi_ops = { + .read = ipod_touch_spi_read, + .write = ipod_touch_spi_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void ipod_touch_spi_reset(DeviceState *d) +{ + IPodTouchSPIState *s = (IPodTouchSPIState *)d; + memset(s->regs, 0, sizeof(s->regs)); + fifo8_reset(&s->tx_fifo); + fifo8_reset(&s->rx_fifo); +} + +static uint32_t base_addr = 0; + +void set_spi_base(uint32_t base) +{ + base_addr = base; +} + +static void ipod_touch_spi_realize(DeviceState *dev, struct Error **errp) +{ + IPodTouchSPIState *s = IPOD_TOUCH_SPI(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + + char bus_name[32] = { 0 }; + snprintf(bus_name, sizeof(bus_name), "%s.bus", dev->id); + s->spi = ssi_create_bus(dev, (const char *)bus_name); + + sysbus_init_irq(sbd, &s->irq); + sysbus_init_irq(sbd, &s->cs_line); + qdev_init_gpio_in_named(dev, apple_spi_cs_set, SSI_GPIO_CS, 1); + char name[5]; + snprintf(name, 5, "spi%d", base_addr); + memory_region_init_io(&s->iomem, OBJECT(s), &spi_ops, s, name, 0x100); + sysbus_init_mmio(sbd, &s->iomem); + s->base = base_addr; + + fifo8_create(&s->tx_fifo, R_FIFO_DEPTH); + fifo8_create(&s->rx_fifo, R_FIFO_DEPTH); + + // create the peripheral + switch(s->base) { + case 0: + break; + case 1: + //ssi_create_peripheral(s->spi, TYPE_IPOD_TOUCH_LCD_PANEL); + break; + case 2: + { + // DeviceState *dev = ssi_create_peripheral(s->spi, TYPE_IPOD_TOUCH_MULTITOUCH); + // IPodTouchMultitouchState *mt = IPOD_TOUCH_MULTITOUCH(dev); + // s->mt = mt; + break; + } + } +} + +static void ipod_touch_spi_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + dc->realize = ipod_touch_spi_realize; + dc->reset = ipod_touch_spi_reset; +} + +static const TypeInfo ipod_touch_spi_info = { + .name = TYPE_IPOD_TOUCH_SPI, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IPodTouchSPIState), + .class_init = ipod_touch_spi_class_init, +}; + +static void ipod_touch_spi_register_types(void) +{ + type_register_static(&ipod_touch_spi_info); +} + +type_init(ipod_touch_spi_register_types) \ No newline at end of file diff --git a/hw/arm/ipod_touch_sysic.c b/hw/arm/ipod_touch_sysic.c new file mode 100644 index 000000000000..d1e8ebfb5839 --- /dev/null +++ b/hw/arm/ipod_touch_sysic.c @@ -0,0 +1,129 @@ +#include "hw/arm/ipod_touch_sysic.h" + +static uint64_t ipod_touch_sysic_read(void *opaque, hwaddr addr, unsigned size) +{ + IPodTouchSYSICState *s = (IPodTouchSYSICState *) opaque; + + //fprintf(stderr, "%s: offset = 0x%08x\n", __func__, addr); + + switch (addr) { + case POWER_ID: + return s->power_id; + case POWER_SETSTATE: + case POWER_STATE: + return s->power_state; + case 0x7a: + case 0x7c: + return 1; + case GPIO_INTLEVEL ... (GPIO_INTLEVEL + GPIO_NUMINTGROUPS * 4): + { + uint8_t group = (addr - GPIO_INTLEVEL) / 4; + return s->gpio_int_level[group]; + } + case GPIO_INTSTAT ... (GPIO_INTSTAT + GPIO_NUMINTGROUPS * 4): + { + uint8_t group = (addr - GPIO_INTSTAT) / 4; + return s->gpio_int_status[group]; + } + case GPIO_INTEN ... (GPIO_INTEN + GPIO_NUMINTGROUPS * 4): + { + uint8_t group = (addr - GPIO_INTEN) / 4; + return s->gpio_int_enabled[group]; + } + case GPIO_INTTYPE ... (GPIO_INTTYPE + GPIO_NUMINTGROUPS * 4): + { + uint8_t group = (addr - GPIO_INTTYPE) / 4; + return s->gpio_int_type[group]; + } + default: + break; + } + return 0; +} + +static void ipod_touch_sysic_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) +{ + IPodTouchSYSICState *s = (IPodTouchSYSICState *) opaque; + + //fprintf(stderr, "%s: writing 0x%08x to 0x%08x\n", __func__, val, addr); + + switch (addr) { + case POWER_ID: + s->power_id = val; + break; + case POWER_ONCTRL: + if((val & 0x20) != 0 || (val & 0x4) != 0 || (val & POWER_ID_ADM) != 0) { break; } // make sure that we do not record the 'on' state of some devices so it appears like they are turned on immediately. + s->power_state = val; + break; + case POWER_OFFCTRL: + s->power_state = val; + break; + case GPIO_INTLEVEL ... (GPIO_INTLEVEL + GPIO_NUMINTGROUPS * 4): + { + break; + } + case GPIO_INTSTAT ... (GPIO_INTSTAT + GPIO_NUMINTGROUPS * 4): + { + uint8_t group = (addr - GPIO_INTSTAT) / 4; + + // acknowledge the interrupts and clear the corresponding bits + s->gpio_int_status[group] = s->gpio_int_status[group] & ~val; + + qemu_irq_lower(s->gpio_irqs[group]); + + break; + } + case GPIO_INTEN ... (GPIO_INTEN + GPIO_NUMINTGROUPS * 4): + { + uint8_t group = (addr - GPIO_INTEN) / 4; + s->gpio_int_enabled[group] = val; + break; + } + case GPIO_INTTYPE ... (GPIO_INTTYPE + GPIO_NUMINTGROUPS * 4): + { + uint8_t group = (addr - GPIO_INTTYPE) / 4; + s->gpio_int_type[group] = val; + break; + } + default: + break; + } +} + +static const MemoryRegionOps ipod_touch_sysic_ops = { + .read = ipod_touch_sysic_read, + .write = ipod_touch_sysic_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void ipod_touch_sysic_init(Object *obj) +{ + IPodTouchSYSICState *s = IPOD_TOUCH_SYSIC(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &ipod_touch_sysic_ops, s, TYPE_IPOD_TOUCH_SYSIC, 0x1000); + sysbus_init_mmio(sbd, &s->iomem); + for(int grp = 0; grp < GPIO_NUMINTGROUPS; grp++) { + sysbus_init_irq(sbd, &s->gpio_irqs[grp]); + } +} + +static void ipod_touch_sysic_class_init(ObjectClass *klass, void *data) +{ + +} + +static const TypeInfo ipod_touch_sysic_type_info = { + .name = TYPE_IPOD_TOUCH_SYSIC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IPodTouchSYSICState), + .instance_init = ipod_touch_sysic_init, + .class_init = ipod_touch_sysic_class_init, +}; + +static void ipod_touch_sysic_register_types(void) +{ + type_register_static(&ipod_touch_sysic_type_info); +} + +type_init(ipod_touch_sysic_register_types) diff --git a/hw/arm/ipod_touch_timer.c b/hw/arm/ipod_touch_timer.c new file mode 100644 index 000000000000..4842f5667994 --- /dev/null +++ b/hw/arm/ipod_touch_timer.c @@ -0,0 +1,143 @@ +#include "hw/arm/ipod_touch_timer.h" + +static void s5l8900_st_update(IPodTouchTimerState *s) +{ + s->freq_out = 1000000000 / 100; + s->tick_interval = /* bcount1 * get_ticks / freq + ((bcount2 * get_ticks / freq)*/ + muldiv64((s->bcount1 < 1000) ? 1000 : s->bcount1, NANOSECONDS_PER_SECOND, s->freq_out); + s->next_planned_tick = 0; +} + +static void s5l8900_st_set_timer(IPodTouchTimerState *s) +{ + uint64_t last = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - s->base_time; + + s->next_planned_tick = last + (s->tick_interval - last % s->tick_interval); + timer_mod(s->st_timer, s->next_planned_tick + s->base_time); + s->last_tick = last; +} + +static void s5l8900_st_tick(void *opaque) +{ + IPodTouchTimerState *s = (IPodTouchTimerState *)opaque; + + if (s->status & TIMER_STATE_START) { + //fprintf(stderr, "%s: Raising irq\n", __func__); + qemu_irq_raise(s->irq); + + /* schedule next interrupt */ + if(!(s->status & TIMER_STATE_MANUALUPDATE)) { + s5l8900_st_set_timer(s); + } + } else { + s->next_planned_tick = 0; + s->last_tick = 0; + timer_del(s->st_timer); + } +} + +static void s5l8900_timer1_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) +{ + //fprintf(stderr, "%s: writing 0x%08x to 0x%08x\n", __func__, value, addr); + IPodTouchTimerState *s = (struct IPodTouchTimerState *) opaque; + + switch(addr){ + + case TIMER_IRQSTAT: + s->irqstat = value; + return; + case TIMER_IRQLATCH: + //fprintf(stderr, "%s: lowering irq\n", __func__); + qemu_irq_lower(s->irq); + return; + case TIMER_4 + TIMER_CONFIG: + s5l8900_st_update(s); + s->config = value; + break; + case TIMER_4 + TIMER_STATE: + if (value & TIMER_STATE_START) { + s->base_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + s5l8900_st_update(s); + s5l8900_st_set_timer(s); + } else if (value == TIMER_STATE_STOP) { + timer_del(s->st_timer); + } + s->status = value; + break; + case TIMER_4 + TIMER_COUNT_BUFFER: + s->bcount1 = s->bcreload = value; + break; + case TIMER_4 + TIMER_COUNT_BUFFER2: + s->bcount2 = value; + break; + default: + break; + } +} + +static uint64_t s5l8900_timer1_read(void *opaque, hwaddr addr, unsigned size) +{ + //fprintf(stderr, "%s: read from location 0x%08x\n", __func__, addr); + IPodTouchTimerState *s = (struct IPodTouchTimerState *) opaque; + uint64_t elapsed_ns, ticks; + + switch (addr) { + case TIMER_TICKSHIGH: // needs to be fixed so that read from low first works as well + + elapsed_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / 2; // the timer ticks twice as slow as the CPU frequency in the kernel + ticks = clock_ns_to_ticks(s->sysclk, elapsed_ns); + //printf("TICKS: %lld\n", ticks); + s->ticks_high = (ticks >> 32); + s->ticks_low = (ticks & 0xFFFFFFFF); + return s->ticks_high; + case TIMER_TICKSLOW: + return s->ticks_low; + case TIMER_IRQSTAT: + return ~0; // s->irqstat; + case TIMER_IRQLATCH: + return 0xffffffff; + + default: + break; + } + return 0; +} + +static const MemoryRegionOps timer1_ops = { + .read = s5l8900_timer1_read, + .write = s5l8900_timer1_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void s5l8900_timer_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(sbd); + IPodTouchTimerState *s = IPOD_TOUCH_TIMER(dev); + + memory_region_init_io(&s->iomem, obj, &timer1_ops, s, "timer1", 0x10001); + sysbus_init_irq(sbd, &s->irq); + + s->base_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + s->st_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, s5l8900_st_tick, s); +} + +static void s5l8900_timer_class_init(ObjectClass *klass, void *data) +{ + +} + +static const TypeInfo ipod_touch_timer_info = { + .name = TYPE_IPOD_TOUCH_TIMER, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IPodTouchTimerState), + .instance_init = s5l8900_timer_init, + .class_init = s5l8900_timer_class_init, +}; + +static void ipod_touch_machine_types(void) +{ + type_register_static(&ipod_touch_timer_info); +} + +type_init(ipod_touch_machine_types) \ No newline at end of file diff --git a/hw/arm/ipod_touch_usb_otg.c b/hw/arm/ipod_touch_usb_otg.c new file mode 100644 index 000000000000..9e95b6a5cb37 --- /dev/null +++ b/hw/arm/ipod_touch_usb_otg.c @@ -0,0 +1,616 @@ +/* + * Synopsys DesignWareCore for USB OTG. + * + * Copyright (c) 2011 Richard Ian Taylor. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#include "qemu/osdep.h" +#include "hw/platform-bus.h" +#include "qapi/error.h" +#include "hw/hw.h" +#include "hw/arm/ipod_touch_usb_otg.h" + +static inline size_t synopsys_usb_tx_fifo_start(synopsys_usb_state *_state, uint32_t _fifo) +{ + if(_fifo == 0) + return _state->gnptxfsiz >> 16; + else + return _state->dptxfsiz[_fifo-1] >> 16; +} + +static inline size_t synopsys_usb_tx_fifo_size(synopsys_usb_state *_state, uint32_t _fifo) +{ + if(_fifo == 0) + return _state->gnptxfsiz & 0xFFFF; + else + return _state->dptxfsiz[_fifo-1] & 0xFFFF; +} + +static void synopsys_usb_update_irq(synopsys_usb_state *_state) +{ + _state->daintsts = 0; + _state->gintsts &=~ (GINTMSK_OEP | GINTMSK_INEP | GINTMSK_OTG); + + if(_state->gotgint) + _state->gintsts |= GINTMSK_OTG; + + int i; + for(i = 0; i < USB_NUM_ENDPOINTS; i++) + { + if(_state->out_eps[i].interrupt_status & _state->doepmsk) + { + _state->daintsts |= 1 << (i+DAINT_OUT_SHIFT); + if(_state->daintmsk & (1 << (i+DAINT_OUT_SHIFT))) + _state->gintsts |= GINTMSK_OEP; + } + + if(_state->in_eps[i].interrupt_status & _state->diepmsk) + { + _state->daintsts |= 1 << (i+DAINT_IN_SHIFT); + if(_state->daintmsk & (1 << (i+DAINT_IN_SHIFT))) + _state->gintsts |= GINTMSK_INEP; + } + } + + if((_state->pcgcctl & 3) == 0 && _state->gintmsk & _state->gintsts) + { + //printf("USB: IRQ triggered 0x%08x & 0x%08x.\n", _state->gintsts, _state->gintmsk); + qemu_irq_raise(_state->irq); + } + else + qemu_irq_lower(_state->irq); +} + +static void synopsys_usb_update_ep(synopsys_usb_state *_state, synopsys_usb_ep_state *_ep) +{ + if(_ep->control & USB_EPCON_SETNAK) + { + _ep->control |= USB_EPCON_NAKSTS; + _ep->interrupt_status |= USB_EPINT_INEPNakEff; + _ep->control &=~ USB_EPCON_SETNAK; + } + + if(_ep->control & USB_EPCON_DISABLE) + { + _ep->interrupt_status |= USB_EPINT_EPDisbld; + _ep->control &=~ (USB_EPCON_DISABLE | USB_EPCON_ENABLE); + } +} + +static void synopsys_usb_update_in_ep(synopsys_usb_state *_state, uint8_t _ep) +{ + synopsys_usb_ep_state *eps = &_state->in_eps[_ep]; + synopsys_usb_update_ep(_state, eps); + + if(eps->control & USB_EPCON_ENABLE) + ;//printf("USB: IN transfer queued on %d.\n", _ep); +} + +static void synopsys_usb_update_out_ep(synopsys_usb_state *_state, uint8_t _ep) +{ + synopsys_usb_ep_state *eps = &_state->out_eps[_ep]; + synopsys_usb_update_ep(_state, eps); + + if(eps->control & USB_EPCON_ENABLE) + ;//printf("USB: OUT transfer queued on %d.\n", _ep); +} + +static uint32_t synopsys_usb_in_ep_read(synopsys_usb_state *_state, uint8_t _ep, hwaddr _addr) +{ + if(_ep >= USB_NUM_ENDPOINTS) + { + hw_error("usb_synopsys: Tried to read from disabled EP %d.\n", _ep); + return 0; + } + + switch (_addr) + { + case 0x00: + return _state->in_eps[_ep].control; + + case 0x08: + return _state->in_eps[_ep].interrupt_status; + + case 0x10: + return _state->in_eps[_ep].tx_size; + + case 0x14: + return _state->in_eps[_ep].dma_address; + + case 0x1C: + return _state->in_eps[_ep].dma_buffer; + + default: + hw_error("usb_synopsys: bad ep read offset 0x" TARGET_FMT_plx "\n", _addr); + break; + } + + return 0; +} + +static uint32_t synopsys_usb_out_ep_read(synopsys_usb_state *_state, int _ep, hwaddr _addr) +{ + if(_ep >= USB_NUM_ENDPOINTS) + { + hw_error("usb_synopsys: Tried to read from disabled EP %d.\n", _ep); + return 0; + } + + switch (_addr) + { + case 0x00: + return _state->out_eps[_ep].control; + + case 0x08: + return _state->out_eps[_ep].interrupt_status; + + case 0x10: + return _state->out_eps[_ep].tx_size; + + case 0x14: + return _state->out_eps[_ep].dma_address; + + case 0x1C: + return _state->out_eps[_ep].dma_buffer; + + default: + hw_error("usb_synopsys: bad ep read offset 0x" TARGET_FMT_plx "\n", _addr); + break; + } + + return 0; +} + +static uint64_t synopsys_usb_read(void *opaque, hwaddr _addr, unsigned size) +{ + synopsys_usb_state *state = (synopsys_usb_state *)opaque; + + //printf("USB: Read 0x%08x.\n", _addr); + + switch(_addr) + { + case PCGCCTL: + return state->pcgcctl; + + case GOTGCTL: + return state->gotgctl; + + case GOTGINT: + return state->gotgint; + + case GRSTCTL: + return state->grstctl; + + case GHWCFG1: + return state->ghwcfg1; + + case GHWCFG2: + return state->ghwcfg2; + + case GHWCFG3: + return state->ghwcfg3; + + case GHWCFG4: + return state->ghwcfg4; + + case GAHBCFG: + return state->gahbcfg; + + case GUSBCFG: + return state->gusbcfg; + + case GINTMSK: + return state->gintmsk; + + case GINTSTS: + return state->gintsts; + + case DIEPMSK: + return state->diepmsk; + + case DOEPMSK: + return state->doepmsk; + + case DAINTMSK: + return state->daintmsk; + + case DAINTSTS: + return state->daintsts; + + case DCTL: + return state->dctl; + + case DCFG: + return state->dcfg; + + case DSTS: + return state->dsts; + + case GRXSTSR: + case GRXSTSP: + return 0; // TODO: Do something about this? + + case GNPTXFSTS: + return 0xFFFFFFFF; + + case GRXFSIZ: + return state->grxfsiz; + + case GNPTXFSIZ: + return state->gnptxfsiz; + + case DIEPTXF(1) ... DIEPTXF(USB_NUM_FIFOS+1): + _addr -= DIEPTXF(1); + _addr >>= 2; + return state->dptxfsiz[_addr]; + + case USB_INREGS ... (USB_INREGS + USB_EPREGS_SIZE - 4): + _addr -= USB_INREGS; + return synopsys_usb_in_ep_read(state, _addr >> 5, _addr & 0x1f); + + case USB_OUTREGS ... (USB_OUTREGS + USB_EPREGS_SIZE - 4): + _addr -= USB_OUTREGS; + return synopsys_usb_out_ep_read(state, _addr >> 5, _addr & 0x1f); + + case USB_FIFO_START ... USB_FIFO_END-4: + _addr -= USB_FIFO_START; + return *((uint32_t*)(&state->fifos[_addr])); + + default: + hw_error("USB: Unhandled read address 0x%08x!\n", _addr); + } + + return 0; +} + +static void synopsys_usb_in_ep_write(synopsys_usb_state *_state, int _ep, hwaddr _addr, uint32_t _val) +{ + if(_ep >= USB_NUM_ENDPOINTS) + { + hw_error("usb_synopsys: Wrote to disabled EP %d.\n", _ep); + return; + } + + switch (_addr) + { + case 0x00: + _state->in_eps[_ep].control = _val; + synopsys_usb_update_in_ep(_state, _ep); + return; + + case 0x08: + _state->in_eps[_ep].interrupt_status &=~ _val; + synopsys_usb_update_irq(_state); + return; + + case 0x10: + _state->in_eps[_ep].tx_size = _val; + return; + + case 0x14: + _state->in_eps[_ep].dma_address = _val; + return; + + case 0x1C: + _state->in_eps[_ep].dma_buffer = _val; + return; + + default: + hw_error("usb_synopsys: bad ep write offset 0x" TARGET_FMT_plx "\n", _addr); + break; + } +} + +static void synopsys_usb_out_ep_write(synopsys_usb_state *_state, int _ep, hwaddr _addr, uint32_t _val) +{ + if(_ep >= USB_NUM_ENDPOINTS) + { + hw_error("usb_synopsys: Wrote to disabled EP %d.\n", _ep); + return; + } + + switch (_addr) + { + case 0x00: + _state->out_eps[_ep].control = _val; + synopsys_usb_update_out_ep(_state, _ep); + return; + + case 0x08: + _state->out_eps[_ep].interrupt_status &=~ _val; + synopsys_usb_update_irq(_state); + return; + + case 0x10: + _state->out_eps[_ep].tx_size = _val; + return; + + case 0x14: + _state->out_eps[_ep].dma_address = _val; + return; + + case 0x1C: + _state->out_eps[_ep].dma_buffer = _val; + return; + + default: + hw_error("usb_synopsys: bad ep write offset 0x" TARGET_FMT_plx "\n", _addr); + break; + } +} + +static void synopsys_usb_write(void *opaque, hwaddr _addr, uint64_t _val, unsigned size) +{ + synopsys_usb_state *state = (synopsys_usb_state *)opaque; + + //printf("USB: Write 0x%08x to 0x%08x.\n", _val, _addr); + + switch(_addr) + { + case PCGCCTL: + state->pcgcctl = _val; + synopsys_usb_update_irq(state); + return; + + case GOTGCTL: + state->gotgctl = _val; + break; + + case GOTGINT: + state->gotgint &=~ _val; + synopsys_usb_update_irq(state); + return; + + case GRSTCTL: + if(_val & GRSTCTL_CORESOFTRESET) + { + state->grstctl = GRSTCTL_CORESOFTRESET; + + // Do reset stuff + // if(state->server_host) + // { + // tcp_usb_cleanup(&state->tcp_state); + // tcp_usb_init(&state->tcp_state, synopsys_usb_tcp_callback, NULL, state); + + // printf("Connecting to USB server at %s:%d...\n", + // state->server_host, state->server_port); + + // int ret = tcp_usb_connect(&state->tcp_state, state->server_host, state->server_port); + // if(ret < 0) + // hw_error("Failed to connect to USB server (%d).\n", ret); + + // printf("Connected to USB server.\n"); + // } + + state->grstctl &= ~GRSTCTL_CORESOFTRESET; + state->grstctl |= GRSTCTL_AHBIDLE; + state->gintsts |= GINTMSK_RESET; + synopsys_usb_update_irq(state); + } + else if(_val == 0) + state->grstctl = _val; + + return; + + case GINTMSK: + state->gintmsk = _val; + synopsys_usb_update_irq(state); + break; + + case GINTSTS: + state->gintsts &=~ _val; + synopsys_usb_update_irq(state); + return; + + case DOEPMSK: + state->doepmsk = _val; + synopsys_usb_update_irq(state); + return; + + case DIEPMSK: + state->diepmsk = _val; + synopsys_usb_update_irq(state); + return; + + case DAINTMSK: + state->daintmsk = _val; + synopsys_usb_update_irq(state); + return; + + case DAINTSTS: + state->daintsts &=~ _val; + synopsys_usb_update_irq(state); + return; + + case GAHBCFG: + state->gahbcfg = _val; + return; + + case GUSBCFG: + state->gusbcfg = _val; + return; + + case DCTL: + if((_val & DCTL_SGNPINNAK) != (state->dctl & DCTL_SGNPINNAK) + && (_val & DCTL_SGNPINNAK)) + { + state->gintsts |= GINTMSK_GINNAKEFF; + _val &=~ DCTL_SGNPINNAK; + } + + if((_val & DCTL_SGOUTNAK) != (state->dctl & DCTL_SGOUTNAK) + && (_val & DCTL_SGOUTNAK)) + { + state->gintsts |= GINTMSK_GOUTNAKEFF; + _val &=~ DCTL_SGOUTNAK; + } + + state->dctl = _val; + synopsys_usb_update_irq(state); + return; + + case DCFG: + //printf("USB: dcfg = 0x%08x.\n", _val); + state->dcfg = _val; + return; + + case GRXFSIZ: + state->grxfsiz = _val; + return; + + case GNPTXFSIZ: + state->gnptxfsiz = _val; + return; + + case DIEPTXF(1) ... DIEPTXF(USB_NUM_FIFOS+1): + _addr -= DIEPTXF(1); + _addr >>= 2; + state->dptxfsiz[_addr] = _val; + return; + + case USB_INREGS ... (USB_INREGS + USB_EPREGS_SIZE - 4): + _addr -= USB_INREGS; + synopsys_usb_in_ep_write(state, _addr >> 5, _addr & 0x1f, _val); + return; + + case USB_OUTREGS ... (USB_OUTREGS + USB_EPREGS_SIZE - 4): + _addr -= USB_OUTREGS; + synopsys_usb_out_ep_write(state, _addr >> 5, _addr & 0x1f, _val); + return; + + case USB_FIFO_START ... USB_FIFO_END-4: + _addr -= USB_FIFO_START; + *((uint32_t*)(&state->fifos[_addr])) = _val; + return; + + default: + hw_error("USB: Unhandled write address 0x%08x!\n", _addr); + } +} + +static const MemoryRegionOps usb_otg_ops = { + .read = synopsys_usb_read, + .write = synopsys_usb_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void s5l8900_usb_otg_reset(DeviceState *d) +{ + synopsys_usb_state *state = S5L8900USBOTG(d); + + printf("USB: cfg = 0x%08x, 0x%08x, 0x%08x, 0x%08x.\n", + state->ghwcfg1, + state->ghwcfg2, + state->ghwcfg3, + state->ghwcfg4); + + state->pcgcctl = 3; + + state->gahbcfg = 0; + state->gusbcfg = 0; + + state->dctl = 0; + state->dcfg = 0; + state->dsts = 0; + + state->gotgctl = 0; + state->gotgint = 0; + + state->gintmsk = 0; + state->gintsts = 0; + + state->daintmsk = 0; + state->daintsts = 0; + + state->diepmsk = 0; + state->doepmsk = 0; + + state->grxfsiz = 0x100; + state->gnptxfsiz = (0x100 << 16) | 0x100; + + uint32_t counter = 0x200; + int i; + for(i = 0; i < USB_NUM_FIFOS; i++) + { + state->dptxfsiz[i] = (counter << 16) | 0x100; + counter += 0x100; + } + + for(i = 0; i < USB_NUM_ENDPOINTS; i++) + { + synopsys_usb_ep_state *in = &state->in_eps[i]; + in->control = 0; + in->dma_address = 0; + in->fifo = 0; + in->tx_size = 0; + + synopsys_usb_ep_state *out = &state->out_eps[i]; + out->control = 0; + out->dma_address = 0; + out->fifo = 0; + out->tx_size = 0; + } + + synopsys_usb_update_irq(state); +} + +static void s5l8900_usb_otg_init1(Object *obj) +{ + DeviceState *dev = DEVICE(obj); + synopsys_usb_state *s = S5L8900USBOTG(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, OBJECT(s), &usb_otg_ops, s, "usb_otg", 0x1000); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); +} + +// Helper for adding to a machine +DeviceState *ipod_touch_init_usb_otg(qemu_irq _irq, uint32_t _hwcfg[4]) +{ + DeviceState *dev = qdev_new(TYPE_S5L8900USBOTG); + synopsys_usb_state *state = S5L8900USBOTG(dev); + + state->ghwcfg1 = _hwcfg[0]; + state->ghwcfg2 = _hwcfg[1]; + state->ghwcfg3 = _hwcfg[2]; + state->ghwcfg4 = _hwcfg[3]; + + SysBusDevice *sdev = SYS_BUS_DEVICE(dev); + sysbus_connect_irq(sdev, 0, _irq); + + return dev; +} + +static void s5l8900_usb_otg_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + dc->reset = s5l8900_usb_otg_reset; +} + +static const TypeInfo s5l8900_usb_otg_info = { + .name = TYPE_S5L8900USBOTG, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(synopsys_usb_state), + .instance_init = s5l8900_usb_otg_init1, + .class_init = s5l8900_usb_otg_class_init, +}; + +static void s5l8900_usb_otg_register_types(void) +{ + type_register_static(&s5l8900_usb_otg_info); +} + +type_init(s5l8900_usb_otg_register_types) \ No newline at end of file diff --git a/hw/arm/ipod_touch_usb_phys.c b/hw/arm/ipod_touch_usb_phys.c new file mode 100644 index 000000000000..686881d637a8 --- /dev/null +++ b/hw/arm/ipod_touch_usb_phys.c @@ -0,0 +1,84 @@ +#include "hw/arm/ipod_touch_usb_phys.h" + +static uint64_t ipod_touch_usb_phys_read(void *opaque, hwaddr addr, unsigned size) +{ + IPodTouchUSBPhysState *s = (IPodTouchUSBPhysState *) opaque; + + switch(addr) + { + case REG_OPHYPWR: + return s->usb_ophypwr; + case REG_OPHYCLK: + return s->usb_ophyclk; + case REG_ORSTCON: + return s->usb_orstcon; + case REG_UNKNOWN1: + return s->usb_unknown1; + case REG_OPHYTUNE: + return s->usb_ophytune; + default: + hw_error("%s: read invalid location 0x%08x\n", __func__, addr); + } +} + +static void ipod_touch_usb_phys_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) +{ + IPodTouchUSBPhysState *s = (IPodTouchUSBPhysState *) opaque; + + switch(addr) + { + case REG_OPHYPWR: + s->usb_ophypwr = val; + return; + case REG_OPHYCLK: + s->usb_ophyclk = val; + return; + case REG_ORSTCON: + s->usb_orstcon = val; + return; + case REG_UNKNOWN1: + s->usb_unknown1 = val; + return; + case REG_OPHYTUNE: + s->usb_ophytune = val; + return; + + default: + hw_error("%s: write invalid location 0x%08x.\n", __func__, addr); + } +} + +static const MemoryRegionOps ipod_touch_usb_phys_ops = { + .read = ipod_touch_usb_phys_read, + .write = ipod_touch_usb_phys_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void ipod_touch_usb_phys_init(Object *obj) +{ + IPodTouchUSBPhysState *s = IPOD_TOUCH_USB_PHYS(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &ipod_touch_usb_phys_ops, s, TYPE_IPOD_TOUCH_USB_PHYS, 0x40); + sysbus_init_mmio(sbd, &s->iomem); +} + +static void ipod_touch_usb_phys_class_init(ObjectClass *klass, void *data) +{ + +} + +static const TypeInfo ipod_touch_usb_phys_type_info = { + .name = TYPE_IPOD_TOUCH_USB_PHYS, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IPodTouchUSBPhysState), + .instance_init = ipod_touch_usb_phys_init, + .class_init = ipod_touch_usb_phys_class_init, +}; + +static void ipod_touch_usb_phys_register_types(void) +{ + type_register_static(&ipod_touch_usb_phys_type_info); +} + +type_init(ipod_touch_usb_phys_register_types) \ No newline at end of file diff --git a/hw/arm/meson.build b/hw/arm/meson.build index d3646277c4da..717d422f7e48 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -62,6 +62,6 @@ arm_ss.add(when: 'CONFIG_FSL_IMX7', if_true: files('fsl-imx7.c', 'mcimx7d-sabre. arm_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c', 'smmuv3.c')) arm_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c')) arm_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c')) -arm_ss.add(when: 'CONFIG_IPOD_TOUCH_2G', if_true: files('ipod_touch_2g.c', 'ipod_touch_clock.c', 'ipod_touch_chipid.c', 'ipod_touch_gpio.c')) +arm_ss.add(when: 'CONFIG_IPOD_TOUCH_2G', if_true: files('ipod_touch_2g.c', 'ipod_touch_clock.c', 'ipod_touch_chipid.c', 'ipod_touch_gpio.c', 'ipod_touch_sysic.c', 'ipod_touch_timer.c', 'ipod_touch_usb_otg.c', 'ipod_touch_usb_phys.c', 'ipod_touch_spi.c')) hw_arch += {'arm': arm_ss} diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig index ecd2883ceb30..a9ff37b78b6d 100644 --- a/hw/intc/Kconfig +++ b/hw/intc/Kconfig @@ -8,6 +8,9 @@ config I8259 config PL190 bool +config PL192 + bool + config IOAPIC bool select I8259 diff --git a/hw/intc/meson.build b/hw/intc/meson.build index bcbf22ff512b..7333e74502e9 100644 --- a/hw/intc/meson.build +++ b/hw/intc/meson.build @@ -19,6 +19,7 @@ softmmu_ss.add(when: 'CONFIG_IMX', if_true: files('imx_avic.c', 'imx_gpcv2.c')) softmmu_ss.add(when: 'CONFIG_IOAPIC', if_true: files('ioapic_common.c')) softmmu_ss.add(when: 'CONFIG_OPENPIC', if_true: files('openpic.c')) softmmu_ss.add(when: 'CONFIG_PL190', if_true: files('pl190.c')) +softmmu_ss.add(when: 'CONFIG_PL192', if_true: files('pl192.c')) softmmu_ss.add(when: 'CONFIG_REALVIEW', if_true: files('realview_gic.c')) softmmu_ss.add(when: 'CONFIG_SLAVIO', if_true: files('slavio_intctl.c')) softmmu_ss.add(when: 'CONFIG_XILINX', if_true: files('xilinx_intc.c')) diff --git a/hw/intc/pl192.c b/hw/intc/pl192.c new file mode 100644 index 000000000000..06e61725d483 --- /dev/null +++ b/hw/intc/pl192.c @@ -0,0 +1,439 @@ +/* + * ARM PrimeCell PL192 Vector Interrupt Controller + * + * Copyright (c) 2009 Samsung Electronics. + * Contributed by Kirill Batuzov + */ + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "hw/irq.h" +#include "hw/hw.h" +#include "qapi/error.h" +#include "hw/intc/pl192.h" + +extern CPUState *getMainCpuEnv(void); + + +static void pl192_update(PL192State *); + +static void pl192_raise(PL192State *s, int is_fiq) +{ + if (is_fiq) { + if (s->fiq) { + /* Raise parent FIQ */ + qemu_irq_raise(s->fiq); + } else { + if (s->daisy) { + /* FIQ is directly propagated through daisy chain */ + pl192_raise(s->daisy, is_fiq); + } else { + fprintf(stderr, "pl192i cannot raise FIQ. This usually means that " + "initialization was done incorrectly.\n"); + } + } + } else { + if (s->irq) { + /* Raise parent IRQ */ + qemu_irq_raise(s->irq); + } else { + if (s->daisy) { + /* Setup daisy input of the next chained contorller and force + it to update it's state */ + s->daisy->daisy_vectaddr = s->address; + s->daisy->daisy_callback = s; + s->daisy->daisy_input = 1; + pl192_update(s->daisy); + } else { + // TODO Needs urgent fixing! + hw_error("pl192: cannot raise IRQ. This usually means that initialization was done incorrectly.\n"); + } + } + } +} + +static void pl192_lower(PL192State *s, int is_fiq) +{ + /* Lower parrent interrupt if there is one */ + if (is_fiq && s->fiq) { + qemu_irq_lower(s->fiq); + } + if (!is_fiq && s->irq) { + qemu_irq_lower(s->irq); + } + /* Propagate to the previous controller in chain if needed */ + if (s->daisy) { + if (!is_fiq) { + s->daisy->daisy_input = 0; + pl192_update(s->daisy); + } else { + pl192_lower(s->daisy, is_fiq); + } + } +} + +/* Find interrupt of the highest priority */ +static uint32_t pl192_priority_sorter(PL192State *s) +{ + int i; + uint32_t prio_irq[PL192_PRIO_LEVELS]; + + for (i = 0; i < PL192_PRIO_LEVELS; i++) { + prio_irq[i] = PL192_NO_IRQ; + } + if (s->daisy_input) { + prio_irq[s->daisy_priority] = PL192_DAISY_IRQ; + } + for (i = PL192_INT_SOURCES - 1; i >= 0; i--) { + if (s->irq_status & (1 << i)) { + prio_irq[s->vect_priority[i]] = i; + } + } + for (i = 0; i < PL192_PRIO_LEVELS; i++) { + if ((s->sw_priority_mask & (1 << i)) && + prio_irq[i] <= PL192_DAISY_IRQ) { + return prio_irq[i]; + } + } + return PL192_NO_IRQ; +} + +static void pl192_update(PL192State *s) +{ + /* TODO: does SOFTINT affects IRQ_STATUS??? */ + s->irq_status = (s->rawintr | s->softint) & s->intenable & ~s->intselect; + s->fiq_status = (s->rawintr | s->softint) & s->intenable & s->intselect; + if (s->fiq_status) { + pl192_raise(s, 1); + } else { + pl192_lower(s, 1); + } + if (s->irq_status || s->daisy_input) { + s->current_highest = pl192_priority_sorter(s); + if (s->current_highest < PL192_INT_SOURCES) { + s->address = s->vect_addr[s->current_highest]; + } else { + s->address = s->daisy_vectaddr; + } + if (s->current_highest != s->current) { + if (s->current_highest < PL192_INT_SOURCES) { + if (s->vect_priority[s->current_highest] >= s->priority) { + return ; + } + } + if (s->current_highest == PL192_DAISY_IRQ) { + if (s->daisy_priority >= s->priority) { + return ; + } + } + if (s->current_highest <= PL192_DAISY_IRQ) { + pl192_raise(s, 0); + } else { + pl192_lower(s, 0); + } + } + } else { + s->current_highest = PL192_NO_IRQ; + pl192_lower(s, 0); + } +} + +/* Set priority level when an interrupt have been acknoledged by CPU. + Also save interrupt id and priority to stack so it can be restored + lately. */ +static inline void pl192_mask_priority(PL192State *s) +{ + if (s->stack_i >= PL192_INT_SOURCES) { + hw_error("pl192: internal error (trying to mask when there are no more sources)\n"); + } + s->stack_i++; + if (s->current == PL192_DAISY_IRQ) { + s->priority = s->daisy_priority; + } else { + s->priority = s->vect_priority[s->current]; + } + s->priority_stack[s->stack_i] = s->priority; + s->irq_stack[s->stack_i] = s->current; +} + +/* Set priority level when interrupt have been successfully processed by CPU. + Also restore previous interrupt id and priority level. */ +static inline void pl192_unmask_priority(PL192State *s) +{ + if (s->stack_i < 1) { + return; // simply ignore this event + //hw_error("pl192: internal error (mask stack insufficient)\n"); + } + s->stack_i--; + s->priority = s->priority_stack[s->stack_i]; + s->current = s->irq_stack[s->stack_i]; +} + +/* IRQ was acknoledged by CPU. Update controller state accordingly */ +static uint32_t pl192_irq_ack(PL192State *s) +{ + int is_daisy = (s->current_highest == PL192_DAISY_IRQ); + uint32_t res = s->address; + + s->current = s->current_highest; + pl192_mask_priority(s); + if (is_daisy) { + pl192_mask_priority(s->daisy_callback); + } + pl192_update(s); + return res; +} + +/* IRQ was processed by CPU. Update controller state accrodingly */ +static void pl192_irq_fin(PL192State *s) +{ + int is_daisy = (s->current == PL192_DAISY_IRQ); + + pl192_unmask_priority(s); + if (is_daisy) { + pl192_unmask_priority(s->daisy_callback); + } + pl192_update(s); + + /* hmm is this right?*/ + /* + if (s->current == PL192_NO_IRQ && (s->current_highest >= PL192_INT_SOURCES)) { + pl192_lower(s, 0); + } + */ +} + +static uint64_t pl192_read(void *opaque, hwaddr offset, unsigned size) +{ + PL192State *s = (PL192State *) opaque; + + if (offset & 3) { + fprintf(stderr, "pl192: bad read offset (1) " TARGET_FMT_plx "\n", offset); + return 0; + } + + if (offset >= 0xfe0 && offset < 0x1000) { + unsigned char pl192_id[] = { 0x92, 0x11, 0x04, 0x00, 0x0D, 0xF0, 0x05, 0xB1 }; + return pl192_id[(offset - 0xfe0) >> 2]; + } + if (offset >= 0x100 && offset < 0x180) { + return s->vect_addr[(offset - 0x100) >> 2]; + } + if (offset >= 0x200 && offset < 0x280) { + return s->vect_priority[(offset - 0x200) >> 2]; + } + + switch (offset) { + case PL192_IRQSTATUS: + //fprintf(stderr, "%s: irqstatus 0x%08x\n", __FUNCTION__, s->irq_status); + return s->irq_status; + case PL192_FIQSTATUS: + return s->fiq_status; + case PL192_RAWINTR: + return s->rawintr; + case PL192_INTSELECT: + return s->intselect; + case PL192_INTENABLE: + return s->intenable; + case PL192_SOFTINT: + return s->softint; + case PL192_PROTECTION: + return s->protection; + case PL192_SWPRIORITYMASK: + return s->sw_priority_mask; + case PL192_PRIORITYDAISY: + return s->daisy_priority; + case PL192_INTENCLEAR: + return 0; + case PL192_SOFTINTCLEAR: + fprintf(stderr, "pl192: attempt to read write-only register (offset = " + TARGET_FMT_plx ")\n", offset); + case PL192_VECTADDR: + return pl192_irq_ack(s); + /* Workaround for kernel code using PL190 */ + case PL190_ITCR: + case PL190_VECTADDR: + case PL190_DEFVECTADDR: + return 0; + default: + fprintf(stderr, "pl192: bad read offset (2) " TARGET_FMT_plx "\n", offset); + return 0; + } +} + +static void pl192_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) +{ + PL192State *s = (PL192State *) opaque; + + if (offset & 3) { + hw_error("pl192: bad write offset (1) " TARGET_FMT_plx "\n", offset); + } + + if (offset >= 0xfe0 && offset < 0x1000) { + hw_error("pl192: attempt to write to a read-only register (offset = " + TARGET_FMT_plx ")\n", offset); + } + if (offset >= 0x100 && offset < 0x180) { + s->vect_addr[(offset - 0x100) >> 2] = value; + pl192_update(s); + return; + } + if (offset >= 0x200 && offset < 0x280) { + s->vect_priority[(offset - 0x200) >> 2] = value & 0xf; + pl192_update(s); + return; + } + + switch (offset) { + case PL192_IRQSTATUS: + /* This is a readonly register, but linux tries to write to it + anyway. Ignore the write. */ + return; + case PL192_FIQSTATUS: + case PL192_RAWINTR: + hw_error("pl192: attempt to write to a read-only register (offset = " + TARGET_FMT_plx ")\n", offset); + break; + case PL192_INTSELECT: + s->intselect = value; + break; + case PL192_INTENABLE: + s->intenable |= value; + break; + case PL192_INTENCLEAR: + s->intenable &= ~value; + break; + case PL192_SOFTINT: + s->softint |= value; + break; + case PL192_SOFTINTCLEAR: + s->softint &= ~value; + break; + case PL192_PROTECTION: + /* TODO: implement protection */ + s->protection = value & 1; + break; + case PL192_SWPRIORITYMASK: + s->sw_priority_mask = value & 0xffff; + break; + case PL192_PRIORITYDAISY: + s->daisy_priority = value & 0xf; + break; + case PL192_VECTADDR: + pl192_irq_fin(s); + return; + case PL190_ITCR: + case PL190_VECTADDR: + case PL190_DEFVECTADDR: + /* NB: This thing is not present here, but linux wants to write it */ + /* Ignore written value */ + return; + default: + fprintf(stderr, "pl192: bad write offset (2) " TARGET_FMT_plx "\n", offset); + return; + } + + pl192_update(s); +} + +static void pl192_irq_handler(void *opaque, int irq, int level) +{ + PL192State *s = (PL192State *) opaque; + + if (level) { + s->rawintr |= 1 << irq; + } else { + s->rawintr &= ~(1 << irq); + } + pl192_update(opaque); +} + +static void pl192_reset(DeviceState *d) +{ + PL192State *s = PL192(d); + int i; + + for (i = 0; i < PL192_INT_SOURCES; i++) { + s->vect_priority[i] = 0xf; + } + s->sw_priority_mask = 0xffff; + s->daisy_priority = 0xf; + s->current = PL192_NO_IRQ; + s->current_highest = PL192_NO_IRQ; + s->stack_i = 0; + s->priority_stack[0] = 0x10; + s->irq_stack[0] = PL192_NO_IRQ; + s->priority = 0x10; +} + +static const MemoryRegionOps pl192_ops = { + .read = pl192_read, + .write = pl192_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +DeviceState *pl192_manual_init(char *mem_name, ...) +{ + DeviceState *dev = qdev_new(TYPE_PL192); + PL192State *s = PL192(dev); + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + va_list va; + qemu_irq irq; + + memory_region_init_io(&s->iomem, OBJECT(s), &pl192_ops, s, mem_name, 0x1000); + sysbus_init_mmio(sbd, &s->iomem); + qdev_init_gpio_in(dev, pl192_irq_handler, PL192_INT_SOURCES); + sysbus_init_irq(sbd, &s->irq); + sysbus_init_irq(sbd, &s->fiq); + sysbus_realize_and_unref(sbd, &error_fatal); + + va_start(va, mem_name); + int n = 0; + while (1) { + irq = va_arg(va, qemu_irq); + if (!irq) { + break; + } + sysbus_connect_irq(sbd, n, irq); + n++; + } + + return dev; +} + +static void pl192_init(Object *obj) +{ + DeviceState *dev = DEVICE(obj); + PL192State *s = PL192(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + //memory_region_init_io(&s->iomem, obj, &pl192_ops, s, "pl192", 0x1000); + //sysbus_init_mmio(sbd, &s->iomem); + //qdev_init_gpio_in(dev, pl192_irq_handler, PL192_INT_SOURCES); + //sysbus_init_irq(sbd, s->irq); + //sysbus_init_irq(sbd, s->fiq); +} + +static void pl192_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = pl192_reset; + //dc->vmsd = &vmstate_pl192; + // TODO save VM +} + +static const TypeInfo pl192_info = { + .name = TYPE_PL192, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PL192State), + .instance_init = pl192_init, + .class_init = pl192_class_init, +}; + +static void pl192_register_types(void) +{ + type_register_static(&pl192_info); +} + +type_init(pl192_register_types) \ No newline at end of file diff --git a/include/hw/arm/ipod_touch_2g.h b/include/hw/arm/ipod_touch_2g.h index 011f85cb0f14..5c0567c4cc89 100644 --- a/include/hw/arm/ipod_touch_2g.h +++ b/include/hw/arm/ipod_touch_2g.h @@ -3,14 +3,31 @@ #include "exec/hwaddr.h" #include "hw/boards.h" +#include "hw/intc/pl192.h" #include "hw/arm/boot.h" #include "cpu.h" +#include "hw/arm/ipod_touch_timer.h" #include "hw/arm/ipod_touch_clock.h" #include "hw/arm/ipod_touch_chipid.h" #include "hw/arm/ipod_touch_gpio.h" +#include "hw/arm/ipod_touch_sysic.h" +#include "hw/arm/ipod_touch_usb_otg.h" +#include "hw/arm/ipod_touch_usb_phys.h" +#include "hw/arm/ipod_touch_spi.h" #define TYPE_IPOD_TOUCH "iPod-Touch" +#define S5L8720_VIC_N 2 +#define S5L8720_VIC_SIZE 32 + +#define S5L8720_TIMER1_IRQ 0x8 +#define S5L8720_USB_OTG_IRQ 0x13 +#define S5L8720_SPI0_IRQ 0x9 +#define S5L8720_SPI1_IRQ 0xA +#define S5L8720_SPI2_IRQ 0xB +#define S5L8720_SPI3_IRQ 0x1C +#define S5L8720_SPI4_IRQ 0x37 + #define IT2G_CPREG_VAR_NAME(name) cpreg_##name #define IT2G_CPREG_VAR_DEF(name) uint64_t IT2G_CPREG_VAR_NAME(name) @@ -21,10 +38,21 @@ // memory addresses #define VROM_MEM_BASE 0x0 #define SRAM1_MEM_BASE 0x22020000 +#define USBOTG_MEM_BASE 0x38400000 +#define VIC0_MEM_BASE 0x38E00000 +#define VIC1_MEM_BASE 0x38E01000 +#define SYSIC_MEM_BASE 0x39700000 +#define SPI0_MEM_BASE 0x3C300000 +#define USBPHYS_MEM_BASE 0x3C400000 #define CLOCK0_MEM_BASE 0x3C500000 +#define TIMER1_MEM_BASE 0x3C700000 +#define SPI1_MEM_BASE 0x3CE00000 #define GPIO_MEM_BASE 0x3CF00000 #define CHIPID_MEM_BASE 0x3D100000 +#define SPI2_MEM_BASE 0x3D200000 +#define SPI3_MEM_BASE 0x3DA00000 #define CLOCK1_MEM_BASE 0x3E000000 +#define SPI4_MEM_BASE 0x3E100000 typedef struct { MachineClass parent; @@ -32,13 +60,21 @@ typedef struct { typedef struct { MachineState parent; + qemu_irq **irq; ARMCPU *cpu; + PL192State *vic0; + PL192State *vic1; IPodTouchClockState *clock0; IPodTouchClockState *clock1; + IPodTouchTimerState *timer1; IPodTouchChipIDState *chipid_state; IPodTouchGPIOState *gpio_state; + IPodTouchSYSICState *sysic; + synopsys_usb_state *usb_otg; + IPodTouchUSBPhysState *usb_phys_state; IT2G_CPREG_VAR_DEF(REG0); IT2G_CPREG_VAR_DEF(REG1); + Clock *sysclk; } IPodTouchMachineState; #endif \ No newline at end of file diff --git a/include/hw/arm/ipod_touch_spi.h b/include/hw/arm/ipod_touch_spi.h new file mode 100644 index 000000000000..1d37aa91a094 --- /dev/null +++ b/include/hw/arm/ipod_touch_spi.h @@ -0,0 +1,82 @@ +#ifndef HW_ARM_IPOD_TOUCH_SPI_H +#define HW_ARM_IPOD_TOUCH_SPI_H + +#include "qemu/osdep.h" +#include "qemu/fifo8.h" +#include "qemu/log.h" +#include "hw/platform-bus.h" +#include "hw/hw.h" +#include "hw/irq.h" +#include "hw/ssi/ssi.h" + +#define TYPE_IPOD_TOUCH_SPI "ipodtouch.spi" +OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchSPIState, IPOD_TOUCH_SPI) + +#define R_CTRL 0x000 +#define R_CTRL_RUN (1 << 0) +#define R_CTRL_TX_RESET (1 << 2) +#define R_CTRL_RX_RESET (1 << 3) + +#define R_CFG 0x004 +#define R_CFG_AGD (1 << 0) +#define R_CFG_CPHA (1 << 1) +#define R_CFG_CPOL (1 << 2) +#define R_CFG_MODE(_x) (((_x) >> 5) & 0x3) +#define R_CFG_MODE_POLLED 0 +#define R_CFG_MODE_IRQ 1 +#define R_CFG_MODE_DMA 2 +#define R_CFG_IE_RXREADY (1 << 7) +#define R_CFG_IE_TXEMPTY (1 << 8) +#define R_CFG_WORD_SIZE(_x) (((_x) >> 13) & 0x3) +#define R_CFG_WORD_SIZE_8B 0 +#define R_CFG_WORD_SIZE_16B 1 +#define R_CFG_WORD_SIZE_32B 2 +#define R_CFG_IE_COMPLETE (1 << 21) + +#define R_STATUS 0x008 +#define R_STATUS_RXREADY (1 << 0) +#define R_STATUS_TXEMPTY (1 << 1) +#define R_STATUS_RXOVERFLOW (1 << 3) +#define R_STATUS_COMPLETE (1 << 22) +#define R_STATUS_TXFIFO_SHIFT (4) +#define R_STATUS_TXFIFO_MASK (31 << R_STATUS_TXFIFO_SHIFT) +#define R_STATUS_RXFIFO_SHIFT (8) +#define R_STATUS_RXFIFO_MASK (31 << R_STATUS_RXFIFO_SHIFT) + +#define R_PIN 0x00c +#define R_PIN_CS (1 << 1) + +#define R_TXDATA 0x010 +#define R_RXDATA 0x020 +#define R_CLKDIV 0x030 +#define R_CLKDIV_MAX 0x7ff +#define R_RXCNT 0x034 +#define R_WORD_DELAY 0x038 +#define R_TXCNT 0x04c + +#define R_FIFO_DEPTH 50000 + +#define REG(_s,_v) ((_s)->regs[(_v)>>2]) +#define MMIO_SIZE (0x4000) + + +typedef struct IPodTouchSPIState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + SSIBus *spi; + + qemu_irq irq; + uint32_t last_irq; + qemu_irq cs_line; + + Fifo8 rx_fifo; + Fifo8 tx_fifo; + uint32_t regs[MMIO_SIZE >> 2]; + uint32_t mmio_size; + uint8_t base; +} IPodTouchSPIState; + +void set_spi_base(uint32_t base); + +#endif \ No newline at end of file diff --git a/include/hw/arm/ipod_touch_sysic.h b/include/hw/arm/ipod_touch_sysic.h new file mode 100644 index 000000000000..ecf9c2e968d6 --- /dev/null +++ b/include/hw/arm/ipod_touch_sysic.h @@ -0,0 +1,43 @@ +#ifndef IPOD_TOUCH_SYSIC_H +#define IPOD_TOUCH_SYSIC_H + +#include "qemu/osdep.h" +#include "qemu/module.h" +#include "qemu/timer.h" +#include "hw/sysbus.h" +#include "hw/irq.h" + +#define TYPE_IPOD_TOUCH_SYSIC "ipodtouch.sysic" +OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchSYSICState, IPOD_TOUCH_SYSIC) + +#define POWER_ID 0x44 +#define POWER_ONCTRL 0xC +#define POWER_OFFCTRL 0x10 +#define POWER_SETSTATE 0x8 +#define POWER_STATE 0x14 // seems to be toggled by writing a 1 to the right device ID - cleared to 0 when the device has started. + +#define POWER_ID_ADM 0x10 + +// the GPIO IC is part of the system controller +#define GPIO_INTLEVEL 0x80 +#define GPIO_INTSTAT 0xA0 +#define GPIO_INTEN 0xC0 +#define GPIO_INTTYPE 0xE0 + +#define GPIO_NUMINTGROUPS 7 + +typedef struct IPodTouchSYSICState { + SysBusDevice parent_obj; + MemoryRegion iomem; + qemu_irq gpio_irqs[GPIO_NUMINTGROUPS]; + uint32_t power_id; + uint32_t power_state; + + // GPIO + uint32_t gpio_int_level[GPIO_NUMINTGROUPS]; + uint32_t gpio_int_status[GPIO_NUMINTGROUPS]; + uint32_t gpio_int_enabled[GPIO_NUMINTGROUPS]; + uint32_t gpio_int_type[GPIO_NUMINTGROUPS]; +} IPodTouchSYSICState; + +#endif \ No newline at end of file diff --git a/include/hw/arm/ipod_touch_timer.h b/include/hw/arm/ipod_touch_timer.h new file mode 100644 index 000000000000..3a3af5033fbc --- /dev/null +++ b/include/hw/arm/ipod_touch_timer.h @@ -0,0 +1,52 @@ +#ifndef IPOD_TOUCH_TIMER_H +#define IPOD_TOUCH_TIMER_H + +#include "qemu/osdep.h" +#include "qemu/module.h" +#include "qemu/timer.h" +#include "hw/sysbus.h" +#include "hw/irq.h" +#include "hw/clock.h" + +#define TYPE_IPOD_TOUCH_TIMER "ipodtouch.timer" +OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchTimerState, IPOD_TOUCH_TIMER) + +#define TIMER_IRQSTAT 0x10000 +#define TIMER_IRQLATCH 0xF8 +#define TIMER_TICKSHIGH 0x80 +#define TIMER_TICKSLOW 0x84 +#define TIMER_STATE_START 1 +#define TIMER_STATE_STOP 0 +#define TIMER_STATE_MANUALUPDATE 2 +#define NUM_TIMERS 7 +#define TIMER_4 0xA0 +#define TIMER_CONFIG 0 +#define TIMER_STATE 0x4 +#define TIMER_COUNT_BUFFER 0x8 +#define TIMER_COUNT_BUFFER2 0xC + +typedef struct IPodTouchTimerState +{ + SysBusDevice busdev; + MemoryRegion iomem; + uint32_t ticks_high; + uint32_t ticks_low; + uint32_t status; + uint32_t config; + uint32_t bcount1; + uint32_t bcount2; + uint32_t prescaler; + uint32_t irqstat; + QEMUTimer *st_timer; + Clock *sysclk; + uint32_t bcreload; + uint32_t freq_out; + uint64_t tick_interval; + uint64_t last_tick; + uint64_t next_planned_tick; + uint64_t base_time; + qemu_irq irq; + +} IPodTouchTimerState; + +#endif \ No newline at end of file diff --git a/include/hw/arm/ipod_touch_usb_otg.h b/include/hw/arm/ipod_touch_usb_otg.h new file mode 100644 index 000000000000..10cdc75c5eb0 --- /dev/null +++ b/include/hw/arm/ipod_touch_usb_otg.h @@ -0,0 +1,267 @@ +#ifndef HW_ARM_IPOD_TOUCH_USB_OTG_H +#define HW_ARM_IPOD_TOUCH_USB_OTG_H + +#include "hw/irq.h" +#include "hw/usb.h" + +#define DEVICE_NAME "usb_synopsys" + +#define TYPE_S5L8900USBOTG "s5l8900usbotg" +OBJECT_DECLARE_SIMPLE_TYPE(synopsys_usb_state, S5L8900USBOTG) + +// Maximums supported by OIB +#define USB_NUM_ENDPOINTS 8 +#define USB_NUM_FIFOS 16 + +#define RX_FIFO_DEPTH 0x1C0 +#define TX_FIFO_DEPTH 0x1C0 +#define TX_FIFO_STARTADDR 0x200 +#define PERIODIC_TX_FIFO_STARTADDR 0x21B +#define PERIODIC_TX_FIFO_DEPTH 0x100 + +// Registers +#define GOTGCTL 0x0 +#define GOTGINT 0x4 +#define GAHBCFG 0x8 +#define GUSBCFG 0xC +#define GRSTCTL 0x10 +#define GINTSTS 0x14 +#define GINTMSK 0x18 +#define GRXSTSR 0x1C +#define GRXSTSP 0x20 +#define GRXFSIZ 0x24 +#define GNPTXFSIZ 0x28 +#define GNPTXFSTS 0x2C +#define GHWCFG1 0x44 +#define GHWCFG2 0x48 +#define GHWCFG3 0x4C +#define GHWCFG4 0x50 +#define DIEPTXF(x) (0x100 + (4*(x))) +#define DCFG 0x800 +#define DCTL 0x804 +#define DSTS 0x808 +#define DIEPMSK 0x810 +#define DOEPMSK 0x814 +#define DAINTSTS 0x818 +#define DAINTMSK 0x81C +#define DTKNQR1 0x820 +#define DTKNQR2 0x824 +#define DTKNQR3 0x830 +#define DTKNQR4 0x834 +#define USB_INREGS 0x900 +#define USB_OUTREGS 0xB00 +#define USB_EPREGS_SIZE 0x200 + +#define USB_FIFO_START 0x1000 +#define USB_FIFO_SIZE (0x100*(USB_NUM_FIFOS+1)) +#define USB_FIFO_END (USB_FIFO_START+USB_FIFO_SIZE) + +#define PCGCCTL 0xE00 + +#define PCGCCTL_ONOFF_MASK 3 // bits 0, 1 +#define PCGCCTL_ON 0 +#define PCGCCTL_OFF 1 + +#define GOTGCTL_BSESSIONVALID (1 << 19) +#define GOTGCTL_SESSIONREQUEST (1 << 1) + +#define GAHBCFG_DMAEN (1 << 5) +#define GAHBCFG_BSTLEN_SINGLE (0 << 1) +#define GAHBCFG_BSTLEN_INCR (1 << 1) +#define GAHBCFG_BSTLEN_INCR4 (3 << 1) +#define GAHBCFG_BSTLEN_INCR8 (5 << 1) +#define GAHBCFG_BSTLEN_INCR16 (7 << 1) +#define GAHBCFG_MASKINT 0x1 + +#define GUSBCFG_TURNAROUND_MASK 0xF +#define GUSBCFG_TURNAROUND_SHIFT 10 +#define GUSBCFG_HNPENABLE (1 << 9) +#define GUSBCFG_SRPENABLE (1 << 8) +#define GUSBCFG_PHYIF16BIT (1 << 3) +#define USB_UNKNOWNREG1_START 0x1708 + +#define GHWCFG2_TKNDEPTH_SHIFT 26 +#define GHWCFG2_TKNDEPTH_MASK 0xF +#define GHWCFG2_NUM_ENDPOINTS_SHIFT 10 +#define GHWCFG2_NUM_ENDPOINTS_MASK 0xf + +#define GHWCFG4_DED_FIFO_EN (1 << 25) + +#define GRSTCTL_AHBIDLE (1 << 31) +#define GRSTCTL_TXFFLUSH (1 << 5) +#define GRSTCTL_TXFFNUM_SHIFT 6 +#define GRSTCTL_TXFFNUM_MASK 0x1f +#define GRSTCTL_CORESOFTRESET 0x1 +#define GRSTCTL_TKNFLUSH 3 + +#define GINTMSK_NONE 0x0 +#define GINTMSK_OTG (1 << 2) +#define GINTMSK_SOF (1 << 3) +#define GINTMSK_GINNAKEFF (1 << 6) +#define GINTMSK_GOUTNAKEFF (1 << 7) +#define GINTMSK_SUSPEND (1 << 11) +#define GINTMSK_RESET (1 << 12) +#define GINTMSK_ENUMDONE (1 << 13) +#define GINTMSK_EPMIS (1 << 17) +#define GINTMSK_INEP (1 << 18) +#define GINTMSK_OEP (1 << 19) +#define GINTMSK_DISCONNECT (1 << 29) +#define GINTMSK_RESUME (1 << 31) + +#define GOTGINT_SESENDDET (1 << 2) + +#define FIFO_DEPTH_SHIFT 16 + +#define GNPTXFSTS_GET_TXQSPCAVAIL(x) GET_BITS(x, 16, 8) + +#define GHWCFG4_DED_FIFO_EN (1 << 25) + +#define DAINT_ALL 0xFFFFFFFF +#define DAINT_NONE 0 +#define DAINT_OUT_SHIFT 16 +#define DAINT_IN_SHIFT 0 + +#define DCTL_SFTDISCONNECT 0x2 +#define DCTL_PROGRAMDONE (1 << 11) +#define DCTL_CGOUTNAK (1 << 10) +#define DCTL_SGOUTNAK (1 << 9) +#define DCTL_CGNPINNAK (1 << 8) +#define DCTL_SGNPINNAK (1 << 7) + +#define DSTS_GET_SPEED(x) GET_BITS(x, 1, 2) + +#define DCFG_NZSTSOUTHSHK (1 << 2) +#define DCFG_EPMSCNT (1 << 18) +#define DCFG_HISPEED 0x0 +#define DCFG_FULLSPEED 0x1 +#define DCFG_DEVICEADDR_UNSHIFTED_MASK 0x7F +#define DCFG_DEVICEADDR_SHIFT 4 +#define DCFG_DEVICEADDRMSK (DCFG_DEVICEADDR_UNSHIFTED_MASK << DCFG_DEVICEADDR_SHIFT) +#define DCFG_ACTIVE_EP_COUNT_MASK 0x1f +#define DCFG_ACTIVE_EP_COUNT_SHIFT 18 + +#define DOEPTSIZ0_SUPCNT_MASK 0x3 +#define DOEPTSIZ0_SUPCNT_SHIFT 29 +#define DOEPTSIZ0_PKTCNT_MASK 0x1 +#define DEPTSIZ0_XFERSIZ_MASK 0x7F +#define DIEPTSIZ_MC_MASK 0x3 +#define DIEPTSIZ_MC_SHIFT 29 +#define DEPTSIZ_PKTCNT_MASK 0x3FF +#define DEPTSIZ_PKTCNT_SHIFT 19 +#define DEPTSIZ_XFERSIZ_MASK 0x1FFFF + +// ENDPOINT_DIRECTIONS register has two bits per endpoint. 0, 1 for endpoint 0. 1, 2 for end point 1, etc. +#define USB_EP_DIRECTION(ep) (USBDirection)(2-((GET_REG(USB + GHWCFG1) >> ((ep) * 2)) & 0x3)) +#define USB_ENDPOINT_DIRECTIONS_BIDIR 0 +#define USB_ENDPOINT_DIRECTIONS_IN 1 +#define USB_ENDPOINT_DIRECTIONS_OUT 2 + +#define USB_START_DELAYUS 10000 +#define USB_SFTDISCONNECT_DELAYUS 4000 +#define USB_ONOFFSTART_DELAYUS 100 +#define USB_RESETWAITFINISH_DELAYUS 1000 +#define USB_SFTCONNECT_DELAYUS 250 +#define USB_PROGRAMDONE_DELAYUS 10 + +#define USB_EPCON_ENABLE (1 << 31) +#define USB_EPCON_DISABLE (1 << 30) +#define USB_EPCON_SETD0PID (1 << 28) +#define USB_EPCON_SETNAK (1 << 27) +#define USB_EPCON_CLEARNAK (1 << 26) +#define USB_EPCON_TXFNUM_MASK 0xf +#define USB_EPCON_TXFNUM_SHIFT 22 +#define USB_EPCON_STALL (1 << 21) +#define USB_EPCON_TYPE_MASK 0x3 +#define USB_EPCON_TYPE_SHIFT 18 +#define USB_EPCON_NAKSTS (1 << 17) +#define USB_EPCON_ACTIVE (1 << 15) +#define USB_EPCON_NEXTEP_MASK 0xF +#define USB_EPCON_NEXTEP_SHIFT 11 +#define USB_EPCON_MPS_MASK 0x7FF + +#define USB_EPINT_INEPNakEff 0x40 +#define USB_EPINT_INTknEPMis 0x20 +#define USB_EPINT_INTknTXFEmp 0x10 +#define USB_EPINT_TimeOUT 0x8 +#define USB_EPINT_AHBErr 0x4 +#define USB_EPINT_EPDisbld 0x2 +#define USB_EPINT_XferCompl 0x1 + +#define USB_EPINT_Back2BackSetup (1 << 6) +#define USB_EPINT_OUTTknEPDis 0x10 +#define USB_EPINT_SetUp 0x8 +#define USB_EPINT_EpDisbld 0x1 +#define USB_EPINT_NONE 0 +#define USB_EPINT_ALL 0xFFFFFFFF + +#define USB_2_0 0x0200 + +#define USB_HIGHSPEED 0 +#define USB_FULLSPEED 1 +#define USB_LOWSPEED 2 +#define USB_FULLSPEED_48_MHZ 3 + +#define USB_CONTROLEP 0 + +typedef struct _synopsys_usb_ep_state +{ + uint32_t control; + uint32_t tx_size; + uint32_t fifo; + uint32_t interrupt_status; + + hwaddr dma_address; + hwaddr dma_buffer; + +} synopsys_usb_ep_state; + +typedef struct synopsys_usb_state +{ + SysBusDevice busdev; + MemoryRegion iomem; + qemu_irq irq; + + char *server_host; + uint32_t server_port; + //tcp_usb_state_t tcp_state; + + uint32_t pcgcctl; + + uint32_t ghwcfg1; + uint32_t ghwcfg2; + uint32_t ghwcfg3; + uint32_t ghwcfg4; + + uint32_t gahbcfg; + uint32_t gusbcfg; + + uint32_t grxfsiz; + uint32_t gnptxfsiz; + + uint32_t gotgctl; + uint32_t gotgint; + uint32_t grstctl; + uint32_t gintmsk; + uint32_t gintsts; + + uint32_t dptxfsiz[USB_NUM_FIFOS]; + + uint32_t dctl; + uint32_t dcfg; + uint32_t dsts; + + uint32_t daintmsk; + uint32_t daintsts; + uint32_t diepmsk; + uint32_t doepmsk; + + synopsys_usb_ep_state in_eps[USB_NUM_ENDPOINTS]; + synopsys_usb_ep_state out_eps[USB_NUM_ENDPOINTS]; + + uint8_t fifos[0x100 * (USB_NUM_FIFOS+1)]; + +} synopsys_usb_state; + +DeviceState *ipod_touch_init_usb_otg(qemu_irq _irq, uint32_t _hwcfg[4]); + +#endif \ No newline at end of file diff --git a/include/hw/arm/ipod_touch_usb_phys.h b/include/hw/arm/ipod_touch_usb_phys.h new file mode 100644 index 000000000000..26aff29cde21 --- /dev/null +++ b/include/hw/arm/ipod_touch_usb_phys.h @@ -0,0 +1,28 @@ +#ifndef HW_ARM_IPOD_TOUCH_USB_PHYS_H +#define HW_ARM_IPOD_TOUCH_USB_PHYS_H + +#include "qemu/osdep.h" +#include "hw/hw.h" +#include "hw/sysbus.h" + +#define TYPE_IPOD_TOUCH_USB_PHYS "ipodtouch.usbphys" +OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchUSBPhysState, IPOD_TOUCH_USB_PHYS) + +#define REG_OPHYPWR 0x0 +#define REG_OPHYCLK 0x4 +#define REG_ORSTCON 0x8 +#define REG_UNKNOWN1 0x1C +#define REG_OPHYTUNE 0x20 + +typedef struct IPodTouchUSBPhysState { + SysBusDevice busdev; + MemoryRegion iomem; + + uint32_t usb_ophypwr; + uint32_t usb_ophyclk; + uint32_t usb_orstcon; + uint32_t usb_unknown1; + uint32_t usb_ophytune; +} IPodTouchUSBPhysState; + +#endif \ No newline at end of file diff --git a/include/hw/intc/pl192.h b/include/hw/intc/pl192.h new file mode 100644 index 000000000000..cb7bb03652f3 --- /dev/null +++ b/include/hw/intc/pl192.h @@ -0,0 +1,80 @@ +#ifndef PL192_H +#define PL192_H + +#include "qemu/osdep.h" + +#define TYPE_PL192 "pl192" +OBJECT_DECLARE_SIMPLE_TYPE(PL192State, PL192) + + +#define PL192_INT_SOURCES 32 +#define PL192_DAISY_IRQ PL192_INT_SOURCES +#define PL192_NO_IRQ PL192_INT_SOURCES+1 +#define PL192_PRIO_LEVELS 16 + +#define PL192_IRQSTATUS 0x00 +#define PL192_FIQSTATUS 0x04 +#define PL192_RAWINTR 0x08 +#define PL192_INTSELECT 0x0C +#define PL192_INTENABLE 0x10 +#define PL192_INTENCLEAR 0x14 +#define PL192_SOFTINT 0x18 +#define PL192_SOFTINTCLEAR 0x1C +#define PL192_PROTECTION 0x20 +#define PL192_SWPRIORITYMASK 0x24 +#define PL192_PRIORITYDAISY 0x28 +#define PL192_VECTADDR 0xF00 +#define PL192_IOMEM_SIZE 0x1000 + +#define PL190_ITCR 0x300 +#define PL190_VECTADDR 0x30 +#define PL190_DEFVECTADDR 0x34 + +#define PL192_IOMEM_SIZE 0x1000 + + +struct PL192State { + SysBusDevice busdev; + MemoryRegion iomem; + + /* Control registers */ + uint32_t irq_status; + uint32_t fiq_status; + uint32_t rawintr; + uint32_t intselect; + uint32_t intenable; + uint32_t softint; + uint32_t protection; + uint32_t sw_priority_mask; + uint32_t vect_addr[PL192_INT_SOURCES]; + uint32_t vect_priority[PL192_INT_SOURCES]; + uint32_t address; + + /* Currently processed interrupt and + highest priority interrupt */ + uint32_t current; + uint32_t current_highest; + + /* Priority masking logic */ + int32_t stack_i; + uint32_t priority_stack[PL192_PRIO_LEVELS+1]; + uint8_t irq_stack[PL192_PRIO_LEVELS+1]; + uint32_t priority; + + /* Daisy-chain interface */ + uint32_t daisy_vectaddr; + uint32_t daisy_priority; + PL192State *daisy_callback; + uint8_t daisy_input; + + /* Parent interrupts */ + qemu_irq irq; + qemu_irq fiq; + + /* Next controller in chain */ + PL192State *daisy; +}; + +DeviceState *pl192_manual_init(char *mem_name, ...); + +#endif \ No newline at end of file From bcb4f83561499c71efb84f5dceb5b0a3d17a6dbe Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Sun, 25 Dec 2022 09:15:45 +0100 Subject: [PATCH 03/58] Added NOR SPI peripheral --- hw/arm/ipod_touch_nor_spi.c | 56 +++++++++++++++++++++++++++++ hw/arm/ipod_touch_spi.c | 1 + hw/arm/meson.build | 2 +- include/hw/arm/ipod_touch_nor_spi.h | 17 +++++++++ include/hw/arm/ipod_touch_spi.h | 1 + 5 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 hw/arm/ipod_touch_nor_spi.c create mode 100644 include/hw/arm/ipod_touch_nor_spi.h diff --git a/hw/arm/ipod_touch_nor_spi.c b/hw/arm/ipod_touch_nor_spi.c new file mode 100644 index 000000000000..3943f08a2d2a --- /dev/null +++ b/hw/arm/ipod_touch_nor_spi.c @@ -0,0 +1,56 @@ +#include "hw/arm/ipod_touch_nor_spi.h" + +static uint32_t ipod_touch_nor_spi_transfer(SSIPeripheral *dev, uint32_t value) +{ + IPodTouchNORSPIState *s = IPOD_TOUCH_NOR_SPI(dev); + + printf("NOR SPI received value 0x%08x\n", value); + + if(!s->cur_cmd && (value == 0x5)) { + // this is a command -> set it + s->cur_cmd = value; + return 0x0; + } + + if(s->cur_cmd) { + uint32_t res = 0; + switch(s->cur_cmd) { + case 0x5: + res = 0x1; + break; + default: + break; + } + + s->cur_cmd = 0; + return res; + } + + return 0x0; +} + +static void ipod_touch_nor_spi_realize(SSIPeripheral *d, Error **errp) +{ + +} + +static void ipod_touch_nor_spi_class_init(ObjectClass *klass, void *data) +{ + SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass); + k->realize = ipod_touch_nor_spi_realize; + k->transfer = ipod_touch_nor_spi_transfer; +} + +static const TypeInfo ipod_touch_nor_spi_type_info = { + .name = TYPE_IPOD_TOUCH_NOR_SPI, + .parent = TYPE_SSI_PERIPHERAL, + .instance_size = sizeof(IPodTouchNORSPIState), + .class_init = ipod_touch_nor_spi_class_init, +}; + +static void ipod_touch_nor_spi_register_types(void) +{ + type_register_static(&ipod_touch_nor_spi_type_info); +} + +type_init(ipod_touch_nor_spi_register_types) diff --git a/hw/arm/ipod_touch_spi.c b/hw/arm/ipod_touch_spi.c index f27a188df9c7..860b28bd9568 100644 --- a/hw/arm/ipod_touch_spi.c +++ b/hw/arm/ipod_touch_spi.c @@ -274,6 +274,7 @@ static void ipod_touch_spi_realize(DeviceState *dev, struct Error **errp) // create the peripheral switch(s->base) { case 0: + ssi_create_peripheral(s->spi, TYPE_IPOD_TOUCH_NOR_SPI); break; case 1: //ssi_create_peripheral(s->spi, TYPE_IPOD_TOUCH_LCD_PANEL); diff --git a/hw/arm/meson.build b/hw/arm/meson.build index 717d422f7e48..61d95cfbf1e4 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -62,6 +62,6 @@ arm_ss.add(when: 'CONFIG_FSL_IMX7', if_true: files('fsl-imx7.c', 'mcimx7d-sabre. arm_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c', 'smmuv3.c')) arm_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c')) arm_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c')) -arm_ss.add(when: 'CONFIG_IPOD_TOUCH_2G', if_true: files('ipod_touch_2g.c', 'ipod_touch_clock.c', 'ipod_touch_chipid.c', 'ipod_touch_gpio.c', 'ipod_touch_sysic.c', 'ipod_touch_timer.c', 'ipod_touch_usb_otg.c', 'ipod_touch_usb_phys.c', 'ipod_touch_spi.c')) +arm_ss.add(when: 'CONFIG_IPOD_TOUCH_2G', if_true: files('ipod_touch_2g.c', 'ipod_touch_clock.c', 'ipod_touch_chipid.c', 'ipod_touch_gpio.c', 'ipod_touch_sysic.c', 'ipod_touch_timer.c', 'ipod_touch_usb_otg.c', 'ipod_touch_usb_phys.c', 'ipod_touch_spi.c', 'ipod_touch_nor_spi.c')) hw_arch += {'arm': arm_ss} diff --git a/include/hw/arm/ipod_touch_nor_spi.h b/include/hw/arm/ipod_touch_nor_spi.h new file mode 100644 index 000000000000..ebbd33ba6db5 --- /dev/null +++ b/include/hw/arm/ipod_touch_nor_spi.h @@ -0,0 +1,17 @@ +#ifndef IPOD_TOUCH_NOR_SPI_H +#define IPOD_TOUCH_NOR_SPI_H + +#include "qemu/osdep.h" +#include "qemu/module.h" +#include "qemu/timer.h" +#include "hw/ssi/ssi.h" + +#define TYPE_IPOD_TOUCH_NOR_SPI "ipodtouch.norspi" +OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchNORSPIState, IPOD_TOUCH_NOR_SPI) + +typedef struct IPodTouchNORSPIState { + SSIPeripheral ssidev; + uint32_t cur_cmd; +} IPodTouchNORSPIState; + +#endif \ No newline at end of file diff --git a/include/hw/arm/ipod_touch_spi.h b/include/hw/arm/ipod_touch_spi.h index 1d37aa91a094..2703324782fa 100644 --- a/include/hw/arm/ipod_touch_spi.h +++ b/include/hw/arm/ipod_touch_spi.h @@ -8,6 +8,7 @@ #include "hw/hw.h" #include "hw/irq.h" #include "hw/ssi/ssi.h" +#include "hw/arm/ipod_touch_nor_spi.h" #define TYPE_IPOD_TOUCH_SPI "ipodtouch.spi" OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchSPIState, IPOD_TOUCH_SPI) From 5ed081ec42eb6fb1eeefed1bd2e898982c018920 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Sun, 25 Dec 2022 23:38:03 +0100 Subject: [PATCH 04/58] S5L8720 SPI seems to be functional --- hw/arm/ipod_touch_chipid.c | 6 +++++- hw/arm/ipod_touch_nor_spi.c | 4 ++-- hw/arm/ipod_touch_spi.c | 15 ++++----------- include/hw/arm/ipod_touch_chipid.h | 2 ++ include/hw/arm/ipod_touch_spi.h | 15 ++++----------- 5 files changed, 17 insertions(+), 25 deletions(-) diff --git a/hw/arm/ipod_touch_chipid.c b/hw/arm/ipod_touch_chipid.c index e7cbc5d31716..eed1a52ea7a5 100644 --- a/hw/arm/ipod_touch_chipid.c +++ b/hw/arm/ipod_touch_chipid.c @@ -9,6 +9,10 @@ static uint64_t ipod_touch_chipid_read(void *opaque, hwaddr addr, unsigned size) return 0; case CHIPID_INFO: return (0x8720 << 16) | 0x1; + case CHIPID_UNKNOWN2: + return 0; + case CHIPID_UNKNOWN3: + return 0; default: hw_error("%s: reading from unknown chip ID register 0x%08x\n", __func__, addr); } @@ -26,7 +30,7 @@ static void ipod_touch_chipid_init(Object *obj) IPodTouchChipIDState *s = IPOD_TOUCH_CHIPID(obj); SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - memory_region_init_io(&s->iomem, obj, &ipod_touch_chipid_ops, s, TYPE_IPOD_TOUCH_CHIPID, 0x10); + memory_region_init_io(&s->iomem, obj, &ipod_touch_chipid_ops, s, TYPE_IPOD_TOUCH_CHIPID, 0x14); sysbus_init_mmio(sbd, &s->iomem); } diff --git a/hw/arm/ipod_touch_nor_spi.c b/hw/arm/ipod_touch_nor_spi.c index 3943f08a2d2a..c9d96a3ae797 100644 --- a/hw/arm/ipod_touch_nor_spi.c +++ b/hw/arm/ipod_touch_nor_spi.c @@ -4,7 +4,7 @@ static uint32_t ipod_touch_nor_spi_transfer(SSIPeripheral *dev, uint32_t value) { IPodTouchNORSPIState *s = IPOD_TOUCH_NOR_SPI(dev); - printf("NOR SPI received value 0x%08x\n", value); + //printf("NOR SPI received value 0x%08x\n", value); if(!s->cur_cmd && (value == 0x5)) { // this is a command -> set it @@ -16,7 +16,7 @@ static uint32_t ipod_touch_nor_spi_transfer(SSIPeripheral *dev, uint32_t value) uint32_t res = 0; switch(s->cur_cmd) { case 0x5: - res = 0x1; + res = 0x0; break; default: break; diff --git a/hw/arm/ipod_touch_spi.c b/hw/arm/ipod_touch_spi.c index 860b28bd9568..93fb992c2307 100644 --- a/hw/arm/ipod_touch_spi.c +++ b/hw/arm/ipod_touch_spi.c @@ -130,7 +130,6 @@ static uint64_t ipod_touch_spi_read(void *opaque, hwaddr addr, unsigned size) //fprintf(stderr, "%s (base %d): read from location 0x%08x\n", __func__, s->base, addr); uint32_t r; - bool run = false; r = s->regs[addr >> 2]; switch (addr) { @@ -145,17 +144,12 @@ static uint64_t ipod_touch_spi_read(void *opaque, hwaddr addr, unsigned size) } buf = fifo8_pop_buf(&s->rx_fifo, word_size, &num); memcpy(&r, buf, num); - if (fifo8_is_empty(&s->rx_fifo)) { - run = true; - } break; } case R_STATUS: { int val = 0; - val |= fifo8_num_used(&s->tx_fifo) << R_STATUS_TXFIFO_SHIFT; - val |= fifo8_num_used(&s->rx_fifo) << R_STATUS_RXFIFO_SHIFT; - val &= (R_STATUS_TXFIFO_MASK | R_STATUS_RXFIFO_MASK); - r &= ~(R_STATUS_TXFIFO_MASK | R_STATUS_RXFIFO_MASK); + val |= (fifo8_num_used(&s->tx_fifo) << R_STATUS_TXFIFO_SHIFT); + val |= (fifo8_num_used(&s->rx_fifo) << R_STATUS_RXFIFO_SHIFT); r |= val; break; } @@ -163,9 +157,6 @@ static uint64_t ipod_touch_spi_read(void *opaque, hwaddr addr, unsigned size) break; } - if (run) { - apple_spi_run(s); - } apple_spi_update_irq(s); return r; } @@ -194,6 +185,8 @@ static void ipod_touch_spi_write(void *opaque, hwaddr addr, uint64_t data, unsig } break; case R_STATUS: + fifo8_reset(&s->tx_fifo); + fifo8_reset(&s->rx_fifo); r = old & (~r); run = true; break; diff --git a/include/hw/arm/ipod_touch_chipid.h b/include/hw/arm/ipod_touch_chipid.h index c6755b9fcf0d..2921f259f32f 100644 --- a/include/hw/arm/ipod_touch_chipid.h +++ b/include/hw/arm/ipod_touch_chipid.h @@ -10,6 +10,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchChipIDState, IPOD_TOUCH_CHIPID) #define CHIPID_UNKNOWN1 0x4 #define CHIPID_INFO 0x8 +#define CHIPID_UNKNOWN2 0xC +#define CHIPID_UNKNOWN3 0x10 typedef struct IPodTouchChipIDState { SysBusDevice busdev; diff --git a/include/hw/arm/ipod_touch_spi.h b/include/hw/arm/ipod_touch_spi.h index 2703324782fa..c635f8cf6c18 100644 --- a/include/hw/arm/ipod_touch_spi.h +++ b/include/hw/arm/ipod_touch_spi.h @@ -22,13 +22,9 @@ OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchSPIState, IPOD_TOUCH_SPI) #define R_CFG_AGD (1 << 0) #define R_CFG_CPHA (1 << 1) #define R_CFG_CPOL (1 << 2) -#define R_CFG_MODE(_x) (((_x) >> 5) & 0x3) -#define R_CFG_MODE_POLLED 0 -#define R_CFG_MODE_IRQ 1 -#define R_CFG_MODE_DMA 2 #define R_CFG_IE_RXREADY (1 << 7) #define R_CFG_IE_TXEMPTY (1 << 8) -#define R_CFG_WORD_SIZE(_x) (((_x) >> 13) & 0x3) +#define R_CFG_WORD_SIZE(_x) (((_x) >> 15) & 0x3) #define R_CFG_WORD_SIZE_8B 0 #define R_CFG_WORD_SIZE_16B 1 #define R_CFG_WORD_SIZE_32B 2 @@ -39,10 +35,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchSPIState, IPOD_TOUCH_SPI) #define R_STATUS_TXEMPTY (1 << 1) #define R_STATUS_RXOVERFLOW (1 << 3) #define R_STATUS_COMPLETE (1 << 22) -#define R_STATUS_TXFIFO_SHIFT (4) -#define R_STATUS_TXFIFO_MASK (31 << R_STATUS_TXFIFO_SHIFT) -#define R_STATUS_RXFIFO_SHIFT (8) -#define R_STATUS_RXFIFO_MASK (31 << R_STATUS_RXFIFO_SHIFT) +#define R_STATUS_TXFIFO_SHIFT (6) +#define R_STATUS_RXFIFO_SHIFT (11) #define R_PIN 0x00c #define R_PIN_CS (1 << 1) @@ -55,7 +49,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchSPIState, IPOD_TOUCH_SPI) #define R_WORD_DELAY 0x038 #define R_TXCNT 0x04c -#define R_FIFO_DEPTH 50000 +#define R_FIFO_DEPTH 16 #define REG(_s,_v) ((_s)->regs[(_v)>>2]) #define MMIO_SIZE (0x4000) @@ -74,7 +68,6 @@ typedef struct IPodTouchSPIState { Fifo8 rx_fifo; Fifo8 tx_fifo; uint32_t regs[MMIO_SIZE >> 2]; - uint32_t mmio_size; uint8_t base; } IPodTouchSPIState; From a8aa1cc8d8654a5a1e580bab5351993c02a5c366 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Mon, 26 Dec 2022 15:07:27 +0100 Subject: [PATCH 05/58] NOR SPI seems to work --- hw/arm/ipod_touch_2g.c | 31 +++++- hw/arm/ipod_touch_aes.c | 135 ++++++++++++++++++++++++ hw/arm/ipod_touch_nor_spi.c | 85 +++++++++++++--- hw/arm/ipod_touch_sha1.c | 153 ++++++++++++++++++++++++++++ hw/arm/ipod_touch_spi.c | 2 + hw/arm/meson.build | 2 +- include/hw/arm/ipod_touch_2g.h | 7 ++ include/hw/arm/ipod_touch_aes.h | 69 +++++++++++++ include/hw/arm/ipod_touch_nor_spi.h | 14 +++ include/hw/arm/ipod_touch_sha1.h | 38 +++++++ include/hw/arm/ipod_touch_spi.h | 1 + 11 files changed, 519 insertions(+), 18 deletions(-) create mode 100644 hw/arm/ipod_touch_aes.c create mode 100644 hw/arm/ipod_touch_sha1.c create mode 100644 include/hw/arm/ipod_touch_aes.h create mode 100644 include/hw/arm/ipod_touch_sha1.h diff --git a/hw/arm/ipod_touch_2g.c b/hw/arm/ipod_touch_2g.c index 6662f981f38f..e2dfd4ad4111 100644 --- a/hw/arm/ipod_touch_2g.c +++ b/hw/arm/ipod_touch_2g.c @@ -92,9 +92,22 @@ static void ipod_touch_memory_setup(MachineState *machine, MemoryRegion *sysmem, } } +static char *ipod_touch_get_nor_path(Object *obj, Error **errp) +{ + IPodTouchMachineState *nms = IPOD_TOUCH_MACHINE(obj); + return g_strdup(nms->nor_path); +} + +static void ipod_touch_set_nor_path(Object *obj, const char *value, Error **errp) +{ + IPodTouchMachineState *nms = IPOD_TOUCH_MACHINE(obj); + g_strlcpy(nms->nor_path, value, sizeof(nms->nor_path)); +} + static void ipod_touch_instance_init(Object *obj) { - + object_property_add_str(obj, "nor", ipod_touch_get_nor_path, ipod_touch_set_nor_path); + object_property_set_description(obj, "nor", "Path to the S5L8720 NOR image"); } static inline qemu_irq s5l8900_get_irq(IPodTouchMachineState *s, int n) @@ -182,7 +195,9 @@ static void ipod_touch_machine_init(MachineState *machine) // init spis set_spi_base(0); - sysbus_create_simple("ipodtouch.spi", SPI0_MEM_BASE, s5l8900_get_irq(nms, S5L8720_SPI0_IRQ)); + dev = sysbus_create_simple("ipodtouch.spi", SPI0_MEM_BASE, s5l8900_get_irq(nms, S5L8720_SPI0_IRQ)); + IPodTouchSPIState *spi0_state = IPOD_TOUCH_SPI(dev); + strcpy(spi0_state->nor->nor_path, nms->nor_path); set_spi_base(1); sysbus_create_simple("ipodtouch.spi", SPI1_MEM_BASE, s5l8900_get_irq(nms, S5L8720_SPI1_IRQ)); @@ -216,6 +231,18 @@ static void ipod_touch_machine_init(MachineState *machine) ipod_touch_memory_setup(machine, sysmem, nsas); + // init SHA1 engine + dev = qdev_new("ipodtouch.sha1"); + IPodTouchSHA1State *sha1_state = IPOD_TOUCH_SHA1(dev); + nms->sha1_state = sha1_state; + memory_region_add_subregion(sysmem, SHA1_MEM_BASE, &sha1_state->iomem); + + // init AES engine + dev = qdev_new("ipodtouch.aes"); + IPodTouchAESState *aes_state = IPOD_TOUCH_AES(dev); + nms->aes_state = aes_state; + memory_region_add_subregion(sysmem, AES_MEM_BASE, &aes_state->iomem); + qemu_register_reset(ipod_touch_cpu_reset, nms); } diff --git a/hw/arm/ipod_touch_aes.c b/hw/arm/ipod_touch_aes.c new file mode 100644 index 000000000000..0076a571d6d0 --- /dev/null +++ b/hw/arm/ipod_touch_aes.c @@ -0,0 +1,135 @@ +#include "hw/arm/ipod_touch_aes.h" + +static uint64_t ipod_touch_aes_read(void *opaque, hwaddr offset, unsigned size) +{ + struct IPodTouchAESState *aesop = (struct IPodTouchAESState *)opaque; + + switch(offset) { + case AES_STATUS: + return aesop->status; + default: + //fprintf(stderr, "%s: UNMAPPED AES_ADDR @ offset 0x%08x\n", __FUNCTION__, offset); + break; + } + + return 0; +} + +static void ipod_touch_aes_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) +{ + struct IPodTouchAESState *aesop = (struct IPodTouchAESState *)opaque; + static uint8_t keylenop = 0; + + uint8_t *inbuf; + uint8_t *buf; + + // fprintf(stderr, "%s: offset 0x%08x value 0x%08x\n", __FUNCTION__, offset, value); + + switch(offset) { + case AES_GO: + inbuf = (uint8_t *)malloc(aesop->insize); + cpu_physical_memory_read((aesop->inaddr - 0x80000000), inbuf, aesop->insize); + + switch(aesop->keytype) { + case AESGID: + fprintf(stderr, "%s: No support for GID key\n", __func__); + return; + case AESUID: + AES_set_decrypt_key(key_uid, sizeof(key_uid) * 8, &aesop->decryptKey); + break; + case AESCustom: + AES_set_decrypt_key((uint8_t *)aesop->custkey, 0x20 * 8, &aesop->decryptKey); + break; + } + + buf = (uint8_t *) malloc(aesop->insize); + + AES_cbc_encrypt(inbuf, buf, aesop->insize, &aesop->decryptKey, (uint8_t *)aesop->ivec, aesop->operation); + + cpu_physical_memory_write((aesop->outaddr - 0x80000000), buf, aesop->insize); + memset(aesop->custkey, 0, 0x20); + memset(aesop->ivec, 0, 0x10); + free(inbuf); + free(buf); + keylenop = 0; + aesop->outsize = aesop->insize; + aesop->status = 0xf; + break; + case AES_KEYLEN: + if(keylenop == 1) { + aesop->operation = value; + } + keylenop++; + aesop->keylen = value; + break; + case AES_INADDR: + aesop->inaddr = value; + break; + case AES_INSIZE: + aesop->insize = value; + break; + case AES_OUTSIZE: + aesop->outsize = value; + break; + case AES_OUTADDR: + aesop->outaddr = value; + break; + case AES_TYPE: + aesop->keytype = value; + break; + case AES_KEY_REG ... ((AES_KEY_REG + AES_KEYSIZE) - 1): + { + uint8_t idx = (offset - AES_KEY_REG) / 4; + aesop->custkey[idx] |= value; + break; + } + case AES_IV_REG ... ((AES_IV_REG + AES_IVSIZE) -1 ): + { + uint8_t idx = (offset - AES_IV_REG) / 4; + aesop->ivec[idx] |= value; + break; + } + default: + //fprintf(stderr, "%s: UNMAPPED AES_ADDR @ offset 0x%08x - 0x%08x\n", __FUNCTION__, offset, value); + break; + } +} + +static const MemoryRegionOps aes_ops = { + .read = ipod_touch_aes_read, + .write = ipod_touch_aes_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void ipod_touch_aes_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(sbd); + IPodTouchAESState *s = IPOD_TOUCH_AES(dev); + + memory_region_init_io(&s->iomem, obj, &aes_ops, s, "aes", 0x100); + sysbus_init_mmio(sbd, &s->iomem); + + memset(&s->custkey, 0, 8 * sizeof(uint32_t)); + memset(&s->ivec, 0, 4 * sizeof(uint32_t)); +} + +static void ipod_touch_aes_class_init(ObjectClass *klass, void *data) +{ + +} + +static const TypeInfo ipod_touch_aes_info = { + .name = TYPE_IPOD_TOUCH_AES, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IPodTouchAESState), + .instance_init = ipod_touch_aes_init, + .class_init = ipod_touch_aes_class_init, +}; + +static void ipod_touch_machine_types(void) +{ + type_register_static(&ipod_touch_aes_info); +} + +type_init(ipod_touch_machine_types) \ No newline at end of file diff --git a/hw/arm/ipod_touch_nor_spi.c b/hw/arm/ipod_touch_nor_spi.c index c9d96a3ae797..52ff35627a38 100644 --- a/hw/arm/ipod_touch_nor_spi.c +++ b/hw/arm/ipod_touch_nor_spi.c @@ -1,37 +1,92 @@ #include "hw/arm/ipod_touch_nor_spi.h" +static void initialize_nor(IPodTouchNORSPIState *s) +{ + unsigned long fsize; + // TODO still hardcoded, string copy not working... + if (g_file_get_contents("/Users/martijndevos/Documents/generate_nor_it2g/nor.bin", (char **)&s->nor_data, &fsize, NULL)) { + s->nor_initialized = true; + } +} + static uint32_t ipod_touch_nor_spi_transfer(SSIPeripheral *dev, uint32_t value) { IPodTouchNORSPIState *s = IPOD_TOUCH_NOR_SPI(dev); //printf("NOR SPI received value 0x%08x\n", value); - if(!s->cur_cmd && (value == 0x5)) { - // this is a command -> set it + if(s->cur_cmd == NOR_READ_DATA_CMD && s->in_buf_cur_ind == s->in_buf_size && value != 0xFF) { + // if we are currently reading from the NOR data and we receive a value that's not the sentinel, reset the current command. + s->cur_cmd = 0; + } + + if(s->cur_cmd == 0) { + // this is a new command -> set it s->cur_cmd = value; + s->out_buf = malloc(0x1000); + s->in_buf = malloc(0x100); + s->in_buf[0] = value; + s->in_buf_size = 0; + s->in_buf_cur_ind = 1; + s->out_buf_cur_ind = 0; + + if(value == NOR_GET_STATUS_CMD) { + s->in_buf_size = 1; + s->out_buf_size = 1; + } + else if(value == NOR_READ_DATA_CMD) { + s->in_buf_size = 4; + s->out_buf_size = 4096; + } + else { + hw_error("Unknown command 0x%02x!", value); + } + return 0x0; } + else if(s->cur_cmd != 0 && s->in_buf_cur_ind < s->in_buf_size) { + // we're reading the command + s->in_buf[s->in_buf_cur_ind] = value; + s->in_buf_cur_ind++; - if(s->cur_cmd) { - uint32_t res = 0; - switch(s->cur_cmd) { - case 0x5: - res = 0x0; - break; - default: - break; + if(s->cur_cmd == NOR_GET_STATUS_CMD && s->in_buf_cur_ind == s->in_buf_size) { + s->out_buf[0] = 0x0; // indicates that the NOR is ready + } + else if(s->cur_cmd == NOR_READ_DATA_CMD && s->in_buf_cur_ind == s->in_buf_size) { + if(!s->nor_initialized) { initialize_nor(s); } + s->nor_read_ind = (s->in_buf[1] << 16) | (s->in_buf[2] << 8) | s->in_buf[3]; + printf("Read index: %d\n", s->nor_read_ind); } - s->cur_cmd = 0; - return res; + return 0x0; + } + else { + uint8_t ret_val; + // otherwise, we're outputting the response + if(s->cur_cmd == NOR_READ_DATA_CMD) { + uint8_t ret_val = s->nor_data[s->nor_read_ind]; + s->nor_read_ind++; + return ret_val; + } + else { + ret_val = s->out_buf[s->out_buf_cur_ind]; + s->out_buf_cur_ind++; + + if(s->cur_cmd != 0 && (s->out_buf_cur_ind == s->out_buf_size)) { + // the command is done - clean up + s->cur_cmd = 0; + free(s->in_buf); + free(s->out_buf); + } + } + return ret_val; } - - return 0x0; } static void ipod_touch_nor_spi_realize(SSIPeripheral *d, Error **errp) { - + IPodTouchNORSPIState *s = IPOD_TOUCH_NOR_SPI(d); + s->nor_initialized = 0; } static void ipod_touch_nor_spi_class_init(ObjectClass *klass, void *data) diff --git a/hw/arm/ipod_touch_sha1.c b/hw/arm/ipod_touch_sha1.c new file mode 100644 index 000000000000..b3325bff46c2 --- /dev/null +++ b/hw/arm/ipod_touch_sha1.c @@ -0,0 +1,153 @@ +#include "hw/arm/ipod_touch_sha1.h" + +static uint64_t swapLong(void *X) { + uint64_t x = (uint64_t) X; + x = (x & 0x00000000FFFFFFFF) << 32 | (x & 0xFFFFFFFF00000000) >> 32; + x = (x & 0x0000FFFF0000FFFF) << 16 | (x & 0xFFFF0000FFFF0000) >> 16; + x = (x & 0x00FF00FF00FF00FF) << 8 | (x & 0xFF00FF00FF00FF00) >> 8; + return x; +} + +static void flush_hw_buffer(IPodTouchSHA1State *s) { + // Flush the hardware buffer to the state buffer and clear the buffer. + memcpy(s->buffer + s->buffer_ind, (uint8_t *)s->hw_buffer, 0x40); + memset(s->hw_buffer, 0, 0x40); + s->hw_buffer_dirty = false; + s->buffer_ind += 0x40; +} + +static void sha1_reset(IPodTouchSHA1State *s) +{ + s->config = 0; + s->memory_start = 0; + s->memory_mode = 0; + s->insize = 0; + memset(&s->buffer, 0, SHA1_BUFFER_SIZE); + memset(&s->hw_buffer, 0, 0x10 * sizeof(uint32_t)); + s->buffer_ind = 0; + memset(&s->hashout, 0, 0x14); + s->hw_buffer_dirty = false; + s->hash_computed = false; +} + +static uint64_t ipod_touch_sha1_read(void *opaque, hwaddr offset, unsigned size) +{ + IPodTouchSHA1State *s = (IPodTouchSHA1State *)opaque; + + //fprintf(stderr, "%s: offset 0x%08x\n", __FUNCTION__, offset); + + switch(offset) { + case SHA_CONFIG: + return s->config; + case SHA_RESET: + return 0; + case SHA_MEMORY_START: + return s->memory_start; + case SHA_MEMORY_MODE: + return s->memory_mode; + case SHA_INSIZE: + return s->insize; + /* Hash result ouput */ + case 0x20 ... 0x34: + //fprintf(stderr, "Hash out %08x\n", *(uint32_t *)&s->hashout[offset - 0x20]); + if(!s->hash_computed) { + // lazy compute the final hash by inspecting the last eight bytes of the buffer, which contains the length of the input data. + uint64_t data_length = swapLong(((uint64_t *)s->buffer)[s->buffer_ind / 8 - 1]) / 8; + + SHA_CTX ctx; + SHA1_Init(&ctx); + SHA1_Update(&ctx, s->buffer, data_length); + SHA1_Final(s->hashout, &ctx); + s->hash_computed = true; + } + + return *(uint32_t *)&s->hashout[offset - 0x20]; + } + + return 0; +} + +static void ipod_touch_sha1_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) +{ + IPodTouchSHA1State *s = (IPodTouchSHA1State *)opaque; + + //fprintf(stderr, "%s: offset 0x%08x value 0x%08x\n", __FUNCTION__, offset, value); + + switch(offset) { + case SHA_CONFIG: + if(value == 0x2 || value == 0xa) + { + if(s->hw_buffer_dirty) { + flush_hw_buffer(s); + } + + if(s->memory_mode) + { + // we are in memory mode - gradually add the memory to the buffer + for(int i = 0; i < s->insize / 0x40; i++) { + cpu_physical_memory_read(s->memory_start + i * 0x40, s->buffer + s->buffer_ind, 0x40); + s->buffer_ind += 0x40; + } + } + } else { + s->config = value; + } + break; + case SHA_RESET: + sha1_reset(s); + break; + case SHA_MEMORY_START: + s->memory_start = value; + break; + case SHA_MEMORY_MODE: + s->memory_mode = value; + break; + case SHA_INSIZE: + assert(value <= SHA1_BUFFER_SIZE); + s->insize = value; + break; + case 0x40 ... 0x7c: + // write to the hardware buffer + s->hw_buffer[(offset - 0x40) / 4] |= value; + s->hw_buffer_dirty = true; + break; + } +} + +static const MemoryRegionOps sha1_ops = { + .read = ipod_touch_sha1_read, + .write = ipod_touch_sha1_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void ipod_touch_sha1_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(sbd); + IPodTouchSHA1State *s = IPOD_TOUCH_SHA1(dev); + + memory_region_init_io(&s->iomem, obj, &sha1_ops, s, "sha1", 0x100); + sysbus_init_mmio(sbd, &s->iomem); + + sha1_reset(s); +} + +static void ipod_touch_sha1_class_init(ObjectClass *klass, void *data) +{ + +} + +static const TypeInfo ipod_touch_sha1_info = { + .name = TYPE_IPOD_TOUCH_SHA1, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IPodTouchSHA1State), + .instance_init = ipod_touch_sha1_init, + .class_init = ipod_touch_sha1_class_init, +}; + +static void ipod_touch_machine_types(void) +{ + type_register_static(&ipod_touch_sha1_info); +} + +type_init(ipod_touch_machine_types) \ No newline at end of file diff --git a/hw/arm/ipod_touch_spi.c b/hw/arm/ipod_touch_spi.c index 93fb992c2307..2a29498038c8 100644 --- a/hw/arm/ipod_touch_spi.c +++ b/hw/arm/ipod_touch_spi.c @@ -268,6 +268,8 @@ static void ipod_touch_spi_realize(DeviceState *dev, struct Error **errp) switch(s->base) { case 0: ssi_create_peripheral(s->spi, TYPE_IPOD_TOUCH_NOR_SPI); + IPodTouchNORSPIState *nor = IPOD_TOUCH_NOR_SPI(dev); + s->nor = nor; break; case 1: //ssi_create_peripheral(s->spi, TYPE_IPOD_TOUCH_LCD_PANEL); diff --git a/hw/arm/meson.build b/hw/arm/meson.build index 61d95cfbf1e4..4c1039183668 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -62,6 +62,6 @@ arm_ss.add(when: 'CONFIG_FSL_IMX7', if_true: files('fsl-imx7.c', 'mcimx7d-sabre. arm_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c', 'smmuv3.c')) arm_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c')) arm_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c')) -arm_ss.add(when: 'CONFIG_IPOD_TOUCH_2G', if_true: files('ipod_touch_2g.c', 'ipod_touch_clock.c', 'ipod_touch_chipid.c', 'ipod_touch_gpio.c', 'ipod_touch_sysic.c', 'ipod_touch_timer.c', 'ipod_touch_usb_otg.c', 'ipod_touch_usb_phys.c', 'ipod_touch_spi.c', 'ipod_touch_nor_spi.c')) +arm_ss.add(when: 'CONFIG_IPOD_TOUCH_2G', if_true: files('ipod_touch_2g.c', 'ipod_touch_clock.c', 'ipod_touch_chipid.c', 'ipod_touch_gpio.c', 'ipod_touch_sysic.c', 'ipod_touch_timer.c', 'ipod_touch_usb_otg.c', 'ipod_touch_usb_phys.c', 'ipod_touch_spi.c', 'ipod_touch_nor_spi.c', 'ipod_touch_sha1.c', 'ipod_touch_aes.c')) hw_arch += {'arm': arm_ss} diff --git a/include/hw/arm/ipod_touch_2g.h b/include/hw/arm/ipod_touch_2g.h index 5c0567c4cc89..3c7c72b6f9c5 100644 --- a/include/hw/arm/ipod_touch_2g.h +++ b/include/hw/arm/ipod_touch_2g.h @@ -14,6 +14,8 @@ #include "hw/arm/ipod_touch_usb_otg.h" #include "hw/arm/ipod_touch_usb_phys.h" #include "hw/arm/ipod_touch_spi.h" +#include "hw/arm/ipod_touch_sha1.h" +#include "hw/arm/ipod_touch_aes.h" #define TYPE_IPOD_TOUCH "iPod-Touch" @@ -38,7 +40,9 @@ // memory addresses #define VROM_MEM_BASE 0x0 #define SRAM1_MEM_BASE 0x22020000 +#define SHA1_MEM_BASE 0x38000000 #define USBOTG_MEM_BASE 0x38400000 +#define AES_MEM_BASE 0x38C00000 #define VIC0_MEM_BASE 0x38E00000 #define VIC1_MEM_BASE 0x38E01000 #define SYSIC_MEM_BASE 0x39700000 @@ -72,9 +76,12 @@ typedef struct { IPodTouchSYSICState *sysic; synopsys_usb_state *usb_otg; IPodTouchUSBPhysState *usb_phys_state; + IPodTouchSHA1State *sha1_state; + IPodTouchAESState *aes_state; IT2G_CPREG_VAR_DEF(REG0); IT2G_CPREG_VAR_DEF(REG1); Clock *sysclk; + char nor_path[1024]; } IPodTouchMachineState; #endif \ No newline at end of file diff --git a/include/hw/arm/ipod_touch_aes.h b/include/hw/arm/ipod_touch_aes.h new file mode 100644 index 000000000000..8c2952d9fe97 --- /dev/null +++ b/include/hw/arm/ipod_touch_aes.h @@ -0,0 +1,69 @@ +#ifndef HW_ARM_IPOD_TOUCH_AES_H +#define HW_ARM_IPOD_TOUCH_AES_H + +#include "qemu/osdep.h" +#include "hw/platform-bus.h" +#include "hw/hw.h" +#include "exec/hwaddr.h" +#include "exec/memory.h" +#include + +#define TYPE_IPOD_TOUCH_AES "ipodtouch.aes" +OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchAESState, IPOD_TOUCH_AES) + +#define key_uid ((uint8_t[]){0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}) + +#define AES_128_CBC_BLOCK_SIZE 64 +#define AES_CONTROL 0x0 +#define AES_GO 0x4 +#define AES_UNKREG0 0x8 +#define AES_STATUS 0xC +#define AES_UNKREG1 0x10 +#define AES_KEYLEN 0x14 +#define AES_INSIZE 0x18 +#define AES_INADDR 0x20 +#define AES_OUTSIZE 0x24 +#define AES_OUTADDR 0x28 +#define AES_AUXSIZE 0x2C +#define AES_AUXADDR 0x30 +#define AES_SIZE3 0x34 +#define AES_KEY_REG 0x4C +#define AES_TYPE 0x6C +#define AES_IV_REG 0x74 +#define AES_KEYSIZE 0x20 +#define AES_IVSIZE 0x10 + +typedef enum AESKeyType { + AESCustom = 0, + AESGID = 1, + AESUID = 2 +} AESKeyType; + +typedef enum AESKeyLen { + AES128 = 0, + AES192 = 1, + AES256 = 2 +} AESKeyLen; + +typedef struct IPodTouchAESState +{ + SysBusDevice busdev; + MemoryRegion iomem; + AES_KEY decryptKey; + uint32_t ivec[4]; + uint32_t insize; + uint32_t inaddr; + uint32_t outsize; + uint32_t outaddr; + uint32_t auxaddr; + uint32_t keytype; + uint32_t status; + uint32_t ctrl; + uint32_t unkreg0; + uint32_t unkreg1; + uint32_t operation; + uint32_t keylen; + uint32_t custkey[8]; +} IPodTouchAESState; + +#endif diff --git a/include/hw/arm/ipod_touch_nor_spi.h b/include/hw/arm/ipod_touch_nor_spi.h index ebbd33ba6db5..ccff9083d88b 100644 --- a/include/hw/arm/ipod_touch_nor_spi.h +++ b/include/hw/arm/ipod_touch_nor_spi.h @@ -5,13 +5,27 @@ #include "qemu/module.h" #include "qemu/timer.h" #include "hw/ssi/ssi.h" +#include "hw/hw.h" #define TYPE_IPOD_TOUCH_NOR_SPI "ipodtouch.norspi" OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchNORSPIState, IPOD_TOUCH_NOR_SPI) +#define NOR_READ_DATA_CMD 0x3 +#define NOR_GET_STATUS_CMD 0x5 + typedef struct IPodTouchNORSPIState { SSIPeripheral ssidev; uint32_t cur_cmd; + uint8_t *in_buf; + uint8_t *out_buf; + uint32_t in_buf_size; + uint32_t out_buf_size; + uint32_t in_buf_cur_ind; + uint32_t out_buf_cur_ind; + uint8_t *nor_data; + uint32_t nor_read_ind; + char nor_path[1024]; + bool nor_initialized; } IPodTouchNORSPIState; #endif \ No newline at end of file diff --git a/include/hw/arm/ipod_touch_sha1.h b/include/hw/arm/ipod_touch_sha1.h new file mode 100644 index 000000000000..1721e6beb3a8 --- /dev/null +++ b/include/hw/arm/ipod_touch_sha1.h @@ -0,0 +1,38 @@ +#ifndef HW_ARM_IPOD_TOUCH_SHA1_H +#define HW_ARM_IPOD_TOUCH_SHA1_H + +#include "qemu/osdep.h" +#include "hw/platform-bus.h" +#include "hw/hw.h" +#include "exec/hwaddr.h" +#include "exec/memory.h" +#include + +#define TYPE_IPOD_TOUCH_SHA1 "ipodtouch.sha1" +OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchSHA1State, IPOD_TOUCH_SHA1) + +#define SHA1_BUFFER_SIZE 1024 * 1024 + +#define SHA_CONFIG 0x0 +#define SHA_RESET 0x4 +#define SHA_MEMORY_MODE 0x80 // whether we read from the memory +#define SHA_MEMORY_START 0x84 +#define SHA_INSIZE 0x8c + +typedef struct IPodTouchSHA1State { + SysBusDevice busdev; + MemoryRegion iomem; + uint32_t config; + uint32_t memory_start; + uint32_t memory_mode; + uint32_t insize; + uint8_t buffer[SHA1_BUFFER_SIZE]; + uint32_t hw_buffer[0x10]; // hardware buffer + uint32_t buffer_ind; + uint8_t hashout[0x14]; + bool hw_buffer_dirty; + bool hash_computed; + SHA_CTX ctx; +} IPodTouchSHA1State; + +#endif \ No newline at end of file diff --git a/include/hw/arm/ipod_touch_spi.h b/include/hw/arm/ipod_touch_spi.h index c635f8cf6c18..688f81262700 100644 --- a/include/hw/arm/ipod_touch_spi.h +++ b/include/hw/arm/ipod_touch_spi.h @@ -69,6 +69,7 @@ typedef struct IPodTouchSPIState { Fifo8 tx_fifo; uint32_t regs[MMIO_SIZE >> 2]; uint8_t base; + IPodTouchNORSPIState *nor; } IPodTouchSPIState; void set_spi_base(uint32_t base); From 7016eae2e67a93aeaa7bfafbabaa187d62d62519 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Tue, 27 Dec 2022 22:18:59 +0100 Subject: [PATCH 06/58] Implemented a first version of the PKE engine --- hw/arm/ipod_touch_2g.c | 6 +++ hw/arm/ipod_touch_pke.c | 83 +++++++++++++++++++++++++++++++++ hw/arm/meson.build | 2 +- include/hw/arm/ipod_touch_2g.h | 9 +++- include/hw/arm/ipod_touch_pke.h | 19 ++++++++ 5 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 hw/arm/ipod_touch_pke.c create mode 100644 include/hw/arm/ipod_touch_pke.h diff --git a/hw/arm/ipod_touch_2g.c b/hw/arm/ipod_touch_2g.c index e2dfd4ad4111..2aac28cd0020 100644 --- a/hw/arm/ipod_touch_2g.c +++ b/hw/arm/ipod_touch_2g.c @@ -243,6 +243,12 @@ static void ipod_touch_machine_init(MachineState *machine) nms->aes_state = aes_state; memory_region_add_subregion(sysmem, AES_MEM_BASE, &aes_state->iomem); + // init PKE engine + dev = qdev_new("ipodtouch.pke"); + IPodTouchPKEState *pke_state = IPOD_TOUCH_PKE(dev); + nms->pke_state = pke_state; + memory_region_add_subregion(sysmem, PKE_MEM_BASE, &pke_state->iomem); + qemu_register_reset(ipod_touch_cpu_reset, nms); } diff --git a/hw/arm/ipod_touch_pke.c b/hw/arm/ipod_touch_pke.c new file mode 100644 index 000000000000..d3477839c0c7 --- /dev/null +++ b/hw/arm/ipod_touch_pke.c @@ -0,0 +1,83 @@ +#include "hw/arm/ipod_touch_pke.h" + +uint8_t LLB_IMG3_HASH[34] = { 0x30, 0x21, 0x30, 0x09, + 0x06, 0x05, 0x2b, 0x0e, + 0x03, 0x02, 0x1a, 0x05, + 0x00, 0x04, 0x14, 0xc0, + 0x67, 0x68, 0x03, 0xe2, + 0x53, 0xd0, 0xf2, 0x8f, + 0x35, 0xba, 0xde, 0x08, + 0xea, 0xdc, 0x3a, 0xb3, + 0xd3, 0x49 }; + +uint8_t LLB_IMG3_HASH_ALGO_ID = 0xCD; + +static uint64_t ipod_touch_pke_read(void *opaque, hwaddr offset, unsigned size) +{ + IPodTouchPKEState *s = (IPodTouchPKEState *)opaque; + + printf("%s: offset 0x%08x\n", __FUNCTION__, offset); + + switch(offset) { + case 0x900 ... 0x9FC: + { + uint32_t *res = (uint32_t *)s->pmod_result; + return res[(offset - 0x900) / 4]; + } + default: + break; + } + + return 0; +} + +static void ipod_touch_pke_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) +{ + IPodTouchPKEState *s = (IPodTouchPKEState *)opaque; + + printf("%s: offset 0x%08x value 0x%08x\n", __FUNCTION__, offset, value); +} + +static const MemoryRegionOps pke_ops = { + .read = ipod_touch_pke_read, + .write = ipod_touch_pke_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void ipod_touch_pke_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(sbd); + IPodTouchPKEState *s = IPOD_TOUCH_PKE(dev); + + memory_region_init_io(&s->iomem, obj, &pke_ops, s, "pke", 0x1000); + sysbus_init_mmio(sbd, &s->iomem); + + // TODO prepare the hard-coded pmod result + for(int i = 0; i < 254; i++) { s->pmod_result[i] = 0xFF; } + s->pmod_result[254] = 0x1; + s->pmod_result[255] = 0x0; + s->pmod_result[35] = 0x0; + for(int i = 0; i < 34; i++) { s->pmod_result[34 - i] = LLB_IMG3_HASH[i]; } + s->pmod_result[0] = LLB_IMG3_HASH_ALGO_ID; +} + +static void ipod_touch_pke_class_init(ObjectClass *klass, void *data) +{ + +} + +static const TypeInfo ipod_touch_pke_info = { + .name = TYPE_IPOD_TOUCH_PKE, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IPodTouchPKEState), + .instance_init = ipod_touch_pke_init, + .class_init = ipod_touch_pke_class_init, +}; + +static void ipod_touch_machine_types(void) +{ + type_register_static(&ipod_touch_pke_info); +} + +type_init(ipod_touch_machine_types) \ No newline at end of file diff --git a/hw/arm/meson.build b/hw/arm/meson.build index 4c1039183668..4e938afecc1a 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -62,6 +62,6 @@ arm_ss.add(when: 'CONFIG_FSL_IMX7', if_true: files('fsl-imx7.c', 'mcimx7d-sabre. arm_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c', 'smmuv3.c')) arm_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c')) arm_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c')) -arm_ss.add(when: 'CONFIG_IPOD_TOUCH_2G', if_true: files('ipod_touch_2g.c', 'ipod_touch_clock.c', 'ipod_touch_chipid.c', 'ipod_touch_gpio.c', 'ipod_touch_sysic.c', 'ipod_touch_timer.c', 'ipod_touch_usb_otg.c', 'ipod_touch_usb_phys.c', 'ipod_touch_spi.c', 'ipod_touch_nor_spi.c', 'ipod_touch_sha1.c', 'ipod_touch_aes.c')) +arm_ss.add(when: 'CONFIG_IPOD_TOUCH_2G', if_true: files('ipod_touch_2g.c', 'ipod_touch_clock.c', 'ipod_touch_chipid.c', 'ipod_touch_gpio.c', 'ipod_touch_sysic.c', 'ipod_touch_timer.c', 'ipod_touch_usb_otg.c', 'ipod_touch_usb_phys.c', 'ipod_touch_spi.c', 'ipod_touch_nor_spi.c', 'ipod_touch_sha1.c', 'ipod_touch_aes.c', 'ipod_touch_pke.c')) hw_arch += {'arm': arm_ss} diff --git a/include/hw/arm/ipod_touch_2g.h b/include/hw/arm/ipod_touch_2g.h index 3c7c72b6f9c5..b137296f4b38 100644 --- a/include/hw/arm/ipod_touch_2g.h +++ b/include/hw/arm/ipod_touch_2g.h @@ -16,6 +16,7 @@ #include "hw/arm/ipod_touch_spi.h" #include "hw/arm/ipod_touch_sha1.h" #include "hw/arm/ipod_touch_aes.h" +#include "hw/arm/ipod_touch_pke.h" #define TYPE_IPOD_TOUCH "iPod-Touch" @@ -52,6 +53,7 @@ #define TIMER1_MEM_BASE 0x3C700000 #define SPI1_MEM_BASE 0x3CE00000 #define GPIO_MEM_BASE 0x3CF00000 +#define PKE_MEM_BASE 0x3D000000 #define CHIPID_MEM_BASE 0x3D100000 #define SPI2_MEM_BASE 0x3D200000 #define SPI3_MEM_BASE 0x3DA00000 @@ -78,10 +80,13 @@ typedef struct { IPodTouchUSBPhysState *usb_phys_state; IPodTouchSHA1State *sha1_state; IPodTouchAESState *aes_state; - IT2G_CPREG_VAR_DEF(REG0); - IT2G_CPREG_VAR_DEF(REG1); + IPodTouchPKEState *pke_state; Clock *sysclk; char nor_path[1024]; + IT2G_CPREG_VAR_DEF(REG0); + IT2G_CPREG_VAR_DEF(REG1); + + } IPodTouchMachineState; #endif \ No newline at end of file diff --git a/include/hw/arm/ipod_touch_pke.h b/include/hw/arm/ipod_touch_pke.h new file mode 100644 index 000000000000..318483c7e8b1 --- /dev/null +++ b/include/hw/arm/ipod_touch_pke.h @@ -0,0 +1,19 @@ +#ifndef HW_ARM_IPOD_TOUCH_PKE_H +#define HW_ARM_IPOD_TOUCH_PKE_H + +#include "qemu/osdep.h" +#include "hw/platform-bus.h" +#include "hw/hw.h" +#include "exec/hwaddr.h" +#include "exec/memory.h" + +#define TYPE_IPOD_TOUCH_PKE "ipodtouch.pke" +OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchPKEState, IPOD_TOUCH_PKE) + +typedef struct IPodTouchPKEState { + SysBusDevice busdev; + MemoryRegion iomem; + uint8_t pmod_result[256]; +} IPodTouchPKEState; + +#endif \ No newline at end of file From d368c006703066de3f527a4110ab83bfae26eb00 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Wed, 28 Dec 2022 13:17:12 +0100 Subject: [PATCH 07/58] PKE engine seems to be operational --- hw/arm/ipod_touch_pke.c | 128 ++++++++++++++++++++++++++------ include/hw/arm/ipod_touch_pke.h | 10 ++- 2 files changed, 114 insertions(+), 24 deletions(-) diff --git a/hw/arm/ipod_touch_pke.c b/hw/arm/ipod_touch_pke.c index d3477839c0c7..b8286b739006 100644 --- a/hw/arm/ipod_touch_pke.c +++ b/hw/arm/ipod_touch_pke.c @@ -1,28 +1,57 @@ #include "hw/arm/ipod_touch_pke.h" +#include +#include + +static uint8_t *datahex(char* string) { + + if(string == NULL) + return NULL; + + size_t slength = strlen(string); + if((slength % 2) != 0) // must be even + return NULL; + + size_t dlength = slength / 2; + + uint8_t* data = malloc(dlength); + memset(data, 0, dlength); + + size_t index = 0; + while (index < slength) { + char c = string[index]; + int value = 0; + if(c >= '0' && c <= '9') + value = (c - '0'); + else if (c >= 'A' && c <= 'F') + value = (10 + (c - 'A')); + else if (c >= 'a' && c <= 'f') + value = (10 + (c - 'a')); + else { + free(data); + return NULL; + } -uint8_t LLB_IMG3_HASH[34] = { 0x30, 0x21, 0x30, 0x09, - 0x06, 0x05, 0x2b, 0x0e, - 0x03, 0x02, 0x1a, 0x05, - 0x00, 0x04, 0x14, 0xc0, - 0x67, 0x68, 0x03, 0xe2, - 0x53, 0xd0, 0xf2, 0x8f, - 0x35, 0xba, 0xde, 0x08, - 0xea, 0xdc, 0x3a, 0xb3, - 0xd3, 0x49 }; + data[(index/2)] += value << (((index + 1) % 2) * 4); -uint8_t LLB_IMG3_HASH_ALGO_ID = 0xCD; + index++; + } + + return data; +} static uint64_t ipod_touch_pke_read(void *opaque, hwaddr offset, unsigned size) { IPodTouchPKEState *s = (IPodTouchPKEState *)opaque; - printf("%s: offset 0x%08x\n", __FUNCTION__, offset); + //printf("%s: offset 0x%08x\n", __FUNCTION__, offset); switch(offset) { - case 0x900 ... 0x9FC: + case REG_PKE_SEG_SIZE: + return s->seg_size_reg; + case REG_PKE_SEG_START ... (REG_PKE_SEG_START + 1024): { - uint32_t *res = (uint32_t *)s->pmod_result; - return res[(offset - 0x900) / 4]; + uint32_t *res = (uint32_t *)s->segments; + return res[(offset - REG_PKE_SEG_START) / 4]; } default: break; @@ -35,7 +64,68 @@ static void ipod_touch_pke_write(void *opaque, hwaddr offset, uint64_t value, un { IPodTouchPKEState *s = (IPodTouchPKEState *)opaque; - printf("%s: offset 0x%08x value 0x%08x\n", __FUNCTION__, offset, value); + //printf("%s: offset 0x%08x value 0x%08x\n", __FUNCTION__, offset, value); + + switch(offset) { + case REG_PKE_SEG_START ... (REG_PKE_SEG_START + 1024): + { + uint32_t *segments_cast = (uint32_t *)s->segments; + segments_cast[(offset - REG_PKE_SEG_START) / 4] = value; + break; + } + case REG_PKE_START: + { + s->num_started++; + + if(s->num_started == 5) { // TODO this is arbitrary! + // printf("Base: 0x"); + // uint32_t *cast = (uint32_t *)(&s->segments[s->segment_size]); // segment 1 + // for(int i = (s->segment_size / 4 - 1); i >= 0; i--) { + // printf("%08x", cast[i]); + // } + // printf("\n"); + + // printf("Mod: 0x"); + // cast = (uint32_t *)s->segments; // segment 0 + // for(int i = (s->segment_size / 4 - 1); i >= 0; i--) { + // printf("%08x", cast[i]); + // } + // printf("\n\n"); + + BIGNUM *mod_bn = BN_lebin2bn(s->segments, s->segment_size, NULL); + BIGNUM *base_bn = BN_lebin2bn(s->segments + s->segment_size, s->segment_size, NULL); + BIGNUM *exp_bn = BN_new(); + BN_dec2bn(&exp_bn,"65537"); + // BN_print(BIO_new_fp(stdout, BIO_NOCLOSE), exp_bn); + // printf("\n\n"); + + BIGNUM *res = BN_new(); + BN_CTX *ctx = BN_CTX_new(); + BN_mod_exp(res, base_bn, exp_bn, mod_bn, ctx); + // BN_print(BIO_new_fp(stdout, BIO_NOCLOSE), res); + // printf("\n\n"); + + char *res_hex = datahex(BN_bn2hex(res)); + + // copy this into SEG1 - note that the hex conversion removes the first 0x00 bytes so we add it back and shift everything to the right one place. + for(int i = 0; i < (s->segment_size - 1); i++) { s->segments[s->segment_size + s->segment_size - 2 - i] = res_hex[i]; } + s->segments[s->segment_size + s->segment_size - 1] = 0x0; + } + break; + } + case REG_PKE_SEG_SIZE: + s->seg_size_reg = value; + uint32_t size_bit = (s->seg_size_reg >> 6); + if(size_bit == 0) { s->segment_size = 256; } + else if(size_bit == 1) { s->segment_size = 128; } + else { hw_error("Unsupported segment size bit %d!", size_bit); } + + break; + case REG_PKE_SWRESET: + s->num_started = 0; + default: + break; + } } static const MemoryRegionOps pke_ops = { @@ -52,14 +142,6 @@ static void ipod_touch_pke_init(Object *obj) memory_region_init_io(&s->iomem, obj, &pke_ops, s, "pke", 0x1000); sysbus_init_mmio(sbd, &s->iomem); - - // TODO prepare the hard-coded pmod result - for(int i = 0; i < 254; i++) { s->pmod_result[i] = 0xFF; } - s->pmod_result[254] = 0x1; - s->pmod_result[255] = 0x0; - s->pmod_result[35] = 0x0; - for(int i = 0; i < 34; i++) { s->pmod_result[34 - i] = LLB_IMG3_HASH[i]; } - s->pmod_result[0] = LLB_IMG3_HASH_ALGO_ID; } static void ipod_touch_pke_class_init(ObjectClass *klass, void *data) diff --git a/include/hw/arm/ipod_touch_pke.h b/include/hw/arm/ipod_touch_pke.h index 318483c7e8b1..8d488150a155 100644 --- a/include/hw/arm/ipod_touch_pke.h +++ b/include/hw/arm/ipod_touch_pke.h @@ -10,10 +10,18 @@ #define TYPE_IPOD_TOUCH_PKE "ipodtouch.pke" OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchPKEState, IPOD_TOUCH_PKE) +#define REG_PKE_START 0x8 +#define REG_PKE_SEG_SIZE 0x14 +#define REG_PKE_SWRESET 0x24 +#define REG_PKE_SEG_START 0x800 + typedef struct IPodTouchPKEState { SysBusDevice busdev; MemoryRegion iomem; - uint8_t pmod_result[256]; + uint8_t segments[1024]; + uint32_t seg_size_reg; + uint32_t segment_size; + uint8_t num_started; } IPodTouchPKEState; #endif \ No newline at end of file From 91b22b8cbec73982877e15b4627f578d16bf9ba7 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Wed, 28 Dec 2022 15:46:33 +0100 Subject: [PATCH 08/58] Fixed various things --- hw/arm/ipod_touch_2g.c | 20 +++++++++++++++++++- hw/arm/ipod_touch_chipid.c | 4 ++-- hw/dma/pl080.c | 20 +++++++++++++++----- include/hw/arm/ipod_touch_2g.h | 6 ++++++ 4 files changed, 42 insertions(+), 8 deletions(-) diff --git a/hw/arm/ipod_touch_2g.c b/hw/arm/ipod_touch_2g.c index 2aac28cd0020..150eeba0a5fb 100644 --- a/hw/arm/ipod_touch_2g.c +++ b/hw/arm/ipod_touch_2g.c @@ -80,7 +80,7 @@ static void ipod_touch_memory_setup(MachineState *machine, MemoryRegion *sysmem, { IPodTouchMachineState *nms = IPOD_TOUCH_MACHINE(machine); - allocate_ram(sysmem, "unknown", 0x22000000, 0x100000); + allocate_ram(sysmem, "llb", 0x22000000, 0x100000); allocate_ram(sysmem, "sram1", SRAM1_MEM_BASE, 0x100000); // load the bootrom (vrom) @@ -136,6 +136,7 @@ static void ipod_touch_machine_init(MachineState *machine) clock_set_hz(nms->sysclk, 12000000ULL); nms->cpu = cpu; + nms->nsas = nsas; // setup VICs nms->irq = g_malloc0(sizeof(qemu_irq *) * 2); @@ -223,6 +224,23 @@ static void ipod_touch_machine_init(MachineState *machine) nms->usb_otg = usb_otg; memory_region_add_subregion(sysmem, USBOTG_MEM_BASE, &nms->usb_otg->iomem); + // init two pl080 DMAC0 devices + dev = qdev_new("pl080"); + PL080State *pl080_1 = PL080(dev); + object_property_set_link(OBJECT(dev), "downstream", OBJECT(sysmem), &error_fatal); + memory_region_add_subregion(sysmem, DMAC0_MEM_BASE, &pl080_1->iomem); + busdev = SYS_BUS_DEVICE(dev); + sysbus_realize(busdev, &error_fatal); + sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_DMAC0_IRQ)); + + dev = qdev_new("pl080"); + PL080State *pl080_2 = PL080(dev); + object_property_set_link(OBJECT(dev), "downstream", OBJECT(sysmem), &error_fatal); + memory_region_add_subregion(sysmem, DMAC1_MEM_BASE, &pl080_2->iomem); + busdev = SYS_BUS_DEVICE(dev); + sysbus_realize(busdev, &error_fatal); + sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_DMAC0_IRQ)); + // init the chip ID module dev = qdev_new("ipodtouch.usbphys"); IPodTouchUSBPhysState *usb_phys_state = IPOD_TOUCH_USB_PHYS(dev); diff --git a/hw/arm/ipod_touch_chipid.c b/hw/arm/ipod_touch_chipid.c index eed1a52ea7a5..39968f9cb9f9 100644 --- a/hw/arm/ipod_touch_chipid.c +++ b/hw/arm/ipod_touch_chipid.c @@ -6,9 +6,9 @@ static uint64_t ipod_touch_chipid_read(void *opaque, hwaddr addr, unsigned size) switch (addr) { case CHIPID_UNKNOWN1: - return 0; + return (1 << 5); // ind5 = production mode case CHIPID_INFO: - return (0x8720 << 16) | 0x1; + return (0x8720 << 16) | (1 << 2); // ind16 = chipid, ind2 = security domain, case CHIPID_UNKNOWN2: return 0; case CHIPID_UNKNOWN3: diff --git a/hw/dma/pl080.c b/hw/dma/pl080.c index 2627307cc85a..e9cb8140c76d 100644 --- a/hw/dma/pl080.c +++ b/hw/dma/pl080.c @@ -142,12 +142,12 @@ static void pl080_run(PL080State *s) case 0: break; case 1: - if ((req & (1u << dest_id)) == 0) - size = 0; + // if ((req & (1u << dest_id)) == 0) + // size = 0; break; case 2: - if ((req & (1u << src_id)) == 0) - size = 0; + // if ((req & (1u << src_id)) == 0) + // size = 0; break; case 3: if ((req & (1u << src_id)) == 0 @@ -155,8 +155,9 @@ static void pl080_run(PL080State *s) size = 0; break; } - if (!size) + if (!size) { continue; + } /* Transfer one element. */ /* ??? Should transfer multiple elements for a burst request. */ @@ -179,6 +180,7 @@ static void pl080_run(PL080State *s) ch->dest += swidth; } + //printf("Transfer size: %d, destination: 0x%08x\n", size, ch->dest); size--; ch->ctrl = (ch->ctrl & 0xfffff000) | size; if (size == 0) { @@ -204,6 +206,7 @@ static void pl080_run(PL080State *s) ch->conf &= ~PL080_CCONF_E; } if (ch->ctrl & PL080_CCTRL_I) { + //printf("Setting interrupt status of channel %d\n", c); s->tc_int |= 1 << c; } } @@ -212,6 +215,7 @@ static void pl080_run(PL080State *s) if (--s->running) s->running = 1; } + pl080_update(s); } static uint64_t pl080_read(void *opaque, hwaddr offset, @@ -289,24 +293,30 @@ static void pl080_write(void *opaque, hwaddr offset, PL080State *s = (PL080State *)opaque; int i; + //fprintf(stderr, "%s: writing 0x%08x to 0x%08x\n", __func__, value, offset); + if (offset >= 0x100 && offset < 0x200) { i = (offset & 0xe0) >> 5; if (i >= s->nchannels) goto bad_offset; switch ((offset >> 2) & 7) { case 0: /* SrcAddr */ + //printf("%s: setting source address of channel %d to 0x%08x\n", __func__, i, value); s->chan[i].src = value; break; case 1: /* DestAddr */ + //printf("%s: setting destination address of channel %d to 0x%08x\n", __func__, i, value); s->chan[i].dest = value; break; case 2: /* LLI */ s->chan[i].lli = value; break; case 3: /* Control */ + //printf("%s: setting control of channel %d to 0x%08x (transfer size: %d)\n", __func__, i, value, value & 0xfff); s->chan[i].ctrl = value; break; case 4: /* Configuration */ + //printf("%s: setting configuration of channel %d to 0x%08x\n", __func__, i, value); s->chan[i].conf = value; pl080_run(s); break; diff --git a/include/hw/arm/ipod_touch_2g.h b/include/hw/arm/ipod_touch_2g.h index b137296f4b38..8c90c21227d8 100644 --- a/include/hw/arm/ipod_touch_2g.h +++ b/include/hw/arm/ipod_touch_2g.h @@ -6,6 +6,7 @@ #include "hw/intc/pl192.h" #include "hw/arm/boot.h" #include "cpu.h" +#include "hw/dma/pl080.h" #include "hw/arm/ipod_touch_timer.h" #include "hw/arm/ipod_touch_clock.h" #include "hw/arm/ipod_touch_chipid.h" @@ -28,6 +29,8 @@ #define S5L8720_SPI0_IRQ 0x9 #define S5L8720_SPI1_IRQ 0xA #define S5L8720_SPI2_IRQ 0xB +#define S5L8720_DMAC0_IRQ 0x10 +#define S5L8720_DMAC1_IRQ 0x11 #define S5L8720_SPI3_IRQ 0x1C #define S5L8720_SPI4_IRQ 0x37 @@ -42,11 +45,13 @@ #define VROM_MEM_BASE 0x0 #define SRAM1_MEM_BASE 0x22020000 #define SHA1_MEM_BASE 0x38000000 +#define DMAC0_MEM_BASE 0x38200000 #define USBOTG_MEM_BASE 0x38400000 #define AES_MEM_BASE 0x38C00000 #define VIC0_MEM_BASE 0x38E00000 #define VIC1_MEM_BASE 0x38E01000 #define SYSIC_MEM_BASE 0x39700000 +#define DMAC1_MEM_BASE 0x39900000 #define SPI0_MEM_BASE 0x3C300000 #define USBPHYS_MEM_BASE 0x3C400000 #define CLOCK0_MEM_BASE 0x3C500000 @@ -66,6 +71,7 @@ typedef struct { typedef struct { MachineState parent; + AddressSpace *nsas; qemu_irq **irq; ARMCPU *cpu; PL192State *vic0; From 07725f5d22bcc1304aa380b426ba4bb824ab87d3 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Sat, 7 Jan 2023 16:31:41 +0100 Subject: [PATCH 09/58] AES engine is correctly decrypting LLB payload --- hw/arm/ipod_touch_aes.c | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/hw/arm/ipod_touch_aes.c b/hw/arm/ipod_touch_aes.c index 0076a571d6d0..1781dd16cf23 100644 --- a/hw/arm/ipod_touch_aes.c +++ b/hw/arm/ipod_touch_aes.c @@ -18,7 +18,6 @@ static uint64_t ipod_touch_aes_read(void *opaque, hwaddr offset, unsigned size) static void ipod_touch_aes_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { struct IPodTouchAESState *aesop = (struct IPodTouchAESState *)opaque; - static uint8_t keylenop = 0; uint8_t *inbuf; uint8_t *buf; @@ -28,38 +27,52 @@ static void ipod_touch_aes_write(void *opaque, hwaddr offset, uint64_t value, un switch(offset) { case AES_GO: inbuf = (uint8_t *)malloc(aesop->insize); - cpu_physical_memory_read((aesop->inaddr - 0x80000000), inbuf, aesop->insize); + cpu_physical_memory_read((aesop->inaddr), inbuf, aesop->insize); switch(aesop->keytype) { - case AESGID: - fprintf(stderr, "%s: No support for GID key\n", __func__); - return; + case AESGID: + break; case AESUID: AES_set_decrypt_key(key_uid, sizeof(key_uid) * 8, &aesop->decryptKey); break; case AESCustom: - AES_set_decrypt_key((uint8_t *)aesop->custkey, 0x20 * 8, &aesop->decryptKey); + AES_set_decrypt_key((uint8_t *)(&aesop->custkey[4]), 0x10 * 8, &aesop->decryptKey); break; } buf = (uint8_t *) malloc(aesop->insize); + //printf("In size: %d, out size: %d, in addr: 0x%08x, in buf: 0x%08x, out addr: 0x%08x\n", aesop->insize, aesop->outsize, aesop->inaddr, ((uint32_t *)inbuf)[0], aesop->outaddr); + + if(aesop->keytype == AESGID) { + // Unfortunately, we don't have access to the GID key. + // However, we know that when the AES engine is invoked with the GID key type, it's for the decryption of the IMG file. + // Instead, we provide an hard-coded key as result and copy it to the output buffer. + // source: https://www.theiphonewiki.com/wiki/Sugar_Bowl_5F138_(iPod2,1) (LLB) + char key[] = { + 0xce, 0x97, 0xa7, 0xc8, 0x2e, 0xf8, 0x64, 0x67, 0x5e, 0xd3, 0x68, 0x05, 0x97, 0xec, 0x2a, 0xef, // IV + 0x27, 0x73, 0x2a, 0x6b, 0xbf, 0xb1, 0x4a, 0x07, 0x25, 0x0a, 0x2e, 0x46, 0x82, 0xbf, 0x3c, 0xba, // key + }; + for(int i = 0; i < aesop->insize; i++) { + buf[i] = key[i]; + } + } + else { + AES_cbc_encrypt(inbuf, buf, aesop->insize, &aesop->decryptKey, (uint8_t *)aesop->ivec, AES_DECRYPT); + } - AES_cbc_encrypt(inbuf, buf, aesop->insize, &aesop->decryptKey, (uint8_t *)aesop->ivec, aesop->operation); - - cpu_physical_memory_write((aesop->outaddr - 0x80000000), buf, aesop->insize); + if(aesop->outaddr != 0x220100ac) { // TODO very ugly hack - for the RSA key decryption, it seems that doing nothing results in the correct decryption key?? + cpu_physical_memory_write((aesop->outaddr), buf, aesop->insize); + } + memset(aesop->custkey, 0, 0x20); memset(aesop->ivec, 0, 0x10); free(inbuf); free(buf); - keylenop = 0; aesop->outsize = aesop->insize; aesop->status = 0xf; break; case AES_KEYLEN: - if(keylenop == 1) { - aesop->operation = value; - } - keylenop++; + aesop->operation = value; aesop->keylen = value; break; case AES_INADDR: From c386a81c40302837c0a3af17ddf2d6182629b6bc Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Sun, 8 Jan 2023 17:20:43 +0100 Subject: [PATCH 10/58] Worked on LLB --- hw/arm/ipod_touch_2g.c | 55 ++++++ hw/arm/ipod_touch_clock.c | 7 + hw/arm/ipod_touch_nor_spi.c | 11 +- hw/arm/ipod_touch_pcf50633_pmu.c | 104 ++++++++++ hw/arm/ipod_touch_spi.c | 2 +- hw/arm/ipod_touch_unknown1.c | 56 ++++++ hw/arm/meson.build | 2 +- hw/i2c/ipod_touch_i2c.c | 237 +++++++++++++++++++++++ hw/i2c/meson.build | 1 + include/hw/arm/ipod_touch_2g.h | 16 +- include/hw/arm/ipod_touch_nor_spi.h | 1 + include/hw/arm/ipod_touch_pcf50633_pmu.h | 32 +++ include/hw/arm/ipod_touch_unknown1.h | 16 ++ include/hw/i2c/ipod_touch_i2c.h | 64 ++++++ 14 files changed, 598 insertions(+), 6 deletions(-) create mode 100644 hw/arm/ipod_touch_pcf50633_pmu.c create mode 100644 hw/arm/ipod_touch_unknown1.c create mode 100644 hw/i2c/ipod_touch_i2c.c create mode 100644 include/hw/arm/ipod_touch_pcf50633_pmu.h create mode 100644 include/hw/arm/ipod_touch_unknown1.h create mode 100644 include/hw/i2c/ipod_touch_i2c.h diff --git a/hw/arm/ipod_touch_2g.c b/hw/arm/ipod_touch_2g.c index 150eeba0a5fb..aeb058f46cda 100644 --- a/hw/arm/ipod_touch_2g.c +++ b/hw/arm/ipod_touch_2g.c @@ -9,6 +9,7 @@ #include "hw/platform-bus.h" #include "hw/block/flash.h" #include "hw/qdev-clock.h" +#include "hw/arm/exynos4210.h" #include "hw/arm/ipod_touch_2g.h" #include "target/arm/cpregs.h" @@ -82,6 +83,7 @@ static void ipod_touch_memory_setup(MachineState *machine, MemoryRegion *sysmem, allocate_ram(sysmem, "llb", 0x22000000, 0x100000); allocate_ram(sysmem, "sram1", SRAM1_MEM_BASE, 0x100000); + allocate_ram(sysmem, "tvout", TVOUT_MEM_BASE, 0x1000); // load the bootrom (vrom) uint8_t *file_data = NULL; @@ -194,6 +196,36 @@ static void ipod_touch_machine_init(MachineState *machine) nms->gpio_state = gpio_state; memory_region_add_subregion(sysmem, GPIO_MEM_BASE, &gpio_state->iomem); + dev = exynos4210_uart_create(UART0_MEM_BASE, 256, 0, serial_hd(0), nms->irq[0][24]); + if (!dev) { + printf("Failed to create uart0 device!\n"); + abort(); + } + + dev = exynos4210_uart_create(UART1_MEM_BASE, 256, 1, serial_hd(1), nms->irq[0][25]); + if (!dev) { + printf("Failed to create uart1 device!\n"); + abort(); + } + + dev = exynos4210_uart_create(UART2_MEM_BASE, 256, 2, serial_hd(2), nms->irq[0][26]); + if (!dev) { + printf("Failed to create uart2 device!\n"); + abort(); + } + + dev = exynos4210_uart_create(UART3_MEM_BASE, 256, 3, serial_hd(3), nms->irq[0][27]); + if (!dev) { + printf("Failed to create uart3 device!\n"); + abort(); + } + + // dev = exynos4210_uart_create(UART4_MEM_BASE, 256, 4, serial_hd(4), nms->irq[0][28]); + // if (!dev) { + // printf("Failed to create uart4 device!\n"); + // abort(); + // } + // init spis set_spi_base(0); dev = sysbus_create_simple("ipodtouch.spi", SPI0_MEM_BASE, s5l8900_get_irq(nms, S5L8720_SPI0_IRQ)); @@ -218,6 +250,11 @@ static void ipod_touch_machine_init(MachineState *machine) nms->chipid_state = chipid_state; memory_region_add_subregion(sysmem, CHIPID_MEM_BASE, &chipid_state->iomem); + // init the unknown1 module + dev = qdev_new("ipodtouch.unknown1"); + IPodTouchUnknown1State *unknown1_state = IPOD_TOUCH_UNKNOWN1(dev); + memory_region_add_subregion(sysmem, UNKNOWN1_MEM_BASE, &unknown1_state->iomem); + // init USB OTG dev = ipod_touch_init_usb_otg(s5l8900_get_irq(nms, S5L8720_USB_OTG_IRQ), s5l8720_usb_hwcfg); synopsys_usb_state *usb_otg = S5L8900USBOTG(dev); @@ -241,6 +278,24 @@ static void ipod_touch_machine_init(MachineState *machine) sysbus_realize(busdev, &error_fatal); sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_DMAC0_IRQ)); + // Init I2C + dev = qdev_new("ipodtouch.i2c"); + IPodTouchI2CState *i2c_state = IPOD_TOUCH_I2C(dev); + nms->i2c0_state = i2c_state; + busdev = SYS_BUS_DEVICE(dev); + sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_I2C0_IRQ)); + memory_region_add_subregion(sysmem, I2C0_MEM_BASE, &i2c_state->iomem); + + // init the PMU + i2c_slave_create_simple(i2c_state->bus, "pcf50633", 0x73); + + dev = qdev_new("ipodtouch.i2c"); + i2c_state = IPOD_TOUCH_I2C(dev); + nms->i2c1_state = i2c_state; + busdev = SYS_BUS_DEVICE(dev); + sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_I2C1_IRQ)); + memory_region_add_subregion(sysmem, I2C1_MEM_BASE, &i2c_state->iomem); + // init the chip ID module dev = qdev_new("ipodtouch.usbphys"); IPodTouchUSBPhysState *usb_phys_state = IPOD_TOUCH_USB_PHYS(dev); diff --git a/hw/arm/ipod_touch_clock.c b/hw/arm/ipod_touch_clock.c index 3741af33aa53..8c1abb9a837b 100644 --- a/hw/arm/ipod_touch_clock.c +++ b/hw/arm/ipod_touch_clock.c @@ -85,6 +85,13 @@ static uint64_t s5l8900_clock_read(void *opaque, hwaddr addr, unsigned size) return s->config1; case CLOCK_CONFIG2: return s->config2; + case CLOCK_CONFIG3: + return s->config3; + case CLOCK_CONFIG4: + return s->config4; + case CLOCK_CONFIG5: + return s->config5; + case CLOCK_PLL0CON: return s->pll0con; case CLOCK_PLL1CON: diff --git a/hw/arm/ipod_touch_nor_spi.c b/hw/arm/ipod_touch_nor_spi.c index 52ff35627a38..d49ee9c1a4e1 100644 --- a/hw/arm/ipod_touch_nor_spi.c +++ b/hw/arm/ipod_touch_nor_spi.c @@ -35,9 +35,17 @@ static uint32_t ipod_touch_nor_spi_transfer(SSIPeripheral *dev, uint32_t value) s->out_buf_size = 1; } else if(value == NOR_READ_DATA_CMD) { + printf("Received read command!\n"); s->in_buf_size = 4; s->out_buf_size = 4096; } + else if(value == NOR_GET_JEDECID) { + s->in_buf_size = 1; + s->out_buf_size = 3; + s->out_buf[0] = 0x1F; // vendor: atmel, device: 0x02 -> AT25DF081A + s->out_buf[1] = 0x45; + s->out_buf[2] = 0x02; + } else { hw_error("Unknown command 0x%02x!", value); } @@ -55,9 +63,7 @@ static uint32_t ipod_touch_nor_spi_transfer(SSIPeripheral *dev, uint32_t value) else if(s->cur_cmd == NOR_READ_DATA_CMD && s->in_buf_cur_ind == s->in_buf_size) { if(!s->nor_initialized) { initialize_nor(s); } s->nor_read_ind = (s->in_buf[1] << 16) | (s->in_buf[2] << 8) | s->in_buf[3]; - printf("Read index: %d\n", s->nor_read_ind); } - return 0x0; } else { @@ -66,6 +72,7 @@ static uint32_t ipod_touch_nor_spi_transfer(SSIPeripheral *dev, uint32_t value) if(s->cur_cmd == NOR_READ_DATA_CMD) { uint8_t ret_val = s->nor_data[s->nor_read_ind]; s->nor_read_ind++; + printf("Ret\n"); return ret_val; } else { diff --git a/hw/arm/ipod_touch_pcf50633_pmu.c b/hw/arm/ipod_touch_pcf50633_pmu.c new file mode 100644 index 000000000000..cd7701a0dca7 --- /dev/null +++ b/hw/arm/ipod_touch_pcf50633_pmu.c @@ -0,0 +1,104 @@ +#include "hw/arm/ipod_touch_pcf50633_pmu.h" + +static int pcf50633_event(I2CSlave *i2c, enum i2c_event event) +{ + return 0; +} + +static int int_to_bcd(int value) { + int shift = 0; + int res = 0; + while (value > 0) { + res |= (value % 10) << (shift++ << 2); + value /= 10; + } + return res; +} + +static uint8_t pcf50633_recv(I2CSlave *i2c) +{ + Pcf50633State *s = PCF50633(i2c); + printf("Reading PMU register %d\n", s->cmd); + + time_t t = time(NULL); + struct tm tm = *localtime(&t); + + int res = 0; + + switch(s->cmd) { + case PMU_MBCS1: + res = 0; // battery power source + break; + case PMU_ADCC1: + res = 0; // battery charge voltage + break; + case PMU_RTCSC: // seconds + res = int_to_bcd(tm.tm_sec); + break; + case PMU_RTCMN: // minutes + res = int_to_bcd(tm.tm_min); + break; + case PMU_RTCHR: // hours + res = int_to_bcd(tm.tm_hour); + break; + case PMU_RTCDT: // days + res = int_to_bcd(tm.tm_mday); + break; + case PMU_RTCMT: // month + res = int_to_bcd(tm.tm_mon + 1); + break; + case PMU_RTCYR: // year + res = int_to_bcd(tm.tm_year - 100); // the year counts from 1900 + break; + case 0x67: + res = 1; // whether we should enable debug UARTS + break; + case 0x69: + res = 0; // boot count error/panic + break; + case 0x76: + res = 0; // unknown register + break; + default: + res = 0; + } + + s->cmd += 1; + return res; +} + +static int pcf50633_send(I2CSlave *i2c, uint8_t data) +{ + Pcf50633State *s = PCF50633(i2c); + s->cmd = data; + return 0; +} + +static void pcf50633_init(Object *obj) +{ + +} + +static void pcf50633_class_init(ObjectClass *klass, void *data) +{ + I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); + + k->event = pcf50633_event; + k->recv = pcf50633_recv; + k->send = pcf50633_send; +} + +static const TypeInfo pcf50633_info = { + .name = TYPE_PCF50633, + .parent = TYPE_I2C_SLAVE, + .instance_init = pcf50633_init, + .instance_size = sizeof(Pcf50633State), + .class_init = pcf50633_class_init, +}; + +static void pcf50633_register_types(void) +{ + type_register_static(&pcf50633_info); +} + +type_init(pcf50633_register_types) \ No newline at end of file diff --git a/hw/arm/ipod_touch_spi.c b/hw/arm/ipod_touch_spi.c index 2a29498038c8..8d33d5eade27 100644 --- a/hw/arm/ipod_touch_spi.c +++ b/hw/arm/ipod_touch_spi.c @@ -186,7 +186,7 @@ static void ipod_touch_spi_write(void *opaque, hwaddr addr, uint64_t data, unsig break; case R_STATUS: fifo8_reset(&s->tx_fifo); - fifo8_reset(&s->rx_fifo); + //fifo8_reset(&s->rx_fifo); r = old & (~r); run = true; break; diff --git a/hw/arm/ipod_touch_unknown1.c b/hw/arm/ipod_touch_unknown1.c new file mode 100644 index 000000000000..d3ccf354db3d --- /dev/null +++ b/hw/arm/ipod_touch_unknown1.c @@ -0,0 +1,56 @@ +#include "hw/arm/ipod_touch_unknown1.h" + +static uint64_t ipod_touch_unknown1_read(void *opaque, hwaddr addr, unsigned size) +{ + //fprintf(stderr, "%s: offset = 0x%08x\n", __func__, addr); + + switch (addr) { + case 0x140: + return 0x2; + case 0x144: + return 0x3; + default: + break; + } + + return 0; +} + +static void ipod_touch_unknown1_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) +{ +} + +static const MemoryRegionOps ipod_touch_unknown1_ops = { + .read = ipod_touch_unknown1_read, + .write = ipod_touch_unknown1_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void ipod_touch_unknown1_init(Object *obj) +{ + IPodTouchUnknown1State *s = IPOD_TOUCH_UNKNOWN1(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &ipod_touch_unknown1_ops, s, TYPE_IPOD_TOUCH_UNKNOWN1, 0x200); + sysbus_init_mmio(sbd, &s->iomem); +} + +static void ipod_touch_unknown1_class_init(ObjectClass *klass, void *data) +{ + +} + +static const TypeInfo ipod_touch_unknown1_type_info = { + .name = TYPE_IPOD_TOUCH_UNKNOWN1, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IPodTouchUnknown1State), + .instance_init = ipod_touch_unknown1_init, + .class_init = ipod_touch_unknown1_class_init, +}; + +static void ipod_touch_unknown1_register_types(void) +{ + type_register_static(&ipod_touch_unknown1_type_info); +} + +type_init(ipod_touch_unknown1_register_types) \ No newline at end of file diff --git a/hw/arm/meson.build b/hw/arm/meson.build index 4e938afecc1a..2fb7f6dd66b5 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -62,6 +62,6 @@ arm_ss.add(when: 'CONFIG_FSL_IMX7', if_true: files('fsl-imx7.c', 'mcimx7d-sabre. arm_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c', 'smmuv3.c')) arm_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c')) arm_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c')) -arm_ss.add(when: 'CONFIG_IPOD_TOUCH_2G', if_true: files('ipod_touch_2g.c', 'ipod_touch_clock.c', 'ipod_touch_chipid.c', 'ipod_touch_gpio.c', 'ipod_touch_sysic.c', 'ipod_touch_timer.c', 'ipod_touch_usb_otg.c', 'ipod_touch_usb_phys.c', 'ipod_touch_spi.c', 'ipod_touch_nor_spi.c', 'ipod_touch_sha1.c', 'ipod_touch_aes.c', 'ipod_touch_pke.c')) +arm_ss.add(when: 'CONFIG_IPOD_TOUCH_2G', if_true: files('ipod_touch_2g.c', 'ipod_touch_clock.c', 'ipod_touch_chipid.c', 'ipod_touch_gpio.c', 'ipod_touch_sysic.c', 'ipod_touch_timer.c', 'ipod_touch_usb_otg.c', 'ipod_touch_usb_phys.c', 'ipod_touch_spi.c', 'ipod_touch_nor_spi.c', 'ipod_touch_sha1.c', 'ipod_touch_aes.c', 'ipod_touch_pke.c', 'ipod_touch_pcf50633_pmu.c', 'ipod_touch_unknown1.c')) hw_arch += {'arm': arm_ss} diff --git a/hw/i2c/ipod_touch_i2c.c b/hw/i2c/ipod_touch_i2c.c new file mode 100644 index 000000000000..991f9e86863d --- /dev/null +++ b/hw/i2c/ipod_touch_i2c.c @@ -0,0 +1,237 @@ +/* + * IPod Touch I2C Bus Serial Interface Emulation + * + * Copyright (C) 2012 Samsung Electronics Co Ltd. + * Maksim Kozlov, + * Igor Mitsyanko, + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see . + * + */ + +#include "hw/i2c/ipod_touch_i2c.h" + +static void s5l8900_i2c_update(IPodTouchI2CState *s) +{ + uint16_t level; + level = (s->status & S5L8900_IICSTAT_START) && + (s->control & S5L8900_IICCON_IRQEN); + + if (s->control & S5L8900_IICCON_IRQPEND) + level = 0; + + qemu_irq_raise(s->irq); +} + +static int s5l8900_i2c_receive(IPodTouchI2CState *s) +{ + int r; + r = i2c_recv(s->bus); + s5l8900_i2c_update(s); + return r; +} + +static int s5l8900_i2c_send(IPodTouchI2CState *s, uint8_t data) +{ + if (!(s->status & S5L8900_IICSTAT_LASTBIT)) { + s->status |= S5L8900_IICCON_ACKEN; + s->data = data; + s->iicreg20 |= 0x100; + i2c_send(s->bus, s->data); + } + s5l8900_i2c_update(s); + return 1; +} + +/* I2C read function */ +static uint64_t ipod_touch_i2c_read(void *opaque, hwaddr offset, unsigned size) +{ + IPodTouchI2CState *s = (IPodTouchI2CState *)opaque; + + //fprintf(stderr, "s5l8900_i2c_read(): offset = 0x%08x\n", offset); + + switch (offset) { + case I2CCON: + return s->control; + case I2CSTAT: + return s->status; + case I2CADD: + return s->address; + case I2CDS: + s->iicreg20 |= 0x100; + s->data = s5l8900_i2c_receive(s); + return s->data; + case I2CLC: + return s->line_ctrl; + case IICREG20: + { + // clear the flags + uint32_t tmp_reg20 = s->iicreg20; + s->iicreg20 &= ~0x100; + s->iicreg20 &= ~0x2000; + return tmp_reg20; + } + default: + break; + //hw_error("s5l8900.i2c: bad read offset 0x" TARGET_FMT_plx "\n", offset); + //fprintf(stderr, "%s: bad read offset 0x%08x\n", __func__, offset); + } + return 0; +} + +/* I2C write function */ +static void ipod_touch_i2c_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) +{ + IPodTouchI2CState *s = (IPodTouchI2CState *)opaque; + int mode; + + //fprintf(stderr, "s5l8900_i2c_write: offset = 0x%08x, val = 0x%08x\n", offset, value); + + qemu_irq_lower(s->irq); + + switch (offset) { + case I2CCON: + if(value & ~(S5L8900_IICCON_ACKEN)) { + s->iicreg20 |= 0x100; + } + if((value & 0x10) && (s->status == 0x90)) { + s->iicreg20 |= 0x2000; + } + s->control = value & 0xff; + + qemu_irq_raise(s->irq); + break; + + case I2CSTAT: + /* We have to make sure we don't miss an end transfer */ + if((!s->active) && ((s->status >> 6) != ((value >> 6)))) { + s->status = value & 0xff; + /* If they toggle the tx bit then we have to force an end transfer before mode update */ + } else if((s->active) && ((s->status >> 6) != ((value >> 6)))) { + i2c_end_transfer(s->bus); + s->active=0; + s->status = value & 0xff; + s->status |= S5L8900_IICSTAT_TXRXEN; + break; + } + mode = (s->status >> 6) & 0x3; + if (value & S5L8900_IICSTAT_TXRXEN) { + /* IIC-bus data output enable/disable bit */ + switch(mode) { + case SR_MODE: + s->data = s5l8900_i2c_receive(s); + break; + case ST_MODE: + s->data = s5l8900_i2c_receive(s); + break; + case MR_MODE: + if (value & S5L8900_IICSTAT_START) { + /* START condition */ + s->status &= ~S5L8900_IICSTAT_LASTBIT; + + s->iicreg20 |= 0x100; + s->active = 1; + i2c_start_transfer(s->bus, s->data >> 1, 1); + } else { + i2c_end_transfer(s->bus); + s->active = 0; + s->status |= S5L8900_IICSTAT_TXRXEN; + } + break; + case MT_MODE: + if (value & S5L8900_IICSTAT_START) { + /* START condition */ + s->status &= ~S5L8900_IICSTAT_LASTBIT; + + s->iicreg20 |= 0x100; + s->active = 1; + i2c_start_transfer(s->bus, s->data >> 1, 0); + } else { + i2c_end_transfer(s->bus); + s->active = 0; + s->status |= S5L8900_IICSTAT_TXRXEN; + } + break; + default: + break; + } + } + s5l8900_i2c_update(s); + break; + + case I2CADD: + s->address = value & 0xff; + break; + + case I2CDS: + s5l8900_i2c_send(s, value & 0xff); + break; + + case I2CLC: + s->line_ctrl = value & 0xff; + break; + + case IICREG20: + //s->iicreg20 &= ~value; + break; + default: + break; + //hw_error("s5l8900.i2c: bad write offset 0x" TARGET_FMT_plx "\n", offset); + //fprintf(stderr, "%s: bad write offset 0x%08x\n", __func__, offset); + } +} + +static const MemoryRegionOps ipod_touch_i2c_ops = { + .read = ipod_touch_i2c_read, + .write = ipod_touch_i2c_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void ipod_touch_i2c_init(Object *obj) +{ + DeviceState *dev = DEVICE(obj); + IPodTouchI2CState *s = IPOD_TOUCH_I2C(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &ipod_touch_i2c_ops, s, TYPE_IPOD_TOUCH_I2C, 0x100); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); + s->bus = i2c_init_bus(dev, "i2c"); +} + +static void ipod_touch_i2c_reset(DeviceState *d) +{ + +} + +static void ipod_touch_i2c_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + dc->reset = ipod_touch_i2c_reset; +} + +static const TypeInfo ipod_touch_i2c_type_info = { + .name = TYPE_IPOD_TOUCH_I2C, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IPodTouchI2CState), + .instance_init = ipod_touch_i2c_init, + .class_init = ipod_touch_i2c_class_init, +}; + +static void ipod_touch_i2c_register_types(void) +{ + type_register_static(&ipod_touch_i2c_type_info); +} + +type_init(ipod_touch_i2c_register_types) diff --git a/hw/i2c/meson.build b/hw/i2c/meson.build index d3df273251f7..4ae1030e0560 100644 --- a/hw/i2c/meson.build +++ b/hw/i2c/meson.build @@ -16,4 +16,5 @@ i2c_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_i2c.c')) i2c_ss.add(when: 'CONFIG_PPC4XX', if_true: files('ppc4xx_i2c.c')) i2c_ss.add(when: 'CONFIG_PCA954X', if_true: files('i2c_mux_pca954x.c')) i2c_ss.add(when: 'CONFIG_PMBUS', if_true: files('pmbus_device.c')) +i2c_ss.add(when: 'CONFIG_IPOD_TOUCH_2G', if_true: files('ipod_touch_i2c.c')) softmmu_ss.add_all(when: 'CONFIG_I2C', if_true: i2c_ss) diff --git a/include/hw/arm/ipod_touch_2g.h b/include/hw/arm/ipod_touch_2g.h index 8c90c21227d8..4504b22dc531 100644 --- a/include/hw/arm/ipod_touch_2g.h +++ b/include/hw/arm/ipod_touch_2g.h @@ -7,6 +7,7 @@ #include "hw/arm/boot.h" #include "cpu.h" #include "hw/dma/pl080.h" +#include "hw/i2c/ipod_touch_i2c.h" #include "hw/arm/ipod_touch_timer.h" #include "hw/arm/ipod_touch_clock.h" #include "hw/arm/ipod_touch_chipid.h" @@ -18,6 +19,7 @@ #include "hw/arm/ipod_touch_sha1.h" #include "hw/arm/ipod_touch_aes.h" #include "hw/arm/ipod_touch_pke.h" +#include "hw/arm/ipod_touch_unknown1.h" #define TYPE_IPOD_TOUCH "iPod-Touch" @@ -31,7 +33,9 @@ #define S5L8720_SPI2_IRQ 0xB #define S5L8720_DMAC0_IRQ 0x10 #define S5L8720_DMAC1_IRQ 0x11 +#define S5L8720_I2C0_IRQ 0x15 #define S5L8720_SPI3_IRQ 0x1C +#define S5L8720_I2C1_IRQ 0x16 #define S5L8720_SPI4_IRQ 0x37 #define IT2G_CPREG_VAR_NAME(name) cpreg_##name @@ -50,18 +54,26 @@ #define AES_MEM_BASE 0x38C00000 #define VIC0_MEM_BASE 0x38E00000 #define VIC1_MEM_BASE 0x38E01000 +#define TVOUT_MEM_BASE 0x39300000 #define SYSIC_MEM_BASE 0x39700000 #define DMAC1_MEM_BASE 0x39900000 #define SPI0_MEM_BASE 0x3C300000 #define USBPHYS_MEM_BASE 0x3C400000 #define CLOCK0_MEM_BASE 0x3C500000 +#define I2C0_MEM_BASE 0x3C600000 #define TIMER1_MEM_BASE 0x3C700000 +#define I2C1_MEM_BASE 0x3C900000 +#define UART0_MEM_BASE 0x3CC00000 #define SPI1_MEM_BASE 0x3CE00000 #define GPIO_MEM_BASE 0x3CF00000 #define PKE_MEM_BASE 0x3D000000 #define CHIPID_MEM_BASE 0x3D100000 #define SPI2_MEM_BASE 0x3D200000 +#define UNKNOWN1_MEM_BASE 0x3d700000 #define SPI3_MEM_BASE 0x3DA00000 +#define UART1_MEM_BASE 0x3DB00000 +#define UART2_MEM_BASE 0x3DC00000 +#define UART3_MEM_BASE 0x3DD00000 #define CLOCK1_MEM_BASE 0x3E000000 #define SPI4_MEM_BASE 0x3E100000 @@ -87,12 +99,12 @@ typedef struct { IPodTouchSHA1State *sha1_state; IPodTouchAESState *aes_state; IPodTouchPKEState *pke_state; + IPodTouchI2CState *i2c0_state; + IPodTouchI2CState *i2c1_state; Clock *sysclk; char nor_path[1024]; IT2G_CPREG_VAR_DEF(REG0); IT2G_CPREG_VAR_DEF(REG1); - - } IPodTouchMachineState; #endif \ No newline at end of file diff --git a/include/hw/arm/ipod_touch_nor_spi.h b/include/hw/arm/ipod_touch_nor_spi.h index ccff9083d88b..6e48d9634d54 100644 --- a/include/hw/arm/ipod_touch_nor_spi.h +++ b/include/hw/arm/ipod_touch_nor_spi.h @@ -12,6 +12,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchNORSPIState, IPOD_TOUCH_NOR_SPI) #define NOR_READ_DATA_CMD 0x3 #define NOR_GET_STATUS_CMD 0x5 +#define NOR_GET_JEDECID 0x9F typedef struct IPodTouchNORSPIState { SSIPeripheral ssidev; diff --git a/include/hw/arm/ipod_touch_pcf50633_pmu.h b/include/hw/arm/ipod_touch_pcf50633_pmu.h new file mode 100644 index 000000000000..af090c5698a7 --- /dev/null +++ b/include/hw/arm/ipod_touch_pcf50633_pmu.h @@ -0,0 +1,32 @@ +#ifndef HW_PCF50633_PMU_H +#define HW_PCF50633_PMU_H + +#include "qemu/osdep.h" +#include "qemu/module.h" +#include "qemu/timer.h" +#include "hw/sysbus.h" +#include "hw/i2c/i2c.h" +#include "hw/irq.h" +#include "time.h" + +#define TYPE_PCF50633 "pcf50633" +OBJECT_DECLARE_SIMPLE_TYPE(Pcf50633State, PCF50633) + +#define PMU_MBCS1 0x4B +#define PMU_ADCC1 0x57 + +// RTC registers +#define PMU_RTCSC 0x59 +#define PMU_RTCMN 0x5A +#define PMU_RTCHR 0x5B +#define PMU_RTCWD 0x5C +#define PMU_RTCDT 0x5D +#define PMU_RTCMT 0x5E +#define PMU_RTCYR 0x5F + +typedef struct Pcf50633State { + I2CSlave i2c; + uint32_t cmd; +} Pcf50633State; + +#endif \ No newline at end of file diff --git a/include/hw/arm/ipod_touch_unknown1.h b/include/hw/arm/ipod_touch_unknown1.h new file mode 100644 index 000000000000..dd4a7495fe1b --- /dev/null +++ b/include/hw/arm/ipod_touch_unknown1.h @@ -0,0 +1,16 @@ +#ifndef HW_ARM_IPOD_TOUCH_UNKNOWN1_H +#define HW_ARM_IPOD_TOUCH_UNKNOWN1_H + +#include "qemu/osdep.h" +#include "hw/hw.h" +#include "hw/sysbus.h" + +#define TYPE_IPOD_TOUCH_UNKNOWN1 "ipodtouch.unknown1" +OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchUnknown1State, IPOD_TOUCH_UNKNOWN1) + +typedef struct IPodTouchUnknown1State { + SysBusDevice busdev; + MemoryRegion iomem; +} IPodTouchUnknown1State; + +#endif \ No newline at end of file diff --git a/include/hw/i2c/ipod_touch_i2c.h b/include/hw/i2c/ipod_touch_i2c.h new file mode 100644 index 000000000000..7675d733661f --- /dev/null +++ b/include/hw/i2c/ipod_touch_i2c.h @@ -0,0 +1,64 @@ +#ifndef IPOD_TOUCH_I2C_H +#define IPOD_TOUCH_I2C_H + +#include "qemu/osdep.h" +#include "qemu/module.h" +#include "qemu/timer.h" +#include "hw/sysbus.h" +#include "hw/i2c/i2c.h" +#include "hw/irq.h" + +#define TYPE_IPOD_TOUCH_I2C "ipodtouch.i2c" +OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchI2CState, IPOD_TOUCH_I2C) + +#define I2CCON 0x00 /* I2C Control register */ +#define I2CSTAT 0x04 /* I2C Status register */ +#define I2CADD 0x08 /* I2C Slave Address register */ +#define I2CDS 0x0c /* I2C Data Shift register */ +#define I2CLC 0x10 /* I2C Line Control register */ + +#define IICREG20 0x20 + +#define SR_MODE 0x0 /* Slave Receive Mode */ +#define ST_MODE 0x1 /* Slave Transmit Mode */ +#define MR_MODE 0x2 /* Master Receive Mode */ +#define MT_MODE 0x3 /* Master Transmit Mode */ + + +#define S5L8900_IICCON_ACKEN (1<<7) +#define S5L8900_IICCON_TXDIV_16 (0<<6) +#define S5L8900_IICCON_TXDIV_512 (1<<6) +#define S5L8900_IICCON_IRQEN (1<<5) +#define S5L8900_IICCON_IRQPEND (1<<4) + +#define S5L8900_IICSTAT_START (1<<5) +#define S5L8900_IICSTAT_BUSBUSY (1<<5) +#define S5L8900_IICSTAT_TXRXEN (1<<4) +#define S5L8900_IICSTAT_ARBITR (1<<3) +#define S5L8900_IICSTAT_ASSLAVE (1<<2) +#define S5L8900_IICSTAT_ADDR0 (1<<1) +#define S5L8900_IICSTAT_LASTBIT (1<<0) + +#define S5L8900_I2C_REG_MEM_SIZE 0x1000 + +typedef struct IPodTouchI2CState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + I2CBus *bus; + qemu_irq irq; + + uint8_t control; + uint8_t status; + uint8_t address; + uint8_t datashift; + uint8_t line_ctrl; + uint32_t iicreg20; + + uint8_t active; + + uint8_t ibmr; + uint8_t data; +} IPodTouchI2CState; + +#endif \ No newline at end of file From b2b7110aef5853fa5c9a591ca321904f2c4f9412 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Sun, 8 Jan 2023 21:51:23 +0100 Subject: [PATCH 11/58] Fixed SPI again --- hw/arm/ipod_touch_nor_spi.c | 1 - hw/arm/ipod_touch_spi.c | 77 +++++++++++++++++++++++-------------- 2 files changed, 48 insertions(+), 30 deletions(-) diff --git a/hw/arm/ipod_touch_nor_spi.c b/hw/arm/ipod_touch_nor_spi.c index d49ee9c1a4e1..751981d5f242 100644 --- a/hw/arm/ipod_touch_nor_spi.c +++ b/hw/arm/ipod_touch_nor_spi.c @@ -72,7 +72,6 @@ static uint32_t ipod_touch_nor_spi_transfer(SSIPeripheral *dev, uint32_t value) if(s->cur_cmd == NOR_READ_DATA_CMD) { uint8_t ret_val = s->nor_data[s->nor_read_ind]; s->nor_read_ind++; - printf("Ret\n"); return ret_val; } else { diff --git a/hw/arm/ipod_touch_spi.c b/hw/arm/ipod_touch_spi.c index 8d33d5eade27..9440cbcdb5b8 100644 --- a/hw/arm/ipod_touch_spi.c +++ b/hw/arm/ipod_touch_spi.c @@ -88,13 +88,20 @@ static void apple_spi_run(IPodTouchSPIState *s) if (!(REG(s, R_CTRL) & R_CTRL_RUN)) { return; } + if (REG(s, R_RXCNT) == 0 && REG(s, R_TXCNT) == 0) { + return; + } - while (!fifo8_is_empty(&s->tx_fifo)) { + apple_spi_update_xfer_tx(s); + + while (REG(s, R_TXCNT) && !fifo8_is_empty(&s->tx_fifo)) { tx = (uint32_t)fifo8_pop(&s->tx_fifo); rx = ssi_transfer(s->spi, tx); + REG(s, R_TXCNT)--; apple_spi_update_xfer_tx(s); if (REG(s, R_RXCNT) > 0) { if (fifo8_is_full(&s->rx_fifo)) { + hw_error("Rx buffer overflow: %d\n", fifo8_num_free(&s->rx_fifo)); qemu_log_mask(LOG_GUEST_ERROR, "%s: rx overflow\n", __func__); REG(s, R_STATUS) |= R_STATUS_RXOVERFLOW; } else { @@ -109,6 +116,7 @@ static void apple_spi_run(IPodTouchSPIState *s) while (!fifo8_is_full(&s->rx_fifo) && (REG(s, R_RXCNT) > 0) && (REG(s, R_CFG) & R_CFG_AGD)) { rx = ssi_transfer(s->spi, 0xff); if (fifo8_is_full(&s->rx_fifo)) { + hw_error("Rx buffer overflow: %d\n", fifo8_num_free(&s->rx_fifo)); qemu_log_mask(LOG_GUEST_ERROR, "%s: rx overflow\n", __func__); REG(s, R_STATUS) |= R_STATUS_RXOVERFLOW; break; @@ -118,45 +126,53 @@ static void apple_spi_run(IPodTouchSPIState *s) apple_spi_update_xfer_rx(s); } } - if (REG(s, R_RXCNT) == 0 && fifo8_is_empty(&s->tx_fifo)) { + if (REG(s, R_RXCNT) == 0 && REG(s, R_TXCNT) == 0) { REG(s, R_STATUS) |= R_STATUS_COMPLETE; - REG(s, R_CTRL) &= ~R_CTRL_RUN; } } static uint64_t ipod_touch_spi_read(void *opaque, hwaddr addr, unsigned size) { IPodTouchSPIState *s = IPOD_TOUCH_SPI(opaque); - //fprintf(stderr, "%s (base %d): read from location 0x%08x\n", __func__, s->base, addr); + //printf("%s (base %d): read from location 0x%08x\n", __func__, s->base, addr); uint32_t r; + bool run = false; r = s->regs[addr >> 2]; switch (addr) { - case R_RXDATA: { - const uint8_t *buf = NULL; - int word_size = apple_spi_word_size(s); - uint32_t num = 0; - if (fifo8_is_empty(&s->rx_fifo)) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: rx underflow\n", __func__); - r = 0; + case R_RXDATA: { + const uint8_t *buf = NULL; + int word_size = apple_spi_word_size(s); + uint32_t num = 0; + if (fifo8_is_empty(&s->rx_fifo)) { + hw_error("Rx buffer underflow\n"); + qemu_log_mask(LOG_GUEST_ERROR, "%s: rx underflow\n", __func__); + r = 0; + break; + } + buf = fifo8_pop_buf(&s->rx_fifo, word_size, &num); + memcpy(&r, buf, num); + + if (fifo8_is_empty(&s->rx_fifo)) { + run = true; + } break; } - buf = fifo8_pop_buf(&s->rx_fifo, word_size, &num); - memcpy(&r, buf, num); - break; - } - case R_STATUS: { - int val = 0; - val |= (fifo8_num_used(&s->tx_fifo) << R_STATUS_TXFIFO_SHIFT); - val |= (fifo8_num_used(&s->rx_fifo) << R_STATUS_RXFIFO_SHIFT); - r |= val; - break; - } - default: - break; + case R_STATUS: { + int val = 0; + val |= (fifo8_num_used(&s->tx_fifo) << R_STATUS_TXFIFO_SHIFT); + val |= (fifo8_num_used(&s->rx_fifo) << R_STATUS_RXFIFO_SHIFT); + r |= val; + break; + } + default: + break; } + if (run) { + apple_spi_run(s); + } apple_spi_update_irq(s); return r; } @@ -164,7 +180,7 @@ static uint64_t ipod_touch_spi_read(void *opaque, hwaddr addr, unsigned size) static void ipod_touch_spi_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) { IPodTouchSPIState *s = IPOD_TOUCH_SPI(opaque); - //fprintf(stderr, "%s (base %d): writing 0x%08x to 0x%08x\n", __func__, s->base, data, addr); + //printf("%s (base %d): writing 0x%08x to 0x%08x\n", __func__, s->base, data, addr); uint32_t r = data; uint32_t *mmio = ®(s, addr); @@ -185,10 +201,7 @@ static void ipod_touch_spi_write(void *opaque, hwaddr addr, uint64_t data, unsig } break; case R_STATUS: - fifo8_reset(&s->tx_fifo); - //fifo8_reset(&s->rx_fifo); r = old & (~r); - run = true; break; case R_PIN: cs_flg = true; @@ -197,7 +210,7 @@ static void ipod_touch_spi_write(void *opaque, hwaddr addr, uint64_t data, unsig int word_size = apple_spi_word_size(s); if ((fifo8_is_full(&s->tx_fifo)) || (fifo8_num_free(&s->tx_fifo) < word_size)) { - hw_error("OVERFLOW: %d\n", fifo8_num_free(&s->tx_fifo)); + hw_error("Tx buffer overflow: %d\n", fifo8_num_free(&s->tx_fifo)); qemu_log_mask(LOG_GUEST_ERROR, "%s: tx overflow\n", __func__); r = 0; break; @@ -219,6 +232,12 @@ static void ipod_touch_spi_write(void *opaque, hwaddr addr, uint64_t data, unsig if (run) { apple_spi_run(s); } + + if(addr == R_STATUS) { + apple_spi_update_xfer_tx(s); + apple_spi_update_xfer_rx(s); + } + apple_spi_update_irq(s); } From 77da53507a307eb0d1cf498ef75a804589142c29 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Fri, 13 Jan 2023 13:03:51 +0100 Subject: [PATCH 12/58] Working on iBoot --- hw/arm/ipod_touch_2g.c | 1 + hw/arm/ipod_touch_pke.c | 43 ++++++++++++++++++++++------------ include/hw/arm/ipod_touch_2g.h | 1 + 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/hw/arm/ipod_touch_2g.c b/hw/arm/ipod_touch_2g.c index aeb058f46cda..335960bc826b 100644 --- a/hw/arm/ipod_touch_2g.c +++ b/hw/arm/ipod_touch_2g.c @@ -81,6 +81,7 @@ static void ipod_touch_memory_setup(MachineState *machine, MemoryRegion *sysmem, { IPodTouchMachineState *nms = IPOD_TOUCH_MACHINE(machine); + allocate_ram(sysmem, "iboot", IBOOT_MEM_BASE, 0x100000); allocate_ram(sysmem, "llb", 0x22000000, 0x100000); allocate_ram(sysmem, "sram1", SRAM1_MEM_BASE, 0x100000); allocate_ram(sysmem, "tvout", TVOUT_MEM_BASE, 0x1000); diff --git a/hw/arm/ipod_touch_pke.c b/hw/arm/ipod_touch_pke.c index b8286b739006..c6a782c01c63 100644 --- a/hw/arm/ipod_touch_pke.c +++ b/hw/arm/ipod_touch_pke.c @@ -67,6 +67,12 @@ static void ipod_touch_pke_write(void *opaque, hwaddr offset, uint64_t value, un //printf("%s: offset 0x%08x value 0x%08x\n", __FUNCTION__, offset, value); switch(offset) { + case 0x0: + s->num_started = 0; + break; + case 0x10: + printf("Seg sign: %d\n", value); + break; case REG_PKE_SEG_START ... (REG_PKE_SEG_START + 1024): { uint32_t *segments_cast = (uint32_t *)s->segments; @@ -77,20 +83,24 @@ static void ipod_touch_pke_write(void *opaque, hwaddr offset, uint64_t value, un { s->num_started++; + if(s->num_started == 5) { + printf("Base: 0x"); + uint32_t *cast = (uint32_t *)(&s->segments[s->segment_size]); // segment 1 + for(int i = (s->segment_size / 4 - 1); i >= 0; i--) { + printf("%08x", cast[i]); + } + printf("\n"); + + printf("Mod: 0x"); + cast = (uint32_t *)s->segments; // segment 0 + for(int i = (s->segment_size / 4 - 1); i >= 0; i--) { + printf("%08x", cast[i]); + } + printf("\n\n"); + } + if(s->num_started == 5) { // TODO this is arbitrary! - // printf("Base: 0x"); - // uint32_t *cast = (uint32_t *)(&s->segments[s->segment_size]); // segment 1 - // for(int i = (s->segment_size / 4 - 1); i >= 0; i--) { - // printf("%08x", cast[i]); - // } - // printf("\n"); - - // printf("Mod: 0x"); - // cast = (uint32_t *)s->segments; // segment 0 - // for(int i = (s->segment_size / 4 - 1); i >= 0; i--) { - // printf("%08x", cast[i]); - // } - // printf("\n\n"); + BIGNUM *mod_bn = BN_lebin2bn(s->segments, s->segment_size, NULL); BIGNUM *base_bn = BN_lebin2bn(s->segments + s->segment_size, s->segment_size, NULL); @@ -102,8 +112,8 @@ static void ipod_touch_pke_write(void *opaque, hwaddr offset, uint64_t value, un BIGNUM *res = BN_new(); BN_CTX *ctx = BN_CTX_new(); BN_mod_exp(res, base_bn, exp_bn, mod_bn, ctx); - // BN_print(BIO_new_fp(stdout, BIO_NOCLOSE), res); - // printf("\n\n"); + BN_print(BIO_new_fp(stdout, BIO_NOCLOSE), res); + printf("\n\n"); char *res_hex = datahex(BN_bn2hex(res)); @@ -114,15 +124,18 @@ static void ipod_touch_pke_write(void *opaque, hwaddr offset, uint64_t value, un break; } case REG_PKE_SEG_SIZE: + printf("Setting size: %d\n", value); s->seg_size_reg = value; uint32_t size_bit = (s->seg_size_reg >> 6); if(size_bit == 0) { s->segment_size = 256; } else if(size_bit == 1) { s->segment_size = 128; } else { hw_error("Unsupported segment size bit %d!", size_bit); } + printf("Segment size: %d\n", s->segment_size); break; case REG_PKE_SWRESET: s->num_started = 0; + break; default: break; } diff --git a/include/hw/arm/ipod_touch_2g.h b/include/hw/arm/ipod_touch_2g.h index 4504b22dc531..c94b050b431a 100644 --- a/include/hw/arm/ipod_touch_2g.h +++ b/include/hw/arm/ipod_touch_2g.h @@ -47,6 +47,7 @@ // memory addresses #define VROM_MEM_BASE 0x0 +#define IBOOT_MEM_BASE 0xFF00000 #define SRAM1_MEM_BASE 0x22020000 #define SHA1_MEM_BASE 0x38000000 #define DMAC0_MEM_BASE 0x38200000 From 4f7625e4cb14c397bf6ab05b4fb0002746130fe6 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Mon, 30 Jan 2023 18:17:53 +0100 Subject: [PATCH 13/58] Hardcoded iBoot decryption keys --- hw/arm/ipod_touch_aes.c | 25 ++++++++++++++++++------- include/hw/arm/ipod_touch_aes.h | 3 ++- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/hw/arm/ipod_touch_aes.c b/hw/arm/ipod_touch_aes.c index 1781dd16cf23..478e33465759 100644 --- a/hw/arm/ipod_touch_aes.c +++ b/hw/arm/ipod_touch_aes.c @@ -47,14 +47,23 @@ static void ipod_touch_aes_write(void *opaque, hwaddr offset, uint64_t value, un // Unfortunately, we don't have access to the GID key. // However, we know that when the AES engine is invoked with the GID key type, it's for the decryption of the IMG file. // Instead, we provide an hard-coded key as result and copy it to the output buffer. - // source: https://www.theiphonewiki.com/wiki/Sugar_Bowl_5F138_(iPod2,1) (LLB) - char key[] = { - 0xce, 0x97, 0xa7, 0xc8, 0x2e, 0xf8, 0x64, 0x67, 0x5e, 0xd3, 0x68, 0x05, 0x97, 0xec, 0x2a, 0xef, // IV - 0x27, 0x73, 0x2a, 0x6b, 0xbf, 0xb1, 0x4a, 0x07, 0x25, 0x0a, 0x2e, 0x46, 0x82, 0xbf, 0x3c, 0xba, // key - }; - for(int i = 0; i < aesop->insize; i++) { - buf[i] = key[i]; + // source: https://www.theiphonewiki.com/wiki/Sugar_Bowl_5F138_(iPod2,1) + if(aesop->gid_encryption_count == 0) { // LLB + char key[] = { + 0xce, 0x97, 0xa7, 0xc8, 0x2e, 0xf8, 0x64, 0x67, 0x5e, 0xd3, 0x68, 0x05, 0x97, 0xec, 0x2a, 0xef, // IV + 0x27, 0x73, 0x2a, 0x6b, 0xbf, 0xb1, 0x4a, 0x07, 0x25, 0x0a, 0x2e, 0x46, 0x82, 0xbf, 0x3c, 0xba, // key + }; + for(int i = 0; i < aesop->insize; i++) { buf[i] = key[i]; } } + else if(aesop->gid_encryption_count == 1) { // iBoot + char key[] = { + 0xb3, 0x63, 0x3a, 0xfb, 0xe0, 0x2e, 0x0e, 0x9b, 0xa4, 0xd7, 0x36, 0x6c, 0x47, 0xab, 0xe5, 0xa8, // IV + 0x2d, 0x91, 0x6d, 0xab, 0xb6, 0xdf, 0xd4, 0x59, 0x4d, 0xbe, 0x36, 0x35, 0xb4, 0xc7, 0x16, 0x62, // key + }; + for(int i = 0; i < aesop->insize; i++) { buf[i] = key[i]; } + } + + aesop->gid_encryption_count++; } else { AES_cbc_encrypt(inbuf, buf, aesop->insize, &aesop->decryptKey, (uint8_t *)aesop->ivec, AES_DECRYPT); @@ -125,6 +134,8 @@ static void ipod_touch_aes_init(Object *obj) memset(&s->custkey, 0, 8 * sizeof(uint32_t)); memset(&s->ivec, 0, 4 * sizeof(uint32_t)); + + s->gid_encryption_count = 0; } static void ipod_touch_aes_class_init(ObjectClass *klass, void *data) diff --git a/include/hw/arm/ipod_touch_aes.h b/include/hw/arm/ipod_touch_aes.h index 8c2952d9fe97..aa60fe7707e1 100644 --- a/include/hw/arm/ipod_touch_aes.h +++ b/include/hw/arm/ipod_touch_aes.h @@ -63,7 +63,8 @@ typedef struct IPodTouchAESState uint32_t unkreg1; uint32_t operation; uint32_t keylen; - uint32_t custkey[8]; + uint32_t custkey[8]; + uint8_t gid_encryption_count; } IPodTouchAESState; #endif From 3e17ca75b60cff203550f72191c9abb437f1d618 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Tue, 31 Jan 2023 16:35:44 +0100 Subject: [PATCH 14/58] Some work on LCD/MIPI DSI --- hw/arm/ipod_touch_2g.c | 16 +++++++ hw/arm/ipod_touch_lcd.c | 69 ++++++++++++++++++++++++++++ hw/arm/ipod_touch_mipi_dsi.c | 67 +++++++++++++++++++++++++++ hw/arm/meson.build | 2 +- include/hw/arm/ipod_touch_2g.h | 12 ++++- include/hw/arm/ipod_touch_lcd.h | 21 +++++++++ include/hw/arm/ipod_touch_mipi_dsi.h | 21 +++++++++ include/hw/arm/ipod_touch_timer.h | 2 +- 8 files changed, 206 insertions(+), 4 deletions(-) create mode 100644 hw/arm/ipod_touch_lcd.c create mode 100644 hw/arm/ipod_touch_mipi_dsi.c create mode 100644 include/hw/arm/ipod_touch_lcd.h create mode 100644 include/hw/arm/ipod_touch_mipi_dsi.h diff --git a/hw/arm/ipod_touch_2g.c b/hw/arm/ipod_touch_2g.c index 335960bc826b..1e66355d35b3 100644 --- a/hw/arm/ipod_touch_2g.c +++ b/hw/arm/ipod_touch_2g.c @@ -85,6 +85,7 @@ static void ipod_touch_memory_setup(MachineState *machine, MemoryRegion *sysmem, allocate_ram(sysmem, "llb", 0x22000000, 0x100000); allocate_ram(sysmem, "sram1", SRAM1_MEM_BASE, 0x100000); allocate_ram(sysmem, "tvout", TVOUT_MEM_BASE, 0x1000); + allocate_ram(sysmem, "framebuffer", FRAMEBUFFER_MEM_BASE, 0x400000); // load the bootrom (vrom) uint8_t *file_data = NULL; @@ -179,6 +180,7 @@ static void ipod_touch_machine_init(MachineState *machine) memory_region_add_subregion(sysmem, TIMER1_MEM_BASE, &timer_state->iomem); SysBusDevice *busdev = SYS_BUS_DEVICE(dev); sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_TIMER1_IRQ)); + //sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_TIMER1_IRQ - 1)); timer_state->sysclk = nms->sysclk; // init sysic @@ -305,6 +307,20 @@ static void ipod_touch_machine_init(MachineState *machine) ipod_touch_memory_setup(machine, sysmem, nsas); + // init the MIPI SDI controller + dev = qdev_new("ipodtouch.mipidsi"); + IPodTouchLCDState *mipi_dsi_state = IPOD_TOUCH_MIPI_DSI(dev); + nms->mipi_dsi_state = mipi_dsi_state; + memory_region_add_subregion(sysmem, MIPI_DSI_MEM_BASE, &mipi_dsi_state->iomem); + + // init LCD + dev = qdev_new("ipodtouch.lcd"); + IPodTouchLCDState *lcd_state = IPOD_TOUCH_LCD(dev); + nms->lcd_state = lcd_state; + sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_LCD_IRQ)); + memory_region_add_subregion(sysmem, DISPLAY_MEM_BASE, &lcd_state->iomem); + sysbus_realize(busdev, &error_fatal); + // init SHA1 engine dev = qdev_new("ipodtouch.sha1"); IPodTouchSHA1State *sha1_state = IPOD_TOUCH_SHA1(dev); diff --git a/hw/arm/ipod_touch_lcd.c b/hw/arm/ipod_touch_lcd.c new file mode 100644 index 000000000000..2cfa2d58413b --- /dev/null +++ b/hw/arm/ipod_touch_lcd.c @@ -0,0 +1,69 @@ +#include "hw/arm/ipod_touch_lcd.h" + +static uint64_t ipod_touch_lcd_read(void *opaque, hwaddr addr, unsigned size) +{ + fprintf(stderr, "%s: read from location 0x%08x\n", __func__, addr); + + IPodTouchLCDState *s = (IPodTouchLCDState *)opaque; + switch(addr) + { + case 0x0: + return 2; + case 0x1b10: + return 2; + default: + // hw_error("%s: read invalid location 0x%08x.\n", __func__, addr); + break; + } + return 0; +} + +static void ipod_touch_lcd_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) +{ + IPodTouchLCDState *s = (IPodTouchLCDState *)opaque; + // fprintf(stderr, "%s: writing 0x%08x to 0x%08x\n", __func__, val, addr); +} + +static const MemoryRegionOps lcd_ops = { + .read = ipod_touch_lcd_read, + .write = ipod_touch_lcd_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void ipod_touch_lcd_realize(DeviceState *dev, Error **errp) +{ + +} + +static void ipod_touch_lcd_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(sbd); + IPodTouchLCDState *s = IPOD_TOUCH_LCD(dev); + + memory_region_init_io(&s->iomem, obj, &lcd_ops, s, "lcd", 0x10000); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); +} + +static void ipod_touch_lcd_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = ipod_touch_lcd_realize; +} + +static const TypeInfo ipod_touch_lcd_info = { + .name = TYPE_IPOD_TOUCH_LCD, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IPodTouchLCDState), + .instance_init = ipod_touch_lcd_init, + .class_init = ipod_touch_lcd_class_init, +}; + +static void ipod_touch_machine_types(void) +{ + type_register_static(&ipod_touch_lcd_info); +} + +type_init(ipod_touch_machine_types) \ No newline at end of file diff --git a/hw/arm/ipod_touch_mipi_dsi.c b/hw/arm/ipod_touch_mipi_dsi.c new file mode 100644 index 000000000000..7e852293e83e --- /dev/null +++ b/hw/arm/ipod_touch_mipi_dsi.c @@ -0,0 +1,67 @@ +#include "hw/arm/ipod_touch_mipi_dsi.h" + +static uint64_t ipod_touch_mipi_dsi_read(void *opaque, hwaddr addr, unsigned size) +{ + fprintf(stderr, "%s: read from location 0x%08x\n", __func__, addr); + + IPodTouchMIPIDSIState *s = (IPodTouchMIPIDSIState *)opaque; + switch(addr) + { + case 0x0: + return 0x103; + default: + // hw_error("%s: read invalid location 0x%08x.\n", __func__, addr); + break; + } + return 0; +} + +static void ipod_touch_mipi_dsi_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) +{ + IPodTouchMIPIDSIState *s = (IPodTouchMIPIDSIState *)opaque; + // fprintf(stderr, "%s: writing 0x%08x to 0x%08x\n", __func__, val, addr); +} + +static const MemoryRegionOps mipi_dsi_ops = { + .read = ipod_touch_mipi_dsi_read, + .write = ipod_touch_mipi_dsi_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void ipod_touch_mipi_dsi_realize(DeviceState *dev, Error **errp) +{ + +} + +static void ipod_touch_mipi_dsi_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(sbd); + IPodTouchMIPIDSIState *s = IPOD_TOUCH_MIPI_DSI(dev); + + memory_region_init_io(&s->iomem, obj, &mipi_dsi_ops, s, "mipi_dsi", 0x10000); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); +} + +static void ipod_touch_mipi_dsi_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = ipod_touch_mipi_dsi_realize; +} + +static const TypeInfo ipod_touch_mipi_dsi_info = { + .name = TYPE_IPOD_TOUCH_MIPI_DSI, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IPodTouchMIPIDSIState), + .instance_init = ipod_touch_mipi_dsi_init, + .class_init = ipod_touch_mipi_dsi_class_init, +}; + +static void ipod_touch_machine_types(void) +{ + type_register_static(&ipod_touch_mipi_dsi_info); +} + +type_init(ipod_touch_machine_types) \ No newline at end of file diff --git a/hw/arm/meson.build b/hw/arm/meson.build index 2fb7f6dd66b5..31a0dea56de6 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -62,6 +62,6 @@ arm_ss.add(when: 'CONFIG_FSL_IMX7', if_true: files('fsl-imx7.c', 'mcimx7d-sabre. arm_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c', 'smmuv3.c')) arm_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c')) arm_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c')) -arm_ss.add(when: 'CONFIG_IPOD_TOUCH_2G', if_true: files('ipod_touch_2g.c', 'ipod_touch_clock.c', 'ipod_touch_chipid.c', 'ipod_touch_gpio.c', 'ipod_touch_sysic.c', 'ipod_touch_timer.c', 'ipod_touch_usb_otg.c', 'ipod_touch_usb_phys.c', 'ipod_touch_spi.c', 'ipod_touch_nor_spi.c', 'ipod_touch_sha1.c', 'ipod_touch_aes.c', 'ipod_touch_pke.c', 'ipod_touch_pcf50633_pmu.c', 'ipod_touch_unknown1.c')) +arm_ss.add(when: 'CONFIG_IPOD_TOUCH_2G', if_true: files('ipod_touch_2g.c', 'ipod_touch_clock.c', 'ipod_touch_chipid.c', 'ipod_touch_gpio.c', 'ipod_touch_sysic.c', 'ipod_touch_timer.c', 'ipod_touch_usb_otg.c', 'ipod_touch_usb_phys.c', 'ipod_touch_spi.c', 'ipod_touch_nor_spi.c', 'ipod_touch_sha1.c', 'ipod_touch_aes.c', 'ipod_touch_pke.c', 'ipod_touch_pcf50633_pmu.c', 'ipod_touch_unknown1.c', 'ipod_touch_lcd.c', 'ipod_touch_mipi_dsi.c')) hw_arch += {'arm': arm_ss} diff --git a/include/hw/arm/ipod_touch_2g.h b/include/hw/arm/ipod_touch_2g.h index c94b050b431a..958b297e870f 100644 --- a/include/hw/arm/ipod_touch_2g.h +++ b/include/hw/arm/ipod_touch_2g.h @@ -20,17 +20,20 @@ #include "hw/arm/ipod_touch_aes.h" #include "hw/arm/ipod_touch_pke.h" #include "hw/arm/ipod_touch_unknown1.h" +#include "hw/arm/ipod_touch_lcd.h" +#include "hw/arm/ipod_touch_mipi_dsi.h" #define TYPE_IPOD_TOUCH "iPod-Touch" #define S5L8720_VIC_N 2 #define S5L8720_VIC_SIZE 32 -#define S5L8720_TIMER1_IRQ 0x8 +#define S5L8720_TIMER1_IRQ 0x7 #define S5L8720_USB_OTG_IRQ 0x13 #define S5L8720_SPI0_IRQ 0x9 #define S5L8720_SPI1_IRQ 0xA #define S5L8720_SPI2_IRQ 0xB +#define S5L8720_LCD_IRQ 0xD #define S5L8720_DMAC0_IRQ 0x10 #define S5L8720_DMAC1_IRQ 0x11 #define S5L8720_I2C0_IRQ 0x15 @@ -47,11 +50,13 @@ // memory addresses #define VROM_MEM_BASE 0x0 +#define FRAMEBUFFER_MEM_BASE 0xFB00000 #define IBOOT_MEM_BASE 0xFF00000 #define SRAM1_MEM_BASE 0x22020000 #define SHA1_MEM_BASE 0x38000000 #define DMAC0_MEM_BASE 0x38200000 #define USBOTG_MEM_BASE 0x38400000 +#define DISPLAY_MEM_BASE 0x38900000 #define AES_MEM_BASE 0x38C00000 #define VIC0_MEM_BASE 0x38E00000 #define VIC1_MEM_BASE 0x38E01000 @@ -70,7 +75,8 @@ #define PKE_MEM_BASE 0x3D000000 #define CHIPID_MEM_BASE 0x3D100000 #define SPI2_MEM_BASE 0x3D200000 -#define UNKNOWN1_MEM_BASE 0x3d700000 +#define UNKNOWN1_MEM_BASE 0x3D700000 +#define MIPI_DSI_MEM_BASE 0x3D800000 #define SPI3_MEM_BASE 0x3DA00000 #define UART1_MEM_BASE 0x3DB00000 #define UART2_MEM_BASE 0x3DC00000 @@ -102,6 +108,8 @@ typedef struct { IPodTouchPKEState *pke_state; IPodTouchI2CState *i2c0_state; IPodTouchI2CState *i2c1_state; + IPodTouchLCDState *lcd_state; + IPodTouchMIPIDSIState *mipi_dsi_state; Clock *sysclk; char nor_path[1024]; IT2G_CPREG_VAR_DEF(REG0); diff --git a/include/hw/arm/ipod_touch_lcd.h b/include/hw/arm/ipod_touch_lcd.h new file mode 100644 index 000000000000..b2c86d3c2da9 --- /dev/null +++ b/include/hw/arm/ipod_touch_lcd.h @@ -0,0 +1,21 @@ +#ifndef IPOD_TOUCH_LCD_H +#define IPOD_TOUCH_LCD_H + +#include +#include "qemu/osdep.h" +#include "qemu/module.h" +#include "qemu/timer.h" +#include "hw/sysbus.h" +#include "hw/irq.h" + +#define TYPE_IPOD_TOUCH_LCD "ipodtouch.lcd" +OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchLCDState, IPOD_TOUCH_LCD) + +typedef struct IPodTouchLCDState +{ + SysBusDevice parent_obj; + MemoryRegion iomem; + qemu_irq irq; +} IPodTouchLCDState; + +#endif \ No newline at end of file diff --git a/include/hw/arm/ipod_touch_mipi_dsi.h b/include/hw/arm/ipod_touch_mipi_dsi.h new file mode 100644 index 000000000000..080eb9a5b943 --- /dev/null +++ b/include/hw/arm/ipod_touch_mipi_dsi.h @@ -0,0 +1,21 @@ +#ifndef IPOD_TOUCH_MIPI_DSI_H +#define IPOD_TOUCH_MIPI_DSI_H + +#include +#include "qemu/osdep.h" +#include "qemu/module.h" +#include "qemu/timer.h" +#include "hw/sysbus.h" +#include "hw/irq.h" + +#define TYPE_IPOD_TOUCH_MIPI_DSI "ipodtouch.mipidsi" +OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchMIPIDSIState, IPOD_TOUCH_MIPI_DSI) + +typedef struct IPodTouchMIPIDSIState +{ + SysBusDevice parent_obj; + MemoryRegion iomem; + qemu_irq irq; +} IPodTouchMIPIDSIState; + +#endif \ No newline at end of file diff --git a/include/hw/arm/ipod_touch_timer.h b/include/hw/arm/ipod_touch_timer.h index 3a3af5033fbc..99708c81720e 100644 --- a/include/hw/arm/ipod_touch_timer.h +++ b/include/hw/arm/ipod_touch_timer.h @@ -12,7 +12,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchTimerState, IPOD_TOUCH_TIMER) #define TIMER_IRQSTAT 0x10000 -#define TIMER_IRQLATCH 0xF8 +#define TIMER_IRQLATCH 0x118 #define TIMER_TICKSHIGH 0x80 #define TIMER_TICKSLOW 0x84 #define TIMER_STATE_START 1 From 463e8d8047bfe0e9129aea3728c5287776ba73e4 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Tue, 7 Feb 2023 19:59:57 +0100 Subject: [PATCH 15/58] Worked on several components --- hw/arm/ipod_touch_2g.c | 10 +++- hw/arm/ipod_touch_fmss.c | 71 ++++++++++++++++++++++++++++ hw/arm/ipod_touch_mipi_dsi.c | 4 +- hw/arm/ipod_touch_nor_spi.c | 1 + hw/arm/ipod_touch_usb_phys.c | 5 +- hw/arm/meson.build | 2 +- include/hw/arm/ipod_touch_2g.h | 71 +++++++++++++++------------- include/hw/arm/ipod_touch_fmss.h | 25 ++++++++++ include/hw/arm/ipod_touch_mipi_dsi.h | 5 ++ 9 files changed, 156 insertions(+), 38 deletions(-) create mode 100644 hw/arm/ipod_touch_fmss.c create mode 100644 include/hw/arm/ipod_touch_fmss.h diff --git a/hw/arm/ipod_touch_2g.c b/hw/arm/ipod_touch_2g.c index 1e66355d35b3..de2ec311b9f8 100644 --- a/hw/arm/ipod_touch_2g.c +++ b/hw/arm/ipod_touch_2g.c @@ -81,6 +81,8 @@ static void ipod_touch_memory_setup(MachineState *machine, MemoryRegion *sysmem, { IPodTouchMachineState *nms = IPOD_TOUCH_MACHINE(machine); + allocate_ram(sysmem, "insecure_ram", INSECURE_RAM_MEM_BASE, 0x3000000); + allocate_ram(sysmem, "secure_ram", SECURE_RAM_MEM_BASE, 0x4B04000); allocate_ram(sysmem, "iboot", IBOOT_MEM_BASE, 0x100000); allocate_ram(sysmem, "llb", 0x22000000, 0x100000); allocate_ram(sysmem, "sram1", SRAM1_MEM_BASE, 0x100000); @@ -292,6 +294,12 @@ static void ipod_touch_machine_init(MachineState *machine) // init the PMU i2c_slave_create_simple(i2c_state->bus, "pcf50633", 0x73); + // init the FMSS flash controller + dev = qdev_new("ipodtouch.fmss"); + IPodTouchFMSSState *fmss_state = IPOD_TOUCH_FMSS(dev); + nms->fmss_state = fmss_state; + memory_region_add_subregion(sysmem, FMSS_MEM_BASE, &fmss_state->iomem); + dev = qdev_new("ipodtouch.i2c"); i2c_state = IPOD_TOUCH_I2C(dev); nms->i2c1_state = i2c_state; @@ -309,7 +317,7 @@ static void ipod_touch_machine_init(MachineState *machine) // init the MIPI SDI controller dev = qdev_new("ipodtouch.mipidsi"); - IPodTouchLCDState *mipi_dsi_state = IPOD_TOUCH_MIPI_DSI(dev); + IPodTouchMIPIDSIState *mipi_dsi_state = IPOD_TOUCH_MIPI_DSI(dev); nms->mipi_dsi_state = mipi_dsi_state; memory_region_add_subregion(sysmem, MIPI_DSI_MEM_BASE, &mipi_dsi_state->iomem); diff --git a/hw/arm/ipod_touch_fmss.c b/hw/arm/ipod_touch_fmss.c new file mode 100644 index 000000000000..8fb1c1517b3c --- /dev/null +++ b/hw/arm/ipod_touch_fmss.c @@ -0,0 +1,71 @@ +#include "hw/arm/ipod_touch_fmss.h" + +static uint64_t ipod_touch_fmss_read(void *opaque, hwaddr addr, unsigned size) +{ + //fprintf(stderr, "%s: read from location 0x%08x\n", __func__, addr); + + IPodTouchFMSSState *s = (IPodTouchFMSSState *)opaque; + switch(addr) + { + case FMSS__CS_BUF_RST_OK: + return 0x1; + case FMSS__CS_IRQ: + return 0x0; + case FMSS__FMCTRL1: + return (0x1 << 30); + default: + // hw_error("%s: read invalid location 0x%08x.\n", __func__, addr); + break; + } + return 0; +} + +static void ipod_touch_fmss_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) +{ + IPodTouchFMSSState *s = (IPodTouchFMSSState *)opaque; + fprintf(stderr, "%s: writing 0x%08x to 0x%08x\n", __func__, val, addr); +} + +static const MemoryRegionOps fmss_ops = { + .read = ipod_touch_fmss_read, + .write = ipod_touch_fmss_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void ipod_touch_fmss_realize(DeviceState *dev, Error **errp) +{ + +} + +static void ipod_touch_fmss_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(sbd); + IPodTouchFMSSState *s = IPOD_TOUCH_FMSS(dev); + + memory_region_init_io(&s->iomem, obj, &fmss_ops, s, "fmss", 0x1000); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); +} + +static void ipod_touch_fmss_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = ipod_touch_fmss_realize; +} + +static const TypeInfo ipod_touch_fmss_info = { + .name = TYPE_IPOD_TOUCH_FMSS, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IPodTouchFMSSState), + .instance_init = ipod_touch_fmss_init, + .class_init = ipod_touch_fmss_class_init, +}; + +static void ipod_touch_machine_types(void) +{ + type_register_static(&ipod_touch_fmss_info); +} + +type_init(ipod_touch_machine_types) \ No newline at end of file diff --git a/hw/arm/ipod_touch_mipi_dsi.c b/hw/arm/ipod_touch_mipi_dsi.c index 7e852293e83e..31af799b98f7 100644 --- a/hw/arm/ipod_touch_mipi_dsi.c +++ b/hw/arm/ipod_touch_mipi_dsi.c @@ -8,7 +8,9 @@ static uint64_t ipod_touch_mipi_dsi_read(void *opaque, hwaddr addr, unsigned siz switch(addr) { case 0x0: - return 0x103; + return 0x103 | rDSIM_STATUS_TxReadyHsClk; + case REG_FIFOCTRL: + return rDSIM_FIFOCTRL_EmptyHSfr; default: // hw_error("%s: read invalid location 0x%08x.\n", __func__, addr); break; diff --git a/hw/arm/ipod_touch_nor_spi.c b/hw/arm/ipod_touch_nor_spi.c index 751981d5f242..377609397b97 100644 --- a/hw/arm/ipod_touch_nor_spi.c +++ b/hw/arm/ipod_touch_nor_spi.c @@ -63,6 +63,7 @@ static uint32_t ipod_touch_nor_spi_transfer(SSIPeripheral *dev, uint32_t value) else if(s->cur_cmd == NOR_READ_DATA_CMD && s->in_buf_cur_ind == s->in_buf_size) { if(!s->nor_initialized) { initialize_nor(s); } s->nor_read_ind = (s->in_buf[1] << 16) | (s->in_buf[2] << 8) | s->in_buf[3]; + printf("Setting NOR read index to: %d\n", s->nor_read_ind); } return 0x0; } diff --git a/hw/arm/ipod_touch_usb_phys.c b/hw/arm/ipod_touch_usb_phys.c index 686881d637a8..f8eb44abab92 100644 --- a/hw/arm/ipod_touch_usb_phys.c +++ b/hw/arm/ipod_touch_usb_phys.c @@ -44,7 +44,8 @@ static void ipod_touch_usb_phys_write(void *opaque, hwaddr addr, uint64_t val, u return; default: - hw_error("%s: write invalid location 0x%08x.\n", __func__, addr); + //hw_error("%s: write invalid location 0x%08x.\n", __func__, addr); + return; } } @@ -59,7 +60,7 @@ static void ipod_touch_usb_phys_init(Object *obj) IPodTouchUSBPhysState *s = IPOD_TOUCH_USB_PHYS(obj); SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - memory_region_init_io(&s->iomem, obj, &ipod_touch_usb_phys_ops, s, TYPE_IPOD_TOUCH_USB_PHYS, 0x40); + memory_region_init_io(&s->iomem, obj, &ipod_touch_usb_phys_ops, s, TYPE_IPOD_TOUCH_USB_PHYS, 0x1000); sysbus_init_mmio(sbd, &s->iomem); } diff --git a/hw/arm/meson.build b/hw/arm/meson.build index 31a0dea56de6..50723674dd66 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -62,6 +62,6 @@ arm_ss.add(when: 'CONFIG_FSL_IMX7', if_true: files('fsl-imx7.c', 'mcimx7d-sabre. arm_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c', 'smmuv3.c')) arm_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c')) arm_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c')) -arm_ss.add(when: 'CONFIG_IPOD_TOUCH_2G', if_true: files('ipod_touch_2g.c', 'ipod_touch_clock.c', 'ipod_touch_chipid.c', 'ipod_touch_gpio.c', 'ipod_touch_sysic.c', 'ipod_touch_timer.c', 'ipod_touch_usb_otg.c', 'ipod_touch_usb_phys.c', 'ipod_touch_spi.c', 'ipod_touch_nor_spi.c', 'ipod_touch_sha1.c', 'ipod_touch_aes.c', 'ipod_touch_pke.c', 'ipod_touch_pcf50633_pmu.c', 'ipod_touch_unknown1.c', 'ipod_touch_lcd.c', 'ipod_touch_mipi_dsi.c')) +arm_ss.add(when: 'CONFIG_IPOD_TOUCH_2G', if_true: files('ipod_touch_2g.c', 'ipod_touch_clock.c', 'ipod_touch_chipid.c', 'ipod_touch_gpio.c', 'ipod_touch_sysic.c', 'ipod_touch_timer.c', 'ipod_touch_usb_otg.c', 'ipod_touch_usb_phys.c', 'ipod_touch_spi.c', 'ipod_touch_nor_spi.c', 'ipod_touch_sha1.c', 'ipod_touch_aes.c', 'ipod_touch_pke.c', 'ipod_touch_pcf50633_pmu.c', 'ipod_touch_unknown1.c', 'ipod_touch_lcd.c', 'ipod_touch_mipi_dsi.c', 'ipod_touch_fmss.c')) hw_arch += {'arm': arm_ss} diff --git a/include/hw/arm/ipod_touch_2g.h b/include/hw/arm/ipod_touch_2g.h index 958b297e870f..c5f33eeecca7 100644 --- a/include/hw/arm/ipod_touch_2g.h +++ b/include/hw/arm/ipod_touch_2g.h @@ -22,6 +22,7 @@ #include "hw/arm/ipod_touch_unknown1.h" #include "hw/arm/ipod_touch_lcd.h" #include "hw/arm/ipod_touch_mipi_dsi.h" +#include "hw/arm/ipod_touch_fmss.h" #define TYPE_IPOD_TOUCH "iPod-Touch" @@ -50,39 +51,42 @@ // memory addresses #define VROM_MEM_BASE 0x0 -#define FRAMEBUFFER_MEM_BASE 0xFB00000 -#define IBOOT_MEM_BASE 0xFF00000 -#define SRAM1_MEM_BASE 0x22020000 -#define SHA1_MEM_BASE 0x38000000 -#define DMAC0_MEM_BASE 0x38200000 -#define USBOTG_MEM_BASE 0x38400000 -#define DISPLAY_MEM_BASE 0x38900000 -#define AES_MEM_BASE 0x38C00000 -#define VIC0_MEM_BASE 0x38E00000 -#define VIC1_MEM_BASE 0x38E01000 -#define TVOUT_MEM_BASE 0x39300000 -#define SYSIC_MEM_BASE 0x39700000 -#define DMAC1_MEM_BASE 0x39900000 -#define SPI0_MEM_BASE 0x3C300000 -#define USBPHYS_MEM_BASE 0x3C400000 -#define CLOCK0_MEM_BASE 0x3C500000 -#define I2C0_MEM_BASE 0x3C600000 -#define TIMER1_MEM_BASE 0x3C700000 -#define I2C1_MEM_BASE 0x3C900000 -#define UART0_MEM_BASE 0x3CC00000 -#define SPI1_MEM_BASE 0x3CE00000 -#define GPIO_MEM_BASE 0x3CF00000 -#define PKE_MEM_BASE 0x3D000000 -#define CHIPID_MEM_BASE 0x3D100000 -#define SPI2_MEM_BASE 0x3D200000 -#define UNKNOWN1_MEM_BASE 0x3D700000 -#define MIPI_DSI_MEM_BASE 0x3D800000 -#define SPI3_MEM_BASE 0x3DA00000 -#define UART1_MEM_BASE 0x3DB00000 -#define UART2_MEM_BASE 0x3DC00000 -#define UART3_MEM_BASE 0x3DD00000 -#define CLOCK1_MEM_BASE 0x3E000000 -#define SPI4_MEM_BASE 0x3E100000 +#define INSECURE_RAM_MEM_BASE 0x8000000 +#define SECURE_RAM_MEM_BASE 0xB000000 +#define FRAMEBUFFER_MEM_BASE 0xFB00000 +#define IBOOT_MEM_BASE 0xFF00000 +#define SRAM1_MEM_BASE 0x22020000 +#define SHA1_MEM_BASE 0x38000000 +#define DMAC0_MEM_BASE 0x38200000 +#define USBOTG_MEM_BASE 0x38400000 +#define DISPLAY_MEM_BASE 0x38900000 +#define FMSS_MEM_BASE 0x38A00000 +#define AES_MEM_BASE 0x38C00000 +#define VIC0_MEM_BASE 0x38E00000 +#define VIC1_MEM_BASE 0x38E01000 +#define TVOUT_MEM_BASE 0x39300000 +#define SYSIC_MEM_BASE 0x39700000 +#define DMAC1_MEM_BASE 0x39900000 +#define SPI0_MEM_BASE 0x3C300000 +#define USBPHYS_MEM_BASE 0x3C400000 +#define CLOCK0_MEM_BASE 0x3C500000 +#define I2C0_MEM_BASE 0x3C600000 +#define TIMER1_MEM_BASE 0x3C700000 +#define I2C1_MEM_BASE 0x3C900000 +#define UART0_MEM_BASE 0x3CC00000 +#define SPI1_MEM_BASE 0x3CE00000 +#define GPIO_MEM_BASE 0x3CF00000 +#define PKE_MEM_BASE 0x3D000000 +#define CHIPID_MEM_BASE 0x3D100000 +#define SPI2_MEM_BASE 0x3D200000 +#define UNKNOWN1_MEM_BASE 0x3D700000 +#define MIPI_DSI_MEM_BASE 0x3D800000 +#define SPI3_MEM_BASE 0x3DA00000 +#define UART1_MEM_BASE 0x3DB00000 +#define UART2_MEM_BASE 0x3DC00000 +#define UART3_MEM_BASE 0x3DD00000 +#define CLOCK1_MEM_BASE 0x3E000000 +#define SPI4_MEM_BASE 0x3E100000 typedef struct { MachineClass parent; @@ -110,6 +114,7 @@ typedef struct { IPodTouchI2CState *i2c1_state; IPodTouchLCDState *lcd_state; IPodTouchMIPIDSIState *mipi_dsi_state; + IPodTouchFMSSState *fmss_state; Clock *sysclk; char nor_path[1024]; IT2G_CPREG_VAR_DEF(REG0); diff --git a/include/hw/arm/ipod_touch_fmss.h b/include/hw/arm/ipod_touch_fmss.h new file mode 100644 index 000000000000..55e7c551ff78 --- /dev/null +++ b/include/hw/arm/ipod_touch_fmss.h @@ -0,0 +1,25 @@ +#ifndef IPOD_TOUCH_FMSS_H +#define IPOD_TOUCH_FMSS_H + +#include +#include "qemu/osdep.h" +#include "qemu/module.h" +#include "qemu/timer.h" +#include "hw/sysbus.h" +#include "hw/irq.h" + +#define TYPE_IPOD_TOUCH_FMSS "ipodtouch.fmss" +OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchFMSSState, IPOD_TOUCH_FMSS) + +#define FMSS__FMCTRL1 0x4 +#define FMSS__CS_IRQ 0xC0C +#define FMSS__CS_BUF_RST_OK 0xC64 + +typedef struct IPodTouchFMSSState +{ + SysBusDevice parent_obj; + MemoryRegion iomem; + qemu_irq irq; +} IPodTouchFMSSState; + +#endif \ No newline at end of file diff --git a/include/hw/arm/ipod_touch_mipi_dsi.h b/include/hw/arm/ipod_touch_mipi_dsi.h index 080eb9a5b943..be6d6c6ffbbe 100644 --- a/include/hw/arm/ipod_touch_mipi_dsi.h +++ b/include/hw/arm/ipod_touch_mipi_dsi.h @@ -11,6 +11,11 @@ #define TYPE_IPOD_TOUCH_MIPI_DSI "ipodtouch.mipidsi" OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchMIPIDSIState, IPOD_TOUCH_MIPI_DSI) +#define REG_FIFOCTRL 0x44 + +#define rDSIM_FIFOCTRL_EmptyHSfr 0x400000 +#define rDSIM_STATUS_TxReadyHsClk 0x400 + typedef struct IPodTouchMIPIDSIState { SysBusDevice parent_obj; From 999255e50832e6cf8e3db10922fa872586886ca1 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Sun, 12 Feb 2023 09:14:08 +0100 Subject: [PATCH 16/58] Got some of the NAND initializations working --- hw/arm/ipod_touch_fmss.c | 23 ++++++++++++++++++++++- include/hw/arm/ipod_touch_fmss.h | 4 ++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/hw/arm/ipod_touch_fmss.c b/hw/arm/ipod_touch_fmss.c index 8fb1c1517b3c..6dfc2d1c6a68 100644 --- a/hw/arm/ipod_touch_fmss.c +++ b/hw/arm/ipod_touch_fmss.c @@ -1,5 +1,11 @@ #include "hw/arm/ipod_touch_fmss.h" +static void write_chip_info(IPodTouchFMSSState *s) +{ + uint32_t chipid[] = { 0xb614d5ad, 0xb614d5ad, 0xb614d5ad, 0xb614d5ad }; + cpu_physical_memory_write(s->reg_target_addr, &chipid, 0x10); +} + static uint64_t ipod_touch_fmss_read(void *opaque, hwaddr addr, unsigned size) { //fprintf(stderr, "%s: read from location 0x%08x\n", __func__, addr); @@ -10,7 +16,7 @@ static uint64_t ipod_touch_fmss_read(void *opaque, hwaddr addr, unsigned size) case FMSS__CS_BUF_RST_OK: return 0x1; case FMSS__CS_IRQ: - return 0x0; + return s->reg_cs_irq_bit; case FMSS__FMCTRL1: return (0x1 << 30); default: @@ -24,6 +30,21 @@ static void ipod_touch_fmss_write(void *opaque, hwaddr addr, uint64_t val, unsig { IPodTouchFMSSState *s = (IPodTouchFMSSState *)opaque; fprintf(stderr, "%s: writing 0x%08x to 0x%08x\n", __func__, val, addr); + + switch(addr) { + case 0xC00: + if(val == 0x0000ffb5) { s->reg_cs_irq_bit = 1; } // TODO ugly and hard-coded + break; + case FMSS__CS_IRQ: + if(val == 0xD) { s->reg_cs_irq_bit = 0; } // clear interrupt bit + break; + case FMSS_TARGET_ADDR: + s->reg_target_addr = val; + break; + case FMSS_CMD: // I assume this is a CMD register?? + if(val == 0x8) { write_chip_info(s); } + break; + } } static const MemoryRegionOps fmss_ops = { diff --git a/include/hw/arm/ipod_touch_fmss.h b/include/hw/arm/ipod_touch_fmss.h index 55e7c551ff78..000938371102 100644 --- a/include/hw/arm/ipod_touch_fmss.h +++ b/include/hw/arm/ipod_touch_fmss.h @@ -14,12 +14,16 @@ OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchFMSSState, IPOD_TOUCH_FMSS) #define FMSS__FMCTRL1 0x4 #define FMSS__CS_IRQ 0xC0C #define FMSS__CS_BUF_RST_OK 0xC64 +#define FMSS_TARGET_ADDR 0xD08 +#define FMSS_CMD 0xD0C typedef struct IPodTouchFMSSState { SysBusDevice parent_obj; MemoryRegion iomem; qemu_irq irq; + uint32_t reg_cs_irq_bit; + uint32_t reg_target_addr; } IPodTouchFMSSState; #endif \ No newline at end of file From fa67c82cabe6f48080f026b0004cf3bc6acc90b9 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Sun, 12 Feb 2023 17:56:47 +0100 Subject: [PATCH 17/58] Got the NAND working a bit more --- hw/arm/ipod_touch_fmss.c | 61 +++++++++++++++++++++++++++++--- include/hw/arm/ipod_touch_fmss.h | 19 ++++++---- 2 files changed, 69 insertions(+), 11 deletions(-) diff --git a/hw/arm/ipod_touch_fmss.c b/hw/arm/ipod_touch_fmss.c index 6dfc2d1c6a68..cc9a40932cd3 100644 --- a/hw/arm/ipod_touch_fmss.c +++ b/hw/arm/ipod_touch_fmss.c @@ -3,7 +3,46 @@ static void write_chip_info(IPodTouchFMSSState *s) { uint32_t chipid[] = { 0xb614d5ad, 0xb614d5ad, 0xb614d5ad, 0xb614d5ad }; - cpu_physical_memory_write(s->reg_target_addr, &chipid, 0x10); + cpu_physical_memory_write(s->reg_cinfo_target_addr, &chipid, 0x10); +} + +static void read_nand_pages(IPodTouchFMSSState *s) +{ + for(int page_ind = 0; page_ind < s->reg_num_pages; page_ind++) { + uint32_t page_nr = 0; + uint32_t page_out_addr = 0; + uint32_t page_spare_out_addr = 0; + cpu_physical_memory_read(s->reg_pages_in_addr + page_ind, &page_nr, 0x4); + cpu_physical_memory_read(s->reg_pages_out_addr + page_ind, &page_out_addr, 0x4); + if(page_nr == 524160) { + // NAND signature page + uint8_t *page = calloc(0x100, sizeof(uint8_t)); + char *magic = "NANDDRIVERSIGN"; + memcpy(page, magic, strlen(magic)); + page[0x34] = 0x4; // length of the info + + // signature (0x43313131) + page[0x38] = 0x31; + page[0x39] = 0x31; + page[0x3A] = 0x31; + page[0x3B] = 0x43; + printf("Will read page %d into address 0x%08x\n", page_nr, page_out_addr); + cpu_physical_memory_write(page_out_addr, page, 0x100); + } + else if(page_nr == 524161) { + // BBT page + uint8_t *page = calloc(0x100, sizeof(uint8_t)); + char *magic = "DEVICEINFOBBT"; + memcpy(page, magic, strlen(magic)); + cpu_physical_memory_write(page_out_addr, page, 0x100); + } + + // write the spare + printf("Writing spare to 0x%08x\n", s->reg_page_spare_out_addr); + uint8_t *spare = calloc(0x10, sizeof(uint8_t)); + spare[9] = 0x80; + cpu_physical_memory_write(s->reg_page_spare_out_addr, spare, 0x10); + } } static uint64_t ipod_touch_fmss_read(void *opaque, hwaddr addr, unsigned size) @@ -38,12 +77,24 @@ static void ipod_touch_fmss_write(void *opaque, hwaddr addr, uint64_t val, unsig case FMSS__CS_IRQ: if(val == 0xD) { s->reg_cs_irq_bit = 0; } // clear interrupt bit break; - case FMSS_TARGET_ADDR: - s->reg_target_addr = val; + case FMSS_CINFO_TARGET_ADDR: + s->reg_cinfo_target_addr = val; + write_chip_info(s); + break; + case FMSS_PAGES_IN_ADDR: + s->reg_pages_in_addr = val; + break; + case FMSS_NUM_PAGES: + s->reg_num_pages = val; + break; + case FMSS_PAGE_SPARE_OUT_ADDR: + s->reg_page_spare_out_addr = val; break; - case FMSS_CMD: // I assume this is a CMD register?? - if(val == 0x8) { write_chip_info(s); } + case FMSS_PAGES_OUT_ADDR: + s->reg_pages_out_addr = val; break; + case 0xD38: + read_nand_pages(s); } } diff --git a/include/hw/arm/ipod_touch_fmss.h b/include/hw/arm/ipod_touch_fmss.h index 000938371102..6c8983bece46 100644 --- a/include/hw/arm/ipod_touch_fmss.h +++ b/include/hw/arm/ipod_touch_fmss.h @@ -11,11 +11,14 @@ #define TYPE_IPOD_TOUCH_FMSS "ipodtouch.fmss" OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchFMSSState, IPOD_TOUCH_FMSS) -#define FMSS__FMCTRL1 0x4 -#define FMSS__CS_IRQ 0xC0C -#define FMSS__CS_BUF_RST_OK 0xC64 -#define FMSS_TARGET_ADDR 0xD08 -#define FMSS_CMD 0xD0C +#define FMSS__FMCTRL1 0x4 +#define FMSS__CS_IRQ 0xC0C +#define FMSS__CS_BUF_RST_OK 0xC64 +#define FMSS_CINFO_TARGET_ADDR 0xD08 +#define FMSS_PAGES_IN_ADDR 0xD0C +#define FMSS_NUM_PAGES 0xD18 +#define FMSS_PAGE_SPARE_OUT_ADDR 0xD1C +#define FMSS_PAGES_OUT_ADDR 0xD20 typedef struct IPodTouchFMSSState { @@ -23,7 +26,11 @@ typedef struct IPodTouchFMSSState MemoryRegion iomem; qemu_irq irq; uint32_t reg_cs_irq_bit; - uint32_t reg_target_addr; + uint32_t reg_cinfo_target_addr; + uint32_t reg_pages_in_addr; + uint32_t reg_num_pages; + uint32_t reg_page_spare_out_addr; + uint32_t reg_pages_out_addr; } IPodTouchFMSSState; #endif \ No newline at end of file From 4ba00929a055500e6cb39c045e1acfe31197a570 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Mon, 12 Jun 2023 20:18:52 +0200 Subject: [PATCH 18/58] Implemented missing registers --- hw/arm/ipod_touch_2g.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/arm/ipod_touch_2g.c b/hw/arm/ipod_touch_2g.c index de2ec311b9f8..dafe8aa2e2a1 100644 --- a/hw/arm/ipod_touch_2g.c +++ b/hw/arm/ipod_touch_2g.c @@ -36,6 +36,8 @@ static void allocate_ram(MemoryRegion *top, const char *name, uint32_t addr, uin static const ARMCPRegInfo it2g_cp_reginfo_tcg[] = { IT2G_CPREG_DEF(REG0, 0, 0, 7, 6, 0, PL1_RW, 0), IT2G_CPREG_DEF(REG1, 0, 0, 15, 2, 4, PL1_RW, 0), + IT2G_CPREG_DEF(REG1, 0, 0, 7, 14, 0, PL1_RW, 0), + IT2G_CPREG_DEF(REG1, 0, 0, 7, 10, 0, PL1_RW, 0), }; static void ipod_touch_cpu_setup(MachineState *machine, MemoryRegion **sysmem, ARMCPU **cpu, AddressSpace **nsas) From 1f85f989cb3558b7a1274f9de0c910c8b9fbaf5a Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Sun, 18 Jun 2023 15:16:02 +0200 Subject: [PATCH 19/58] Circumventing NAND --- hw/arm/ipod_touch_2g.c | 6 ++ hw/arm/ipod_touch_aes.c | 9 +- hw/arm/ipod_touch_block_device.c | 108 +++++++++++++++++++++++ hw/arm/ipod_touch_fmss.c | 66 ++++++++------ hw/arm/meson.build | 2 +- include/hw/arm/ipod_touch_2g.h | 3 + include/hw/arm/ipod_touch_block_device.h | 26 ++++++ include/hw/arm/ipod_touch_fmss.h | 8 ++ include/hw/arm/ipod_touch_sha1.h | 2 +- 9 files changed, 201 insertions(+), 29 deletions(-) create mode 100644 hw/arm/ipod_touch_block_device.c create mode 100644 include/hw/arm/ipod_touch_block_device.h diff --git a/hw/arm/ipod_touch_2g.c b/hw/arm/ipod_touch_2g.c index dafe8aa2e2a1..86f9e8aa8979 100644 --- a/hw/arm/ipod_touch_2g.c +++ b/hw/arm/ipod_touch_2g.c @@ -349,6 +349,12 @@ static void ipod_touch_machine_init(MachineState *machine) nms->pke_state = pke_state; memory_region_add_subregion(sysmem, PKE_MEM_BASE, &pke_state->iomem); + // init block device engine + dev = qdev_new("ipodtouch.blockdevice"); + IPodTouchBlockDeviceState *bdev_state = IPOD_TOUCH_BLOCK_DEVICE(dev); + nms->bdev_state = bdev_state; + memory_region_add_subregion(sysmem, BLOCK_DEVICE_MEM_BASE, &bdev_state->iomem); + qemu_register_reset(ipod_touch_cpu_reset, nms); } diff --git a/hw/arm/ipod_touch_aes.c b/hw/arm/ipod_touch_aes.c index 478e33465759..808fa839c954 100644 --- a/hw/arm/ipod_touch_aes.c +++ b/hw/arm/ipod_touch_aes.c @@ -41,7 +41,7 @@ static void ipod_touch_aes_write(void *opaque, hwaddr offset, uint64_t value, un } buf = (uint8_t *) malloc(aesop->insize); - //printf("In size: %d, out size: %d, in addr: 0x%08x, in buf: 0x%08x, out addr: 0x%08x\n", aesop->insize, aesop->outsize, aesop->inaddr, ((uint32_t *)inbuf)[0], aesop->outaddr); + printf("In size: %d, out size: %d, in addr: 0x%08x, in buf: 0x%08x, out addr: 0x%08x\n", aesop->insize, aesop->outsize, aesop->inaddr, ((uint32_t *)inbuf)[0], aesop->outaddr); if(aesop->keytype == AESGID) { // Unfortunately, we don't have access to the GID key. @@ -62,6 +62,13 @@ static void ipod_touch_aes_write(void *opaque, hwaddr offset, uint64_t value, un }; for(int i = 0; i < aesop->insize; i++) { buf[i] = key[i]; } } + else if(aesop->gid_encryption_count == 2) { // kernelcache + char key[] = { + 0xa1, 0x91, 0x29, 0x12, 0x90, 0xd4, 0x87, 0xff, 0x07, 0x31, 0x96, 0x9c, 0x5f, 0xc8, 0xd9, 0x18, // IV + 0x0e, 0x4d, 0x23, 0xfa, 0x67, 0x59, 0x99, 0xd5, 0x95, 0x9d, 0xd1, 0x0c, 0x8d, 0xd7, 0x3d, 0x20, // key + }; + for(int i = 0; i < aesop->insize; i++) { buf[i] = key[i]; } + } aesop->gid_encryption_count++; } diff --git a/hw/arm/ipod_touch_block_device.c b/hw/arm/ipod_touch_block_device.c new file mode 100644 index 000000000000..2173ac09ac7c --- /dev/null +++ b/hw/arm/ipod_touch_block_device.c @@ -0,0 +1,108 @@ +#include "hw/arm/ipod_touch_block_device.h" +#include "hw/hw.h" + +static uint64_t ipod_touch_block_device_read(void *opaque, hwaddr addr, unsigned size) +{ + fprintf(stderr, "%s: read from location 0x%08x\n", __func__, addr); + + IPodTouchBlockDeviceState *s = (IPodTouchBlockDeviceState *)opaque; + switch(addr) + { + default: + // hw_error("%s: read invalid location 0x%08x.\n", __func__, addr); + break; + } + return 0; +} + +static void ipod_touch_block_device_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) +{ + IPodTouchBlockDeviceState *s = (IPodTouchBlockDeviceState *)opaque; + fprintf(stderr, "%s: writing 0x%08x to 0x%08x\n", __func__, val, addr); + + switch(addr) + { + case 0x0: + s->block_num_reg = val; + break; + case 0x4: + s->num_blocks_reg = val; + break; + case 0x8: + s->out_addr_reg = val; + break; + default: + // hw_error("%s: read invalid location 0x%08x.\n", __func__, addr); + break; + } + + if(addr == 0x8) { + // load the block + printf("Will load block %d (count: %d) into address 0x%08x\n", s->block_num_reg, s->num_blocks_reg, s->out_addr_reg); + + for(int block_nr = 0; block_nr < s->num_blocks_reg; block_nr++) { + char filename[200]; + int block_to_read = s->block_num_reg + block_nr; + sprintf(filename, "/Users/martijndevos/Documents/generate_nand_it2g/blocks/%d.blk", block_to_read); + struct stat st = {0}; + if (stat(filename, &st) == -1) { + printf("Will preparing empty block %d", block_to_read); + // page storage does not exist - initialize an empty buffer + memset(s->block_buffer, 0, BYTES_PER_BLOCK); + } + else { + FILE *f = fopen(filename, "rb"); + if (f == NULL) { hw_error("Unable to read file!"); } + fread(s->block_buffer, sizeof(char), BYTES_PER_BLOCK, f); + fclose(f); + } + + cpu_physical_memory_write(s->out_addr_reg + block_nr * BYTES_PER_BLOCK, s->block_buffer, BYTES_PER_BLOCK); + } + } +} + +static const MemoryRegionOps block_device_ops = { + .read = ipod_touch_block_device_read, + .write = ipod_touch_block_device_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void ipod_touch_block_device_realize(DeviceState *dev, Error **errp) +{ + +} + +static void ipod_touch_block_device_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DeviceState *dev = DEVICE(sbd); + IPodTouchBlockDeviceState *s = IPOD_TOUCH_BLOCK_DEVICE(dev); + + memory_region_init_io(&s->iomem, obj, &block_device_ops, s, "block_device", 0x100); + sysbus_init_mmio(sbd, &s->iomem); + + s->block_buffer = (uint8_t *)malloc(BYTES_PER_BLOCK); +} + +static void ipod_touch_block_device_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = ipod_touch_block_device_realize; +} + +static const TypeInfo ipod_touch_block_device_info = { + .name = TYPE_IPOD_TOUCH_BLOCK_DEVICE, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IPodTouchBlockDeviceState), + .instance_init = ipod_touch_block_device_init, + .class_init = ipod_touch_block_device_class_init, +}; + +static void ipod_touch_machine_types(void) +{ + type_register_static(&ipod_touch_block_device_info); +} + +type_init(ipod_touch_machine_types) \ No newline at end of file diff --git a/hw/arm/ipod_touch_fmss.c b/hw/arm/ipod_touch_fmss.c index cc9a40932cd3..ad6a58a981b4 100644 --- a/hw/arm/ipod_touch_fmss.c +++ b/hw/arm/ipod_touch_fmss.c @@ -8,40 +8,51 @@ static void write_chip_info(IPodTouchFMSSState *s) static void read_nand_pages(IPodTouchFMSSState *s) { + // patch the FTL_Read method + uint16_t *data = malloc(sizeof(uint16_t) * 9); + data[0] = 0xB500; // push {lr} + data[1] = 0x4B14; // ldr r3, [pc, #0x50] + data[2] = 0x6018; // str r0, [r3] + data[3] = 0x3304; // adds r3, #4 + data[4] = 0x6019; // str r1, [r3] + data[5] = 0x3304; // adds r3, #4 + data[6] = 0x601A; // str r1, [r3] -> this will trigger the block loading + data[7] = 0x2000; // movs r0, #0 + data[8] = 0xBD00; // pop {pc} + cpu_physical_memory_write(0x0ff02d1c, (uint8_t *)data, 18); + + uint32_t *data2 = malloc(sizeof(uint32_t) * 1); + data2[0] = 0x39400000; + cpu_physical_memory_write(0x0ff02d1c + 0x54, (uint8_t *)data2, 4); + for(int page_ind = 0; page_ind < s->reg_num_pages; page_ind++) { uint32_t page_nr = 0; uint32_t page_out_addr = 0; - uint32_t page_spare_out_addr = 0; cpu_physical_memory_read(s->reg_pages_in_addr + page_ind, &page_nr, 0x4); cpu_physical_memory_read(s->reg_pages_out_addr + page_ind, &page_out_addr, 0x4); - if(page_nr == 524160) { - // NAND signature page - uint8_t *page = calloc(0x100, sizeof(uint8_t)); - char *magic = "NANDDRIVERSIGN"; - memcpy(page, magic, strlen(magic)); - page[0x34] = 0x4; // length of the info - - // signature (0x43313131) - page[0x38] = 0x31; - page[0x39] = 0x31; - page[0x3A] = 0x31; - page[0x3B] = 0x43; - printf("Will read page %d into address 0x%08x\n", page_nr, page_out_addr); - cpu_physical_memory_write(page_out_addr, page, 0x100); + + printf("Will read page %d into address 0x%08x and spare into address 0x%08x\n", page_nr, page_out_addr, s->reg_page_spare_out_addr); + + // prepare the page + char filename[200]; + sprintf(filename, "/Users/martijndevos/Documents/generate_nand_it2g/nand/%d.page", page_nr); + struct stat st = {0}; + if (stat(filename, &st) == -1) { + printf("Will preparing empty page %d", page_nr); + // page storage does not exist - initialize an empty buffer + memset(s->page_buffer, 0, NAND_BYTES_PER_PAGE); + memset(s->page_spare_buffer, 0, NAND_BYTES_PER_SPARE); } - else if(page_nr == 524161) { - // BBT page - uint8_t *page = calloc(0x100, sizeof(uint8_t)); - char *magic = "DEVICEINFOBBT"; - memcpy(page, magic, strlen(magic)); - cpu_physical_memory_write(page_out_addr, page, 0x100); + else { + FILE *f = fopen(filename, "rb"); + if (f == NULL) { hw_error("Unable to read file!"); } + fread(s->page_buffer, sizeof(char), NAND_BYTES_PER_PAGE, f); + fread(s->page_spare_buffer, sizeof(char), NAND_BYTES_PER_SPARE, f); + fclose(f); } - // write the spare - printf("Writing spare to 0x%08x\n", s->reg_page_spare_out_addr); - uint8_t *spare = calloc(0x10, sizeof(uint8_t)); - spare[9] = 0x80; - cpu_physical_memory_write(s->reg_page_spare_out_addr, spare, 0x10); + cpu_physical_memory_write(page_out_addr, s->page_buffer, NAND_BYTES_PER_PAGE); + cpu_physical_memory_write(s->reg_page_spare_out_addr, s->page_spare_buffer, NAND_BYTES_PER_SPARE); } } @@ -118,6 +129,9 @@ static void ipod_touch_fmss_init(Object *obj) memory_region_init_io(&s->iomem, obj, &fmss_ops, s, "fmss", 0x1000); sysbus_init_mmio(sbd, &s->iomem); sysbus_init_irq(sbd, &s->irq); + + s->page_buffer = (uint8_t *)malloc(NAND_BYTES_PER_PAGE); + s->page_spare_buffer = (uint8_t *)malloc(NAND_BYTES_PER_SPARE); } static void ipod_touch_fmss_class_init(ObjectClass *klass, void *data) diff --git a/hw/arm/meson.build b/hw/arm/meson.build index 50723674dd66..f8c4ae134e9e 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -62,6 +62,6 @@ arm_ss.add(when: 'CONFIG_FSL_IMX7', if_true: files('fsl-imx7.c', 'mcimx7d-sabre. arm_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c', 'smmuv3.c')) arm_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c')) arm_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c')) -arm_ss.add(when: 'CONFIG_IPOD_TOUCH_2G', if_true: files('ipod_touch_2g.c', 'ipod_touch_clock.c', 'ipod_touch_chipid.c', 'ipod_touch_gpio.c', 'ipod_touch_sysic.c', 'ipod_touch_timer.c', 'ipod_touch_usb_otg.c', 'ipod_touch_usb_phys.c', 'ipod_touch_spi.c', 'ipod_touch_nor_spi.c', 'ipod_touch_sha1.c', 'ipod_touch_aes.c', 'ipod_touch_pke.c', 'ipod_touch_pcf50633_pmu.c', 'ipod_touch_unknown1.c', 'ipod_touch_lcd.c', 'ipod_touch_mipi_dsi.c', 'ipod_touch_fmss.c')) +arm_ss.add(when: 'CONFIG_IPOD_TOUCH_2G', if_true: files('ipod_touch_2g.c', 'ipod_touch_clock.c', 'ipod_touch_chipid.c', 'ipod_touch_gpio.c', 'ipod_touch_sysic.c', 'ipod_touch_timer.c', 'ipod_touch_usb_otg.c', 'ipod_touch_usb_phys.c', 'ipod_touch_spi.c', 'ipod_touch_nor_spi.c', 'ipod_touch_sha1.c', 'ipod_touch_aes.c', 'ipod_touch_pke.c', 'ipod_touch_pcf50633_pmu.c', 'ipod_touch_unknown1.c', 'ipod_touch_lcd.c', 'ipod_touch_mipi_dsi.c', 'ipod_touch_fmss.c', 'ipod_touch_block_device.c')) hw_arch += {'arm': arm_ss} diff --git a/include/hw/arm/ipod_touch_2g.h b/include/hw/arm/ipod_touch_2g.h index c5f33eeecca7..24e49408abf7 100644 --- a/include/hw/arm/ipod_touch_2g.h +++ b/include/hw/arm/ipod_touch_2g.h @@ -23,6 +23,7 @@ #include "hw/arm/ipod_touch_lcd.h" #include "hw/arm/ipod_touch_mipi_dsi.h" #include "hw/arm/ipod_touch_fmss.h" +#include "hw/arm/ipod_touch_block_device.h" #define TYPE_IPOD_TOUCH "iPod-Touch" @@ -65,6 +66,7 @@ #define VIC0_MEM_BASE 0x38E00000 #define VIC1_MEM_BASE 0x38E01000 #define TVOUT_MEM_BASE 0x39300000 +#define BLOCK_DEVICE_MEM_BASE 0x39400000 #define SYSIC_MEM_BASE 0x39700000 #define DMAC1_MEM_BASE 0x39900000 #define SPI0_MEM_BASE 0x3C300000 @@ -115,6 +117,7 @@ typedef struct { IPodTouchLCDState *lcd_state; IPodTouchMIPIDSIState *mipi_dsi_state; IPodTouchFMSSState *fmss_state; + IPodTouchBlockDeviceState *bdev_state; Clock *sysclk; char nor_path[1024]; IT2G_CPREG_VAR_DEF(REG0); diff --git a/include/hw/arm/ipod_touch_block_device.h b/include/hw/arm/ipod_touch_block_device.h new file mode 100644 index 000000000000..55bcf0a049f3 --- /dev/null +++ b/include/hw/arm/ipod_touch_block_device.h @@ -0,0 +1,26 @@ +#ifndef IPOD_TOUCH_BLOCK_DEVICE_H +#define IPOD_TOUCH_BLOCK_DEVICE_H + +#include +#include "qemu/osdep.h" +#include "qemu/module.h" +#include "qemu/timer.h" +#include "hw/sysbus.h" + +#define TYPE_IPOD_TOUCH_BLOCK_DEVICE "ipodtouch.blockdevice" +OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchBlockDeviceState, IPOD_TOUCH_BLOCK_DEVICE) + +#define BYTES_PER_BLOCK 4096 + +typedef struct IPodTouchBlockDeviceState +{ + SysBusDevice parent_obj; + MemoryRegion iomem; + uint32_t block_num_reg; + uint32_t num_blocks_reg; + uint32_t out_addr_reg; + + uint8_t *block_buffer; +} IPodTouchBlockDeviceState; + +#endif \ No newline at end of file diff --git a/include/hw/arm/ipod_touch_fmss.h b/include/hw/arm/ipod_touch_fmss.h index 6c8983bece46..fc78b33f64e2 100644 --- a/include/hw/arm/ipod_touch_fmss.h +++ b/include/hw/arm/ipod_touch_fmss.h @@ -6,11 +6,15 @@ #include "qemu/module.h" #include "qemu/timer.h" #include "hw/sysbus.h" +#include "hw/hw.h" #include "hw/irq.h" #define TYPE_IPOD_TOUCH_FMSS "ipodtouch.fmss" OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchFMSSState, IPOD_TOUCH_FMSS) +#define NAND_BYTES_PER_PAGE 2048 +#define NAND_BYTES_PER_SPARE 64 + #define FMSS__FMCTRL1 0x4 #define FMSS__CS_IRQ 0xC0C #define FMSS__CS_BUF_RST_OK 0xC64 @@ -25,6 +29,10 @@ typedef struct IPodTouchFMSSState SysBusDevice parent_obj; MemoryRegion iomem; qemu_irq irq; + + uint8_t *page_buffer; + uint8_t *page_spare_buffer; + uint32_t reg_cs_irq_bit; uint32_t reg_cinfo_target_addr; uint32_t reg_pages_in_addr; diff --git a/include/hw/arm/ipod_touch_sha1.h b/include/hw/arm/ipod_touch_sha1.h index 1721e6beb3a8..3aa8d89d26c5 100644 --- a/include/hw/arm/ipod_touch_sha1.h +++ b/include/hw/arm/ipod_touch_sha1.h @@ -11,7 +11,7 @@ #define TYPE_IPOD_TOUCH_SHA1 "ipodtouch.sha1" OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchSHA1State, IPOD_TOUCH_SHA1) -#define SHA1_BUFFER_SIZE 1024 * 1024 +#define SHA1_BUFFER_SIZE 1024 * 1024 * 5 #define SHA_CONFIG 0x0 #define SHA_RESET 0x4 From ac405b5f410ace6ff60d2b0e9907687e4f67adcf Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Sat, 1 Jul 2023 20:45:49 +0200 Subject: [PATCH 20/58] Able to load kernel, with some hacks! --- hw/arm/ipod_touch_aes.c | 21 ++++++++++++++++++--- hw/arm/ipod_touch_fmss.c | 4 ++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/hw/arm/ipod_touch_aes.c b/hw/arm/ipod_touch_aes.c index 808fa839c954..eef01cbed5c3 100644 --- a/hw/arm/ipod_touch_aes.c +++ b/hw/arm/ipod_touch_aes.c @@ -41,7 +41,7 @@ static void ipod_touch_aes_write(void *opaque, hwaddr offset, uint64_t value, un } buf = (uint8_t *) malloc(aesop->insize); - printf("In size: %d, out size: %d, in addr: 0x%08x, in buf: 0x%08x, out addr: 0x%08x\n", aesop->insize, aesop->outsize, aesop->inaddr, ((uint32_t *)inbuf)[0], aesop->outaddr); + printf("In size: %d, out size: %d, in addr: 0x%08x, in buf: 0x%08x, out addr: 0x%08x, %d\n", aesop->insize, aesop->outsize, aesop->inaddr, ((uint32_t *)inbuf)[0], aesop->outaddr, aesop->gid_encryption_count); if(aesop->keytype == AESGID) { // Unfortunately, we don't have access to the GID key. @@ -69,6 +69,13 @@ static void ipod_touch_aes_write(void *opaque, hwaddr offset, uint64_t value, un }; for(int i = 0; i < aesop->insize; i++) { buf[i] = key[i]; } } + else if(aesop->gid_encryption_count == 3) { // device tree + char key[] = { + 0xcc, 0xff, 0x63, 0x4e, 0xe1, 0x27, 0x35, 0xf0, 0x19, 0x16, 0xc4, 0xa6, 0xb2, 0x0f, 0xf1, 0x45, // IV + 0xe1, 0x7b, 0xcd, 0x56, 0x8d, 0xf1, 0xcd, 0xdc, 0x8f, 0xec, 0xbf, 0x54, 0x87, 0xd5, 0xc3, 0xce, // key + }; + for(int i = 0; i < aesop->insize; i++) { buf[i] = key[i]; } + } aesop->gid_encryption_count++; } @@ -76,10 +83,18 @@ static void ipod_touch_aes_write(void *opaque, hwaddr offset, uint64_t value, un AES_cbc_encrypt(inbuf, buf, aesop->insize, &aesop->decryptKey, (uint8_t *)aesop->ivec, AES_DECRYPT); } - if(aesop->outaddr != 0x220100ac) { // TODO very ugly hack - for the RSA key decryption, it seems that doing nothing results in the correct decryption key?? + if(aesop->outaddr != 0x220100ac && aesop->outaddr != 0x0bf08468) { // TODO very ugly hack - for the RSA key decryption, it seems that doing nothing results in the correct decryption key?? + // BUG: after decrypting the kernel, we update the Adler CRC code and number of expected bytes. + if(aesop->outaddr == 0x0b000020) { + printf("Adjusting sizes for the kernel...\n"); + uint32_t *cast_buf = (uint32_t *)buf; + cast_buf[2] = 0xA7886041; // adler + cast_buf[3] = 0xF5D37E00; // 8311797 in big endian + } + cpu_physical_memory_write((aesop->outaddr), buf, aesop->insize); } - + memset(aesop->custkey, 0, 0x20); memset(aesop->ivec, 0, 0x10); free(inbuf); diff --git a/hw/arm/ipod_touch_fmss.c b/hw/arm/ipod_touch_fmss.c index ad6a58a981b4..870e9eb03033 100644 --- a/hw/arm/ipod_touch_fmss.c +++ b/hw/arm/ipod_touch_fmss.c @@ -25,6 +25,10 @@ static void read_nand_pages(IPodTouchFMSSState *s) data2[0] = 0x39400000; cpu_physical_memory_write(0x0ff02d1c + 0x54, (uint8_t *)data2, 4); + // boot args + char *boot_args = "boot-args=debug=0x8 kextlog=0xfff cpus=1 rd=disk0s1 serial=1 io=0xffff8fff"; + cpu_physical_memory_write(0x0ff2a584, boot_args, strlen(boot_args)); + for(int page_ind = 0; page_ind < s->reg_num_pages; page_ind++) { uint32_t page_nr = 0; uint32_t page_out_addr = 0; From f260d8455fdca76aa91702acc096388de848809a Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Sun, 2 Jul 2023 18:19:26 +0200 Subject: [PATCH 21/58] Added workaround for device tree and several memory mappings --- hw/arm/ipod_touch_2g.c | 10 +++++++++- hw/arm/ipod_touch_aes.c | 7 ++++++- hw/arm/ipod_touch_pke.c | 2 +- include/hw/arm/ipod_touch_2g.h | 10 +++++++++- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/hw/arm/ipod_touch_2g.c b/hw/arm/ipod_touch_2g.c index 86f9e8aa8979..2229913b9e73 100644 --- a/hw/arm/ipod_touch_2g.c +++ b/hw/arm/ipod_touch_2g.c @@ -88,8 +88,16 @@ static void ipod_touch_memory_setup(MachineState *machine, MemoryRegion *sysmem, allocate_ram(sysmem, "iboot", IBOOT_MEM_BASE, 0x100000); allocate_ram(sysmem, "llb", 0x22000000, 0x100000); allocate_ram(sysmem, "sram1", SRAM1_MEM_BASE, 0x100000); - allocate_ram(sysmem, "tvout", TVOUT_MEM_BASE, 0x1000); + allocate_ram(sysmem, "mbx1", MBX1_MEM_BASE, 0x1000000); + allocate_ram(sysmem, "mbx2", MBX2_MEM_BASE, 0x1000); + allocate_ram(sysmem, "tvout1", TVOUT1_MEM_BASE, 0x1000); + allocate_ram(sysmem, "tvout2", TVOUT2_MEM_BASE, 0x1000); + allocate_ram(sysmem, "tvout3", TVOUT3_MEM_BASE, 0x1000); allocate_ram(sysmem, "framebuffer", FRAMEBUFFER_MEM_BASE, 0x400000); + allocate_ram(sysmem, "edgeic", EDGEIC_MEM_BASE, 0x1000); + allocate_ram(sysmem, "swi", SWI_MEM_BASE, 0x1000); + allocate_ram(sysmem, "sdio", SDIO_MEM_BASE, 0x1000); + allocate_ram(sysmem, "h264", H264_MEM_BASE, 0x4000); // load the bootrom (vrom) uint8_t *file_data = NULL; diff --git a/hw/arm/ipod_touch_aes.c b/hw/arm/ipod_touch_aes.c index eef01cbed5c3..63ae0092fc63 100644 --- a/hw/arm/ipod_touch_aes.c +++ b/hw/arm/ipod_touch_aes.c @@ -86,12 +86,17 @@ static void ipod_touch_aes_write(void *opaque, hwaddr offset, uint64_t value, un if(aesop->outaddr != 0x220100ac && aesop->outaddr != 0x0bf08468) { // TODO very ugly hack - for the RSA key decryption, it seems that doing nothing results in the correct decryption key?? // BUG: after decrypting the kernel, we update the Adler CRC code and number of expected bytes. if(aesop->outaddr == 0x0b000020) { - printf("Adjusting sizes for the kernel...\n"); uint32_t *cast_buf = (uint32_t *)buf; cast_buf[2] = 0xA7886041; // adler cast_buf[3] = 0xF5D37E00; // 8311797 in big endian } + // BUG: after decrypting the device tree, the last few bytes are incorrect + if(aesop->outaddr == 0x0bf00020) { + uint32_t *cast_buf = (uint32_t *)buf; + cast_buf[8429] = 0x4; // setting the size of the AAPL,phandle property to 4 + } + cpu_physical_memory_write((aesop->outaddr), buf, aesop->insize); } diff --git a/hw/arm/ipod_touch_pke.c b/hw/arm/ipod_touch_pke.c index c6a782c01c63..2559c3cd5a60 100644 --- a/hw/arm/ipod_touch_pke.c +++ b/hw/arm/ipod_touch_pke.c @@ -129,7 +129,7 @@ static void ipod_touch_pke_write(void *opaque, hwaddr offset, uint64_t value, un uint32_t size_bit = (s->seg_size_reg >> 6); if(size_bit == 0) { s->segment_size = 256; } else if(size_bit == 1) { s->segment_size = 128; } - else { hw_error("Unsupported segment size bit %d!", size_bit); } + else { } printf("Segment size: %d\n", s->segment_size); break; diff --git a/include/hw/arm/ipod_touch_2g.h b/include/hw/arm/ipod_touch_2g.h index 24e49408abf7..337e16a50c50 100644 --- a/include/hw/arm/ipod_touch_2g.h +++ b/include/hw/arm/ipod_touch_2g.h @@ -63,12 +63,19 @@ #define DISPLAY_MEM_BASE 0x38900000 #define FMSS_MEM_BASE 0x38A00000 #define AES_MEM_BASE 0x38C00000 +#define SDIO_MEM_BASE 0x38D00000 #define VIC0_MEM_BASE 0x38E00000 #define VIC1_MEM_BASE 0x38E01000 -#define TVOUT_MEM_BASE 0x39300000 +#define EDGEIC_MEM_BASE 0x38E02000 +#define H264_MEM_BASE 0x38F00000 +#define TVOUT1_MEM_BASE 0x39100000 +#define TVOUT2_MEM_BASE 0x39200000 +#define TVOUT3_MEM_BASE 0x39300000 #define BLOCK_DEVICE_MEM_BASE 0x39400000 #define SYSIC_MEM_BASE 0x39700000 #define DMAC1_MEM_BASE 0x39900000 +#define MBX1_MEM_BASE 0x3B000000 +#define MBX2_MEM_BASE 0x39400000 #define SPI0_MEM_BASE 0x3C300000 #define USBPHYS_MEM_BASE 0x3C400000 #define CLOCK0_MEM_BASE 0x3C500000 @@ -87,6 +94,7 @@ #define UART1_MEM_BASE 0x3DB00000 #define UART2_MEM_BASE 0x3DC00000 #define UART3_MEM_BASE 0x3DD00000 +#define SWI_MEM_BASE 0x3DE00000 #define CLOCK1_MEM_BASE 0x3E000000 #define SPI4_MEM_BASE 0x3E100000 From 5b185bc4fed1c70565e90f505e4972f58d6e8e05 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Mon, 3 Jul 2023 20:48:22 +0200 Subject: [PATCH 22/58] Got more peripherals up and running! --- hw/arm/ipod_touch_2g.c | 9 ++++- hw/arm/ipod_touch_fmss.c | 12 +++++-- hw/arm/ipod_touch_mbx.c | 59 ++++++++++++++++++++++++++++++++ hw/arm/ipod_touch_nor_spi.c | 4 +++ hw/arm/ipod_touch_usb_phys.c | 3 +- hw/arm/meson.build | 2 +- include/hw/arm/ipod_touch_2g.h | 3 ++ include/hw/arm/ipod_touch_fmss.h | 1 + include/hw/arm/ipod_touch_mbx.h | 16 +++++++++ 9 files changed, 103 insertions(+), 6 deletions(-) create mode 100644 hw/arm/ipod_touch_mbx.c create mode 100644 include/hw/arm/ipod_touch_mbx.h diff --git a/hw/arm/ipod_touch_2g.c b/hw/arm/ipod_touch_2g.c index 2229913b9e73..1c53fb309e04 100644 --- a/hw/arm/ipod_touch_2g.c +++ b/hw/arm/ipod_touch_2g.c @@ -88,7 +88,6 @@ static void ipod_touch_memory_setup(MachineState *machine, MemoryRegion *sysmem, allocate_ram(sysmem, "iboot", IBOOT_MEM_BASE, 0x100000); allocate_ram(sysmem, "llb", 0x22000000, 0x100000); allocate_ram(sysmem, "sram1", SRAM1_MEM_BASE, 0x100000); - allocate_ram(sysmem, "mbx1", MBX1_MEM_BASE, 0x1000000); allocate_ram(sysmem, "mbx2", MBX2_MEM_BASE, 0x1000); allocate_ram(sysmem, "tvout1", TVOUT1_MEM_BASE, 0x1000); allocate_ram(sysmem, "tvout2", TVOUT2_MEM_BASE, 0x1000); @@ -308,6 +307,8 @@ static void ipod_touch_machine_init(MachineState *machine) dev = qdev_new("ipodtouch.fmss"); IPodTouchFMSSState *fmss_state = IPOD_TOUCH_FMSS(dev); nms->fmss_state = fmss_state; + busdev = SYS_BUS_DEVICE(dev); + sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_FMSS_IRQ)); memory_region_add_subregion(sysmem, FMSS_MEM_BASE, &fmss_state->iomem); dev = qdev_new("ipodtouch.i2c"); @@ -363,6 +364,12 @@ static void ipod_touch_machine_init(MachineState *machine) nms->bdev_state = bdev_state; memory_region_add_subregion(sysmem, BLOCK_DEVICE_MEM_BASE, &bdev_state->iomem); + // init the MBX + dev = qdev_new("ipodtouch.mbx"); + IPodTouchMBXState *mbx_state = IPOD_TOUCH_MBX(dev); + nms->mbx_state = mbx_state; + memory_region_add_subregion(sysmem, MBX1_MEM_BASE, &mbx_state->iomem); + qemu_register_reset(ipod_touch_cpu_reset, nms); } diff --git a/hw/arm/ipod_touch_fmss.c b/hw/arm/ipod_touch_fmss.c index 870e9eb03033..ee84bc5c2907 100644 --- a/hw/arm/ipod_touch_fmss.c +++ b/hw/arm/ipod_touch_fmss.c @@ -26,7 +26,7 @@ static void read_nand_pages(IPodTouchFMSSState *s) cpu_physical_memory_write(0x0ff02d1c + 0x54, (uint8_t *)data2, 4); // boot args - char *boot_args = "boot-args=debug=0x8 kextlog=0xfff cpus=1 rd=disk0s1 serial=1 io=0xffff8fff"; + char *boot_args = "kextlog=0xfff debug=0x8 cpus=1 rd=disk0s1 serial=1 io=0xffff8fff"; cpu_physical_memory_write(0x0ff2a584, boot_args, strlen(boot_args)); for(int page_ind = 0; page_ind < s->reg_num_pages; page_ind++) { @@ -62,7 +62,7 @@ static void read_nand_pages(IPodTouchFMSSState *s) static uint64_t ipod_touch_fmss_read(void *opaque, hwaddr addr, unsigned size) { - //fprintf(stderr, "%s: read from location 0x%08x\n", __func__, addr); + fprintf(stderr, "%s: read from location 0x%08x\n", __func__, addr); IPodTouchFMSSState *s = (IPodTouchFMSSState *)opaque; switch(addr) @@ -71,8 +71,12 @@ static uint64_t ipod_touch_fmss_read(void *opaque, hwaddr addr, unsigned size) return 0x1; case FMSS__CS_IRQ: return s->reg_cs_irq_bit; + case FMSS__CS_IRQMASK: + return 0x1; case FMSS__FMCTRL1: return (0x1 << 30); + case 0xD00: + return 42; default: // hw_error("%s: read invalid location 0x%08x.\n", __func__, addr); break; @@ -88,9 +92,11 @@ static void ipod_touch_fmss_write(void *opaque, hwaddr addr, uint64_t val, unsig switch(addr) { case 0xC00: if(val == 0x0000ffb5) { s->reg_cs_irq_bit = 1; } // TODO ugly and hard-coded + if(val == 0xfff5) { s->reg_cs_irq_bit = 1; qemu_set_irq(s->irq, 1); } break; case FMSS__CS_IRQ: - if(val == 0xD) { s->reg_cs_irq_bit = 0; } // clear interrupt bit + s->reg_cs_irq_bit = 0; + qemu_set_irq(s->irq, 0); break; case FMSS_CINFO_TARGET_ADDR: s->reg_cinfo_target_addr = val; diff --git a/hw/arm/ipod_touch_mbx.c b/hw/arm/ipod_touch_mbx.c new file mode 100644 index 000000000000..b9891e4914e0 --- /dev/null +++ b/hw/arm/ipod_touch_mbx.c @@ -0,0 +1,59 @@ +#include "hw/arm/ipod_touch_mbx.h" + +static uint64_t ipod_touch_mbx_read(void *opaque, hwaddr addr, unsigned size) +{ + printf("%s: read from location 0x%08x\n", __func__, addr); + switch(addr) + { + case 0x12c: + return 0x40; + case 0xf00: + return (2 << 0x10) | (1 << 0x18); // seems to be some kind of identifier + case 0x1020: + return 0x10000; + default: + break; + } + return 0; +} + +static void ipod_touch_mbx_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) +{ + IPodTouchMBXState *s = (IPodTouchMBXState *)opaque; + fprintf(stderr, "%s: writing 0x%08x to 0x%08x\n", __func__, val, addr); +} + +static const MemoryRegionOps ipod_touch_mbx_ops = { + .read = ipod_touch_mbx_read, + .write = ipod_touch_mbx_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void ipod_touch_mbx_init(Object *obj) +{ + IPodTouchMBXState *s = IPOD_TOUCH_MBX(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &ipod_touch_mbx_ops, s, TYPE_IPOD_TOUCH_MBX, 0x1000000); + sysbus_init_mmio(sbd, &s->iomem); +} + +static void ipod_touch_mbx_class_init(ObjectClass *klass, void *data) +{ + +} + +static const TypeInfo ipod_touch_mbx_type_info = { + .name = TYPE_IPOD_TOUCH_MBX, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IPodTouchMBXState), + .instance_init = ipod_touch_mbx_init, + .class_init = ipod_touch_mbx_class_init, +}; + +static void ipod_touch_mbx_register_types(void) +{ + type_register_static(&ipod_touch_mbx_type_info); +} + +type_init(ipod_touch_mbx_register_types) \ No newline at end of file diff --git a/hw/arm/ipod_touch_nor_spi.c b/hw/arm/ipod_touch_nor_spi.c index 377609397b97..0dbf4b5866a8 100644 --- a/hw/arm/ipod_touch_nor_spi.c +++ b/hw/arm/ipod_touch_nor_spi.c @@ -14,6 +14,9 @@ static uint32_t ipod_touch_nor_spi_transfer(SSIPeripheral *dev, uint32_t value) IPodTouchNORSPIState *s = IPOD_TOUCH_NOR_SPI(dev); //printf("NOR SPI received value 0x%08x\n", value); + if(value == NOR_GET_JEDECID) { + printf("RECEIVED JEDCID VALUE\n"); + } if(s->cur_cmd == NOR_READ_DATA_CMD && s->in_buf_cur_ind == s->in_buf_size && value != 0xFF) { // if we are currently reading from the NOR data and we receive a value that's not the sentinel, reset the current command. @@ -40,6 +43,7 @@ static uint32_t ipod_touch_nor_spi_transfer(SSIPeripheral *dev, uint32_t value) s->out_buf_size = 4096; } else if(value == NOR_GET_JEDECID) { + printf("WILL RETURN JEDCID\n"); s->in_buf_size = 1; s->out_buf_size = 3; s->out_buf[0] = 0x1F; // vendor: atmel, device: 0x02 -> AT25DF081A diff --git a/hw/arm/ipod_touch_usb_phys.c b/hw/arm/ipod_touch_usb_phys.c index f8eb44abab92..7b5fc81a2f06 100644 --- a/hw/arm/ipod_touch_usb_phys.c +++ b/hw/arm/ipod_touch_usb_phys.c @@ -17,7 +17,8 @@ static uint64_t ipod_touch_usb_phys_read(void *opaque, hwaddr addr, unsigned siz case REG_OPHYTUNE: return s->usb_ophytune; default: - hw_error("%s: read invalid location 0x%08x\n", __func__, addr); + return 0x0; + //hw_error("%s: read invalid location 0x%08x\n", __func__, addr); } } diff --git a/hw/arm/meson.build b/hw/arm/meson.build index f8c4ae134e9e..7af709753b17 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -62,6 +62,6 @@ arm_ss.add(when: 'CONFIG_FSL_IMX7', if_true: files('fsl-imx7.c', 'mcimx7d-sabre. arm_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c', 'smmuv3.c')) arm_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c')) arm_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c')) -arm_ss.add(when: 'CONFIG_IPOD_TOUCH_2G', if_true: files('ipod_touch_2g.c', 'ipod_touch_clock.c', 'ipod_touch_chipid.c', 'ipod_touch_gpio.c', 'ipod_touch_sysic.c', 'ipod_touch_timer.c', 'ipod_touch_usb_otg.c', 'ipod_touch_usb_phys.c', 'ipod_touch_spi.c', 'ipod_touch_nor_spi.c', 'ipod_touch_sha1.c', 'ipod_touch_aes.c', 'ipod_touch_pke.c', 'ipod_touch_pcf50633_pmu.c', 'ipod_touch_unknown1.c', 'ipod_touch_lcd.c', 'ipod_touch_mipi_dsi.c', 'ipod_touch_fmss.c', 'ipod_touch_block_device.c')) +arm_ss.add(when: 'CONFIG_IPOD_TOUCH_2G', if_true: files('ipod_touch_2g.c', 'ipod_touch_clock.c', 'ipod_touch_chipid.c', 'ipod_touch_gpio.c', 'ipod_touch_sysic.c', 'ipod_touch_timer.c', 'ipod_touch_usb_otg.c', 'ipod_touch_usb_phys.c', 'ipod_touch_spi.c', 'ipod_touch_nor_spi.c', 'ipod_touch_sha1.c', 'ipod_touch_aes.c', 'ipod_touch_pke.c', 'ipod_touch_pcf50633_pmu.c', 'ipod_touch_unknown1.c', 'ipod_touch_lcd.c', 'ipod_touch_mipi_dsi.c', 'ipod_touch_fmss.c', 'ipod_touch_block_device.c', 'ipod_touch_mbx.c')) hw_arch += {'arm': arm_ss} diff --git a/include/hw/arm/ipod_touch_2g.h b/include/hw/arm/ipod_touch_2g.h index 337e16a50c50..372e88f341b9 100644 --- a/include/hw/arm/ipod_touch_2g.h +++ b/include/hw/arm/ipod_touch_2g.h @@ -24,6 +24,7 @@ #include "hw/arm/ipod_touch_mipi_dsi.h" #include "hw/arm/ipod_touch_fmss.h" #include "hw/arm/ipod_touch_block_device.h" +#include "hw/arm/ipod_touch_mbx.h" #define TYPE_IPOD_TOUCH "iPod-Touch" @@ -41,6 +42,7 @@ #define S5L8720_I2C0_IRQ 0x15 #define S5L8720_SPI3_IRQ 0x1C #define S5L8720_I2C1_IRQ 0x16 +#define S5L8720_FMSS_IRQ 0x36 #define S5L8720_SPI4_IRQ 0x37 #define IT2G_CPREG_VAR_NAME(name) cpreg_##name @@ -126,6 +128,7 @@ typedef struct { IPodTouchMIPIDSIState *mipi_dsi_state; IPodTouchFMSSState *fmss_state; IPodTouchBlockDeviceState *bdev_state; + IPodTouchMBXState *mbx_state; Clock *sysclk; char nor_path[1024]; IT2G_CPREG_VAR_DEF(REG0); diff --git a/include/hw/arm/ipod_touch_fmss.h b/include/hw/arm/ipod_touch_fmss.h index fc78b33f64e2..647e10a77f14 100644 --- a/include/hw/arm/ipod_touch_fmss.h +++ b/include/hw/arm/ipod_touch_fmss.h @@ -17,6 +17,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchFMSSState, IPOD_TOUCH_FMSS) #define FMSS__FMCTRL1 0x4 #define FMSS__CS_IRQ 0xC0C +#define FMSS__CS_IRQMASK 0xC10 #define FMSS__CS_BUF_RST_OK 0xC64 #define FMSS_CINFO_TARGET_ADDR 0xD08 #define FMSS_PAGES_IN_ADDR 0xD0C diff --git a/include/hw/arm/ipod_touch_mbx.h b/include/hw/arm/ipod_touch_mbx.h new file mode 100644 index 000000000000..89fcd00c8004 --- /dev/null +++ b/include/hw/arm/ipod_touch_mbx.h @@ -0,0 +1,16 @@ +#ifndef HW_ARM_IPOD_TOUCH_MBX_H +#define HW_ARM_IPOD_TOUCH_MBX_H + +#include "qemu/osdep.h" +#include "hw/hw.h" +#include "hw/sysbus.h" + +#define TYPE_IPOD_TOUCH_MBX "ipodtouch.mbx" +OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchMBXState, IPOD_TOUCH_MBX) + +typedef struct IPodTouchMBXState { + SysBusDevice busdev; + MemoryRegion iomem; +} IPodTouchMBXState; + +#endif \ No newline at end of file From 0b74ae5cfd0a47c784a1fd02516ef64ac4600578 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Wed, 5 Jul 2023 22:04:03 +0200 Subject: [PATCH 23/58] Got some more stuff running --- hw/arm/ipod_touch_2g.c | 3 +- hw/arm/ipod_touch_fmss.c | 62 ++++++++++++++++++++++++---- hw/arm/ipod_touch_mbx.c | 39 +++++++++++++---- hw/arm/ipod_touch_mipi_dsi.c | 25 ++++++++++- include/hw/arm/ipod_touch_2g.h | 3 +- include/hw/arm/ipod_touch_mbx.h | 3 +- include/hw/arm/ipod_touch_mipi_dsi.h | 7 ++++ 7 files changed, 124 insertions(+), 18 deletions(-) diff --git a/hw/arm/ipod_touch_2g.c b/hw/arm/ipod_touch_2g.c index 1c53fb309e04..f5b939d8c7a0 100644 --- a/hw/arm/ipod_touch_2g.c +++ b/hw/arm/ipod_touch_2g.c @@ -368,7 +368,8 @@ static void ipod_touch_machine_init(MachineState *machine) dev = qdev_new("ipodtouch.mbx"); IPodTouchMBXState *mbx_state = IPOD_TOUCH_MBX(dev); nms->mbx_state = mbx_state; - memory_region_add_subregion(sysmem, MBX1_MEM_BASE, &mbx_state->iomem); + memory_region_add_subregion(sysmem, MBX1_MEM_BASE, &mbx_state->iomem1); + memory_region_add_subregion(sysmem, MBX2_MEM_BASE, &mbx_state->iomem2); qemu_register_reset(ipod_touch_cpu_reset, nms); } diff --git a/hw/arm/ipod_touch_fmss.c b/hw/arm/ipod_touch_fmss.c index ee84bc5c2907..657891b60cf6 100644 --- a/hw/arm/ipod_touch_fmss.c +++ b/hw/arm/ipod_touch_fmss.c @@ -1,5 +1,12 @@ #include "hw/arm/ipod_touch_fmss.h" +static uint32_t reverse_byte_order(uint32_t value) { + return ((value & 0x000000FF) << 24) | + ((value & 0x0000FF00) << 8) | + ((value & 0x00FF0000) >> 8) | + ((value & 0xFF000000) >> 24); +} + static void write_chip_info(IPodTouchFMSSState *s) { uint32_t chipid[] = { 0xb614d5ad, 0xb614d5ad, 0xb614d5ad, 0xb614d5ad }; @@ -8,7 +15,7 @@ static void write_chip_info(IPodTouchFMSSState *s) static void read_nand_pages(IPodTouchFMSSState *s) { - // patch the FTL_Read method + // patch the FTL_Read method in iBoot uint16_t *data = malloc(sizeof(uint16_t) * 9); data[0] = 0xB500; // push {lr} data[1] = 0x4B14; // ldr r3, [pc, #0x50] @@ -16,17 +23,58 @@ static void read_nand_pages(IPodTouchFMSSState *s) data[3] = 0x3304; // adds r3, #4 data[4] = 0x6019; // str r1, [r3] data[5] = 0x3304; // adds r3, #4 - data[6] = 0x601A; // str r1, [r3] -> this will trigger the block loading + data[6] = 0x601A; // str r2, [r3] -> this will trigger the block loading data[7] = 0x2000; // movs r0, #0 data[8] = 0xBD00; // pop {pc} cpu_physical_memory_write(0x0ff02d1c, (uint8_t *)data, 18); - uint32_t *data2 = malloc(sizeof(uint32_t) * 1); - data2[0] = 0x39400000; - cpu_physical_memory_write(0x0ff02d1c + 0x54, (uint8_t *)data2, 4); + uint32_t *block_driver_addr = malloc(sizeof(uint32_t) * 1); + block_driver_addr[0] = 0x38A00F00; + cpu_physical_memory_write(0x0ff02d1c + 0x54, (uint8_t *)block_driver_addr, 4); + + // patch the FTL_Read method in the kernel (which is not in thumb) + uint32_t *data2 = malloc(sizeof(uint32_t) * 20); + data2[0] = reverse_byte_order(0xf0402de9); // push on stack + + // store the block number and number of blocks in the block driver + data2[1] = reverse_byte_order(0x50309FE5); // ldr r3, [pc, #0x50] + data2[2] = reverse_byte_order(0x000083E5); // str r0, [r3] + data2[3] = reverse_byte_order(0x043093E2); // adds r3, #4 + data2[4] = reverse_byte_order(0x001083E5); // str r1, [r3] + data2[5] = reverse_byte_order(0x043093E2); // adds r3, #4 + + // get the physical address of the current io_buffer of the NANDFTL + data2[6] = reverse_byte_order(0x0500A0E1); // mov r0,r5 -> load the AppleNANDFTL object, which seems to reside in r5 + data2[7] = reverse_byte_order(0x001190E5); // ldr r1, [r0,#0x100] -> load the io_buffer object + data2[8] = reverse_byte_order(0x002091E5); // ldr r2,[r1,#0x0] -> load the vtable of the io_buffer + data2[9] = reverse_byte_order(0x0100A0E1); // mov r0,r1 -> make the io_buffer object the first parameter + data2[10] = reverse_byte_order(0x0010A0E3); // mov r1,#0 -> set the second parameter to 0 + data2[11] = reverse_byte_order(0x0340A0E1); // mov r4,r3 -> make sure our block driver address is safe because r3 will be overridden + data2[12] = reverse_byte_order(0x0FE0A0E1); // mov lr,pc + data2[13] = reverse_byte_order(0x98F092E5); // ldr pc,[r2,#0x98] -> jump to the getPhysicalSegment function + + // store the address + data2[14] = reverse_byte_order(0x000084E5); // str r0, [r4] -> this will trigger the block loading + + // return + data2[15] = reverse_byte_order(0x0000B0E3); // movs r0, #0 + data2[16] = reverse_byte_order(0xf080bde8); // pop from stack + + cpu_physical_memory_write(0x858fdd4, (uint8_t *)data2, sizeof(uint32_t) * 17); + + // aux data + uint32_t *aux_data = malloc(sizeof(uint32_t) * 20); + aux_data[0] = 0xE366aF00; // virtual address of the block driver + // aux_data[1] = 0xc0db0640; // NAND FTL object + cpu_physical_memory_write(0x858fdd4 + 0x5C, (uint8_t *)aux_data, 4); + + // TEMP - replace the IOService wait + data[0] = 0x00BF; + cpu_physical_memory_write(0x8176482, (uint8_t *)data, 2); + // boot args - char *boot_args = "kextlog=0xfff debug=0x8 cpus=1 rd=disk0s1 serial=1 io=0xffff8fff"; + char *boot_args = "kextlog=0xfff debug=0x8 cpus=1 rd=disk0s1 serial=1 io=0xffffffff debug-usb=0xffffffff"; cpu_physical_memory_write(0x0ff2a584, boot_args, strlen(boot_args)); for(int page_ind = 0; page_ind < s->reg_num_pages; page_ind++) { @@ -136,7 +184,7 @@ static void ipod_touch_fmss_init(Object *obj) DeviceState *dev = DEVICE(sbd); IPodTouchFMSSState *s = IPOD_TOUCH_FMSS(dev); - memory_region_init_io(&s->iomem, obj, &fmss_ops, s, "fmss", 0x1000); + memory_region_init_io(&s->iomem, obj, &fmss_ops, s, "fmss", 0xF00); sysbus_init_mmio(sbd, &s->iomem); sysbus_init_irq(sbd, &s->irq); diff --git a/hw/arm/ipod_touch_mbx.c b/hw/arm/ipod_touch_mbx.c index b9891e4914e0..47ecaabe8b4e 100644 --- a/hw/arm/ipod_touch_mbx.c +++ b/hw/arm/ipod_touch_mbx.c @@ -1,6 +1,6 @@ #include "hw/arm/ipod_touch_mbx.h" -static uint64_t ipod_touch_mbx_read(void *opaque, hwaddr addr, unsigned size) +static uint64_t ipod_touch_mbx1_read(void *opaque, hwaddr addr, unsigned size) { printf("%s: read from location 0x%08x\n", __func__, addr); switch(addr) @@ -17,15 +17,38 @@ static uint64_t ipod_touch_mbx_read(void *opaque, hwaddr addr, unsigned size) return 0; } -static void ipod_touch_mbx_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) +static void ipod_touch_mbx1_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { IPodTouchMBXState *s = (IPodTouchMBXState *)opaque; fprintf(stderr, "%s: writing 0x%08x to 0x%08x\n", __func__, val, addr); } -static const MemoryRegionOps ipod_touch_mbx_ops = { - .read = ipod_touch_mbx_read, - .write = ipod_touch_mbx_write, +static uint64_t ipod_touch_mbx2_read(void *opaque, hwaddr addr, unsigned size) +{ + printf("%s: read from location 0x%08x\n", __func__, addr); + switch(addr) + { + default: + break; + } + return 0; +} + +static void ipod_touch_mbx2_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) +{ + IPodTouchMBXState *s = (IPodTouchMBXState *)opaque; + fprintf(stderr, "%s: writing 0x%08x to 0x%08x\n", __func__, val, addr); +} + +static const MemoryRegionOps ipod_touch_mbx1_ops = { + .read = ipod_touch_mbx1_read, + .write = ipod_touch_mbx1_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static const MemoryRegionOps ipod_touch_mbx2_ops = { + .read = ipod_touch_mbx2_read, + .write = ipod_touch_mbx2_write, .endianness = DEVICE_NATIVE_ENDIAN, }; @@ -34,8 +57,10 @@ static void ipod_touch_mbx_init(Object *obj) IPodTouchMBXState *s = IPOD_TOUCH_MBX(obj); SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - memory_region_init_io(&s->iomem, obj, &ipod_touch_mbx_ops, s, TYPE_IPOD_TOUCH_MBX, 0x1000000); - sysbus_init_mmio(sbd, &s->iomem); + memory_region_init_io(&s->iomem1, obj, &ipod_touch_mbx1_ops, s, TYPE_IPOD_TOUCH_MBX, 0x10000); + sysbus_init_mmio(sbd, &s->iomem1); + memory_region_init_io(&s->iomem2, obj, &ipod_touch_mbx2_ops, s, TYPE_IPOD_TOUCH_MBX, 0x10000); + sysbus_init_mmio(sbd, &s->iomem2); } static void ipod_touch_mbx_class_init(ObjectClass *klass, void *data) diff --git a/hw/arm/ipod_touch_mipi_dsi.c b/hw/arm/ipod_touch_mipi_dsi.c index 31af799b98f7..7d4de7e09cd7 100644 --- a/hw/arm/ipod_touch_mipi_dsi.c +++ b/hw/arm/ipod_touch_mipi_dsi.c @@ -9,6 +9,18 @@ static uint64_t ipod_touch_mipi_dsi_read(void *opaque, hwaddr addr, unsigned siz { case 0x0: return 0x103 | rDSIM_STATUS_TxReadyHsClk; + case REG_INTSRC: + return rDSIM_INTSRC_RxDatDone; + case REG_RXFIFO: + printf("READ ABC\n"); + if(!s->return_panel_id) { + s->return_panel_id = true; + return DSIM_RSP_LONG_READ | (3 << 8); // the latter part indicates the length of the response (the panel ID) + } else { + s->return_panel_id = false; + return 0x00a1d13c; + } + case REG_FIFOCTRL: return rDSIM_FIFOCTRL_EmptyHSfr; default: @@ -21,7 +33,16 @@ static uint64_t ipod_touch_mipi_dsi_read(void *opaque, hwaddr addr, unsigned siz static void ipod_touch_mipi_dsi_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { IPodTouchMIPIDSIState *s = (IPodTouchMIPIDSIState *)opaque; - // fprintf(stderr, "%s: writing 0x%08x to 0x%08x\n", __func__, val, addr); + fprintf(stderr, "%s: writing 0x%08x to 0x%08x\n", __func__, val, addr); + + switch(addr) + { + case REG_PKTHDR: + s->pkthdr_reg = val; + break; + default: + break; + } } static const MemoryRegionOps mipi_dsi_ops = { @@ -44,6 +65,8 @@ static void ipod_touch_mipi_dsi_init(Object *obj) memory_region_init_io(&s->iomem, obj, &mipi_dsi_ops, s, "mipi_dsi", 0x10000); sysbus_init_mmio(sbd, &s->iomem); sysbus_init_irq(sbd, &s->irq); + + s->return_panel_id = 0; } static void ipod_touch_mipi_dsi_class_init(ObjectClass *klass, void *data) diff --git a/include/hw/arm/ipod_touch_2g.h b/include/hw/arm/ipod_touch_2g.h index 372e88f341b9..699ae0a951b5 100644 --- a/include/hw/arm/ipod_touch_2g.h +++ b/include/hw/arm/ipod_touch_2g.h @@ -64,6 +64,7 @@ #define USBOTG_MEM_BASE 0x38400000 #define DISPLAY_MEM_BASE 0x38900000 #define FMSS_MEM_BASE 0x38A00000 +#define BLOCK_DEVICE_MEM_BASE 0x38A00F00 #define AES_MEM_BASE 0x38C00000 #define SDIO_MEM_BASE 0x38D00000 #define VIC0_MEM_BASE 0x38E00000 @@ -73,7 +74,7 @@ #define TVOUT1_MEM_BASE 0x39100000 #define TVOUT2_MEM_BASE 0x39200000 #define TVOUT3_MEM_BASE 0x39300000 -#define BLOCK_DEVICE_MEM_BASE 0x39400000 +//#define BLOCK_DEVICE_MEM_BASE 0x39400000 #define SYSIC_MEM_BASE 0x39700000 #define DMAC1_MEM_BASE 0x39900000 #define MBX1_MEM_BASE 0x3B000000 diff --git a/include/hw/arm/ipod_touch_mbx.h b/include/hw/arm/ipod_touch_mbx.h index 89fcd00c8004..f65eaf289bc7 100644 --- a/include/hw/arm/ipod_touch_mbx.h +++ b/include/hw/arm/ipod_touch_mbx.h @@ -10,7 +10,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchMBXState, IPOD_TOUCH_MBX) typedef struct IPodTouchMBXState { SysBusDevice busdev; - MemoryRegion iomem; + MemoryRegion iomem1; + MemoryRegion iomem2; } IPodTouchMBXState; #endif \ No newline at end of file diff --git a/include/hw/arm/ipod_touch_mipi_dsi.h b/include/hw/arm/ipod_touch_mipi_dsi.h index be6d6c6ffbbe..f35f359bb82d 100644 --- a/include/hw/arm/ipod_touch_mipi_dsi.h +++ b/include/hw/arm/ipod_touch_mipi_dsi.h @@ -11,16 +11,23 @@ #define TYPE_IPOD_TOUCH_MIPI_DSI "ipodtouch.mipidsi" OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchMIPIDSIState, IPOD_TOUCH_MIPI_DSI) +#define REG_INTSRC 0x2C +#define REG_PKTHDR 0x34 +#define REG_RXFIFO 0x3C #define REG_FIFOCTRL 0x44 +#define DSIM_RSP_LONG_READ 0x1A #define rDSIM_FIFOCTRL_EmptyHSfr 0x400000 #define rDSIM_STATUS_TxReadyHsClk 0x400 +#define rDSIM_INTSRC_RxDatDone 0x00040000 typedef struct IPodTouchMIPIDSIState { SysBusDevice parent_obj; MemoryRegion iomem; qemu_irq irq; + uint32_t pkthdr_reg; + bool return_panel_id; } IPodTouchMIPIDSIState; #endif \ No newline at end of file From 288942882a522cf8f6bf62277a7d8cd98904d510 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Fri, 7 Jul 2023 20:34:58 +0200 Subject: [PATCH 24/58] Mikey is loading --- hw/arm/ipod_touch_2g.c | 25 ++++++---- hw/arm/ipod_touch_cd3272_mikey.c | 58 ++++++++++++++++++++++++ hw/arm/ipod_touch_lis302dl.c | 55 ++++++++++++++++++++++ hw/arm/ipod_touch_mipi_dsi.c | 2 +- hw/arm/meson.build | 2 +- hw/i2c/ipod_touch_i2c.c | 11 ++++- include/hw/arm/ipod_touch_cd3272_mikey.h | 20 ++++++++ include/hw/arm/ipod_touch_lis302dl.h | 23 ++++++++++ include/hw/i2c/ipod_touch_i2c.h | 1 + 9 files changed, 185 insertions(+), 12 deletions(-) create mode 100644 hw/arm/ipod_touch_cd3272_mikey.c create mode 100644 hw/arm/ipod_touch_lis302dl.c create mode 100644 include/hw/arm/ipod_touch_cd3272_mikey.h create mode 100644 include/hw/arm/ipod_touch_lis302dl.h diff --git a/hw/arm/ipod_touch_2g.c b/hw/arm/ipod_touch_2g.c index f5b939d8c7a0..1f96d7671ae5 100644 --- a/hw/arm/ipod_touch_2g.c +++ b/hw/arm/ipod_touch_2g.c @@ -292,9 +292,10 @@ static void ipod_touch_machine_init(MachineState *machine) sysbus_realize(busdev, &error_fatal); sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_DMAC0_IRQ)); - // Init I2C + // Init I2C0 dev = qdev_new("ipodtouch.i2c"); IPodTouchI2CState *i2c_state = IPOD_TOUCH_I2C(dev); + i2c_state->base = 0; nms->i2c0_state = i2c_state; busdev = SYS_BUS_DEVICE(dev); sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_I2C0_IRQ)); @@ -303,21 +304,29 @@ static void ipod_touch_machine_init(MachineState *machine) // init the PMU i2c_slave_create_simple(i2c_state->bus, "pcf50633", 0x73); - // init the FMSS flash controller - dev = qdev_new("ipodtouch.fmss"); - IPodTouchFMSSState *fmss_state = IPOD_TOUCH_FMSS(dev); - nms->fmss_state = fmss_state; - busdev = SYS_BUS_DEVICE(dev); - sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_FMSS_IRQ)); - memory_region_add_subregion(sysmem, FMSS_MEM_BASE, &fmss_state->iomem); + // init the accelerometer + I2CSlave *accelerometer = i2c_slave_create_simple(i2c_state->bus, "lis302dl", 0x1D); + // Init I2C1 dev = qdev_new("ipodtouch.i2c"); i2c_state = IPOD_TOUCH_I2C(dev); nms->i2c1_state = i2c_state; + i2c_state->base = 1; busdev = SYS_BUS_DEVICE(dev); sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_I2C1_IRQ)); memory_region_add_subregion(sysmem, I2C1_MEM_BASE, &i2c_state->iomem); + // init the Mikey + i2c_slave_create_simple(i2c_state->bus, "cd3272mikey", 0x39); + + // init the FMSS flash controller + dev = qdev_new("ipodtouch.fmss"); + IPodTouchFMSSState *fmss_state = IPOD_TOUCH_FMSS(dev); + nms->fmss_state = fmss_state; + busdev = SYS_BUS_DEVICE(dev); + sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_FMSS_IRQ)); + memory_region_add_subregion(sysmem, FMSS_MEM_BASE, &fmss_state->iomem); + // init the chip ID module dev = qdev_new("ipodtouch.usbphys"); IPodTouchUSBPhysState *usb_phys_state = IPOD_TOUCH_USB_PHYS(dev); diff --git a/hw/arm/ipod_touch_cd3272_mikey.c b/hw/arm/ipod_touch_cd3272_mikey.c new file mode 100644 index 000000000000..f135f1c3090f --- /dev/null +++ b/hw/arm/ipod_touch_cd3272_mikey.c @@ -0,0 +1,58 @@ +#include "hw/arm/ipod_touch_cd3272_mikey.h" + +static int cd3272_mikey_event(I2CSlave *i2c, enum i2c_event event) +{ + return 0; +} + +static uint8_t cd3272_mikey_recv(I2CSlave *i2c) +{ + CD3272MikeyState *s = CD3272MIKEY(i2c); + printf("Reading mikey register %d\n", s->cmd); + + int res = 0; + + switch(s->cmd) { + default: + res = 0; + } + + s->cmd += 1; + return res; +} + +static int cd3272_mikey_send(I2CSlave *i2c, uint8_t data) +{ + CD3272MikeyState *s = CD3272MIKEY(i2c); + s->cmd = data; + return 0; +} + +static void cd3272_mikey_init(Object *obj) +{ + +} + +static void cd3272_mikey_class_init(ObjectClass *klass, void *data) +{ + I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); + + k->event = cd3272_mikey_event; + k->recv = cd3272_mikey_recv; + k->send = cd3272_mikey_send; +} + +static const TypeInfo cd3272_mikey_info = { + .name = TYPE_CD3272MIKEY, + .parent = TYPE_I2C_SLAVE, + .instance_init = cd3272_mikey_init, + .instance_size = sizeof(CD3272MikeyState), + .class_init = cd3272_mikey_class_init, +}; + +static void cd3272_mikey_register_types(void) +{ + type_register_static(&cd3272_mikey_info); +} + +type_init(cd3272_mikey_register_types) \ No newline at end of file diff --git a/hw/arm/ipod_touch_lis302dl.c b/hw/arm/ipod_touch_lis302dl.c new file mode 100644 index 000000000000..4ac7434e8d62 --- /dev/null +++ b/hw/arm/ipod_touch_lis302dl.c @@ -0,0 +1,55 @@ +#include "hw/arm/ipod_touch_lis302dl.h" + +static int lis302dl_event(I2CSlave *i2c, enum i2c_event event) +{ + return 0; +} + +static uint8_t lis302dl_recv(I2CSlave *i2c) +{ + LIS302DLState *s = LIS302DL(i2c); + printf("Reading accelerometer register %d\n", s->cmd); + + switch(s->cmd) { + case ACCEL_WHOAMI: + return ACCEL_WHOAMI_VALUE; // whoami value + default: + return 0; + } +} + +static int lis302dl_send(I2CSlave *i2c, uint8_t data) +{ + LIS302DLState *s = LIS302DL(i2c); + s->cmd = data; + return 0; +} + +static void lis302dl_init(Object *obj) +{ + +} + +static void lis302dl_class_init(ObjectClass *klass, void *data) +{ + I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); + + k->event = lis302dl_event; + k->recv = lis302dl_recv; + k->send = lis302dl_send; +} + +static const TypeInfo lis302dl_info = { + .name = TYPE_LIS302DL, + .parent = TYPE_I2C_SLAVE, + .instance_init = lis302dl_init, + .instance_size = sizeof(LIS302DLState), + .class_init = lis302dl_class_init, +}; + +static void lis302dl_register_types(void) +{ + type_register_static(&lis302dl_info); +} + +type_init(lis302dl_register_types) \ No newline at end of file diff --git a/hw/arm/ipod_touch_mipi_dsi.c b/hw/arm/ipod_touch_mipi_dsi.c index 7d4de7e09cd7..38b373c2502b 100644 --- a/hw/arm/ipod_touch_mipi_dsi.c +++ b/hw/arm/ipod_touch_mipi_dsi.c @@ -12,9 +12,9 @@ static uint64_t ipod_touch_mipi_dsi_read(void *opaque, hwaddr addr, unsigned siz case REG_INTSRC: return rDSIM_INTSRC_RxDatDone; case REG_RXFIFO: - printf("READ ABC\n"); if(!s->return_panel_id) { s->return_panel_id = true; + // TODO this should be rewritten as a proper queue! return DSIM_RSP_LONG_READ | (3 << 8); // the latter part indicates the length of the response (the panel ID) } else { s->return_panel_id = false; diff --git a/hw/arm/meson.build b/hw/arm/meson.build index 7af709753b17..fd7cc9604069 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -62,6 +62,6 @@ arm_ss.add(when: 'CONFIG_FSL_IMX7', if_true: files('fsl-imx7.c', 'mcimx7d-sabre. arm_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c', 'smmuv3.c')) arm_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c')) arm_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c')) -arm_ss.add(when: 'CONFIG_IPOD_TOUCH_2G', if_true: files('ipod_touch_2g.c', 'ipod_touch_clock.c', 'ipod_touch_chipid.c', 'ipod_touch_gpio.c', 'ipod_touch_sysic.c', 'ipod_touch_timer.c', 'ipod_touch_usb_otg.c', 'ipod_touch_usb_phys.c', 'ipod_touch_spi.c', 'ipod_touch_nor_spi.c', 'ipod_touch_sha1.c', 'ipod_touch_aes.c', 'ipod_touch_pke.c', 'ipod_touch_pcf50633_pmu.c', 'ipod_touch_unknown1.c', 'ipod_touch_lcd.c', 'ipod_touch_mipi_dsi.c', 'ipod_touch_fmss.c', 'ipod_touch_block_device.c', 'ipod_touch_mbx.c')) +arm_ss.add(when: 'CONFIG_IPOD_TOUCH_2G', if_true: files('ipod_touch_2g.c', 'ipod_touch_clock.c', 'ipod_touch_chipid.c', 'ipod_touch_gpio.c', 'ipod_touch_sysic.c', 'ipod_touch_timer.c', 'ipod_touch_usb_otg.c', 'ipod_touch_usb_phys.c', 'ipod_touch_spi.c', 'ipod_touch_nor_spi.c', 'ipod_touch_sha1.c', 'ipod_touch_aes.c', 'ipod_touch_pke.c', 'ipod_touch_pcf50633_pmu.c', 'ipod_touch_unknown1.c', 'ipod_touch_lcd.c', 'ipod_touch_mipi_dsi.c', 'ipod_touch_fmss.c', 'ipod_touch_block_device.c', 'ipod_touch_mbx.c', 'ipod_touch_cd3272_mikey.c', 'ipod_touch_lis302dl.c')) hw_arch += {'arm': arm_ss} diff --git a/hw/i2c/ipod_touch_i2c.c b/hw/i2c/ipod_touch_i2c.c index 991f9e86863d..b7a19f654d1f 100644 --- a/hw/i2c/ipod_touch_i2c.c +++ b/hw/i2c/ipod_touch_i2c.c @@ -96,7 +96,7 @@ static void ipod_touch_i2c_write(void *opaque, hwaddr offset, uint64_t value, un IPodTouchI2CState *s = (IPodTouchI2CState *)opaque; int mode; - //fprintf(stderr, "s5l8900_i2c_write: offset = 0x%08x, val = 0x%08x\n", offset, value); + //printf("s5l8900_i2c_write (base %d): offset = 0x%08x, val = 0x%08x\n", s->base, offset, value); qemu_irq_lower(s->irq); @@ -198,6 +198,8 @@ static const MemoryRegionOps ipod_touch_i2c_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; +static int i2c_index = 0; + static void ipod_touch_i2c_init(Object *obj) { DeviceState *dev = DEVICE(obj); @@ -207,7 +209,12 @@ static void ipod_touch_i2c_init(Object *obj) memory_region_init_io(&s->iomem, obj, &ipod_touch_i2c_ops, s, TYPE_IPOD_TOUCH_I2C, 0x100); sysbus_init_mmio(sbd, &s->iomem); sysbus_init_irq(sbd, &s->irq); - s->bus = i2c_init_bus(dev, "i2c"); + + char bus_name[5]; + sprintf(bus_name, "i2c%d", i2c_index); + + s->bus = i2c_init_bus(dev, bus_name); + i2c_index += 1; } static void ipod_touch_i2c_reset(DeviceState *d) diff --git a/include/hw/arm/ipod_touch_cd3272_mikey.h b/include/hw/arm/ipod_touch_cd3272_mikey.h new file mode 100644 index 000000000000..79941313b35c --- /dev/null +++ b/include/hw/arm/ipod_touch_cd3272_mikey.h @@ -0,0 +1,20 @@ +#ifndef HW_CD3272_MIKEY_H +#define HW_CD3272_MIKEY_H + +#include "qemu/osdep.h" +#include "qemu/module.h" +#include "qemu/timer.h" +#include "hw/sysbus.h" +#include "hw/i2c/i2c.h" +#include "hw/irq.h" +#include "time.h" + +#define TYPE_CD3272MIKEY "cd3272mikey" +OBJECT_DECLARE_SIMPLE_TYPE(CD3272MikeyState, CD3272MIKEY) + +typedef struct CD3272MikeyState { + I2CSlave i2c; + uint32_t cmd; +} CD3272MikeyState; + +#endif \ No newline at end of file diff --git a/include/hw/arm/ipod_touch_lis302dl.h b/include/hw/arm/ipod_touch_lis302dl.h new file mode 100644 index 000000000000..551f908cc9cf --- /dev/null +++ b/include/hw/arm/ipod_touch_lis302dl.h @@ -0,0 +1,23 @@ +#ifndef HW_LIS302DL_H +#define HW_LIS302DL_H + +#include "qemu/osdep.h" +#include "qemu/module.h" +#include "qemu/timer.h" +#include "hw/sysbus.h" +#include "hw/i2c/i2c.h" +#include "hw/irq.h" + +#define TYPE_LIS302DL "lis302dl" +OBJECT_DECLARE_SIMPLE_TYPE(LIS302DLState, LIS302DL) + +#define ACCEL_WHOAMI 0x0F + +#define ACCEL_WHOAMI_VALUE 0x3B + +typedef struct LIS302DLState { + I2CSlave i2c; + uint32_t cmd; +} LIS302DLState; + +#endif \ No newline at end of file diff --git a/include/hw/i2c/ipod_touch_i2c.h b/include/hw/i2c/ipod_touch_i2c.h index 7675d733661f..b90353542aba 100644 --- a/include/hw/i2c/ipod_touch_i2c.h +++ b/include/hw/i2c/ipod_touch_i2c.h @@ -47,6 +47,7 @@ typedef struct IPodTouchI2CState { MemoryRegion iomem; I2CBus *bus; qemu_irq irq; + uint8_t base; uint8_t control; uint8_t status; From 9a2d42ca335757f9b301e62ca9c511fc53af0e9a Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Fri, 7 Jul 2023 22:48:18 +0200 Subject: [PATCH 25/58] Got NOR up and running on both SPI0 and SPI1 --- hw/arm/ipod_touch_2g.c | 6 +++++- hw/arm/ipod_touch_mipi_dsi.c | 1 + hw/arm/ipod_touch_nor_spi.c | 4 ++-- hw/arm/ipod_touch_spi.c | 7 +++++-- include/hw/arm/ipod_touch_2g.h | 2 ++ 5 files changed, 15 insertions(+), 5 deletions(-) diff --git a/hw/arm/ipod_touch_2g.c b/hw/arm/ipod_touch_2g.c index 1f96d7671ae5..2b0218e71d51 100644 --- a/hw/arm/ipod_touch_2g.c +++ b/hw/arm/ipod_touch_2g.c @@ -244,10 +244,14 @@ static void ipod_touch_machine_init(MachineState *machine) set_spi_base(0); dev = sysbus_create_simple("ipodtouch.spi", SPI0_MEM_BASE, s5l8900_get_irq(nms, S5L8720_SPI0_IRQ)); IPodTouchSPIState *spi0_state = IPOD_TOUCH_SPI(dev); + nms->spi0_state = spi0_state; strcpy(spi0_state->nor->nor_path, nms->nor_path); set_spi_base(1); - sysbus_create_simple("ipodtouch.spi", SPI1_MEM_BASE, s5l8900_get_irq(nms, S5L8720_SPI1_IRQ)); + dev = sysbus_create_simple("ipodtouch.spi", SPI1_MEM_BASE, s5l8900_get_irq(nms, S5L8720_SPI1_IRQ)); + IPodTouchSPIState *spi1_state = IPOD_TOUCH_SPI(dev); + nms->spi1_state = spi1_state; + strcpy(spi1_state->nor->nor_path, nms->nor_path); set_spi_base(2); sysbus_create_simple("ipodtouch.spi", SPI2_MEM_BASE, s5l8900_get_irq(nms, S5L8720_SPI2_IRQ)); diff --git a/hw/arm/ipod_touch_mipi_dsi.c b/hw/arm/ipod_touch_mipi_dsi.c index 38b373c2502b..6969cd50f44b 100644 --- a/hw/arm/ipod_touch_mipi_dsi.c +++ b/hw/arm/ipod_touch_mipi_dsi.c @@ -12,6 +12,7 @@ static uint64_t ipod_touch_mipi_dsi_read(void *opaque, hwaddr addr, unsigned siz case REG_INTSRC: return rDSIM_INTSRC_RxDatDone; case REG_RXFIFO: + return 0; if(!s->return_panel_id) { s->return_panel_id = true; // TODO this should be rewritten as a proper queue! diff --git a/hw/arm/ipod_touch_nor_spi.c b/hw/arm/ipod_touch_nor_spi.c index 0dbf4b5866a8..28a33d8c81c1 100644 --- a/hw/arm/ipod_touch_nor_spi.c +++ b/hw/arm/ipod_touch_nor_spi.c @@ -13,7 +13,7 @@ static uint32_t ipod_touch_nor_spi_transfer(SSIPeripheral *dev, uint32_t value) { IPodTouchNORSPIState *s = IPOD_TOUCH_NOR_SPI(dev); - //printf("NOR SPI received value 0x%08x\n", value); + printf("NOR SPI received value 0x%08x\n", value); if(value == NOR_GET_JEDECID) { printf("RECEIVED JEDCID VALUE\n"); } @@ -36,6 +36,7 @@ static uint32_t ipod_touch_nor_spi_transfer(SSIPeripheral *dev, uint32_t value) if(value == NOR_GET_STATUS_CMD) { s->in_buf_size = 1; s->out_buf_size = 1; + s->out_buf[0] = 0; } else if(value == NOR_READ_DATA_CMD) { printf("Received read command!\n"); @@ -43,7 +44,6 @@ static uint32_t ipod_touch_nor_spi_transfer(SSIPeripheral *dev, uint32_t value) s->out_buf_size = 4096; } else if(value == NOR_GET_JEDECID) { - printf("WILL RETURN JEDCID\n"); s->in_buf_size = 1; s->out_buf_size = 3; s->out_buf[0] = 0x1F; // vendor: atmel, device: 0x02 -> AT25DF081A diff --git a/hw/arm/ipod_touch_spi.c b/hw/arm/ipod_touch_spi.c index 9440cbcdb5b8..380812363cbe 100644 --- a/hw/arm/ipod_touch_spi.c +++ b/hw/arm/ipod_touch_spi.c @@ -284,14 +284,17 @@ static void ipod_touch_spi_realize(DeviceState *dev, struct Error **errp) fifo8_create(&s->rx_fifo, R_FIFO_DEPTH); // create the peripheral + IPodTouchNORSPIState *nor; switch(s->base) { case 0: ssi_create_peripheral(s->spi, TYPE_IPOD_TOUCH_NOR_SPI); - IPodTouchNORSPIState *nor = IPOD_TOUCH_NOR_SPI(dev); + nor = IPOD_TOUCH_NOR_SPI(dev); s->nor = nor; break; case 1: - //ssi_create_peripheral(s->spi, TYPE_IPOD_TOUCH_LCD_PANEL); + ssi_create_peripheral(s->spi, TYPE_IPOD_TOUCH_NOR_SPI); + nor = IPOD_TOUCH_NOR_SPI(dev); + s->nor = nor; break; case 2: { diff --git a/include/hw/arm/ipod_touch_2g.h b/include/hw/arm/ipod_touch_2g.h index 699ae0a951b5..2e095fd72a64 100644 --- a/include/hw/arm/ipod_touch_2g.h +++ b/include/hw/arm/ipod_touch_2g.h @@ -115,6 +115,8 @@ typedef struct { IPodTouchClockState *clock0; IPodTouchClockState *clock1; IPodTouchTimerState *timer1; + IPodTouchSPIState *spi0_state; + IPodTouchSPIState *spi1_state; IPodTouchChipIDState *chipid_state; IPodTouchGPIOState *gpio_state; IPodTouchSYSICState *sysic; From 6c4f8814361422b713864e945b7f1301d75fe876 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Sat, 8 Jul 2023 16:43:02 +0200 Subject: [PATCH 26/58] Several fixes and changes --- hw/arm/ipod_touch_2g.c | 37 ++- hw/arm/ipod_touch_aes.c | 22 +- hw/arm/ipod_touch_fmss.c | 3 +- hw/arm/ipod_touch_lcd.c | 128 +++++++- hw/arm/ipod_touch_mipi_dsi.c | 1 - hw/arm/ipod_touch_multitouch.c | 415 +++++++++++++++++++++++++ hw/arm/ipod_touch_nor_spi.c | 1 - hw/arm/ipod_touch_pke.c | 24 +- hw/arm/ipod_touch_scaler_csc.c | 54 ++++ hw/arm/ipod_touch_spi.c | 12 +- hw/arm/meson.build | 2 +- hw/dma/pl080.c | 6 +- include/hw/arm/ipod_touch_2g.h | 7 +- include/hw/arm/ipod_touch_lcd.h | 14 + include/hw/arm/ipod_touch_multitouch.h | 160 ++++++++++ include/hw/arm/ipod_touch_scaler_csc.h | 19 ++ include/hw/arm/ipod_touch_spi.h | 9 +- include/hw/dma/pl080.h | 3 +- 18 files changed, 861 insertions(+), 56 deletions(-) create mode 100644 hw/arm/ipod_touch_multitouch.c create mode 100644 hw/arm/ipod_touch_scaler_csc.c create mode 100644 include/hw/arm/ipod_touch_multitouch.h create mode 100644 include/hw/arm/ipod_touch_scaler_csc.h diff --git a/hw/arm/ipod_touch_2g.c b/hw/arm/ipod_touch_2g.c index 2b0218e71d51..90a9502e2679 100644 --- a/hw/arm/ipod_touch_2g.c +++ b/hw/arm/ipod_touch_2g.c @@ -88,7 +88,6 @@ static void ipod_touch_memory_setup(MachineState *machine, MemoryRegion *sysmem, allocate_ram(sysmem, "iboot", IBOOT_MEM_BASE, 0x100000); allocate_ram(sysmem, "llb", 0x22000000, 0x100000); allocate_ram(sysmem, "sram1", SRAM1_MEM_BASE, 0x100000); - allocate_ram(sysmem, "mbx2", MBX2_MEM_BASE, 0x1000); allocate_ram(sysmem, "tvout1", TVOUT1_MEM_BASE, 0x1000); allocate_ram(sysmem, "tvout2", TVOUT2_MEM_BASE, 0x1000); allocate_ram(sysmem, "tvout3", TVOUT3_MEM_BASE, 0x1000); @@ -260,7 +259,9 @@ static void ipod_touch_machine_init(MachineState *machine) sysbus_create_simple("ipodtouch.spi", SPI3_MEM_BASE, s5l8900_get_irq(nms, S5L8720_SPI3_IRQ)); set_spi_base(4); - sysbus_create_simple("ipodtouch.spi", SPI4_MEM_BASE, s5l8900_get_irq(nms, S5L8720_SPI4_IRQ)); + dev = sysbus_create_simple("ipodtouch.spi", SPI4_MEM_BASE, s5l8900_get_irq(nms, S5L8720_SPI4_IRQ)); + IPodTouchSPIState *spi4_state = IPOD_TOUCH_SPI(dev); + nms->spi4_state = spi4_state; // init the chip ID module dev = qdev_new("ipodtouch.chipid"); @@ -283,7 +284,7 @@ static void ipod_touch_machine_init(MachineState *machine) dev = qdev_new("pl080"); PL080State *pl080_1 = PL080(dev); object_property_set_link(OBJECT(dev), "downstream", OBJECT(sysmem), &error_fatal); - memory_region_add_subregion(sysmem, DMAC0_MEM_BASE, &pl080_1->iomem); + memory_region_add_subregion(sysmem, DMAC0_MEM_BASE, &pl080_1->iomem1); busdev = SYS_BUS_DEVICE(dev); sysbus_realize(busdev, &error_fatal); sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_DMAC0_IRQ)); @@ -291,10 +292,11 @@ static void ipod_touch_machine_init(MachineState *machine) dev = qdev_new("pl080"); PL080State *pl080_2 = PL080(dev); object_property_set_link(OBJECT(dev), "downstream", OBJECT(sysmem), &error_fatal); - memory_region_add_subregion(sysmem, DMAC1_MEM_BASE, &pl080_2->iomem); + memory_region_add_subregion(sysmem, DMAC1_0_MEM_BASE, &pl080_2->iomem1); + memory_region_add_subregion(sysmem, DMAC1_1_MEM_BASE, &pl080_2->iomem2); busdev = SYS_BUS_DEVICE(dev); sysbus_realize(busdev, &error_fatal); - sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_DMAC0_IRQ)); + sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_DMAC1_IRQ)); // Init I2C0 dev = qdev_new("ipodtouch.i2c"); @@ -302,11 +304,12 @@ static void ipod_touch_machine_init(MachineState *machine) i2c_state->base = 0; nms->i2c0_state = i2c_state; busdev = SYS_BUS_DEVICE(dev); - sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_I2C0_IRQ)); memory_region_add_subregion(sysmem, I2C0_MEM_BASE, &i2c_state->iomem); + sysbus_realize(busdev, &error_fatal); + sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_I2C0_IRQ)); // init the PMU - i2c_slave_create_simple(i2c_state->bus, "pcf50633", 0x73); + I2CSlave * pmu = i2c_slave_create_simple(i2c_state->bus, "pcf50633", 0x73); // init the accelerometer I2CSlave *accelerometer = i2c_slave_create_simple(i2c_state->bus, "lis302dl", 0x1D); @@ -317,19 +320,21 @@ static void ipod_touch_machine_init(MachineState *machine) nms->i2c1_state = i2c_state; i2c_state->base = 1; busdev = SYS_BUS_DEVICE(dev); - sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_I2C1_IRQ)); memory_region_add_subregion(sysmem, I2C1_MEM_BASE, &i2c_state->iomem); + sysbus_realize(busdev, &error_fatal); + sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_I2C1_IRQ)); // init the Mikey - i2c_slave_create_simple(i2c_state->bus, "cd3272mikey", 0x39); + I2CSlave *cd327mikey = i2c_slave_create_simple(i2c_state->bus, "cd3272mikey", 0x39); // init the FMSS flash controller dev = qdev_new("ipodtouch.fmss"); IPodTouchFMSSState *fmss_state = IPOD_TOUCH_FMSS(dev); nms->fmss_state = fmss_state; busdev = SYS_BUS_DEVICE(dev); - sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_FMSS_IRQ)); memory_region_add_subregion(sysmem, FMSS_MEM_BASE, &fmss_state->iomem); + sysbus_realize(busdev, &error_fatal); + sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_FMSS_IRQ)); // init the chip ID module dev = qdev_new("ipodtouch.usbphys"); @@ -348,10 +353,20 @@ static void ipod_touch_machine_init(MachineState *machine) // init LCD dev = qdev_new("ipodtouch.lcd"); IPodTouchLCDState *lcd_state = IPOD_TOUCH_LCD(dev); + lcd_state->sysmem = sysmem; nms->lcd_state = lcd_state; - sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_LCD_IRQ)); + busdev = SYS_BUS_DEVICE(dev); memory_region_add_subregion(sysmem, DISPLAY_MEM_BASE, &lcd_state->iomem); sysbus_realize(busdev, &error_fatal); + sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_LCD_IRQ)); + + // init scaler / CSC + dev = qdev_new("ipodtouch.scalercsc"); + IPodTouchScalerCSCState *scaler_csc_state = IPOD_TOUCH_SCALER_CSC(dev); + nms->scaler_csc_state = scaler_csc_state; + busdev = SYS_BUS_DEVICE(dev); + memory_region_add_subregion(sysmem, SCALER_CSC_MEM_BASE, &scaler_csc_state->iomem); + sysbus_realize(busdev, &error_fatal); // init SHA1 engine dev = qdev_new("ipodtouch.sha1"); diff --git a/hw/arm/ipod_touch_aes.c b/hw/arm/ipod_touch_aes.c index 63ae0092fc63..6961d19be5c9 100644 --- a/hw/arm/ipod_touch_aes.c +++ b/hw/arm/ipod_touch_aes.c @@ -23,9 +23,13 @@ static void ipod_touch_aes_write(void *opaque, hwaddr offset, uint64_t value, un uint8_t *buf; // fprintf(stderr, "%s: offset 0x%08x value 0x%08x\n", __FUNCTION__, offset, value); + uint32_t *data = malloc(sizeof(uint16_t) * 9); switch(offset) { case AES_GO: + // PATCH OUT + // in iBoot, we also patch the length check after LZSS compression since that can lead to issues + inbuf = (uint8_t *)malloc(aesop->insize); cpu_physical_memory_read((aesop->inaddr), inbuf, aesop->insize); @@ -62,14 +66,26 @@ static void ipod_touch_aes_write(void *opaque, hwaddr offset, uint64_t value, un }; for(int i = 0; i < aesop->insize; i++) { buf[i] = key[i]; } } - else if(aesop->gid_encryption_count == 2) { // kernelcache + else if(aesop->gid_encryption_count == 2) { // apple logo + + // very ugly - we patch out here the LZSS check + data[0] = 0x0; // NOP + cpu_physical_memory_write(0x0ff119f0, (uint8_t *)data, 4); + + char key[] = { + 0x64, 0x23, 0x8f, 0xb0, 0x32, 0x91, 0x42, 0x25, 0x22, 0xb5, 0xdd, 0x28, 0x3f, 0xc3, 0x89, 0x5c, // IV + 0x85, 0x9f, 0xd4, 0xd3, 0x82, 0xb8, 0x38, 0x51, 0x56, 0xfc, 0x58, 0x1a, 0x7f, 0x1d, 0x97, 0x22, // key + }; + for(int i = 0; i < aesop->insize; i++) { buf[i] = key[i]; } + } + else if(aesop->gid_encryption_count == 3) { // kernelcache char key[] = { 0xa1, 0x91, 0x29, 0x12, 0x90, 0xd4, 0x87, 0xff, 0x07, 0x31, 0x96, 0x9c, 0x5f, 0xc8, 0xd9, 0x18, // IV 0x0e, 0x4d, 0x23, 0xfa, 0x67, 0x59, 0x99, 0xd5, 0x95, 0x9d, 0xd1, 0x0c, 0x8d, 0xd7, 0x3d, 0x20, // key }; for(int i = 0; i < aesop->insize; i++) { buf[i] = key[i]; } } - else if(aesop->gid_encryption_count == 3) { // device tree + else if(aesop->gid_encryption_count == 4) { // device tree char key[] = { 0xcc, 0xff, 0x63, 0x4e, 0xe1, 0x27, 0x35, 0xf0, 0x19, 0x16, 0xc4, 0xa6, 0xb2, 0x0f, 0xf1, 0x45, // IV 0xe1, 0x7b, 0xcd, 0x56, 0x8d, 0xf1, 0xcd, 0xdc, 0x8f, 0xec, 0xbf, 0x54, 0x87, 0xd5, 0xc3, 0xce, // key @@ -83,7 +99,7 @@ static void ipod_touch_aes_write(void *opaque, hwaddr offset, uint64_t value, un AES_cbc_encrypt(inbuf, buf, aesop->insize, &aesop->decryptKey, (uint8_t *)aesop->ivec, AES_DECRYPT); } - if(aesop->outaddr != 0x220100ac && aesop->outaddr != 0x0bf08468) { // TODO very ugly hack - for the RSA key decryption, it seems that doing nothing results in the correct decryption key?? + if(aesop->outaddr != 0x220100ac && aesop->outaddr != 0x0bf08468 && aesop->outaddr != 0x0fb9bcdc) { // TODO very ugly hack - for the RSA key decryption, it seems that doing nothing results in the correct decryption key?? // BUG: after decrypting the kernel, we update the Adler CRC code and number of expected bytes. if(aesop->outaddr == 0x0b000020) { uint32_t *cast_buf = (uint32_t *)buf; diff --git a/hw/arm/ipod_touch_fmss.c b/hw/arm/ipod_touch_fmss.c index 657891b60cf6..10751109460a 100644 --- a/hw/arm/ipod_touch_fmss.c +++ b/hw/arm/ipod_touch_fmss.c @@ -83,14 +83,13 @@ static void read_nand_pages(IPodTouchFMSSState *s) cpu_physical_memory_read(s->reg_pages_in_addr + page_ind, &page_nr, 0x4); cpu_physical_memory_read(s->reg_pages_out_addr + page_ind, &page_out_addr, 0x4); - printf("Will read page %d into address 0x%08x and spare into address 0x%08x\n", page_nr, page_out_addr, s->reg_page_spare_out_addr); + //printf("Will read page %d into address 0x%08x and spare into address 0x%08x\n", page_nr, page_out_addr, s->reg_page_spare_out_addr); // prepare the page char filename[200]; sprintf(filename, "/Users/martijndevos/Documents/generate_nand_it2g/nand/%d.page", page_nr); struct stat st = {0}; if (stat(filename, &st) == -1) { - printf("Will preparing empty page %d", page_nr); // page storage does not exist - initialize an empty buffer memset(s->page_buffer, 0, NAND_BYTES_PER_PAGE); memset(s->page_spare_buffer, 0, NAND_BYTES_PER_SPARE); diff --git a/hw/arm/ipod_touch_lcd.c b/hw/arm/ipod_touch_lcd.c index 2cfa2d58413b..342944f1ab1d 100644 --- a/hw/arm/ipod_touch_lcd.c +++ b/hw/arm/ipod_touch_lcd.c @@ -1,4 +1,7 @@ #include "hw/arm/ipod_touch_lcd.h" +#include "ui/pixel_ops.h" +#include "ui/console.h" +#include "hw/display/framebuffer.h" static uint64_t ipod_touch_lcd_read(void *opaque, hwaddr addr, unsigned size) { @@ -9,6 +12,16 @@ static uint64_t ipod_touch_lcd_read(void *opaque, hwaddr addr, unsigned size) { case 0x0: return 2; + case 0x4: + return s->lcd_con; + case 0x20: + return s->w1_display_depth_info; + case 0x24: + return s->w1_framebuffer_base; + case 0x28: + return s->w1_hspan; + case 0x30: + return s->w1_display_resolution_info; case 0x1b10: return 2; default: @@ -21,7 +34,95 @@ static uint64_t ipod_touch_lcd_read(void *opaque, hwaddr addr, unsigned size) static void ipod_touch_lcd_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { IPodTouchLCDState *s = (IPodTouchLCDState *)opaque; - // fprintf(stderr, "%s: writing 0x%08x to 0x%08x\n", __func__, val, addr); + fprintf(stderr, "%s: writing 0x%08x to 0x%08x\n", __func__, val, addr); + + switch(addr) { + case 0x4: + s->lcd_con = val; + break; + case 0x20: + s->w1_display_depth_info = val; + break; + case 0x24: + s->w1_framebuffer_base = val; + break; + case 0x28: + s->w1_hspan = val; + break; + case 0x30: + s->w1_display_resolution_info = val; + break; + case 0xC: + qemu_irq_lower(s->irq); + break; + } +} + +static void lcd_invalidate(void *opaque) +{ + IPodTouchLCDState *s = opaque; + s->invalidate = 1; +} + +static void draw_line32_32(void *opaque, uint8_t *d, const uint8_t *s, int width, int deststep) +{ + uint8_t r, g, b; + + do { + //v = lduw_le_p((void *) s); + //printf("V: %d\n", *s); + b = s[0]; + g = s[1]; + r = s[2]; + //printf("R: %d, G: %d, B: %d\n", r, g, b); + ((uint32_t *) d)[0] = rgb_to_pixel32(r, g, b); + s += 4; + d += 4; + } while (-- width != 0); +} + +static void lcd_refresh(void *opaque) +{ + //fprintf(stderr, "%s: refreshing LCD screen\n", __func__); + + IPodTouchLCDState *lcd = (IPodTouchLCDState *) opaque; + DisplaySurface *surface = qemu_console_surface(lcd->con); + drawfn draw_line; + int src_width, dest_width; + int height, first, last; + int width, linesize; + + if (!lcd || !lcd->con || !surface_bits_per_pixel(surface)) + return; + + dest_width = 4; + draw_line = draw_line32_32; + + /* Resolution */ + first = last = 0; + width = 320; + height = 480; + lcd->invalidate = 1; + + src_width = 4 * width; + linesize = surface_stride(surface); + + if(lcd->invalidate) { + framebuffer_update_memory_section(&lcd->fbsection, lcd->sysmem, lcd->w1_framebuffer_base, height, 4 * width); + } + + framebuffer_update_display(surface, &lcd->fbsection, + width, height, + src_width, /* Length of source line, in bytes. */ + linesize, /* Bytes between adjacent horizontal output pixels. */ + dest_width, /* Bytes between adjacent vertical output pixels. */ + lcd->invalidate, + draw_line, NULL, + &first, &last); + if (first >= 0) { + dpy_gfx_update(lcd->con, 0, first, width, last - first + 1); + } + lcd->invalidate = 0; } static const MemoryRegionOps lcd_ops = { @@ -30,9 +131,32 @@ static const MemoryRegionOps lcd_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; +static const GraphicHwOps gfx_ops = { + .invalidate = lcd_invalidate, + .gfx_update = lcd_refresh, +}; + +static void refresh_timer_tick(void *opaque) +{ + IPodTouchLCDState *s = (IPodTouchLCDState *)opaque; + + //qemu_irq_raise(s->irq); + + //timer_mod(s->refresh_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + NANOSECONDS_PER_SECOND / LCD_REFRESH_RATE_FREQUENCY); +} + static void ipod_touch_lcd_realize(DeviceState *dev, Error **errp) { - + IPodTouchLCDState *s = IPOD_TOUCH_LCD(dev); + s->con = graphic_console_init(dev, 0, &gfx_ops, s); + qemu_console_resize(s->con, 320, 480); + + // add mouse handler + //qemu_add_mouse_event_handler(ipod_touch_lcd_mouse_event, s, 1, "iPod Touch Touchscreen"); + + // initialize the refresh timer + s->refresh_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, refresh_timer_tick, s); + timer_mod(s->refresh_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + NANOSECONDS_PER_SECOND / LCD_REFRESH_RATE_FREQUENCY); } static void ipod_touch_lcd_init(Object *obj) diff --git a/hw/arm/ipod_touch_mipi_dsi.c b/hw/arm/ipod_touch_mipi_dsi.c index 6969cd50f44b..38b373c2502b 100644 --- a/hw/arm/ipod_touch_mipi_dsi.c +++ b/hw/arm/ipod_touch_mipi_dsi.c @@ -12,7 +12,6 @@ static uint64_t ipod_touch_mipi_dsi_read(void *opaque, hwaddr addr, unsigned siz case REG_INTSRC: return rDSIM_INTSRC_RxDatDone; case REG_RXFIFO: - return 0; if(!s->return_panel_id) { s->return_panel_id = true; // TODO this should be rewritten as a proper queue! diff --git a/hw/arm/ipod_touch_multitouch.c b/hw/arm/ipod_touch_multitouch.c new file mode 100644 index 000000000000..85fdb5a020e2 --- /dev/null +++ b/hw/arm/ipod_touch_multitouch.c @@ -0,0 +1,415 @@ +#include "hw/arm/ipod_touch_multitouch.h" + +static void prepare_interface_version_response(IPodTouchMultitouchState *s) { + memset(s->out_buffer + 1, 0, 15); + + // set the interface version + s->out_buffer[2] = MT_INTERFACE_VERSION; + + // set the max packet size + s->out_buffer[3] = (MT_MAX_PACKET_SIZE & 0xFF); + s->out_buffer[4] = (MT_MAX_PACKET_SIZE >> 8) & 0xFF; + + // compute and set the checksum + uint32_t checksum = 0; + for(int i = 0; i < 14; i++) { + checksum += s->out_buffer[i]; + } + + s->out_buffer[14] = (checksum & 0xFF); + s->out_buffer[15] = (checksum >> 8) & 0xFF; +} + +static void prepare_cmd_status_response(IPodTouchMultitouchState *s) { + memset(s->out_buffer + 1, 0, 15); + + // TODO we should probably set some CMD status here + + // compute and set the checksum + uint32_t checksum = 0; + for(int i = 0; i < 14; i++) { + checksum += s->out_buffer[i]; + } + + s->out_buffer[14] = (checksum & 0xFF); + s->out_buffer[15] = (checksum >> 8) & 0xFF; +} + +static void prepare_report_info_response(IPodTouchMultitouchState *s, uint8_t report_id) { + memset(s->out_buffer + 1, 0, 15); + + // set the error + s->out_buffer[2] = 0; + + // set the report length + uint32_t report_length = 0; + if(report_id == MT_REPORT_UNKNOWN1) { + report_length = MT_REPORT_UNKNOWN1_SIZE; + } + else if(report_id == MT_REPORT_FAMILY_ID) { + report_length = MT_REPORT_FAMILY_ID_SIZE; + } + else if(report_id == MT_REPORT_SENSOR_INFO) { + report_length = MT_REPORT_SENSOR_INFO_SIZE; + } + else if(report_id == MT_REPORT_SENSOR_REGION_DESC) { + report_length = MT_REPORT_SENSOR_REGION_DESC_SIZE; + } + else if(report_id == MT_REPORT_SENSOR_REGION_PARAM) { + report_length = MT_REPORT_SENSOR_REGION_PARAM_SIZE; + } + else if(report_id == MT_REPORT_SENSOR_DIMENSIONS) { + report_length = MT_REPORT_SENSOR_DIMENSIONS_SIZE; + } + else { + hw_error("Unknown report ID 0x%02x\n", report_id); + } + + s->out_buffer[3] = (report_length & 0xFF); + s->out_buffer[4] = (report_length >> 8) & 0xFF; + + // compute and set the checksum + uint32_t checksum = 0; + for(int i = 0; i < 14; i++) { + checksum += s->out_buffer[i]; + } + + s->out_buffer[14] = (checksum & 0xFF); + s->out_buffer[15] = (checksum >> 8) & 0xFF; +} + +static void prepare_short_control_response(IPodTouchMultitouchState *s, uint8_t report_id) { + memset(s->out_buffer + 1, 0, 15); + + if(report_id == MT_REPORT_FAMILY_ID) { + s->out_buffer[3] = MT_FAMILY_ID; + } + else if(report_id == MT_REPORT_SENSOR_INFO) { + s->out_buffer[3] = MT_ENDIANNESS; + s->out_buffer[4] = MT_SENSOR_ROWS; + s->out_buffer[5] = MT_SENSOR_COLUMNS; + s->out_buffer[6] = (MT_BCD_VERSION & 0xFF); + s->out_buffer[7] = (MT_BCD_VERSION >> 8) & 0xFF; + } + else if(report_id == MT_REPORT_SENSOR_REGION_DESC) { + s->out_buffer[3] = MT_SENSOR_REGION_DESC; + } + else if(report_id == MT_REPORT_SENSOR_REGION_PARAM) { + s->out_buffer[3] = MT_SENSOR_REGION_PARAM; + } + else if(report_id == MT_REPORT_SENSOR_DIMENSIONS) { + uint32_t *ob_int32 = (uint32_t *)&s->out_buffer[3]; + ob_int32[0] = MT_SENSOR_SURFACE_WIDTH; + ob_int32[1] = MT_SENSOR_SURFACE_HEIGHT; + } + else { + hw_error("Unknown report ID 0x%02x\n", report_id); + } + + // compute and set the checksum + uint32_t checksum = 0; + for(int i = 0; i < 14; i++) { + checksum += s->out_buffer[i]; + } + + s->out_buffer[14] = (checksum & 0xFF); + s->out_buffer[15] = (checksum >> 8) & 0xFF; +} + +static uint32_t ipod_touch_multitouch_transfer(SSIPeripheral *dev, uint32_t value) +{ + IPodTouchMultitouchState *s = IPOD_TOUCH_MULTITOUCH(dev); + + //printf(" Got value: 0x%02x\n", value); + + if(s->cur_cmd == 0) { + //printf("Starting command 0x%02x\n", value); + // we're currently not in a command - start a new command + s->cur_cmd = value; + s->out_buffer = malloc(0x100); + s->out_buffer[0] = value; // the response header + s->buf_ind = 0; + s->in_buffer = malloc(0x100); + s->in_buffer_ind = 0; + + if(value == 0x18) { // filler packet?? + s->buf_size = 2; + s->out_buffer[1] = 0xE1; + } + else if(value == 0x1A) { // HBPP ACK + s->buf_size = 2; + if(s->hbpp_atn_ack_response[0] == 0 && s->hbpp_atn_ack_response[1] == 0) { + // return the default ACK response + s->out_buffer[0] = 0x4B; + s->out_buffer[1] = 0xC1; + } + else { + s->out_buffer[0] = s->hbpp_atn_ack_response[0]; + s->out_buffer[1] = s->hbpp_atn_ack_response[1]; + } + + } + else if(value == 0x1C) { // read register + s->buf_size = 8; + memset(s->out_buffer, 0, 8); // just return zeros + } + else if(value == 0x1D) { // execute + s->buf_size = 12; + memset(s->out_buffer, 0, 12); // just return zeros + } + else if(value == 0x1F) { // calibration + s->buf_size = 2; + s->out_buffer[1] = 0x0; + } + else if(value == 0x1E) { // write register + s->buf_size = 16; + memset(s->out_buffer, 0, 16); // just return zeros + } + else if(value == 0x1F) { // calibration + s->buf_size = 2; + s->out_buffer[1] = 0x0; + } + else if(value == MT_CMD_HBPP_DATA_PACKET) { + s->buf_size = 20; // should be enough initially, until we get the packet length + memset(s->out_buffer + 1, 0, 20 - 1); // just return zeros + } + else if(value == 0x47) { // unknown command, probably used to clear the interrupt + s->buf_size = 2; + } + else if(value == MT_CMD_GET_CMD_STATUS) { + s->buf_size = 16; + prepare_cmd_status_response(s); + } + else if(value == MT_CMD_GET_INTERFACE_VERSION) { + s->buf_size = 16; + prepare_interface_version_response(s); + } + else if(value == MT_CMD_GET_REPORT_INFO) { + s->buf_size = 16; + } + else if(value == MT_CMD_SHORT_CONTROL_WRITE) { + s->buf_size = 16; + } + else if(value == MT_CMD_SHORT_CONTROL_READ) { + s->buf_size = 16; + } + else if(value == MT_CMD_FRAME_READ) { + printf("Will read frame!\n"); + s->buf_size = sizeof(MTFrame); + free(s->out_buffer); + s->out_buffer = (uint8_t *) s->next_frame; + } + else { + hw_error("Unknown command 0x%02x!", value); + } + } + + s->in_buffer[s->in_buffer_ind] = value; + s->in_buffer_ind++; + + if(s->cur_cmd == MT_CMD_HBPP_DATA_PACKET && s->in_buffer_ind == 10) { + // verify the header checksum + uint32_t checksum = 0; + for(int i = 2; i < 8; i++) { + checksum += s->in_buffer[i]; + } + + if(checksum != (s->in_buffer[8] << 8 | s->in_buffer[9])) { + hw_error("HBPP data header checksum doesn't match!"); + } + + uint32_t data_len = (s->in_buffer[2] << 10) | (s->in_buffer[3] << 2) + 5; + // extend the lengths of the in/out buffers + free(s->in_buffer); + s->in_buffer = malloc(data_len + 0x10); + + free(s->out_buffer); + s->out_buffer = malloc(data_len); + memset(s->out_buffer, 0, data_len); + s->buf_size = data_len; + s->buf_ind = 0; + } + else if(s->cur_cmd == MT_CMD_GET_REPORT_INFO && s->in_buffer_ind == 2) { + prepare_report_info_response(s, s->in_buffer[1]); + } + else if(s->cur_cmd == MT_CMD_SHORT_CONTROL_WRITE && s->in_buffer_ind == 16) { + // TODO we should persist the report here! + } + else if(s->cur_cmd == MT_CMD_SHORT_CONTROL_READ && s->in_buffer_ind == 2) { + prepare_short_control_response(s, s->in_buffer[1]); + } + + // TODO process register writes! + + uint8_t ret_val = s->out_buffer[s->buf_ind]; + s->buf_ind++; + + //printf(" Got value: 0x%02x, returning 0x%02x (index: %d, buffer length: %d)\n", value, ret_val, s->buf_ind, s->buf_size); + + if(s->buf_ind == s->buf_size) { + //printf("Finished command 0x%02x\n", s->cur_cmd); + + if(s->cur_cmd == 0x1E) { + // make sure we return a success status on the next HBPP ACK + s->hbpp_atn_ack_response[0] = 0x4A; + s->hbpp_atn_ack_response[1] = 0xD1; + } + + // we're done with the command + s->cur_cmd = 0; + s->buf_size = 0; + //free(s->out_buffer); + //free(s->in_buffer); + } + + return ret_val; +} + +static MTFrame *get_frame(IPodTouchMultitouchState *s, uint8_t event, float x, float y, uint16_t radius1, uint16_t radius2, uint16_t radius3, uint16_t contactDensity) { + MTFrame *frame = calloc(sizeof(MTFrame), sizeof(uint8_t *)); + + uint16_t data_len = sizeof(MTFrameHeader) + sizeof(FingerData) + 2; + + /// create the frame length packet + frame->frame_length.cmd = MT_CMD_FRAME_READ; + frame->frame_length.length1 = (data_len & 0xFF); + frame->frame_length.length2 = (data_len >> 8) & 0xFF; + + uint16_t checksum = 0; + for(int i = 0; i < 14; i++) { + checksum += ((uint8_t *) &frame->frame_length)[i]; + } + frame->frame_length.checksum1 = (checksum & 0xFF); + frame->frame_length.checksum2 = (checksum >> 8) & 0xFF; + + // create the frame packet + frame->frame_packet.cmd = MT_CMD_FRAME_READ; + frame->frame_packet.length1 = (data_len & 0xFF); + frame->frame_packet.length2 = (data_len >> 8) & 0xFF; + + checksum = 0; + for(int i = 0; i < 4; i++) { + checksum += ((uint8_t *) &frame->frame_length)[i]; + } + + // the first five bytes have to sum up to 0. + frame->frame_packet.checksum_pad = 0xFF - (checksum & 0xFF) + 1; + + frame->frame_packet.header.type = MT_FRAME_TYPE_PATH; + frame->frame_packet.header.frameNum = s->frame_counter; + frame->frame_packet.header.headerLen = sizeof(MTFrameHeader); + uint64_t elapsed_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / 1000000; + frame->frame_packet.header.timestamp = elapsed_ns; + frame->frame_packet.header.numFingers = 1; + frame->frame_packet.header.fingerDataLen = sizeof(FingerData); + + // create the finger data + frame->finger_data.id = 1; + frame->finger_data.event = event; + frame->finger_data.unk_2 = 2; + frame->finger_data.unk_3 = 1; + + // compute the velocity + int diff_x = (int)((x - s->prev_touch_x) * MT_INTERNAL_SENSOR_SURFACE_WIDTH); + int diff_y = (int)((x - s->prev_touch_y) * MT_INTERNAL_SENSOR_SURFACE_HEIGHT); + frame->finger_data.velX = diff_x / (elapsed_ns - s->last_frame_timestamp) * 1000; + frame->finger_data.velY = diff_y / (elapsed_ns - s->last_frame_timestamp) * 1000; + + frame->finger_data.x = (int)(x * MT_INTERNAL_SENSOR_SURFACE_WIDTH); + frame->finger_data.y = (int)(y * MT_INTERNAL_SENSOR_SURFACE_HEIGHT); + frame->finger_data.radius1 = radius1; + frame->finger_data.radius2 = radius2; + frame->finger_data.radius3 = radius3; + frame->finger_data.angle = 19317; + frame->finger_data.contactDensity = contactDensity; // seems to be a medium press + + // compute the checksum over the frame data. + checksum = 0; + for(int i = 0; i < data_len - 2; i++) { + checksum += ((uint8_t *) &frame->frame_packet.header)[i]; + } + frame->checksum1 = (checksum & 0xFF); + frame->checksum2 = (checksum >> 8) & 0xFF; + + s->last_frame_timestamp = elapsed_ns; + s->frame_counter += 1; + + return frame; +} + +static void ipod_touch_multitouch_inform_frame_ready(IPodTouchMultitouchState *s) { + s->sysic->gpio_int_status[4] |= (1 << 27); // the multitouch interrupt bit is in group 4 (32 interrupts per group), and the 27th of the 4th group + qemu_irq_raise(s->sysic->gpio_irqs[4]); +} + +void ipod_touch_multitouch_on_touch(IPodTouchMultitouchState *s) { + s->touch_down = true; + + s->next_frame = get_frame(s, MT_EVENT_TOUCH_START, s->touch_x, s->touch_y, 100, 660, 580, 150); + ipod_touch_multitouch_inform_frame_ready(s); + + timer_mod(s->touch_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + NANOSECONDS_PER_SECOND / 10); +} + +void ipod_touch_multitouch_on_release(IPodTouchMultitouchState *s) { + s->next_frame = get_frame(s, MT_EVENT_TOUCH_ENDED, s->touch_x, s->touch_y, 0, 0, 0, 0); + s->touch_down = false; + ipod_touch_multitouch_inform_frame_ready(s); + + timer_del(s->touch_timer); + timer_mod(s->touch_end_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + NANOSECONDS_PER_SECOND / 10); +} + +static void touch_timer_tick(void *opaque) +{ + IPodTouchMultitouchState *s = (IPodTouchMultitouchState *)opaque; + + s->next_frame = get_frame(s, MT_EVENT_TOUCH_MOVED, s->touch_x, s->touch_y, 100, 660, 580, 150); + ipod_touch_multitouch_inform_frame_ready(s); + + if(s->touch_down) { + // reschedule the timer + timer_mod(s->touch_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + NANOSECONDS_PER_SECOND / 10); + } +} + +static void touch_end_timer_tick(void *opaque) +{ + IPodTouchMultitouchState *s = (IPodTouchMultitouchState *)opaque; + s->next_frame = get_frame(s, MT_EVENT_TOUCH_FULL_END, s->touch_x, s->touch_y, 0, 0, 0, 0); + s->touch_down = false; + ipod_touch_multitouch_inform_frame_ready(s); +} + +static void ipod_touch_multitouch_realize(SSIPeripheral *d, Error **errp) +{ + IPodTouchMultitouchState *s = IPOD_TOUCH_MULTITOUCH(d); + memset(s->hbpp_atn_ack_response, 0, 2); + s->touch_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, touch_timer_tick, s); + s->touch_end_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, touch_end_timer_tick, s); + + s->prev_touch_x = 0; + s->prev_touch_y = 0; + s->last_frame_timestamp = 0; +} + +static void ipod_touch_multitouch_class_init(ObjectClass *klass, void *data) +{ + SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass); + k->realize = ipod_touch_multitouch_realize; + k->transfer = ipod_touch_multitouch_transfer; +} + +static const TypeInfo ipod_touch_multitouch_type_info = { + .name = TYPE_IPOD_TOUCH_MULTITOUCH, + .parent = TYPE_SSI_PERIPHERAL, + .instance_size = sizeof(IPodTouchMultitouchState), + .class_init = ipod_touch_multitouch_class_init, +}; + +static void ipod_touch_multitouch_register_types(void) +{ + type_register_static(&ipod_touch_multitouch_type_info); +} + +type_init(ipod_touch_multitouch_register_types) diff --git a/hw/arm/ipod_touch_nor_spi.c b/hw/arm/ipod_touch_nor_spi.c index 28a33d8c81c1..4305ee9d46e0 100644 --- a/hw/arm/ipod_touch_nor_spi.c +++ b/hw/arm/ipod_touch_nor_spi.c @@ -13,7 +13,6 @@ static uint32_t ipod_touch_nor_spi_transfer(SSIPeripheral *dev, uint32_t value) { IPodTouchNORSPIState *s = IPOD_TOUCH_NOR_SPI(dev); - printf("NOR SPI received value 0x%08x\n", value); if(value == NOR_GET_JEDECID) { printf("RECEIVED JEDCID VALUE\n"); } diff --git a/hw/arm/ipod_touch_pke.c b/hw/arm/ipod_touch_pke.c index 2559c3cd5a60..b1c0cd469ed3 100644 --- a/hw/arm/ipod_touch_pke.c +++ b/hw/arm/ipod_touch_pke.c @@ -71,7 +71,6 @@ static void ipod_touch_pke_write(void *opaque, hwaddr offset, uint64_t value, un s->num_started = 0; break; case 0x10: - printf("Seg sign: %d\n", value); break; case REG_PKE_SEG_START ... (REG_PKE_SEG_START + 1024): { @@ -83,22 +82,6 @@ static void ipod_touch_pke_write(void *opaque, hwaddr offset, uint64_t value, un { s->num_started++; - if(s->num_started == 5) { - printf("Base: 0x"); - uint32_t *cast = (uint32_t *)(&s->segments[s->segment_size]); // segment 1 - for(int i = (s->segment_size / 4 - 1); i >= 0; i--) { - printf("%08x", cast[i]); - } - printf("\n"); - - printf("Mod: 0x"); - cast = (uint32_t *)s->segments; // segment 0 - for(int i = (s->segment_size / 4 - 1); i >= 0; i--) { - printf("%08x", cast[i]); - } - printf("\n\n"); - } - if(s->num_started == 5) { // TODO this is arbitrary! @@ -112,8 +95,8 @@ static void ipod_touch_pke_write(void *opaque, hwaddr offset, uint64_t value, un BIGNUM *res = BN_new(); BN_CTX *ctx = BN_CTX_new(); BN_mod_exp(res, base_bn, exp_bn, mod_bn, ctx); - BN_print(BIO_new_fp(stdout, BIO_NOCLOSE), res); - printf("\n\n"); + // BN_print(BIO_new_fp(stdout, BIO_NOCLOSE), res); + // printf("\n\n"); char *res_hex = datahex(BN_bn2hex(res)); @@ -124,14 +107,11 @@ static void ipod_touch_pke_write(void *opaque, hwaddr offset, uint64_t value, un break; } case REG_PKE_SEG_SIZE: - printf("Setting size: %d\n", value); s->seg_size_reg = value; uint32_t size_bit = (s->seg_size_reg >> 6); if(size_bit == 0) { s->segment_size = 256; } else if(size_bit == 1) { s->segment_size = 128; } else { } - printf("Segment size: %d\n", s->segment_size); - break; case REG_PKE_SWRESET: s->num_started = 0; diff --git a/hw/arm/ipod_touch_scaler_csc.c b/hw/arm/ipod_touch_scaler_csc.c new file mode 100644 index 000000000000..c6b9bf026f1a --- /dev/null +++ b/hw/arm/ipod_touch_scaler_csc.c @@ -0,0 +1,54 @@ +#include "hw/arm/ipod_touch_scaler_csc.h" + +static uint64_t ipod_touch_scaler_csc_read(void *opaque, hwaddr addr, unsigned size) +{ + //fprintf(stderr, "%s: offset = 0x%08x\n", __func__, addr); + + switch (addr) { + default: + return 0; + } + + return 0; +} + +static void ipod_touch_scaler_csc_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) +{ + IPodTouchScalerCSCState *s = IPOD_TOUCH_SCALER_CSC(opaque); + //printf("%s (base %d): writing 0x%08x to 0x%08x\n", __func__, s->base, data, addr); +} + +static const MemoryRegionOps ipod_touch_scaler_csc_ops = { + .read = ipod_touch_scaler_csc_read, + .write = ipod_touch_scaler_csc_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void ipod_touch_scaler_csc_init(Object *obj) +{ + IPodTouchScalerCSCState *s = IPOD_TOUCH_SCALER_CSC(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &ipod_touch_scaler_csc_ops, s, TYPE_IPOD_TOUCH_SCALER_CSC, 0x1000); + sysbus_init_mmio(sbd, &s->iomem); +} + +static void ipod_touch_scaler_csc_class_init(ObjectClass *klass, void *data) +{ + +} + +static const TypeInfo ipod_touch_scaler_csc_type_info = { + .name = TYPE_IPOD_TOUCH_SCALER_CSC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IPodTouchScalerCSCState), + .instance_init = ipod_touch_scaler_csc_init, + .class_init = ipod_touch_scaler_csc_class_init, +}; + +static void ipod_touch_scaler_csc_register_types(void) +{ + type_register_static(&ipod_touch_scaler_csc_type_info); +} + +type_init(ipod_touch_scaler_csc_register_types) \ No newline at end of file diff --git a/hw/arm/ipod_touch_spi.c b/hw/arm/ipod_touch_spi.c index 380812363cbe..4de86d092800 100644 --- a/hw/arm/ipod_touch_spi.c +++ b/hw/arm/ipod_touch_spi.c @@ -280,8 +280,8 @@ static void ipod_touch_spi_realize(DeviceState *dev, struct Error **errp) sysbus_init_mmio(sbd, &s->iomem); s->base = base_addr; - fifo8_create(&s->tx_fifo, R_FIFO_DEPTH); - fifo8_create(&s->rx_fifo, R_FIFO_DEPTH); + fifo8_create(&s->tx_fifo, R_FIFO_TX_DEPTH); + fifo8_create(&s->rx_fifo, R_FIFO_RX_DEPTH); // create the peripheral IPodTouchNORSPIState *nor; @@ -296,11 +296,11 @@ static void ipod_touch_spi_realize(DeviceState *dev, struct Error **errp) nor = IPOD_TOUCH_NOR_SPI(dev); s->nor = nor; break; - case 2: + case 4: { - // DeviceState *dev = ssi_create_peripheral(s->spi, TYPE_IPOD_TOUCH_MULTITOUCH); - // IPodTouchMultitouchState *mt = IPOD_TOUCH_MULTITOUCH(dev); - // s->mt = mt; + DeviceState *dev = ssi_create_peripheral(s->spi, TYPE_IPOD_TOUCH_MULTITOUCH); + IPodTouchMultitouchState *mt = IPOD_TOUCH_MULTITOUCH(dev); + s->mt = mt; break; } } diff --git a/hw/arm/meson.build b/hw/arm/meson.build index fd7cc9604069..98b2d625a57e 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -62,6 +62,6 @@ arm_ss.add(when: 'CONFIG_FSL_IMX7', if_true: files('fsl-imx7.c', 'mcimx7d-sabre. arm_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c', 'smmuv3.c')) arm_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c')) arm_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c')) -arm_ss.add(when: 'CONFIG_IPOD_TOUCH_2G', if_true: files('ipod_touch_2g.c', 'ipod_touch_clock.c', 'ipod_touch_chipid.c', 'ipod_touch_gpio.c', 'ipod_touch_sysic.c', 'ipod_touch_timer.c', 'ipod_touch_usb_otg.c', 'ipod_touch_usb_phys.c', 'ipod_touch_spi.c', 'ipod_touch_nor_spi.c', 'ipod_touch_sha1.c', 'ipod_touch_aes.c', 'ipod_touch_pke.c', 'ipod_touch_pcf50633_pmu.c', 'ipod_touch_unknown1.c', 'ipod_touch_lcd.c', 'ipod_touch_mipi_dsi.c', 'ipod_touch_fmss.c', 'ipod_touch_block_device.c', 'ipod_touch_mbx.c', 'ipod_touch_cd3272_mikey.c', 'ipod_touch_lis302dl.c')) +arm_ss.add(when: 'CONFIG_IPOD_TOUCH_2G', if_true: files('ipod_touch_2g.c', 'ipod_touch_clock.c', 'ipod_touch_chipid.c', 'ipod_touch_gpio.c', 'ipod_touch_sysic.c', 'ipod_touch_timer.c', 'ipod_touch_usb_otg.c', 'ipod_touch_usb_phys.c', 'ipod_touch_spi.c', 'ipod_touch_nor_spi.c', 'ipod_touch_sha1.c', 'ipod_touch_aes.c', 'ipod_touch_pke.c', 'ipod_touch_pcf50633_pmu.c', 'ipod_touch_unknown1.c', 'ipod_touch_lcd.c', 'ipod_touch_mipi_dsi.c', 'ipod_touch_fmss.c', 'ipod_touch_block_device.c', 'ipod_touch_mbx.c', 'ipod_touch_cd3272_mikey.c', 'ipod_touch_lis302dl.c', 'ipod_touch_multitouch.c', 'ipod_touch_scaler_csc.c')) hw_arch += {'arm': arm_ss} diff --git a/hw/dma/pl080.c b/hw/dma/pl080.c index e9cb8140c76d..4097e9281485 100644 --- a/hw/dma/pl080.c +++ b/hw/dma/pl080.c @@ -391,8 +391,10 @@ static void pl080_init(Object *obj) SysBusDevice *sbd = SYS_BUS_DEVICE(obj); PL080State *s = PL080(obj); - memory_region_init_io(&s->iomem, OBJECT(s), &pl080_ops, s, "pl080", 0x1000); - sysbus_init_mmio(sbd, &s->iomem); + memory_region_init_io(&s->iomem1, OBJECT(s), &pl080_ops, s, "pl080", 0x1000); + sysbus_init_mmio(sbd, &s->iomem1); + memory_region_init_io(&s->iomem2, OBJECT(s), &pl080_ops, s, "pl080", 0x1000); + sysbus_init_mmio(sbd, &s->iomem2); sysbus_init_irq(sbd, &s->irq); sysbus_init_irq(sbd, &s->interr); sysbus_init_irq(sbd, &s->inttc); diff --git a/include/hw/arm/ipod_touch_2g.h b/include/hw/arm/ipod_touch_2g.h index 2e095fd72a64..6969fc6dc15f 100644 --- a/include/hw/arm/ipod_touch_2g.h +++ b/include/hw/arm/ipod_touch_2g.h @@ -25,6 +25,7 @@ #include "hw/arm/ipod_touch_fmss.h" #include "hw/arm/ipod_touch_block_device.h" #include "hw/arm/ipod_touch_mbx.h" +#include "hw/arm/ipod_touch_scaler_csc.h" #define TYPE_IPOD_TOUCH "iPod-Touch" @@ -62,6 +63,7 @@ #define SHA1_MEM_BASE 0x38000000 #define DMAC0_MEM_BASE 0x38200000 #define USBOTG_MEM_BASE 0x38400000 +#define DMAC1_0_MEM_BASE 0x38700000 #define DISPLAY_MEM_BASE 0x38900000 #define FMSS_MEM_BASE 0x38A00000 #define BLOCK_DEVICE_MEM_BASE 0x38A00F00 @@ -71,12 +73,13 @@ #define VIC1_MEM_BASE 0x38E01000 #define EDGEIC_MEM_BASE 0x38E02000 #define H264_MEM_BASE 0x38F00000 +#define SCALER_CSC_MEM_BASE 0x39000000 #define TVOUT1_MEM_BASE 0x39100000 #define TVOUT2_MEM_BASE 0x39200000 #define TVOUT3_MEM_BASE 0x39300000 //#define BLOCK_DEVICE_MEM_BASE 0x39400000 #define SYSIC_MEM_BASE 0x39700000 -#define DMAC1_MEM_BASE 0x39900000 +#define DMAC1_1_MEM_BASE 0x39900000 #define MBX1_MEM_BASE 0x3B000000 #define MBX2_MEM_BASE 0x39400000 #define SPI0_MEM_BASE 0x3C300000 @@ -117,6 +120,7 @@ typedef struct { IPodTouchTimerState *timer1; IPodTouchSPIState *spi0_state; IPodTouchSPIState *spi1_state; + IPodTouchSPIState *spi4_state; IPodTouchChipIDState *chipid_state; IPodTouchGPIOState *gpio_state; IPodTouchSYSICState *sysic; @@ -132,6 +136,7 @@ typedef struct { IPodTouchFMSSState *fmss_state; IPodTouchBlockDeviceState *bdev_state; IPodTouchMBXState *mbx_state; + IPodTouchScalerCSCState *scaler_csc_state; Clock *sysclk; char nor_path[1024]; IT2G_CPREG_VAR_DEF(REG0); diff --git a/include/hw/arm/ipod_touch_lcd.h b/include/hw/arm/ipod_touch_lcd.h index b2c86d3c2da9..be60582d407e 100644 --- a/include/hw/arm/ipod_touch_lcd.h +++ b/include/hw/arm/ipod_touch_lcd.h @@ -11,11 +11,25 @@ #define TYPE_IPOD_TOUCH_LCD "ipodtouch.lcd" OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchLCDState, IPOD_TOUCH_LCD) +#define LCD_REFRESH_RATE_FREQUENCY 10 + typedef struct IPodTouchLCDState { SysBusDevice parent_obj; + MemoryRegion *sysmem; MemoryRegion iomem; + QemuConsole *con; + int invalidate; + MemoryRegionSection fbsection; qemu_irq irq; + uint32_t lcd_con; + + uint32_t w1_display_resolution_info; + uint32_t w1_framebuffer_base; + uint32_t w1_hspan; + uint32_t w1_display_depth_info; + + QEMUTimer *refresh_timer; } IPodTouchLCDState; #endif \ No newline at end of file diff --git a/include/hw/arm/ipod_touch_multitouch.h b/include/hw/arm/ipod_touch_multitouch.h new file mode 100644 index 000000000000..f48972d4b503 --- /dev/null +++ b/include/hw/arm/ipod_touch_multitouch.h @@ -0,0 +1,160 @@ +#ifndef IPOD_TOUCH_MULTITOUCH_H +#define IPOD_TOUCH_MULTITOUCH_H + +#include "qemu/osdep.h" +#include "qemu/module.h" +#include "qemu/timer.h" +#include "qapi/error.h" +#include "hw/hw.h" +#include "hw/ssi/ssi.h" +#include "hw/arm/ipod_touch_sysic.h" +#include "hw/arm/ipod_touch_gpio.h" + +#define TYPE_IPOD_TOUCH_MULTITOUCH "ipodtouch.multitouch" +OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchMultitouchState, IPOD_TOUCH_MULTITOUCH) + +#define MT_INTERFACE_VERSION 0x1 +#define MT_FAMILY_ID 81 +#define MT_ENDIANNESS 0x1 +#define MT_SENSOR_ROWS 15 +#define MT_SENSOR_COLUMNS 10 +#define MT_BCD_VERSION 51 +#define MT_SENSOR_REGION_DESC 0x0 +#define MT_SENSOR_REGION_PARAM 0x0 +#define MT_MAX_PACKET_SIZE 0x294 // 660 +#define MT_SENSOR_SURFACE_WIDTH 5000 +#define MT_SENSOR_SURFACE_HEIGHT 7500 + +// internal surface width/height +#define MT_INTERNAL_SENSOR_SURFACE_WIDTH (9000 - MT_SENSOR_SURFACE_WIDTH) * 84 / 73 +#define MT_INTERNAL_SENSOR_SURFACE_HEIGHT (13850 - MT_SENSOR_SURFACE_HEIGHT) * 84 / 73 + +// report IDs +#define MT_REPORT_UNKNOWN1 0x70 +#define MT_REPORT_FAMILY_ID 0xD1 +#define MT_REPORT_SENSOR_INFO 0xD3 +#define MT_REPORT_SENSOR_REGION_DESC 0xD0 +#define MT_REPORT_SENSOR_REGION_PARAM 0xA1 +#define MT_REPORT_SENSOR_DIMENSIONS 0xD9 + +// report sizes +#define MT_REPORT_UNKNOWN1_SIZE 0x1 +#define MT_REPORT_FAMILY_ID_SIZE 0x1 +#define MT_REPORT_SENSOR_INFO_SIZE 0x5 +#define MT_REPORT_SENSOR_REGION_DESC_SIZE 0x1 +#define MT_REPORT_SENSOR_REGION_PARAM_SIZE 0x1 +#define MT_REPORT_SENSOR_DIMENSIONS_SIZE 0x8 + +#define MT_CMD_HBPP_DATA_PACKET 0x30 +#define MT_CMD_GET_CMD_STATUS 0xE1 +#define MT_CMD_GET_INTERFACE_VERSION 0xE2 +#define MT_CMD_GET_REPORT_INFO 0xE3 +#define MT_CMD_SHORT_CONTROL_WRITE 0xE4 +#define MT_CMD_SHORT_CONTROL_READ 0xE6 +#define MT_CMD_FRAME_READ 0xEA + +// frame types +#define MT_FRAME_TYPE_PATH 0x44 + +// frame event types +#define MT_EVENT_TOUCH_FULL_END 0x0 +#define MT_EVENT_TOUCH_START 0x3 +#define MT_EVENT_TOUCH_MOVED 0x4 +#define MT_EVENT_TOUCH_ENDED 0x7 + +typedef struct MTFrameLengthPacket +{ + uint8_t cmd; + uint8_t length1; + uint8_t length2; + uint8_t unused[11]; + uint8_t checksum1; + uint8_t checksum2; +} __attribute__((__packed__)) MTFrameLengthPacket; + +typedef struct MTFrameHeader +{ + uint8_t type; + uint8_t frameNum; + uint8_t headerLen; + uint8_t unk_3; + uint32_t timestamp; + uint8_t unk_8; + uint8_t unk_9; + uint8_t unk_A; + uint8_t unk_B; + uint16_t unk_C; + uint16_t isImage; + + uint8_t numFingers; + uint8_t fingerDataLen; + uint16_t unk_12; + uint16_t unk_14; + uint16_t unk_16; +} __attribute__((__packed__)) MTFrameHeader; + +typedef struct MTFramePacket +{ + uint8_t cmd; + uint8_t unused1; + uint8_t length1; + uint8_t length2; + uint8_t checksum_pad; + MTFrameHeader header; +} __attribute__((__packed__)) MTFramePacket; + +typedef struct FingerData +{ + uint8_t id; + uint8_t event; + uint8_t unk_2; + uint8_t unk_3; + int16_t x; + int16_t y; + int16_t velX; + int16_t velY; + uint16_t radius2; + uint16_t radius3; + uint16_t angle; + uint16_t radius1; + uint16_t contactDensity; + uint16_t unk_16; + uint16_t unk_18; + uint16_t unk_1A; +} __attribute__((__packed__)) FingerData; + +typedef struct MTFrame { + MTFrameLengthPacket frame_length; + MTFramePacket frame_packet; + FingerData finger_data; // TODO we assume one finger for now + uint8_t checksum1; + uint8_t checksum2; +} __attribute__((__packed__)) MTFrame; + +typedef struct IPodTouchMultitouchState { + SSIPeripheral ssidev; + uint8_t cur_cmd; + uint8_t *out_buffer; + uint8_t *in_buffer; + uint32_t buf_size; + uint32_t buf_ind; + uint32_t in_buffer_ind; + uint8_t hbpp_atn_ack_response[2]; + MTFrame *next_frame; + uint32_t frame_counter; + bool touch_down; + QEMUTimer *touch_timer; + QEMUTimer *touch_end_timer; + IPodTouchSYSICState *sysic; + IPodTouchGPIOState *gpio_state; + float touch_x; + float touch_y; + float prev_touch_x; + float prev_touch_y; + uint64_t last_frame_timestamp; +} IPodTouchMultitouchState; + +void ipod_touch_multitouch_on_touch(IPodTouchMultitouchState *s); +void ipod_touch_multitouch_on_release(IPodTouchMultitouchState *s); + +#endif \ No newline at end of file diff --git a/include/hw/arm/ipod_touch_scaler_csc.h b/include/hw/arm/ipod_touch_scaler_csc.h new file mode 100644 index 000000000000..0fcb257cc67e --- /dev/null +++ b/include/hw/arm/ipod_touch_scaler_csc.h @@ -0,0 +1,19 @@ +#ifndef HW_ARM_IPOD_TOUCH_SCALER_CSC_H +#define HW_ARM_IPOD_TOUCH_SCALER_CSC_H + +#include "qemu/osdep.h" +#include "hw/platform-bus.h" +#include "hw/hw.h" +#include "exec/hwaddr.h" +#include "exec/memory.h" + +#define TYPE_IPOD_TOUCH_SCALER_CSC "ipodtouch.scalercsc" +OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchScalerCSCState, IPOD_TOUCH_SCALER_CSC) + + +typedef struct IPodTouchScalerCSCState { + SysBusDevice busdev; + MemoryRegion iomem; +} IPodTouchScalerCSCState; + +#endif \ No newline at end of file diff --git a/include/hw/arm/ipod_touch_spi.h b/include/hw/arm/ipod_touch_spi.h index 688f81262700..515fb67b23f0 100644 --- a/include/hw/arm/ipod_touch_spi.h +++ b/include/hw/arm/ipod_touch_spi.h @@ -9,6 +9,7 @@ #include "hw/irq.h" #include "hw/ssi/ssi.h" #include "hw/arm/ipod_touch_nor_spi.h" +#include "hw/arm/ipod_touch_multitouch.h" #define TYPE_IPOD_TOUCH_SPI "ipodtouch.spi" OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchSPIState, IPOD_TOUCH_SPI) @@ -49,7 +50,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchSPIState, IPOD_TOUCH_SPI) #define R_WORD_DELAY 0x038 #define R_TXCNT 0x04c -#define R_FIFO_DEPTH 16 +#define R_FIFO_TX_DEPTH 50000 +#define R_FIFO_RX_DEPTH 16 #define REG(_s,_v) ((_s)->regs[(_v)>>2]) #define MMIO_SIZE (0x4000) @@ -60,16 +62,17 @@ typedef struct IPodTouchSPIState { MemoryRegion iomem; SSIBus *spi; + IPodTouchMultitouchState *mt; qemu_irq irq; uint32_t last_irq; qemu_irq cs_line; - Fifo8 rx_fifo; - Fifo8 tx_fifo; uint32_t regs[MMIO_SIZE >> 2]; uint8_t base; IPodTouchNORSPIState *nor; + Fifo8 rx_fifo; + Fifo8 tx_fifo; } IPodTouchSPIState; void set_spi_base(uint32_t base); diff --git a/include/hw/dma/pl080.h b/include/hw/dma/pl080.h index 3c9659e4381f..caf06c295d2e 100644 --- a/include/hw/dma/pl080.h +++ b/include/hw/dma/pl080.h @@ -49,7 +49,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(PL080State, PL080) struct PL080State { SysBusDevice parent_obj; - MemoryRegion iomem; + MemoryRegion iomem1; + MemoryRegion iomem2; uint8_t tc_int; uint8_t tc_mask; uint8_t err_int; From 1744cb29cf1d8e61638452769ad074d5d628af03 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Wed, 12 Jul 2023 20:38:20 +0200 Subject: [PATCH 27/58] Multiple fixes for SPI --- hw/arm/ipod_touch_2g.c | 2 +- hw/arm/ipod_touch_fmss.c | 7 +----- hw/arm/ipod_touch_nor_spi.c | 34 ++++++++++++++++++++++++----- hw/arm/ipod_touch_spi.c | 18 ++++++++------- include/hw/arm/ipod_touch_nor_spi.h | 6 +++++ 5 files changed, 46 insertions(+), 21 deletions(-) diff --git a/hw/arm/ipod_touch_2g.c b/hw/arm/ipod_touch_2g.c index 90a9502e2679..d70067744186 100644 --- a/hw/arm/ipod_touch_2g.c +++ b/hw/arm/ipod_touch_2g.c @@ -250,7 +250,7 @@ static void ipod_touch_machine_init(MachineState *machine) dev = sysbus_create_simple("ipodtouch.spi", SPI1_MEM_BASE, s5l8900_get_irq(nms, S5L8720_SPI1_IRQ)); IPodTouchSPIState *spi1_state = IPOD_TOUCH_SPI(dev); nms->spi1_state = spi1_state; - strcpy(spi1_state->nor->nor_path, nms->nor_path); + //strcpy(spi1_state->nor->nor_path, nms->nor_path); set_spi_base(2); sysbus_create_simple("ipodtouch.spi", SPI2_MEM_BASE, s5l8900_get_irq(nms, S5L8720_SPI2_IRQ)); diff --git a/hw/arm/ipod_touch_fmss.c b/hw/arm/ipod_touch_fmss.c index 10751109460a..48d88587fb25 100644 --- a/hw/arm/ipod_touch_fmss.c +++ b/hw/arm/ipod_touch_fmss.c @@ -68,13 +68,8 @@ static void read_nand_pages(IPodTouchFMSSState *s) // aux_data[1] = 0xc0db0640; // NAND FTL object cpu_physical_memory_write(0x858fdd4 + 0x5C, (uint8_t *)aux_data, 4); - // TEMP - replace the IOService wait - data[0] = 0x00BF; - cpu_physical_memory_write(0x8176482, (uint8_t *)data, 2); - - // boot args - char *boot_args = "kextlog=0xfff debug=0x8 cpus=1 rd=disk0s1 serial=1 io=0xffffffff debug-usb=0xffffffff"; + char *boot_args = "kextlog=0xfff debug=0x8 cpus=1 rd=disk0s1 serial=1 io=0xffff8fff debug-usb=0xffffffff"; cpu_physical_memory_write(0x0ff2a584, boot_args, strlen(boot_args)); for(int page_ind = 0; page_ind < s->reg_num_pages; page_ind++) { diff --git a/hw/arm/ipod_touch_nor_spi.c b/hw/arm/ipod_touch_nor_spi.c index 4305ee9d46e0..aedd2b6c381e 100644 --- a/hw/arm/ipod_touch_nor_spi.c +++ b/hw/arm/ipod_touch_nor_spi.c @@ -13,10 +13,6 @@ static uint32_t ipod_touch_nor_spi_transfer(SSIPeripheral *dev, uint32_t value) { IPodTouchNORSPIState *s = IPOD_TOUCH_NOR_SPI(dev); - if(value == NOR_GET_JEDECID) { - printf("RECEIVED JEDCID VALUE\n"); - } - if(s->cur_cmd == NOR_READ_DATA_CMD && s->in_buf_cur_ind == s->in_buf_size && value != 0xFF) { // if we are currently reading from the NOR data and we receive a value that's not the sentinel, reset the current command. s->cur_cmd = 0; @@ -25,23 +21,48 @@ static uint32_t ipod_touch_nor_spi_transfer(SSIPeripheral *dev, uint32_t value) if(s->cur_cmd == 0) { // this is a new command -> set it s->cur_cmd = value; + printf("NEW CMD %d\n", s->cur_cmd); s->out_buf = malloc(0x1000); - s->in_buf = malloc(0x100); + s->in_buf = malloc(0x1000); s->in_buf[0] = value; s->in_buf_size = 0; s->in_buf_cur_ind = 1; s->out_buf_cur_ind = 0; - if(value == NOR_GET_STATUS_CMD) { + if(value == NOR_WRITE_TO_STATUS_REG) { s->in_buf_size = 1; s->out_buf_size = 1; s->out_buf[0] = 0; } + else if(value == NOR_GET_STATUS_CMD) { + printf("GET STATUS\n"); + s->in_buf_size = 1; + s->out_buf_size = 1; + s->out_buf[0] = 0; + } + else if(value == NOR_WRITE_DATA_CMD) { + s->in_buf_size = 4; + s->out_buf_size = 256; + for(int i = 0; i < 256; i++) { s->out_buf[i] = 0; }; // TODO we ignore this command for now + } else if(value == NOR_READ_DATA_CMD) { printf("Received read command!\n"); s->in_buf_size = 4; s->out_buf_size = 4096; } + else if(value == NOR_ERASE_BLOCK) { + s->in_buf_size = 1; + s->out_buf_size = 3; + for(int i = 0; i < 3; i++) { s->out_buf[i] = 0x0; } // TODO we ignore this command for now + } + else if(value == NOR_ENABLE_WRITE) { + s->write_enabled = 1; + s->cur_cmd = 0; + } + else if(value == NOR_DISABLE_WRITE) { + s->write_enabled = 0; + s->cur_cmd = 0; + } else if(value == NOR_GET_JEDECID) { s->in_buf_size = 1; s->out_buf_size = 3; @@ -50,6 +71,7 @@ static uint32_t ipod_touch_nor_spi_transfer(SSIPeripheral *dev, uint32_t value) s->out_buf[2] = 0x02; } else { + printf("Unknown command %d!\n", value); hw_error("Unknown command 0x%02x!", value); } diff --git a/hw/arm/ipod_touch_spi.c b/hw/arm/ipod_touch_spi.c index 4de86d092800..a8b1cabb4c89 100644 --- a/hw/arm/ipod_touch_spi.c +++ b/hw/arm/ipod_touch_spi.c @@ -94,6 +94,9 @@ static void apple_spi_run(IPodTouchSPIState *s) apple_spi_update_xfer_tx(s); + //printf("TX queue: %d, RX queue: %d\n", REG(s, R_TXCNT), REG(s, R_RXCNT)); + //printf("TX buffer size: %d, RX buffer size: %d\n", fifo8_num_used(&s->tx_fifo), fifo8_num_used(&s->rx_fifo)); + while (REG(s, R_TXCNT) && !fifo8_is_empty(&s->tx_fifo)) { tx = (uint32_t)fifo8_pop(&s->tx_fifo); rx = ssi_transfer(s->spi, tx); @@ -129,6 +132,8 @@ static void apple_spi_run(IPodTouchSPIState *s) if (REG(s, R_RXCNT) == 0 && REG(s, R_TXCNT) == 0) { REG(s, R_STATUS) |= R_STATUS_COMPLETE; } + + //printf(" TX buffer size: %d, RX buffer size: %d\n", fifo8_num_used(&s->tx_fifo), fifo8_num_used(&s->rx_fifo)); } static uint64_t ipod_touch_spi_read(void *opaque, hwaddr addr, unsigned size) @@ -201,6 +206,7 @@ static void ipod_touch_spi_write(void *opaque, hwaddr addr, uint64_t data, unsig } break; case R_STATUS: + run = true; r = old & (~r); break; case R_PIN: @@ -208,12 +214,8 @@ static void ipod_touch_spi_write(void *opaque, hwaddr addr, uint64_t data, unsig break; case R_TXDATA ... R_TXDATA + 3: { int word_size = apple_spi_word_size(s); - if ((fifo8_is_full(&s->tx_fifo)) - || (fifo8_num_free(&s->tx_fifo) < word_size)) { + if (fifo8_is_full(&s->tx_fifo) || fifo8_num_free(&s->tx_fifo) < word_size) { hw_error("Tx buffer overflow: %d\n", fifo8_num_free(&s->tx_fifo)); - qemu_log_mask(LOG_GUEST_ERROR, "%s: tx overflow\n", __func__); - r = 0; - break; } fifo8_push_all(&s->tx_fifo, (uint8_t *)&r, word_size); break; @@ -292,9 +294,9 @@ static void ipod_touch_spi_realize(DeviceState *dev, struct Error **errp) s->nor = nor; break; case 1: - ssi_create_peripheral(s->spi, TYPE_IPOD_TOUCH_NOR_SPI); - nor = IPOD_TOUCH_NOR_SPI(dev); - s->nor = nor; + //ssi_create_peripheral(s->spi, TYPE_IPOD_TOUCH_NOR_SPI); + //nor = IPOD_TOUCH_NOR_SPI(dev); + //s->nor = nor; break; case 4: { diff --git a/include/hw/arm/ipod_touch_nor_spi.h b/include/hw/arm/ipod_touch_nor_spi.h index 6e48d9634d54..1f4a87d497a3 100644 --- a/include/hw/arm/ipod_touch_nor_spi.h +++ b/include/hw/arm/ipod_touch_nor_spi.h @@ -10,8 +10,13 @@ #define TYPE_IPOD_TOUCH_NOR_SPI "ipodtouch.norspi" OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchNORSPIState, IPOD_TOUCH_NOR_SPI) +#define NOR_WRITE_TO_STATUS_REG 0x1 +#define NOR_WRITE_DATA_CMD 0x2 #define NOR_READ_DATA_CMD 0x3 +#define NOR_DISABLE_WRITE 0x4 #define NOR_GET_STATUS_CMD 0x5 +#define NOR_ENABLE_WRITE 0x6 +#define NOR_ERASE_BLOCK 0x20 #define NOR_GET_JEDECID 0x9F typedef struct IPodTouchNORSPIState { @@ -24,6 +29,7 @@ typedef struct IPodTouchNORSPIState { uint32_t in_buf_cur_ind; uint32_t out_buf_cur_ind; uint8_t *nor_data; + uint8_t write_enabled; uint32_t nor_read_ind; char nor_path[1024]; bool nor_initialized; From dd673b69f5ed26551dcc258a71e045da94a7c3f3 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Thu, 27 Jul 2023 16:28:07 +0200 Subject: [PATCH 28/58] Booting SpringBoard --- hw/arm/ipod_touch_aes.c | 1 + hw/arm/ipod_touch_fmss.c | 98 ++++++++++++-------------------- hw/arm/ipod_touch_mbx.c | 4 +- include/hw/arm/ipod_touch_fmss.h | 4 +- 4 files changed, 42 insertions(+), 65 deletions(-) diff --git a/hw/arm/ipod_touch_aes.c b/hw/arm/ipod_touch_aes.c index 6961d19be5c9..146b734adbea 100644 --- a/hw/arm/ipod_touch_aes.c +++ b/hw/arm/ipod_touch_aes.c @@ -111,6 +111,7 @@ static void ipod_touch_aes_write(void *opaque, hwaddr offset, uint64_t value, un if(aesop->outaddr == 0x0bf00020) { uint32_t *cast_buf = (uint32_t *)buf; cast_buf[8429] = 0x4; // setting the size of the AAPL,phandle property to 4 + cast_buf[8430] = 0x0011C4F0; // set the right handle } cpu_physical_memory_write((aesop->outaddr), buf, aesop->insize); diff --git a/hw/arm/ipod_touch_fmss.c b/hw/arm/ipod_touch_fmss.c index 48d88587fb25..66691c1821ca 100644 --- a/hw/arm/ipod_touch_fmss.c +++ b/hw/arm/ipod_touch_fmss.c @@ -7,6 +7,15 @@ static uint32_t reverse_byte_order(uint32_t value) { ((value & 0xFF000000) >> 24); } +static uint8_t find_bit_index(uint8_t num) { + int index = 0; + while (num > 1) { + num >>= 1; + index++; + } + return index; +} + static void write_chip_info(IPodTouchFMSSState *s) { uint32_t chipid[] = { 0xb614d5ad, 0xb614d5ad, 0xb614d5ad, 0xb614d5ad }; @@ -15,79 +24,31 @@ static void write_chip_info(IPodTouchFMSSState *s) static void read_nand_pages(IPodTouchFMSSState *s) { - // patch the FTL_Read method in iBoot - uint16_t *data = malloc(sizeof(uint16_t) * 9); - data[0] = 0xB500; // push {lr} - data[1] = 0x4B14; // ldr r3, [pc, #0x50] - data[2] = 0x6018; // str r0, [r3] - data[3] = 0x3304; // adds r3, #4 - data[4] = 0x6019; // str r1, [r3] - data[5] = 0x3304; // adds r3, #4 - data[6] = 0x601A; // str r2, [r3] -> this will trigger the block loading - data[7] = 0x2000; // movs r0, #0 - data[8] = 0xBD00; // pop {pc} - cpu_physical_memory_write(0x0ff02d1c, (uint8_t *)data, 18); - - uint32_t *block_driver_addr = malloc(sizeof(uint32_t) * 1); - block_driver_addr[0] = 0x38A00F00; - cpu_physical_memory_write(0x0ff02d1c + 0x54, (uint8_t *)block_driver_addr, 4); - - // patch the FTL_Read method in the kernel (which is not in thumb) - uint32_t *data2 = malloc(sizeof(uint32_t) * 20); - data2[0] = reverse_byte_order(0xf0402de9); // push on stack - - // store the block number and number of blocks in the block driver - data2[1] = reverse_byte_order(0x50309FE5); // ldr r3, [pc, #0x50] - data2[2] = reverse_byte_order(0x000083E5); // str r0, [r3] - data2[3] = reverse_byte_order(0x043093E2); // adds r3, #4 - data2[4] = reverse_byte_order(0x001083E5); // str r1, [r3] - data2[5] = reverse_byte_order(0x043093E2); // adds r3, #4 - - // get the physical address of the current io_buffer of the NANDFTL - data2[6] = reverse_byte_order(0x0500A0E1); // mov r0,r5 -> load the AppleNANDFTL object, which seems to reside in r5 - data2[7] = reverse_byte_order(0x001190E5); // ldr r1, [r0,#0x100] -> load the io_buffer object - data2[8] = reverse_byte_order(0x002091E5); // ldr r2,[r1,#0x0] -> load the vtable of the io_buffer - data2[9] = reverse_byte_order(0x0100A0E1); // mov r0,r1 -> make the io_buffer object the first parameter - data2[10] = reverse_byte_order(0x0010A0E3); // mov r1,#0 -> set the second parameter to 0 - data2[11] = reverse_byte_order(0x0340A0E1); // mov r4,r3 -> make sure our block driver address is safe because r3 will be overridden - data2[12] = reverse_byte_order(0x0FE0A0E1); // mov lr,pc - data2[13] = reverse_byte_order(0x98F092E5); // ldr pc,[r2,#0x98] -> jump to the getPhysicalSegment function - - // store the address - data2[14] = reverse_byte_order(0x000084E5); // str r0, [r4] -> this will trigger the block loading - - // return - data2[15] = reverse_byte_order(0x0000B0E3); // movs r0, #0 - data2[16] = reverse_byte_order(0xf080bde8); // pop from stack - - cpu_physical_memory_write(0x858fdd4, (uint8_t *)data2, sizeof(uint32_t) * 17); - - // aux data - uint32_t *aux_data = malloc(sizeof(uint32_t) * 20); - aux_data[0] = 0xE366aF00; // virtual address of the block driver - // aux_data[1] = 0xc0db0640; // NAND FTL object - cpu_physical_memory_write(0x858fdd4 + 0x5C, (uint8_t *)aux_data, 4); - // boot args - char *boot_args = "kextlog=0xfff debug=0x8 cpus=1 rd=disk0s1 serial=1 io=0xffff8fff debug-usb=0xffffffff"; + char *boot_args = "kextlog=0xfff debug=0x8 cpus=1 rd=disk0s1 serial=1 pmu-debug=0x1 io=0xffff8fff debug-usb=0xffffffff"; cpu_physical_memory_write(0x0ff2a584, boot_args, strlen(boot_args)); + int page_out_buf_ind = 0; for(int page_ind = 0; page_ind < s->reg_num_pages; page_ind++) { uint32_t page_nr = 0; uint32_t page_out_addr = 0; - cpu_physical_memory_read(s->reg_pages_in_addr + page_ind, &page_nr, 0x4); - cpu_physical_memory_read(s->reg_pages_out_addr + page_ind, &page_out_addr, 0x4); - - //printf("Will read page %d into address 0x%08x and spare into address 0x%08x\n", page_nr, page_out_addr, s->reg_page_spare_out_addr); + uint32_t cs = 0; + cpu_physical_memory_read(s->reg_pages_in_addr + (page_ind * sizeof(uint32_t)), &page_nr, sizeof(uint32_t)); + + cpu_physical_memory_read(s->reg_cs_buf_addr + (page_ind * sizeof(uint32_t)), &cs, sizeof(uint32_t)); + cs = find_bit_index(cs); // prepare the page char filename[200]; - sprintf(filename, "/Users/martijndevos/Documents/generate_nand_it2g/nand/%d.page", page_nr); + sprintf(filename, "/Users/martijndevos/Documents/generate_nand_it2g/nand/cs%d/%d.page", cs, page_nr); struct stat st = {0}; if (stat(filename, &st) == -1) { // page storage does not exist - initialize an empty buffer memset(s->page_buffer, 0, NAND_BYTES_PER_PAGE); memset(s->page_spare_buffer, 0, NAND_BYTES_PER_SPARE); + + uint32_t *buf_cst = (uint32_t *) s->page_spare_buffer; + buf_cst[2] = 0x00FF00FF; } else { FILE *f = fopen(filename, "rb"); @@ -97,8 +58,18 @@ static void read_nand_pages(IPodTouchFMSSState *s) fclose(f); } - cpu_physical_memory_write(page_out_addr, s->page_buffer, NAND_BYTES_PER_PAGE); - cpu_physical_memory_write(s->reg_page_spare_out_addr, s->page_spare_buffer, NAND_BYTES_PER_SPARE); + // we write away the page in two parts, 2048 bytes first and then the other 2048 bytes. + int write_buf_size = NAND_BYTES_PER_PAGE / 2; + for(int i = 0; i < 2; i++) { + cpu_physical_memory_read(s->reg_pages_out_addr + (page_out_buf_ind * sizeof(uint32_t)), &page_out_addr, sizeof(uint32_t)); + cpu_physical_memory_write(page_out_addr, s->page_buffer + i * write_buf_size, write_buf_size); + // printf("Will read page %d @ cs %d into address 0x%08x and spare into address 0x%08x\n", page_nr, cs, page_out_addr, s->reg_page_spare_out_addr); + page_out_buf_ind++; + + } + + // finally, write the spare + cpu_physical_memory_write(s->reg_page_spare_out_addr + page_ind * 0xc, s->page_spare_buffer, NAND_BYTES_PER_SPARE); } } @@ -129,7 +100,7 @@ static uint64_t ipod_touch_fmss_read(void *opaque, hwaddr addr, unsigned size) static void ipod_touch_fmss_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { IPodTouchFMSSState *s = (IPodTouchFMSSState *)opaque; - fprintf(stderr, "%s: writing 0x%08x to 0x%08x\n", __func__, val, addr); + //printf("%s: writing 0x%08x to 0x%08x\n", __func__, val, addr); switch(addr) { case 0xC00: @@ -147,6 +118,9 @@ static void ipod_touch_fmss_write(void *opaque, hwaddr addr, uint64_t val, unsig case FMSS_PAGES_IN_ADDR: s->reg_pages_in_addr = val; break; + case FMSS_CS_BUF_ADDR: + s->reg_cs_buf_addr = val; + break; case FMSS_NUM_PAGES: s->reg_num_pages = val; break; diff --git a/hw/arm/ipod_touch_mbx.c b/hw/arm/ipod_touch_mbx.c index 47ecaabe8b4e..974a6fde1c46 100644 --- a/hw/arm/ipod_touch_mbx.c +++ b/hw/arm/ipod_touch_mbx.c @@ -57,9 +57,9 @@ static void ipod_touch_mbx_init(Object *obj) IPodTouchMBXState *s = IPOD_TOUCH_MBX(obj); SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - memory_region_init_io(&s->iomem1, obj, &ipod_touch_mbx1_ops, s, TYPE_IPOD_TOUCH_MBX, 0x10000); + memory_region_init_io(&s->iomem1, obj, &ipod_touch_mbx1_ops, s, TYPE_IPOD_TOUCH_MBX, 0x1000000); sysbus_init_mmio(sbd, &s->iomem1); - memory_region_init_io(&s->iomem2, obj, &ipod_touch_mbx2_ops, s, TYPE_IPOD_TOUCH_MBX, 0x10000); + memory_region_init_io(&s->iomem2, obj, &ipod_touch_mbx2_ops, s, TYPE_IPOD_TOUCH_MBX, 0x1000); sysbus_init_mmio(sbd, &s->iomem2); } diff --git a/include/hw/arm/ipod_touch_fmss.h b/include/hw/arm/ipod_touch_fmss.h index 647e10a77f14..186fd731c1a3 100644 --- a/include/hw/arm/ipod_touch_fmss.h +++ b/include/hw/arm/ipod_touch_fmss.h @@ -12,7 +12,7 @@ #define TYPE_IPOD_TOUCH_FMSS "ipodtouch.fmss" OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchFMSSState, IPOD_TOUCH_FMSS) -#define NAND_BYTES_PER_PAGE 2048 +#define NAND_BYTES_PER_PAGE 4096 #define NAND_BYTES_PER_SPARE 64 #define FMSS__FMCTRL1 0x4 @@ -21,6 +21,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchFMSSState, IPOD_TOUCH_FMSS) #define FMSS__CS_BUF_RST_OK 0xC64 #define FMSS_CINFO_TARGET_ADDR 0xD08 #define FMSS_PAGES_IN_ADDR 0xD0C +#define FMSS_CS_BUF_ADDR 0xD10 #define FMSS_NUM_PAGES 0xD18 #define FMSS_PAGE_SPARE_OUT_ADDR 0xD1C #define FMSS_PAGES_OUT_ADDR 0xD20 @@ -37,6 +38,7 @@ typedef struct IPodTouchFMSSState uint32_t reg_cs_irq_bit; uint32_t reg_cinfo_target_addr; uint32_t reg_pages_in_addr; + uint32_t reg_cs_buf_addr; uint32_t reg_num_pages; uint32_t reg_page_spare_out_addr; uint32_t reg_pages_out_addr; From 37f8199e5203db3c163e9f4e313c7883f3993e11 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Thu, 27 Jul 2023 19:44:17 +0200 Subject: [PATCH 29/58] Booting up until lockdownd! --- hw/arm/ipod_touch_fmss.c | 25 ++++++++++++++++++++++--- include/hw/arm/ipod_touch_fmss.h | 2 ++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/hw/arm/ipod_touch_fmss.c b/hw/arm/ipod_touch_fmss.c index 66691c1821ca..c18889556f07 100644 --- a/hw/arm/ipod_touch_fmss.c +++ b/hw/arm/ipod_touch_fmss.c @@ -22,6 +22,12 @@ static void write_chip_info(IPodTouchFMSSState *s) cpu_physical_memory_write(s->reg_cinfo_target_addr, &chipid, 0x10); } +static void dump_registers(IPodTouchFMSSState *s) { + printf("FMSS_PAGES_IN_ADDR: 0x%08x\n", s->reg_pages_in_addr); + printf("FMSS_CS_BUF_ADDR: 0x%08x\n", s->reg_cs_buf_addr); + printf("FMSS_NUM_PAGES: 0x%08x\n", s->reg_num_pages); +} + static void read_nand_pages(IPodTouchFMSSState *s) { // boot args @@ -29,15 +35,23 @@ static void read_nand_pages(IPodTouchFMSSState *s) cpu_physical_memory_write(0x0ff2a584, boot_args, strlen(boot_args)); int page_out_buf_ind = 0; + //dump_registers(s); + //printf("Start CMD...\n"); for(int page_ind = 0; page_ind < s->reg_num_pages; page_ind++) { uint32_t page_nr = 0; uint32_t page_out_addr = 0; uint32_t cs = 0; cpu_physical_memory_read(s->reg_pages_in_addr + (page_ind * sizeof(uint32_t)), &page_nr, sizeof(uint32_t)); - cpu_physical_memory_read(s->reg_cs_buf_addr + (page_ind * sizeof(uint32_t)), &cs, sizeof(uint32_t)); + uint32_t og_cs = cs; cs = find_bit_index(cs); + if(cs > 3) { + printf("CS %d invalid! (og CS: %d, reading page %d)\n", cs, og_cs, page_nr); + dump_registers(s); + hw_error("CS %d invalid!", cs); + } + // prepare the page char filename[200]; sprintf(filename, "/Users/martijndevos/Documents/generate_nand_it2g/nand/cs%d/%d.page", cs, page_nr); @@ -63,7 +77,7 @@ static void read_nand_pages(IPodTouchFMSSState *s) for(int i = 0; i < 2; i++) { cpu_physical_memory_read(s->reg_pages_out_addr + (page_out_buf_ind * sizeof(uint32_t)), &page_out_addr, sizeof(uint32_t)); cpu_physical_memory_write(page_out_addr, s->page_buffer + i * write_buf_size, write_buf_size); - // printf("Will read page %d @ cs %d into address 0x%08x and spare into address 0x%08x\n", page_nr, cs, page_out_addr, s->reg_page_spare_out_addr); + //printf("Will read page %d @ cs %d into address 0x%08x and spare into address 0x%08x\n", page_nr, cs, page_out_addr, s->reg_page_spare_out_addr); page_out_buf_ind++; } @@ -130,8 +144,13 @@ static void ipod_touch_fmss_write(void *opaque, hwaddr addr, uint64_t val, unsig case FMSS_PAGES_OUT_ADDR: s->reg_pages_out_addr = val; break; + case FMSS_CSGENRC: + s->reg_csgenrc = val; + break; case 0xD38: - read_nand_pages(s); + if(s->reg_csgenrc == 0xa01) { read_nand_pages(s); } + else { printf("NAND write not suported yet!\n"); } + } } diff --git a/include/hw/arm/ipod_touch_fmss.h b/include/hw/arm/ipod_touch_fmss.h index 186fd731c1a3..b84647d5364c 100644 --- a/include/hw/arm/ipod_touch_fmss.h +++ b/include/hw/arm/ipod_touch_fmss.h @@ -25,6 +25,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchFMSSState, IPOD_TOUCH_FMSS) #define FMSS_NUM_PAGES 0xD18 #define FMSS_PAGE_SPARE_OUT_ADDR 0xD1C #define FMSS_PAGES_OUT_ADDR 0xD20 +#define FMSS_CSGENRC 0xD30 typedef struct IPodTouchFMSSState { @@ -42,6 +43,7 @@ typedef struct IPodTouchFMSSState uint32_t reg_num_pages; uint32_t reg_page_spare_out_addr; uint32_t reg_pages_out_addr; + uint32_t reg_csgenrc; } IPodTouchFMSSState; #endif \ No newline at end of file From c3c18302101a8da2f83068508eb7e0d638b218d0 Mon Sep 17 00:00:00 2001 From: zoe-vb <96234996+zoe-vb@users.noreply.github.com> Date: Fri, 11 Aug 2023 00:02:34 +0100 Subject: [PATCH 30/58] Update ipod_touch_fmss.c fix issue where boot arguments were not actually updating when recompiling qemu. --- hw/arm/ipod_touch_fmss.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/arm/ipod_touch_fmss.c b/hw/arm/ipod_touch_fmss.c index c18889556f07..e4988b314c58 100644 --- a/hw/arm/ipod_touch_fmss.c +++ b/hw/arm/ipod_touch_fmss.c @@ -31,7 +31,7 @@ static void dump_registers(IPodTouchFMSSState *s) { static void read_nand_pages(IPodTouchFMSSState *s) { // boot args - char *boot_args = "kextlog=0xfff debug=0x8 cpus=1 rd=disk0s1 serial=1 pmu-debug=0x1 io=0xffff8fff debug-usb=0xffffffff"; + const char *boot_args = "kextlog=0xfff debug=0x8 cpus=1 rd=disk0s1 serial=1 pmu-debug=0x1 io=0xffff8fff debug-usb=0xffffffff"; // if not const then overwritten cpu_physical_memory_write(0x0ff2a584, boot_args, strlen(boot_args)); int page_out_buf_ind = 0; @@ -199,4 +199,4 @@ static void ipod_touch_machine_types(void) type_register_static(&ipod_touch_fmss_info); } -type_init(ipod_touch_machine_types) \ No newline at end of file +type_init(ipod_touch_machine_types) From 0a48ea3de8b24666bdadad11d933fc666b553e5f Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Sat, 12 Aug 2023 10:57:15 +0200 Subject: [PATCH 31/58] Started working on SDIO --- hw/arm/ipod_touch_2g.c | 7 +- hw/arm/ipod_touch_sdio.c | 106 +++++++++++++++++++++++++++++++ hw/arm/meson.build | 2 +- include/hw/arm/ipod_touch_2g.h | 2 + include/hw/arm/ipod_touch_sdio.h | 37 +++++++++++ 5 files changed, 152 insertions(+), 2 deletions(-) create mode 100644 hw/arm/ipod_touch_sdio.c create mode 100644 include/hw/arm/ipod_touch_sdio.h diff --git a/hw/arm/ipod_touch_2g.c b/hw/arm/ipod_touch_2g.c index d70067744186..9ba037896c9a 100644 --- a/hw/arm/ipod_touch_2g.c +++ b/hw/arm/ipod_touch_2g.c @@ -94,7 +94,6 @@ static void ipod_touch_memory_setup(MachineState *machine, MemoryRegion *sysmem, allocate_ram(sysmem, "framebuffer", FRAMEBUFFER_MEM_BASE, 0x400000); allocate_ram(sysmem, "edgeic", EDGEIC_MEM_BASE, 0x1000); allocate_ram(sysmem, "swi", SWI_MEM_BASE, 0x1000); - allocate_ram(sysmem, "sdio", SDIO_MEM_BASE, 0x1000); allocate_ram(sysmem, "h264", H264_MEM_BASE, 0x4000); // load the bootrom (vrom) @@ -209,6 +208,12 @@ static void ipod_touch_machine_init(MachineState *machine) nms->gpio_state = gpio_state; memory_region_add_subregion(sysmem, GPIO_MEM_BASE, &gpio_state->iomem); + // init SDIO + dev = qdev_new("ipodtouch.sdio"); + IPodTouchSDIOState *sdio_state = IPOD_TOUCH_SDIO(dev); + nms->sdio_state = sdio_state; + memory_region_add_subregion(sysmem, SDIO_MEM_BASE, &sdio_state->iomem); + dev = exynos4210_uart_create(UART0_MEM_BASE, 256, 0, serial_hd(0), nms->irq[0][24]); if (!dev) { printf("Failed to create uart0 device!\n"); diff --git a/hw/arm/ipod_touch_sdio.c b/hw/arm/ipod_touch_sdio.c new file mode 100644 index 000000000000..c81b2fce1668 --- /dev/null +++ b/hw/arm/ipod_touch_sdio.c @@ -0,0 +1,106 @@ +#include "hw/arm/ipod_touch_sdio.h" + +void sdio_exec_cmd(IPodTouchSDIOState *s) +{ + uint32_t addr = (s->arg >> 9) & 0x1ffff; + printf("SDIO ADDR: %d\n", addr); + if(addr == 0) { + // reading slot 0 - make sure there is a device here + s->resp0 = ~0; + } +} + +static void ipod_touch_sdio_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) +{ + printf("%s: writing 0x%08x to 0x%08x\n", __func__, value, addr); + + IPodTouchSDIOState *s = (struct IPodTouchSDIOState *) opaque; + + switch(addr) { + case SDIO_CMD: + s->cmd = value; + if(value & (1 << 31)) { + sdio_exec_cmd(s); + } + break; + case SDIO_ARGU: + s->arg = value; + break; + case SDIO_CSR: + s->csr = value; + break; + case SDIO_IRQMASK: + s->irq_mask = value; + break; + default: + break; + } +} + +static uint64_t ipod_touch_sdio_read(void *opaque, hwaddr addr, unsigned size) +{ + printf("%s: offset = 0x%08x\n", __func__, addr); + + IPodTouchSDIOState *s = (struct IPodTouchSDIOState *) opaque; + + switch (addr) { + case SDIO_CMD: + return s->cmd; + case SDIO_ARGU: + return s->arg; + case SDIO_DSTA: + return (1 << 0) | (1 << 4) ; // 0x1 indicates that the SDIO is ready for a CMD, (1 << 4) that the command is complete + case SDIO_RESP0: + return s->resp0; + case SDIO_RESP1: + return s->resp1; + case SDIO_RESP2: + return s->resp2; + case SDIO_RESP3: + return s->resp3; + case SDIO_CSR: + return s->csr; + case SDIO_IRQMASK: + return s->irq_mask; + default: + break; + } + + return 0; +} + +static const MemoryRegionOps ipod_touch_sdio_ops = { + .read = ipod_touch_sdio_read, + .write = ipod_touch_sdio_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void ipod_touch_sdio_init(Object *obj) +{ + DeviceState *dev = DEVICE(obj); + IPodTouchSDIOState *s = IPOD_TOUCH_SDIO(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init_io(&s->iomem, obj, &ipod_touch_sdio_ops, s, TYPE_IPOD_TOUCH_SDIO, 4096); + sysbus_init_mmio(sbd, &s->iomem); +} + +static void ipod_touch_sdio_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); +} + +static const TypeInfo ipod_touch_sdio_type_info = { + .name = TYPE_IPOD_TOUCH_SDIO, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IPodTouchSDIOState), + .instance_init = ipod_touch_sdio_init, + .class_init = ipod_touch_sdio_class_init, +}; + +static void ipod_touch_sdio_register_types(void) +{ + type_register_static(&ipod_touch_sdio_type_info); +} + +type_init(ipod_touch_sdio_register_types) \ No newline at end of file diff --git a/hw/arm/meson.build b/hw/arm/meson.build index 98b2d625a57e..bfb691ae21e8 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -62,6 +62,6 @@ arm_ss.add(when: 'CONFIG_FSL_IMX7', if_true: files('fsl-imx7.c', 'mcimx7d-sabre. arm_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c', 'smmuv3.c')) arm_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c')) arm_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c')) -arm_ss.add(when: 'CONFIG_IPOD_TOUCH_2G', if_true: files('ipod_touch_2g.c', 'ipod_touch_clock.c', 'ipod_touch_chipid.c', 'ipod_touch_gpio.c', 'ipod_touch_sysic.c', 'ipod_touch_timer.c', 'ipod_touch_usb_otg.c', 'ipod_touch_usb_phys.c', 'ipod_touch_spi.c', 'ipod_touch_nor_spi.c', 'ipod_touch_sha1.c', 'ipod_touch_aes.c', 'ipod_touch_pke.c', 'ipod_touch_pcf50633_pmu.c', 'ipod_touch_unknown1.c', 'ipod_touch_lcd.c', 'ipod_touch_mipi_dsi.c', 'ipod_touch_fmss.c', 'ipod_touch_block_device.c', 'ipod_touch_mbx.c', 'ipod_touch_cd3272_mikey.c', 'ipod_touch_lis302dl.c', 'ipod_touch_multitouch.c', 'ipod_touch_scaler_csc.c')) +arm_ss.add(when: 'CONFIG_IPOD_TOUCH_2G', if_true: files('ipod_touch_2g.c', 'ipod_touch_clock.c', 'ipod_touch_chipid.c', 'ipod_touch_gpio.c', 'ipod_touch_sysic.c', 'ipod_touch_timer.c', 'ipod_touch_usb_otg.c', 'ipod_touch_usb_phys.c', 'ipod_touch_spi.c', 'ipod_touch_nor_spi.c', 'ipod_touch_sha1.c', 'ipod_touch_aes.c', 'ipod_touch_pke.c', 'ipod_touch_pcf50633_pmu.c', 'ipod_touch_unknown1.c', 'ipod_touch_lcd.c', 'ipod_touch_mipi_dsi.c', 'ipod_touch_fmss.c', 'ipod_touch_block_device.c', 'ipod_touch_mbx.c', 'ipod_touch_cd3272_mikey.c', 'ipod_touch_lis302dl.c', 'ipod_touch_multitouch.c', 'ipod_touch_scaler_csc.c', 'ipod_touch_sdio.c')) hw_arch += {'arm': arm_ss} diff --git a/include/hw/arm/ipod_touch_2g.h b/include/hw/arm/ipod_touch_2g.h index 6969fc6dc15f..93e192e00050 100644 --- a/include/hw/arm/ipod_touch_2g.h +++ b/include/hw/arm/ipod_touch_2g.h @@ -26,6 +26,7 @@ #include "hw/arm/ipod_touch_block_device.h" #include "hw/arm/ipod_touch_mbx.h" #include "hw/arm/ipod_touch_scaler_csc.h" +#include "hw/arm/ipod_touch_sdio.h" #define TYPE_IPOD_TOUCH "iPod-Touch" @@ -137,6 +138,7 @@ typedef struct { IPodTouchBlockDeviceState *bdev_state; IPodTouchMBXState *mbx_state; IPodTouchScalerCSCState *scaler_csc_state; + IPodTouchSDIOState *sdio_state; Clock *sysclk; char nor_path[1024]; IT2G_CPREG_VAR_DEF(REG0); diff --git a/include/hw/arm/ipod_touch_sdio.h b/include/hw/arm/ipod_touch_sdio.h new file mode 100644 index 000000000000..333f561a5839 --- /dev/null +++ b/include/hw/arm/ipod_touch_sdio.h @@ -0,0 +1,37 @@ +#ifndef IPOD_TOUCH_SDIO_H +#define IPOD_TOUCH_SDIO_H + +#include "qemu/osdep.h" +#include "qemu/module.h" +#include "qemu/timer.h" +#include "hw/sysbus.h" + +#define TYPE_IPOD_TOUCH_SDIO "ipodtouch.sdio" +OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchSDIOState, IPOD_TOUCH_SDIO) + +#define SDIO_CMD 0x8 +#define SDIO_ARGU 0xC +#define SDIO_DSTA 0x18 +#define SDIO_RESP0 0x20 +#define SDIO_RESP1 0x24 +#define SDIO_RESP2 0x28 +#define SDIO_RESP3 0x2C +#define SDIO_CSR 0x34 +#define SDIO_IRQMASK 0x3C + +typedef struct IPodTouchSDIOState +{ + SysBusDevice parent_obj; + MemoryRegion iomem; + + uint32_t cmd; + uint32_t arg; + uint32_t csr; + uint32_t resp0; + uint32_t resp1; + uint32_t resp2; + uint32_t resp3; + uint32_t irq_mask; +} IPodTouchSDIOState; + +#endif \ No newline at end of file From ee22d61aa75e62870f817881f17b0997f8c4196c Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Tue, 29 Aug 2023 22:07:49 +0200 Subject: [PATCH 32/58] Made some progress with the BCM4325 --- hw/arm/ipod_touch_mbx.c | 109 +++++++++++++++++++++++++++++++ hw/arm/ipod_touch_sdio.c | 64 ++++++++++++++++-- include/hw/arm/ipod_touch_sdio.h | 15 +++++ 3 files changed, 183 insertions(+), 5 deletions(-) diff --git a/hw/arm/ipod_touch_mbx.c b/hw/arm/ipod_touch_mbx.c index 974a6fde1c46..a06fcad17846 100644 --- a/hw/arm/ipod_touch_mbx.c +++ b/hw/arm/ipod_touch_mbx.c @@ -1,5 +1,12 @@ #include "hw/arm/ipod_touch_mbx.h" +static uint32_t reverse_byte_order(uint32_t value) { + return ((value & 0x000000FF) << 24) | + ((value & 0x0000FF00) << 8) | + ((value & 0x00FF0000) >> 8) | + ((value & 0xFF000000) >> 24); +} + static uint64_t ipod_touch_mbx1_read(void *opaque, hwaddr addr, unsigned size) { printf("%s: read from location 0x%08x\n", __func__, addr); @@ -23,11 +30,113 @@ static void ipod_touch_mbx1_write(void *opaque, hwaddr addr, uint64_t val, unsig fprintf(stderr, "%s: writing 0x%08x to 0x%08x\n", __func__, val, addr); } +static void patch_kernel() +{ + // patch the loading of the AppleBCM4325 driver + char *bcm4325_vars = "test"; + + // write the pointer to our custom subroutine + uint32_t *data = malloc(sizeof(uint32_t) * 200); + data[0] = 0xC0460000; + cpu_physical_memory_write(0x8324aa8, (uint8_t *)data, sizeof(uint32_t) * 1); + + // create the call to the subroutine + data = malloc(sizeof(uint32_t) * 200); + data[0] = reverse_byte_order(0x0640A0E1); // mov r4, r6 + data[1] = reverse_byte_order(0x9C309FE5); // ldr r3, [pc, #0x9c] + data[2] = reverse_byte_order(0x33FF2FE1); // blx r3 + cpu_physical_memory_write(0x8324a00, (uint8_t *)data, sizeof(uint32_t) * 3); + + // fill in the driver load subroutine + data = malloc(sizeof(uint32_t) * 200); + data[0] = reverse_byte_order(0xFE402DE9); // push on stack + + // create the OSData object containing the BCM4325Vars string + data[1] = reverse_byte_order(0xF4009FE5); // ldr r0, [pc, #0xf4] + data[2] = reverse_byte_order(0x2010B0E3); // movs r1, #0x20 + data[3] = reverse_byte_order(0xF0309FE5); // ldr r3, [pc, #0xf0] + data[4] = reverse_byte_order(0x33FF2FE1); // blx r3 <- calling OSData::withBytes + data[5] = reverse_byte_order(0x0050A0E1); // mov r5, r0 (to save the created object) + + // create the OSDictionary object that we will pass to AppleBCM4325::init + data[6] = reverse_byte_order(0x0100B0E3); // movs r0, #0x1 + data[7] = reverse_byte_order(0xE4309FE5); // ldr r3, [pc, #0xe4] + data[8] = reverse_byte_order(0x33FF2FE1); // blx r3 <- calling OSDictionary::withCapacity + data[9] = reverse_byte_order(0x0060A0E1); // mov r6, r0 (to save the created object) + + // call OSDictionary::setObject + data[10] = reverse_byte_order(0x00C096E5); // ldr r12, [r6, #0x0] (get the vtable of the OSDictionary) + data[11] = reverse_byte_order(0xD8109FE5); // ldr r1, [pc, #0xd8] + data[12] = reverse_byte_order(0x0520A0E1); // mov r2, r5 + data[13] = reverse_byte_order(0x0FE0A0E1); // mov lr, pc + data[14] = reverse_byte_order(0x98F09CE5); // ldr pc, [r12, #0x98] + + // create the AppleBCM4325 object + data[15] = reverse_byte_order(0x010AB0E3); // movs r0, #0x1000 + data[16] = reverse_byte_order(0xC8309FE5); // ldr r3, [pc, #0xc8] + data[17] = reverse_byte_order(0x33FF2FE1); // blx r3 <- calling OSObject::operator.new + data[18] = reverse_byte_order(0x0050A0E1); // mov r5, r0 (to save the new object somewhere) + + // call AppleBCM4325 object initialization + data[19] = reverse_byte_order(0xC0309FE5); // ldr r3, [pc, #0xc0] + data[20] = reverse_byte_order(0x33FF2FE1); // blx r3 + + // call the IONetworkController metaclass initialization + data[21] = reverse_byte_order(0x0100B0E3); // movs r0, #0x1 + data[22] = reverse_byte_order(0xB8109FE5); // ldr r1, [pc, #0xb8] + data[23] = reverse_byte_order(0xB8209FE5); // ldr r2, [pc, #0xb8] + data[24] = reverse_byte_order(0x32FF2FE1); // blx r2 + + // load the "com.apple.driver.AppleBCM4325" kext + data[25] = reverse_byte_order(0xB4009FE5); // ldr r0, [pc, #0xb4] + data[26] = reverse_byte_order(0x0110B0E3); // movs r1, #0x1 + data[27] = reverse_byte_order(0xB0209FE5); // ldr r2, [pc, #0xd8] + data[28] = reverse_byte_order(0x32FF2FE1); // blx r2 + + // call AppleBCM4325::init + data[29] = reverse_byte_order(0x00C095E5); // ldr r12, [r5, #0x0] (get the vtable) + data[30] = reverse_byte_order(0x0500A0E1); // mov r0, r5 + data[31] = reverse_byte_order(0x0610A0E1); // mov r1, r6 + data[32] = reverse_byte_order(0x0FE0A0E1); // mov lr, pc + data[33] = reverse_byte_order(0x6CF09CE5); // ldr pc, [r12, #0x6c] + + // call AppleBCM4325::start + data[34] = reverse_byte_order(0x00C095E5); // ldr r12, [r5, #0x0] (get the vtable) + data[35] = reverse_byte_order(0x0500A0E1); // mov r0, r5 + data[36] = reverse_byte_order(0x0410A0E1); // mov r1, r4 + data[37] = reverse_byte_order(0x0FE0A0E1); // mov lr, pc + data[38] = reverse_byte_order(0x78F19CE5); // ldr pc, [r12, #0x178] + + data[39] = reverse_byte_order(0xFE80BDE8); // pop from stack + + cpu_physical_memory_write(0x8460000, (uint8_t *)data, sizeof(uint32_t) * 50); + + // write the data section of the driver load subroutine (0x100 items from the start of the subroutine) + data = malloc(sizeof(uint32_t) * 200); + data[0] = 0xc0460200; // the address of the BCM4325Vars string + data[1] = 0xc013c373; // the address of OSData::withBytes + data[2] = 0xc013cc3d; // the address of OSDictionary::withCapacity + data[3] = 0xc03467bc; // the "BCM4325Vars" string + data[4] = 0xc013ad8d; // the address of OSObject::operator.new + data[5] = 0xc032c294; // the object initialization method of AppleBCM4325 + data[6] = 0xffff; // the 2nd parameter for the call to the IONetworkController metaclass initialization + data[7] = 0xc02f94f9; // the initialization method of the IONetworkController metaclass + data[8] = 0xc038a320; // the "com.apple.driver.AppleBCM4325" string + data[9] = 0xc015de01; // the kmod_load_request method + + cpu_physical_memory_write(0x8460100, (uint8_t *)data, sizeof(uint32_t) * 10); + + // write the BCM4325Vars string + cpu_physical_memory_write(0x8460200, (uint8_t *)bcm4325_vars, strlen(bcm4325_vars)); +} + static uint64_t ipod_touch_mbx2_read(void *opaque, hwaddr addr, unsigned size) { printf("%s: read from location 0x%08x\n", __func__, addr); switch(addr) { + case 0xC: + patch_kernel(); default: break; } diff --git a/hw/arm/ipod_touch_sdio.c b/hw/arm/ipod_touch_sdio.c index c81b2fce1668..1fc8904d6795 100644 --- a/hw/arm/ipod_touch_sdio.c +++ b/hw/arm/ipod_touch_sdio.c @@ -2,11 +2,35 @@ void sdio_exec_cmd(IPodTouchSDIOState *s) { + uint32_t cmd_type = s->cmd & 0x3f; uint32_t addr = (s->arg >> 9) & 0x1ffff; - printf("SDIO ADDR: %d\n", addr); - if(addr == 0) { - // reading slot 0 - make sure there is a device here - s->resp0 = ~0; + printf("SDIO CMD: %d, ADDR: %d\n", cmd_type, addr); + if(cmd_type == 0x3) { + // RCA request - ignore + } + else if(cmd_type == 0x5) { + if(addr == 0) { + // reading slot 0 - make sure there is a device here + s->resp0 = (1 << 31) /* indicate ready */ | (BCM4325_FUNCTIONS << CMD5_FUNC_OFFSET) /* number of functions */; + } + } + else if(cmd_type == 0x7) { + // select card - ignore + } + else if(cmd_type == 0x34) { + // CMD52 - read/write from a register + bool is_write = (s->arg >> 31) != 0; + if(is_write) { + uint8_t data = s->arg & 0xFF; + s->registers[addr] = data; + if(addr == 0x2) { s->registers[0x3] = data; } // if we write to register 2, we also write the same result to register 3 (this is the enabled functions register) + printf("Writing %d to register %d\n", data, addr); + } else { + s->resp0 = s->registers[addr]; + } + } + else { + hw_error("Unknown SDIO command %d", cmd_type); } } @@ -19,13 +43,19 @@ static void ipod_touch_sdio_write(void *opaque, hwaddr addr, uint64_t value, uns switch(addr) { case SDIO_CMD: s->cmd = value; - if(value & (1 << 31)) { + if(value & (1 << 31)) { // execute bit is set sdio_exec_cmd(s); } break; case SDIO_ARGU: s->arg = value; break; + case SDIO_STATE: + s->state = value; + break; + case SDIO_STAC: + s->stac = value; + break; case SDIO_CSR: s->csr = value; break; @@ -48,6 +78,10 @@ static uint64_t ipod_touch_sdio_read(void *opaque, hwaddr addr, unsigned size) return s->cmd; case SDIO_ARGU: return s->arg; + case SDIO_STATE: + return s->state; + case SDIO_STAC: + return s->stac; case SDIO_DSTA: return (1 << 0) | (1 << 4) ; // 0x1 indicates that the SDIO is ready for a CMD, (1 << 4) that the command is complete case SDIO_RESP0: @@ -81,6 +115,26 @@ static void ipod_touch_sdio_init(Object *obj) IPodTouchSDIOState *s = IPOD_TOUCH_SDIO(obj); SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + s->registers[0x9] = CIS_OFFSET; // registers 0x9 - 0xB contain the relative address offset, which we set to 0xC8 (200) + s->registers[19] = 0x1; // enable support for high speed mode + + // set the vendor information + s->registers[CIS_OFFSET] = CIS_MANUFACTURER_ID; + s->registers[CIS_OFFSET + 1] = 0x4; + s->registers[CIS_OFFSET + 2] = BCM4325_MANUFACTURER & 0xFF; + s->registers[CIS_OFFSET + 3] = (BCM4325_MANUFACTURER >> 8) & 0xFF; + s->registers[CIS_OFFSET + 4] = BCM4325_PRODUCT_ID & 0xFF; + s->registers[CIS_OFFSET + 5] = (BCM4325_PRODUCT_ID >> 8) & 0xFF; + + // set the MAC address + s->registers[CIS_OFFSET + 6] = CIS_FUNCTION_EXTENSION; + s->registers[CIS_OFFSET + 8] = 0x4; // unknown + s->registers[CIS_OFFSET + 9] = 0x6; // the length of the MAC address + + for(int i = 0; i < 6; i++) { // TODO should be fixed + s->registers[CIS_OFFSET + 10 + i] = 0x42; + } + memory_region_init_io(&s->iomem, obj, &ipod_touch_sdio_ops, s, TYPE_IPOD_TOUCH_SDIO, 4096); sysbus_init_mmio(sbd, &s->iomem); } diff --git a/include/hw/arm/ipod_touch_sdio.h b/include/hw/arm/ipod_touch_sdio.h index 333f561a5839..9b049036655a 100644 --- a/include/hw/arm/ipod_touch_sdio.h +++ b/include/hw/arm/ipod_touch_sdio.h @@ -5,12 +5,15 @@ #include "qemu/module.h" #include "qemu/timer.h" #include "hw/sysbus.h" +#include "hw/hw.h" #define TYPE_IPOD_TOUCH_SDIO "ipodtouch.sdio" OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchSDIOState, IPOD_TOUCH_SDIO) #define SDIO_CMD 0x8 #define SDIO_ARGU 0xC +#define SDIO_STATE 0x10 +#define SDIO_STAC 0x14 #define SDIO_DSTA 0x18 #define SDIO_RESP0 0x20 #define SDIO_RESP1 0x24 @@ -19,6 +22,15 @@ OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchSDIOState, IPOD_TOUCH_SDIO) #define SDIO_CSR 0x34 #define SDIO_IRQMASK 0x3C +#define CMD5_FUNC_OFFSET 28 +#define CIS_OFFSET 0xC8 +#define CIS_MANUFACTURER_ID 0x20 +#define CIS_FUNCTION_EXTENSION 0x22 + +#define BCM4325_FUNCTIONS 0x1 +#define BCM4325_MANUFACTURER 0x4D50 +#define BCM4325_PRODUCT_ID 0x4D48 + typedef struct IPodTouchSDIOState { SysBusDevice parent_obj; @@ -26,12 +38,15 @@ typedef struct IPodTouchSDIOState uint32_t cmd; uint32_t arg; + uint32_t state; + uint32_t stac; uint32_t csr; uint32_t resp0; uint32_t resp1; uint32_t resp2; uint32_t resp3; uint32_t irq_mask; + uint8_t registers[0x200]; } IPodTouchSDIOState; #endif \ No newline at end of file From 86be721bbcfb822c33799bcde599f81a2f0d30fe Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Wed, 30 Aug 2023 19:03:20 +0200 Subject: [PATCH 33/58] Got a tiny bit further in the boot process --- hw/arm/ipod_touch_sdio.c | 39 +++++++++++++++++++++++++++++++- include/hw/arm/ipod_touch_sdio.h | 8 +++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/hw/arm/ipod_touch_sdio.c b/hw/arm/ipod_touch_sdio.c index 1fc8904d6795..84593e48d354 100644 --- a/hw/arm/ipod_touch_sdio.c +++ b/hw/arm/ipod_touch_sdio.c @@ -26,8 +26,28 @@ void sdio_exec_cmd(IPodTouchSDIOState *s) if(addr == 0x2) { s->registers[0x3] = data; } // if we write to register 2, we also write the same result to register 3 (this is the enabled functions register) printf("Writing %d to register %d\n", data, addr); } else { - s->resp0 = s->registers[addr]; + if(addr == 0x1000e) { + // misc register + s->resp0 = (1 << 6); // enable ALP clock + } + else { + s->resp0 = s->registers[addr]; + } + } + } + else if(cmd_type == 0x35) { + // CMD53 - block transfer + // TODO implement + // toggle IRQ register + printf("SDIO: Executing cmd53 with block size %d and %d blocks (reg address: 0x%08x, destination address: 0x%08x)\n", s->blklen, s->numblk, addr, s->baddr); + + if(addr == 0x8000) { + // chip ID register + uint32_t chipid[] = { 0x5 << 0x10 }; + cpu_physical_memory_write(s->baddr, &chipid, 0x4); } + + s->irq_reg = 0x1; } else { hw_error("Unknown SDIO command %d", cmd_type); @@ -62,6 +82,15 @@ static void ipod_touch_sdio_write(void *opaque, hwaddr addr, uint64_t value, uns case SDIO_IRQMASK: s->irq_mask = value; break; + case SDIO_BADDR: + s->baddr = value; + break; + case SDIO_BLKLEN: + s->blklen = value; + break; + case SDIO_NUMBLK: + s->numblk = value; + break; default: break; } @@ -94,8 +123,16 @@ static uint64_t ipod_touch_sdio_read(void *opaque, hwaddr addr, unsigned size) return s->resp3; case SDIO_CSR: return s->csr; + case SDIO_IRQ: + return s->irq_reg; case SDIO_IRQMASK: return s->irq_mask; + case SDIO_BADDR: + return s->baddr; + case SDIO_BLKLEN: + return s->blklen; + case SDIO_NUMBLK: + return s->numblk; default: break; } diff --git a/include/hw/arm/ipod_touch_sdio.h b/include/hw/arm/ipod_touch_sdio.h index 9b049036655a..61e96c9da607 100644 --- a/include/hw/arm/ipod_touch_sdio.h +++ b/include/hw/arm/ipod_touch_sdio.h @@ -20,7 +20,11 @@ OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchSDIOState, IPOD_TOUCH_SDIO) #define SDIO_RESP2 0x28 #define SDIO_RESP3 0x2C #define SDIO_CSR 0x34 +#define SDIO_IRQ 0x38 #define SDIO_IRQMASK 0x3C +#define SDIO_BADDR 0x44 +#define SDIO_BLKLEN 0x48 +#define SDIO_NUMBLK 0x4C #define CMD5_FUNC_OFFSET 28 #define CIS_OFFSET 0xC8 @@ -45,7 +49,11 @@ typedef struct IPodTouchSDIOState uint32_t resp1; uint32_t resp2; uint32_t resp3; + uint32_t irq_reg; uint32_t irq_mask; + uint32_t baddr; + uint32_t blklen; + uint32_t numblk; uint8_t registers[0x200]; } IPodTouchSDIOState; From cbc8c89420422ebe2ae2df11d0634d3067000acf Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Fri, 1 Sep 2023 21:28:35 +0200 Subject: [PATCH 34/58] Got SDIO IRQ working --- hw/arm/ipod_touch_2g.c | 3 +++ hw/arm/ipod_touch_sdio.c | 28 ++++++++++++++++++++-------- include/hw/arm/ipod_touch_2g.h | 1 + include/hw/arm/ipod_touch_sdio.h | 4 +++- 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/hw/arm/ipod_touch_2g.c b/hw/arm/ipod_touch_2g.c index 9ba037896c9a..ff0107137a00 100644 --- a/hw/arm/ipod_touch_2g.c +++ b/hw/arm/ipod_touch_2g.c @@ -213,6 +213,9 @@ static void ipod_touch_machine_init(MachineState *machine) IPodTouchSDIOState *sdio_state = IPOD_TOUCH_SDIO(dev); nms->sdio_state = sdio_state; memory_region_add_subregion(sysmem, SDIO_MEM_BASE, &sdio_state->iomem); + busdev = SYS_BUS_DEVICE(dev); + sysbus_realize(busdev, &error_fatal); + sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_SDIO_IRQ)); dev = exynos4210_uart_create(UART0_MEM_BASE, 256, 0, serial_hd(0), nms->irq[0][24]); if (!dev) { diff --git a/hw/arm/ipod_touch_sdio.c b/hw/arm/ipod_touch_sdio.c index 84593e48d354..d0f4e1360665 100644 --- a/hw/arm/ipod_touch_sdio.c +++ b/hw/arm/ipod_touch_sdio.c @@ -24,30 +24,38 @@ void sdio_exec_cmd(IPodTouchSDIOState *s) uint8_t data = s->arg & 0xFF; s->registers[addr] = data; if(addr == 0x2) { s->registers[0x3] = data; } // if we write to register 2, we also write the same result to register 3 (this is the enabled functions register) - printf("Writing %d to register %d\n", data, addr); + printf("SDIO: Executing cmd52 by writing 0x%02x to register 0x%02x\n", data, addr); } else { if(addr == 0x1000e) { // misc register - s->resp0 = (1 << 6); // enable ALP clock + s->resp0 = (1 << 6) /* enable ALP clock */ | (1 << 7); /* enable HT clock */ } else { + printf("Loading as response reg 0x%02x 0x%02x\n", s->registers[addr], addr); s->resp0 = s->registers[addr]; } } } else if(cmd_type == 0x35) { // CMD53 - block transfer - // TODO implement - // toggle IRQ register printf("SDIO: Executing cmd53 with block size %d and %d blocks (reg address: 0x%08x, destination address: 0x%08x)\n", s->blklen, s->numblk, addr, s->baddr); - if(addr == 0x8000) { - // chip ID register - uint32_t chipid[] = { 0x5 << 0x10 }; - cpu_physical_memory_write(s->baddr, &chipid, 0x4); + addr = addr & 0x7fff; + + bool is_write = (s->arg >> 31) != 0; + if(is_write) { + cpu_physical_memory_read(s->baddr, &s->registers[addr], s->blklen * s->numblk); + } else { + if(addr == 0x0) { + // chip ID register + uint32_t chipid[] = { 0x5 << 0x10 }; + cpu_physical_memory_write(s->baddr, &chipid, 0x4); + } } + // toggle IRQ register s->irq_reg = 0x1; + qemu_irq_raise(s->irq); } else { hw_error("Unknown SDIO command %d", cmd_type); @@ -79,6 +87,9 @@ static void ipod_touch_sdio_write(void *opaque, hwaddr addr, uint64_t value, uns case SDIO_CSR: s->csr = value; break; + case SDIO_IRQ: + qemu_irq_lower(s->irq); + break; case SDIO_IRQMASK: s->irq_mask = value; break; @@ -174,6 +185,7 @@ static void ipod_touch_sdio_init(Object *obj) memory_region_init_io(&s->iomem, obj, &ipod_touch_sdio_ops, s, TYPE_IPOD_TOUCH_SDIO, 4096); sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); } static void ipod_touch_sdio_class_init(ObjectClass *klass, void *data) diff --git a/include/hw/arm/ipod_touch_2g.h b/include/hw/arm/ipod_touch_2g.h index 93e192e00050..4d302502f58e 100644 --- a/include/hw/arm/ipod_touch_2g.h +++ b/include/hw/arm/ipod_touch_2g.h @@ -44,6 +44,7 @@ #define S5L8720_I2C0_IRQ 0x15 #define S5L8720_SPI3_IRQ 0x1C #define S5L8720_I2C1_IRQ 0x16 +#define S5L8720_SDIO_IRQ 0x2A #define S5L8720_FMSS_IRQ 0x36 #define S5L8720_SPI4_IRQ 0x37 diff --git a/include/hw/arm/ipod_touch_sdio.h b/include/hw/arm/ipod_touch_sdio.h index 61e96c9da607..ce8fde22366b 100644 --- a/include/hw/arm/ipod_touch_sdio.h +++ b/include/hw/arm/ipod_touch_sdio.h @@ -6,6 +6,7 @@ #include "qemu/timer.h" #include "hw/sysbus.h" #include "hw/hw.h" +#include "hw/irq.h" #define TYPE_IPOD_TOUCH_SDIO "ipodtouch.sdio" OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchSDIOState, IPOD_TOUCH_SDIO) @@ -39,6 +40,7 @@ typedef struct IPodTouchSDIOState { SysBusDevice parent_obj; MemoryRegion iomem; + qemu_irq irq; uint32_t cmd; uint32_t arg; @@ -54,7 +56,7 @@ typedef struct IPodTouchSDIOState uint32_t baddr; uint32_t blklen; uint32_t numblk; - uint8_t registers[0x200]; + uint8_t registers[0x10000]; } IPodTouchSDIOState; #endif \ No newline at end of file From 182f275929cdffa221528888dbd56b99f84f9283 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Sun, 3 Sep 2023 14:45:07 +0200 Subject: [PATCH 35/58] More work on SDIO/BCM4325 --- hw/arm/ipod_touch_sdio.c | 27 ++++++++++++++++++++++----- include/hw/arm/ipod_touch_sdio.h | 1 + 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/hw/arm/ipod_touch_sdio.c b/hw/arm/ipod_touch_sdio.c index d0f4e1360665..a5c7de939db9 100644 --- a/hw/arm/ipod_touch_sdio.c +++ b/hw/arm/ipod_touch_sdio.c @@ -1,10 +1,18 @@ #include "hw/arm/ipod_touch_sdio.h" +static void trigger_irq(void *opaque) +{ + IPodTouchSDIOState *s = (IPodTouchSDIOState *)opaque; + s->irq_reg = 0x3; + qemu_irq_raise(s->irq); +} + void sdio_exec_cmd(IPodTouchSDIOState *s) { uint32_t cmd_type = s->cmd & 0x3f; uint32_t addr = (s->arg >> 9) & 0x1ffff; - printf("SDIO CMD: %d, ADDR: %d\n", cmd_type, addr); + uint32_t func = (s->arg >> 28) & 0x7; + printf("SDIO CMD: %d, ADDR: %d, FUNC: %d\n", cmd_type, addr, func); if(cmd_type == 0x3) { // RCA request - ignore } @@ -38,13 +46,20 @@ void sdio_exec_cmd(IPodTouchSDIOState *s) } else if(cmd_type == 0x35) { // CMD53 - block transfer - printf("SDIO: Executing cmd53 with block size %d and %d blocks (reg address: 0x%08x, destination address: 0x%08x)\n", s->blklen, s->numblk, addr, s->baddr); - addr = addr & 0x7fff; - bool is_write = (s->arg >> 31) != 0; + printf("SDIO: Executing cmd53 with block size %d and %d blocks (reg address: 0x%08x, destination address: 0x%08x, write? %d)\n", s->blklen, s->numblk, addr, s->baddr, is_write); + if(is_write) { - cpu_physical_memory_read(s->baddr, &s->registers[addr], s->blklen * s->numblk); + if(func == 0x1) { + cpu_physical_memory_read(s->baddr, &s->registers[addr], s->blklen * s->numblk); + } + else if(func == 0x2) { + // this is a BCM4325 command - schedule the IRQ request to indicate that the command has been completed + s->irq_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, trigger_irq, s); + timer_mod(s->irq_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 50); + printf("INT SCHED\n"); + } } else { if(addr == 0x0) { // chip ID register @@ -56,6 +71,7 @@ void sdio_exec_cmd(IPodTouchSDIOState *s) // toggle IRQ register s->irq_reg = 0x1; qemu_irq_raise(s->irq); + printf("Raised IRQ\n"); } else { hw_error("Unknown SDIO command %d", cmd_type); @@ -89,6 +105,7 @@ static void ipod_touch_sdio_write(void *opaque, hwaddr addr, uint64_t value, uns break; case SDIO_IRQ: qemu_irq_lower(s->irq); + printf("Lowered IRQ\n"); break; case SDIO_IRQMASK: s->irq_mask = value; diff --git a/include/hw/arm/ipod_touch_sdio.h b/include/hw/arm/ipod_touch_sdio.h index ce8fde22366b..1a110eac32bc 100644 --- a/include/hw/arm/ipod_touch_sdio.h +++ b/include/hw/arm/ipod_touch_sdio.h @@ -56,6 +56,7 @@ typedef struct IPodTouchSDIOState uint32_t baddr; uint32_t blklen; uint32_t numblk; + QEMUTimer *irq_timer; uint8_t registers[0x10000]; } IPodTouchSDIOState; From 94972bf6c83e4f933e233a24a098b1fa011cf851 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Mon, 4 Sep 2023 21:43:19 +0200 Subject: [PATCH 36/58] BCM4325 driver gets past initialization!! --- hw/arm/ipod_touch_mbx.c | 55 ++++--------------------------- hw/arm/ipod_touch_sdio.c | 56 ++++++++++++++++++++++++-------- include/hw/arm/ipod_touch_sdio.h | 10 +++++- 3 files changed, 59 insertions(+), 62 deletions(-) diff --git a/hw/arm/ipod_touch_mbx.c b/hw/arm/ipod_touch_mbx.c index a06fcad17846..300f1207dab2 100644 --- a/hw/arm/ipod_touch_mbx.c +++ b/hw/arm/ipod_touch_mbx.c @@ -45,41 +45,17 @@ static void patch_kernel() data[0] = reverse_byte_order(0x0640A0E1); // mov r4, r6 data[1] = reverse_byte_order(0x9C309FE5); // ldr r3, [pc, #0x9c] data[2] = reverse_byte_order(0x33FF2FE1); // blx r3 - cpu_physical_memory_write(0x8324a00, (uint8_t *)data, sizeof(uint32_t) * 3); + data[3] = reverse_byte_order(0x00F020E3); // NOP + data[4] = reverse_byte_order(0x00F020E3); // NOP + data[5] = reverse_byte_order(0x00F020E3); // NOP + cpu_physical_memory_write(0x8324a00, (uint8_t *)data, sizeof(uint32_t) * 6); // fill in the driver load subroutine data = malloc(sizeof(uint32_t) * 200); data[0] = reverse_byte_order(0xFE402DE9); // push on stack - // create the OSData object containing the BCM4325Vars string - data[1] = reverse_byte_order(0xF4009FE5); // ldr r0, [pc, #0xf4] - data[2] = reverse_byte_order(0x2010B0E3); // movs r1, #0x20 - data[3] = reverse_byte_order(0xF0309FE5); // ldr r3, [pc, #0xf0] - data[4] = reverse_byte_order(0x33FF2FE1); // blx r3 <- calling OSData::withBytes - data[5] = reverse_byte_order(0x0050A0E1); // mov r5, r0 (to save the created object) - - // create the OSDictionary object that we will pass to AppleBCM4325::init - data[6] = reverse_byte_order(0x0100B0E3); // movs r0, #0x1 - data[7] = reverse_byte_order(0xE4309FE5); // ldr r3, [pc, #0xe4] - data[8] = reverse_byte_order(0x33FF2FE1); // blx r3 <- calling OSDictionary::withCapacity - data[9] = reverse_byte_order(0x0060A0E1); // mov r6, r0 (to save the created object) - - // call OSDictionary::setObject - data[10] = reverse_byte_order(0x00C096E5); // ldr r12, [r6, #0x0] (get the vtable of the OSDictionary) - data[11] = reverse_byte_order(0xD8109FE5); // ldr r1, [pc, #0xd8] - data[12] = reverse_byte_order(0x0520A0E1); // mov r2, r5 - data[13] = reverse_byte_order(0x0FE0A0E1); // mov lr, pc - data[14] = reverse_byte_order(0x98F09CE5); // ldr pc, [r12, #0x98] - - // create the AppleBCM4325 object - data[15] = reverse_byte_order(0x010AB0E3); // movs r0, #0x1000 - data[16] = reverse_byte_order(0xC8309FE5); // ldr r3, [pc, #0xc8] - data[17] = reverse_byte_order(0x33FF2FE1); // blx r3 <- calling OSObject::operator.new - data[18] = reverse_byte_order(0x0050A0E1); // mov r5, r0 (to save the new object somewhere) - - // call AppleBCM4325 object initialization - data[19] = reverse_byte_order(0xC0309FE5); // ldr r3, [pc, #0xc0] - data[20] = reverse_byte_order(0x33FF2FE1); // blx r3 + // TODO I should clean this up + for(int i = 1; i < 21; i++) { data[i] = reverse_byte_order(0x00F020E3); } // NOP // call the IONetworkController metaclass initialization data[21] = reverse_byte_order(0x0100B0E3); // movs r0, #0x1 @@ -93,21 +69,7 @@ static void patch_kernel() data[27] = reverse_byte_order(0xB0209FE5); // ldr r2, [pc, #0xd8] data[28] = reverse_byte_order(0x32FF2FE1); // blx r2 - // call AppleBCM4325::init - data[29] = reverse_byte_order(0x00C095E5); // ldr r12, [r5, #0x0] (get the vtable) - data[30] = reverse_byte_order(0x0500A0E1); // mov r0, r5 - data[31] = reverse_byte_order(0x0610A0E1); // mov r1, r6 - data[32] = reverse_byte_order(0x0FE0A0E1); // mov lr, pc - data[33] = reverse_byte_order(0x6CF09CE5); // ldr pc, [r12, #0x6c] - - // call AppleBCM4325::start - data[34] = reverse_byte_order(0x00C095E5); // ldr r12, [r5, #0x0] (get the vtable) - data[35] = reverse_byte_order(0x0500A0E1); // mov r0, r5 - data[36] = reverse_byte_order(0x0410A0E1); // mov r1, r4 - data[37] = reverse_byte_order(0x0FE0A0E1); // mov lr, pc - data[38] = reverse_byte_order(0x78F19CE5); // ldr pc, [r12, #0x178] - - data[39] = reverse_byte_order(0xFE80BDE8); // pop from stack + data[29] = reverse_byte_order(0xFE80BDE8); // pop from stack cpu_physical_memory_write(0x8460000, (uint8_t *)data, sizeof(uint32_t) * 50); @@ -125,9 +87,6 @@ static void patch_kernel() data[9] = 0xc015de01; // the kmod_load_request method cpu_physical_memory_write(0x8460100, (uint8_t *)data, sizeof(uint32_t) * 10); - - // write the BCM4325Vars string - cpu_physical_memory_write(0x8460200, (uint8_t *)bcm4325_vars, strlen(bcm4325_vars)); } static uint64_t ipod_touch_mbx2_read(void *opaque, hwaddr addr, unsigned size) diff --git a/hw/arm/ipod_touch_sdio.c b/hw/arm/ipod_touch_sdio.c index a5c7de939db9..6cf55615b86d 100644 --- a/hw/arm/ipod_touch_sdio.c +++ b/hw/arm/ipod_touch_sdio.c @@ -2,8 +2,9 @@ static void trigger_irq(void *opaque) { + printf("ABChere\n"); IPodTouchSDIOState *s = (IPodTouchSDIOState *)opaque; - s->irq_reg = 0x3; + s->irq_reg = 0x2; qemu_irq_raise(s->irq); } @@ -38,6 +39,10 @@ void sdio_exec_cmd(IPodTouchSDIOState *s) // misc register s->resp0 = (1 << 6) /* enable ALP clock */ | (1 << 7); /* enable HT clock */ } + else if(addr == 0x2020) { + // some indication that packets are ready?? + s->resp0 = (1 << 6); + } else { printf("Loading as response reg 0x%02x 0x%02x\n", s->registers[addr], addr); s->resp0 = s->registers[addr]; @@ -55,17 +60,36 @@ void sdio_exec_cmd(IPodTouchSDIOState *s) cpu_physical_memory_read(s->baddr, &s->registers[addr], s->blklen * s->numblk); } else if(func == 0x2) { - // this is a BCM4325 command - schedule the IRQ request to indicate that the command has been completed - s->irq_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, trigger_irq, s); - timer_mod(s->irq_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 50); + // this is a BCM4325 command - add a frame to the queue and schedule the IRQ request to indicate that the command has been completed + BCM4325FrameHeaderPacket *frame_header = calloc(sizeof(BCM4325FrameHeaderPacket), sizeof(uint8_t *)); + uint16_t length = 14; + frame_header->frame_length = length; + frame_header->checksum = length ^ 0xffff; + g_queue_push_tail(s->rx_fifo, frame_header); + + timer_mod(s->irq_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + NANOSECONDS_PER_SECOND / 50); printf("INT SCHED\n"); } } else { - if(addr == 0x0) { - // chip ID register - uint32_t chipid[] = { 0x5 << 0x10 }; - cpu_physical_memory_write(s->baddr, &chipid, 0x4); + if(func == 0x1) { + if(addr == 0x0) { + // chip ID register + uint32_t chipid[] = { 0x5 << 0x10 }; + cpu_physical_memory_write(s->baddr, &chipid, 0x4); + } } + else if(func == 0x2) { + // we're reading a frame + BCM4325FrameHeaderPacket *frame_header = (BCM4325FrameHeaderPacket *) g_queue_pop_head(s->rx_fifo); + + if(!frame_header) { + // create an empty frame + printf("Creating empty response frame\n"); + frame_header = calloc(sizeof(BCM4325FrameHeaderPacket), sizeof(uint8_t *)); + } + cpu_physical_memory_write(s->baddr, frame_header, sizeof(BCM4325FrameHeaderPacket)); + } + } // toggle IRQ register @@ -191,18 +215,24 @@ static void ipod_touch_sdio_init(Object *obj) s->registers[CIS_OFFSET + 4] = BCM4325_PRODUCT_ID & 0xFF; s->registers[CIS_OFFSET + 5] = (BCM4325_PRODUCT_ID >> 8) & 0xFF; - // set the MAC address + // set the MAC address (00:23:32:6E:AA:10) s->registers[CIS_OFFSET + 6] = CIS_FUNCTION_EXTENSION; s->registers[CIS_OFFSET + 8] = 0x4; // unknown s->registers[CIS_OFFSET + 9] = 0x6; // the length of the MAC address - - for(int i = 0; i < 6; i++) { // TODO should be fixed - s->registers[CIS_OFFSET + 10 + i] = 0x42; - } + s->registers[CIS_OFFSET + 10] = 0x0; + s->registers[CIS_OFFSET + 11] = 0x23; + s->registers[CIS_OFFSET + 12] = 0x32; + s->registers[CIS_OFFSET + 13] = 0x6E; + s->registers[CIS_OFFSET + 14] = 0xAA; + s->registers[CIS_OFFSET + 15] = 0x10; memory_region_init_io(&s->iomem, obj, &ipod_touch_sdio_ops, s, TYPE_IPOD_TOUCH_SDIO, 4096); sysbus_init_mmio(sbd, &s->iomem); sysbus_init_irq(sbd, &s->irq); + + s->irq_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, trigger_irq, s); + + s->rx_fifo = g_queue_new(); } static void ipod_touch_sdio_class_init(ObjectClass *klass, void *data) diff --git a/include/hw/arm/ipod_touch_sdio.h b/include/hw/arm/ipod_touch_sdio.h index 1a110eac32bc..a0d389ab3b1b 100644 --- a/include/hw/arm/ipod_touch_sdio.h +++ b/include/hw/arm/ipod_touch_sdio.h @@ -36,11 +36,16 @@ OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchSDIOState, IPOD_TOUCH_SDIO) #define BCM4325_MANUFACTURER 0x4D50 #define BCM4325_PRODUCT_ID 0x4D48 +typedef struct BCM4325FrameHeaderPacket +{ + uint16_t frame_length; + uint16_t checksum; +} __attribute__((__packed__)) BCM4325FrameHeaderPacket; + typedef struct IPodTouchSDIOState { SysBusDevice parent_obj; MemoryRegion iomem; - qemu_irq irq; uint32_t cmd; uint32_t arg; @@ -57,6 +62,9 @@ typedef struct IPodTouchSDIOState uint32_t blklen; uint32_t numblk; QEMUTimer *irq_timer; + qemu_irq irq; + qemu_irq irq2; + GQueue *rx_fifo; uint8_t registers[0x10000]; } IPodTouchSDIOState; From f7b6729f88d96b3b43334c60688e78b6bf8c0fc8 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Wed, 6 Sep 2023 19:53:45 +0200 Subject: [PATCH 37/58] Device is activated! --- hw/arm/ipod_touch_fmss.c | 4 ++++ hw/arm/ipod_touch_sdio.c | 16 ++++++---------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/hw/arm/ipod_touch_fmss.c b/hw/arm/ipod_touch_fmss.c index e4988b314c58..455963d51ff1 100644 --- a/hw/arm/ipod_touch_fmss.c +++ b/hw/arm/ipod_touch_fmss.c @@ -34,6 +34,10 @@ static void read_nand_pages(IPodTouchFMSSState *s) const char *boot_args = "kextlog=0xfff debug=0x8 cpus=1 rd=disk0s1 serial=1 pmu-debug=0x1 io=0xffff8fff debug-usb=0xffffffff"; // if not const then overwritten cpu_physical_memory_write(0x0ff2a584, boot_args, strlen(boot_args)); + // patch iBoot - we want to inject the bluetooth MAC address which is located as sub-node of uart1 and not uart3 in the device tree... + char *chr = "arm-io/uart1/bluetooth"; + cpu_physical_memory_write(0x0ff2206c, chr, strlen(chr)); + int page_out_buf_ind = 0; //dump_registers(s); //printf("Start CMD...\n"); diff --git a/hw/arm/ipod_touch_sdio.c b/hw/arm/ipod_touch_sdio.c index 6cf55615b86d..26c4009e8ce5 100644 --- a/hw/arm/ipod_touch_sdio.c +++ b/hw/arm/ipod_touch_sdio.c @@ -2,7 +2,6 @@ static void trigger_irq(void *opaque) { - printf("ABChere\n"); IPodTouchSDIOState *s = (IPodTouchSDIOState *)opaque; s->irq_reg = 0x2; qemu_irq_raise(s->irq); @@ -13,14 +12,14 @@ void sdio_exec_cmd(IPodTouchSDIOState *s) uint32_t cmd_type = s->cmd & 0x3f; uint32_t addr = (s->arg >> 9) & 0x1ffff; uint32_t func = (s->arg >> 28) & 0x7; - printf("SDIO CMD: %d, ADDR: %d, FUNC: %d\n", cmd_type, addr, func); + //printf("SDIO CMD: %d, ADDR: %d, FUNC: %d\n", cmd_type, addr, func); if(cmd_type == 0x3) { // RCA request - ignore } else if(cmd_type == 0x5) { if(addr == 0) { // reading slot 0 - make sure there is a device here - s->resp0 = (1 << 31) /* indicate ready */ | (BCM4325_FUNCTIONS << CMD5_FUNC_OFFSET) /* number of functions */; + //s->resp0 = (1 << 31) /* indicate ready */ | (BCM4325_FUNCTIONS << CMD5_FUNC_OFFSET) /* number of functions */; } } else if(cmd_type == 0x7) { @@ -44,7 +43,7 @@ void sdio_exec_cmd(IPodTouchSDIOState *s) s->resp0 = (1 << 6); } else { - printf("Loading as response reg 0x%02x 0x%02x\n", s->registers[addr], addr); + printf("SDIO: Executing cmd52 by reading from 0x%02x (value: 0x%02x)\n", addr, s->registers[addr]); s->resp0 = s->registers[addr]; } } @@ -68,7 +67,6 @@ void sdio_exec_cmd(IPodTouchSDIOState *s) g_queue_push_tail(s->rx_fifo, frame_header); timer_mod(s->irq_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + NANOSECONDS_PER_SECOND / 50); - printf("INT SCHED\n"); } } else { if(func == 0x1) { @@ -84,7 +82,6 @@ void sdio_exec_cmd(IPodTouchSDIOState *s) if(!frame_header) { // create an empty frame - printf("Creating empty response frame\n"); frame_header = calloc(sizeof(BCM4325FrameHeaderPacket), sizeof(uint8_t *)); } cpu_physical_memory_write(s->baddr, frame_header, sizeof(BCM4325FrameHeaderPacket)); @@ -95,7 +92,7 @@ void sdio_exec_cmd(IPodTouchSDIOState *s) // toggle IRQ register s->irq_reg = 0x1; qemu_irq_raise(s->irq); - printf("Raised IRQ\n"); + //printf("Raised IRQ\n"); } else { hw_error("Unknown SDIO command %d", cmd_type); @@ -104,7 +101,7 @@ void sdio_exec_cmd(IPodTouchSDIOState *s) static void ipod_touch_sdio_write(void *opaque, hwaddr addr, uint64_t value, unsigned size) { - printf("%s: writing 0x%08x to 0x%08x\n", __func__, value, addr); + //printf("%s: writing 0x%08x to 0x%08x\n", __func__, value, addr); IPodTouchSDIOState *s = (struct IPodTouchSDIOState *) opaque; @@ -129,7 +126,6 @@ static void ipod_touch_sdio_write(void *opaque, hwaddr addr, uint64_t value, uns break; case SDIO_IRQ: qemu_irq_lower(s->irq); - printf("Lowered IRQ\n"); break; case SDIO_IRQMASK: s->irq_mask = value; @@ -150,7 +146,7 @@ static void ipod_touch_sdio_write(void *opaque, hwaddr addr, uint64_t value, uns static uint64_t ipod_touch_sdio_read(void *opaque, hwaddr addr, unsigned size) { - printf("%s: offset = 0x%08x\n", __func__, addr); + //printf("%s: offset = 0x%08x\n", __func__, addr); IPodTouchSDIOState *s = (struct IPodTouchSDIOState *) opaque; From cc21020f6413018d00379a7e15fbb5134a93eaa1 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Wed, 6 Sep 2023 21:55:35 +0200 Subject: [PATCH 38/58] Started working on TVOut This is blocking starting the display server --- hw/arm/ipod_touch_2g.c | 16 ++- hw/arm/ipod_touch_tvout.c | 169 ++++++++++++++++++++++++++++++ hw/arm/meson.build | 2 +- include/hw/arm/ipod_touch_2g.h | 10 +- include/hw/arm/ipod_touch_tvout.h | 38 +++++++ 5 files changed, 226 insertions(+), 9 deletions(-) create mode 100644 hw/arm/ipod_touch_tvout.c create mode 100644 include/hw/arm/ipod_touch_tvout.h diff --git a/hw/arm/ipod_touch_2g.c b/hw/arm/ipod_touch_2g.c index ff0107137a00..1d91f1b32d5e 100644 --- a/hw/arm/ipod_touch_2g.c +++ b/hw/arm/ipod_touch_2g.c @@ -88,9 +88,6 @@ static void ipod_touch_memory_setup(MachineState *machine, MemoryRegion *sysmem, allocate_ram(sysmem, "iboot", IBOOT_MEM_BASE, 0x100000); allocate_ram(sysmem, "llb", 0x22000000, 0x100000); allocate_ram(sysmem, "sram1", SRAM1_MEM_BASE, 0x100000); - allocate_ram(sysmem, "tvout1", TVOUT1_MEM_BASE, 0x1000); - allocate_ram(sysmem, "tvout2", TVOUT2_MEM_BASE, 0x1000); - allocate_ram(sysmem, "tvout3", TVOUT3_MEM_BASE, 0x1000); allocate_ram(sysmem, "framebuffer", FRAMEBUFFER_MEM_BASE, 0x400000); allocate_ram(sysmem, "edgeic", EDGEIC_MEM_BASE, 0x1000); allocate_ram(sysmem, "swi", SWI_MEM_BASE, 0x1000); @@ -277,6 +274,17 @@ static void ipod_touch_machine_init(MachineState *machine) nms->chipid_state = chipid_state; memory_region_add_subregion(sysmem, CHIPID_MEM_BASE, &chipid_state->iomem); + // init the TVOut instance + dev = qdev_new("ipodtouch.tvout"); + IPodTouchTVOutState *tvout_state = IPOD_TOUCH_TVOUT(dev); + nms->tvout_state = tvout_state; + memory_region_add_subregion(sysmem, TVOUT_MIXER1_MEM_BASE, &tvout_state->mixer1_iomem); + memory_region_add_subregion(sysmem, TVOUT_MIXER2_MEM_BASE, &tvout_state->mixer2_iomem); + memory_region_add_subregion(sysmem, TVOUT_SDO_MEM_BASE, &tvout_state->sdo_iomem); + busdev = SYS_BUS_DEVICE(dev); + sysbus_realize(busdev, &error_fatal); + sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_TVOUT_SDO_IRQ)); + // init the unknown1 module dev = qdev_new("ipodtouch.unknown1"); IPodTouchUnknown1State *unknown1_state = IPOD_TOUCH_UNKNOWN1(dev); @@ -344,7 +352,7 @@ static void ipod_touch_machine_init(MachineState *machine) sysbus_realize(busdev, &error_fatal); sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8720_FMSS_IRQ)); - // init the chip ID module + // init the USB module dev = qdev_new("ipodtouch.usbphys"); IPodTouchUSBPhysState *usb_phys_state = IPOD_TOUCH_USB_PHYS(dev); nms->usb_phys_state = usb_phys_state; diff --git a/hw/arm/ipod_touch_tvout.c b/hw/arm/ipod_touch_tvout.c new file mode 100644 index 000000000000..3df4f2291e23 --- /dev/null +++ b/hw/arm/ipod_touch_tvout.c @@ -0,0 +1,169 @@ +#include "hw/arm/ipod_touch_tvout.h" +#include "qapi/error.h" + +static uint64_t ipod_touch_tvout_sdo_read(void *opaque, hwaddr offset, unsigned size) +{ + IPodTouchTVOutState *s = (IPodTouchTVOutState *)opaque; + + printf("%s: offset = 0x%08x\n", __func__, offset); + + switch(offset) { + case SDO_IRQ: + return s->sdo_irq; + case SDO_IRQMASK: + return s->sdo_irq_mask; + default: + break; + } + + return 0; +} + +static void ipod_touch_tvout_sdo_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) +{ + IPodTouchTVOutState *s = (IPodTouchTVOutState *)opaque; + + printf("%s: writing 0x%08x to 0x%08x\n", __func__, value, offset); + + switch(offset) { + case SDO_IRQ: + s->sdo_irq = value; + printf("LOWERING SDO IRQ\n"); + qemu_irq_lower(s->irq); + return; + case SDO_IRQMASK: + s->sdo_irq_mask = value; + return; + } +} + +static uint64_t ipod_touch_tvout_mixer1_read(void *opaque, hwaddr offset, unsigned size) +{ + IPodTouchTVOutState *s = (IPodTouchTVOutState *)opaque; + + printf("%s: offset = 0x%08x\n", __func__, offset); + + switch(offset) { + case MXR_STATUS: + return s->mixer1_status; + case MXR_CFG: + return s->mixer1_cfg; + default: + break; + } + + return 0; +} + +static void ipod_touch_tvout_mixer1_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) +{ + IPodTouchTVOutState *s = (IPodTouchTVOutState *)opaque; + + printf("%s: writing 0x%08x to 0x%08x\n", __func__, value, offset); + + switch(offset) { + case MXR_STATUS: + s->mixer1_status = value; + if(value == 0x185 && (s->sdo_irq_mask & 1) == 0) { + printf("Raising SDO irq\n"); + qemu_irq_raise(s->irq); + } + break; + case MXR_CFG: + s->mixer1_cfg = value; + break; + } +} + +static uint64_t ipod_touch_tvout_mixer2_read(void *opaque, hwaddr offset, unsigned size) +{ + IPodTouchTVOutState *s = (IPodTouchTVOutState *)opaque; + + printf("%s: offset = 0x%08x\n", __func__, offset); + + switch(offset) { + case MXR_STATUS: + return s->mixer2_status; + case MXR_CFG: + return s->mixer2_cfg; + default: + break; + } + + return 0; +} + +static void ipod_touch_tvout_mixer2_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) +{ + IPodTouchTVOutState *s = (IPodTouchTVOutState *)opaque; + + printf("%s: writing 0x%08x to 0x%08x\n", __func__, value, offset); + + switch(offset) { + case MXR_STATUS: + s->mixer2_status = value; + break; + case MXR_CFG: + s->mixer2_cfg = value; + break; + } +} + +static const MemoryRegionOps ipod_touch_tvout_sdo_ops = { + .read = ipod_touch_tvout_sdo_read, + .write = ipod_touch_tvout_sdo_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static const MemoryRegionOps ipod_touch_tvout_mixer1_ops = { + .read = ipod_touch_tvout_mixer1_read, + .write = ipod_touch_tvout_mixer1_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static const MemoryRegionOps ipod_touch_tvout_mixer2_ops = { + .read = ipod_touch_tvout_mixer2_read, + .write = ipod_touch_tvout_mixer2_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static void ipod_touch_tvout_init(Object *obj) +{ + DeviceState *dev = DEVICE(obj); + IPodTouchTVOutState *s = IPOD_TOUCH_TVOUT(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + // mixer 1 + memory_region_init_io(&s->mixer1_iomem, obj, &ipod_touch_tvout_mixer1_ops, s, "tvout_mixer1", 4096); + sysbus_init_mmio(sbd, &s->mixer1_iomem); + + // mixer 2 + memory_region_init_io(&s->mixer2_iomem, obj, &ipod_touch_tvout_mixer2_ops, s, "tvout_mixer2", 4096); + sysbus_init_mmio(sbd, &s->mixer2_iomem); + + // SDO + memory_region_init_io(&s->sdo_iomem, obj, &ipod_touch_tvout_sdo_ops, s, "tvout_sdo", 4096); + sysbus_init_mmio(sbd, &s->sdo_iomem); + + sysbus_init_irq(sbd, &s->irq); +} + +static void ipod_touch_tvout_class_init(ObjectClass *klass, void *data) +{ + +} + +static const TypeInfo ipod_touch_tvout_type_info = { + .name = TYPE_IPOD_TOUCH_TVOUT, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(IPodTouchTVOutState), + .instance_init = ipod_touch_tvout_init, + .class_init = ipod_touch_tvout_class_init, +}; + +static void ipod_touch_tvout_register_types(void) +{ + type_register_static(&ipod_touch_tvout_type_info); +} + +type_init(ipod_touch_tvout_register_types) \ No newline at end of file diff --git a/hw/arm/meson.build b/hw/arm/meson.build index bfb691ae21e8..4071eeebc8d9 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -62,6 +62,6 @@ arm_ss.add(when: 'CONFIG_FSL_IMX7', if_true: files('fsl-imx7.c', 'mcimx7d-sabre. arm_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c', 'smmuv3.c')) arm_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c')) arm_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c')) -arm_ss.add(when: 'CONFIG_IPOD_TOUCH_2G', if_true: files('ipod_touch_2g.c', 'ipod_touch_clock.c', 'ipod_touch_chipid.c', 'ipod_touch_gpio.c', 'ipod_touch_sysic.c', 'ipod_touch_timer.c', 'ipod_touch_usb_otg.c', 'ipod_touch_usb_phys.c', 'ipod_touch_spi.c', 'ipod_touch_nor_spi.c', 'ipod_touch_sha1.c', 'ipod_touch_aes.c', 'ipod_touch_pke.c', 'ipod_touch_pcf50633_pmu.c', 'ipod_touch_unknown1.c', 'ipod_touch_lcd.c', 'ipod_touch_mipi_dsi.c', 'ipod_touch_fmss.c', 'ipod_touch_block_device.c', 'ipod_touch_mbx.c', 'ipod_touch_cd3272_mikey.c', 'ipod_touch_lis302dl.c', 'ipod_touch_multitouch.c', 'ipod_touch_scaler_csc.c', 'ipod_touch_sdio.c')) +arm_ss.add(when: 'CONFIG_IPOD_TOUCH_2G', if_true: files('ipod_touch_2g.c', 'ipod_touch_clock.c', 'ipod_touch_chipid.c', 'ipod_touch_gpio.c', 'ipod_touch_sysic.c', 'ipod_touch_timer.c', 'ipod_touch_usb_otg.c', 'ipod_touch_usb_phys.c', 'ipod_touch_spi.c', 'ipod_touch_nor_spi.c', 'ipod_touch_sha1.c', 'ipod_touch_aes.c', 'ipod_touch_pke.c', 'ipod_touch_pcf50633_pmu.c', 'ipod_touch_unknown1.c', 'ipod_touch_lcd.c', 'ipod_touch_mipi_dsi.c', 'ipod_touch_fmss.c', 'ipod_touch_block_device.c', 'ipod_touch_mbx.c', 'ipod_touch_cd3272_mikey.c', 'ipod_touch_lis302dl.c', 'ipod_touch_multitouch.c', 'ipod_touch_scaler_csc.c', 'ipod_touch_sdio.c', 'ipod_touch_tvout.c')) hw_arch += {'arm': arm_ss} diff --git a/include/hw/arm/ipod_touch_2g.h b/include/hw/arm/ipod_touch_2g.h index 4d302502f58e..4a3da59691b4 100644 --- a/include/hw/arm/ipod_touch_2g.h +++ b/include/hw/arm/ipod_touch_2g.h @@ -27,6 +27,7 @@ #include "hw/arm/ipod_touch_mbx.h" #include "hw/arm/ipod_touch_scaler_csc.h" #include "hw/arm/ipod_touch_sdio.h" +#include "hw/arm/ipod_touch_tvout.h" #define TYPE_IPOD_TOUCH "iPod-Touch" @@ -44,6 +45,7 @@ #define S5L8720_I2C0_IRQ 0x15 #define S5L8720_SPI3_IRQ 0x1C #define S5L8720_I2C1_IRQ 0x16 +#define S5L8720_TVOUT_SDO_IRQ 0x1E #define S5L8720_SDIO_IRQ 0x2A #define S5L8720_FMSS_IRQ 0x36 #define S5L8720_SPI4_IRQ 0x37 @@ -76,10 +78,9 @@ #define EDGEIC_MEM_BASE 0x38E02000 #define H264_MEM_BASE 0x38F00000 #define SCALER_CSC_MEM_BASE 0x39000000 -#define TVOUT1_MEM_BASE 0x39100000 -#define TVOUT2_MEM_BASE 0x39200000 -#define TVOUT3_MEM_BASE 0x39300000 -//#define BLOCK_DEVICE_MEM_BASE 0x39400000 +#define TVOUT_MIXER2_MEM_BASE 0x39100000 +#define TVOUT_MIXER1_MEM_BASE 0x39200000 +#define TVOUT_SDO_MEM_BASE 0x39300000 #define SYSIC_MEM_BASE 0x39700000 #define DMAC1_1_MEM_BASE 0x39900000 #define MBX1_MEM_BASE 0x3B000000 @@ -140,6 +141,7 @@ typedef struct { IPodTouchMBXState *mbx_state; IPodTouchScalerCSCState *scaler_csc_state; IPodTouchSDIOState *sdio_state; + IPodTouchTVOutState *tvout_state; Clock *sysclk; char nor_path[1024]; IT2G_CPREG_VAR_DEF(REG0); diff --git a/include/hw/arm/ipod_touch_tvout.h b/include/hw/arm/ipod_touch_tvout.h new file mode 100644 index 000000000000..c7f1f966b110 --- /dev/null +++ b/include/hw/arm/ipod_touch_tvout.h @@ -0,0 +1,38 @@ +#ifndef IPOD_TOUCH_TVOUT_H +#define IPOD_TOUCH_TVOUT_H + +#include "qemu/osdep.h" +#include "qemu/module.h" +#include "qemu/timer.h" +#include "hw/hw.h" +#include "hw/sysbus.h" +#include "hw/irq.h" + +#define SDO_IRQ 0x280 +#define SDO_IRQMASK 0x284 + +#define MXR_STATUS 0x0 +#define MXR_CFG 0x4 + +#define TYPE_IPOD_TOUCH_TVOUT "ipodtouch.tvout" +OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchTVOutState, IPOD_TOUCH_TVOUT) + +typedef struct IPodTouchTVOutState { + SysBusDevice parent_obj; + + MemoryRegion mixer1_iomem; + MemoryRegion mixer2_iomem; + MemoryRegion sdo_iomem; + qemu_irq irq; + + uint32_t mixer1_status; + uint32_t mixer1_cfg; + + uint32_t mixer2_status; + uint32_t mixer2_cfg; + + uint32_t sdo_irq; + uint32_t sdo_irq_mask; +} IPodTouchTVOutState; + +#endif \ No newline at end of file From 0bdff11572b9a55e8e0931adacc905de5a397c62 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Fri, 8 Sep 2023 17:29:18 +0200 Subject: [PATCH 39/58] Worked on TVOut --- hw/arm/ipod_touch_tvout.c | 33 ++++++++++++++++++++----------- include/hw/arm/ipod_touch_tvout.h | 6 ++++++ 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/hw/arm/ipod_touch_tvout.c b/hw/arm/ipod_touch_tvout.c index 3df4f2291e23..41dcd9f243bc 100644 --- a/hw/arm/ipod_touch_tvout.c +++ b/hw/arm/ipod_touch_tvout.c @@ -5,9 +5,13 @@ static uint64_t ipod_touch_tvout_sdo_read(void *opaque, hwaddr offset, unsigned { IPodTouchTVOutState *s = (IPodTouchTVOutState *)opaque; - printf("%s: offset = 0x%08x\n", __func__, offset); + //printf("%s: offset = 0x%08x\n", __func__, offset); switch(offset) { + case SDO_CLKCON: + return s->sdo_clkcon; + case SDO_CONFIG: + return s->sdo_config; case SDO_IRQ: return s->sdo_irq; case SDO_IRQMASK: @@ -23,12 +27,17 @@ static void ipod_touch_tvout_sdo_write(void *opaque, hwaddr offset, uint64_t val { IPodTouchTVOutState *s = (IPodTouchTVOutState *)opaque; - printf("%s: writing 0x%08x to 0x%08x\n", __func__, value, offset); + //printf("%s: writing 0x%08x to 0x%08x\n", __func__, value, offset); switch(offset) { + case SDO_CLKCON: + s->sdo_clkcon = value; + return; + case SDO_CONFIG: + s->sdo_config = value; + return; case SDO_IRQ: - s->sdo_irq = value; - printf("LOWERING SDO IRQ\n"); + s->sdo_irq = 0x0; qemu_irq_lower(s->irq); return; case SDO_IRQMASK: @@ -41,11 +50,11 @@ static uint64_t ipod_touch_tvout_mixer1_read(void *opaque, hwaddr offset, unsign { IPodTouchTVOutState *s = (IPodTouchTVOutState *)opaque; - printf("%s: offset = 0x%08x\n", __func__, offset); + //printf("%s: offset = 0x%08x\n", __func__, offset); switch(offset) { case MXR_STATUS: - return s->mixer1_status; + return 0x4; case MXR_CFG: return s->mixer1_cfg; default: @@ -59,13 +68,13 @@ static void ipod_touch_tvout_mixer1_write(void *opaque, hwaddr offset, uint64_t { IPodTouchTVOutState *s = (IPodTouchTVOutState *)opaque; - printf("%s: writing 0x%08x to 0x%08x\n", __func__, value, offset); + //printf("%s: writing 0x%08x to 0x%08x\n", __func__, value, offset); switch(offset) { case MXR_STATUS: - s->mixer1_status = value; - if(value == 0x185 && (s->sdo_irq_mask & 1) == 0) { - printf("Raising SDO irq\n"); + if((value & 0x1) && (s->sdo_irq_mask & 1) == 0 && s->irq_count < 2) { + s->sdo_irq = 0x1; + s->irq_count += 1; // ugly hack for now qemu_irq_raise(s->irq); } break; @@ -79,7 +88,7 @@ static uint64_t ipod_touch_tvout_mixer2_read(void *opaque, hwaddr offset, unsign { IPodTouchTVOutState *s = (IPodTouchTVOutState *)opaque; - printf("%s: offset = 0x%08x\n", __func__, offset); + //printf("%s: offset = 0x%08x\n", __func__, offset); switch(offset) { case MXR_STATUS: @@ -97,7 +106,7 @@ static void ipod_touch_tvout_mixer2_write(void *opaque, hwaddr offset, uint64_t { IPodTouchTVOutState *s = (IPodTouchTVOutState *)opaque; - printf("%s: writing 0x%08x to 0x%08x\n", __func__, value, offset); + //printf("%s: writing 0x%08x to 0x%08x\n", __func__, value, offset); switch(offset) { case MXR_STATUS: diff --git a/include/hw/arm/ipod_touch_tvout.h b/include/hw/arm/ipod_touch_tvout.h index c7f1f966b110..bf343b4a1749 100644 --- a/include/hw/arm/ipod_touch_tvout.h +++ b/include/hw/arm/ipod_touch_tvout.h @@ -8,6 +8,8 @@ #include "hw/sysbus.h" #include "hw/irq.h" +#define SDO_CLKCON 0x0 +#define SDO_CONFIG 0x8 #define SDO_IRQ 0x280 #define SDO_IRQMASK 0x284 @@ -31,8 +33,12 @@ typedef struct IPodTouchTVOutState { uint32_t mixer2_status; uint32_t mixer2_cfg; + uint32_t sdo_clkcon; + uint32_t sdo_config; uint32_t sdo_irq; uint32_t sdo_irq_mask; + + uint32_t irq_count; } IPodTouchTVOutState; #endif \ No newline at end of file From 603dafdb84de530330a3a660e1d308875659363f Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Fri, 3 Nov 2023 18:02:38 +0100 Subject: [PATCH 40/58] LCD + Multitouch working!! --- hw/arm/ipod_touch_2g.c | 17 ++++++++++---- hw/arm/ipod_touch_fmss.c | 2 +- hw/arm/ipod_touch_lcd.c | 41 ++++++++++++++++++++++++++------- hw/arm/ipod_touch_multitouch.c | 4 ++-- hw/arm/ipod_touch_sdio.c | 2 +- include/hw/arm/ipod_touch_2g.h | 9 ++++++++ include/hw/arm/ipod_touch_lcd.h | 4 ++++ 7 files changed, 63 insertions(+), 16 deletions(-) diff --git a/hw/arm/ipod_touch_2g.c b/hw/arm/ipod_touch_2g.c index 1d91f1b32d5e..81f9f4019933 100644 --- a/hw/arm/ipod_touch_2g.c +++ b/hw/arm/ipod_touch_2g.c @@ -194,10 +194,16 @@ static void ipod_touch_machine_init(MachineState *machine) IPodTouchSYSICState *sysic_state = IPOD_TOUCH_SYSIC(dev); nms->sysic = (IPodTouchSYSICState *) g_malloc0(sizeof(struct IPodTouchSYSICState)); memory_region_add_subregion(sysmem, SYSIC_MEM_BASE, &sysic_state->iomem); - // busdev = SYS_BUS_DEVICE(dev); - // for(int grp = 0; grp < GPIO_NUMINTGROUPS; grp++) { - // sysbus_connect_irq(busdev, grp, s5l8900_get_irq(nms, S5L8900_GPIO_IRQS[grp])); - // } + busdev = SYS_BUS_DEVICE(dev); + for(int grp = 0; grp < GPIO_NUMINTGROUPS; grp++) { + sysbus_connect_irq(busdev, grp, s5l8900_get_irq(nms, S5L8900_GPIO_IRQS[grp])); + } + + sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8900_GPIO_G0_IRQ)); + sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8900_GPIO_G1_IRQ)); + sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8900_GPIO_G2_IRQ)); + sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8900_GPIO_G3_IRQ)); + sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8900_GPIO_G4_IRQ)); // init GPIO dev = qdev_new("ipodtouch.gpio"); @@ -266,6 +272,8 @@ static void ipod_touch_machine_init(MachineState *machine) set_spi_base(4); dev = sysbus_create_simple("ipodtouch.spi", SPI4_MEM_BASE, s5l8900_get_irq(nms, S5L8720_SPI4_IRQ)); IPodTouchSPIState *spi4_state = IPOD_TOUCH_SPI(dev); + spi4_state->mt->sysic = sysic_state; + spi4_state->mt->gpio_state = gpio_state; nms->spi4_state = spi4_state; // init the chip ID module @@ -370,6 +378,7 @@ static void ipod_touch_machine_init(MachineState *machine) dev = qdev_new("ipodtouch.lcd"); IPodTouchLCDState *lcd_state = IPOD_TOUCH_LCD(dev); lcd_state->sysmem = sysmem; + lcd_state->mt = spi4_state->mt; nms->lcd_state = lcd_state; busdev = SYS_BUS_DEVICE(dev); memory_region_add_subregion(sysmem, DISPLAY_MEM_BASE, &lcd_state->iomem); diff --git a/hw/arm/ipod_touch_fmss.c b/hw/arm/ipod_touch_fmss.c index 455963d51ff1..3c88d956f924 100644 --- a/hw/arm/ipod_touch_fmss.c +++ b/hw/arm/ipod_touch_fmss.c @@ -93,7 +93,7 @@ static void read_nand_pages(IPodTouchFMSSState *s) static uint64_t ipod_touch_fmss_read(void *opaque, hwaddr addr, unsigned size) { - fprintf(stderr, "%s: read from location 0x%08x\n", __func__, addr); + //fprintf(stderr, "%s: read from location 0x%08x\n", __func__, addr); IPodTouchFMSSState *s = (IPodTouchFMSSState *)opaque; switch(addr) diff --git a/hw/arm/ipod_touch_lcd.c b/hw/arm/ipod_touch_lcd.c index 342944f1ab1d..22106568b1ef 100644 --- a/hw/arm/ipod_touch_lcd.c +++ b/hw/arm/ipod_touch_lcd.c @@ -5,7 +5,7 @@ static uint64_t ipod_touch_lcd_read(void *opaque, hwaddr addr, unsigned size) { - fprintf(stderr, "%s: read from location 0x%08x\n", __func__, addr); + //printf("%s: read from location 0x%08x\n", __func__, addr); IPodTouchLCDState *s = (IPodTouchLCDState *)opaque; switch(addr) @@ -14,6 +14,8 @@ static uint64_t ipod_touch_lcd_read(void *opaque, hwaddr addr, unsigned size) return 2; case 0x4: return s->lcd_con; + case 0xC: + return 0x1; //s->unknown1; case 0x20: return s->w1_display_depth_info; case 0x24: @@ -34,12 +36,16 @@ static uint64_t ipod_touch_lcd_read(void *opaque, hwaddr addr, unsigned size) static void ipod_touch_lcd_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { IPodTouchLCDState *s = (IPodTouchLCDState *)opaque; - fprintf(stderr, "%s: writing 0x%08x to 0x%08x\n", __func__, val, addr); + //printf("%s: writing 0x%08x to 0x%08x\n", __func__, val, addr); switch(addr) { case 0x4: s->lcd_con = val; break; + case 0xC: + s->unknown1 = val; + qemu_irq_lower(s->irq); + break; case 0x20: s->w1_display_depth_info = val; break; @@ -52,9 +58,6 @@ static void ipod_touch_lcd_write(void *opaque, hwaddr addr, uint64_t val, unsign case 0x30: s->w1_display_resolution_info = val; break; - case 0xC: - qemu_irq_lower(s->irq); - break; } } @@ -136,13 +139,35 @@ static const GraphicHwOps gfx_ops = { .gfx_update = lcd_refresh, }; +static void ipod_touch_lcd_mouse_event(void *opaque, int x, int y, int z, int buttons_state) +{ + //printf("CLICKY %d %d %d %d\n", x, y, z, buttons_state); + + // convert x and y to fractional numbers + float fx = x / pow(2, 15); + float fy = 1 - y / pow(2, 15); + + IPodTouchLCDState *lcd = (IPodTouchLCDState *) opaque; + lcd->mt->prev_touch_x = lcd->mt->touch_x; + lcd->mt->prev_touch_y = lcd->mt->touch_y; + lcd->mt->touch_x = fx; + lcd->mt->touch_y = fy; + + if(buttons_state && !lcd->mt->touch_down) { + ipod_touch_multitouch_on_touch(lcd->mt); + } + else if(!buttons_state && lcd->mt->touch_down) { + ipod_touch_multitouch_on_release(lcd->mt); + } +} + static void refresh_timer_tick(void *opaque) { IPodTouchLCDState *s = (IPodTouchLCDState *)opaque; - //qemu_irq_raise(s->irq); + qemu_irq_raise(s->irq); - //timer_mod(s->refresh_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + NANOSECONDS_PER_SECOND / LCD_REFRESH_RATE_FREQUENCY); + timer_mod(s->refresh_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + NANOSECONDS_PER_SECOND / LCD_REFRESH_RATE_FREQUENCY); } static void ipod_touch_lcd_realize(DeviceState *dev, Error **errp) @@ -152,7 +177,7 @@ static void ipod_touch_lcd_realize(DeviceState *dev, Error **errp) qemu_console_resize(s->con, 320, 480); // add mouse handler - //qemu_add_mouse_event_handler(ipod_touch_lcd_mouse_event, s, 1, "iPod Touch Touchscreen"); + qemu_add_mouse_event_handler(ipod_touch_lcd_mouse_event, s, 1, "iPod Touch Touchscreen"); // initialize the refresh timer s->refresh_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, refresh_timer_tick, s); diff --git a/hw/arm/ipod_touch_multitouch.c b/hw/arm/ipod_touch_multitouch.c index 85fdb5a020e2..cff561000e25 100644 --- a/hw/arm/ipod_touch_multitouch.c +++ b/hw/arm/ipod_touch_multitouch.c @@ -338,8 +338,8 @@ static MTFrame *get_frame(IPodTouchMultitouchState *s, uint8_t event, float x, f } static void ipod_touch_multitouch_inform_frame_ready(IPodTouchMultitouchState *s) { - s->sysic->gpio_int_status[4] |= (1 << 27); // the multitouch interrupt bit is in group 4 (32 interrupts per group), and the 27th of the 4th group - qemu_irq_raise(s->sysic->gpio_irqs[4]); + s->sysic->gpio_int_status[3] |= (1 << 13); // the multitouch interrupt bit is in group 3 (32 interrupts per group), and the 13th of the 3th group + qemu_irq_raise(s->sysic->gpio_irqs[3]); } void ipod_touch_multitouch_on_touch(IPodTouchMultitouchState *s) { diff --git a/hw/arm/ipod_touch_sdio.c b/hw/arm/ipod_touch_sdio.c index 26c4009e8ce5..0fe2799e3a4b 100644 --- a/hw/arm/ipod_touch_sdio.c +++ b/hw/arm/ipod_touch_sdio.c @@ -66,7 +66,7 @@ void sdio_exec_cmd(IPodTouchSDIOState *s) frame_header->checksum = length ^ 0xffff; g_queue_push_tail(s->rx_fifo, frame_header); - timer_mod(s->irq_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + NANOSECONDS_PER_SECOND / 50); + timer_mod(s->irq_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + NANOSECONDS_PER_SECOND / 100); } } else { if(func == 0x1) { diff --git a/include/hw/arm/ipod_touch_2g.h b/include/hw/arm/ipod_touch_2g.h index 4a3da59691b4..5e5698434d26 100644 --- a/include/hw/arm/ipod_touch_2g.h +++ b/include/hw/arm/ipod_touch_2g.h @@ -50,6 +50,15 @@ #define S5L8720_FMSS_IRQ 0x36 #define S5L8720_SPI4_IRQ 0x37 +// GPIO interrupts +#define S5L8900_GPIO_G0_IRQ 0x21 +#define S5L8900_GPIO_G1_IRQ 0x20 +#define S5L8900_GPIO_G2_IRQ 0x1F +#define S5L8900_GPIO_G3_IRQ 0x03 +#define S5L8900_GPIO_G4_IRQ 0x02 + +const int S5L8900_GPIO_IRQS[5] = { S5L8900_GPIO_G0_IRQ, S5L8900_GPIO_G1_IRQ, S5L8900_GPIO_G2_IRQ, S5L8900_GPIO_G3_IRQ, S5L8900_GPIO_G4_IRQ }; + #define IT2G_CPREG_VAR_NAME(name) cpreg_##name #define IT2G_CPREG_VAR_DEF(name) uint64_t IT2G_CPREG_VAR_NAME(name) diff --git a/include/hw/arm/ipod_touch_lcd.h b/include/hw/arm/ipod_touch_lcd.h index be60582d407e..f8c8c5c7c709 100644 --- a/include/hw/arm/ipod_touch_lcd.h +++ b/include/hw/arm/ipod_touch_lcd.h @@ -7,6 +7,7 @@ #include "qemu/timer.h" #include "hw/sysbus.h" #include "hw/irq.h" +#include "hw/arm/ipod_touch_multitouch.h" #define TYPE_IPOD_TOUCH_LCD "ipodtouch.lcd" OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchLCDState, IPOD_TOUCH_LCD) @@ -19,6 +20,7 @@ typedef struct IPodTouchLCDState MemoryRegion *sysmem; MemoryRegion iomem; QemuConsole *con; + IPodTouchMultitouchState *mt; int invalidate; MemoryRegionSection fbsection; qemu_irq irq; @@ -29,6 +31,8 @@ typedef struct IPodTouchLCDState uint32_t w1_hspan; uint32_t w1_display_depth_info; + uint32_t unknown1; + QEMUTimer *refresh_timer; } IPodTouchLCDState; From 8b4c1455b7fa6418fe6fab1938e88c7726fff9e0 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Fri, 3 Nov 2023 18:16:18 +0100 Subject: [PATCH 41/58] Prevent GUI grab --- ui/sdl2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/sdl2.c b/ui/sdl2.c index 8cb77416af2b..61765f8d411f 100644 --- a/ui/sdl2.c +++ b/ui/sdl2.c @@ -208,6 +208,7 @@ static void sdl_show_cursor(struct sdl2_console *scon) static void sdl_grab_start(struct sdl2_console *scon) { + return; QemuConsole *con = scon ? scon->dcl.con : NULL; if (!con || !qemu_console_is_graphic(con)) { From 9390b5a38c4c14940589012cab8fa8e9255b43fa Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Sat, 4 Nov 2023 14:08:38 +0100 Subject: [PATCH 42/58] Home/power buttons working --- hw/arm/ipod_touch_2g.c | 43 ++++++++++++++++++++++++++++++++ hw/arm/ipod_touch_gpio.c | 6 ++--- include/hw/arm/ipod_touch_2g.h | 1 + include/hw/arm/ipod_touch_gpio.h | 8 +++--- 4 files changed, 51 insertions(+), 7 deletions(-) diff --git a/hw/arm/ipod_touch_2g.c b/hw/arm/ipod_touch_2g.c index 81f9f4019933..7ceaf131f1dc 100644 --- a/hw/arm/ipod_touch_2g.c +++ b/hw/arm/ipod_touch_2g.c @@ -132,6 +132,47 @@ static uint32_t s5l8720_usb_hwcfg[] = { 0x01f08024 }; +static void ipod_touch_key_event(void *opaque, int keycode) +{ + bool do_irq = false; + int gpio_group = 0, gpio_selector = 0; + + IPodTouchMultitouchState *s = (IPodTouchMultitouchState *)opaque; + if(keycode == 25 || keycode == 153) { + // power button + gpio_group = GPIO_BUTTON_POWER_IRQ / NUM_GPIO_PINS; + gpio_selector = GPIO_BUTTON_POWER_IRQ % NUM_GPIO_PINS; + + if(keycode == 25 && (s->gpio_state->gpio_state & (1 << (GPIO_BUTTON_POWER & 0xf))) == 0) { + s->gpio_state->gpio_state |= (1 << (GPIO_BUTTON_POWER & 0xf)); + do_irq = true; + } + else if(keycode == 153) { + s->gpio_state->gpio_state &= ~(1 << (GPIO_BUTTON_POWER & 0xf)); + do_irq = true; + } + } + else if(keycode == 35 || keycode == 163) { + // home button + gpio_group = GPIO_BUTTON_HOME_IRQ / NUM_GPIO_PINS; + gpio_selector = GPIO_BUTTON_HOME_IRQ % NUM_GPIO_PINS; + + if(keycode == 35 && (s->gpio_state->gpio_state & (1 << (GPIO_BUTTON_HOME & 0xf))) == 0) { + s->gpio_state->gpio_state |= (1 << (GPIO_BUTTON_HOME & 0xf)); + do_irq = true; + } + else if(keycode == 163) { + s->gpio_state->gpio_state &= ~(1 << (GPIO_BUTTON_HOME & 0xf)); + do_irq = true; + } + } + + if(do_irq) { + s->sysic->gpio_int_status[gpio_group] |= (1 << gpio_selector); + qemu_irq_raise(s->sysic->gpio_irqs[gpio_group]); + } +} + static void ipod_touch_machine_init(MachineState *machine) { IPodTouchMachineState *nms = IPOD_TOUCH_MACHINE(machine); @@ -425,6 +466,8 @@ static void ipod_touch_machine_init(MachineState *machine) memory_region_add_subregion(sysmem, MBX2_MEM_BASE, &mbx_state->iomem2); qemu_register_reset(ipod_touch_cpu_reset, nms); + + qemu_add_kbd_event_handler(ipod_touch_key_event, spi4_state->mt); } static void ipod_touch_machine_class_init(ObjectClass *klass, void *data) diff --git a/hw/arm/ipod_touch_gpio.c b/hw/arm/ipod_touch_gpio.c index 8941a505db49..cefad9ebee52 100644 --- a/hw/arm/ipod_touch_gpio.c +++ b/hw/arm/ipod_touch_gpio.c @@ -13,11 +13,11 @@ static void s5l8900_gpio_write(void *opaque, hwaddr addr, uint64_t value, unsign static uint64_t s5l8900_gpio_read(void *opaque, hwaddr addr, unsigned size) { - //fprintf(stderr, "%s: read from location 0x%08x\n", __func__, addr); + fprintf(stderr, "%s: read from location 0x%08x\n", __func__, addr); IPodTouchGPIOState *s = (struct IPodTouchGPIOState *) opaque; switch(addr) { - case 0x2c4: + case 0x184: // TODO: This offset only makes sure that the GPIO triggers associated with the home/power button work correctly!! return s->gpio_state; default: break; @@ -38,7 +38,7 @@ static void s5l8900_gpio_init(Object *obj) DeviceState *dev = DEVICE(sbd); IPodTouchGPIOState *s = IPOD_TOUCH_GPIO(dev); - memory_region_init_io(&s->iomem, obj, &gpio_ops, s, "gpio", 0x10000); + memory_region_init_io(&s->iomem, obj, &gpio_ops, s, "gpio", 0x1000); } static void s5l8900_gpio_class_init(ObjectClass *klass, void *data) diff --git a/include/hw/arm/ipod_touch_2g.h b/include/hw/arm/ipod_touch_2g.h index 5e5698434d26..4df65cf51632 100644 --- a/include/hw/arm/ipod_touch_2g.h +++ b/include/hw/arm/ipod_touch_2g.h @@ -5,6 +5,7 @@ #include "hw/boards.h" #include "hw/intc/pl192.h" #include "hw/arm/boot.h" +#include "ui/console.h" #include "cpu.h" #include "hw/dma/pl080.h" #include "hw/i2c/ipod_touch_i2c.h" diff --git a/include/hw/arm/ipod_touch_gpio.h b/include/hw/arm/ipod_touch_gpio.h index 1707e39a76e8..bdb093c9787f 100644 --- a/include/hw/arm/ipod_touch_gpio.h +++ b/include/hw/arm/ipod_touch_gpio.h @@ -10,11 +10,11 @@ #define TYPE_IPOD_TOUCH_GPIO "ipodtouch.gpio" OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchGPIOState, IPOD_TOUCH_GPIO) -#define GPIO_BUTTON_POWER 0x1605 -#define GPIO_BUTTON_HOME 0x1606 +#define GPIO_BUTTON_POWER 0xC02 +#define GPIO_BUTTON_HOME 0xC01 -#define GPIO_BUTTON_POWER_IRQ 0x2D -#define GPIO_BUTTON_HOME_IRQ 0x2E +#define GPIO_BUTTON_POWER_IRQ 0x7A +#define GPIO_BUTTON_HOME_IRQ 0x79 #define NUM_GPIO_PINS 0x20 From 4a95aeacb3daaa07475d23f89c7a95c81c0c8e24 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Wed, 8 Nov 2023 19:49:54 +0100 Subject: [PATCH 43/58] Removed print statement --- hw/arm/ipod_touch_multitouch.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/arm/ipod_touch_multitouch.c b/hw/arm/ipod_touch_multitouch.c index cff561000e25..4a7dbac0aa68 100644 --- a/hw/arm/ipod_touch_multitouch.c +++ b/hw/arm/ipod_touch_multitouch.c @@ -194,7 +194,6 @@ static uint32_t ipod_touch_multitouch_transfer(SSIPeripheral *dev, uint32_t valu s->buf_size = 16; } else if(value == MT_CMD_FRAME_READ) { - printf("Will read frame!\n"); s->buf_size = sizeof(MTFrame); free(s->out_buffer); s->out_buffer = (uint8_t *) s->next_frame; From 6024cbc9838158643826503576fd0d4e0b7a0a4f Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Wed, 8 Nov 2023 21:18:14 +0100 Subject: [PATCH 44/58] Made paths flexible --- hw/arm/ipod_touch_2g.c | 54 ++++++++---- hw/arm/ipod_touch_block_device.c | 108 ----------------------- hw/arm/ipod_touch_fmss.c | 13 +-- hw/arm/ipod_touch_nor_spi.c | 7 +- hw/arm/ipod_touch_spi.c | 10 +-- hw/arm/meson.build | 2 +- include/hw/arm/ipod_touch_2g.h | 5 +- include/hw/arm/ipod_touch_block_device.h | 26 ------ include/hw/arm/ipod_touch_fmss.h | 1 + include/hw/arm/ipod_touch_nor_spi.h | 2 +- include/hw/arm/ipod_touch_spi.h | 2 +- 11 files changed, 51 insertions(+), 179 deletions(-) delete mode 100644 hw/arm/ipod_touch_block_device.c delete mode 100644 include/hw/arm/ipod_touch_block_device.h diff --git a/hw/arm/ipod_touch_2g.c b/hw/arm/ipod_touch_2g.c index 7ceaf131f1dc..bf0476642a19 100644 --- a/hw/arm/ipod_touch_2g.c +++ b/hw/arm/ipod_touch_2g.c @@ -96,12 +96,24 @@ static void ipod_touch_memory_setup(MachineState *machine, MemoryRegion *sysmem, // load the bootrom (vrom) uint8_t *file_data = NULL; unsigned long fsize; - if (g_file_get_contents("/Users/martijndevos/Documents/ipod_touch_2g_emulation/bootrom_240_4", (char **)&file_data, &fsize, NULL)) { + if (g_file_get_contents(nms->bootrom_path, (char **)&file_data, &fsize, NULL)) { allocate_ram(sysmem, "vrom", 0x0, 0x20000); address_space_rw(nsas, VROM_MEM_BASE, MEMTXATTRS_UNSPECIFIED, (uint8_t *)file_data, fsize, 1); } } +static char *ipod_touch_get_bootrom_path(Object *obj, Error **errp) +{ + IPodTouchMachineState *nms = IPOD_TOUCH_MACHINE(obj); + return g_strdup(nms->bootrom_path); +} + +static void ipod_touch_set_bootrom_path(Object *obj, const char *value, Error **errp) +{ + IPodTouchMachineState *nms = IPOD_TOUCH_MACHINE(obj); + g_strlcpy(nms->bootrom_path, value, sizeof(nms->bootrom_path)); +} + static char *ipod_touch_get_nor_path(Object *obj, Error **errp) { IPodTouchMachineState *nms = IPOD_TOUCH_MACHINE(obj); @@ -114,10 +126,28 @@ static void ipod_touch_set_nor_path(Object *obj, const char *value, Error **errp g_strlcpy(nms->nor_path, value, sizeof(nms->nor_path)); } +static char *ipod_touch_get_nand_path(Object *obj, Error **errp) +{ + IPodTouchMachineState *nms = IPOD_TOUCH_MACHINE(obj); + return g_strdup(nms->nand_path); +} + +static void ipod_touch_set_nand_path(Object *obj, const char *value, Error **errp) +{ + IPodTouchMachineState *nms = IPOD_TOUCH_MACHINE(obj); + g_strlcpy(nms->nand_path, value, sizeof(nms->nand_path)); +} + static void ipod_touch_instance_init(Object *obj) { + object_property_add_str(obj, "bootrom", ipod_touch_get_bootrom_path, ipod_touch_set_bootrom_path); + object_property_set_description(obj, "bootrom", "Path to the S5L8720 bootrom binary"); + object_property_add_str(obj, "nor", ipod_touch_get_nor_path, ipod_touch_set_nor_path); object_property_set_description(obj, "nor", "Path to the S5L8720 NOR image"); + + object_property_add_str(obj, "nand", ipod_touch_get_nand_path, ipod_touch_set_nand_path); + object_property_set_description(obj, "nand", "Path to the NAND files"); } static inline qemu_irq s5l8900_get_irq(IPodTouchMachineState *s, int n) @@ -263,26 +293,22 @@ static void ipod_touch_machine_init(MachineState *machine) dev = exynos4210_uart_create(UART0_MEM_BASE, 256, 0, serial_hd(0), nms->irq[0][24]); if (!dev) { - printf("Failed to create uart0 device!\n"); - abort(); + hw_error("Failed to create UART0 device!"); } dev = exynos4210_uart_create(UART1_MEM_BASE, 256, 1, serial_hd(1), nms->irq[0][25]); if (!dev) { - printf("Failed to create uart1 device!\n"); - abort(); + hw_error("Failed to create UART0 device!"); } dev = exynos4210_uart_create(UART2_MEM_BASE, 256, 2, serial_hd(2), nms->irq[0][26]); if (!dev) { - printf("Failed to create uart2 device!\n"); - abort(); + hw_error("Failed to create UART0 device!"); } dev = exynos4210_uart_create(UART3_MEM_BASE, 256, 3, serial_hd(3), nms->irq[0][27]); if (!dev) { - printf("Failed to create uart3 device!\n"); - abort(); + hw_error("Failed to create UART0 device!"); } // dev = exynos4210_uart_create(UART4_MEM_BASE, 256, 4, serial_hd(4), nms->irq[0][28]); @@ -295,14 +321,13 @@ static void ipod_touch_machine_init(MachineState *machine) set_spi_base(0); dev = sysbus_create_simple("ipodtouch.spi", SPI0_MEM_BASE, s5l8900_get_irq(nms, S5L8720_SPI0_IRQ)); IPodTouchSPIState *spi0_state = IPOD_TOUCH_SPI(dev); + spi0_state->nor->nor_path = nms->nor_path; nms->spi0_state = spi0_state; - strcpy(spi0_state->nor->nor_path, nms->nor_path); set_spi_base(1); dev = sysbus_create_simple("ipodtouch.spi", SPI1_MEM_BASE, s5l8900_get_irq(nms, S5L8720_SPI1_IRQ)); IPodTouchSPIState *spi1_state = IPOD_TOUCH_SPI(dev); nms->spi1_state = spi1_state; - //strcpy(spi1_state->nor->nor_path, nms->nor_path); set_spi_base(2); sysbus_create_simple("ipodtouch.spi", SPI2_MEM_BASE, s5l8900_get_irq(nms, S5L8720_SPI2_IRQ)); @@ -395,6 +420,7 @@ static void ipod_touch_machine_init(MachineState *machine) // init the FMSS flash controller dev = qdev_new("ipodtouch.fmss"); IPodTouchFMSSState *fmss_state = IPOD_TOUCH_FMSS(dev); + fmss_state->nand_path = nms->nand_path; nms->fmss_state = fmss_state; busdev = SYS_BUS_DEVICE(dev); memory_region_add_subregion(sysmem, FMSS_MEM_BASE, &fmss_state->iomem); @@ -452,12 +478,6 @@ static void ipod_touch_machine_init(MachineState *machine) nms->pke_state = pke_state; memory_region_add_subregion(sysmem, PKE_MEM_BASE, &pke_state->iomem); - // init block device engine - dev = qdev_new("ipodtouch.blockdevice"); - IPodTouchBlockDeviceState *bdev_state = IPOD_TOUCH_BLOCK_DEVICE(dev); - nms->bdev_state = bdev_state; - memory_region_add_subregion(sysmem, BLOCK_DEVICE_MEM_BASE, &bdev_state->iomem); - // init the MBX dev = qdev_new("ipodtouch.mbx"); IPodTouchMBXState *mbx_state = IPOD_TOUCH_MBX(dev); diff --git a/hw/arm/ipod_touch_block_device.c b/hw/arm/ipod_touch_block_device.c deleted file mode 100644 index 2173ac09ac7c..000000000000 --- a/hw/arm/ipod_touch_block_device.c +++ /dev/null @@ -1,108 +0,0 @@ -#include "hw/arm/ipod_touch_block_device.h" -#include "hw/hw.h" - -static uint64_t ipod_touch_block_device_read(void *opaque, hwaddr addr, unsigned size) -{ - fprintf(stderr, "%s: read from location 0x%08x\n", __func__, addr); - - IPodTouchBlockDeviceState *s = (IPodTouchBlockDeviceState *)opaque; - switch(addr) - { - default: - // hw_error("%s: read invalid location 0x%08x.\n", __func__, addr); - break; - } - return 0; -} - -static void ipod_touch_block_device_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) -{ - IPodTouchBlockDeviceState *s = (IPodTouchBlockDeviceState *)opaque; - fprintf(stderr, "%s: writing 0x%08x to 0x%08x\n", __func__, val, addr); - - switch(addr) - { - case 0x0: - s->block_num_reg = val; - break; - case 0x4: - s->num_blocks_reg = val; - break; - case 0x8: - s->out_addr_reg = val; - break; - default: - // hw_error("%s: read invalid location 0x%08x.\n", __func__, addr); - break; - } - - if(addr == 0x8) { - // load the block - printf("Will load block %d (count: %d) into address 0x%08x\n", s->block_num_reg, s->num_blocks_reg, s->out_addr_reg); - - for(int block_nr = 0; block_nr < s->num_blocks_reg; block_nr++) { - char filename[200]; - int block_to_read = s->block_num_reg + block_nr; - sprintf(filename, "/Users/martijndevos/Documents/generate_nand_it2g/blocks/%d.blk", block_to_read); - struct stat st = {0}; - if (stat(filename, &st) == -1) { - printf("Will preparing empty block %d", block_to_read); - // page storage does not exist - initialize an empty buffer - memset(s->block_buffer, 0, BYTES_PER_BLOCK); - } - else { - FILE *f = fopen(filename, "rb"); - if (f == NULL) { hw_error("Unable to read file!"); } - fread(s->block_buffer, sizeof(char), BYTES_PER_BLOCK, f); - fclose(f); - } - - cpu_physical_memory_write(s->out_addr_reg + block_nr * BYTES_PER_BLOCK, s->block_buffer, BYTES_PER_BLOCK); - } - } -} - -static const MemoryRegionOps block_device_ops = { - .read = ipod_touch_block_device_read, - .write = ipod_touch_block_device_write, - .endianness = DEVICE_NATIVE_ENDIAN, -}; - -static void ipod_touch_block_device_realize(DeviceState *dev, Error **errp) -{ - -} - -static void ipod_touch_block_device_init(Object *obj) -{ - SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - DeviceState *dev = DEVICE(sbd); - IPodTouchBlockDeviceState *s = IPOD_TOUCH_BLOCK_DEVICE(dev); - - memory_region_init_io(&s->iomem, obj, &block_device_ops, s, "block_device", 0x100); - sysbus_init_mmio(sbd, &s->iomem); - - s->block_buffer = (uint8_t *)malloc(BYTES_PER_BLOCK); -} - -static void ipod_touch_block_device_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = ipod_touch_block_device_realize; -} - -static const TypeInfo ipod_touch_block_device_info = { - .name = TYPE_IPOD_TOUCH_BLOCK_DEVICE, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(IPodTouchBlockDeviceState), - .instance_init = ipod_touch_block_device_init, - .class_init = ipod_touch_block_device_class_init, -}; - -static void ipod_touch_machine_types(void) -{ - type_register_static(&ipod_touch_block_device_info); -} - -type_init(ipod_touch_machine_types) \ No newline at end of file diff --git a/hw/arm/ipod_touch_fmss.c b/hw/arm/ipod_touch_fmss.c index 3c88d956f924..4cd105d48c68 100644 --- a/hw/arm/ipod_touch_fmss.c +++ b/hw/arm/ipod_touch_fmss.c @@ -1,12 +1,5 @@ #include "hw/arm/ipod_touch_fmss.h" -static uint32_t reverse_byte_order(uint32_t value) { - return ((value & 0x000000FF) << 24) | - ((value & 0x0000FF00) << 8) | - ((value & 0x00FF0000) >> 8) | - ((value & 0xFF000000) >> 24); -} - static uint8_t find_bit_index(uint8_t num) { int index = 0; while (num > 1) { @@ -35,7 +28,7 @@ static void read_nand_pages(IPodTouchFMSSState *s) cpu_physical_memory_write(0x0ff2a584, boot_args, strlen(boot_args)); // patch iBoot - we want to inject the bluetooth MAC address which is located as sub-node of uart1 and not uart3 in the device tree... - char *chr = "arm-io/uart1/bluetooth"; + const char *chr = "arm-io/uart1/bluetooth"; cpu_physical_memory_write(0x0ff2206c, chr, strlen(chr)); int page_out_buf_ind = 0; @@ -51,14 +44,14 @@ static void read_nand_pages(IPodTouchFMSSState *s) cs = find_bit_index(cs); if(cs > 3) { - printf("CS %d invalid! (og CS: %d, reading page %d)\n", cs, og_cs, page_nr); + printf("CS %d invalid! (original CS: %d, reading page %d)\n", cs, og_cs, page_nr); dump_registers(s); hw_error("CS %d invalid!", cs); } // prepare the page char filename[200]; - sprintf(filename, "/Users/martijndevos/Documents/generate_nand_it2g/nand/cs%d/%d.page", cs, page_nr); + sprintf(filename, "%s/cs%d/%d.page", s->nand_path, cs, page_nr); struct stat st = {0}; if (stat(filename, &st) == -1) { // page storage does not exist - initialize an empty buffer diff --git a/hw/arm/ipod_touch_nor_spi.c b/hw/arm/ipod_touch_nor_spi.c index aedd2b6c381e..b6d4591d337f 100644 --- a/hw/arm/ipod_touch_nor_spi.c +++ b/hw/arm/ipod_touch_nor_spi.c @@ -3,8 +3,7 @@ static void initialize_nor(IPodTouchNORSPIState *s) { unsigned long fsize; - // TODO still hardcoded, string copy not working... - if (g_file_get_contents("/Users/martijndevos/Documents/generate_nor_it2g/nor.bin", (char **)&s->nor_data, &fsize, NULL)) { + if (g_file_get_contents(s->nor_path, (char **)&s->nor_data, &fsize, NULL)) { s->nor_initialized = true; } } @@ -21,7 +20,6 @@ static uint32_t ipod_touch_nor_spi_transfer(SSIPeripheral *dev, uint32_t value) if(s->cur_cmd == 0) { // this is a new command -> set it s->cur_cmd = value; - printf("NEW CMD %d\n", s->cur_cmd); s->out_buf = malloc(0x1000); s->in_buf = malloc(0x1000); s->in_buf[0] = value; @@ -35,7 +33,6 @@ static uint32_t ipod_touch_nor_spi_transfer(SSIPeripheral *dev, uint32_t value) s->out_buf[0] = 0; } else if(value == NOR_GET_STATUS_CMD) { - printf("GET STATUS\n"); s->in_buf_size = 1; s->out_buf_size = 1; s->out_buf[0] = 0; @@ -46,7 +43,6 @@ static uint32_t ipod_touch_nor_spi_transfer(SSIPeripheral *dev, uint32_t value) for(int i = 0; i < 256; i++) { s->out_buf[i] = 0; }; // TODO we ignore this command for now } else if(value == NOR_READ_DATA_CMD) { - printf("Received read command!\n"); s->in_buf_size = 4; s->out_buf_size = 4096; } @@ -88,7 +84,6 @@ static uint32_t ipod_touch_nor_spi_transfer(SSIPeripheral *dev, uint32_t value) else if(s->cur_cmd == NOR_READ_DATA_CMD && s->in_buf_cur_ind == s->in_buf_size) { if(!s->nor_initialized) { initialize_nor(s); } s->nor_read_ind = (s->in_buf[1] << 16) | (s->in_buf[2] << 8) | s->in_buf[3]; - printf("Setting NOR read index to: %d\n", s->nor_read_ind); } return 0x0; } diff --git a/hw/arm/ipod_touch_spi.c b/hw/arm/ipod_touch_spi.c index a8b1cabb4c89..49924b8e53e9 100644 --- a/hw/arm/ipod_touch_spi.c +++ b/hw/arm/ipod_touch_spi.c @@ -286,17 +286,15 @@ static void ipod_touch_spi_realize(DeviceState *dev, struct Error **errp) fifo8_create(&s->rx_fifo, R_FIFO_RX_DEPTH); // create the peripheral - IPodTouchNORSPIState *nor; switch(s->base) { case 0: - ssi_create_peripheral(s->spi, TYPE_IPOD_TOUCH_NOR_SPI); - nor = IPOD_TOUCH_NOR_SPI(dev); + { + DeviceState *dev = ssi_create_peripheral(s->spi, TYPE_IPOD_TOUCH_NOR_SPI); + IPodTouchNORSPIState *nor = IPOD_TOUCH_NOR_SPI(dev); s->nor = nor; break; + } case 1: - //ssi_create_peripheral(s->spi, TYPE_IPOD_TOUCH_NOR_SPI); - //nor = IPOD_TOUCH_NOR_SPI(dev); - //s->nor = nor; break; case 4: { diff --git a/hw/arm/meson.build b/hw/arm/meson.build index 4071eeebc8d9..5963b71ef260 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -62,6 +62,6 @@ arm_ss.add(when: 'CONFIG_FSL_IMX7', if_true: files('fsl-imx7.c', 'mcimx7d-sabre. arm_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c', 'smmuv3.c')) arm_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c')) arm_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c')) -arm_ss.add(when: 'CONFIG_IPOD_TOUCH_2G', if_true: files('ipod_touch_2g.c', 'ipod_touch_clock.c', 'ipod_touch_chipid.c', 'ipod_touch_gpio.c', 'ipod_touch_sysic.c', 'ipod_touch_timer.c', 'ipod_touch_usb_otg.c', 'ipod_touch_usb_phys.c', 'ipod_touch_spi.c', 'ipod_touch_nor_spi.c', 'ipod_touch_sha1.c', 'ipod_touch_aes.c', 'ipod_touch_pke.c', 'ipod_touch_pcf50633_pmu.c', 'ipod_touch_unknown1.c', 'ipod_touch_lcd.c', 'ipod_touch_mipi_dsi.c', 'ipod_touch_fmss.c', 'ipod_touch_block_device.c', 'ipod_touch_mbx.c', 'ipod_touch_cd3272_mikey.c', 'ipod_touch_lis302dl.c', 'ipod_touch_multitouch.c', 'ipod_touch_scaler_csc.c', 'ipod_touch_sdio.c', 'ipod_touch_tvout.c')) +arm_ss.add(when: 'CONFIG_IPOD_TOUCH_2G', if_true: files('ipod_touch_2g.c', 'ipod_touch_clock.c', 'ipod_touch_chipid.c', 'ipod_touch_gpio.c', 'ipod_touch_sysic.c', 'ipod_touch_timer.c', 'ipod_touch_usb_otg.c', 'ipod_touch_usb_phys.c', 'ipod_touch_spi.c', 'ipod_touch_nor_spi.c', 'ipod_touch_sha1.c', 'ipod_touch_aes.c', 'ipod_touch_pke.c', 'ipod_touch_pcf50633_pmu.c', 'ipod_touch_unknown1.c', 'ipod_touch_lcd.c', 'ipod_touch_mipi_dsi.c', 'ipod_touch_fmss.c', 'ipod_touch_mbx.c', 'ipod_touch_cd3272_mikey.c', 'ipod_touch_lis302dl.c', 'ipod_touch_multitouch.c', 'ipod_touch_scaler_csc.c', 'ipod_touch_sdio.c', 'ipod_touch_tvout.c')) hw_arch += {'arm': arm_ss} diff --git a/include/hw/arm/ipod_touch_2g.h b/include/hw/arm/ipod_touch_2g.h index 4df65cf51632..8f1d87f51776 100644 --- a/include/hw/arm/ipod_touch_2g.h +++ b/include/hw/arm/ipod_touch_2g.h @@ -24,7 +24,6 @@ #include "hw/arm/ipod_touch_lcd.h" #include "hw/arm/ipod_touch_mipi_dsi.h" #include "hw/arm/ipod_touch_fmss.h" -#include "hw/arm/ipod_touch_block_device.h" #include "hw/arm/ipod_touch_mbx.h" #include "hw/arm/ipod_touch_scaler_csc.h" #include "hw/arm/ipod_touch_sdio.h" @@ -80,7 +79,6 @@ const int S5L8900_GPIO_IRQS[5] = { S5L8900_GPIO_G0_IRQ, S5L8900_GPIO_G1_IRQ, S5L #define DMAC1_0_MEM_BASE 0x38700000 #define DISPLAY_MEM_BASE 0x38900000 #define FMSS_MEM_BASE 0x38A00000 -#define BLOCK_DEVICE_MEM_BASE 0x38A00F00 #define AES_MEM_BASE 0x38C00000 #define SDIO_MEM_BASE 0x38D00000 #define VIC0_MEM_BASE 0x38E00000 @@ -147,13 +145,14 @@ typedef struct { IPodTouchLCDState *lcd_state; IPodTouchMIPIDSIState *mipi_dsi_state; IPodTouchFMSSState *fmss_state; - IPodTouchBlockDeviceState *bdev_state; IPodTouchMBXState *mbx_state; IPodTouchScalerCSCState *scaler_csc_state; IPodTouchSDIOState *sdio_state; IPodTouchTVOutState *tvout_state; Clock *sysclk; + char bootrom_path[1024]; char nor_path[1024]; + char nand_path[1024]; IT2G_CPREG_VAR_DEF(REG0); IT2G_CPREG_VAR_DEF(REG1); } IPodTouchMachineState; diff --git a/include/hw/arm/ipod_touch_block_device.h b/include/hw/arm/ipod_touch_block_device.h deleted file mode 100644 index 55bcf0a049f3..000000000000 --- a/include/hw/arm/ipod_touch_block_device.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef IPOD_TOUCH_BLOCK_DEVICE_H -#define IPOD_TOUCH_BLOCK_DEVICE_H - -#include -#include "qemu/osdep.h" -#include "qemu/module.h" -#include "qemu/timer.h" -#include "hw/sysbus.h" - -#define TYPE_IPOD_TOUCH_BLOCK_DEVICE "ipodtouch.blockdevice" -OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchBlockDeviceState, IPOD_TOUCH_BLOCK_DEVICE) - -#define BYTES_PER_BLOCK 4096 - -typedef struct IPodTouchBlockDeviceState -{ - SysBusDevice parent_obj; - MemoryRegion iomem; - uint32_t block_num_reg; - uint32_t num_blocks_reg; - uint32_t out_addr_reg; - - uint8_t *block_buffer; -} IPodTouchBlockDeviceState; - -#endif \ No newline at end of file diff --git a/include/hw/arm/ipod_touch_fmss.h b/include/hw/arm/ipod_touch_fmss.h index b84647d5364c..252465fb57ca 100644 --- a/include/hw/arm/ipod_touch_fmss.h +++ b/include/hw/arm/ipod_touch_fmss.h @@ -44,6 +44,7 @@ typedef struct IPodTouchFMSSState uint32_t reg_page_spare_out_addr; uint32_t reg_pages_out_addr; uint32_t reg_csgenrc; + char *nand_path; } IPodTouchFMSSState; #endif \ No newline at end of file diff --git a/include/hw/arm/ipod_touch_nor_spi.h b/include/hw/arm/ipod_touch_nor_spi.h index 1f4a87d497a3..d259459d2602 100644 --- a/include/hw/arm/ipod_touch_nor_spi.h +++ b/include/hw/arm/ipod_touch_nor_spi.h @@ -21,6 +21,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchNORSPIState, IPOD_TOUCH_NOR_SPI) typedef struct IPodTouchNORSPIState { SSIPeripheral ssidev; + char *nor_path; uint32_t cur_cmd; uint8_t *in_buf; uint8_t *out_buf; @@ -31,7 +32,6 @@ typedef struct IPodTouchNORSPIState { uint8_t *nor_data; uint8_t write_enabled; uint32_t nor_read_ind; - char nor_path[1024]; bool nor_initialized; } IPodTouchNORSPIState; diff --git a/include/hw/arm/ipod_touch_spi.h b/include/hw/arm/ipod_touch_spi.h index 515fb67b23f0..1e8eee974984 100644 --- a/include/hw/arm/ipod_touch_spi.h +++ b/include/hw/arm/ipod_touch_spi.h @@ -63,6 +63,7 @@ typedef struct IPodTouchSPIState { MemoryRegion iomem; SSIBus *spi; IPodTouchMultitouchState *mt; + IPodTouchNORSPIState *nor; qemu_irq irq; uint32_t last_irq; @@ -70,7 +71,6 @@ typedef struct IPodTouchSPIState { uint32_t regs[MMIO_SIZE >> 2]; uint8_t base; - IPodTouchNORSPIState *nor; Fifo8 rx_fifo; Fifo8 tx_fifo; } IPodTouchSPIState; From 817beeefa8673607b78f8aff1caa39daa2d7cba5 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Wed, 8 Nov 2023 21:18:52 +0100 Subject: [PATCH 45/58] Added run instructions --- RUNNING.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 RUNNING.md diff --git a/RUNNING.md b/RUNNING.md new file mode 100644 index 000000000000..a14a4231bb31 --- /dev/null +++ b/RUNNING.md @@ -0,0 +1,40 @@ +## Running the iPod Touch 2G Emulator + +This file contains the instructions on how to run the iPod Touch 2G emulator using QEMU. +Note that this is an experimental release and the functionality of the device is still limited. + +### Building QEMU + +Compile QEMU by running the following commands from the root directory: + +``` +mkdir build +cd build +../configure --enable-sdl --disable-cocoa --target-list=arm-softmmu --disable-capstone --disable-pie --disable-slirp --extra-cflags=-I/usr/local/opt/openssl@3/include --extra-ldflags='-L/usr/local/opt/openssl@3/lib -lcrypto' +make +``` + +Note that we’re explicitly enabling compilation of the SDL library which is used for interaction with the emulator (e.g., capturing keyboard and mouse events). Also, we only configure and build the ARM emulator. +We are also linking against OpenSSL as the AES/SHA1/PKE engines use some of the library’s cryptographic functions. +Remember to update the include and library paths to the OpenSSL library in case they are located elsewhere. +You can speed up the `make` command by passing the number of available CPU cores with the `-j` flag, e.g., use `make -j6` to compile using six CPU cores. +The compilation process should produce the `qemu-system-arm` binary in the `build/arm-softmmu` directory. + +### Downloading the Required Files + +We need a few files to successfully boot the iPod Touch emulator to the home screen, which I published [here](https://github.com/devos50/qemu-ios/releases/tag/n72ap_v1) for convenience. You can download all these files from here, and they include the following: +- The S5L8720 bootrom binary, which is started as the very first thing when booting. +- A NOR image that contains various auxillary files used by the bootloader. I provide some instructions on how to generate this image yourself [here](https://github.com/devos50/qemu-ios-generate-nor). +- A NAND image that contains the root file system. I provide some instructions on how to generate this image yourself [here](https://github.com/devos50/qemu-ios-generate-nand). + +Download all the required files and save them to a convenient location. You should unzip the `nand_n72ap.zip` file, which contains a single directory named `nand`. + +### Running the Emulator + +We are now ready to run the emulator from the build directory with the following command: + +``` +./arm-softmmu/qemu-system-arm -M iPod-Touch,bootrom=,nand=,nor= -serial mon:stdio -cpu max -m 2G -d unimp +``` + +If there are any issues running the above commands, please let me know by [opening an issue](https://github.com/devos50/qemu-ios/issues/new). From 374d3a330fffbc1850e2037c8ecc601329e99394 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Wed, 8 Nov 2023 21:24:22 +0100 Subject: [PATCH 46/58] Changed README.md --- README.md | 13 ++++ README.rst | 171 ----------------------------------------------------- 2 files changed, 13 insertions(+), 171 deletions(-) create mode 100644 README.md delete mode 100644 README.rst diff --git a/README.md b/README.md new file mode 100644 index 000000000000..fc854eff4767 --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +# QEMU-iOS + +QEMU-iOS is an emulator for legacy Apple devices. +Currently, the iPod Touch 1G and iPod Touch 2G are supported. + +### Running the iPod Touch 1G + +Instructions on how to run the iPod Touch 1G emulator can be found [here](https://devos50.github.io/blog/2022/ipod-touch-qemu-pt2/). +A technical blog post with more information about the peripherals and reverse engineering process is published [here](https://devos50.github.io/blog/2022/ipod-touch-qemu/). + +### Running the iPod Touch 2G + +Instructions on how to run the iPod Touch 2G emulator can be found [here](https://github.com/devos50/qemu-ios/blob/ipod_touch_2g/RUNNING.md). \ No newline at end of file diff --git a/README.rst b/README.rst deleted file mode 100644 index 21df79ef4379..000000000000 --- a/README.rst +++ /dev/null @@ -1,171 +0,0 @@ -=========== -QEMU README -=========== - -QEMU is a generic and open source machine & userspace emulator and -virtualizer. - -QEMU is capable of emulating a complete machine in software without any -need for hardware virtualization support. By using dynamic translation, -it achieves very good performance. QEMU can also integrate with the Xen -and KVM hypervisors to provide emulated hardware while allowing the -hypervisor to manage the CPU. With hypervisor support, QEMU can achieve -near native performance for CPUs. When QEMU emulates CPUs directly it is -capable of running operating systems made for one machine (e.g. an ARMv7 -board) on a different machine (e.g. an x86_64 PC board). - -QEMU is also capable of providing userspace API virtualization for Linux -and BSD kernel interfaces. This allows binaries compiled against one -architecture ABI (e.g. the Linux PPC64 ABI) to be run on a host using a -different architecture ABI (e.g. the Linux x86_64 ABI). This does not -involve any hardware emulation, simply CPU and syscall emulation. - -QEMU aims to fit into a variety of use cases. It can be invoked directly -by users wishing to have full control over its behaviour and settings. -It also aims to facilitate integration into higher level management -layers, by providing a stable command line interface and monitor API. -It is commonly invoked indirectly via the libvirt library when using -open source applications such as oVirt, OpenStack and virt-manager. - -QEMU as a whole is released under the GNU General Public License, -version 2. For full licensing details, consult the LICENSE file. - - -Documentation -============= - -Documentation can be found hosted online at -``_. The documentation for the -current development version that is available at -``_ is generated from the ``docs/`` -folder in the source tree, and is built by `Sphinx -`_. - - -Building -======== - -QEMU is multi-platform software intended to be buildable on all modern -Linux platforms, OS-X, Win32 (via the Mingw64 toolchain) and a variety -of other UNIX targets. The simple steps to build QEMU are: - - -.. code-block:: shell - - mkdir build - cd build - ../configure - make - -Additional information can also be found online via the QEMU website: - -* ``_ -* ``_ -* ``_ - - -Submitting patches -================== - -The QEMU source code is maintained under the GIT version control system. - -.. code-block:: shell - - git clone https://gitlab.com/qemu-project/qemu.git - -When submitting patches, one common approach is to use 'git -format-patch' and/or 'git send-email' to format & send the mail to the -qemu-devel@nongnu.org mailing list. All patches submitted must contain -a 'Signed-off-by' line from the author. Patches should follow the -guidelines set out in the `style section -`_ of -the Developers Guide. - -Additional information on submitting patches can be found online via -the QEMU website - -* ``_ -* ``_ - -The QEMU website is also maintained under source control. - -.. code-block:: shell - - git clone https://gitlab.com/qemu-project/qemu-web.git - -* ``_ - -A 'git-publish' utility was created to make above process less -cumbersome, and is highly recommended for making regular contributions, -or even just for sending consecutive patch series revisions. It also -requires a working 'git send-email' setup, and by default doesn't -automate everything, so you may want to go through the above steps -manually for once. - -For installation instructions, please go to - -* ``_ - -The workflow with 'git-publish' is: - -.. code-block:: shell - - $ git checkout master -b my-feature - $ # work on new commits, add your 'Signed-off-by' lines to each - $ git publish - -Your patch series will be sent and tagged as my-feature-v1 if you need to refer -back to it in the future. - -Sending v2: - -.. code-block:: shell - - $ git checkout my-feature # same topic branch - $ # making changes to the commits (using 'git rebase', for example) - $ git publish - -Your patch series will be sent with 'v2' tag in the subject and the git tip -will be tagged as my-feature-v2. - -Bug reporting -============= - -The QEMU project uses GitLab issues to track bugs. Bugs -found when running code built from QEMU git or upstream released sources -should be reported via: - -* ``_ - -If using QEMU via an operating system vendor pre-built binary package, it -is preferable to report bugs to the vendor's own bug tracker first. If -the bug is also known to affect latest upstream code, it can also be -reported via GitLab. - -For additional information on bug reporting consult: - -* ``_ - - -ChangeLog -========= - -For version history and release notes, please visit -``_ or look at the git history for -more detailed information. - - -Contact -======= - -The QEMU community can be contacted in a number of ways, with the two -main methods being email and IRC - -* ``_ -* ``_ -* #qemu on irc.oftc.net - -Information on additional methods of contacting the community can be -found online via the QEMU website: - -* ``_ From 472781b587321ab311aa9d0b8d7c17d606a90744 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Wed, 8 Nov 2023 21:27:06 +0100 Subject: [PATCH 47/58] Update README.md Added image --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index fc854eff4767..a2c92093ee85 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ QEMU-iOS is an emulator for legacy Apple devices. Currently, the iPod Touch 1G and iPod Touch 2G are supported. +it2g-qemu + ### Running the iPod Touch 1G Instructions on how to run the iPod Touch 1G emulator can be found [here](https://devos50.github.io/blog/2022/ipod-touch-qemu-pt2/). @@ -10,4 +12,4 @@ A technical blog post with more information about the peripherals and reverse en ### Running the iPod Touch 2G -Instructions on how to run the iPod Touch 2G emulator can be found [here](https://github.com/devos50/qemu-ios/blob/ipod_touch_2g/RUNNING.md). \ No newline at end of file +Instructions on how to run the iPod Touch 2G emulator can be found [here](https://github.com/devos50/qemu-ios/blob/ipod_touch_2g/RUNNING.md). From 93121ee2bbd5a8ce9e902d8cefcafdbbc092b701 Mon Sep 17 00:00:00 2001 From: breakgimme <30757793+breakgimme@users.noreply.github.com> Date: Wed, 8 Nov 2023 22:02:17 +0100 Subject: [PATCH 48/58] fix the configure command for apple silicon macs --- RUNNING.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/RUNNING.md b/RUNNING.md index a14a4231bb31..ad32b4ea4b60 100644 --- a/RUNNING.md +++ b/RUNNING.md @@ -10,7 +10,10 @@ Compile QEMU by running the following commands from the root directory: ``` mkdir build cd build +# On Intel Macs ../configure --enable-sdl --disable-cocoa --target-list=arm-softmmu --disable-capstone --disable-pie --disable-slirp --extra-cflags=-I/usr/local/opt/openssl@3/include --extra-ldflags='-L/usr/local/opt/openssl@3/lib -lcrypto' +# On Apple Silicon Macs +../configure --enable-sdl --disable-cocoa --target-list=arm-softmmu --disable-capstone --disable-pie --disable-slirp --extra-cflags=-I/opt/homebrew/opt/openssl@3/include --extra-ldflags='-L/opt/homebrew/opt/openssl@3/lib -lcrypto' make ``` From ce0ce0a64e467e8bda95cba2c8dabc91e9b49ee2 Mon Sep 17 00:00:00 2001 From: Ryan <69303239+spetterman66@users.noreply.github.com> Date: Thu, 23 Nov 2023 14:40:39 +0100 Subject: [PATCH 49/58] Different file paths on Microsoft Windows --- RUNNING.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RUNNING.md b/RUNNING.md index ad32b4ea4b60..91671ccc1d47 100644 --- a/RUNNING.md +++ b/RUNNING.md @@ -14,6 +14,8 @@ cd build ../configure --enable-sdl --disable-cocoa --target-list=arm-softmmu --disable-capstone --disable-pie --disable-slirp --extra-cflags=-I/usr/local/opt/openssl@3/include --extra-ldflags='-L/usr/local/opt/openssl@3/lib -lcrypto' # On Apple Silicon Macs ../configure --enable-sdl --disable-cocoa --target-list=arm-softmmu --disable-capstone --disable-pie --disable-slirp --extra-cflags=-I/opt/homebrew/opt/openssl@3/include --extra-ldflags='-L/opt/homebrew/opt/openssl@3/lib -lcrypto' +# On Microsoft Windows (with MINGW64) +../configure --enable-sdl --disable-cocoa --target-list=arm-softmmu --disable-capstone --disable-slirp --disable-pie --extra-cflags=-I/mingw64/include/openssl --extra-ldflags='-L/mingw64/lib -lcrypto' make ``` From 6c18b04f3c70c9b3749c96e7d01157c7b5ffd5b9 Mon Sep 17 00:00:00 2001 From: Ryan <69303239+spetterman66@users.noreply.github.com> Date: Thu, 23 Nov 2023 14:42:39 +0100 Subject: [PATCH 50/58] Switch position of "extern" and "G_NORETURN" Please read https://www.mail-archive.com/qemu-devel@nongnu.org/msg950158.html, it fixes a bug in compilation on Microsoft Windows. --- include/qemu/osdep.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h index b9c4307779c5..3d6cb431ad99 100644 --- a/include/qemu/osdep.h +++ b/include/qemu/osdep.h @@ -177,7 +177,7 @@ extern "C" { * supports QEMU_ERROR, this will be reported at compile time; otherwise * this will be reported at link time due to the missing symbol. */ -extern G_NORETURN +G_NORETURN extern void QEMU_ERROR("code path is reachable") qemu_build_not_reached_always(void); #if defined(__OPTIMIZE__) && !defined(__NO_INLINE__) From 65a80f936ee92c6fc429fe1697b6409b9952ee85 Mon Sep 17 00:00:00 2001 From: Ryan <69303239+spetterman66@users.noreply.github.com> Date: Thu, 23 Nov 2023 20:11:36 +0100 Subject: [PATCH 51/58] Include disablement of the stack protector in the configure script This commit is intended to address the issue of stack smashing being detected when running QEMU-IOS on Microsoft Windows built with MINGW64, which causes the emulator to be unable to run. --- RUNNING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RUNNING.md b/RUNNING.md index 91671ccc1d47..95c374ed7159 100644 --- a/RUNNING.md +++ b/RUNNING.md @@ -15,7 +15,7 @@ cd build # On Apple Silicon Macs ../configure --enable-sdl --disable-cocoa --target-list=arm-softmmu --disable-capstone --disable-pie --disable-slirp --extra-cflags=-I/opt/homebrew/opt/openssl@3/include --extra-ldflags='-L/opt/homebrew/opt/openssl@3/lib -lcrypto' # On Microsoft Windows (with MINGW64) -../configure --enable-sdl --disable-cocoa --target-list=arm-softmmu --disable-capstone --disable-slirp --disable-pie --extra-cflags=-I/mingw64/include/openssl --extra-ldflags='-L/mingw64/lib -lcrypto' +../configure --enable-sdl --disable-cocoa --target-list=arm-softmmu --disable-capstone --disable-slirp --disable-pie --extra-cflags=-I/mingw64/include/openssl --extra-ldflags='-L/mingw64/lib -lcrypto' --disable-stack-protector make ``` From aaee2c4dbf2a0779777b6e55544573647354acc0 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Tue, 28 Nov 2023 09:04:17 +0100 Subject: [PATCH 52/58] Deleted workflow from IT2G branch --- .github/workflows/lockdown.yml | 30 ------------------------------ 1 file changed, 30 deletions(-) delete mode 100644 .github/workflows/lockdown.yml diff --git a/.github/workflows/lockdown.yml b/.github/workflows/lockdown.yml deleted file mode 100644 index d5e1265cffb3..000000000000 --- a/.github/workflows/lockdown.yml +++ /dev/null @@ -1,30 +0,0 @@ -# Configuration for Repo Lockdown - https://github.com/dessant/repo-lockdown - -name: 'Repo Lockdown' - -on: - pull_request_target: - types: opened - -permissions: - pull-requests: write - -jobs: - action: - runs-on: ubuntu-latest - steps: - - uses: dessant/repo-lockdown@v2 - with: - pr-comment: | - Thank you for your interest in the QEMU project. - - This repository is a read-only mirror of the project's repostories hosted - on https://gitlab.com/qemu-project/qemu.git. - The project does not process merge requests filed on GitHub. - - QEMU welcomes contributions of code (either fixing bugs or adding new - functionality). However, we get a lot of patches, and so we have some - guidelines about contributing on the project website: - https://www.qemu.org/contribute/ - lock-pr: true - close-pr: true From 04eeb538d1b8ac6e97253a53d82f20fe10f2900b Mon Sep 17 00:00:00 2001 From: jvyden Date: Thu, 14 Dec 2023 20:29:27 -0500 Subject: [PATCH 53/58] Check if Bootrom/NOR/NAND files exist before attempting to use --- hw/arm/ipod_touch_2g.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/hw/arm/ipod_touch_2g.c b/hw/arm/ipod_touch_2g.c index bf0476642a19..1c3e997fde6a 100644 --- a/hw/arm/ipod_touch_2g.c +++ b/hw/arm/ipod_touch_2g.c @@ -110,6 +110,12 @@ static char *ipod_touch_get_bootrom_path(Object *obj, Error **errp) static void ipod_touch_set_bootrom_path(Object *obj, const char *value, Error **errp) { + gboolean bootrom_exists = g_file_test(value, G_FILE_TEST_EXISTS); + if(!bootrom_exists) { + error_report("bootrom at path \"%s\" must exist", value); + exit(1); + } + IPodTouchMachineState *nms = IPOD_TOUCH_MACHINE(obj); g_strlcpy(nms->bootrom_path, value, sizeof(nms->bootrom_path)); } @@ -122,6 +128,12 @@ static char *ipod_touch_get_nor_path(Object *obj, Error **errp) static void ipod_touch_set_nor_path(Object *obj, const char *value, Error **errp) { + gboolean nor_exists = g_file_test(value, G_FILE_TEST_EXISTS); + if(!nor_exists) { + error_report("NOR at path \"%s\" must exist", value); + exit(1); + } + IPodTouchMachineState *nms = IPOD_TOUCH_MACHINE(obj); g_strlcpy(nms->nor_path, value, sizeof(nms->nor_path)); } @@ -134,6 +146,12 @@ static char *ipod_touch_get_nand_path(Object *obj, Error **errp) static void ipod_touch_set_nand_path(Object *obj, const char *value, Error **errp) { + gboolean nand_exists = g_file_test(value, G_FILE_TEST_EXISTS & G_FILE_TEST_IS_DIR); + if(!nand_exists) { + error_report("NAND at path \"%s\" must be a directory", value); + exit(1); + } + IPodTouchMachineState *nms = IPOD_TOUCH_MACHINE(obj); g_strlcpy(nms->nand_path, value, sizeof(nms->nand_path)); } From b4aacff740692c8ae358ff998665d45ec7f60517 Mon Sep 17 00:00:00 2001 From: jvyden Date: Thu, 14 Dec 2023 20:45:44 -0500 Subject: [PATCH 54/58] Fix NAND path check --- hw/arm/ipod_touch_2g.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/arm/ipod_touch_2g.c b/hw/arm/ipod_touch_2g.c index 1c3e997fde6a..0d86e9089e2d 100644 --- a/hw/arm/ipod_touch_2g.c +++ b/hw/arm/ipod_touch_2g.c @@ -146,7 +146,7 @@ static char *ipod_touch_get_nand_path(Object *obj, Error **errp) static void ipod_touch_set_nand_path(Object *obj, const char *value, Error **errp) { - gboolean nand_exists = g_file_test(value, G_FILE_TEST_EXISTS & G_FILE_TEST_IS_DIR); + gboolean nand_exists = g_file_test(value, G_FILE_TEST_IS_DIR); if(!nand_exists) { error_report("NAND at path \"%s\" must be a directory", value); exit(1); From 09e689fce103a489490ca03178429b007d679a2d Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Sat, 16 Dec 2023 17:25:20 +0100 Subject: [PATCH 55/58] Update README.md with a schematic --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index a2c92093ee85..fa51cc0b48c3 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,11 @@ Currently, the iPod Touch 1G and iPod Touch 2G are supported. it2g-qemu +The schematic below shows the most important hardware components of the iPod Touch 2G and their interactions. +The schematic for the iPod Touch 1G is mostly similar. + +it2g-schematic + ### Running the iPod Touch 1G Instructions on how to run the iPod Touch 1G emulator can be found [here](https://devos50.github.io/blog/2022/ipod-touch-qemu-pt2/). From be55c408ce3bb0b9ec8b6bbc45456a060e6344c6 Mon Sep 17 00:00:00 2001 From: Martijn de Vos Date: Sun, 24 Dec 2023 10:11:07 +0100 Subject: [PATCH 56/58] Update RUNNING.md --- RUNNING.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/RUNNING.md b/RUNNING.md index 95c374ed7159..a81d7fd9fff7 100644 --- a/RUNNING.md +++ b/RUNNING.md @@ -5,6 +5,13 @@ Note that this is an experimental release and the functionality of the device is ### Building QEMU +Make sure you have the required libraries installed to compile QEMU: + +``` +# On MacOS +brew install glib ninja pixman pkg-config sdl2 +``` + Compile QEMU by running the following commands from the root directory: ``` From 87dafcd4ada56a3e49dce28dd115e3464fd1af11 Mon Sep 17 00:00:00 2001 From: MrDiagnose Date: Sun, 24 Dec 2023 23:02:38 +0530 Subject: [PATCH 57/58] Update RUNNING.md updated build instructions for linux & windows --- RUNNING.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/RUNNING.md b/RUNNING.md index a81d7fd9fff7..826dbb280a7a 100644 --- a/RUNNING.md +++ b/RUNNING.md @@ -10,8 +10,14 @@ Make sure you have the required libraries installed to compile QEMU: ``` # On MacOS brew install glib ninja pixman pkg-config sdl2 -``` +# On Linux (Ubuntu) +sudo apt install make ninja-build pkg-config libssl-dev libsdl2-dev libpixman-1-dev libpixman-1-0 libglib2.0-dev + +# On Windows (MSYS2/mingw64) +pacman -S base-devel mingw-w64-x86_64-toolchain git python ninja mingw-w64-x86_64-glib2 mingw-w64-x86_64-pixman python-setuptools mingw-w64-x86_64-SDL2 + +``` Compile QEMU by running the following commands from the root directory: ``` @@ -19,10 +25,13 @@ mkdir build cd build # On Intel Macs ../configure --enable-sdl --disable-cocoa --target-list=arm-softmmu --disable-capstone --disable-pie --disable-slirp --extra-cflags=-I/usr/local/opt/openssl@3/include --extra-ldflags='-L/usr/local/opt/openssl@3/lib -lcrypto' + # On Apple Silicon Macs ../configure --enable-sdl --disable-cocoa --target-list=arm-softmmu --disable-capstone --disable-pie --disable-slirp --extra-cflags=-I/opt/homebrew/opt/openssl@3/include --extra-ldflags='-L/opt/homebrew/opt/openssl@3/lib -lcrypto' + # On Microsoft Windows (with MINGW64) -../configure --enable-sdl --disable-cocoa --target-list=arm-softmmu --disable-capstone --disable-slirp --disable-pie --extra-cflags=-I/mingw64/include/openssl --extra-ldflags='-L/mingw64/lib -lcrypto' --disable-stack-protector +../configure --enable-sdl --disable-cocoa --target-list=arm-softmmu --disable-capstone --disable-slirp --disable-pie --extra-cflags=-I/mingw64/include/openssl --extra-ldflags='-L/mingw64/lib -lcrypto' --disable-stack-protector --disable-werror + make ``` From 3ed141cd1a199ddf17b3835e577a95f359555c22 Mon Sep 17 00:00:00 2001 From: ant Date: Wed, 27 Dec 2023 12:14:14 +0100 Subject: [PATCH 58/58] TCP TUNNEL compiled and Emulator working fine, Guest side to be tested --- hw/arm/guest-fds.c | 72 +++++++++ hw/arm/guest-file.c | 111 ++++++++++++++ hw/arm/guest-services.c | 178 ++++++++++++++++++++++ hw/arm/guest-socket.c | 192 ++++++++++++++++++++++++ hw/arm/ipod_touch_2g.c | 24 ++- hw/arm/meson.build | 2 +- include/hw/arm/guest-services/fds.h | 67 +++++++++ include/hw/arm/guest-services/file.h | 69 +++++++++ include/hw/arm/guest-services/general.h | 88 +++++++++++ include/hw/arm/guest-services/socket.h | 96 ++++++++++++ include/hw/arm/ipod_touch_2g.h | 6 +- 11 files changed, 901 insertions(+), 4 deletions(-) create mode 100644 hw/arm/guest-fds.c create mode 100644 hw/arm/guest-file.c create mode 100644 hw/arm/guest-services.c create mode 100644 hw/arm/guest-socket.c create mode 100644 include/hw/arm/guest-services/fds.h create mode 100644 include/hw/arm/guest-services/file.h create mode 100644 include/hw/arm/guest-services/general.h create mode 100644 include/hw/arm/guest-services/socket.h diff --git a/hw/arm/guest-fds.c b/hw/arm/guest-fds.c new file mode 100644 index 000000000000..f1094432c211 --- /dev/null +++ b/hw/arm/guest-fds.c @@ -0,0 +1,72 @@ +/* + * QEMU TCP Tunnelling + * + * Copyright (c) 2019 Lev Aronsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without retvaltriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPretvalS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include "hw/arm/guest-services/fds.h" +#include "cpu.h" + +int32_t guest_svcs_fds[MAX_FD_COUNT] = { [0 ... MAX_FD_COUNT-1] = -1 }; + +int32_t qc_handle_close(CPUState *cpu, int32_t fd) +{ + VERIFY_FD(fd); + + int retval = -1; + + if ((retval = close(guest_svcs_fds[fd])) < 0) { + guest_svcs_errno = errno; + } else { + // TODO: should this be in the "else" clause, or performed regardless? + guest_svcs_fds[fd] = -1; + } + + return retval; +} + +int32_t qc_handle_fcntl_getfl(CPUState *cpu, int32_t fd) +{ + VERIFY_FD(fd); + + int retval = -1; + + if ((retval = fcntl(guest_svcs_fds[fd], F_GETFL)) < 0) { + guest_svcs_errno = errno; + } + + return retval; +} + +int32_t qc_handle_fcntl_setfl(CPUState *cpu, int32_t fd, int32_t flags) +{ + VERIFY_FD(fd); + + int retval = -1; + + if ((retval = fcntl(guest_svcs_fds[fd], F_SETFL, flags)) < 0) { + guest_svcs_errno = errno; + } + + return retval; +} diff --git a/hw/arm/guest-file.c b/hw/arm/guest-file.c new file mode 100644 index 000000000000..f9f4709769a5 --- /dev/null +++ b/hw/arm/guest-file.c @@ -0,0 +1,111 @@ +/* + * QEMU Host file guest access + * + * Copyright (c) 2020 Jonathan Afek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "hw/arm/guest-services/file.h" +#include "cpu.h" + +static int32_t file_fds[MAX_FILE_FDS] = { [0 ... MAX_FILE_FDS-1] = -1 }; + +void qc_file_open(uint64_t index, const char *filename) +{ + if (index >= MAX_FILE_FDS) { + abort(); + } + if (-1 != file_fds[index]) { + abort(); + } + file_fds[index] = open(filename, O_RDWR); + if (-1 == file_fds[index]) { + abort(); + } +} + +int64_t qc_handle_write_file(CPUState *cpu, uint64_t buffer_guest_ptr, + uint64_t length, uint64_t offset, uint64_t index) +{ + uint8_t buf[MAX_FILE_TRANSACTION_LEN]; + + if (index >= MAX_FILE_FDS) { + abort(); + } + int fd = file_fds[index]; + if (-1 == fd) { + abort(); + } + if (offset != lseek(fd, offset, SEEK_SET)) { + abort(); + } + if (length > MAX_FILE_TRANSACTION_LEN) { + abort(); + } + cpu_memory_rw_debug(cpu, buffer_guest_ptr, &buf[0], length, 0); + if (length != write(fd, &buf[0], length)) { + abort(); + } + + return 0; +} + +int64_t qc_handle_read_file(CPUState *cpu, uint64_t buffer_guest_ptr, + uint64_t length, uint64_t offset, uint64_t index) +{ + uint8_t buf[MAX_FILE_TRANSACTION_LEN]; + if (index >= MAX_FILE_FDS) { + abort(); + } + int fd = file_fds[index]; + if (-1 == fd) { + abort(); + } + if (offset != lseek(fd, offset, SEEK_SET)) { + abort(); + } + if (length > MAX_FILE_TRANSACTION_LEN) { + abort(); + } + if (length != read(fd, &buf[0], length)) { + abort(); + } + cpu_memory_rw_debug(cpu, buffer_guest_ptr, &buf[0], length, 1); + + return 0; +} + +int64_t qc_handle_size_file(uint64_t index) +{ + struct stat st; + + if (index >= MAX_FILE_FDS) { + abort(); + } + int fd = file_fds[index]; + if (-1 == fd) { + abort(); + } + if (-1 == fstat(fd, &st)) { + abort(); + } + + return st.st_size; +} diff --git a/hw/arm/guest-services.c b/hw/arm/guest-services.c new file mode 100644 index 000000000000..078369e9cc73 --- /dev/null +++ b/hw/arm/guest-services.c @@ -0,0 +1,178 @@ +/* + * QEMU TCP Tunnelling + * + * Copyright (c) 2019 Lev Aronsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/arm/boot.h" +#include "exec/address-spaces.h" +#include "hw/misc/unimp.h" +#include "sysemu/sysemu.h" +#include "qemu/error-report.h" +#include "hw/platform-bus.h" +#include "hw/arm/ipod_touch_2g.h" +#include "cpu.h" + +int32_t guest_svcs_errno = 0; + +uint32_t qemu_call_status(CPUARMState *env) +{ + // NOT USED FOR NOW + return 0; +} + +void qemu_call(CPUARMState *env, uint32_t value) +{ + CPUState *cpu = qemu_get_cpu(0); + qemu_call_t qcall; + uint64_t i = 0; + +/* static uint8_t hooks_installed = false; + + if (!value) { + // Special case: not a regular QEMU call. This is used by our + // kernel task port patch to notify of the readiness for the + // hook installation. + + IPodTouchMachineState *nms = IPOD_TOUCH_MACHINE(qdev_get_machine()); + KernelTrHookParams *hook = &nms->hook; + + if (0 != hook->va) { + //install the hook here because we need the MMU to be already + //configured and all the memory mapped before installing the hook + xnu_hook_tr_copy_install(hook->va, hook->pa, hook->buf_va, + hook->buf_pa, hook->code, hook->code_size, + hook->buf_size, hook->scratch_reg); + + } + + if (!hooks_installed) { + for (i = 0; i < nms->hook_funcs_count; i++) { + xnu_hook_tr_copy_install(nms->hook_funcs[i].va, + nms->hook_funcs[i].pa, + nms->hook_funcs[i].buf_va, + nms->hook_funcs[i].buf_pa, + nms->hook_funcs[i].code, + nms->hook_funcs[i].code_size, + nms->hook_funcs[i].buf_size, + nms->hook_funcs[i].scratch_reg); + } + hooks_installed = true; + } + + //emulate original opcode: str x20, [x23] + value = env->xregs[20]; + cpu_memory_rw_debug(cpu, env->xregs[23], (uint8_t*) &value, + sizeof(value), 1); + + return; + } + */ + // Read the request + cpu_memory_rw_debug(cpu, value, (uint8_t*) &qcall, sizeof(qcall), 0); + + switch (qcall.call_number) { + // File Descriptors + case QC_CLOSE: + qcall.retval = qc_handle_close(cpu, qcall.args.close.fd); + break; + case QC_FCNTL: + switch (qcall.args.fcntl.cmd) { + case F_GETFL: + qcall.retval = qc_handle_fcntl_getfl( + cpu, qcall.args.fcntl.fd); + break; + case F_SETFL: + qcall.retval = qc_handle_fcntl_setfl( + cpu, qcall.args.fcntl.fd, qcall.args.fcntl.flags); + break; + default: + guest_svcs_errno = EINVAL; + qcall.retval = -1; + } + break; + + // Socket API + case QC_SOCKET: + qcall.retval = qc_handle_socket(cpu, qcall.args.socket.domain, + qcall.args.socket.type, + qcall.args.socket.protocol); + break; + case QC_ACCEPT: + qcall.retval = qc_handle_accept(cpu, qcall.args.accept.socket, + qcall.args.accept.addr, + qcall.args.accept.addrlen); + break; + case QC_BIND: + qcall.retval = qc_handle_bind(cpu, qcall.args.bind.socket, + qcall.args.bind.addr, + qcall.args.bind.addrlen); + break; + case QC_CONNECT: + qcall.retval = qc_handle_connect(cpu, qcall.args.connect.socket, + qcall.args.connect.addr, + qcall.args.connect.addrlen); + break; + case QC_LISTEN: + qcall.retval = qc_handle_listen(cpu, qcall.args.listen.socket, + qcall.args.listen.backlog); + break; + case QC_RECV: + qcall.retval = qc_handle_recv(cpu, qcall.args.recv.socket, + qcall.args.recv.buffer, + qcall.args.recv.length, + qcall.args.recv.flags); + break; + case QC_SEND: + qcall.retval = qc_handle_send(cpu, qcall.args.send.socket, + qcall.args.send.buffer, + qcall.args.send.length, + qcall.args.send.flags); + break; + case QC_WRITE_FILE: + qcall.retval = qc_handle_write_file(cpu, + qcall.args.write_file.buffer_guest_ptr, + qcall.args.write_file.length, + qcall.args.write_file.offset, + qcall.args.write_file.index); + break; + case QC_READ_FILE: + qcall.retval = qc_handle_read_file(cpu, + qcall.args.read_file.buffer_guest_ptr, + qcall.args.read_file.length, + qcall.args.read_file.offset, + qcall.args.read_file.index); + break; + case QC_SIZE_FILE: + qcall.retval = qc_handle_size_file(qcall.args.size_file.index); + break; + default: + // TODO: handle unknown call numbers + break; + } + + qcall.error = guest_svcs_errno; + + // Write the response + cpu_memory_rw_debug(cpu, value, (uint8_t*) &qcall, sizeof(qcall), 1); +} diff --git a/hw/arm/guest-socket.c b/hw/arm/guest-socket.c new file mode 100644 index 000000000000..fdf9d1e2df0c --- /dev/null +++ b/hw/arm/guest-socket.c @@ -0,0 +1,192 @@ +/* + * QEMU TCP Tunnelling + * + * Copyright (c) 2019 Lev Aronsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without retvaltriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPretvalS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "hw/arm/guest-services/socket.h" +#include "hw/arm/guest-services/fds.h" +#include "sys/socket.h" +#include "cpu.h" + +#define SOCKET_TIMEOUT_USECS (10) + +static int32_t find_free_socket(void) { + for (int i = 0; i < MAX_FD_COUNT; ++i) { + if (-1 == guest_svcs_fds[i]) { + return i; + } + } + + guest_svcs_errno = ENOMEM; + return -1; +} + +int32_t qc_handle_socket(CPUState *cpu, int32_t domain, int32_t type, + int32_t protocol) +{ + int retval = find_free_socket(); + + if (retval < 0) { + guest_svcs_errno = ENOTSOCK; + } else if ((guest_svcs_fds[retval] = socket(domain, type, protocol)) < 0) { + retval = -1; + guest_svcs_errno = errno; + } + + return retval; +} + +int32_t qc_handle_accept(CPUState *cpu, int32_t sckt, struct sockaddr *g_addr, + socklen_t *g_addrlen) +{ + struct sockaddr_in addr; + socklen_t addrlen; + + VERIFY_FD(sckt); + + int retval = find_free_socket(); + + // TODO: timeout + if (retval < 0) { + guest_svcs_errno = ENOTSOCK; + } else if ((guest_svcs_fds[retval] = accept(guest_svcs_fds[sckt], + (struct sockaddr *) &addr, + &addrlen)) < 0) { + retval = -1; + guest_svcs_errno = errno; + } else { + cpu_memory_rw_debug(cpu, (target_ulong) g_addr, (uint8_t*) &addr, + sizeof(addr), 1); + cpu_memory_rw_debug(cpu, (target_ulong) g_addrlen, + (uint8_t*) &addrlen, sizeof(addrlen), 1); + } + + return retval; +} + +int32_t qc_handle_bind(CPUState *cpu, int32_t sckt, struct sockaddr *g_addr, + socklen_t addrlen) +{ + struct sockaddr_in addr; + + VERIFY_FD(sckt); + + int retval = 0; + + if (addrlen > sizeof(addr)) { + guest_svcs_errno = ENOMEM; + } else { + cpu_memory_rw_debug(cpu, (target_ulong) g_addr, (uint8_t*) &addr, + sizeof(addr), 0); + + if ((retval = bind(guest_svcs_fds[sckt], (struct sockaddr *) &addr, + addrlen)) < 0) { + guest_svcs_errno = errno; + } else { + cpu_memory_rw_debug(cpu, (target_ulong) g_addr, (uint8_t*) &addr, + sizeof(addr), 1); + } + } + + return retval; +} + +int32_t qc_handle_connect(CPUState *cpu, int32_t sckt, struct sockaddr *g_addr, + socklen_t addrlen) +{ + struct sockaddr_in addr; + + VERIFY_FD(sckt); + + int retval = 0; + + if (addrlen > sizeof(addr)) { + guest_svcs_errno = ENOMEM; + } else { + cpu_memory_rw_debug(cpu, (target_ulong) g_addr, (uint8_t*) &addr, + sizeof(addr), 0); + + if ((retval = connect(guest_svcs_fds[sckt], (struct sockaddr *) &addr, + addrlen)) < 0) { + guest_svcs_errno = errno; + } else { + cpu_memory_rw_debug(cpu, (target_ulong) g_addr, (uint8_t*) &addr, + sizeof(addr), 1); + } + } + + return retval; +} + +int32_t qc_handle_listen(CPUState *cpu, int32_t sckt, int32_t backlog) +{ + VERIFY_FD(sckt); + + int retval = 0; + + if ((retval = listen(guest_svcs_fds[sckt], backlog)) < 0) { + guest_svcs_errno = errno; + } + + return retval; +} + +int32_t qc_handle_recv(CPUState *cpu, int32_t sckt, void *g_buffer, + size_t length, int32_t flags) +{ + VERIFY_FD(sckt); + uint8_t buffer[MAX_BUF_SIZE]; + + int retval = -1; + + // TODO: timeout + if (length > MAX_BUF_SIZE) { + guest_svcs_errno = ENOMEM; + } else if ((retval = recv(guest_svcs_fds[sckt], buffer, length, flags)) <= 0) { + guest_svcs_errno = errno; + } else { + cpu_memory_rw_debug(cpu, (target_ulong) g_buffer, buffer, retval, 1); + } + + return retval; +} + +int32_t qc_handle_send(CPUState *cpu, int32_t sckt, void *g_buffer, + size_t length, int32_t flags) +{ + VERIFY_FD(sckt); + uint8_t buffer[MAX_BUF_SIZE]; + + int retval = -1; + + if (length > MAX_BUF_SIZE) { + guest_svcs_errno = ENOMEM; + } else { + cpu_memory_rw_debug(cpu, (target_ulong) g_buffer, buffer, length, 0); + + if ((retval = send(guest_svcs_fds[sckt], buffer, length, flags)) < 0) { + guest_svcs_errno = errno; + } + } + + return retval; +} diff --git a/hw/arm/ipod_touch_2g.c b/hw/arm/ipod_touch_2g.c index 0d86e9089e2d..bc5106ef410d 100644 --- a/hw/arm/ipod_touch_2g.c +++ b/hw/arm/ipod_touch_2g.c @@ -26,6 +26,27 @@ - offsetof(ARMCPU, env) \ } +#define IT2G_CPREG_DEF_QEMU_CALL \ + { \ + .cp = 15, \ + .name = "QEMU_CALL", \ + .opc0 = 0, \ + .opc1 = 3, \ + .crn = 15, \ + .crm = 15, \ + .opc2 = 0, \ + .access = PL0_RW, \ + .resetvalue = 0, \ + .state = ARM_CP_STATE_AA32, \ + .type = ARM_CP_IO, \ + .fieldoffset = offsetof(IPodTouchMachineState, IT2G_CPREG_VAR_NAME(QEMU_CALL)) \ + - offsetof(ARMCPU, env), \ + .readfn = qemu_call_status, \ + .writefn = qemu_call, \ + } + +const int S5L8900_GPIO_IRQS[5] = { S5L8900_GPIO_G0_IRQ, S5L8900_GPIO_G1_IRQ, S5L8900_GPIO_G2_IRQ, S5L8900_GPIO_G3_IRQ, S5L8900_GPIO_G4_IRQ }; + static void allocate_ram(MemoryRegion *top, const char *name, uint32_t addr, uint32_t size) { MemoryRegion *sec = g_new(MemoryRegion, 1); @@ -38,6 +59,7 @@ static const ARMCPRegInfo it2g_cp_reginfo_tcg[] = { IT2G_CPREG_DEF(REG1, 0, 0, 15, 2, 4, PL1_RW, 0), IT2G_CPREG_DEF(REG1, 0, 0, 7, 14, 0, PL1_RW, 0), IT2G_CPREG_DEF(REG1, 0, 0, 7, 10, 0, PL1_RW, 0), + IT2G_CPREG_DEF_QEMU_CALL, }; static void ipod_touch_cpu_setup(MachineState *machine, MemoryRegion **sysmem, ARMCPU **cpu, AddressSpace **nsas) @@ -531,4 +553,4 @@ static void ipod_touch_machine_types(void) type_register_static(&ipod_touch_machine_info); } -type_init(ipod_touch_machine_types) \ No newline at end of file +type_init(ipod_touch_machine_types) diff --git a/hw/arm/meson.build b/hw/arm/meson.build index 5963b71ef260..3ccd7e90f9be 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -62,6 +62,6 @@ arm_ss.add(when: 'CONFIG_FSL_IMX7', if_true: files('fsl-imx7.c', 'mcimx7d-sabre. arm_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c', 'smmuv3.c')) arm_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c')) arm_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c')) -arm_ss.add(when: 'CONFIG_IPOD_TOUCH_2G', if_true: files('ipod_touch_2g.c', 'ipod_touch_clock.c', 'ipod_touch_chipid.c', 'ipod_touch_gpio.c', 'ipod_touch_sysic.c', 'ipod_touch_timer.c', 'ipod_touch_usb_otg.c', 'ipod_touch_usb_phys.c', 'ipod_touch_spi.c', 'ipod_touch_nor_spi.c', 'ipod_touch_sha1.c', 'ipod_touch_aes.c', 'ipod_touch_pke.c', 'ipod_touch_pcf50633_pmu.c', 'ipod_touch_unknown1.c', 'ipod_touch_lcd.c', 'ipod_touch_mipi_dsi.c', 'ipod_touch_fmss.c', 'ipod_touch_mbx.c', 'ipod_touch_cd3272_mikey.c', 'ipod_touch_lis302dl.c', 'ipod_touch_multitouch.c', 'ipod_touch_scaler_csc.c', 'ipod_touch_sdio.c', 'ipod_touch_tvout.c')) +arm_ss.add(when: 'CONFIG_IPOD_TOUCH_2G', if_true: files('ipod_touch_2g.c', 'ipod_touch_clock.c', 'ipod_touch_chipid.c', 'ipod_touch_gpio.c','guest-services.c', 'guest-socket.c', 'guest-fds.c', 'guest-file.c', 'ipod_touch_sysic.c', 'ipod_touch_timer.c', 'ipod_touch_usb_otg.c', 'ipod_touch_usb_phys.c', 'ipod_touch_spi.c', 'ipod_touch_nor_spi.c', 'ipod_touch_sha1.c', 'ipod_touch_aes.c', 'ipod_touch_pke.c', 'ipod_touch_pcf50633_pmu.c', 'ipod_touch_unknown1.c', 'ipod_touch_lcd.c', 'ipod_touch_mipi_dsi.c', 'ipod_touch_fmss.c', 'ipod_touch_mbx.c', 'ipod_touch_cd3272_mikey.c', 'ipod_touch_lis302dl.c', 'ipod_touch_multitouch.c', 'ipod_touch_scaler_csc.c', 'ipod_touch_sdio.c', 'ipod_touch_tvout.c')) hw_arch += {'arm': arm_ss} diff --git a/include/hw/arm/guest-services/fds.h b/include/hw/arm/guest-services/fds.h new file mode 100644 index 000000000000..83a415c34375 --- /dev/null +++ b/include/hw/arm/guest-services/fds.h @@ -0,0 +1,67 @@ +/* + * QEMU TCP Tunnelling + * + * Copyright (c) 2019 Lev Aronsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HW_ARM_GUEST_SERVICES_FDS_H +#define HW_ARM_GUEST_SERVICES_FDS_H + +#ifndef OUT_OF_TREE_BUILD +#include "qemu/osdep.h" +#else +#include "sys/types.h" +#include "sys/socket.h" +#endif + +#define MAX_FD_COUNT (256) + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wredundant-decls" +extern int32_t guest_svcs_errno; +#pragma GCC diagnostic pop +extern int32_t guest_svcs_fds[MAX_FD_COUNT]; + +#define VERIFY_FD(s) \ + if ((s < 0) || (s >= MAX_FD_COUNT) || (-1 == guest_svcs_fds[s])) return -1; + +typedef struct __attribute__((packed)) { + int32_t fd; +} qc_close_args_t; + +typedef struct __attribute__((packed)) { + int32_t fd; + int32_t cmd; + union { + int32_t flags; + }; +} qc_fcntl_args_t; + +#ifndef OUT_OF_TREE_BUILD +int32_t qc_handle_close(CPUState *cpu, int32_t fd); +int32_t qc_handle_fcntl_getfl(CPUState *cpu, int32_t fd); +int32_t qc_handle_fcntl_setfl(CPUState *cpu, int32_t fd, int32_t flags); +#else +int qc_close(int fd); +int qc_fcntl(int fd, int cmd, ...); +#endif + +#endif // HW_ARM_GUEST_SERVICES_FDS_H diff --git a/include/hw/arm/guest-services/file.h b/include/hw/arm/guest-services/file.h new file mode 100644 index 000000000000..bd885913d5c0 --- /dev/null +++ b/include/hw/arm/guest-services/file.h @@ -0,0 +1,69 @@ +/* + * QEMU Host file guest access + * + * Copyright (c) 2020 Jonathan Afek + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HW_ARM_GUEST_SERVICES_FILE_H +#define HW_ARM_GUEST_SERVICES_FILE_H + +#ifndef OUT_OF_TREE_BUILD +#include "qemu/osdep.h" +#else +#include "sys/types.h" +#endif + +#define MAX_FILE_FDS (8) +#define MAX_FILE_TRANSACTION_LEN (0x2000) + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wredundant-decls" +extern int32_t guest_svcs_errno; +#pragma GCC diagnostic pop + +typedef struct __attribute__((packed)) { + uint64_t buffer_guest_ptr; + uint64_t length; + uint64_t offset; + uint64_t index; +} qc_write_file_args_t, qc_read_file_args_t; + +typedef struct __attribute__((packed)) { + uint64_t index; +} qc_size_file_args_t; + +#ifndef OUT_OF_TREE_BUILD +void qc_file_open(uint64_t index, const char *filename); + +int64_t qc_handle_write_file(CPUState *cpu, uint64_t buffer_guest_ptr, + uint64_t length, uint64_t offset, uint64_t index); +int64_t qc_handle_read_file(CPUState *cpu, uint64_t buffer_guest_ptr, + uint64_t length, uint64_t offset, uint64_t index); +int64_t qc_handle_size_file(uint64_t index); +#else +int64_t qc_write_file(void *buffer_guest_ptr, uint64_t length, + uint64_t offset, uint64_t index); +int64_t qc_read_file(void *buffer_guest_ptr, uint64_t length, + uint64_t offset, uint64_t index); +int64_t qc_size_file(uint64_t index); +#endif + +#endif diff --git a/include/hw/arm/guest-services/general.h b/include/hw/arm/guest-services/general.h new file mode 100644 index 000000000000..34c6229dab14 --- /dev/null +++ b/include/hw/arm/guest-services/general.h @@ -0,0 +1,88 @@ +/* + * QEMU TCP Tunnelling + * + * Copyright (c) 2019 Lev Aronsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HW_ARM_GUEST_SERVICES_GENERAL_H +#define HW_ARM_GUEST_SERVICES_GENERAL_H + +#include "hw/arm/guest-services/socket.h" +#include "hw/arm/guest-services/fds.h" +#include "hw/arm/guest-services/file.h" + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wredundant-decls" +extern int32_t guest_svcs_errno; +#pragma GCC diagnostic pop + +typedef enum { + // File Descriptors API + QC_CLOSE = 0x100, + QC_FCNTL, + + // Socket API + QC_SOCKET = 0x110, + QC_ACCEPT, + QC_BIND, + QC_CONNECT, + QC_LISTEN, + QC_RECV, + QC_SEND, + QC_WRITE_FILE, + QC_READ_FILE, + QC_SIZE_FILE, +} qemu_call_number_t; + +typedef struct __attribute__((packed)) { + // Request + qemu_call_number_t call_number; + union { + // File Descriptors API + qc_close_args_t close; + qc_fcntl_args_t fcntl; + // Socket API + qc_socket_args_t socket; + qc_accept_args_t accept; + qc_bind_args_t bind; + qc_connect_args_t connect; + qc_listen_args_t listen; + qc_recv_args_t recv; + qc_send_args_t send; + qc_write_file_args_t write_file; + qc_read_file_args_t read_file; + qc_size_file_args_t size_file; + } args; + + // Response + int64_t retval; + int64_t error; +} qemu_call_t; + +#ifndef OUT_OF_TREE_BUILD +uint32_t qemu_call_status(CPUARMState *env); +void qemu_call(CPUARMState *env, uint32_t value); +#else +uint32_t qemu_call_status(qemu_call_t *qcall); +void qemu_call(qemu_call_t *qcall); +#endif + +#endif // HW_ARM_GUEST_SERVICES_GENERAL_H diff --git a/include/hw/arm/guest-services/socket.h b/include/hw/arm/guest-services/socket.h new file mode 100644 index 000000000000..ff98bd8b668e --- /dev/null +++ b/include/hw/arm/guest-services/socket.h @@ -0,0 +1,96 @@ +/* + * QEMU TCP Tunnelling + * + * Copyright (c) 2019 Lev Aronsky + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef HW_ARM_GUEST_SERVICES_SOCKET_H +#define HW_ARM_GUEST_SERVICES_SOCKET_H + +#ifndef OUT_OF_TREE_BUILD +#include "qemu/osdep.h" +#else +#include "sys/types.h" +#include "sys/socket.h" +#endif + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wredundant-decls" +extern int32_t guest_svcs_errno; +#pragma GCC diagnostic pop + +#define MAX_BUF_SIZE (4096) + +typedef struct __attribute__((packed)) { + int32_t domain; + int32_t type; + int32_t protocol; +} qc_socket_args_t; + +typedef struct __attribute__((packed)) { + int32_t socket; + struct sockaddr *addr; + socklen_t *addrlen; +} qc_accept_args_t; + +typedef struct __attribute__((packed)) { + int32_t socket; + struct sockaddr *addr; + socklen_t addrlen; +} qc_bind_args_t, qc_connect_args_t; + +typedef struct __attribute__((packed)) { + int32_t socket; + int32_t backlog; +} qc_listen_args_t; + +typedef struct __attribute__((packed)) { + int32_t socket; + void *buffer; + size_t length; + int flags; +} qc_recv_args_t, qc_send_args_t; + +#ifndef OUT_OF_TREE_BUILD +int32_t qc_handle_socket(CPUState *cpu, int32_t domain, int32_t type, + int32_t protocol); +int32_t qc_handle_accept(CPUState *cpu, int32_t sckt, struct sockaddr *addr, + socklen_t *addrlen); +int32_t qc_handle_bind(CPUState *cpu, int32_t sckt, struct sockaddr *addr, + socklen_t addrlen); +int32_t qc_handle_connect(CPUState *cpu, int32_t sckt, struct sockaddr *addr, + socklen_t addrlen); +int32_t qc_handle_listen(CPUState *cpu, int32_t sckt, int32_t backlog); +int32_t qc_handle_recv(CPUState *cpu, int32_t sckt, void *buffer, + size_t length, int32_t flags); +int32_t qc_handle_send(CPUState *cpu, int32_t sckt, void *buffer, + size_t length, int32_t flags); +#else +int qc_socket(int domain, int type, int protocol); +int qc_accept(int sckt, struct sockaddr *addr, socklen_t *addrlen); +int qc_bind(int sckt, const struct sockaddr *addr, socklen_t addrlen); +int qc_connect(int sckt, const struct sockaddr *addr, socklen_t addrlen); +int qc_listen(int sckt, int backlog); +ssize_t qc_recv(int sckt, void *buffer, size_t length, int flags); +ssize_t qc_send(int sckt, const void *buffer, size_t length, int flags); +#endif + +#endif // HW_ARM_GUEST_SERVICES_SOCKET_H diff --git a/include/hw/arm/ipod_touch_2g.h b/include/hw/arm/ipod_touch_2g.h index 8f1d87f51776..c506b8ae2236 100644 --- a/include/hw/arm/ipod_touch_2g.h +++ b/include/hw/arm/ipod_touch_2g.h @@ -28,6 +28,7 @@ #include "hw/arm/ipod_touch_scaler_csc.h" #include "hw/arm/ipod_touch_sdio.h" #include "hw/arm/ipod_touch_tvout.h" +#include "hw/arm/guest-services/general.h" #define TYPE_IPOD_TOUCH "iPod-Touch" @@ -57,7 +58,7 @@ #define S5L8900_GPIO_G3_IRQ 0x03 #define S5L8900_GPIO_G4_IRQ 0x02 -const int S5L8900_GPIO_IRQS[5] = { S5L8900_GPIO_G0_IRQ, S5L8900_GPIO_G1_IRQ, S5L8900_GPIO_G2_IRQ, S5L8900_GPIO_G3_IRQ, S5L8900_GPIO_G4_IRQ }; +extern const int S5L8900_GPIO_IRQS[5]; #define IT2G_CPREG_VAR_NAME(name) cpreg_##name #define IT2G_CPREG_VAR_DEF(name) uint64_t IT2G_CPREG_VAR_NAME(name) @@ -155,6 +156,7 @@ typedef struct { char nand_path[1024]; IT2G_CPREG_VAR_DEF(REG0); IT2G_CPREG_VAR_DEF(REG1); + IT2G_CPREG_VAR_DEF(QEMU_CALL); } IPodTouchMachineState; -#endif \ No newline at end of file +#endif