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