map and unmap reserved regions, before accessing through /dev/mem read
interface. This is for full compatibility with existing /dev/mem
usages.
For regions that are mapped in identity map, we use __va().

Signed-off-by: Venkatesh Pallipadi <[EMAIL PROTECTED]>
Signed-off-by: Suresh Siddha <[EMAIL PROTECTED]>

Index: linux-2.6.git/arch/x86/mm/ioremap.c
===================================================================
--- linux-2.6.git.orig/arch/x86/mm/ioremap.c    2008-01-15 10:05:13.000000000 
-0800
+++ linux-2.6.git/arch/x86/mm/ioremap.c 2008-01-15 10:39:18.000000000 -0800
@@ -32,6 +32,39 @@
 }
 EXPORT_SYMBOL(ioremap_wc);
 
+/*
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+ * access
+ */
+void *xlate_dev_mem_ptr(unsigned long phys)
+{
+       void *addr;
+       unsigned long start = phys & PAGE_MASK;
+
+       /*
+        * If any memory in PAGE_SIZE is valid, then we can use __va. Otherwise
+        * ioremap and unmap the memory.
+        */
+       if (is_memory_any_valid(start, start + PAGE_SIZE))
+               return __va(phys);
+
+       addr = (void *)ioremap(start, PAGE_SIZE);
+       if (addr)
+               addr = (void *)((unsigned long)addr | (phys & ~PAGE_MASK));
+
+       return addr;
+}
+
+void unxlate_dev_mem_ptr(unsigned long phys, void *addr)
+{
+       unsigned long start = phys & PAGE_MASK;
+       if (is_memory_any_valid(start, start + PAGE_SIZE))
+               return;
+
+       iounmap((void __iomem *)((unsigned long)addr & PAGE_MASK));
+       return;
+}
+
 int valid_phys_addr_range(unsigned long addr, size_t count)
 {
        if (addr + count > __pa(high_memory))
Index: linux-2.6.git/drivers/char/mem.c
===================================================================
--- linux-2.6.git.orig/drivers/char/mem.c       2008-01-15 10:05:13.000000000 
-0800
+++ linux-2.6.git/drivers/char/mem.c    2008-01-15 10:05:51.000000000 -0800
@@ -127,9 +127,14 @@
                 * by the kernel or data corruption may occur
                 */
                ptr = xlate_dev_mem_ptr(p);
+               if (!ptr)
+                       return -EFAULT;
 
                if (copy_to_user(buf, ptr, sz))
                        return -EFAULT;
+
+               unxlate_dev_mem_ptr(p, ptr);
+
                buf += sz;
                p += sz;
                count -= sz;
@@ -184,6 +189,11 @@
                 * by the kernel or data corruption may occur
                 */
                ptr = xlate_dev_mem_ptr(p);
+               if (!ptr) {
+                       if (written)
+                               break;
+                       return -EFAULT;
+               }
 
                copied = copy_from_user(ptr, buf, sz);
                if (copied) {
@@ -192,6 +202,9 @@
                                break;
                        return -EFAULT;
                }
+
+               unxlate_dev_mem_ptr(p, ptr);
+
                buf += sz;
                p += sz;
                count -= sz;
Index: linux-2.6.git/include/asm-generic/iomap.h
===================================================================
--- linux-2.6.git.orig/include/asm-generic/iomap.h      2008-01-15 
10:05:13.000000000 -0800
+++ linux-2.6.git/include/asm-generic/iomap.h   2008-01-15 10:23:24.000000000 
-0800
@@ -69,4 +69,8 @@
 #define ioremap_wc ioremap_nocache
 #endif
 
+#ifndef unxlate_dev_mem_ptr
+static inline void unxlate_dev_mem_ptr(unsigned long phys, void *addr) {}
+#endif
+
 #endif
Index: linux-2.6.git/include/asm-x86/io.h
===================================================================
--- linux-2.6.git.orig/include/asm-x86/io.h     2008-01-15 10:05:13.000000000 
-0800
+++ linux-2.6.git/include/asm-x86/io.h  2008-01-15 10:21:42.000000000 -0800
@@ -2,6 +2,7 @@
 #define _ASM_X86_IO_H
 
 #define ioremap_wc ioremap_wc
+#define unxlate_dev_mem_ptr unxlate_dev_mem_ptr
 
 #ifdef CONFIG_X86_32
 # include "io_32.h"
@@ -10,6 +11,8 @@
 #endif
 
 extern void __iomem * ioremap_wc(unsigned long offset, unsigned long size);
+extern void *xlate_dev_mem_ptr(unsigned long phys);
+extern void unxlate_dev_mem_ptr(unsigned long phys, void *addr);
 
 #define ARCH_HAS_VALID_PHYS_ADDR_RANGE
 
Index: linux-2.6.git/include/asm-x86/io_32.h
===================================================================
--- linux-2.6.git.orig/include/asm-x86/io_32.h  2008-01-15 10:05:13.000000000 
-0800
+++ linux-2.6.git/include/asm-x86/io_32.h       2008-01-15 10:05:51.000000000 
-0800
@@ -49,12 +49,6 @@
 #include <linux/vmalloc.h>
 
 /*
- * Convert a physical pointer to a virtual kernel pointer for /dev/mem
- * access
- */
-#define xlate_dev_mem_ptr(p)   __va(p)
-
-/*
  * Convert a virtual cached pointer to an uncached pointer
  */
 #define xlate_dev_kmem_ptr(p)  p
Index: linux-2.6.git/include/asm-x86/io_64.h
===================================================================
--- linux-2.6.git.orig/include/asm-x86/io_64.h  2008-01-15 10:05:13.000000000 
-0800
+++ linux-2.6.git/include/asm-x86/io_64.h       2008-01-15 10:05:51.000000000 
-0800
@@ -278,12 +278,6 @@
 #define BIO_VMERGE_BOUNDARY iommu_bio_merge
 
 /*
- * Convert a physical pointer to a virtual kernel pointer for /dev/mem
- * access
- */
-#define xlate_dev_mem_ptr(p)   __va(p)
-
-/*
  * Convert a virtual cached pointer to an uncached pointer
  */
 #define xlate_dev_kmem_ptr(p)  p

-- 
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to