dm: implement ivshmem inter-vm communication for hv-land

This patch is used to create and destroy an ivshmem device which
is emulated in hypervisor.

Tracked-On: #4853

Signed-off-by: Yuan Liu <yuan1.liu@intel.com>
Acked-by: Wang, Yu1 <yu1.wang@intel.com>
This commit is contained in:
Yuan Liu 2020-08-26 11:04:51 +08:00 committed by wenlingz
parent 1d084073d6
commit 91e2fcfecf

View File

@ -62,12 +62,16 @@
#define IVSHMEM_DOORBELL_REG 0x0c
#define IVSHMEM_RESERVED_REG 0x0f
#define hv_land_prefix "hv:/"
#define dm_land_prefix "sos:/"
struct pci_ivshmem_vdev {
struct pci_vdev *dev;
char *name;
int fd;
void *addr;
uint32_t size;
bool is_hv_land;
};
static int
@ -135,6 +139,28 @@ err:
return -1;
}
static int
create_ivshmem_from_hv(struct vmctx *ctx, struct pci_vdev *vdev,
const char *shm_name, uint32_t shm_size)
{
struct acrn_emul_dev dev = {};
uint64_t addr = 0;
dev.dev_id.fields.vendor_id = IVSHMEM_VENDOR_ID;
dev.dev_id.fields.device_id = IVSHMEM_DEVICE_ID;
dev.slot = PCI_BDF(vdev->bus, vdev->slot, vdev->func);
dev.io_addr[IVSHMEM_MMIO_BAR] = pci_get_cfgdata32(vdev,
PCIR_BAR(IVSHMEM_MMIO_BAR));
addr = pci_get_cfgdata32(vdev, PCIR_BAR(IVSHMEM_MEM_BAR));
addr |= 0x0c; /* 64bit, prefetchable */
dev.io_addr[IVSHMEM_MEM_BAR] = addr;
addr = pci_get_cfgdata32(vdev, PCIR_BAR(IVSHMEM_MEM_BAR + 1));
dev.io_addr[IVSHMEM_MEM_BAR + 1] = addr;
dev.io_size[IVSHMEM_MEM_BAR] = shm_size;
strncpy((char*)dev.args, shm_name, 32);
return vm_create_hv_vdev(ctx, &dev);
}
static void
pci_ivshmem_write(struct vmctx *ctx, int vcpu, struct pci_vdev *dev,
int baridx, uint64_t offset, int size, uint64_t value)
@ -217,6 +243,8 @@ pci_ivshmem_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
uint32_t size;
char *tmp, *name, *orig;
struct pci_ivshmem_vdev *ivshmem_vdev = NULL;
bool is_hv_land;
int rc;
/* ivshmem device usage: "-s N,ivshmem,shm_name,shm_size" */
tmp = orig = strdup(opts);
@ -229,6 +257,17 @@ pci_ivshmem_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
pr_warn("the shared memory size is not set\n");
goto err;
}
if (!strncmp(name, hv_land_prefix, strlen(hv_land_prefix))) {
is_hv_land = true;
} else if (!strncmp(name, dm_land_prefix, strlen(dm_land_prefix))) {
is_hv_land = false;
name += strlen(dm_land_prefix);
} else {
pr_warn("the ivshmem memory prefix name is incorrect\n");
goto err;
}
if (dm_strtoui(tmp, &tmp, 10, &size) != 0) {
pr_warn("the shared memory size is incorrect, %s\n", tmp);
goto err;
@ -247,6 +286,7 @@ pci_ivshmem_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
}
ivshmem_vdev->dev = dev;
ivshmem_vdev->is_hv_land = is_hv_land;
dev->arg = ivshmem_vdev;
/* initialize config space */
@ -258,12 +298,17 @@ pci_ivshmem_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
pci_emul_alloc_bar(dev, IVSHMEM_MMIO_BAR, PCIBAR_MEM32, IVSHMEM_REG_SIZE);
pci_emul_alloc_bar(dev, IVSHMEM_MEM_BAR, PCIBAR_MEM64, size);
/*
* TODO: If UOS reprograms ivshmem BAR2, the shared memory will be
* unavailable for UOS, so we need to remap GPA and HPA of shared
* memory in this case.
*/
if (create_ivshmem_from_dm(ctx, dev, name, size) < 0)
if (is_hv_land) {
rc = create_ivshmem_from_hv(ctx, dev, name, size);
} else {
/*
* TODO: If UOS reprograms ivshmem BAR2, the shared memory will be
* unavailable for UOS, so we need to remap GPA and HPA of shared
* memory in this case.
*/
rc = create_ivshmem_from_dm(ctx, dev, name, size);
}
if (rc < 0)
goto err;
free(orig);
@ -287,6 +332,18 @@ destroy_ivshmem_from_dm(struct pci_ivshmem_vdev *vdev)
close(vdev->fd);
}
static void
destroy_ivshmem_from_hv(struct vmctx *ctx, struct pci_vdev *vdev)
{
struct acrn_emul_dev emul_dev = {};
emul_dev.dev_id.fields.vendor_id = IVSHMEM_VENDOR_ID;
emul_dev.dev_id.fields.device_id = IVSHMEM_DEVICE_ID;
emul_dev.slot = PCI_BDF(vdev->bus, vdev->slot, vdev->func);
vm_destroy_hv_vdev(ctx, &emul_dev);
}
static void
pci_ivshmem_deinit(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
{
@ -297,7 +354,11 @@ pci_ivshmem_deinit(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
pr_warn("%s, invalid ivshmem instance\n", __func__);
return;
}
destroy_ivshmem_from_dm(vdev);
if (vdev->is_hv_land)
destroy_ivshmem_from_hv(ctx, dev);
else
destroy_ivshmem_from_dm(vdev);
if (vdev->name) {
/*
* shm_unlink will only remove the shared memory file object,
@ -311,6 +372,7 @@ pci_ivshmem_deinit(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
*/
free(vdev->name);
}
free(vdev);
dev->arg = NULL;
}