From 533b33548f4ee1c1b74b9bd531d50999c858cc05 Mon Sep 17 00:00:00 2001 From: Tucker Osman Date: Sun, 15 Jan 2023 02:39:23 -0600 Subject: [PATCH] bodged SPI peripheral. makes it to LCD init now. I have no idea how this SPI peripheral works. but now I'm getting a memory exception on the registers that should drive the LCD, so that's pretty awesome. now it's at feature parity with my bespoke emulator, except for the part where the SPI peripheral has more of a chance to work in more conditions because there's no paravirtualization going on here... it just does what it does. --- .gdbinit | 21 ++++++++++++++-- hw/arm/ipod_touch_chipid.c | 2 +- hw/arm/ipod_touch_nor_spi.c | 38 ++++++++++++++++++++--------- hw/arm/ipod_touch_spi.c | 27 +++++++++++++++----- hw/arm/ipod_touch_timer.c | 4 +-- include/hw/arm/ipod_touch.h | 2 +- include/hw/arm/ipod_touch_chipid.h | 2 +- include/hw/arm/ipod_touch_nor_spi.h | 2 ++ 8 files changed, 73 insertions(+), 25 deletions(-) diff --git a/.gdbinit b/.gdbinit index 8242949ed66e..7c6a07e65bf9 100644 --- a/.gdbinit +++ b/.gdbinit @@ -15,6 +15,23 @@ layout vmdebug focus cmd set confirm off -# first instruction of a module! maps to 40080242 efi_DxeMain_entrypoint in Ghidra -break *0x9fbf242 +define sf + break *($pc + 6) + continue +end + +define dump + x/32bx $pc +end + +# break on a CPU exception +break *0x10 +break *0x9f022c0 + +# first instruction of a module! maps to 40080242 efi_DxeMain_entrypoint in Ghidra, offset of 0x360C1000 +# break *0x9fbf242 + +# testing where the ARM exception is... +# break *0x09ef12fa +break *0x9ef5362 continue diff --git a/hw/arm/ipod_touch_chipid.c b/hw/arm/ipod_touch_chipid.c index a62a7323e754..4159b6047f09 100644 --- a/hw/arm/ipod_touch_chipid.c +++ b/hw/arm/ipod_touch_chipid.c @@ -5,7 +5,7 @@ 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 0x4: + case 0x0: return (CHIP_REVISION << 24); default: break; diff --git a/hw/arm/ipod_touch_nor_spi.c b/hw/arm/ipod_touch_nor_spi.c index e92f4908223f..ec27d3ad51f7 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); + if(value != 0xFF) 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. @@ -30,17 +30,31 @@ static uint32_t ipod_touch_nor_spi_transfer(SSIPeripheral *dev, uint32_t value) 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); + switch(value) { + case 0x00: + break; + case NOR_GET_STATUS_CMD: + s->in_buf_size = 1; + s->out_buf_size = 1; + break; + case NOR_READ_DATA_CMD: + s->in_buf_size = 4; + s->out_buf_size = 4096; + break; + case NOR_RESET_CMD: + s->in_buf_size = 1; + s->out_buf_size = 1; + break; + case NOR_ENABLE_STATUS_WRITE_CMD: + s->in_buf_size = 1; + s->out_buf_size = 1; + break; + case NOR_WRITE_STATUS_CMD: + s->in_buf_size = 3; + s->out_buf_size = 1; + break; + default: + hw_error("Unknown command 0x%02x!", value); } return 0x0; diff --git a/hw/arm/ipod_touch_spi.c b/hw/arm/ipod_touch_spi.c index 531f8ad30d6f..f7d2fe0ae8c3 100644 --- a/hw/arm/ipod_touch_spi.c +++ b/hw/arm/ipod_touch_spi.c @@ -91,10 +91,6 @@ static void apple_spi_run(S5L8900SPIState *s) // 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); @@ -136,13 +132,18 @@ static void apple_spi_run(S5L8900SPIState *s) 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); uint32_t r; bool run = false; r = s->regs[addr >> 2]; switch (addr) { + case R_CTRL: { + if(REG(s, R_CTRL) == 0) { + r = 0x00000002; + } + break; + } case R_RXDATA: { const uint8_t *buf = NULL; int word_size = apple_spi_word_size(s); @@ -165,13 +166,22 @@ static uint64_t s5l8900_spi_read(void *opaque, hwaddr addr, unsigned size) val |= (fifo8_num_used(&s->tx_fifo) << R_STATUS_TXFIFO_SHIFT); val |= (fifo8_num_used(&s->rx_fifo) << R_STATUS_RXFIFO_SHIFT); r |= val; + // fprintf(stderr, "val is %d, r is %d, R_CTRL is %d, R_STATUS is %d, R_RXCNT is %d, R_TXCNT is %d, R_CFG is %d, R_PIN is %d, R_TXDATA is %d, R_RXDATA is %d\n", val, r, REG(s, R_CTRL), REG(s, R_STATUS), REG(s, R_RXCNT), REG(s, R_TXCNT), REG(s, R_CFG), REG(s, R_PIN), REG(s, R_TXDATA), REG(s, R_RXDATA)); r = 0x3e00; + if(REG(s, R_CTRL) & 0xC) { + if(REG(s, R_TXDATA) == 0xFF && val > 0) r = 0xFF0; // the nor was probably just reset + else if(REG(s, R_TXDATA) == 0xFF && r != REG(s, R_STATUS)) r = 0x0; + else if(REG(s, R_TXDATA) == 0xFF && val == 0 && REG(s, R_RXCNT) == 0) r = 0xF0; + else r = 0; + } break; } default: break; } + // fprintf(stderr, "%s (base %d): read from location 0x%08x -> 0x%08X\n", __func__, s->base, addr, r); + if (run) { apple_spi_run(s); } @@ -201,6 +211,12 @@ static void s5l8900_spi_write(void *opaque, hwaddr addr, uint64_t data, unsigned if (r & R_CTRL_RUN && !fifo8_is_empty(&s->tx_fifo)) { run = true; } + if(r & 0xC) { + REG(s, R_STATUS) |= 0xF0; + } + if (r == 0) { + REG(s, R_CTRL) = 2; + } break; case R_STATUS: r = old & (~r); @@ -217,7 +233,6 @@ static void s5l8900_spi_write(void *opaque, hwaddr addr, uint64_t data, unsigned } 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; diff --git a/hw/arm/ipod_touch_timer.c b/hw/arm/ipod_touch_timer.c index 026a5551aadf..98490d1a455a 100644 --- a/hw/arm/ipod_touch_timer.c +++ b/hw/arm/ipod_touch_timer.c @@ -77,7 +77,7 @@ static void s5l8900_timer1_write(void *opaque, hwaddr addr, uint64_t value, unsi static uint64_t s5l8900_timer1_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); IPodTouchTimerState *s = (struct IPodTouchTimerState *) opaque; uint64_t elapsed_ns, ticks; @@ -86,7 +86,7 @@ static uint64_t s5l8900_timer1_read(void *opaque, hwaddr addr, unsigned size) 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); + // printf("TICKS: %lld\n", ticks); s->ticks_high = (ticks >> 32); s->ticks_low = (ticks & 0xFFFFFFFF); return s->ticks_low; diff --git a/include/hw/arm/ipod_touch.h b/include/hw/arm/ipod_touch.h index 8d7cc624a04c..b5fd3af944b6 100644 --- a/include/hw/arm/ipod_touch.h +++ b/include/hw/arm/ipod_touch.h @@ -95,7 +95,7 @@ const int S5L8900_GPIO_IRQS[7] = { S5L8900_GPIO_G0_IRQ, S5L8900_GPIO_G1_IRQ, S5L #define SPI2_MEM_BASE 0x3D200000 #define WATCHDOG_MEM_BASE 0x3C800000 #define DISPLAY_MEM_BASE 0x38900000 -#define CHIPID_MEM_BASE 0x3e500000 +#define CHIPID_MEM_BASE 0x3D100000 #define RAM_MEM_BASE 0x8000000 #define SHA1_MEM_BASE 0x38000000 #define AES_MEM_BASE 0x38C00000 diff --git a/include/hw/arm/ipod_touch_chipid.h b/include/hw/arm/ipod_touch_chipid.h index 4159bad1fce6..bbf9d795bb45 100644 --- a/include/hw/arm/ipod_touch_chipid.h +++ b/include/hw/arm/ipod_touch_chipid.h @@ -8,7 +8,7 @@ #define TYPE_IPOD_TOUCH_CHIPID "ipodtouch.chipid" OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchChipIDState, IPOD_TOUCH_CHIPID) -#define CHIP_REVISION 0x2 +#define CHIP_REVISION 0x0 typedef struct IPodTouchChipIDState { SysBusDevice busdev; diff --git a/include/hw/arm/ipod_touch_nor_spi.h b/include/hw/arm/ipod_touch_nor_spi.h index f612aef531a0..2c41645d9b11 100644 --- a/include/hw/arm/ipod_touch_nor_spi.h +++ b/include/hw/arm/ipod_touch_nor_spi.h @@ -12,6 +12,8 @@ OBJECT_DECLARE_SIMPLE_TYPE(IPodTouchNORSPIState, IPOD_TOUCH_NOR_SPI) #define NOR_READ_DATA_CMD 0x3 #define NOR_GET_STATUS_CMD 0x5 +#define NOR_ENABLE_STATUS_WRITE_CMD 0x50 +#define NOR_WRITE_STATUS_CMD 0x1 #define NOR_RESET_CMD 0xFF typedef struct IPodTouchNORSPIState {