• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef _ASM_POWERPC_BOOK3S_64_KUP_RADIX_H
3 #define _ASM_POWERPC_BOOK3S_64_KUP_RADIX_H
4 
5 #include <linux/const.h>
6 
7 #define AMR_KUAP_BLOCK_READ	UL(0x4000000000000000)
8 #define AMR_KUAP_BLOCK_WRITE	UL(0x8000000000000000)
9 #define AMR_KUAP_BLOCKED	(AMR_KUAP_BLOCK_READ | AMR_KUAP_BLOCK_WRITE)
10 #define AMR_KUAP_SHIFT		62
11 
12 #ifdef __ASSEMBLY__
13 
14 #ifdef CONFIG_PPC_KUAP
15 .macro kuap_restore_amr	gpr
16 	BEGIN_MMU_FTR_SECTION_NESTED(67)
17 	ld	\gpr, STACK_REGS_KUAP(r1)
18 	mtspr	SPRN_AMR, \gpr
19 	END_MMU_FTR_SECTION_NESTED_IFSET(MMU_FTR_RADIX_KUAP, 67)
20 .endm
21 
22 .macro kuap_check_amr gpr1, gpr2
23 #ifdef CONFIG_PPC_KUAP_DEBUG
24 	BEGIN_MMU_FTR_SECTION_NESTED(67)
25 	mfspr	\gpr1, SPRN_AMR
26 	li	\gpr2, (AMR_KUAP_BLOCKED >> AMR_KUAP_SHIFT)
27 	sldi	\gpr2, \gpr2, AMR_KUAP_SHIFT
28 999:	tdne	\gpr1, \gpr2
29 	EMIT_BUG_ENTRY 999b, __FILE__, __LINE__, (BUGFLAG_WARNING | BUGFLAG_ONCE)
30 	END_MMU_FTR_SECTION_NESTED_IFSET(MMU_FTR_RADIX_KUAP, 67)
31 #endif
32 .endm
33 #endif
34 
35 .macro kuap_save_amr_and_lock gpr1, gpr2, use_cr, msr_pr_cr
36 #ifdef CONFIG_PPC_KUAP
37 	BEGIN_MMU_FTR_SECTION_NESTED(67)
38 	.ifnb \msr_pr_cr
39 	bne	\msr_pr_cr, 99f
40 	.endif
41 	mfspr	\gpr1, SPRN_AMR
42 	std	\gpr1, STACK_REGS_KUAP(r1)
43 	li	\gpr2, (AMR_KUAP_BLOCKED >> AMR_KUAP_SHIFT)
44 	sldi	\gpr2, \gpr2, AMR_KUAP_SHIFT
45 	cmpd	\use_cr, \gpr1, \gpr2
46 	beq	\use_cr, 99f
47 	// We don't isync here because we very recently entered via rfid
48 	mtspr	SPRN_AMR, \gpr2
49 	isync
50 99:
51 	END_MMU_FTR_SECTION_NESTED_IFSET(MMU_FTR_RADIX_KUAP, 67)
52 #endif
53 .endm
54 
55 #else /* !__ASSEMBLY__ */
56 
57 #include <linux/jump_label.h>
58 
59 DECLARE_STATIC_KEY_FALSE(uaccess_flush_key);
60 
61 #ifdef CONFIG_PPC_KUAP
62 
63 #include <asm/reg.h>
64 
65 /*
66  * We support individually allowing read or write, but we don't support nesting
67  * because that would require an expensive read/modify write of the AMR.
68  */
69 
set_kuap(unsigned long value)70 static inline void set_kuap(unsigned long value)
71 {
72 	if (!early_mmu_has_feature(MMU_FTR_RADIX_KUAP))
73 		return;
74 
75 	/*
76 	 * ISA v3.0B says we need a CSI (Context Synchronising Instruction) both
77 	 * before and after the move to AMR. See table 6 on page 1134.
78 	 */
79 	isync();
80 	mtspr(SPRN_AMR, value);
81 	isync();
82 }
83 
84 static inline bool
bad_kuap_fault(struct pt_regs * regs,unsigned long address,bool is_write)85 bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
86 {
87 	return WARN(mmu_has_feature(MMU_FTR_RADIX_KUAP) &&
88 		    (regs->kuap & (is_write ? AMR_KUAP_BLOCK_WRITE : AMR_KUAP_BLOCK_READ)),
89 		    "Bug: %s fault blocked by AMR!", is_write ? "Write" : "Read");
90 }
91 #else /* CONFIG_PPC_KUAP */
kuap_restore_amr(struct pt_regs * regs,unsigned long amr)92 static inline void kuap_restore_amr(struct pt_regs *regs, unsigned long amr) { }
set_kuap(unsigned long value)93 static inline void set_kuap(unsigned long value) { }
94 #endif /* !CONFIG_PPC_KUAP */
95 
allow_user_access(void __user * to,const void __user * from,unsigned long size,unsigned long dir)96 static __always_inline void allow_user_access(void __user *to, const void __user *from,
97 					      unsigned long size, unsigned long dir)
98 {
99 	// This is written so we can resolve to a single case at build time
100 	BUILD_BUG_ON(!__builtin_constant_p(dir));
101 	if (dir == KUAP_READ)
102 		set_kuap(AMR_KUAP_BLOCK_WRITE);
103 	else if (dir == KUAP_WRITE)
104 		set_kuap(AMR_KUAP_BLOCK_READ);
105 	else
106 		set_kuap(0);
107 }
108 
prevent_user_access(void __user * to,const void __user * from,unsigned long size,unsigned long dir)109 static inline void prevent_user_access(void __user *to, const void __user *from,
110 				       unsigned long size, unsigned long dir)
111 {
112 	set_kuap(AMR_KUAP_BLOCKED);
113 	if (static_branch_unlikely(&uaccess_flush_key))
114 		do_uaccess_flush();
115 }
116 
117 #endif /* __ASSEMBLY__ */
118 
119 #endif /* _ASM_POWERPC_BOOK3S_64_KUP_RADIX_H */
120