|
19 | 19 | #include <linux/irqchip/arm-gic.h>
|
20 | 20 | #include <linux/kvm_host.h>
|
21 | 21 |
|
| 22 | +#include <asm/kvm_emulate.h> |
22 | 23 | #include <asm/kvm_hyp.h>
|
23 | 24 |
|
24 | 25 | static void __hyp_text save_maint_int_state(struct kvm_vcpu *vcpu,
|
@@ -171,6 +172,44 @@ void __hyp_text __vgic_v2_restore_state(struct kvm_vcpu *vcpu)
|
171 | 172 | #ifdef CONFIG_ARM64
|
172 | 173 | bool __hyp_text __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu)
|
173 | 174 | {
|
| 175 | + struct kvm *kvm = kern_hyp_va(vcpu->kvm); |
| 176 | + struct vgic_dist *vgic = &kvm->arch.vgic; |
| 177 | + phys_addr_t fault_ipa; |
| 178 | + void __iomem *addr; |
| 179 | + int rd; |
| 180 | + |
| 181 | + /* Build the full address */ |
| 182 | + fault_ipa = kvm_vcpu_get_fault_ipa(vcpu); |
| 183 | + fault_ipa |= kvm_vcpu_get_hfar(vcpu) & GENMASK(11, 0); |
| 184 | + |
| 185 | + /* If not for GICV, move on */ |
| 186 | + if (fault_ipa < vgic->vgic_cpu_base || |
| 187 | + fault_ipa >= (vgic->vgic_cpu_base + KVM_VGIC_V2_CPU_SIZE)) |
174 | 188 | return false;
|
| 189 | + |
| 190 | + /* Reject anything but a 32bit access */ |
| 191 | + if (kvm_vcpu_dabt_get_as(vcpu) != sizeof(u32)) |
| 192 | + return false; |
| 193 | + |
| 194 | + /* Not aligned? Don't bother */ |
| 195 | + if (fault_ipa & 3) |
| 196 | + return false; |
| 197 | + |
| 198 | + rd = kvm_vcpu_dabt_get_rd(vcpu); |
| 199 | + addr = kern_hyp_va((kern_hyp_va(&kvm_vgic_global_state))->vcpu_base_va); |
| 200 | + addr += fault_ipa - vgic->vgic_cpu_base; |
| 201 | + |
| 202 | + if (kvm_vcpu_dabt_iswrite(vcpu)) { |
| 203 | + u32 data = vcpu_data_guest_to_host(vcpu, |
| 204 | + vcpu_get_reg(vcpu, rd), |
| 205 | + sizeof(u32)); |
| 206 | + writel_relaxed(data, addr); |
| 207 | + } else { |
| 208 | + u32 data = readl_relaxed(addr); |
| 209 | + vcpu_set_reg(vcpu, rd, vcpu_data_host_to_guest(vcpu, data, |
| 210 | + sizeof(u32))); |
| 211 | + } |
| 212 | + |
| 213 | + return true; |
175 | 214 | }
|
176 | 215 | #endif
|
0 commit comments