diff --git a/hypervisor/common/hypercall.c b/hypervisor/common/hypercall.c index 24282667a..86ac0f574 100644 --- a/hypervisor/common/hypercall.c +++ b/hypervisor/common/hypercall.c @@ -20,6 +20,7 @@ #include #include #include +#include #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) diff --git a/hypervisor/dm/vpci/ivshmem.c b/hypervisor/dm/vpci/ivshmem.c index 31840be19..be22e77e3 100644 --- a/hypervisor/dm/vpci/ivshmem.c +++ b/hypervisor/dm/vpci/ivshmem.c @@ -9,13 +9,12 @@ #include #include #include +#include #include #include #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, diff --git a/hypervisor/include/arch/x86/vm_config.h b/hypervisor/include/arch/x86/vm_config.h index 29e6a250b..feb5b5346 100644 --- a/hypervisor/include/arch/x86/vm_config.h +++ b/hypervisor/include/arch/x86/vm_config.h @@ -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); diff --git a/hypervisor/include/dm/ivshmem.h b/hypervisor/include/dm/ivshmem.h index fd6bfe1e2..06ebacc41 100644 --- a/hypervisor/include/dm/ivshmem.h +++ b/hypervisor/include/dm/ivshmem.h @@ -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 */