1/* $NetBSD: convert_xmm_s87.c,v 1.3 2014/02/15 22:20:42 dsl Exp $ */
2
3/*-
4 * Copyright (c) 1998, 2000, 2001, 2008 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Charles M. Hannum; by Jason R. Thorpe of Wasabi Systems, Inc.
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#include <sys/cdefs.h>
33__KERNEL_RCSID(0, "$NetBSD: convert_xmm_s87.c,v 1.3 2014/02/15 22:20:42 dsl Exp $");
34
35
36#include <sys/param.h>
37#include <sys/systm.h>
38#include <x86/fpu.h>
39
40void
41process_xmm_to_s87(const struct fxsave *sxmm, struct save87 *s87)
42{
43 unsigned int tag, ab_tag;
44 const struct fpaccfx *fx_reg;
45 struct fpacc87 *s87_reg;
46 int i;
47
48 /*
49 * For historic reasons core dumps and ptrace all use the old save87
50 * layout. Convert the important parts.
51 * getucontext gets what we give it.
52 * setucontext should return something given by getucontext, but
53 * we are (at the moment) willing to change it.
54 *
55 * It really isn't worth setting the 'tag' bits to 01 (zero) or
56 * 10 (NaN etc) since the processor will set any internal bits
57 * correctly when the value is loaded (the 287 believed them).
58 *
59 * Additionally the s87_tw and s87_tw are 'indexed' by the actual
60 * register numbers, whereas the registers themselves have ST(0)
61 * first. Pairing the values and tags can only be done with
62 * reference to the 'top of stack'.
63 *
64 * If any x87 registers are used, they will typically be from
65 * r7 downwards - so the high bits of the tag register indicate
66 * used registers. The conversions are not optimised for this.
67 *
68 * The ABI we use requires the FP stack to be empty on every
69 * function call. I think this means that the stack isn't expected
70 * to overflow - overflow doesn't drop a core in my testing.
71 *
72 * Note that this code writes to all of the 's87' structure that
73 * actually gets written to userspace.
74 */
75
76 /* FPU control/status */
77 s87->s87_cw = sxmm->fx_cw;
78 s87->s87_sw = sxmm->fx_sw;
79 /* tag word handled below */
80 s87->s87_ip = sxmm->fx_ip;
81 s87->s87_opcode = sxmm->fx_opcode;
82 s87->s87_dp = sxmm->fx_dp;
83
84 /* FP registers (in stack order) */
85 fx_reg = sxmm->fx_87_ac;
86 s87_reg = s87->s87_ac;
87 for (i = 0; i < 8; fx_reg++, s87_reg++, i++)
88 *s87_reg = fx_reg->r;
89
90 /* Tag word and registers. */
91 ab_tag = sxmm->fx_tw & 0xff; /* Bits set if valid */
92 if (ab_tag == 0) {
93 /* none used */
94 s87->s87_tw = 0xffff;
95 return;
96 }
97
98 tag = 0;
99 /* Separate bits of abridged tag word with zeros */
100 for (i = 0x80; i != 0; tag <<= 1, i >>= 1)
101 tag |= ab_tag & i;
102 /* Replicate and invert so that 0 => 0b11 and 1 => 0b00 */
103 s87->s87_tw = (tag | tag >> 1) ^ 0xffff;
104}
105
106void
107process_s87_to_xmm(const struct save87 *s87, struct fxsave *sxmm)
108{
109 unsigned int tag, ab_tag;
110 struct fpaccfx *fx_reg;
111 const struct fpacc87 *s87_reg;
112 int i;
113
114 /*
115 * ptrace gives us registers in the save87 format and
116 * we must convert them to the correct format.
117 *
118 * This code is normally used when overwriting the processes
119 * registers (in the pcb), so it musn't change any other fields.
120 *
121 * There is a lot of pad in 'struct fxsave', if the destination
122 * is written to userspace, it must be zeroed first.
123 */
124
125 /* FPU control/status */
126 sxmm->fx_cw = s87->s87_cw;
127 sxmm->fx_sw = s87->s87_sw;
128 /* tag word handled below */
129 sxmm->fx_ip = s87->s87_ip;
130 sxmm->fx_opcode = s87->s87_opcode;
131 sxmm->fx_dp = s87->s87_dp;
132
133 /* Tag word */
134 tag = s87->s87_tw; /* 0b11 => unused */
135 if (tag == 0xffff) {
136 /* All unused - values don't matter, zero for safety */
137 sxmm->fx_tw = 0;
138 memset(&sxmm->fx_87_ac, 0, sizeof sxmm->fx_87_ac);
139 return;
140 }
141
142 tag ^= 0xffff; /* So 0b00 is unused */
143 tag |= tag >> 1; /* Look at even bits */
144 ab_tag = 0;
145 i = 1;
146 do
147 ab_tag |= tag & i;
148 while ((tag >>= 1) >= (i <<= 1));
149 sxmm->fx_tw = ab_tag;
150
151 /* FP registers (in stack order) */
152 fx_reg = sxmm->fx_87_ac;
153 s87_reg = s87->s87_ac;
154 for (i = 0; i < 8; fx_reg++, s87_reg++, i++)
155 fx_reg->r = *s87_reg;
156}
157