bitkeeper revision 1.879.1.4 (40910c4eH3ROUM3oHZRCARBR6iMt8w)
authormwilli2@equilibrium.research.intel-research.net <mwilli2@equilibrium.research.intel-research.net>
Thu, 29 Apr 2004 14:08:14 +0000 (14:08 +0000)
committermwilli2@equilibrium.research.intel-research.net <mwilli2@equilibrium.research.intel-research.net>
Thu, 29 Apr 2004 14:08:14 +0000 (14:08 +0000)
Updates to PCI virt:
    * Add support for hiding devices from dom0
    * Don't show bridges to non-0 domains by default.
    * Return the standard value of all 1s for config reads to
      non-visible devices.

xen/common/kernel.c
xen/common/physdev.c

index 3c10cf3ca2f8b68df64583a40e76a56ce582c6cc..098ca8aba03137720564dc7f82e36e029429e8c7 100644 (file)
@@ -73,6 +73,9 @@ unsigned char opt_pdb[10] = "none";
 unsigned int opt_tbuf_size = 1;
 /* opt_sched: scheduler - default to Borrowed Virtual Time */
 char opt_sched[10] = "bvt";
+/* opt_physdev_dom0_hide: list of PCI slots to hide from dom0
+ * Should have the format '(%02x:%02x.%1x)(%02x:%02x.%1x)...etc' */
+char opt_physdev_dom0_hide[20] = "";
 
 static struct {
     unsigned char *name;
@@ -94,6 +97,7 @@ static struct {
     { "pdb",              OPT_STR,  &opt_pdb },
     { "tbuf_size",        OPT_UINT, &opt_tbuf_size },
     { "sched",            OPT_STR,  &opt_sched },
+    { "physdev_dom0_hide",OPT_STR,  &opt_physdev_dom0_hide },
     { NULL,               0,        NULL     }
 };
 
index 0d14a31527be0386595230ab51dfb7d9f862e75e..b57c6b564b6781f0759f870dfae4c2cced9370ac 100644 (file)
@@ -115,16 +115,17 @@ static void add_dev_to_task(struct task_struct *p,
 
 /*
  * physdev_pci_access_modify:
- * Allow/disallow access to a specific PCI device. Also allow read access to 
- * PCI devices from the device to the root of the device tree. If the given 
- * device is a bridge, then the domain should get access to all the devices 
- * attached to that bridge (XXX this is unimplemented!).
+ * Allow/disallow access to a specific PCI device.  Guests should not be
+ * allowed to see bridge devices as it needlessly complicates things (one
+ * possible exception to this is the AGP bridge).  If the given device is a
+ * bridge, then the domain should get access to all the leaf devices below
+ * that bridge (XXX this is unimplemented!).
  */
 int physdev_pci_access_modify(
     domid_t dom, int bus, int dev, int func, int enable)
 {
     struct task_struct *p;
-    struct pci_dev *pdev, *rdev, *tdev;
+    struct pci_dev *pdev;
     int rc = 0;
  
     if ( !IS_PRIV(current) )
@@ -145,7 +146,7 @@ int physdev_pci_access_modify(
         return -ESRCH;
 
     /* Make the domain privileged. */
-    set_bit(PF_PRIVILEGED, &p->flags); 
+    set_bit(PF_PRIVILEGED, &p->flags);
 
     /* Grant write access to the specified device. */
     if ( (pdev = pci_find_slot(bus, PCI_DEVFN(dev, func))) == NULL )
@@ -155,27 +156,10 @@ int physdev_pci_access_modify(
         goto out;
     }
     add_dev_to_task(p, pdev, ACC_WRITE);
+
     INFO("  add RW %02x:%02x:%02x\n", pdev->bus->number,
          PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
 
-    /* Grant read access to the root device. */
-    if ( (rdev = pci_find_slot(0, PCI_DEVFN(0, 0))) == NULL )
-    {
-        INFO("  bizarre -- no PCI root dev\n");
-        rc = -ENODEV;
-        goto out;
-    }
-    add_dev_to_task(p, rdev, ACC_READ);
-    INFO("  add R0 %02x:%02x:%02x\n", 0, 0, 0);
-
-    /* Grant read access to all devices on the path to the root. */
-    for ( tdev = pdev->bus->self; tdev != NULL; tdev = tdev->bus->self )
-    {
-        add_dev_to_task(p, tdev, ACC_READ);
-        INFO("  add RO %02x:%02x:%02x\n", tdev->bus->number,
-             PCI_SLOT(tdev->devfn), PCI_FUNC(tdev->devfn));
-    }
-
     /* Is the device a bridge or cardbus? */
     if ( pdev->hdr_type != PCI_HEADER_TYPE_NORMAL )
         INFO("XXX can't give access to bridge devices yet\n");
@@ -256,8 +240,16 @@ static int do_base_address_access(phys_dev_t *pdev, int acc, int idx,
 
     if ( len != sizeof(u32) )
     {
-        INFO("Guest attempting sub-dword %s to BASE_ADDRESS %d\n", 
+        /* This isn't illegal, but there doesn't seem to be a very good reason
+         * to do it for normal devices (bridges are another matter).  Since it
+         * would complicate the code below, we don't support this for now. */
+
+        /* We could set *val to some value but the guest may well be in trouble
+         * anyway if this write fails.  Hopefully the printk will give us a
+         * clue what went wrong. */
+        printk("Guest attempting sub-dword %s to BASE_ADDRESS %d\n", 
              (acc == ACC_READ) ? "read" : "write", idx);
+        
         return -EPERM;
     }
 
@@ -420,7 +412,13 @@ static long pci_cfgreg_read(int bus, int dev, int func, int reg,
     phys_dev_t *pdev;
 
     if ( (ret = check_dev_acc(current, bus, dev, func, &pdev)) != 0 )
-        return ret;
+    {
+        /* PCI spec states that reads from non-existent devices should return
+         * all 1s.  In this case the domain has no read access, which should
+         * also look like the device is non-existent. */
+        *val = 0xFFFFFFFF;
+        return 0;
+    }
 
     /* Fake out read requests for some registers. */
     switch ( reg )
@@ -608,6 +606,21 @@ long do_physdev_op(physdev_op_t *uop)
     return ret;
 }
 
+/* Test if boot params specify this device should NOT be visible to DOM0
+ * (e.g. so that another domain can control it instead) */
+int pcidev_dom0_hidden(struct pci_dev *dev)
+{
+    extern char opt_physdev_dom0_hide[];
+    char cmp[10] = "(.......)";
+    
+    strncpy(&cmp[1], dev->slot_name, 7);
+
+    if ( strstr(opt_physdev_dom0_hide, dev->slot_name) == NULL )
+        return 0;
+    
+    return 1;
+}
+
 
 /* Domain 0 has read access to all devices. */
 void physdev_init_dom0(struct task_struct *p)
@@ -619,14 +632,24 @@ void physdev_init_dom0(struct task_struct *p)
 
     pci_for_each_dev(dev)
     {
-        /* Skip bridges and other peculiarities for now. */
-        if ( dev->hdr_type != PCI_HEADER_TYPE_NORMAL )
-            continue;
-        pdev = kmalloc(sizeof(phys_dev_t), GFP_KERNEL);
-        pdev->dev = dev;
-        pdev->flags = ACC_WRITE;
-        pdev->state = 0;
-        pdev->owner = p;
-        list_add(&pdev->node, &p->pcidev_list);
-       }    
+        if ( !pcidev_dom0_hidden(dev) )
+        {            
+            /* Skip bridges and other peculiarities for now. */
+            if ( dev->hdr_type != PCI_HEADER_TYPE_NORMAL )
+                continue;
+            
+            pdev = kmalloc(sizeof(phys_dev_t), GFP_KERNEL);
+            pdev->dev = dev;
+            pdev->flags = ACC_WRITE;
+            pdev->state = 0;
+            pdev->owner = p;
+            list_add(&pdev->node, &p->pcidev_list);
+        }
+        else
+        {
+            printk("Hiding PCI device %s from DOM0\n",
+                   dev->slot_name);
+        }
+    }
 }
+