qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio
at master 177 lines 5.0 kB view raw
1/* 2 * Copyright (c) 2018, Impinj, Inc. 3 * 4 * Chipidea USB block emulation code 5 * 6 * Author: Andrey Smirnov <andrew.smirnov@gmail.com> 7 * 8 * This work is licensed under the terms of the GNU GPL, version 2 or later. 9 * See the COPYING file in the top-level directory. 10 */ 11 12#include "qemu/osdep.h" 13#include "hw/usb/hcd-ehci.h" 14#include "hw/usb/chipidea.h" 15#include "qemu/log.h" 16#include "qemu/module.h" 17 18enum { 19 CHIPIDEA_USBx_DCIVERSION = 0x000, 20 CHIPIDEA_USBx_DCCPARAMS = 0x004, 21 CHIPIDEA_USBx_DCCPARAMS_HC = BIT(8), 22}; 23 24static uint64_t chipidea_read(void *opaque, hwaddr offset, 25 unsigned size) 26{ 27 return 0; 28} 29 30static void chipidea_write(void *opaque, hwaddr offset, 31 uint64_t value, unsigned size) 32{ 33} 34 35static const struct MemoryRegionOps chipidea_ops = { 36 .read = chipidea_read, 37 .write = chipidea_write, 38 .endianness = DEVICE_NATIVE_ENDIAN, 39 .impl = { 40 /* 41 * Our device would not work correctly if the guest was doing 42 * unaligned access. This might not be a limitation on the 43 * real device but in practice there is no reason for a guest 44 * to access this device unaligned. 45 */ 46 .min_access_size = 4, 47 .max_access_size = 4, 48 .unaligned = false, 49 }, 50}; 51 52static uint64_t chipidea_dc_read(void *opaque, hwaddr offset, 53 unsigned size) 54{ 55 switch (offset) { 56 case CHIPIDEA_USBx_DCIVERSION: 57 return 0x1; 58 case CHIPIDEA_USBx_DCCPARAMS: 59 /* 60 * Real hardware (at least i.MX7) will also report the 61 * controller as "Device Capable" (and 8 supported endpoints), 62 * but there doesn't seem to be much point in doing so, since 63 * we don't emulate that part. 64 */ 65 return CHIPIDEA_USBx_DCCPARAMS_HC; 66 } 67 68 return 0; 69} 70 71static void chipidea_dc_write(void *opaque, hwaddr offset, 72 uint64_t value, unsigned size) 73{ 74} 75 76static const struct MemoryRegionOps chipidea_dc_ops = { 77 .read = chipidea_dc_read, 78 .write = chipidea_dc_write, 79 .endianness = DEVICE_NATIVE_ENDIAN, 80 .impl = { 81 /* 82 * Our device would not work correctly if the guest was doing 83 * unaligned access. This might not be a limitation on the real 84 * device but in practice there is no reason for a guest to access 85 * this device unaligned. 86 */ 87 .min_access_size = 4, 88 .max_access_size = 4, 89 .unaligned = false, 90 }, 91}; 92 93static void chipidea_init(Object *obj) 94{ 95 EHCIState *ehci = &SYS_BUS_EHCI(obj)->ehci; 96 ChipideaState *ci = CHIPIDEA(obj); 97 int i; 98 99 for (i = 0; i < ARRAY_SIZE(ci->iomem); i++) { 100 const struct { 101 const char *name; 102 hwaddr offset; 103 uint64_t size; 104 const struct MemoryRegionOps *ops; 105 } regions[ARRAY_SIZE(ci->iomem)] = { 106 /* 107 * Registers located between offsets 0x000 and 0xFC 108 */ 109 { 110 .name = TYPE_CHIPIDEA ".misc", 111 .offset = 0x000, 112 .size = 0x100, 113 .ops = &chipidea_ops, 114 }, 115 /* 116 * Registers located between offsets 0x1A4 and 0x1DC 117 */ 118 { 119 .name = TYPE_CHIPIDEA ".endpoints", 120 .offset = 0x1A4, 121 .size = 0x1DC - 0x1A4 + 4, 122 .ops = &chipidea_ops, 123 }, 124 /* 125 * USB_x_DCIVERSION and USB_x_DCCPARAMS 126 */ 127 { 128 .name = TYPE_CHIPIDEA ".dc", 129 .offset = 0x120, 130 .size = 8, 131 .ops = &chipidea_dc_ops, 132 }, 133 }; 134 135 memory_region_init_io(&ci->iomem[i], 136 obj, 137 regions[i].ops, 138 ci, 139 regions[i].name, 140 regions[i].size); 141 142 memory_region_add_subregion(&ehci->mem, 143 regions[i].offset, 144 &ci->iomem[i]); 145 } 146} 147 148static void chipidea_class_init(ObjectClass *klass, void *data) 149{ 150 DeviceClass *dc = DEVICE_CLASS(klass); 151 SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(klass); 152 153 /* 154 * Offsets used were taken from i.MX7Dual Applications Processor 155 * Reference Manual, Rev 0.1, p. 3177, Table 11-59 156 */ 157 sec->capsbase = 0x100; 158 sec->opregbase = 0x140; 159 sec->portnr = 1; 160 161 set_bit(DEVICE_CATEGORY_USB, dc->categories); 162 dc->desc = "Chipidea USB Module"; 163} 164 165static const TypeInfo chipidea_info = { 166 .name = TYPE_CHIPIDEA, 167 .parent = TYPE_SYS_BUS_EHCI, 168 .instance_size = sizeof(ChipideaState), 169 .instance_init = chipidea_init, 170 .class_init = chipidea_class_init, 171}; 172 173static void chipidea_register_type(void) 174{ 175 type_register_static(&chipidea_info); 176} 177type_init(chipidea_register_type)