12679f9bdSChristophe Leroy /* SPDX-License-Identifier: GPL-2.0 */
22679f9bdSChristophe Leroy #ifndef _ASM_POWERPC_KUP_8XX_H_
32679f9bdSChristophe Leroy #define _ASM_POWERPC_KUP_8XX_H_
42679f9bdSChristophe Leroy
52679f9bdSChristophe Leroy #include <asm/bug.h>
644448640SChristophe Leroy #include <asm/mmu.h>
72679f9bdSChristophe Leroy
82679f9bdSChristophe Leroy #ifdef CONFIG_PPC_KUAP
92679f9bdSChristophe Leroy
10c1672883SChristophe Leroy #ifndef __ASSEMBLY__
112679f9bdSChristophe Leroy
122679f9bdSChristophe Leroy #include <asm/reg.h>
132679f9bdSChristophe Leroy
__kuap_save_and_lock(struct pt_regs * regs)14eb52f66fSChristophe Leroy static __always_inline void __kuap_save_and_lock(struct pt_regs *regs)
150b45359aSChristophe Leroy {
160b45359aSChristophe Leroy regs->kuap = mfspr(SPRN_MD_AP);
170b45359aSChristophe Leroy mtspr(SPRN_MD_AP, MD_APG_KUAP);
180b45359aSChristophe Leroy }
191bec4adcSChristophe Leroy #define __kuap_save_and_lock __kuap_save_and_lock
200b45359aSChristophe Leroy
kuap_user_restore(struct pt_regs * regs)21eb52f66fSChristophe Leroy static __always_inline void kuap_user_restore(struct pt_regs *regs)
220b45359aSChristophe Leroy {
230b45359aSChristophe Leroy }
240b45359aSChristophe Leroy
__kuap_kernel_restore(struct pt_regs * regs,unsigned long kuap)25eb52f66fSChristophe Leroy static __always_inline void __kuap_kernel_restore(struct pt_regs *regs, unsigned long kuap)
260b45359aSChristophe Leroy {
270b45359aSChristophe Leroy mtspr(SPRN_MD_AP, regs->kuap);
280b45359aSChristophe Leroy }
290b45359aSChristophe Leroy
301bec4adcSChristophe Leroy #ifdef CONFIG_PPC_KUAP_DEBUG
__kuap_get_and_assert_locked(void)31eb52f66fSChristophe Leroy static __always_inline unsigned long __kuap_get_and_assert_locked(void)
320b45359aSChristophe Leroy {
33880df2d4SChristophe Leroy WARN_ON_ONCE(mfspr(SPRN_MD_AP) >> 16 != MD_APG_KUAP >> 16);
340b45359aSChristophe Leroy
35880df2d4SChristophe Leroy return 0;
360b45359aSChristophe Leroy }
371bec4adcSChristophe Leroy #define __kuap_get_and_assert_locked __kuap_get_and_assert_locked
381bec4adcSChristophe Leroy #endif
390b45359aSChristophe Leroy
uaccess_begin_8xx(unsigned long val)40*3a24ea0dSChristophe Leroy static __always_inline void uaccess_begin_8xx(unsigned long val)
41*3a24ea0dSChristophe Leroy {
42*3a24ea0dSChristophe Leroy asm(ASM_MMU_FTR_IFSET("mtspr %0, %1", "", %2) : :
43*3a24ea0dSChristophe Leroy "i"(SPRN_MD_AP), "r"(val), "i"(MMU_FTR_KUAP) : "memory");
44*3a24ea0dSChristophe Leroy }
45*3a24ea0dSChristophe Leroy
uaccess_end_8xx(void)46*3a24ea0dSChristophe Leroy static __always_inline void uaccess_end_8xx(void)
47*3a24ea0dSChristophe Leroy {
48*3a24ea0dSChristophe Leroy asm(ASM_MMU_FTR_IFSET("mtspr %0, %1", "", %2) : :
49*3a24ea0dSChristophe Leroy "i"(SPRN_MD_AP), "r"(MD_APG_KUAP), "i"(MMU_FTR_KUAP) : "memory");
50*3a24ea0dSChristophe Leroy }
51*3a24ea0dSChristophe Leroy
allow_user_access(void __user * to,const void __user * from,unsigned long size,unsigned long dir)52*3a24ea0dSChristophe Leroy static __always_inline void allow_user_access(void __user *to, const void __user *from,
531d8f739bSChristophe Leroy unsigned long size, unsigned long dir)
542679f9bdSChristophe Leroy {
55*3a24ea0dSChristophe Leroy uaccess_begin_8xx(MD_APG_INIT);
562679f9bdSChristophe Leroy }
572679f9bdSChristophe Leroy
prevent_user_access(unsigned long dir)58*3a24ea0dSChristophe Leroy static __always_inline void prevent_user_access(unsigned long dir)
592679f9bdSChristophe Leroy {
60*3a24ea0dSChristophe Leroy uaccess_end_8xx();
612679f9bdSChristophe Leroy }
622679f9bdSChristophe Leroy
prevent_user_access_return(void)63*3a24ea0dSChristophe Leroy static __always_inline unsigned long prevent_user_access_return(void)
643d7dfd63SChristophe Leroy {
65f6025a14SChristophe Leroy unsigned long flags;
66f6025a14SChristophe Leroy
67f6025a14SChristophe Leroy flags = mfspr(SPRN_MD_AP);
683d7dfd63SChristophe Leroy
69*3a24ea0dSChristophe Leroy uaccess_end_8xx();
703d7dfd63SChristophe Leroy
713d7dfd63SChristophe Leroy return flags;
723d7dfd63SChristophe Leroy }
733d7dfd63SChristophe Leroy
restore_user_access(unsigned long flags)74*3a24ea0dSChristophe Leroy static __always_inline void restore_user_access(unsigned long flags)
753d7dfd63SChristophe Leroy {
76*3a24ea0dSChristophe Leroy uaccess_begin_8xx(flags);
773d7dfd63SChristophe Leroy }
783d7dfd63SChristophe Leroy
79eb52f66fSChristophe Leroy static __always_inline bool
__bad_kuap_fault(struct pt_regs * regs,unsigned long address,bool is_write)80ba454f9cSChristophe Leroy __bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
812679f9bdSChristophe Leroy {
823dc12dfeSChristophe Leroy return !((regs->kuap ^ MD_APG_KUAP) & 0xff000000);
832679f9bdSChristophe Leroy }
842679f9bdSChristophe Leroy
852679f9bdSChristophe Leroy #endif /* !__ASSEMBLY__ */
862679f9bdSChristophe Leroy
872679f9bdSChristophe Leroy #endif /* CONFIG_PPC_KUAP */
882679f9bdSChristophe Leroy
892679f9bdSChristophe Leroy #endif /* _ASM_POWERPC_KUP_8XX_H_ */
90