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 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 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