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