xref: /qemu/hw/remote/message.c (revision bd36adb8df5d62a2b4d4ded6357fb50b69a508fa)
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 #include "qemu-common.h"
12 
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 
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 
30 void coroutine_fn mpqemu_remote_msg_loop_co(void *data)
31 {
32     g_autofree RemoteCommDev *com = (RemoteCommDev *)data;
33     PCIDevice *pci_dev = NULL;
34     Error *local_err = NULL;
35 
36     assert(com->ioc);
37 
38     pci_dev = com->dev;
39     for (; !local_err;) {
40         MPQemuMsg msg = {0};
41 
42         if (!mpqemu_msg_recv(&msg, com->ioc, &local_err)) {
43             break;
44         }
45 
46         if (!mpqemu_msg_valid(&msg)) {
47             error_setg(&local_err, "Received invalid message from proxy"
48                                    "in remote process pid="FMT_pid"",
49                                    getpid());
50             break;
51         }
52 
53         switch (msg.cmd) {
54         case MPQEMU_CMD_PCI_CFGWRITE:
55             process_config_write(com->ioc, pci_dev, &msg, &local_err);
56             break;
57         case MPQEMU_CMD_PCI_CFGREAD:
58             process_config_read(com->ioc, pci_dev, &msg, &local_err);
59             break;
60         case MPQEMU_CMD_BAR_WRITE:
61             process_bar_write(com->ioc, &msg, &local_err);
62             break;
63         case MPQEMU_CMD_BAR_READ:
64             process_bar_read(com->ioc, &msg, &local_err);
65             break;
66         case MPQEMU_CMD_SYNC_SYSMEM:
67             remote_sysmem_reconfig(&msg, &local_err);
68             break;
69         case MPQEMU_CMD_SET_IRQFD:
70             process_set_irqfd_msg(pci_dev, &msg);
71             break;
72         default:
73             error_setg(&local_err,
74                        "Unknown command (%d) received for device %s"
75                        " (pid="FMT_pid")",
76                        msg.cmd, DEVICE(pci_dev)->id, getpid());
77         }
78     }
79 
80     if (local_err) {
81         error_report_err(local_err);
82         qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_ERROR);
83     } else {
84         qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
85     }
86 }
87 
88 static void process_config_write(QIOChannel *ioc, PCIDevice *dev,
89                                  MPQemuMsg *msg, Error **errp)
90 {
91     ERRP_GUARD();
92     PciConfDataMsg *conf = (PciConfDataMsg *)&msg->data.pci_conf_data;
93     MPQemuMsg ret = { 0 };
94 
95     if ((conf->addr + sizeof(conf->val)) > pci_config_size(dev)) {
96         error_setg(errp, "Bad address for PCI config write, pid "FMT_pid".",
97                    getpid());
98         ret.data.u64 = UINT64_MAX;
99     } else {
100         pci_default_write_config(dev, conf->addr, conf->val, conf->len);
101     }
102 
103     ret.cmd = MPQEMU_CMD_RET;
104     ret.size = sizeof(ret.data.u64);
105 
106     if (!mpqemu_msg_send(&ret, ioc, NULL)) {
107         error_prepend(errp, "Error returning code to proxy, pid "FMT_pid": ",
108                       getpid());
109     }
110 }
111 
112 static void process_config_read(QIOChannel *ioc, PCIDevice *dev,
113                                 MPQemuMsg *msg, Error **errp)
114 {
115     ERRP_GUARD();
116     PciConfDataMsg *conf = (PciConfDataMsg *)&msg->data.pci_conf_data;
117     MPQemuMsg ret = { 0 };
118 
119     if ((conf->addr + sizeof(conf->val)) > pci_config_size(dev)) {
120         error_setg(errp, "Bad address for PCI config read, pid "FMT_pid".",
121                    getpid());
122         ret.data.u64 = UINT64_MAX;
123     } else {
124         ret.data.u64 = pci_default_read_config(dev, conf->addr, conf->len);
125     }
126 
127     ret.cmd = MPQEMU_CMD_RET;
128     ret.size = sizeof(ret.data.u64);
129 
130     if (!mpqemu_msg_send(&ret, ioc, NULL)) {
131         error_prepend(errp, "Error returning code to proxy, pid "FMT_pid": ",
132                       getpid());
133     }
134 }
135 
136 static void process_bar_write(QIOChannel *ioc, MPQemuMsg *msg, Error **errp)
137 {
138     ERRP_GUARD();
139     BarAccessMsg *bar_access = &msg->data.bar_access;
140     AddressSpace *as =
141         bar_access->memory ? &address_space_memory : &address_space_io;
142     MPQemuMsg ret = { 0 };
143     MemTxResult res;
144     uint64_t val;
145 
146     if (!is_power_of_2(bar_access->size) ||
147        (bar_access->size > sizeof(uint64_t))) {
148         ret.data.u64 = UINT64_MAX;
149         goto fail;
150     }
151 
152     val = cpu_to_le64(bar_access->val);
153 
154     res = address_space_rw(as, bar_access->addr, MEMTXATTRS_UNSPECIFIED,
155                            (void *)&val, bar_access->size, true);
156 
157     if (res != MEMTX_OK) {
158         error_setg(errp, "Bad address %"PRIx64" for mem write, pid "FMT_pid".",
159                    bar_access->addr, getpid());
160         ret.data.u64 = -1;
161     }
162 
163 fail:
164     ret.cmd = MPQEMU_CMD_RET;
165     ret.size = sizeof(ret.data.u64);
166 
167     if (!mpqemu_msg_send(&ret, ioc, NULL)) {
168         error_prepend(errp, "Error returning code to proxy, pid "FMT_pid": ",
169                       getpid());
170     }
171 }
172 
173 static void process_bar_read(QIOChannel *ioc, MPQemuMsg *msg, Error **errp)
174 {
175     ERRP_GUARD();
176     BarAccessMsg *bar_access = &msg->data.bar_access;
177     MPQemuMsg ret = { 0 };
178     AddressSpace *as;
179     MemTxResult res;
180     uint64_t val = 0;
181 
182     as = bar_access->memory ? &address_space_memory : &address_space_io;
183 
184     if (!is_power_of_2(bar_access->size) ||
185        (bar_access->size > sizeof(uint64_t))) {
186         val = UINT64_MAX;
187         goto fail;
188     }
189 
190     res = address_space_rw(as, bar_access->addr, MEMTXATTRS_UNSPECIFIED,
191                            (void *)&val, bar_access->size, false);
192 
193     if (res != MEMTX_OK) {
194         error_setg(errp, "Bad address %"PRIx64" for mem read, pid "FMT_pid".",
195                    bar_access->addr, getpid());
196         val = UINT64_MAX;
197     }
198 
199 fail:
200     ret.cmd = MPQEMU_CMD_RET;
201     ret.data.u64 = le64_to_cpu(val);
202     ret.size = sizeof(ret.data.u64);
203 
204     if (!mpqemu_msg_send(&ret, ioc, NULL)) {
205         error_prepend(errp, "Error returning code to proxy, pid "FMT_pid": ",
206                       getpid());
207     }
208 }
209