[S390] Add real memory access functions
authorMichael Holzheu <holzheu@linux.vnet.ibm.com>
Sun, 30 Oct 2011 14:16:39 +0000 (15:16 +0100)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Sun, 30 Oct 2011 14:16:42 +0000 (15:16 +0100)
Add access function for real memory needed by s390 kdump backend.

Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
arch/s390/include/asm/system.h
arch/s390/mm/maccess.c
drivers/s390/char/zcore.c

index 6582f69..afb849e 100644 (file)
@@ -114,6 +114,8 @@ extern void pfault_fini(void);
 extern void cmma_init(void);
 extern int memcpy_real(void *, void *, size_t);
 extern void copy_to_absolute_zero(void *dest, void *src, size_t count);
+extern int copy_to_user_real(void __user *dest, void *src, size_t count);
+extern int copy_from_user_real(void *dest, void __user *src, size_t count);
 
 #define finish_arch_switch(prev) do {                                       \
        set_fs(current->thread.mm_segment);                                  \
index 5dbbaa6..1cb8427 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/errno.h>
+#include <linux/gfp.h>
 #include <asm/system.h>
 
 /*
@@ -60,6 +61,9 @@ long probe_kernel_write(void *dst, const void *src, size_t size)
        return copied < 0 ? -EFAULT : 0;
 }
 
+/*
+ * Copy memory in real mode (kernel to kernel)
+ */
 int memcpy_real(void *dest, void *src, size_t count)
 {
        register unsigned long _dest asm("2") = (unsigned long) dest;
@@ -101,3 +105,55 @@ void copy_to_absolute_zero(void *dest, void *src, size_t count)
        __ctl_load(cr0, 0, 0);
        preempt_enable();
 }
+
+/*
+ * Copy memory from kernel (real) to user (virtual)
+ */
+int copy_to_user_real(void __user *dest, void *src, size_t count)
+{
+       int offs = 0, size, rc;
+       char *buf;
+
+       buf = (char *) __get_free_page(GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+       rc = -EFAULT;
+       while (offs < count) {
+               size = min(PAGE_SIZE, count - offs);
+               if (memcpy_real(buf, src + offs, size))
+                       goto out;
+               if (copy_to_user(dest + offs, buf, size))
+                       goto out;
+               offs += size;
+       }
+       rc = 0;
+out:
+       free_page((unsigned long) buf);
+       return rc;
+}
+
+/*
+ * Copy memory from user (virtual) to kernel (real)
+ */
+int copy_from_user_real(void *dest, void __user *src, size_t count)
+{
+       int offs = 0, size, rc;
+       char *buf;
+
+       buf = (char *) __get_free_page(GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+       rc = -EFAULT;
+       while (offs < count) {
+               size = min(PAGE_SIZE, count - offs);
+               if (copy_from_user(buf, src + offs, size))
+                       goto out;
+               if (memcpy_real(dest + offs, buf, size))
+                       goto out;
+               offs += size;
+       }
+       rc = 0;
+out:
+       free_page((unsigned long) buf);
+       return rc;
+}
index 3b94044..f4f1da2 100644 (file)
@@ -142,22 +142,6 @@ static int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count)
        return memcpy_hsa(dest, src, count, TO_KERNEL);
 }
 
-static int memcpy_real_user(void __user *dest, unsigned long src, size_t count)
-{
-       static char buf[4096];
-       int offs = 0, size;
-
-       while (offs < count) {
-               size = min(sizeof(buf), count - offs);
-               if (memcpy_real(buf, (void *) src + offs, size))
-                       return -EFAULT;
-               if (copy_to_user(dest + offs, buf, size))
-                       return -EFAULT;
-               offs += size;
-       }
-       return 0;
-}
-
 static int __init init_cpu_info(enum arch_id arch)
 {
        struct save_area *sa;
@@ -346,8 +330,8 @@ static ssize_t zcore_read(struct file *file, char __user *buf, size_t count,
 
        /* Copy from real mem */
        size = count - mem_offs - hdr_count;
-       rc = memcpy_real_user(buf + hdr_count + mem_offs, mem_start + mem_offs,
-                             size);
+       rc = copy_to_user_real(buf + hdr_count + mem_offs,
+                              (void *) mem_start + mem_offs, size);
        if (rc)
                goto fail;