qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

message.c (7037B)


      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 }