2012-12-10 16:15:34 +00:00
/*
* Copyright ( C ) 2012 , 2013 - ARM Ltd
* Author : Marc Zyngier < marc . zyngier @ arm . com >
*
* Derived from arch / arm / kvm / coproc . h
* Copyright ( C ) 2012 - Virtual Open Systems and Columbia University
* Authors : Christoffer Dall < c . dall @ virtualopensystems . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License , version 2 , as
* published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# ifndef __ARM64_KVM_SYS_REGS_LOCAL_H__
# define __ARM64_KVM_SYS_REGS_LOCAL_H__
struct sys_reg_params {
u8 Op0 ;
u8 Op1 ;
u8 CRn ;
u8 CRm ;
u8 Op2 ;
2015-12-04 15:03:13 +03:00
u64 regval ;
2012-12-10 16:15:34 +00:00
bool is_write ;
2014-01-21 10:55:17 +00:00
bool is_aarch32 ;
bool is_32bit ; /* Only valid if is_aarch32 is true */
2012-12-10 16:15:34 +00:00
} ;
struct sys_reg_desc {
2018-12-04 10:44:22 +00:00
/* Sysreg string for debug */
const char * name ;
2012-12-10 16:15:34 +00:00
/* MRS/MSR instruction which accesses it. */
u8 Op0 ;
u8 Op1 ;
u8 CRn ;
u8 CRm ;
u8 Op2 ;
/* Trapped access from guest, if non-NULL. */
bool ( * access ) ( struct kvm_vcpu * ,
2015-12-04 15:03:12 +03:00
struct sys_reg_params * ,
2012-12-10 16:15:34 +00:00
const struct sys_reg_desc * ) ;
/* Initialization for vcpu. */
void ( * reset ) ( struct kvm_vcpu * , const struct sys_reg_desc * ) ;
/* Index into sys_reg[], or 0 if we don't need to save it. */
int reg ;
/* Value (usually reset value) */
u64 val ;
2015-07-07 17:30:00 +01:00
/* Custom get/set_user functions, fallback to generic if NULL */
int ( * get_user ) ( struct kvm_vcpu * vcpu , const struct sys_reg_desc * rd ,
const struct kvm_one_reg * reg , void __user * uaddr ) ;
int ( * set_user ) ( struct kvm_vcpu * vcpu , const struct sys_reg_desc * rd ,
const struct kvm_one_reg * reg , void __user * uaddr ) ;
2018-09-28 14:39:15 +01:00
/* Return mask of REG_* runtime visibility overrides */
unsigned int ( * visibility ) ( const struct kvm_vcpu * vcpu ,
const struct sys_reg_desc * rd ) ;
2012-12-10 16:15:34 +00:00
} ;
2018-09-28 14:39:15 +01:00
# define REG_HIDDEN_USER (1 << 0) /* hidden from userspace ioctls */
# define REG_HIDDEN_GUEST (1 << 1) /* hidden from guest */
2012-12-10 16:15:34 +00:00
static inline void print_sys_reg_instr ( const struct sys_reg_params * p )
{
/* Look, we even formatted it for you to paste into the table! */
kvm_pr_unimpl ( " { Op0(%2u), Op1(%2u), CRn(%2u), CRm(%2u), Op2(%2u), func_%s }, \n " ,
p - > Op0 , p - > Op1 , p - > CRn , p - > CRm , p - > Op2 , p - > is_write ? " write " : " read " ) ;
}
static inline bool ignore_write ( struct kvm_vcpu * vcpu ,
const struct sys_reg_params * p )
{
return true ;
}
static inline bool read_zero ( struct kvm_vcpu * vcpu ,
2015-12-04 15:03:12 +03:00
struct sys_reg_params * p )
2012-12-10 16:15:34 +00:00
{
2015-12-04 15:03:13 +03:00
p - > regval = 0 ;
2012-12-10 16:15:34 +00:00
return true ;
}
/* Reset functions */
static inline void reset_unknown ( struct kvm_vcpu * vcpu ,
const struct sys_reg_desc * r )
{
BUG_ON ( ! r - > reg ) ;
BUG_ON ( r - > reg > = NR_SYS_REGS ) ;
2016-03-16 15:38:53 +01:00
__vcpu_sys_reg ( vcpu , r - > reg ) = 0x1de7ec7edbadc0deULL ;
2012-12-10 16:15:34 +00:00
}
static inline void reset_val ( struct kvm_vcpu * vcpu , const struct sys_reg_desc * r )
{
BUG_ON ( ! r - > reg ) ;
BUG_ON ( r - > reg > = NR_SYS_REGS ) ;
2016-03-16 15:38:53 +01:00
__vcpu_sys_reg ( vcpu , r - > reg ) = r - > val ;
2012-12-10 16:15:34 +00:00
}
2018-09-28 14:39:15 +01:00
static inline bool sysreg_hidden_from_guest ( const struct kvm_vcpu * vcpu ,
const struct sys_reg_desc * r )
{
if ( likely ( ! r - > visibility ) )
return false ;
return r - > visibility ( vcpu , r ) & REG_HIDDEN_GUEST ;
}
static inline bool sysreg_hidden_from_user ( const struct kvm_vcpu * vcpu ,
const struct sys_reg_desc * r )
{
if ( likely ( ! r - > visibility ) )
return false ;
return r - > visibility ( vcpu , r ) & REG_HIDDEN_USER ;
}
2012-12-10 16:15:34 +00:00
static inline int cmp_sys_reg ( const struct sys_reg_desc * i1 ,
const struct sys_reg_desc * i2 )
{
BUG_ON ( i1 = = i2 ) ;
if ( ! i1 )
return 1 ;
else if ( ! i2 )
return - 1 ;
if ( i1 - > Op0 ! = i2 - > Op0 )
return i1 - > Op0 - i2 - > Op0 ;
if ( i1 - > Op1 ! = i2 - > Op1 )
return i1 - > Op1 - i2 - > Op1 ;
if ( i1 - > CRn ! = i2 - > CRn )
return i1 - > CRn - i2 - > CRn ;
if ( i1 - > CRm ! = i2 - > CRm )
return i1 - > CRm - i2 - > CRm ;
return i1 - > Op2 - i2 - > Op2 ;
}
2017-01-26 19:50:48 +05:30
const struct sys_reg_desc * find_reg_by_id ( u64 id ,
struct sys_reg_params * params ,
const struct sys_reg_desc table [ ] ,
unsigned int num ) ;
2012-12-10 16:15:34 +00:00
# define Op0(_x) .Op0 = _x
# define Op1(_x) .Op1 = _x
# define CRn(_x) .CRn = _x
# define CRm(_x) .CRm = _x
# define Op2(_x) .Op2 = _x
2017-01-13 17:25:11 +00:00
# define SYS_DESC(reg) \
2018-12-04 10:44:22 +00:00
. name = # reg , \
2017-01-13 17:25:11 +00:00
Op0 ( sys_reg_Op0 ( reg ) ) , Op1 ( sys_reg_Op1 ( reg ) ) , \
CRn ( sys_reg_CRn ( reg ) ) , CRm ( sys_reg_CRm ( reg ) ) , \
Op2 ( sys_reg_Op2 ( reg ) )
2012-12-10 16:15:34 +00:00
# endif /* __ARM64_KVM_SYS_REGS_LOCAL_H__ */