1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef _ASM_POWERPC_KUP_BOOKE_H_
3 #define _ASM_POWERPC_KUP_BOOKE_H_
4 
5 #include <asm/bug.h>
6 
7 #ifdef CONFIG_PPC_KUAP
8 
9 #ifdef __ASSEMBLY__
10 
11 .macro kuap_check_amr	gpr1, gpr2
12 .endm
13 
14 #else
15 
16 #include <linux/jump_label.h>
17 #include <linux/sched.h>
18 
19 #include <asm/reg.h>
20 
21 extern struct static_key_false disable_kuap_key;
22 
23 static __always_inline bool kuap_is_disabled(void)
24 {
25 	return static_branch_unlikely(&disable_kuap_key);
26 }
27 
28 static inline void __kuap_lock(void)
29 {
30 	mtspr(SPRN_PID, 0);
31 	isync();
32 }
33 
34 static inline void __kuap_save_and_lock(struct pt_regs *regs)
35 {
36 	regs->kuap = mfspr(SPRN_PID);
37 	mtspr(SPRN_PID, 0);
38 	isync();
39 }
40 
41 static inline void kuap_user_restore(struct pt_regs *regs)
42 {
43 	if (kuap_is_disabled())
44 		return;
45 
46 	mtspr(SPRN_PID, current->thread.pid);
47 
48 	/* Context synchronisation is performed by rfi */
49 }
50 
51 static inline void __kuap_kernel_restore(struct pt_regs *regs, unsigned long kuap)
52 {
53 	if (regs->kuap)
54 		mtspr(SPRN_PID, current->thread.pid);
55 
56 	/* Context synchronisation is performed by rfi */
57 }
58 
59 static inline unsigned long __kuap_get_and_assert_locked(void)
60 {
61 	unsigned long kuap = mfspr(SPRN_PID);
62 
63 	if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG))
64 		WARN_ON_ONCE(kuap);
65 
66 	return kuap;
67 }
68 
69 static inline void __allow_user_access(void __user *to, const void __user *from,
70 				       unsigned long size, unsigned long dir)
71 {
72 	mtspr(SPRN_PID, current->thread.pid);
73 	isync();
74 }
75 
76 static inline void __prevent_user_access(unsigned long dir)
77 {
78 	mtspr(SPRN_PID, 0);
79 	isync();
80 }
81 
82 static inline unsigned long __prevent_user_access_return(void)
83 {
84 	unsigned long flags = mfspr(SPRN_PID);
85 
86 	mtspr(SPRN_PID, 0);
87 	isync();
88 
89 	return flags;
90 }
91 
92 static inline void __restore_user_access(unsigned long flags)
93 {
94 	if (flags) {
95 		mtspr(SPRN_PID, current->thread.pid);
96 		isync();
97 	}
98 }
99 
100 static inline bool
101 __bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
102 {
103 	return !regs->kuap;
104 }
105 
106 #endif /* !__ASSEMBLY__ */
107 
108 #endif /* CONFIG_PPC_KUAP */
109 
110 #endif /* _ASM_POWERPC_KUP_BOOKE_H_ */
111