xref: /openbmc/linux/arch/s390/kvm/gaccess.h (revision 930beb5a)
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 */
115