aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/s390/include/asm/system.h2
-rw-r--r--arch/s390/mm/maccess.c56
2 files changed, 58 insertions, 0 deletions
diff --git a/arch/s390/include/asm/system.h b/arch/s390/include/asm/system.h
index 6582f69f2389..afb849e4bf4b 100644
--- a/arch/s390/include/asm/system.h
+++ b/arch/s390/include/asm/system.h
@@ -114,6 +114,8 @@ extern void pfault_fini(void);
114extern void cmma_init(void); 114extern void cmma_init(void);
115extern int memcpy_real(void *, void *, size_t); 115extern int memcpy_real(void *, void *, size_t);
116extern void copy_to_absolute_zero(void *dest, void *src, size_t count); 116extern void copy_to_absolute_zero(void *dest, void *src, size_t count);
117extern int copy_to_user_real(void __user *dest, void *src, size_t count);
118extern int copy_from_user_real(void *dest, void __user *src, size_t count);
117 119
118#define finish_arch_switch(prev) do { \ 120#define finish_arch_switch(prev) do { \
119 set_fs(current->thread.mm_segment); \ 121 set_fs(current->thread.mm_segment); \
diff --git a/arch/s390/mm/maccess.c b/arch/s390/mm/maccess.c
index 5dbbaa6e594c..1cb8427bedfb 100644
--- a/arch/s390/mm/maccess.c
+++ b/arch/s390/mm/maccess.c
@@ -11,6 +11,7 @@
11#include <linux/kernel.h> 11#include <linux/kernel.h>
12#include <linux/types.h> 12#include <linux/types.h>
13#include <linux/errno.h> 13#include <linux/errno.h>
14#include <linux/gfp.h>
14#include <asm/system.h> 15#include <asm/system.h>
15 16
16/* 17/*
@@ -60,6 +61,9 @@ long probe_kernel_write(void *dst, const void *src, size_t size)
60 return copied < 0 ? -EFAULT : 0; 61 return copied < 0 ? -EFAULT : 0;
61} 62}
62 63
64/*
65 * Copy memory in real mode (kernel to kernel)
66 */
63int memcpy_real(void *dest, void *src, size_t count) 67int memcpy_real(void *dest, void *src, size_t count)
64{ 68{
65 register unsigned long _dest asm("2") = (unsigned long) dest; 69 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)
101 __ctl_load(cr0, 0, 0); 105 __ctl_load(cr0, 0, 0);
102 preempt_enable(); 106 preempt_enable();
103} 107}
108
109/*
110 * Copy memory from kernel (real) to user (virtual)
111 */
112int copy_to_user_real(void __user *dest, void *src, size_t count)
113{
114 int offs = 0, size, rc;
115 char *buf;
116
117 buf = (char *) __get_free_page(GFP_KERNEL);
118 if (!buf)
119 return -ENOMEM;
120 rc = -EFAULT;
121 while (offs < count) {
122 size = min(PAGE_SIZE, count - offs);
123 if (memcpy_real(buf, src + offs, size))
124 goto out;
125 if (copy_to_user(dest + offs, buf, size))
126 goto out;
127 offs += size;
128 }
129 rc = 0;
130out:
131 free_page((unsigned long) buf);
132 return rc;
133}
134
135/*
136 * Copy memory from user (virtual) to kernel (real)
137 */
138int copy_from_user_real(void *dest, void __user *src, size_t count)
139{
140 int offs = 0, size, rc;
141 char *buf;
142
143 buf = (char *) __get_free_page(GFP_KERNEL);
144 if (!buf)
145 return -ENOMEM;
146 rc = -EFAULT;
147 while (offs < count) {
148 size = min(PAGE_SIZE, count - offs);
149 if (copy_from_user(buf, src + offs, size))
150 goto out;
151 if (memcpy_real(dest + offs, buf, size))
152 goto out;
153 offs += size;
154 }
155 rc = 0;
156out:
157 free_page((unsigned long) buf);
158 return rc;
159}