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