mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 10:11:27 +01:00
This patch add virtual IOAPIC support for VMX guest.
Signed-off-by: Yunhong Jiang <yunhong.jiang@intel.com> Signed-off-by: Xin Li <xin.b.li@intel.com> Signed-off-by: Eddie Dong <eddie.dong@intel.com> Signed-off-by: Jun Nakajima <jun.nakajima@intel.com>
This commit is contained in:
1 parent
27ec4c403f
commit
4fe21ad371
8 files changed
+772
-4
No files matched your search
+11
-1
@@ -33,6 +33,7 @@
|
||||
#include <asm/vmx.h>
|
||||
#include <public/io/vmx_vpic.h>
|
||||
#include <asm/current.h>
|
||||
#include <asm/vmx_vioapic.h>
|
||||
#include <asm/vmx_vlapic.h>
|
||||
|
||||
/* set irq level. If an edge is detected, then the IRR is set to 1 */
|
||||
@@ -124,6 +125,7 @@ void pic_set_irq_new(void *opaque, int irq, int level)
|
||||
{
|
||||
struct vmx_virpic *s = opaque;
|
||||
|
||||
vmx_vioapic_set_irq(current->domain, irq, level);
|
||||
pic_set_irq1(&s->pics[irq >> 3], irq & 7, level);
|
||||
/* used for IOAPIC irqs */
|
||||
if (s->alt_irq_func)
|
||||
@@ -135,6 +137,7 @@ void do_pic_irqs (struct vmx_virpic *s, uint16_t irqs)
|
||||
{
|
||||
s->pics[1].irr |= (uint8_t)(irqs >> 8);
|
||||
s->pics[0].irr |= (uint8_t) irqs;
|
||||
vmx_vioapic_do_irqs(current->domain, irqs);
|
||||
pic_update_irq(s);
|
||||
}
|
||||
|
||||
@@ -142,6 +145,7 @@ void do_pic_irqs_clear (struct vmx_virpic *s, uint16_t irqs)
|
||||
{
|
||||
s->pics[1].irr &= ~(uint8_t)(irqs >> 8);
|
||||
s->pics[0].irr &= ~(uint8_t) irqs;
|
||||
vmx_vioapic_do_irqs_clear(current->domain, irqs);
|
||||
pic_update_irq(s);
|
||||
}
|
||||
|
||||
@@ -521,7 +525,13 @@ int cpu_get_pic_interrupt(struct vcpu *v, int *type)
|
||||
|
||||
int is_pit_irq(struct vcpu *v, int irq, int type)
|
||||
{
|
||||
int pit_vec = v->domain->arch.vmx_platform.vmx_pic.pics[0].irq_base;
|
||||
int pit_vec;
|
||||
|
||||
if (type == VLAPIC_DELIV_MODE_EXT)
|
||||
pit_vec = v->domain->arch.vmx_platform.vmx_pic.pics[0].irq_base;
|
||||
else
|
||||
pit_vec =
|
||||
v->domain->arch.vmx_platform.vmx_vioapic.redirtbl[0].RedirForm.vector;
|
||||
|
||||
return (irq == pit_vec);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,608 @@
|
||||
/*
|
||||
* Copyright (C) 2001 MandrakeSoft S.A.
|
||||
*
|
||||
* MandrakeSoft S.A.
|
||||
* 43, rue d'Aboukir
|
||||
* 75002 Paris - France
|
||||
* http://www.linux-mandrake.com/
|
||||
* http://www.mandrakesoft.com/
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* Yunhong Jiang <yunhong.jiang@intel.com>
|
||||
* Ported to xen by using virtual IRQ line.
|
||||
*/
|
||||
|
||||
#include <asm/vmx_vioapic.h>
|
||||
#include <asm/vmx_platform.h>
|
||||
|
||||
#include <xen/config.h>
|
||||
#include <xen/types.h>
|
||||
#include <xen/mm.h>
|
||||
#include <xen/xmalloc.h>
|
||||
#include <xen/lib.h>
|
||||
#include <xen/errno.h>
|
||||
#include <xen/sched.h>
|
||||
#include <public/io/ioreq.h>
|
||||
#include <asm/vmx.h>
|
||||
#include <public/io/vmx_vpic.h>
|
||||
#include <asm/current.h>
|
||||
|
||||
static void ioapic_enable(vmx_vioapic_t *s, uint8_t enable)
|
||||
{
|
||||
if (enable)
|
||||
s->flags |= IOAPIC_ENABLE_FLAG;
|
||||
else
|
||||
s->flags &= ~IOAPIC_ENABLE_FLAG;
|
||||
}
|
||||
|
||||
static void ioapic_dump_redir(vmx_vioapic_t *s, uint8_t entry)
|
||||
{
|
||||
ASSERT(s);
|
||||
|
||||
RedirStatus redir = s->redirtbl[entry];
|
||||
|
||||
VMX_DBG_LOG(DBG_LEVEL_IOAPIC, "ioapic_dump_redir "
|
||||
"entry %x vector %x deliver_mod %x destmode %x delivestatus %x "
|
||||
"polarity %x remote_irr %x trigmod %x mask %x dest_id %x\n",
|
||||
entry, redir.RedirForm.vector, redir.RedirForm.deliver_mode,
|
||||
redir.RedirForm.destmode, redir.RedirForm.delivestatus,
|
||||
redir.RedirForm.polarity, redir.RedirForm.remoteirr,
|
||||
redir.RedirForm.trigmod, redir.RedirForm.mask,
|
||||
redir.RedirForm.dest_id);
|
||||
}
|
||||
|
||||
#ifdef VMX_DOMAIN_SAVE_RESTORE
|
||||
void ioapic_save(QEMUFile* f, void* opaque)
|
||||
{
|
||||
printk("no implementation for ioapic_save\n");
|
||||
}
|
||||
|
||||
int ioapic_load(QEMUFile* f, void* opaque, int version_id)
|
||||
{
|
||||
printk("no implementation for ioapic_load\n");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static unsigned long vmx_vioapic_read_indirect(struct vmx_vioapic *s,
|
||||
unsigned long addr,
|
||||
unsigned long length)
|
||||
{
|
||||
unsigned long result = 0;
|
||||
|
||||
ASSERT(s);
|
||||
|
||||
switch (s->ioregsel) {
|
||||
case IOAPIC_REG_VERSION:
|
||||
result = ((((IOAPIC_NUM_PINS-1) & 0xff) << 16)
|
||||
| (IOAPIC_VERSION_ID & 0x0f));
|
||||
break;
|
||||
|
||||
#ifndef __ia64__
|
||||
case IOAPIC_REG_APIC_ID:
|
||||
result = ((s->id & 0xf) << 24);
|
||||
break;
|
||||
|
||||
case IOAPIC_REG_ARB_ID:
|
||||
/* XXX how arb_id used on p4? */
|
||||
result = ((s->id & 0xf) << 24);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
{
|
||||
uint32_t redir_index = 0;
|
||||
uint64_t redir_content = 0;
|
||||
|
||||
redir_index = (s->ioregsel - 0x10) >> 1;
|
||||
|
||||
if (redir_index >= 0 && redir_index < IOAPIC_NUM_PINS) {
|
||||
redir_content = s->redirtbl[redir_index].value;
|
||||
|
||||
result = (s->ioregsel & 0x1)?
|
||||
(redir_content >> 32) & 0xffffffff :
|
||||
redir_content & 0xffffffff;
|
||||
} else {
|
||||
printk("upic_mem_readl:undefined ioregsel %x\n",
|
||||
s->ioregsel);
|
||||
domain_crash_synchronous();
|
||||
}
|
||||
break;
|
||||
}
|
||||
} /* switch */
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static unsigned long vmx_vioapic_read(struct vcpu *v,
|
||||
unsigned long addr,
|
||||
unsigned long length)
|
||||
{
|
||||
struct vmx_vioapic *s = &(v->domain->arch.vmx_platform.vmx_vioapic);
|
||||
uint32_t result = 0;
|
||||
|
||||
VMX_DBG_LOG(DBG_LEVEL_IOAPIC, "vmx_vioapic_read addr %lx\n", addr);
|
||||
|
||||
ASSERT(s);
|
||||
|
||||
addr &= 0xff;
|
||||
|
||||
switch (addr) {
|
||||
case IOAPIC_REG_SELECT:
|
||||
result = s->ioregsel;
|
||||
break;
|
||||
|
||||
case IOAPIC_REG_WINDOW:
|
||||
result = vmx_vioapic_read_indirect(s, addr, length);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void vmx_vioapic_write_indirect(struct vmx_vioapic *s,
|
||||
unsigned long addr,
|
||||
unsigned long length,
|
||||
unsigned long val)
|
||||
{
|
||||
switch (s->ioregsel) {
|
||||
case IOAPIC_REG_VERSION:
|
||||
printk("vmx_vioapic_write_indirect: version register read only\n");
|
||||
break;
|
||||
|
||||
#ifndef __ia64__
|
||||
case IOAPIC_REG_APIC_ID:
|
||||
s->id = (val >> 24) & 0xf;
|
||||
break;
|
||||
|
||||
case IOAPIC_REG_ARB_ID:
|
||||
s->arb_id = val;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
{
|
||||
uint32_t redir_index = 0;
|
||||
|
||||
VMX_DBG_LOG(DBG_LEVEL_IOAPIC, "vmx_vioapic_write_indirect "
|
||||
"change redir index %x val %lx\n",
|
||||
redir_index, val);
|
||||
|
||||
redir_index = (s->ioregsel - 0x10) >> 1;
|
||||
|
||||
if (redir_index >= 0 && redir_index < IOAPIC_NUM_PINS) {
|
||||
uint64_t redir_content;
|
||||
|
||||
redir_content = s->redirtbl[redir_index].value;
|
||||
|
||||
if (s->ioregsel & 0x1)
|
||||
redir_content = (((uint64_t)val & 0xffffffff) << 32) |
|
||||
(redir_content & 0xffffffff);
|
||||
else
|
||||
redir_content = ((redir_content >> 32) << 32) |
|
||||
(val & 0xffffffff);
|
||||
s->redirtbl[redir_index].value = redir_content;
|
||||
} else {
|
||||
printk("vmx_vioapic_write_indirect "
|
||||
"error register %x\n", s->ioregsel);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} /* switch */
|
||||
}
|
||||
|
||||
static void vmx_vioapic_write(struct vcpu *v,
|
||||
unsigned long addr,
|
||||
unsigned long length,
|
||||
unsigned long val)
|
||||
{
|
||||
vmx_vioapic_t *s = &(v->domain->arch.vmx_platform.vmx_vioapic);
|
||||
|
||||
ASSERT(s);
|
||||
|
||||
addr &= 0xff;
|
||||
|
||||
switch (addr) {
|
||||
case IOAPIC_REG_SELECT:
|
||||
s->ioregsel = val;
|
||||
break;
|
||||
|
||||
case IOAPIC_REG_WINDOW:
|
||||
vmx_vioapic_write_indirect(s, addr, length, val);
|
||||
break;
|
||||
|
||||
#ifdef __ia64__
|
||||
case IOAPIC_REG_EOI:
|
||||
ioapic_update_EOI(v->domain, val);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int vmx_vioapic_range(struct vcpu *v, unsigned long addr)
|
||||
{
|
||||
vmx_vioapic_t *s = &(v->domain->arch.vmx_platform.vmx_vioapic);
|
||||
|
||||
if ((s->flags & IOAPIC_ENABLE_FLAG) &&
|
||||
(addr >= s->base_address &&
|
||||
(addr <= s->base_address + IOAPIC_MEM_LENGTH)))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct vmx_mmio_handler vioapic_mmio_handler = {
|
||||
.check_handler = vmx_vioapic_range,
|
||||
.read_handler = vmx_vioapic_read,
|
||||
.write_handler = vmx_vioapic_write
|
||||
};
|
||||
|
||||
static void vmx_vioapic_reset(vmx_vioapic_t *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
memset(s, 0, sizeof(vmx_vioapic_t));
|
||||
|
||||
for (i = 0; i < IOAPIC_NUM_PINS; i++)
|
||||
s->redirtbl[i].RedirForm.mask = 0x1;
|
||||
}
|
||||
|
||||
static void ioapic_update_config(vmx_vioapic_t *s,
|
||||
unsigned long address,
|
||||
uint8_t enable)
|
||||
{
|
||||
ASSERT(s);
|
||||
|
||||
ioapic_enable(s, enable);
|
||||
|
||||
if (address != s->base_address)
|
||||
s->base_address = address;
|
||||
}
|
||||
|
||||
static int ioapic_inj_irq(vmx_vioapic_t *s,
|
||||
struct vlapic * target,
|
||||
uint8_t vector,
|
||||
uint8_t trig_mode,
|
||||
uint8_t delivery_mode)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
ASSERT(s && target);
|
||||
|
||||
VMX_DBG_LOG(DBG_LEVEL_IOAPIC, "ioapic_inj_irq "
|
||||
"irq %d trig %d delive mode %d\n",
|
||||
vector, trig_mode, delivery_mode);
|
||||
|
||||
switch (delivery_mode) {
|
||||
case VLAPIC_DELIV_MODE_FIXED:
|
||||
case VLAPIC_DELIV_MODE_LPRI:
|
||||
if (test_and_set_bit(vector, &target->irr[0]) && trig_mode == 1) {
|
||||
/* the level interrupt should not happen before it is cleard */
|
||||
printk("<ioapic_inj_irq> level interrupt happen before cleard\n");
|
||||
}
|
||||
if (trig_mode)
|
||||
test_and_set_bit(vector, &target->tmr[0]);
|
||||
result = 1;
|
||||
break;
|
||||
default:
|
||||
printk("<ioapic_inj_irq> error delivery mode %d\n",
|
||||
delivery_mode);
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifndef __ia64__
|
||||
static int ioapic_match_logical_addr(vmx_vioapic_t *s, int number, uint8_t dest)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
ASSERT(s && s->lapic_info[number]);
|
||||
|
||||
VMX_DBG_LOG(DBG_LEVEL_IOAPIC, "ioapic_match_logical_addr "
|
||||
"number %i dest %x\n",
|
||||
number, dest);
|
||||
|
||||
switch (((s->lapic_info[number]->dest_format >> 28) & 0xf)) {
|
||||
case 0xf:
|
||||
result =
|
||||
(dest & ((s->lapic_info[number]->logical_dest >> 24) & 0xff)) != 0;
|
||||
break;
|
||||
case 0x0:
|
||||
/* Should we support flat cluster mode ?*/
|
||||
if ( ((s->lapic_info[number]->logical_dest >> 28)
|
||||
== ((dest >> 0x4) & 0xf)) &&
|
||||
(((s->lapic_info[number]->logical_dest >> 24) & 0xf)
|
||||
& (dest & 0xf)) )
|
||||
result = 1;
|
||||
break;
|
||||
default:
|
||||
printk("error DFR value for %x local apic\n", number);
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#else
|
||||
extern int ioapic_match_logical_addr(vmx_vioapic_t *s, int number, uint8_t dest);
|
||||
#endif
|
||||
|
||||
static uint32_t ioapic_get_delivery_bitmask(vmx_vioapic_t *s,
|
||||
uint16_t dest,
|
||||
uint8_t dest_mode,
|
||||
uint8_t vector,
|
||||
uint8_t delivery_mode)
|
||||
{
|
||||
uint32_t mask = 0;
|
||||
int i;
|
||||
|
||||
VMX_DBG_LOG(DBG_LEVEL_IOAPIC, "ioapic_get_delivery_bitmask "
|
||||
"dest %d dest_mode %d "
|
||||
"vector %d del_mode %d, lapic_count %d\n",
|
||||
dest, dest_mode, vector, delivery_mode, s->lapic_count);
|
||||
|
||||
ASSERT(s);
|
||||
|
||||
if (dest_mode == 0) { /* Physical mode */
|
||||
for (i = 0; i < s->lapic_count; i++) {
|
||||
if (s->lapic_info[i]->id == dest) {
|
||||
mask = 1 << i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* logical destination. call match_logical_addr for each APIC. */
|
||||
if (dest != 0) {
|
||||
for (i=0; i< s->lapic_count; i++) {
|
||||
if ( s->lapic_info[i] &&
|
||||
ioapic_match_logical_addr(s, i, dest) ) {
|
||||
mask |= (1<<i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VMX_DBG_LOG(DBG_LEVEL_IOAPIC, "ioapic_get_delivery_bitmask "
|
||||
"mask %x\n", mask);
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
static void ioapic_deliver(vmx_vioapic_t *s, int irqno)
|
||||
{
|
||||
uint16_t dest = s->redirtbl[irqno].RedirForm.dest_id;
|
||||
uint8_t dest_mode = s->redirtbl[irqno].RedirForm.destmode;
|
||||
uint8_t delivery_mode = s->redirtbl[irqno].RedirForm.deliver_mode;
|
||||
uint8_t vector = s->redirtbl[irqno].RedirForm.vector;
|
||||
uint8_t trig_mode = s->redirtbl[irqno].RedirForm.trigmod;
|
||||
uint32_t deliver_bitmask;
|
||||
|
||||
VMX_DBG_LOG(DBG_LEVEL_IOAPIC, "IOAPIC deliver: "
|
||||
"dest %x dest_mode %x delivery_mode %x vector %x trig_mode %x\n",
|
||||
dest, dest_mode, delivery_mode, vector, trig_mode);
|
||||
|
||||
deliver_bitmask =
|
||||
ioapic_get_delivery_bitmask(s, dest, dest_mode, vector, delivery_mode);
|
||||
|
||||
if (!deliver_bitmask) {
|
||||
VMX_DBG_LOG(DBG_LEVEL_IOAPIC, "ioapic deliver "
|
||||
"no target on destination\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
switch (delivery_mode) {
|
||||
case VLAPIC_DELIV_MODE_LPRI:
|
||||
{
|
||||
struct vlapic* target;
|
||||
|
||||
target = apic_round_robin(
|
||||
s->domain, dest_mode, vector, deliver_bitmask);
|
||||
ioapic_inj_irq(s, target, vector, trig_mode, delivery_mode);
|
||||
break;
|
||||
}
|
||||
|
||||
case VLAPIC_DELIV_MODE_FIXED:
|
||||
case VLAPIC_DELIV_MODE_EXT:
|
||||
{
|
||||
uint8_t bit;
|
||||
for (bit = 0; bit < s->lapic_count; bit++) {
|
||||
if (deliver_bitmask & (1 << bit)) {
|
||||
if (s->lapic_info[bit]) {
|
||||
ioapic_inj_irq(s, s->lapic_info[bit],
|
||||
vector, trig_mode, delivery_mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case VLAPIC_DELIV_MODE_SMI:
|
||||
case VLAPIC_DELIV_MODE_NMI:
|
||||
case VLAPIC_DELIV_MODE_INIT:
|
||||
case VLAPIC_DELIV_MODE_STARTUP:
|
||||
default:
|
||||
printk("Not support delivey mode %d\n", delivery_mode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int ioapic_get_highest_irq(vmx_vioapic_t *s)
|
||||
{
|
||||
uint32_t irqs;
|
||||
|
||||
ASSERT(s);
|
||||
|
||||
irqs = s->irr & ~s->isr;
|
||||
return __fls(irqs);
|
||||
}
|
||||
|
||||
|
||||
static void service_ioapic(vmx_vioapic_t *s)
|
||||
{
|
||||
int irqno;
|
||||
|
||||
while ((irqno = ioapic_get_highest_irq(s)) != -1) {
|
||||
|
||||
VMX_DBG_LOG(DBG_LEVEL_IOAPIC, "service_ioapic "
|
||||
"highest irqno %x\n", irqno);
|
||||
|
||||
if (!s->redirtbl[irqno].RedirForm.mask) {
|
||||
ioapic_deliver(s, irqno);
|
||||
}
|
||||
|
||||
if (s->redirtbl[irqno].RedirForm.trigmod == IOAPIC_LEVEL_TRIGGER) {
|
||||
s->isr |= (1 << irqno);
|
||||
}
|
||||
|
||||
s->irr &= ~(1 << irqno);
|
||||
}
|
||||
}
|
||||
|
||||
void vmx_vioapic_do_irqs(struct domain *d, uint16_t irqs)
|
||||
{
|
||||
vmx_vioapic_t *s = &(d->arch.vmx_platform.vmx_vioapic);
|
||||
|
||||
if (!vmx_apic_support(d))
|
||||
return;
|
||||
|
||||
s->irr |= irqs;
|
||||
service_ioapic(s);
|
||||
}
|
||||
|
||||
void vmx_vioapic_do_irqs_clear(struct domain *d, uint16_t irqs)
|
||||
{
|
||||
vmx_vioapic_t *s = &(d->arch.vmx_platform.vmx_vioapic);
|
||||
|
||||
if (!vmx_apic_support(d))
|
||||
return;
|
||||
|
||||
s->irr &= ~irqs;
|
||||
service_ioapic(s);
|
||||
}
|
||||
|
||||
void vmx_vioapic_set_irq(struct domain *d, int irq, int level)
|
||||
{
|
||||
vmx_vioapic_t *s = &(d->arch.vmx_platform.vmx_vioapic);
|
||||
|
||||
if (!vmx_apic_support(d))
|
||||
return ;
|
||||
|
||||
VMX_DBG_LOG(DBG_LEVEL_IOAPIC, "ioapic_set_irq "
|
||||
"irq %x level %x\n", irq, level);
|
||||
|
||||
if (irq < 0 || irq >= IOAPIC_NUM_PINS) {
|
||||
printk("ioapic_set_irq irq %x is illegal\n", irq);
|
||||
domain_crash_synchronous();
|
||||
}
|
||||
|
||||
if (!IOAPICEnabled(s) || s->redirtbl[irq].RedirForm.mask)
|
||||
return;
|
||||
|
||||
ioapic_dump_redir(s, irq);
|
||||
|
||||
if (irq >= 0 && irq < IOAPIC_NUM_PINS) {
|
||||
uint32_t bit = 1 << irq;
|
||||
if (s->redirtbl[irq].RedirForm.trigmod == IOAPIC_LEVEL_TRIGGER) {
|
||||
if (level)
|
||||
s->irr |= bit;
|
||||
else
|
||||
s->irr &= ~bit;
|
||||
} else {
|
||||
if (level)
|
||||
/* XXX No irr clear for edge interrupt */
|
||||
s->irr |= bit;
|
||||
}
|
||||
}
|
||||
|
||||
service_ioapic(s);
|
||||
}
|
||||
|
||||
/* XXX If level interrupt, use vector->irq table for performance */
|
||||
static int get_redir_num(vmx_vioapic_t *s, int vector)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
ASSERT(s);
|
||||
|
||||
for(i = 0; i < IOAPIC_NUM_PINS - 1; i++) {
|
||||
if (s->redirtbl[i].RedirForm.vector == vector)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void ioapic_update_EOI(struct domain *d, int vector)
|
||||
{
|
||||
vmx_vioapic_t *s = &(d->arch.vmx_platform.vmx_vioapic);
|
||||
int redir_num;
|
||||
|
||||
if ((redir_num = get_redir_num(s, vector)) == -1) {
|
||||
printk("Can't find redir item for %d EOI \n", vector);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!test_and_clear_bit(redir_num, &s->isr)) {
|
||||
printk("redir %d not set for %d EOI\n", redir_num, vector);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int vmx_vioapic_add_lapic(struct vlapic *vlapic, struct vcpu *v)
|
||||
{
|
||||
vmx_vioapic_t *s = &(v->domain->arch.vmx_platform.vmx_vioapic);
|
||||
|
||||
if (v->vcpu_id != s->lapic_count) {
|
||||
printk("vmx_vioapic_add_lapic "
|
||||
"cpu_id not match vcpu_id %x lapic_count %x\n",
|
||||
v->vcpu_id, s->lapic_count);
|
||||
domain_crash_synchronous();
|
||||
}
|
||||
|
||||
s->lapic_info[s->lapic_count ++] = vlapic;
|
||||
|
||||
return s->lapic_count;
|
||||
}
|
||||
|
||||
vmx_vioapic_t * vmx_vioapic_init(struct domain *d)
|
||||
{
|
||||
int i = 0;
|
||||
vmx_vioapic_t *s = &(d->arch.vmx_platform.vmx_vioapic);
|
||||
|
||||
VMX_DBG_LOG(DBG_LEVEL_IOAPIC, "vmx_vioapic_init\n");
|
||||
|
||||
vmx_vioapic_reset(s);
|
||||
|
||||
s->domain = d;
|
||||
|
||||
for (i = 0; i < MAX_LAPIC_NUM; i++)
|
||||
s->lapic_info[i] = NULL;
|
||||
|
||||
/* Remove after GFW ready */
|
||||
ioapic_update_config(s, IOAPIC_DEFAULT_BASE_ADDRESS, 1);
|
||||
|
||||
return s;
|
||||
}
|
||||
@@ -34,12 +34,14 @@
|
||||
#ifdef CONFIG_VMX
|
||||
|
||||
extern struct vmx_mmio_handler vlapic_mmio_handler;
|
||||
extern struct vmx_mmio_handler vioapic_mmio_handler;
|
||||
|
||||
#define VMX_MMIO_HANDLER_NR 1
|
||||
#define VMX_MMIO_HANDLER_NR 2
|
||||
|
||||
struct vmx_mmio_handler *vmx_mmio_handlers[VMX_MMIO_HANDLER_NR] =
|
||||
{
|
||||
&vlapic_mmio_handler
|
||||
&vlapic_mmio_handler,
|
||||
&vioapic_mmio_handler
|
||||
};
|
||||
|
||||
static inline void vmx_mmio_access(struct vcpu *v,
|
||||
|
||||
@@ -307,6 +307,11 @@ vlapic_EOI_set(struct vlapic *vlapic)
|
||||
|
||||
vlapic_clear_isr(vlapic, vector);
|
||||
vlapic_update_ppr(vlapic);
|
||||
|
||||
if (test_and_clear_bit(vector, &vlapic->tmr[0])) {
|
||||
extern void ioapic_update_EOI(struct domain *d, int vector);
|
||||
ioapic_update_EOI(vlapic->domain, vector);
|
||||
}
|
||||
}
|
||||
|
||||
int vlapic_check_vector(struct vlapic *vlapic,
|
||||
@@ -969,6 +974,8 @@ static int vlapic_reset(struct vlapic *vlapic)
|
||||
|
||||
vlapic->spurious_vec = 0xff;
|
||||
|
||||
vmx_vioapic_add_lapic(vlapic, v);
|
||||
|
||||
init_ac_timer(&vlapic->vlapic_timer,
|
||||
vlapic_timer_fn, vlapic, v->processor);
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <asm/processor.h>
|
||||
#include <asm/msr.h>
|
||||
#include <asm/vmx.h>
|
||||
#include <asm/vmx_vioapic.h>
|
||||
#include <asm/flushtlb.h>
|
||||
#include <xen/event.h>
|
||||
#include <xen/kernel.h>
|
||||
@@ -255,6 +256,7 @@ static void vmx_setup_platform(struct domain* d)
|
||||
|
||||
if ( vmx_apic_support(d) ) {
|
||||
spin_lock_init(&d->arch.vmx_platform.round_robin_lock);
|
||||
vmx_vioapic_init(d);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <asm/e820.h>
|
||||
#include <asm/vmx_virpit.h>
|
||||
#include <asm/vmx_intercept.h>
|
||||
#include <asm/vmx_vioapic.h>
|
||||
#include <public/io/vmx_vpic.h>
|
||||
|
||||
#define MAX_OPERAND_NUM 2
|
||||
@@ -85,6 +86,7 @@ struct vmx_platform {
|
||||
struct vmx_virpit vmx_pit;
|
||||
struct vmx_io_handler vmx_io_handler;
|
||||
struct vmx_virpic vmx_pic;
|
||||
struct vmx_vioapic vmx_vioapic;
|
||||
unsigned char round_info[256];
|
||||
spinlock_t round_robin_lock;
|
||||
int interrupt_request;
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (C) 2001 MandrakeSoft S.A.
|
||||
*
|
||||
* MandrakeSoft S.A.
|
||||
* 43, rue d'Aboukir
|
||||
* 75002 Paris - France
|
||||
* http://www.linux-mandrake.com/
|
||||
* http://www.mandrakesoft.com/
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _IOAPIC_H_
|
||||
#define _IOAPIC_H_
|
||||
|
||||
#include <xen/config.h>
|
||||
#include <xen/types.h>
|
||||
#include <xen/smp.h>
|
||||
|
||||
#ifndef __ia64__
|
||||
#define IOAPIC_VERSION_ID 0x11
|
||||
#else
|
||||
#define IOAPIC_VERSION_ID 0x21
|
||||
#endif
|
||||
|
||||
#define IOAPIC_NUM_PINS 24
|
||||
#define MAX_LAPIC_NUM 32
|
||||
|
||||
#define IOAPIC_LEVEL_TRIGGER 1
|
||||
|
||||
#define IOAPIC_DEFAULT_BASE_ADDRESS 0xfec00000
|
||||
#define IOAPIC_MEM_LENGTH 0x100
|
||||
|
||||
#define IOAPIC_ENABLE_MASK 0x0
|
||||
#define IOAPIC_ENABLE_FLAG (1 << IOAPIC_ENABLE_MASK)
|
||||
#define IOAPICEnabled(s) (s->flags & IOAPIC_ENABLE_FLAG)
|
||||
|
||||
#define IOAPIC_REG_SELECT 0x0
|
||||
#define IOAPIC_REG_WINDOW 0x10
|
||||
|
||||
#ifdef __ia64__
|
||||
#define IOAPIC_REG_ASSERTION 0x20
|
||||
#define IOAPIC_REG_EOI 0x40
|
||||
#endif
|
||||
|
||||
#ifndef __ia64__
|
||||
#define IOAPIC_REG_APIC_ID 0x0
|
||||
#define IOAPIC_REG_ARB_ID 0x2
|
||||
#endif
|
||||
|
||||
#define IOAPIC_REG_VERSION 0x1
|
||||
|
||||
#ifdef __ia64__
|
||||
typedef union RedirStatus
|
||||
{
|
||||
uint64_t value;
|
||||
struct {
|
||||
uint16_t dest_id;
|
||||
uint8_t reserved[3];
|
||||
uint8_t reserve:7;
|
||||
uint8_t mask:1; /* interrupt mask*/
|
||||
uint8_t trigmod:1;
|
||||
uint8_t remoteirr:1;
|
||||
uint8_t polarity:1;
|
||||
uint8_t delivestatus:1;
|
||||
uint8_t destmode:1;
|
||||
uint8_t deliver_mode:3;
|
||||
uint8_t vector;
|
||||
} RedirForm;
|
||||
} RedirStatus;
|
||||
#else
|
||||
typedef union RedirStatus
|
||||
{
|
||||
uint64_t value;
|
||||
struct {
|
||||
uint8_t vector;
|
||||
uint8_t deliver_mode:3;
|
||||
uint8_t destmode:1;
|
||||
uint8_t delivestatus:1;
|
||||
uint8_t polarity:1;
|
||||
uint8_t remoteirr:1;
|
||||
uint8_t trigmod:1;
|
||||
uint8_t mask:1; /* interrupt mask*/
|
||||
uint8_t reserve:7;
|
||||
uint8_t reserved[4];
|
||||
uint8_t dest_id;
|
||||
} RedirForm;
|
||||
} RedirStatus;
|
||||
#endif
|
||||
|
||||
#define IOAPIC_MEM_LENGTH 0x100
|
||||
#define IOAPIC_ENABLE_MASK 0x0
|
||||
#define IOAPIC_ENABLE_FLAG (1 << IOAPIC_ENABLE_MASK)
|
||||
#define MAX_LAPIC_NUM 32
|
||||
|
||||
typedef struct vmx_vioapic {
|
||||
uint32_t ioregsel;
|
||||
uint32_t irr;
|
||||
uint32_t isr; /* This is used for level trigger */
|
||||
uint32_t flags;
|
||||
uint32_t lapic_count;
|
||||
uint32_t id;
|
||||
uint32_t arb_id;
|
||||
unsigned long base_address;
|
||||
RedirStatus redirtbl[IOAPIC_NUM_PINS];
|
||||
struct vlapic *lapic_info[MAX_LAPIC_NUM];
|
||||
struct domain *domain;
|
||||
} vmx_vioapic_t;
|
||||
|
||||
vmx_vioapic_t *vmx_vioapic_init(struct domain *d);
|
||||
|
||||
void vmx_vioapic_do_irqs_clear(struct domain *d, uint16_t irqs);
|
||||
void vmx_vioapic_do_irqs(struct domain *d, uint16_t irqs);
|
||||
void vmx_vioapic_set_irq(struct domain *d, int irq, int level);
|
||||
|
||||
int vmx_vioapic_add_lapic(struct vlapic *vlapic, struct vcpu *v);
|
||||
|
||||
#ifdef VMX_DOMAIN_SAVE_RESTORE
|
||||
void ioapic_save(QEMUFile* f, void* opaque);
|
||||
int ioapic_load(QEMUFile* f, void* opaque, int version_id);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -284,7 +284,8 @@ enum vmcs_field {
|
||||
#define DBG_LEVEL_VMMU (1 << 5)
|
||||
#define DBG_LEVEL_VLAPIC (1 << 6)
|
||||
#define DBG_LEVEL_VLAPIC_TIMER (1 << 7)
|
||||
#define DBG_LEVEL_VLAPIC_INTERRUPT (1 << 7)
|
||||
#define DBG_LEVEL_VLAPIC_INTERRUPT (1 << 8)
|
||||
#define DBG_LEVEL_IOAPIC (1 << 9)
|
||||
|
||||
extern unsigned int opt_vmx_debug_level;
|
||||
#define VMX_DBG_LOG(level, _f, _a...) \
|
||||
|
||||