|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH] VT-d: fix RMRR related error handling
> From: Jan Beulich
> Sent: Monday, October 06, 2014 8:44 AM
>
> - reassign_device_ownership() now tears down RMRR mappings (for other
> than Dom0)
> - to facilitate that, rmrr_identity_mapping() now deals with both
> establishing and tearing down of these mappings (the open coded
> equivalent in intel_iommu_remove_device() is being replaced at once)
> - intel_iommu_assign_device() now unrolls the assignment upon RMRR
> mapping errors
> - intel_iommu_add_device() now returns consistent values upon RMRR
> mapping failures (was: failure when last iteration ran into a
> problem, success otherwise)
> - intel_iommu_remove_device() no longer special cases Dom0 (it only
> ever gets called for devices removed from the _system_, not a domain)
> - rmrr_identity_mapping() now returns a proper error indicator instead
> of -1 when intel_iommu_map_page() failed
>
> Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
Acked-by: Kevin Tian <kevin.tian@xxxxxxxxx>
>
> --- a/xen/drivers/passthrough/vtd/iommu.c
> +++ b/xen/drivers/passthrough/vtd/iommu.c
> @@ -1661,38 +1661,6 @@ out:
> return ret;
> }
>
> -static int reassign_device_ownership(
> - struct domain *source,
> - struct domain *target,
> - u8 devfn, struct pci_dev *pdev)
> -{
> - int ret;
> -
> - /*
> - * Devices assigned to untrusted domains (here assumed to be any
> domU)
> - * can attempt to send arbitrary LAPIC/MSI messages. We are
> unprotected
> - * by the root complex unless interrupt remapping is enabled.
> - */
> - if ( (target != hardware_domain) && !iommu_intremap )
> - untrusted_msi = 1;
> -
> - ret = domain_context_unmap(source, devfn, pdev);
> - if ( ret )
> - return ret;
> -
> - ret = domain_context_mapping(target, devfn, pdev);
> - if ( ret )
> - return ret;
> -
> - if ( devfn == pdev->devfn )
> - {
> - list_move(&pdev->domain_list, &target->arch.pdev_list);
> - pdev->domain = target;
> - }
> -
> - return ret;
> -}
> -
> static void iommu_domain_teardown(struct domain *d)
> {
> struct hvm_iommu *hd = domain_hvm_iommu(d);
> @@ -1839,11 +1807,11 @@ static void iommu_set_pgd(struct domain
> hd->arch.pgd_maddr =
> pagetable_get_paddr(pagetable_from_mfn(pgd_mfn));
> }
>
> -static int rmrr_identity_mapping(struct domain *d,
> - struct acpi_rmrr_unit *rmrr)
> +static int rmrr_identity_mapping(struct domain *d, bool_t map,
> + const struct acpi_rmrr_unit *rmrr)
> {
> - u64 base, end;
> - unsigned long base_pfn, end_pfn;
> + unsigned long base_pfn = rmrr->base_address >> PAGE_SHIFT_4K;
> + unsigned long end_pfn = PAGE_ALIGN_4K(rmrr->end_address) >>
> PAGE_SHIFT_4K;
> struct mapped_rmrr *mrmrr;
> struct hvm_iommu *hd = domain_hvm_iommu(d);
>
> @@ -1859,21 +1827,40 @@ static int rmrr_identity_mapping(struct
> if ( mrmrr->base == rmrr->base_address &&
> mrmrr->end == rmrr->end_address )
> {
> - ++mrmrr->count;
> - return 0;
> + int ret = 0;
> +
> + if ( map )
> + {
> + ++mrmrr->count;
> + return 0;
> + }
> +
> + if ( --mrmrr->count )
> + return 0;
> +
> + while ( base_pfn < end_pfn )
> + {
> + if ( intel_iommu_unmap_page(d, base_pfn) )
> + ret = -ENXIO;
> + base_pfn++;
> + }
> +
> + list_del(&mrmrr->list);
> + xfree(mrmrr);
> + return ret;
> }
> }
>
> - base = rmrr->base_address & PAGE_MASK_4K;
> - base_pfn = base >> PAGE_SHIFT_4K;
> - end = PAGE_ALIGN_4K(rmrr->end_address);
> - end_pfn = end >> PAGE_SHIFT_4K;
> + if ( !map )
> + return -ENOENT;
>
> while ( base_pfn < end_pfn )
> {
> - if ( intel_iommu_map_page(d, base_pfn, base_pfn,
> -
> IOMMUF_readable|IOMMUF_writable) )
> - return -1;
> + int err = intel_iommu_map_page(d, base_pfn, base_pfn,
> +
> IOMMUF_readable|IOMMUF_writable);
> +
> + if ( err )
> + return err;
> base_pfn++;
> }
>
> @@ -1913,14 +1900,14 @@ static int intel_iommu_add_device(u8 dev
> PCI_BUS(bdf) == pdev->bus &&
> PCI_DEVFN2(bdf) == devfn )
> {
> - ret = rmrr_identity_mapping(pdev->domain, rmrr);
> + ret = rmrr_identity_mapping(pdev->domain, 1, rmrr);
> if ( ret )
> dprintk(XENLOG_ERR VTDPREFIX, "d%d: RMRR mapping
> failed\n",
> pdev->domain->domain_id);
> }
> }
>
> - return ret;
> + return 0;
> }
>
> static int intel_iommu_enable_device(struct pci_dev *pdev)
> @@ -1949,52 +1936,12 @@ static int intel_iommu_remove_device(u8
>
> for_each_rmrr_device ( rmrr, bdf, i )
> {
> - struct hvm_iommu *hd;
> - struct mapped_rmrr *mrmrr, *tmp;
> -
> if ( rmrr->segment != pdev->seg ||
> PCI_BUS(bdf) != pdev->bus ||
> PCI_DEVFN2(bdf) != devfn )
> continue;
>
> - /*
> - * If the device belongs to the hardware domain, and it has RMRR,
> don't
> - * remove it from the hardware domain, because BIOS may use
> RMRR at
> - * booting time.
> - */
> - if ( is_hardware_domain(pdev->domain) )
> - return 0;
> -
> - hd = domain_hvm_iommu(pdev->domain);
> -
> - /*
> - * No need to acquire hd->mapping_lock: Both insertion and
> removal
> - * get done while holding pcidevs_lock.
> - */
> - ASSERT(spin_is_locked(&pcidevs_lock));
> - list_for_each_entry_safe ( mrmrr, tmp, &hd->arch.mapped_rmrrs,
> list )
> - {
> - unsigned long base_pfn, end_pfn;
> -
> - if ( rmrr->base_address != mrmrr->base ||
> - rmrr->end_address != mrmrr->end )
> - continue;
> -
> - if ( --mrmrr->count )
> - break;
> -
> - base_pfn = (mrmrr->base & PAGE_MASK_4K) >>
> PAGE_SHIFT_4K;
> - end_pfn = PAGE_ALIGN_4K(mrmrr->end) >> PAGE_SHIFT_4K;
> - while ( base_pfn < end_pfn )
> - {
> - if ( intel_iommu_unmap_page(pdev->domain, base_pfn) )
> - return -ENXIO;
> - base_pfn++;
> - }
> -
> - list_del(&mrmrr->list);
> - xfree(mrmrr);
> - }
> + rmrr_identity_mapping(pdev->domain, 0, rmrr);
> }
>
> return domain_context_unmap(pdev->domain, devfn, pdev);
> @@ -2152,7 +2099,7 @@ static void __hwdom_init setup_hwdom_rmr
> spin_lock(&pcidevs_lock);
> for_each_rmrr_device ( rmrr, bdf, i )
> {
> - ret = rmrr_identity_mapping(d, rmrr);
> + ret = rmrr_identity_mapping(d, 1, rmrr);
> if ( ret )
> dprintk(XENLOG_ERR VTDPREFIX,
> "IOMMU: mapping reserved region failed\n");
> @@ -2262,6 +2209,62 @@ int __init intel_vtd_setup(void)
> return ret;
> }
>
> +static int reassign_device_ownership(
> + struct domain *source,
> + struct domain *target,
> + u8 devfn, struct pci_dev *pdev)
> +{
> + int ret;
> +
> + /*
> + * Devices assigned to untrusted domains (here assumed to be any
> domU)
> + * can attempt to send arbitrary LAPIC/MSI messages. We are
> unprotected
> + * by the root complex unless interrupt remapping is enabled.
> + */
> + if ( (target != hardware_domain) && !iommu_intremap )
> + untrusted_msi = 1;
> +
> + /*
> + * If the device belongs to the hardware domain, and it has RMRR, don't
> + * remove it from the hardware domain, because BIOS may use RMRR
> at
> + * booting time. Also account for the special casing of USB below (in
> + * intel_iommu_assign_device()).
> + */
> + if ( !is_hardware_domain(source) &&
> + !is_usb_device(pdev->seg, pdev->bus, pdev->devfn) )
> + {
> + const struct acpi_rmrr_unit *rmrr;
> + u16 bdf;
> + unsigned int i;
> +
> + for_each_rmrr_device( rmrr, bdf, i )
> + if ( rmrr->segment == pdev->seg &&
> + PCI_BUS(bdf) == pdev->bus &&
> + PCI_DEVFN2(bdf) == devfn )
> + {
> + ret = rmrr_identity_mapping(source, 0, rmrr);
> + if ( ret != -ENOENT )
> + return ret;
> + }
> + }
> +
> + ret = domain_context_unmap(source, devfn, pdev);
> + if ( ret )
> + return ret;
> +
> + ret = domain_context_mapping(target, devfn, pdev);
> + if ( ret )
> + return ret;
> +
> + if ( devfn == pdev->devfn )
> + {
> + list_move(&pdev->domain_list, &target->arch.pdev_list);
> + pdev->domain = target;
> + }
> +
> + return ret;
> +}
> +
> static int intel_iommu_assign_device(
> struct domain *d, u8 devfn, struct pci_dev *pdev)
> {
> @@ -2275,7 +2278,7 @@ static int intel_iommu_assign_device(
>
> ret = reassign_device_ownership(hardware_domain, d, devfn, pdev);
> if ( ret )
> - goto done;
> + return ret;
>
> /* FIXME: Because USB RMRR conflicts with guest bios region,
> * ignore USB RMRR temporarily.
> @@ -2283,10 +2286,7 @@ static int intel_iommu_assign_device(
> seg = pdev->seg;
> bus = pdev->bus;
> if ( is_usb_device(seg, bus, pdev->devfn) )
> - {
> - ret = 0;
> - goto done;
> - }
> + return 0;
>
> /* Setup rmrr identity mapping */
> for_each_rmrr_device( rmrr, bdf, i )
> @@ -2295,17 +2295,19 @@ static int intel_iommu_assign_device(
> PCI_BUS(bdf) == bus &&
> PCI_DEVFN2(bdf) == devfn )
> {
> - ret = rmrr_identity_mapping(d, rmrr);
> + ret = rmrr_identity_mapping(d, 1, rmrr);
> if ( ret )
> {
> - dprintk(XENLOG_ERR VTDPREFIX,
> - "IOMMU: mapping reserved region failed\n");
> - goto done;
> + reassign_device_ownership(d, hardware_domain, devfn,
> pdev);
> + printk(XENLOG_G_ERR VTDPREFIX
> + " cannot map reserved region
> (%"PRIx64",%"PRIx64"] for Dom%d (%d)\n",
> + rmrr->base_address, rmrr->end_address,
> + d->domain_id, ret);
> + break;
> }
> }
> }
>
> -done:
> return ret;
> }
>
>
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |