143afcf8fSChristophe Leroy /* SPDX-License-Identifier: GPL-2.0 */
243afcf8fSChristophe Leroy #ifndef _ASM_POWERPC_KUP_BOOKE_H_
343afcf8fSChristophe Leroy #define _ASM_POWERPC_KUP_BOOKE_H_
443afcf8fSChristophe Leroy
543afcf8fSChristophe Leroy #include <asm/bug.h>
6*3a24ea0dSChristophe Leroy #include <asm/mmu.h>
743afcf8fSChristophe Leroy
843afcf8fSChristophe Leroy #ifdef CONFIG_PPC_KUAP
943afcf8fSChristophe Leroy
1043afcf8fSChristophe Leroy #ifdef __ASSEMBLY__
1143afcf8fSChristophe Leroy
1243afcf8fSChristophe Leroy .macro kuap_check_amr gpr1, gpr2
1343afcf8fSChristophe Leroy .endm
1443afcf8fSChristophe Leroy
1543afcf8fSChristophe Leroy #else
1643afcf8fSChristophe Leroy
1743afcf8fSChristophe Leroy #include <linux/sched.h>
1843afcf8fSChristophe Leroy
1943afcf8fSChristophe Leroy #include <asm/reg.h>
2043afcf8fSChristophe Leroy
__kuap_lock(void)21eb52f66fSChristophe Leroy static __always_inline void __kuap_lock(void)
2243afcf8fSChristophe Leroy {
2343afcf8fSChristophe Leroy mtspr(SPRN_PID, 0);
2443afcf8fSChristophe Leroy isync();
2543afcf8fSChristophe Leroy }
261bec4adcSChristophe Leroy #define __kuap_lock __kuap_lock
2743afcf8fSChristophe Leroy
__kuap_save_and_lock(struct pt_regs * regs)28eb52f66fSChristophe Leroy static __always_inline void __kuap_save_and_lock(struct pt_regs *regs)
2943afcf8fSChristophe Leroy {
3043afcf8fSChristophe Leroy regs->kuap = mfspr(SPRN_PID);
3143afcf8fSChristophe Leroy mtspr(SPRN_PID, 0);
3243afcf8fSChristophe Leroy isync();
3343afcf8fSChristophe Leroy }
341bec4adcSChristophe Leroy #define __kuap_save_and_lock __kuap_save_and_lock
3543afcf8fSChristophe Leroy
kuap_user_restore(struct pt_regs * regs)36eb52f66fSChristophe Leroy static __always_inline void kuap_user_restore(struct pt_regs *regs)
3743afcf8fSChristophe Leroy {
3843afcf8fSChristophe Leroy if (kuap_is_disabled())
3943afcf8fSChristophe Leroy return;
4043afcf8fSChristophe Leroy
4143afcf8fSChristophe Leroy mtspr(SPRN_PID, current->thread.pid);
4243afcf8fSChristophe Leroy
4343afcf8fSChristophe Leroy /* Context synchronisation is performed by rfi */
4443afcf8fSChristophe Leroy }
4543afcf8fSChristophe Leroy
__kuap_kernel_restore(struct pt_regs * regs,unsigned long kuap)46eb52f66fSChristophe Leroy static __always_inline void __kuap_kernel_restore(struct pt_regs *regs, unsigned long kuap)
4743afcf8fSChristophe Leroy {
4843afcf8fSChristophe Leroy if (regs->kuap)
4943afcf8fSChristophe Leroy mtspr(SPRN_PID, current->thread.pid);
5043afcf8fSChristophe Leroy
5143afcf8fSChristophe Leroy /* Context synchronisation is performed by rfi */
5243afcf8fSChristophe Leroy }
5343afcf8fSChristophe Leroy
541bec4adcSChristophe Leroy #ifdef CONFIG_PPC_KUAP_DEBUG
__kuap_get_and_assert_locked(void)55eb52f66fSChristophe Leroy static __always_inline unsigned long __kuap_get_and_assert_locked(void)
5643afcf8fSChristophe Leroy {
57880df2d4SChristophe Leroy WARN_ON_ONCE(mfspr(SPRN_PID));
5843afcf8fSChristophe Leroy
59880df2d4SChristophe Leroy return 0;
6043afcf8fSChristophe Leroy }
611bec4adcSChristophe Leroy #define __kuap_get_and_assert_locked __kuap_get_and_assert_locked
621bec4adcSChristophe Leroy #endif
6343afcf8fSChristophe Leroy
uaccess_begin_booke(unsigned long val)64*3a24ea0dSChristophe Leroy static __always_inline void uaccess_begin_booke(unsigned long val)
65*3a24ea0dSChristophe Leroy {
66*3a24ea0dSChristophe Leroy asm(ASM_MMU_FTR_IFSET("mtspr %0, %1; isync", "", %2) : :
67*3a24ea0dSChristophe Leroy "i"(SPRN_PID), "r"(val), "i"(MMU_FTR_KUAP) : "memory");
68*3a24ea0dSChristophe Leroy }
69*3a24ea0dSChristophe Leroy
uaccess_end_booke(void)70*3a24ea0dSChristophe Leroy static __always_inline void uaccess_end_booke(void)
71*3a24ea0dSChristophe Leroy {
72*3a24ea0dSChristophe Leroy asm(ASM_MMU_FTR_IFSET("mtspr %0, %1; isync", "", %2) : :
73*3a24ea0dSChristophe Leroy "i"(SPRN_PID), "r"(0), "i"(MMU_FTR_KUAP) : "memory");
74*3a24ea0dSChristophe Leroy }
75*3a24ea0dSChristophe Leroy
allow_user_access(void __user * to,const void __user * from,unsigned long size,unsigned long dir)76*3a24ea0dSChristophe Leroy static __always_inline void allow_user_access(void __user *to, const void __user *from,
7743afcf8fSChristophe Leroy unsigned long size, unsigned long dir)
7843afcf8fSChristophe Leroy {
79*3a24ea0dSChristophe Leroy uaccess_begin_booke(current->thread.pid);
8043afcf8fSChristophe Leroy }
8143afcf8fSChristophe Leroy
prevent_user_access(unsigned long dir)82*3a24ea0dSChristophe Leroy static __always_inline void prevent_user_access(unsigned long dir)
8343afcf8fSChristophe Leroy {
84*3a24ea0dSChristophe Leroy uaccess_end_booke();
8543afcf8fSChristophe Leroy }
8643afcf8fSChristophe Leroy
prevent_user_access_return(void)87*3a24ea0dSChristophe Leroy static __always_inline unsigned long prevent_user_access_return(void)
8843afcf8fSChristophe Leroy {
8943afcf8fSChristophe Leroy unsigned long flags = mfspr(SPRN_PID);
9043afcf8fSChristophe Leroy
91*3a24ea0dSChristophe Leroy uaccess_end_booke();
9243afcf8fSChristophe Leroy
9343afcf8fSChristophe Leroy return flags;
9443afcf8fSChristophe Leroy }
9543afcf8fSChristophe Leroy
restore_user_access(unsigned long flags)96*3a24ea0dSChristophe Leroy static __always_inline void restore_user_access(unsigned long flags)
9743afcf8fSChristophe Leroy {
98*3a24ea0dSChristophe Leroy if (flags)
99*3a24ea0dSChristophe Leroy uaccess_begin_booke(current->thread.pid);
10043afcf8fSChristophe Leroy }
10143afcf8fSChristophe Leroy
102eb52f66fSChristophe Leroy static __always_inline bool
__bad_kuap_fault(struct pt_regs * regs,unsigned long address,bool is_write)10343afcf8fSChristophe Leroy __bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
10443afcf8fSChristophe Leroy {
10543afcf8fSChristophe Leroy return !regs->kuap;
10643afcf8fSChristophe Leroy }
10743afcf8fSChristophe Leroy
10843afcf8fSChristophe Leroy #endif /* !__ASSEMBLY__ */
10943afcf8fSChristophe Leroy
11043afcf8fSChristophe Leroy #endif /* CONFIG_PPC_KUAP */
11143afcf8fSChristophe Leroy
11243afcf8fSChristophe Leroy #endif /* _ASM_POWERPC_KUP_BOOKE_H_ */
113