mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-08-13 13:56:19 +00:00
hv: io: add unregister_mmio_emulation_handler API
Since guest could re-program PCI device MSI-X table BAR, we should add mmio emulation handler unregister. However, after add unregister_mmio_emulation_handler API, emul_mmio_regions is no longer accurate. Just replace it with max_emul_mmio_regions which records the max index of the emul_mmio_node. Tracked-On: #3475 Signed-off-by: Li, Fei1 <fei1.li@intel.com>
This commit is contained in:
parent
dc1e2adaec
commit
2c158d5ad4
@ -439,7 +439,6 @@ int32_t create_vm(uint16_t vm_id, struct acrn_vm_config *vm_config, struct acrn_
|
|||||||
(void)memset((void *)vm, 0U, sizeof(struct acrn_vm));
|
(void)memset((void *)vm, 0U, sizeof(struct acrn_vm));
|
||||||
vm->vm_id = vm_id;
|
vm->vm_id = vm_id;
|
||||||
vm->hw.created_vcpus = 0U;
|
vm->hw.created_vcpus = 0U;
|
||||||
vm->emul_mmio_regions = 0U;
|
|
||||||
|
|
||||||
init_ept_mem_ops(&vm->arch_vm.ept_mem_ops, vm->vm_id);
|
init_ept_mem_ops(&vm->arch_vm.ept_mem_ops, vm->vm_id);
|
||||||
vm->arch_vm.nworld_eptp = vm->arch_vm.ept_mem_ops.get_pml4_page(vm->arch_vm.ept_mem_ops.info);
|
vm->arch_vm.nworld_eptp = vm->arch_vm.ept_mem_ops.get_pml4_page(vm->arch_vm.ept_mem_ops.info);
|
||||||
|
@ -474,7 +474,7 @@ hv_emulate_mmio(struct acrn_vcpu *vcpu, struct io_request *io_req)
|
|||||||
{
|
{
|
||||||
int32_t status = -ENODEV;
|
int32_t status = -ENODEV;
|
||||||
uint16_t idx;
|
uint16_t idx;
|
||||||
uint64_t address, size;
|
uint64_t address, size, base, end;
|
||||||
struct mmio_request *mmio_req = &io_req->reqs.mmio;
|
struct mmio_request *mmio_req = &io_req->reqs.mmio;
|
||||||
struct mem_io_node *mmio_handler = NULL;
|
struct mem_io_node *mmio_handler = NULL;
|
||||||
hv_mem_io_handler_t read_write = NULL;
|
hv_mem_io_handler_t read_write = NULL;
|
||||||
@ -487,32 +487,26 @@ hv_emulate_mmio(struct acrn_vcpu *vcpu, struct io_request *io_req)
|
|||||||
address = mmio_req->address;
|
address = mmio_req->address;
|
||||||
size = mmio_req->size;
|
size = mmio_req->size;
|
||||||
|
|
||||||
for (idx = 0U; idx < vcpu->vm->emul_mmio_regions; idx++) {
|
for (idx = 0U; idx <= vcpu->vm->max_emul_mmio_regions; idx++) {
|
||||||
uint64_t base, end;
|
|
||||||
bool emulation_done = false;
|
|
||||||
|
|
||||||
mmio_handler = &(vcpu->vm->emul_mmio[idx]);
|
mmio_handler = &(vcpu->vm->emul_mmio[idx]);
|
||||||
|
if (mmio_handler->read_write != NULL) {
|
||||||
base = mmio_handler->range_start;
|
base = mmio_handler->range_start;
|
||||||
end = mmio_handler->range_end;
|
end = mmio_handler->range_end;
|
||||||
|
|
||||||
if (((address + size) <= base) || (address >= end)) {
|
if (((address + size) <= base) || (address >= end)) {
|
||||||
continue;
|
continue;
|
||||||
} else if (!((address >= base) && ((address + size) <= end))) {
|
|
||||||
pr_fatal("Err MMIO, address:0x%llx, size:%x", address, size);
|
|
||||||
status = -EIO;
|
|
||||||
emulation_done = true;
|
|
||||||
} else {
|
} else {
|
||||||
if (mmio_handler->read_write != NULL) {
|
if ((address >= base) && ((address + size) <= end)) {
|
||||||
read_write = mmio_handler->read_write;
|
read_write = mmio_handler->read_write;
|
||||||
handler_private_data = mmio_handler->handler_private_data;
|
handler_private_data = mmio_handler->handler_private_data;
|
||||||
emulation_done = true;
|
} else {
|
||||||
|
pr_fatal("Err MMIO, address:0x%llx, size:%x", address, size);
|
||||||
|
status = -EIO;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (emulation_done) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ((status == -ENODEV) && (read_write != NULL)) {
|
if ((status == -ENODEV) && (read_write != NULL)) {
|
||||||
status = read_write(io_req, handler_private_data);
|
status = read_write(io_req, handler_private_data);
|
||||||
@ -616,11 +610,67 @@ void register_pio_emulation_handler(struct acrn_vm *vm, uint32_t pio_idx,
|
|||||||
vm->emul_pio[pio_idx].io_write = io_write_fn_ptr;
|
vm->emul_pio[pio_idx].io_write = io_write_fn_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Find match MMIO node
|
||||||
|
*
|
||||||
|
* This API find match MMIO node from \p vm.
|
||||||
|
*
|
||||||
|
* @param vm The VM to which the MMIO node is belong to.
|
||||||
|
*
|
||||||
|
* @return If there's a match mmio_node return it, otherwise return NULL;
|
||||||
|
*/
|
||||||
|
static inline struct mem_io_node *find_match_mmio_node(struct acrn_vm *vm,
|
||||||
|
uint64_t start, uint64_t end)
|
||||||
|
{
|
||||||
|
bool found = false;
|
||||||
|
uint16_t idx;
|
||||||
|
struct mem_io_node *mmio_node;
|
||||||
|
|
||||||
|
for (idx = 0U; idx < CONFIG_MAX_EMULATED_MMIO_REGIONS; idx++) {
|
||||||
|
mmio_node = &(vm->emul_mmio[idx]);
|
||||||
|
if ((mmio_node->range_start == start) && (mmio_node->range_end == end)) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
pr_fatal("%s, vm[%d] no match mmio region [0x%llx, 0x%llx] is found",
|
||||||
|
__func__, vm->vm_id, start, end);
|
||||||
|
mmio_node = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mmio_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Find a free MMIO node
|
||||||
|
*
|
||||||
|
* This API find a free MMIO node from \p vm.
|
||||||
|
*
|
||||||
|
* @param vm The VM to which the MMIO node is belong to.
|
||||||
|
*
|
||||||
|
* @return If there's a free mmio_node return it, otherwise return NULL;
|
||||||
|
*/
|
||||||
|
static inline struct mem_io_node *find_free_mmio_node(struct acrn_vm *vm)
|
||||||
|
{
|
||||||
|
uint16_t idx;
|
||||||
|
struct mem_io_node *mmio_node = find_match_mmio_node(vm, 0UL, 0UL);
|
||||||
|
|
||||||
|
if (mmio_node != NULL) {
|
||||||
|
idx = (uint16_t)(uint64_t)(mmio_node - &(vm->emul_mmio[0U]));
|
||||||
|
if (vm->max_emul_mmio_regions < idx) {
|
||||||
|
vm->max_emul_mmio_regions = idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mmio_node;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Register a MMIO handler
|
* @brief Register a MMIO handler
|
||||||
*
|
*
|
||||||
* This API registers a MMIO handler to \p vm before it is Started
|
* This API registers a MMIO handler to \p vm
|
||||||
* For Pre-launched VMs, this API can be called after it is Started
|
|
||||||
*
|
*
|
||||||
* @param vm The VM to which the MMIO handler is registered
|
* @param vm The VM to which the MMIO handler is registered
|
||||||
* @param read_write The handler for emulating accesses to the given range
|
* @param read_write The handler for emulating accesses to the given range
|
||||||
@ -638,18 +688,14 @@ void register_mmio_emulation_handler(struct acrn_vm *vm,
|
|||||||
|
|
||||||
/* Ensure both a read/write handler and range check function exist */
|
/* Ensure both a read/write handler and range check function exist */
|
||||||
if ((read_write != NULL) && (end > start)) {
|
if ((read_write != NULL) && (end > start)) {
|
||||||
if (vm->emul_mmio_regions >= CONFIG_MAX_EMULATED_MMIO_REGIONS) {
|
mmio_node = find_free_mmio_node(vm);
|
||||||
pr_err("the emulated mmio region is out of range");
|
if (mmio_node != NULL) {
|
||||||
} else {
|
|
||||||
mmio_node = &(vm->emul_mmio[vm->emul_mmio_regions]);
|
|
||||||
/* Fill in information for this node */
|
/* Fill in information for this node */
|
||||||
mmio_node->read_write = read_write;
|
mmio_node->read_write = read_write;
|
||||||
mmio_node->handler_private_data = handler_private_data;
|
mmio_node->handler_private_data = handler_private_data;
|
||||||
mmio_node->range_start = start;
|
mmio_node->range_start = start;
|
||||||
mmio_node->range_end = end;
|
mmio_node->range_end = end;
|
||||||
|
|
||||||
(vm->emul_mmio_regions)++;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SOS would map all its memory at beginning, so we
|
* SOS would map all its memory at beginning, so we
|
||||||
* should unmap it. But UOS will not, so we shouldn't
|
* should unmap it. But UOS will not, so we shouldn't
|
||||||
@ -663,3 +709,24 @@ void register_mmio_emulation_handler(struct acrn_vm *vm,
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unregister a MMIO handler
|
||||||
|
*
|
||||||
|
* This API unregisters a MMIO handler to \p vm
|
||||||
|
*
|
||||||
|
* @param vm The VM to which the MMIO handler is unregistered
|
||||||
|
* @param start The base address of the range which wants to unregister
|
||||||
|
* @param end The end of the range (exclusive) which wants to unregister
|
||||||
|
*
|
||||||
|
* @return None
|
||||||
|
*/
|
||||||
|
void unregister_mmio_emulation_handler(struct acrn_vm *vm,
|
||||||
|
uint64_t start, uint64_t end)
|
||||||
|
{
|
||||||
|
struct mem_io_node *mmio_node = find_match_mmio_node(vm, start, end);
|
||||||
|
|
||||||
|
if (mmio_node != NULL) {
|
||||||
|
(void)memset(mmio_node, 0U, sizeof(struct mem_io_node));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -125,7 +125,7 @@ struct acrn_vm {
|
|||||||
struct iommu_domain *iommu; /* iommu domain of this VM */
|
struct iommu_domain *iommu; /* iommu domain of this VM */
|
||||||
spinlock_t vm_lock; /* Spin-lock used to protect VM modifications */
|
spinlock_t vm_lock; /* Spin-lock used to protect VM modifications */
|
||||||
|
|
||||||
uint16_t emul_mmio_regions; /* Number of emulated mmio regions */
|
uint16_t max_emul_mmio_regions; /* max index of the emulated mmio_region */
|
||||||
struct mem_io_node emul_mmio[CONFIG_MAX_EMULATED_MMIO_REGIONS];
|
struct mem_io_node emul_mmio[CONFIG_MAX_EMULATED_MMIO_REGIONS];
|
||||||
|
|
||||||
struct vm_io_handler_desc emul_pio[EMUL_PIO_IDX_MAX];
|
struct vm_io_handler_desc emul_pio[EMUL_PIO_IDX_MAX];
|
||||||
|
@ -251,7 +251,7 @@ void register_pio_emulation_handler(struct acrn_vm *vm, uint32_t pio_idx,
|
|||||||
/**
|
/**
|
||||||
* @brief Register a MMIO handler
|
* @brief Register a MMIO handler
|
||||||
*
|
*
|
||||||
* This API registers a MMIO handler to \p vm before it is launched.
|
* This API registers a MMIO handler to \p vm.
|
||||||
*
|
*
|
||||||
* @param vm The VM to which the MMIO handler is registered
|
* @param vm The VM to which the MMIO handler is registered
|
||||||
* @param read_write The handler for emulating accesses to the given range
|
* @param read_write The handler for emulating accesses to the given range
|
||||||
@ -265,6 +265,20 @@ void register_mmio_emulation_handler(struct acrn_vm *vm,
|
|||||||
hv_mem_io_handler_t read_write, uint64_t start,
|
hv_mem_io_handler_t read_write, uint64_t start,
|
||||||
uint64_t end, void *handler_private_data);
|
uint64_t end, void *handler_private_data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unregister a MMIO handler
|
||||||
|
*
|
||||||
|
* This API unregisters a MMIO handler to \p vm
|
||||||
|
*
|
||||||
|
* @param vm The VM to which the MMIO handler is unregistered
|
||||||
|
* @param start The base address of the range which wants to unregister
|
||||||
|
* @param end The end of the range (exclusive) which wants to unregister
|
||||||
|
*
|
||||||
|
* @return None
|
||||||
|
*/
|
||||||
|
void unregister_mmio_emulation_handler(struct acrn_vm *vm,
|
||||||
|
uint64_t start, uint64_t end);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user