162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef _ASM_POWERPC_KUP_8XX_H_
362306a36Sopenharmony_ci#define _ASM_POWERPC_KUP_8XX_H_
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <asm/bug.h>
662306a36Sopenharmony_ci#include <asm/mmu.h>
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#ifdef CONFIG_PPC_KUAP
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#ifndef __ASSEMBLY__
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <asm/reg.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_cistatic __always_inline void __kuap_save_and_lock(struct pt_regs *regs)
1562306a36Sopenharmony_ci{
1662306a36Sopenharmony_ci	regs->kuap = mfspr(SPRN_MD_AP);
1762306a36Sopenharmony_ci	mtspr(SPRN_MD_AP, MD_APG_KUAP);
1862306a36Sopenharmony_ci}
1962306a36Sopenharmony_ci#define __kuap_save_and_lock __kuap_save_and_lock
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistatic __always_inline void kuap_user_restore(struct pt_regs *regs)
2262306a36Sopenharmony_ci{
2362306a36Sopenharmony_ci}
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistatic __always_inline void __kuap_kernel_restore(struct pt_regs *regs, unsigned long kuap)
2662306a36Sopenharmony_ci{
2762306a36Sopenharmony_ci	mtspr(SPRN_MD_AP, regs->kuap);
2862306a36Sopenharmony_ci}
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#ifdef CONFIG_PPC_KUAP_DEBUG
3162306a36Sopenharmony_cistatic __always_inline unsigned long __kuap_get_and_assert_locked(void)
3262306a36Sopenharmony_ci{
3362306a36Sopenharmony_ci	WARN_ON_ONCE(mfspr(SPRN_MD_AP) >> 16 != MD_APG_KUAP >> 16);
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	return 0;
3662306a36Sopenharmony_ci}
3762306a36Sopenharmony_ci#define __kuap_get_and_assert_locked __kuap_get_and_assert_locked
3862306a36Sopenharmony_ci#endif
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistatic __always_inline void uaccess_begin_8xx(unsigned long val)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	asm(ASM_MMU_FTR_IFSET("mtspr %0, %1", "", %2) : :
4362306a36Sopenharmony_ci	    "i"(SPRN_MD_AP), "r"(val), "i"(MMU_FTR_KUAP) : "memory");
4462306a36Sopenharmony_ci}
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistatic __always_inline void uaccess_end_8xx(void)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	asm(ASM_MMU_FTR_IFSET("mtspr %0, %1", "", %2) : :
4962306a36Sopenharmony_ci	    "i"(SPRN_MD_AP), "r"(MD_APG_KUAP), "i"(MMU_FTR_KUAP) : "memory");
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic __always_inline void allow_user_access(void __user *to, const void __user *from,
5362306a36Sopenharmony_ci					      unsigned long size, unsigned long dir)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	uaccess_begin_8xx(MD_APG_INIT);
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic __always_inline void prevent_user_access(unsigned long dir)
5962306a36Sopenharmony_ci{
6062306a36Sopenharmony_ci	uaccess_end_8xx();
6162306a36Sopenharmony_ci}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistatic __always_inline unsigned long prevent_user_access_return(void)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	unsigned long flags;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	flags = mfspr(SPRN_MD_AP);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	uaccess_end_8xx();
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	return flags;
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistatic __always_inline void restore_user_access(unsigned long flags)
7562306a36Sopenharmony_ci{
7662306a36Sopenharmony_ci	uaccess_begin_8xx(flags);
7762306a36Sopenharmony_ci}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistatic __always_inline bool
8062306a36Sopenharmony_ci__bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	return !((regs->kuap ^ MD_APG_KUAP) & 0xff000000);
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci#endif /* !__ASSEMBLY__ */
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci#endif /* CONFIG_PPC_KUAP */
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci#endif /* _ASM_POWERPC_KUP_8XX_H_ */
90