aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2017-02-17 09:32:18 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-03-22 07:43:39 -0400
commit61e79860b4bc6259a9685a107a6b34352d6dc7bd (patch)
tree2933e2eb4dd2df971d92c1eb91d1c5a9d01e52b4
parent8ca7ef0d9af9644a65e3e22ccc1937f00caa777b (diff)
arm64: KVM: VHE: Clear HCR_TGE when invalidating guest TLBs
commit 68925176296a8b995e503349200e256674bfe5ac upstream. When invalidating guest TLBs, special care must be taken to actually shoot the guest TLBs and not the host ones if we're running on a VHE system. This is controlled by the HCR_EL2.TGE bit, which we forget to clear before invalidating TLBs. Address the issue by introducing two wrappers (__tlb_switch_to_guest and __tlb_switch_to_host) that take care of both the VTTBR_EL2 and HCR_EL2.TGE switching. Reported-by: Tomasz Nowicki <tnowicki@caviumnetworks.com> Tested-by: Tomasz Nowicki <tnowicki@caviumnetworks.com> Reviewed-by: Christoffer Dall <cdall@linaro.org> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--arch/arm64/kvm/hyp/tlb.c64
1 files changed, 55 insertions, 9 deletions
diff --git a/arch/arm64/kvm/hyp/tlb.c b/arch/arm64/kvm/hyp/tlb.c
index 88e2f2b938f0..55889d057757 100644
--- a/arch/arm64/kvm/hyp/tlb.c
+++ b/arch/arm64/kvm/hyp/tlb.c
@@ -17,14 +17,62 @@
17 17
18#include <asm/kvm_hyp.h> 18#include <asm/kvm_hyp.h>
19 19
20static void __hyp_text __tlb_switch_to_guest_vhe(struct kvm *kvm)
21{
22 u64 val;
23
24 /*
25 * With VHE enabled, we have HCR_EL2.{E2H,TGE} = {1,1}, and
26 * most TLB operations target EL2/EL0. In order to affect the
27 * guest TLBs (EL1/EL0), we need to change one of these two
28 * bits. Changing E2H is impossible (goodbye TTBR1_EL2), so
29 * let's flip TGE before executing the TLB operation.
30 */
31 write_sysreg(kvm->arch.vttbr, vttbr_el2);
32 val = read_sysreg(hcr_el2);
33 val &= ~HCR_TGE;
34 write_sysreg(val, hcr_el2);
35 isb();
36}
37
38static void __hyp_text __tlb_switch_to_guest_nvhe(struct kvm *kvm)
39{
40 write_sysreg(kvm->arch.vttbr, vttbr_el2);
41 isb();
42}
43
44static hyp_alternate_select(__tlb_switch_to_guest,
45 __tlb_switch_to_guest_nvhe,
46 __tlb_switch_to_guest_vhe,
47 ARM64_HAS_VIRT_HOST_EXTN);
48
49static void __hyp_text __tlb_switch_to_host_vhe(struct kvm *kvm)
50{
51 /*
52 * We're done with the TLB operation, let's restore the host's
53 * view of HCR_EL2.
54 */
55 write_sysreg(0, vttbr_el2);
56 write_sysreg(HCR_HOST_VHE_FLAGS, hcr_el2);
57}
58
59static void __hyp_text __tlb_switch_to_host_nvhe(struct kvm *kvm)
60{
61 write_sysreg(0, vttbr_el2);
62}
63
64static hyp_alternate_select(__tlb_switch_to_host,
65 __tlb_switch_to_host_nvhe,
66 __tlb_switch_to_host_vhe,
67 ARM64_HAS_VIRT_HOST_EXTN);
68
20void __hyp_text __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa) 69void __hyp_text __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa)
21{ 70{
22 dsb(ishst); 71 dsb(ishst);
23 72
24 /* Switch to requested VMID */ 73 /* Switch to requested VMID */
25 kvm = kern_hyp_va(kvm); 74 kvm = kern_hyp_va(kvm);
26 write_sysreg(kvm->arch.vttbr, vttbr_el2); 75 __tlb_switch_to_guest()(kvm);
27 isb();
28 76
29 /* 77 /*
30 * We could do so much better if we had the VA as well. 78 * We could do so much better if we had the VA as well.
@@ -45,7 +93,7 @@ void __hyp_text __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa)
45 dsb(ish); 93 dsb(ish);
46 isb(); 94 isb();
47 95
48 write_sysreg(0, vttbr_el2); 96 __tlb_switch_to_host()(kvm);
49} 97}
50 98
51void __hyp_text __kvm_tlb_flush_vmid(struct kvm *kvm) 99void __hyp_text __kvm_tlb_flush_vmid(struct kvm *kvm)
@@ -54,14 +102,13 @@ void __hyp_text __kvm_tlb_flush_vmid(struct kvm *kvm)
54 102
55 /* Switch to requested VMID */ 103 /* Switch to requested VMID */
56 kvm = kern_hyp_va(kvm); 104 kvm = kern_hyp_va(kvm);
57 write_sysreg(kvm->arch.vttbr, vttbr_el2); 105 __tlb_switch_to_guest()(kvm);
58 isb();
59 106
60 asm volatile("tlbi vmalls12e1is" : : ); 107 asm volatile("tlbi vmalls12e1is" : : );
61 dsb(ish); 108 dsb(ish);
62 isb(); 109 isb();
63 110
64 write_sysreg(0, vttbr_el2); 111 __tlb_switch_to_host()(kvm);
65} 112}
66 113
67void __hyp_text __kvm_tlb_flush_local_vmid(struct kvm_vcpu *vcpu) 114void __hyp_text __kvm_tlb_flush_local_vmid(struct kvm_vcpu *vcpu)
@@ -69,14 +116,13 @@ void __hyp_text __kvm_tlb_flush_local_vmid(struct kvm_vcpu *vcpu)
69 struct kvm *kvm = kern_hyp_va(kern_hyp_va(vcpu)->kvm); 116 struct kvm *kvm = kern_hyp_va(kern_hyp_va(vcpu)->kvm);
70 117
71 /* Switch to requested VMID */ 118 /* Switch to requested VMID */
72 write_sysreg(kvm->arch.vttbr, vttbr_el2); 119 __tlb_switch_to_guest()(kvm);
73 isb();
74 120
75 asm volatile("tlbi vmalle1" : : ); 121 asm volatile("tlbi vmalle1" : : );
76 dsb(nsh); 122 dsb(nsh);
77 isb(); 123 isb();
78 124
79 write_sysreg(0, vttbr_el2); 125 __tlb_switch_to_host()(kvm);
80} 126}
81 127
82void __hyp_text __kvm_flush_vm_context(void) 128void __hyp_text __kvm_flush_vm_context(void)