162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2012-2015 - ARM Ltd 462306a36Sopenharmony_ci * Author: Marc Zyngier <marc.zyngier@arm.com> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <hyp/adjust_pc.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/compiler.h> 1062306a36Sopenharmony_ci#include <linux/irqchip/arm-gic-v3.h> 1162306a36Sopenharmony_ci#include <linux/kvm_host.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <asm/kvm_emulate.h> 1462306a36Sopenharmony_ci#include <asm/kvm_hyp.h> 1562306a36Sopenharmony_ci#include <asm/kvm_mmu.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define vtr_to_max_lr_idx(v) ((v) & 0xf) 1862306a36Sopenharmony_ci#define vtr_to_nr_pre_bits(v) ((((u32)(v) >> 26) & 7) + 1) 1962306a36Sopenharmony_ci#define vtr_to_nr_apr_regs(v) (1 << (vtr_to_nr_pre_bits(v) - 5)) 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic u64 __gic_v3_get_lr(unsigned int lr) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci switch (lr & 0xf) { 2462306a36Sopenharmony_ci case 0: 2562306a36Sopenharmony_ci return read_gicreg(ICH_LR0_EL2); 2662306a36Sopenharmony_ci case 1: 2762306a36Sopenharmony_ci return read_gicreg(ICH_LR1_EL2); 2862306a36Sopenharmony_ci case 2: 2962306a36Sopenharmony_ci return read_gicreg(ICH_LR2_EL2); 3062306a36Sopenharmony_ci case 3: 3162306a36Sopenharmony_ci return read_gicreg(ICH_LR3_EL2); 3262306a36Sopenharmony_ci case 4: 3362306a36Sopenharmony_ci return read_gicreg(ICH_LR4_EL2); 3462306a36Sopenharmony_ci case 5: 3562306a36Sopenharmony_ci return read_gicreg(ICH_LR5_EL2); 3662306a36Sopenharmony_ci case 6: 3762306a36Sopenharmony_ci return read_gicreg(ICH_LR6_EL2); 3862306a36Sopenharmony_ci case 7: 3962306a36Sopenharmony_ci return read_gicreg(ICH_LR7_EL2); 4062306a36Sopenharmony_ci case 8: 4162306a36Sopenharmony_ci return read_gicreg(ICH_LR8_EL2); 4262306a36Sopenharmony_ci case 9: 4362306a36Sopenharmony_ci return read_gicreg(ICH_LR9_EL2); 4462306a36Sopenharmony_ci case 10: 4562306a36Sopenharmony_ci return read_gicreg(ICH_LR10_EL2); 4662306a36Sopenharmony_ci case 11: 4762306a36Sopenharmony_ci return read_gicreg(ICH_LR11_EL2); 4862306a36Sopenharmony_ci case 12: 4962306a36Sopenharmony_ci return read_gicreg(ICH_LR12_EL2); 5062306a36Sopenharmony_ci case 13: 5162306a36Sopenharmony_ci return read_gicreg(ICH_LR13_EL2); 5262306a36Sopenharmony_ci case 14: 5362306a36Sopenharmony_ci return read_gicreg(ICH_LR14_EL2); 5462306a36Sopenharmony_ci case 15: 5562306a36Sopenharmony_ci return read_gicreg(ICH_LR15_EL2); 5662306a36Sopenharmony_ci } 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci unreachable(); 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic void __gic_v3_set_lr(u64 val, int lr) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci switch (lr & 0xf) { 6462306a36Sopenharmony_ci case 0: 6562306a36Sopenharmony_ci write_gicreg(val, ICH_LR0_EL2); 6662306a36Sopenharmony_ci break; 6762306a36Sopenharmony_ci case 1: 6862306a36Sopenharmony_ci write_gicreg(val, ICH_LR1_EL2); 6962306a36Sopenharmony_ci break; 7062306a36Sopenharmony_ci case 2: 7162306a36Sopenharmony_ci write_gicreg(val, ICH_LR2_EL2); 7262306a36Sopenharmony_ci break; 7362306a36Sopenharmony_ci case 3: 7462306a36Sopenharmony_ci write_gicreg(val, ICH_LR3_EL2); 7562306a36Sopenharmony_ci break; 7662306a36Sopenharmony_ci case 4: 7762306a36Sopenharmony_ci write_gicreg(val, ICH_LR4_EL2); 7862306a36Sopenharmony_ci break; 7962306a36Sopenharmony_ci case 5: 8062306a36Sopenharmony_ci write_gicreg(val, ICH_LR5_EL2); 8162306a36Sopenharmony_ci break; 8262306a36Sopenharmony_ci case 6: 8362306a36Sopenharmony_ci write_gicreg(val, ICH_LR6_EL2); 8462306a36Sopenharmony_ci break; 8562306a36Sopenharmony_ci case 7: 8662306a36Sopenharmony_ci write_gicreg(val, ICH_LR7_EL2); 8762306a36Sopenharmony_ci break; 8862306a36Sopenharmony_ci case 8: 8962306a36Sopenharmony_ci write_gicreg(val, ICH_LR8_EL2); 9062306a36Sopenharmony_ci break; 9162306a36Sopenharmony_ci case 9: 9262306a36Sopenharmony_ci write_gicreg(val, ICH_LR9_EL2); 9362306a36Sopenharmony_ci break; 9462306a36Sopenharmony_ci case 10: 9562306a36Sopenharmony_ci write_gicreg(val, ICH_LR10_EL2); 9662306a36Sopenharmony_ci break; 9762306a36Sopenharmony_ci case 11: 9862306a36Sopenharmony_ci write_gicreg(val, ICH_LR11_EL2); 9962306a36Sopenharmony_ci break; 10062306a36Sopenharmony_ci case 12: 10162306a36Sopenharmony_ci write_gicreg(val, ICH_LR12_EL2); 10262306a36Sopenharmony_ci break; 10362306a36Sopenharmony_ci case 13: 10462306a36Sopenharmony_ci write_gicreg(val, ICH_LR13_EL2); 10562306a36Sopenharmony_ci break; 10662306a36Sopenharmony_ci case 14: 10762306a36Sopenharmony_ci write_gicreg(val, ICH_LR14_EL2); 10862306a36Sopenharmony_ci break; 10962306a36Sopenharmony_ci case 15: 11062306a36Sopenharmony_ci write_gicreg(val, ICH_LR15_EL2); 11162306a36Sopenharmony_ci break; 11262306a36Sopenharmony_ci } 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic void __vgic_v3_write_ap0rn(u32 val, int n) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci switch (n) { 11862306a36Sopenharmony_ci case 0: 11962306a36Sopenharmony_ci write_gicreg(val, ICH_AP0R0_EL2); 12062306a36Sopenharmony_ci break; 12162306a36Sopenharmony_ci case 1: 12262306a36Sopenharmony_ci write_gicreg(val, ICH_AP0R1_EL2); 12362306a36Sopenharmony_ci break; 12462306a36Sopenharmony_ci case 2: 12562306a36Sopenharmony_ci write_gicreg(val, ICH_AP0R2_EL2); 12662306a36Sopenharmony_ci break; 12762306a36Sopenharmony_ci case 3: 12862306a36Sopenharmony_ci write_gicreg(val, ICH_AP0R3_EL2); 12962306a36Sopenharmony_ci break; 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic void __vgic_v3_write_ap1rn(u32 val, int n) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci switch (n) { 13662306a36Sopenharmony_ci case 0: 13762306a36Sopenharmony_ci write_gicreg(val, ICH_AP1R0_EL2); 13862306a36Sopenharmony_ci break; 13962306a36Sopenharmony_ci case 1: 14062306a36Sopenharmony_ci write_gicreg(val, ICH_AP1R1_EL2); 14162306a36Sopenharmony_ci break; 14262306a36Sopenharmony_ci case 2: 14362306a36Sopenharmony_ci write_gicreg(val, ICH_AP1R2_EL2); 14462306a36Sopenharmony_ci break; 14562306a36Sopenharmony_ci case 3: 14662306a36Sopenharmony_ci write_gicreg(val, ICH_AP1R3_EL2); 14762306a36Sopenharmony_ci break; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cistatic u32 __vgic_v3_read_ap0rn(int n) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci u32 val; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci switch (n) { 15662306a36Sopenharmony_ci case 0: 15762306a36Sopenharmony_ci val = read_gicreg(ICH_AP0R0_EL2); 15862306a36Sopenharmony_ci break; 15962306a36Sopenharmony_ci case 1: 16062306a36Sopenharmony_ci val = read_gicreg(ICH_AP0R1_EL2); 16162306a36Sopenharmony_ci break; 16262306a36Sopenharmony_ci case 2: 16362306a36Sopenharmony_ci val = read_gicreg(ICH_AP0R2_EL2); 16462306a36Sopenharmony_ci break; 16562306a36Sopenharmony_ci case 3: 16662306a36Sopenharmony_ci val = read_gicreg(ICH_AP0R3_EL2); 16762306a36Sopenharmony_ci break; 16862306a36Sopenharmony_ci default: 16962306a36Sopenharmony_ci unreachable(); 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci return val; 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic u32 __vgic_v3_read_ap1rn(int n) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci u32 val; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci switch (n) { 18062306a36Sopenharmony_ci case 0: 18162306a36Sopenharmony_ci val = read_gicreg(ICH_AP1R0_EL2); 18262306a36Sopenharmony_ci break; 18362306a36Sopenharmony_ci case 1: 18462306a36Sopenharmony_ci val = read_gicreg(ICH_AP1R1_EL2); 18562306a36Sopenharmony_ci break; 18662306a36Sopenharmony_ci case 2: 18762306a36Sopenharmony_ci val = read_gicreg(ICH_AP1R2_EL2); 18862306a36Sopenharmony_ci break; 18962306a36Sopenharmony_ci case 3: 19062306a36Sopenharmony_ci val = read_gicreg(ICH_AP1R3_EL2); 19162306a36Sopenharmony_ci break; 19262306a36Sopenharmony_ci default: 19362306a36Sopenharmony_ci unreachable(); 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci return val; 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_civoid __vgic_v3_save_state(struct vgic_v3_cpu_if *cpu_if) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci u64 used_lrs = cpu_if->used_lrs; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci /* 20462306a36Sopenharmony_ci * Make sure stores to the GIC via the memory mapped interface 20562306a36Sopenharmony_ci * are now visible to the system register interface when reading the 20662306a36Sopenharmony_ci * LRs, and when reading back the VMCR on non-VHE systems. 20762306a36Sopenharmony_ci */ 20862306a36Sopenharmony_ci if (used_lrs || !has_vhe()) { 20962306a36Sopenharmony_ci if (!cpu_if->vgic_sre) { 21062306a36Sopenharmony_ci dsb(sy); 21162306a36Sopenharmony_ci isb(); 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (used_lrs || cpu_if->its_vpe.its_vm) { 21662306a36Sopenharmony_ci int i; 21762306a36Sopenharmony_ci u32 elrsr; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci elrsr = read_gicreg(ICH_ELRSR_EL2); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci write_gicreg(cpu_if->vgic_hcr & ~ICH_HCR_EN, ICH_HCR_EL2); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci for (i = 0; i < used_lrs; i++) { 22462306a36Sopenharmony_ci if (elrsr & (1 << i)) 22562306a36Sopenharmony_ci cpu_if->vgic_lr[i] &= ~ICH_LR_STATE; 22662306a36Sopenharmony_ci else 22762306a36Sopenharmony_ci cpu_if->vgic_lr[i] = __gic_v3_get_lr(i); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci __gic_v3_set_lr(0, i); 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_civoid __vgic_v3_restore_state(struct vgic_v3_cpu_if *cpu_if) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci u64 used_lrs = cpu_if->used_lrs; 23762306a36Sopenharmony_ci int i; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci if (used_lrs || cpu_if->its_vpe.its_vm) { 24062306a36Sopenharmony_ci write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci for (i = 0; i < used_lrs; i++) 24362306a36Sopenharmony_ci __gic_v3_set_lr(cpu_if->vgic_lr[i], i); 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci /* 24762306a36Sopenharmony_ci * Ensure that writes to the LRs, and on non-VHE systems ensure that 24862306a36Sopenharmony_ci * the write to the VMCR in __vgic_v3_activate_traps(), will have 24962306a36Sopenharmony_ci * reached the (re)distributors. This ensure the guest will read the 25062306a36Sopenharmony_ci * correct values from the memory-mapped interface. 25162306a36Sopenharmony_ci */ 25262306a36Sopenharmony_ci if (used_lrs || !has_vhe()) { 25362306a36Sopenharmony_ci if (!cpu_if->vgic_sre) { 25462306a36Sopenharmony_ci isb(); 25562306a36Sopenharmony_ci dsb(sy); 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_civoid __vgic_v3_activate_traps(struct vgic_v3_cpu_if *cpu_if) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci /* 26362306a36Sopenharmony_ci * VFIQEn is RES1 if ICC_SRE_EL1.SRE is 1. This causes a 26462306a36Sopenharmony_ci * Group0 interrupt (as generated in GICv2 mode) to be 26562306a36Sopenharmony_ci * delivered as a FIQ to the guest, with potentially fatal 26662306a36Sopenharmony_ci * consequences. So we must make sure that ICC_SRE_EL1 has 26762306a36Sopenharmony_ci * been actually programmed with the value we want before 26862306a36Sopenharmony_ci * starting to mess with the rest of the GIC, and VMCR_EL2 in 26962306a36Sopenharmony_ci * particular. This logic must be called before 27062306a36Sopenharmony_ci * __vgic_v3_restore_state(). 27162306a36Sopenharmony_ci */ 27262306a36Sopenharmony_ci if (!cpu_if->vgic_sre) { 27362306a36Sopenharmony_ci write_gicreg(0, ICC_SRE_EL1); 27462306a36Sopenharmony_ci isb(); 27562306a36Sopenharmony_ci write_gicreg(cpu_if->vgic_vmcr, ICH_VMCR_EL2); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci if (has_vhe()) { 27962306a36Sopenharmony_ci /* 28062306a36Sopenharmony_ci * Ensure that the write to the VMCR will have reached 28162306a36Sopenharmony_ci * the (re)distributors. This ensure the guest will 28262306a36Sopenharmony_ci * read the correct values from the memory-mapped 28362306a36Sopenharmony_ci * interface. 28462306a36Sopenharmony_ci */ 28562306a36Sopenharmony_ci isb(); 28662306a36Sopenharmony_ci dsb(sy); 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci /* 29162306a36Sopenharmony_ci * Prevent the guest from touching the GIC system registers if 29262306a36Sopenharmony_ci * SRE isn't enabled for GICv3 emulation. 29362306a36Sopenharmony_ci */ 29462306a36Sopenharmony_ci write_gicreg(read_gicreg(ICC_SRE_EL2) & ~ICC_SRE_EL2_ENABLE, 29562306a36Sopenharmony_ci ICC_SRE_EL2); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci /* 29862306a36Sopenharmony_ci * If we need to trap system registers, we must write 29962306a36Sopenharmony_ci * ICH_HCR_EL2 anyway, even if no interrupts are being 30062306a36Sopenharmony_ci * injected, 30162306a36Sopenharmony_ci */ 30262306a36Sopenharmony_ci if (static_branch_unlikely(&vgic_v3_cpuif_trap) || 30362306a36Sopenharmony_ci cpu_if->its_vpe.its_vm) 30462306a36Sopenharmony_ci write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2); 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_civoid __vgic_v3_deactivate_traps(struct vgic_v3_cpu_if *cpu_if) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci u64 val; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci if (!cpu_if->vgic_sre) { 31262306a36Sopenharmony_ci cpu_if->vgic_vmcr = read_gicreg(ICH_VMCR_EL2); 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci val = read_gicreg(ICC_SRE_EL2); 31662306a36Sopenharmony_ci write_gicreg(val | ICC_SRE_EL2_ENABLE, ICC_SRE_EL2); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci if (!cpu_if->vgic_sre) { 31962306a36Sopenharmony_ci /* Make sure ENABLE is set at EL2 before setting SRE at EL1 */ 32062306a36Sopenharmony_ci isb(); 32162306a36Sopenharmony_ci write_gicreg(1, ICC_SRE_EL1); 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci /* 32562306a36Sopenharmony_ci * If we were trapping system registers, we enabled the VGIC even if 32662306a36Sopenharmony_ci * no interrupts were being injected, and we disable it again here. 32762306a36Sopenharmony_ci */ 32862306a36Sopenharmony_ci if (static_branch_unlikely(&vgic_v3_cpuif_trap) || 32962306a36Sopenharmony_ci cpu_if->its_vpe.its_vm) 33062306a36Sopenharmony_ci write_gicreg(0, ICH_HCR_EL2); 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_civoid __vgic_v3_save_aprs(struct vgic_v3_cpu_if *cpu_if) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci u64 val; 33662306a36Sopenharmony_ci u32 nr_pre_bits; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci val = read_gicreg(ICH_VTR_EL2); 33962306a36Sopenharmony_ci nr_pre_bits = vtr_to_nr_pre_bits(val); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci switch (nr_pre_bits) { 34262306a36Sopenharmony_ci case 7: 34362306a36Sopenharmony_ci cpu_if->vgic_ap0r[3] = __vgic_v3_read_ap0rn(3); 34462306a36Sopenharmony_ci cpu_if->vgic_ap0r[2] = __vgic_v3_read_ap0rn(2); 34562306a36Sopenharmony_ci fallthrough; 34662306a36Sopenharmony_ci case 6: 34762306a36Sopenharmony_ci cpu_if->vgic_ap0r[1] = __vgic_v3_read_ap0rn(1); 34862306a36Sopenharmony_ci fallthrough; 34962306a36Sopenharmony_ci default: 35062306a36Sopenharmony_ci cpu_if->vgic_ap0r[0] = __vgic_v3_read_ap0rn(0); 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci switch (nr_pre_bits) { 35462306a36Sopenharmony_ci case 7: 35562306a36Sopenharmony_ci cpu_if->vgic_ap1r[3] = __vgic_v3_read_ap1rn(3); 35662306a36Sopenharmony_ci cpu_if->vgic_ap1r[2] = __vgic_v3_read_ap1rn(2); 35762306a36Sopenharmony_ci fallthrough; 35862306a36Sopenharmony_ci case 6: 35962306a36Sopenharmony_ci cpu_if->vgic_ap1r[1] = __vgic_v3_read_ap1rn(1); 36062306a36Sopenharmony_ci fallthrough; 36162306a36Sopenharmony_ci default: 36262306a36Sopenharmony_ci cpu_if->vgic_ap1r[0] = __vgic_v3_read_ap1rn(0); 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci} 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_civoid __vgic_v3_restore_aprs(struct vgic_v3_cpu_if *cpu_if) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci u64 val; 36962306a36Sopenharmony_ci u32 nr_pre_bits; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci val = read_gicreg(ICH_VTR_EL2); 37262306a36Sopenharmony_ci nr_pre_bits = vtr_to_nr_pre_bits(val); 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci switch (nr_pre_bits) { 37562306a36Sopenharmony_ci case 7: 37662306a36Sopenharmony_ci __vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[3], 3); 37762306a36Sopenharmony_ci __vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[2], 2); 37862306a36Sopenharmony_ci fallthrough; 37962306a36Sopenharmony_ci case 6: 38062306a36Sopenharmony_ci __vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[1], 1); 38162306a36Sopenharmony_ci fallthrough; 38262306a36Sopenharmony_ci default: 38362306a36Sopenharmony_ci __vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[0], 0); 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci switch (nr_pre_bits) { 38762306a36Sopenharmony_ci case 7: 38862306a36Sopenharmony_ci __vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[3], 3); 38962306a36Sopenharmony_ci __vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[2], 2); 39062306a36Sopenharmony_ci fallthrough; 39162306a36Sopenharmony_ci case 6: 39262306a36Sopenharmony_ci __vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[1], 1); 39362306a36Sopenharmony_ci fallthrough; 39462306a36Sopenharmony_ci default: 39562306a36Sopenharmony_ci __vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[0], 0); 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci} 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_civoid __vgic_v3_init_lrs(void) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci int max_lr_idx = vtr_to_max_lr_idx(read_gicreg(ICH_VTR_EL2)); 40262306a36Sopenharmony_ci int i; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci for (i = 0; i <= max_lr_idx; i++) 40562306a36Sopenharmony_ci __gic_v3_set_lr(0, i); 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci/* 40962306a36Sopenharmony_ci * Return the GIC CPU configuration: 41062306a36Sopenharmony_ci * - [31:0] ICH_VTR_EL2 41162306a36Sopenharmony_ci * - [62:32] RES0 41262306a36Sopenharmony_ci * - [63] MMIO (GICv2) capable 41362306a36Sopenharmony_ci */ 41462306a36Sopenharmony_ciu64 __vgic_v3_get_gic_config(void) 41562306a36Sopenharmony_ci{ 41662306a36Sopenharmony_ci u64 val, sre = read_gicreg(ICC_SRE_EL1); 41762306a36Sopenharmony_ci unsigned long flags = 0; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci /* 42062306a36Sopenharmony_ci * To check whether we have a MMIO-based (GICv2 compatible) 42162306a36Sopenharmony_ci * CPU interface, we need to disable the system register 42262306a36Sopenharmony_ci * view. To do that safely, we have to prevent any interrupt 42362306a36Sopenharmony_ci * from firing (which would be deadly). 42462306a36Sopenharmony_ci * 42562306a36Sopenharmony_ci * Note that this only makes sense on VHE, as interrupts are 42662306a36Sopenharmony_ci * already masked for nVHE as part of the exception entry to 42762306a36Sopenharmony_ci * EL2. 42862306a36Sopenharmony_ci */ 42962306a36Sopenharmony_ci if (has_vhe()) 43062306a36Sopenharmony_ci flags = local_daif_save(); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci /* 43362306a36Sopenharmony_ci * Table 11-2 "Permitted ICC_SRE_ELx.SRE settings" indicates 43462306a36Sopenharmony_ci * that to be able to set ICC_SRE_EL1.SRE to 0, all the 43562306a36Sopenharmony_ci * interrupt overrides must be set. You've got to love this. 43662306a36Sopenharmony_ci */ 43762306a36Sopenharmony_ci sysreg_clear_set(hcr_el2, 0, HCR_AMO | HCR_FMO | HCR_IMO); 43862306a36Sopenharmony_ci isb(); 43962306a36Sopenharmony_ci write_gicreg(0, ICC_SRE_EL1); 44062306a36Sopenharmony_ci isb(); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci val = read_gicreg(ICC_SRE_EL1); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci write_gicreg(sre, ICC_SRE_EL1); 44562306a36Sopenharmony_ci isb(); 44662306a36Sopenharmony_ci sysreg_clear_set(hcr_el2, HCR_AMO | HCR_FMO | HCR_IMO, 0); 44762306a36Sopenharmony_ci isb(); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci if (has_vhe()) 45062306a36Sopenharmony_ci local_daif_restore(flags); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci val = (val & ICC_SRE_EL1_SRE) ? 0 : (1ULL << 63); 45362306a36Sopenharmony_ci val |= read_gicreg(ICH_VTR_EL2); 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci return val; 45662306a36Sopenharmony_ci} 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ciu64 __vgic_v3_read_vmcr(void) 45962306a36Sopenharmony_ci{ 46062306a36Sopenharmony_ci return read_gicreg(ICH_VMCR_EL2); 46162306a36Sopenharmony_ci} 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_civoid __vgic_v3_write_vmcr(u32 vmcr) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci write_gicreg(vmcr, ICH_VMCR_EL2); 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_cistatic int __vgic_v3_bpr_min(void) 46962306a36Sopenharmony_ci{ 47062306a36Sopenharmony_ci /* See Pseudocode for VPriorityGroup */ 47162306a36Sopenharmony_ci return 8 - vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2)); 47262306a36Sopenharmony_ci} 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_cistatic int __vgic_v3_get_group(struct kvm_vcpu *vcpu) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci u64 esr = kvm_vcpu_get_esr(vcpu); 47762306a36Sopenharmony_ci u8 crm = (esr & ESR_ELx_SYS64_ISS_CRM_MASK) >> ESR_ELx_SYS64_ISS_CRM_SHIFT; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci return crm != 8; 48062306a36Sopenharmony_ci} 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci#define GICv3_IDLE_PRIORITY 0xff 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_cistatic int __vgic_v3_highest_priority_lr(struct kvm_vcpu *vcpu, u32 vmcr, 48562306a36Sopenharmony_ci u64 *lr_val) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci unsigned int used_lrs = vcpu->arch.vgic_cpu.vgic_v3.used_lrs; 48862306a36Sopenharmony_ci u8 priority = GICv3_IDLE_PRIORITY; 48962306a36Sopenharmony_ci int i, lr = -1; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci for (i = 0; i < used_lrs; i++) { 49262306a36Sopenharmony_ci u64 val = __gic_v3_get_lr(i); 49362306a36Sopenharmony_ci u8 lr_prio = (val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci /* Not pending in the state? */ 49662306a36Sopenharmony_ci if ((val & ICH_LR_STATE) != ICH_LR_PENDING_BIT) 49762306a36Sopenharmony_ci continue; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci /* Group-0 interrupt, but Group-0 disabled? */ 50062306a36Sopenharmony_ci if (!(val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG0_MASK)) 50162306a36Sopenharmony_ci continue; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci /* Group-1 interrupt, but Group-1 disabled? */ 50462306a36Sopenharmony_ci if ((val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG1_MASK)) 50562306a36Sopenharmony_ci continue; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci /* Not the highest priority? */ 50862306a36Sopenharmony_ci if (lr_prio >= priority) 50962306a36Sopenharmony_ci continue; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci /* This is a candidate */ 51262306a36Sopenharmony_ci priority = lr_prio; 51362306a36Sopenharmony_ci *lr_val = val; 51462306a36Sopenharmony_ci lr = i; 51562306a36Sopenharmony_ci } 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci if (lr == -1) 51862306a36Sopenharmony_ci *lr_val = ICC_IAR1_EL1_SPURIOUS; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci return lr; 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_cistatic int __vgic_v3_find_active_lr(struct kvm_vcpu *vcpu, int intid, 52462306a36Sopenharmony_ci u64 *lr_val) 52562306a36Sopenharmony_ci{ 52662306a36Sopenharmony_ci unsigned int used_lrs = vcpu->arch.vgic_cpu.vgic_v3.used_lrs; 52762306a36Sopenharmony_ci int i; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci for (i = 0; i < used_lrs; i++) { 53062306a36Sopenharmony_ci u64 val = __gic_v3_get_lr(i); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci if ((val & ICH_LR_VIRTUAL_ID_MASK) == intid && 53362306a36Sopenharmony_ci (val & ICH_LR_ACTIVE_BIT)) { 53462306a36Sopenharmony_ci *lr_val = val; 53562306a36Sopenharmony_ci return i; 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci } 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci *lr_val = ICC_IAR1_EL1_SPURIOUS; 54062306a36Sopenharmony_ci return -1; 54162306a36Sopenharmony_ci} 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_cistatic int __vgic_v3_get_highest_active_priority(void) 54462306a36Sopenharmony_ci{ 54562306a36Sopenharmony_ci u8 nr_apr_regs = vtr_to_nr_apr_regs(read_gicreg(ICH_VTR_EL2)); 54662306a36Sopenharmony_ci u32 hap = 0; 54762306a36Sopenharmony_ci int i; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci for (i = 0; i < nr_apr_regs; i++) { 55062306a36Sopenharmony_ci u32 val; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci /* 55362306a36Sopenharmony_ci * The ICH_AP0Rn_EL2 and ICH_AP1Rn_EL2 registers 55462306a36Sopenharmony_ci * contain the active priority levels for this VCPU 55562306a36Sopenharmony_ci * for the maximum number of supported priority 55662306a36Sopenharmony_ci * levels, and we return the full priority level only 55762306a36Sopenharmony_ci * if the BPR is programmed to its minimum, otherwise 55862306a36Sopenharmony_ci * we return a combination of the priority level and 55962306a36Sopenharmony_ci * subpriority, as determined by the setting of the 56062306a36Sopenharmony_ci * BPR, but without the full subpriority. 56162306a36Sopenharmony_ci */ 56262306a36Sopenharmony_ci val = __vgic_v3_read_ap0rn(i); 56362306a36Sopenharmony_ci val |= __vgic_v3_read_ap1rn(i); 56462306a36Sopenharmony_ci if (!val) { 56562306a36Sopenharmony_ci hap += 32; 56662306a36Sopenharmony_ci continue; 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci return (hap + __ffs(val)) << __vgic_v3_bpr_min(); 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci return GICv3_IDLE_PRIORITY; 57362306a36Sopenharmony_ci} 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_cistatic unsigned int __vgic_v3_get_bpr0(u32 vmcr) 57662306a36Sopenharmony_ci{ 57762306a36Sopenharmony_ci return (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT; 57862306a36Sopenharmony_ci} 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_cistatic unsigned int __vgic_v3_get_bpr1(u32 vmcr) 58162306a36Sopenharmony_ci{ 58262306a36Sopenharmony_ci unsigned int bpr; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci if (vmcr & ICH_VMCR_CBPR_MASK) { 58562306a36Sopenharmony_ci bpr = __vgic_v3_get_bpr0(vmcr); 58662306a36Sopenharmony_ci if (bpr < 7) 58762306a36Sopenharmony_ci bpr++; 58862306a36Sopenharmony_ci } else { 58962306a36Sopenharmony_ci bpr = (vmcr & ICH_VMCR_BPR1_MASK) >> ICH_VMCR_BPR1_SHIFT; 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci return bpr; 59362306a36Sopenharmony_ci} 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci/* 59662306a36Sopenharmony_ci * Convert a priority to a preemption level, taking the relevant BPR 59762306a36Sopenharmony_ci * into account by zeroing the sub-priority bits. 59862306a36Sopenharmony_ci */ 59962306a36Sopenharmony_cistatic u8 __vgic_v3_pri_to_pre(u8 pri, u32 vmcr, int grp) 60062306a36Sopenharmony_ci{ 60162306a36Sopenharmony_ci unsigned int bpr; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci if (!grp) 60462306a36Sopenharmony_ci bpr = __vgic_v3_get_bpr0(vmcr) + 1; 60562306a36Sopenharmony_ci else 60662306a36Sopenharmony_ci bpr = __vgic_v3_get_bpr1(vmcr); 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci return pri & (GENMASK(7, 0) << bpr); 60962306a36Sopenharmony_ci} 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci/* 61262306a36Sopenharmony_ci * The priority value is independent of any of the BPR values, so we 61362306a36Sopenharmony_ci * normalize it using the minimal BPR value. This guarantees that no 61462306a36Sopenharmony_ci * matter what the guest does with its BPR, we can always set/get the 61562306a36Sopenharmony_ci * same value of a priority. 61662306a36Sopenharmony_ci */ 61762306a36Sopenharmony_cistatic void __vgic_v3_set_active_priority(u8 pri, u32 vmcr, int grp) 61862306a36Sopenharmony_ci{ 61962306a36Sopenharmony_ci u8 pre, ap; 62062306a36Sopenharmony_ci u32 val; 62162306a36Sopenharmony_ci int apr; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci pre = __vgic_v3_pri_to_pre(pri, vmcr, grp); 62462306a36Sopenharmony_ci ap = pre >> __vgic_v3_bpr_min(); 62562306a36Sopenharmony_ci apr = ap / 32; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci if (!grp) { 62862306a36Sopenharmony_ci val = __vgic_v3_read_ap0rn(apr); 62962306a36Sopenharmony_ci __vgic_v3_write_ap0rn(val | BIT(ap % 32), apr); 63062306a36Sopenharmony_ci } else { 63162306a36Sopenharmony_ci val = __vgic_v3_read_ap1rn(apr); 63262306a36Sopenharmony_ci __vgic_v3_write_ap1rn(val | BIT(ap % 32), apr); 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci} 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_cistatic int __vgic_v3_clear_highest_active_priority(void) 63762306a36Sopenharmony_ci{ 63862306a36Sopenharmony_ci u8 nr_apr_regs = vtr_to_nr_apr_regs(read_gicreg(ICH_VTR_EL2)); 63962306a36Sopenharmony_ci u32 hap = 0; 64062306a36Sopenharmony_ci int i; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci for (i = 0; i < nr_apr_regs; i++) { 64362306a36Sopenharmony_ci u32 ap0, ap1; 64462306a36Sopenharmony_ci int c0, c1; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci ap0 = __vgic_v3_read_ap0rn(i); 64762306a36Sopenharmony_ci ap1 = __vgic_v3_read_ap1rn(i); 64862306a36Sopenharmony_ci if (!ap0 && !ap1) { 64962306a36Sopenharmony_ci hap += 32; 65062306a36Sopenharmony_ci continue; 65162306a36Sopenharmony_ci } 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci c0 = ap0 ? __ffs(ap0) : 32; 65462306a36Sopenharmony_ci c1 = ap1 ? __ffs(ap1) : 32; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci /* Always clear the LSB, which is the highest priority */ 65762306a36Sopenharmony_ci if (c0 < c1) { 65862306a36Sopenharmony_ci ap0 &= ~BIT(c0); 65962306a36Sopenharmony_ci __vgic_v3_write_ap0rn(ap0, i); 66062306a36Sopenharmony_ci hap += c0; 66162306a36Sopenharmony_ci } else { 66262306a36Sopenharmony_ci ap1 &= ~BIT(c1); 66362306a36Sopenharmony_ci __vgic_v3_write_ap1rn(ap1, i); 66462306a36Sopenharmony_ci hap += c1; 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci /* Rescale to 8 bits of priority */ 66862306a36Sopenharmony_ci return hap << __vgic_v3_bpr_min(); 66962306a36Sopenharmony_ci } 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci return GICv3_IDLE_PRIORITY; 67262306a36Sopenharmony_ci} 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_cistatic void __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 67562306a36Sopenharmony_ci{ 67662306a36Sopenharmony_ci u64 lr_val; 67762306a36Sopenharmony_ci u8 lr_prio, pmr; 67862306a36Sopenharmony_ci int lr, grp; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci grp = __vgic_v3_get_group(vcpu); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci lr = __vgic_v3_highest_priority_lr(vcpu, vmcr, &lr_val); 68362306a36Sopenharmony_ci if (lr < 0) 68462306a36Sopenharmony_ci goto spurious; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci if (grp != !!(lr_val & ICH_LR_GROUP)) 68762306a36Sopenharmony_ci goto spurious; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci pmr = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT; 69062306a36Sopenharmony_ci lr_prio = (lr_val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT; 69162306a36Sopenharmony_ci if (pmr <= lr_prio) 69262306a36Sopenharmony_ci goto spurious; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci if (__vgic_v3_get_highest_active_priority() <= __vgic_v3_pri_to_pre(lr_prio, vmcr, grp)) 69562306a36Sopenharmony_ci goto spurious; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci lr_val &= ~ICH_LR_STATE; 69862306a36Sopenharmony_ci lr_val |= ICH_LR_ACTIVE_BIT; 69962306a36Sopenharmony_ci __gic_v3_set_lr(lr_val, lr); 70062306a36Sopenharmony_ci __vgic_v3_set_active_priority(lr_prio, vmcr, grp); 70162306a36Sopenharmony_ci vcpu_set_reg(vcpu, rt, lr_val & ICH_LR_VIRTUAL_ID_MASK); 70262306a36Sopenharmony_ci return; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_cispurious: 70562306a36Sopenharmony_ci vcpu_set_reg(vcpu, rt, ICC_IAR1_EL1_SPURIOUS); 70662306a36Sopenharmony_ci} 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_cistatic void __vgic_v3_clear_active_lr(int lr, u64 lr_val) 70962306a36Sopenharmony_ci{ 71062306a36Sopenharmony_ci lr_val &= ~ICH_LR_ACTIVE_BIT; 71162306a36Sopenharmony_ci if (lr_val & ICH_LR_HW) { 71262306a36Sopenharmony_ci u32 pid; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci pid = (lr_val & ICH_LR_PHYS_ID_MASK) >> ICH_LR_PHYS_ID_SHIFT; 71562306a36Sopenharmony_ci gic_write_dir(pid); 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci __gic_v3_set_lr(lr_val, lr); 71962306a36Sopenharmony_ci} 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_cistatic void __vgic_v3_bump_eoicount(void) 72262306a36Sopenharmony_ci{ 72362306a36Sopenharmony_ci u32 hcr; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci hcr = read_gicreg(ICH_HCR_EL2); 72662306a36Sopenharmony_ci hcr += 1 << ICH_HCR_EOIcount_SHIFT; 72762306a36Sopenharmony_ci write_gicreg(hcr, ICH_HCR_EL2); 72862306a36Sopenharmony_ci} 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_cistatic void __vgic_v3_write_dir(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 73162306a36Sopenharmony_ci{ 73262306a36Sopenharmony_ci u32 vid = vcpu_get_reg(vcpu, rt); 73362306a36Sopenharmony_ci u64 lr_val; 73462306a36Sopenharmony_ci int lr; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci /* EOImode == 0, nothing to be done here */ 73762306a36Sopenharmony_ci if (!(vmcr & ICH_VMCR_EOIM_MASK)) 73862306a36Sopenharmony_ci return; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci /* No deactivate to be performed on an LPI */ 74162306a36Sopenharmony_ci if (vid >= VGIC_MIN_LPI) 74262306a36Sopenharmony_ci return; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci lr = __vgic_v3_find_active_lr(vcpu, vid, &lr_val); 74562306a36Sopenharmony_ci if (lr == -1) { 74662306a36Sopenharmony_ci __vgic_v3_bump_eoicount(); 74762306a36Sopenharmony_ci return; 74862306a36Sopenharmony_ci } 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci __vgic_v3_clear_active_lr(lr, lr_val); 75162306a36Sopenharmony_ci} 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_cistatic void __vgic_v3_write_eoir(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 75462306a36Sopenharmony_ci{ 75562306a36Sopenharmony_ci u32 vid = vcpu_get_reg(vcpu, rt); 75662306a36Sopenharmony_ci u64 lr_val; 75762306a36Sopenharmony_ci u8 lr_prio, act_prio; 75862306a36Sopenharmony_ci int lr, grp; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci grp = __vgic_v3_get_group(vcpu); 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci /* Drop priority in any case */ 76362306a36Sopenharmony_ci act_prio = __vgic_v3_clear_highest_active_priority(); 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci lr = __vgic_v3_find_active_lr(vcpu, vid, &lr_val); 76662306a36Sopenharmony_ci if (lr == -1) { 76762306a36Sopenharmony_ci /* Do not bump EOIcount for LPIs that aren't in the LRs */ 76862306a36Sopenharmony_ci if (!(vid >= VGIC_MIN_LPI)) 76962306a36Sopenharmony_ci __vgic_v3_bump_eoicount(); 77062306a36Sopenharmony_ci return; 77162306a36Sopenharmony_ci } 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci /* EOImode == 1 and not an LPI, nothing to be done here */ 77462306a36Sopenharmony_ci if ((vmcr & ICH_VMCR_EOIM_MASK) && !(vid >= VGIC_MIN_LPI)) 77562306a36Sopenharmony_ci return; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci lr_prio = (lr_val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci /* If priorities or group do not match, the guest has fscked-up. */ 78062306a36Sopenharmony_ci if (grp != !!(lr_val & ICH_LR_GROUP) || 78162306a36Sopenharmony_ci __vgic_v3_pri_to_pre(lr_prio, vmcr, grp) != act_prio) 78262306a36Sopenharmony_ci return; 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci /* Let's now perform the deactivation */ 78562306a36Sopenharmony_ci __vgic_v3_clear_active_lr(lr, lr_val); 78662306a36Sopenharmony_ci} 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_cistatic void __vgic_v3_read_igrpen0(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 78962306a36Sopenharmony_ci{ 79062306a36Sopenharmony_ci vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG0_MASK)); 79162306a36Sopenharmony_ci} 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_cistatic void __vgic_v3_read_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 79462306a36Sopenharmony_ci{ 79562306a36Sopenharmony_ci vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG1_MASK)); 79662306a36Sopenharmony_ci} 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_cistatic void __vgic_v3_write_igrpen0(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 79962306a36Sopenharmony_ci{ 80062306a36Sopenharmony_ci u64 val = vcpu_get_reg(vcpu, rt); 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci if (val & 1) 80362306a36Sopenharmony_ci vmcr |= ICH_VMCR_ENG0_MASK; 80462306a36Sopenharmony_ci else 80562306a36Sopenharmony_ci vmcr &= ~ICH_VMCR_ENG0_MASK; 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci __vgic_v3_write_vmcr(vmcr); 80862306a36Sopenharmony_ci} 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_cistatic void __vgic_v3_write_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 81162306a36Sopenharmony_ci{ 81262306a36Sopenharmony_ci u64 val = vcpu_get_reg(vcpu, rt); 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci if (val & 1) 81562306a36Sopenharmony_ci vmcr |= ICH_VMCR_ENG1_MASK; 81662306a36Sopenharmony_ci else 81762306a36Sopenharmony_ci vmcr &= ~ICH_VMCR_ENG1_MASK; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci __vgic_v3_write_vmcr(vmcr); 82062306a36Sopenharmony_ci} 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_cistatic void __vgic_v3_read_bpr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 82362306a36Sopenharmony_ci{ 82462306a36Sopenharmony_ci vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr0(vmcr)); 82562306a36Sopenharmony_ci} 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_cistatic void __vgic_v3_read_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 82862306a36Sopenharmony_ci{ 82962306a36Sopenharmony_ci vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr1(vmcr)); 83062306a36Sopenharmony_ci} 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_cistatic void __vgic_v3_write_bpr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 83362306a36Sopenharmony_ci{ 83462306a36Sopenharmony_ci u64 val = vcpu_get_reg(vcpu, rt); 83562306a36Sopenharmony_ci u8 bpr_min = __vgic_v3_bpr_min() - 1; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci /* Enforce BPR limiting */ 83862306a36Sopenharmony_ci if (val < bpr_min) 83962306a36Sopenharmony_ci val = bpr_min; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci val <<= ICH_VMCR_BPR0_SHIFT; 84262306a36Sopenharmony_ci val &= ICH_VMCR_BPR0_MASK; 84362306a36Sopenharmony_ci vmcr &= ~ICH_VMCR_BPR0_MASK; 84462306a36Sopenharmony_ci vmcr |= val; 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci __vgic_v3_write_vmcr(vmcr); 84762306a36Sopenharmony_ci} 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_cistatic void __vgic_v3_write_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 85062306a36Sopenharmony_ci{ 85162306a36Sopenharmony_ci u64 val = vcpu_get_reg(vcpu, rt); 85262306a36Sopenharmony_ci u8 bpr_min = __vgic_v3_bpr_min(); 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci if (vmcr & ICH_VMCR_CBPR_MASK) 85562306a36Sopenharmony_ci return; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci /* Enforce BPR limiting */ 85862306a36Sopenharmony_ci if (val < bpr_min) 85962306a36Sopenharmony_ci val = bpr_min; 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci val <<= ICH_VMCR_BPR1_SHIFT; 86262306a36Sopenharmony_ci val &= ICH_VMCR_BPR1_MASK; 86362306a36Sopenharmony_ci vmcr &= ~ICH_VMCR_BPR1_MASK; 86462306a36Sopenharmony_ci vmcr |= val; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci __vgic_v3_write_vmcr(vmcr); 86762306a36Sopenharmony_ci} 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_cistatic void __vgic_v3_read_apxrn(struct kvm_vcpu *vcpu, int rt, int n) 87062306a36Sopenharmony_ci{ 87162306a36Sopenharmony_ci u32 val; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci if (!__vgic_v3_get_group(vcpu)) 87462306a36Sopenharmony_ci val = __vgic_v3_read_ap0rn(n); 87562306a36Sopenharmony_ci else 87662306a36Sopenharmony_ci val = __vgic_v3_read_ap1rn(n); 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci vcpu_set_reg(vcpu, rt, val); 87962306a36Sopenharmony_ci} 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_cistatic void __vgic_v3_write_apxrn(struct kvm_vcpu *vcpu, int rt, int n) 88262306a36Sopenharmony_ci{ 88362306a36Sopenharmony_ci u32 val = vcpu_get_reg(vcpu, rt); 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci if (!__vgic_v3_get_group(vcpu)) 88662306a36Sopenharmony_ci __vgic_v3_write_ap0rn(val, n); 88762306a36Sopenharmony_ci else 88862306a36Sopenharmony_ci __vgic_v3_write_ap1rn(val, n); 88962306a36Sopenharmony_ci} 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_cistatic void __vgic_v3_read_apxr0(struct kvm_vcpu *vcpu, 89262306a36Sopenharmony_ci u32 vmcr, int rt) 89362306a36Sopenharmony_ci{ 89462306a36Sopenharmony_ci __vgic_v3_read_apxrn(vcpu, rt, 0); 89562306a36Sopenharmony_ci} 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_cistatic void __vgic_v3_read_apxr1(struct kvm_vcpu *vcpu, 89862306a36Sopenharmony_ci u32 vmcr, int rt) 89962306a36Sopenharmony_ci{ 90062306a36Sopenharmony_ci __vgic_v3_read_apxrn(vcpu, rt, 1); 90162306a36Sopenharmony_ci} 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_cistatic void __vgic_v3_read_apxr2(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 90462306a36Sopenharmony_ci{ 90562306a36Sopenharmony_ci __vgic_v3_read_apxrn(vcpu, rt, 2); 90662306a36Sopenharmony_ci} 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_cistatic void __vgic_v3_read_apxr3(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 90962306a36Sopenharmony_ci{ 91062306a36Sopenharmony_ci __vgic_v3_read_apxrn(vcpu, rt, 3); 91162306a36Sopenharmony_ci} 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_cistatic void __vgic_v3_write_apxr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 91462306a36Sopenharmony_ci{ 91562306a36Sopenharmony_ci __vgic_v3_write_apxrn(vcpu, rt, 0); 91662306a36Sopenharmony_ci} 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_cistatic void __vgic_v3_write_apxr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 91962306a36Sopenharmony_ci{ 92062306a36Sopenharmony_ci __vgic_v3_write_apxrn(vcpu, rt, 1); 92162306a36Sopenharmony_ci} 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_cistatic void __vgic_v3_write_apxr2(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 92462306a36Sopenharmony_ci{ 92562306a36Sopenharmony_ci __vgic_v3_write_apxrn(vcpu, rt, 2); 92662306a36Sopenharmony_ci} 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_cistatic void __vgic_v3_write_apxr3(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 92962306a36Sopenharmony_ci{ 93062306a36Sopenharmony_ci __vgic_v3_write_apxrn(vcpu, rt, 3); 93162306a36Sopenharmony_ci} 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_cistatic void __vgic_v3_read_hppir(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 93462306a36Sopenharmony_ci{ 93562306a36Sopenharmony_ci u64 lr_val; 93662306a36Sopenharmony_ci int lr, lr_grp, grp; 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci grp = __vgic_v3_get_group(vcpu); 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci lr = __vgic_v3_highest_priority_lr(vcpu, vmcr, &lr_val); 94162306a36Sopenharmony_ci if (lr == -1) 94262306a36Sopenharmony_ci goto spurious; 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci lr_grp = !!(lr_val & ICH_LR_GROUP); 94562306a36Sopenharmony_ci if (lr_grp != grp) 94662306a36Sopenharmony_ci lr_val = ICC_IAR1_EL1_SPURIOUS; 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_cispurious: 94962306a36Sopenharmony_ci vcpu_set_reg(vcpu, rt, lr_val & ICH_LR_VIRTUAL_ID_MASK); 95062306a36Sopenharmony_ci} 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_cistatic void __vgic_v3_read_pmr(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 95362306a36Sopenharmony_ci{ 95462306a36Sopenharmony_ci vmcr &= ICH_VMCR_PMR_MASK; 95562306a36Sopenharmony_ci vmcr >>= ICH_VMCR_PMR_SHIFT; 95662306a36Sopenharmony_ci vcpu_set_reg(vcpu, rt, vmcr); 95762306a36Sopenharmony_ci} 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_cistatic void __vgic_v3_write_pmr(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 96062306a36Sopenharmony_ci{ 96162306a36Sopenharmony_ci u32 val = vcpu_get_reg(vcpu, rt); 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci val <<= ICH_VMCR_PMR_SHIFT; 96462306a36Sopenharmony_ci val &= ICH_VMCR_PMR_MASK; 96562306a36Sopenharmony_ci vmcr &= ~ICH_VMCR_PMR_MASK; 96662306a36Sopenharmony_ci vmcr |= val; 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci write_gicreg(vmcr, ICH_VMCR_EL2); 96962306a36Sopenharmony_ci} 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_cistatic void __vgic_v3_read_rpr(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 97262306a36Sopenharmony_ci{ 97362306a36Sopenharmony_ci u32 val = __vgic_v3_get_highest_active_priority(); 97462306a36Sopenharmony_ci vcpu_set_reg(vcpu, rt, val); 97562306a36Sopenharmony_ci} 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_cistatic void __vgic_v3_read_ctlr(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 97862306a36Sopenharmony_ci{ 97962306a36Sopenharmony_ci u32 vtr, val; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci vtr = read_gicreg(ICH_VTR_EL2); 98262306a36Sopenharmony_ci /* PRIbits */ 98362306a36Sopenharmony_ci val = ((vtr >> 29) & 7) << ICC_CTLR_EL1_PRI_BITS_SHIFT; 98462306a36Sopenharmony_ci /* IDbits */ 98562306a36Sopenharmony_ci val |= ((vtr >> 23) & 7) << ICC_CTLR_EL1_ID_BITS_SHIFT; 98662306a36Sopenharmony_ci /* SEIS */ 98762306a36Sopenharmony_ci if (kvm_vgic_global_state.ich_vtr_el2 & ICH_VTR_SEIS_MASK) 98862306a36Sopenharmony_ci val |= BIT(ICC_CTLR_EL1_SEIS_SHIFT); 98962306a36Sopenharmony_ci /* A3V */ 99062306a36Sopenharmony_ci val |= ((vtr >> 21) & 1) << ICC_CTLR_EL1_A3V_SHIFT; 99162306a36Sopenharmony_ci /* EOImode */ 99262306a36Sopenharmony_ci val |= ((vmcr & ICH_VMCR_EOIM_MASK) >> ICH_VMCR_EOIM_SHIFT) << ICC_CTLR_EL1_EOImode_SHIFT; 99362306a36Sopenharmony_ci /* CBPR */ 99462306a36Sopenharmony_ci val |= (vmcr & ICH_VMCR_CBPR_MASK) >> ICH_VMCR_CBPR_SHIFT; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci vcpu_set_reg(vcpu, rt, val); 99762306a36Sopenharmony_ci} 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_cistatic void __vgic_v3_write_ctlr(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 100062306a36Sopenharmony_ci{ 100162306a36Sopenharmony_ci u32 val = vcpu_get_reg(vcpu, rt); 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci if (val & ICC_CTLR_EL1_CBPR_MASK) 100462306a36Sopenharmony_ci vmcr |= ICH_VMCR_CBPR_MASK; 100562306a36Sopenharmony_ci else 100662306a36Sopenharmony_ci vmcr &= ~ICH_VMCR_CBPR_MASK; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci if (val & ICC_CTLR_EL1_EOImode_MASK) 100962306a36Sopenharmony_ci vmcr |= ICH_VMCR_EOIM_MASK; 101062306a36Sopenharmony_ci else 101162306a36Sopenharmony_ci vmcr &= ~ICH_VMCR_EOIM_MASK; 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci write_gicreg(vmcr, ICH_VMCR_EL2); 101462306a36Sopenharmony_ci} 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ciint __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu) 101762306a36Sopenharmony_ci{ 101862306a36Sopenharmony_ci int rt; 101962306a36Sopenharmony_ci u64 esr; 102062306a36Sopenharmony_ci u32 vmcr; 102162306a36Sopenharmony_ci void (*fn)(struct kvm_vcpu *, u32, int); 102262306a36Sopenharmony_ci bool is_read; 102362306a36Sopenharmony_ci u32 sysreg; 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci esr = kvm_vcpu_get_esr(vcpu); 102662306a36Sopenharmony_ci if (vcpu_mode_is_32bit(vcpu)) { 102762306a36Sopenharmony_ci if (!kvm_condition_valid(vcpu)) { 102862306a36Sopenharmony_ci __kvm_skip_instr(vcpu); 102962306a36Sopenharmony_ci return 1; 103062306a36Sopenharmony_ci } 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci sysreg = esr_cp15_to_sysreg(esr); 103362306a36Sopenharmony_ci } else { 103462306a36Sopenharmony_ci sysreg = esr_sys64_to_sysreg(esr); 103562306a36Sopenharmony_ci } 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ; 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci switch (sysreg) { 104062306a36Sopenharmony_ci case SYS_ICC_IAR0_EL1: 104162306a36Sopenharmony_ci case SYS_ICC_IAR1_EL1: 104262306a36Sopenharmony_ci if (unlikely(!is_read)) 104362306a36Sopenharmony_ci return 0; 104462306a36Sopenharmony_ci fn = __vgic_v3_read_iar; 104562306a36Sopenharmony_ci break; 104662306a36Sopenharmony_ci case SYS_ICC_EOIR0_EL1: 104762306a36Sopenharmony_ci case SYS_ICC_EOIR1_EL1: 104862306a36Sopenharmony_ci if (unlikely(is_read)) 104962306a36Sopenharmony_ci return 0; 105062306a36Sopenharmony_ci fn = __vgic_v3_write_eoir; 105162306a36Sopenharmony_ci break; 105262306a36Sopenharmony_ci case SYS_ICC_IGRPEN1_EL1: 105362306a36Sopenharmony_ci if (is_read) 105462306a36Sopenharmony_ci fn = __vgic_v3_read_igrpen1; 105562306a36Sopenharmony_ci else 105662306a36Sopenharmony_ci fn = __vgic_v3_write_igrpen1; 105762306a36Sopenharmony_ci break; 105862306a36Sopenharmony_ci case SYS_ICC_BPR1_EL1: 105962306a36Sopenharmony_ci if (is_read) 106062306a36Sopenharmony_ci fn = __vgic_v3_read_bpr1; 106162306a36Sopenharmony_ci else 106262306a36Sopenharmony_ci fn = __vgic_v3_write_bpr1; 106362306a36Sopenharmony_ci break; 106462306a36Sopenharmony_ci case SYS_ICC_AP0Rn_EL1(0): 106562306a36Sopenharmony_ci case SYS_ICC_AP1Rn_EL1(0): 106662306a36Sopenharmony_ci if (is_read) 106762306a36Sopenharmony_ci fn = __vgic_v3_read_apxr0; 106862306a36Sopenharmony_ci else 106962306a36Sopenharmony_ci fn = __vgic_v3_write_apxr0; 107062306a36Sopenharmony_ci break; 107162306a36Sopenharmony_ci case SYS_ICC_AP0Rn_EL1(1): 107262306a36Sopenharmony_ci case SYS_ICC_AP1Rn_EL1(1): 107362306a36Sopenharmony_ci if (is_read) 107462306a36Sopenharmony_ci fn = __vgic_v3_read_apxr1; 107562306a36Sopenharmony_ci else 107662306a36Sopenharmony_ci fn = __vgic_v3_write_apxr1; 107762306a36Sopenharmony_ci break; 107862306a36Sopenharmony_ci case SYS_ICC_AP0Rn_EL1(2): 107962306a36Sopenharmony_ci case SYS_ICC_AP1Rn_EL1(2): 108062306a36Sopenharmony_ci if (is_read) 108162306a36Sopenharmony_ci fn = __vgic_v3_read_apxr2; 108262306a36Sopenharmony_ci else 108362306a36Sopenharmony_ci fn = __vgic_v3_write_apxr2; 108462306a36Sopenharmony_ci break; 108562306a36Sopenharmony_ci case SYS_ICC_AP0Rn_EL1(3): 108662306a36Sopenharmony_ci case SYS_ICC_AP1Rn_EL1(3): 108762306a36Sopenharmony_ci if (is_read) 108862306a36Sopenharmony_ci fn = __vgic_v3_read_apxr3; 108962306a36Sopenharmony_ci else 109062306a36Sopenharmony_ci fn = __vgic_v3_write_apxr3; 109162306a36Sopenharmony_ci break; 109262306a36Sopenharmony_ci case SYS_ICC_HPPIR0_EL1: 109362306a36Sopenharmony_ci case SYS_ICC_HPPIR1_EL1: 109462306a36Sopenharmony_ci if (unlikely(!is_read)) 109562306a36Sopenharmony_ci return 0; 109662306a36Sopenharmony_ci fn = __vgic_v3_read_hppir; 109762306a36Sopenharmony_ci break; 109862306a36Sopenharmony_ci case SYS_ICC_IGRPEN0_EL1: 109962306a36Sopenharmony_ci if (is_read) 110062306a36Sopenharmony_ci fn = __vgic_v3_read_igrpen0; 110162306a36Sopenharmony_ci else 110262306a36Sopenharmony_ci fn = __vgic_v3_write_igrpen0; 110362306a36Sopenharmony_ci break; 110462306a36Sopenharmony_ci case SYS_ICC_BPR0_EL1: 110562306a36Sopenharmony_ci if (is_read) 110662306a36Sopenharmony_ci fn = __vgic_v3_read_bpr0; 110762306a36Sopenharmony_ci else 110862306a36Sopenharmony_ci fn = __vgic_v3_write_bpr0; 110962306a36Sopenharmony_ci break; 111062306a36Sopenharmony_ci case SYS_ICC_DIR_EL1: 111162306a36Sopenharmony_ci if (unlikely(is_read)) 111262306a36Sopenharmony_ci return 0; 111362306a36Sopenharmony_ci fn = __vgic_v3_write_dir; 111462306a36Sopenharmony_ci break; 111562306a36Sopenharmony_ci case SYS_ICC_RPR_EL1: 111662306a36Sopenharmony_ci if (unlikely(!is_read)) 111762306a36Sopenharmony_ci return 0; 111862306a36Sopenharmony_ci fn = __vgic_v3_read_rpr; 111962306a36Sopenharmony_ci break; 112062306a36Sopenharmony_ci case SYS_ICC_CTLR_EL1: 112162306a36Sopenharmony_ci if (is_read) 112262306a36Sopenharmony_ci fn = __vgic_v3_read_ctlr; 112362306a36Sopenharmony_ci else 112462306a36Sopenharmony_ci fn = __vgic_v3_write_ctlr; 112562306a36Sopenharmony_ci break; 112662306a36Sopenharmony_ci case SYS_ICC_PMR_EL1: 112762306a36Sopenharmony_ci if (is_read) 112862306a36Sopenharmony_ci fn = __vgic_v3_read_pmr; 112962306a36Sopenharmony_ci else 113062306a36Sopenharmony_ci fn = __vgic_v3_write_pmr; 113162306a36Sopenharmony_ci break; 113262306a36Sopenharmony_ci default: 113362306a36Sopenharmony_ci return 0; 113462306a36Sopenharmony_ci } 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci vmcr = __vgic_v3_read_vmcr(); 113762306a36Sopenharmony_ci rt = kvm_vcpu_sys_get_rt(vcpu); 113862306a36Sopenharmony_ci fn(vcpu, vmcr, rt); 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci __kvm_skip_instr(vcpu); 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci return 1; 114362306a36Sopenharmony_ci} 1144