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