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