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