[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 = &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);
+}
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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.