1/* $NetBSD: fpu.c,v 1.12 2016/09/29 17:01:43 maxv Exp $ */
2
3/*-
4 * Copyright (c) 2008 The NetBSD Foundation, Inc. All
5 * rights reserved.
6 *
7 * This code is derived from software developed for The NetBSD Foundation
8 * by Andrew Doran.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32/*-
33 * Copyright (c) 1991 The Regents of the University of California.
34 * All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 *
60 * @(#)npx.c 7.2 (Berkeley) 5/12/91
61 */
62
63/*-
64 * Copyright (c) 1994, 1995, 1998 Charles M. Hannum. All rights reserved.
65 * Copyright (c) 1990 William Jolitz.
66 *
67 * Redistribution and use in source and binary forms, with or without
68 * modification, are permitted provided that the following conditions
69 * are met:
70 * 1. Redistributions of source code must retain the above copyright
71 * notice, this list of conditions and the following disclaimer.
72 * 2. Redistributions in binary form must reproduce the above copyright
73 * notice, this list of conditions and the following disclaimer in the
74 * documentation and/or other materials provided with the distribution.
75 * 3. All advertising materials mentioning features or use of this software
76 * must display the following acknowledgement:
77 * This product includes software developed by the University of
78 * California, Berkeley and its contributors.
79 * 4. Neither the name of the University nor the names of its contributors
80 * may be used to endorse or promote products derived from this software
81 * without specific prior written permission.
82 *
83 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
84 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
85 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
86 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
87 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
88 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
89 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
90 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
91 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
92 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
93 * SUCH DAMAGE.
94 *
95 * @(#)npx.c 7.2 (Berkeley) 5/12/91
96 */
97
98#include <sys/cdefs.h>
99__KERNEL_RCSID(0, "$NetBSD: fpu.c,v 1.12 2016/09/29 17:01:43 maxv Exp $");
100
101#include "opt_multiprocessor.h"
102
103#include <sys/param.h>
104#include <sys/systm.h>
105#include <sys/conf.h>
106#include <sys/cpu.h>
107#include <sys/file.h>
108#include <sys/proc.h>
109#include <sys/kernel.h>
110
111#include <machine/cpu.h>
112#include <machine/intr.h>
113#include <machine/cpufunc.h>
114#include <machine/pcb.h>
115#include <machine/trap.h>
116#include <machine/specialreg.h>
117#include <x86/cpu.h>
118#include <x86/fpu.h>
119
120/* Check some duplicate definitions match */
121#include <machine/fenv.h>
122
123#ifdef XEN
124#define clts() HYPERVISOR_fpu_taskswitch(0)
125#define stts() HYPERVISOR_fpu_taskswitch(1)
126#endif
127
128static inline union savefpu *
129process_fpframe(struct lwp *lwp)
130{
131 struct pcb *pcb = lwp_getpcb(lwp);
132
133 return &pcb->pcb_savefpu;
134}
135
136/*
137 * The following table is used to ensure that the FPE_... value
138 * that is passed as a trapcode to the signal handler of the user
139 * process does not have more than one bit set.
140 *
141 * Multiple bits may be set if SSE simd instructions generate errors
142 * on more than one value or if the user process modifies the control
143 * word while a status word bit is already set (which this is a sign
144 * of bad coding).
145 * We have no choise than to narrow them down to one bit, since we must
146 * not send a trapcode that is not exactly one of the FPE_ macros.
147 *
148 * The mechanism has a static table with 127 entries. Each combination
149 * of the 7 FPU status word exception bits directly translates to a
150 * position in this table, where a single FPE_... value is stored.
151 * This FPE_... value stored there is considered the "most important"
152 * of the exception bits and will be sent as the signal code. The
153 * precedence of the bits is based upon Intel Document "Numerical
154 * Applications", Chapter "Special Computational Situations".
155 *
156 * The code to choose one of these values does these steps:
157 * 1) Throw away status word bits that cannot be masked.
158 * 2) Throw away the bits currently masked in the control word,
159 * assuming the user isn't interested in them anymore.
160 * 3) Reinsert status word bit 7 (stack fault) if it is set, which
161 * cannot be masked but must be presered.
162 * 'Stack fault' is a sub-class of 'invalid operation'.
163 * 4) Use the remaining bits to point into the trapcode table.
164 *
165 * The 6 maskable bits in order of their preference, as stated in the
166 * above referenced Intel manual:
167 * 1 Invalid operation (FP_X_INV)
168 * 1a Stack underflow
169 * 1b Stack overflow
170 * 1c Operand of unsupported format
171 * 1d SNaN operand.
172 * 2 QNaN operand (not an exception, irrelavant here)
173 * 3 Any other invalid-operation not mentioned above or zero divide
174 * (FP_X_INV, FP_X_DZ)
175 * 4 Denormal operand (FP_X_DNML)
176 * 5 Numeric over/underflow (FP_X_OFL, FP_X_UFL)
177 * 6 Inexact result (FP_X_IMP)
178 *
179 * NB: the above seems to mix up the mxscr error bits and the x87 ones.
180 * They are in the same order, but there is no EN_SW_STACK_FAULT in the mmx
181 * status.
182 *
183 * The table is nearly, but not quite, in bit order (ZERODIV and DENORM
184 * are swapped).
185 *
186 * This table assumes that any stack fault is cleared - so that an INVOP
187 * fault will only be reported as FLTSUB once.
188 * This might not happen if the mask is being changed.
189 */
190#define FPE_xxx1(f) (f & EN_SW_INVOP \
191 ? (f & EN_SW_STACK_FAULT ? FPE_FLTSUB : FPE_FLTINV) \
192 : f & EN_SW_ZERODIV ? FPE_FLTDIV \
193 : f & EN_SW_DENORM ? FPE_FLTUND \
194 : f & EN_SW_OVERFLOW ? FPE_FLTOVF \
195 : f & EN_SW_UNDERFLOW ? FPE_FLTUND \
196 : f & EN_SW_PRECLOSS ? FPE_FLTRES \
197 : f & EN_SW_STACK_FAULT ? FPE_FLTSUB : 0)
198#define FPE_xxx2(f) FPE_xxx1(f), FPE_xxx1((f + 1))
199#define FPE_xxx4(f) FPE_xxx2(f), FPE_xxx2((f + 2))
200#define FPE_xxx8(f) FPE_xxx4(f), FPE_xxx4((f + 4))
201#define FPE_xxx16(f) FPE_xxx8(f), FPE_xxx8((f + 8))
202#define FPE_xxx32(f) FPE_xxx16(f), FPE_xxx16((f + 16))
203static const uint8_t fpetable[128] = {
204 FPE_xxx32(0), FPE_xxx32(32), FPE_xxx32(64), FPE_xxx32(96)
205};
206#undef FPE_xxx1
207#undef FPE_xxx2
208#undef FPE_xxx4
209#undef FPE_xxx8
210#undef FPE_xxx16
211#undef FPE_xxx32
212
213/*
214 * Init the FPU.
215 *
216 * This might not be strictly necessary since it will be initialised
217 * for each process. However it does no harm.
218 */
219void
220fpuinit(struct cpu_info *ci)
221{
222 if (!i386_fpu_present)
223 return;
224
225 clts();
226 fninit();
227 stts();
228}
229
230static void
231send_sigill(void *rip)
232{
233 /* No fpu (486SX) - send SIGILL */
234 ksiginfo_t ksi;
235
236 x86_enable_intr();
237 KSI_INIT_TRAP(&ksi);
238 ksi.ksi_signo = SIGILL;
239 ksi.ksi_addr = rip;
240 (*curlwp->l_proc->p_emul->e_trapsignal)(curlwp, &ksi);
241 return;
242}
243
244/*
245 * This is a synchronous trap on either an x87 instruction (due to an
246 * unmasked error on the previous x87 instruction) or on an SSE/SSE2 etc
247 * instruction due to an error on the instruction itself.
248 *
249 * If trap actually generates a signal, then the fpu state is saved
250 * and then copied onto the process's user-stack, and then recovered
251 * from there when the signal returns (or from the jmp_buf if the
252 * signal handler exits with a longjmp()).
253 *
254 * All this code need to do is save the reason for the trap.
255 * For x87 interrupts the status word bits need clearing to stop the
256 * trap re-occurring.
257 *
258 * The mxcsr bits are 'sticky' and need clearing to not confuse a later trap.
259 *
260 * Since this is a synchronous trap, the fpu registers must still belong
261 * to the correct process (we trap through an interrupt gate so that
262 * interrupts are disabled on entry).
263 * Interrupts (these better include IPIs) are left disabled until we've
264 * finished looking at fpu registers.
265 *
266 * For amd64 the calling code (in amd64_trap.S) has already checked
267 * that we trapped from usermode.
268 */
269
270void
271fputrap(struct trapframe *frame)
272{
273 uint32_t statbits;
274 ksiginfo_t ksi;
275
276 if (!USERMODE(frame->tf_cs, frame->tf_eflags))
277 panic("fpu trap from kernel, trapframe %p\n", frame);
278
279 if (i386_fpu_present == 0) {
280 send_sigill((void *)X86_TF_RIP(frame));
281 return;
282 }
283
284 /*
285 * At this point, fpcurlwp should be curlwp. If it wasn't, the TS bit
286 * should be set, and we should have gotten a DNA exception.
287 */
288 KASSERT(curcpu()->ci_fpcurlwp == curlwp);
289
290 if (frame->tf_trapno == T_XMM) {
291 uint32_t mxcsr;
292 x86_stmxcsr(&mxcsr);
293 statbits = mxcsr;
294 /* Clear the sticky status bits */
295 mxcsr &= ~0x3f;
296 x86_ldmxcsr(&mxcsr);
297
298 /* Remove masked interrupts and non-status bits */
299 statbits &= ~(statbits >> 7) & 0x3f;
300 /* Mark this is an XMM status */
301 statbits |= 0x10000;
302 } else {
303 uint16_t cw, sw;
304 /* Get current control and status words */
305 fnstcw(&cw);
306 fnstsw(&sw);
307 /* Clear any pending exceptions from status word */
308 fnclex();
309
310 /* Removed masked interrupts */
311 statbits = sw & ~(cw & 0x3f);
312 }
313
314 /* Doesn't matter now if we get pre-empted */
315 x86_enable_intr();
316
317 KSI_INIT_TRAP(&ksi);
318 ksi.ksi_signo = SIGFPE;
319 ksi.ksi_addr = (void *)X86_TF_RIP(frame);
320 ksi.ksi_code = fpetable[statbits & 0x7f];
321 ksi.ksi_trap = statbits;
322 (*curlwp->l_proc->p_emul->e_trapsignal)(curlwp, &ksi);
323}
324
325/*
326 * Implement device not available (DNA) exception
327 *
328 * If we were the last lwp to use the FPU, we can simply return.
329 * Otherwise, we save the previous state, if necessary, and restore
330 * our last saved state.
331 *
332 * Called directly from the trap 0x13 entry with interrupts still disabled.
333 */
334void
335fpudna(struct trapframe *frame)
336{
337 struct cpu_info *ci;
338 struct lwp *l, *fl;
339 struct pcb *pcb;
340 int s;
341
342 if (!USERMODE(frame->tf_cs, frame->tf_eflags))
343 panic("fpudna from kernel, ip %p, trapframe %p\n",
344 (void *)X86_TF_RIP(frame), frame);
345
346 if (i386_fpu_present == 0) {
347 send_sigill((void *)X86_TF_RIP(frame));
348 return;
349 }
350
351 ci = curcpu();
352
353 /* Save soft spl level - interrupts are hard disabled */
354 s = splhigh();
355
356 /* Save state on current CPU. */
357 l = ci->ci_curlwp;
358 pcb = lwp_getpcb(l);
359 fl = ci->ci_fpcurlwp;
360 if (fl != NULL) {
361 /*
362 * It seems we can get here on Xen even if we didn't
363 * switch lwp. In this case do nothing
364 */
365 if (fl == l) {
366 KASSERT(pcb->pcb_fpcpu == ci);
367 clts();
368 splx(s);
369 return;
370 }
371 fpusave_cpu(true);
372 }
373
374 /* Save our state if on a remote CPU. */
375 if (pcb->pcb_fpcpu != NULL) {
376 /* Explicitly disable preemption before dropping spl. */
377 kpreempt_disable();
378 splx(s);
379
380 /* Actually enable interrupts */
381 x86_enable_intr();
382
383 fpusave_lwp(l, true);
384 KASSERT(pcb->pcb_fpcpu == NULL);
385 s = splhigh();
386 kpreempt_enable();
387 }
388
389 /*
390 * Restore state on this CPU, or initialize. Ensure that
391 * the entire update is atomic with respect to FPU-sync IPIs.
392 */
393 clts();
394 ci->ci_fpcurlwp = l;
395 pcb->pcb_fpcpu = ci;
396
397 if (i386_use_fxsave) {
398 if (x86_xsave_features != 0) {
399 xrstor(&pcb->pcb_savefpu, x86_xsave_features);
400 } else {
401 /*
402 * AMD FPU's do not restore FIP, FDP, and FOP on
403 * fxrstor, leaking other process's execution history.
404 * Clear them manually by loading a zero.
405 *
406 * Clear the ES bit in the x87 status word if it is
407 * currently set, in order to avoid causing a fault
408 * in the upcoming load.
409 */
410 if (fngetsw() & 0x80)
411 fnclex();
412 fldummy();
413
414 fxrstor(&pcb->pcb_savefpu);
415 }
416 } else {
417 frstor(&pcb->pcb_savefpu);
418 }
419
420 KASSERT(ci == curcpu());
421 splx(s);
422}
423
424/*
425 * Save current CPU's FPU state. Must be called at IPL_HIGH.
426 */
427void
428fpusave_cpu(bool save)
429{
430 struct cpu_info *ci;
431 struct pcb *pcb;
432 struct lwp *l;
433
434 KASSERT(curcpu()->ci_ilevel == IPL_HIGH);
435
436 ci = curcpu();
437 l = ci->ci_fpcurlwp;
438 if (l == NULL) {
439 return;
440 }
441 pcb = lwp_getpcb(l);
442
443 if (save) {
444 clts();
445 if (i386_use_fxsave) {
446 if (x86_xsave_features != 0)
447 xsave(&pcb->pcb_savefpu, x86_xsave_features);
448 else
449 fxsave(&pcb->pcb_savefpu);
450 } else {
451 fnsave(&pcb->pcb_savefpu);
452 }
453 }
454
455 stts();
456 pcb->pcb_fpcpu = NULL;
457 ci->ci_fpcurlwp = NULL;
458}
459
460/*
461 * Save l's FPU state, which may be on this processor or another processor.
462 * It may take some time, so we avoid disabling preemption where possible.
463 * Caller must know that the target LWP is stopped, otherwise this routine
464 * may race against it.
465 */
466void
467fpusave_lwp(struct lwp *l, bool save)
468{
469 struct pcb *pcb = lwp_getpcb(l);
470 struct cpu_info *oci;
471 int s, spins, ticks;
472
473 spins = 0;
474 ticks = hardclock_ticks;
475 for (;;) {
476 s = splhigh();
477 oci = pcb->pcb_fpcpu;
478 if (oci == NULL) {
479 splx(s);
480 break;
481 }
482 if (oci == curcpu()) {
483 KASSERT(oci->ci_fpcurlwp == l);
484 fpusave_cpu(save);
485 splx(s);
486 break;
487 }
488 splx(s);
489#ifdef XEN
490 if (xen_send_ipi(oci, XEN_IPI_SYNCH_FPU) != 0) {
491 panic("xen_send_ipi(%s, XEN_IPI_SYNCH_FPU) failed.",
492 cpu_name(oci));
493 }
494#else /* XEN */
495 x86_send_ipi(oci, X86_IPI_SYNCH_FPU);
496#endif
497 while (pcb->pcb_fpcpu == oci && ticks == hardclock_ticks) {
498 x86_pause();
499 spins++;
500 }
501 if (spins > 100000000) {
502 panic("fpusave_lwp: did not");
503 }
504 }
505}
506
507void
508fpu_set_default_cw(struct lwp *l, unsigned int x87_cw)
509{
510 union savefpu *fpu_save = process_fpframe(l);
511
512 if (i386_use_fxsave)
513 fpu_save->sv_xmm.fx_cw = x87_cw;
514 else
515 fpu_save->sv_87.s87_cw = x87_cw;
516 fpu_save->sv_os.fxo_dflt_cw = x87_cw;
517}
518
519/*
520 * Exec needs to clear the fpu save area to avoid leaking info from the
521 * old process to userspace.
522 */
523void
524fpu_save_area_clear(struct lwp *l, unsigned int x87_cw)
525{
526 union savefpu *fpu_save;
527
528 fpusave_lwp(l, false);
529 fpu_save = process_fpframe(l);
530
531 if (i386_use_fxsave) {
532 memset(&fpu_save->sv_xmm, 0, sizeof(fpu_save->sv_xmm));
533 fpu_save->sv_xmm.fx_mxcsr = __INITIAL_MXCSR__;
534 fpu_save->sv_xmm.fx_mxcsr_mask = __INITIAL_MXCSR_MASK__;
535 fpu_save->sv_xmm.fx_cw = x87_cw;
536 } else {
537 memset(&fpu_save->sv_87, 0, x86_fpu_save_size);
538 fpu_save->sv_87.s87_tw = 0xffff;
539 fpu_save->sv_87.s87_cw = x87_cw;
540 }
541 fpu_save->sv_os.fxo_dflt_cw = x87_cw;
542}
543
544/* For signal handlers the register values don't matter */
545void
546fpu_save_area_reset(struct lwp *l)
547{
548 union savefpu *fpu_save = process_fpframe(l);
549
550 if (i386_use_fxsave) {
551 fpu_save->sv_xmm.fx_mxcsr = __INITIAL_MXCSR__;
552 fpu_save->sv_xmm.fx_mxcsr_mask = __INITIAL_MXCSR_MASK__;
553 fpu_save->sv_xmm.fx_tw = 0;
554 fpu_save->sv_xmm.fx_cw = fpu_save->sv_os.fxo_dflt_cw;
555 } else {
556 fpu_save->sv_87.s87_tw = 0xffff;
557 fpu_save->sv_87.s87_cw = fpu_save->sv_os.fxo_dflt_cw;
558 }
559}
560
561/* During fork the xsave data needs to be copied */
562void
563fpu_save_area_fork(struct pcb *pcb2, const struct pcb *pcb1)
564{
565 ssize_t extra;
566
567 /* The pcb itself has been copied, but the xsave area
568 * extends further. */
569
570 extra = offsetof(struct pcb, pcb_savefpu) + x86_fpu_save_size -
571 sizeof (struct pcb);
572
573 if (extra > 0)
574 memcpy(pcb2 + 1, pcb1 + 1, extra);
575}
576
577
578/*
579 * Write the FP registers.
580 * Buffer has usually come from userspace so should not be trusted.
581 */
582void
583process_write_fpregs_xmm(struct lwp *l, const struct fxsave *fpregs)
584{
585 union savefpu *fpu_save;
586
587 fpusave_lwp(l, false);
588 fpu_save = process_fpframe(l);
589
590 if (i386_use_fxsave) {
591 memcpy(&fpu_save->sv_xmm, fpregs, sizeof(fpu_save->sv_xmm));
592 /* Invalid bits in the mxcsr_mask will cause faults */
593 fpu_save->sv_xmm.fx_mxcsr_mask &= __INITIAL_MXCSR_MASK__;
594 } else {
595 process_xmm_to_s87(fpregs, &fpu_save->sv_87);
596 }
597}
598
599/* We need to use x87 format for 32bit ptrace */
600void
601process_write_fpregs_s87(struct lwp *l, const struct save87 *fpregs)
602{
603 union savefpu *fpu_save;
604
605 if (i386_use_fxsave) {
606 /* Save so we don't lose the xmm registers */
607 fpusave_lwp(l, true);
608 fpu_save = process_fpframe(l);
609 process_s87_to_xmm(fpregs, &fpu_save->sv_xmm);
610 } else {
611 fpusave_lwp(l, false);
612 fpu_save = process_fpframe(l);
613 memcpy(&fpu_save->sv_87, fpregs, sizeof(fpu_save->sv_87));
614 }
615}
616
617/*
618 * Read fpu registers, the buffer is usually copied out to userspace.
619 * Ensure we write to the entire structure.
620 */
621void
622process_read_fpregs_xmm(struct lwp *l, struct fxsave *fpregs)
623{
624 union savefpu *fpu_save;
625
626 fpusave_lwp(l, true);
627 fpu_save = process_fpframe(l);
628
629 if (i386_use_fxsave) {
630 memcpy(fpregs, &fpu_save->sv_xmm, sizeof(fpu_save->sv_xmm));
631 } else {
632 /* This usually gets copied to userspace */
633 memset(fpregs, 0, sizeof(*fpregs));
634 process_s87_to_xmm(&fpu_save->sv_87, fpregs);
635 }
636}
637
638void
639process_read_fpregs_s87(struct lwp *l, struct save87 *fpregs)
640{
641 union savefpu *fpu_save;
642
643 fpusave_lwp(l, true);
644 fpu_save = process_fpframe(l);
645
646 if (i386_use_fxsave) {
647 memset(fpregs, 0, 12);
648 process_xmm_to_s87(&fpu_save->sv_xmm, fpregs);
649 } else {
650 memcpy(fpregs, &fpu_save->sv_87, sizeof(fpu_save->sv_87));
651 }
652}
653