162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2012,2013 - ARM Ltd 462306a36Sopenharmony_ci * Author: Marc Zyngier <marc.zyngier@arm.com> 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Derived from arch/arm/kvm/coproc.c: 762306a36Sopenharmony_ci * Copyright (C) 2012 - Virtual Open Systems and Columbia University 862306a36Sopenharmony_ci * Authors: Rusty Russell <rusty@rustcorp.com.au> 962306a36Sopenharmony_ci * Christoffer Dall <c.dall@virtualopensystems.com> 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/bitfield.h> 1362306a36Sopenharmony_ci#include <linux/bsearch.h> 1462306a36Sopenharmony_ci#include <linux/cacheinfo.h> 1562306a36Sopenharmony_ci#include <linux/kvm_host.h> 1662306a36Sopenharmony_ci#include <linux/mm.h> 1762306a36Sopenharmony_ci#include <linux/printk.h> 1862306a36Sopenharmony_ci#include <linux/uaccess.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include <asm/cacheflush.h> 2162306a36Sopenharmony_ci#include <asm/cputype.h> 2262306a36Sopenharmony_ci#include <asm/debug-monitors.h> 2362306a36Sopenharmony_ci#include <asm/esr.h> 2462306a36Sopenharmony_ci#include <asm/kvm_arm.h> 2562306a36Sopenharmony_ci#include <asm/kvm_emulate.h> 2662306a36Sopenharmony_ci#include <asm/kvm_hyp.h> 2762306a36Sopenharmony_ci#include <asm/kvm_mmu.h> 2862306a36Sopenharmony_ci#include <asm/kvm_nested.h> 2962306a36Sopenharmony_ci#include <asm/perf_event.h> 3062306a36Sopenharmony_ci#include <asm/sysreg.h> 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#include <trace/events/kvm.h> 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#include "sys_regs.h" 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#include "trace.h" 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* 3962306a36Sopenharmony_ci * For AArch32, we only take care of what is being trapped. Anything 4062306a36Sopenharmony_ci * that has to do with init and userspace access has to go via the 4162306a36Sopenharmony_ci * 64bit interface. 4262306a36Sopenharmony_ci */ 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic u64 sys_reg_to_index(const struct sys_reg_desc *reg); 4562306a36Sopenharmony_cistatic int set_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, 4662306a36Sopenharmony_ci u64 val); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic bool read_from_write_only(struct kvm_vcpu *vcpu, 4962306a36Sopenharmony_ci struct sys_reg_params *params, 5062306a36Sopenharmony_ci const struct sys_reg_desc *r) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci WARN_ONCE(1, "Unexpected sys_reg read to write-only register\n"); 5362306a36Sopenharmony_ci print_sys_reg_instr(params); 5462306a36Sopenharmony_ci kvm_inject_undefined(vcpu); 5562306a36Sopenharmony_ci return false; 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic bool write_to_read_only(struct kvm_vcpu *vcpu, 5962306a36Sopenharmony_ci struct sys_reg_params *params, 6062306a36Sopenharmony_ci const struct sys_reg_desc *r) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci WARN_ONCE(1, "Unexpected sys_reg write to read-only register\n"); 6362306a36Sopenharmony_ci print_sys_reg_instr(params); 6462306a36Sopenharmony_ci kvm_inject_undefined(vcpu); 6562306a36Sopenharmony_ci return false; 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ciu64 vcpu_read_sys_reg(const struct kvm_vcpu *vcpu, int reg) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci u64 val = 0x8badf00d8badf00d; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci if (vcpu_get_flag(vcpu, SYSREGS_ON_CPU) && 7362306a36Sopenharmony_ci __vcpu_read_sys_reg_from_cpu(reg, &val)) 7462306a36Sopenharmony_ci return val; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci return __vcpu_sys_reg(vcpu, reg); 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_civoid vcpu_write_sys_reg(struct kvm_vcpu *vcpu, u64 val, int reg) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci if (vcpu_get_flag(vcpu, SYSREGS_ON_CPU) && 8262306a36Sopenharmony_ci __vcpu_write_sys_reg_to_cpu(val, reg)) 8362306a36Sopenharmony_ci return; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci __vcpu_sys_reg(vcpu, reg) = val; 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci/* CSSELR values; used to index KVM_REG_ARM_DEMUX_ID_CCSIDR */ 8962306a36Sopenharmony_ci#define CSSELR_MAX 14 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/* 9262306a36Sopenharmony_ci * Returns the minimum line size for the selected cache, expressed as 9362306a36Sopenharmony_ci * Log2(bytes). 9462306a36Sopenharmony_ci */ 9562306a36Sopenharmony_cistatic u8 get_min_cache_line_size(bool icache) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci u64 ctr = read_sanitised_ftr_reg(SYS_CTR_EL0); 9862306a36Sopenharmony_ci u8 field; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci if (icache) 10162306a36Sopenharmony_ci field = SYS_FIELD_GET(CTR_EL0, IminLine, ctr); 10262306a36Sopenharmony_ci else 10362306a36Sopenharmony_ci field = SYS_FIELD_GET(CTR_EL0, DminLine, ctr); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci /* 10662306a36Sopenharmony_ci * Cache line size is represented as Log2(words) in CTR_EL0. 10762306a36Sopenharmony_ci * Log2(bytes) can be derived with the following: 10862306a36Sopenharmony_ci * 10962306a36Sopenharmony_ci * Log2(words) + 2 = Log2(bytes / 4) + 2 11062306a36Sopenharmony_ci * = Log2(bytes) - 2 + 2 11162306a36Sopenharmony_ci * = Log2(bytes) 11262306a36Sopenharmony_ci */ 11362306a36Sopenharmony_ci return field + 2; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci/* Which cache CCSIDR represents depends on CSSELR value. */ 11762306a36Sopenharmony_cistatic u32 get_ccsidr(struct kvm_vcpu *vcpu, u32 csselr) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci u8 line_size; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci if (vcpu->arch.ccsidr) 12262306a36Sopenharmony_ci return vcpu->arch.ccsidr[csselr]; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci line_size = get_min_cache_line_size(csselr & CSSELR_EL1_InD); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci /* 12762306a36Sopenharmony_ci * Fabricate a CCSIDR value as the overriding value does not exist. 12862306a36Sopenharmony_ci * The real CCSIDR value will not be used as it can vary by the 12962306a36Sopenharmony_ci * physical CPU which the vcpu currently resides in. 13062306a36Sopenharmony_ci * 13162306a36Sopenharmony_ci * The line size is determined with get_min_cache_line_size(), which 13262306a36Sopenharmony_ci * should be valid for all CPUs even if they have different cache 13362306a36Sopenharmony_ci * configuration. 13462306a36Sopenharmony_ci * 13562306a36Sopenharmony_ci * The associativity bits are cleared, meaning the geometry of all data 13662306a36Sopenharmony_ci * and unified caches (which are guaranteed to be PIPT and thus 13762306a36Sopenharmony_ci * non-aliasing) are 1 set and 1 way. 13862306a36Sopenharmony_ci * Guests should not be doing cache operations by set/way at all, and 13962306a36Sopenharmony_ci * for this reason, we trap them and attempt to infer the intent, so 14062306a36Sopenharmony_ci * that we can flush the entire guest's address space at the appropriate 14162306a36Sopenharmony_ci * time. The exposed geometry minimizes the number of the traps. 14262306a36Sopenharmony_ci * [If guests should attempt to infer aliasing properties from the 14362306a36Sopenharmony_ci * geometry (which is not permitted by the architecture), they would 14462306a36Sopenharmony_ci * only do so for virtually indexed caches.] 14562306a36Sopenharmony_ci * 14662306a36Sopenharmony_ci * We don't check if the cache level exists as it is allowed to return 14762306a36Sopenharmony_ci * an UNKNOWN value if not. 14862306a36Sopenharmony_ci */ 14962306a36Sopenharmony_ci return SYS_FIELD_PREP(CCSIDR_EL1, LineSize, line_size - 4); 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic int set_ccsidr(struct kvm_vcpu *vcpu, u32 csselr, u32 val) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci u8 line_size = FIELD_GET(CCSIDR_EL1_LineSize, val) + 4; 15562306a36Sopenharmony_ci u32 *ccsidr = vcpu->arch.ccsidr; 15662306a36Sopenharmony_ci u32 i; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci if ((val & CCSIDR_EL1_RES0) || 15962306a36Sopenharmony_ci line_size < get_min_cache_line_size(csselr & CSSELR_EL1_InD)) 16062306a36Sopenharmony_ci return -EINVAL; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci if (!ccsidr) { 16362306a36Sopenharmony_ci if (val == get_ccsidr(vcpu, csselr)) 16462306a36Sopenharmony_ci return 0; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci ccsidr = kmalloc_array(CSSELR_MAX, sizeof(u32), GFP_KERNEL_ACCOUNT); 16762306a36Sopenharmony_ci if (!ccsidr) 16862306a36Sopenharmony_ci return -ENOMEM; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci for (i = 0; i < CSSELR_MAX; i++) 17162306a36Sopenharmony_ci ccsidr[i] = get_ccsidr(vcpu, i); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci vcpu->arch.ccsidr = ccsidr; 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci ccsidr[csselr] = val; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci return 0; 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic bool access_rw(struct kvm_vcpu *vcpu, 18262306a36Sopenharmony_ci struct sys_reg_params *p, 18362306a36Sopenharmony_ci const struct sys_reg_desc *r) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci if (p->is_write) 18662306a36Sopenharmony_ci vcpu_write_sys_reg(vcpu, p->regval, r->reg); 18762306a36Sopenharmony_ci else 18862306a36Sopenharmony_ci p->regval = vcpu_read_sys_reg(vcpu, r->reg); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci return true; 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci/* 19462306a36Sopenharmony_ci * See note at ARMv7 ARM B1.14.4 (TL;DR: S/W ops are not easily virtualized). 19562306a36Sopenharmony_ci */ 19662306a36Sopenharmony_cistatic bool access_dcsw(struct kvm_vcpu *vcpu, 19762306a36Sopenharmony_ci struct sys_reg_params *p, 19862306a36Sopenharmony_ci const struct sys_reg_desc *r) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci if (!p->is_write) 20162306a36Sopenharmony_ci return read_from_write_only(vcpu, p, r); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci /* 20462306a36Sopenharmony_ci * Only track S/W ops if we don't have FWB. It still indicates 20562306a36Sopenharmony_ci * that the guest is a bit broken (S/W operations should only 20662306a36Sopenharmony_ci * be done by firmware, knowing that there is only a single 20762306a36Sopenharmony_ci * CPU left in the system, and certainly not from non-secure 20862306a36Sopenharmony_ci * software). 20962306a36Sopenharmony_ci */ 21062306a36Sopenharmony_ci if (!cpus_have_const_cap(ARM64_HAS_STAGE2_FWB)) 21162306a36Sopenharmony_ci kvm_set_way_flush(vcpu); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci return true; 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic bool access_dcgsw(struct kvm_vcpu *vcpu, 21762306a36Sopenharmony_ci struct sys_reg_params *p, 21862306a36Sopenharmony_ci const struct sys_reg_desc *r) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci if (!kvm_has_mte(vcpu->kvm)) { 22162306a36Sopenharmony_ci kvm_inject_undefined(vcpu); 22262306a36Sopenharmony_ci return false; 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci /* Treat MTE S/W ops as we treat the classic ones: with contempt */ 22662306a36Sopenharmony_ci return access_dcsw(vcpu, p, r); 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistatic void get_access_mask(const struct sys_reg_desc *r, u64 *mask, u64 *shift) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci switch (r->aarch32_map) { 23262306a36Sopenharmony_ci case AA32_LO: 23362306a36Sopenharmony_ci *mask = GENMASK_ULL(31, 0); 23462306a36Sopenharmony_ci *shift = 0; 23562306a36Sopenharmony_ci break; 23662306a36Sopenharmony_ci case AA32_HI: 23762306a36Sopenharmony_ci *mask = GENMASK_ULL(63, 32); 23862306a36Sopenharmony_ci *shift = 32; 23962306a36Sopenharmony_ci break; 24062306a36Sopenharmony_ci default: 24162306a36Sopenharmony_ci *mask = GENMASK_ULL(63, 0); 24262306a36Sopenharmony_ci *shift = 0; 24362306a36Sopenharmony_ci break; 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci/* 24862306a36Sopenharmony_ci * Generic accessor for VM registers. Only called as long as HCR_TVM 24962306a36Sopenharmony_ci * is set. If the guest enables the MMU, we stop trapping the VM 25062306a36Sopenharmony_ci * sys_regs and leave it in complete control of the caches. 25162306a36Sopenharmony_ci */ 25262306a36Sopenharmony_cistatic bool access_vm_reg(struct kvm_vcpu *vcpu, 25362306a36Sopenharmony_ci struct sys_reg_params *p, 25462306a36Sopenharmony_ci const struct sys_reg_desc *r) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci bool was_enabled = vcpu_has_cache_enabled(vcpu); 25762306a36Sopenharmony_ci u64 val, mask, shift; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci BUG_ON(!p->is_write); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci get_access_mask(r, &mask, &shift); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci if (~mask) { 26462306a36Sopenharmony_ci val = vcpu_read_sys_reg(vcpu, r->reg); 26562306a36Sopenharmony_ci val &= ~mask; 26662306a36Sopenharmony_ci } else { 26762306a36Sopenharmony_ci val = 0; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci val |= (p->regval & (mask >> shift)) << shift; 27162306a36Sopenharmony_ci vcpu_write_sys_reg(vcpu, val, r->reg); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci kvm_toggle_cache(vcpu, was_enabled); 27462306a36Sopenharmony_ci return true; 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic bool access_actlr(struct kvm_vcpu *vcpu, 27862306a36Sopenharmony_ci struct sys_reg_params *p, 27962306a36Sopenharmony_ci const struct sys_reg_desc *r) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci u64 mask, shift; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci if (p->is_write) 28462306a36Sopenharmony_ci return ignore_write(vcpu, p); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci get_access_mask(r, &mask, &shift); 28762306a36Sopenharmony_ci p->regval = (vcpu_read_sys_reg(vcpu, r->reg) & mask) >> shift; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci return true; 29062306a36Sopenharmony_ci} 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci/* 29362306a36Sopenharmony_ci * Trap handler for the GICv3 SGI generation system register. 29462306a36Sopenharmony_ci * Forward the request to the VGIC emulation. 29562306a36Sopenharmony_ci * The cp15_64 code makes sure this automatically works 29662306a36Sopenharmony_ci * for both AArch64 and AArch32 accesses. 29762306a36Sopenharmony_ci */ 29862306a36Sopenharmony_cistatic bool access_gic_sgi(struct kvm_vcpu *vcpu, 29962306a36Sopenharmony_ci struct sys_reg_params *p, 30062306a36Sopenharmony_ci const struct sys_reg_desc *r) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci bool g1; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (!p->is_write) 30562306a36Sopenharmony_ci return read_from_write_only(vcpu, p, r); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci /* 30862306a36Sopenharmony_ci * In a system where GICD_CTLR.DS=1, a ICC_SGI0R_EL1 access generates 30962306a36Sopenharmony_ci * Group0 SGIs only, while ICC_SGI1R_EL1 can generate either group, 31062306a36Sopenharmony_ci * depending on the SGI configuration. ICC_ASGI1R_EL1 is effectively 31162306a36Sopenharmony_ci * equivalent to ICC_SGI0R_EL1, as there is no "alternative" secure 31262306a36Sopenharmony_ci * group. 31362306a36Sopenharmony_ci */ 31462306a36Sopenharmony_ci if (p->Op0 == 0) { /* AArch32 */ 31562306a36Sopenharmony_ci switch (p->Op1) { 31662306a36Sopenharmony_ci default: /* Keep GCC quiet */ 31762306a36Sopenharmony_ci case 0: /* ICC_SGI1R */ 31862306a36Sopenharmony_ci g1 = true; 31962306a36Sopenharmony_ci break; 32062306a36Sopenharmony_ci case 1: /* ICC_ASGI1R */ 32162306a36Sopenharmony_ci case 2: /* ICC_SGI0R */ 32262306a36Sopenharmony_ci g1 = false; 32362306a36Sopenharmony_ci break; 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci } else { /* AArch64 */ 32662306a36Sopenharmony_ci switch (p->Op2) { 32762306a36Sopenharmony_ci default: /* Keep GCC quiet */ 32862306a36Sopenharmony_ci case 5: /* ICC_SGI1R_EL1 */ 32962306a36Sopenharmony_ci g1 = true; 33062306a36Sopenharmony_ci break; 33162306a36Sopenharmony_ci case 6: /* ICC_ASGI1R_EL1 */ 33262306a36Sopenharmony_ci case 7: /* ICC_SGI0R_EL1 */ 33362306a36Sopenharmony_ci g1 = false; 33462306a36Sopenharmony_ci break; 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci vgic_v3_dispatch_sgi(vcpu, p->regval, g1); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci return true; 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cistatic bool access_gic_sre(struct kvm_vcpu *vcpu, 34462306a36Sopenharmony_ci struct sys_reg_params *p, 34562306a36Sopenharmony_ci const struct sys_reg_desc *r) 34662306a36Sopenharmony_ci{ 34762306a36Sopenharmony_ci if (p->is_write) 34862306a36Sopenharmony_ci return ignore_write(vcpu, p); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci p->regval = vcpu->arch.vgic_cpu.vgic_v3.vgic_sre; 35162306a36Sopenharmony_ci return true; 35262306a36Sopenharmony_ci} 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_cistatic bool trap_raz_wi(struct kvm_vcpu *vcpu, 35562306a36Sopenharmony_ci struct sys_reg_params *p, 35662306a36Sopenharmony_ci const struct sys_reg_desc *r) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci if (p->is_write) 35962306a36Sopenharmony_ci return ignore_write(vcpu, p); 36062306a36Sopenharmony_ci else 36162306a36Sopenharmony_ci return read_zero(vcpu, p); 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cistatic bool trap_undef(struct kvm_vcpu *vcpu, 36562306a36Sopenharmony_ci struct sys_reg_params *p, 36662306a36Sopenharmony_ci const struct sys_reg_desc *r) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci kvm_inject_undefined(vcpu); 36962306a36Sopenharmony_ci return false; 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci/* 37362306a36Sopenharmony_ci * ARMv8.1 mandates at least a trivial LORegion implementation, where all the 37462306a36Sopenharmony_ci * RW registers are RES0 (which we can implement as RAZ/WI). On an ARMv8.0 37562306a36Sopenharmony_ci * system, these registers should UNDEF. LORID_EL1 being a RO register, we 37662306a36Sopenharmony_ci * treat it separately. 37762306a36Sopenharmony_ci */ 37862306a36Sopenharmony_cistatic bool trap_loregion(struct kvm_vcpu *vcpu, 37962306a36Sopenharmony_ci struct sys_reg_params *p, 38062306a36Sopenharmony_ci const struct sys_reg_desc *r) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci u64 val = read_sanitised_ftr_reg(SYS_ID_AA64MMFR1_EL1); 38362306a36Sopenharmony_ci u32 sr = reg_to_encoding(r); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci if (!(val & (0xfUL << ID_AA64MMFR1_EL1_LO_SHIFT))) { 38662306a36Sopenharmony_ci kvm_inject_undefined(vcpu); 38762306a36Sopenharmony_ci return false; 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci if (p->is_write && sr == SYS_LORID_EL1) 39162306a36Sopenharmony_ci return write_to_read_only(vcpu, p, r); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci return trap_raz_wi(vcpu, p, r); 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_cistatic bool trap_oslar_el1(struct kvm_vcpu *vcpu, 39762306a36Sopenharmony_ci struct sys_reg_params *p, 39862306a36Sopenharmony_ci const struct sys_reg_desc *r) 39962306a36Sopenharmony_ci{ 40062306a36Sopenharmony_ci u64 oslsr; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci if (!p->is_write) 40362306a36Sopenharmony_ci return read_from_write_only(vcpu, p, r); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci /* Forward the OSLK bit to OSLSR */ 40662306a36Sopenharmony_ci oslsr = __vcpu_sys_reg(vcpu, OSLSR_EL1) & ~OSLSR_EL1_OSLK; 40762306a36Sopenharmony_ci if (p->regval & OSLAR_EL1_OSLK) 40862306a36Sopenharmony_ci oslsr |= OSLSR_EL1_OSLK; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci __vcpu_sys_reg(vcpu, OSLSR_EL1) = oslsr; 41162306a36Sopenharmony_ci return true; 41262306a36Sopenharmony_ci} 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_cistatic bool trap_oslsr_el1(struct kvm_vcpu *vcpu, 41562306a36Sopenharmony_ci struct sys_reg_params *p, 41662306a36Sopenharmony_ci const struct sys_reg_desc *r) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci if (p->is_write) 41962306a36Sopenharmony_ci return write_to_read_only(vcpu, p, r); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci p->regval = __vcpu_sys_reg(vcpu, r->reg); 42262306a36Sopenharmony_ci return true; 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_cistatic int set_oslsr_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, 42662306a36Sopenharmony_ci u64 val) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci /* 42962306a36Sopenharmony_ci * The only modifiable bit is the OSLK bit. Refuse the write if 43062306a36Sopenharmony_ci * userspace attempts to change any other bit in the register. 43162306a36Sopenharmony_ci */ 43262306a36Sopenharmony_ci if ((val ^ rd->val) & ~OSLSR_EL1_OSLK) 43362306a36Sopenharmony_ci return -EINVAL; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci __vcpu_sys_reg(vcpu, rd->reg) = val; 43662306a36Sopenharmony_ci return 0; 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cistatic bool trap_dbgauthstatus_el1(struct kvm_vcpu *vcpu, 44062306a36Sopenharmony_ci struct sys_reg_params *p, 44162306a36Sopenharmony_ci const struct sys_reg_desc *r) 44262306a36Sopenharmony_ci{ 44362306a36Sopenharmony_ci if (p->is_write) { 44462306a36Sopenharmony_ci return ignore_write(vcpu, p); 44562306a36Sopenharmony_ci } else { 44662306a36Sopenharmony_ci p->regval = read_sysreg(dbgauthstatus_el1); 44762306a36Sopenharmony_ci return true; 44862306a36Sopenharmony_ci } 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci/* 45262306a36Sopenharmony_ci * We want to avoid world-switching all the DBG registers all the 45362306a36Sopenharmony_ci * time: 45462306a36Sopenharmony_ci * 45562306a36Sopenharmony_ci * - If we've touched any debug register, it is likely that we're 45662306a36Sopenharmony_ci * going to touch more of them. It then makes sense to disable the 45762306a36Sopenharmony_ci * traps and start doing the save/restore dance 45862306a36Sopenharmony_ci * - If debug is active (DBG_MDSCR_KDE or DBG_MDSCR_MDE set), it is 45962306a36Sopenharmony_ci * then mandatory to save/restore the registers, as the guest 46062306a36Sopenharmony_ci * depends on them. 46162306a36Sopenharmony_ci * 46262306a36Sopenharmony_ci * For this, we use a DIRTY bit, indicating the guest has modified the 46362306a36Sopenharmony_ci * debug registers, used as follow: 46462306a36Sopenharmony_ci * 46562306a36Sopenharmony_ci * On guest entry: 46662306a36Sopenharmony_ci * - If the dirty bit is set (because we're coming back from trapping), 46762306a36Sopenharmony_ci * disable the traps, save host registers, restore guest registers. 46862306a36Sopenharmony_ci * - If debug is actively in use (DBG_MDSCR_KDE or DBG_MDSCR_MDE set), 46962306a36Sopenharmony_ci * set the dirty bit, disable the traps, save host registers, 47062306a36Sopenharmony_ci * restore guest registers. 47162306a36Sopenharmony_ci * - Otherwise, enable the traps 47262306a36Sopenharmony_ci * 47362306a36Sopenharmony_ci * On guest exit: 47462306a36Sopenharmony_ci * - If the dirty bit is set, save guest registers, restore host 47562306a36Sopenharmony_ci * registers and clear the dirty bit. This ensure that the host can 47662306a36Sopenharmony_ci * now use the debug registers. 47762306a36Sopenharmony_ci */ 47862306a36Sopenharmony_cistatic bool trap_debug_regs(struct kvm_vcpu *vcpu, 47962306a36Sopenharmony_ci struct sys_reg_params *p, 48062306a36Sopenharmony_ci const struct sys_reg_desc *r) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci access_rw(vcpu, p, r); 48362306a36Sopenharmony_ci if (p->is_write) 48462306a36Sopenharmony_ci vcpu_set_flag(vcpu, DEBUG_DIRTY); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci trace_trap_reg(__func__, r->reg, p->is_write, p->regval); 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci return true; 48962306a36Sopenharmony_ci} 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci/* 49262306a36Sopenharmony_ci * reg_to_dbg/dbg_to_reg 49362306a36Sopenharmony_ci * 49462306a36Sopenharmony_ci * A 32 bit write to a debug register leave top bits alone 49562306a36Sopenharmony_ci * A 32 bit read from a debug register only returns the bottom bits 49662306a36Sopenharmony_ci * 49762306a36Sopenharmony_ci * All writes will set the DEBUG_DIRTY flag to ensure the hyp code 49862306a36Sopenharmony_ci * switches between host and guest values in future. 49962306a36Sopenharmony_ci */ 50062306a36Sopenharmony_cistatic void reg_to_dbg(struct kvm_vcpu *vcpu, 50162306a36Sopenharmony_ci struct sys_reg_params *p, 50262306a36Sopenharmony_ci const struct sys_reg_desc *rd, 50362306a36Sopenharmony_ci u64 *dbg_reg) 50462306a36Sopenharmony_ci{ 50562306a36Sopenharmony_ci u64 mask, shift, val; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci get_access_mask(rd, &mask, &shift); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci val = *dbg_reg; 51062306a36Sopenharmony_ci val &= ~mask; 51162306a36Sopenharmony_ci val |= (p->regval & (mask >> shift)) << shift; 51262306a36Sopenharmony_ci *dbg_reg = val; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci vcpu_set_flag(vcpu, DEBUG_DIRTY); 51562306a36Sopenharmony_ci} 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_cistatic void dbg_to_reg(struct kvm_vcpu *vcpu, 51862306a36Sopenharmony_ci struct sys_reg_params *p, 51962306a36Sopenharmony_ci const struct sys_reg_desc *rd, 52062306a36Sopenharmony_ci u64 *dbg_reg) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci u64 mask, shift; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci get_access_mask(rd, &mask, &shift); 52562306a36Sopenharmony_ci p->regval = (*dbg_reg & mask) >> shift; 52662306a36Sopenharmony_ci} 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_cistatic bool trap_bvr(struct kvm_vcpu *vcpu, 52962306a36Sopenharmony_ci struct sys_reg_params *p, 53062306a36Sopenharmony_ci const struct sys_reg_desc *rd) 53162306a36Sopenharmony_ci{ 53262306a36Sopenharmony_ci u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_bvr[rd->CRm]; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci if (p->is_write) 53562306a36Sopenharmony_ci reg_to_dbg(vcpu, p, rd, dbg_reg); 53662306a36Sopenharmony_ci else 53762306a36Sopenharmony_ci dbg_to_reg(vcpu, p, rd, dbg_reg); 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci trace_trap_reg(__func__, rd->CRm, p->is_write, *dbg_reg); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci return true; 54262306a36Sopenharmony_ci} 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_cistatic int set_bvr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, 54562306a36Sopenharmony_ci u64 val) 54662306a36Sopenharmony_ci{ 54762306a36Sopenharmony_ci vcpu->arch.vcpu_debug_state.dbg_bvr[rd->CRm] = val; 54862306a36Sopenharmony_ci return 0; 54962306a36Sopenharmony_ci} 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_cistatic int get_bvr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, 55262306a36Sopenharmony_ci u64 *val) 55362306a36Sopenharmony_ci{ 55462306a36Sopenharmony_ci *val = vcpu->arch.vcpu_debug_state.dbg_bvr[rd->CRm]; 55562306a36Sopenharmony_ci return 0; 55662306a36Sopenharmony_ci} 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_cistatic u64 reset_bvr(struct kvm_vcpu *vcpu, 55962306a36Sopenharmony_ci const struct sys_reg_desc *rd) 56062306a36Sopenharmony_ci{ 56162306a36Sopenharmony_ci vcpu->arch.vcpu_debug_state.dbg_bvr[rd->CRm] = rd->val; 56262306a36Sopenharmony_ci return rd->val; 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_cistatic bool trap_bcr(struct kvm_vcpu *vcpu, 56662306a36Sopenharmony_ci struct sys_reg_params *p, 56762306a36Sopenharmony_ci const struct sys_reg_desc *rd) 56862306a36Sopenharmony_ci{ 56962306a36Sopenharmony_ci u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_bcr[rd->CRm]; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci if (p->is_write) 57262306a36Sopenharmony_ci reg_to_dbg(vcpu, p, rd, dbg_reg); 57362306a36Sopenharmony_ci else 57462306a36Sopenharmony_ci dbg_to_reg(vcpu, p, rd, dbg_reg); 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci trace_trap_reg(__func__, rd->CRm, p->is_write, *dbg_reg); 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci return true; 57962306a36Sopenharmony_ci} 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_cistatic int set_bcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, 58262306a36Sopenharmony_ci u64 val) 58362306a36Sopenharmony_ci{ 58462306a36Sopenharmony_ci vcpu->arch.vcpu_debug_state.dbg_bcr[rd->CRm] = val; 58562306a36Sopenharmony_ci return 0; 58662306a36Sopenharmony_ci} 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_cistatic int get_bcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, 58962306a36Sopenharmony_ci u64 *val) 59062306a36Sopenharmony_ci{ 59162306a36Sopenharmony_ci *val = vcpu->arch.vcpu_debug_state.dbg_bcr[rd->CRm]; 59262306a36Sopenharmony_ci return 0; 59362306a36Sopenharmony_ci} 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_cistatic u64 reset_bcr(struct kvm_vcpu *vcpu, 59662306a36Sopenharmony_ci const struct sys_reg_desc *rd) 59762306a36Sopenharmony_ci{ 59862306a36Sopenharmony_ci vcpu->arch.vcpu_debug_state.dbg_bcr[rd->CRm] = rd->val; 59962306a36Sopenharmony_ci return rd->val; 60062306a36Sopenharmony_ci} 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_cistatic bool trap_wvr(struct kvm_vcpu *vcpu, 60362306a36Sopenharmony_ci struct sys_reg_params *p, 60462306a36Sopenharmony_ci const struct sys_reg_desc *rd) 60562306a36Sopenharmony_ci{ 60662306a36Sopenharmony_ci u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_wvr[rd->CRm]; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci if (p->is_write) 60962306a36Sopenharmony_ci reg_to_dbg(vcpu, p, rd, dbg_reg); 61062306a36Sopenharmony_ci else 61162306a36Sopenharmony_ci dbg_to_reg(vcpu, p, rd, dbg_reg); 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci trace_trap_reg(__func__, rd->CRm, p->is_write, 61462306a36Sopenharmony_ci vcpu->arch.vcpu_debug_state.dbg_wvr[rd->CRm]); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci return true; 61762306a36Sopenharmony_ci} 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_cistatic int set_wvr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, 62062306a36Sopenharmony_ci u64 val) 62162306a36Sopenharmony_ci{ 62262306a36Sopenharmony_ci vcpu->arch.vcpu_debug_state.dbg_wvr[rd->CRm] = val; 62362306a36Sopenharmony_ci return 0; 62462306a36Sopenharmony_ci} 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_cistatic int get_wvr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, 62762306a36Sopenharmony_ci u64 *val) 62862306a36Sopenharmony_ci{ 62962306a36Sopenharmony_ci *val = vcpu->arch.vcpu_debug_state.dbg_wvr[rd->CRm]; 63062306a36Sopenharmony_ci return 0; 63162306a36Sopenharmony_ci} 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_cistatic u64 reset_wvr(struct kvm_vcpu *vcpu, 63462306a36Sopenharmony_ci const struct sys_reg_desc *rd) 63562306a36Sopenharmony_ci{ 63662306a36Sopenharmony_ci vcpu->arch.vcpu_debug_state.dbg_wvr[rd->CRm] = rd->val; 63762306a36Sopenharmony_ci return rd->val; 63862306a36Sopenharmony_ci} 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_cistatic bool trap_wcr(struct kvm_vcpu *vcpu, 64162306a36Sopenharmony_ci struct sys_reg_params *p, 64262306a36Sopenharmony_ci const struct sys_reg_desc *rd) 64362306a36Sopenharmony_ci{ 64462306a36Sopenharmony_ci u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_wcr[rd->CRm]; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci if (p->is_write) 64762306a36Sopenharmony_ci reg_to_dbg(vcpu, p, rd, dbg_reg); 64862306a36Sopenharmony_ci else 64962306a36Sopenharmony_ci dbg_to_reg(vcpu, p, rd, dbg_reg); 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci trace_trap_reg(__func__, rd->CRm, p->is_write, *dbg_reg); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci return true; 65462306a36Sopenharmony_ci} 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_cistatic int set_wcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, 65762306a36Sopenharmony_ci u64 val) 65862306a36Sopenharmony_ci{ 65962306a36Sopenharmony_ci vcpu->arch.vcpu_debug_state.dbg_wcr[rd->CRm] = val; 66062306a36Sopenharmony_ci return 0; 66162306a36Sopenharmony_ci} 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_cistatic int get_wcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, 66462306a36Sopenharmony_ci u64 *val) 66562306a36Sopenharmony_ci{ 66662306a36Sopenharmony_ci *val = vcpu->arch.vcpu_debug_state.dbg_wcr[rd->CRm]; 66762306a36Sopenharmony_ci return 0; 66862306a36Sopenharmony_ci} 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_cistatic u64 reset_wcr(struct kvm_vcpu *vcpu, 67162306a36Sopenharmony_ci const struct sys_reg_desc *rd) 67262306a36Sopenharmony_ci{ 67362306a36Sopenharmony_ci vcpu->arch.vcpu_debug_state.dbg_wcr[rd->CRm] = rd->val; 67462306a36Sopenharmony_ci return rd->val; 67562306a36Sopenharmony_ci} 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_cistatic u64 reset_amair_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r) 67862306a36Sopenharmony_ci{ 67962306a36Sopenharmony_ci u64 amair = read_sysreg(amair_el1); 68062306a36Sopenharmony_ci vcpu_write_sys_reg(vcpu, amair, AMAIR_EL1); 68162306a36Sopenharmony_ci return amair; 68262306a36Sopenharmony_ci} 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_cistatic u64 reset_actlr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r) 68562306a36Sopenharmony_ci{ 68662306a36Sopenharmony_ci u64 actlr = read_sysreg(actlr_el1); 68762306a36Sopenharmony_ci vcpu_write_sys_reg(vcpu, actlr, ACTLR_EL1); 68862306a36Sopenharmony_ci return actlr; 68962306a36Sopenharmony_ci} 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_cistatic u64 reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r) 69262306a36Sopenharmony_ci{ 69362306a36Sopenharmony_ci u64 mpidr; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci /* 69662306a36Sopenharmony_ci * Map the vcpu_id into the first three affinity level fields of 69762306a36Sopenharmony_ci * the MPIDR. We limit the number of VCPUs in level 0 due to a 69862306a36Sopenharmony_ci * limitation to 16 CPUs in that level in the ICC_SGIxR registers 69962306a36Sopenharmony_ci * of the GICv3 to be able to address each CPU directly when 70062306a36Sopenharmony_ci * sending IPIs. 70162306a36Sopenharmony_ci */ 70262306a36Sopenharmony_ci mpidr = (vcpu->vcpu_id & 0x0f) << MPIDR_LEVEL_SHIFT(0); 70362306a36Sopenharmony_ci mpidr |= ((vcpu->vcpu_id >> 4) & 0xff) << MPIDR_LEVEL_SHIFT(1); 70462306a36Sopenharmony_ci mpidr |= ((vcpu->vcpu_id >> 12) & 0xff) << MPIDR_LEVEL_SHIFT(2); 70562306a36Sopenharmony_ci mpidr |= (1ULL << 31); 70662306a36Sopenharmony_ci vcpu_write_sys_reg(vcpu, mpidr, MPIDR_EL1); 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci return mpidr; 70962306a36Sopenharmony_ci} 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_cistatic unsigned int pmu_visibility(const struct kvm_vcpu *vcpu, 71262306a36Sopenharmony_ci const struct sys_reg_desc *r) 71362306a36Sopenharmony_ci{ 71462306a36Sopenharmony_ci if (kvm_vcpu_has_pmu(vcpu)) 71562306a36Sopenharmony_ci return 0; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci return REG_HIDDEN; 71862306a36Sopenharmony_ci} 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_cistatic u64 reset_pmu_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r) 72162306a36Sopenharmony_ci{ 72262306a36Sopenharmony_ci u64 n, mask = BIT(ARMV8_PMU_CYCLE_IDX); 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci /* No PMU available, any PMU reg may UNDEF... */ 72562306a36Sopenharmony_ci if (!kvm_arm_support_pmu_v3()) 72662306a36Sopenharmony_ci return 0; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci n = read_sysreg(pmcr_el0) >> ARMV8_PMU_PMCR_N_SHIFT; 72962306a36Sopenharmony_ci n &= ARMV8_PMU_PMCR_N_MASK; 73062306a36Sopenharmony_ci if (n) 73162306a36Sopenharmony_ci mask |= GENMASK(n - 1, 0); 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci reset_unknown(vcpu, r); 73462306a36Sopenharmony_ci __vcpu_sys_reg(vcpu, r->reg) &= mask; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci return __vcpu_sys_reg(vcpu, r->reg); 73762306a36Sopenharmony_ci} 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_cistatic u64 reset_pmevcntr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r) 74062306a36Sopenharmony_ci{ 74162306a36Sopenharmony_ci reset_unknown(vcpu, r); 74262306a36Sopenharmony_ci __vcpu_sys_reg(vcpu, r->reg) &= GENMASK(31, 0); 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci return __vcpu_sys_reg(vcpu, r->reg); 74562306a36Sopenharmony_ci} 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_cistatic u64 reset_pmevtyper(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r) 74862306a36Sopenharmony_ci{ 74962306a36Sopenharmony_ci reset_unknown(vcpu, r); 75062306a36Sopenharmony_ci __vcpu_sys_reg(vcpu, r->reg) &= ARMV8_PMU_EVTYPE_MASK; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci return __vcpu_sys_reg(vcpu, r->reg); 75362306a36Sopenharmony_ci} 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_cistatic u64 reset_pmselr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r) 75662306a36Sopenharmony_ci{ 75762306a36Sopenharmony_ci reset_unknown(vcpu, r); 75862306a36Sopenharmony_ci __vcpu_sys_reg(vcpu, r->reg) &= ARMV8_PMU_COUNTER_MASK; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci return __vcpu_sys_reg(vcpu, r->reg); 76162306a36Sopenharmony_ci} 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_cistatic u64 reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r) 76462306a36Sopenharmony_ci{ 76562306a36Sopenharmony_ci u64 pmcr; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci /* No PMU available, PMCR_EL0 may UNDEF... */ 76862306a36Sopenharmony_ci if (!kvm_arm_support_pmu_v3()) 76962306a36Sopenharmony_ci return 0; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci /* Only preserve PMCR_EL0.N, and reset the rest to 0 */ 77262306a36Sopenharmony_ci pmcr = read_sysreg(pmcr_el0) & (ARMV8_PMU_PMCR_N_MASK << ARMV8_PMU_PMCR_N_SHIFT); 77362306a36Sopenharmony_ci if (!kvm_supports_32bit_el0()) 77462306a36Sopenharmony_ci pmcr |= ARMV8_PMU_PMCR_LC; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci __vcpu_sys_reg(vcpu, r->reg) = pmcr; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci return __vcpu_sys_reg(vcpu, r->reg); 77962306a36Sopenharmony_ci} 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_cistatic bool check_pmu_access_disabled(struct kvm_vcpu *vcpu, u64 flags) 78262306a36Sopenharmony_ci{ 78362306a36Sopenharmony_ci u64 reg = __vcpu_sys_reg(vcpu, PMUSERENR_EL0); 78462306a36Sopenharmony_ci bool enabled = (reg & flags) || vcpu_mode_priv(vcpu); 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci if (!enabled) 78762306a36Sopenharmony_ci kvm_inject_undefined(vcpu); 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci return !enabled; 79062306a36Sopenharmony_ci} 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_cistatic bool pmu_access_el0_disabled(struct kvm_vcpu *vcpu) 79362306a36Sopenharmony_ci{ 79462306a36Sopenharmony_ci return check_pmu_access_disabled(vcpu, ARMV8_PMU_USERENR_EN); 79562306a36Sopenharmony_ci} 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_cistatic bool pmu_write_swinc_el0_disabled(struct kvm_vcpu *vcpu) 79862306a36Sopenharmony_ci{ 79962306a36Sopenharmony_ci return check_pmu_access_disabled(vcpu, ARMV8_PMU_USERENR_SW | ARMV8_PMU_USERENR_EN); 80062306a36Sopenharmony_ci} 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_cistatic bool pmu_access_cycle_counter_el0_disabled(struct kvm_vcpu *vcpu) 80362306a36Sopenharmony_ci{ 80462306a36Sopenharmony_ci return check_pmu_access_disabled(vcpu, ARMV8_PMU_USERENR_CR | ARMV8_PMU_USERENR_EN); 80562306a36Sopenharmony_ci} 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_cistatic bool pmu_access_event_counter_el0_disabled(struct kvm_vcpu *vcpu) 80862306a36Sopenharmony_ci{ 80962306a36Sopenharmony_ci return check_pmu_access_disabled(vcpu, ARMV8_PMU_USERENR_ER | ARMV8_PMU_USERENR_EN); 81062306a36Sopenharmony_ci} 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_cistatic bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p, 81362306a36Sopenharmony_ci const struct sys_reg_desc *r) 81462306a36Sopenharmony_ci{ 81562306a36Sopenharmony_ci u64 val; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci if (pmu_access_el0_disabled(vcpu)) 81862306a36Sopenharmony_ci return false; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci if (p->is_write) { 82162306a36Sopenharmony_ci /* 82262306a36Sopenharmony_ci * Only update writeable bits of PMCR (continuing into 82362306a36Sopenharmony_ci * kvm_pmu_handle_pmcr() as well) 82462306a36Sopenharmony_ci */ 82562306a36Sopenharmony_ci val = __vcpu_sys_reg(vcpu, PMCR_EL0); 82662306a36Sopenharmony_ci val &= ~ARMV8_PMU_PMCR_MASK; 82762306a36Sopenharmony_ci val |= p->regval & ARMV8_PMU_PMCR_MASK; 82862306a36Sopenharmony_ci if (!kvm_supports_32bit_el0()) 82962306a36Sopenharmony_ci val |= ARMV8_PMU_PMCR_LC; 83062306a36Sopenharmony_ci kvm_pmu_handle_pmcr(vcpu, val); 83162306a36Sopenharmony_ci } else { 83262306a36Sopenharmony_ci /* PMCR.P & PMCR.C are RAZ */ 83362306a36Sopenharmony_ci val = __vcpu_sys_reg(vcpu, PMCR_EL0) 83462306a36Sopenharmony_ci & ~(ARMV8_PMU_PMCR_P | ARMV8_PMU_PMCR_C); 83562306a36Sopenharmony_ci p->regval = val; 83662306a36Sopenharmony_ci } 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci return true; 83962306a36Sopenharmony_ci} 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_cistatic bool access_pmselr(struct kvm_vcpu *vcpu, struct sys_reg_params *p, 84262306a36Sopenharmony_ci const struct sys_reg_desc *r) 84362306a36Sopenharmony_ci{ 84462306a36Sopenharmony_ci if (pmu_access_event_counter_el0_disabled(vcpu)) 84562306a36Sopenharmony_ci return false; 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci if (p->is_write) 84862306a36Sopenharmony_ci __vcpu_sys_reg(vcpu, PMSELR_EL0) = p->regval; 84962306a36Sopenharmony_ci else 85062306a36Sopenharmony_ci /* return PMSELR.SEL field */ 85162306a36Sopenharmony_ci p->regval = __vcpu_sys_reg(vcpu, PMSELR_EL0) 85262306a36Sopenharmony_ci & ARMV8_PMU_COUNTER_MASK; 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci return true; 85562306a36Sopenharmony_ci} 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_cistatic bool access_pmceid(struct kvm_vcpu *vcpu, struct sys_reg_params *p, 85862306a36Sopenharmony_ci const struct sys_reg_desc *r) 85962306a36Sopenharmony_ci{ 86062306a36Sopenharmony_ci u64 pmceid, mask, shift; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci BUG_ON(p->is_write); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci if (pmu_access_el0_disabled(vcpu)) 86562306a36Sopenharmony_ci return false; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci get_access_mask(r, &mask, &shift); 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci pmceid = kvm_pmu_get_pmceid(vcpu, (p->Op2 & 1)); 87062306a36Sopenharmony_ci pmceid &= mask; 87162306a36Sopenharmony_ci pmceid >>= shift; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci p->regval = pmceid; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci return true; 87662306a36Sopenharmony_ci} 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_cistatic bool pmu_counter_idx_valid(struct kvm_vcpu *vcpu, u64 idx) 87962306a36Sopenharmony_ci{ 88062306a36Sopenharmony_ci u64 pmcr, val; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci pmcr = __vcpu_sys_reg(vcpu, PMCR_EL0); 88362306a36Sopenharmony_ci val = (pmcr >> ARMV8_PMU_PMCR_N_SHIFT) & ARMV8_PMU_PMCR_N_MASK; 88462306a36Sopenharmony_ci if (idx >= val && idx != ARMV8_PMU_CYCLE_IDX) { 88562306a36Sopenharmony_ci kvm_inject_undefined(vcpu); 88662306a36Sopenharmony_ci return false; 88762306a36Sopenharmony_ci } 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci return true; 89062306a36Sopenharmony_ci} 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_cistatic int get_pmu_evcntr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, 89362306a36Sopenharmony_ci u64 *val) 89462306a36Sopenharmony_ci{ 89562306a36Sopenharmony_ci u64 idx; 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci if (r->CRn == 9 && r->CRm == 13 && r->Op2 == 0) 89862306a36Sopenharmony_ci /* PMCCNTR_EL0 */ 89962306a36Sopenharmony_ci idx = ARMV8_PMU_CYCLE_IDX; 90062306a36Sopenharmony_ci else 90162306a36Sopenharmony_ci /* PMEVCNTRn_EL0 */ 90262306a36Sopenharmony_ci idx = ((r->CRm & 3) << 3) | (r->Op2 & 7); 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci *val = kvm_pmu_get_counter_value(vcpu, idx); 90562306a36Sopenharmony_ci return 0; 90662306a36Sopenharmony_ci} 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_cistatic bool access_pmu_evcntr(struct kvm_vcpu *vcpu, 90962306a36Sopenharmony_ci struct sys_reg_params *p, 91062306a36Sopenharmony_ci const struct sys_reg_desc *r) 91162306a36Sopenharmony_ci{ 91262306a36Sopenharmony_ci u64 idx = ~0UL; 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci if (r->CRn == 9 && r->CRm == 13) { 91562306a36Sopenharmony_ci if (r->Op2 == 2) { 91662306a36Sopenharmony_ci /* PMXEVCNTR_EL0 */ 91762306a36Sopenharmony_ci if (pmu_access_event_counter_el0_disabled(vcpu)) 91862306a36Sopenharmony_ci return false; 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci idx = __vcpu_sys_reg(vcpu, PMSELR_EL0) 92162306a36Sopenharmony_ci & ARMV8_PMU_COUNTER_MASK; 92262306a36Sopenharmony_ci } else if (r->Op2 == 0) { 92362306a36Sopenharmony_ci /* PMCCNTR_EL0 */ 92462306a36Sopenharmony_ci if (pmu_access_cycle_counter_el0_disabled(vcpu)) 92562306a36Sopenharmony_ci return false; 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci idx = ARMV8_PMU_CYCLE_IDX; 92862306a36Sopenharmony_ci } 92962306a36Sopenharmony_ci } else if (r->CRn == 0 && r->CRm == 9) { 93062306a36Sopenharmony_ci /* PMCCNTR */ 93162306a36Sopenharmony_ci if (pmu_access_event_counter_el0_disabled(vcpu)) 93262306a36Sopenharmony_ci return false; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci idx = ARMV8_PMU_CYCLE_IDX; 93562306a36Sopenharmony_ci } else if (r->CRn == 14 && (r->CRm & 12) == 8) { 93662306a36Sopenharmony_ci /* PMEVCNTRn_EL0 */ 93762306a36Sopenharmony_ci if (pmu_access_event_counter_el0_disabled(vcpu)) 93862306a36Sopenharmony_ci return false; 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci idx = ((r->CRm & 3) << 3) | (r->Op2 & 7); 94162306a36Sopenharmony_ci } 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci /* Catch any decoding mistake */ 94462306a36Sopenharmony_ci WARN_ON(idx == ~0UL); 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci if (!pmu_counter_idx_valid(vcpu, idx)) 94762306a36Sopenharmony_ci return false; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci if (p->is_write) { 95062306a36Sopenharmony_ci if (pmu_access_el0_disabled(vcpu)) 95162306a36Sopenharmony_ci return false; 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci kvm_pmu_set_counter_value(vcpu, idx, p->regval); 95462306a36Sopenharmony_ci } else { 95562306a36Sopenharmony_ci p->regval = kvm_pmu_get_counter_value(vcpu, idx); 95662306a36Sopenharmony_ci } 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci return true; 95962306a36Sopenharmony_ci} 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_cistatic bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p, 96262306a36Sopenharmony_ci const struct sys_reg_desc *r) 96362306a36Sopenharmony_ci{ 96462306a36Sopenharmony_ci u64 idx, reg; 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci if (pmu_access_el0_disabled(vcpu)) 96762306a36Sopenharmony_ci return false; 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci if (r->CRn == 9 && r->CRm == 13 && r->Op2 == 1) { 97062306a36Sopenharmony_ci /* PMXEVTYPER_EL0 */ 97162306a36Sopenharmony_ci idx = __vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_PMU_COUNTER_MASK; 97262306a36Sopenharmony_ci reg = PMEVTYPER0_EL0 + idx; 97362306a36Sopenharmony_ci } else if (r->CRn == 14 && (r->CRm & 12) == 12) { 97462306a36Sopenharmony_ci idx = ((r->CRm & 3) << 3) | (r->Op2 & 7); 97562306a36Sopenharmony_ci if (idx == ARMV8_PMU_CYCLE_IDX) 97662306a36Sopenharmony_ci reg = PMCCFILTR_EL0; 97762306a36Sopenharmony_ci else 97862306a36Sopenharmony_ci /* PMEVTYPERn_EL0 */ 97962306a36Sopenharmony_ci reg = PMEVTYPER0_EL0 + idx; 98062306a36Sopenharmony_ci } else { 98162306a36Sopenharmony_ci BUG(); 98262306a36Sopenharmony_ci } 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci if (!pmu_counter_idx_valid(vcpu, idx)) 98562306a36Sopenharmony_ci return false; 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci if (p->is_write) { 98862306a36Sopenharmony_ci kvm_pmu_set_counter_event_type(vcpu, p->regval, idx); 98962306a36Sopenharmony_ci kvm_vcpu_pmu_restore_guest(vcpu); 99062306a36Sopenharmony_ci } else { 99162306a36Sopenharmony_ci p->regval = __vcpu_sys_reg(vcpu, reg) & ARMV8_PMU_EVTYPE_MASK; 99262306a36Sopenharmony_ci } 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci return true; 99562306a36Sopenharmony_ci} 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_cistatic bool access_pmcnten(struct kvm_vcpu *vcpu, struct sys_reg_params *p, 99862306a36Sopenharmony_ci const struct sys_reg_desc *r) 99962306a36Sopenharmony_ci{ 100062306a36Sopenharmony_ci u64 val, mask; 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci if (pmu_access_el0_disabled(vcpu)) 100362306a36Sopenharmony_ci return false; 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci mask = kvm_pmu_valid_counter_mask(vcpu); 100662306a36Sopenharmony_ci if (p->is_write) { 100762306a36Sopenharmony_ci val = p->regval & mask; 100862306a36Sopenharmony_ci if (r->Op2 & 0x1) { 100962306a36Sopenharmony_ci /* accessing PMCNTENSET_EL0 */ 101062306a36Sopenharmony_ci __vcpu_sys_reg(vcpu, PMCNTENSET_EL0) |= val; 101162306a36Sopenharmony_ci kvm_pmu_enable_counter_mask(vcpu, val); 101262306a36Sopenharmony_ci kvm_vcpu_pmu_restore_guest(vcpu); 101362306a36Sopenharmony_ci } else { 101462306a36Sopenharmony_ci /* accessing PMCNTENCLR_EL0 */ 101562306a36Sopenharmony_ci __vcpu_sys_reg(vcpu, PMCNTENSET_EL0) &= ~val; 101662306a36Sopenharmony_ci kvm_pmu_disable_counter_mask(vcpu, val); 101762306a36Sopenharmony_ci } 101862306a36Sopenharmony_ci } else { 101962306a36Sopenharmony_ci p->regval = __vcpu_sys_reg(vcpu, PMCNTENSET_EL0); 102062306a36Sopenharmony_ci } 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci return true; 102362306a36Sopenharmony_ci} 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_cistatic bool access_pminten(struct kvm_vcpu *vcpu, struct sys_reg_params *p, 102662306a36Sopenharmony_ci const struct sys_reg_desc *r) 102762306a36Sopenharmony_ci{ 102862306a36Sopenharmony_ci u64 mask = kvm_pmu_valid_counter_mask(vcpu); 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci if (check_pmu_access_disabled(vcpu, 0)) 103162306a36Sopenharmony_ci return false; 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci if (p->is_write) { 103462306a36Sopenharmony_ci u64 val = p->regval & mask; 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci if (r->Op2 & 0x1) 103762306a36Sopenharmony_ci /* accessing PMINTENSET_EL1 */ 103862306a36Sopenharmony_ci __vcpu_sys_reg(vcpu, PMINTENSET_EL1) |= val; 103962306a36Sopenharmony_ci else 104062306a36Sopenharmony_ci /* accessing PMINTENCLR_EL1 */ 104162306a36Sopenharmony_ci __vcpu_sys_reg(vcpu, PMINTENSET_EL1) &= ~val; 104262306a36Sopenharmony_ci } else { 104362306a36Sopenharmony_ci p->regval = __vcpu_sys_reg(vcpu, PMINTENSET_EL1); 104462306a36Sopenharmony_ci } 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci return true; 104762306a36Sopenharmony_ci} 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_cistatic bool access_pmovs(struct kvm_vcpu *vcpu, struct sys_reg_params *p, 105062306a36Sopenharmony_ci const struct sys_reg_desc *r) 105162306a36Sopenharmony_ci{ 105262306a36Sopenharmony_ci u64 mask = kvm_pmu_valid_counter_mask(vcpu); 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci if (pmu_access_el0_disabled(vcpu)) 105562306a36Sopenharmony_ci return false; 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci if (p->is_write) { 105862306a36Sopenharmony_ci if (r->CRm & 0x2) 105962306a36Sopenharmony_ci /* accessing PMOVSSET_EL0 */ 106062306a36Sopenharmony_ci __vcpu_sys_reg(vcpu, PMOVSSET_EL0) |= (p->regval & mask); 106162306a36Sopenharmony_ci else 106262306a36Sopenharmony_ci /* accessing PMOVSCLR_EL0 */ 106362306a36Sopenharmony_ci __vcpu_sys_reg(vcpu, PMOVSSET_EL0) &= ~(p->regval & mask); 106462306a36Sopenharmony_ci } else { 106562306a36Sopenharmony_ci p->regval = __vcpu_sys_reg(vcpu, PMOVSSET_EL0); 106662306a36Sopenharmony_ci } 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci return true; 106962306a36Sopenharmony_ci} 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_cistatic bool access_pmswinc(struct kvm_vcpu *vcpu, struct sys_reg_params *p, 107262306a36Sopenharmony_ci const struct sys_reg_desc *r) 107362306a36Sopenharmony_ci{ 107462306a36Sopenharmony_ci u64 mask; 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci if (!p->is_write) 107762306a36Sopenharmony_ci return read_from_write_only(vcpu, p, r); 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci if (pmu_write_swinc_el0_disabled(vcpu)) 108062306a36Sopenharmony_ci return false; 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci mask = kvm_pmu_valid_counter_mask(vcpu); 108362306a36Sopenharmony_ci kvm_pmu_software_increment(vcpu, p->regval & mask); 108462306a36Sopenharmony_ci return true; 108562306a36Sopenharmony_ci} 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_cistatic bool access_pmuserenr(struct kvm_vcpu *vcpu, struct sys_reg_params *p, 108862306a36Sopenharmony_ci const struct sys_reg_desc *r) 108962306a36Sopenharmony_ci{ 109062306a36Sopenharmony_ci if (p->is_write) { 109162306a36Sopenharmony_ci if (!vcpu_mode_priv(vcpu)) { 109262306a36Sopenharmony_ci kvm_inject_undefined(vcpu); 109362306a36Sopenharmony_ci return false; 109462306a36Sopenharmony_ci } 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci __vcpu_sys_reg(vcpu, PMUSERENR_EL0) = 109762306a36Sopenharmony_ci p->regval & ARMV8_PMU_USERENR_MASK; 109862306a36Sopenharmony_ci } else { 109962306a36Sopenharmony_ci p->regval = __vcpu_sys_reg(vcpu, PMUSERENR_EL0) 110062306a36Sopenharmony_ci & ARMV8_PMU_USERENR_MASK; 110162306a36Sopenharmony_ci } 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci return true; 110462306a36Sopenharmony_ci} 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci/* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */ 110762306a36Sopenharmony_ci#define DBG_BCR_BVR_WCR_WVR_EL1(n) \ 110862306a36Sopenharmony_ci { SYS_DESC(SYS_DBGBVRn_EL1(n)), \ 110962306a36Sopenharmony_ci trap_bvr, reset_bvr, 0, 0, get_bvr, set_bvr }, \ 111062306a36Sopenharmony_ci { SYS_DESC(SYS_DBGBCRn_EL1(n)), \ 111162306a36Sopenharmony_ci trap_bcr, reset_bcr, 0, 0, get_bcr, set_bcr }, \ 111262306a36Sopenharmony_ci { SYS_DESC(SYS_DBGWVRn_EL1(n)), \ 111362306a36Sopenharmony_ci trap_wvr, reset_wvr, 0, 0, get_wvr, set_wvr }, \ 111462306a36Sopenharmony_ci { SYS_DESC(SYS_DBGWCRn_EL1(n)), \ 111562306a36Sopenharmony_ci trap_wcr, reset_wcr, 0, 0, get_wcr, set_wcr } 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci#define PMU_SYS_REG(name) \ 111862306a36Sopenharmony_ci SYS_DESC(SYS_##name), .reset = reset_pmu_reg, \ 111962306a36Sopenharmony_ci .visibility = pmu_visibility 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci/* Macro to expand the PMEVCNTRn_EL0 register */ 112262306a36Sopenharmony_ci#define PMU_PMEVCNTR_EL0(n) \ 112362306a36Sopenharmony_ci { PMU_SYS_REG(PMEVCNTRn_EL0(n)), \ 112462306a36Sopenharmony_ci .reset = reset_pmevcntr, .get_user = get_pmu_evcntr, \ 112562306a36Sopenharmony_ci .access = access_pmu_evcntr, .reg = (PMEVCNTR0_EL0 + n), } 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci/* Macro to expand the PMEVTYPERn_EL0 register */ 112862306a36Sopenharmony_ci#define PMU_PMEVTYPER_EL0(n) \ 112962306a36Sopenharmony_ci { PMU_SYS_REG(PMEVTYPERn_EL0(n)), \ 113062306a36Sopenharmony_ci .reset = reset_pmevtyper, \ 113162306a36Sopenharmony_ci .access = access_pmu_evtyper, .reg = (PMEVTYPER0_EL0 + n), } 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_cistatic bool undef_access(struct kvm_vcpu *vcpu, struct sys_reg_params *p, 113462306a36Sopenharmony_ci const struct sys_reg_desc *r) 113562306a36Sopenharmony_ci{ 113662306a36Sopenharmony_ci kvm_inject_undefined(vcpu); 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci return false; 113962306a36Sopenharmony_ci} 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci/* Macro to expand the AMU counter and type registers*/ 114262306a36Sopenharmony_ci#define AMU_AMEVCNTR0_EL0(n) { SYS_DESC(SYS_AMEVCNTR0_EL0(n)), undef_access } 114362306a36Sopenharmony_ci#define AMU_AMEVTYPER0_EL0(n) { SYS_DESC(SYS_AMEVTYPER0_EL0(n)), undef_access } 114462306a36Sopenharmony_ci#define AMU_AMEVCNTR1_EL0(n) { SYS_DESC(SYS_AMEVCNTR1_EL0(n)), undef_access } 114562306a36Sopenharmony_ci#define AMU_AMEVTYPER1_EL0(n) { SYS_DESC(SYS_AMEVTYPER1_EL0(n)), undef_access } 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_cistatic unsigned int ptrauth_visibility(const struct kvm_vcpu *vcpu, 114862306a36Sopenharmony_ci const struct sys_reg_desc *rd) 114962306a36Sopenharmony_ci{ 115062306a36Sopenharmony_ci return vcpu_has_ptrauth(vcpu) ? 0 : REG_HIDDEN; 115162306a36Sopenharmony_ci} 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci/* 115462306a36Sopenharmony_ci * If we land here on a PtrAuth access, that is because we didn't 115562306a36Sopenharmony_ci * fixup the access on exit by allowing the PtrAuth sysregs. The only 115662306a36Sopenharmony_ci * way this happens is when the guest does not have PtrAuth support 115762306a36Sopenharmony_ci * enabled. 115862306a36Sopenharmony_ci */ 115962306a36Sopenharmony_ci#define __PTRAUTH_KEY(k) \ 116062306a36Sopenharmony_ci { SYS_DESC(SYS_## k), undef_access, reset_unknown, k, \ 116162306a36Sopenharmony_ci .visibility = ptrauth_visibility} 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci#define PTRAUTH_KEY(k) \ 116462306a36Sopenharmony_ci __PTRAUTH_KEY(k ## KEYLO_EL1), \ 116562306a36Sopenharmony_ci __PTRAUTH_KEY(k ## KEYHI_EL1) 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_cistatic bool access_arch_timer(struct kvm_vcpu *vcpu, 116862306a36Sopenharmony_ci struct sys_reg_params *p, 116962306a36Sopenharmony_ci const struct sys_reg_desc *r) 117062306a36Sopenharmony_ci{ 117162306a36Sopenharmony_ci enum kvm_arch_timers tmr; 117262306a36Sopenharmony_ci enum kvm_arch_timer_regs treg; 117362306a36Sopenharmony_ci u64 reg = reg_to_encoding(r); 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci switch (reg) { 117662306a36Sopenharmony_ci case SYS_CNTP_TVAL_EL0: 117762306a36Sopenharmony_ci case SYS_AARCH32_CNTP_TVAL: 117862306a36Sopenharmony_ci tmr = TIMER_PTIMER; 117962306a36Sopenharmony_ci treg = TIMER_REG_TVAL; 118062306a36Sopenharmony_ci break; 118162306a36Sopenharmony_ci case SYS_CNTP_CTL_EL0: 118262306a36Sopenharmony_ci case SYS_AARCH32_CNTP_CTL: 118362306a36Sopenharmony_ci tmr = TIMER_PTIMER; 118462306a36Sopenharmony_ci treg = TIMER_REG_CTL; 118562306a36Sopenharmony_ci break; 118662306a36Sopenharmony_ci case SYS_CNTP_CVAL_EL0: 118762306a36Sopenharmony_ci case SYS_AARCH32_CNTP_CVAL: 118862306a36Sopenharmony_ci tmr = TIMER_PTIMER; 118962306a36Sopenharmony_ci treg = TIMER_REG_CVAL; 119062306a36Sopenharmony_ci break; 119162306a36Sopenharmony_ci case SYS_CNTPCT_EL0: 119262306a36Sopenharmony_ci case SYS_CNTPCTSS_EL0: 119362306a36Sopenharmony_ci case SYS_AARCH32_CNTPCT: 119462306a36Sopenharmony_ci tmr = TIMER_PTIMER; 119562306a36Sopenharmony_ci treg = TIMER_REG_CNT; 119662306a36Sopenharmony_ci break; 119762306a36Sopenharmony_ci default: 119862306a36Sopenharmony_ci print_sys_reg_msg(p, "%s", "Unhandled trapped timer register"); 119962306a36Sopenharmony_ci kvm_inject_undefined(vcpu); 120062306a36Sopenharmony_ci return false; 120162306a36Sopenharmony_ci } 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci if (p->is_write) 120462306a36Sopenharmony_ci kvm_arm_timer_write_sysreg(vcpu, tmr, treg, p->regval); 120562306a36Sopenharmony_ci else 120662306a36Sopenharmony_ci p->regval = kvm_arm_timer_read_sysreg(vcpu, tmr, treg); 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci return true; 120962306a36Sopenharmony_ci} 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_cistatic s64 kvm_arm64_ftr_safe_value(u32 id, const struct arm64_ftr_bits *ftrp, 121262306a36Sopenharmony_ci s64 new, s64 cur) 121362306a36Sopenharmony_ci{ 121462306a36Sopenharmony_ci struct arm64_ftr_bits kvm_ftr = *ftrp; 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci /* Some features have different safe value type in KVM than host features */ 121762306a36Sopenharmony_ci switch (id) { 121862306a36Sopenharmony_ci case SYS_ID_AA64DFR0_EL1: 121962306a36Sopenharmony_ci if (kvm_ftr.shift == ID_AA64DFR0_EL1_PMUVer_SHIFT) 122062306a36Sopenharmony_ci kvm_ftr.type = FTR_LOWER_SAFE; 122162306a36Sopenharmony_ci break; 122262306a36Sopenharmony_ci case SYS_ID_DFR0_EL1: 122362306a36Sopenharmony_ci if (kvm_ftr.shift == ID_DFR0_EL1_PerfMon_SHIFT) 122462306a36Sopenharmony_ci kvm_ftr.type = FTR_LOWER_SAFE; 122562306a36Sopenharmony_ci break; 122662306a36Sopenharmony_ci } 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci return arm64_ftr_safe_value(&kvm_ftr, new, cur); 122962306a36Sopenharmony_ci} 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci/** 123262306a36Sopenharmony_ci * arm64_check_features() - Check if a feature register value constitutes 123362306a36Sopenharmony_ci * a subset of features indicated by the idreg's KVM sanitised limit. 123462306a36Sopenharmony_ci * 123562306a36Sopenharmony_ci * This function will check if each feature field of @val is the "safe" value 123662306a36Sopenharmony_ci * against idreg's KVM sanitised limit return from reset() callback. 123762306a36Sopenharmony_ci * If a field value in @val is the same as the one in limit, it is always 123862306a36Sopenharmony_ci * considered the safe value regardless For register fields that are not in 123962306a36Sopenharmony_ci * writable, only the value in limit is considered the safe value. 124062306a36Sopenharmony_ci * 124162306a36Sopenharmony_ci * Return: 0 if all the fields are safe. Otherwise, return negative errno. 124262306a36Sopenharmony_ci */ 124362306a36Sopenharmony_cistatic int arm64_check_features(struct kvm_vcpu *vcpu, 124462306a36Sopenharmony_ci const struct sys_reg_desc *rd, 124562306a36Sopenharmony_ci u64 val) 124662306a36Sopenharmony_ci{ 124762306a36Sopenharmony_ci const struct arm64_ftr_reg *ftr_reg; 124862306a36Sopenharmony_ci const struct arm64_ftr_bits *ftrp = NULL; 124962306a36Sopenharmony_ci u32 id = reg_to_encoding(rd); 125062306a36Sopenharmony_ci u64 writable_mask = rd->val; 125162306a36Sopenharmony_ci u64 limit = rd->reset(vcpu, rd); 125262306a36Sopenharmony_ci u64 mask = 0; 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci /* 125562306a36Sopenharmony_ci * Hidden and unallocated ID registers may not have a corresponding 125662306a36Sopenharmony_ci * struct arm64_ftr_reg. Of course, if the register is RAZ we know the 125762306a36Sopenharmony_ci * only safe value is 0. 125862306a36Sopenharmony_ci */ 125962306a36Sopenharmony_ci if (sysreg_visible_as_raz(vcpu, rd)) 126062306a36Sopenharmony_ci return val ? -E2BIG : 0; 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci ftr_reg = get_arm64_ftr_reg(id); 126362306a36Sopenharmony_ci if (!ftr_reg) 126462306a36Sopenharmony_ci return -EINVAL; 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci ftrp = ftr_reg->ftr_bits; 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_ci for (; ftrp && ftrp->width; ftrp++) { 126962306a36Sopenharmony_ci s64 f_val, f_lim, safe_val; 127062306a36Sopenharmony_ci u64 ftr_mask; 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci ftr_mask = arm64_ftr_mask(ftrp); 127362306a36Sopenharmony_ci if ((ftr_mask & writable_mask) != ftr_mask) 127462306a36Sopenharmony_ci continue; 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci f_val = arm64_ftr_value(ftrp, val); 127762306a36Sopenharmony_ci f_lim = arm64_ftr_value(ftrp, limit); 127862306a36Sopenharmony_ci mask |= ftr_mask; 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci if (f_val == f_lim) 128162306a36Sopenharmony_ci safe_val = f_val; 128262306a36Sopenharmony_ci else 128362306a36Sopenharmony_ci safe_val = kvm_arm64_ftr_safe_value(id, ftrp, f_val, f_lim); 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci if (safe_val != f_val) 128662306a36Sopenharmony_ci return -E2BIG; 128762306a36Sopenharmony_ci } 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci /* For fields that are not writable, values in limit are the safe values. */ 129062306a36Sopenharmony_ci if ((val & ~mask) != (limit & ~mask)) 129162306a36Sopenharmony_ci return -E2BIG; 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci return 0; 129462306a36Sopenharmony_ci} 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_cistatic u8 pmuver_to_perfmon(u8 pmuver) 129762306a36Sopenharmony_ci{ 129862306a36Sopenharmony_ci switch (pmuver) { 129962306a36Sopenharmony_ci case ID_AA64DFR0_EL1_PMUVer_IMP: 130062306a36Sopenharmony_ci return ID_DFR0_EL1_PerfMon_PMUv3; 130162306a36Sopenharmony_ci case ID_AA64DFR0_EL1_PMUVer_IMP_DEF: 130262306a36Sopenharmony_ci return ID_DFR0_EL1_PerfMon_IMPDEF; 130362306a36Sopenharmony_ci default: 130462306a36Sopenharmony_ci /* Anything ARMv8.1+ and NI have the same value. For now. */ 130562306a36Sopenharmony_ci return pmuver; 130662306a36Sopenharmony_ci } 130762306a36Sopenharmony_ci} 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci/* Read a sanitised cpufeature ID register by sys_reg_desc */ 131062306a36Sopenharmony_cistatic u64 __kvm_read_sanitised_id_reg(const struct kvm_vcpu *vcpu, 131162306a36Sopenharmony_ci const struct sys_reg_desc *r) 131262306a36Sopenharmony_ci{ 131362306a36Sopenharmony_ci u32 id = reg_to_encoding(r); 131462306a36Sopenharmony_ci u64 val; 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci if (sysreg_visible_as_raz(vcpu, r)) 131762306a36Sopenharmony_ci return 0; 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci val = read_sanitised_ftr_reg(id); 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci switch (id) { 132262306a36Sopenharmony_ci case SYS_ID_AA64PFR1_EL1: 132362306a36Sopenharmony_ci if (!kvm_has_mte(vcpu->kvm)) 132462306a36Sopenharmony_ci val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MTE); 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_SME); 132762306a36Sopenharmony_ci break; 132862306a36Sopenharmony_ci case SYS_ID_AA64ISAR1_EL1: 132962306a36Sopenharmony_ci if (!vcpu_has_ptrauth(vcpu)) 133062306a36Sopenharmony_ci val &= ~(ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_APA) | 133162306a36Sopenharmony_ci ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_API) | 133262306a36Sopenharmony_ci ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_GPA) | 133362306a36Sopenharmony_ci ARM64_FEATURE_MASK(ID_AA64ISAR1_EL1_GPI)); 133462306a36Sopenharmony_ci break; 133562306a36Sopenharmony_ci case SYS_ID_AA64ISAR2_EL1: 133662306a36Sopenharmony_ci if (!vcpu_has_ptrauth(vcpu)) 133762306a36Sopenharmony_ci val &= ~(ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_APA3) | 133862306a36Sopenharmony_ci ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_GPA3)); 133962306a36Sopenharmony_ci if (!cpus_have_final_cap(ARM64_HAS_WFXT)) 134062306a36Sopenharmony_ci val &= ~ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_WFxT); 134162306a36Sopenharmony_ci val &= ~ARM64_FEATURE_MASK(ID_AA64ISAR2_EL1_MOPS); 134262306a36Sopenharmony_ci break; 134362306a36Sopenharmony_ci case SYS_ID_AA64MMFR2_EL1: 134462306a36Sopenharmony_ci val &= ~ID_AA64MMFR2_EL1_CCIDX_MASK; 134562306a36Sopenharmony_ci break; 134662306a36Sopenharmony_ci case SYS_ID_MMFR4_EL1: 134762306a36Sopenharmony_ci val &= ~ARM64_FEATURE_MASK(ID_MMFR4_EL1_CCIDX); 134862306a36Sopenharmony_ci break; 134962306a36Sopenharmony_ci } 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci return val; 135262306a36Sopenharmony_ci} 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_cistatic u64 kvm_read_sanitised_id_reg(struct kvm_vcpu *vcpu, 135562306a36Sopenharmony_ci const struct sys_reg_desc *r) 135662306a36Sopenharmony_ci{ 135762306a36Sopenharmony_ci return __kvm_read_sanitised_id_reg(vcpu, r); 135862306a36Sopenharmony_ci} 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_cistatic u64 read_id_reg(const struct kvm_vcpu *vcpu, const struct sys_reg_desc *r) 136162306a36Sopenharmony_ci{ 136262306a36Sopenharmony_ci return IDREG(vcpu->kvm, reg_to_encoding(r)); 136362306a36Sopenharmony_ci} 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci/* 136662306a36Sopenharmony_ci * Return true if the register's (Op0, Op1, CRn, CRm, Op2) is 136762306a36Sopenharmony_ci * (3, 0, 0, crm, op2), where 1<=crm<8, 0<=op2<8. 136862306a36Sopenharmony_ci */ 136962306a36Sopenharmony_cistatic inline bool is_id_reg(u32 id) 137062306a36Sopenharmony_ci{ 137162306a36Sopenharmony_ci return (sys_reg_Op0(id) == 3 && sys_reg_Op1(id) == 0 && 137262306a36Sopenharmony_ci sys_reg_CRn(id) == 0 && sys_reg_CRm(id) >= 1 && 137362306a36Sopenharmony_ci sys_reg_CRm(id) < 8); 137462306a36Sopenharmony_ci} 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_cistatic unsigned int id_visibility(const struct kvm_vcpu *vcpu, 137762306a36Sopenharmony_ci const struct sys_reg_desc *r) 137862306a36Sopenharmony_ci{ 137962306a36Sopenharmony_ci u32 id = reg_to_encoding(r); 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci switch (id) { 138262306a36Sopenharmony_ci case SYS_ID_AA64ZFR0_EL1: 138362306a36Sopenharmony_ci if (!vcpu_has_sve(vcpu)) 138462306a36Sopenharmony_ci return REG_RAZ; 138562306a36Sopenharmony_ci break; 138662306a36Sopenharmony_ci } 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci return 0; 138962306a36Sopenharmony_ci} 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_cistatic unsigned int aa32_id_visibility(const struct kvm_vcpu *vcpu, 139262306a36Sopenharmony_ci const struct sys_reg_desc *r) 139362306a36Sopenharmony_ci{ 139462306a36Sopenharmony_ci /* 139562306a36Sopenharmony_ci * AArch32 ID registers are UNKNOWN if AArch32 isn't implemented at any 139662306a36Sopenharmony_ci * EL. Promote to RAZ/WI in order to guarantee consistency between 139762306a36Sopenharmony_ci * systems. 139862306a36Sopenharmony_ci */ 139962306a36Sopenharmony_ci if (!kvm_supports_32bit_el0()) 140062306a36Sopenharmony_ci return REG_RAZ | REG_USER_WI; 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci return id_visibility(vcpu, r); 140362306a36Sopenharmony_ci} 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_cistatic unsigned int raz_visibility(const struct kvm_vcpu *vcpu, 140662306a36Sopenharmony_ci const struct sys_reg_desc *r) 140762306a36Sopenharmony_ci{ 140862306a36Sopenharmony_ci return REG_RAZ; 140962306a36Sopenharmony_ci} 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci/* cpufeature ID register access trap handlers */ 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_cistatic bool access_id_reg(struct kvm_vcpu *vcpu, 141462306a36Sopenharmony_ci struct sys_reg_params *p, 141562306a36Sopenharmony_ci const struct sys_reg_desc *r) 141662306a36Sopenharmony_ci{ 141762306a36Sopenharmony_ci if (p->is_write) 141862306a36Sopenharmony_ci return write_to_read_only(vcpu, p, r); 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ci p->regval = read_id_reg(vcpu, r); 142162306a36Sopenharmony_ci if (vcpu_has_nv(vcpu)) 142262306a36Sopenharmony_ci access_nested_id_reg(vcpu, p, r); 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci return true; 142562306a36Sopenharmony_ci} 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci/* Visibility overrides for SVE-specific control registers */ 142862306a36Sopenharmony_cistatic unsigned int sve_visibility(const struct kvm_vcpu *vcpu, 142962306a36Sopenharmony_ci const struct sys_reg_desc *rd) 143062306a36Sopenharmony_ci{ 143162306a36Sopenharmony_ci if (vcpu_has_sve(vcpu)) 143262306a36Sopenharmony_ci return 0; 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci return REG_HIDDEN; 143562306a36Sopenharmony_ci} 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_cistatic u64 read_sanitised_id_aa64pfr0_el1(struct kvm_vcpu *vcpu, 143862306a36Sopenharmony_ci const struct sys_reg_desc *rd) 143962306a36Sopenharmony_ci{ 144062306a36Sopenharmony_ci u64 val = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1); 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci if (!vcpu_has_sve(vcpu)) 144362306a36Sopenharmony_ci val &= ~ID_AA64PFR0_EL1_SVE_MASK; 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci /* 144662306a36Sopenharmony_ci * The default is to expose CSV2 == 1 if the HW isn't affected. 144762306a36Sopenharmony_ci * Although this is a per-CPU feature, we make it global because 144862306a36Sopenharmony_ci * asymmetric systems are just a nuisance. 144962306a36Sopenharmony_ci * 145062306a36Sopenharmony_ci * Userspace can override this as long as it doesn't promise 145162306a36Sopenharmony_ci * the impossible. 145262306a36Sopenharmony_ci */ 145362306a36Sopenharmony_ci if (arm64_get_spectre_v2_state() == SPECTRE_UNAFFECTED) { 145462306a36Sopenharmony_ci val &= ~ID_AA64PFR0_EL1_CSV2_MASK; 145562306a36Sopenharmony_ci val |= SYS_FIELD_PREP_ENUM(ID_AA64PFR0_EL1, CSV2, IMP); 145662306a36Sopenharmony_ci } 145762306a36Sopenharmony_ci if (arm64_get_meltdown_state() == SPECTRE_UNAFFECTED) { 145862306a36Sopenharmony_ci val &= ~ID_AA64PFR0_EL1_CSV3_MASK; 145962306a36Sopenharmony_ci val |= SYS_FIELD_PREP_ENUM(ID_AA64PFR0_EL1, CSV3, IMP); 146062306a36Sopenharmony_ci } 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci if (kvm_vgic_global_state.type == VGIC_V3) { 146362306a36Sopenharmony_ci val &= ~ID_AA64PFR0_EL1_GIC_MASK; 146462306a36Sopenharmony_ci val |= SYS_FIELD_PREP_ENUM(ID_AA64PFR0_EL1, GIC, IMP); 146562306a36Sopenharmony_ci } 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci val &= ~ID_AA64PFR0_EL1_AMU_MASK; 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci return val; 147062306a36Sopenharmony_ci} 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_cistatic u64 read_sanitised_id_aa64dfr0_el1(struct kvm_vcpu *vcpu, 147362306a36Sopenharmony_ci const struct sys_reg_desc *rd) 147462306a36Sopenharmony_ci{ 147562306a36Sopenharmony_ci u64 val = read_sanitised_ftr_reg(SYS_ID_AA64DFR0_EL1); 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci /* Limit debug to ARMv8.0 */ 147862306a36Sopenharmony_ci val &= ~ID_AA64DFR0_EL1_DebugVer_MASK; 147962306a36Sopenharmony_ci val |= SYS_FIELD_PREP_ENUM(ID_AA64DFR0_EL1, DebugVer, IMP); 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci /* 148262306a36Sopenharmony_ci * Only initialize the PMU version if the vCPU was configured with one. 148362306a36Sopenharmony_ci */ 148462306a36Sopenharmony_ci val &= ~ID_AA64DFR0_EL1_PMUVer_MASK; 148562306a36Sopenharmony_ci if (kvm_vcpu_has_pmu(vcpu)) 148662306a36Sopenharmony_ci val |= SYS_FIELD_PREP(ID_AA64DFR0_EL1, PMUVer, 148762306a36Sopenharmony_ci kvm_arm_pmu_get_pmuver_limit()); 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci /* Hide SPE from guests */ 149062306a36Sopenharmony_ci val &= ~ID_AA64DFR0_EL1_PMSVer_MASK; 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci return val; 149362306a36Sopenharmony_ci} 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_cistatic int set_id_aa64dfr0_el1(struct kvm_vcpu *vcpu, 149662306a36Sopenharmony_ci const struct sys_reg_desc *rd, 149762306a36Sopenharmony_ci u64 val) 149862306a36Sopenharmony_ci{ 149962306a36Sopenharmony_ci u8 pmuver = SYS_FIELD_GET(ID_AA64DFR0_EL1, PMUVer, val); 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci /* 150262306a36Sopenharmony_ci * Prior to commit 3d0dba5764b9 ("KVM: arm64: PMU: Move the 150362306a36Sopenharmony_ci * ID_AA64DFR0_EL1.PMUver limit to VM creation"), KVM erroneously 150462306a36Sopenharmony_ci * exposed an IMP_DEF PMU to userspace and the guest on systems w/ 150562306a36Sopenharmony_ci * non-architectural PMUs. Of course, PMUv3 is the only game in town for 150662306a36Sopenharmony_ci * PMU virtualization, so the IMP_DEF value was rather user-hostile. 150762306a36Sopenharmony_ci * 150862306a36Sopenharmony_ci * At minimum, we're on the hook to allow values that were given to 150962306a36Sopenharmony_ci * userspace by KVM. Cover our tracks here and replace the IMP_DEF value 151062306a36Sopenharmony_ci * with a more sensible NI. The value of an ID register changing under 151162306a36Sopenharmony_ci * the nose of the guest is unfortunate, but is certainly no more 151262306a36Sopenharmony_ci * surprising than an ill-guided PMU driver poking at impdef system 151362306a36Sopenharmony_ci * registers that end in an UNDEF... 151462306a36Sopenharmony_ci */ 151562306a36Sopenharmony_ci if (pmuver == ID_AA64DFR0_EL1_PMUVer_IMP_DEF) 151662306a36Sopenharmony_ci val &= ~ID_AA64DFR0_EL1_PMUVer_MASK; 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci return set_id_reg(vcpu, rd, val); 151962306a36Sopenharmony_ci} 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_cistatic u64 read_sanitised_id_dfr0_el1(struct kvm_vcpu *vcpu, 152262306a36Sopenharmony_ci const struct sys_reg_desc *rd) 152362306a36Sopenharmony_ci{ 152462306a36Sopenharmony_ci u8 perfmon = pmuver_to_perfmon(kvm_arm_pmu_get_pmuver_limit()); 152562306a36Sopenharmony_ci u64 val = read_sanitised_ftr_reg(SYS_ID_DFR0_EL1); 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci val &= ~ID_DFR0_EL1_PerfMon_MASK; 152862306a36Sopenharmony_ci if (kvm_vcpu_has_pmu(vcpu)) 152962306a36Sopenharmony_ci val |= SYS_FIELD_PREP(ID_DFR0_EL1, PerfMon, perfmon); 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci return val; 153262306a36Sopenharmony_ci} 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_cistatic int set_id_dfr0_el1(struct kvm_vcpu *vcpu, 153562306a36Sopenharmony_ci const struct sys_reg_desc *rd, 153662306a36Sopenharmony_ci u64 val) 153762306a36Sopenharmony_ci{ 153862306a36Sopenharmony_ci u8 perfmon = SYS_FIELD_GET(ID_DFR0_EL1, PerfMon, val); 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci if (perfmon == ID_DFR0_EL1_PerfMon_IMPDEF) { 154162306a36Sopenharmony_ci val &= ~ID_DFR0_EL1_PerfMon_MASK; 154262306a36Sopenharmony_ci perfmon = 0; 154362306a36Sopenharmony_ci } 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci /* 154662306a36Sopenharmony_ci * Allow DFR0_EL1.PerfMon to be set from userspace as long as 154762306a36Sopenharmony_ci * it doesn't promise more than what the HW gives us on the 154862306a36Sopenharmony_ci * AArch64 side (as everything is emulated with that), and 154962306a36Sopenharmony_ci * that this is a PMUv3. 155062306a36Sopenharmony_ci */ 155162306a36Sopenharmony_ci if (perfmon != 0 && perfmon < ID_DFR0_EL1_PerfMon_PMUv3) 155262306a36Sopenharmony_ci return -EINVAL; 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_ci return set_id_reg(vcpu, rd, val); 155562306a36Sopenharmony_ci} 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci/* 155862306a36Sopenharmony_ci * cpufeature ID register user accessors 155962306a36Sopenharmony_ci * 156062306a36Sopenharmony_ci * For now, these registers are immutable for userspace, so no values 156162306a36Sopenharmony_ci * are stored, and for set_id_reg() we don't allow the effective value 156262306a36Sopenharmony_ci * to be changed. 156362306a36Sopenharmony_ci */ 156462306a36Sopenharmony_cistatic int get_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, 156562306a36Sopenharmony_ci u64 *val) 156662306a36Sopenharmony_ci{ 156762306a36Sopenharmony_ci /* 156862306a36Sopenharmony_ci * Avoid locking if the VM has already started, as the ID registers are 156962306a36Sopenharmony_ci * guaranteed to be invariant at that point. 157062306a36Sopenharmony_ci */ 157162306a36Sopenharmony_ci if (kvm_vm_has_ran_once(vcpu->kvm)) { 157262306a36Sopenharmony_ci *val = read_id_reg(vcpu, rd); 157362306a36Sopenharmony_ci return 0; 157462306a36Sopenharmony_ci } 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci mutex_lock(&vcpu->kvm->arch.config_lock); 157762306a36Sopenharmony_ci *val = read_id_reg(vcpu, rd); 157862306a36Sopenharmony_ci mutex_unlock(&vcpu->kvm->arch.config_lock); 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci return 0; 158162306a36Sopenharmony_ci} 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_cistatic int set_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, 158462306a36Sopenharmony_ci u64 val) 158562306a36Sopenharmony_ci{ 158662306a36Sopenharmony_ci u32 id = reg_to_encoding(rd); 158762306a36Sopenharmony_ci int ret; 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci mutex_lock(&vcpu->kvm->arch.config_lock); 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_ci /* 159262306a36Sopenharmony_ci * Once the VM has started the ID registers are immutable. Reject any 159362306a36Sopenharmony_ci * write that does not match the final register value. 159462306a36Sopenharmony_ci */ 159562306a36Sopenharmony_ci if (kvm_vm_has_ran_once(vcpu->kvm)) { 159662306a36Sopenharmony_ci if (val != read_id_reg(vcpu, rd)) 159762306a36Sopenharmony_ci ret = -EBUSY; 159862306a36Sopenharmony_ci else 159962306a36Sopenharmony_ci ret = 0; 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci mutex_unlock(&vcpu->kvm->arch.config_lock); 160262306a36Sopenharmony_ci return ret; 160362306a36Sopenharmony_ci } 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci ret = arm64_check_features(vcpu, rd, val); 160662306a36Sopenharmony_ci if (!ret) 160762306a36Sopenharmony_ci IDREG(vcpu->kvm, id) = val; 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci mutex_unlock(&vcpu->kvm->arch.config_lock); 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci /* 161262306a36Sopenharmony_ci * arm64_check_features() returns -E2BIG to indicate the register's 161362306a36Sopenharmony_ci * feature set is a superset of the maximally-allowed register value. 161462306a36Sopenharmony_ci * While it would be nice to precisely describe this to userspace, the 161562306a36Sopenharmony_ci * existing UAPI for KVM_SET_ONE_REG has it that invalid register 161662306a36Sopenharmony_ci * writes return -EINVAL. 161762306a36Sopenharmony_ci */ 161862306a36Sopenharmony_ci if (ret == -E2BIG) 161962306a36Sopenharmony_ci ret = -EINVAL; 162062306a36Sopenharmony_ci return ret; 162162306a36Sopenharmony_ci} 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_cistatic int get_raz_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, 162462306a36Sopenharmony_ci u64 *val) 162562306a36Sopenharmony_ci{ 162662306a36Sopenharmony_ci *val = 0; 162762306a36Sopenharmony_ci return 0; 162862306a36Sopenharmony_ci} 162962306a36Sopenharmony_ci 163062306a36Sopenharmony_cistatic int set_wi_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, 163162306a36Sopenharmony_ci u64 val) 163262306a36Sopenharmony_ci{ 163362306a36Sopenharmony_ci return 0; 163462306a36Sopenharmony_ci} 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_cistatic bool access_ctr(struct kvm_vcpu *vcpu, struct sys_reg_params *p, 163762306a36Sopenharmony_ci const struct sys_reg_desc *r) 163862306a36Sopenharmony_ci{ 163962306a36Sopenharmony_ci if (p->is_write) 164062306a36Sopenharmony_ci return write_to_read_only(vcpu, p, r); 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci p->regval = read_sanitised_ftr_reg(SYS_CTR_EL0); 164362306a36Sopenharmony_ci return true; 164462306a36Sopenharmony_ci} 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_cistatic bool access_clidr(struct kvm_vcpu *vcpu, struct sys_reg_params *p, 164762306a36Sopenharmony_ci const struct sys_reg_desc *r) 164862306a36Sopenharmony_ci{ 164962306a36Sopenharmony_ci if (p->is_write) 165062306a36Sopenharmony_ci return write_to_read_only(vcpu, p, r); 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci p->regval = __vcpu_sys_reg(vcpu, r->reg); 165362306a36Sopenharmony_ci return true; 165462306a36Sopenharmony_ci} 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_ci/* 165762306a36Sopenharmony_ci * Fabricate a CLIDR_EL1 value instead of using the real value, which can vary 165862306a36Sopenharmony_ci * by the physical CPU which the vcpu currently resides in. 165962306a36Sopenharmony_ci */ 166062306a36Sopenharmony_cistatic u64 reset_clidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r) 166162306a36Sopenharmony_ci{ 166262306a36Sopenharmony_ci u64 ctr_el0 = read_sanitised_ftr_reg(SYS_CTR_EL0); 166362306a36Sopenharmony_ci u64 clidr; 166462306a36Sopenharmony_ci u8 loc; 166562306a36Sopenharmony_ci 166662306a36Sopenharmony_ci if ((ctr_el0 & CTR_EL0_IDC)) { 166762306a36Sopenharmony_ci /* 166862306a36Sopenharmony_ci * Data cache clean to the PoU is not required so LoUU and LoUIS 166962306a36Sopenharmony_ci * will not be set and a unified cache, which will be marked as 167062306a36Sopenharmony_ci * LoC, will be added. 167162306a36Sopenharmony_ci * 167262306a36Sopenharmony_ci * If not DIC, let the unified cache L2 so that an instruction 167362306a36Sopenharmony_ci * cache can be added as L1 later. 167462306a36Sopenharmony_ci */ 167562306a36Sopenharmony_ci loc = (ctr_el0 & CTR_EL0_DIC) ? 1 : 2; 167662306a36Sopenharmony_ci clidr = CACHE_TYPE_UNIFIED << CLIDR_CTYPE_SHIFT(loc); 167762306a36Sopenharmony_ci } else { 167862306a36Sopenharmony_ci /* 167962306a36Sopenharmony_ci * Data cache clean to the PoU is required so let L1 have a data 168062306a36Sopenharmony_ci * cache and mark it as LoUU and LoUIS. As L1 has a data cache, 168162306a36Sopenharmony_ci * it can be marked as LoC too. 168262306a36Sopenharmony_ci */ 168362306a36Sopenharmony_ci loc = 1; 168462306a36Sopenharmony_ci clidr = 1 << CLIDR_LOUU_SHIFT; 168562306a36Sopenharmony_ci clidr |= 1 << CLIDR_LOUIS_SHIFT; 168662306a36Sopenharmony_ci clidr |= CACHE_TYPE_DATA << CLIDR_CTYPE_SHIFT(1); 168762306a36Sopenharmony_ci } 168862306a36Sopenharmony_ci 168962306a36Sopenharmony_ci /* 169062306a36Sopenharmony_ci * Instruction cache invalidation to the PoU is required so let L1 have 169162306a36Sopenharmony_ci * an instruction cache. If L1 already has a data cache, it will be 169262306a36Sopenharmony_ci * CACHE_TYPE_SEPARATE. 169362306a36Sopenharmony_ci */ 169462306a36Sopenharmony_ci if (!(ctr_el0 & CTR_EL0_DIC)) 169562306a36Sopenharmony_ci clidr |= CACHE_TYPE_INST << CLIDR_CTYPE_SHIFT(1); 169662306a36Sopenharmony_ci 169762306a36Sopenharmony_ci clidr |= loc << CLIDR_LOC_SHIFT; 169862306a36Sopenharmony_ci 169962306a36Sopenharmony_ci /* 170062306a36Sopenharmony_ci * Add tag cache unified to data cache. Allocation tags and data are 170162306a36Sopenharmony_ci * unified in a cache line so that it looks valid even if there is only 170262306a36Sopenharmony_ci * one cache line. 170362306a36Sopenharmony_ci */ 170462306a36Sopenharmony_ci if (kvm_has_mte(vcpu->kvm)) 170562306a36Sopenharmony_ci clidr |= 2 << CLIDR_TTYPE_SHIFT(loc); 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_ci __vcpu_sys_reg(vcpu, r->reg) = clidr; 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci return __vcpu_sys_reg(vcpu, r->reg); 171062306a36Sopenharmony_ci} 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_cistatic int set_clidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, 171362306a36Sopenharmony_ci u64 val) 171462306a36Sopenharmony_ci{ 171562306a36Sopenharmony_ci u64 ctr_el0 = read_sanitised_ftr_reg(SYS_CTR_EL0); 171662306a36Sopenharmony_ci u64 idc = !CLIDR_LOC(val) || (!CLIDR_LOUIS(val) && !CLIDR_LOUU(val)); 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ci if ((val & CLIDR_EL1_RES0) || (!(ctr_el0 & CTR_EL0_IDC) && idc)) 171962306a36Sopenharmony_ci return -EINVAL; 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_ci __vcpu_sys_reg(vcpu, rd->reg) = val; 172262306a36Sopenharmony_ci 172362306a36Sopenharmony_ci return 0; 172462306a36Sopenharmony_ci} 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_cistatic bool access_csselr(struct kvm_vcpu *vcpu, struct sys_reg_params *p, 172762306a36Sopenharmony_ci const struct sys_reg_desc *r) 172862306a36Sopenharmony_ci{ 172962306a36Sopenharmony_ci int reg = r->reg; 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci if (p->is_write) 173262306a36Sopenharmony_ci vcpu_write_sys_reg(vcpu, p->regval, reg); 173362306a36Sopenharmony_ci else 173462306a36Sopenharmony_ci p->regval = vcpu_read_sys_reg(vcpu, reg); 173562306a36Sopenharmony_ci return true; 173662306a36Sopenharmony_ci} 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_cistatic bool access_ccsidr(struct kvm_vcpu *vcpu, struct sys_reg_params *p, 173962306a36Sopenharmony_ci const struct sys_reg_desc *r) 174062306a36Sopenharmony_ci{ 174162306a36Sopenharmony_ci u32 csselr; 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci if (p->is_write) 174462306a36Sopenharmony_ci return write_to_read_only(vcpu, p, r); 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_ci csselr = vcpu_read_sys_reg(vcpu, CSSELR_EL1); 174762306a36Sopenharmony_ci csselr &= CSSELR_EL1_Level | CSSELR_EL1_InD; 174862306a36Sopenharmony_ci if (csselr < CSSELR_MAX) 174962306a36Sopenharmony_ci p->regval = get_ccsidr(vcpu, csselr); 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_ci return true; 175262306a36Sopenharmony_ci} 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_cistatic unsigned int mte_visibility(const struct kvm_vcpu *vcpu, 175562306a36Sopenharmony_ci const struct sys_reg_desc *rd) 175662306a36Sopenharmony_ci{ 175762306a36Sopenharmony_ci if (kvm_has_mte(vcpu->kvm)) 175862306a36Sopenharmony_ci return 0; 175962306a36Sopenharmony_ci 176062306a36Sopenharmony_ci return REG_HIDDEN; 176162306a36Sopenharmony_ci} 176262306a36Sopenharmony_ci 176362306a36Sopenharmony_ci#define MTE_REG(name) { \ 176462306a36Sopenharmony_ci SYS_DESC(SYS_##name), \ 176562306a36Sopenharmony_ci .access = undef_access, \ 176662306a36Sopenharmony_ci .reset = reset_unknown, \ 176762306a36Sopenharmony_ci .reg = name, \ 176862306a36Sopenharmony_ci .visibility = mte_visibility, \ 176962306a36Sopenharmony_ci} 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_cistatic unsigned int el2_visibility(const struct kvm_vcpu *vcpu, 177262306a36Sopenharmony_ci const struct sys_reg_desc *rd) 177362306a36Sopenharmony_ci{ 177462306a36Sopenharmony_ci if (vcpu_has_nv(vcpu)) 177562306a36Sopenharmony_ci return 0; 177662306a36Sopenharmony_ci 177762306a36Sopenharmony_ci return REG_HIDDEN; 177862306a36Sopenharmony_ci} 177962306a36Sopenharmony_ci 178062306a36Sopenharmony_ci#define EL2_REG(name, acc, rst, v) { \ 178162306a36Sopenharmony_ci SYS_DESC(SYS_##name), \ 178262306a36Sopenharmony_ci .access = acc, \ 178362306a36Sopenharmony_ci .reset = rst, \ 178462306a36Sopenharmony_ci .reg = name, \ 178562306a36Sopenharmony_ci .visibility = el2_visibility, \ 178662306a36Sopenharmony_ci .val = v, \ 178762306a36Sopenharmony_ci} 178862306a36Sopenharmony_ci 178962306a36Sopenharmony_ci/* 179062306a36Sopenharmony_ci * EL{0,1}2 registers are the EL2 view on an EL0 or EL1 register when 179162306a36Sopenharmony_ci * HCR_EL2.E2H==1, and only in the sysreg table for convenience of 179262306a36Sopenharmony_ci * handling traps. Given that, they are always hidden from userspace. 179362306a36Sopenharmony_ci */ 179462306a36Sopenharmony_cistatic unsigned int elx2_visibility(const struct kvm_vcpu *vcpu, 179562306a36Sopenharmony_ci const struct sys_reg_desc *rd) 179662306a36Sopenharmony_ci{ 179762306a36Sopenharmony_ci return REG_HIDDEN_USER; 179862306a36Sopenharmony_ci} 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_ci#define EL12_REG(name, acc, rst, v) { \ 180162306a36Sopenharmony_ci SYS_DESC(SYS_##name##_EL12), \ 180262306a36Sopenharmony_ci .access = acc, \ 180362306a36Sopenharmony_ci .reset = rst, \ 180462306a36Sopenharmony_ci .reg = name##_EL1, \ 180562306a36Sopenharmony_ci .val = v, \ 180662306a36Sopenharmony_ci .visibility = elx2_visibility, \ 180762306a36Sopenharmony_ci} 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ci/* 181062306a36Sopenharmony_ci * Since reset() callback and field val are not used for idregs, they will be 181162306a36Sopenharmony_ci * used for specific purposes for idregs. 181262306a36Sopenharmony_ci * The reset() would return KVM sanitised register value. The value would be the 181362306a36Sopenharmony_ci * same as the host kernel sanitised value if there is no KVM sanitisation. 181462306a36Sopenharmony_ci * The val would be used as a mask indicating writable fields for the idreg. 181562306a36Sopenharmony_ci * Only bits with 1 are writable from userspace. This mask might not be 181662306a36Sopenharmony_ci * necessary in the future whenever all ID registers are enabled as writable 181762306a36Sopenharmony_ci * from userspace. 181862306a36Sopenharmony_ci */ 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci/* sys_reg_desc initialiser for known cpufeature ID registers */ 182162306a36Sopenharmony_ci#define ID_SANITISED(name) { \ 182262306a36Sopenharmony_ci SYS_DESC(SYS_##name), \ 182362306a36Sopenharmony_ci .access = access_id_reg, \ 182462306a36Sopenharmony_ci .get_user = get_id_reg, \ 182562306a36Sopenharmony_ci .set_user = set_id_reg, \ 182662306a36Sopenharmony_ci .visibility = id_visibility, \ 182762306a36Sopenharmony_ci .reset = kvm_read_sanitised_id_reg, \ 182862306a36Sopenharmony_ci .val = 0, \ 182962306a36Sopenharmony_ci} 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_ci/* sys_reg_desc initialiser for known cpufeature ID registers */ 183262306a36Sopenharmony_ci#define AA32_ID_SANITISED(name) { \ 183362306a36Sopenharmony_ci SYS_DESC(SYS_##name), \ 183462306a36Sopenharmony_ci .access = access_id_reg, \ 183562306a36Sopenharmony_ci .get_user = get_id_reg, \ 183662306a36Sopenharmony_ci .set_user = set_id_reg, \ 183762306a36Sopenharmony_ci .visibility = aa32_id_visibility, \ 183862306a36Sopenharmony_ci .reset = kvm_read_sanitised_id_reg, \ 183962306a36Sopenharmony_ci .val = 0, \ 184062306a36Sopenharmony_ci} 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci/* 184362306a36Sopenharmony_ci * sys_reg_desc initialiser for architecturally unallocated cpufeature ID 184462306a36Sopenharmony_ci * register with encoding Op0=3, Op1=0, CRn=0, CRm=crm, Op2=op2 184562306a36Sopenharmony_ci * (1 <= crm < 8, 0 <= Op2 < 8). 184662306a36Sopenharmony_ci */ 184762306a36Sopenharmony_ci#define ID_UNALLOCATED(crm, op2) { \ 184862306a36Sopenharmony_ci Op0(3), Op1(0), CRn(0), CRm(crm), Op2(op2), \ 184962306a36Sopenharmony_ci .access = access_id_reg, \ 185062306a36Sopenharmony_ci .get_user = get_id_reg, \ 185162306a36Sopenharmony_ci .set_user = set_id_reg, \ 185262306a36Sopenharmony_ci .visibility = raz_visibility, \ 185362306a36Sopenharmony_ci .reset = kvm_read_sanitised_id_reg, \ 185462306a36Sopenharmony_ci .val = 0, \ 185562306a36Sopenharmony_ci} 185662306a36Sopenharmony_ci 185762306a36Sopenharmony_ci/* 185862306a36Sopenharmony_ci * sys_reg_desc initialiser for known ID registers that we hide from guests. 185962306a36Sopenharmony_ci * For now, these are exposed just like unallocated ID regs: they appear 186062306a36Sopenharmony_ci * RAZ for the guest. 186162306a36Sopenharmony_ci */ 186262306a36Sopenharmony_ci#define ID_HIDDEN(name) { \ 186362306a36Sopenharmony_ci SYS_DESC(SYS_##name), \ 186462306a36Sopenharmony_ci .access = access_id_reg, \ 186562306a36Sopenharmony_ci .get_user = get_id_reg, \ 186662306a36Sopenharmony_ci .set_user = set_id_reg, \ 186762306a36Sopenharmony_ci .visibility = raz_visibility, \ 186862306a36Sopenharmony_ci .reset = kvm_read_sanitised_id_reg, \ 186962306a36Sopenharmony_ci .val = 0, \ 187062306a36Sopenharmony_ci} 187162306a36Sopenharmony_ci 187262306a36Sopenharmony_cistatic bool access_sp_el1(struct kvm_vcpu *vcpu, 187362306a36Sopenharmony_ci struct sys_reg_params *p, 187462306a36Sopenharmony_ci const struct sys_reg_desc *r) 187562306a36Sopenharmony_ci{ 187662306a36Sopenharmony_ci if (p->is_write) 187762306a36Sopenharmony_ci __vcpu_sys_reg(vcpu, SP_EL1) = p->regval; 187862306a36Sopenharmony_ci else 187962306a36Sopenharmony_ci p->regval = __vcpu_sys_reg(vcpu, SP_EL1); 188062306a36Sopenharmony_ci 188162306a36Sopenharmony_ci return true; 188262306a36Sopenharmony_ci} 188362306a36Sopenharmony_ci 188462306a36Sopenharmony_cistatic bool access_elr(struct kvm_vcpu *vcpu, 188562306a36Sopenharmony_ci struct sys_reg_params *p, 188662306a36Sopenharmony_ci const struct sys_reg_desc *r) 188762306a36Sopenharmony_ci{ 188862306a36Sopenharmony_ci if (p->is_write) 188962306a36Sopenharmony_ci vcpu_write_sys_reg(vcpu, p->regval, ELR_EL1); 189062306a36Sopenharmony_ci else 189162306a36Sopenharmony_ci p->regval = vcpu_read_sys_reg(vcpu, ELR_EL1); 189262306a36Sopenharmony_ci 189362306a36Sopenharmony_ci return true; 189462306a36Sopenharmony_ci} 189562306a36Sopenharmony_ci 189662306a36Sopenharmony_cistatic bool access_spsr(struct kvm_vcpu *vcpu, 189762306a36Sopenharmony_ci struct sys_reg_params *p, 189862306a36Sopenharmony_ci const struct sys_reg_desc *r) 189962306a36Sopenharmony_ci{ 190062306a36Sopenharmony_ci if (p->is_write) 190162306a36Sopenharmony_ci __vcpu_sys_reg(vcpu, SPSR_EL1) = p->regval; 190262306a36Sopenharmony_ci else 190362306a36Sopenharmony_ci p->regval = __vcpu_sys_reg(vcpu, SPSR_EL1); 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_ci return true; 190662306a36Sopenharmony_ci} 190762306a36Sopenharmony_ci 190862306a36Sopenharmony_ci/* 190962306a36Sopenharmony_ci * Architected system registers. 191062306a36Sopenharmony_ci * Important: Must be sorted ascending by Op0, Op1, CRn, CRm, Op2 191162306a36Sopenharmony_ci * 191262306a36Sopenharmony_ci * Debug handling: We do trap most, if not all debug related system 191362306a36Sopenharmony_ci * registers. The implementation is good enough to ensure that a guest 191462306a36Sopenharmony_ci * can use these with minimal performance degradation. The drawback is 191562306a36Sopenharmony_ci * that we don't implement any of the external debug architecture. 191662306a36Sopenharmony_ci * This should be revisited if we ever encounter a more demanding 191762306a36Sopenharmony_ci * guest... 191862306a36Sopenharmony_ci */ 191962306a36Sopenharmony_cistatic const struct sys_reg_desc sys_reg_descs[] = { 192062306a36Sopenharmony_ci { SYS_DESC(SYS_DC_ISW), access_dcsw }, 192162306a36Sopenharmony_ci { SYS_DESC(SYS_DC_IGSW), access_dcgsw }, 192262306a36Sopenharmony_ci { SYS_DESC(SYS_DC_IGDSW), access_dcgsw }, 192362306a36Sopenharmony_ci { SYS_DESC(SYS_DC_CSW), access_dcsw }, 192462306a36Sopenharmony_ci { SYS_DESC(SYS_DC_CGSW), access_dcgsw }, 192562306a36Sopenharmony_ci { SYS_DESC(SYS_DC_CGDSW), access_dcgsw }, 192662306a36Sopenharmony_ci { SYS_DESC(SYS_DC_CISW), access_dcsw }, 192762306a36Sopenharmony_ci { SYS_DESC(SYS_DC_CIGSW), access_dcgsw }, 192862306a36Sopenharmony_ci { SYS_DESC(SYS_DC_CIGDSW), access_dcgsw }, 192962306a36Sopenharmony_ci 193062306a36Sopenharmony_ci DBG_BCR_BVR_WCR_WVR_EL1(0), 193162306a36Sopenharmony_ci DBG_BCR_BVR_WCR_WVR_EL1(1), 193262306a36Sopenharmony_ci { SYS_DESC(SYS_MDCCINT_EL1), trap_debug_regs, reset_val, MDCCINT_EL1, 0 }, 193362306a36Sopenharmony_ci { SYS_DESC(SYS_MDSCR_EL1), trap_debug_regs, reset_val, MDSCR_EL1, 0 }, 193462306a36Sopenharmony_ci DBG_BCR_BVR_WCR_WVR_EL1(2), 193562306a36Sopenharmony_ci DBG_BCR_BVR_WCR_WVR_EL1(3), 193662306a36Sopenharmony_ci DBG_BCR_BVR_WCR_WVR_EL1(4), 193762306a36Sopenharmony_ci DBG_BCR_BVR_WCR_WVR_EL1(5), 193862306a36Sopenharmony_ci DBG_BCR_BVR_WCR_WVR_EL1(6), 193962306a36Sopenharmony_ci DBG_BCR_BVR_WCR_WVR_EL1(7), 194062306a36Sopenharmony_ci DBG_BCR_BVR_WCR_WVR_EL1(8), 194162306a36Sopenharmony_ci DBG_BCR_BVR_WCR_WVR_EL1(9), 194262306a36Sopenharmony_ci DBG_BCR_BVR_WCR_WVR_EL1(10), 194362306a36Sopenharmony_ci DBG_BCR_BVR_WCR_WVR_EL1(11), 194462306a36Sopenharmony_ci DBG_BCR_BVR_WCR_WVR_EL1(12), 194562306a36Sopenharmony_ci DBG_BCR_BVR_WCR_WVR_EL1(13), 194662306a36Sopenharmony_ci DBG_BCR_BVR_WCR_WVR_EL1(14), 194762306a36Sopenharmony_ci DBG_BCR_BVR_WCR_WVR_EL1(15), 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_ci { SYS_DESC(SYS_MDRAR_EL1), trap_raz_wi }, 195062306a36Sopenharmony_ci { SYS_DESC(SYS_OSLAR_EL1), trap_oslar_el1 }, 195162306a36Sopenharmony_ci { SYS_DESC(SYS_OSLSR_EL1), trap_oslsr_el1, reset_val, OSLSR_EL1, 195262306a36Sopenharmony_ci OSLSR_EL1_OSLM_IMPLEMENTED, .set_user = set_oslsr_el1, }, 195362306a36Sopenharmony_ci { SYS_DESC(SYS_OSDLR_EL1), trap_raz_wi }, 195462306a36Sopenharmony_ci { SYS_DESC(SYS_DBGPRCR_EL1), trap_raz_wi }, 195562306a36Sopenharmony_ci { SYS_DESC(SYS_DBGCLAIMSET_EL1), trap_raz_wi }, 195662306a36Sopenharmony_ci { SYS_DESC(SYS_DBGCLAIMCLR_EL1), trap_raz_wi }, 195762306a36Sopenharmony_ci { SYS_DESC(SYS_DBGAUTHSTATUS_EL1), trap_dbgauthstatus_el1 }, 195862306a36Sopenharmony_ci 195962306a36Sopenharmony_ci { SYS_DESC(SYS_MDCCSR_EL0), trap_raz_wi }, 196062306a36Sopenharmony_ci { SYS_DESC(SYS_DBGDTR_EL0), trap_raz_wi }, 196162306a36Sopenharmony_ci // DBGDTR[TR]X_EL0 share the same encoding 196262306a36Sopenharmony_ci { SYS_DESC(SYS_DBGDTRTX_EL0), trap_raz_wi }, 196362306a36Sopenharmony_ci 196462306a36Sopenharmony_ci { SYS_DESC(SYS_DBGVCR32_EL2), NULL, reset_val, DBGVCR32_EL2, 0 }, 196562306a36Sopenharmony_ci 196662306a36Sopenharmony_ci { SYS_DESC(SYS_MPIDR_EL1), NULL, reset_mpidr, MPIDR_EL1 }, 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_ci /* 196962306a36Sopenharmony_ci * ID regs: all ID_SANITISED() entries here must have corresponding 197062306a36Sopenharmony_ci * entries in arm64_ftr_regs[]. 197162306a36Sopenharmony_ci */ 197262306a36Sopenharmony_ci 197362306a36Sopenharmony_ci /* AArch64 mappings of the AArch32 ID registers */ 197462306a36Sopenharmony_ci /* CRm=1 */ 197562306a36Sopenharmony_ci AA32_ID_SANITISED(ID_PFR0_EL1), 197662306a36Sopenharmony_ci AA32_ID_SANITISED(ID_PFR1_EL1), 197762306a36Sopenharmony_ci { SYS_DESC(SYS_ID_DFR0_EL1), 197862306a36Sopenharmony_ci .access = access_id_reg, 197962306a36Sopenharmony_ci .get_user = get_id_reg, 198062306a36Sopenharmony_ci .set_user = set_id_dfr0_el1, 198162306a36Sopenharmony_ci .visibility = aa32_id_visibility, 198262306a36Sopenharmony_ci .reset = read_sanitised_id_dfr0_el1, 198362306a36Sopenharmony_ci .val = ID_DFR0_EL1_PerfMon_MASK, }, 198462306a36Sopenharmony_ci ID_HIDDEN(ID_AFR0_EL1), 198562306a36Sopenharmony_ci AA32_ID_SANITISED(ID_MMFR0_EL1), 198662306a36Sopenharmony_ci AA32_ID_SANITISED(ID_MMFR1_EL1), 198762306a36Sopenharmony_ci AA32_ID_SANITISED(ID_MMFR2_EL1), 198862306a36Sopenharmony_ci AA32_ID_SANITISED(ID_MMFR3_EL1), 198962306a36Sopenharmony_ci 199062306a36Sopenharmony_ci /* CRm=2 */ 199162306a36Sopenharmony_ci AA32_ID_SANITISED(ID_ISAR0_EL1), 199262306a36Sopenharmony_ci AA32_ID_SANITISED(ID_ISAR1_EL1), 199362306a36Sopenharmony_ci AA32_ID_SANITISED(ID_ISAR2_EL1), 199462306a36Sopenharmony_ci AA32_ID_SANITISED(ID_ISAR3_EL1), 199562306a36Sopenharmony_ci AA32_ID_SANITISED(ID_ISAR4_EL1), 199662306a36Sopenharmony_ci AA32_ID_SANITISED(ID_ISAR5_EL1), 199762306a36Sopenharmony_ci AA32_ID_SANITISED(ID_MMFR4_EL1), 199862306a36Sopenharmony_ci AA32_ID_SANITISED(ID_ISAR6_EL1), 199962306a36Sopenharmony_ci 200062306a36Sopenharmony_ci /* CRm=3 */ 200162306a36Sopenharmony_ci AA32_ID_SANITISED(MVFR0_EL1), 200262306a36Sopenharmony_ci AA32_ID_SANITISED(MVFR1_EL1), 200362306a36Sopenharmony_ci AA32_ID_SANITISED(MVFR2_EL1), 200462306a36Sopenharmony_ci ID_UNALLOCATED(3,3), 200562306a36Sopenharmony_ci AA32_ID_SANITISED(ID_PFR2_EL1), 200662306a36Sopenharmony_ci ID_HIDDEN(ID_DFR1_EL1), 200762306a36Sopenharmony_ci AA32_ID_SANITISED(ID_MMFR5_EL1), 200862306a36Sopenharmony_ci ID_UNALLOCATED(3,7), 200962306a36Sopenharmony_ci 201062306a36Sopenharmony_ci /* AArch64 ID registers */ 201162306a36Sopenharmony_ci /* CRm=4 */ 201262306a36Sopenharmony_ci { SYS_DESC(SYS_ID_AA64PFR0_EL1), 201362306a36Sopenharmony_ci .access = access_id_reg, 201462306a36Sopenharmony_ci .get_user = get_id_reg, 201562306a36Sopenharmony_ci .set_user = set_id_reg, 201662306a36Sopenharmony_ci .reset = read_sanitised_id_aa64pfr0_el1, 201762306a36Sopenharmony_ci .val = ID_AA64PFR0_EL1_CSV2_MASK | ID_AA64PFR0_EL1_CSV3_MASK, }, 201862306a36Sopenharmony_ci ID_SANITISED(ID_AA64PFR1_EL1), 201962306a36Sopenharmony_ci ID_UNALLOCATED(4,2), 202062306a36Sopenharmony_ci ID_UNALLOCATED(4,3), 202162306a36Sopenharmony_ci ID_SANITISED(ID_AA64ZFR0_EL1), 202262306a36Sopenharmony_ci ID_HIDDEN(ID_AA64SMFR0_EL1), 202362306a36Sopenharmony_ci ID_UNALLOCATED(4,6), 202462306a36Sopenharmony_ci ID_UNALLOCATED(4,7), 202562306a36Sopenharmony_ci 202662306a36Sopenharmony_ci /* CRm=5 */ 202762306a36Sopenharmony_ci { SYS_DESC(SYS_ID_AA64DFR0_EL1), 202862306a36Sopenharmony_ci .access = access_id_reg, 202962306a36Sopenharmony_ci .get_user = get_id_reg, 203062306a36Sopenharmony_ci .set_user = set_id_aa64dfr0_el1, 203162306a36Sopenharmony_ci .reset = read_sanitised_id_aa64dfr0_el1, 203262306a36Sopenharmony_ci .val = ID_AA64DFR0_EL1_PMUVer_MASK, }, 203362306a36Sopenharmony_ci ID_SANITISED(ID_AA64DFR1_EL1), 203462306a36Sopenharmony_ci ID_UNALLOCATED(5,2), 203562306a36Sopenharmony_ci ID_UNALLOCATED(5,3), 203662306a36Sopenharmony_ci ID_HIDDEN(ID_AA64AFR0_EL1), 203762306a36Sopenharmony_ci ID_HIDDEN(ID_AA64AFR1_EL1), 203862306a36Sopenharmony_ci ID_UNALLOCATED(5,6), 203962306a36Sopenharmony_ci ID_UNALLOCATED(5,7), 204062306a36Sopenharmony_ci 204162306a36Sopenharmony_ci /* CRm=6 */ 204262306a36Sopenharmony_ci ID_SANITISED(ID_AA64ISAR0_EL1), 204362306a36Sopenharmony_ci ID_SANITISED(ID_AA64ISAR1_EL1), 204462306a36Sopenharmony_ci ID_SANITISED(ID_AA64ISAR2_EL1), 204562306a36Sopenharmony_ci ID_UNALLOCATED(6,3), 204662306a36Sopenharmony_ci ID_UNALLOCATED(6,4), 204762306a36Sopenharmony_ci ID_UNALLOCATED(6,5), 204862306a36Sopenharmony_ci ID_UNALLOCATED(6,6), 204962306a36Sopenharmony_ci ID_UNALLOCATED(6,7), 205062306a36Sopenharmony_ci 205162306a36Sopenharmony_ci /* CRm=7 */ 205262306a36Sopenharmony_ci ID_SANITISED(ID_AA64MMFR0_EL1), 205362306a36Sopenharmony_ci ID_SANITISED(ID_AA64MMFR1_EL1), 205462306a36Sopenharmony_ci ID_SANITISED(ID_AA64MMFR2_EL1), 205562306a36Sopenharmony_ci ID_SANITISED(ID_AA64MMFR3_EL1), 205662306a36Sopenharmony_ci ID_UNALLOCATED(7,4), 205762306a36Sopenharmony_ci ID_UNALLOCATED(7,5), 205862306a36Sopenharmony_ci ID_UNALLOCATED(7,6), 205962306a36Sopenharmony_ci ID_UNALLOCATED(7,7), 206062306a36Sopenharmony_ci 206162306a36Sopenharmony_ci { SYS_DESC(SYS_SCTLR_EL1), access_vm_reg, reset_val, SCTLR_EL1, 0x00C50078 }, 206262306a36Sopenharmony_ci { SYS_DESC(SYS_ACTLR_EL1), access_actlr, reset_actlr, ACTLR_EL1 }, 206362306a36Sopenharmony_ci { SYS_DESC(SYS_CPACR_EL1), NULL, reset_val, CPACR_EL1, 0 }, 206462306a36Sopenharmony_ci 206562306a36Sopenharmony_ci MTE_REG(RGSR_EL1), 206662306a36Sopenharmony_ci MTE_REG(GCR_EL1), 206762306a36Sopenharmony_ci 206862306a36Sopenharmony_ci { SYS_DESC(SYS_ZCR_EL1), NULL, reset_val, ZCR_EL1, 0, .visibility = sve_visibility }, 206962306a36Sopenharmony_ci { SYS_DESC(SYS_TRFCR_EL1), undef_access }, 207062306a36Sopenharmony_ci { SYS_DESC(SYS_SMPRI_EL1), undef_access }, 207162306a36Sopenharmony_ci { SYS_DESC(SYS_SMCR_EL1), undef_access }, 207262306a36Sopenharmony_ci { SYS_DESC(SYS_TTBR0_EL1), access_vm_reg, reset_unknown, TTBR0_EL1 }, 207362306a36Sopenharmony_ci { SYS_DESC(SYS_TTBR1_EL1), access_vm_reg, reset_unknown, TTBR1_EL1 }, 207462306a36Sopenharmony_ci { SYS_DESC(SYS_TCR_EL1), access_vm_reg, reset_val, TCR_EL1, 0 }, 207562306a36Sopenharmony_ci { SYS_DESC(SYS_TCR2_EL1), access_vm_reg, reset_val, TCR2_EL1, 0 }, 207662306a36Sopenharmony_ci 207762306a36Sopenharmony_ci PTRAUTH_KEY(APIA), 207862306a36Sopenharmony_ci PTRAUTH_KEY(APIB), 207962306a36Sopenharmony_ci PTRAUTH_KEY(APDA), 208062306a36Sopenharmony_ci PTRAUTH_KEY(APDB), 208162306a36Sopenharmony_ci PTRAUTH_KEY(APGA), 208262306a36Sopenharmony_ci 208362306a36Sopenharmony_ci { SYS_DESC(SYS_SPSR_EL1), access_spsr}, 208462306a36Sopenharmony_ci { SYS_DESC(SYS_ELR_EL1), access_elr}, 208562306a36Sopenharmony_ci 208662306a36Sopenharmony_ci { SYS_DESC(SYS_AFSR0_EL1), access_vm_reg, reset_unknown, AFSR0_EL1 }, 208762306a36Sopenharmony_ci { SYS_DESC(SYS_AFSR1_EL1), access_vm_reg, reset_unknown, AFSR1_EL1 }, 208862306a36Sopenharmony_ci { SYS_DESC(SYS_ESR_EL1), access_vm_reg, reset_unknown, ESR_EL1 }, 208962306a36Sopenharmony_ci 209062306a36Sopenharmony_ci { SYS_DESC(SYS_ERRIDR_EL1), trap_raz_wi }, 209162306a36Sopenharmony_ci { SYS_DESC(SYS_ERRSELR_EL1), trap_raz_wi }, 209262306a36Sopenharmony_ci { SYS_DESC(SYS_ERXFR_EL1), trap_raz_wi }, 209362306a36Sopenharmony_ci { SYS_DESC(SYS_ERXCTLR_EL1), trap_raz_wi }, 209462306a36Sopenharmony_ci { SYS_DESC(SYS_ERXSTATUS_EL1), trap_raz_wi }, 209562306a36Sopenharmony_ci { SYS_DESC(SYS_ERXADDR_EL1), trap_raz_wi }, 209662306a36Sopenharmony_ci { SYS_DESC(SYS_ERXMISC0_EL1), trap_raz_wi }, 209762306a36Sopenharmony_ci { SYS_DESC(SYS_ERXMISC1_EL1), trap_raz_wi }, 209862306a36Sopenharmony_ci 209962306a36Sopenharmony_ci MTE_REG(TFSR_EL1), 210062306a36Sopenharmony_ci MTE_REG(TFSRE0_EL1), 210162306a36Sopenharmony_ci 210262306a36Sopenharmony_ci { SYS_DESC(SYS_FAR_EL1), access_vm_reg, reset_unknown, FAR_EL1 }, 210362306a36Sopenharmony_ci { SYS_DESC(SYS_PAR_EL1), NULL, reset_unknown, PAR_EL1 }, 210462306a36Sopenharmony_ci 210562306a36Sopenharmony_ci { SYS_DESC(SYS_PMSCR_EL1), undef_access }, 210662306a36Sopenharmony_ci { SYS_DESC(SYS_PMSNEVFR_EL1), undef_access }, 210762306a36Sopenharmony_ci { SYS_DESC(SYS_PMSICR_EL1), undef_access }, 210862306a36Sopenharmony_ci { SYS_DESC(SYS_PMSIRR_EL1), undef_access }, 210962306a36Sopenharmony_ci { SYS_DESC(SYS_PMSFCR_EL1), undef_access }, 211062306a36Sopenharmony_ci { SYS_DESC(SYS_PMSEVFR_EL1), undef_access }, 211162306a36Sopenharmony_ci { SYS_DESC(SYS_PMSLATFR_EL1), undef_access }, 211262306a36Sopenharmony_ci { SYS_DESC(SYS_PMSIDR_EL1), undef_access }, 211362306a36Sopenharmony_ci { SYS_DESC(SYS_PMBLIMITR_EL1), undef_access }, 211462306a36Sopenharmony_ci { SYS_DESC(SYS_PMBPTR_EL1), undef_access }, 211562306a36Sopenharmony_ci { SYS_DESC(SYS_PMBSR_EL1), undef_access }, 211662306a36Sopenharmony_ci /* PMBIDR_EL1 is not trapped */ 211762306a36Sopenharmony_ci 211862306a36Sopenharmony_ci { PMU_SYS_REG(PMINTENSET_EL1), 211962306a36Sopenharmony_ci .access = access_pminten, .reg = PMINTENSET_EL1 }, 212062306a36Sopenharmony_ci { PMU_SYS_REG(PMINTENCLR_EL1), 212162306a36Sopenharmony_ci .access = access_pminten, .reg = PMINTENSET_EL1 }, 212262306a36Sopenharmony_ci { SYS_DESC(SYS_PMMIR_EL1), trap_raz_wi }, 212362306a36Sopenharmony_ci 212462306a36Sopenharmony_ci { SYS_DESC(SYS_MAIR_EL1), access_vm_reg, reset_unknown, MAIR_EL1 }, 212562306a36Sopenharmony_ci { SYS_DESC(SYS_PIRE0_EL1), NULL, reset_unknown, PIRE0_EL1 }, 212662306a36Sopenharmony_ci { SYS_DESC(SYS_PIR_EL1), NULL, reset_unknown, PIR_EL1 }, 212762306a36Sopenharmony_ci { SYS_DESC(SYS_AMAIR_EL1), access_vm_reg, reset_amair_el1, AMAIR_EL1 }, 212862306a36Sopenharmony_ci 212962306a36Sopenharmony_ci { SYS_DESC(SYS_LORSA_EL1), trap_loregion }, 213062306a36Sopenharmony_ci { SYS_DESC(SYS_LOREA_EL1), trap_loregion }, 213162306a36Sopenharmony_ci { SYS_DESC(SYS_LORN_EL1), trap_loregion }, 213262306a36Sopenharmony_ci { SYS_DESC(SYS_LORC_EL1), trap_loregion }, 213362306a36Sopenharmony_ci { SYS_DESC(SYS_LORID_EL1), trap_loregion }, 213462306a36Sopenharmony_ci 213562306a36Sopenharmony_ci { SYS_DESC(SYS_VBAR_EL1), access_rw, reset_val, VBAR_EL1, 0 }, 213662306a36Sopenharmony_ci { SYS_DESC(SYS_DISR_EL1), NULL, reset_val, DISR_EL1, 0 }, 213762306a36Sopenharmony_ci 213862306a36Sopenharmony_ci { SYS_DESC(SYS_ICC_IAR0_EL1), write_to_read_only }, 213962306a36Sopenharmony_ci { SYS_DESC(SYS_ICC_EOIR0_EL1), read_from_write_only }, 214062306a36Sopenharmony_ci { SYS_DESC(SYS_ICC_HPPIR0_EL1), write_to_read_only }, 214162306a36Sopenharmony_ci { SYS_DESC(SYS_ICC_DIR_EL1), read_from_write_only }, 214262306a36Sopenharmony_ci { SYS_DESC(SYS_ICC_RPR_EL1), write_to_read_only }, 214362306a36Sopenharmony_ci { SYS_DESC(SYS_ICC_SGI1R_EL1), access_gic_sgi }, 214462306a36Sopenharmony_ci { SYS_DESC(SYS_ICC_ASGI1R_EL1), access_gic_sgi }, 214562306a36Sopenharmony_ci { SYS_DESC(SYS_ICC_SGI0R_EL1), access_gic_sgi }, 214662306a36Sopenharmony_ci { SYS_DESC(SYS_ICC_IAR1_EL1), write_to_read_only }, 214762306a36Sopenharmony_ci { SYS_DESC(SYS_ICC_EOIR1_EL1), read_from_write_only }, 214862306a36Sopenharmony_ci { SYS_DESC(SYS_ICC_HPPIR1_EL1), write_to_read_only }, 214962306a36Sopenharmony_ci { SYS_DESC(SYS_ICC_SRE_EL1), access_gic_sre }, 215062306a36Sopenharmony_ci 215162306a36Sopenharmony_ci { SYS_DESC(SYS_CONTEXTIDR_EL1), access_vm_reg, reset_val, CONTEXTIDR_EL1, 0 }, 215262306a36Sopenharmony_ci { SYS_DESC(SYS_TPIDR_EL1), NULL, reset_unknown, TPIDR_EL1 }, 215362306a36Sopenharmony_ci 215462306a36Sopenharmony_ci { SYS_DESC(SYS_ACCDATA_EL1), undef_access }, 215562306a36Sopenharmony_ci 215662306a36Sopenharmony_ci { SYS_DESC(SYS_SCXTNUM_EL1), undef_access }, 215762306a36Sopenharmony_ci 215862306a36Sopenharmony_ci { SYS_DESC(SYS_CNTKCTL_EL1), NULL, reset_val, CNTKCTL_EL1, 0}, 215962306a36Sopenharmony_ci 216062306a36Sopenharmony_ci { SYS_DESC(SYS_CCSIDR_EL1), access_ccsidr }, 216162306a36Sopenharmony_ci { SYS_DESC(SYS_CLIDR_EL1), access_clidr, reset_clidr, CLIDR_EL1, 216262306a36Sopenharmony_ci .set_user = set_clidr }, 216362306a36Sopenharmony_ci { SYS_DESC(SYS_CCSIDR2_EL1), undef_access }, 216462306a36Sopenharmony_ci { SYS_DESC(SYS_SMIDR_EL1), undef_access }, 216562306a36Sopenharmony_ci { SYS_DESC(SYS_CSSELR_EL1), access_csselr, reset_unknown, CSSELR_EL1 }, 216662306a36Sopenharmony_ci { SYS_DESC(SYS_CTR_EL0), access_ctr }, 216762306a36Sopenharmony_ci { SYS_DESC(SYS_SVCR), undef_access }, 216862306a36Sopenharmony_ci 216962306a36Sopenharmony_ci { PMU_SYS_REG(PMCR_EL0), .access = access_pmcr, 217062306a36Sopenharmony_ci .reset = reset_pmcr, .reg = PMCR_EL0 }, 217162306a36Sopenharmony_ci { PMU_SYS_REG(PMCNTENSET_EL0), 217262306a36Sopenharmony_ci .access = access_pmcnten, .reg = PMCNTENSET_EL0 }, 217362306a36Sopenharmony_ci { PMU_SYS_REG(PMCNTENCLR_EL0), 217462306a36Sopenharmony_ci .access = access_pmcnten, .reg = PMCNTENSET_EL0 }, 217562306a36Sopenharmony_ci { PMU_SYS_REG(PMOVSCLR_EL0), 217662306a36Sopenharmony_ci .access = access_pmovs, .reg = PMOVSSET_EL0 }, 217762306a36Sopenharmony_ci /* 217862306a36Sopenharmony_ci * PM_SWINC_EL0 is exposed to userspace as RAZ/WI, as it was 217962306a36Sopenharmony_ci * previously (and pointlessly) advertised in the past... 218062306a36Sopenharmony_ci */ 218162306a36Sopenharmony_ci { PMU_SYS_REG(PMSWINC_EL0), 218262306a36Sopenharmony_ci .get_user = get_raz_reg, .set_user = set_wi_reg, 218362306a36Sopenharmony_ci .access = access_pmswinc, .reset = NULL }, 218462306a36Sopenharmony_ci { PMU_SYS_REG(PMSELR_EL0), 218562306a36Sopenharmony_ci .access = access_pmselr, .reset = reset_pmselr, .reg = PMSELR_EL0 }, 218662306a36Sopenharmony_ci { PMU_SYS_REG(PMCEID0_EL0), 218762306a36Sopenharmony_ci .access = access_pmceid, .reset = NULL }, 218862306a36Sopenharmony_ci { PMU_SYS_REG(PMCEID1_EL0), 218962306a36Sopenharmony_ci .access = access_pmceid, .reset = NULL }, 219062306a36Sopenharmony_ci { PMU_SYS_REG(PMCCNTR_EL0), 219162306a36Sopenharmony_ci .access = access_pmu_evcntr, .reset = reset_unknown, 219262306a36Sopenharmony_ci .reg = PMCCNTR_EL0, .get_user = get_pmu_evcntr}, 219362306a36Sopenharmony_ci { PMU_SYS_REG(PMXEVTYPER_EL0), 219462306a36Sopenharmony_ci .access = access_pmu_evtyper, .reset = NULL }, 219562306a36Sopenharmony_ci { PMU_SYS_REG(PMXEVCNTR_EL0), 219662306a36Sopenharmony_ci .access = access_pmu_evcntr, .reset = NULL }, 219762306a36Sopenharmony_ci /* 219862306a36Sopenharmony_ci * PMUSERENR_EL0 resets as unknown in 64bit mode while it resets as zero 219962306a36Sopenharmony_ci * in 32bit mode. Here we choose to reset it as zero for consistency. 220062306a36Sopenharmony_ci */ 220162306a36Sopenharmony_ci { PMU_SYS_REG(PMUSERENR_EL0), .access = access_pmuserenr, 220262306a36Sopenharmony_ci .reset = reset_val, .reg = PMUSERENR_EL0, .val = 0 }, 220362306a36Sopenharmony_ci { PMU_SYS_REG(PMOVSSET_EL0), 220462306a36Sopenharmony_ci .access = access_pmovs, .reg = PMOVSSET_EL0 }, 220562306a36Sopenharmony_ci 220662306a36Sopenharmony_ci { SYS_DESC(SYS_TPIDR_EL0), NULL, reset_unknown, TPIDR_EL0 }, 220762306a36Sopenharmony_ci { SYS_DESC(SYS_TPIDRRO_EL0), NULL, reset_unknown, TPIDRRO_EL0 }, 220862306a36Sopenharmony_ci { SYS_DESC(SYS_TPIDR2_EL0), undef_access }, 220962306a36Sopenharmony_ci 221062306a36Sopenharmony_ci { SYS_DESC(SYS_SCXTNUM_EL0), undef_access }, 221162306a36Sopenharmony_ci 221262306a36Sopenharmony_ci { SYS_DESC(SYS_AMCR_EL0), undef_access }, 221362306a36Sopenharmony_ci { SYS_DESC(SYS_AMCFGR_EL0), undef_access }, 221462306a36Sopenharmony_ci { SYS_DESC(SYS_AMCGCR_EL0), undef_access }, 221562306a36Sopenharmony_ci { SYS_DESC(SYS_AMUSERENR_EL0), undef_access }, 221662306a36Sopenharmony_ci { SYS_DESC(SYS_AMCNTENCLR0_EL0), undef_access }, 221762306a36Sopenharmony_ci { SYS_DESC(SYS_AMCNTENSET0_EL0), undef_access }, 221862306a36Sopenharmony_ci { SYS_DESC(SYS_AMCNTENCLR1_EL0), undef_access }, 221962306a36Sopenharmony_ci { SYS_DESC(SYS_AMCNTENSET1_EL0), undef_access }, 222062306a36Sopenharmony_ci AMU_AMEVCNTR0_EL0(0), 222162306a36Sopenharmony_ci AMU_AMEVCNTR0_EL0(1), 222262306a36Sopenharmony_ci AMU_AMEVCNTR0_EL0(2), 222362306a36Sopenharmony_ci AMU_AMEVCNTR0_EL0(3), 222462306a36Sopenharmony_ci AMU_AMEVCNTR0_EL0(4), 222562306a36Sopenharmony_ci AMU_AMEVCNTR0_EL0(5), 222662306a36Sopenharmony_ci AMU_AMEVCNTR0_EL0(6), 222762306a36Sopenharmony_ci AMU_AMEVCNTR0_EL0(7), 222862306a36Sopenharmony_ci AMU_AMEVCNTR0_EL0(8), 222962306a36Sopenharmony_ci AMU_AMEVCNTR0_EL0(9), 223062306a36Sopenharmony_ci AMU_AMEVCNTR0_EL0(10), 223162306a36Sopenharmony_ci AMU_AMEVCNTR0_EL0(11), 223262306a36Sopenharmony_ci AMU_AMEVCNTR0_EL0(12), 223362306a36Sopenharmony_ci AMU_AMEVCNTR0_EL0(13), 223462306a36Sopenharmony_ci AMU_AMEVCNTR0_EL0(14), 223562306a36Sopenharmony_ci AMU_AMEVCNTR0_EL0(15), 223662306a36Sopenharmony_ci AMU_AMEVTYPER0_EL0(0), 223762306a36Sopenharmony_ci AMU_AMEVTYPER0_EL0(1), 223862306a36Sopenharmony_ci AMU_AMEVTYPER0_EL0(2), 223962306a36Sopenharmony_ci AMU_AMEVTYPER0_EL0(3), 224062306a36Sopenharmony_ci AMU_AMEVTYPER0_EL0(4), 224162306a36Sopenharmony_ci AMU_AMEVTYPER0_EL0(5), 224262306a36Sopenharmony_ci AMU_AMEVTYPER0_EL0(6), 224362306a36Sopenharmony_ci AMU_AMEVTYPER0_EL0(7), 224462306a36Sopenharmony_ci AMU_AMEVTYPER0_EL0(8), 224562306a36Sopenharmony_ci AMU_AMEVTYPER0_EL0(9), 224662306a36Sopenharmony_ci AMU_AMEVTYPER0_EL0(10), 224762306a36Sopenharmony_ci AMU_AMEVTYPER0_EL0(11), 224862306a36Sopenharmony_ci AMU_AMEVTYPER0_EL0(12), 224962306a36Sopenharmony_ci AMU_AMEVTYPER0_EL0(13), 225062306a36Sopenharmony_ci AMU_AMEVTYPER0_EL0(14), 225162306a36Sopenharmony_ci AMU_AMEVTYPER0_EL0(15), 225262306a36Sopenharmony_ci AMU_AMEVCNTR1_EL0(0), 225362306a36Sopenharmony_ci AMU_AMEVCNTR1_EL0(1), 225462306a36Sopenharmony_ci AMU_AMEVCNTR1_EL0(2), 225562306a36Sopenharmony_ci AMU_AMEVCNTR1_EL0(3), 225662306a36Sopenharmony_ci AMU_AMEVCNTR1_EL0(4), 225762306a36Sopenharmony_ci AMU_AMEVCNTR1_EL0(5), 225862306a36Sopenharmony_ci AMU_AMEVCNTR1_EL0(6), 225962306a36Sopenharmony_ci AMU_AMEVCNTR1_EL0(7), 226062306a36Sopenharmony_ci AMU_AMEVCNTR1_EL0(8), 226162306a36Sopenharmony_ci AMU_AMEVCNTR1_EL0(9), 226262306a36Sopenharmony_ci AMU_AMEVCNTR1_EL0(10), 226362306a36Sopenharmony_ci AMU_AMEVCNTR1_EL0(11), 226462306a36Sopenharmony_ci AMU_AMEVCNTR1_EL0(12), 226562306a36Sopenharmony_ci AMU_AMEVCNTR1_EL0(13), 226662306a36Sopenharmony_ci AMU_AMEVCNTR1_EL0(14), 226762306a36Sopenharmony_ci AMU_AMEVCNTR1_EL0(15), 226862306a36Sopenharmony_ci AMU_AMEVTYPER1_EL0(0), 226962306a36Sopenharmony_ci AMU_AMEVTYPER1_EL0(1), 227062306a36Sopenharmony_ci AMU_AMEVTYPER1_EL0(2), 227162306a36Sopenharmony_ci AMU_AMEVTYPER1_EL0(3), 227262306a36Sopenharmony_ci AMU_AMEVTYPER1_EL0(4), 227362306a36Sopenharmony_ci AMU_AMEVTYPER1_EL0(5), 227462306a36Sopenharmony_ci AMU_AMEVTYPER1_EL0(6), 227562306a36Sopenharmony_ci AMU_AMEVTYPER1_EL0(7), 227662306a36Sopenharmony_ci AMU_AMEVTYPER1_EL0(8), 227762306a36Sopenharmony_ci AMU_AMEVTYPER1_EL0(9), 227862306a36Sopenharmony_ci AMU_AMEVTYPER1_EL0(10), 227962306a36Sopenharmony_ci AMU_AMEVTYPER1_EL0(11), 228062306a36Sopenharmony_ci AMU_AMEVTYPER1_EL0(12), 228162306a36Sopenharmony_ci AMU_AMEVTYPER1_EL0(13), 228262306a36Sopenharmony_ci AMU_AMEVTYPER1_EL0(14), 228362306a36Sopenharmony_ci AMU_AMEVTYPER1_EL0(15), 228462306a36Sopenharmony_ci 228562306a36Sopenharmony_ci { SYS_DESC(SYS_CNTPCT_EL0), access_arch_timer }, 228662306a36Sopenharmony_ci { SYS_DESC(SYS_CNTPCTSS_EL0), access_arch_timer }, 228762306a36Sopenharmony_ci { SYS_DESC(SYS_CNTP_TVAL_EL0), access_arch_timer }, 228862306a36Sopenharmony_ci { SYS_DESC(SYS_CNTP_CTL_EL0), access_arch_timer }, 228962306a36Sopenharmony_ci { SYS_DESC(SYS_CNTP_CVAL_EL0), access_arch_timer }, 229062306a36Sopenharmony_ci 229162306a36Sopenharmony_ci /* PMEVCNTRn_EL0 */ 229262306a36Sopenharmony_ci PMU_PMEVCNTR_EL0(0), 229362306a36Sopenharmony_ci PMU_PMEVCNTR_EL0(1), 229462306a36Sopenharmony_ci PMU_PMEVCNTR_EL0(2), 229562306a36Sopenharmony_ci PMU_PMEVCNTR_EL0(3), 229662306a36Sopenharmony_ci PMU_PMEVCNTR_EL0(4), 229762306a36Sopenharmony_ci PMU_PMEVCNTR_EL0(5), 229862306a36Sopenharmony_ci PMU_PMEVCNTR_EL0(6), 229962306a36Sopenharmony_ci PMU_PMEVCNTR_EL0(7), 230062306a36Sopenharmony_ci PMU_PMEVCNTR_EL0(8), 230162306a36Sopenharmony_ci PMU_PMEVCNTR_EL0(9), 230262306a36Sopenharmony_ci PMU_PMEVCNTR_EL0(10), 230362306a36Sopenharmony_ci PMU_PMEVCNTR_EL0(11), 230462306a36Sopenharmony_ci PMU_PMEVCNTR_EL0(12), 230562306a36Sopenharmony_ci PMU_PMEVCNTR_EL0(13), 230662306a36Sopenharmony_ci PMU_PMEVCNTR_EL0(14), 230762306a36Sopenharmony_ci PMU_PMEVCNTR_EL0(15), 230862306a36Sopenharmony_ci PMU_PMEVCNTR_EL0(16), 230962306a36Sopenharmony_ci PMU_PMEVCNTR_EL0(17), 231062306a36Sopenharmony_ci PMU_PMEVCNTR_EL0(18), 231162306a36Sopenharmony_ci PMU_PMEVCNTR_EL0(19), 231262306a36Sopenharmony_ci PMU_PMEVCNTR_EL0(20), 231362306a36Sopenharmony_ci PMU_PMEVCNTR_EL0(21), 231462306a36Sopenharmony_ci PMU_PMEVCNTR_EL0(22), 231562306a36Sopenharmony_ci PMU_PMEVCNTR_EL0(23), 231662306a36Sopenharmony_ci PMU_PMEVCNTR_EL0(24), 231762306a36Sopenharmony_ci PMU_PMEVCNTR_EL0(25), 231862306a36Sopenharmony_ci PMU_PMEVCNTR_EL0(26), 231962306a36Sopenharmony_ci PMU_PMEVCNTR_EL0(27), 232062306a36Sopenharmony_ci PMU_PMEVCNTR_EL0(28), 232162306a36Sopenharmony_ci PMU_PMEVCNTR_EL0(29), 232262306a36Sopenharmony_ci PMU_PMEVCNTR_EL0(30), 232362306a36Sopenharmony_ci /* PMEVTYPERn_EL0 */ 232462306a36Sopenharmony_ci PMU_PMEVTYPER_EL0(0), 232562306a36Sopenharmony_ci PMU_PMEVTYPER_EL0(1), 232662306a36Sopenharmony_ci PMU_PMEVTYPER_EL0(2), 232762306a36Sopenharmony_ci PMU_PMEVTYPER_EL0(3), 232862306a36Sopenharmony_ci PMU_PMEVTYPER_EL0(4), 232962306a36Sopenharmony_ci PMU_PMEVTYPER_EL0(5), 233062306a36Sopenharmony_ci PMU_PMEVTYPER_EL0(6), 233162306a36Sopenharmony_ci PMU_PMEVTYPER_EL0(7), 233262306a36Sopenharmony_ci PMU_PMEVTYPER_EL0(8), 233362306a36Sopenharmony_ci PMU_PMEVTYPER_EL0(9), 233462306a36Sopenharmony_ci PMU_PMEVTYPER_EL0(10), 233562306a36Sopenharmony_ci PMU_PMEVTYPER_EL0(11), 233662306a36Sopenharmony_ci PMU_PMEVTYPER_EL0(12), 233762306a36Sopenharmony_ci PMU_PMEVTYPER_EL0(13), 233862306a36Sopenharmony_ci PMU_PMEVTYPER_EL0(14), 233962306a36Sopenharmony_ci PMU_PMEVTYPER_EL0(15), 234062306a36Sopenharmony_ci PMU_PMEVTYPER_EL0(16), 234162306a36Sopenharmony_ci PMU_PMEVTYPER_EL0(17), 234262306a36Sopenharmony_ci PMU_PMEVTYPER_EL0(18), 234362306a36Sopenharmony_ci PMU_PMEVTYPER_EL0(19), 234462306a36Sopenharmony_ci PMU_PMEVTYPER_EL0(20), 234562306a36Sopenharmony_ci PMU_PMEVTYPER_EL0(21), 234662306a36Sopenharmony_ci PMU_PMEVTYPER_EL0(22), 234762306a36Sopenharmony_ci PMU_PMEVTYPER_EL0(23), 234862306a36Sopenharmony_ci PMU_PMEVTYPER_EL0(24), 234962306a36Sopenharmony_ci PMU_PMEVTYPER_EL0(25), 235062306a36Sopenharmony_ci PMU_PMEVTYPER_EL0(26), 235162306a36Sopenharmony_ci PMU_PMEVTYPER_EL0(27), 235262306a36Sopenharmony_ci PMU_PMEVTYPER_EL0(28), 235362306a36Sopenharmony_ci PMU_PMEVTYPER_EL0(29), 235462306a36Sopenharmony_ci PMU_PMEVTYPER_EL0(30), 235562306a36Sopenharmony_ci /* 235662306a36Sopenharmony_ci * PMCCFILTR_EL0 resets as unknown in 64bit mode while it resets as zero 235762306a36Sopenharmony_ci * in 32bit mode. Here we choose to reset it as zero for consistency. 235862306a36Sopenharmony_ci */ 235962306a36Sopenharmony_ci { PMU_SYS_REG(PMCCFILTR_EL0), .access = access_pmu_evtyper, 236062306a36Sopenharmony_ci .reset = reset_val, .reg = PMCCFILTR_EL0, .val = 0 }, 236162306a36Sopenharmony_ci 236262306a36Sopenharmony_ci EL2_REG(VPIDR_EL2, access_rw, reset_unknown, 0), 236362306a36Sopenharmony_ci EL2_REG(VMPIDR_EL2, access_rw, reset_unknown, 0), 236462306a36Sopenharmony_ci EL2_REG(SCTLR_EL2, access_rw, reset_val, SCTLR_EL2_RES1), 236562306a36Sopenharmony_ci EL2_REG(ACTLR_EL2, access_rw, reset_val, 0), 236662306a36Sopenharmony_ci EL2_REG(HCR_EL2, access_rw, reset_val, 0), 236762306a36Sopenharmony_ci EL2_REG(MDCR_EL2, access_rw, reset_val, 0), 236862306a36Sopenharmony_ci EL2_REG(CPTR_EL2, access_rw, reset_val, CPTR_NVHE_EL2_RES1), 236962306a36Sopenharmony_ci EL2_REG(HSTR_EL2, access_rw, reset_val, 0), 237062306a36Sopenharmony_ci EL2_REG(HFGRTR_EL2, access_rw, reset_val, 0), 237162306a36Sopenharmony_ci EL2_REG(HFGWTR_EL2, access_rw, reset_val, 0), 237262306a36Sopenharmony_ci EL2_REG(HFGITR_EL2, access_rw, reset_val, 0), 237362306a36Sopenharmony_ci EL2_REG(HACR_EL2, access_rw, reset_val, 0), 237462306a36Sopenharmony_ci 237562306a36Sopenharmony_ci EL2_REG(HCRX_EL2, access_rw, reset_val, 0), 237662306a36Sopenharmony_ci 237762306a36Sopenharmony_ci EL2_REG(TTBR0_EL2, access_rw, reset_val, 0), 237862306a36Sopenharmony_ci EL2_REG(TTBR1_EL2, access_rw, reset_val, 0), 237962306a36Sopenharmony_ci EL2_REG(TCR_EL2, access_rw, reset_val, TCR_EL2_RES1), 238062306a36Sopenharmony_ci EL2_REG(VTTBR_EL2, access_rw, reset_val, 0), 238162306a36Sopenharmony_ci EL2_REG(VTCR_EL2, access_rw, reset_val, 0), 238262306a36Sopenharmony_ci 238362306a36Sopenharmony_ci { SYS_DESC(SYS_DACR32_EL2), NULL, reset_unknown, DACR32_EL2 }, 238462306a36Sopenharmony_ci EL2_REG(HDFGRTR_EL2, access_rw, reset_val, 0), 238562306a36Sopenharmony_ci EL2_REG(HDFGWTR_EL2, access_rw, reset_val, 0), 238662306a36Sopenharmony_ci EL2_REG(SPSR_EL2, access_rw, reset_val, 0), 238762306a36Sopenharmony_ci EL2_REG(ELR_EL2, access_rw, reset_val, 0), 238862306a36Sopenharmony_ci { SYS_DESC(SYS_SP_EL1), access_sp_el1}, 238962306a36Sopenharmony_ci 239062306a36Sopenharmony_ci { SYS_DESC(SYS_IFSR32_EL2), NULL, reset_unknown, IFSR32_EL2 }, 239162306a36Sopenharmony_ci EL2_REG(AFSR0_EL2, access_rw, reset_val, 0), 239262306a36Sopenharmony_ci EL2_REG(AFSR1_EL2, access_rw, reset_val, 0), 239362306a36Sopenharmony_ci EL2_REG(ESR_EL2, access_rw, reset_val, 0), 239462306a36Sopenharmony_ci { SYS_DESC(SYS_FPEXC32_EL2), NULL, reset_val, FPEXC32_EL2, 0x700 }, 239562306a36Sopenharmony_ci 239662306a36Sopenharmony_ci EL2_REG(FAR_EL2, access_rw, reset_val, 0), 239762306a36Sopenharmony_ci EL2_REG(HPFAR_EL2, access_rw, reset_val, 0), 239862306a36Sopenharmony_ci 239962306a36Sopenharmony_ci EL2_REG(MAIR_EL2, access_rw, reset_val, 0), 240062306a36Sopenharmony_ci EL2_REG(AMAIR_EL2, access_rw, reset_val, 0), 240162306a36Sopenharmony_ci 240262306a36Sopenharmony_ci EL2_REG(VBAR_EL2, access_rw, reset_val, 0), 240362306a36Sopenharmony_ci EL2_REG(RVBAR_EL2, access_rw, reset_val, 0), 240462306a36Sopenharmony_ci { SYS_DESC(SYS_RMR_EL2), trap_undef }, 240562306a36Sopenharmony_ci 240662306a36Sopenharmony_ci EL2_REG(CONTEXTIDR_EL2, access_rw, reset_val, 0), 240762306a36Sopenharmony_ci EL2_REG(TPIDR_EL2, access_rw, reset_val, 0), 240862306a36Sopenharmony_ci 240962306a36Sopenharmony_ci EL2_REG(CNTVOFF_EL2, access_rw, reset_val, 0), 241062306a36Sopenharmony_ci EL2_REG(CNTHCTL_EL2, access_rw, reset_val, 0), 241162306a36Sopenharmony_ci 241262306a36Sopenharmony_ci EL12_REG(SCTLR, access_vm_reg, reset_val, 0x00C50078), 241362306a36Sopenharmony_ci EL12_REG(CPACR, access_rw, reset_val, 0), 241462306a36Sopenharmony_ci EL12_REG(TTBR0, access_vm_reg, reset_unknown, 0), 241562306a36Sopenharmony_ci EL12_REG(TTBR1, access_vm_reg, reset_unknown, 0), 241662306a36Sopenharmony_ci EL12_REG(TCR, access_vm_reg, reset_val, 0), 241762306a36Sopenharmony_ci { SYS_DESC(SYS_SPSR_EL12), access_spsr}, 241862306a36Sopenharmony_ci { SYS_DESC(SYS_ELR_EL12), access_elr}, 241962306a36Sopenharmony_ci EL12_REG(AFSR0, access_vm_reg, reset_unknown, 0), 242062306a36Sopenharmony_ci EL12_REG(AFSR1, access_vm_reg, reset_unknown, 0), 242162306a36Sopenharmony_ci EL12_REG(ESR, access_vm_reg, reset_unknown, 0), 242262306a36Sopenharmony_ci EL12_REG(FAR, access_vm_reg, reset_unknown, 0), 242362306a36Sopenharmony_ci EL12_REG(MAIR, access_vm_reg, reset_unknown, 0), 242462306a36Sopenharmony_ci EL12_REG(AMAIR, access_vm_reg, reset_amair_el1, 0), 242562306a36Sopenharmony_ci EL12_REG(VBAR, access_rw, reset_val, 0), 242662306a36Sopenharmony_ci EL12_REG(CONTEXTIDR, access_vm_reg, reset_val, 0), 242762306a36Sopenharmony_ci EL12_REG(CNTKCTL, access_rw, reset_val, 0), 242862306a36Sopenharmony_ci 242962306a36Sopenharmony_ci EL2_REG(SP_EL2, NULL, reset_unknown, 0), 243062306a36Sopenharmony_ci}; 243162306a36Sopenharmony_ci 243262306a36Sopenharmony_cistatic const struct sys_reg_desc *first_idreg; 243362306a36Sopenharmony_ci 243462306a36Sopenharmony_cistatic bool trap_dbgdidr(struct kvm_vcpu *vcpu, 243562306a36Sopenharmony_ci struct sys_reg_params *p, 243662306a36Sopenharmony_ci const struct sys_reg_desc *r) 243762306a36Sopenharmony_ci{ 243862306a36Sopenharmony_ci if (p->is_write) { 243962306a36Sopenharmony_ci return ignore_write(vcpu, p); 244062306a36Sopenharmony_ci } else { 244162306a36Sopenharmony_ci u64 dfr = read_sanitised_ftr_reg(SYS_ID_AA64DFR0_EL1); 244262306a36Sopenharmony_ci u64 pfr = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1); 244362306a36Sopenharmony_ci u32 el3 = !!cpuid_feature_extract_unsigned_field(pfr, ID_AA64PFR0_EL1_EL3_SHIFT); 244462306a36Sopenharmony_ci 244562306a36Sopenharmony_ci p->regval = ((((dfr >> ID_AA64DFR0_EL1_WRPs_SHIFT) & 0xf) << 28) | 244662306a36Sopenharmony_ci (((dfr >> ID_AA64DFR0_EL1_BRPs_SHIFT) & 0xf) << 24) | 244762306a36Sopenharmony_ci (((dfr >> ID_AA64DFR0_EL1_CTX_CMPs_SHIFT) & 0xf) << 20) 244862306a36Sopenharmony_ci | (6 << 16) | (1 << 15) | (el3 << 14) | (el3 << 12)); 244962306a36Sopenharmony_ci return true; 245062306a36Sopenharmony_ci } 245162306a36Sopenharmony_ci} 245262306a36Sopenharmony_ci 245362306a36Sopenharmony_ci/* 245462306a36Sopenharmony_ci * AArch32 debug register mappings 245562306a36Sopenharmony_ci * 245662306a36Sopenharmony_ci * AArch32 DBGBVRn is mapped to DBGBVRn_EL1[31:0] 245762306a36Sopenharmony_ci * AArch32 DBGBXVRn is mapped to DBGBVRn_EL1[63:32] 245862306a36Sopenharmony_ci * 245962306a36Sopenharmony_ci * None of the other registers share their location, so treat them as 246062306a36Sopenharmony_ci * if they were 64bit. 246162306a36Sopenharmony_ci */ 246262306a36Sopenharmony_ci#define DBG_BCR_BVR_WCR_WVR(n) \ 246362306a36Sopenharmony_ci /* DBGBVRn */ \ 246462306a36Sopenharmony_ci { AA32(LO), Op1( 0), CRn( 0), CRm((n)), Op2( 4), trap_bvr, NULL, n }, \ 246562306a36Sopenharmony_ci /* DBGBCRn */ \ 246662306a36Sopenharmony_ci { Op1( 0), CRn( 0), CRm((n)), Op2( 5), trap_bcr, NULL, n }, \ 246762306a36Sopenharmony_ci /* DBGWVRn */ \ 246862306a36Sopenharmony_ci { Op1( 0), CRn( 0), CRm((n)), Op2( 6), trap_wvr, NULL, n }, \ 246962306a36Sopenharmony_ci /* DBGWCRn */ \ 247062306a36Sopenharmony_ci { Op1( 0), CRn( 0), CRm((n)), Op2( 7), trap_wcr, NULL, n } 247162306a36Sopenharmony_ci 247262306a36Sopenharmony_ci#define DBGBXVR(n) \ 247362306a36Sopenharmony_ci { AA32(HI), Op1( 0), CRn( 1), CRm((n)), Op2( 1), trap_bvr, NULL, n } 247462306a36Sopenharmony_ci 247562306a36Sopenharmony_ci/* 247662306a36Sopenharmony_ci * Trapped cp14 registers. We generally ignore most of the external 247762306a36Sopenharmony_ci * debug, on the principle that they don't really make sense to a 247862306a36Sopenharmony_ci * guest. Revisit this one day, would this principle change. 247962306a36Sopenharmony_ci */ 248062306a36Sopenharmony_cistatic const struct sys_reg_desc cp14_regs[] = { 248162306a36Sopenharmony_ci /* DBGDIDR */ 248262306a36Sopenharmony_ci { Op1( 0), CRn( 0), CRm( 0), Op2( 0), trap_dbgdidr }, 248362306a36Sopenharmony_ci /* DBGDTRRXext */ 248462306a36Sopenharmony_ci { Op1( 0), CRn( 0), CRm( 0), Op2( 2), trap_raz_wi }, 248562306a36Sopenharmony_ci 248662306a36Sopenharmony_ci DBG_BCR_BVR_WCR_WVR(0), 248762306a36Sopenharmony_ci /* DBGDSCRint */ 248862306a36Sopenharmony_ci { Op1( 0), CRn( 0), CRm( 1), Op2( 0), trap_raz_wi }, 248962306a36Sopenharmony_ci DBG_BCR_BVR_WCR_WVR(1), 249062306a36Sopenharmony_ci /* DBGDCCINT */ 249162306a36Sopenharmony_ci { Op1( 0), CRn( 0), CRm( 2), Op2( 0), trap_debug_regs, NULL, MDCCINT_EL1 }, 249262306a36Sopenharmony_ci /* DBGDSCRext */ 249362306a36Sopenharmony_ci { Op1( 0), CRn( 0), CRm( 2), Op2( 2), trap_debug_regs, NULL, MDSCR_EL1 }, 249462306a36Sopenharmony_ci DBG_BCR_BVR_WCR_WVR(2), 249562306a36Sopenharmony_ci /* DBGDTR[RT]Xint */ 249662306a36Sopenharmony_ci { Op1( 0), CRn( 0), CRm( 3), Op2( 0), trap_raz_wi }, 249762306a36Sopenharmony_ci /* DBGDTR[RT]Xext */ 249862306a36Sopenharmony_ci { Op1( 0), CRn( 0), CRm( 3), Op2( 2), trap_raz_wi }, 249962306a36Sopenharmony_ci DBG_BCR_BVR_WCR_WVR(3), 250062306a36Sopenharmony_ci DBG_BCR_BVR_WCR_WVR(4), 250162306a36Sopenharmony_ci DBG_BCR_BVR_WCR_WVR(5), 250262306a36Sopenharmony_ci /* DBGWFAR */ 250362306a36Sopenharmony_ci { Op1( 0), CRn( 0), CRm( 6), Op2( 0), trap_raz_wi }, 250462306a36Sopenharmony_ci /* DBGOSECCR */ 250562306a36Sopenharmony_ci { Op1( 0), CRn( 0), CRm( 6), Op2( 2), trap_raz_wi }, 250662306a36Sopenharmony_ci DBG_BCR_BVR_WCR_WVR(6), 250762306a36Sopenharmony_ci /* DBGVCR */ 250862306a36Sopenharmony_ci { Op1( 0), CRn( 0), CRm( 7), Op2( 0), trap_debug_regs, NULL, DBGVCR32_EL2 }, 250962306a36Sopenharmony_ci DBG_BCR_BVR_WCR_WVR(7), 251062306a36Sopenharmony_ci DBG_BCR_BVR_WCR_WVR(8), 251162306a36Sopenharmony_ci DBG_BCR_BVR_WCR_WVR(9), 251262306a36Sopenharmony_ci DBG_BCR_BVR_WCR_WVR(10), 251362306a36Sopenharmony_ci DBG_BCR_BVR_WCR_WVR(11), 251462306a36Sopenharmony_ci DBG_BCR_BVR_WCR_WVR(12), 251562306a36Sopenharmony_ci DBG_BCR_BVR_WCR_WVR(13), 251662306a36Sopenharmony_ci DBG_BCR_BVR_WCR_WVR(14), 251762306a36Sopenharmony_ci DBG_BCR_BVR_WCR_WVR(15), 251862306a36Sopenharmony_ci 251962306a36Sopenharmony_ci /* DBGDRAR (32bit) */ 252062306a36Sopenharmony_ci { Op1( 0), CRn( 1), CRm( 0), Op2( 0), trap_raz_wi }, 252162306a36Sopenharmony_ci 252262306a36Sopenharmony_ci DBGBXVR(0), 252362306a36Sopenharmony_ci /* DBGOSLAR */ 252462306a36Sopenharmony_ci { Op1( 0), CRn( 1), CRm( 0), Op2( 4), trap_oslar_el1 }, 252562306a36Sopenharmony_ci DBGBXVR(1), 252662306a36Sopenharmony_ci /* DBGOSLSR */ 252762306a36Sopenharmony_ci { Op1( 0), CRn( 1), CRm( 1), Op2( 4), trap_oslsr_el1, NULL, OSLSR_EL1 }, 252862306a36Sopenharmony_ci DBGBXVR(2), 252962306a36Sopenharmony_ci DBGBXVR(3), 253062306a36Sopenharmony_ci /* DBGOSDLR */ 253162306a36Sopenharmony_ci { Op1( 0), CRn( 1), CRm( 3), Op2( 4), trap_raz_wi }, 253262306a36Sopenharmony_ci DBGBXVR(4), 253362306a36Sopenharmony_ci /* DBGPRCR */ 253462306a36Sopenharmony_ci { Op1( 0), CRn( 1), CRm( 4), Op2( 4), trap_raz_wi }, 253562306a36Sopenharmony_ci DBGBXVR(5), 253662306a36Sopenharmony_ci DBGBXVR(6), 253762306a36Sopenharmony_ci DBGBXVR(7), 253862306a36Sopenharmony_ci DBGBXVR(8), 253962306a36Sopenharmony_ci DBGBXVR(9), 254062306a36Sopenharmony_ci DBGBXVR(10), 254162306a36Sopenharmony_ci DBGBXVR(11), 254262306a36Sopenharmony_ci DBGBXVR(12), 254362306a36Sopenharmony_ci DBGBXVR(13), 254462306a36Sopenharmony_ci DBGBXVR(14), 254562306a36Sopenharmony_ci DBGBXVR(15), 254662306a36Sopenharmony_ci 254762306a36Sopenharmony_ci /* DBGDSAR (32bit) */ 254862306a36Sopenharmony_ci { Op1( 0), CRn( 2), CRm( 0), Op2( 0), trap_raz_wi }, 254962306a36Sopenharmony_ci 255062306a36Sopenharmony_ci /* DBGDEVID2 */ 255162306a36Sopenharmony_ci { Op1( 0), CRn( 7), CRm( 0), Op2( 7), trap_raz_wi }, 255262306a36Sopenharmony_ci /* DBGDEVID1 */ 255362306a36Sopenharmony_ci { Op1( 0), CRn( 7), CRm( 1), Op2( 7), trap_raz_wi }, 255462306a36Sopenharmony_ci /* DBGDEVID */ 255562306a36Sopenharmony_ci { Op1( 0), CRn( 7), CRm( 2), Op2( 7), trap_raz_wi }, 255662306a36Sopenharmony_ci /* DBGCLAIMSET */ 255762306a36Sopenharmony_ci { Op1( 0), CRn( 7), CRm( 8), Op2( 6), trap_raz_wi }, 255862306a36Sopenharmony_ci /* DBGCLAIMCLR */ 255962306a36Sopenharmony_ci { Op1( 0), CRn( 7), CRm( 9), Op2( 6), trap_raz_wi }, 256062306a36Sopenharmony_ci /* DBGAUTHSTATUS */ 256162306a36Sopenharmony_ci { Op1( 0), CRn( 7), CRm(14), Op2( 6), trap_dbgauthstatus_el1 }, 256262306a36Sopenharmony_ci}; 256362306a36Sopenharmony_ci 256462306a36Sopenharmony_ci/* Trapped cp14 64bit registers */ 256562306a36Sopenharmony_cistatic const struct sys_reg_desc cp14_64_regs[] = { 256662306a36Sopenharmony_ci /* DBGDRAR (64bit) */ 256762306a36Sopenharmony_ci { Op1( 0), CRm( 1), .access = trap_raz_wi }, 256862306a36Sopenharmony_ci 256962306a36Sopenharmony_ci /* DBGDSAR (64bit) */ 257062306a36Sopenharmony_ci { Op1( 0), CRm( 2), .access = trap_raz_wi }, 257162306a36Sopenharmony_ci}; 257262306a36Sopenharmony_ci 257362306a36Sopenharmony_ci#define CP15_PMU_SYS_REG(_map, _Op1, _CRn, _CRm, _Op2) \ 257462306a36Sopenharmony_ci AA32(_map), \ 257562306a36Sopenharmony_ci Op1(_Op1), CRn(_CRn), CRm(_CRm), Op2(_Op2), \ 257662306a36Sopenharmony_ci .visibility = pmu_visibility 257762306a36Sopenharmony_ci 257862306a36Sopenharmony_ci/* Macro to expand the PMEVCNTRn register */ 257962306a36Sopenharmony_ci#define PMU_PMEVCNTR(n) \ 258062306a36Sopenharmony_ci { CP15_PMU_SYS_REG(DIRECT, 0, 0b1110, \ 258162306a36Sopenharmony_ci (0b1000 | (((n) >> 3) & 0x3)), ((n) & 0x7)), \ 258262306a36Sopenharmony_ci .access = access_pmu_evcntr } 258362306a36Sopenharmony_ci 258462306a36Sopenharmony_ci/* Macro to expand the PMEVTYPERn register */ 258562306a36Sopenharmony_ci#define PMU_PMEVTYPER(n) \ 258662306a36Sopenharmony_ci { CP15_PMU_SYS_REG(DIRECT, 0, 0b1110, \ 258762306a36Sopenharmony_ci (0b1100 | (((n) >> 3) & 0x3)), ((n) & 0x7)), \ 258862306a36Sopenharmony_ci .access = access_pmu_evtyper } 258962306a36Sopenharmony_ci/* 259062306a36Sopenharmony_ci * Trapped cp15 registers. TTBR0/TTBR1 get a double encoding, 259162306a36Sopenharmony_ci * depending on the way they are accessed (as a 32bit or a 64bit 259262306a36Sopenharmony_ci * register). 259362306a36Sopenharmony_ci */ 259462306a36Sopenharmony_cistatic const struct sys_reg_desc cp15_regs[] = { 259562306a36Sopenharmony_ci { Op1( 0), CRn( 0), CRm( 0), Op2( 1), access_ctr }, 259662306a36Sopenharmony_ci { Op1( 0), CRn( 1), CRm( 0), Op2( 0), access_vm_reg, NULL, SCTLR_EL1 }, 259762306a36Sopenharmony_ci /* ACTLR */ 259862306a36Sopenharmony_ci { AA32(LO), Op1( 0), CRn( 1), CRm( 0), Op2( 1), access_actlr, NULL, ACTLR_EL1 }, 259962306a36Sopenharmony_ci /* ACTLR2 */ 260062306a36Sopenharmony_ci { AA32(HI), Op1( 0), CRn( 1), CRm( 0), Op2( 3), access_actlr, NULL, ACTLR_EL1 }, 260162306a36Sopenharmony_ci { Op1( 0), CRn( 2), CRm( 0), Op2( 0), access_vm_reg, NULL, TTBR0_EL1 }, 260262306a36Sopenharmony_ci { Op1( 0), CRn( 2), CRm( 0), Op2( 1), access_vm_reg, NULL, TTBR1_EL1 }, 260362306a36Sopenharmony_ci /* TTBCR */ 260462306a36Sopenharmony_ci { AA32(LO), Op1( 0), CRn( 2), CRm( 0), Op2( 2), access_vm_reg, NULL, TCR_EL1 }, 260562306a36Sopenharmony_ci /* TTBCR2 */ 260662306a36Sopenharmony_ci { AA32(HI), Op1( 0), CRn( 2), CRm( 0), Op2( 3), access_vm_reg, NULL, TCR_EL1 }, 260762306a36Sopenharmony_ci { Op1( 0), CRn( 3), CRm( 0), Op2( 0), access_vm_reg, NULL, DACR32_EL2 }, 260862306a36Sopenharmony_ci /* DFSR */ 260962306a36Sopenharmony_ci { Op1( 0), CRn( 5), CRm( 0), Op2( 0), access_vm_reg, NULL, ESR_EL1 }, 261062306a36Sopenharmony_ci { Op1( 0), CRn( 5), CRm( 0), Op2( 1), access_vm_reg, NULL, IFSR32_EL2 }, 261162306a36Sopenharmony_ci /* ADFSR */ 261262306a36Sopenharmony_ci { Op1( 0), CRn( 5), CRm( 1), Op2( 0), access_vm_reg, NULL, AFSR0_EL1 }, 261362306a36Sopenharmony_ci /* AIFSR */ 261462306a36Sopenharmony_ci { Op1( 0), CRn( 5), CRm( 1), Op2( 1), access_vm_reg, NULL, AFSR1_EL1 }, 261562306a36Sopenharmony_ci /* DFAR */ 261662306a36Sopenharmony_ci { AA32(LO), Op1( 0), CRn( 6), CRm( 0), Op2( 0), access_vm_reg, NULL, FAR_EL1 }, 261762306a36Sopenharmony_ci /* IFAR */ 261862306a36Sopenharmony_ci { AA32(HI), Op1( 0), CRn( 6), CRm( 0), Op2( 2), access_vm_reg, NULL, FAR_EL1 }, 261962306a36Sopenharmony_ci 262062306a36Sopenharmony_ci /* 262162306a36Sopenharmony_ci * DC{C,I,CI}SW operations: 262262306a36Sopenharmony_ci */ 262362306a36Sopenharmony_ci { Op1( 0), CRn( 7), CRm( 6), Op2( 2), access_dcsw }, 262462306a36Sopenharmony_ci { Op1( 0), CRn( 7), CRm(10), Op2( 2), access_dcsw }, 262562306a36Sopenharmony_ci { Op1( 0), CRn( 7), CRm(14), Op2( 2), access_dcsw }, 262662306a36Sopenharmony_ci 262762306a36Sopenharmony_ci /* PMU */ 262862306a36Sopenharmony_ci { CP15_PMU_SYS_REG(DIRECT, 0, 9, 12, 0), .access = access_pmcr }, 262962306a36Sopenharmony_ci { CP15_PMU_SYS_REG(DIRECT, 0, 9, 12, 1), .access = access_pmcnten }, 263062306a36Sopenharmony_ci { CP15_PMU_SYS_REG(DIRECT, 0, 9, 12, 2), .access = access_pmcnten }, 263162306a36Sopenharmony_ci { CP15_PMU_SYS_REG(DIRECT, 0, 9, 12, 3), .access = access_pmovs }, 263262306a36Sopenharmony_ci { CP15_PMU_SYS_REG(DIRECT, 0, 9, 12, 4), .access = access_pmswinc }, 263362306a36Sopenharmony_ci { CP15_PMU_SYS_REG(DIRECT, 0, 9, 12, 5), .access = access_pmselr }, 263462306a36Sopenharmony_ci { CP15_PMU_SYS_REG(LO, 0, 9, 12, 6), .access = access_pmceid }, 263562306a36Sopenharmony_ci { CP15_PMU_SYS_REG(LO, 0, 9, 12, 7), .access = access_pmceid }, 263662306a36Sopenharmony_ci { CP15_PMU_SYS_REG(DIRECT, 0, 9, 13, 0), .access = access_pmu_evcntr }, 263762306a36Sopenharmony_ci { CP15_PMU_SYS_REG(DIRECT, 0, 9, 13, 1), .access = access_pmu_evtyper }, 263862306a36Sopenharmony_ci { CP15_PMU_SYS_REG(DIRECT, 0, 9, 13, 2), .access = access_pmu_evcntr }, 263962306a36Sopenharmony_ci { CP15_PMU_SYS_REG(DIRECT, 0, 9, 14, 0), .access = access_pmuserenr }, 264062306a36Sopenharmony_ci { CP15_PMU_SYS_REG(DIRECT, 0, 9, 14, 1), .access = access_pminten }, 264162306a36Sopenharmony_ci { CP15_PMU_SYS_REG(DIRECT, 0, 9, 14, 2), .access = access_pminten }, 264262306a36Sopenharmony_ci { CP15_PMU_SYS_REG(DIRECT, 0, 9, 14, 3), .access = access_pmovs }, 264362306a36Sopenharmony_ci { CP15_PMU_SYS_REG(HI, 0, 9, 14, 4), .access = access_pmceid }, 264462306a36Sopenharmony_ci { CP15_PMU_SYS_REG(HI, 0, 9, 14, 5), .access = access_pmceid }, 264562306a36Sopenharmony_ci /* PMMIR */ 264662306a36Sopenharmony_ci { CP15_PMU_SYS_REG(DIRECT, 0, 9, 14, 6), .access = trap_raz_wi }, 264762306a36Sopenharmony_ci 264862306a36Sopenharmony_ci /* PRRR/MAIR0 */ 264962306a36Sopenharmony_ci { AA32(LO), Op1( 0), CRn(10), CRm( 2), Op2( 0), access_vm_reg, NULL, MAIR_EL1 }, 265062306a36Sopenharmony_ci /* NMRR/MAIR1 */ 265162306a36Sopenharmony_ci { AA32(HI), Op1( 0), CRn(10), CRm( 2), Op2( 1), access_vm_reg, NULL, MAIR_EL1 }, 265262306a36Sopenharmony_ci /* AMAIR0 */ 265362306a36Sopenharmony_ci { AA32(LO), Op1( 0), CRn(10), CRm( 3), Op2( 0), access_vm_reg, NULL, AMAIR_EL1 }, 265462306a36Sopenharmony_ci /* AMAIR1 */ 265562306a36Sopenharmony_ci { AA32(HI), Op1( 0), CRn(10), CRm( 3), Op2( 1), access_vm_reg, NULL, AMAIR_EL1 }, 265662306a36Sopenharmony_ci 265762306a36Sopenharmony_ci /* ICC_SRE */ 265862306a36Sopenharmony_ci { Op1( 0), CRn(12), CRm(12), Op2( 5), access_gic_sre }, 265962306a36Sopenharmony_ci 266062306a36Sopenharmony_ci { Op1( 0), CRn(13), CRm( 0), Op2( 1), access_vm_reg, NULL, CONTEXTIDR_EL1 }, 266162306a36Sopenharmony_ci 266262306a36Sopenharmony_ci /* Arch Tmers */ 266362306a36Sopenharmony_ci { SYS_DESC(SYS_AARCH32_CNTP_TVAL), access_arch_timer }, 266462306a36Sopenharmony_ci { SYS_DESC(SYS_AARCH32_CNTP_CTL), access_arch_timer }, 266562306a36Sopenharmony_ci 266662306a36Sopenharmony_ci /* PMEVCNTRn */ 266762306a36Sopenharmony_ci PMU_PMEVCNTR(0), 266862306a36Sopenharmony_ci PMU_PMEVCNTR(1), 266962306a36Sopenharmony_ci PMU_PMEVCNTR(2), 267062306a36Sopenharmony_ci PMU_PMEVCNTR(3), 267162306a36Sopenharmony_ci PMU_PMEVCNTR(4), 267262306a36Sopenharmony_ci PMU_PMEVCNTR(5), 267362306a36Sopenharmony_ci PMU_PMEVCNTR(6), 267462306a36Sopenharmony_ci PMU_PMEVCNTR(7), 267562306a36Sopenharmony_ci PMU_PMEVCNTR(8), 267662306a36Sopenharmony_ci PMU_PMEVCNTR(9), 267762306a36Sopenharmony_ci PMU_PMEVCNTR(10), 267862306a36Sopenharmony_ci PMU_PMEVCNTR(11), 267962306a36Sopenharmony_ci PMU_PMEVCNTR(12), 268062306a36Sopenharmony_ci PMU_PMEVCNTR(13), 268162306a36Sopenharmony_ci PMU_PMEVCNTR(14), 268262306a36Sopenharmony_ci PMU_PMEVCNTR(15), 268362306a36Sopenharmony_ci PMU_PMEVCNTR(16), 268462306a36Sopenharmony_ci PMU_PMEVCNTR(17), 268562306a36Sopenharmony_ci PMU_PMEVCNTR(18), 268662306a36Sopenharmony_ci PMU_PMEVCNTR(19), 268762306a36Sopenharmony_ci PMU_PMEVCNTR(20), 268862306a36Sopenharmony_ci PMU_PMEVCNTR(21), 268962306a36Sopenharmony_ci PMU_PMEVCNTR(22), 269062306a36Sopenharmony_ci PMU_PMEVCNTR(23), 269162306a36Sopenharmony_ci PMU_PMEVCNTR(24), 269262306a36Sopenharmony_ci PMU_PMEVCNTR(25), 269362306a36Sopenharmony_ci PMU_PMEVCNTR(26), 269462306a36Sopenharmony_ci PMU_PMEVCNTR(27), 269562306a36Sopenharmony_ci PMU_PMEVCNTR(28), 269662306a36Sopenharmony_ci PMU_PMEVCNTR(29), 269762306a36Sopenharmony_ci PMU_PMEVCNTR(30), 269862306a36Sopenharmony_ci /* PMEVTYPERn */ 269962306a36Sopenharmony_ci PMU_PMEVTYPER(0), 270062306a36Sopenharmony_ci PMU_PMEVTYPER(1), 270162306a36Sopenharmony_ci PMU_PMEVTYPER(2), 270262306a36Sopenharmony_ci PMU_PMEVTYPER(3), 270362306a36Sopenharmony_ci PMU_PMEVTYPER(4), 270462306a36Sopenharmony_ci PMU_PMEVTYPER(5), 270562306a36Sopenharmony_ci PMU_PMEVTYPER(6), 270662306a36Sopenharmony_ci PMU_PMEVTYPER(7), 270762306a36Sopenharmony_ci PMU_PMEVTYPER(8), 270862306a36Sopenharmony_ci PMU_PMEVTYPER(9), 270962306a36Sopenharmony_ci PMU_PMEVTYPER(10), 271062306a36Sopenharmony_ci PMU_PMEVTYPER(11), 271162306a36Sopenharmony_ci PMU_PMEVTYPER(12), 271262306a36Sopenharmony_ci PMU_PMEVTYPER(13), 271362306a36Sopenharmony_ci PMU_PMEVTYPER(14), 271462306a36Sopenharmony_ci PMU_PMEVTYPER(15), 271562306a36Sopenharmony_ci PMU_PMEVTYPER(16), 271662306a36Sopenharmony_ci PMU_PMEVTYPER(17), 271762306a36Sopenharmony_ci PMU_PMEVTYPER(18), 271862306a36Sopenharmony_ci PMU_PMEVTYPER(19), 271962306a36Sopenharmony_ci PMU_PMEVTYPER(20), 272062306a36Sopenharmony_ci PMU_PMEVTYPER(21), 272162306a36Sopenharmony_ci PMU_PMEVTYPER(22), 272262306a36Sopenharmony_ci PMU_PMEVTYPER(23), 272362306a36Sopenharmony_ci PMU_PMEVTYPER(24), 272462306a36Sopenharmony_ci PMU_PMEVTYPER(25), 272562306a36Sopenharmony_ci PMU_PMEVTYPER(26), 272662306a36Sopenharmony_ci PMU_PMEVTYPER(27), 272762306a36Sopenharmony_ci PMU_PMEVTYPER(28), 272862306a36Sopenharmony_ci PMU_PMEVTYPER(29), 272962306a36Sopenharmony_ci PMU_PMEVTYPER(30), 273062306a36Sopenharmony_ci /* PMCCFILTR */ 273162306a36Sopenharmony_ci { CP15_PMU_SYS_REG(DIRECT, 0, 14, 15, 7), .access = access_pmu_evtyper }, 273262306a36Sopenharmony_ci 273362306a36Sopenharmony_ci { Op1(1), CRn( 0), CRm( 0), Op2(0), access_ccsidr }, 273462306a36Sopenharmony_ci { Op1(1), CRn( 0), CRm( 0), Op2(1), access_clidr }, 273562306a36Sopenharmony_ci 273662306a36Sopenharmony_ci /* CCSIDR2 */ 273762306a36Sopenharmony_ci { Op1(1), CRn( 0), CRm( 0), Op2(2), undef_access }, 273862306a36Sopenharmony_ci 273962306a36Sopenharmony_ci { Op1(2), CRn( 0), CRm( 0), Op2(0), access_csselr, NULL, CSSELR_EL1 }, 274062306a36Sopenharmony_ci}; 274162306a36Sopenharmony_ci 274262306a36Sopenharmony_cistatic const struct sys_reg_desc cp15_64_regs[] = { 274362306a36Sopenharmony_ci { Op1( 0), CRn( 0), CRm( 2), Op2( 0), access_vm_reg, NULL, TTBR0_EL1 }, 274462306a36Sopenharmony_ci { CP15_PMU_SYS_REG(DIRECT, 0, 0, 9, 0), .access = access_pmu_evcntr }, 274562306a36Sopenharmony_ci { Op1( 0), CRn( 0), CRm(12), Op2( 0), access_gic_sgi }, /* ICC_SGI1R */ 274662306a36Sopenharmony_ci { SYS_DESC(SYS_AARCH32_CNTPCT), access_arch_timer }, 274762306a36Sopenharmony_ci { Op1( 1), CRn( 0), CRm( 2), Op2( 0), access_vm_reg, NULL, TTBR1_EL1 }, 274862306a36Sopenharmony_ci { Op1( 1), CRn( 0), CRm(12), Op2( 0), access_gic_sgi }, /* ICC_ASGI1R */ 274962306a36Sopenharmony_ci { Op1( 2), CRn( 0), CRm(12), Op2( 0), access_gic_sgi }, /* ICC_SGI0R */ 275062306a36Sopenharmony_ci { SYS_DESC(SYS_AARCH32_CNTP_CVAL), access_arch_timer }, 275162306a36Sopenharmony_ci { SYS_DESC(SYS_AARCH32_CNTPCTSS), access_arch_timer }, 275262306a36Sopenharmony_ci}; 275362306a36Sopenharmony_ci 275462306a36Sopenharmony_cistatic bool check_sysreg_table(const struct sys_reg_desc *table, unsigned int n, 275562306a36Sopenharmony_ci bool is_32) 275662306a36Sopenharmony_ci{ 275762306a36Sopenharmony_ci unsigned int i; 275862306a36Sopenharmony_ci 275962306a36Sopenharmony_ci for (i = 0; i < n; i++) { 276062306a36Sopenharmony_ci if (!is_32 && table[i].reg && !table[i].reset) { 276162306a36Sopenharmony_ci kvm_err("sys_reg table %pS entry %d lacks reset\n", &table[i], i); 276262306a36Sopenharmony_ci return false; 276362306a36Sopenharmony_ci } 276462306a36Sopenharmony_ci 276562306a36Sopenharmony_ci if (i && cmp_sys_reg(&table[i-1], &table[i]) >= 0) { 276662306a36Sopenharmony_ci kvm_err("sys_reg table %pS entry %d out of order\n", &table[i - 1], i - 1); 276762306a36Sopenharmony_ci return false; 276862306a36Sopenharmony_ci } 276962306a36Sopenharmony_ci } 277062306a36Sopenharmony_ci 277162306a36Sopenharmony_ci return true; 277262306a36Sopenharmony_ci} 277362306a36Sopenharmony_ci 277462306a36Sopenharmony_ciint kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu) 277562306a36Sopenharmony_ci{ 277662306a36Sopenharmony_ci kvm_inject_undefined(vcpu); 277762306a36Sopenharmony_ci return 1; 277862306a36Sopenharmony_ci} 277962306a36Sopenharmony_ci 278062306a36Sopenharmony_cistatic void perform_access(struct kvm_vcpu *vcpu, 278162306a36Sopenharmony_ci struct sys_reg_params *params, 278262306a36Sopenharmony_ci const struct sys_reg_desc *r) 278362306a36Sopenharmony_ci{ 278462306a36Sopenharmony_ci trace_kvm_sys_access(*vcpu_pc(vcpu), params, r); 278562306a36Sopenharmony_ci 278662306a36Sopenharmony_ci /* Check for regs disabled by runtime config */ 278762306a36Sopenharmony_ci if (sysreg_hidden(vcpu, r)) { 278862306a36Sopenharmony_ci kvm_inject_undefined(vcpu); 278962306a36Sopenharmony_ci return; 279062306a36Sopenharmony_ci } 279162306a36Sopenharmony_ci 279262306a36Sopenharmony_ci /* 279362306a36Sopenharmony_ci * Not having an accessor means that we have configured a trap 279462306a36Sopenharmony_ci * that we don't know how to handle. This certainly qualifies 279562306a36Sopenharmony_ci * as a gross bug that should be fixed right away. 279662306a36Sopenharmony_ci */ 279762306a36Sopenharmony_ci BUG_ON(!r->access); 279862306a36Sopenharmony_ci 279962306a36Sopenharmony_ci /* Skip instruction if instructed so */ 280062306a36Sopenharmony_ci if (likely(r->access(vcpu, params, r))) 280162306a36Sopenharmony_ci kvm_incr_pc(vcpu); 280262306a36Sopenharmony_ci} 280362306a36Sopenharmony_ci 280462306a36Sopenharmony_ci/* 280562306a36Sopenharmony_ci * emulate_cp -- tries to match a sys_reg access in a handling table, and 280662306a36Sopenharmony_ci * call the corresponding trap handler. 280762306a36Sopenharmony_ci * 280862306a36Sopenharmony_ci * @params: pointer to the descriptor of the access 280962306a36Sopenharmony_ci * @table: array of trap descriptors 281062306a36Sopenharmony_ci * @num: size of the trap descriptor array 281162306a36Sopenharmony_ci * 281262306a36Sopenharmony_ci * Return true if the access has been handled, false if not. 281362306a36Sopenharmony_ci */ 281462306a36Sopenharmony_cistatic bool emulate_cp(struct kvm_vcpu *vcpu, 281562306a36Sopenharmony_ci struct sys_reg_params *params, 281662306a36Sopenharmony_ci const struct sys_reg_desc *table, 281762306a36Sopenharmony_ci size_t num) 281862306a36Sopenharmony_ci{ 281962306a36Sopenharmony_ci const struct sys_reg_desc *r; 282062306a36Sopenharmony_ci 282162306a36Sopenharmony_ci if (!table) 282262306a36Sopenharmony_ci return false; /* Not handled */ 282362306a36Sopenharmony_ci 282462306a36Sopenharmony_ci r = find_reg(params, table, num); 282562306a36Sopenharmony_ci 282662306a36Sopenharmony_ci if (r) { 282762306a36Sopenharmony_ci perform_access(vcpu, params, r); 282862306a36Sopenharmony_ci return true; 282962306a36Sopenharmony_ci } 283062306a36Sopenharmony_ci 283162306a36Sopenharmony_ci /* Not handled */ 283262306a36Sopenharmony_ci return false; 283362306a36Sopenharmony_ci} 283462306a36Sopenharmony_ci 283562306a36Sopenharmony_cistatic void unhandled_cp_access(struct kvm_vcpu *vcpu, 283662306a36Sopenharmony_ci struct sys_reg_params *params) 283762306a36Sopenharmony_ci{ 283862306a36Sopenharmony_ci u8 esr_ec = kvm_vcpu_trap_get_class(vcpu); 283962306a36Sopenharmony_ci int cp = -1; 284062306a36Sopenharmony_ci 284162306a36Sopenharmony_ci switch (esr_ec) { 284262306a36Sopenharmony_ci case ESR_ELx_EC_CP15_32: 284362306a36Sopenharmony_ci case ESR_ELx_EC_CP15_64: 284462306a36Sopenharmony_ci cp = 15; 284562306a36Sopenharmony_ci break; 284662306a36Sopenharmony_ci case ESR_ELx_EC_CP14_MR: 284762306a36Sopenharmony_ci case ESR_ELx_EC_CP14_64: 284862306a36Sopenharmony_ci cp = 14; 284962306a36Sopenharmony_ci break; 285062306a36Sopenharmony_ci default: 285162306a36Sopenharmony_ci WARN_ON(1); 285262306a36Sopenharmony_ci } 285362306a36Sopenharmony_ci 285462306a36Sopenharmony_ci print_sys_reg_msg(params, 285562306a36Sopenharmony_ci "Unsupported guest CP%d access at: %08lx [%08lx]\n", 285662306a36Sopenharmony_ci cp, *vcpu_pc(vcpu), *vcpu_cpsr(vcpu)); 285762306a36Sopenharmony_ci kvm_inject_undefined(vcpu); 285862306a36Sopenharmony_ci} 285962306a36Sopenharmony_ci 286062306a36Sopenharmony_ci/** 286162306a36Sopenharmony_ci * kvm_handle_cp_64 -- handles a mrrc/mcrr trap on a guest CP14/CP15 access 286262306a36Sopenharmony_ci * @vcpu: The VCPU pointer 286362306a36Sopenharmony_ci * @run: The kvm_run struct 286462306a36Sopenharmony_ci */ 286562306a36Sopenharmony_cistatic int kvm_handle_cp_64(struct kvm_vcpu *vcpu, 286662306a36Sopenharmony_ci const struct sys_reg_desc *global, 286762306a36Sopenharmony_ci size_t nr_global) 286862306a36Sopenharmony_ci{ 286962306a36Sopenharmony_ci struct sys_reg_params params; 287062306a36Sopenharmony_ci u64 esr = kvm_vcpu_get_esr(vcpu); 287162306a36Sopenharmony_ci int Rt = kvm_vcpu_sys_get_rt(vcpu); 287262306a36Sopenharmony_ci int Rt2 = (esr >> 10) & 0x1f; 287362306a36Sopenharmony_ci 287462306a36Sopenharmony_ci params.CRm = (esr >> 1) & 0xf; 287562306a36Sopenharmony_ci params.is_write = ((esr & 1) == 0); 287662306a36Sopenharmony_ci 287762306a36Sopenharmony_ci params.Op0 = 0; 287862306a36Sopenharmony_ci params.Op1 = (esr >> 16) & 0xf; 287962306a36Sopenharmony_ci params.Op2 = 0; 288062306a36Sopenharmony_ci params.CRn = 0; 288162306a36Sopenharmony_ci 288262306a36Sopenharmony_ci /* 288362306a36Sopenharmony_ci * Make a 64-bit value out of Rt and Rt2. As we use the same trap 288462306a36Sopenharmony_ci * backends between AArch32 and AArch64, we get away with it. 288562306a36Sopenharmony_ci */ 288662306a36Sopenharmony_ci if (params.is_write) { 288762306a36Sopenharmony_ci params.regval = vcpu_get_reg(vcpu, Rt) & 0xffffffff; 288862306a36Sopenharmony_ci params.regval |= vcpu_get_reg(vcpu, Rt2) << 32; 288962306a36Sopenharmony_ci } 289062306a36Sopenharmony_ci 289162306a36Sopenharmony_ci /* 289262306a36Sopenharmony_ci * If the table contains a handler, handle the 289362306a36Sopenharmony_ci * potential register operation in the case of a read and return 289462306a36Sopenharmony_ci * with success. 289562306a36Sopenharmony_ci */ 289662306a36Sopenharmony_ci if (emulate_cp(vcpu, ¶ms, global, nr_global)) { 289762306a36Sopenharmony_ci /* Split up the value between registers for the read side */ 289862306a36Sopenharmony_ci if (!params.is_write) { 289962306a36Sopenharmony_ci vcpu_set_reg(vcpu, Rt, lower_32_bits(params.regval)); 290062306a36Sopenharmony_ci vcpu_set_reg(vcpu, Rt2, upper_32_bits(params.regval)); 290162306a36Sopenharmony_ci } 290262306a36Sopenharmony_ci 290362306a36Sopenharmony_ci return 1; 290462306a36Sopenharmony_ci } 290562306a36Sopenharmony_ci 290662306a36Sopenharmony_ci unhandled_cp_access(vcpu, ¶ms); 290762306a36Sopenharmony_ci return 1; 290862306a36Sopenharmony_ci} 290962306a36Sopenharmony_ci 291062306a36Sopenharmony_cistatic bool emulate_sys_reg(struct kvm_vcpu *vcpu, struct sys_reg_params *params); 291162306a36Sopenharmony_ci 291262306a36Sopenharmony_ci/* 291362306a36Sopenharmony_ci * The CP10 ID registers are architecturally mapped to AArch64 feature 291462306a36Sopenharmony_ci * registers. Abuse that fact so we can rely on the AArch64 handler for accesses 291562306a36Sopenharmony_ci * from AArch32. 291662306a36Sopenharmony_ci */ 291762306a36Sopenharmony_cistatic bool kvm_esr_cp10_id_to_sys64(u64 esr, struct sys_reg_params *params) 291862306a36Sopenharmony_ci{ 291962306a36Sopenharmony_ci u8 reg_id = (esr >> 10) & 0xf; 292062306a36Sopenharmony_ci bool valid; 292162306a36Sopenharmony_ci 292262306a36Sopenharmony_ci params->is_write = ((esr & 1) == 0); 292362306a36Sopenharmony_ci params->Op0 = 3; 292462306a36Sopenharmony_ci params->Op1 = 0; 292562306a36Sopenharmony_ci params->CRn = 0; 292662306a36Sopenharmony_ci params->CRm = 3; 292762306a36Sopenharmony_ci 292862306a36Sopenharmony_ci /* CP10 ID registers are read-only */ 292962306a36Sopenharmony_ci valid = !params->is_write; 293062306a36Sopenharmony_ci 293162306a36Sopenharmony_ci switch (reg_id) { 293262306a36Sopenharmony_ci /* MVFR0 */ 293362306a36Sopenharmony_ci case 0b0111: 293462306a36Sopenharmony_ci params->Op2 = 0; 293562306a36Sopenharmony_ci break; 293662306a36Sopenharmony_ci /* MVFR1 */ 293762306a36Sopenharmony_ci case 0b0110: 293862306a36Sopenharmony_ci params->Op2 = 1; 293962306a36Sopenharmony_ci break; 294062306a36Sopenharmony_ci /* MVFR2 */ 294162306a36Sopenharmony_ci case 0b0101: 294262306a36Sopenharmony_ci params->Op2 = 2; 294362306a36Sopenharmony_ci break; 294462306a36Sopenharmony_ci default: 294562306a36Sopenharmony_ci valid = false; 294662306a36Sopenharmony_ci } 294762306a36Sopenharmony_ci 294862306a36Sopenharmony_ci if (valid) 294962306a36Sopenharmony_ci return true; 295062306a36Sopenharmony_ci 295162306a36Sopenharmony_ci kvm_pr_unimpl("Unhandled cp10 register %s: %u\n", 295262306a36Sopenharmony_ci params->is_write ? "write" : "read", reg_id); 295362306a36Sopenharmony_ci return false; 295462306a36Sopenharmony_ci} 295562306a36Sopenharmony_ci 295662306a36Sopenharmony_ci/** 295762306a36Sopenharmony_ci * kvm_handle_cp10_id() - Handles a VMRS trap on guest access to a 'Media and 295862306a36Sopenharmony_ci * VFP Register' from AArch32. 295962306a36Sopenharmony_ci * @vcpu: The vCPU pointer 296062306a36Sopenharmony_ci * 296162306a36Sopenharmony_ci * MVFR{0-2} are architecturally mapped to the AArch64 MVFR{0-2}_EL1 registers. 296262306a36Sopenharmony_ci * Work out the correct AArch64 system register encoding and reroute to the 296362306a36Sopenharmony_ci * AArch64 system register emulation. 296462306a36Sopenharmony_ci */ 296562306a36Sopenharmony_ciint kvm_handle_cp10_id(struct kvm_vcpu *vcpu) 296662306a36Sopenharmony_ci{ 296762306a36Sopenharmony_ci int Rt = kvm_vcpu_sys_get_rt(vcpu); 296862306a36Sopenharmony_ci u64 esr = kvm_vcpu_get_esr(vcpu); 296962306a36Sopenharmony_ci struct sys_reg_params params; 297062306a36Sopenharmony_ci 297162306a36Sopenharmony_ci /* UNDEF on any unhandled register access */ 297262306a36Sopenharmony_ci if (!kvm_esr_cp10_id_to_sys64(esr, ¶ms)) { 297362306a36Sopenharmony_ci kvm_inject_undefined(vcpu); 297462306a36Sopenharmony_ci return 1; 297562306a36Sopenharmony_ci } 297662306a36Sopenharmony_ci 297762306a36Sopenharmony_ci if (emulate_sys_reg(vcpu, ¶ms)) 297862306a36Sopenharmony_ci vcpu_set_reg(vcpu, Rt, params.regval); 297962306a36Sopenharmony_ci 298062306a36Sopenharmony_ci return 1; 298162306a36Sopenharmony_ci} 298262306a36Sopenharmony_ci 298362306a36Sopenharmony_ci/** 298462306a36Sopenharmony_ci * kvm_emulate_cp15_id_reg() - Handles an MRC trap on a guest CP15 access where 298562306a36Sopenharmony_ci * CRn=0, which corresponds to the AArch32 feature 298662306a36Sopenharmony_ci * registers. 298762306a36Sopenharmony_ci * @vcpu: the vCPU pointer 298862306a36Sopenharmony_ci * @params: the system register access parameters. 298962306a36Sopenharmony_ci * 299062306a36Sopenharmony_ci * Our cp15 system register tables do not enumerate the AArch32 feature 299162306a36Sopenharmony_ci * registers. Conveniently, our AArch64 table does, and the AArch32 system 299262306a36Sopenharmony_ci * register encoding can be trivially remapped into the AArch64 for the feature 299362306a36Sopenharmony_ci * registers: Append op0=3, leaving op1, CRn, CRm, and op2 the same. 299462306a36Sopenharmony_ci * 299562306a36Sopenharmony_ci * According to DDI0487G.b G7.3.1, paragraph "Behavior of VMSAv8-32 32-bit 299662306a36Sopenharmony_ci * System registers with (coproc=0b1111, CRn==c0)", read accesses from this 299762306a36Sopenharmony_ci * range are either UNKNOWN or RES0. Rerouting remains architectural as we 299862306a36Sopenharmony_ci * treat undefined registers in this range as RAZ. 299962306a36Sopenharmony_ci */ 300062306a36Sopenharmony_cistatic int kvm_emulate_cp15_id_reg(struct kvm_vcpu *vcpu, 300162306a36Sopenharmony_ci struct sys_reg_params *params) 300262306a36Sopenharmony_ci{ 300362306a36Sopenharmony_ci int Rt = kvm_vcpu_sys_get_rt(vcpu); 300462306a36Sopenharmony_ci 300562306a36Sopenharmony_ci /* Treat impossible writes to RO registers as UNDEFINED */ 300662306a36Sopenharmony_ci if (params->is_write) { 300762306a36Sopenharmony_ci unhandled_cp_access(vcpu, params); 300862306a36Sopenharmony_ci return 1; 300962306a36Sopenharmony_ci } 301062306a36Sopenharmony_ci 301162306a36Sopenharmony_ci params->Op0 = 3; 301262306a36Sopenharmony_ci 301362306a36Sopenharmony_ci /* 301462306a36Sopenharmony_ci * All registers where CRm > 3 are known to be UNKNOWN/RAZ from AArch32. 301562306a36Sopenharmony_ci * Avoid conflicting with future expansion of AArch64 feature registers 301662306a36Sopenharmony_ci * and simply treat them as RAZ here. 301762306a36Sopenharmony_ci */ 301862306a36Sopenharmony_ci if (params->CRm > 3) 301962306a36Sopenharmony_ci params->regval = 0; 302062306a36Sopenharmony_ci else if (!emulate_sys_reg(vcpu, params)) 302162306a36Sopenharmony_ci return 1; 302262306a36Sopenharmony_ci 302362306a36Sopenharmony_ci vcpu_set_reg(vcpu, Rt, params->regval); 302462306a36Sopenharmony_ci return 1; 302562306a36Sopenharmony_ci} 302662306a36Sopenharmony_ci 302762306a36Sopenharmony_ci/** 302862306a36Sopenharmony_ci * kvm_handle_cp_32 -- handles a mrc/mcr trap on a guest CP14/CP15 access 302962306a36Sopenharmony_ci * @vcpu: The VCPU pointer 303062306a36Sopenharmony_ci * @run: The kvm_run struct 303162306a36Sopenharmony_ci */ 303262306a36Sopenharmony_cistatic int kvm_handle_cp_32(struct kvm_vcpu *vcpu, 303362306a36Sopenharmony_ci struct sys_reg_params *params, 303462306a36Sopenharmony_ci const struct sys_reg_desc *global, 303562306a36Sopenharmony_ci size_t nr_global) 303662306a36Sopenharmony_ci{ 303762306a36Sopenharmony_ci int Rt = kvm_vcpu_sys_get_rt(vcpu); 303862306a36Sopenharmony_ci 303962306a36Sopenharmony_ci params->regval = vcpu_get_reg(vcpu, Rt); 304062306a36Sopenharmony_ci 304162306a36Sopenharmony_ci if (emulate_cp(vcpu, params, global, nr_global)) { 304262306a36Sopenharmony_ci if (!params->is_write) 304362306a36Sopenharmony_ci vcpu_set_reg(vcpu, Rt, params->regval); 304462306a36Sopenharmony_ci return 1; 304562306a36Sopenharmony_ci } 304662306a36Sopenharmony_ci 304762306a36Sopenharmony_ci unhandled_cp_access(vcpu, params); 304862306a36Sopenharmony_ci return 1; 304962306a36Sopenharmony_ci} 305062306a36Sopenharmony_ci 305162306a36Sopenharmony_ciint kvm_handle_cp15_64(struct kvm_vcpu *vcpu) 305262306a36Sopenharmony_ci{ 305362306a36Sopenharmony_ci return kvm_handle_cp_64(vcpu, cp15_64_regs, ARRAY_SIZE(cp15_64_regs)); 305462306a36Sopenharmony_ci} 305562306a36Sopenharmony_ci 305662306a36Sopenharmony_ciint kvm_handle_cp15_32(struct kvm_vcpu *vcpu) 305762306a36Sopenharmony_ci{ 305862306a36Sopenharmony_ci struct sys_reg_params params; 305962306a36Sopenharmony_ci 306062306a36Sopenharmony_ci params = esr_cp1x_32_to_params(kvm_vcpu_get_esr(vcpu)); 306162306a36Sopenharmony_ci 306262306a36Sopenharmony_ci /* 306362306a36Sopenharmony_ci * Certain AArch32 ID registers are handled by rerouting to the AArch64 306462306a36Sopenharmony_ci * system register table. Registers in the ID range where CRm=0 are 306562306a36Sopenharmony_ci * excluded from this scheme as they do not trivially map into AArch64 306662306a36Sopenharmony_ci * system register encodings. 306762306a36Sopenharmony_ci */ 306862306a36Sopenharmony_ci if (params.Op1 == 0 && params.CRn == 0 && params.CRm) 306962306a36Sopenharmony_ci return kvm_emulate_cp15_id_reg(vcpu, ¶ms); 307062306a36Sopenharmony_ci 307162306a36Sopenharmony_ci return kvm_handle_cp_32(vcpu, ¶ms, cp15_regs, ARRAY_SIZE(cp15_regs)); 307262306a36Sopenharmony_ci} 307362306a36Sopenharmony_ci 307462306a36Sopenharmony_ciint kvm_handle_cp14_64(struct kvm_vcpu *vcpu) 307562306a36Sopenharmony_ci{ 307662306a36Sopenharmony_ci return kvm_handle_cp_64(vcpu, cp14_64_regs, ARRAY_SIZE(cp14_64_regs)); 307762306a36Sopenharmony_ci} 307862306a36Sopenharmony_ci 307962306a36Sopenharmony_ciint kvm_handle_cp14_32(struct kvm_vcpu *vcpu) 308062306a36Sopenharmony_ci{ 308162306a36Sopenharmony_ci struct sys_reg_params params; 308262306a36Sopenharmony_ci 308362306a36Sopenharmony_ci params = esr_cp1x_32_to_params(kvm_vcpu_get_esr(vcpu)); 308462306a36Sopenharmony_ci 308562306a36Sopenharmony_ci return kvm_handle_cp_32(vcpu, ¶ms, cp14_regs, ARRAY_SIZE(cp14_regs)); 308662306a36Sopenharmony_ci} 308762306a36Sopenharmony_ci 308862306a36Sopenharmony_cistatic bool is_imp_def_sys_reg(struct sys_reg_params *params) 308962306a36Sopenharmony_ci{ 309062306a36Sopenharmony_ci // See ARM DDI 0487E.a, section D12.3.2 309162306a36Sopenharmony_ci return params->Op0 == 3 && (params->CRn & 0b1011) == 0b1011; 309262306a36Sopenharmony_ci} 309362306a36Sopenharmony_ci 309462306a36Sopenharmony_ci/** 309562306a36Sopenharmony_ci * emulate_sys_reg - Emulate a guest access to an AArch64 system register 309662306a36Sopenharmony_ci * @vcpu: The VCPU pointer 309762306a36Sopenharmony_ci * @params: Decoded system register parameters 309862306a36Sopenharmony_ci * 309962306a36Sopenharmony_ci * Return: true if the system register access was successful, false otherwise. 310062306a36Sopenharmony_ci */ 310162306a36Sopenharmony_cistatic bool emulate_sys_reg(struct kvm_vcpu *vcpu, 310262306a36Sopenharmony_ci struct sys_reg_params *params) 310362306a36Sopenharmony_ci{ 310462306a36Sopenharmony_ci const struct sys_reg_desc *r; 310562306a36Sopenharmony_ci 310662306a36Sopenharmony_ci r = find_reg(params, sys_reg_descs, ARRAY_SIZE(sys_reg_descs)); 310762306a36Sopenharmony_ci 310862306a36Sopenharmony_ci if (likely(r)) { 310962306a36Sopenharmony_ci perform_access(vcpu, params, r); 311062306a36Sopenharmony_ci return true; 311162306a36Sopenharmony_ci } 311262306a36Sopenharmony_ci 311362306a36Sopenharmony_ci if (is_imp_def_sys_reg(params)) { 311462306a36Sopenharmony_ci kvm_inject_undefined(vcpu); 311562306a36Sopenharmony_ci } else { 311662306a36Sopenharmony_ci print_sys_reg_msg(params, 311762306a36Sopenharmony_ci "Unsupported guest sys_reg access at: %lx [%08lx]\n", 311862306a36Sopenharmony_ci *vcpu_pc(vcpu), *vcpu_cpsr(vcpu)); 311962306a36Sopenharmony_ci kvm_inject_undefined(vcpu); 312062306a36Sopenharmony_ci } 312162306a36Sopenharmony_ci return false; 312262306a36Sopenharmony_ci} 312362306a36Sopenharmony_ci 312462306a36Sopenharmony_cistatic void kvm_reset_id_regs(struct kvm_vcpu *vcpu) 312562306a36Sopenharmony_ci{ 312662306a36Sopenharmony_ci const struct sys_reg_desc *idreg = first_idreg; 312762306a36Sopenharmony_ci u32 id = reg_to_encoding(idreg); 312862306a36Sopenharmony_ci struct kvm *kvm = vcpu->kvm; 312962306a36Sopenharmony_ci 313062306a36Sopenharmony_ci if (test_bit(KVM_ARCH_FLAG_ID_REGS_INITIALIZED, &kvm->arch.flags)) 313162306a36Sopenharmony_ci return; 313262306a36Sopenharmony_ci 313362306a36Sopenharmony_ci lockdep_assert_held(&kvm->arch.config_lock); 313462306a36Sopenharmony_ci 313562306a36Sopenharmony_ci /* Initialize all idregs */ 313662306a36Sopenharmony_ci while (is_id_reg(id)) { 313762306a36Sopenharmony_ci IDREG(kvm, id) = idreg->reset(vcpu, idreg); 313862306a36Sopenharmony_ci 313962306a36Sopenharmony_ci idreg++; 314062306a36Sopenharmony_ci id = reg_to_encoding(idreg); 314162306a36Sopenharmony_ci } 314262306a36Sopenharmony_ci 314362306a36Sopenharmony_ci set_bit(KVM_ARCH_FLAG_ID_REGS_INITIALIZED, &kvm->arch.flags); 314462306a36Sopenharmony_ci} 314562306a36Sopenharmony_ci 314662306a36Sopenharmony_ci/** 314762306a36Sopenharmony_ci * kvm_reset_sys_regs - sets system registers to reset value 314862306a36Sopenharmony_ci * @vcpu: The VCPU pointer 314962306a36Sopenharmony_ci * 315062306a36Sopenharmony_ci * This function finds the right table above and sets the registers on the 315162306a36Sopenharmony_ci * virtual CPU struct to their architecturally defined reset values. 315262306a36Sopenharmony_ci */ 315362306a36Sopenharmony_civoid kvm_reset_sys_regs(struct kvm_vcpu *vcpu) 315462306a36Sopenharmony_ci{ 315562306a36Sopenharmony_ci unsigned long i; 315662306a36Sopenharmony_ci 315762306a36Sopenharmony_ci kvm_reset_id_regs(vcpu); 315862306a36Sopenharmony_ci 315962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sys_reg_descs); i++) { 316062306a36Sopenharmony_ci const struct sys_reg_desc *r = &sys_reg_descs[i]; 316162306a36Sopenharmony_ci 316262306a36Sopenharmony_ci if (is_id_reg(reg_to_encoding(r))) 316362306a36Sopenharmony_ci continue; 316462306a36Sopenharmony_ci 316562306a36Sopenharmony_ci if (r->reset) 316662306a36Sopenharmony_ci r->reset(vcpu, r); 316762306a36Sopenharmony_ci } 316862306a36Sopenharmony_ci} 316962306a36Sopenharmony_ci 317062306a36Sopenharmony_ci/** 317162306a36Sopenharmony_ci * kvm_handle_sys_reg -- handles a mrs/msr trap on a guest sys_reg access 317262306a36Sopenharmony_ci * @vcpu: The VCPU pointer 317362306a36Sopenharmony_ci */ 317462306a36Sopenharmony_ciint kvm_handle_sys_reg(struct kvm_vcpu *vcpu) 317562306a36Sopenharmony_ci{ 317662306a36Sopenharmony_ci struct sys_reg_params params; 317762306a36Sopenharmony_ci unsigned long esr = kvm_vcpu_get_esr(vcpu); 317862306a36Sopenharmony_ci int Rt = kvm_vcpu_sys_get_rt(vcpu); 317962306a36Sopenharmony_ci 318062306a36Sopenharmony_ci trace_kvm_handle_sys_reg(esr); 318162306a36Sopenharmony_ci 318262306a36Sopenharmony_ci if (__check_nv_sr_forward(vcpu)) 318362306a36Sopenharmony_ci return 1; 318462306a36Sopenharmony_ci 318562306a36Sopenharmony_ci params = esr_sys64_to_params(esr); 318662306a36Sopenharmony_ci params.regval = vcpu_get_reg(vcpu, Rt); 318762306a36Sopenharmony_ci 318862306a36Sopenharmony_ci if (!emulate_sys_reg(vcpu, ¶ms)) 318962306a36Sopenharmony_ci return 1; 319062306a36Sopenharmony_ci 319162306a36Sopenharmony_ci if (!params.is_write) 319262306a36Sopenharmony_ci vcpu_set_reg(vcpu, Rt, params.regval); 319362306a36Sopenharmony_ci return 1; 319462306a36Sopenharmony_ci} 319562306a36Sopenharmony_ci 319662306a36Sopenharmony_ci/****************************************************************************** 319762306a36Sopenharmony_ci * Userspace API 319862306a36Sopenharmony_ci *****************************************************************************/ 319962306a36Sopenharmony_ci 320062306a36Sopenharmony_cistatic bool index_to_params(u64 id, struct sys_reg_params *params) 320162306a36Sopenharmony_ci{ 320262306a36Sopenharmony_ci switch (id & KVM_REG_SIZE_MASK) { 320362306a36Sopenharmony_ci case KVM_REG_SIZE_U64: 320462306a36Sopenharmony_ci /* Any unused index bits means it's not valid. */ 320562306a36Sopenharmony_ci if (id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK 320662306a36Sopenharmony_ci | KVM_REG_ARM_COPROC_MASK 320762306a36Sopenharmony_ci | KVM_REG_ARM64_SYSREG_OP0_MASK 320862306a36Sopenharmony_ci | KVM_REG_ARM64_SYSREG_OP1_MASK 320962306a36Sopenharmony_ci | KVM_REG_ARM64_SYSREG_CRN_MASK 321062306a36Sopenharmony_ci | KVM_REG_ARM64_SYSREG_CRM_MASK 321162306a36Sopenharmony_ci | KVM_REG_ARM64_SYSREG_OP2_MASK)) 321262306a36Sopenharmony_ci return false; 321362306a36Sopenharmony_ci params->Op0 = ((id & KVM_REG_ARM64_SYSREG_OP0_MASK) 321462306a36Sopenharmony_ci >> KVM_REG_ARM64_SYSREG_OP0_SHIFT); 321562306a36Sopenharmony_ci params->Op1 = ((id & KVM_REG_ARM64_SYSREG_OP1_MASK) 321662306a36Sopenharmony_ci >> KVM_REG_ARM64_SYSREG_OP1_SHIFT); 321762306a36Sopenharmony_ci params->CRn = ((id & KVM_REG_ARM64_SYSREG_CRN_MASK) 321862306a36Sopenharmony_ci >> KVM_REG_ARM64_SYSREG_CRN_SHIFT); 321962306a36Sopenharmony_ci params->CRm = ((id & KVM_REG_ARM64_SYSREG_CRM_MASK) 322062306a36Sopenharmony_ci >> KVM_REG_ARM64_SYSREG_CRM_SHIFT); 322162306a36Sopenharmony_ci params->Op2 = ((id & KVM_REG_ARM64_SYSREG_OP2_MASK) 322262306a36Sopenharmony_ci >> KVM_REG_ARM64_SYSREG_OP2_SHIFT); 322362306a36Sopenharmony_ci return true; 322462306a36Sopenharmony_ci default: 322562306a36Sopenharmony_ci return false; 322662306a36Sopenharmony_ci } 322762306a36Sopenharmony_ci} 322862306a36Sopenharmony_ci 322962306a36Sopenharmony_ciconst struct sys_reg_desc *get_reg_by_id(u64 id, 323062306a36Sopenharmony_ci const struct sys_reg_desc table[], 323162306a36Sopenharmony_ci unsigned int num) 323262306a36Sopenharmony_ci{ 323362306a36Sopenharmony_ci struct sys_reg_params params; 323462306a36Sopenharmony_ci 323562306a36Sopenharmony_ci if (!index_to_params(id, ¶ms)) 323662306a36Sopenharmony_ci return NULL; 323762306a36Sopenharmony_ci 323862306a36Sopenharmony_ci return find_reg(¶ms, table, num); 323962306a36Sopenharmony_ci} 324062306a36Sopenharmony_ci 324162306a36Sopenharmony_ci/* Decode an index value, and find the sys_reg_desc entry. */ 324262306a36Sopenharmony_cistatic const struct sys_reg_desc * 324362306a36Sopenharmony_ciid_to_sys_reg_desc(struct kvm_vcpu *vcpu, u64 id, 324462306a36Sopenharmony_ci const struct sys_reg_desc table[], unsigned int num) 324562306a36Sopenharmony_ci 324662306a36Sopenharmony_ci{ 324762306a36Sopenharmony_ci const struct sys_reg_desc *r; 324862306a36Sopenharmony_ci 324962306a36Sopenharmony_ci /* We only do sys_reg for now. */ 325062306a36Sopenharmony_ci if ((id & KVM_REG_ARM_COPROC_MASK) != KVM_REG_ARM64_SYSREG) 325162306a36Sopenharmony_ci return NULL; 325262306a36Sopenharmony_ci 325362306a36Sopenharmony_ci r = get_reg_by_id(id, table, num); 325462306a36Sopenharmony_ci 325562306a36Sopenharmony_ci /* Not saved in the sys_reg array and not otherwise accessible? */ 325662306a36Sopenharmony_ci if (r && (!(r->reg || r->get_user) || sysreg_hidden(vcpu, r))) 325762306a36Sopenharmony_ci r = NULL; 325862306a36Sopenharmony_ci 325962306a36Sopenharmony_ci return r; 326062306a36Sopenharmony_ci} 326162306a36Sopenharmony_ci 326262306a36Sopenharmony_ci/* 326362306a36Sopenharmony_ci * These are the invariant sys_reg registers: we let the guest see the 326462306a36Sopenharmony_ci * host versions of these, so they're part of the guest state. 326562306a36Sopenharmony_ci * 326662306a36Sopenharmony_ci * A future CPU may provide a mechanism to present different values to 326762306a36Sopenharmony_ci * the guest, or a future kvm may trap them. 326862306a36Sopenharmony_ci */ 326962306a36Sopenharmony_ci 327062306a36Sopenharmony_ci#define FUNCTION_INVARIANT(reg) \ 327162306a36Sopenharmony_ci static u64 get_##reg(struct kvm_vcpu *v, \ 327262306a36Sopenharmony_ci const struct sys_reg_desc *r) \ 327362306a36Sopenharmony_ci { \ 327462306a36Sopenharmony_ci ((struct sys_reg_desc *)r)->val = read_sysreg(reg); \ 327562306a36Sopenharmony_ci return ((struct sys_reg_desc *)r)->val; \ 327662306a36Sopenharmony_ci } 327762306a36Sopenharmony_ci 327862306a36Sopenharmony_ciFUNCTION_INVARIANT(midr_el1) 327962306a36Sopenharmony_ciFUNCTION_INVARIANT(revidr_el1) 328062306a36Sopenharmony_ciFUNCTION_INVARIANT(aidr_el1) 328162306a36Sopenharmony_ci 328262306a36Sopenharmony_cistatic u64 get_ctr_el0(struct kvm_vcpu *v, const struct sys_reg_desc *r) 328362306a36Sopenharmony_ci{ 328462306a36Sopenharmony_ci ((struct sys_reg_desc *)r)->val = read_sanitised_ftr_reg(SYS_CTR_EL0); 328562306a36Sopenharmony_ci return ((struct sys_reg_desc *)r)->val; 328662306a36Sopenharmony_ci} 328762306a36Sopenharmony_ci 328862306a36Sopenharmony_ci/* ->val is filled in by kvm_sys_reg_table_init() */ 328962306a36Sopenharmony_cistatic struct sys_reg_desc invariant_sys_regs[] __ro_after_init = { 329062306a36Sopenharmony_ci { SYS_DESC(SYS_MIDR_EL1), NULL, get_midr_el1 }, 329162306a36Sopenharmony_ci { SYS_DESC(SYS_REVIDR_EL1), NULL, get_revidr_el1 }, 329262306a36Sopenharmony_ci { SYS_DESC(SYS_AIDR_EL1), NULL, get_aidr_el1 }, 329362306a36Sopenharmony_ci { SYS_DESC(SYS_CTR_EL0), NULL, get_ctr_el0 }, 329462306a36Sopenharmony_ci}; 329562306a36Sopenharmony_ci 329662306a36Sopenharmony_cistatic int get_invariant_sys_reg(u64 id, u64 __user *uaddr) 329762306a36Sopenharmony_ci{ 329862306a36Sopenharmony_ci const struct sys_reg_desc *r; 329962306a36Sopenharmony_ci 330062306a36Sopenharmony_ci r = get_reg_by_id(id, invariant_sys_regs, 330162306a36Sopenharmony_ci ARRAY_SIZE(invariant_sys_regs)); 330262306a36Sopenharmony_ci if (!r) 330362306a36Sopenharmony_ci return -ENOENT; 330462306a36Sopenharmony_ci 330562306a36Sopenharmony_ci return put_user(r->val, uaddr); 330662306a36Sopenharmony_ci} 330762306a36Sopenharmony_ci 330862306a36Sopenharmony_cistatic int set_invariant_sys_reg(u64 id, u64 __user *uaddr) 330962306a36Sopenharmony_ci{ 331062306a36Sopenharmony_ci const struct sys_reg_desc *r; 331162306a36Sopenharmony_ci u64 val; 331262306a36Sopenharmony_ci 331362306a36Sopenharmony_ci r = get_reg_by_id(id, invariant_sys_regs, 331462306a36Sopenharmony_ci ARRAY_SIZE(invariant_sys_regs)); 331562306a36Sopenharmony_ci if (!r) 331662306a36Sopenharmony_ci return -ENOENT; 331762306a36Sopenharmony_ci 331862306a36Sopenharmony_ci if (get_user(val, uaddr)) 331962306a36Sopenharmony_ci return -EFAULT; 332062306a36Sopenharmony_ci 332162306a36Sopenharmony_ci /* This is what we mean by invariant: you can't change it. */ 332262306a36Sopenharmony_ci if (r->val != val) 332362306a36Sopenharmony_ci return -EINVAL; 332462306a36Sopenharmony_ci 332562306a36Sopenharmony_ci return 0; 332662306a36Sopenharmony_ci} 332762306a36Sopenharmony_ci 332862306a36Sopenharmony_cistatic int demux_c15_get(struct kvm_vcpu *vcpu, u64 id, void __user *uaddr) 332962306a36Sopenharmony_ci{ 333062306a36Sopenharmony_ci u32 val; 333162306a36Sopenharmony_ci u32 __user *uval = uaddr; 333262306a36Sopenharmony_ci 333362306a36Sopenharmony_ci /* Fail if we have unknown bits set. */ 333462306a36Sopenharmony_ci if (id & ~(KVM_REG_ARCH_MASK|KVM_REG_SIZE_MASK|KVM_REG_ARM_COPROC_MASK 333562306a36Sopenharmony_ci | ((1 << KVM_REG_ARM_COPROC_SHIFT)-1))) 333662306a36Sopenharmony_ci return -ENOENT; 333762306a36Sopenharmony_ci 333862306a36Sopenharmony_ci switch (id & KVM_REG_ARM_DEMUX_ID_MASK) { 333962306a36Sopenharmony_ci case KVM_REG_ARM_DEMUX_ID_CCSIDR: 334062306a36Sopenharmony_ci if (KVM_REG_SIZE(id) != 4) 334162306a36Sopenharmony_ci return -ENOENT; 334262306a36Sopenharmony_ci val = (id & KVM_REG_ARM_DEMUX_VAL_MASK) 334362306a36Sopenharmony_ci >> KVM_REG_ARM_DEMUX_VAL_SHIFT; 334462306a36Sopenharmony_ci if (val >= CSSELR_MAX) 334562306a36Sopenharmony_ci return -ENOENT; 334662306a36Sopenharmony_ci 334762306a36Sopenharmony_ci return put_user(get_ccsidr(vcpu, val), uval); 334862306a36Sopenharmony_ci default: 334962306a36Sopenharmony_ci return -ENOENT; 335062306a36Sopenharmony_ci } 335162306a36Sopenharmony_ci} 335262306a36Sopenharmony_ci 335362306a36Sopenharmony_cistatic int demux_c15_set(struct kvm_vcpu *vcpu, u64 id, void __user *uaddr) 335462306a36Sopenharmony_ci{ 335562306a36Sopenharmony_ci u32 val, newval; 335662306a36Sopenharmony_ci u32 __user *uval = uaddr; 335762306a36Sopenharmony_ci 335862306a36Sopenharmony_ci /* Fail if we have unknown bits set. */ 335962306a36Sopenharmony_ci if (id & ~(KVM_REG_ARCH_MASK|KVM_REG_SIZE_MASK|KVM_REG_ARM_COPROC_MASK 336062306a36Sopenharmony_ci | ((1 << KVM_REG_ARM_COPROC_SHIFT)-1))) 336162306a36Sopenharmony_ci return -ENOENT; 336262306a36Sopenharmony_ci 336362306a36Sopenharmony_ci switch (id & KVM_REG_ARM_DEMUX_ID_MASK) { 336462306a36Sopenharmony_ci case KVM_REG_ARM_DEMUX_ID_CCSIDR: 336562306a36Sopenharmony_ci if (KVM_REG_SIZE(id) != 4) 336662306a36Sopenharmony_ci return -ENOENT; 336762306a36Sopenharmony_ci val = (id & KVM_REG_ARM_DEMUX_VAL_MASK) 336862306a36Sopenharmony_ci >> KVM_REG_ARM_DEMUX_VAL_SHIFT; 336962306a36Sopenharmony_ci if (val >= CSSELR_MAX) 337062306a36Sopenharmony_ci return -ENOENT; 337162306a36Sopenharmony_ci 337262306a36Sopenharmony_ci if (get_user(newval, uval)) 337362306a36Sopenharmony_ci return -EFAULT; 337462306a36Sopenharmony_ci 337562306a36Sopenharmony_ci return set_ccsidr(vcpu, val, newval); 337662306a36Sopenharmony_ci default: 337762306a36Sopenharmony_ci return -ENOENT; 337862306a36Sopenharmony_ci } 337962306a36Sopenharmony_ci} 338062306a36Sopenharmony_ci 338162306a36Sopenharmony_ciint kvm_sys_reg_get_user(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg, 338262306a36Sopenharmony_ci const struct sys_reg_desc table[], unsigned int num) 338362306a36Sopenharmony_ci{ 338462306a36Sopenharmony_ci u64 __user *uaddr = (u64 __user *)(unsigned long)reg->addr; 338562306a36Sopenharmony_ci const struct sys_reg_desc *r; 338662306a36Sopenharmony_ci u64 val; 338762306a36Sopenharmony_ci int ret; 338862306a36Sopenharmony_ci 338962306a36Sopenharmony_ci r = id_to_sys_reg_desc(vcpu, reg->id, table, num); 339062306a36Sopenharmony_ci if (!r || sysreg_hidden_user(vcpu, r)) 339162306a36Sopenharmony_ci return -ENOENT; 339262306a36Sopenharmony_ci 339362306a36Sopenharmony_ci if (r->get_user) { 339462306a36Sopenharmony_ci ret = (r->get_user)(vcpu, r, &val); 339562306a36Sopenharmony_ci } else { 339662306a36Sopenharmony_ci val = __vcpu_sys_reg(vcpu, r->reg); 339762306a36Sopenharmony_ci ret = 0; 339862306a36Sopenharmony_ci } 339962306a36Sopenharmony_ci 340062306a36Sopenharmony_ci if (!ret) 340162306a36Sopenharmony_ci ret = put_user(val, uaddr); 340262306a36Sopenharmony_ci 340362306a36Sopenharmony_ci return ret; 340462306a36Sopenharmony_ci} 340562306a36Sopenharmony_ci 340662306a36Sopenharmony_ciint kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 340762306a36Sopenharmony_ci{ 340862306a36Sopenharmony_ci void __user *uaddr = (void __user *)(unsigned long)reg->addr; 340962306a36Sopenharmony_ci int err; 341062306a36Sopenharmony_ci 341162306a36Sopenharmony_ci if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX) 341262306a36Sopenharmony_ci return demux_c15_get(vcpu, reg->id, uaddr); 341362306a36Sopenharmony_ci 341462306a36Sopenharmony_ci err = get_invariant_sys_reg(reg->id, uaddr); 341562306a36Sopenharmony_ci if (err != -ENOENT) 341662306a36Sopenharmony_ci return err; 341762306a36Sopenharmony_ci 341862306a36Sopenharmony_ci return kvm_sys_reg_get_user(vcpu, reg, 341962306a36Sopenharmony_ci sys_reg_descs, ARRAY_SIZE(sys_reg_descs)); 342062306a36Sopenharmony_ci} 342162306a36Sopenharmony_ci 342262306a36Sopenharmony_ciint kvm_sys_reg_set_user(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg, 342362306a36Sopenharmony_ci const struct sys_reg_desc table[], unsigned int num) 342462306a36Sopenharmony_ci{ 342562306a36Sopenharmony_ci u64 __user *uaddr = (u64 __user *)(unsigned long)reg->addr; 342662306a36Sopenharmony_ci const struct sys_reg_desc *r; 342762306a36Sopenharmony_ci u64 val; 342862306a36Sopenharmony_ci int ret; 342962306a36Sopenharmony_ci 343062306a36Sopenharmony_ci if (get_user(val, uaddr)) 343162306a36Sopenharmony_ci return -EFAULT; 343262306a36Sopenharmony_ci 343362306a36Sopenharmony_ci r = id_to_sys_reg_desc(vcpu, reg->id, table, num); 343462306a36Sopenharmony_ci if (!r || sysreg_hidden_user(vcpu, r)) 343562306a36Sopenharmony_ci return -ENOENT; 343662306a36Sopenharmony_ci 343762306a36Sopenharmony_ci if (sysreg_user_write_ignore(vcpu, r)) 343862306a36Sopenharmony_ci return 0; 343962306a36Sopenharmony_ci 344062306a36Sopenharmony_ci if (r->set_user) { 344162306a36Sopenharmony_ci ret = (r->set_user)(vcpu, r, val); 344262306a36Sopenharmony_ci } else { 344362306a36Sopenharmony_ci __vcpu_sys_reg(vcpu, r->reg) = val; 344462306a36Sopenharmony_ci ret = 0; 344562306a36Sopenharmony_ci } 344662306a36Sopenharmony_ci 344762306a36Sopenharmony_ci return ret; 344862306a36Sopenharmony_ci} 344962306a36Sopenharmony_ci 345062306a36Sopenharmony_ciint kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 345162306a36Sopenharmony_ci{ 345262306a36Sopenharmony_ci void __user *uaddr = (void __user *)(unsigned long)reg->addr; 345362306a36Sopenharmony_ci int err; 345462306a36Sopenharmony_ci 345562306a36Sopenharmony_ci if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX) 345662306a36Sopenharmony_ci return demux_c15_set(vcpu, reg->id, uaddr); 345762306a36Sopenharmony_ci 345862306a36Sopenharmony_ci err = set_invariant_sys_reg(reg->id, uaddr); 345962306a36Sopenharmony_ci if (err != -ENOENT) 346062306a36Sopenharmony_ci return err; 346162306a36Sopenharmony_ci 346262306a36Sopenharmony_ci return kvm_sys_reg_set_user(vcpu, reg, 346362306a36Sopenharmony_ci sys_reg_descs, ARRAY_SIZE(sys_reg_descs)); 346462306a36Sopenharmony_ci} 346562306a36Sopenharmony_ci 346662306a36Sopenharmony_cistatic unsigned int num_demux_regs(void) 346762306a36Sopenharmony_ci{ 346862306a36Sopenharmony_ci return CSSELR_MAX; 346962306a36Sopenharmony_ci} 347062306a36Sopenharmony_ci 347162306a36Sopenharmony_cistatic int write_demux_regids(u64 __user *uindices) 347262306a36Sopenharmony_ci{ 347362306a36Sopenharmony_ci u64 val = KVM_REG_ARM64 | KVM_REG_SIZE_U32 | KVM_REG_ARM_DEMUX; 347462306a36Sopenharmony_ci unsigned int i; 347562306a36Sopenharmony_ci 347662306a36Sopenharmony_ci val |= KVM_REG_ARM_DEMUX_ID_CCSIDR; 347762306a36Sopenharmony_ci for (i = 0; i < CSSELR_MAX; i++) { 347862306a36Sopenharmony_ci if (put_user(val | i, uindices)) 347962306a36Sopenharmony_ci return -EFAULT; 348062306a36Sopenharmony_ci uindices++; 348162306a36Sopenharmony_ci } 348262306a36Sopenharmony_ci return 0; 348362306a36Sopenharmony_ci} 348462306a36Sopenharmony_ci 348562306a36Sopenharmony_cistatic u64 sys_reg_to_index(const struct sys_reg_desc *reg) 348662306a36Sopenharmony_ci{ 348762306a36Sopenharmony_ci return (KVM_REG_ARM64 | KVM_REG_SIZE_U64 | 348862306a36Sopenharmony_ci KVM_REG_ARM64_SYSREG | 348962306a36Sopenharmony_ci (reg->Op0 << KVM_REG_ARM64_SYSREG_OP0_SHIFT) | 349062306a36Sopenharmony_ci (reg->Op1 << KVM_REG_ARM64_SYSREG_OP1_SHIFT) | 349162306a36Sopenharmony_ci (reg->CRn << KVM_REG_ARM64_SYSREG_CRN_SHIFT) | 349262306a36Sopenharmony_ci (reg->CRm << KVM_REG_ARM64_SYSREG_CRM_SHIFT) | 349362306a36Sopenharmony_ci (reg->Op2 << KVM_REG_ARM64_SYSREG_OP2_SHIFT)); 349462306a36Sopenharmony_ci} 349562306a36Sopenharmony_ci 349662306a36Sopenharmony_cistatic bool copy_reg_to_user(const struct sys_reg_desc *reg, u64 __user **uind) 349762306a36Sopenharmony_ci{ 349862306a36Sopenharmony_ci if (!*uind) 349962306a36Sopenharmony_ci return true; 350062306a36Sopenharmony_ci 350162306a36Sopenharmony_ci if (put_user(sys_reg_to_index(reg), *uind)) 350262306a36Sopenharmony_ci return false; 350362306a36Sopenharmony_ci 350462306a36Sopenharmony_ci (*uind)++; 350562306a36Sopenharmony_ci return true; 350662306a36Sopenharmony_ci} 350762306a36Sopenharmony_ci 350862306a36Sopenharmony_cistatic int walk_one_sys_reg(const struct kvm_vcpu *vcpu, 350962306a36Sopenharmony_ci const struct sys_reg_desc *rd, 351062306a36Sopenharmony_ci u64 __user **uind, 351162306a36Sopenharmony_ci unsigned int *total) 351262306a36Sopenharmony_ci{ 351362306a36Sopenharmony_ci /* 351462306a36Sopenharmony_ci * Ignore registers we trap but don't save, 351562306a36Sopenharmony_ci * and for which no custom user accessor is provided. 351662306a36Sopenharmony_ci */ 351762306a36Sopenharmony_ci if (!(rd->reg || rd->get_user)) 351862306a36Sopenharmony_ci return 0; 351962306a36Sopenharmony_ci 352062306a36Sopenharmony_ci if (sysreg_hidden_user(vcpu, rd)) 352162306a36Sopenharmony_ci return 0; 352262306a36Sopenharmony_ci 352362306a36Sopenharmony_ci if (!copy_reg_to_user(rd, uind)) 352462306a36Sopenharmony_ci return -EFAULT; 352562306a36Sopenharmony_ci 352662306a36Sopenharmony_ci (*total)++; 352762306a36Sopenharmony_ci return 0; 352862306a36Sopenharmony_ci} 352962306a36Sopenharmony_ci 353062306a36Sopenharmony_ci/* Assumed ordered tables, see kvm_sys_reg_table_init. */ 353162306a36Sopenharmony_cistatic int walk_sys_regs(struct kvm_vcpu *vcpu, u64 __user *uind) 353262306a36Sopenharmony_ci{ 353362306a36Sopenharmony_ci const struct sys_reg_desc *i2, *end2; 353462306a36Sopenharmony_ci unsigned int total = 0; 353562306a36Sopenharmony_ci int err; 353662306a36Sopenharmony_ci 353762306a36Sopenharmony_ci i2 = sys_reg_descs; 353862306a36Sopenharmony_ci end2 = sys_reg_descs + ARRAY_SIZE(sys_reg_descs); 353962306a36Sopenharmony_ci 354062306a36Sopenharmony_ci while (i2 != end2) { 354162306a36Sopenharmony_ci err = walk_one_sys_reg(vcpu, i2++, &uind, &total); 354262306a36Sopenharmony_ci if (err) 354362306a36Sopenharmony_ci return err; 354462306a36Sopenharmony_ci } 354562306a36Sopenharmony_ci return total; 354662306a36Sopenharmony_ci} 354762306a36Sopenharmony_ci 354862306a36Sopenharmony_ciunsigned long kvm_arm_num_sys_reg_descs(struct kvm_vcpu *vcpu) 354962306a36Sopenharmony_ci{ 355062306a36Sopenharmony_ci return ARRAY_SIZE(invariant_sys_regs) 355162306a36Sopenharmony_ci + num_demux_regs() 355262306a36Sopenharmony_ci + walk_sys_regs(vcpu, (u64 __user *)NULL); 355362306a36Sopenharmony_ci} 355462306a36Sopenharmony_ci 355562306a36Sopenharmony_ciint kvm_arm_copy_sys_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) 355662306a36Sopenharmony_ci{ 355762306a36Sopenharmony_ci unsigned int i; 355862306a36Sopenharmony_ci int err; 355962306a36Sopenharmony_ci 356062306a36Sopenharmony_ci /* Then give them all the invariant registers' indices. */ 356162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(invariant_sys_regs); i++) { 356262306a36Sopenharmony_ci if (put_user(sys_reg_to_index(&invariant_sys_regs[i]), uindices)) 356362306a36Sopenharmony_ci return -EFAULT; 356462306a36Sopenharmony_ci uindices++; 356562306a36Sopenharmony_ci } 356662306a36Sopenharmony_ci 356762306a36Sopenharmony_ci err = walk_sys_regs(vcpu, uindices); 356862306a36Sopenharmony_ci if (err < 0) 356962306a36Sopenharmony_ci return err; 357062306a36Sopenharmony_ci uindices += err; 357162306a36Sopenharmony_ci 357262306a36Sopenharmony_ci return write_demux_regids(uindices); 357362306a36Sopenharmony_ci} 357462306a36Sopenharmony_ci 357562306a36Sopenharmony_ciint __init kvm_sys_reg_table_init(void) 357662306a36Sopenharmony_ci{ 357762306a36Sopenharmony_ci struct sys_reg_params params; 357862306a36Sopenharmony_ci bool valid = true; 357962306a36Sopenharmony_ci unsigned int i; 358062306a36Sopenharmony_ci 358162306a36Sopenharmony_ci /* Make sure tables are unique and in order. */ 358262306a36Sopenharmony_ci valid &= check_sysreg_table(sys_reg_descs, ARRAY_SIZE(sys_reg_descs), false); 358362306a36Sopenharmony_ci valid &= check_sysreg_table(cp14_regs, ARRAY_SIZE(cp14_regs), true); 358462306a36Sopenharmony_ci valid &= check_sysreg_table(cp14_64_regs, ARRAY_SIZE(cp14_64_regs), true); 358562306a36Sopenharmony_ci valid &= check_sysreg_table(cp15_regs, ARRAY_SIZE(cp15_regs), true); 358662306a36Sopenharmony_ci valid &= check_sysreg_table(cp15_64_regs, ARRAY_SIZE(cp15_64_regs), true); 358762306a36Sopenharmony_ci valid &= check_sysreg_table(invariant_sys_regs, ARRAY_SIZE(invariant_sys_regs), false); 358862306a36Sopenharmony_ci 358962306a36Sopenharmony_ci if (!valid) 359062306a36Sopenharmony_ci return -EINVAL; 359162306a36Sopenharmony_ci 359262306a36Sopenharmony_ci /* We abuse the reset function to overwrite the table itself. */ 359362306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(invariant_sys_regs); i++) 359462306a36Sopenharmony_ci invariant_sys_regs[i].reset(NULL, &invariant_sys_regs[i]); 359562306a36Sopenharmony_ci 359662306a36Sopenharmony_ci /* Find the first idreg (SYS_ID_PFR0_EL1) in sys_reg_descs. */ 359762306a36Sopenharmony_ci params = encoding_to_params(SYS_ID_PFR0_EL1); 359862306a36Sopenharmony_ci first_idreg = find_reg(¶ms, sys_reg_descs, ARRAY_SIZE(sys_reg_descs)); 359962306a36Sopenharmony_ci if (!first_idreg) 360062306a36Sopenharmony_ci return -EINVAL; 360162306a36Sopenharmony_ci 360262306a36Sopenharmony_ci if (kvm_get_mode() == KVM_MODE_NV) 360362306a36Sopenharmony_ci return populate_nv_trap_config(); 360462306a36Sopenharmony_ci 360562306a36Sopenharmony_ci return 0; 360662306a36Sopenharmony_ci} 3607