bdif.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. /*
  2. * VMApple Backdoor Interface
  3. *
  4. * Copyright © 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  5. *
  6. * This work is licensed under the terms of the GNU GPL, version 2 or later.
  7. * See the COPYING file in the top-level directory.
  8. *
  9. * SPDX-License-Identifier: GPL-2.0-or-later
  10. */
  11. #include "qemu/osdep.h"
  12. #include "qemu/units.h"
  13. #include "qemu/log.h"
  14. #include "qemu/module.h"
  15. #include "trace.h"
  16. #include "hw/vmapple/vmapple.h"
  17. #include "hw/sysbus.h"
  18. #include "hw/block/block.h"
  19. #include "qapi/error.h"
  20. #include "system/block-backend.h"
  21. #include "system/dma.h"
  22. OBJECT_DECLARE_SIMPLE_TYPE(VMAppleBdifState, VMAPPLE_BDIF)
  23. struct VMAppleBdifState {
  24. SysBusDevice parent_obj;
  25. BlockBackend *aux;
  26. BlockBackend *root;
  27. MemoryRegion mmio;
  28. };
  29. #define VMAPPLE_BDIF_SIZE 0x00200000
  30. #define REG_DEVID_MASK 0xffff0000
  31. #define DEVID_ROOT 0x00000000
  32. #define DEVID_AUX 0x00010000
  33. #define DEVID_USB 0x00100000
  34. #define REG_STATUS 0x0
  35. #define REG_STATUS_ACTIVE BIT(0)
  36. #define REG_CFG 0x4
  37. #define REG_CFG_ACTIVE BIT(1)
  38. #define REG_UNK1 0x8
  39. #define REG_BUSY 0x10
  40. #define REG_BUSY_READY BIT(0)
  41. #define REG_UNK2 0x400
  42. #define REG_CMD 0x408
  43. #define REG_NEXT_DEVICE 0x420
  44. #define REG_UNK3 0x434
  45. typedef struct VblkSector {
  46. uint32_t pad;
  47. uint32_t pad2;
  48. uint32_t sector;
  49. uint32_t pad3;
  50. } VblkSector;
  51. typedef struct VblkReqCmd {
  52. uint64_t addr;
  53. uint32_t len;
  54. uint32_t flags;
  55. } VblkReqCmd;
  56. typedef struct VblkReq {
  57. VblkReqCmd sector;
  58. VblkReqCmd data;
  59. VblkReqCmd retval;
  60. } VblkReq;
  61. #define VBLK_DATA_FLAGS_READ 0x00030001
  62. #define VBLK_DATA_FLAGS_WRITE 0x00010001
  63. #define VBLK_RET_SUCCESS 0
  64. #define VBLK_RET_FAILED 1
  65. static uint64_t bdif_read(void *opaque, hwaddr offset, unsigned size)
  66. {
  67. uint64_t ret = -1;
  68. uint64_t devid = offset & REG_DEVID_MASK;
  69. switch (offset & ~REG_DEVID_MASK) {
  70. case REG_STATUS:
  71. ret = REG_STATUS_ACTIVE;
  72. break;
  73. case REG_CFG:
  74. ret = REG_CFG_ACTIVE;
  75. break;
  76. case REG_UNK1:
  77. ret = 0x420;
  78. break;
  79. case REG_BUSY:
  80. ret = REG_BUSY_READY;
  81. break;
  82. case REG_UNK2:
  83. ret = 0x1;
  84. break;
  85. case REG_UNK3:
  86. ret = 0x0;
  87. break;
  88. case REG_NEXT_DEVICE:
  89. switch (devid) {
  90. case DEVID_ROOT:
  91. ret = 0x8000000;
  92. break;
  93. case DEVID_AUX:
  94. ret = 0x10000;
  95. break;
  96. }
  97. break;
  98. }
  99. trace_bdif_read(offset, size, ret);
  100. return ret;
  101. }
  102. static void le2cpu_sector(VblkSector *sector)
  103. {
  104. sector->sector = le32_to_cpu(sector->sector);
  105. }
  106. static void le2cpu_reqcmd(VblkReqCmd *cmd)
  107. {
  108. cmd->addr = le64_to_cpu(cmd->addr);
  109. cmd->len = le32_to_cpu(cmd->len);
  110. cmd->flags = le32_to_cpu(cmd->flags);
  111. }
  112. static void le2cpu_req(VblkReq *req)
  113. {
  114. le2cpu_reqcmd(&req->sector);
  115. le2cpu_reqcmd(&req->data);
  116. le2cpu_reqcmd(&req->retval);
  117. }
  118. static void vblk_cmd(uint64_t devid, BlockBackend *blk, uint64_t gp_addr,
  119. uint64_t static_off)
  120. {
  121. VblkReq req;
  122. VblkSector sector;
  123. uint64_t off = 0;
  124. g_autofree char *buf = NULL;
  125. uint8_t ret = VBLK_RET_FAILED;
  126. int r;
  127. MemTxResult dma_result;
  128. dma_result = dma_memory_read(&address_space_memory, gp_addr,
  129. &req, sizeof(req), MEMTXATTRS_UNSPECIFIED);
  130. if (dma_result != MEMTX_OK) {
  131. goto out;
  132. }
  133. le2cpu_req(&req);
  134. if (req.sector.len != sizeof(sector)) {
  135. goto out;
  136. }
  137. /* Read the vblk command */
  138. dma_result = dma_memory_read(&address_space_memory, req.sector.addr,
  139. &sector, sizeof(sector),
  140. MEMTXATTRS_UNSPECIFIED);
  141. if (dma_result != MEMTX_OK) {
  142. goto out;
  143. }
  144. le2cpu_sector(&sector);
  145. off = sector.sector * 512ULL + static_off;
  146. /* Sanity check that we're not allocating bogus sizes */
  147. if (req.data.len > 128 * MiB) {
  148. goto out;
  149. }
  150. buf = g_malloc0(req.data.len);
  151. switch (req.data.flags) {
  152. case VBLK_DATA_FLAGS_READ:
  153. r = blk_pread(blk, off, req.data.len, buf, 0);
  154. trace_bdif_vblk_read(devid == DEVID_AUX ? "aux" : "root",
  155. req.data.addr, off, req.data.len, r);
  156. if (r < 0) {
  157. goto out;
  158. }
  159. dma_result = dma_memory_write(&address_space_memory, req.data.addr, buf,
  160. req.data.len, MEMTXATTRS_UNSPECIFIED);
  161. if (dma_result == MEMTX_OK) {
  162. ret = VBLK_RET_SUCCESS;
  163. }
  164. break;
  165. case VBLK_DATA_FLAGS_WRITE:
  166. /* Not needed, iBoot only reads */
  167. break;
  168. default:
  169. break;
  170. }
  171. out:
  172. dma_memory_write(&address_space_memory, req.retval.addr, &ret, 1,
  173. MEMTXATTRS_UNSPECIFIED);
  174. }
  175. static void bdif_write(void *opaque, hwaddr offset,
  176. uint64_t value, unsigned size)
  177. {
  178. VMAppleBdifState *s = opaque;
  179. uint64_t devid = (offset & REG_DEVID_MASK);
  180. trace_bdif_write(offset, size, value);
  181. switch (offset & ~REG_DEVID_MASK) {
  182. case REG_CMD:
  183. switch (devid) {
  184. case DEVID_ROOT:
  185. vblk_cmd(devid, s->root, value, 0x0);
  186. break;
  187. case DEVID_AUX:
  188. vblk_cmd(devid, s->aux, value, 0x0);
  189. break;
  190. }
  191. break;
  192. }
  193. }
  194. static const MemoryRegionOps bdif_ops = {
  195. .read = bdif_read,
  196. .write = bdif_write,
  197. .endianness = DEVICE_NATIVE_ENDIAN,
  198. .valid = {
  199. .min_access_size = 1,
  200. .max_access_size = 8,
  201. },
  202. .impl = {
  203. .min_access_size = 1,
  204. .max_access_size = 8,
  205. },
  206. };
  207. static void bdif_init(Object *obj)
  208. {
  209. VMAppleBdifState *s = VMAPPLE_BDIF(obj);
  210. memory_region_init_io(&s->mmio, obj, &bdif_ops, obj,
  211. "VMApple Backdoor Interface", VMAPPLE_BDIF_SIZE);
  212. sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
  213. }
  214. static const Property bdif_properties[] = {
  215. DEFINE_PROP_DRIVE("aux", VMAppleBdifState, aux),
  216. DEFINE_PROP_DRIVE("root", VMAppleBdifState, root),
  217. };
  218. static void bdif_class_init(ObjectClass *klass, void *data)
  219. {
  220. DeviceClass *dc = DEVICE_CLASS(klass);
  221. dc->desc = "VMApple Backdoor Interface";
  222. device_class_set_props(dc, bdif_properties);
  223. }
  224. static const TypeInfo bdif_info = {
  225. .name = TYPE_VMAPPLE_BDIF,
  226. .parent = TYPE_SYS_BUS_DEVICE,
  227. .instance_size = sizeof(VMAppleBdifState),
  228. .instance_init = bdif_init,
  229. .class_init = bdif_class_init,
  230. };
  231. static void bdif_register_types(void)
  232. {
  233. type_register_static(&bdif_info);
  234. }
  235. type_init(bdif_register_types)