19ed24f4bSMarc Zyngier // SPDX-License-Identifier: GPL-2.0-only 29ed24f4bSMarc Zyngier /* 39ed24f4bSMarc Zyngier * Copyright (C) 2012-2015 - ARM Ltd 49ed24f4bSMarc Zyngier * Author: Marc Zyngier <marc.zyngier@arm.com> 59ed24f4bSMarc Zyngier */ 69ed24f4bSMarc Zyngier 79ed24f4bSMarc Zyngier #include <linux/compiler.h> 89ed24f4bSMarc Zyngier #include <linux/irqchip/arm-gic-v3.h> 99ed24f4bSMarc Zyngier #include <linux/kvm_host.h> 109ed24f4bSMarc Zyngier 119ed24f4bSMarc Zyngier #include <asm/kvm_emulate.h> 129ed24f4bSMarc Zyngier #include <asm/kvm_hyp.h> 139ed24f4bSMarc Zyngier #include <asm/kvm_mmu.h> 149ed24f4bSMarc Zyngier 159ed24f4bSMarc Zyngier #define vtr_to_max_lr_idx(v) ((v) & 0xf) 169ed24f4bSMarc Zyngier #define vtr_to_nr_pre_bits(v) ((((u32)(v) >> 26) & 7) + 1) 179ed24f4bSMarc Zyngier #define vtr_to_nr_apr_regs(v) (1 << (vtr_to_nr_pre_bits(v) - 5)) 189ed24f4bSMarc Zyngier 19c50cb043SDavid Brazdil static u64 __gic_v3_get_lr(unsigned int lr) 209ed24f4bSMarc Zyngier { 219ed24f4bSMarc Zyngier switch (lr & 0xf) { 229ed24f4bSMarc Zyngier case 0: 239ed24f4bSMarc Zyngier return read_gicreg(ICH_LR0_EL2); 249ed24f4bSMarc Zyngier case 1: 259ed24f4bSMarc Zyngier return read_gicreg(ICH_LR1_EL2); 269ed24f4bSMarc Zyngier case 2: 279ed24f4bSMarc Zyngier return read_gicreg(ICH_LR2_EL2); 289ed24f4bSMarc Zyngier case 3: 299ed24f4bSMarc Zyngier return read_gicreg(ICH_LR3_EL2); 309ed24f4bSMarc Zyngier case 4: 319ed24f4bSMarc Zyngier return read_gicreg(ICH_LR4_EL2); 329ed24f4bSMarc Zyngier case 5: 339ed24f4bSMarc Zyngier return read_gicreg(ICH_LR5_EL2); 349ed24f4bSMarc Zyngier case 6: 359ed24f4bSMarc Zyngier return read_gicreg(ICH_LR6_EL2); 369ed24f4bSMarc Zyngier case 7: 379ed24f4bSMarc Zyngier return read_gicreg(ICH_LR7_EL2); 389ed24f4bSMarc Zyngier case 8: 399ed24f4bSMarc Zyngier return read_gicreg(ICH_LR8_EL2); 409ed24f4bSMarc Zyngier case 9: 419ed24f4bSMarc Zyngier return read_gicreg(ICH_LR9_EL2); 429ed24f4bSMarc Zyngier case 10: 439ed24f4bSMarc Zyngier return read_gicreg(ICH_LR10_EL2); 449ed24f4bSMarc Zyngier case 11: 459ed24f4bSMarc Zyngier return read_gicreg(ICH_LR11_EL2); 469ed24f4bSMarc Zyngier case 12: 479ed24f4bSMarc Zyngier return read_gicreg(ICH_LR12_EL2); 489ed24f4bSMarc Zyngier case 13: 499ed24f4bSMarc Zyngier return read_gicreg(ICH_LR13_EL2); 509ed24f4bSMarc Zyngier case 14: 519ed24f4bSMarc Zyngier return read_gicreg(ICH_LR14_EL2); 529ed24f4bSMarc Zyngier case 15: 539ed24f4bSMarc Zyngier return read_gicreg(ICH_LR15_EL2); 549ed24f4bSMarc Zyngier } 559ed24f4bSMarc Zyngier 569ed24f4bSMarc Zyngier unreachable(); 579ed24f4bSMarc Zyngier } 589ed24f4bSMarc Zyngier 59c50cb043SDavid Brazdil static void __gic_v3_set_lr(u64 val, int lr) 609ed24f4bSMarc Zyngier { 619ed24f4bSMarc Zyngier switch (lr & 0xf) { 629ed24f4bSMarc Zyngier case 0: 639ed24f4bSMarc Zyngier write_gicreg(val, ICH_LR0_EL2); 649ed24f4bSMarc Zyngier break; 659ed24f4bSMarc Zyngier case 1: 669ed24f4bSMarc Zyngier write_gicreg(val, ICH_LR1_EL2); 679ed24f4bSMarc Zyngier break; 689ed24f4bSMarc Zyngier case 2: 699ed24f4bSMarc Zyngier write_gicreg(val, ICH_LR2_EL2); 709ed24f4bSMarc Zyngier break; 719ed24f4bSMarc Zyngier case 3: 729ed24f4bSMarc Zyngier write_gicreg(val, ICH_LR3_EL2); 739ed24f4bSMarc Zyngier break; 749ed24f4bSMarc Zyngier case 4: 759ed24f4bSMarc Zyngier write_gicreg(val, ICH_LR4_EL2); 769ed24f4bSMarc Zyngier break; 779ed24f4bSMarc Zyngier case 5: 789ed24f4bSMarc Zyngier write_gicreg(val, ICH_LR5_EL2); 799ed24f4bSMarc Zyngier break; 809ed24f4bSMarc Zyngier case 6: 819ed24f4bSMarc Zyngier write_gicreg(val, ICH_LR6_EL2); 829ed24f4bSMarc Zyngier break; 839ed24f4bSMarc Zyngier case 7: 849ed24f4bSMarc Zyngier write_gicreg(val, ICH_LR7_EL2); 859ed24f4bSMarc Zyngier break; 869ed24f4bSMarc Zyngier case 8: 879ed24f4bSMarc Zyngier write_gicreg(val, ICH_LR8_EL2); 889ed24f4bSMarc Zyngier break; 899ed24f4bSMarc Zyngier case 9: 909ed24f4bSMarc Zyngier write_gicreg(val, ICH_LR9_EL2); 919ed24f4bSMarc Zyngier break; 929ed24f4bSMarc Zyngier case 10: 939ed24f4bSMarc Zyngier write_gicreg(val, ICH_LR10_EL2); 949ed24f4bSMarc Zyngier break; 959ed24f4bSMarc Zyngier case 11: 969ed24f4bSMarc Zyngier write_gicreg(val, ICH_LR11_EL2); 979ed24f4bSMarc Zyngier break; 989ed24f4bSMarc Zyngier case 12: 999ed24f4bSMarc Zyngier write_gicreg(val, ICH_LR12_EL2); 1009ed24f4bSMarc Zyngier break; 1019ed24f4bSMarc Zyngier case 13: 1029ed24f4bSMarc Zyngier write_gicreg(val, ICH_LR13_EL2); 1039ed24f4bSMarc Zyngier break; 1049ed24f4bSMarc Zyngier case 14: 1059ed24f4bSMarc Zyngier write_gicreg(val, ICH_LR14_EL2); 1069ed24f4bSMarc Zyngier break; 1079ed24f4bSMarc Zyngier case 15: 1089ed24f4bSMarc Zyngier write_gicreg(val, ICH_LR15_EL2); 1099ed24f4bSMarc Zyngier break; 1109ed24f4bSMarc Zyngier } 1119ed24f4bSMarc Zyngier } 1129ed24f4bSMarc Zyngier 113c50cb043SDavid Brazdil static void __vgic_v3_write_ap0rn(u32 val, int n) 1149ed24f4bSMarc Zyngier { 1159ed24f4bSMarc Zyngier switch (n) { 1169ed24f4bSMarc Zyngier case 0: 1179ed24f4bSMarc Zyngier write_gicreg(val, ICH_AP0R0_EL2); 1189ed24f4bSMarc Zyngier break; 1199ed24f4bSMarc Zyngier case 1: 1209ed24f4bSMarc Zyngier write_gicreg(val, ICH_AP0R1_EL2); 1219ed24f4bSMarc Zyngier break; 1229ed24f4bSMarc Zyngier case 2: 1239ed24f4bSMarc Zyngier write_gicreg(val, ICH_AP0R2_EL2); 1249ed24f4bSMarc Zyngier break; 1259ed24f4bSMarc Zyngier case 3: 1269ed24f4bSMarc Zyngier write_gicreg(val, ICH_AP0R3_EL2); 1279ed24f4bSMarc Zyngier break; 1289ed24f4bSMarc Zyngier } 1299ed24f4bSMarc Zyngier } 1309ed24f4bSMarc Zyngier 131c50cb043SDavid Brazdil static void __vgic_v3_write_ap1rn(u32 val, int n) 1329ed24f4bSMarc Zyngier { 1339ed24f4bSMarc Zyngier switch (n) { 1349ed24f4bSMarc Zyngier case 0: 1359ed24f4bSMarc Zyngier write_gicreg(val, ICH_AP1R0_EL2); 1369ed24f4bSMarc Zyngier break; 1379ed24f4bSMarc Zyngier case 1: 1389ed24f4bSMarc Zyngier write_gicreg(val, ICH_AP1R1_EL2); 1399ed24f4bSMarc Zyngier break; 1409ed24f4bSMarc Zyngier case 2: 1419ed24f4bSMarc Zyngier write_gicreg(val, ICH_AP1R2_EL2); 1429ed24f4bSMarc Zyngier break; 1439ed24f4bSMarc Zyngier case 3: 1449ed24f4bSMarc Zyngier write_gicreg(val, ICH_AP1R3_EL2); 1459ed24f4bSMarc Zyngier break; 1469ed24f4bSMarc Zyngier } 1479ed24f4bSMarc Zyngier } 1489ed24f4bSMarc Zyngier 149c50cb043SDavid Brazdil static u32 __vgic_v3_read_ap0rn(int n) 1509ed24f4bSMarc Zyngier { 1519ed24f4bSMarc Zyngier u32 val; 1529ed24f4bSMarc Zyngier 1539ed24f4bSMarc Zyngier switch (n) { 1549ed24f4bSMarc Zyngier case 0: 1559ed24f4bSMarc Zyngier val = read_gicreg(ICH_AP0R0_EL2); 1569ed24f4bSMarc Zyngier break; 1579ed24f4bSMarc Zyngier case 1: 1589ed24f4bSMarc Zyngier val = read_gicreg(ICH_AP0R1_EL2); 1599ed24f4bSMarc Zyngier break; 1609ed24f4bSMarc Zyngier case 2: 1619ed24f4bSMarc Zyngier val = read_gicreg(ICH_AP0R2_EL2); 1629ed24f4bSMarc Zyngier break; 1639ed24f4bSMarc Zyngier case 3: 1649ed24f4bSMarc Zyngier val = read_gicreg(ICH_AP0R3_EL2); 1659ed24f4bSMarc Zyngier break; 1669ed24f4bSMarc Zyngier default: 1679ed24f4bSMarc Zyngier unreachable(); 1689ed24f4bSMarc Zyngier } 1699ed24f4bSMarc Zyngier 1709ed24f4bSMarc Zyngier return val; 1719ed24f4bSMarc Zyngier } 1729ed24f4bSMarc Zyngier 173c50cb043SDavid Brazdil static u32 __vgic_v3_read_ap1rn(int n) 1749ed24f4bSMarc Zyngier { 1759ed24f4bSMarc Zyngier u32 val; 1769ed24f4bSMarc Zyngier 1779ed24f4bSMarc Zyngier switch (n) { 1789ed24f4bSMarc Zyngier case 0: 1799ed24f4bSMarc Zyngier val = read_gicreg(ICH_AP1R0_EL2); 1809ed24f4bSMarc Zyngier break; 1819ed24f4bSMarc Zyngier case 1: 1829ed24f4bSMarc Zyngier val = read_gicreg(ICH_AP1R1_EL2); 1839ed24f4bSMarc Zyngier break; 1849ed24f4bSMarc Zyngier case 2: 1859ed24f4bSMarc Zyngier val = read_gicreg(ICH_AP1R2_EL2); 1869ed24f4bSMarc Zyngier break; 1879ed24f4bSMarc Zyngier case 3: 1889ed24f4bSMarc Zyngier val = read_gicreg(ICH_AP1R3_EL2); 1899ed24f4bSMarc Zyngier break; 1909ed24f4bSMarc Zyngier default: 1919ed24f4bSMarc Zyngier unreachable(); 1929ed24f4bSMarc Zyngier } 1939ed24f4bSMarc Zyngier 1949ed24f4bSMarc Zyngier return val; 1959ed24f4bSMarc Zyngier } 1969ed24f4bSMarc Zyngier 197c50cb043SDavid Brazdil void __vgic_v3_save_state(struct vgic_v3_cpu_if *cpu_if) 1989ed24f4bSMarc Zyngier { 199fc5d1f1aSChristoffer Dall u64 used_lrs = cpu_if->used_lrs; 2009ed24f4bSMarc Zyngier 2019ed24f4bSMarc Zyngier /* 2029ed24f4bSMarc Zyngier * Make sure stores to the GIC via the memory mapped interface 2039ed24f4bSMarc Zyngier * are now visible to the system register interface when reading the 2049ed24f4bSMarc Zyngier * LRs, and when reading back the VMCR on non-VHE systems. 2059ed24f4bSMarc Zyngier */ 2069ed24f4bSMarc Zyngier if (used_lrs || !has_vhe()) { 2079ed24f4bSMarc Zyngier if (!cpu_if->vgic_sre) { 2089ed24f4bSMarc Zyngier dsb(sy); 2099ed24f4bSMarc Zyngier isb(); 2109ed24f4bSMarc Zyngier } 2119ed24f4bSMarc Zyngier } 2129ed24f4bSMarc Zyngier 2139ed24f4bSMarc Zyngier if (used_lrs || cpu_if->its_vpe.its_vm) { 2149ed24f4bSMarc Zyngier int i; 2159ed24f4bSMarc Zyngier u32 elrsr; 2169ed24f4bSMarc Zyngier 2179ed24f4bSMarc Zyngier elrsr = read_gicreg(ICH_ELRSR_EL2); 2189ed24f4bSMarc Zyngier 2199ed24f4bSMarc Zyngier write_gicreg(cpu_if->vgic_hcr & ~ICH_HCR_EN, ICH_HCR_EL2); 2209ed24f4bSMarc Zyngier 2219ed24f4bSMarc Zyngier for (i = 0; i < used_lrs; i++) { 2229ed24f4bSMarc Zyngier if (elrsr & (1 << i)) 2239ed24f4bSMarc Zyngier cpu_if->vgic_lr[i] &= ~ICH_LR_STATE; 2249ed24f4bSMarc Zyngier else 2259ed24f4bSMarc Zyngier cpu_if->vgic_lr[i] = __gic_v3_get_lr(i); 2269ed24f4bSMarc Zyngier 2279ed24f4bSMarc Zyngier __gic_v3_set_lr(0, i); 2289ed24f4bSMarc Zyngier } 2299ed24f4bSMarc Zyngier } 2309ed24f4bSMarc Zyngier } 2319ed24f4bSMarc Zyngier 232c50cb043SDavid Brazdil void __vgic_v3_restore_state(struct vgic_v3_cpu_if *cpu_if) 2339ed24f4bSMarc Zyngier { 234fc5d1f1aSChristoffer Dall u64 used_lrs = cpu_if->used_lrs; 2359ed24f4bSMarc Zyngier int i; 2369ed24f4bSMarc Zyngier 2379ed24f4bSMarc Zyngier if (used_lrs || cpu_if->its_vpe.its_vm) { 2389ed24f4bSMarc Zyngier write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2); 2399ed24f4bSMarc Zyngier 2409ed24f4bSMarc Zyngier for (i = 0; i < used_lrs; i++) 2419ed24f4bSMarc Zyngier __gic_v3_set_lr(cpu_if->vgic_lr[i], i); 2429ed24f4bSMarc Zyngier } 2439ed24f4bSMarc Zyngier 2449ed24f4bSMarc Zyngier /* 2459ed24f4bSMarc Zyngier * Ensure that writes to the LRs, and on non-VHE systems ensure that 2469ed24f4bSMarc Zyngier * the write to the VMCR in __vgic_v3_activate_traps(), will have 2479ed24f4bSMarc Zyngier * reached the (re)distributors. This ensure the guest will read the 2489ed24f4bSMarc Zyngier * correct values from the memory-mapped interface. 2499ed24f4bSMarc Zyngier */ 2509ed24f4bSMarc Zyngier if (used_lrs || !has_vhe()) { 2519ed24f4bSMarc Zyngier if (!cpu_if->vgic_sre) { 2529ed24f4bSMarc Zyngier isb(); 2539ed24f4bSMarc Zyngier dsb(sy); 2549ed24f4bSMarc Zyngier } 2559ed24f4bSMarc Zyngier } 2569ed24f4bSMarc Zyngier } 2579ed24f4bSMarc Zyngier 258c50cb043SDavid Brazdil void __vgic_v3_activate_traps(struct vgic_v3_cpu_if *cpu_if) 2599ed24f4bSMarc Zyngier { 2609ed24f4bSMarc Zyngier /* 2619ed24f4bSMarc Zyngier * VFIQEn is RES1 if ICC_SRE_EL1.SRE is 1. This causes a 2629ed24f4bSMarc Zyngier * Group0 interrupt (as generated in GICv2 mode) to be 2639ed24f4bSMarc Zyngier * delivered as a FIQ to the guest, with potentially fatal 2649ed24f4bSMarc Zyngier * consequences. So we must make sure that ICC_SRE_EL1 has 2659ed24f4bSMarc Zyngier * been actually programmed with the value we want before 2669ed24f4bSMarc Zyngier * starting to mess with the rest of the GIC, and VMCR_EL2 in 2679ed24f4bSMarc Zyngier * particular. This logic must be called before 2689ed24f4bSMarc Zyngier * __vgic_v3_restore_state(). 2699ed24f4bSMarc Zyngier */ 2709ed24f4bSMarc Zyngier if (!cpu_if->vgic_sre) { 2719ed24f4bSMarc Zyngier write_gicreg(0, ICC_SRE_EL1); 2729ed24f4bSMarc Zyngier isb(); 2739ed24f4bSMarc Zyngier write_gicreg(cpu_if->vgic_vmcr, ICH_VMCR_EL2); 2749ed24f4bSMarc Zyngier 2759ed24f4bSMarc Zyngier 2769ed24f4bSMarc Zyngier if (has_vhe()) { 2779ed24f4bSMarc Zyngier /* 2789ed24f4bSMarc Zyngier * Ensure that the write to the VMCR will have reached 2799ed24f4bSMarc Zyngier * the (re)distributors. This ensure the guest will 2809ed24f4bSMarc Zyngier * read the correct values from the memory-mapped 2819ed24f4bSMarc Zyngier * interface. 2829ed24f4bSMarc Zyngier */ 2839ed24f4bSMarc Zyngier isb(); 2849ed24f4bSMarc Zyngier dsb(sy); 2859ed24f4bSMarc Zyngier } 2869ed24f4bSMarc Zyngier } 2879ed24f4bSMarc Zyngier 2889ed24f4bSMarc Zyngier /* 2899ed24f4bSMarc Zyngier * Prevent the guest from touching the GIC system registers if 2909ed24f4bSMarc Zyngier * SRE isn't enabled for GICv3 emulation. 2919ed24f4bSMarc Zyngier */ 2929ed24f4bSMarc Zyngier write_gicreg(read_gicreg(ICC_SRE_EL2) & ~ICC_SRE_EL2_ENABLE, 2939ed24f4bSMarc Zyngier ICC_SRE_EL2); 2949ed24f4bSMarc Zyngier 2959ed24f4bSMarc Zyngier /* 2969ed24f4bSMarc Zyngier * If we need to trap system registers, we must write 2979ed24f4bSMarc Zyngier * ICH_HCR_EL2 anyway, even if no interrupts are being 2989ed24f4bSMarc Zyngier * injected, 2999ed24f4bSMarc Zyngier */ 3009ed24f4bSMarc Zyngier if (static_branch_unlikely(&vgic_v3_cpuif_trap) || 3019ed24f4bSMarc Zyngier cpu_if->its_vpe.its_vm) 3029ed24f4bSMarc Zyngier write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2); 3039ed24f4bSMarc Zyngier } 3049ed24f4bSMarc Zyngier 305c50cb043SDavid Brazdil void __vgic_v3_deactivate_traps(struct vgic_v3_cpu_if *cpu_if) 3069ed24f4bSMarc Zyngier { 3079ed24f4bSMarc Zyngier u64 val; 3089ed24f4bSMarc Zyngier 3099ed24f4bSMarc Zyngier if (!cpu_if->vgic_sre) { 3109ed24f4bSMarc Zyngier cpu_if->vgic_vmcr = read_gicreg(ICH_VMCR_EL2); 3119ed24f4bSMarc Zyngier } 3129ed24f4bSMarc Zyngier 3139ed24f4bSMarc Zyngier val = read_gicreg(ICC_SRE_EL2); 3149ed24f4bSMarc Zyngier write_gicreg(val | ICC_SRE_EL2_ENABLE, ICC_SRE_EL2); 3159ed24f4bSMarc Zyngier 3169ed24f4bSMarc Zyngier if (!cpu_if->vgic_sre) { 3179ed24f4bSMarc Zyngier /* Make sure ENABLE is set at EL2 before setting SRE at EL1 */ 3189ed24f4bSMarc Zyngier isb(); 3199ed24f4bSMarc Zyngier write_gicreg(1, ICC_SRE_EL1); 3209ed24f4bSMarc Zyngier } 3219ed24f4bSMarc Zyngier 3229ed24f4bSMarc Zyngier /* 3239ed24f4bSMarc Zyngier * If we were trapping system registers, we enabled the VGIC even if 3249ed24f4bSMarc Zyngier * no interrupts were being injected, and we disable it again here. 3259ed24f4bSMarc Zyngier */ 3269ed24f4bSMarc Zyngier if (static_branch_unlikely(&vgic_v3_cpuif_trap) || 3279ed24f4bSMarc Zyngier cpu_if->its_vpe.its_vm) 3289ed24f4bSMarc Zyngier write_gicreg(0, ICH_HCR_EL2); 3299ed24f4bSMarc Zyngier } 3309ed24f4bSMarc Zyngier 331c50cb043SDavid Brazdil void __vgic_v3_save_aprs(struct vgic_v3_cpu_if *cpu_if) 3329ed24f4bSMarc Zyngier { 3339ed24f4bSMarc Zyngier u64 val; 3349ed24f4bSMarc Zyngier u32 nr_pre_bits; 3359ed24f4bSMarc Zyngier 3369ed24f4bSMarc Zyngier val = read_gicreg(ICH_VTR_EL2); 3379ed24f4bSMarc Zyngier nr_pre_bits = vtr_to_nr_pre_bits(val); 3389ed24f4bSMarc Zyngier 3399ed24f4bSMarc Zyngier switch (nr_pre_bits) { 3409ed24f4bSMarc Zyngier case 7: 3419ed24f4bSMarc Zyngier cpu_if->vgic_ap0r[3] = __vgic_v3_read_ap0rn(3); 3429ed24f4bSMarc Zyngier cpu_if->vgic_ap0r[2] = __vgic_v3_read_ap0rn(2); 343df561f66SGustavo A. R. Silva fallthrough; 3449ed24f4bSMarc Zyngier case 6: 3459ed24f4bSMarc Zyngier cpu_if->vgic_ap0r[1] = __vgic_v3_read_ap0rn(1); 346df561f66SGustavo A. R. Silva fallthrough; 3479ed24f4bSMarc Zyngier default: 3489ed24f4bSMarc Zyngier cpu_if->vgic_ap0r[0] = __vgic_v3_read_ap0rn(0); 3499ed24f4bSMarc Zyngier } 3509ed24f4bSMarc Zyngier 3519ed24f4bSMarc Zyngier switch (nr_pre_bits) { 3529ed24f4bSMarc Zyngier case 7: 3539ed24f4bSMarc Zyngier cpu_if->vgic_ap1r[3] = __vgic_v3_read_ap1rn(3); 3549ed24f4bSMarc Zyngier cpu_if->vgic_ap1r[2] = __vgic_v3_read_ap1rn(2); 355df561f66SGustavo A. R. Silva fallthrough; 3569ed24f4bSMarc Zyngier case 6: 3579ed24f4bSMarc Zyngier cpu_if->vgic_ap1r[1] = __vgic_v3_read_ap1rn(1); 358df561f66SGustavo A. R. Silva fallthrough; 3599ed24f4bSMarc Zyngier default: 3609ed24f4bSMarc Zyngier cpu_if->vgic_ap1r[0] = __vgic_v3_read_ap1rn(0); 3619ed24f4bSMarc Zyngier } 3629ed24f4bSMarc Zyngier } 3639ed24f4bSMarc Zyngier 364c50cb043SDavid Brazdil void __vgic_v3_restore_aprs(struct vgic_v3_cpu_if *cpu_if) 3659ed24f4bSMarc Zyngier { 3669ed24f4bSMarc Zyngier u64 val; 3679ed24f4bSMarc Zyngier u32 nr_pre_bits; 3689ed24f4bSMarc Zyngier 3699ed24f4bSMarc Zyngier val = read_gicreg(ICH_VTR_EL2); 3709ed24f4bSMarc Zyngier nr_pre_bits = vtr_to_nr_pre_bits(val); 3719ed24f4bSMarc Zyngier 3729ed24f4bSMarc Zyngier switch (nr_pre_bits) { 3739ed24f4bSMarc Zyngier case 7: 3749ed24f4bSMarc Zyngier __vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[3], 3); 3759ed24f4bSMarc Zyngier __vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[2], 2); 376df561f66SGustavo A. R. Silva fallthrough; 3779ed24f4bSMarc Zyngier case 6: 3789ed24f4bSMarc Zyngier __vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[1], 1); 379df561f66SGustavo A. R. Silva fallthrough; 3809ed24f4bSMarc Zyngier default: 3819ed24f4bSMarc Zyngier __vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[0], 0); 3829ed24f4bSMarc Zyngier } 3839ed24f4bSMarc Zyngier 3849ed24f4bSMarc Zyngier switch (nr_pre_bits) { 3859ed24f4bSMarc Zyngier case 7: 3869ed24f4bSMarc Zyngier __vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[3], 3); 3879ed24f4bSMarc Zyngier __vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[2], 2); 388df561f66SGustavo A. R. Silva fallthrough; 3899ed24f4bSMarc Zyngier case 6: 3909ed24f4bSMarc Zyngier __vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[1], 1); 391df561f66SGustavo A. R. Silva fallthrough; 3929ed24f4bSMarc Zyngier default: 3939ed24f4bSMarc Zyngier __vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[0], 0); 3949ed24f4bSMarc Zyngier } 3959ed24f4bSMarc Zyngier } 3969ed24f4bSMarc Zyngier 397c50cb043SDavid Brazdil void __vgic_v3_init_lrs(void) 3989ed24f4bSMarc Zyngier { 3999ed24f4bSMarc Zyngier int max_lr_idx = vtr_to_max_lr_idx(read_gicreg(ICH_VTR_EL2)); 4009ed24f4bSMarc Zyngier int i; 4019ed24f4bSMarc Zyngier 4029ed24f4bSMarc Zyngier for (i = 0; i <= max_lr_idx; i++) 4039ed24f4bSMarc Zyngier __gic_v3_set_lr(0, i); 4049ed24f4bSMarc Zyngier } 4059ed24f4bSMarc Zyngier 406c50cb043SDavid Brazdil u64 __vgic_v3_get_ich_vtr_el2(void) 4079ed24f4bSMarc Zyngier { 4089ed24f4bSMarc Zyngier return read_gicreg(ICH_VTR_EL2); 4099ed24f4bSMarc Zyngier } 4109ed24f4bSMarc Zyngier 411c50cb043SDavid Brazdil u64 __vgic_v3_read_vmcr(void) 4129ed24f4bSMarc Zyngier { 4139ed24f4bSMarc Zyngier return read_gicreg(ICH_VMCR_EL2); 4149ed24f4bSMarc Zyngier } 4159ed24f4bSMarc Zyngier 416c50cb043SDavid Brazdil void __vgic_v3_write_vmcr(u32 vmcr) 4179ed24f4bSMarc Zyngier { 4189ed24f4bSMarc Zyngier write_gicreg(vmcr, ICH_VMCR_EL2); 4199ed24f4bSMarc Zyngier } 4209ed24f4bSMarc Zyngier 421c50cb043SDavid Brazdil static int __vgic_v3_bpr_min(void) 4229ed24f4bSMarc Zyngier { 4239ed24f4bSMarc Zyngier /* See Pseudocode for VPriorityGroup */ 4249ed24f4bSMarc Zyngier return 8 - vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2)); 4259ed24f4bSMarc Zyngier } 4269ed24f4bSMarc Zyngier 427c50cb043SDavid Brazdil static int __vgic_v3_get_group(struct kvm_vcpu *vcpu) 4289ed24f4bSMarc Zyngier { 4293a949f4cSGavin Shan u32 esr = kvm_vcpu_get_esr(vcpu); 4309ed24f4bSMarc Zyngier u8 crm = (esr & ESR_ELx_SYS64_ISS_CRM_MASK) >> ESR_ELx_SYS64_ISS_CRM_SHIFT; 4319ed24f4bSMarc Zyngier 4329ed24f4bSMarc Zyngier return crm != 8; 4339ed24f4bSMarc Zyngier } 4349ed24f4bSMarc Zyngier 4359ed24f4bSMarc Zyngier #define GICv3_IDLE_PRIORITY 0xff 4369ed24f4bSMarc Zyngier 437c50cb043SDavid Brazdil static int __vgic_v3_highest_priority_lr(struct kvm_vcpu *vcpu, u32 vmcr, 4389ed24f4bSMarc Zyngier u64 *lr_val) 4399ed24f4bSMarc Zyngier { 440fc5d1f1aSChristoffer Dall unsigned int used_lrs = vcpu->arch.vgic_cpu.vgic_v3.used_lrs; 4419ed24f4bSMarc Zyngier u8 priority = GICv3_IDLE_PRIORITY; 4429ed24f4bSMarc Zyngier int i, lr = -1; 4439ed24f4bSMarc Zyngier 4449ed24f4bSMarc Zyngier for (i = 0; i < used_lrs; i++) { 4459ed24f4bSMarc Zyngier u64 val = __gic_v3_get_lr(i); 4469ed24f4bSMarc Zyngier u8 lr_prio = (val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT; 4479ed24f4bSMarc Zyngier 4489ed24f4bSMarc Zyngier /* Not pending in the state? */ 4499ed24f4bSMarc Zyngier if ((val & ICH_LR_STATE) != ICH_LR_PENDING_BIT) 4509ed24f4bSMarc Zyngier continue; 4519ed24f4bSMarc Zyngier 4529ed24f4bSMarc Zyngier /* Group-0 interrupt, but Group-0 disabled? */ 4539ed24f4bSMarc Zyngier if (!(val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG0_MASK)) 4549ed24f4bSMarc Zyngier continue; 4559ed24f4bSMarc Zyngier 4569ed24f4bSMarc Zyngier /* Group-1 interrupt, but Group-1 disabled? */ 4579ed24f4bSMarc Zyngier if ((val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG1_MASK)) 4589ed24f4bSMarc Zyngier continue; 4599ed24f4bSMarc Zyngier 4609ed24f4bSMarc Zyngier /* Not the highest priority? */ 4619ed24f4bSMarc Zyngier if (lr_prio >= priority) 4629ed24f4bSMarc Zyngier continue; 4639ed24f4bSMarc Zyngier 4649ed24f4bSMarc Zyngier /* This is a candidate */ 4659ed24f4bSMarc Zyngier priority = lr_prio; 4669ed24f4bSMarc Zyngier *lr_val = val; 4679ed24f4bSMarc Zyngier lr = i; 4689ed24f4bSMarc Zyngier } 4699ed24f4bSMarc Zyngier 4709ed24f4bSMarc Zyngier if (lr == -1) 4719ed24f4bSMarc Zyngier *lr_val = ICC_IAR1_EL1_SPURIOUS; 4729ed24f4bSMarc Zyngier 4739ed24f4bSMarc Zyngier return lr; 4749ed24f4bSMarc Zyngier } 4759ed24f4bSMarc Zyngier 476c50cb043SDavid Brazdil static int __vgic_v3_find_active_lr(struct kvm_vcpu *vcpu, int intid, 477c50cb043SDavid Brazdil u64 *lr_val) 4789ed24f4bSMarc Zyngier { 479fc5d1f1aSChristoffer Dall unsigned int used_lrs = vcpu->arch.vgic_cpu.vgic_v3.used_lrs; 4809ed24f4bSMarc Zyngier int i; 4819ed24f4bSMarc Zyngier 4829ed24f4bSMarc Zyngier for (i = 0; i < used_lrs; i++) { 4839ed24f4bSMarc Zyngier u64 val = __gic_v3_get_lr(i); 4849ed24f4bSMarc Zyngier 4859ed24f4bSMarc Zyngier if ((val & ICH_LR_VIRTUAL_ID_MASK) == intid && 4869ed24f4bSMarc Zyngier (val & ICH_LR_ACTIVE_BIT)) { 4879ed24f4bSMarc Zyngier *lr_val = val; 4889ed24f4bSMarc Zyngier return i; 4899ed24f4bSMarc Zyngier } 4909ed24f4bSMarc Zyngier } 4919ed24f4bSMarc Zyngier 4929ed24f4bSMarc Zyngier *lr_val = ICC_IAR1_EL1_SPURIOUS; 4939ed24f4bSMarc Zyngier return -1; 4949ed24f4bSMarc Zyngier } 4959ed24f4bSMarc Zyngier 496c50cb043SDavid Brazdil static int __vgic_v3_get_highest_active_priority(void) 4979ed24f4bSMarc Zyngier { 4989ed24f4bSMarc Zyngier u8 nr_apr_regs = vtr_to_nr_apr_regs(read_gicreg(ICH_VTR_EL2)); 4999ed24f4bSMarc Zyngier u32 hap = 0; 5009ed24f4bSMarc Zyngier int i; 5019ed24f4bSMarc Zyngier 5029ed24f4bSMarc Zyngier for (i = 0; i < nr_apr_regs; i++) { 5039ed24f4bSMarc Zyngier u32 val; 5049ed24f4bSMarc Zyngier 5059ed24f4bSMarc Zyngier /* 5069ed24f4bSMarc Zyngier * The ICH_AP0Rn_EL2 and ICH_AP1Rn_EL2 registers 5079ed24f4bSMarc Zyngier * contain the active priority levels for this VCPU 5089ed24f4bSMarc Zyngier * for the maximum number of supported priority 5099ed24f4bSMarc Zyngier * levels, and we return the full priority level only 5109ed24f4bSMarc Zyngier * if the BPR is programmed to its minimum, otherwise 5119ed24f4bSMarc Zyngier * we return a combination of the priority level and 5129ed24f4bSMarc Zyngier * subpriority, as determined by the setting of the 5139ed24f4bSMarc Zyngier * BPR, but without the full subpriority. 5149ed24f4bSMarc Zyngier */ 5159ed24f4bSMarc Zyngier val = __vgic_v3_read_ap0rn(i); 5169ed24f4bSMarc Zyngier val |= __vgic_v3_read_ap1rn(i); 5179ed24f4bSMarc Zyngier if (!val) { 5189ed24f4bSMarc Zyngier hap += 32; 5199ed24f4bSMarc Zyngier continue; 5209ed24f4bSMarc Zyngier } 5219ed24f4bSMarc Zyngier 5229ed24f4bSMarc Zyngier return (hap + __ffs(val)) << __vgic_v3_bpr_min(); 5239ed24f4bSMarc Zyngier } 5249ed24f4bSMarc Zyngier 5259ed24f4bSMarc Zyngier return GICv3_IDLE_PRIORITY; 5269ed24f4bSMarc Zyngier } 5279ed24f4bSMarc Zyngier 528c50cb043SDavid Brazdil static unsigned int __vgic_v3_get_bpr0(u32 vmcr) 5299ed24f4bSMarc Zyngier { 5309ed24f4bSMarc Zyngier return (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT; 5319ed24f4bSMarc Zyngier } 5329ed24f4bSMarc Zyngier 533c50cb043SDavid Brazdil static unsigned int __vgic_v3_get_bpr1(u32 vmcr) 5349ed24f4bSMarc Zyngier { 5359ed24f4bSMarc Zyngier unsigned int bpr; 5369ed24f4bSMarc Zyngier 5379ed24f4bSMarc Zyngier if (vmcr & ICH_VMCR_CBPR_MASK) { 5389ed24f4bSMarc Zyngier bpr = __vgic_v3_get_bpr0(vmcr); 5399ed24f4bSMarc Zyngier if (bpr < 7) 5409ed24f4bSMarc Zyngier bpr++; 5419ed24f4bSMarc Zyngier } else { 5429ed24f4bSMarc Zyngier bpr = (vmcr & ICH_VMCR_BPR1_MASK) >> ICH_VMCR_BPR1_SHIFT; 5439ed24f4bSMarc Zyngier } 5449ed24f4bSMarc Zyngier 5459ed24f4bSMarc Zyngier return bpr; 5469ed24f4bSMarc Zyngier } 5479ed24f4bSMarc Zyngier 5489ed24f4bSMarc Zyngier /* 5499ed24f4bSMarc Zyngier * Convert a priority to a preemption level, taking the relevant BPR 5509ed24f4bSMarc Zyngier * into account by zeroing the sub-priority bits. 5519ed24f4bSMarc Zyngier */ 552c50cb043SDavid Brazdil static u8 __vgic_v3_pri_to_pre(u8 pri, u32 vmcr, int grp) 5539ed24f4bSMarc Zyngier { 5549ed24f4bSMarc Zyngier unsigned int bpr; 5559ed24f4bSMarc Zyngier 5569ed24f4bSMarc Zyngier if (!grp) 5579ed24f4bSMarc Zyngier bpr = __vgic_v3_get_bpr0(vmcr) + 1; 5589ed24f4bSMarc Zyngier else 5599ed24f4bSMarc Zyngier bpr = __vgic_v3_get_bpr1(vmcr); 5609ed24f4bSMarc Zyngier 5619ed24f4bSMarc Zyngier return pri & (GENMASK(7, 0) << bpr); 5629ed24f4bSMarc Zyngier } 5639ed24f4bSMarc Zyngier 5649ed24f4bSMarc Zyngier /* 5659ed24f4bSMarc Zyngier * The priority value is independent of any of the BPR values, so we 566656012c7SFuad Tabba * normalize it using the minimal BPR value. This guarantees that no 5679ed24f4bSMarc Zyngier * matter what the guest does with its BPR, we can always set/get the 5689ed24f4bSMarc Zyngier * same value of a priority. 5699ed24f4bSMarc Zyngier */ 570c50cb043SDavid Brazdil static void __vgic_v3_set_active_priority(u8 pri, u32 vmcr, int grp) 5719ed24f4bSMarc Zyngier { 5729ed24f4bSMarc Zyngier u8 pre, ap; 5739ed24f4bSMarc Zyngier u32 val; 5749ed24f4bSMarc Zyngier int apr; 5759ed24f4bSMarc Zyngier 5769ed24f4bSMarc Zyngier pre = __vgic_v3_pri_to_pre(pri, vmcr, grp); 5779ed24f4bSMarc Zyngier ap = pre >> __vgic_v3_bpr_min(); 5789ed24f4bSMarc Zyngier apr = ap / 32; 5799ed24f4bSMarc Zyngier 5809ed24f4bSMarc Zyngier if (!grp) { 5819ed24f4bSMarc Zyngier val = __vgic_v3_read_ap0rn(apr); 5829ed24f4bSMarc Zyngier __vgic_v3_write_ap0rn(val | BIT(ap % 32), apr); 5839ed24f4bSMarc Zyngier } else { 5849ed24f4bSMarc Zyngier val = __vgic_v3_read_ap1rn(apr); 5859ed24f4bSMarc Zyngier __vgic_v3_write_ap1rn(val | BIT(ap % 32), apr); 5869ed24f4bSMarc Zyngier } 5879ed24f4bSMarc Zyngier } 5889ed24f4bSMarc Zyngier 589c50cb043SDavid Brazdil static int __vgic_v3_clear_highest_active_priority(void) 5909ed24f4bSMarc Zyngier { 5919ed24f4bSMarc Zyngier u8 nr_apr_regs = vtr_to_nr_apr_regs(read_gicreg(ICH_VTR_EL2)); 5929ed24f4bSMarc Zyngier u32 hap = 0; 5939ed24f4bSMarc Zyngier int i; 5949ed24f4bSMarc Zyngier 5959ed24f4bSMarc Zyngier for (i = 0; i < nr_apr_regs; i++) { 5969ed24f4bSMarc Zyngier u32 ap0, ap1; 5979ed24f4bSMarc Zyngier int c0, c1; 5989ed24f4bSMarc Zyngier 5999ed24f4bSMarc Zyngier ap0 = __vgic_v3_read_ap0rn(i); 6009ed24f4bSMarc Zyngier ap1 = __vgic_v3_read_ap1rn(i); 6019ed24f4bSMarc Zyngier if (!ap0 && !ap1) { 6029ed24f4bSMarc Zyngier hap += 32; 6039ed24f4bSMarc Zyngier continue; 6049ed24f4bSMarc Zyngier } 6059ed24f4bSMarc Zyngier 6069ed24f4bSMarc Zyngier c0 = ap0 ? __ffs(ap0) : 32; 6079ed24f4bSMarc Zyngier c1 = ap1 ? __ffs(ap1) : 32; 6089ed24f4bSMarc Zyngier 6099ed24f4bSMarc Zyngier /* Always clear the LSB, which is the highest priority */ 6109ed24f4bSMarc Zyngier if (c0 < c1) { 6119ed24f4bSMarc Zyngier ap0 &= ~BIT(c0); 6129ed24f4bSMarc Zyngier __vgic_v3_write_ap0rn(ap0, i); 6139ed24f4bSMarc Zyngier hap += c0; 6149ed24f4bSMarc Zyngier } else { 6159ed24f4bSMarc Zyngier ap1 &= ~BIT(c1); 6169ed24f4bSMarc Zyngier __vgic_v3_write_ap1rn(ap1, i); 6179ed24f4bSMarc Zyngier hap += c1; 6189ed24f4bSMarc Zyngier } 6199ed24f4bSMarc Zyngier 6209ed24f4bSMarc Zyngier /* Rescale to 8 bits of priority */ 6219ed24f4bSMarc Zyngier return hap << __vgic_v3_bpr_min(); 6229ed24f4bSMarc Zyngier } 6239ed24f4bSMarc Zyngier 6249ed24f4bSMarc Zyngier return GICv3_IDLE_PRIORITY; 6259ed24f4bSMarc Zyngier } 6269ed24f4bSMarc Zyngier 627c50cb043SDavid Brazdil static void __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 6289ed24f4bSMarc Zyngier { 6299ed24f4bSMarc Zyngier u64 lr_val; 6309ed24f4bSMarc Zyngier u8 lr_prio, pmr; 6319ed24f4bSMarc Zyngier int lr, grp; 6329ed24f4bSMarc Zyngier 6339ed24f4bSMarc Zyngier grp = __vgic_v3_get_group(vcpu); 6349ed24f4bSMarc Zyngier 6359ed24f4bSMarc Zyngier lr = __vgic_v3_highest_priority_lr(vcpu, vmcr, &lr_val); 6369ed24f4bSMarc Zyngier if (lr < 0) 6379ed24f4bSMarc Zyngier goto spurious; 6389ed24f4bSMarc Zyngier 6399ed24f4bSMarc Zyngier if (grp != !!(lr_val & ICH_LR_GROUP)) 6409ed24f4bSMarc Zyngier goto spurious; 6419ed24f4bSMarc Zyngier 6429ed24f4bSMarc Zyngier pmr = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT; 6439ed24f4bSMarc Zyngier lr_prio = (lr_val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT; 6449ed24f4bSMarc Zyngier if (pmr <= lr_prio) 6459ed24f4bSMarc Zyngier goto spurious; 6469ed24f4bSMarc Zyngier 6479ed24f4bSMarc Zyngier if (__vgic_v3_get_highest_active_priority() <= __vgic_v3_pri_to_pre(lr_prio, vmcr, grp)) 6489ed24f4bSMarc Zyngier goto spurious; 6499ed24f4bSMarc Zyngier 6509ed24f4bSMarc Zyngier lr_val &= ~ICH_LR_STATE; 6519ed24f4bSMarc Zyngier /* No active state for LPIs */ 6529ed24f4bSMarc Zyngier if ((lr_val & ICH_LR_VIRTUAL_ID_MASK) <= VGIC_MAX_SPI) 6539ed24f4bSMarc Zyngier lr_val |= ICH_LR_ACTIVE_BIT; 6549ed24f4bSMarc Zyngier __gic_v3_set_lr(lr_val, lr); 6559ed24f4bSMarc Zyngier __vgic_v3_set_active_priority(lr_prio, vmcr, grp); 6569ed24f4bSMarc Zyngier vcpu_set_reg(vcpu, rt, lr_val & ICH_LR_VIRTUAL_ID_MASK); 6579ed24f4bSMarc Zyngier return; 6589ed24f4bSMarc Zyngier 6599ed24f4bSMarc Zyngier spurious: 6609ed24f4bSMarc Zyngier vcpu_set_reg(vcpu, rt, ICC_IAR1_EL1_SPURIOUS); 6619ed24f4bSMarc Zyngier } 6629ed24f4bSMarc Zyngier 663c50cb043SDavid Brazdil static void __vgic_v3_clear_active_lr(int lr, u64 lr_val) 6649ed24f4bSMarc Zyngier { 6659ed24f4bSMarc Zyngier lr_val &= ~ICH_LR_ACTIVE_BIT; 6669ed24f4bSMarc Zyngier if (lr_val & ICH_LR_HW) { 6679ed24f4bSMarc Zyngier u32 pid; 6689ed24f4bSMarc Zyngier 6699ed24f4bSMarc Zyngier pid = (lr_val & ICH_LR_PHYS_ID_MASK) >> ICH_LR_PHYS_ID_SHIFT; 6709ed24f4bSMarc Zyngier gic_write_dir(pid); 6719ed24f4bSMarc Zyngier } 6729ed24f4bSMarc Zyngier 6739ed24f4bSMarc Zyngier __gic_v3_set_lr(lr_val, lr); 6749ed24f4bSMarc Zyngier } 6759ed24f4bSMarc Zyngier 676c50cb043SDavid Brazdil static void __vgic_v3_bump_eoicount(void) 6779ed24f4bSMarc Zyngier { 6789ed24f4bSMarc Zyngier u32 hcr; 6799ed24f4bSMarc Zyngier 6809ed24f4bSMarc Zyngier hcr = read_gicreg(ICH_HCR_EL2); 6819ed24f4bSMarc Zyngier hcr += 1 << ICH_HCR_EOIcount_SHIFT; 6829ed24f4bSMarc Zyngier write_gicreg(hcr, ICH_HCR_EL2); 6839ed24f4bSMarc Zyngier } 6849ed24f4bSMarc Zyngier 685c50cb043SDavid Brazdil static void __vgic_v3_write_dir(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 6869ed24f4bSMarc Zyngier { 6879ed24f4bSMarc Zyngier u32 vid = vcpu_get_reg(vcpu, rt); 6889ed24f4bSMarc Zyngier u64 lr_val; 6899ed24f4bSMarc Zyngier int lr; 6909ed24f4bSMarc Zyngier 6919ed24f4bSMarc Zyngier /* EOImode == 0, nothing to be done here */ 6929ed24f4bSMarc Zyngier if (!(vmcr & ICH_VMCR_EOIM_MASK)) 6939ed24f4bSMarc Zyngier return; 6949ed24f4bSMarc Zyngier 6959ed24f4bSMarc Zyngier /* No deactivate to be performed on an LPI */ 6969ed24f4bSMarc Zyngier if (vid >= VGIC_MIN_LPI) 6979ed24f4bSMarc Zyngier return; 6989ed24f4bSMarc Zyngier 6999ed24f4bSMarc Zyngier lr = __vgic_v3_find_active_lr(vcpu, vid, &lr_val); 7009ed24f4bSMarc Zyngier if (lr == -1) { 7019ed24f4bSMarc Zyngier __vgic_v3_bump_eoicount(); 7029ed24f4bSMarc Zyngier return; 7039ed24f4bSMarc Zyngier } 7049ed24f4bSMarc Zyngier 7059ed24f4bSMarc Zyngier __vgic_v3_clear_active_lr(lr, lr_val); 7069ed24f4bSMarc Zyngier } 7079ed24f4bSMarc Zyngier 708c50cb043SDavid Brazdil static void __vgic_v3_write_eoir(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 7099ed24f4bSMarc Zyngier { 7109ed24f4bSMarc Zyngier u32 vid = vcpu_get_reg(vcpu, rt); 7119ed24f4bSMarc Zyngier u64 lr_val; 7129ed24f4bSMarc Zyngier u8 lr_prio, act_prio; 7139ed24f4bSMarc Zyngier int lr, grp; 7149ed24f4bSMarc Zyngier 7159ed24f4bSMarc Zyngier grp = __vgic_v3_get_group(vcpu); 7169ed24f4bSMarc Zyngier 7179ed24f4bSMarc Zyngier /* Drop priority in any case */ 7189ed24f4bSMarc Zyngier act_prio = __vgic_v3_clear_highest_active_priority(); 7199ed24f4bSMarc Zyngier 7209ed24f4bSMarc Zyngier /* If EOIing an LPI, no deactivate to be performed */ 7219ed24f4bSMarc Zyngier if (vid >= VGIC_MIN_LPI) 7229ed24f4bSMarc Zyngier return; 7239ed24f4bSMarc Zyngier 7249ed24f4bSMarc Zyngier /* EOImode == 1, nothing to be done here */ 7259ed24f4bSMarc Zyngier if (vmcr & ICH_VMCR_EOIM_MASK) 7269ed24f4bSMarc Zyngier return; 7279ed24f4bSMarc Zyngier 7289ed24f4bSMarc Zyngier lr = __vgic_v3_find_active_lr(vcpu, vid, &lr_val); 7299ed24f4bSMarc Zyngier if (lr == -1) { 7309ed24f4bSMarc Zyngier __vgic_v3_bump_eoicount(); 7319ed24f4bSMarc Zyngier return; 7329ed24f4bSMarc Zyngier } 7339ed24f4bSMarc Zyngier 7349ed24f4bSMarc Zyngier lr_prio = (lr_val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT; 7359ed24f4bSMarc Zyngier 7369ed24f4bSMarc Zyngier /* If priorities or group do not match, the guest has fscked-up. */ 7379ed24f4bSMarc Zyngier if (grp != !!(lr_val & ICH_LR_GROUP) || 7389ed24f4bSMarc Zyngier __vgic_v3_pri_to_pre(lr_prio, vmcr, grp) != act_prio) 7399ed24f4bSMarc Zyngier return; 7409ed24f4bSMarc Zyngier 7419ed24f4bSMarc Zyngier /* Let's now perform the deactivation */ 7429ed24f4bSMarc Zyngier __vgic_v3_clear_active_lr(lr, lr_val); 7439ed24f4bSMarc Zyngier } 7449ed24f4bSMarc Zyngier 745c50cb043SDavid Brazdil static void __vgic_v3_read_igrpen0(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 7469ed24f4bSMarc Zyngier { 7479ed24f4bSMarc Zyngier vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG0_MASK)); 7489ed24f4bSMarc Zyngier } 7499ed24f4bSMarc Zyngier 750c50cb043SDavid Brazdil static void __vgic_v3_read_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 7519ed24f4bSMarc Zyngier { 7529ed24f4bSMarc Zyngier vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG1_MASK)); 7539ed24f4bSMarc Zyngier } 7549ed24f4bSMarc Zyngier 755c50cb043SDavid Brazdil static void __vgic_v3_write_igrpen0(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 7569ed24f4bSMarc Zyngier { 7579ed24f4bSMarc Zyngier u64 val = vcpu_get_reg(vcpu, rt); 7589ed24f4bSMarc Zyngier 7599ed24f4bSMarc Zyngier if (val & 1) 7609ed24f4bSMarc Zyngier vmcr |= ICH_VMCR_ENG0_MASK; 7619ed24f4bSMarc Zyngier else 7629ed24f4bSMarc Zyngier vmcr &= ~ICH_VMCR_ENG0_MASK; 7639ed24f4bSMarc Zyngier 7649ed24f4bSMarc Zyngier __vgic_v3_write_vmcr(vmcr); 7659ed24f4bSMarc Zyngier } 7669ed24f4bSMarc Zyngier 767c50cb043SDavid Brazdil static void __vgic_v3_write_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 7689ed24f4bSMarc Zyngier { 7699ed24f4bSMarc Zyngier u64 val = vcpu_get_reg(vcpu, rt); 7709ed24f4bSMarc Zyngier 7719ed24f4bSMarc Zyngier if (val & 1) 7729ed24f4bSMarc Zyngier vmcr |= ICH_VMCR_ENG1_MASK; 7739ed24f4bSMarc Zyngier else 7749ed24f4bSMarc Zyngier vmcr &= ~ICH_VMCR_ENG1_MASK; 7759ed24f4bSMarc Zyngier 7769ed24f4bSMarc Zyngier __vgic_v3_write_vmcr(vmcr); 7779ed24f4bSMarc Zyngier } 7789ed24f4bSMarc Zyngier 779c50cb043SDavid Brazdil static void __vgic_v3_read_bpr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 7809ed24f4bSMarc Zyngier { 7819ed24f4bSMarc Zyngier vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr0(vmcr)); 7829ed24f4bSMarc Zyngier } 7839ed24f4bSMarc Zyngier 784c50cb043SDavid Brazdil static void __vgic_v3_read_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 7859ed24f4bSMarc Zyngier { 7869ed24f4bSMarc Zyngier vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr1(vmcr)); 7879ed24f4bSMarc Zyngier } 7889ed24f4bSMarc Zyngier 789c50cb043SDavid Brazdil static void __vgic_v3_write_bpr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 7909ed24f4bSMarc Zyngier { 7919ed24f4bSMarc Zyngier u64 val = vcpu_get_reg(vcpu, rt); 7929ed24f4bSMarc Zyngier u8 bpr_min = __vgic_v3_bpr_min() - 1; 7939ed24f4bSMarc Zyngier 7949ed24f4bSMarc Zyngier /* Enforce BPR limiting */ 7959ed24f4bSMarc Zyngier if (val < bpr_min) 7969ed24f4bSMarc Zyngier val = bpr_min; 7979ed24f4bSMarc Zyngier 7989ed24f4bSMarc Zyngier val <<= ICH_VMCR_BPR0_SHIFT; 7999ed24f4bSMarc Zyngier val &= ICH_VMCR_BPR0_MASK; 8009ed24f4bSMarc Zyngier vmcr &= ~ICH_VMCR_BPR0_MASK; 8019ed24f4bSMarc Zyngier vmcr |= val; 8029ed24f4bSMarc Zyngier 8039ed24f4bSMarc Zyngier __vgic_v3_write_vmcr(vmcr); 8049ed24f4bSMarc Zyngier } 8059ed24f4bSMarc Zyngier 806c50cb043SDavid Brazdil static void __vgic_v3_write_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 8079ed24f4bSMarc Zyngier { 8089ed24f4bSMarc Zyngier u64 val = vcpu_get_reg(vcpu, rt); 8099ed24f4bSMarc Zyngier u8 bpr_min = __vgic_v3_bpr_min(); 8109ed24f4bSMarc Zyngier 8119ed24f4bSMarc Zyngier if (vmcr & ICH_VMCR_CBPR_MASK) 8129ed24f4bSMarc Zyngier return; 8139ed24f4bSMarc Zyngier 8149ed24f4bSMarc Zyngier /* Enforce BPR limiting */ 8159ed24f4bSMarc Zyngier if (val < bpr_min) 8169ed24f4bSMarc Zyngier val = bpr_min; 8179ed24f4bSMarc Zyngier 8189ed24f4bSMarc Zyngier val <<= ICH_VMCR_BPR1_SHIFT; 8199ed24f4bSMarc Zyngier val &= ICH_VMCR_BPR1_MASK; 8209ed24f4bSMarc Zyngier vmcr &= ~ICH_VMCR_BPR1_MASK; 8219ed24f4bSMarc Zyngier vmcr |= val; 8229ed24f4bSMarc Zyngier 8239ed24f4bSMarc Zyngier __vgic_v3_write_vmcr(vmcr); 8249ed24f4bSMarc Zyngier } 8259ed24f4bSMarc Zyngier 826c50cb043SDavid Brazdil static void __vgic_v3_read_apxrn(struct kvm_vcpu *vcpu, int rt, int n) 8279ed24f4bSMarc Zyngier { 8289ed24f4bSMarc Zyngier u32 val; 8299ed24f4bSMarc Zyngier 8309ed24f4bSMarc Zyngier if (!__vgic_v3_get_group(vcpu)) 8319ed24f4bSMarc Zyngier val = __vgic_v3_read_ap0rn(n); 8329ed24f4bSMarc Zyngier else 8339ed24f4bSMarc Zyngier val = __vgic_v3_read_ap1rn(n); 8349ed24f4bSMarc Zyngier 8359ed24f4bSMarc Zyngier vcpu_set_reg(vcpu, rt, val); 8369ed24f4bSMarc Zyngier } 8379ed24f4bSMarc Zyngier 838c50cb043SDavid Brazdil static void __vgic_v3_write_apxrn(struct kvm_vcpu *vcpu, int rt, int n) 8399ed24f4bSMarc Zyngier { 8409ed24f4bSMarc Zyngier u32 val = vcpu_get_reg(vcpu, rt); 8419ed24f4bSMarc Zyngier 8429ed24f4bSMarc Zyngier if (!__vgic_v3_get_group(vcpu)) 8439ed24f4bSMarc Zyngier __vgic_v3_write_ap0rn(val, n); 8449ed24f4bSMarc Zyngier else 8459ed24f4bSMarc Zyngier __vgic_v3_write_ap1rn(val, n); 8469ed24f4bSMarc Zyngier } 8479ed24f4bSMarc Zyngier 848c50cb043SDavid Brazdil static void __vgic_v3_read_apxr0(struct kvm_vcpu *vcpu, 8499ed24f4bSMarc Zyngier u32 vmcr, int rt) 8509ed24f4bSMarc Zyngier { 8519ed24f4bSMarc Zyngier __vgic_v3_read_apxrn(vcpu, rt, 0); 8529ed24f4bSMarc Zyngier } 8539ed24f4bSMarc Zyngier 854c50cb043SDavid Brazdil static void __vgic_v3_read_apxr1(struct kvm_vcpu *vcpu, 8559ed24f4bSMarc Zyngier u32 vmcr, int rt) 8569ed24f4bSMarc Zyngier { 8579ed24f4bSMarc Zyngier __vgic_v3_read_apxrn(vcpu, rt, 1); 8589ed24f4bSMarc Zyngier } 8599ed24f4bSMarc Zyngier 860c50cb043SDavid Brazdil static void __vgic_v3_read_apxr2(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 8619ed24f4bSMarc Zyngier { 8629ed24f4bSMarc Zyngier __vgic_v3_read_apxrn(vcpu, rt, 2); 8639ed24f4bSMarc Zyngier } 8649ed24f4bSMarc Zyngier 865c50cb043SDavid Brazdil static void __vgic_v3_read_apxr3(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 8669ed24f4bSMarc Zyngier { 8679ed24f4bSMarc Zyngier __vgic_v3_read_apxrn(vcpu, rt, 3); 8689ed24f4bSMarc Zyngier } 8699ed24f4bSMarc Zyngier 870c50cb043SDavid Brazdil static void __vgic_v3_write_apxr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 8719ed24f4bSMarc Zyngier { 8729ed24f4bSMarc Zyngier __vgic_v3_write_apxrn(vcpu, rt, 0); 8739ed24f4bSMarc Zyngier } 8749ed24f4bSMarc Zyngier 875c50cb043SDavid Brazdil static void __vgic_v3_write_apxr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 8769ed24f4bSMarc Zyngier { 8779ed24f4bSMarc Zyngier __vgic_v3_write_apxrn(vcpu, rt, 1); 8789ed24f4bSMarc Zyngier } 8799ed24f4bSMarc Zyngier 880c50cb043SDavid Brazdil static void __vgic_v3_write_apxr2(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 8819ed24f4bSMarc Zyngier { 8829ed24f4bSMarc Zyngier __vgic_v3_write_apxrn(vcpu, rt, 2); 8839ed24f4bSMarc Zyngier } 8849ed24f4bSMarc Zyngier 885c50cb043SDavid Brazdil static void __vgic_v3_write_apxr3(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 8869ed24f4bSMarc Zyngier { 8879ed24f4bSMarc Zyngier __vgic_v3_write_apxrn(vcpu, rt, 3); 8889ed24f4bSMarc Zyngier } 8899ed24f4bSMarc Zyngier 890c50cb043SDavid Brazdil static void __vgic_v3_read_hppir(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 8919ed24f4bSMarc Zyngier { 8929ed24f4bSMarc Zyngier u64 lr_val; 8939ed24f4bSMarc Zyngier int lr, lr_grp, grp; 8949ed24f4bSMarc Zyngier 8959ed24f4bSMarc Zyngier grp = __vgic_v3_get_group(vcpu); 8969ed24f4bSMarc Zyngier 8979ed24f4bSMarc Zyngier lr = __vgic_v3_highest_priority_lr(vcpu, vmcr, &lr_val); 8989ed24f4bSMarc Zyngier if (lr == -1) 8999ed24f4bSMarc Zyngier goto spurious; 9009ed24f4bSMarc Zyngier 9019ed24f4bSMarc Zyngier lr_grp = !!(lr_val & ICH_LR_GROUP); 9029ed24f4bSMarc Zyngier if (lr_grp != grp) 9039ed24f4bSMarc Zyngier lr_val = ICC_IAR1_EL1_SPURIOUS; 9049ed24f4bSMarc Zyngier 9059ed24f4bSMarc Zyngier spurious: 9069ed24f4bSMarc Zyngier vcpu_set_reg(vcpu, rt, lr_val & ICH_LR_VIRTUAL_ID_MASK); 9079ed24f4bSMarc Zyngier } 9089ed24f4bSMarc Zyngier 909c50cb043SDavid Brazdil static void __vgic_v3_read_pmr(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 9109ed24f4bSMarc Zyngier { 9119ed24f4bSMarc Zyngier vmcr &= ICH_VMCR_PMR_MASK; 9129ed24f4bSMarc Zyngier vmcr >>= ICH_VMCR_PMR_SHIFT; 9139ed24f4bSMarc Zyngier vcpu_set_reg(vcpu, rt, vmcr); 9149ed24f4bSMarc Zyngier } 9159ed24f4bSMarc Zyngier 916c50cb043SDavid Brazdil static void __vgic_v3_write_pmr(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 9179ed24f4bSMarc Zyngier { 9189ed24f4bSMarc Zyngier u32 val = vcpu_get_reg(vcpu, rt); 9199ed24f4bSMarc Zyngier 9209ed24f4bSMarc Zyngier val <<= ICH_VMCR_PMR_SHIFT; 9219ed24f4bSMarc Zyngier val &= ICH_VMCR_PMR_MASK; 9229ed24f4bSMarc Zyngier vmcr &= ~ICH_VMCR_PMR_MASK; 9239ed24f4bSMarc Zyngier vmcr |= val; 9249ed24f4bSMarc Zyngier 9259ed24f4bSMarc Zyngier write_gicreg(vmcr, ICH_VMCR_EL2); 9269ed24f4bSMarc Zyngier } 9279ed24f4bSMarc Zyngier 928c50cb043SDavid Brazdil static void __vgic_v3_read_rpr(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 9299ed24f4bSMarc Zyngier { 9309ed24f4bSMarc Zyngier u32 val = __vgic_v3_get_highest_active_priority(); 9319ed24f4bSMarc Zyngier vcpu_set_reg(vcpu, rt, val); 9329ed24f4bSMarc Zyngier } 9339ed24f4bSMarc Zyngier 934c50cb043SDavid Brazdil static void __vgic_v3_read_ctlr(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 9359ed24f4bSMarc Zyngier { 9369ed24f4bSMarc Zyngier u32 vtr, val; 9379ed24f4bSMarc Zyngier 9389ed24f4bSMarc Zyngier vtr = read_gicreg(ICH_VTR_EL2); 9399ed24f4bSMarc Zyngier /* PRIbits */ 9409ed24f4bSMarc Zyngier val = ((vtr >> 29) & 7) << ICC_CTLR_EL1_PRI_BITS_SHIFT; 9419ed24f4bSMarc Zyngier /* IDbits */ 9429ed24f4bSMarc Zyngier val |= ((vtr >> 23) & 7) << ICC_CTLR_EL1_ID_BITS_SHIFT; 9439ed24f4bSMarc Zyngier /* SEIS */ 9449ed24f4bSMarc Zyngier val |= ((vtr >> 22) & 1) << ICC_CTLR_EL1_SEIS_SHIFT; 9459ed24f4bSMarc Zyngier /* A3V */ 9469ed24f4bSMarc Zyngier val |= ((vtr >> 21) & 1) << ICC_CTLR_EL1_A3V_SHIFT; 9479ed24f4bSMarc Zyngier /* EOImode */ 9489ed24f4bSMarc Zyngier val |= ((vmcr & ICH_VMCR_EOIM_MASK) >> ICH_VMCR_EOIM_SHIFT) << ICC_CTLR_EL1_EOImode_SHIFT; 9499ed24f4bSMarc Zyngier /* CBPR */ 9509ed24f4bSMarc Zyngier val |= (vmcr & ICH_VMCR_CBPR_MASK) >> ICH_VMCR_CBPR_SHIFT; 9519ed24f4bSMarc Zyngier 9529ed24f4bSMarc Zyngier vcpu_set_reg(vcpu, rt, val); 9539ed24f4bSMarc Zyngier } 9549ed24f4bSMarc Zyngier 955c50cb043SDavid Brazdil static void __vgic_v3_write_ctlr(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 9569ed24f4bSMarc Zyngier { 9579ed24f4bSMarc Zyngier u32 val = vcpu_get_reg(vcpu, rt); 9589ed24f4bSMarc Zyngier 9599ed24f4bSMarc Zyngier if (val & ICC_CTLR_EL1_CBPR_MASK) 9609ed24f4bSMarc Zyngier vmcr |= ICH_VMCR_CBPR_MASK; 9619ed24f4bSMarc Zyngier else 9629ed24f4bSMarc Zyngier vmcr &= ~ICH_VMCR_CBPR_MASK; 9639ed24f4bSMarc Zyngier 9649ed24f4bSMarc Zyngier if (val & ICC_CTLR_EL1_EOImode_MASK) 9659ed24f4bSMarc Zyngier vmcr |= ICH_VMCR_EOIM_MASK; 9669ed24f4bSMarc Zyngier else 9679ed24f4bSMarc Zyngier vmcr &= ~ICH_VMCR_EOIM_MASK; 9689ed24f4bSMarc Zyngier 9699ed24f4bSMarc Zyngier write_gicreg(vmcr, ICH_VMCR_EL2); 9709ed24f4bSMarc Zyngier } 9719ed24f4bSMarc Zyngier 972c50cb043SDavid Brazdil int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu) 9739ed24f4bSMarc Zyngier { 9749ed24f4bSMarc Zyngier int rt; 9759ed24f4bSMarc Zyngier u32 esr; 9769ed24f4bSMarc Zyngier u32 vmcr; 9779ed24f4bSMarc Zyngier void (*fn)(struct kvm_vcpu *, u32, int); 9789ed24f4bSMarc Zyngier bool is_read; 9799ed24f4bSMarc Zyngier u32 sysreg; 9809ed24f4bSMarc Zyngier 9813a949f4cSGavin Shan esr = kvm_vcpu_get_esr(vcpu); 9829ed24f4bSMarc Zyngier if (vcpu_mode_is_32bit(vcpu)) { 9839ed24f4bSMarc Zyngier if (!kvm_condition_valid(vcpu)) { 9849ed24f4bSMarc Zyngier __kvm_skip_instr(vcpu); 9859ed24f4bSMarc Zyngier return 1; 9869ed24f4bSMarc Zyngier } 9879ed24f4bSMarc Zyngier 9889ed24f4bSMarc Zyngier sysreg = esr_cp15_to_sysreg(esr); 9899ed24f4bSMarc Zyngier } else { 9909ed24f4bSMarc Zyngier sysreg = esr_sys64_to_sysreg(esr); 9919ed24f4bSMarc Zyngier } 9929ed24f4bSMarc Zyngier 9939ed24f4bSMarc Zyngier is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ; 9949ed24f4bSMarc Zyngier 9959ed24f4bSMarc Zyngier switch (sysreg) { 9969ed24f4bSMarc Zyngier case SYS_ICC_IAR0_EL1: 9979ed24f4bSMarc Zyngier case SYS_ICC_IAR1_EL1: 9989ed24f4bSMarc Zyngier if (unlikely(!is_read)) 9999ed24f4bSMarc Zyngier return 0; 10009ed24f4bSMarc Zyngier fn = __vgic_v3_read_iar; 10019ed24f4bSMarc Zyngier break; 10029ed24f4bSMarc Zyngier case SYS_ICC_EOIR0_EL1: 10039ed24f4bSMarc Zyngier case SYS_ICC_EOIR1_EL1: 10049ed24f4bSMarc Zyngier if (unlikely(is_read)) 10059ed24f4bSMarc Zyngier return 0; 10069ed24f4bSMarc Zyngier fn = __vgic_v3_write_eoir; 10079ed24f4bSMarc Zyngier break; 10089ed24f4bSMarc Zyngier case SYS_ICC_IGRPEN1_EL1: 10099ed24f4bSMarc Zyngier if (is_read) 10109ed24f4bSMarc Zyngier fn = __vgic_v3_read_igrpen1; 10119ed24f4bSMarc Zyngier else 10129ed24f4bSMarc Zyngier fn = __vgic_v3_write_igrpen1; 10139ed24f4bSMarc Zyngier break; 10149ed24f4bSMarc Zyngier case SYS_ICC_BPR1_EL1: 10159ed24f4bSMarc Zyngier if (is_read) 10169ed24f4bSMarc Zyngier fn = __vgic_v3_read_bpr1; 10179ed24f4bSMarc Zyngier else 10189ed24f4bSMarc Zyngier fn = __vgic_v3_write_bpr1; 10199ed24f4bSMarc Zyngier break; 10209ed24f4bSMarc Zyngier case SYS_ICC_AP0Rn_EL1(0): 10219ed24f4bSMarc Zyngier case SYS_ICC_AP1Rn_EL1(0): 10229ed24f4bSMarc Zyngier if (is_read) 10239ed24f4bSMarc Zyngier fn = __vgic_v3_read_apxr0; 10249ed24f4bSMarc Zyngier else 10259ed24f4bSMarc Zyngier fn = __vgic_v3_write_apxr0; 10269ed24f4bSMarc Zyngier break; 10279ed24f4bSMarc Zyngier case SYS_ICC_AP0Rn_EL1(1): 10289ed24f4bSMarc Zyngier case SYS_ICC_AP1Rn_EL1(1): 10299ed24f4bSMarc Zyngier if (is_read) 10309ed24f4bSMarc Zyngier fn = __vgic_v3_read_apxr1; 10319ed24f4bSMarc Zyngier else 10329ed24f4bSMarc Zyngier fn = __vgic_v3_write_apxr1; 10339ed24f4bSMarc Zyngier break; 10349ed24f4bSMarc Zyngier case SYS_ICC_AP0Rn_EL1(2): 10359ed24f4bSMarc Zyngier case SYS_ICC_AP1Rn_EL1(2): 10369ed24f4bSMarc Zyngier if (is_read) 10379ed24f4bSMarc Zyngier fn = __vgic_v3_read_apxr2; 10389ed24f4bSMarc Zyngier else 10399ed24f4bSMarc Zyngier fn = __vgic_v3_write_apxr2; 10409ed24f4bSMarc Zyngier break; 10419ed24f4bSMarc Zyngier case SYS_ICC_AP0Rn_EL1(3): 10429ed24f4bSMarc Zyngier case SYS_ICC_AP1Rn_EL1(3): 10439ed24f4bSMarc Zyngier if (is_read) 10449ed24f4bSMarc Zyngier fn = __vgic_v3_read_apxr3; 10459ed24f4bSMarc Zyngier else 10469ed24f4bSMarc Zyngier fn = __vgic_v3_write_apxr3; 10479ed24f4bSMarc Zyngier break; 10489ed24f4bSMarc Zyngier case SYS_ICC_HPPIR0_EL1: 10499ed24f4bSMarc Zyngier case SYS_ICC_HPPIR1_EL1: 10509ed24f4bSMarc Zyngier if (unlikely(!is_read)) 10519ed24f4bSMarc Zyngier return 0; 10529ed24f4bSMarc Zyngier fn = __vgic_v3_read_hppir; 10539ed24f4bSMarc Zyngier break; 10549ed24f4bSMarc Zyngier case SYS_ICC_IGRPEN0_EL1: 10559ed24f4bSMarc Zyngier if (is_read) 10569ed24f4bSMarc Zyngier fn = __vgic_v3_read_igrpen0; 10579ed24f4bSMarc Zyngier else 10589ed24f4bSMarc Zyngier fn = __vgic_v3_write_igrpen0; 10599ed24f4bSMarc Zyngier break; 10609ed24f4bSMarc Zyngier case SYS_ICC_BPR0_EL1: 10619ed24f4bSMarc Zyngier if (is_read) 10629ed24f4bSMarc Zyngier fn = __vgic_v3_read_bpr0; 10639ed24f4bSMarc Zyngier else 10649ed24f4bSMarc Zyngier fn = __vgic_v3_write_bpr0; 10659ed24f4bSMarc Zyngier break; 10669ed24f4bSMarc Zyngier case SYS_ICC_DIR_EL1: 10679ed24f4bSMarc Zyngier if (unlikely(is_read)) 10689ed24f4bSMarc Zyngier return 0; 10699ed24f4bSMarc Zyngier fn = __vgic_v3_write_dir; 10709ed24f4bSMarc Zyngier break; 10719ed24f4bSMarc Zyngier case SYS_ICC_RPR_EL1: 10729ed24f4bSMarc Zyngier if (unlikely(!is_read)) 10739ed24f4bSMarc Zyngier return 0; 10749ed24f4bSMarc Zyngier fn = __vgic_v3_read_rpr; 10759ed24f4bSMarc Zyngier break; 10769ed24f4bSMarc Zyngier case SYS_ICC_CTLR_EL1: 10779ed24f4bSMarc Zyngier if (is_read) 10789ed24f4bSMarc Zyngier fn = __vgic_v3_read_ctlr; 10799ed24f4bSMarc Zyngier else 10809ed24f4bSMarc Zyngier fn = __vgic_v3_write_ctlr; 10819ed24f4bSMarc Zyngier break; 10829ed24f4bSMarc Zyngier case SYS_ICC_PMR_EL1: 10839ed24f4bSMarc Zyngier if (is_read) 10849ed24f4bSMarc Zyngier fn = __vgic_v3_read_pmr; 10859ed24f4bSMarc Zyngier else 10869ed24f4bSMarc Zyngier fn = __vgic_v3_write_pmr; 10879ed24f4bSMarc Zyngier break; 10889ed24f4bSMarc Zyngier default: 10899ed24f4bSMarc Zyngier return 0; 10909ed24f4bSMarc Zyngier } 10919ed24f4bSMarc Zyngier 10929ed24f4bSMarc Zyngier vmcr = __vgic_v3_read_vmcr(); 10939ed24f4bSMarc Zyngier rt = kvm_vcpu_sys_get_rt(vcpu); 10949ed24f4bSMarc Zyngier fn(vcpu, vmcr, rt); 10959ed24f4bSMarc Zyngier 10969ed24f4bSMarc Zyngier __kvm_skip_instr(vcpu); 10979ed24f4bSMarc Zyngier 10989ed24f4bSMarc Zyngier return 1; 10999ed24f4bSMarc Zyngier } 1100