Skip to content

Commit

Permalink
multi-process: Forward PCI config space acceses to the remote process
Browse files Browse the repository at this point in the history
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>
Message-id: d3c94f4618813234655356c60e6f0d0362ff42d6.1611938319.git.jag.raman@oracle.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
  • Loading branch information
elena-ufimtseva authored and stefanhaRH committed Feb 10, 2021
1 parent e7b2c9e commit 11ab872
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 1 deletion.
60 changes: 60 additions & 0 deletions hw/remote/message.c
Expand Up @@ -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, Error **errp);
static void process_config_read(QIOChannel *ioc, PCIDevice *dev,
MPQemuMsg *msg, Error **errp);

void coroutine_fn mpqemu_remote_msg_loop_co(void *data)
{
Expand All @@ -40,6 +46,12 @@ void coroutine_fn mpqemu_remote_msg_loop_co(void *data)
}

switch (msg.cmd) {
case MPQEMU_CMD_PCI_CFGWRITE:
process_config_write(com->ioc, pci_dev, &msg, &local_err);
break;
case MPQEMU_CMD_PCI_CFGREAD:
process_config_read(com->ioc, pci_dev, &msg, &local_err);
break;
default:
error_setg(&local_err,
"Unknown command (%d) received for device %s"
Expand All @@ -55,3 +67,51 @@ void coroutine_fn mpqemu_remote_msg_loop_co(void *data)
qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
}
}

static void process_config_write(QIOChannel *ioc, PCIDevice *dev,
MPQemuMsg *msg, Error **errp)
{
ERRP_GUARD();
PciConfDataMsg *conf = (PciConfDataMsg *)&msg->data.pci_conf_data;
MPQemuMsg ret = { 0 };

if ((conf->addr + sizeof(conf->val)) > pci_config_size(dev)) {
error_setg(errp, "Bad address for PCI config write, pid "FMT_pid".",
getpid());
ret.data.u64 = UINT64_MAX;
} else {
pci_default_write_config(dev, conf->addr, conf->val, conf->len);
}

ret.cmd = MPQEMU_CMD_RET;
ret.size = sizeof(ret.data.u64);

if (!mpqemu_msg_send(&ret, ioc, NULL)) {
error_prepend(errp, "Error returning code to proxy, pid "FMT_pid": ",
getpid());
}
}

static void process_config_read(QIOChannel *ioc, PCIDevice *dev,
MPQemuMsg *msg, Error **errp)
{
ERRP_GUARD();
PciConfDataMsg *conf = (PciConfDataMsg *)&msg->data.pci_conf_data;
MPQemuMsg ret = { 0 };

if ((conf->addr + sizeof(conf->val)) > pci_config_size(dev)) {
error_setg(errp, "Bad address for PCI config read, pid "FMT_pid".",
getpid());
ret.data.u64 = UINT64_MAX;
} else {
ret.data.u64 = pci_default_read_config(dev, conf->addr, conf->len);
}

ret.cmd = MPQEMU_CMD_RET;
ret.size = sizeof(ret.data.u64);

if (!mpqemu_msg_send(&ret, ioc, NULL)) {
error_prepend(errp, "Error returning code to proxy, pid "FMT_pid": ",
getpid());
}
}
8 changes: 7 additions & 1 deletion hw/remote/mpqemu-link.c
Expand Up @@ -207,7 +207,7 @@ uint64_t mpqemu_msg_send_and_await_reply(MPQemuMsg *msg, PCIProxyDev *pdev,
return ret;
}

if (!mpqemu_msg_valid(&msg_reply)) {
if (!mpqemu_msg_valid(&msg_reply) || msg_reply.cmd != MPQEMU_CMD_RET) {
error_setg(errp, "ERROR: Invalid reply received for command %d",
msg->cmd);
return ret;
Expand Down Expand Up @@ -242,6 +242,12 @@ bool mpqemu_msg_valid(MPQemuMsg *msg)
return false;
}
break;
case MPQEMU_CMD_PCI_CFGWRITE:
case MPQEMU_CMD_PCI_CFGREAD:
if (msg->size != sizeof(PciConfDataMsg)) {
return false;
}
break;
default:
break;
}
Expand Down
55 changes: 55 additions & 0 deletions hw/remote/proxy.c
Expand Up @@ -17,6 +17,8 @@
#include "monitor/monitor.h"
#include "migration/blocker.h"
#include "qemu/sockets.h"
#include "hw/remote/mpqemu-link.h"
#include "qemu/error-report.h"

static void pci_proxy_dev_realize(PCIDevice *device, Error **errp)
{
Expand Down Expand Up @@ -65,6 +67,56 @@ static void pci_proxy_dev_exit(PCIDevice *pdev)
error_free(dev->migration_blocker);
}

static void config_op_send(PCIProxyDev *pdev, uint32_t addr, uint32_t *val,
int len, 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 == MPQEMU_CMD_PCI_CFGWRITE) ? *val : 0;
msg.data.pci_conf_data.len = len;
msg.size = sizeof(PciConfDataMsg);

ret = mpqemu_msg_send_and_await_reply(&msg, pdev, &local_err);
if (local_err) {
error_report_err(local_err);
}

if (ret == UINT64_MAX) {
error_report("Failed to perform PCI config %s operation",
(op == MPQEMU_CMD_PCI_CFGREAD) ? "READ" : "WRITE");
}

if (op == MPQEMU_CMD_PCI_CFGREAD) {
*val = (uint32_t)ret;
}
}

static uint32_t pci_proxy_read_config(PCIDevice *d, uint32_t addr, int len)
{
uint32_t val;

config_op_send(PCI_PROXY_DEV(d), addr, &val, len, MPQEMU_CMD_PCI_CFGREAD);

return val;
}

static void pci_proxy_write_config(PCIDevice *d, uint32_t addr, uint32_t val,
int len)
{
/*
* 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, len);

config_op_send(PCI_PROXY_DEV(d), addr, &val, len, MPQEMU_CMD_PCI_CFGWRITE);
}

static Property proxy_properties[] = {
DEFINE_PROP_STRING("fd", PCIProxyDev, fd),
DEFINE_PROP_END_OF_LIST(),
Expand All @@ -77,6 +129,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);
}

Expand Down
10 changes: 10 additions & 0 deletions include/hw/remote/mpqemu-link.h
Expand Up @@ -34,6 +34,9 @@
*/
typedef enum {
MPQEMU_CMD_SYNC_SYSMEM,
MPQEMU_CMD_RET,
MPQEMU_CMD_PCI_CFGWRITE,
MPQEMU_CMD_PCI_CFGREAD,
MPQEMU_CMD_MAX,
} MPQemuCmd;

Expand All @@ -43,6 +46,12 @@ typedef struct {
off_t offsets[REMOTE_MAX_FDS];
} SyncSysmemMsg;

typedef struct {
uint32_t addr;
uint32_t val;
int len;
} PciConfDataMsg;

/**
* MPQemuMsg:
* @cmd: The remote command
Expand All @@ -60,6 +69,7 @@ typedef struct {

union {
uint64_t u64;
PciConfDataMsg pci_conf_data;
SyncSysmemMsg sync_sysmem;
} data;

Expand Down

0 comments on commit 11ab872

Please sign in to comment.