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 7cdb5e02eSMarc Zyngier #include <hyp/adjust_pc.h> 8cdb5e02eSMarc Zyngier 99ed24f4bSMarc Zyngier #include <linux/compiler.h> 109ed24f4bSMarc Zyngier #include <linux/irqchip/arm-gic-v3.h> 119ed24f4bSMarc Zyngier #include <linux/kvm_host.h> 129ed24f4bSMarc Zyngier 139ed24f4bSMarc Zyngier #include <asm/kvm_emulate.h> 149ed24f4bSMarc Zyngier #include <asm/kvm_hyp.h> 159ed24f4bSMarc Zyngier #include <asm/kvm_mmu.h> 169ed24f4bSMarc Zyngier 179ed24f4bSMarc Zyngier #define vtr_to_max_lr_idx(v) ((v) & 0xf) 189ed24f4bSMarc Zyngier #define vtr_to_nr_pre_bits(v) ((((u32)(v) >> 26) & 7) + 1) 199ed24f4bSMarc Zyngier #define vtr_to_nr_apr_regs(v) (1 << (vtr_to_nr_pre_bits(v) - 5)) 209ed24f4bSMarc Zyngier 21c50cb043SDavid Brazdil static u64 __gic_v3_get_lr(unsigned int lr) 229ed24f4bSMarc Zyngier { 239ed24f4bSMarc Zyngier switch (lr & 0xf) { 249ed24f4bSMarc Zyngier case 0: 259ed24f4bSMarc Zyngier return read_gicreg(ICH_LR0_EL2); 269ed24f4bSMarc Zyngier case 1: 279ed24f4bSMarc Zyngier return read_gicreg(ICH_LR1_EL2); 289ed24f4bSMarc Zyngier case 2: 299ed24f4bSMarc Zyngier return read_gicreg(ICH_LR2_EL2); 309ed24f4bSMarc Zyngier case 3: 319ed24f4bSMarc Zyngier return read_gicreg(ICH_LR3_EL2); 329ed24f4bSMarc Zyngier case 4: 339ed24f4bSMarc Zyngier return read_gicreg(ICH_LR4_EL2); 349ed24f4bSMarc Zyngier case 5: 359ed24f4bSMarc Zyngier return read_gicreg(ICH_LR5_EL2); 369ed24f4bSMarc Zyngier case 6: 379ed24f4bSMarc Zyngier return read_gicreg(ICH_LR6_EL2); 389ed24f4bSMarc Zyngier case 7: 399ed24f4bSMarc Zyngier return read_gicreg(ICH_LR7_EL2); 409ed24f4bSMarc Zyngier case 8: 419ed24f4bSMarc Zyngier return read_gicreg(ICH_LR8_EL2); 429ed24f4bSMarc Zyngier case 9: 439ed24f4bSMarc Zyngier return read_gicreg(ICH_LR9_EL2); 449ed24f4bSMarc Zyngier case 10: 459ed24f4bSMarc Zyngier return read_gicreg(ICH_LR10_EL2); 469ed24f4bSMarc Zyngier case 11: 479ed24f4bSMarc Zyngier return read_gicreg(ICH_LR11_EL2); 489ed24f4bSMarc Zyngier case 12: 499ed24f4bSMarc Zyngier return read_gicreg(ICH_LR12_EL2); 509ed24f4bSMarc Zyngier case 13: 519ed24f4bSMarc Zyngier return read_gicreg(ICH_LR13_EL2); 529ed24f4bSMarc Zyngier case 14: 539ed24f4bSMarc Zyngier return read_gicreg(ICH_LR14_EL2); 549ed24f4bSMarc Zyngier case 15: 559ed24f4bSMarc Zyngier return read_gicreg(ICH_LR15_EL2); 569ed24f4bSMarc Zyngier } 579ed24f4bSMarc Zyngier 589ed24f4bSMarc Zyngier unreachable(); 599ed24f4bSMarc Zyngier } 609ed24f4bSMarc Zyngier 61c50cb043SDavid Brazdil static void __gic_v3_set_lr(u64 val, int lr) 629ed24f4bSMarc Zyngier { 639ed24f4bSMarc Zyngier switch (lr & 0xf) { 649ed24f4bSMarc Zyngier case 0: 659ed24f4bSMarc Zyngier write_gicreg(val, ICH_LR0_EL2); 669ed24f4bSMarc Zyngier break; 679ed24f4bSMarc Zyngier case 1: 689ed24f4bSMarc Zyngier write_gicreg(val, ICH_LR1_EL2); 699ed24f4bSMarc Zyngier break; 709ed24f4bSMarc Zyngier case 2: 719ed24f4bSMarc Zyngier write_gicreg(val, ICH_LR2_EL2); 729ed24f4bSMarc Zyngier break; 739ed24f4bSMarc Zyngier case 3: 749ed24f4bSMarc Zyngier write_gicreg(val, ICH_LR3_EL2); 759ed24f4bSMarc Zyngier break; 769ed24f4bSMarc Zyngier case 4: 779ed24f4bSMarc Zyngier write_gicreg(val, ICH_LR4_EL2); 789ed24f4bSMarc Zyngier break; 799ed24f4bSMarc Zyngier case 5: 809ed24f4bSMarc Zyngier write_gicreg(val, ICH_LR5_EL2); 819ed24f4bSMarc Zyngier break; 829ed24f4bSMarc Zyngier case 6: 839ed24f4bSMarc Zyngier write_gicreg(val, ICH_LR6_EL2); 849ed24f4bSMarc Zyngier break; 859ed24f4bSMarc Zyngier case 7: 869ed24f4bSMarc Zyngier write_gicreg(val, ICH_LR7_EL2); 879ed24f4bSMarc Zyngier break; 889ed24f4bSMarc Zyngier case 8: 899ed24f4bSMarc Zyngier write_gicreg(val, ICH_LR8_EL2); 909ed24f4bSMarc Zyngier break; 919ed24f4bSMarc Zyngier case 9: 929ed24f4bSMarc Zyngier write_gicreg(val, ICH_LR9_EL2); 939ed24f4bSMarc Zyngier break; 949ed24f4bSMarc Zyngier case 10: 959ed24f4bSMarc Zyngier write_gicreg(val, ICH_LR10_EL2); 969ed24f4bSMarc Zyngier break; 979ed24f4bSMarc Zyngier case 11: 989ed24f4bSMarc Zyngier write_gicreg(val, ICH_LR11_EL2); 999ed24f4bSMarc Zyngier break; 1009ed24f4bSMarc Zyngier case 12: 1019ed24f4bSMarc Zyngier write_gicreg(val, ICH_LR12_EL2); 1029ed24f4bSMarc Zyngier break; 1039ed24f4bSMarc Zyngier case 13: 1049ed24f4bSMarc Zyngier write_gicreg(val, ICH_LR13_EL2); 1059ed24f4bSMarc Zyngier break; 1069ed24f4bSMarc Zyngier case 14: 1079ed24f4bSMarc Zyngier write_gicreg(val, ICH_LR14_EL2); 1089ed24f4bSMarc Zyngier break; 1099ed24f4bSMarc Zyngier case 15: 1109ed24f4bSMarc Zyngier write_gicreg(val, ICH_LR15_EL2); 1119ed24f4bSMarc Zyngier break; 1129ed24f4bSMarc Zyngier } 1139ed24f4bSMarc Zyngier } 1149ed24f4bSMarc Zyngier 115c50cb043SDavid Brazdil static void __vgic_v3_write_ap0rn(u32 val, int n) 1169ed24f4bSMarc Zyngier { 1179ed24f4bSMarc Zyngier switch (n) { 1189ed24f4bSMarc Zyngier case 0: 1199ed24f4bSMarc Zyngier write_gicreg(val, ICH_AP0R0_EL2); 1209ed24f4bSMarc Zyngier break; 1219ed24f4bSMarc Zyngier case 1: 1229ed24f4bSMarc Zyngier write_gicreg(val, ICH_AP0R1_EL2); 1239ed24f4bSMarc Zyngier break; 1249ed24f4bSMarc Zyngier case 2: 1259ed24f4bSMarc Zyngier write_gicreg(val, ICH_AP0R2_EL2); 1269ed24f4bSMarc Zyngier break; 1279ed24f4bSMarc Zyngier case 3: 1289ed24f4bSMarc Zyngier write_gicreg(val, ICH_AP0R3_EL2); 1299ed24f4bSMarc Zyngier break; 1309ed24f4bSMarc Zyngier } 1319ed24f4bSMarc Zyngier } 1329ed24f4bSMarc Zyngier 133c50cb043SDavid Brazdil static void __vgic_v3_write_ap1rn(u32 val, int n) 1349ed24f4bSMarc Zyngier { 1359ed24f4bSMarc Zyngier switch (n) { 1369ed24f4bSMarc Zyngier case 0: 1379ed24f4bSMarc Zyngier write_gicreg(val, ICH_AP1R0_EL2); 1389ed24f4bSMarc Zyngier break; 1399ed24f4bSMarc Zyngier case 1: 1409ed24f4bSMarc Zyngier write_gicreg(val, ICH_AP1R1_EL2); 1419ed24f4bSMarc Zyngier break; 1429ed24f4bSMarc Zyngier case 2: 1439ed24f4bSMarc Zyngier write_gicreg(val, ICH_AP1R2_EL2); 1449ed24f4bSMarc Zyngier break; 1459ed24f4bSMarc Zyngier case 3: 1469ed24f4bSMarc Zyngier write_gicreg(val, ICH_AP1R3_EL2); 1479ed24f4bSMarc Zyngier break; 1489ed24f4bSMarc Zyngier } 1499ed24f4bSMarc Zyngier } 1509ed24f4bSMarc Zyngier 151c50cb043SDavid Brazdil static u32 __vgic_v3_read_ap0rn(int n) 1529ed24f4bSMarc Zyngier { 1539ed24f4bSMarc Zyngier u32 val; 1549ed24f4bSMarc Zyngier 1559ed24f4bSMarc Zyngier switch (n) { 1569ed24f4bSMarc Zyngier case 0: 1579ed24f4bSMarc Zyngier val = read_gicreg(ICH_AP0R0_EL2); 1589ed24f4bSMarc Zyngier break; 1599ed24f4bSMarc Zyngier case 1: 1609ed24f4bSMarc Zyngier val = read_gicreg(ICH_AP0R1_EL2); 1619ed24f4bSMarc Zyngier break; 1629ed24f4bSMarc Zyngier case 2: 1639ed24f4bSMarc Zyngier val = read_gicreg(ICH_AP0R2_EL2); 1649ed24f4bSMarc Zyngier break; 1659ed24f4bSMarc Zyngier case 3: 1669ed24f4bSMarc Zyngier val = read_gicreg(ICH_AP0R3_EL2); 1679ed24f4bSMarc Zyngier break; 1689ed24f4bSMarc Zyngier default: 1699ed24f4bSMarc Zyngier unreachable(); 1709ed24f4bSMarc Zyngier } 1719ed24f4bSMarc Zyngier 1729ed24f4bSMarc Zyngier return val; 1739ed24f4bSMarc Zyngier } 1749ed24f4bSMarc Zyngier 175c50cb043SDavid Brazdil static u32 __vgic_v3_read_ap1rn(int n) 1769ed24f4bSMarc Zyngier { 1779ed24f4bSMarc Zyngier u32 val; 1789ed24f4bSMarc Zyngier 1799ed24f4bSMarc Zyngier switch (n) { 1809ed24f4bSMarc Zyngier case 0: 1819ed24f4bSMarc Zyngier val = read_gicreg(ICH_AP1R0_EL2); 1829ed24f4bSMarc Zyngier break; 1839ed24f4bSMarc Zyngier case 1: 1849ed24f4bSMarc Zyngier val = read_gicreg(ICH_AP1R1_EL2); 1859ed24f4bSMarc Zyngier break; 1869ed24f4bSMarc Zyngier case 2: 1879ed24f4bSMarc Zyngier val = read_gicreg(ICH_AP1R2_EL2); 1889ed24f4bSMarc Zyngier break; 1899ed24f4bSMarc Zyngier case 3: 1909ed24f4bSMarc Zyngier val = read_gicreg(ICH_AP1R3_EL2); 1919ed24f4bSMarc Zyngier break; 1929ed24f4bSMarc Zyngier default: 1939ed24f4bSMarc Zyngier unreachable(); 1949ed24f4bSMarc Zyngier } 1959ed24f4bSMarc Zyngier 1969ed24f4bSMarc Zyngier return val; 1979ed24f4bSMarc Zyngier } 1989ed24f4bSMarc Zyngier 199c50cb043SDavid Brazdil void __vgic_v3_save_state(struct vgic_v3_cpu_if *cpu_if) 2009ed24f4bSMarc Zyngier { 201fc5d1f1aSChristoffer Dall u64 used_lrs = cpu_if->used_lrs; 2029ed24f4bSMarc Zyngier 2039ed24f4bSMarc Zyngier /* 2049ed24f4bSMarc Zyngier * Make sure stores to the GIC via the memory mapped interface 2059ed24f4bSMarc Zyngier * are now visible to the system register interface when reading the 2069ed24f4bSMarc Zyngier * LRs, and when reading back the VMCR on non-VHE systems. 2079ed24f4bSMarc Zyngier */ 2089ed24f4bSMarc Zyngier if (used_lrs || !has_vhe()) { 2099ed24f4bSMarc Zyngier if (!cpu_if->vgic_sre) { 2109ed24f4bSMarc Zyngier dsb(sy); 2119ed24f4bSMarc Zyngier isb(); 2129ed24f4bSMarc Zyngier } 2139ed24f4bSMarc Zyngier } 2149ed24f4bSMarc Zyngier 2159ed24f4bSMarc Zyngier if (used_lrs || cpu_if->its_vpe.its_vm) { 2169ed24f4bSMarc Zyngier int i; 2179ed24f4bSMarc Zyngier u32 elrsr; 2189ed24f4bSMarc Zyngier 2199ed24f4bSMarc Zyngier elrsr = read_gicreg(ICH_ELRSR_EL2); 2209ed24f4bSMarc Zyngier 2219ed24f4bSMarc Zyngier write_gicreg(cpu_if->vgic_hcr & ~ICH_HCR_EN, ICH_HCR_EL2); 2229ed24f4bSMarc Zyngier 2239ed24f4bSMarc Zyngier for (i = 0; i < used_lrs; i++) { 2249ed24f4bSMarc Zyngier if (elrsr & (1 << i)) 2259ed24f4bSMarc Zyngier cpu_if->vgic_lr[i] &= ~ICH_LR_STATE; 2269ed24f4bSMarc Zyngier else 2279ed24f4bSMarc Zyngier cpu_if->vgic_lr[i] = __gic_v3_get_lr(i); 2289ed24f4bSMarc Zyngier 2299ed24f4bSMarc Zyngier __gic_v3_set_lr(0, i); 2309ed24f4bSMarc Zyngier } 2319ed24f4bSMarc Zyngier } 2329ed24f4bSMarc Zyngier } 2339ed24f4bSMarc Zyngier 234c50cb043SDavid Brazdil void __vgic_v3_restore_state(struct vgic_v3_cpu_if *cpu_if) 2359ed24f4bSMarc Zyngier { 236fc5d1f1aSChristoffer Dall u64 used_lrs = cpu_if->used_lrs; 2379ed24f4bSMarc Zyngier int i; 2389ed24f4bSMarc Zyngier 2399ed24f4bSMarc Zyngier if (used_lrs || cpu_if->its_vpe.its_vm) { 2409ed24f4bSMarc Zyngier write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2); 2419ed24f4bSMarc Zyngier 2429ed24f4bSMarc Zyngier for (i = 0; i < used_lrs; i++) 2439ed24f4bSMarc Zyngier __gic_v3_set_lr(cpu_if->vgic_lr[i], i); 2449ed24f4bSMarc Zyngier } 2459ed24f4bSMarc Zyngier 2469ed24f4bSMarc Zyngier /* 2479ed24f4bSMarc Zyngier * Ensure that writes to the LRs, and on non-VHE systems ensure that 2489ed24f4bSMarc Zyngier * the write to the VMCR in __vgic_v3_activate_traps(), will have 2499ed24f4bSMarc Zyngier * reached the (re)distributors. This ensure the guest will read the 2509ed24f4bSMarc Zyngier * correct values from the memory-mapped interface. 2519ed24f4bSMarc Zyngier */ 2529ed24f4bSMarc Zyngier if (used_lrs || !has_vhe()) { 2539ed24f4bSMarc Zyngier if (!cpu_if->vgic_sre) { 2549ed24f4bSMarc Zyngier isb(); 2559ed24f4bSMarc Zyngier dsb(sy); 2569ed24f4bSMarc Zyngier } 2579ed24f4bSMarc Zyngier } 2589ed24f4bSMarc Zyngier } 2599ed24f4bSMarc Zyngier 260c50cb043SDavid Brazdil void __vgic_v3_activate_traps(struct vgic_v3_cpu_if *cpu_if) 2619ed24f4bSMarc Zyngier { 2629ed24f4bSMarc Zyngier /* 2639ed24f4bSMarc Zyngier * VFIQEn is RES1 if ICC_SRE_EL1.SRE is 1. This causes a 2649ed24f4bSMarc Zyngier * Group0 interrupt (as generated in GICv2 mode) to be 2659ed24f4bSMarc Zyngier * delivered as a FIQ to the guest, with potentially fatal 2669ed24f4bSMarc Zyngier * consequences. So we must make sure that ICC_SRE_EL1 has 2679ed24f4bSMarc Zyngier * been actually programmed with the value we want before 2689ed24f4bSMarc Zyngier * starting to mess with the rest of the GIC, and VMCR_EL2 in 2699ed24f4bSMarc Zyngier * particular. This logic must be called before 2709ed24f4bSMarc Zyngier * __vgic_v3_restore_state(). 2719ed24f4bSMarc Zyngier */ 2729ed24f4bSMarc Zyngier if (!cpu_if->vgic_sre) { 2739ed24f4bSMarc Zyngier write_gicreg(0, ICC_SRE_EL1); 2749ed24f4bSMarc Zyngier isb(); 2759ed24f4bSMarc Zyngier write_gicreg(cpu_if->vgic_vmcr, ICH_VMCR_EL2); 2769ed24f4bSMarc Zyngier 2779ed24f4bSMarc Zyngier 2789ed24f4bSMarc Zyngier if (has_vhe()) { 2799ed24f4bSMarc Zyngier /* 2809ed24f4bSMarc Zyngier * Ensure that the write to the VMCR will have reached 2819ed24f4bSMarc Zyngier * the (re)distributors. This ensure the guest will 2829ed24f4bSMarc Zyngier * read the correct values from the memory-mapped 2839ed24f4bSMarc Zyngier * interface. 2849ed24f4bSMarc Zyngier */ 2859ed24f4bSMarc Zyngier isb(); 2869ed24f4bSMarc Zyngier dsb(sy); 2879ed24f4bSMarc Zyngier } 2889ed24f4bSMarc Zyngier } 2899ed24f4bSMarc Zyngier 2909ed24f4bSMarc Zyngier /* 2919ed24f4bSMarc Zyngier * Prevent the guest from touching the GIC system registers if 2929ed24f4bSMarc Zyngier * SRE isn't enabled for GICv3 emulation. 2939ed24f4bSMarc Zyngier */ 2949ed24f4bSMarc Zyngier write_gicreg(read_gicreg(ICC_SRE_EL2) & ~ICC_SRE_EL2_ENABLE, 2959ed24f4bSMarc Zyngier ICC_SRE_EL2); 2969ed24f4bSMarc Zyngier 2979ed24f4bSMarc Zyngier /* 2989ed24f4bSMarc Zyngier * If we need to trap system registers, we must write 2999ed24f4bSMarc Zyngier * ICH_HCR_EL2 anyway, even if no interrupts are being 3009ed24f4bSMarc Zyngier * injected, 3019ed24f4bSMarc Zyngier */ 3029ed24f4bSMarc Zyngier if (static_branch_unlikely(&vgic_v3_cpuif_trap) || 3039ed24f4bSMarc Zyngier cpu_if->its_vpe.its_vm) 3049ed24f4bSMarc Zyngier write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2); 3059ed24f4bSMarc Zyngier } 3069ed24f4bSMarc Zyngier 307c50cb043SDavid Brazdil void __vgic_v3_deactivate_traps(struct vgic_v3_cpu_if *cpu_if) 3089ed24f4bSMarc Zyngier { 3099ed24f4bSMarc Zyngier u64 val; 3109ed24f4bSMarc Zyngier 3119ed24f4bSMarc Zyngier if (!cpu_if->vgic_sre) { 3129ed24f4bSMarc Zyngier cpu_if->vgic_vmcr = read_gicreg(ICH_VMCR_EL2); 3139ed24f4bSMarc Zyngier } 3149ed24f4bSMarc Zyngier 3159ed24f4bSMarc Zyngier val = read_gicreg(ICC_SRE_EL2); 3169ed24f4bSMarc Zyngier write_gicreg(val | ICC_SRE_EL2_ENABLE, ICC_SRE_EL2); 3179ed24f4bSMarc Zyngier 3189ed24f4bSMarc Zyngier if (!cpu_if->vgic_sre) { 3199ed24f4bSMarc Zyngier /* Make sure ENABLE is set at EL2 before setting SRE at EL1 */ 3209ed24f4bSMarc Zyngier isb(); 3219ed24f4bSMarc Zyngier write_gicreg(1, ICC_SRE_EL1); 3229ed24f4bSMarc Zyngier } 3239ed24f4bSMarc Zyngier 3249ed24f4bSMarc Zyngier /* 3259ed24f4bSMarc Zyngier * If we were trapping system registers, we enabled the VGIC even if 3269ed24f4bSMarc Zyngier * no interrupts were being injected, and we disable it again here. 3279ed24f4bSMarc Zyngier */ 3289ed24f4bSMarc Zyngier if (static_branch_unlikely(&vgic_v3_cpuif_trap) || 3299ed24f4bSMarc Zyngier cpu_if->its_vpe.its_vm) 3309ed24f4bSMarc Zyngier write_gicreg(0, ICH_HCR_EL2); 3319ed24f4bSMarc Zyngier } 3329ed24f4bSMarc Zyngier 333c50cb043SDavid Brazdil void __vgic_v3_save_aprs(struct vgic_v3_cpu_if *cpu_if) 3349ed24f4bSMarc Zyngier { 3359ed24f4bSMarc Zyngier u64 val; 3369ed24f4bSMarc Zyngier u32 nr_pre_bits; 3379ed24f4bSMarc Zyngier 3389ed24f4bSMarc Zyngier val = read_gicreg(ICH_VTR_EL2); 3399ed24f4bSMarc Zyngier nr_pre_bits = vtr_to_nr_pre_bits(val); 3409ed24f4bSMarc Zyngier 3419ed24f4bSMarc Zyngier switch (nr_pre_bits) { 3429ed24f4bSMarc Zyngier case 7: 3439ed24f4bSMarc Zyngier cpu_if->vgic_ap0r[3] = __vgic_v3_read_ap0rn(3); 3449ed24f4bSMarc Zyngier cpu_if->vgic_ap0r[2] = __vgic_v3_read_ap0rn(2); 345df561f66SGustavo A. R. Silva fallthrough; 3469ed24f4bSMarc Zyngier case 6: 3479ed24f4bSMarc Zyngier cpu_if->vgic_ap0r[1] = __vgic_v3_read_ap0rn(1); 348df561f66SGustavo A. R. Silva fallthrough; 3499ed24f4bSMarc Zyngier default: 3509ed24f4bSMarc Zyngier cpu_if->vgic_ap0r[0] = __vgic_v3_read_ap0rn(0); 3519ed24f4bSMarc Zyngier } 3529ed24f4bSMarc Zyngier 3539ed24f4bSMarc Zyngier switch (nr_pre_bits) { 3549ed24f4bSMarc Zyngier case 7: 3559ed24f4bSMarc Zyngier cpu_if->vgic_ap1r[3] = __vgic_v3_read_ap1rn(3); 3569ed24f4bSMarc Zyngier cpu_if->vgic_ap1r[2] = __vgic_v3_read_ap1rn(2); 357df561f66SGustavo A. R. Silva fallthrough; 3589ed24f4bSMarc Zyngier case 6: 3599ed24f4bSMarc Zyngier cpu_if->vgic_ap1r[1] = __vgic_v3_read_ap1rn(1); 360df561f66SGustavo A. R. Silva fallthrough; 3619ed24f4bSMarc Zyngier default: 3629ed24f4bSMarc Zyngier cpu_if->vgic_ap1r[0] = __vgic_v3_read_ap1rn(0); 3639ed24f4bSMarc Zyngier } 3649ed24f4bSMarc Zyngier } 3659ed24f4bSMarc Zyngier 366c50cb043SDavid Brazdil void __vgic_v3_restore_aprs(struct vgic_v3_cpu_if *cpu_if) 3679ed24f4bSMarc Zyngier { 3689ed24f4bSMarc Zyngier u64 val; 3699ed24f4bSMarc Zyngier u32 nr_pre_bits; 3709ed24f4bSMarc Zyngier 3719ed24f4bSMarc Zyngier val = read_gicreg(ICH_VTR_EL2); 3729ed24f4bSMarc Zyngier nr_pre_bits = vtr_to_nr_pre_bits(val); 3739ed24f4bSMarc Zyngier 3749ed24f4bSMarc Zyngier switch (nr_pre_bits) { 3759ed24f4bSMarc Zyngier case 7: 3769ed24f4bSMarc Zyngier __vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[3], 3); 3779ed24f4bSMarc Zyngier __vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[2], 2); 378df561f66SGustavo A. R. Silva fallthrough; 3799ed24f4bSMarc Zyngier case 6: 3809ed24f4bSMarc Zyngier __vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[1], 1); 381df561f66SGustavo A. R. Silva fallthrough; 3829ed24f4bSMarc Zyngier default: 3839ed24f4bSMarc Zyngier __vgic_v3_write_ap0rn(cpu_if->vgic_ap0r[0], 0); 3849ed24f4bSMarc Zyngier } 3859ed24f4bSMarc Zyngier 3869ed24f4bSMarc Zyngier switch (nr_pre_bits) { 3879ed24f4bSMarc Zyngier case 7: 3889ed24f4bSMarc Zyngier __vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[3], 3); 3899ed24f4bSMarc Zyngier __vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[2], 2); 390df561f66SGustavo A. R. Silva fallthrough; 3919ed24f4bSMarc Zyngier case 6: 3929ed24f4bSMarc Zyngier __vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[1], 1); 393df561f66SGustavo A. R. Silva fallthrough; 3949ed24f4bSMarc Zyngier default: 3959ed24f4bSMarc Zyngier __vgic_v3_write_ap1rn(cpu_if->vgic_ap1r[0], 0); 3969ed24f4bSMarc Zyngier } 3979ed24f4bSMarc Zyngier } 3989ed24f4bSMarc Zyngier 399c50cb043SDavid Brazdil void __vgic_v3_init_lrs(void) 4009ed24f4bSMarc Zyngier { 4019ed24f4bSMarc Zyngier int max_lr_idx = vtr_to_max_lr_idx(read_gicreg(ICH_VTR_EL2)); 4029ed24f4bSMarc Zyngier int i; 4039ed24f4bSMarc Zyngier 4049ed24f4bSMarc Zyngier for (i = 0; i <= max_lr_idx; i++) 4059ed24f4bSMarc Zyngier __gic_v3_set_lr(0, i); 4069ed24f4bSMarc Zyngier } 4079ed24f4bSMarc Zyngier 408b9d699e2SMarc Zyngier /* 409b9d699e2SMarc Zyngier * Return the GIC CPU configuration: 410b9d699e2SMarc Zyngier * - [31:0] ICH_VTR_EL2 411*9739f6efSMarc Zyngier * - [62:32] RES0 412*9739f6efSMarc Zyngier * - [63] MMIO (GICv2) capable 413b9d699e2SMarc Zyngier */ 414b9d699e2SMarc Zyngier u64 __vgic_v3_get_gic_config(void) 4159ed24f4bSMarc Zyngier { 416*9739f6efSMarc Zyngier u64 val, sre = read_gicreg(ICC_SRE_EL1); 417*9739f6efSMarc Zyngier unsigned long flags = 0; 418*9739f6efSMarc Zyngier 419*9739f6efSMarc Zyngier /* 420*9739f6efSMarc Zyngier * To check whether we have a MMIO-based (GICv2 compatible) 421*9739f6efSMarc Zyngier * CPU interface, we need to disable the system register 422*9739f6efSMarc Zyngier * view. To do that safely, we have to prevent any interrupt 423*9739f6efSMarc Zyngier * from firing (which would be deadly). 424*9739f6efSMarc Zyngier * 425*9739f6efSMarc Zyngier * Note that this only makes sense on VHE, as interrupts are 426*9739f6efSMarc Zyngier * already masked for nVHE as part of the exception entry to 427*9739f6efSMarc Zyngier * EL2. 428*9739f6efSMarc Zyngier */ 429*9739f6efSMarc Zyngier if (has_vhe()) 430*9739f6efSMarc Zyngier flags = local_daif_save(); 431*9739f6efSMarc Zyngier 432*9739f6efSMarc Zyngier write_gicreg(0, ICC_SRE_EL1); 433*9739f6efSMarc Zyngier isb(); 434*9739f6efSMarc Zyngier 435*9739f6efSMarc Zyngier val = read_gicreg(ICC_SRE_EL1); 436*9739f6efSMarc Zyngier 437*9739f6efSMarc Zyngier write_gicreg(sre, ICC_SRE_EL1); 438*9739f6efSMarc Zyngier isb(); 439*9739f6efSMarc Zyngier 440*9739f6efSMarc Zyngier if (has_vhe()) 441*9739f6efSMarc Zyngier local_daif_restore(flags); 442*9739f6efSMarc Zyngier 443*9739f6efSMarc Zyngier val = (val & ICC_SRE_EL1_SRE) ? 0 : (1ULL << 63); 444*9739f6efSMarc Zyngier val |= read_gicreg(ICH_VTR_EL2); 445*9739f6efSMarc Zyngier 446*9739f6efSMarc Zyngier return val; 4479ed24f4bSMarc Zyngier } 4489ed24f4bSMarc Zyngier 449c50cb043SDavid Brazdil u64 __vgic_v3_read_vmcr(void) 4509ed24f4bSMarc Zyngier { 4519ed24f4bSMarc Zyngier return read_gicreg(ICH_VMCR_EL2); 4529ed24f4bSMarc Zyngier } 4539ed24f4bSMarc Zyngier 454c50cb043SDavid Brazdil void __vgic_v3_write_vmcr(u32 vmcr) 4559ed24f4bSMarc Zyngier { 4569ed24f4bSMarc Zyngier write_gicreg(vmcr, ICH_VMCR_EL2); 4579ed24f4bSMarc Zyngier } 4589ed24f4bSMarc Zyngier 459c50cb043SDavid Brazdil static int __vgic_v3_bpr_min(void) 4609ed24f4bSMarc Zyngier { 4619ed24f4bSMarc Zyngier /* See Pseudocode for VPriorityGroup */ 4629ed24f4bSMarc Zyngier return 8 - vtr_to_nr_pre_bits(read_gicreg(ICH_VTR_EL2)); 4639ed24f4bSMarc Zyngier } 4649ed24f4bSMarc Zyngier 465c50cb043SDavid Brazdil static int __vgic_v3_get_group(struct kvm_vcpu *vcpu) 4669ed24f4bSMarc Zyngier { 4673a949f4cSGavin Shan u32 esr = kvm_vcpu_get_esr(vcpu); 4689ed24f4bSMarc Zyngier u8 crm = (esr & ESR_ELx_SYS64_ISS_CRM_MASK) >> ESR_ELx_SYS64_ISS_CRM_SHIFT; 4699ed24f4bSMarc Zyngier 4709ed24f4bSMarc Zyngier return crm != 8; 4719ed24f4bSMarc Zyngier } 4729ed24f4bSMarc Zyngier 4739ed24f4bSMarc Zyngier #define GICv3_IDLE_PRIORITY 0xff 4749ed24f4bSMarc Zyngier 475c50cb043SDavid Brazdil static int __vgic_v3_highest_priority_lr(struct kvm_vcpu *vcpu, u32 vmcr, 4769ed24f4bSMarc Zyngier u64 *lr_val) 4779ed24f4bSMarc Zyngier { 478fc5d1f1aSChristoffer Dall unsigned int used_lrs = vcpu->arch.vgic_cpu.vgic_v3.used_lrs; 4799ed24f4bSMarc Zyngier u8 priority = GICv3_IDLE_PRIORITY; 4809ed24f4bSMarc Zyngier int i, lr = -1; 4819ed24f4bSMarc Zyngier 4829ed24f4bSMarc Zyngier for (i = 0; i < used_lrs; i++) { 4839ed24f4bSMarc Zyngier u64 val = __gic_v3_get_lr(i); 4849ed24f4bSMarc Zyngier u8 lr_prio = (val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT; 4859ed24f4bSMarc Zyngier 4869ed24f4bSMarc Zyngier /* Not pending in the state? */ 4879ed24f4bSMarc Zyngier if ((val & ICH_LR_STATE) != ICH_LR_PENDING_BIT) 4889ed24f4bSMarc Zyngier continue; 4899ed24f4bSMarc Zyngier 4909ed24f4bSMarc Zyngier /* Group-0 interrupt, but Group-0 disabled? */ 4919ed24f4bSMarc Zyngier if (!(val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG0_MASK)) 4929ed24f4bSMarc Zyngier continue; 4939ed24f4bSMarc Zyngier 4949ed24f4bSMarc Zyngier /* Group-1 interrupt, but Group-1 disabled? */ 4959ed24f4bSMarc Zyngier if ((val & ICH_LR_GROUP) && !(vmcr & ICH_VMCR_ENG1_MASK)) 4969ed24f4bSMarc Zyngier continue; 4979ed24f4bSMarc Zyngier 4989ed24f4bSMarc Zyngier /* Not the highest priority? */ 4999ed24f4bSMarc Zyngier if (lr_prio >= priority) 5009ed24f4bSMarc Zyngier continue; 5019ed24f4bSMarc Zyngier 5029ed24f4bSMarc Zyngier /* This is a candidate */ 5039ed24f4bSMarc Zyngier priority = lr_prio; 5049ed24f4bSMarc Zyngier *lr_val = val; 5059ed24f4bSMarc Zyngier lr = i; 5069ed24f4bSMarc Zyngier } 5079ed24f4bSMarc Zyngier 5089ed24f4bSMarc Zyngier if (lr == -1) 5099ed24f4bSMarc Zyngier *lr_val = ICC_IAR1_EL1_SPURIOUS; 5109ed24f4bSMarc Zyngier 5119ed24f4bSMarc Zyngier return lr; 5129ed24f4bSMarc Zyngier } 5139ed24f4bSMarc Zyngier 514c50cb043SDavid Brazdil static int __vgic_v3_find_active_lr(struct kvm_vcpu *vcpu, int intid, 515c50cb043SDavid Brazdil u64 *lr_val) 5169ed24f4bSMarc Zyngier { 517fc5d1f1aSChristoffer Dall unsigned int used_lrs = vcpu->arch.vgic_cpu.vgic_v3.used_lrs; 5189ed24f4bSMarc Zyngier int i; 5199ed24f4bSMarc Zyngier 5209ed24f4bSMarc Zyngier for (i = 0; i < used_lrs; i++) { 5219ed24f4bSMarc Zyngier u64 val = __gic_v3_get_lr(i); 5229ed24f4bSMarc Zyngier 5239ed24f4bSMarc Zyngier if ((val & ICH_LR_VIRTUAL_ID_MASK) == intid && 5249ed24f4bSMarc Zyngier (val & ICH_LR_ACTIVE_BIT)) { 5259ed24f4bSMarc Zyngier *lr_val = val; 5269ed24f4bSMarc Zyngier return i; 5279ed24f4bSMarc Zyngier } 5289ed24f4bSMarc Zyngier } 5299ed24f4bSMarc Zyngier 5309ed24f4bSMarc Zyngier *lr_val = ICC_IAR1_EL1_SPURIOUS; 5319ed24f4bSMarc Zyngier return -1; 5329ed24f4bSMarc Zyngier } 5339ed24f4bSMarc Zyngier 534c50cb043SDavid Brazdil static int __vgic_v3_get_highest_active_priority(void) 5359ed24f4bSMarc Zyngier { 5369ed24f4bSMarc Zyngier u8 nr_apr_regs = vtr_to_nr_apr_regs(read_gicreg(ICH_VTR_EL2)); 5379ed24f4bSMarc Zyngier u32 hap = 0; 5389ed24f4bSMarc Zyngier int i; 5399ed24f4bSMarc Zyngier 5409ed24f4bSMarc Zyngier for (i = 0; i < nr_apr_regs; i++) { 5419ed24f4bSMarc Zyngier u32 val; 5429ed24f4bSMarc Zyngier 5439ed24f4bSMarc Zyngier /* 5449ed24f4bSMarc Zyngier * The ICH_AP0Rn_EL2 and ICH_AP1Rn_EL2 registers 5459ed24f4bSMarc Zyngier * contain the active priority levels for this VCPU 5469ed24f4bSMarc Zyngier * for the maximum number of supported priority 5479ed24f4bSMarc Zyngier * levels, and we return the full priority level only 5489ed24f4bSMarc Zyngier * if the BPR is programmed to its minimum, otherwise 5499ed24f4bSMarc Zyngier * we return a combination of the priority level and 5509ed24f4bSMarc Zyngier * subpriority, as determined by the setting of the 5519ed24f4bSMarc Zyngier * BPR, but without the full subpriority. 5529ed24f4bSMarc Zyngier */ 5539ed24f4bSMarc Zyngier val = __vgic_v3_read_ap0rn(i); 5549ed24f4bSMarc Zyngier val |= __vgic_v3_read_ap1rn(i); 5559ed24f4bSMarc Zyngier if (!val) { 5569ed24f4bSMarc Zyngier hap += 32; 5579ed24f4bSMarc Zyngier continue; 5589ed24f4bSMarc Zyngier } 5599ed24f4bSMarc Zyngier 5609ed24f4bSMarc Zyngier return (hap + __ffs(val)) << __vgic_v3_bpr_min(); 5619ed24f4bSMarc Zyngier } 5629ed24f4bSMarc Zyngier 5639ed24f4bSMarc Zyngier return GICv3_IDLE_PRIORITY; 5649ed24f4bSMarc Zyngier } 5659ed24f4bSMarc Zyngier 566c50cb043SDavid Brazdil static unsigned int __vgic_v3_get_bpr0(u32 vmcr) 5679ed24f4bSMarc Zyngier { 5689ed24f4bSMarc Zyngier return (vmcr & ICH_VMCR_BPR0_MASK) >> ICH_VMCR_BPR0_SHIFT; 5699ed24f4bSMarc Zyngier } 5709ed24f4bSMarc Zyngier 571c50cb043SDavid Brazdil static unsigned int __vgic_v3_get_bpr1(u32 vmcr) 5729ed24f4bSMarc Zyngier { 5739ed24f4bSMarc Zyngier unsigned int bpr; 5749ed24f4bSMarc Zyngier 5759ed24f4bSMarc Zyngier if (vmcr & ICH_VMCR_CBPR_MASK) { 5769ed24f4bSMarc Zyngier bpr = __vgic_v3_get_bpr0(vmcr); 5779ed24f4bSMarc Zyngier if (bpr < 7) 5789ed24f4bSMarc Zyngier bpr++; 5799ed24f4bSMarc Zyngier } else { 5809ed24f4bSMarc Zyngier bpr = (vmcr & ICH_VMCR_BPR1_MASK) >> ICH_VMCR_BPR1_SHIFT; 5819ed24f4bSMarc Zyngier } 5829ed24f4bSMarc Zyngier 5839ed24f4bSMarc Zyngier return bpr; 5849ed24f4bSMarc Zyngier } 5859ed24f4bSMarc Zyngier 5869ed24f4bSMarc Zyngier /* 5879ed24f4bSMarc Zyngier * Convert a priority to a preemption level, taking the relevant BPR 5889ed24f4bSMarc Zyngier * into account by zeroing the sub-priority bits. 5899ed24f4bSMarc Zyngier */ 590c50cb043SDavid Brazdil static u8 __vgic_v3_pri_to_pre(u8 pri, u32 vmcr, int grp) 5919ed24f4bSMarc Zyngier { 5929ed24f4bSMarc Zyngier unsigned int bpr; 5939ed24f4bSMarc Zyngier 5949ed24f4bSMarc Zyngier if (!grp) 5959ed24f4bSMarc Zyngier bpr = __vgic_v3_get_bpr0(vmcr) + 1; 5969ed24f4bSMarc Zyngier else 5979ed24f4bSMarc Zyngier bpr = __vgic_v3_get_bpr1(vmcr); 5989ed24f4bSMarc Zyngier 5999ed24f4bSMarc Zyngier return pri & (GENMASK(7, 0) << bpr); 6009ed24f4bSMarc Zyngier } 6019ed24f4bSMarc Zyngier 6029ed24f4bSMarc Zyngier /* 6039ed24f4bSMarc Zyngier * The priority value is independent of any of the BPR values, so we 604656012c7SFuad Tabba * normalize it using the minimal BPR value. This guarantees that no 6059ed24f4bSMarc Zyngier * matter what the guest does with its BPR, we can always set/get the 6069ed24f4bSMarc Zyngier * same value of a priority. 6079ed24f4bSMarc Zyngier */ 608c50cb043SDavid Brazdil static void __vgic_v3_set_active_priority(u8 pri, u32 vmcr, int grp) 6099ed24f4bSMarc Zyngier { 6109ed24f4bSMarc Zyngier u8 pre, ap; 6119ed24f4bSMarc Zyngier u32 val; 6129ed24f4bSMarc Zyngier int apr; 6139ed24f4bSMarc Zyngier 6149ed24f4bSMarc Zyngier pre = __vgic_v3_pri_to_pre(pri, vmcr, grp); 6159ed24f4bSMarc Zyngier ap = pre >> __vgic_v3_bpr_min(); 6169ed24f4bSMarc Zyngier apr = ap / 32; 6179ed24f4bSMarc Zyngier 6189ed24f4bSMarc Zyngier if (!grp) { 6199ed24f4bSMarc Zyngier val = __vgic_v3_read_ap0rn(apr); 6209ed24f4bSMarc Zyngier __vgic_v3_write_ap0rn(val | BIT(ap % 32), apr); 6219ed24f4bSMarc Zyngier } else { 6229ed24f4bSMarc Zyngier val = __vgic_v3_read_ap1rn(apr); 6239ed24f4bSMarc Zyngier __vgic_v3_write_ap1rn(val | BIT(ap % 32), apr); 6249ed24f4bSMarc Zyngier } 6259ed24f4bSMarc Zyngier } 6269ed24f4bSMarc Zyngier 627c50cb043SDavid Brazdil static int __vgic_v3_clear_highest_active_priority(void) 6289ed24f4bSMarc Zyngier { 6299ed24f4bSMarc Zyngier u8 nr_apr_regs = vtr_to_nr_apr_regs(read_gicreg(ICH_VTR_EL2)); 6309ed24f4bSMarc Zyngier u32 hap = 0; 6319ed24f4bSMarc Zyngier int i; 6329ed24f4bSMarc Zyngier 6339ed24f4bSMarc Zyngier for (i = 0; i < nr_apr_regs; i++) { 6349ed24f4bSMarc Zyngier u32 ap0, ap1; 6359ed24f4bSMarc Zyngier int c0, c1; 6369ed24f4bSMarc Zyngier 6379ed24f4bSMarc Zyngier ap0 = __vgic_v3_read_ap0rn(i); 6389ed24f4bSMarc Zyngier ap1 = __vgic_v3_read_ap1rn(i); 6399ed24f4bSMarc Zyngier if (!ap0 && !ap1) { 6409ed24f4bSMarc Zyngier hap += 32; 6419ed24f4bSMarc Zyngier continue; 6429ed24f4bSMarc Zyngier } 6439ed24f4bSMarc Zyngier 6449ed24f4bSMarc Zyngier c0 = ap0 ? __ffs(ap0) : 32; 6459ed24f4bSMarc Zyngier c1 = ap1 ? __ffs(ap1) : 32; 6469ed24f4bSMarc Zyngier 6479ed24f4bSMarc Zyngier /* Always clear the LSB, which is the highest priority */ 6489ed24f4bSMarc Zyngier if (c0 < c1) { 6499ed24f4bSMarc Zyngier ap0 &= ~BIT(c0); 6509ed24f4bSMarc Zyngier __vgic_v3_write_ap0rn(ap0, i); 6519ed24f4bSMarc Zyngier hap += c0; 6529ed24f4bSMarc Zyngier } else { 6539ed24f4bSMarc Zyngier ap1 &= ~BIT(c1); 6549ed24f4bSMarc Zyngier __vgic_v3_write_ap1rn(ap1, i); 6559ed24f4bSMarc Zyngier hap += c1; 6569ed24f4bSMarc Zyngier } 6579ed24f4bSMarc Zyngier 6589ed24f4bSMarc Zyngier /* Rescale to 8 bits of priority */ 6599ed24f4bSMarc Zyngier return hap << __vgic_v3_bpr_min(); 6609ed24f4bSMarc Zyngier } 6619ed24f4bSMarc Zyngier 6629ed24f4bSMarc Zyngier return GICv3_IDLE_PRIORITY; 6639ed24f4bSMarc Zyngier } 6649ed24f4bSMarc Zyngier 665c50cb043SDavid Brazdil static void __vgic_v3_read_iar(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 6669ed24f4bSMarc Zyngier { 6679ed24f4bSMarc Zyngier u64 lr_val; 6689ed24f4bSMarc Zyngier u8 lr_prio, pmr; 6699ed24f4bSMarc Zyngier int lr, grp; 6709ed24f4bSMarc Zyngier 6719ed24f4bSMarc Zyngier grp = __vgic_v3_get_group(vcpu); 6729ed24f4bSMarc Zyngier 6739ed24f4bSMarc Zyngier lr = __vgic_v3_highest_priority_lr(vcpu, vmcr, &lr_val); 6749ed24f4bSMarc Zyngier if (lr < 0) 6759ed24f4bSMarc Zyngier goto spurious; 6769ed24f4bSMarc Zyngier 6779ed24f4bSMarc Zyngier if (grp != !!(lr_val & ICH_LR_GROUP)) 6789ed24f4bSMarc Zyngier goto spurious; 6799ed24f4bSMarc Zyngier 6809ed24f4bSMarc Zyngier pmr = (vmcr & ICH_VMCR_PMR_MASK) >> ICH_VMCR_PMR_SHIFT; 6819ed24f4bSMarc Zyngier lr_prio = (lr_val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT; 6829ed24f4bSMarc Zyngier if (pmr <= lr_prio) 6839ed24f4bSMarc Zyngier goto spurious; 6849ed24f4bSMarc Zyngier 6859ed24f4bSMarc Zyngier if (__vgic_v3_get_highest_active_priority() <= __vgic_v3_pri_to_pre(lr_prio, vmcr, grp)) 6869ed24f4bSMarc Zyngier goto spurious; 6879ed24f4bSMarc Zyngier 6889ed24f4bSMarc Zyngier lr_val &= ~ICH_LR_STATE; 6899ed24f4bSMarc Zyngier /* No active state for LPIs */ 6909ed24f4bSMarc Zyngier if ((lr_val & ICH_LR_VIRTUAL_ID_MASK) <= VGIC_MAX_SPI) 6919ed24f4bSMarc Zyngier lr_val |= ICH_LR_ACTIVE_BIT; 6929ed24f4bSMarc Zyngier __gic_v3_set_lr(lr_val, lr); 6939ed24f4bSMarc Zyngier __vgic_v3_set_active_priority(lr_prio, vmcr, grp); 6949ed24f4bSMarc Zyngier vcpu_set_reg(vcpu, rt, lr_val & ICH_LR_VIRTUAL_ID_MASK); 6959ed24f4bSMarc Zyngier return; 6969ed24f4bSMarc Zyngier 6979ed24f4bSMarc Zyngier spurious: 6989ed24f4bSMarc Zyngier vcpu_set_reg(vcpu, rt, ICC_IAR1_EL1_SPURIOUS); 6999ed24f4bSMarc Zyngier } 7009ed24f4bSMarc Zyngier 701c50cb043SDavid Brazdil static void __vgic_v3_clear_active_lr(int lr, u64 lr_val) 7029ed24f4bSMarc Zyngier { 7039ed24f4bSMarc Zyngier lr_val &= ~ICH_LR_ACTIVE_BIT; 7049ed24f4bSMarc Zyngier if (lr_val & ICH_LR_HW) { 7059ed24f4bSMarc Zyngier u32 pid; 7069ed24f4bSMarc Zyngier 7079ed24f4bSMarc Zyngier pid = (lr_val & ICH_LR_PHYS_ID_MASK) >> ICH_LR_PHYS_ID_SHIFT; 7089ed24f4bSMarc Zyngier gic_write_dir(pid); 7099ed24f4bSMarc Zyngier } 7109ed24f4bSMarc Zyngier 7119ed24f4bSMarc Zyngier __gic_v3_set_lr(lr_val, lr); 7129ed24f4bSMarc Zyngier } 7139ed24f4bSMarc Zyngier 714c50cb043SDavid Brazdil static void __vgic_v3_bump_eoicount(void) 7159ed24f4bSMarc Zyngier { 7169ed24f4bSMarc Zyngier u32 hcr; 7179ed24f4bSMarc Zyngier 7189ed24f4bSMarc Zyngier hcr = read_gicreg(ICH_HCR_EL2); 7199ed24f4bSMarc Zyngier hcr += 1 << ICH_HCR_EOIcount_SHIFT; 7209ed24f4bSMarc Zyngier write_gicreg(hcr, ICH_HCR_EL2); 7219ed24f4bSMarc Zyngier } 7229ed24f4bSMarc Zyngier 723c50cb043SDavid Brazdil static void __vgic_v3_write_dir(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 7249ed24f4bSMarc Zyngier { 7259ed24f4bSMarc Zyngier u32 vid = vcpu_get_reg(vcpu, rt); 7269ed24f4bSMarc Zyngier u64 lr_val; 7279ed24f4bSMarc Zyngier int lr; 7289ed24f4bSMarc Zyngier 7299ed24f4bSMarc Zyngier /* EOImode == 0, nothing to be done here */ 7309ed24f4bSMarc Zyngier if (!(vmcr & ICH_VMCR_EOIM_MASK)) 7319ed24f4bSMarc Zyngier return; 7329ed24f4bSMarc Zyngier 7339ed24f4bSMarc Zyngier /* No deactivate to be performed on an LPI */ 7349ed24f4bSMarc Zyngier if (vid >= VGIC_MIN_LPI) 7359ed24f4bSMarc Zyngier return; 7369ed24f4bSMarc Zyngier 7379ed24f4bSMarc Zyngier lr = __vgic_v3_find_active_lr(vcpu, vid, &lr_val); 7389ed24f4bSMarc Zyngier if (lr == -1) { 7399ed24f4bSMarc Zyngier __vgic_v3_bump_eoicount(); 7409ed24f4bSMarc Zyngier return; 7419ed24f4bSMarc Zyngier } 7429ed24f4bSMarc Zyngier 7439ed24f4bSMarc Zyngier __vgic_v3_clear_active_lr(lr, lr_val); 7449ed24f4bSMarc Zyngier } 7459ed24f4bSMarc Zyngier 746c50cb043SDavid Brazdil static void __vgic_v3_write_eoir(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 7479ed24f4bSMarc Zyngier { 7489ed24f4bSMarc Zyngier u32 vid = vcpu_get_reg(vcpu, rt); 7499ed24f4bSMarc Zyngier u64 lr_val; 7509ed24f4bSMarc Zyngier u8 lr_prio, act_prio; 7519ed24f4bSMarc Zyngier int lr, grp; 7529ed24f4bSMarc Zyngier 7539ed24f4bSMarc Zyngier grp = __vgic_v3_get_group(vcpu); 7549ed24f4bSMarc Zyngier 7559ed24f4bSMarc Zyngier /* Drop priority in any case */ 7569ed24f4bSMarc Zyngier act_prio = __vgic_v3_clear_highest_active_priority(); 7579ed24f4bSMarc Zyngier 7589ed24f4bSMarc Zyngier /* If EOIing an LPI, no deactivate to be performed */ 7599ed24f4bSMarc Zyngier if (vid >= VGIC_MIN_LPI) 7609ed24f4bSMarc Zyngier return; 7619ed24f4bSMarc Zyngier 7629ed24f4bSMarc Zyngier /* EOImode == 1, nothing to be done here */ 7639ed24f4bSMarc Zyngier if (vmcr & ICH_VMCR_EOIM_MASK) 7649ed24f4bSMarc Zyngier return; 7659ed24f4bSMarc Zyngier 7669ed24f4bSMarc Zyngier lr = __vgic_v3_find_active_lr(vcpu, vid, &lr_val); 7679ed24f4bSMarc Zyngier if (lr == -1) { 7689ed24f4bSMarc Zyngier __vgic_v3_bump_eoicount(); 7699ed24f4bSMarc Zyngier return; 7709ed24f4bSMarc Zyngier } 7719ed24f4bSMarc Zyngier 7729ed24f4bSMarc Zyngier lr_prio = (lr_val & ICH_LR_PRIORITY_MASK) >> ICH_LR_PRIORITY_SHIFT; 7739ed24f4bSMarc Zyngier 7749ed24f4bSMarc Zyngier /* If priorities or group do not match, the guest has fscked-up. */ 7759ed24f4bSMarc Zyngier if (grp != !!(lr_val & ICH_LR_GROUP) || 7769ed24f4bSMarc Zyngier __vgic_v3_pri_to_pre(lr_prio, vmcr, grp) != act_prio) 7779ed24f4bSMarc Zyngier return; 7789ed24f4bSMarc Zyngier 7799ed24f4bSMarc Zyngier /* Let's now perform the deactivation */ 7809ed24f4bSMarc Zyngier __vgic_v3_clear_active_lr(lr, lr_val); 7819ed24f4bSMarc Zyngier } 7829ed24f4bSMarc Zyngier 783c50cb043SDavid Brazdil static void __vgic_v3_read_igrpen0(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 7849ed24f4bSMarc Zyngier { 7859ed24f4bSMarc Zyngier vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG0_MASK)); 7869ed24f4bSMarc Zyngier } 7879ed24f4bSMarc Zyngier 788c50cb043SDavid Brazdil static void __vgic_v3_read_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 7899ed24f4bSMarc Zyngier { 7909ed24f4bSMarc Zyngier vcpu_set_reg(vcpu, rt, !!(vmcr & ICH_VMCR_ENG1_MASK)); 7919ed24f4bSMarc Zyngier } 7929ed24f4bSMarc Zyngier 793c50cb043SDavid Brazdil static void __vgic_v3_write_igrpen0(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 7949ed24f4bSMarc Zyngier { 7959ed24f4bSMarc Zyngier u64 val = vcpu_get_reg(vcpu, rt); 7969ed24f4bSMarc Zyngier 7979ed24f4bSMarc Zyngier if (val & 1) 7989ed24f4bSMarc Zyngier vmcr |= ICH_VMCR_ENG0_MASK; 7999ed24f4bSMarc Zyngier else 8009ed24f4bSMarc Zyngier vmcr &= ~ICH_VMCR_ENG0_MASK; 8019ed24f4bSMarc Zyngier 8029ed24f4bSMarc Zyngier __vgic_v3_write_vmcr(vmcr); 8039ed24f4bSMarc Zyngier } 8049ed24f4bSMarc Zyngier 805c50cb043SDavid Brazdil static void __vgic_v3_write_igrpen1(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 8069ed24f4bSMarc Zyngier { 8079ed24f4bSMarc Zyngier u64 val = vcpu_get_reg(vcpu, rt); 8089ed24f4bSMarc Zyngier 8099ed24f4bSMarc Zyngier if (val & 1) 8109ed24f4bSMarc Zyngier vmcr |= ICH_VMCR_ENG1_MASK; 8119ed24f4bSMarc Zyngier else 8129ed24f4bSMarc Zyngier vmcr &= ~ICH_VMCR_ENG1_MASK; 8139ed24f4bSMarc Zyngier 8149ed24f4bSMarc Zyngier __vgic_v3_write_vmcr(vmcr); 8159ed24f4bSMarc Zyngier } 8169ed24f4bSMarc Zyngier 817c50cb043SDavid Brazdil static void __vgic_v3_read_bpr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 8189ed24f4bSMarc Zyngier { 8199ed24f4bSMarc Zyngier vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr0(vmcr)); 8209ed24f4bSMarc Zyngier } 8219ed24f4bSMarc Zyngier 822c50cb043SDavid Brazdil static void __vgic_v3_read_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 8239ed24f4bSMarc Zyngier { 8249ed24f4bSMarc Zyngier vcpu_set_reg(vcpu, rt, __vgic_v3_get_bpr1(vmcr)); 8259ed24f4bSMarc Zyngier } 8269ed24f4bSMarc Zyngier 827c50cb043SDavid Brazdil static void __vgic_v3_write_bpr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 8289ed24f4bSMarc Zyngier { 8299ed24f4bSMarc Zyngier u64 val = vcpu_get_reg(vcpu, rt); 8309ed24f4bSMarc Zyngier u8 bpr_min = __vgic_v3_bpr_min() - 1; 8319ed24f4bSMarc Zyngier 8329ed24f4bSMarc Zyngier /* Enforce BPR limiting */ 8339ed24f4bSMarc Zyngier if (val < bpr_min) 8349ed24f4bSMarc Zyngier val = bpr_min; 8359ed24f4bSMarc Zyngier 8369ed24f4bSMarc Zyngier val <<= ICH_VMCR_BPR0_SHIFT; 8379ed24f4bSMarc Zyngier val &= ICH_VMCR_BPR0_MASK; 8389ed24f4bSMarc Zyngier vmcr &= ~ICH_VMCR_BPR0_MASK; 8399ed24f4bSMarc Zyngier vmcr |= val; 8409ed24f4bSMarc Zyngier 8419ed24f4bSMarc Zyngier __vgic_v3_write_vmcr(vmcr); 8429ed24f4bSMarc Zyngier } 8439ed24f4bSMarc Zyngier 844c50cb043SDavid Brazdil static void __vgic_v3_write_bpr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 8459ed24f4bSMarc Zyngier { 8469ed24f4bSMarc Zyngier u64 val = vcpu_get_reg(vcpu, rt); 8479ed24f4bSMarc Zyngier u8 bpr_min = __vgic_v3_bpr_min(); 8489ed24f4bSMarc Zyngier 8499ed24f4bSMarc Zyngier if (vmcr & ICH_VMCR_CBPR_MASK) 8509ed24f4bSMarc Zyngier return; 8519ed24f4bSMarc Zyngier 8529ed24f4bSMarc Zyngier /* Enforce BPR limiting */ 8539ed24f4bSMarc Zyngier if (val < bpr_min) 8549ed24f4bSMarc Zyngier val = bpr_min; 8559ed24f4bSMarc Zyngier 8569ed24f4bSMarc Zyngier val <<= ICH_VMCR_BPR1_SHIFT; 8579ed24f4bSMarc Zyngier val &= ICH_VMCR_BPR1_MASK; 8589ed24f4bSMarc Zyngier vmcr &= ~ICH_VMCR_BPR1_MASK; 8599ed24f4bSMarc Zyngier vmcr |= val; 8609ed24f4bSMarc Zyngier 8619ed24f4bSMarc Zyngier __vgic_v3_write_vmcr(vmcr); 8629ed24f4bSMarc Zyngier } 8639ed24f4bSMarc Zyngier 864c50cb043SDavid Brazdil static void __vgic_v3_read_apxrn(struct kvm_vcpu *vcpu, int rt, int n) 8659ed24f4bSMarc Zyngier { 8669ed24f4bSMarc Zyngier u32 val; 8679ed24f4bSMarc Zyngier 8689ed24f4bSMarc Zyngier if (!__vgic_v3_get_group(vcpu)) 8699ed24f4bSMarc Zyngier val = __vgic_v3_read_ap0rn(n); 8709ed24f4bSMarc Zyngier else 8719ed24f4bSMarc Zyngier val = __vgic_v3_read_ap1rn(n); 8729ed24f4bSMarc Zyngier 8739ed24f4bSMarc Zyngier vcpu_set_reg(vcpu, rt, val); 8749ed24f4bSMarc Zyngier } 8759ed24f4bSMarc Zyngier 876c50cb043SDavid Brazdil static void __vgic_v3_write_apxrn(struct kvm_vcpu *vcpu, int rt, int n) 8779ed24f4bSMarc Zyngier { 8789ed24f4bSMarc Zyngier u32 val = vcpu_get_reg(vcpu, rt); 8799ed24f4bSMarc Zyngier 8809ed24f4bSMarc Zyngier if (!__vgic_v3_get_group(vcpu)) 8819ed24f4bSMarc Zyngier __vgic_v3_write_ap0rn(val, n); 8829ed24f4bSMarc Zyngier else 8839ed24f4bSMarc Zyngier __vgic_v3_write_ap1rn(val, n); 8849ed24f4bSMarc Zyngier } 8859ed24f4bSMarc Zyngier 886c50cb043SDavid Brazdil static void __vgic_v3_read_apxr0(struct kvm_vcpu *vcpu, 8879ed24f4bSMarc Zyngier u32 vmcr, int rt) 8889ed24f4bSMarc Zyngier { 8899ed24f4bSMarc Zyngier __vgic_v3_read_apxrn(vcpu, rt, 0); 8909ed24f4bSMarc Zyngier } 8919ed24f4bSMarc Zyngier 892c50cb043SDavid Brazdil static void __vgic_v3_read_apxr1(struct kvm_vcpu *vcpu, 8939ed24f4bSMarc Zyngier u32 vmcr, int rt) 8949ed24f4bSMarc Zyngier { 8959ed24f4bSMarc Zyngier __vgic_v3_read_apxrn(vcpu, rt, 1); 8969ed24f4bSMarc Zyngier } 8979ed24f4bSMarc Zyngier 898c50cb043SDavid Brazdil static void __vgic_v3_read_apxr2(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 8999ed24f4bSMarc Zyngier { 9009ed24f4bSMarc Zyngier __vgic_v3_read_apxrn(vcpu, rt, 2); 9019ed24f4bSMarc Zyngier } 9029ed24f4bSMarc Zyngier 903c50cb043SDavid Brazdil static void __vgic_v3_read_apxr3(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 9049ed24f4bSMarc Zyngier { 9059ed24f4bSMarc Zyngier __vgic_v3_read_apxrn(vcpu, rt, 3); 9069ed24f4bSMarc Zyngier } 9079ed24f4bSMarc Zyngier 908c50cb043SDavid Brazdil static void __vgic_v3_write_apxr0(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 9099ed24f4bSMarc Zyngier { 9109ed24f4bSMarc Zyngier __vgic_v3_write_apxrn(vcpu, rt, 0); 9119ed24f4bSMarc Zyngier } 9129ed24f4bSMarc Zyngier 913c50cb043SDavid Brazdil static void __vgic_v3_write_apxr1(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 9149ed24f4bSMarc Zyngier { 9159ed24f4bSMarc Zyngier __vgic_v3_write_apxrn(vcpu, rt, 1); 9169ed24f4bSMarc Zyngier } 9179ed24f4bSMarc Zyngier 918c50cb043SDavid Brazdil static void __vgic_v3_write_apxr2(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 9199ed24f4bSMarc Zyngier { 9209ed24f4bSMarc Zyngier __vgic_v3_write_apxrn(vcpu, rt, 2); 9219ed24f4bSMarc Zyngier } 9229ed24f4bSMarc Zyngier 923c50cb043SDavid Brazdil static void __vgic_v3_write_apxr3(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 9249ed24f4bSMarc Zyngier { 9259ed24f4bSMarc Zyngier __vgic_v3_write_apxrn(vcpu, rt, 3); 9269ed24f4bSMarc Zyngier } 9279ed24f4bSMarc Zyngier 928c50cb043SDavid Brazdil static void __vgic_v3_read_hppir(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 9299ed24f4bSMarc Zyngier { 9309ed24f4bSMarc Zyngier u64 lr_val; 9319ed24f4bSMarc Zyngier int lr, lr_grp, grp; 9329ed24f4bSMarc Zyngier 9339ed24f4bSMarc Zyngier grp = __vgic_v3_get_group(vcpu); 9349ed24f4bSMarc Zyngier 9359ed24f4bSMarc Zyngier lr = __vgic_v3_highest_priority_lr(vcpu, vmcr, &lr_val); 9369ed24f4bSMarc Zyngier if (lr == -1) 9379ed24f4bSMarc Zyngier goto spurious; 9389ed24f4bSMarc Zyngier 9399ed24f4bSMarc Zyngier lr_grp = !!(lr_val & ICH_LR_GROUP); 9409ed24f4bSMarc Zyngier if (lr_grp != grp) 9419ed24f4bSMarc Zyngier lr_val = ICC_IAR1_EL1_SPURIOUS; 9429ed24f4bSMarc Zyngier 9439ed24f4bSMarc Zyngier spurious: 9449ed24f4bSMarc Zyngier vcpu_set_reg(vcpu, rt, lr_val & ICH_LR_VIRTUAL_ID_MASK); 9459ed24f4bSMarc Zyngier } 9469ed24f4bSMarc Zyngier 947c50cb043SDavid Brazdil static void __vgic_v3_read_pmr(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 9489ed24f4bSMarc Zyngier { 9499ed24f4bSMarc Zyngier vmcr &= ICH_VMCR_PMR_MASK; 9509ed24f4bSMarc Zyngier vmcr >>= ICH_VMCR_PMR_SHIFT; 9519ed24f4bSMarc Zyngier vcpu_set_reg(vcpu, rt, vmcr); 9529ed24f4bSMarc Zyngier } 9539ed24f4bSMarc Zyngier 954c50cb043SDavid Brazdil static void __vgic_v3_write_pmr(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 9559ed24f4bSMarc Zyngier { 9569ed24f4bSMarc Zyngier u32 val = vcpu_get_reg(vcpu, rt); 9579ed24f4bSMarc Zyngier 9589ed24f4bSMarc Zyngier val <<= ICH_VMCR_PMR_SHIFT; 9599ed24f4bSMarc Zyngier val &= ICH_VMCR_PMR_MASK; 9609ed24f4bSMarc Zyngier vmcr &= ~ICH_VMCR_PMR_MASK; 9619ed24f4bSMarc Zyngier vmcr |= val; 9629ed24f4bSMarc Zyngier 9639ed24f4bSMarc Zyngier write_gicreg(vmcr, ICH_VMCR_EL2); 9649ed24f4bSMarc Zyngier } 9659ed24f4bSMarc Zyngier 966c50cb043SDavid Brazdil static void __vgic_v3_read_rpr(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 9679ed24f4bSMarc Zyngier { 9689ed24f4bSMarc Zyngier u32 val = __vgic_v3_get_highest_active_priority(); 9699ed24f4bSMarc Zyngier vcpu_set_reg(vcpu, rt, val); 9709ed24f4bSMarc Zyngier } 9719ed24f4bSMarc Zyngier 972c50cb043SDavid Brazdil static void __vgic_v3_read_ctlr(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 9739ed24f4bSMarc Zyngier { 9749ed24f4bSMarc Zyngier u32 vtr, val; 9759ed24f4bSMarc Zyngier 9769ed24f4bSMarc Zyngier vtr = read_gicreg(ICH_VTR_EL2); 9779ed24f4bSMarc Zyngier /* PRIbits */ 9789ed24f4bSMarc Zyngier val = ((vtr >> 29) & 7) << ICC_CTLR_EL1_PRI_BITS_SHIFT; 9799ed24f4bSMarc Zyngier /* IDbits */ 9809ed24f4bSMarc Zyngier val |= ((vtr >> 23) & 7) << ICC_CTLR_EL1_ID_BITS_SHIFT; 9819ed24f4bSMarc Zyngier /* SEIS */ 9829ed24f4bSMarc Zyngier val |= ((vtr >> 22) & 1) << ICC_CTLR_EL1_SEIS_SHIFT; 9839ed24f4bSMarc Zyngier /* A3V */ 9849ed24f4bSMarc Zyngier val |= ((vtr >> 21) & 1) << ICC_CTLR_EL1_A3V_SHIFT; 9859ed24f4bSMarc Zyngier /* EOImode */ 9869ed24f4bSMarc Zyngier val |= ((vmcr & ICH_VMCR_EOIM_MASK) >> ICH_VMCR_EOIM_SHIFT) << ICC_CTLR_EL1_EOImode_SHIFT; 9879ed24f4bSMarc Zyngier /* CBPR */ 9889ed24f4bSMarc Zyngier val |= (vmcr & ICH_VMCR_CBPR_MASK) >> ICH_VMCR_CBPR_SHIFT; 9899ed24f4bSMarc Zyngier 9909ed24f4bSMarc Zyngier vcpu_set_reg(vcpu, rt, val); 9919ed24f4bSMarc Zyngier } 9929ed24f4bSMarc Zyngier 993c50cb043SDavid Brazdil static void __vgic_v3_write_ctlr(struct kvm_vcpu *vcpu, u32 vmcr, int rt) 9949ed24f4bSMarc Zyngier { 9959ed24f4bSMarc Zyngier u32 val = vcpu_get_reg(vcpu, rt); 9969ed24f4bSMarc Zyngier 9979ed24f4bSMarc Zyngier if (val & ICC_CTLR_EL1_CBPR_MASK) 9989ed24f4bSMarc Zyngier vmcr |= ICH_VMCR_CBPR_MASK; 9999ed24f4bSMarc Zyngier else 10009ed24f4bSMarc Zyngier vmcr &= ~ICH_VMCR_CBPR_MASK; 10019ed24f4bSMarc Zyngier 10029ed24f4bSMarc Zyngier if (val & ICC_CTLR_EL1_EOImode_MASK) 10039ed24f4bSMarc Zyngier vmcr |= ICH_VMCR_EOIM_MASK; 10049ed24f4bSMarc Zyngier else 10059ed24f4bSMarc Zyngier vmcr &= ~ICH_VMCR_EOIM_MASK; 10069ed24f4bSMarc Zyngier 10079ed24f4bSMarc Zyngier write_gicreg(vmcr, ICH_VMCR_EL2); 10089ed24f4bSMarc Zyngier } 10099ed24f4bSMarc Zyngier 1010c50cb043SDavid Brazdil int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu) 10119ed24f4bSMarc Zyngier { 10129ed24f4bSMarc Zyngier int rt; 10139ed24f4bSMarc Zyngier u32 esr; 10149ed24f4bSMarc Zyngier u32 vmcr; 10159ed24f4bSMarc Zyngier void (*fn)(struct kvm_vcpu *, u32, int); 10169ed24f4bSMarc Zyngier bool is_read; 10179ed24f4bSMarc Zyngier u32 sysreg; 10189ed24f4bSMarc Zyngier 10193a949f4cSGavin Shan esr = kvm_vcpu_get_esr(vcpu); 10209ed24f4bSMarc Zyngier if (vcpu_mode_is_32bit(vcpu)) { 10219ed24f4bSMarc Zyngier if (!kvm_condition_valid(vcpu)) { 10229ed24f4bSMarc Zyngier __kvm_skip_instr(vcpu); 10239ed24f4bSMarc Zyngier return 1; 10249ed24f4bSMarc Zyngier } 10259ed24f4bSMarc Zyngier 10269ed24f4bSMarc Zyngier sysreg = esr_cp15_to_sysreg(esr); 10279ed24f4bSMarc Zyngier } else { 10289ed24f4bSMarc Zyngier sysreg = esr_sys64_to_sysreg(esr); 10299ed24f4bSMarc Zyngier } 10309ed24f4bSMarc Zyngier 10319ed24f4bSMarc Zyngier is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ; 10329ed24f4bSMarc Zyngier 10339ed24f4bSMarc Zyngier switch (sysreg) { 10349ed24f4bSMarc Zyngier case SYS_ICC_IAR0_EL1: 10359ed24f4bSMarc Zyngier case SYS_ICC_IAR1_EL1: 10369ed24f4bSMarc Zyngier if (unlikely(!is_read)) 10379ed24f4bSMarc Zyngier return 0; 10389ed24f4bSMarc Zyngier fn = __vgic_v3_read_iar; 10399ed24f4bSMarc Zyngier break; 10409ed24f4bSMarc Zyngier case SYS_ICC_EOIR0_EL1: 10419ed24f4bSMarc Zyngier case SYS_ICC_EOIR1_EL1: 10429ed24f4bSMarc Zyngier if (unlikely(is_read)) 10439ed24f4bSMarc Zyngier return 0; 10449ed24f4bSMarc Zyngier fn = __vgic_v3_write_eoir; 10459ed24f4bSMarc Zyngier break; 10469ed24f4bSMarc Zyngier case SYS_ICC_IGRPEN1_EL1: 10479ed24f4bSMarc Zyngier if (is_read) 10489ed24f4bSMarc Zyngier fn = __vgic_v3_read_igrpen1; 10499ed24f4bSMarc Zyngier else 10509ed24f4bSMarc Zyngier fn = __vgic_v3_write_igrpen1; 10519ed24f4bSMarc Zyngier break; 10529ed24f4bSMarc Zyngier case SYS_ICC_BPR1_EL1: 10539ed24f4bSMarc Zyngier if (is_read) 10549ed24f4bSMarc Zyngier fn = __vgic_v3_read_bpr1; 10559ed24f4bSMarc Zyngier else 10569ed24f4bSMarc Zyngier fn = __vgic_v3_write_bpr1; 10579ed24f4bSMarc Zyngier break; 10589ed24f4bSMarc Zyngier case SYS_ICC_AP0Rn_EL1(0): 10599ed24f4bSMarc Zyngier case SYS_ICC_AP1Rn_EL1(0): 10609ed24f4bSMarc Zyngier if (is_read) 10619ed24f4bSMarc Zyngier fn = __vgic_v3_read_apxr0; 10629ed24f4bSMarc Zyngier else 10639ed24f4bSMarc Zyngier fn = __vgic_v3_write_apxr0; 10649ed24f4bSMarc Zyngier break; 10659ed24f4bSMarc Zyngier case SYS_ICC_AP0Rn_EL1(1): 10669ed24f4bSMarc Zyngier case SYS_ICC_AP1Rn_EL1(1): 10679ed24f4bSMarc Zyngier if (is_read) 10689ed24f4bSMarc Zyngier fn = __vgic_v3_read_apxr1; 10699ed24f4bSMarc Zyngier else 10709ed24f4bSMarc Zyngier fn = __vgic_v3_write_apxr1; 10719ed24f4bSMarc Zyngier break; 10729ed24f4bSMarc Zyngier case SYS_ICC_AP0Rn_EL1(2): 10739ed24f4bSMarc Zyngier case SYS_ICC_AP1Rn_EL1(2): 10749ed24f4bSMarc Zyngier if (is_read) 10759ed24f4bSMarc Zyngier fn = __vgic_v3_read_apxr2; 10769ed24f4bSMarc Zyngier else 10779ed24f4bSMarc Zyngier fn = __vgic_v3_write_apxr2; 10789ed24f4bSMarc Zyngier break; 10799ed24f4bSMarc Zyngier case SYS_ICC_AP0Rn_EL1(3): 10809ed24f4bSMarc Zyngier case SYS_ICC_AP1Rn_EL1(3): 10819ed24f4bSMarc Zyngier if (is_read) 10829ed24f4bSMarc Zyngier fn = __vgic_v3_read_apxr3; 10839ed24f4bSMarc Zyngier else 10849ed24f4bSMarc Zyngier fn = __vgic_v3_write_apxr3; 10859ed24f4bSMarc Zyngier break; 10869ed24f4bSMarc Zyngier case SYS_ICC_HPPIR0_EL1: 10879ed24f4bSMarc Zyngier case SYS_ICC_HPPIR1_EL1: 10889ed24f4bSMarc Zyngier if (unlikely(!is_read)) 10899ed24f4bSMarc Zyngier return 0; 10909ed24f4bSMarc Zyngier fn = __vgic_v3_read_hppir; 10919ed24f4bSMarc Zyngier break; 10929ed24f4bSMarc Zyngier case SYS_ICC_IGRPEN0_EL1: 10939ed24f4bSMarc Zyngier if (is_read) 10949ed24f4bSMarc Zyngier fn = __vgic_v3_read_igrpen0; 10959ed24f4bSMarc Zyngier else 10969ed24f4bSMarc Zyngier fn = __vgic_v3_write_igrpen0; 10979ed24f4bSMarc Zyngier break; 10989ed24f4bSMarc Zyngier case SYS_ICC_BPR0_EL1: 10999ed24f4bSMarc Zyngier if (is_read) 11009ed24f4bSMarc Zyngier fn = __vgic_v3_read_bpr0; 11019ed24f4bSMarc Zyngier else 11029ed24f4bSMarc Zyngier fn = __vgic_v3_write_bpr0; 11039ed24f4bSMarc Zyngier break; 11049ed24f4bSMarc Zyngier case SYS_ICC_DIR_EL1: 11059ed24f4bSMarc Zyngier if (unlikely(is_read)) 11069ed24f4bSMarc Zyngier return 0; 11079ed24f4bSMarc Zyngier fn = __vgic_v3_write_dir; 11089ed24f4bSMarc Zyngier break; 11099ed24f4bSMarc Zyngier case SYS_ICC_RPR_EL1: 11109ed24f4bSMarc Zyngier if (unlikely(!is_read)) 11119ed24f4bSMarc Zyngier return 0; 11129ed24f4bSMarc Zyngier fn = __vgic_v3_read_rpr; 11139ed24f4bSMarc Zyngier break; 11149ed24f4bSMarc Zyngier case SYS_ICC_CTLR_EL1: 11159ed24f4bSMarc Zyngier if (is_read) 11169ed24f4bSMarc Zyngier fn = __vgic_v3_read_ctlr; 11179ed24f4bSMarc Zyngier else 11189ed24f4bSMarc Zyngier fn = __vgic_v3_write_ctlr; 11199ed24f4bSMarc Zyngier break; 11209ed24f4bSMarc Zyngier case SYS_ICC_PMR_EL1: 11219ed24f4bSMarc Zyngier if (is_read) 11229ed24f4bSMarc Zyngier fn = __vgic_v3_read_pmr; 11239ed24f4bSMarc Zyngier else 11249ed24f4bSMarc Zyngier fn = __vgic_v3_write_pmr; 11259ed24f4bSMarc Zyngier break; 11269ed24f4bSMarc Zyngier default: 11279ed24f4bSMarc Zyngier return 0; 11289ed24f4bSMarc Zyngier } 11299ed24f4bSMarc Zyngier 11309ed24f4bSMarc Zyngier vmcr = __vgic_v3_read_vmcr(); 11319ed24f4bSMarc Zyngier rt = kvm_vcpu_sys_get_rt(vcpu); 11329ed24f4bSMarc Zyngier fn(vcpu, vmcr, rt); 11339ed24f4bSMarc Zyngier 11349ed24f4bSMarc Zyngier __kvm_skip_instr(vcpu); 11359ed24f4bSMarc Zyngier 11369ed24f4bSMarc Zyngier return 1; 11379ed24f4bSMarc Zyngier } 1138