| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: patch.c,v 1.24 2017/10/27 23:22:01 riastradh Exp $ */ | | 1 | /* $NetBSD: patch.c,v 1.25 2018/01/07 11:24:45 maxv Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2007, 2008, 2009 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2007, 2008, 2009 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Andrew Doran. | | 8 | * by Andrew Doran. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
| @@ -24,27 +24,27 @@ | | | @@ -24,27 +24,27 @@ |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | /* | | 32 | /* |
33 | * Patch kernel code at boot time, depending on available CPU features. | | 33 | * Patch kernel code at boot time, depending on available CPU features. |
34 | */ | | 34 | */ |
35 | | | 35 | |
36 | #include <sys/cdefs.h> | | 36 | #include <sys/cdefs.h> |
37 | __KERNEL_RCSID(0, "$NetBSD: patch.c,v 1.24 2017/10/27 23:22:01 riastradh Exp $"); | | 37 | __KERNEL_RCSID(0, "$NetBSD: patch.c,v 1.25 2018/01/07 11:24:45 maxv Exp $"); |
38 | | | 38 | |
39 | #include "opt_lockdebug.h" | | 39 | #include "opt_lockdebug.h" |
40 | #ifdef i386 | | 40 | #ifdef i386 |
41 | #include "opt_spldebug.h" | | 41 | #include "opt_spldebug.h" |
42 | #endif | | 42 | #endif |
43 | | | 43 | |
44 | #include <sys/types.h> | | 44 | #include <sys/types.h> |
45 | #include <sys/systm.h> | | 45 | #include <sys/systm.h> |
46 | | | 46 | |
47 | #include <machine/cpu.h> | | 47 | #include <machine/cpu.h> |
48 | #include <machine/cpufunc.h> | | 48 | #include <machine/cpufunc.h> |
49 | #include <machine/specialreg.h> | | 49 | #include <machine/specialreg.h> |
50 | | | 50 | |
| @@ -120,34 +120,34 @@ patchfunc(void *from_s, void *from_e, vo | | | @@ -120,34 +120,34 @@ patchfunc(void *from_s, void *from_e, vo |
120 | #ifdef GPROF | | 120 | #ifdef GPROF |
121 | #ifdef i386 | | 121 | #ifdef i386 |
122 | #define MCOUNT_CALL_OFFSET 3 | | 122 | #define MCOUNT_CALL_OFFSET 3 |
123 | #endif | | 123 | #endif |
124 | #ifdef __x86_64__ | | 124 | #ifdef __x86_64__ |
125 | #define MCOUNT_CALL_OFFSET 5 | | 125 | #define MCOUNT_CALL_OFFSET 5 |
126 | #endif | | 126 | #endif |
127 | /* Patch mcount call offset */ | | 127 | /* Patch mcount call offset */ |
128 | adjust_jumpoff((uint8_t *)from_s + MCOUNT_CALL_OFFSET, from_s, to_s); | | 128 | adjust_jumpoff((uint8_t *)from_s + MCOUNT_CALL_OFFSET, from_s, to_s); |
129 | #endif | | 129 | #endif |
130 | } | | 130 | } |
131 | | | 131 | |
132 | static inline void __unused | | 132 | static inline void __unused |
133 | patchbytes(void *addr, const int byte1, const int byte2, const int byte3) | | 133 | patchbytes(void *addr, const uint8_t *bytes, size_t size) |
134 | { | | 134 | { |
| | | 135 | uint8_t *ptr = (uint8_t *)addr; |
| | | 136 | size_t i; |
135 | | | 137 | |
136 | ((uint8_t *)addr)[0] = (uint8_t)byte1; | | 138 | for (i = 0; i < size; i++) { |
137 | if (byte2 != -1) | | 139 | ptr[i] = bytes[i]; |
138 | ((uint8_t *)addr)[1] = (uint8_t)byte2; | | 140 | } |
139 | if (byte3 != -1) | | | |
140 | ((uint8_t *)addr)[2] = (uint8_t)byte3; | | | |
141 | } | | 141 | } |
142 | | | 142 | |
143 | void | | 143 | void |
144 | x86_patch(bool early) | | 144 | x86_patch(bool early) |
145 | { | | 145 | { |
146 | static bool first, second; | | 146 | static bool first, second; |
147 | u_long psl; | | 147 | u_long psl; |
148 | u_long cr0; | | 148 | u_long cr0; |
149 | int i; | | 149 | int i; |
150 | | | 150 | |
151 | if (early) { | | 151 | if (early) { |
152 | if (first) | | 152 | if (first) |
153 | return; | | 153 | return; |
| @@ -159,31 +159,35 @@ x86_patch(bool early) | | | @@ -159,31 +159,35 @@ x86_patch(bool early) |
159 | } | | 159 | } |
160 | | | 160 | |
161 | /* Disable interrupts. */ | | 161 | /* Disable interrupts. */ |
162 | psl = x86_read_psl(); | | 162 | psl = x86_read_psl(); |
163 | x86_disable_intr(); | | 163 | x86_disable_intr(); |
164 | | | 164 | |
165 | /* Disable write protection in supervisor mode. */ | | 165 | /* Disable write protection in supervisor mode. */ |
166 | cr0 = rcr0(); | | 166 | cr0 = rcr0(); |
167 | lcr0(cr0 & ~CR0_WP); | | 167 | lcr0(cr0 & ~CR0_WP); |
168 | | | 168 | |
169 | #if !defined(GPROF) | | 169 | #if !defined(GPROF) |
170 | if (!early && ncpu == 1) { | | 170 | if (!early && ncpu == 1) { |
171 | #ifndef LOCKDEBUG | | 171 | #ifndef LOCKDEBUG |
| | | 172 | const uint8_t bytes[] = { |
| | | 173 | X86_NOP |
| | | 174 | }; |
| | | 175 | |
172 | /* Uniprocessor: kill LOCK prefixes. */ | | 176 | /* Uniprocessor: kill LOCK prefixes. */ |
173 | for (i = 0; x86_lockpatch[i] != 0; i++) | | 177 | for (i = 0; x86_lockpatch[i] != 0; i++) |
174 | patchbytes(x86_lockpatch[i], X86_NOP, -1, -1); | | 178 | patchbytes(x86_lockpatch[i], bytes, sizeof(bytes)); |
175 | for (i = 0; atomic_lockpatch[i] != 0; i++) | | 179 | for (i = 0; atomic_lockpatch[i] != 0; i++) |
176 | patchbytes(atomic_lockpatch[i], X86_NOP, -1, -1); | | 180 | patchbytes(atomic_lockpatch[i], bytes, sizeof(bytes)); |
177 | #endif /* !LOCKDEBUG */ | | 181 | #endif /* !LOCKDEBUG */ |
178 | } | | 182 | } |
179 | if (!early && (cpu_feature[0] & CPUID_SSE2) != 0) { | | 183 | if (!early && (cpu_feature[0] & CPUID_SSE2) != 0) { |
180 | /* | | 184 | /* |
181 | * Faster memory barriers. We do not need to patch | | 185 | * Faster memory barriers. We do not need to patch |
182 | * membar_producer to use SFENCE because on x86 | | 186 | * membar_producer to use SFENCE because on x86 |
183 | * ordinary non-temporal stores are always issued in | | 187 | * ordinary non-temporal stores are always issued in |
184 | * program order to main memory and to other CPUs. | | 188 | * program order to main memory and to other CPUs. |
185 | */ | | 189 | */ |
186 | patchfunc( | | 190 | patchfunc( |
187 | sse2_lfence, sse2_lfence_end, | | 191 | sse2_lfence, sse2_lfence_end, |
188 | membar_consumer, membar_consumer_end, | | 192 | membar_consumer, membar_consumer_end, |
189 | NULL | | 193 | NULL |
| @@ -227,50 +231,61 @@ x86_patch(bool early) | | | @@ -227,50 +231,61 @@ x86_patch(bool early) |
227 | #endif /* i386 && !LOCKDEBUG */ | | 231 | #endif /* i386 && !LOCKDEBUG */ |
228 | } | | 232 | } |
229 | #endif /* !SPLDEBUG */ | | 233 | #endif /* !SPLDEBUG */ |
230 | | | 234 | |
231 | /* | | 235 | /* |
232 | * On some Opteron revisions, locked operations erroneously | | 236 | * On some Opteron revisions, locked operations erroneously |
233 | * allow memory references to be `bled' outside of critical | | 237 | * allow memory references to be `bled' outside of critical |
234 | * sections. Apply workaround. | | 238 | * sections. Apply workaround. |
235 | */ | | 239 | */ |
236 | if (cpu_vendor == CPUVENDOR_AMD && | | 240 | if (cpu_vendor == CPUVENDOR_AMD && |
237 | (CPUID_TO_FAMILY(cpu_info_primary.ci_signature) == 0xe || | | 241 | (CPUID_TO_FAMILY(cpu_info_primary.ci_signature) == 0xe || |
238 | (CPUID_TO_FAMILY(cpu_info_primary.ci_signature) == 0xf && | | 242 | (CPUID_TO_FAMILY(cpu_info_primary.ci_signature) == 0xf && |
239 | CPUID_TO_EXTMODEL(cpu_info_primary.ci_signature) < 0x4))) { | | 243 | CPUID_TO_EXTMODEL(cpu_info_primary.ci_signature) < 0x4))) { |
| | | 244 | const uint8_t bytes[] = { |
| | | 245 | 0x0F, 0xAE, 0xE8 /* lfence */ |
| | | 246 | }; |
| | | 247 | |
240 | for (i = 0; x86_retpatch[i] != 0; i++) { | | 248 | for (i = 0; x86_retpatch[i] != 0; i++) { |
241 | /* ret,nop,nop,ret -> lfence,ret */ | | 249 | /* ret,nop,nop,ret -> lfence,ret */ |
242 | patchbytes(x86_retpatch[i], 0x0f, 0xae, 0xe8); | | 250 | patchbytes(x86_retpatch[i], bytes, sizeof(bytes)); |
243 | } | | 251 | } |
244 | } | | 252 | } |
245 | | | 253 | |
246 | #ifdef amd64 | | 254 | #ifdef amd64 |
247 | /* | | 255 | /* |
248 | * If SMAP is present then patch the prepared holes with clac/stac | | 256 | * If SMAP is present then patch the prepared holes with clac/stac |
249 | * instructions. | | 257 | * instructions. |
250 | * | | 258 | * |
251 | * clac = 0x0f, 0x01, 0xca | | 259 | * clac = 0x0f, 0x01, 0xca |
252 | * stac = 0x0f, 0x01, 0xcb | | 260 | * stac = 0x0f, 0x01, 0xcb |
253 | */ | | 261 | */ |
254 | if (!early && cpu_feature[5] & CPUID_SEF_SMAP) { | | 262 | if (!early && cpu_feature[5] & CPUID_SEF_SMAP) { |
255 | KASSERT(rcr4() & CR4_SMAP); | | 263 | KASSERT(rcr4() & CR4_SMAP); |
| | | 264 | const uint8_t clac_bytes[] = { |
| | | 265 | 0x0F, 0x01, 0xCA /* clac */ |
| | | 266 | }; |
| | | 267 | const uint8_t stac_bytes[] = { |
| | | 268 | 0x0F, 0x01, 0xCB /* stac */ |
| | | 269 | }; |
| | | 270 | |
256 | for (i = 0; x86_clacpatch[i] != NULL; i++) { | | 271 | for (i = 0; x86_clacpatch[i] != NULL; i++) { |
257 | /* ret,int3,int3 -> clac */ | | 272 | /* ret,int3,int3 -> clac */ |
258 | patchbytes(x86_clacpatch[i], | | 273 | patchbytes(x86_clacpatch[i], clac_bytes, |
259 | 0x0f, 0x01, 0xca); | | 274 | sizeof(clac_bytes)); |
260 | } | | 275 | } |
261 | for (i = 0; x86_stacpatch[i] != NULL; i++) { | | 276 | for (i = 0; x86_stacpatch[i] != NULL; i++) { |
262 | /* ret,int3,int3 -> stac */ | | 277 | /* ret,int3,int3 -> stac */ |
263 | patchbytes(x86_stacpatch[i], | | 278 | patchbytes(x86_stacpatch[i], stac_bytes, |
264 | 0x0f, 0x01, 0xcb); | | 279 | sizeof(stac_bytes)); |
265 | } | | 280 | } |
266 | } | | 281 | } |
267 | #endif | | 282 | #endif |
268 | | | 283 | |
269 | /* Write back and invalidate cache, flush pipelines. */ | | 284 | /* Write back and invalidate cache, flush pipelines. */ |
270 | wbinvd(); | | 285 | wbinvd(); |
271 | x86_flush(); | | 286 | x86_flush(); |
272 | x86_write_psl(psl); | | 287 | x86_write_psl(psl); |
273 | | | 288 | |
274 | /* Re-enable write protection. */ | | 289 | /* Re-enable write protection. */ |
275 | lcr0(cr0); | | 290 | lcr0(cr0); |
276 | } | | 291 | } |