f6a3c1935e75e8e9fea2ad678db1f8a364e1f677
[linux-2.6-microblaze.git] / arch / powerpc / include / asm / nohash / 32 / kup-8xx.h
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(void __user *to, const void __user *from,
75                                        unsigned long size, unsigned long dir)
76 {
77         if (kuap_is_disabled())
78                 return;
79
80         mtspr(SPRN_MD_AP, MD_APG_KUAP);
81 }
82
83 static inline unsigned long prevent_user_access_return(void)
84 {
85         unsigned long flags;
86
87         if (kuap_is_disabled())
88                 return MD_APG_INIT;
89
90         flags = mfspr(SPRN_MD_AP);
91
92         mtspr(SPRN_MD_AP, MD_APG_KUAP);
93
94         return flags;
95 }
96
97 static inline void restore_user_access(unsigned long flags)
98 {
99         if (kuap_is_disabled())
100                 return;
101
102         mtspr(SPRN_MD_AP, flags);
103 }
104
105 static inline bool
106 bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
107 {
108         if (kuap_is_disabled())
109                 return false;
110
111         return !((regs->kuap ^ MD_APG_KUAP) & 0xff000000);
112 }
113
114 #endif /* !__ASSEMBLY__ */
115
116 #endif /* CONFIG_PPC_KUAP */
117
118 #endif /* _ASM_POWERPC_KUP_8XX_H_ */