blob: 302e0e52b0097e7f21a30bfb3fd9a1866e8c4274 [file] [log] [blame]
Heiko Carstensb0c632d2008-03-25 18:47:20 +01001/*
Heiko Carstensa53c8fa2012-07-20 11:15:04 +02002 * access guest memory
Heiko Carstensb0c632d2008-03-25 18:47:20 +01003 *
Heiko Carstensa53c8fa2012-07-20 11:15:04 +02004 * Copyright IBM Corp. 2008, 2009
Heiko Carstensb0c632d2008-03-25 18:47:20 +01005 *
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>
Christian Ehrhardt628eb9b2009-05-25 13:40:51 +020019#include "kvm-s390.h"
Heiko Carstensb0c632d2008-03-25 18:47:20 +010020
Heiko Carstens0a75ca22013-03-05 13:14:47 +010021static inline void __user *__gptr_to_uptr(struct kvm_vcpu *vcpu,
22 void __user *gptr,
23 int prefixing)
Heiko Carstensb0c632d2008-03-25 18:47:20 +010024{
Martin Schwidefsky00963692008-07-25 15:51:00 +020025 unsigned long prefix = vcpu->arch.sie_block->prefix;
Heiko Carstens396083a2013-03-05 13:14:44 +010026 unsigned long gaddr = (unsigned long) gptr;
27 unsigned long uaddr;
Heiko Carstensb0c632d2008-03-25 18:47:20 +010028
Heiko Carstensf9dc72e2013-03-05 13:14:45 +010029 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 }
Heiko Carstens396083a2013-03-05 13:14:44 +010035 uaddr = gmap_fault(gaddr, vcpu->arch.gmap);
36 if (IS_ERR_VALUE(uaddr))
37 uaddr = -EFAULT;
Heiko Carstens0a75ca22013-03-05 13:14:47 +010038 return (void __user *)uaddr;
Heiko Carstensb0c632d2008-03-25 18:47:20 +010039}
40
Heiko Carstens396083a2013-03-05 13:14:44 +010041#define get_guest(vcpu, x, gptr) \
42({ \
Heiko Carstensf9dc72e2013-03-05 13:14:45 +010043 __typeof__(gptr) __uptr = __gptr_to_uptr(vcpu, gptr, 1);\
Heiko Carstens396083a2013-03-05 13:14:44 +010044 int __mask = sizeof(__typeof__(*(gptr))) - 1; \
Heiko Carstens0a75ca22013-03-05 13:14:47 +010045 int __ret = PTR_RET((void __force *)__uptr); \
Heiko Carstens396083a2013-03-05 13:14:44 +010046 \
47 if (!__ret) { \
48 BUG_ON((unsigned long)__uptr & __mask); \
49 __ret = get_user(x, __uptr); \
50 } \
51 __ret; \
52})
Heiko Carstensb0c632d2008-03-25 18:47:20 +010053
Heiko Carstens396083a2013-03-05 13:14:44 +010054#define put_guest(vcpu, x, gptr) \
55({ \
Heiko Carstensf9dc72e2013-03-05 13:14:45 +010056 __typeof__(gptr) __uptr = __gptr_to_uptr(vcpu, gptr, 1);\
Heiko Carstens396083a2013-03-05 13:14:44 +010057 int __mask = sizeof(__typeof__(*(gptr))) - 1; \
Heiko Carstens0a75ca22013-03-05 13:14:47 +010058 int __ret = PTR_RET((void __force *)__uptr); \
Heiko Carstens396083a2013-03-05 13:14:44 +010059 \
60 if (!__ret) { \
61 BUG_ON((unsigned long)__uptr & __mask); \
62 __ret = put_user(x, __uptr); \
63 } \
64 __ret; \
65})
Heiko Carstensb0c632d2008-03-25 18:47:20 +010066
Heiko Carstensf9dc72e2013-03-05 13:14:45 +010067static inline int __copy_guest(struct kvm_vcpu *vcpu, unsigned long to,
68 unsigned long from, unsigned long len,
69 int to_guest, int prefixing)
Heiko Carstensb0c632d2008-03-25 18:47:20 +010070{
Heiko Carstensf9dc72e2013-03-05 13:14:45 +010071 unsigned long _len, rc;
Heiko Carstens0a75ca22013-03-05 13:14:47 +010072 void __user *uptr;
Heiko Carstensb0c632d2008-03-25 18:47:20 +010073
Heiko Carstensf9dc72e2013-03-05 13:14:45 +010074 while (len) {
Heiko Carstens0a75ca22013-03-05 13:14:47 +010075 uptr = to_guest ? (void __user *)to : (void __user *)from;
Heiko Carstensf9dc72e2013-03-05 13:14:45 +010076 uptr = __gptr_to_uptr(vcpu, uptr, prefixing);
Heiko Carstens0a75ca22013-03-05 13:14:47 +010077 if (IS_ERR((void __force *)uptr))
Heiko Carstensf9dc72e2013-03-05 13:14:45 +010078 return -EFAULT;
79 _len = PAGE_SIZE - ((unsigned long)uptr & (PAGE_SIZE - 1));
80 _len = min(_len, len);
81 if (to_guest)
Heiko Carstens0a75ca22013-03-05 13:14:47 +010082 rc = copy_to_user((void __user *) uptr, (void *)from, _len);
Heiko Carstensf9dc72e2013-03-05 13:14:45 +010083 else
Heiko Carstens0a75ca22013-03-05 13:14:47 +010084 rc = copy_from_user((void *)to, (void __user *)uptr, _len);
Heiko Carstensf9dc72e2013-03-05 13:14:45 +010085 if (rc)
86 return -EFAULT;
87 len -= _len;
88 from += _len;
89 to += _len;
Heiko Carstensb0c632d2008-03-25 18:47:20 +010090 }
91 return 0;
92}
93
Heiko Carstensf9dc72e2013-03-05 13:14:45 +010094#define copy_to_guest(vcpu, to, from, size) \
95 __copy_guest(vcpu, to, (unsigned long)from, size, 1, 1)
96#define copy_from_guest(vcpu, to, from, size) \
97 __copy_guest(vcpu, (unsigned long)to, from, size, 0, 1)
98#define copy_to_guest_absolute(vcpu, to, from, size) \
99 __copy_guest(vcpu, to, (unsigned long)from, size, 1, 0)
100#define copy_from_guest_absolute(vcpu, to, from, size) \
101 __copy_guest(vcpu, (unsigned long)to, from, size, 0, 0)
Carsten Otte092670c2011-07-24 10:48:22 +0200102
Heiko Carstensf9dc72e2013-03-05 13:14:45 +0100103#endif /* __KVM_S390_GACCESS_H */