aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArjan van de Ven <arjan@linux.intel.com>2008-10-22 22:55:31 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2009-01-07 14:12:32 -0500
commite8de1481fd7126ee9e93d6889da6f00c05e1e019 (patch)
tree3e0e564f6aff2f8f0f66bdf37dc2eb87d6e17cde
parent23616941914917cf25b94789856b5326b68d8ee8 (diff)
resource: allow MMIO exclusivity for device drivers
Device drivers that use pci_request_regions() (and similar APIs) have a reasonable expectation that they are the only ones accessing their device. As part of the e1000e hunt, we were afraid that some userland (X or some bootsplash stuff) was mapping the MMIO region that the driver thought it had exclusively via /dev/mem or via various sysfs resource mappings. This patch adds the option for device drivers to cause their reserved regions to the "banned from /dev/mem use" list, so now both kernel memory and device-exclusive MMIO regions are banned. NOTE: This is only active when CONFIG_STRICT_DEVMEM is set. In addition to the config option, a kernel parameter iomem=relaxed is provided for the cases where developers want to diagnose, in the field, drivers issues from userspace. Reviewed-by: Matthew Wilcox <willy@linux.intel.com> Signed-off-by: Arjan van de Ven <arjan@linux.intel.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
-rw-r--r--Documentation/kernel-parameters.txt4
-rw-r--r--arch/x86/mm/init_32.c2
-rw-r--r--arch/x86/mm/init_64.c2
-rw-r--r--drivers/net/e1000e/netdev.c2
-rw-r--r--drivers/pci/pci-sysfs.c3
-rw-r--r--drivers/pci/pci.c107
-rw-r--r--include/linux/ioport.h11
-rw-r--r--include/linux/pci.h3
-rw-r--r--kernel/resource.c61
9 files changed, 176 insertions, 19 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 0b3f6711d2f1..0072fabb1dd1 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -918,6 +918,10 @@ and is between 256 and 4096 characters. It is defined in the file
918 918
919 inttest= [IA64] 919 inttest= [IA64]
920 920
921 iomem= Disable strict checking of access to MMIO memory
922 strict regions from userspace.
923 relaxed
924
921 iommu= [x86] 925 iommu= [x86]
922 off 926 off
923 force 927 force
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c
index 544d724caeee..88f1b10de3be 100644
--- a/arch/x86/mm/init_32.c
+++ b/arch/x86/mm/init_32.c
@@ -328,6 +328,8 @@ int devmem_is_allowed(unsigned long pagenr)
328{ 328{
329 if (pagenr <= 256) 329 if (pagenr <= 256)
330 return 1; 330 return 1;
331 if (iomem_is_exclusive(pagenr << PAGE_SHIFT))
332 return 0;
331 if (!page_is_ram(pagenr)) 333 if (!page_is_ram(pagenr))
332 return 1; 334 return 1;
333 return 0; 335 return 0;
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index 54c437e96541..23f68e77ad1f 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -888,6 +888,8 @@ int devmem_is_allowed(unsigned long pagenr)
888{ 888{
889 if (pagenr <= 256) 889 if (pagenr <= 256)
890 return 1; 890 return 1;
891 if (iomem_is_exclusive(pagenr << PAGE_SHIFT))
892 return 0;
891 if (!page_is_ram(pagenr)) 893 if (!page_is_ram(pagenr))
892 return 1; 894 return 1;
893 return 0; 895 return 0;
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index d4639facd1bd..91817d0afcaf 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -4807,7 +4807,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
4807 } 4807 }
4808 } 4808 }
4809 4809
4810 err = pci_request_selected_regions(pdev, 4810 err = pci_request_selected_regions_exclusive(pdev,
4811 pci_select_bars(pdev, IORESOURCE_MEM), 4811 pci_select_bars(pdev, IORESOURCE_MEM),
4812 e1000e_driver_name); 4812 e1000e_driver_name);
4813 if (err) 4813 if (err)
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 388440e0d222..d5cdccf27a69 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -620,6 +620,9 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
620 vma->vm_pgoff += start >> PAGE_SHIFT; 620 vma->vm_pgoff += start >> PAGE_SHIFT;
621 mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io; 621 mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io;
622 622
623 if (res->flags & IORESOURCE_MEM && iomem_is_exclusive(start))
624 return -EINVAL;
625
623 return pci_mmap_page_range(pdev, vma, mmap_type, write_combine); 626 return pci_mmap_page_range(pdev, vma, mmap_type, write_combine);
624} 627}
625 628
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 2cfa41e367a7..47663dc0daf7 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1395,7 +1395,8 @@ void pci_release_region(struct pci_dev *pdev, int bar)
1395 * Returns 0 on success, or %EBUSY on error. A warning 1395 * Returns 0 on success, or %EBUSY on error. A warning
1396 * message is also printed on failure. 1396 * message is also printed on failure.
1397 */ 1397 */
1398int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name) 1398static int __pci_request_region(struct pci_dev *pdev, int bar, const char *res_name,
1399 int exclusive)
1399{ 1400{
1400 struct pci_devres *dr; 1401 struct pci_devres *dr;
1401 1402
@@ -1408,8 +1409,9 @@ int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name)
1408 goto err_out; 1409 goto err_out;
1409 } 1410 }
1410 else if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) { 1411 else if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) {
1411 if (!request_mem_region(pci_resource_start(pdev, bar), 1412 if (!__request_mem_region(pci_resource_start(pdev, bar),
1412 pci_resource_len(pdev, bar), res_name)) 1413 pci_resource_len(pdev, bar), res_name,
1414 exclusive))
1413 goto err_out; 1415 goto err_out;
1414 } 1416 }
1415 1417
@@ -1428,6 +1430,47 @@ err_out:
1428} 1430}
1429 1431
1430/** 1432/**
1433 * pci_request_region - Reserved PCI I/O and memory resource
1434 * @pdev: PCI device whose resources are to be reserved
1435 * @bar: BAR to be reserved
1436 * @res_name: Name to be associated with resource.
1437 *
1438 * Mark the PCI region associated with PCI device @pdev BR @bar as
1439 * being reserved by owner @res_name. Do not access any
1440 * address inside the PCI regions unless this call returns
1441 * successfully.
1442 *
1443 * Returns 0 on success, or %EBUSY on error. A warning
1444 * message is also printed on failure.
1445 */
1446int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name)
1447{
1448 return __pci_request_region(pdev, bar, res_name, 0);
1449}
1450
1451/**
1452 * pci_request_region_exclusive - Reserved PCI I/O and memory resource
1453 * @pdev: PCI device whose resources are to be reserved
1454 * @bar: BAR to be reserved
1455 * @res_name: Name to be associated with resource.
1456 *
1457 * Mark the PCI region associated with PCI device @pdev BR @bar as
1458 * being reserved by owner @res_name. Do not access any
1459 * address inside the PCI regions unless this call returns
1460 * successfully.
1461 *
1462 * Returns 0 on success, or %EBUSY on error. A warning
1463 * message is also printed on failure.
1464 *
1465 * The key difference that _exclusive makes it that userspace is
1466 * explicitly not allowed to map the resource via /dev/mem or
1467 * sysfs.
1468 */
1469int pci_request_region_exclusive(struct pci_dev *pdev, int bar, const char *res_name)
1470{
1471 return __pci_request_region(pdev, bar, res_name, IORESOURCE_EXCLUSIVE);
1472}
1473/**
1431 * pci_release_selected_regions - Release selected PCI I/O and memory resources 1474 * pci_release_selected_regions - Release selected PCI I/O and memory resources
1432 * @pdev: PCI device whose resources were previously reserved 1475 * @pdev: PCI device whose resources were previously reserved
1433 * @bars: Bitmask of BARs to be released 1476 * @bars: Bitmask of BARs to be released
@@ -1444,20 +1487,14 @@ void pci_release_selected_regions(struct pci_dev *pdev, int bars)
1444 pci_release_region(pdev, i); 1487 pci_release_region(pdev, i);
1445} 1488}
1446 1489
1447/** 1490int __pci_request_selected_regions(struct pci_dev *pdev, int bars,
1448 * pci_request_selected_regions - Reserve selected PCI I/O and memory resources 1491 const char *res_name, int excl)
1449 * @pdev: PCI device whose resources are to be reserved
1450 * @bars: Bitmask of BARs to be requested
1451 * @res_name: Name to be associated with resource
1452 */
1453int pci_request_selected_regions(struct pci_dev *pdev, int bars,
1454 const char *res_name)
1455{ 1492{
1456 int i; 1493 int i;
1457 1494
1458 for (i = 0; i < 6; i++) 1495 for (i = 0; i < 6; i++)
1459 if (bars & (1 << i)) 1496 if (bars & (1 << i))
1460 if(pci_request_region(pdev, i, res_name)) 1497 if (__pci_request_region(pdev, i, res_name, excl))
1461 goto err_out; 1498 goto err_out;
1462 return 0; 1499 return 0;
1463 1500
@@ -1469,6 +1506,26 @@ err_out:
1469 return -EBUSY; 1506 return -EBUSY;
1470} 1507}
1471 1508
1509
1510/**
1511 * pci_request_selected_regions - Reserve selected PCI I/O and memory resources
1512 * @pdev: PCI device whose resources are to be reserved
1513 * @bars: Bitmask of BARs to be requested
1514 * @res_name: Name to be associated with resource
1515 */
1516int pci_request_selected_regions(struct pci_dev *pdev, int bars,
1517 const char *res_name)
1518{
1519 return __pci_request_selected_regions(pdev, bars, res_name, 0);
1520}
1521
1522int pci_request_selected_regions_exclusive(struct pci_dev *pdev,
1523 int bars, const char *res_name)
1524{
1525 return __pci_request_selected_regions(pdev, bars, res_name,
1526 IORESOURCE_EXCLUSIVE);
1527}
1528
1472/** 1529/**
1473 * pci_release_regions - Release reserved PCI I/O and memory resources 1530 * pci_release_regions - Release reserved PCI I/O and memory resources
1474 * @pdev: PCI device whose resources were previously reserved by pci_request_regions 1531 * @pdev: PCI device whose resources were previously reserved by pci_request_regions
@@ -1502,6 +1559,29 @@ int pci_request_regions(struct pci_dev *pdev, const char *res_name)
1502} 1559}
1503 1560
1504/** 1561/**
1562 * pci_request_regions_exclusive - Reserved PCI I/O and memory resources
1563 * @pdev: PCI device whose resources are to be reserved
1564 * @res_name: Name to be associated with resource.
1565 *
1566 * Mark all PCI regions associated with PCI device @pdev as
1567 * being reserved by owner @res_name. Do not access any
1568 * address inside the PCI regions unless this call returns
1569 * successfully.
1570 *
1571 * pci_request_regions_exclusive() will mark the region so that
1572 * /dev/mem and the sysfs MMIO access will not be allowed.
1573 *
1574 * Returns 0 on success, or %EBUSY on error. A warning
1575 * message is also printed on failure.
1576 */
1577int pci_request_regions_exclusive(struct pci_dev *pdev, const char *res_name)
1578{
1579 return pci_request_selected_regions_exclusive(pdev,
1580 ((1 << 6) - 1), res_name);
1581}
1582
1583
1584/**
1505 * pci_set_master - enables bus-mastering for device dev 1585 * pci_set_master - enables bus-mastering for device dev
1506 * @dev: the PCI device to enable 1586 * @dev: the PCI device to enable
1507 * 1587 *
@@ -2149,10 +2229,13 @@ EXPORT_SYMBOL(pci_find_capability);
2149EXPORT_SYMBOL(pci_bus_find_capability); 2229EXPORT_SYMBOL(pci_bus_find_capability);
2150EXPORT_SYMBOL(pci_release_regions); 2230EXPORT_SYMBOL(pci_release_regions);
2151EXPORT_SYMBOL(pci_request_regions); 2231EXPORT_SYMBOL(pci_request_regions);
2232EXPORT_SYMBOL(pci_request_regions_exclusive);
2152EXPORT_SYMBOL(pci_release_region); 2233EXPORT_SYMBOL(pci_release_region);
2153EXPORT_SYMBOL(pci_request_region); 2234EXPORT_SYMBOL(pci_request_region);
2235EXPORT_SYMBOL(pci_request_region_exclusive);
2154EXPORT_SYMBOL(pci_release_selected_regions); 2236EXPORT_SYMBOL(pci_release_selected_regions);
2155EXPORT_SYMBOL(pci_request_selected_regions); 2237EXPORT_SYMBOL(pci_request_selected_regions);
2238EXPORT_SYMBOL(pci_request_selected_regions_exclusive);
2156EXPORT_SYMBOL(pci_set_master); 2239EXPORT_SYMBOL(pci_set_master);
2157EXPORT_SYMBOL(pci_set_mwi); 2240EXPORT_SYMBOL(pci_set_mwi);
2158EXPORT_SYMBOL(pci_try_set_mwi); 2241EXPORT_SYMBOL(pci_try_set_mwi);
diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index 041e95aac2bf..f6bb2ca8e3ba 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -49,6 +49,7 @@ struct resource_list {
49#define IORESOURCE_SIZEALIGN 0x00020000 /* size indicates alignment */ 49#define IORESOURCE_SIZEALIGN 0x00020000 /* size indicates alignment */
50#define IORESOURCE_STARTALIGN 0x00040000 /* start field is alignment */ 50#define IORESOURCE_STARTALIGN 0x00040000 /* start field is alignment */
51 51
52#define IORESOURCE_EXCLUSIVE 0x08000000 /* Userland may not map this resource */
52#define IORESOURCE_DISABLED 0x10000000 53#define IORESOURCE_DISABLED 0x10000000
53#define IORESOURCE_UNSET 0x20000000 54#define IORESOURCE_UNSET 0x20000000
54#define IORESOURCE_AUTO 0x40000000 55#define IORESOURCE_AUTO 0x40000000
@@ -133,13 +134,16 @@ static inline unsigned long resource_type(struct resource *res)
133} 134}
134 135
135/* Convenience shorthand with allocation */ 136/* Convenience shorthand with allocation */
136#define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name)) 137#define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name), 0)
137#define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name)) 138#define __request_mem_region(start,n,name, excl) __request_region(&iomem_resource, (start), (n), (name), excl)
139#define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name), 0)
140#define request_mem_region_exclusive(start,n,name) \
141 __request_region(&iomem_resource, (start), (n), (name), IORESOURCE_EXCLUSIVE)
138#define rename_region(region, newname) do { (region)->name = (newname); } while (0) 142#define rename_region(region, newname) do { (region)->name = (newname); } while (0)
139 143
140extern struct resource * __request_region(struct resource *, 144extern struct resource * __request_region(struct resource *,
141 resource_size_t start, 145 resource_size_t start,
142 resource_size_t n, const char *name); 146 resource_size_t n, const char *name, int relaxed);
143 147
144/* Compatibility cruft */ 148/* Compatibility cruft */
145#define release_region(start,n) __release_region(&ioport_resource, (start), (n)) 149#define release_region(start,n) __release_region(&ioport_resource, (start), (n))
@@ -175,6 +179,7 @@ extern struct resource * __devm_request_region(struct device *dev,
175extern void __devm_release_region(struct device *dev, struct resource *parent, 179extern void __devm_release_region(struct device *dev, struct resource *parent,
176 resource_size_t start, resource_size_t n); 180 resource_size_t start, resource_size_t n);
177extern int iomem_map_sanity_check(resource_size_t addr, unsigned long size); 181extern int iomem_map_sanity_check(resource_size_t addr, unsigned long size);
182extern int iomem_is_exclusive(u64 addr);
178 183
179#endif /* __ASSEMBLY__ */ 184#endif /* __ASSEMBLY__ */
180#endif /* _LINUX_IOPORT_H */ 185#endif /* _LINUX_IOPORT_H */
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 59a3dc2059d3..bfcb39ca8879 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -686,10 +686,13 @@ void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *),
686 int (*)(struct pci_dev *, u8, u8)); 686 int (*)(struct pci_dev *, u8, u8));
687#define HAVE_PCI_REQ_REGIONS 2 687#define HAVE_PCI_REQ_REGIONS 2
688int __must_check pci_request_regions(struct pci_dev *, const char *); 688int __must_check pci_request_regions(struct pci_dev *, const char *);
689int __must_check pci_request_regions_exclusive(struct pci_dev *, const char *);
689void pci_release_regions(struct pci_dev *); 690void pci_release_regions(struct pci_dev *);
690int __must_check pci_request_region(struct pci_dev *, int, const char *); 691int __must_check pci_request_region(struct pci_dev *, int, const char *);
692int __must_check pci_request_region_exclusive(struct pci_dev *, int, const char *);
691void pci_release_region(struct pci_dev *, int); 693void pci_release_region(struct pci_dev *, int);
692int pci_request_selected_regions(struct pci_dev *, int, const char *); 694int pci_request_selected_regions(struct pci_dev *, int, const char *);
695int pci_request_selected_regions_exclusive(struct pci_dev *, int, const char *);
693void pci_release_selected_regions(struct pci_dev *, int); 696void pci_release_selected_regions(struct pci_dev *, int);
694 697
695/* drivers/pci/bus.c */ 698/* drivers/pci/bus.c */
diff --git a/kernel/resource.c b/kernel/resource.c
index e633106b12f6..ca6a1536b205 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -623,7 +623,7 @@ resource_size_t resource_alignment(struct resource *res)
623 */ 623 */
624struct resource * __request_region(struct resource *parent, 624struct resource * __request_region(struct resource *parent,
625 resource_size_t start, resource_size_t n, 625 resource_size_t start, resource_size_t n,
626 const char *name) 626 const char *name, int flags)
627{ 627{
628 struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL); 628 struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);
629 629
@@ -634,6 +634,7 @@ struct resource * __request_region(struct resource *parent,
634 res->start = start; 634 res->start = start;
635 res->end = start + n - 1; 635 res->end = start + n - 1;
636 res->flags = IORESOURCE_BUSY; 636 res->flags = IORESOURCE_BUSY;
637 res->flags |= flags;
637 638
638 write_lock(&resource_lock); 639 write_lock(&resource_lock);
639 640
@@ -679,7 +680,7 @@ int __check_region(struct resource *parent, resource_size_t start,
679{ 680{
680 struct resource * res; 681 struct resource * res;
681 682
682 res = __request_region(parent, start, n, "check-region"); 683 res = __request_region(parent, start, n, "check-region", 0);
683 if (!res) 684 if (!res)
684 return -EBUSY; 685 return -EBUSY;
685 686
@@ -776,7 +777,7 @@ struct resource * __devm_request_region(struct device *dev,
776 dr->start = start; 777 dr->start = start;
777 dr->n = n; 778 dr->n = n;
778 779
779 res = __request_region(parent, start, n, name); 780 res = __request_region(parent, start, n, name, 0);
780 if (res) 781 if (res)
781 devres_add(dev, dr); 782 devres_add(dev, dr);
782 else 783 else
@@ -876,3 +877,57 @@ int iomem_map_sanity_check(resource_size_t addr, unsigned long size)
876 877
877 return err; 878 return err;
878} 879}
880
881#ifdef CONFIG_STRICT_DEVMEM
882static int strict_iomem_checks = 1;
883#else
884static int strict_iomem_checks;
885#endif
886
887/*
888 * check if an address is reserved in the iomem resource tree
889 * returns 1 if reserved, 0 if not reserved.
890 */
891int iomem_is_exclusive(u64 addr)
892{
893 struct resource *p = &iomem_resource;
894 int err = 0;
895 loff_t l;
896 int size = PAGE_SIZE;
897
898 if (!strict_iomem_checks)
899 return 0;
900
901 addr = addr & PAGE_MASK;
902
903 read_lock(&resource_lock);
904 for (p = p->child; p ; p = r_next(NULL, p, &l)) {
905 /*
906 * We can probably skip the resources without
907 * IORESOURCE_IO attribute?
908 */
909 if (p->start >= addr + size)
910 break;
911 if (p->end < addr)
912 continue;
913 if (p->flags & IORESOURCE_BUSY &&
914 p->flags & IORESOURCE_EXCLUSIVE) {
915 err = 1;
916 break;
917 }
918 }
919 read_unlock(&resource_lock);
920
921 return err;
922}
923
924static int __init strict_iomem(char *str)
925{
926 if (strstr(str, "relaxed"))
927 strict_iomem_checks = 0;
928 if (strstr(str, "strict"))
929 strict_iomem_checks = 1;
930 return 1;
931}
932
933__setup("iomem=", strict_iomem);