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
impl_di_prop_int_from_prom(uchar_t * intp,int n)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
di_prop_reset_pos(prop_handle_t * ph)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
di_prop_save_pos(prop_handle_t * ph)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
di_prop_restore_pos(prop_handle_t * ph)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
di_prop_fm_decode_ints(prop_handle_t * ph,void * data,uint_t * nelements)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
di_prop_fm_decode_strings(prop_handle_t * ph,void * data,uint_t * nelements)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
di_prop_fm_decode_bytes(prop_handle_t * ph,void * data,uint_t * nelements)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
di_prop_1275_int(prop_handle_t * ph,uint_t cmd,int * data)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
di_prop_int64_op(prop_handle_t * ph,uint_t cmd,int64_t * data)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
di_prop_1275_string(prop_handle_t * ph,uint_t cmd,char * data)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
di_prop_1275_bytes(prop_handle_t * ph,uint_t cmd,uchar_t * data,uint_t nelements)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
di_prop_decode_common(void * data,int size,int prop_type,int prom)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
di_slot_names_free(int count,di_slot_name_t * slot_names)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
di_slot_names_decode(uchar_t * rawdata,int rawlen,di_slot_name_t ** prop_data)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