aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-06-07 23:12:15 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-06-07 23:12:15 -0400
commita68a7509d3af8ee458d32b2416b0c2aaf2a4a7e3 (patch)
treea0e6a40ff4c384364d9eca02d490eab7dca21eee
parent639b4ac691c6f6e48921dc576379c176f82f3250 (diff)
parentfd49c81f080a997aad4b0e73541cd42772b6a772 (diff)
Merge tag 'vfio-v3.16-rc1' of git://github.com/awilliam/linux-vfio into next
Pull VFIO updates from Alex Williamson: "A handful of VFIO bug fixes for v3.16" * tag 'vfio-v3.16-rc1' of git://github.com/awilliam/linux-vfio: drivers/vfio/pci: Fix wrong MSI interrupt count drivers/vfio: Rework offsetofend() vfio/iommu_type1: Avoid overflow vfio/pci: Fix unchecked return value vfio/pci: Fix sizing of DPA and THP express capabilities
-rw-r--r--drivers/vfio/pci/vfio_pci.c6
-rw-r--r--drivers/vfio/pci/vfio_pci_config.c7
-rw-r--r--drivers/vfio/vfio_iommu_type1.c45
-rw-r--r--include/linux/vfio.h5
4 files changed, 26 insertions, 37 deletions
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
index 7ba042498857..010e0f8b8e4f 100644
--- a/drivers/vfio/pci/vfio_pci.c
+++ b/drivers/vfio/pci/vfio_pci.c
@@ -57,7 +57,8 @@ static int vfio_pci_enable(struct vfio_pci_device *vdev)
57 57
58 ret = vfio_config_init(vdev); 58 ret = vfio_config_init(vdev);
59 if (ret) { 59 if (ret) {
60 pci_load_and_free_saved_state(pdev, &vdev->pci_saved_state); 60 kfree(vdev->pci_saved_state);
61 vdev->pci_saved_state = NULL;
61 pci_disable_device(pdev); 62 pci_disable_device(pdev);
62 return ret; 63 return ret;
63 } 64 }
@@ -196,8 +197,7 @@ static int vfio_pci_get_irq_count(struct vfio_pci_device *vdev, int irq_type)
196 if (pos) { 197 if (pos) {
197 pci_read_config_word(vdev->pdev, 198 pci_read_config_word(vdev->pdev,
198 pos + PCI_MSI_FLAGS, &flags); 199 pos + PCI_MSI_FLAGS, &flags);
199 200 return 1 << ((flags & PCI_MSI_FLAGS_QMASK) >> 1);
200 return 1 << (flags & PCI_MSI_FLAGS_QMASK);
201 } 201 }
202 } else if (irq_type == VFIO_PCI_MSIX_IRQ_INDEX) { 202 } else if (irq_type == VFIO_PCI_MSIX_IRQ_INDEX) {
203 u8 pos; 203 u8 pos;
diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c
index 83cd1574c810..e50790e91f76 100644
--- a/drivers/vfio/pci/vfio_pci_config.c
+++ b/drivers/vfio/pci/vfio_pci_config.c
@@ -1126,8 +1126,7 @@ static int vfio_ext_cap_len(struct vfio_pci_device *vdev, u16 ecap, u16 epos)
1126 return pcibios_err_to_errno(ret); 1126 return pcibios_err_to_errno(ret);
1127 1127
1128 byte &= PCI_DPA_CAP_SUBSTATE_MASK; 1128 byte &= PCI_DPA_CAP_SUBSTATE_MASK;
1129 byte = round_up(byte + 1, 4); 1129 return PCI_DPA_BASE_SIZEOF + byte + 1;
1130 return PCI_DPA_BASE_SIZEOF + byte;
1131 case PCI_EXT_CAP_ID_TPH: 1130 case PCI_EXT_CAP_ID_TPH:
1132 ret = pci_read_config_dword(pdev, epos + PCI_TPH_CAP, &dword); 1131 ret = pci_read_config_dword(pdev, epos + PCI_TPH_CAP, &dword);
1133 if (ret) 1132 if (ret)
@@ -1136,9 +1135,9 @@ static int vfio_ext_cap_len(struct vfio_pci_device *vdev, u16 ecap, u16 epos)
1136 if ((dword & PCI_TPH_CAP_LOC_MASK) == PCI_TPH_LOC_CAP) { 1135 if ((dword & PCI_TPH_CAP_LOC_MASK) == PCI_TPH_LOC_CAP) {
1137 int sts; 1136 int sts;
1138 1137
1139 sts = byte & PCI_TPH_CAP_ST_MASK; 1138 sts = dword & PCI_TPH_CAP_ST_MASK;
1140 sts >>= PCI_TPH_CAP_ST_SHIFT; 1139 sts >>= PCI_TPH_CAP_ST_SHIFT;
1141 return PCI_TPH_BASE_SIZEOF + round_up(sts * 2, 4); 1140 return PCI_TPH_BASE_SIZEOF + (sts * 2) + 2;
1142 } 1141 }
1143 return PCI_TPH_BASE_SIZEOF; 1142 return PCI_TPH_BASE_SIZEOF;
1144 default: 1143 default:
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index 6673e7be507f..0734fbe5b651 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -524,7 +524,7 @@ unwind:
524static int vfio_dma_do_map(struct vfio_iommu *iommu, 524static int vfio_dma_do_map(struct vfio_iommu *iommu,
525 struct vfio_iommu_type1_dma_map *map) 525 struct vfio_iommu_type1_dma_map *map)
526{ 526{
527 dma_addr_t end, iova; 527 dma_addr_t iova = map->iova;
528 unsigned long vaddr = map->vaddr; 528 unsigned long vaddr = map->vaddr;
529 size_t size = map->size; 529 size_t size = map->size;
530 long npage; 530 long npage;
@@ -533,39 +533,30 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
533 struct vfio_dma *dma; 533 struct vfio_dma *dma;
534 unsigned long pfn; 534 unsigned long pfn;
535 535
536 end = map->iova + map->size; 536 /* Verify that none of our __u64 fields overflow */
537 if (map->size != size || map->vaddr != vaddr || map->iova != iova)
538 return -EINVAL;
537 539
538 mask = ((uint64_t)1 << __ffs(vfio_pgsize_bitmap(iommu))) - 1; 540 mask = ((uint64_t)1 << __ffs(vfio_pgsize_bitmap(iommu))) - 1;
539 541
542 WARN_ON(mask & PAGE_MASK);
543
540 /* READ/WRITE from device perspective */ 544 /* READ/WRITE from device perspective */
541 if (map->flags & VFIO_DMA_MAP_FLAG_WRITE) 545 if (map->flags & VFIO_DMA_MAP_FLAG_WRITE)
542 prot |= IOMMU_WRITE; 546 prot |= IOMMU_WRITE;
543 if (map->flags & VFIO_DMA_MAP_FLAG_READ) 547 if (map->flags & VFIO_DMA_MAP_FLAG_READ)
544 prot |= IOMMU_READ; 548 prot |= IOMMU_READ;
545 549
546 if (!prot) 550 if (!prot || !size || (size | iova | vaddr) & mask)
547 return -EINVAL; /* No READ/WRITE? */
548
549 if (vaddr & mask)
550 return -EINVAL;
551 if (map->iova & mask)
552 return -EINVAL;
553 if (!map->size || map->size & mask)
554 return -EINVAL;
555
556 WARN_ON(mask & PAGE_MASK);
557
558 /* Don't allow IOVA wrap */
559 if (end && end < map->iova)
560 return -EINVAL; 551 return -EINVAL;
561 552
562 /* Don't allow virtual address wrap */ 553 /* Don't allow IOVA or virtual address wrap */
563 if (vaddr + map->size && vaddr + map->size < vaddr) 554 if (iova + size - 1 < iova || vaddr + size - 1 < vaddr)
564 return -EINVAL; 555 return -EINVAL;
565 556
566 mutex_lock(&iommu->lock); 557 mutex_lock(&iommu->lock);
567 558
568 if (vfio_find_dma(iommu, map->iova, map->size)) { 559 if (vfio_find_dma(iommu, iova, size)) {
569 mutex_unlock(&iommu->lock); 560 mutex_unlock(&iommu->lock);
570 return -EEXIST; 561 return -EEXIST;
571 } 562 }
@@ -576,17 +567,17 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
576 return -ENOMEM; 567 return -ENOMEM;
577 } 568 }
578 569
579 dma->iova = map->iova; 570 dma->iova = iova;
580 dma->vaddr = map->vaddr; 571 dma->vaddr = vaddr;
581 dma->prot = prot; 572 dma->prot = prot;
582 573
583 /* Insert zero-sized and grow as we map chunks of it */ 574 /* Insert zero-sized and grow as we map chunks of it */
584 vfio_link_dma(iommu, dma); 575 vfio_link_dma(iommu, dma);
585 576
586 for (iova = map->iova; iova < end; iova += size, vaddr += size) { 577 while (size) {
587 /* Pin a contiguous chunk of memory */ 578 /* Pin a contiguous chunk of memory */
588 npage = vfio_pin_pages(vaddr, (end - iova) >> PAGE_SHIFT, 579 npage = vfio_pin_pages(vaddr + dma->size,
589 prot, &pfn); 580 size >> PAGE_SHIFT, prot, &pfn);
590 if (npage <= 0) { 581 if (npage <= 0) {
591 WARN_ON(!npage); 582 WARN_ON(!npage);
592 ret = (int)npage; 583 ret = (int)npage;
@@ -594,14 +585,14 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
594 } 585 }
595 586
596 /* Map it! */ 587 /* Map it! */
597 ret = vfio_iommu_map(iommu, iova, pfn, npage, prot); 588 ret = vfio_iommu_map(iommu, iova + dma->size, pfn, npage, prot);
598 if (ret) { 589 if (ret) {
599 vfio_unpin_pages(pfn, npage, prot, true); 590 vfio_unpin_pages(pfn, npage, prot, true);
600 break; 591 break;
601 } 592 }
602 593
603 size = npage << PAGE_SHIFT; 594 size -= npage << PAGE_SHIFT;
604 dma->size += size; 595 dma->size += npage << PAGE_SHIFT;
605 } 596 }
606 597
607 if (ret) 598 if (ret)
diff --git a/include/linux/vfio.h b/include/linux/vfio.h
index 81022a52bc34..8ec980b5e3af 100644
--- a/include/linux/vfio.h
+++ b/include/linux/vfio.h
@@ -86,9 +86,8 @@ extern void vfio_unregister_iommu_driver(
86 * from user space. This allows us to easily determine if the provided 86 * from user space. This allows us to easily determine if the provided
87 * structure is sized to include various fields. 87 * structure is sized to include various fields.
88 */ 88 */
89#define offsetofend(TYPE, MEMBER) ({ \ 89#define offsetofend(TYPE, MEMBER) \
90 TYPE tmp; \ 90 (offsetof(TYPE, MEMBER) + sizeof(((TYPE *)0)->MEMBER))
91 offsetof(TYPE, MEMBER) + sizeof(tmp.MEMBER); }) \
92 91
93/* 92/*
94 * External user API 93 * External user API