xref: /titanic_52/usr/src/lib/efcode/engine/properties.c (revision 06e46062ef4f5f4b687cbafb4518fb123fe23920)
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
37 create_prop(fcode_env_t *env, char *name)
38 {
39 	push_a_string(env, name);
40 	property(env);
41 }
42 
43 void
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
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
60 addr_cmp(void *a, void *b)
61 {
62 	return ((uchar_t *)a == (uchar_t *)b);
63 }
64 
65 static void *
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
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 *
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 *
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
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
479 make_special_property(fcode_env_t *env, char *name)
480 {
481 	push_a_string(env, name);
482 	property(env);
483 }
484 
485 void
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
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
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
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
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
558 print_indented(char *name)
559 {
560 	log_message(MSG_INFO, "%-28s", name);
561 }
562 
563 static void
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
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
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
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
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
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
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
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
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
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
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
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