hw/arm: add authenticated A6 IMG3 boot lab

Model the A6 crypto, interrupt, USB, and platform blocks needed to boot SecureROM through iBSS into iBEC Recovery.

Add local lab identity, IMG3, and APTicket tooling, patched macOS recovery utilities, UART and GDB access, and English end-user documentation.
This commit is contained in:
2026-09-01 09:51:49 -07:00
parent 47977dd34a
commit 5d9a60a926
45 changed files with 6002 additions and 265 deletions
+89 -7
View File
@@ -5,6 +5,9 @@
#include "hw/core/boards.h"
#include "hw/core/loader.h"
#include "hw/misc/unimp.h"
#include "hw/misc/s5l8950x-aes.h"
#include "hw/misc/s5l8950x-pke.h"
#include "hw/misc/s5l8950x-sha1.h"
#include "hw/core/sysbus.h"
#include "system/address-spaces.h"
#include "target/arm/cpu.h"
@@ -30,6 +33,39 @@ static const ARMCPRegInfo s5l8950x_cp_reginfo[] = {
.access = PL1_W,
.type = ARM_CP_NOP,
},
{
.name = "APPLE_SWIFT_AUX_CFG",
.cp = 15,
.opc1 = 1,
.crn = 15,
.crm = 2,
.opc2 = 4,
.access = PL1_RW,
.type = ARM_CP_CONST,
.resetvalue = 0,
},
{
.name = "APPLE_SWIFT_AUX_CFG2",
.cp = 15,
.opc1 = 1,
.crn = 15,
.crm = 2,
.opc2 = 5,
.access = PL1_RW,
.type = ARM_CP_CONST,
.resetvalue = 0,
},
{
.name = "APPLE_SWIFT_AUX_CFG3",
.cp = 15,
.opc1 = 1,
.crn = 15,
.crm = 2,
.opc2 = 7,
.access = PL1_RW,
.type = ARM_CP_CONST,
.resetvalue = 0,
},
};
/* Addresses */
@@ -40,21 +76,30 @@ static const ARMCPRegInfo s5l8950x_cp_reginfo[] = {
#define S5L8950X_SDIO_BASE 0x20000000
#define S5L8950X_USB_PHY_BASE 0x36000000
#define S5L8950X_USB_BASE 0x36100000
#define S5L8950X_SHA1_BASE 0x3C500000
#define S5L8950X_SHA1_BASE 0x30200000
#define S5L8950X_SPI_BASE 0x3D200000
#define S5L8950X_AES_BASE 0x3E000000
#define S5L8950X_AES_DMA_BASE 0x37000000
#define S5L8950X_AES_BASE 0x37800000
#define S5L8950X_IIC_BASE 0x3E100000
#define S5L8950X_PKE_BASE 0x3E200000
#define S5L8950X_PKE_BASE 0x33100000
#define S5L8950X_WDT_BASE 0x3E300000
#define S5L8950X_CHIPID_BASE 0x3F500000
#define S5L8950X_TIMER_BASE 0x3F200000
#define S5L8950X_PMGR_BASE 0x3F100000
#define S5L8950X_CLOCK_BASE 0x3F800000
#define S5L8950X_MEMCTL_BASE 0x39500000
#define S5L8950X_AMC_BASE 0x40000000
#define S5L8950X_AIC_BASE 0x3F200000
#define S5L8950X_UART_BASE 0x44300000
#define S5L8950X_UART_BASE 0x32B00000
#define S5L8950X_GPIO_BASE 0x3FA00000
#define S5L8950X_DRAM_BASE 0x80000000
static const hwaddr s5l8950x_i2c_base[] = {
0x33200000,
0x33300000,
0x33400000,
};
static void s5l8950x_init(Object *obj)
{
S5L8950XState *s = S5L8950X(obj);
@@ -84,11 +129,8 @@ static void s5l8950x_realize(DeviceState *dev, Error **errp)
/* Create unimplemented devices */
create_unimplemented_device("s5l8950x.sdio", S5L8950X_SDIO_BASE, 0x10000);
create_unimplemented_device("s5l8950x.sha1", S5L8950X_SHA1_BASE, 0x1000);
create_unimplemented_device("s5l8950x.spi", S5L8950X_SPI_BASE, 0x1000);
create_unimplemented_device("s5l8950x.aes", S5L8950X_AES_BASE, 0x1000);
create_unimplemented_device("s5l8950x.iic", S5L8950X_IIC_BASE, 0x1000);
create_unimplemented_device("s5l8950x.pke", S5L8950X_PKE_BASE, 0x1000);
create_unimplemented_device("s5l8950x.wdt", S5L8950X_WDT_BASE, 0x1000);
create_unimplemented_device("s5l8950x.amc", S5L8950X_AMC_BASE, 0x1000);
@@ -98,6 +140,22 @@ static void s5l8950x_realize(DeviceState *dev, Error **errp)
sysbus_realize_and_unref(s->chipid, &error_fatal);
sysbus_mmio_map(s->chipid, 0, S5L8950X_CHIPID_BASE);
DeviceState *dev_aes = qdev_new(TYPE_S5L8950X_AES);
s->aes = SYS_BUS_DEVICE(dev_aes);
sysbus_realize_and_unref(s->aes, &error_fatal);
sysbus_mmio_map(s->aes, 0, S5L8950X_AES_DMA_BASE);
sysbus_mmio_map(s->aes, 1, S5L8950X_AES_BASE);
DeviceState *dev_pke = qdev_new(TYPE_S5L8950X_PKE);
s->pke = SYS_BUS_DEVICE(dev_pke);
sysbus_realize_and_unref(s->pke, &error_fatal);
sysbus_mmio_map(s->pke, 0, S5L8950X_PKE_BASE);
DeviceState *dev_sha1 = qdev_new(TYPE_S5L8950X_SHA1);
s->sha1 = SYS_BUS_DEVICE(dev_sha1);
sysbus_realize_and_unref(s->sha1, &error_fatal);
sysbus_mmio_map(s->sha1, 0, S5L8950X_SHA1_BASE);
DeviceState *dev_aic = qdev_new(TYPE_S5L8950X_AIC);
s->aic = SYS_BUS_DEVICE(dev_aic);
sysbus_realize_and_unref(s->aic, &error_fatal);
@@ -112,14 +170,38 @@ static void s5l8950x_realize(DeviceState *dev, Error **errp)
s->uart = SYS_BUS_DEVICE(dev_uart);
sysbus_realize_and_unref(s->uart, &error_fatal);
sysbus_mmio_map(s->uart, 0, S5L8950X_UART_BASE);
/* iBoot's A6 UART table maps 0x32b00000 to external IRQ 0x44. */
sysbus_connect_irq(s->uart, 0,
qdev_get_gpio_in(dev_aic, 0x44));
DeviceState *dev_pmgr = qdev_new(TYPE_S5L8950X_PMGR);
s->pmgr = SYS_BUS_DEVICE(dev_pmgr);
sysbus_realize_and_unref(s->pmgr, &error_fatal);
sysbus_mmio_map(s->pmgr, 0, S5L8950X_PMGR_BASE);
DeviceState *dev_clock = qdev_new(TYPE_S5L8950X_CLOCK);
s->clock = SYS_BUS_DEVICE(dev_clock);
sysbus_realize_and_unref(s->clock, &error_fatal);
sysbus_mmio_map(s->clock, 0, S5L8950X_CLOCK_BASE);
DeviceState *dev_memctl = qdev_new(TYPE_S5L8950X_MEMCTL);
s->memctl = SYS_BUS_DEVICE(dev_memctl);
sysbus_realize_and_unref(s->memctl, &error_fatal);
sysbus_mmio_map(s->memctl, 0, S5L8950X_MEMCTL_BASE);
for (size_t i = 0; i < ARRAY_SIZE(s5l8950x_i2c_base); i++) {
DeviceState *dev_i2c = qdev_new(TYPE_S5L8950X_I2C);
s->i2c[i] = SYS_BUS_DEVICE(dev_i2c);
sysbus_realize_and_unref(s->i2c[i], &error_fatal);
sysbus_mmio_map(s->i2c[i], 0, s5l8950x_i2c_base[i]);
sysbus_connect_irq(s->i2c[i], 0,
qdev_get_gpio_in(dev_aic, 0x46 + i));
}
DeviceState *dev_gpio = qdev_new(TYPE_S5L8950X_GPIO);
qdev_prop_set_bit(dev_gpio, "force-dfu", true);
qdev_prop_set_uint8(dev_gpio, "board-straps", 2);
s->gpio = SYS_BUS_DEVICE(dev_gpio);
sysbus_realize_and_unref(s->gpio, &error_fatal);
sysbus_mmio_map(s->gpio, 0, S5L8950X_GPIO_BASE);