Merge branch 'for-linus' of git://git.open-osd.org/linux-open-osd
[sfrench/cifs-2.6.git] / arch / s390 / kvm / gaccess.h
1 /*
2  * 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 /* Convert real to absolute address by applying the prefix of the CPU */
22 static inline unsigned long kvm_s390_real_to_abs(struct kvm_vcpu *vcpu,
23                                                  unsigned long gaddr)
24 {
25         unsigned long prefix  = vcpu->arch.sie_block->prefix;
26         if (gaddr < 2 * PAGE_SIZE)
27                 gaddr += prefix;
28         else if (gaddr >= prefix && gaddr < prefix + 2 * PAGE_SIZE)
29                 gaddr -= prefix;
30         return gaddr;
31 }
32
33 static inline void __user *__gptr_to_uptr(struct kvm_vcpu *vcpu,
34                                           void __user *gptr,
35                                           int prefixing)
36 {
37         unsigned long gaddr = (unsigned long) gptr;
38         unsigned long uaddr;
39
40         if (prefixing)
41                 gaddr = kvm_s390_real_to_abs(vcpu, gaddr);
42         uaddr = gmap_fault(gaddr, vcpu->arch.gmap);
43         if (IS_ERR_VALUE(uaddr))
44                 uaddr = -EFAULT;
45         return (void __user *)uaddr;
46 }
47
48 #define get_guest(vcpu, x, gptr)                                \
49 ({                                                              \
50         __typeof__(gptr) __uptr = __gptr_to_uptr(vcpu, gptr, 1);\
51         int __mask = sizeof(__typeof__(*(gptr))) - 1;           \
52         int __ret;                                              \
53                                                                 \
54         if (IS_ERR((void __force *)__uptr)) {                   \
55                 __ret = PTR_ERR((void __force *)__uptr);        \
56         } else {                                                \
57                 BUG_ON((unsigned long)__uptr & __mask);         \
58                 __ret = get_user(x, __uptr);                    \
59         }                                                       \
60         __ret;                                                  \
61 })
62
63 #define put_guest(vcpu, x, gptr)                                \
64 ({                                                              \
65         __typeof__(gptr) __uptr = __gptr_to_uptr(vcpu, gptr, 1);\
66         int __mask = sizeof(__typeof__(*(gptr))) - 1;           \
67         int __ret;                                              \
68                                                                 \
69         if (IS_ERR((void __force *)__uptr)) {                   \
70                 __ret = PTR_ERR((void __force *)__uptr);        \
71         } else {                                                \
72                 BUG_ON((unsigned long)__uptr & __mask);         \
73                 __ret = put_user(x, __uptr);                    \
74         }                                                       \
75         __ret;                                                  \
76 })
77
78 static inline int __copy_guest(struct kvm_vcpu *vcpu, unsigned long to,
79                                unsigned long from, unsigned long len,
80                                int to_guest, int prefixing)
81 {
82         unsigned long _len, rc;
83         void __user *uptr;
84
85         while (len) {
86                 uptr = to_guest ? (void __user *)to : (void __user *)from;
87                 uptr = __gptr_to_uptr(vcpu, uptr, prefixing);
88                 if (IS_ERR((void __force *)uptr))
89                         return -EFAULT;
90                 _len = PAGE_SIZE - ((unsigned long)uptr & (PAGE_SIZE - 1));
91                 _len = min(_len, len);
92                 if (to_guest)
93                         rc = copy_to_user((void __user *) uptr, (void *)from, _len);
94                 else
95                         rc = copy_from_user((void *)to, (void __user *)uptr, _len);
96                 if (rc)
97                         return -EFAULT;
98                 len -= _len;
99                 from += _len;
100                 to += _len;
101         }
102         return 0;
103 }
104
105 #define copy_to_guest(vcpu, to, from, size) \
106         __copy_guest(vcpu, to, (unsigned long)from, size, 1, 1)
107 #define copy_from_guest(vcpu, to, from, size) \
108         __copy_guest(vcpu, (unsigned long)to, from, size, 0, 1)
109 #define copy_to_guest_absolute(vcpu, to, from, size) \
110         __copy_guest(vcpu, to, (unsigned long)from, size, 1, 0)
111 #define copy_from_guest_absolute(vcpu, to, from, size) \
112         __copy_guest(vcpu, (unsigned long)to, from, size, 0, 0)
113
114 #endif /* __KVM_S390_GACCESS_H */