[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH] Xen: enhanced PV on HVM



Hi all,
this patch is for Xen and it is derived from an earlier patch by Shen.
The changes introduced by this patch include:

- add support to some vcpuops and physdevops for HVM domains;

- introduce a new interrupt callback method for HVM domains;

- allow HVM guests to map emulated interrupts to pirqs;

in addition to these modifications, the new version of the patch
supports remapping of real hardware interrupts into evtchns.

Signed-off-by: Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx>
Signed-off-by: Sheng Yang <sheng@xxxxxxxxxxxxxxx>

---

diff -r 3bb163b74673 xen/arch/x86/domain.c
--- a/xen/arch/x86/domain.c     Fri Feb 12 09:24:18 2010 +0000
+++ b/xen/arch/x86/domain.c     Tue Mar 09 15:34:11 2010 +0000
@@ -496,6 +496,16 @@
             if ( !IO_APIC_IRQ(i) )
                 d->arch.irq_pirq[i] = d->arch.pirq_irq[i] = i;
 
+        d->arch.pirq_emuirq = xmalloc_array(int, d->nr_pirqs);
+        d->arch.emuirq_pirq = xmalloc_array(int, d->nr_pirqs);
+        if ( !d->arch.pirq_emuirq || !d->arch.emuirq_pirq )
+            goto fail;
+        memset(d->arch.pirq_emuirq, -1,
+               d->nr_pirqs * sizeof(*d->arch.pirq_emuirq));
+        memset(d->arch.emuirq_pirq, -1,
+               d->nr_pirqs * sizeof(*d->arch.emuirq_pirq));
+
+
         if ( (rc = iommu_domain_init(d)) != 0 )
             goto fail;
 
@@ -686,7 +696,16 @@
 
     if ( is_hvm_vcpu(v) )
     {
+        unsigned long eip, cs;
         hvm_set_info_guest(v);
+
+        eip = c(user_regs.eip);
+        if (eip != 0) {
+            cs = eip >> 12 << 8;
+            hvm_vcpu_reset_state(v, cs, 0);
+            hvm_funcs.set_tsc_offset(v, 0);
+        }
+
         goto out;
     }
 
diff -r 3bb163b74673 xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c    Fri Feb 12 09:24:18 2010 +0000
+++ b/xen/arch/x86/hvm/hvm.c    Tue Mar 09 15:34:11 2010 +0000
@@ -2231,6 +2231,21 @@
     return rc;
 }
 
