1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * VGIC system registers handling functions for AArch64 mode 4 */ 5 6 #include <linux/irqchip/arm-gic-v3.h> 7 #include <linux/kvm.h> 8 #include <linux/kvm_host.h> 9 #include <asm/kvm_emulate.h> 10 #include "vgic/vgic.h" 11 #include "sys_regs.h" 12 13 static int set_gic_ctlr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, 14 u64 val) 15 { 16 u32 host_pri_bits, host_id_bits, host_seis, host_a3v, seis, a3v; 17 struct vgic_cpu *vgic_v3_cpu = &vcpu->arch.vgic_cpu; 18 struct vgic_vmcr vmcr; 19 20 vgic_get_vmcr(vcpu, &vmcr); 21 22 /* 23 * Disallow restoring VM state if not supported by this 24 * hardware. 25 */ 26 host_pri_bits = FIELD_GET(ICC_CTLR_EL1_PRI_BITS_MASK, val) + 1; 27 if (host_pri_bits > vgic_v3_cpu->num_pri_bits) 28 return -EINVAL; 29 30 vgic_v3_cpu->num_pri_bits = host_pri_bits; 31 32 host_id_bits = FIELD_GET(ICC_CTLR_EL1_ID_BITS_MASK, val); 33 if (host_id_bits > vgic_v3_cpu->num_id_bits) 34 return -EINVAL; 35 36 vgic_v3_cpu->num_id_bits = host_id_bits; 37 38 host_seis = FIELD_GET(ICH_VTR_SEIS_MASK, kvm_vgic_global_state.ich_vtr_el2); 39 seis = FIELD_GET(ICC_CTLR_EL1_SEIS_MASK, val); 40 if (host_seis != seis) 41 return -EINVAL; 42 43 host_a3v = FIELD_GET(ICH_VTR_A3V_MASK, kvm_vgic_global_state.ich_vtr_el2); 44 a3v = FIELD_GET(ICC_CTLR_EL1_A3V_MASK, val); 45 if (host_a3v != a3v) 46 return -EINVAL; 47 48 /* 49 * Here set VMCR.CTLR in ICC_CTLR_EL1 layout. 50 * The vgic_set_vmcr() will convert to ICH_VMCR layout. 51 */ 52 vmcr.cbpr = FIELD_GET(ICC_CTLR_EL1_CBPR_MASK, val); 53 vmcr.eoim = FIELD_GET(ICC_CTLR_EL1_EOImode_MASK, val); 54 vgic_set_vmcr(vcpu, &vmcr); 55 56 return 0; 57 } 58 59 static int get_gic_ctlr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, 60 u64 *valp) 61 { 62 struct vgic_cpu *vgic_v3_cpu = &vcpu->arch.vgic_cpu; 63 struct vgic_vmcr vmcr; 64 u64 val; 65 66 vgic_get_vmcr(vcpu, &vmcr); 67 val = 0; 68 val |= FIELD_PREP(ICC_CTLR_EL1_PRI_BITS_MASK, vgic_v3_cpu->num_pri_bits - 1); 69 val |= FIELD_PREP(ICC_CTLR_EL1_ID_BITS_MASK, vgic_v3_cpu->num_id_bits); 70 val |= FIELD_PREP(ICC_CTLR_EL1_SEIS_MASK, 71 FIELD_GET(ICH_VTR_SEIS_MASK, 72 kvm_vgic_global_state.ich_vtr_el2)); 73 val |= FIELD_PREP(ICC_CTLR_EL1_A3V_MASK, 74 FIELD_GET(ICH_VTR_A3V_MASK, kvm_vgic_global_state.ich_vtr_el2)); 75 /* 76 * The VMCR.CTLR value is in ICC_CTLR_EL1 layout. 77 * Extract it directly using ICC_CTLR_EL1 reg definitions. 78 */ 79 val |= FIELD_PREP(ICC_CTLR_EL1_CBPR_MASK, vmcr.cbpr); 80 val |= FIELD_PREP(ICC_CTLR_EL1_EOImode_MASK, vmcr.eoim); 81 82 *valp = val; 83 84 return 0; 85 } 86 87 static int set_gic_pmr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, 88 u64 val) 89 { 90 struct vgic_vmcr vmcr; 91 92 vgic_get_vmcr(vcpu, &vmcr); 93 vmcr.pmr = FIELD_GET(ICC_PMR_EL1_MASK, val); 94 vgic_set_vmcr(vcpu, &vmcr); 95 96 return 0; 97 } 98 99 static int get_gic_pmr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, 100 u64 *val) 101 { 102 struct vgic_vmcr vmcr; 103 104 vgic_get_vmcr(vcpu, &vmcr); 105 *val = FIELD_PREP(ICC_PMR_EL1_MASK, vmcr.pmr); 106 107 return 0; 108 } 109 110 static int set_gic_bpr0(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, 111 u64 val) 112 { 113 struct vgic_vmcr vmcr; 114 115 vgic_get_vmcr(vcpu, &vmcr); 116 vmcr.bpr = FIELD_GET(ICC_BPR0_EL1_MASK, val); 117 vgic_set_vmcr(vcpu, &vmcr); 118 119 return 0; 120 } 121 122 static int get_gic_bpr0(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, 123 u64 *val) 124 { 125 struct vgic_vmcr vmcr; 126 127 vgic_get_vmcr(vcpu, &vmcr); 128 *val = FIELD_PREP(ICC_BPR0_EL1_MASK, vmcr.bpr); 129 130 return 0; 131 } 132 133 static int set_gic_bpr1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, 134 u64 val) 135 { 136 struct vgic_vmcr vmcr; 137 138 vgic_get_vmcr(vcpu, &vmcr); 139 if (!vmcr.cbpr) { 140 vmcr.abpr = FIELD_GET(ICC_BPR1_EL1_MASK, val); 141 vgic_set_vmcr(vcpu, &vmcr); 142 } 143 144 return 0; 145 } 146 147 static int get_gic_bpr1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, 148 u64 *val) 149 { 150 struct vgic_vmcr vmcr; 151 152 vgic_get_vmcr(vcpu, &vmcr); 153 if (!vmcr.cbpr) 154 *val = FIELD_PREP(ICC_BPR1_EL1_MASK, vmcr.abpr); 155 else 156 *val = min((vmcr.bpr + 1), 7U); 157 158 159 return 0; 160 } 161 162 static int set_gic_grpen0(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, 163 u64 val) 164 { 165 struct vgic_vmcr vmcr; 166 167 vgic_get_vmcr(vcpu, &vmcr); 168 vmcr.grpen0 = FIELD_GET(ICC_IGRPEN0_EL1_MASK, val); 169 vgic_set_vmcr(vcpu, &vmcr); 170 171 return 0; 172 } 173 174 static int get_gic_grpen0(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, 175 u64 *val) 176 { 177 struct vgic_vmcr vmcr; 178 179 vgic_get_vmcr(vcpu, &vmcr); 180 *val = FIELD_PREP(ICC_IGRPEN0_EL1_MASK, vmcr.grpen0); 181 182 return 0; 183 } 184 185 static int set_gic_grpen1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, 186 u64 val) 187 { 188 struct vgic_vmcr vmcr; 189 190 vgic_get_vmcr(vcpu, &vmcr); 191 vmcr.grpen1 = FIELD_GET(ICC_IGRPEN1_EL1_MASK, val); 192 vgic_set_vmcr(vcpu, &vmcr); 193 194 return 0; 195 } 196 197 static int get_gic_grpen1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, 198 u64 *val) 199 { 200 struct vgic_vmcr vmcr; 201 202 vgic_get_vmcr(vcpu, &vmcr); 203 *val = FIELD_GET(ICC_IGRPEN1_EL1_MASK, vmcr.grpen1); 204 205 return 0; 206 } 207 208 static void set_apr_reg(struct kvm_vcpu *vcpu, u64 val, u8 apr, u8 idx) 209 { 210 struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3; 211 212 if (apr) 213 vgicv3->vgic_ap1r[idx] = val; 214 else 215 vgicv3->vgic_ap0r[idx] = val; 216 } 217 218 static u64 get_apr_reg(struct kvm_vcpu *vcpu, u8 apr, u8 idx) 219 { 220 struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3; 221 222 if (apr) 223 return vgicv3->vgic_ap1r[idx]; 224 else 225 return vgicv3->vgic_ap0r[idx]; 226 } 227 228 static int set_gic_ap0r(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, 229 u64 val) 230 231 { 232 u8 idx = r->Op2 & 3; 233 234 if (idx > vgic_v3_max_apr_idx(vcpu)) 235 return -EINVAL; 236 237 set_apr_reg(vcpu, val, 0, idx); 238 return 0; 239 } 240 241 static int get_gic_ap0r(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, 242 u64 *val) 243 { 244 u8 idx = r->Op2 & 3; 245 246 if (idx > vgic_v3_max_apr_idx(vcpu)) 247 return -EINVAL; 248 249 *val = get_apr_reg(vcpu, 0, idx); 250 251 return 0; 252 } 253 254 static int set_gic_ap1r(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, 255 u64 val) 256 257 { 258 u8 idx = r->Op2 & 3; 259 260 if (idx > vgic_v3_max_apr_idx(vcpu)) 261 return -EINVAL; 262 263 set_apr_reg(vcpu, val, 1, idx); 264 return 0; 265 } 266 267 static int get_gic_ap1r(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, 268 u64 *val) 269 { 270 u8 idx = r->Op2 & 3; 271 272 if (idx > vgic_v3_max_apr_idx(vcpu)) 273 return -EINVAL; 274 275 *val = get_apr_reg(vcpu, 1, idx); 276 277 return 0; 278 } 279 280 static int set_gic_sre(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, 281 u64 val) 282 { 283 /* Validate SRE bit */ 284 if (!(val & ICC_SRE_EL1_SRE)) 285 return -EINVAL; 286 287 return 0; 288 } 289 290 static int get_gic_sre(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, 291 u64 *val) 292 { 293 struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3; 294 295 *val = vgicv3->vgic_sre; 296 297 return 0; 298 } 299 300 static const struct sys_reg_desc gic_v3_icc_reg_descs[] = { 301 { SYS_DESC(SYS_ICC_PMR_EL1), 302 .set_user = set_gic_pmr, .get_user = get_gic_pmr, }, 303 { SYS_DESC(SYS_ICC_BPR0_EL1), 304 .set_user = set_gic_bpr0, .get_user = get_gic_bpr0, }, 305 { SYS_DESC(SYS_ICC_AP0R0_EL1), 306 .set_user = set_gic_ap0r, .get_user = get_gic_ap0r, }, 307 { SYS_DESC(SYS_ICC_AP0R1_EL1), 308 .set_user = set_gic_ap0r, .get_user = get_gic_ap0r, }, 309 { SYS_DESC(SYS_ICC_AP0R2_EL1), 310 .set_user = set_gic_ap0r, .get_user = get_gic_ap0r, }, 311 { SYS_DESC(SYS_ICC_AP0R3_EL1), 312 .set_user = set_gic_ap0r, .get_user = get_gic_ap0r, }, 313 { SYS_DESC(SYS_ICC_AP1R0_EL1), 314 .set_user = set_gic_ap1r, .get_user = get_gic_ap1r, }, 315 { SYS_DESC(SYS_ICC_AP1R1_EL1), 316 .set_user = set_gic_ap1r, .get_user = get_gic_ap1r, }, 317 { SYS_DESC(SYS_ICC_AP1R2_EL1), 318 .set_user = set_gic_ap1r, .get_user = get_gic_ap1r, }, 319 { SYS_DESC(SYS_ICC_AP1R3_EL1), 320 .set_user = set_gic_ap1r, .get_user = get_gic_ap1r, }, 321 { SYS_DESC(SYS_ICC_BPR1_EL1), 322 .set_user = set_gic_bpr1, .get_user = get_gic_bpr1, }, 323 { SYS_DESC(SYS_ICC_CTLR_EL1), 324 .set_user = set_gic_ctlr, .get_user = get_gic_ctlr, }, 325 { SYS_DESC(SYS_ICC_SRE_EL1), 326 .set_user = set_gic_sre, .get_user = get_gic_sre, }, 327 { SYS_DESC(SYS_ICC_IGRPEN0_EL1), 328 .set_user = set_gic_grpen0, .get_user = get_gic_grpen0, }, 329 { SYS_DESC(SYS_ICC_IGRPEN1_EL1), 330 .set_user = set_gic_grpen1, .get_user = get_gic_grpen1, }, 331 }; 332 333 static u64 attr_to_id(u64 attr) 334 { 335 return ARM64_SYS_REG(FIELD_GET(KVM_REG_ARM_VGIC_SYSREG_OP0_MASK, attr), 336 FIELD_GET(KVM_REG_ARM_VGIC_SYSREG_OP1_MASK, attr), 337 FIELD_GET(KVM_REG_ARM_VGIC_SYSREG_CRN_MASK, attr), 338 FIELD_GET(KVM_REG_ARM_VGIC_SYSREG_CRM_MASK, attr), 339 FIELD_GET(KVM_REG_ARM_VGIC_SYSREG_OP2_MASK, attr)); 340 } 341 342 int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) 343 { 344 if (get_reg_by_id(attr_to_id(attr->attr), gic_v3_icc_reg_descs, 345 ARRAY_SIZE(gic_v3_icc_reg_descs))) 346 return 0; 347 348 return -ENXIO; 349 } 350 351 int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, 352 struct kvm_device_attr *attr, 353 bool is_write) 354 { 355 struct kvm_one_reg reg = { 356 .id = attr_to_id(attr->attr), 357 .addr = attr->addr, 358 }; 359 360 if (is_write) 361 return kvm_sys_reg_set_user(vcpu, ®, gic_v3_icc_reg_descs, 362 ARRAY_SIZE(gic_v3_icc_reg_descs)); 363 else 364 return kvm_sys_reg_get_user(vcpu, ®, gic_v3_icc_reg_descs, 365 ARRAY_SIZE(gic_v3_icc_reg_descs)); 366 } 367
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.