Skip to content

Commit

Permalink
SPI might work? EFI header loads!
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
lemonjesus committed Jan 12, 2023
1 parent 2c7a61f commit 6228621
Show file tree
Hide file tree
Showing 9 changed files with 225 additions and 53 deletions.
2 changes: 1 addition & 1 deletion .gdbinit
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ layout vmdebug
focus cmd
set confirm off

break *0x20003010
break *0x20002fe4
continue
2 changes: 1 addition & 1 deletion TuckerNotes.md
Original file line number Diff line number Diff line change
@@ -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:
Expand Down
37 changes: 26 additions & 11 deletions hw/arm/ipod_touch.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand All @@ -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)
Expand Down Expand Up @@ -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));
Expand Down
113 changes: 113 additions & 0 deletions hw/arm/ipod_touch_nor_spi.c
Original file line number Diff line number Diff line change
@@ -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)
85 changes: 48 additions & 37 deletions hw/arm/ipod_touch_spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand All @@ -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) {
Expand All @@ -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 = &REG(s, addr);
Expand All @@ -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;
Expand All @@ -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);
}

Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion hw/arm/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -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}
2 changes: 1 addition & 1 deletion include/hw/arm/ipod_touch.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Loading

0 comments on commit 6228621

Please sign in to comment.