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

[Xen-devel] [PATCH] PCI: don't allow guest assignment of devices used by Xen


  • To: "xen-devel" <xen-devel@xxxxxxxxxxxxx>
  • From: "Jan Beulich" <JBeulich@xxxxxxxx>
  • Date: Tue, 11 Sep 2012 12:33:39 +0100
  • Delivery-date: Tue, 11 Sep 2012 11:34:04 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xen.org>

This covers the devices used for the console and the AMD IOMMU ones (as
would be any others that might get passed to pci_ro_device()).

Boot video device determination cloned from similar Linux logic.

Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
---
Note that to apply cleanly, this has to go on top of the serial console
improvement series posted earlier.

--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -311,9 +311,12 @@ void __init arch_init_memory(void)
      * Initialise our DOMID_XEN domain.
      * Any Xen-heap pages that we will allow to be mapped will have
      * their domain field set to dom_xen.
+     * Hidden PCI devices will also be associated with this domain
+     * (but be [partly] controlled by Dom0 nevertheless).
      */
     dom_xen = domain_create(DOMID_XEN, DOMCRF_dummy, 0);
     BUG_ON(IS_ERR(dom_xen));
+    INIT_LIST_HEAD(&dom_xen->arch.pdev_list);
 
     /*
      * Initialise our DOMID_IO domain.
--- a/xen/drivers/char/ehci-dbgp.c
+++ b/xen/drivers/char/ehci-dbgp.c
@@ -1364,6 +1364,8 @@ static void __init ehci_dbgp_init_postir
     init_timer(&dbgp->timer, ehci_dbgp_poll, port, 0);
 
     ehci_dbgp_setup_postirq(dbgp);
+
+    pci_hide_device(dbgp->bus, PCI_DEVFN(dbgp->slot, dbgp->func));
 }
 
 static int ehci_dbgp_check_release(struct ehci_dbgp *dbgp)
--- a/xen/drivers/char/ns16550.c
+++ b/xen/drivers/char/ns16550.c
@@ -334,6 +334,10 @@ static void __init ns16550_init_postirq(
     }
 
     ns16550_setup_postirq(uart);
+
+    if ( uart->bar || uart->ps_bdf_enable )
+        pci_hide_device(uart->ps_bdf[0], PCI_DEVFN(uart->ps_bdf[1],
+                                                   uart->ps_bdf[2]));
 }
 
 static void ns16550_suspend(struct serial_port *port)
--- a/xen/drivers/passthrough/iommu.c
+++ b/xen/drivers/passthrough/iommu.c
@@ -208,7 +208,7 @@ static int device_assigned(u16 seg, u8 b
     pdev = pci_get_pdev_by_domain(dom0, seg, bus, devfn);
     spin_unlock(&pcidevs_lock);
 
-    return pdev ? 0 : -1;
+    return pdev ? 0 : -EBUSY;
 }
 
 static int assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn)
@@ -614,7 +614,8 @@ int iommu_do_domctl(
         bus = (domctl->u.assign_device.machine_sbdf >> 8) & 0xff;
         devfn = domctl->u.assign_device.machine_sbdf & 0xff;
 
-        ret = assign_device(d, seg, bus, devfn);
+        ret = device_assigned(seg, bus, devfn) ?:
+              assign_device(d, seg, bus, devfn);
         if ( ret )
             printk(XENLOG_G_ERR "XEN_DOMCTL_assign_device: "
                    "assign %04x:%02x:%02x.%u to dom%d failed (%d)\n",
--- a/xen/drivers/passthrough/pci.c
+++ b/xen/drivers/passthrough/pci.c
@@ -208,6 +208,31 @@ static void free_pdev(struct pci_seg *ps
     xfree(pdev);
 }
 
+static void _pci_hide_device(struct pci_dev *pdev)
+{
+    if ( pdev->domain )
+        return;
+    pdev->domain = dom_xen;
+    list_add(&pdev->domain_list, &dom_xen->arch.pdev_list);
+}
+
+int __init pci_hide_device(int bus, int devfn)
+{
+    struct pci_dev *pdev;
+    int rc = -ENOMEM;
+
+    spin_lock(&pcidevs_lock);
+    pdev = alloc_pdev(get_pseg(0), bus, devfn);
+    if ( pdev )
+    {
+        _pci_hide_device(pdev);
+        rc = 0;
+    }
+    spin_unlock(&pcidevs_lock);
+
+    return rc;
+}
+
 int __init pci_ro_device(int seg, int bus, int devfn)
 {
     struct pci_seg *pseg = alloc_pseg(seg);
@@ -231,6 +256,7 @@ int __init pci_ro_device(int seg, int bu
 
     __set_bit(PCI_BDF2(bus, devfn), pseg->ro_map);
     arch_pci_ro_device(seg, PCI_BDF2(bus, devfn));
+    _pci_hide_device(pdev);
 
     return 0;
 }
@@ -718,9 +744,22 @@ static int __init _setup_dom0_pci_device
             if ( !pdev )
                 continue;
 
-            pdev->domain = ctxt->d;
-            list_add(&pdev->domain_list, &ctxt->d->arch.pdev_list);
-            ctxt->handler(pdev);
+            if ( !pdev->domain )
+            {
+                pdev->domain = ctxt->d;
+                list_add(&pdev->domain_list, &ctxt->d->arch.pdev_list);
+                ctxt->handler(pdev);
+            }
+            else if ( pdev->domain == dom_xen )
+            {
+                pdev->domain = ctxt->d;
+                ctxt->handler(pdev);
+                pdev->domain = dom_xen;
+            }
+            else if ( pdev->domain != ctxt->d )
+                printk(XENLOG_WARNING "Dom%d owning %04x:%02x:%02x.%u?\n",
+                       pdev->domain->domain_id, pseg->nr, bus,
+                       PCI_SLOT(devfn), PCI_FUNC(devfn));
         }
     }
 
--- a/xen/drivers/video/vga.c
+++ b/xen/drivers/video/vga.c
@@ -9,6 +9,7 @@
 #include <xen/lib.h>
 #include <xen/mm.h>
 #include <xen/vga.h>
+#include <xen/pci.h>
 #include <asm/io.h>
 
 /* Filled in by arch boot code. */
