18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci#ifndef _ASM_X86_MMU_CONTEXT_H 38c2ecf20Sopenharmony_ci#define _ASM_X86_MMU_CONTEXT_H 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#include <asm/desc.h> 68c2ecf20Sopenharmony_ci#include <linux/atomic.h> 78c2ecf20Sopenharmony_ci#include <linux/mm_types.h> 88c2ecf20Sopenharmony_ci#include <linux/pkeys.h> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <trace/events/tlb.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <asm/tlbflush.h> 138c2ecf20Sopenharmony_ci#include <asm/paravirt.h> 148c2ecf20Sopenharmony_ci#include <asm/debugreg.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ciextern atomic64_t last_mm_ctx_id; 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#ifndef CONFIG_PARAVIRT_XXL 198c2ecf20Sopenharmony_cistatic inline void paravirt_activate_mm(struct mm_struct *prev, 208c2ecf20Sopenharmony_ci struct mm_struct *next) 218c2ecf20Sopenharmony_ci{ 228c2ecf20Sopenharmony_ci} 238c2ecf20Sopenharmony_ci#endif /* !CONFIG_PARAVIRT_XXL */ 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#ifdef CONFIG_PERF_EVENTS 268c2ecf20Sopenharmony_ciDECLARE_STATIC_KEY_FALSE(rdpmc_never_available_key); 278c2ecf20Sopenharmony_ciDECLARE_STATIC_KEY_FALSE(rdpmc_always_available_key); 288c2ecf20Sopenharmony_civoid cr4_update_pce(void *ignored); 298c2ecf20Sopenharmony_ci#endif 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#ifdef CONFIG_MODIFY_LDT_SYSCALL 328c2ecf20Sopenharmony_ci/* 338c2ecf20Sopenharmony_ci * ldt_structs can be allocated, used, and freed, but they are never 348c2ecf20Sopenharmony_ci * modified while live. 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_cistruct ldt_struct { 378c2ecf20Sopenharmony_ci /* 388c2ecf20Sopenharmony_ci * Xen requires page-aligned LDTs with special permissions. This is 398c2ecf20Sopenharmony_ci * needed to prevent us from installing evil descriptors such as 408c2ecf20Sopenharmony_ci * call gates. On native, we could merge the ldt_struct and LDT 418c2ecf20Sopenharmony_ci * allocations, but it's not worth trying to optimize. 428c2ecf20Sopenharmony_ci */ 438c2ecf20Sopenharmony_ci struct desc_struct *entries; 448c2ecf20Sopenharmony_ci unsigned int nr_entries; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci /* 478c2ecf20Sopenharmony_ci * If PTI is in use, then the entries array is not mapped while we're 488c2ecf20Sopenharmony_ci * in user mode. The whole array will be aliased at the addressed 498c2ecf20Sopenharmony_ci * given by ldt_slot_va(slot). We use two slots so that we can allocate 508c2ecf20Sopenharmony_ci * and map, and enable a new LDT without invalidating the mapping 518c2ecf20Sopenharmony_ci * of an older, still-in-use LDT. 528c2ecf20Sopenharmony_ci * 538c2ecf20Sopenharmony_ci * slot will be -1 if this LDT doesn't have an alias mapping. 548c2ecf20Sopenharmony_ci */ 558c2ecf20Sopenharmony_ci int slot; 568c2ecf20Sopenharmony_ci}; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* 598c2ecf20Sopenharmony_ci * Used for LDT copy/destruction. 608c2ecf20Sopenharmony_ci */ 618c2ecf20Sopenharmony_cistatic inline void init_new_context_ldt(struct mm_struct *mm) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci mm->context.ldt = NULL; 648c2ecf20Sopenharmony_ci init_rwsem(&mm->context.ldt_usr_sem); 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ciint ldt_dup_context(struct mm_struct *oldmm, struct mm_struct *mm); 678c2ecf20Sopenharmony_civoid destroy_context_ldt(struct mm_struct *mm); 688c2ecf20Sopenharmony_civoid ldt_arch_exit_mmap(struct mm_struct *mm); 698c2ecf20Sopenharmony_ci#else /* CONFIG_MODIFY_LDT_SYSCALL */ 708c2ecf20Sopenharmony_cistatic inline void init_new_context_ldt(struct mm_struct *mm) { } 718c2ecf20Sopenharmony_cistatic inline int ldt_dup_context(struct mm_struct *oldmm, 728c2ecf20Sopenharmony_ci struct mm_struct *mm) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci return 0; 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_cistatic inline void destroy_context_ldt(struct mm_struct *mm) { } 778c2ecf20Sopenharmony_cistatic inline void ldt_arch_exit_mmap(struct mm_struct *mm) { } 788c2ecf20Sopenharmony_ci#endif 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci#ifdef CONFIG_MODIFY_LDT_SYSCALL 818c2ecf20Sopenharmony_ciextern void load_mm_ldt(struct mm_struct *mm); 828c2ecf20Sopenharmony_ciextern void switch_ldt(struct mm_struct *prev, struct mm_struct *next); 838c2ecf20Sopenharmony_ci#else 848c2ecf20Sopenharmony_cistatic inline void load_mm_ldt(struct mm_struct *mm) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci clear_LDT(); 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_cistatic inline void switch_ldt(struct mm_struct *prev, struct mm_struct *next) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci DEBUG_LOCKS_WARN_ON(preemptible()); 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci#endif 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ciextern void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci/* 978c2ecf20Sopenharmony_ci * Init a new mm. Used on mm copies, like at fork() 988c2ecf20Sopenharmony_ci * and on mm's that are brand-new, like at execve(). 998c2ecf20Sopenharmony_ci */ 1008c2ecf20Sopenharmony_cistatic inline int init_new_context(struct task_struct *tsk, 1018c2ecf20Sopenharmony_ci struct mm_struct *mm) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci mutex_init(&mm->context.lock); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci mm->context.ctx_id = atomic64_inc_return(&last_mm_ctx_id); 1068c2ecf20Sopenharmony_ci atomic64_set(&mm->context.tlb_gen, 0); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS 1098c2ecf20Sopenharmony_ci if (cpu_feature_enabled(X86_FEATURE_OSPKE)) { 1108c2ecf20Sopenharmony_ci /* pkey 0 is the default and allocated implicitly */ 1118c2ecf20Sopenharmony_ci mm->context.pkey_allocation_map = 0x1; 1128c2ecf20Sopenharmony_ci /* -1 means unallocated or invalid */ 1138c2ecf20Sopenharmony_ci mm->context.execute_only_pkey = -1; 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci#endif 1168c2ecf20Sopenharmony_ci init_new_context_ldt(mm); 1178c2ecf20Sopenharmony_ci return 0; 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_cistatic inline void destroy_context(struct mm_struct *mm) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci destroy_context_ldt(mm); 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ciextern void switch_mm(struct mm_struct *prev, struct mm_struct *next, 1258c2ecf20Sopenharmony_ci struct task_struct *tsk); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ciextern void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, 1288c2ecf20Sopenharmony_ci struct task_struct *tsk); 1298c2ecf20Sopenharmony_ci#define switch_mm_irqs_off switch_mm_irqs_off 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci#define activate_mm(prev, next) \ 1328c2ecf20Sopenharmony_cido { \ 1338c2ecf20Sopenharmony_ci paravirt_activate_mm((prev), (next)); \ 1348c2ecf20Sopenharmony_ci switch_mm((prev), (next), NULL); \ 1358c2ecf20Sopenharmony_ci} while (0); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_32 1388c2ecf20Sopenharmony_ci#define deactivate_mm(tsk, mm) \ 1398c2ecf20Sopenharmony_cido { \ 1408c2ecf20Sopenharmony_ci lazy_load_gs(0); \ 1418c2ecf20Sopenharmony_ci} while (0) 1428c2ecf20Sopenharmony_ci#else 1438c2ecf20Sopenharmony_ci#define deactivate_mm(tsk, mm) \ 1448c2ecf20Sopenharmony_cido { \ 1458c2ecf20Sopenharmony_ci load_gs_index(0); \ 1468c2ecf20Sopenharmony_ci loadsegment(fs, 0); \ 1478c2ecf20Sopenharmony_ci} while (0) 1488c2ecf20Sopenharmony_ci#endif 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic inline void arch_dup_pkeys(struct mm_struct *oldmm, 1518c2ecf20Sopenharmony_ci struct mm_struct *mm) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS 1548c2ecf20Sopenharmony_ci if (!cpu_feature_enabled(X86_FEATURE_OSPKE)) 1558c2ecf20Sopenharmony_ci return; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci /* Duplicate the oldmm pkey state in mm: */ 1588c2ecf20Sopenharmony_ci mm->context.pkey_allocation_map = oldmm->context.pkey_allocation_map; 1598c2ecf20Sopenharmony_ci mm->context.execute_only_pkey = oldmm->context.execute_only_pkey; 1608c2ecf20Sopenharmony_ci#endif 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic inline int arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci arch_dup_pkeys(oldmm, mm); 1668c2ecf20Sopenharmony_ci paravirt_arch_dup_mmap(oldmm, mm); 1678c2ecf20Sopenharmony_ci return ldt_dup_context(oldmm, mm); 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic inline void arch_exit_mmap(struct mm_struct *mm) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci paravirt_arch_exit_mmap(mm); 1738c2ecf20Sopenharmony_ci ldt_arch_exit_mmap(mm); 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_64 1778c2ecf20Sopenharmony_cistatic inline bool is_64bit_mm(struct mm_struct *mm) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci return !IS_ENABLED(CONFIG_IA32_EMULATION) || 1808c2ecf20Sopenharmony_ci !(mm->context.ia32_compat == TIF_IA32); 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci#else 1838c2ecf20Sopenharmony_cistatic inline bool is_64bit_mm(struct mm_struct *mm) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci return false; 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci#endif 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic inline void arch_unmap(struct mm_struct *mm, unsigned long start, 1908c2ecf20Sopenharmony_ci unsigned long end) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci/* 1958c2ecf20Sopenharmony_ci * We only want to enforce protection keys on the current process 1968c2ecf20Sopenharmony_ci * because we effectively have no access to PKRU for other 1978c2ecf20Sopenharmony_ci * processes or any way to tell *which * PKRU in a threaded 1988c2ecf20Sopenharmony_ci * process we could use. 1998c2ecf20Sopenharmony_ci * 2008c2ecf20Sopenharmony_ci * So do not enforce things if the VMA is not from the current 2018c2ecf20Sopenharmony_ci * mm, or if we are in a kernel thread. 2028c2ecf20Sopenharmony_ci */ 2038c2ecf20Sopenharmony_cistatic inline bool arch_vma_access_permitted(struct vm_area_struct *vma, 2048c2ecf20Sopenharmony_ci bool write, bool execute, bool foreign) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci /* pkeys never affect instruction fetches */ 2078c2ecf20Sopenharmony_ci if (execute) 2088c2ecf20Sopenharmony_ci return true; 2098c2ecf20Sopenharmony_ci /* allow access if the VMA is not one from this process */ 2108c2ecf20Sopenharmony_ci if (foreign || vma_is_foreign(vma)) 2118c2ecf20Sopenharmony_ci return true; 2128c2ecf20Sopenharmony_ci return __pkru_allows_pkey(vma_pkey(vma), write); 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ciunsigned long __get_current_cr3_fast(void); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci#endif /* _ASM_X86_MMU_CONTEXT_H */ 218