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, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright (c) 2000 by Sun Microsystems, Inc.
24 * All rights reserved.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include <fcode/private.h>
34 #include <fcode/log.h>
35
36 void
create_prop(fcode_env_t * env,char * name)37 create_prop(fcode_env_t *env, char *name)
38 {
39 push_a_string(env, name);
40 property(env);
41 }
42
43 void
create_int_prop(fcode_env_t * env,char * name,int val)44 create_int_prop(fcode_env_t *env, char *name, int val)
45 {
46 PUSH(DS, val);
47 encode_int(env);
48 create_prop(env, name);
49 }
50
51 void
create_string_prop(fcode_env_t * env,char * name,char * val)52 create_string_prop(fcode_env_t *env, char *name, char *val)
53 {
54 push_a_string(env, val);
55 encode_string(env);
56 create_prop(env, name);
57 }
58
59 static int
addr_cmp(void * a,void * b)60 addr_cmp(void *a, void *b)
61 {
62 return ((uchar_t *)a == (uchar_t *)b);
63 }
64
65 static void *
add_property_buffer(fcode_env_t * env,int len)66 add_property_buffer(fcode_env_t *env, int len)
67 {
68 void *data = MALLOC(len+1);
69 return (add_resource(&env->propbufs, data, addr_cmp));
70 }
71
72 static void
free_property_buffer(fcode_env_t * env,void * buffer)73 free_property_buffer(fcode_env_t *env, void *buffer)
74 {
75 free_resource(&env->propbufs, buffer, addr_cmp);
76 FREE(buffer);
77 }
78
79 /*
80 * Golden Rule:
81 * DO NOT cache the value of the head of the property list *before*
82 * looking up a property.
83 * This routine is also responsible for purging dead properties
84 * and that *can* affect the head pointer.
85 * you have been warned!
86 */
87 prop_t *
find_property(device_t * d,char * name)88 find_property(device_t *d, char *name)
89 {
90 prop_t *p = d->properties, *prev;
91 prop_t *found = NULL;
92
93 prev = NULL;
94 while (p && !found) {
95 if (p->name) {
96 if (strcmp(name, p->name) == 0) {
97 found = p;
98 }
99 prev = p;
100 p = p->next;
101 } else {
102 prop_t *dead;
103
104 if (prev)
105 prev->next = p->next;
106 else {
107 /* last prop in chain */
108 d->properties = p->next;
109 }
110 dead = p;
111 p = p->next;
112 FREE(dead->name);
113 FREE(dead->data);
114 FREE(dead);
115 }
116 }
117 return (found);
118 }
119
120 static prop_t *
stack_find_property(fcode_env_t * env,device_t * d)121 stack_find_property(fcode_env_t *env, device_t *d)
122 {
123 char *propname;
124
125 propname = pop_a_string(env, NULL);
126 return (find_property(d, propname));
127 }
128
129 void
property(fcode_env_t * env)130 property(fcode_env_t *env)
131 {
132 int datalen;
133 char *propname, *srcptr;
134 prop_t *p;
135 device_t *d;
136
137 CHECK_DEPTH(env, 4, "property");
138 if (MYSELF) {
139 d = MYSELF->device;
140 } else {
141 d = env->current_device;
142 if (!d) {
143 void *buffer;
144
145 two_drop(env);
146 if ((buffer = pop_a_string(env, NULL)) != NULL)
147 free_property_buffer(env, buffer);
148 return;
149 }
150 }
151 propname = pop_a_string(env, NULL);
152 p = find_property(d, propname);
153 if (p == NULL) {
154 p = MALLOC(sizeof (prop_t));
155 p->next = d->properties;
156 d->properties = p;
157 p->name = STRDUP(propname);
158 } else if (p->data)
159 FREE(p->data); /* release old resources */
160 srcptr = pop_a_string(env, &datalen);
161 p->data = MALLOC(datalen+1);
162 p->size = datalen;
163 memcpy(p->data, srcptr, datalen);
164 p->data[datalen] = 0;
165 if (srcptr)
166 free_property_buffer(env, srcptr);
167 }
168
169 prop_t *
lookup_package_property(fcode_env_t * env,char * propname,device_t * d)170 lookup_package_property(fcode_env_t *env, char *propname, device_t *d)
171 {
172 prop_t *p;
173
174 p = find_property(d, propname);
175 if (p) {
176 return (p);
177 }
178 if (d->vectors.get_package_prop) {
179 static prop_t sp;
180 fstack_t fail, n;
181
182 /* recreate the FORTH environment for the remote call */
183 push_a_string(env, propname);
184 REVERT_PHANDLE(env, n, d);
185 PUSH(DS, n);
186 d->vectors.get_package_prop(env);
187 fail = POP(DS);
188 if (fail)
189 return (NULL);
190 sp.size = POP(DS);
191 sp.data = (uchar_t *)POP(DS);
192 sp.name = propname;
193 sp.next = NULL;
194 return (&sp);
195 }
196 return (NULL);
197 }
198
199 void
get_package_property(fcode_env_t * env)200 get_package_property(fcode_env_t *env)
201 {
202 prop_t *p;
203 device_t *d;
204 char *propname;
205
206 CHECK_DEPTH(env, 3, "get-package-property");
207 CONVERT_PHANDLE(env, d, POP(DS));
208 propname = pop_a_string(env, NULL);
209 p = lookup_package_property(env, propname, d);
210 if (p) {
211 PUSH(DS, (fstack_t)p->data);
212 PUSH(DS, p->size);
213 PUSH(DS, FALSE);
214 } else
215 PUSH(DS, TRUE);
216 }
217
218 void
get_inherited_prop(fcode_env_t * env)219 get_inherited_prop(fcode_env_t *env)
220 {
221 instance_t *ih;
222 device_t *dev;
223 prop_t *prop;
224 char *pname;
225 int plen;
226
227 /*
228 * First, we look thru the in-memory device tree for the property.
229 * If we don't find it, we call get_inherited_prop, which "knows" it's
230 * not going to find the property below the attachment point.
231 */
232
233 CHECK_DEPTH(env, 2, "get-inherited-property");
234 pname = pop_a_string(env, &plen);
235 ih = MYSELF;
236 if (ih) {
237 for (; ih; ih = ih->parent) {
238 dev = ih->device;
239 prop = find_property(dev, pname);
240 if (prop) {
241 PUSH(DS, (fstack_t)prop->data);
242 PUSH(DS, (fstack_t)prop->size);
243 PUSH(DS, FALSE);
244 return;
245 }
246 }
247 if (dev->vectors.get_inherited_prop) {
248 push_a_string(env, pname);
249 dev->vectors.get_inherited_prop(env);
250 return;
251 }
252 }
253 PUSH(DS, TRUE);
254 }
255
256 void
delete_property(fcode_env_t * env)257 delete_property(fcode_env_t *env)
258 {
259 CHECK_DEPTH(env, 2, "delete-property");
260 if (MYSELF) {
261 prop_t *p;
262
263 p = stack_find_property(env, MYSELF->device);
264 if (p) {
265 /*
266 * write the name as NULL; the space will be free'd
267 * the next time a property lookup passes this node
268 */
269 p->name = NULL;
270 }
271 } else {
272 two_drop(env);
273 }
274 }
275
276 void
get_my_property(fcode_env_t * env)277 get_my_property(fcode_env_t *env)
278 {
279 CHECK_DEPTH(env, 2, "get-my-property");
280 PUSH(DS, (fstack_t)MYSELF);
281 ihandle_to_phandle(env);
282 get_package_property(env);
283 }
284
285 void
encode_string(fcode_env_t * env)286 encode_string(fcode_env_t *env)
287 {
288 char *str;
289 char *prop;
290 int len;
291
292 CHECK_DEPTH(env, 2, "encode-string");
293 str = pop_a_string(env, &len);
294
295 prop = add_property_buffer(env, len);
296 memcpy(prop, str, len);
297 prop[len] = 0;
298 PUSH(DS, (fstack_t)prop);
299 PUSH(DS, len + 1);
300 }
301
302 void
encode_int(fcode_env_t * env)303 encode_int(fcode_env_t *env)
304 {
305 uchar_t *ptr;
306 uint32_t p;
307
308 CHECK_DEPTH(env, 1, "encode-int");
309 p = POP(DS);
310 ptr = add_property_buffer(env, sizeof (uint32_t));
311
312 memcpy(ptr, (char *)&p, sizeof (uint32_t));
313 PUSH(DS, (fstack_t)ptr);
314 PUSH(DS, sizeof (uint32_t));
315 }
316
317 void
encode_phys(fcode_env_t * env)318 encode_phys(fcode_env_t *env)
319 {
320 uint_t ncells;
321
322 ncells = get_number_of_parent_address_cells(env);
323 CHECK_DEPTH(env, ncells, "encode-phys");
324 encode_int(env);
325 while (--ncells) {
326 rot(env);
327 encode_int(env);
328 encode_plus(env);
329 }
330 }
331
332 static fstack_t
get_decoded_int(uchar_t * dp)333 get_decoded_int(uchar_t *dp)
334 {
335 uint32_t d;
336
337 memcpy((char *)&d, dp, sizeof (uint32_t));
338 return (d);
339 }
340
341 int
get_default_intprop(fcode_env_t * env,char * name,device_t * d,int def)342 get_default_intprop(fcode_env_t *env, char *name, device_t *d, int def)
343 {
344 prop_t *p;
345
346 if (!d) /* Kludge for testing */
347 return (def);
348 p = lookup_package_property(env, name, d);
349 if (p == NULL)
350 return (def);
351 return (get_decoded_int(p->data));
352 }
353
354 int
get_num_addr_cells(fcode_env_t * env,device_t * d)355 get_num_addr_cells(fcode_env_t *env, device_t *d)
356 {
357 return (get_default_intprop(env, "#address-cells", d, 2));
358 }
359
360 int
get_num_size_cells(fcode_env_t * env,device_t * d)361 get_num_size_cells(fcode_env_t *env, device_t *d)
362 {
363 return (get_default_intprop(env, "#size-cells", d, 1));
364 }
365
366 void
decode_phys(fcode_env_t * env)367 decode_phys(fcode_env_t *env)
368 {
369 char *ptr;
370 int len;
371 int adr_cells;
372 int offset;
373
374 CHECK_DEPTH(env, 2, "decode-phys");
375 ptr = pop_a_string(env, &len);
376
377 adr_cells = get_num_addr_cells(env, env->current_device->parent);
378
379 offset = sizeof (uint32_t) * adr_cells;
380
381 PUSH(DS, (fstack_t)(ptr + offset));
382 PUSH(DS, len + offset);
383
384 while (adr_cells--) {
385 fstack_t d;
386 offset -= sizeof (uint32_t);
387 d = get_decoded_int((uchar_t *)(ptr + offset));
388 PUSH(DS, d);
389 }
390 }
391
392 /*
393 * 'reg' Fcode 0x116
394 */
395 void
reg_prop(fcode_env_t * env)396 reg_prop(fcode_env_t *env)
397 {
398 fstack_t size;
399
400 CHECK_DEPTH(env, 1, "reg");
401 size = POP(DS);
402 encode_phys(env);
403 PUSH(DS, size);
404 encode_int(env);
405 encode_plus(env);
406 create_prop(env, "reg");
407 }
408
409 void
encode_bytes(fcode_env_t * env)410 encode_bytes(fcode_env_t *env)
411 {
412 char *str;
413 char *prop;
414 int len;
415
416 CHECK_DEPTH(env, 2, "encode-bytes");
417 str = pop_a_string(env, &len);
418 prop = add_property_buffer(env, len);
419 memcpy(prop, str, len);
420 prop[len] = 0;
421 PUSH(DS, (fstack_t)prop);
422 PUSH(DS, len);
423 }
424
425 void
decode_int(fcode_env_t * env)426 decode_int(fcode_env_t *env)
427 {
428 char *dp;
429 fstack_t d;
430 int len;
431
432 CHECK_DEPTH(env, 2, "decode-int");
433 dp = pop_a_string(env, &len);
434 PUSH(DS, (fstack_t)(dp + sizeof (uint32_t)));
435 PUSH(DS, len - sizeof (uint32_t));
436 d = get_decoded_int((uchar_t *)dp);
437 PUSH(DS, d);
438 }
439
440 void
decode_string(fcode_env_t * env)441 decode_string(fcode_env_t *env)
442 {
443 int plen, len;
444 char *dp;
445
446 CHECK_DEPTH(env, 2, "decode-string");
447 dp = pop_a_string(env, &plen);
448 len = strlen(dp) + 1;
449 PUSH(DS, (fstack_t)(dp + len));
450 PUSH(DS, plen - len);
451 PUSH(DS, (fstack_t)dp);
452 PUSH(DS, len - 1);
453 }
454
455 void
encode_plus(fcode_env_t * env)456 encode_plus(fcode_env_t *env)
457 {
458 int len1, len2;
459 char *src1, *src2;
460 uchar_t *new;
461
462 CHECK_DEPTH(env, 4, "encode+");
463 src1 = pop_a_string(env, &len1);
464 src2 = pop_a_string(env, &len2);
465 new = add_property_buffer(env, len1 + len2);
466 if (src2) {
467 memcpy(new, src2, len2);
468 free_property_buffer(env, src2);
469 }
470 if (src1) {
471 memcpy(new + len2, src1, len1);
472 free_property_buffer(env, src1);
473 }
474 PUSH(DS, (fstack_t)new);
475 PUSH(DS, len1 + len2);
476 }
477
478 static void
make_special_property(fcode_env_t * env,char * name)479 make_special_property(fcode_env_t *env, char *name)
480 {
481 push_a_string(env, name);
482 property(env);
483 }
484
485 void
device_name(fcode_env_t * env)486 device_name(fcode_env_t *env)
487 {
488 CHECK_DEPTH(env, 2, "device-name");
489 encode_string(env);
490 make_special_property(env, "name");
491 }
492
493 void
model_prop(fcode_env_t * env)494 model_prop(fcode_env_t *env)
495 {
496 CHECK_DEPTH(env, 2, "model");
497 encode_string(env);
498 make_special_property(env, "model");
499 }
500
501 void
device_type(fcode_env_t * env)502 device_type(fcode_env_t *env)
503 {
504 CHECK_DEPTH(env, 2, "device-type");
505 encode_string(env);
506 make_special_property(env, "device_type");
507 }
508
509 /*
510 * 'next-property' Fcode implementation.
511 */
512 void
next_property(fcode_env_t * env)513 next_property(fcode_env_t *env)
514 {
515 device_t *phandle;
516 char *previous;
517 prop_t *p;
518
519 CHECK_DEPTH(env, 3, "next-property");
520 phandle = (device_t *)POP(DS);
521 previous = pop_a_string(env, NULL);
522 p = phandle->properties;
523 if (previous == NULL)
524 p = phandle->properties;
525 else if (p = find_property(phandle, previous))
526 p = p->next;
527
528 for (; p != NULL && p->name == NULL; p = p->next)
529 ;
530
531 if (p)
532 push_a_string(env, p->name);
533 else
534 push_a_string(env, "");
535 PUSH(DS, TRUE);
536 }
537
538 void
get_property(fcode_env_t * env)539 get_property(fcode_env_t *env)
540 {
541 if (MYSELF)
542 get_my_property(env);
543 else if (env->current_device) {
544 fstack_t d;
545
546 REVERT_PHANDLE(env, d, env->current_device);
547 PUSH(DS, d);
548 get_package_property(env);
549 } else {
550 two_drop(env);
551 log_message(MSG_WARN, "No device context\n");
552 }
553 }
554
555 #ifdef DEBUG
556
557 static void
print_indented(char * name)558 print_indented(char *name)
559 {
560 log_message(MSG_INFO, "%-28s", name);
561 }
562
563 static void
print_string(fcode_env_t * env,uchar_t * data,int len)564 print_string(fcode_env_t *env, uchar_t *data, int len)
565 {
566 while (len > 0) {
567 int nlen = (strlen((char *)data)+1);
568 log_message(MSG_INFO, "%s\n", data);
569 len -= nlen;
570 data += nlen;
571 if (len > 0)
572 print_indented("");
573 }
574 }
575
576 static void
print_ints(uchar_t * data,int len,int crlf)577 print_ints(uchar_t *data, int len, int crlf)
578 {
579 uint32_t d;
580
581 while (len--) {
582 d = get_decoded_int(data);
583 log_message(MSG_INFO, "%8.8lx ", d);
584 data += sizeof (uint32_t);
585 }
586 if (crlf)
587 log_message(MSG_INFO, "\n");
588 }
589
590 static void
print_integer(fcode_env_t * env,uchar_t * data,int len)591 print_integer(fcode_env_t *env, uchar_t *data, int len)
592 {
593 print_ints(data, len/sizeof (uint32_t), 1);
594 }
595
596 static void
print_bytes(fcode_env_t * env,uchar_t * data,int len)597 print_bytes(fcode_env_t *env, uchar_t *data, int len)
598 {
599 while (len--) {
600 log_message(MSG_INFO, "%2.2x ", *data++);
601 }
602 log_message(MSG_INFO, "\n");
603 }
604
605 static void
print_bytes_indented(fcode_env_t * env,uchar_t * data,int len)606 print_bytes_indented(fcode_env_t *env, uchar_t *data, int len)
607 {
608 int nbytes;
609
610 for (; ; ) {
611 nbytes = min(len, 16);
612 print_bytes(env, data, nbytes);
613 len -= nbytes;
614 data += nbytes;
615 if (len == 0)
616 break;
617 print_indented("");
618 }
619 }
620
621 static void
print_reg(fcode_env_t * env,uchar_t * data,int len)622 print_reg(fcode_env_t *env, uchar_t *data, int len)
623 {
624 int pcells, nlen;
625
626 if (env->current_device != NULL &&
627 env->current_device->parent != NULL) {
628 pcells = get_num_size_cells(env, env->current_device->parent);
629 pcells += get_num_addr_cells(env, env->current_device->parent);
630 nlen = pcells*sizeof (uint32_t);
631 while (len > 0) {
632 print_ints(data, pcells, 1);
633 len -= nlen;
634 data += nlen;
635 if (len > 0)
636 print_indented("");
637 }
638 } else
639 print_bytes_indented(env, data, len);
640 }
641
642 static void
print_imap(fcode_env_t * env,uchar_t * dp,int len)643 print_imap(fcode_env_t *env, uchar_t *dp, int len)
644 {
645 int n, icells;
646
647 if (env->current_device == NULL) {
648 print_bytes_indented(env, dp, len);
649 return;
650 }
651 n = get_num_addr_cells(env, env->current_device);
652
653 while (len) {
654 int offset;
655 fstack_t data;
656 device_t *node;
657
658 offset = 0;
659 data = get_decoded_int(dp+((n+1)*sizeof (uint32_t)));
660 CONVERT_PHANDLE(env, node, data);
661 offset += (n+2)*sizeof (uint32_t);
662 print_ints(dp, (n+2), 0);
663 icells = get_default_intprop(env, "#interrupt-cells", node, 1);
664 print_ints(dp+offset, icells, 1);
665 offset += icells*sizeof (uint32_t);
666 dp += offset;
667 len -= offset;
668 if (len)
669 print_indented("");
670 }
671 }
672
673 static void
print_ranges(fcode_env_t * env,uchar_t * data,int len)674 print_ranges(fcode_env_t *env, uchar_t *data, int len)
675 {
676 int pcells, nlen;
677
678 if (env->current_device != NULL &&
679 env->current_device->parent != NULL) {
680 pcells = get_num_addr_cells(env, env->current_device);
681 pcells += get_num_addr_cells(env, env->current_device->parent);
682 pcells += get_num_size_cells(env, env->current_device);
683 nlen = pcells*sizeof (uint32_t);
684 while (len > 0) {
685 print_ints(data, pcells, 1);
686 len -= nlen;
687 data += nlen;
688 if (len > 0)
689 print_indented("");
690 }
691 } else
692 print_bytes_indented(env, data, len);
693 }
694
695 typedef struct MAGIC_PROP {
696 char *name;
697 void (*fn)(fcode_env_t *env, uchar_t *data, int len);
698 } magic_prop_t;
699
700 static magic_prop_t magic_props[] = {
701 { "name", print_string },
702 { "device_type", print_string },
703 { "model", print_string },
704 { "reg", print_reg },
705 { "assigned-addresses", print_reg },
706 { "interrupt-map", print_imap },
707 { "#interrupt-cells", print_integer },
708 { "interrupt-map-mask", print_integer },
709 { "#size-cells", print_integer },
710 { "#address-cells", print_integer },
711 { "ranges", print_ranges },
712 { "device-id", print_integer },
713 { "vendor-id", print_integer },
714 { "class-code", print_integer },
715 { "compatible", print_string },
716 { "version", print_string },
717 { "manufacturer", print_string },
718 { NULL, NULL }
719 };
720
721 static void
print_content(fcode_env_t * env,char * prop,uchar_t * data,int len)722 print_content(fcode_env_t *env, char *prop, uchar_t *data, int len)
723 {
724 magic_prop_t *p;
725
726 for (p = magic_props; p->name; p++)
727 if (strcmp(prop, p->name) == 0) {
728 (*p->fn)(env, data, len);
729 return;
730 }
731 print_bytes_indented(env, data, len);
732 }
733
734 void
print_property(fcode_env_t * env,prop_t * p,char * prepend)735 print_property(fcode_env_t *env, prop_t *p, char *prepend)
736 {
737 char buf[40];
738 char *name = (p->name ? p->name : "<noname>");
739
740 if (prepend) {
741 sprintf(buf, "%s %s", prepend, name);
742 name = buf;
743 }
744 print_indented(name);
745 if (p->name)
746 print_content(env, p->name, p->data, p->size);
747 else
748 print_bytes_indented(env, p->data, p->size);
749 }
750
751 void
dot_properties(fcode_env_t * env)752 dot_properties(fcode_env_t *env)
753 {
754 prop_t *p;
755 instance_t *omyself;
756
757 omyself = MYSELF;
758 MYSELF = NULL;
759
760 if (env->current_device) {
761 for (p = env->current_device->properties; p; p = p->next)
762 print_property(env, p, NULL);
763 } else {
764 log_message(MSG_INFO, "No device context\n");
765 }
766 MYSELF = omyself;
767 }
768
769 #endif
770
771 #pragma init(_init)
772
773 static void
_init(void)774 _init(void)
775 {
776 fcode_env_t *env = initial_env;
777
778 ASSERT(env);
779 NOTICE;
780
781 P1275(0x110, 0, "property", property);
782 P1275(0x111, 0, "encode-int", encode_int);
783 P1275(0x112, 0, "encode+", encode_plus);
784 P1275(0x113, 0, "encode-phys", encode_phys);
785 P1275(0x114, 0, "encode-string", encode_string);
786 P1275(0x115, 0, "encode-bytes", encode_bytes);
787 P1275(0x116, 0, "reg", reg_prop);
788 FCODE(0x117, 0, "intr", fc_obsolete);
789 FCODE(0x118, 0, "driver", fc_historical);
790 P1275(0x119, 0, "model", model_prop);
791 P1275(0x11a, 0, "device-type", device_type);
792
793 P1275(0x128, 0, "decode-phys", decode_phys);
794
795 P1275(0x201, 0, "device-name", device_name);
796
797 P1275(0x21a, 0, "get-my-property", get_my_property);
798 P1275(0x21b, 0, "decode-int", decode_int);
799 P1275(0x21c, 0, "decode-string", decode_string);
800 P1275(0x21d, 0, "get-inherited-property", get_inherited_prop);
801 P1275(0x21e, 0, "delete-property", delete_property);
802 P1275(0x21f, 0, "get-package-property", get_package_property);
803
804 P1275(0x23d, 0, "next-property", next_property);
805
806 FORTH(0, "get-property", get_property);
807 FORTH(0, ".properties", dot_properties);
808 }
809