mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-09-22 01:07:57 +00:00
hv:Replace dynamic memory with static for port io
-- Add emulated port io index -- Add emulated pio array in vm structure -- Remove port list in vm structure -- Remove free_io_emulation_resource/register_io_handler/ create_io_handler APIs v2-->v3: -- not add 'is_emulated', check len == 0U -- Check if io_read/io_write handler is NULL before calling -- Replace ENUM with MACRO for emulated pio index to avoid MISRA-C violations v1-->v2: -- Remove EMUL_PIO_NUM in Kconfig, add emulated pio index for PIC/PCI/UART/RTC/PM Tracked-On: #861 Signed-off-by: Mingqiang Chi <mingqiang.chi@intel.com> Reviewed-by: Jason Chen CJ <jason.cj.chen@intel.com> Acked-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
@@ -187,7 +187,7 @@ static void pm1ab_io_write(__unused struct acrn_vm *vm, uint16_t addr, size_t wi
|
||||
}
|
||||
|
||||
static void
|
||||
register_gas_io_handler(struct acrn_vm *vm, const struct acpi_generic_address *gas)
|
||||
register_gas_io_handler(struct acrn_vm *vm, uint32_t pio_idx, const struct acpi_generic_address *gas)
|
||||
{
|
||||
uint8_t io_len[5] = {0, 1, 2, 4, 8};
|
||||
struct vm_io_range gas_io;
|
||||
@@ -203,7 +203,7 @@ register_gas_io_handler(struct acrn_vm *vm, const struct acpi_generic_address *g
|
||||
gas_io.base = (uint16_t)gas->address;
|
||||
gas_io.len = io_len[gas->access_size];
|
||||
|
||||
register_io_emulation_handler(vm, &gas_io,
|
||||
register_io_emulation_handler(vm, pio_idx, &gas_io,
|
||||
&pm1ab_io_read, &pm1ab_io_write);
|
||||
|
||||
pr_dbg("Enable PM1A trap for VM %d, port 0x%x, size %d\n",
|
||||
@@ -214,8 +214,8 @@ void register_pm1ab_handler(struct acrn_vm *vm)
|
||||
{
|
||||
struct pm_s_state_data *sx_data = vm->pm.sx_state_data;
|
||||
|
||||
register_gas_io_handler(vm, &(sx_data->pm1a_evt));
|
||||
register_gas_io_handler(vm, &(sx_data->pm1b_evt));
|
||||
register_gas_io_handler(vm, &(sx_data->pm1a_cnt));
|
||||
register_gas_io_handler(vm, &(sx_data->pm1b_cnt));
|
||||
register_gas_io_handler(vm, PM1A_EVT_PIO_IDX, &(sx_data->pm1a_evt));
|
||||
register_gas_io_handler(vm, PM1B_EVT_PIO_IDX, &(sx_data->pm1b_evt));
|
||||
register_gas_io_handler(vm, PM1A_CNT_PIO_IDX, &(sx_data->pm1a_cnt));
|
||||
register_gas_io_handler(vm, PM1B_CNT_PIO_IDX, &(sx_data->pm1b_cnt));
|
||||
}
|
||||
|
@@ -211,9 +211,6 @@ int shutdown_vm(struct acrn_vm *vm)
|
||||
/* Free EPT allocated resources assigned to VM */
|
||||
destroy_ept(vm);
|
||||
|
||||
/* TODO: De-initialize I/O Emulation */
|
||||
free_io_emulation_resource(vm);
|
||||
|
||||
/* Free iommu */
|
||||
if (vm->iommu != NULL) {
|
||||
destroy_iommu_domain(vm->iommu);
|
||||
|
@@ -196,39 +196,40 @@ hv_emulate_pio(const struct acrn_vcpu *vcpu, struct io_request *io_req)
|
||||
int32_t status = -ENODEV;
|
||||
uint16_t port, size;
|
||||
uint32_t mask;
|
||||
uint32_t idx;
|
||||
struct acrn_vm *vm = vcpu->vm;
|
||||
struct pio_request *pio_req = &io_req->reqs.pio;
|
||||
struct vm_io_handler *handler;
|
||||
struct vm_io_handler_desc *handler;
|
||||
|
||||
port = (uint16_t)pio_req->address;
|
||||
size = (uint16_t)pio_req->size;
|
||||
mask = 0xFFFFFFFFU >> (32U - 8U * size);
|
||||
|
||||
for (handler = vm->arch_vm.io_handler;
|
||||
handler != NULL; handler = handler->next) {
|
||||
uint16_t base = handler->desc.addr;
|
||||
uint16_t end = base + (uint16_t)handler->desc.len;
|
||||
for (idx = 0U; idx < EMUL_PIO_IDX_MAX; idx++) {
|
||||
handler = &(vm->arch_vm.emul_pio[idx]);
|
||||
if (handler->len == 0U) {
|
||||
continue;
|
||||
}
|
||||
uint16_t base = handler->addr;
|
||||
uint16_t end = base + (uint16_t)handler->len;
|
||||
|
||||
if ((port >= end) || (port + size <= base)) {
|
||||
continue;
|
||||
} else if (!((port >= base) && ((port + size) <= end))) {
|
||||
pr_fatal("Err:IO, port 0x%04x, size=%hu spans devices",
|
||||
port, size);
|
||||
pr_fatal("Err:IO, port 0x%04x, size=%hu spans devices", port, size);
|
||||
status = -EIO;
|
||||
break;
|
||||
} else {
|
||||
if (pio_req->direction == REQUEST_WRITE) {
|
||||
handler->desc.io_write(vm, port, size,
|
||||
pio_req->value & mask);
|
||||
|
||||
pr_dbg("IO write on port %04x, data %08x", port,
|
||||
pio_req->value & mask);
|
||||
if (handler->io_write) {
|
||||
handler->io_write(vm, port, size, pio_req->value & mask);
|
||||
}
|
||||
pr_dbg("IO write on port %04x, data %08x", port, pio_req->value & mask);
|
||||
} else {
|
||||
pio_req->value = handler->desc.io_read(vm, port,
|
||||
size);
|
||||
|
||||
pr_dbg("IO read on port %04x, data %08x",
|
||||
port, pio_req->value);
|
||||
if (handler->io_read) {
|
||||
pio_req->value = handler->io_read(vm, port, size);
|
||||
}
|
||||
pr_dbg("IO read on port %04x, data %08x", port, pio_req->value);
|
||||
}
|
||||
status = 0;
|
||||
break;
|
||||
@@ -394,37 +395,6 @@ int32_t pio_instr_vmexit_handler(struct acrn_vcpu *vcpu)
|
||||
return status;
|
||||
}
|
||||
|
||||
static void register_io_handler(struct acrn_vm *vm, struct vm_io_handler *hdlr)
|
||||
{
|
||||
if (vm->arch_vm.io_handler != NULL) {
|
||||
hdlr->next = vm->arch_vm.io_handler;
|
||||
}
|
||||
|
||||
vm->arch_vm.io_handler = hdlr;
|
||||
}
|
||||
|
||||
static void empty_io_handler_list(struct acrn_vm *vm)
|
||||
{
|
||||
struct vm_io_handler *handler = vm->arch_vm.io_handler;
|
||||
struct vm_io_handler *tmp;
|
||||
|
||||
while (handler != NULL) {
|
||||
tmp = handler;
|
||||
handler = tmp->next;
|
||||
free(tmp);
|
||||
}
|
||||
vm->arch_vm.io_handler = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Free I/O bitmaps and port I/O handlers of \p vm
|
||||
*
|
||||
* @param vm The VM whose I/O bitmaps and handlers are to be freed
|
||||
*/
|
||||
void free_io_emulation_resource(struct acrn_vm *vm)
|
||||
{
|
||||
empty_io_handler_list(vm);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Allow a VM to access a port I/O range
|
||||
@@ -464,27 +434,6 @@ static void deny_guest_pio_access(struct acrn_vm *vm, uint16_t port_address,
|
||||
}
|
||||
}
|
||||
|
||||
static struct vm_io_handler *create_io_handler(uint32_t port, uint32_t len,
|
||||
io_read_fn_t io_read_fn_ptr,
|
||||
io_write_fn_t io_write_fn_ptr)
|
||||
{
|
||||
|
||||
struct vm_io_handler *handler;
|
||||
|
||||
handler = calloc(1U, sizeof(struct vm_io_handler));
|
||||
|
||||
if (handler != NULL) {
|
||||
handler->desc.addr = port;
|
||||
handler->desc.len = len;
|
||||
handler->desc.io_read = io_read_fn_ptr;
|
||||
handler->desc.io_write = io_write_fn_ptr;
|
||||
} else {
|
||||
pr_err("Error: out of memory");
|
||||
}
|
||||
|
||||
return handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize the I/O bitmap for \p vm
|
||||
*
|
||||
@@ -503,30 +452,23 @@ void setup_io_bitmap(struct acrn_vm *vm)
|
||||
/**
|
||||
* @brief Register a port I/O handler
|
||||
*
|
||||
* @param vm The VM to which the port I/O handlers are registered
|
||||
* @param range The port I/O range that the given handlers can emulate
|
||||
* @param vm The VM to which the port I/O handlers are registered
|
||||
* @param pio_idx The emulated port io index
|
||||
* @param range The emulated port io range
|
||||
* @param io_read_fn_ptr The handler for emulating reads from the given range
|
||||
* @param io_write_fn_ptr The handler for emulating writes to the given range
|
||||
* @pre pio_idx < EMUL_PIO_IDX_MAX
|
||||
*/
|
||||
void register_io_emulation_handler(struct acrn_vm *vm, const struct vm_io_range *range,
|
||||
io_read_fn_t io_read_fn_ptr,
|
||||
io_write_fn_t io_write_fn_ptr)
|
||||
void register_io_emulation_handler(struct acrn_vm *vm, uint32_t pio_idx,
|
||||
const struct vm_io_range *range, io_read_fn_t io_read_fn_ptr, io_write_fn_t io_write_fn_ptr)
|
||||
{
|
||||
struct vm_io_handler *handler = NULL;
|
||||
|
||||
if ((io_read_fn_ptr == NULL) || (io_write_fn_ptr == NULL)) {
|
||||
pr_err("Invalid IO handler.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_vm0(vm)) {
|
||||
deny_guest_pio_access(vm, range->base, range->len);
|
||||
}
|
||||
|
||||
handler = create_io_handler(range->base,
|
||||
range->len, io_read_fn_ptr, io_write_fn_ptr);
|
||||
|
||||
register_io_handler(vm, handler);
|
||||
vm->arch_vm.emul_pio[pio_idx].addr = range->base;
|
||||
vm->arch_vm.emul_pio[pio_idx].len = range->len;
|
||||
vm->arch_vm.emul_pio[pio_idx].io_read = io_read_fn_ptr;
|
||||
vm->arch_vm.emul_pio[pio_idx].io_write = io_write_fn_ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user