2008-03-25 18:47:20 +01:00
/*
2012-07-20 11:15:04 +02:00
* access guest memory
2008-03-25 18:47:20 +01:00
*
2012-07-20 11:15:04 +02:00
* Copyright IBM Corp . 2008 , 2009
2008-03-25 18:47:20 +01:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License ( version 2 only )
* as published by the Free Software Foundation .
*
* Author ( s ) : Carsten Otte < cotte @ de . ibm . com >
*/
# ifndef __KVM_S390_GACCESS_H
# define __KVM_S390_GACCESS_H
# include <linux/compiler.h>
# include <linux/kvm_host.h>
# include <asm/uaccess.h>
2009-05-25 13:40:51 +02:00
# include "kvm-s390.h"
2008-03-25 18:47:20 +01:00
2013-03-05 13:14:47 +01:00
static inline void __user * __gptr_to_uptr ( struct kvm_vcpu * vcpu ,
void __user * gptr ,
int prefixing )
2008-03-25 18:47:20 +01:00
{
2008-07-25 15:51:00 +02:00
unsigned long prefix = vcpu - > arch . sie_block - > prefix ;
2013-03-05 13:14:44 +01:00
unsigned long gaddr = ( unsigned long ) gptr ;
unsigned long uaddr ;
2013-03-05 13:14:45 +01:00
if ( prefixing ) {
if ( gaddr < 2 * PAGE_SIZE )
gaddr + = prefix ;
else if ( ( gaddr > = prefix ) & & ( gaddr < prefix + 2 * PAGE_SIZE ) )
gaddr - = prefix ;
}
2013-03-05 13:14:44 +01:00
uaddr = gmap_fault ( gaddr , vcpu - > arch . gmap ) ;
if ( IS_ERR_VALUE ( uaddr ) )
uaddr = - EFAULT ;
2013-03-05 13:14:47 +01:00
return ( void __user * ) uaddr ;
2008-03-25 18:47:20 +01:00
}
2013-03-05 13:14:44 +01:00
# define get_guest(vcpu, x, gptr) \
( { \
2013-03-05 13:14:45 +01:00
__typeof__ ( gptr ) __uptr = __gptr_to_uptr ( vcpu , gptr , 1 ) ; \
2013-03-05 13:14:44 +01:00
int __mask = sizeof ( __typeof__ ( * ( gptr ) ) ) - 1 ; \
2013-03-05 13:14:47 +01:00
int __ret = PTR_RET ( ( void __force * ) __uptr ) ; \
2013-03-05 13:14:44 +01:00
\
if ( ! __ret ) { \
BUG_ON ( ( unsigned long ) __uptr & __mask ) ; \
__ret = get_user ( x , __uptr ) ; \
} \
__ret ; \
} )
# define put_guest(vcpu, x, gptr) \
( { \
2013-03-05 13:14:45 +01:00
__typeof__ ( gptr ) __uptr = __gptr_to_uptr ( vcpu , gptr , 1 ) ; \
2013-03-05 13:14:44 +01:00
int __mask = sizeof ( __typeof__ ( * ( gptr ) ) ) - 1 ; \
2013-03-05 13:14:47 +01:00
int __ret = PTR_RET ( ( void __force * ) __uptr ) ; \
2013-03-05 13:14:44 +01:00
\
if ( ! __ret ) { \
BUG_ON ( ( unsigned long ) __uptr & __mask ) ; \
__ret = put_user ( x , __uptr ) ; \
} \
__ret ; \
} )
2008-03-25 18:47:20 +01:00
2013-03-05 13:14:45 +01:00
static inline int __copy_guest ( struct kvm_vcpu * vcpu , unsigned long to ,
unsigned long from , unsigned long len ,
int to_guest , int prefixing )
2008-03-25 18:47:20 +01:00
{
2013-03-05 13:14:45 +01:00
unsigned long _len , rc ;
2013-03-05 13:14:47 +01:00
void __user * uptr ;
2013-03-05 13:14:45 +01:00
while ( len ) {
2013-03-05 13:14:47 +01:00
uptr = to_guest ? ( void __user * ) to : ( void __user * ) from ;
2013-03-05 13:14:45 +01:00
uptr = __gptr_to_uptr ( vcpu , uptr , prefixing ) ;
2013-03-05 13:14:47 +01:00
if ( IS_ERR ( ( void __force * ) uptr ) )
2013-03-05 13:14:45 +01:00
return - EFAULT ;
_len = PAGE_SIZE - ( ( unsigned long ) uptr & ( PAGE_SIZE - 1 ) ) ;
_len = min ( _len , len ) ;
if ( to_guest )
2013-03-05 13:14:47 +01:00
rc = copy_to_user ( ( void __user * ) uptr , ( void * ) from , _len ) ;
2013-03-05 13:14:45 +01:00
else
2013-03-05 13:14:47 +01:00
rc = copy_from_user ( ( void * ) to , ( void __user * ) uptr , _len ) ;
2013-03-05 13:14:45 +01:00
if ( rc )
return - EFAULT ;
len - = _len ;
from + = _len ;
to + = _len ;
2008-03-25 18:47:20 +01:00
}
return 0 ;
}
2013-03-05 13:14:45 +01:00
# define copy_to_guest(vcpu, to, from, size) \
__copy_guest ( vcpu , to , ( unsigned long ) from , size , 1 , 1 )
# define copy_from_guest(vcpu, to, from, size) \
__copy_guest ( vcpu , ( unsigned long ) to , from , size , 0 , 1 )
# define copy_to_guest_absolute(vcpu, to, from, size) \
__copy_guest ( vcpu , to , ( unsigned long ) from , size , 1 , 0 )
# define copy_from_guest_absolute(vcpu, to, from, size) \
__copy_guest ( vcpu , ( unsigned long ) to , from , size , 0 , 0 )
2011-07-24 10:48:22 +02:00
2013-03-05 13:14:45 +01:00
# endif /* __KVM_S390_GACCESS_H */