1/* SPDX-License-Identifier: GPL-2.0 */ 2#ifndef _ASM_POWERPC_KUP_H_ 3#define _ASM_POWERPC_KUP_H_ 4 5#define KUAP_READ 1 6#define KUAP_WRITE 2 7#define KUAP_READ_WRITE (KUAP_READ | KUAP_WRITE) 8 9#ifndef __ASSEMBLY__ 10#include <linux/types.h> 11 12static __always_inline bool kuap_is_disabled(void); 13#endif 14 15#ifdef CONFIG_PPC_BOOK3S_64 16#include <asm/book3s/64/kup.h> 17#endif 18 19#ifdef CONFIG_PPC_8xx 20#include <asm/nohash/32/kup-8xx.h> 21#endif 22 23#ifdef CONFIG_BOOKE_OR_40x 24#include <asm/nohash/kup-booke.h> 25#endif 26 27#ifdef CONFIG_PPC_BOOK3S_32 28#include <asm/book3s/32/kup.h> 29#endif 30 31#ifdef __ASSEMBLY__ 32#ifndef CONFIG_PPC_KUAP 33.macro kuap_check_amr gpr1, gpr2 34.endm 35 36#endif 37 38#else /* !__ASSEMBLY__ */ 39 40extern bool disable_kuep; 41extern bool disable_kuap; 42 43#include <linux/pgtable.h> 44 45void setup_kup(void); 46void setup_kuep(bool disabled); 47 48#ifdef CONFIG_PPC_KUAP 49void setup_kuap(bool disabled); 50 51static __always_inline bool kuap_is_disabled(void) 52{ 53 return !mmu_has_feature(MMU_FTR_KUAP); 54} 55#else 56static inline void setup_kuap(bool disabled) { } 57 58static __always_inline bool kuap_is_disabled(void) { return true; } 59 60static __always_inline bool 61__bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write) 62{ 63 return false; 64} 65 66static __always_inline void kuap_user_restore(struct pt_regs *regs) { } 67static __always_inline void __kuap_kernel_restore(struct pt_regs *regs, unsigned long amr) { } 68 69/* 70 * book3s/64/kup-radix.h defines these functions for the !KUAP case to flush 71 * the L1D cache after user accesses. Only include the empty stubs for other 72 * platforms. 73 */ 74#ifndef CONFIG_PPC_BOOK3S_64 75static __always_inline void allow_user_access(void __user *to, const void __user *from, 76 unsigned long size, unsigned long dir) { } 77static __always_inline void prevent_user_access(unsigned long dir) { } 78static __always_inline unsigned long prevent_user_access_return(void) { return 0UL; } 79static __always_inline void restore_user_access(unsigned long flags) { } 80#endif /* CONFIG_PPC_BOOK3S_64 */ 81#endif /* CONFIG_PPC_KUAP */ 82 83static __always_inline bool 84bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write) 85{ 86 if (kuap_is_disabled()) 87 return false; 88 89 return __bad_kuap_fault(regs, address, is_write); 90} 91 92static __always_inline void kuap_lock(void) 93{ 94#ifdef __kuap_lock 95 if (kuap_is_disabled()) 96 return; 97 98 __kuap_lock(); 99#endif 100} 101 102static __always_inline void kuap_save_and_lock(struct pt_regs *regs) 103{ 104#ifdef __kuap_save_and_lock 105 if (kuap_is_disabled()) 106 return; 107 108 __kuap_save_and_lock(regs); 109#endif 110} 111 112static __always_inline void kuap_kernel_restore(struct pt_regs *regs, unsigned long amr) 113{ 114 if (kuap_is_disabled()) 115 return; 116 117 __kuap_kernel_restore(regs, amr); 118} 119 120static __always_inline unsigned long kuap_get_and_assert_locked(void) 121{ 122#ifdef __kuap_get_and_assert_locked 123 if (!kuap_is_disabled()) 124 return __kuap_get_and_assert_locked(); 125#endif 126 return 0; 127} 128 129static __always_inline void kuap_assert_locked(void) 130{ 131 if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG)) 132 kuap_get_and_assert_locked(); 133} 134 135static __always_inline void allow_read_from_user(const void __user *from, unsigned long size) 136{ 137 barrier_nospec(); 138 allow_user_access(NULL, from, size, KUAP_READ); 139} 140 141static __always_inline void allow_write_to_user(void __user *to, unsigned long size) 142{ 143 allow_user_access(to, NULL, size, KUAP_WRITE); 144} 145 146static __always_inline void allow_read_write_user(void __user *to, const void __user *from, 147 unsigned long size) 148{ 149 barrier_nospec(); 150 allow_user_access(to, from, size, KUAP_READ_WRITE); 151} 152 153static __always_inline void prevent_read_from_user(const void __user *from, unsigned long size) 154{ 155 prevent_user_access(KUAP_READ); 156} 157 158static __always_inline void prevent_write_to_user(void __user *to, unsigned long size) 159{ 160 prevent_user_access(KUAP_WRITE); 161} 162 163static __always_inline void prevent_read_write_user(void __user *to, const void __user *from, 164 unsigned long size) 165{ 166 prevent_user_access(KUAP_READ_WRITE); 167} 168 169static __always_inline void prevent_current_access_user(void) 170{ 171 prevent_user_access(KUAP_READ_WRITE); 172} 173 174static __always_inline void prevent_current_read_from_user(void) 175{ 176 prevent_user_access(KUAP_READ); 177} 178 179static __always_inline void prevent_current_write_to_user(void) 180{ 181 prevent_user_access(KUAP_WRITE); 182} 183 184#endif /* !__ASSEMBLY__ */ 185 186#endif /* _ASM_POWERPC_KUAP_H_ */ 187