Commit 5d9cb4db authored by Linus Torvalds's avatar Linus Torvalds

Add sparse "__iomem" infrastructure to check PCI address usage

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.
parent 3f63a8d2
...@@ -110,9 +110,9 @@ static int remap_area_pages(unsigned long address, unsigned long phys_addr, ...@@ -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 * have to convert them into an offset in a page-aligned mapping, but the
* caller shouldn't need to know that small detail. * 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; struct vm_struct * area;
unsigned long offset, last_addr; unsigned long offset, last_addr;
...@@ -125,7 +125,7 @@ void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flag ...@@ -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.. * Don't remap the low PCI/ISA area, it's always mapped..
*/ */
if (phys_addr >= 0xA0000 && last_addr < 0x100000) 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.. * 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 ...@@ -156,12 +156,12 @@ void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flag
if (!area) if (!area)
return NULL; return NULL;
area->phys_addr = phys_addr; area->phys_addr = phys_addr;
addr = area->addr; addr = (void __iomem *) area->addr;
if (remap_area_pages((unsigned long) addr, phys_addr, size, flags)) { if (remap_area_pages((unsigned long) addr, phys_addr, size, flags)) {
vunmap(addr); vunmap((void __force *) addr);
return NULL; 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 ...@@ -187,10 +187,10 @@ void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flag
* Must be freed with iounmap. * 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; unsigned long last_addr;
void *p = __ioremap(phys_addr, size, _PAGE_PCD); void __iomem *p = __ioremap(phys_addr, size, _PAGE_PCD);
if (!p) if (!p)
return p; return p;
...@@ -221,12 +221,12 @@ void *ioremap_nocache (unsigned long phys_addr, unsigned long size) ...@@ -221,12 +221,12 @@ void *ioremap_nocache (unsigned long phys_addr, unsigned long size)
return p; return p;
} }
void iounmap(void *addr) void iounmap(volatile void __iomem *addr)
{ {
struct vm_struct *p; struct vm_struct *p;
if (addr <= high_memory) if ((void __force *) addr <= high_memory)
return; return;
p = remove_vm_area((void *) (PAGE_MASK & (unsigned long) addr)); p = remove_vm_area((void *) (PAGE_MASK & (unsigned long __force) addr));
if (!p) { if (!p) {
printk("__iounmap: bad address %p\n", addr); printk("__iounmap: bad address %p\n", addr);
return; return;
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
#define _ASM_IO_H #define _ASM_IO_H
#include <linux/config.h> #include <linux/config.h>
#include <linux/string.h>
#include <linux/compiler.h>
/* /*
* This file contains the definitions for the x86 IO instructions * This file contains the definitions for the x86 IO instructions
...@@ -86,7 +88,7 @@ static inline void * phys_to_virt(unsigned long address) ...@@ -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) #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 * ioremap - map bus memory into CPU space
...@@ -100,13 +102,13 @@ extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long ...@@ -100,13 +102,13 @@ extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long
* address. * 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); return __ioremap(offset, size, 0);
} }
extern void * ioremap_nocache (unsigned long offset, unsigned long size); extern void __iomem * ioremap_nocache(unsigned long offset, unsigned long size);
extern void iounmap(void *addr); extern void iounmap(volatile void __iomem *addr);
/* /*
* bt_ioremap() and bt_iounmap() are for temporary early boot-time * bt_ioremap() and bt_iounmap() are for temporary early boot-time
...@@ -139,9 +141,18 @@ extern void bt_iounmap(void *addr, unsigned long size); ...@@ -139,9 +141,18 @@ extern void bt_iounmap(void *addr, unsigned long size);
* memory location directly. * memory location directly.
*/ */
#define readb(addr) (*(volatile unsigned char *) (addr)) static inline unsigned char readb(const volatile void __iomem *addr)
#define readw(addr) (*(volatile unsigned short *) (addr)) {
#define readl(addr) (*(volatile unsigned int *) (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 readb_relaxed(addr) readb(addr)
#define readw_relaxed(addr) readw(addr) #define readw_relaxed(addr) readw(addr)
#define readl_relaxed(addr) readl(addr) #define readl_relaxed(addr) readl(addr)
...@@ -149,16 +160,34 @@ extern void bt_iounmap(void *addr, unsigned long size); ...@@ -149,16 +160,34 @@ extern void bt_iounmap(void *addr, unsigned long size);
#define __raw_readw readw #define __raw_readw readw
#define __raw_readl readl #define __raw_readl readl
#define writeb(b,addr) (*(volatile unsigned char *) (addr) = (b)) static inline void writeb(unsigned char b, volatile void __iomem *addr)
#define writew(b,addr) (*(volatile unsigned short *) (addr) = (b)) {
#define writel(b,addr) (*(volatile unsigned int *) (addr) = (b)) *(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_writeb writeb
#define __raw_writew writew #define __raw_writew writew
#define __raw_writel writel #define __raw_writel writel
#define memset_io(a,b,c) memset((void *)(a),(b),(c)) static inline void memset_io(volatile void __iomem *addr, unsigned char val, int count)
#define memcpy_fromio(a,b,c) __memcpy((a),(void *)(b),(c)) {
#define memcpy_toio(a,b,c) __memcpy((void *)(a),(b),(c)) 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 * 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); ...@@ -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 * used as the IO-area pointer (it can be iounmapped as well, so the
* analogy with PCI is quite large): * 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_readb(a) readb(__ISA_IO_base + (a))
#define isa_readw(a) readw(__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); ...@@ -185,8 +214,8 @@ extern void bt_iounmap(void *addr, unsigned long size);
* Again, i386 does not require mem IO specific function. * 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 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 *)(__ISA_IO_base + (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 * check_signature - find BIOS signatures
...@@ -199,7 +228,7 @@ extern void bt_iounmap(void *addr, unsigned long size); ...@@ -199,7 +228,7 @@ extern void bt_iounmap(void *addr, unsigned long size);
* Returns 1 on a match. * 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) const unsigned char *signature, int length)
{ {
int retval = 0; int retval = 0;
......
...@@ -6,13 +6,17 @@ ...@@ -6,13 +6,17 @@
# define __kernel /* default address space */ # define __kernel /* default address space */
# define __safe __attribute__((safe)) # define __safe __attribute__((safe))
# define __force __attribute__((force)) # define __force __attribute__((force))
# define __iomem __attribute__((noderef, address_space(2)))
extern void __chk_user_ptr(void __user *); extern void __chk_user_ptr(void __user *);
extern void __chk_io_ptr(void __iomem *);
#else #else
# define __user # define __user
# define __kernel # define __kernel
# define __safe # define __safe
# define __force # define __force
# define __iomem
# define __chk_user_ptr(x) (void)0 # define __chk_user_ptr(x) (void)0
# define __chk_io_ptr(x) (void)0
#endif #endif
#ifdef __KERNEL__ #ifdef __KERNEL__
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment