18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2012,2013 - ARM Ltd
48c2ecf20Sopenharmony_ci * Author: Marc Zyngier <marc.zyngier@arm.com>
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Derived from arch/arm/kvm/coproc.h
78c2ecf20Sopenharmony_ci * Copyright (C) 2012 - Virtual Open Systems and Columbia University
88c2ecf20Sopenharmony_ci * Authors: Christoffer Dall <c.dall@virtualopensystems.com>
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#ifndef __ARM64_KVM_SYS_REGS_LOCAL_H__
128c2ecf20Sopenharmony_ci#define __ARM64_KVM_SYS_REGS_LOCAL_H__
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_cistruct sys_reg_params {
158c2ecf20Sopenharmony_ci	u8	Op0;
168c2ecf20Sopenharmony_ci	u8	Op1;
178c2ecf20Sopenharmony_ci	u8	CRn;
188c2ecf20Sopenharmony_ci	u8	CRm;
198c2ecf20Sopenharmony_ci	u8	Op2;
208c2ecf20Sopenharmony_ci	u64	regval;
218c2ecf20Sopenharmony_ci	bool	is_write;
228c2ecf20Sopenharmony_ci	bool	is_aarch32;
238c2ecf20Sopenharmony_ci	bool	is_32bit;	/* Only valid if is_aarch32 is true */
248c2ecf20Sopenharmony_ci};
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistruct sys_reg_desc {
278c2ecf20Sopenharmony_ci	/* Sysreg string for debug */
288c2ecf20Sopenharmony_ci	const char *name;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	/* MRS/MSR instruction which accesses it. */
318c2ecf20Sopenharmony_ci	u8	Op0;
328c2ecf20Sopenharmony_ci	u8	Op1;
338c2ecf20Sopenharmony_ci	u8	CRn;
348c2ecf20Sopenharmony_ci	u8	CRm;
358c2ecf20Sopenharmony_ci	u8	Op2;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	/* Trapped access from guest, if non-NULL. */
388c2ecf20Sopenharmony_ci	bool (*access)(struct kvm_vcpu *,
398c2ecf20Sopenharmony_ci		       struct sys_reg_params *,
408c2ecf20Sopenharmony_ci		       const struct sys_reg_desc *);
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	/* Initialization for vcpu. */
438c2ecf20Sopenharmony_ci	void (*reset)(struct kvm_vcpu *, const struct sys_reg_desc *);
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	/* Index into sys_reg[], or 0 if we don't need to save it. */
468c2ecf20Sopenharmony_ci	int reg;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	/* Value (usually reset value) */
498c2ecf20Sopenharmony_ci	u64 val;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	/* Custom get/set_user functions, fallback to generic if NULL */
528c2ecf20Sopenharmony_ci	int (*get_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
538c2ecf20Sopenharmony_ci			const struct kvm_one_reg *reg, void __user *uaddr);
548c2ecf20Sopenharmony_ci	int (*set_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
558c2ecf20Sopenharmony_ci			const struct kvm_one_reg *reg, void __user *uaddr);
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	/* Return mask of REG_* runtime visibility overrides */
588c2ecf20Sopenharmony_ci	unsigned int (*visibility)(const struct kvm_vcpu *vcpu,
598c2ecf20Sopenharmony_ci				   const struct sys_reg_desc *rd);
608c2ecf20Sopenharmony_ci};
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci#define REG_HIDDEN		(1 << 0) /* hidden from userspace and guest */
638c2ecf20Sopenharmony_ci#define REG_RAZ			(1 << 1) /* RAZ from userspace and guest */
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistatic __printf(2, 3)
668c2ecf20Sopenharmony_ciinline void print_sys_reg_msg(const struct sys_reg_params *p,
678c2ecf20Sopenharmony_ci				       char *fmt, ...)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	va_list va;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	va_start(va, fmt);
728c2ecf20Sopenharmony_ci	/* Look, we even formatted it for you to paste into the table! */
738c2ecf20Sopenharmony_ci	kvm_pr_unimpl("%pV { Op0(%2u), Op1(%2u), CRn(%2u), CRm(%2u), Op2(%2u), func_%s },\n",
748c2ecf20Sopenharmony_ci		      &(struct va_format){ fmt, &va },
758c2ecf20Sopenharmony_ci		      p->Op0, p->Op1, p->CRn, p->CRm, p->Op2, p->is_write ? "write" : "read");
768c2ecf20Sopenharmony_ci	va_end(va);
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_cistatic inline void print_sys_reg_instr(const struct sys_reg_params *p)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	/* GCC warns on an empty format string */
828c2ecf20Sopenharmony_ci	print_sys_reg_msg(p, "%s", "");
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_cistatic inline bool ignore_write(struct kvm_vcpu *vcpu,
868c2ecf20Sopenharmony_ci				const struct sys_reg_params *p)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	return true;
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_cistatic inline bool read_zero(struct kvm_vcpu *vcpu,
928c2ecf20Sopenharmony_ci			     struct sys_reg_params *p)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	p->regval = 0;
958c2ecf20Sopenharmony_ci	return true;
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci/* Reset functions */
998c2ecf20Sopenharmony_cistatic inline void reset_unknown(struct kvm_vcpu *vcpu,
1008c2ecf20Sopenharmony_ci				 const struct sys_reg_desc *r)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	BUG_ON(!r->reg);
1038c2ecf20Sopenharmony_ci	BUG_ON(r->reg >= NR_SYS_REGS);
1048c2ecf20Sopenharmony_ci	__vcpu_sys_reg(vcpu, r->reg) = 0x1de7ec7edbadc0deULL;
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cistatic inline void reset_val(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
1088c2ecf20Sopenharmony_ci{
1098c2ecf20Sopenharmony_ci	BUG_ON(!r->reg);
1108c2ecf20Sopenharmony_ci	BUG_ON(r->reg >= NR_SYS_REGS);
1118c2ecf20Sopenharmony_ci	__vcpu_sys_reg(vcpu, r->reg) = r->val;
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_cistatic inline bool sysreg_hidden(const struct kvm_vcpu *vcpu,
1158c2ecf20Sopenharmony_ci				 const struct sys_reg_desc *r)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	if (likely(!r->visibility))
1188c2ecf20Sopenharmony_ci		return false;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	return r->visibility(vcpu, r) & REG_HIDDEN;
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic inline bool sysreg_visible_as_raz(const struct kvm_vcpu *vcpu,
1248c2ecf20Sopenharmony_ci					 const struct sys_reg_desc *r)
1258c2ecf20Sopenharmony_ci{
1268c2ecf20Sopenharmony_ci	if (likely(!r->visibility))
1278c2ecf20Sopenharmony_ci		return false;
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	return r->visibility(vcpu, r) & REG_RAZ;
1308c2ecf20Sopenharmony_ci}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cistatic inline int cmp_sys_reg(const struct sys_reg_desc *i1,
1338c2ecf20Sopenharmony_ci			      const struct sys_reg_desc *i2)
1348c2ecf20Sopenharmony_ci{
1358c2ecf20Sopenharmony_ci	BUG_ON(i1 == i2);
1368c2ecf20Sopenharmony_ci	if (!i1)
1378c2ecf20Sopenharmony_ci		return 1;
1388c2ecf20Sopenharmony_ci	else if (!i2)
1398c2ecf20Sopenharmony_ci		return -1;
1408c2ecf20Sopenharmony_ci	if (i1->Op0 != i2->Op0)
1418c2ecf20Sopenharmony_ci		return i1->Op0 - i2->Op0;
1428c2ecf20Sopenharmony_ci	if (i1->Op1 != i2->Op1)
1438c2ecf20Sopenharmony_ci		return i1->Op1 - i2->Op1;
1448c2ecf20Sopenharmony_ci	if (i1->CRn != i2->CRn)
1458c2ecf20Sopenharmony_ci		return i1->CRn - i2->CRn;
1468c2ecf20Sopenharmony_ci	if (i1->CRm != i2->CRm)
1478c2ecf20Sopenharmony_ci		return i1->CRm - i2->CRm;
1488c2ecf20Sopenharmony_ci	return i1->Op2 - i2->Op2;
1498c2ecf20Sopenharmony_ci}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ciconst struct sys_reg_desc *find_reg_by_id(u64 id,
1528c2ecf20Sopenharmony_ci					  struct sys_reg_params *params,
1538c2ecf20Sopenharmony_ci					  const struct sys_reg_desc table[],
1548c2ecf20Sopenharmony_ci					  unsigned int num);
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci#define Op0(_x) 	.Op0 = _x
1578c2ecf20Sopenharmony_ci#define Op1(_x) 	.Op1 = _x
1588c2ecf20Sopenharmony_ci#define CRn(_x)		.CRn = _x
1598c2ecf20Sopenharmony_ci#define CRm(_x) 	.CRm = _x
1608c2ecf20Sopenharmony_ci#define Op2(_x) 	.Op2 = _x
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci#define SYS_DESC(reg)					\
1638c2ecf20Sopenharmony_ci	.name = #reg,					\
1648c2ecf20Sopenharmony_ci	Op0(sys_reg_Op0(reg)), Op1(sys_reg_Op1(reg)),	\
1658c2ecf20Sopenharmony_ci	CRn(sys_reg_CRn(reg)), CRm(sys_reg_CRm(reg)),	\
1668c2ecf20Sopenharmony_ci	Op2(sys_reg_Op2(reg))
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci#endif /* __ARM64_KVM_SYS_REGS_LOCAL_H__ */
169