diff options
author | Steve French <sfrench@us.ibm.com> | 2008-04-28 00:01:34 -0400 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2008-04-28 00:01:34 -0400 |
commit | 1dbbb6077426f8ce63d6a59c5ac6613e1689cbde (patch) | |
tree | 6141d4d7a8eb7c557705bdfa764137d4fd2e4924 /arch/s390/kvm/gaccess.h | |
parent | d09e860cf07e7c9ee12920a09f5080e30a12a23a (diff) | |
parent | 064922a805ec7aadfafdd27aa6b4908d737c3c1d (diff) |
Merge branch 'master' of /pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'arch/s390/kvm/gaccess.h')
-rw-r--r-- | arch/s390/kvm/gaccess.h | 274 |
1 files changed, 274 insertions, 0 deletions
diff --git a/arch/s390/kvm/gaccess.h b/arch/s390/kvm/gaccess.h new file mode 100644 index 000000000000..4e0633c413f3 --- /dev/null +++ b/arch/s390/kvm/gaccess.h | |||
@@ -0,0 +1,274 @@ | |||
1 | /* | ||
2 | * gaccess.h - access guest memory | ||
3 | * | ||
4 | * Copyright IBM Corp. 2008 | ||
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 | |||
20 | static inline void __user *__guestaddr_to_user(struct kvm_vcpu *vcpu, | ||
21 | u64 guestaddr) | ||
22 | { | ||
23 | u64 prefix = vcpu->arch.sie_block->prefix; | ||
24 | u64 origin = vcpu->kvm->arch.guest_origin; | ||
25 | u64 memsize = vcpu->kvm->arch.guest_memsize; | ||
26 | |||
27 | if (guestaddr < 2 * PAGE_SIZE) | ||
28 | guestaddr += prefix; | ||
29 | else if ((guestaddr >= prefix) && (guestaddr < prefix + 2 * PAGE_SIZE)) | ||
30 | guestaddr -= prefix; | ||
31 | |||
32 | if (guestaddr > memsize) | ||
33 | return (void __user __force *) ERR_PTR(-EFAULT); | ||
34 | |||
35 | guestaddr += origin; | ||
36 | |||
37 | return (void __user *) guestaddr; | ||
38 | } | ||
39 | |||
40 | static inline int get_guest_u64(struct kvm_vcpu *vcpu, u64 guestaddr, | ||
41 | u64 *result) | ||
42 | { | ||
43 | void __user *uptr = __guestaddr_to_user(vcpu, guestaddr); | ||
44 | |||
45 | BUG_ON(guestaddr & 7); | ||
46 | |||
47 | if (IS_ERR((void __force *) uptr)) | ||
48 | return PTR_ERR((void __force *) uptr); | ||
49 | |||
50 | return get_user(*result, (u64 __user *) uptr); | ||
51 | } | ||
52 | |||
53 | static inline int get_guest_u32(struct kvm_vcpu *vcpu, u64 guestaddr, | ||
54 | u32 *result) | ||
55 | { | ||
56 | void __user *uptr = __guestaddr_to_user(vcpu, guestaddr); | ||
57 | |||
58 | BUG_ON(guestaddr & 3); | ||
59 | |||
60 | if (IS_ERR((void __force *) uptr)) | ||
61 | return PTR_ERR((void __force *) uptr); | ||
62 | |||
63 | return get_user(*result, (u32 __user *) uptr); | ||
64 | } | ||
65 | |||
66 | static inline int get_guest_u16(struct kvm_vcpu *vcpu, u64 guestaddr, | ||
67 | u16 *result) | ||
68 | { | ||
69 | void __user *uptr = __guestaddr_to_user(vcpu, guestaddr); | ||
70 | |||
71 | BUG_ON(guestaddr & 1); | ||
72 | |||
73 | if (IS_ERR(uptr)) | ||
74 | return PTR_ERR(uptr); | ||
75 | |||
76 | return get_user(*result, (u16 __user *) uptr); | ||
77 | } | ||
78 | |||
79 | static inline int get_guest_u8(struct kvm_vcpu *vcpu, u64 guestaddr, | ||
80 | u8 *result) | ||
81 | { | ||
82 | void __user *uptr = __guestaddr_to_user(vcpu, guestaddr); | ||
83 | |||
84 | if (IS_ERR((void __force *) uptr)) | ||
85 | return PTR_ERR((void __force *) uptr); | ||
86 | |||
87 | return get_user(*result, (u8 __user *) uptr); | ||
88 | } | ||
89 | |||
90 | static inline int put_guest_u64(struct kvm_vcpu *vcpu, u64 guestaddr, | ||
91 | u64 value) | ||
92 | { | ||
93 | void __user *uptr = __guestaddr_to_user(vcpu, guestaddr); | ||
94 | |||
95 | BUG_ON(guestaddr & 7); | ||
96 | |||
97 | if (IS_ERR((void __force *) uptr)) | ||
98 | return PTR_ERR((void __force *) uptr); | ||
99 | |||
100 | return put_user(value, (u64 __user *) uptr); | ||
101 | } | ||
102 | |||
103 | static inline int put_guest_u32(struct kvm_vcpu *vcpu, u64 guestaddr, | ||
104 | u32 value) | ||
105 | { | ||
106 | void __user *uptr = __guestaddr_to_user(vcpu, guestaddr); | ||
107 | |||
108 | BUG_ON(guestaddr & 3); | ||
109 | |||
110 | if (IS_ERR((void __force *) uptr)) | ||
111 | return PTR_ERR((void __force *) uptr); | ||
112 | |||
113 | return put_user(value, (u32 __user *) uptr); | ||
114 | } | ||
115 | |||
116 | static inline int put_guest_u16(struct kvm_vcpu *vcpu, u64 guestaddr, | ||
117 | u16 value) | ||
118 | { | ||
119 | void __user *uptr = __guestaddr_to_user(vcpu, guestaddr); | ||
120 | |||
121 | BUG_ON(guestaddr & 1); | ||
122 | |||
123 | if (IS_ERR((void __force *) uptr)) | ||
124 | return PTR_ERR((void __force *) uptr); | ||
125 | |||
126 | return put_user(value, (u16 __user *) uptr); | ||
127 | } | ||
128 | |||
129 | static inline int put_guest_u8(struct kvm_vcpu *vcpu, u64 guestaddr, | ||
130 | u8 value) | ||
131 | { | ||
132 | void __user *uptr = __guestaddr_to_user(vcpu, guestaddr); | ||
133 | |||
134 | if (IS_ERR((void __force *) uptr)) | ||
135 | return PTR_ERR((void __force *) uptr); | ||
136 | |||
137 | return put_user(value, (u8 __user *) uptr); | ||
138 | } | ||
139 | |||
140 | |||
141 | static inline int __copy_to_guest_slow(struct kvm_vcpu *vcpu, u64 guestdest, | ||
142 | const void *from, unsigned long n) | ||
143 | { | ||
144 | int rc; | ||
145 | unsigned long i; | ||
146 | const u8 *data = from; | ||
147 | |||
148 | for (i = 0; i < n; i++) { | ||
149 | rc = put_guest_u8(vcpu, guestdest++, *(data++)); | ||
150 | if (rc < 0) | ||
151 | return rc; | ||
152 | } | ||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | static inline int copy_to_guest(struct kvm_vcpu *vcpu, u64 guestdest, | ||
157 | const void *from, unsigned long n) | ||
158 | { | ||
159 | u64 prefix = vcpu->arch.sie_block->prefix; | ||
160 | u64 origin = vcpu->kvm->arch.guest_origin; | ||
161 | u64 memsize = vcpu->kvm->arch.guest_memsize; | ||
162 | |||
163 | if ((guestdest < 2 * PAGE_SIZE) && (guestdest + n > 2 * PAGE_SIZE)) | ||
164 | goto slowpath; | ||
165 | |||
166 | if ((guestdest < prefix) && (guestdest + n > prefix)) | ||
167 | goto slowpath; | ||
168 | |||
169 | if ((guestdest < prefix + 2 * PAGE_SIZE) | ||
170 | && (guestdest + n > prefix + 2 * PAGE_SIZE)) | ||
171 | goto slowpath; | ||
172 | |||
173 | if (guestdest < 2 * PAGE_SIZE) | ||
174 | guestdest += prefix; | ||
175 | else if ((guestdest >= prefix) && (guestdest < prefix + 2 * PAGE_SIZE)) | ||
176 | guestdest -= prefix; | ||
177 | |||
178 | if (guestdest + n > memsize) | ||
179 | return -EFAULT; | ||
180 | |||
181 | if (guestdest + n < guestdest) | ||
182 | return -EFAULT; | ||
183 | |||
184 | guestdest += origin; | ||
185 | |||
186 | return copy_to_user((void __user *) guestdest, from, n); | ||
187 | slowpath: | ||
188 | return __copy_to_guest_slow(vcpu, guestdest, from, n); | ||
189 | } | ||
190 | |||
191 | static inline int __copy_from_guest_slow(struct kvm_vcpu *vcpu, void *to, | ||
192 | u64 guestsrc, unsigned long n) | ||
193 | { | ||
194 | int rc; | ||
195 | unsigned long i; | ||
196 | u8 *data = to; | ||
197 | |||
198 | for (i = 0; i < n; i++) { | ||
199 | rc = get_guest_u8(vcpu, guestsrc++, data++); | ||
200 | if (rc < 0) | ||
201 | return rc; | ||
202 | } | ||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | static inline int copy_from_guest(struct kvm_vcpu *vcpu, void *to, | ||
207 | u64 guestsrc, unsigned long n) | ||
208 | { | ||
209 | u64 prefix = vcpu->arch.sie_block->prefix; | ||
210 | u64 origin = vcpu->kvm->arch.guest_origin; | ||
211 | u64 memsize = vcpu->kvm->arch.guest_memsize; | ||
212 | |||
213 | if ((guestsrc < 2 * PAGE_SIZE) && (guestsrc + n > 2 * PAGE_SIZE)) | ||
214 | goto slowpath; | ||
215 | |||
216 | if ((guestsrc < prefix) && (guestsrc + n > prefix)) | ||
217 | goto slowpath; | ||
218 | |||
219 | if ((guestsrc < prefix + 2 * PAGE_SIZE) | ||
220 | && (guestsrc + n > prefix + 2 * PAGE_SIZE)) | ||
221 | goto slowpath; | ||
222 | |||
223 | if (guestsrc < 2 * PAGE_SIZE) | ||
224 | guestsrc += prefix; | ||
225 | else if ((guestsrc >= prefix) && (guestsrc < prefix + 2 * PAGE_SIZE)) | ||
226 | guestsrc -= prefix; | ||
227 | |||
228 | if (guestsrc + n > memsize) | ||
229 | return -EFAULT; | ||
230 | |||
231 | if (guestsrc + n < guestsrc) | ||
232 | return -EFAULT; | ||
233 | |||
234 | guestsrc += origin; | ||
235 | |||
236 | return copy_from_user(to, (void __user *) guestsrc, n); | ||
237 | slowpath: | ||
238 | return __copy_from_guest_slow(vcpu, to, guestsrc, n); | ||
239 | } | ||
240 | |||
241 | static inline int copy_to_guest_absolute(struct kvm_vcpu *vcpu, u64 guestdest, | ||
242 | const void *from, unsigned long n) | ||
243 | { | ||
244 | u64 origin = vcpu->kvm->arch.guest_origin; | ||
245 | u64 memsize = vcpu->kvm->arch.guest_memsize; | ||
246 | |||
247 | if (guestdest + n > memsize) | ||
248 | return -EFAULT; | ||
249 | |||
250 | if (guestdest + n < guestdest) | ||
251 | return -EFAULT; | ||
252 | |||
253 | guestdest += origin; | ||
254 | |||
255 | return copy_to_user((void __user *) guestdest, from, n); | ||
256 | } | ||
257 | |||
258 | static inline int copy_from_guest_absolute(struct kvm_vcpu *vcpu, void *to, | ||
259 | u64 guestsrc, unsigned long n) | ||
260 | { | ||
261 | u64 origin = vcpu->kvm->arch.guest_origin; | ||
262 | u64 memsize = vcpu->kvm->arch.guest_memsize; | ||
263 | |||
264 | if (guestsrc + n > memsize) | ||
265 | return -EFAULT; | ||
266 | |||
267 | if (guestsrc + n < guestsrc) | ||
268 | return -EFAULT; | ||
269 | |||
270 | guestsrc += origin; | ||
271 | |||
272 | return copy_from_user(to, (void __user *) guestsrc, n); | ||
273 | } | ||
274 | #endif | ||