aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/include/asm/kvm_mmu.h43
-rw-r--r--arch/arm/kvm/mmu.c12
-rw-r--r--arch/arm64/include/asm/kvm_mmu.h13
3 files changed, 50 insertions, 18 deletions
diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h
index 552c31f5a3f7..1bca8f8af442 100644
--- a/arch/arm/include/asm/kvm_mmu.h
+++ b/arch/arm/include/asm/kvm_mmu.h
@@ -162,13 +162,10 @@ static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
162 return (vcpu->arch.cp15[c1_SCTLR] & 0b101) == 0b101; 162 return (vcpu->arch.cp15[c1_SCTLR] & 0b101) == 0b101;
163} 163}
164 164
165static inline void coherent_cache_guest_page(struct kvm_vcpu *vcpu, hva_t hva, 165static inline void __coherent_cache_guest_page(struct kvm_vcpu *vcpu, pfn_t pfn,
166 unsigned long size, 166 unsigned long size,
167 bool ipa_uncached) 167 bool ipa_uncached)
168{ 168{
169 if (!vcpu_has_cache_enabled(vcpu) || ipa_uncached)
170 kvm_flush_dcache_to_poc((void *)hva, size);
171
172 /* 169 /*
173 * If we are going to insert an instruction page and the icache is 170 * If we are going to insert an instruction page and the icache is
174 * either VIPT or PIPT, there is a potential problem where the host 171 * either VIPT or PIPT, there is a potential problem where the host
@@ -180,10 +177,38 @@ static inline void coherent_cache_guest_page(struct kvm_vcpu *vcpu, hva_t hva,
180 * 177 *
181 * VIVT caches are tagged using both the ASID and the VMID and doesn't 178 * VIVT caches are tagged using both the ASID and the VMID and doesn't
182 * need any kind of flushing (DDI 0406C.b - Page B3-1392). 179 * need any kind of flushing (DDI 0406C.b - Page B3-1392).
180 *
181 * We need to do this through a kernel mapping (using the
182 * user-space mapping has proved to be the wrong
183 * solution). For that, we need to kmap one page at a time,
184 * and iterate over the range.
183 */ 185 */
184 if (icache_is_pipt()) { 186
185 __cpuc_coherent_user_range(hva, hva + size); 187 bool need_flush = !vcpu_has_cache_enabled(vcpu) || ipa_uncached;
186 } else if (!icache_is_vivt_asid_tagged()) { 188
189 VM_BUG_ON(size & PAGE_MASK);
190
191 if (!need_flush && !icache_is_pipt())
192 goto vipt_cache;
193
194 while (size) {
195 void *va = kmap_atomic_pfn(pfn);
196
197 if (need_flush)
198 kvm_flush_dcache_to_poc(va, PAGE_SIZE);
199
200 if (icache_is_pipt())
201 __cpuc_coherent_user_range((unsigned long)va,
202 (unsigned long)va + PAGE_SIZE);
203
204 size -= PAGE_SIZE;
205 pfn++;
206
207 kunmap_atomic(va);
208 }
209
210vipt_cache:
211 if (!icache_is_pipt() && !icache_is_vivt_asid_tagged()) {
187 /* any kind of VIPT cache */ 212 /* any kind of VIPT cache */
188 __flush_icache_all(); 213 __flush_icache_all();
189 } 214 }
diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
index 78e68abcb01f..136662547ca6 100644
--- a/arch/arm/kvm/mmu.c
+++ b/arch/arm/kvm/mmu.c
@@ -957,6 +957,12 @@ static bool kvm_is_device_pfn(unsigned long pfn)
957 return !pfn_valid(pfn); 957 return !pfn_valid(pfn);
958} 958}
959 959
960static void coherent_cache_guest_page(struct kvm_vcpu *vcpu, pfn_t pfn,
961 unsigned long size, bool uncached)
962{
963 __coherent_cache_guest_page(vcpu, pfn, size, uncached);
964}
965
960static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, 966static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
961 struct kvm_memory_slot *memslot, unsigned long hva, 967 struct kvm_memory_slot *memslot, unsigned long hva,
962 unsigned long fault_status) 968 unsigned long fault_status)
@@ -1046,8 +1052,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
1046 kvm_set_s2pmd_writable(&new_pmd); 1052 kvm_set_s2pmd_writable(&new_pmd);
1047 kvm_set_pfn_dirty(pfn); 1053 kvm_set_pfn_dirty(pfn);
1048 } 1054 }
1049 coherent_cache_guest_page(vcpu, hva & PMD_MASK, PMD_SIZE, 1055 coherent_cache_guest_page(vcpu, pfn, PMD_SIZE, fault_ipa_uncached);
1050 fault_ipa_uncached);
1051 ret = stage2_set_pmd_huge(kvm, memcache, fault_ipa, &new_pmd); 1056 ret = stage2_set_pmd_huge(kvm, memcache, fault_ipa, &new_pmd);
1052 } else { 1057 } else {
1053 pte_t new_pte = pfn_pte(pfn, mem_type); 1058 pte_t new_pte = pfn_pte(pfn, mem_type);
@@ -1055,8 +1060,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
1055 kvm_set_s2pte_writable(&new_pte); 1060 kvm_set_s2pte_writable(&new_pte);
1056 kvm_set_pfn_dirty(pfn); 1061 kvm_set_pfn_dirty(pfn);
1057 } 1062 }
1058 coherent_cache_guest_page(vcpu, hva, PAGE_SIZE, 1063 coherent_cache_guest_page(vcpu, pfn, PAGE_SIZE, fault_ipa_uncached);
1059 fault_ipa_uncached);
1060 ret = stage2_set_pte(kvm, memcache, fault_ipa, &new_pte, 1064 ret = stage2_set_pte(kvm, memcache, fault_ipa, &new_pte,
1061 pgprot_val(mem_type) == pgprot_val(PAGE_S2_DEVICE)); 1065 pgprot_val(mem_type) == pgprot_val(PAGE_S2_DEVICE));
1062 } 1066 }
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index cbdc236d81f8..adcf49547301 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -243,15 +243,18 @@ static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
243 return (vcpu_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101; 243 return (vcpu_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
244} 244}
245 245
246static inline void coherent_cache_guest_page(struct kvm_vcpu *vcpu, hva_t hva, 246static inline void __coherent_cache_guest_page(struct kvm_vcpu *vcpu, pfn_t pfn,
247 unsigned long size, 247 unsigned long size,
248 bool ipa_uncached) 248 bool ipa_uncached)
249{ 249{
250 void *va = page_address(pfn_to_page(pfn));
251
250 if (!vcpu_has_cache_enabled(vcpu) || ipa_uncached) 252 if (!vcpu_has_cache_enabled(vcpu) || ipa_uncached)
251 kvm_flush_dcache_to_poc((void *)hva, size); 253 kvm_flush_dcache_to_poc(va, size);
252 254
253 if (!icache_is_aliasing()) { /* PIPT */ 255 if (!icache_is_aliasing()) { /* PIPT */
254 flush_icache_range(hva, hva + size); 256 flush_icache_range((unsigned long)va,
257 (unsigned long)va + size);
255 } else if (!icache_is_aivivt()) { /* non ASID-tagged VIVT */ 258 } else if (!icache_is_aivivt()) { /* non ASID-tagged VIVT */
256 /* any kind of VIPT cache */ 259 /* any kind of VIPT cache */
257 __flush_icache_all(); 260 __flush_icache_all();