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 <linux/compiler.h>
8 #include <linux/irqchip/arm-gic.h>
9 #include <linux/kvm_host.h>
10 #include <linux/swab.h>
12 #include <asm/kvm_emulate.h>
13 #include <asm/kvm_hyp.h>
14 #include <asm/kvm_mmu.h>
16 static bool __hyp_text
__is_be(struct kvm_vcpu
*vcpu
)
18 if (vcpu_mode_is_32bit(vcpu
))
19 return !!(read_sysreg_el2(SYS_SPSR
) & PSR_AA32_E_BIT
);
21 return !!(read_sysreg(SCTLR_EL1
) & SCTLR_ELx_EE
);
25 * __vgic_v2_perform_cpuif_access -- perform a GICV access on behalf of the
28 * @vcpu: the offending vcpu
31 * 1: GICV access successfully performed
32 * 0: Not a GICV access
33 * -1: Illegal GICV access successfully performed
35 int __hyp_text
__vgic_v2_perform_cpuif_access(struct kvm_vcpu
*vcpu
)
37 struct kvm
*kvm
= kern_hyp_va(vcpu
->kvm
);
38 struct vgic_dist
*vgic
= &kvm
->arch
.vgic
;
39 phys_addr_t fault_ipa
;
43 /* Build the full address */
44 fault_ipa
= kvm_vcpu_get_fault_ipa(vcpu
);
45 fault_ipa
|= kvm_vcpu_get_hfar(vcpu
) & GENMASK(11, 0);
47 /* If not for GICV, move on */
48 if (fault_ipa
< vgic
->vgic_cpu_base
||
49 fault_ipa
>= (vgic
->vgic_cpu_base
+ KVM_VGIC_V2_CPU_SIZE
))
52 /* Reject anything but a 32bit access */
53 if (kvm_vcpu_dabt_get_as(vcpu
) != sizeof(u32
)) {
54 __kvm_skip_instr(vcpu
);
58 /* Not aligned? Don't bother */
60 __kvm_skip_instr(vcpu
);
64 rd
= kvm_vcpu_dabt_get_rd(vcpu
);
65 addr
= hyp_symbol_addr(kvm_vgic_global_state
)->vcpu_hyp_va
;
66 addr
+= fault_ipa
- vgic
->vgic_cpu_base
;
68 if (kvm_vcpu_dabt_iswrite(vcpu
)) {
69 u32 data
= vcpu_get_reg(vcpu
, rd
);
71 /* guest pre-swabbed data, undo this for writel() */
74 writel_relaxed(data
, addr
);
76 u32 data
= readl_relaxed(addr
);
78 /* guest expects swabbed data */
81 vcpu_set_reg(vcpu
, rd
, data
);
84 __kvm_skip_instr(vcpu
);