+static long hvm_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg)
+{
+    switch ( cmd )
+    {
+        case PHYSDEVOP_setup_gsi:
+        case PHYSDEVOP_map_pirq:
+        case PHYSDEVOP_unmap_pirq:
+        case PHYSDEVOP_eoi:
+        case PHYSDEVOP_irq_status_query:
+            return do_physdev_op(cmd, arg);
+        default:
+            return -ENOSYS;
+    }
+}
+
 static long hvm_vcpu_op(
     int cmd, int vcpuid, XEN_GUEST_HANDLE(void) arg)
 {
@@ -2240,6 +2255,14 @@
     {
     case VCPUOP_register_runstate_memory_area:
     case VCPUOP_get_runstate_info:
+    case VCPUOP_initialise:
+    case VCPUOP_up:
+    case VCPUOP_is_up:
+    case VCPUOP_set_periodic_timer:
+    case VCPUOP_stop_periodic_timer:
+    case VCPUOP_set_singleshot_timer:
+    case VCPUOP_stop_singleshot_timer:
+    case VCPUOP_register_vcpu_time_memory_area:
         rc = do_vcpu_op(cmd, vcpuid, arg);
         break;
     default:
@@ -2262,9 +2285,11 @@
     [ __HYPERVISOR_memory_op ] = (hvm_hypercall_t *)hvm_memory_op,
     [ __HYPERVISOR_grant_table_op ] = (hvm_hypercall_t *)hvm_grant_table_op,
     [ __HYPERVISOR_vcpu_op ] = (hvm_hypercall_t *)hvm_vcpu_op,
+    [ __HYPERVISOR_physdev_op ] = (hvm_hypercall_t *)hvm_physdev_op,
     HYPERCALL(xen_version),
     HYPERCALL(event_channel_op),
     HYPERCALL(sched_op),
+    HYPERCALL(set_timer_op),
     HYPERCALL(hvm_op)
 };
 
@@ -2296,6 +2321,14 @@
     {
     case VCPUOP_register_runstate_memory_area:
     case VCPUOP_get_runstate_info:
+    case VCPUOP_initialise:
+    case VCPUOP_up:
+    case VCPUOP_is_up:
+    case VCPUOP_set_periodic_timer:
+    case VCPUOP_stop_periodic_timer:
+    case VCPUOP_set_singleshot_timer:
+    case VCPUOP_stop_singleshot_timer:
+    case VCPUOP_register_vcpu_time_memory_area:
         rc = compat_vcpu_op(cmd, vcpuid, arg);
         break;
     default:
@@ -2306,13 +2339,33 @@
     return rc;
 }
 
+static long hvm_physdev_op_compat32(
+    int cmd, XEN_GUEST_HANDLE(void) arg)
+{
+    switch ( cmd )
+    {
+        case PHYSDEVOP_setup_gsi:
+        case PHYSDEVOP_map_pirq:
+        case PHYSDEVOP_unmap_pirq:
+        case PHYSDEVOP_eoi:
+        case PHYSDEVOP_irq_status_query:
+            return compat_physdev_op(cmd, arg);
+        break;
+    default:
+            return -ENOSYS;
+        break;
+    }
+}
+
 static hvm_hypercall_t *hvm_hypercall64_table[NR_hypercalls] = {
     [ __HYPERVISOR_memory_op ] = (hvm_hypercall_t *)hvm_memory_op,
     [ __HYPERVISOR_grant_table_op ] = (hvm_hypercall_t *)hvm_grant_table_op,
     [ __HYPERVISOR_vcpu_op ] = (hvm_hypercall_t *)hvm_vcpu_op,
+    [ __HYPERVISOR_physdev_op ] = (hvm_hypercall_t *)hvm_physdev_op,
     HYPERCALL(xen_version),
     HYPERCALL(event_channel_op),
     HYPERCALL(sched_op),
+    HYPERCALL(set_timer_op),
     HYPERCALL(hvm_op)
 };
 
@@ -2320,9 +2373,11 @@
     [ __HYPERVISOR_memory_op ] = (hvm_hypercall_t *)hvm_memory_op_compat32,
     [ __HYPERVISOR_grant_table_op ] = (hvm_hypercall_t 
*)hvm_grant_table_op_compat32,
     [ __HYPERVISOR_vcpu_op ] = (hvm_hypercall_t *)hvm_vcpu_op_compat32,
+    [ __HYPERVISOR_physdev_op ] = (hvm_hypercall_t *)hvm_physdev_op_compat32,
     HYPERCALL(xen_version),
     HYPERCALL(event_channel_op),
     HYPERCALL(sched_op),
+    HYPERCALL(set_timer_op),
     HYPERCALL(hvm_op)
 };
 
diff -r 3bb163b74673 xen/arch/x86/hvm/irq.c
--- a/xen/arch/x86/hvm/irq.c    Fri Feb 12 09:24:18 2010 +0000
+++ b/xen/arch/x86/hvm/irq.c    Tue Mar 09 15:34:11 2010 +0000
@@ -23,8 +23,29 @@
 #include <xen/types.h>
 #include <xen/event.h>
 #include <xen/sched.h>
+#include <xen/irq.h>
 #include <asm/hvm/domain.h>
 #include <asm/hvm/support.h>
+
+/* Must be called with hvm_domain->irq_lock hold */
+static void assert_irq(struct domain *d, unsigned ioapic_gsi, unsigned pic_irq)
+{
+    int pirq = domain_emuirq_to_pirq(d, ioapic_gsi);
+    if ( pirq >= 0 )
+    {
+        send_guest_pirq(d, pirq);
+        return;
+    }
+    vioapic_irq_positive_edge(d, ioapic_gsi);
+    vpic_irq_positive_edge(d, pic_irq);
+}
+
+/* Must be called with hvm_domain->irq_lock hold */
+static void deassert_irq(struct domain *d, unsigned isa_irq)
+{
+    if ( domain_emuirq_to_pirq(d, isa_irq) <= 0 )
+        vpic_irq_negative_edge(d, isa_irq);
+}
 
 static void __hvm_pci_intx_assert(
     struct domain *d, unsigned int device, unsigned int intx)
@@ -45,10 +66,7 @@
     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) )
-    {
-        vioapic_irq_positive_edge(d, isa_irq);
-        vpic_irq_positive_edge(d, isa_irq);
-    }
+        assert_irq(d, isa_irq, isa_irq);
 }
 
 void hvm_pci_intx_assert(
@@ -77,7 +95,7 @@
     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) )
