18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci#ifndef _ASM_POWERPC_KUP_8XX_H_
38c2ecf20Sopenharmony_ci#define _ASM_POWERPC_KUP_8XX_H_
48c2ecf20Sopenharmony_ci
58c2ecf20Sopenharmony_ci#include <asm/bug.h>
68c2ecf20Sopenharmony_ci#include <asm/mmu.h>
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_KUAP
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#ifdef __ASSEMBLY__
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci.macro kuap_save_and_lock	sp, thread, gpr1, gpr2, gpr3
138c2ecf20Sopenharmony_ci	lis	\gpr2, MD_APG_KUAP@h	/* only APG0 and APG1 are used */
148c2ecf20Sopenharmony_ci	mfspr	\gpr1, SPRN_MD_AP
158c2ecf20Sopenharmony_ci	mtspr	SPRN_MD_AP, \gpr2
168c2ecf20Sopenharmony_ci	stw	\gpr1, STACK_REGS_KUAP(\sp)
178c2ecf20Sopenharmony_ci.endm
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci.macro kuap_restore	sp, current, gpr1, gpr2, gpr3
208c2ecf20Sopenharmony_ci	lwz	\gpr1, STACK_REGS_KUAP(\sp)
218c2ecf20Sopenharmony_ci	mtspr	SPRN_MD_AP, \gpr1
228c2ecf20Sopenharmony_ci.endm
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci.macro kuap_check	current, gpr
258c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_KUAP_DEBUG
268c2ecf20Sopenharmony_ci	mfspr	\gpr, SPRN_MD_AP
278c2ecf20Sopenharmony_ci	rlwinm	\gpr, \gpr, 16, 0xffff
288c2ecf20Sopenharmony_ci999:	twnei	\gpr, MD_APG_KUAP@h
298c2ecf20Sopenharmony_ci	EMIT_BUG_ENTRY 999b, __FILE__, __LINE__, (BUGFLAG_WARNING | BUGFLAG_ONCE)
308c2ecf20Sopenharmony_ci#endif
318c2ecf20Sopenharmony_ci.endm
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#else /* !__ASSEMBLY__ */
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#include <asm/reg.h>
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic inline void allow_user_access(void __user *to, const void __user *from,
388c2ecf20Sopenharmony_ci				     unsigned long size, unsigned long dir)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	mtspr(SPRN_MD_AP, MD_APG_INIT);
418c2ecf20Sopenharmony_ci}
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistatic inline void prevent_user_access(void __user *to, const void __user *from,
448c2ecf20Sopenharmony_ci				       unsigned long size, unsigned long dir)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	mtspr(SPRN_MD_AP, MD_APG_KUAP);
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistatic inline unsigned long prevent_user_access_return(void)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	unsigned long flags = mfspr(SPRN_MD_AP);
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	mtspr(SPRN_MD_AP, MD_APG_KUAP);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	return flags;
568c2ecf20Sopenharmony_ci}
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistatic inline void restore_user_access(unsigned long flags)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	mtspr(SPRN_MD_AP, flags);
618c2ecf20Sopenharmony_ci}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistatic inline bool
648c2ecf20Sopenharmony_cibad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	return WARN(!((regs->kuap ^ MD_APG_KUAP) & 0xff000000),
678c2ecf20Sopenharmony_ci		    "Bug: fault blocked by AP register !");
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci#endif /* !__ASSEMBLY__ */
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC_KUAP */
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci#endif /* _ASM_POWERPC_KUP_8XX_H_ */
75