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