1 /* 2 * Copyright © 2020, 2021 Oracle and/or its affiliates. 3 * 4 * This work is licensed under the terms of the GNU GPL-v2, version 2 or later. 5 * 6 * See the COPYING file in the top-level directory. 7 * 8 */ 9 10 #include "qemu/osdep.h" 11 12 #include "hw/remote/machine.h" 13 #include "io/channel.h" 14 #include "hw/remote/mpqemu-link.h" 15 #include "qapi/error.h" 16 #include "sysemu/runstate.h" 17 #include "hw/pci/pci.h" 18 #include "exec/memattrs.h" 19 #include "hw/remote/memory.h" 20 #include "hw/remote/iohub.h" 21 #include "sysemu/reset.h" 22 23 static void process_config_write(QIOChannel *ioc, PCIDevice *dev, 24 MPQemuMsg *msg, Error **errp); 25 static void process_config_read(QIOChannel *ioc, PCIDevice *dev, 26 MPQemuMsg *msg, Error **errp); 27 static void process_bar_write(QIOChannel *ioc, MPQemuMsg *msg, Error **errp); 28 static void process_bar_read(QIOChannel *ioc, MPQemuMsg *msg, Error **errp); 29 static void process_device_reset_msg(QIOChannel *ioc, PCIDevice *dev, 30 Error **errp); 31 32 void coroutine_fn mpqemu_remote_msg_loop_co(void *data) 33 { 34 g_autofree RemoteCommDev *com = (RemoteCommDev *)data; 35 PCIDevice *pci_dev = NULL; 36 Error *local_err = NULL; 37 38 assert(com->ioc); 39 40 pci_dev = com->dev; 41 for (; !local_err;) { 42 MPQemuMsg msg = {0}; 43 44 if (!mpqemu_msg_recv(&msg, com->ioc, &local_err)) { 45 break; 46 } 47 48 if (!mpqemu_msg_valid(&msg)) { 49 error_setg(&local_err, "Received invalid message from proxy" 50 "in remote process pid="FMT_pid"", 51 getpid()); 52 break; 53 } 54 55 switch (msg.cmd) { 56 case MPQEMU_CMD_PCI_CFGWRITE: 57 process_config_write(com->ioc, pci_dev, &msg, &local_err); 58 break; 59 case MPQEMU_CMD_PCI_CFGREAD: 60 process_config_read(com->ioc, pci_dev, &msg, &local_err); 61 break; 62 case MPQEMU_CMD_BAR_WRITE: 63 process_bar_write(com->ioc, &msg, &local_err); 64 break; 65 case MPQEMU_CMD_BAR_READ: 66 process_bar_read(com->ioc, &msg, &local_err); 67 break; 68 case MPQEMU_CMD_SYNC_SYSMEM: 69 remote_sysmem_reconfig(&msg, &local_err); 70 break; 71 case MPQEMU_CMD_SET_IRQFD: 72 process_set_irqfd_msg(pci_dev, &msg); 73 break; 74 case MPQEMU_CMD_DEVICE_RESET: 75 process_device_reset_msg(com->ioc, pci_dev, &local_err); 76 break; 77 default: 78 error_setg(&local_err, 79 "Unknown command (%d) received for device %s" 80 " (pid="FMT_pid")", 81 msg.cmd, DEVICE(pci_dev)->id, getpid()); 82 } 83 } 84 85 if (local_err) { 86 error_report_err(local_err); 87 qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_ERROR); 88 } else { 89 qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); 90 } 91 } 92 93 static void process_config_write(QIOChannel *ioc, PCIDevice *dev, 94 MPQemuMsg *msg, Error **errp) 95 { 96 ERRP_GUARD(); 97 PciConfDataMsg *conf = (PciConfDataMsg *)&msg->data.pci_conf_data; 98 MPQemuMsg ret = { 0 }; 99 100 if ((conf->addr + sizeof(conf->val)) > pci_config_size(dev)) { 101 error_setg(errp, "Bad address for PCI config write, pid "FMT_pid".", 102 getpid()); 103 ret.data.u64 = UINT64_MAX; 104 } else { 105 pci_default_write_config(dev, conf->addr, conf->val, conf->len); 106 } 107 108 ret.cmd = MPQEMU_CMD_RET; 109 ret.size = sizeof(ret.data.u64); 110 111 if (!mpqemu_msg_send(&ret, ioc, NULL)) { 112 error_prepend(errp, "Error returning code to proxy, pid "FMT_pid": ", 113 getpid()); 114 } 115 } 116 117 static void process_config_read(QIOChannel *ioc, PCIDevice *dev, 118 MPQemuMsg *msg, Error **errp) 119 { 120 ERRP_GUARD(); 121 PciConfDataMsg *conf = (PciConfDataMsg *)&msg->data.pci_conf_data; 122 MPQemuMsg ret = { 0 }; 123 124 if ((conf->addr + sizeof(conf->val)) > pci_config_size(dev)) { 125 error_setg(errp, "Bad address for PCI config read, pid "FMT_pid".", 126 getpid()); 127 ret.data.u64 = UINT64_MAX; 128 } else { 129 ret.data.u64 = pci_default_read_config(dev, conf->addr, conf->len); 130 } 131 132 ret.cmd = MPQEMU_CMD_RET; 133 ret.size = sizeof(ret.data.u64); 134 135 if (!mpqemu_msg_send(&ret, ioc, NULL)) { 136 error_prepend(errp, "Error returning code to proxy, pid "FMT_pid": ", 137 getpid()); 138 } 139 } 140 141 static void process_bar_write(QIOChannel *ioc, MPQemuMsg *msg, Error **errp) 142 { 143 ERRP_GUARD(); 144 BarAccessMsg *bar_access = &msg->data.bar_access; 145 AddressSpace *as = 146 bar_access->memory ? &address_space_memory : &address_space_io; 147 MPQemuMsg ret = { 0 }; 148 MemTxResult res; 149 uint64_t val; 150 151 if (!is_power_of_2(bar_access->size) || 152 (bar_access->size > sizeof(uint64_t))) { 153 ret.data.u64 = UINT64_MAX; 154 goto fail; 155 } 156 157 val = cpu_to_le64(bar_access->val); 158 159 res = address_space_rw(as, bar_access->addr, MEMTXATTRS_UNSPECIFIED, 160 (void *)&val, bar_access->size, true); 161 162 if (res != MEMTX_OK) { 163 error_setg(errp, "Bad address %"PRIx64" for mem write, pid "FMT_pid".", 164 bar_access->addr, getpid()); 165 ret.data.u64 = -1; 166 } 167 168 fail: 169 ret.cmd = MPQEMU_CMD_RET; 170 ret.size = sizeof(ret.data.u64); 171 172 if (!mpqemu_msg_send(&ret, ioc, NULL)) { 173 error_prepend(errp, "Error returning code to proxy, pid "FMT_pid": ", 174 getpid()); 175 } 176 } 177 178 static void process_bar_read(QIOChannel *ioc, MPQemuMsg *msg, Error **errp) 179 { 180 ERRP_GUARD(); 181 BarAccessMsg *bar_access = &msg->data.bar_access; 182 MPQemuMsg ret = { 0 }; 183 AddressSpace *as; 184 MemTxResult res; 185 uint64_t val = 0; 186 187 as = bar_access->memory ? &address_space_memory : &address_space_io; 188 189 if (!is_power_of_2(bar_access->size) || 190 (bar_access->size > sizeof(uint64_t))) { 191 val = UINT64_MAX; 192 goto fail; 193 } 194 195 res = address_space_rw(as, bar_access->addr, MEMTXATTRS_UNSPECIFIED, 196 (void *)&val, bar_access->size, false); 197 198 if (res != MEMTX_OK) { 199 error_setg(errp, "Bad address %"PRIx64" for mem read, pid "FMT_pid".", 200 bar_access->addr, getpid()); 201 val = UINT64_MAX; 202 } 203 204 fail: 205 ret.cmd = MPQEMU_CMD_RET; 206 ret.data.u64 = le64_to_cpu(val); 207 ret.size = sizeof(ret.data.u64); 208 209 if (!mpqemu_msg_send(&ret, ioc, NULL)) { 210 error_prepend(errp, "Error returning code to proxy, pid "FMT_pid": ", 211 getpid()); 212 } 213 } 214 215 static void process_device_reset_msg(QIOChannel *ioc, PCIDevice *dev, 216 Error **errp) 217 { 218 DeviceClass *dc = DEVICE_GET_CLASS(dev); 219 DeviceState *s = DEVICE(dev); 220 MPQemuMsg ret = { 0 }; 221 222 if (dc->reset) { 223 dc->reset(s); 224 } 225 226 ret.cmd = MPQEMU_CMD_RET; 227 228 mpqemu_msg_send(&ret, ioc, errp); 229 } 230