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