xref: /linux/arch/arm/include/asm/uaccess-asm.h (revision 3ff78451b8e446e9a548b98a0d4dd8d24dc5780b)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #ifndef __ASM_UACCESS_ASM_H__
4 #define __ASM_UACCESS_ASM_H__
5 
6 #include <asm/asm-offsets.h>
7 #include <asm/domain.h>
8 #include <asm/page.h>
9 #include <asm/thread_info.h>
10 
11 	.macro	csdb
12 #ifdef CONFIG_THUMB2_KERNEL
13 	.inst.w	0xf3af8014
14 #else
15 	.inst	0xe320f014
16 #endif
17 	.endm
18 
19 	.macro check_uaccess, addr:req, size:req, limit:req, tmp:req, bad:req
20 #ifndef CONFIG_CPU_USE_DOMAINS
21 	adds	\tmp, \addr, #\size - 1
22 	sbcscc	\tmp, \tmp, \limit
23 	bcs	\bad
24 #ifdef CONFIG_CPU_SPECTRE
25 	movcs	\addr, #0
26 	csdb
27 #endif
28 #endif
29 	.endm
30 
31 	.macro uaccess_mask_range_ptr, addr:req, size:req, limit:req, tmp:req
32 #ifdef CONFIG_CPU_SPECTRE
33 	sub	\tmp, \limit, #1
34 	subs	\tmp, \tmp, \addr	@ tmp = limit - 1 - addr
35 	addhs	\tmp, \tmp, #1		@ if (tmp >= 0) {
36 	subshs	\tmp, \tmp, \size	@ tmp = limit - (addr + size) }
37 	movlo	\addr, #0		@ if (tmp < 0) addr = NULL
38 	csdb
39 #endif
40 	.endm
41 
42 #if defined(CONFIG_CPU_SW_DOMAIN_PAN)
43 
44 	.macro	uaccess_disable, tmp, isb=1
45 	/*
46 	 * Whenever we re-enter userspace, the domains should always be
47 	 * set appropriately.
48 	 */
49 	mov	\tmp, #DACR_UACCESS_DISABLE
50 	mcr	p15, 0, \tmp, c3, c0, 0		@ Set domain register
51 	.if	\isb
52 	instr_sync
53 	.endif
54 	.endm
55 
56 	.macro	uaccess_enable, tmp, isb=1
57 	/*
58 	 * Whenever we re-enter userspace, the domains should always be
59 	 * set appropriately.
60 	 */
61 	mov	\tmp, #DACR_UACCESS_ENABLE
62 	mcr	p15, 0, \tmp, c3, c0, 0
63 	.if	\isb
64 	instr_sync
65 	.endif
66 	.endm
67 
68 #elif defined(CONFIG_CPU_TTBR0_PAN)
69 
70 	.macro	uaccess_disable, tmp, isb=1
71 	/*
72 	 * Disable TTBR0 page table walks (EDP0 = 1), use the reserved ASID
73 	 * from TTBR1 (A1 = 1) and enable TTBR1 page table walks for kernel
74 	 * addresses by reducing TTBR0 range to 32MB (T0SZ = 7).
75 	 */
76 	mrc	p15, 0, \tmp, c2, c0, 2		@ read TTBCR
77 	orr	\tmp, \tmp, #TTBCR_EPD0 | TTBCR_T0SZ_MASK
78 	orr	\tmp, \tmp, #TTBCR_A1
79 	mcr	p15, 0, \tmp, c2, c0, 2		@ write TTBCR
80 	.if	\isb
81 	instr_sync
82 	.endif
83 	.endm
84 
85 	.macro	uaccess_enable, tmp, isb=1
86 	/*
87 	 * Enable TTBR0 page table walks (T0SZ = 0, EDP0 = 0) and ASID from
88 	 * TTBR0 (A1 = 0).
89 	 */
90 	mrc	p15, 0, \tmp, c2, c0, 2		@ read TTBCR
91 	bic	\tmp, \tmp, #TTBCR_EPD0 | TTBCR_T0SZ_MASK
92 	bic	\tmp, \tmp, #TTBCR_A1
93 	mcr	p15, 0, \tmp, c2, c0, 2		@ write TTBCR
94 	.if	\isb
95 	instr_sync
96 	.endif
97 	.endm
98 
99 #else
100 
101 	.macro	uaccess_disable, tmp, isb=1
102 	.endm
103 
104 	.macro	uaccess_enable, tmp, isb=1
105 	.endm
106 
107 #endif
108 
109 #if defined(CONFIG_CPU_SW_DOMAIN_PAN) || defined(CONFIG_CPU_USE_DOMAINS)
110 #define DACR(x...)	x
111 #else
112 #define DACR(x...)
113 #endif
114 
115 #ifdef CONFIG_CPU_TTBR0_PAN
116 #define PAN(x...)	x
117 #else
118 #define PAN(x...)
119 #endif
120 
121 	/*
122 	 * Save the address limit on entry to a privileged exception.
123 	 *
124 	 * If we are using the DACR for kernel access by the user accessors
125 	 * (CONFIG_CPU_USE_DOMAINS=y), always reset the DACR kernel domain
126 	 * back to client mode, whether or not \disable is set.
127 	 *
128 	 * If we are using SW PAN, set the DACR user domain to no access
129 	 * if \disable is set.
130 	 */
131 	.macro	uaccess_entry, tsk, tmp0, tmp1, tmp2, disable
132  DACR(	mrc	p15, 0, \tmp0, c3, c0, 0)
133  DACR(	str	\tmp0, [sp, #SVC_DACR])
134  PAN(	mrc	p15, 0, \tmp0, c2, c0, 2)
135  PAN(	str	\tmp0, [sp, #SVC_TTBCR])
136 	.if \disable && IS_ENABLED(CONFIG_CPU_SW_DOMAIN_PAN)
137 	/* kernel=client, user=no access */
138 	mov	\tmp2, #DACR_UACCESS_DISABLE
139 	mcr	p15, 0, \tmp2, c3, c0, 0
140 	instr_sync
141 	.elseif IS_ENABLED(CONFIG_CPU_USE_DOMAINS)
142 	/* kernel=client */
143 	bic	\tmp2, \tmp0, #domain_mask(DOMAIN_KERNEL)
144 	orr	\tmp2, \tmp2, #domain_val(DOMAIN_KERNEL, DOMAIN_CLIENT)
145 	mcr	p15, 0, \tmp2, c3, c0, 0
146 	instr_sync
147 	.endif
148 	.endm
149 
150 	/* Restore the user access state previously saved by uaccess_entry */
151 	.macro	uaccess_exit, tsk, tmp0, tmp1
152  DACR(	ldr	\tmp0, [sp, #SVC_DACR])
153  DACR(	mcr	p15, 0, \tmp0, c3, c0, 0)
154  PAN(	ldr	\tmp0, [sp, #SVC_TTBCR])
155  PAN(	mcr	p15, 0, \tmp0, c2, c0, 2)
156 	.endm
157 
158 #undef DACR
159 #undef PAN
160 
161 #endif /* __ASM_UACCESS_ASM_H__ */
162