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