xref: /linux/arch/powerpc/include/asm/kup.h (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
169795cabSChristophe Leroy /* SPDX-License-Identifier: GPL-2.0 */
269795cabSChristophe Leroy #ifndef _ASM_POWERPC_KUP_H_
369795cabSChristophe Leroy #define _ASM_POWERPC_KUP_H_
469795cabSChristophe Leroy 
51d8f739bSChristophe Leroy #define KUAP_READ	1
61d8f739bSChristophe Leroy #define KUAP_WRITE	2
71d8f739bSChristophe Leroy #define KUAP_READ_WRITE	(KUAP_READ | KUAP_WRITE)
81d8f739bSChristophe Leroy 
926e04120SChristophe Leroy #ifndef __ASSEMBLY__
1026e04120SChristophe Leroy #include <linux/types.h>
1126e04120SChristophe Leroy 
1226e04120SChristophe Leroy static __always_inline bool kuap_is_disabled(void);
1326e04120SChristophe Leroy #endif
1426e04120SChristophe Leroy 
15178d52c6SMichael Ellerman #ifdef CONFIG_PPC_BOOK3S_64
163b47b754SAneesh Kumar K.V #include <asm/book3s/64/kup.h>
17890274c2SMichael Ellerman #endif
183b47b754SAneesh Kumar K.V 
192679f9bdSChristophe Leroy #ifdef CONFIG_PPC_8xx
202679f9bdSChristophe Leroy #include <asm/nohash/32/kup-8xx.h>
212679f9bdSChristophe Leroy #endif
223b47b754SAneesh Kumar K.V 
23*002b27a5SMichael Ellerman #ifdef CONFIG_BOOKE
2443afcf8fSChristophe Leroy #include <asm/nohash/kup-booke.h>
2543afcf8fSChristophe Leroy #endif
2643afcf8fSChristophe Leroy 
2731ed2b13SChristophe Leroy #ifdef CONFIG_PPC_BOOK3S_32
2831ed2b13SChristophe Leroy #include <asm/book3s/32/kup.h>
2931ed2b13SChristophe Leroy #endif
30890274c2SMichael Ellerman 
31e2fb9f54SChristophe Leroy #ifdef __ASSEMBLY__
32e2fb9f54SChristophe Leroy #ifndef CONFIG_PPC_KUAP
33178d52c6SMichael Ellerman .macro kuap_check_amr	gpr1, gpr2
34178d52c6SMichael Ellerman .endm
35178d52c6SMichael Ellerman 
36e2fb9f54SChristophe Leroy #endif
37e2fb9f54SChristophe Leroy 
38e2fb9f54SChristophe Leroy #else /* !__ASSEMBLY__ */
3969795cabSChristophe Leroy 
4061130e20SAneesh Kumar K.V extern bool disable_kuep;
4161130e20SAneesh Kumar K.V extern bool disable_kuap;
4261130e20SAneesh Kumar K.V 
43ca5999fdSMike Rapoport #include <linux/pgtable.h>
44de78a9c4SChristophe Leroy 
456c1fa60dSChristophe Leroy void setup_kup(void);
460fb1c25aSChristophe Leroy void setup_kuep(bool disabled);
470fb1c25aSChristophe Leroy 
48de78a9c4SChristophe Leroy #ifdef CONFIG_PPC_KUAP
49de78a9c4SChristophe Leroy void setup_kuap(bool disabled);
5026e04120SChristophe Leroy 
kuap_is_disabled(void)5126e04120SChristophe Leroy static __always_inline bool kuap_is_disabled(void)
5226e04120SChristophe Leroy {
5326e04120SChristophe Leroy 	return !mmu_has_feature(MMU_FTR_KUAP);
5426e04120SChristophe Leroy }
55de78a9c4SChristophe Leroy #else
setup_kuap(bool disabled)56de78a9c4SChristophe Leroy static inline void setup_kuap(bool disabled) { }
579a32a7e7SNicholas Piggin 
kuap_is_disabled(void)58c252f384SChristophe Leroy static __always_inline bool kuap_is_disabled(void) { return true; }
59c252f384SChristophe Leroy 
60eb52f66fSChristophe Leroy static __always_inline bool
__bad_kuap_fault(struct pt_regs * regs,unsigned long address,bool is_write)61ba454f9cSChristophe Leroy __bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
629a32a7e7SNicholas Piggin {
639a32a7e7SNicholas Piggin 	return false;
649a32a7e7SNicholas Piggin }
659a32a7e7SNicholas Piggin 
kuap_user_restore(struct pt_regs * regs)66eb52f66fSChristophe Leroy static __always_inline void kuap_user_restore(struct pt_regs *regs) { }
__kuap_kernel_restore(struct pt_regs * regs,unsigned long amr)67eb52f66fSChristophe Leroy static __always_inline void __kuap_kernel_restore(struct pt_regs *regs, unsigned long amr) { }
68ad2d2344SChristophe Leroy 
699a32a7e7SNicholas Piggin /*
709a32a7e7SNicholas Piggin  * book3s/64/kup-radix.h defines these functions for the !KUAP case to flush
719a32a7e7SNicholas Piggin  * the L1D cache after user accesses. Only include the empty stubs for other
729a32a7e7SNicholas Piggin  * platforms.
739a32a7e7SNicholas Piggin  */
74178d52c6SMichael Ellerman #ifndef CONFIG_PPC_BOOK3S_64
allow_user_access(void __user * to,const void __user * from,unsigned long size,unsigned long dir)753a24ea0dSChristophe Leroy static __always_inline void allow_user_access(void __user *to, const void __user *from,
761d8f739bSChristophe Leroy 					      unsigned long size, unsigned long dir) { }
prevent_user_access(unsigned long dir)773a24ea0dSChristophe Leroy static __always_inline void prevent_user_access(unsigned long dir) { }
prevent_user_access_return(void)783a24ea0dSChristophe Leroy static __always_inline unsigned long prevent_user_access_return(void) { return 0UL; }
restore_user_access(unsigned long flags)793a24ea0dSChristophe Leroy static __always_inline void restore_user_access(unsigned long flags) { }
80178d52c6SMichael Ellerman #endif /* CONFIG_PPC_BOOK3S_64 */
81de78a9c4SChristophe Leroy #endif /* CONFIG_PPC_KUAP */
82de78a9c4SChristophe Leroy 
83ba454f9cSChristophe Leroy static __always_inline bool
bad_kuap_fault(struct pt_regs * regs,unsigned long address,bool is_write)84ba454f9cSChristophe Leroy bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
85ba454f9cSChristophe Leroy {
86c252f384SChristophe Leroy 	if (kuap_is_disabled())
87c252f384SChristophe Leroy 		return false;
88c252f384SChristophe Leroy 
89ba454f9cSChristophe Leroy 	return __bad_kuap_fault(regs, address, is_write);
90ba454f9cSChristophe Leroy }
91ba454f9cSChristophe Leroy 
kuap_lock(void)92937fb700SChristophe Leroy static __always_inline void kuap_lock(void)
93937fb700SChristophe Leroy {
941bec4adcSChristophe Leroy #ifdef __kuap_lock
95937fb700SChristophe Leroy 	if (kuap_is_disabled())
96937fb700SChristophe Leroy 		return;
97937fb700SChristophe Leroy 
98937fb700SChristophe Leroy 	__kuap_lock();
991bec4adcSChristophe Leroy #endif
100937fb700SChristophe Leroy }
101937fb700SChristophe Leroy 
kuap_save_and_lock(struct pt_regs * regs)102ba454f9cSChristophe Leroy static __always_inline void kuap_save_and_lock(struct pt_regs *regs)
103ba454f9cSChristophe Leroy {
1041bec4adcSChristophe Leroy #ifdef __kuap_save_and_lock
105c252f384SChristophe Leroy 	if (kuap_is_disabled())
106c252f384SChristophe Leroy 		return;
107c252f384SChristophe Leroy 
108ba454f9cSChristophe Leroy 	__kuap_save_and_lock(regs);
1091bec4adcSChristophe Leroy #endif
110ba454f9cSChristophe Leroy }
111ba454f9cSChristophe Leroy 
kuap_kernel_restore(struct pt_regs * regs,unsigned long amr)112ba454f9cSChristophe Leroy static __always_inline void kuap_kernel_restore(struct pt_regs *regs, unsigned long amr)
113ba454f9cSChristophe Leroy {
114c252f384SChristophe Leroy 	if (kuap_is_disabled())
115c252f384SChristophe Leroy 		return;
116c252f384SChristophe Leroy 
117ba454f9cSChristophe Leroy 	__kuap_kernel_restore(regs, amr);
118ba454f9cSChristophe Leroy }
119ba454f9cSChristophe Leroy 
kuap_get_and_assert_locked(void)120ba454f9cSChristophe Leroy static __always_inline unsigned long kuap_get_and_assert_locked(void)
121ba454f9cSChristophe Leroy {
1221bec4adcSChristophe Leroy #ifdef __kuap_get_and_assert_locked
1231bec4adcSChristophe Leroy 	if (!kuap_is_disabled())
124ba454f9cSChristophe Leroy 		return __kuap_get_and_assert_locked();
1251bec4adcSChristophe Leroy #endif
1261bec4adcSChristophe Leroy 	return 0;
1271bec4adcSChristophe Leroy }
1281bec4adcSChristophe Leroy 
kuap_assert_locked(void)1291bec4adcSChristophe Leroy static __always_inline void kuap_assert_locked(void)
1301bec4adcSChristophe Leroy {
1311bec4adcSChristophe Leroy 	if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG))
1321bec4adcSChristophe Leroy 		kuap_get_and_assert_locked();
133ba454f9cSChristophe Leroy }
134ba454f9cSChristophe Leroy 
allow_read_from_user(const void __user * from,unsigned long size)135240efd71SChristophe Leroy static __always_inline void allow_read_from_user(const void __user *from, unsigned long size)
136de78a9c4SChristophe Leroy {
1378524e2e7SChristophe Leroy 	barrier_nospec();
1381d8f739bSChristophe Leroy 	allow_user_access(NULL, from, size, KUAP_READ);
139de78a9c4SChristophe Leroy }
140de78a9c4SChristophe Leroy 
allow_write_to_user(void __user * to,unsigned long size)141240efd71SChristophe Leroy static __always_inline void allow_write_to_user(void __user *to, unsigned long size)
142de78a9c4SChristophe Leroy {
1431d8f739bSChristophe Leroy 	allow_user_access(to, NULL, size, KUAP_WRITE);
1441d8f739bSChristophe Leroy }
1451d8f739bSChristophe Leroy 
allow_read_write_user(void __user * to,const void __user * from,unsigned long size)146240efd71SChristophe Leroy static __always_inline void allow_read_write_user(void __user *to, const void __user *from,
1471d8f739bSChristophe Leroy 						  unsigned long size)
1481d8f739bSChristophe Leroy {
1498524e2e7SChristophe Leroy 	barrier_nospec();
1501d8f739bSChristophe Leroy 	allow_user_access(to, from, size, KUAP_READ_WRITE);
151de78a9c4SChristophe Leroy }
152de78a9c4SChristophe Leroy 
prevent_read_from_user(const void __user * from,unsigned long size)153240efd71SChristophe Leroy static __always_inline void prevent_read_from_user(const void __user *from, unsigned long size)
154de78a9c4SChristophe Leroy {
155cb2f1fb2SChristophe Leroy 	prevent_user_access(KUAP_READ);
156de78a9c4SChristophe Leroy }
157de78a9c4SChristophe Leroy 
prevent_write_to_user(void __user * to,unsigned long size)158240efd71SChristophe Leroy static __always_inline void prevent_write_to_user(void __user *to, unsigned long size)
159de78a9c4SChristophe Leroy {
160cb2f1fb2SChristophe Leroy 	prevent_user_access(KUAP_WRITE);
1611d8f739bSChristophe Leroy }
1621d8f739bSChristophe Leroy 
prevent_read_write_user(void __user * to,const void __user * from,unsigned long size)163240efd71SChristophe Leroy static __always_inline void prevent_read_write_user(void __user *to, const void __user *from,
1641d8f739bSChristophe Leroy 						    unsigned long size)
1651d8f739bSChristophe Leroy {
166cb2f1fb2SChristophe Leroy 	prevent_user_access(KUAP_READ_WRITE);
167de78a9c4SChristophe Leroy }
168de78a9c4SChristophe Leroy 
prevent_current_access_user(void)169240efd71SChristophe Leroy static __always_inline void prevent_current_access_user(void)
170bedb4dbeSChristophe Leroy {
171cb2f1fb2SChristophe Leroy 	prevent_user_access(KUAP_READ_WRITE);
172bedb4dbeSChristophe Leroy }
173bedb4dbeSChristophe Leroy 
prevent_current_read_from_user(void)174240efd71SChristophe Leroy static __always_inline void prevent_current_read_from_user(void)
1754fe5cda9SChristophe Leroy {
176cb2f1fb2SChristophe Leroy 	prevent_user_access(KUAP_READ);
1774fe5cda9SChristophe Leroy }
1784fe5cda9SChristophe Leroy 
prevent_current_write_to_user(void)179240efd71SChristophe Leroy static __always_inline void prevent_current_write_to_user(void)
1804fe5cda9SChristophe Leroy {
181cb2f1fb2SChristophe Leroy 	prevent_user_access(KUAP_WRITE);
1824fe5cda9SChristophe Leroy }
1834fe5cda9SChristophe Leroy 
18469795cabSChristophe Leroy #endif /* !__ASSEMBLY__ */
18569795cabSChristophe Leroy 
1861d8f739bSChristophe Leroy #endif /* _ASM_POWERPC_KUAP_H_ */
187