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