]> git.hungrycats.org Git - linux/commitdiff
Add sparse "__iomem" infrastructure to check PCI address usage
authorLinus Torvalds <torvalds@evo.osdl.org>
Fri, 10 Sep 2004 12:01:36 +0000 (05:01 -0700)
committerLinus Torvalds <torvalds@evo.osdl.org>
Fri, 10 Sep 2004 12:01:36 +0000 (05:01 -0700)
There's tons of mis-use of PCI memory-mapped IO that is used
as if it was regular memory. That fails disastrously on a number
of architectures, and it doesn't help that it just happens to
work on regular x86 boxes.

This makes makes us do much stricter type-checking. Some of it
visible to the regular compiler, but the bulk of it is for sparse.

arch/i386/mm/ioremap.c
include/asm-i386/io.h
include/linux/compiler.h

index 7b11be02843b4ea675bce96d17e75fc998706624..aee0bb1f495d6380ba4a1b498c34aa01882a0686 100644 (file)
@@ -110,9 +110,9 @@ static int remap_area_pages(unsigned long address, unsigned long phys_addr,
  * have to convert them into an offset in a page-aligned mapping, but the
  * caller shouldn't need to know that small detail.
  */
-void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
+void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
 {
-       void * addr;
+       void __iomem * addr;
        struct vm_struct * area;
        unsigned long offset, last_addr;
 
@@ -125,7 +125,7 @@ void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flag
         * Don't remap the low PCI/ISA area, it's always mapped..
         */
        if (phys_addr >= 0xA0000 && last_addr < 0x100000)
-               return phys_to_virt(phys_addr);
+               return (void __iomem *) phys_to_virt(phys_addr);
 
        /*
         * Don't allow anybody to remap normal RAM that we're using..
@@ -156,12 +156,12 @@ void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flag
        if (!area)
                return NULL;
        area->phys_addr = phys_addr;
-       addr = area->addr;
+       addr = (void __iomem *) area->addr;
        if (remap_area_pages((unsigned long) addr, phys_addr, size, flags)) {
-               vunmap(addr);
+               vunmap((void __force *) addr);
                return NULL;
        }
-       return (void *) (offset + (char *)addr);
+       return (void __iomem *) (offset + (char __iomem *)addr);
 }
 
 
@@ -187,10 +187,10 @@ void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flag
  * Must be freed with iounmap.
  */
 
-void *ioremap_nocache (unsigned long phys_addr, unsigned long size)
+void __iomem *ioremap_nocache (unsigned long phys_addr, unsigned long size)
 {
        unsigned long last_addr;
-       void *p = __ioremap(phys_addr, size, _PAGE_PCD);
+       void __iomem *p = __ioremap(phys_addr, size, _PAGE_PCD);
        if (!p) 
                return p; 
 
@@ -221,12 +221,12 @@ void *ioremap_nocache (unsigned long phys_addr, unsigned long size)
        return p;                                       
 }
 
-void iounmap(void *addr)
+void iounmap(volatile void __iomem *addr)
 {
        struct vm_struct *p;
-       if (addr <= high_memory) 
+       if ((void __force *) addr <= high_memory) 
                return; 
-       p = remove_vm_area((void *) (PAGE_MASK & (unsigned long) addr));
+       p = remove_vm_area((void *) (PAGE_MASK & (unsigned long __force) addr));
        if (!p) { 
                printk("__iounmap: bad address %p\n", addr);
                return;
index 1d9fa560d6b60d03284d84c9ac139b44c81357e4..b659a98cba1da964c1de2327fd71ad9f49ff8825 100644 (file)
@@ -2,6 +2,8 @@
 #define _ASM_IO_H
 
 #include <linux/config.h>
+#include <linux/string.h>
+#include <linux/compiler.h>
 
 /*
  * This file contains the definitions for the x86 IO instructions
@@ -86,7 +88,7 @@ static inline void * phys_to_virt(unsigned long address)
  */
 #define page_to_phys(page)    ((dma_addr_t)page_to_pfn(page) << PAGE_SHIFT)
 
-extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
+extern void __iomem * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
 
 /**
  * ioremap     -   map bus memory into CPU space
@@ -100,13 +102,13 @@ extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long
  * address. 
  */
 
-static inline void * ioremap (unsigned long offset, unsigned long size)
+static inline void __iomem * ioremap(unsigned long offset, unsigned long size)
 {
        return __ioremap(offset, size, 0);
 }
 
-extern void * ioremap_nocache (unsigned long offset, unsigned long size);
-extern void iounmap(void *addr);
+extern void __iomem * ioremap_nocache(unsigned long offset, unsigned long size);
+extern void iounmap(volatile void __iomem *addr);
 
 /*
  * bt_ioremap() and bt_iounmap() are for temporary early boot-time
@@ -139,9 +141,18 @@ extern void bt_iounmap(void *addr, unsigned long size);
  * memory location directly.
  */
 
-#define readb(addr) (*(volatile unsigned char *) (addr))
-#define readw(addr) (*(volatile unsigned short *) (addr))
-#define readl(addr) (*(volatile unsigned int *) (addr))
+static inline unsigned char readb(const volatile void __iomem *addr)
+{
+       return *(volatile unsigned char __force *) addr;
+}
+static inline unsigned short readw(const volatile void __iomem *addr)
+{
+       return *(volatile unsigned short __force *) addr;
+}
+static inline unsigned int readl(const volatile void __iomem *addr)
+{
+       return *(volatile unsigned int __force *) addr;
+}
 #define readb_relaxed(addr) readb(addr)
 #define readw_relaxed(addr) readw(addr)
 #define readl_relaxed(addr) readl(addr)
@@ -149,16 +160,34 @@ extern void bt_iounmap(void *addr, unsigned long size);
 #define __raw_readw readw
 #define __raw_readl readl
 
-#define writeb(b,addr) (*(volatile unsigned char *) (addr) = (b))
-#define writew(b,addr) (*(volatile unsigned short *) (addr) = (b))
-#define writel(b,addr) (*(volatile unsigned int *) (addr) = (b))
+static inline void writeb(unsigned char b, volatile void __iomem *addr)
+{
+       *(volatile unsigned char __force *) addr = b;
+}
+static inline void writew(unsigned short b, volatile void __iomem *addr)
+{
+       *(volatile unsigned short __force *) addr = b;
+}
+static inline void writel(unsigned int b, volatile void __iomem *addr)
+{
+       *(volatile unsigned int __force *) addr = b;
+}
 #define __raw_writeb writeb
 #define __raw_writew writew
 #define __raw_writel writel
 
-#define memset_io(a,b,c)       memset((void *)(a),(b),(c))
-#define memcpy_fromio(a,b,c)   __memcpy((a),(void *)(b),(c))
-#define memcpy_toio(a,b,c)     __memcpy((void *)(a),(b),(c))
+static inline void memset_io(volatile void __iomem *addr, unsigned char val, int count)
+{
+       memset((void __force *) addr, val, count);
+}
+static inline void memcpy_fromio(void *dst, volatile void __iomem *src, int count)
+{
+       __memcpy(dst, (void __force *) src, count);
+}
+static inline void memcpy_toio(volatile void __iomem *dst, void *src, int count)
+{
+       __memcpy((void __force *) dst, src, count);
+}
 
 /*
  * ISA space is 'always mapped' on a typical x86 system, no need to
@@ -168,7 +197,7 @@ extern void bt_iounmap(void *addr, unsigned long size);
  * used as the IO-area pointer (it can be iounmapped as well, so the
  * analogy with PCI is quite large):
  */
-#define __ISA_IO_base ((char *)(PAGE_OFFSET))
+#define __ISA_IO_base ((char __iomem *)(PAGE_OFFSET))
 
 #define isa_readb(a) readb(__ISA_IO_base + (a))
 #define isa_readw(a) readw(__ISA_IO_base + (a))
@@ -185,8 +214,8 @@ extern void bt_iounmap(void *addr, unsigned long size);
  * Again, i386 does not require mem IO specific function.
  */
 
-#define eth_io_copy_and_sum(a,b,c,d)           eth_copy_and_sum((a),(void *)(b),(c),(d))
-#define isa_eth_io_copy_and_sum(a,b,c,d)       eth_copy_and_sum((a),(void *)(__ISA_IO_base + (b)),(c),(d))
+#define eth_io_copy_and_sum(a,b,c,d)           eth_copy_and_sum((a),(void __force *)(b),(c),(d))
+#define isa_eth_io_copy_and_sum(a,b,c,d)       eth_copy_and_sum((a),(void __force *)(__ISA_IO_base + (b)),(c),(d))
 
 /**
  *     check_signature         -       find BIOS signatures
@@ -199,7 +228,7 @@ extern void bt_iounmap(void *addr, unsigned long size);
  *     Returns 1 on a match.
  */
  
-static inline int check_signature(unsigned long io_addr,
+static inline int check_signature(volatile void __iomem * io_addr,
        const unsigned char *signature, int length)
 {
        int retval = 0;
index aabe12cb898c9106033f5b29ee0dacde2262e8ad..62949aa638bbb8cf76de1510b2d0ba5b0b97d375 100644 (file)
@@ -6,13 +6,17 @@
 # define __kernel      /* default address space */
 # define __safe                __attribute__((safe))
 # define __force       __attribute__((force))
+# define __iomem       __attribute__((noderef, address_space(2)))
 extern void __chk_user_ptr(void __user *);
+extern void __chk_io_ptr(void __iomem *);
 #else
 # define __user
 # define __kernel
 # define __safe
 # define __force
+# define __iomem
 # define __chk_user_ptr(x) (void)0
+# define __chk_io_ptr(x) (void)0
 #endif
 
 #ifdef __KERNEL__