xref: /openbmc/qemu/hw/remote/message.c (revision 76277cf82f0e1123bd69ec59d22014b8f78485ec)
148b06f50SJagannathan Raman /*
248b06f50SJagannathan Raman  * Copyright © 2020, 2021 Oracle and/or its affiliates.
348b06f50SJagannathan Raman  *
448b06f50SJagannathan Raman  * This work is licensed under the terms of the GNU GPL-v2, version 2 or later.
548b06f50SJagannathan Raman  *
648b06f50SJagannathan Raman  * See the COPYING file in the top-level directory.
748b06f50SJagannathan Raman  *
848b06f50SJagannathan Raman  */
948b06f50SJagannathan Raman 
1048b06f50SJagannathan Raman #include "qemu/osdep.h"
1148b06f50SJagannathan Raman 
1248b06f50SJagannathan Raman #include "hw/remote/machine.h"
1348b06f50SJagannathan Raman #include "io/channel.h"
1448b06f50SJagannathan Raman #include "hw/remote/mpqemu-link.h"
1548b06f50SJagannathan Raman #include "qapi/error.h"
1648b06f50SJagannathan Raman #include "sysemu/runstate.h"
1711ab8725SElena Ufimtseva #include "hw/pci/pci.h"
187ee3f823SJagannathan Raman #include "exec/memattrs.h"
19c746b74aSJagannathan Raman #include "hw/remote/memory.h"
20bd36adb8SJagannathan Raman #include "hw/remote/iohub.h"
21b6cc02d9SElena Ufimtseva #include "sysemu/reset.h"
2211ab8725SElena Ufimtseva 
2311ab8725SElena Ufimtseva static void process_config_write(QIOChannel *ioc, PCIDevice *dev,
2411ab8725SElena Ufimtseva                                  MPQemuMsg *msg, Error **errp);
2511ab8725SElena Ufimtseva static void process_config_read(QIOChannel *ioc, PCIDevice *dev,
2611ab8725SElena Ufimtseva                                 MPQemuMsg *msg, Error **errp);
277ee3f823SJagannathan Raman static void process_bar_write(QIOChannel *ioc, MPQemuMsg *msg, Error **errp);
287ee3f823SJagannathan Raman static void process_bar_read(QIOChannel *ioc, MPQemuMsg *msg, Error **errp);
29b6cc02d9SElena Ufimtseva static void process_device_reset_msg(QIOChannel *ioc, PCIDevice *dev,
30b6cc02d9SElena Ufimtseva                                      Error **errp);
3148b06f50SJagannathan Raman 
mpqemu_remote_msg_loop_co(void * data)3248b06f50SJagannathan Raman void coroutine_fn mpqemu_remote_msg_loop_co(void *data)
3348b06f50SJagannathan Raman {
3448b06f50SJagannathan Raman     g_autofree RemoteCommDev *com = (RemoteCommDev *)data;
3548b06f50SJagannathan Raman     PCIDevice *pci_dev = NULL;
3648b06f50SJagannathan Raman     Error *local_err = NULL;
3748b06f50SJagannathan Raman 
3848b06f50SJagannathan Raman     assert(com->ioc);
3948b06f50SJagannathan Raman 
4048b06f50SJagannathan Raman     pci_dev = com->dev;
4148b06f50SJagannathan Raman     for (; !local_err;) {
4248b06f50SJagannathan Raman         MPQemuMsg msg = {0};
4348b06f50SJagannathan Raman 
4448b06f50SJagannathan Raman         if (!mpqemu_msg_recv(&msg, com->ioc, &local_err)) {
4548b06f50SJagannathan Raman             break;
4648b06f50SJagannathan Raman         }
4748b06f50SJagannathan Raman 
4848b06f50SJagannathan Raman         if (!mpqemu_msg_valid(&msg)) {
4948b06f50SJagannathan Raman             error_setg(&local_err, "Received invalid message from proxy"
5048b06f50SJagannathan Raman                                    "in remote process pid="FMT_pid"",
5148b06f50SJagannathan Raman                                    getpid());
5248b06f50SJagannathan Raman             break;
5348b06f50SJagannathan Raman         }
5448b06f50SJagannathan Raman 
5548b06f50SJagannathan Raman         switch (msg.cmd) {
5611ab8725SElena Ufimtseva         case MPQEMU_CMD_PCI_CFGWRITE:
5711ab8725SElena Ufimtseva             process_config_write(com->ioc, pci_dev, &msg, &local_err);
5811ab8725SElena Ufimtseva             break;
5911ab8725SElena Ufimtseva         case MPQEMU_CMD_PCI_CFGREAD:
6011ab8725SElena Ufimtseva             process_config_read(com->ioc, pci_dev, &msg, &local_err);
6111ab8725SElena Ufimtseva             break;
627ee3f823SJagannathan Raman         case MPQEMU_CMD_BAR_WRITE:
637ee3f823SJagannathan Raman             process_bar_write(com->ioc, &msg, &local_err);
647ee3f823SJagannathan Raman             break;
657ee3f823SJagannathan Raman         case MPQEMU_CMD_BAR_READ:
667ee3f823SJagannathan Raman             process_bar_read(com->ioc, &msg, &local_err);
677ee3f823SJagannathan Raman             break;
68c746b74aSJagannathan Raman         case MPQEMU_CMD_SYNC_SYSMEM:
69c746b74aSJagannathan Raman             remote_sysmem_reconfig(&msg, &local_err);
70c746b74aSJagannathan Raman             break;
71bd36adb8SJagannathan Raman         case MPQEMU_CMD_SET_IRQFD:
72bd36adb8SJagannathan Raman             process_set_irqfd_msg(pci_dev, &msg);
73bd36adb8SJagannathan Raman             break;
74b6cc02d9SElena Ufimtseva         case MPQEMU_CMD_DEVICE_RESET:
75b6cc02d9SElena Ufimtseva             process_device_reset_msg(com->ioc, pci_dev, &local_err);
76b6cc02d9SElena Ufimtseva             break;
7748b06f50SJagannathan Raman         default:
7848b06f50SJagannathan Raman             error_setg(&local_err,
7948b06f50SJagannathan Raman                        "Unknown command (%d) received for device %s"
8048b06f50SJagannathan Raman                        " (pid="FMT_pid")",
8148b06f50SJagannathan Raman                        msg.cmd, DEVICE(pci_dev)->id, getpid());
8248b06f50SJagannathan Raman         }
8348b06f50SJagannathan Raman     }
8448b06f50SJagannathan Raman 
8548b06f50SJagannathan Raman     if (local_err) {
8648b06f50SJagannathan Raman         error_report_err(local_err);
8748b06f50SJagannathan Raman         qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_ERROR);
8848b06f50SJagannathan Raman     } else {
8948b06f50SJagannathan Raman         qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
9048b06f50SJagannathan Raman     }
9148b06f50SJagannathan Raman }
9211ab8725SElena Ufimtseva 
process_config_write(QIOChannel * ioc,PCIDevice * dev,MPQemuMsg * msg,Error ** errp)9311ab8725SElena Ufimtseva static void process_config_write(QIOChannel *ioc, PCIDevice *dev,
9411ab8725SElena Ufimtseva                                  MPQemuMsg *msg, Error **errp)
9511ab8725SElena Ufimtseva {
9611ab8725SElena Ufimtseva     ERRP_GUARD();
9711ab8725SElena Ufimtseva     PciConfDataMsg *conf = (PciConfDataMsg *)&msg->data.pci_conf_data;
9811ab8725SElena Ufimtseva     MPQemuMsg ret = { 0 };
9911ab8725SElena Ufimtseva 
10011ab8725SElena Ufimtseva     if ((conf->addr + sizeof(conf->val)) > pci_config_size(dev)) {
10111ab8725SElena Ufimtseva         error_setg(errp, "Bad address for PCI config write, pid "FMT_pid".",
10211ab8725SElena Ufimtseva                    getpid());
10311ab8725SElena Ufimtseva         ret.data.u64 = UINT64_MAX;
10411ab8725SElena Ufimtseva     } else {
10511ab8725SElena Ufimtseva         pci_default_write_config(dev, conf->addr, conf->val, conf->len);
10611ab8725SElena Ufimtseva     }
10711ab8725SElena Ufimtseva 
10811ab8725SElena Ufimtseva     ret.cmd = MPQEMU_CMD_RET;
10911ab8725SElena Ufimtseva     ret.size = sizeof(ret.data.u64);
11011ab8725SElena Ufimtseva 
11111ab8725SElena Ufimtseva     if (!mpqemu_msg_send(&ret, ioc, NULL)) {
11211ab8725SElena Ufimtseva         error_prepend(errp, "Error returning code to proxy, pid "FMT_pid": ",
11311ab8725SElena Ufimtseva                       getpid());
11411ab8725SElena Ufimtseva     }
11511ab8725SElena Ufimtseva }
11611ab8725SElena Ufimtseva 
process_config_read(QIOChannel * ioc,PCIDevice * dev,MPQemuMsg * msg,Error ** errp)11711ab8725SElena Ufimtseva static void process_config_read(QIOChannel *ioc, PCIDevice *dev,
11811ab8725SElena Ufimtseva                                 MPQemuMsg *msg, Error **errp)
11911ab8725SElena Ufimtseva {
12011ab8725SElena Ufimtseva     ERRP_GUARD();
12111ab8725SElena Ufimtseva     PciConfDataMsg *conf = (PciConfDataMsg *)&msg->data.pci_conf_data;
12211ab8725SElena Ufimtseva     MPQemuMsg ret = { 0 };
12311ab8725SElena Ufimtseva 
12411ab8725SElena Ufimtseva     if ((conf->addr + sizeof(conf->val)) > pci_config_size(dev)) {
12511ab8725SElena Ufimtseva         error_setg(errp, "Bad address for PCI config read, pid "FMT_pid".",
12611ab8725SElena Ufimtseva                    getpid());
12711ab8725SElena Ufimtseva         ret.data.u64 = UINT64_MAX;
12811ab8725SElena Ufimtseva     } else {
12911ab8725SElena Ufimtseva         ret.data.u64 = pci_default_read_config(dev, conf->addr, conf->len);
13011ab8725SElena Ufimtseva     }
13111ab8725SElena Ufimtseva 
13211ab8725SElena Ufimtseva     ret.cmd = MPQEMU_CMD_RET;
13311ab8725SElena Ufimtseva     ret.size = sizeof(ret.data.u64);
13411ab8725SElena Ufimtseva 
13511ab8725SElena Ufimtseva     if (!mpqemu_msg_send(&ret, ioc, NULL)) {
13611ab8725SElena Ufimtseva         error_prepend(errp, "Error returning code to proxy, pid "FMT_pid": ",
13711ab8725SElena Ufimtseva                       getpid());
13811ab8725SElena Ufimtseva     }
13911ab8725SElena Ufimtseva }
1407ee3f823SJagannathan Raman 
process_bar_write(QIOChannel * ioc,MPQemuMsg * msg,Error ** errp)1417ee3f823SJagannathan Raman static void process_bar_write(QIOChannel *ioc, MPQemuMsg *msg, Error **errp)
1427ee3f823SJagannathan Raman {
1437ee3f823SJagannathan Raman     ERRP_GUARD();
1447ee3f823SJagannathan Raman     BarAccessMsg *bar_access = &msg->data.bar_access;
1457ee3f823SJagannathan Raman     AddressSpace *as =
1467ee3f823SJagannathan Raman         bar_access->memory ? &address_space_memory : &address_space_io;
1477ee3f823SJagannathan Raman     MPQemuMsg ret = { 0 };
1487ee3f823SJagannathan Raman     MemTxResult res;
1497ee3f823SJagannathan Raman     uint64_t val;
1507ee3f823SJagannathan Raman 
1517ee3f823SJagannathan Raman     if (!is_power_of_2(bar_access->size) ||
1527ee3f823SJagannathan Raman        (bar_access->size > sizeof(uint64_t))) {
1537ee3f823SJagannathan Raman         ret.data.u64 = UINT64_MAX;
1547ee3f823SJagannathan Raman         goto fail;
1557ee3f823SJagannathan Raman     }
1567ee3f823SJagannathan Raman 
1577ee3f823SJagannathan Raman     val = cpu_to_le64(bar_access->val);
1587ee3f823SJagannathan Raman 
1597ee3f823SJagannathan Raman     res = address_space_rw(as, bar_access->addr, MEMTXATTRS_UNSPECIFIED,
1607ee3f823SJagannathan Raman                            (void *)&val, bar_access->size, true);
1617ee3f823SJagannathan Raman 
1627ee3f823SJagannathan Raman     if (res != MEMTX_OK) {
1637ee3f823SJagannathan Raman         error_setg(errp, "Bad address %"PRIx64" for mem write, pid "FMT_pid".",
1647ee3f823SJagannathan Raman                    bar_access->addr, getpid());
1657ee3f823SJagannathan Raman         ret.data.u64 = -1;
1667ee3f823SJagannathan Raman     }
1677ee3f823SJagannathan Raman 
1687ee3f823SJagannathan Raman fail:
1697ee3f823SJagannathan Raman     ret.cmd = MPQEMU_CMD_RET;
1707ee3f823SJagannathan Raman     ret.size = sizeof(ret.data.u64);
1717ee3f823SJagannathan Raman 
1727ee3f823SJagannathan Raman     if (!mpqemu_msg_send(&ret, ioc, NULL)) {
1737ee3f823SJagannathan Raman         error_prepend(errp, "Error returning code to proxy, pid "FMT_pid": ",
1747ee3f823SJagannathan Raman                       getpid());
1757ee3f823SJagannathan Raman     }
1767ee3f823SJagannathan Raman }
1777ee3f823SJagannathan Raman 
process_bar_read(QIOChannel * ioc,MPQemuMsg * msg,Error ** errp)1787ee3f823SJagannathan Raman static void process_bar_read(QIOChannel *ioc, MPQemuMsg *msg, Error **errp)
1797ee3f823SJagannathan Raman {
1807ee3f823SJagannathan Raman     ERRP_GUARD();
1817ee3f823SJagannathan Raman     BarAccessMsg *bar_access = &msg->data.bar_access;
1827ee3f823SJagannathan Raman     MPQemuMsg ret = { 0 };
1837ee3f823SJagannathan Raman     AddressSpace *as;
1847ee3f823SJagannathan Raman     MemTxResult res;
1857ee3f823SJagannathan Raman     uint64_t val = 0;
1867ee3f823SJagannathan Raman 
1877ee3f823SJagannathan Raman     as = bar_access->memory ? &address_space_memory : &address_space_io;
1887ee3f823SJagannathan Raman 
1897ee3f823SJagannathan Raman     if (!is_power_of_2(bar_access->size) ||
1907ee3f823SJagannathan Raman        (bar_access->size > sizeof(uint64_t))) {
1917ee3f823SJagannathan Raman         val = UINT64_MAX;
1927ee3f823SJagannathan Raman         goto fail;
1937ee3f823SJagannathan Raman     }
1947ee3f823SJagannathan Raman 
1957ee3f823SJagannathan Raman     res = address_space_rw(as, bar_access->addr, MEMTXATTRS_UNSPECIFIED,
1967ee3f823SJagannathan Raman                            (void *)&val, bar_access->size, false);
1977ee3f823SJagannathan Raman 
1987ee3f823SJagannathan Raman     if (res != MEMTX_OK) {
1997ee3f823SJagannathan Raman         error_setg(errp, "Bad address %"PRIx64" for mem read, pid "FMT_pid".",
2007ee3f823SJagannathan Raman                    bar_access->addr, getpid());
2017ee3f823SJagannathan Raman         val = UINT64_MAX;
2027ee3f823SJagannathan Raman     }
2037ee3f823SJagannathan Raman 
2047ee3f823SJagannathan Raman fail:
2057ee3f823SJagannathan Raman     ret.cmd = MPQEMU_CMD_RET;
2067ee3f823SJagannathan Raman     ret.data.u64 = le64_to_cpu(val);
2077ee3f823SJagannathan Raman     ret.size = sizeof(ret.data.u64);
2087ee3f823SJagannathan Raman 
2097ee3f823SJagannathan Raman     if (!mpqemu_msg_send(&ret, ioc, NULL)) {
2107ee3f823SJagannathan Raman         error_prepend(errp, "Error returning code to proxy, pid "FMT_pid": ",
2117ee3f823SJagannathan Raman                       getpid());
2127ee3f823SJagannathan Raman     }
2137ee3f823SJagannathan Raman }
214b6cc02d9SElena Ufimtseva 
process_device_reset_msg(QIOChannel * ioc,PCIDevice * dev,Error ** errp)215b6cc02d9SElena Ufimtseva static void process_device_reset_msg(QIOChannel *ioc, PCIDevice *dev,
216b6cc02d9SElena Ufimtseva                                      Error **errp)
217b6cc02d9SElena Ufimtseva {
218b6cc02d9SElena Ufimtseva     DeviceState *s = DEVICE(dev);
219b6cc02d9SElena Ufimtseva     MPQemuMsg ret = { 0 };
220b6cc02d9SElena Ufimtseva 
221*7d3a421fSPeter Maydell     device_cold_reset(s);
222b6cc02d9SElena Ufimtseva 
223b6cc02d9SElena Ufimtseva     ret.cmd = MPQEMU_CMD_RET;
224b6cc02d9SElena Ufimtseva 
225b6cc02d9SElena Ufimtseva     mpqemu_msg_send(&ret, ioc, errp);
226b6cc02d9SElena Ufimtseva }
227