[HVM] Update VPIC device model for new interrupt delivery code.

Move BSP VLAPIC initialisation to hvmloader.
Remove callback_irq update hack from Linux unmodified drivers.
Signed-off-by: Keir Fraser <keir@xensource.com>
This commit is contained in:
kaf24@localhost.localdomain committed 2006-11-26 13:37:27 +00:00
1 parent 9d4052382a
commit 00a70f44a6
16 files changed
+714 -655

No files matched your search

+108
View File
@@ -0,0 +1,108 @@
#ifndef __ASM_APICDEF_H
#define __ASM_APICDEF_H
#define APIC_DEFAULT_PHYS_BASE 0xfee00000
#define APIC_ID 0x20
#define APIC_ID_MASK (0xFFu<<24)
#define GET_APIC_ID(x) (((x)>>24)&0xFFu)
#define SET_APIC_ID(x) (((x)<<24))
#define APIC_LVR 0x30
#define APIC_LVR_MASK 0xFF00FF
#define GET_APIC_VERSION(x) ((x)&0xFF)
#define GET_APIC_MAXLVT(x) (((x)>>16)&0xFF)
#define APIC_INTEGRATED(x) ((x)&0xF0)
#define APIC_XAPIC(x) ((x) >= 0x14)
#define APIC_TASKPRI 0x80
#define APIC_TPRI_MASK 0xFF
#define APIC_ARBPRI 0x90
#define APIC_ARBPRI_MASK 0xFF
#define APIC_PROCPRI 0xA0
#define APIC_EOI 0xB0
#define APIC_EIO_ACK 0x0
#define APIC_RRR 0xC0
#define APIC_LDR 0xD0
#define APIC_LDR_MASK (0xFF<<24)
#define GET_APIC_LOGICAL_ID(x) (((x)>>24)&0xFF)
#define SET_APIC_LOGICAL_ID(x) (((x)<<24))
#define APIC_ALL_CPUS 0xFF
#define APIC_DFR 0xE0
#define APIC_DFR_CLUSTER 0x0FFFFFFFul
#define APIC_DFR_FLAT 0xFFFFFFFFul
#define APIC_SPIV 0xF0
#define APIC_SPIV_FOCUS_DISABLED (1<<9)
#define APIC_SPIV_APIC_ENABLED (1<<8)
#define APIC_ISR 0x100
#define APIC_TMR 0x180
#define APIC_IRR 0x200
#define APIC_ESR 0x280
#define APIC_ESR_SEND_CS 0x00001
#define APIC_ESR_RECV_CS 0x00002
#define APIC_ESR_SEND_ACC 0x00004
#define APIC_ESR_RECV_ACC 0x00008
#define APIC_ESR_SENDILL 0x00020
#define APIC_ESR_RECVILL 0x00040
#define APIC_ESR_ILLREGA 0x00080
#define APIC_ICR 0x300
#define APIC_DEST_SELF 0x40000
#define APIC_DEST_ALLINC 0x80000
#define APIC_DEST_ALLBUT 0xC0000
#define APIC_ICR_RR_MASK 0x30000
#define APIC_ICR_RR_INVALID 0x00000
#define APIC_ICR_RR_INPROG 0x10000
#define APIC_ICR_RR_VALID 0x20000
#define APIC_INT_LEVELTRIG 0x08000
#define APIC_INT_ASSERT 0x04000
#define APIC_ICR_BUSY 0x01000
#define APIC_DEST_LOGICAL 0x00800
#define APIC_DEST_PHYSICAL 0x00000
#define APIC_DM_FIXED 0x00000
#define APIC_DM_LOWEST 0x00100
#define APIC_DM_SMI 0x00200
#define APIC_DM_REMRD 0x00300
#define APIC_DM_NMI 0x00400
#define APIC_DM_INIT 0x00500
#define APIC_DM_STARTUP 0x00600
#define APIC_DM_EXTINT 0x00700
#define APIC_VECTOR_MASK 0x000FF
#define APIC_ICR2 0x310
#define GET_APIC_DEST_FIELD(x) (((x)>>24)&0xFF)
#define SET_APIC_DEST_FIELD(x) ((x)<<24)
#define APIC_LVTT 0x320
#define APIC_LVTTHMR 0x330
#define APIC_LVTPC 0x340
#define APIC_LVT0 0x350
#define APIC_LVT_TIMER_BASE_MASK (0x3<<18)
#define GET_APIC_TIMER_BASE(x) (((x)>>18)&0x3)
#define SET_APIC_TIMER_BASE(x) (((x)<<18))
#define APIC_TIMER_BASE_CLKIN 0x0
#define APIC_TIMER_BASE_TMBASE 0x1
#define APIC_TIMER_BASE_DIV 0x2
#define APIC_LVT_TIMER_PERIODIC (1<<17)
#define APIC_LVT_MASKED (1<<16)
#define APIC_LVT_LEVEL_TRIGGER (1<<15)
#define APIC_LVT_REMOTE_IRR (1<<14)
#define APIC_INPUT_POLARITY (1<<13)
#define APIC_SEND_PENDING (1<<12)
#define APIC_MODE_MASK 0x700
#define GET_APIC_DELIVERY_MODE(x) (((x)>>8)&0x7)
#define SET_APIC_DELIVERY_MODE(x,y) (((x)&~0x700)|((y)<<8))
#define APIC_MODE_FIXED 0x0
#define APIC_MODE_NMI 0x4
#define APIC_MODE_EXTINT 0x7
#define APIC_LVT1 0x360
#define APIC_LVTERR 0x370
#define APIC_TMICT 0x380
#define APIC_TMCCT 0x390
#define APIC_TDCR 0x3E0
#define APIC_TDR_DIV_TMBASE (1<<2)
#define APIC_TDR_DIV_1 0xB
#define APIC_TDR_DIV_2 0x0
#define APIC_TDR_DIV_4 0x1
#define APIC_TDR_DIV_8 0x2
#define APIC_TDR_DIV_16 0x3
#define APIC_TDR_DIV_32 0x8
#define APIC_TDR_DIV_64 0x9
#define APIC_TDR_DIV_128 0xA
#endif
+7 -9
View File
@@ -26,6 +26,7 @@
#include "acpi_utils.h"
#include "smbios.h"
#include "config.h"
#include "apic_regs.h"
#include "pci_regs.h"
#include <xen/version.h>
#include <xen/hvm/params.h>
@@ -154,16 +155,13 @@ init_hypercalls(void)
static void apic_setup(void)
{
volatile uint32_t *ioregsel;
volatile uint32_t *iowin;
/* IOAPIC memory-mapped access window registers. */
ioregsel = (volatile uint32_t *)(IOAPIC_BASE_ADDRESS + 0x00);
iowin = (volatile uint32_t *)(IOAPIC_BASE_ADDRESS + 0x10);
/* Set the IOAPIC ID to tha static value used in the MP/ACPI tables. */
*ioregsel = 0;
*iowin = IOAPIC_ID;
ioapic_write(0x00, IOAPIC_ID);
/* Set up Virtual Wire mode. */
lapic_write(APIC_SPIV, APIC_SPIV_APIC_ENABLED | 0xFF);
lapic_write(APIC_LVT0, APIC_MODE_EXTINT << 8);
lapic_write(APIC_LVT1, APIC_MODE_NMI << 8);
}
static void pci_setup(void)
+13 -11
View File
@@ -309,22 +309,24 @@ uint64_t e820_malloc(uint64_t size, uint32_t type, uint64_t mask)
uint32_t ioapic_read(uint32_t reg)
{
uint32_t *ioregsel = (uint32_t *)(IOAPIC_BASE_ADDRESS + 0x00);
uint32_t *iowin = (uint32_t *)(IOAPIC_BASE_ADDRESS + 0x10);
*ioregsel = reg;
mb();
return *iowin;
*(volatile uint32_t *)(IOAPIC_BASE_ADDRESS + 0x00) = reg;
return *(volatile uint32_t *)(IOAPIC_BASE_ADDRESS + 0x10);
}
void ioapic_write(uint32_t reg, uint32_t val)
{
uint32_t *ioregsel = (uint32_t *)(IOAPIC_BASE_ADDRESS + 0x00);
uint32_t *iowin = (uint32_t *)(IOAPIC_BASE_ADDRESS + 0x10);
*(volatile uint32_t *)(IOAPIC_BASE_ADDRESS + 0x00) = reg;
*(volatile uint32_t *)(IOAPIC_BASE_ADDRESS + 0x10) = val;
}
*ioregsel = reg;
wmb();
*iowin = val;
uint32_t lapic_read(uint32_t reg)
{
return *(volatile uint32_t *)(LAPIC_BASE_ADDRESS + reg);
}
void lapic_write(uint32_t reg, uint32_t val)
{
*(volatile uint32_t *)(LAPIC_BASE_ADDRESS + reg) = val;
}
#define PCI_CONF1_ADDRESS(bus, devfn, reg) \
+6
View File
@@ -20,6 +20,12 @@ uint8_t inb(uint16_t addr);
uint16_t inw(uint16_t addr);
uint32_t inl(uint16_t addr);
/* APIC access */
uint32_t ioapic_read(uint32_t reg);
void ioapic_write(uint32_t reg, uint32_t val);
uint32_t lapic_read(uint32_t reg);
void lapic_write(uint32_t reg, uint32_t val);
/* PCI access */
uint32_t pci_read(uint32_t devfn, uint32_t reg, uint32_t len);
#define pci_readb(devfn, reg) ((uint8_t) pci_read(devfn, reg, 1))
@@ -132,7 +132,7 @@ EXPORT_SYMBOL(notify_remote_via_irq);
irqreturn_t evtchn_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
unsigned int l1i, l2i, port;
unsigned int l1i, port;
int cpu = smp_processor_id();
irqreturn_t(*handler) (int, void *, struct pt_regs *);
shared_info_t *s = shared_info_area;
@@ -140,44 +140,28 @@ irqreturn_t evtchn_interrupt(int irq, void *dev_id, struct pt_regs *regs)
unsigned long l1, l2;
v->evtchn_upcall_pending = 0;
/* NB. No need for a barrier here -- XCHG is a barrier
* on x86. */
/* NB. No need for a barrier here -- XCHG is a barrier on x86. */
l1 = xchg(&v->evtchn_pending_sel, 0);
while (l1 != 0)
{
while (l1 != 0) {
l1i = __ffs(l1);
l1 &= ~(1 << l1i);
l2 = s->evtchn_pending[l1i] & ~s->evtchn_mask[l1i];
while (l2 != 0)
{
l2i = __ffs(l2);
port = (l1i * BITS_PER_LONG) + l2i;
while ((l2 = s->evtchn_pending[l1i] & ~s->evtchn_mask[l1i])) {
port = (l1i * BITS_PER_LONG) + __ffs(l2);
synch_clear_bit(port, &s->evtchn_pending[0]);
if ((handler = evtchns[port].handler) != NULL)
{
handler(port, evtchns[port].dev_id,
regs);
}
else
{
printk(KERN_WARNING "unexpected event channel upcall on port %d!\n", port);
}
l2 = s->evtchn_pending[l1i] & ~s->evtchn_mask[l1i];
printk(KERN_WARNING "unexpected event channel "
"upcall on port %d!\n", port);
}
}
/* Make sure the hypervisor has a chance to notice that the
upcall_pending condition has been cleared, so that we don't
try and reinject the interrupt again. */
(void)HYPERVISOR_xen_version(0, NULL);
return IRQ_HANDLED;
}
void force_evtchn_callback(void)
{
(void)HYPERVISOR_xen_version(0, NULL);
(void)HYPERVISOR_xen_version(0, NULL);
}
EXPORT_SYMBOL(force_evtchn_callback);
+1 -1
View File
@@ -3,7 +3,6 @@ subdir-y += vmx
obj-y += hvm.o
obj-y += i8254.o
obj-y += i8259.o
obj-y += instrlen.o
obj-y += intercept.o
obj-y += io.o
@@ -13,3 +12,4 @@ obj-y += pmtimer.o
obj-y += rtc.o
obj-y += vioapic.o
obj-y += vlapic.o
obj-y += vpic.o
+8 -8
View File
@@ -168,14 +168,13 @@ int hvm_domain_initialise(struct domain *d)
spin_lock_init(&d->arch.hvm_domain.pbuf_lock);
spin_lock_init(&d->arch.hvm_domain.buffered_io_lock);
spin_lock_init(&d->arch.hvm_domain.irq.lock);
rc = shadow_enable(d, SHM2_refcounts|SHM2_translate|SHM2_external);
if ( rc != 0 )
return rc;
pic_init(domain_vpic(d));
register_pic_io_hook(d);
vpic_init(d);
vioapic_init(d);
return 0;
@@ -244,13 +243,14 @@ void hvm_vcpu_destroy(struct vcpu *v)
int cpu_get_interrupt(struct vcpu *v, int *type)
{
int irq;
int vector;
if ( (irq = cpu_get_apic_interrupt(v, type)) != -1 )
return irq;
if ( (vector = cpu_get_apic_interrupt(v, type)) != -1 )
return vector;
if ( (v->vcpu_id == 0) && ((irq = cpu_get_pic_interrupt(v, type)) != -1) )
return irq;
if ( (v->vcpu_id == 0) &&
((vector = cpu_get_pic_interrupt(v, type)) != -1) )
return vector;
return -1;
}
-515
View File
@@ -1,515 +0,0 @@
/*
* i8259 interrupt controller emulation
*
* Copyright (c) 2003-2004 Fabrice Bellard
* Copyright (c) 2005 Intel Corperation
* Copyright (c) 2006 Keir Fraser, XenSource Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#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 <asm/hvm/hvm.h>
#include <asm/hvm/io.h>
#include <asm/hvm/support.h>
#include <asm/current.h>
static inline void pic_set_irq1(PicState *s, int irq, int level)
{
int mask = 1 << irq;
ASSERT(spin_is_locked(vpic_lock(s->pics_state)));
if ( s->elcr & mask )
{
/* Level triggered. */
if ( level )
{
s->irr |= mask;
s->last_irr |= mask;
}
else
{
s->irr &= ~mask;
s->last_irr &= ~mask;
}
}
else
{
/* Edge triggered. */
if ( level )
{
if ( (s->last_irr & mask) == 0 )
s->irr |= mask;
s->last_irr |= mask;
}
else
{
s->last_irr &= ~mask;
}
}
}
/* Return the highest priority found in mask. Return 8 if no irq. */
static inline int get_priority(PicState *s, int mask)
{
int priority;
ASSERT(spin_is_locked(vpic_lock(s->pics_state)));
if ( mask == 0 )
return 8;
priority = 0;
while ( (mask & (1 << ((priority + s->priority_add) & 7))) == 0 )
priority++;
return priority;
}
/* Return the PIC's highest priority pending interrupt. Return -1 if none. */
static int pic_get_irq(PicState *s)
{
int mask, cur_priority, priority;
ASSERT(spin_is_locked(vpic_lock(s->pics_state)));
mask = s->irr & ~s->imr;
priority = get_priority(s, mask);
if ( priority == 8 )
return -1;
/*
* Compute current priority. If special fully nested mode on the master,
* the IRQ coming from the slave is not taken into account for the
* priority computation.
*/
mask = s->isr;
if ( s->special_fully_nested_mode && (s == &s->pics_state->pics[0]) )
mask &= ~(1 << 2);
cur_priority = get_priority(s, mask);
if ( priority < cur_priority )
/* Higher priority found: an irq should be generated. */
return (priority + s->priority_add) & 7;
return -1;
}
/* Raise irq to CPU if necessary. */
static void pic_update_irq(struct vpic *vpic)
{
int irq2, irq;
ASSERT(spin_is_locked(vpic_lock(vpic)));
/* First look at slave PIC. */
irq2 = pic_get_irq(&vpic->pics[1]);
if ( irq2 >= 0 )
{
/* If irq request by slave pic, signal master PIC. */
pic_set_irq1(&vpic->pics[0], 2, 1);
pic_set_irq1(&vpic->pics[0], 2, 0);
}
/* Look at requested IRQ. */
irq = pic_get_irq(&vpic->pics[0]);
if ( irq >= 0 )
vpic->irq_pending = 1;
}
void pic_set_irq(struct vpic *vpic, int irq, int level)
{
ASSERT(spin_is_locked(vpic_lock(vpic)));
pic_set_irq1(&vpic->pics[irq >> 3], irq & 7, level);
pic_update_irq(vpic);
}
/* Acknowledge interrupt @irq. */
static inline void pic_intack(PicState *s, int irq)
{
ASSERT(spin_is_locked(vpic_lock(s->pics_state)));
if ( s->auto_eoi )
{
if ( s->rotate_on_auto_eoi )
s->priority_add = (irq + 1) & 7;
}
else
{
s->isr |= (1 << irq);
}
/* We don't clear a level sensitive interrupt here */
if ( !(s->elcr & (1 << irq)) )
s->irr &= ~(1 << irq);
}
static int pic_read_irq(struct vpic *vpic)
{
int irq, irq2, intno;
spin_lock(vpic_lock(vpic));
irq = pic_get_irq(&vpic->pics[0]);
if ( irq >= 0 )
{
pic_intack(&vpic->pics[0], irq);
if ( irq == 2 )
{
irq2 = pic_get_irq(&vpic->pics[1]);
if ( irq2 >= 0 )
{
pic_intack(&vpic->pics[1], irq2);
}
else
{
gdprintk(XENLOG_WARNING, "Spurious irq on slave i8259.\n");
irq2 = 7;
}
intno = vpic->pics[1].irq_base + irq2;
irq = irq2 + 8;
}
else
{
intno = vpic->pics[0].irq_base + irq;
}
}
else
{
irq = 7;
intno = vpic->pics[0].irq_base + irq;
gdprintk(XENLOG_WARNING, "Spurious irq on master i8259.\n");
}
pic_update_irq(vpic);
spin_unlock(vpic_lock(vpic));
return intno;
}
static void pic_reset(void *opaque)
{
PicState *s = opaque;
s->last_irr = 0;
s->irr = 0;
s->imr = 0;
s->isr = 0;
s->priority_add = 0;
s->irq_base = 0;
s->read_reg_select = 0;
s->poll = 0;
s->special_mask = 0;
s->init_state = 0;
s->auto_eoi = 0;
s->rotate_on_auto_eoi = 0;
s->special_fully_nested_mode = 0;
s->init4 = 0;
/* Note: ELCR is not reset */
}
static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
PicState *s = opaque;
int priority, cmd, irq;
ASSERT(spin_is_locked(vpic_lock(s->pics_state)));
addr &= 1;
if ( addr == 0 )
{
if ( val & 0x10 )
{
pic_reset(s);
s->pics_state->irq_pending = 0;
s->init_state = 1;
s->init4 = val & 1;
}
else if ( val & 0x08 )
{
if ( val & 0x04 )
s->poll = 1;
if ( val & 0x02 )
s->read_reg_select = val & 1;
if ( val & 0x40 )
s->special_mask = (val >> 5) & 1;
}
else
{
cmd = val >> 5;
switch ( cmd )
{
case 0:
case 4:
s->rotate_on_auto_eoi = cmd >> 2;
break;
case 1:
case 5:
priority = get_priority(s, s->isr);
if (priority != 8) {
irq = (priority + s->priority_add) & 7;
s->isr &= ~(1 << irq);
if (cmd == 5)
s->priority_add = (irq + 1) & 7;
pic_update_irq(s->pics_state);
}
break;
case 3:
irq = val & 7;
s->isr &= ~(1 << irq);
pic_update_irq(s->pics_state);
break;
case 6:
s->priority_add = (val + 1) & 7;
pic_update_irq(s->pics_state);
break;
case 7:
irq = val & 7;
s->isr &= ~(1 << irq);
s->priority_add = (irq + 1) & 7;
pic_update_irq(s->pics_state);
break;
default:
break;
}
}
}
else
{
switch ( s->init_state )
{
case 0:
s->imr = val;
pic_update_irq(s->pics_state);
break;
case 1:
s->irq_base = val & 0xf8;
s->init_state = 2;
break;
case 2:
s->init_state = s->init4 ? 3 : 0;
break;
case 3:
s->special_fully_nested_mode = (val >> 4) & 1;
s->auto_eoi = (val >> 1) & 1;
s->init_state = 0;
break;
}
}
}
static uint32_t pic_poll_read (PicState *s, uint32_t addr1)
{
int ret;
ASSERT(spin_is_locked(vpic_lock(s->pics_state)));
ret = pic_get_irq(s);
if ( ret >= 0 )
{
if ( addr1 >> 7 )
{
s->pics_state->pics[0].isr &= ~(1 << 2);
s->pics_state->pics[0].irr &= ~(1 << 2);
}
s->irr &= ~(1 << ret);
s->isr &= ~(1 << ret);
if ( (addr1 >> 7) || (ret != 2) )
pic_update_irq(s->pics_state);
}
else
{
ret = 0x07;
pic_update_irq(s->pics_state);
}
return ret;
}
static uint32_t pic_ioport_read(void *opaque, uint32_t addr1)
{
PicState *s = opaque;
ASSERT(spin_is_locked(vpic_lock(s->pics_state)));
if ( s->poll )
{
s->poll = 0;
return pic_poll_read(s, addr1);
}
if ( (addr1 & 1) == 0 )
return (s->read_reg_select ? s->isr : s->irr);
return s->imr;
}
static void elcr_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
PicState *s = opaque;
ASSERT(spin_is_locked(vpic_lock(s->pics_state)));
s->elcr = val & s->elcr_mask;
}
static uint32_t elcr_ioport_read(void *opaque, uint32_t addr1)
{
PicState *s = opaque;
return s->elcr;
}
static void pic_init1(int io_addr, int elcr_addr, PicState *s)
{
pic_reset(s);
}
void pic_init(struct vpic *vpic)
{
memset(vpic, 0, sizeof(*vpic));
spin_lock_init(vpic_lock(vpic));
vpic->pics[0].pics_state = vpic;
vpic->pics[1].pics_state = vpic;
vpic->pics[0].elcr_mask = 0xf8;
vpic->pics[1].elcr_mask = 0xde;
pic_init1(0x20, 0x4d0, &vpic->pics[0]);
pic_init1(0xa0, 0x4d1, &vpic->pics[1]);
}
static int intercept_pic_io(ioreq_t *p)
{
struct vpic *vpic = domain_vpic(current->domain);
uint32_t data;
if ( (p->size != 1) || (p->count != 1) )
{
gdprintk(XENLOG_WARNING,
"PIC_IO wrong access size %d!\n", (int)p->size);
return 1;
}
if ( p->dir == IOREQ_WRITE )
{
if ( p->data_is_ptr )
(void)hvm_copy_from_guest_phys(&data, p->data, p->size);
else
data = p->data;
spin_lock(vpic_lock(vpic));
pic_ioport_write((void*)&vpic->pics[p->addr>>7],
(uint32_t) p->addr, (uint32_t) (data & 0xff));
spin_unlock(vpic_lock(vpic));
}
else
{
spin_lock(vpic_lock(vpic));
data = pic_ioport_read(
(void*)&vpic->pics[p->addr>>7], (uint32_t) p->addr);
spin_unlock(vpic_lock(vpic));
if ( p->data_is_ptr )
(void)hvm_copy_to_guest_phys(p->data, &data, p->size);
else
p->data = (u64)data;
}
return 1;
}
static int intercept_elcr_io(ioreq_t *p)
{
struct vpic *vpic = domain_vpic(current->domain);
uint32_t data;
if ( (p->size != 1) || (p->count != 1) )
{
gdprintk(XENLOG_WARNING,
"PIC_IO wrong access size %d!\n", (int)p->size);
return 1;
}
if ( p->dir == IOREQ_WRITE )
{
if ( p->data_is_ptr )
(void)hvm_copy_from_guest_phys(&data, p->data, p->size);
else
data = p->data;
spin_lock(vpic_lock(vpic));
elcr_ioport_write((void*)&vpic->pics[p->addr&1],
(uint32_t) p->addr, (uint32_t)( data & 0xff));
spin_unlock(vpic_lock(vpic));
}
else
{
data = (u64) elcr_ioport_read(
(void*)&vpic->pics[p->addr&1], (uint32_t) p->addr);
if ( p->data_is_ptr )
(void)hvm_copy_to_guest_phys(p->data, &data, p->size);
else
p->data = (u64)data;
}
return 1;
}
void register_pic_io_hook(struct domain *d)
{
register_portio_handler(d, 0x20, 2, intercept_pic_io);
register_portio_handler(d, 0x4d0, 1, intercept_elcr_io);
register_portio_handler(d, 0xa0, 2, intercept_pic_io);
register_portio_handler(d, 0x4d1, 1, intercept_elcr_io);
}
int cpu_get_pic_interrupt(struct vcpu *v, int *type)
{
int intno;
struct vpic *vpic = domain_vpic(v->domain);
if ( !vlapic_accept_pic_intr(v) )
return -1;
if ( xchg(&vpic->irq_pending, 0) == 0 )
return -1;
/* Read the irq from the PIC. */
intno = pic_read_irq(vpic);
*type = APIC_DM_EXTINT;
return intno;
}
int is_periodic_irq(struct vcpu *v, int irq, int type)
{
int vec;
struct periodic_time *pt = &v->domain->arch.hvm_domain.pl_time.periodic_tm;
if ( pt->irq != 0 )
return 0;
if ( type == APIC_DM_EXTINT )
vec = domain_vpic(v->domain)->pics[0].irq_base;
else
vec = domain_vioapic(v->domain)->redirtbl[0].fields.vector;
return (irq == vec);
}
+10 -10
View File
@@ -48,7 +48,7 @@ void hvm_pci_intx_assert(
(hvm_irq->gsi_assert_count[isa_irq]++ == 0) )
{
vioapic_irq_positive_edge(d, isa_irq);
pic_set_irq(&hvm_irq->vpic, isa_irq, 1);
vpic_irq_positive_edge(d, isa_irq);
}
out:
@@ -75,7 +75,7 @@ void hvm_pci_intx_deassert(
isa_irq = hvm_irq->pci_link_route[link];
if ( (--hvm_irq->pci_link_assert_count[link] == 0) && isa_irq &&
(--hvm_irq->gsi_assert_count[isa_irq] == 0) )
pic_set_irq(&hvm_irq->vpic, isa_irq, 0);
vpic_irq_negative_edge(d, isa_irq);
out:
spin_unlock(&hvm_irq->lock);
@@ -94,7 +94,7 @@ void hvm_isa_irq_assert(
(hvm_irq->gsi_assert_count[isa_irq]++ == 0) )
{
vioapic_irq_positive_edge(d, isa_irq);
pic_set_irq(&hvm_irq->vpic, isa_irq, 1);
vpic_irq_positive_edge(d, isa_irq);
}
spin_unlock(&hvm_irq->lock);
@@ -111,7 +111,7 @@ void hvm_isa_irq_deassert(
if ( __test_and_clear_bit(isa_irq, &hvm_irq->isa_irq) &&
(--hvm_irq->gsi_assert_count[isa_irq] == 0) )
pic_set_irq(&hvm_irq->vpic, isa_irq, 0);
vpic_irq_negative_edge(d, isa_irq);
spin_unlock(&hvm_irq->lock);
}
@@ -140,7 +140,7 @@ void hvm_set_callback_irq_level(void)
{
vioapic_irq_positive_edge(d, gsi);
if ( gsi <= 15 )
pic_set_irq(&hvm_irq->vpic, gsi, 1);
vpic_irq_positive_edge(d, gsi);
}
}
else
@@ -149,7 +149,7 @@ void hvm_set_callback_irq_level(void)
(--hvm_irq->gsi_assert_count[gsi] == 0) )
{
if ( gsi <= 15 )
pic_set_irq(&hvm_irq->vpic, gsi, 0);
vpic_irq_negative_edge(d, gsi);
}
}
@@ -175,12 +175,12 @@ void hvm_set_pci_link_route(struct domain *d, u8 link, u8 isa_irq)
goto out;
if ( old_isa_irq && (--hvm_irq->gsi_assert_count[old_isa_irq] == 0) )
pic_set_irq(&hvm_irq->vpic, isa_irq, 0);
vpic_irq_negative_edge(d, isa_irq);
if ( isa_irq && (hvm_irq->gsi_assert_count[isa_irq]++ == 0) )
{
vioapic_irq_positive_edge(d, isa_irq);
pic_set_irq(&hvm_irq->vpic, isa_irq, 1);
vpic_irq_positive_edge(d, isa_irq);
}
out:
@@ -210,13 +210,13 @@ void hvm_set_callback_gsi(struct domain *d, unsigned int gsi)
if ( old_gsi && (--hvm_irq->gsi_assert_count[old_gsi] == 0) )
if ( old_gsi <= 15 )
pic_set_irq(&hvm_irq->vpic, old_gsi, 0);
vpic_irq_negative_edge(d, old_gsi);
if ( gsi && (hvm_irq->gsi_assert_count[gsi]++ == 0) )
{
vioapic_irq_positive_edge(d, gsi);
if ( gsi <= 15 )
pic_set_irq(&hvm_irq->vpic, gsi, 1);
vpic_irq_positive_edge(d, gsi);
}
out:
+25 -24
View File
@@ -128,32 +128,33 @@ asmlinkage void svm_intr_assist(void)
}
/* have we got an interrupt to inject? */
if ( intr_vector >= 0 )
if ( intr_vector < 0 )
return;
switch ( intr_type )
{
switch ( intr_type )
{
case APIC_DM_EXTINT:
case APIC_DM_FIXED:
case APIC_DM_LOWEST:
/* Re-injecting a PIT interruptt? */
if ( re_injecting && pt->enabled &&
is_periodic_irq(v, intr_vector, intr_type) )
++pt->pending_intr_nr;
/* let's inject this interrupt */
TRACE_3D(TRC_VMX_INTR, v->domain->domain_id, intr_vector, 0);
svm_inject_extint(v, intr_vector);
break;
case APIC_DM_SMI:
case APIC_DM_NMI:
case APIC_DM_INIT:
case APIC_DM_STARTUP:
default:
printk("Unsupported interrupt type: %d\n", intr_type);
BUG();
break;
}
hvm_interrupt_post(v, intr_vector, intr_type);
case APIC_DM_EXTINT:
case APIC_DM_FIXED:
case APIC_DM_LOWEST:
/* Re-injecting a PIT interruptt? */
if ( re_injecting && pt->enabled &&
is_periodic_irq(v, intr_vector, intr_type) )
++pt->pending_intr_nr;
/* let's inject this interrupt */
TRACE_3D(TRC_VMX_INTR, v->domain->domain_id, intr_vector, 0);
svm_inject_extint(v, intr_vector);
break;
case APIC_DM_SMI:
case APIC_DM_NMI:
case APIC_DM_INIT:
case APIC_DM_STARTUP:
default:
printk("Unsupported interrupt type: %d\n", intr_type);
BUG();
break;
}
hvm_interrupt_post(v, intr_vector, intr_type);
}
/*
+2 -14
View File
@@ -2,6 +2,7 @@
* vlapic.c: virtualize LAPIC for HVM vcpus.
*
* Copyright (c) 2004, Intel Corporation.
* Copyright (c) 2006 Keir Fraser, XenSource Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -38,9 +39,6 @@
#define VLAPIC_VERSION 0x00050014
#define VLAPIC_LVT_NUM 6
/* XXX remove this definition after GFW enabled */
#define VLAPIC_NO_BIOS
extern u32 get_apic_bus_cycle(void);
#define APIC_BUS_CYCLE_NS (((s_time_t)get_apic_bus_cycle()) / 1000)
@@ -147,7 +145,6 @@ int vlapic_find_highest_irr(struct vlapic *vlapic)
return result;
}
int vlapic_set_irq(struct vlapic *vlapic, uint8_t vec, uint8_t trig)
{
int ret;
@@ -860,7 +857,7 @@ int cpu_has_pending_irq(struct vcpu *v)
if ( !vlapic_accept_pic_intr(v) )
return 0;
return plat->irq.vpic.irq_pending;
return plat->irq.vpic[0].int_output;
}
void vlapic_post_injection(struct vcpu *v, int vector, int deliver_mode)
@@ -960,15 +957,6 @@ int vlapic_init(struct vcpu *v)
init_timer(&vlapic->vlapic_timer,
vlapic_timer_fn, vlapic, v->processor);
#ifdef VLAPIC_NO_BIOS
/* According to mp specification, BIOS will enable LVT0/1. */
if ( v->vcpu_id == 0 )
{
vlapic_set_reg(vlapic, APIC_LVT0, APIC_MODE_EXTINT << 8);
vlapic_set_reg(vlapic, APIC_LVT1, APIC_MODE_NMI << 8);
}
#endif
return 0;
}
+15 -7
View File
@@ -115,7 +115,8 @@ asmlinkage void vmx_intr_assist(void)
has_ext_irq = cpu_has_pending_irq(v);
if (unlikely(v->arch.hvm_vmx.vector_injected)) {
if ( unlikely(v->arch.hvm_vmx.vector_injected) )
{
v->arch.hvm_vmx.vector_injected=0;
if (unlikely(has_ext_irq)) enable_irq_window(v);
return;
@@ -123,7 +124,8 @@ asmlinkage void vmx_intr_assist(void)
/* This could be moved earlier in the VMX resume sequence. */
idtv_info_field = __vmread(IDT_VECTORING_INFO_FIELD);
if (unlikely(idtv_info_field & INTR_INFO_VALID_MASK)) {
if ( unlikely(idtv_info_field & INTR_INFO_VALID_MASK) )
{
__vmwrite(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field);
/*
@@ -145,9 +147,11 @@ asmlinkage void vmx_intr_assist(void)
return;
}
if (likely(!has_ext_irq)) return;
if ( likely(!has_ext_irq) )
return;
if (unlikely(is_interruptibility_state())) {
if ( unlikely(is_interruptibility_state()) )
{
/* pre-cleared for emulated instruction */
enable_irq_window(v);
HVM_DBG_LOG(DBG_LEVEL_1, "interruptibility");
@@ -155,13 +159,18 @@ asmlinkage void vmx_intr_assist(void)
}
eflags = __vmread(GUEST_RFLAGS);
if (irq_masked(eflags)) {
if ( irq_masked(eflags) )
{
enable_irq_window(v);
return;
}
highest_vector = cpu_get_interrupt(v, &intr_type);
switch (intr_type) {
if ( highest_vector < 0 )
return;
switch ( intr_type )
{
case APIC_DM_EXTINT:
case APIC_DM_FIXED:
case APIC_DM_LOWEST:
@@ -180,7 +189,6 @@ asmlinkage void vmx_intr_assist(void)
}
hvm_interrupt_post(v, highest_vector, intr_type);
return;
}
/*
+463
View File
@@ -0,0 +1,463 @@
/*
* i8259 interrupt controller emulation
*
* Copyright (c) 2003-2004 Fabrice Bellard
* Copyright (c) 2005 Intel Corperation
* Copyright (c) 2006 Keir Fraser, XenSource Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <xen/config.h>
#include <xen/types.h>
#include <xen/event.h>
#include <xen/lib.h>
#include <xen/errno.h>
#include <xen/sched.h>
#include <asm/hvm/hvm.h>
#include <asm/hvm/io.h>
#include <asm/hvm/support.h>
#define vpic_domain(v) (container_of((v), struct domain, \
arch.hvm_domain.irq.vpic[!vpic->is_master]))
#define __vpic_lock(v) &container_of((v), struct hvm_irq, \
vpic[!(v)->is_master])->lock
#define vpic_lock(v) spin_lock(__vpic_lock(v))
#define vpic_unlock(v) spin_unlock(__vpic_lock(v))
#define vpic_is_locked(v) spin_is_locked(__vpic_lock(v))
#define vpic_elcr_mask(v) (vpic->is_master ? (uint8_t)0xd8 : (uint8_t)0xfe);
/* Return the highest priority found in mask. Return 8 if none. */
#define VPIC_PRIO_NONE 8
static int vpic_get_priority(struct vpic *vpic, uint8_t mask)
{
int prio;
ASSERT(vpic_is_locked(vpic));
if ( mask == 0 )
return VPIC_PRIO_NONE;
/* prio = ffs(mask ROL vpic->priority_add); */
asm ( "rol %%cl,%b1 ; bsf %1,%0"
: "=r" (prio) : "r" ((uint32_t)mask), "c" (vpic->priority_add) );
return prio;
}
/* Return the PIC's highest priority pending interrupt. Return -1 if none. */
static int vpic_get_highest_priority_irq(struct vpic *vpic)
{
int cur_priority, priority, irq;
uint8_t mask;
ASSERT(vpic_is_locked(vpic));
mask = vpic->irr & ~vpic->imr;
priority = vpic_get_priority(vpic, mask);
if ( priority == VPIC_PRIO_NONE )
return -1;
irq = (priority + vpic->priority_add) & 7;
/*
* Compute current priority. If special fully nested mode on the master,
* the IRQ coming from the slave is not taken into account for the
* priority computation. In special mask mode, masked interrupts do not
* block lower-priority interrupts even if their IS bit is set.
*/
mask = vpic->isr;
if ( vpic->special_fully_nested_mode && vpic->is_master && (irq == 2) )
mask &= ~(1 << 2);
if ( vpic->special_mask_mode )
mask &= ~vpic->imr;
cur_priority = vpic_get_priority(vpic, mask);
/* If a higher priority is found then an irq should be generated. */
return (priority < cur_priority) ? irq : -1;
}
static void vpic_update_int_output(struct vpic *vpic)
{
int irq;
ASSERT(vpic_is_locked(vpic));
irq = vpic_get_highest_priority_irq(vpic);
if ( vpic->int_output == (irq >= 0) )
return;
/* INT line transition L->H or H->L. */
vpic->int_output = !vpic->int_output;
if ( vpic->int_output )
{
if ( vpic->is_master )
{
/* Master INT line is connected to VCPU0's VLAPIC LVT0. */
struct vcpu *v = vpic_domain(vpic)->vcpu[0];
if ( (v != NULL) && vlapic_accept_pic_intr(v) )
vcpu_kick(v);
}
else
{
/* Assert slave line in master PIC. */
(--vpic)->irr |= 1 << 2;
vpic_update_int_output(vpic);
}
}
else if ( !vpic->is_master )
{
/* Clear slave line in master PIC. */
(--vpic)->irr &= ~(1 << 2);
vpic_update_int_output(vpic);
}
}
static void __vpic_intack(struct vpic *vpic, int irq)
{
uint8_t mask = 1 << irq;
ASSERT(vpic_is_locked(vpic));
/* Edge-triggered: clear the IRR (forget the edge). */
if ( !(vpic->elcr & mask) )
vpic->irr &= ~mask;
if ( !vpic->auto_eoi )
vpic->isr |= mask;
else if ( vpic->rotate_on_auto_eoi )
vpic->priority_add = (irq + 1) & 7;
vpic_update_int_output(vpic);
}
static int vpic_intack(struct vpic *vpic)
{
int irq = -1;
vpic_lock(vpic);
if ( !vpic->int_output )
goto out;
irq = vpic_get_highest_priority_irq(vpic);
BUG_ON(irq < 0);
__vpic_intack(vpic, irq);
if ( (irq == 2) && vpic->is_master )
{
vpic++; /* Slave PIC */
irq = vpic_get_highest_priority_irq(vpic);
BUG_ON(irq < 0);
__vpic_intack(vpic, irq);
irq += 8;
}
out:
vpic_unlock(vpic);
return irq;
}
static void vpic_ioport_write(struct vpic *vpic, uint32_t addr, uint32_t val)
{
int priority, cmd, irq;
uint8_t mask;
vpic_lock(vpic);
addr &= 1;
if ( addr == 0 )
{
if ( val & 0x10 )
{
/* ICW1 */
/* Clear edge-sensing logic. */
vpic->irr &= vpic->elcr;
/* No interrupts masked or in service. */
vpic->imr = vpic->isr = 0;
/* IR7 is lowest priority. */
vpic->priority_add = 0;
vpic->rotate_on_auto_eoi = 0;
vpic->special_mask_mode = 0;
vpic->readsel_isr = 0;
vpic->poll = 0;
if ( !(val & 1) )
{
/* NO ICW4: ICW4 features are cleared. */
vpic->auto_eoi = 0;
vpic->special_fully_nested_mode = 0;
}
vpic->init_state = ((val & 3) << 2) | 1;
}
else if ( val & 0x08 )
{
/* OCW3 */
if ( val & 0x04 )
vpic->poll = 1;
if ( val & 0x02 )
vpic->readsel_isr = val & 1;
if ( val & 0x40 )
vpic->special_mask_mode = (val >> 5) & 1;
}
else
{
/* OCW2 */
cmd = val >> 5;
switch ( cmd )
{
case 0: /* Rotate in AEOI Mode (Clear) */
case 4: /* Rotate in AEOI Mode (Set) */
vpic->rotate_on_auto_eoi = cmd >> 2;
break;
case 1: /* Non-Specific EOI */
case 5: /* Non-Specific EOI & Rotate */
mask = vpic->isr;
if ( vpic->special_mask_mode )
mask &= ~vpic->imr; /* SMM: ignore masked IRs. */
priority = vpic_get_priority(vpic, mask);
if ( priority == VPIC_PRIO_NONE )
break;
irq = (priority + vpic->priority_add) & 7;
vpic->isr &= ~(1 << irq);
if ( cmd == 5 )
vpic->priority_add = (irq + 1) & 7;
break;
case 3: /* Specific EOI */
case 7: /* Specific EOI & Rotate */
irq = val & 7;
vpic->isr &= ~(1 << irq);
if ( cmd == 7 )
vpic->priority_add = (irq + 1) & 7;
break;
case 6: /* Set Priority */
vpic->priority_add = (val + 1) & 7;
break;
}
}
}
else
{
switch ( vpic->init_state & 3 )
{
case 0:
/* OCW1 */
vpic->imr = val;
break;
case 1:
/* ICW2 */
vpic->irq_base = val & 0xf8;
vpic->init_state++;
if ( !(vpic->init_state & 8) )
break; /* CASCADE mode: wait for write to ICW3. */
/* SNGL mode: fall through (no ICW3). */
case 2:
/* ICW3 */
vpic->init_state++;
if ( !(vpic->init_state & 4) )
vpic->init_state = 0; /* No ICW4: init done */
break;
case 3:
/* ICW4 */
vpic->special_fully_nested_mode = (val >> 4) & 1;
vpic->auto_eoi = (val >> 1) & 1;
vpic->init_state = 0;
break;
}
}
vpic_update_int_output(vpic);
vpic_unlock(vpic);
}
static uint32_t vpic_ioport_read(struct vpic *vpic, uint32_t addr)
{
if ( vpic->poll )
{
vpic->poll = 0;
return vpic_intack(vpic);
}
if ( (addr & 1) == 0 )
return (vpic->readsel_isr ? vpic->isr : vpic->irr);
return vpic->imr;
}
static int vpic_intercept_pic_io(ioreq_t *p)
{
struct vpic *vpic;
uint32_t data;
if ( (p->size != 1) || (p->count != 1) )
{
gdprintk(XENLOG_WARNING, "PIC_IO bad access size %d\n", (int)p->size);
return 1;
}
vpic = &current->domain->arch.hvm_domain.irq.vpic[p->addr >> 7];
if ( p->dir == IOREQ_WRITE )
{
if ( p->data_is_ptr )
(void)hvm_copy_from_guest_phys(&data, p->data, p->size);
else
data = p->data;
vpic_ioport_write(vpic, (uint32_t)p->addr, (uint8_t)data);
}
else
{
data = vpic_ioport_read(vpic, (uint32_t)p->addr);
if ( p->data_is_ptr )
(void)hvm_copy_to_guest_phys(p->data, &data, p->size);
else
p->data = (u64)data;
}
return 1;
}
static int vpic_intercept_elcr_io(ioreq_t *p)
{
struct vpic *vpic;
uint32_t data;
if ( (p->size != 1) || (p->count != 1) )
{
gdprintk(XENLOG_WARNING, "PIC_IO bad access size %d\n", (int)p->size);
return 1;
}
vpic = &current->domain->arch.hvm_domain.irq.vpic[p->addr & 1];
if ( p->dir == IOREQ_WRITE )
{
if ( p->data_is_ptr )
(void)hvm_copy_from_guest_phys(&data, p->data, p->size);
else
data = p->data;
/* Some IRs are always edge trig. Slave IR is always level trig. */
data &= vpic_elcr_mask(vpic);
if ( vpic->is_master )
data |= 1 << 2;
vpic->elcr = data;
}
else
{
/* Reader should not see hardcoded level-triggered slave IR. */
data = vpic->elcr & vpic_elcr_mask(vpic);
if ( p->data_is_ptr )
(void)hvm_copy_to_guest_phys(p->data, &data, p->size);
else
p->data = data;
}
return 1;
}
void vpic_init(struct domain *d)
{
struct vpic *vpic;
/* Master PIC. */
vpic = &d->arch.hvm_domain.irq.vpic[0];
memset(vpic, 0, sizeof(*vpic));
vpic->is_master = 1;
vpic->elcr = 1 << 2;
register_portio_handler(d, 0x20, 2, vpic_intercept_pic_io);
register_portio_handler(d, 0x4d0, 1, vpic_intercept_elcr_io);
/* Slave PIC. */
vpic++;
memset(vpic, 0, sizeof(*vpic));
register_portio_handler(d, 0xa0, 2, vpic_intercept_pic_io);
register_portio_handler(d, 0x4d1, 1, vpic_intercept_elcr_io);
}
void vpic_irq_positive_edge(struct domain *d, int irq)
{
struct vpic *vpic = &d->arch.hvm_domain.irq.vpic[irq >> 3];
uint8_t mask = 1 << (irq & 7);
ASSERT(irq <= 15);
ASSERT(vpic_is_locked(vpic));
if ( irq == 2 )
return;
vpic->irr |= mask;
if ( !(vpic->imr & mask) )
vpic_update_int_output(vpic);
}
void vpic_irq_negative_edge(struct domain *d, int irq)
{
struct vpic *vpic = &d->arch.hvm_domain.irq.vpic[irq >> 3];
uint8_t mask = 1 << (irq & 7);
ASSERT(irq <= 15);
ASSERT(vpic_is_locked(vpic));
if ( irq == 2 )
return;
vpic->irr &= ~mask;
if ( !(vpic->imr & mask) )
vpic_update_int_output(vpic);
}
int cpu_get_pic_interrupt(struct vcpu *v, int *type)
{
int irq, vector;
struct vpic *vpic = &v->domain->arch.hvm_domain.irq.vpic[0];
if ( !vlapic_accept_pic_intr(v) || !vpic->int_output )
return -1;
irq = vpic_intack(vpic);
if ( irq == -1 )
return -1;
vector = vpic[irq >> 3].irq_base + (irq & 7);
*type = APIC_DM_EXTINT;
return vector;
}
int is_periodic_irq(struct vcpu *v, int irq, int type)
{
int vec;
struct periodic_time *pt = &v->domain->arch.hvm_domain.pl_time.periodic_tm;
if ( pt->irq != 0 )
return 0;
if ( type == APIC_DM_EXTINT )
vec = v->domain->arch.hvm_domain.irq.vpic[0].irq_base;
else
vec = domain_vioapic(v->domain)->redirtbl[0].fields.vector;
return (irq == vec);
}
+1 -1
View File
@@ -75,7 +75,7 @@ struct hvm_irq {
* 8-15: Slave 8259 PIC, IO-APIC pins 8-15
* 16+ : IO-APIC pins 16+
*/
struct vpic vpic;
struct vpic vpic[2]; /* 0=master; 1=slave */
struct vioapic vioapic;
/* Last VCPU that was delivered a LowestPrio interrupt. */
+1
View File
@@ -2,6 +2,7 @@
* hvm_vlapic.h: virtualize LAPIC definitions.
*
* Copyright (c) 2004, Intel Corporation.
* Copyright (c) 2006 Keir Fraser, XenSource Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
+46 -31
View File
@@ -27,40 +27,55 @@
#ifndef __ASM_X86_HVM_VPIC_H__
#define __ASM_X86_HVM_VPIC_H__
#define domain_vpic(d) (&(d)->arch.hvm_domain.irq.vpic)
#define vpic_domain(v) (container_of((v), struct domain, \
arch.hvm_domain.irq.vpic))
#define vpic_lock(v) (&container_of((v), struct hvm_irq, vpic)->lock)
typedef struct PicState {
uint8_t last_irr; /* edge detection */
uint8_t irr; /* interrupt request register */
uint8_t imr; /* interrupt mask register */
uint8_t isr; /* interrupt service register */
uint8_t priority_add; /* highest irq priority */
uint8_t irq_base;
uint8_t read_reg_select;
uint8_t poll;
uint8_t special_mask;
uint8_t init_state;
uint8_t auto_eoi;
uint8_t rotate_on_auto_eoi;
uint8_t special_fully_nested_mode;
uint8_t init4; /* true if 4 byte init */
uint8_t elcr; /* PIIX edge/trigger selection*/
uint8_t elcr_mask;
struct vpic *pics_state;
} PicState;
struct vpic {
/* 0 is master pic, 1 is slave pic */
PicState pics[2];
int irq_pending;
/* IR line bitmasks. */
uint8_t irr, imr, isr;
/* Line IRx maps to IRQ irq_base+x */
uint8_t irq_base;
/*
* Where are we in ICW2-4 initialisation (0 means no init in progress)?
* Bits 0-1 (=x): Next write at A=1 sets ICW(x+1).
* Bit 2: ICW1.IC4 (1 == ICW4 included in init sequence)
* Bit 3: ICW1.SNGL (0 == ICW3 included in init sequence)
*/
uint8_t init_state:4;
/* IR line with highest priority. */
uint8_t priority_add:4;
/* Reads from A=0 obtain ISR or IRR? */
uint8_t readsel_isr:1;
/* Reads perform a polling read? */
uint8_t poll:1;
/* Automatically clear IRQs from the ISR during INTA? */
uint8_t auto_eoi:1;
/* Automatically rotate IRQ priorities during AEOI? */
uint8_t rotate_on_auto_eoi:1;
/* Exclude slave inputs when considering in-service IRQs? */
uint8_t special_fully_nested_mode:1;
/* Special mask mode excludes masked IRs from AEOI and priority checks. */
uint8_t special_mask_mode:1;
/* Is this a master PIC or slave PIC? (NB. This is not programmable.) */
uint8_t is_master:1;
/* Edge/trigger selection. */
uint8_t elcr;
/* Virtual INT output. */
uint8_t int_output;
};
void pic_set_irq(struct vpic *vpic, int irq, int level);
void pic_init(struct vpic *vpic);
void register_pic_io_hook(struct domain *d);
void vpic_irq_positive_edge(struct domain *d, int irq);
void vpic_irq_negative_edge(struct domain *d, int irq);
void vpic_init(struct domain *d);
int cpu_get_pic_interrupt(struct vcpu *v, int *type);
int is_periodic_irq(struct vcpu *v, int irq, int type);
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.