diff --git a/Makefile.objs b/Makefile.objs index c05f5e59b..7eab2dee5 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -170,6 +170,7 @@ user-obj-y += cutils.o cache-utils.o hw-obj-y = hw-obj-y += vl.o loader.o +hw-obj-y += iemu.o hw-obj-$(CONFIG_VIRTIO) += virtio.o virtio-console.o hw-obj-y += fw_cfg.o hw-obj-$(CONFIG_PCI) += pci.o pci_bridge.o diff --git a/devices/iPhone1/config.xml b/devices/iPhone1/config.xml new file mode 100644 index 000000000..c85eba26b --- /dev/null +++ b/devices/iPhone1/config.xml @@ -0,0 +1,7 @@ + + iPhone1 + m68ap + skin.xml + iboot + 0x18000000 + diff --git a/skin/devices/iphone2g/iphone2g-landscape.png b/devices/iPhone1/landscape.png similarity index 100% rename from skin/devices/iphone2g/iphone2g-landscape.png rename to devices/iPhone1/landscape.png diff --git a/skin/devices/iphone2g/iphone2g-portrait.png b/devices/iPhone1/portrait.png similarity index 100% rename from skin/devices/iphone2g/iphone2g-portrait.png rename to devices/iPhone1/portrait.png diff --git a/skin/devices/iphone2g/skin.xml b/devices/iPhone1/skin.xml similarity index 73% rename from skin/devices/iphone2g/skin.xml rename to devices/iPhone1/skin.xml index c7be880c4..fcfd9b905 100644 --- a/skin/devices/iphone2g/skin.xml +++ b/devices/iPhone1/skin.xml @@ -2,13 +2,13 @@ - + - + diff --git a/hw/iphone2g.c b/hw/iphone2g.c index 6ff1c3969..008858a51 100644 --- a/hw/iphone2g.c +++ b/hw/iphone2g.c @@ -29,8 +29,7 @@ #define RAM_SIZE 0x08000000 #define NOR_BASE_ADDR 0x24000000 -uint32_t g_debug = (0 - //S5L8900_DEBUG_CLK +uint32_t g_debug = ( 0 //S5L8900_DEBUG_CLK //0xffffffff | ); uint32_t g_dlevel = 0; @@ -244,16 +243,11 @@ static uint32_t lcd_read(void *opaque, target_phys_addr_t offset) return 0; } -// Not implemented static void lcd_write(void *opaque, target_phys_addr_t offset, uint32_t value) { - //iphone2g_lcd_s *s = (iphone2g_lcd_s *)opaque; - //fprintf(stderr, "%s: offset 0x%08x value 0x%08x\n", __FUNCTION__, offset, value); - if(offset == 0x78) // Window 2 framebuffer. Doesn't detect active window yet! { // Framebuffer Address - //fprintf(stderr, "%s: Found framebuffer at 0x%08x.\n", __func__, value); frame_base = value; } } @@ -286,12 +280,12 @@ static iphone2g_lcd_s * iphone2g_lcd_init(target_phys_addr_t base) static uint32_t aes_read(void *opaque, target_phys_addr_t offset) { - struct iphone2g_aes_s *aesop = (struct iphone2g_aes_s *)opaque; + struct aes_s *aesop = (struct aes_s *)opaque; //fprintf(stderr, "%s: offset 0x%08x\n", __FUNCTION__, offset); switch(offset) { - case IPHONE2G_AES_STATUS: + case AES_STATUS: return aesop->status; default: //fprintf(stderr, "%s: UNMAPPED AES_ADDR @ offset 0x%08x\n", __FUNCTION__, offset); @@ -301,93 +295,80 @@ static uint32_t aes_read(void *opaque, target_phys_addr_t offset) return 0; } -typedef struct cryptdata { - uint8_t crypt[0x80]; -} cryptdata; - -cryptdata cdata[] = -{ - {{0x93, 0x1E, 0x46, 0xB9, 0x79, 0x17, 0xd9, 0xFE, 0xA, 0x0, 0x1D, 0xAD, 0x10, 0x82, 0xA8, 0x15, 0x96, 0x4F, 0xDC, 0x24, 0x11, 0xAB, 0xCD, 0xA6, 0xDE, -0xDD, 0xE9, 0xDA, 0xCC, 0xB4, 0xE6, 0xD9, 0x5, 0x0}}, - {{0x6B, 0x84, 0x3, 0x34, 0x9E, 0x4, 0xCB, 0xDD, 0xFF, 0x69, 0x73, 0x40, 0x53, 0x60, 0xC, 0xF7, 0xC7, 0xF, 0x2C, 0x2, 0xD, 0xA3, 0x2A, 0xFD, 0xEA, 0x8E, 0xC8, 0xEC, 0x2D, 0xa, 0xF5, 0x5E, 0x5, 0x0}}, - {{0xBD, 0x9F, 0x26, 0xC7, 0xFD, 0xF3, 0xC3, 0xDF, 0xA2, 0xE7, 0x88, 0xDB, 0x48, 0x3B, 0x7C, 0x70, 0x57, 0xFF, 0xF2, 0x7F, 0x26, 0x65, 0x80, 0x4D, 0xB4, 0x2B, 0x48, 0x5F, 0x4, 0xDF, 0x31, 0xf, 0x5, 0x0}}, - {{0x8A, 0x37, 0x45, 0x45, 0xD7, 0x94, 0xCC, 0xC5, 0xD2, 0xE5, 0x5F, 0x51, 0x85, 0x12, 0xE3, 0x57, 0xA5, 0x6F, 0xFC, 0xF2, 0xBD, 0xE3, 0xF5, 0x39, 0x2, 0x14, 0x8F, 0x69, 0x49, 0x37, 0xA9, 0x1F, 0x5, 0x0}}, - {{0xF8, 0xCB, 0xEE, 0x5F, 0xB5, 0xB1, 0x2C, 0x25, 0xf, 0x5A, 0x7F, 0x45, 0xE9, 0xB8, 0x55, 0xAE, 0xFC, 0x6C, 0x69, 0x3E, 0x6E, 0x65, 0x4D, 0x69, 0x66, 0x33, 0x17, 0x67, 0xFC, 0x9E, 0x2A, 0x8, 0x5, 0x0}}, - {{0xE7, 0x25, 0x5, 0x46, 0xAC, 0x12, 0xEA, 0x24, 0x7F, 0x1D, 0xC1, 0x98, 0x72, 0x48, 0x69, 0x8F, 0xBC, 0x3A, 0x83, 0xc, 0xAB, 0xA2, 0xC8, 0xD6, 0x8E, 0xC2, 0x5E, 0xD3, 0xFD, 0x6, 0x2A, 0xE6, 0x5, 0x0}}, - {{0xC5, 0xDA, 0x96, 0xBD, 0x24, 0xBC, 0x53, 0x77, 0x61, 0x70, 0x4E, 0x84, 0x39, 0xBF, 0x18, 0x3C, 0x29, 0x2C, 0x1F, 0xD6, 0xE1, 0x66, 0x9C, 0xAD, 0x84, 0xDF, 0x4A, 0x12, 0xF2, 0x19, 0x12, 0x72, 0x5, 0x0}}, - {{0x18, 0x60, 0x8A, 0x5B, 0x1, 0x90, 0x3E, 0x77, 0xCB, 0xAE, 0xA7, 0xA8, 0xEF, 0xA6, 0xF6, 0xF0, 0xF7, 0x44, 0x6C, 0x5A, 0xd, 0x3D, 0xC6, 0xEE, 0x20, 0xB5, 0x7A, 0x11, 0xFD, 0x6F, 0x2C, 0x6F, 0x5, 0x0}}, - {{0x2F, 0x3C, 0x85, 0x5, 0x84, 0x40, 0xED, 0xA4, 0xF6, 0x6A, 0x1A, 0x78, 0x4F, 0x3F, 0x5D, 0x26, 0xD4, 0xEE, 0x80, 0x5C, 0x67, 0xF5, 0x92, 0x90, 0x37, 0x59, 0x3A, 0x1E, 0x19, 0x89, 0xB6, 0x38, 0x79, 0x58, 0x50, 0x5C, 0xEA, 0x8D, 0xED, 0x16, 0xB4, 0xA2, 0xA, 0xA7, 0x59, 0xC8, 0x29, 0x23, 0x87, 0x57, 0xC8, 0xD1, 0xD9, 0xC0, 0x98, 0x9D, 0xF5, 0xCF, 0x71, 0x9F, 0x20, 0xD8, 0x61, 0x3D, 0x11}}, - {{0x2F, 0x3C, 0x85, 0x5, 0x84, 0x40, 0xED, 0xA4, 0xF6, 0x6A, 0x1A, 0x78, 0x4F, 0x3F, 0x5D, 0x26, 0xD4, 0xEE, 0x80, 0x5C, 0x67, 0xF5, 0x92, 0x90, 0x37, 0x59, 0x3A, 0x1E, 0x19, 0x89, 0xB6, 0x38, 0x79, 0x58, 0x50, 0x5C, 0xEA, 0x8D, 0xED, 0x16, 0xB4, 0xA2, 0xA, 0xA7, 0x59, 0xC8, 0x29, 0x23, 0x87, 0x57, 0xC8, 0xD1, 0xD9, 0xC0, 0x98, 0x9D, 0xF5, 0xCF, 0x71, 0x9F, 0x20, 0xD8, 0x61, 0x3D, 0x11}}, - {{0x2F, 0x3C, 0x85, 0x5, 0x84, 0x40, 0xED, 0xA4, 0xF6, 0x6A, 0x1A, 0x78, 0x4F, 0x3F, 0x5D, 0x26, 0xD4, 0xEE, 0x80, 0x5C, 0x67, 0xF5, 0x92, 0x90, 0x37, 0x59, 0x3A, 0x1E, 0x19, 0x89, 0xB6, 0x38, 0x79, 0x58, 0x50, 0x5C, 0xEA, 0x8D, 0xED, 0x16, 0xB4, 0xA2, 0xA, 0xA7, 0x59, 0xC8, 0x29, 0x23, 0x87, 0x57, 0xC8, 0xD1, 0xD9, 0xC0, 0x98, 0x9D, 0xF5, 0xCF, 0x71, 0x9F, 0x20, 0xD8, 0x61, 0x3D, 0x11}}, - {{0x2F, 0x3C, 0x85, 0x5, 0x84, 0x40, 0xED, 0xA4, 0xF6, 0x6A, 0x1A, 0x78, 0x4F, 0x3F, 0x5D, 0x26, 0xD4, 0xEE, 0x80, 0x5C, 0x67, 0xF5, 0x92, 0x90, 0x37, 0x59, 0x3A, 0x1E, 0x19, 0x89, 0xB6, 0x38, 0x79, 0x58, 0x50, 0x5C, 0xEA, 0x8D, 0xED, 0x16, 0xB4, 0xA2, 0xA, 0xA7, 0x59, 0xC8, 0x29, 0x23, 0x87, 0x57, 0xC8, 0xD1, 0xD9, 0xC0, 0x98, 0x9D, 0xF5, 0xCF, 0x71, 0x9F, 0x20, 0xD8, 0x61, 0x3D, 0x11}} - -}; -static int ccount = 0; - static void aes_write(void *opaque, target_phys_addr_t offset, uint32_t value) { - struct iphone2g_aes_s *aesop = (struct iphone2g_aes_s *)opaque; - uint8_t inbuf[0x1000]; - uint8_t *buf; - //uint32_t ctr; + struct aes_s *aesop = (struct aes_s *)opaque; + static uint8_t keylenop = 0; - //fprintf(stderr, "%s: offset 0x%08x value 0x%08x\n", __FUNCTION__, offset, value); + uint8_t inbuf[0x1000]; + uint8_t *buf; - switch(offset) { - case IPHONE2G_AES_GO: - //fprintf(stderr, "%s: Received AES_GO lets do it\n", __FUNCTION__); - memset(aesop->ivec, 0, 16); + //fprintf(stderr, "%s: offset 0x%08x value 0x%08x\n", __FUNCTION__, offset, value); + switch(offset) { + case AES_GO: memset(inbuf, 0, sizeof(inbuf)); - //fprintf(stderr, "%s: AES_DECRYPT INADDR 0x%08x INSIZE 0x%08x OUTADDR 0x%08x\n", __FUNCTION__, aesop->inaddr, aesop->insize, aesop->outaddr); - cpu_physical_memory_read((aesop->inaddr - 0x80000000), (uint8_t *)inbuf, aesop->insize); - /* - for( ctr = 0; ctr < aesop->insize; ctr++ ) - { - fprintf(stderr, "%02x ", inbuf[ ctr ] ); - } - fprintf(stderr, "\n" ); - */ - buf = (uint8_t *) malloc(aesop->insize); - memset(buf, 0, aesop->insize); - if(aesop->insize >= 0x20) - { - memcpy(buf, cdata[ccount].crypt, aesop->insize); - ccount++; - } else { - //AES_cbc_encrypt(inbuf, buf, aesop->insize, &aesop->decryptKey, aesop->ivec, AES_DECRYPT); - /* - fprintf(stderr, "decrypting: "); - for( ctr = 0; ctr < aesop->insize; ctr++ ) - { - fprintf(stderr, "%02x ", buf[ ctr ] ); - } - */ - ; + + 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 *) qemu_mallocz(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); - free(buf); + memset(aesop->custkey, 0, 0x20); + memset(aesop->ivec, 0, 0x10); + qemu_free(buf); + keylenop = 0; aesop->outsize = aesop->insize; aesop->status = 0xf; break; - case IPHONE2G_AES_INADDR: + case AES_KEYLEN: + if(keylenop == 1) { + aesop->operation = value; + } + keylenop++; + aesop->keylen = value; + break; + case AES_INADDR: aesop->inaddr = value; break; - case IPHONE2G_AES_INSIZE: + case AES_INSIZE: aesop->insize = value; break; - case IPHONE2G_AES_OUTSIZE: + case AES_OUTSIZE: aesop->outsize = value; break; - case IPHONE2G_AES_OUTADDR: + case AES_OUTADDR: aesop->outaddr = value; break; - case IPHONE2G_AES_KEY ... ((IPHONE2G_AES_KEY + IPHONE2G_AES_KEYSIZE) - 1): - break; - case IPHONE2G_AES_IV ... ((IPHONE2G_AES_IV + IPHONE2G_AES_IVSIZE) -1 ): + 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; @@ -407,16 +388,123 @@ static CPUWriteMemoryFunc *aes_writefn[] = { aes_write, }; -static void iphone2g_aes_init(target_phys_addr_t base) +static void aes_init(target_phys_addr_t base) { - struct iphone2g_aes_s *aesop = (struct iphone2g_aes_s *) qemu_mallocz(sizeof(iphone2g_aes_s)); + struct aes_s *aesop = (struct aes_s *) qemu_mallocz(sizeof(aes_s)); int io; io = cpu_register_io_memory(aes_readfn, aes_writefn, aesop, DEVICE_LITTLE_ENDIAN); cpu_register_physical_memory(base, 0xFF, io); +} + +typedef struct sha1_status { + uint32_t config; + uint32_t reset; + uint32_t hresult; + uint32_t insize; + uint32_t unkstat; + uint8_t hashout[0x14]; +} sha1_status_s; + +static void sha1_reset(void *opaque) +{ + sha1_status_s *s = (sha1_status_s *)opaque; + memset(s, 0, sizeof(sha1_status_s)); +} + +static uint32_t sha1_read(void *opaque, target_phys_addr_t offset) +{ + sha1_status_s *s = (sha1_status_s *)opaque; + + //fprintf(stderr, "%s: offset 0x%08x\n", __FUNCTION__, offset); - //AES_set_decrypt_key(key_0x837, sizeof(key_0x837) * 8, &aesop->decryptKey); + switch(offset) { + case SHA_CONFIG: + return s->config; + case SHA_RESET: + return 0; + case SHA_HRESULT: + return s->hresult; + case SHA_INSIZE: + return s->insize; + /* Hash result ouput */ + case 0x20 ... 0x34: + //fprintf(stderr, "Hash out %08x\n", *(uint32_t *)&s->hashout[offset - 0x20]); + return *(uint32_t *)&s->hashout[offset - 0x20]; + } + return 0; +} + +static void sha1_write(void *opaque, target_phys_addr_t offset, + uint32_t value) +{ + sha1_status_s *s = (sha1_status_s *)opaque; + + //fprintf(stderr, "%s: offset 0x%08x value 0x%08x\n", __FUNCTION__, offset, value); + + switch(offset) { + case SHA_CONFIG: + if((value & 0x2) && (s->config & 0x8)) + { + uint8_t *hptr; + + if(!s->hresult || !s->insize) + return; + + /* Why do they give us incorrect size? */ + s->insize += 0x20; + + hptr = (uint8_t *) qemu_mallocz(s->insize); + cpu_physical_memory_read(s->hresult, (uint8_t *)hptr, s->insize); + + SHA_CTX context; + SHA1_Init(&context); + SHA1_Update(&context, (uint8_t*) hptr, s->insize); + SHA1_Final(s->hashout, &context); + + qemu_free(hptr); + } else { + s->config = value; + } + break; + case SHA_RESET: + if(value & 1) + sha1_reset(s); + break; + case SHA_HRESULT: + s->hresult = value; + break; + case SHA_INSIZE: + s->insize = value; + break; + case SHA_UNKSTAT: + s->unkstat = value; + break; + } + + +} + +static CPUReadMemoryFunc * const sha1_readfn[] = { + sha1_read, + sha1_read, + sha1_read, +}; + +static CPUWriteMemoryFunc * const sha1_writefn[] = { + sha1_write, + sha1_write, + sha1_write, +}; + +static void sha1_init(target_phys_addr_t base) +{ + sha1_status_s *s = (sha1_status_s *) qemu_mallocz(sizeof(sha1_status_s)); + int iomemtype = cpu_register_io_memory(sha1_readfn, + sha1_writefn, + s, DEVICE_LITTLE_ENDIAN); + cpu_register_physical_memory(base, 0xFF, iomemtype); } typedef struct iphone2gKeyState_s { @@ -500,7 +588,9 @@ static void iphone2g_init(ram_addr_t ram_size, exit(1); } - cpu_register_physical_memory(iboot_base, (ram_addr_t)iboot_size,(phys_flash = qemu_ram_alloc(NULL, "iphone2g.iboot", iboot_size))); + cpu_register_physical_memory(0x22000000, 0x500000, qemu_ram_alloc(NULL, "iphone2g.sram", 0x500000)); + + cpu_register_physical_memory(iboot_base, (ram_addr_t)iboot_size, qemu_ram_alloc(NULL, "iphone2g.iboot", iboot_size) | IO_MEM_RAM); load_image_targphys(option_rom[0].name, iboot_base, iboot_size); @@ -508,7 +598,7 @@ static void iphone2g_init(ram_addr_t ram_size, /* Map in default ram space */ cpu_register_physical_memory(RAM_BASE_ADDR, RAM_SIZE, ramoff | IO_MEM_RAM); /* Also map higher ram space to default */ - cpu_register_physical_memory(RAM_HIGH_ADDR, RAM_SIZE, ramoff | IO_MEM_RAM); + //cpu_register_physical_memory(RAM_HIGH_ADDR, RAM_SIZE, ramoff | IO_MEM_RAM); /* Also also map to 0x0 as that's what OIB uses */ cpu_register_physical_memory(0x0, RAM_SIZE, ramoff | IO_MEM_RAM); @@ -531,7 +621,10 @@ static void iphone2g_init(ram_addr_t ram_size, iphone2g_lcd_init(LCD_BASE_ADDR); /* Init AES hardware */ - iphone2g_aes_init(AES_BASE_ADDR); + aes_init(AES_BASE_ADDR); + + /* Init SHA1 hardware */ + sha1_init(SHA1_BASE_ADDR); /* Button emulation */ iphone2g_register_keyboard(); @@ -540,8 +633,8 @@ static void iphone2g_init(ram_addr_t ram_size, } static QEMUMachine iphone2g_machine = { - .name = "iphone2g", - .desc = "iPhone 2G", + .name = "iPhone1", + .desc = "iPhone 1", .init = iphone2g_init, }; diff --git a/hw/iphone2g.h b/hw/iphone2g.h index e980213a1..51a116bce 100644 --- a/hw/iphone2g.h +++ b/hw/iphone2g.h @@ -4,39 +4,59 @@ #include #include -#define key_0x837 ((uint8_t[]){0x18, 0x84, 0x58, 0xA6, 0xD1, 0x50, 0x34, 0xDF, 0xE3, 0x86, 0xF2, 0x3B, 0x61, 0xD4, 0x37, 0x74}) +#define key_uid ((uint8_t[]){0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}) + +#define GET_BITS(x, start, length) ((((uint32_t)(x)) << (32 - ((start) + (length)))) >> (32 - (length))) +#define GET_KEYLEN(x) GET_BITS(x, 16, 2) #define LCD_BASE_ADDR 0x38900000 #define LCD_WIDTH 320 #define LCD_HEIGHT 480 +#define SHA1_BASE_ADDR 0x38000000 +#define SHA_CONFIG 0x0 +#define SHA_RESET 0x4 +#define SHA_UNKSTAT 0x7c +#define SHA_HRESULT 0x84 +#define SHA_INSIZE 0x8c + #define AES_128_CBC_BLOCK_SIZE 64 #define AES_BASE_ADDR 0x38C00000 - #define IPHONE2G_AES_CONTROL 0x0 - #define IPHONE2G_AES_GO 0x4 - #define IPHONE2G_AES_UNKREG0 0x8 - #define IPHONE2G_AES_STATUS 0xC - #define IPHONE2G_AES_UNKREG1 0x10 - #define IPHONE2G_AES_KEYLEN 0x14 - #define IPHONE2G_AES_INSIZE 0x18 - #define IPHONE2G_AES_INADDR 0x20 - #define IPHONE2G_AES_OUTSIZE 0x24 - #define IPHONE2G_AES_OUTADDR 0x28 - #define IPHONE2G_AES_AUXSIZE 0x2C - #define IPHONE2G_AES_AUXADDR 0x30 - #define IPHONE2G_AES_SIZE3 0x34 - #define IPHONE2G_AES_KEY 0x4C - #define IPHONE2G_AES_TYPE 0x6C - #define IPHONE2G_AES_IV 0x74 - #define IPHONE2G_AES_KEYSIZE 0x20 - #define IPHONE2G_AES_IVSIZE 0x10 - - - -typedef struct iphone2g_aes_s +#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 aes_s { AES_KEY decryptKey; - uint8_t ivec[16]; + uint32_t ivec[4]; uint32_t insize; uint32_t inaddr; uint32_t outsize; @@ -47,8 +67,10 @@ typedef struct iphone2g_aes_s uint32_t ctrl; uint32_t unkreg0; uint32_t unkreg1; + uint32_t operation; uint32_t keylen; -} iphone2g_aes_s; + uint32_t custkey[8]; +} aes_s; typedef struct iphone2g_lcd_s { diff --git a/hw/s5l8900.c b/hw/s5l8900.c index 9bc97874f..4f361f305 100644 --- a/hw/s5l8900.c +++ b/hw/s5l8900.c @@ -42,11 +42,66 @@ typedef struct s5l8900_timer_s { 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; + 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; } s5l8900_timer_s; struct s5l8900_gpio_s s5l8900_gpio_state[32]; +static void s5l8900_st_tick(void *opaque); + +/* Update tick_interval */ +static void s5l8900_st_update(s5l8900_timer_s *s) +{ + s->freq_out = 1000000000 / 100; + s->tick_interval = /* bcount1 * get_ticks / freq + ((bcount2 * get_ticks / freq)*/ + muldiv64((s->bcount1 < 1000) ? 1000 : s->bcount1, get_ticks_per_sec(), s->freq_out); + s->next_planned_tick = 0; + + //fprintf(stderr, "%s: freq_out 0x%08x tick_interval %lld ticks per sec %lld\n", __func__, s->freq_out, s->tick_interval, get_ticks_per_sec()); +} + +static void s5l8900_st_set_timer(s5l8900_timer_s *s) +{ + uint64_t last = qemu_get_clock_ns(vm_clock) - s->base_time; + + s->next_planned_tick = last + (s->tick_interval - last % s->tick_interval); + qemu_mod_timer(s->st_timer, s->next_planned_tick + s->base_time); + s->last_tick = last; +} + +/* counter step */ +static void s5l8900_st_tick(void *opaque) +{ + s5l8900_timer_s *s = (s5l8900_timer_s *)opaque; + + if (s->status & TIMER_STATE_START) { + //fprintf(stderr, "%s: Raising irq\n", __func__); + qemu_irq_raise(s->irq); + + /* schedule next interrupt */ + s5l8900_st_set_timer(s); + } else { + s->next_planned_tick = 0; + s->last_tick = 0; + qemu_del_timer(s->st_timer); + } +} + static uint32_t s5l8900_timer1_read(void *opaque, target_phys_addr_t addr) { s5l8900_timer_s *s = (struct s5l8900_timer_s *) opaque; @@ -62,6 +117,11 @@ static uint32_t s5l8900_timer1_read(void *opaque, target_phys_addr_t addr) return s->ticks_high; case TIMER_TICKSLOW: return s->ticks_low; + case TIMER_IRQSTAT: + return s->irqstat; + case TIMER_IRQLATCH: + return 0xffffffff; + default: S5L8900_DEBUG(S5L8900_DEBUG_CLK, S5L8900_DLVL_ERR, "%s: UNMAPPED offset = 0x%02x\n", __FUNCTION__, (int)addr); } @@ -70,9 +130,43 @@ static uint32_t s5l8900_timer1_read(void *opaque, target_phys_addr_t addr) static void s5l8900_timer1_write(void *opaque, target_phys_addr_t addr, uint32_t value) { + s5l8900_timer_s *s = (struct s5l8900_timer_s *) opaque; + + S5L8900_DEBUG(S5L8900_DEBUG_CLK, S5L8900_DLVL_ERR, "%s: offset = 0x%02x value = 0x%08x\n", __FUNCTION__, (int)addr, value); + 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->status & TIMER_STATE_START)) { + s->base_time = qemu_get_clock_ns(vm_clock); + s5l8900_st_update(s); + s5l8900_st_set_timer(s); + } else if ((value & TIMER_STATE_START) < (s->status & TIMER_STATE_START)) { + qemu_del_timer(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; + } - S5L8900_DEBUG(S5L8900_DEBUG_CLK, S5L8900_DLVL_ERR, "%s: offset = 0x%02x\n", __FUNCTION__, (int)addr); - + return; } static CPUReadMemoryFunc *s5l8900_timer1_readfn[] = { @@ -87,16 +181,19 @@ static CPUWriteMemoryFunc *s5l8900_timer1_writefn[] = { s5l8900_timer1_write, }; -static void s5l8900_timer_init(target_phys_addr_t base) +static void s5l8900_timer_init(target_phys_addr_t base, qemu_irq irq) { struct s5l8900_timer_s *timer1 = (struct s5l8900_timer_s *) qemu_mallocz(sizeof(struct s5l8900_timer_s)); int iomemtype = cpu_register_io_memory(s5l8900_timer1_readfn, s5l8900_timer1_writefn, timer1, DEVICE_LITTLE_ENDIAN); - S5L8900_OPAQUE("TIMER1", timer1); - timer1->ticks_high = 0; - timer1->ticks_low = 0; + timer1->irq = irq; cpu_register_physical_memory(base, 0xFF, iomemtype); + + timer1->base_time = qemu_get_clock_ns(vm_clock); + + timer1->st_timer = qemu_new_timer_ns(vm_clock, s5l8900_st_tick, timer1); + } static uint32_t s5l8900_clk1_read(void *opaque, target_phys_addr_t addr) @@ -142,48 +239,6 @@ static CPUWriteMemoryFunc *s5l8900_clk1_writefn[] = { s5l8900_clk1_write, }; - -static uint32_t s5l8900_miu_read(void *opaque, target_phys_addr_t addr) -{ - S5L8900_DEBUG(S5L8900_DEBUG_MIU, S5L8900_DLVL_ERR, "%s: offset = 0x%02x\n", __FUNCTION__, (int)addr); - - switch (addr) { - case POWER_ID: - return (3 << 24); //for older iboots - //return (5 << 0x18); // new iboots - default: - S5L8900_DEBUG(S5L8900_DEBUG_MIU, S5L8900_DLVL_ERR, "%s: UNMAPPED offset = 0x%02x\n", __FUNCTION__, (int)addr); - } - return 0; -} - -static void s5l8900_miu_write(void *opaque, target_phys_addr_t addr, uint32_t value) -{ - - S5L8900_DEBUG(S5L8900_DEBUG_MIU, S5L8900_DLVL_ERR, "%s: offset = 0x%02x\n", __FUNCTION__, (int)addr); - -} - -static CPUReadMemoryFunc *s5l8900_miu_readfn[] = { - s5l8900_miu_read, - s5l8900_miu_read, - s5l8900_miu_read, -}; - -static CPUWriteMemoryFunc *s5l8900_miu_writefn[] = { - s5l8900_miu_write, - s5l8900_miu_write, - s5l8900_miu_write, -}; - -static void s5l8900_miu_init(target_phys_addr_t base) -{ - int iomemtype = cpu_register_io_memory(s5l8900_miu_readfn, - s5l8900_miu_writefn, NULL, DEVICE_LITTLE_ENDIAN); - cpu_register_physical_memory(base, 0x50, iomemtype); -} - - static void s5l8900_clk_init(target_phys_addr_t base) { struct s5l8900_clk1_s *clk1 = (struct s5l8900_clk1_s *) qemu_mallocz(sizeof(struct s5l8900_clk1_s)); @@ -202,15 +257,55 @@ static uint32_t s5l8900_chipid_read(void *opaque, target_phys_addr_t addr) switch(addr) { case 0x04: - #if 0 /* only enable if your on 3.1.3 */ { - uint32_t debug_uart = 0xffffffff; - cpu_physical_memory_write(0x1802765C, (uint8_t *)&debug_uart, 4); + uint32_t debug_uart = 0xffffffff; + //cpu_physical_memory_write(0x1802765C, (uint8_t *)&debug_uart, 4); + //cpu_physical_memory_write(0x18029FE0, (uint8_t *)&debug_uart, 4); + cpu_physical_memory_write(0x18022FA0, (uint8_t *)&debug_uart, 4); } - #endif return 0xfffffffc; case 0x8: return 0x4; + case 0xc: + fprintf(stderr, "Loading kernel image\n"); + { + struct stat st; + unsigned int size; + int ret; + uint8_t *buf; + uint32_t debug_uart = 0xffffffff; + //cpu_physical_memory_write(0x1802765C, (uint8_t *)&debug_uart, 4); + //cpu_physical_memory_write(0x18029FE0, (uint8_t *)&debug_uart, 4); + cpu_physical_memory_write(0x18022FA0, (uint8_t *)&debug_uart, 4); + + stat("../../ibootfiles/kernelcache.release.s5l8900x.no8900", &st); + size = st.st_size; + + FILE *fd = fopen("../../ibootfiles/kernelcache.release.s5l8900x.no8900", "r"); + + buf = (uint8_t *)malloc(size); + ret = fread(buf, 1, size, fd); + fprintf(stderr, "kernel read %d\n", ret); + if(ret != size) + { + fprintf(stderr, "error reading kernel %d ret %d\n", size, ret); + } + fclose(fd); + cpu_physical_memory_write(0x08000000, buf, size); + free(buf); + stat("../../ibootfiles/ramdisk-1.0.2.dmg", &st); + size = st.st_size; + fd = fopen("../../ibootfiles/ramdisk-1.0.2.dmg", "r"); + buf = (uint8_t *)malloc(size); + ret = fread(buf, 1, size, fd); + if(ret != size) + { + fprintf(stderr, "error reading ramdisk %d ret %d\n", size, ret); + } + fclose(fd); + cpu_physical_memory_write(0x9340000, buf, size); + free(buf); + } default: S5L8900_DEBUG(S5L8900_DEBUG_CHIPID, S5L8900_DLVL_ERR, "%s: UNMAPPED offset = 0x%02x\n", __FUNCTION__, (int)addr); @@ -231,18 +326,19 @@ static CPUWriteMemoryFunc *s5l8900_chipid_writefn[] = { NULL, }; -static void s5l8900_gpioic_write(void *opaque, target_phys_addr_t addr, uint32_t value) +static void s5l8900_sysic_write(void *opaque, target_phys_addr_t addr, uint32_t value) { //fprintf(stderr, "%s: offset 0x%08x value 0x%08x\n", __func__, addr, value); } -static uint32_t s5l8900_gpioic_read(void *opaque, target_phys_addr_t addr) +static uint32_t s5l8900_sysic_read(void *opaque, target_phys_addr_t addr) { //fprintf(stderr, "%s: offset 0x%08x\n", __func__, addr); switch(addr) { - case 0x44: - return 0x5000005; + case POWER_ID: + //return (3 << 24); //for older iboots + return (2 << 0x18); case 0x7a: case 0x7c: return 1; @@ -251,23 +347,23 @@ static uint32_t s5l8900_gpioic_read(void *opaque, target_phys_addr_t addr) return 0; } -static CPUReadMemoryFunc *s5l8900_gpioic_readfn[] = { - s5l8900_gpioic_read, - s5l8900_gpioic_read, - s5l8900_gpioic_read, +static CPUReadMemoryFunc *s5l8900_sysic_readfn[] = { + s5l8900_sysic_read, + s5l8900_sysic_read, + s5l8900_sysic_read, }; -static CPUWriteMemoryFunc *s5l8900_gpioic_writefn[] = { - s5l8900_gpioic_write, - s5l8900_gpioic_write, - s5l8900_gpioic_write, +static CPUWriteMemoryFunc *s5l8900_sysic_writefn[] = { + s5l8900_sysic_write, + s5l8900_sysic_write, + s5l8900_sysic_write, }; -static void s5l8900_gpioic_init(target_phys_addr_t base) +static void s5l8900_sysic_init(target_phys_addr_t base) { - int iomemtype = cpu_register_io_memory(s5l8900_gpioic_readfn, - s5l8900_gpioic_writefn, NULL, DEVICE_LITTLE_ENDIAN); + int iomemtype = cpu_register_io_memory(s5l8900_sysic_readfn, + s5l8900_sysic_writefn, NULL, DEVICE_LITTLE_ENDIAN); cpu_register_physical_memory(base, 0x3FF, iomemtype); } @@ -349,7 +445,8 @@ static uint32_t s5l8900_usb_phy_read(void *opaque, target_phys_addr_t offset) return s->usb_ophytune; default: - hw_error("%s: read invalid location 0x%08x.\n", __func__, offset); + //hw_error("%s: read invalid location 0x%08x.\n", __func__, offset); + fprintf(stderr, "%s: read invalid location 0x%08x\n", __func__, offset); return 0; } @@ -379,7 +476,8 @@ static void s5l8900_usb_phy_write(void *opaque, target_phys_addr_t offset, uint3 return; default: - hw_error("%s: write invalid location 0x%08x.\n", __func__, offset); + //hw_error("%s: write invalid location 0x%08x.\n", __func__, offset); + fprintf(stderr, "%s: write invalid location 0x%08x\n", __func__, offset); } } @@ -455,17 +553,14 @@ s5l8900_state *s5l8900_init(void) /* CLKs */ s5l8900_clk_init(CLOCK1); - /* MIU */ - s5l8900_miu_init(MIU_BASE); - /* Sytem Timer */ - s5l8900_timer_init(S5L8900_TIMER1); + s5l8900_timer_init(TIMER1, s5l8900_get_irq(s, IRQ_TIMER0)); /* GPIO */ s5l8900_gpio_init(S5L8900_GPIO_BASE); - /* GPIOIC */ - s5l8900_gpioic_init(S5L8900_GPIOIC_BASE); + /* SYSIC */ + s5l8900_sysic_init(S5L8900_SYSIC_BASE); /* Uart */ s5l8900_uart_init(S5L8900_UART0_BASE, 0, 256, s5l8900_get_irq(s, S5L8900_IRQ_UART0), serial_hds[0]); diff --git a/hw/s5l8900.h b/hw/s5l8900.h index f1f6b113e..7e3bab8cf 100644 --- a/hw/s5l8900.h +++ b/hw/s5l8900.h @@ -4,9 +4,11 @@ #include "qemu-timer.h" // Devices +// SYSIC/MIU +#define S5L8900_SYSIC_BASE 0x39A00000 +#define POWER_ID 0x44 // GPIO -#define S5L8900_GPIOIC_BASE 0x39A00000 #define S5L8900_GPIO_BASE 0x3E400000 #define S5L8900_IRQ_GPIO0 0x21 #define S5L8900_IRQ_GPIO1 0x20 @@ -32,10 +34,6 @@ #define PCF50633_ADDR_SET 0xe7 #define BUTTONS_IIC_STATE 0x4B -// MIU -#define MIU_BASE 0x39A00000 -#define POWER_ID 0x44 - // Chip ID #define S5L8900_CHIPID 0x3e500000 @@ -45,10 +43,21 @@ #define S5L8900_IRQ_UART0 24 // TIMERS -#define S5L8900_IRQ_TIMER0 7 -#define S5L8900_TIMER1 0x3E200000 +#define IRQ_TIMER0 7 +#define TIMER_IRQSTAT 0x10000 +#define TIMER_IRQLATCH 0xF8 +#define TIMER1 0x3E200000 #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 // VIC #define S5l8900_I2C0_BASE 0x3C600000 diff --git a/hw/s5l8900_i2c.c b/hw/s5l8900_i2c.c index 7fc9f888d..90f9ca5f1 100644 --- a/hw/s5l8900_i2c.c +++ b/hw/s5l8900_i2c.c @@ -126,8 +126,8 @@ static uint32_t s5l8900_i2c_read(void *opaque, target_phys_addr_t offset) return tmp_reg20; } default: - hw_error("s5l8900.i2c: bad read offset 0x" TARGET_FMT_plx "\n", - offset); + //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; } @@ -229,8 +229,8 @@ static void s5l8900_i2c_write(void *opaque, target_phys_addr_t offset, //s->iicreg20 &= ~value; break; default: - hw_error("s5l8900.i2c: bad write offset 0x" TARGET_FMT_plx "\n", - offset); + //hw_error("s5l8900.i2c: bad write offset 0x" TARGET_FMT_plx "\n", offset); + fprintf(stderr, "%s: bad write offset 0x%08x\n", __func__, offset); } } diff --git a/hw/usb_synopsys.c b/hw/usb_synopsys.c index a554dd163..b1cf7fef3 100644 --- a/hw/usb_synopsys.c +++ b/hw/usb_synopsys.c @@ -325,7 +325,7 @@ static void synopsys_usb_update_irq(synopsys_usb_state *_state) if((_state->pcgcctl & 3) == 0 && _state->gintmsk & _state->gintsts) { - printf("USB: IRQ triggered 0x%08x & 0x%08x.\n", _state->gintsts, _state->gintmsk); + //printf("USB: IRQ triggered 0x%08x & 0x%08x.\n", _state->gintsts, _state->gintmsk); qemu_irq_raise(_state->irq); } else @@ -354,7 +354,7 @@ static void synopsys_usb_update_in_ep(synopsys_usb_state *_state, uint8_t _ep) synopsys_usb_update_ep(_state, eps); if(eps->control & USB_EPCON_ENABLE) - printf("USB: IN transfer queued on %d.\n", _ep); + ;//printf("USB: IN transfer queued on %d.\n", _ep); } static void synopsys_usb_update_out_ep(synopsys_usb_state *_state, uint8_t _ep) @@ -363,7 +363,7 @@ static void synopsys_usb_update_out_ep(synopsys_usb_state *_state, uint8_t _ep) synopsys_usb_update_ep(_state, eps); if(eps->control & USB_EPCON_ENABLE) - printf("USB: OUT transfer queued on %d.\n", _ep); + ;//printf("USB: OUT transfer queued on %d.\n", _ep); } static int synopsys_usb_tcp_callback(tcp_usb_state_t *_state, void *_arg, tcp_usb_header_t *_hdr, char *_buffer) @@ -393,7 +393,7 @@ static int synopsys_usb_tcp_callback(tcp_usb_state_t *_state, void *_arg, tcp_us if(eps->control & USB_EPCON_STALL) { eps->control &=~ USB_EPCON_STALL; // Should this be EP0 only - printf("USB: Stall.\n"); + //printf("USB: Stall.\n"); ret = USB_RET_STALL; } else if(eps->control & USB_EPCON_ENABLE) @@ -417,7 +417,7 @@ static int synopsys_usb_tcp_callback(tcp_usb_state_t *_state, void *_arg, tcp_us if(txfs + txfz > sizeof(state->fifos)) hw_error("usb_synopsys: USB transfer would overflow FIFO buffer!\n"); - printf("USB: Starting IN transfer on EP %d (%d)...\n", ep, amtDone); + //printf("USB: Starting IN transfer on EP %d (%d)...\n", ep, amtDone); if(amtDone > 0) { @@ -430,7 +430,7 @@ static int synopsys_usb_tcp_callback(tcp_usb_state_t *_state, void *_arg, tcp_us memcpy(_buffer, (char*)&state->fifos[txfs], amtDone); } - printf("USB: IN transfer complete!\n"); + //printf("USB: IN transfer complete!\n"); eps->tx_size = (eps->tx_size &~ DEPTSIZ_XFERSIZ_MASK) | ((sz-amtDone) & DEPTSIZ_XFERSIZ_MASK); @@ -448,7 +448,7 @@ static int synopsys_usb_tcp_callback(tcp_usb_state_t *_state, void *_arg, tcp_us if(eps->control & USB_EPCON_STALL) { eps->control &=~ USB_EPCON_STALL; // Should this be EP0 only - printf("USB: Stall.\n"); + //printf("USB: Stall.\n"); ret = USB_RET_STALL; } else if(eps->control & USB_EPCON_ENABLE) @@ -468,7 +468,7 @@ static int synopsys_usb_tcp_callback(tcp_usb_state_t *_state, void *_arg, tcp_us if(rxfz > sizeof(state->fifos)) hw_error("usb_synopsys: USB transfer would overflow FIFO buffer!\n"); - printf("USB: Starting OUT transfer on EP %d (%d)...\n", ep, amtDone); + //printf("USB: Starting OUT transfer on EP %d (%d)...\n", ep, amtDone); if(amtDone > 0) { @@ -486,6 +486,7 @@ static int synopsys_usb_tcp_callback(tcp_usb_state_t *_state, void *_arg, tcp_us if(_hdr->flags & tcp_usb_setup) { + /* printf("USB: Setup %02x %02x %02x %02x %02x %02x %02x %02x\n", state->fifos[0], state->fifos[1], @@ -495,7 +496,7 @@ static int synopsys_usb_tcp_callback(tcp_usb_state_t *_state, void *_arg, tcp_us state->fifos[5], state->fifos[6], state->fifos[7]); - + */ eps->interrupt_status |= USB_EPINT_SetUp; } else diff --git a/iemu.c b/iemu.c new file mode 100644 index 000000000..87a243cb7 --- /dev/null +++ b/iemu.c @@ -0,0 +1,216 @@ +/* + * iEmu + * + * Written by cmw + * + * This code is licenced under the GPL. + */ + +#include +#include "expat.h" +#include +#include + +#include "hw/boards.h" +#include "iemu.h" + +const static int BUFFER_SIZE = 512; + +typedef struct dev_config +{ + char *devname; + char *skinfile; + char *bootname; + char *hwid; + uint8_t boottype; + uint32_t loadaddr; + char *fwver; +} DevConfig; + +static DevConfig *curdev = NULL; +const char *tagval = NULL; +char fwpath[PATH_MAX]; + +#define DEFAULT_DEVICE_PATH "devices/" + +static int iemu_parse_config(const char *deviceName, char *file); + +static inline int value_is(const char *attr, const char *name) +{ + return (strcasecmp(attr, name) == 0); +} + +char *iemu_get_skin(void) +{ + if(curdev) + return curdev->skinfile; + return NULL; +} + +void iemu_fw_list(const char *device) +{ + DIR *iemufwdir; + struct dirent *ep; + + sprintf(fwpath, "%s%s", DEFAULT_DEVICE_PATH, device); + iemufwdir = opendir(fwpath); + + if(iemufwdir != NULL) + { + printf("Available %s firmware versions\n", device); + while ((ep = readdir(iemufwdir)) != NULL) + { + if((strcmp(ep->d_name, ".") != 0) && (strcmp(ep->d_name, "..") != 0) && ep->d_type == DT_DIR) + { + printf("\tVersion: %s\n", ep->d_name); + } + } + closedir(iemufwdir); + } else { + fprintf(stderr, "Couldn't open firmware dir %s\n", fwpath); + } +} + +int iemu_fw_load(const char *device, const char *iemuVersion) +{ + char dflist[PATH_MAX]; + struct stat st; + + /* Find default device config */ + sprintf(dflist, "%s%s/config.xml", DEFAULT_DEVICE_PATH, device); + if(stat(dflist, &st) < 0) + return 0; + + iemu_parse_config(device, dflist); + + /* Check version */ + + return 1; +} + +int iemu_fw_init(const char *optarg, const char *device) +{ +/* + if(!iemu_fw_load(device, optarg)) + return -1; +*/ + return 0; +} + +static void parser_char_data (void *data, const XML_Char *s, int len) +{ + char *tmp; + int i, empty; + DevConfig *parserconfig = (DevConfig*)data; + + assert(tmp = (char *) malloc(len+1)); + strncpy(tmp, s, len); + tmp[len] = '\0'; + + for(i=0, empty=true; tmp[i]; i++) + { + if(!isspace(tmp[i])) + { + empty = false; + break; + } + } + + if(empty || !tagval) { + free(tmp); + return; + } + + if(value_is(tagval, "device")) + parserconfig->devname = strdup(tmp); + + if(value_is(tagval, "hwid")) + parserconfig->hwid = strdup(tmp); + + if(value_is(tagval, "skin")) { + sprintf(fwpath, "%s%s/%s", DEFAULT_DEVICE_PATH, parserconfig->devname, tmp); + parserconfig->skinfile = strdup(fwpath); + } + + if(value_is(tagval, "boot")) { + parserconfig->bootname = strdup(tmp); + if(value_is(tmp, "iboot")) { + parserconfig->boottype = BOOT_TYPE_IBOOT; + } + if(value_is(tmp, "openiboot")) { + parserconfig->boottype = BOOT_TYPE_OPENIBOOT; + } + if(value_is(tmp, "vrom")) { + parserconfig->boottype = BOOT_TYPE_VROM; + } + } + + if(value_is(tagval, "loadaddr")) + sscanf(tmp, "0x%08x", &parserconfig->loadaddr); + + free(tmp); + tagval = NULL; +} + +static void parser_start_hndl(void *data, const char *element, const char **attr) +{ + // make sure device is first tag + tagval = element; +} + +static void parser_end_hndl(void *data, const char *element) +{ + // if device but no data error +} + +static int iemu_parse_config(const char *deviceName, char *file) +{ + FILE* device_xml; + char buffer[BUFFER_SIZE]; + int done; + XML_Parser parser = XML_ParserCreate(NULL); + + assert(curdev = (DevConfig *) malloc(sizeof(DevConfig))); + + if (parser) { + curdev->devname = strdup(deviceName); + + XML_SetUserData(parser, (void*)curdev); + XML_SetCharacterDataHandler(parser, parser_char_data); + XML_SetElementHandler(parser, parser_start_hndl, parser_end_hndl); + + device_xml = fopen(file, "r"); + printf("device_xml: iemu_config_file = '%s'\n", file); + if (!device_xml) { + fprintf(stderr, "Error opening device config file '%s'\n", file); + XML_ParserFree(parser); + return -1; + } + + do { + if (fgets(buffer, sizeof(buffer), device_xml) == NULL) + done = 1; + else { + done = feof(device_xml); + if (!XML_Parse(parser, buffer, strlen(buffer), done)) { + fprintf(stderr, "Parse error at line %d: %s\n", + (int)XML_GetCurrentLineNumber(parser), + XML_ErrorString(XML_GetErrorCode(parser))); + // Continue anyway + } + } + } while (!done); + + if (done && !feof(device_xml)) { + fprintf(stderr, "Parse error, unexpected EOF\n"); + // Continue anyway + } + + XML_ParserFree(parser); + + fclose(device_xml); + printf("bootname = %s, loadaddr = 0x%08x\n", curdev->bootname, curdev->loadaddr); + return 0; + } + return -1; +} diff --git a/iemu.h b/iemu.h new file mode 100644 index 000000000..f42dbb92d --- /dev/null +++ b/iemu.h @@ -0,0 +1,15 @@ +#ifndef IOS_FW_H +#define IOS_FW_H + +typedef enum { + BOOT_TYPE_IBOOT = 1, + BOOT_TYPE_OPENIBOOT, + BOOT_TYPE_VROM +} boot_type; + +void iemu_fw_list(const char *device); +int iemu_fw_load(const char *deviceName, const char *iemuVersion); +int iemu_fw_init(const char *optarg, const char *device); +char *iemu_get_skin(void); + +#endif diff --git a/qemu-options.hx b/qemu-options.hx index 76cb4b41f..e264d10f7 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -760,6 +760,15 @@ Enable/disable audio stream compression (using celt 0.5.1). Default is on. @end table ETEXI +DEF("firmware", HAS_ARG, QEMU_OPTION_iosfirmware, + "-firmware iOS firmware version\n", + QEMU_ARCH_ARM) +STEXI +@item -firmware @var{firmware} +@findex -firmware +iOS firmware version +ETEXI + DEF("portrait", 0, QEMU_OPTION_portrait, "-portrait rotate graphical output 90 deg left (only PXA LCD)\n", QEMU_ARCH_ALL) diff --git a/skin/skin_config.c b/skin/skin_config.c index fdbb8b9e5..0dfc42f55 100644 --- a/skin/skin_config.c +++ b/skin/skin_config.c @@ -171,8 +171,8 @@ int skin_activate_layout(SkinScreen* skin, int rotation) if (layout->width == 0 || layout->height == 0) { // No value given in XML, use some default //printf("Default layout values\n"); - layout->width = 732; - layout->height = 392; + layout->width = 320; + layout->height = 480; } if (layout->emuscreen_width == 0 || layout->emuscreen_height == 0) { // No default value given, make it 800x480 then diff --git a/vl.c b/vl.c index 2a8b8b02b..75a3051fc 100644 --- a/vl.c +++ b/vl.c @@ -145,6 +145,8 @@ int main(int argc, char **argv) #include "qemu-config.h" #include "qemu-objects.h" #include "qemu-options.h" +#include "iemu.h" + #ifdef CONFIG_VIRTFS #include "fsdev/qemu-fsdev.h" #endif @@ -2200,12 +2202,26 @@ int main(int argc, char **argv, char **envp) exit(1); #endif break; + case QEMU_OPTION_iosfirmware: + if (*optarg == '?') { + iemu_fw_list(machine->name); + exit(0); + } else { + if(iemu_fw_init(optarg, machine->name) < 0) + { + fprintf(stderr, "Invalid firmware version %s for device %s\n", optarg, machine->name); + exit(0); + } + /* Load skin */ + skin_file = iemu_get_skin(); + } + break; case QEMU_OPTION_portrait: graphic_rotate = 1; break; - case QEMU_OPTION_landscape: - graphic_rotate = 0; - break; + case QEMU_OPTION_landscape: + graphic_rotate = 0; + break; case QEMU_OPTION_kernel: kernel_filename = optarg; break;