xref: /qemu/hw/remote/message.c (revision 11ab872588335918ddc83c73957077bb85a38a6d)
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 
20 static void process_config_write(QIOChannel *ioc, PCIDevice *dev,
21                                  MPQemuMsg *msg, Error **errp);
22 static void process_config_read(QIOChannel *ioc, PCIDevice *dev,
23                                 MPQemuMsg *msg, Error **errp);
24 
25 void coroutine_fn mpqemu_remote_msg_loop_co(void *data)
26 {
27     g_autofree RemoteCommDev *com = (RemoteCommDev *)data;
28     PCIDevice *pci_dev = NULL;
29     Error *local_err = NULL;
30 
31     assert(com->ioc);
32 
33     pci_dev = com->dev;
34     for (; !local_err;) {
35         MPQemuMsg msg = {0};
36 
37         if (!mpqemu_msg_recv(&msg, com->ioc, &local_err)) {
38             break;
39         }
40 
41         if (!mpqemu_msg_valid(&msg)) {
42             error_setg(&local_err, "Received invalid message from proxy"
43                                    "in remote process pid="FMT_pid"",
44                                    getpid());
45             break;
46         }
47 
48         switch (msg.cmd) {
49         case MPQEMU_CMD_PCI_CFGWRITE:
50             process_config_write(com->ioc, pci_dev, &msg, &local_err);
51             break;
52         case MPQEMU_CMD_PCI_CFGREAD:
53             process_config_read(com->ioc, pci_dev, &msg, &local_err);
54             break;
55         default:
56             error_setg(&local_err,
57                        "Unknown command (%d) received for device %s"
58                        " (pid="FMT_pid")",
59                        msg.cmd, DEVICE(pci_dev)->id, getpid());
60         }
61     }
62 
63     if (local_err) {
64         error_report_err(local_err);
65         qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_ERROR);
66     } else {
67         qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
68     }
69 }
70 
71 static void process_config_write(QIOChannel *ioc, PCIDevice *dev,
72                                  MPQemuMsg *msg, Error **errp)
73 {
74     ERRP_GUARD();
75     PciConfDataMsg *conf = (PciConfDataMsg *)&msg->data.pci_conf_data;
76     MPQemuMsg ret = { 0 };
77 
78     if ((conf->addr + sizeof(conf->val)) > pci_config_size(dev)) {
79         error_setg(errp, "Bad address for PCI config write, pid "FMT_pid".",
80                    getpid());
81         ret.data.u64 = UINT64_MAX;
82     } else {
83         pci_default_write_config(dev, conf->addr, conf->val, conf->len);
84     }
85 
86     ret.cmd = MPQEMU_CMD_RET;
87     ret.size = sizeof(ret.data.u64);
88 
89     if (!mpqemu_msg_send(&ret, ioc, NULL)) {
90         error_prepend(errp, "Error returning code to proxy, pid "FMT_pid": ",
91                       getpid());
92     }
93 }
94 
95 static void process_config_read(QIOChannel *ioc, PCIDevice *dev,
96                                 MPQemuMsg *msg, Error **errp)
97 {
98     ERRP_GUARD();
99     PciConfDataMsg *conf = (PciConfDataMsg *)&msg->data.pci_conf_data;
100     MPQemuMsg ret = { 0 };
101 
102     if ((conf->addr + sizeof(conf->val)) > pci_config_size(dev)) {
103         error_setg(errp, "Bad address for PCI config read, pid "FMT_pid".",
104                    getpid());
105         ret.data.u64 = UINT64_MAX;
106     } else {
107         ret.data.u64 = pci_default_read_config(dev, conf->addr, conf->len);
108     }
109 
110     ret.cmd = MPQEMU_CMD_RET;
111     ret.size = sizeof(ret.data.u64);
112 
113     if (!mpqemu_msg_send(&ret, ioc, NULL)) {
114         error_prepend(errp, "Error returning code to proxy, pid "FMT_pid": ",
115                       getpid());
116     }
117 }
118