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>
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 964ff3b..83495885 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -134,6 +134,10 @@
}
#endif
+void __attribute__((weak)) unxlate_dev_mem_ptr(unsigned long phys, void *addr)
+{
+}
+
/*
* This funcion reads the *physical* memory. The f_pos points directly to the
* memory location.
@@ -176,17 +180,25 @@
sz = min_t(unsigned long, sz, count);
+ if (!range_is_allowed(p >> PAGE_SHIFT, count))
+ return -EPERM;
+
/*
* On ia64 if a page has been mapped somewhere as
* uncached, then it must also be accessed uncached
* by the kernel or data corruption may occur
*/
ptr = xlate_dev_mem_ptr(p);
-
- if (!range_is_allowed(p >> PAGE_SHIFT, count))
- return -EPERM;
- if (copy_to_user(buf, ptr, sz))
+ if (!ptr)
return -EFAULT;
+
+ if (copy_to_user(buf, ptr, sz)) {
+ unxlate_dev_mem_ptr(p, ptr);
+ return -EFAULT;
+ }
+
+ unxlate_dev_mem_ptr(p, ptr);
+
buf += sz;
p += sz;
count -= sz;
@@ -235,22 +247,32 @@
sz = min_t(unsigned long, sz, count);
+ if (!range_is_allowed(p >> PAGE_SHIFT, sz))
+ return -EPERM;
+
/*
* On ia64 if a page has been mapped somewhere as
* uncached, then it must also be accessed uncached
* by the kernel or data corruption may occur
*/
ptr = xlate_dev_mem_ptr(p);
-
- if (!range_is_allowed(p >> PAGE_SHIFT, sz))
- return -EPERM;
- copied = copy_from_user(ptr, buf, sz);
- if (copied) {
- written += sz - copied;
+ if (!ptr) {
if (written)
break;
return -EFAULT;
}
+
+ copied = copy_from_user(ptr, buf, sz);
+ if (copied) {
+ written += sz - copied;
+ unxlate_dev_mem_ptr(p, ptr);
+ if (written)
+ break;
+ return -EFAULT;
+ }
+
+ unxlate_dev_mem_ptr(p, ptr);
+
buf += sz;
p += sz;
count -= sz;