Home | History | Annotate | Download | only in libdevinfo
      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  */
     58 int
     59 impl_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  */
     81 void
     82 di_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  */
     92 void
     93 di_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  */
    101 void
    102 di_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  */
    114 static int
    115 di_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  */
    190 static int
    191 di_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  */
    270 static int
    271 di_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  */
    370 int
    371 di_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  */
    485 int
    486 di_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  */
    588 int
    589 di_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  */
    725 int
    726 di_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  */
    814 static 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  */
    825 int
    826 di_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 
    934 void
    935 di_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  */
    962 int
    963 di_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*/
   1029 ERROUT:
   1030 	di_slot_names_free(maxcount, slot_names);
   1031 	*prop_data = NULL;
   1032 	return (-1);
   1033 }
   1034