1 /* SPDX-License-Identifier: GPL-2.0 */ 2 #ifndef _ASM_POWERPC_KUP_BOOKE_H_ 3 #define _ASM_POWERPC_KUP_BOOKE_H_ 4 5 #include <asm/bug.h> 6 7 #ifdef CONFIG_PPC_KUAP 8 9 #ifdef __ASSEMBLY__ 10 11 .macro kuap_check_amr gpr1, gpr2 12 .endm 13 14 #else 15 16 #include <linux/jump_label.h> 17 #include <linux/sched.h> 18 19 #include <asm/reg.h> 20 21 extern struct static_key_false disable_kuap_key; 22 23 static __always_inline bool kuap_is_disabled(void) 24 { 25 return static_branch_unlikely(&disable_kuap_key); 26 } 27 28 static inline void __kuap_lock(void) 29 { 30 mtspr(SPRN_PID, 0); 31 isync(); 32 } 33 34 static inline void __kuap_save_and_lock(struct pt_regs *regs) 35 { 36 regs->kuap = mfspr(SPRN_PID); 37 mtspr(SPRN_PID, 0); 38 isync(); 39 } 40 41 static inline void kuap_user_restore(struct pt_regs *regs) 42 { 43 if (kuap_is_disabled()) 44 return; 45 46 mtspr(SPRN_PID, current->thread.pid); 47 48 /* Context synchronisation is performed by rfi */ 49 } 50 51 static inline void __kuap_kernel_restore(struct pt_regs *regs, unsigned long kuap) 52 { 53 if (regs->kuap) 54 mtspr(SPRN_PID, current->thread.pid); 55 56 /* Context synchronisation is performed by rfi */ 57 } 58 59 static inline unsigned long __kuap_get_and_assert_locked(void) 60 { 61 unsigned long kuap = mfspr(SPRN_PID); 62 63 if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG)) 64 WARN_ON_ONCE(kuap); 65 66 return kuap; 67 } 68 69 static inline void __allow_user_access(void __user *to, const void __user *from, 70 unsigned long size, unsigned long dir) 71 { 72 mtspr(SPRN_PID, current->thread.pid); 73 isync(); 74 } 75 76 static inline void __prevent_user_access(unsigned long dir) 77 { 78 mtspr(SPRN_PID, 0); 79 isync(); 80 } 81 82 static inline unsigned long __prevent_user_access_return(void) 83 { 84 unsigned long flags = mfspr(SPRN_PID); 85 86 mtspr(SPRN_PID, 0); 87 isync(); 88 89 return flags; 90 } 91 92 static inline void __restore_user_access(unsigned long flags) 93 { 94 if (flags) { 95 mtspr(SPRN_PID, current->thread.pid); 96 isync(); 97 } 98 } 99 100 static inline bool 101 __bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write) 102 { 103 return !regs->kuap; 104 } 105 106 #endif /* !__ASSEMBLY__ */ 107 108 #endif /* CONFIG_PPC_KUAP */ 109 110 #endif /* _ASM_POWERPC_KUP_BOOKE_H_ */ 111