11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2d017d7b0SVijaya Kumar K /* 3d017d7b0SVijaya Kumar K * VGIC system registers handling functions for AArch64 mode 4d017d7b0SVijaya Kumar K */ 5d017d7b0SVijaya Kumar K 6d017d7b0SVijaya Kumar K #include <linux/irqchip/arm-gic-v3.h> 7d017d7b0SVijaya Kumar K #include <linux/kvm.h> 8d017d7b0SVijaya Kumar K #include <linux/kvm_host.h> 9d017d7b0SVijaya Kumar K #include <asm/kvm_emulate.h> 109ed24f4bSMarc Zyngier #include "vgic/vgic.h" 11d017d7b0SVijaya Kumar K #include "sys_regs.h" 12d017d7b0SVijaya Kumar K 13d017d7b0SVijaya Kumar K static bool access_gic_ctlr(struct kvm_vcpu *vcpu, struct sys_reg_params *p, 14d017d7b0SVijaya Kumar K const struct sys_reg_desc *r) 15d017d7b0SVijaya Kumar K { 16d017d7b0SVijaya Kumar K u32 host_pri_bits, host_id_bits, host_seis, host_a3v, seis, a3v; 17d017d7b0SVijaya Kumar K struct vgic_cpu *vgic_v3_cpu = &vcpu->arch.vgic_cpu; 18d017d7b0SVijaya Kumar K struct vgic_vmcr vmcr; 19d017d7b0SVijaya Kumar K u64 val; 20d017d7b0SVijaya Kumar K 21d017d7b0SVijaya Kumar K vgic_get_vmcr(vcpu, &vmcr); 22d017d7b0SVijaya Kumar K if (p->is_write) { 23d017d7b0SVijaya Kumar K val = p->regval; 24d017d7b0SVijaya Kumar K 25d017d7b0SVijaya Kumar K /* 26d017d7b0SVijaya Kumar K * Disallow restoring VM state if not supported by this 27d017d7b0SVijaya Kumar K * hardware. 28d017d7b0SVijaya Kumar K */ 29d017d7b0SVijaya Kumar K host_pri_bits = ((val & ICC_CTLR_EL1_PRI_BITS_MASK) >> 30d017d7b0SVijaya Kumar K ICC_CTLR_EL1_PRI_BITS_SHIFT) + 1; 31d017d7b0SVijaya Kumar K if (host_pri_bits > vgic_v3_cpu->num_pri_bits) 32d017d7b0SVijaya Kumar K return false; 33d017d7b0SVijaya Kumar K 34d017d7b0SVijaya Kumar K vgic_v3_cpu->num_pri_bits = host_pri_bits; 35d017d7b0SVijaya Kumar K 36d017d7b0SVijaya Kumar K host_id_bits = (val & ICC_CTLR_EL1_ID_BITS_MASK) >> 37d017d7b0SVijaya Kumar K ICC_CTLR_EL1_ID_BITS_SHIFT; 38d017d7b0SVijaya Kumar K if (host_id_bits > vgic_v3_cpu->num_id_bits) 39d017d7b0SVijaya Kumar K return false; 40d017d7b0SVijaya Kumar K 41d017d7b0SVijaya Kumar K vgic_v3_cpu->num_id_bits = host_id_bits; 42d017d7b0SVijaya Kumar K 43d017d7b0SVijaya Kumar K host_seis = ((kvm_vgic_global_state.ich_vtr_el2 & 44d017d7b0SVijaya Kumar K ICH_VTR_SEIS_MASK) >> ICH_VTR_SEIS_SHIFT); 45d017d7b0SVijaya Kumar K seis = (val & ICC_CTLR_EL1_SEIS_MASK) >> 46d017d7b0SVijaya Kumar K ICC_CTLR_EL1_SEIS_SHIFT; 47d017d7b0SVijaya Kumar K if (host_seis != seis) 48d017d7b0SVijaya Kumar K return false; 49d017d7b0SVijaya Kumar K 50d017d7b0SVijaya Kumar K host_a3v = ((kvm_vgic_global_state.ich_vtr_el2 & 51d017d7b0SVijaya Kumar K ICH_VTR_A3V_MASK) >> ICH_VTR_A3V_SHIFT); 52d017d7b0SVijaya Kumar K a3v = (val & ICC_CTLR_EL1_A3V_MASK) >> ICC_CTLR_EL1_A3V_SHIFT; 53d017d7b0SVijaya Kumar K if (host_a3v != a3v) 54d017d7b0SVijaya Kumar K return false; 55d017d7b0SVijaya Kumar K 56d017d7b0SVijaya Kumar K /* 57d017d7b0SVijaya Kumar K * Here set VMCR.CTLR in ICC_CTLR_EL1 layout. 58d017d7b0SVijaya Kumar K * The vgic_set_vmcr() will convert to ICH_VMCR layout. 59d017d7b0SVijaya Kumar K */ 6028232a43SChristoffer Dall vmcr.cbpr = (val & ICC_CTLR_EL1_CBPR_MASK) >> ICC_CTLR_EL1_CBPR_SHIFT; 6128232a43SChristoffer Dall vmcr.eoim = (val & ICC_CTLR_EL1_EOImode_MASK) >> ICC_CTLR_EL1_EOImode_SHIFT; 62d017d7b0SVijaya Kumar K vgic_set_vmcr(vcpu, &vmcr); 63d017d7b0SVijaya Kumar K } else { 64d017d7b0SVijaya Kumar K val = 0; 65d017d7b0SVijaya Kumar K val |= (vgic_v3_cpu->num_pri_bits - 1) << 66d017d7b0SVijaya Kumar K ICC_CTLR_EL1_PRI_BITS_SHIFT; 67d017d7b0SVijaya Kumar K val |= vgic_v3_cpu->num_id_bits << ICC_CTLR_EL1_ID_BITS_SHIFT; 68d017d7b0SVijaya Kumar K val |= ((kvm_vgic_global_state.ich_vtr_el2 & 69d017d7b0SVijaya Kumar K ICH_VTR_SEIS_MASK) >> ICH_VTR_SEIS_SHIFT) << 70d017d7b0SVijaya Kumar K ICC_CTLR_EL1_SEIS_SHIFT; 71d017d7b0SVijaya Kumar K val |= ((kvm_vgic_global_state.ich_vtr_el2 & 72d017d7b0SVijaya Kumar K ICH_VTR_A3V_MASK) >> ICH_VTR_A3V_SHIFT) << 73d017d7b0SVijaya Kumar K ICC_CTLR_EL1_A3V_SHIFT; 74d017d7b0SVijaya Kumar K /* 75d017d7b0SVijaya Kumar K * The VMCR.CTLR value is in ICC_CTLR_EL1 layout. 76d017d7b0SVijaya Kumar K * Extract it directly using ICC_CTLR_EL1 reg definitions. 77d017d7b0SVijaya Kumar K */ 7828232a43SChristoffer Dall val |= (vmcr.cbpr << ICC_CTLR_EL1_CBPR_SHIFT) & ICC_CTLR_EL1_CBPR_MASK; 7928232a43SChristoffer Dall val |= (vmcr.eoim << ICC_CTLR_EL1_EOImode_SHIFT) & ICC_CTLR_EL1_EOImode_MASK; 80d017d7b0SVijaya Kumar K 81d017d7b0SVijaya Kumar K p->regval = val; 82d017d7b0SVijaya Kumar K } 83d017d7b0SVijaya Kumar K 84d017d7b0SVijaya Kumar K return true; 85d017d7b0SVijaya Kumar K } 86d017d7b0SVijaya Kumar K 87d017d7b0SVijaya Kumar K static bool access_gic_pmr(struct kvm_vcpu *vcpu, struct sys_reg_params *p, 88d017d7b0SVijaya Kumar K const struct sys_reg_desc *r) 89d017d7b0SVijaya Kumar K { 90d017d7b0SVijaya Kumar K struct vgic_vmcr vmcr; 91d017d7b0SVijaya Kumar K 92d017d7b0SVijaya Kumar K vgic_get_vmcr(vcpu, &vmcr); 93d017d7b0SVijaya Kumar K if (p->is_write) { 94d017d7b0SVijaya Kumar K vmcr.pmr = (p->regval & ICC_PMR_EL1_MASK) >> ICC_PMR_EL1_SHIFT; 95d017d7b0SVijaya Kumar K vgic_set_vmcr(vcpu, &vmcr); 96d017d7b0SVijaya Kumar K } else { 97d017d7b0SVijaya Kumar K p->regval = (vmcr.pmr << ICC_PMR_EL1_SHIFT) & ICC_PMR_EL1_MASK; 98d017d7b0SVijaya Kumar K } 99d017d7b0SVijaya Kumar K 100d017d7b0SVijaya Kumar K return true; 101d017d7b0SVijaya Kumar K } 102d017d7b0SVijaya Kumar K 103d017d7b0SVijaya Kumar K static bool access_gic_bpr0(struct kvm_vcpu *vcpu, struct sys_reg_params *p, 104d017d7b0SVijaya Kumar K const struct sys_reg_desc *r) 105d017d7b0SVijaya Kumar K { 106d017d7b0SVijaya Kumar K struct vgic_vmcr vmcr; 107d017d7b0SVijaya Kumar K 108d017d7b0SVijaya Kumar K vgic_get_vmcr(vcpu, &vmcr); 109d017d7b0SVijaya Kumar K if (p->is_write) { 110d017d7b0SVijaya Kumar K vmcr.bpr = (p->regval & ICC_BPR0_EL1_MASK) >> 111d017d7b0SVijaya Kumar K ICC_BPR0_EL1_SHIFT; 112d017d7b0SVijaya Kumar K vgic_set_vmcr(vcpu, &vmcr); 113d017d7b0SVijaya Kumar K } else { 114d017d7b0SVijaya Kumar K p->regval = (vmcr.bpr << ICC_BPR0_EL1_SHIFT) & 115d017d7b0SVijaya Kumar K ICC_BPR0_EL1_MASK; 116d017d7b0SVijaya Kumar K } 117d017d7b0SVijaya Kumar K 118d017d7b0SVijaya Kumar K return true; 119d017d7b0SVijaya Kumar K } 120d017d7b0SVijaya Kumar K 121d017d7b0SVijaya Kumar K static bool access_gic_bpr1(struct kvm_vcpu *vcpu, struct sys_reg_params *p, 122d017d7b0SVijaya Kumar K const struct sys_reg_desc *r) 123d017d7b0SVijaya Kumar K { 124d017d7b0SVijaya Kumar K struct vgic_vmcr vmcr; 125d017d7b0SVijaya Kumar K 126d017d7b0SVijaya Kumar K if (!p->is_write) 127d017d7b0SVijaya Kumar K p->regval = 0; 128d017d7b0SVijaya Kumar K 129d017d7b0SVijaya Kumar K vgic_get_vmcr(vcpu, &vmcr); 13028232a43SChristoffer Dall if (!vmcr.cbpr) { 131d017d7b0SVijaya Kumar K if (p->is_write) { 132d017d7b0SVijaya Kumar K vmcr.abpr = (p->regval & ICC_BPR1_EL1_MASK) >> 133d017d7b0SVijaya Kumar K ICC_BPR1_EL1_SHIFT; 134d017d7b0SVijaya Kumar K vgic_set_vmcr(vcpu, &vmcr); 135d017d7b0SVijaya Kumar K } else { 136d017d7b0SVijaya Kumar K p->regval = (vmcr.abpr << ICC_BPR1_EL1_SHIFT) & 137d017d7b0SVijaya Kumar K ICC_BPR1_EL1_MASK; 138d017d7b0SVijaya Kumar K } 139d017d7b0SVijaya Kumar K } else { 140d017d7b0SVijaya Kumar K if (!p->is_write) 141d017d7b0SVijaya Kumar K p->regval = min((vmcr.bpr + 1), 7U); 142d017d7b0SVijaya Kumar K } 143d017d7b0SVijaya Kumar K 144d017d7b0SVijaya Kumar K return true; 145d017d7b0SVijaya Kumar K } 146d017d7b0SVijaya Kumar K 147d017d7b0SVijaya Kumar K static bool access_gic_grpen0(struct kvm_vcpu *vcpu, struct sys_reg_params *p, 148d017d7b0SVijaya Kumar K const struct sys_reg_desc *r) 149d017d7b0SVijaya Kumar K { 150d017d7b0SVijaya Kumar K struct vgic_vmcr vmcr; 151d017d7b0SVijaya Kumar K 152d017d7b0SVijaya Kumar K vgic_get_vmcr(vcpu, &vmcr); 153d017d7b0SVijaya Kumar K if (p->is_write) { 154d017d7b0SVijaya Kumar K vmcr.grpen0 = (p->regval & ICC_IGRPEN0_EL1_MASK) >> 155d017d7b0SVijaya Kumar K ICC_IGRPEN0_EL1_SHIFT; 156d017d7b0SVijaya Kumar K vgic_set_vmcr(vcpu, &vmcr); 157d017d7b0SVijaya Kumar K } else { 158d017d7b0SVijaya Kumar K p->regval = (vmcr.grpen0 << ICC_IGRPEN0_EL1_SHIFT) & 159d017d7b0SVijaya Kumar K ICC_IGRPEN0_EL1_MASK; 160d017d7b0SVijaya Kumar K } 161d017d7b0SVijaya Kumar K 162d017d7b0SVijaya Kumar K return true; 163d017d7b0SVijaya Kumar K } 164d017d7b0SVijaya Kumar K 165d017d7b0SVijaya Kumar K static bool access_gic_grpen1(struct kvm_vcpu *vcpu, struct sys_reg_params *p, 166d017d7b0SVijaya Kumar K const struct sys_reg_desc *r) 167d017d7b0SVijaya Kumar K { 168d017d7b0SVijaya Kumar K struct vgic_vmcr vmcr; 169d017d7b0SVijaya Kumar K 170d017d7b0SVijaya Kumar K vgic_get_vmcr(vcpu, &vmcr); 171d017d7b0SVijaya Kumar K if (p->is_write) { 172d017d7b0SVijaya Kumar K vmcr.grpen1 = (p->regval & ICC_IGRPEN1_EL1_MASK) >> 173d017d7b0SVijaya Kumar K ICC_IGRPEN1_EL1_SHIFT; 174d017d7b0SVijaya Kumar K vgic_set_vmcr(vcpu, &vmcr); 175d017d7b0SVijaya Kumar K } else { 176d017d7b0SVijaya Kumar K p->regval = (vmcr.grpen1 << ICC_IGRPEN1_EL1_SHIFT) & 177d017d7b0SVijaya Kumar K ICC_IGRPEN1_EL1_MASK; 178d017d7b0SVijaya Kumar K } 179d017d7b0SVijaya Kumar K 180d017d7b0SVijaya Kumar K return true; 181d017d7b0SVijaya Kumar K } 182d017d7b0SVijaya Kumar K 183d017d7b0SVijaya Kumar K static void vgic_v3_access_apr_reg(struct kvm_vcpu *vcpu, 184d017d7b0SVijaya Kumar K struct sys_reg_params *p, u8 apr, u8 idx) 185d017d7b0SVijaya Kumar K { 186d017d7b0SVijaya Kumar K struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3; 187d017d7b0SVijaya Kumar K uint32_t *ap_reg; 188d017d7b0SVijaya Kumar K 189d017d7b0SVijaya Kumar K if (apr) 190d017d7b0SVijaya Kumar K ap_reg = &vgicv3->vgic_ap1r[idx]; 191d017d7b0SVijaya Kumar K else 192d017d7b0SVijaya Kumar K ap_reg = &vgicv3->vgic_ap0r[idx]; 193d017d7b0SVijaya Kumar K 194d017d7b0SVijaya Kumar K if (p->is_write) 195d017d7b0SVijaya Kumar K *ap_reg = p->regval; 196d017d7b0SVijaya Kumar K else 197d017d7b0SVijaya Kumar K p->regval = *ap_reg; 198d017d7b0SVijaya Kumar K } 199d017d7b0SVijaya Kumar K 200d017d7b0SVijaya Kumar K static bool access_gic_aprn(struct kvm_vcpu *vcpu, struct sys_reg_params *p, 201d017d7b0SVijaya Kumar K const struct sys_reg_desc *r, u8 apr) 202d017d7b0SVijaya Kumar K { 203d017d7b0SVijaya Kumar K u8 idx = r->Op2 & 3; 204d017d7b0SVijaya Kumar K 20550f5bd57SChristoffer Dall if (idx > vgic_v3_max_apr_idx(vcpu)) 206d017d7b0SVijaya Kumar K goto err; 207d017d7b0SVijaya Kumar K 20850f5bd57SChristoffer Dall vgic_v3_access_apr_reg(vcpu, p, apr, idx); 209d017d7b0SVijaya Kumar K return true; 210d017d7b0SVijaya Kumar K err: 211d017d7b0SVijaya Kumar K if (!p->is_write) 212d017d7b0SVijaya Kumar K p->regval = 0; 213d017d7b0SVijaya Kumar K 214d017d7b0SVijaya Kumar K return false; 215d017d7b0SVijaya Kumar K } 216d017d7b0SVijaya Kumar K 217d017d7b0SVijaya Kumar K static bool access_gic_ap0r(struct kvm_vcpu *vcpu, struct sys_reg_params *p, 218d017d7b0SVijaya Kumar K const struct sys_reg_desc *r) 219d017d7b0SVijaya Kumar K 220d017d7b0SVijaya Kumar K { 221d017d7b0SVijaya Kumar K return access_gic_aprn(vcpu, p, r, 0); 222d017d7b0SVijaya Kumar K } 223d017d7b0SVijaya Kumar K 224d017d7b0SVijaya Kumar K static bool access_gic_ap1r(struct kvm_vcpu *vcpu, struct sys_reg_params *p, 225d017d7b0SVijaya Kumar K const struct sys_reg_desc *r) 226d017d7b0SVijaya Kumar K { 227d017d7b0SVijaya Kumar K return access_gic_aprn(vcpu, p, r, 1); 228d017d7b0SVijaya Kumar K } 229d017d7b0SVijaya Kumar K 230d017d7b0SVijaya Kumar K static bool access_gic_sre(struct kvm_vcpu *vcpu, struct sys_reg_params *p, 231d017d7b0SVijaya Kumar K const struct sys_reg_desc *r) 232d017d7b0SVijaya Kumar K { 233d017d7b0SVijaya Kumar K struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3; 234d017d7b0SVijaya Kumar K 235d017d7b0SVijaya Kumar K /* Validate SRE bit */ 236d017d7b0SVijaya Kumar K if (p->is_write) { 237d017d7b0SVijaya Kumar K if (!(p->regval & ICC_SRE_EL1_SRE)) 238d017d7b0SVijaya Kumar K return false; 239d017d7b0SVijaya Kumar K } else { 240d017d7b0SVijaya Kumar K p->regval = vgicv3->vgic_sre; 241d017d7b0SVijaya Kumar K } 242d017d7b0SVijaya Kumar K 243d017d7b0SVijaya Kumar K return true; 244d017d7b0SVijaya Kumar K } 245d017d7b0SVijaya Kumar K static const struct sys_reg_desc gic_v3_icc_reg_descs[] = { 2460959db6cSMark Rutland { SYS_DESC(SYS_ICC_PMR_EL1), access_gic_pmr }, 2470959db6cSMark Rutland { SYS_DESC(SYS_ICC_BPR0_EL1), access_gic_bpr0 }, 2480959db6cSMark Rutland { SYS_DESC(SYS_ICC_AP0R0_EL1), access_gic_ap0r }, 2490959db6cSMark Rutland { SYS_DESC(SYS_ICC_AP0R1_EL1), access_gic_ap0r }, 2500959db6cSMark Rutland { SYS_DESC(SYS_ICC_AP0R2_EL1), access_gic_ap0r }, 2510959db6cSMark Rutland { SYS_DESC(SYS_ICC_AP0R3_EL1), access_gic_ap0r }, 2520959db6cSMark Rutland { SYS_DESC(SYS_ICC_AP1R0_EL1), access_gic_ap1r }, 2530959db6cSMark Rutland { SYS_DESC(SYS_ICC_AP1R1_EL1), access_gic_ap1r }, 2540959db6cSMark Rutland { SYS_DESC(SYS_ICC_AP1R2_EL1), access_gic_ap1r }, 2550959db6cSMark Rutland { SYS_DESC(SYS_ICC_AP1R3_EL1), access_gic_ap1r }, 2560959db6cSMark Rutland { SYS_DESC(SYS_ICC_BPR1_EL1), access_gic_bpr1 }, 2570959db6cSMark Rutland { SYS_DESC(SYS_ICC_CTLR_EL1), access_gic_ctlr }, 2580959db6cSMark Rutland { SYS_DESC(SYS_ICC_SRE_EL1), access_gic_sre }, 2590959db6cSMark Rutland { SYS_DESC(SYS_ICC_IGRPEN0_EL1), access_gic_grpen0 }, 2600959db6cSMark Rutland { SYS_DESC(SYS_ICC_IGRPEN1_EL1), access_gic_grpen1 }, 261d017d7b0SVijaya Kumar K }; 262d017d7b0SVijaya Kumar K 263*b61fc085SMarc Zyngier static u64 attr_to_id(u64 attr) 264d017d7b0SVijaya Kumar K { 265*b61fc085SMarc Zyngier return ARM64_SYS_REG(FIELD_GET(KVM_REG_ARM_VGIC_SYSREG_OP0_MASK, attr), 266*b61fc085SMarc Zyngier FIELD_GET(KVM_REG_ARM_VGIC_SYSREG_OP1_MASK, attr), 267*b61fc085SMarc Zyngier FIELD_GET(KVM_REG_ARM_VGIC_SYSREG_CRN_MASK, attr), 268*b61fc085SMarc Zyngier FIELD_GET(KVM_REG_ARM_VGIC_SYSREG_CRM_MASK, attr), 269*b61fc085SMarc Zyngier FIELD_GET(KVM_REG_ARM_VGIC_SYSREG_OP2_MASK, attr)); 270*b61fc085SMarc Zyngier } 271d017d7b0SVijaya Kumar K 272*b61fc085SMarc Zyngier int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) 273*b61fc085SMarc Zyngier { 274*b61fc085SMarc Zyngier if (get_reg_by_id(attr_to_id(attr->attr), gic_v3_icc_reg_descs, 275d017d7b0SVijaya Kumar K ARRAY_SIZE(gic_v3_icc_reg_descs))) 276d017d7b0SVijaya Kumar K return 0; 277d017d7b0SVijaya Kumar K 278d017d7b0SVijaya Kumar K return -ENXIO; 279d017d7b0SVijaya Kumar K } 280d017d7b0SVijaya Kumar K 281d017d7b0SVijaya Kumar K int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write, u64 id, 282d017d7b0SVijaya Kumar K u64 *reg) 283d017d7b0SVijaya Kumar K { 284d017d7b0SVijaya Kumar K struct sys_reg_params params; 285d017d7b0SVijaya Kumar K const struct sys_reg_desc *r; 286d017d7b0SVijaya Kumar K u64 sysreg = (id & KVM_DEV_ARM_VGIC_SYSREG_MASK) | KVM_REG_SIZE_U64; 287d017d7b0SVijaya Kumar K 288d017d7b0SVijaya Kumar K if (is_write) 289d017d7b0SVijaya Kumar K params.regval = *reg; 290d017d7b0SVijaya Kumar K params.is_write = is_write; 291d017d7b0SVijaya Kumar K 292d017d7b0SVijaya Kumar K r = find_reg_by_id(sysreg, ¶ms, gic_v3_icc_reg_descs, 293d017d7b0SVijaya Kumar K ARRAY_SIZE(gic_v3_icc_reg_descs)); 294d017d7b0SVijaya Kumar K if (!r) 295d017d7b0SVijaya Kumar K return -ENXIO; 296d017d7b0SVijaya Kumar K 297d017d7b0SVijaya Kumar K if (!r->access(vcpu, ¶ms, r)) 298d017d7b0SVijaya Kumar K return -EINVAL; 299d017d7b0SVijaya Kumar K 300d017d7b0SVijaya Kumar K if (!is_write) 301d017d7b0SVijaya Kumar K *reg = params.regval; 302d017d7b0SVijaya Kumar K 303d017d7b0SVijaya Kumar K return 0; 304d017d7b0SVijaya Kumar K } 305