-        vpic_irq_negative_edge(d, isa_irq);
+        deassert_irq(d, isa_irq);
 }
 
 void hvm_pci_intx_deassert(
@@ -100,10 +118,7 @@
 
     if ( !__test_and_set_bit(isa_irq, &hvm_irq->isa_irq.i) &&
          (hvm_irq->gsi_assert_count[gsi]++ == 0) )
-    {
-        vioapic_irq_positive_edge(d, gsi);
-        vpic_irq_positive_edge(d, isa_irq);
-    }
+        assert_irq(d, gsi, isa_irq);
 
     spin_unlock(&d->arch.hvm_domain.irq_lock);
 }
@@ -120,7 +135,7 @@
 
     if ( __test_and_clear_bit(isa_irq, &hvm_irq->isa_irq.i) &&
          (--hvm_irq->gsi_assert_count[gsi] == 0) )
-        vpic_irq_negative_edge(d, isa_irq);
+        deassert_irq(d, isa_irq);
 
     spin_unlock(&d->arch.hvm_domain.irq_lock);
 }
@@ -185,16 +200,16 @@
 
 void hvm_assert_evtchn_irq(struct vcpu *v)
 {
-    if ( v->vcpu_id != 0 )
-        return;
-
     if ( unlikely(in_irq() || !local_irq_is_enabled()) )
     {
         tasklet_schedule(&v->arch.hvm_vcpu.assert_evtchn_irq_tasklet);
         return;
     }
 
-    hvm_set_callback_irq_level(v);
+    if (is_hvm_pv_evtchn_vcpu(v))
+        vcpu_kick(v);
+    else
+        hvm_set_callback_irq_level(v);
 }
 
 void hvm_set_pci_link_route(struct domain *d, u8 link, u8 isa_irq)
@@ -251,7 +266,7 @@
 
     via_type = (uint8_t)(via >> 56) + 1;
     if ( ((via_type == HVMIRQ_callback_gsi) && (via == 0)) ||
-         (via_type > HVMIRQ_callback_pci_intx) )
+         (via_type > HVMIRQ_callback_vector) )
         via_type = HVMIRQ_callback_none;
 
     spin_lock(&d->arch.hvm_domain.irq_lock);
@@ -297,6 +312,9 @@
         if ( hvm_irq->callback_via_asserted )
              __hvm_pci_intx_assert(d, pdev, pintx);
         break;
+    case HVMIRQ_callback_vector:
+        hvm_irq->callback_via.vector = (uint8_t)via;
+        break;
     default:
         break;
     }
@@ -312,6 +330,10 @@
     case HVMIRQ_callback_pci_intx:
         printk("PCI INTx Dev 0x%02x Int%c\n", pdev, 'A' + pintx);
         break;
+    case HVMIRQ_callback_vector:
+        printk("Set HVMIRQ_callback_vector to %u\n",
+               hvm_irq->callback_via.vector);
+        break;
     default:
         printk("None\n");
         break;
@@ -323,6 +345,10 @@
     struct hvm_domain *plat = &v->domain->arch.hvm_domain;
     int vector;
 
+    if (plat->irq.callback_via_type == HVMIRQ_callback_vector &&
+            vcpu_info(v, evtchn_upcall_pending))
+        return hvm_intack_vector(plat->irq.callback_via.vector);
+ 
     if ( unlikely(v->nmi_pending) )
         return hvm_intack_nmi;
 
@@ -363,6 +389,8 @@
     case hvm_intsrc_lapic:
         if ( !vlapic_ack_pending_irq(v, intack.vector) )
             intack = hvm_intack_none;
+        break;
+    case hvm_intsrc_vector:
         break;
     default:
         intack = hvm_intack_none;
diff -r 3bb163b74673 xen/arch/x86/hvm/vmx/intr.c
--- a/xen/arch/x86/hvm/vmx/intr.c       Fri Feb 12 09:24:18 2010 +0000
+++ b/xen/arch/x86/hvm/vmx/intr.c       Tue Mar 09 15:34:11 2010 +0000
@@ -164,7 +164,8 @@
     {
         HVMTRACE_2D(INJ_VIRQ, intack.vector, /*fake=*/ 0);
         vmx_inject_extint(intack.vector);
-        pt_intr_post(v, intack);
+        if (intack.source != hvm_intsrc_vector)
+             pt_intr_post(v, intack);
     }
 
     /* Is there another IRQ to queue up behind this one? */
