aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSuresh Siddha <suresh.b.siddha@intel.com>2008-09-25 21:43:34 -0400
committerIngo Molnar <mingo@elte.hu>2008-09-26 03:42:20 -0400
commit379daf6290814e41f14880094b7b773640df2461 (patch)
treee9b016fd4b8dcb0e4fbe39af75db84f313b6fd75
parent9a22b6e76ba75fa0f3963cdec7829156d00a7173 (diff)
IO resources, x86: ioremap sanity check to catch mapping requests exceeding the BAR sizes
Go through the iomem resource tree to check if any of the ioremap() requests span more than any slot in the iomem resource tree and do a WARN_ON() if we hit this check. This will raise a red-flag, if some driver is mapping more than what is needed. And hopefully identify possible corruptions much earlier. Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--arch/x86/mm/ioremap.c6
-rw-r--r--include/linux/ioport.h1
-rw-r--r--kernel/resource.c33
3 files changed, 40 insertions, 0 deletions
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
index d4b6e6a29ae3..c818b45bd07d 100644
--- a/arch/x86/mm/ioremap.c
+++ b/arch/x86/mm/ioremap.c
@@ -150,6 +150,12 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr,
150 return (__force void __iomem *)phys_to_virt(phys_addr); 150 return (__force void __iomem *)phys_to_virt(phys_addr);
151 151
152 /* 152 /*
153 * Check if the request spans more than any BAR in the iomem resource
154 * tree.
155 */
156 WARN_ON(iomem_map_sanity_check(phys_addr, size));
157
158 /*
153 * Don't allow anybody to remap normal RAM that we're using.. 159 * Don't allow anybody to remap normal RAM that we're using..
154 */ 160 */
155 for (pfn = phys_addr >> PAGE_SHIFT; 161 for (pfn = phys_addr >> PAGE_SHIFT;
diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index fded376b94e3..01712cf1a38b 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -169,6 +169,7 @@ extern struct resource * __devm_request_region(struct device *dev,
169 169
170extern void __devm_release_region(struct device *dev, struct resource *parent, 170extern void __devm_release_region(struct device *dev, struct resource *parent,
171 resource_size_t start, resource_size_t n); 171 resource_size_t start, resource_size_t n);
172extern int iomem_map_sanity_check(resource_size_t addr, unsigned long size);
172 173
173#endif /* __ASSEMBLY__ */ 174#endif /* __ASSEMBLY__ */
174#endif /* _LINUX_IOPORT_H */ 175#endif /* _LINUX_IOPORT_H */
diff --git a/kernel/resource.c b/kernel/resource.c
index fc59dcc4795b..1d003a50ee17 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -827,3 +827,36 @@ static int __init reserve_setup(char *str)
827} 827}
828 828
829__setup("reserve=", reserve_setup); 829__setup("reserve=", reserve_setup);
830
831/*
832 * Check if the requested addr and size spans more than any slot in the
833 * iomem resource tree.
834 */
835int iomem_map_sanity_check(resource_size_t addr, unsigned long size)
836{
837 struct resource *p = &iomem_resource;
838 int err = 0;
839 loff_t l;
840
841 read_lock(&resource_lock);
842 for (p = p->child; p ; p = r_next(NULL, p, &l)) {
843 /*
844 * We can probably skip the resources without
845 * IORESOURCE_IO attribute?
846 */
847 if (p->start >= addr + size)
848 continue;
849 if (p->end < addr)
850 continue;
851 if (p->start <= addr && (p->end >= addr + size - 1))
852 continue;
853 printk(KERN_WARNING "resource map sanity check conflict: "
854 "0x%llx 0x%llx 0x%llx 0x%llx %s\n",
855 addr, addr + size - 1, p->start, p->end, p->name);
856 err = -1;
857 break;
858 }
859 read_unlock(&resource_lock);
860
861 return err;
862}