1 /* 2 * Copyright © 2018, 2021 Oracle and/or its affiliates. 3 * 4 * This work is licensed under the terms of the GNU GPL, version 2 or later. 5 * See the COPYING file in the top-level directory. 6 * 7 */ 8 9 #include "qemu/osdep.h" 10 #include "qemu-common.h" 11 12 #include "hw/remote/proxy.h" 13 #include "hw/pci/pci.h" 14 #include "qapi/error.h" 15 #include "io/channel-util.h" 16 #include "hw/qdev-properties.h" 17 #include "monitor/monitor.h" 18 #include "migration/blocker.h" 19 #include "qemu/sockets.h" 20 #include "hw/remote/mpqemu-link.h" 21 #include "qemu/error-report.h" 22 #include "hw/remote/proxy-memory-listener.h" 23 #include "qom/object.h" 24 #include "qemu/event_notifier.h" 25 #include "sysemu/kvm.h" 26 #include "util/event_notifier-posix.c" 27 28 static void proxy_intx_update(PCIDevice *pci_dev) 29 { 30 PCIProxyDev *dev = PCI_PROXY_DEV(pci_dev); 31 PCIINTxRoute route; 32 int pin = pci_get_byte(pci_dev->config + PCI_INTERRUPT_PIN) - 1; 33 34 if (dev->virq != -1) { 35 kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, &dev->intr, dev->virq); 36 dev->virq = -1; 37 } 38 39 route = pci_device_route_intx_to_irq(pci_dev, pin); 40 41 dev->virq = route.irq; 42 43 if (dev->virq != -1) { 44 kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, &dev->intr, 45 &dev->resample, dev->virq); 46 } 47 } 48 49 static void setup_irqfd(PCIProxyDev *dev) 50 { 51 PCIDevice *pci_dev = PCI_DEVICE(dev); 52 MPQemuMsg msg; 53 Error *local_err = NULL; 54 55 event_notifier_init(&dev->intr, 0); 56 event_notifier_init(&dev->resample, 0); 57 58 memset(&msg, 0, sizeof(MPQemuMsg)); 59 msg.cmd = MPQEMU_CMD_SET_IRQFD; 60 msg.num_fds = 2; 61 msg.fds[0] = event_notifier_get_fd(&dev->intr); 62 msg.fds[1] = event_notifier_get_fd(&dev->resample); 63 msg.size = 0; 64 65 if (!mpqemu_msg_send(&msg, dev->ioc, &local_err)) { 66 error_report_err(local_err); 67 } 68 69 dev->virq = -1; 70 71 proxy_intx_update(pci_dev); 72 73 pci_device_set_intx_routing_notifier(pci_dev, proxy_intx_update); 74 } 75 76 static void pci_proxy_dev_realize(PCIDevice *device, Error **errp) 77 { 78 ERRP_GUARD(); 79 PCIProxyDev *dev = PCI_PROXY_DEV(device); 80 int fd; 81 82 if (!dev->fd) { 83 error_setg(errp, "fd parameter not specified for %s", 84 DEVICE(device)->id); 85 return; 86 } 87 88 fd = monitor_fd_param(monitor_cur(), dev->fd, errp); 89 if (fd == -1) { 90 error_prepend(errp, "proxy: unable to parse fd %s: ", dev->fd); 91 return; 92 } 93 94 if (!fd_is_socket(fd)) { 95 error_setg(errp, "proxy: fd %d is not a socket", fd); 96 close(fd); 97 return; 98 } 99 100 dev->ioc = qio_channel_new_fd(fd, errp); 101 102 error_setg(&dev->migration_blocker, "%s does not support migration", 103 TYPE_PCI_PROXY_DEV); 104 migrate_add_blocker(dev->migration_blocker, errp); 105 106 qemu_mutex_init(&dev->io_mutex); 107 qio_channel_set_blocking(dev->ioc, true, NULL); 108 109 proxy_memory_listener_configure(&dev->proxy_listener, dev->ioc); 110 111 setup_irqfd(dev); 112 } 113 114 static void pci_proxy_dev_exit(PCIDevice *pdev) 115 { 116 PCIProxyDev *dev = PCI_PROXY_DEV(pdev); 117 118 if (dev->ioc) { 119 qio_channel_close(dev->ioc, NULL); 120 } 121 122 migrate_del_blocker(dev->migration_blocker); 123 124 error_free(dev->migration_blocker); 125 126 proxy_memory_listener_deconfigure(&dev->proxy_listener); 127 128 event_notifier_cleanup(&dev->intr); 129 event_notifier_cleanup(&dev->resample); 130 } 131 132 static void config_op_send(PCIProxyDev *pdev, uint32_t addr, uint32_t *val, 133 int len, unsigned int op) 134 { 135 MPQemuMsg msg = { 0 }; 136 uint64_t ret = -EINVAL; 137 Error *local_err = NULL; 138 139 msg.cmd = op; 140 msg.data.pci_conf_data.addr = addr; 141 msg.data.pci_conf_data.val = (op == MPQEMU_CMD_PCI_CFGWRITE) ? *val : 0; 142 msg.data.pci_conf_data.len = len; 143 msg.size = sizeof(PciConfDataMsg); 144 145 ret = mpqemu_msg_send_and_await_reply(&msg, pdev, &local_err); 146 if (local_err) { 147 error_report_err(local_err); 148 } 149 150 if (ret == UINT64_MAX) { 151 error_report("Failed to perform PCI config %s operation", 152 (op == MPQEMU_CMD_PCI_CFGREAD) ? "READ" : "WRITE"); 153 } 154 155 if (op == MPQEMU_CMD_PCI_CFGREAD) { 156 *val = (uint32_t)ret; 157 } 158 } 159 160 static uint32_t pci_proxy_read_config(PCIDevice *d, uint32_t addr, int len) 161 { 162 uint32_t val; 163 164 config_op_send(PCI_PROXY_DEV(d), addr, &val, len, MPQEMU_CMD_PCI_CFGREAD); 165 166 return val; 167 } 168 169 static void pci_proxy_write_config(PCIDevice *d, uint32_t addr, uint32_t val, 170 int len) 171 { 172 /* 173 * Some of the functions access the copy of remote device's PCI config 174 * space which is cached in the proxy device. Therefore, maintain 175 * it updated. 176 */ 177 pci_default_write_config(d, addr, val, len); 178 179 config_op_send(PCI_PROXY_DEV(d), addr, &val, len, MPQEMU_CMD_PCI_CFGWRITE); 180 } 181 182 static Property proxy_properties[] = { 183 DEFINE_PROP_STRING("fd", PCIProxyDev, fd), 184 DEFINE_PROP_END_OF_LIST(), 185 }; 186 187 static void pci_proxy_dev_class_init(ObjectClass *klass, void *data) 188 { 189 DeviceClass *dc = DEVICE_CLASS(klass); 190 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); 191 192 k->realize = pci_proxy_dev_realize; 193 k->exit = pci_proxy_dev_exit; 194 k->config_read = pci_proxy_read_config; 195 k->config_write = pci_proxy_write_config; 196 197 device_class_set_props(dc, proxy_properties); 198 } 199 200 static const TypeInfo pci_proxy_dev_type_info = { 201 .name = TYPE_PCI_PROXY_DEV, 202 .parent = TYPE_PCI_DEVICE, 203 .instance_size = sizeof(PCIProxyDev), 204 .class_init = pci_proxy_dev_class_init, 205 .interfaces = (InterfaceInfo[]) { 206 { INTERFACE_CONVENTIONAL_PCI_DEVICE }, 207 { }, 208 }, 209 }; 210 211 static void pci_proxy_dev_register_types(void) 212 { 213 type_register_static(&pci_proxy_dev_type_info); 214 } 215 216 type_init(pci_proxy_dev_register_types) 217 218 static void send_bar_access_msg(PCIProxyDev *pdev, MemoryRegion *mr, 219 bool write, hwaddr addr, uint64_t *val, 220 unsigned size, bool memory) 221 { 222 MPQemuMsg msg = { 0 }; 223 long ret = -EINVAL; 224 Error *local_err = NULL; 225 226 msg.size = sizeof(BarAccessMsg); 227 msg.data.bar_access.addr = mr->addr + addr; 228 msg.data.bar_access.size = size; 229 msg.data.bar_access.memory = memory; 230 231 if (write) { 232 msg.cmd = MPQEMU_CMD_BAR_WRITE; 233 msg.data.bar_access.val = *val; 234 } else { 235 msg.cmd = MPQEMU_CMD_BAR_READ; 236 } 237 238 ret = mpqemu_msg_send_and_await_reply(&msg, pdev, &local_err); 239 if (local_err) { 240 error_report_err(local_err); 241 } 242 243 if (!write) { 244 *val = ret; 245 } 246 } 247 248 static void proxy_bar_write(void *opaque, hwaddr addr, uint64_t val, 249 unsigned size) 250 { 251 ProxyMemoryRegion *pmr = opaque; 252 253 send_bar_access_msg(pmr->dev, &pmr->mr, true, addr, &val, size, 254 pmr->memory); 255 } 256 257 static uint64_t proxy_bar_read(void *opaque, hwaddr addr, unsigned size) 258 { 259 ProxyMemoryRegion *pmr = opaque; 260 uint64_t val; 261 262 send_bar_access_msg(pmr->dev, &pmr->mr, false, addr, &val, size, 263 pmr->memory); 264 265 return val; 266 } 267 268 const MemoryRegionOps proxy_mr_ops = { 269 .read = proxy_bar_read, 270 .write = proxy_bar_write, 271 .endianness = DEVICE_NATIVE_ENDIAN, 272 .impl = { 273 .min_access_size = 1, 274 .max_access_size = 8, 275 }, 276 }; 277