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