diff options
author | venkatesh.pallipadi@intel.com <venkatesh.pallipadi@intel.com> | 2008-03-18 20:00:15 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-04-24 17:40:47 -0400 |
commit | e045fb2a988a9a1964059b0d33dbaf18d12f925f (patch) | |
tree | 61dbd03abd83dcf6d5195fa6463ea96e125784f6 | |
parent | e2beb3eae627211b67e456c53f946cede2ac10d7 (diff) |
x86: PAT avoid aliasing in /dev/mem read/write
Add xlate and unxlate around /dev/mem read/write. This sets up the mapping
that can be used for /dev/mem read and write without aliasing worries.
Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
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.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 |