1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef _ASM_POWERPC_BOOK3S_32_KUP_H
3 #define _ASM_POWERPC_BOOK3S_32_KUP_H
6 #include <asm/book3s/32/mmu-hash.h>
12 #ifdef CONFIG_PPC_KUAP
14 #include <linux/sched.h>
16 #define KUAP_NONE (~0UL)
18 static inline void kuap_lock_one(unsigned long addr)
20 mtsr(mfsr(addr) | SR_KS, addr);
21 isync(); /* Context sync required after mtsr() */
24 static inline void kuap_unlock_one(unsigned long addr)
26 mtsr(mfsr(addr) & ~SR_KS, addr);
27 isync(); /* Context sync required after mtsr() */
30 static inline void __kuap_save_and_lock(struct pt_regs *regs)
32 unsigned long kuap = current->thread.kuap;
35 if (unlikely(kuap == KUAP_NONE))
38 current->thread.kuap = KUAP_NONE;
41 #define __kuap_save_and_lock __kuap_save_and_lock
43 static inline void kuap_user_restore(struct pt_regs *regs)
47 static inline void __kuap_kernel_restore(struct pt_regs *regs, unsigned long kuap)
49 if (unlikely(kuap != KUAP_NONE)) {
50 current->thread.kuap = KUAP_NONE;
54 if (likely(regs->kuap == KUAP_NONE))
57 current->thread.kuap = regs->kuap;
59 kuap_unlock_one(regs->kuap);
62 static inline unsigned long __kuap_get_and_assert_locked(void)
64 unsigned long kuap = current->thread.kuap;
66 WARN_ON_ONCE(IS_ENABLED(CONFIG_PPC_KUAP_DEBUG) && kuap != KUAP_NONE);
70 #define __kuap_get_and_assert_locked __kuap_get_and_assert_locked
72 static __always_inline void __allow_user_access(void __user *to, const void __user *from,
73 u32 size, unsigned long dir)
75 BUILD_BUG_ON(!__builtin_constant_p(dir));
77 if (!(dir & KUAP_WRITE))
80 current->thread.kuap = (__force u32)to;
81 kuap_unlock_one((__force u32)to);
84 static __always_inline void __prevent_user_access(unsigned long dir)
86 u32 kuap = current->thread.kuap;
88 BUILD_BUG_ON(!__builtin_constant_p(dir));
90 if (!(dir & KUAP_WRITE))
93 current->thread.kuap = KUAP_NONE;
97 static inline unsigned long __prevent_user_access_return(void)
99 unsigned long flags = current->thread.kuap;
101 if (flags != KUAP_NONE) {
102 current->thread.kuap = KUAP_NONE;
103 kuap_lock_one(flags);
109 static inline void __restore_user_access(unsigned long flags)
111 if (flags != KUAP_NONE) {
112 current->thread.kuap = flags;
113 kuap_unlock_one(flags);
118 __bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
120 unsigned long kuap = regs->kuap;
124 if (kuap == KUAP_NONE)
128 * If faulting address doesn't match unlocked segment, change segment.
129 * In case of unaligned store crossing two segments, emulate store.
131 if ((kuap ^ address) & 0xf0000000) {
132 if (!(kuap & 0x0fffffff) && address > kuap - 4 && fix_alignment(regs)) {
133 regs_add_return_ip(regs, 4);
134 emulate_single_step(regs);
136 regs->kuap = address;
143 #endif /* CONFIG_PPC_KUAP */
145 #endif /* __ASSEMBLY__ */
147 #endif /* _ASM_POWERPC_BOOK3S_32_KUP_H */