1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29 /*
30 * Portions of this source code were derived from Berkeley
31 * 4.3 BSD under license from the Regents of the University of
32 * California.
33 */
34
35 #pragma ident "%Z%%M% %I% %E% SMI"
36
37 /*
38 * Generic XDR routines impelmentation.
39 *
40 * These are the "floating point" xdr routines used to (de)serialize
41 * most common data items. See xdr.h for more info on the interface to
42 * xdr.
43 */
44
45 #include "mt.h"
46 #include <sys/types.h>
47 #include <stdio.h>
48 #include <rpc/types.h>
49 #include <rpc/xdr.h>
50
51 /*
52 * This routine works on Suns, 3b2, 68000s, 386 and Vaxen in a manner
53 * which is very efficient as bit twiddling is all that is needed. All
54 * other machines can use this code but the code is inefficient as
55 * various mathematical operations are used to generate the ieee format.
56 * In addition rounding errors may occur due to the calculations involved.
57 * To be most efficient, new machines should have their own ifdefs.
58 * The encoding routines will fail if the machines try to encode a
59 * float/double whose value can not be represented by the ieee format,
60 * e.g. the exponent is too big/small.
61 * ieee largest float = (2 ^ 128) * 0x1.fffff
62 * ieee smallest float = (2 ^ -127) * 0x1.00000
63 * ieee largest double = (2 ^ 1024) * 0x1.fffff
64 * ieee smallest double = (2 ^ -1023) * 0x1.00000
65 * The decoding routines assumes that the receiving machine can handle
66 * floats/doubles as large/small as the values stated above. If you
67 * use a machine which can not represent these values, you will need
68 * to put ifdefs in the decode sections to identify areas of failure.
69 */
70
71 #if defined(vax)
72
73 /*
74 * What IEEE single precision floating point looks like this on a
75 * vax.
76 */
77
78 struct ieee_single {
79 unsigned int mantissa: 23;
80 unsigned int exp : 8;
81 unsigned int sign : 1;
82 };
83
84 #define IEEE_SNG_BIAS 0x7f
85 #define VAX_SNG_BIAS 0x81
86
87
88 /* Vax single precision floating point */
89 struct vax_single {
90 unsigned int mantissa1 : 7;
91 unsigned int exp : 8;
92 unsigned int sign : 1;
93 unsigned int mantissa2 : 16;
94 };
95
96 #define VAX_SNG_BIAS 0x81
97
98 static struct sgl_limits {
99 struct vax_single s;
100 struct ieee_single ieee;
101 } sgl_limits[2] = {
102 {{ 0x7f, 0xff, 0x0, 0xffff }, /* Max Vax */
103 { 0x0, 0xff, 0x0 }}, /* Max IEEE */
104 {{ 0x0, 0x0, 0x0, 0x0 }, /* Min Vax */
105 { 0x0, 0x0, 0x0 }} /* Min IEEE */
106 };
107 #endif /* vax */
108
109 bool_t
xdr_float(XDR * xdrs,float * fp)110 xdr_float(XDR *xdrs, float *fp)
111 {
112 #if defined(vax)
113 struct ieee_single is;
114 struct vax_single vs, *vsp;
115 struct sgl_limits *lim;
116 size_t i;
117 #endif
118
119 switch (xdrs->x_op) {
120
121 case XDR_ENCODE:
122 #if defined(mc68000) || defined(sparc) || defined(u3b2) || \
123 defined(u3b15) || defined(i386) || defined(amd64)
124 return (XDR_PUTINT32(xdrs, (int *)fp));
125 #else
126 #if defined(vax)
127 vs = *((struct vax_single *)fp);
128 if ((vs.exp == 1) || (vs.exp == 2)) {
129 /* map these to subnormals */
130 is.exp = 0;
131 is.mantissa = (vs.mantissa1 << 16) | vs.mantissa2;
132 /* lose some precision */
133 is.mantissa >>= 3 - vs.exp;
134 is.mantissa += (1 << (20 + vs.exp));
135 goto shipit;
136 }
137 for (i = 0, lim = sgl_limits;
138 i < (int)(sizeof (sgl_limits) /
139 sizeof (struct sgl_limits));
140 i++, lim++) {
141 if ((vs.mantissa2 == lim->s.mantissa2) &&
142 (vs.exp == lim->s.exp) &&
143 (vs.mantissa1 == lim->s.mantissa1)) {
144 is = lim->ieee;
145 goto shipit;
146 }
147 }
148 is.exp = vs.exp - VAX_SNG_BIAS + IEEE_SNG_BIAS;
149 is.mantissa = (vs.mantissa1 << 16) | vs.mantissa2;
150 shipit:
151 is.sign = vs.sign;
152 return (XDR_PUTINT32(xdrs, (int32_t *)&is));
153 #else
154 {
155 /*
156 * Every machine can do this, its just not very efficient.
157 * In addtion, some rounding errors may occur do to the
158 * calculations involved.
159 */
160 float f;
161 int neg = 0;
162 int exp = 0;
163 int32_t val;
164
165 f = *fp;
166 if (f == 0) {
167 val = 0;
168 return (XDR_PUTINT32(xdrs, &val));
169 }
170 if (f < 0) {
171 f = 0 - f;
172 neg = 1;
173 }
174 while (f < 1) {
175 f = f * 2;
176 --exp;
177 }
178 while (f >= 2) {
179 f = f/2;
180 ++exp;
181 }
182 if ((exp > 128) || (exp < -127)) {
183 /* over or under flowing ieee exponent */
184 return (FALSE);
185 }
186 val = neg;
187 val = val << 8; /* for the exponent */
188 val += 127 + exp; /* 127 is the bias */
189 val = val << 23; /* for the mantissa */
190 val += (int32_t)((f - 1) * 8388608); /* 2 ^ 23 */
191 return (XDR_PUTINT32(xdrs, &val));
192 }
193 #endif
194 #endif
195
196 case XDR_DECODE:
197 #if defined(mc68000) || defined(sparc) || defined(u3b2) || \
198 defined(u3b15) || defined(i386) || defined(amd64)
199 return (XDR_GETINT32(xdrs, (int *)fp));
200 #else
201 #if defined(vax)
202 vsp = (struct vax_single *)fp;
203 if (!XDR_GETINT32(xdrs, (int32_t *)&is))
204 return (FALSE);
205
206 for (i = 0, lim = sgl_limits;
207 i < (int)(sizeof (sgl_limits) /
208 sizeof (struct sgl_limits));
209 i++, lim++) {
210 if ((is.exp == lim->ieee.exp) &&
211 (is.mantissa == lim->ieee.mantissa)) {
212 *vsp = lim->s;
213 goto doneit;
214 } else if ((is.exp == 0) && (lim->ieee.exp == 0)) {
215 /* Special Case */
216 unsigned tmp = is.mantissa >> 20;
217 if (tmp >= 4) {
218 vsp->exp = 2;
219 } else if (tmp >= 2) {
220 vsp->exp = 1;
221 } else {
222 *vsp = min.s;
223 break;
224 } /* else */
225 tmp = is.mantissa - (1 << (20 + vsp->exp));
226 tmp <<= 3 - vsp->exp;
227 vsp->mantissa2 = tmp;
228 vsp->mantissa1 = (tmp >> 16);
229 goto doneit;
230 }
231 vsp->exp = is.exp - IEEE_SNG_BIAS + VAX_SNG_BIAS;
232 vsp->mantissa2 = is.mantissa;
233 vsp->mantissa1 = (is.mantissa >> 16);
234 doneit:
235 vsp->sign = is.sign;
236 return (TRUE);
237 #else
238 {
239 /*
240 * Every machine can do this, its just not very
241 * efficient. It assumes that the decoding machine's
242 * float can represent any value in the range of
243 * ieee largest float = (2 ^ 128) * 0x1.fffff
244 * to
245 * ieee smallest float = (2 ^ -127) * 0x1.00000
246 * In addtion, some rounding errors may occur do to the
247 * calculations involved.
248 */
249 float f;
250 int neg = 0;
251 int exp = 0;
252 int32_t val;
253
254 if (!XDR_GETINT32(xdrs, (int32_t *)&val))
255 return (FALSE);
256 neg = val & 0x80000000;
257 exp = (val & 0x7f800000) >> 23;
258 exp -= 127; /* subtract exponent base */
259 f = (val & 0x007fffff) * 0.00000011920928955078125;
260 /* 2 ^ -23 */
261 f++;
262 while (exp != 0) {
263 if (exp < 0) {
264 f = f/2.0;
265 ++exp;
266 } else {
267 f = f * 2.0;
268 --exp;
269 }
270 }
271 if (neg)
272 f = 0 - f;
273 *fp = f;
274 }
275 return (TRUE);
276 #endif
277 #endif
278
279 case XDR_FREE:
280 return (TRUE);
281 }
282 return (FALSE);
283 }
284
285 /*
286 * This routine works on Suns (Sky / 68000's) and Vaxen.
287 */
288
289 #if defined(vax)
290 /* What IEEE double precision floating point looks like on a Vax */
291 struct ieee_double {
292 unsigned int mantissa1 : 20;
293 unsigned int exp : 11;
294 unsigned int sign : 1;
295 unsigned int mantissa2 : 32;
296 };
297
298 /* Vax double precision floating point */
299 struct vax_double {
300 unsigned int mantissa1 : 7;
301 unsigned int exp : 8;
302 unsigned int sign : 1;
303 unsigned int mantissa2 : 16;
304 unsigned int mantissa3 : 16;
305 unsigned int mantissa4 : 16;
306 };
307
308 #define VAX_DBL_BIAS 0x81
309 #define IEEE_DBL_BIAS 0x3ff
310 #define MASK(nbits) ((1 << nbits) - 1)
311
312 static struct dbl_limits {
313 struct vax_double d;
314 struct ieee_double ieee;
315 } dbl_limits[2] = {
316 {{ 0x7f, 0xff, 0x0, 0xffff, 0xffff, 0xffff }, /* Max Vax */
317 { 0x0, 0x7ff, 0x0, 0x0 }}, /* Max IEEE */
318 {{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, /* Min Vax */
319 { 0x0, 0x0, 0x0, 0x0 }} /* Min IEEE */
320 };
321
322 #endif /* vax */
323
324
325 bool_t
326 xdr_double(XDR *xdrs, double *dp)
327 {
328 int *lp;
329 #if defined(vax)
330 struct ieee_double id;
331 struct vax_double vd;
332 struct dbl_limits *lim;
333 size_t i;
334 #endif
335
336 switch (xdrs->x_op) {
337
338 case XDR_ENCODE:
339 #if defined(mc68000) || defined(u3b2) || defined(u3b15) || \
340 defined(_LONG_LONG_HTOL)
341 lp = (int *)dp;
342 return (XDR_PUTINT32(xdrs, lp++) && XDR_PUTINT32(xdrs, lp));
343 #else
344 #if defined(_LONG_LONG_LTOH)
345 lp = (int *)dp;
346 lp++;
347 return (XDR_PUTINT32(xdrs, lp--) && XDR_PUTINT32(xdrs, lp));
348 #else
349 #if defined(vax)
350 vd = *((struct vax_double *)dp);
351 for (i = 0, lim = dbl_limits;
352 i < (int)(sizeof (dbl_limits) /
353 sizeof (struct dbl_limits));
354 i++, lim++) {
355 if ((vd.mantissa4 == lim->d.mantissa4) &&
356 (vd.mantissa3 == lim->d.mantissa3) &&
357 (vd.mantissa2 == lim->d.mantissa2) &&
358 (vd.mantissa1 == lim->d.mantissa1) &&
359 (vd.exp == lim->d.exp)) {
360 id = lim->ieee;
361 goto shipit;
362 }
363 }
364 id.exp = vd.exp - VAX_DBL_BIAS + IEEE_DBL_BIAS;
365 id.mantissa1 = (vd.mantissa1 << 13) | (vd.mantissa2 >> 3);
366 id.mantissa2 = ((vd.mantissa2 & MASK(3)) << 29) |
367 (vd.mantissa3 << 13) |
368 ((vd.mantissa4 >> 3) & MASK(13));
369 shipit:
370 id.sign = vd.sign;
371 lp = (int32_t *)&id;
372 #else
373 {
374 /*
375 * Every machine can do this, its just not very efficient.
376 * In addtion, some rounding errors may occur do to the
377 * calculations involved.
378 */
379 double d;
380 int neg = 0;
381 int exp = 0;
382 int32_t val[2];
383
384 d = *dp;
385 if (d == 0) {
386 val[0] = 0;
387 val[1] = 0;
388 lp = val;
389 return (XDR_PUTINT32(xdrs, lp++) &&
390 XDR_PUTINT32(xdrs, lp));
391 }
392 if (d < 0) {
393 d = 0 - d;
394 neg = 1;
395 }
396 while (d < 1) {
397 d = d * 2;
398 --exp;
399 }
400 while (d >= 2) {
401 d = d/2;
402 ++exp;
403 }
404 if ((exp > 1024) || (exp < -1023)) {
405 /* over or under flowing ieee exponent */
406 return (FALSE);
407 }
408 val[0] = neg;
409 val[0] = val[0] << 11; /* for the exponent */
410 val[0] += 1023 + exp; /* 1023 is the bias */
411 val[0] = val[0] << 20; /* for the mantissa */
412 val[0] += (int32_t)((d - 1) * 1048576); /* 2 ^ 20 */
413 val[1] += (int32_t)((((d - 1) * 1048576) - val[0])
414 * 4294967296);
415 /* 2 ^ 32 */
416 lp = val;
417 }
418 #endif
419 return (XDR_PUTINT32(xdrs, lp++) && XDR_PUTINT32(xdrs, lp));
420 #endif
421 #endif
422
423 case XDR_DECODE:
424 #if defined(mc68000) || defined(u3b2) || defined(u3b15) || \
425 defined(_LONG_LONG_HTOL)
426 lp = (int *)dp;
427 return (XDR_GETINT32(xdrs, lp++) && XDR_GETINT32(xdrs, lp));
428 #else
429 #if defined(_LONG_LONG_LTOH)
430 lp = (int *)dp;
431 lp++;
432 return (XDR_GETINT32(xdrs, lp--) && XDR_GETINT32(xdrs, lp));
433 #else
434 #if defined(vax)
435 lp = (int32_t *)&id;
436 if (!XDR_GETINT32(xdrs, lp++) || !XDR_GETINT32(xdrs, lp))
437 return (FALSE);
438 for (i = 0, lim = dbl_limits;
439 i < sizeof (dbl_limits)/sizeof (struct dbl_limits);
440 i++, lim++) {
441 if ((id.mantissa2 == lim->ieee.mantissa2) &&
442 (id.mantissa1 == lim->ieee.mantissa1) &&
443 (id.exp == lim->ieee.exp)) {
444 vd = lim->d;
445 goto doneit;
446 }
447 }
448 vd.exp = id.exp - IEEE_DBL_BIAS + VAX_DBL_BIAS;
449 vd.mantissa1 = (id.mantissa1 >> 13);
450 vd.mantissa2 = ((id.mantissa1 & MASK(13)) << 3) |
451 (id.mantissa2 >> 29);
452 vd.mantissa3 = (id.mantissa2 >> 13);
453 vd.mantissa4 = (id.mantissa2 << 3);
454 doneit:
455 vd.sign = id.sign;
456 *dp = *((double *)&vd);
457 return (TRUE);
458 #else
459 {
460 /*
461 * Every machine can do this, its just not very
462 * efficient. It assumes that the decoding machine's
463 * double can represent any value in the range of
464 * ieee largest double = (2 ^ 1024) * 0x1.fffffffffffff
465 * to
466 * ieee smallest double = (2 ^ -1023) * 0x1.0000000000000
467 * In addtion, some rounding errors may occur do to the
468 * calculations involved.
469 */
470 double d;
471 int neg = 0;
472 int exp = 0;
473 int32_t val[2];
474
475 lp = val;
476 if (!XDR_GETINT32(xdrs, lp++) || !XDR_GETINT32(xdrs, lp))
477 return (FALSE);
478 neg = val[0] & 0x80000000;
479 exp = (val[0] & 0x7ff00000) >> 20;
480 exp -= 1023; /* subtract exponent base */
481 d = (val[0] & 0x000fffff) * 0.00000095367431640625;
482 /* 2 ^ -20 */
483 d += (val[1] * 0.0000000000000002220446049250313);
484 /* 2 ^ -52 */
485 d++;
486 while (exp != 0) {
487 if (exp < 0) {
488 d = d/2.0;
489 ++exp;
490 } else {
491 d = d * 2.0;
492 --exp;
493 }
494 }
495 if (neg)
496 d = 0 - d;
497 *dp = d;
498 }
499 #endif
500 #endif
501 #endif
502
503 case XDR_FREE:
504 return (TRUE);
505 }
506 return (FALSE);
507 }
508
509 /* ARGSUSED */
510 bool_t
511 xdr_quadruple(XDR *xdrs, long double *fp)
512 {
513 /*
514 * The Sparc uses IEEE FP encoding, so just do a byte copy
515 */
516
517 #if !defined(sparc)
518 return (FALSE);
519 #else
520 switch (xdrs->x_op) {
521 case XDR_ENCODE:
522 return (XDR_PUTBYTES(xdrs, (char *)fp, sizeof (long double)));
523 case XDR_DECODE:
524 return (XDR_GETBYTES(xdrs, (char *)fp, sizeof (long double)));
525 case XDR_FREE:
526 return (TRUE);
527 }
528 return (FALSE);
529 #endif
530 }
531