Commit | Line | Data |
---|---|---|
747ffc2f RK |
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> | |
a9ff6961 | 8 | #include <asm/page.h> |
747ffc2f RK |
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 | ||
7af5b901 | 42 | #if defined(CONFIG_CPU_SW_DOMAIN_PAN) |
de7f60f0 LW |
43 | |
44 | .macro uaccess_disable, tmp, isb=1 | |
747ffc2f RK |
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 | |
747ffc2f RK |
54 | .endm |
55 | ||
56 | .macro uaccess_enable, tmp, isb=1 | |
747ffc2f RK |
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 | |
747ffc2f RK |
66 | .endm |
67 | ||
7af5b901 LW |
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 | ||
de7f60f0 LW |
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 | ||
71f8af11 | 109 | #if defined(CONFIG_CPU_SW_DOMAIN_PAN) || defined(CONFIG_CPU_USE_DOMAINS) |
8ede890b RK |
110 | #define DACR(x...) x |
111 | #else | |
112 | #define DACR(x...) | |
7af5b901 LW |
113 | #endif |
114 | ||
115 | #ifdef CONFIG_CPU_TTBR0_PAN | |
116 | #define PAN(x...) x | |
117 | #else | |
118 | #define PAN(x...) | |
747ffc2f | 119 | #endif |
747ffc2f RK |
120 | |
121 | /* | |
71f8af11 RK |
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. | |
747ffc2f RK |
130 | */ |
131 | .macro uaccess_entry, tsk, tmp0, tmp1, tmp2, disable | |
8ede890b RK |
132 | DACR( mrc p15, 0, \tmp0, c3, c0, 0) |
133 | DACR( str \tmp0, [sp, #SVC_DACR]) | |
7af5b901 LW |
134 | PAN( mrc p15, 0, \tmp0, c2, c0, 2) |
135 | PAN( str \tmp0, [sp, #SVC_TTBCR]) | |
71f8af11 RK |
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 | |
747ffc2f RK |
147 | .endif |
148 | .endm | |
149 | ||
150 | /* Restore the user access state previously saved by uaccess_entry */ | |
151 | .macro uaccess_exit, tsk, tmp0, tmp1 | |
8ede890b | 152 | DACR( ldr \tmp0, [sp, #SVC_DACR]) |
8ede890b | 153 | DACR( mcr p15, 0, \tmp0, c3, c0, 0) |
7af5b901 LW |
154 | PAN( ldr \tmp0, [sp, #SVC_TTBCR]) |
155 | PAN( mcr p15, 0, \tmp0, c2, c0, 2) | |
747ffc2f RK |
156 | .endm |
157 | ||
8ede890b | 158 | #undef DACR |
7af5b901 | 159 | #undef PAN |
8ede890b | 160 | |
747ffc2f | 161 | #endif /* __ASM_UACCESS_ASM_H__ */ |