]> git.saurik.com Git - apple/xnu.git/blob - osfmk/i386/fpu.c
0ac53d48c30e63f6e7e0e8cf80a044cc92f3730e
[apple/xnu.git] / osfmk / i386 / fpu.c
1 /*
2 * Copyright (c) 2000-2018 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * @OSF_COPYRIGHT@
30 */
31 /*
32 * Mach Operating System
33 * Copyright (c) 1992-1990 Carnegie Mellon University
34 * All Rights Reserved.
35 *
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
41 *
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
45 *
46 * Carnegie Mellon requests users of this software to return to
47 *
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
52 *
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
56
57 #include <mach/exception_types.h>
58 #include <mach/i386/thread_status.h>
59 #include <mach/i386/fp_reg.h>
60
61 #include <kern/mach_param.h>
62 #include <kern/processor.h>
63 #include <kern/thread.h>
64 #include <kern/zalloc.h>
65 #include <kern/misc_protos.h>
66 #include <kern/spl.h>
67 #include <kern/assert.h>
68
69 #include <libkern/OSAtomic.h>
70
71 #include <architecture/i386/pio.h>
72 #include <i386/cpuid.h>
73 #include <i386/fpu.h>
74 #include <i386/proc_reg.h>
75 #include <i386/misc_protos.h>
76 #include <i386/thread.h>
77 #include <i386/trap.h>
78
79 xstate_t fpu_capability = UNDEFINED; /* extended state capability */
80 xstate_t fpu_default = UNDEFINED; /* default extended state */
81
82 #define ALIGNED(addr, size) (((uintptr_t)(addr)&((size)-1))==0)
83
84 /* Forward */
85
86 extern void fpinit(void);
87 extern void fp_save(
88 thread_t thr_act);
89 extern void fp_load(
90 thread_t thr_act);
91
92 static void configure_mxcsr_capability_mask(x86_ext_thread_state_t *fps);
93 static xstate_t thread_xstate(thread_t);
94
95 x86_ext_thread_state_t initial_fp_state __attribute((aligned(64)));
96 x86_ext_thread_state_t default_avx512_state __attribute((aligned(64)));
97 x86_ext_thread_state_t default_avx_state __attribute((aligned(64)));
98 x86_ext_thread_state_t default_fx_state __attribute((aligned(64)));
99
100 /* Global MXCSR capability bitmask */
101 static unsigned int mxcsr_capability_mask;
102
103 #define fninit() \
104 __asm__ volatile("fninit")
105
106 #define fnstcw(control) \
107 __asm__("fnstcw %0" : "=m" (*(unsigned short *)(control)))
108
109 #define fldcw(control) \
110 __asm__ volatile("fldcw %0" : : "m" (*(unsigned short *) &(control)) )
111
112 #define fnclex() \
113 __asm__ volatile("fnclex")
114
115 #define fnsave(state) \
116 __asm__ volatile("fnsave %0" : "=m" (*state))
117
118 #define frstor(state) \
119 __asm__ volatile("frstor %0" : : "m" (state))
120
121 #define fwait() \
122 __asm__("fwait");
123
124 static inline void
125 fxrstor(struct x86_fx_thread_state *a)
126 {
127 __asm__ __volatile__ ("fxrstor %0" :: "m" (*a));
128 }
129
130 static inline void
131 fxsave(struct x86_fx_thread_state *a)
132 {
133 __asm__ __volatile__ ("fxsave %0" : "=m" (*a));
134 }
135
136 static inline void
137 fxrstor64(struct x86_fx_thread_state *a)
138 {
139 __asm__ __volatile__ ("fxrstor64 %0" :: "m" (*a));
140 }
141
142 static inline void
143 fxsave64(struct x86_fx_thread_state *a)
144 {
145 __asm__ __volatile__ ("fxsave64 %0" : "=m" (*a));
146 }
147
148 #if !defined(RC_HIDE_XNU_J137)
149 #define IS_VALID_XSTATE(x) ((x) == FP || (x) == AVX || (x) == AVX512)
150 #else
151 #define IS_VALID_XSTATE(x) ((x) == FP || (x) == AVX)
152 #endif
153
154 zone_t ifps_zone[] = {
155 [FP] = NULL,
156 [AVX] = NULL,
157 #if !defined(RC_HIDE_XNU_J137)
158 [AVX512] = NULL
159 #endif
160 };
161 static uint32_t fp_state_size[] = {
162 [FP] = sizeof(struct x86_fx_thread_state),
163 [AVX] = sizeof(struct x86_avx_thread_state),
164 #if !defined(RC_HIDE_XNU_J137)
165 [AVX512] = sizeof(struct x86_avx512_thread_state)
166 #endif
167 };
168
169 static const char *xstate_name[] = {
170 [UNDEFINED] = "UNDEFINED",
171 [FP] = "FP",
172 [AVX] = "AVX",
173 #if !defined(RC_HIDE_XNU_J137)
174 [AVX512] = "AVX512"
175 #endif
176 };
177
178 #if !defined(RC_HIDE_XNU_J137)
179 #define fpu_ZMM_capable (fpu_capability == AVX512)
180 #define fpu_YMM_capable (fpu_capability == AVX || fpu_capability == AVX512)
181 /*
182 * On-demand AVX512 support
183 * ------------------------
184 * On machines with AVX512 support, by default, threads are created with
185 * AVX512 masked off in XCR0 and an AVX-sized savearea is used. However, AVX512
186 * capabilities are advertised in the commpage and via sysctl. If a thread
187 * opts to use AVX512 instructions, the first will result in a #UD exception.
188 * Faulting AVX512 intructions are recognizable by their unique prefix.
189 * This exception results in the thread being promoted to use an AVX512-sized
190 * savearea and for the AVX512 bit masks being set in its XCR0. The faulting
191 * instruction is re-driven and the thread can proceed to perform AVX512
192 * operations.
193 *
194 * In addition to AVX512 instructions causing promotion, the thread_set_state()
195 * primitive with an AVX512 state flavor result in promotion.
196 *
197 * AVX512 promotion of the first thread in a task causes the default xstate
198 * of the task to be promoted so that any subsequently created or subsequently
199 * DNA-faulted thread will have AVX512 xstate and it will not need to fault-in
200 * a promoted xstate.
201 *
202 * Two savearea zones are used: the default pool of AVX-sized (832 byte) areas
203 * and a second pool of larger AVX512-sized (2688 byte) areas.
204 *
205 * Note the initial state value is an AVX512 object but that the AVX initial
206 * value is a subset of it.
207 */
208 #else
209 #define fpu_YMM_capable (fpu_capability == AVX)
210 #endif
211 static uint32_t cpuid_reevaluated = 0;
212
213 static void fpu_store_registers(void *, boolean_t);
214 static void fpu_load_registers(void *);
215
216 #if !defined(RC_HIDE_XNU_J137)
217 static const uint32_t xstate_xmask[] = {
218 [FP] = FP_XMASK,
219 [AVX] = AVX_XMASK,
220 [AVX512] = AVX512_XMASK
221 };
222 #else
223 static const uint32_t xstate_xmask[] = {
224 [FP] = FP_XMASK,
225 [AVX] = AVX_XMASK,
226 };
227 #endif
228
229 static inline void
230 xsave(struct x86_fx_thread_state *a, uint32_t rfbm)
231 {
232 __asm__ __volatile__ ("xsave %0" :"=m" (*a) : "a"(rfbm), "d"(0));
233 }
234
235 static inline void
236 xsave64(struct x86_fx_thread_state *a, uint32_t rfbm)
237 {
238 __asm__ __volatile__ ("xsave64 %0" :"=m" (*a) : "a"(rfbm), "d"(0));
239 }
240
241 static inline void
242 xrstor(struct x86_fx_thread_state *a, uint32_t rfbm)
243 {
244 __asm__ __volatile__ ("xrstor %0" :: "m" (*a), "a"(rfbm), "d"(0));
245 }
246
247 static inline void
248 xrstor64(struct x86_fx_thread_state *a, uint32_t rfbm)
249 {
250 __asm__ __volatile__ ("xrstor64 %0" :: "m" (*a), "a"(rfbm), "d"(0));
251 }
252
253 #if !defined(RC_HIDE_XNU_J137)
254 __unused static inline void
255 vzeroupper(void)
256 {
257 __asm__ __volatile__ ("vzeroupper" ::);
258 }
259
260 static boolean_t fpu_thread_promote_avx512(thread_t); /* Forward */
261
262 /*
263 * Define a wrapper for bcopy to defeat destination size checka.
264 * This is needed to treat repeated objects such as
265 * _STRUCT_XMM_REG fpu_ymmh0;
266 * ...
267 * _STRUCT_XMM_REG fpu_ymmh7;
268 * as an array and to copy like so:
269 * bcopy_nockch(src,&dst->fpu_ymmh0,8*sizeof(_STRUCT_XMM_REG));
270 * without the compiler throwing a __builtin__memmove_chk error.
271 */
272 static inline void
273 bcopy_nochk(void *_src, void *_dst, size_t _len)
274 {
275 bcopy(_src, _dst, _len);
276 }
277
278 /*
279 * Furthermore, make compile-time asserts that no padding creeps into structures
280 * for which we're doing this.
281 */
282 #define ASSERT_PACKED(t, m1, m2, n, mt) \
283 extern char assert_packed_ ## t ## _ ## m1 ## _ ## m2 \
284 [(offsetof(t,m2) - offsetof(t,m1) == (n - 1)*sizeof(mt)) ? 1 : -1]
285
286 ASSERT_PACKED(x86_avx_state32_t, fpu_ymmh0, fpu_ymmh7, 8, _STRUCT_XMM_REG);
287
288 ASSERT_PACKED(x86_avx_state64_t, fpu_ymmh0, fpu_ymmh15, 16, _STRUCT_XMM_REG);
289
290 ASSERT_PACKED(x86_avx512_state32_t, fpu_k0, fpu_k7, 8, _STRUCT_OPMASK_REG);
291 ASSERT_PACKED(x86_avx512_state32_t, fpu_ymmh0, fpu_ymmh7, 8, _STRUCT_XMM_REG);
292 ASSERT_PACKED(x86_avx512_state32_t, fpu_zmmh0, fpu_zmmh7, 8, _STRUCT_YMM_REG);
293
294 ASSERT_PACKED(x86_avx512_state64_t, fpu_k0, fpu_k7, 8, _STRUCT_OPMASK_REG);
295 ASSERT_PACKED(x86_avx512_state64_t, fpu_ymmh0, fpu_ymmh15, 16, _STRUCT_XMM_REG);
296 ASSERT_PACKED(x86_avx512_state64_t, fpu_zmmh0, fpu_zmmh15, 16, _STRUCT_YMM_REG);
297 ASSERT_PACKED(x86_avx512_state64_t, fpu_zmm16, fpu_zmm31, 16, _STRUCT_ZMM_REG);
298
299 #if defined(DEBUG_AVX512)
300
301 #define DBG(x...) kprintf("DBG: " x)
302
303 typedef struct { uint8_t byte[8]; } opmask_t;
304 typedef struct { uint8_t byte[16]; } xmm_t;
305 typedef struct { uint8_t byte[32]; } ymm_t;
306 typedef struct { uint8_t byte[64]; } zmm_t;
307
308 static void
309 DBG_AVX512_STATE(struct x86_avx512_thread_state *sp)
310 {
311 int i, j;
312 xmm_t *xmm = (xmm_t *) &sp->fp.fx_XMM_reg;
313 xmm_t *ymmh = (xmm_t *) &sp->x_YMM_Hi128;
314 ymm_t *zmmh = (ymm_t *) &sp->x_ZMM_Hi256;
315 zmm_t *zmm = (zmm_t *) &sp->x_Hi16_ZMM;
316 opmask_t *k = (opmask_t *) &sp->x_Opmask;
317
318 kprintf("x_YMM_Hi128: %lu\n", offsetof(struct x86_avx512_thread_state, x_YMM_Hi128));
319 kprintf("x_Opmask: %lu\n", offsetof(struct x86_avx512_thread_state, x_Opmask));
320 kprintf("x_ZMM_Hi256: %lu\n", offsetof(struct x86_avx512_thread_state, x_ZMM_Hi256));
321 kprintf("x_Hi16_ZMM: %lu\n", offsetof(struct x86_avx512_thread_state, x_Hi16_ZMM));
322
323 kprintf("XCR0: 0x%016llx\n", xgetbv(XCR0));
324 kprintf("XINUSE: 0x%016llx\n", xgetbv(1));
325
326 /* Print all ZMM registers */
327 for (i = 0; i < 16; i++) {
328 kprintf("zmm%d:\t0x", i);
329 for (j = 0; j < 16; j++) {
330 kprintf("%02x", xmm[i].byte[j]);
331 }
332 for (j = 0; j < 16; j++) {
333 kprintf("%02x", ymmh[i].byte[j]);
334 }
335 for (j = 0; j < 32; j++) {
336 kprintf("%02x", zmmh[i].byte[j]);
337 }
338 kprintf("\n");
339 }
340 for (i = 0; i < 16; i++) {
341 kprintf("zmm%d:\t0x", 16 + i);
342 for (j = 0; j < 64; j++) {
343 kprintf("%02x", zmm[i].byte[j]);
344 }
345 kprintf("\n");
346 }
347 for (i = 0; i < 8; i++) {
348 kprintf("k%d:\t0x", i);
349 for (j = 0; j < 8; j++) {
350 kprintf("%02x", k[i].byte[j]);
351 }
352 kprintf("\n");
353 }
354
355 kprintf("xstate_bv: 0x%016llx\n", sp->_xh.xstate_bv);
356 kprintf("xcomp_bv: 0x%016llx\n", sp->_xh.xcomp_bv);
357 }
358 #else
359 #define DBG(x...)
360 static void
361 DBG_AVX512_STATE(__unused struct x86_avx512_thread_state *sp)
362 {
363 return;
364 }
365 #endif /* DEBUG_AVX512 */
366
367 #endif
368
369 #if DEBUG
370 static inline unsigned short
371 fnstsw(void)
372 {
373 unsigned short status;
374 __asm__ volatile ("fnstsw %0" : "=ma" (status));
375 return status;
376 }
377 #endif
378
379 /*
380 * Configure the initial FPU state presented to new threads.
381 * Determine the MXCSR capability mask, which allows us to mask off any
382 * potentially unsafe "reserved" bits before restoring the FPU context.
383 * *Not* per-cpu, assumes symmetry.
384 */
385
386 static void
387 configure_mxcsr_capability_mask(x86_ext_thread_state_t *fps)
388 {
389 /* XSAVE requires a 64 byte aligned store */
390 assert(ALIGNED(fps, 64));
391 /* Clear, to prepare for the diagnostic FXSAVE */
392 bzero(fps, sizeof(*fps));
393
394 fpinit();
395 fpu_store_registers(fps, FALSE);
396
397 mxcsr_capability_mask = fps->fx.fx_MXCSR_MASK;
398
399 /* Set default mask value if necessary */
400 if (mxcsr_capability_mask == 0) {
401 mxcsr_capability_mask = 0xffbf;
402 }
403
404 /* Clear vector register store */
405 bzero(&fps->fx.fx_XMM_reg[0][0], sizeof(fps->fx.fx_XMM_reg));
406 bzero(fps->avx.x_YMM_Hi128, sizeof(fps->avx.x_YMM_Hi128));
407 #if !defined(RC_HIDE_XNU_J137)
408 if (fpu_ZMM_capable) {
409 bzero(fps->avx512.x_ZMM_Hi256, sizeof(fps->avx512.x_ZMM_Hi256));
410 bzero(fps->avx512.x_Hi16_ZMM, sizeof(fps->avx512.x_Hi16_ZMM));
411 bzero(fps->avx512.x_Opmask, sizeof(fps->avx512.x_Opmask));
412 }
413 #endif
414
415 fps->fx.fp_valid = TRUE;
416 fps->fx.fp_save_layout = fpu_YMM_capable ? XSAVE32: FXSAVE32;
417 fpu_load_registers(fps);
418
419 if (fpu_ZMM_capable) {
420 xsave64((struct x86_fx_thread_state *)&default_avx512_state, xstate_xmask[AVX512]);
421 }
422 if (fpu_YMM_capable) {
423 xsave64((struct x86_fx_thread_state *)&default_avx_state, xstate_xmask[AVX]);
424 } else {
425 fxsave64((struct x86_fx_thread_state *)&default_fx_state);
426 }
427
428 /* Poison values to trap unsafe usage */
429 fps->fx.fp_valid = 0xFFFFFFFF;
430 fps->fx.fp_save_layout = FP_UNUSED;
431
432 /* Re-enable FPU/SSE DNA exceptions */
433 set_ts();
434 }
435
436 int fpsimd_fault_popc = 0;
437 /*
438 * Look for FPU and initialize it.
439 * Called on each CPU.
440 */
441 void
442 init_fpu(void)
443 {
444 #if DEBUG
445 unsigned short status;
446 unsigned short control;
447 #endif
448 /*
449 * Check for FPU by initializing it,
450 * then trying to read the correct bit patterns from
451 * the control and status registers.
452 */
453 set_cr0((get_cr0() & ~(CR0_EM | CR0_TS)) | CR0_NE); /* allow use of FPU */
454 fninit();
455 #if DEBUG
456 status = fnstsw();
457 fnstcw(&control);
458
459 assert(((status & 0xff) == 0) && ((control & 0x103f) == 0x3f));
460 #endif
461 /* Advertise SSE support */
462 if (cpuid_features() & CPUID_FEATURE_FXSR) {
463 set_cr4(get_cr4() | CR4_OSFXS);
464 /* And allow SIMD exceptions if present */
465 if (cpuid_features() & CPUID_FEATURE_SSE) {
466 set_cr4(get_cr4() | CR4_OSXMM);
467 }
468 } else {
469 panic("fpu is not FP_FXSR");
470 }
471
472 fpu_capability = fpu_default = FP;
473
474 PE_parse_boot_argn("fpsimd_fault_popc", &fpsimd_fault_popc, sizeof(fpsimd_fault_popc));
475
476 #if !defined(RC_HIDE_XNU_J137)
477 static boolean_t is_avx512_enabled = TRUE;
478 if (cpu_number() == master_cpu) {
479 if (cpuid_leaf7_features() & CPUID_LEAF7_FEATURE_AVX512F) {
480 PE_parse_boot_argn("avx512", &is_avx512_enabled, sizeof(boolean_t));
481 kprintf("AVX512 supported %s\n",
482 is_avx512_enabled ? "and enabled" : "but disabled");
483 }
484 }
485 #endif
486
487 /* Configure the XSAVE context mechanism if the processor supports
488 * AVX/YMM registers
489 */
490 if (cpuid_features() & CPUID_FEATURE_XSAVE) {
491 cpuid_xsave_leaf_t *xs0p = &cpuid_info()->cpuid_xsave_leaf[0];
492 #if !defined(RC_HIDE_XNU_J137)
493 if (is_avx512_enabled &&
494 (xs0p->extended_state[eax] & XFEM_ZMM) == XFEM_ZMM) {
495 assert(xs0p->extended_state[eax] & XFEM_SSE);
496 assert(xs0p->extended_state[eax] & XFEM_YMM);
497 fpu_capability = AVX512;
498 /* XSAVE container size for all features */
499 set_cr4(get_cr4() | CR4_OSXSAVE);
500 xsetbv(0, AVX512_XMASK);
501 /* Re-evaluate CPUID, once, to reflect OSXSAVE */
502 if (OSCompareAndSwap(0, 1, &cpuid_reevaluated)) {
503 cpuid_set_info();
504 }
505 /* Verify that now selected state can be accommodated */
506 assert(xs0p->extended_state[ebx] == fp_state_size[AVX512]);
507 /*
508 * AVX set until AVX512 is used.
509 * See comment above about on-demand AVX512 support.
510 */
511 xsetbv(0, AVX_XMASK);
512 fpu_default = AVX;
513 } else
514 #endif
515 if (xs0p->extended_state[eax] & XFEM_YMM) {
516 assert(xs0p->extended_state[eax] & XFEM_SSE);
517 fpu_capability = AVX;
518 fpu_default = AVX;
519 /* XSAVE container size for all features */
520 set_cr4(get_cr4() | CR4_OSXSAVE);
521 xsetbv(0, AVX_XMASK);
522 /* Re-evaluate CPUID, once, to reflect OSXSAVE */
523 if (OSCompareAndSwap(0, 1, &cpuid_reevaluated)) {
524 cpuid_set_info();
525 }
526 /* Verify that now selected state can be accommodated */
527 assert(xs0p->extended_state[ebx] == fp_state_size[AVX]);
528 }
529 }
530
531 if (cpu_number() == master_cpu) {
532 kprintf("fpu_state: %s, state_size: %d\n",
533 xstate_name[fpu_capability],
534 fp_state_size[fpu_capability]);
535 }
536
537 fpinit();
538 current_cpu_datap()->cpu_xstate = fpu_default;
539
540 /*
541 * Trap wait instructions. Turn off FPU for now.
542 */
543 set_cr0(get_cr0() | CR0_TS | CR0_MP);
544 }
545
546 /*
547 * Allocate and initialize FP state for specified xstate.
548 * Don't load state.
549 */
550 static void *
551 fp_state_alloc(xstate_t xs)
552 {
553 struct x86_fx_thread_state *ifps;
554
555 assert(ifps_zone[xs] != NULL);
556 ifps = zalloc(ifps_zone[xs]);
557
558 #if DEBUG
559 if (!(ALIGNED(ifps, 64))) {
560 panic("fp_state_alloc: %p, %u, %p, %u",
561 ifps, (unsigned) ifps_zone[xs]->elem_size,
562 (void *) ifps_zone[xs]->free_elements,
563 (unsigned) ifps_zone[xs]->alloc_size);
564 }
565 #endif
566 bzero(ifps, fp_state_size[xs]);
567
568 return ifps;
569 }
570
571 static inline void
572 fp_state_free(void *ifps, xstate_t xs)
573 {
574 assert(ifps_zone[xs] != NULL);
575 zfree(ifps_zone[xs], ifps);
576 }
577
578 void
579 clear_fpu(void)
580 {
581 set_ts();
582 }
583
584
585 static void
586 fpu_load_registers(void *fstate)
587 {
588 struct x86_fx_thread_state *ifps = fstate;
589 fp_save_layout_t layout = ifps->fp_save_layout;
590
591 assert(current_task() == NULL || \
592 (thread_is_64bit_addr(current_thread()) ? \
593 (layout == FXSAVE64 || layout == XSAVE64) : \
594 (layout == FXSAVE32 || layout == XSAVE32)));
595 assert(ALIGNED(ifps, 64));
596 assert(ml_get_interrupts_enabled() == FALSE);
597
598 #if DEBUG
599 if (layout == XSAVE32 || layout == XSAVE64) {
600 struct x86_avx_thread_state *iavx = fstate;
601 unsigned i;
602 /* Verify reserved bits in the XSAVE header*/
603 if (iavx->_xh.xstate_bv & ~xstate_xmask[current_xstate()]) {
604 panic("iavx->_xh.xstate_bv: 0x%llx", iavx->_xh.xstate_bv);
605 }
606 for (i = 0; i < sizeof(iavx->_xh.xhrsvd); i++) {
607 if (iavx->_xh.xhrsvd[i]) {
608 panic("Reserved bit set");
609 }
610 }
611 }
612 if (fpu_YMM_capable) {
613 if (layout != XSAVE32 && layout != XSAVE64) {
614 panic("Inappropriate layout: %u\n", layout);
615 }
616 }
617 #endif /* DEBUG */
618
619 switch (layout) {
620 case FXSAVE64:
621 fxrstor64(ifps);
622 break;
623 case FXSAVE32:
624 fxrstor(ifps);
625 break;
626 case XSAVE64:
627 xrstor64(ifps, xstate_xmask[current_xstate()]);
628 break;
629 case XSAVE32:
630 xrstor(ifps, xstate_xmask[current_xstate()]);
631 break;
632 default:
633 panic("fpu_load_registers() bad layout: %d\n", layout);
634 }
635 }
636
637 static void
638 fpu_store_registers(void *fstate, boolean_t is64)
639 {
640 struct x86_fx_thread_state *ifps = fstate;
641 assert(ALIGNED(ifps, 64));
642 xstate_t xs = current_xstate();
643 switch (xs) {
644 case FP:
645 if (is64) {
646 fxsave64(fstate);
647 ifps->fp_save_layout = FXSAVE64;
648 } else {
649 fxsave(fstate);
650 ifps->fp_save_layout = FXSAVE32;
651 }
652 break;
653 case AVX:
654 #if !defined(RC_HIDE_XNU_J137)
655 case AVX512:
656 #endif
657 if (is64) {
658 xsave64(ifps, xstate_xmask[xs]);
659 ifps->fp_save_layout = XSAVE64;
660 } else {
661 xsave(ifps, xstate_xmask[xs]);
662 ifps->fp_save_layout = XSAVE32;
663 }
664 break;
665 default:
666 panic("fpu_store_registers() bad xstate: %d\n", xs);
667 }
668 }
669
670 /*
671 * Initialize FP handling.
672 */
673
674 void
675 fpu_module_init(void)
676 {
677 if (!IS_VALID_XSTATE(fpu_default)) {
678 panic("fpu_module_init: invalid extended state %u\n",
679 fpu_default);
680 }
681
682 /* We explicitly choose an allocation size of 13 pages = 64 * 832
683 * to eliminate waste for the 832 byte sized
684 * AVX XSAVE register save area.
685 */
686 ifps_zone[fpu_default] = zinit(fp_state_size[fpu_default],
687 thread_max * fp_state_size[fpu_default],
688 64 * fp_state_size[fpu_default],
689 "x86 fpsave state");
690
691 /* To maintain the required alignment, disable
692 * zone debugging for this zone as that appends
693 * 16 bytes to each element.
694 */
695 zone_change(ifps_zone[fpu_default], Z_ALIGNMENT_REQUIRED, TRUE);
696
697 #if !defined(RC_HIDE_XNU_J137)
698 /*
699 * If AVX512 is supported, create a separate savearea zone.
700 * with allocation size: 19 pages = 32 * 2668
701 */
702 if (fpu_capability == AVX512) {
703 ifps_zone[AVX512] = zinit(fp_state_size[AVX512],
704 thread_max * fp_state_size[AVX512],
705 32 * fp_state_size[AVX512],
706 "x86 avx512 save state");
707 zone_change(ifps_zone[AVX512], Z_ALIGNMENT_REQUIRED, TRUE);
708 }
709 #endif
710
711 /* Determine MXCSR reserved bits and configure initial FPU state*/
712 configure_mxcsr_capability_mask(&initial_fp_state);
713 }
714
715 /*
716 * Context switch fpu state.
717 * Always save old thread`s FPU context but don't load new .. allow that to fault-in.
718 * Switch to the new task's xstate.
719 */
720
721 void
722 fpu_switch_context(thread_t old, thread_t new)
723 {
724 struct x86_fx_thread_state *ifps;
725 cpu_data_t *cdp = current_cpu_datap();
726 xstate_t new_xstate = new ? thread_xstate(new) : fpu_default;
727
728 assert(ml_get_interrupts_enabled() == FALSE);
729 ifps = (old)->machine.ifps;
730 #if DEBUG
731 if (ifps && ((ifps->fp_valid != FALSE) && (ifps->fp_valid != TRUE))) {
732 panic("ifps->fp_valid: %u\n", ifps->fp_valid);
733 }
734 #endif
735 if (ifps != 0 && (ifps->fp_valid == FALSE)) {
736 /* Clear CR0.TS in preparation for the FP context save. In
737 * theory, this shouldn't be necessary since a live FPU should
738 * indicate that TS is clear. However, various routines
739 * (such as sendsig & sigreturn) manipulate TS directly.
740 */
741 clear_ts();
742 /* registers are in FPU - save to memory */
743 boolean_t is64 = (thread_is_64bit_addr(old) &&
744 is_saved_state64(old->machine.iss));
745
746 fpu_store_registers(ifps, is64);
747 ifps->fp_valid = TRUE;
748
749 if (fpu_ZMM_capable && (cdp->cpu_xstate == AVX512)) {
750 xrstor64((struct x86_fx_thread_state *)&default_avx512_state, xstate_xmask[AVX512]);
751 } else if (fpu_YMM_capable) {
752 xrstor64((struct x86_fx_thread_state *) &default_avx_state, xstate_xmask[AVX]);
753 } else {
754 fxrstor64((struct x86_fx_thread_state *)&default_fx_state);
755 }
756 }
757
758 assertf(fpu_YMM_capable ? (xgetbv(XCR0) == xstate_xmask[cdp->cpu_xstate]) : TRUE, "XCR0 mismatch: 0x%llx 0x%x 0x%x", xgetbv(XCR0), cdp->cpu_xstate, xstate_xmask[cdp->cpu_xstate]);
759 if (new_xstate != (xstate_t) cdp->cpu_xstate) {
760 DBG("fpu_switch_context(%p,%p) new xstate: %s\n",
761 old, new, xstate_name[new_xstate]);
762 xsetbv(0, xstate_xmask[new_xstate]);
763 cdp->cpu_xstate = new_xstate;
764 }
765 set_ts();
766 }
767
768
769 /*
770 * Free a FPU save area.
771 * Called only when thread terminating - no locking necessary.
772 */
773 void
774 fpu_free(thread_t thread, void *fps)
775 {
776 pcb_t pcb = THREAD_TO_PCB(thread);
777
778 fp_state_free(fps, pcb->xstate);
779 pcb->xstate = UNDEFINED;
780 }
781
782 /*
783 * Set the floating-point state for a thread based
784 * on the FXSave formatted data. This is basically
785 * the same as fpu_set_state except it uses the
786 * expanded data structure.
787 * If the thread is not the current thread, it is
788 * not running (held). Locking needed against
789 * concurrent fpu_set_state or fpu_get_state.
790 */
791 kern_return_t
792 fpu_set_fxstate(
793 thread_t thr_act,
794 thread_state_t tstate,
795 thread_flavor_t f)
796 {
797 struct x86_fx_thread_state *ifps;
798 struct x86_fx_thread_state *new_ifps;
799 x86_float_state64_t *state;
800 pcb_t pcb;
801 boolean_t old_valid, fresh_state = FALSE;
802
803 if (fpu_capability == UNDEFINED) {
804 return KERN_FAILURE;
805 }
806
807 if ((f == x86_AVX_STATE32 || f == x86_AVX_STATE64) &&
808 fpu_capability < AVX) {
809 return KERN_FAILURE;
810 }
811
812 #if !defined(RC_HIDE_XNU_J137)
813 if ((f == x86_AVX512_STATE32 || f == x86_AVX512_STATE64) &&
814 thread_xstate(thr_act) == AVX) {
815 if (!fpu_thread_promote_avx512(thr_act)) {
816 return KERN_FAILURE;
817 }
818 }
819 #endif
820
821 state = (x86_float_state64_t *)tstate;
822
823 assert(thr_act != THREAD_NULL);
824 pcb = THREAD_TO_PCB(thr_act);
825
826 if (state == NULL) {
827 /*
828 * new FPU state is 'invalid'.
829 * Deallocate the fp state if it exists.
830 */
831 simple_lock(&pcb->lock, LCK_GRP_NULL);
832
833 ifps = pcb->ifps;
834 pcb->ifps = 0;
835
836 simple_unlock(&pcb->lock);
837
838 if (ifps != 0) {
839 fp_state_free(ifps, thread_xstate(thr_act));
840 }
841 } else {
842 /*
843 * Valid incoming state. Allocate the fp state if there is none.
844 */
845 new_ifps = 0;
846 Retry:
847 simple_lock(&pcb->lock, LCK_GRP_NULL);
848
849 ifps = pcb->ifps;
850 if (ifps == 0) {
851 if (new_ifps == 0) {
852 simple_unlock(&pcb->lock);
853 new_ifps = fp_state_alloc(thread_xstate(thr_act));
854 goto Retry;
855 }
856 ifps = new_ifps;
857 new_ifps = 0;
858 pcb->ifps = ifps;
859 pcb->xstate = thread_xstate(thr_act);
860 fresh_state = TRUE;
861 }
862
863 /*
864 * now copy over the new data.
865 */
866
867 old_valid = ifps->fp_valid;
868
869 #if DEBUG || DEVELOPMENT
870 if ((fresh_state == FALSE) && (old_valid == FALSE) && (thr_act != current_thread())) {
871 panic("fpu_set_fxstate inconsistency, thread: %p not stopped", thr_act);
872 }
873 #endif
874 /*
875 * Clear any reserved bits in the MXCSR to prevent a GPF
876 * when issuing an FXRSTOR.
877 */
878
879 state->fpu_mxcsr &= mxcsr_capability_mask;
880
881 bcopy((char *)&state->fpu_fcw, (char *)ifps, fp_state_size[FP]);
882
883 switch (thread_xstate(thr_act)) {
884 case UNDEFINED_FULL:
885 case FP_FULL:
886 case AVX_FULL:
887 case AVX512_FULL:
888 panic("fpu_set_fxstate() INVALID xstate: 0x%x", thread_xstate(thr_act));
889 break;
890
891 case UNDEFINED:
892 panic("fpu_set_fxstate() UNDEFINED xstate");
893 break;
894 case FP:
895 ifps->fp_save_layout = thread_is_64bit_addr(thr_act) ? FXSAVE64 : FXSAVE32;
896 break;
897 case AVX: {
898 struct x86_avx_thread_state *iavx = (void *) ifps;
899 x86_avx_state64_t *xs = (x86_avx_state64_t *) state;
900
901 iavx->fp.fp_save_layout = thread_is_64bit_addr(thr_act) ? XSAVE64 : XSAVE32;
902
903 /* Sanitize XSAVE header */
904 bzero(&iavx->_xh.xhrsvd[0], sizeof(iavx->_xh.xhrsvd));
905 iavx->_xh.xstate_bv = AVX_XMASK;
906 iavx->_xh.xcomp_bv = 0;
907
908 if (f == x86_AVX_STATE32) {
909 bcopy_nochk(&xs->fpu_ymmh0, iavx->x_YMM_Hi128, 8 * sizeof(_STRUCT_XMM_REG));
910 } else if (f == x86_AVX_STATE64) {
911 bcopy_nochk(&xs->fpu_ymmh0, iavx->x_YMM_Hi128, 16 * sizeof(_STRUCT_XMM_REG));
912 } else {
913 iavx->_xh.xstate_bv = (XFEM_SSE | XFEM_X87);
914 }
915 break;
916 }
917 #if !defined(RC_HIDE_XNU_J137)
918 case AVX512: {
919 struct x86_avx512_thread_state *iavx = (void *) ifps;
920 union {
921 thread_state_t ts;
922 x86_avx512_state32_t *s32;
923 x86_avx512_state64_t *s64;
924 } xs = { .ts = tstate };
925
926 iavx->fp.fp_save_layout = thread_is_64bit_addr(thr_act) ? XSAVE64 : XSAVE32;
927
928 /* Sanitize XSAVE header */
929 bzero(&iavx->_xh.xhrsvd[0], sizeof(iavx->_xh.xhrsvd));
930 iavx->_xh.xstate_bv = AVX512_XMASK;
931 iavx->_xh.xcomp_bv = 0;
932
933 switch (f) {
934 case x86_AVX512_STATE32:
935 bcopy_nochk(&xs.s32->fpu_k0, iavx->x_Opmask, 8 * sizeof(_STRUCT_OPMASK_REG));
936 bcopy_nochk(&xs.s32->fpu_zmmh0, iavx->x_ZMM_Hi256, 8 * sizeof(_STRUCT_YMM_REG));
937 bcopy_nochk(&xs.s32->fpu_ymmh0, iavx->x_YMM_Hi128, 8 * sizeof(_STRUCT_XMM_REG));
938 DBG_AVX512_STATE(iavx);
939 break;
940 case x86_AVX_STATE32:
941 bcopy_nochk(&xs.s32->fpu_ymmh0, iavx->x_YMM_Hi128, 8 * sizeof(_STRUCT_XMM_REG));
942 break;
943 case x86_AVX512_STATE64:
944 bcopy_nochk(&xs.s64->fpu_k0, iavx->x_Opmask, 8 * sizeof(_STRUCT_OPMASK_REG));
945 bcopy_nochk(&xs.s64->fpu_zmm16, iavx->x_Hi16_ZMM, 16 * sizeof(_STRUCT_ZMM_REG));
946 bcopy_nochk(&xs.s64->fpu_zmmh0, iavx->x_ZMM_Hi256, 16 * sizeof(_STRUCT_YMM_REG));
947 bcopy_nochk(&xs.s64->fpu_ymmh0, iavx->x_YMM_Hi128, 16 * sizeof(_STRUCT_XMM_REG));
948 DBG_AVX512_STATE(iavx);
949 break;
950 case x86_AVX_STATE64:
951 bcopy_nochk(&xs.s64->fpu_ymmh0, iavx->x_YMM_Hi128, 16 * sizeof(_STRUCT_XMM_REG));
952 break;
953 }
954 break;
955 }
956 #endif
957 }
958
959 ifps->fp_valid = old_valid;
960
961 if (old_valid == FALSE) {
962 boolean_t istate = ml_set_interrupts_enabled(FALSE);
963 ifps->fp_valid = TRUE;
964 /* If altering the current thread's state, disable FPU */
965 if (thr_act == current_thread()) {
966 set_ts();
967 }
968
969 ml_set_interrupts_enabled(istate);
970 }
971
972 simple_unlock(&pcb->lock);
973
974 if (new_ifps != 0) {
975 fp_state_free(new_ifps, thread_xstate(thr_act));
976 }
977 }
978 return KERN_SUCCESS;
979 }
980
981 /*
982 * Get the floating-point state for a thread.
983 * If the thread is not the current thread, it is
984 * not running (held). Locking needed against
985 * concurrent fpu_set_state or fpu_get_state.
986 */
987 kern_return_t
988 fpu_get_fxstate(
989 thread_t thr_act,
990 thread_state_t tstate,
991 thread_flavor_t f)
992 {
993 struct x86_fx_thread_state *ifps;
994 x86_float_state64_t *state;
995 kern_return_t ret = KERN_FAILURE;
996 pcb_t pcb;
997
998 if (fpu_capability == UNDEFINED) {
999 return KERN_FAILURE;
1000 }
1001
1002 if ((f == x86_AVX_STATE32 || f == x86_AVX_STATE64) &&
1003 fpu_capability < AVX) {
1004 return KERN_FAILURE;
1005 }
1006
1007 #if !defined(RC_HIDE_XNU_J137)
1008 if ((f == x86_AVX512_STATE32 || f == x86_AVX512_STATE64) &&
1009 thread_xstate(thr_act) != AVX512) {
1010 return KERN_FAILURE;
1011 }
1012 #endif
1013
1014 state = (x86_float_state64_t *)tstate;
1015
1016 assert(thr_act != THREAD_NULL);
1017 pcb = THREAD_TO_PCB(thr_act);
1018
1019 simple_lock(&pcb->lock, LCK_GRP_NULL);
1020
1021 ifps = pcb->ifps;
1022 if (ifps == 0) {
1023 /*
1024 * No valid floating-point state.
1025 */
1026
1027 bcopy((char *)&initial_fp_state, (char *)&state->fpu_fcw,
1028 fp_state_size[FP]);
1029
1030 simple_unlock(&pcb->lock);
1031
1032 return KERN_SUCCESS;
1033 }
1034 /*
1035 * Make sure we`ve got the latest fp state info
1036 * If the live fpu state belongs to our target
1037 */
1038 if (thr_act == current_thread()) {
1039 boolean_t intr;
1040
1041 intr = ml_set_interrupts_enabled(FALSE);
1042
1043 clear_ts();
1044 fp_save(thr_act);
1045 clear_fpu();
1046
1047 (void)ml_set_interrupts_enabled(intr);
1048 }
1049 if (ifps->fp_valid) {
1050 bcopy((char *)ifps, (char *)&state->fpu_fcw, fp_state_size[FP]);
1051 switch (thread_xstate(thr_act)) {
1052 case UNDEFINED_FULL:
1053 case FP_FULL:
1054 case AVX_FULL:
1055 case AVX512_FULL:
1056 panic("fpu_get_fxstate() INVALID xstate: 0x%x", thread_xstate(thr_act));
1057 break;
1058
1059 case UNDEFINED:
1060 panic("fpu_get_fxstate() UNDEFINED xstate");
1061 break;
1062 case FP:
1063 break; /* already done */
1064 case AVX: {
1065 struct x86_avx_thread_state *iavx = (void *) ifps;
1066 x86_avx_state64_t *xs = (x86_avx_state64_t *) state;
1067 if (f == x86_AVX_STATE32) {
1068 bcopy_nochk(iavx->x_YMM_Hi128, &xs->fpu_ymmh0, 8 * sizeof(_STRUCT_XMM_REG));
1069 } else if (f == x86_AVX_STATE64) {
1070 bcopy_nochk(iavx->x_YMM_Hi128, &xs->fpu_ymmh0, 16 * sizeof(_STRUCT_XMM_REG));
1071 }
1072 break;
1073 }
1074 #if !defined(RC_HIDE_XNU_J137)
1075 case AVX512: {
1076 struct x86_avx512_thread_state *iavx = (void *) ifps;
1077 union {
1078 thread_state_t ts;
1079 x86_avx512_state32_t *s32;
1080 x86_avx512_state64_t *s64;
1081 } xs = { .ts = tstate };
1082 switch (f) {
1083 case x86_AVX512_STATE32:
1084 bcopy_nochk(iavx->x_Opmask, &xs.s32->fpu_k0, 8 * sizeof(_STRUCT_OPMASK_REG));
1085 bcopy_nochk(iavx->x_ZMM_Hi256, &xs.s32->fpu_zmmh0, 8 * sizeof(_STRUCT_YMM_REG));
1086 bcopy_nochk(iavx->x_YMM_Hi128, &xs.s32->fpu_ymmh0, 8 * sizeof(_STRUCT_XMM_REG));
1087 DBG_AVX512_STATE(iavx);
1088 break;
1089 case x86_AVX_STATE32:
1090 bcopy_nochk(iavx->x_YMM_Hi128, &xs.s32->fpu_ymmh0, 8 * sizeof(_STRUCT_XMM_REG));
1091 break;
1092 case x86_AVX512_STATE64:
1093 bcopy_nochk(iavx->x_Opmask, &xs.s64->fpu_k0, 8 * sizeof(_STRUCT_OPMASK_REG));
1094 bcopy_nochk(iavx->x_Hi16_ZMM, &xs.s64->fpu_zmm16, 16 * sizeof(_STRUCT_ZMM_REG));
1095 bcopy_nochk(iavx->x_ZMM_Hi256, &xs.s64->fpu_zmmh0, 16 * sizeof(_STRUCT_YMM_REG));
1096 bcopy_nochk(iavx->x_YMM_Hi128, &xs.s64->fpu_ymmh0, 16 * sizeof(_STRUCT_XMM_REG));
1097 DBG_AVX512_STATE(iavx);
1098 break;
1099 case x86_AVX_STATE64:
1100 bcopy_nochk(iavx->x_YMM_Hi128, &xs.s64->fpu_ymmh0, 16 * sizeof(_STRUCT_XMM_REG));
1101 break;
1102 }
1103 break;
1104 }
1105 #endif
1106 }
1107
1108 ret = KERN_SUCCESS;
1109 }
1110 simple_unlock(&pcb->lock);
1111
1112 return ret;
1113 }
1114
1115
1116
1117 /*
1118 * the child thread is 'stopped' with the thread
1119 * mutex held and is currently not known by anyone
1120 * so no way for fpu state to get manipulated by an
1121 * outside agency -> no need for pcb lock
1122 */
1123
1124 void
1125 fpu_dup_fxstate(
1126 thread_t parent,
1127 thread_t child)
1128 {
1129 struct x86_fx_thread_state *new_ifps = NULL;
1130 boolean_t intr;
1131 pcb_t ppcb;
1132 xstate_t xstate = thread_xstate(parent);
1133
1134 ppcb = THREAD_TO_PCB(parent);
1135
1136 if (ppcb->ifps == NULL) {
1137 return;
1138 }
1139
1140 if (child->machine.ifps) {
1141 panic("fpu_dup_fxstate: child's ifps non-null");
1142 }
1143
1144 new_ifps = fp_state_alloc(xstate);
1145
1146 simple_lock(&ppcb->lock, LCK_GRP_NULL);
1147
1148 if (ppcb->ifps != NULL) {
1149 struct x86_fx_thread_state *ifps = ppcb->ifps;
1150 /*
1151 * Make sure we`ve got the latest fp state info
1152 */
1153 if (current_thread() == parent) {
1154 intr = ml_set_interrupts_enabled(FALSE);
1155 assert(current_thread() == parent);
1156 clear_ts();
1157 fp_save(parent);
1158 clear_fpu();
1159
1160 (void)ml_set_interrupts_enabled(intr);
1161 }
1162
1163 if (ifps->fp_valid) {
1164 child->machine.ifps = new_ifps;
1165 child->machine.xstate = xstate;
1166 bcopy((char *)(ppcb->ifps),
1167 (char *)(child->machine.ifps),
1168 fp_state_size[xstate]);
1169
1170 /* Mark the new fp saved state as non-live. */
1171 /* Temporarily disabled: radar 4647827
1172 * new_ifps->fp_valid = TRUE;
1173 */
1174
1175 /*
1176 * Clear any reserved bits in the MXCSR to prevent a GPF
1177 * when issuing an FXRSTOR.
1178 */
1179 new_ifps->fx_MXCSR &= mxcsr_capability_mask;
1180 new_ifps = NULL;
1181 }
1182 }
1183 simple_unlock(&ppcb->lock);
1184
1185 if (new_ifps != NULL) {
1186 fp_state_free(new_ifps, xstate);
1187 }
1188 }
1189
1190 /*
1191 * Initialize FPU.
1192 * FNINIT programs the x87 control word to 0x37f, which matches
1193 * the desired default for macOS.
1194 */
1195
1196 void
1197 fpinit(void)
1198 {
1199 boolean_t istate = ml_set_interrupts_enabled(FALSE);
1200 clear_ts();
1201 fninit();
1202 #if DEBUG
1203 /* We skip this power-on-default verification sequence on
1204 * non-DEBUG, as dirtying the x87 control word may slow down
1205 * xsave/xrstor and affect energy use.
1206 */
1207 unsigned short control, control2;
1208 fnstcw(&control);
1209 control2 = control;
1210 control &= ~(FPC_PC | FPC_RC); /* Clear precision & rounding control */
1211 control |= (FPC_PC_64 | /* Set precision */
1212 FPC_RC_RN | /* round-to-nearest */
1213 FPC_ZE | /* Suppress zero-divide */
1214 FPC_OE | /* and overflow */
1215 FPC_UE | /* underflow */
1216 FPC_IE | /* Allow NaNQs and +-INF */
1217 FPC_DE | /* Allow denorms as operands */
1218 FPC_PE); /* No trap for precision loss */
1219 assert(control == control2);
1220 fldcw(control);
1221 #endif
1222 /* Initialize SSE/SSE2 */
1223 __builtin_ia32_ldmxcsr(0x1f80);
1224 if (fpu_YMM_capable) {
1225 vzeroall();
1226 } else {
1227 xmmzeroall();
1228 }
1229 ml_set_interrupts_enabled(istate);
1230 }
1231
1232 /*
1233 * Coprocessor not present.
1234 */
1235
1236 uint64_t x86_isr_fp_simd_use;
1237
1238 void
1239 fpnoextflt(void)
1240 {
1241 boolean_t intr;
1242 thread_t thr_act;
1243 pcb_t pcb;
1244 struct x86_fx_thread_state *ifps = 0;
1245 xstate_t xstate = current_xstate();
1246
1247 thr_act = current_thread();
1248 pcb = THREAD_TO_PCB(thr_act);
1249
1250 if (pcb->ifps == 0 && !get_interrupt_level()) {
1251 ifps = fp_state_alloc(xstate);
1252 bcopy((char *)&initial_fp_state, (char *)ifps,
1253 fp_state_size[xstate]);
1254 if (!thread_is_64bit_addr(thr_act)) {
1255 ifps->fp_save_layout = fpu_YMM_capable ? XSAVE32 : FXSAVE32;
1256 } else {
1257 ifps->fp_save_layout = fpu_YMM_capable ? XSAVE64 : FXSAVE64;
1258 }
1259 ifps->fp_valid = TRUE;
1260 }
1261 intr = ml_set_interrupts_enabled(FALSE);
1262
1263 clear_ts(); /* Enable FPU use */
1264
1265 if (__improbable(get_interrupt_level())) {
1266 /* Track number of #DNA traps at interrupt context,
1267 * which is likely suboptimal. Racy, but good enough.
1268 */
1269 x86_isr_fp_simd_use++;
1270 /*
1271 * Save current FP/SIMD context if valid
1272 * Initialize live FP/SIMD registers
1273 */
1274 if (pcb->ifps) {
1275 fp_save(thr_act);
1276 }
1277 fpinit();
1278 } else {
1279 if (pcb->ifps == 0) {
1280 pcb->ifps = ifps;
1281 pcb->xstate = xstate;
1282 ifps = 0;
1283 }
1284 /*
1285 * Load this thread`s state into coprocessor live context.
1286 */
1287 fp_load(thr_act);
1288 }
1289 (void)ml_set_interrupts_enabled(intr);
1290
1291 if (ifps) {
1292 fp_state_free(ifps, xstate);
1293 }
1294 }
1295
1296 /*
1297 * FPU overran end of segment.
1298 * Re-initialize FPU. Floating point state is not valid.
1299 */
1300
1301 void
1302 fpextovrflt(void)
1303 {
1304 thread_t thr_act = current_thread();
1305 pcb_t pcb;
1306 struct x86_fx_thread_state *ifps;
1307 boolean_t intr;
1308 xstate_t xstate = current_xstate();
1309
1310 intr = ml_set_interrupts_enabled(FALSE);
1311
1312 if (get_interrupt_level()) {
1313 panic("FPU segment overrun exception at interrupt context\n");
1314 }
1315 if (current_task() == kernel_task) {
1316 panic("FPU segment overrun exception in kernel thread context\n");
1317 }
1318
1319 /*
1320 * This is a non-recoverable error.
1321 * Invalidate the thread`s FPU state.
1322 */
1323 pcb = THREAD_TO_PCB(thr_act);
1324 simple_lock(&pcb->lock, LCK_GRP_NULL);
1325 ifps = pcb->ifps;
1326 pcb->ifps = 0;
1327 simple_unlock(&pcb->lock);
1328
1329 /*
1330 * Re-initialize the FPU.
1331 */
1332 clear_ts();
1333 fninit();
1334
1335 /*
1336 * And disable access.
1337 */
1338 clear_fpu();
1339
1340 (void)ml_set_interrupts_enabled(intr);
1341
1342 if (ifps) {
1343 fp_state_free(ifps, xstate);
1344 }
1345
1346 /*
1347 * Raise exception.
1348 */
1349 i386_exception(EXC_BAD_ACCESS, VM_PROT_READ | VM_PROT_EXECUTE, 0);
1350 /*NOTREACHED*/
1351 }
1352
1353 extern void fpxlog(int, uint32_t, uint32_t, uint32_t);
1354
1355 /*
1356 * FPU error. Called by AST.
1357 */
1358
1359 void
1360 fpexterrflt(void)
1361 {
1362 thread_t thr_act = current_thread();
1363 struct x86_fx_thread_state *ifps = thr_act->machine.ifps;
1364 boolean_t intr;
1365
1366 intr = ml_set_interrupts_enabled(FALSE);
1367
1368 if (get_interrupt_level()) {
1369 panic("FPU error exception at interrupt context\n");
1370 }
1371 if (current_task() == kernel_task) {
1372 panic("FPU error exception in kernel thread context\n");
1373 }
1374
1375 /*
1376 * Save the FPU state and turn off the FPU.
1377 */
1378 fp_save(thr_act);
1379
1380 (void)ml_set_interrupts_enabled(intr);
1381
1382 const uint32_t mask = ifps->fx_control &
1383 (FPC_IM | FPC_DM | FPC_ZM | FPC_OM | FPC_UE | FPC_PE);
1384 const uint32_t xcpt = ~mask & (ifps->fx_status &
1385 (FPS_IE | FPS_DE | FPS_ZE | FPS_OE | FPS_UE | FPS_PE));
1386 fpxlog(EXC_I386_EXTERR, ifps->fx_status, ifps->fx_control, xcpt);
1387 /*
1388 * Raise FPU exception.
1389 * Locking not needed on pcb->ifps,
1390 * since thread is running.
1391 */
1392 i386_exception(EXC_ARITHMETIC,
1393 EXC_I386_EXTERR,
1394 ifps->fx_status);
1395
1396 /*NOTREACHED*/
1397 }
1398
1399 /*
1400 * Save FPU state.
1401 *
1402 * Locking not needed:
1403 * . if called from fpu_get_state, pcb already locked.
1404 * . if called from fpnoextflt or fp_intr, we are single-cpu
1405 * . otherwise, thread is running.
1406 * N.B.: Must be called with interrupts disabled
1407 */
1408
1409 void
1410 fp_save(
1411 thread_t thr_act)
1412 {
1413 pcb_t pcb = THREAD_TO_PCB(thr_act);
1414 struct x86_fx_thread_state *ifps = pcb->ifps;
1415
1416 assert(ifps != 0);
1417 if (ifps != 0 && !ifps->fp_valid) {
1418 assert((get_cr0() & CR0_TS) == 0);
1419 /* registers are in FPU */
1420 ifps->fp_valid = TRUE;
1421 fpu_store_registers(ifps, thread_is_64bit_addr(thr_act));
1422 }
1423 }
1424
1425 /*
1426 * Restore FPU state from PCB.
1427 *
1428 * Locking not needed; always called on the current thread.
1429 */
1430
1431 void
1432 fp_load(
1433 thread_t thr_act)
1434 {
1435 pcb_t pcb = THREAD_TO_PCB(thr_act);
1436 struct x86_fx_thread_state *ifps = pcb->ifps;
1437
1438 assert(ifps);
1439 #if DEBUG
1440 if (ifps->fp_valid != FALSE && ifps->fp_valid != TRUE) {
1441 panic("fp_load() invalid fp_valid: %u, fp_save_layout: %u\n",
1442 ifps->fp_valid, ifps->fp_save_layout);
1443 }
1444 #endif
1445
1446 if (ifps->fp_valid == FALSE) {
1447 fpinit();
1448 } else {
1449 fpu_load_registers(ifps);
1450 }
1451 ifps->fp_valid = FALSE; /* in FPU */
1452 }
1453
1454 /*
1455 * SSE arithmetic exception handling code.
1456 * Basically the same as the x87 exception handler with a different subtype
1457 */
1458
1459 void
1460 fpSSEexterrflt(void)
1461 {
1462 thread_t thr_act = current_thread();
1463 struct x86_fx_thread_state *ifps = thr_act->machine.ifps;
1464 boolean_t intr;
1465
1466 intr = ml_set_interrupts_enabled(FALSE);
1467
1468 if (get_interrupt_level()) {
1469 panic("SSE exception at interrupt context\n");
1470 }
1471 if (current_task() == kernel_task) {
1472 panic("SSE exception in kernel thread context\n");
1473 }
1474
1475 /*
1476 * Save the FPU state and turn off the FPU.
1477 */
1478 fp_save(thr_act);
1479
1480 (void)ml_set_interrupts_enabled(intr);
1481 /*
1482 * Raise FPU exception.
1483 * Locking not needed on pcb->ifps,
1484 * since thread is running.
1485 */
1486 const uint32_t mask = (ifps->fx_MXCSR >> 7) &
1487 (FPC_IM | FPC_DM | FPC_ZM | FPC_OM | FPC_UE | FPC_PE);
1488 const uint32_t xcpt = ~mask & (ifps->fx_MXCSR &
1489 (FPS_IE | FPS_DE | FPS_ZE | FPS_OE | FPS_UE | FPS_PE));
1490 fpxlog(EXC_I386_SSEEXTERR, ifps->fx_MXCSR, ifps->fx_MXCSR, xcpt);
1491
1492 i386_exception(EXC_ARITHMETIC,
1493 EXC_I386_SSEEXTERR,
1494 ifps->fx_MXCSR);
1495 /*NOTREACHED*/
1496 }
1497
1498
1499 #if !defined(RC_HIDE_XNU_J137)
1500 /*
1501 * If a thread is using an AVX-sized savearea:
1502 * - allocate a new AVX512-sized area,
1503 * - copy the 256-bit state into the 512-bit area,
1504 * - deallocate the smaller area
1505 */
1506 static void
1507 fpu_savearea_promote_avx512(thread_t thread)
1508 {
1509 struct x86_avx_thread_state *ifps = NULL;
1510 struct x86_avx512_thread_state *ifps512 = NULL;
1511 pcb_t pcb = THREAD_TO_PCB(thread);
1512 boolean_t do_avx512_alloc = FALSE;
1513
1514 DBG("fpu_upgrade_savearea(%p)\n", thread);
1515
1516 simple_lock(&pcb->lock, LCK_GRP_NULL);
1517
1518 ifps = pcb->ifps;
1519 if (ifps == NULL) {
1520 pcb->xstate = AVX512;
1521 simple_unlock(&pcb->lock);
1522 if (thread != current_thread()) {
1523 /* nothing to be done */
1524
1525 return;
1526 }
1527 fpnoextflt();
1528 return;
1529 }
1530
1531 if (pcb->xstate != AVX512) {
1532 do_avx512_alloc = TRUE;
1533 }
1534 simple_unlock(&pcb->lock);
1535
1536 if (do_avx512_alloc == TRUE) {
1537 ifps512 = fp_state_alloc(AVX512);
1538 }
1539
1540 simple_lock(&pcb->lock, LCK_GRP_NULL);
1541 if (thread == current_thread()) {
1542 boolean_t intr;
1543
1544 intr = ml_set_interrupts_enabled(FALSE);
1545
1546 clear_ts();
1547 fp_save(thread);
1548 clear_fpu();
1549
1550 xsetbv(0, AVX512_XMASK);
1551 current_cpu_datap()->cpu_xstate = AVX512;
1552 (void)ml_set_interrupts_enabled(intr);
1553 }
1554 assert(ifps->fp.fp_valid);
1555
1556 /* Allocate an AVX512 savearea and copy AVX state into it */
1557 if (pcb->xstate != AVX512) {
1558 bcopy(ifps, ifps512, fp_state_size[AVX]);
1559 pcb->ifps = ifps512;
1560 pcb->xstate = AVX512;
1561 ifps512 = NULL;
1562 } else {
1563 ifps = NULL;
1564 }
1565 /* The PCB lock is redundant in some scenarios given the higher level
1566 * thread mutex, but its pre-emption disablement is relied upon here
1567 */
1568 simple_unlock(&pcb->lock);
1569
1570 if (ifps) {
1571 fp_state_free(ifps, AVX);
1572 }
1573 if (ifps512) {
1574 fp_state_free(ifps, AVX512);
1575 }
1576 }
1577
1578 /*
1579 * Upgrade the calling thread to AVX512.
1580 */
1581 boolean_t
1582 fpu_thread_promote_avx512(thread_t thread)
1583 {
1584 task_t task = current_task();
1585
1586 if (thread != current_thread()) {
1587 return FALSE;
1588 }
1589 if (!ml_fpu_avx512_enabled()) {
1590 return FALSE;
1591 }
1592
1593 fpu_savearea_promote_avx512(thread);
1594
1595 /* Racy but the task's xstate is only a hint */
1596 task->xstate = AVX512;
1597
1598 return TRUE;
1599 }
1600
1601
1602 /*
1603 * Called from user_trap() when an invalid opcode fault is taken.
1604 * If the user is attempting an AVX512 instruction on a machine
1605 * that supports this, we switch the calling thread to use
1606 * a larger savearea, set its XCR0 bit mask to enable AVX512 and
1607 * return directly via thread_exception_return().
1608 * Otherwise simply return.
1609 */
1610 #define MAX_X86_INSN_LENGTH (16)
1611 void
1612 fpUDflt(user_addr_t rip)
1613 {
1614 uint8_t instruction_prefix;
1615 boolean_t is_AVX512_instruction = FALSE;
1616 user_addr_t original_rip = rip;
1617 do {
1618 /* TODO: as an optimisation, copy up to the lesser of the
1619 * next page boundary or maximal prefix length in one pass
1620 * rather than issue multiple copyins
1621 */
1622 if (copyin(rip, (char *) &instruction_prefix, 1)) {
1623 return;
1624 }
1625 DBG("fpUDflt(0x%016llx) prefix: 0x%x\n",
1626 rip, instruction_prefix);
1627 /* TODO: determine more specifically which prefixes
1628 * are sane possibilities for AVX512 insns
1629 */
1630 switch (instruction_prefix) {
1631 case 0x2E: /* CS segment override */
1632 case 0x36: /* SS segment override */
1633 case 0x3E: /* DS segment override */
1634 case 0x26: /* ES segment override */
1635 case 0x64: /* FS segment override */
1636 case 0x65: /* GS segment override */
1637 case 0x66: /* Operand-size override */
1638 case 0x67: /* address-size override */
1639 /* Skip optional prefixes */
1640 rip++;
1641 if ((rip - original_rip) > MAX_X86_INSN_LENGTH) {
1642 return;
1643 }
1644 break;
1645 case 0x62: /* EVEX */
1646 case 0xC5: /* VEX 2-byte */
1647 case 0xC4: /* VEX 3-byte */
1648 is_AVX512_instruction = TRUE;
1649 break;
1650 default:
1651 return;
1652 }
1653 } while (!is_AVX512_instruction);
1654
1655 /* Here if we detect attempted execution of an AVX512 instruction */
1656
1657 /*
1658 * Fail if this machine doesn't support AVX512
1659 */
1660 if (fpu_capability != AVX512) {
1661 return;
1662 }
1663
1664 assert(xgetbv(XCR0) == AVX_XMASK);
1665
1666 DBG("fpUDflt() switching xstate to AVX512\n");
1667 (void) fpu_thread_promote_avx512(current_thread());
1668
1669 thread_exception_return();
1670 /* NOT REACHED */
1671 }
1672 #endif /* !defined(RC_HIDE_XNU_J137) */
1673
1674 void
1675 fp_setvalid(boolean_t value)
1676 {
1677 thread_t thr_act = current_thread();
1678 struct x86_fx_thread_state *ifps = thr_act->machine.ifps;
1679
1680 if (ifps) {
1681 ifps->fp_valid = value;
1682
1683 if (value == TRUE) {
1684 boolean_t istate = ml_set_interrupts_enabled(FALSE);
1685 clear_fpu();
1686 ml_set_interrupts_enabled(istate);
1687 }
1688 }
1689 }
1690
1691 boolean_t
1692 ml_fpu_avx_enabled(void)
1693 {
1694 return fpu_capability >= AVX;
1695 }
1696
1697 #if !defined(RC_HIDE_XNU_J137)
1698 boolean_t
1699 ml_fpu_avx512_enabled(void)
1700 {
1701 return fpu_capability == AVX512;
1702 }
1703 #endif
1704
1705 static xstate_t
1706 task_xstate(task_t task)
1707 {
1708 if (task == TASK_NULL) {
1709 return fpu_default;
1710 } else {
1711 return task->xstate;
1712 }
1713 }
1714
1715 static xstate_t
1716 thread_xstate(thread_t thread)
1717 {
1718 xstate_t xs = THREAD_TO_PCB(thread)->xstate;
1719 if (xs == UNDEFINED) {
1720 return task_xstate(thread->task);
1721 } else {
1722 return xs;
1723 }
1724 }
1725
1726 xstate_t
1727 current_xstate(void)
1728 {
1729 return thread_xstate(current_thread());
1730 }
1731
1732 /*
1733 * Called when exec'ing between bitnesses.
1734 * If valid FPU state exists, adjust the layout.
1735 */
1736 void
1737 fpu_switch_addrmode(thread_t thread, boolean_t is_64bit)
1738 {
1739 struct x86_fx_thread_state *ifps = thread->machine.ifps;
1740 mp_disable_preemption();
1741
1742 if (ifps && ifps->fp_valid) {
1743 if (thread_xstate(thread) == FP) {
1744 ifps->fp_save_layout = is_64bit ? FXSAVE64 : FXSAVE32;
1745 } else {
1746 ifps->fp_save_layout = is_64bit ? XSAVE64 : XSAVE32;
1747 }
1748 }
1749 mp_enable_preemption();
1750 }
1751
1752 static inline uint32_t
1753 fpsimd_pop(uintptr_t ins, int sz)
1754 {
1755 uint32_t rv = 0;
1756
1757
1758 while (sz >= 16) {
1759 uint32_t rv1, rv2;
1760 uint64_t *ins64 = (uint64_t *) ins;
1761 uint64_t *ins642 = (uint64_t *) (ins + 8);
1762 rv1 = __builtin_popcountll(*ins64);
1763 rv2 = __builtin_popcountll(*ins642);
1764 rv += rv1 + rv2;
1765 sz -= 16;
1766 ins += 16;
1767 }
1768
1769 while (sz >= 4) {
1770 uint32_t *ins32 = (uint32_t *) ins;
1771 rv += __builtin_popcount(*ins32);
1772 sz -= 4;
1773 ins += 4;
1774 }
1775
1776 while (sz > 0) {
1777 char *ins8 = (char *)ins;
1778 rv += __builtin_popcount(*ins8);
1779 sz--;
1780 ins++;
1781 }
1782 return rv;
1783 }
1784
1785 uint32_t
1786 thread_fpsimd_hash(thread_t ft)
1787 {
1788 if (fpsimd_fault_popc == 0) {
1789 return 0;
1790 }
1791
1792 uint32_t prv = 0;
1793 boolean_t istate = ml_set_interrupts_enabled(FALSE);
1794 struct x86_fx_thread_state *pifps = THREAD_TO_PCB(ft)->ifps;
1795
1796 if (pifps) {
1797 if (pifps->fp_valid) {
1798 prv = fpsimd_pop((uintptr_t) &pifps->fx_XMM_reg[0][0],
1799 sizeof(pifps->fx_XMM_reg));
1800 } else {
1801 uintptr_t cr0 = get_cr0();
1802 clear_ts();
1803 fp_save(ft);
1804 prv = fpsimd_pop((uintptr_t) &pifps->fx_XMM_reg[0][0],
1805 sizeof(pifps->fx_XMM_reg));
1806 pifps->fp_valid = FALSE;
1807 if (cr0 & CR0_TS) {
1808 set_cr0(cr0);
1809 }
1810 }
1811 }
1812 ml_set_interrupts_enabled(istate);
1813 return prv;
1814 }