[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] [HVM] Update VPIC device model for new interrupt delivery code.
# HG changeset patch # User kaf24@xxxxxxxxxxxxxxxxxxxxx # Node ID d37b210bb8a7fc3154c72adb6b673f47d57864c4 # Parent 074b4b34e049269f25b3134bae8f6f1efd7b0cdb [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@xxxxxxxxxxxxx> --- xen/arch/x86/hvm/i8259.c | 515 --------------------- tools/firmware/hvmloader/apic_regs.h | 108 ++++ tools/firmware/hvmloader/hvmloader.c | 16 tools/firmware/hvmloader/util.c | 26 - tools/firmware/hvmloader/util.h | 6 unmodified_drivers/linux-2.6/platform-pci/evtchn.c | 32 - xen/arch/x86/hvm/Makefile | 2 xen/arch/x86/hvm/hvm.c | 20 xen/arch/x86/hvm/irq.c | 20 xen/arch/x86/hvm/svm/intr.c | 49 + xen/arch/x86/hvm/vlapic.c | 16 xen/arch/x86/hvm/vmx/io.c | 24 xen/arch/x86/hvm/vpic.c | 463 ++++++++++++++++++ xen/include/asm-x86/hvm/irq.h | 2 xen/include/asm-x86/hvm/vlapic.h | 1 xen/include/asm-x86/hvm/vpic.h | 73 +- 16 files changed, 716 insertions(+), 657 deletions(-) diff -r 074b4b34e049 -r d37b210bb8a7 tools/firmware/hvmloader/hvmloader.c --- a/tools/firmware/hvmloader/hvmloader.c Fri Nov 24 15:42:14 2006 +0000 +++ b/tools/firmware/hvmloader/hvmloader.c Sun Nov 26 13:37:27 2006 +0000 @@ -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) diff -r 074b4b34e049 -r d37b210bb8a7 tools/firmware/hvmloader/util.c --- a/tools/firmware/hvmloader/util.c Fri Nov 24 15:42:14 2006 +0000 +++ b/tools/firmware/hvmloader/util.c Sun Nov 26 13:37:27 2006 +0000 @@ -309,22 +309,24 @@ uint64_t e820_malloc(uint64_t size, uint 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); - - *ioregsel = reg; - wmb(); - *iowin = val; + *(volatile uint32_t *)(IOAPIC_BASE_ADDRESS + 0x00) = reg; + *(volatile uint32_t *)(IOAPIC_BASE_ADDRESS + 0x10) = 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) \ diff -r 074b4b34e049 -r d37b210bb8a7 tools/firmware/hvmloader/util.h --- a/tools/firmware/hvmloader/util.h Fri Nov 24 15:42:14 2006 +0000 +++ b/tools/firmware/hvmloader/util.h Sun Nov 26 13:37:27 2006 +0000 @@ -19,6 +19,12 @@ uint8_t inb(uint16_t addr); 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); diff -r 074b4b34e049 -r d37b210bb8a7 unmodified_drivers/linux-2.6/platform-pci/evtchn.c --- a/unmodified_drivers/linux-2.6/platform-pci/evtchn.c Fri Nov 24 15:42:14 2006 +0000 +++ b/unmodified_drivers/linux-2.6/platform-pci/evtchn.c Sun Nov 26 13:37:27 2006 +0000 @@ -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, vo 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); diff -r 074b4b34e049 -r d37b210bb8a7 xen/arch/x86/hvm/Makefile --- a/xen/arch/x86/hvm/Makefile Fri Nov 24 15:42:14 2006 +0000 +++ b/xen/arch/x86/hvm/Makefile Sun Nov 26 13:37:27 2006 +0000 @@ -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 += rtc.o obj-y += rtc.o obj-y += vioapic.o obj-y += vlapic.o +obj-y += vpic.o diff -r 074b4b34e049 -r d37b210bb8a7 xen/arch/x86/hvm/hvm.c --- a/xen/arch/x86/hvm/hvm.c Fri Nov 24 15:42:14 2006 +0000 +++ b/xen/arch/x86/hvm/hvm.c Sun Nov 26 13:37:27 2006 +0000 @@ -168,14 +168,13 @@ int hvm_domain_initialise(struct domain 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; - - if ( (irq = cpu_get_apic_interrupt(v, type)) != -1 ) - return irq; - - if ( (v->vcpu_id == 0) && ((irq = cpu_get_pic_interrupt(v, type)) != -1) ) - return irq; + int vector; + + if ( (vector = cpu_get_apic_interrupt(v, type)) != -1 ) + return vector; + + if ( (v->vcpu_id == 0) && + ((vector = cpu_get_pic_interrupt(v, type)) != -1) ) + return vector; return -1; } diff -r 074b4b34e049 -r d37b210bb8a7 xen/arch/x86/hvm/irq.c --- a/xen/arch/x86/hvm/irq.c Fri Nov 24 15:42:14 2006 +0000 +++ b/xen/arch/x86/hvm/irq.c Sun Nov 26 13:37:27 2006 +0000 @@ -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 domai 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 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: diff -r 074b4b34e049 -r d37b210bb8a7 xen/arch/x86/hvm/svm/intr.c --- a/xen/arch/x86/hvm/svm/intr.c Fri Nov 24 15:42:14 2006 +0000 +++ b/xen/arch/x86/hvm/svm/intr.c Sun Nov 26 13:37:27 2006 +0000 @@ -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); } /* diff -r 074b4b34e049 -r d37b210bb8a7 xen/arch/x86/hvm/vlapic.c --- a/xen/arch/x86/hvm/vlapic.c Fri Nov 24 15:42:14 2006 +0000 +++ b/xen/arch/x86/hvm/vlapic.c Sun Nov 26 13:37:27 2006 +0000 @@ -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 vlapi 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; } diff -r 074b4b34e049 -r d37b210bb8a7 xen/arch/x86/hvm/vmx/io.c --- a/xen/arch/x86/hvm/vmx/io.c Fri Nov 24 15:42:14 2006 +0000 +++ b/xen/arch/x86/hvm/vmx/io.c Sun Nov 26 13:37:27 2006 +0000 @@ -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 (unlikely(is_interruptibility_state())) { + if ( likely(!has_ext_irq) ) + return; + + 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; } /* diff -r 074b4b34e049 -r d37b210bb8a7 xen/include/asm-x86/hvm/irq.h --- a/xen/include/asm-x86/hvm/irq.h Fri Nov 24 15:42:14 2006 +0000 +++ b/xen/include/asm-x86/hvm/irq.h Sun Nov 26 13:37:27 2006 +0000 @@ -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. */ diff -r 074b4b34e049 -r d37b210bb8a7 xen/include/asm-x86/hvm/vlapic.h --- a/xen/include/asm-x86/hvm/vlapic.h Fri Nov 24 15:42:14 2006 +0000 +++ b/xen/include/asm-x86/hvm/vlapic.h Sun Nov 26 13:37:27 2006 +0000 @@ -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, diff -r 074b4b34e049 -r d37b210bb8a7 xen/include/asm-x86/hvm/vpic.h --- a/xen/include/asm-x86/hvm/vpic.h Fri Nov 24 15:42:14 2006 +0000 +++ b/xen/include/asm-x86/hvm/vpic.h Sun Nov 26 13:37:27 2006 +0000 @@ -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) +struct vpic { + /* IR line bitmasks. */ + uint8_t irr, imr, isr; -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 */ + /* Line IRx maps to IRQ irq_base+x */ 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; + /* + * 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); diff -r 074b4b34e049 -r d37b210bb8a7 tools/firmware/hvmloader/apic_regs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/firmware/hvmloader/apic_regs.h Sun Nov 26 13:37:27 2006 +0000 @@ -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 diff -r 074b4b34e049 -r d37b210bb8a7 xen/arch/x86/hvm/vpic.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/x86/hvm/vpic.c Sun Nov 26 13:37:27 2006 +0000 @@ -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 = ¤t->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 = ¤t->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); +} diff -r 074b4b34e049 -r d37b210bb8a7 xen/arch/x86/hvm/i8259.c --- a/xen/arch/x86/hvm/i8259.c Fri Nov 24 15:42:14 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -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); -} _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |