~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/powerpc/kernel/vecemu.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /*
  3  * Routines to emulate some Altivec/VMX instructions, specifically
  4  * those that can trap when given denormalized operands in Java mode.
  5  */
  6 #include <linux/kernel.h>
  7 #include <linux/errno.h>
  8 #include <linux/sched.h>
  9 #include <asm/ptrace.h>
 10 #include <asm/processor.h>
 11 #include <asm/switch_to.h>
 12 #include <linux/uaccess.h>
 13 #include <asm/inst.h>
 14 
 15 /* Functions in vector.S */
 16 extern void vaddfp(vector128 *dst, vector128 *a, vector128 *b);
 17 extern void vsubfp(vector128 *dst, vector128 *a, vector128 *b);
 18 extern void vmaddfp(vector128 *dst, vector128 *a, vector128 *b, vector128 *c);
 19 extern void vnmsubfp(vector128 *dst, vector128 *a, vector128 *b, vector128 *c);
 20 extern void vrefp(vector128 *dst, vector128 *src);
 21 extern void vrsqrtefp(vector128 *dst, vector128 *src);
 22 extern void vexptep(vector128 *dst, vector128 *src);
 23 
 24 static unsigned int exp2s[8] = {
 25         0x800000,
 26         0x8b95c2,
 27         0x9837f0,
 28         0xa5fed7,
 29         0xb504f3,
 30         0xc5672a,
 31         0xd744fd,
 32         0xeac0c7
 33 };
 34 
 35 /*
 36  * Computes an estimate of 2^x.  The `s' argument is the 32-bit
 37  * single-precision floating-point representation of x.
 38  */
 39 static unsigned int eexp2(unsigned int s)
 40 {
 41         int exp, pwr;
 42         unsigned int mant, frac;
 43 
 44         /* extract exponent field from input */
 45         exp = ((s >> 23) & 0xff) - 127;
 46         if (exp > 7) {
 47                 /* check for NaN input */
 48                 if (exp == 128 && (s & 0x7fffff) != 0)
 49                         return s | 0x400000;    /* return QNaN */
 50                 /* 2^-big = 0, 2^+big = +Inf */
 51                 return (s & 0x80000000)? 0: 0x7f800000; /* 0 or +Inf */
 52         }
 53         if (exp < -23)
 54                 return 0x3f800000;      /* 1.0 */
 55 
 56         /* convert to fixed point integer in 9.23 representation */
 57         pwr = (s & 0x7fffff) | 0x800000;
 58         if (exp > 0)
 59                 pwr <<= exp;
 60         else
 61                 pwr >>= -exp;
 62         if (s & 0x80000000)
 63                 pwr = -pwr;
 64 
 65         /* extract integer part, which becomes exponent part of result */
 66         exp = (pwr >> 23) + 126;
 67         if (exp >= 254)
 68                 return 0x7f800000;
 69         if (exp < -23)
 70                 return 0;
 71 
 72         /* table lookup on top 3 bits of fraction to get mantissa */
 73         mant = exp2s[(pwr >> 20) & 7];
 74 
 75         /* linear interpolation using remaining 20 bits of fraction */
 76         asm("mulhwu %0,%1,%2" : "=r" (frac)
 77             : "r" (pwr << 12), "r" (0x172b83ff));
 78         asm("mulhwu %0,%1,%2" : "=r" (frac) : "r" (frac), "r" (mant));
 79         mant += frac;
 80 
 81         if (exp >= 0)
 82                 return mant + (exp << 23);
 83 
 84         /* denormalized result */
 85         exp = -exp;
 86         mant += 1 << (exp - 1);
 87         return mant >> exp;
 88 }
 89 
 90 /*
 91  * Computes an estimate of log_2(x).  The `s' argument is the 32-bit
 92  * single-precision floating-point representation of x.
 93  */
 94 static unsigned int elog2(unsigned int s)
 95 {
 96         int exp, mant, lz, frac;
 97 
 98         exp = s & 0x7f800000;
 99         mant = s & 0x7fffff;
100         if (exp == 0x7f800000) {        /* Inf or NaN */
101                 if (mant != 0)
102                         s |= 0x400000;  /* turn NaN into QNaN */
103                 return s;
104         }
105         if ((exp | mant) == 0)          /* +0 or -0 */
106                 return 0xff800000;      /* return -Inf */
107 
108         if (exp == 0) {
109                 /* denormalized */
110                 asm("cntlzw %0,%1" : "=r" (lz) : "r" (mant));
111                 mant <<= lz - 8;
112                 exp = (-118 - lz) << 23;
113         } else {
114                 mant |= 0x800000;
115                 exp -= 127 << 23;
116         }
117 
118         if (mant >= 0xb504f3) {                         /* 2^0.5 * 2^23 */
119                 exp |= 0x400000;                        /* 0.5 * 2^23 */
120                 asm("mulhwu %0,%1,%2" : "=r" (mant)
121                     : "r" (mant), "r" (0xb504f334));    /* 2^-0.5 * 2^32 */
122         }
123         if (mant >= 0x9837f0) {                         /* 2^0.25 * 2^23 */
124                 exp |= 0x200000;                        /* 0.25 * 2^23 */
125                 asm("mulhwu %0,%1,%2" : "=r" (mant)
126                     : "r" (mant), "r" (0xd744fccb));    /* 2^-0.25 * 2^32 */
127         }
128         if (mant >= 0x8b95c2) {                         /* 2^0.125 * 2^23 */
129                 exp |= 0x100000;                        /* 0.125 * 2^23 */
130                 asm("mulhwu %0,%1,%2" : "=r" (mant)
131                     : "r" (mant), "r" (0xeac0c6e8));    /* 2^-0.125 * 2^32 */
132         }
133         if (mant > 0x800000) {                          /* 1.0 * 2^23 */
134                 /* calculate (mant - 1) * 1.381097463 */
135                 /* 1.381097463 == 0.125 / (2^0.125 - 1) */
136                 asm("mulhwu %0,%1,%2" : "=r" (frac)
137                     : "r" ((mant - 0x800000) << 1), "r" (0xb0c7cd3a));
138                 exp += frac;
139         }
140         s = exp & 0x80000000;
141         if (exp != 0) {
142                 if (s)
143                         exp = -exp;
144                 asm("cntlzw %0,%1" : "=r" (lz) : "r" (exp));
145                 lz = 8 - lz;
146                 if (lz > 0)
147                         exp >>= lz;
148                 else if (lz < 0)
149                         exp <<= -lz;
150                 s += ((lz + 126) << 23) + exp;
151         }
152         return s;
153 }
154 
155 #define VSCR_SAT        1
156 
157 static int ctsxs(unsigned int x, int scale, unsigned int *vscrp)
158 {
159         int exp, mant;
160 
161         exp = (x >> 23) & 0xff;
162         mant = x & 0x7fffff;
163         if (exp == 255 && mant != 0)
164                 return 0;               /* NaN -> 0 */
165         exp = exp - 127 + scale;
166         if (exp < 0)
167                 return 0;               /* round towards zero */
168         if (exp >= 31) {
169                 /* saturate, unless the result would be -2^31 */
170                 if (x + (scale << 23) != 0xcf000000)
171                         *vscrp |= VSCR_SAT;
172                 return (x & 0x80000000)? 0x80000000: 0x7fffffff;
173         }
174         mant |= 0x800000;
175         mant = (mant << 7) >> (30 - exp);
176         return (x & 0x80000000)? -mant: mant;
177 }
178 
179 static unsigned int ctuxs(unsigned int x, int scale, unsigned int *vscrp)
180 {
181         int exp;
182         unsigned int mant;
183 
184         exp = (x >> 23) & 0xff;
185         mant = x & 0x7fffff;
186         if (exp == 255 && mant != 0)
187                 return 0;               /* NaN -> 0 */
188         exp = exp - 127 + scale;
189         if (exp < 0)
190                 return 0;               /* round towards zero */
191         if (x & 0x80000000) {
192                 /* negative => saturate to 0 */
193                 *vscrp |= VSCR_SAT;
194                 return 0;
195         }
196         if (exp >= 32) {
197                 /* saturate */
198                 *vscrp |= VSCR_SAT;
199                 return 0xffffffff;
200         }
201         mant |= 0x800000;
202         mant = (mant << 8) >> (31 - exp);
203         return mant;
204 }
205 
206 /* Round to floating integer, towards 0 */
207 static unsigned int rfiz(unsigned int x)
208 {
209         int exp;
210 
211         exp = ((x >> 23) & 0xff) - 127;
212         if (exp == 128 && (x & 0x7fffff) != 0)
213                 return x | 0x400000;    /* NaN -> make it a QNaN */
214         if (exp >= 23)
215                 return x;               /* it's an integer already (or Inf) */
216         if (exp < 0)
217                 return x & 0x80000000;  /* |x| < 1.0 rounds to 0 */
218         return x & ~(0x7fffff >> exp);
219 }
220 
221 /* Round to floating integer, towards +/- Inf */
222 static unsigned int rfii(unsigned int x)
223 {
224         int exp, mask;
225 
226         exp = ((x >> 23) & 0xff) - 127;
227         if (exp == 128 && (x & 0x7fffff) != 0)
228                 return x | 0x400000;    /* NaN -> make it a QNaN */
229         if (exp >= 23)
230                 return x;               /* it's an integer already (or Inf) */
231         if ((x & 0x7fffffff) == 0)
232                 return x;               /* +/-0 -> +/-0 */
233         if (exp < 0)
234                 /* 0 < |x| < 1.0 rounds to +/- 1.0 */
235                 return (x & 0x80000000) | 0x3f800000;
236         mask = 0x7fffff >> exp;
237         /* mantissa overflows into exponent - that's OK,
238            it can't overflow into the sign bit */
239         return (x + mask) & ~mask;
240 }
241 
242 /* Round to floating integer, to nearest */
243 static unsigned int rfin(unsigned int x)
244 {
245         int exp, half;
246 
247         exp = ((x >> 23) & 0xff) - 127;
248         if (exp == 128 && (x & 0x7fffff) != 0)
249                 return x | 0x400000;    /* NaN -> make it a QNaN */
250         if (exp >= 23)
251                 return x;               /* it's an integer already (or Inf) */
252         if (exp < -1)
253                 return x & 0x80000000;  /* |x| < 0.5 -> +/-0 */
254         if (exp == -1)
255                 /* 0.5 <= |x| < 1.0 rounds to +/- 1.0 */
256                 return (x & 0x80000000) | 0x3f800000;
257         half = 0x400000 >> exp;
258         /* add 0.5 to the magnitude and chop off the fraction bits */
259         return (x + half) & ~(0x7fffff >> exp);
260 }
261 
262 int emulate_altivec(struct pt_regs *regs)
263 {
264         ppc_inst_t instr;
265         unsigned int i, word;
266         unsigned int va, vb, vc, vd;
267         vector128 *vrs;
268 
269         if (get_user_instr(instr, (void __user *)regs->nip))
270                 return -EFAULT;
271 
272         word = ppc_inst_val(instr);
273         if (ppc_inst_primary_opcode(instr) != 4)
274                 return -EINVAL;         /* not an altivec instruction */
275         vd = (word >> 21) & 0x1f;
276         va = (word >> 16) & 0x1f;
277         vb = (word >> 11) & 0x1f;
278         vc = (word >> 6) & 0x1f;
279 
280         vrs = current->thread.vr_state.vr;
281         switch (word & 0x3f) {
282         case 10:
283                 switch (vc) {
284                 case 0: /* vaddfp */
285                         vaddfp(&vrs[vd], &vrs[va], &vrs[vb]);
286                         break;
287                 case 1: /* vsubfp */
288                         vsubfp(&vrs[vd], &vrs[va], &vrs[vb]);
289                         break;
290                 case 4: /* vrefp */
291                         vrefp(&vrs[vd], &vrs[vb]);
292                         break;
293                 case 5: /* vrsqrtefp */
294                         vrsqrtefp(&vrs[vd], &vrs[vb]);
295                         break;
296                 case 6: /* vexptefp */
297                         for (i = 0; i < 4; ++i)
298                                 vrs[vd].u[i] = eexp2(vrs[vb].u[i]);
299                         break;
300                 case 7: /* vlogefp */
301                         for (i = 0; i < 4; ++i)
302                                 vrs[vd].u[i] = elog2(vrs[vb].u[i]);
303                         break;
304                 case 8:         /* vrfin */
305                         for (i = 0; i < 4; ++i)
306                                 vrs[vd].u[i] = rfin(vrs[vb].u[i]);
307                         break;
308                 case 9:         /* vrfiz */
309                         for (i = 0; i < 4; ++i)
310                                 vrs[vd].u[i] = rfiz(vrs[vb].u[i]);
311                         break;
312                 case 10:        /* vrfip */
313                         for (i = 0; i < 4; ++i) {
314                                 u32 x = vrs[vb].u[i];
315                                 x = (x & 0x80000000)? rfiz(x): rfii(x);
316                                 vrs[vd].u[i] = x;
317                         }
318                         break;
319                 case 11:        /* vrfim */
320                         for (i = 0; i < 4; ++i) {
321                                 u32 x = vrs[vb].u[i];
322                                 x = (x & 0x80000000)? rfii(x): rfiz(x);
323                                 vrs[vd].u[i] = x;
324                         }
325                         break;
326                 case 14:        /* vctuxs */
327                         for (i = 0; i < 4; ++i)
328                                 vrs[vd].u[i] = ctuxs(vrs[vb].u[i], va,
329                                         &current->thread.vr_state.vscr.u[3]);
330                         break;
331                 case 15:        /* vctsxs */
332                         for (i = 0; i < 4; ++i)
333                                 vrs[vd].u[i] = ctsxs(vrs[vb].u[i], va,
334                                         &current->thread.vr_state.vscr.u[3]);
335                         break;
336                 default:
337                         return -EINVAL;
338                 }
339                 break;
340         case 46:        /* vmaddfp */
341                 vmaddfp(&vrs[vd], &vrs[va], &vrs[vb], &vrs[vc]);
342                 break;
343         case 47:        /* vnmsubfp */
344                 vnmsubfp(&vrs[vd], &vrs[va], &vrs[vb], &vrs[vc]);
345                 break;
346         default:
347                 return -EINVAL;
348         }
349 
350         return 0;
351 }
352 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php