1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2012-2015 - ARM Ltd
4 * Author: Marc Zyngier <marc.zyngier@arm.com>
7 #include <hyp/adjust_pc.h>
9 #include <linux/compiler.h>
10 #include <linux/irqchip/arm-gic.h>
11 #include <linux/kvm_host.h>
12 #include <linux/swab.h>
14 #include <asm/kvm_emulate.h>
15 #include <asm/kvm_hyp.h>
16 #include <asm/kvm_mmu.h>
18 static bool __is_be(struct kvm_vcpu
*vcpu
)
20 if (vcpu_mode_is_32bit(vcpu
))
21 return !!(read_sysreg_el2(SYS_SPSR
) & PSR_AA32_E_BIT
);
23 return !!(read_sysreg(SCTLR_EL1
) & SCTLR_ELx_EE
);
27 * __vgic_v2_perform_cpuif_access -- perform a GICV access on behalf of the
30 * @vcpu: the offending vcpu
33 * 1: GICV access successfully performed
34 * 0: Not a GICV access
35 * -1: Illegal GICV access successfully performed
37 int __vgic_v2_perform_cpuif_access(struct kvm_vcpu
*vcpu
)
39 struct kvm
*kvm
= kern_hyp_va(vcpu
->kvm
);
40 struct vgic_dist
*vgic
= &kvm
->arch
.vgic
;
41 phys_addr_t fault_ipa
;
45 /* Build the full address */
46 fault_ipa
= kvm_vcpu_get_fault_ipa(vcpu
);
47 fault_ipa
|= kvm_vcpu_get_hfar(vcpu
) & GENMASK(11, 0);
49 /* If not for GICV, move on */
50 if (fault_ipa
< vgic
->vgic_cpu_base
||
51 fault_ipa
>= (vgic
->vgic_cpu_base
+ KVM_VGIC_V2_CPU_SIZE
))
54 /* Reject anything but a 32bit access */
55 if (kvm_vcpu_dabt_get_as(vcpu
) != sizeof(u32
)) {
56 __kvm_skip_instr(vcpu
);
60 /* Not aligned? Don't bother */
62 __kvm_skip_instr(vcpu
);
66 rd
= kvm_vcpu_dabt_get_rd(vcpu
);
67 addr
= kvm_vgic_global_state
.vcpu_hyp_va
;
68 addr
+= fault_ipa
- vgic
->vgic_cpu_base
;
70 if (kvm_vcpu_dabt_iswrite(vcpu
)) {
71 u32 data
= vcpu_get_reg(vcpu
, rd
);
73 /* guest pre-swabbed data, undo this for writel() */
74 data
= __kvm_swab32(data
);
76 writel_relaxed(data
, addr
);
78 u32 data
= readl_relaxed(addr
);
80 /* guest expects swabbed data */
81 data
= __kvm_swab32(data
);
83 vcpu_set_reg(vcpu
, rd
, data
);
86 __kvm_skip_instr(vcpu
);