Modèle iPhone 3GS ios6-n88 et simulateur iOS 6 #7
No files matched your search
@@ -18,3 +18,8 @@ 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).
|
||||
|
||||
### iPhone 3GS sous iOS 6.1.6 (expérimental)
|
||||
|
||||
Modèle `ios6-n88` (`hw/arm/ios6_n88.c`) et outils de développement natif :
|
||||
voir [`ios6/README.md`](ios6/README.md), y compris la procédure macOS.
|
||||
@@ -0,0 +1,471 @@
|
||||
/*
|
||||
* Prototype de démarrage direct du noyau iOS 6 sur N88AP (S5L8920).
|
||||
* GPL-2.0-or-later. Les périphériques absents restent explicitement tracés.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/loader.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/arm/boot.h"
|
||||
#include "target/arm/cpu.h"
|
||||
#include "hw/arm/ipod_touch_uart.h"
|
||||
#include "hw/intc/pl192.h"
|
||||
#include "hw/irq.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "sysemu/reset.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "ui/console.h"
|
||||
|
||||
#define TYPE_IOS6_N88 MACHINE_TYPE_NAME("ios6-n88")
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(IOS6N88State, IOS6_N88)
|
||||
|
||||
struct IOS6N88State {
|
||||
MachineState parent;
|
||||
ARMCPU *cpu;
|
||||
MemoryRegion ram, vectors, io, rootdisk;
|
||||
bool rootfs;
|
||||
uint32_t ram_base;
|
||||
uint32_t entry;
|
||||
uint32_t clcd[0x3000 / 4], dsim[0x1000 / 4];
|
||||
uint32_t dart[2][0x1000 / 4];
|
||||
uint32_t dart_tables[2][16];
|
||||
unsigned dart_trace;
|
||||
unsigned display_trace;
|
||||
QemuConsole *console;
|
||||
struct {
|
||||
uint32_t regs[16];
|
||||
uint8_t fifo[256], devices[128][256], cursor[128];
|
||||
unsigned count, readpos, trace;
|
||||
qemu_irq irq;
|
||||
} i2c[2];
|
||||
unsigned unknown_reads, unknown_writes;
|
||||
PL192State *vic[3];
|
||||
QEMUTimer *timer;
|
||||
QEMUTimer *vblank_timer;
|
||||
qemu_irq timer_irq;
|
||||
qemu_irq display_irq;
|
||||
uint32_t timer_count, timer_control;
|
||||
};
|
||||
|
||||
static void n88_display_irq(IOS6N88State *s)
|
||||
{
|
||||
qemu_set_irq(s->display_irq, !!(s->clcd[8 / 4] & s->clcd[0xc / 4]));
|
||||
}
|
||||
|
||||
static void n88_vblank(void *opaque)
|
||||
{
|
||||
IOS6N88State *s = opaque;
|
||||
if (s->clcd[0x1b10 / 4] & 1) {
|
||||
s->clcd[0xc / 4] |= 1;
|
||||
n88_display_irq(s);
|
||||
}
|
||||
timer_mod(s->vblank_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 16666667);
|
||||
}
|
||||
|
||||
static void n88_timer_expired(void *opaque)
|
||||
{
|
||||
IOS6N88State *s = opaque;
|
||||
qemu_set_irq(s->timer_irq, 1);
|
||||
}
|
||||
|
||||
static void n88_timer_schedule(IOS6N88State *s)
|
||||
{
|
||||
timer_del(s->timer);
|
||||
if (s->timer_control & 1) {
|
||||
uint64_t ns = ((uint64_t)s->timer_count * 1000000000 + 23999999) / 24000000;
|
||||
timer_mod(s->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + MAX(ns, 1));
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t n88_io_read(void *opaque, hwaddr addr, unsigned size)
|
||||
{
|
||||
IOS6N88State *s = opaque;
|
||||
if (addr >= 0x05400000 && addr < 0x05403000) {
|
||||
uint32_t value = s->clcd[(addr - 0x05400000) / 4];
|
||||
if (addr != 0x05400410 && s->display_trace++ < 3000) {
|
||||
qemu_log_mask(LOG_UNIMP, "n88 clcd R %04x = %08x\n", (unsigned)(addr - 0x05400000), value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
if (addr >= 0x09000000 && addr < 0x09001000) {
|
||||
unsigned offset = addr - 0x09000000;
|
||||
uint32_t value = s->dsim[offset / 4];
|
||||
if (offset == 0) {
|
||||
value = 0x80100103;
|
||||
if (s->dsim[0x14 / 4] & 2) { value |= 0x230; }
|
||||
if (s->dsim[0x14 / 4] & 1) { value &= ~0x230; }
|
||||
if (s->dsim[8 / 4] & 0x80000000) { value |= 0x400; }
|
||||
}
|
||||
if (offset == 0x44) { value |= 0x500000; }
|
||||
if (s->display_trace++ < 3000) {
|
||||
qemu_log_mask(LOG_UNIMP, "n88 dsim R %04x = %08x\n", offset, value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
int bus = (addr & ~0xfffULL) == 0x03200000 ? 0 :
|
||||
(addr & ~0xfffULL) == 0x03400000 ? 1 : -1;
|
||||
if (bus >= 0 && (addr & 0xfff) < 0x40) {
|
||||
unsigned reg = (addr & 0xfff) / 4;
|
||||
uint32_t value = s->i2c[bus].regs[reg];
|
||||
if (reg == 8) { value = s->i2c[bus].fifo[s->i2c[bus].readpos++ % 256]; }
|
||||
if (s->i2c[bus].trace++ < 1000) {
|
||||
qemu_log_mask(LOG_UNIMP, "n88 i2c%d R %02x = %08x\n", bus, reg * 4, value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
/* Compteur libre 24 MHz, confirmé par le noyau et openiBoot S5L8920. */
|
||||
if (addr == 0x3f100200 || addr == 0x3f100204) {
|
||||
uint64_t ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
uint64_t ticks = (ns / 1000) * 24 + ((ns % 1000) * 24) / 1000;
|
||||
return addr == 0x3f100200 ? (uint32_t)ticks : ticks >> 32;
|
||||
}
|
||||
if (addr == 0x3f100208) { return s->timer_count; }
|
||||
if (addr == 0x3f100220) { return s->timer_control; }
|
||||
if (s->unknown_reads++ < 200) {
|
||||
qemu_log_mask(LOG_UNIMP, "n88: lecture MMIO non implémentée @0x%08" HWADDR_PRIx " taille %u\n",
|
||||
addr + 0x80000000, size);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void n88_io_write(void *opaque, hwaddr addr, uint64_t value, unsigned size)
|
||||
{
|
||||
IOS6N88State *s = opaque;
|
||||
if ((addr & ~0xfffULL) == 0x3fe00000 || (addr & ~0xfffULL) == 0x3ff00000) {
|
||||
unsigned index = (addr >> 20) & 1;
|
||||
unsigned offset = addr & 0xfff;
|
||||
s->dart[index][offset / 4] = value;
|
||||
if (offset == 8 && (value & 1)) {
|
||||
s->dart_tables[index][(value >> 8) & 15] = value & 0x0ffff000;
|
||||
}
|
||||
if (s->dart_trace++ < 300) {
|
||||
qemu_log_mask(LOG_UNIMP, "n88 dart%u W %04x = %08" PRIx64 "\n", index, offset, value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (addr >= 0x05400000 && addr < 0x05403000) {
|
||||
unsigned offset = addr - 0x05400000;
|
||||
uint32_t stored = value;
|
||||
if (offset == 0) { stored = (stored & ~0x100) | 2; }
|
||||
if (offset == 0xc || offset == 0x1b2c) { stored = s->clcd[offset / 4] & ~value; }
|
||||
if (offset == 0x1b10) { stored |= 2; }
|
||||
s->clcd[offset / 4] = stored;
|
||||
if (offset == 8 || offset == 0xc) { n88_display_irq(s); }
|
||||
if (offset != 0x408 && offset != 0x40c && s->display_trace++ < 3000) {
|
||||
qemu_log_mask(LOG_UNIMP, "n88 clcd W %04x = %08" PRIx64 "\n", offset, value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (addr >= 0x09000000 && addr < 0x09001000) {
|
||||
unsigned offset = addr - 0x09000000;
|
||||
if (offset == 0x2c) { s->dsim[offset / 4] &= ~value; }
|
||||
else { s->dsim[offset / 4] = value; }
|
||||
if (offset == 0x34) { s->dsim[0x2c / 4] |= 0x10000000; }
|
||||
if (s->display_trace++ < 3000) {
|
||||
qemu_log_mask(LOG_UNIMP, "n88 dsim W %04x = %08" PRIx64 "\n", offset, value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
int bus = (addr & ~0xfffULL) == 0x03200000 ? 0 :
|
||||
(addr & ~0xfffULL) == 0x03400000 ? 1 : -1;
|
||||
if (bus >= 0 && (addr & 0xfff) < 0x40) {
|
||||
unsigned reg = (addr & 0xfff) / 4;
|
||||
if (s->i2c[bus].trace++ < 1000) {
|
||||
qemu_log_mask(LOG_UNIMP, "n88 i2c%d W %02x = %08" PRIx64 "\n", bus, reg * 4, value);
|
||||
}
|
||||
if (reg == 3) {
|
||||
s->i2c[bus].regs[3] &= ~value;
|
||||
qemu_set_irq(s->i2c[bus].irq, !!s->i2c[bus].regs[3]);
|
||||
} else if (reg == 8) {
|
||||
s->i2c[bus].fifo[s->i2c[bus].count++ % 256] = value;
|
||||
} else {
|
||||
s->i2c[bus].regs[reg] = value;
|
||||
}
|
||||
if (reg == 9 && (value == 4 || value == 5)) {
|
||||
unsigned slave = s->i2c[bus].regs[0] & 127;
|
||||
unsigned count = MIN(s->i2c[bus].regs[6], 256);
|
||||
uint8_t *cursor = &s->i2c[bus].cursor[slave];
|
||||
*cursor = s->i2c[bus].regs[4];
|
||||
/* LIS302DL: bit 7 selects register auto-increment, not a bank. */
|
||||
if (bus == 0 && slave == 0x1d) {
|
||||
*cursor &= 0x7f;
|
||||
}
|
||||
if (value == 5 && s->i2c[bus].count) {
|
||||
for (unsigned i = 0; i < MIN(s->i2c[bus].count, 256); i++) {
|
||||
s->i2c[bus].devices[slave][(*cursor)++] = s->i2c[bus].fifo[i];
|
||||
}
|
||||
if (bus == 0 && slave == 0x1d) {
|
||||
/* CTRL_REG2 BOOT self-clears after loading calibration. */
|
||||
s->i2c[bus].devices[slave][0x21] &= ~0x40;
|
||||
}
|
||||
} else if (value == 4) {
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
s->i2c[bus].fifo[i] = s->i2c[bus].devices[slave][(*cursor)++];
|
||||
}
|
||||
}
|
||||
s->i2c[bus].count = s->i2c[bus].readpos = 0;
|
||||
s->i2c[bus].regs[3] = 0x10;
|
||||
qemu_set_irq(s->i2c[bus].irq, 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (addr == 0x3f100208) {
|
||||
s->timer_count = value;
|
||||
n88_timer_schedule(s);
|
||||
return;
|
||||
}
|
||||
if (addr == 0x3f100220) {
|
||||
s->timer_control = value;
|
||||
if (value & 2) { qemu_set_irq(s->timer_irq, 0); }
|
||||
n88_timer_schedule(s);
|
||||
return;
|
||||
}
|
||||
if (s->unknown_writes++ < 200) {
|
||||
qemu_log_mask(LOG_UNIMP, "n88: écriture MMIO non implémentée @0x%08" HWADDR_PRIx " = 0x%" PRIx64 "\n",
|
||||
addr + 0x80000000, value);
|
||||
}
|
||||
}
|
||||
|
||||
static const MemoryRegionOps n88_io_ops = {
|
||||
.read = n88_io_read,
|
||||
.write = n88_io_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.valid = { .min_access_size = 1, .max_access_size = 4 },
|
||||
};
|
||||
|
||||
/* Lecture DMA du LCD : RAM directe à l'amorçage, puis fenêtre legacy-DART. */
|
||||
static bool n88_display_read(IOS6N88State *s, uint32_t source, uint8_t *output, unsigned remaining)
|
||||
{
|
||||
uint8_t *ram = memory_region_get_ram_ptr(&s->ram);
|
||||
while (remaining) {
|
||||
uint32_t physical = source;
|
||||
unsigned count = MIN(remaining, 0x1000 - (source & 0xfff));
|
||||
if (source >= 0x3c000000 && source < 0x40000000) {
|
||||
/* 16 tables de 1024 PTE, pages de 4 Kio, adresses RAM 28 bits. */
|
||||
unsigned page = (source - 0x3c000000) >> 12;
|
||||
uint32_t table = s->dart_tables[0][page >> 10];
|
||||
if (!table || table > 0x10000000 - 0x1000) { return false; }
|
||||
uint32_t pte = ldl_le_p(ram + table + (page & 1023) * 4);
|
||||
if (!(pte & 1)) { return false; }
|
||||
physical = s->ram_base + (pte & 0x0ffff000) + (source & 0xfff);
|
||||
}
|
||||
if (physical < s->ram_base ||
|
||||
(uint64_t)physical + count > s->ram_base + 0x10000000ULL) { return false; }
|
||||
memcpy(output, ram + physical - s->ram_base, count);
|
||||
source += count;
|
||||
output += count;
|
||||
remaining -= count;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void n88_display_update(void *opaque)
|
||||
{
|
||||
IOS6N88State *s = opaque;
|
||||
DisplaySurface *surface = qemu_console_surface(s->console);
|
||||
for (unsigned row = 0; row < 480; row++) {
|
||||
memset(surface_data(surface) + row * surface_stride(surface), 0, 320 * 4);
|
||||
}
|
||||
/* Les deux fenêtres RGB utilisées par le pilote AppleM2CLCD : fond et UI. */
|
||||
for (unsigned plane = 0; plane < 2; plane++) {
|
||||
unsigned base = (0x20 + plane * 0x20) / 4;
|
||||
if (!(s->clcd[1] & (0x10 << plane))) { continue; }
|
||||
uint32_t control = s->clcd[base];
|
||||
unsigned format = (control >> 8) & 7;
|
||||
unsigned pixel_size = format == 7 ? 4 : format == 4 ? 2 : 0;
|
||||
if (!pixel_size) { continue; }
|
||||
unsigned x = s->clcd[base + 5] >> 16, y = s->clcd[base + 5] & 0xffff;
|
||||
if (x >= 320 || y >= 480) { continue; }
|
||||
unsigned width = MIN(s->clcd[base + 4] >> 16, 320 - x);
|
||||
unsigned height = MIN(s->clcd[base + 4] & 0xffff, 480 - y);
|
||||
unsigned pitch = s->clcd[base + 2];
|
||||
if (pitch < width || pitch > 4096) { continue; }
|
||||
for (unsigned row = 0; row < height; row++) {
|
||||
uint8_t line[320 * 4];
|
||||
uint64_t address = (uint64_t)s->clcd[base + 1] + row * pitch * pixel_size;
|
||||
if (address > UINT32_MAX || !n88_display_read(s, address, line, width * pixel_size)) { break; }
|
||||
uint32_t *output = (uint32_t *)(surface_data(surface) + (row + y) * surface_stride(surface)) + x;
|
||||
for (unsigned col = 0; col < width; col++) {
|
||||
uint32_t color;
|
||||
if (pixel_size == 2) {
|
||||
uint16_t pixel = lduw_le_p(line + col * 2);
|
||||
color = (((pixel >> 11) * 255 / 31) << 16) |
|
||||
((((pixel >> 5) & 63) * 255 / 63) << 8) | ((pixel & 31) * 255 / 31);
|
||||
} else {
|
||||
color = ldl_le_p(line + col * 4);
|
||||
}
|
||||
if (pixel_size == 4 && (control & 0x10000)) {
|
||||
unsigned inverse_alpha = 255 - (color >> 24);
|
||||
uint32_t blended = 0;
|
||||
for (unsigned shift = 0; shift < 24; shift += 8) {
|
||||
unsigned component = ((color >> shift) & 255) +
|
||||
(((output[col] >> shift) & 255) * inverse_alpha + 127) / 255;
|
||||
blended |= MIN(component, 255) << shift;
|
||||
}
|
||||
output[col] = blended;
|
||||
} else {
|
||||
output[col] = color & 0xffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dpy_gfx_update(s->console, 0, 0, 320, 480);
|
||||
}
|
||||
|
||||
static const GraphicHwOps n88_display_ops = {
|
||||
.gfx_update = n88_display_update,
|
||||
};
|
||||
|
||||
static void n88_reset(void *opaque)
|
||||
{
|
||||
IOS6N88State *s = opaque;
|
||||
cpu_reset(CPU(s->cpu));
|
||||
s->cpu->env.regs[0] = s->ram_base + 0x01000000;
|
||||
s->cpu->env.regs[1] = 0;
|
||||
cpu_set_pc(CPU(s->cpu), s->entry);
|
||||
s->unknown_reads = s->unknown_writes = s->display_trace = 0;
|
||||
for (unsigned i = 0; i < 2; i++) {
|
||||
memset(s->i2c[i].regs, 0, sizeof(s->i2c[i].regs));
|
||||
memset(s->i2c[i].devices, 0, sizeof(s->i2c[i].devices));
|
||||
memset(s->i2c[i].fifo, 0, sizeof(s->i2c[i].fifo));
|
||||
memset(s->i2c[i].cursor, 0, sizeof(s->i2c[i].cursor));
|
||||
s->i2c[i].count = s->i2c[i].readpos = s->i2c[i].trace = 0;
|
||||
qemu_set_irq(s->i2c[i].irq, 0);
|
||||
}
|
||||
s->i2c[0].devices[0x1d][0x0f] = 0x3b; /* LIS302DL WHO_AM_I */
|
||||
s->i2c[0].devices[0x1d][0x20] = 0x07; /* axes enabled, power-down */
|
||||
s->i2c[0].devices[0x1d][0x27] = 0x0f; /* stationary sample available */
|
||||
s->i2c[0].devices[0x1d][0x2d] = 56; /* approximately +1 g on Z */
|
||||
memset(s->clcd, 0, sizeof(s->clcd));
|
||||
memset(s->dsim, 0, sizeof(s->dsim));
|
||||
memset(s->dart, 0, sizeof(s->dart));
|
||||
memset(s->dart_tables, 0, sizeof(s->dart_tables));
|
||||
s->dart_trace = 0;
|
||||
s->clcd[0] = 0x20087;
|
||||
s->clcd[1] = 0x10;
|
||||
s->clcd[0x20 / 4] = 0x200700;
|
||||
s->clcd[0x24 / 4] = s->ram_base + 0x0f000000;
|
||||
s->clcd[0x28 / 4] = 320;
|
||||
s->clcd[0x30 / 4] = (320 << 16) | 480;
|
||||
s->clcd[0x1b10 / 4] = 3;
|
||||
s->clcd[0x1b24 / 4] = (319 << 16) | 479;
|
||||
timer_del(s->timer);
|
||||
s->timer_count = s->timer_control = 0;
|
||||
qemu_set_irq(s->timer_irq, 0);
|
||||
qemu_set_irq(s->display_irq, 0);
|
||||
timer_mod(s->vblank_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 16666667);
|
||||
}
|
||||
|
||||
static void n88_init(MachineState *machine)
|
||||
{
|
||||
IOS6N88State *s = IOS6_N88(machine);
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
Object *cpuobj = object_new(machine->cpu_type);
|
||||
s->ram_base = s->rootfs ? 0x70000000 : 0x40000000;
|
||||
s->cpu = ARM_CPU(cpuobj);
|
||||
object_property_set_bool(cpuobj, "has_el3", false, &error_fatal);
|
||||
object_property_set_link(cpuobj, "memory", OBJECT(sysmem), &error_fatal);
|
||||
qdev_realize(DEVICE(cpuobj), NULL, &error_fatal);
|
||||
memory_region_init_ram(&s->ram, NULL, "n88.ram", 0x10000000, &error_fatal);
|
||||
memory_region_add_subregion(sysmem, s->ram_base, &s->ram);
|
||||
/* Le bootstrap 10B500 installe ses vecteurs via un mapping de la page 0.
|
||||
* Modèle minimal de cette page, sans prétendre émuler la BootROM. */
|
||||
memory_region_init_ram(&s->vectors, NULL, "n88.vector-page", 0x1000, &error_fatal);
|
||||
memory_region_add_subregion(sysmem, 0, &s->vectors);
|
||||
memory_region_init_io(&s->io, OBJECT(machine), &n88_io_ops, s, "n88.unimplemented-io", 0x40000000);
|
||||
memory_region_add_subregion_overlap(sysmem, 0x80000000, &s->io, -10);
|
||||
for (unsigned i = 0; i < 3; i++) {
|
||||
char name[16];
|
||||
snprintf(name, sizeof(name), "n88.vic%u", i);
|
||||
DeviceState *dev;
|
||||
if (i == 0) {
|
||||
dev = pl192_manual_init(name,
|
||||
qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ),
|
||||
qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_FIQ), NULL);
|
||||
} else {
|
||||
dev = pl192_manual_init(name, NULL);
|
||||
}
|
||||
s->vic[i] = PL192(dev);
|
||||
if (i) { s->vic[i]->daisy = s->vic[i - 1]; }
|
||||
memory_region_add_subregion_overlap(sysmem, 0xbf200000 + 0x10000 * i,
|
||||
&s->vic[i]->iomem, 0);
|
||||
}
|
||||
s->i2c[0].irq = qdev_get_gpio_in(DEVICE(s->vic[0]), 19);
|
||||
s->i2c[1].irq = qdev_get_gpio_in(DEVICE(s->vic[0]), 17);
|
||||
s->timer_irq = qdev_get_gpio_in(DEVICE(s->vic[0]), 6);
|
||||
s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, n88_timer_expired, s);
|
||||
s->display_irq = qdev_get_gpio_in(DEVICE(s->vic[1]), 5); /* DeviceTree : IRQ 37. */
|
||||
s->vblank_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, n88_vblank, s);
|
||||
/* Le DeviceTree original désigne uart0 (0x82500000) comme boot-console. */
|
||||
ipod_touch_uart_create(0x82500000, serial_hd(0),
|
||||
qdev_get_gpio_in(DEVICE(s->vic[0]), 24));
|
||||
ipod_touch_uart_create(0x82600000, serial_hd(1),
|
||||
qdev_get_gpio_in(DEVICE(s->vic[0]), 23));
|
||||
if (!machine->kernel_filename || !machine->dtb) {
|
||||
error_report("ios6-n88 attend -kernel kernel.bin et -dtb boot-data.bin (tools/prepare_boot.py)");
|
||||
exit(1);
|
||||
}
|
||||
if (load_image_targphys(machine->kernel_filename, s->ram_base + 0x1000, 0x00fff000) < 0 ||
|
||||
load_image_targphys(machine->dtb, s->ram_base + 0x01000000, 0x01000000) < 0) {
|
||||
error_report("Chargement du noyau ou des paramètres impossible");
|
||||
exit(1);
|
||||
}
|
||||
if (s->rootfs) {
|
||||
int64_t size = machine->initrd_filename ? get_image_size(machine->initrd_filename) : -1;
|
||||
if (size <= 0 || size > 0x6ff00000 || size % 4096) {
|
||||
error_report("rootfs attend une image HFS alignée à 4096 octets, < 1791 Mio");
|
||||
exit(1);
|
||||
}
|
||||
/* MAP_PRIVATE : les écritures invitées ne modifient jamais l'image. */
|
||||
memory_region_init_ram_from_file(&s->rootdisk, NULL, "n88.rootdisk",
|
||||
size, 0, RAM_READONLY_FD, machine->initrd_filename, 0, &error_fatal);
|
||||
memory_region_add_subregion(sysmem, 0x00100000, &s->rootdisk);
|
||||
} else if (machine->initrd_filename &&
|
||||
load_image_targphys(machine->initrd_filename, 0x42000000, 0x02000000) < 0) {
|
||||
error_report("Chargement du disque de restauration impossible");
|
||||
exit(1);
|
||||
}
|
||||
/* Entrée LC_UNIXTHREAD vérifiée par prepare_boot.py pour 10B500/n88. */
|
||||
s->entry = s->ram_base + 0x86084;
|
||||
s->console = graphic_console_init(NULL, 0, &n88_display_ops, s);
|
||||
qemu_console_resize(s->console, 320, 480);
|
||||
qemu_register_reset(n88_reset, s);
|
||||
}
|
||||
|
||||
static bool n88_get_rootfs(Object *obj, Error **errp)
|
||||
{
|
||||
return IOS6_N88(obj)->rootfs;
|
||||
}
|
||||
|
||||
static void n88_set_rootfs(Object *obj, bool value, Error **errp)
|
||||
{
|
||||
IOS6_N88(obj)->rootfs = value;
|
||||
}
|
||||
|
||||
static void n88_class_init(ObjectClass *oc, void *data)
|
||||
{
|
||||
MachineClass *mc = MACHINE_CLASS(oc);
|
||||
mc->desc = "iPhone 3GS iOS 6: prototype de démarrage du noyau";
|
||||
mc->init = n88_init;
|
||||
mc->default_cpu_type = ARM_CPU_TYPE_NAME("cortex-a8");
|
||||
mc->default_ram_size = 0x10000000;
|
||||
mc->max_cpus = 1;
|
||||
object_class_property_add_bool(oc, "rootfs", n88_get_rootfs, n88_set_rootfs);
|
||||
}
|
||||
|
||||
static const TypeInfo n88_type = {
|
||||
.name = TYPE_IOS6_N88,
|
||||
.parent = TYPE_MACHINE,
|
||||
.instance_size = sizeof(IOS6N88State),
|
||||
.class_init = n88_class_init,
|
||||
};
|
||||
|
||||
static void n88_register(void)
|
||||
{
|
||||
type_register_static(&n88_type);
|
||||
}
|
||||
type_init(n88_register)
|
||||
@@ -73,3 +73,5 @@ system_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_peripherals.c'))
|
||||
system_ss.add(when: 'CONFIG_TOSA', if_true: files('tosa.c'))
|
||||
|
||||
hw_arch += {'arm': arm_ss}
|
||||
|
||||
arm_ss.add(when: 'CONFIG_IPOD_TOUCH_2G', if_true: files('ios6_n88.c'))
|
||||
@@ -0,0 +1,7 @@
|
||||
.venv/
|
||||
build/
|
||||
firmware/
|
||||
references/
|
||||
evidence/
|
||||
__pycache__/
|
||||
run/
|
||||
@@ -0,0 +1,39 @@
|
||||
# Émulateur iOS 6 pour le développement natif
|
||||
|
||||
Lire `README.md` pour la procédure complète et les limites. Le projet exécute
|
||||
iOS 6.1.6 (10B500) pour iPhone 3GS dans QEMU. Il sert aux agents à compiler,
|
||||
installer et tester des apps natives ARM32, via les commandes locales.
|
||||
L’utilisateur ne souhaite pas de panneau web de pilotage.
|
||||
|
||||
## Utilisation
|
||||
|
||||
- Travailler depuis `/home/dev/ios6-emu`. Vérifier `bin/ios6 status` et
|
||||
`bin/ios6 front` avant de modifier une session existante.
|
||||
- Démarrer avec `bin/ios6 start`, puis attendre avec `bin/ios6 wait`.
|
||||
- Compiler l’exemple : `.venv/bin/python tools/build_app.py`.
|
||||
- Installer : `bin/ios6 install build/apps/SimulatorLab.app`.
|
||||
L’installation sauvegarde le disque et redémarre la VM.
|
||||
- Lancer : `bin/ios6 launch org.ios6emu.SimulatorLab`.
|
||||
- Piloter avec `tap`, `swipe`, `home` ; observer avec `screenshot`, `logs`,
|
||||
`front`, `get` et `exec`. Consulter `bin/ios6 --help` pour les arguments.
|
||||
- Tester l’exemple installé : `.venv/bin/python tools/smoke_test.py`.
|
||||
Les rapports et captures sont conservés dans `run/reports/`.
|
||||
|
||||
## État partagé et conservation des données
|
||||
|
||||
La VM et son disque sont partagés par les sessions de cet environnement.
|
||||
Éviter les tests, installations et gestes concurrents : ils modifient le même
|
||||
état invité. Une session déjà démarrée peut être utilisée par une autre tâche.
|
||||
Pour arrêter en conservant les changements, utiliser `bin/ios6 stop`.
|
||||
Tuer QEMU ou utiliser `stop --discard` perd les changements non sauvegardés.
|
||||
Ne jamais modifier le disque hors ligne pendant que la VM tourne.
|
||||
Ne pas réinitialiser un disque existant dans le cadre d’un simple test d’app.
|
||||
L’émulateur iPhone OS 2 dans `/srv/homes/iphoneos2/ipod-emu` est indépendant.
|
||||
|
||||
## Portée des résultats
|
||||
|
||||
La chaîne a été validée avec l’app UIKit `SimulatorLab` : compilation,
|
||||
installation, lancement, gestes, fichiers, logs, HTTP vers l’hôte et persistance
|
||||
après redémarrage. GPU, audio, caméra, modem, GPS et stockage sécurisé matériel
|
||||
ne sont pas reproduits. La compatibilité de chaque nouvelle app doit être
|
||||
vérifiée ; ne pas présenter ces tests comme une validation sur iPhone physique.
|
||||
+377
@@ -0,0 +1,377 @@
|
||||
# Simulateur expérimental iOS 6 — développement natif
|
||||
|
||||
Le vrai **iOS 6.1.6 (10B500, iPhone 3GS)** tourne dans QEMU, avec SpringBoard,
|
||||
UIKit et un écran 320 × 480. On peut compiler une app Objective-C ARM32,
|
||||
l’installer, la lancer, envoyer des gestes et vérifier ses fichiers et ses logs.
|
||||
Cet outil est destiné au pilotage direct par l’agent de développement :
|
||||
commandes locales, captures du framebuffer réel et tests automatisés.
|
||||
|
||||
Il vit dans le dossier `ios6/` du fork `Mahtan/qemu-ios` ; le modèle de machine
|
||||
est `hw/arm/ios6_n88.c`, compilé avec le reste du dépôt. Sur le workbench, la
|
||||
copie de travail est le worktree `/home/dev/qemu-ios-ios6` (branche
|
||||
`agent/ios6-n88`), et `/home/dev/ios6-emu` pointe vers son dossier `ios6/`.
|
||||
|
||||
## Utiliser la session locale
|
||||
|
||||
```bash
|
||||
cd /home/dev/ios6-emu
|
||||
bin/ios6 start
|
||||
bin/ios6 wait
|
||||
```
|
||||
|
||||
L’agent utilise `bin/ios6` pour installer et lancer les apps, envoyer des gestes,
|
||||
inspecter leur état et récupérer les preuves de test. Les fonctions de
|
||||
`tools/simulator.py` sont aussi accessibles depuis les scripts Python.
|
||||
|
||||
```bash
|
||||
# Construire et installer l’exemple natif
|
||||
.venv/bin/python tools/build_app.py
|
||||
bin/ios6 install build/apps/SimulatorLab.app
|
||||
bin/ios6 launch org.ios6emu.SimulatorLab
|
||||
|
||||
# Piloter et observer
|
||||
bin/ios6 tap 160 296
|
||||
bin/ios6 swipe 160 400 160 140 --ms 600
|
||||
bin/ios6 front
|
||||
bin/ios6 screenshot run/capture.png
|
||||
bin/ios6 logs SimulatorLab
|
||||
bin/ios6 get /var/mobile/Library/Caches/SimulatorLab-result.txt run/result.txt
|
||||
bin/ios6 home
|
||||
|
||||
# Test automatisé de l’exemple installé
|
||||
.venv/bin/python tools/smoke_test.py
|
||||
|
||||
# Conserver les données et arrêter
|
||||
bin/ios6 stop
|
||||
```
|
||||
|
||||
`install` copie le bundle sous `/Applications/<identifiant>.app`, sauvegarde le
|
||||
disque et redémarre iOS pour enregistrer l’app. Prévoir quelques minutes.
|
||||
Les bundles acceptés contiennent un exécutable Mach-O ARM32 signé ad hoc ;
|
||||
les identifiants Apple et les liens symboliques sont refusés.
|
||||
Une mise à jour remplace les fichiers fournis ; les anciens fichiers supplémentaires
|
||||
restent présents. Les apps sont installées comme applications système de développement,
|
||||
pas dans un conteneur App Store : les tests d’isolation ne sont pas représentatifs.
|
||||
|
||||
**Persistance : utiliser `bin/ios6 stop`.** Le disque invité est en RAM ; cette
|
||||
commande synchronise, suspend la VM, extrait le volume et rejoue son journal HFS
|
||||
dans une nouvelle copie avant de remplacer `firmware/rootfs-dev.hfs`.
|
||||
Tuer QEMU perd les changements depuis la dernière sauvegarde.
|
||||
`stop --discard` abandonne explicitement ces changements.
|
||||
Ne jamais modifier hors ligne le disque d’une VM active.
|
||||
|
||||
Le test `smoke_test.py` contrôle SpringBoard, le lancement de l’app,
|
||||
la remise à zéro et trois incréments UIKit, le transfert binaire,
|
||||
un aller-retour HTTP vers l’hôte et les traces NSLog. Il conserve capture,
|
||||
logs et rapport dans `run/reports/`. Les preuves de validation sont dans
|
||||
[`results/20261003-native-apps`](results/20261003-native-apps).
|
||||
|
||||
## Sur macOS (non encore essayé)
|
||||
|
||||
Le disque et le noyau préparés ne sont pas dans Git : ce sont des fichiers Apple
|
||||
(1,8 Gio). Une archive prête est sur le NAS, dans le gestionnaire de fichiers UGOS :
|
||||
`data/workbench/home/ios6-emu-mac/ios6-emu-firmware.tar.zst` (930 Mio, SHA-256
|
||||
dans le fichier `.sha256` voisin). Elle contient `firmware/rootfs-dev.hfs`,
|
||||
`firmware/kernel-rootfs.bin` et `firmware/boot-display-rootfs.bin`, soit le
|
||||
nécessaire pour `bin/ios6 start`.
|
||||
|
||||
```bash
|
||||
brew install ninja pkgconf glib pixman libpng jpeg-turbo openssl@3 libslirp zstd
|
||||
git clone https://git.mahtan-melwasul.com/Mahtan/qemu-ios.git && cd qemu-ios/ios6
|
||||
shasum -a 256 -c ~/Downloads/ios6-emu-firmware.tar.zst.sha256 # depuis ~/Downloads
|
||||
zstd -dc ~/Downloads/ios6-emu-firmware.tar.zst | tar -xf -
|
||||
export PKG_CONFIG_PATH="$(brew --prefix openssl@3)/lib/pkgconfig:$PKG_CONFIG_PATH"
|
||||
bash tools/build.sh # compile ce dépôt QEMU dans ios6/build, puis netd
|
||||
bin/ios6 start && bin/ios6 wait
|
||||
.venv/bin/python tools/smoke_test.py
|
||||
```
|
||||
|
||||
L’affichage est accessible en VNC sur
|
||||
`127.0.0.1:5906` (Partage d’écran : `vnc://127.0.0.1:5906`).
|
||||
`bin/ios6 stop` sauvegarde le disque dans `firmware/rootfs-dev.hfs` du Mac ;
|
||||
il reste indépendant de celui du workbench.
|
||||
|
||||
Restent propres au workbench Linux : la préparation du disque
|
||||
(`prepare_rootfs.py`, `prepare_dev.py`, qui utilisent `ipod-emu`), la compilation de
|
||||
l’agent invité (`build_agent.sh`) et celle des apps (`build_app.py`), qui demandent
|
||||
`/opt/cctools` et les SDK locaux. Compiler les apps sur le workbench puis les copier
|
||||
sur le Mac pour `bin/ios6 install`.
|
||||
|
||||
## Préparer un autre projet natif
|
||||
|
||||
L’exemple est dans [`apps/SimulatorLab/main.m`](apps/SimulatorLab/main.m).
|
||||
Le petit script de compilation assemble les fichiers `.m` à la racine d’un projet,
|
||||
crée son Info.plist et signe son exécutable avec `ldid` :
|
||||
|
||||
```bash
|
||||
.venv/bin/python tools/build_app.py apps/MonApp --bundle-id org.exemple.MonApp
|
||||
bin/ios6 install build/apps/MonApp.app
|
||||
bin/ios6 launch org.exemple.MonApp
|
||||
```
|
||||
|
||||
Le SDK iOS 6.0 est local sous `references/sdk/iPhoneOS6.0.sdk`. Le script
|
||||
`tools/prepare_sdk.py` récupère les trois archives du dépôt
|
||||
[Sn0wCooder/theos-sdks](https://github.com/Sn0wCooder/theos-sdks/tree/3111c86f53b021dabee781aec3fb2d9fb8f3f862/iPhoneOS6.0.sdk),
|
||||
à une révision fixe, et vérifie le SHA-256 de l’archive assemblée.
|
||||
Un SDK existant peut être choisi avec `--sdk` ou `IOS6_SDK`.
|
||||
La compilation utilise le cross-compilateur `/opt/cctools/bin/arm-apple-darwin9-gcc`
|
||||
et `ldid` déjà présents dans cet environnement. Ce script est un point de départ
|
||||
pour les projets Objective-C simples ; il ne gère pas les projets Xcode,
|
||||
les storyboards ou la copie des ressources. Pas de prise en charge Swift.
|
||||
|
||||
Pour préparer un disque de développement après la préparation du firmware
|
||||
et du profil complet décrite plus bas :
|
||||
|
||||
```bash
|
||||
python3 tools/prepare_boot.py --profile display --rootfs --software-rendering
|
||||
bash tools/build.sh
|
||||
python3 tools/prepare_dev.py
|
||||
python3 tools/prepare_sdk.py
|
||||
```
|
||||
|
||||
`prepare_dev.py` conserve le disque de démonstration et ajoute l’agent au nouveau
|
||||
`rootfs-dev.hfs`. Il exige `--reset` pour remplacer un disque de développement
|
||||
existant et refuse d’opérer sur une VM active. L’agent est compilé avec le SDK
|
||||
2.2.1 local pour ses API C communes ; les apps utilisent le SDK 6.0.
|
||||
Le relais hôte nécessite les en-têtes et la bibliothèque `libslirp` via pkg-config.
|
||||
|
||||
## Réseau et automatisation
|
||||
|
||||
UART1 (`0x82600000`, IRQ 23, `/dev/tty.debug`) transporte PPP en mode PIO.
|
||||
L’agent publie la configuration réseau dans configd. L’invité utilise
|
||||
`10.0.2.15`, la passerelle hôte `10.0.2.2` et le relais DNS `10.0.2.3`.
|
||||
Un serveur HTTP local peut donc être testé depuis une app via `http://10.0.2.2:PORT`.
|
||||
Les anciens protocoles TLS d’iOS 6 peuvent être incompatibles avec les services modernes.
|
||||
|
||||
L’agent root est accessible sur **127.0.0.1:7796**
|
||||
et l’affichage VNC sur **127.0.0.1:5906**. Le tactile passe par GraphicsServices,
|
||||
pas par VNC. Ces interfaces de développement restent liées à la boucle locale.
|
||||
`bin/ios6 exec /chemin/programme arguments` lance un processus invité et transmet
|
||||
son code de sortie ; `put fichier-local /chemin/invité` et `get` transfèrent les fichiers.
|
||||
Les journaux de session et les PID sont sous `run/`.
|
||||
L’autorisation `com.apple.springboard.launchapplications` de l’agent permet
|
||||
le lancement avec `SBSLaunchApplicationWithIdentifier`.
|
||||
|
||||
## Portée et limites
|
||||
|
||||
La chaîne a été validée avec l’app UIKit fournie. La compatibilité de chaque
|
||||
nouvelle app reste à tester. Le GPU, l’audio, la caméra, le modem, le GPS et
|
||||
le stockage sécurisé matériel ne sont pas reproduits. L’accéléromètre est fixe.
|
||||
Il n’y a pas encore de saisie directe au clavier hôte, de multitouch,
|
||||
de débogueur source intégré, ni d’installation IPA/App Store.
|
||||
Ce prototype permet des tests fonctionnels ; ses performances et son matériel
|
||||
ne représentent pas fidèlement un iPhone physique.
|
||||
|
||||

|
||||
|
||||
## Historique du démarrage système
|
||||
|
||||
Le premier écran d’accueil a été reproduit depuis le firmware original en
|
||||
approximativement 220 secondes, puis vers 115 secondes depuis un volume initialisé.
|
||||
Les captures proviennent du framebuffer invité.
|
||||
|
||||

|
||||
|
||||
Deux profils permettent de distinguer les résultats :
|
||||
|
||||
- Le profil initial exécute le noyau sans patch, avec le disque de restauration.
|
||||
Il reste conservé comme référence et bloque sur le coprocesseur ARM7M.
|
||||
- Le profil expérimental `display --rootfs` charge le système complet, omet
|
||||
les dépendances audio/IOP et la boussole, et adapte le memdev au stockage physique. Il emploie
|
||||
quatre modifications d'opcodes documentées dans `prepare_boot.py` (deux pour
|
||||
le disque, deux pour borner l'attente de l'horloge), avec vérification des
|
||||
octets originaux. Le DeviceTree désactive le protocole NAND `secure-root-prefix`
|
||||
selon le chemin prévu par AppleARMPE et renseigne le panneau Pinot.
|
||||
|
||||
L'horloge, le PMU et le panneau LCD sont reconnus grâce aux modèles expérimentaux
|
||||
I²C/CLCD/DSIM. La sortie graphique traduit les tables legacy-DART remplies
|
||||
par AppleH2PDART et émet l'interruption LCD 37 à 60 Hz.
|
||||
Ces modèles sont partiels : ils ne constituent pas une émulation
|
||||
fidèle du matériel, ni du GPU. Un trousseau temporaire en RAM est accepté par
|
||||
AppleKeyStore ; le stockage sécurisé matériel reste absent.
|
||||
|
||||
iBoot et la BootROM ne sont pas exécutés : le noyau est lancé directement.
|
||||
Le texte « iBoot version » vient d'une propriété du DeviceTree.
|
||||
|
||||
### Essai du système complet
|
||||
|
||||
```bash
|
||||
python3 tools/prepare_rootfs.py # recrée uniquement la copie rootfs-vm.hfs
|
||||
python3 tools/prepare_boot.py --profile display --rootfs --software-rendering
|
||||
bash tools/build.sh
|
||||
python3 tools/probe.py --seconds 300 --boot-data boot-display-rootfs.bin \
|
||||
--rootfs --capture-interval 10 --dump-disk
|
||||
```
|
||||
|
||||
Le disque original reste dans `firmware/rootfs.hfs`. Sa copie expérimentale
|
||||
`rootfs-vm.hfs` est agrandie à 1776 Mio et reçoit un `fstab` pour `/dev/md0`,
|
||||
la journalisation ASL. `--software-rendering` omet le GPU SGX du DeviceTree.
|
||||
Les variables `CA_NO_ACCEL=1`, `CA_ENABLE_OGL=0` sont également transmises
|
||||
aux processus graphiques. Le paramètre `launchctl_enforce_codesign=0`, lu
|
||||
par le `launchctl` original, permet le chargement des plists locales au lieu
|
||||
des configurations précompilées du cache xpcd. Leur prise en compte a été
|
||||
vérifiée dans l'environnement des processus invités.
|
||||
Le programme expérimental `src/keybag_init.c`, installé comme `ios6-session`,
|
||||
initialise un trousseau de session sans clé matérielle, via les fonctions Apple
|
||||
du cache 10B500. Le démon `keybagd` original est conservé et son job est écarté.
|
||||
Le service de session n'enregistre pas son port IPC : les clients n'attendent
|
||||
donc pas une réponse d'un serveur absent. Le profil ajoute
|
||||
`amfi_allow_any_signature=1` pour exécuter cet outil local.
|
||||
Le service vérifie l'absence de code de verrouillage avant d'envoyer le geste
|
||||
initial. Il réveille ensuite régulièrement l'écran pendant six minutes pour
|
||||
la démonstration, puis cesse toute entrée automatique.
|
||||
Le bundle `CommCenterMigrator.migrator` est conservé dans
|
||||
`/System/Library/EmulatorDisabledMigrators` : la migration cellulaire attendait
|
||||
indéfiniment le modem absent. Les autres migrations Apple restent exécutées.
|
||||
Les capacités cellulaires de `N88AP.plist` sont désactivées pour éviter
|
||||
les fonctions liées au modem. Cela ne suffit pas à supprimer les appels
|
||||
CoreTelephony de SpringBoard : les jobs `CommCenter*` sont aussi conservés
|
||||
hors de `LaunchDaemons`, dans `EmulatorDisabledDaemons`.
|
||||
Le job `mediaserverd` est également écarté, l'audio n'étant pas émulé.
|
||||
Les tables de polices Apple U/UR remplacent les tables H/HR qui désignent
|
||||
des fichiers absents de ce firmware. Le modèle LIS302DL acquitte son reset
|
||||
et fournit une accélération verticale fixe. Le bundle `Setup.app` est conservé
|
||||
dans `EmulatorDisabledApplications`, hors du répertoire des applications :
|
||||
l'assistant exige des services d'activation absents de cette VM.
|
||||
L'état d'activation n'est pas modifié.
|
||||
La sonde `probe.py` utilise un mapping privé : les écritures invitées disparaissent à l'arrêt,
|
||||
sauf si `--dump-disk` conserve un instantané `guest-disk.hfs` dans les preuves.
|
||||
|
||||
`--diagnostic-panic` provoque volontairement une panique à la fin d'un essai
|
||||
pour relever les processus et piles. Le journal précédant cette intervention
|
||||
est sauvegardé séparément ; ce diagnostic ne compte pas comme une panique
|
||||
spontanée. La sonde conserve aussi `screen.ppm`, sans modifier ses pixels.
|
||||
`--capture-interval 30` ajoute des captures pendant le démarrage ; `--dump-ram`
|
||||
conserve les 256 Mio de RAM. Un essai est borné à 300 secondes au maximum.
|
||||
`python3 tools/verify.py --rootfs` vérifie les artefacts et le plan mémoire ;
|
||||
`python3 tools/verify_display.py` teste séparément le périphérique graphique
|
||||
avec des pixels synthétiques, sans démarrer iOS.
|
||||
|
||||
Un premier démarrage a terminé les migrations Apple sur le volume agrandi.
|
||||
Son instantané local est conservé dans `firmware/rootfs-initialized.hfs` ;
|
||||
son journal HFS est encore actif. Les modifications hors ligne de cet
|
||||
instantané ont produit des erreurs de lecture au démarrage suivant.
|
||||
`tools/recover_hfs.py source.hfs nouvelle-copie.hfs` vérifie et rejoue ses
|
||||
transactions dans une nouvelle copie avant toute modification hors ligne.
|
||||
Il contrôle les sommes de contrôle du journal et des blocs ; il ne remplace
|
||||
pas une vérification complète du système de fichiers. Le premier essai de
|
||||
cette récupération a permis de reprendre l'état initialisé et de modifier
|
||||
les configurations sans reproduire l'erreur de lecture du profil.
|
||||
`prepare_rootfs.py` repart toujours du firmware original et réinitialise cette
|
||||
copie de travail. Le fichier `evidence/initialized-rootfs.json` trace l'instantané.
|
||||
|
||||
## Reproduire dans cet environnement
|
||||
|
||||
Les commandes se lancent depuis `ios6/` (`/home/dev/ios6-emu` sur le workbench).
|
||||
L'émulateur iPhone OS 2 et sa session sous `/srv/homes/iphoneos2/ipod-emu`
|
||||
ne sont pas modifiés.
|
||||
|
||||
```bash
|
||||
cd /home/dev/ios6-emu
|
||||
python3 tools/verify.py
|
||||
python3 tools/probe.py --seconds 10 --trace \
|
||||
--expect-panic 'ARM7M not stopped for some reason'
|
||||
```
|
||||
|
||||
La sonde crée un nouveau dossier `evidence/probe-<date>/` par essai, conserve
|
||||
`serial.log`, `qemu.log`, `stderr.log`, la commande et les registres dans
|
||||
`result.json`, puis arrête uniquement la VM qu'elle a lancée. Elle utilise un
|
||||
socket QMP privé, sans ouvrir de port TCP. La durée est bornée à 300 secondes et
|
||||
la trace à environ 32 Mio (contrôle toutes les 50 ms).
|
||||
|
||||
Sans `--expect-panic`, une panique invitée produit le code de sortie **2**.
|
||||
Avec cette option, le code **0** signifie que le blocage attendu a été retrouvé,
|
||||
pas que le système a fini de démarrer. `guest_status` et `milestones` décrivent
|
||||
séparément les progrès observés.
|
||||
|
||||
Une trace ciblée est possible :
|
||||
|
||||
```bash
|
||||
python3 tools/probe.py --seconds 5 \
|
||||
--trace-range 0x8065f600..0x8065f800 \
|
||||
--expect-panic 'ARM7M not stopped for some reason'
|
||||
.venv/bin/python tools/kernel_address.py 0x8065f7c0
|
||||
```
|
||||
|
||||
## Préparation et compilation
|
||||
|
||||
Les fichiers Apple, les téléchargements de référence, l'environnement Python
|
||||
et les sorties de compilation restent locaux et sont exclus de Git.
|
||||
|
||||
```bash
|
||||
cd /home/dev/ios6-emu
|
||||
python3 tools/prepare_firmware.py
|
||||
python3 tools/prepare_boot.py
|
||||
bash tools/build.sh
|
||||
python3 tools/verify.py
|
||||
```
|
||||
|
||||
`prepare_firmware.py` récupère l'IPSW directement chez Apple, vérifie son SHA-256,
|
||||
extrait les conteneurs IMG3 avec OpenSSL et vérifie la taille et l'Adler32 du
|
||||
noyau LZSS. Le dernier bloc AES doit être lu avec le padding du tag IMG3 :
|
||||
l'ancien `xpwntool` disponible ici tronquait 45 octets à la décompression.
|
||||
|
||||
`tools/build.sh` configure le dépôt parent dans `ios6/build` (cible
|
||||
`arm-softmmu` seule) : il ne touche pas au `build/` de l'émulateur 2.2.1.
|
||||
Le modèle **`hw/arm/ios6_n88.c`** est déclaré dans `hw/arm/meson.build`
|
||||
sous `CONFIG_IPOD_TOUCH_2G` ; le binaire contient donc aussi la machine iPod.
|
||||
|
||||
Dépendances de compilation : GCC, Git, Ninja, pkg-config, Python avec venv,
|
||||
en-têtes GLib/Pixman/OpenSSL et dépendances habituelles de ce fork QEMU.
|
||||
Les paquets Python sont isolés dans `.venv`. L'image du workbench ne fournit
|
||||
pas encore Ninja, pkgconf, diffutils ni les bibliothèques d'exécution
|
||||
(pixman, libpng, libjpeg-turbo, alsa-lib, libslirp) : les installer avec
|
||||
`sudo pacman -S` après chaque redémarrage du conteneur.
|
||||
|
||||
## Matériel et chargement réalisés
|
||||
|
||||
| Élément | Modèle actuel |
|
||||
|---|---|
|
||||
| CPU | Cortex-A8 ARMv7 de QEMU, un cœur |
|
||||
| RAM | 256 Mio physiques à `0x40000000`, dont 240 Mio annoncés utilisables |
|
||||
| Vecteurs | Page de RAM expérimentale à l'adresse physique zéro |
|
||||
| Console | UART Samsung à `0x82500000`, réutilisée du fork iPod |
|
||||
| Interruptions | Trois PL192 à `0xbf200000`, `0xbf210000`, `0xbf220000` |
|
||||
| Temps | Compteur 24 MHz à `0xbf100200/204` ; timer one-shot `208/220`, ligne VIC 6 |
|
||||
| Noyau | Segments Mach-O chargés à partir de `0x40001000`, entrée `0x40086084` |
|
||||
| Paramètres | `boot_args` à `0x41000000`, format Version **5** requis par 10B500 |
|
||||
| DeviceTree | À `0x41004000`, issu du firmware et complété comme par un chargeur |
|
||||
| RAMDisk | Disque de restauration Apple à `0x42000000` |
|
||||
| Autres MMIO | Réponses nulles et traces bornées ; périphériques **non émulés** |
|
||||
|
||||
Le profil `rootfs` relocalise la RAM à `0x70000000`, les paramètres à
|
||||
`0x71000000` et la VRAM à `0x7f000000`. Son disque de 1776 Mio commence à
|
||||
`0x00100000` et ne chevauche pas la RAM ni les MMIO.
|
||||
|
||||
Le compteur et le timer sont des modèles minimaux validés pour ce démarrage,
|
||||
pas une implémentation exhaustive du contrôleur S5L8920. La page de vecteurs
|
||||
est également un aménagement de démarrage direct, à préciser avant de viser
|
||||
une émulation fidèle de la chaîne de boot.
|
||||
|
||||
Le DeviceTree reçoit les fréquences CPU, la mémoire, la console et les régions
|
||||
réservées `pram`/`vram`, ainsi qu'une partition NVRAM `common` vide et valide.
|
||||
Les placeholders NVRAM nuls du firmware entraînaient une boucle infinie dans
|
||||
IODTNVRAM. La graine aléatoire fixe est réservée à ces essais reproductibles.
|
||||
Dans le profil initial, le code du noyau n'est jamais réécrit ; `verify.py` compare chaque segment et
|
||||
vérifie la mise à zéro du BSS ainsi que les limites des allocations.
|
||||
|
||||
## Preuves du premier démarrage
|
||||
|
||||
Le dossier [`results/20261003-springboard`](results/20261003-springboard) conserve
|
||||
la capture de l'écran d'accueil. Le dossier
|
||||
[`results/20261003-first-boot`](results/20261003-first-boot) conserve
|
||||
le rapport de validation, les empreintes des composants et le journal série
|
||||
(aux retours de ligne normalisés ; original brut dans `evidence/`).
|
||||
Deux essais avec la NVRAM corrigée ont reproduit le blocage ARM7M. La trace
|
||||
du dernier essai contient des FIQ et IRQ réellement prises par le processeur.
|
||||
|
||||
Ces preuves concernent le premier jalon, antérieur au démarrage de `launchd`.
|
||||
Les essais plus récents et leurs instantanés se trouvent dans `evidence/`.
|
||||
Les adresses et les symboles se contrôlent avec `kernel_address.py`,
|
||||
`kext_info.py` et `cache_address.py` (cache dyld avec glissement explicite).
|
||||
|
||||
Références : [QEMU-iOS](https://github.com/devos50/qemu-ios),
|
||||
[openiBoot S5L8920](https://github.com/iDroid-Project/openiBoot/tree/master/plat-s5l8920),
|
||||
[structure boot_args Apple](https://github.com/apple-oss-distributions/xnu/blob/main/pexpert/pexpert/arm/boot.h),
|
||||
[IODTNVRAM Apple](https://github.com/apple-oss-distributions/xnu/blob/xnu-2050.48.11/iokit/Kernel/IONVRAM.cpp).
|
||||
Les adresses sont recoupées avec le DeviceTree et le noyau exacts du firmware.
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0"><dict>
|
||||
<key>com.apple.springboard.launchapplications</key><true/>
|
||||
<key>com.apple.backboardd.launchapplications</key><true/>
|
||||
</dict></plist>
|
||||
@@ -0,0 +1,942 @@
|
||||
/*
|
||||
* Agent de développement iOS 6, lancé par launchd en root.
|
||||
* Adapté de l'agent local de l'émulateur iPhone OS 2.
|
||||
*
|
||||
* 1. Réseau : lance pppd sur l'UART1 (/dev/tty.debug, reliée à ios6-netd côté hôte) et publie le lien dans le
|
||||
* SCDynamicStore de configd (IPv4, routeur, DNS), pour qu'iOS le considère comme le réseau actif.
|
||||
* 2. Pilotage : serveur TCP sur le port 7788 (redirigé vers 127.0.0.1:7796 sur l'hôte).
|
||||
*
|
||||
* Protocole : une requête = une ligne, champs séparés par des tabulations. Réponse : "OK <n> [info]\n" ou
|
||||
* "ERR <n>\n", suivi de n octets. Pour "put", n octets de contenu suivent la ligne de requête.
|
||||
*/
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
/* SCDynamicStore est dans SystemConfiguration.framework mais marqué indisponible dans les en-têtes iPhone */
|
||||
typedef const struct __SCDynamicStore *SCDynamicStoreRef;
|
||||
extern SCDynamicStoreRef SCDynamicStoreCreate(CFAllocatorRef, CFStringRef, void *, void *);
|
||||
extern Boolean SCDynamicStoreSetValue(SCDynamicStoreRef, CFStringRef, CFPropertyListRef);
|
||||
extern CFPropertyListRef SCDynamicStoreCopyValue(SCDynamicStoreRef, CFStringRef);
|
||||
extern CFArrayRef SCDynamicStoreCopyKeyList(SCDynamicStoreRef, CFStringRef);
|
||||
#include <arpa/inet.h>
|
||||
#include <dirent.h>
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <net/if.h>
|
||||
/* net/route.h absent du SDK iPhone : structures du socket de routage de XNU 1228 (Darwin 9) */
|
||||
struct rt_metrics {
|
||||
u_int32_t rmx_locks, rmx_mtu, rmx_hopcount;
|
||||
int32_t rmx_expire;
|
||||
u_int32_t rmx_recvpipe, rmx_sendpipe, rmx_ssthresh, rmx_rtt, rmx_rttvar, rmx_pksent;
|
||||
u_int32_t rmx_filler[4];
|
||||
};
|
||||
struct rt_msghdr {
|
||||
u_short rtm_msglen;
|
||||
u_char rtm_version, rtm_type;
|
||||
u_short rtm_index;
|
||||
int rtm_flags, rtm_addrs;
|
||||
pid_t rtm_pid;
|
||||
int rtm_seq, rtm_errno, rtm_use;
|
||||
u_int32_t rtm_inits;
|
||||
struct rt_metrics rtm_rmx;
|
||||
};
|
||||
#define RTM_VERSION 5
|
||||
#define RTM_ADD 0x1
|
||||
#define RTM_CHANGE 0x3
|
||||
#define NET_RT_DUMP 1
|
||||
#define RTF_UP 0x1
|
||||
#define RTF_GATEWAY 0x2
|
||||
#define RTF_STATIC 0x800
|
||||
#define RTA_DST 0x1
|
||||
#define RTA_GATEWAY 0x2
|
||||
#define RTA_NETMASK 0x4
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <signal.h>
|
||||
#include <spawn.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
#include <termios.h>
|
||||
#include <notify.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define VERSION "ios6-1"
|
||||
#define PORT 7788
|
||||
#define PPP_TTY "/dev/tty.debug"
|
||||
#define GUEST_IP "10.0.2.15"
|
||||
#define GW_IP "10.0.2.2"
|
||||
#define DNS_IP "10.0.2.3"
|
||||
#define SERVICE_ID "emuppp" /* pppd publie son état sous State:/Network/Service/<id> */
|
||||
|
||||
extern char **environ;
|
||||
static FILE *con;
|
||||
static pid_t pppd_pid;
|
||||
static SCDynamicStoreRef store;
|
||||
static int net_published;
|
||||
|
||||
static void clog_(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
if (!con) return;
|
||||
fputs("emuagent: ", con);
|
||||
va_start(ap, fmt);
|
||||
vfprintf(con, fmt, ap);
|
||||
va_end(ap);
|
||||
fputc('\n', con);
|
||||
}
|
||||
|
||||
#include "../src/session_input.h"
|
||||
|
||||
/* ---------- réseau ---------- */
|
||||
|
||||
static void start_pppd(void)
|
||||
{
|
||||
char *argv[] = { "/usr/sbin/pppd", PPP_TTY, "115200", "local", "nocrtscts", "noauth", "nodetach",
|
||||
"persist", "maxfail", "0", "holdoff", "2", "defaultroute", "noipdefault",
|
||||
"ipcp-accept-local", "ipcp-accept-remote", "usepeerdns", "novj", "noccp",
|
||||
"lcp-echo-interval", "0", "mtu", "1500", "mru", "1500", "serviceid", SERVICE_ID, NULL };
|
||||
posix_spawn_file_actions_t fa;
|
||||
posix_spawn_file_actions_init(&fa);
|
||||
posix_spawn_file_actions_addopen(&fa, 0, "/dev/null", O_RDONLY, 0);
|
||||
posix_spawn_file_actions_addopen(&fa, 1, "/dev/console", O_WRONLY, 0);
|
||||
posix_spawn_file_actions_addopen(&fa, 2, "/dev/console", O_WRONLY, 0);
|
||||
if (posix_spawn(&pppd_pid, argv[0], &fa, NULL, argv, environ) != 0) {
|
||||
clog_("pppd : échec du lancement (%s)", strerror(errno));
|
||||
pppd_pid = 0;
|
||||
} else {
|
||||
clog_("pppd lancé (pid %d) sur %s", pppd_pid, PPP_TTY);
|
||||
}
|
||||
posix_spawn_file_actions_destroy(&fa);
|
||||
}
|
||||
|
||||
static int ppp_up(char *ifname, size_t len)
|
||||
{
|
||||
struct ifaddrs *ifa, *i;
|
||||
int up = 0;
|
||||
if (getifaddrs(&ifa)) return 0;
|
||||
for (i = ifa; i; i = i->ifa_next) {
|
||||
if (!strncmp(i->ifa_name, "ppp", 3) && i->ifa_addr && i->ifa_addr->sa_family == AF_INET && (i->ifa_flags & IFF_UP)) {
|
||||
strncpy(ifname, i->ifa_name, len);
|
||||
up = 1;
|
||||
}
|
||||
}
|
||||
freeifaddrs(ifa);
|
||||
return up;
|
||||
}
|
||||
|
||||
static CFArrayRef str_array(const char *s)
|
||||
{
|
||||
CFStringRef v = CFStringCreateWithCString(NULL, s, kCFStringEncodingUTF8);
|
||||
CFArrayRef a = CFArrayCreate(NULL, (const void **)&v, 1, &kCFTypeArrayCallBacks);
|
||||
CFRelease(v);
|
||||
return a;
|
||||
}
|
||||
|
||||
static void set_key(CFStringRef key, CFDictionaryRef val)
|
||||
{
|
||||
if (!SCDynamicStoreSetValue(store, key, val)) clog_("SCDynamicStoreSetValue a échoué");
|
||||
}
|
||||
|
||||
/* Route par défaut via la passerelle PPP (RTM_ADD sur le socket de routage, comme route add default) */
|
||||
static int route_msg(int type)
|
||||
{
|
||||
struct {
|
||||
struct rt_msghdr h;
|
||||
struct sockaddr_in dst, gw, mask;
|
||||
} m;
|
||||
memset(&m, 0, sizeof m);
|
||||
m.h.rtm_msglen = sizeof m;
|
||||
m.h.rtm_version = RTM_VERSION;
|
||||
m.h.rtm_type = type;
|
||||
m.h.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
|
||||
m.h.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
|
||||
m.h.rtm_pid = getpid();
|
||||
m.h.rtm_seq = 1;
|
||||
m.dst.sin_len = m.gw.sin_len = m.mask.sin_len = sizeof(struct sockaddr_in);
|
||||
m.dst.sin_family = m.gw.sin_family = m.mask.sin_family = AF_INET;
|
||||
inet_aton(GW_IP, &m.gw.sin_addr);
|
||||
int s = socket(PF_ROUTE, SOCK_RAW, 0);
|
||||
if (s < 0) return -1;
|
||||
int r = write(s, &m, sizeof m) == sizeof m ? 0 : -1;
|
||||
int e = errno;
|
||||
close(s);
|
||||
errno = e;
|
||||
return r;
|
||||
}
|
||||
|
||||
static int add_default_route(void)
|
||||
{
|
||||
if (route_msg(RTM_ADD) == 0) return 0;
|
||||
if (errno == EEXIST && route_msg(RTM_CHANGE) == 0) return 0; /* une route par défaut existait déjà */
|
||||
clog_("route par défaut : %s", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
static CFMutableDictionaryRef dict(void)
|
||||
{
|
||||
return CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
}
|
||||
|
||||
/*
|
||||
* Déclare le service PPP côté Setup: (ce que contiendrait preferences.plist pour un service configuré) : sans cela,
|
||||
* IPMonitor ignore l'état publié par pppd et n'installe ni la route par défaut ni le DNS global.
|
||||
*/
|
||||
static void publish_setup(void)
|
||||
{
|
||||
if (!store) store = SCDynamicStoreCreate(NULL, CFSTR("emuagent"), NULL, NULL);
|
||||
if (!store) { clog_("SCDynamicStoreCreate a échoué"); return; }
|
||||
|
||||
CFMutableDictionaryRef svc = dict(), itf = dict(), ipv4 = dict(), glob = dict();
|
||||
CFDictionarySetValue(svc, CFSTR("UserDefinedName"), CFSTR("Émulateur (PPP)"));
|
||||
set_key(CFSTR("Setup:/Network/Service/" SERVICE_ID), svc);
|
||||
CFDictionarySetValue(itf, CFSTR("Type"), CFSTR("PPP"));
|
||||
CFDictionarySetValue(itf, CFSTR("SubType"), CFSTR("PPPSerial"));
|
||||
CFDictionarySetValue(itf, CFSTR("DeviceName"), CFSTR("tty.bluetooth"));
|
||||
set_key(CFSTR("Setup:/Network/Service/" SERVICE_ID "/Interface"), itf);
|
||||
CFDictionarySetValue(ipv4, CFSTR("ConfigMethod"), CFSTR("PPP"));
|
||||
set_key(CFSTR("Setup:/Network/Service/" SERVICE_ID "/IPv4"), ipv4);
|
||||
CFArrayRef order = str_array(SERVICE_ID);
|
||||
CFDictionarySetValue(glob, CFSTR("ServiceOrder"), order);
|
||||
set_key(CFSTR("Setup:/Network/Global/IPv4"), glob);
|
||||
CFRelease(order); CFRelease(svc); CFRelease(itf); CFRelease(ipv4); CFRelease(glob);
|
||||
}
|
||||
|
||||
/* Lien monté : vérifie qu'IPMonitor a bien installé la route par défaut, sinon la pose nous-mêmes */
|
||||
static void publish_network(const char *ifname)
|
||||
{
|
||||
net_published = 1;
|
||||
sleep(1);
|
||||
if (add_default_route() == 0) clog_("lien %s prêt (%s via %s, DNS %s)", ifname, GUEST_IP, GW_IP, DNS_IP);
|
||||
}
|
||||
|
||||
static void net_tick(void)
|
||||
{
|
||||
int status;
|
||||
char ifname[IFNAMSIZ];
|
||||
if (pppd_pid && waitpid(pppd_pid, &status, WNOHANG) == pppd_pid) {
|
||||
clog_("pppd terminé (statut %d), relance", status);
|
||||
pppd_pid = 0;
|
||||
net_published = 0;
|
||||
}
|
||||
if (!pppd_pid) { publish_setup(); start_pppd(); }
|
||||
int up = ppp_up(ifname, sizeof ifname);
|
||||
if (up && !net_published) publish_network(ifname);
|
||||
if (!up) net_published = 0;
|
||||
}
|
||||
|
||||
/* ---------- réponses ---------- */
|
||||
|
||||
static int send_all(int fd, const void *b, size_t n)
|
||||
{
|
||||
const char *p = b;
|
||||
while (n) {
|
||||
ssize_t w = write(fd, p, n);
|
||||
if (w <= 0) { if (w < 0 && errno == EINTR) continue; if (!w) errno = EIO; return -1; }
|
||||
p += w; n -= w;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void reply(int fd, int ok, const char *info, const void *data, size_t len)
|
||||
{
|
||||
char hdr[128];
|
||||
snprintf(hdr, sizeof hdr, "%s %zu%s%s\n", ok ? "OK" : "ERR", len, info ? " " : "", info ? info : "");
|
||||
send_all(fd, hdr, strlen(hdr));
|
||||
if (len) send_all(fd, data, len);
|
||||
}
|
||||
|
||||
static void reply_str(int fd, int ok, const char *fmt, ...)
|
||||
{
|
||||
char buf[4096];
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(buf, sizeof buf, fmt, ap);
|
||||
va_end(ap);
|
||||
reply(fd, ok, NULL, buf, strlen(buf));
|
||||
}
|
||||
|
||||
/* tampon dynamique */
|
||||
struct buf { char *p; size_t n, cap; };
|
||||
static void bput(struct buf *b, const void *d, size_t n)
|
||||
{
|
||||
if (b->n + n + 1 > b->cap) {
|
||||
b->cap = (b->n + n + 1) * 2;
|
||||
b->p = realloc(b->p, b->cap);
|
||||
}
|
||||
memcpy(b->p + b->n, d, n);
|
||||
b->n += n;
|
||||
b->p[b->n] = 0;
|
||||
}
|
||||
static void bprintf(struct buf *b, const char *fmt, ...)
|
||||
{
|
||||
char tmp[2048];
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
int n = vsnprintf(tmp, sizeof tmp, fmt, ap);
|
||||
va_end(ap);
|
||||
bput(b, tmp, n < (int)sizeof tmp ? n : (int)sizeof tmp - 1);
|
||||
}
|
||||
|
||||
/* ---------- commandes ---------- */
|
||||
|
||||
static void cmd_exec(int fd, char **args, int nargs)
|
||||
{
|
||||
int pfd[2];
|
||||
pid_t pid;
|
||||
if (nargs < 1) { reply_str(fd, 0, "usage: exec<TAB>programme<TAB>args..."); return; }
|
||||
pipe(pfd);
|
||||
posix_spawn_file_actions_t fa;
|
||||
posix_spawn_file_actions_init(&fa);
|
||||
posix_spawn_file_actions_addopen(&fa, 0, "/dev/null", O_RDONLY, 0);
|
||||
posix_spawn_file_actions_adddup2(&fa, pfd[1], 1);
|
||||
posix_spawn_file_actions_adddup2(&fa, pfd[1], 2);
|
||||
posix_spawn_file_actions_addclose(&fa, pfd[0]);
|
||||
char *argv[64];
|
||||
int i;
|
||||
for (i = 0; i < nargs && i < 63; i++) argv[i] = args[i];
|
||||
argv[i] = NULL;
|
||||
int err = posix_spawn(&pid, argv[0], &fa, NULL, argv, environ);
|
||||
posix_spawn_file_actions_destroy(&fa);
|
||||
close(pfd[1]);
|
||||
if (err) { close(pfd[0]); reply_str(fd, 0, "posix_spawn %s : %s", argv[0], strerror(err)); return; }
|
||||
|
||||
struct buf out = { 0 };
|
||||
char tmp[4096];
|
||||
time_t start = time(NULL);
|
||||
fcntl(pfd[0], F_SETFL, O_NONBLOCK);
|
||||
for (;;) {
|
||||
fd_set rs;
|
||||
struct timeval tv = { 1, 0 };
|
||||
FD_ZERO(&rs); FD_SET(pfd[0], &rs);
|
||||
if (select(pfd[0] + 1, &rs, NULL, NULL, &tv) > 0) {
|
||||
ssize_t n = read(pfd[0], tmp, sizeof tmp);
|
||||
if (n > 0) { bput(&out, tmp, n); continue; }
|
||||
if (n == 0) break;
|
||||
}
|
||||
if (time(NULL) - start > 120) { kill(pid, SIGKILL); bprintf(&out, "\n[emuagent: délai dépassé, processus tué]\n"); break; }
|
||||
}
|
||||
close(pfd[0]);
|
||||
int status = 0;
|
||||
waitpid(pid, &status, 0);
|
||||
char info[32];
|
||||
snprintf(info, sizeof info, "%d", WIFEXITED(status) ? WEXITSTATUS(status) : 128 + WTERMSIG(status));
|
||||
reply(fd, 1, info, out.p, out.n);
|
||||
free(out.p);
|
||||
}
|
||||
|
||||
static int (*p_SBSLaunchApplication)(CFStringRef, unsigned char);
|
||||
static CFStringRef (*p_SBSApplicationLaunchingErrorString)(int);
|
||||
static CFStringRef (*p_SBSCopyFrontmostApplicationDisplayIdentifier)(void);
|
||||
static unsigned (*p_SBSSpringBoardServerPort)(void);
|
||||
static int (*p_SBGetScreenLockStatus)(unsigned, unsigned char *, unsigned char *);
|
||||
static int (*p_SBDimScreen)(unsigned, unsigned char);
|
||||
|
||||
static void load_sbs(void)
|
||||
{
|
||||
static void *h;
|
||||
if (h) return;
|
||||
h = dlopen("/System/Library/PrivateFrameworks/SpringBoardServices.framework/SpringBoardServices", RTLD_NOW);
|
||||
if (!h) return;
|
||||
p_SBSSpringBoardServerPort = dlsym(h, "SBSSpringBoardServerPort");
|
||||
p_SBGetScreenLockStatus = dlsym(h, "SBGetScreenLockStatus");
|
||||
p_SBDimScreen = dlsym(h, "SBDimScreen");
|
||||
p_SBSLaunchApplication = dlsym(h, "SBSLaunchApplicationWithIdentifier");
|
||||
p_SBSApplicationLaunchingErrorString = dlsym(h, "SBSApplicationLaunchingErrorString");
|
||||
p_SBSCopyFrontmostApplicationDisplayIdentifier = dlsym(h, "SBSCopyFrontmostApplicationDisplayIdentifier");
|
||||
}
|
||||
|
||||
static void cfstr(CFStringRef s, char *out, size_t len)
|
||||
{
|
||||
out[0] = 0;
|
||||
if (s) CFStringGetCString(s, out, len, kCFStringEncodingUTF8);
|
||||
}
|
||||
|
||||
/* API MIG du firmware 2.2.1 : les deux états sont des octets, retour kern_return_t. */
|
||||
static void cmd_screen(int fd, int wake)
|
||||
{
|
||||
load_sbs();
|
||||
if (!p_SBSSpringBoardServerPort || !p_SBGetScreenLockStatus || !p_SBDimScreen) {
|
||||
reply_str(fd, 0, "API d'écran indisponible"); return;
|
||||
}
|
||||
unsigned port = p_SBSSpringBoardServerPort();
|
||||
unsigned char locked = 0, passcode = 0;
|
||||
int rc = p_SBGetScreenLockStatus(port, &locked, &passcode);
|
||||
if (rc) { reply_str(fd, 0, "SBGetScreenLockStatus : %d", rc); return; }
|
||||
if (wake) {
|
||||
/* SBApplicationRequestedDeviceUnlock affiche le clavier de code même
|
||||
sans code activé. Réveiller seulement l'écran, puis glisser côté hôte. */
|
||||
rc = p_SBDimScreen(port, 0);
|
||||
if (rc) { reply_str(fd, 0, "SBDimScreen : %d", rc); return; }
|
||||
}
|
||||
reply_str(fd, 1, "locked=%u passcode=%u", locked, passcode);
|
||||
}
|
||||
|
||||
static void cmd_launch(int fd, char **args, int nargs)
|
||||
{
|
||||
load_sbs();
|
||||
if (!p_SBSLaunchApplication) { reply_str(fd, 0, "SpringBoardServices indisponible"); return; }
|
||||
if (nargs != 1) { reply_str(fd, 0, "usage: launch<TAB>bundle-id"); return; }
|
||||
CFStringRef id = CFStringCreateWithCString(NULL, args[0], kCFStringEncodingUTF8);
|
||||
int r = p_SBSLaunchApplication(id, 0);
|
||||
CFRelease(id);
|
||||
if (r == 0) { reply_str(fd, 1, "lancé"); return; }
|
||||
char err[256] = "?";
|
||||
if (p_SBSApplicationLaunchingErrorString) cfstr(p_SBSApplicationLaunchingErrorString(r), err, sizeof err);
|
||||
reply_str(fd, 0, "SBSLaunchApplication : %d (%s)", r, err);
|
||||
}
|
||||
|
||||
/* fetch<TAB>http://hôte[:port]/chemin : résolution DNS + GET HTTP depuis l'iPod (diagnostic réseau) */
|
||||
static void cmd_fetch(int fd, char **args, int nargs)
|
||||
{
|
||||
char host[256], path[1024] = "/", port[8] = "80";
|
||||
if (nargs < 1 || strncmp(args[0], "http://", 7)) { reply_str(fd, 0, "usage: fetch<TAB>http://hôte[:port]/chemin"); return; }
|
||||
const char *h = args[0] + 7, *slash = strchr(h, '/');
|
||||
size_t hl = slash ? (size_t)(slash - h) : strlen(h);
|
||||
if (hl >= sizeof host) hl = sizeof host - 1;
|
||||
memcpy(host, h, hl); host[hl] = 0;
|
||||
if (slash) strncpy(path, slash, sizeof path - 1);
|
||||
char *colon = strchr(host, ':');
|
||||
if (colon) { *colon = 0; strncpy(port, colon + 1, sizeof port - 1); }
|
||||
|
||||
struct addrinfo hints = { .ai_family = AF_INET, .ai_socktype = SOCK_STREAM }, *res;
|
||||
int e = getaddrinfo(host, port, &hints, &res);
|
||||
if (e) { reply_str(fd, 0, "getaddrinfo %s : %s", host, gai_strerror(e)); return; }
|
||||
char ip[32];
|
||||
inet_ntop(AF_INET, &((struct sockaddr_in *)res->ai_addr)->sin_addr, ip, sizeof ip);
|
||||
int s = socket(AF_INET, SOCK_STREAM, 0);
|
||||
struct timeval to = { 15, 0 };
|
||||
setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &to, sizeof to);
|
||||
setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &to, sizeof to);
|
||||
if (connect(s, res->ai_addr, res->ai_addrlen)) { reply_str(fd, 0, "connect %s (%s) : %s", host, ip, strerror(errno)); close(s); freeaddrinfo(res); return; }
|
||||
freeaddrinfo(res);
|
||||
char req[1400];
|
||||
snprintf(req, sizeof req, "GET %s HTTP/1.0\r\nHost: %s\r\nUser-Agent: emuagent\r\nConnection: close\r\n\r\n", path, host);
|
||||
send_all(s, req, strlen(req));
|
||||
struct buf b = { 0 };
|
||||
bprintf(&b, "[%s -> %s]\n", host, ip);
|
||||
char tmp[4096];
|
||||
ssize_t n;
|
||||
while (b.n < 256 * 1024 && (n = read(s, tmp, sizeof tmp)) > 0) bput(&b, tmp, n);
|
||||
close(s);
|
||||
reply(fd, 1, NULL, b.p, b.n);
|
||||
free(b.p);
|
||||
}
|
||||
|
||||
/* sc[<TAB>clé] : liste des clés du SCDynamicStore, ou valeur d'une clé (plist XML) */
|
||||
static void cmd_sc(int fd, char **args, int nargs)
|
||||
{
|
||||
if (!store) store = SCDynamicStoreCreate(NULL, CFSTR("emuagent"), NULL, NULL);
|
||||
CFStringRef k = CFStringCreateWithCString(NULL, nargs ? args[0] : ".*", kCFStringEncodingUTF8);
|
||||
CFPropertyListRef v = nargs && !strchr(args[0], '*') ? SCDynamicStoreCopyValue(store, k) : SCDynamicStoreCopyKeyList(store, k);
|
||||
CFRelease(k);
|
||||
if (!v) { reply_str(fd, 0, "clé absente"); return; }
|
||||
CFDataRef x = CFPropertyListCreateXMLData(NULL, v);
|
||||
reply(fd, 1, NULL, CFDataGetBytePtr(x), CFDataGetLength(x));
|
||||
CFRelease(x);
|
||||
CFRelease(v);
|
||||
}
|
||||
|
||||
/* routes : table de routage IPv4 (sysctl NET_RT_DUMP) */
|
||||
static void cmd_routes(int fd)
|
||||
{
|
||||
int mib[6] = { CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_DUMP, 0 };
|
||||
size_t len = 0;
|
||||
if (sysctl(mib, 6, NULL, &len, NULL, 0)) { reply_str(fd, 0, "sysctl : %s", strerror(errno)); return; }
|
||||
char *b = malloc(len), *p;
|
||||
sysctl(mib, 6, b, &len, NULL, 0);
|
||||
struct buf out = { 0 };
|
||||
for (p = b; p < b + len;) {
|
||||
struct rt_msghdr *h = (struct rt_msghdr *)p;
|
||||
struct sockaddr *sa = (struct sockaddr *)(h + 1);
|
||||
char txt[3][32] = { "-", "-", "-" };
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (!(h->rtm_addrs & (1 << i))) continue;
|
||||
if (sa->sa_family == AF_INET) inet_ntop(AF_INET, &((struct sockaddr_in *)sa)->sin_addr, txt[i], 32);
|
||||
else if (sa->sa_family == AF_LINK) strcpy(txt[i], "link");
|
||||
else if (sa->sa_len == 0) strcpy(txt[i], "0");
|
||||
sa = (struct sockaddr *)((char *)sa + (sa->sa_len ? ((sa->sa_len + 3) & ~3) : 4));
|
||||
}
|
||||
char ifn[IFNAMSIZ] = "?";
|
||||
if_indextoname(h->rtm_index, ifn);
|
||||
bprintf(&out, "%-16s gw %-16s mask %-16s %s flags 0x%x\n", txt[0], txt[1], txt[2], ifn, h->rtm_flags);
|
||||
p += h->rtm_msglen;
|
||||
}
|
||||
free(b);
|
||||
reply(fd, 1, NULL, out.p ? out.p : "", out.n);
|
||||
free(out.p);
|
||||
}
|
||||
|
||||
static void cmd_front(int fd)
|
||||
{
|
||||
load_sbs();
|
||||
char s[256] = "";
|
||||
if (p_SBSCopyFrontmostApplicationDisplayIdentifier) {
|
||||
CFStringRef f = p_SBSCopyFrontmostApplicationDisplayIdentifier();
|
||||
cfstr(f, s, sizeof s);
|
||||
if (f) CFRelease(f);
|
||||
}
|
||||
reply_str(fd, 1, "%s", s[0] ? s : "com.apple.springboard");
|
||||
}
|
||||
|
||||
static void list_apps_in(struct buf *b, const char *dir, int depth)
|
||||
{
|
||||
DIR *d = opendir(dir);
|
||||
struct dirent *e;
|
||||
if (!d) return;
|
||||
while ((e = readdir(d))) {
|
||||
char path[1024];
|
||||
if (e->d_name[0] == '.') continue;
|
||||
snprintf(path, sizeof path, "%s/%s", dir, e->d_name);
|
||||
size_t l = strlen(e->d_name);
|
||||
if (l > 4 && !strcmp(e->d_name + l - 4, ".app")) {
|
||||
CFURLRef u = CFURLCreateFromFileSystemRepresentation(NULL, (UInt8 *)path, strlen(path), true);
|
||||
CFBundleRef bundle = CFBundleCreate(NULL, u);
|
||||
char id[256] = "", name[256] = "";
|
||||
if (bundle) {
|
||||
cfstr(CFBundleGetIdentifier(bundle), id, sizeof id);
|
||||
CFTypeRef n = CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("CFBundleDisplayName"));
|
||||
if (!n) n = CFBundleGetValueForInfoDictionaryKey(bundle, kCFBundleNameKey);
|
||||
if (n && CFGetTypeID(n) == CFStringGetTypeID()) cfstr(n, name, sizeof name);
|
||||
CFRelease(bundle);
|
||||
}
|
||||
CFRelease(u);
|
||||
bprintf(b, "%s\t%s\t%s\n", id, name, path);
|
||||
} else if (depth > 0) {
|
||||
list_apps_in(b, path, depth - 1);
|
||||
}
|
||||
}
|
||||
closedir(d);
|
||||
}
|
||||
|
||||
static void cmd_apps(int fd)
|
||||
{
|
||||
struct buf b = { 0 };
|
||||
list_apps_in(&b, "/Applications", 0);
|
||||
list_apps_in(&b, "/private/var/mobile/Applications", 1);
|
||||
reply(fd, 1, NULL, b.p, b.n);
|
||||
free(b.p);
|
||||
}
|
||||
|
||||
static int mkdirs(const char *path)
|
||||
{
|
||||
char tmp[1024];
|
||||
strncpy(tmp, path, sizeof tmp - 1);
|
||||
tmp[sizeof tmp - 1] = 0;
|
||||
for (char *p = tmp + 1; *p; p++) {
|
||||
if (*p == '/') { *p = 0; mkdir(tmp, 0755); *p = '/'; }
|
||||
}
|
||||
return mkdir(tmp, 0755) == 0 || errno == EEXIST ? 0 : -1;
|
||||
}
|
||||
|
||||
static int read_full(int fd, void *b, size_t n)
|
||||
{
|
||||
char *p = b;
|
||||
while (n) {
|
||||
ssize_t r = read(fd, p, n);
|
||||
if (r <= 0) { if (r < 0 && errno == EINTR) continue; if (!r) errno = EIO; return -1; }
|
||||
p += r; n -= r;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Transferts par blocs : ne pas allouer la taille du fichier sur l'iPod. */
|
||||
static void cmd_put(int fd, char **args, int nargs)
|
||||
{
|
||||
if (nargs < 3) { reply_str(fd, 0, "usage: put<TAB>chemin<TAB>mode octal<TAB>taille + données"); return; }
|
||||
char *end;
|
||||
errno = 0;
|
||||
unsigned long size = strtoul(args[2], &end, 10);
|
||||
if (errno || !args[2][0] || args[2][0] == '-' || *end) {
|
||||
reply_str(fd, 0, "taille invalide"); return;
|
||||
}
|
||||
char dir[1024];
|
||||
if (strlen(args[0]) >= sizeof dir) { reply_str(fd, 0, "chemin trop long"); return; }
|
||||
strcpy(dir, args[0]);
|
||||
char *slash = strrchr(dir, '/');
|
||||
if (slash && slash != dir) { *slash = 0; mkdirs(dir); }
|
||||
char tmp[1100];
|
||||
snprintf(tmp, sizeof tmp, "%s.emuagent-XXXXXX", args[0]);
|
||||
int f = mkstemp(tmp);
|
||||
if (f < 0) { reply_str(fd, 0, "création : %s", strerror(errno)); return; }
|
||||
char data[65536];
|
||||
size_t remaining = size;
|
||||
int failed = 0;
|
||||
while (remaining) {
|
||||
size_t chunk = remaining < sizeof data ? remaining : sizeof data;
|
||||
if (read_full(fd, data, chunk) || send_all(f, data, chunk)) { failed = 1; break; }
|
||||
remaining -= chunk;
|
||||
}
|
||||
if (!failed && (fchmod(f, strtoul(args[1], NULL, 8)) || fsync(f))) failed = 1;
|
||||
int saved = errno;
|
||||
if (close(f) && !failed) { failed = 1; saved = errno; }
|
||||
if (!failed && rename(tmp, args[0])) { failed = 1; saved = errno; }
|
||||
if (failed) {
|
||||
unlink(tmp);
|
||||
reply_str(fd, 0, "écriture de %s : %s", args[0], strerror(saved));
|
||||
return;
|
||||
}
|
||||
reply_str(fd, 1, "%lu octets écrits", size);
|
||||
}
|
||||
|
||||
static void cmd_get(int fd, char **args, int nargs)
|
||||
{
|
||||
if (nargs < 1) { reply_str(fd, 0, "usage: get<TAB>chemin"); return; }
|
||||
int f = open(args[0], O_RDONLY | O_NONBLOCK);
|
||||
struct stat st;
|
||||
if (f < 0 || fstat(f, &st) || !S_ISREG(st.st_mode)) {
|
||||
reply_str(fd, 0, "lecture de %s impossible", args[0]);
|
||||
if (f >= 0) close(f);
|
||||
return;
|
||||
}
|
||||
char hdr[128], data[65536];
|
||||
snprintf(hdr, sizeof hdr, "OK %llu\n", (unsigned long long)st.st_size);
|
||||
if (send_all(fd, hdr, strlen(hdr))) { close(f); return; }
|
||||
off_t remaining = st.st_size;
|
||||
while (remaining) {
|
||||
size_t chunk = remaining < (off_t)sizeof data ? (size_t)remaining : sizeof data;
|
||||
/* Après l'en-tête, une erreur impose de fermer la connexion :
|
||||
le client détecte la réponse incomplète et conserve son ancien fichier. */
|
||||
if (read_full(f, data, chunk) || send_all(fd, data, chunk)) {
|
||||
close(f); shutdown(fd, SHUT_RDWR); return;
|
||||
}
|
||||
remaining -= chunk;
|
||||
}
|
||||
close(f);
|
||||
}
|
||||
|
||||
static void cmd_ls(int fd, char **args, int nargs)
|
||||
{
|
||||
const char *path = nargs ? args[0] : "/";
|
||||
DIR *d = opendir(path);
|
||||
if (!d) { reply_str(fd, 0, "%s : %s", path, strerror(errno)); return; }
|
||||
struct buf b = { 0 };
|
||||
struct dirent *e;
|
||||
while ((e = readdir(d))) {
|
||||
char p[1024];
|
||||
struct stat st;
|
||||
if (!strcmp(e->d_name, ".") || !strcmp(e->d_name, "..")) continue;
|
||||
snprintf(p, sizeof p, "%s/%s", path, e->d_name);
|
||||
if (lstat(p, &st)) continue;
|
||||
bprintf(&b, "%c%04o %5d %5d %10lld %s\n", S_ISDIR(st.st_mode) ? 'd' : S_ISLNK(st.st_mode) ? 'l' : '-',
|
||||
st.st_mode & 07777, st.st_uid, st.st_gid, (long long)st.st_size, e->d_name);
|
||||
}
|
||||
closedir(d);
|
||||
reply(fd, 1, NULL, b.p ? b.p : "", b.n);
|
||||
free(b.p);
|
||||
}
|
||||
|
||||
static int rm_rf(const char *path)
|
||||
{
|
||||
struct stat st;
|
||||
if (lstat(path, &st)) return -1;
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
DIR *d = opendir(path);
|
||||
struct dirent *e;
|
||||
while (d && (e = readdir(d))) {
|
||||
char p[1024];
|
||||
if (!strcmp(e->d_name, ".") || !strcmp(e->d_name, "..")) continue;
|
||||
snprintf(p, sizeof p, "%s/%s", path, e->d_name);
|
||||
rm_rf(p);
|
||||
}
|
||||
if (d) closedir(d);
|
||||
return rmdir(path);
|
||||
}
|
||||
return unlink(path);
|
||||
}
|
||||
|
||||
static void cmd_ps(int fd)
|
||||
{
|
||||
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
|
||||
size_t len = 0;
|
||||
sysctl(mib, 3, NULL, &len, NULL, 0);
|
||||
struct kinfo_proc *procs = malloc(len);
|
||||
if (sysctl(mib, 3, procs, &len, NULL, 0)) { reply_str(fd, 0, "sysctl : %s", strerror(errno)); free(procs); return; }
|
||||
struct buf b = { 0 };
|
||||
bprintf(&b, " PID PPID UID COMMAND\n");
|
||||
for (size_t i = 0; i < len / sizeof *procs; i++) {
|
||||
struct kinfo_proc *p = &procs[i];
|
||||
bprintf(&b, "%5d %5d %5d %s\n", p->kp_proc.p_pid, p->kp_eproc.e_ppid, p->kp_eproc.e_ucred.cr_uid, p->kp_proc.p_comm);
|
||||
}
|
||||
reply(fd, 1, NULL, b.p, b.n);
|
||||
free(b.p);
|
||||
free(procs);
|
||||
}
|
||||
|
||||
static int kill_by_name(const char *name, int sig)
|
||||
{
|
||||
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 }, n = 0;
|
||||
size_t len = 0;
|
||||
sysctl(mib, 3, NULL, &len, NULL, 0);
|
||||
struct kinfo_proc *procs = malloc(len);
|
||||
if (!sysctl(mib, 3, procs, &len, NULL, 0)) {
|
||||
for (size_t i = 0; i < len / sizeof *procs; i++) {
|
||||
if (!strcmp(procs[i].kp_proc.p_comm, name) && !kill(procs[i].kp_proc.p_pid, sig)) n++;
|
||||
}
|
||||
}
|
||||
free(procs);
|
||||
return n;
|
||||
}
|
||||
|
||||
static void cmd_kill(int fd, char **args, int nargs)
|
||||
{
|
||||
if (nargs < 1) { reply_str(fd, 0, "usage: kill<TAB>pid|nom[<TAB>signal]"); return; }
|
||||
int sig = nargs > 1 ? atoi(args[1]) : SIGTERM;
|
||||
char *end;
|
||||
long pid = strtol(args[0], &end, 10);
|
||||
if (!*end) {
|
||||
if (kill(pid, sig)) reply_str(fd, 0, "kill %ld : %s", pid, strerror(errno));
|
||||
else reply_str(fd, 1, "1");
|
||||
} else {
|
||||
int n = kill_by_name(args[0], sig);
|
||||
reply_str(fd, n > 0, "%d", n);
|
||||
}
|
||||
}
|
||||
|
||||
static void cmd_net(int fd)
|
||||
{
|
||||
struct ifaddrs *ifa, *i;
|
||||
struct buf b = { 0 };
|
||||
if (!getifaddrs(&ifa)) {
|
||||
for (i = ifa; i; i = i->ifa_next) {
|
||||
if (i->ifa_addr && i->ifa_addr->sa_family == AF_INET) {
|
||||
char a[32], dst[32] = "";
|
||||
inet_ntop(AF_INET, &((struct sockaddr_in *)i->ifa_addr)->sin_addr, a, sizeof a);
|
||||
if (i->ifa_dstaddr && (i->ifa_flags & IFF_POINTOPOINT))
|
||||
inet_ntop(AF_INET, &((struct sockaddr_in *)i->ifa_dstaddr)->sin_addr, dst, sizeof dst);
|
||||
bprintf(&b, "%s %s%s%s %s\n", i->ifa_name, a, dst[0] ? " -> " : "", dst, (i->ifa_flags & IFF_UP) ? "up" : "down");
|
||||
}
|
||||
}
|
||||
freeifaddrs(ifa);
|
||||
}
|
||||
bprintf(&b, "pppd: %s, configd: %s\n", pppd_pid ? "actif" : "arrêté", net_published ? "publié" : "non publié");
|
||||
reply(fd, 1, NULL, b.p, b.n);
|
||||
free(b.p);
|
||||
}
|
||||
|
||||
static void cmd_touch(int fd, char **a, int n)
|
||||
{
|
||||
if (n != 5) { reply_str(fd, 0, "touch x1 y1 x2 y2 duration_ms"); return; }
|
||||
float v[4];
|
||||
for (int i=0;i<4;i++) { char *end; v[i]=strtof(a[i],&end); if (*end || !(v[i]>=0 && v[i]<(i%2?480:320))) { reply_str(fd,0,"coordonnees invalides"); return; } }
|
||||
unsigned ms=atoi(a[4]); if(ms<32 || ms>5000) { reply_str(fd,0,"duree invalide"); return; }
|
||||
load_sbs(); char bundle[256]="";
|
||||
CFStringRef front=p_SBSCopyFrontmostApplicationDisplayIdentifier ? p_SBSCopyFrontmostApplicationDisplayIdentifier() : NULL;
|
||||
if(front) { cfstr(front,bundle,sizeof bundle); CFRelease(front); }
|
||||
int rc=send_touch_gesture(v[0],v[1],v[2],v[3],ms,bundle[0] && strcmp(bundle,"com.apple.springboard") ? bundle : NULL);
|
||||
reply_str(fd,rc==0,"touch %d %s",rc,bundle);
|
||||
}
|
||||
|
||||
static const char *front_target(char *bundle, size_t len)
|
||||
{
|
||||
load_sbs(); bundle[0]=0;
|
||||
CFStringRef front=p_SBSCopyFrontmostApplicationDisplayIdentifier ? p_SBSCopyFrontmostApplicationDisplayIdentifier() : NULL;
|
||||
if(front) { cfstr(front,bundle,len); CFRelease(front); }
|
||||
return bundle[0] && strcmp(bundle,"com.apple.springboard") ? bundle : NULL;
|
||||
}
|
||||
|
||||
/* text <chaîne UTF-8> : une touche par unité UTF-16, vers l'app au premier plan. */
|
||||
static void cmd_text(int fd, char **a, int n)
|
||||
{
|
||||
if (n != 1) { reply_str(fd, 0, "text chaine"); return; }
|
||||
CFStringRef s = CFStringCreateWithCString(NULL, a[0], kCFStringEncodingUTF8);
|
||||
if (!s) { reply_str(fd, 0, "UTF-8 invalide"); return; }
|
||||
char bundle[256]; const char *target = front_target(bundle, sizeof bundle);
|
||||
int rc = 0;
|
||||
for (CFIndex i = 0; i < CFStringGetLength(s) && !rc; i++) rc = send_key_event(CFStringGetCharacterAtIndex(s, i), target);
|
||||
CFRelease(s);
|
||||
reply_str(fd, rc == 0, "text %d %s", rc, bundle);
|
||||
}
|
||||
|
||||
/* key return|backspace|tab|0xNNNN */
|
||||
static void cmd_key(int fd, char **a, int n)
|
||||
{
|
||||
static const struct { const char *name; UniChar code; } keys[] = { {"return", '\n'}, {"backspace", 0x08}, {"tab", '\t'} };
|
||||
if (n < 1 || n > 3) { reply_str(fd, 0, "key return|backspace|tab|0xNNNN [sequence DdUu [keycode]]"); return; }
|
||||
long code = -1;
|
||||
for (size_t i = 0; i < sizeof keys / sizeof *keys; i++) if (!strcmp(a[0], keys[i].name)) code = keys[i].code;
|
||||
if (code < 0 && !strncmp(a[0], "0x", 2)) { char *end; code = strtol(a[0] + 2, &end, 16); if (*end || code <= 0 || code > 0xffff) code = -1; }
|
||||
if (code < 0) { reply_str(fd, 0, "touche inconnue : %s", a[0]); return; }
|
||||
char bundle[256]; const char *target = front_target(bundle, sizeof bundle);
|
||||
int rc = n > 1 ? send_key_sequence((UniChar)code, target, a[1], n > 2 ? (uint16_t)strtol(a[2], NULL, 0) : 0)
|
||||
: send_key_event((UniChar)code, target);
|
||||
reply_str(fd, rc == 0, "key %d %s", rc, bundle);
|
||||
}
|
||||
|
||||
static void handle(int fd, char *line)
|
||||
{
|
||||
char *args[64];
|
||||
int n = 0;
|
||||
for (char *t = strtok(line, "\t"); t && n < 64; t = strtok(NULL, "\t")) args[n++] = t;
|
||||
if (!n) return;
|
||||
char *cmd = args[0];
|
||||
char **a = args + 1;
|
||||
int na = n - 1;
|
||||
if (!strcmp(cmd, "ping")) reply_str(fd, 1, "emuagent %s", VERSION);
|
||||
else if (!strcmp(cmd, "touch")) cmd_touch(fd,a,na);
|
||||
else if (!strcmp(cmd, "text")) cmd_text(fd,a,na);
|
||||
else if (!strcmp(cmd, "key")) cmd_key(fd,a,na);
|
||||
else if (!strcmp(cmd, "home")) {
|
||||
void *h=dlopen("/System/Library/PrivateFrameworks/SpringBoardServices.framework/SpringBoardServices",RTLD_NOW);
|
||||
int (*fn)(void)=h?dlsym(h,"SBSSuspendFrontmostApplication"):NULL;
|
||||
reply_str(fd,fn && fn(),"home");
|
||||
}
|
||||
else if (!strcmp(cmd, "exec")) cmd_exec(fd, a, na);
|
||||
else if (!strcmp(cmd, "launch")) cmd_launch(fd, a, na);
|
||||
else if (!strcmp(cmd, "front")) cmd_front(fd);
|
||||
else if (!strcmp(cmd, "screen")) cmd_screen(fd, 0);
|
||||
else if (!strcmp(cmd, "wake")) cmd_screen(fd, 1);
|
||||
else if (!strcmp(cmd, "fetch")) cmd_fetch(fd, a, na);
|
||||
else if (!strcmp(cmd, "sc")) cmd_sc(fd, a, na);
|
||||
else if (!strcmp(cmd, "routes")) cmd_routes(fd);
|
||||
else if (!strcmp(cmd, "settime")) {
|
||||
/* Réglage explicite de l'heure pour les tests (secondes Unix). */
|
||||
struct timeval tv = { na ? strtol(a[0], NULL, 10) : 0, 0 };
|
||||
if (na && !settimeofday(&tv, NULL)) {
|
||||
notify_post("com.apple.system.clock_set"); /* SpringBoard et les apps mettent leur horloge à jour */
|
||||
reply_str(fd, 1, "%ld", (long)tv.tv_sec);
|
||||
}
|
||||
else reply_str(fd, 0, "settimeofday : %s", strerror(errno));
|
||||
}
|
||||
else if (!strcmp(cmd, "apps")) cmd_apps(fd);
|
||||
else if (!strcmp(cmd, "put")) cmd_put(fd, a, na);
|
||||
else if (!strcmp(cmd, "get")) cmd_get(fd, a, na);
|
||||
else if (!strcmp(cmd, "ls")) cmd_ls(fd, a, na);
|
||||
else if (!strcmp(cmd, "rm")) { if (na && !rm_rf(a[0])) reply_str(fd, 1, "supprimé"); else reply_str(fd, 0, "rm : %s", strerror(errno)); }
|
||||
else if (!strcmp(cmd, "mkdir")) { if (na && !mkdirs(a[0])) reply_str(fd, 1, "ok"); else reply_str(fd, 0, "mkdir : %s", strerror(errno)); }
|
||||
else if (!strcmp(cmd, "ps")) cmd_ps(fd);
|
||||
else if (!strcmp(cmd, "kill")) cmd_kill(fd, a, na);
|
||||
else if (!strcmp(cmd, "net")) cmd_net(fd);
|
||||
else if (!strcmp(cmd, "respring")) reply_str(fd, kill_by_name("SpringBoard", SIGTERM) > 0, "SpringBoard relancé");
|
||||
else if (!strcmp(cmd, "sync")) { sync(); reply_str(fd, 1, "ok"); }
|
||||
else reply_str(fd, 0, "commande inconnue : %s (ping touch text key exec launch fetch sc routes settime screen wake front apps put get ls rm mkdir ps kill net respring sync)", cmd);
|
||||
}
|
||||
|
||||
static void serve_client(int fd)
|
||||
{
|
||||
char line[8192];
|
||||
size_t len = 0;
|
||||
for (;;) {
|
||||
char c;
|
||||
ssize_t r = read(fd, &c, 1);
|
||||
if (r <= 0) break;
|
||||
if (c == '\n') {
|
||||
line[len] = 0;
|
||||
handle(fd, line);
|
||||
len = 0;
|
||||
} else if (len < sizeof line - 1) {
|
||||
line[len++] = c;
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
/* diagnostic : si /private/var/root/emuagent-ttytest existe, lit la ligne série brute pendant 20 s avant pppd */
|
||||
static void tty_selftest(void)
|
||||
{
|
||||
struct stat st;
|
||||
if (stat("/private/var/root/emuagent-ttytest", &st)) return;
|
||||
int fd = open(PPP_TTY, O_RDWR | O_NOCTTY | O_NONBLOCK);
|
||||
clog_("ttytest : open %s -> %d (%s)", PPP_TTY, fd, fd < 0 ? strerror(errno) : "ok");
|
||||
if (fd < 0) return;
|
||||
struct termios t;
|
||||
tcgetattr(fd, &t); cfmakeraw(&t); cfsetspeed(&t, B115200); t.c_cflag |= CLOCAL | CREAD; t.c_cflag &= ~CRTSCTS;
|
||||
tcsetattr(fd, TCSANOW, &t);
|
||||
write(fd, "EMUAGENT-TTYTEST\n", 17);
|
||||
time_t start = time(NULL);
|
||||
size_t total = 0;
|
||||
while (time(NULL) - start < 20) {
|
||||
char b[256];
|
||||
ssize_t n = read(fd, b, sizeof b);
|
||||
if (n > 0) {
|
||||
total += n;
|
||||
char hex[64] = "";
|
||||
for (int i = 0; i < n && i < 16; i++) sprintf(hex + 3 * i, "%02x ", (unsigned char)b[i]);
|
||||
clog_("ttytest : %zd octets : %s", n, hex);
|
||||
} else {
|
||||
usleep(100000);
|
||||
}
|
||||
}
|
||||
clog_("ttytest : %zu octets reçus au total", total);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
/* iPhone OS 2.x does not implement the public idle-sleep assertions.
|
||||
* Its root power domain does support SleepDisabled, which is required
|
||||
* because this emulated SoC cannot resume from deep sleep. */
|
||||
static void prevent_idle_sleep(void)
|
||||
{
|
||||
void *h = dlopen("/System/Library/Frameworks/IOKit.framework/IOKit", RTLD_NOW);
|
||||
CFMutableDictionaryRef (*matching)(const char *) = h ? dlsym(h, "IOServiceMatching") : NULL;
|
||||
unsigned (*get_service)(unsigned, CFDictionaryRef) = h ? dlsym(h, "IOServiceGetMatchingService") : NULL;
|
||||
int (*set_property)(unsigned, CFStringRef, CFTypeRef) = h ? dlsym(h, "IORegistryEntrySetCFProperty") : NULL;
|
||||
int (*release)(unsigned) = h ? dlsym(h, "IOObjectRelease") : NULL;
|
||||
if (!matching || !get_service || !set_property || !release) {
|
||||
clog_("controle de veille IOKit indisponible");
|
||||
return;
|
||||
}
|
||||
unsigned root = get_service(0, matching("IOPMrootDomain"));
|
||||
if (!root) {
|
||||
clog_("IOPMrootDomain indisponible");
|
||||
return;
|
||||
}
|
||||
int rc = set_property(root, CFSTR("SleepDisabled"), kCFBooleanTrue);
|
||||
release(root);
|
||||
clog_("SleepDisabled: 0x%x", rc);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
con = fopen("/dev/console", "w");
|
||||
if (con) setvbuf(con, NULL, _IONBF, 0);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
clog_("version %s, port %d", VERSION, PORT);
|
||||
prevent_idle_sleep();
|
||||
tty_selftest();
|
||||
|
||||
/* agent relancé (mise à jour, crash) : le pppd de l'instance précédente tient encore la ligne série */
|
||||
if (kill_by_name("pppd", SIGTERM) > 0) { clog_("ancien pppd arrêté"); sleep(2); }
|
||||
|
||||
int s = socket(AF_INET, SOCK_STREAM, 0), one = 1;
|
||||
fcntl(s, F_SETFD, FD_CLOEXEC); /* sinon pppd hérite du port d'écoute */
|
||||
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one);
|
||||
struct sockaddr_in a = { .sin_family = AF_INET, .sin_port = htons(PORT), .sin_addr.s_addr = htonl(INADDR_ANY) };
|
||||
while (bind(s, (struct sockaddr *)&a, sizeof a)) { clog_("bind : %s, nouvel essai", strerror(errno)); sleep(2); }
|
||||
listen(s, 4);
|
||||
|
||||
for (;;) {
|
||||
pid_t z;
|
||||
int zs;
|
||||
while ((z = waitpid(-1, &zs, WNOHANG)) > 0) {
|
||||
if (z == pppd_pid) { clog_("pppd terminé (statut %d), relance", zs); pppd_pid = 0; net_published = 0; }
|
||||
}
|
||||
net_tick();
|
||||
fd_set rs;
|
||||
struct timeval tv = { 2, 0 };
|
||||
FD_ZERO(&rs);
|
||||
FD_SET(s, &rs);
|
||||
if (select(s + 1, &rs, NULL, NULL, &tv) > 0) {
|
||||
int c = accept(s, NULL, NULL);
|
||||
if (c >= 0) {
|
||||
fcntl(c, F_SETFD, FD_CLOEXEC);
|
||||
/* un processus par client : une commande longue ou bloquée ne gêne ni les autres ni le suivi réseau */
|
||||
pid_t p = fork();
|
||||
if (p == 0) {
|
||||
close(s);
|
||||
struct timeval to = { 300, 0 };
|
||||
setsockopt(c, SOL_SOCKET, SO_RCVTIMEO, &to, sizeof to);
|
||||
serve_client(c);
|
||||
_exit(0);
|
||||
}
|
||||
close(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,657 @@
|
||||
#define SLIRP_DEPRECATED_OK 1
|
||||
/*
|
||||
* ipod-netd : réseau pour l'émulateur iPod Touch 2G, sans privilèges.
|
||||
*
|
||||
* Termine le lien PPP que pppd (côté iPhone OS) ouvre sur l'UART1 émulée, et passe les paquets IP à libslirp :
|
||||
* NAT vers Internet, DNS (10.0.2.3), redirections de ports hôte -> iPod.
|
||||
*
|
||||
* ipod-netd [-s uart1.sock] [-L [addr:]hostport:guestport]... [-v]
|
||||
*
|
||||
* Adresses : iPod 10.0.2.15, passerelle 10.0.2.2, DNS 10.0.2.3. Défaut : -L 127.0.0.1:7788:7788 (emuagent).
|
||||
*/
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <slirp/libslirp.h>
|
||||
|
||||
#define GUEST_IP "10.0.2.15"
|
||||
#define GW_IP "10.0.2.2"
|
||||
#define DNS_IP "10.0.2.3"
|
||||
|
||||
static const uint8_t guest_mac[6] = { 0x52, 0x54, 0x00, 0x12, 0x34, 0x56 };
|
||||
static const uint8_t slirp_mac[6] = { 0x52, 0x55, 0x0a, 0x00, 0x02, 0x02 };
|
||||
|
||||
static int verbose;
|
||||
static int uart = -1;
|
||||
static const char *sock_path;
|
||||
static Slirp *slirp;
|
||||
|
||||
static void logm(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
fprintf(stderr, "[%ld.%03ld] ", (long)ts.tv_sec % 100000, ts.tv_nsec / 1000000);
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
|
||||
/* ---------- PPP : trames HDLC (RFC 1662) ---------- */
|
||||
|
||||
static uint16_t fcstab[256];
|
||||
|
||||
static void fcs_init(void)
|
||||
{
|
||||
for (int b = 0; b < 256; b++) {
|
||||
uint16_t v = b;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
v = (v & 1) ? (v >> 1) ^ 0x8408 : v >> 1;
|
||||
}
|
||||
fcstab[b] = v;
|
||||
}
|
||||
}
|
||||
|
||||
static uint16_t fcs16(uint16_t fcs, const uint8_t *p, size_t len)
|
||||
{
|
||||
while (len--) {
|
||||
fcs = (fcs >> 8) ^ fcstab[(fcs ^ *p++) & 0xff];
|
||||
}
|
||||
return fcs;
|
||||
}
|
||||
|
||||
static void ppp_send(uint16_t proto, const uint8_t *data, size_t len)
|
||||
{
|
||||
static uint8_t raw[4 + 2048], out[2 * (sizeof(raw) + 2) + 2];
|
||||
if (uart < 0 || len > 2048) {
|
||||
return;
|
||||
}
|
||||
raw[0] = 0xff; raw[1] = 0x03; raw[2] = proto >> 8; raw[3] = proto & 0xff;
|
||||
memcpy(raw + 4, data, len);
|
||||
size_t n = 4 + len;
|
||||
uint16_t fcs = fcs16(0xffff, raw, n) ^ 0xffff;
|
||||
raw[n++] = fcs & 0xff;
|
||||
raw[n++] = fcs >> 8;
|
||||
|
||||
size_t o = 0;
|
||||
out[o++] = 0x7e;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
uint8_t c = raw[i];
|
||||
if (c < 0x20 || c == 0x7e || c == 0x7d) {
|
||||
out[o++] = 0x7d;
|
||||
c ^= 0x20;
|
||||
}
|
||||
out[o++] = c;
|
||||
}
|
||||
out[o++] = 0x7e;
|
||||
for (size_t w = 0; w < o;) {
|
||||
ssize_t r = write(uart, out + w, o - w);
|
||||
if (r < 0) {
|
||||
if (errno == EINTR || errno == EAGAIN) {
|
||||
continue;
|
||||
}
|
||||
return;
|
||||
}
|
||||
w += r;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- LCP / IPCP ---------- */
|
||||
|
||||
enum { CONF_REQ = 1, CONF_ACK, CONF_NAK, CONF_REJ, TERM_REQ, TERM_ACK, CODE_REJ, PROTO_REJ, ECHO_REQ, ECHO_REP, DISC_REQ };
|
||||
|
||||
#define PROTO_IP 0x0021
|
||||
#define PROTO_LCP 0xc021
|
||||
#define PROTO_IPCP 0x8021
|
||||
|
||||
struct ncp {
|
||||
const char *name;
|
||||
uint16_t proto;
|
||||
int acked_peer; /* on a acquitté la requête du pair */
|
||||
int acked_ours; /* le pair a acquitté la nôtre */
|
||||
uint8_t id;
|
||||
time_t last_req;
|
||||
};
|
||||
|
||||
static struct ncp lcp = { "LCP", PROTO_LCP }, ipcp = { "IPCP", PROTO_IPCP };
|
||||
static uint32_t lcp_magic = 0x49504f44; /* "IPOD" */
|
||||
|
||||
static int is_open(struct ncp *n)
|
||||
{
|
||||
return n->acked_peer && n->acked_ours;
|
||||
}
|
||||
|
||||
static void send_ctl(uint16_t proto, uint8_t code, uint8_t id, const uint8_t *opts, size_t len)
|
||||
{
|
||||
uint8_t pkt[1500];
|
||||
pkt[0] = code; pkt[1] = id; pkt[2] = (len + 4) >> 8; pkt[3] = (len + 4) & 0xff;
|
||||
memcpy(pkt + 4, opts, len);
|
||||
ppp_send(proto, pkt, len + 4);
|
||||
}
|
||||
|
||||
static void send_conf_req(struct ncp *n)
|
||||
{
|
||||
uint8_t opts[16];
|
||||
size_t len = 0;
|
||||
if (n == &ipcp) {
|
||||
struct in_addr a;
|
||||
inet_aton(GW_IP, &a);
|
||||
opts[len++] = 3; opts[len++] = 6;
|
||||
memcpy(opts + len, &a, 4); len += 4;
|
||||
} else {
|
||||
opts[len++] = 5; opts[len++] = 6;
|
||||
uint32_t m = htonl(lcp_magic);
|
||||
memcpy(opts + len, &m, 4); len += 4;
|
||||
}
|
||||
send_ctl(n->proto, CONF_REQ, ++n->id, opts, len);
|
||||
n->last_req = time(NULL);
|
||||
}
|
||||
|
||||
static void guest_announce(void);
|
||||
|
||||
static void ncp_opened(struct ncp *n)
|
||||
{
|
||||
logm("%s ouvert", n->name);
|
||||
if (n == &lcp) {
|
||||
send_conf_req(&ipcp);
|
||||
} else {
|
||||
logm("lien IP prêt : iPod %s, passerelle %s, DNS %s", GUEST_IP, GW_IP, DNS_IP);
|
||||
guest_announce();
|
||||
}
|
||||
}
|
||||
|
||||
/* Traite une Configure-Request du pair : Ack / Nak / Rej, option par option (RFC 1661 §5.1) */
|
||||
static void handle_conf_req(struct ncp *n, uint8_t id, const uint8_t *opts, size_t len)
|
||||
{
|
||||
uint8_t ack[1500], nak[1500], rej[1500];
|
||||
size_t na = 0, nn = 0, nr = 0;
|
||||
struct in_addr want_ip, want_dns;
|
||||
inet_aton(GUEST_IP, &want_ip);
|
||||
inet_aton(DNS_IP, &want_dns);
|
||||
|
||||
for (size_t i = 0; i + 2 <= len;) {
|
||||
uint8_t type = opts[i], olen = opts[i + 1];
|
||||
if (olen < 2 || i + olen > len) {
|
||||
break;
|
||||
}
|
||||
const uint8_t *o = opts + i;
|
||||
int reject = 0, naked = 0;
|
||||
if (n == &lcp) {
|
||||
switch (type) {
|
||||
case 1: /* MRU */
|
||||
case 2: /* ACCM : on échappe de toute façon tous les caractères de contrôle */
|
||||
case 5: /* magic */
|
||||
case 7: /* PFC */
|
||||
case 8: /* ACFC */
|
||||
break;
|
||||
default: /* authentification, callback... */
|
||||
reject = 1;
|
||||
}
|
||||
} else {
|
||||
if ((type == 3 || type == 129 || type == 131) && olen == 6) {
|
||||
const struct in_addr *want = type == 3 ? &want_ip : &want_dns;
|
||||
if (memcmp(o + 2, want, 4)) {
|
||||
memcpy(nak + nn, o, 2);
|
||||
memcpy(nak + nn + 2, want, 4);
|
||||
nn += 6;
|
||||
naked = 1;
|
||||
}
|
||||
} else {
|
||||
reject = 1; /* compression VJ, NBNS... */
|
||||
}
|
||||
}
|
||||
if (reject) {
|
||||
memcpy(rej + nr, o, olen); nr += olen;
|
||||
} else if (!naked) {
|
||||
memcpy(ack + na, o, olen); na += olen;
|
||||
}
|
||||
i += olen;
|
||||
}
|
||||
if (nr) {
|
||||
send_ctl(n->proto, CONF_REJ, id, rej, nr);
|
||||
} else if (nn) {
|
||||
send_ctl(n->proto, CONF_NAK, id, nak, nn);
|
||||
} else {
|
||||
int was_open = is_open(n);
|
||||
send_ctl(n->proto, CONF_ACK, id, ack, na);
|
||||
n->acked_peer = 1;
|
||||
if (!n->acked_ours) {
|
||||
send_conf_req(n);
|
||||
}
|
||||
if (!was_open && is_open(n)) {
|
||||
ncp_opened(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_ctl(struct ncp *n, const uint8_t *p, size_t len)
|
||||
{
|
||||
if (len < 4) {
|
||||
return;
|
||||
}
|
||||
uint8_t code = p[0], id = p[1];
|
||||
size_t plen = (p[2] << 8) | p[3];
|
||||
if (plen < 4 || plen > len) {
|
||||
return;
|
||||
}
|
||||
const uint8_t *data = p + 4;
|
||||
size_t dlen = plen - 4;
|
||||
if (verbose) {
|
||||
logm("%s <- code %d id %d len %zu", n->name, code, id, dlen);
|
||||
}
|
||||
|
||||
switch (code) {
|
||||
case CONF_REQ:
|
||||
if (n == &lcp && is_open(&lcp)) { /* renégociation : tout repart de zéro */
|
||||
lcp.acked_ours = 0;
|
||||
ipcp.acked_peer = ipcp.acked_ours = 0;
|
||||
}
|
||||
if (n == &ipcp && !is_open(&lcp)) {
|
||||
return;
|
||||
}
|
||||
handle_conf_req(n, id, data, dlen);
|
||||
break;
|
||||
case CONF_ACK:
|
||||
if (id == n->id && !n->acked_ours) {
|
||||
n->acked_ours = 1;
|
||||
if (is_open(n)) {
|
||||
ncp_opened(n);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CONF_NAK:
|
||||
case CONF_REJ:
|
||||
/* nos options sont minimales : on les renvoie sans l'option refusée */
|
||||
send_ctl(n->proto, CONF_REQ, ++n->id, NULL, 0);
|
||||
break;
|
||||
case TERM_REQ:
|
||||
send_ctl(n->proto, TERM_ACK, id, NULL, 0);
|
||||
logm("%s fermé par l'iPod", n->name);
|
||||
n->acked_peer = n->acked_ours = 0;
|
||||
if (n == &lcp) {
|
||||
ipcp.acked_peer = ipcp.acked_ours = 0;
|
||||
}
|
||||
break;
|
||||
case ECHO_REQ:
|
||||
if (n == &lcp && dlen >= 4) {
|
||||
uint8_t rep[1500];
|
||||
uint32_t m = htonl(lcp_magic);
|
||||
memcpy(rep, &m, 4);
|
||||
memcpy(rep + 4, data + 4, dlen - 4);
|
||||
send_ctl(PROTO_LCP, ECHO_REP, id, rep, dlen);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- IP <-> slirp (trames Ethernet fictives) ---------- */
|
||||
|
||||
static void log_ip(const char *dir, const uint8_t *ip, size_t len)
|
||||
{
|
||||
if (!verbose || len < 20) return;
|
||||
char a[16], b[16];
|
||||
snprintf(a, sizeof a, "%d.%d.%d.%d", ip[12], ip[13], ip[14], ip[15]);
|
||||
snprintf(b, sizeof b, "%d.%d.%d.%d", ip[16], ip[17], ip[18], ip[19]);
|
||||
int ihl = (ip[0] & 0xf) * 4, proto = ip[9];
|
||||
if (proto == 1 && len > (size_t)ihl + 1) logm("%s ICMP %s -> %s type %d code %d", dir, a, b, ip[ihl], ip[ihl + 1]);
|
||||
else if ((proto == 6 || proto == 17) && len >= (size_t)ihl + 4)
|
||||
logm("%s %s %s:%d -> %s:%d len %zu", dir, proto == 6 ? "TCP" : "UDP", a, (ip[ihl] << 8) | ip[ihl + 1], b, (ip[ihl + 2] << 8) | ip[ihl + 3], len);
|
||||
else logm("%s proto %d %s -> %s", dir, proto, a, b);
|
||||
}
|
||||
|
||||
static void slirp_ip_input(const uint8_t *ip, size_t len)
|
||||
{
|
||||
log_ip("iPod ->", ip, len);
|
||||
uint8_t frame[14 + 2048];
|
||||
if (len > 2048) {
|
||||
return;
|
||||
}
|
||||
memcpy(frame, slirp_mac, 6);
|
||||
memcpy(frame + 6, guest_mac, 6);
|
||||
frame[12] = 0x08; frame[13] = 0x00;
|
||||
memcpy(frame + 14, ip, len);
|
||||
slirp_input(slirp, frame, len + 14);
|
||||
}
|
||||
|
||||
static void arp_packet(uint16_t op, const uint8_t *dst_mac, const uint8_t *target_ip)
|
||||
{
|
||||
uint8_t f[42];
|
||||
struct in_addr gip;
|
||||
inet_aton(GUEST_IP, &gip);
|
||||
memcpy(f, dst_mac, 6);
|
||||
memcpy(f + 6, guest_mac, 6);
|
||||
f[12] = 0x08; f[13] = 0x06;
|
||||
f[14] = 0; f[15] = 1; f[16] = 8; f[17] = 0; f[18] = 6; f[19] = 4;
|
||||
f[20] = 0; f[21] = op;
|
||||
memcpy(f + 22, guest_mac, 6);
|
||||
memcpy(f + 28, &gip, 4);
|
||||
memcpy(f + 32, op == 2 ? dst_mac : (const uint8_t *)"\0\0\0\0\0\0", 6);
|
||||
memcpy(f + 38, target_ip, 4);
|
||||
slirp_input(slirp, f, sizeof f);
|
||||
}
|
||||
|
||||
/* ARP gratuit : slirp apprend l'adresse MAC de l'iPod */
|
||||
static void guest_announce(void)
|
||||
{
|
||||
static const uint8_t bcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
struct in_addr gw;
|
||||
inet_aton(GW_IP, &gw);
|
||||
arp_packet(1, bcast, (const uint8_t *)&gw);
|
||||
}
|
||||
|
||||
static slirp_ssize_t slirp_send(const void *buf, size_t len, void *opaque)
|
||||
{
|
||||
const uint8_t *f = buf;
|
||||
if (len < 14) {
|
||||
return len;
|
||||
}
|
||||
uint16_t type = (f[12] << 8) | f[13];
|
||||
if (type == 0x0806 && len >= 42 && f[21] == 1) {
|
||||
struct in_addr gip;
|
||||
inet_aton(GUEST_IP, &gip);
|
||||
if (!memcmp(f + 38, &gip, 4)) {
|
||||
arp_packet(2, f + 22, f + 28);
|
||||
}
|
||||
} else if (type == 0x0800 && is_open(&ipcp)) {
|
||||
log_ip("-> iPod", f + 14, len - 14);
|
||||
ppp_send(PROTO_IP, f + 14, len - 14);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/* ---------- réception PPP ---------- */
|
||||
|
||||
static void ppp_frame(uint8_t *p, size_t len)
|
||||
{
|
||||
if (len < 4 || fcs16(0xffff, p, len) != 0xf0b8) {
|
||||
if (verbose && len) {
|
||||
logm("trame invalide (%zu octets)", len);
|
||||
}
|
||||
return;
|
||||
}
|
||||
len -= 2;
|
||||
if (len >= 2 && p[0] == 0xff && p[1] == 0x03) {
|
||||
p += 2; len -= 2;
|
||||
}
|
||||
if (!len) {
|
||||
return;
|
||||
}
|
||||
uint16_t proto;
|
||||
if (p[0] & 1) {
|
||||
proto = p[0]; p += 1; len -= 1;
|
||||
} else {
|
||||
if (len < 2) {
|
||||
return;
|
||||
}
|
||||
proto = (p[0] << 8) | p[1]; p += 2; len -= 2;
|
||||
}
|
||||
switch (proto) {
|
||||
case PROTO_LCP:
|
||||
handle_ctl(&lcp, p, len);
|
||||
break;
|
||||
case PROTO_IPCP:
|
||||
if (is_open(&lcp)) {
|
||||
handle_ctl(&ipcp, p, len);
|
||||
}
|
||||
break;
|
||||
case PROTO_IP:
|
||||
if (is_open(&ipcp)) {
|
||||
slirp_ip_input(p, len);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (is_open(&lcp)) { /* IPV6CP, CCP... : Protocol-Reject */
|
||||
uint8_t rej[1500];
|
||||
size_t n = len > 1400 ? 1400 : len;
|
||||
rej[0] = proto >> 8; rej[1] = proto & 0xff;
|
||||
memcpy(rej + 2, p, n);
|
||||
send_ctl(PROTO_LCP, PROTO_REJ, ++lcp.id, rej, n + 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void uart_input(const uint8_t *buf, size_t n)
|
||||
{
|
||||
static uint8_t frame[4096];
|
||||
static size_t flen;
|
||||
static int esc;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
uint8_t c = buf[i];
|
||||
if (c == 0x7e) {
|
||||
ppp_frame(frame, flen);
|
||||
flen = 0; esc = 0;
|
||||
} else if (c == 0x7d) {
|
||||
esc = 1;
|
||||
} else {
|
||||
if (esc) {
|
||||
c ^= 0x20; esc = 0;
|
||||
}
|
||||
if (flen < sizeof frame) {
|
||||
frame[flen++] = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- boucle principale, timers slirp ---------- */
|
||||
|
||||
struct timer { SlirpTimerCb cb; void *cb_opaque; SlirpTimerId id; int by_id; int64_t expire; int used; };
|
||||
static struct timer timers[16];
|
||||
|
||||
static int64_t now_ns(void)
|
||||
{
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return ts.tv_sec * 1000000000LL + ts.tv_nsec;
|
||||
}
|
||||
|
||||
static int64_t cb_clock(void *o) { return now_ns(); }
|
||||
static void cb_guest_error(const char *msg, void *o) { logm("slirp : %s", msg); }
|
||||
static void cb_notify(void *o) {}
|
||||
static void cb_register_poll_fd(int fd, void *o) {} /* on repasse tous les sockets à poll() à chaque tour */
|
||||
static void cb_unregister_poll_fd(int fd, void *o) {}
|
||||
|
||||
static struct timer *timer_alloc(void)
|
||||
{
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (!timers[i].used) {
|
||||
memset(&timers[i], 0, sizeof timers[i]);
|
||||
timers[i].used = 1;
|
||||
timers[i].expire = -1;
|
||||
return &timers[i];
|
||||
}
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
static void *cb_timer_new(SlirpTimerCb cb, void *cb_opaque, void *o)
|
||||
{
|
||||
struct timer *t = timer_alloc();
|
||||
t->cb = cb; t->cb_opaque = cb_opaque;
|
||||
return t;
|
||||
}
|
||||
|
||||
static void *cb_timer_new_opaque(SlirpTimerId id, void *cb_opaque, void *o)
|
||||
{
|
||||
struct timer *t = timer_alloc();
|
||||
t->id = id; t->by_id = 1; t->cb_opaque = cb_opaque;
|
||||
return t;
|
||||
}
|
||||
|
||||
static void cb_timer_free(void *t, void *o) { ((struct timer *)t)->used = 0; }
|
||||
static void cb_timer_mod(void *t, int64_t expire_ms, void *o) { ((struct timer *)t)->expire = expire_ms; }
|
||||
|
||||
static struct pollfd pfds[1024];
|
||||
static int npfds;
|
||||
|
||||
static int add_poll(slirp_os_socket fd, int events, void *o)
|
||||
{
|
||||
short ev = 0;
|
||||
if (events & SLIRP_POLL_IN) ev |= POLLIN;
|
||||
if (events & SLIRP_POLL_OUT) ev |= POLLOUT;
|
||||
if (events & SLIRP_POLL_PRI) ev |= POLLPRI;
|
||||
pfds[npfds].fd = fd;
|
||||
pfds[npfds].events = ev;
|
||||
pfds[npfds].revents = 0;
|
||||
return npfds++;
|
||||
}
|
||||
|
||||
static int get_revents(int idx, void *o)
|
||||
{
|
||||
short r = pfds[idx].revents;
|
||||
int ev = 0;
|
||||
if (r & POLLIN) ev |= SLIRP_POLL_IN;
|
||||
if (r & POLLOUT) ev |= SLIRP_POLL_OUT;
|
||||
if (r & POLLPRI) ev |= SLIRP_POLL_PRI;
|
||||
if (r & POLLERR) ev |= SLIRP_POLL_ERR;
|
||||
if (r & POLLHUP) ev |= SLIRP_POLL_HUP;
|
||||
return ev;
|
||||
}
|
||||
|
||||
static int uart_connect(void)
|
||||
{
|
||||
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
struct sockaddr_un a = { .sun_family = AF_UNIX };
|
||||
strncpy(a.sun_path, sock_path, sizeof a.sun_path - 1);
|
||||
if (connect(fd, (struct sockaddr *)&a, sizeof a) < 0) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
static void add_fwd(const char *spec)
|
||||
{
|
||||
char buf[128], *parts[3];
|
||||
int n = 0;
|
||||
strncpy(buf, spec, sizeof buf - 1);
|
||||
buf[sizeof buf - 1] = 0;
|
||||
for (char *t = strtok(buf, ":"); t && n < 3; t = strtok(NULL, ":")) {
|
||||
parts[n++] = t;
|
||||
}
|
||||
struct in_addr host, guest;
|
||||
inet_aton("127.0.0.1", &host);
|
||||
inet_aton(GUEST_IP, &guest);
|
||||
int hp, gp;
|
||||
if (n == 3) {
|
||||
inet_aton(parts[0], &host);
|
||||
hp = atoi(parts[1]); gp = atoi(parts[2]);
|
||||
} else if (n == 2) {
|
||||
hp = atoi(parts[0]); gp = atoi(parts[1]);
|
||||
} else {
|
||||
fprintf(stderr, "redirection invalide : %s\n", spec);
|
||||
exit(1);
|
||||
}
|
||||
if (slirp_add_hostfwd(slirp, 0, host, hp, guest, gp) < 0) {
|
||||
logm("redirection %s impossible (port occupé ?)", spec);
|
||||
/* Ne pas laisser le client contacter le relais d'une autre session. */
|
||||
exit(1);
|
||||
} else {
|
||||
logm("redirection tcp %s:%d -> iPod:%d", inet_ntoa(host), hp, gp);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
const char *fwds[32];
|
||||
int nfwd = 0;
|
||||
static char default_sock[512];
|
||||
snprintf(default_sock, sizeof default_sock, "%s/ipod-emu/run/uart1.sock", getenv("HOME"));
|
||||
sock_path = default_sock;
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "-s") && i + 1 < argc) sock_path = argv[++i];
|
||||
else if (!strcmp(argv[i], "-L") && i + 1 < argc && nfwd < 32) fwds[nfwd++] = argv[++i];
|
||||
else if (!strcmp(argv[i], "-v")) verbose = 1;
|
||||
else { fprintf(stderr, "usage: %s [-s uart1.sock] [-L [addr:]hostport:guestport]... [-v]\n", argv[0]); return 1; }
|
||||
}
|
||||
if (!nfwd) fwds[nfwd++] = "127.0.0.1:7788:7788";
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
fcs_init();
|
||||
|
||||
SlirpConfig cfg = { 0 };
|
||||
cfg.version = 4;
|
||||
cfg.in_enabled = true;
|
||||
inet_aton("10.0.2.0", &cfg.vnetwork);
|
||||
inet_aton("255.255.255.0", &cfg.vnetmask);
|
||||
inet_aton(GW_IP, &cfg.vhost);
|
||||
inet_aton(DNS_IP, &cfg.vnameserver);
|
||||
inet_aton(GUEST_IP, &cfg.vdhcp_start);
|
||||
cfg.vhostname = "ipod-emu-host";
|
||||
cfg.if_mtu = 1500;
|
||||
cfg.if_mru = 1500;
|
||||
static const SlirpCb cb = {
|
||||
.send_packet = slirp_send, .guest_error = cb_guest_error, .clock_get_ns = cb_clock,
|
||||
.timer_new = cb_timer_new, .timer_free = cb_timer_free, .timer_mod = cb_timer_mod,
|
||||
.notify = cb_notify, .timer_new_opaque = cb_timer_new_opaque,
|
||||
.register_poll_fd = cb_register_poll_fd, .unregister_poll_fd = cb_unregister_poll_fd,
|
||||
};
|
||||
slirp = slirp_new(&cfg, &cb, NULL);
|
||||
for (int i = 0; i < nfwd; i++) add_fwd(fwds[i]);
|
||||
|
||||
for (;;) {
|
||||
if (uart < 0) {
|
||||
uart = uart_connect();
|
||||
if (uart < 0) {
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
logm("connecté à %s, en attente de pppd", sock_path);
|
||||
lcp.acked_peer = lcp.acked_ours = ipcp.acked_peer = ipcp.acked_ours = 0;
|
||||
}
|
||||
|
||||
uint32_t timeout = 1000;
|
||||
npfds = 0;
|
||||
int uidx = add_poll(uart, SLIRP_POLL_IN, NULL);
|
||||
slirp_pollfds_fill_socket(slirp, &timeout, add_poll, NULL);
|
||||
int64_t now_ms = now_ns() / 1000000;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (timers[i].used && timers[i].expire >= 0) {
|
||||
int64_t d = timers[i].expire - now_ms;
|
||||
if (d < 0) d = 0;
|
||||
if (d < timeout) timeout = d;
|
||||
}
|
||||
}
|
||||
int r = poll(pfds, npfds, timeout);
|
||||
slirp_pollfds_poll(slirp, r < 0, get_revents, NULL);
|
||||
|
||||
now_ms = now_ns() / 1000000;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
struct timer *t = &timers[i];
|
||||
if (t->used && t->expire >= 0 && t->expire <= now_ms) {
|
||||
t->expire = -1;
|
||||
if (t->by_id) slirp_handle_timer(slirp, t->id, t->cb_opaque);
|
||||
else t->cb(t->cb_opaque);
|
||||
}
|
||||
}
|
||||
|
||||
if (r > 0 && (pfds[uidx].revents & (POLLIN | POLLHUP | POLLERR))) {
|
||||
uint8_t buf[4096];
|
||||
ssize_t n = read(uart, buf, sizeof buf);
|
||||
if (n <= 0) {
|
||||
logm("UART déconnectée (émulateur arrêté ?)");
|
||||
close(uart);
|
||||
uart = -1;
|
||||
continue;
|
||||
}
|
||||
uart_input(buf, n);
|
||||
}
|
||||
|
||||
/* relance des Configure-Request non acquittées */
|
||||
time_t t = time(NULL);
|
||||
if (is_open(&lcp) && !ipcp.acked_ours && t - ipcp.last_req >= 2) send_conf_req(&ipcp);
|
||||
if (lcp.acked_peer && !lcp.acked_ours && t - lcp.last_req >= 2) send_conf_req(&lcp);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface LabController : UIViewController {
|
||||
UILabel *counterLabel;
|
||||
NSInteger count;
|
||||
}
|
||||
- (void)increment;
|
||||
- (void)resetCount;
|
||||
@end
|
||||
@implementation LabController
|
||||
- (void)save {
|
||||
counterLabel.text=[NSString stringWithFormat:@"%ld",(long)count];
|
||||
NSString *state=[NSString stringWithFormat:@"count=%ld\n",(long)count];
|
||||
[state writeToFile:@"/var/mobile/Library/Caches/SimulatorLab-result.txt" atomically:YES encoding:NSUTF8StringEncoding error:NULL];
|
||||
NSLog(@"SimulatorLab count=%ld",(long)count);
|
||||
}
|
||||
- (void)increment { count++; [self save]; }
|
||||
- (void)resetCount { count=0; [self save]; }
|
||||
- (void)loadView {
|
||||
UIView *v=[[UIView alloc] initWithFrame:CGRectMake(0,0,320,460)];
|
||||
v.backgroundColor=[UIColor colorWithRed:0.92 green:0.94 blue:0.97 alpha:1]; self.view=v; [v release];
|
||||
UILabel *title=[[[UILabel alloc] initWithFrame:CGRectMake(20,30,280,45)] autorelease];
|
||||
title.text=@"Simulator Lab";title.font=[UIFont boldSystemFontOfSize:28];title.textAlignment=NSTextAlignmentCenter;title.backgroundColor=[UIColor clearColor];[self.view addSubview:title];
|
||||
UILabel *subtitle=[[[UILabel alloc] initWithFrame:CGRectMake(20,80,280,30)] autorelease];subtitle.text=@"Application native · iOS 6";subtitle.textAlignment=NSTextAlignmentCenter;subtitle.backgroundColor=[UIColor clearColor];[self.view addSubview:subtitle];
|
||||
counterLabel=[[UILabel alloc] initWithFrame:CGRectMake(20,130,280,100)];counterLabel.font=[UIFont boldSystemFontOfSize:64];counterLabel.textAlignment=NSTextAlignmentCenter;counterLabel.backgroundColor=[UIColor clearColor];[self.view addSubview:counterLabel];
|
||||
UIButton *plus=[UIButton buttonWithType:UIButtonTypeRoundedRect];plus.frame=CGRectMake(40,250,240,55);[plus setTitle:@"Ajouter +1" forState:UIControlStateNormal];[plus addTarget:self action:@selector(increment) forControlEvents:UIControlEventTouchUpInside];[self.view addSubview:plus];
|
||||
UIButton *reset=[UIButton buttonWithType:UIButtonTypeRoundedRect];reset.frame=CGRectMake(40,325,240,45);[reset setTitle:@"Remettre à zéro" forState:UIControlStateNormal];[reset addTarget:self action:@selector(resetCount) forControlEvents:UIControlEventTouchUpInside];[self.view addSubview:reset];
|
||||
[self save];
|
||||
}
|
||||
- (void)dealloc { [counterLabel release];[super dealloc]; }
|
||||
@end
|
||||
@interface LabApp : NSObject <UIApplicationDelegate> { UIWindow *window; }
|
||||
@end
|
||||
@implementation LabApp
|
||||
- (void)applicationDidFinishLaunching:(UIApplication *)app {
|
||||
window=[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
|
||||
LabController *vc=[[LabController alloc] init];
|
||||
window.rootViewController=vc;[vc release];[window makeKeyAndVisible];
|
||||
NSLog(@"SimulatorLab ready");
|
||||
}
|
||||
@end
|
||||
int main(int argc,char **argv) { NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init]; int r=UIApplicationMain(argc,argv,nil,@"LabApp");[pool release];return r; }
|
||||
Executable
+4
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
sim_root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
|
||||
exec "$sim_root/.venv/bin/python" "$sim_root/tools/simulator.py" "$@"
|
||||
@@ -0,0 +1,291 @@
|
||||
// Fenêtre macOS pour la VM iOS 6 : affiche l'écran via le VNC local de QEMU
|
||||
// et transmet la souris et le clavier à l'agent invité (127.0.0.1:7796).
|
||||
import AppKit
|
||||
|
||||
let vncPort: UInt16 = 5906
|
||||
let agentPort: UInt16 = 7796
|
||||
|
||||
// MARK: - Sockets bloquantes
|
||||
|
||||
final class Socket {
|
||||
let fd: Int32
|
||||
init?(port: UInt16) {
|
||||
fd = socket(AF_INET, SOCK_STREAM, 0)
|
||||
if fd < 0 { return nil }
|
||||
var one: Int32 = 1
|
||||
setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &one, socklen_t(MemoryLayout<Int32>.size))
|
||||
var addr = sockaddr_in()
|
||||
addr.sin_family = sa_family_t(AF_INET)
|
||||
addr.sin_port = port.bigEndian
|
||||
addr.sin_addr.s_addr = inet_addr("127.0.0.1")
|
||||
let ok = withUnsafePointer(to: &addr) {
|
||||
$0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
|
||||
connect(fd, $0, socklen_t(MemoryLayout<sockaddr_in>.size)) == 0
|
||||
}
|
||||
}
|
||||
if !ok { close(fd); return nil }
|
||||
}
|
||||
deinit { close(fd) }
|
||||
func read(_ n: Int) throws -> [UInt8] {
|
||||
var out = [UInt8](repeating: 0, count: n)
|
||||
var got = 0
|
||||
while got < n {
|
||||
let r = out.withUnsafeMutableBytes { recv(fd, $0.baseAddress! + got, n - got, 0) }
|
||||
if r <= 0 { throw POSIXError(.ECONNRESET) }
|
||||
got += r
|
||||
}
|
||||
return out
|
||||
}
|
||||
func readInto(_ buffer: UnsafeMutableRawPointer, _ n: Int) throws {
|
||||
var got = 0
|
||||
while got < n {
|
||||
let r = recv(fd, buffer + got, n - got, 0)
|
||||
if r <= 0 { throw POSIXError(.ECONNRESET) }
|
||||
got += r
|
||||
}
|
||||
}
|
||||
func write(_ bytes: [UInt8]) throws {
|
||||
var sent = 0
|
||||
while sent < bytes.count {
|
||||
let r = bytes.withUnsafeBytes { send(fd, $0.baseAddress! + sent, bytes.count - sent, 0) }
|
||||
if r <= 0 { throw POSIXError(.EPIPE) }
|
||||
sent += r
|
||||
}
|
||||
}
|
||||
func readLine() throws -> String {
|
||||
var line = [UInt8]()
|
||||
while true {
|
||||
let c = try read(1)[0]
|
||||
if c == 10 { return String(decoding: line, as: UTF8.self) }
|
||||
line.append(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func u16(_ b: [UInt8], _ i: Int) -> Int { Int(b[i]) << 8 | Int(b[i + 1]) }
|
||||
func u32(_ b: [UInt8], _ i: Int) -> Int { u16(b, i) << 16 | u16(b, i + 2) }
|
||||
func be16(_ v: Int) -> [UInt8] { [UInt8(v >> 8 & 0xff), UInt8(v & 0xff)] }
|
||||
|
||||
// MARK: - Agent invité
|
||||
|
||||
final class Agent {
|
||||
private let queue = DispatchQueue(label: "agent")
|
||||
private var warnedKeyboard = false
|
||||
/// Envoie une commande de l'agent ; les gestes sont exécutés dans l'ordre.
|
||||
func send(_ fields: [String]) {
|
||||
queue.async {
|
||||
guard let s = Socket(port: agentPort) else { return }
|
||||
do {
|
||||
try s.write(Array((fields.joined(separator: "\t") + "\n").utf8))
|
||||
let header = try s.readLine().split(separator: " ", maxSplits: 2).map(String.init)
|
||||
let size = header.count > 1 ? Int(header[1]) ?? 0 : 0
|
||||
let body = String(decoding: try s.read(size), as: UTF8.self)
|
||||
if header.first == "ERR" {
|
||||
if body.contains("commande inconnue") {
|
||||
if !self.warnedKeyboard { self.warnedKeyboard = true; NSLog("Clavier indisponible : l'agent n'a pas encore text/key") }
|
||||
} else { NSLog("Agent : %@", body) }
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Client VNC (encodage brut)
|
||||
|
||||
final class VNCClient {
|
||||
var onFrame: ((CGImage?) -> Void)?
|
||||
private var width = 0, height = 0
|
||||
private var pixels = [UInt8]()
|
||||
|
||||
func run() {
|
||||
Thread.detachNewThread { [weak self] in
|
||||
while let self {
|
||||
try? self.session()
|
||||
DispatchQueue.main.async { self.onFrame?(nil) }
|
||||
Thread.sleep(forTimeInterval: 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func session() throws {
|
||||
guard let s = Socket(port: vncPort) else { return }
|
||||
_ = try s.read(12)
|
||||
try s.write(Array("RFB 003.008\n".utf8))
|
||||
let count = Int(try s.read(1)[0])
|
||||
guard count > 0, try s.read(count).contains(1) else { return }
|
||||
try s.write([1])
|
||||
guard try s.read(4) == [0, 0, 0, 0] else { return }
|
||||
try s.write([1]) // connexion partagée
|
||||
let initMsg = try s.read(24)
|
||||
resize(u16(initMsg, 0), u16(initMsg, 2))
|
||||
_ = try s.read(u32(initMsg, 20))
|
||||
// 32 bpp, profondeur 24, little-endian, rouge << 16 : octets BGRX.
|
||||
try s.write([0, 0, 0, 0, 32, 24, 0, 1, 0, 255, 0, 255, 0, 255, 16, 8, 0, 0, 0, 0])
|
||||
try s.write([2, 0] + be16(2) + [0, 0, 0, 0] + [0xff, 0xff, 0xff, 0x21]) // brut, DesktopSize
|
||||
try request(s, incremental: false)
|
||||
while true {
|
||||
let type = try s.read(1)[0]
|
||||
switch type {
|
||||
case 0:
|
||||
let head = try s.read(3)
|
||||
for _ in 0..<u16(head, 1) {
|
||||
let r = try s.read(12)
|
||||
let x = u16(r, 0), y = u16(r, 2), w = u16(r, 4), h = u16(r, 6)
|
||||
let encoding = Int32(bitPattern: UInt32(u32(r, 8)))
|
||||
if encoding == -223 { resize(w, h); continue }
|
||||
guard encoding == 0 else { return }
|
||||
try readRect(s, x, y, w, h)
|
||||
}
|
||||
publish()
|
||||
try request(s, incremental: true)
|
||||
case 1:
|
||||
let head = try s.read(5)
|
||||
_ = try s.read(6 * u16(head, 3))
|
||||
case 2: break
|
||||
case 3:
|
||||
let head = try s.read(7)
|
||||
_ = try s.read(u32(head, 3))
|
||||
default: return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func resize(_ w: Int, _ h: Int) {
|
||||
width = w; height = h
|
||||
pixels = [UInt8](repeating: 0, count: w * h * 4)
|
||||
}
|
||||
|
||||
private func readRect(_ s: Socket, _ x: Int, _ y: Int, _ w: Int, _ h: Int) throws {
|
||||
guard x + w <= width, y + h <= height else { throw POSIXError(.EINVAL) }
|
||||
try pixels.withUnsafeMutableBytes { buf in
|
||||
for row in 0..<h {
|
||||
try s.readInto(buf.baseAddress! + ((y + row) * width + x) * 4, w * 4)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func request(_ s: Socket, incremental: Bool) throws {
|
||||
try s.write([3, incremental ? 1 : 0, 0, 0, 0, 0] + be16(width) + be16(height))
|
||||
}
|
||||
|
||||
private func publish() {
|
||||
let data = Data(pixels) as CFData
|
||||
guard let provider = CGDataProvider(data: data) else { return }
|
||||
let info = CGBitmapInfo(rawValue: CGImageAlphaInfo.noneSkipFirst.rawValue | CGBitmapInfo.byteOrder32Little.rawValue)
|
||||
let image = CGImage(width: width, height: height, bitsPerComponent: 8, bitsPerPixel: 32,
|
||||
bytesPerRow: width * 4, space: CGColorSpaceCreateDeviceRGB(), bitmapInfo: info,
|
||||
provider: provider, decode: nil, shouldInterpolate: false, intent: .defaultIntent)
|
||||
DispatchQueue.main.async { self.onFrame?(image) }
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Vue de l'écran
|
||||
|
||||
final class ScreenView: NSView {
|
||||
let agent = Agent()
|
||||
var screenSize = CGSize(width: 320, height: 480)
|
||||
private var press: (CGPoint, Date)?
|
||||
|
||||
override var isFlipped: Bool { true }
|
||||
override var acceptsFirstResponder: Bool { true }
|
||||
override func acceptsFirstMouse(for event: NSEvent?) -> Bool { true }
|
||||
|
||||
func show(_ image: CGImage?) {
|
||||
wantsLayer = true
|
||||
layer?.backgroundColor = NSColor.black.cgColor
|
||||
layer?.contentsGravity = .resize
|
||||
layer?.magnificationFilter = .nearest
|
||||
layer?.contents = image
|
||||
if let image { screenSize = CGSize(width: image.width, height: image.height) }
|
||||
}
|
||||
|
||||
private func guestPoint(_ event: NSEvent) -> CGPoint {
|
||||
let p = convert(event.locationInWindow, from: nil)
|
||||
let x = min(max(p.x / bounds.width * screenSize.width, 0), screenSize.width - 1)
|
||||
let y = min(max(p.y / bounds.height * screenSize.height, 0), screenSize.height - 1)
|
||||
return CGPoint(x: x.rounded(), y: y.rounded())
|
||||
}
|
||||
|
||||
override func mouseDown(with event: NSEvent) { press = (guestPoint(event), Date()) }
|
||||
|
||||
override func mouseUp(with event: NSEvent) {
|
||||
guard let (start, time) = press else { return }
|
||||
press = nil
|
||||
var end = guestPoint(event)
|
||||
var ms = Int(Date().timeIntervalSince(time) * 1000)
|
||||
if abs(end.x - start.x) < 6 && abs(end.y - start.y) < 6 { end = start }
|
||||
ms = min(max(ms, 96), 5000)
|
||||
agent.send(["touch", "\(Int(start.x))", "\(Int(start.y))", "\(Int(end.x))", "\(Int(end.y))", "\(ms)"])
|
||||
}
|
||||
|
||||
override func rightMouseDown(with event: NSEvent) { agent.send(["home"]) }
|
||||
|
||||
override func keyDown(with event: NSEvent) {
|
||||
switch event.keyCode {
|
||||
case 53: agent.send(["home"]) // Échap
|
||||
case 36, 76: agent.send(["key", "return"])
|
||||
case 51: agent.send(["key", "backspace"])
|
||||
case 48: agent.send(["key", "tab"])
|
||||
default:
|
||||
guard let text = event.characters, !text.isEmpty,
|
||||
!event.modifierFlags.contains(.command),
|
||||
text.unicodeScalars.allSatisfy({ $0.value >= 0x20 && $0.value != 0x7f && $0.value < 0xf700 })
|
||||
else { return super.keyDown(with: event) }
|
||||
agent.send(["text", text])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Application
|
||||
|
||||
final class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
var window: NSWindow!
|
||||
let vnc = VNCClient()
|
||||
|
||||
func applicationDidFinishLaunching(_ note: Notification) {
|
||||
let view = ScreenView(frame: NSRect(x: 0, y: 0, width: 320, height: 480))
|
||||
view.show(nil)
|
||||
window = NSWindow(contentRect: view.frame, styleMask: [.titled, .closable, .miniaturizable, .resizable],
|
||||
backing: .buffered, defer: false)
|
||||
window.title = "iOS 6"
|
||||
window.contentView = view
|
||||
window.contentAspectRatio = NSSize(width: 320, height: 480)
|
||||
window.setContentSize(NSSize(width: 320, height: 480))
|
||||
window.center()
|
||||
window.makeKeyAndOrderFront(nil)
|
||||
window.makeFirstResponder(view)
|
||||
buildMenu(view)
|
||||
vnc.onFrame = { [weak view] image in view?.show(image) }
|
||||
vnc.run()
|
||||
NSApp.activate(ignoringOtherApps: true)
|
||||
}
|
||||
|
||||
func applicationShouldTerminateAfterLastWindowClosed(_ app: NSApplication) -> Bool { true }
|
||||
|
||||
private func buildMenu(_ view: ScreenView) {
|
||||
let main = NSMenu()
|
||||
let appItem = NSMenuItem(); main.addItem(appItem)
|
||||
let appMenu = NSMenu()
|
||||
appMenu.addItem(withTitle: "Quitter", action: #selector(NSApplication.terminate(_:)), keyEquivalent: "q")
|
||||
appItem.submenu = appMenu
|
||||
let deviceItem = NSMenuItem(); main.addItem(deviceItem)
|
||||
let device = NSMenu(title: "Appareil")
|
||||
for (title, key, action) in [("Home", "h", #selector(home)), ("Taille réelle", "1", #selector(size1)), ("Taille ×2", "2", #selector(size2))] {
|
||||
let item = device.addItem(withTitle: title, action: action, keyEquivalent: key)
|
||||
item.keyEquivalentModifierMask = [.command, .shift]
|
||||
item.target = self
|
||||
}
|
||||
deviceItem.submenu = device
|
||||
NSApp.mainMenu = main
|
||||
}
|
||||
|
||||
@objc func home() { (window.contentView as? ScreenView)?.agent.send(["home"]) }
|
||||
@objc func size1() { window.setContentSize(NSSize(width: 320, height: 480)) }
|
||||
@objc func size2() { window.setContentSize(NSSize(width: 640, height: 960)) }
|
||||
}
|
||||
|
||||
let app = NSApplication.shared
|
||||
let delegate = AppDelegate()
|
||||
app.delegate = delegate
|
||||
app.setActivationPolicy(.regular)
|
||||
app.run()
|
||||
@@ -0,0 +1,3 @@
|
||||
meson>=1.0,<2
|
||||
distlib>=0.3,<1
|
||||
capstone>=5,<6
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"kernel_entry": "0x80086084",
|
||||
"physical_entry": "0x40086084",
|
||||
"kernel_bytes": 12083200,
|
||||
"boot_args_bytes": 320,
|
||||
"devicetree_bytes": 57764,
|
||||
"kernel_patches": [],
|
||||
"command_line": "-v debug=0x14e serial=3 rd=md0 keepsyms=1"
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
[
|
||||
"/home/dev/ios6-emu/build/qemu-system-arm",
|
||||
"-M",
|
||||
"ios6-n88",
|
||||
"-kernel",
|
||||
"/home/dev/ios6-emu/firmware/kernel.bin",
|
||||
"-dtb",
|
||||
"/home/dev/ios6-emu/firmware/boot-data.bin",
|
||||
"-initrd",
|
||||
"/home/dev/ios6-emu/firmware/RestoreRamdisk.dec",
|
||||
"-display",
|
||||
"none",
|
||||
"-serial",
|
||||
"file:/home/dev/ios6-emu/evidence/probe-20261003T101443-261760Z/serial.log",
|
||||
"-monitor",
|
||||
"none",
|
||||
"-qmp",
|
||||
"unix:/home/dev/ios6-emu/evidence/probe-20261003T101443-261760Z/qmp,server=on,wait=off",
|
||||
"-d",
|
||||
"unimp,guest_errors,in_asm,int",
|
||||
"-D",
|
||||
"/home/dev/ios6-emu/evidence/probe-20261003T101443-261760Z/qemu.log",
|
||||
"-no-reboot"
|
||||
]
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"ipsw_url": "https://secure-appldnld.apple.com/iOS6.1/091-3457.20140221.Btt3e/iPhone2,1_6.1.6_10B500_Restore.ipsw",
|
||||
"ipsw_sha256": "37a4b3bb0cbc0cc4c94f4ec2987f23c9207644c2669084084c4a78e8325e6b91",
|
||||
"keys_url": "https://raw.githubusercontent.com/LukeZGD/Legacy-iOS-Kit-Keys/af6bf5934dc61ed557a967a3f42ab7fb8ed8c45e/iPhone2,1/10B500/index.html",
|
||||
"components": {
|
||||
"Kernelcache": {
|
||||
"member": "kernelcache.release.n88",
|
||||
"bytes": 11821056,
|
||||
"sha256": "ec4787ac012567f9c10ba2d5ab611058545bce7e17cd95ef310eba94bfca9b78"
|
||||
},
|
||||
"DeviceTree": {
|
||||
"member": "Firmware/all_flash/all_flash.n88ap.production/DeviceTree.n88ap.img3",
|
||||
"bytes": 57856,
|
||||
"sha256": "6608eba10d4a1086a4d3f5d299b8b9582bcb27262206152ea4029ca1a25718ad"
|
||||
},
|
||||
"RestoreRamdisk": {
|
||||
"member": "048-2889-001.dmg",
|
||||
"bytes": 13459456,
|
||||
"sha256": "e5c7eff45a0e36b7f6fdda9246bc8c0ff0561d4cedd615035f3ebe23c3d235e8"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"qemu_base": "6cdda3bc1326f0ae54f40e2b852372dcc4921565",
|
||||
"qemu_local": "/srv/homes/iphoneos2/qemu-ios",
|
||||
"qemu_upstream": "https://github.com/devos50/qemu-ios",
|
||||
"hardware_reference": "https://github.com/iDroid-Project/openiBoot/tree/master/plat-s5l8920",
|
||||
"boot_args_reference": "https://github.com/apple-oss-distributions/xnu/blob/main/pexpert/pexpert/arm/boot.h",
|
||||
"firmware_metadata": "https://api.ipsw.me/v4/device/iPhone2,1?type=ipsw",
|
||||
"note": "Les adresses MMIO du prototype sont recoup\u00e9es avec le DeviceTree Apple 10B500/n88."
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"run": "/home/dev/ios6-emu/evidence/probe-20261003T101443-261760Z",
|
||||
"seconds": 10.0,
|
||||
"status": {
|
||||
"status": "paused",
|
||||
"singlestep": false,
|
||||
"running": false
|
||||
},
|
||||
"registers": "\r\nCPU#0\r\nR00=cae2b9a8 R01=00000000 R02=800895a4 R03=802dc000\r\nR04=cae2b9a8 R05=802ffd88 R06=cae2b9a8 R07=cae2b998\r\nR08=802ffcc0 R09=3b9ac9ff R10=00000001 R11=cae2baa0\r\nR12=c00d9200 R13=cae2b994 R14=8001732f R15=800895a8\r\nPSR=a00000d3 N-C- A svc32\r\ns00=00000000 s01=00000000 d00=0000000000000000\r\ns02=00000000 s03=00000000 d01=0000000000000000\r\ns04=00000000 s05=00000000 d02=0000000000000000\r\ns06=00000000 s07=00000000 d03=0000000000000000\r\ns08=00000000 s09=00000000 d04=0000000000000000\r\ns10=00000000 s11=00000000 d05=0000000000000000\r\ns12=00000000 s13=00000000 d06=0000000000000000\r\ns14=00000000 s15=00000000 d07=0000000000000000\r\ns16=00000000 s17=00000000 d08=0000000000000000\r\ns18=00000000 s19=00000000 d09=0000000000000000\r\ns20=00000000 s21=00000000 d10=0000000000000000\r\ns22=00000000 s23=00000000 d11=0000000000000000\r\ns24=00000000 s25=00000000 d12=0000000000000000\r\ns26=00000000 s27=00000000 d13=0000000000000000\r\ns28=00000000 s29=00000000 d14=0000000000000000\r\ns30=00000000 s31=00000000 d15=0000000000000000\r\ns32=00000000 s33=00000000 d16=0000000000000000\r\ns34=00000000 s35=00000000 d17=0000000000000000\r\ns36=00000000 s37=00000000 d18=0000000000000000\r\ns38=00000000 s39=00000000 d19=0000000000000000\r\ns40=00000000 s41=00000000 d20=0000000000000000\r\ns42=00000000 s43=00000000 d21=0000000000000000\r\ns44=00000000 s45=00000000 d22=0000000000000000\r\ns46=00000000 s47=00000000 d23=0000000000000000\r\ns48=00000000 s49=00000000 d24=0000000000000000\r\ns50=00000000 s51=00000000 d25=0000000000000000\r\ns52=00000000 s53=00000000 d26=0000000000000000\r\ns54=00000000 s55=00000000 d27=0000000000000000\r\ns56=00000000 s57=00000000 d28=0000000000000000\r\ns58=00000000 s59=00000000 d29=0000000000000000\r\ns60=00000000 s61=00000000 d30=0000000000000000\r\ns62=00000000 s63=00000000 d31=0000000000000000\r\nFPSCR: 03000000\r\n",
|
||||
"instructions": "0xffffffff800895a8: Asm output not supported on this arch\r\n",
|
||||
"stack": "cae2b994: 0x8030037c 0xcae2b9c0 0x8000d071 0x0e58154a\r\ncae2b9a4: 0x00000000 0x0e57d1c6 0x00000000 0xcae2baec\r\ncae2b9b4: 0x802ffcc0 0x00000000 0x802ffcb0 0xcae2ba48\r\ncae2b9c4: 0x8000c6a3 0x802d4580 0x00000000 0x802ffd88\r\ncae2b9d4: 0x00000001 0x00000000 0x00000000 0x00000001\r\ncae2b9e4: 0x834baab8 0x8334ae80 0x80327c80 0x833375d0\r\ncae2b9f4: 0x80326708 0x834baa80 0xcae2ba30 0xcae2ba08\r\ncae2ba04: 0x8027c470 0xcae2ba18 0x8027c42c 0x802ffca0\r\n",
|
||||
"returncode": 0,
|
||||
"guest_status": "kernel-panic",
|
||||
"panic": "panic(cpu 0 caller 0x8065f7ed): \"ARM7M not stopped for some reason\"",
|
||||
"milestones": {
|
||||
"serial_console": true,
|
||||
"crypto_self_tests": true,
|
||||
"platform_driver": true,
|
||||
"interrupt_controller_driver": true,
|
||||
"userspace_confirmed": false
|
||||
},
|
||||
"expected_panic_matched": true
|
||||
}
|
||||
@@ -0,0 +1,955 @@
|
||||
iBoot version: ios6-emu direct-kernel prototype
|
||||
corecrypto kext started!
|
||||
Running kernel space in FIPS MODE
|
||||
Plist hmac value is 9fd77803e256b61c91d83182dfb9aee94e57b18702a272b6a206fb074ca8e541
|
||||
Computed hmac value is 9fd77803e256b61c91d83182dfb9aee94e57b18702a272b6a206fb074ca8e541
|
||||
corecrypto.kext FIPS integrity POST test passed!
|
||||
corecrypto.kext FIPS AES CBC POST test passed!
|
||||
corecrypto.kext FIPS TDES CBC POST test passed!
|
||||
corecrypto.kext FIPS SHA POST test passed!
|
||||
corecrypto.kext FIPS HMAC POST test passed!
|
||||
corecrypto.kext FIPS ECDSA POST test passed!
|
||||
corecrypto.kext FIPS DRBG POST test passed!
|
||||
corecrypto.kext FIPS POST passed!
|
||||
AppleS5L8920XIO::start: chip-revision: A0
|
||||
AppleARMPL192VIC::start: _vicBaseAddress = 0xcc44d000
|
||||
AppleS5L8920XGPIOIC::start: gpioicBaseAddress: 0xc4dc6000
|
||||
AppleARMPerformanceController::traceBufferEnable: Trace is enabled
|
||||
AppleS5L8920XPerformanceController::start: _pcBaseAddress: 0xc4dcd000 _pcMCUBaseAddress: 0xc4dd5000
|
||||
AppleARMPerformanceController configured with 1 Performance Domains
|
||||
Performance Domain 0 : pcVoltageStateCount: 3 pcPerformanceStateCount: 4
|
||||
Voltage State 0 : .vsPerformanceLimit: /2 .vsDeviceConstraint: 1ff8ffef ffff8fff
|
||||
Voltage State 1 : .vsPerformanceLimit: /2 .vsDeviceConstraint: 1ffeffff ffff8fff
|
||||
Voltage State 2 : .vsPerformanceLimit: /1 .vsDeviceConstraint: 1fffffff ffff8fff
|
||||
Performance State 0 : .psPerformanceDivider: /1 .psVoltageRequired: 2 .psDeviceConstraint: 1fffffff ffff8fff
|
||||
Performance State 1 : .psPerformanceDivider: /2 .psVoltageRequired: 0 .psDeviceConstraint: 1ffeb5ff ffe78fff
|
||||
Performance State 2 : .psPerformanceDivider: /4 .psVoltageRequired: 0 .psDeviceConstraint: 1ffe24ff ffe78fff
|
||||
Performance State 3 : .psPerformanceDivider: /8 .psVoltageRequired: 0 .psDeviceConstraint: 1ffe20df ffe78fff
|
||||
AppleARMPerformanceController: Dynamic Performance State Management Enabled on Performance Domain 0
|
||||
AppleARMPerformanceController: Dynamic Voltage Control Enabled on Performance Domain 0 with 10000us activity timeout and 100us grace period
|
||||
IOSDIOController::init(): IOSDIOFamily-34 Feb 13 2013 21:35:31 @ 0x833db700
|
||||
AppleIOPSDIO::start(): AppleIOPSDIO-12 Feb 13 2013 22:17:01
|
||||
AppleBaseband::start(0x83407dc0): baseband
|
||||
AppleARMBacklight::start: Backlight calibration data 0
|
||||
Couldn't alloc class "AppleRawIOAddressSpace"
|
||||
+ AppleM2ScalerCSCDriver[0x83505f00]::start(provider 0x8339e480)
|
||||
AppleH2CamIn::start
|
||||
AppleH2CamIn::start, fSensorExtClkFunction = 0x83371CC0
|
||||
AppleH2CamIn::start, fSensorShutdownFunction = 0x83383BA0
|
||||
AppleH2CamIn::start, fISPResetFunction = 0x83357180
|
||||
+ H264EncDriver: start (provider 0x8339e300)
|
||||
+ H264EncDriver: compiled on Feb 13 2013 22:32:00
|
||||
AppleVXD375 - start (provider 0x8339e280)
|
||||
AppleVXD375 - compiled on Feb 13 2013 22:32:12
|
||||
AppleARMIICController::start buffer=0x8345a300 entries=8
|
||||
AppleS5L8920XI2CController::start: i2c0 _i2cBaseAddress: 0xcae0d000
|
||||
AppleARMIICController::start buffer=0x8345a280 entries=8
|
||||
AppleS5L8920XI2CController::start: i2c2 _i2cBaseAddress: 0xcae0e000
|
||||
AppleS5L8920XPWM::start: _pwmBaseAddress: 0xcae15000
|
||||
AppleSamsungLP65USBPhy::start: hsic disabled
|
||||
AppleSamsungMIPIDSIController::start: _dsimBaseAddress = 0xcae16000
|
||||
AppleSamsungSWI::start: _swiBaseAddress: 0x00000000cae1d000
|
||||
AppleSamsungSWI::start: _swiBaseAddress: _swiWorstCaseIntraVBUCK=0
|
||||
AppleS5L8920XAudioComplex::start: audio-complex audioAHBMemoryMap: 0x83592840 audioAPBMemoryMap: 0x835927e8 ncoRef: 0
|
||||
AppleS5L8920XI2SController::start: i2s0 i2sBaseAddress: 0xcae25000
|
||||
AppleS5L8920XI2SController::start: i2s1 i2sBaseAddress: 0xcae26000
|
||||
AppleS5L8920XI2SController::start: i2s2 i2sBaseAddress: 0xcae2d000
|
||||
AppleSamsungSerial: Identified Serial Port on ARM Device=uart0 at 0x82500000(0xcae3d000)
|
||||
AppleSamsungSerial: Identified Serial Port on ARM Device=uart4 at 0x82900000(0xcae45000)
|
||||
ARM7M::start: mapped I/O registers at 0xcaded000/0x86300000, 0xcadee000/0xbf300000
|
||||
IOP::start: starting IOP (DEBUG) @ 0x835f7d80
|
||||
IOP::_prepareFirmwareImage: EmbeddedIOP firmware s5l8920x-RELEASE iBoot-1537.9.55
|
||||
panic(cpu 0 caller 0x8065f7ed): "ARM7M not stopped for some reason"
|
||||
Debugger message: panic
|
||||
OS version: Not set yet
|
||||
Kernel version: Darwin Kernel Version 13.0.0: Wed Feb 13 21:35:42 PST 2013; root:xnu-2107.7.55.2.2~1/RELEASE_ARM_S5L8920X
|
||||
iBoot version: ios6-emu direct-kernel prototype
|
||||
secure boot?: NO
|
||||
Paniclog version: 1
|
||||
Epoch Time: sec usec
|
||||
Boot : 0x00000000 0x00000000
|
||||
Sleep : 0x00000000 0x00000000
|
||||
Wake : 0x00000000 0x00000000
|
||||
Calendar: 0x00000002 0x00016c10
|
||||
|
||||
Task 0xc048ec20: 1578 pages, 79 threads: pid 0: kernel_task
|
||||
thread 0xc04ab2a0
|
||||
kernel backtrace: cae2bd30
|
||||
lr: 0x80089f41 fp: 0xcae2bd60
|
||||
lr: 0x8008a7dd fp: 0xcae2bd8c
|
||||
lr: 0x80017ca7 fp: 0xcae2bda4
|
||||
lr: 0x8065f7ed fp: 0xcae2bdcc
|
||||
lr: 0x809391f1 fp: 0xcae2bde8
|
||||
lr: 0x80939a7d fp: 0xcae2be04
|
||||
lr: 0x8025914f fp: 0xcae2be2c
|
||||
lr: 0x80939a4f fp: 0xcae2be48
|
||||
lr: 0x8065ab17 fp: 0xcae2be54
|
||||
lr: 0x80898e1f fp: 0xcae2be60
|
||||
lr: 0x80898c03 fp: 0xcae2be94
|
||||
lr: 0x808989d5 fp: 0xcae2bea8
|
||||
lr: 0x80896673 fp: 0xcae2bed8
|
||||
lr: 0x80249b47 fp: 0xcae2bf10
|
||||
lr: 0x802497c3 fp: 0xcae2bf60
|
||||
lr: 0x8024a299 fp: 0xcae2bf88
|
||||
lr: 0x8024a06b fp: 0xcae2bfa8
|
||||
lr: 0x8008805c fp: 0x00000000
|
||||
|
||||
Debugger message: panic
|
||||
OS version: Not set yet
|
||||
Kernel version: Darwin Kernel Version 13.0.0: Wed Feb 13 21:35:42 PST 2013; root:xnu-2107.7.55.2.2~1/RELEASE_ARM_S5L8920X
|
||||
iBoot version: ios6-emu direct-kernel prototype
|
||||
secure boot?: NO
|
||||
Paniclog version: 1
|
||||
Epoch Time: sec usec
|
||||
Boot : 0x00000000 0x00000000
|
||||
Sleep : 0x00000000 0x00000000
|
||||
Wake : 0x00000000 0x00000000
|
||||
Calendar: 0x00000002 0x0001a537
|
||||
|
||||
|
||||
********* Dumping thread state and stacks *********
|
||||
|
||||
Task 0xc048ec20: 1578 pages, 79 threads: pid 0: kernel_task
|
||||
thread 0x80302670
|
||||
kernel state:
|
||||
r0: 0x00000000 r1: 0x00000000 r2: 0x00000000 r3: 0x00000000
|
||||
r4: 0x0199268f r5: 0xc04a48f0 r6: 0x00000000 r7: 0xc4dbbda4
|
||||
r8: 0x00000000 r9: 0x0000c000 r10: 0x80329838 r11: 0x80302670
|
||||
r12: 0x800880a0 sp: 0xc4dbbd78 lr: 0x80024cab pc: 0x00000000
|
||||
cpsr: 0x00000093 fsr: 0x00000000 far: 0x00000000
|
||||
kernel backtrace: c4dbbda4
|
||||
lr: 0x800244d9 fp: 0xc4dbbdd0
|
||||
lr: 0x8001eddd fp: 0xc4dbbdf0
|
||||
lr: 0x80240693 fp: 0xc4dbbe10
|
||||
lr: 0x8024b055 fp: 0xc4dbbe40
|
||||
lr: 0x80249ea3 fp: 0xc4dbbe50
|
||||
lr: 0x80240b0f fp: 0xc4dbbe60
|
||||
lr: 0x802bbce7 fp: 0xc4dbbf9c
|
||||
lr: 0x800271e9 fp: 0xc4dbbfa8
|
||||
lr: 0x8008805c fp: 0x00000000
|
||||
|
||||
thread 0xc04ad990
|
||||
kernel continuation: 0x800256c9
|
||||
|
||||
thread 0xc04ad400
|
||||
kernel continuation: 0x80022059
|
||||
|
||||
thread 0xc04ace70
|
||||
kernel continuation: 0x8002cf39
|
||||
|
||||
thread 0xc04ac8e0
|
||||
kernel continuation: 0x8002d135
|
||||
|
||||
thread 0xc04ac350
|
||||
kernel continuation: 0x8002fc65
|
||||
|
||||
thread 0xc04abdc0
|
||||
kernel state:
|
||||
r0: 0x00000000 r1: 0x00000000 r2: 0x00000000 r3: 0x00000000
|
||||
r4: 0x01be7e71 r5: 0xc04a9c60 r6: 0x00000000 r7: 0xc4debf40
|
||||
r8: 0x00000000 r9: 0x00000000 r10: 0x80329838 r11: 0xc04abdc0
|
||||
r12: 0x800880a0 sp: 0xc4debf14 lr: 0x80024cab pc: 0x00000000
|
||||
cpsr: 0x00000093 fsr: 0x00000000 far: 0x00000000
|
||||
kernel backtrace: c4debf40
|
||||
lr: 0x800244d9 fp: 0xc4debf6c
|
||||
lr: 0x80033173 fp: 0xc4debfa8
|
||||
lr: 0x8008805c fp: 0x00000000
|
||||
|
||||
thread 0xc04ab830
|
||||
kernel continuation: 0x802582fd
|
||||
|
||||
thread 0xc04aa780
|
||||
kernel continuation: 0x802582fd
|
||||
|
||||
thread 0xc04a7b00
|
||||
kernel state:
|
||||
r0: 0x00000000 r1: 0x00000000 r2: 0x00000000 r3: 0x00000000
|
||||
r4: 0x01ea275f r5: 0xc058d990 r6: 0x00000000 r7: 0xcae4bd94
|
||||
r8: 0x00000000 r9: 0x0000c000 r10: 0x80329838 r11: 0xc04a7b00
|
||||
r12: 0x800880a0 sp: 0xcae4bd68 lr: 0x80024cab pc: 0x00000000
|
||||
cpsr: 0x00000093 fsr: 0x00000000 far: 0x00000000
|
||||
kernel backtrace: cae4bd94
|
||||
lr: 0x800244d9 fp: 0xcae4bdc0
|
||||
lr: 0x8001ed6d fp: 0xcae4bdd8
|
||||
lr: 0x80240655 fp: 0xcae4bdf0
|
||||
lr: 0x8024b01d fp: 0xcae4be20
|
||||
lr: 0x80249ea3 fp: 0xcae4be30
|
||||
lr: 0x804ac80d fp: 0xcae4be64
|
||||
lr: 0x804ac789 fp: 0xcae4be74
|
||||
lr: 0x80988693 fp: 0xcae4bebc
|
||||
lr: 0x8076a53f fp: 0xcae4bed8
|
||||
lr: 0x80249b47 fp: 0xcae4bf10
|
||||
lr: 0x802497c3 fp: 0xcae4bf60
|
||||
lr: 0x8024a299 fp: 0xcae4bf88
|
||||
lr: 0x8024a06b fp: 0xcae4bfa8
|
||||
lr: 0x8008805c fp: 0x00000000
|
||||
|
||||
thread 0xc04a7570
|
||||
kernel state:
|
||||
r0: 0x00000000 r1: 0x00000000 r2: 0x00000000 r3: 0x00000000
|
||||
r4: 0x02a97213 r5: 0xc04a2200 r6: 0x00000000 r7: 0xcae53dd8
|
||||
r8: 0x00000000 r9: 0x00000000 r10: 0x80329838 r11: 0xc04a7570
|
||||
r12: 0x800880a0 sp: 0xcae53dac lr: 0x80024cab pc: 0x00000000
|
||||
cpsr: 0x00000093 fsr: 0x00000000 far: 0x00000000
|
||||
kernel backtrace: cae53dd8
|
||||
lr: 0x800244d9 fp: 0xcae53e04
|
||||
lr: 0x8001ed6d fp: 0xcae53e1c
|
||||
lr: 0x802642b3 fp: 0xcae53e30
|
||||
lr: 0x8024bf13 fp: 0xcae53e4c
|
||||
lr: 0x8024bff7 fp: 0xcae53e64
|
||||
lr: 0x8024c097 fp: 0xcae53e80
|
||||
lr: 0x80258a9f fp: 0xcae53ea0
|
||||
lr: 0x80258b7b fp: 0xcae53ec4
|
||||
lr: 0x8079a32f fp: 0xcae53ed8
|
||||
lr: 0x80249b47 fp: 0xcae53f10
|
||||
lr: 0x802497c3 fp: 0xcae53f60
|
||||
lr: 0x8024a299 fp: 0xcae53f88
|
||||
lr: 0x8024a06b fp: 0xcae53fa8
|
||||
lr: 0x8008805c fp: 0x00000000
|
||||
|
||||
thread 0xc04a6a50
|
||||
kernel state:
|
||||
r0: 0x00000000 r1: 0x00000000 r2: 0x00000000 r3: 0x00000000
|
||||
r4: 0x01f30645 r5: 0xc04a64c0 r6: 0x00000000 r7: 0xcae63d4c
|
||||
r8: 0x00000000 r9: 0x00000000 r10: 0x80329838 r11: 0xc04a6a50
|
||||
r12: 0x800880a0 sp: 0xcae63d20 lr: 0x80024cab pc: 0x00000000
|
||||
cpsr: 0x00000093 fsr: 0x00000000 far: 0x00000000
|
||||
kernel backtrace: cae63d4c
|
||||
lr: 0x800244d9 fp: 0xcae63d78
|
||||
lr: 0x8001ed6d fp: 0xcae63d90
|
||||
lr: 0x80240655 fp: 0xcae63da8
|
||||
lr: 0x8024b01d fp: 0xcae63dd8
|
||||
lr: 0x80249ea3 fp: 0xcae63de8
|
||||
lr: 0x804ac80d fp: 0xcae63e1c
|
||||
lr: 0x804ac789 fp: 0xcae63e2c
|
||||
lr: 0x80a548c5 fp: 0xcae63e7c
|
||||
lr: 0x80a55f99 fp: 0xcae63ec4
|
||||
lr: 0x80a565ad fp: 0xcae63ed8
|
||||
lr: 0x80249b47 fp: 0xcae63f10
|
||||
lr: 0x802497c3 fp: 0xcae63f60
|
||||
lr: 0x8024a299 fp: 0xcae63f88
|
||||
lr: 0x8024a06b fp: 0xcae63fa8
|
||||
lr: 0x8008805c fp: 0x00000000
|
||||
|
||||
thread 0xc04a64c0
|
||||
kernel state:
|
||||
r0: 0x00000000 r1: 0x00000000 r2: 0x00000000 r3: 0x00000000
|
||||
r4: 0x01f49395 r5: 0xc058ce70 r6: 0x00000000 r7: 0xcae6bd8c
|
||||
r8: 0x00000000 r9: 0x0000c000 r10: 0x80329838 r11: 0xc04a64c0
|
||||
r12: 0x800880a0 sp: 0xcae6bd60 lr: 0x80024cab pc: 0x00000000
|
||||
cpsr: 0x00000093 fsr: 0x00000000 far: 0x00000000
|
||||
kernel backtrace: cae6bd8c
|
||||
lr: 0x800244d9 fp: 0xcae6bdb8
|
||||
lr: 0x8001ed6d fp: 0xcae6bdd0
|
||||
lr: 0x80240655 fp: 0xcae6bde8
|
||||
lr: 0x8024b01d fp: 0xcae6be1c
|
||||
lr: 0x80249ea3 fp: 0xcae6be2c
|
||||
lr: 0x804ac80d fp: 0xcae6be60
|
||||
lr: 0x804ac789 fp: 0xcae6be70
|
||||
lr: 0x804bbde3 fp: 0xcae6bed8
|
||||
lr: 0x80249b47 fp: 0xcae6bf10
|
||||
lr: 0x802497c3 fp: 0xcae6bf60
|
||||
lr: 0x8024a299 fp: 0xcae6bf88
|
||||
lr: 0x8024a06b fp: 0xcae6bfa8
|
||||
lr: 0x8008805c fp: 0x00000000
|
||||
|
||||
thread 0xc04a4e80
|
||||
kernel continuation: 0x8002fde1
|
||||
|
||||
thread 0xc04a48f0
|
||||
kernel continuation: 0x801e34a5
|
||||
|
||||
>>>>>>>>thread 0xc04ab2a0
|
||||
>>>>>>>> kernel backtrace: cae2bd60
|
||||
>>>>>>>> lr: 0x8008a7e5 fp: 0xcae2bd8c
|
||||
>>>>>>>> lr: 0x80017ca7 fp: 0xcae2bda4
|
||||
>>>>>>>> lr: 0x8065f7ed fp: 0xcae2bdcc
|
||||
>>>>>>>> lr: 0x809391f1 fp: 0xcae2bde8
|
||||
>>>>>>>> lr: 0x80939a7d fp: 0xcae2be04
|
||||
>>>>>>>> lr: 0x8025914f fp: 0xcae2be2c
|
||||
>>>>>>>> lr: 0x80939a4f fp: 0xcae2be48
|
||||
>>>>>>>> lr: 0x8065ab17 fp: 0xcae2be54
|
||||
>>>>>>>> lr: 0x80898e1f fp: 0xcae2be60
|
||||
>>>>>>>> lr: 0x80898c03 fp: 0xcae2be94
|
||||
>>>>>>>> lr: 0x808989d5 fp: 0xcae2bea8
|
||||
>>>>>>>> lr: 0x80896673 fp: 0xcae2bed8
|
||||
>>>>>>>> lr: 0x80249b47 fp: 0xcae2bf10
|
||||
>>>>>>>> lr: 0x802497c3 fp: 0xcae2bf60
|
||||
>>>>>>>> lr: 0x8024a299 fp: 0xcae2bf88
|
||||
>>>>>>>> lr: 0x8024a06b fp: 0xcae2bfa8
|
||||
>>>>>>>> lr: 0x8008805c fp: 0x00000000
|
||||
|
||||
thread 0xc04a3840
|
||||
kernel state:
|
||||
r0: 0x00000000 r1: 0x00000000 r2: 0x00000000 r3: 0x00000000
|
||||
r4: 0x02239bed r5: 0xc0588bb0 r6: 0x00000000 r7: 0xcae0be14
|
||||
r8: 0x00000000 r9: 0x00000000 r10: 0x80329838 r11: 0xc04a3840
|
||||
r12: 0x800880a0 sp: 0xcae0bde8 lr: 0x80024cab pc: 0x00000000
|
||||
cpsr: 0x00000093 fsr: 0x00000000 far: 0x00000000
|
||||
kernel backtrace: cae0be14
|
||||
lr: 0x800244d9 fp: 0xcae0be40
|
||||
lr: 0x8001ed6d fp: 0xcae0be58
|
||||
lr: 0x80240655 fp: 0xcae0be70
|
||||
lr: 0x8024b01d fp: 0xcae0bea0
|
||||
lr: 0x809e37d5 fp: 0xcae0bed8
|
||||
lr: 0x80249b47 fp: 0xcae0bf10
|
||||
lr: 0x802497c3 fp: 0xcae0bf60
|
||||
lr: 0x8024a299 fp: 0xcae0bf88
|
||||
lr: 0x8024a06b fp: 0xcae0bfa8
|
||||
lr: 0x8008805c fp: 0x00000000
|
||||
|
||||
thread 0xc04a32b0
|
||||
kernel state:
|
||||
r0: 0x79656b3c r1: 0x5064693e r2: 0x75646f72 r3: 0x2f3c7463
|
||||
r4: 0x022cc054 r5: 0xc04a2d20 r6: 0x00000000 r7: 0xcc363dcc
|
||||
r8: 0x00000000 r9: 0x00000000 r10: 0x80329838 r11: 0xc04a32b0
|
||||
r12: 0x800880a0 sp: 0xcc363da0 lr: 0x80024cab pc: 0x3c3e7265
|
||||
cpsr: 0x00000093 fsr: 0x6b3c3e74 far: 0x413e7965
|
||||
kernel backtrace: cc363dcc
|
||||
lr: 0x800244d9 fp: 0xcc363df8
|
||||
lr: 0x8001ed6d fp: 0xcc363e10
|
||||
lr: 0x80240655 fp: 0xcc363e28
|
||||
lr: 0x8024b01d fp: 0xcc363e58
|
||||
lr: 0x80249ea3 fp: 0xcc363e68
|
||||
lr: 0x80706d67 fp: 0xcc363e98
|
||||
lr: 0x809b5e75 fp: 0xcc363ed8
|
||||
lr: 0x80249b47 fp: 0xcc363f10
|
||||
lr: 0x802497c3 fp: 0xcc363f60
|
||||
lr: 0x8024a299 fp: 0xcc363f88
|
||||
lr: 0x8024a06b fp: 0xcc363fa8
|
||||
lr: 0x8008805c fp: 0x00000000
|
||||
|
||||
thread 0xc04a2d20
|
||||
kernel state:
|
||||
r0: 0x6b3c3e67 r1: 0x4e3e7965 r2: 0x6d754853 r3: 0x65526e61
|
||||
r4: 0x022e9b7b r5: 0xc05896d0 r6: 0x00000000 r7: 0xcc36be04
|
||||
r8: 0x00000000 r9: 0x0000c000 r10: 0x80329838 r11: 0xc04a2d20
|
||||
r12: 0x800880a0 sp: 0xcc36bdd8 lr: 0x80024cab pc: 0x322d3630
|
||||
cpsr: 0x00000093 fsr: 0x6c707041 far: 0x6e492065
|
||||
kernel backtrace: cc36be04
|
||||
lr: 0x800244d9 fp: 0xcc36be30
|
||||
lr: 0x8001ed6d fp: 0xcc36be48
|
||||
lr: 0x80240655 fp: 0xcc36be60
|
||||
lr: 0x8024b01d fp: 0xcc36be90
|
||||
lr: 0x80249ea3 fp: 0xcc36bea0
|
||||
lr: 0x806ed0c3 fp: 0xcc36bed8
|
||||
lr: 0x80249b47 fp: 0xcc36bf10
|
||||
lr: 0x802497c3 fp: 0xcc36bf60
|
||||
lr: 0x8024a299 fp: 0xcc36bf88
|
||||
lr: 0x8024a06b fp: 0xcc36bfa8
|
||||
lr: 0x8008805c fp: 0x00000000
|
||||
|
||||
thread 0xc04a2790
|
||||
kernel state:
|
||||
r0: 0x67616944 r1: 0x74736f6e r2: 0x61446369 r3: 0x63416174
|
||||
r4: 0x0230ec4b r5: 0xc04a2200 r6: 0x00000000 r7: 0xcc373dfc
|
||||
r8: 0x00000000 r9: 0x00000000 r10: 0x80329838 r11: 0xc04a2790
|
||||
r12: 0x800880a0 sp: 0xcc373dd0 lr: 0x80024cab pc: 0x656b2f3c
|
||||
cpsr: 0x00000093 fsr: 0x3e746369 far: 0x79656b3c
|
||||
kernel backtrace: cc373dfc
|
||||
lr: 0x800244d9 fp: 0xcc373e28
|
||||
lr: 0x8001ed6d fp: 0xcc373e40
|
||||
lr: 0x80240655 fp: 0xcc373e58
|
||||
lr: 0x8024b01d fp: 0xcc373e8c
|
||||
lr: 0x80249ea3 fp: 0xcc373e9c
|
||||
lr: 0x806d1d2b fp: 0xcc373ed8
|
||||
lr: 0x80249b47 fp: 0xcc373f10
|
||||
lr: 0x802497c3 fp: 0xcc373f60
|
||||
lr: 0x8024a299 fp: 0xcc373f88
|
||||
lr: 0x8024a06b fp: 0xcc373fa8
|
||||
lr: 0x8008805c fp: 0x00000000
|
||||
|
||||
thread 0xc04a2200
|
||||
kernel state:
|
||||
r0: 0x75415641 r1: 0x446f6964 r2: 0x65766972 r3: 0x6b2f3c72
|
||||
r4: 0x02a9d2fd r5: 0xc04a1c70 r6: 0x00000000 r7: 0xcc37be0c
|
||||
r8: 0x00000000 r9: 0x00000000 r10: 0x80329838 r11: 0xc04a2200
|
||||
r12: 0x800880a0 sp: 0xcc37bde0 lr: 0x80024cab pc: 0x76697244
|
||||
cpsr: 0x00000093 fsr: 0x69727473 far: 0x3c3e676e
|
||||
kernel backtrace: cc37be0c
|
||||
lr: 0x800244d9 fp: 0xcc37be38
|
||||
lr: 0x8001ed6d fp: 0xcc37be50
|
||||
lr: 0x80240655 fp: 0xcc37be68
|
||||
lr: 0x8024b01d fp: 0xcc37be98
|
||||
lr: 0x80249ea3 fp: 0xcc37bea8
|
||||
lr: 0x80b0cc4b fp: 0xcc37bed8
|
||||
lr: 0x80249b47 fp: 0xcc37bf10
|
||||
lr: 0x802497c3 fp: 0xcc37bf60
|
||||
lr: 0x8024a299 fp: 0xcc37bf88
|
||||
lr: 0x8024a06b fp: 0xcc37bfa8
|
||||
lr: 0x8008805c fp: 0x00000000
|
||||
|
||||
thread 0xc04a1c70
|
||||
kernel state:
|
||||
r0: 0x3c737361 r1: 0x79656b2f r2: 0x74733c3e r3: 0x676e6972
|
||||
r4: 0x02aa226e r5: 0xc04a16e0 r6: 0x00000000 r7: 0xcc383dfc
|
||||
r8: 0x00000000 r9: 0x00000000 r10: 0x80329838 r11: 0xc04a1c70
|
||||
r12: 0x800880a0 sp: 0xcc383dd0 lr: 0x80024cab pc: 0x6c707041
|
||||
cpsr: 0x00000093 fsr: 0x3c6c6562 far: 0x7274732f
|
||||
kernel backtrace: cc383dfc
|
||||
lr: 0x800244d9 fp: 0xcc383e28
|
||||
lr: 0x8001ed6d fp: 0xcc383e40
|
||||
lr: 0x80240655 fp: 0xcc383e58
|
||||
lr: 0x8024b01d fp: 0xcc383e8c
|
||||
lr: 0x80249ea3 fp: 0xcc383e9c
|
||||
lr: 0x80a8bf79 fp: 0xcc383ed8
|
||||
lr: 0x80249b47 fp: 0xcc383f10
|
||||
lr: 0x802497c3 fp: 0xcc383f60
|
||||
lr: 0x8024a299 fp: 0xcc383f88
|
||||
lr: 0x8024a06b fp: 0xcc383fa8
|
||||
lr: 0x8008805c fp: 0x00000000
|
||||
|
||||
thread 0xc04a16e0
|
||||
kernel state:
|
||||
r0: 0x2f3c7469 r1: 0x3e79656b r2: 0x7274733c r3: 0x20676e69
|
||||
r4: 0x02aac1ff r5: 0xc049b2c0 r6: 0x00000000 r7: 0xcc38be24
|
||||
r8: 0x00000000 r9: 0x0000c000 r10: 0x80329838 r11: 0xc04a16e0
|
||||
r12: 0x800880a0 sp: 0xcc38bdf8 lr: 0x80024cab pc: 0x74726f70
|
||||
cpsr: 0x00000093 fsr: 0x3e79656b far: 0x7274733c
|
||||
kernel backtrace: cc38be24
|
||||
lr: 0x800244d9 fp: 0xcc38be50
|
||||
lr: 0x8001ed6d fp: 0xcc38be68
|
||||
lr: 0x80240655 fp: 0xcc38be80
|
||||
lr: 0x8024b01d fp: 0xcc38beb0
|
||||
lr: 0x80249ea3 fp: 0xcc38bec0
|
||||
lr: 0x804e562f fp: 0xcc38bed8
|
||||
lr: 0x80249b47 fp: 0xcc38bf10
|
||||
lr: 0x802497c3 fp: 0xcc38bf60
|
||||
lr: 0x8024a299 fp: 0xcc38bf88
|
||||
lr: 0x8024a06b fp: 0xcc38bfa8
|
||||
lr: 0x8008805c fp: 0x00000000
|
||||
|
||||
thread 0xc04a0630
|
||||
kernel state:
|
||||
r0: 0x00000000 r1: 0x00000000 r2: 0x00000000 r3: 0x00000000
|
||||
r4: 0x02491bfa r5: 0xc058bdc0 r6: 0x00000000 r7: 0xcc3a3d7c
|
||||
r8: 0x00000000 r9: 0x0000c000 r10: 0x80329838 r11: 0xc04a0630
|
||||
r12: 0x800880a0 sp: 0xcc3a3d50 lr: 0x80024cab pc: 0x00000000
|
||||
cpsr: 0x00000093 fsr: 0x00000000 far: 0x00000000
|
||||
kernel backtrace: cc3a3d7c
|
||||
lr: 0x800244d9 fp: 0xcc3a3da8
|
||||
lr: 0x8001ed6d fp: 0xcc3a3dc0
|
||||
lr: 0x80240655 fp: 0xcc3a3dd8
|
||||
lr: 0x8024b01d fp: 0xcc3a3e0c
|
||||
lr: 0x80249ea3 fp: 0xcc3a3e1c
|
||||
lr: 0x8026935d fp: 0xcc3a3e5c
|
||||
lr: 0x80259ecd fp: 0xcc3a3e80
|
||||
lr: 0x80259f85 fp: 0xcc3a3ea8
|
||||
lr: 0x809502e5 fp: 0xcc3a3ec0
|
||||
lr: 0x80952279 fp: 0xcc3a3ecc
|
||||
lr: 0x80952631 fp: 0xcc3a3ed8
|
||||
lr: 0x80249b47 fp: 0xcc3a3f10
|
||||
lr: 0x802497c3 fp: 0xcc3a3f60
|
||||
lr: 0x8024a299 fp: 0xcc3a3f88
|
||||
lr: 0x8024a06b fp: 0xcc3a3fa8
|
||||
lr: 0x8008805c fp: 0x00000000
|
||||
|
||||
thread 0xc049fb10
|
||||
kernel state:
|
||||
r0: 0x00000000 r1: 0x00000000 r2: 0x00000000 r3: 0x00000000
|
||||
r4: 0x024d9ad5 r5: 0xc04aad10 r6: 0x00000000 r7: 0xcc3b3d3c
|
||||
r8: 0x00000000 r9: 0x0000c000 r10: 0x80329838 r11: 0xc049fb10
|
||||
r12: 0x800880a0 sp: 0xcc3b3d10 lr: 0x80024cab pc: 0x00000000
|
||||
cpsr: 0x00000093 fsr: 0x00000000 far: 0x00000000
|
||||
kernel backtrace: cc3b3d3c
|
||||
lr: 0x800244d9 fp: 0xcc3b3d68
|
||||
lr: 0x8001ed6d fp: 0xcc3b3d80
|
||||
lr: 0x80240655 fp: 0xcc3b3d98
|
||||
lr: 0x8024b01d fp: 0xcc3b3dc8
|
||||
lr: 0x80249ea3 fp: 0xcc3b3dd8
|
||||
lr: 0x8026935d fp: 0xcc3b3e18
|
||||
lr: 0x80259ecd fp: 0xcc3b3e3c
|
||||
lr: 0x80259f85 fp: 0xcc3b3e64
|
||||
lr: 0x8083bf8f fp: 0xcc3b3ed8
|
||||
lr: 0x80249b47 fp: 0xcc3b3f10
|
||||
lr: 0x802497c3 fp: 0xcc3b3f60
|
||||
lr: 0x8024a299 fp: 0xcc3b3f88
|
||||
lr: 0x8024a06b fp: 0xcc3b3fa8
|
||||
lr: 0x8008805c fp: 0x00000000
|
||||
|
||||
thread 0xc049f580
|
||||
kernel state:
|
||||
r0: 0x36223d65 r1: 0x303e2234 r2: 0x33303878 r3: 0x30303963
|
||||
r4: 0x024eb061 r5: 0xc058c8e0 r6: 0x00000000 r7: 0xcc3bbd3c
|
||||
r8: 0x00000000 r9: 0x0000c000 r10: 0x80329838 r11: 0xc049f580
|
||||
r12: 0x800880a0 sp: 0xcc3bbd10 lr: 0x80024cab pc: 0x73207265
|
||||
cpsr: 0x00000093 fsr: 0x22343622 far: 0x3878303e
|
||||
kernel backtrace: cc3bbd3c
|
||||
lr: 0x800244d9 fp: 0xcc3bbd68
|
||||
lr: 0x8001ed6d fp: 0xcc3bbd80
|
||||
lr: 0x80240655 fp: 0xcc3bbd98
|
||||
lr: 0x8024b01d fp: 0xcc3bbdc8
|
||||
lr: 0x80249ea3 fp: 0xcc3bbdd8
|
||||
lr: 0x8026935d fp: 0xcc3bbe18
|
||||
lr: 0x80259ecd fp: 0xcc3bbe3c
|
||||
lr: 0x80259f85 fp: 0xcc3bbe64
|
||||
lr: 0x8083bf8f fp: 0xcc3bbed8
|
||||
lr: 0x80249b47 fp: 0xcc3bbf10
|
||||
lr: 0x802497c3 fp: 0xcc3bbf60
|
||||
lr: 0x8024a299 fp: 0xcc3bbf88
|
||||
lr: 0x8024a06b fp: 0xcc3bbfa8
|
||||
lr: 0x8008805c fp: 0x00000000
|
||||
|
||||
thread 0xc049eff0
|
||||
kernel state:
|
||||
r0: 0x00000000 r1: 0x00000000 r2: 0x00000000 r3: 0x00000000
|
||||
r4: 0x025023bd r5: 0xc04a5410 r6: 0x00000000 r7: 0xcc3c3d3c
|
||||
r8: 0x00000000 r9: 0x0000c000 r10: 0x80329838 r11: 0xc049eff0
|
||||
r12: 0x800880a0 sp: 0xcc3c3d10 lr: 0x80024cab pc: 0x00000000
|
||||
cpsr: 0x00000093 fsr: 0x00000000 far: 0x00000000
|
||||
kernel backtrace: cc3c3d3c
|
||||
lr: 0x800244d9 fp: 0xcc3c3d68
|
||||
lr: 0x8001ed6d fp: 0xcc3c3d80
|
||||
lr: 0x80240655 fp: 0xcc3c3d98
|
||||
lr: 0x8024b01d fp: 0xcc3c3dc8
|
||||
lr: 0x80249ea3 fp: 0xcc3c3dd8
|
||||
lr: 0x8026935d fp: 0xcc3c3e18
|
||||
lr: 0x80259ecd fp: 0xcc3c3e3c
|
||||
lr: 0x80259f85 fp: 0xcc3c3e64
|
||||
lr: 0x8083bf8f fp: 0xcc3c3ed8
|
||||
lr: 0x80249b47 fp: 0xcc3c3f10
|
||||
lr: 0x802497c3 fp: 0xcc3c3f60
|
||||
lr: 0x8024a299 fp: 0xcc3c3f88
|
||||
lr: 0x8024a06b fp: 0xcc3c3fa8
|
||||
lr: 0x8008805c fp: 0x00000000
|
||||
|
||||
thread 0xc049ce90
|
||||
kernel state:
|
||||
r0: 0x00000000 r1: 0x00000000 r2: 0x00000000 r3: 0x00000000
|
||||
r4: 0x02a07426 r5: 0xc0586fe0 r6: 0x00000000 r7: 0xcc3f3de4
|
||||
r8: 0x00000000 r9: 0x00000000 r10: 0x80329838 r11: 0xc049ce90
|
||||
r12: 0x800880a0 sp: 0xcc3f3db8 lr: 0x80024cab pc: 0x00000000
|
||||
cpsr: 0x00000093 fsr: 0x00000000 far: 0x00000000
|
||||
kernel backtrace: cc3f3de4
|
||||
lr: 0x800244d9 fp: 0xcc3f3e10
|
||||
lr: 0x8001ed6d fp: 0xcc3f3e28
|
||||
lr: 0x80240655 fp: 0xcc3f3e40
|
||||
lr: 0x8024b01d fp: 0xcc3f3e70
|
||||
lr: 0x80249ea3 fp: 0xcc3f3e80
|
||||
lr: 0x804ac80d fp: 0xcc3f3eb4
|
||||
lr: 0x804ac789 fp: 0xcc3f3ec4
|
||||
lr: 0x80a6d51d fp: 0xcc3f3ed8
|
||||
lr: 0x80249b47 fp: 0xcc3f3f10
|
||||
lr: 0x802497c3 fp: 0xcc3f3f60
|
||||
lr: 0x8024a299 fp: 0xcc3f3f88
|
||||
lr: 0x8024a06b fp: 0xcc3f3fa8
|
||||
lr: 0x8008805c fp: 0x00000000
|
||||
|
||||
thread 0xc049bde0
|
||||
kernel state:
|
||||
r0: 0x00000000 r1: 0x00000000 r2: 0x00000000 r3: 0x00000000
|
||||
r4: 0x02654ead r5: 0xc049b850 r6: 0x00000000 r7: 0xcc40bdfc
|
||||
r8: 0x00000000 r9: 0x00000000 r10: 0x80329838 r11: 0xc049bde0
|
||||
r12: 0x800880a0 sp: 0xcc40bdd0 lr: 0x80024cab pc: 0x00000000
|
||||
cpsr: 0x00000093 fsr: 0x00000000 far: 0x00000000
|
||||
kernel backtrace: cc40bdfc
|
||||
lr: 0x800244d9 fp: 0xcc40be28
|
||||
lr: 0x8001ed6d fp: 0xcc40be40
|
||||
lr: 0x80240655 fp: 0xcc40be58
|
||||
lr: 0x8024b01d fp: 0xcc40be8c
|
||||
lr: 0x80249ea3 fp: 0xcc40be9c
|
||||
lr: 0x806d1d2b fp: 0xcc40bed8
|
||||
lr: 0x80249b47 fp: 0xcc40bf10
|
||||
lr: 0x802497c3 fp: 0xcc40bf60
|
||||
lr: 0x8024a299 fp: 0xcc40bf88
|
||||
lr: 0x8024a06b fp: 0xcc40bfa8
|
||||
lr: 0x8008805c fp: 0x00000000
|
||||
|
||||
thread 0xc04996f0
|
||||
kernel state:
|
||||
r0: 0x00000000 r1: 0x00000000 r2: 0x00000000 r3: 0x00000000
|
||||
r4: 0x02f76a91 r5: 0xc04ace70 r6: 0x00000000 r7: 0xcc443d64
|
||||
r8: 0x00000000 r9: 0x00000000 r10: 0x80329838 r11: 0xc04996f0
|
||||
r12: 0x800880a0 sp: 0xcc443d38 lr: 0x80024cab pc: 0x00000000
|
||||
cpsr: 0x00000093 fsr: 0x00000000 far: 0x00000000
|
||||
kernel backtrace: cc443d64
|
||||
lr: 0x800244d9 fp: 0xcc443d90
|
||||
lr: 0x8001ed6d fp: 0xcc443da8
|
||||
lr: 0x80240655 fp: 0xcc443dc0
|
||||
lr: 0x8024b01d fp: 0xcc443df0
|
||||
lr: 0x80249ea3 fp: 0xcc443e00
|
||||
lr: 0x8026935d fp: 0xcc443e40
|
||||
lr: 0x80259ecd fp: 0xcc443e64
|
||||
lr: 0x80259f85 fp: 0xcc443e8c
|
||||
lr: 0x808c9fe5 fp: 0xcc443eb8
|
||||
lr: 0x808c9e73 fp: 0xcc443ed8
|
||||
lr: 0x80249b47 fp: 0xcc443f10
|
||||
lr: 0x802497c3 fp: 0xcc443f60
|
||||
lr: 0x8024a299 fp: 0xcc443f88
|
||||
lr: 0x8024a06b fp: 0xcc443fa8
|
||||
lr: 0x8008805c fp: 0x00000000
|
||||
|
||||
thread 0xc0499160
|
||||
kernel state:
|
||||
r0: 0x00000000 r1: 0x00000000 r2: 0x00000000 r3: 0x00000000
|
||||
r4: 0x029df5a9 r5: 0xc0586a50 r6: 0x00000000 r7: 0xcc44bdfc
|
||||
r8: 0x00000000 r9: 0x0000c000 r10: 0x80329838 r11: 0xc0499160
|
||||
r12: 0x800880a0 sp: 0xcc44bdd0 lr: 0x80024cab pc: 0x00000000
|
||||
cpsr: 0x00000093 fsr: 0x00000000 far: 0x00000000
|
||||
kernel backtrace: cc44bdfc
|
||||
lr: 0x800244d9 fp: 0xcc44be28
|
||||
lr: 0x8001ed6d fp: 0xcc44be40
|
||||
lr: 0x80240655 fp: 0xcc44be58
|
||||
lr: 0x8024b01d fp: 0xcc44be8c
|
||||
lr: 0x80249ea3 fp: 0xcc44be9c
|
||||
lr: 0x80ac2227 fp: 0xcc44bed8
|
||||
lr: 0x80249b47 fp: 0xcc44bf10
|
||||
lr: 0x802497c3 fp: 0xcc44bf60
|
||||
lr: 0x8024a299 fp: 0xcc44bf88
|
||||
lr: 0x8024a06b fp: 0xcc44bfa8
|
||||
lr: 0x8008805c fp: 0x00000000
|
||||
|
||||
thread 0xc0498bd0
|
||||
kernel continuation: 0x802582fd
|
||||
|
||||
thread 0xc0498640
|
||||
kernel state:
|
||||
r0: 0x00000000 r1: 0x00000000 r2: 0x00000000 r3: 0x00000000
|
||||
r4: 0x02a96d0f r5: 0xc04a7570 r6: 0x00000000 r7: 0xcc4cbdf0
|
||||
r8: 0x00000000 r9: 0x00000000 r10: 0x80329838 r11: 0xc0498640
|
||||
r12: 0x800880a0 sp: 0xcc4cbdc4 lr: 0x80024cab pc: 0x00000000
|
||||
cpsr: 0x00000093 fsr: 0x00000000 far: 0x00000000
|
||||
kernel backtrace: cc4cbdf0
|
||||
lr: 0x800244d9 fp: 0xcc4cbe1c
|
||||
lr: 0x804b04f7 fp: 0xcc4cbe48
|
||||
lr: 0x8024715b fp: 0xcc4cbe70
|
||||
lr: 0x80668893 fp: 0xcc4cbebc
|
||||
lr: 0x808a284f fp: 0xcc4cbed8
|
||||
lr: 0x80249b47 fp: 0xcc4cbf10
|
||||
lr: 0x802497c3 fp: 0xcc4cbf60
|
||||
lr: 0x8024a299 fp: 0xcc4cbf88
|
||||
lr: 0x8024a06b fp: 0xcc4cbfa8
|
||||
lr: 0x8008805c fp: 0x00000000
|
||||
|
||||
thread 0xc04980b0
|
||||
kernel continuation: 0x802582fd
|
||||
|
||||
thread 0xc0497b20
|
||||
kernel continuation: 0x802582fd
|
||||
|
||||
thread 0xc0497590
|
||||
kernel continuation: 0x802582fd
|
||||
|
||||
thread 0xc0497000
|
||||
kernel state:
|
||||
r0: 0x00000000 r1: 0x00000000 r2: 0x00000000 r3: 0x00000000
|
||||
r4: 0x01e5bdb3 r5: 0xc04a7b00 r6: 0x00000000 r7: 0xcae5bf64
|
||||
r8: 0x00000000 r9: 0x00000000 r10: 0x80329838 r11: 0xc0497000
|
||||
r12: 0x800880a0 sp: 0xcae5bf38 lr: 0x80024cab pc: 0x00000000
|
||||
cpsr: 0x00000093 fsr: 0x00000000 far: 0x00000000
|
||||
kernel backtrace: cae5bf64
|
||||
lr: 0x800244d9 fp: 0xcae5bf90
|
||||
lr: 0x80258339 fp: 0xcae5bfa8
|
||||
lr: 0x8008805c fp: 0x00000000
|
||||
|
||||
thread 0xc058d990
|
||||
kernel continuation: 0x802582fd
|
||||
|
||||
thread 0xc058d400
|
||||
kernel continuation: 0x802582fd
|
||||
|
||||
thread 0xc058ce70
|
||||
kernel continuation: 0x802582fd
|
||||
|
||||
thread 0xc058ad10
|
||||
kernel continuation: 0x802582fd
|
||||
|
||||
thread 0xc0588bb0
|
||||
kernel continuation: 0x802582fd
|
||||
|
||||
thread 0xc0589140
|
||||
kernel state:
|
||||
r0: 0x00000000 r1: 0x00000000 r2: 0x00000000 r3: 0x00000000
|
||||
r4: 0x0223a2ca r5: 0xc04a32b0 r6: 0x00000000 r7: 0xcc4dbf64
|
||||
r8: 0x00000000 r9: 0x00000000 r10: 0x80329838 r11: 0xc0589140
|
||||
r12: 0x800880a0 sp: 0xcc4dbf38 lr: 0x80024cab pc: 0x00000000
|
||||
cpsr: 0x00000093 fsr: 0x00000000 far: 0x00000000
|
||||
kernel backtrace: cc4dbf64
|
||||
lr: 0x800244d9 fp: 0xcc4dbf90
|
||||
lr: 0x80258339 fp: 0xcc4dbfa8
|
||||
lr: 0x8008805c fp: 0x00000000
|
||||
|
||||
thread 0xc05896d0
|
||||
kernel continuation: 0x802582fd
|
||||
|
||||
thread 0xc0589c60
|
||||
kernel continuation: 0x802582fd
|
||||
|
||||
thread 0xc058a1f0
|
||||
kernel continuation: 0x802582fd
|
||||
|
||||
thread 0xc058a780
|
||||
kernel continuation: 0x802582fd
|
||||
|
||||
thread 0xc058bdc0
|
||||
kernel continuation: 0x802582fd
|
||||
|
||||
thread 0xc058c350
|
||||
kernel continuation: 0x802582fd
|
||||
|
||||
thread 0xc04aad10
|
||||
kernel continuation: 0x802582fd
|
||||
|
||||
thread 0xc058c8e0
|
||||
kernel continuation: 0x802582fd
|
||||
|
||||
thread 0xc04a5410
|
||||
kernel continuation: 0x802582fd
|
||||
|
||||
thread 0xc04a9140
|
||||
kernel continuation: 0x802582fd
|
||||
|
||||
thread 0xc04a3dd0
|
||||
kernel continuation: 0x802582fd
|
||||
|
||||
thread 0xc04a5f30
|
||||
kernel continuation: 0x802582fd
|
||||
|
||||
thread 0xc04a59a0
|
||||
kernel continuation: 0x802582fd
|
||||
|
||||
thread 0xc0588090
|
||||
kernel continuation: 0x802582fd
|
||||
|
||||
thread 0xc0587570
|
||||
kernel continuation: 0x802582fd
|
||||
|
||||
thread 0xc0586fe0
|
||||
kernel continuation: 0x802582fd
|
||||
|
||||
thread 0xc0588620
|
||||
kernel continuation: 0x802582fd
|
||||
|
||||
thread 0xc049d420
|
||||
kernel state:
|
||||
r0: 0x00000000 r1: 0x00000000 r2: 0x00000000 r3: 0x00000000
|
||||
r4: 0x026b871e r5: 0xc04a4360 r6: 0x00000000 r7: 0xcae43ddc
|
||||
r8: 0x00000000 r9: 0x0000c000 r10: 0x80329838 r11: 0xc049d420
|
||||
r12: 0x800880a0 sp: 0xcae43db0 lr: 0x80024cab pc: 0x00000000
|
||||
cpsr: 0x00000093 fsr: 0x00000000 far: 0x00000000
|
||||
kernel backtrace: cae43ddc
|
||||
lr: 0x800244d9 fp: 0xcae43e08
|
||||
lr: 0x8001ed6d fp: 0xcae43e20
|
||||
lr: 0x80240655 fp: 0xcae43e38
|
||||
lr: 0x8024b01d fp: 0xcae43e68
|
||||
lr: 0x80249ea3 fp: 0xcae43e78
|
||||
lr: 0x804ac80d fp: 0xcae43eac
|
||||
lr: 0x804ac789 fp: 0xcae43ebc
|
||||
lr: 0x8093f86f fp: 0xcae43ed8
|
||||
lr: 0x80249b47 fp: 0xcae43f10
|
||||
lr: 0x802497c3 fp: 0xcae43f60
|
||||
lr: 0x8024a299 fp: 0xcae43f88
|
||||
lr: 0x8024a06b fp: 0xcae43fa8
|
||||
lr: 0x8008805c fp: 0x00000000
|
||||
|
||||
thread 0xc058b830
|
||||
kernel continuation: 0x802582fd
|
||||
|
||||
thread 0xc04a0bc0
|
||||
kernel continuation: 0x802582fd
|
||||
|
||||
thread 0xc058b2a0
|
||||
kernel continuation: 0x802582fd
|
||||
|
||||
thread 0xc04a8090
|
||||
kernel continuation: 0x802582fd
|
||||
|
||||
thread 0xc0586a50
|
||||
kernel continuation: 0x802582fd
|
||||
|
||||
thread 0xc04a6fe0
|
||||
kernel continuation: 0x8002fde1
|
||||
|
||||
thread 0xc049b2c0
|
||||
kernel continuation: 0x802582fd
|
||||
|
||||
thread 0xc04a4360
|
||||
kernel state:
|
||||
r0: 0x00000000 r1: 0x00000000 r2: 0x00000000 r3: 0x00000000
|
||||
r4: 0x02aef154 r5: 0xc04aa780 r6: 0x00000000 r7: 0xcae73e24
|
||||
r8: 0x00000000 r9: 0x00000000 r10: 0x80329838 r11: 0xc04a4360
|
||||
r12: 0x800880a0 sp: 0xcae73df8 lr: 0x80024cab pc: 0x00000000
|
||||
cpsr: 0x00000093 fsr: 0x00000000 far: 0x00000000
|
||||
kernel backtrace: cae73e24
|
||||
lr: 0x800244d9 fp: 0xcae73e50
|
||||
lr: 0x8001ed6d fp: 0xcae73e68
|
||||
lr: 0x80240655 fp: 0xcae73e80
|
||||
lr: 0x8024b01d fp: 0xcae73eb0
|
||||
lr: 0x80249d95 fp: 0xcae73ec4
|
||||
lr: 0x80249f35 fp: 0xcae73ed8
|
||||
lr: 0x80249b23 fp: 0xcae73f10
|
||||
lr: 0x802497c3 fp: 0xcae73f60
|
||||
lr: 0x8024a299 fp: 0xcae73f88
|
||||
lr: 0x8024a06b fp: 0xcae73fa8
|
||||
lr: 0x8008805c fp: 0x00000000
|
||||
|
||||
thread 0xc049b850
|
||||
kernel state:
|
||||
r0: 0x00000000 r1: 0x00000000 r2: 0x00000000 r3: 0x00000000
|
||||
r4: 0x02b2ce4b r5: 0xc04aa780 r6: 0x00000000 r7: 0xcc3abe24
|
||||
r8: 0x00000000 r9: 0x00000000 r10: 0x80329838 r11: 0xc049b850
|
||||
r12: 0x800880a0 sp: 0xcc3abdf8 lr: 0x80024cab pc: 0x00000000
|
||||
cpsr: 0x00000093 fsr: 0x00000000 far: 0x00000000
|
||||
kernel backtrace: cc3abe24
|
||||
lr: 0x800244d9 fp: 0xcc3abe50
|
||||
lr: 0x8001ed6d fp: 0xcc3abe68
|
||||
lr: 0x80240655 fp: 0xcc3abe80
|
||||
lr: 0x8024b01d fp: 0xcc3abeb0
|
||||
lr: 0x80249d95 fp: 0xcc3abec4
|
||||
lr: 0x80249f35 fp: 0xcc3abed8
|
||||
lr: 0x80249b23 fp: 0xcc3abf10
|
||||
lr: 0x802497c3 fp: 0xcc3abf60
|
||||
lr: 0x8024a299 fp: 0xcc3abf88
|
||||
lr: 0x8024a06b fp: 0xcc3abfa8
|
||||
lr: 0x8008805c fp: 0x00000000
|
||||
|
||||
thread 0xc0587b00
|
||||
kernel state:
|
||||
r0: 0x00000000 r1: 0x00000000 r2: 0x00000000 r3: 0x00000000
|
||||
r4: 0x02b840ac r5: 0xc049c900 r6: 0x00000000 r7: 0xcc3cbde4
|
||||
r8: 0x00000000 r9: 0x00000000 r10: 0x80329838 r11: 0xc0587b00
|
||||
r12: 0x800880a0 sp: 0xcc3cbdb8 lr: 0x80024cab pc: 0x00000000
|
||||
cpsr: 0x00000093 fsr: 0x00000000 far: 0x00000000
|
||||
kernel backtrace: cc3cbde4
|
||||
lr: 0x800244d9 fp: 0xcc3cbe10
|
||||
lr: 0x8001ed6d fp: 0xcc3cbe28
|
||||
lr: 0x80240655 fp: 0xcc3cbe40
|
||||
lr: 0x80258781 fp: 0xcc3cbe48
|
||||
lr: 0x8078bfdd fp: 0xcc3cbe64
|
||||
lr: 0x804ad255 fp: 0xcc3cbe74
|
||||
lr: 0x804ad167 fp: 0xcc3cbe88
|
||||
lr: 0x8025914f fp: 0xcc3cbeb0
|
||||
lr: 0x804ad8e5 fp: 0xcc3cbee8
|
||||
lr: 0x80ad0949 fp: 0xcc3cbefc
|
||||
lr: 0x80acfa7f fp: 0xcc3cbf10
|
||||
lr: 0x80249657 fp: 0xcc3cbf60
|
||||
lr: 0x8024a299 fp: 0xcc3cbf88
|
||||
lr: 0x8024a06b fp: 0xcc3cbfa8
|
||||
lr: 0x8008805c fp: 0x00000000
|
||||
|
||||
thread 0xc049c900
|
||||
kernel state:
|
||||
r0: 0x00000000 r1: 0x00000000 r2: 0x00000000 r3: 0x00000000
|
||||
r4: 0x02bacb7e r5: 0xc05864c0 r6: 0x00000000 r7: 0xcae33e08
|
||||
r8: 0x00000000 r9: 0x00000000 r10: 0x80329838 r11: 0xc049c900
|
||||
r12: 0x800880a0 sp: 0xcae33ddc lr: 0x80024cab pc: 0x00000000
|
||||
cpsr: 0x00000093 fsr: 0x00000000 far: 0x00000000
|
||||
kernel backtrace: cae33e08
|
||||
lr: 0x800244d9 fp: 0xcae33e34
|
||||
lr: 0x8001ed6d fp: 0xcae33e4c
|
||||
lr: 0x80240655 fp: 0xcae33e64
|
||||
lr: 0x80258781 fp: 0xcae33e6c
|
||||
lr: 0x804ad14f fp: 0xcae33e80
|
||||
lr: 0x8025914f fp: 0xcae33ea8
|
||||
lr: 0x804ad8e5 fp: 0xcae33ee0
|
||||
lr: 0x808113b5 fp: 0xcae33ef4
|
||||
lr: 0x80811681 fp: 0xcae33f10
|
||||
lr: 0x80249657 fp: 0xcae33f60
|
||||
lr: 0x8024a299 fp: 0xcae33f88
|
||||
lr: 0x8024a06b fp: 0xcae33fa8
|
||||
lr: 0x8008805c fp: 0x00000000
|
||||
|
||||
thread 0xc05864c0
|
||||
kernel state:
|
||||
r0: 0x00000000 r1: 0x00000000 r2: 0x00000000 r3: 0x00000000
|
||||
r4: 0x02bb5c89 r5: 0xc0585f30 r6: 0x00000000 r7: 0xc4dd3e08
|
||||
r8: 0x00000000 r9: 0x00000000 r10: 0x80329838 r11: 0xc05864c0
|
||||
r12: 0x800880a0 sp: 0xc4dd3ddc lr: 0x80024cab pc: 0x00000000
|
||||
cpsr: 0x00000093 fsr: 0x00000000 far: 0x00000000
|
||||
kernel backtrace: c4dd3e08
|
||||
lr: 0x800244d9 fp: 0xc4dd3e34
|
||||
lr: 0x8001ed6d fp: 0xc4dd3e4c
|
||||
lr: 0x80240655 fp: 0xc4dd3e64
|
||||
lr: 0x80258781 fp: 0xc4dd3e6c
|
||||
lr: 0x804ad14f fp: 0xc4dd3e80
|
||||
lr: 0x8025914f fp: 0xc4dd3ea8
|
||||
lr: 0x804ad8e5 fp: 0xc4dd3ee0
|
||||
lr: 0x808113b5 fp: 0xc4dd3ef4
|
||||
lr: 0x80811681 fp: 0xc4dd3f10
|
||||
lr: 0x80249657 fp: 0xc4dd3f60
|
||||
lr: 0x8024a299 fp: 0xc4dd3f88
|
||||
lr: 0x8024a06b fp: 0xc4dd3fa8
|
||||
lr: 0x8008805c fp: 0x00000000
|
||||
|
||||
thread 0xc0585f30
|
||||
kernel state:
|
||||
r0: 0x00000000 r1: 0x00000000 r2: 0x00000000 r3: 0x00000000
|
||||
r4: 0x02c7b225 r5: 0xc05859a0 r6: 0x00000000 r7: 0xcae3be1c
|
||||
r8: 0x00000000 r9: 0x00000000 r10: 0x80329838 r11: 0xc0585f30
|
||||
r12: 0x800880a0 sp: 0xcae3bdf0 lr: 0x80024cab pc: 0x00000000
|
||||
cpsr: 0x00000093 fsr: 0x00000000 far: 0x00000000
|
||||
kernel backtrace: cae3be1c
|
||||
lr: 0x800244d9 fp: 0xcae3be48
|
||||
lr: 0x8001ed6d fp: 0xcae3be60
|
||||
lr: 0x80240655 fp: 0xcae3be78
|
||||
lr: 0x8024b01d fp: 0xcae3bea8
|
||||
lr: 0x80249ea3 fp: 0xcae3beb8
|
||||
lr: 0x807c2379 fp: 0xcae3bed8
|
||||
lr: 0x80249b47 fp: 0xcae3bf10
|
||||
lr: 0x802497c3 fp: 0xcae3bf60
|
||||
lr: 0x8024a299 fp: 0xcae3bf88
|
||||
lr: 0x8024a06b fp: 0xcae3bfa8
|
||||
lr: 0x8008805c fp: 0x00000000
|
||||
|
||||
thread 0xc05859a0
|
||||
kernel state:
|
||||
r0: 0x00000000 r1: 0x00000000 r2: 0x00000000 r3: 0x00000000
|
||||
r4: 0x02caa3ab r5: 0xc0585410 r6: 0x00000000 r7: 0xcadfbd9c
|
||||
r8: 0x00000000 r9: 0x00000000 r10: 0x80329838 r11: 0xc05859a0
|
||||
r12: 0x800880a0 sp: 0xcadfbd70 lr: 0x80024cab pc: 0x00000000
|
||||
cpsr: 0x00000093 fsr: 0x00000000 far: 0x00000000
|
||||
kernel backtrace: cadfbd9c
|
||||
lr: 0x800244d9 fp: 0xcadfbdc8
|
||||
lr: 0x8001ed6d fp: 0xcadfbde0
|
||||
lr: 0x80240655 fp: 0xcadfbdf8
|
||||
lr: 0x80258781 fp: 0xcadfbe00
|
||||
lr: 0x804ad14f fp: 0xcadfbe14
|
||||
lr: 0x8025914f fp: 0xcadfbe3c
|
||||
lr: 0x804ad8e5 fp: 0xcadfbe74
|
||||
lr: 0x80ae6a21 fp: 0xcadfbea0
|
||||
lr: 0x80ae63c7 fp: 0xcadfbed8
|
||||
lr: 0x80249b47 fp: 0xcadfbf10
|
||||
lr: 0x802497c3 fp: 0xcadfbf60
|
||||
lr: 0x8024a299 fp: 0xcadfbf88
|
||||
lr: 0x8024a06b fp: 0xcadfbfa8
|
||||
lr: 0x8008805c fp: 0x00000000
|
||||
|
||||
thread 0xc0585410
|
||||
kernel state:
|
||||
r0: 0x00000000 r1: 0x00000000 r2: 0x00000000 r3: 0x00000000
|
||||
r4: 0x02cd1181 r5: 0xc0584e80 r6: 0x00000000 r7: 0xcc423dec
|
||||
r8: 0x00000000 r9: 0x0000c000 r10: 0x80329838 r11: 0xc0585410
|
||||
r12: 0x800880a0 sp: 0xcc423dc0 lr: 0x80024cab pc: 0x00000000
|
||||
cpsr: 0x00000093 fsr: 0x00000000 far: 0x00000000
|
||||
kernel backtrace: cc423dec
|
||||
lr: 0x800244d9 fp: 0xcc423e18
|
||||
lr: 0x8001ed6d fp: 0xcc423e30
|
||||
lr: 0x802642b3 fp: 0xcc423e44
|
||||
lr: 0x8024bf13 fp: 0xcc423e60
|
||||
lr: 0x8024bff7 fp: 0xcc423e78
|
||||
lr: 0x8024c097 fp: 0xcc423e94
|
||||
lr: 0x807e2707 fp: 0xcc423ebc
|
||||
lr: 0x8076a53f fp: 0xcc423ed8
|
||||
lr: 0x80249b47 fp: 0xcc423f10
|
||||
lr: 0x802497c3 fp: 0xcc423f60
|
||||
lr: 0x8024a299 fp: 0xcc423f88
|
||||
lr: 0x8024a06b fp: 0xcc423fa8
|
||||
lr: 0x8008805c fp: 0x00000000
|
||||
|
||||
thread 0xc0584360
|
||||
kernel continuation: 0x8002cd11
|
||||
|
||||
thread 0xc0583dd0
|
||||
kernel continuation: 0x802582fd
|
||||
|
||||
thread 0xc05832b0
|
||||
kernel state:
|
||||
r0: 0x00000000 r1: 0x00000000 r2: 0x00000000 r3: 0x00000000
|
||||
r4: 0x02e0715b r5: 0xc0582d20 r6: 0x00000000 r7: 0xcc403f64
|
||||
r8: 0x00000000 r9: 0x00000000 r10: 0x80329838 r11: 0xc05832b0
|
||||
r12: 0x800880a0 sp: 0xcc403f38 lr: 0x80024cab pc: 0x00000000
|
||||
cpsr: 0x00000093 fsr: 0x00000000 far: 0x00000000
|
||||
kernel backtrace: cc403f64
|
||||
lr: 0x800244d9 fp: 0xcc403f90
|
||||
lr: 0x80258339 fp: 0xcc403fa8
|
||||
lr: 0x8008805c fp: 0x00000000
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"run": "/home/dev/ios6-emu/evidence/probe-20261003T101443-261760Z",
|
||||
"seconds": 10.0,
|
||||
"status": {
|
||||
"status": "paused",
|
||||
"singlestep": false,
|
||||
"running": false
|
||||
},
|
||||
"returncode": 0,
|
||||
"guest_status": "kernel-panic",
|
||||
"panic": "panic(cpu 0 caller 0x8065f7ed): \"ARM7M not stopped for some reason\"",
|
||||
"milestones": {
|
||||
"serial_console": true,
|
||||
"crypto_self_tests": true,
|
||||
"platform_driver": true,
|
||||
"interrupt_controller_driver": true,
|
||||
"userspace_confirmed": false
|
||||
},
|
||||
"expected_panic_matched": true,
|
||||
"exceptions": {
|
||||
"Taking exception 6 [FIQ] on CPU 0": 341,
|
||||
"Taking exception 1 [Undefined Instruction] on CPU 0": 16,
|
||||
"Taking exception 5 [IRQ] on CPU 0": 1
|
||||
},
|
||||
"kernel_modified": false,
|
||||
"machine": "ios6-n88",
|
||||
"firmware": "iPhone2,1 / 6.1.6 / 10B500"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
OK : empreintes, DeviceTree, noyau inchangé, BSS, mémoire réservée, RAMDisk, NVRAM et source QEMU.
|
||||
@@ -0,0 +1,31 @@
|
||||
Dec 31 16:00:33 iPhone installd[32]: 0x3d7dfb88 verify_signer_identity: MISValidateSignatureAndCopyInfo failed for /Applications/org.ios6emu.SimulatorLab.app/SimulatorLab: 0xe800801c
|
||||
Dec 31 16:00:33 iPhone installd[32]: 0x3d7dfb88 load_application_info: WARNING: failed to validate binary at path /Applications/org.ios6emu.SimulatorLab.app/SimulatorLab: 0xe800801c. This binary may not work properly.
|
||||
Dec 31 16:00:33 iPhone installd[32]: 0x3d7dfb88 __reconcileApps_block_invoke_0550: org.ios6emu.SimulatorLab got added
|
||||
Oct 3 06:28:39 iPhone amfid[137]: /Applications/org.ios6emu.SimulatorLab.app/SimulatorLab not valid: 0xe800801c: No code signature found.
|
||||
Oct 3 06:28:42 iPhone SimulatorLab[140]: SimulatorLab count=0
|
||||
Oct 3 06:28:42 iPhone SimulatorLab[140]: SimulatorLab ready
|
||||
Oct 3 06:29:01 iPhone SimulatorLab[140]: 5 transactions
|
||||
Oct 3 06:29:12 iPhone SimulatorLab[140]: 1 transactions
|
||||
Oct 3 06:29:13 iPhone SimulatorLab[140]: SimulatorLab count=1
|
||||
Oct 3 06:29:13 iPhone SimulatorLab[140]: 1 transactions
|
||||
Oct 3 06:30:00 iPhone SimulatorLab[140]: 1 transactions
|
||||
Oct 3 06:31:00 iPhone SimulatorLab[140]: 1 transactions
|
||||
Oct 3 06:32:00 iPhone SimulatorLab[140]: 1 transactions
|
||||
Oct 3 06:33:00 iPhone SimulatorLab[140]: 1 transactions
|
||||
Oct 3 06:34:01 iPhone SimulatorLab[140]: 1 transactions
|
||||
Oct 3 06:34:02 iPhone SimulatorLab[140]: 6 transactions
|
||||
Oct 3 06:34:03 iPhone SimulatorLab[140]: 9 transactions
|
||||
Oct 3 06:35:00 iPhone SimulatorLab[140]: 1 transactions
|
||||
Oct 3 06:35:29 iPhone SimulatorLab[140]: 1 transactions
|
||||
Oct 3 06:35:38 iPhone SimulatorLab[140]: 1 transactions
|
||||
Dec 31 16:00:41 iPhone installd[31]: 0x3ba54b88 verify_signer_identity: MISValidateSignatureAndCopyInfo failed for /Applications/org.ios6emu.SimulatorLab.app/SimulatorLab: 0xe800801c
|
||||
Dec 31 16:00:41 iPhone installd[31]: 0x3ba54b88 load_application_info: WARNING: failed to validate binary at path /Applications/org.ios6emu.SimulatorLab.app/SimulatorLab: 0xe800801c. This binary may not work properly.
|
||||
Oct 3 06:28:34 iPhone amfid[151]: /Applications/org.ios6emu.SimulatorLab.app/SimulatorLab not valid: 0xe800801c: No code signature found.
|
||||
Oct 3 06:28:39 iPhone SimulatorLab[150]: SimulatorLab count=0
|
||||
Oct 3 06:28:40 iPhone SimulatorLab[150]: SimulatorLab ready
|
||||
Oct 3 06:28:42 iPhone SimulatorLab[150]: 5 transactions
|
||||
Oct 3 06:28:42 iPhone SimulatorLab[150]: SimulatorLab count=1
|
||||
Oct 3 06:28:43 iPhone SimulatorLab[150]: 2 transactions
|
||||
Oct 3 06:28:44 iPhone SimulatorLab[150]: SimulatorLab count=2
|
||||
Oct 3 06:28:45 iPhone SimulatorLab[150]: 2 transactions
|
||||
Oct 3 06:28:45 iPhone SimulatorLab[150]: SimulatorLab count=3
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"firmware": "iOS 6.1.6 (10B500), iPhone2,1",
|
||||
"app_architecture": "ARMv7 Mach-O",
|
||||
"sdk": "iPhoneOS6.0.sdk",
|
||||
"sdk_archive_sha256": "68a163f56d7ff9abcad18586a15c76f572de99e13c122e119118e228cdecb652",
|
||||
"checks": [
|
||||
"native app rebuilt and reinstalled",
|
||||
"data file survived installation and cold reboot",
|
||||
"system bundle IDs rejected",
|
||||
"non Mach-O executables rejected",
|
||||
"symlink bundles rejected",
|
||||
"concurrent lifecycle lock rejected",
|
||||
"firmware and memory layout verification passed"
|
||||
],
|
||||
"sha256": {
|
||||
"build/apps/SimulatorLab.app/SimulatorLab": "06e91095ac3a7bcd0e5015c93cbcdebeb6e7fbc2e5b4ff590296ece9cab8c104",
|
||||
"build/ios6-agent": "c503acea3a901770af193386e8e5bf8ca1728fa1eaf6fb28bea35553e369a737",
|
||||
"build/qemu-system-arm": "c59f1330b7ee5bb59b63be009b6442e68f9d862398ebb447f362bbe968864ac4",
|
||||
"firmware/kernel-rootfs.bin": "56fa914337772f16a8c6155f958e5f5551852820988b9d6d910236a8936084f1",
|
||||
"firmware/boot-display-rootfs.bin": "1c773d638522c173e0c3183558a2f19ae34d931572902fc54e55c0977cfc513b"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"date": "20261003T134812Z",
|
||||
"bundle": "org.ios6emu.SimulatorLab",
|
||||
"checks": [
|
||||
"retour à SpringBoard",
|
||||
"lancement natif par SpringBoardServices",
|
||||
"bouton de remise à zéro",
|
||||
"trois appuis UIKit : count=3",
|
||||
"transfert binaire aller-retour",
|
||||
"HTTP invité vers serveur local via PPP",
|
||||
"coordonnées tactiles invalides refusées",
|
||||
"récupération des traces NSLog"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
[
|
||||
"/home/dev/ios6-emu/build/qemu-system-arm",
|
||||
"-M",
|
||||
"ios6-n88,rootfs=on",
|
||||
"-kernel",
|
||||
"/home/dev/ios6-emu/firmware/kernel-rootfs.bin",
|
||||
"-dtb",
|
||||
"/home/dev/ios6-emu/firmware/boot-display-rootfs.bin",
|
||||
"-initrd",
|
||||
"/home/dev/ios6-emu/firmware/rootfs-vm.hfs",
|
||||
"-display",
|
||||
"none",
|
||||
"-serial",
|
||||
"file:/home/dev/ios6-emu/evidence/probe-20261003T124815-824562Z/serial.log",
|
||||
"-monitor",
|
||||
"none",
|
||||
"-qmp",
|
||||
"unix:/home/dev/ios6-emu/evidence/probe-20261003T124815-824562Z/qmp,server=on,wait=off",
|
||||
"-d",
|
||||
"unimp,guest_errors",
|
||||
"-D",
|
||||
"/home/dev/ios6-emu/evidence/probe-20261003T124815-824562Z/qemu.log",
|
||||
"-no-reboot"
|
||||
]
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"run": "/home/dev/ios6-emu/evidence/probe-20261003T124815-824562Z",
|
||||
"seconds": 150.0,
|
||||
"status": {
|
||||
"status": "paused",
|
||||
"singlestep": false,
|
||||
"running": false
|
||||
},
|
||||
"registers": "\r\nCPU#0\r\nR00=00000000 R01=00000000 R02=800895a4 R03=802dc000\r\nR04=00000000 R05=80329838 R06=00000000 R07=ccc2bf9c\r\nR08=800256c9 R09=c0430990 R10=80076add R11=80324f78\r\nR12=c00d9200 R13=ccc2bf74 R14=800254a1 R15=800895ac\r\nPSR=a0000093 N-C- A svc32\r\ns00=00000000 s01=00000000 d00=0000000000000000\r\ns02=000f3917 s03=00000000 d01=00000000000f3917\r\ns04=00000000 s05=00000000 d02=0000000000000000\r\ns06=00000000 s07=00000000 d03=0000000000000000\r\ns08=6c707061 s09=6f692e65 d04=6f692e656c707061\r\ns10=2e74696b s11=6374616d d05=6374616d2e74696b\r\ns12=676e6968 s13=00000000 d06=00000000676e6968\r\ns14=6e657665 s15=706f2d74 d07=706f2d746e657665\r\ns16=0ed6dd56 s17=422dd863 d08=422dd8630ed6dd56\r\ns18=00000000 s19=00000000 d09=0000000000000000\r\ns20=00000000 s21=00000000 d10=0000000000000000\r\ns22=00000000 s23=00000000 d11=0000000000000000\r\ns24=00000000 s25=00000000 d12=0000000000000000\r\ns26=00000000 s27=00000000 d13=0000000000000000\r\ns28=00000000 s29=00000000 d14=0000000000000000\r\ns30=00000000 s31=00000000 d15=0000000000000000\r\ns32=f4833efe s33=c1cd27e3 d16=c1cd27e3f4833efe\r\ns34=38b3168a s35=3fef4376 d17=3fef437638b3168a\r\ns36=a0b5ed8d s37=3eb0c6f7 d18=3eb0c6f7a0b5ed8d\r\ns38=40000000 s39=c1cd27e4 d19=c1cd27e440000000\r\ns40=00000000 s41=00000000 d20=0000000000000000\r\ns42=00000000 s43=00000000 d21=0000000000000000\r\ns44=00000000 s45=00000000 d22=0000000000000000\r\ns46=00000000 s47=00000000 d23=0000000000000000\r\ns48=00000000 s49=00000000 d24=0000000000000000\r\ns50=00000000 s51=00000000 d25=0000000000000000\r\ns52=00000000 s53=00000000 d26=0000000000000000\r\ns54=00000000 s55=00000000 d27=0000000000000000\r\ns56=00000000 s57=00000000 d28=0000000000000000\r\ns58=00000000 s59=00000000 d29=0000000000000000\r\ns60=00000000 s61=00000000 d30=0000000000000000\r\ns62=00000000 s63=00000000 d31=0000000000000000\r\nFPSCR: 23000010\r\n",
|
||||
"instructions": "0xffffffff800895ac: Asm output not supported on this arch\r\n",
|
||||
"stack": "ccc2bf74: 0x00000001 0x80076add 0x800104f1 0x8033d318\r\nccc2bf84: 0x800256c9 0x80076add 0xc050af30 0x80329838\r\nccc2bf94: 0xc0430990 0x800256c9 0xccc2bfa8 0x800256db\r\nccc2bfa4: 0x00000000 0x00000000 0x8008805c 0x00000000\r\nccc2bfb4: 0x00000000 0x00000000 0x00000000 0x00000000\r\nccc2bfc4: 0x80329838 0x80329d0c 0xccc2bf9c 0x80329cf8\r\nccc2bfd4: 0xc0430990 0x80325460 0x80324f78 0x80025505\r\nccc2bfe4: 0xccc2bf74 0x80088bb8 0x00000000 0x00000093\r\n",
|
||||
"returncode": 0,
|
||||
"guest_status": "partial-boot",
|
||||
"panic": null,
|
||||
"milestones": {
|
||||
"serial_console": true,
|
||||
"crypto_self_tests": true,
|
||||
"platform_driver": true,
|
||||
"interrupt_controller_driver": true,
|
||||
"userspace_confirmed": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,615 @@
|
||||
iBoot version: ios6-emu direct-kernel prototype
|
||||
|
||||
|
||||
corecrypto kext started!
|
||||
|
||||
|
||||
Running kernel space in FIPS MODE
|
||||
|
||||
|
||||
Plist hmac value is 9fd77803e256b61c91d83182dfb9aee94e57b18702a272b6a206fb074ca8e541
|
||||
|
||||
|
||||
Computed hmac value is 9fd77803e256b61c91d83182dfb9aee94e57b18702a272b6a206fb074ca8e541
|
||||
|
||||
|
||||
corecrypto.kext FIPS integrity POST test passed!
|
||||
|
||||
|
||||
corecrypto.kext FIPS AES CBC POST test passed!
|
||||
|
||||
|
||||
corecrypto.kext FIPS TDES CBC POST test passed!
|
||||
|
||||
|
||||
corecrypto.kext FIPS SHA POST test passed!
|
||||
|
||||
|
||||
corecrypto.kext FIPS HMAC POST test passed!
|
||||
|
||||
|
||||
corecrypto.kext FIPS ECDSA POST test passed!
|
||||
|
||||
|
||||
corecrypto.kext FIPS DRBG POST test passed!
|
||||
|
||||
|
||||
corecrypto.kext FIPS POST passed!
|
||||
|
||||
|
||||
kern_return_t _initializeAppleMobileFileIntegrity(): signature enforcement disabled by boot-arg
|
||||
|
||||
|
||||
AppleS5L8920XIO::start: chip-revision: A0
|
||||
|
||||
AppleARMBacklight::start: Backlight calibration data 0
|
||||
|
||||
|
||||
Couldn't alloc class "AppleRawIOAddressSpace"
|
||||
|
||||
|
||||
AppleARMPL192VIC::start: _vicBaseAddress = 0xcc3c5000
|
||||
|
||||
AppleS5L8920XGPIOIC::start: gpioicBaseAddress: 0xc4d3a000
|
||||
|
||||
AppleARMPerformanceController::traceBufferEnable: Trace is enabled
|
||||
|
||||
AppleS5L8920XPerformanceController::start: _pcBaseAddress: 0xc4d4d000 _pcMCUBaseAddress: 0xc4d3e000
|
||||
|
||||
AppleARMPerformanceController configured with 1 Performance Domains
|
||||
|
||||
Performance Domain 0 : pcVoltageStateCount: 3 pcPerformanceStateCount: 4
|
||||
|
||||
Voltage State 0 : .vsPerformanceLimit: /2 .vsDeviceConstraint: 1ff8ffef ffff8fff
|
||||
|
||||
Voltage State 1 : .vsPerformanceLimit: /2 .vsDeviceConstraint: 1ffeffff ffff8fff
|
||||
|
||||
Voltage State 2 : .vsPerformanceLimit: /1 .vsDeviceConstraint: 1fffffff ffff8fff
|
||||
|
||||
Performance State 0 : .psPerformanceDivider: /1 .psVoltageRequired: 2 .psDeviceConstraint: 1fffffff ffff8fff
|
||||
|
||||
Performance State 1 : .psPerformanceDivider: /2 .psVoltageRequired: 0 .psDeviceConstraint: 1ffeb5ff ffe78fff
|
||||
|
||||
Performance State 2 : .psPerformanceDivider: /4 .psVoltageRequired: 0 .psDeviceConstraint: 1ffe24ff ffe78fff
|
||||
|
||||
Performance State 3 : .psPerformanceDivider: /8 .psVoltageRequired: 0 .psDeviceConstraint: 1ffe20df ffe78fff
|
||||
|
||||
AppleARMPerformanceController: Dynamic Performance State Management Enabled on Performance Domain 0
|
||||
|
||||
|
||||
AppleARMPerformanceController: Dynamic Voltage Control Enabled on Performance Domain 0 with 10000us activity timeout and 100us grace period
|
||||
|
||||
|
||||
IOSDIOController::init(): IOSDIOFamily-34 Feb 13 2013 21:35:31 @ 0x833dc500
|
||||
|
||||
|
||||
AppleBaseband::start(0x83407dc0): baseband
|
||||
|
||||
AppleIOPSDIO::start(): AppleIOPSDIO-12 Feb 13 2013 22:17:01
|
||||
|
||||
|
||||
+ AppleM2ScalerCSCDriver[0x834e3f00]::start(provider 0x8339f480)
|
||||
|
||||
|
||||
AppleH2CamIn::start
|
||||
|
||||
AppleH2CamIn::start, fSensorExtClkFunction = 0x83372F90
|
||||
|
||||
AppleH2CamIn::start, fSensorShutdownFunction = 0x83372F60
|
||||
|
||||
AppleH2CamIn::start, fISPResetFunction = 0x8336AA80
|
||||
|
||||
+ H264EncDriver: start (provider 0x8339f300)
|
||||
|
||||
+ H264EncDriver: compiled on Feb 13 2013 22:32:00
|
||||
|
||||
AppleVXD375 - start (provider 0x8339f280)
|
||||
|
||||
AppleVXD375 - compiled on Feb 13 2013 22:32:12
|
||||
|
||||
AppleSamsungSerial: Identified Serial Port on ARM Device=uart0 at 0x82500000(0xcad86000)
|
||||
|
||||
|
||||
AppleSamsungSerial: Identified Serial Port on ARM Device=uart4 at 0x82900000(0xcad8e000)
|
||||
|
||||
|
||||
AppleARMIICController::start buffer=0x8355dd80 entries=8
|
||||
|
||||
AppleS5L8920XI2CController::start: i2c0 _i2cBaseAddress: 0xcad96000
|
||||
|
||||
|
||||
AppleD1755PMU::start: pmu _pmuIICNub: 0x83582d90 built 21:35:40 Feb 13 2013
|
||||
|
||||
AppleD1755PMU::start: reading DOWN converter voltages
|
||||
|
||||
AppleD1755PMU::start: DOWN0: 725mV
|
||||
|
||||
AppleD1755PMU::start: DOWN1: 725mV
|
||||
|
||||
AppleD1755PMU::start: DOWN2: 725mV
|
||||
|
||||
AppleD1755PMU::start: DOWN3: 725mV
|
||||
|
||||
AppleD1755PMU::start: set VBUCK1_PRE1 to 0
|
||||
|
||||
AppleD1755PMU::start: set VBUCK1_PRE2 to 0
|
||||
|
||||
AppleD1755PMU::start: set VBUCK1_PRE3 to 0
|
||||
|
||||
AppleD1755PMU::start: using SWI for CPU BUCK changes
|
||||
|
||||
AppleARMIICController::start buffer=0x8355d600 entries=8
|
||||
|
||||
AppleS5L8920XI2CController::start: i2c2 _i2cBaseAddress: 0xcad9d000
|
||||
|
||||
|
||||
AppleS5L8920XPWM::start: _pwmBaseAddress: 0xcad9e000
|
||||
|
||||
AppleSamsungLP65USBPhy::start: hsic disabled
|
||||
|
||||
|
||||
AppleSamsungMIPIDSIController::start: _dsimBaseAddress = 0xcada5000
|
||||
|
||||
AppleSamsungSWI::start: _swiBaseAddress: 0x00000000cada6000
|
||||
|
||||
AppleSamsungSWI::start: _swiBaseAddress: _swiWorstCaseIntraVBUCK=0
|
||||
|
||||
BSD root: md0, major 3, minor 0
|
||||
|
||||
|
||||
com.apple.AppleFSCompressionTypeZlib kmod start
|
||||
|
||||
|
||||
AppleARMBacklight::start: _minDACLevel=56 _maxDACLevel=245
|
||||
|
||||
|
||||
000001.770986 AppleBasebandN88::loadDebugArguments: Loaded debug arguments 0x00000001
|
||||
|
||||
|
||||
ApplePinotLCD: _lcdPanelID: 0x00e50486 _lcdPanelClass: 1
|
||||
|
||||
|
||||
AppleSamsungLP65USBPhy::start : registers at virtual: 0xc4d46000, physical: 0x86000000
|
||||
|
||||
com.apple.AppleFSCompressionTypeZlib load succeeded
|
||||
|
||||
|
||||
virtual bool AppleMobileFileIntegrity::start(IOService *): built Feb 11 2014 20:55:23
|
||||
|
||||
|
||||
IOSurfaceRoot::installMemoryRegions()
|
||||
|
||||
L2TP domain init
|
||||
|
||||
|
||||
L2TP domain init complete
|
||||
|
||||
|
||||
PPTP domain init
|
||||
|
||||
|
||||
virtual bool AppleM2ScalerCSCHal::init(uint32_t, IOService *, IOService *, IOWorkLoop *): scalerNumber=0, IOKitProvider=0x8339f480, powerProvider=0x8339f480
|
||||
|
||||
|
||||
bool AppleM2ScalerCSCHal::mapRegisterMemory(IOService *): Scaler 0 RegisterMemoryMap[0x835d3108]: base=0xc4d55000 physical address = 0x85500000 length = 4096
|
||||
|
||||
|
||||
Scaler 0 enableDeviceClock(true,HALF_CLOCK_INDEX) = 0x0
|
||||
|
||||
|
||||
Scaler 0 enableDeviceClock(true,FULL_CLOCK_INDEX) = 0xe00002c7
|
||||
|
||||
|
||||
Scaler 0 enableDevicePower(true,0,HALF_CLOCK_INDEX) = 0xe00002c7
|
||||
|
||||
|
||||
Scaler HW version at start is 0x0
|
||||
|
||||
|
||||
void AppleM2ScalerCSCHal::setScalerPropertiesAndExtents() WARNING: Failed to find properties and extents data for SOC 0x0, Scaler HW Version 0x0
|
||||
|
||||
|
||||
Scaler 0 enableDeviceClock(false,FULL_CLOCK_INDEX) = 0xe00002c7
|
||||
|
||||
|
||||
AppleM2TVOut, fMapper: 0
|
||||
|
||||
|
||||
H264Driver: power_off_hardware
|
||||
|
||||
H264Driver: power_on_hardware
|
||||
|
||||
H264Driver: power_off_hardware
|
||||
|
||||
AppleVXD375: deviceType = H2A/H2P
|
||||
|
||||
AppleH2CamIn::getDARTInstance
|
||||
|
||||
AppleH2CamIn::power_off_hardware
|
||||
|
||||
AppleH2CamIn::setPowerStateGated: 1
|
||||
|
||||
AppleH2CamIn::setPowerStateGated, ISPCPU firmware not yet loaded
|
||||
|
||||
AppleH2CamIn::setPowerStateGated: 0
|
||||
|
||||
AppleM2CLCD, fMapper: 0
|
||||
|
||||
|
||||
AppleM2CLCD (0x834e0000)
|
||||
|
||||
|
||||
virtual bool AppleM2ScalerCSCDriver::start(IOService *) Object=0x834e3f00: Provider=0x8339f480: Register Service
|
||||
|
||||
|
||||
virtual bool AppleM2ScalerCSCDriver::start(IOService *): this=0x834e3f00, Added Scaler Number = 0
|
||||
|
||||
|
||||
TVOUT SHUT DOWN PROBLEM: !(enable.reg.clkgating_rdy)
|
||||
|
||||
|
||||
IOReturn AppleJPEGHal::reset_jpeg_block() : SW Reset failed (2)
|
||||
|
||||
TVOUT SHUT DOWN PROBLEM: !(mix_ctrl.reg.reg_mixer_ready_clk_down)
|
||||
|
||||
|
||||
AppleM2ScalerCSCDriver: Added framebuffer device: AppleM2CLCD id: 834e0000
|
||||
|
||||
|
||||
TVOUT SHUT DOWN PROBLEM: !(readSDOReg(SDO_CLKCON) & 0x2)
|
||||
|
||||
|
||||
TVOUT SHUT DOWN PROBLEM: !(enable.reg.clkgating_rdy)
|
||||
|
||||
|
||||
TVOUT SHUT DOWN PROBLEM: !(mix_ctrl.reg.reg_mixer_ready_clk_down)
|
||||
|
||||
|
||||
TVOUT SHUT DOWN PROBLEM: !(readSDOReg(SDO_CLKCON) & 0x2)
|
||||
|
||||
|
||||
TVOUT SHUT DOWN PROBLEM: !(enable.reg.clkgating_rdy)
|
||||
|
||||
|
||||
TVOUT SHUT DOWN PROBLEM: !(mix_ctrl.reg.reg_mixer_ready_clk_down)
|
||||
|
||||
|
||||
TVOUT SHUT DOWN PROBLEM: !(readSDOReg(SDO_CLKCON) & 0x2)
|
||||
|
||||
|
||||
TVOUT SHUT DOWN PROBLEM: !(enable.reg.clkgating_rdy)
|
||||
|
||||
|
||||
AppleD1755PMU::_readADCGated(3) ADC read bad state: 1
|
||||
|
||||
|
||||
AppleD1755PMU::_readADCGated(3) failed with status=e00002d6
|
||||
|
||||
|
||||
TVOUT SHUT DOWN PROBLEM: !(mix_ctrl.reg.reg_mixer_ready_clk_down)
|
||||
|
||||
|
||||
TVOUT SHUT DOWN PROBLEM: !(readSDOReg(SDO_CLKCON) & 0x2)
|
||||
|
||||
|
||||
AppleM2ScalerCSCDriver: Added framebuffer device: AppleM2TVOut id: 832cf400
|
||||
|
||||
|
||||
com.apple.launchd 1 com.apple.launchd 1 *** launchd[1] has started up. ***
|
||||
|
||||
|
||||
|
||||
com.apple.launchd 1 com.apple.launchd 1 *** Verbose boot, will log to /dev/console. ***
|
||||
|
||||
|
||||
|
||||
AppleD1755PMU::_readADCGated(3) ADC read bad state: 1
|
||||
|
||||
|
||||
AppleD1755PMU::_readADCGated(3) failed with status=e00002d6
|
||||
|
||||
|
||||
GetMasterBlock: Error 16 opening /dev/md0
|
||||
|
||||
|
||||
|
||||
/dev/md0 on / (hfs, local, journaled, noatime)
|
||||
|
||||
|
||||
|
||||
FIPS User Space Integrity Check Success
|
||||
|
||||
|
||||
|
||||
AppleD1755PMU::_readADCGated(4) ADC read bad state: 1
|
||||
|
||||
|
||||
AppleD1755PMU::_readADCGated(4) failed with status=e00002d6
|
||||
|
||||
|
||||
AppleD1755PMUPowerSource: AppleUSBCableDetect 0
|
||||
|
||||
|
||||
AppleD1755PMUPowerSource: AppleUSBCableType Detached
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice::init : Logging Buffer Length = 4K
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice::start : buffer-options 0x00000400
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice::start : registers at 0xccbaf000, 0x86100000 physical
|
||||
|
||||
AppleSynopsysOTGDevice::start : object is 0xc0581600, registers at 0xccbaf000, 0x86100000 physical
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice::findMaxEndpoints: in EPs: 7, out EPs: 7, max_endpoint: 8, num_endpoints: 14
|
||||
|
||||
|
||||
IOAccessoryPortSerial::start: iap: could not set up serial port: device is offline
|
||||
|
||||
|
||||
AppleD1755PMU::_readADCGated(3) ADC read bad state: 1
|
||||
|
||||
|
||||
AppleD1755PMU::_readADCGated(3) failed with status=e00002d6
|
||||
|
||||
|
||||
FIPS USER Space POST Success!
|
||||
|
||||
|
||||
|
||||
AppleIOPSDIOEndpoint::init(): Failed to get IOP after 10 sec.
|
||||
|
||||
|
||||
TVOUT SHUT DOWN PROBLEM: !(enable.reg.clkgating_rdy)
|
||||
|
||||
|
||||
TVOUT SHUT DOWN PROBLEM: !(mix_ctrl.reg.reg_mixer_ready_clk_down)
|
||||
|
||||
|
||||
TVOUT SHUT DOWN PROBLEM: !(readSDOReg(SDO_CLKCON) & 0x2)
|
||||
|
||||
|
||||
virtual void AppleM2CLCD::do_set_debug_flags(uint32_t, uint32_t), ******************** DITHER STATE IS SET TO 0 **********************
|
||||
|
||||
|
||||
launchd[18] Builtin profile: ptpd (sandbox)
|
||||
|
||||
|
||||
launchd[41] Builtin profile: iapd (sandbox)
|
||||
|
||||
|
||||
launchd[56] Builtin profile: BTServer (sandbox)
|
||||
|
||||
|
||||
AMFI: Invalid signature but permitting execution
|
||||
|
||||
|
||||
booted from secure root: give device keybag access to everyone
|
||||
|
||||
|
||||
booted from secure root: give device keybag access to everyone
|
||||
|
||||
|
||||
booted from secure root: give device keybag access to everyone
|
||||
|
||||
|
||||
booted from secure root: give device keybag access to everyone
|
||||
|
||||
|
||||
launchd[66] Builtin profile: apsd (sandbox)
|
||||
|
||||
|
||||
launchd[67] Builtin profile: mobileassetd (sandbox)
|
||||
|
||||
|
||||
com.apple.launchd 1 com.apple.SpringBoard 61 (com.apple.SpringBoard) Stopping job...
|
||||
|
||||
|
||||
|
||||
ios6-emu: initialisation du trousseau systC(me
|
||||
|
||||
|
||||
|
||||
booted from secure root: give device keybag access to everyone
|
||||
|
||||
|
||||
Will try to use UIDPlus to derive key
|
||||
|
||||
|
||||
AppleKeyStore:cp_key_store_action(1)
|
||||
|
||||
|
||||
booted from secure root: give device keybag access to everyone
|
||||
|
||||
|
||||
ios6-emu: trousseau RAM create=0 handle=1
|
||||
|
||||
|
||||
|
||||
AppleKeyStore:cp_key_store_action(1)
|
||||
|
||||
|
||||
ios6-emu: trousseau RAM set_system=0
|
||||
|
||||
|
||||
|
||||
ios6-emu: preferences de session synchronisees=1
|
||||
|
||||
|
||||
|
||||
booted from secure root: give device keybag access to everyone
|
||||
|
||||
|
||||
ios6-emu: environnement graphique pid=12 /usr/libexec/backboardd
|
||||
|
||||
|
||||
|
||||
ios6-emu: CA_ENABLE_OGL=0
|
||||
|
||||
|
||||
|
||||
ios6-emu: CA_PRINT_PERF=1
|
||||
|
||||
|
||||
|
||||
ios6-emu: CA_NO_ACCEL=1
|
||||
|
||||
|
||||
|
||||
ios6-emu: environnement graphique pid=69 /System/Library/CoreServices/SpringBoard.app/SpringBoard
|
||||
|
||||
|
||||
|
||||
ios6-emu: CA_ENABLE_OGL=0
|
||||
|
||||
|
||||
|
||||
ios6-emu: CA_PRINT_PERF=1
|
||||
|
||||
|
||||
|
||||
ios6-emu: CA_NO_ACCEL=1
|
||||
|
||||
|
||||
|
||||
ios6-emu: ecran status=268435459 verrouille=0 code=1
|
||||
|
||||
|
||||
|
||||
launchd[76] Builtin profile: geod (sandbox)
|
||||
|
||||
|
||||
ios6-emu: ecran status=268435459 verrouille=0 code=1
|
||||
|
||||
|
||||
|
||||
booted from secure root: give device keybag access to everyone
|
||||
|
||||
|
||||
booted from secure root: give device keybag access to everyone
|
||||
|
||||
|
||||
ios6-emu: ecran status=0 verrouille=1 code=0
|
||||
|
||||
|
||||
|
||||
launchd[83] Builtin profile: MobileMail (sandbox)
|
||||
|
||||
|
||||
booted from secure root: give device keybag access to everyone
|
||||
|
||||
|
||||
booted from secure root: give device keybag access to everyone
|
||||
|
||||
|
||||
ios6-emu: geste de deverrouillage transmis a GraphicsServices
|
||||
|
||||
|
||||
|
||||
booted from secure root: give device keybag access to everyone
|
||||
|
||||
|
||||
booted from secure root: give device keybag access to everyone
|
||||
|
||||
|
||||
launchd[90] Builtin profile: syncdefaultsd (sandbox)
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice - Configuration: PTP
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice Interface: PTP
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice - Configuration: iPod USB Interface
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice Interface: USBAudioControl
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice Interface: USBAudioStreaming
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice Interface: IapOverUsbHid
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice - Configuration: PTP + Apple Mobile Device
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice Interface: PTP
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice Interface: AppleUSBMux
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice - Configuration: PTP + Apple Mobile Device + Apple USB Ethernet
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice Interface: PTP
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice Interface: AppleUSBMux
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice Interface: AppleUSBEthernet
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice::gated_registerFunction Register function USBAudioControl
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice::gated_registerFunction Register function USBAudioStreaming
|
||||
|
||||
|
||||
IOAccessoryPortUSB::start
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice::gated_registerFunction Register function IapOverUsbHid
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice::gated_registerFunction Register function AppleUSBEthernet
|
||||
|
||||
|
||||
virtual bool AppleUSBDeviceMux::start(IOService *) build: Feb 13 2013 22:02:59
|
||||
|
||||
|
||||
init_waste
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice::gated_registerFunction Register function AppleUSBMux
|
||||
|
||||
|
||||
AppleUSBEthernetDevice: Ethernet address 02:00:00:00:00:00
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice::gated_registerFunction Register function PTP
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice::startUSBStack Starting usb stack
|
||||
|
||||
|
||||
booted from secure root: give device keybag access to everyone
|
||||
|
||||
|
||||
ios6-emu: ecran status=0 verrouille=0 code=0
|
||||
|
||||
|
||||
|
||||
AppleIOPSDIOEndpoint::init(): Failed to get IOP after 130 sec.
|
||||
|
||||
|
||||
booted from secure root: give device keybag access to everyone
|
||||
|
||||
|
||||
ios6-emu: ecran status=0 verrouille=0 code=0
|
||||
|
||||
|
||||
|
||||
booted from secure root: give device keybag access to everyone
|
||||
|
||||
|
||||
booted from secure root: give device keybag access to everyone
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"src/ios6_n88.c": "62181b482dbf5ae0361c7646a307c59e407938f8e7825f250301f8608ca2c0c4",
|
||||
"src/keybag_init.c": "136c2393f637eef473e57294a44d48ce8b48242554738eba7e748b1ab22064ec",
|
||||
"src/session_input.h": "00a66abb65d195cba0604383103d85c2e1bf22e7dd24d2b4b45329817ad58039",
|
||||
"tools/prepare_boot.py": "7e85bee06a3fcd3c98fb7ad4c88cdf1a7af1c4d1c477e6ab6434f2274cdb7371",
|
||||
"tools/prepare_rootfs.py": "2b5e3bd75cdb8a5fc297aede2396608162f3e36faf70056806e0b29510cf960f",
|
||||
"tools/probe.py": "4755c5aee24cdb6f78aac661e7578188fc5a4125d379899e09b7171265d49ad3",
|
||||
"build/qemu-system-arm": "1b00b4c610ec94e3402b3cc06fcee20b23101b923ea33b5469c71f8c76fe85f3",
|
||||
"build/ios6-keybag-init": "f24a67328c4b4be6afd0fcbd507c63bd421aeb0caf616491de622289ddbbd9fc",
|
||||
"firmware/kernel-rootfs.bin": "56fa914337772f16a8c6155f958e5f5551852820988b9d6d910236a8936084f1",
|
||||
"firmware/boot-display-rootfs.bin": "117530bb9feddd2c39892830ee0a73942a52eb0980b8956c892dbd42dc30bfca"
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
[
|
||||
"/home/dev/ios6-emu/build/qemu-system-arm",
|
||||
"-M",
|
||||
"ios6-n88,rootfs=on",
|
||||
"-kernel",
|
||||
"/home/dev/ios6-emu/firmware/kernel-rootfs.bin",
|
||||
"-dtb",
|
||||
"/home/dev/ios6-emu/firmware/boot-display-rootfs.bin",
|
||||
"-initrd",
|
||||
"/home/dev/ios6-emu/firmware/rootfs-vm.hfs",
|
||||
"-display",
|
||||
"none",
|
||||
"-serial",
|
||||
"file:/home/dev/ios6-emu/evidence/probe-20261003T125116-664879Z/serial.log",
|
||||
"-monitor",
|
||||
"none",
|
||||
"-qmp",
|
||||
"unix:/home/dev/ios6-emu/evidence/probe-20261003T125116-664879Z/qmp,server=on,wait=off",
|
||||
"-d",
|
||||
"unimp,guest_errors",
|
||||
"-D",
|
||||
"/home/dev/ios6-emu/evidence/probe-20261003T125116-664879Z/qemu.log",
|
||||
"-no-reboot"
|
||||
]
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"run": "/home/dev/ios6-emu/evidence/probe-20261003T125116-664879Z",
|
||||
"seconds": 300.0,
|
||||
"status": {
|
||||
"status": "paused",
|
||||
"singlestep": false,
|
||||
"running": false
|
||||
},
|
||||
"registers": "\r\nCPU#0\r\nR00=0000000a R01=00000001 R02=800895dc R03=802dc000\r\nR04=00000001 R05=acf331f0 R06=0000000a R07=c0463f08\r\nR08=802dc000 R09=8008958c R10=c00d9200 R11=00000003\r\nR12=00000000 R13=802d9fb0 R14=800895ec R15=80089590\r\nPSR=a00001d1 N-C- A fiq32\r\ns00=00000000 s01=00000000 d00=0000000000000000\r\ns02=00000000 s03=00000000 d01=0000000000000000\r\ns04=00000000 s05=00000000 d02=0000000000000000\r\ns06=00000000 s07=00000000 d03=0000000000000000\r\ns08=20313932 s09=32337830 d04=3233783020313932\r\ns10=66333363 s11=30203130 d05=3020313066333363\r\ns12=00000000 s13=bf97fd80 d06=bf97fd8000000000\r\ns14=aa000000 s15=c1cd27e3 d07=c1cd27e3aa000000\r\ns16=00000000 s17=3ff00000 d08=3ff0000000000000\r\ns18=00000000 s19=00000000 d09=0000000000000000\r\ns20=00000000 s21=00000000 d10=0000000000000000\r\ns22=00000000 s23=00000000 d11=0000000000000000\r\ns24=00000000 s25=00000000 d12=0000000000000000\r\ns26=00000000 s27=00000000 d13=0000000000000000\r\ns28=00000000 s29=00000000 d14=0000000000000000\r\ns30=00000000 s31=00000000 d15=0000000000000000\r\ns32=00000000 s33=00000000 d16=0000000000000000\r\ns34=00000000 s35=00000000 d17=0000000000000000\r\ns36=a0b5ed8d s37=3eb0c6f7 d18=3eb0c6f7a0b5ed8d\r\ns38=40000000 s39=c1cd27e4 d19=c1cd27e440000000\r\ns40=00000000 s41=00000000 d20=0000000000000000\r\ns42=00000000 s43=40740000 d21=4074000000000000\r\ns44=00000000 s45=40640000 d22=4064000000000000\r\ns46=00000000 s47=00000000 d23=0000000000000000\r\ns48=00000000 s49=00000000 d24=0000000000000000\r\ns50=00000000 s51=00000000 d25=0000000000000000\r\ns52=00000000 s53=00000000 d26=0000000000000000\r\ns54=ffffffff s55=ffffffff d27=ffffffffffffffff\r\ns56=ffffffff s57=ffffffff d28=ffffffffffffffff\r\ns58=ffffffff s59=ffffffff d29=ffffffffffffffff\r\ns60=fcfcffff s61=30300b0b d30=30300b0bfcfcffff\r\ns62=fcfcffff s63=30300b0b d31=30300b0bfcfcffff\r\nFPSCR: 8b000095\r\n",
|
||||
"instructions": "0xffffffff80089590: Asm output not supported on this arch\r\n",
|
||||
"stack": "802d9fb0: 0x0000000a 0x00000001 0x800895dc 0x802dc000\r\n802d9fc0: 0x00000001 0xacf331f0 0x0000000a 0xc0463f08\r\n802d9fd0: 0x802dc000 0x8008958c 0xc00d9200 0x00000003\r\n802d9fe0: 0x00000000 0x00000000 0x00000000 0x800895e8\r\n802d9ff0: 0xa0000093 0x00000000 0x00000000 0x00000000\r\n802da000: 0x00000000 0x00000000 0x00000000 0x00000000\r\n802da010: 0x00000000 0x00000000 0x00000000 0x00000000\r\n802da020: 0x00000000 0x00000000 0x00000000 0x00000000\r\n",
|
||||
"returncode": 0,
|
||||
"guest_status": "partial-boot",
|
||||
"panic": null,
|
||||
"milestones": {
|
||||
"serial_console": true,
|
||||
"crypto_self_tests": true,
|
||||
"platform_driver": true,
|
||||
"interrupt_controller_driver": true,
|
||||
"userspace_confirmed": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,998 @@
|
||||
iBoot version: ios6-emu direct-kernel prototype
|
||||
|
||||
|
||||
corecrypto kext started!
|
||||
|
||||
|
||||
Running kernel space in FIPS MODE
|
||||
|
||||
|
||||
Plist hmac value is 9fd77803e256b61c91d83182dfb9aee94e57b18702a272b6a206fb074ca8e541
|
||||
|
||||
|
||||
Computed hmac value is 9fd77803e256b61c91d83182dfb9aee94e57b18702a272b6a206fb074ca8e541
|
||||
|
||||
|
||||
corecrypto.kext FIPS integrity POST test passed!
|
||||
|
||||
|
||||
corecrypto.kext FIPS AES CBC POST test passed!
|
||||
|
||||
|
||||
corecrypto.kext FIPS TDES CBC POST test passed!
|
||||
|
||||
|
||||
corecrypto.kext FIPS SHA POST test passed!
|
||||
|
||||
|
||||
corecrypto.kext FIPS HMAC POST test passed!
|
||||
|
||||
|
||||
corecrypto.kext FIPS ECDSA POST test passed!
|
||||
|
||||
|
||||
corecrypto.kext FIPS DRBG POST test passed!
|
||||
|
||||
|
||||
corecrypto.kext FIPS POST passed!
|
||||
|
||||
|
||||
kern_return_t _initializeAppleMobileFileIntegrity(): signature enforcement disabled by boot-arg
|
||||
|
||||
|
||||
AppleS5L8920XIO::start: chip-revision: A0
|
||||
|
||||
AppleARMBacklight::start: Backlight calibration data 0
|
||||
|
||||
|
||||
Couldn't alloc class "AppleRawIOAddressSpace"
|
||||
|
||||
|
||||
AppleARMPL192VIC::start: _vicBaseAddress = 0xcc38e000
|
||||
|
||||
AppleS5L8920XGPIOIC::start: gpioicBaseAddress: 0xc4df2000
|
||||
|
||||
AppleARMPerformanceController::traceBufferEnable: Trace is enabled
|
||||
|
||||
AppleS5L8920XPerformanceController::start: _pcBaseAddress: 0xc4e05000 _pcMCUBaseAddress: 0xc4df6000
|
||||
|
||||
AppleARMPerformanceController configured with 1 Performance Domains
|
||||
|
||||
Performance Domain 0 : pcVoltageStateCount: 3 pcPerformanceStateCount: 4
|
||||
|
||||
Voltage State 0 : .vsPerformanceLimit: /2 .vsDeviceConstraint: 1ff8ffef ffff8fff
|
||||
|
||||
Voltage State 1 : .vsPerformanceLimit: /2 .vsDeviceConstraint: 1ffeffff ffff8fff
|
||||
|
||||
Voltage State 2 : .vsPerformanceLimit: /1 .vsDeviceConstraint: 1fffffff ffff8fff
|
||||
|
||||
Performance State 0 : .psPerformanceDivider: /1 .psVoltageRequired: 2 .psDeviceConstraint: 1fffffff ffff8fff
|
||||
|
||||
Performance State 1 : .psPerformanceDivider: /2 .psVoltageRequired: 0 .psDeviceConstraint: 1ffeb5ff ffe78fff
|
||||
|
||||
Performance State 2 : .psPerformanceDivider: /4 .psVoltageRequired: 0 .psDeviceConstraint: 1ffe24ff ffe78fff
|
||||
|
||||
Performance State 3 : .psPerformanceDivider: /8 .psVoltageRequired: 0 .psDeviceConstraint: 1ffe20df ffe78fff
|
||||
|
||||
AppleARMPerformanceController: Dynamic Performance State Management Enabled on Performance Domain 0
|
||||
|
||||
|
||||
AppleARMPerformanceController: Dynamic Voltage Control Enabled on Performance Domain 0 with 10000us activity timeout and 100us grace period
|
||||
|
||||
|
||||
IOSDIOController::init(): IOSDIOFamily-34 Feb 13 2013 21:35:31 @ 0x833dc300
|
||||
|
||||
|
||||
AppleIOPSDIO::start(): AppleIOPSDIO-12 Feb 13 2013 22:17:01
|
||||
|
||||
|
||||
AppleBaseband::start(0x833f9e18): baseband
|
||||
|
||||
+ AppleM2ScalerCSCDriver[0x834eaf00]::start(provider 0x8339f380)
|
||||
|
||||
|
||||
AppleH2CamIn::start
|
||||
|
||||
AppleH2CamIn::start, fSensorExtClkFunction = 0x83372F60
|
||||
|
||||
AppleH2CamIn::start, fSensorShutdownFunction = 0x83372EA0
|
||||
|
||||
AppleH2CamIn::start, fISPResetFunction = 0x8334A000
|
||||
|
||||
+ H264EncDriver: start (provider 0x8339f200)
|
||||
|
||||
+ H264EncDriver: compiled on Feb 13 2013 22:32:00
|
||||
|
||||
AppleVXD375 - start (provider 0x8339f180)
|
||||
|
||||
AppleVXD375 - compiled on Feb 13 2013 22:32:12
|
||||
|
||||
AppleSamsungSerial: Identified Serial Port on ARM Device=uart0 at 0x82500000(0xcae3e000)
|
||||
|
||||
|
||||
AppleSamsungSerial: Identified Serial Port on ARM Device=uart4 at 0x82900000(0xcae46000)
|
||||
|
||||
|
||||
AppleARMIICController::start buffer=0x83584d80 entries=8
|
||||
|
||||
AppleS5L8920XI2CController::start: i2c0 _i2cBaseAddress: 0xcae4e000
|
||||
|
||||
|
||||
AppleD1755PMU::start: pmu _pmuIICNub: 0x83589d90 built 21:35:40 Feb 13 2013
|
||||
|
||||
AppleD1755PMU::start: reading DOWN converter voltages
|
||||
|
||||
AppleD1755PMU::start: DOWN0: 725mV
|
||||
|
||||
AppleD1755PMU::start: DOWN1: 725mV
|
||||
|
||||
AppleD1755PMU::start: DOWN2: 725mV
|
||||
|
||||
AppleD1755PMU::start: DOWN3: 725mV
|
||||
|
||||
AppleD1755PMU::start: set VBUCK1_PRE1 to 0
|
||||
|
||||
AppleD1755PMU::start: set VBUCK1_PRE2 to 0
|
||||
|
||||
AppleD1755PMU::start: set VBUCK1_PRE3 to 0
|
||||
|
||||
AppleD1755PMU::start: using SWI for CPU BUCK changes
|
||||
|
||||
BSD root: md0, major 3, minor 0
|
||||
|
||||
|
||||
com.apple.AppleFSCompressionTypeZlib kmod start
|
||||
|
||||
|
||||
com.apple.AppleFSCompressionTypeZlib load succeeded
|
||||
|
||||
|
||||
virtual bool AppleMobileFileIntegrity::start(IOService *): built Feb 11 2014 20:55:23
|
||||
|
||||
|
||||
IOSurfaceRoot::installMemoryRegions()
|
||||
|
||||
000001.603790 AppleBasebandN88::loadDebugArguments: Loaded debug arguments 0x00000001
|
||||
|
||||
|
||||
AppleARMIICController::start buffer=0x83677080 entries=8
|
||||
|
||||
AppleS5L8920XI2CController::start: i2c2 _i2cBaseAddress: 0xcae56000
|
||||
|
||||
|
||||
AppleS5L8920XPWM::start: _pwmBaseAddress: 0xcae5d000
|
||||
|
||||
L2TP domain init
|
||||
|
||||
|
||||
L2TP domain init complete
|
||||
|
||||
|
||||
PPTP domain init
|
||||
|
||||
|
||||
AppleSamsungLP65USBPhy::start: hsic disabled
|
||||
|
||||
|
||||
AppleM2CLCD, fMapper: 0
|
||||
|
||||
|
||||
AppleM2CLCD (0x834c9000)
|
||||
|
||||
|
||||
AppleSamsungMIPIDSIController::start: _dsimBaseAddress = 0xc4dfd000
|
||||
|
||||
ApplePinotLCD: _lcdPanelID: 0x00e50486 _lcdPanelClass: 1
|
||||
|
||||
|
||||
AppleSamsungSWI::start: _swiBaseAddress: 0x00000000c4dfe000
|
||||
|
||||
AppleSamsungSWI::start: _swiBaseAddress: _swiWorstCaseIntraVBUCK=0
|
||||
|
||||
virtual bool AppleM2ScalerCSCHal::init(uint32_t, IOService *, IOService *, IOWorkLoop *): scalerNumber=0, IOKitProvider=0x8339f380, powerProvider=0x8339f380
|
||||
|
||||
|
||||
bool AppleM2ScalerCSCHal::mapRegisterMemory(IOService *): Scaler 0 RegisterMemoryMap[0x836b0738]: base=0xc4e0e000 physical address = 0x85500000 length = 4096
|
||||
|
||||
|
||||
AppleM2TVOut, fMapper: 0
|
||||
|
||||
|
||||
H264Driver: power_off_hardware
|
||||
|
||||
H264Driver: power_on_hardware
|
||||
|
||||
AppleVXD375: deviceType = H2A/H2P
|
||||
|
||||
AppleH2CamIn::getDARTInstance
|
||||
|
||||
AppleH2CamIn::power_off_hardware
|
||||
|
||||
AppleH2CamIn::setPowerStateGated: 1
|
||||
|
||||
AppleH2CamIn::setPowerStateGated, ISPCPU firmware not yet loaded
|
||||
|
||||
AppleH2CamIn::setPowerStateGated: 0
|
||||
|
||||
AppleSamsungLP65USBPhy::start : registers at virtual: 0xcae75000, physical: 0x86000000
|
||||
|
||||
AppleARMBacklight::start: _minDACLevel=56 _maxDACLevel=245
|
||||
|
||||
|
||||
IOReturn AppleJPEGHal::reset_jpeg_block() : SW Reset failed (2)
|
||||
|
||||
H264Driver: power_off_hardware
|
||||
|
||||
Scaler 0 enableDeviceClock(true,HALF_CLOCK_INDEX) = 0x0
|
||||
|
||||
|
||||
Scaler 0 enableDeviceClock(true,FULL_CLOCK_INDEX) = 0xe00002c7
|
||||
|
||||
|
||||
Scaler 0 enableDevicePower(true,0,HALF_CLOCK_INDEX) = 0xe00002c7
|
||||
|
||||
|
||||
Scaler HW version at start is 0x0
|
||||
|
||||
|
||||
void AppleM2ScalerCSCHal::setScalerPropertiesAndExtents() WARNING: Failed to find properties and extents data for SOC 0x0, Scaler HW Version 0x0
|
||||
|
||||
|
||||
Scaler 0 enableDeviceClock(false,FULL_CLOCK_INDEX) = 0xe00002c7
|
||||
|
||||
|
||||
AppleM2ScalerCSCDriver: Added framebuffer device: AppleM2CLCD id: 834c9000
|
||||
|
||||
|
||||
virtual bool AppleM2ScalerCSCDriver::start(IOService *) Object=0x834eaf00: Provider=0x8339f380: Register Service
|
||||
|
||||
|
||||
virtual bool AppleM2ScalerCSCDriver::start(IOService *): this=0x834eaf00, Added Scaler Number = 0
|
||||
|
||||
|
||||
TVOUT SHUT DOWN PROBLEM: !(enable.reg.clkgating_rdy)
|
||||
|
||||
|
||||
TVOUT SHUT DOWN PROBLEM: !(mix_ctrl.reg.reg_mixer_ready_clk_down)
|
||||
|
||||
|
||||
TVOUT SHUT DOWN PROBLEM: !(readSDOReg(SDO_CLKCON) & 0x2)
|
||||
|
||||
|
||||
TVOUT SHUT DOWN PROBLEM: !(enable.reg.clkgating_rdy)
|
||||
|
||||
|
||||
TVOUT SHUT DOWN PROBLEM: !(mix_ctrl.reg.reg_mixer_ready_clk_down)
|
||||
|
||||
|
||||
TVOUT SHUT DOWN PROBLEM: !(readSDOReg(SDO_CLKCON) & 0x2)
|
||||
|
||||
|
||||
AppleD1755PMU::_readADCGated(3) ADC read bad state: 1
|
||||
|
||||
|
||||
AppleD1755PMU::_readADCGated(3) failed with status=e00002d6
|
||||
|
||||
|
||||
IOAccessoryPortSerial::start: iap: could not set up serial port: device is offline
|
||||
|
||||
|
||||
TVOUT SHUT DOWN PROBLEM: !(enable.reg.clkgating_rdy)
|
||||
|
||||
|
||||
TVOUT SHUT DOWN PROBLEM: !(mix_ctrl.reg.reg_mixer_ready_clk_down)
|
||||
|
||||
|
||||
TVOUT SHUT DOWN PROBLEM: !(readSDOReg(SDO_CLKCON) & 0x2)
|
||||
|
||||
|
||||
TVOUT SHUT DOWN PROBLEM: !(enable.reg.clkgating_rdy)
|
||||
|
||||
|
||||
TVOUT SHUT DOWN PROBLEM: !(mix_ctrl.reg.reg_mixer_ready_clk_down)
|
||||
|
||||
|
||||
TVOUT SHUT DOWN PROBLEM: !(readSDOReg(SDO_CLKCON) & 0x2)
|
||||
|
||||
|
||||
AppleM2ScalerCSCDriver: Added framebuffer device: AppleM2TVOut id: 832cf400
|
||||
|
||||
|
||||
com.apple.launchd 1 com.apple.launchd 1 *** launchd[1] has started up. ***
|
||||
|
||||
|
||||
|
||||
com.apple.launchd 1 com.apple.launchd 1 *** Verbose boot, will log to /dev/console. ***
|
||||
|
||||
|
||||
|
||||
AppleD1755PMU::_readADCGated(3) ADC read bad state: 1
|
||||
|
||||
|
||||
AppleD1755PMU::_readADCGated(3) failed with status=e00002d6
|
||||
|
||||
|
||||
GetMasterBlock: Error 16 opening /dev/md0
|
||||
|
||||
|
||||
|
||||
/dev/md0 on / (hfs, local, journaled, noatime)
|
||||
|
||||
|
||||
|
||||
FIPS User Space Integrity Check Success
|
||||
|
||||
|
||||
|
||||
AppleD1755PMU::_readADCGated(4) ADC read bad state: 1
|
||||
|
||||
|
||||
AppleD1755PMU::_readADCGated(4) failed with status=e00002d6
|
||||
|
||||
|
||||
AppleD1755PMUPowerSource: AppleUSBCableDetect 0
|
||||
|
||||
|
||||
AppleD1755PMUPowerSource: AppleUSBCableType Detached
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice::init : Logging Buffer Length = 4K
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice::start : buffer-options 0x00000400
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice::start : registers at 0xccc7d000, 0x86100000 physical
|
||||
|
||||
AppleSynopsysOTGDevice::start : object is 0xc0626600, registers at 0xccc7d000, 0x86100000 physical
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice::findMaxEndpoints: in EPs: 7, out EPs: 7, max_endpoint: 8, num_endpoints: 14
|
||||
|
||||
|
||||
AppleD1755PMU::_readADCGated(3) ADC read bad state: 1
|
||||
|
||||
|
||||
AppleD1755PMU::_readADCGated(3) failed with status=e00002d6
|
||||
|
||||
|
||||
FIPS USER Space POST Success!
|
||||
|
||||
|
||||
|
||||
AppleIOPSDIOEndpoint::init(): Failed to get IOP after 10 sec.
|
||||
|
||||
|
||||
TVOUT SHUT DOWN PROBLEM: !(enable.reg.clkgating_rdy)
|
||||
|
||||
|
||||
TVOUT SHUT DOWN PROBLEM: !(mix_ctrl.reg.reg_mixer_ready_clk_down)
|
||||
|
||||
|
||||
TVOUT SHUT DOWN PROBLEM: !(readSDOReg(SDO_CLKCON) & 0x2)
|
||||
|
||||
|
||||
virtual void AppleM2CLCD::do_set_debug_flags(uint32_t, uint32_t), ******************** DITHER STATE IS SET TO 0 **********************
|
||||
|
||||
|
||||
booted from secure root: give device keybag access to everyone
|
||||
|
||||
|
||||
booted from secure root: give device keybag access to everyone
|
||||
|
||||
|
||||
launchd[19] Builtin profile: ptpd (sandbox)
|
||||
|
||||
|
||||
launchd[42] Builtin profile: iapd (sandbox)
|
||||
|
||||
|
||||
launchd[57] Builtin profile: BTServer (sandbox)
|
||||
|
||||
|
||||
AMFI: Invalid signature but permitting execution
|
||||
|
||||
|
||||
booted from secure root: give device keybag access to everyone
|
||||
|
||||
|
||||
booted from secure root: give device keybag access to everyone
|
||||
|
||||
|
||||
launchd[64] Builtin profile: apsd (sandbox)
|
||||
|
||||
|
||||
ios6-emu: initialisation du trousseau systC(me
|
||||
|
||||
|
||||
|
||||
booted from secure root: give device keybag access to everyone
|
||||
|
||||
|
||||
Will try to use UIDPlus to derive key
|
||||
|
||||
|
||||
launchd[66] Builtin profile: mobileassetd (sandbox)
|
||||
|
||||
|
||||
AppleKeyStore:cp_key_store_action(1)
|
||||
|
||||
|
||||
booted from secure root: give device keybag access to everyone
|
||||
|
||||
|
||||
ios6-emu: trousseau RAM create=0 handle=1
|
||||
|
||||
|
||||
|
||||
AppleKeyStore:cp_key_store_action(1)
|
||||
|
||||
|
||||
ios6-emu: trousseau RAM set_system=0
|
||||
|
||||
|
||||
|
||||
booted from secure root: give device keybag access to everyone
|
||||
|
||||
|
||||
ios6-emu: preferences de session synchronisees=1
|
||||
|
||||
|
||||
|
||||
ios6-emu: environnement graphique pid=12 /usr/libexec/backboardd
|
||||
|
||||
|
||||
|
||||
ios6-emu: CA_ENABLE_OGL=0
|
||||
|
||||
|
||||
|
||||
ios6-emu: CA_PRINT_PERF=1
|
||||
|
||||
|
||||
|
||||
ios6-emu: CA_NO_ACCEL=1
|
||||
|
||||
|
||||
|
||||
ios6-emu: environnement graphique pid=60 /System/Library/CoreServices/SpringBoard.app/SpringBoard
|
||||
|
||||
|
||||
|
||||
ios6-emu: CA_ENABLE_OGL=0
|
||||
|
||||
|
||||
|
||||
ios6-emu: CA_PRINT_PERF=1
|
||||
|
||||
|
||||
|
||||
ios6-emu: CA_NO_ACCEL=1
|
||||
|
||||
|
||||
|
||||
ios6-emu: ecran status=268435459 verrouille=0 code=1
|
||||
|
||||
|
||||
|
||||
ios6-emu: ecran status=268435459 verrouille=0 code=1
|
||||
|
||||
|
||||
|
||||
booted from secure root: give device keybag access to everyone
|
||||
|
||||
|
||||
booted from secure root: give device keybag access to everyone
|
||||
|
||||
|
||||
ios6-emu: ecran status=268435459 verrouille=0 code=1
|
||||
|
||||
|
||||
|
||||
ios6-emu: ecran status=268435459 verrouille=0 code=1
|
||||
|
||||
|
||||
|
||||
booted from secure root: give device keybag access to everyone
|
||||
|
||||
|
||||
booted from secure root: give device keybag access to everyone
|
||||
|
||||
|
||||
booted from secure root: give device keybag access to everyone
|
||||
|
||||
|
||||
ios6-emu: ecran status=268435459 verrouille=0 code=1
|
||||
|
||||
|
||||
|
||||
AppleIOPSDIOEndpoint::init(): Failed to get IOP after 130 sec.
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice - Configuration: PTP
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice Interface: PTP
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice - Configuration: iPod USB Interface
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice Interface: USBAudioControl
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice Interface: USBAudioStreaming
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice Interface: IapOverUsbHid
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice - Configuration: PTP + Apple Mobile Device
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice Interface: PTP
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice Interface: AppleUSBMux
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice - Configuration: PTP + Apple Mobile Device + Apple USB Ethernet
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice Interface: PTP
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice Interface: AppleUSBMux
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice Interface: AppleUSBEthernet
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice::gated_registerFunction Register function USBAudioControl
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice::gated_registerFunction Register function USBAudioStreaming
|
||||
|
||||
|
||||
IOAccessoryPortUSB::start
|
||||
|
||||
|
||||
virtual bool AppleUSBDeviceMux::start(IOService *) build: Feb 13 2013 22:02:59
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice::gated_registerFunction Register function IapOverUsbHid
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice::gated_registerFunction Register function AppleUSBEthernet
|
||||
|
||||
|
||||
init_waste
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice::gated_registerFunction Register function AppleUSBMux
|
||||
|
||||
|
||||
AppleUSBEthernetDevice: Ethernet address 02:00:00:00:00:00
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice::gated_registerFunction Register function PTP
|
||||
|
||||
|
||||
AppleSynopsysOTGDevice::startUSBStack Starting usb stack
|
||||
|
||||
|
||||
ios6-emu: ecran status=268435459 verrouille=0 code=1
|
||||
|
||||
|
||||
|
||||
launchd[87] Builtin profile: geod (sandbox)
|
||||
|
||||
|
||||
ios6-emu: ecran status=268435459 verrouille=0 code=1
|
||||
|
||||
|
||||
|
||||
booted from secure root: give device keybag access to everyone
|
||||
|
||||
|
||||
booted from secure root: give device keybag access to everyone
|
||||
|
||||
|
||||
launchd[95] Builtin profile: MobileMail (sandbox)
|
||||
|
||||
|
||||
ios6-emu: ecran status=0 verrouille=1 code=0
|
||||
|
||||
|
||||
|
||||
booted from secure root: give device keybag access to everyone
|
||||
|
||||
|
||||
void AppleM2CLCD::disable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
ApplePinotLCD::_lcdEnable: enable: 0
|
||||
|
||||
booted from secure root: give device keybag access to everyone
|
||||
|
||||
|
||||
ios6-emu: geste de deverrouillage transmis a GraphicsServices
|
||||
|
||||
|
||||
|
||||
launchd[100] Builtin profile: syncdefaultsd (sandbox)
|
||||
|
||||
|
||||
ios6-emu: ecran status=0 verrouille=1 code=0
|
||||
|
||||
|
||||
|
||||
ApplePinotLCD::_lcdEnable: enable: 1
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
booted from secure root: give device keybag access to everyone
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
Dec 31 16:03:34 iPhone SpringBoard[60] <Error>: too many attempts to unregister from camera preview well changes, ignoring
|
||||
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
ios6-emu: geste de deverrouillage transmis a GraphicsServices
|
||||
|
||||
|
||||
|
||||
booted from secure root: give device keybag access to everyone
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
booted from secure root: give device keybag access to everyone
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
ios6-emu: ecran status=0 verrouille=0 code=0
|
||||
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
void AppleM2CLCD::safe_enable_backlight(), Where is my backlight?
|
||||
|
||||
|
||||
ios6-emu: ecran status=0 verrouille=0 code=0
|
||||
|
||||
|
||||
|
||||
AppleIOPSDIOEndpoint::init(): Failed to get IOP after 250 sec.
|
||||
|
||||
|
||||
ios6-emu: ecran status=0 verrouille=0 code=0
|
||||
|
||||
|
||||
|
||||
ios6-emu: ecran status=0 verrouille=0 code=0
|
||||
|
||||
|
||||
|
||||
ios6-emu: ecran status=0 verrouille=0 code=0
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 211 KiB |
@@ -0,0 +1 @@
|
||||
OK : scanout DART, pages disjointes, composition alpha, limites des plans et acquittement VBlank.
|
||||
@@ -0,0 +1,2 @@
|
||||
OK : empreintes, DeviceTree, noyau inchangé, BSS, mémoire réservée, RAMDisk, NVRAM et source QEMU.
|
||||
OK : quatre adaptations noyau, RAM relocalisée, disque HFSX indépendant, panneau LCD et framebuffer.
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"firmware": "iPhone2,1 iOS 6.1.6 10B500",
|
||||
"capture_source": "evidence/probe-20261003T125116-664879Z/screen-023.png",
|
||||
"capture_sha256": "ec37647301c0f4a5a80f4e47a8369a8043dededbdc05c8b8b66eced0ff646043",
|
||||
"verification": "Écran d’accueil et dock inspectés visuellement ; capture QMP du framebuffer invité.",
|
||||
"original_iphoneos2_unchanged": true,
|
||||
"limitations": [
|
||||
"Geste de démarrage automatique via GraphicsServices",
|
||||
"Pas encore de tactile commandé par la souris hôte",
|
||||
"Pas de réseau, modem, audio ou accélération SGX",
|
||||
"Trousseau de session RAM expérimental ; firmware non activé"
|
||||
],
|
||||
"fresh_boot_reproduced": true,
|
||||
"first_home_capture_seconds": 220,
|
||||
"screen_lock_status": {
|
||||
"locked": false,
|
||||
"passcode": false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/* Provisionnement expérimental du volume vierge ; exécuté uniquement dans la VM. */
|
||||
#include <stdio.h>
|
||||
#include <dlfcn.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include "session_input.h"
|
||||
|
||||
static void configure_session(void)
|
||||
{
|
||||
CFStringRef user = CFSTR("mobile"), host = kCFPreferencesAnyHost;
|
||||
CFStringRef buddy = CFSTR("com.apple.purplebuddy");
|
||||
CFStringRef keys[] = { CFSTR("ForceNoBuddy"), CFSTR("SetupDone"),
|
||||
CFSTR("SetupFinishedAllSteps") };
|
||||
for (unsigned i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) {
|
||||
CFPreferencesSetValue(keys[i], kCFBooleanTrue, buddy, user, host);
|
||||
}
|
||||
int version = 3;
|
||||
CFNumberRef number = CFNumberCreate(NULL, kCFNumberIntType, &version);
|
||||
CFPreferencesSetValue(CFSTR("SetupVersion"), number, buddy, user, host);
|
||||
CFRelease(number);
|
||||
printf("ios6-emu: preferences de session synchronisees=%d\n",
|
||||
CFPreferencesSynchronize(buddy, user, host));
|
||||
chown("/var/mobile/Library/Preferences/com.apple.purplebuddy.plist", 501, 501);
|
||||
chown("/var/mobile/Library/Preferences/com.apple.purplebuddy.notbackedup.plist", 501, 501);
|
||||
double seconds = 3600;
|
||||
number = CFNumberCreate(NULL, kCFNumberDoubleType, &seconds);
|
||||
CFPreferencesSetValue(CFSTR("SBAutoDimTime"), number, CFSTR("com.apple.springboard"), user, host);
|
||||
CFRelease(number);
|
||||
CFPreferencesSynchronize(CFSTR("com.apple.springboard"), user, host);
|
||||
chown("/var/mobile/Library/Preferences/com.apple.springboard.plist", 501, 501);
|
||||
}
|
||||
|
||||
static void diagnose_graphics_environment(void)
|
||||
{
|
||||
static unsigned char seen[160];
|
||||
static char buffer[65536];
|
||||
for (int pid = 2; pid < 160; pid++) {
|
||||
if (seen[pid]) continue;
|
||||
int mib[] = { CTL_KERN, KERN_PROCARGS2, pid };
|
||||
size_t size = sizeof(buffer) - 1;
|
||||
if (sysctl(mib, 3, buffer, &size, NULL, 0) || size <= sizeof(int)) continue;
|
||||
buffer[size] = 0;
|
||||
const char *path = buffer + sizeof(int);
|
||||
if (!strstr(path, "/backboardd") && !strstr(path, "/SpringBoard")) continue;
|
||||
seen[pid] = 1;
|
||||
printf("ios6-emu: environnement graphique pid=%d %s\n", pid, path);
|
||||
for (size_t offset = sizeof(int); offset < size;) {
|
||||
const char *entry = buffer + offset;
|
||||
if (!strncmp(entry, "CA_", 3)) printf("ios6-emu: %s\n", entry);
|
||||
offset += strlen(entry) + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Déverrouillage de la session de démonstration vierge, sans code configuré.
|
||||
* Utilise le serveur SpringBoard, sans modifier son exécutable. */
|
||||
static void show_home_screen(void)
|
||||
{
|
||||
static void *library;
|
||||
if (!library) library = dlopen("/System/Library/PrivateFrameworks/SpringBoardServices.framework/SpringBoardServices", RTLD_NOW);
|
||||
if (!library) return;
|
||||
unsigned (*server)(void) = dlsym(library, "SBSSpringBoardServerPort");
|
||||
int (*status)(unsigned, unsigned char *, unsigned char *) = dlsym(library, "SBGetScreenLockStatus");
|
||||
int (*dim)(unsigned, unsigned char) = dlsym(library, "SBDimScreen");
|
||||
if (!server || !status || !dim) return;
|
||||
unsigned port = server();
|
||||
unsigned char locked = 0, passcode = 1;
|
||||
int result = status(port, &locked, &passcode);
|
||||
printf("ios6-emu: ecran status=%d verrouille=%u code=%u\n", result, locked, passcode);
|
||||
if (result || passcode) return;
|
||||
dim(port, 0);
|
||||
if (locked) {
|
||||
sleep(1);
|
||||
send_unlock_swipe();
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
freopen("/dev/console", "w", stdout);
|
||||
freopen("/dev/console", "w", stderr);
|
||||
setbuf(stdout, NULL);
|
||||
setbuf(stderr, NULL);
|
||||
puts("ios6-emu: initialisation du trousseau système");
|
||||
void *library = dlopen("/System/Library/PrivateFrameworks/MobileKeyBag.framework/MobileKeyBag", RTLD_NOW);
|
||||
if (!library) {
|
||||
fprintf(stderr, "MobileKeyBag: %s\n", dlerror());
|
||||
return 1;
|
||||
}
|
||||
int (*create_system)(int, const char *) = dlsym(library, "MKBKeyBagCreateSystemUnwrapped");
|
||||
if (!create_system) {
|
||||
fprintf(stderr, "MKBKeyBagCreateSystemUnwrapped absent\n");
|
||||
return 1;
|
||||
}
|
||||
/* Fonctions internes vérifiées du cache 10B500 : création puis adoption
|
||||
* du trousseau de session. Aucun fichier chiffré sans clé matérielle. */
|
||||
uintptr_t slide = (uintptr_t)create_system - 0x354a40bd;
|
||||
int (*create_bag)(void *, int, int *) = (void *)(slide + 0x354a75b1);
|
||||
int (*set_system)(int) = (void *)(slide + 0x354a7371);
|
||||
if (memcmp((void *)(slide + 0x354a75b0), "\xf0\xb5\x03\xaf\x8d\xb0\x6c\x46", 8) ||
|
||||
memcmp((void *)(slide + 0x354a7370), "\x90\xb5\x01\xaf\x89\xb0\x6c\x46", 8)) {
|
||||
fputs("ios6-emu: MobileKeyBag incompatible avec 10B500\n", stderr);
|
||||
return 1;
|
||||
}
|
||||
int handle = -1;
|
||||
int result = create_bag(NULL, (int)0x80000000, &handle);
|
||||
printf("ios6-emu: trousseau RAM create=%d handle=%d\n", result, handle);
|
||||
if (result) return 2;
|
||||
result = set_system(handle);
|
||||
printf("ios6-emu: trousseau RAM set_system=%d\n", result);
|
||||
if (result) return 3;
|
||||
configure_session();
|
||||
/* Inclut le premier démarrage et ses migrations ; maintient la démo
|
||||
* visible pendant six minutes, puis cesse toute entrée automatique. */
|
||||
for (int iteration = 0; iteration < 24; iteration++) {
|
||||
sleep(15);
|
||||
diagnose_graphics_environment();
|
||||
show_home_screen();
|
||||
sync();
|
||||
}
|
||||
for (;;) pause();
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/* Geste de démonstration via GraphicsServices, ABI ARM32 iOS 6.
|
||||
* Structure recoupée avec GSEvent.h et l'implémentation iOS 6 de hid-support :
|
||||
* https://github.com/mringwal/hid-support/tree/master/hidspringboard
|
||||
* Aucun pixel n'est dessiné par cet outil.
|
||||
*/
|
||||
static int send_touch_gesture(float x1, float y1, float x2, float y2, unsigned duration_ms, const char *bundle)
|
||||
{
|
||||
void *gs = dlopen("/System/Library/PrivateFrameworks/GraphicsServices.framework/GraphicsServices", RTLD_NOW);
|
||||
if (!gs) return -1;
|
||||
void (*send)(const void *) = dlsym(gs, "GSSendSystemEvent");
|
||||
void (*send_port)(const void *, unsigned) = dlsym(gs, "GSSendEvent");
|
||||
unsigned (*copy_port)(const char *) = dlsym(gs, "GSCopyPurpleNamedPort");
|
||||
uint64_t (*timestamp)(void) = dlsym(gs, "GSCurrentEventTimestamp");
|
||||
if (!send || !timestamp) { dlclose(gs); return -1; }
|
||||
unsigned port = bundle && copy_port ? copy_port(bundle) : 0;
|
||||
if (bundle && (!port || !send_port)) { dlclose(gs); return -2; }
|
||||
/* GSEventRecord: 52 octets ; GSHandInfo: 36 ; GSPathInfo: 24. */
|
||||
for (int step = 0; step <= 31; step++) {
|
||||
uint32_t packet[28] = {0};
|
||||
unsigned char *bytes = (void *)packet;
|
||||
int down = step < 31;
|
||||
float fraction = (step < 30 ? step : 30) / 30.0f;
|
||||
float point[2] = {x1 + (x2-x1)*fraction, y1 + (y2-y1)*fraction};
|
||||
uint64_t time = timestamp();
|
||||
packet[0] = 3001;
|
||||
memcpy(bytes + 8, point, sizeof(point));
|
||||
memcpy(bytes + 16, point, sizeof(point));
|
||||
memcpy(bytes + 28, &time, sizeof(time));
|
||||
packet[12] = 60;
|
||||
packet[13] = step == 0 ? 1 : down ? 2 : 6;
|
||||
bytes[86] = 1; /* path count, iOS 5+ */
|
||||
bytes[88] = 1; /* path index */
|
||||
bytes[89] = 2; /* path identity */
|
||||
bytes[90] = down ? 3 : 0; /* range + touch */
|
||||
memcpy(bytes + 100, point, sizeof(point));
|
||||
if (port) send_port(packet, port); else send(packet);
|
||||
usleep(duration_ms * 1000 / 32);
|
||||
}
|
||||
dlclose(gs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Touche clavier matériel (GSEventKeyDown 10 / KeyUp 11). GSEventCreateKeyEvent
|
||||
* exige le clavier d'un processus UIKit : l'enregistrement est donc construit
|
||||
* à la main. GSHardwareKeyInfo (144 octets) suit l'en-tête de 52 octets :
|
||||
* keyCode, charIgnoringModifier, charCode, charSet, puis longueur et UTF-16
|
||||
* des caractères (32 max), même chose pour les caractères non modifiés. */
|
||||
static int send_key_sequence(UniChar unicode, const char *bundle, const char *seq, uint16_t keycode);
|
||||
static int send_key_event(UniChar unicode, const char *bundle)
|
||||
{
|
||||
/* Vérifié sous iOS 6.1.6 : UIKit insère le caractère porté par chaque
|
||||
* événement, et seul un relâchement avec caractère arrête la répétition.
|
||||
* L'appui est donc vide et le relâchement porte le caractère. */
|
||||
return send_key_sequence(unicode, bundle, "dU", 0);
|
||||
}
|
||||
|
||||
/* seq : D/d appui avec/sans caractère, U/u relâchement avec/sans caractère. */
|
||||
static int send_key_sequence(UniChar unicode, const char *bundle, const char *seq, uint16_t keycode)
|
||||
{
|
||||
void *gs = dlopen("/System/Library/PrivateFrameworks/GraphicsServices.framework/GraphicsServices", RTLD_NOW);
|
||||
if (!gs) return -1;
|
||||
void (*send)(const void *) = dlsym(gs, "GSSendSystemEvent");
|
||||
void (*send_port)(const void *, unsigned) = dlsym(gs, "GSSendEvent");
|
||||
unsigned (*copy_port)(const char *) = dlsym(gs, "GSCopyPurpleNamedPort");
|
||||
uint64_t (*timestamp)(void) = dlsym(gs, "GSCurrentEventTimestamp");
|
||||
if (!send || !timestamp) { dlclose(gs); return -1; }
|
||||
unsigned port = bundle && copy_port ? copy_port(bundle) : 0;
|
||||
if (bundle && (!port || !send_port)) { dlclose(gs); return -2; }
|
||||
for (const char *step = seq; *step; step++) {
|
||||
uint32_t packet[49] = {0}; /* 52 + 144 octets */
|
||||
unsigned char *bytes = (void *)packet;
|
||||
uint64_t time = timestamp();
|
||||
UniChar info[4] = {keycode, unicode, unicode, 0};
|
||||
uint16_t one = *step == 'D' || *step == 'U';
|
||||
packet[0] = *step == 'D' || *step == 'd' ? 10 : 11;
|
||||
memcpy(bytes + 28, &time, sizeof(time));
|
||||
packet[12] = 144; /* infoSize */
|
||||
memcpy(bytes + 52, info, sizeof(info));
|
||||
memcpy(bytes + 60, &one, 2); /* characters_length */
|
||||
memcpy(bytes + 62, &unicode, 2); /* characters[0] */
|
||||
memcpy(bytes + 126, &one, 2); /* unmodified_characters_length */
|
||||
memcpy(bytes + 128, &unicode, 2);
|
||||
if (port) send_port(packet, port); else send(packet);
|
||||
usleep(50000); /* 20 ms : caractères perdus près des espaces */
|
||||
}
|
||||
dlclose(gs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void send_unlock_swipe(void)
|
||||
{
|
||||
send_touch_gesture(50, 433, 245, 433, 800, NULL);
|
||||
}
|
||||
Executable
+26
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
# Compile le QEMU de ce dépôt (modèle ios6-n88 inclus) et le relais netd
|
||||
# dans ios6/build, sans toucher au build/ de l'émulateur iPhone OS 2.
|
||||
set -euo pipefail
|
||||
sim_root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
qemu_root="$(dirname -- "$sim_root")"
|
||||
cd "$sim_root"
|
||||
for program in cc ninja pkg-config git python3; do
|
||||
command -v "$program" >/dev/null || { echo "Dépendance absente : $program" >&2; exit 1; }
|
||||
done
|
||||
mkdir -p evidence build
|
||||
if [[ ! -d .venv ]]; then
|
||||
python3 -m venv .venv
|
||||
fi
|
||||
.venv/bin/python -m pip install -r requirements.txt > evidence/python-deps.log 2>&1
|
||||
cd build
|
||||
"$qemu_root/configure" --python="$sim_root/.venv/bin/python" \
|
||||
--target-list=arm-softmmu --disable-docs --disable-werror \
|
||||
--disable-gtk --disable-sdl --disable-slirp --disable-capstone \
|
||||
--disable-tools --disable-guest-agent --disable-debug-info \
|
||||
--extra-cflags="$(pkg-config --cflags openssl 2>/dev/null)" \
|
||||
--extra-ldflags="$(pkg-config --libs-only-L openssl 2>/dev/null) -lcrypto" > ../evidence/configure.log 2>&1
|
||||
ninja -j"${IOS6_BUILD_JOBS:-4}" qemu-system-arm > ../evidence/build.log 2>&1
|
||||
cd ..
|
||||
bash tools/build_netd.sh
|
||||
echo 'Compilation du prototype iOS 6 terminée.'
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
sim_root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
|
||||
cd "$sim_root"
|
||||
mkdir -p build
|
||||
if [[ -x /opt/cctools/bin/arm-apple-darwin9-gcc ]]; then
|
||||
/opt/cctools/bin/arm-apple-darwin9-gcc -isysroot /opt/theos/sdks/iPhoneOS2.2.1.sdk -miphoneos-version-min=2.2.1 -std=gnu99 -O2 agent/ios6-agent.c -framework CoreFoundation -framework SystemConfiguration -o build/ios6-agent
|
||||
/opt/cctools/bin/ldid -Sagent/entitlements.plist build/ios6-agent
|
||||
else
|
||||
# macOS : clang de Xcode, mêmes contraintes que tools/build_app.py
|
||||
# (cible 5.1 pour LC_UNIXTHREAD, code ARM seulement).
|
||||
sdk=${IOS6_SDK:-$sim_root/references/sdk/iPhoneOS6.0.sdk}
|
||||
[[ -f $sdk/SDKSettings.plist ]] || sdk=${THEOS:-$HOME/theos}/sdks/iPhoneOS6.1.sdk
|
||||
xcrun clang -target armv7-apple-ios5.1 -marm -isysroot "$sdk" -std=gnu99 -O2 -Wno-incompatible-pointer-types-discards-qualifiers \
|
||||
agent/ios6-agent.c -framework CoreFoundation -framework SystemConfiguration -o build/ios6-agent
|
||||
ldid -Sagent/entitlements.plist build/ios6-agent
|
||||
fi
|
||||
bash tools/build_netd.sh
|
||||
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Compile un projet Objective-C simple (.m) en bundle ARM pour la VM iOS 6."""
|
||||
import argparse,os,pathlib,plistlib,shutil,subprocess
|
||||
ROOT=pathlib.Path(__file__).resolve().parents[1]
|
||||
CCTOOLS=pathlib.Path('/opt/cctools/bin')
|
||||
def default_sdk():
|
||||
if os.environ.get('IOS6_SDK'): return os.environ['IOS6_SDK']
|
||||
for sdk in (ROOT/'references/sdk/iPhoneOS6.0.sdk',pathlib.Path(os.environ.get('THEOS',pathlib.Path.home()/'theos'))/'sdks/iPhoneOS6.1.sdk'):
|
||||
if (sdk/'SDKSettings.plist').is_file(): return str(sdk)
|
||||
return str(ROOT/'references/sdk/iPhoneOS6.0.sdk')
|
||||
def compiler():
|
||||
"""GCC cctools sous Linux, clang de Xcode sous macOS."""
|
||||
if (CCTOOLS/'arm-apple-darwin9-gcc').exists(): return [str(CCTOOLS/'arm-apple-darwin9-gcc'),'-arch','armv7','-miphoneos-version-min=6.0'],str(CCTOOLS/'ldid')
|
||||
# Le ld récent ne pose plus le bit Thumb sur le point d'entrée LC_MAIN ni sur
|
||||
# les IMP Objective-C : sous iOS 6, le saut part en mode ARM (SIGBUS
|
||||
# EXC_ARM_DA_ALIGN). Cible 5.1 (crt1.o, LC_UNIXTHREAD) et code ARM seulement.
|
||||
return ['xcrun','clang','-target','armv7-apple-ios5.1','-marm'],shutil.which('ldid') or 'ldid'
|
||||
def main():
|
||||
p=argparse.ArgumentParser(description=__doc__);p.add_argument('project',type=pathlib.Path,nargs='?',default=ROOT/'apps/SimulatorLab');p.add_argument('--bundle-id');p.add_argument('--sdk',default=default_sdk());a=p.parse_args()
|
||||
if not pathlib.Path(a.sdk,'SDKSettings.plist').is_file(): p.error('SDK iOS absent : exécuter tools/prepare_sdk.py ou fournir --sdk')
|
||||
name=a.project.resolve().name;out=ROOT/'build/apps'/(name+'.app');out.mkdir(parents=True,exist_ok=True)
|
||||
a.bundle_id=a.bundle_id or 'org.ios6emu.'+name
|
||||
sources=sorted(a.project.glob('*.m'))
|
||||
if not sources: p.error('Aucune source Objective-C')
|
||||
cc,ldid=compiler()
|
||||
subprocess.run([*cc,'-isysroot',a.sdk,'-fblocks','-std=gnu99','-O2','-Wall','-Wextra',*map(str,sources),'-framework','UIKit','-framework','Foundation','-framework','CoreGraphics','-o',str(out/name)],check=True)
|
||||
(out/'Info.plist').write_bytes(plistlib.dumps({'CFBundleIdentifier':a.bundle_id,'CFBundleExecutable':name,'CFBundleName':name,'CFBundleDisplayName':name,'CFBundlePackageType':'APPL','CFBundleVersion':'1','MinimumOSVersion':'6.0','LSRequiresIPhoneOS':True,'UIDeviceFamily':[1]}))
|
||||
subprocess.run([ldid,'-S',str(out/name)],check=True);print(out)
|
||||
if __name__=='__main__': main()
|
||||
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env bash
|
||||
# Compile la fenêtre macOS de la VM iOS 6 dans build/iOS6 Simulator.app.
|
||||
set -euo pipefail
|
||||
sim_root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
|
||||
app="$sim_root/build/iOS6 Simulator.app"
|
||||
mkdir -p "$app/Contents/MacOS"
|
||||
xcrun swiftc -O -o "$app/Contents/MacOS/iOS6Simulator" "$sim_root/macos/iOS6Simulator.swift"
|
||||
cat > "$app/Contents/Info.plist" <<'PLIST'
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0"><dict>
|
||||
<key>CFBundleIdentifier</key><string>org.ios6emu.mac</string>
|
||||
<key>CFBundleName</key><string>iOS6 Simulator</string>
|
||||
<key>CFBundleExecutable</key><string>iOS6Simulator</string>
|
||||
<key>CFBundlePackageType</key><string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key><string>1.0</string>
|
||||
<key>LSMinimumSystemVersion</key><string>13.0</string>
|
||||
<key>NSHighResolutionCapable</key><true/>
|
||||
</dict></plist>
|
||||
PLIST
|
||||
codesign -s - --force "$app" >/dev/null
|
||||
echo "$app"
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
# Relais réseau de l'hôte (PPP sur UART1 vers libslirp) ; Linux et macOS.
|
||||
set -euo pipefail
|
||||
sim_root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
|
||||
cd "$sim_root"
|
||||
mkdir -p build
|
||||
cc -O2 agent/netd.c -o build/ios6-netd.new \
|
||||
-I"$(pkg-config --variable=includedir slirp)" $(pkg-config --cflags --libs slirp)
|
||||
mv build/ios6-netd.new build/ios6-netd
|
||||
@@ -0,0 +1,73 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Résout une adresse ARM32 dans le cache dyld Apple, avec glissement explicite."""
|
||||
import argparse
|
||||
import pathlib
|
||||
import struct
|
||||
|
||||
ROOT = pathlib.Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
class Cache:
|
||||
def __init__(self):
|
||||
self.data = (ROOT / 'firmware/dyld_shared_cache_armv7').read_bytes()
|
||||
b = self.data
|
||||
assert b[:16] == b'dyld_v1 armv7\0'
|
||||
mo, mc, io, ic = struct.unpack_from('<4I', b, 16)
|
||||
self.maps = [struct.unpack_from('<QQQII', b, mo + 32*i) for i in range(mc)]
|
||||
self.images = []
|
||||
for i in range(ic):
|
||||
address, _, _, name, _ = struct.unpack_from('<QQQII', b, io + 32*i)
|
||||
self.images.append((address, self.string(name)))
|
||||
self.images.sort()
|
||||
|
||||
def string(self, offset):
|
||||
return self.data[offset:self.data.index(0, offset)].decode(errors='replace')
|
||||
|
||||
def offset(self, address):
|
||||
for base, size, offset, _, _ in self.maps:
|
||||
if base <= address < base + size:
|
||||
return offset + address - base
|
||||
raise ValueError(hex(address))
|
||||
|
||||
def resolve(self, address):
|
||||
base, name = max(i for i in self.images if i[0] <= address)
|
||||
header = self.offset(base)
|
||||
cursor = header + 28
|
||||
symbols = []
|
||||
for _ in range(struct.unpack_from('<I', self.data, header + 16)[0]):
|
||||
cmd, size = struct.unpack_from('<II', self.data, cursor)
|
||||
if cmd == 2:
|
||||
so, count, st, _ = struct.unpack_from('<4I', self.data, cursor + 8)
|
||||
for i in range(count):
|
||||
no, _, _, _, value = struct.unpack_from('<IBBHI', self.data, so + 12*i)
|
||||
if base <= value <= address:
|
||||
symbols.append((value, self.string(st + no)))
|
||||
cursor += size
|
||||
previous = max(symbols) if symbols else None
|
||||
named = [s for s in symbols if s[1] != '<redacted>']
|
||||
return name, previous, max(named) if named else None
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('addresses', nargs='+', type=lambda a: int(a, 0))
|
||||
parser.add_argument('--slide', type=lambda a: int(a, 0), default=0)
|
||||
parser.add_argument('--bytes', type=int, default=0)
|
||||
args = parser.parse_args()
|
||||
cache = Cache()
|
||||
for runtime in args.addresses:
|
||||
address = (runtime - args.slide) & ~1
|
||||
name, previous, named = cache.resolve(address)
|
||||
print(f'{runtime:#x} -> {address:#x} : {name}')
|
||||
for label, symbol in [('symbole précédent', previous), ('export précédent', named)]:
|
||||
if symbol:
|
||||
print(f' {label}: {symbol[1]}+{address-symbol[0]:#x}')
|
||||
if args.bytes:
|
||||
from capstone import Cs, CS_ARCH_ARM, CS_MODE_THUMB
|
||||
offset = cache.offset(address)
|
||||
for i in Cs(CS_ARCH_ARM, CS_MODE_THUMB).disasm(cache.data[offset:offset + args.bytes], address):
|
||||
print(f' {i.address:08x}: {i.mnemonic:10s} {i.op_str}')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,67 @@
|
||||
"""Client RSP minimal pour examiner notre VM QEMU locale."""
|
||||
import socket
|
||||
|
||||
|
||||
class Remote:
|
||||
def __init__(self, path):
|
||||
self.socket = socket.socket(socket.AF_UNIX)
|
||||
self.socket.settimeout(10)
|
||||
self.socket.connect(str(path))
|
||||
|
||||
def command(self, command):
|
||||
payload = command.encode()
|
||||
self.socket.sendall(b'$' + payload + b'#' + f'{sum(payload) & 255:02x}'.encode())
|
||||
return self.receive()
|
||||
|
||||
def receive(self):
|
||||
while True:
|
||||
marker = self.socket.recv(1)
|
||||
if not marker:
|
||||
raise EOFError('Débogueur déconnecté')
|
||||
if marker == b'$':
|
||||
break
|
||||
reply = bytearray()
|
||||
while True:
|
||||
c = self.socket.recv(1)
|
||||
if c == b'#':
|
||||
break
|
||||
if not c:
|
||||
raise EOFError('Débogueur déconnecté')
|
||||
reply += c
|
||||
checksum = self.socket.recv(2)
|
||||
assert int(checksum, 16) == sum(reply) & 255
|
||||
self.socket.sendall(b'+')
|
||||
# Décodage RSP : échappement et répétition.
|
||||
result = bytearray()
|
||||
i = 0
|
||||
while i < len(reply):
|
||||
if reply[i] == ord('}'):
|
||||
i += 1
|
||||
result.append(reply[i] ^ 0x20)
|
||||
elif reply[i] == ord('*'):
|
||||
i += 1
|
||||
result.extend([result[-1]] * (reply[i] - 29))
|
||||
else:
|
||||
result.append(reply[i])
|
||||
i += 1
|
||||
return result.decode()
|
||||
|
||||
def monitor(self, command):
|
||||
result = self.command('qRcmd,' + command.encode().hex())
|
||||
output = bytearray()
|
||||
while result != 'OK':
|
||||
if not result.startswith('O'):
|
||||
raise RuntimeError(result)
|
||||
output += bytes.fromhex(result[1:])
|
||||
result = self.receive()
|
||||
return output.decode(errors='replace')
|
||||
|
||||
def write_memory(self, address, data):
|
||||
assert self.command(f'M{address:x},{len(data):x}:{data.hex()}') == 'OK'
|
||||
|
||||
def write_register(self, number, value):
|
||||
assert self.command(f'P{number:x}:{value.to_bytes(4, "little").hex()}') == 'OK'
|
||||
|
||||
def close(self):
|
||||
self.command('D')
|
||||
self.socket.close()
|
||||
Executable
+83
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Lecture des formats Apple DeviceTree et Mach-O ARM32, sans modification."""
|
||||
import json
|
||||
import pathlib
|
||||
import struct
|
||||
|
||||
|
||||
def devicetree(data, offset=0):
|
||||
nprops, nchildren = struct.unpack_from('<II', data, offset)
|
||||
offset += 8
|
||||
assert nprops < 10000 and nchildren < 10000
|
||||
props = {}
|
||||
for _ in range(nprops):
|
||||
name, size = struct.unpack_from('<32sI', data, offset)
|
||||
size &= 0x7fffffff
|
||||
offset += 36
|
||||
assert offset + size <= len(data)
|
||||
props[name.rstrip(b'\0').decode()] = data[offset:offset + size]
|
||||
offset += (size + 3) & ~3
|
||||
children = []
|
||||
for _ in range(nchildren):
|
||||
child, offset = devicetree(data, offset)
|
||||
children.append(child)
|
||||
return (props, children), offset
|
||||
|
||||
|
||||
def encode_tree(node):
|
||||
props, children = node
|
||||
result = bytearray(struct.pack('<II', len(props), len(children)))
|
||||
for name, value in props.items():
|
||||
result += struct.pack('<32sI', name.encode(), len(value))
|
||||
result += value + b'\0' * (-len(value) % 4)
|
||||
for child in children:
|
||||
result += encode_tree(child)
|
||||
return bytes(result)
|
||||
|
||||
|
||||
def walk(node, parent=''):
|
||||
props, children = node
|
||||
path = parent + '/' + props.get('name', b'?').rstrip(b'\0').decode(errors='replace')
|
||||
yield path, props
|
||||
for child in children:
|
||||
yield from walk(child, path)
|
||||
|
||||
|
||||
def macho(data):
|
||||
magic, cpu, subcpu, kind, ncmds, cmdsize, flags = struct.unpack_from('<7I', data)
|
||||
assert magic == 0xfeedface and cpu == 12
|
||||
segments = []
|
||||
entry = None
|
||||
offset = 28
|
||||
for _ in range(ncmds):
|
||||
cmd, size = struct.unpack_from('<II', data, offset)
|
||||
assert size >= 8 and offset + size <= len(data)
|
||||
if cmd == 1:
|
||||
name, va, vsize, fo, fs, maxp, initp, ns, sf = struct.unpack_from('<16s8I', data, offset + 8)
|
||||
segments.append(dict(name=name.rstrip(b'\0').decode(), vmaddr=va,
|
||||
vmsize=vsize, fileoff=fo, filesize=fs))
|
||||
elif cmd == 5:
|
||||
flavor, count = struct.unpack_from('<II', data, offset + 8)
|
||||
assert flavor == 1 and count == 17
|
||||
entry = struct.unpack_from('<I', data, offset + 16 + 15 * 4)[0]
|
||||
offset += size
|
||||
assert entry is not None
|
||||
return dict(entry=entry, segments=segments)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
root = pathlib.Path(__file__).resolve().parents[1]
|
||||
print(json.dumps(macho((root / 'firmware/Kernelcache.dec').read_bytes()), indent=2))
|
||||
tree, _ = devicetree((root / 'firmware/DeviceTree.dec').read_bytes())
|
||||
for path, props in walk(tree):
|
||||
print(path)
|
||||
for key, value in props.items():
|
||||
if key in ('name',):
|
||||
continue
|
||||
if value and all(32 <= x < 127 or x == 0 for x in value):
|
||||
formatted = repr(value.rstrip(b'\0').decode())
|
||||
elif len(value) % 4 == 0 and len(value) <= 128:
|
||||
formatted = ' '.join(hex(x) for x in struct.unpack('<' + 'I' * (len(value) // 4), value))
|
||||
else:
|
||||
formatted = value[:64].hex() + ('...' if len(value) > 64 else '')
|
||||
print(' ', key, formatted)
|
||||
Executable
+51
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Résout et désassemble une adresse du noyau ARM32 de référence."""
|
||||
import argparse
|
||||
import pathlib
|
||||
import struct
|
||||
from inspect_firmware import macho
|
||||
|
||||
ROOT = pathlib.Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def symbols(data):
|
||||
offset = 28
|
||||
result = []
|
||||
for _ in range(struct.unpack_from('<I', data, 16)[0]):
|
||||
cmd, size = struct.unpack_from('<II', data, offset)
|
||||
if cmd == 2:
|
||||
symoff, count, stroff, strsize = struct.unpack_from('<4I', data, offset + 8)
|
||||
for i in range(count):
|
||||
name, kind, section, desc, value = struct.unpack_from('<IBBHI', data, symoff + 12 * i)
|
||||
end = data.find(b'\0', stroff + name, stroff + strsize)
|
||||
if value and end >= 0:
|
||||
result.append((value, data[stroff + name:end].decode(errors='replace')))
|
||||
offset += size
|
||||
return sorted(result)
|
||||
|
||||
|
||||
def main():
|
||||
from capstone import Cs, CS_ARCH_ARM, CS_MODE_ARM, CS_MODE_THUMB
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('address', type=lambda s: int(s, 0))
|
||||
parser.add_argument('--arm', action='store_true')
|
||||
parser.add_argument('--bytes', type=int, default=128)
|
||||
args = parser.parse_args()
|
||||
address = args.address & ~1
|
||||
if 0x40000000 <= address < 0x50000000:
|
||||
address += 0x40000000
|
||||
data = (ROOT / 'firmware/Kernelcache.dec').read_bytes()
|
||||
previous = [s for s in symbols(data) if s[0] <= address]
|
||||
if previous:
|
||||
value, name = previous[-1]
|
||||
print(f'Symbole exporté précédent : {name}+0x{address-value:x} (peut être une autre fonction)')
|
||||
info = macho(data)
|
||||
segment = next(s for s in info['segments'] if s['vmaddr'] <= address < s['vmaddr'] + s['filesize'])
|
||||
offset = address - segment['vmaddr'] + segment['fileoff']
|
||||
mode = CS_MODE_ARM if args.arm else CS_MODE_THUMB
|
||||
for i in Cs(CS_ARCH_ARM, mode).disasm(data[offset:offset + args.bytes], address):
|
||||
print(f'{i.address:08x}: {i.mnemonic:10s} {i.op_str}')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Lit OSSerializeXML (ID/IDREF) et décrit les extensions du kernelcache."""
|
||||
import base64
|
||||
import json
|
||||
import pathlib
|
||||
import xml.etree.ElementTree as ET
|
||||
from inspect_firmware import macho
|
||||
|
||||
ROOT = pathlib.Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def deserialize(data):
|
||||
references = {}
|
||||
def parse(node):
|
||||
if 'IDREF' in node.attrib:
|
||||
return references[node.attrib['IDREF']]
|
||||
if node.tag == 'dict':
|
||||
children = list(node)
|
||||
value = {children[i].text: parse(children[i+1]) for i in range(0, len(children), 2)}
|
||||
elif node.tag == 'array':
|
||||
value = [parse(child) for child in node]
|
||||
elif node.tag == 'integer':
|
||||
value = int(node.text or '0', 0)
|
||||
elif node.tag in ('true', 'false'):
|
||||
value = node.tag == 'true'
|
||||
elif node.tag == 'data':
|
||||
value = base64.b64decode(node.text or '')
|
||||
else:
|
||||
value = node.text or ''
|
||||
if 'ID' in node.attrib:
|
||||
references[node.attrib['ID']] = value
|
||||
return value
|
||||
return parse(ET.fromstring(data))
|
||||
|
||||
|
||||
def kexts():
|
||||
b = (ROOT / 'firmware/Kernelcache.dec').read_bytes()
|
||||
s = next(s for s in macho(b)['segments'] if s['name'] == '__PRELINK_INFO')
|
||||
return deserialize(b[s['fileoff']:s['fileoff'] + s['filesize']].split(b'\0')[0])['_PrelinkInfoDictionary']
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print(json.dumps(kexts(), indent=2, default=lambda v: v.hex()))
|
||||
@@ -0,0 +1,99 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Résout les méthodes Objective-C et les imports d'un Mach-O ARM32 local."""
|
||||
import argparse
|
||||
import pathlib
|
||||
import struct
|
||||
|
||||
|
||||
class MachO:
|
||||
def __init__(self, path):
|
||||
self.data = pathlib.Path(path).read_bytes()
|
||||
b = self.data
|
||||
assert b[:4] == bytes.fromhex('cefaedfe'), 'Mach-O ARM32 simple requis'
|
||||
assert struct.unpack_from('<I', b, 4)[0] == 12
|
||||
self.maps, self.sections, self.names = [], {}, {}
|
||||
cursor = 28
|
||||
symbols = indirect = None
|
||||
for _ in range(struct.unpack_from('<I', b, 16)[0]):
|
||||
cmd, size = struct.unpack_from('<II', b, cursor)
|
||||
if cmd == 1:
|
||||
_, va, vs, offset, fs, _, _, count, _ = struct.unpack_from('<16s8I', b, cursor + 8)
|
||||
self.maps.append((va, fs, offset))
|
||||
for i in range(count):
|
||||
section = struct.unpack_from('<16s16s9I', b, cursor + 56 + 68*i)
|
||||
self.sections[section[0].rstrip(b'\0').decode()] = section[2:]
|
||||
elif cmd == 2:
|
||||
symbols = struct.unpack_from('<4I', b, cursor + 8)
|
||||
elif cmd == 11:
|
||||
indirect = struct.unpack_from('<II', b, cursor + 56)
|
||||
cursor += size
|
||||
if symbols and indirect:
|
||||
so, _, strings, _ = symbols
|
||||
for section in self.sections.values():
|
||||
va, size, _, _, _, _, flags, first, stride = section
|
||||
if flags & 255 != 8:
|
||||
continue
|
||||
for i in range(size // stride):
|
||||
index = struct.unpack_from('<I', b, indirect[0] + 4*(first+i))[0]
|
||||
name = struct.unpack_from('<I', b, so + 12*index)[0] + strings
|
||||
self.names[va + i*stride] = self.cstring_offset(name)
|
||||
if '__objc_classlist' in self.sections:
|
||||
va, size, *_ = self.sections['__objc_classlist']
|
||||
for pointer in range(va, va + size, 4):
|
||||
cls = self.word(pointer)
|
||||
for obj, prefix in ((cls, '-'), (self.word(cls), '+')):
|
||||
ro = self.word(obj + 16) & ~3
|
||||
name = self.string(self.word(ro + 16))
|
||||
methods = self.word(ro + 20)
|
||||
if not methods:
|
||||
continue
|
||||
stride, count = self.word(methods) & 0xfffc, self.word(methods + 4)
|
||||
for i in range(count):
|
||||
method = methods + 8 + i*stride
|
||||
selector = self.string(self.word(method))
|
||||
self.names[self.word(method + 8) & ~1] = f'{prefix}[{name} {selector}]'
|
||||
|
||||
def offset(self, address):
|
||||
for va, size, offset in self.maps:
|
||||
if va <= address < va + size:
|
||||
return offset + address - va
|
||||
raise ValueError(f'Adresse non présente dans le fichier : {address:#x}')
|
||||
|
||||
def word(self, address):
|
||||
return struct.unpack_from('<I', self.data, self.offset(address))[0]
|
||||
|
||||
def cstring_offset(self, offset):
|
||||
return self.data[offset:self.data.index(0, offset)].decode(errors='replace')
|
||||
|
||||
def string(self, address):
|
||||
return self.cstring_offset(self.offset(address))
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('image', type=pathlib.Path)
|
||||
parser.add_argument('addresses', nargs='+', type=lambda x: int(x, 0))
|
||||
parser.add_argument('--slide', type=lambda x: int(x, 0), default=0)
|
||||
parser.add_argument('--bytes', type=int, default=0)
|
||||
args = parser.parse_args()
|
||||
macho = MachO(args.image)
|
||||
for runtime in args.addresses:
|
||||
address = (runtime - args.slide) & ~1
|
||||
previous = max((a for a in macho.names if a <= address), default=None)
|
||||
print(f'{runtime:#x} -> {address:#x}')
|
||||
if previous is not None:
|
||||
print(f' Méthode/import précédent : {macho.names[previous]}+{address-previous:#x}')
|
||||
if args.bytes:
|
||||
from capstone import Cs, CS_ARCH_ARM, CS_MODE_THUMB
|
||||
offset = macho.offset(address)
|
||||
for ins in Cs(CS_ARCH_ARM, CS_MODE_THUMB).disasm(macho.data[offset:offset+args.bytes], address):
|
||||
annotation = ''
|
||||
if ins.mnemonic.startswith('bl') and ins.op_str.startswith('#0x'):
|
||||
target = int(ins.op_str[1:], 16)
|
||||
if target in macho.names:
|
||||
annotation = ' ; ' + macho.names[target]
|
||||
print(f' {ins.address:08x}: {ins.mnemonic:10s} {ins.op_str}{annotation}')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Executable
+149
@@ -0,0 +1,149 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Prépare un démarrage direct 10B500/n88 en conservant le firmware original."""
|
||||
import json
|
||||
import argparse
|
||||
import pathlib
|
||||
import struct
|
||||
from inspect_firmware import devicetree, encode_tree, macho, walk
|
||||
|
||||
ROOT = pathlib.Path(__file__).resolve().parents[1]
|
||||
FW = ROOT / 'firmware'
|
||||
u32 = lambda *values: struct.pack('<' + 'I' * len(values), *values)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--profile', choices=['original', 'display', 'core'], default='original')
|
||||
parser.add_argument('--rootfs', action='store_true', help='Disque iOS complet, RAM relocalisée et memdev physique')
|
||||
parser.add_argument('--software-rendering', action='store_true', help='Essai sans publication du GPU SGX dans le DeviceTree')
|
||||
options = parser.parse_args()
|
||||
pa = 0x70000000 if options.rootfs else 0x40000000
|
||||
kernel = (FW / 'Kernelcache.dec').read_bytes()
|
||||
info = macho(kernel)
|
||||
assert info['entry'] == 0x80086084, 'Ce prototype attend le noyau 10B500/n88'
|
||||
base = 0x80001000
|
||||
end = max(s['vmaddr'] + s['vmsize'] for s in info['segments'])
|
||||
assert end < 0x81000000
|
||||
flat = bytearray(end - base)
|
||||
for s in info['segments']:
|
||||
if s['filesize']:
|
||||
assert s['fileoff'] + s['filesize'] <= len(kernel)
|
||||
offset = s['vmaddr'] - base
|
||||
flat[offset:offset + s['filesize']] = kernel[s['fileoff']:s['fileoff'] + s['filesize']]
|
||||
patches = []
|
||||
if options.rootfs:
|
||||
# Adaptations du seul noyau expérimental ; chaque opcode source est vérifié.
|
||||
for address, before, after, reason in [
|
||||
(0x80270822, '17f69dff', '00bf00bf', 'RAMDisk : conserver une adresse physique'),
|
||||
(0x80270828, '0021', '0121', 'mdevadd : activer les transferts physiques'),
|
||||
(0x80240af8, '1e21', '0121', 'IORTC absent : limiter son attente à une seconde'),
|
||||
(0x804b0674, '1e21', '0121', 'Horloge absente : limiter son attente à une seconde'),
|
||||
]:
|
||||
offset = address - base
|
||||
original, replacement = bytes.fromhex(before), bytes.fromhex(after)
|
||||
assert flat[offset:offset + len(original)] == original, hex(address)
|
||||
flat[offset:offset + len(original)] = replacement
|
||||
patches.append(dict(address=hex(address), original=before, replacement=after, reason=reason))
|
||||
kernel_name = 'kernel-rootfs.bin' if options.rootfs else 'kernel.bin'
|
||||
(FW / kernel_name).write_bytes(flat)
|
||||
tree, _ = devicetree((FW / 'DeviceTree.dec').read_bytes())
|
||||
nodes = dict(walk(tree))
|
||||
removed = []
|
||||
if options.profile in ('display', 'core'):
|
||||
# Le système graphique est conservé ; le coprocesseur audio et ses
|
||||
# consommateurs sont exclus jusqu'à leur émulation effective.
|
||||
excluded = {'iop', 'audio-complex', 'i2s0', 'i2s1', 'i2s2', 'compass', 'compass1'}
|
||||
if options.software_rendering:
|
||||
excluded.add('sgx')
|
||||
def prune(node):
|
||||
props, children = node
|
||||
for child in list(children):
|
||||
name = child[0].get('name', b'').rstrip(b'\0').decode()
|
||||
if name in excluded:
|
||||
removed.append(name)
|
||||
child[0]['compatible'] = b'ios6-emu,disabled\0'
|
||||
else:
|
||||
prune(child)
|
||||
prune(tree)
|
||||
if options.profile == 'core':
|
||||
arm_io = next(n for n in tree[1] if n[0].get('name') == b'arm-io\0')
|
||||
for child in list(arm_io[1]):
|
||||
name = child[0]['name'].rstrip(b'\0').decode()
|
||||
if name not in {'vic', 'uart0'}:
|
||||
removed.append(name)
|
||||
child[0]['compatible'] = b'ios6-emu,disabled\0'
|
||||
if options.profile == 'display':
|
||||
# Identifiant non nul requis par ApplePinotLCD ; panneau expérimental.
|
||||
nodes['/device-tree/arm-io/mipi-dsim/lcd']['lcd-panel-id'] = u32(0xE50486)
|
||||
root = nodes['/device-tree']
|
||||
if options.rootfs:
|
||||
# Mode sans vérification NAND prévu par AppleARMPE ; le disque est local.
|
||||
root.pop('secure-root-prefix', None)
|
||||
# Le profil expérimental ne publie pas de classe de modem physique.
|
||||
nodes['/device-tree/baseband']['class'] = u32(0)
|
||||
# UART debug dédié au lien de développement PPP, sans contrôleur DMA.
|
||||
for key in ('dma-channels', 'dma-parent', 'dma-types'):
|
||||
nodes['/device-tree/arm-io/uart1'].pop(key, None)
|
||||
root['clock-frequency'] = u32(600000000)
|
||||
root['platform-name'] = b's5l8920x\0'
|
||||
chosen = nodes['/device-tree/chosen']
|
||||
chosen.update({'chip-id': u32(0x8920), 'board-id': u32(0),
|
||||
'debug-enabled': u32(1), 'secure-boot': u32(0),
|
||||
'firmware-version': b'ios6-emu direct-kernel prototype\0',
|
||||
'random-seed': bytes(range(64))})
|
||||
# IODTNVRAM parcourt des partitions CHRP de longueur non nulle en unités
|
||||
# de 16 octets. Le placeholder IPSW (8192 zéros) provoque une boucle infinie.
|
||||
nvram = bytearray(8192)
|
||||
nvram[:16] = struct.pack('<BBH12s', 0x70, 0, len(nvram) // 16, b'common')
|
||||
checksum = sum(nvram[:16])
|
||||
nvram[1] = (checksum & 255) + (checksum >> 8)
|
||||
chosen['nvram-proxy-data'] = bytes(nvram)
|
||||
cpu = nodes['/device-tree/cpus/cpu0']
|
||||
for key, value in {'clock-frequency': 600000000, 'timebase-frequency': 24000000,
|
||||
'bus-frequency': 100000000, 'memory-frequency': 200000000,
|
||||
'peripheral-frequency': 100000000, 'fixed-frequency': 24000000,
|
||||
'cpu-version': 0x410fc080, 'reg': 0}.items():
|
||||
cpu[key] = u32(value)
|
||||
nodes['/device-tree/memory']['reg'] = u32(pa, 0x10000000)
|
||||
# Régions réservées par le chargeur : journal de panique et framebuffer.
|
||||
# Le firmware contient des placeholders nuls qu'iBoot remplit normalement.
|
||||
nodes['/device-tree/pram']['reg'] = u32(pa + 0x0ffe0000, 0x10000)
|
||||
nodes['/device-tree/vram']['reg'] = u32(pa + 0x0f000000, 0x100000)
|
||||
nodes['/device-tree/arm-io']['chip-revision'] = u32(0)
|
||||
nodes['/device-tree/arm-io']['usbphy-frequency'] = u32(24000000)
|
||||
nodes['/device-tree/arm-io/vic']['vic-offset'] = u32(0)
|
||||
memory = nodes['/device-tree/chosen/memory-map']
|
||||
memory['RAMDisk'] = u32(0x00100000 if options.rootfs else 0x42000000,
|
||||
(FW / ('rootfs-vm.hfs' if options.rootfs else 'RestoreRamdisk.dec')).stat().st_size)
|
||||
memory['Kernel-__TEXT'] = u32(pa + 0x1000, info['segments'][0]['vmsize'])
|
||||
dt = encode_tree(tree)
|
||||
dt_pa = pa + 0x01004000
|
||||
# boot_args ARM32: revision/version, bases, mémoire, sommet des allocations,
|
||||
# Boot_Video (6 mots), machineType, DeviceTree virtuel, longueur, cmdline.
|
||||
# 10B500 exige Version == 5 (contrôle à 0x8027acea).
|
||||
args = struct.pack('<HH', 1, 5)
|
||||
args += u32(0x80000000, pa, 0x0f000000, pa + 0x03000000)
|
||||
args += u32(pa + 0x0f000000, 0, 320 * 4, 320, 480, 32)
|
||||
args += u32(0, dt_pa + 0x80000000 - pa, len(dt))
|
||||
cmd = b'-v debug=0x14e serial=3 rd=md0 keepsyms=1'
|
||||
if options.rootfs:
|
||||
# launchctl utilise sinon les plists précompilées du cache xpcd,
|
||||
# en ignorant les configurations et le job de provisionnement locaux.
|
||||
cmd += b' amfi_allow_any_signature=1 launchctl_enforce_codesign=0'
|
||||
assert len(cmd) < 256
|
||||
args += cmd.ljust(256, b'\0') + u32(0, 0x10000000)
|
||||
boot = args.ljust(0x4000, b'\0') + dt
|
||||
output_name = 'boot-data.bin' if options.profile == 'original' else f'boot-{options.profile}.bin'
|
||||
if options.rootfs:
|
||||
output_name = f'boot-{options.profile}-rootfs.bin'
|
||||
(FW / output_name).write_bytes(boot)
|
||||
report = dict(kernel_entry=hex(info['entry']), physical_entry=hex(pa + 0x86084),
|
||||
kernel_bytes=len(flat), boot_args_bytes=len(args), devicetree_bytes=len(dt),
|
||||
kernel_patches=patches, kernel_file=kernel_name, command_line=cmd.decode(), profile=options.profile,
|
||||
removed_devices=removed, boot_file=output_name)
|
||||
(ROOT / 'evidence/boot-layout.json').write_text(json.dumps(report, indent=2) + '\n')
|
||||
print(json.dumps(report, indent=2))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Crée le disque de développement, en conservant le disque de démonstration."""
|
||||
import argparse,json,pathlib,plistlib,subprocess
|
||||
from simulator import ROOT,DISK,pid,lifecycle_lock
|
||||
from recover_hfs import recover
|
||||
HFS='/srv/homes/iphoneos2/ipod-emu/xpwn/b/hfs/hfsplus'
|
||||
def main():
|
||||
p=argparse.ArgumentParser(description=__doc__);p.add_argument('--checkpoint',type=pathlib.Path);p.add_argument('--reset',action='store_true');a=p.parse_args()
|
||||
with lifecycle_lock():
|
||||
if pid('qemu'): p.error('Arrêter la VM avant de préparer le disque')
|
||||
if DISK.exists() and not a.reset: p.error('Disque existant ; --reset requis pour le remplacer')
|
||||
subprocess.run(['bash',str(ROOT/'tools/build_agent.sh')],check=True)
|
||||
temp=DISK.with_name('rootfs-dev-new.hfs');temp.unlink(missing_ok=True)
|
||||
if a.checkpoint:recover(a.checkpoint,temp)
|
||||
else:subprocess.run(['cp','--reflink=auto','--sparse=always',str(ROOT/'firmware/rootfs-vm.hfs'),str(temp)],check=True)
|
||||
config={'Label':'org.ios6-emu.agent','ProgramArguments':['/usr/libexec/ios6-agent'],'RunAtLoad':True,'KeepAlive':True}
|
||||
local=ROOT/'build/ios6-agent.plist';local.write_bytes(plistlib.dumps(config))
|
||||
for args in [('add',ROOT/'build/ios6-agent','/usr/libexec/ios6-agent'),('chmod','755','/usr/libexec/ios6-agent'),('add',local,'/System/Library/LaunchDaemons/org.ios6-emu.agent.plist')]:
|
||||
subprocess.run([HFS,str(temp),*map(str,args)],check=True)
|
||||
# Conserver l'image précédente tant que la nouvelle n'est pas prête.
|
||||
temp.replace(DISK)
|
||||
print(DISK)
|
||||
if __name__=='__main__':main()
|
||||
Executable
+114
@@ -0,0 +1,114 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Télécharge et extrait le firmware Apple de référence, avec vérifications."""
|
||||
import hashlib
|
||||
import json
|
||||
import pathlib
|
||||
import struct
|
||||
import subprocess
|
||||
import urllib.request
|
||||
import zipfile
|
||||
import zlib
|
||||
|
||||
ROOT = pathlib.Path(__file__).resolve().parents[1]
|
||||
FW = ROOT / 'firmware'
|
||||
URL = 'https://secure-appldnld.apple.com/iOS6.1/091-3457.20140221.Btt3e/iPhone2,1_6.1.6_10B500_Restore.ipsw'
|
||||
SHA256 = '37a4b3bb0cbc0cc4c94f4ec2987f23c9207644c2669084084c4a78e8325e6b91'
|
||||
KEYS_URL = 'https://raw.githubusercontent.com/LukeZGD/Legacy-iOS-Kit-Keys/af6bf5934dc61ed557a967a3f42ab7fb8ed8c45e/iPhone2,1/10B500/index.html'
|
||||
|
||||
|
||||
def download(url, dest):
|
||||
if dest.exists():
|
||||
return
|
||||
temporary = dest.with_suffix(dest.suffix + '.part')
|
||||
with urllib.request.urlopen(url, timeout=60) as response, temporary.open('wb') as out:
|
||||
while block := response.read(1024 * 1024):
|
||||
out.write(block)
|
||||
temporary.replace(dest)
|
||||
|
||||
|
||||
def lzss(data):
|
||||
assert data[:8] == b'complzss'
|
||||
checksum, expected, compressed = struct.unpack_from('>III', data, 8)
|
||||
assert 0 < expected <= 64 * 1024 * 1024 and 384 + compressed <= len(data)
|
||||
source = data[384:384 + compressed]
|
||||
output = bytearray()
|
||||
ring = bytearray(b' ' * 4096)
|
||||
pos, cursor = 4096 - 18, 0
|
||||
while cursor < len(source):
|
||||
flags = source[cursor]
|
||||
cursor += 1
|
||||
for bit in range(8):
|
||||
if cursor == len(source):
|
||||
break
|
||||
if flags & (1 << bit):
|
||||
values = [source[cursor]]
|
||||
cursor += 1
|
||||
idx, count = 0, 1
|
||||
else:
|
||||
assert cursor + 2 <= len(source)
|
||||
a, b = source[cursor:cursor + 2]
|
||||
cursor += 2
|
||||
idx, count = a | ((b & 0xf0) << 4), (b & 15) + 3
|
||||
values = None
|
||||
assert len(output) + count <= expected
|
||||
for j in range(count):
|
||||
c = values[0] if values else ring[(idx + j) & 4095]
|
||||
output.append(c)
|
||||
ring[pos] = c
|
||||
pos = (pos + 1) & 4095
|
||||
assert len(output) == expected, 'Taille LZSS incorrecte'
|
||||
assert zlib.adler32(output) == checksum, 'Somme Adler32 incorrecte'
|
||||
return bytes(output)
|
||||
|
||||
|
||||
def decrypt_img3(data, key):
|
||||
assert data[:4] == b'3gmI'
|
||||
cursor = 20
|
||||
while cursor + 12 <= len(data):
|
||||
tag, size, length = struct.unpack_from('<4sII', data, cursor)
|
||||
assert size >= 12 and cursor + size <= len(data)
|
||||
if tag == b'ATAD':
|
||||
# DATA déclare parfois une taille non alignée ; le dernier bloc AES
|
||||
# inclut le padding du tag (nécessaire pour ce kernelcache).
|
||||
encrypted_size = (length + 15) & ~15
|
||||
assert encrypted_size <= size - 12
|
||||
encrypted = data[cursor + 12:cursor + 12 + encrypted_size]
|
||||
decoded = subprocess.run(
|
||||
['openssl', 'enc', '-d', '-aes-256-cbc', '-K', key['key'],
|
||||
'-iv', key['iv'], '-nopad'], input=encrypted,
|
||||
capture_output=True, check=True).stdout[:length]
|
||||
return lzss(decoded) if decoded.startswith(b'complzss') else decoded
|
||||
cursor += size
|
||||
raise ValueError('Tag DATA absent')
|
||||
|
||||
|
||||
def main():
|
||||
FW.mkdir(exist_ok=True)
|
||||
(ROOT / 'evidence').mkdir(exist_ok=True)
|
||||
ipsw = FW / URL.rsplit('/', 1)[-1]
|
||||
download(URL, ipsw)
|
||||
with ipsw.open('rb') as source:
|
||||
assert hashlib.file_digest(source, 'sha256').hexdigest() == SHA256, 'IPSW corrompu'
|
||||
download(KEYS_URL, FW / 'keys.json')
|
||||
keys = json.loads((FW / 'keys.json').read_text())
|
||||
assert keys['identifier'] == 'iPhone2,1' and keys['buildid'] == '10B500'
|
||||
manifest = dict(ipsw_url=URL, ipsw_sha256=SHA256, keys_url=KEYS_URL, components={})
|
||||
with zipfile.ZipFile(ipsw) as archive:
|
||||
for image in ('Kernelcache', 'DeviceTree', 'RestoreRamdisk'):
|
||||
key = next(k for k in keys['keys'] if k['image'] == image)
|
||||
names = [n for n in archive.namelist() if n.rsplit('/', 1)[-1] == key['filename']]
|
||||
assert len(names) == 1
|
||||
decoded = decrypt_img3(archive.read(names[0]), key)
|
||||
if image == 'Kernelcache':
|
||||
assert decoded[:4] == b'\xce\xfa\xed\xfe'
|
||||
temporary = FW / (image + '.dec.tmp')
|
||||
temporary.write_bytes(decoded)
|
||||
temporary.replace(FW / (image + '.dec'))
|
||||
manifest['components'][image] = dict(member=names[0], bytes=len(decoded),
|
||||
sha256=hashlib.sha256(decoded).hexdigest())
|
||||
print(image, len(decoded), 'octets vérifiés', flush=True)
|
||||
(ROOT / 'evidence/firmware-manifest.json').write_text(json.dumps(manifest, indent=2) + '\n')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,165 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Prépare une copie HFS indépendante du système iOS pour le disque virtuel."""
|
||||
import hashlib
|
||||
import json
|
||||
import pathlib
|
||||
import plistlib
|
||||
import shutil
|
||||
import struct
|
||||
import subprocess
|
||||
import zipfile
|
||||
|
||||
from prepare_firmware import FW, ROOT, SHA256
|
||||
|
||||
LEGACY = pathlib.Path('/srv/homes/iphoneos2/ipod-emu')
|
||||
HFS = LEGACY / 'xpwn/b/hfs/hfsplus'
|
||||
SIZE = 0x6f000000
|
||||
|
||||
|
||||
def run(*args):
|
||||
subprocess.run([str(a) for a in args], check=True, timeout=120)
|
||||
|
||||
|
||||
def main():
|
||||
original = FW / 'rootfs.hfs'
|
||||
if not original.exists():
|
||||
ipsw = FW / 'iPhone2,1_6.1.6_10B500_Restore.ipsw'
|
||||
with ipsw.open('rb') as f:
|
||||
assert hashlib.file_digest(f, 'sha256').hexdigest() == SHA256
|
||||
key = next(k for k in json.loads((FW / 'keys.json').read_text())['keys'] if k['image'] == 'RootFS')
|
||||
encrypted = FW / key['filename']
|
||||
with zipfile.ZipFile(ipsw) as archive, archive.open(key['filename']) as source, encrypted.open('wb') as output:
|
||||
shutil.copyfileobj(source, output)
|
||||
run(LEGACY / 'dmg2img/vfdecrypt', '-i', encrypted, '-k', key['key'], '-o', FW / 'rootfs.dmg')
|
||||
run(LEGACY / 'dmg2img/dmg2img', FW / 'rootfs.dmg', FW / 'rootfs.img')
|
||||
with (FW / 'rootfs.img').open('rb') as source:
|
||||
header = source.read(512)
|
||||
assert header[:2] == b'ER'
|
||||
blocksize = struct.unpack_from('>H', header, 2)[0]
|
||||
source.seek(blocksize)
|
||||
entry = source.read(512)
|
||||
count = struct.unpack_from('>I', entry, 4)[0]
|
||||
for index in range(1, count + 1):
|
||||
source.seek(index * blocksize)
|
||||
entry = source.read(512)
|
||||
assert entry[:2] == b'PM'
|
||||
if entry[48:80].split(b'\0')[0] == b'Apple_HFSX':
|
||||
start, blocks = struct.unpack_from('>II', entry, 8)
|
||||
source.seek(start * blocksize)
|
||||
with original.open('wb') as output:
|
||||
remaining = blocks * blocksize
|
||||
while remaining:
|
||||
data = source.read(min(remaining, 1024 * 1024))
|
||||
assert data
|
||||
output.write(data)
|
||||
remaining -= len(data)
|
||||
break
|
||||
else:
|
||||
raise ValueError('Partition Apple_HFSX absente')
|
||||
image = FW / 'rootfs-vm.hfs'
|
||||
# Une reconstruction explicite réinitialise uniquement la copie expérimentale.
|
||||
run('cp', '--reflink=auto', '--sparse=always', original, image)
|
||||
run(HFS, image, 'grow', SIZE)
|
||||
fstab = ROOT / 'evidence/vm-fstab'
|
||||
fstab.write_text('/dev/md0 / hfs rw 0 0\n')
|
||||
run(HFS, image, 'add', fstab, '/etc/fstab')
|
||||
# Trousseau de session en RAM, indépendant du serveur keybagd d'Apple.
|
||||
helper = ROOT / 'build/ios6-keybag-init'
|
||||
run('/opt/cctools/bin/arm-apple-darwin9-gcc', '-isysroot',
|
||||
'/opt/theos/sdks/iPhoneOS2.2.1.sdk', '-miphoneos-version-min=2.2.1',
|
||||
'-std=gnu99', '-O2', '-Wall', '-Wextra', ROOT / 'src/keybag_init.c',
|
||||
'-framework', 'CoreFoundation', '-o', helper)
|
||||
run('/opt/cctools/bin/ldid', '-S', helper)
|
||||
run(HFS, image, 'add', helper, '/usr/libexec/ios6-session')
|
||||
run(HFS, image, 'chmod', '755', '/usr/libexec/ios6-session')
|
||||
# Le migrateur du modem attend indéfiniment CommCenter sans baseband.
|
||||
# Conserver le bundle Apple hors du répertoire parcouru par DataMigrator.
|
||||
run(HFS, image, 'mkdir', '/System/Library/EmulatorDisabledMigrators')
|
||||
run(HFS, image, 'mv', '/System/Library/DataClassMigrators/CommCenterMigrator.migrator',
|
||||
'/System/Library/EmulatorDisabledMigrators/CommCenterMigrator.migrator')
|
||||
# L'assistant de configuration exige des services d'activation absents de
|
||||
# cette VM. Son bundle reste conservé hors des applications enregistrées.
|
||||
run(HFS, image, 'mkdir', '/System/Library/EmulatorDisabledApplications')
|
||||
run(HFS, image, 'mv', '/Applications/Setup.app',
|
||||
'/System/Library/EmulatorDisabledApplications/Setup.app')
|
||||
run(HFS, image, 'mkdir', '/System/Library/EmulatorDisabledDaemons')
|
||||
for name in ('CommCenter', 'CommCenterClassic', 'CommCenterLite',
|
||||
'CommCenterMobileHelper', 'CommCenterRootHelper', 'mediaserverd',
|
||||
'mobile.keybagd'):
|
||||
filename = f'com.apple.{name}.plist'
|
||||
run(HFS, image, 'mv', f'/System/Library/LaunchDaemons/{filename}',
|
||||
f'/System/Library/EmulatorDisabledDaemons/{filename}')
|
||||
session = ROOT / 'evidence/ios6-session.plist'
|
||||
session.write_bytes(plistlib.dumps({
|
||||
'Label': 'org.ios6-emu.session', 'RunAtLoad': True,
|
||||
'ProgramArguments': ['/usr/libexec/ios6-session'],
|
||||
'StandardOutPath': '/dev/console', 'StandardErrorPath': '/dev/console',
|
||||
}))
|
||||
run(HFS, image, 'add', session, '/System/Library/LaunchDaemons/org.ios6-emu.session.plist')
|
||||
# SpringBoard ne doit pas attendre les réponses d'un modem inexistant.
|
||||
capability_path = '/System/Library/CoreServices/SpringBoard.app/N88AP.plist'
|
||||
capability_file = ROOT / 'evidence/N88AP-vm.plist'
|
||||
run(HFS, original, 'extract', capability_path, capability_file)
|
||||
capabilities = plistlib.loads(capability_file.read_bytes())
|
||||
for key in ('telephony', 'any-telephony', 'sms', 'mms', 'personal-hotspot'):
|
||||
capabilities['capabilities'][key] = False
|
||||
capabilities['capabilities']['telephony-maximum-generation'] = 0.0
|
||||
capability_file.write_bytes(plistlib.dumps(capabilities))
|
||||
run(HFS, image, 'rm', capability_path)
|
||||
run(HFS, image, 'add', capability_file, capability_path)
|
||||
# Le firmware n88 fournit les fontes _UH ; le profil graphique sans SGX
|
||||
# sélectionne sinon les tables _H dont les fichiers sont absents.
|
||||
for target, source in [('CGFontCache', 'CGFontCacheU'), ('CGFontCacheR', 'CGFontCacheUR')]:
|
||||
local = ROOT / f'evidence/{target}-vm.plist'
|
||||
run(HFS, original, 'extract', f'/System/Library/Fonts/{source}.plist', local)
|
||||
run(HFS, image, 'add', local, f'/System/Library/Fonts/{target}.plist')
|
||||
setup = ROOT / 'evidence/vm-setup.plist'
|
||||
setup.write_bytes(plistlib.dumps({
|
||||
'SetupDone': True, 'SetupFinishedAllSteps': True,
|
||||
'SetupVersion': 3, 'ForceNoBuddy': True,
|
||||
}))
|
||||
for domain in ('com.apple.purplebuddy', 'com.apple.purplebuddy.notbackedup'):
|
||||
run(HFS, image, 'add', setup, f'/var/mobile/Library/Preferences/{domain}.plist')
|
||||
for name in ('backboardd', 'SpringBoard'):
|
||||
guest_path = f'/System/Library/LaunchDaemons/com.apple.{name}.plist'
|
||||
local_path = ROOT / f'evidence/{name}-console.plist'
|
||||
run(HFS, original, 'extract', guest_path, local_path)
|
||||
config = plistlib.loads(local_path.read_bytes())
|
||||
config.update(StandardOutPath='/dev/console', StandardErrorPath='/dev/console')
|
||||
config['EnvironmentVariables'] = {
|
||||
'CA_NO_ACCEL': '1', 'CA_ENABLE_OGL': '0', 'CA_PRINT_PERF': '1',
|
||||
}
|
||||
local_path.write_bytes(plistlib.dumps(config))
|
||||
run(HFS, image, 'rm', guest_path)
|
||||
run(HFS, image, 'add', local_path, guest_path)
|
||||
asl = ROOT / 'evidence/vm-asl.conf'
|
||||
asl.write_text('? [>= Level 0] file /var/log/ios6-emu.log format=bsd mode=0644\n'
|
||||
'? [= Sender backboardd] file /dev/console format=bsd\n'
|
||||
'? [= Sender SpringBoard] file /dev/console format=bsd\n'
|
||||
'? [= Sender DataMigrator] file /dev/console format=bsd\n'
|
||||
'? [<= PID 1] store\n')
|
||||
run(HFS, image, 'add', asl, '/etc/asl.conf')
|
||||
with image.open('rb') as f:
|
||||
f.seek(1024)
|
||||
header = f.read(512)
|
||||
assert header[:2] == b'HX'
|
||||
blocksize, blocks, free = struct.unpack_from('>III', header, 40)
|
||||
assert blocks * blocksize == SIZE and free > 0
|
||||
report = {'image': str(image), 'bytes': SIZE, 'free_bytes': free * blocksize,
|
||||
'changes': ['fstab: volume unique md0, lecture-écriture, sans fsck automatique',
|
||||
'ios6-session: trousseau RAM et geste tactile de démonstration ; keybagd Apple conservé, job écarté',
|
||||
'CommCenterMigrator: conservé hors du répertoire des migrations (modem absent)',
|
||||
'CommCenter et mediaserverd: jobs conservés hors de LaunchDaemons (modem/audio absents)',
|
||||
'Polices: tables Apple U/UR pour les fichiers _UH présents',
|
||||
'Assistant initial: SetupDone, SetupFinishedAllSteps, SetupVersion=3, ForceNoBuddy',
|
||||
'Setup.app: conservée hors du répertoire des applications',
|
||||
'N88AP: capacités de téléphonie désactivées (modem absent)',
|
||||
'backboardd et SpringBoard: console, CA_NO_ACCEL=1, CA_ENABLE_OGL=0',
|
||||
'SpringBoard: lancement par backboardd (configuration Apple)',
|
||||
'journal ASL: /var/log/ios6-emu.log']}
|
||||
(ROOT / 'evidence/rootfs-layout.json').write_text(json.dumps(report, indent=2) + '\n')
|
||||
print(json.dumps(report, indent=2))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Prépare le SDK iOS 6.0 de référence, épinglé et vérifié."""
|
||||
import hashlib
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import urllib.request
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
COMMIT = '3111c86f53b021dabee781aec3fb2d9fb8f3f862'
|
||||
SHA256 = '68a163f56d7ff9abcad18586a15c76f572de99e13c122e119118e228cdecb652'
|
||||
BASE = f'https://raw.githubusercontent.com/Sn0wCooder/theos-sdks/{COMMIT}/iPhoneOS6.0.sdk/'
|
||||
|
||||
def main():
|
||||
refs = ROOT / 'references'
|
||||
refs.mkdir(exist_ok=True)
|
||||
archive = refs / 'ios6-sdk.zip'
|
||||
if not archive.exists():
|
||||
temporary = archive.with_suffix('.download')
|
||||
with temporary.open('wb') as out:
|
||||
for number in range(1, 4):
|
||||
name = f'iPhoneOS6.0.sdk.zip.{number:03}'
|
||||
print('Téléchargement :', name, flush=True)
|
||||
with urllib.request.urlopen(BASE + name, timeout=120) as response:
|
||||
while chunk := response.read(1024 * 1024):
|
||||
out.write(chunk)
|
||||
temporary.replace(archive)
|
||||
digest = hashlib.sha256()
|
||||
with archive.open('rb') as stream:
|
||||
while chunk := stream.read(1024 * 1024): digest.update(chunk)
|
||||
if digest.hexdigest() != SHA256:
|
||||
raise SystemExit('SHA-256 du SDK incorrect ; archive conservée pour diagnostic')
|
||||
destination = refs / 'sdk'
|
||||
sdk = destination / 'iPhoneOS6.0.sdk'
|
||||
if not sdk.exists():
|
||||
destination.mkdir(exist_ok=True)
|
||||
subprocess.run(['unzip', '-q', str(archive), '-d', str(destination)], check=True)
|
||||
if not (sdk / 'SDKSettings.plist').is_file():
|
||||
raise SystemExit('SDK incomplet')
|
||||
print(sdk)
|
||||
|
||||
if __name__ == '__main__': main()
|
||||
Executable
+173
@@ -0,0 +1,173 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Essai borné : console série, MMIO, registres et arrêt de cette seule VM."""
|
||||
import argparse
|
||||
import datetime
|
||||
import json
|
||||
import pathlib
|
||||
import re
|
||||
import socket
|
||||
import subprocess
|
||||
import time
|
||||
from gdb_remote import Remote
|
||||
|
||||
ROOT = pathlib.Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--seconds', type=float, default=5)
|
||||
parser.add_argument('--trace', action='store_true', help='Trace assembleur (plafond 32 Mio)')
|
||||
parser.add_argument('--trace-range', help='Plage QEMU -dfilter pour les registres de chaque bloc')
|
||||
parser.add_argument('--expect-panic', help='Valide un blocage connu au lieu de le signaler comme échec')
|
||||
parser.add_argument('--boot-data', default='boot-data.bin')
|
||||
parser.add_argument('--diagnostic-panic', action='store_true', help='Déclenche volontairement une panique pour inspecter les threads bloqués')
|
||||
parser.add_argument('--rootfs', action='store_true')
|
||||
parser.add_argument('--dump-disk', action='store_true', help='Sauvegarde le disque privé avant arrêt pour lire les journaux invités')
|
||||
parser.add_argument('--dump-ram', action='store_true', help='Sauvegarde la RAM pour examiner les tables DMA et les tampons écran')
|
||||
parser.add_argument('--capture-interval', type=float, default=0, help='Capture périodique en secondes ; zéro désactive')
|
||||
options = parser.parse_args()
|
||||
assert 0 < options.seconds <= 300
|
||||
assert options.capture_interval >= 0
|
||||
run = ROOT / 'evidence' / datetime.datetime.now(datetime.timezone.utc).strftime('probe-%Y%m%dT%H%M%S-%fZ')
|
||||
run.mkdir(parents=True)
|
||||
# Socket court pour respecter la limite Unix de 108 caractères.
|
||||
sockpath = run / 'qmp'
|
||||
fw = ROOT / 'firmware'
|
||||
command = [str(ROOT / 'build/qemu-system-arm'), '-M', 'ios6-n88' + (',rootfs=on' if options.rootfs else ''),
|
||||
'-kernel', str(fw / ('kernel-rootfs.bin' if options.rootfs else 'kernel.bin')), '-dtb', str(fw / options.boot_data),
|
||||
'-initrd', str(fw / ('rootfs-vm.hfs' if options.rootfs else 'RestoreRamdisk.dec')), '-display', 'none',
|
||||
'-serial', 'file:' + str(run / 'serial.log'), '-monitor', 'none',
|
||||
'-qmp', 'unix:' + str(sockpath) + ',server=on,wait=off',
|
||||
'-d', 'unimp,guest_errors' + (',in_asm,int' if options.trace else ''),
|
||||
'-D', str(run / 'qemu.log'), '-no-reboot']
|
||||
if options.diagnostic_panic:
|
||||
command += ['-gdb', 'unix:' + str(run / 'gdb') + ',server=on,wait=off']
|
||||
if options.trace_range:
|
||||
command += ['-d', 'unimp,guest_errors,in_asm,int,cpu', '-dfilter', options.trace_range]
|
||||
(run / 'command.json').write_text(json.dumps(command, indent=2) + '\n')
|
||||
result = {'run': str(run), 'seconds': options.seconds}
|
||||
with (run / 'stderr.log').open('wb') as err:
|
||||
process = subprocess.Popen(command, stdout=err, stderr=err)
|
||||
try:
|
||||
deadline = time.monotonic() + 10
|
||||
while not sockpath.exists() and process.poll() is None and time.monotonic() < deadline:
|
||||
time.sleep(.05)
|
||||
with socket.socket(socket.AF_UNIX) as client:
|
||||
client.settimeout(5)
|
||||
client.connect(str(sockpath))
|
||||
stream = client.makefile('rwb')
|
||||
json.loads(stream.readline())
|
||||
|
||||
def qmp(name, **arguments):
|
||||
stream.write(json.dumps({'execute': name, 'arguments': arguments}).encode() + b'\n')
|
||||
stream.flush()
|
||||
while True:
|
||||
reply = json.loads(stream.readline())
|
||||
if 'return' in reply:
|
||||
return reply['return']
|
||||
if 'error' in reply:
|
||||
raise RuntimeError(reply['error'])
|
||||
|
||||
qmp('qmp_capabilities')
|
||||
deadline = time.monotonic() + options.seconds
|
||||
next_capture = time.monotonic() + options.capture_interval
|
||||
capture_number = 0
|
||||
while process.poll() is None and time.monotonic() < deadline:
|
||||
if (run / 'qemu.log').stat().st_size > 32 * 1024 * 1024:
|
||||
result['trace_limit_reached'] = True
|
||||
break
|
||||
if options.rootfs and options.capture_interval and time.monotonic() >= next_capture:
|
||||
capture_number += 1
|
||||
qmp('screendump', filename=str(run / f'screen-{capture_number:03d}.png'), format='png')
|
||||
next_capture = time.monotonic() + options.capture_interval
|
||||
time.sleep(.05)
|
||||
qmp('stop')
|
||||
result['status'] = qmp('query-status')
|
||||
result['registers'] = qmp('human-monitor-command', **{'command-line': 'info registers'})
|
||||
registers = dict(re.findall(r'R(\d\d)=([0-9a-fA-F]+)', result['registers']))
|
||||
for field, reg, fmt in [('instructions', '15', '16i'), ('stack', '13', '32wx')]:
|
||||
result[field] = qmp('human-monitor-command', **{'command-line': f'x /{fmt} 0x{registers[reg]}'})
|
||||
if options.rootfs:
|
||||
qmp('screendump', filename=str(run / 'screen.ppm'))
|
||||
qmp('screendump', filename=str(run / 'screen.png'), format='png')
|
||||
if options.dump_ram:
|
||||
client.settimeout(60)
|
||||
qmp('pmemsave', val=0x70000000 if options.rootfs else 0x40000000,
|
||||
size=0x10000000, filename=str(run / 'ram.bin'))
|
||||
client.settimeout(5)
|
||||
if options.dump_disk:
|
||||
assert options.rootfs
|
||||
client.settimeout(60)
|
||||
qmp('pmemsave', val=0x100000, size=(fw / 'rootfs-vm.hfs').stat().st_size, filename=str(run / 'guest-disk.hfs'))
|
||||
assert (run / 'guest-disk.hfs').stat().st_size == (fw / 'rootfs-vm.hfs').stat().st_size
|
||||
client.settimeout(5)
|
||||
# Un arrêt spontané peut passer par Debugger() sans la chaîne
|
||||
# « panic(cpu » ; conserver sa pile plutôt que la remplacer.
|
||||
serial_so_far = (run / 'serial.log').read_text(errors='replace')
|
||||
natural_debugger = re.search(r'panic\(cpu[^\n]+|Debugger message:[^\n]+', serial_so_far)
|
||||
if options.diagnostic_panic and not natural_debugger:
|
||||
for _ in range(200):
|
||||
psr = int(re.search(r'PSR=([0-9a-fA-F]+)', result['registers']).group(1), 16)
|
||||
# Éviter les trampolines ARM de retour de syscall :
|
||||
# leur SP/R7 n'est pas un cadre C de noyau ordinaire.
|
||||
if psr & 0x3f == 0x33:
|
||||
break
|
||||
qmp('cont')
|
||||
time.sleep(.01)
|
||||
qmp('stop')
|
||||
result['registers'] = qmp('human-monitor-command', **{'command-line': 'info registers'})
|
||||
assert psr & 0x3f == 0x33, 'Diagnostic : contexte SVC Thumb introuvable'
|
||||
result['diagnostic_panic_requested'] = True
|
||||
(run / 'serial-before-diagnostic.log').write_bytes((run / 'serial.log').read_bytes())
|
||||
remote = Remote(run / 'gdb')
|
||||
remote.command('qSupported')
|
||||
remote.command('Hg0')
|
||||
# Chaîne constante du noyau : aucun écrasement de mémoire invitée.
|
||||
remote.write_register(0, 0x80288d9c)
|
||||
psr = int(re.search(r'PSR=([0-9a-fA-F]+)', result['registers']).group(1), 16)
|
||||
remote.write_register(25, psr | 0x20)
|
||||
remote.write_register(15, 0x80017c11)
|
||||
remote.close()
|
||||
qmp('cont')
|
||||
time.sleep(3)
|
||||
qmp('stop')
|
||||
qmp('quit')
|
||||
process.wait(timeout=5)
|
||||
except Exception as exc:
|
||||
result['error'] = f'{type(exc).__name__}: {exc}'
|
||||
finally:
|
||||
if process.poll() is None:
|
||||
process.terminate()
|
||||
try:
|
||||
process.wait(timeout=5)
|
||||
except subprocess.TimeoutExpired:
|
||||
process.kill()
|
||||
process.wait()
|
||||
result['returncode'] = process.returncode
|
||||
serial = (run / 'serial.log').read_text(errors='replace') if (run / 'serial.log').exists() else ''
|
||||
natural_serial = (run / 'serial-before-diagnostic.log').read_text(errors='replace') if options.diagnostic_panic and (run / 'serial-before-diagnostic.log').exists() else serial
|
||||
panic = re.search(r'panic\(cpu[^\n]+|Debugger message:[^\n]+', natural_serial)
|
||||
result['guest_status'] = 'kernel-panic' if panic else 'partial-boot'
|
||||
result['panic'] = panic.group() if panic else None
|
||||
result['milestones'] = {
|
||||
'serial_console': 'iBoot version:' in serial,
|
||||
'crypto_self_tests': 'corecrypto.kext FIPS POST passed!' in serial,
|
||||
'platform_driver': 'AppleS5L8920XIO::start' in serial,
|
||||
'interrupt_controller_driver': 'AppleARMPL192VIC::start' in serial,
|
||||
'userspace_confirmed': '*** launchd[1] has started up. ***' in serial,
|
||||
}
|
||||
# Ces jalons n'impliquent ni montage du disque ni démarrage de launchd.
|
||||
if options.expect_panic:
|
||||
result['expected_panic_matched'] = bool(panic and options.expect_panic in panic.group())
|
||||
(run / 'result.json').write_text(json.dumps(result, indent=2) + '\n')
|
||||
print(json.dumps({k: v for k, v in result.items() if k not in ('registers', 'instructions', 'stack')}, indent=2))
|
||||
if 'error' in result or result['returncode'] != 0:
|
||||
raise SystemExit(1)
|
||||
if options.expect_panic and not result['expected_panic_matched']:
|
||||
raise SystemExit(1)
|
||||
if panic and not options.expect_panic:
|
||||
raise SystemExit(2)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,135 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Rejoue le journal d'un instantané HFSX dans une nouvelle copie hors ligne.
|
||||
|
||||
Format : Apple TN1150 et xnu-2050.18.24/bsd/vfs/vfs_journal.{c,h}.
|
||||
Ce lecteur strict traite les transactions validées jusqu'à jhdr.end ; il ne
|
||||
remplace pas fsck et n'efface pas le marqueur de volume monté.
|
||||
https://developer.apple.com/library/archive/technotes/tn/tn1150.html
|
||||
https://github.com/apple-oss-distributions/xnu/tree/xnu-2050.18.24/bsd/vfs
|
||||
"""
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import pathlib
|
||||
import shutil
|
||||
import struct
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
def checksum(data):
|
||||
value = 0
|
||||
for byte in data:
|
||||
value = ((value << 8) ^ (value + byte)) & 0xffffffff
|
||||
return value ^ 0xffffffff
|
||||
|
||||
|
||||
def verified_header(data, checksum_offset, endian):
|
||||
data = bytearray(data)
|
||||
expected = struct.unpack_from(endian + 'I', data, checksum_offset)[0]
|
||||
data[checksum_offset:checksum_offset+4] = bytes(4)
|
||||
assert checksum(data) == expected, 'Somme de contrôle du journal incorrecte'
|
||||
|
||||
|
||||
def recover(source, destination):
|
||||
assert source.resolve() != destination.resolve()
|
||||
assert not destination.exists(), 'La destination doit être nouvelle'
|
||||
image_size = source.stat().st_size
|
||||
with source.open('rb') as image:
|
||||
image.seek(1024)
|
||||
vh = image.read(512)
|
||||
assert vh[:4] == b'HX\0\5'
|
||||
attributes, jib_block = struct.unpack_from('>I', vh, 4)[0], struct.unpack_from('>I', vh, 12)[0]
|
||||
block_size, blocks = struct.unpack_from('>II', vh, 40)
|
||||
assert blocks * block_size == image_size and attributes & 0x2000
|
||||
image.seek(jib_block * block_size)
|
||||
jib = image.read(64)
|
||||
assert struct.unpack_from('>I', jib)[0] == 1, 'Journal interne initialisé requis'
|
||||
journal_offset, journal_size = struct.unpack_from('>QQ', jib, 36)
|
||||
assert journal_offset + journal_size <= image_size
|
||||
image.seek(journal_offset)
|
||||
journal = image.read(journal_size)
|
||||
assert len(journal) == journal_size
|
||||
endian = '<' if journal[:4] == b'xLNJ' else '>'
|
||||
magic, marker, start, end, size, bh_size, _, sector = struct.unpack_from(endian + 'IIQQQIII', journal)
|
||||
assert magic == 0x4a4e4c78 and marker == 0x12345678 and size == journal_size
|
||||
assert sector == 512 and bh_size >= 512
|
||||
verified_header(journal[:44], 36, endian)
|
||||
start = sector if start == size else start
|
||||
end = sector if end == size else end
|
||||
assert sector <= start < size and sector <= end < size
|
||||
|
||||
def advance(offset, length):
|
||||
return sector + (offset - sector + length) % (size - sector)
|
||||
|
||||
def read(offset, length):
|
||||
assert sector <= offset < size and 0 <= length < size - sector
|
||||
first = min(length, size - offset)
|
||||
return journal[offset:offset+first] + journal[sector:sector+length-first]
|
||||
|
||||
writes, headers, total, previous_sequence = [], 0, 0, None
|
||||
position = start
|
||||
while position != end:
|
||||
header = read(position, bh_size)
|
||||
maximum, count, used, _, flags = struct.unpack_from(endian + 'HHIII', header)
|
||||
assert 1 <= count <= maximum and 16 + 16*count <= bh_size
|
||||
assert bh_size <= used < size - sector and not flags & ~3
|
||||
verified_header(header[:32], 8, endian)
|
||||
sequence = struct.unpack_from(endian + 'I', header, 28)[0]
|
||||
if previous_sequence is not None:
|
||||
assert sequence in (previous_sequence, (previous_sequence + 1) & 0xffffffff)
|
||||
previous_sequence = sequence
|
||||
offset, consumed = advance(position, bh_size), bh_size
|
||||
for index in range(1, count):
|
||||
number, length, expected = struct.unpack_from(endian + 'QII', header, 16 + 16*index)
|
||||
assert length and length % sector == 0
|
||||
data = read(offset, length)
|
||||
if number != 0xffffffffffffffff:
|
||||
if flags & 1 and expected:
|
||||
assert checksum(data) == expected, f'Bloc corrompu : {number:#x}'
|
||||
target = number * sector
|
||||
assert target + length <= image_size
|
||||
assert target + length <= journal_offset or target >= journal_offset + journal_size
|
||||
writes.append((target, data))
|
||||
consumed += length
|
||||
offset = advance(offset, length)
|
||||
assert consumed == used
|
||||
total += used
|
||||
assert total <= size - sector, 'Boucle dans le journal'
|
||||
position = advance(position, used)
|
||||
headers += 1
|
||||
# Toutes les validations précèdent la création de la copie.
|
||||
if sys.platform == 'darwin':
|
||||
# cp BSD : clone APFS (-c), copie simple si le volume ne le permet pas.
|
||||
if subprocess.run(['cp', '-c', str(source), str(destination)]).returncode:
|
||||
shutil.copyfile(source, destination)
|
||||
else:
|
||||
subprocess.run(['cp', '--reflink=auto', '--sparse=always', str(source), str(destination)], check=True)
|
||||
with destination.open('r+b') as image:
|
||||
for target, data in writes:
|
||||
image.seek(target)
|
||||
image.write(data)
|
||||
image.flush()
|
||||
os.fsync(image.fileno())
|
||||
header = bytearray(journal[:sector])
|
||||
struct.pack_into(endian + 'Q', header, 8, end)
|
||||
struct.pack_into(endian + 'I', header, 36, 0)
|
||||
struct.pack_into(endian + 'I', header, 36, checksum(header[:44]))
|
||||
image.seek(journal_offset)
|
||||
image.write(header)
|
||||
image.flush()
|
||||
os.fsync(image.fileno())
|
||||
return {'source': str(source), 'destination': str(destination),
|
||||
'block_lists': headers, 'block_writes': len(writes), 'journal_bytes': total}
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('source', type=pathlib.Path)
|
||||
parser.add_argument('destination', type=pathlib.Path)
|
||||
args = parser.parse_args()
|
||||
print(json.dumps(recover(args.source, args.destination), indent=2))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,212 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Outils de développement pour la VM iOS 6 locale."""
|
||||
import argparse
|
||||
import contextlib
|
||||
import fcntl
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import plistlib
|
||||
import signal
|
||||
import socket
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
RUN = ROOT / 'run'
|
||||
DISK = ROOT / 'firmware/rootfs-dev.hfs'
|
||||
PORT = 7796
|
||||
|
||||
class Agent:
|
||||
def __init__(self, timeout=60):
|
||||
self.sock = socket.create_connection(('127.0.0.1', PORT), timeout=timeout)
|
||||
self.stream = self.sock.makefile('rb')
|
||||
def __enter__(self): return self
|
||||
def __exit__(self, *args): self.stream.close(); self.sock.close()
|
||||
def call(self, *fields, data=None):
|
||||
if any('\n' in str(x) or '\t' in str(x) for x in fields):
|
||||
raise ValueError('Champs de protocole invalides')
|
||||
self.sock.sendall(('\t'.join(map(str, fields))+'\n').encode())
|
||||
if data is not None: self.sock.sendall(data)
|
||||
header = self.stream.readline(4096).decode().strip().split(' ', 2)
|
||||
if len(header)<2 or header[0] not in ('OK','ERR'): raise RuntimeError('Réponse agent invalide')
|
||||
size=int(header[1]); body=bytearray()
|
||||
if not 0<=size<=64*1024*1024: raise RuntimeError('Réponse trop grande')
|
||||
while len(body)<size:
|
||||
chunk=self.stream.read(min(65536,size-len(body)))
|
||||
if not chunk: raise RuntimeError('Réponse tronquée')
|
||||
body.extend(chunk)
|
||||
if header[0]=='ERR': raise RuntimeError(body.decode(errors='replace'))
|
||||
return bytes(body), header[2] if len(header)>2 else ''
|
||||
|
||||
def command(*args, timeout=60):
|
||||
with Agent(timeout) as a: return a.call(*args)[0].decode(errors='replace')
|
||||
|
||||
class Monitor:
|
||||
def __enter__(self):
|
||||
self.sock=socket.socket(socket.AF_UNIX); self.sock.settimeout(60)
|
||||
self.sock.connect(str(RUN/'qmp.sock')); self.stream=self.sock.makefile('rwb')
|
||||
json.loads(self.stream.readline()); self.call('qmp_capabilities'); return self
|
||||
def call(self, name, **args):
|
||||
self.stream.write(json.dumps({'execute':name,'arguments':args}).encode()+b'\n'); self.stream.flush()
|
||||
while True:
|
||||
r=json.loads(self.stream.readline())
|
||||
if 'error' in r: raise RuntimeError(r['error'])
|
||||
if 'return' in r: return r['return']
|
||||
def __exit__(self,*args): self.stream.close(); self.sock.close()
|
||||
|
||||
def pid(kind):
|
||||
try:
|
||||
n=int((RUN/(kind+'.pid')).read_text())
|
||||
# macOS n'a pas /proc : ps donne la même ligne de commande.
|
||||
if Path('/proc/self').exists(): args=Path(f'/proc/{n}/cmdline').read_bytes()
|
||||
else: args=subprocess.run(['ps','-o','command=','-p',str(n)],capture_output=True).stdout
|
||||
expected=b'ios6-n88' if kind=='qemu' else str(ROOT/'build/ios6-netd').encode()
|
||||
return n if expected in args else None
|
||||
except (OSError,ValueError): return None
|
||||
|
||||
@contextlib.contextmanager
|
||||
def lifecycle_lock():
|
||||
RUN.mkdir(exist_ok=True)
|
||||
with (RUN/'lifecycle.lock').open('a') as f:
|
||||
fcntl.flock(f,fcntl.LOCK_EX|fcntl.LOCK_NB); yield
|
||||
|
||||
def start():
|
||||
with lifecycle_lock():
|
||||
if pid('qemu'): return
|
||||
if not DISK.exists(): raise RuntimeError('Préparer le disque avec tools/prepare_dev.py')
|
||||
if pid('netd'): os.kill(pid('netd'),signal.SIGTERM); time.sleep(.2)
|
||||
for name in ('qmp.sock','uart1.sock'): (RUN/name).unlink(missing_ok=True)
|
||||
args=[str(ROOT/'build/qemu-system-arm'),'-L',str(ROOT.parent/'pc-bios'),'-M','ios6-n88,rootfs=on',
|
||||
'-kernel',str(ROOT/'firmware/kernel-rootfs.bin'),'-dtb',str(ROOT/'firmware/boot-display-rootfs.bin'),
|
||||
'-initrd',str(DISK),'-display','none','-vnc','127.0.0.1:6','-serial','file:'+str(RUN/'serial.log'),
|
||||
'-serial','unix:'+str(RUN/'uart1.sock')+',server=on,wait=off',
|
||||
'-qmp','unix:'+str(RUN/'qmp.sock')+',server=on,wait=off','-monitor','none','-no-reboot']
|
||||
with (RUN/'qemu.log').open('wb') as log: p=subprocess.Popen(args,cwd=ROOT,stdout=log,stderr=log,start_new_session=True)
|
||||
(RUN/'qemu.pid').write_text(str(p.pid))
|
||||
for _ in range(100):
|
||||
if p.poll() is not None: raise RuntimeError((RUN/'qemu.log').read_text())
|
||||
if (RUN/'qmp.sock').exists(): break
|
||||
time.sleep(.1)
|
||||
with (RUN/'netd.log').open('wb') as log:
|
||||
n=subprocess.Popen([str(ROOT/'build/ios6-netd'),'-s',str(RUN/'uart1.sock'),'-L',f'127.0.0.1:{PORT}:7788'],stdout=log,stderr=log,start_new_session=True)
|
||||
(RUN/'netd.pid').write_text(str(n.pid))
|
||||
time.sleep(.5)
|
||||
if n.poll() is not None:
|
||||
p.terminate(); raise RuntimeError((RUN/'netd.log').read_text())
|
||||
|
||||
def wait_ready(timeout=360):
|
||||
end=time.monotonic()+timeout; last='agent absent'
|
||||
while time.monotonic()<end:
|
||||
if not pid('qemu'): raise RuntimeError('VM arrêtée')
|
||||
try:
|
||||
last=command('screen',timeout=3)
|
||||
if 'locked=0' in last: return last
|
||||
if 'passcode=0' in last: unlock()
|
||||
except (OSError,RuntimeError,ValueError): pass
|
||||
time.sleep(2)
|
||||
raise TimeoutError('Interface non disponible : '+last)
|
||||
|
||||
def unlock():
|
||||
s=command('screen'); command('wake')
|
||||
if 'locked=0' in s: return
|
||||
if 'passcode=0' not in s: raise RuntimeError('Code de verrouillage actif')
|
||||
time.sleep(.5); command('touch',50,433,245,433,800)
|
||||
|
||||
def screenshot(path):
|
||||
path=Path(path).resolve(); path.parent.mkdir(parents=True,exist_ok=True)
|
||||
with Monitor() as m: m.call('screendump',filename=str(path),format='png')
|
||||
return str(path)
|
||||
|
||||
def stop(discard=False):
|
||||
with lifecycle_lock():
|
||||
if not pid('qemu'): return
|
||||
if not discard:
|
||||
command('sync'); time.sleep(1)
|
||||
raw=RUN/'checkpoint.hfs'; clean=RUN/'checkpoint-clean.hfs'
|
||||
with Monitor() as m:
|
||||
m.call('stop')
|
||||
try:
|
||||
if not discard:
|
||||
m.call('human-monitor-command',**{'command-line':f'pmemsave 0x100000 0x6f000000 "{raw}"'})
|
||||
if raw.stat().st_size!=0x6f000000: raise RuntimeError('Instantané incomplet')
|
||||
clean.unlink(missing_ok=True)
|
||||
from recover_hfs import recover
|
||||
recover(raw,clean)
|
||||
os.replace(clean,DISK)
|
||||
m.call('quit')
|
||||
except BaseException:
|
||||
m.call('cont'); raise
|
||||
if pid('netd'): os.kill(pid('netd'),signal.SIGTERM)
|
||||
for _ in range(100):
|
||||
if not pid('qemu') and not pid('netd'): break
|
||||
time.sleep(.05)
|
||||
else: raise RuntimeError('Les processus de la VM ne se sont pas arrêtés')
|
||||
raw.unlink(missing_ok=True)
|
||||
|
||||
def install(app):
|
||||
app=Path(app).resolve()
|
||||
if app.suffix!='.app' or not app.is_dir(): raise ValueError('Bundle .app invalide')
|
||||
files=sorted(app.rglob('*'))
|
||||
if any(f.is_symlink() or not (f.is_dir() or f.is_file()) for f in files):
|
||||
raise ValueError('Liens symboliques et fichiers spéciaux non pris en charge')
|
||||
info=plistlib.loads((app/'Info.plist').read_bytes())
|
||||
bundle=info['CFBundleIdentifier']; executable=info['CFBundleExecutable']
|
||||
if not isinstance(executable,str) or not executable or '/' in executable or executable in ('.','..'): raise ValueError('Exécutable invalide')
|
||||
binary=(app/executable).read_bytes()
|
||||
if binary[:4]!=b'\xce\xfa\xed\xfe' or int.from_bytes(binary[4:8],'little')!=12: raise ValueError('Exécutable ARM32 Mach-O requis')
|
||||
if not isinstance(bundle,str) or not bundle or not bundle.isascii() or not all(c.isalnum() or c in '._-' for c in bundle): raise ValueError('Identifiant invalide')
|
||||
if bundle.startswith('com.apple.'): raise ValueError('Identifiant réservé au système')
|
||||
destination='/Applications/'+bundle+'.app'
|
||||
with Agent() as a:
|
||||
a.call('mkdir',destination)
|
||||
for f in files:
|
||||
remote=destination+'/'+str(f.relative_to(app))
|
||||
if f.is_dir(): a.call('mkdir',remote)
|
||||
else:
|
||||
data=f.read_bytes(); a.call('put',remote,'755' if f.name==executable else '644',len(data),data=data)
|
||||
a.call('sync')
|
||||
# Enregistrement des nouveaux bundles par le scan de démarrage d'iOS.
|
||||
stop(); start(); wait_ready()
|
||||
return bundle
|
||||
|
||||
def main():
|
||||
p=argparse.ArgumentParser(description=__doc__); sub=p.add_subparsers(dest='cmd',required=True)
|
||||
for name in ('start','status','home','unlock','apps','front','net','respring'): sub.add_parser(name)
|
||||
s=sub.add_parser('stop');s.add_argument('--discard',action='store_true')
|
||||
w=sub.add_parser('wait');w.add_argument('seconds',type=int,nargs='?',default=360)
|
||||
s=sub.add_parser('screenshot');s.add_argument('path',nargs='?',default=str(RUN/'screen.png'))
|
||||
for name in ('launch','install','logs'): s=sub.add_parser(name);s.add_argument('value')
|
||||
s=sub.add_parser('tap');s.add_argument('x',type=float);s.add_argument('y',type=float)
|
||||
s=sub.add_parser('swipe');s.add_argument('coords',type=float,nargs=4);s.add_argument('--ms',type=int,default=600)
|
||||
s=sub.add_parser('get');s.add_argument('remote');s.add_argument('local')
|
||||
s=sub.add_parser('put');s.add_argument('local');s.add_argument('remote')
|
||||
s=sub.add_parser('exec');s.add_argument('args',nargs=argparse.REMAINDER)
|
||||
a=p.parse_args(); c=a.cmd
|
||||
if c=='start': start(); print('VM démarrée. Attendre : bin/ios6 wait')
|
||||
elif c=='wait': print(wait_ready(a.seconds))
|
||||
elif c=='stop': stop(a.discard); print('VM arrêtée'+(' sans sauvegarde' if a.discard else ', disque sauvegardé'))
|
||||
elif c=='status': print(json.dumps({'running':bool(pid('qemu')),'pid':pid('qemu'),'vnc':'127.0.0.1:5906'},indent=2))
|
||||
elif c=='screenshot': print(screenshot(a.path))
|
||||
elif c=='unlock': unlock(); print(command('screen'))
|
||||
elif c=='install': print(install(a.value))
|
||||
elif c=='tap': print(command('touch',a.x,a.y,a.x,a.y,96))
|
||||
elif c=='swipe': print(command('touch',*a.coords,a.ms))
|
||||
elif c=='get':
|
||||
with Agent() as agent: data,_=agent.call('get',a.remote)
|
||||
Path(a.local).write_bytes(data)
|
||||
elif c=='put':
|
||||
data=Path(a.local).read_bytes()
|
||||
with Agent() as agent: agent.call('put',a.remote,'644',len(data),data=data)
|
||||
elif c=='logs':
|
||||
log=command('get','/var/log/ios6-emu.log');print('\n'.join(x for x in log.splitlines() if a.value in x)[-64000:])
|
||||
elif c=='launch': print(command('launch',a.value))
|
||||
elif c=='exec':
|
||||
with Agent() as agent: data,code=agent.call('exec',*a.args)
|
||||
sys.stdout.buffer.write(data);sys.exit(int(code or 0))
|
||||
else: print(command(c))
|
||||
|
||||
if __name__=='__main__':
|
||||
try: main()
|
||||
except (OSError,ValueError,RuntimeError,TimeoutError,KeyError) as e: sys.exit(str(e))
|
||||
@@ -0,0 +1,86 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Teste une vraie app native installée, le tactile, les fichiers et le réseau."""
|
||||
import argparse
|
||||
from datetime import datetime, timezone
|
||||
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
||||
import json
|
||||
import threading
|
||||
import time
|
||||
|
||||
from simulator import Agent, ROOT, command, screenshot, wait_ready
|
||||
|
||||
BUNDLE = 'org.ios6emu.SimulatorLab'
|
||||
STATE = '/var/mobile/Library/Caches/SimulatorLab-result.txt'
|
||||
|
||||
def await_value(read, expected, timeout=15):
|
||||
deadline = time.monotonic() + timeout
|
||||
while time.monotonic() < deadline:
|
||||
actual = read().strip()
|
||||
if actual == expected: return
|
||||
time.sleep(.3)
|
||||
raise AssertionError(f'Attendu {expected!r}, obtenu {actual!r}')
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--output', type=str)
|
||||
args = parser.parse_args()
|
||||
stamp = datetime.now(timezone.utc).strftime('%Y%m%dT%H%M%SZ')
|
||||
output = ROOT / (args.output or f'run/reports/{stamp}')
|
||||
output.mkdir(parents=True, exist_ok=True)
|
||||
results = {'date': stamp, 'bundle': BUNDLE, 'checks': []}
|
||||
def passed(name):
|
||||
results['checks'].append(name)
|
||||
print('PASS:', name, flush=True)
|
||||
wait_ready()
|
||||
command('home')
|
||||
await_value(lambda: command('front'), 'com.apple.springboard')
|
||||
passed('retour à SpringBoard')
|
||||
command('launch', BUNDLE)
|
||||
await_value(lambda: command('front'), BUNDLE)
|
||||
time.sleep(2)
|
||||
passed('lancement natif par SpringBoardServices')
|
||||
command('touch', 160, 367, 160, 367, 96)
|
||||
await_value(lambda: command('get', STATE), 'count=0')
|
||||
passed('bouton de remise à zéro')
|
||||
for expected in range(1, 4):
|
||||
command('touch', 160, 296, 160, 296, 96)
|
||||
await_value(lambda: command('get', STATE), f'count={expected}')
|
||||
passed('trois appuis UIKit : count=3')
|
||||
with Agent() as agent:
|
||||
data = b'ios6-agent-roundtrip\x00\xff\n'
|
||||
agent.call('put', '/tmp/ios6-smoke-test.bin', '644', len(data), data=data)
|
||||
assert agent.call('get', '/tmp/ios6-smoke-test.bin')[0] == data
|
||||
agent.call('rm', '/tmp/ios6-smoke-test.bin')
|
||||
passed('transfert binaire aller-retour')
|
||||
class Handler(BaseHTTPRequestHandler):
|
||||
def log_message(self, *args): pass
|
||||
def do_GET(self):
|
||||
body = b'ios6-network-roundtrip'
|
||||
self.send_response(200)
|
||||
self.send_header('Content-Length', str(len(body)))
|
||||
self.end_headers()
|
||||
self.wfile.write(body)
|
||||
server = ThreadingHTTPServer(('127.0.0.1', 0), Handler)
|
||||
threading.Thread(target=server.serve_forever, daemon=True).start()
|
||||
try:
|
||||
response = command('fetch', f'http://10.0.2.2:{server.server_port}/test')
|
||||
assert '200 OK' in response and 'ios6-network-roundtrip' in response, response
|
||||
finally:
|
||||
server.shutdown(); server.server_close()
|
||||
passed('HTTP invité vers serveur local via PPP')
|
||||
try:
|
||||
command('touch', -1, 0, 160, 296, 96)
|
||||
except RuntimeError:
|
||||
passed('coordonnées tactiles invalides refusées')
|
||||
else:
|
||||
raise AssertionError('Coordonnées invalides acceptées')
|
||||
logs = command('get', '/var/log/ios6-emu.log')
|
||||
logs = '\n'.join(line for line in logs.splitlines() if 'SimulatorLab' in line)
|
||||
assert 'count=3' in logs, 'Trace NSLog absente'
|
||||
(output / 'app.log').write_text(logs + '\n')
|
||||
passed('récupération des traces NSLog')
|
||||
screenshot(output / 'native-app.png')
|
||||
(output / 'validation.json').write_text(json.dumps(results, indent=2, ensure_ascii=False)+'\n')
|
||||
print(output, flush=True)
|
||||
|
||||
if __name__ == '__main__': main()
|
||||
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Remplace l'agent invité par build/ios6-agent ; launchd (KeepAlive) le relance.
|
||||
|
||||
Le fichier est écrit de façon atomique puis l'agent courant est arrêté. Lancer
|
||||
ensuite `bin/ios6 stop` pour conserver la nouvelle version sur le disque.
|
||||
"""
|
||||
import time
|
||||
|
||||
from simulator import Agent, ROOT, command
|
||||
|
||||
def main():
|
||||
data = (ROOT / 'build/ios6-agent').read_bytes()
|
||||
with Agent() as agent:
|
||||
agent.call('put', '/usr/libexec/ios6-agent', '755', len(data), data=data)
|
||||
agent.call('sync')
|
||||
# Chaque client est servi par un fils : arrêter le processus lancé par launchd.
|
||||
main_pid = next(line.split()[0] for line in command('ps').splitlines()
|
||||
if line.split()[1:] == ['1', '0', 'ios6-agent'])
|
||||
try: command('kill', main_pid, 15, timeout=5)
|
||||
except Exception: pass # l'agent s'arrête avant de répondre
|
||||
deadline = time.monotonic() + 30
|
||||
while True:
|
||||
time.sleep(1)
|
||||
try: print('agent relancé :', command('ping', timeout=5)); return
|
||||
except Exception:
|
||||
if time.monotonic() > deadline: raise SystemExit("L'agent ne répond plus")
|
||||
|
||||
if __name__ == '__main__': main()
|
||||
@@ -0,0 +1,93 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Contrôles des vrais artefacts Apple et du contrat de chargement du prototype."""
|
||||
import hashlib
|
||||
import argparse
|
||||
import pathlib
|
||||
import struct
|
||||
from inspect_firmware import devicetree, encode_tree, macho, walk
|
||||
|
||||
ROOT = pathlib.Path(__file__).resolve().parents[1]
|
||||
FW = ROOT / 'firmware'
|
||||
EXPECTED = {
|
||||
'Kernelcache.dec': 'ec4787ac012567f9c10ba2d5ab611058545bce7e17cd95ef310eba94bfca9b78',
|
||||
'DeviceTree.dec': '6608eba10d4a1086a4d3f5d299b8b9582bcb27262206152ea4029ca1a25718ad',
|
||||
'RestoreRamdisk.dec': 'e5c7eff45a0e36b7f6fdda9246bc8c0ff0561d4cedd615035f3ebe23c3d235e8',
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--rootfs', action='store_true', help='Vérifie aussi le profil système complet')
|
||||
options = parser.parse_args()
|
||||
for name, digest in EXPECTED.items():
|
||||
assert hashlib.sha256((FW / name).read_bytes()).hexdigest() == digest, name
|
||||
original = (FW / 'DeviceTree.dec').read_bytes()
|
||||
tree, consumed = devicetree(original)
|
||||
assert encode_tree(tree) == original[:consumed]
|
||||
kernel = (FW / 'Kernelcache.dec').read_bytes()
|
||||
image = (FW / 'kernel.bin').read_bytes()
|
||||
info = macho(kernel)
|
||||
assert info['entry'] == 0x80086084
|
||||
for s in info['segments']:
|
||||
start = s['vmaddr'] - 0x80001000
|
||||
assert image[start:start + s['filesize']] == kernel[s['fileoff']:s['fileoff'] + s['filesize']]
|
||||
assert not any(image[start + s['filesize']:start + s['vmsize']])
|
||||
boot = (FW / 'boot-data.bin').read_bytes()
|
||||
assert struct.unpack_from('<HH', boot) == (1, 5)
|
||||
virt, phys, usable, top = struct.unpack_from('<4I', boot, 4)
|
||||
assert virt == 0x80000000 and phys == 0x40000000
|
||||
assert 0x42000000 + (FW / 'RestoreRamdisk.dec').stat().st_size <= top
|
||||
assert top <= phys + usable <= 0x4f000000
|
||||
dt_va, dt_len = struct.unpack_from('<II', boot, 48)
|
||||
dt_offset = dt_va - virt + phys - 0x41000000
|
||||
tree, end = devicetree(boot, dt_offset)
|
||||
assert end - dt_offset == dt_len
|
||||
nodes = dict(walk(tree))
|
||||
assert nodes['/device-tree']['model'] == b'iPhone2,1\0'
|
||||
ramdisk = struct.unpack('<II', nodes['/device-tree/chosen/memory-map']['RAMDisk'])
|
||||
assert ramdisk == (0x42000000, (FW / 'RestoreRamdisk.dec').stat().st_size)
|
||||
nvram = nodes['/device-tree/chosen']['nvram-proxy-data']
|
||||
offset = 0
|
||||
while offset < len(nvram):
|
||||
size = struct.unpack_from('<H', nvram, offset + 2)[0] * 16
|
||||
assert size >= 16 and offset + size <= len(nvram)
|
||||
header = bytearray(nvram[offset:offset + 16])
|
||||
checksum, header[1] = header[1], 0
|
||||
total = 0
|
||||
for byte in header:
|
||||
total += byte
|
||||
total = (total & 255) + (total >> 8)
|
||||
assert checksum == total
|
||||
offset += size
|
||||
assert offset == 8192
|
||||
assert "files('ios6_n88.c')" in (ROOT.parent / 'hw/arm/meson.build').read_text()
|
||||
print('OK : empreintes, DeviceTree, noyau inchangé, BSS, mémoire réservée, RAMDisk, NVRAM et source QEMU.')
|
||||
if options.rootfs:
|
||||
expected = bytearray(image)
|
||||
for address, replacement in [(0x80270822, '00bf00bf'), (0x80270828, '0121'),
|
||||
(0x80240af8, '0121'), (0x804b0674, '0121')]:
|
||||
offset = address - 0x80001000
|
||||
value = bytes.fromhex(replacement)
|
||||
expected[offset:offset + len(value)] = value
|
||||
assert (FW / 'kernel-rootfs.bin').read_bytes() == expected, 'Modifications supplémentaires du noyau'
|
||||
boot = (FW / 'boot-display-rootfs.bin').read_bytes()
|
||||
assert struct.unpack_from('<4I', boot, 4) == (0x80000000, 0x70000000, 0x0f000000, 0x73000000)
|
||||
assert struct.unpack_from('<6I', boot, 20) == (0x7f000000, 0, 1280, 320, 480, 32)
|
||||
tree, end = devicetree(boot, 0x4000)
|
||||
nodes = dict(walk(tree))
|
||||
assert end - 0x4000 == struct.unpack_from('<I', boot, 52)[0]
|
||||
size = (FW / 'rootfs-vm.hfs').stat().st_size
|
||||
assert size == 0x6f000000 and 0x100000 + size < 0x70000000
|
||||
assert nodes['/device-tree/chosen/memory-map']['RAMDisk'] == struct.pack('<II', 0x100000, size)
|
||||
assert 'secure-root-prefix' not in nodes['/device-tree']
|
||||
assert nodes['/device-tree/arm-io/mipi-dsim/lcd']['lcd-panel-id'] == struct.pack('<I', 0xE50486)
|
||||
with (FW / 'rootfs-vm.hfs').open('rb') as disk:
|
||||
disk.seek(1024)
|
||||
header = disk.read(512)
|
||||
blocksize, blocks, free = struct.unpack_from('>III', header, 40)
|
||||
assert header[:2] == b'HX' and blocksize * blocks == size and free > 0
|
||||
print('OK : quatre adaptations noyau, RAM relocalisée, disque HFSX indépendant, panneau LCD et framebuffer.')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,120 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Teste le scanout QEMU avec des pixels synthétiques, sans démarrer iOS.
|
||||
|
||||
Ce contrôle matériel ne constitue jamais une preuve d'affichage de SpringBoard.
|
||||
"""
|
||||
import json
|
||||
import pathlib
|
||||
import socket
|
||||
import struct
|
||||
import subprocess
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
ROOT = pathlib.Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def main():
|
||||
with tempfile.TemporaryDirectory(prefix='ios6-display-') as directory:
|
||||
tmp = pathlib.Path(directory)
|
||||
with (tmp / 'stderr').open('wb') as log:
|
||||
process = subprocess.Popen([
|
||||
str(ROOT / 'build/qemu-system-arm'), '-M', 'ios6-n88,rootfs=on',
|
||||
'-accel', 'qtest', '-display', 'none', '-serial', 'none', '-monitor', 'none',
|
||||
'-kernel', str(ROOT / 'firmware/kernel-rootfs.bin'),
|
||||
'-dtb', str(ROOT / 'firmware/boot-display-rootfs.bin'),
|
||||
'-initrd', str(ROOT / 'firmware/rootfs-vm.hfs'),
|
||||
'-qmp', f'unix:{tmp}/qmp,server=on,wait=off',
|
||||
'-qtest', f'unix:{tmp}/qtest,server=on,wait=off',
|
||||
], stdout=log, stderr=log)
|
||||
sockets = []
|
||||
try:
|
||||
def connect(name):
|
||||
deadline = time.monotonic() + 10
|
||||
while time.monotonic() < deadline:
|
||||
client = socket.socket(socket.AF_UNIX)
|
||||
client.settimeout(5)
|
||||
try:
|
||||
client.connect(str(tmp / name))
|
||||
sockets.append(client)
|
||||
return client.makefile('rwb')
|
||||
except (FileNotFoundError, ConnectionRefusedError):
|
||||
client.close()
|
||||
assert process.poll() is None, (tmp / 'stderr').read_text()
|
||||
time.sleep(.02)
|
||||
raise TimeoutError(name)
|
||||
|
||||
monitor = connect('qmp')
|
||||
json.loads(monitor.readline())
|
||||
|
||||
def qmp(command, **args):
|
||||
monitor.write(json.dumps({'execute': command, 'arguments': args}).encode() + b'\n')
|
||||
monitor.flush()
|
||||
while True:
|
||||
response = json.loads(monitor.readline())
|
||||
assert 'error' not in response, response
|
||||
if 'return' in response:
|
||||
return response['return']
|
||||
|
||||
qmp('qmp_capabilities')
|
||||
test = connect('qtest')
|
||||
|
||||
def command(value):
|
||||
test.write(value.encode() + b'\n')
|
||||
test.flush()
|
||||
result = test.readline().decode().strip()
|
||||
assert result.startswith('OK'), result
|
||||
return result.split()[1:]
|
||||
|
||||
def write32(address, value):
|
||||
command(f'writel {address:#x} {value:#x}')
|
||||
|
||||
def write(address, value):
|
||||
command(f'write {address:#x} {len(value):#x} 0x{value.hex()}')
|
||||
|
||||
# Deux pages physiques disjointes dans une même image DMA.
|
||||
write(0x7e000000, struct.pack('<I', 0xff204060) * 1024)
|
||||
write(0x7d008000, struct.pack('<I', 0xff102030) * 1024)
|
||||
write(0x7c000000, struct.pack('<III', 0x0e000001, 0x0d008001, 0x0b000001))
|
||||
write32(0xbfe00008, 0x0c000001)
|
||||
write32(0x85400024, 0x3c000000)
|
||||
write32(0x85400030, (320 << 16) | 6)
|
||||
# Un pixel rouge prémultiplié à 50 %, superposé en (2, 1).
|
||||
write32(0x7b000000, 0x80800000)
|
||||
for offset, value in {4: 0x30, 0x40: 0x310700, 0x44: 0x3c002000,
|
||||
0x48: 1, 0x50: 0x10001, 0x54: 0x20001}.items():
|
||||
write32(0x85400000 + offset, value)
|
||||
qmp('screendump', filename=str(tmp / 'screen.ppm'))
|
||||
pixels = (tmp / 'screen.ppm').read_bytes()
|
||||
assert pixels[:15] == b'P6\n320 480\n255\n'
|
||||
pixels = pixels[15:]
|
||||
|
||||
def rgb(x, y):
|
||||
offset = (y * 320 + x) * 3
|
||||
return tuple(pixels[offset:offset + 3])
|
||||
|
||||
assert rgb(0, 0) == (32, 64, 96)
|
||||
assert rgb(63, 3) == (32, 64, 96)
|
||||
assert rgb(64, 3) == (16, 32, 48), 'Frontière de page DART'
|
||||
assert rgb(2, 1) == (144, 32, 48), 'Composition alpha'
|
||||
assert rgb(0, 7) == (0, 0, 0), 'Limites du plan'
|
||||
write32(0x8540000c, 0xffffffff)
|
||||
write32(0x85400008, 1)
|
||||
command('clock_step 16666667')
|
||||
assert int(command('readl 0x8540000c')[0], 0) & 1
|
||||
write32(0x8540000c, 1)
|
||||
assert int(command('readl 0x8540000c')[0], 0) == 0
|
||||
qmp('quit')
|
||||
process.wait(timeout=5)
|
||||
assert process.returncode == 0
|
||||
finally:
|
||||
for client in sockets:
|
||||
client.close()
|
||||
if process.poll() is None:
|
||||
process.kill()
|
||||
process.wait()
|
||||
print('OK : scanout DART, pages disjointes, composition alpha, limites des plans et acquittement VBlank.')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,121 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Relais VNC : transmet l'affichage de QEMU et convertit la souris en gestes tactiles.
|
||||
|
||||
Le client VNC se connecte au relais (127.0.0.1:5907 par défaut). L'affichage
|
||||
et les messages du client passent tels quels vers QEMU (127.0.0.1:5906), sauf
|
||||
les événements souris et clavier : un appui suivi d'un relâchement du bouton
|
||||
gauche devient un geste `touch` de l'agent (tap ou glissé, avec sa durée), le
|
||||
bouton droit et la touche Échap envoient `home`. Les touches imprimables
|
||||
deviennent `text <caractère>`, Entrée, Retour arrière et Tab `key <nom>`.
|
||||
"""
|
||||
import argparse
|
||||
import queue
|
||||
import socket
|
||||
import struct
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
|
||||
from simulator import command
|
||||
|
||||
WIDTH, HEIGHT = 320, 480
|
||||
KEY_ESCAPE, KEY_HOME = 0xff1b, 0xff50
|
||||
SPECIAL_KEYS = {0xff0d: 'return', 0xff8d: 'return', 0xff08: 'backspace', 0xff09: 'tab'}
|
||||
|
||||
def recv_exact(sock, n):
|
||||
data = bytearray()
|
||||
while len(data) < n:
|
||||
chunk = sock.recv(n - len(data))
|
||||
if not chunk: raise ConnectionError
|
||||
data.extend(chunk)
|
||||
return bytes(data)
|
||||
|
||||
def pipe(src, dst):
|
||||
try:
|
||||
while chunk := src.recv(65536): dst.sendall(chunk)
|
||||
except OSError: pass
|
||||
finally:
|
||||
for s in (src, dst):
|
||||
try: s.shutdown(socket.SHUT_RDWR)
|
||||
except OSError: pass
|
||||
|
||||
def gestures(actions):
|
||||
warned = False
|
||||
while True:
|
||||
args = actions.get()
|
||||
try: command(*args)
|
||||
except Exception as e:
|
||||
if 'commande inconnue' not in str(e): print('geste refusé :', e, file=sys.stderr, flush=True)
|
||||
elif not warned:
|
||||
warned = True
|
||||
print("clavier indisponible : l'agent invité n'a pas encore les commandes text/key", file=sys.stderr, flush=True)
|
||||
|
||||
def clamp(v, top): return min(max(v, 0), top - 1)
|
||||
|
||||
def client_messages(client, qemu, actions):
|
||||
"""Lit le flux client RFB message par message pour isoler la souris et le clavier."""
|
||||
version = recv_exact(client, 12); qemu.sendall(version)
|
||||
if version != b'RFB 003.003\n': qemu.sendall(recv_exact(client, 1)) # type de sécurité
|
||||
qemu.sendall(recv_exact(client, 1)) # ClientInit
|
||||
buttons, press = 0, None
|
||||
while True:
|
||||
kind = recv_exact(client, 1)[0]
|
||||
if kind == 5:
|
||||
mask, x, y = struct.unpack('>BHH', recv_exact(client, 5))
|
||||
x, y = clamp(x, WIDTH), clamp(y, HEIGHT)
|
||||
if mask & 1 and not buttons & 1: press = (x, y, time.monotonic())
|
||||
elif buttons & 1 and not mask & 1 and press:
|
||||
x0, y0, t0 = press; press = None
|
||||
ms = int((time.monotonic() - t0) * 1000)
|
||||
if abs(x - x0) < 6 and abs(y - y0) < 6: x, y, ms = x0, y0, max(ms, 96)
|
||||
actions.put(('touch', x0, y0, x, y, min(max(ms, 96), 5000)))
|
||||
if mask & 4 and not buttons & 4: actions.put(('home',))
|
||||
buttons = mask
|
||||
continue
|
||||
if kind == 4:
|
||||
down, key = struct.unpack('>B2xI', recv_exact(client, 7))
|
||||
if not down: continue
|
||||
if key in (KEY_ESCAPE, KEY_HOME): actions.put(('home',))
|
||||
elif key in SPECIAL_KEYS: actions.put(('key', SPECIAL_KEYS[key]))
|
||||
elif 0x20 <= key < 0x100 and key != 0x7f: actions.put(('text', chr(key)))
|
||||
elif key & 0xff000000 == 0x01000000: actions.put(('text', chr(key & 0xffffff)))
|
||||
continue
|
||||
if kind == 255:
|
||||
body = recv_exact(client, 11) # événement clavier étendu QEMU, ignoré
|
||||
if body[0] != 0: raise ConnectionError(f'message QEMU {body[0]} non géré')
|
||||
continue
|
||||
if kind == 0: body = recv_exact(client, 19)
|
||||
elif kind == 2:
|
||||
head = recv_exact(client, 3); body = head + recv_exact(client, 4 * struct.unpack('>xH', head)[0])
|
||||
elif kind == 3: body = recv_exact(client, 9)
|
||||
elif kind == 6:
|
||||
head = recv_exact(client, 7); body = head + recv_exact(client, struct.unpack('>3xI', head)[0])
|
||||
elif kind == 150: body = recv_exact(client, 9)
|
||||
elif kind == 248:
|
||||
head = recv_exact(client, 7); body = head + recv_exact(client, 16 * head[4])
|
||||
elif kind == 250:
|
||||
head = recv_exact(client, 8); body = head + recv_exact(client, head[7])
|
||||
else: raise ConnectionError(f'message client {kind} non géré')
|
||||
qemu.sendall(bytes([kind]) + body)
|
||||
|
||||
def serve(client, target, actions):
|
||||
with client, socket.create_connection(target) as qemu:
|
||||
threading.Thread(target=pipe, args=(qemu, client), daemon=True).start()
|
||||
try: client_messages(client, qemu, actions)
|
||||
except (ConnectionError, OSError) as e:
|
||||
if str(e): print('connexion fermée :', e, file=sys.stderr, flush=True)
|
||||
|
||||
def main():
|
||||
p = argparse.ArgumentParser(description=__doc__)
|
||||
p.add_argument('--port', type=int, default=5907)
|
||||
p.add_argument('--qemu-port', type=int, default=5906)
|
||||
a = p.parse_args()
|
||||
actions = queue.Queue()
|
||||
threading.Thread(target=gestures, args=(actions,), daemon=True).start()
|
||||
server = socket.create_server(('127.0.0.1', a.port))
|
||||
print(f'Relais VNC tactile : vnc://127.0.0.1:{a.port}', flush=True)
|
||||
while True:
|
||||
client, _ = server.accept()
|
||||
threading.Thread(target=serve, args=(client, ('127.0.0.1', a.qemu_port), actions), daemon=True).start()
|
||||
|
||||
if __name__ == '__main__': main()
|
||||
Reference in new issue
Block a user