17c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier/*
27c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier * Copyright (C) 2012,2013 - ARM Ltd
37c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier * Author: Marc Zyngier <marc.zyngier@arm.com>
47c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier *
57c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier * Derived from arch/arm/kvm/coproc.h
67c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier * Copyright (C) 2012 - Virtual Open Systems and Columbia University
77c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier * Authors: Christoffer Dall <c.dall@virtualopensystems.com>
87c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier *
97c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier * This program is free software; you can redistribute it and/or modify
107c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier * it under the terms of the GNU General Public License, version 2, as
117c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier * published by the Free Software Foundation.
127c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier *
137c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier * This program is distributed in the hope that it will be useful,
147c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier * but WITHOUT ANY WARRANTY; without even the implied warranty of
157c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
167c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier * GNU General Public License for more details.
177c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier *
187c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier * You should have received a copy of the GNU General Public License
197c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier * along with this program.  If not, see <http://www.gnu.org/licenses/>.
207c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier */
217c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier
227c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier#ifndef __ARM64_KVM_SYS_REGS_LOCAL_H__
237c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier#define __ARM64_KVM_SYS_REGS_LOCAL_H__
247c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier
257c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngierstruct sys_reg_params {
267c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	u8	Op0;
277c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	u8	Op1;
287c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	u8	CRn;
297c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	u8	CRm;
307c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	u8	Op2;
317c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	u8	Rt;
327c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	bool	is_write;
332072d29c46b73e39b3c6c56c6027af77086f45fdMarc Zyngier	bool	is_aarch32;
342072d29c46b73e39b3c6c56c6027af77086f45fdMarc Zyngier	bool	is_32bit;	/* Only valid if is_aarch32 is true */
357c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier};
367c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier
377c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngierstruct sys_reg_desc {
387c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	/* MRS/MSR instruction which accesses it. */
397c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	u8	Op0;
407c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	u8	Op1;
417c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	u8	CRn;
427c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	u8	CRm;
437c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	u8	Op2;
447c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier
457c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	/* Trapped access from guest, if non-NULL. */
467c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	bool (*access)(struct kvm_vcpu *,
477c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier		       const struct sys_reg_params *,
487c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier		       const struct sys_reg_desc *);
497c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier
507c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	/* Initialization for vcpu. */
517c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	void (*reset)(struct kvm_vcpu *, const struct sys_reg_desc *);
527c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier
537c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	/* Index into sys_reg[], or 0 if we don't need to save it. */
547c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	int reg;
557c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier
567c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	/* Value (usually reset value) */
577c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	u64 val;
587c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier};
597c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier
607c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngierstatic inline void print_sys_reg_instr(const struct sys_reg_params *p)
617c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier{
627c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	/* Look, we even formatted it for you to paste into the table! */
637c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	kvm_pr_unimpl(" { Op0(%2u), Op1(%2u), CRn(%2u), CRm(%2u), Op2(%2u), func_%s },\n",
647c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier		      p->Op0, p->Op1, p->CRn, p->CRm, p->Op2, p->is_write ? "write" : "read");
657c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier}
667c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier
677c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngierstatic inline bool ignore_write(struct kvm_vcpu *vcpu,
687c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier				const struct sys_reg_params *p)
697c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier{
707c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	return true;
717c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier}
727c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier
737c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngierstatic inline bool read_zero(struct kvm_vcpu *vcpu,
747c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier			     const struct sys_reg_params *p)
757c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier{
767c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	*vcpu_reg(vcpu, p->Rt) = 0;
777c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	return true;
787c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier}
797c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier
807c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngierstatic inline bool write_to_read_only(struct kvm_vcpu *vcpu,
817c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier				      const struct sys_reg_params *params)
827c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier{
837c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	kvm_debug("sys_reg write to read-only register at: %lx\n",
847c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier		  *vcpu_pc(vcpu));
857c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	print_sys_reg_instr(params);
867c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	return false;
877c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier}
887c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier
897c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngierstatic inline bool read_from_write_only(struct kvm_vcpu *vcpu,
907c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier					const struct sys_reg_params *params)
917c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier{
927c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	kvm_debug("sys_reg read to write-only register at: %lx\n",
937c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier		  *vcpu_pc(vcpu));
947c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	print_sys_reg_instr(params);
957c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	return false;
967c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier}
977c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier
987c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier/* Reset functions */
997c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngierstatic inline void reset_unknown(struct kvm_vcpu *vcpu,
1007c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier				 const struct sys_reg_desc *r)
1017c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier{
1027c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	BUG_ON(!r->reg);
1037c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	BUG_ON(r->reg >= NR_SYS_REGS);
1047c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	vcpu_sys_reg(vcpu, r->reg) = 0x1de7ec7edbadc0deULL;
1057c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier}
1067c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier
1077c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngierstatic inline void reset_val(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
1087c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier{
1097c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	BUG_ON(!r->reg);
1107c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	BUG_ON(r->reg >= NR_SYS_REGS);
1117c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	vcpu_sys_reg(vcpu, r->reg) = r->val;
1127c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier}
1137c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier
1147c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngierstatic inline int cmp_sys_reg(const struct sys_reg_desc *i1,
1157c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier			      const struct sys_reg_desc *i2)
1167c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier{
1177c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	BUG_ON(i1 == i2);
1187c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	if (!i1)
1197c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier		return 1;
1207c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	else if (!i2)
1217c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier		return -1;
1227c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	if (i1->Op0 != i2->Op0)
1237c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier		return i1->Op0 - i2->Op0;
1247c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	if (i1->Op1 != i2->Op1)
1257c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier		return i1->Op1 - i2->Op1;
1267c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	if (i1->CRn != i2->CRn)
1277c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier		return i1->CRn - i2->CRn;
1287c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	if (i1->CRm != i2->CRm)
1297c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier		return i1->CRm - i2->CRm;
1307c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier	return i1->Op2 - i2->Op2;
1317c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier}
1327c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier
1337c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier
1347c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier#define Op0(_x) 	.Op0 = _x
1357c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier#define Op1(_x) 	.Op1 = _x
1367c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier#define CRn(_x)		.CRn = _x
1377c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier#define CRm(_x) 	.CRm = _x
1387c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier#define Op2(_x) 	.Op2 = _x
1397c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier
1407c8c5e6a9101ea57a1c2c9faff0917e79251a21eMarc Zyngier#endif /* __ARM64_KVM_SYS_REGS_LOCAL_H__ */
141