xref: /openbmc/linux/arch/s390/kvm/gaccess.h (revision 6ee73861)
1 /*
2  * gaccess.h -  access guest memory
3  *
4  * Copyright IBM Corp. 2008,2009
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License (version 2 only)
8  * as published by the Free Software Foundation.
9  *
10  *    Author(s): Carsten Otte <cotte@de.ibm.com>
11  */
12 
13 #ifndef __KVM_S390_GACCESS_H
14 #define __KVM_S390_GACCESS_H
15 
16 #include <linux/compiler.h>
17 #include <linux/kvm_host.h>
18 #include <asm/uaccess.h>
19 #include "kvm-s390.h"
20 
21 static inline void __user *__guestaddr_to_user(struct kvm_vcpu *vcpu,
22 					       unsigned long guestaddr)
23 {
24 	unsigned long prefix  = vcpu->arch.sie_block->prefix;
25 	unsigned long origin  = vcpu->arch.sie_block->gmsor;
26 	unsigned long memsize = kvm_s390_vcpu_get_memsize(vcpu);
27 
28 	if (guestaddr < 2 * PAGE_SIZE)
29 		guestaddr += prefix;
30 	else if ((guestaddr >= prefix) && (guestaddr < prefix + 2 * PAGE_SIZE))
31 		guestaddr -= prefix;
32 
33 	if (guestaddr > memsize)
34 		return (void __user __force *) ERR_PTR(-EFAULT);
35 
36 	guestaddr += origin;
37 
38 	return (void __user *) guestaddr;
39 }
40 
41 static inline int get_guest_u64(struct kvm_vcpu *vcpu, unsigned long guestaddr,
42 				u64 *result)
43 {
44 	void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
45 
46 	BUG_ON(guestaddr & 7);
47 
48 	if (IS_ERR((void __force *) uptr))
49 		return PTR_ERR((void __force *) uptr);
50 
51 	return get_user(*result, (unsigned long __user *) uptr);
52 }
53 
54 static inline int get_guest_u32(struct kvm_vcpu *vcpu, unsigned long guestaddr,
55 				u32 *result)
56 {
57 	void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
58 
59 	BUG_ON(guestaddr & 3);
60 
61 	if (IS_ERR((void __force *) uptr))
62 		return PTR_ERR((void __force *) uptr);
63 
64 	return get_user(*result, (u32 __user *) uptr);
65 }
66 
67 static inline int get_guest_u16(struct kvm_vcpu *vcpu, unsigned long guestaddr,
68 				u16 *result)
69 {
70 	void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
71 
72 	BUG_ON(guestaddr & 1);
73 
74 	if (IS_ERR(uptr))
75 		return PTR_ERR(uptr);
76 
77 	return get_user(*result, (u16 __user *) uptr);
78 }
79 
80 static inline int get_guest_u8(struct kvm_vcpu *vcpu, unsigned long guestaddr,
81 			       u8 *result)
82 {
83 	void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
84 
85 	if (IS_ERR((void __force *) uptr))
86 		return PTR_ERR((void __force *) uptr);
87 
88 	return get_user(*result, (u8 __user *) uptr);
89 }
90 
91 static inline int put_guest_u64(struct kvm_vcpu *vcpu, unsigned long guestaddr,
92 				u64 value)
93 {
94 	void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
95 
96 	BUG_ON(guestaddr & 7);
97 
98 	if (IS_ERR((void __force *) uptr))
99 		return PTR_ERR((void __force *) uptr);
100 
101 	return put_user(value, (u64 __user *) uptr);
102 }
103 
104 static inline int put_guest_u32(struct kvm_vcpu *vcpu, unsigned long guestaddr,
105 				u32 value)
106 {
107 	void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
108 
109 	BUG_ON(guestaddr & 3);
110 
111 	if (IS_ERR((void __force *) uptr))
112 		return PTR_ERR((void __force *) uptr);
113 
114 	return put_user(value, (u32 __user *) uptr);
115 }
116 
117 static inline int put_guest_u16(struct kvm_vcpu *vcpu, unsigned long guestaddr,
118 				u16 value)
119 {
120 	void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
121 
122 	BUG_ON(guestaddr & 1);
123 
124 	if (IS_ERR((void __force *) uptr))
125 		return PTR_ERR((void __force *) uptr);
126 
127 	return put_user(value, (u16 __user *) uptr);
128 }
129 
130 static inline int put_guest_u8(struct kvm_vcpu *vcpu, unsigned long guestaddr,
131 			       u8 value)
132 {
133 	void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
134 
135 	if (IS_ERR((void __force *) uptr))
136 		return PTR_ERR((void __force *) uptr);
137 
138 	return put_user(value, (u8 __user *) uptr);
139 }
140 
141 
142 static inline int __copy_to_guest_slow(struct kvm_vcpu *vcpu,
143 				       unsigned long guestdest,
144 				       const void *from, unsigned long n)
145 {
146 	int rc;
147 	unsigned long i;
148 	const u8 *data = from;
149 
150 	for (i = 0; i < n; i++) {
151 		rc = put_guest_u8(vcpu, guestdest++, *(data++));
152 		if (rc < 0)
153 			return rc;
154 	}
155 	return 0;
156 }
157 
158 static inline int copy_to_guest(struct kvm_vcpu *vcpu, unsigned long guestdest,
159 				const void *from, unsigned long n)
160 {
161 	unsigned long prefix  = vcpu->arch.sie_block->prefix;
162 	unsigned long origin  = vcpu->arch.sie_block->gmsor;
163 	unsigned long memsize = kvm_s390_vcpu_get_memsize(vcpu);
164 
165 	if ((guestdest < 2 * PAGE_SIZE) && (guestdest + n > 2 * PAGE_SIZE))
166 		goto slowpath;
167 
168 	if ((guestdest < prefix) && (guestdest + n > prefix))
169 		goto slowpath;
170 
171 	if ((guestdest < prefix + 2 * PAGE_SIZE)
172 	    && (guestdest + n > prefix + 2 * PAGE_SIZE))
173 		goto slowpath;
174 
175 	if (guestdest < 2 * PAGE_SIZE)
176 		guestdest += prefix;
177 	else if ((guestdest >= prefix) && (guestdest < prefix + 2 * PAGE_SIZE))
178 		guestdest -= prefix;
179 
180 	if (guestdest + n > memsize)
181 		return -EFAULT;
182 
183 	if (guestdest + n < guestdest)
184 		return -EFAULT;
185 
186 	guestdest += origin;
187 
188 	return copy_to_user((void __user *) guestdest, from, n);
189 slowpath:
190 	return __copy_to_guest_slow(vcpu, guestdest, from, n);
191 }
192 
193 static inline int __copy_from_guest_slow(struct kvm_vcpu *vcpu, void *to,
194 					 unsigned long guestsrc,
195 					 unsigned long n)
196 {
197 	int rc;
198 	unsigned long i;
199 	u8 *data = to;
200 
201 	for (i = 0; i < n; i++) {
202 		rc = get_guest_u8(vcpu, guestsrc++, data++);
203 		if (rc < 0)
204 			return rc;
205 	}
206 	return 0;
207 }
208 
209 static inline int copy_from_guest(struct kvm_vcpu *vcpu, void *to,
210 				  unsigned long guestsrc, unsigned long n)
211 {
212 	unsigned long prefix  = vcpu->arch.sie_block->prefix;
213 	unsigned long origin  = vcpu->arch.sie_block->gmsor;
214 	unsigned long memsize = kvm_s390_vcpu_get_memsize(vcpu);
215 
216 	if ((guestsrc < 2 * PAGE_SIZE) && (guestsrc + n > 2 * PAGE_SIZE))
217 		goto slowpath;
218 
219 	if ((guestsrc < prefix) && (guestsrc + n > prefix))
220 		goto slowpath;
221 
222 	if ((guestsrc < prefix + 2 * PAGE_SIZE)
223 	    && (guestsrc + n > prefix + 2 * PAGE_SIZE))
224 		goto slowpath;
225 
226 	if (guestsrc < 2 * PAGE_SIZE)
227 		guestsrc += prefix;
228 	else if ((guestsrc >= prefix) && (guestsrc < prefix + 2 * PAGE_SIZE))
229 		guestsrc -= prefix;
230 
231 	if (guestsrc + n > memsize)
232 		return -EFAULT;
233 
234 	if (guestsrc + n < guestsrc)
235 		return -EFAULT;
236 
237 	guestsrc += origin;
238 
239 	return copy_from_user(to, (void __user *) guestsrc, n);
240 slowpath:
241 	return __copy_from_guest_slow(vcpu, to, guestsrc, n);
242 }
243 
244 static inline int copy_to_guest_absolute(struct kvm_vcpu *vcpu,
245 					 unsigned long guestdest,
246 					 const void *from, unsigned long n)
247 {
248 	unsigned long origin  = vcpu->arch.sie_block->gmsor;
249 	unsigned long memsize = kvm_s390_vcpu_get_memsize(vcpu);
250 
251 	if (guestdest + n > memsize)
252 		return -EFAULT;
253 
254 	if (guestdest + n < guestdest)
255 		return -EFAULT;
256 
257 	guestdest += origin;
258 
259 	return copy_to_user((void __user *) guestdest, from, n);
260 }
261 
262 static inline int copy_from_guest_absolute(struct kvm_vcpu *vcpu, void *to,
263 					   unsigned long guestsrc,
264 					   unsigned long n)
265 {
266 	unsigned long origin  = vcpu->arch.sie_block->gmsor;
267 	unsigned long memsize = kvm_s390_vcpu_get_memsize(vcpu);
268 
269 	if (guestsrc + n > memsize)
270 		return -EFAULT;
271 
272 	if (guestsrc + n < guestsrc)
273 		return -EFAULT;
274 
275 	guestsrc += origin;
276 
277 	return copy_from_user(to, (void __user *) guestsrc, n);
278 }
279 #endif
280