xref: /openbmc/linux/arch/arm64/kvm/sys_regs.h (revision 47334146)
1caab277bSThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-only */
27c8c5e6aSMarc Zyngier /*
37c8c5e6aSMarc Zyngier  * Copyright (C) 2012,2013 - ARM Ltd
47c8c5e6aSMarc Zyngier  * Author: Marc Zyngier <marc.zyngier@arm.com>
57c8c5e6aSMarc Zyngier  *
67c8c5e6aSMarc Zyngier  * Derived from arch/arm/kvm/coproc.h
77c8c5e6aSMarc Zyngier  * Copyright (C) 2012 - Virtual Open Systems and Columbia University
87c8c5e6aSMarc Zyngier  * Authors: Christoffer Dall <c.dall@virtualopensystems.com>
97c8c5e6aSMarc Zyngier  */
107c8c5e6aSMarc Zyngier 
117c8c5e6aSMarc Zyngier #ifndef __ARM64_KVM_SYS_REGS_LOCAL_H__
127c8c5e6aSMarc Zyngier #define __ARM64_KVM_SYS_REGS_LOCAL_H__
137c8c5e6aSMarc Zyngier 
14f76f89e2SFuad Tabba #include <linux/bsearch.h>
15f76f89e2SFuad Tabba 
16f76f89e2SFuad Tabba #define reg_to_encoding(x)						\
17f76f89e2SFuad Tabba 	sys_reg((u32)(x)->Op0, (u32)(x)->Op1,				\
18f76f89e2SFuad Tabba 		(u32)(x)->CRn, (u32)(x)->CRm, (u32)(x)->Op2)
19f76f89e2SFuad Tabba 
207c8c5e6aSMarc Zyngier struct sys_reg_params {
217c8c5e6aSMarc Zyngier 	u8	Op0;
227c8c5e6aSMarc Zyngier 	u8	Op1;
237c8c5e6aSMarc Zyngier 	u8	CRn;
247c8c5e6aSMarc Zyngier 	u8	CRm;
257c8c5e6aSMarc Zyngier 	u8	Op2;
262ec5be3dSPavel Fedin 	u64	regval;
277c8c5e6aSMarc Zyngier 	bool	is_write;
287c8c5e6aSMarc Zyngier };
297c8c5e6aSMarc Zyngier 
30*47334146SJing Zhang #define encoding_to_params(reg)						\
31*47334146SJing Zhang 	((struct sys_reg_params){ .Op0 = sys_reg_Op0(reg),		\
32*47334146SJing Zhang 				  .Op1 = sys_reg_Op1(reg),		\
33*47334146SJing Zhang 				  .CRn = sys_reg_CRn(reg),		\
34*47334146SJing Zhang 				  .CRm = sys_reg_CRm(reg),		\
35*47334146SJing Zhang 				  .Op2 = sys_reg_Op2(reg) })
36*47334146SJing Zhang 
37f76f89e2SFuad Tabba #define esr_sys64_to_params(esr)                                               \
38f76f89e2SFuad Tabba 	((struct sys_reg_params){ .Op0 = ((esr) >> 20) & 3,                    \
39f76f89e2SFuad Tabba 				  .Op1 = ((esr) >> 14) & 0x7,                  \
40f76f89e2SFuad Tabba 				  .CRn = ((esr) >> 10) & 0xf,                  \
41f76f89e2SFuad Tabba 				  .CRm = ((esr) >> 1) & 0xf,                   \
42f76f89e2SFuad Tabba 				  .Op2 = ((esr) >> 17) & 0x7,                  \
43f76f89e2SFuad Tabba 				  .is_write = !((esr) & 1) })
44f76f89e2SFuad Tabba 
45e6519766SOliver Upton #define esr_cp1x_32_to_params(esr)						\
46e6519766SOliver Upton 	((struct sys_reg_params){ .Op1 = ((esr) >> 14) & 0x7,			\
47e6519766SOliver Upton 				  .CRn = ((esr) >> 10) & 0xf,			\
48e6519766SOliver Upton 				  .CRm = ((esr) >> 1) & 0xf,			\
49e6519766SOliver Upton 				  .Op2 = ((esr) >> 17) & 0x7,			\
50e6519766SOliver Upton 				  .is_write = !((esr) & 1) })
51e6519766SOliver Upton 
527c8c5e6aSMarc Zyngier struct sys_reg_desc {
53599d79dcSMarc Zyngier 	/* Sysreg string for debug */
54599d79dcSMarc Zyngier 	const char *name;
55599d79dcSMarc Zyngier 
566ed6750fSMarc Zyngier 	enum {
57a9e192cdSAlexandru Elisei 		AA32_DIRECT,
586ed6750fSMarc Zyngier 		AA32_LO,
596ed6750fSMarc Zyngier 		AA32_HI,
606ed6750fSMarc Zyngier 	} aarch32_map;
616ed6750fSMarc Zyngier 
627c8c5e6aSMarc Zyngier 	/* MRS/MSR instruction which accesses it. */
637c8c5e6aSMarc Zyngier 	u8	Op0;
647c8c5e6aSMarc Zyngier 	u8	Op1;
657c8c5e6aSMarc Zyngier 	u8	CRn;
667c8c5e6aSMarc Zyngier 	u8	CRm;
677c8c5e6aSMarc Zyngier 	u8	Op2;
687c8c5e6aSMarc Zyngier 
697c8c5e6aSMarc Zyngier 	/* Trapped access from guest, if non-NULL. */
707c8c5e6aSMarc Zyngier 	bool (*access)(struct kvm_vcpu *,
713fec037dSPavel Fedin 		       struct sys_reg_params *,
727c8c5e6aSMarc Zyngier 		       const struct sys_reg_desc *);
737c8c5e6aSMarc Zyngier 
74d86cde6eSJing Zhang 	/*
75d86cde6eSJing Zhang 	 * Initialization for vcpu. Return initialized value, or KVM
76d86cde6eSJing Zhang 	 * sanitized value for ID registers.
77d86cde6eSJing Zhang 	 */
78d86cde6eSJing Zhang 	u64 (*reset)(struct kvm_vcpu *, const struct sys_reg_desc *);
797c8c5e6aSMarc Zyngier 
807c8c5e6aSMarc Zyngier 	/* Index into sys_reg[], or 0 if we don't need to save it. */
817c8c5e6aSMarc Zyngier 	int reg;
827c8c5e6aSMarc Zyngier 
83d86cde6eSJing Zhang 	/* Value (usually reset value), or write mask for idregs */
847c8c5e6aSMarc Zyngier 	u64 val;
8584e690bfSAlex Bennée 
8684e690bfSAlex Bennée 	/* Custom get/set_user functions, fallback to generic if NULL */
8784e690bfSAlex Bennée 	int (*get_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
88978ceeb3SMarc Zyngier 			u64 *val);
8984e690bfSAlex Bennée 	int (*set_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
90978ceeb3SMarc Zyngier 			u64 val);
917f34e409SDave Martin 
927f34e409SDave Martin 	/* Return mask of REG_* runtime visibility overrides */
937f34e409SDave Martin 	unsigned int (*visibility)(const struct kvm_vcpu *vcpu,
947f34e409SDave Martin 				   const struct sys_reg_desc *rd);
957c8c5e6aSMarc Zyngier };
967c8c5e6aSMarc Zyngier 
9701fe5aceSAndrew Jones #define REG_HIDDEN		(1 << 0) /* hidden from userspace and guest */
98e6b367dbSMarc Zyngier #define REG_HIDDEN_USER		(1 << 1) /* hidden from userspace only */
99e6b367dbSMarc Zyngier #define REG_RAZ			(1 << 2) /* RAZ from userspace and guest */
100e6b367dbSMarc Zyngier #define REG_USER_WI		(1 << 3) /* WI from userspace only */
1017f34e409SDave Martin 
102bf4b96bbSMark Rutland static __printf(2, 3)
print_sys_reg_msg(const struct sys_reg_params * p,char * fmt,...)103bf4b96bbSMark Rutland inline void print_sys_reg_msg(const struct sys_reg_params *p,
104bf4b96bbSMark Rutland 				       char *fmt, ...)
105bf4b96bbSMark Rutland {
106bf4b96bbSMark Rutland 	va_list va;
107bf4b96bbSMark Rutland 
108bf4b96bbSMark Rutland 	va_start(va, fmt);
109bf4b96bbSMark Rutland 	/* Look, we even formatted it for you to paste into the table! */
110bf4b96bbSMark Rutland 	kvm_pr_unimpl("%pV { Op0(%2u), Op1(%2u), CRn(%2u), CRm(%2u), Op2(%2u), func_%s },\n",
111bf4b96bbSMark Rutland 		      &(struct va_format){ fmt, &va },
112bf4b96bbSMark Rutland 		      p->Op0, p->Op1, p->CRn, p->CRm, p->Op2, p->is_write ? "write" : "read");
113bf4b96bbSMark Rutland 	va_end(va);
114bf4b96bbSMark Rutland }
115bf4b96bbSMark Rutland 
print_sys_reg_instr(const struct sys_reg_params * p)1167c8c5e6aSMarc Zyngier static inline void print_sys_reg_instr(const struct sys_reg_params *p)
1177c8c5e6aSMarc Zyngier {
118bf4b96bbSMark Rutland 	/* GCC warns on an empty format string */
119bf4b96bbSMark Rutland 	print_sys_reg_msg(p, "%s", "");
1207c8c5e6aSMarc Zyngier }
1217c8c5e6aSMarc Zyngier 
ignore_write(struct kvm_vcpu * vcpu,const struct sys_reg_params * p)1227c8c5e6aSMarc Zyngier static inline bool ignore_write(struct kvm_vcpu *vcpu,
1237c8c5e6aSMarc Zyngier 				const struct sys_reg_params *p)
1247c8c5e6aSMarc Zyngier {
1257c8c5e6aSMarc Zyngier 	return true;
1267c8c5e6aSMarc Zyngier }
1277c8c5e6aSMarc Zyngier 
read_zero(struct kvm_vcpu * vcpu,struct sys_reg_params * p)1287c8c5e6aSMarc Zyngier static inline bool read_zero(struct kvm_vcpu *vcpu,
1293fec037dSPavel Fedin 			     struct sys_reg_params *p)
1307c8c5e6aSMarc Zyngier {
1312ec5be3dSPavel Fedin 	p->regval = 0;
1327c8c5e6aSMarc Zyngier 	return true;
1337c8c5e6aSMarc Zyngier }
1347c8c5e6aSMarc Zyngier 
1357c8c5e6aSMarc Zyngier /* Reset functions */
reset_unknown(struct kvm_vcpu * vcpu,const struct sys_reg_desc * r)136d86cde6eSJing Zhang static inline u64 reset_unknown(struct kvm_vcpu *vcpu,
1377c8c5e6aSMarc Zyngier 				 const struct sys_reg_desc *r)
1387c8c5e6aSMarc Zyngier {
1397c8c5e6aSMarc Zyngier 	BUG_ON(!r->reg);
1407c8c5e6aSMarc Zyngier 	BUG_ON(r->reg >= NR_SYS_REGS);
1418d404c4cSChristoffer Dall 	__vcpu_sys_reg(vcpu, r->reg) = 0x1de7ec7edbadc0deULL;
142d86cde6eSJing Zhang 	return __vcpu_sys_reg(vcpu, r->reg);
1437c8c5e6aSMarc Zyngier }
1447c8c5e6aSMarc Zyngier 
reset_val(struct kvm_vcpu * vcpu,const struct sys_reg_desc * r)145d86cde6eSJing Zhang static inline u64 reset_val(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
1467c8c5e6aSMarc Zyngier {
1477c8c5e6aSMarc Zyngier 	BUG_ON(!r->reg);
1487c8c5e6aSMarc Zyngier 	BUG_ON(r->reg >= NR_SYS_REGS);
1498d404c4cSChristoffer Dall 	__vcpu_sys_reg(vcpu, r->reg) = r->val;
150d86cde6eSJing Zhang 	return __vcpu_sys_reg(vcpu, r->reg);
1517c8c5e6aSMarc Zyngier }
1527c8c5e6aSMarc Zyngier 
sysreg_visibility(const struct kvm_vcpu * vcpu,const struct sys_reg_desc * r)1535d9a718bSOliver Upton static inline unsigned int sysreg_visibility(const struct kvm_vcpu *vcpu,
1547f34e409SDave Martin 					     const struct sys_reg_desc *r)
1557f34e409SDave Martin {
1567f34e409SDave Martin 	if (likely(!r->visibility))
1575d9a718bSOliver Upton 		return 0;
1587f34e409SDave Martin 
1595d9a718bSOliver Upton 	return r->visibility(vcpu, r);
1605d9a718bSOliver Upton }
1615d9a718bSOliver Upton 
sysreg_hidden(const struct kvm_vcpu * vcpu,const struct sys_reg_desc * r)1625d9a718bSOliver Upton static inline bool sysreg_hidden(const struct kvm_vcpu *vcpu,
1635d9a718bSOliver Upton 				 const struct sys_reg_desc *r)
1645d9a718bSOliver Upton {
1655d9a718bSOliver Upton 	return sysreg_visibility(vcpu, r) & REG_HIDDEN;
1667f34e409SDave Martin }
1677f34e409SDave Martin 
sysreg_hidden_user(const struct kvm_vcpu * vcpu,const struct sys_reg_desc * r)168e6b367dbSMarc Zyngier static inline bool sysreg_hidden_user(const struct kvm_vcpu *vcpu,
169e6b367dbSMarc Zyngier 				      const struct sys_reg_desc *r)
170e6b367dbSMarc Zyngier {
171e6b367dbSMarc Zyngier 	if (likely(!r->visibility))
172e6b367dbSMarc Zyngier 		return false;
173e6b367dbSMarc Zyngier 
174e6b367dbSMarc Zyngier 	return r->visibility(vcpu, r) & (REG_HIDDEN | REG_HIDDEN_USER);
175e6b367dbSMarc Zyngier }
176e6b367dbSMarc Zyngier 
sysreg_visible_as_raz(const struct kvm_vcpu * vcpu,const struct sys_reg_desc * r)177912dee57SAndrew Jones static inline bool sysreg_visible_as_raz(const struct kvm_vcpu *vcpu,
178912dee57SAndrew Jones 					 const struct sys_reg_desc *r)
179912dee57SAndrew Jones {
1805d9a718bSOliver Upton 	return sysreg_visibility(vcpu, r) & REG_RAZ;
181912dee57SAndrew Jones }
182912dee57SAndrew Jones 
sysreg_user_write_ignore(const struct kvm_vcpu * vcpu,const struct sys_reg_desc * r)1834de06e4cSOliver Upton static inline bool sysreg_user_write_ignore(const struct kvm_vcpu *vcpu,
1844de06e4cSOliver Upton 					    const struct sys_reg_desc *r)
1854de06e4cSOliver Upton {
1864de06e4cSOliver Upton 	return sysreg_visibility(vcpu, r) & REG_USER_WI;
1874de06e4cSOliver Upton }
1884de06e4cSOliver Upton 
cmp_sys_reg(const struct sys_reg_desc * i1,const struct sys_reg_desc * i2)1897c8c5e6aSMarc Zyngier static inline int cmp_sys_reg(const struct sys_reg_desc *i1,
1907c8c5e6aSMarc Zyngier 			      const struct sys_reg_desc *i2)
1917c8c5e6aSMarc Zyngier {
1927c8c5e6aSMarc Zyngier 	BUG_ON(i1 == i2);
1937c8c5e6aSMarc Zyngier 	if (!i1)
1947c8c5e6aSMarc Zyngier 		return 1;
1957c8c5e6aSMarc Zyngier 	else if (!i2)
1967c8c5e6aSMarc Zyngier 		return -1;
1977c8c5e6aSMarc Zyngier 	if (i1->Op0 != i2->Op0)
1987c8c5e6aSMarc Zyngier 		return i1->Op0 - i2->Op0;
1997c8c5e6aSMarc Zyngier 	if (i1->Op1 != i2->Op1)
2007c8c5e6aSMarc Zyngier 		return i1->Op1 - i2->Op1;
2017c8c5e6aSMarc Zyngier 	if (i1->CRn != i2->CRn)
2027c8c5e6aSMarc Zyngier 		return i1->CRn - i2->CRn;
2037c8c5e6aSMarc Zyngier 	if (i1->CRm != i2->CRm)
2047c8c5e6aSMarc Zyngier 		return i1->CRm - i2->CRm;
2057c8c5e6aSMarc Zyngier 	return i1->Op2 - i2->Op2;
2067c8c5e6aSMarc Zyngier }
2077c8c5e6aSMarc Zyngier 
match_sys_reg(const void * key,const void * elt)208f76f89e2SFuad Tabba static inline int match_sys_reg(const void *key, const void *elt)
209f76f89e2SFuad Tabba {
210f76f89e2SFuad Tabba 	const unsigned long pval = (unsigned long)key;
211f76f89e2SFuad Tabba 	const struct sys_reg_desc *r = elt;
212f76f89e2SFuad Tabba 
213f76f89e2SFuad Tabba 	return pval - reg_to_encoding(r);
214f76f89e2SFuad Tabba }
215f76f89e2SFuad Tabba 
216f76f89e2SFuad Tabba static inline const struct sys_reg_desc *
find_reg(const struct sys_reg_params * params,const struct sys_reg_desc table[],unsigned int num)217f76f89e2SFuad Tabba find_reg(const struct sys_reg_params *params, const struct sys_reg_desc table[],
218f76f89e2SFuad Tabba 	 unsigned int num)
219f76f89e2SFuad Tabba {
220f76f89e2SFuad Tabba 	unsigned long pval = reg_to_encoding(params);
221f76f89e2SFuad Tabba 
222f76f89e2SFuad Tabba 	return __inline_bsearch((void *)pval, table, num, sizeof(table[0]), match_sys_reg);
223f76f89e2SFuad Tabba }
224f76f89e2SFuad Tabba 
225da8d120fSMarc Zyngier const struct sys_reg_desc *get_reg_by_id(u64 id,
226da8d120fSMarc Zyngier 					 const struct sys_reg_desc table[],
227da8d120fSMarc Zyngier 					 unsigned int num);
228da8d120fSMarc Zyngier 
229c5332898SMarc Zyngier int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *);
230c5332898SMarc Zyngier int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *);
231ba23aec9SMarc Zyngier int kvm_sys_reg_get_user(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg,
232ba23aec9SMarc Zyngier 			 const struct sys_reg_desc table[], unsigned int num);
233ba23aec9SMarc Zyngier int kvm_sys_reg_set_user(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg,
234ba23aec9SMarc Zyngier 			 const struct sys_reg_desc table[], unsigned int num);
235ba23aec9SMarc Zyngier 
2366ed6750fSMarc Zyngier #define AA32(_x)	.aarch32_map = AA32_##_x
2377c8c5e6aSMarc Zyngier #define Op0(_x) 	.Op0 = _x
2387c8c5e6aSMarc Zyngier #define Op1(_x) 	.Op1 = _x
2397c8c5e6aSMarc Zyngier #define CRn(_x)		.CRn = _x
2407c8c5e6aSMarc Zyngier #define CRm(_x) 	.CRm = _x
2417c8c5e6aSMarc Zyngier #define Op2(_x) 	.Op2 = _x
2427c8c5e6aSMarc Zyngier 
2438db5d8f1SMark Rutland #define SYS_DESC(reg)					\
244599d79dcSMarc Zyngier 	.name = #reg,					\
2458db5d8f1SMark Rutland 	Op0(sys_reg_Op0(reg)), Op1(sys_reg_Op1(reg)),	\
2468db5d8f1SMark Rutland 	CRn(sys_reg_CRn(reg)), CRm(sys_reg_CRm(reg)),	\
2478db5d8f1SMark Rutland 	Op2(sys_reg_Op2(reg))
2488db5d8f1SMark Rutland 
2497c8c5e6aSMarc Zyngier #endif /* __ARM64_KVM_SYS_REGS_LOCAL_H__ */
250