From 62286216c89af1c41ae92cc15f408a5cec9fe168 Mon Sep 17 00:00:00 2001 From: Tucker Osman Date: Wed, 11 Jan 2023 23:23:48 -0600 Subject: [PATCH] SPI might work? EFI header loads! It appears the EFI IMG header is loading correctly. The next step is to stub out the validation code to blindly load and run a decrypted EFI. Which I have to supply and document how to build. I think I should figure out why I need to do a three-file layer in my Unicorn emulator... not sure what's going on with that. Simply replacing the EFI contents with the decrypted version should be sufficient. No idea. --- .gdbinit | 2 +- TuckerNotes.md | 2 +- hw/arm/ipod_touch.c | 37 ++++++--- hw/arm/ipod_touch_nor_spi.c | 113 ++++++++++++++++++++++++++++ hw/arm/ipod_touch_spi.c | 85 ++++++++++++--------- hw/arm/meson.build | 2 +- include/hw/arm/ipod_touch.h | 2 +- include/hw/arm/ipod_touch_nor_spi.h | 32 ++++++++ include/hw/arm/ipod_touch_spi.h | 3 +- 9 files changed, 225 insertions(+), 53 deletions(-) create mode 100644 hw/arm/ipod_touch_nor_spi.c create mode 100644 include/hw/arm/ipod_touch_nor_spi.h diff --git a/.gdbinit b/.gdbinit index b837a6d3b97c..8a578b0ef273 100644 --- a/.gdbinit +++ b/.gdbinit @@ -15,5 +15,5 @@ layout vmdebug focus cmd set confirm off -break *0x20003010 +break *0x20002fe4 continue diff --git a/TuckerNotes.md b/TuckerNotes.md index ce5be4fea6f5..79130143d0ce 100644 --- a/TuckerNotes.md +++ b/TuckerNotes.md @@ -1,6 +1,6 @@ Run it with: ``` -./arm-softmmu/qemu-system-arm -M iPod-Touch,bootrom=/home/tucker/Development/qemu-ipod-nano/build/s5l8702-bootrom.bin,iboot=/home/tucker/Development/qemu-ipod-nano/build/iboot_204_n45ap.bin,nand=/home/tucker/Development/qemu-ipod-nano/build/nand -serial mon:stdio -cpu max -m 1G -d unimp -pflash /home/tucker/Development/qemu-ipod-nano/build/nor_n45ap.bin +./arm-softmmu/qemu-system-arm -M iPod-Touch,bootrom=/home/tucker/Development/qemu-ipod-nano/build/s5l8702-bootrom.bin,iboot=/home/tucker/Development/qemu-ipod-nano/build/iboot_204_n45ap.bin,nand=/home/tucker/Development/qemu-ipod-nano/build/nand -serial mon:stdio -cpu max -m 1G -d unimp -pflash /home/tucker/Development/qemu-ipod-nano/build/nor_image.bin ``` Run the iPhone code with: diff --git a/hw/arm/ipod_touch.c b/hw/arm/ipod_touch.c index 54557514d4e8..2e18b4f22d98 100644 --- a/hw/arm/ipod_touch.c +++ b/hw/arm/ipod_touch.c @@ -228,16 +228,16 @@ static void ipod_touch_memory_setup(MachineState *machine, MemoryRegion *sysmem, allocate_ram(sysmem, "framebuffer", FRAMEBUFFER_MEM_BASE, align_64k_high(4 * 320 * 480)); // setup 1MB NOR - nms->nor_drive = drive_get(IF_PFLASH, 0, 0); - if (!nms->nor_drive) { - printf("A NOR image must be given with the -pflash parameter\n"); - abort(); - } - - if(!pflash_cfi02_register(NOR_MEM_BASE, "nor", 1024 * 1024, nms->nor_drive ? blk_by_legacy_dinfo(nms->nor_drive) : NULL, 4096, 1, 2, 0x00bf, 0x273f, 0x0, 0x0, 0x555, 0x2aa, 0)) { - printf("Error registering NOR flash!\n"); - abort(); - } + // nms->nor_drive = drive_get(IF_PFLASH, 0, 0); + // if (!nms->nor_drive) { + // printf("A NOR image must be given with the -pflash parameter\n"); + // abort(); + // } + + // if(!pflash_cfi02_register(NOR_MEM_BASE, "nor", 1024 * 1024, nms->nor_drive ? blk_by_legacy_dinfo(nms->nor_drive) : NULL, 4096, 1, 2, 0x00bf, 0x273f, 0x0, 0x0, 0x555, 0x2aa, 0)) { + // printf("Error registering NOR flash!\n"); + // abort(); + // } } static char *ipod_touch_get_bootrom_path(Object *obj, Error **errp) @@ -276,6 +276,18 @@ static void ipod_touch_set_nand_path(Object *obj, const char *value, Error **err g_strlcpy(nms->nand_path, value, sizeof(nms->nand_path)); } +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, "bootrom", ipod_touch_get_bootrom_path, ipod_touch_set_bootrom_path); @@ -286,6 +298,9 @@ static void ipod_touch_instance_init(Object *obj) 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"); + + 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 iPod Nano 3G NOR image"); } static inline qemu_irq s5l8900_get_irq(IPodTouchMachineState *s, int n) @@ -460,7 +475,7 @@ static void ipod_touch_machine_init(MachineState *machine) set_spi_base(0); dev = sysbus_create_simple("s5l8900spi", SPI0_MEM_BASE, s5l8900_get_irq(nms, S5L8900_SPI0_IRQ)); S5L8900SPIState *spi0_state = S5L8900SPI(dev); - spi0_state->nor_drive = nms->nor_drive; + strcpy(spi0_state->nor->nor_path, nms->nor_path); set_spi_base(1); sysbus_create_simple("s5l8900spi", SPI1_MEM_BASE, s5l8900_get_irq(nms, S5L8900_SPI1_IRQ)); diff --git a/hw/arm/ipod_touch_nor_spi.c b/hw/arm/ipod_touch_nor_spi.c new file mode 100644 index 000000000000..f3d7bb995eac --- /dev/null +++ b/hw/arm/ipod_touch_nor_spi.c @@ -0,0 +1,113 @@ +#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("/home/tucker/Development/qemu-ipod-nano/build/nor_image.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 == 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 if(value == NOR_RESET_CMD) { + s->in_buf_size = 1; + s->out_buf_size = 1; + } 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 == 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_RESET_CMD && s->in_buf_cur_ind == s->in_buf_size) { + s->out_buf[0] = 0x0; // indicates that the NOR is reset + } 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 { + 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; + } +} + +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) +{ + 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 2ed4e48e8d1c..3204483c7eb5 100644 --- a/hw/arm/ipod_touch_spi.c +++ b/hw/arm/ipod_touch_spi.c @@ -88,13 +88,20 @@ static void apple_spi_run(S5L8900SPIState *s) fprintf(stderr, "apple_spi_run\n"); if (!(REG(s, R_CTRL) & R_CTRL_RUN)) { - fprintf(stderr, "apple_spi_run: not running\n"); - // return; + fprintf(stderr, "apple_spi_run: not running: R_CTRL\n"); + return; } + if (REG(s, R_RXCNT) == 0 && REG(s, R_TXCNT) == 0) { + fprintf(stderr, "apple_spi_run: not running: R_RXCNT\n"); + return; + } + + apple_spi_update_xfer_tx(s); while (!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)) { @@ -121,49 +128,48 @@ static void apple_spi_run(S5L8900SPIState *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 s5l8900_spi_read(void *opaque, hwaddr addr, unsigned size) { S5L8900SPIState *s = S5L8900SPI(opaque); - fprintf(stderr, "%s (base %d): read from location 0x%08x\n", __func__, s->base, addr); + // 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; + 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; } - buf = fifo8_pop_buf(&s->rx_fifo, word_size, &num); - memcpy(&r, buf, num); - if (fifo8_is_empty(&s->rx_fifo)) { - run = true; + 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; + r = 0x3e00; + break; } - 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; + default: + break; } if (run) { @@ -176,7 +182,7 @@ static uint64_t s5l8900_spi_read(void *opaque, hwaddr addr, unsigned size) static void s5l8900_spi_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) { S5L8900SPIState *s = S5L8900SPI(opaque); - fprintf(stderr, "%s (base %d): writing 0x%08x to 0x%08x\n", __func__, s->base, data, addr); + // 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); @@ -198,21 +204,20 @@ static void s5l8900_spi_write(void *opaque, hwaddr addr, uint64_t data, unsigned 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)); + if ((fifo8_is_full(&s->tx_fifo)) || (fifo8_num_free(&s->tx_fifo) < word_size)) { 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); + if(REG(s, R_CTRL) & R_CTRL_RUN) run = true; + REG(s, R_STATUS) = 0x3e00; break; case R_CFG: run = true; @@ -229,6 +234,12 @@ static void s5l8900_spi_write(void *opaque, hwaddr addr, uint64_t data, unsigned 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); } @@ -277,9 +288,9 @@ static void s5l8900_spi_realize(DeviceState *dev, struct Error **errp) // create the peripheral switch(s->base) { case 0: - BlockBackend* blk = s->nor_drive ? blk_by_legacy_dinfo(s->nor_drive) : NULL; - qdev_prop_set_drive_err(s->spi, "drive", blk, NULL); - dev = ssi_create_peripheral(s->spi, "sst25vf080b"); + 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_LCD_PANEL); diff --git a/hw/arm/meson.build b/hw/arm/meson.build index b03bd7d42a6a..3a0531b0ba59 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -58,6 +58,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', if_true: files('ipod_touch.c', 'ipod_touch_spi.c', 'ipod_touch_sysic.c', 'ipod_touch_aes.c', 'ipod_touch_sha1.c', 'ipod_touch_usb_otg.c', 'ipod_touch_8900_engine.c', 'ipod_touch_nand.c', 'ipod_touch_nand_ecc.c', 'ipod_touch_pcf50633_pmu.c', 'ipod_touch_adm.c', 'ipod_touch_chipid.c', 'ipod_touch_tvout.c', 'ipod_touch_lcd_panel.c', 'ipod_touch_multitouch.c', 'ipod_touch_lcd.c', 'ipod_touch_lis302dl.c', 'ipod_touch_aes.c', 'ipod_touch_sha1.c', 'ipod_touch_timer.c', 'ipod_touch_clock.c', 'ipod_touch_gpio.c', 'ipod_touch_sdio.c')) +arm_ss.add(when: 'CONFIG_IPOD_TOUCH', if_true: files('ipod_touch.c', 'ipod_touch_spi.c', 'ipod_touch_sysic.c', 'ipod_touch_aes.c', 'ipod_touch_sha1.c', 'ipod_touch_usb_otg.c', 'ipod_touch_8900_engine.c', 'ipod_touch_nand.c', 'ipod_touch_nand_ecc.c', 'ipod_touch_pcf50633_pmu.c', 'ipod_touch_adm.c', 'ipod_touch_chipid.c', 'ipod_touch_tvout.c', 'ipod_touch_lcd_panel.c', 'ipod_touch_multitouch.c', 'ipod_touch_lcd.c', 'ipod_touch_lis302dl.c', 'ipod_touch_aes.c', 'ipod_touch_sha1.c', 'ipod_touch_timer.c', 'ipod_touch_clock.c', 'ipod_touch_gpio.c', 'ipod_touch_sdio.c', 'ipod_touch_nor_spi.c')) hw_arch += {'arm': arm_ss} diff --git a/include/hw/arm/ipod_touch.h b/include/hw/arm/ipod_touch.h index cbded7d67632..98ce0e4e4150 100644 --- a/include/hw/arm/ipod_touch.h +++ b/include/hw/arm/ipod_touch.h @@ -170,7 +170,7 @@ typedef struct { char bootrom_path[1024]; char iboot_path[1024]; char nand_path[1024]; - DriveInfo* nor_drive; + char nor_path[1024]; } 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 new file mode 100644 index 000000000000..f612aef531a0 --- /dev/null +++ b/include/hw/arm/ipod_touch_nor_spi.h @@ -0,0 +1,32 @@ +#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" +#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 +#define NOR_RESET_CMD 0xFF + +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_spi.h b/include/hw/arm/ipod_touch_spi.h index 0d197563833a..13c8f4586734 100644 --- a/include/hw/arm/ipod_touch_spi.h +++ b/include/hw/arm/ipod_touch_spi.h @@ -11,6 +11,7 @@ #include "hw/ssi/ssi.h" #include "hw/arm/ipod_touch_lcd_panel.h" #include "hw/arm/ipod_touch_multitouch.h" +#include "hw/arm/ipod_touch_nor_spi.h" #define TYPE_S5L8900SPI "s5l8900spi" OBJECT_DECLARE_SIMPLE_TYPE(S5L8900SPIState, S5L8900SPI) @@ -80,7 +81,7 @@ typedef struct S5L8900SPIState { uint32_t mmio_size; uint8_t base; - DriveInfo *nor_drive; + IPodTouchNORSPIState *nor; } S5L8900SPIState; void set_spi_base(uint32_t base);