| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276 |
- /* SPDX-License-Identifier: GPL-2.0-only */
- /*
- * Copyright (C) 2012,2013 - ARM Ltd
- * Author: Marc Zyngier <marc.zyngier@arm.com>
- *
- * Derived from arch/arm/kvm/coproc.h
- * Copyright (C) 2012 - Virtual Open Systems and Columbia University
- * Authors: Christoffer Dall <c.dall@virtualopensystems.com>
- */
- #ifndef __ARM64_KVM_SYS_REGS_LOCAL_H__
- #define __ARM64_KVM_SYS_REGS_LOCAL_H__
- #include <linux/bsearch.h>
- #define reg_to_encoding(x) \
- sys_reg((u32)(x)->Op0, (u32)(x)->Op1, \
- (u32)(x)->CRn, (u32)(x)->CRm, (u32)(x)->Op2)
- struct sys_reg_params {
- u8 Op0;
- u8 Op1;
- u8 CRn;
- u8 CRm;
- u8 Op2;
- u64 regval;
- bool is_write;
- };
- #define encoding_to_params(reg) \
- ((struct sys_reg_params){ .Op0 = sys_reg_Op0(reg), \
- .Op1 = sys_reg_Op1(reg), \
- .CRn = sys_reg_CRn(reg), \
- .CRm = sys_reg_CRm(reg), \
- .Op2 = sys_reg_Op2(reg) })
- #define esr_sys64_to_params(esr) \
- ((struct sys_reg_params){ .Op0 = ((esr) >> 20) & 3, \
- .Op1 = ((esr) >> 14) & 0x7, \
- .CRn = ((esr) >> 10) & 0xf, \
- .CRm = ((esr) >> 1) & 0xf, \
- .Op2 = ((esr) >> 17) & 0x7, \
- .is_write = !((esr) & 1) })
- #define esr_cp1x_32_to_params(esr) \
- ((struct sys_reg_params){ .Op1 = ((esr) >> 14) & 0x7, \
- .CRn = ((esr) >> 10) & 0xf, \
- .CRm = ((esr) >> 1) & 0xf, \
- .Op2 = ((esr) >> 17) & 0x7, \
- .is_write = !((esr) & 1) })
- /*
- * The Feature ID space is defined as the System register space in AArch64
- * with op0==3, op1=={0, 1, 3}, CRn==0, CRm=={0-7}, op2=={0-7}.
- */
- static inline bool in_feat_id_space(struct sys_reg_params *p)
- {
- return (p->Op0 == 3 && !(p->Op1 & 0b100) && p->Op1 != 2 &&
- p->CRn == 0 && !(p->CRm & 0b1000));
- }
- struct sys_reg_desc {
- /* Sysreg string for debug */
- const char *name;
- enum {
- AA32_DIRECT,
- AA32_LO,
- AA32_HI,
- } aarch32_map;
- /* MRS/MSR instruction which accesses it. */
- u8 Op0;
- u8 Op1;
- u8 CRn;
- u8 CRm;
- u8 Op2;
- /* Trapped access from guest, if non-NULL. */
- bool (*access)(struct kvm_vcpu *,
- struct sys_reg_params *,
- const struct sys_reg_desc *);
- /*
- * Initialization for vcpu. Return initialized value, or KVM
- * sanitized value for ID registers.
- */
- u64 (*reset)(struct kvm_vcpu *, const struct sys_reg_desc *);
- /* Index into sys_reg[], or 0 if we don't need to save it. */
- int reg;
- /* Value (usually reset value), or write mask for idregs */
- u64 val;
- /* Custom get/set_user functions, fallback to generic if NULL */
- int (*get_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
- u64 *val);
- int (*set_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
- u64 val);
- /* Return mask of REG_* runtime visibility overrides */
- unsigned int (*visibility)(const struct kvm_vcpu *vcpu,
- const struct sys_reg_desc *rd);
- };
- #define REG_HIDDEN (1 << 0) /* hidden from userspace and guest */
- #define REG_RAZ (1 << 1) /* RAZ from userspace and guest */
- #define REG_USER_WI (1 << 2) /* WI from userspace only */
- static __printf(2, 3)
- inline void print_sys_reg_msg(const struct sys_reg_params *p,
- char *fmt, ...)
- {
- va_list va;
- va_start(va, fmt);
- /* Look, we even formatted it for you to paste into the table! */
- kvm_pr_unimpl("%pV { Op0(%2u), Op1(%2u), CRn(%2u), CRm(%2u), Op2(%2u), func_%s },\n",
- &(struct va_format){ fmt, &va },
- p->Op0, p->Op1, p->CRn, p->CRm, p->Op2, str_write_read(p->is_write));
- va_end(va);
- }
- static inline void print_sys_reg_instr(const struct sys_reg_params *p)
- {
- /* GCC warns on an empty format string */
- print_sys_reg_msg(p, "%s", "");
- }
- static inline bool ignore_write(struct kvm_vcpu *vcpu,
- const struct sys_reg_params *p)
- {
- return true;
- }
- static inline bool read_zero(struct kvm_vcpu *vcpu,
- struct sys_reg_params *p)
- {
- p->regval = 0;
- return true;
- }
- /* Reset functions */
- static inline u64 reset_unknown(struct kvm_vcpu *vcpu,
- const struct sys_reg_desc *r)
- {
- BUG_ON(!r->reg);
- BUG_ON(r->reg >= NR_SYS_REGS);
- __vcpu_assign_sys_reg(vcpu, r->reg, 0x1de7ec7edbadc0deULL);
- return __vcpu_sys_reg(vcpu, r->reg);
- }
- static inline u64 reset_val(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
- {
- BUG_ON(!r->reg);
- BUG_ON(r->reg >= NR_SYS_REGS);
- __vcpu_assign_sys_reg(vcpu, r->reg, r->val);
- return __vcpu_sys_reg(vcpu, r->reg);
- }
- static inline unsigned int sysreg_visibility(const struct kvm_vcpu *vcpu,
- const struct sys_reg_desc *r)
- {
- if (likely(!r->visibility))
- return 0;
- return r->visibility(vcpu, r);
- }
- static inline bool sysreg_hidden(const struct kvm_vcpu *vcpu,
- const struct sys_reg_desc *r)
- {
- return sysreg_visibility(vcpu, r) & REG_HIDDEN;
- }
- static inline bool sysreg_visible_as_raz(const struct kvm_vcpu *vcpu,
- const struct sys_reg_desc *r)
- {
- return sysreg_visibility(vcpu, r) & REG_RAZ;
- }
- static inline bool sysreg_user_write_ignore(const struct kvm_vcpu *vcpu,
- const struct sys_reg_desc *r)
- {
- return sysreg_visibility(vcpu, r) & REG_USER_WI;
- }
- static inline int cmp_sys_reg(const struct sys_reg_desc *i1,
- const struct sys_reg_desc *i2)
- {
- BUG_ON(i1 == i2);
- if (!i1)
- return 1;
- else if (!i2)
- return -1;
- if (i1->Op0 != i2->Op0)
- return i1->Op0 - i2->Op0;
- if (i1->Op1 != i2->Op1)
- return i1->Op1 - i2->Op1;
- if (i1->CRn != i2->CRn)
- return i1->CRn - i2->CRn;
- if (i1->CRm != i2->CRm)
- return i1->CRm - i2->CRm;
- return i1->Op2 - i2->Op2;
- }
- static inline int match_sys_reg(const void *key, const void *elt)
- {
- const unsigned long pval = (unsigned long)key;
- const struct sys_reg_desc *r = elt;
- return pval - reg_to_encoding(r);
- }
- static inline const struct sys_reg_desc *
- find_reg(const struct sys_reg_params *params, const struct sys_reg_desc table[],
- unsigned int num)
- {
- unsigned long pval = reg_to_encoding(params);
- return __inline_bsearch((void *)pval, table, num, sizeof(table[0]), match_sys_reg);
- }
- const struct sys_reg_desc *get_reg_by_id(u64 id,
- const struct sys_reg_desc table[],
- unsigned int num);
- int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *);
- int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *);
- int kvm_sys_reg_get_user(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg,
- const struct sys_reg_desc table[], unsigned int num);
- int kvm_sys_reg_set_user(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg,
- const struct sys_reg_desc table[], unsigned int num);
- bool triage_sysreg_trap(struct kvm_vcpu *vcpu, int *sr_index);
- int kvm_finalize_sys_regs(struct kvm_vcpu *vcpu);
- #define AA32(_x) .aarch32_map = AA32_##_x
- #define Op0(_x) .Op0 = _x
- #define Op1(_x) .Op1 = _x
- #define CRn(_x) .CRn = _x
- #define CRm(_x) .CRm = _x
- #define Op2(_x) .Op2 = _x
- #define SYS_DESC(reg) \
- .name = #reg, \
- Op0(sys_reg_Op0(reg)), Op1(sys_reg_Op1(reg)), \
- CRn(sys_reg_CRn(reg)), CRm(sys_reg_CRm(reg)), \
- Op2(sys_reg_Op2(reg))
- #define CP15_SYS_DESC(reg) \
- .name = #reg, \
- .aarch32_map = AA32_DIRECT, \
- Op0(0), Op1(sys_reg_Op1(reg)), \
- CRn(sys_reg_CRn(reg)), CRm(sys_reg_CRm(reg)), \
- Op2(sys_reg_Op2(reg))
- #define ID_REG_LIMIT_FIELD_ENUM(val, reg, field, limit) \
- ({ \
- u64 __f_val = FIELD_GET(reg##_##field##_MASK, val); \
- (val) &= ~reg##_##field##_MASK; \
- (val) |= FIELD_PREP(reg##_##field##_MASK, \
- min(__f_val, \
- (u64)SYS_FIELD_VALUE(reg, field, limit))); \
- (val); \
- })
- #define TO_ARM64_SYS_REG(r) ARM64_SYS_REG(sys_reg_Op0(SYS_ ## r), \
- sys_reg_Op1(SYS_ ## r), \
- sys_reg_CRn(SYS_ ## r), \
- sys_reg_CRm(SYS_ ## r), \
- sys_reg_Op2(SYS_ ## r))
- #endif /* __ARM64_KVM_SYS_REGS_LOCAL_H__ */
|