diff -r 3bb163b74673 xen/arch/x86/irq.c
--- a/xen/arch/x86/irq.c        Fri Feb 12 09:24:18 2010 +0000
+++ b/xen/arch/x86/irq.c        Tue Mar 09 15:34:11 2010 +0000
@@ -1394,7 +1394,10 @@
     {
         for ( i = 16; i < nr_irqs_gsi; i++ )
             if ( !d->arch.pirq_irq[i] )
-                break;
+            {
+                if ( !is_hvm_domain(d) || d->arch.pirq_emuirq[i] < 0 )
+                    break;
+            }
         if ( i == nr_irqs_gsi )
             return -ENOSPC;
     }
@@ -1402,7 +1405,10 @@
     {
         for ( i = d->nr_pirqs - 1; i >= nr_irqs_gsi; i-- )
             if ( !d->arch.pirq_irq[i] )
-                break;
+            {
+                if ( !is_hvm_domain(d) || d->arch.pirq_emuirq[i] < 0 )
+                    break;
+            }
         if ( i < nr_irqs_gsi )
             return -ENOSPC;
     }
@@ -1733,3 +1739,65 @@
         peoi[sp].ready = 1;
     flush_ready_eoi();
 }
+
+int map_domain_emuirq_pirq(
+    struct domain *d, int pirq, int emuirq, int type, void *data)
+{
+    int old_emuirq, old_pirq, ret = 0;
+
+    ASSERT(spin_is_locked(&d->event_lock));
+
+    if ( !is_hvm_domain(d) )
+        return -EINVAL;
+
+    if ( pirq < 0 || pirq >= d->nr_pirqs || emuirq < 0 || emuirq >= nr_irqs )
+    {
+        dprintk(XENLOG_G_ERR, "dom%d: invalid pirq %d or irq %d\n",
+                d->domain_id, pirq, emuirq);
+        return -EINVAL;
+    }
+
+    old_emuirq = domain_pirq_to_emuirq(d, pirq);
+    old_pirq = domain_emuirq_to_pirq(d, emuirq);
+
+    if ( (old_emuirq > 0 && (old_emuirq != emuirq) ) ||
+         (old_pirq > 0 && (old_pirq != pirq)) )
+    {
+        dprintk(XENLOG_G_WARNING, "dom%d: pirq %d or emuirq %d already 
mapped\n",
+                d->domain_id, pirq, emuirq);
+        return 0;
+    }
+
+    d->arch.pirq_emuirq[pirq] = emuirq;
+    d->arch.emuirq_pirq[emuirq] = pirq;
+
+    return ret;
+}
+
+int unmap_domain_pirq_emuirq(struct domain *d, int pirq)
+{
+    int emuirq, ret = 0;
+
+    if ( !is_hvm_domain(d) )
+        return -EINVAL;
+
+    if ( (pirq < 0) || (pirq >= d->nr_pirqs) )
+        return -EINVAL;
+
+    ASSERT(spin_is_locked(&d->event_lock));
+
+    emuirq = domain_pirq_to_emuirq(d, pirq);
+    if ( emuirq <= 0 )
+    {
+        dprintk(XENLOG_G_ERR, "dom%d: pirq %d not mapped\n",
+                d->domain_id, pirq);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    d->arch.pirq_emuirq[pirq] = -1;
+    d->arch.emuirq_pirq[emuirq] = -1;
+
+ done:
+    return ret;
+}
diff -r 3bb163b74673 xen/arch/x86/physdev.c
--- a/xen/arch/x86/physdev.c    Fri Feb 12 09:24:18 2010 +0000
+++ b/xen/arch/x86/physdev.c    Tue Mar 09 15:34:11 2010 +0000
@@ -44,6 +44,49 @@
 
     if ( d == NULL )
         return -ESRCH;
+   
+    if ( map->domid == DOMID_SELF && is_hvm_domain(d) )
+    {
+        spin_lock(&d->event_lock);
+        switch ( map->type )
+        {
+            case MAP_PIRQ_TYPE_GSI :
+                {
+                    struct hvm_irq_dpci *hvm_irq_dpci;
+                    struct hvm_girq_dpci_mapping *girq;
+                    uint32_t machine_gsi = map->pirq;
+
+                    hvm_irq_dpci = domain_get_irq_dpci(d);
+                    if (hvm_irq_dpci) {
+                        list_for_each_entry ( girq, 
&hvm_irq_dpci->girq[map->index], list ) {
+                            machine_gsi = girq->machine_gsi;
+                        }
+                    }
+                    if ( machine_gsi != map->pirq )
+                    {
+                        map->index = domain_pirq_to_irq(d, machine_gsi);
+                        pirq = machine_gsi;
+                    }
+                    else
+                    {
+                        pirq = map->pirq;
+                        if ( pirq < 0 )
+                        {
+                            pirq = get_free_pirq(d, map->type, map->index);
+                        }
+                    }
+                    ret = map_domain_emuirq_pirq(d, pirq, map->index, 
map->type, NULL);
+                    map->pirq = pirq;
+                }
+                break;
+            default :
+                ret = -EINVAL;
+                dprintk(XENLOG_G_WARNING, "map type %d not supported yet\n", 
map->type);
+                break;
+        }
+        spin_unlock(&d->event_lock);
+        return ret;
+    }
 
     if ( !IS_PRIV_FOR(current->domain, d) )
     {
@@ -143,7 +186,18 @@
             goto done;
         }
         else
-            pirq = map->pirq;
+        {
+            if ( is_hvm_domain(d) && domain_pirq_to_emuirq(d, map->pirq) >= 0)
+                pirq = get_free_pirq(d, map->type, map->index);
+            else
+                pirq = map->pirq;
+            if ( pirq < 0 )
+            {
+                dprintk(XENLOG_G_ERR, "dom%d: no free pirq\n", d->domain_id);
+                ret = pirq;
+                goto done;
+            }
+        }
     }
 
     ret = map_domain_pirq(d, pirq, irq, map->type, map_data);
