Merge branch 'fix/hda' into topic/hda
[pandora-kernel.git] / arch / s390 / kvm / gaccess.h
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