2 * gaccess.h - access guest memory
4 * Copyright IBM Corp. 2008,2009
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.
10 * Author(s): Carsten Otte <cotte@de.ibm.com>
13 #ifndef __KVM_S390_GACCESS_H
14 #define __KVM_S390_GACCESS_H
16 #include <linux/compiler.h>
17 #include <linux/kvm_host.h>
18 #include <asm/uaccess.h>
21 static inline void __user *__guestaddr_to_user(struct kvm_vcpu *vcpu,
22 unsigned long guestaddr)
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);
28 if (guestaddr < 2 * PAGE_SIZE)
30 else if ((guestaddr >= prefix) && (guestaddr < prefix + 2 * PAGE_SIZE))
33 if (guestaddr > memsize)
34 return (void __user __force *) ERR_PTR(-EFAULT);
38 return (void __user *) guestaddr;
41 static inline int get_guest_u64(struct kvm_vcpu *vcpu, unsigned long guestaddr,
44 void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
46 BUG_ON(guestaddr & 7);
48 if (IS_ERR((void __force *) uptr))
49 return PTR_ERR((void __force *) uptr);
51 return get_user(*result, (unsigned long __user *) uptr);
54 static inline int get_guest_u32(struct kvm_vcpu *vcpu, unsigned long guestaddr,
57 void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
59 BUG_ON(guestaddr & 3);
61 if (IS_ERR((void __force *) uptr))
62 return PTR_ERR((void __force *) uptr);
64 return get_user(*result, (u32 __user *) uptr);
67 static inline int get_guest_u16(struct kvm_vcpu *vcpu, unsigned long guestaddr,
70 void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
72 BUG_ON(guestaddr & 1);
77 return get_user(*result, (u16 __user *) uptr);
80 static inline int get_guest_u8(struct kvm_vcpu *vcpu, unsigned long guestaddr,
83 void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
85 if (IS_ERR((void __force *) uptr))
86 return PTR_ERR((void __force *) uptr);
88 return get_user(*result, (u8 __user *) uptr);
91 static inline int put_guest_u64(struct kvm_vcpu *vcpu, unsigned long guestaddr,
94 void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
96 BUG_ON(guestaddr & 7);
98 if (IS_ERR((void __force *) uptr))
99 return PTR_ERR((void __force *) uptr);
101 return put_user(value, (u64 __user *) uptr);
104 static inline int put_guest_u32(struct kvm_vcpu *vcpu, unsigned long guestaddr,
107 void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
109 BUG_ON(guestaddr & 3);
111 if (IS_ERR((void __force *) uptr))
112 return PTR_ERR((void __force *) uptr);
114 return put_user(value, (u32 __user *) uptr);
117 static inline int put_guest_u16(struct kvm_vcpu *vcpu, unsigned long guestaddr,
120 void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
122 BUG_ON(guestaddr & 1);
124 if (IS_ERR((void __force *) uptr))
125 return PTR_ERR((void __force *) uptr);
127 return put_user(value, (u16 __user *) uptr);
130 static inline int put_guest_u8(struct kvm_vcpu *vcpu, unsigned long guestaddr,
133 void __user *uptr = __guestaddr_to_user(vcpu, guestaddr);
135 if (IS_ERR((void __force *) uptr))
136 return PTR_ERR((void __force *) uptr);
138 return put_user(value, (u8 __user *) uptr);
142 static inline int __copy_to_guest_slow(struct kvm_vcpu *vcpu,
143 unsigned long guestdest,
144 const void *from, unsigned long n)
148 const u8 *data = from;
150 for (i = 0; i < n; i++) {
151 rc = put_guest_u8(vcpu, guestdest++, *(data++));
158 static inline int copy_to_guest(struct kvm_vcpu *vcpu, unsigned long guestdest,
159 const void *from, unsigned long n)
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);
165 if ((guestdest < 2 * PAGE_SIZE) && (guestdest + n > 2 * PAGE_SIZE))
168 if ((guestdest < prefix) && (guestdest + n > prefix))
171 if ((guestdest < prefix + 2 * PAGE_SIZE)
172 && (guestdest + n > prefix + 2 * PAGE_SIZE))
175 if (guestdest < 2 * PAGE_SIZE)
177 else if ((guestdest >= prefix) && (guestdest < prefix + 2 * PAGE_SIZE))
180 if (guestdest + n > memsize)
183 if (guestdest + n < guestdest)
188 return copy_to_user((void __user *) guestdest, from, n);
190 return __copy_to_guest_slow(vcpu, guestdest, from, n);
193 static inline int __copy_from_guest_slow(struct kvm_vcpu *vcpu, void *to,
194 unsigned long guestsrc,
201 for (i = 0; i < n; i++) {
202 rc = get_guest_u8(vcpu, guestsrc++, data++);
209 static inline int copy_from_guest(struct kvm_vcpu *vcpu, void *to,
210 unsigned long guestsrc, unsigned long n)
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);
216 if ((guestsrc < 2 * PAGE_SIZE) && (guestsrc + n > 2 * PAGE_SIZE))
219 if ((guestsrc < prefix) && (guestsrc + n > prefix))
222 if ((guestsrc < prefix + 2 * PAGE_SIZE)
223 && (guestsrc + n > prefix + 2 * PAGE_SIZE))
226 if (guestsrc < 2 * PAGE_SIZE)
228 else if ((guestsrc >= prefix) && (guestsrc < prefix + 2 * PAGE_SIZE))
231 if (guestsrc + n > memsize)
234 if (guestsrc + n < guestsrc)
239 return copy_from_user(to, (void __user *) guestsrc, n);
241 return __copy_from_guest_slow(vcpu, to, guestsrc, n);
244 static inline int copy_to_guest_absolute(struct kvm_vcpu *vcpu,
245 unsigned long guestdest,
246 const void *from, unsigned long n)
248 unsigned long origin = vcpu->arch.sie_block->gmsor;
249 unsigned long memsize = kvm_s390_vcpu_get_memsize(vcpu);
251 if (guestdest + n > memsize)
254 if (guestdest + n < guestdest)
259 return copy_to_user((void __user *) guestdest, from, n);
262 static inline int copy_from_guest_absolute(struct kvm_vcpu *vcpu, void *to,
263 unsigned long guestsrc,
266 unsigned long origin = vcpu->arch.sie_block->gmsor;
267 unsigned long memsize = kvm_s390_vcpu_get_memsize(vcpu);
269 if (guestsrc + n > memsize)
272 if (guestsrc + n < guestsrc)
277 return copy_from_user(to, (void __user *) guestsrc, n);