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:
Mingqiang Chi 2018-11-05 19:05:34 +08:00 committed by lijinxia
parent 5a1f24473d
commit 73530055b6
11 changed files with 61 additions and 130 deletions

View File

@ -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

View File

@ -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));
}

View File

@ -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);

View File

@ -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;
}
/**

View File

@ -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);
}
/**

View File

@ -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.

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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)
{

View File

@ -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