diff --git a/doc/developer-guides/hld/hv-io-emulation.rst b/doc/developer-guides/hld/hv-io-emulation.rst index 132fdb8e6..44d3385a4 100644 --- a/doc/developer-guides/hld/hv-io-emulation.rst +++ b/doc/developer-guides/hld/hv-io-emulation.rst @@ -322,9 +322,6 @@ I/O bitmaps and register or unregister I/O handlers: .. doxygenfunction:: register_mmio_emulation_handler :project: Project ACRN -.. doxygenfunction:: unregister_mmio_emulation_handler - :project: Project ACRN - I/O Emulation ============= diff --git a/hypervisor/arch/x86/Kconfig b/hypervisor/arch/x86/Kconfig index fba0c07a9..d45a3cc4f 100644 --- a/hypervisor/arch/x86/Kconfig +++ b/hypervisor/arch/x86/Kconfig @@ -86,6 +86,11 @@ config MAX_PCPU_NUM range 1 8 default 8 +config MAX_EMULATED_MMIO_REGIONS + int "Maximum number of emulated mmio regions" + range 0 128 + default 16 + config MAX_IOMMU_NUM int "Maximum number of IOMMU devices" range 1 2 diff --git a/hypervisor/arch/x86/guest/vm.c b/hypervisor/arch/x86/guest/vm.c index 5e87b21e6..22ddfeb86 100644 --- a/hypervisor/arch/x86/guest/vm.c +++ b/hypervisor/arch/x86/guest/vm.c @@ -80,9 +80,8 @@ int create_vm(struct vm_description *vm_desc, struct acrn_vm **rtn_vm) /* Map Virtual Machine to its VM Description */ vm->vm_desc = vm_desc; #endif - /* Init mmio list */ - INIT_LIST_HEAD(&vm->mmio_list); vm->hw.created_vcpus = 0U; + vm->emul_mmio_regions = 0U; /* gpa_lowtop are used for system start up */ vm->hw.gpa_lowtop = 0UL; @@ -173,8 +172,6 @@ int create_vm(struct vm_description *vm_desc, struct acrn_vm **rtn_vm) err: - vioapic_cleanup(vm_ioapic(vm)); - if (vm->arch_vm.nworld_eptp != NULL) { (void)memset(vm->arch_vm.nworld_eptp, 0U, CPU_PAGE_SIZE); } @@ -205,9 +202,6 @@ int shutdown_vm(struct acrn_vm *vm) ptdev_release_all_entries(vm); - /* cleanup vioapic */ - vioapic_cleanup(vm_ioapic(vm)); - /* Free EPT allocated resources assigned to VM */ destroy_ept(vm); diff --git a/hypervisor/arch/x86/io.c b/hypervisor/arch/x86/io.c index af8fc5777..a4330eb86 100644 --- a/hypervisor/arch/x86/io.c +++ b/hypervisor/arch/x86/io.c @@ -253,31 +253,32 @@ static int32_t hv_emulate_mmio(struct acrn_vcpu *vcpu, struct io_request *io_req) { int status = -ENODEV; + uint16_t idx; uint64_t address, size; - struct list_head *pos; struct mmio_request *mmio_req = &io_req->reqs.mmio; struct mem_io_node *mmio_handler = NULL; address = mmio_req->address; size = mmio_req->size; - list_for_each(pos, &vcpu->vm->mmio_list) { + for (idx = 0U; idx < vcpu->vm->emul_mmio_regions; idx++) { uint64_t base, end; - mmio_handler = list_entry(pos, struct mem_io_node, list); + mmio_handler = &(vcpu->vm->emul_mmio[idx]); base = mmio_handler->range_start; end = mmio_handler->range_end; if ((address + size <= base) || (address >= end)) { continue; } else if (!((address >= base) && (address + size <= end))) { - pr_fatal("Err MMIO, address:0x%llx, size:%x", - address, size); + pr_fatal("Err MMIO, address:0x%llx, size:%x", address, size); return -EIO; } else { /* Handle this MMIO operation */ - status = mmio_handler->read_write(io_req, mmio_handler->handler_private_data); - break; + if (mmio_handler->read_write) { + status = mmio_handler->read_write(io_req, mmio_handler->handler_private_data); + break; + } } } @@ -499,64 +500,35 @@ int register_mmio_emulation_handler(struct acrn_vm *vm, /* Ensure both a read/write handler and range check function exist */ if ((read_write != NULL) && (end > start)) { - /* Allocate memory for node */ - mmio_node = - (struct mem_io_node *)calloc(1U, sizeof(struct mem_io_node)); - /* Ensure memory successfully allocated */ - if (mmio_node != NULL) { - /* Fill in information for this node */ - mmio_node->read_write = read_write; - mmio_node->handler_private_data = handler_private_data; - - INIT_LIST_HEAD(&mmio_node->list); - list_add(&mmio_node->list, &vm->mmio_list); - - mmio_node->range_start = start; - mmio_node->range_end = end; - - /* - * SOS would map all its memory at beginning, so we - * should unmap it. But UOS will not, so we shouldn't - * need to unmap it. - */ - if (is_vm0(vm)) { - ept_mr_del(vm, - (uint64_t *)vm->arch_vm.nworld_eptp, - start, end - start); - } - - /* Return success */ - status = 0; + if (vm->emul_mmio_regions >= CONFIG_MAX_EMULATED_MMIO_REGIONS) { + pr_err("the emulated mmio region is out of range"); + return status; } + mmio_node = &(vm->emul_mmio[vm->emul_mmio_regions]); + /* Fill in information for this node */ + mmio_node->read_write = read_write; + mmio_node->handler_private_data = handler_private_data; + mmio_node->range_start = start; + mmio_node->range_end = end; + + (vm->emul_mmio_regions)++; + + /* + * SOS would map all its memory at beginning, so we + * should unmap it. But UOS will not, so we shouldn't + * need to unmap it. + */ + if (is_vm0(vm)) { + ept_mr_del(vm, (uint64_t *)vm->arch_vm.nworld_eptp, + start, end - start); + } + + /* Return success */ + status = 0; + } /* Return status to caller */ return status; } - -/** - * @brief Unregister a MMIO handler - * - * @param vm The VM from which MMIO handlers are unregistered - * @param start The base address of the range the to-be-unregistered handler is for - * @param end The end of the range (exclusive) the to-be-unregistered handler is for - */ -void unregister_mmio_emulation_handler(struct acrn_vm *vm, uint64_t start, - uint64_t end) -{ - struct list_head *pos, *tmp; - struct mem_io_node *mmio_node; - - list_for_each_safe(pos, tmp, &vm->mmio_list) { - mmio_node = list_entry(pos, struct mem_io_node, list); - - if ((mmio_node->range_start == start) && - (mmio_node->range_end == end)) { - /* assume only one entry found in mmio_list */ - list_del_init(&mmio_node->list); - free(mmio_node); - break; - } - } -} diff --git a/hypervisor/dm/vioapic.c b/hypervisor/dm/vioapic.c index cdfd2c803..450871343 100644 --- a/hypervisor/dm/vioapic.c +++ b/hypervisor/dm/vioapic.c @@ -523,14 +523,6 @@ vioapic_init(struct acrn_vm *vm) vm); } -void -vioapic_cleanup(const struct acrn_vioapic *vioapic) -{ - unregister_mmio_emulation_handler(vioapic->vm, - (uint64_t)VIOAPIC_BASE, - (uint64_t)VIOAPIC_BASE + VIOAPIC_SIZE); -} - uint32_t vioapic_pincount(const struct acrn_vm *vm) { diff --git a/hypervisor/dm/vpci/msix.c b/hypervisor/dm/vpci/msix.c index d08eea301..858ef4e29 100644 --- a/hypervisor/dm/vpci/msix.c +++ b/hypervisor/dm/vpci/msix.c @@ -387,11 +387,7 @@ static int vmsix_init(struct pci_vdev *vdev) static int vmsix_deinit(struct pci_vdev *vdev) { - if (vdev->msix.intercepted_size != 0UL) { - unregister_mmio_emulation_handler(vdev->vpci->vm, vdev->msix.intercepted_gpa, - vdev->msix.intercepted_gpa + vdev->msix.intercepted_size); - vdev->msix.intercepted_size = 0U; - } + vdev->msix.intercepted_size = 0U; if (vdev->msix.table_count != 0U) { ptdev_remove_msix_remapping(vdev->vpci->vm, vdev->vbdf.value, vdev->msix.table_count); diff --git a/hypervisor/include/arch/x86/guest/vioapic.h b/hypervisor/include/arch/x86/guest/vioapic.h index e341b4f0f..0ba4e663c 100644 --- a/hypervisor/include/arch/x86/guest/vioapic.h +++ b/hypervisor/include/arch/x86/guest/vioapic.h @@ -56,7 +56,6 @@ struct acrn_vioapic { }; void vioapic_init(struct acrn_vm *vm); -void vioapic_cleanup(const struct acrn_vioapic *vioapic); void vioapic_reset(struct acrn_vioapic *vioapic); diff --git a/hypervisor/include/arch/x86/guest/vm.h b/hypervisor/include/arch/x86/guest/vm.h index de315f071..8d8e73c47 100644 --- a/hypervisor/include/arch/x86/guest/vm.h +++ b/hypervisor/include/arch/x86/guest/vm.h @@ -134,9 +134,8 @@ struct acrn_vm { struct iommu_domain *iommu; /* iommu domain of this VM */ spinlock_t spinlock; /* Spin-lock used to protect VM modifications */ - struct list_head mmio_list; /* list for mmio. This list is not updated - * when vm is active. So no lock needed - */ + uint16_t emul_mmio_regions; /* Number of emulated mmio regions */ + struct mem_io_node emul_mmio[CONFIG_MAX_EMULATED_MMIO_REGIONS]; unsigned char GUID[16]; struct secure_world_control sworld_control; diff --git a/hypervisor/include/arch/x86/ioreq.h b/hypervisor/include/arch/x86/ioreq.h index c19f3d6f5..89d1c9903 100644 --- a/hypervisor/include/arch/x86/ioreq.h +++ b/hypervisor/include/arch/x86/ioreq.h @@ -227,16 +227,6 @@ int register_mmio_emulation_handler(struct acrn_vm *vm, hv_mem_io_handler_t read_write, uint64_t start, uint64_t end, void *handler_private_data); -/** - * @brief Unregister a MMIO handler - * - * @param vm The VM from which MMIO handlers are unregistered - * @param start The base address of the range the to-be-unregistered handler is for - * @param end The end of the range (exclusive) the to-be-unregistered handler is for - */ -void unregister_mmio_emulation_handler(struct acrn_vm *vm, uint64_t start, - uint64_t end); - /** * @brief General post-work for MMIO emulation *