WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [xen-unstable] [HVM] Update VPIC device model for new in

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] [HVM] Update VPIC device model for new interrupt delivery code.
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Sun, 26 Nov 2006 14:30:14 +0000
Delivery-date: Sun, 26 Nov 2006 06:29:50 -0800
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# 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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] [HVM] Update VPIC device model for new interrupt delivery code., Xen patchbot-unstable <=