1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef _ASM_POWERPC_KUP_8XX_H_
3 #define _ASM_POWERPC_KUP_8XX_H_
4 
5 #include <asm/bug.h>
6 #include <asm/mmu.h>
7 
8 #ifdef CONFIG_PPC_KUAP
9 
10 #ifndef __ASSEMBLY__
11 
12 #include <linux/jump_label.h>
13 
14 #include <asm/reg.h>
15 
16 extern struct static_key_false disable_kuap_key;
17 
18 static __always_inline bool kuap_is_disabled(void)
19 {
20 	return static_branch_unlikely(&disable_kuap_key);
21 }
22 
23 static inline void kuap_save_and_lock(struct pt_regs *regs)
24 {
25 	if (kuap_is_disabled())
26 		return;
27 
28 	regs->kuap = mfspr(SPRN_MD_AP);
29 	mtspr(SPRN_MD_AP, MD_APG_KUAP);
30 }
31 
32 static inline void kuap_user_restore(struct pt_regs *regs)
33 {
34 }
35 
36 static inline void kuap_kernel_restore(struct pt_regs *regs, unsigned long kuap)
37 {
38 	if (kuap_is_disabled())
39 		return;
40 
41 	mtspr(SPRN_MD_AP, regs->kuap);
42 }
43 
44 static inline unsigned long kuap_get_and_assert_locked(void)
45 {
46 	unsigned long kuap;
47 
48 	if (kuap_is_disabled())
49 		return MD_APG_INIT;
50 
51 	kuap = mfspr(SPRN_MD_AP);
52 
53 	if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG))
54 		WARN_ON_ONCE(kuap >> 16 != MD_APG_KUAP >> 16);
55 
56 	return kuap;
57 }
58 
59 static inline void kuap_assert_locked(void)
60 {
61 	if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG) && !kuap_is_disabled())
62 		kuap_get_and_assert_locked();
63 }
64 
65 static inline void allow_user_access(void __user *to, const void __user *from,
66 				     unsigned long size, unsigned long dir)
67 {
68 	if (kuap_is_disabled())
69 		return;
70 
71 	mtspr(SPRN_MD_AP, MD_APG_INIT);
72 }
73 
74 static inline void prevent_user_access(unsigned long dir)
75 {
76 	if (kuap_is_disabled())
77 		return;
78 
79 	mtspr(SPRN_MD_AP, MD_APG_KUAP);
80 }
81 
82 static inline unsigned long prevent_user_access_return(void)
83 {
84 	unsigned long flags;
85 
86 	if (kuap_is_disabled())
87 		return MD_APG_INIT;
88 
89 	flags = mfspr(SPRN_MD_AP);
90 
91 	mtspr(SPRN_MD_AP, MD_APG_KUAP);
92 
93 	return flags;
94 }
95 
96 static inline void restore_user_access(unsigned long flags)
97 {
98 	if (kuap_is_disabled())
99 		return;
100 
101 	mtspr(SPRN_MD_AP, flags);
102 }
103 
104 static inline bool
105 bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
106 {
107 	if (kuap_is_disabled())
108 		return false;
109 
110 	return !((regs->kuap ^ MD_APG_KUAP) & 0xff000000);
111 }
112 
113 #endif /* !__ASSEMBLY__ */
114 
115 #endif /* CONFIG_PPC_KUAP */
116 
117 #endif /* _ASM_POWERPC_KUP_8XX_H_ */
118