mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-19 04:02:05 +00:00
hv: vioapic init for SOS VM on platforms with multiple IO-APICs
For SOS VM, when the target platform has multiple IO-APICs, there should be equal number of virtual IO-APICs. This patch adds support for emulating multiple vIOAPICs per VM. Tracked-On: #4151 Signed-off-by: Sainath Grandhi <sainath.grandhi@intel.com> Acked-by: Eddie Dong <eddie.dong@Intel.com>
This commit is contained in:
parent
f67ac09141
commit
fe5a108c7b
@ -898,8 +898,13 @@ vlapic_process_eoi(struct acrn_vlapic *vlapic)
|
|||||||
vlapic_update_ppr(vlapic);
|
vlapic_update_ppr(vlapic);
|
||||||
|
|
||||||
if (bitmap32_test((uint16_t)bitpos, &tmrptr[i].v)) {
|
if (bitmap32_test((uint16_t)bitpos, &tmrptr[i].v)) {
|
||||||
/* hook to vIOAPIC */
|
/*
|
||||||
vioapic_process_eoi(vlapic->vm, vector);
|
* Per Intel SDM 10.8.5, Software can inhibit the broadcast of
|
||||||
|
* EOI by setting bit 12 of the Spurious Interrupt Vector
|
||||||
|
* Register of the LAPIC.
|
||||||
|
* TODO: Check if the bit 12 "Suppress EOI Broadcasts" is set.
|
||||||
|
*/
|
||||||
|
vioapic_broadcast_eoi(vlapic->vm, vector);
|
||||||
}
|
}
|
||||||
|
|
||||||
vcpu_make_request(vlapic->vcpu, ACRN_REQUEST_EVENT);
|
vcpu_make_request(vlapic->vcpu, ACRN_REQUEST_EVENT);
|
||||||
@ -2513,7 +2518,7 @@ int32_t veoi_vmexit_handler(struct acrn_vcpu *vcpu)
|
|||||||
|
|
||||||
if (bitmap32_test((uint16_t)(vector & 0x1fU), &tmrptr[idx].v)) {
|
if (bitmap32_test((uint16_t)(vector & 0x1fU), &tmrptr[idx].v)) {
|
||||||
/* hook to vIOAPIC */
|
/* hook to vIOAPIC */
|
||||||
vioapic_process_eoi(vlapic->vm, vector);
|
vioapic_broadcast_eoi(vlapic->vm, vector);
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE_2L(TRACE_VMEXIT_APICV_VIRT_EOI, vector, 0UL);
|
TRACE_2L(TRACE_VMEXIT_APICV_VIRT_EOI, vector, 0UL);
|
||||||
|
@ -659,7 +659,7 @@ int32_t reset_vm(struct acrn_vm *vm)
|
|||||||
}
|
}
|
||||||
|
|
||||||
reset_vm_ioreqs(vm);
|
reset_vm_ioreqs(vm);
|
||||||
vioapic_reset(vm);
|
reset_vioapics(vm);
|
||||||
destroy_secure_world(vm, false);
|
destroy_secure_world(vm, false);
|
||||||
vm->sworld_control.flag.active = 0UL;
|
vm->sworld_control.flag.active = 0UL;
|
||||||
vm->state = VM_CREATED;
|
vm->state = VM_CREATED;
|
||||||
|
@ -73,6 +73,17 @@ uint32_t get_pic_pin_from_ioapic_pin(uint32_t pin_index)
|
|||||||
return pin_id;
|
return pin_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t get_platform_ioapic_info (struct ioapic_info **plat_ioapic_info)
|
||||||
|
{
|
||||||
|
*plat_ioapic_info = ioapic_array;
|
||||||
|
return ioapic_num;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t get_gsi_to_ioapic_index(uint32_t gsi)
|
||||||
|
{
|
||||||
|
return gsi_table_data[gsi].ioapic_info.index;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @pre gsi < NR_MAX_GSI
|
* @pre gsi < NR_MAX_GSI
|
||||||
*/
|
*/
|
||||||
|
@ -353,7 +353,7 @@ int32_t hcall_set_irqline(const struct acrn_vm *vm, uint16_t vmid,
|
|||||||
int32_t ret = -1;
|
int32_t ret = -1;
|
||||||
|
|
||||||
if (!is_poweroff_vm(target_vm) && is_postlaunched_vm(target_vm)) {
|
if (!is_poweroff_vm(target_vm) && is_postlaunched_vm(target_vm)) {
|
||||||
if (ops->gsi < vioapic_pincount(vm)) {
|
if (ops->gsi < get_vm_gsicount(vm)) {
|
||||||
if (ops->gsi < vpic_pincount()) {
|
if (ops->gsi < vpic_pincount()) {
|
||||||
/*
|
/*
|
||||||
* IRQ line for 8254 timer is connected to
|
* IRQ line for 8254 timer is connected to
|
||||||
@ -905,8 +905,13 @@ int32_t hcall_set_ptdev_intr_info(struct acrn_vm *vm, uint16_t vmid, uint64_t pa
|
|||||||
spinlock_obtain(&vpci->lock);
|
spinlock_obtain(&vpci->lock);
|
||||||
vdev = pci_find_vdev(vpci, bdf);
|
vdev = pci_find_vdev(vpci, bdf);
|
||||||
spinlock_release(&vpci->lock);
|
spinlock_release(&vpci->lock);
|
||||||
|
/*
|
||||||
|
* TODO: Change the hc_ptdev_irq structure member names
|
||||||
|
* virt_pin to virt_gsi
|
||||||
|
* phys_pin to phys_gsi
|
||||||
|
*/
|
||||||
if ((vdev != NULL) && (vdev->pdev->bdf.value == irq.phys_bdf)) {
|
if ((vdev != NULL) && (vdev->pdev->bdf.value == irq.phys_bdf)) {
|
||||||
if ((((!irq.intx.pic_pin) && (irq.intx.virt_pin < vioapic_pincount(target_vm))) ||
|
if ((((!irq.intx.pic_pin) && (irq.intx.virt_pin < get_vm_gsicount(target_vm))) ||
|
||||||
((irq.intx.pic_pin) && (irq.intx.virt_pin < vpic_pincount()))) &&
|
((irq.intx.pic_pin) && (irq.intx.virt_pin < vpic_pincount()))) &&
|
||||||
is_gsi_valid(irq.intx.phys_pin)) {
|
is_gsi_valid(irq.intx.phys_pin)) {
|
||||||
ret = ptirq_add_intx_remapping(target_vm, irq.intx.virt_pin,
|
ret = ptirq_add_intx_remapping(target_vm, irq.intx.virt_pin,
|
||||||
@ -954,8 +959,13 @@ hcall_reset_ptdev_intr_info(struct acrn_vm *vm, uint16_t vmid, uint64_t param)
|
|||||||
spinlock_obtain(&vpci->lock);
|
spinlock_obtain(&vpci->lock);
|
||||||
vdev = pci_find_vdev(vpci, bdf);
|
vdev = pci_find_vdev(vpci, bdf);
|
||||||
spinlock_release(&vpci->lock);
|
spinlock_release(&vpci->lock);
|
||||||
|
/*
|
||||||
|
* TODO: Change the hc_ptdev_irq structure member names
|
||||||
|
* virt_pin to virt_gsi
|
||||||
|
* phys_pin to phys_gsi
|
||||||
|
*/
|
||||||
if ((vdev != NULL) && (vdev->pdev->bdf.value == irq.phys_bdf)) {
|
if ((vdev != NULL) && (vdev->pdev->bdf.value == irq.phys_bdf)) {
|
||||||
if (((!irq.intx.pic_pin) && (irq.intx.virt_pin < vioapic_pincount(target_vm))) ||
|
if (((!irq.intx.pic_pin) && (irq.intx.virt_pin < get_vm_gsicount(target_vm))) ||
|
||||||
((irq.intx.pic_pin) && (irq.intx.virt_pin < vpic_pincount()))) {
|
((irq.intx.pic_pin) && (irq.intx.virt_pin < vpic_pincount()))) {
|
||||||
ptirq_remove_intx_remapping(target_vm, irq.intx.virt_pin, irq.intx.pic_pin);
|
ptirq_remove_intx_remapping(target_vm, irq.intx.virt_pin, irq.intx.pic_pin);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
@ -1173,7 +1173,7 @@ static void get_vioapic_info(char *str_arg, size_t str_max, uint16_t vmid)
|
|||||||
uint32_t delmode, vector, dest;
|
uint32_t delmode, vector, dest;
|
||||||
bool level, phys, remote_irr, mask;
|
bool level, phys, remote_irr, mask;
|
||||||
struct acrn_vm *vm = get_vm_from_vmid(vmid);
|
struct acrn_vm *vm = get_vm_from_vmid(vmid);
|
||||||
uint32_t gsi, pincount;
|
uint32_t gsi, gsi_count;
|
||||||
|
|
||||||
if (is_poweroff_vm(vm)) {
|
if (is_poweroff_vm(vm)) {
|
||||||
len = snprintf(str, size, "\r\nvm is not exist for vmid %hu", vmid);
|
len = snprintf(str, size, "\r\nvm is not exist for vmid %hu", vmid);
|
||||||
@ -1192,9 +1192,12 @@ static void get_vioapic_info(char *str_arg, size_t str_max, uint16_t vmid)
|
|||||||
size -= len;
|
size -= len;
|
||||||
str += len;
|
str += len;
|
||||||
|
|
||||||
pincount = vioapic_pincount(vm);
|
gsi_count = get_vm_gsicount(vm);
|
||||||
rte.full = 0UL;
|
rte.full = 0UL;
|
||||||
for (gsi = 0U; gsi < pincount; gsi++) {
|
for (gsi = 0U; gsi < gsi_count; gsi++) {
|
||||||
|
if (is_sos_vm(vm) && (!is_gsi_valid(gsi))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
vioapic_get_rte(vm, gsi, &rte);
|
vioapic_get_rte(vm, gsi, &rte);
|
||||||
mask = (rte.bits.intr_mask == IOAPIC_RTE_MASK_SET);
|
mask = (rte.bits.intr_mask == IOAPIC_RTE_MASK_SET);
|
||||||
remote_irr = (rte.bits.remote_irr == IOAPIC_RTE_REM_IRR);
|
remote_irr = (rte.bits.remote_irr == IOAPIC_RTE_REM_IRR);
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
#include <ept.h>
|
#include <ept.h>
|
||||||
#include <assign.h>
|
#include <assign.h>
|
||||||
#include <logmsg.h>
|
#include <logmsg.h>
|
||||||
|
#include <ioapic.h>
|
||||||
|
|
||||||
#define RTBL_RO_BITS ((uint32_t)0x00004000U | (uint32_t)0x00001000U) /*Remote IRR and Delivery Status bits*/
|
#define RTBL_RO_BITS ((uint32_t)0x00004000U | (uint32_t)0x00001000U) /*Remote IRR and Delivery Status bits*/
|
||||||
|
|
||||||
@ -45,16 +46,16 @@
|
|||||||
#define IOAPIC_ID_MASK 0x0f000000U
|
#define IOAPIC_ID_MASK 0x0f000000U
|
||||||
#define MASK_ALL_INTERRUPTS 0x0001000000010000UL
|
#define MASK_ALL_INTERRUPTS 0x0001000000010000UL
|
||||||
|
|
||||||
static inline struct acrn_vioapic *vm_ioapic(const struct acrn_vm *vm)
|
static inline struct acrn_vioapics *vm_ioapics(const struct acrn_vm *vm)
|
||||||
{
|
{
|
||||||
return (struct acrn_vioapic *)&(vm->arch_vm.vioapic);
|
return (struct acrn_vioapics *)&(vm->arch_vm.vioapics);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @pre pin < vioapic_pincount(vm)
|
* @pre pin < vioapic->nr_pins
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
vioapic_generate_intr(struct acrn_vioapic *vioapic, uint32_t pin)
|
vioapic_generate_intr(struct acrn_single_vioapic *vioapic, uint32_t pin)
|
||||||
{
|
{
|
||||||
uint32_t vector, dest, delmode;
|
uint32_t vector, dest, delmode;
|
||||||
union ioapic_rte rte;
|
union ioapic_rte rte;
|
||||||
@ -84,10 +85,10 @@ vioapic_generate_intr(struct acrn_vioapic *vioapic, uint32_t pin)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @pre pin < vioapic_pincount(vm)
|
* @pre pin < vioapic->nr_pins
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
vioapic_set_pinstate(struct acrn_vioapic *vioapic, uint32_t pin, uint32_t level)
|
vioapic_set_pinstate(struct acrn_single_vioapic *vioapic, uint32_t pin, uint32_t level)
|
||||||
{
|
{
|
||||||
uint32_t old_lvl;
|
uint32_t old_lvl;
|
||||||
union ioapic_rte rte;
|
union ioapic_rte rte;
|
||||||
@ -113,6 +114,30 @@ vioapic_set_pinstate(struct acrn_vioapic *vioapic, uint32_t pin, uint32_t level)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct acrn_single_vioapic *
|
||||||
|
vgsi_to_vioapic_and_vpin(const struct acrn_vm *vm, uint32_t vgsi, uint32_t *vpin)
|
||||||
|
{
|
||||||
|
struct acrn_single_vioapic *vioapic;
|
||||||
|
uint8_t vioapic_index = 0U;
|
||||||
|
|
||||||
|
if (is_sos_vm(vm)) {
|
||||||
|
/*
|
||||||
|
* Utilize platform ioapic_info for SOS VM
|
||||||
|
*/
|
||||||
|
vioapic_index = get_gsi_to_ioapic_index(vgsi);
|
||||||
|
if (vpin != NULL) {
|
||||||
|
*vpin = gsi_to_ioapic_pin(vgsi);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (vpin != NULL) {
|
||||||
|
*vpin = vgsi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vioapic = (struct acrn_single_vioapic *)&(vm->arch_vm.vioapics.vioapic_array[vioapic_index]);
|
||||||
|
return vioapic;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set vIOAPIC IRQ line status.
|
* @brief Set vIOAPIC IRQ line status.
|
||||||
*
|
*
|
||||||
@ -120,11 +145,11 @@ vioapic_set_pinstate(struct acrn_vioapic *vioapic, uint32_t pin, uint32_t level)
|
|||||||
* operation be done with ioapic lock.
|
* operation be done with ioapic lock.
|
||||||
*
|
*
|
||||||
* @param[in] vm Pointer to target VM
|
* @param[in] vm Pointer to target VM
|
||||||
* @param[in] irqline Target IRQ number
|
* @param[in] vgsi Target GSI number
|
||||||
* @param[in] operation Action options: GSI_SET_HIGH/GSI_SET_LOW/
|
* @param[in] operation Action options: GSI_SET_HIGH/GSI_SET_LOW/
|
||||||
* GSI_RAISING_PULSE/GSI_FALLING_PULSE
|
* GSI_RAISING_PULSE/GSI_FALLING_PULSE
|
||||||
*
|
*
|
||||||
* @pre irqline < vioapic_pincount(vm)
|
* @pre vgsi < get_vm_gsicount(vm)
|
||||||
* @pre vm != NULL
|
* @pre vm != NULL
|
||||||
* @pre vioapic->ready == true
|
* @pre vioapic->ready == true
|
||||||
* @return None
|
* @return None
|
||||||
@ -132,10 +157,10 @@ vioapic_set_pinstate(struct acrn_vioapic *vioapic, uint32_t pin, uint32_t level)
|
|||||||
void
|
void
|
||||||
vioapic_set_irqline_nolock(const struct acrn_vm *vm, uint32_t vgsi, uint32_t operation)
|
vioapic_set_irqline_nolock(const struct acrn_vm *vm, uint32_t vgsi, uint32_t operation)
|
||||||
{
|
{
|
||||||
struct acrn_vioapic *vioapic;
|
struct acrn_single_vioapic *vioapic;
|
||||||
uint32_t pin = vgsi;
|
uint32_t pin;
|
||||||
|
|
||||||
vioapic = vm_ioapic(vm);
|
vioapic = vgsi_to_vioapic_and_vpin(vm, vgsi, &pin);
|
||||||
|
|
||||||
switch (operation) {
|
switch (operation) {
|
||||||
case GSI_SET_HIGH:
|
case GSI_SET_HIGH:
|
||||||
@ -164,11 +189,11 @@ vioapic_set_irqline_nolock(const struct acrn_vm *vm, uint32_t vgsi, uint32_t ope
|
|||||||
* @brief Set vIOAPIC IRQ line status.
|
* @brief Set vIOAPIC IRQ line status.
|
||||||
*
|
*
|
||||||
* @param[in] vm Pointer to target VM
|
* @param[in] vm Pointer to target VM
|
||||||
* @param[in] irqline Target IRQ number
|
* @param[in] vgsi Target GSI number
|
||||||
* @param[in] operation Action options: GSI_SET_HIGH/GSI_SET_LOW/
|
* @param[in] operation Action options: GSI_SET_HIGH/GSI_SET_LOW/
|
||||||
* GSI_RAISING_PULSE/GSI_FALLING_PULSE
|
* GSI_RAISING_PULSE/GSI_FALLING_PULSE
|
||||||
*
|
*
|
||||||
* @pre irqline < vioapic_pincount(vm)
|
* @pre vgsi < get_vm_gsicount(vm)
|
||||||
* @pre vm != NULL
|
* @pre vm != NULL
|
||||||
*
|
*
|
||||||
* @return None
|
* @return None
|
||||||
@ -177,20 +202,21 @@ void
|
|||||||
vioapic_set_irqline_lock(const struct acrn_vm *vm, uint32_t vgsi, uint32_t operation)
|
vioapic_set_irqline_lock(const struct acrn_vm *vm, uint32_t vgsi, uint32_t operation)
|
||||||
{
|
{
|
||||||
uint64_t rflags;
|
uint64_t rflags;
|
||||||
uint32_t irqline = vgsi;
|
struct acrn_single_vioapic *vioapic;
|
||||||
struct acrn_vioapic *vioapic = vm_ioapic(vm);
|
|
||||||
|
vioapic = vgsi_to_vioapic_and_vpin(vm, vgsi, NULL);
|
||||||
if (vioapic->ready) {
|
if (vioapic->ready) {
|
||||||
spinlock_irqsave_obtain(&(vioapic->mtx), &rflags);
|
spinlock_irqsave_obtain(&(vioapic->mtx), &rflags);
|
||||||
vioapic_set_irqline_nolock(vm, irqline, operation);
|
vioapic_set_irqline_nolock(vm, vgsi, operation);
|
||||||
spinlock_irqrestore_release(&(vioapic->mtx), rflags);
|
spinlock_irqrestore_release(&(vioapic->mtx), rflags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t
|
static uint32_t
|
||||||
vioapic_indirect_read(const struct acrn_vioapic *vioapic, uint32_t addr)
|
vioapic_indirect_read(const struct acrn_single_vioapic *vioapic, uint32_t addr)
|
||||||
{
|
{
|
||||||
uint32_t regnum, ret = 0U;
|
uint32_t regnum, ret = 0U;
|
||||||
uint32_t pin, pincount = vioapic_pincount(vioapic->vm);
|
uint32_t pin, pincount = vioapic->nr_pins;
|
||||||
|
|
||||||
regnum = addr & 0xffU;
|
regnum = addr & 0xffU;
|
||||||
switch (regnum) {
|
switch (regnum) {
|
||||||
@ -229,7 +255,7 @@ vioapic_indirect_read(const struct acrn_vioapic *vioapic, uint32_t addr)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool vioapic_need_intr(const struct acrn_vioapic *vioapic, uint16_t pin)
|
static inline bool vioapic_need_intr(const struct acrn_single_vioapic *vioapic, uint16_t pin)
|
||||||
{
|
{
|
||||||
uint32_t lvl;
|
uint32_t lvl;
|
||||||
union ioapic_rte rte;
|
union ioapic_rte rte;
|
||||||
@ -250,11 +276,11 @@ static inline bool vioapic_need_intr(const struct acrn_vioapic *vioapic, uint16_
|
|||||||
* spinlock_irqsave_obtain(&(vioapic->mtx), &rflags) & spinlock_irqrestore_release(&(vioapic->mtx), rflags)
|
* spinlock_irqsave_obtain(&(vioapic->mtx), &rflags) & spinlock_irqrestore_release(&(vioapic->mtx), rflags)
|
||||||
* by caller.
|
* by caller.
|
||||||
*/
|
*/
|
||||||
static void vioapic_indirect_write(struct acrn_vioapic *vioapic, uint32_t addr, uint32_t data)
|
static void vioapic_indirect_write(struct acrn_single_vioapic *vioapic, uint32_t addr, uint32_t data)
|
||||||
{
|
{
|
||||||
union ioapic_rte last, new, changed;
|
union ioapic_rte last, new, changed;
|
||||||
uint32_t regnum;
|
uint32_t regnum;
|
||||||
uint32_t pin, pincount = vioapic_pincount(vioapic->vm);
|
uint32_t pin, pincount = vioapic->nr_pins;
|
||||||
|
|
||||||
regnum = addr & 0xffUL;
|
regnum = addr & 0xffUL;
|
||||||
switch (regnum) {
|
switch (regnum) {
|
||||||
@ -332,7 +358,8 @@ static void vioapic_indirect_write(struct acrn_vioapic *vioapic, uint32_t addr,
|
|||||||
if ((new.bits.intr_mask == IOAPIC_RTE_MASK_CLR) || (last.bits.intr_mask == IOAPIC_RTE_MASK_CLR)) {
|
if ((new.bits.intr_mask == IOAPIC_RTE_MASK_CLR) || (last.bits.intr_mask == IOAPIC_RTE_MASK_CLR)) {
|
||||||
/* VM enable intr */
|
/* VM enable intr */
|
||||||
/* NOTE: only support max 256 pin */
|
/* NOTE: only support max 256 pin */
|
||||||
(void)ptirq_intx_pin_remap(vioapic->vm, pin, INTX_CTLR_IOAPIC);
|
|
||||||
|
(void)ptirq_intx_pin_remap(vioapic->vm, vioapic->gsi_base + pin, INTX_CTLR_IOAPIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -352,7 +379,7 @@ static void vioapic_indirect_write(struct acrn_vioapic *vioapic, uint32_t addr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
vioapic_mmio_rw(struct acrn_vioapic *vioapic, uint64_t gpa,
|
vioapic_mmio_rw(struct acrn_single_vioapic *vioapic, uint64_t gpa,
|
||||||
uint32_t *data, bool do_read)
|
uint32_t *data, bool do_read)
|
||||||
{
|
{
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
@ -396,11 +423,10 @@ vioapic_mmio_rw(struct acrn_vioapic *vioapic, uint64_t gpa,
|
|||||||
* @pre vm != NULL
|
* @pre vm != NULL
|
||||||
* @pre vioapic->ready == true
|
* @pre vioapic->ready == true
|
||||||
*/
|
*/
|
||||||
void
|
static void
|
||||||
vioapic_process_eoi(struct acrn_vm *vm, uint32_t vector)
|
vioapic_process_eoi(struct acrn_single_vioapic *vioapic, uint32_t vector)
|
||||||
{
|
{
|
||||||
struct acrn_vioapic *vioapic;
|
uint32_t pin, pincount = vioapic->nr_pins;
|
||||||
uint32_t pin, pincount = vioapic_pincount(vm);
|
|
||||||
union ioapic_rte rte;
|
union ioapic_rte rte;
|
||||||
uint64_t rflags;
|
uint64_t rflags;
|
||||||
|
|
||||||
@ -408,7 +434,6 @@ vioapic_process_eoi(struct acrn_vm *vm, uint32_t vector)
|
|||||||
pr_err("vioapic_process_eoi: invalid vector %u", vector);
|
pr_err("vioapic_process_eoi: invalid vector %u", vector);
|
||||||
}
|
}
|
||||||
|
|
||||||
vioapic = vm_ioapic(vm);
|
|
||||||
dev_dbg(DBG_LEVEL_VIOAPIC, "ioapic processing eoi for vector %u", vector);
|
dev_dbg(DBG_LEVEL_VIOAPIC, "ioapic processing eoi for vector %u", vector);
|
||||||
|
|
||||||
/* notify device to ack if assigned pin */
|
/* notify device to ack if assigned pin */
|
||||||
@ -419,7 +444,7 @@ vioapic_process_eoi(struct acrn_vm *vm, uint32_t vector)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ptirq_intx_ack(vm, pin, INTX_CTLR_IOAPIC);
|
ptirq_intx_ack(vioapic->vm, vioapic->gsi_base + pin, INTX_CTLR_IOAPIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -444,14 +469,28 @@ vioapic_process_eoi(struct acrn_vm *vm, uint32_t vector)
|
|||||||
spinlock_irqrestore_release(&(vioapic->mtx), rflags);
|
spinlock_irqrestore_release(&(vioapic->mtx), rflags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void vioapic_broadcast_eoi(const struct acrn_vm *vm, uint32_t vector)
|
||||||
vioapic_reset(struct acrn_vm *vm)
|
{
|
||||||
|
struct acrn_single_vioapic *vioapic;
|
||||||
|
uint8_t vioapic_index;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For platforms with multiple IO-APICs, EOI message from LAPIC is
|
||||||
|
* broadcast to all IO-APICs. Emulating the same behavior here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (vioapic_index = 0U; vioapic_index < vm->arch_vm.vioapics.ioapic_num; vioapic_index++) {
|
||||||
|
vioapic = &(vm_ioapics(vm)->vioapic_array[vioapic_index]);
|
||||||
|
vioapic_process_eoi(vioapic, vector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void reset_one_vioapic(struct acrn_single_vioapic *vioapic)
|
||||||
{
|
{
|
||||||
uint32_t pin, pincount;
|
uint32_t pin, pincount;
|
||||||
struct acrn_vioapic *vioapic = vm_ioapic(vm);
|
|
||||||
|
|
||||||
/* Initialize all redirection entries to mask all interrupts */
|
/* Initialize all redirection entries to mask all interrupts */
|
||||||
pincount = vioapic_pincount(vm);
|
pincount = vioapic->nr_pins;
|
||||||
for (pin = 0U; pin < pincount; pin++) {
|
for (pin = 0U; pin < pincount; pin++) {
|
||||||
vioapic->rtbl[pin].full = MASK_ALL_INTERRUPTS;
|
vioapic->rtbl[pin].full = MASK_ALL_INTERRUPTS;
|
||||||
}
|
}
|
||||||
@ -459,35 +498,80 @@ vioapic_reset(struct acrn_vm *vm)
|
|||||||
vioapic->ioregsel = 0U;
|
vioapic->ioregsel = 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void reset_vioapics(const struct acrn_vm *vm)
|
||||||
|
{
|
||||||
|
struct acrn_vioapics *vioapics = vm_ioapics(vm);
|
||||||
|
uint8_t vioapic_index;
|
||||||
|
|
||||||
|
for (vioapic_index = 0U; vioapic_index < vioapics->ioapic_num; vioapic_index++) {
|
||||||
|
reset_one_vioapic(&vioapics->vioapic_array[vioapic_index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
vioapic_init(struct acrn_vm *vm)
|
vioapic_init(struct acrn_vm *vm)
|
||||||
{
|
{
|
||||||
vm->arch_vm.vioapic.vm = vm;
|
struct ioapic_info *platform_ioapic_info;
|
||||||
spinlock_init(&(vm->arch_vm.vioapic.mtx));
|
uint8_t platform_ioapic_num;
|
||||||
|
uint8_t vioapic_index;
|
||||||
|
struct acrn_single_vioapic *vioapic;
|
||||||
|
|
||||||
vm->arch_vm.vioapic.base_addr = VIOAPIC_BASE;
|
|
||||||
if (is_sos_vm(vm)) {
|
if (is_sos_vm(vm)) {
|
||||||
vm->arch_vm.vioapic.nr_pins = REDIR_ENTRIES_HW;
|
platform_ioapic_num = get_platform_ioapic_info(&platform_ioapic_info);
|
||||||
} else {
|
vm->arch_vm.vioapics.ioapic_num = platform_ioapic_num;
|
||||||
vm->arch_vm.vioapic.nr_pins = VIOAPIC_RTE_NUM;
|
for (vioapic_index = 0U; vioapic_index < platform_ioapic_num; vioapic_index++) {
|
||||||
}
|
vioapic = &vm->arch_vm.vioapics.vioapic_array[vioapic_index];
|
||||||
|
spinlock_init(&(vioapic->mtx));
|
||||||
|
vioapic->nr_pins = platform_ioapic_info[vioapic_index].nr_pins;
|
||||||
|
vioapic->base_addr = platform_ioapic_info[vioapic_index].addr;
|
||||||
|
vioapic->gsi_base = platform_ioapic_info[vioapic_index].gsi_base;
|
||||||
|
|
||||||
vioapic_reset(vm);
|
vioapic->vm = vm;
|
||||||
|
reset_one_vioapic(vioapic);
|
||||||
|
|
||||||
register_mmio_emulation_handler(vm,
|
register_mmio_emulation_handler(vm,
|
||||||
vioapic_mmio_access_handler,
|
vioapic_mmio_access_handler,
|
||||||
(uint64_t)vm->arch_vm.vioapic.base_addr,
|
(uint64_t)vioapic->base_addr,
|
||||||
(uint64_t)vm->arch_vm.vioapic.base_addr + VIOAPIC_SIZE,
|
(uint64_t)vioapic->base_addr + VIOAPIC_SIZE,
|
||||||
(void *)&vm->arch_vm.vioapic, false);
|
(void *)vioapic, false);
|
||||||
ept_del_mr(vm, (uint64_t *)vm->arch_vm.nworld_eptp,
|
ept_del_mr(vm, (uint64_t *)vm->arch_vm.nworld_eptp,
|
||||||
(uint64_t)vm->arch_vm.vioapic.base_addr, VIOAPIC_SIZE);
|
(uint64_t)vioapic->base_addr, VIOAPIC_SIZE);
|
||||||
vm->arch_vm.vioapic.ready = true;
|
vioapic->ready = true;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Maximum number of GSI is computed as GSI base of the IOAPIC i.e. enumerated last in ACPI MADT
|
||||||
|
* plus the number of interrupt pins of that IOAPIC.
|
||||||
|
*/
|
||||||
|
vm->arch_vm.vioapics.nr_gsi = platform_ioapic_info[platform_ioapic_num - 1U].gsi_base +
|
||||||
|
platform_ioapic_info[platform_ioapic_num - 1U].nr_pins;
|
||||||
|
} else {
|
||||||
|
vm->arch_vm.vioapics.ioapic_num = 1U;
|
||||||
|
vioapic = &vm->arch_vm.vioapics.vioapic_array[0U];
|
||||||
|
spinlock_init(&(vioapic->mtx));
|
||||||
|
vioapic->nr_pins = VIOAPIC_RTE_NUM;
|
||||||
|
vioapic->base_addr = VIOAPIC_BASE;
|
||||||
|
vioapic->gsi_base = 0U;
|
||||||
|
vioapic->vm = vm;
|
||||||
|
reset_one_vioapic(&vm->arch_vm.vioapics.vioapic_array[0U]);
|
||||||
|
|
||||||
|
|
||||||
|
register_mmio_emulation_handler(vm,
|
||||||
|
vioapic_mmio_access_handler,
|
||||||
|
(uint64_t)vioapic->base_addr,
|
||||||
|
(uint64_t)vioapic->base_addr + VIOAPIC_SIZE,
|
||||||
|
(void *)vioapic, false);
|
||||||
|
ept_del_mr(vm, (uint64_t *)vm->arch_vm.nworld_eptp,
|
||||||
|
(uint64_t)vioapic->base_addr, VIOAPIC_SIZE);
|
||||||
|
vioapic->ready = true;
|
||||||
|
|
||||||
|
vm->arch_vm.vioapics.nr_gsi = VIOAPIC_RTE_NUM;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t
|
uint32_t
|
||||||
vioapic_pincount(const struct acrn_vm *vm)
|
get_vm_gsicount(const struct acrn_vm *vm)
|
||||||
{
|
{
|
||||||
return vm->arch_vm.vioapic.nr_pins;
|
return vm->arch_vm.vioapics.nr_gsi;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -496,7 +580,7 @@ vioapic_pincount(const struct acrn_vm *vm)
|
|||||||
*/
|
*/
|
||||||
int32_t vioapic_mmio_access_handler(struct io_request *io_req, void *handler_private_data)
|
int32_t vioapic_mmio_access_handler(struct io_request *io_req, void *handler_private_data)
|
||||||
{
|
{
|
||||||
struct acrn_vioapic *vioapic = (struct acrn_vioapic *)handler_private_data;
|
struct acrn_single_vioapic *vioapic = (struct acrn_single_vioapic *)handler_private_data;
|
||||||
struct mmio_request *mmio = &io_req->reqs.mmio;
|
struct mmio_request *mmio = &io_req->reqs.mmio;
|
||||||
uint64_t gpa = mmio->address;
|
uint64_t gpa = mmio->address;
|
||||||
int32_t ret = 0;
|
int32_t ret = 0;
|
||||||
@ -522,14 +606,15 @@ int32_t vioapic_mmio_access_handler(struct io_request *io_req, void *handler_pri
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @pre vm->arch_vm.vioapic != NULL
|
* @pre vm->arch_vm.vioapics != NULL
|
||||||
|
* @pre vgsi < get_vm_gsicount(vm)
|
||||||
* @pre rte != NULL
|
* @pre rte != NULL
|
||||||
*/
|
*/
|
||||||
void vioapic_get_rte(const struct acrn_vm *vm, uint32_t vgsi, union ioapic_rte *rte)
|
void vioapic_get_rte(const struct acrn_vm *vm, uint32_t vgsi, union ioapic_rte *rte)
|
||||||
{
|
{
|
||||||
struct acrn_vioapic *vioapic;
|
struct acrn_single_vioapic *vioapic;
|
||||||
uint32_t pin = vgsi;
|
uint32_t pin;
|
||||||
|
vioapic = vgsi_to_vioapic_and_vpin(vm, vgsi, &pin);
|
||||||
|
|
||||||
vioapic = vm_ioapic(vm);
|
|
||||||
*rte = vioapic->rtbl[pin];
|
*rte = vioapic->rtbl[pin];
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,7 @@ struct vm_arch {
|
|||||||
void *sworld_eptp;
|
void *sworld_eptp;
|
||||||
struct memory_ops ept_mem_ops;
|
struct memory_ops ept_mem_ops;
|
||||||
|
|
||||||
struct acrn_vioapic vioapic; /* Virtual IOAPIC base address */
|
struct acrn_vioapics vioapics; /* Virtual IOAPIC/s */
|
||||||
struct acrn_vpic vpic; /* Virtual PIC */
|
struct acrn_vpic vpic; /* Virtual PIC */
|
||||||
#ifdef CONFIG_HYPERV_ENABLED
|
#ifdef CONFIG_HYPERV_ENABLED
|
||||||
struct acrn_hyperv hyperv;
|
struct acrn_hyperv hyperv;
|
||||||
|
@ -26,6 +26,8 @@ uint32_t gsi_to_ioapic_pin(uint32_t gsi);
|
|||||||
int32_t init_ioapic_id_info(void);
|
int32_t init_ioapic_id_info(void);
|
||||||
uint8_t ioapic_irq_to_ioapic_id(uint32_t irq);
|
uint8_t ioapic_irq_to_ioapic_id(uint32_t irq);
|
||||||
|
|
||||||
|
uint8_t get_platform_ioapic_info (struct ioapic_info **plat_ioapic_info);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @defgroup ioapic_ext_apis IOAPIC External Interfaces
|
* @defgroup ioapic_ext_apis IOAPIC External Interfaces
|
||||||
*
|
*
|
||||||
@ -108,6 +110,7 @@ struct gsi_table {
|
|||||||
|
|
||||||
void *gsi_to_ioapic_base(uint32_t gsi);
|
void *gsi_to_ioapic_base(uint32_t gsi);
|
||||||
uint32_t get_max_nr_gsi(void);
|
uint32_t get_max_nr_gsi(void);
|
||||||
|
uint8_t get_gsi_to_ioapic_index(uint32_t gsi);
|
||||||
uint32_t get_pic_pin_from_ioapic_pin(uint32_t pin_index);
|
uint32_t get_pic_pin_from_ioapic_pin(uint32_t pin_index);
|
||||||
bool is_gsi_valid(uint32_t gsi);
|
bool is_gsi_valid(uint32_t gsi);
|
||||||
#endif /* IOAPIC_H */
|
#endif /* IOAPIC_H */
|
||||||
|
@ -48,11 +48,16 @@
|
|||||||
|
|
||||||
#define IOAPIC_RTE_LOW_INTVEC ((uint32_t)IOAPIC_RTE_INTVEC)
|
#define IOAPIC_RTE_LOW_INTVEC ((uint32_t)IOAPIC_RTE_INTVEC)
|
||||||
|
|
||||||
struct acrn_vioapic {
|
/*
|
||||||
struct acrn_vm *vm;
|
* id field is used to emulate the IOAPIC_ID register of vIOAPIC
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct acrn_single_vioapic {
|
||||||
spinlock_t mtx;
|
spinlock_t mtx;
|
||||||
|
struct acrn_vm *vm;
|
||||||
uint32_t base_addr;
|
uint32_t base_addr;
|
||||||
uint32_t nr_pins;
|
uint32_t nr_pins;
|
||||||
|
uint32_t gsi_base;
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
bool ready;
|
bool ready;
|
||||||
uint32_t ioregsel;
|
uint32_t ioregsel;
|
||||||
@ -61,8 +66,19 @@ struct acrn_vioapic {
|
|||||||
uint64_t pin_state[STATE_BITMAP_SIZE];
|
uint64_t pin_state[STATE_BITMAP_SIZE];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ioapic_num represents the number of IO-APICs emulated for the VM.
|
||||||
|
* nr_gsi represents the maximum number of GSI emulated for the VM.
|
||||||
|
*/
|
||||||
|
struct acrn_vioapics {
|
||||||
|
uint8_t ioapic_num;
|
||||||
|
uint32_t nr_gsi;
|
||||||
|
struct acrn_single_vioapic vioapic_array[CONFIG_MAX_IOAPIC_NUM];
|
||||||
|
};
|
||||||
|
|
||||||
|
void dump_vioapic(struct acrn_vm *vm);
|
||||||
void vioapic_init(struct acrn_vm *vm);
|
void vioapic_init(struct acrn_vm *vm);
|
||||||
void vioapic_reset(struct acrn_vm *vm);
|
void reset_vioapics(const struct acrn_vm *vm);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -102,8 +118,8 @@ void vioapic_set_irqline_lock(const struct acrn_vm *vm, uint32_t vgsi, uint32_t
|
|||||||
*/
|
*/
|
||||||
void vioapic_set_irqline_nolock(const struct acrn_vm *vm, uint32_t vgsi, uint32_t operation);
|
void vioapic_set_irqline_nolock(const struct acrn_vm *vm, uint32_t vgsi, uint32_t operation);
|
||||||
|
|
||||||
uint32_t vioapic_pincount(const struct acrn_vm *vm);
|
uint32_t get_vm_gsicount(const struct acrn_vm *vm);
|
||||||
void vioapic_process_eoi(struct acrn_vm *vm, uint32_t vector);
|
void vioapic_broadcast_eoi(const struct acrn_vm *vm, uint32_t vector);
|
||||||
void vioapic_get_rte(const struct acrn_vm *vm, uint32_t vgsi, union ioapic_rte *rte);
|
void vioapic_get_rte(const struct acrn_vm *vm, uint32_t vgsi, union ioapic_rte *rte);
|
||||||
int32_t vioapic_mmio_access_handler(struct io_request *io_req, void *handler_private_data);
|
int32_t vioapic_mmio_access_handler(struct io_request *io_req, void *handler_private_data);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user