xref: /titanic_41/usr/src/lib/efcode/engine/package.c (revision 7a286c471efbab8562f7655a82931904703fffe0)
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 2006 Sun Microsystems, Inc.   All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <stddef.h>
31 #include <string.h>
32 
33 #include <fcode/private.h>
34 #include <fcode/log.h>
35 
36 #include <fcdriver/fcdriver.h>
37 
38 #define	MIN_VALUES	100
39 
40 static void
41 check_my_self(fcode_env_t *env, char *fn)
42 {
43 	if (!MYSELF)
44 		forth_abort(env, "%s: MYSELF is NULL", fn);
45 }
46 
47 uint_t
48 get_number_of_parent_address_cells(fcode_env_t *env)
49 {
50 	uint_t ncells;
51 	device_t *d;
52 	static char func_name[] = "get_number_of_parent_address_cells";
53 
54 	if (MYSELF == NULL)	/* Kludge for testing */
55 		return (2);
56 	d = MYSELF->device;
57 	ncells = d->parent_adr_cells;
58 	if (ncells == 0) {
59 		ncells = get_default_intprop(env, "#address-cells", d->parent,
60 		    2);
61 		if (ncells > MAX_MY_ADDR) {
62 			log_message(MSG_ERROR, "%s: %s:"
63 			    " ncells (%d) > MAX_MY_ADDR (%d)\n", func_name,
64 			    get_path(env, d->parent), ncells, MAX_MY_ADDR);
65 			ncells = MAX_MY_ADDR;
66 		}
67 		d->parent_adr_cells = ncells;
68 	}
69 	return (ncells);
70 }
71 
72 instance_t *
73 create_ihandle(fcode_env_t *env, device_t *phandle, instance_t *parent)
74 {
75 	instance_t *ihandle;
76 	int i;
77 
78 	ihandle = MALLOC(sizeof (instance_t));
79 
80 	i = max(phandle->data_size[INIT_DATA], MIN_VALUES);
81 	ihandle->data[INIT_DATA] = MALLOC(sizeof (fstack_t) * i);
82 	memcpy(ihandle->data[INIT_DATA], phandle->init_data,
83 	    (size_t) (sizeof (fstack_t) * i));
84 
85 	i = max(phandle->data_size[UINIT_DATA], MIN_VALUES);
86 	ihandle->data[UINIT_DATA] = MALLOC(sizeof (fstack_t) * i);
87 
88 	ihandle->my_space = phandle->my_space;
89 	memcpy(ihandle->my_addr, phandle->my_addr, sizeof (ihandle->my_addr));
90 	ihandle->parent = parent;
91 	ihandle->device = phandle;
92 	return (ihandle);
93 }
94 
95 device_t *
96 create_phandle(fcode_env_t *env, device_t *parent)
97 {
98 	device_t *phandle;
99 
100 	phandle = MALLOC(sizeof (device_t));
101 	phandle->init_data = MALLOC(sizeof (fstack_t) * MIN_VALUES);
102 	phandle->data_size[INIT_DATA] = 0;
103 	phandle->data_size[UINIT_DATA] = 0;
104 	phandle->parent = parent;
105 	return (phandle);
106 }
107 
108 
109 static void
110 do_push_package(fcode_env_t *env, device_t *d)
111 {
112 	do_previous(env);
113 	do_also(env);
114 	if (d != NULL) {
115 		CONTEXT = (token_t *)(&d->vocabulary);
116 		debug_msg(DEBUG_CONTEXT, "CONTEXT:push_package: %s%d/%p/%p\n",
117 		    get_path(env, d), env->order_depth, CONTEXT, env->current);
118 	}
119 }
120 
121 static void
122 push_package(fcode_env_t *env)
123 {
124 	device_t *d;
125 	phandle_t ph;
126 
127 	CHECK_DEPTH(env, 1, "push-package");
128 	ph = POP(DS);
129 	CONVERT_PHANDLE(env, d, ph);
130 	do_push_package(env, d);
131 }
132 
133 static void
134 pop_package(fcode_env_t *env)
135 {
136 	do_previous(env);
137 	do_definitions(env);
138 }
139 
140 static void
141 interpose(fcode_env_t *env)
142 {
143 	TODO;	/* interpose - not yet implemented */
144 }
145 
146 void
147 activate_device(fcode_env_t *env, device_t *d)
148 {
149 	env->current_device = d;
150 	do_push_package(env, d);
151 	do_definitions(env);
152 }
153 
154 void
155 deactivate_device(fcode_env_t *env, device_t *d)
156 {
157 	env->current_device = d;
158 	do_previous(env);
159 	if (d != NULL) {
160 		CONTEXT = (token_t *)(&d->vocabulary);
161 		debug_msg(DEBUG_CONTEXT, "CONTEXT:deactivate_device:"
162 		    " %s%d/%p/%p\n", get_path(env, d), env->order_depth,
163 		    CONTEXT, env->current);
164 	}
165 	do_definitions(env);
166 }
167 
168 /*
169  * Starfire hack to set '/' device_type to 'upa'
170  */
171 #include <sys/systeminfo.h>
172 static void
173 starfire_hack(fcode_env_t *env)
174 {
175 	char platform[100];
176 
177 	sysinfo(SI_PLATFORM, platform, sizeof (platform));
178 	if (strcmp(platform, "SUNW,Ultra-Enterprise-10000") == 0 &&
179 	    find_property(env->root_node, "device_type") == NULL) {
180 		create_string_prop(env, "device_type", "upa");
181 	}
182 }
183 
184 void
185 root_node(fcode_env_t *env)
186 {
187 	do_also(env);
188 	activate_device(env, env->root_node);
189 	starfire_hack(env);
190 }
191 
192 void
193 child_node(fcode_env_t *env)
194 {
195 	device_t *d;
196 
197 	CHECK_DEPTH(env, 1, "child");
198 	CONVERT_PHANDLE(env, d, TOS);
199 	TOS = (fstack_t)d->child;
200 	REVERT_PHANDLE(env, TOS, d->child);
201 }
202 
203 void
204 peer_node(fcode_env_t *env)
205 {
206 	device_t *d;
207 
208 	CHECK_DEPTH(env, 1, "peer");
209 	CONVERT_PHANDLE(env, d, TOS);
210 	REVERT_PHANDLE(env, TOS, d->peer);
211 }
212 
213 void
214 new_device(fcode_env_t *env)
215 {
216 	device_t *phandle, *parent;
217 	device_t *peer;
218 
219 	check_my_self(env, "new-device");
220 
221 	parent = MYSELF->device;
222 	phandle = create_phandle(env, parent);
223 	MYSELF = create_ihandle(env, phandle, MYSELF);
224 	activate_device(env, phandle);
225 	if (parent->child) {
226 		/* Insert new child at end of peer list */
227 		for (peer = parent->child; peer->peer; peer = peer->peer)
228 			;
229 		peer->peer = phandle;
230 	} else
231 		parent->child = phandle;	/* First child */
232 	ALLOCATE_PHANDLE(env);
233 }
234 
235 void
236 finish_device(fcode_env_t *env)
237 {
238 	fstack_t *mem;
239 	device_t *my_dev, *parent_dev;
240 	instance_t *parent, *myself = MYSELF;
241 	int  n;
242 
243 	check_my_self(env, "finish-device");
244 	ASSERT(myself->device);
245 	ASSERT(env->current_device);
246 	n = myself->device->data_size[INIT_DATA];
247 
248 	/*
249 	 * Paranoia.. reserve a little more instance data than we need
250 	 */
251 	mem = MALLOC(sizeof (fstack_t) * (n+8));
252 	memcpy(mem, MYSELF->device->init_data, sizeof (fstack_t) * n);
253 	FREE(myself->device->init_data);
254 	my_dev = myself->device;
255 	my_dev->init_data = mem;
256 	parent = MYSELF->parent;
257 	parent_dev = env->current_device->parent;
258 	FREE(MYSELF);
259 	MYSELF = parent;
260 	activate_device(env, parent_dev);
261 }
262 
263 static void
264 create_internal_value(fcode_env_t *env, char *name, int offset, int token)
265 {
266 	header(env, name, strlen(name), 0);
267 	COMPILE_TOKEN(&noop);
268 	EXPOSE_ACF;
269 	if (token) {
270 		SET_TOKEN(token, 0, name, LINK_TO_ACF(env->lastlink));
271 	}
272 	PUSH(DS, offset);
273 	lcomma(env);
274 	set_internal_value_actions(env);
275 }
276 
277 static void
278 create_my_self(fcode_env_t *env)
279 {
280 	int offset = offsetof(fcode_env_t, my_self);
281 
282 	create_internal_value(env, "my-self", offset, 0x203);
283 }
284 
285 static void
286 create_my_space(fcode_env_t *env)
287 {
288 	int offset = offsetof(instance_t, my_space);
289 
290 	create_internal_value(env, "my-space", -offset, 0x103);
291 }
292 
293 void
294 my_address(fcode_env_t *env)
295 {
296 	fstack_t *adr_ptr;
297 	uint_t ncells;
298 
299 	check_my_self(env, "my-address");
300 	ncells = get_number_of_parent_address_cells(env);
301 	adr_ptr = MYSELF->my_addr;
302 	while (--ncells) {
303 		PUSH(DS, *adr_ptr);
304 		adr_ptr++;
305 	}
306 }
307 
308 void
309 my_unit(fcode_env_t *env)
310 {
311 	check_my_self(env, "my-unit");
312 	my_address(env);
313 	PUSH(DS, MYSELF->my_space);
314 }
315 
316 static void
317 my_args(fcode_env_t *env)
318 {
319 	check_my_self(env, "my-args");
320 	PUSH(DS, (fstack_t)MYSELF->my_args);
321 	PUSH(DS, (fstack_t)MYSELF->my_args_len);
322 }
323 
324 int
325 call_my_parent(fcode_env_t *env, char *method)
326 {
327 	push_a_string(env, method);
328 	dollar_call_parent(env);
329 	return (env->last_error);
330 }
331 
332 void
333 set_args(fcode_env_t *env)
334 {
335 	int args_len;
336 	common_data_t *cdp;
337 	uint_t ncells;
338 	fstack_t *adr_ptr, *adr_ptr1, space;
339 
340 	CHECK_DEPTH(env, 4, "set-args");
341 
342 	check_my_self(env, "set-args");
343 
344 	/*
345 	 * Handle args argument of set-args.
346 	 */
347 	if (MYSELF->my_args) {
348 		FREE(MYSELF->my_args);
349 		MYSELF->my_args = NULL;
350 	}
351 	two_swap(env);
352 	MYSELF->my_args = pop_a_duped_string(env, &args_len);
353 	MYSELF->my_args_len = args_len;
354 
355 	if (call_my_parent(env, "decode-unit"))
356 		forth_abort(env, "set-args: decode-unit failed");
357 
358 	ncells = get_number_of_parent_address_cells(env);
359 
360 	/*
361 	 * Kludge: For GP2, my-space comes from decode-unit hi.address.
362 	 * for PCI, my-space from decode-unit won't have the bus#, so we need
363 	 * to get it from config_address.  Unfortunately, there is no easy
364 	 * way to figure out here which one we're looking at.  We take the
365 	 * expediant of or'ing the two values together.
366 	 */
367 	space = POP(DS);	/* pop phys.hi */
368 	if ((cdp = (common_data_t *)env->private) != NULL)
369 		space |= cdp->fc.config_address;
370 
371 	MYSELF->device->my_space = MYSELF->my_space = space;
372 
373 	adr_ptr = MYSELF->my_addr;
374 	adr_ptr1 = MYSELF->device->my_addr;
375 	while (--ncells) {
376 		*adr_ptr++ = *adr_ptr1++ = POP(DS);
377 	}
378 }
379 
380 void
381 my_parent(fcode_env_t *env)
382 {
383 	check_my_self(env, "my-parent");
384 	PUSH(DS, (fstack_t)MYSELF->parent);
385 }
386 
387 instance_t *
388 open_instance_chain(fcode_env_t *env, device_t *phandle, int exec)
389 {
390 	instance_t *parent;
391 
392 	if (!phandle)
393 		return (NULL);
394 	parent = open_instance_chain(env, phandle->parent, exec);
395 	return (create_ihandle(env, phandle, parent));
396 }
397 
398 void
399 close_instance_chain(fcode_env_t *env, instance_t *ihandle, int exec)
400 {
401 	instance_t *parent;
402 
403 	if (ihandle) {
404 		parent = ihandle->parent;
405 		close_instance_chain(env, parent, exec);
406 		if (ihandle->my_args)
407 			FREE(ihandle->my_args);
408 		FREE(ihandle);
409 	}
410 }
411 
412 void
413 begin_package(fcode_env_t *env)
414 {
415 	fstack_t ok;
416 	char *name;
417 
418 	CHECK_DEPTH(env, 6, "begin-package");
419 	two_dup(env);
420 	name = pop_a_string(env, NULL);
421 	find_package(env);
422 	ok = POP(DS);
423 	if (ok) {
424 		PUSH(DS, 0);
425 		PUSH(DS, 0);
426 		rot(env);
427 		open_package(env);
428 		MYSELF = (instance_t *)POP(DS);
429 		check_my_self(env, "begin-package");
430 		new_device(env);
431 		set_args(env);
432 	} else {
433 		log_message(MSG_INFO, "Package '%s' not found\n", name);
434 	}
435 }
436 
437 void
438 open_package(fcode_env_t *env)
439 {
440 	device_t *phandle;
441 	instance_t *ihandle;
442 	int len;
443 
444 	CHECK_DEPTH(env, 3, "open-package");
445 	CONVERT_PHANDLE(env, phandle, POP(DS));
446 	ihandle = open_instance_chain(env, phandle, 1);
447 	ihandle->my_args = pop_a_duped_string(env, &len);
448 	ihandle->my_args_len = len;
449 	PUSH(DS, (fstack_t)ihandle);
450 }
451 
452 void
453 dollar_open_package(fcode_env_t *env)
454 {
455 	fstack_t ok;
456 
457 	CHECK_DEPTH(env, 4, "$open-package");
458 	find_package(env);
459 	ok = POP(DS);
460 	if (ok) {
461 		open_package(env);
462 	} else {
463 		(void) POP(DS);
464 		(void) POP(DS);
465 		PUSH(DS, 0);
466 	}
467 }
468 
469 void
470 close_package(fcode_env_t *env)
471 {
472 	instance_t *ihandle;
473 
474 	CHECK_DEPTH(env, 1, "close-package");
475 	ihandle = (instance_t *)POP(DS);
476 	close_instance_chain(env, ihandle, 1);
477 }
478 
479 static void (*find_method_hook)(fcode_env_t *);
480 
481 void
482 set_find_method_hook(fcode_env_t *env, void (*hook)(fcode_env_t *))
483 {
484 	find_method_hook = hook;
485 }
486 
487 void
488 find_method(fcode_env_t *env)
489 {
490 	fstack_t d;
491 	device_t *device;
492 	acf_t acf = 0;
493 
494 	CHECK_DEPTH(env, 3, "find-method");
495 	if (find_method_hook) {
496 		(*find_method_hook)(env);
497 		if (TOS)		/* Found it */
498 			return;
499 		POP(DS);
500 	}
501 
502 	d = POP(DS);
503 	CONVERT_PHANDLE(env, device, d);
504 	PUSH(DS, (fstack_t)&device->vocabulary);
505 	acf = voc_find(env);
506 	PUSH(DS, (fstack_t)acf);
507 	if (acf) {
508 		PUSH(DS, TRUE);
509 	}
510 }
511 
512 /*
513  * 'call-package' Fcode
514  */
515 void
516 call_package(fcode_env_t *env)
517 {
518 	instance_t *ihandle, *saved_myself;
519 
520 	CHECK_DEPTH(env, 2, "call-package");
521 	ihandle = (instance_t *)POP(DS);
522 	saved_myself = MYSELF;
523 	MYSELF = ihandle;
524 	execute(env);
525 	MYSELF = saved_myself;
526 }
527 
528 void
529 ihandle_to_phandle(fcode_env_t *env)
530 {
531 	instance_t *i;
532 
533 	CHECK_DEPTH(env, 1, "ihandle>phandle");
534 	i = (instance_t *)TOS;
535 	REVERT_PHANDLE(env, TOS, i->device);
536 }
537 
538 char *
539 get_package_name(fcode_env_t *env, device_t *d)
540 {
541 	char *name;
542 	prop_t *prop;
543 
544 	prop = lookup_package_property(env, "name", d);
545 	if (prop == NULL) {
546 		name = "<Unnamed>";
547 	} else {
548 		name = (char *)prop->data;
549 	}
550 	return (name);
551 }
552 
553 static char *package_search_path = "/packages:/openprom";
554 
555 device_t *
556 match_package_path(fcode_env_t *env, char *path)
557 {
558 	device_t *d;
559 	char *name;
560 	int len;
561 
562 	if (*path == '/') {
563 		d = env->root_node->child;
564 		path++;
565 	} else
566 		d = env->current_device;
567 	while (*path != '\0' && d != NULL) {
568 		name = get_package_name(env, d);
569 		len = strlen(name);
570 		if (strncmp(name, path, len) == 0) {
571 			path += len;
572 			if (*path == '\0') {
573 				return (d);
574 			}
575 			/* skip the '/' */
576 			if (*path++ != '/')
577 				break;
578 			d = d->child;
579 		} else {
580 			d = d->peer;
581 		}
582 	}
583 	return (NULL);
584 }
585 
586 device_t *
587 locate_package(fcode_env_t *env, char *start)
588 {
589 	device_t *d;
590 	char *p, *next_p;
591 	char *tpath, *fpath;
592 
593 	if ((d = match_package_path(env, start)) != NULL)
594 		return (d);
595 
596 	/*
597 	 * ignore starting '/'
598 	 */
599 	if (*start == '/')
600 		*start++;
601 
602 	fpath = STRDUP(package_search_path);
603 	for (p = fpath; p != NULL; p = next_p) {
604 		if ((next_p = strchr(p, ':')) != NULL)
605 			*next_p++ = '\0';
606 		tpath = MALLOC(strlen(p) + strlen(start) + 2);
607 		sprintf(tpath, "%s/%s", p, start);
608 		if ((d = match_package_path(env, tpath)) != NULL) {
609 			FREE(fpath);
610 			FREE(tpath);
611 			return (d);
612 		}
613 		FREE(tpath);
614 	}
615 	FREE(fpath);
616 	return (NULL);
617 }
618 
619 void
620 find_package(fcode_env_t *env)
621 {
622 	char *path;
623 	device_t *package;
624 	fstack_t ph = 0;
625 
626 	CHECK_DEPTH(env, 2, "find-package");
627 	if ((path = pop_a_duped_string(env, NULL)) != NULL) {
628 		if (strcmp(path, "/") == 0)
629 			package = env->root_node;
630 		else
631 			package = locate_package(env, path);
632 		FREE(path);
633 		REVERT_PHANDLE(env, ph, package);
634 	}
635 	PUSH(DS, ph);
636 	if (package)
637 		PUSH(DS, TRUE);
638 }
639 
640 static void
641 encode_unit_hack(fcode_env_t *env)
642 {
643 	int hi, i;
644 	uint_t ncells = get_number_of_parent_address_cells(env);
645 
646 	for (i = 0; i < ncells; i++)
647 		POP(DS);
648 	push_a_string(env, NULL);
649 }
650 
651 void
652 dollar_call_method(fcode_env_t *env)
653 {
654 	instance_t *old_myself;
655 	instance_t *myself;
656 	device_t *device;
657 	char *method;
658 
659 	CHECK_DEPTH(env, 3, "$call-method");
660 	check_my_self(env, "$call-method");
661 	old_myself = MYSELF;
662 	myself = (instance_t *)POP(DS);
663 
664 	method = (char *)DS[-1];
665 	debug_msg(DEBUG_CALL_METHOD, "$call_method %s\n", method);
666 
667 	if (old_myself && !myself) {
668 		/* We hit the root of our tree */
669 		device = old_myself->device;
670 		return;
671 	}
672 
673 	MYSELF = myself;
674 	check_my_self(env, "$call-method");
675 	device = MYSELF->device;
676 	do_push_package(env, device);
677 	PUSH(DS, (fstack_t)device);
678 	REVERT_PHANDLE(env, TOS, device);
679 	find_method(env);
680 	if (TOS) {
681 		(void) POP(DS);
682 		execute(env);
683 	} else if (strcmp(method, "encode-unit") == 0) {
684 		encode_unit_hack(env);
685 	} else {
686 		throw_from_fclib(env, 1, "Unimplemented package method: %s%s",
687 		    get_path(env, device), method);
688 	}
689 	MYSELF = old_myself;
690 	do_push_package(env, MYSELF->device);
691 }
692 
693 void
694 dollar_call_parent(fcode_env_t *env)
695 {
696 	CHECK_DEPTH(env, 2, "$call-parent");
697 
698 	check_my_self(env, "$call-parent");
699 
700 	PUSH(DS, (fstack_t)MYSELF->parent);
701 	dollar_call_method(env);
702 }
703 
704 #ifdef DEBUG
705 void
706 current_device(fcode_env_t *env)
707 {
708 	PUSH(DS, (fstack_t)&env->current_device);
709 }
710 
711 char *
712 get_path(fcode_env_t *env, device_t *d)
713 {
714 	char *pre_path, *name, *path;
715 	int n;
716 
717 	if (d->parent)
718 		pre_path = get_path(env, d->parent);
719 	else
720 		pre_path = STRDUP("");
721 
722 	name = get_package_name(env, d);
723 	n = strlen(pre_path) + strlen(name) + 1;
724 	path = MALLOC(n);
725 	strcpy(path, pre_path);
726 	strcat(path, name);
727 	if (d->child && d->parent)
728 		strcat(path, "/");
729 	FREE(pre_path);
730 	return (path);
731 }
732 
733 static void
734 pwd_dollar(fcode_env_t *env)
735 {
736 	if (env->current_device)
737 		push_a_string(env, get_path(env, env->current_device));
738 	else
739 		push_a_string(env, NULL);
740 }
741 
742 void
743 pwd(fcode_env_t *env)
744 {
745 	if (env->current_device) {
746 		log_message(MSG_INFO, "%s\n",
747 		    get_path(env, env->current_device));
748 	} else {
749 		log_message(MSG_INFO, "No device context\n");
750 	}
751 }
752 
753 void
754 do_ls(fcode_env_t *env)
755 {
756 	device_t *d;
757 
758 	if (env->current_device == NULL) {
759 		log_message(MSG_INFO, "No device context\n");
760 		return;
761 	}
762 
763 	d = env->current_device->child;
764 	while (d) {
765 		char *name;
766 		fstack_t ph;
767 		name = get_package_name(env, d);
768 		REVERT_PHANDLE(env, ph, d);
769 		log_message(MSG_INFO, "%llx %s\n", (uint64_t)ph, name);
770 		d = d->peer;
771 	}
772 }
773 
774 void
775 paren_cd(fcode_env_t *env)
776 {
777 	char *str;
778 	device_t *p;
779 
780 	str = pop_a_string(env, NULL);
781 	if (strcmp(str, "/") == 0) {
782 		root_node(env);
783 		return;
784 	}
785 
786 	if (env->current_device == NULL) {
787 		log_message(MSG_INFO, "No device context\n");
788 		return;
789 	}
790 
791 	if (strcmp(str, "..") == 0)
792 		p = env->current_device->parent;
793 	else {
794 		device_t *n = env->current_device->child;
795 
796 		p = NULL;
797 		while (n) {
798 			char *name;
799 
800 			name = get_package_name(env, n);
801 			if (strcmp(name, str) == 0) {
802 				p = n;
803 				break;
804 			}
805 			n = n->peer;
806 		}
807 	}
808 
809 	if (p) {
810 		activate_device(env, p);
811 	} else {
812 		log_message(MSG_INFO, "No such node: %s\n", str);
813 	}
814 }
815 
816 void
817 do_cd(fcode_env_t *env)
818 {
819 	parse_word(env);
820 	paren_cd(env);
821 }
822 
823 void
824 do_unselect_dev(fcode_env_t *env)
825 {
826 	check_my_self(env, "unselect-dev");
827 	PUSH(DS, (fstack_t)MYSELF);
828 	close_package(env);
829 	deactivate_device(env, NULL);
830 }
831 
832 void
833 do_select_dev(fcode_env_t *env)
834 {
835 	PUSH(DS, 0);
836 	PUSH(DS, 0);
837 	two_swap(env);
838 	dollar_open_package(env);
839 	if (TOS) {
840 		MYSELF = (instance_t *)POP(DS);
841 		check_my_self(env, "select-dev");
842 		activate_device(env, MYSELF->device);
843 	} else {
844 		drop(env);
845 		log_message(MSG_INFO, "Can't open package\n");
846 	}
847 }
848 
849 void
850 device_end(fcode_env_t *env)
851 {
852 	if (env->current_device) {
853 		deactivate_device(env, NULL);
854 	}
855 }
856 
857 void
858 end_package(fcode_env_t *env)
859 {
860 	finish_device(env);
861 	close_instance_chain(env, MYSELF, 0);
862 	device_end(env);
863 	MYSELF = NULL;
864 }
865 
866 void
867 exec_parent_method(fcode_env_t *env)
868 {
869 	instance_t *old_myself;
870 	instance_t *myself;
871 	device_t *device;
872 	char *method;
873 	fstack_t d;
874 
875 	check_my_self(env, "exec-parent-method");
876 	old_myself = MYSELF;
877 	MYSELF = MYSELF->parent;
878 
879 	method = (char *)DS[-1];
880 	debug_msg(DEBUG_FIND_FCODE, "exec_parent_method: '%s'\n", method);
881 
882 	check_my_self(env, "exec-parent-method");
883 	device = MYSELF->device;
884 	do_push_package(env, device);
885 	PUSH(DS, (fstack_t)device);
886 	REVERT_PHANDLE(env, TOS, device);
887 	find_method(env);
888 	d = POP(DS);
889 	if (d) {
890 		debug_msg(DEBUG_FIND_FCODE, "exec-parent-method: '%s'/%x"
891 		    " execute\n", method, (int)TOS);
892 		execute(env);
893 		PUSH(DS, TRUE);
894 	} else {
895 		debug_msg(DEBUG_FIND_FCODE, "exec-parent-method: '%s'"
896 		    " not found\n", method);
897 		PUSH(DS, FALSE);
898 	}
899 	MYSELF = old_myself;
900 	do_push_package(env, MYSELF->device);
901 }
902 
903 void
904 dump_device(fcode_env_t *env)
905 {
906 	device_t *phandle;
907 	int i;
908 
909 	CONVERT_PHANDLE(env, phandle, POP(DS));
910 	log_message(MSG_DEBUG, "Node:      %p\n", phandle);
911 	log_message(MSG_DEBUG, "  Parent:  (%8p) %p\n",
912 	    &phandle->parent, phandle->parent);
913 	log_message(MSG_DEBUG, "  Child:   (%8p) %p\n",
914 	    &phandle->child, phandle->child);
915 	log_message(MSG_DEBUG, "  Peer:    (%8p) %p\n",
916 	    &phandle->peer, phandle->peer);
917 	log_message(MSG_DEBUG, "  Private: (%8p) %p\n",
918 	    &phandle->private, phandle->private);
919 	log_message(MSG_DEBUG, "  Props:   (%8p) %p\n",
920 	    &phandle->properties, phandle->properties);
921 	log_message(MSG_DEBUG, "  Voc:     (%8p) %p\n",
922 	    &phandle->vocabulary, phandle->vocabulary);
923 	log_message(MSG_DEBUG, "  sizes:   (%8p) %d %d\n",
924 	    &phandle->data_size,
925 	    phandle->data_size[INIT_DATA],
926 	    phandle->data_size[UINIT_DATA]);
927 	log_message(MSG_DEBUG, "  my_space: %x\n", phandle->my_space);
928 	log_message(MSG_DEBUG, "  my_addr :");
929 	for (i = 0; i < MAX_MY_ADDR; i++)
930 		log_message(MSG_DEBUG, " %x", (int)phandle->my_addr[i]);
931 	log_message(MSG_DEBUG, "\n");
932 	log_message(MSG_DEBUG, "  data:    (%8p)\n", phandle->init_data);
933 	for (i = 0; i < phandle->data_size[INIT_DATA]; i++) {
934 		log_message(MSG_DEBUG, "    %3d  -> (%8p) %x\n", i,
935 		    &phandle->init_data[i], phandle->init_data[i]);
936 	}
937 }
938 
939 void
940 dump_instance(fcode_env_t *env)
941 {
942 	int i;
943 	instance_t *ihandle;
944 
945 	ihandle = (instance_t *)POP(DS);
946 	log_message(MSG_DEBUG, "Ihandle:      %p\n", ihandle);
947 	log_message(MSG_DEBUG, "  Parent:  (%8p) %p\n",
948 	    &ihandle->parent, ihandle->parent);
949 	log_message(MSG_DEBUG, "  Device:  (%8p) %p\n",
950 	    &ihandle->device, ihandle->device);
951 	log_message(MSG_DEBUG, "  args:     '%s'\n",
952 	    ((ihandle->my_args) ? ihandle->my_args : ""));
953 	log_message(MSG_DEBUG, "  my-space: %x\n", ihandle->my_space);
954 	log_message(MSG_DEBUG, "  my_addr :");
955 	for (i = 0; i < MAX_MY_ADDR; i++)
956 		log_message(MSG_DEBUG, " %x", (int)ihandle->my_addr[i]);
957 	log_message(MSG_DEBUG, "\n");
958 	log_message(MSG_DEBUG, "  sizes:   %d %d\n",
959 	    ihandle->device->data_size[INIT_DATA],
960 	    ihandle->device->data_size[UINIT_DATA]);
961 	log_message(MSG_DEBUG, "  data:    (%8p) %x %x\n",
962 	    ihandle->data, ihandle->data[0], ihandle->data[1]);
963 	if (ihandle->device->data_size[INIT_DATA]) {
964 		log_message(MSG_DEBUG, "  Initialised:\n");
965 		for (i = 0; i < ihandle->device->data_size[INIT_DATA]; i++) {
966 			log_message(MSG_DEBUG, "    %3d  -> (%8p) %x\n", i,
967 			    &ihandle->data[INIT_DATA][i],
968 			    ihandle->data[INIT_DATA][i]);
969 		}
970 	}
971 	if (ihandle->device->data_size[INIT_DATA]) {
972 		log_message(MSG_DEBUG, "  UnInitialised:\n");
973 		for (i = 0; i < ihandle->device->data_size[UINIT_DATA]; i++) {
974 			log_message(MSG_DEBUG, "    %3d  -> (%8p) %x\n", i,
975 			    &ihandle->data[UINIT_DATA][i],
976 			    ihandle->data[UINIT_DATA][i]);
977 		}
978 	}
979 }
980 
981 #endif
982 
983 #pragma init(_init)
984 
985 #ifdef CONVERT_HANDLES
986 static device_t	*
987 safe_convert_phandle(fcode_env_t *env, fstack_t d)
988 {
989 	return ((device_t *)d);
990 }
991 
992 static fstack_t
993 safe_revert_phandle(fcode_env_t *env, device_t *d)
994 {
995 	return ((fstack_t)d);
996 }
997 
998 static void
999 safe_allocate_phandle(fcode_env_t *env)
1000 {
1001 }
1002 
1003 #endif
1004 
1005 static void
1006 _init(void)
1007 {
1008 	fcode_env_t *env = initial_env;
1009 	char *name = "/";
1010 	device_t *d;
1011 
1012 	ASSERT(env);
1013 	NOTICE;
1014 
1015 #ifdef CONVERT_HANDLES
1016 	env->convert_phandle = safe_convert_phandle;
1017 	env->revert_phandle = safe_revert_phandle;
1018 	env->allocate_phandle = safe_allocate_phandle;
1019 #endif
1020 
1021 	/* build the root node */
1022 	d = create_phandle(env, NULL);
1023 	env->current_device = d;
1024 	env->root_node = d;
1025 	push_a_string(env, name);
1026 	device_name(env);
1027 	env->current_device = NULL;
1028 
1029 	create_my_self(env);
1030 	create_my_space(env);
1031 
1032 	P1275(0x102, 0,		"my-address",		my_address);
1033 	/* Fcode 0x103 "my-space" is created using create_internal_value */
1034 
1035 	P1275(0x11f, 0,		"new-device",		new_device);
1036 
1037 	P1275(0x127, 0,		"finish-device",	finish_device);
1038 
1039 	FCODE(0x129, 0,		"push-package",		push_package);
1040 	FCODE(0x12a, 0,		"pop-package",		pop_package);
1041 	FCODE(0x12b, 0,		"interpose",		interpose);
1042 
1043 	P1275(0x202, 0,		"my-args",		my_args);
1044 	/* Fcode 0x203 "my-self" is created using create_internal_value */
1045 	P1275(0x204, 0,		"find-package",		find_package);
1046 	P1275(0x205, 0,		"open-package",		open_package);
1047 	P1275(0x206, 0,		"close-package",	close_package);
1048 	P1275(0x207, 0,		"find-method",		find_method);
1049 	P1275(0x208, 0,		"call-package",		call_package);
1050 	P1275(0x209, 0,		"$call-parent",		dollar_call_parent);
1051 	P1275(0x20a, 0,		"my-parent",		my_parent);
1052 	P1275(0x20b, 0,		"ihandle>phandle",	ihandle_to_phandle);
1053 
1054 	P1275(0x20d, 0,		"my-unit",		my_unit);
1055 	P1275(0x20e, 0,		"$call-method",		dollar_call_method);
1056 	P1275(0x20f, 0,		"$open-package",	dollar_open_package);
1057 
1058 	P1275(0x23b, 0,		"child",		child_node);
1059 	P1275(0x23c, 0,		"peer",			peer_node);
1060 
1061 	P1275(0x23f, 0,		"set-args",		set_args);
1062 
1063 	FORTH(IMMEDIATE,	"root-node",		root_node);
1064 	FORTH(0,		"current-device",	current_device);
1065 	FORTH(0,		"pwd$",			pwd_dollar);
1066 	FORTH(IMMEDIATE,	"pwd",			pwd);
1067 	FORTH(IMMEDIATE,	"ls",			do_ls);
1068 	FORTH(IMMEDIATE,	"(cd)",			paren_cd);
1069 	FORTH(IMMEDIATE,	"cd",			do_cd);
1070 	FORTH(IMMEDIATE,	"device-end",		device_end);
1071 	FORTH(0,		"select-dev",		do_select_dev);
1072 	FORTH(0,		"unselect-dev",		do_unselect_dev);
1073 	FORTH(0,		"begin-package",	begin_package);
1074 	FORTH(0,		"end-package",		end_package);
1075 	FORTH(IMMEDIATE,	"dump-device",		dump_device);
1076 	FORTH(IMMEDIATE,	"dump-instance",	dump_instance);
1077 	FORTH(0,		"exec-parent-method",	exec_parent_method);
1078 }
1079