10179bb3cSAlexander Graf /* 20179bb3cSAlexander Graf * VMApple Backdoor Interface 30179bb3cSAlexander Graf * 40179bb3cSAlexander Graf * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. 50179bb3cSAlexander Graf * 60179bb3cSAlexander Graf * This work is licensed under the terms of the GNU GPL, version 2 or later. 70179bb3cSAlexander Graf * See the COPYING file in the top-level directory. 80179bb3cSAlexander Graf * 90179bb3cSAlexander Graf * SPDX-License-Identifier: GPL-2.0-or-later 100179bb3cSAlexander Graf */ 110179bb3cSAlexander Graf 120179bb3cSAlexander Graf #include "qemu/osdep.h" 130179bb3cSAlexander Graf #include "qemu/units.h" 140179bb3cSAlexander Graf #include "qemu/log.h" 150179bb3cSAlexander Graf #include "qemu/module.h" 160179bb3cSAlexander Graf #include "trace.h" 170179bb3cSAlexander Graf #include "hw/vmapple/vmapple.h" 180179bb3cSAlexander Graf #include "hw/sysbus.h" 190179bb3cSAlexander Graf #include "hw/block/block.h" 200179bb3cSAlexander Graf #include "qapi/error.h" 210179bb3cSAlexander Graf #include "system/block-backend.h" 220179bb3cSAlexander Graf #include "system/dma.h" 230179bb3cSAlexander Graf 240179bb3cSAlexander Graf OBJECT_DECLARE_SIMPLE_TYPE(VMAppleBdifState, VMAPPLE_BDIF) 250179bb3cSAlexander Graf 260179bb3cSAlexander Graf struct VMAppleBdifState { 270179bb3cSAlexander Graf SysBusDevice parent_obj; 280179bb3cSAlexander Graf 290179bb3cSAlexander Graf BlockBackend *aux; 300179bb3cSAlexander Graf BlockBackend *root; 310179bb3cSAlexander Graf MemoryRegion mmio; 320179bb3cSAlexander Graf }; 330179bb3cSAlexander Graf 340179bb3cSAlexander Graf #define VMAPPLE_BDIF_SIZE 0x00200000 350179bb3cSAlexander Graf 360179bb3cSAlexander Graf #define REG_DEVID_MASK 0xffff0000 370179bb3cSAlexander Graf #define DEVID_ROOT 0x00000000 380179bb3cSAlexander Graf #define DEVID_AUX 0x00010000 390179bb3cSAlexander Graf #define DEVID_USB 0x00100000 400179bb3cSAlexander Graf 410179bb3cSAlexander Graf #define REG_STATUS 0x0 420179bb3cSAlexander Graf #define REG_STATUS_ACTIVE BIT(0) 430179bb3cSAlexander Graf #define REG_CFG 0x4 440179bb3cSAlexander Graf #define REG_CFG_ACTIVE BIT(1) 450179bb3cSAlexander Graf #define REG_UNK1 0x8 460179bb3cSAlexander Graf #define REG_BUSY 0x10 470179bb3cSAlexander Graf #define REG_BUSY_READY BIT(0) 480179bb3cSAlexander Graf #define REG_UNK2 0x400 490179bb3cSAlexander Graf #define REG_CMD 0x408 500179bb3cSAlexander Graf #define REG_NEXT_DEVICE 0x420 510179bb3cSAlexander Graf #define REG_UNK3 0x434 520179bb3cSAlexander Graf 530179bb3cSAlexander Graf typedef struct VblkSector { 540179bb3cSAlexander Graf uint32_t pad; 550179bb3cSAlexander Graf uint32_t pad2; 560179bb3cSAlexander Graf uint32_t sector; 570179bb3cSAlexander Graf uint32_t pad3; 580179bb3cSAlexander Graf } VblkSector; 590179bb3cSAlexander Graf 600179bb3cSAlexander Graf typedef struct VblkReqCmd { 610179bb3cSAlexander Graf uint64_t addr; 620179bb3cSAlexander Graf uint32_t len; 630179bb3cSAlexander Graf uint32_t flags; 640179bb3cSAlexander Graf } VblkReqCmd; 650179bb3cSAlexander Graf 660179bb3cSAlexander Graf typedef struct VblkReq { 670179bb3cSAlexander Graf VblkReqCmd sector; 680179bb3cSAlexander Graf VblkReqCmd data; 690179bb3cSAlexander Graf VblkReqCmd retval; 700179bb3cSAlexander Graf } VblkReq; 710179bb3cSAlexander Graf 720179bb3cSAlexander Graf #define VBLK_DATA_FLAGS_READ 0x00030001 730179bb3cSAlexander Graf #define VBLK_DATA_FLAGS_WRITE 0x00010001 740179bb3cSAlexander Graf 750179bb3cSAlexander Graf #define VBLK_RET_SUCCESS 0 760179bb3cSAlexander Graf #define VBLK_RET_FAILED 1 770179bb3cSAlexander Graf 780179bb3cSAlexander Graf static uint64_t bdif_read(void *opaque, hwaddr offset, unsigned size) 790179bb3cSAlexander Graf { 800179bb3cSAlexander Graf uint64_t ret = -1; 810179bb3cSAlexander Graf uint64_t devid = offset & REG_DEVID_MASK; 820179bb3cSAlexander Graf 830179bb3cSAlexander Graf switch (offset & ~REG_DEVID_MASK) { 840179bb3cSAlexander Graf case REG_STATUS: 850179bb3cSAlexander Graf ret = REG_STATUS_ACTIVE; 860179bb3cSAlexander Graf break; 870179bb3cSAlexander Graf case REG_CFG: 880179bb3cSAlexander Graf ret = REG_CFG_ACTIVE; 890179bb3cSAlexander Graf break; 900179bb3cSAlexander Graf case REG_UNK1: 910179bb3cSAlexander Graf ret = 0x420; 920179bb3cSAlexander Graf break; 930179bb3cSAlexander Graf case REG_BUSY: 940179bb3cSAlexander Graf ret = REG_BUSY_READY; 950179bb3cSAlexander Graf break; 960179bb3cSAlexander Graf case REG_UNK2: 970179bb3cSAlexander Graf ret = 0x1; 980179bb3cSAlexander Graf break; 990179bb3cSAlexander Graf case REG_UNK3: 1000179bb3cSAlexander Graf ret = 0x0; 1010179bb3cSAlexander Graf break; 1020179bb3cSAlexander Graf case REG_NEXT_DEVICE: 1030179bb3cSAlexander Graf switch (devid) { 1040179bb3cSAlexander Graf case DEVID_ROOT: 1050179bb3cSAlexander Graf ret = 0x8000000; 1060179bb3cSAlexander Graf break; 1070179bb3cSAlexander Graf case DEVID_AUX: 1080179bb3cSAlexander Graf ret = 0x10000; 1090179bb3cSAlexander Graf break; 1100179bb3cSAlexander Graf } 1110179bb3cSAlexander Graf break; 1120179bb3cSAlexander Graf } 1130179bb3cSAlexander Graf 1140179bb3cSAlexander Graf trace_bdif_read(offset, size, ret); 1150179bb3cSAlexander Graf return ret; 1160179bb3cSAlexander Graf } 1170179bb3cSAlexander Graf 1180179bb3cSAlexander Graf static void le2cpu_sector(VblkSector *sector) 1190179bb3cSAlexander Graf { 1200179bb3cSAlexander Graf sector->sector = le32_to_cpu(sector->sector); 1210179bb3cSAlexander Graf } 1220179bb3cSAlexander Graf 1230179bb3cSAlexander Graf static void le2cpu_reqcmd(VblkReqCmd *cmd) 1240179bb3cSAlexander Graf { 1250179bb3cSAlexander Graf cmd->addr = le64_to_cpu(cmd->addr); 1260179bb3cSAlexander Graf cmd->len = le32_to_cpu(cmd->len); 1270179bb3cSAlexander Graf cmd->flags = le32_to_cpu(cmd->flags); 1280179bb3cSAlexander Graf } 1290179bb3cSAlexander Graf 1300179bb3cSAlexander Graf static void le2cpu_req(VblkReq *req) 1310179bb3cSAlexander Graf { 1320179bb3cSAlexander Graf le2cpu_reqcmd(&req->sector); 1330179bb3cSAlexander Graf le2cpu_reqcmd(&req->data); 1340179bb3cSAlexander Graf le2cpu_reqcmd(&req->retval); 1350179bb3cSAlexander Graf } 1360179bb3cSAlexander Graf 1370179bb3cSAlexander Graf static void vblk_cmd(uint64_t devid, BlockBackend *blk, uint64_t gp_addr, 1380179bb3cSAlexander Graf uint64_t static_off) 1390179bb3cSAlexander Graf { 1400179bb3cSAlexander Graf VblkReq req; 1410179bb3cSAlexander Graf VblkSector sector; 1420179bb3cSAlexander Graf uint64_t off = 0; 1430179bb3cSAlexander Graf g_autofree char *buf = NULL; 1440179bb3cSAlexander Graf uint8_t ret = VBLK_RET_FAILED; 1450179bb3cSAlexander Graf int r; 1460179bb3cSAlexander Graf MemTxResult dma_result; 1470179bb3cSAlexander Graf 1480179bb3cSAlexander Graf dma_result = dma_memory_read(&address_space_memory, gp_addr, 1490179bb3cSAlexander Graf &req, sizeof(req), MEMTXATTRS_UNSPECIFIED); 1500179bb3cSAlexander Graf if (dma_result != MEMTX_OK) { 1510179bb3cSAlexander Graf goto out; 1520179bb3cSAlexander Graf } 1530179bb3cSAlexander Graf 1540179bb3cSAlexander Graf le2cpu_req(&req); 1550179bb3cSAlexander Graf 1560179bb3cSAlexander Graf if (req.sector.len != sizeof(sector)) { 1570179bb3cSAlexander Graf goto out; 1580179bb3cSAlexander Graf } 1590179bb3cSAlexander Graf 1600179bb3cSAlexander Graf /* Read the vblk command */ 1610179bb3cSAlexander Graf dma_result = dma_memory_read(&address_space_memory, req.sector.addr, 1620179bb3cSAlexander Graf §or, sizeof(sector), 1630179bb3cSAlexander Graf MEMTXATTRS_UNSPECIFIED); 1640179bb3cSAlexander Graf if (dma_result != MEMTX_OK) { 1650179bb3cSAlexander Graf goto out; 1660179bb3cSAlexander Graf } 1670179bb3cSAlexander Graf le2cpu_sector(§or); 1680179bb3cSAlexander Graf 1690179bb3cSAlexander Graf off = sector.sector * 512ULL + static_off; 1700179bb3cSAlexander Graf 1710179bb3cSAlexander Graf /* Sanity check that we're not allocating bogus sizes */ 1720179bb3cSAlexander Graf if (req.data.len > 128 * MiB) { 1730179bb3cSAlexander Graf goto out; 1740179bb3cSAlexander Graf } 1750179bb3cSAlexander Graf 1760179bb3cSAlexander Graf buf = g_malloc0(req.data.len); 1770179bb3cSAlexander Graf switch (req.data.flags) { 1780179bb3cSAlexander Graf case VBLK_DATA_FLAGS_READ: 1790179bb3cSAlexander Graf r = blk_pread(blk, off, req.data.len, buf, 0); 1800179bb3cSAlexander Graf trace_bdif_vblk_read(devid == DEVID_AUX ? "aux" : "root", 1810179bb3cSAlexander Graf req.data.addr, off, req.data.len, r); 1820179bb3cSAlexander Graf if (r < 0) { 1830179bb3cSAlexander Graf goto out; 1840179bb3cSAlexander Graf } 1850179bb3cSAlexander Graf dma_result = dma_memory_write(&address_space_memory, req.data.addr, buf, 1860179bb3cSAlexander Graf req.data.len, MEMTXATTRS_UNSPECIFIED); 1870179bb3cSAlexander Graf if (dma_result == MEMTX_OK) { 1880179bb3cSAlexander Graf ret = VBLK_RET_SUCCESS; 1890179bb3cSAlexander Graf } 1900179bb3cSAlexander Graf break; 1910179bb3cSAlexander Graf case VBLK_DATA_FLAGS_WRITE: 1920179bb3cSAlexander Graf /* Not needed, iBoot only reads */ 1930179bb3cSAlexander Graf break; 1940179bb3cSAlexander Graf default: 1950179bb3cSAlexander Graf break; 1960179bb3cSAlexander Graf } 1970179bb3cSAlexander Graf 1980179bb3cSAlexander Graf out: 1990179bb3cSAlexander Graf dma_memory_write(&address_space_memory, req.retval.addr, &ret, 1, 2000179bb3cSAlexander Graf MEMTXATTRS_UNSPECIFIED); 2010179bb3cSAlexander Graf } 2020179bb3cSAlexander Graf 2030179bb3cSAlexander Graf static void bdif_write(void *opaque, hwaddr offset, 2040179bb3cSAlexander Graf uint64_t value, unsigned size) 2050179bb3cSAlexander Graf { 2060179bb3cSAlexander Graf VMAppleBdifState *s = opaque; 2070179bb3cSAlexander Graf uint64_t devid = (offset & REG_DEVID_MASK); 2080179bb3cSAlexander Graf 2090179bb3cSAlexander Graf trace_bdif_write(offset, size, value); 2100179bb3cSAlexander Graf 2110179bb3cSAlexander Graf switch (offset & ~REG_DEVID_MASK) { 2120179bb3cSAlexander Graf case REG_CMD: 2130179bb3cSAlexander Graf switch (devid) { 2140179bb3cSAlexander Graf case DEVID_ROOT: 2150179bb3cSAlexander Graf vblk_cmd(devid, s->root, value, 0x0); 2160179bb3cSAlexander Graf break; 2170179bb3cSAlexander Graf case DEVID_AUX: 2180179bb3cSAlexander Graf vblk_cmd(devid, s->aux, value, 0x0); 2190179bb3cSAlexander Graf break; 2200179bb3cSAlexander Graf } 2210179bb3cSAlexander Graf break; 2220179bb3cSAlexander Graf } 2230179bb3cSAlexander Graf } 2240179bb3cSAlexander Graf 2250179bb3cSAlexander Graf static const MemoryRegionOps bdif_ops = { 2260179bb3cSAlexander Graf .read = bdif_read, 2270179bb3cSAlexander Graf .write = bdif_write, 2280179bb3cSAlexander Graf .endianness = DEVICE_NATIVE_ENDIAN, 2290179bb3cSAlexander Graf .valid = { 2300179bb3cSAlexander Graf .min_access_size = 1, 2310179bb3cSAlexander Graf .max_access_size = 8, 2320179bb3cSAlexander Graf }, 2330179bb3cSAlexander Graf .impl = { 2340179bb3cSAlexander Graf .min_access_size = 1, 2350179bb3cSAlexander Graf .max_access_size = 8, 2360179bb3cSAlexander Graf }, 2370179bb3cSAlexander Graf }; 2380179bb3cSAlexander Graf 2390179bb3cSAlexander Graf static void bdif_init(Object *obj) 2400179bb3cSAlexander Graf { 2410179bb3cSAlexander Graf VMAppleBdifState *s = VMAPPLE_BDIF(obj); 2420179bb3cSAlexander Graf 2430179bb3cSAlexander Graf memory_region_init_io(&s->mmio, obj, &bdif_ops, obj, 2440179bb3cSAlexander Graf "VMApple Backdoor Interface", VMAPPLE_BDIF_SIZE); 2450179bb3cSAlexander Graf sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); 2460179bb3cSAlexander Graf } 2470179bb3cSAlexander Graf 2480179bb3cSAlexander Graf static const Property bdif_properties[] = { 2490179bb3cSAlexander Graf DEFINE_PROP_DRIVE("aux", VMAppleBdifState, aux), 2500179bb3cSAlexander Graf DEFINE_PROP_DRIVE("root", VMAppleBdifState, root), 2510179bb3cSAlexander Graf }; 2520179bb3cSAlexander Graf 253*12d1a768SPhilippe Mathieu-Daudé static void bdif_class_init(ObjectClass *klass, const void *data) 2540179bb3cSAlexander Graf { 2550179bb3cSAlexander Graf DeviceClass *dc = DEVICE_CLASS(klass); 2560179bb3cSAlexander Graf 2570179bb3cSAlexander Graf dc->desc = "VMApple Backdoor Interface"; 2580179bb3cSAlexander Graf device_class_set_props(dc, bdif_properties); 2590179bb3cSAlexander Graf } 2600179bb3cSAlexander Graf 2610179bb3cSAlexander Graf static const TypeInfo bdif_info = { 2620179bb3cSAlexander Graf .name = TYPE_VMAPPLE_BDIF, 2630179bb3cSAlexander Graf .parent = TYPE_SYS_BUS_DEVICE, 2640179bb3cSAlexander Graf .instance_size = sizeof(VMAppleBdifState), 2650179bb3cSAlexander Graf .instance_init = bdif_init, 2660179bb3cSAlexander Graf .class_init = bdif_class_init, 2670179bb3cSAlexander Graf }; 2680179bb3cSAlexander Graf 2690179bb3cSAlexander Graf static void bdif_register_types(void) 2700179bb3cSAlexander Graf { 2710179bb3cSAlexander Graf type_register_static(&bdif_info); 2720179bb3cSAlexander Graf } 2730179bb3cSAlexander Graf 2740179bb3cSAlexander Graf type_init(bdif_register_types) 275