~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/arm64/kvm/hyp/tlb.c

Version: ~ [ linux-5.14-rc1 ] ~ [ linux-5.13.1 ] ~ [ linux-5.12.16 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.49 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.131 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.197 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.239 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.275 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.275 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * Copyright (C) 2015 - ARM Ltd
  3  * Author: Marc Zyngier <marc.zyngier@arm.com>
  4  *
  5  * This program is free software; you can redistribute it and/or modify
  6  * it under the terms of the GNU General Public License version 2 as
  7  * published by the Free Software Foundation.
  8  *
  9  * This program is distributed in the hope that it will be useful,
 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 12  * GNU General Public License for more details.
 13  *
 14  * You should have received a copy of the GNU General Public License
 15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 16  */
 17 
 18 #include <asm/kvm_hyp.h>
 19 #include <asm/kvm_mmu.h>
 20 #include <asm/tlbflush.h>
 21 
 22 static void __hyp_text __tlb_switch_to_guest_vhe(struct kvm *kvm)
 23 {
 24         u64 val;
 25 
 26         /*
 27          * With VHE enabled, we have HCR_EL2.{E2H,TGE} = {1,1}, and
 28          * most TLB operations target EL2/EL0. In order to affect the
 29          * guest TLBs (EL1/EL0), we need to change one of these two
 30          * bits. Changing E2H is impossible (goodbye TTBR1_EL2), so
 31          * let's flip TGE before executing the TLB operation.
 32          */
 33         write_sysreg(kvm->arch.vttbr, vttbr_el2);
 34         val = read_sysreg(hcr_el2);
 35         val &= ~HCR_TGE;
 36         write_sysreg(val, hcr_el2);
 37         isb();
 38 }
 39 
 40 static void __hyp_text __tlb_switch_to_guest_nvhe(struct kvm *kvm)
 41 {
 42         write_sysreg(kvm->arch.vttbr, vttbr_el2);
 43         isb();
 44 }
 45 
 46 static hyp_alternate_select(__tlb_switch_to_guest,
 47                             __tlb_switch_to_guest_nvhe,
 48                             __tlb_switch_to_guest_vhe,
 49                             ARM64_HAS_VIRT_HOST_EXTN);
 50 
 51 static void __hyp_text __tlb_switch_to_host_vhe(struct kvm *kvm)
 52 {
 53         /*
 54          * We're done with the TLB operation, let's restore the host's
 55          * view of HCR_EL2.
 56          */
 57         write_sysreg(0, vttbr_el2);
 58         write_sysreg(HCR_HOST_VHE_FLAGS, hcr_el2);
 59 }
 60 
 61 static void __hyp_text __tlb_switch_to_host_nvhe(struct kvm *kvm)
 62 {
 63         write_sysreg(0, vttbr_el2);
 64 }
 65 
 66 static hyp_alternate_select(__tlb_switch_to_host,
 67                             __tlb_switch_to_host_nvhe,
 68                             __tlb_switch_to_host_vhe,
 69                             ARM64_HAS_VIRT_HOST_EXTN);
 70 
 71 void __hyp_text __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa)
 72 {
 73         dsb(ishst);
 74 
 75         /* Switch to requested VMID */
 76         kvm = kern_hyp_va(kvm);
 77         __tlb_switch_to_guest()(kvm);
 78 
 79         /*
 80          * We could do so much better if we had the VA as well.
 81          * Instead, we invalidate Stage-2 for this IPA, and the
 82          * whole of Stage-1. Weep...
 83          */
 84         ipa >>= 12;
 85         __tlbi(ipas2e1is, ipa);
 86 
 87         /*
 88          * We have to ensure completion of the invalidation at Stage-2,
 89          * since a table walk on another CPU could refill a TLB with a
 90          * complete (S1 + S2) walk based on the old Stage-2 mapping if
 91          * the Stage-1 invalidation happened first.
 92          */
 93         dsb(ish);
 94         __tlbi(vmalle1is);
 95         dsb(ish);
 96         isb();
 97 
 98         /*
 99          * If the host is running at EL1 and we have a VPIPT I-cache,
100          * then we must perform I-cache maintenance at EL2 in order for
101          * it to have an effect on the guest. Since the guest cannot hit
102          * I-cache lines allocated with a different VMID, we don't need
103          * to worry about junk out of guest reset (we nuke the I-cache on
104          * VMID rollover), but we do need to be careful when remapping
105          * executable pages for the same guest. This can happen when KSM
106          * takes a CoW fault on an executable page, copies the page into
107          * a page that was previously mapped in the guest and then needs
108          * to invalidate the guest view of the I-cache for that page
109          * from EL1. To solve this, we invalidate the entire I-cache when
110          * unmapping a page from a guest if we have a VPIPT I-cache but
111          * the host is running at EL1. As above, we could do better if
112          * we had the VA.
113          *
114          * The moral of this story is: if you have a VPIPT I-cache, then
115          * you should be running with VHE enabled.
116          */
117         if (!has_vhe() && icache_is_vpipt())
118                 __flush_icache_all();
119 
120         __tlb_switch_to_host()(kvm);
121 }
122 
123 void __hyp_text __kvm_tlb_flush_vmid(struct kvm *kvm)
124 {
125         dsb(ishst);
126 
127         /* Switch to requested VMID */
128         kvm = kern_hyp_va(kvm);
129         __tlb_switch_to_guest()(kvm);
130 
131         __tlbi(vmalls12e1is);
132         dsb(ish);
133         isb();
134 
135         __tlb_switch_to_host()(kvm);
136 }
137 
138 void __hyp_text __kvm_tlb_flush_local_vmid(struct kvm_vcpu *vcpu)
139 {
140         struct kvm *kvm = kern_hyp_va(kern_hyp_va(vcpu)->kvm);
141 
142         /* Switch to requested VMID */
143         __tlb_switch_to_guest()(kvm);
144 
145         __tlbi(vmalle1);
146         dsb(nsh);
147         isb();
148 
149         __tlb_switch_to_host()(kvm);
150 }
151 
152 void __hyp_text __kvm_flush_vm_context(void)
153 {
154         dsb(ishst);
155         __tlbi(alle1is);
156         asm volatile("ic ialluis" : : );
157         dsb(ish);
158 }
159 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp