xref: /OK3568_Linux_fs/kernel/arch/powerpc/include/asm/pkeys.h (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0+ */
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * PowerPC Memory Protection Keys management
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright 2017, Ram Pai, IBM Corporation.
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #ifndef _ASM_POWERPC_KEYS_H
9*4882a593Smuzhiyun #define _ASM_POWERPC_KEYS_H
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <linux/jump_label.h>
12*4882a593Smuzhiyun #include <asm/firmware.h>
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun extern int num_pkey;
15*4882a593Smuzhiyun extern u32 reserved_allocation_mask; /* bits set for reserved keys */
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #define ARCH_VM_PKEY_FLAGS (VM_PKEY_BIT0 | VM_PKEY_BIT1 | VM_PKEY_BIT2 | \
18*4882a593Smuzhiyun 			    VM_PKEY_BIT3 | VM_PKEY_BIT4)
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun /* Override any generic PKEY permission defines */
21*4882a593Smuzhiyun #define PKEY_DISABLE_EXECUTE   0x4
22*4882a593Smuzhiyun #define PKEY_ACCESS_MASK       (PKEY_DISABLE_ACCESS | \
23*4882a593Smuzhiyun 				PKEY_DISABLE_WRITE  | \
24*4882a593Smuzhiyun 				PKEY_DISABLE_EXECUTE)
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun #ifdef CONFIG_PPC_BOOK3S_64
27*4882a593Smuzhiyun #include <asm/book3s/64/pkeys.h>
28*4882a593Smuzhiyun #else
29*4882a593Smuzhiyun #error "Not supported"
30*4882a593Smuzhiyun #endif
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun 
pkey_to_vmflag_bits(u16 pkey)33*4882a593Smuzhiyun static inline u64 pkey_to_vmflag_bits(u16 pkey)
34*4882a593Smuzhiyun {
35*4882a593Smuzhiyun 	return (((u64)pkey << VM_PKEY_SHIFT) & ARCH_VM_PKEY_FLAGS);
36*4882a593Smuzhiyun }
37*4882a593Smuzhiyun 
vma_pkey(struct vm_area_struct * vma)38*4882a593Smuzhiyun static inline int vma_pkey(struct vm_area_struct *vma)
39*4882a593Smuzhiyun {
40*4882a593Smuzhiyun 	if (!mmu_has_feature(MMU_FTR_PKEY))
41*4882a593Smuzhiyun 		return 0;
42*4882a593Smuzhiyun 	return (vma->vm_flags & ARCH_VM_PKEY_FLAGS) >> VM_PKEY_SHIFT;
43*4882a593Smuzhiyun }
44*4882a593Smuzhiyun 
arch_max_pkey(void)45*4882a593Smuzhiyun static inline int arch_max_pkey(void)
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun 	return num_pkey;
48*4882a593Smuzhiyun }
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun #define pkey_alloc_mask(pkey) (0x1 << pkey)
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun #define mm_pkey_allocation_map(mm) (mm->context.pkey_allocation_map)
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun #define __mm_pkey_allocated(mm, pkey) {	\
55*4882a593Smuzhiyun 	mm_pkey_allocation_map(mm) |= pkey_alloc_mask(pkey); \
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun #define __mm_pkey_free(mm, pkey) {	\
59*4882a593Smuzhiyun 	mm_pkey_allocation_map(mm) &= ~pkey_alloc_mask(pkey);	\
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun #define __mm_pkey_is_allocated(mm, pkey)	\
63*4882a593Smuzhiyun 	(mm_pkey_allocation_map(mm) & pkey_alloc_mask(pkey))
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun #define __mm_pkey_is_reserved(pkey) (reserved_allocation_mask & \
66*4882a593Smuzhiyun 				       pkey_alloc_mask(pkey))
67*4882a593Smuzhiyun 
mm_pkey_is_allocated(struct mm_struct * mm,int pkey)68*4882a593Smuzhiyun static inline bool mm_pkey_is_allocated(struct mm_struct *mm, int pkey)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun 	if (pkey < 0 || pkey >= arch_max_pkey())
71*4882a593Smuzhiyun 		return false;
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 	/* Reserved keys are never allocated. */
74*4882a593Smuzhiyun 	if (__mm_pkey_is_reserved(pkey))
75*4882a593Smuzhiyun 		return false;
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	return __mm_pkey_is_allocated(mm, pkey);
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun /*
81*4882a593Smuzhiyun  * Returns a positive, 5-bit key on success, or -1 on failure.
82*4882a593Smuzhiyun  * Relies on the mmap_lock to protect against concurrency in mm_pkey_alloc() and
83*4882a593Smuzhiyun  * mm_pkey_free().
84*4882a593Smuzhiyun  */
mm_pkey_alloc(struct mm_struct * mm)85*4882a593Smuzhiyun static inline int mm_pkey_alloc(struct mm_struct *mm)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun 	/*
88*4882a593Smuzhiyun 	 * Note: this is the one and only place we make sure that the pkey is
89*4882a593Smuzhiyun 	 * valid as far as the hardware is concerned. The rest of the kernel
90*4882a593Smuzhiyun 	 * trusts that only good, valid pkeys come out of here.
91*4882a593Smuzhiyun 	 */
92*4882a593Smuzhiyun 	u32 all_pkeys_mask = (u32)(~(0x0));
93*4882a593Smuzhiyun 	int ret;
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	if (!mmu_has_feature(MMU_FTR_PKEY))
96*4882a593Smuzhiyun 		return -1;
97*4882a593Smuzhiyun 	/*
98*4882a593Smuzhiyun 	 * Are we out of pkeys? We must handle this specially because ffz()
99*4882a593Smuzhiyun 	 * behavior is undefined if there are no zeros.
100*4882a593Smuzhiyun 	 */
101*4882a593Smuzhiyun 	if (mm_pkey_allocation_map(mm) == all_pkeys_mask)
102*4882a593Smuzhiyun 		return -1;
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 	ret = ffz((u32)mm_pkey_allocation_map(mm));
105*4882a593Smuzhiyun 	__mm_pkey_allocated(mm, ret);
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	return ret;
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun 
mm_pkey_free(struct mm_struct * mm,int pkey)110*4882a593Smuzhiyun static inline int mm_pkey_free(struct mm_struct *mm, int pkey)
111*4882a593Smuzhiyun {
112*4882a593Smuzhiyun 	if (!mmu_has_feature(MMU_FTR_PKEY))
113*4882a593Smuzhiyun 		return -1;
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	if (!mm_pkey_is_allocated(mm, pkey))
116*4882a593Smuzhiyun 		return -EINVAL;
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	__mm_pkey_free(mm, pkey);
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	return 0;
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun /*
124*4882a593Smuzhiyun  * Try to dedicate one of the protection keys to be used as an
125*4882a593Smuzhiyun  * execute-only protection key.
126*4882a593Smuzhiyun  */
127*4882a593Smuzhiyun extern int execute_only_pkey(struct mm_struct *mm);
128*4882a593Smuzhiyun extern int __arch_override_mprotect_pkey(struct vm_area_struct *vma,
129*4882a593Smuzhiyun 					 int prot, int pkey);
arch_override_mprotect_pkey(struct vm_area_struct * vma,int prot,int pkey)130*4882a593Smuzhiyun static inline int arch_override_mprotect_pkey(struct vm_area_struct *vma,
131*4882a593Smuzhiyun 					      int prot, int pkey)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun 	if (!mmu_has_feature(MMU_FTR_PKEY))
134*4882a593Smuzhiyun 		return 0;
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	/*
137*4882a593Smuzhiyun 	 * Is this an mprotect_pkey() call? If so, never override the value that
138*4882a593Smuzhiyun 	 * came from the user.
139*4882a593Smuzhiyun 	 */
140*4882a593Smuzhiyun 	if (pkey != -1)
141*4882a593Smuzhiyun 		return pkey;
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	return __arch_override_mprotect_pkey(vma, prot, pkey);
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun extern int __arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
147*4882a593Smuzhiyun 				       unsigned long init_val);
arch_set_user_pkey_access(struct task_struct * tsk,int pkey,unsigned long init_val)148*4882a593Smuzhiyun static inline int arch_set_user_pkey_access(struct task_struct *tsk, int pkey,
149*4882a593Smuzhiyun 					    unsigned long init_val)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun 	if (!mmu_has_feature(MMU_FTR_PKEY))
152*4882a593Smuzhiyun 		return -EINVAL;
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	/*
155*4882a593Smuzhiyun 	 * userspace should not change pkey-0 permissions.
156*4882a593Smuzhiyun 	 * pkey-0 is associated with every page in the kernel.
157*4882a593Smuzhiyun 	 * If userspace denies any permission on pkey-0, the
158*4882a593Smuzhiyun 	 * kernel cannot operate.
159*4882a593Smuzhiyun 	 */
160*4882a593Smuzhiyun 	if (pkey == 0)
161*4882a593Smuzhiyun 		return init_val ? -EINVAL : 0;
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	return __arch_set_user_pkey_access(tsk, pkey, init_val);
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun 
arch_pkeys_enabled(void)166*4882a593Smuzhiyun static inline bool arch_pkeys_enabled(void)
167*4882a593Smuzhiyun {
168*4882a593Smuzhiyun 	return mmu_has_feature(MMU_FTR_PKEY);
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun extern void pkey_mm_init(struct mm_struct *mm);
172*4882a593Smuzhiyun extern bool arch_supports_pkeys(int cap);
173*4882a593Smuzhiyun extern unsigned int arch_usable_pkeys(void);
174*4882a593Smuzhiyun extern void thread_pkey_regs_save(struct thread_struct *thread);
175*4882a593Smuzhiyun extern void thread_pkey_regs_restore(struct thread_struct *new_thread,
176*4882a593Smuzhiyun 				     struct thread_struct *old_thread);
177*4882a593Smuzhiyun extern void thread_pkey_regs_init(struct thread_struct *thread);
178*4882a593Smuzhiyun #endif /*_ASM_POWERPC_KEYS_H */
179