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