@@ -106,6 +107,61 @@ void __init vga_endboot(void)
 
     if ( !vgacon_keep )
         vga_puts = vga_noop_puts;
+    else
+    {
+        int bus, devfn;
+
+        for ( bus = 0; bus < 256; ++bus )
+            for ( devfn = 0; devfn < 256; ++devfn )
+            {
+                const struct pci_dev *pdev;
+                u8 b = bus, df = devfn, sb;
+
+                spin_lock(&pcidevs_lock);
+                pdev = pci_get_pdev(0, bus, devfn);
+                spin_unlock(&pcidevs_lock);
+
+                if ( !pdev ||
+                     pci_conf_read16(0, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
+                                     PCI_CLASS_DEVICE) != 0x0300 ||
+                     !(pci_conf_read16(0, bus, PCI_SLOT(devfn),
+                                       PCI_FUNC(devfn), PCI_COMMAND) &
+                       (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) )
+                    continue;
+
+                while ( b )
+                {
+                    switch ( find_upstream_bridge(0, &b, &df, &sb) )
+                    {
+                    case 0:
+                        b = 0;
+                        break;
+                    case 1:
+                        switch ( pci_conf_read8(0, b, PCI_SLOT(df),
+                                                PCI_FUNC(df),
+                                                PCI_HEADER_TYPE) )
+                        {
+                        case PCI_HEADER_TYPE_BRIDGE:
+                        case PCI_HEADER_TYPE_CARDBUS:
+                            if ( pci_conf_read16(0, b, PCI_SLOT(df),
+                                                 PCI_FUNC(df),
+                                                 PCI_BRIDGE_CONTROL) &
+                                 PCI_BRIDGE_CTL_VGA )
+                                continue;
+                            break;
+                        }
+                        break;
+                    }
+                    break;
+                }
+                if ( !b )
+                {
+                    printk(XENLOG_INFO "Boot video device %02x:%02x.%u\n",
+                           bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
+                    pci_hide_device(bus, devfn);
+                }
+            }
+    }
 
     switch ( vga_console_info.video_type )
     {
--- a/xen/include/xen/pci.h
+++ b/xen/include/xen/pci.h
@@ -103,6 +103,7 @@ int pci_add_device(u16 seg, u8 bus, u8 d
 int pci_remove_device(u16 seg, u8 bus, u8 devfn);
 int pci_ro_device(int seg, int bus, int devfn);
 void arch_pci_ro_device(int seg, int bdf);
+int pci_hide_device(int bus, int devfn);
 struct pci_dev *pci_get_pdev(int seg, int bus, int devfn);
 struct pci_dev *pci_get_pdev_by_domain(
     struct domain *, int seg, int bus, int devfn);


Attachment: pci-disallow-assign.patch
Description: Text document

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel

 


Rackspace

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