diff options
| -rw-r--r-- | arch/x86/mm/ioremap.c | 29 | ||||
| -rw-r--r-- | drivers/char/mem.c | 32 | ||||
| -rw-r--r-- | include/asm-x86/io.h | 8 | ||||
| -rw-r--r-- | include/asm-x86/io_32.h | 6 | ||||
| -rw-r--r-- | include/asm-x86/io_64.h | 6 |
5 files changed, 64 insertions, 17 deletions
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c index 3a4baf95e24d..caac7d5699a7 100644 --- a/arch/x86/mm/ioremap.c +++ b/arch/x86/mm/ioremap.c | |||
| @@ -336,6 +336,35 @@ void iounmap(volatile void __iomem *addr) | |||
| 336 | } | 336 | } |
| 337 | EXPORT_SYMBOL(iounmap); | 337 | EXPORT_SYMBOL(iounmap); |
| 338 | 338 | ||
| 339 | /* | ||
| 340 | * Convert a physical pointer to a virtual kernel pointer for /dev/mem | ||
| 341 | * access | ||
| 342 | */ | ||
| 343 | void *xlate_dev_mem_ptr(unsigned long phys) | ||
| 344 | { | ||
| 345 | void *addr; | ||
| 346 | unsigned long start = phys & PAGE_MASK; | ||
| 347 | |||
| 348 | /* If page is RAM, we can use __va. Otherwise ioremap and unmap. */ | ||
| 349 | if (page_is_ram(start >> PAGE_SHIFT)) | ||
| 350 | return __va(phys); | ||
| 351 | |||
| 352 | addr = (void *)ioremap(start, PAGE_SIZE); | ||
| 353 | if (addr) | ||
| 354 | addr = (void *)((unsigned long)addr | (phys & ~PAGE_MASK)); | ||
| 355 | |||
| 356 | return addr; | ||
| 357 | } | ||
| 358 | |||
| 359 | void unxlate_dev_mem_ptr(unsigned long phys, void *addr) | ||
| 360 | { | ||
| 361 | if (page_is_ram(phys >> PAGE_SHIFT)) | ||
| 362 | return; | ||
| 363 | |||
| 364 | iounmap((void __iomem *)((unsigned long)addr & PAGE_MASK)); | ||
| 365 | return; | ||
| 366 | } | ||
| 367 | |||
| 339 | #ifdef CONFIG_X86_32 | 368 | #ifdef CONFIG_X86_32 |
| 340 | 369 | ||
| 341 | int __initdata early_ioremap_debug; | 370 | int __initdata early_ioremap_debug; |
diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 964ff3b1cff4..83495885ada0 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c | |||
| @@ -134,6 +134,10 @@ static inline int range_is_allowed(unsigned long pfn, unsigned long size) | |||
| 134 | } | 134 | } |
| 135 | #endif | 135 | #endif |
| 136 | 136 | ||
| 137 | void __attribute__((weak)) unxlate_dev_mem_ptr(unsigned long phys, void *addr) | ||
| 138 | { | ||
| 139 | } | ||
| 140 | |||
| 137 | /* | 141 | /* |
| 138 | * This funcion reads the *physical* memory. The f_pos points directly to the | 142 | * This funcion reads the *physical* memory. The f_pos points directly to the |
| 139 | * memory location. | 143 | * memory location. |
| @@ -176,17 +180,25 @@ static ssize_t read_mem(struct file * file, char __user * buf, | |||
| 176 | 180 | ||
| 177 | sz = min_t(unsigned long, sz, count); | 181 | sz = min_t(unsigned long, sz, count); |
| 178 | 182 | ||
| 183 | if (!range_is_allowed(p >> PAGE_SHIFT, count)) | ||
| 184 | return -EPERM; | ||
| 185 | |||
| 179 | /* | 186 | /* |
| 180 | * On ia64 if a page has been mapped somewhere as | 187 | * On ia64 if a page has been mapped somewhere as |
| 181 | * uncached, then it must also be accessed uncached | 188 | * uncached, then it must also be accessed uncached |
| 182 | * by the kernel or data corruption may occur | 189 | * by the kernel or data corruption may occur |
| 183 | */ | 190 | */ |
| 184 | ptr = xlate_dev_mem_ptr(p); | 191 | ptr = xlate_dev_mem_ptr(p); |
| 192 | if (!ptr) | ||
| 193 | return -EFAULT; | ||
| 185 | 194 | ||
| 186 | if (!range_is_allowed(p >> PAGE_SHIFT, count)) | 195 | if (copy_to_user(buf, ptr, sz)) { |
| 187 | return -EPERM; | 196 | unxlate_dev_mem_ptr(p, ptr); |
| 188 | if (copy_to_user(buf, ptr, sz)) | ||
| 189 | return -EFAULT; | 197 | return -EFAULT; |
| 198 | } | ||
| 199 | |||
| 200 | unxlate_dev_mem_ptr(p, ptr); | ||
| 201 | |||
| 190 | buf += sz; | 202 | buf += sz; |
| 191 | p += sz; | 203 | p += sz; |
| 192 | count -= sz; | 204 | count -= sz; |
| @@ -235,22 +247,32 @@ static ssize_t write_mem(struct file * file, const char __user * buf, | |||
| 235 | 247 | ||
| 236 | sz = min_t(unsigned long, sz, count); | 248 | sz = min_t(unsigned long, sz, count); |
| 237 | 249 | ||
| 250 | if (!range_is_allowed(p >> PAGE_SHIFT, sz)) | ||
| 251 | return -EPERM; | ||
| 252 | |||
| 238 | /* | 253 | /* |
| 239 | * On ia64 if a page has been mapped somewhere as | 254 | * On ia64 if a page has been mapped somewhere as |
| 240 | * uncached, then it must also be accessed uncached | 255 | * uncached, then it must also be accessed uncached |
| 241 | * by the kernel or data corruption may occur | 256 | * by the kernel or data corruption may occur |
| 242 | */ | 257 | */ |
| 243 | ptr = xlate_dev_mem_ptr(p); | 258 | ptr = xlate_dev_mem_ptr(p); |
| 259 | if (!ptr) { | ||
| 260 | if (written) | ||
| 261 | break; | ||
| 262 | return -EFAULT; | ||
| 263 | } | ||
| 244 | 264 | ||
| 245 | if (!range_is_allowed(p >> PAGE_SHIFT, sz)) | ||
| 246 | return -EPERM; | ||
| 247 | copied = copy_from_user(ptr, buf, sz); | 265 | copied = copy_from_user(ptr, buf, sz); |
| 248 | if (copied) { | 266 | if (copied) { |
| 249 | written += sz - copied; | 267 | written += sz - copied; |
| 268 | unxlate_dev_mem_ptr(p, ptr); | ||
| 250 | if (written) | 269 | if (written) |
| 251 | break; | 270 | break; |
| 252 | return -EFAULT; | 271 | return -EFAULT; |
| 253 | } | 272 | } |
| 273 | |||
| 274 | unxlate_dev_mem_ptr(p, ptr); | ||
| 275 | |||
| 254 | buf += sz; | 276 | buf += sz; |
| 255 | p += sz; | 277 | p += sz; |
| 256 | count -= sz; | 278 | count -= sz; |
diff --git a/include/asm-x86/io.h b/include/asm-x86/io.h index 7b292d386713..d5b11f60dbd0 100644 --- a/include/asm-x86/io.h +++ b/include/asm-x86/io.h | |||
| @@ -1,3 +1,6 @@ | |||
| 1 | #ifndef _ASM_X86_IO_H | ||
| 2 | #define _ASM_X86_IO_H | ||
| 3 | |||
| 1 | #define ARCH_HAS_IOREMAP_WC | 4 | #define ARCH_HAS_IOREMAP_WC |
| 2 | 5 | ||
| 3 | #ifdef CONFIG_X86_32 | 6 | #ifdef CONFIG_X86_32 |
| @@ -5,7 +8,12 @@ | |||
| 5 | #else | 8 | #else |
| 6 | # include "io_64.h" | 9 | # include "io_64.h" |
| 7 | #endif | 10 | #endif |
| 11 | |||
| 12 | extern void *xlate_dev_mem_ptr(unsigned long phys); | ||
| 13 | extern void unxlate_dev_mem_ptr(unsigned long phys, void *addr); | ||
| 14 | |||
| 8 | extern int ioremap_change_attr(unsigned long vaddr, unsigned long size, | 15 | extern int ioremap_change_attr(unsigned long vaddr, unsigned long size, |
| 9 | unsigned long prot_val); | 16 | unsigned long prot_val); |
| 10 | extern void __iomem *ioremap_wc(unsigned long offset, unsigned long size); | 17 | extern void __iomem *ioremap_wc(unsigned long offset, unsigned long size); |
| 11 | 18 | ||
| 19 | #endif /* _ASM_X86_IO_H */ | ||
diff --git a/include/asm-x86/io_32.h b/include/asm-x86/io_32.h index 509045f5fda2..6e73467a4fb1 100644 --- a/include/asm-x86/io_32.h +++ b/include/asm-x86/io_32.h | |||
| @@ -49,12 +49,6 @@ | |||
| 49 | #include <linux/vmalloc.h> | 49 | #include <linux/vmalloc.h> |
| 50 | 50 | ||
| 51 | /* | 51 | /* |
| 52 | * Convert a physical pointer to a virtual kernel pointer for /dev/mem | ||
| 53 | * access | ||
| 54 | */ | ||
| 55 | #define xlate_dev_mem_ptr(p) __va(p) | ||
| 56 | |||
| 57 | /* | ||
| 58 | * Convert a virtual cached pointer to an uncached pointer | 52 | * Convert a virtual cached pointer to an uncached pointer |
| 59 | */ | 53 | */ |
| 60 | #define xlate_dev_kmem_ptr(p) p | 54 | #define xlate_dev_kmem_ptr(p) p |
diff --git a/include/asm-x86/io_64.h b/include/asm-x86/io_64.h index c2f5eef47b88..0930bedf9e4d 100644 --- a/include/asm-x86/io_64.h +++ b/include/asm-x86/io_64.h | |||
| @@ -308,12 +308,6 @@ extern int iommu_bio_merge; | |||
| 308 | #define BIO_VMERGE_BOUNDARY iommu_bio_merge | 308 | #define BIO_VMERGE_BOUNDARY iommu_bio_merge |
| 309 | 309 | ||
| 310 | /* | 310 | /* |
| 311 | * Convert a physical pointer to a virtual kernel pointer for /dev/mem | ||
| 312 | * access | ||
| 313 | */ | ||
| 314 | #define xlate_dev_mem_ptr(p) __va(p) | ||
| 315 | |||
| 316 | /* | ||
| 317 | * Convert a virtual cached pointer to an uncached pointer | 311 | * Convert a virtual cached pointer to an uncached pointer |
| 318 | */ | 312 | */ |
| 319 | #define xlate_dev_kmem_ptr(p) p | 313 | #define xlate_dev_kmem_ptr(p) p |
