162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2012 ARM Ltd. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci#ifndef __ASM_MMU_H 662306a36Sopenharmony_ci#define __ASM_MMU_H 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <asm/cputype.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#define MMCF_AARCH32 0x1 /* mm context flag for AArch32 executables */ 1162306a36Sopenharmony_ci#define USER_ASID_BIT 48 1262306a36Sopenharmony_ci#define USER_ASID_FLAG (UL(1) << USER_ASID_BIT) 1362306a36Sopenharmony_ci#define TTBR_ASID_MASK (UL(0xffff) << 48) 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#ifndef __ASSEMBLY__ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <linux/refcount.h> 1862306a36Sopenharmony_ci#include <asm/cpufeature.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_citypedef struct { 2162306a36Sopenharmony_ci atomic64_t id; 2262306a36Sopenharmony_ci#ifdef CONFIG_COMPAT 2362306a36Sopenharmony_ci void *sigpage; 2462306a36Sopenharmony_ci#endif 2562306a36Sopenharmony_ci refcount_t pinned; 2662306a36Sopenharmony_ci void *vdso; 2762306a36Sopenharmony_ci unsigned long flags; 2862306a36Sopenharmony_ci} mm_context_t; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/* 3162306a36Sopenharmony_ci * We use atomic64_read() here because the ASID for an 'mm_struct' can 3262306a36Sopenharmony_ci * be reallocated when scheduling one of its threads following a 3362306a36Sopenharmony_ci * rollover event (see new_context() and flush_context()). In this case, 3462306a36Sopenharmony_ci * a concurrent TLBI (e.g. via try_to_unmap_one() and ptep_clear_flush()) 3562306a36Sopenharmony_ci * may use a stale ASID. This is fine in principle as the new ASID is 3662306a36Sopenharmony_ci * guaranteed to be clean in the TLB, but the TLBI routines have to take 3762306a36Sopenharmony_ci * care to handle the following race: 3862306a36Sopenharmony_ci * 3962306a36Sopenharmony_ci * CPU 0 CPU 1 CPU 2 4062306a36Sopenharmony_ci * 4162306a36Sopenharmony_ci * // ptep_clear_flush(mm) 4262306a36Sopenharmony_ci * xchg_relaxed(pte, 0) 4362306a36Sopenharmony_ci * DSB ISHST 4462306a36Sopenharmony_ci * old = ASID(mm) 4562306a36Sopenharmony_ci * | <rollover> 4662306a36Sopenharmony_ci * | new = new_context(mm) 4762306a36Sopenharmony_ci * \-----------------> atomic_set(mm->context.id, new) 4862306a36Sopenharmony_ci * cpu_switch_mm(mm) 4962306a36Sopenharmony_ci * // Hardware walk of pte using new ASID 5062306a36Sopenharmony_ci * TLBI(old) 5162306a36Sopenharmony_ci * 5262306a36Sopenharmony_ci * In this scenario, the barrier on CPU 0 and the dependency on CPU 1 5362306a36Sopenharmony_ci * ensure that the page-table walker on CPU 1 *must* see the invalid PTE 5462306a36Sopenharmony_ci * written by CPU 0. 5562306a36Sopenharmony_ci */ 5662306a36Sopenharmony_ci#define ASID(mm) (atomic64_read(&(mm)->context.id) & 0xffff) 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic inline bool arm64_kernel_unmapped_at_el0(void) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci return cpus_have_const_cap(ARM64_UNMAP_KERNEL_AT_EL0); 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ciextern void arm64_memblock_init(void); 6462306a36Sopenharmony_ciextern void paging_init(void); 6562306a36Sopenharmony_ciextern void bootmem_init(void); 6662306a36Sopenharmony_ciextern void __iomem *early_io_map(phys_addr_t phys, unsigned long virt); 6762306a36Sopenharmony_ciextern void create_mapping_noalloc(phys_addr_t phys, unsigned long virt, 6862306a36Sopenharmony_ci phys_addr_t size, pgprot_t prot); 6962306a36Sopenharmony_ciextern void create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys, 7062306a36Sopenharmony_ci unsigned long virt, phys_addr_t size, 7162306a36Sopenharmony_ci pgprot_t prot, bool page_mappings_only); 7262306a36Sopenharmony_ciextern void *fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot); 7362306a36Sopenharmony_ciextern void mark_linear_text_alias_ro(void); 7462306a36Sopenharmony_ciextern bool kaslr_requires_kpti(void); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci#define INIT_MM_CONTEXT(name) \ 7762306a36Sopenharmony_ci .pgd = init_pg_dir, 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci#endif /* !__ASSEMBLY__ */ 8062306a36Sopenharmony_ci#endif 81