diff -Naurp --exclude-from /home/muli/w/dontdiff xen-unstable-src-200503071354/xen/common/physdev.c vpci/xen/common/physdev.c --- xen-unstable-src-200503071354/xen/common/physdev.c 2005-03-03 23:17:33.000000000 -0500 +++ vpci/xen/common/physdev.c 2005-03-07 17:41:59.000000000 -0500 @@ -32,12 +32,13 @@ /* Called by PHYSDEV_PCI_INITIALISE_DEVICE to finalise IRQ routing. */ extern void pcibios_enable_irq(struct pci_dev *dev); -#if 0 +#if 1 #define VERBOSE_INFO(_f, _a...) printk( _f , ## _a ) #else #define VERBOSE_INFO(_f, _a...) ((void)0) #endif +#define VERBOSE #ifdef VERBOSE #define INFO(_f, _a...) printk( _f, ## _a ) #else @@ -85,31 +86,91 @@ static phys_dev_t *find_pdev(struct doma } /* Add a device to a per-domain device-access list. */ -static void add_dev_to_task(struct domain *p, - struct pci_dev *dev, int acc) +static int add_dev_to_task(struct domain *p, struct pci_dev *dev, + int acc) { - phys_dev_t *pdev; + phys_dev_t *physdev; - if ( (pdev = find_pdev(p, dev)) ) - { - /* Sevice already on list: update access permissions. */ - pdev->flags = acc; - return; - } - - if ( (pdev = xmalloc(phys_dev_t)) == NULL ) + if ( (physdev = xmalloc(phys_dev_t)) == NULL ) { INFO("Error allocating pdev structure.\n"); - return; + return -ENOMEM; } - pdev->dev = dev; - pdev->flags = acc; - pdev->state = 0; - list_add(&pdev->node, &p->pcidev_list); + physdev->dev = dev; + physdev->flags = acc; + physdev->state = 0; + list_add(&physdev->node, &p->pcidev_list); if ( acc == ACC_WRITE ) - pdev->owner = p; + physdev->owner = p; + + return 0; +} + +/* Remove a device from a per-domain device-access list. */ +static void remove_dev_from_task(struct domain *p, struct pci_dev *dev) +{ + phys_dev_t *physdev = find_pdev(p, dev); + + if ( physdev == NULL ) + BUG(); + + list_del(&physdev->node); + + xfree(physdev); +} + +static int setup_ioport_memory_access(domid_t dom, struct domain* p, + struct exec_domain* ed, + struct pci_dev *pdev) +{ + struct exec_domain* edc; + int i, j; + + /* Now, setup access to the IO ports and memory regions for the device. */ + if ( ed->arch.io_bitmap == NULL ) + { + if ( (ed->arch.io_bitmap = xmalloc_array(u8, IOBMP_BYTES)) == NULL ) + return -ENOMEM; + + memset(ed->arch.io_bitmap, 0xFF, IOBMP_BYTES); + + ed->arch.io_bitmap_sel = ~0ULL; + + for_each_exec_domain(p, edc) { + if (edc == ed) + continue; + edc->arch.io_bitmap = ed->arch.io_bitmap; + } + } + + for ( i = 0; i < DEVICE_COUNT_RESOURCE; i++ ) + { + struct resource *r = &pdev->resource[i]; + + if ( r->flags & IORESOURCE_IO ) + { + /* Give the domain access to the IO ports it needs. Currently, + * this will allow all processes in that domain access to those + * ports as well. This will do for now, since driver domains don't + * run untrusted processes! */ + INFO("Giving domain %u IO resources (%lx - %lx) " + "for device %s\n", dom, r->start, r->end, pdev->slot_name); + for ( j = r->start; j < r->end + 1; j++ ) + { + clear_bit(j, ed->arch.io_bitmap); + clear_bit(j / IOBMP_BITS_PER_SELBIT, &ed->arch.io_bitmap_sel); + } + } + /* rights to IO memory regions are checked when the domain maps them */ + } + + for_each_exec_domain(p, edc) { + if (edc == ed) + continue; + edc->arch.io_bitmap_sel = ed->arch.io_bitmap_sel; + } } /* @@ -124,9 +185,11 @@ int physdev_pci_access_modify( domid_t dom, int bus, int dev, int func, int enable) { struct domain *p; - struct exec_domain *ed, *edc; + struct exec_domain *ed; struct pci_dev *pdev; - int i, j, rc = 0; + phys_dev_t *physdev; + int rc = 0; + int oldacc = -1; if ( !IS_PRIV(current->domain) ) BUG(); @@ -158,66 +221,46 @@ int physdev_pci_access_modify( { INFO(" dev does not exist\n"); rc = -ENODEV; - goto out; + goto clear_priviledge; + } + + if ( (physdev = find_pdev(p, pdev)) != NULL) { + /* Sevice already on list: update access permissions. */ + oldacc = physdev->flags; + physdev->flags = ACC_WRITE; + } else { + if ( (rc = add_dev_to_task(p, pdev, ACC_WRITE)) < 0) + goto clear_priviledge; } - 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)); /* Is the device a bridge or cardbus? */ - if ( pdev->hdr_type != PCI_HEADER_TYPE_NORMAL ) + if ( pdev->hdr_type != PCI_HEADER_TYPE_NORMAL ) { INFO("XXX can't give access to bridge devices yet\n"); - - /* Now, setup access to the IO ports and memory regions for the device. */ - - if ( ed->arch.io_bitmap == NULL ) - { - if ( (ed->arch.io_bitmap = xmalloc_array(u8, IOBMP_BYTES)) == NULL ) - { - rc = -ENOMEM; - goto out; - } - memset(ed->arch.io_bitmap, 0xFF, IOBMP_BYTES); - - ed->arch.io_bitmap_sel = ~0ULL; - - for_each_exec_domain(p, edc) { - if (edc == ed) - continue; - edc->arch.io_bitmap = ed->arch.io_bitmap; - } + rc = -EPERM; + goto remove_dev; } - for ( i = 0; i < DEVICE_COUNT_RESOURCE; i++ ) - { - struct resource *r = &pdev->resource[i]; - - if ( r->flags & IORESOURCE_IO ) - { - /* Give the domain access to the IO ports it needs. Currently, - * this will allow all processes in that domain access to those - * ports as well. This will do for now, since driver domains don't - * run untrusted processes! */ - INFO("Giving domain %u IO resources (%lx - %lx) " - "for device %s\n", dom, r->start, r->end, pdev->slot_name); - for ( j = r->start; j < r->end + 1; j++ ) - { - clear_bit(j, ed->arch.io_bitmap); - clear_bit(j / IOBMP_BITS_PER_SELBIT, &ed->arch.io_bitmap_sel); - } - } + if ( (rc = setup_ioport_memory_access(dom, p, ed, pdev)) < 0 ) + goto remove_dev; - /* rights to IO memory regions are checked when the domain maps them */ - } + put_domain(p); + return rc; - for_each_exec_domain(p, edc) { - if (edc == ed) - continue; - edc->arch.io_bitmap_sel = ed->arch.io_bitmap_sel; +remove_dev: + if (oldacc == -1) { + /* new device was added - remove it from the list */ + remove_dev_from_task(p, pdev); + } else { + /* device already existed - just undo the access changes */ + physdev->flags = oldacc; } - - out: + +clear_priviledge: + clear_bit(DF_PHYSDEV, &p->d_flags); + clear_bit(DF_PRIVILEGED, &p->d_flags); put_domain(p); return rc; } @@ -279,7 +322,7 @@ inline static int check_dev_acc (struct if ( bus > PCI_BUSMAX || dev > PCI_DEVMAX || func > PCI_FUNCMAX ) return -EINVAL; - VERBOSE_INFO("b=%x d=%x f=%x ", bus, dev, func); + VERBOSE_INFO("mx b=%x d=%x f=%x ", bus, dev, func); /* check target device */ target_devfn = PCI_DEVFN(dev, func); @@ -553,7 +596,7 @@ static long pci_cfgreg_read(int bus, int default: ret = pci_config_read(0, bus, dev, func, reg, len, val); - VERBOSE_INFO("pci read : %02x:%02x:%02x reg=0x%02x len=0x%02x " + VERBOSE_INFO("xxx pci read : %02x:%02x:%02x reg=0x%02x len=0x%02x " "val=0x%08x\n", bus, dev, func, reg, len, *val); break; } @@ -708,7 +751,9 @@ long do_physdev_op(physdev_op_t *uop) break; } - copy_to_user(uop, &op, sizeof(op)); + if (copy_to_user(uop, &op, sizeof(op))) + ret = -EFAULT; + return ret; } @@ -764,7 +809,12 @@ void physdev_init_dom0(struct domain *p) if ( (dev->hdr_type != PCI_HEADER_TYPE_NORMAL) && (dev->hdr_type != PCI_HEADER_TYPE_CARDBUS) ) continue; - pdev = xmalloc(phys_dev_t); + + if ( (pdev = xmalloc(phys_dev_t)) == NULL ) { + INFO("failed to allocate physical device structure!\n"); + break; + } + pdev->dev = dev; pdev->flags = ACC_WRITE; pdev->state = 0;