@@ -172,6 +226,14 @@
 
     if ( d == NULL )
         return -ESRCH;
+
+    if ( is_hvm_domain(d) )
+    {
+        spin_lock(&d->event_lock);
+        ret = unmap_domain_pirq_emuirq(d, unmap->pirq);
+        spin_unlock(&d->event_lock);
+        goto free_domain;
+    }
 
     ret = -EPERM;
     if ( !IS_PRIV_FOR(current->domain, d) )
@@ -206,7 +268,10 @@
             break;
         if ( v->domain->arch.pirq_eoi_map )
             evtchn_unmask(v->domain->pirq_to_evtchn[eoi.irq]);
-        ret = pirq_guest_eoi(v->domain, eoi.irq);
+        if ( !is_hvm_domain(v->domain) )
+            ret = pirq_guest_eoi(v->domain, eoi.irq);
+        else
+            ret = 0;
         break;
     }
 
@@ -261,6 +326,12 @@
         if ( (irq < 0) || (irq >= v->domain->nr_pirqs) )
             break;
         irq_status_query.flags = 0;
+        if ( is_hvm_domain(v->domain) )
+        {
+            ret = copy_to_guest(arg, &irq_status_query, 1) ? -EFAULT : 0;
+            break;
+        }
+
         /*
          * Even edge-triggered or message-based IRQs can need masking from
          * time to time. If teh guest is not dynamically checking for this
@@ -465,6 +536,11 @@
     case PHYSDEVOP_setup_gsi: {
         struct physdev_setup_gsi setup_gsi;
 
+        /* In the HVM case we are setting up an emulated GSI, therefore
+         * there is no need to do anything here */
+        if ( is_hvm_domain(v->domain) )
+            return 0;
+
         ret = -EPERM;
         if ( !IS_PRIV(v->domain) )
             break;
diff -r 3bb163b74673 xen/common/event_channel.c
--- a/xen/common/event_channel.c        Fri Feb 12 09:24:18 2010 +0000
+++ b/xen/common/event_channel.c        Tue Mar 09 15:34:11 2010 +0000
@@ -305,7 +305,7 @@
     if ( (pirq < 0) || (pirq >= d->nr_pirqs) )
         return -EINVAL;
 
-    if ( !irq_access_permitted(d, pirq) )
+    if ( !is_hvm_domain(d) && !irq_access_permitted(d, pirq) )
         return -EPERM;
 
     spin_lock(&d->event_lock);
@@ -319,12 +319,15 @@
     chn = evtchn_from_port(d, port);
 
     d->pirq_to_evtchn[pirq] = port;
