Message ID | 67d558deedfeb3d331e013edd857b2d193e8617e.1606853298.git.jag.raman@oracle.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Initial support for multi-process Qemu | expand |
Hi On Wed, Dec 2, 2020 at 12:25 AM Jagannathan Raman <jag.raman@oracle.com> wrote: > From: Elena Ufimtseva <elena.ufimtseva@oracle.com> > > The Proxy Object sends the PCI config space accesses as messages > to the remote process over the communication channel > > Signed-off-by: Elena Ufimtseva <elena.ufimtseva@oracle.com> > Signed-off-by: Jagannathan Raman <jag.raman@oracle.com> > Signed-off-by: John G Johnson <john.g.johnson@oracle.com> > Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> > --- > include/hw/remote/mpqemu-link.h | 9 ++++++ > hw/remote/message.c | 62 > +++++++++++++++++++++++++++++++++++++++++ > hw/remote/mpqemu-link.c | 6 ++++ > hw/remote/proxy.c | 51 +++++++++++++++++++++++++++++++++ > 4 files changed, 128 insertions(+) > > diff --git a/include/hw/remote/mpqemu-link.h > b/include/hw/remote/mpqemu-link.h > index cee9468..057c98b 100644 > --- a/include/hw/remote/mpqemu-link.h > +++ b/include/hw/remote/mpqemu-link.h > @@ -34,6 +34,8 @@ typedef enum { > MPQEMU_CMD_INIT, > SYNC_SYSMEM, > RET_MSG, > + PCI_CONFIG_WRITE, > + PCI_CONFIG_READ, > MPQEMU_CMD_MAX, > It would be a good idea to prefix all enums with MQEMU_CMD. } MPQemuCmd; > > @@ -43,6 +45,12 @@ typedef struct { > off_t offsets[REMOTE_MAX_FDS]; > } SyncSysmemMsg; > > +typedef struct { > + uint32_t addr; > + uint32_t val; > + int l; > "len" please, it's already short enough :) +} PciConfDataMsg; > + > /** > * MPQemuMsg: > * @cmd: The remote command > @@ -60,6 +68,7 @@ typedef struct { > > union { > uint64_t u64; > + PciConfDataMsg pci_conf_data; > SyncSysmemMsg sync_sysmem; > } data; > > diff --git a/hw/remote/message.c b/hw/remote/message.c > index 1f2edc7..52a6f6f 100644 > --- a/hw/remote/message.c > +++ b/hw/remote/message.c > @@ -15,6 +15,12 @@ > #include "hw/remote/mpqemu-link.h" > #include "qapi/error.h" > #include "sysemu/runstate.h" > +#include "hw/pci/pci.h" > + > +static void process_config_write(QIOChannel *ioc, PCIDevice *dev, > + MPQemuMsg *msg); > +static void process_config_read(QIOChannel *ioc, PCIDevice *dev, > + MPQemuMsg *msg); > > void coroutine_fn mpqemu_remote_msg_loop_co(void *data) > { > @@ -43,6 +49,12 @@ void coroutine_fn mpqemu_remote_msg_loop_co(void *data) > } > > switch (msg.cmd) { > + case PCI_CONFIG_WRITE: > + process_config_write(com->ioc, pci_dev, &msg); > + break; > Some other process_ functions take &local_err. I think this is a better idea, so error reporting is done in a single place from mpqemu_remote_msg_loop_co() for now + case PCI_CONFIG_READ: > + process_config_read(com->ioc, pci_dev, &msg); > + break; > default: > error_setg(&local_err, > "Unknown command (%d) received for device %s > (pid=%d)", > @@ -60,3 +72,53 @@ void coroutine_fn mpqemu_remote_msg_loop_co(void *data) > > return; > } > + > +static void process_config_write(QIOChannel *ioc, PCIDevice *dev, > + MPQemuMsg *msg) > +{ > + PciConfDataMsg *conf = (PciConfDataMsg *)&msg->data.pci_conf_data; > + MPQemuMsg ret = { 0 }; > + Error *local_err = NULL; > + > + if ((conf->addr + sizeof(conf->val)) > pci_config_size(dev)) { > + error_report("Bad address received when writing PCI config, pid > %d", > + getpid()); > Should use FMT_pid. But then, I am not sure some error messages should have PID, while most of them dont. That should be either the job of a log manager, or a custom logger function/option. + ret.data.u64 = UINT64_MAX; > + } else { > + pci_default_write_config(dev, conf->addr, conf->val, conf->l); > + } > + > + ret.cmd = RET_MSG; > + ret.size = sizeof(ret.data.u64); > + > + mpqemu_msg_send(&ret, ioc, &local_err); > + if (local_err) { > + error_report("Could not send message to proxy from pid %d", > + getpid()); > Here it leaks local_err, and ignores it. Use error_prepend instead? + } > +} > + > +static void process_config_read(QIOChannel *ioc, PCIDevice *dev, > + MPQemuMsg *msg) > +{ > + PciConfDataMsg *conf = (PciConfDataMsg *)&msg->data.pci_conf_data; > + MPQemuMsg ret = { 0 }; > + Error *local_err = NULL; > + > + if ((conf->addr + sizeof(conf->val)) > pci_config_size(dev)) { > + error_report("Bad address received when reading PCI config, pid > %d", > + getpid()); > + ret.data.u64 = UINT64_MAX; > + } else { > + ret.data.u64 = pci_default_read_config(dev, conf->addr, conf->l); > + } > + > + ret.cmd = RET_MSG; > + ret.size = sizeof(ret.data.u64); > + > + mpqemu_msg_send(&ret, ioc, &local_err); > + if (local_err) { > + error_report("Could not send message to proxy from pid %d", > + getpid()); > Same as earlier + } > +} > diff --git a/hw/remote/mpqemu-link.c b/hw/remote/mpqemu-link.c > index 18c8a54..83dbd65 100644 > --- a/hw/remote/mpqemu-link.c > +++ b/hw/remote/mpqemu-link.c > @@ -283,6 +283,12 @@ bool mpqemu_msg_valid(MPQemuMsg *msg) > return false; > } > break; > + case PCI_CONFIG_WRITE: > + case PCI_CONFIG_READ: > + if (msg->size != sizeof(PciConfDataMsg)) { > + return false; > + } > + break; > default: > break; > } > diff --git a/hw/remote/proxy.c b/hw/remote/proxy.c > index 29100bc..c193484 100644 > --- a/hw/remote/proxy.c > +++ b/hw/remote/proxy.c > @@ -16,6 +16,8 @@ > #include "hw/qdev-properties.h" > #include "monitor/monitor.h" > #include "migration/blocker.h" > +#include "hw/remote/mpqemu-link.h" > +#include "qemu/error-report.h" > > static void proxy_set_socket(PCIProxyDev *pdev, int fd, Error **errp) > { > @@ -69,6 +71,52 @@ static void pci_proxy_dev_exit(PCIDevice *pdev) > error_free(dev->migration_blocker); > } > > +static int config_op_send(PCIProxyDev *pdev, uint32_t addr, uint32_t *val, > + int l, unsigned int op) > +{ > + MPQemuMsg msg = { 0 }; > + uint64_t ret = -EINVAL; > + Error *local_err = NULL; > + > + msg.cmd = op; > + msg.data.pci_conf_data.addr = addr; > + msg.data.pci_conf_data.val = (op == PCI_CONFIG_WRITE) ? *val : 0; > + msg.data.pci_conf_data.l = l; > + msg.size = sizeof(PciConfDataMsg); > + > + ret = mpqemu_msg_send_and_await_reply(&msg, pdev, &local_err); > + if (local_err) { > + error_report_err(local_err); > + } > + if (op == PCI_CONFIG_READ) { > + *val = (uint32_t)ret; > That's a suspicious cast, without error checking. + } > + > + return ret; > +} > + > +static uint32_t pci_proxy_read_config(PCIDevice *d, uint32_t addr, int > len) > +{ > + uint32_t val; > + > + (void)config_op_send(PCI_PROXY_DEV(d), addr, &val, len, > PCI_CONFIG_READ); > I don't know why (void)cast here, please enlighten me + > + return val; > +} > + > +static void pci_proxy_write_config(PCIDevice *d, uint32_t addr, uint32_t > val, > + int l) > +{ > + /* > + * Some of the functions access the copy of remote device's PCI config > + * space which is cached in the proxy device. Therefore, maintain > + * it updated. > + */ > + pci_default_write_config(d, addr, val, l); > + > + (void)config_op_send(PCI_PROXY_DEV(d), addr, &val, l, > PCI_CONFIG_WRITE); > again +} > + > static void pci_proxy_dev_class_init(ObjectClass *klass, void *data) > { > DeviceClass *dc = DEVICE_CLASS(klass); > @@ -76,6 +124,9 @@ static void pci_proxy_dev_class_init(ObjectClass > *klass, void *data) > > k->realize = pci_proxy_dev_realize; > k->exit = pci_proxy_dev_exit; > + k->config_read = pci_proxy_read_config; > + k->config_write = pci_proxy_write_config; > + > device_class_set_props(dc, proxy_properties); > } > > -- > 1.8.3.1 > >
diff --git a/include/hw/remote/mpqemu-link.h b/include/hw/remote/mpqemu-link.h index cee9468..057c98b 100644 --- a/include/hw/remote/mpqemu-link.h +++ b/include/hw/remote/mpqemu-link.h @@ -34,6 +34,8 @@ typedef enum { MPQEMU_CMD_INIT, SYNC_SYSMEM, RET_MSG, + PCI_CONFIG_WRITE, + PCI_CONFIG_READ, MPQEMU_CMD_MAX, } MPQemuCmd; @@ -43,6 +45,12 @@ typedef struct { off_t offsets[REMOTE_MAX_FDS]; } SyncSysmemMsg; +typedef struct { + uint32_t addr; + uint32_t val; + int l; +} PciConfDataMsg; + /** * MPQemuMsg: * @cmd: The remote command @@ -60,6 +68,7 @@ typedef struct { union { uint64_t u64; + PciConfDataMsg pci_conf_data; SyncSysmemMsg sync_sysmem; } data; diff --git a/hw/remote/message.c b/hw/remote/message.c index 1f2edc7..52a6f6f 100644 --- a/hw/remote/message.c +++ b/hw/remote/message.c @@ -15,6 +15,12 @@ #include "hw/remote/mpqemu-link.h" #include "qapi/error.h" #include "sysemu/runstate.h" +#include "hw/pci/pci.h" + +static void process_config_write(QIOChannel *ioc, PCIDevice *dev, + MPQemuMsg *msg); +static void process_config_read(QIOChannel *ioc, PCIDevice *dev, + MPQemuMsg *msg); void coroutine_fn mpqemu_remote_msg_loop_co(void *data) { @@ -43,6 +49,12 @@ void coroutine_fn mpqemu_remote_msg_loop_co(void *data) } switch (msg.cmd) { + case PCI_CONFIG_WRITE: + process_config_write(com->ioc, pci_dev, &msg); + break; + case PCI_CONFIG_READ: + process_config_read(com->ioc, pci_dev, &msg); + break; default: error_setg(&local_err, "Unknown command (%d) received for device %s (pid=%d)", @@ -60,3 +72,53 @@ void coroutine_fn mpqemu_remote_msg_loop_co(void *data) return; } + +static void process_config_write(QIOChannel *ioc, PCIDevice *dev, + MPQemuMsg *msg) +{ + PciConfDataMsg *conf = (PciConfDataMsg *)&msg->data.pci_conf_data; + MPQemuMsg ret = { 0 }; + Error *local_err = NULL; + + if ((conf->addr + sizeof(conf->val)) > pci_config_size(dev)) { + error_report("Bad address received when writing PCI config, pid %d", + getpid()); + ret.data.u64 = UINT64_MAX; + } else { + pci_default_write_config(dev, conf->addr, conf->val, conf->l); + } + + ret.cmd = RET_MSG; + ret.size = sizeof(ret.data.u64); + + mpqemu_msg_send(&ret, ioc, &local_err); + if (local_err) { + error_report("Could not send message to proxy from pid %d", + getpid()); + } +} + +static void process_config_read(QIOChannel *ioc, PCIDevice *dev, + MPQemuMsg *msg) +{ + PciConfDataMsg *conf = (PciConfDataMsg *)&msg->data.pci_conf_data; + MPQemuMsg ret = { 0 }; + Error *local_err = NULL; + + if ((conf->addr + sizeof(conf->val)) > pci_config_size(dev)) { + error_report("Bad address received when reading PCI config, pid %d", + getpid()); + ret.data.u64 = UINT64_MAX; + } else { + ret.data.u64 = pci_default_read_config(dev, conf->addr, conf->l); + } + + ret.cmd = RET_MSG; + ret.size = sizeof(ret.data.u64); + + mpqemu_msg_send(&ret, ioc, &local_err); + if (local_err) { + error_report("Could not send message to proxy from pid %d", + getpid()); + } +} diff --git a/hw/remote/mpqemu-link.c b/hw/remote/mpqemu-link.c index 18c8a54..83dbd65 100644 --- a/hw/remote/mpqemu-link.c +++ b/hw/remote/mpqemu-link.c @@ -283,6 +283,12 @@ bool mpqemu_msg_valid(MPQemuMsg *msg) return false; } break; + case PCI_CONFIG_WRITE: + case PCI_CONFIG_READ: + if (msg->size != sizeof(PciConfDataMsg)) { + return false; + } + break; default: break; } diff --git a/hw/remote/proxy.c b/hw/remote/proxy.c index 29100bc..c193484 100644 --- a/hw/remote/proxy.c +++ b/hw/remote/proxy.c @@ -16,6 +16,8 @@ #include "hw/qdev-properties.h" #include "monitor/monitor.h" #include "migration/blocker.h" +#include "hw/remote/mpqemu-link.h" +#include "qemu/error-report.h" static void proxy_set_socket(PCIProxyDev *pdev, int fd, Error **errp) { @@ -69,6 +71,52 @@ static void pci_proxy_dev_exit(PCIDevice *pdev) error_free(dev->migration_blocker); } +static int config_op_send(PCIProxyDev *pdev, uint32_t addr, uint32_t *val, + int l, unsigned int op) +{ + MPQemuMsg msg = { 0 }; + uint64_t ret = -EINVAL; + Error *local_err = NULL; + + msg.cmd = op; + msg.data.pci_conf_data.addr = addr; + msg.data.pci_conf_data.val = (op == PCI_CONFIG_WRITE) ? *val : 0; + msg.data.pci_conf_data.l = l; + msg.size = sizeof(PciConfDataMsg); + + ret = mpqemu_msg_send_and_await_reply(&msg, pdev, &local_err); + if (local_err) { + error_report_err(local_err); + } + if (op == PCI_CONFIG_READ) { + *val = (uint32_t)ret; + } + + return ret; +} + +static uint32_t pci_proxy_read_config(PCIDevice *d, uint32_t addr, int len) +{ + uint32_t val; + + (void)config_op_send(PCI_PROXY_DEV(d), addr, &val, len, PCI_CONFIG_READ); + + return val; +} + +static void pci_proxy_write_config(PCIDevice *d, uint32_t addr, uint32_t val, + int l) +{ + /* + * Some of the functions access the copy of remote device's PCI config + * space which is cached in the proxy device. Therefore, maintain + * it updated. + */ + pci_default_write_config(d, addr, val, l); + + (void)config_op_send(PCI_PROXY_DEV(d), addr, &val, l, PCI_CONFIG_WRITE); +} + static void pci_proxy_dev_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -76,6 +124,9 @@ static void pci_proxy_dev_class_init(ObjectClass *klass, void *data) k->realize = pci_proxy_dev_realize; k->exit = pci_proxy_dev_exit; + k->config_read = pci_proxy_read_config; + k->config_write = pci_proxy_write_config; + device_class_set_props(dc, proxy_properties); }