162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci#ifndef _ASM_X86_MMU_CONTEXT_H 362306a36Sopenharmony_ci#define _ASM_X86_MMU_CONTEXT_H 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <asm/desc.h> 662306a36Sopenharmony_ci#include <linux/atomic.h> 762306a36Sopenharmony_ci#include <linux/mm_types.h> 862306a36Sopenharmony_ci#include <linux/pkeys.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <trace/events/tlb.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <asm/tlbflush.h> 1362306a36Sopenharmony_ci#include <asm/paravirt.h> 1462306a36Sopenharmony_ci#include <asm/debugreg.h> 1562306a36Sopenharmony_ci#include <asm/gsseg.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ciextern atomic64_t last_mm_ctx_id; 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#ifdef CONFIG_PERF_EVENTS 2062306a36Sopenharmony_ciDECLARE_STATIC_KEY_FALSE(rdpmc_never_available_key); 2162306a36Sopenharmony_ciDECLARE_STATIC_KEY_FALSE(rdpmc_always_available_key); 2262306a36Sopenharmony_civoid cr4_update_pce(void *ignored); 2362306a36Sopenharmony_ci#endif 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#ifdef CONFIG_MODIFY_LDT_SYSCALL 2662306a36Sopenharmony_ci/* 2762306a36Sopenharmony_ci * ldt_structs can be allocated, used, and freed, but they are never 2862306a36Sopenharmony_ci * modified while live. 2962306a36Sopenharmony_ci */ 3062306a36Sopenharmony_cistruct ldt_struct { 3162306a36Sopenharmony_ci /* 3262306a36Sopenharmony_ci * Xen requires page-aligned LDTs with special permissions. This is 3362306a36Sopenharmony_ci * needed to prevent us from installing evil descriptors such as 3462306a36Sopenharmony_ci * call gates. On native, we could merge the ldt_struct and LDT 3562306a36Sopenharmony_ci * allocations, but it's not worth trying to optimize. 3662306a36Sopenharmony_ci */ 3762306a36Sopenharmony_ci struct desc_struct *entries; 3862306a36Sopenharmony_ci unsigned int nr_entries; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci /* 4162306a36Sopenharmony_ci * If PTI is in use, then the entries array is not mapped while we're 4262306a36Sopenharmony_ci * in user mode. The whole array will be aliased at the addressed 4362306a36Sopenharmony_ci * given by ldt_slot_va(slot). We use two slots so that we can allocate 4462306a36Sopenharmony_ci * and map, and enable a new LDT without invalidating the mapping 4562306a36Sopenharmony_ci * of an older, still-in-use LDT. 4662306a36Sopenharmony_ci * 4762306a36Sopenharmony_ci * slot will be -1 if this LDT doesn't have an alias mapping. 4862306a36Sopenharmony_ci */ 4962306a36Sopenharmony_ci int slot; 5062306a36Sopenharmony_ci}; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci/* 5362306a36Sopenharmony_ci * Used for LDT copy/destruction. 5462306a36Sopenharmony_ci */ 5562306a36Sopenharmony_cistatic inline void init_new_context_ldt(struct mm_struct *mm) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci mm->context.ldt = NULL; 5862306a36Sopenharmony_ci init_rwsem(&mm->context.ldt_usr_sem); 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ciint ldt_dup_context(struct mm_struct *oldmm, struct mm_struct *mm); 6162306a36Sopenharmony_civoid destroy_context_ldt(struct mm_struct *mm); 6262306a36Sopenharmony_civoid ldt_arch_exit_mmap(struct mm_struct *mm); 6362306a36Sopenharmony_ci#else /* CONFIG_MODIFY_LDT_SYSCALL */ 6462306a36Sopenharmony_cistatic inline void init_new_context_ldt(struct mm_struct *mm) { } 6562306a36Sopenharmony_cistatic inline int ldt_dup_context(struct mm_struct *oldmm, 6662306a36Sopenharmony_ci struct mm_struct *mm) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci return 0; 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_cistatic inline void destroy_context_ldt(struct mm_struct *mm) { } 7162306a36Sopenharmony_cistatic inline void ldt_arch_exit_mmap(struct mm_struct *mm) { } 7262306a36Sopenharmony_ci#endif 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci#ifdef CONFIG_MODIFY_LDT_SYSCALL 7562306a36Sopenharmony_ciextern void load_mm_ldt(struct mm_struct *mm); 7662306a36Sopenharmony_ciextern void switch_ldt(struct mm_struct *prev, struct mm_struct *next); 7762306a36Sopenharmony_ci#else 7862306a36Sopenharmony_cistatic inline void load_mm_ldt(struct mm_struct *mm) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci clear_LDT(); 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_cistatic inline void switch_ldt(struct mm_struct *prev, struct mm_struct *next) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci DEBUG_LOCKS_WARN_ON(preemptible()); 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci#endif 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci#ifdef CONFIG_ADDRESS_MASKING 8962306a36Sopenharmony_cistatic inline unsigned long mm_lam_cr3_mask(struct mm_struct *mm) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci return mm->context.lam_cr3_mask; 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic inline void dup_lam(struct mm_struct *oldmm, struct mm_struct *mm) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci mm->context.lam_cr3_mask = oldmm->context.lam_cr3_mask; 9762306a36Sopenharmony_ci mm->context.untag_mask = oldmm->context.untag_mask; 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci#define mm_untag_mask mm_untag_mask 10162306a36Sopenharmony_cistatic inline unsigned long mm_untag_mask(struct mm_struct *mm) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci return mm->context.untag_mask; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic inline void mm_reset_untag_mask(struct mm_struct *mm) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci mm->context.untag_mask = -1UL; 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci#define arch_pgtable_dma_compat arch_pgtable_dma_compat 11262306a36Sopenharmony_cistatic inline bool arch_pgtable_dma_compat(struct mm_struct *mm) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci return !mm_lam_cr3_mask(mm) || 11562306a36Sopenharmony_ci test_bit(MM_CONTEXT_FORCE_TAGGED_SVA, &mm->context.flags); 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci#else 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic inline unsigned long mm_lam_cr3_mask(struct mm_struct *mm) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci return 0; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic inline void dup_lam(struct mm_struct *oldmm, struct mm_struct *mm) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic inline void mm_reset_untag_mask(struct mm_struct *mm) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci#endif 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci#define enter_lazy_tlb enter_lazy_tlb 13462306a36Sopenharmony_ciextern void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci/* 13762306a36Sopenharmony_ci * Init a new mm. Used on mm copies, like at fork() 13862306a36Sopenharmony_ci * and on mm's that are brand-new, like at execve(). 13962306a36Sopenharmony_ci */ 14062306a36Sopenharmony_ci#define init_new_context init_new_context 14162306a36Sopenharmony_cistatic inline int init_new_context(struct task_struct *tsk, 14262306a36Sopenharmony_ci struct mm_struct *mm) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci mutex_init(&mm->context.lock); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci mm->context.ctx_id = atomic64_inc_return(&last_mm_ctx_id); 14762306a36Sopenharmony_ci atomic64_set(&mm->context.tlb_gen, 0); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS 15062306a36Sopenharmony_ci if (cpu_feature_enabled(X86_FEATURE_OSPKE)) { 15162306a36Sopenharmony_ci /* pkey 0 is the default and allocated implicitly */ 15262306a36Sopenharmony_ci mm->context.pkey_allocation_map = 0x1; 15362306a36Sopenharmony_ci /* -1 means unallocated or invalid */ 15462306a36Sopenharmony_ci mm->context.execute_only_pkey = -1; 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci#endif 15762306a36Sopenharmony_ci mm_reset_untag_mask(mm); 15862306a36Sopenharmony_ci init_new_context_ldt(mm); 15962306a36Sopenharmony_ci return 0; 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci#define destroy_context destroy_context 16362306a36Sopenharmony_cistatic inline void destroy_context(struct mm_struct *mm) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci destroy_context_ldt(mm); 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ciextern void switch_mm(struct mm_struct *prev, struct mm_struct *next, 16962306a36Sopenharmony_ci struct task_struct *tsk); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ciextern void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, 17262306a36Sopenharmony_ci struct task_struct *tsk); 17362306a36Sopenharmony_ci#define switch_mm_irqs_off switch_mm_irqs_off 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci#define activate_mm(prev, next) \ 17662306a36Sopenharmony_cido { \ 17762306a36Sopenharmony_ci paravirt_enter_mmap(next); \ 17862306a36Sopenharmony_ci switch_mm((prev), (next), NULL); \ 17962306a36Sopenharmony_ci} while (0); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci#ifdef CONFIG_X86_32 18262306a36Sopenharmony_ci#define deactivate_mm(tsk, mm) \ 18362306a36Sopenharmony_cido { \ 18462306a36Sopenharmony_ci loadsegment(gs, 0); \ 18562306a36Sopenharmony_ci} while (0) 18662306a36Sopenharmony_ci#else 18762306a36Sopenharmony_ci#define deactivate_mm(tsk, mm) \ 18862306a36Sopenharmony_cido { \ 18962306a36Sopenharmony_ci shstk_free(tsk); \ 19062306a36Sopenharmony_ci load_gs_index(0); \ 19162306a36Sopenharmony_ci loadsegment(fs, 0); \ 19262306a36Sopenharmony_ci} while (0) 19362306a36Sopenharmony_ci#endif 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistatic inline void arch_dup_pkeys(struct mm_struct *oldmm, 19662306a36Sopenharmony_ci struct mm_struct *mm) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS 19962306a36Sopenharmony_ci if (!cpu_feature_enabled(X86_FEATURE_OSPKE)) 20062306a36Sopenharmony_ci return; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci /* Duplicate the oldmm pkey state in mm: */ 20362306a36Sopenharmony_ci mm->context.pkey_allocation_map = oldmm->context.pkey_allocation_map; 20462306a36Sopenharmony_ci mm->context.execute_only_pkey = oldmm->context.execute_only_pkey; 20562306a36Sopenharmony_ci#endif 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistatic inline int arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci arch_dup_pkeys(oldmm, mm); 21162306a36Sopenharmony_ci paravirt_enter_mmap(mm); 21262306a36Sopenharmony_ci dup_lam(oldmm, mm); 21362306a36Sopenharmony_ci return ldt_dup_context(oldmm, mm); 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic inline void arch_exit_mmap(struct mm_struct *mm) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci paravirt_arch_exit_mmap(mm); 21962306a36Sopenharmony_ci ldt_arch_exit_mmap(mm); 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci#ifdef CONFIG_X86_64 22362306a36Sopenharmony_cistatic inline bool is_64bit_mm(struct mm_struct *mm) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci return !IS_ENABLED(CONFIG_IA32_EMULATION) || 22662306a36Sopenharmony_ci !test_bit(MM_CONTEXT_UPROBE_IA32, &mm->context.flags); 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci#else 22962306a36Sopenharmony_cistatic inline bool is_64bit_mm(struct mm_struct *mm) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci return false; 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci#endif 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic inline void arch_unmap(struct mm_struct *mm, unsigned long start, 23662306a36Sopenharmony_ci unsigned long end) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci} 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci/* 24162306a36Sopenharmony_ci * We only want to enforce protection keys on the current process 24262306a36Sopenharmony_ci * because we effectively have no access to PKRU for other 24362306a36Sopenharmony_ci * processes or any way to tell *which * PKRU in a threaded 24462306a36Sopenharmony_ci * process we could use. 24562306a36Sopenharmony_ci * 24662306a36Sopenharmony_ci * So do not enforce things if the VMA is not from the current 24762306a36Sopenharmony_ci * mm, or if we are in a kernel thread. 24862306a36Sopenharmony_ci */ 24962306a36Sopenharmony_cistatic inline bool arch_vma_access_permitted(struct vm_area_struct *vma, 25062306a36Sopenharmony_ci bool write, bool execute, bool foreign) 25162306a36Sopenharmony_ci{ 25262306a36Sopenharmony_ci /* pkeys never affect instruction fetches */ 25362306a36Sopenharmony_ci if (execute) 25462306a36Sopenharmony_ci return true; 25562306a36Sopenharmony_ci /* allow access if the VMA is not one from this process */ 25662306a36Sopenharmony_ci if (foreign || vma_is_foreign(vma)) 25762306a36Sopenharmony_ci return true; 25862306a36Sopenharmony_ci return __pkru_allows_pkey(vma_pkey(vma), write); 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ciunsigned long __get_current_cr3_fast(void); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci#include <asm-generic/mmu_context.h> 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci#endif /* _ASM_X86_MMU_CONTEXT_H */ 266