Commit 61e79860 authored by Marc Zyngier's avatar Marc Zyngier Committed by Greg Kroah-Hartman

arm64: KVM: VHE: Clear HCR_TGE when invalidating guest TLBs

commit 68925176 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: default avatarTomasz Nowicki <tnowicki@caviumnetworks.com>
Tested-by: default avatarTomasz Nowicki <tnowicki@caviumnetworks.com>
Reviewed-by: default avatarChristoffer Dall <cdall@linaro.org>
Signed-off-by: default avatarMarc Zyngier <marc.zyngier@arm.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 8ca7ef0d
...@@ -17,14 +17,62 @@ ...@@ -17,14 +17,62 @@
#include <asm/kvm_hyp.h> #include <asm/kvm_hyp.h>
static void __hyp_text __tlb_switch_to_guest_vhe(struct kvm *kvm)
{
u64 val;
/*
* With VHE enabled, we have HCR_EL2.{E2H,TGE} = {1,1}, and
* most TLB operations target EL2/EL0. In order to affect the
* guest TLBs (EL1/EL0), we need to change one of these two
* bits. Changing E2H is impossible (goodbye TTBR1_EL2), so
* let's flip TGE before executing the TLB operation.
*/
write_sysreg(kvm->arch.vttbr, vttbr_el2);
val = read_sysreg(hcr_el2);
val &= ~HCR_TGE;
write_sysreg(val, hcr_el2);
isb();
}
static void __hyp_text __tlb_switch_to_guest_nvhe(struct kvm *kvm)
{
write_sysreg(kvm->arch.vttbr, vttbr_el2);
isb();
}
static hyp_alternate_select(__tlb_switch_to_guest,
__tlb_switch_to_guest_nvhe,
__tlb_switch_to_guest_vhe,
ARM64_HAS_VIRT_HOST_EXTN);
static void __hyp_text __tlb_switch_to_host_vhe(struct kvm *kvm)
{
/*
* We're done with the TLB operation, let's restore the host's
* view of HCR_EL2.
*/
write_sysreg(0, vttbr_el2);
write_sysreg(HCR_HOST_VHE_FLAGS, hcr_el2);
}
static void __hyp_text __tlb_switch_to_host_nvhe(struct kvm *kvm)
{
write_sysreg(0, vttbr_el2);
}
static hyp_alternate_select(__tlb_switch_to_host,
__tlb_switch_to_host_nvhe,
__tlb_switch_to_host_vhe,
ARM64_HAS_VIRT_HOST_EXTN);
void __hyp_text __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa) void __hyp_text __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa)
{ {
dsb(ishst); dsb(ishst);
/* Switch to requested VMID */ /* Switch to requested VMID */
kvm = kern_hyp_va(kvm); kvm = kern_hyp_va(kvm);
write_sysreg(kvm->arch.vttbr, vttbr_el2); __tlb_switch_to_guest()(kvm);
isb();
/* /*
* We could do so much better if we had the VA as well. * 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,7 +93,7 @@ void __hyp_text __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa)
dsb(ish); dsb(ish);
isb(); isb();
write_sysreg(0, vttbr_el2); __tlb_switch_to_host()(kvm);
} }
void __hyp_text __kvm_tlb_flush_vmid(struct kvm *kvm) void __hyp_text __kvm_tlb_flush_vmid(struct kvm *kvm)
...@@ -54,14 +102,13 @@ void __hyp_text __kvm_tlb_flush_vmid(struct kvm *kvm) ...@@ -54,14 +102,13 @@ void __hyp_text __kvm_tlb_flush_vmid(struct kvm *kvm)
/* Switch to requested VMID */ /* Switch to requested VMID */
kvm = kern_hyp_va(kvm); kvm = kern_hyp_va(kvm);
write_sysreg(kvm->arch.vttbr, vttbr_el2); __tlb_switch_to_guest()(kvm);
isb();
asm volatile("tlbi vmalls12e1is" : : ); asm volatile("tlbi vmalls12e1is" : : );
dsb(ish); dsb(ish);
isb(); isb();
write_sysreg(0, vttbr_el2); __tlb_switch_to_host()(kvm);
} }
void __hyp_text __kvm_tlb_flush_local_vmid(struct kvm_vcpu *vcpu) void __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,14 +116,13 @@ void __hyp_text __kvm_tlb_flush_local_vmid(struct kvm_vcpu *vcpu)
struct kvm *kvm = kern_hyp_va(kern_hyp_va(vcpu)->kvm); struct kvm *kvm = kern_hyp_va(kern_hyp_va(vcpu)->kvm);
/* Switch to requested VMID */ /* Switch to requested VMID */
write_sysreg(kvm->arch.vttbr, vttbr_el2); __tlb_switch_to_guest()(kvm);
isb();
asm volatile("tlbi vmalle1" : : ); asm volatile("tlbi vmalle1" : : );
dsb(nsh); dsb(nsh);
isb(); isb();
write_sysreg(0, vttbr_el2); __tlb_switch_to_host()(kvm);
} }
void __hyp_text __kvm_flush_vm_context(void) void __hyp_text __kvm_flush_vm_context(void)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment