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
kuap_is_disabled(void)23 static __always_inline bool kuap_is_disabled(void)
24 {
25 return static_branch_unlikely(&disable_kuap_key);
26 }
27
__kuap_lock(void)28 static inline void __kuap_lock(void)
29 {
30 mtspr(SPRN_PID, 0);
31 isync();
32 }
33
__kuap_save_and_lock(struct pt_regs * regs)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
kuap_user_restore(struct pt_regs * regs)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
__kuap_kernel_restore(struct pt_regs * regs,unsigned long kuap)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
__kuap_get_and_assert_locked(void)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
__allow_user_access(void __user * to,const void __user * from,unsigned long size,unsigned long dir)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
__prevent_user_access(unsigned long dir)76 static inline void __prevent_user_access(unsigned long dir)
77 {
78 mtspr(SPRN_PID, 0);
79 isync();
80 }
81
__prevent_user_access_return(void)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
__restore_user_access(unsigned long flags)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
__bad_kuap_fault(struct pt_regs * regs,unsigned long address,bool is_write)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