Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 | /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2012 - Virtual Open Systems and Columbia University * Author: Christoffer Dall <c.dall@virtualopensystems.com> */ #ifndef __ARM_KVM_MMU_H__ #define __ARM_KVM_MMU_H__ #include <asm/memory.h> #include <asm/page.h> /* * We directly use the kernel VA for the HYP, as we can directly share * the mapping (HTTBR "covers" TTBR1). */ #define kern_hyp_va(kva) (kva) /* Contrary to arm64, there is no need to generate a PC-relative address */ #define hyp_symbol_addr(s) \ ({ \ typeof(s) *addr = &(s); \ addr; \ }) #ifndef __ASSEMBLY__ #include <linux/highmem.h> #include <asm/cacheflush.h> #include <asm/cputype.h> #include <asm/kvm_arm.h> #include <asm/kvm_hyp.h> #include <asm/pgalloc.h> #include <asm/stage2_pgtable.h> /* Ensure compatibility with arm64 */ #define VA_BITS 32 #define kvm_phys_shift(kvm) KVM_PHYS_SHIFT #define kvm_phys_size(kvm) (1ULL << kvm_phys_shift(kvm)) #define kvm_phys_mask(kvm) (kvm_phys_size(kvm) - 1ULL) #define kvm_vttbr_baddr_mask(kvm) VTTBR_BADDR_MASK #define stage2_pgd_size(kvm) (PTRS_PER_S2_PGD * sizeof(pgd_t)) int create_hyp_mappings(void *from, void *to, pgprot_t prot); int create_hyp_io_mappings(phys_addr_t phys_addr, size_t size, void __iomem **kaddr, void __iomem **haddr); int create_hyp_exec_mappings(phys_addr_t phys_addr, size_t size, void **haddr); void free_hyp_pgds(void); void stage2_unmap_vm(struct kvm *kvm); int kvm_alloc_stage2_pgd(struct kvm *kvm); void kvm_free_stage2_pgd(struct kvm *kvm); int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa, phys_addr_t pa, unsigned long size, bool writable); int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run); void kvm_mmu_free_memory_caches(struct kvm_vcpu *vcpu); phys_addr_t kvm_mmu_get_httbr(void); phys_addr_t kvm_get_idmap_vector(void); int kvm_mmu_init(void); void kvm_clear_hyp_idmap(void); #define kvm_mk_pmd(ptep) __pmd(__pa(ptep) | PMD_TYPE_TABLE) #define kvm_mk_pud(pmdp) __pud(__pa(pmdp) | PMD_TYPE_TABLE) #define kvm_mk_pgd(pudp) ({ BUILD_BUG(); 0; }) #define kvm_pfn_pte(pfn, prot) pfn_pte(pfn, prot) #define kvm_pfn_pmd(pfn, prot) pfn_pmd(pfn, prot) #define kvm_pfn_pud(pfn, prot) (__pud(0)) #define kvm_pud_pfn(pud) ({ WARN_ON(1); 0; }) #define kvm_pmd_mkhuge(pmd) pmd_mkhuge(pmd) /* No support for pud hugepages */ #define kvm_pud_mkhuge(pud) ( {WARN_ON(1); pud; }) /* * The following kvm_*pud*() functions are provided strictly to allow * sharing code with arm64. They should never be called in practice. */ static inline void kvm_set_s2pud_readonly(pud_t *pud) { WARN_ON(1); } static inline bool kvm_s2pud_readonly(pud_t *pud) { WARN_ON(1); return false; } static inline void kvm_set_pud(pud_t *pud, pud_t new_pud) { WARN_ON(1); } static inline pud_t kvm_s2pud_mkwrite(pud_t pud) { WARN_ON(1); return pud; } static inline pud_t kvm_s2pud_mkexec(pud_t pud) { WARN_ON(1); return pud; } static inline bool kvm_s2pud_exec(pud_t *pud) { WARN_ON(1); return false; } static inline pud_t kvm_s2pud_mkyoung(pud_t pud) { BUG(); return pud; } static inline bool kvm_s2pud_young(pud_t pud) { WARN_ON(1); return false; } static inline pte_t kvm_s2pte_mkwrite(pte_t pte) { pte_val(pte) |= L_PTE_S2_RDWR; return pte; } static inline pmd_t kvm_s2pmd_mkwrite(pmd_t pmd) { pmd_val(pmd) |= L_PMD_S2_RDWR; return pmd; } static inline pte_t kvm_s2pte_mkexec(pte_t pte) { pte_val(pte) &= ~L_PTE_XN; return pte; } static inline pmd_t kvm_s2pmd_mkexec(pmd_t pmd) { pmd_val(pmd) &= ~PMD_SECT_XN; return pmd; } static inline void kvm_set_s2pte_readonly(pte_t *pte) { pte_val(*pte) = (pte_val(*pte) & ~L_PTE_S2_RDWR) | L_PTE_S2_RDONLY; } static inline bool kvm_s2pte_readonly(pte_t *pte) { return (pte_val(*pte) & L_PTE_S2_RDWR) == L_PTE_S2_RDONLY; } static inline bool kvm_s2pte_exec(pte_t *pte) { return !(pte_val(*pte) & L_PTE_XN); } static inline void kvm_set_s2pmd_readonly(pmd_t *pmd) { pmd_val(*pmd) = (pmd_val(*pmd) & ~L_PMD_S2_RDWR) | L_PMD_S2_RDONLY; } static inline bool kvm_s2pmd_readonly(pmd_t *pmd) { return (pmd_val(*pmd) & L_PMD_S2_RDWR) == L_PMD_S2_RDONLY; } static inline bool kvm_s2pmd_exec(pmd_t *pmd) { return !(pmd_val(*pmd) & PMD_SECT_XN); } static inline bool kvm_page_empty(void *ptr) { struct page *ptr_page = virt_to_page(ptr); return page_count(ptr_page) == 1; } #define kvm_pte_table_empty(kvm, ptep) kvm_page_empty(ptep) #define kvm_pmd_table_empty(kvm, pmdp) kvm_page_empty(pmdp) #define kvm_pud_table_empty(kvm, pudp) false #define hyp_pte_table_empty(ptep) kvm_page_empty(ptep) #define hyp_pmd_table_empty(pmdp) kvm_page_empty(pmdp) #define hyp_pud_table_empty(pudp) false struct kvm; #define kvm_flush_dcache_to_poc(a,l) __cpuc_flush_dcache_area((a), (l)) static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu) { return (vcpu_cp15(vcpu, c1_SCTLR) & 0b101) == 0b101; } static inline void __clean_dcache_guest_page(kvm_pfn_t pfn, unsigned long size) { /* * Clean the dcache to the Point of Coherency. * * We need to do this through a kernel mapping (using the * user-space mapping has proved to be the wrong * solution). For that, we need to kmap one page at a time, * and iterate over the range. */ VM_BUG_ON(size & ~PAGE_MASK); while (size) { void *va = kmap_atomic_pfn(pfn); kvm_flush_dcache_to_poc(va, PAGE_SIZE); size -= PAGE_SIZE; pfn++; kunmap_atomic(va); } } static inline void __invalidate_icache_guest_page(kvm_pfn_t pfn, unsigned long size) { u32 iclsz; /* * If we are going to insert an instruction page and the icache is * either VIPT or PIPT, there is a potential problem where the host * (or another VM) may have used the same page as this guest, and we * read incorrect data from the icache. If we're using a PIPT cache, * we can invalidate just that page, but if we are using a VIPT cache * we need to invalidate the entire icache - damn shame - as written * in the ARM ARM (DDI 0406C.b - Page B3-1393). * * VIVT caches are tagged using both the ASID and the VMID and doesn't * need any kind of flushing (DDI 0406C.b - Page B3-1392). */ VM_BUG_ON(size & ~PAGE_MASK); if (icache_is_vivt_asid_tagged()) return; if (!icache_is_pipt()) { /* any kind of VIPT cache */ __flush_icache_all(); return; } /* * CTR IminLine contains Log2 of the number of words in the * cache line, so we can get the number of words as * 2 << (IminLine - 1). To get the number of bytes, we * multiply by 4 (the number of bytes in a 32-bit word), and * get 4 << (IminLine). */ iclsz = 4 << (read_cpuid(CPUID_CACHETYPE) & 0xf); while (size) { void *va = kmap_atomic_pfn(pfn); void *end = va + PAGE_SIZE; void *addr = va; do { write_sysreg(addr, ICIMVAU); addr += iclsz; } while (addr < end); dsb(ishst); isb(); size -= PAGE_SIZE; pfn++; kunmap_atomic(va); } /* Check if we need to invalidate the BTB */ if ((read_cpuid_ext(CPUID_EXT_MMFR1) >> 28) != 4) { write_sysreg(0, BPIALLIS); dsb(ishst); isb(); } } static inline void __kvm_flush_dcache_pte(pte_t pte) { void *va = kmap_atomic(pte_page(pte)); kvm_flush_dcache_to_poc(va, PAGE_SIZE); kunmap_atomic(va); } static inline void __kvm_flush_dcache_pmd(pmd_t pmd) { unsigned long size = PMD_SIZE; kvm_pfn_t pfn = pmd_pfn(pmd); while (size) { void *va = kmap_atomic_pfn(pfn); kvm_flush_dcache_to_poc(va, PAGE_SIZE); pfn++; size -= PAGE_SIZE; kunmap_atomic(va); } } static inline void __kvm_flush_dcache_pud(pud_t pud) { } #define kvm_virt_to_phys(x) virt_to_idmap((unsigned long)(x)) void kvm_set_way_flush(struct kvm_vcpu *vcpu); void kvm_toggle_cache(struct kvm_vcpu *vcpu, bool was_enabled); static inline bool __kvm_cpu_uses_extended_idmap(void) { return false; } static inline unsigned long __kvm_idmap_ptrs_per_pgd(void) { return PTRS_PER_PGD; } static inline void __kvm_extend_hypmap(pgd_t *boot_hyp_pgd, pgd_t *hyp_pgd, pgd_t *merged_hyp_pgd, unsigned long hyp_idmap_start) { } static inline unsigned int kvm_get_vmid_bits(void) { return 8; } /* * We are not in the kvm->srcu critical section most of the time, so we take * the SRCU read lock here. Since we copy the data from the user page, we * can immediately drop the lock again. */ static inline int kvm_read_guest_lock(struct kvm *kvm, gpa_t gpa, void *data, unsigned long len) { int srcu_idx = srcu_read_lock(&kvm->srcu); int ret = kvm_read_guest(kvm, gpa, data, len); srcu_read_unlock(&kvm->srcu, srcu_idx); return ret; } static inline int kvm_write_guest_lock(struct kvm *kvm, gpa_t gpa, const void *data, unsigned long len) { int srcu_idx = srcu_read_lock(&kvm->srcu); int ret = kvm_write_guest(kvm, gpa, data, len); srcu_read_unlock(&kvm->srcu, srcu_idx); return ret; } static inline void *kvm_get_hyp_vector(void) { switch(read_cpuid_part()) { #ifdef CONFIG_HARDEN_BRANCH_PREDICTOR case ARM_CPU_PART_CORTEX_A12: case ARM_CPU_PART_CORTEX_A17: { extern char __kvm_hyp_vector_bp_inv[]; return kvm_ksym_ref(__kvm_hyp_vector_bp_inv); } case ARM_CPU_PART_BRAHMA_B15: case ARM_CPU_PART_CORTEX_A15: { extern char __kvm_hyp_vector_ic_inv[]; return kvm_ksym_ref(__kvm_hyp_vector_ic_inv); } #endif default: { extern char __kvm_hyp_vector[]; return kvm_ksym_ref(__kvm_hyp_vector); } } } static inline int kvm_map_vectors(void) { return 0; } static inline int hyp_map_aux_data(void) { return 0; } #define kvm_phys_to_vttbr(addr) (addr) static inline void kvm_set_ipa_limit(void) {} static __always_inline u64 kvm_get_vttbr(struct kvm *kvm) { struct kvm_vmid *vmid = &kvm->arch.vmid; u64 vmid_field, baddr; baddr = kvm->arch.pgd_phys; vmid_field = (u64)vmid->vmid << VTTBR_VMID_SHIFT; return kvm_phys_to_vttbr(baddr) | vmid_field; } #endif /* !__ASSEMBLY__ */ #endif /* __ARM_KVM_MMU_H__ */ |