hv: implement ivshmem device creation and destruction

For ivshmem vdev creation, the vdev vBDF, vBARs, shared memory region
name and size are set by device model. The shared memory name and size
must be same as the corresponding device configuration which is configured
by offline tool.

v3: add a comment to the vbar_base member of the acrn_vm_pci_dev_config
    structure that vbar_base is power-on default value

Tracked-On: #4853

Signed-off-by: Yuan Liu <yuan1.liu@intel.com>
Acked-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
Yuan Liu 2020-08-25 14:27:36 +08:00 committed by wenlingz
parent 8a34cf03ca
commit 6d0f0ebd8a
4 changed files with 69 additions and 4 deletions

View File

@ -20,6 +20,7 @@
#include <logmsg.h>
#include <ioapic.h>
#include <mmio_dev.h>
#include <ivshmem.h>
#define DBG_LEVEL_HYCALL 6U
@ -36,7 +37,11 @@ struct emul_dev_ops {
};
static struct emul_dev_ops emul_dev_ops_tbl[] = {
{0, NULL, NULL}, /* implemented in next patch */
#ifdef CONFIG_IVSHMEM_ENABLED
{(IVSHMEM_VENDOR_ID | (IVSHMEM_DEVICE_ID << 16U)), create_ivshmem_vdev , destroy_ivshmem_vdev},
#else
{(IVSHMEM_VENDOR_ID | (IVSHMEM_DEVICE_ID << 16U)), NULL, NULL},
#endif
};
bool is_hypercall_from_ring0(void)

View File

@ -9,13 +9,12 @@
#include <mmu.h>
#include <ept.h>
#include <logmsg.h>
#include <errno.h>
#include <ivshmem.h>
#include <ivshmem_cfg.h>
#include "vpci_priv.h"
/* config space of ivshmem device */
#define IVSHMEM_VENDOR_ID 0x1af4U
#define IVSHMEM_DEVICE_ID 0x1110U
#define IVSHMEM_CLASS 0x05U
#define IVSHMEM_REV 0x01U
@ -254,6 +253,63 @@ static void deinit_ivshmem_vdev(struct pci_vdev *vdev)
vdev->user = NULL;
}
/**
* @pre vm != NULL
* @pre dev != NULL
*/
int32_t create_ivshmem_vdev(struct acrn_vm *vm, struct acrn_emul_dev *dev)
{
uint32_t i;
struct acrn_vm_config *vm_config = get_vm_config(vm->vm_id);
struct acrn_vm_pci_dev_config *dev_config = NULL;
int32_t ret = -EINVAL;
for (i = 0U; i < vm_config->pci_dev_num; i++) {
dev_config = &vm_config->pci_devs[i];
if (strncmp(dev_config->shm_region_name, (char *)dev->args, sizeof(dev_config->shm_region_name)) == 0) {
struct ivshmem_shm_region *region = find_shm_region(dev_config->shm_region_name);
if ((region != NULL) && (region->size == dev->io_size[IVSHMEM_SHM_BAR])) {
spinlock_obtain(&vm->vpci.lock);
dev_config->vbdf.value = (uint16_t) dev->slot;
dev_config->vbar_base[IVSHMEM_MMIO_BAR] = (uint64_t) dev->io_addr[IVSHMEM_MMIO_BAR];
dev_config->vbar_base[IVSHMEM_SHM_BAR] = (uint64_t) dev->io_addr[IVSHMEM_SHM_BAR];
dev_config->vbar_base[IVSHMEM_SHM_BAR] |= ((uint64_t) dev->io_addr[IVSHMEM_SHM_BAR + 1U]) << 32U;
(void) vpci_init_vdev(&vm->vpci, dev_config, NULL);
spinlock_release(&vm->vpci.lock);
ret = 0;
} else {
pr_warn("%s, failed to create ivshmem device %x:%x.%x\n", __func__,
dev->slot >> 8U, (dev->slot >> 3U) & 0x1fU, dev->slot & 0x7U);
}
break;
}
}
return ret;
}
/**
* @pre vm != NULL
* @pre dev != NULL
*/
int32_t destroy_ivshmem_vdev(struct acrn_vm *vm, struct acrn_emul_dev *dev)
{
struct pci_vdev *vdev;
union pci_bdf bdf;
int32_t ret = 0;
bdf.value = (uint16_t) dev->slot;
vdev = pci_find_vdev(&vm->vpci, bdf);
if (vdev != NULL) {
vdev->pci_dev_config->vbdf.value = UNASSIGNED_VBDF;
(void)memset(vdev->pci_dev_config->vbar_base, 0U, sizeof(vdev->pci_dev_config->vbar_base));
} else {
pr_warn("%s, failed to destroy ivshmem device %x:%x.%x\n",
__func__, bdf.bits.b, bdf.bits.d, bdf.bits.f);
ret = -EINVAL;
}
return ret;
}
const struct pci_vdev_ops vpci_ivshmem_ops = {
.init_vdev = init_ivshmem_vdev,
.deinit_vdev = deinit_ivshmem_vdev,

View File

@ -148,7 +148,7 @@ struct acrn_vm_pci_dev_config {
union pci_bdf vbdf; /* virtual BDF of PCI device */
union pci_bdf pbdf; /* physical BDF of PCI device */
char shm_region_name[32]; /* TODO: combine pbdf and shm_region_name into a union member */
uint64_t vbar_base[PCI_BAR_COUNT]; /* vbar base address of PCI device */
uint64_t vbar_base[PCI_BAR_COUNT]; /* vbar base address of PCI device, which is power-on default value */
struct pci_pdev *pdev; /* the physical PCI device if it's a PT device */
const struct pci_vdev_ops *vdev_ops; /* operations for PCI CFG read/write */
} __aligned(8);

View File

@ -7,6 +7,8 @@
#ifndef IVSHMEM_H
#define IVSHMEM_H
#define IVSHMEM_VENDOR_ID 0x1af4U
#define IVSHMEM_DEVICE_ID 0x1110U
#ifdef CONFIG_IVSHMEM_ENABLED
struct ivshmem_shm_region {
char name[32];
@ -25,6 +27,8 @@ extern const struct pci_vdev_ops vpci_ivshmem_ops;
*/
void init_ivshmem_shared_memory(void);
int32_t create_ivshmem_vdev(struct acrn_vm *vm, struct acrn_emul_dev *dev);
int32_t destroy_ivshmem_vdev(struct acrn_vm *vm, struct acrn_emul_dev *dev);
#endif /* CONFIG_IVSHMEM_ENABLED */
#endif /* IVSHMEM_H */