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:
parent
5a1f24473d
commit
73530055b6
|
@ -316,9 +316,6 @@ I/O bitmaps and register or unregister I/O handlers:
|
|||
.. doxygenfunction:: allow_guest_pio_access
|
||||
:project: Project ACRN
|
||||
|
||||
.. doxygenfunction:: free_io_emulation_resource
|
||||
:project: Project ACRN
|
||||
|
||||
.. doxygenfunction:: register_io_emulation_handler
|
||||
:project: Project ACRN
|
||||
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
@ -504,29 +453,22 @@ 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 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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -327,7 +327,7 @@ static void vuart_register_io_handler(struct acrn_vm *vm)
|
|||
.len = 8U
|
||||
};
|
||||
|
||||
register_io_emulation_handler(vm, &range, vuart_read, vuart_write);
|
||||
register_io_emulation_handler(vm, UART_PIO_IDX, &range, vuart_read, vuart_write);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -131,7 +131,7 @@ void vpci_init(struct acrn_vm *vm)
|
|||
#endif
|
||||
|
||||
if ((vpci->ops->init != NULL) && (vpci->ops->init(vm) == 0)) {
|
||||
register_io_emulation_handler(vm, &pci_cfg_range,
|
||||
register_io_emulation_handler(vm, PCI_PIO_IDX, &pci_cfg_range,
|
||||
&pci_cfg_io_read, &pci_cfg_io_write);
|
||||
/* This is a tmp solution to avoid sos reboot failure, it need pass-thru IO port CF9 for Reset Control
|
||||
* register.
|
||||
|
|
|
@ -866,11 +866,11 @@ static void vpic_register_io_handler(struct acrn_vm *vm)
|
|||
.len = 2U
|
||||
};
|
||||
|
||||
register_io_emulation_handler(vm, &master_range,
|
||||
register_io_emulation_handler(vm, PIC_MASTER_PIO_IDX, &master_range,
|
||||
&vpic_master_io_read, &vpic_master_io_write);
|
||||
register_io_emulation_handler(vm, &slave_range,
|
||||
register_io_emulation_handler(vm, PIC_SLAVE_PIO_IDX, &slave_range,
|
||||
&vpic_slave_io_read, &vpic_slave_io_write);
|
||||
register_io_emulation_handler(vm, &elcr_range,
|
||||
register_io_emulation_handler(vm, PIC_ELC_PIO_IDX, &elcr_range,
|
||||
&vpic_elc_io_read, &vpic_elc_io_write);
|
||||
}
|
||||
|
||||
|
|
|
@ -77,5 +77,5 @@ void vrtc_init(struct acrn_vm *vm)
|
|||
/* Initializing the CMOS RAM offset to 0U */
|
||||
vm->vrtc_offset = 0U;
|
||||
|
||||
register_io_emulation_handler(vm, &range, vrtc_read, vrtc_write);
|
||||
register_io_emulation_handler(vm, RTC_PIO_IDX, &range, vrtc_read, vrtc_write);
|
||||
}
|
||||
|
|
|
@ -103,15 +103,7 @@ struct vm_arch {
|
|||
void *tmp_pg_array; /* Page array for tmp guest paging struct */
|
||||
struct acrn_vioapic vioapic; /* Virtual IOAPIC base address */
|
||||
struct acrn_vpic vpic; /* Virtual PIC */
|
||||
/**
|
||||
* A link to the IO handler of this VM.
|
||||
* We only register io handle to this link
|
||||
* when create VM on sequences and ungister it when
|
||||
* destory VM. So there no need lock to prevent preempt.
|
||||
* Besides, there only a few io handlers now, we don't
|
||||
* need binary search temporary.
|
||||
*/
|
||||
struct vm_io_handler *io_handler;
|
||||
struct vm_io_handler_desc emul_pio[EMUL_PIO_IDX_MAX];
|
||||
|
||||
/* reference to virtual platform to come here (as needed) */
|
||||
} __aligned(CPU_PAGE_SIZE);
|
||||
|
|
|
@ -9,6 +9,19 @@
|
|||
|
||||
#include <types.h>
|
||||
|
||||
/* Define emulated port IO index */
|
||||
#define PIC_MASTER_PIO_IDX 0U
|
||||
#define PIC_SLAVE_PIO_IDX (PIC_MASTER_PIO_IDX + 1U)
|
||||
#define PIC_ELC_PIO_IDX (PIC_SLAVE_PIO_IDX + 1U)
|
||||
#define PCI_PIO_IDX (PIC_ELC_PIO_IDX + 1U)
|
||||
#define UART_PIO_IDX (PCI_PIO_IDX + 1U)
|
||||
#define PM1A_EVT_PIO_IDX (UART_PIO_IDX + 1U)
|
||||
#define PM1A_CNT_PIO_IDX (PM1A_EVT_PIO_IDX + 1U)
|
||||
#define PM1B_EVT_PIO_IDX (PM1A_CNT_PIO_IDX + 1U)
|
||||
#define PM1B_CNT_PIO_IDX (PM1B_EVT_PIO_IDX + 1U)
|
||||
#define RTC_PIO_IDX (PM1B_CNT_PIO_IDX + 1U)
|
||||
#define EMUL_PIO_IDX_MAX (RTC_PIO_IDX + 1U)
|
||||
|
||||
/* Write 1 byte to specified I/O port */
|
||||
static inline void pio_write8(uint8_t value, uint16_t port)
|
||||
{
|
||||
|
|
|
@ -47,7 +47,7 @@ struct vm_io_range {
|
|||
uint32_t flags; /**< IO port attributes */
|
||||
};
|
||||
|
||||
struct vm_io_handler;
|
||||
struct vm_io_handler_desc;
|
||||
struct acrn_vm;
|
||||
struct acrn_vcpu;
|
||||
|
||||
|
@ -108,10 +108,6 @@ struct vm_io_handler_desc {
|
|||
io_write_fn_t io_write;
|
||||
};
|
||||
|
||||
struct vm_io_handler {
|
||||
struct vm_io_handler *next;
|
||||
struct vm_io_handler_desc desc;
|
||||
};
|
||||
|
||||
#define IO_ATTR_R 0U
|
||||
#define IO_ATTR_RW 1U
|
||||
|
@ -187,13 +183,6 @@ int32_t pio_instr_vmexit_handler(struct acrn_vcpu *vcpu);
|
|||
*/
|
||||
void setup_io_bitmap(struct acrn_vm *vm);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @brief Allow a VM to access a port I/O range
|
||||
*
|
||||
|
@ -211,13 +200,14 @@ void allow_guest_pio_access(struct acrn_vm *vm, uint16_t port_address,
|
|||
* @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 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);
|
||||
|
||||
/**
|
||||
* @brief Register a MMIO handler
|
||||
|
|
Loading…
Reference in New Issue