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 | |
40 | void |
41 | process_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 | |
106 | void |
107 | process_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 | |