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
78struct	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 */
89struct	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
98static 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
109bool_t
110xdr_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 */
291struct	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 */
299struct  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
312static 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
325bool_t
326xdr_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 */
510bool_t
511xdr_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