diff options
| -rw-r--r-- | arch/arm/include/asm/kvm_mmu.h | 43 | ||||
| -rw-r--r-- | arch/arm/kvm/mmu.c | 12 | ||||
| -rw-r--r-- | arch/arm64/include/asm/kvm_mmu.h | 13 |
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 | ||
| 165 | static inline void coherent_cache_guest_page(struct kvm_vcpu *vcpu, hva_t hva, | 165 | static 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 | |||
| 210 | vipt_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 | ||
| 960 | static 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 | |||
| 960 | static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, | 966 | static 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 | ||
| 246 | static inline void coherent_cache_guest_page(struct kvm_vcpu *vcpu, hva_t hva, | 246 | static 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(); |
