1a7bf3034SPavel Fedin /* 2a7bf3034SPavel Fedin * ARM Generic Interrupt Controller using KVM in-kernel support 3a7bf3034SPavel Fedin * 4a7bf3034SPavel Fedin * Copyright (c) 2015 Samsung Electronics Co., Ltd. 5a7bf3034SPavel Fedin * Written by Pavel Fedin 6a7bf3034SPavel Fedin * Based on vGICv2 code by Peter Maydell 7a7bf3034SPavel Fedin * 8a7bf3034SPavel Fedin * This program is free software; you can redistribute it and/or modify 9a7bf3034SPavel Fedin * it under the terms of the GNU General Public License as published by 10a7bf3034SPavel Fedin * the Free Software Foundation, either version 2 of the License, or 11a7bf3034SPavel Fedin * (at your option) any later version. 12a7bf3034SPavel Fedin * 13a7bf3034SPavel Fedin * This program is distributed in the hope that it will be useful, 14a7bf3034SPavel Fedin * but WITHOUT ANY WARRANTY; without even the implied warranty of 15a7bf3034SPavel Fedin * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16a7bf3034SPavel Fedin * GNU General Public License for more details. 17a7bf3034SPavel Fedin * 18a7bf3034SPavel Fedin * You should have received a copy of the GNU General Public License along 19a7bf3034SPavel Fedin * with this program; if not, see <http://www.gnu.org/licenses/>. 20a7bf3034SPavel Fedin */ 21a7bf3034SPavel Fedin 228ef94f0bSPeter Maydell #include "qemu/osdep.h" 23da34e65cSMarkus Armbruster #include "qapi/error.h" 24a7bf3034SPavel Fedin #include "hw/intc/arm_gicv3_common.h" 25a7bf3034SPavel Fedin #include "hw/sysbus.h" 26367b9f52SVijaya Kumar K #include "qemu/error-report.h" 270b8fa32fSMarkus Armbruster #include "qemu/module.h" 28a7bf3034SPavel Fedin #include "sysemu/kvm.h" 2954d31236SMarkus Armbruster #include "sysemu/runstate.h" 30a7bf3034SPavel Fedin #include "kvm_arm.h" 31367b9f52SVijaya Kumar K #include "gicv3_internal.h" 32a7bf3034SPavel Fedin #include "vgic_common.h" 33795c40b8SJuan Quintela #include "migration/blocker.h" 34db1015e9SEduardo Habkost #include "qom/object.h" 35a7bf3034SPavel Fedin 36a7bf3034SPavel Fedin #ifdef DEBUG_GICV3_KVM 37a7bf3034SPavel Fedin #define DPRINTF(fmt, ...) \ 38a7bf3034SPavel Fedin do { fprintf(stderr, "kvm_gicv3: " fmt, ## __VA_ARGS__); } while (0) 39a7bf3034SPavel Fedin #else 40a7bf3034SPavel Fedin #define DPRINTF(fmt, ...) \ 41a7bf3034SPavel Fedin do { } while (0) 42a7bf3034SPavel Fedin #endif 43a7bf3034SPavel Fedin 44a7bf3034SPavel Fedin #define TYPE_KVM_ARM_GICV3 "kvm-arm-gicv3" 45db1015e9SEduardo Habkost typedef struct KVMARMGICv3Class KVMARMGICv3Class; 46fa34a3c5SEduardo Habkost /* This is reusing the GICv3State typedef from ARM_GICV3_ITS_COMMON */ 47fa34a3c5SEduardo Habkost DECLARE_OBJ_CHECKERS(GICv3State, KVMARMGICv3Class, 48fa34a3c5SEduardo Habkost KVM_ARM_GICV3, TYPE_KVM_ARM_GICV3) 49a7bf3034SPavel Fedin 50367b9f52SVijaya Kumar K #define KVM_DEV_ARM_VGIC_SYSREG(op0, op1, crn, crm, op2) \ 51367b9f52SVijaya Kumar K (ARM64_SYS_REG_SHIFT_MASK(op0, OP0) | \ 52367b9f52SVijaya Kumar K ARM64_SYS_REG_SHIFT_MASK(op1, OP1) | \ 53367b9f52SVijaya Kumar K ARM64_SYS_REG_SHIFT_MASK(crn, CRN) | \ 54367b9f52SVijaya Kumar K ARM64_SYS_REG_SHIFT_MASK(crm, CRM) | \ 55367b9f52SVijaya Kumar K ARM64_SYS_REG_SHIFT_MASK(op2, OP2)) 56367b9f52SVijaya Kumar K 57367b9f52SVijaya Kumar K #define ICC_PMR_EL1 \ 58367b9f52SVijaya Kumar K KVM_DEV_ARM_VGIC_SYSREG(3, 0, 4, 6, 0) 59367b9f52SVijaya Kumar K #define ICC_BPR0_EL1 \ 60367b9f52SVijaya Kumar K KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 8, 3) 61367b9f52SVijaya Kumar K #define ICC_AP0R_EL1(n) \ 62367b9f52SVijaya Kumar K KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 8, 4 | n) 63367b9f52SVijaya Kumar K #define ICC_AP1R_EL1(n) \ 64367b9f52SVijaya Kumar K KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 9, n) 65367b9f52SVijaya Kumar K #define ICC_BPR1_EL1 \ 66367b9f52SVijaya Kumar K KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 12, 3) 67367b9f52SVijaya Kumar K #define ICC_CTLR_EL1 \ 68367b9f52SVijaya Kumar K KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 12, 4) 69367b9f52SVijaya Kumar K #define ICC_SRE_EL1 \ 70367b9f52SVijaya Kumar K KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 12, 5) 71367b9f52SVijaya Kumar K #define ICC_IGRPEN0_EL1 \ 72367b9f52SVijaya Kumar K KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 12, 6) 73367b9f52SVijaya Kumar K #define ICC_IGRPEN1_EL1 \ 74367b9f52SVijaya Kumar K KVM_DEV_ARM_VGIC_SYSREG(3, 0, 12, 12, 7) 75367b9f52SVijaya Kumar K 76db1015e9SEduardo Habkost struct KVMARMGICv3Class { 77a7bf3034SPavel Fedin ARMGICv3CommonClass parent_class; 78a7bf3034SPavel Fedin DeviceRealize parent_realize; 79a7bf3034SPavel Fedin void (*parent_reset)(DeviceState *dev); 80db1015e9SEduardo Habkost }; 81a7bf3034SPavel Fedin 82a7bf3034SPavel Fedin static void kvm_arm_gicv3_set_irq(void *opaque, int irq, int level) 83a7bf3034SPavel Fedin { 84a7bf3034SPavel Fedin GICv3State *s = (GICv3State *)opaque; 85a7bf3034SPavel Fedin 86a7bf3034SPavel Fedin kvm_arm_gic_set_irq(s->num_irq, irq, level); 87a7bf3034SPavel Fedin } 88a7bf3034SPavel Fedin 89367b9f52SVijaya Kumar K #define KVM_VGIC_ATTR(reg, typer) \ 90367b9f52SVijaya Kumar K ((typer & KVM_DEV_ARM_VGIC_V3_MPIDR_MASK) | (reg)) 91367b9f52SVijaya Kumar K 92367b9f52SVijaya Kumar K static inline void kvm_gicd_access(GICv3State *s, int offset, 93367b9f52SVijaya Kumar K uint32_t *val, bool write) 94367b9f52SVijaya Kumar K { 95367b9f52SVijaya Kumar K kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_DIST_REGS, 96367b9f52SVijaya Kumar K KVM_VGIC_ATTR(offset, 0), 97556969e9SEric Auger val, write, &error_abort); 98367b9f52SVijaya Kumar K } 99367b9f52SVijaya Kumar K 100367b9f52SVijaya Kumar K static inline void kvm_gicr_access(GICv3State *s, int offset, int cpu, 101367b9f52SVijaya Kumar K uint32_t *val, bool write) 102367b9f52SVijaya Kumar K { 103367b9f52SVijaya Kumar K kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS, 104367b9f52SVijaya Kumar K KVM_VGIC_ATTR(offset, s->cpu[cpu].gicr_typer), 105556969e9SEric Auger val, write, &error_abort); 106367b9f52SVijaya Kumar K } 107367b9f52SVijaya Kumar K 108367b9f52SVijaya Kumar K static inline void kvm_gicc_access(GICv3State *s, uint64_t reg, int cpu, 109367b9f52SVijaya Kumar K uint64_t *val, bool write) 110367b9f52SVijaya Kumar K { 111367b9f52SVijaya Kumar K kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS, 112367b9f52SVijaya Kumar K KVM_VGIC_ATTR(reg, s->cpu[cpu].gicr_typer), 113556969e9SEric Auger val, write, &error_abort); 114367b9f52SVijaya Kumar K } 115367b9f52SVijaya Kumar K 116367b9f52SVijaya Kumar K static inline void kvm_gic_line_level_access(GICv3State *s, int irq, int cpu, 117367b9f52SVijaya Kumar K uint32_t *val, bool write) 118367b9f52SVijaya Kumar K { 119367b9f52SVijaya Kumar K kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO, 120367b9f52SVijaya Kumar K KVM_VGIC_ATTR(irq, s->cpu[cpu].gicr_typer) | 121367b9f52SVijaya Kumar K (VGIC_LEVEL_INFO_LINE_LEVEL << 122367b9f52SVijaya Kumar K KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT), 123556969e9SEric Auger val, write, &error_abort); 124367b9f52SVijaya Kumar K } 125367b9f52SVijaya Kumar K 126367b9f52SVijaya Kumar K /* Loop through each distributor IRQ related register; since bits 127367b9f52SVijaya Kumar K * corresponding to SPIs and PPIs are RAZ/WI when affinity routing 128367b9f52SVijaya Kumar K * is enabled, we skip those. 129367b9f52SVijaya Kumar K */ 130367b9f52SVijaya Kumar K #define for_each_dist_irq_reg(_irq, _max, _field_width) \ 131367b9f52SVijaya Kumar K for (_irq = GIC_INTERNAL; _irq < _max; _irq += (32 / _field_width)) 132367b9f52SVijaya Kumar K 133367b9f52SVijaya Kumar K static void kvm_dist_get_priority(GICv3State *s, uint32_t offset, uint8_t *bmp) 134367b9f52SVijaya Kumar K { 135367b9f52SVijaya Kumar K uint32_t reg, *field; 136367b9f52SVijaya Kumar K int irq; 137367b9f52SVijaya Kumar K 1381dcf3675SShannon Zhao /* For the KVM GICv3, affinity routing is always enabled, and the first 8 1391dcf3675SShannon Zhao * GICD_IPRIORITYR<n> registers are always RAZ/WI. The corresponding 1401dcf3675SShannon Zhao * functionality is replaced by GICR_IPRIORITYR<n>. It doesn't need to 1411dcf3675SShannon Zhao * sync them. So it needs to skip the field of GIC_INTERNAL irqs in bmp and 1421dcf3675SShannon Zhao * offset. 1431dcf3675SShannon Zhao */ 1441dcf3675SShannon Zhao field = (uint32_t *)(bmp + GIC_INTERNAL); 1451dcf3675SShannon Zhao offset += (GIC_INTERNAL * 8) / 8; 146367b9f52SVijaya Kumar K for_each_dist_irq_reg(irq, s->num_irq, 8) { 147367b9f52SVijaya Kumar K kvm_gicd_access(s, offset, ®, false); 148367b9f52SVijaya Kumar K *field = reg; 149367b9f52SVijaya Kumar K offset += 4; 150367b9f52SVijaya Kumar K field++; 151367b9f52SVijaya Kumar K } 152367b9f52SVijaya Kumar K } 153367b9f52SVijaya Kumar K 154367b9f52SVijaya Kumar K static void kvm_dist_put_priority(GICv3State *s, uint32_t offset, uint8_t *bmp) 155367b9f52SVijaya Kumar K { 156367b9f52SVijaya Kumar K uint32_t reg, *field; 157367b9f52SVijaya Kumar K int irq; 158367b9f52SVijaya Kumar K 1591dcf3675SShannon Zhao /* For the KVM GICv3, affinity routing is always enabled, and the first 8 1601dcf3675SShannon Zhao * GICD_IPRIORITYR<n> registers are always RAZ/WI. The corresponding 1611dcf3675SShannon Zhao * functionality is replaced by GICR_IPRIORITYR<n>. It doesn't need to 1621dcf3675SShannon Zhao * sync them. So it needs to skip the field of GIC_INTERNAL irqs in bmp and 1631dcf3675SShannon Zhao * offset. 1641dcf3675SShannon Zhao */ 1651dcf3675SShannon Zhao field = (uint32_t *)(bmp + GIC_INTERNAL); 1661dcf3675SShannon Zhao offset += (GIC_INTERNAL * 8) / 8; 167367b9f52SVijaya Kumar K for_each_dist_irq_reg(irq, s->num_irq, 8) { 168367b9f52SVijaya Kumar K reg = *field; 169367b9f52SVijaya Kumar K kvm_gicd_access(s, offset, ®, true); 170367b9f52SVijaya Kumar K offset += 4; 171367b9f52SVijaya Kumar K field++; 172367b9f52SVijaya Kumar K } 173367b9f52SVijaya Kumar K } 174367b9f52SVijaya Kumar K 175367b9f52SVijaya Kumar K static void kvm_dist_get_edge_trigger(GICv3State *s, uint32_t offset, 176367b9f52SVijaya Kumar K uint32_t *bmp) 177367b9f52SVijaya Kumar K { 178367b9f52SVijaya Kumar K uint32_t reg; 179367b9f52SVijaya Kumar K int irq; 180367b9f52SVijaya Kumar K 181910e2048SShannon Zhao /* For the KVM GICv3, affinity routing is always enabled, and the first 2 182910e2048SShannon Zhao * GICD_ICFGR<n> registers are always RAZ/WI. The corresponding 183910e2048SShannon Zhao * functionality is replaced by GICR_ICFGR<n>. It doesn't need to sync 184910e2048SShannon Zhao * them. So it should increase the offset to skip GIC_INTERNAL irqs. 185910e2048SShannon Zhao * This matches the for_each_dist_irq_reg() macro which also skips the 186910e2048SShannon Zhao * first GIC_INTERNAL irqs. 187910e2048SShannon Zhao */ 188910e2048SShannon Zhao offset += (GIC_INTERNAL * 2) / 8; 189367b9f52SVijaya Kumar K for_each_dist_irq_reg(irq, s->num_irq, 2) { 190367b9f52SVijaya Kumar K kvm_gicd_access(s, offset, ®, false); 191367b9f52SVijaya Kumar K reg = half_unshuffle32(reg >> 1); 192367b9f52SVijaya Kumar K if (irq % 32 != 0) { 193367b9f52SVijaya Kumar K reg = (reg << 16); 194367b9f52SVijaya Kumar K } 195367b9f52SVijaya Kumar K *gic_bmp_ptr32(bmp, irq) |= reg; 196367b9f52SVijaya Kumar K offset += 4; 197367b9f52SVijaya Kumar K } 198367b9f52SVijaya Kumar K } 199367b9f52SVijaya Kumar K 200367b9f52SVijaya Kumar K static void kvm_dist_put_edge_trigger(GICv3State *s, uint32_t offset, 201367b9f52SVijaya Kumar K uint32_t *bmp) 202367b9f52SVijaya Kumar K { 203367b9f52SVijaya Kumar K uint32_t reg; 204367b9f52SVijaya Kumar K int irq; 205367b9f52SVijaya Kumar K 206910e2048SShannon Zhao /* For the KVM GICv3, affinity routing is always enabled, and the first 2 207910e2048SShannon Zhao * GICD_ICFGR<n> registers are always RAZ/WI. The corresponding 208910e2048SShannon Zhao * functionality is replaced by GICR_ICFGR<n>. It doesn't need to sync 209910e2048SShannon Zhao * them. So it should increase the offset to skip GIC_INTERNAL irqs. 210910e2048SShannon Zhao * This matches the for_each_dist_irq_reg() macro which also skips the 211910e2048SShannon Zhao * first GIC_INTERNAL irqs. 212910e2048SShannon Zhao */ 213910e2048SShannon Zhao offset += (GIC_INTERNAL * 2) / 8; 214367b9f52SVijaya Kumar K for_each_dist_irq_reg(irq, s->num_irq, 2) { 215367b9f52SVijaya Kumar K reg = *gic_bmp_ptr32(bmp, irq); 216367b9f52SVijaya Kumar K if (irq % 32 != 0) { 217367b9f52SVijaya Kumar K reg = (reg & 0xffff0000) >> 16; 218367b9f52SVijaya Kumar K } else { 219367b9f52SVijaya Kumar K reg = reg & 0xffff; 220367b9f52SVijaya Kumar K } 221367b9f52SVijaya Kumar K reg = half_shuffle32(reg) << 1; 222367b9f52SVijaya Kumar K kvm_gicd_access(s, offset, ®, true); 223367b9f52SVijaya Kumar K offset += 4; 224367b9f52SVijaya Kumar K } 225367b9f52SVijaya Kumar K } 226367b9f52SVijaya Kumar K 227367b9f52SVijaya Kumar K static void kvm_gic_get_line_level_bmp(GICv3State *s, uint32_t *bmp) 228367b9f52SVijaya Kumar K { 229367b9f52SVijaya Kumar K uint32_t reg; 230367b9f52SVijaya Kumar K int irq; 231367b9f52SVijaya Kumar K 232367b9f52SVijaya Kumar K for_each_dist_irq_reg(irq, s->num_irq, 1) { 233367b9f52SVijaya Kumar K kvm_gic_line_level_access(s, irq, 0, ®, false); 234367b9f52SVijaya Kumar K *gic_bmp_ptr32(bmp, irq) = reg; 235367b9f52SVijaya Kumar K } 236367b9f52SVijaya Kumar K } 237367b9f52SVijaya Kumar K 238367b9f52SVijaya Kumar K static void kvm_gic_put_line_level_bmp(GICv3State *s, uint32_t *bmp) 239367b9f52SVijaya Kumar K { 240367b9f52SVijaya Kumar K uint32_t reg; 241367b9f52SVijaya Kumar K int irq; 242367b9f52SVijaya Kumar K 243367b9f52SVijaya Kumar K for_each_dist_irq_reg(irq, s->num_irq, 1) { 244367b9f52SVijaya Kumar K reg = *gic_bmp_ptr32(bmp, irq); 245367b9f52SVijaya Kumar K kvm_gic_line_level_access(s, irq, 0, ®, true); 246367b9f52SVijaya Kumar K } 247367b9f52SVijaya Kumar K } 248367b9f52SVijaya Kumar K 249367b9f52SVijaya Kumar K /* Read a bitmap register group from the kernel VGIC. */ 250367b9f52SVijaya Kumar K static void kvm_dist_getbmp(GICv3State *s, uint32_t offset, uint32_t *bmp) 251367b9f52SVijaya Kumar K { 252367b9f52SVijaya Kumar K uint32_t reg; 253367b9f52SVijaya Kumar K int irq; 254367b9f52SVijaya Kumar K 255910e2048SShannon Zhao /* For the KVM GICv3, affinity routing is always enabled, and the 256910e2048SShannon Zhao * GICD_IGROUPR0/GICD_IGRPMODR0/GICD_ISENABLER0/GICD_ISPENDR0/ 257910e2048SShannon Zhao * GICD_ISACTIVER0 registers are always RAZ/WI. The corresponding 258910e2048SShannon Zhao * functionality is replaced by the GICR registers. It doesn't need to sync 259910e2048SShannon Zhao * them. So it should increase the offset to skip GIC_INTERNAL irqs. 260910e2048SShannon Zhao * This matches the for_each_dist_irq_reg() macro which also skips the 261910e2048SShannon Zhao * first GIC_INTERNAL irqs. 262910e2048SShannon Zhao */ 263910e2048SShannon Zhao offset += (GIC_INTERNAL * 1) / 8; 264367b9f52SVijaya Kumar K for_each_dist_irq_reg(irq, s->num_irq, 1) { 265367b9f52SVijaya Kumar K kvm_gicd_access(s, offset, ®, false); 266367b9f52SVijaya Kumar K *gic_bmp_ptr32(bmp, irq) = reg; 267367b9f52SVijaya Kumar K offset += 4; 268367b9f52SVijaya Kumar K } 269367b9f52SVijaya Kumar K } 270367b9f52SVijaya Kumar K 271367b9f52SVijaya Kumar K static void kvm_dist_putbmp(GICv3State *s, uint32_t offset, 272367b9f52SVijaya Kumar K uint32_t clroffset, uint32_t *bmp) 273367b9f52SVijaya Kumar K { 274367b9f52SVijaya Kumar K uint32_t reg; 275367b9f52SVijaya Kumar K int irq; 276367b9f52SVijaya Kumar K 277910e2048SShannon Zhao /* For the KVM GICv3, affinity routing is always enabled, and the 278910e2048SShannon Zhao * GICD_IGROUPR0/GICD_IGRPMODR0/GICD_ISENABLER0/GICD_ISPENDR0/ 279910e2048SShannon Zhao * GICD_ISACTIVER0 registers are always RAZ/WI. The corresponding 280910e2048SShannon Zhao * functionality is replaced by the GICR registers. It doesn't need to sync 281910e2048SShannon Zhao * them. So it should increase the offset and clroffset to skip GIC_INTERNAL 282910e2048SShannon Zhao * irqs. This matches the for_each_dist_irq_reg() macro which also skips the 283910e2048SShannon Zhao * first GIC_INTERNAL irqs. 284910e2048SShannon Zhao */ 285910e2048SShannon Zhao offset += (GIC_INTERNAL * 1) / 8; 286910e2048SShannon Zhao if (clroffset != 0) { 287910e2048SShannon Zhao clroffset += (GIC_INTERNAL * 1) / 8; 288910e2048SShannon Zhao } 289910e2048SShannon Zhao 290367b9f52SVijaya Kumar K for_each_dist_irq_reg(irq, s->num_irq, 1) { 291367b9f52SVijaya Kumar K /* If this bitmap is a set/clear register pair, first write to the 292367b9f52SVijaya Kumar K * clear-reg to clear all bits before using the set-reg to write 293367b9f52SVijaya Kumar K * the 1 bits. 294367b9f52SVijaya Kumar K */ 295367b9f52SVijaya Kumar K if (clroffset != 0) { 296367b9f52SVijaya Kumar K reg = 0; 297367b9f52SVijaya Kumar K kvm_gicd_access(s, clroffset, ®, true); 29834ffacaeSShannon Zhao clroffset += 4; 299367b9f52SVijaya Kumar K } 300367b9f52SVijaya Kumar K reg = *gic_bmp_ptr32(bmp, irq); 301367b9f52SVijaya Kumar K kvm_gicd_access(s, offset, ®, true); 302367b9f52SVijaya Kumar K offset += 4; 303367b9f52SVijaya Kumar K } 304367b9f52SVijaya Kumar K } 305367b9f52SVijaya Kumar K 306367b9f52SVijaya Kumar K static void kvm_arm_gicv3_check(GICv3State *s) 307367b9f52SVijaya Kumar K { 308367b9f52SVijaya Kumar K uint32_t reg; 309367b9f52SVijaya Kumar K uint32_t num_irq; 310367b9f52SVijaya Kumar K 311367b9f52SVijaya Kumar K /* Sanity checking s->num_irq */ 312367b9f52SVijaya Kumar K kvm_gicd_access(s, GICD_TYPER, ®, false); 313367b9f52SVijaya Kumar K num_irq = ((reg & 0x1f) + 1) * 32; 314367b9f52SVijaya Kumar K 315367b9f52SVijaya Kumar K if (num_irq < s->num_irq) { 316367b9f52SVijaya Kumar K error_report("Model requests %u IRQs, but kernel supports max %u", 317367b9f52SVijaya Kumar K s->num_irq, num_irq); 318367b9f52SVijaya Kumar K abort(); 319367b9f52SVijaya Kumar K } 320367b9f52SVijaya Kumar K } 321367b9f52SVijaya Kumar K 322a7bf3034SPavel Fedin static void kvm_arm_gicv3_put(GICv3State *s) 323a7bf3034SPavel Fedin { 324367b9f52SVijaya Kumar K uint32_t regl, regh, reg; 325367b9f52SVijaya Kumar K uint64_t reg64, redist_typer; 326367b9f52SVijaya Kumar K int ncpu, i; 327367b9f52SVijaya Kumar K 328367b9f52SVijaya Kumar K kvm_arm_gicv3_check(s); 329367b9f52SVijaya Kumar K 330367b9f52SVijaya Kumar K kvm_gicr_access(s, GICR_TYPER, 0, ®l, false); 331367b9f52SVijaya Kumar K kvm_gicr_access(s, GICR_TYPER + 4, 0, ®h, false); 332367b9f52SVijaya Kumar K redist_typer = ((uint64_t)regh << 32) | regl; 333367b9f52SVijaya Kumar K 334367b9f52SVijaya Kumar K reg = s->gicd_ctlr; 335367b9f52SVijaya Kumar K kvm_gicd_access(s, GICD_CTLR, ®, true); 336367b9f52SVijaya Kumar K 337367b9f52SVijaya Kumar K if (redist_typer & GICR_TYPER_PLPIS) { 338618bacabSZenghui Yu /* 339618bacabSZenghui Yu * Restore base addresses before LPIs are potentially enabled by 340618bacabSZenghui Yu * GICR_CTLR write 341618bacabSZenghui Yu */ 342367b9f52SVijaya Kumar K for (ncpu = 0; ncpu < s->num_cpu; ncpu++) { 343367b9f52SVijaya Kumar K GICv3CPUState *c = &s->cpu[ncpu]; 344367b9f52SVijaya Kumar K 345367b9f52SVijaya Kumar K reg64 = c->gicr_propbaser; 346367b9f52SVijaya Kumar K regl = (uint32_t)reg64; 347367b9f52SVijaya Kumar K kvm_gicr_access(s, GICR_PROPBASER, ncpu, ®l, true); 348367b9f52SVijaya Kumar K regh = (uint32_t)(reg64 >> 32); 349367b9f52SVijaya Kumar K kvm_gicr_access(s, GICR_PROPBASER + 4, ncpu, ®h, true); 350367b9f52SVijaya Kumar K 351367b9f52SVijaya Kumar K reg64 = c->gicr_pendbaser; 352367b9f52SVijaya Kumar K regl = (uint32_t)reg64; 353367b9f52SVijaya Kumar K kvm_gicr_access(s, GICR_PENDBASER, ncpu, ®l, true); 354367b9f52SVijaya Kumar K regh = (uint32_t)(reg64 >> 32); 355367b9f52SVijaya Kumar K kvm_gicr_access(s, GICR_PENDBASER + 4, ncpu, ®h, true); 356367b9f52SVijaya Kumar K } 357367b9f52SVijaya Kumar K } 358367b9f52SVijaya Kumar K 359367b9f52SVijaya Kumar K /* Redistributor state (one per CPU) */ 360367b9f52SVijaya Kumar K 361367b9f52SVijaya Kumar K for (ncpu = 0; ncpu < s->num_cpu; ncpu++) { 362367b9f52SVijaya Kumar K GICv3CPUState *c = &s->cpu[ncpu]; 363367b9f52SVijaya Kumar K 364367b9f52SVijaya Kumar K reg = c->gicr_ctlr; 365367b9f52SVijaya Kumar K kvm_gicr_access(s, GICR_CTLR, ncpu, ®, true); 366367b9f52SVijaya Kumar K 367367b9f52SVijaya Kumar K reg = c->gicr_statusr[GICV3_NS]; 368367b9f52SVijaya Kumar K kvm_gicr_access(s, GICR_STATUSR, ncpu, ®, true); 369367b9f52SVijaya Kumar K 370367b9f52SVijaya Kumar K reg = c->gicr_waker; 371367b9f52SVijaya Kumar K kvm_gicr_access(s, GICR_WAKER, ncpu, ®, true); 372367b9f52SVijaya Kumar K 373367b9f52SVijaya Kumar K reg = c->gicr_igroupr0; 374367b9f52SVijaya Kumar K kvm_gicr_access(s, GICR_IGROUPR0, ncpu, ®, true); 375367b9f52SVijaya Kumar K 376367b9f52SVijaya Kumar K reg = ~0; 377367b9f52SVijaya Kumar K kvm_gicr_access(s, GICR_ICENABLER0, ncpu, ®, true); 378367b9f52SVijaya Kumar K reg = c->gicr_ienabler0; 379367b9f52SVijaya Kumar K kvm_gicr_access(s, GICR_ISENABLER0, ncpu, ®, true); 380367b9f52SVijaya Kumar K 381367b9f52SVijaya Kumar K /* Restore config before pending so we treat level/edge correctly */ 382367b9f52SVijaya Kumar K reg = half_shuffle32(c->edge_trigger >> 16) << 1; 383367b9f52SVijaya Kumar K kvm_gicr_access(s, GICR_ICFGR1, ncpu, ®, true); 384367b9f52SVijaya Kumar K 385367b9f52SVijaya Kumar K reg = c->level; 386367b9f52SVijaya Kumar K kvm_gic_line_level_access(s, 0, ncpu, ®, true); 387367b9f52SVijaya Kumar K 388367b9f52SVijaya Kumar K reg = ~0; 389367b9f52SVijaya Kumar K kvm_gicr_access(s, GICR_ICPENDR0, ncpu, ®, true); 390367b9f52SVijaya Kumar K reg = c->gicr_ipendr0; 391367b9f52SVijaya Kumar K kvm_gicr_access(s, GICR_ISPENDR0, ncpu, ®, true); 392367b9f52SVijaya Kumar K 393367b9f52SVijaya Kumar K reg = ~0; 394367b9f52SVijaya Kumar K kvm_gicr_access(s, GICR_ICACTIVER0, ncpu, ®, true); 395367b9f52SVijaya Kumar K reg = c->gicr_iactiver0; 396367b9f52SVijaya Kumar K kvm_gicr_access(s, GICR_ISACTIVER0, ncpu, ®, true); 397367b9f52SVijaya Kumar K 398367b9f52SVijaya Kumar K for (i = 0; i < GIC_INTERNAL; i += 4) { 399367b9f52SVijaya Kumar K reg = c->gicr_ipriorityr[i] | 400367b9f52SVijaya Kumar K (c->gicr_ipriorityr[i + 1] << 8) | 401367b9f52SVijaya Kumar K (c->gicr_ipriorityr[i + 2] << 16) | 402367b9f52SVijaya Kumar K (c->gicr_ipriorityr[i + 3] << 24); 403367b9f52SVijaya Kumar K kvm_gicr_access(s, GICR_IPRIORITYR + i, ncpu, ®, true); 404367b9f52SVijaya Kumar K } 405367b9f52SVijaya Kumar K } 406367b9f52SVijaya Kumar K 407367b9f52SVijaya Kumar K /* Distributor state (shared between all CPUs */ 408367b9f52SVijaya Kumar K reg = s->gicd_statusr[GICV3_NS]; 409367b9f52SVijaya Kumar K kvm_gicd_access(s, GICD_STATUSR, ®, true); 410367b9f52SVijaya Kumar K 411367b9f52SVijaya Kumar K /* s->enable bitmap -> GICD_ISENABLERn */ 412367b9f52SVijaya Kumar K kvm_dist_putbmp(s, GICD_ISENABLER, GICD_ICENABLER, s->enabled); 413367b9f52SVijaya Kumar K 414367b9f52SVijaya Kumar K /* s->group bitmap -> GICD_IGROUPRn */ 415367b9f52SVijaya Kumar K kvm_dist_putbmp(s, GICD_IGROUPR, 0, s->group); 416367b9f52SVijaya Kumar K 417367b9f52SVijaya Kumar K /* Restore targets before pending to ensure the pending state is set on 418367b9f52SVijaya Kumar K * the appropriate CPU interfaces in the kernel 419367b9f52SVijaya Kumar K */ 420367b9f52SVijaya Kumar K 421367b9f52SVijaya Kumar K /* s->gicd_irouter[irq] -> GICD_IROUTERn 422367b9f52SVijaya Kumar K * We can't use kvm_dist_put() here because the registers are 64-bit 423367b9f52SVijaya Kumar K */ 424367b9f52SVijaya Kumar K for (i = GIC_INTERNAL; i < s->num_irq; i++) { 425367b9f52SVijaya Kumar K uint32_t offset; 426367b9f52SVijaya Kumar K 427367b9f52SVijaya Kumar K offset = GICD_IROUTER + (sizeof(uint32_t) * i); 428367b9f52SVijaya Kumar K reg = (uint32_t)s->gicd_irouter[i]; 429367b9f52SVijaya Kumar K kvm_gicd_access(s, offset, ®, true); 430367b9f52SVijaya Kumar K 431367b9f52SVijaya Kumar K offset = GICD_IROUTER + (sizeof(uint32_t) * i) + 4; 432367b9f52SVijaya Kumar K reg = (uint32_t)(s->gicd_irouter[i] >> 32); 433367b9f52SVijaya Kumar K kvm_gicd_access(s, offset, ®, true); 434367b9f52SVijaya Kumar K } 435367b9f52SVijaya Kumar K 436367b9f52SVijaya Kumar K /* s->trigger bitmap -> GICD_ICFGRn 437367b9f52SVijaya Kumar K * (restore configuration registers before pending IRQs so we treat 438367b9f52SVijaya Kumar K * level/edge correctly) 439367b9f52SVijaya Kumar K */ 440367b9f52SVijaya Kumar K kvm_dist_put_edge_trigger(s, GICD_ICFGR, s->edge_trigger); 441367b9f52SVijaya Kumar K 442367b9f52SVijaya Kumar K /* s->level bitmap -> line_level */ 443367b9f52SVijaya Kumar K kvm_gic_put_line_level_bmp(s, s->level); 444367b9f52SVijaya Kumar K 445367b9f52SVijaya Kumar K /* s->pending bitmap -> GICD_ISPENDRn */ 446367b9f52SVijaya Kumar K kvm_dist_putbmp(s, GICD_ISPENDR, GICD_ICPENDR, s->pending); 447367b9f52SVijaya Kumar K 448367b9f52SVijaya Kumar K /* s->active bitmap -> GICD_ISACTIVERn */ 449367b9f52SVijaya Kumar K kvm_dist_putbmp(s, GICD_ISACTIVER, GICD_ICACTIVER, s->active); 450367b9f52SVijaya Kumar K 451367b9f52SVijaya Kumar K /* s->gicd_ipriority[] -> GICD_IPRIORITYRn */ 452367b9f52SVijaya Kumar K kvm_dist_put_priority(s, GICD_IPRIORITYR, s->gicd_ipriority); 453367b9f52SVijaya Kumar K 454367b9f52SVijaya Kumar K /* CPU Interface state (one per CPU) */ 455367b9f52SVijaya Kumar K 456367b9f52SVijaya Kumar K for (ncpu = 0; ncpu < s->num_cpu; ncpu++) { 457367b9f52SVijaya Kumar K GICv3CPUState *c = &s->cpu[ncpu]; 458367b9f52SVijaya Kumar K int num_pri_bits; 459367b9f52SVijaya Kumar K 460367b9f52SVijaya Kumar K kvm_gicc_access(s, ICC_SRE_EL1, ncpu, &c->icc_sre_el1, true); 461367b9f52SVijaya Kumar K kvm_gicc_access(s, ICC_CTLR_EL1, ncpu, 462367b9f52SVijaya Kumar K &c->icc_ctlr_el1[GICV3_NS], true); 463367b9f52SVijaya Kumar K kvm_gicc_access(s, ICC_IGRPEN0_EL1, ncpu, 464367b9f52SVijaya Kumar K &c->icc_igrpen[GICV3_G0], true); 465367b9f52SVijaya Kumar K kvm_gicc_access(s, ICC_IGRPEN1_EL1, ncpu, 466367b9f52SVijaya Kumar K &c->icc_igrpen[GICV3_G1NS], true); 467367b9f52SVijaya Kumar K kvm_gicc_access(s, ICC_PMR_EL1, ncpu, &c->icc_pmr_el1, true); 468367b9f52SVijaya Kumar K kvm_gicc_access(s, ICC_BPR0_EL1, ncpu, &c->icc_bpr[GICV3_G0], true); 469367b9f52SVijaya Kumar K kvm_gicc_access(s, ICC_BPR1_EL1, ncpu, &c->icc_bpr[GICV3_G1NS], true); 470367b9f52SVijaya Kumar K 471367b9f52SVijaya Kumar K num_pri_bits = ((c->icc_ctlr_el1[GICV3_NS] & 472367b9f52SVijaya Kumar K ICC_CTLR_EL1_PRIBITS_MASK) >> 473367b9f52SVijaya Kumar K ICC_CTLR_EL1_PRIBITS_SHIFT) + 1; 474367b9f52SVijaya Kumar K 475367b9f52SVijaya Kumar K switch (num_pri_bits) { 476367b9f52SVijaya Kumar K case 7: 477367b9f52SVijaya Kumar K reg64 = c->icc_apr[GICV3_G0][3]; 478367b9f52SVijaya Kumar K kvm_gicc_access(s, ICC_AP0R_EL1(3), ncpu, ®64, true); 479367b9f52SVijaya Kumar K reg64 = c->icc_apr[GICV3_G0][2]; 480367b9f52SVijaya Kumar K kvm_gicc_access(s, ICC_AP0R_EL1(2), ncpu, ®64, true); 481*d85afd1eSChen Qun /* fall through */ 482367b9f52SVijaya Kumar K case 6: 483367b9f52SVijaya Kumar K reg64 = c->icc_apr[GICV3_G0][1]; 484367b9f52SVijaya Kumar K kvm_gicc_access(s, ICC_AP0R_EL1(1), ncpu, ®64, true); 485*d85afd1eSChen Qun /* fall through */ 486367b9f52SVijaya Kumar K default: 487367b9f52SVijaya Kumar K reg64 = c->icc_apr[GICV3_G0][0]; 488367b9f52SVijaya Kumar K kvm_gicc_access(s, ICC_AP0R_EL1(0), ncpu, ®64, true); 489367b9f52SVijaya Kumar K } 490367b9f52SVijaya Kumar K 491367b9f52SVijaya Kumar K switch (num_pri_bits) { 492367b9f52SVijaya Kumar K case 7: 493367b9f52SVijaya Kumar K reg64 = c->icc_apr[GICV3_G1NS][3]; 494367b9f52SVijaya Kumar K kvm_gicc_access(s, ICC_AP1R_EL1(3), ncpu, ®64, true); 495367b9f52SVijaya Kumar K reg64 = c->icc_apr[GICV3_G1NS][2]; 496367b9f52SVijaya Kumar K kvm_gicc_access(s, ICC_AP1R_EL1(2), ncpu, ®64, true); 497*d85afd1eSChen Qun /* fall through */ 498367b9f52SVijaya Kumar K case 6: 499367b9f52SVijaya Kumar K reg64 = c->icc_apr[GICV3_G1NS][1]; 500367b9f52SVijaya Kumar K kvm_gicc_access(s, ICC_AP1R_EL1(1), ncpu, ®64, true); 501*d85afd1eSChen Qun /* fall through */ 502367b9f52SVijaya Kumar K default: 503367b9f52SVijaya Kumar K reg64 = c->icc_apr[GICV3_G1NS][0]; 504367b9f52SVijaya Kumar K kvm_gicc_access(s, ICC_AP1R_EL1(0), ncpu, ®64, true); 505367b9f52SVijaya Kumar K } 506367b9f52SVijaya Kumar K } 507a7bf3034SPavel Fedin } 508a7bf3034SPavel Fedin 509a7bf3034SPavel Fedin static void kvm_arm_gicv3_get(GICv3State *s) 510a7bf3034SPavel Fedin { 511367b9f52SVijaya Kumar K uint32_t regl, regh, reg; 512367b9f52SVijaya Kumar K uint64_t reg64, redist_typer; 513367b9f52SVijaya Kumar K int ncpu, i; 514367b9f52SVijaya Kumar K 515367b9f52SVijaya Kumar K kvm_arm_gicv3_check(s); 516367b9f52SVijaya Kumar K 517367b9f52SVijaya Kumar K kvm_gicr_access(s, GICR_TYPER, 0, ®l, false); 518367b9f52SVijaya Kumar K kvm_gicr_access(s, GICR_TYPER + 4, 0, ®h, false); 519367b9f52SVijaya Kumar K redist_typer = ((uint64_t)regh << 32) | regl; 520367b9f52SVijaya Kumar K 521367b9f52SVijaya Kumar K kvm_gicd_access(s, GICD_CTLR, ®, false); 522367b9f52SVijaya Kumar K s->gicd_ctlr = reg; 523367b9f52SVijaya Kumar K 524367b9f52SVijaya Kumar K /* Redistributor state (one per CPU) */ 525367b9f52SVijaya Kumar K 526367b9f52SVijaya Kumar K for (ncpu = 0; ncpu < s->num_cpu; ncpu++) { 527367b9f52SVijaya Kumar K GICv3CPUState *c = &s->cpu[ncpu]; 528367b9f52SVijaya Kumar K 529367b9f52SVijaya Kumar K kvm_gicr_access(s, GICR_CTLR, ncpu, ®, false); 530367b9f52SVijaya Kumar K c->gicr_ctlr = reg; 531367b9f52SVijaya Kumar K 532367b9f52SVijaya Kumar K kvm_gicr_access(s, GICR_STATUSR, ncpu, ®, false); 533367b9f52SVijaya Kumar K c->gicr_statusr[GICV3_NS] = reg; 534367b9f52SVijaya Kumar K 535367b9f52SVijaya Kumar K kvm_gicr_access(s, GICR_WAKER, ncpu, ®, false); 536367b9f52SVijaya Kumar K c->gicr_waker = reg; 537367b9f52SVijaya Kumar K 538367b9f52SVijaya Kumar K kvm_gicr_access(s, GICR_IGROUPR0, ncpu, ®, false); 539367b9f52SVijaya Kumar K c->gicr_igroupr0 = reg; 540367b9f52SVijaya Kumar K kvm_gicr_access(s, GICR_ISENABLER0, ncpu, ®, false); 541367b9f52SVijaya Kumar K c->gicr_ienabler0 = reg; 542367b9f52SVijaya Kumar K kvm_gicr_access(s, GICR_ICFGR1, ncpu, ®, false); 543367b9f52SVijaya Kumar K c->edge_trigger = half_unshuffle32(reg >> 1) << 16; 544367b9f52SVijaya Kumar K kvm_gic_line_level_access(s, 0, ncpu, ®, false); 545367b9f52SVijaya Kumar K c->level = reg; 546367b9f52SVijaya Kumar K kvm_gicr_access(s, GICR_ISPENDR0, ncpu, ®, false); 547367b9f52SVijaya Kumar K c->gicr_ipendr0 = reg; 548367b9f52SVijaya Kumar K kvm_gicr_access(s, GICR_ISACTIVER0, ncpu, ®, false); 549367b9f52SVijaya Kumar K c->gicr_iactiver0 = reg; 550367b9f52SVijaya Kumar K 551367b9f52SVijaya Kumar K for (i = 0; i < GIC_INTERNAL; i += 4) { 552367b9f52SVijaya Kumar K kvm_gicr_access(s, GICR_IPRIORITYR + i, ncpu, ®, false); 553367b9f52SVijaya Kumar K c->gicr_ipriorityr[i] = extract32(reg, 0, 8); 554367b9f52SVijaya Kumar K c->gicr_ipriorityr[i + 1] = extract32(reg, 8, 8); 555367b9f52SVijaya Kumar K c->gicr_ipriorityr[i + 2] = extract32(reg, 16, 8); 556367b9f52SVijaya Kumar K c->gicr_ipriorityr[i + 3] = extract32(reg, 24, 8); 557367b9f52SVijaya Kumar K } 558367b9f52SVijaya Kumar K } 559367b9f52SVijaya Kumar K 560367b9f52SVijaya Kumar K if (redist_typer & GICR_TYPER_PLPIS) { 561367b9f52SVijaya Kumar K for (ncpu = 0; ncpu < s->num_cpu; ncpu++) { 562367b9f52SVijaya Kumar K GICv3CPUState *c = &s->cpu[ncpu]; 563367b9f52SVijaya Kumar K 564367b9f52SVijaya Kumar K kvm_gicr_access(s, GICR_PROPBASER, ncpu, ®l, false); 565367b9f52SVijaya Kumar K kvm_gicr_access(s, GICR_PROPBASER + 4, ncpu, ®h, false); 566367b9f52SVijaya Kumar K c->gicr_propbaser = ((uint64_t)regh << 32) | regl; 567367b9f52SVijaya Kumar K 568367b9f52SVijaya Kumar K kvm_gicr_access(s, GICR_PENDBASER, ncpu, ®l, false); 569367b9f52SVijaya Kumar K kvm_gicr_access(s, GICR_PENDBASER + 4, ncpu, ®h, false); 570367b9f52SVijaya Kumar K c->gicr_pendbaser = ((uint64_t)regh << 32) | regl; 571367b9f52SVijaya Kumar K } 572367b9f52SVijaya Kumar K } 573367b9f52SVijaya Kumar K 574367b9f52SVijaya Kumar K /* Distributor state (shared between all CPUs */ 575367b9f52SVijaya Kumar K 576367b9f52SVijaya Kumar K kvm_gicd_access(s, GICD_STATUSR, ®, false); 577367b9f52SVijaya Kumar K s->gicd_statusr[GICV3_NS] = reg; 578367b9f52SVijaya Kumar K 579367b9f52SVijaya Kumar K /* GICD_IGROUPRn -> s->group bitmap */ 580367b9f52SVijaya Kumar K kvm_dist_getbmp(s, GICD_IGROUPR, s->group); 581367b9f52SVijaya Kumar K 582367b9f52SVijaya Kumar K /* GICD_ISENABLERn -> s->enabled bitmap */ 583367b9f52SVijaya Kumar K kvm_dist_getbmp(s, GICD_ISENABLER, s->enabled); 584367b9f52SVijaya Kumar K 585367b9f52SVijaya Kumar K /* Line level of irq */ 586367b9f52SVijaya Kumar K kvm_gic_get_line_level_bmp(s, s->level); 587367b9f52SVijaya Kumar K /* GICD_ISPENDRn -> s->pending bitmap */ 588367b9f52SVijaya Kumar K kvm_dist_getbmp(s, GICD_ISPENDR, s->pending); 589367b9f52SVijaya Kumar K 590367b9f52SVijaya Kumar K /* GICD_ISACTIVERn -> s->active bitmap */ 591367b9f52SVijaya Kumar K kvm_dist_getbmp(s, GICD_ISACTIVER, s->active); 592367b9f52SVijaya Kumar K 593367b9f52SVijaya Kumar K /* GICD_ICFGRn -> s->trigger bitmap */ 594367b9f52SVijaya Kumar K kvm_dist_get_edge_trigger(s, GICD_ICFGR, s->edge_trigger); 595367b9f52SVijaya Kumar K 596367b9f52SVijaya Kumar K /* GICD_IPRIORITYRn -> s->gicd_ipriority[] */ 597367b9f52SVijaya Kumar K kvm_dist_get_priority(s, GICD_IPRIORITYR, s->gicd_ipriority); 598367b9f52SVijaya Kumar K 599367b9f52SVijaya Kumar K /* GICD_IROUTERn -> s->gicd_irouter[irq] */ 600367b9f52SVijaya Kumar K for (i = GIC_INTERNAL; i < s->num_irq; i++) { 601367b9f52SVijaya Kumar K uint32_t offset; 602367b9f52SVijaya Kumar K 603367b9f52SVijaya Kumar K offset = GICD_IROUTER + (sizeof(uint32_t) * i); 604367b9f52SVijaya Kumar K kvm_gicd_access(s, offset, ®l, false); 605367b9f52SVijaya Kumar K offset = GICD_IROUTER + (sizeof(uint32_t) * i) + 4; 606367b9f52SVijaya Kumar K kvm_gicd_access(s, offset, ®h, false); 607367b9f52SVijaya Kumar K s->gicd_irouter[i] = ((uint64_t)regh << 32) | regl; 608367b9f52SVijaya Kumar K } 609367b9f52SVijaya Kumar K 610367b9f52SVijaya Kumar K /***************************************************************** 611367b9f52SVijaya Kumar K * CPU Interface(s) State 612367b9f52SVijaya Kumar K */ 613367b9f52SVijaya Kumar K 614367b9f52SVijaya Kumar K for (ncpu = 0; ncpu < s->num_cpu; ncpu++) { 615367b9f52SVijaya Kumar K GICv3CPUState *c = &s->cpu[ncpu]; 616367b9f52SVijaya Kumar K int num_pri_bits; 617367b9f52SVijaya Kumar K 618367b9f52SVijaya Kumar K kvm_gicc_access(s, ICC_SRE_EL1, ncpu, &c->icc_sre_el1, false); 619367b9f52SVijaya Kumar K kvm_gicc_access(s, ICC_CTLR_EL1, ncpu, 620367b9f52SVijaya Kumar K &c->icc_ctlr_el1[GICV3_NS], false); 621367b9f52SVijaya Kumar K kvm_gicc_access(s, ICC_IGRPEN0_EL1, ncpu, 622367b9f52SVijaya Kumar K &c->icc_igrpen[GICV3_G0], false); 623367b9f52SVijaya Kumar K kvm_gicc_access(s, ICC_IGRPEN1_EL1, ncpu, 624367b9f52SVijaya Kumar K &c->icc_igrpen[GICV3_G1NS], false); 625367b9f52SVijaya Kumar K kvm_gicc_access(s, ICC_PMR_EL1, ncpu, &c->icc_pmr_el1, false); 626367b9f52SVijaya Kumar K kvm_gicc_access(s, ICC_BPR0_EL1, ncpu, &c->icc_bpr[GICV3_G0], false); 627367b9f52SVijaya Kumar K kvm_gicc_access(s, ICC_BPR1_EL1, ncpu, &c->icc_bpr[GICV3_G1NS], false); 628367b9f52SVijaya Kumar K num_pri_bits = ((c->icc_ctlr_el1[GICV3_NS] & 629367b9f52SVijaya Kumar K ICC_CTLR_EL1_PRIBITS_MASK) >> 630367b9f52SVijaya Kumar K ICC_CTLR_EL1_PRIBITS_SHIFT) + 1; 631367b9f52SVijaya Kumar K 632367b9f52SVijaya Kumar K switch (num_pri_bits) { 633367b9f52SVijaya Kumar K case 7: 634367b9f52SVijaya Kumar K kvm_gicc_access(s, ICC_AP0R_EL1(3), ncpu, ®64, false); 635367b9f52SVijaya Kumar K c->icc_apr[GICV3_G0][3] = reg64; 636367b9f52SVijaya Kumar K kvm_gicc_access(s, ICC_AP0R_EL1(2), ncpu, ®64, false); 637367b9f52SVijaya Kumar K c->icc_apr[GICV3_G0][2] = reg64; 638*d85afd1eSChen Qun /* fall through */ 639367b9f52SVijaya Kumar K case 6: 640367b9f52SVijaya Kumar K kvm_gicc_access(s, ICC_AP0R_EL1(1), ncpu, ®64, false); 641367b9f52SVijaya Kumar K c->icc_apr[GICV3_G0][1] = reg64; 642*d85afd1eSChen Qun /* fall through */ 643367b9f52SVijaya Kumar K default: 644367b9f52SVijaya Kumar K kvm_gicc_access(s, ICC_AP0R_EL1(0), ncpu, ®64, false); 645367b9f52SVijaya Kumar K c->icc_apr[GICV3_G0][0] = reg64; 646367b9f52SVijaya Kumar K } 647367b9f52SVijaya Kumar K 648367b9f52SVijaya Kumar K switch (num_pri_bits) { 649367b9f52SVijaya Kumar K case 7: 650367b9f52SVijaya Kumar K kvm_gicc_access(s, ICC_AP1R_EL1(3), ncpu, ®64, false); 651367b9f52SVijaya Kumar K c->icc_apr[GICV3_G1NS][3] = reg64; 652367b9f52SVijaya Kumar K kvm_gicc_access(s, ICC_AP1R_EL1(2), ncpu, ®64, false); 653367b9f52SVijaya Kumar K c->icc_apr[GICV3_G1NS][2] = reg64; 654*d85afd1eSChen Qun /* fall through */ 655367b9f52SVijaya Kumar K case 6: 656367b9f52SVijaya Kumar K kvm_gicc_access(s, ICC_AP1R_EL1(1), ncpu, ®64, false); 657367b9f52SVijaya Kumar K c->icc_apr[GICV3_G1NS][1] = reg64; 658*d85afd1eSChen Qun /* fall through */ 659367b9f52SVijaya Kumar K default: 660367b9f52SVijaya Kumar K kvm_gicc_access(s, ICC_AP1R_EL1(0), ncpu, ®64, false); 661367b9f52SVijaya Kumar K c->icc_apr[GICV3_G1NS][0] = reg64; 662367b9f52SVijaya Kumar K } 663367b9f52SVijaya Kumar K } 664a7bf3034SPavel Fedin } 665a7bf3034SPavel Fedin 66607a5628cSVijaya Kumar K static void arm_gicv3_icc_reset(CPUARMState *env, const ARMCPRegInfo *ri) 66707a5628cSVijaya Kumar K { 66807a5628cSVijaya Kumar K GICv3State *s; 66907a5628cSVijaya Kumar K GICv3CPUState *c; 67007a5628cSVijaya Kumar K 67107a5628cSVijaya Kumar K c = (GICv3CPUState *)env->gicv3state; 67207a5628cSVijaya Kumar K s = c->gic; 67307a5628cSVijaya Kumar K 67407a5628cSVijaya Kumar K c->icc_pmr_el1 = 0; 67507a5628cSVijaya Kumar K c->icc_bpr[GICV3_G0] = GIC_MIN_BPR; 67607a5628cSVijaya Kumar K c->icc_bpr[GICV3_G1] = GIC_MIN_BPR; 67707a5628cSVijaya Kumar K c->icc_bpr[GICV3_G1NS] = GIC_MIN_BPR; 67807a5628cSVijaya Kumar K 67907a5628cSVijaya Kumar K c->icc_sre_el1 = 0x7; 68007a5628cSVijaya Kumar K memset(c->icc_apr, 0, sizeof(c->icc_apr)); 68107a5628cSVijaya Kumar K memset(c->icc_igrpen, 0, sizeof(c->icc_igrpen)); 682e7d54416SEric Auger 683e7d54416SEric Auger if (s->migration_blocker) { 684e7d54416SEric Auger return; 685e7d54416SEric Auger } 686e7d54416SEric Auger 687e7d54416SEric Auger /* Initialize to actual HW supported configuration */ 688e7d54416SEric Auger kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS, 6891e11a139SKeqian Zhu KVM_VGIC_ATTR(ICC_CTLR_EL1, c->gicr_typer), 690556969e9SEric Auger &c->icc_ctlr_el1[GICV3_NS], false, &error_abort); 691e7d54416SEric Auger 692e7d54416SEric Auger c->icc_ctlr_el1[GICV3_S] = c->icc_ctlr_el1[GICV3_NS]; 69307a5628cSVijaya Kumar K } 69407a5628cSVijaya Kumar K 695a7bf3034SPavel Fedin static void kvm_arm_gicv3_reset(DeviceState *dev) 696a7bf3034SPavel Fedin { 697a7bf3034SPavel Fedin GICv3State *s = ARM_GICV3_COMMON(dev); 698a7bf3034SPavel Fedin KVMARMGICv3Class *kgc = KVM_ARM_GICV3_GET_CLASS(s); 699a7bf3034SPavel Fedin 700a7bf3034SPavel Fedin DPRINTF("Reset\n"); 701a7bf3034SPavel Fedin 702a7bf3034SPavel Fedin kgc->parent_reset(dev); 703367b9f52SVijaya Kumar K 704367b9f52SVijaya Kumar K if (s->migration_blocker) { 705367b9f52SVijaya Kumar K DPRINTF("Cannot put kernel gic state, no kernel interface\n"); 706367b9f52SVijaya Kumar K return; 707367b9f52SVijaya Kumar K } 708367b9f52SVijaya Kumar K 709a7bf3034SPavel Fedin kvm_arm_gicv3_put(s); 710a7bf3034SPavel Fedin } 711a7bf3034SPavel Fedin 71207a5628cSVijaya Kumar K /* 71307a5628cSVijaya Kumar K * CPU interface registers of GIC needs to be reset on CPU reset. 71407a5628cSVijaya Kumar K * For the calling arm_gicv3_icc_reset() on CPU reset, we register 71507a5628cSVijaya Kumar K * below ARMCPRegInfo. As we reset the whole cpu interface under single 71607a5628cSVijaya Kumar K * register reset, we define only one register of CPU interface instead 71707a5628cSVijaya Kumar K * of defining all the registers. 71807a5628cSVijaya Kumar K */ 71907a5628cSVijaya Kumar K static const ARMCPRegInfo gicv3_cpuif_reginfo[] = { 72007a5628cSVijaya Kumar K { .name = "ICC_CTLR_EL1", .state = ARM_CP_STATE_BOTH, 72107a5628cSVijaya Kumar K .opc0 = 3, .opc1 = 0, .crn = 12, .crm = 12, .opc2 = 4, 72207a5628cSVijaya Kumar K /* 72307a5628cSVijaya Kumar K * If ARM_CP_NOP is used, resetfn is not called, 72407a5628cSVijaya Kumar K * So ARM_CP_NO_RAW is appropriate type. 72507a5628cSVijaya Kumar K */ 72607a5628cSVijaya Kumar K .type = ARM_CP_NO_RAW, 72707a5628cSVijaya Kumar K .access = PL1_RW, 72807a5628cSVijaya Kumar K .readfn = arm_cp_read_zero, 72907a5628cSVijaya Kumar K .writefn = arm_cp_write_ignore, 73007a5628cSVijaya Kumar K /* 73107a5628cSVijaya Kumar K * We hang the whole cpu interface reset routine off here 73207a5628cSVijaya Kumar K * rather than parcelling it out into one little function 73307a5628cSVijaya Kumar K * per register 73407a5628cSVijaya Kumar K */ 73507a5628cSVijaya Kumar K .resetfn = arm_gicv3_icc_reset, 73607a5628cSVijaya Kumar K }, 73707a5628cSVijaya Kumar K REGINFO_SENTINEL 73807a5628cSVijaya Kumar K }; 73907a5628cSVijaya Kumar K 740d5aa0c22SEric Auger /** 741d5aa0c22SEric Auger * vm_change_state_handler - VM change state callback aiming at flushing 742d5aa0c22SEric Auger * RDIST pending tables into guest RAM 743d5aa0c22SEric Auger * 744d5aa0c22SEric Auger * The tables get flushed to guest RAM whenever the VM gets stopped. 745d5aa0c22SEric Auger */ 746d5aa0c22SEric Auger static void vm_change_state_handler(void *opaque, int running, 747d5aa0c22SEric Auger RunState state) 748d5aa0c22SEric Auger { 749d5aa0c22SEric Auger GICv3State *s = (GICv3State *)opaque; 750d5aa0c22SEric Auger Error *err = NULL; 751d5aa0c22SEric Auger int ret; 752d5aa0c22SEric Auger 753d5aa0c22SEric Auger if (running) { 754d5aa0c22SEric Auger return; 755d5aa0c22SEric Auger } 756d5aa0c22SEric Auger 757d5aa0c22SEric Auger ret = kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, 758d5aa0c22SEric Auger KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES, 759d5aa0c22SEric Auger NULL, true, &err); 760d5aa0c22SEric Auger if (err) { 761d5aa0c22SEric Auger error_report_err(err); 762d5aa0c22SEric Auger } 763d5aa0c22SEric Auger if (ret < 0 && ret != -EFAULT) { 764d5aa0c22SEric Auger abort(); 765d5aa0c22SEric Auger } 766d5aa0c22SEric Auger } 767d5aa0c22SEric Auger 768d5aa0c22SEric Auger 769a7bf3034SPavel Fedin static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) 770a7bf3034SPavel Fedin { 771a7bf3034SPavel Fedin GICv3State *s = KVM_ARM_GICV3(dev); 772a7bf3034SPavel Fedin KVMARMGICv3Class *kgc = KVM_ARM_GICV3_GET_CLASS(s); 77380d67333SEric Auger bool multiple_redist_region_allowed; 774a7bf3034SPavel Fedin Error *local_err = NULL; 775d19a4d4eSEric Auger int i; 776a7bf3034SPavel Fedin 777a7bf3034SPavel Fedin DPRINTF("kvm_arm_gicv3_realize\n"); 778a7bf3034SPavel Fedin 779a7bf3034SPavel Fedin kgc->parent_realize(dev, &local_err); 780a7bf3034SPavel Fedin if (local_err) { 781a7bf3034SPavel Fedin error_propagate(errp, local_err); 782a7bf3034SPavel Fedin return; 783a7bf3034SPavel Fedin } 784a7bf3034SPavel Fedin 785a7bf3034SPavel Fedin if (s->security_extn) { 786a7bf3034SPavel Fedin error_setg(errp, "the in-kernel VGICv3 does not implement the " 787a7bf3034SPavel Fedin "security extensions"); 788a7bf3034SPavel Fedin return; 789a7bf3034SPavel Fedin } 790a7bf3034SPavel Fedin 7911e575b66SEric Auger gicv3_init_irqs_and_mmio(s, kvm_arm_gicv3_set_irq, NULL, &local_err); 7921e575b66SEric Auger if (local_err) { 7931e575b66SEric Auger error_propagate(errp, local_err); 7941e575b66SEric Auger return; 7951e575b66SEric Auger } 796a7bf3034SPavel Fedin 79707a5628cSVijaya Kumar K for (i = 0; i < s->num_cpu; i++) { 79807a5628cSVijaya Kumar K ARMCPU *cpu = ARM_CPU(qemu_get_cpu(i)); 79907a5628cSVijaya Kumar K 80007a5628cSVijaya Kumar K define_arm_cp_regs(cpu, gicv3_cpuif_reginfo); 80107a5628cSVijaya Kumar K } 80207a5628cSVijaya Kumar K 803a7bf3034SPavel Fedin /* Try to create the device via the device control API */ 804a7bf3034SPavel Fedin s->dev_fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_V3, false); 805a7bf3034SPavel Fedin if (s->dev_fd < 0) { 806a7bf3034SPavel Fedin error_setg_errno(errp, -s->dev_fd, "error creating in-kernel VGIC"); 807a7bf3034SPavel Fedin return; 808a7bf3034SPavel Fedin } 809a7bf3034SPavel Fedin 81080d67333SEric Auger multiple_redist_region_allowed = 81180d67333SEric Auger kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, 81280d67333SEric Auger KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION); 81380d67333SEric Auger 81480d67333SEric Auger if (!multiple_redist_region_allowed && s->nb_redist_regions > 1) { 81580d67333SEric Auger error_setg(errp, "Multiple VGICv3 redistributor regions are not " 81680d67333SEric Auger "supported by this host kernel"); 81780d67333SEric Auger error_append_hint(errp, "A maximum of %d VCPUs can be used", 81880d67333SEric Auger s->redist_region_count[0]); 81980d67333SEric Auger return; 82080d67333SEric Auger } 82180d67333SEric Auger 822a7bf3034SPavel Fedin kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 823556969e9SEric Auger 0, &s->num_irq, true, &error_abort); 824a7bf3034SPavel Fedin 825a7bf3034SPavel Fedin /* Tell the kernel to complete VGIC initialization now */ 826a7bf3034SPavel Fedin kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, 827556969e9SEric Auger KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true, &error_abort); 828a7bf3034SPavel Fedin 829a7bf3034SPavel Fedin kvm_arm_register_device(&s->iomem_dist, -1, KVM_DEV_ARM_VGIC_GRP_ADDR, 83019d1bd0bSEric Auger KVM_VGIC_V3_ADDR_TYPE_DIST, s->dev_fd, 0); 83180d67333SEric Auger 83280d67333SEric Auger if (!multiple_redist_region_allowed) { 8331e575b66SEric Auger kvm_arm_register_device(&s->iomem_redist[0], -1, 8341e575b66SEric Auger KVM_DEV_ARM_VGIC_GRP_ADDR, 83519d1bd0bSEric Auger KVM_VGIC_V3_ADDR_TYPE_REDIST, s->dev_fd, 0); 83680d67333SEric Auger } else { 83780d67333SEric Auger /* we register regions in reverse order as "devices" are inserted at 83880d67333SEric Auger * the head of a QSLIST and the list is then popped from the head 83980d67333SEric Auger * onwards by kvm_arm_machine_init_done() 84080d67333SEric Auger */ 84180d67333SEric Auger for (i = s->nb_redist_regions - 1; i >= 0; i--) { 84280d67333SEric Auger /* Address mask made of the rdist region index and count */ 84380d67333SEric Auger uint64_t addr_ormask = 84480d67333SEric Auger i | ((uint64_t)s->redist_region_count[i] << 52); 84580d67333SEric Auger 84680d67333SEric Auger kvm_arm_register_device(&s->iomem_redist[i], -1, 84780d67333SEric Auger KVM_DEV_ARM_VGIC_GRP_ADDR, 84880d67333SEric Auger KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, 84980d67333SEric Auger s->dev_fd, addr_ormask); 85080d67333SEric Auger } 85180d67333SEric Auger } 852757caeedSPavel Fedin 853d19a4d4eSEric Auger if (kvm_has_gsi_routing()) { 854d19a4d4eSEric Auger /* set up irq routing */ 855d19a4d4eSEric Auger for (i = 0; i < s->num_irq - GIC_INTERNAL; ++i) { 856d19a4d4eSEric Auger kvm_irqchip_add_irq_route(kvm_state, i, 0, i); 857d19a4d4eSEric Auger } 858d19a4d4eSEric Auger 859d19a4d4eSEric Auger kvm_gsi_routing_allowed = true; 860d19a4d4eSEric Auger 861d19a4d4eSEric Auger kvm_irqchip_commit_routes(kvm_state); 862d19a4d4eSEric Auger } 863367b9f52SVijaya Kumar K 864367b9f52SVijaya Kumar K if (!kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_DIST_REGS, 865367b9f52SVijaya Kumar K GICD_CTLR)) { 866367b9f52SVijaya Kumar K error_setg(&s->migration_blocker, "This operating system kernel does " 867367b9f52SVijaya Kumar K "not support vGICv3 migration"); 868386f6c07SMarkus Armbruster if (migrate_add_blocker(s->migration_blocker, errp) < 0) { 869367b9f52SVijaya Kumar K error_free(s->migration_blocker); 870367b9f52SVijaya Kumar K return; 871367b9f52SVijaya Kumar K } 872367b9f52SVijaya Kumar K } 873d5aa0c22SEric Auger if (kvm_device_check_attr(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, 874d5aa0c22SEric Auger KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES)) { 875d5aa0c22SEric Auger qemu_add_vm_change_state_handler(vm_change_state_handler, s); 876d5aa0c22SEric Auger } 877a7bf3034SPavel Fedin } 878a7bf3034SPavel Fedin 879a7bf3034SPavel Fedin static void kvm_arm_gicv3_class_init(ObjectClass *klass, void *data) 880a7bf3034SPavel Fedin { 881a7bf3034SPavel Fedin DeviceClass *dc = DEVICE_CLASS(klass); 882a7bf3034SPavel Fedin ARMGICv3CommonClass *agcc = ARM_GICV3_COMMON_CLASS(klass); 883a7bf3034SPavel Fedin KVMARMGICv3Class *kgc = KVM_ARM_GICV3_CLASS(klass); 884a7bf3034SPavel Fedin 885a7bf3034SPavel Fedin agcc->pre_save = kvm_arm_gicv3_get; 886a7bf3034SPavel Fedin agcc->post_load = kvm_arm_gicv3_put; 887bf853881SPhilippe Mathieu-Daudé device_class_set_parent_realize(dc, kvm_arm_gicv3_realize, 888bf853881SPhilippe Mathieu-Daudé &kgc->parent_realize); 889bf853881SPhilippe Mathieu-Daudé device_class_set_parent_reset(dc, kvm_arm_gicv3_reset, &kgc->parent_reset); 890a7bf3034SPavel Fedin } 891a7bf3034SPavel Fedin 892a7bf3034SPavel Fedin static const TypeInfo kvm_arm_gicv3_info = { 893a7bf3034SPavel Fedin .name = TYPE_KVM_ARM_GICV3, 894a7bf3034SPavel Fedin .parent = TYPE_ARM_GICV3_COMMON, 895a7bf3034SPavel Fedin .instance_size = sizeof(GICv3State), 896a7bf3034SPavel Fedin .class_init = kvm_arm_gicv3_class_init, 897a7bf3034SPavel Fedin .class_size = sizeof(KVMARMGICv3Class), 898a7bf3034SPavel Fedin }; 899a7bf3034SPavel Fedin 900a7bf3034SPavel Fedin static void kvm_arm_gicv3_register_types(void) 901a7bf3034SPavel Fedin { 902a7bf3034SPavel Fedin type_register_static(&kvm_arm_gicv3_info); 903a7bf3034SPavel Fedin } 904a7bf3034SPavel Fedin 905a7bf3034SPavel Fedin type_init(kvm_arm_gicv3_register_types) 906