18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2012-2015 - ARM Ltd 48c2ecf20Sopenharmony_ci * Author: Marc Zyngier <marc.zyngier@arm.com> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/compiler.h> 88c2ecf20Sopenharmony_ci#include <linux/irqchip/arm-gic-v3.h> 98c2ecf20Sopenharmony_ci#include <linux/kvm_host.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <asm/kvm_emulate.h> 128c2ecf20Sopenharmony_ci#include <asm/kvm_hyp.h> 138c2ecf20Sopenharmony_ci#include <asm/kvm_mmu.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#define vtr_to_max_lr_idx(v) ((v) & 0xf) 168c2ecf20Sopenharmony_ci#define vtr_to_nr_pre_bits(v) ((((u32)(v) >> 26) & 7) + 1) 178c2ecf20Sopenharmony_ci#define vtr_to_nr_apr_regs(v) (1 << (vtr_to_nr_pre_bits(v) - 5)) 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic u64 __gic_v3_get_lr(unsigned int lr) 208c2ecf20Sopenharmony_ci{ 218c2ecf20Sopenharmony_ci switch (lr & 0xf) { 228c2ecf20Sopenharmony_ci case 0: 238c2ecf20Sopenharmony_ci return read_gicreg(ICH_LR0_EL2); 248c2ecf20Sopenharmony_ci case 1: 258c2ecf20Sopenharmony_ci return read_gicreg(ICH_LR1_EL2); 268c2ecf20Sopenharmony_ci case 2: 278c2ecf20Sopenharmony_ci return read_gicreg(ICH_LR2_EL2); 288c2ecf20Sopenharmony_ci case 3: 298c2ecf20Sopenharmony_ci return read_gicreg(ICH_LR3_EL2); 308c2ecf20Sopenharmony_ci case 4: 318c2ecf20Sopenharmony_ci return read_gicreg(ICH_LR4_EL2); 328c2ecf20Sopenharmony_ci case 5: 338c2ecf20Sopenharmony_ci return read_gicreg(ICH_LR5_EL2); 348c2ecf20Sopenharmony_ci case 6: 358c2ecf20Sopenharmony_ci return read_gicreg(ICH_LR6_EL2); 368c2ecf20Sopenharmony_ci case 7: 378c2ecf20Sopenharmony_ci return read_gicreg(ICH_LR7_EL2); 388c2ecf20Sopenharmony_ci case 8: 398c2ecf20Sopenharmony_ci return read_gicreg(ICH_LR8_EL2); 408c2ecf20Sopenharmony_ci case 9: 418c2ecf20Sopenharmony_ci return read_gicreg(ICH_LR9_EL2); 428c2ecf20Sopenharmony_ci case 10: 438c2ecf20Sopenharmony_ci return read_gicreg(ICH_LR10_EL2); 448c2ecf20Sopenharmony_ci case 11: 458c2ecf20Sopenharmony_ci return read_gicreg(ICH_LR11_EL2); 468c2ecf20Sopenharmony_ci case 12: 478c2ecf20Sopenharmony_ci return read_gicreg(ICH_LR12_EL2); 488c2ecf20Sopenharmony_ci case 13: 498c2ecf20Sopenharmony_ci return read_gicreg(ICH_LR13_EL2); 508c2ecf20Sopenharmony_ci case 14: 518c2ecf20Sopenharmony_ci return read_gicreg(ICH_LR14_EL2); 528c2ecf20Sopenharmony_ci case 15: 538c2ecf20Sopenharmony_ci return read_gicreg(ICH_LR15_EL2); 548c2ecf20Sopenharmony_ci } 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci unreachable(); 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic void __gic_v3_set_lr(u64 val, int lr) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci switch (lr & 0xf) { 628c2ecf20Sopenharmony_ci case 0: 638c2ecf20Sopenharmony_ci write_gicreg(val, ICH_LR0_EL2); 648c2ecf20Sopenharmony_ci break; 658c2ecf20Sopenharmony_ci case 1: 668c2ecf20Sopenharmony_ci write_gicreg(val, ICH_LR1_EL2); 678c2ecf20Sopenharmony_ci break; 688c2ecf20Sopenharmony_ci case 2: 698c2ecf20Sopenharmony_ci write_gicreg(val, ICH_LR2_EL2); 708c2ecf20Sopenharmony_ci break; 718c2ecf20Sopenharmony_ci case 3: 728c2ecf20Sopenharmony_ci write_gicreg(val, ICH_LR3_EL2); 738c2ecf20Sopenharmony_ci break; 748c2ecf20Sopenharmony_ci case 4: 758c2ecf20Sopenharmony_ci write_gicreg(val, ICH_LR4_EL2); 768c2ecf20Sopenharmony_ci break; 778c2ecf20Sopenharmony_ci case 5: 788c2ecf20Sopenharmony_ci write_gicreg(val, ICH_LR5_EL2); 798c2ecf20Sopenharmony_ci break; 808c2ecf20Sopenharmony_ci case 6: 818c2ecf20Sopenharmony_ci write_gicreg(val, ICH_LR6_EL2); 828c2ecf20Sopenharmony_ci break; 838c2ecf20Sopenharmony_ci case 7: 848c2ecf20Sopenharmony_ci write_gicreg(val, ICH_LR7_EL2); 858c2ecf20Sopenharmony_ci break; 868c2ecf20Sopenharmony_ci case 8: 878c2ecf20Sopenharmony_ci write_gicreg(val, ICH_LR8_EL2); 888c2ecf20Sopenharmony_ci break; 898c2ecf20Sopenharmony_ci case 9: 908c2ecf20Sopenharmony_ci write_gicreg(val, ICH_LR9_EL2); 918c2ecf20Sopenharmony_ci break; 928c2ecf20Sopenharmony_ci case 10: 938c2ecf20Sopenharmony_ci write_gicreg(val, ICH_LR10_EL2); 948c2ecf20Sopenharmony_ci break; 958c2ecf20Sopenharmony_ci case 11: 968c2ecf20Sopenharmony_ci write_gicreg(val, ICH_LR11_EL2); 978c2ecf20Sopenharmony_ci break; 988c2ecf20Sopenharmony_ci case 12: 998c2ecf20Sopenharmony_ci write_gicreg(val, ICH_LR12_EL2); 1008c2ecf20Sopenharmony_ci break; 1018c2ecf20Sopenharmony_ci case 13: 1028c2ecf20Sopenharmony_ci write_gicreg(val, ICH_LR13_EL2); 1038c2ecf20Sopenharmony_ci break; 1048c2ecf20Sopenharmony_ci case 14: 1058c2ecf20Sopenharmony_ci write_gicreg(val, ICH_LR14_EL2); 1068c2ecf20Sopenharmony_ci break; 1078c2ecf20Sopenharmony_ci case 15: 1088c2ecf20Sopenharmony_ci write_gicreg(val, ICH_LR15_EL2); 1098c2ecf20Sopenharmony_ci break; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic void __vgic_v3_write_ap0rn(u32 val, int n) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci switch (n) { 1168c2ecf20Sopenharmony_ci case 0: 1178c2ecf20Sopenharmony_ci write_gicreg(val, ICH_AP0R0_EL2); 1188c2ecf20Sopenharmony_ci break; 1198c2ecf20Sopenharmony_ci case 1: 1208c2ecf20Sopenharmony_ci write_gicreg(val, ICH_AP0R1_EL2); 1218c2ecf20Sopenharmony_ci break; 1228c2ecf20Sopenharmony_ci case 2: 1238c2ecf20Sopenharmony_ci write_gicreg(val, ICH_AP0R2_EL2); 1248c2ecf20Sopenharmony_ci break; 1258c2ecf20Sopenharmony_ci case 3: 1268c2ecf20Sopenharmony_ci write_gicreg(val, ICH_AP0R3_EL2); 1278c2ecf20Sopenharmony_ci break; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic void __vgic_v3_write_ap1rn(u32 val, int n) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci switch (n) { 1348c2ecf20Sopenharmony_ci case 0: 1358c2ecf20Sopenharmony_ci write_gicreg(val, ICH_AP1R0_EL2); 1368c2ecf20Sopenharmony_ci break; 1378c2ecf20Sopenharmony_ci case 1: 1388c2ecf20Sopenharmony_ci write_gicreg(val, ICH_AP1R1_EL2); 1398c2ecf20Sopenharmony_ci break; 1408c2ecf20Sopenharmony_ci case 2: 1418c2ecf20Sopenharmony_ci write_gicreg(val, ICH_AP1R2_EL2); 1428c2ecf20Sopenharmony_ci break; 1438c2ecf20Sopenharmony_ci case 3: 1448c2ecf20Sopenharmony_ci write_gicreg(val, ICH_AP1R3_EL2); 1458c2ecf20Sopenharmony_ci break; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic u32 __vgic_v3_read_ap0rn(int n) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci u32 val; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci switch (n) { 1548c2ecf20Sopenharmony_ci case 0: 1558c2ecf20Sopenharmony_ci val = read_gicreg(ICH_AP0R0_EL2); 1568c2ecf20Sopenharmony_ci break; 1578c2ecf20Sopenharmony_ci case 1: 1588c2ecf20Sopenharmony_ci val = read_gicreg(ICH_AP0R1_EL2); 1598c2ecf20Sopenharmony_ci break; 1608c2ecf20Sopenharmony_ci case 2: 1618c2ecf20Sopenharmony_ci val = read_gicreg(ICH_AP0R2_EL2); 1628c2ecf20Sopenharmony_ci break; 1638c2ecf20Sopenharmony_ci case 3: 1648c2ecf20Sopenharmony_ci val = read_gicreg(ICH_AP0R3_EL2); 1658c2ecf20Sopenharmony_ci break; 1668c2ecf20Sopenharmony_ci default: 1678c2ecf20Sopenharmony_ci unreachable(); 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci return val; 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic u32 __vgic_v3_read_ap1rn(int n) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci u32 val; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci switch (n) { 1788c2ecf20Sopenharmony_ci case 0: 1798c2ecf20Sopenharmony_ci val = read_gicreg(ICH_AP1R0_EL2); 1808c2ecf20Sopenharmony_ci break; 1818c2ecf20Sopenharmony_ci case 1: 1828c2ecf20Sopenharmony_ci val = read_gicreg(ICH_AP1R1_EL2); 1838c2ecf20Sopenharmony_ci break; 1848c2ecf20Sopenharmony_ci case 2: 1858c2ecf20Sopenharmony_ci val = read_gicreg(ICH_AP1R2_EL2); 1868c2ecf20Sopenharmony_ci break; 1878c2ecf20Sopenharmony_ci case 3: 1888c2ecf20Sopenharmony_ci val = read_gicreg(ICH_AP1R3_EL2); 1898c2ecf20Sopenharmony_ci break; 1908c2ecf20Sopenharmony_ci default: 1918c2ecf20Sopenharmony_ci unreachable(); 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci return val; 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_civoid __vgic_v3_save_state(struct vgic_v3_cpu_if *cpu_if) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci u64 used_lrs = cpu_if->used_lrs; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci /* 2028c2ecf20Sopenharmony_ci * Make sure stores to the GIC via the memory mapped interface 2038c2ecf20Sopenharmony_ci * are now visible to the system register interface when reading the 2048c2ecf20Sopenharmony_ci * LRs, and when reading back the VMCR on non-VHE systems. 2058c2ecf20Sopenharmony_ci */ 2068c2ecf20Sopenharmony_ci if (used_lrs || !has_vhe()) { 2078c2ecf20Sopenharmony_ci if (!cpu_if->vgic_sre) { 2088c2ecf20Sopenharmony_ci dsb(sy); 2098c2ecf20Sopenharmony_ci isb(); 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci if (used_lrs || cpu_if->its_vpe.its_vm) { 2148c2ecf20Sopenharmony_ci int i; 2158c2ecf20Sopenharmony_ci u32 elrsr; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci elrsr = read_gicreg(ICH_ELRSR_EL2); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci write_gicreg(cpu_if->vgic_hcr & ~ICH_HCR_EN, ICH_HCR_EL2); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci for (i = 0; i < used_lrs; i++) { 2228c2ecf20Sopenharmony_ci if (elrsr & (1 << i)) 2238c2ecf20Sopenharmony_ci cpu_if->vgic_lr[i] &= ~ICH_LR_STATE; 2248c2ecf20Sopenharmony_ci else 2258c2ecf20Sopenharmony_ci cpu_if->vgic_lr[i] = __gic_v3_get_lr(i); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci __gic_v3_set_lr(0, i); 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_civoid __vgic_v3_restore_state(struct vgic_v3_cpu_if *cpu_if) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci u64 used_lrs = cpu_if->used_lrs; 2358c2ecf20Sopenharmony_ci int i; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci if (used_lrs || cpu_if->its_vpe.its_vm) { 2388c2ecf20Sopenharmony_ci write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci for (i = 0; i < used_lrs; i++) 2418c2ecf20Sopenharmony_ci __gic_v3_set_lr(cpu_if->vgic_lr[i], i); 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci /* 2458c2ecf20Sopenharmony_ci * Ensure that writes to the LRs, and on non-VHE systems ensure that 2468c2ecf20Sopenharmony_ci * the write to the VMCR in __vgic_v3_activate_traps(), will have 2478c2ecf20Sopenharmony_ci * reached the (re)distributors. This ensure the guest will read the 2488c2ecf20Sopenharmony_ci * correct values from the memory-mapped interface. 2498c2ecf20Sopenharmony_ci */ 2508c2ecf20Sopenharmony_ci if (used_lrs || !has_vhe()) { 2518c2ecf20Sopenharmony_ci if (!cpu_if->vgic_sre) { 2528c2ecf20Sopenharmony_ci isb(); 2538c2ecf20Sopenharmony_ci dsb(sy); 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_civoid __vgic_v3_activate_traps(struct vgic_v3_cpu_if *cpu_if) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci /* 2618c2ecf20Sopenharmony_ci * VFIQEn is RES1 if ICC_SRE_EL1.SRE is 1. This causes a 2628c2ecf20Sopenharmony_ci * Group0 interrupt (as generated in GICv2 mode) to be 2638c2ecf20Sopenharmony_ci * delivered as a FIQ to the guest, with potentially fatal 2648c2ecf20Sopenharmony_ci * consequences. So we must make sure that ICC_SRE_EL1 has 2658c2ecf20Sopenharmony_ci * been actually programmed with the value we want before 2668c2ecf20Sopenharmony_ci * starting to mess with the rest of the GIC, and VMCR_EL2 in 2678c2ecf20Sopenharmony_ci * particular. This logic must be called before 2688c2ecf20Sopenharmony_ci * __vgic_v3_restore_state(). 2698c2ecf20Sopenharmony_ci */ 2708c2ecf20Sopenharmony_ci if (!cpu_if->vgic_sre) { 2718c2ecf20Sopenharmony_ci write_gicreg(0, ICC_SRE_EL1); 2728c2ecf20Sopenharmony_ci isb(); 2738c2ecf20Sopenharmony_ci write_gicreg(cpu_if->vgic_vmcr, ICH_VMCR_EL2); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci if (has_vhe()) { 2778c2ecf20Sopenharmony_ci /* 2788c2ecf20Sopenharmony_ci * Ensure that the write to the VMCR will have reached 2798c2ecf20Sopenharmony_ci * the (re)distributors. This ensure the guest will 2808c2ecf20Sopenharmony_ci * read the correct values from the memory-mapped 2818c2ecf20Sopenharmony_ci * interface. 2828c2ecf20Sopenharmony_ci */ 2838c2ecf20Sopenharmony_ci isb(); 2848c2ecf20Sopenharmony_ci dsb(sy); 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci /* 2898c2ecf20Sopenharmony_ci * Prevent the guest from touching the GIC system registers if 2908c2ecf20Sopenharmony_ci * SRE isn't enabled for GICv3 emulation. 2918c2ecf20Sopenharmony_ci */ 2928c2ecf20Sopenharmony_ci write_gicreg(read_gicreg(ICC_SRE_EL2) & ~ICC_SRE_EL2_ENABLE, 2938c2ecf20Sopenharmony_ci ICC_SRE_EL2); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci /* 2968c2ecf20Sopenharmony_ci * If we need to trap system registers, we must write 2978c2ecf20Sopenharmony_ci * ICH_HCR_EL2 anyway, even if no interrupts are being 2988c2ecf20Sopenharmony_ci * injected, 2998c2ecf20Sopenharmony_ci */ 3008c2ecf20Sopenharmony_ci if (static_branch_unlikely(&vgic_v3_cpuif_trap) || 3018c2ecf20Sopenharmony_ci cpu_if->its_vpe.its_vm) 3028c2ecf20Sopenharmony_ci write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2); 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_civoid __vgic_v3_deactivate_traps(struct vgic_v3_cpu_if *cpu_if) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci u64 val; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci if (!cpu_if->vgic_sre) { 3108c2ecf20Sopenharmony_ci cpu_if->vgic_vmcr = read_gicreg(ICH_VMCR_EL2); 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci val = read_gicreg(ICC_SRE_EL2); 3148c2ecf20Sopenharmony_ci write_gicreg(val | ICC_SRE_EL2_ENABLE, ICC_SRE_EL2); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci if (!cpu_if->vgic_sre) { 3178c2ecf20Sopenharmony_ci /* Make sure ENABLE is set at EL2 before setting SRE at EL1 */ 3188c2ecf20Sopenharmony_ci isb(); 3198c2ecf20Sopenharmony_ci write_gicreg(1, ICC_SRE_EL1); 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci /* 3238c2ecf20Sopenharmony_ci * If we were trapping system registers, we enabled the VGIC even if 3248c2ecf20Sopenharmony_ci * no interrupts were being injected, and we disable it again here. 3258c2ecf20Sopenharmony_ci */ 3268c2ecf20Sopenharmony_ci if (static_branch_unlikely(&vgic_v3_cpuif_trap) || 3278c2ecf20Sopenharmony_ci cpu_if->its_vpe.its_vm) 3288c2ecf20Sopenharmony_ci write_gicreg(0, ICH_HCR_EL2); 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_civoid __vgic_v3_save_aprs(struct vgic_v3_cpu_if *cpu_if) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci u64 val; 3348c2ecf20Sopenharmony_ci u32 nr_pre_bits; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci val = read_gicreg(ICH_VTR_EL2); 3378c2ecf20Sopenharmony_ci nr_pre_bits = vtr_to_nr_pre_bits(val); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci switch (nr_pre_bits) { 3408c2ecf20Sopenharmony_ci case 7: 3418c2ecf20Sopenharmony_ci cpu_if->vgic_ap0r[3] = __vgic_v3_read_ap0rn(3); 3428c2ecf20Sopenharmony_ci cpu_if->vgic_ap0r[2] = __vgic_v3_read_ap0rn(2); 3438c2ecf20Sopenharmony_ci fallthrough; 3448c2ecf20Sopenharmony_ci case 6: 3458c2ecf20Sopenharmony_ci cpu_if->vgic_ap0r[1] = __vgic_v3_read_ap0rn(1); 3468c2ecf20Sopenharmony_ci fallthrough; 3478c2ecf20Sopenharmony_ci default: 3488c2ecf20Sopenharmony_ci cpu_if->vgic_ap0r[0] = __vgic_v3_read_ap0rn(0); 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci switch (nr_pre_bits) { 3528c2ecf20Sopenharmony_ci case 7: 3538c2ecf20Sopenharmony_ci cpu_if->vgic_ap1r[3] = __vgic_v3_read_ap1rn(3); 3548c2ecf20Sopenharmony_ci cpu_if->vgic_ap1r[2] = __vgic_v3_read_ap1rn(2); 3558c2ecf20Sopenharmony_ci fallthrough; 3568c2ecf20Sopenharmony_ci case 6: 3578c2ecf20Sopenharmony_ci cpu_if->vgic_ap1r[1] = __vgic_v3_read_ap1rn(1); 3588c2ecf20Sopenharmony_ci fallthrough; 3598c2ecf20Sopenharmony_ci default: 3608c2ecf20Sopenharmony_ci cpu_if->vgic_ap1r[0] = __vgic_v3_read_ap1rn(0); 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci} 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_civoid __vgic_v3_restore_aprs(struct vgic_v3_cpu_if *cpu_if) 3658c2ecf20Sopenharmony_ci{ 3668c2ecf20Sopenharmony_ci u64 val; 3678c2ecf20Sopenharmony_ci u32 nr_pre_bits; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci val = read_gicreg(ICH_VTR_EL2); 3708c2ecf20Sopenharmony_ci nr_pre_bits = vtr_to_nr_pre_bits(val); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci switch (nr_pre_bits) { 3738c2ecf20Sopenharmony_ci case 7: 3748c2ecf20Sopenharmony_ci __vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[3], 3); 3758c2ecf20Sopenharmony_ci __vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[2], 2); 3768c2ecf20Sopenharmony_ci fallthrough; 3778c2ecf20Sopenharmony_ci case 6: 3788c2ecf20Sopenharmony_ci __vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[1], 1); 3798c2ecf20Sopenharmony_ci fallthrough; 3808c2ecf20Sopenharmony_ci default: 3818c2ecf20Sopenharmony_ci __vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[0], 0); 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci switch (nr_pre_bits) { 3858c2ecf20Sopenharmony_ci case 7: 3868c2ecf20Sopenharmony_ci __vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[3], 3); 3878c2ecf20Sopenharmony_ci __vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[2], 2); 3888c2ecf20Sopenharmony_ci fallthrough; 3898c2ecf20Sopenharmony_ci case 6: 3908c2ecf20Sopenharmony_ci __vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[1], 1); 3918c2ecf20Sopenharmony_ci fallthrough; 3928c2ecf20Sopenharmony_ci default: 3938c2ecf20Sopenharmony_ci __vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[0], 0); 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_civoid __vgic_v3_init_lrs(void) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci int max_lr_idx = vtr_to_max_lr_idx(read_gicreg(ICH_VTR_EL2)); 4008c2ecf20Sopenharmony_ci int i; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci for (i = 0; i <= max_lr_idx; i++) 4038c2ecf20Sopenharmony_ci __gic_v3_set_lr(0, i); 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ciu64 __vgic_v3_get_ich_vtr_el2(void) 4078c2ecf20Sopenharmony_ci{ 4088c2ecf20Sopenharmony_ci return read_gicreg(ICH_VTR_EL2); 4098c2ecf20Sopenharmony_ci} 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ciu64 __vgic_v3_read_vmcr(void) 4128c2ecf20Sopenharmony_ci{ 4138c2ecf20Sopenharmony_ci return read_gicreg(ICH_VMCR_EL2); 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_civoid __vgic_v3_write_vmcr(u32 vmcr) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci write_gicreg(vmcr, ICH_VMCR_EL2); 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic int __vgic_v3_bpr_min(void) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci /* See Pseudocode for VPriorityGroup */ 4248c2ecf20Sopenharmony_ci return 8 - vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2)); 4258c2ecf20Sopenharmony_ci} 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_cistatic int __vgic_v3_get_group(struct kvm_vcpu *vcpu) 4288c2ecf20Sopenharmony_ci{ 4298c2ecf20Sopenharmony_ci u32 esr = kvm_vcpu_get_esr(vcpu); 4308c2ecf20Sopenharmony_ci u8 crm = (esr & ESR_ELx_SYS64_ISS_CRM_MASK) >> ESR_ELx_SYS64_ISS_CRM_SHIFT; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci return crm != 8; 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci#define GICv3_IDLE_PRIORITY 0xff 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_cistatic int __vgic_v3_highest_priority_lr(struct kvm_vcpu *vcpu, u32 vmcr, 4388c2ecf20Sopenharmony_ci u64 *lr_val) 4398c2ecf20Sopenharmony_ci{ 4408c2ecf20Sopenharmony_ci unsigned int used_lrs = vcpu->arch.vgic_cpu.vgic_v3.used_lrs; 4418c2ecf20Sopenharmony_ci u8 priority = GICv3_IDLE_PRIORITY; 4428c2ecf20Sopenharmony_ci int i, lr = -1; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci for (i = 0; i < used_lrs; i++) { 4458c2ecf20Sopenharmony_ci u64 val = __gic_v3_get_lr(i); 4468c2ecf20Sopenharmony_ci u8 lr_prio = (val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci /* Not pending in the state? */ 4498c2ecf20Sopenharmony_ci if ((val & ICH_LR_STATE) != ICH_LR_PENDING_BIT) 4508c2ecf20Sopenharmony_ci continue; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci /* Group-0 interrupt, but Group-0 disabled? */ 4538c2ecf20Sopenharmony_ci if (!(val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG0_MASK)) 4548c2ecf20Sopenharmony_ci continue; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci /* Group-1 interrupt, but Group-1 disabled? */ 4578c2ecf20Sopenharmony_ci if ((val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG1_MASK)) 4588c2ecf20Sopenharmony_ci continue; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci /* Not the highest priority? */ 4618c2ecf20Sopenharmony_ci if (lr_prio >= priority) 4628c2ecf20Sopenharmony_ci continue; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci /* This is a candidate */ 4658c2ecf20Sopenharmony_ci priority = lr_prio; 4668c2ecf20Sopenharmony_ci *lr_val = val; 4678c2ecf20Sopenharmony_ci lr = i; 4688c2ecf20Sopenharmony_ci } 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci if (lr == -1) 4718c2ecf20Sopenharmony_ci *lr_val = ICC_IAR1_EL1_SPURIOUS; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci return lr; 4748c2ecf20Sopenharmony_ci} 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_cistatic int __vgic_v3_find_active_lr(struct kvm_vcpu *vcpu, int intid, 4778c2ecf20Sopenharmony_ci u64 *lr_val) 4788c2ecf20Sopenharmony_ci{ 4798c2ecf20Sopenharmony_ci unsigned int used_lrs = vcpu->arch.vgic_cpu.vgic_v3.used_lrs; 4808c2ecf20Sopenharmony_ci int i; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci for (i = 0; i < used_lrs; i++) { 4838c2ecf20Sopenharmony_ci u64 val = __gic_v3_get_lr(i); 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci if ((val & ICH_LR_VIRTUAL_ID_MASK) == intid && 4868c2ecf20Sopenharmony_ci (val & ICH_LR_ACTIVE_BIT)) { 4878c2ecf20Sopenharmony_ci *lr_val = val; 4888c2ecf20Sopenharmony_ci return i; 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci *lr_val = ICC_IAR1_EL1_SPURIOUS; 4938c2ecf20Sopenharmony_ci return -1; 4948c2ecf20Sopenharmony_ci} 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_cistatic int __vgic_v3_get_highest_active_priority(void) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci u8 nr_apr_regs = vtr_to_nr_apr_regs(read_gicreg(ICH_VTR_EL2)); 4998c2ecf20Sopenharmony_ci u32 hap = 0; 5008c2ecf20Sopenharmony_ci int i; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci for (i = 0; i < nr_apr_regs; i++) { 5038c2ecf20Sopenharmony_ci u32 val; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci /* 5068c2ecf20Sopenharmony_ci * The ICH_AP0Rn_EL2 and ICH_AP1Rn_EL2 registers 5078c2ecf20Sopenharmony_ci * contain the active priority levels for this VCPU 5088c2ecf20Sopenharmony_ci * for the maximum number of supported priority 5098c2ecf20Sopenharmony_ci * levels, and we return the full priority level only 5108c2ecf20Sopenharmony_ci * if the BPR is programmed to its minimum, otherwise 5118c2ecf20Sopenharmony_ci * we return a combination of the priority level and 5128c2ecf20Sopenharmony_ci * subpriority, as determined by the setting of the 5138c2ecf20Sopenharmony_ci * BPR, but without the full subpriority. 5148c2ecf20Sopenharmony_ci */ 5158c2ecf20Sopenharmony_ci val = __vgic_v3_read_ap0rn(i); 5168c2ecf20Sopenharmony_ci val |= __vgic_v3_read_ap1rn(i); 5178c2ecf20Sopenharmony_ci if (!val) { 5188c2ecf20Sopenharmony_ci hap += 32; 5198c2ecf20Sopenharmony_ci continue; 5208c2ecf20Sopenharmony_ci } 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci return (hap + __ffs(val)) << __vgic_v3_bpr_min(); 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci return GICv3_IDLE_PRIORITY; 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_cistatic unsigned int __vgic_v3_get_bpr0(u32 vmcr) 5298c2ecf20Sopenharmony_ci{ 5308c2ecf20Sopenharmony_ci return (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT; 5318c2ecf20Sopenharmony_ci} 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_cistatic unsigned int __vgic_v3_get_bpr1(u32 vmcr) 5348c2ecf20Sopenharmony_ci{ 5358c2ecf20Sopenharmony_ci unsigned int bpr; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci if (vmcr & ICH_VMCR_CBPR_MASK) { 5388c2ecf20Sopenharmony_ci bpr = __vgic_v3_get_bpr0(vmcr); 5398c2ecf20Sopenharmony_ci if (bpr < 7) 5408c2ecf20Sopenharmony_ci bpr++; 5418c2ecf20Sopenharmony_ci } else { 5428c2ecf20Sopenharmony_ci bpr = (vmcr & ICH_VMCR_BPR1_MASK) >> ICH_VMCR_BPR1_SHIFT; 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci return bpr; 5468c2ecf20Sopenharmony_ci} 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci/* 5498c2ecf20Sopenharmony_ci * Convert a priority to a preemption level, taking the relevant BPR 5508c2ecf20Sopenharmony_ci * into account by zeroing the sub-priority bits. 5518c2ecf20Sopenharmony_ci */ 5528c2ecf20Sopenharmony_cistatic u8 __vgic_v3_pri_to_pre(u8 pri, u32 vmcr, int grp) 5538c2ecf20Sopenharmony_ci{ 5548c2ecf20Sopenharmony_ci unsigned int bpr; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci if (!grp) 5578c2ecf20Sopenharmony_ci bpr = __vgic_v3_get_bpr0(vmcr) + 1; 5588c2ecf20Sopenharmony_ci else 5598c2ecf20Sopenharmony_ci bpr = __vgic_v3_get_bpr1(vmcr); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci return pri & (GENMASK(7, 0) << bpr); 5628c2ecf20Sopenharmony_ci} 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci/* 5658c2ecf20Sopenharmony_ci * The priority value is independent of any of the BPR values, so we 5668c2ecf20Sopenharmony_ci * normalize it using the minimal BPR value. This guarantees that no 5678c2ecf20Sopenharmony_ci * matter what the guest does with its BPR, we can always set/get the 5688c2ecf20Sopenharmony_ci * same value of a priority. 5698c2ecf20Sopenharmony_ci */ 5708c2ecf20Sopenharmony_cistatic void __vgic_v3_set_active_priority(u8 pri, u32 vmcr, int grp) 5718c2ecf20Sopenharmony_ci{ 5728c2ecf20Sopenharmony_ci u8 pre, ap; 5738c2ecf20Sopenharmony_ci u32 val; 5748c2ecf20Sopenharmony_ci int apr; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci pre = __vgic_v3_pri_to_pre(pri, vmcr, grp); 5778c2ecf20Sopenharmony_ci ap = pre >> __vgic_v3_bpr_min(); 5788c2ecf20Sopenharmony_ci apr = ap / 32; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci if (!grp) { 5818c2ecf20Sopenharmony_ci val = __vgic_v3_read_ap0rn(apr); 5828c2ecf20Sopenharmony_ci __vgic_v3_write_ap0rn(val | BIT(ap % 32), apr); 5838c2ecf20Sopenharmony_ci } else { 5848c2ecf20Sopenharmony_ci val = __vgic_v3_read_ap1rn(apr); 5858c2ecf20Sopenharmony_ci __vgic_v3_write_ap1rn(val | BIT(ap % 32), apr); 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci} 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_cistatic int __vgic_v3_clear_highest_active_priority(void) 5908c2ecf20Sopenharmony_ci{ 5918c2ecf20Sopenharmony_ci u8 nr_apr_regs = vtr_to_nr_apr_regs(read_gicreg(ICH_VTR_EL2)); 5928c2ecf20Sopenharmony_ci u32 hap = 0; 5938c2ecf20Sopenharmony_ci int i; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci for (i = 0; i < nr_apr_regs; i++) { 5968c2ecf20Sopenharmony_ci u32 ap0, ap1; 5978c2ecf20Sopenharmony_ci int c0, c1; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci ap0 = __vgic_v3_read_ap0rn(i); 6008c2ecf20Sopenharmony_ci ap1 = __vgic_v3_read_ap1rn(i); 6018c2ecf20Sopenharmony_ci if (!ap0 && !ap1) { 6028c2ecf20Sopenharmony_ci hap += 32; 6038c2ecf20Sopenharmony_ci continue; 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci c0 = ap0 ? __ffs(ap0) : 32; 6078c2ecf20Sopenharmony_ci c1 = ap1 ? __ffs(ap1) : 32; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci /* Always clear the LSB, which is the highest priority */ 6108c2ecf20Sopenharmony_ci if (c0 < c1) { 6118c2ecf20Sopenharmony_ci ap0 &= ~BIT(c0); 6128c2ecf20Sopenharmony_ci __vgic_v3_write_ap0rn(ap0, i); 6138c2ecf20Sopenharmony_ci hap += c0; 6148c2ecf20Sopenharmony_ci } else { 6158c2ecf20Sopenharmony_ci ap1 &= ~BIT(c1); 6168c2ecf20Sopenharmony_ci __vgic_v3_write_ap1rn(ap1, i); 6178c2ecf20Sopenharmony_ci hap += c1; 6188c2ecf20Sopenharmony_ci } 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci /* Rescale to 8 bits of priority */ 6218c2ecf20Sopenharmony_ci return hap << __vgic_v3_bpr_min(); 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci return GICv3_IDLE_PRIORITY; 6258c2ecf20Sopenharmony_ci} 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_cistatic void __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 6288c2ecf20Sopenharmony_ci{ 6298c2ecf20Sopenharmony_ci u64 lr_val; 6308c2ecf20Sopenharmony_ci u8 lr_prio, pmr; 6318c2ecf20Sopenharmony_ci int lr, grp; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci grp = __vgic_v3_get_group(vcpu); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci lr = __vgic_v3_highest_priority_lr(vcpu, vmcr, &lr_val); 6368c2ecf20Sopenharmony_ci if (lr < 0) 6378c2ecf20Sopenharmony_ci goto spurious; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci if (grp != !!(lr_val & ICH_LR_GROUP)) 6408c2ecf20Sopenharmony_ci goto spurious; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci pmr = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT; 6438c2ecf20Sopenharmony_ci lr_prio = (lr_val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT; 6448c2ecf20Sopenharmony_ci if (pmr <= lr_prio) 6458c2ecf20Sopenharmony_ci goto spurious; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci if (__vgic_v3_get_highest_active_priority() <= __vgic_v3_pri_to_pre(lr_prio, vmcr, grp)) 6488c2ecf20Sopenharmony_ci goto spurious; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci lr_val &= ~ICH_LR_STATE; 6518c2ecf20Sopenharmony_ci /* No active state for LPIs */ 6528c2ecf20Sopenharmony_ci if ((lr_val & ICH_LR_VIRTUAL_ID_MASK) <= VGIC_MAX_SPI) 6538c2ecf20Sopenharmony_ci lr_val |= ICH_LR_ACTIVE_BIT; 6548c2ecf20Sopenharmony_ci __gic_v3_set_lr(lr_val, lr); 6558c2ecf20Sopenharmony_ci __vgic_v3_set_active_priority(lr_prio, vmcr, grp); 6568c2ecf20Sopenharmony_ci vcpu_set_reg(vcpu, rt, lr_val & ICH_LR_VIRTUAL_ID_MASK); 6578c2ecf20Sopenharmony_ci return; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_cispurious: 6608c2ecf20Sopenharmony_ci vcpu_set_reg(vcpu, rt, ICC_IAR1_EL1_SPURIOUS); 6618c2ecf20Sopenharmony_ci} 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_cistatic void __vgic_v3_clear_active_lr(int lr, u64 lr_val) 6648c2ecf20Sopenharmony_ci{ 6658c2ecf20Sopenharmony_ci lr_val &= ~ICH_LR_ACTIVE_BIT; 6668c2ecf20Sopenharmony_ci if (lr_val & ICH_LR_HW) { 6678c2ecf20Sopenharmony_ci u32 pid; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci pid = (lr_val & ICH_LR_PHYS_ID_MASK) >> ICH_LR_PHYS_ID_SHIFT; 6708c2ecf20Sopenharmony_ci gic_write_dir(pid); 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci __gic_v3_set_lr(lr_val, lr); 6748c2ecf20Sopenharmony_ci} 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_cistatic void __vgic_v3_bump_eoicount(void) 6778c2ecf20Sopenharmony_ci{ 6788c2ecf20Sopenharmony_ci u32 hcr; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci hcr = read_gicreg(ICH_HCR_EL2); 6818c2ecf20Sopenharmony_ci hcr += 1 << ICH_HCR_EOIcount_SHIFT; 6828c2ecf20Sopenharmony_ci write_gicreg(hcr, ICH_HCR_EL2); 6838c2ecf20Sopenharmony_ci} 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_cistatic void __vgic_v3_write_dir(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 6868c2ecf20Sopenharmony_ci{ 6878c2ecf20Sopenharmony_ci u32 vid = vcpu_get_reg(vcpu, rt); 6888c2ecf20Sopenharmony_ci u64 lr_val; 6898c2ecf20Sopenharmony_ci int lr; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci /* EOImode == 0, nothing to be done here */ 6928c2ecf20Sopenharmony_ci if (!(vmcr & ICH_VMCR_EOIM_MASK)) 6938c2ecf20Sopenharmony_ci return; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci /* No deactivate to be performed on an LPI */ 6968c2ecf20Sopenharmony_ci if (vid >= VGIC_MIN_LPI) 6978c2ecf20Sopenharmony_ci return; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci lr = __vgic_v3_find_active_lr(vcpu, vid, &lr_val); 7008c2ecf20Sopenharmony_ci if (lr == -1) { 7018c2ecf20Sopenharmony_ci __vgic_v3_bump_eoicount(); 7028c2ecf20Sopenharmony_ci return; 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci __vgic_v3_clear_active_lr(lr, lr_val); 7068c2ecf20Sopenharmony_ci} 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_cistatic void __vgic_v3_write_eoir(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci u32 vid = vcpu_get_reg(vcpu, rt); 7118c2ecf20Sopenharmony_ci u64 lr_val; 7128c2ecf20Sopenharmony_ci u8 lr_prio, act_prio; 7138c2ecf20Sopenharmony_ci int lr, grp; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci grp = __vgic_v3_get_group(vcpu); 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci /* Drop priority in any case */ 7188c2ecf20Sopenharmony_ci act_prio = __vgic_v3_clear_highest_active_priority(); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci /* If EOIing an LPI, no deactivate to be performed */ 7218c2ecf20Sopenharmony_ci if (vid >= VGIC_MIN_LPI) 7228c2ecf20Sopenharmony_ci return; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci /* EOImode == 1, nothing to be done here */ 7258c2ecf20Sopenharmony_ci if (vmcr & ICH_VMCR_EOIM_MASK) 7268c2ecf20Sopenharmony_ci return; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci lr = __vgic_v3_find_active_lr(vcpu, vid, &lr_val); 7298c2ecf20Sopenharmony_ci if (lr == -1) { 7308c2ecf20Sopenharmony_ci __vgic_v3_bump_eoicount(); 7318c2ecf20Sopenharmony_ci return; 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci lr_prio = (lr_val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci /* If priorities or group do not match, the guest has fscked-up. */ 7378c2ecf20Sopenharmony_ci if (grp != !!(lr_val & ICH_LR_GROUP) || 7388c2ecf20Sopenharmony_ci __vgic_v3_pri_to_pre(lr_prio, vmcr, grp) != act_prio) 7398c2ecf20Sopenharmony_ci return; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci /* Let's now perform the deactivation */ 7428c2ecf20Sopenharmony_ci __vgic_v3_clear_active_lr(lr, lr_val); 7438c2ecf20Sopenharmony_ci} 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_cistatic void __vgic_v3_read_igrpen0(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 7468c2ecf20Sopenharmony_ci{ 7478c2ecf20Sopenharmony_ci vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG0_MASK)); 7488c2ecf20Sopenharmony_ci} 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_cistatic void __vgic_v3_read_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 7518c2ecf20Sopenharmony_ci{ 7528c2ecf20Sopenharmony_ci vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG1_MASK)); 7538c2ecf20Sopenharmony_ci} 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_cistatic void __vgic_v3_write_igrpen0(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 7568c2ecf20Sopenharmony_ci{ 7578c2ecf20Sopenharmony_ci u64 val = vcpu_get_reg(vcpu, rt); 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci if (val & 1) 7608c2ecf20Sopenharmony_ci vmcr |= ICH_VMCR_ENG0_MASK; 7618c2ecf20Sopenharmony_ci else 7628c2ecf20Sopenharmony_ci vmcr &= ~ICH_VMCR_ENG0_MASK; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci __vgic_v3_write_vmcr(vmcr); 7658c2ecf20Sopenharmony_ci} 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_cistatic void __vgic_v3_write_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 7688c2ecf20Sopenharmony_ci{ 7698c2ecf20Sopenharmony_ci u64 val = vcpu_get_reg(vcpu, rt); 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci if (val & 1) 7728c2ecf20Sopenharmony_ci vmcr |= ICH_VMCR_ENG1_MASK; 7738c2ecf20Sopenharmony_ci else 7748c2ecf20Sopenharmony_ci vmcr &= ~ICH_VMCR_ENG1_MASK; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci __vgic_v3_write_vmcr(vmcr); 7778c2ecf20Sopenharmony_ci} 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_cistatic void __vgic_v3_read_bpr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 7808c2ecf20Sopenharmony_ci{ 7818c2ecf20Sopenharmony_ci vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr0(vmcr)); 7828c2ecf20Sopenharmony_ci} 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_cistatic void __vgic_v3_read_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 7858c2ecf20Sopenharmony_ci{ 7868c2ecf20Sopenharmony_ci vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr1(vmcr)); 7878c2ecf20Sopenharmony_ci} 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_cistatic void __vgic_v3_write_bpr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 7908c2ecf20Sopenharmony_ci{ 7918c2ecf20Sopenharmony_ci u64 val = vcpu_get_reg(vcpu, rt); 7928c2ecf20Sopenharmony_ci u8 bpr_min = __vgic_v3_bpr_min() - 1; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci /* Enforce BPR limiting */ 7958c2ecf20Sopenharmony_ci if (val < bpr_min) 7968c2ecf20Sopenharmony_ci val = bpr_min; 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci val <<= ICH_VMCR_BPR0_SHIFT; 7998c2ecf20Sopenharmony_ci val &= ICH_VMCR_BPR0_MASK; 8008c2ecf20Sopenharmony_ci vmcr &= ~ICH_VMCR_BPR0_MASK; 8018c2ecf20Sopenharmony_ci vmcr |= val; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci __vgic_v3_write_vmcr(vmcr); 8048c2ecf20Sopenharmony_ci} 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_cistatic void __vgic_v3_write_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 8078c2ecf20Sopenharmony_ci{ 8088c2ecf20Sopenharmony_ci u64 val = vcpu_get_reg(vcpu, rt); 8098c2ecf20Sopenharmony_ci u8 bpr_min = __vgic_v3_bpr_min(); 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci if (vmcr & ICH_VMCR_CBPR_MASK) 8128c2ecf20Sopenharmony_ci return; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci /* Enforce BPR limiting */ 8158c2ecf20Sopenharmony_ci if (val < bpr_min) 8168c2ecf20Sopenharmony_ci val = bpr_min; 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci val <<= ICH_VMCR_BPR1_SHIFT; 8198c2ecf20Sopenharmony_ci val &= ICH_VMCR_BPR1_MASK; 8208c2ecf20Sopenharmony_ci vmcr &= ~ICH_VMCR_BPR1_MASK; 8218c2ecf20Sopenharmony_ci vmcr |= val; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci __vgic_v3_write_vmcr(vmcr); 8248c2ecf20Sopenharmony_ci} 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_cistatic void __vgic_v3_read_apxrn(struct kvm_vcpu *vcpu, int rt, int n) 8278c2ecf20Sopenharmony_ci{ 8288c2ecf20Sopenharmony_ci u32 val; 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci if (!__vgic_v3_get_group(vcpu)) 8318c2ecf20Sopenharmony_ci val = __vgic_v3_read_ap0rn(n); 8328c2ecf20Sopenharmony_ci else 8338c2ecf20Sopenharmony_ci val = __vgic_v3_read_ap1rn(n); 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci vcpu_set_reg(vcpu, rt, val); 8368c2ecf20Sopenharmony_ci} 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_cistatic void __vgic_v3_write_apxrn(struct kvm_vcpu *vcpu, int rt, int n) 8398c2ecf20Sopenharmony_ci{ 8408c2ecf20Sopenharmony_ci u32 val = vcpu_get_reg(vcpu, rt); 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci if (!__vgic_v3_get_group(vcpu)) 8438c2ecf20Sopenharmony_ci __vgic_v3_write_ap0rn(val, n); 8448c2ecf20Sopenharmony_ci else 8458c2ecf20Sopenharmony_ci __vgic_v3_write_ap1rn(val, n); 8468c2ecf20Sopenharmony_ci} 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_cistatic void __vgic_v3_read_apxr0(struct kvm_vcpu *vcpu, 8498c2ecf20Sopenharmony_ci u32 vmcr, int rt) 8508c2ecf20Sopenharmony_ci{ 8518c2ecf20Sopenharmony_ci __vgic_v3_read_apxrn(vcpu, rt, 0); 8528c2ecf20Sopenharmony_ci} 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_cistatic void __vgic_v3_read_apxr1(struct kvm_vcpu *vcpu, 8558c2ecf20Sopenharmony_ci u32 vmcr, int rt) 8568c2ecf20Sopenharmony_ci{ 8578c2ecf20Sopenharmony_ci __vgic_v3_read_apxrn(vcpu, rt, 1); 8588c2ecf20Sopenharmony_ci} 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_cistatic void __vgic_v3_read_apxr2(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 8618c2ecf20Sopenharmony_ci{ 8628c2ecf20Sopenharmony_ci __vgic_v3_read_apxrn(vcpu, rt, 2); 8638c2ecf20Sopenharmony_ci} 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_cistatic void __vgic_v3_read_apxr3(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 8668c2ecf20Sopenharmony_ci{ 8678c2ecf20Sopenharmony_ci __vgic_v3_read_apxrn(vcpu, rt, 3); 8688c2ecf20Sopenharmony_ci} 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_cistatic void __vgic_v3_write_apxr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 8718c2ecf20Sopenharmony_ci{ 8728c2ecf20Sopenharmony_ci __vgic_v3_write_apxrn(vcpu, rt, 0); 8738c2ecf20Sopenharmony_ci} 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_cistatic void __vgic_v3_write_apxr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 8768c2ecf20Sopenharmony_ci{ 8778c2ecf20Sopenharmony_ci __vgic_v3_write_apxrn(vcpu, rt, 1); 8788c2ecf20Sopenharmony_ci} 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_cistatic void __vgic_v3_write_apxr2(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 8818c2ecf20Sopenharmony_ci{ 8828c2ecf20Sopenharmony_ci __vgic_v3_write_apxrn(vcpu, rt, 2); 8838c2ecf20Sopenharmony_ci} 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_cistatic void __vgic_v3_write_apxr3(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 8868c2ecf20Sopenharmony_ci{ 8878c2ecf20Sopenharmony_ci __vgic_v3_write_apxrn(vcpu, rt, 3); 8888c2ecf20Sopenharmony_ci} 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_cistatic void __vgic_v3_read_hppir(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 8918c2ecf20Sopenharmony_ci{ 8928c2ecf20Sopenharmony_ci u64 lr_val; 8938c2ecf20Sopenharmony_ci int lr, lr_grp, grp; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci grp = __vgic_v3_get_group(vcpu); 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci lr = __vgic_v3_highest_priority_lr(vcpu, vmcr, &lr_val); 8988c2ecf20Sopenharmony_ci if (lr == -1) 8998c2ecf20Sopenharmony_ci goto spurious; 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci lr_grp = !!(lr_val & ICH_LR_GROUP); 9028c2ecf20Sopenharmony_ci if (lr_grp != grp) 9038c2ecf20Sopenharmony_ci lr_val = ICC_IAR1_EL1_SPURIOUS; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_cispurious: 9068c2ecf20Sopenharmony_ci vcpu_set_reg(vcpu, rt, lr_val & ICH_LR_VIRTUAL_ID_MASK); 9078c2ecf20Sopenharmony_ci} 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_cistatic void __vgic_v3_read_pmr(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 9108c2ecf20Sopenharmony_ci{ 9118c2ecf20Sopenharmony_ci vmcr &= ICH_VMCR_PMR_MASK; 9128c2ecf20Sopenharmony_ci vmcr >>= ICH_VMCR_PMR_SHIFT; 9138c2ecf20Sopenharmony_ci vcpu_set_reg(vcpu, rt, vmcr); 9148c2ecf20Sopenharmony_ci} 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_cistatic void __vgic_v3_write_pmr(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 9178c2ecf20Sopenharmony_ci{ 9188c2ecf20Sopenharmony_ci u32 val = vcpu_get_reg(vcpu, rt); 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci val <<= ICH_VMCR_PMR_SHIFT; 9218c2ecf20Sopenharmony_ci val &= ICH_VMCR_PMR_MASK; 9228c2ecf20Sopenharmony_ci vmcr &= ~ICH_VMCR_PMR_MASK; 9238c2ecf20Sopenharmony_ci vmcr |= val; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci write_gicreg(vmcr, ICH_VMCR_EL2); 9268c2ecf20Sopenharmony_ci} 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_cistatic void __vgic_v3_read_rpr(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 9298c2ecf20Sopenharmony_ci{ 9308c2ecf20Sopenharmony_ci u32 val = __vgic_v3_get_highest_active_priority(); 9318c2ecf20Sopenharmony_ci vcpu_set_reg(vcpu, rt, val); 9328c2ecf20Sopenharmony_ci} 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_cistatic void __vgic_v3_read_ctlr(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 9358c2ecf20Sopenharmony_ci{ 9368c2ecf20Sopenharmony_ci u32 vtr, val; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci vtr = read_gicreg(ICH_VTR_EL2); 9398c2ecf20Sopenharmony_ci /* PRIbits */ 9408c2ecf20Sopenharmony_ci val = ((vtr >> 29) & 7) << ICC_CTLR_EL1_PRI_BITS_SHIFT; 9418c2ecf20Sopenharmony_ci /* IDbits */ 9428c2ecf20Sopenharmony_ci val |= ((vtr >> 23) & 7) << ICC_CTLR_EL1_ID_BITS_SHIFT; 9438c2ecf20Sopenharmony_ci /* SEIS */ 9448c2ecf20Sopenharmony_ci val |= ((vtr >> 22) & 1) << ICC_CTLR_EL1_SEIS_SHIFT; 9458c2ecf20Sopenharmony_ci /* A3V */ 9468c2ecf20Sopenharmony_ci val |= ((vtr >> 21) & 1) << ICC_CTLR_EL1_A3V_SHIFT; 9478c2ecf20Sopenharmony_ci /* EOImode */ 9488c2ecf20Sopenharmony_ci val |= ((vmcr & ICH_VMCR_EOIM_MASK) >> ICH_VMCR_EOIM_SHIFT) << ICC_CTLR_EL1_EOImode_SHIFT; 9498c2ecf20Sopenharmony_ci /* CBPR */ 9508c2ecf20Sopenharmony_ci val |= (vmcr & ICH_VMCR_CBPR_MASK) >> ICH_VMCR_CBPR_SHIFT; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci vcpu_set_reg(vcpu, rt, val); 9538c2ecf20Sopenharmony_ci} 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_cistatic void __vgic_v3_write_ctlr(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 9568c2ecf20Sopenharmony_ci{ 9578c2ecf20Sopenharmony_ci u32 val = vcpu_get_reg(vcpu, rt); 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci if (val & ICC_CTLR_EL1_CBPR_MASK) 9608c2ecf20Sopenharmony_ci vmcr |= ICH_VMCR_CBPR_MASK; 9618c2ecf20Sopenharmony_ci else 9628c2ecf20Sopenharmony_ci vmcr &= ~ICH_VMCR_CBPR_MASK; 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci if (val & ICC_CTLR_EL1_EOImode_MASK) 9658c2ecf20Sopenharmony_ci vmcr |= ICH_VMCR_EOIM_MASK; 9668c2ecf20Sopenharmony_ci else 9678c2ecf20Sopenharmony_ci vmcr &= ~ICH_VMCR_EOIM_MASK; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci write_gicreg(vmcr, ICH_VMCR_EL2); 9708c2ecf20Sopenharmony_ci} 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ciint __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu) 9738c2ecf20Sopenharmony_ci{ 9748c2ecf20Sopenharmony_ci int rt; 9758c2ecf20Sopenharmony_ci u32 esr; 9768c2ecf20Sopenharmony_ci u32 vmcr; 9778c2ecf20Sopenharmony_ci void (*fn)(struct kvm_vcpu *, u32, int); 9788c2ecf20Sopenharmony_ci bool is_read; 9798c2ecf20Sopenharmony_ci u32 sysreg; 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci esr = kvm_vcpu_get_esr(vcpu); 9828c2ecf20Sopenharmony_ci if (vcpu_mode_is_32bit(vcpu)) { 9838c2ecf20Sopenharmony_ci if (!kvm_condition_valid(vcpu)) { 9848c2ecf20Sopenharmony_ci __kvm_skip_instr(vcpu); 9858c2ecf20Sopenharmony_ci return 1; 9868c2ecf20Sopenharmony_ci } 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci sysreg = esr_cp15_to_sysreg(esr); 9898c2ecf20Sopenharmony_ci } else { 9908c2ecf20Sopenharmony_ci sysreg = esr_sys64_to_sysreg(esr); 9918c2ecf20Sopenharmony_ci } 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ; 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci switch (sysreg) { 9968c2ecf20Sopenharmony_ci case SYS_ICC_IAR0_EL1: 9978c2ecf20Sopenharmony_ci case SYS_ICC_IAR1_EL1: 9988c2ecf20Sopenharmony_ci if (unlikely(!is_read)) 9998c2ecf20Sopenharmony_ci return 0; 10008c2ecf20Sopenharmony_ci fn = __vgic_v3_read_iar; 10018c2ecf20Sopenharmony_ci break; 10028c2ecf20Sopenharmony_ci case SYS_ICC_EOIR0_EL1: 10038c2ecf20Sopenharmony_ci case SYS_ICC_EOIR1_EL1: 10048c2ecf20Sopenharmony_ci if (unlikely(is_read)) 10058c2ecf20Sopenharmony_ci return 0; 10068c2ecf20Sopenharmony_ci fn = __vgic_v3_write_eoir; 10078c2ecf20Sopenharmony_ci break; 10088c2ecf20Sopenharmony_ci case SYS_ICC_IGRPEN1_EL1: 10098c2ecf20Sopenharmony_ci if (is_read) 10108c2ecf20Sopenharmony_ci fn = __vgic_v3_read_igrpen1; 10118c2ecf20Sopenharmony_ci else 10128c2ecf20Sopenharmony_ci fn = __vgic_v3_write_igrpen1; 10138c2ecf20Sopenharmony_ci break; 10148c2ecf20Sopenharmony_ci case SYS_ICC_BPR1_EL1: 10158c2ecf20Sopenharmony_ci if (is_read) 10168c2ecf20Sopenharmony_ci fn = __vgic_v3_read_bpr1; 10178c2ecf20Sopenharmony_ci else 10188c2ecf20Sopenharmony_ci fn = __vgic_v3_write_bpr1; 10198c2ecf20Sopenharmony_ci break; 10208c2ecf20Sopenharmony_ci case SYS_ICC_AP0Rn_EL1(0): 10218c2ecf20Sopenharmony_ci case SYS_ICC_AP1Rn_EL1(0): 10228c2ecf20Sopenharmony_ci if (is_read) 10238c2ecf20Sopenharmony_ci fn = __vgic_v3_read_apxr0; 10248c2ecf20Sopenharmony_ci else 10258c2ecf20Sopenharmony_ci fn = __vgic_v3_write_apxr0; 10268c2ecf20Sopenharmony_ci break; 10278c2ecf20Sopenharmony_ci case SYS_ICC_AP0Rn_EL1(1): 10288c2ecf20Sopenharmony_ci case SYS_ICC_AP1Rn_EL1(1): 10298c2ecf20Sopenharmony_ci if (is_read) 10308c2ecf20Sopenharmony_ci fn = __vgic_v3_read_apxr1; 10318c2ecf20Sopenharmony_ci else 10328c2ecf20Sopenharmony_ci fn = __vgic_v3_write_apxr1; 10338c2ecf20Sopenharmony_ci break; 10348c2ecf20Sopenharmony_ci case SYS_ICC_AP0Rn_EL1(2): 10358c2ecf20Sopenharmony_ci case SYS_ICC_AP1Rn_EL1(2): 10368c2ecf20Sopenharmony_ci if (is_read) 10378c2ecf20Sopenharmony_ci fn = __vgic_v3_read_apxr2; 10388c2ecf20Sopenharmony_ci else 10398c2ecf20Sopenharmony_ci fn = __vgic_v3_write_apxr2; 10408c2ecf20Sopenharmony_ci break; 10418c2ecf20Sopenharmony_ci case SYS_ICC_AP0Rn_EL1(3): 10428c2ecf20Sopenharmony_ci case SYS_ICC_AP1Rn_EL1(3): 10438c2ecf20Sopenharmony_ci if (is_read) 10448c2ecf20Sopenharmony_ci fn = __vgic_v3_read_apxr3; 10458c2ecf20Sopenharmony_ci else 10468c2ecf20Sopenharmony_ci fn = __vgic_v3_write_apxr3; 10478c2ecf20Sopenharmony_ci break; 10488c2ecf20Sopenharmony_ci case SYS_ICC_HPPIR0_EL1: 10498c2ecf20Sopenharmony_ci case SYS_ICC_HPPIR1_EL1: 10508c2ecf20Sopenharmony_ci if (unlikely(!is_read)) 10518c2ecf20Sopenharmony_ci return 0; 10528c2ecf20Sopenharmony_ci fn = __vgic_v3_read_hppir; 10538c2ecf20Sopenharmony_ci break; 10548c2ecf20Sopenharmony_ci case SYS_ICC_IGRPEN0_EL1: 10558c2ecf20Sopenharmony_ci if (is_read) 10568c2ecf20Sopenharmony_ci fn = __vgic_v3_read_igrpen0; 10578c2ecf20Sopenharmony_ci else 10588c2ecf20Sopenharmony_ci fn = __vgic_v3_write_igrpen0; 10598c2ecf20Sopenharmony_ci break; 10608c2ecf20Sopenharmony_ci case SYS_ICC_BPR0_EL1: 10618c2ecf20Sopenharmony_ci if (is_read) 10628c2ecf20Sopenharmony_ci fn = __vgic_v3_read_bpr0; 10638c2ecf20Sopenharmony_ci else 10648c2ecf20Sopenharmony_ci fn = __vgic_v3_write_bpr0; 10658c2ecf20Sopenharmony_ci break; 10668c2ecf20Sopenharmony_ci case SYS_ICC_DIR_EL1: 10678c2ecf20Sopenharmony_ci if (unlikely(is_read)) 10688c2ecf20Sopenharmony_ci return 0; 10698c2ecf20Sopenharmony_ci fn = __vgic_v3_write_dir; 10708c2ecf20Sopenharmony_ci break; 10718c2ecf20Sopenharmony_ci case SYS_ICC_RPR_EL1: 10728c2ecf20Sopenharmony_ci if (unlikely(!is_read)) 10738c2ecf20Sopenharmony_ci return 0; 10748c2ecf20Sopenharmony_ci fn = __vgic_v3_read_rpr; 10758c2ecf20Sopenharmony_ci break; 10768c2ecf20Sopenharmony_ci case SYS_ICC_CTLR_EL1: 10778c2ecf20Sopenharmony_ci if (is_read) 10788c2ecf20Sopenharmony_ci fn = __vgic_v3_read_ctlr; 10798c2ecf20Sopenharmony_ci else 10808c2ecf20Sopenharmony_ci fn = __vgic_v3_write_ctlr; 10818c2ecf20Sopenharmony_ci break; 10828c2ecf20Sopenharmony_ci case SYS_ICC_PMR_EL1: 10838c2ecf20Sopenharmony_ci if (is_read) 10848c2ecf20Sopenharmony_ci fn = __vgic_v3_read_pmr; 10858c2ecf20Sopenharmony_ci else 10868c2ecf20Sopenharmony_ci fn = __vgic_v3_write_pmr; 10878c2ecf20Sopenharmony_ci break; 10888c2ecf20Sopenharmony_ci default: 10898c2ecf20Sopenharmony_ci return 0; 10908c2ecf20Sopenharmony_ci } 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci vmcr = __vgic_v3_read_vmcr(); 10938c2ecf20Sopenharmony_ci rt = kvm_vcpu_sys_get_rt(vcpu); 10948c2ecf20Sopenharmony_ci fn(vcpu, vmcr, rt); 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci __kvm_skip_instr(vcpu); 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci return 1; 10998c2ecf20Sopenharmony_ci} 1100