diff --git a/hypervisor/dm/io_req.c b/hypervisor/dm/io_req.c index b3123ac87..fb946c44d 100644 --- a/hypervisor/dm/io_req.c +++ b/hypervisor/dm/io_req.c @@ -459,6 +459,7 @@ static int32_t hv_emulate_mmio(struct acrn_vcpu *vcpu, struct io_request *io_req) { int32_t status = -ENODEV; + bool hold_lock = true; uint16_t idx; uint64_t address, size, base, end; struct mmio_request *mmio_req = &io_req->reqs.mmio; @@ -484,6 +485,7 @@ hv_emulate_mmio(struct acrn_vcpu *vcpu, struct io_request *io_req) continue; } else { if ((address >= base) && ((address + size) <= end)) { + hold_lock = mmio_handler->hold_lock; read_write = mmio_handler->read_write; handler_private_data = mmio_handler->handler_private_data; } else { @@ -496,7 +498,16 @@ hv_emulate_mmio(struct acrn_vcpu *vcpu, struct io_request *io_req) } if ((status == -ENODEV) && (read_write != NULL)) { + /* This mmio_handler will never modify once register, so we don't + * need to hold the lock when handling the MMIO access. + */ + if (!hold_lock) { + spinlock_release(&vcpu->vm->emul_mmio_lock); + } status = read_write(io_req, handler_private_data); + if (!hold_lock) { + spinlock_obtain(&vcpu->vm->emul_mmio_lock); + } } spinlock_release(&vcpu->vm->emul_mmio_lock); @@ -669,7 +680,7 @@ static inline struct mem_io_node *find_free_mmio_node(struct acrn_vm *vm) */ void 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) + uint64_t end, void *handler_private_data, bool hold_lock) { struct mem_io_node *mmio_node; @@ -679,6 +690,7 @@ void register_mmio_emulation_handler(struct acrn_vm *vm, mmio_node = find_free_mmio_node(vm); if (mmio_node != NULL) { /* Fill in information for this node */ + mmio_node->hold_lock = hold_lock; mmio_node->read_write = read_write; mmio_node->handler_private_data = handler_private_data; mmio_node->range_start = start; diff --git a/hypervisor/dm/vioapic.c b/hypervisor/dm/vioapic.c index de07e77a1..2df15efee 100644 --- a/hypervisor/dm/vioapic.c +++ b/hypervisor/dm/vioapic.c @@ -472,7 +472,7 @@ vioapic_init(struct acrn_vm *vm) vioapic_mmio_access_handler, (uint64_t)VIOAPIC_BASE, (uint64_t)VIOAPIC_BASE + VIOAPIC_SIZE, - vm); + vm, false); ept_del_mr(vm, (uint64_t *)vm->arch_vm.nworld_eptp, (uint64_t)VIOAPIC_BASE, (uint64_t)VIOAPIC_SIZE); vm->arch_vm.vioapic.ready = true; diff --git a/hypervisor/dm/vpci/pci_pt.c b/hypervisor/dm/vpci/pci_pt.c index 1f1dbd0e3..6e03381e0 100644 --- a/hypervisor/dm/vpci/pci_pt.c +++ b/hypervisor/dm/vpci/pci_pt.c @@ -112,7 +112,7 @@ static void vdev_pt_map_mem_vbar(struct pci_vdev *vdev, uint32_t idx) addr_lo = round_page_down(addr_lo); addr_hi = round_page_up(addr_hi); register_mmio_emulation_handler(vm, vmsix_handle_table_mmio_access, - addr_lo, addr_hi, vdev); + addr_lo, addr_hi, vdev, true); ept_del_mr(vm, (uint64_t *)vm->arch_vm.nworld_eptp, addr_lo, addr_hi - addr_lo); msix->mmio_gpa = vbar->base; } diff --git a/hypervisor/dm/vpci/vpci.c b/hypervisor/dm/vpci/vpci.c index 96e6cee4f..ad4293419 100644 --- a/hypervisor/dm/vpci/vpci.c +++ b/hypervisor/dm/vpci/vpci.c @@ -249,7 +249,7 @@ void vpci_init(struct acrn_vm *vm) pci_mmcfg_base = (vm_config->load_order == SOS_VM) ? get_mmcfg_base() : 0xE0000000UL; vm->vpci.pci_mmcfg_base = pci_mmcfg_base; register_mmio_emulation_handler(vm, vpci_handle_mmconfig_access, - pci_mmcfg_base, pci_mmcfg_base + PCI_MMCONFIG_SIZE, &vm->vpci); + pci_mmcfg_base, pci_mmcfg_base + PCI_MMCONFIG_SIZE, &vm->vpci, false); } /* Intercept and handle I/O ports CF8h */ diff --git a/hypervisor/include/dm/io_req.h b/hypervisor/include/dm/io_req.h index 8c853884a..21242bf56 100644 --- a/hypervisor/include/dm/io_req.h +++ b/hypervisor/include/dm/io_req.h @@ -112,6 +112,13 @@ typedef int32_t (*hv_mem_io_handler_t)(struct io_request *io_req, void *handler_ * @brief Structure for MMIO handler node */ struct mem_io_node { + + /** + * @brief Whether the lock needs to hold when handle the MMIO access + */ + bool hold_lock; + + /** * @brief A pointer to the handler * @@ -258,12 +265,13 @@ void register_pio_emulation_handler(struct acrn_vm *vm, uint32_t pio_idx, * @param start The base address of the range \p read_write can emulate * @param end The end of the range (exclusive) \p read_write can emulate * @param handler_private_data Handler-specific data which will be passed to \p read_write when called + * @param hold_lock Whether hold the lock to handle the MMIO access * * @return None */ void 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); + uint64_t end, void *handler_private_data, bool hold_lock); /** * @brief Unregister a MMIO handler