Home | History | Annotate | Line # | Download | only in x86
      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