aboutsummaryrefslogtreecommitdiffstats
path: root/virt/kvm
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2016-09-06 04:28:46 -0400
committerChristoffer Dall <christoffer.dall@linaro.org>2016-09-08 06:53:00 -0400
commitbf8feb39642b4c71c644e2d534ce53029bd2219b (patch)
treed1431a60d21e578e1bac31afc39cc69252f290ec /virt/kvm
parentfb5ee369ccd3986b28adc20d43d73a2b2c141977 (diff)
arm64: KVM: vgic-v2: Add GICV access from HYP
Now that we have the necessary infrastructure to handle MMIO accesses in HYP, perform the GICV access on behalf of the guest. This requires checking that the access is strictly 32bit, properly aligned, and falls within the expected range. When all condition are satisfied, we perform the access and tell the rest of the HYP code that the instruction has been correctly emulated. Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Diffstat (limited to 'virt/kvm')
-rw-r--r--virt/kvm/arm/hyp/vgic-v2-sr.c39
1 files changed, 39 insertions, 0 deletions
diff --git a/virt/kvm/arm/hyp/vgic-v2-sr.c b/virt/kvm/arm/hyp/vgic-v2-sr.c
index 3e2a62e27eba..a052f2056cc0 100644
--- a/virt/kvm/arm/hyp/vgic-v2-sr.c
+++ b/virt/kvm/arm/hyp/vgic-v2-sr.c
@@ -19,6 +19,7 @@
19#include <linux/irqchip/arm-gic.h> 19#include <linux/irqchip/arm-gic.h>
20#include <linux/kvm_host.h> 20#include <linux/kvm_host.h>
21 21
22#include <asm/kvm_emulate.h>
22#include <asm/kvm_hyp.h> 23#include <asm/kvm_hyp.h>
23 24
24static void __hyp_text save_maint_int_state(struct kvm_vcpu *vcpu, 25static 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#ifdef CONFIG_ARM64 172#ifdef CONFIG_ARM64
172bool __hyp_text __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu) 173bool __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 return false; 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#endif 215#endif