-    rc = pirq_guest_bind(d->vcpu[0], pirq, 
-                         !!(bind->flags & BIND_PIRQ__WILL_SHARE));
-    if ( rc != 0 )
+    if ( !is_hvm_domain(d) )
     {
-        d->pirq_to_evtchn[pirq] = 0;
-        goto out;
+        rc = pirq_guest_bind(d->vcpu[0], pirq, 
+                !!(bind->flags & BIND_PIRQ__WILL_SHARE));
+        if ( rc != 0 )
+        {
+            d->pirq_to_evtchn[pirq] = 0;
+            goto out;
+        }
     }
 
     chn->state  = ECS_PIRQ;
@@ -376,7 +379,8 @@
         break;
 
     case ECS_PIRQ:
-        pirq_guest_unbind(d1, chn1->u.pirq);
+        if ( !is_hvm_domain(d1) )
+            pirq_guest_unbind(d1, chn1->u.pirq);
         d1->pirq_to_evtchn[chn1->u.pirq] = 0;
         break;
 
@@ -636,8 +640,17 @@
     /*
      * It should not be possible to race with __evtchn_close():
      * The caller of this function must synchronise with pirq_guest_unbind().
+     *
+     * In the HVM case port is 0 when the guest disable the
+     * emulated interrupt\evtchn.
      */
-    ASSERT(port != 0);
+    if (!port)
+    {
+        if ( is_hvm_domain(d) )
+            return 0;
+        else
+            return -EINVAL;
+    }
 
     chn = evtchn_from_port(d, port);
     return evtchn_set_pending(d->vcpu[chn->notify_vcpu_id], port);
