xref: /qemu/hw/vmapple/bdif.c (revision 06b40d250ecfa1633209c2e431a7a38acfd03a98)
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 
bdif_read(void * opaque,hwaddr offset,unsigned size)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 
le2cpu_sector(VblkSector * sector)1180179bb3cSAlexander Graf static void le2cpu_sector(VblkSector *sector)
1190179bb3cSAlexander Graf {
1200179bb3cSAlexander Graf     sector->sector = le32_to_cpu(sector->sector);
1210179bb3cSAlexander Graf }
1220179bb3cSAlexander Graf 
le2cpu_reqcmd(VblkReqCmd * cmd)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 
le2cpu_req(VblkReq * req)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 
vblk_cmd(uint64_t devid,BlockBackend * blk,uint64_t gp_addr,uint64_t static_off)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                                  &sector, sizeof(sector),
1630179bb3cSAlexander Graf                                  MEMTXATTRS_UNSPECIFIED);
1640179bb3cSAlexander Graf     if (dma_result != MEMTX_OK) {
1650179bb3cSAlexander Graf         goto out;
1660179bb3cSAlexander Graf     }
1670179bb3cSAlexander Graf     le2cpu_sector(&sector);
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 
bdif_write(void * opaque,hwaddr offset,uint64_t value,unsigned size)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 
bdif_init(Object * obj)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 
bdif_class_init(ObjectClass * klass,const void * data)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 
bdif_register_types(void)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