sys_regs.h (5550B)
1/* SPDX-License-Identifier: GPL-2.0-only */ 2/* 3 * Copyright (C) 2012,2013 - ARM Ltd 4 * Author: Marc Zyngier <marc.zyngier@arm.com> 5 * 6 * Derived from arch/arm/kvm/coproc.h 7 * Copyright (C) 2012 - Virtual Open Systems and Columbia University 8 * Authors: Christoffer Dall <c.dall@virtualopensystems.com> 9 */ 10 11#ifndef __ARM64_KVM_SYS_REGS_LOCAL_H__ 12#define __ARM64_KVM_SYS_REGS_LOCAL_H__ 13 14#include <linux/bsearch.h> 15 16#define reg_to_encoding(x) \ 17 sys_reg((u32)(x)->Op0, (u32)(x)->Op1, \ 18 (u32)(x)->CRn, (u32)(x)->CRm, (u32)(x)->Op2) 19 20struct sys_reg_params { 21 u8 Op0; 22 u8 Op1; 23 u8 CRn; 24 u8 CRm; 25 u8 Op2; 26 u64 regval; 27 bool is_write; 28}; 29 30#define esr_sys64_to_params(esr) \ 31 ((struct sys_reg_params){ .Op0 = ((esr) >> 20) & 3, \ 32 .Op1 = ((esr) >> 14) & 0x7, \ 33 .CRn = ((esr) >> 10) & 0xf, \ 34 .CRm = ((esr) >> 1) & 0xf, \ 35 .Op2 = ((esr) >> 17) & 0x7, \ 36 .is_write = !((esr) & 1) }) 37 38#define esr_cp1x_32_to_params(esr) \ 39 ((struct sys_reg_params){ .Op1 = ((esr) >> 14) & 0x7, \ 40 .CRn = ((esr) >> 10) & 0xf, \ 41 .CRm = ((esr) >> 1) & 0xf, \ 42 .Op2 = ((esr) >> 17) & 0x7, \ 43 .is_write = !((esr) & 1) }) 44 45struct sys_reg_desc { 46 /* Sysreg string for debug */ 47 const char *name; 48 49 enum { 50 AA32_DIRECT, 51 AA32_LO, 52 AA32_HI, 53 } aarch32_map; 54 55 /* MRS/MSR instruction which accesses it. */ 56 u8 Op0; 57 u8 Op1; 58 u8 CRn; 59 u8 CRm; 60 u8 Op2; 61 62 /* Trapped access from guest, if non-NULL. */ 63 bool (*access)(struct kvm_vcpu *, 64 struct sys_reg_params *, 65 const struct sys_reg_desc *); 66 67 /* Initialization for vcpu. */ 68 void (*reset)(struct kvm_vcpu *, const struct sys_reg_desc *); 69 70 /* Index into sys_reg[], or 0 if we don't need to save it. */ 71 int reg; 72 73 /* Value (usually reset value) */ 74 u64 val; 75 76 /* Custom get/set_user functions, fallback to generic if NULL */ 77 int (*get_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, 78 const struct kvm_one_reg *reg, void __user *uaddr); 79 int (*set_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, 80 const struct kvm_one_reg *reg, void __user *uaddr); 81 82 /* Return mask of REG_* runtime visibility overrides */ 83 unsigned int (*visibility)(const struct kvm_vcpu *vcpu, 84 const struct sys_reg_desc *rd); 85}; 86 87#define REG_HIDDEN (1 << 0) /* hidden from userspace and guest */ 88#define REG_RAZ (1 << 1) /* RAZ from userspace and guest */ 89 90static __printf(2, 3) 91inline void print_sys_reg_msg(const struct sys_reg_params *p, 92 char *fmt, ...) 93{ 94 va_list va; 95 96 va_start(va, fmt); 97 /* Look, we even formatted it for you to paste into the table! */ 98 kvm_pr_unimpl("%pV { Op0(%2u), Op1(%2u), CRn(%2u), CRm(%2u), Op2(%2u), func_%s },\n", 99 &(struct va_format){ fmt, &va }, 100 p->Op0, p->Op1, p->CRn, p->CRm, p->Op2, p->is_write ? "write" : "read"); 101 va_end(va); 102} 103 104static inline void print_sys_reg_instr(const struct sys_reg_params *p) 105{ 106 /* GCC warns on an empty format string */ 107 print_sys_reg_msg(p, "%s", ""); 108} 109 110static inline bool ignore_write(struct kvm_vcpu *vcpu, 111 const struct sys_reg_params *p) 112{ 113 return true; 114} 115 116static inline bool read_zero(struct kvm_vcpu *vcpu, 117 struct sys_reg_params *p) 118{ 119 p->regval = 0; 120 return true; 121} 122 123/* Reset functions */ 124static inline void reset_unknown(struct kvm_vcpu *vcpu, 125 const struct sys_reg_desc *r) 126{ 127 BUG_ON(!r->reg); 128 BUG_ON(r->reg >= NR_SYS_REGS); 129 __vcpu_sys_reg(vcpu, r->reg) = 0x1de7ec7edbadc0deULL; 130} 131 132static inline void reset_val(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r) 133{ 134 BUG_ON(!r->reg); 135 BUG_ON(r->reg >= NR_SYS_REGS); 136 __vcpu_sys_reg(vcpu, r->reg) = r->val; 137} 138 139static inline bool sysreg_hidden(const struct kvm_vcpu *vcpu, 140 const struct sys_reg_desc *r) 141{ 142 if (likely(!r->visibility)) 143 return false; 144 145 return r->visibility(vcpu, r) & REG_HIDDEN; 146} 147 148static inline bool sysreg_visible_as_raz(const struct kvm_vcpu *vcpu, 149 const struct sys_reg_desc *r) 150{ 151 if (likely(!r->visibility)) 152 return false; 153 154 return r->visibility(vcpu, r) & REG_RAZ; 155} 156 157static inline int cmp_sys_reg(const struct sys_reg_desc *i1, 158 const struct sys_reg_desc *i2) 159{ 160 BUG_ON(i1 == i2); 161 if (!i1) 162 return 1; 163 else if (!i2) 164 return -1; 165 if (i1->Op0 != i2->Op0) 166 return i1->Op0 - i2->Op0; 167 if (i1->Op1 != i2->Op1) 168 return i1->Op1 - i2->Op1; 169 if (i1->CRn != i2->CRn) 170 return i1->CRn - i2->CRn; 171 if (i1->CRm != i2->CRm) 172 return i1->CRm - i2->CRm; 173 return i1->Op2 - i2->Op2; 174} 175 176static inline int match_sys_reg(const void *key, const void *elt) 177{ 178 const unsigned long pval = (unsigned long)key; 179 const struct sys_reg_desc *r = elt; 180 181 return pval - reg_to_encoding(r); 182} 183 184static inline const struct sys_reg_desc * 185find_reg(const struct sys_reg_params *params, const struct sys_reg_desc table[], 186 unsigned int num) 187{ 188 unsigned long pval = reg_to_encoding(params); 189 190 return __inline_bsearch((void *)pval, table, num, sizeof(table[0]), match_sys_reg); 191} 192 193const struct sys_reg_desc *find_reg_by_id(u64 id, 194 struct sys_reg_params *params, 195 const struct sys_reg_desc table[], 196 unsigned int num); 197 198#define AA32(_x) .aarch32_map = AA32_##_x 199#define Op0(_x) .Op0 = _x 200#define Op1(_x) .Op1 = _x 201#define CRn(_x) .CRn = _x 202#define CRm(_x) .CRm = _x 203#define Op2(_x) .Op2 = _x 204 205#define SYS_DESC(reg) \ 206 .name = #reg, \ 207 Op0(sys_reg_Op0(reg)), Op1(sys_reg_Op1(reg)), \ 208 CRn(sys_reg_CRn(reg)), CRm(sys_reg_CRm(reg)), \ 209 Op2(sys_reg_Op2(reg)) 210 211#endif /* __ARM64_KVM_SYS_REGS_LOCAL_H__ */