]> git.saurik.com Git - apple/xnu.git/blame - osfmk/i386/fpu.c
xnu-1228.15.4.tar.gz
[apple/xnu.git] / osfmk / i386 / fpu.c
CommitLineData
1c79356b 1/*
2d21ac55 2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
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.
8f6c56a5 14 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
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 */
58
1c79356b
A
59#include <platforms.h>
60
61#include <mach/exception_types.h>
62#include <mach/i386/thread_status.h>
63#include <mach/i386/fp_reg.h>
64
65#include <kern/mach_param.h>
91447636 66#include <kern/processor.h>
1c79356b
A
67#include <kern/thread.h>
68#include <kern/zalloc.h>
69#include <kern/misc_protos.h>
70#include <kern/spl.h>
71#include <kern/assert.h>
72
73#include <i386/thread.h>
74#include <i386/fpu.h>
75#include <i386/trap.h>
0c530ab8 76#include <architecture/i386/pio.h>
55e303ae 77#include <i386/cpuid.h>
1c79356b 78#include <i386/misc_protos.h>
0c530ab8 79#include <i386/proc_reg.h>
1c79356b 80
0c530ab8 81int fp_kind = FP_NO; /* not inited */
1c79356b
A
82zone_t ifps_zone; /* zone for FPU save area */
83
55e303ae 84#define ALIGNED(addr,size) (((unsigned)(addr)&((size)-1))==0)
1c79356b
A
85
86/* Forward */
87
88extern void fpinit(void);
89extern void fp_save(
91447636 90 thread_t thr_act);
1c79356b 91extern void fp_load(
91447636 92 thread_t thr_act);
1c79356b 93
0c530ab8
A
94static void configure_mxcsr_capability_mask(struct x86_fpsave_state *ifps);
95
96struct x86_fpsave_state starting_fp_state;
97
98
99/* Global MXCSR capability bitmask */
100static unsigned int mxcsr_capability_mask;
101
102/*
103 * Determine the MXCSR capability mask, which allows us to mask off any
104 * potentially unsafe "reserved" bits before restoring the FPU context.
105 * *Not* per-cpu, assumes symmetry.
106 */
107static void
108configure_mxcsr_capability_mask(struct x86_fpsave_state *ifps)
109{
110 /* FXSAVE requires a 16 byte aligned store */
111 assert(ALIGNED(ifps,16));
112 /* Clear, to prepare for the diagnostic FXSAVE */
113 bzero(ifps, sizeof(*ifps));
114 /* Disable FPU/SSE Device Not Available exceptions */
115 clear_ts();
116
117 __asm__ volatile("fxsave %0" : "=m" (ifps->fx_save_state));
118 mxcsr_capability_mask = ifps->fx_save_state.fx_MXCSR_MASK;
119
120 /* Set default mask value if necessary */
121 if (mxcsr_capability_mask == 0)
122 mxcsr_capability_mask = 0xffbf;
123
124 /* Re-enable FPU/SSE DNA exceptions */
125 set_ts();
126}
127
128/*
129 * Allocate and initialize FP state for current thread.
130 * Don't load state.
131 */
132static struct x86_fpsave_state *
133fp_state_alloc(void)
134{
135 struct x86_fpsave_state *ifps;
136
137 ifps = (struct x86_fpsave_state *)zalloc(ifps_zone);
138 assert(ALIGNED(ifps,16));
139 bzero((char *)ifps, sizeof *ifps);
140
141 return ifps;
142}
143
144static inline void
145fp_state_free(struct x86_fpsave_state *ifps)
146{
147 zfree(ifps_zone, ifps);
148}
149
150
1c79356b
A
151/*
152 * Look for FPU and initialize it.
153 * Called on each CPU.
154 */
155void
156init_fpu(void)
157{
158 unsigned short status, control;
159
160 /*
161 * Check for FPU by initializing it,
162 * then trying to read the correct bit patterns from
163 * the control and status registers.
164 */
91447636 165 set_cr0((get_cr0() & ~(CR0_EM|CR0_TS)) | CR0_NE); /* allow use of FPU */
1c79356b
A
166
167 fninit();
168 status = fnstsw();
169 fnstcw(&control);
170
171 if ((status & 0xff) == 0 &&
55e303ae
A
172 (control & 0x103f) == 0x3f)
173 {
55e303ae 174 /* Use FPU save/restore instructions if available */
0c530ab8 175 if (cpuid_features() & CPUID_FEATURE_FXSR) {
2d21ac55 176 fp_kind = FP_FXSR;
0c530ab8 177 set_cr4(get_cr4() | CR4_FXS);
0c530ab8
A
178 /* And allow SIMD instructions if present */
179 if (cpuid_features() & CPUID_FEATURE_SSE) {
0c530ab8
A
180 set_cr4(get_cr4() | CR4_XMM);
181 }
0c530ab8
A
182 } else
183 panic("fpu is not FP_FXSR");
55e303ae 184
1c79356b 185 /*
0c530ab8
A
186 * initialze FPU to normal starting
187 * position so that we can take a snapshot
188 * of that state and store it for future use
189 * when we're asked for the FPU state of a
190 * thread, and it hasn't initiated any yet
1c79356b 191 */
0c530ab8
A
192 fpinit();
193 fxsave(&starting_fp_state.fx_save_state);
194
195 /*
196 * Trap wait instructions. Turn off FPU for now.
197 */
198 set_cr0(get_cr0() | CR0_TS | CR0_MP);
1c79356b
A
199 }
200 else
201 {
202 /*
203 * NO FPU.
204 */
0c530ab8 205 panic("fpu is not FP_FXSR");
1c79356b
A
206 }
207}
208
209/*
210 * Initialize FP handling.
211 */
212void
213fpu_module_init(void)
214{
0c530ab8
A
215 struct x86_fpsave_state *new_ifps;
216
217 ifps_zone = zinit(sizeof(struct x86_fpsave_state),
218 THREAD_MAX * sizeof(struct x86_fpsave_state),
219 THREAD_CHUNK * sizeof(struct x86_fpsave_state),
220 "x86 fpsave state");
221 new_ifps = fp_state_alloc();
222 /* Determine MXCSR reserved bits */
223 configure_mxcsr_capability_mask(new_ifps);
224 fp_state_free(new_ifps);
1c79356b
A
225}
226
227/*
228 * Free a FPU save area.
229 * Called only when thread terminating - no locking necessary.
230 */
231void
2d21ac55 232fpu_free(struct x86_fpsave_state *fps)
1c79356b 233{
0c530ab8 234 fp_state_free(fps);
1c79356b
A
235}
236
55e303ae
A
237/*
238 * Set the floating-point state for a thread based
239 * on the FXSave formatted data. This is basically
240 * the same as fpu_set_state except it uses the
241 * expanded data structure.
242 * If the thread is not the current thread, it is
243 * not running (held). Locking needed against
244 * concurrent fpu_set_state or fpu_get_state.
245 */
246kern_return_t
247fpu_set_fxstate(
2d21ac55 248 thread_t thr_act,
0c530ab8 249 thread_state_t tstate)
55e303ae 250{
0c530ab8
A
251 struct x86_fpsave_state *ifps;
252 struct x86_fpsave_state *new_ifps;
253 x86_float_state64_t *state;
254 pcb_t pcb;
55e303ae 255
55e303ae 256 if (fp_kind == FP_NO)
2d21ac55 257 return KERN_FAILURE;
0c530ab8
A
258
259 state = (x86_float_state64_t *)tstate;
55e303ae 260
91447636
A
261 assert(thr_act != THREAD_NULL);
262 pcb = thr_act->machine.pcb;
55e303ae 263
0c530ab8 264 if (state == NULL) {
2d21ac55
A
265 /*
266 * new FPU state is 'invalid'.
267 * Deallocate the fp state if it exists.
268 */
269 simple_lock(&pcb->lock);
0c530ab8
A
270
271 ifps = pcb->ifps;
272 pcb->ifps = 0;
4452a7af 273
2d21ac55 274 simple_unlock(&pcb->lock);
0c530ab8
A
275
276 if (ifps != 0)
2d21ac55 277 fp_state_free(ifps);
0c530ab8 278 } else {
2d21ac55
A
279 /*
280 * Valid state. Allocate the fp state if there is none.
281 */
282 new_ifps = 0;
55e303ae 283 Retry:
2d21ac55 284 simple_lock(&pcb->lock);
0c530ab8
A
285
286 ifps = pcb->ifps;
2d21ac55
A
287 if (ifps == 0) {
288 if (new_ifps == 0) {
289 simple_unlock(&pcb->lock);
290 new_ifps = fp_state_alloc();
291 goto Retry;
55e303ae 292 }
2d21ac55
A
293 ifps = new_ifps;
294 new_ifps = 0;
295 pcb->ifps = ifps;
296 }
297 /*
298 * now copy over the new data.
299 */
300 bcopy((char *)&state->fpu_fcw,
0c530ab8 301 (char *)&ifps->fx_save_state, sizeof(struct x86_fx_save));
4452a7af 302
0c530ab8
A
303 /* XXX The layout of the state set from user-space may need to be
304 * validated for consistency.
305 */
306 ifps->fp_save_layout = thread_is_64bit(thr_act) ? FXSAVE64 : FXSAVE32;
2d21ac55
A
307 /* Mark the thread's floating point status as non-live. */
308 /* Temporarily disabled: radar 4647827
309 * ifps->fp_valid = TRUE;
310 */
311
0c530ab8
A
312 /*
313 * Clear any reserved bits in the MXCSR to prevent a GPF
314 * when issuing an FXRSTOR.
315 */
2d21ac55 316 ifps->fx_save_state.fx_MXCSR &= mxcsr_capability_mask;
6601e61a 317
2d21ac55 318 simple_unlock(&pcb->lock);
0c530ab8 319
2d21ac55
A
320 if (new_ifps != 0)
321 fp_state_free(new_ifps);
0c530ab8 322 }
55e303ae
A
323 return KERN_SUCCESS;
324}
325
326/*
327 * Get the floating-point state for a thread.
328 * If the thread is not the current thread, it is
329 * not running (held). Locking needed against
330 * concurrent fpu_set_state or fpu_get_state.
331 */
332kern_return_t
333fpu_get_fxstate(
2d21ac55 334 thread_t thr_act,
0c530ab8 335 thread_state_t tstate)
55e303ae 336{
0c530ab8
A
337 struct x86_fpsave_state *ifps;
338 x86_float_state64_t *state;
339 kern_return_t ret = KERN_FAILURE;
340 pcb_t pcb;
55e303ae 341
0c530ab8 342 if (fp_kind == FP_NO)
2d21ac55 343 return KERN_FAILURE;
0c530ab8
A
344
345 state = (x86_float_state64_t *)tstate;
55e303ae 346
91447636
A
347 assert(thr_act != THREAD_NULL);
348 pcb = thr_act->machine.pcb;
55e303ae
A
349
350 simple_lock(&pcb->lock);
0c530ab8
A
351
352 ifps = pcb->ifps;
55e303ae 353 if (ifps == 0) {
2d21ac55 354 /*
0c530ab8
A
355 * No valid floating-point state.
356 */
2d21ac55 357 bcopy((char *)&starting_fp_state.fx_save_state,
0c530ab8
A
358 (char *)&state->fpu_fcw, sizeof(struct x86_fx_save));
359
360 simple_unlock(&pcb->lock);
6601e61a 361
0c530ab8
A
362 return KERN_SUCCESS;
363 }
364 /*
365 * Make sure we`ve got the latest fp state info
366 * If the live fpu state belongs to our target
367 */
2d21ac55
A
368 if (thr_act == current_thread()) {
369 boolean_t intr;
8f6c56a5 370
0c530ab8 371 intr = ml_set_interrupts_enabled(FALSE);
89b3af67 372
0c530ab8
A
373 clear_ts();
374 fp_save(thr_act);
375 clear_fpu();
6601e61a 376
0c530ab8 377 (void)ml_set_interrupts_enabled(intr);
6601e61a 378 }
0c530ab8
A
379 if (ifps->fp_valid) {
380 bcopy((char *)&ifps->fx_save_state,
381 (char *)&state->fpu_fcw, sizeof(struct x86_fx_save));
382 ret = KERN_SUCCESS;
6601e61a 383 }
0c530ab8 384 simple_unlock(&pcb->lock);
21362eb3 385
0c530ab8 386 return ret;
6601e61a 387}
21362eb3 388
0c530ab8 389
2d21ac55 390
6601e61a 391/*
0c530ab8
A
392 * the child thread is 'stopped' with the thread
393 * mutex held and is currently not known by anyone
394 * so no way for fpu state to get manipulated by an
395 * outside agency -> no need for pcb lock
6601e61a 396 */
0c530ab8
A
397
398void
399fpu_dup_fxstate(
400 thread_t parent,
401 thread_t child)
6601e61a 402{
0c530ab8
A
403 struct x86_fpsave_state *new_ifps = NULL;
404 boolean_t intr;
405 pcb_t ppcb;
21362eb3 406
0c530ab8 407 ppcb = parent->machine.pcb;
21362eb3 408
0c530ab8
A
409 if (ppcb->ifps == NULL)
410 return;
4452a7af 411
0c530ab8
A
412 if (child->machine.pcb->ifps)
413 panic("fpu_dup_fxstate: child's ifps non-null");
4452a7af 414
0c530ab8 415 new_ifps = fp_state_alloc();
5d5c5d0d 416
0c530ab8 417 simple_lock(&ppcb->lock);
6601e61a 418
0c530ab8
A
419 if (ppcb->ifps != NULL) {
420 /*
421 * Make sure we`ve got the latest fp state info
422 */
423 intr = ml_set_interrupts_enabled(FALSE);
6601e61a 424
0c530ab8
A
425 clear_ts();
426 fp_save(parent);
427 clear_fpu();
6601e61a 428
0c530ab8 429 (void)ml_set_interrupts_enabled(intr);
6601e61a 430
0c530ab8
A
431 if (ppcb->ifps->fp_valid) {
432 child->machine.pcb->ifps = new_ifps;
433
434 bcopy((char *)&(ppcb->ifps->fx_save_state),
435 (char *)&(child->machine.pcb->ifps->fx_save_state), sizeof(struct x86_fx_save));
436
437 new_ifps->fp_save_layout = ppcb->ifps->fp_save_layout;
2d21ac55
A
438 /* Mark the new fp saved state as non-live. */
439 /* Temporarily disabled: radar 4647827
440 * new_ifps->fp_valid = TRUE;
441 */
0c530ab8
A
442 /*
443 * Clear any reserved bits in the MXCSR to prevent a GPF
444 * when issuing an FXRSTOR.
445 */
446 new_ifps->fx_save_state.fx_MXCSR &= mxcsr_capability_mask;
447 new_ifps = NULL;
448 }
6601e61a 449 }
0c530ab8 450 simple_unlock(&ppcb->lock);
89b3af67 451
0c530ab8
A
452 if (new_ifps != NULL)
453 fp_state_free(new_ifps);
6601e61a 454}
4452a7af 455
0c530ab8 456
1c79356b
A
457/*
458 * Initialize FPU.
459 *
1c79356b
A
460 */
461void
462fpinit(void)
463{
464 unsigned short control;
465
1c79356b
A
466 clear_ts();
467 fninit();
468 fnstcw(&control);
469 control &= ~(FPC_PC|FPC_RC); /* Clear precision & rounding control */
0c530ab8 470 control |= (FPC_PC_64 | /* Set precision */
1c79356b
A
471 FPC_RC_RN | /* round-to-nearest */
472 FPC_ZE | /* Suppress zero-divide */
473 FPC_OE | /* and overflow */
474 FPC_UE | /* underflow */
475 FPC_IE | /* Allow NaNQs and +-INF */
476 FPC_DE | /* Allow denorms as operands */
477 FPC_PE); /* No trap for precision loss */
478 fldcw(control);
0c530ab8
A
479
480 /* Initialize SSE/SSE2 */
2d21ac55
A
481 __builtin_ia32_ldmxcsr(0x1f80);
482 }
1c79356b
A
483
484/*
485 * Coprocessor not present.
486 */
487
488void
489fpnoextflt(void)
490{
0c530ab8 491 boolean_t intr;
2d21ac55
A
492 thread_t thr_act;
493 pcb_t pcb;
494 struct x86_fpsave_state *ifps = 0;
495
496 thr_act = current_thread();
497 pcb = thr_act->machine.pcb;
498
499 if (pcb->ifps == 0 && !get_interrupt_level())
500 ifps = fp_state_alloc();
4452a7af 501
0c530ab8
A
502 intr = ml_set_interrupts_enabled(FALSE);
503
504 clear_ts(); /* Enable FPU use */
505
506 if (get_interrupt_level()) {
507 /*
508 * Save current coprocessor context if valid
509 * Initialize coprocessor live context
510 */
2d21ac55 511 fp_save(thr_act);
0c530ab8
A
512 fpinit();
513 } else {
2d21ac55
A
514 if (pcb->ifps == 0) {
515 pcb->ifps = ifps;
516 ifps = 0;
517 }
0c530ab8
A
518 /*
519 * Load this thread`s state into coprocessor live context.
520 */
2d21ac55 521 fp_load(thr_act);
0c530ab8 522 }
0c530ab8 523 (void)ml_set_interrupts_enabled(intr);
2d21ac55
A
524
525 if (ifps)
526 fp_state_free(ifps);
1c79356b
A
527}
528
529/*
530 * FPU overran end of segment.
531 * Re-initialize FPU. Floating point state is not valid.
532 */
533
534void
535fpextovrflt(void)
536{
0c530ab8
A
537 thread_t thr_act = current_thread();
538 pcb_t pcb;
539 struct x86_fpsave_state *ifps;
540 boolean_t intr;
541
542 intr = ml_set_interrupts_enabled(FALSE);
543
544 if (get_interrupt_level())
2d21ac55 545 panic("FPU segment overrun exception at interrupt context\n");
0c530ab8
A
546 if (current_task() == kernel_task)
547 panic("FPU segment overrun exception in kernel thread context\n");
1c79356b 548
1c79356b
A
549 /*
550 * This is a non-recoverable error.
551 * Invalidate the thread`s FPU state.
552 */
91447636 553 pcb = thr_act->machine.pcb;
1c79356b 554 simple_lock(&pcb->lock);
0c530ab8
A
555 ifps = pcb->ifps;
556 pcb->ifps = 0;
1c79356b
A
557 simple_unlock(&pcb->lock);
558
559 /*
560 * Re-initialize the FPU.
561 */
562 clear_ts();
563 fninit();
564
565 /*
566 * And disable access.
567 */
568 clear_fpu();
569
0c530ab8
A
570 (void)ml_set_interrupts_enabled(intr);
571
1c79356b 572 if (ifps)
91447636 573 zfree(ifps_zone, ifps);
1c79356b
A
574
575 /*
576 * Raise exception.
577 */
578 i386_exception(EXC_BAD_ACCESS, VM_PROT_READ|VM_PROT_EXECUTE, 0);
579 /*NOTREACHED*/
580}
581
582/*
583 * FPU error. Called by AST.
584 */
585
586void
587fpexterrflt(void)
588{
0c530ab8
A
589 thread_t thr_act = current_thread();
590 struct x86_fpsave_state *ifps = thr_act->machine.pcb->ifps;
591 boolean_t intr;
592
593 intr = ml_set_interrupts_enabled(FALSE);
594
595 if (get_interrupt_level())
596 panic("FPU error exception at interrupt context\n");
597 if (current_task() == kernel_task)
598 panic("FPU error exception in kernel thread context\n");
1c79356b 599
1c79356b
A
600 /*
601 * Save the FPU state and turn off the FPU.
602 */
603 fp_save(thr_act);
1c79356b 604
0c530ab8
A
605 (void)ml_set_interrupts_enabled(intr);
606
1c79356b
A
607 /*
608 * Raise FPU exception.
0c530ab8 609 * Locking not needed on pcb->ifps,
1c79356b
A
610 * since thread is running.
611 */
612 i386_exception(EXC_ARITHMETIC,
613 EXC_I386_EXTERR,
0c530ab8
A
614 ifps->fx_save_state.fx_status);
615
1c79356b
A
616 /*NOTREACHED*/
617}
618
619/*
620 * Save FPU state.
621 *
622 * Locking not needed:
623 * . if called from fpu_get_state, pcb already locked.
624 * . if called from fpnoextflt or fp_intr, we are single-cpu
625 * . otherwise, thread is running.
0c530ab8 626 * N.B.: Must be called with interrupts disabled
1c79356b 627 */
0c530ab8 628
1c79356b
A
629void
630fp_save(
91447636 631 thread_t thr_act)
1c79356b 632{
0c530ab8
A
633 pcb_t pcb = thr_act->machine.pcb;
634 struct x86_fpsave_state *ifps = pcb->ifps;
635
1c79356b 636 if (ifps != 0 && !ifps->fp_valid) {
0c530ab8
A
637 assert((get_cr0() & CR0_TS) == 0);
638 /* registers are in FPU */
639 ifps->fp_valid = TRUE;
640
641 if (!thread_is_64bit(thr_act)) {
642 /* save the compatibility/legacy mode XMM+x87 state */
643 fxsave(&ifps->fx_save_state);
644 ifps->fp_save_layout = FXSAVE32;
645 }
646 else {
647 fxsave64(&ifps->fx_save_state);
648 ifps->fp_save_layout = FXSAVE64;
649 }
1c79356b
A
650 }
651}
652
653/*
654 * Restore FPU state from PCB.
655 *
656 * Locking not needed; always called on the current thread.
657 */
658
659void
660fp_load(
91447636 661 thread_t thr_act)
1c79356b 662{
0c530ab8
A
663 pcb_t pcb = thr_act->machine.pcb;
664 struct x86_fpsave_state *ifps;
665
666 ifps = pcb->ifps;
667 if (ifps == 0 || ifps->fp_valid == FALSE) {
668 if (ifps == 0) {
669 /* FIXME: This allocation mechanism should be revised
670 * for scenarios where interrupts are disabled.
671 */
672 ifps = fp_state_alloc();
673 pcb->ifps = ifps;
674 }
675 fpinit();
1c79356b 676 } else {
0c530ab8
A
677 assert(ifps->fp_save_layout == FXSAVE32 || ifps->fp_save_layout == FXSAVE64);
678 if (ifps->fp_save_layout == FXSAVE32) {
679 /* Restore the compatibility/legacy mode XMM+x87 state */
680 fxrstor(&ifps->fx_save_state);
681 }
682 else if (ifps->fp_save_layout == FXSAVE64) {
683 fxrstor64(&ifps->fx_save_state);
684 }
1c79356b
A
685 }
686 ifps->fp_valid = FALSE; /* in FPU */
687}
688
55e303ae 689
1c79356b
A
690
691/*
91447636 692 * fpflush(thread_t)
1c79356b
A
693 * Flush the current act's state, if needed
694 * (used by thread_terminate_self to ensure fp faults
695 * aren't satisfied by overly general trap code in the
696 * context of the reaper thread)
697 */
698void
91447636 699fpflush(__unused thread_t thr_act)
1c79356b 700{
1c79356b 701 /* not needed on MP x86s; fp not lazily evaluated */
1c79356b
A
702}
703
1c79356b 704/*
0c530ab8
A
705 * SSE arithmetic exception handling code.
706 * Basically the same as the x87 exception handler with a different subtype
1c79356b
A
707 */
708
709void
0c530ab8 710fpSSEexterrflt(void)
1c79356b 711{
0c530ab8
A
712 thread_t thr_act = current_thread();
713 struct x86_fpsave_state *ifps = thr_act->machine.pcb->ifps;
714 boolean_t intr;
4452a7af 715
0c530ab8
A
716 intr = ml_set_interrupts_enabled(FALSE);
717
718 if (get_interrupt_level())
719 panic("SSE exception at interrupt context\n");
720 if (current_task() == kernel_task)
721 panic("SSE exception in kernel thread context\n");
1c79356b
A
722
723 /*
0c530ab8 724 * Save the FPU state and turn off the FPU.
1c79356b 725 */
1c79356b 726 fp_save(thr_act);
1c79356b 727
0c530ab8 728 (void)ml_set_interrupts_enabled(intr);
1c79356b 729 /*
0c530ab8
A
730 * Raise FPU exception.
731 * Locking not needed on pcb->ifps,
732 * since thread is running.
1c79356b 733 */
0c530ab8
A
734 assert(ifps->fp_save_layout == FXSAVE32 || ifps->fp_save_layout == FXSAVE64);
735 i386_exception(EXC_ARITHMETIC,
736 EXC_I386_SSEEXTERR,
737 ifps->fx_save_state.fx_status);
738 /*NOTREACHED*/
739}
740
741
742void
743fp_setvalid(boolean_t value) {
744 thread_t thr_act = current_thread();
745 struct x86_fpsave_state *ifps = thr_act->machine.pcb->ifps;
746
747 if (ifps) {
748 ifps->fp_valid = value;
749
750 if (value == TRUE)
751 clear_fpu();
752 }
1c79356b 753}