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 * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#pragma ident	"%Z%%M%	%I%	%E% SMI"
27
28/*
29 * This file contains kernel property decode routines adopted from
30 * sunddi.c and ddi_impl.c. The following changes have been applied.
31 *
32 * (1) Replace kmem_alloc by malloc. Remove negative indexing
33 * (2) Decoding applies only to prom properties.
34 * (3) For strings, the return value is a composite string, not a string array.
35 * (4) impl_ddi_prop_int_from_prom() uses _LITTLE_ENDIAN from isa_defs.h
36 *
37 * XXX This file should be kept in sync with kernel property encoding.
38 */
39
40#include <stdlib.h>
41#include <strings.h>
42#include <synch.h>
43#include <ctype.h>
44#include <sys/types.h>
45#include <sys/dditypes.h>
46#include <sys/ddipropdefs.h>
47#include <sys/isa_defs.h>
48
49#include "libdevinfo.h"
50
51/*
52 * Return an integer in native machine format from an OBP 1275 integer
53 * representation, which is big-endian, with no particular alignment
54 * guarantees. intp points to the OBP data, and n the number of bytes.
55 *
56 * Byte-swapping may be needed on some implementations.
57 */
58int
59impl_di_prop_int_from_prom(uchar_t *intp, int n)
60{
61	int i = 0;
62
63#if defined(_LITTLE_ENDIAN)
64	intp += n;
65	while (n-- > 0) {
66		i = (i << 8) | *(--intp);
67	}
68#else
69	while (n-- > 0) {
70		i = (i << 8) | *intp++;
71	}
72#endif	/* defined(_LITTLE_ENDIAN) */
73
74	return (i);
75}
76
77/*
78 * Reset the current location pointer in the property handle to the
79 * beginning of the data.
80 */
81void
82di_prop_reset_pos(prop_handle_t *ph)
83{
84	ph->ph_cur_pos = ph->ph_data;
85	ph->ph_save_pos = ph->ph_data;
86}
87
88/*
89 * Restore the current location pointer in the property handle to the
90 * saved position.
91 */
92void
93di_prop_save_pos(prop_handle_t *ph)
94{
95	ph->ph_save_pos = ph->ph_cur_pos;
96}
97
98/*
99 * Save the location that the current location poiner is pointing to..
100 */
101void
102di_prop_restore_pos(prop_handle_t *ph)
103{
104	ph->ph_cur_pos = ph->ph_save_pos;
105}
106
107/*
108 * Property encode/decode functions
109 */
110
111/*
112 * Decode an array of integers property
113 */
114static int
115di_prop_fm_decode_ints(prop_handle_t *ph, void *data, uint_t *nelements)
116{
117	int	i;
118	int	cnt = 0;
119	int	*tmp;
120	int	*intp;
121	int	n;
122
123	/*
124	 * Figure out how many array elements there are by going through the
125	 * data without decoding it first and counting.
126	 */
127	for (;;) {
128		i = DDI_PROP_INT(ph, DDI_PROP_CMD_SKIP, NULL);
129		if (i < 0)
130			break;
131		cnt++;
132	}
133
134	/*
135	 * If there are no elements return an error
136	 */
137	if (cnt == 0)
138		return (DDI_PROP_END_OF_DATA);
139
140	/*
141	 * If we cannot skip through the data, we cannot decode it
142	 */
143	if (i == DDI_PROP_RESULT_ERROR)
144		return (DDI_PROP_CANNOT_DECODE);
145
146	/*
147	 * Reset the data pointer to the beginning of the encoded data
148	 */
149	di_prop_reset_pos(ph);
150
151	/*
152	 * Allocated memory to store the decoded value in.
153	 */
154	if ((intp = malloc(cnt * sizeof (int))) == NULL) {
155		return (DDI_PROP_CANNOT_DECODE);
156	}
157
158
159	/*
160	 * Decode each elemente and place it in the space we just allocated
161	 */
162	tmp = intp;
163	for (n = 0; n < cnt; n++, tmp++) {
164		i = DDI_PROP_INT(ph, DDI_PROP_CMD_DECODE, tmp);
165		if (i < DDI_PROP_RESULT_OK) {
166			/*
167			 * Free the space we just allocated
168			 * and return an error.
169			 */
170			free(intp);
171			switch (i) {
172			case DDI_PROP_RESULT_EOF:
173				return (DDI_PROP_END_OF_DATA);
174
175			case DDI_PROP_RESULT_ERROR:
176				return (DDI_PROP_CANNOT_DECODE);
177			}
178		}
179	}
180
181	*nelements = cnt;
182	*(int **)data = intp;
183
184	return (DDI_PROP_SUCCESS);
185}
186
187/*
188 * Decode an array of strings.
189 */
190static int
191di_prop_fm_decode_strings(prop_handle_t *ph, void *data, uint_t *nelements)
192{
193	int		cnt = 0;
194	char		*strs;
195	char		*tmp;
196	int		size;
197	int		i;
198	int		n;
199	int		nbytes;
200
201	/*
202	 * Figure out how much memory we need for the sum total
203	 */
204	nbytes = 0;
205
206	for (;;) {
207		/*
208		 * Get the decoded size of the current encoded string.
209		 */
210		size = DDI_PROP_STR(ph, DDI_PROP_CMD_GET_DSIZE, NULL);
211		if (size < 0)
212			break;
213
214		cnt++;
215		nbytes += size;
216	}
217
218	/*
219	 * If there are no elements return an error
220	 */
221	if (cnt == 0)
222		return (DDI_PROP_END_OF_DATA);
223
224	/*
225	 * If we cannot skip through the data, we cannot decode it
226	 */
227	if (size == DDI_PROP_RESULT_ERROR)
228		return (DDI_PROP_CANNOT_DECODE);
229
230	/*
231	 * Allocate memory in which to store the decoded strings.
232	 */
233	if ((strs = malloc(nbytes)) == NULL) {
234		return (DDI_PROP_CANNOT_DECODE);
235	}
236
237	/*
238	 * Finally, we can decode each string
239	 */
240	di_prop_reset_pos(ph);
241	tmp = strs;
242	for (n = 0; n < cnt; n++) {
243		i = DDI_PROP_STR(ph, DDI_PROP_CMD_DECODE, tmp);
244		if (i < DDI_PROP_RESULT_OK) {
245			/*
246			 * Free the space we just allocated
247			 * and return an error
248			 */
249			free(strs);
250			switch (i) {
251			case DDI_PROP_RESULT_EOF:
252				return (DDI_PROP_END_OF_DATA);
253
254			case DDI_PROP_RESULT_ERROR:
255				return (DDI_PROP_CANNOT_DECODE);
256			}
257		}
258		tmp += strlen(tmp) + 1;
259	}
260
261	*(char **)data = strs;
262	*nelements = cnt;
263
264	return (DDI_PROP_SUCCESS);
265}
266
267/*
268 * Decode an array of bytes.
269 */
270static int
271di_prop_fm_decode_bytes(prop_handle_t *ph, void *data, uint_t *nelements)
272{
273	uchar_t		*tmp;
274	int		nbytes;
275	int		i;
276
277	/*
278	 * If there are no elements return an error
279	 */
280	if (ph->ph_size == 0)
281		return (DDI_PROP_END_OF_DATA);
282
283	/*
284	 * Get the size of the encoded array of bytes.
285	 */
286	nbytes = DDI_PROP_BYTES(ph, DDI_PROP_CMD_GET_DSIZE,
287		data, ph->ph_size);
288	if (nbytes < DDI_PROP_RESULT_OK) {
289		switch (nbytes) {
290		case DDI_PROP_RESULT_EOF:
291			return (DDI_PROP_END_OF_DATA);
292
293		case DDI_PROP_RESULT_ERROR:
294			return (DDI_PROP_CANNOT_DECODE);
295		}
296	}
297
298	/*
299	 * Allocated memory to store the decoded value in.
300	 */
301	if ((tmp = malloc(nbytes)) == NULL) {
302		return (DDI_PROP_CANNOT_DECODE);
303	}
304
305	/*
306	 * Decode each element and place it in the space we just allocated
307	 */
308	i = DDI_PROP_BYTES(ph, DDI_PROP_CMD_DECODE, tmp, nbytes);
309	if (i < DDI_PROP_RESULT_OK) {
310		/*
311		 * Free the space we just allocated
312		 * and return an error
313		 */
314		free(tmp);
315		switch (i) {
316		case DDI_PROP_RESULT_EOF:
317			return (DDI_PROP_END_OF_DATA);
318
319		case DDI_PROP_RESULT_ERROR:
320			return (DDI_PROP_CANNOT_DECODE);
321		}
322	}
323
324	*(uchar_t **)data = tmp;
325	*nelements = nbytes;
326
327	return (DDI_PROP_SUCCESS);
328}
329
330/*
331 * OBP 1275 integer, string and byte operators.
332 *
333 * DDI_PROP_CMD_DECODE:
334 *
335 *	DDI_PROP_RESULT_ERROR:		cannot decode the data
336 *	DDI_PROP_RESULT_EOF:		end of data
337 *	DDI_PROP_OK:			data was decoded
338 *
339 * DDI_PROP_CMD_ENCODE:
340 *
341 *	DDI_PROP_RESULT_ERROR:		cannot encode the data
342 *	DDI_PROP_RESULT_EOF:		end of data
343 *	DDI_PROP_OK:			data was encoded
344 *
345 * DDI_PROP_CMD_SKIP:
346 *
347 *	DDI_PROP_RESULT_ERROR:		cannot skip the data
348 *	DDI_PROP_RESULT_EOF:		end of data
349 *	DDI_PROP_OK:			data was skipped
350 *
351 * DDI_PROP_CMD_GET_ESIZE:
352 *
353 *	DDI_PROP_RESULT_ERROR:		cannot get encoded size
354 *	DDI_PROP_RESULT_EOF:		end of data
355 *	> 0:				the encoded size
356 *
357 * DDI_PROP_CMD_GET_DSIZE:
358 *
359 *	DDI_PROP_RESULT_ERROR:		cannot get decoded size
360 *	DDI_PROP_RESULT_EOF:		end of data
361 *	> 0:				the decoded size
362 */
363
364/*
365 * OBP 1275 integer operator
366 *
367 * OBP properties are a byte stream of data, so integers may not be
368 * properly aligned. Therefore we need to copy them one byte at a time.
369 */
370int
371di_prop_1275_int(prop_handle_t *ph, uint_t cmd, int *data)
372{
373	int	i;
374
375	switch (cmd) {
376	case DDI_PROP_CMD_DECODE:
377		/*
378		 * Check that there is encoded data
379		 */
380		if (ph->ph_cur_pos == NULL || ph->ph_size == 0)
381			return (DDI_PROP_RESULT_ERROR);
382		if (ph->ph_flags & PH_FROM_PROM) {
383			i = ph->ph_size < PROP_1275_INT_SIZE ?
384			    ph->ph_size : PROP_1275_INT_SIZE;
385			if ((int *)ph->ph_cur_pos > ((int *)ph->ph_data +
386			    ph->ph_size - i))
387				return (DDI_PROP_RESULT_ERROR);
388		} else if (ph->ph_size < sizeof (int) ||
389		    ((int *)ph->ph_cur_pos > ((int *)ph->ph_data +
390		    ph->ph_size - sizeof (int)))) {
391			return (DDI_PROP_RESULT_ERROR);
392		}
393
394		/*
395		 * Copy the integer, using the implementation-specific
396		 * copy function if the property is coming from the PROM.
397		 */
398		if (ph->ph_flags & PH_FROM_PROM) {
399			*data = impl_di_prop_int_from_prom(
400			    (uchar_t *)ph->ph_cur_pos,
401			    (ph->ph_size < PROP_1275_INT_SIZE) ?
402			    ph->ph_size : PROP_1275_INT_SIZE);
403		} else {
404			bcopy(ph->ph_cur_pos, (caddr_t)data, sizeof (int));
405		}
406
407		/*
408		 * Move the current location to the start of the next
409		 * bit of undecoded data.
410		 */
411		ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos + PROP_1275_INT_SIZE;
412		return (DDI_PROP_RESULT_OK);
413
414	case DDI_PROP_CMD_ENCODE:
415		/*
416		 * Check that there is room to encoded the data
417		 */
418		if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
419		    ph->ph_size < PROP_1275_INT_SIZE ||
420		    ((int *)ph->ph_cur_pos > ((int *)ph->ph_data +
421		    ph->ph_size - sizeof (int))))
422			return (DDI_PROP_RESULT_ERROR);
423
424		/*
425		 * Encode the integer into the byte stream one byte at a
426		 * time.
427		 */
428		bcopy((caddr_t)data, ph->ph_cur_pos, sizeof (int));
429
430		/*
431		 * Move the current location to the start of the next bit of
432		 * space where we can store encoded data.
433		 */
434		ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos + PROP_1275_INT_SIZE;
435		return (DDI_PROP_RESULT_OK);
436
437	case DDI_PROP_CMD_SKIP:
438		/*
439		 * Check that there is encoded data
440		 */
441		if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
442		    ph->ph_size < PROP_1275_INT_SIZE)
443			return (DDI_PROP_RESULT_ERROR);
444
445
446		if ((caddr_t)ph->ph_cur_pos ==
447		    (caddr_t)ph->ph_data + ph->ph_size) {
448			return (DDI_PROP_RESULT_EOF);
449		} else if ((caddr_t)ph->ph_cur_pos >
450		    (caddr_t)ph->ph_data + ph->ph_size) {
451			return (DDI_PROP_RESULT_EOF);
452		}
453
454		/*
455		 * Move the current location to the start of the next bit of
456		 * undecoded data.
457		 */
458		ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos + PROP_1275_INT_SIZE;
459		return (DDI_PROP_RESULT_OK);
460
461	case DDI_PROP_CMD_GET_ESIZE:
462		/*
463		 * Return the size of an encoded integer on OBP
464		 */
465		return (PROP_1275_INT_SIZE);
466
467	case DDI_PROP_CMD_GET_DSIZE:
468		/*
469		 * Return the size of a decoded integer on the system.
470		 */
471		return (sizeof (int));
472	}
473
474	/*NOTREACHED*/
475	return (0);	/* keep gcc happy */
476}
477
478/*
479 * 64 bit integer operator
480 *
481 * This is an extension, defined by Sun, to the 1275 integer
482 * operator.  This routine handles the encoding/decoding of
483 * 64 bit integer properties.
484 */
485int
486di_prop_int64_op(prop_handle_t *ph, uint_t cmd, int64_t *data)
487{
488	switch (cmd) {
489	case DDI_PROP_CMD_DECODE:
490		/*
491		 * Check that there is encoded data
492		 */
493		if (ph->ph_cur_pos == NULL || ph->ph_size == 0)
494			return (DDI_PROP_RESULT_ERROR);
495		if (ph->ph_flags & PH_FROM_PROM) {
496			return (DDI_PROP_RESULT_ERROR);
497		} else if (ph->ph_size < sizeof (int64_t) ||
498		    ((int64_t *)ph->ph_cur_pos > ((int64_t *)ph->ph_data +
499		    ph->ph_size - sizeof (int64_t)))) {
500			return (DDI_PROP_RESULT_ERROR);
501		}
502
503		/*
504		 * Copy the integer, using the implementation-specific
505		 * copy function if the property is coming from the PROM.
506		 */
507		bcopy(ph->ph_cur_pos, (caddr_t)data, sizeof (int64_t));
508
509		/*
510		 * Move the current location to the start of the next
511		 * bit of undecoded data.
512		 */
513		ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos +
514		    sizeof (int64_t);
515		return (DDI_PROP_RESULT_OK);
516
517	case DDI_PROP_CMD_ENCODE:
518		/*
519		 * Check that there is room to encoded the data
520		 */
521		if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
522		    ph->ph_size < sizeof (int64_t) ||
523		    ((int64_t *)ph->ph_cur_pos > ((int64_t *)ph->ph_data +
524		    ph->ph_size - sizeof (int64_t))))
525			return (DDI_PROP_RESULT_ERROR);
526
527		/*
528		 * Encode the integer into the byte stream one byte at a
529		 * time.
530		 */
531		bcopy((caddr_t)data, ph->ph_cur_pos, sizeof (int64_t));
532
533		/*
534		 * Move the current location to the start of the next bit of
535		 * space where we can store encoded data.
536		 */
537		ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos +
538		    sizeof (int64_t);
539		return (DDI_PROP_RESULT_OK);
540
541	case DDI_PROP_CMD_SKIP:
542		/*
543		 * Check that there is encoded data
544		 */
545		if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
546		    ph->ph_size < sizeof (int64_t))
547			return (DDI_PROP_RESULT_ERROR);
548
549
550		if ((caddr_t)ph->ph_cur_pos ==
551		    (caddr_t)ph->ph_data + ph->ph_size) {
552			return (DDI_PROP_RESULT_EOF);
553		} else if ((caddr_t)ph->ph_cur_pos >
554		    (caddr_t)ph->ph_data + ph->ph_size) {
555			return (DDI_PROP_RESULT_EOF);
556		}
557
558		/*
559		 * Move the current location to the start of the next bit of
560		 * undecoded data.
561		 */
562		ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos +
563		    sizeof (int64_t);
564		return (DDI_PROP_RESULT_OK);
565
566	case DDI_PROP_CMD_GET_ESIZE:
567		/*
568		 * Return the size of an encoded integer on OBP
569		 */
570		return (sizeof (int64_t));
571
572	case DDI_PROP_CMD_GET_DSIZE:
573		/*
574		 * Return the size of a decoded integer on the system.
575		 */
576		return (sizeof (int64_t));
577	}
578
579	/*NOTREACHED*/
580	return (0);	/* keep gcc happy */
581}
582
583/*
584 * OBP 1275 string operator.
585 *
586 * OBP strings are NULL terminated.
587 */
588int
589di_prop_1275_string(prop_handle_t *ph, uint_t cmd, char *data)
590{
591	int	n;
592	char	*p;
593	char	*end;
594
595	switch (cmd) {
596	case DDI_PROP_CMD_DECODE:
597		/*
598		 * Check that there is encoded data
599		 */
600		if (ph->ph_cur_pos == NULL || ph->ph_size == 0) {
601			return (DDI_PROP_RESULT_ERROR);
602		}
603
604		n = strlen((char *)ph->ph_cur_pos) + 1;
605		if ((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
606		    ph->ph_size - n)) {
607			return (DDI_PROP_RESULT_ERROR);
608		}
609
610		/*
611		 * Copy the NULL terminated string
612		 */
613		bcopy((char *)ph->ph_cur_pos, data, n);
614
615		/*
616		 * Move the current location to the start of the next bit of
617		 * undecoded data.
618		 */
619		ph->ph_cur_pos = (char *)ph->ph_cur_pos + n;
620		return (DDI_PROP_RESULT_OK);
621
622	case DDI_PROP_CMD_ENCODE:
623		/*
624		 * Check that there is room to encoded the data
625		 */
626		if (ph->ph_cur_pos == NULL || ph->ph_size == 0) {
627			return (DDI_PROP_RESULT_ERROR);
628		}
629
630		n = strlen(data) + 1;
631		if ((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
632		    ph->ph_size - n)) {
633			return (DDI_PROP_RESULT_ERROR);
634		}
635
636		/*
637		 * Copy the NULL terminated string
638		 */
639		bcopy(data, (char *)ph->ph_cur_pos, n);
640
641		/*
642		 * Move the current location to the start of the next bit of
643		 * space where we can store encoded data.
644		 */
645		ph->ph_cur_pos = (char *)ph->ph_cur_pos + n;
646		return (DDI_PROP_RESULT_OK);
647
648	case DDI_PROP_CMD_SKIP:
649		/*
650		 * Check that there is encoded data
651		 */
652		if (ph->ph_cur_pos == NULL || ph->ph_size == 0) {
653			return (DDI_PROP_RESULT_ERROR);
654		}
655
656		/*
657		 * Return the string length plus one for the NULL
658		 * We know the size of the property, we need to
659		 * ensure that the string is properly formatted,
660		 * since we may be looking up random OBP data.
661		 */
662		p = (char *)ph->ph_cur_pos;
663		end = (char *)ph->ph_data + ph->ph_size;
664
665		if (p == end) {
666			return (DDI_PROP_RESULT_EOF);
667		}
668
669		/*
670		 * Make sure each char is printable
671		 */
672		for (n = 0; p < end && isascii(*p) && !iscntrl(*p); n++, p++)
673			;
674
675		/* Check termination and non-zero length */
676		if ((*p == 0) && (n != 0)) {
677			ph->ph_cur_pos = p + 1;
678			return (DDI_PROP_RESULT_OK);
679		}
680
681		return (DDI_PROP_RESULT_ERROR);
682
683	case DDI_PROP_CMD_GET_ESIZE:
684		/*
685		 * Return the size of the encoded string on OBP.
686		 */
687		return (strlen(data) + 1);
688
689	case DDI_PROP_CMD_GET_DSIZE:
690		/*
691		 * Return the string length plus one for the NULL
692		 * We know the size of the property, we need to
693		 * ensure that the string is properly formatted,
694		 * since we may be looking up random OBP data.
695		 */
696		p = (char *)ph->ph_cur_pos;
697		end = (char *)ph->ph_data + ph->ph_size;
698		for (n = 0; p < end; n++) {
699			if (*p++ == '\0') {
700				ph->ph_cur_pos = p;
701				return (n+1);
702			}
703		}
704
705		/*
706		 * Add check here to separate EOF and ERROR.
707		 */
708		if (p == end)
709			return (DDI_PROP_RESULT_EOF);
710
711		return (DDI_PROP_RESULT_ERROR);
712
713	}
714
715	/*NOTREACHED*/
716	return (0);	/* keep gcc happy */
717}
718
719/*
720 * OBP 1275 byte operator
721 *
722 * Caller must specify the number of bytes to get. OBP encodes bytes
723 * as a byte so there is a 1-to-1 translation.
724 */
725int
726di_prop_1275_bytes(prop_handle_t *ph, uint_t cmd, uchar_t *data,
727    uint_t nelements)
728{
729	switch (cmd) {
730	case DDI_PROP_CMD_DECODE:
731		/*
732		 * Check that there is encoded data
733		 */
734		if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
735		    ph->ph_size < nelements ||
736		    ((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
737		    ph->ph_size - nelements)))
738			return (DDI_PROP_RESULT_ERROR);
739
740		/*
741		 * Copy out the bytes
742		 */
743		bcopy((char *)ph->ph_cur_pos, (char *)data, nelements);
744
745		/*
746		 * Move the current location
747		 */
748		ph->ph_cur_pos = (char *)ph->ph_cur_pos + nelements;
749		return (DDI_PROP_RESULT_OK);
750
751	case DDI_PROP_CMD_ENCODE:
752		/*
753		 * Check that there is room to encode the data
754		 */
755		if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
756		    ph->ph_size < nelements ||
757		    ((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
758		    ph->ph_size - nelements)))
759			return (DDI_PROP_RESULT_ERROR);
760
761		/*
762		 * Copy in the bytes
763		 */
764		bcopy((char *)data, (char *)ph->ph_cur_pos, nelements);
765
766		/*
767		 * Move the current location to the start of the next bit of
768		 * space where we can store encoded data.
769		 */
770		ph->ph_cur_pos = (char *)ph->ph_cur_pos + nelements;
771		return (DDI_PROP_RESULT_OK);
772
773	case DDI_PROP_CMD_SKIP:
774		/*
775		 * Check that there is encoded data
776		 */
777		if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
778		    ph->ph_size < nelements)
779			return (DDI_PROP_RESULT_ERROR);
780
781		if ((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
782		    ph->ph_size - nelements))
783			return (DDI_PROP_RESULT_EOF);
784
785		/*
786		 * Move the current location
787		 */
788		ph->ph_cur_pos = (char *)ph->ph_cur_pos + nelements;
789		return (DDI_PROP_RESULT_OK);
790
791	case DDI_PROP_CMD_GET_ESIZE:
792		/*
793		 * The size in bytes of the encoded size is the
794		 * same as the decoded size provided by the caller.
795		 */
796		return (nelements);
797
798	case DDI_PROP_CMD_GET_DSIZE:
799		/*
800		 * Just return the number of bytes specified by the caller.
801		 */
802		return (nelements);
803
804	}
805
806	/*NOTREACHED*/
807	return (0);	/* keep gcc happy */
808}
809
810/*
811 * Used for properties that come from the OBP, hardware configuration files,
812 * or that are created by calls to ddi_prop_update(9F).
813 */
814static struct prop_handle_ops prop_1275_ops = {
815	di_prop_1275_int,
816	di_prop_1275_string,
817	di_prop_1275_bytes,
818	di_prop_int64_op
819};
820
821/*
822 * Now the real thing:
823 * Extract type-specific values of an property
824 */
825int
826di_prop_decode_common(void *data, int size, int prop_type, int prom)
827{
828	int n;
829	int nelements;
830	char *cp, *end;
831	prop_handle_t ph;
832	int (*prop_decoder)(prop_handle_t *, void *, uint_t *);
833
834	/*
835	 * If the encoded data came from software, no decoding needed
836	 */
837	if (!prom) {
838		switch (prop_type) {
839		case DI_PROP_TYPE_INT:
840			if (size % sizeof (int))
841				nelements = -1;
842			else
843				nelements = size / sizeof (int);
844			break;
845
846		case DI_PROP_TYPE_INT64:
847			if (size % sizeof (int64_t))
848				nelements = -1;
849			else
850				nelements = size / sizeof (int64_t);
851			break;
852
853		case DI_PROP_TYPE_STRING:
854			nelements = 0;
855			cp = *(char **)data;
856			end = cp + size;
857			/*
858			 * Don't trust the data passed in by the caller.
859			 * Check every char to make sure it is indeed a
860			 * string property.
861			 */
862			while (cp < end) {
863				/* skip to next non-printable char */
864				for (n = 0; cp < end &&
865				    isascii(*cp) && !iscntrl(*cp); n++, cp++)
866					;
867
868				/*
869				 * Fail if reached end (i.e. last char != 0),
870				 * or has a non-printable char. A zero length
871				 * string is acceptable.
872				 */
873				if (cp == end || *cp != 0) {
874					nelements = -1;
875					break;
876				}
877				/*
878				 * Increment # strings and keep going
879				 */
880				nelements++;
881				cp++;
882			}
883
884			break;
885
886		case DI_PROP_TYPE_BYTE:
887			nelements = size;
888		}
889
890		return (nelements);
891	}
892
893	/*
894	 * Get the encoded data
895	 */
896	bzero((caddr_t)&ph, sizeof (prop_handle_t));
897	ph.ph_data = *(uchar_t **)data;
898	ph.ph_size = size;
899
900	/*
901	 * The data came from prom, use the 1275 OBP decode/encode routines.
902	 */
903	ph.ph_cur_pos = ph.ph_data;
904	ph.ph_save_pos = ph.ph_data;
905	ph.ph_ops = &prop_1275_ops;
906	ph.ph_flags = PH_FROM_PROM;
907
908	switch (prop_type) {
909	case DI_PROP_TYPE_INT:
910		prop_decoder = di_prop_fm_decode_ints;
911		break;
912	case DI_PROP_TYPE_STRING:
913		prop_decoder = di_prop_fm_decode_strings;
914		break;
915	case DI_PROP_TYPE_BYTE:
916	default:
917		prop_decoder = di_prop_fm_decode_bytes;
918		break;
919	}
920
921	if ((*prop_decoder)(&ph, data, (uint_t *)&nelements)
922	    != DDI_PROP_SUCCESS)
923		return (-1);
924
925	/*
926	 * Free the encoded data
927	 */
928	if (size != 0)
929		free(ph.ph_data);
930
931	return (nelements);
932}
933
934void
935di_slot_names_free(int count, di_slot_name_t *slot_names)
936{
937	if (slot_names == NULL)
938		return;
939
940	while (--count >= 0) {
941		if (slot_names[count].name != NULL)
942			free(slot_names[count].name);
943	}
944	free(slot_names);
945}
946
947/*
948 * 1275 "slot-names" format: [int][string1][string2]...[stringN]
949 *	- [int] is a 1275 encoded integer
950 *      - [string1]...[stringN] are concatenated null-terminated strings
951 *      - each bit position in [int] represents a pci device number
952 *	- each bit which is set in [int] represents a slot with a device
953 *	  number of that bit position
954 *      - each string in [string1]...[stringN] identifies a slot name only
955 *	  for the bits which are set in [int]
956 *	- the ordering of strings follow the ordering of bits set in [int]
957 *
958 * an allocated array of di_slot_name_t is returned through prop_data if
959 * [int] is non-zero and the number of entries as the return value;
960 * use di_slot_names_free() to free the array
961 */
962int
963di_slot_names_decode(uchar_t *rawdata, int rawlen,
964    di_slot_name_t **prop_data)
965{
966	char *sp, *maxsp;
967	int count, i;
968	size_t len;
969	int slots;
970	int maxcount = 0;
971	int maxslots = 0;
972	di_slot_name_t *slot_names = NULL;
973
974	if (rawlen < sizeof (slots))
975		goto ERROUT;
976
977	slots = impl_di_prop_int_from_prom(rawdata, sizeof (slots));
978	if (slots == 0) {
979		*prop_data = NULL;
980		return (0);
981	}
982
983	maxslots = sizeof (slots) * 8;
984	count = 0;
985	for (i = 0; i < maxslots; i++) {
986		if (slots & (1 << i))
987			count++;
988	}
989	maxslots = i;
990	maxcount = count;
991	slot_names = malloc(sizeof (*slot_names) * maxcount);
992	bzero(slot_names, sizeof (*slot_names) * maxcount);
993
994	/* also handle unterminated strings */
995	sp = (char *)(rawdata + sizeof (slots));
996	maxsp = sp + (rawlen - sizeof (slots));
997	count = 0;
998	for (i = 0; i < maxslots; i++) {
999		if (slots & (1 << i)) {
1000			if (sp > maxsp)
1001				break;
1002			len = strnlen(sp, (maxsp - sp) + 1);
1003			if (len == 0)
1004				break;
1005
1006			slot_names[count].name =
1007			    malloc(sizeof (char) * (len + 1));
1008			(void) strlcpy(slot_names[count].name, sp, len + 1);
1009
1010			slot_names[count].num = i;
1011
1012			sp += len + 1;
1013			count++;
1014		}
1015	}
1016
1017	/*
1018	 * check if the number of strings match with the number of slots;
1019	 * we can also get a lesser string count even when there appears to be
1020	 * the correct number of strings if one or more pair of strings are
1021	 * seperated by more than one NULL byte
1022	 */
1023	if (count != maxcount)
1024		goto ERROUT;
1025
1026	*prop_data = slot_names;
1027	return (maxcount);
1028	/*NOTREACHED*/
1029ERROUT:
1030	di_slot_names_free(maxcount, slot_names);
1031	*prop_data = NULL;
1032	return (-1);
1033}
1034