summaryrefslogtreecommitdiff
path: root/drivers/char/mem.c
diff options
context:
space:
mode:
authorvenkatesh.pallipadi@intel.com <venkatesh.pallipadi@intel.com>2008-03-18 17:00:15 -0700
committerIngo Molnar <mingo@elte.hu>2008-04-24 23:40:47 +0200
commite045fb2a988a9a1964059b0d33dbaf18d12f925f (patch)
tree61dbd03abd83dcf6d5195fa6463ea96e125784f6 /drivers/char/mem.c
parente2beb3eae627211b67e456c53f946cede2ac10d7 (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>
Diffstat (limited to 'drivers/char/mem.c')
-rw-r--r--drivers/char/mem.c32
1 files changed, 27 insertions, 5 deletions
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)
}
#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 @@ static ssize_t read_mem(struct file * file, char __user * buf,
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 (!ptr)
+ return -EFAULT;
- if (!range_is_allowed(p >> PAGE_SHIFT, count))
- return -EPERM;
- if (copy_to_user(buf, ptr, sz))
+ 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 @@ static ssize_t write_mem(struct file * file, const char __user * buf,
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 (!ptr) {
+ if (written)
+ break;
+ return -EFAULT;
+ }
- if (!range_is_allowed(p >> PAGE_SHIFT, sz))
- return -EPERM;
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;