@@ -824,6 +837,7 @@
 long do_event_channel_op(int cmd, XEN_GUEST_HANDLE(void) arg)
 {
     long rc;
+    struct domain *d = current->domain;
 
     switch ( cmd )
     {
@@ -852,6 +866,10 @@
         if ( copy_from_guest(&bind_virq, arg, 1) != 0 )
             return -EFAULT;
         rc = evtchn_bind_virq(&bind_virq);
+        if ( is_hvm_domain(d) && bind_virq.virq == VIRQ_TIMER) {
+            update_domain_wallclock_time(d);
+            hvm_funcs.set_tsc_offset(d->vcpu[0], 0);
+        }
         if ( (rc == 0) && (copy_to_guest(arg, &bind_virq, 1) != 0) )
             rc = -EFAULT; /* Cleaning up here would be a mess! */
         break;
diff -r 3bb163b74673 xen/drivers/passthrough/io.c
--- a/xen/drivers/passthrough/io.c      Fri Feb 12 09:24:18 2010 +0000
+++ b/xen/drivers/passthrough/io.c      Tue Mar 09 15:34:11 2010 +0000
@@ -446,7 +446,11 @@
 extern int vmsi_deliver(struct domain *d, int pirq);
 static int hvm_pci_msi_assert(struct domain *d, int pirq)
 {
-    return vmsi_deliver(d, pirq);
+    int emuirq = domain_pirq_to_emuirq(d, pirq);
+    if ( emuirq < 0 )
+        return vmsi_deliver(d, pirq);
+    else
+        return send_guest_pirq(d, pirq);
 }
 #endif
 
@@ -480,7 +484,10 @@
         {
             device = digl->device;
             intx = digl->intx;
-            hvm_pci_intx_assert(d, device, intx);
+            if ( is_hvm_domain(d) && domain_pirq_to_emuirq(d, pirq) >=0 )
+                send_guest_pirq(d, pirq);
+            else
+                hvm_pci_intx_assert(d, device, intx);
             hvm_irq_dpci->mirq[pirq].pending++;
 
 #ifdef SUPPORT_MSI_REMAPPING
diff -r 3bb163b74673 xen/include/asm-x86/domain.h
--- a/xen/include/asm-x86/domain.h      Fri Feb 12 09:24:18 2010 +0000
+++ b/xen/include/asm-x86/domain.h      Tue Mar 09 15:34:11 2010 +0000
@@ -278,6 +278,9 @@
     /* NB. protected by d->event_lock and by irq_desc[irq].lock */
     int *irq_pirq;
     int *pirq_irq;
+    /* pirq to emulated irq and vice versa */
+    int *emuirq_pirq;
+    int *pirq_emuirq;
 
     /* Shared page for notifying that explicit PIRQ EOI is required. */
     unsigned long *pirq_eoi_map;
diff -r 3bb163b74673 xen/include/asm-x86/hvm/hvm.h
--- a/xen/include/asm-x86/hvm/hvm.h     Fri Feb 12 09:24:18 2010 +0000
+++ b/xen/include/asm-x86/hvm/hvm.h     Tue Mar 09 15:34:11 2010 +0000
@@ -33,7 +33,8 @@
     hvm_intsrc_pic,
     hvm_intsrc_lapic,
     hvm_intsrc_nmi,
-    hvm_intsrc_mce
+    hvm_intsrc_mce,
+    hvm_intsrc_vector
 };
 struct hvm_intack {
     uint8_t source; /* enum hvm_intsrc */
@@ -44,6 +45,7 @@
 #define hvm_intack_lapic(vec) ( (struct hvm_intack) { hvm_intsrc_lapic, vec } )
 #define hvm_intack_nmi        ( (struct hvm_intack) { hvm_intsrc_nmi,   2 } )
 #define hvm_intack_mce        ( (struct hvm_intack) { hvm_intsrc_mce,   18 } )
+#define hvm_intack_vector(vec)( (struct hvm_intack) { hvm_intsrc_vector, vec } 
)
 enum hvm_intblk {
     hvm_intblk_none,      /* not blocked (deliverable) */
     hvm_intblk_shadow,    /* MOV-SS or STI shadow */
diff -r 3bb163b74673 xen/include/asm-x86/hvm/irq.h
--- a/xen/include/asm-x86/hvm/irq.h     Fri Feb 12 09:24:18 2010 +0000
+++ b/xen/include/asm-x86/hvm/irq.h     Tue Mar 09 15:34:11 2010 +0000
@@ -54,12 +54,14 @@
         enum {
             HVMIRQ_callback_none,
             HVMIRQ_callback_gsi,
-            HVMIRQ_callback_pci_intx
+            HVMIRQ_callback_pci_intx,
+            HVMIRQ_callback_vector
         } callback_via_type;
     };
     union {
         uint32_t gsi;
         struct { uint8_t dev, intx; } pci;
+        uint32_t vector;
     } callback_via;
 
     /* Number of INTx wires asserting each PCI-ISA link. */
diff -r 3bb163b74673 xen/include/asm-x86/irq.h
--- a/xen/include/asm-x86/irq.h Fri Feb 12 09:24:18 2010 +0000
+++ b/xen/include/asm-x86/irq.h Tue Mar 09 15:34:11 2010 +0000
@@ -112,6 +112,9 @@
 int map_domain_pirq(struct domain *d, int pirq, int irq, int type,
                            void *data);
 int unmap_domain_pirq(struct domain *d, int pirq);
+int map_domain_emuirq_pirq(struct domain *d, int pirq, int irq, int type,
+                           void *data);
+int unmap_domain_pirq_emuirq(struct domain *d, int pirq);
 int get_free_pirq(struct domain *d, int type, int index);
 void free_domain_pirqs(struct domain *d);
 
@@ -147,5 +150,7 @@
 
 #define domain_pirq_to_irq(d, pirq) ((d)->arch.pirq_irq[pirq])
 #define domain_irq_to_pirq(d, irq) ((d)->arch.irq_pirq[irq])
+#define domain_pirq_to_emuirq(d, pirq) ((d)->arch.pirq_emuirq[pirq])
+#define domain_emuirq_to_pirq(d, emuirq) ((d)->arch.emuirq_pirq[emuirq])
 
 #endif /* _ASM_HW_IRQ_H */
diff -r 3bb163b74673 xen/include/xen/sched.h
--- a/xen/include/xen/sched.h   Fri Feb 12 09:24:18 2010 +0000
+++ b/xen/include/xen/sched.h   Tue Mar 09 15:34:11 2010 +0000
@@ -592,6 +592,9 @@
 #define VM_ASSIST(_d,_t) (test_bit((_t), &(_d)->vm_assist))
 
 #define is_hvm_domain(d) ((d)->is_hvm)
+#define is_hvm_pv_evtchn_domain(d) (is_hvm_domain(d) && \
+           d->arch.hvm_domain.irq.callback_via_type == HVMIRQ_callback_vector)
+#define is_hvm_pv_evtchn_vcpu(v) (is_hvm_pv_evtchn_domain(v->domain))
 #define is_hvm_vcpu(v)   (is_hvm_domain(v->domain))
 #define need_iommu(d)    ((d)->need_iommu)
 

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

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