xref: /illumos-gate/usr/src/common/ficl/loader.c (revision 9f923083)
1 /*
2  * Copyright (c) 2000 Daniel Capo Sobral
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  *	$FreeBSD$
27  */
28 
29 /*
30  * l o a d e r . c
31  * Additional FICL words designed for FreeBSD's loader
32  */
33 
34 #ifndef STAND
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <dirent.h>
38 #include <fcntl.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <unistd.h>
42 #include <strings.h>
43 #include <termios.h>
44 #else
45 #include <stand.h>
46 #ifdef __i386__
47 #include <machine/cpufunc.h>
48 #endif
49 #include "bootstrap.h"
50 #endif
51 #include <string.h>
52 #include "ficl.h"
53 
54 extern int biospci_count_device_type(uint32_t);
55 extern int biospci_write_config(uint32_t, int, int, uint32_t);
56 extern int biospci_read_config(uint32_t, int, int, uint32_t *);
57 extern int biospci_find_devclass(uint32_t, int, uint32_t *);
58 extern int biospci_find_device(uint32_t, int, uint32_t *);
59 extern uint32_t biospci_locator(uint8_t, uint8_t, uint8_t);
60 
61 /*
62  *		FreeBSD's loader interaction words and extras
63  *
64  *		setenv      ( value n name n' -- )
65  *		setenv?     ( value n name n' flag -- )
66  *		getenv      ( addr n -- addr' n' | -1 )
67  *		unsetenv    ( addr n -- )
68  *		copyin      ( addr addr' len -- )
69  *		copyout     ( addr addr' len -- )
70  *		findfile    ( name len type len' -- addr )
71  *		pnpdevices  ( -- addr )
72  *		pnphandlers ( -- addr )
73  *		ccall       ( [[...[p10] p9] ... p1] n addr -- result )
74  *		.#	    ( value -- )
75  */
76 
77 void
78 ficlSetenv(ficlVm *pVM)
79 {
80 	char *name, *value;
81 	char *namep, *valuep;
82 	int names, values;
83 
84 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 4, 0);
85 
86 	names = ficlStackPopInteger(ficlVmGetDataStack(pVM));
87 	namep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM));
88 	values = ficlStackPopInteger(ficlVmGetDataStack(pVM));
89 	valuep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM));
90 
91 	name = (char *)ficlMalloc(names+1);
92 	if (!name)
93 		ficlVmThrowError(pVM, "Error: out of memory");
94 	strncpy(name, namep, names);
95 	name[names] = '\0';
96 	value = (char *)ficlMalloc(values+1);
97 	if (!value)
98 		ficlVmThrowError(pVM, "Error: out of memory");
99 	strncpy(value, valuep, values);
100 	value[values] = '\0';
101 
102 	setenv(name, value, 1);
103 	ficlFree(name);
104 	ficlFree(value);
105 }
106 
107 void
108 ficlSetenvq(ficlVm *pVM)
109 {
110 	char *name, *value;
111 	char *namep, *valuep;
112 	int names, values, overwrite;
113 
114 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 5, 0);
115 
116 	overwrite = ficlStackPopInteger(ficlVmGetDataStack(pVM));
117 	names = ficlStackPopInteger(ficlVmGetDataStack(pVM));
118 	namep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM));
119 	values = ficlStackPopInteger(ficlVmGetDataStack(pVM));
120 	valuep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM));
121 
122 	name = (char *)ficlMalloc(names+1);
123 	if (!name)
124 		ficlVmThrowError(pVM, "Error: out of memory");
125 	strncpy(name, namep, names);
126 	name[names] = '\0';
127 	value = (char *)ficlMalloc(values+1);
128 	if (!value)
129 		ficlVmThrowError(pVM, "Error: out of memory");
130 	strncpy(value, valuep, values);
131 	value[values] = '\0';
132 
133 	setenv(name, value, overwrite);
134 	ficlFree(name);
135 	ficlFree(value);
136 }
137 
138 void
139 ficlGetenv(ficlVm *pVM)
140 {
141 	char *name, *value;
142 	char *namep;
143 	int names;
144 
145 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 2);
146 
147 	names = ficlStackPopInteger(ficlVmGetDataStack(pVM));
148 	namep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM));
149 
150 	name = (char *)ficlMalloc(names+1);
151 	if (!name)
152 		ficlVmThrowError(pVM, "Error: out of memory");
153 	strncpy(name, namep, names);
154 	name[names] = '\0';
155 
156 	value = getenv(name);
157 	ficlFree(name);
158 
159 	if (value != NULL) {
160 		ficlStackPushPointer(ficlVmGetDataStack(pVM), value);
161 		ficlStackPushInteger(ficlVmGetDataStack(pVM), strlen(value));
162 	} else
163 		ficlStackPushInteger(ficlVmGetDataStack(pVM), -1);
164 }
165 
166 void
167 ficlUnsetenv(ficlVm *pVM)
168 {
169 	char *name;
170 	char *namep;
171 	int names;
172 
173 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 0);
174 
175 	names = ficlStackPopInteger(ficlVmGetDataStack(pVM));
176 	namep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM));
177 
178 	name = (char *)ficlMalloc(names+1);
179 	if (!name)
180 		ficlVmThrowError(pVM, "Error: out of memory");
181 	strncpy(name, namep, names);
182 	name[names] = '\0';
183 
184 	unsetenv(name);
185 	ficlFree(name);
186 }
187 
188 void
189 ficlCopyin(ficlVm *pVM)
190 {
191 #ifdef STAND
192 	void*		src;
193 	vm_offset_t	dest;
194 	size_t		len;
195 #endif
196 
197 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 0);
198 
199 #ifdef STAND
200 	len = ficlStackPopInteger(ficlVmGetDataStack(pVM));
201 	dest = ficlStackPopInteger(ficlVmGetDataStack(pVM));
202 	src = ficlStackPopPointer(ficlVmGetDataStack(pVM));
203 	archsw.arch_copyin(src, dest, len);
204 #else
205 	(void) ficlStackPopInteger(ficlVmGetDataStack(pVM));
206 	(void) ficlStackPopInteger(ficlVmGetDataStack(pVM));
207 	(void) ficlStackPopPointer(ficlVmGetDataStack(pVM));
208 #endif
209 }
210 
211 void
212 ficlCopyout(ficlVm *pVM)
213 {
214 #ifdef STAND
215 	void*		dest;
216 	vm_offset_t	src;
217 	size_t		len;
218 #endif
219 
220 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 0);
221 
222 #ifdef STAND
223 	len = ficlStackPopInteger(ficlVmGetDataStack(pVM));
224 	dest = ficlStackPopPointer(ficlVmGetDataStack(pVM));
225 	src = ficlStackPopInteger(ficlVmGetDataStack(pVM));
226 	archsw.arch_copyout(src, dest, len);
227 #else
228 	(void) ficlStackPopInteger(ficlVmGetDataStack(pVM));
229 	(void) ficlStackPopPointer(ficlVmGetDataStack(pVM));
230 	(void) ficlStackPopInteger(ficlVmGetDataStack(pVM));
231 #endif
232 }
233 
234 void
235 ficlFindfile(ficlVm *pVM)
236 {
237 #ifdef STAND
238 	char	*name, *type;
239 	char	*namep, *typep;
240 	int	names, types;
241 #endif
242 	struct	preloaded_file *fp;
243 
244 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 4, 1);
245 
246 #ifdef STAND
247 	types = ficlStackPopInteger(ficlVmGetDataStack(pVM));
248 	typep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM));
249 	names = ficlStackPopInteger(ficlVmGetDataStack(pVM));
250 	namep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM));
251 
252 	name = (char *)ficlMalloc(names+1);
253 	if (!name)
254 		ficlVmThrowError(pVM, "Error: out of memory");
255 	strncpy(name, namep, names);
256 	name[names] = '\0';
257 	type = (char *)ficlMalloc(types+1);
258 	if (!type)
259 		ficlVmThrowError(pVM, "Error: out of memory");
260 	strncpy(type, typep, types);
261 	type[types] = '\0';
262 
263 	fp = file_findfile(name, type);
264 #else
265 	(void) ficlStackPopInteger(ficlVmGetDataStack(pVM));
266 	(void) ficlStackPopPointer(ficlVmGetDataStack(pVM));
267 	(void) ficlStackPopInteger(ficlVmGetDataStack(pVM));
268 	(void) ficlStackPopPointer(ficlVmGetDataStack(pVM));
269 
270 	fp = NULL;
271 #endif
272 	ficlStackPushPointer(ficlVmGetDataStack(pVM), fp);
273 }
274 
275 #ifdef STAND
276 #ifdef HAVE_PNP
277 
278 void
279 ficlPnpdevices(ficlVm *pVM)
280 {
281 	static int pnp_devices_initted = 0;
282 
283 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 0, 1);
284 
285 	if (!pnp_devices_initted) {
286 		STAILQ_INIT(&pnp_devices);
287 		pnp_devices_initted = 1;
288 	}
289 
290 	ficlStackPushPointer(ficlVmGetDataStack(pVM), &pnp_devices);
291 }
292 
293 void
294 ficlPnphandlers(ficlVm *pVM)
295 {
296 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 0, 1);
297 
298 	ficlStackPushPointer(ficlVmGetDataStack(pVM), pnphandlers);
299 }
300 
301 #endif
302 #endif /* ifdef STAND */
303 
304 void
305 ficlCcall(ficlVm *pVM)
306 {
307 	int (*func)(int, ...);
308 	int result, p[10];
309 	int nparam, i;
310 
311 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 0);
312 
313 	func = (int (*)(int, ...))ficlStackPopPointer(ficlVmGetDataStack(pVM));
314 	nparam = ficlStackPopInteger(ficlVmGetDataStack(pVM));
315 
316 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), nparam, 1);
317 
318 	for (i = 0; i < nparam; i++)
319 		p[i] = ficlStackPopInteger(ficlVmGetDataStack(pVM));
320 
321 	result = func(p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8],
322 	    p[9]);
323 
324 	ficlStackPushInteger(ficlVmGetDataStack(pVM), result);
325 }
326 
327 /*
328  * f i c l E x e c F D
329  * reads in text from file fd and passes it to ficlExec()
330  * returns FICL_VM_STATUS_OUT_OF_TEXT on success or the ficlExec() error
331  * code on failure.
332  */
333 #define	nLINEBUF	256
334 int
335 ficlExecFD(ficlVm *pVM, int fd)
336 {
337 	char cp[nLINEBUF];
338 	int nLine = 0, rval = FICL_VM_STATUS_OUT_OF_TEXT;
339 	char ch;
340 	ficlCell id;
341 	ficlString s;
342 
343 	id = pVM->sourceId;
344 	pVM->sourceId.i = fd+1; /* in loader we can get 0, there is no stdin */
345 
346 	/* feed each line to ficlExec */
347 	while (1) {
348 		int status, i;
349 
350 		i = 0;
351 		while ((status = read(fd, &ch, 1)) > 0 && ch != '\n')
352 			cp[i++] = ch;
353 		nLine++;
354 		if (!i) {
355 			if (status < 1)
356 				break;
357 			continue;
358 		}
359 		if (cp[i] == '\n')
360 			cp[i] = '\0';
361 
362 		FICL_STRING_SET_POINTER(s, cp);
363 		FICL_STRING_SET_LENGTH(s, i);
364 
365 		rval = ficlVmExecuteString(pVM, s);
366 		if (rval != FICL_VM_STATUS_QUIT &&
367 		    rval != FICL_VM_STATUS_USER_EXIT &&
368 		    rval != FICL_VM_STATUS_OUT_OF_TEXT) {
369 			pVM->sourceId = id;
370 			(void) ficlVmEvaluate(pVM, "");
371 			return (rval);
372 		}
373 	}
374 	pVM->sourceId = id;
375 
376 	/*
377 	 * Pass an empty line with SOURCE-ID == -1 to flush
378 	 * any pending REFILLs (as required by FILE wordset)
379 	 */
380 	(void) ficlVmEvaluate(pVM, "");
381 
382 	if (rval == FICL_VM_STATUS_USER_EXIT)
383 		ficlVmThrow(pVM, FICL_VM_STATUS_USER_EXIT);
384 
385 	return (rval);
386 }
387 
388 static void displayCellNoPad(ficlVm *pVM)
389 {
390 	ficlCell c;
391 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0);
392 
393 	c = ficlStackPop(ficlVmGetDataStack(pVM));
394 	ficlLtoa((c).i, pVM->pad, pVM->base);
395 	ficlVmTextOut(pVM, pVM->pad);
396 }
397 
398 /*
399  * isdir? - Return whether an fd corresponds to a directory.
400  *
401  * isdir? ( fd -- bool )
402  */
403 static void
404 isdirQuestion(ficlVm *pVM)
405 {
406 	struct stat sb;
407 	ficlInteger flag;
408 	int fd;
409 
410 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 1);
411 
412 	fd = ficlStackPopInteger(ficlVmGetDataStack(pVM));
413 	flag = FICL_FALSE;
414 	do {
415 		if (fd < 0)
416 			break;
417 		if (fstat(fd, &sb) < 0)
418 			break;
419 		if (!S_ISDIR(sb.st_mode))
420 			break;
421 		flag = FICL_TRUE;
422 	} while (0);
423 	ficlStackPushInteger(ficlVmGetDataStack(pVM), flag);
424 }
425 
426 /*
427  * fopen - open a file and return new fd on stack.
428  *
429  * fopen ( ptr count mode -- fd )
430  */
431 extern char *get_dev(const char *);
432 
433 static void
434 pfopen(ficlVm *pVM)
435 {
436 	int mode, fd, count;
437 	char *ptr, *name;
438 #ifndef STAND
439 	char *tmp;
440 #endif
441 
442 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 1);
443 
444 	mode = ficlStackPopInteger(ficlVmGetDataStack(pVM));	/* get mode */
445 	count = ficlStackPopInteger(ficlVmGetDataStack(pVM));	/* get count */
446 	ptr = ficlStackPopPointer(ficlVmGetDataStack(pVM));	/* get ptr */
447 
448 	if ((count < 0) || (ptr == NULL)) {
449 		ficlStackPushInteger(ficlVmGetDataStack(pVM), -1);
450 		return;
451 	}
452 
453 	/* ensure that the string is null terminated */
454 	name = (char *)malloc(count+1);
455 	bcopy(ptr, name, count);
456 	name[count] = 0;
457 #ifndef STAND
458 	tmp = get_dev(name);
459 	free(name);
460 	name = tmp;
461 #endif
462 
463 	/* open the file */
464 	fd = open(name, mode);
465 	free(name);
466 	ficlStackPushInteger(ficlVmGetDataStack(pVM), fd);
467 }
468 
469 /*
470  * fclose - close a file who's fd is on stack.
471  * fclose ( fd -- )
472  */
473 static void
474 pfclose(ficlVm *pVM)
475 {
476 	int fd;
477 
478 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0);
479 
480 	fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get fd */
481 	if (fd != -1)
482 		close(fd);
483 }
484 
485 /*
486  * fread - read file contents
487  * fread  ( fd buf nbytes  -- nread )
488  */
489 static void
490 pfread(ficlVm *pVM)
491 {
492 	int fd, len;
493 	char *buf;
494 
495 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 1);
496 
497 	len = ficlStackPopInteger(ficlVmGetDataStack(pVM));
498 	buf = ficlStackPopPointer(ficlVmGetDataStack(pVM)); /* get buffer */
499 	fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get fd */
500 	if (len > 0 && buf && fd != -1)
501 		ficlStackPushInteger(ficlVmGetDataStack(pVM),
502 		    read(fd, buf, len));
503 	else
504 		ficlStackPushInteger(ficlVmGetDataStack(pVM), -1);
505 }
506 
507 /*
508  * fopendir - open directory
509  *
510  * fopendir ( addr len -- ptr TRUE | FALSE )
511  */
512 static void pfopendir(ficlVm *pVM)
513 {
514 #ifndef STAND
515 	DIR *dir;
516 	char *tmp;
517 #else
518 	struct stat sb;
519 	int fd;
520 #endif
521 	int count;
522 	char *ptr, *name;
523 	ficlInteger flag = FICL_FALSE;
524 
525 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 1);
526 
527 	count = ficlStackPopInteger(ficlVmGetDataStack(pVM));
528 	ptr = ficlStackPopPointer(ficlVmGetDataStack(pVM));	/* get ptr */
529 
530 	if ((count < 0) || (ptr == NULL)) {
531 		ficlStackPushInteger(ficlVmGetDataStack(pVM), -1);
532 		return;
533 	}
534 	/* ensure that the string is null terminated */
535 	name = (char *)malloc(count+1);
536 	bcopy(ptr, name, count);
537 	name[count] = 0;
538 #ifndef STAND
539 	tmp = get_dev(name);
540 	free(name);
541 	name = tmp;
542 #else
543 	fd = open(name, O_RDONLY);
544 	free(name);
545 	do {
546 		if (fd < 0)
547 			break;
548 		if (fstat(fd, &sb) < 0)
549 			break;
550 		if (!S_ISDIR(sb.st_mode))
551 			break;
552 		flag = FICL_TRUE;
553 		ficlStackPushInteger(ficlVmGetDataStack(pVM), fd);
554 		ficlStackPushInteger(ficlVmGetDataStack(pVM), flag);
555 		return;
556 	} while (0);
557 
558 	if (fd >= 0)
559 		close(fd);
560 
561 	ficlStackPushInteger(ficlVmGetDataStack(pVM), flag);
562 		return;
563 #endif
564 #ifndef STAND
565 	dir = opendir(name);
566 	if (dir == NULL) {
567 		ficlStackPushInteger(ficlVmGetDataStack(pVM), flag);
568 		return;
569 	} else
570 		flag = FICL_TRUE;
571 
572 	ficlStackPushPointer(ficlVmGetDataStack(pVM), dir);
573 	ficlStackPushInteger(ficlVmGetDataStack(pVM), flag);
574 #endif
575 }
576 
577 /*
578  * freaddir - read directory contents
579  * freaddir ( fd -- ptr len TRUE | FALSE )
580  */
581 static void
582 pfreaddir(ficlVm *pVM)
583 {
584 #ifndef STAND
585 	static DIR *dir = NULL;
586 #else
587 	int fd;
588 #endif
589 	struct dirent *d = NULL;
590 
591 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 3);
592 	/*
593 	 * libstand readdir does not always return . nor .. so filter
594 	 * them out to have consistent behaviour.
595 	 */
596 #ifndef STAND
597 	dir = ficlStackPopPointer(ficlVmGetDataStack(pVM));
598 	if (dir != NULL)
599 		do {
600 			d = readdir(dir);
601 			if (d != NULL && strcmp(d->d_name, ".") == 0)
602 				continue;
603 			if (d != NULL && strcmp(d->d_name, "..") == 0)
604 				continue;
605 			break;
606 		} while (d != NULL);
607 #else
608 	fd = ficlStackPopInteger(ficlVmGetDataStack(pVM));
609 	if (fd != -1)
610 		do {
611 			d = readdirfd(fd);
612 			if (d != NULL && strcmp(d->d_name, ".") == 0)
613 				continue;
614 			if (d != NULL && strcmp(d->d_name, "..") == 0)
615 				continue;
616 			break;
617 		} while (d != NULL);
618 #endif
619 	if (d != NULL) {
620 		ficlStackPushPointer(ficlVmGetDataStack(pVM), d->d_name);
621 		ficlStackPushInteger(ficlVmGetDataStack(pVM),
622 		    strlen(d->d_name));
623 		ficlStackPushInteger(ficlVmGetDataStack(pVM), FICL_TRUE);
624 	} else {
625 		ficlStackPushInteger(ficlVmGetDataStack(pVM), FICL_FALSE);
626 	}
627 }
628 
629 /*
630  * fclosedir - close a dir on stack.
631  *
632  * fclosedir ( fd -- )
633  */
634 static void
635 pfclosedir(ficlVm *pVM)
636 {
637 #ifndef STAND
638 	DIR *dir;
639 #else
640 	int fd;
641 #endif
642 
643 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0);
644 
645 #ifndef STAND
646 	dir = ficlStackPopPointer(ficlVmGetDataStack(pVM)); /* get dir */
647 	if (dir != NULL)
648 		closedir(dir);
649 #else
650 	fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get fd */
651 	if (fd != -1)
652 		close(fd);
653 #endif
654 }
655 
656 /*
657  * fload - interpret file contents
658  *
659  * fload  ( fd -- )
660  */
661 static void pfload(ficlVm *pVM)
662 {
663 	int fd;
664 
665 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0);
666 
667 	fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get fd */
668 	if (fd != -1)
669 		ficlExecFD(pVM, fd);
670 }
671 
672 /*
673  * fwrite - write file contents
674  *
675  * fwrite  ( fd buf nbytes  -- nwritten )
676  */
677 static void
678 pfwrite(ficlVm *pVM)
679 {
680 	int fd, len;
681 	char *buf;
682 
683 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 1);
684 
685 	len = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* bytes to read */
686 	buf = ficlStackPopPointer(ficlVmGetDataStack(pVM)); /* get buffer */
687 	fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get fd */
688 	if (len > 0 && buf && fd != -1)
689 		ficlStackPushInteger(ficlVmGetDataStack(pVM),
690 		    write(fd, buf, len));
691 	else
692 		ficlStackPushInteger(ficlVmGetDataStack(pVM), -1);
693 }
694 
695 /*
696  * fseek - seek to a new position in a file
697  *
698  * fseek  ( fd ofs whence  -- pos )
699  */
700 static void
701 pfseek(ficlVm *pVM)
702 {
703 	int fd, pos, whence;
704 
705 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 1);
706 
707 	whence = ficlStackPopInteger(ficlVmGetDataStack(pVM));
708 	pos = ficlStackPopInteger(ficlVmGetDataStack(pVM));
709 	fd = ficlStackPopInteger(ficlVmGetDataStack(pVM));
710 	ficlStackPushInteger(ficlVmGetDataStack(pVM), lseek(fd, pos, whence));
711 }
712 
713 /*
714  * key - get a character from stdin
715  *
716  * key ( -- char )
717  */
718 static void
719 key(ficlVm *pVM)
720 {
721 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 0, 1);
722 
723 	ficlStackPushInteger(ficlVmGetDataStack(pVM), getchar());
724 }
725 
726 /*
727  * key? - check for a character from stdin (FACILITY)
728  * key? ( -- flag )
729  */
730 static void
731 keyQuestion(ficlVm *pVM)
732 {
733 #ifndef STAND
734 	char ch = -1;
735 	struct termios oldt;
736 	struct termios newt;
737 #endif
738 
739 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 0, 1);
740 
741 #ifndef STAND
742 	tcgetattr(STDIN_FILENO, &oldt);
743 	newt = oldt;
744 	newt.c_lflag &= ~(ICANON | ECHO);
745 	newt.c_cc[VMIN] = 0;
746 	newt.c_cc[VTIME] = 0;
747 	tcsetattr(STDIN_FILENO, TCSANOW, &newt);
748 	ch = getchar();
749 	tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
750 
751 	if (ch != -1)
752 		(void) ungetc(ch, stdin);
753 
754 	ficlStackPushInteger(ficlVmGetDataStack(pVM),
755 	    ch != -1? FICL_TRUE : FICL_FALSE);
756 #else
757 	ficlStackPushInteger(ficlVmGetDataStack(pVM),
758 	    ischar()? FICL_TRUE : FICL_FALSE);
759 #endif
760 }
761 
762 /*
763  * seconds - gives number of seconds since beginning of time
764  *
765  * beginning of time is defined as:
766  *
767  *	BTX	- number of seconds since midnight
768  *	FreeBSD	- number of seconds since Jan 1 1970
769  *
770  * seconds ( -- u )
771  */
772 static void
773 pseconds(ficlVm *pVM)
774 {
775 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 0, 1);
776 
777 	ficlStackPushUnsigned(ficlVmGetDataStack(pVM),
778 	    (ficlUnsigned) time(NULL));
779 }
780 
781 /*
782  * ms - wait at least that many milliseconds (FACILITY)
783  * ms ( u -- )
784  */
785 static void
786 ms(ficlVm *pVM)
787 {
788 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0);
789 
790 #ifndef STAND
791 	usleep(ficlStackPopUnsigned(ficlVmGetDataStack(pVM)) * 1000);
792 #else
793 	delay(ficlStackPopUnsigned(ficlVmGetDataStack(pVM)) * 1000);
794 #endif
795 }
796 
797 /*
798  * fkey - get a character from a file
799  * fkey ( file -- char )
800  */
801 static void
802 fkey(ficlVm *pVM)
803 {
804 	int i, fd;
805 	char ch;
806 
807 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 1);
808 
809 	fd = ficlStackPopInteger(ficlVmGetDataStack(pVM));
810 	i = read(fd, &ch, 1);
811 	ficlStackPushInteger(ficlVmGetDataStack(pVM), i > 0 ? ch : -1);
812 }
813 
814 
815 #ifdef STAND
816 #ifdef __i386__
817 
818 /*
819  * outb ( port# c -- )
820  * Store a byte to I/O port number port#
821  */
822 void
823 ficlOutb(ficlVm *pVM)
824 {
825 	uint8_t c;
826 	uint32_t port;
827 
828 	port = ficlStackPopUnsigned(ficlVmGetDataStack(pVM));
829 	c = ficlStackPopInteger(ficlVmGetDataStack(pVM));
830 	outb(port, c);
831 }
832 
833 /*
834  * inb ( port# -- c )
835  * Fetch a byte from I/O port number port#
836  */
837 void
838 ficlInb(ficlVm *pVM)
839 {
840 	uint8_t c;
841 	uint32_t port;
842 
843 	port = ficlStackPopUnsigned(ficlVmGetDataStack(pVM));
844 	c = inb(port);
845 	ficlStackPushInteger(ficlVmGetDataStack(pVM), c);
846 }
847 
848 /*
849  * pcibios-device-count (devid -- count)
850  *
851  * Returns the PCI BIOS' count of how many devices matching devid are
852  * in the system. devid is the 32-bit vendor + device.
853  */
854 static void
855 ficlPciBiosCountDevices(ficlVm *pVM)
856 {
857 	uint32_t devid;
858 	int i;
859 
860 	devid = ficlStackPopInteger(ficlVmGetDataStack(pVM));
861 
862 	i = biospci_count_device_type(devid);
863 
864 	ficlStackPushInteger(ficlVmGetDataStack(pVM), i);
865 }
866 
867 /*
868  * pcibios-write-config (locator offset width value -- )
869  *
870  * Writes the specified config register.
871  * Locator is bus << 8 | device << 3 | fuction
872  * offset is the pci config register
873  * width is 0 for byte, 1 for word, 2 for dword
874  * value is the value to write
875  */
876 static void
877 ficlPciBiosWriteConfig(ficlVm *pVM)
878 {
879 	uint32_t value, width, offset, locator;
880 
881 	value = ficlStackPopInteger(ficlVmGetDataStack(pVM));
882 	width = ficlStackPopInteger(ficlVmGetDataStack(pVM));
883 	offset = ficlStackPopInteger(ficlVmGetDataStack(pVM));
884 	locator = ficlStackPopInteger(ficlVmGetDataStack(pVM));
885 
886 	biospci_write_config(locator, offset, width, value);
887 }
888 
889 /*
890  * pcibios-read-config (locator offset width -- value)
891  *
892  * Reads the specified config register.
893  * Locator is bus << 8 | device << 3 | fuction
894  * offset is the pci config register
895  * width is 0 for byte, 1 for word, 2 for dword
896  * value is the value to read from the register
897  */
898 static void
899 ficlPciBiosReadConfig(ficlVm *pVM)
900 {
901 	uint32_t value, width, offset, locator;
902 
903 	width = ficlStackPopInteger(ficlVmGetDataStack(pVM));
904 	offset = ficlStackPopInteger(ficlVmGetDataStack(pVM));
905 	locator = ficlStackPopInteger(ficlVmGetDataStack(pVM));
906 
907 	biospci_read_config(locator, offset, width, &value);
908 
909 	ficlStackPushInteger(ficlVmGetDataStack(pVM), value);
910 }
911 
912 /*
913  * pcibios-find-devclass (class index -- locator)
914  *
915  * Finds the index'th instance of class in the pci tree.
916  * must be an exact match.
917  * class is the class to search for.
918  * index 0..N (set to 0, increment until error)
919  *
920  * Locator is bus << 8 | device << 3 | fuction (or -1 on error)
921  */
922 static void
923 ficlPciBiosFindDevclass(ficlVm *pVM)
924 {
925 	uint32_t index, class, locator;
926 
927 	index = ficlStackPopInteger(ficlVmGetDataStack(pVM));
928 	class = ficlStackPopInteger(ficlVmGetDataStack(pVM));
929 
930 	if (biospci_find_devclass(class, index, &locator))
931 		locator = 0xffffffff;
932 
933 	ficlStackPushInteger(ficlVmGetDataStack(pVM), locator);
934 }
935 
936 /*
937  * pcibios-find-device(devid index -- locator)
938  *
939  * Finds the index'th instance of devid in the pci tree.
940  * must be an exact match.
941  * class is the class to search for.
942  * index 0..N (set to 0, increment until error)
943  *
944  * Locator is bus << 8 | device << 3 | fuction (or -1 on error)
945  */
946 static void
947 ficlPciBiosFindDevice(ficlVm *pVM)
948 {
949 	uint32_t index, devid, locator;
950 
951 	index = ficlStackPopInteger(ficlVmGetDataStack(pVM));
952 	devid = ficlStackPopInteger(ficlVmGetDataStack(pVM));
953 
954 	if (biospci_find_device(devid, index, &locator))
955 		locator = 0xffffffff;
956 
957 	ficlStackPushInteger(ficlVmGetDataStack(pVM), locator);
958 }
959 
960 /*
961  * pcibios-find-device(bus device function -- locator)
962  *
963  * converts bus, device, function to locator.
964  *
965  * Locator is bus << 8 | device << 3 | fuction
966  */
967 static void
968 ficlPciBiosLocator(ficlVm *pVM)
969 {
970 	uint32_t bus, device, function, locator;
971 
972 	function = ficlStackPopInteger(ficlVmGetDataStack(pVM));
973 	device = ficlStackPopInteger(ficlVmGetDataStack(pVM));
974 	bus = ficlStackPopInteger(ficlVmGetDataStack(pVM));
975 
976 	locator = biospci_locator(bus, device, function);
977 
978 	ficlStackPushInteger(ficlVmGetDataStack(pVM), locator);
979 }
980 #endif
981 #endif
982 
983 /*
984  * Retrieves free space remaining on the dictionary
985  */
986 static void
987 freeHeap(ficlVm *pVM)
988 {
989 	ficlStackPushInteger(ficlVmGetDataStack(pVM),
990 	    ficlDictionaryCellsAvailable(ficlVmGetDictionary(pVM)));
991 }
992 
993 /*
994  * f i c l C o m p i l e P l a t f o r m
995  * Build FreeBSD platform extensions into the system dictionary
996  */
997 void
998 ficlSystemCompilePlatform(ficlSystem *pSys)
999 {
1000 	ficlDictionary *dp = ficlSystemGetDictionary(pSys);
1001 	ficlDictionary *env = ficlSystemGetEnvironment(pSys);
1002 
1003 	FICL_SYSTEM_ASSERT(pSys, dp);
1004 	FICL_SYSTEM_ASSERT(pSys, env);
1005 
1006 	ficlDictionarySetPrimitive(dp, ".#", displayCellNoPad,
1007 	    FICL_WORD_DEFAULT);
1008 	ficlDictionarySetPrimitive(dp, "isdir?", isdirQuestion,
1009 	    FICL_WORD_DEFAULT);
1010 	ficlDictionarySetPrimitive(dp, "fopen", pfopen, FICL_WORD_DEFAULT);
1011 	ficlDictionarySetPrimitive(dp, "fclose", pfclose, FICL_WORD_DEFAULT);
1012 	ficlDictionarySetPrimitive(dp, "fread", pfread, FICL_WORD_DEFAULT);
1013 	ficlDictionarySetPrimitive(dp, "fopendir", pfopendir,
1014 	    FICL_WORD_DEFAULT);
1015 	ficlDictionarySetPrimitive(dp, "freaddir", pfreaddir,
1016 	    FICL_WORD_DEFAULT);
1017 	ficlDictionarySetPrimitive(dp, "fclosedir", pfclosedir,
1018 	    FICL_WORD_DEFAULT);
1019 	ficlDictionarySetPrimitive(dp, "fload", pfload, FICL_WORD_DEFAULT);
1020 	ficlDictionarySetPrimitive(dp, "fkey", fkey, FICL_WORD_DEFAULT);
1021 	ficlDictionarySetPrimitive(dp, "fseek", pfseek, FICL_WORD_DEFAULT);
1022 	ficlDictionarySetPrimitive(dp, "fwrite", pfwrite, FICL_WORD_DEFAULT);
1023 	ficlDictionarySetPrimitive(dp, "key", key, FICL_WORD_DEFAULT);
1024 	ficlDictionarySetPrimitive(dp, "key?", keyQuestion, FICL_WORD_DEFAULT);
1025 	ficlDictionarySetPrimitive(dp, "ms", ms, FICL_WORD_DEFAULT);
1026 	ficlDictionarySetPrimitive(dp, "seconds", pseconds, FICL_WORD_DEFAULT);
1027 	ficlDictionarySetPrimitive(dp, "heap?", freeHeap, FICL_WORD_DEFAULT);
1028 
1029 	ficlDictionarySetPrimitive(dp, "setenv", ficlSetenv, FICL_WORD_DEFAULT);
1030 	ficlDictionarySetPrimitive(dp, "setenv?", ficlSetenvq,
1031 	    FICL_WORD_DEFAULT);
1032 	ficlDictionarySetPrimitive(dp, "getenv", ficlGetenv, FICL_WORD_DEFAULT);
1033 	ficlDictionarySetPrimitive(dp, "unsetenv", ficlUnsetenv,
1034 	    FICL_WORD_DEFAULT);
1035 	ficlDictionarySetPrimitive(dp, "copyin", ficlCopyin, FICL_WORD_DEFAULT);
1036 	ficlDictionarySetPrimitive(dp, "copyout", ficlCopyout,
1037 	    FICL_WORD_DEFAULT);
1038 	ficlDictionarySetPrimitive(dp, "findfile", ficlFindfile,
1039 	    FICL_WORD_DEFAULT);
1040 	ficlDictionarySetPrimitive(dp, "ccall", ficlCcall, FICL_WORD_DEFAULT);
1041 #ifdef STAND
1042 #ifdef __i386__
1043 	ficlDictionarySetPrimitive(dp, "outb", ficlOutb, FICL_WORD_DEFAULT);
1044 	ficlDictionarySetPrimitive(dp, "inb", ficlInb, FICL_WORD_DEFAULT);
1045 #endif
1046 #ifdef HAVE_PNP
1047 	ficlDictionarySetPrimitive(dp, "pnpdevices", ficlPnpdevices,
1048 	    FICL_WORD_DEFAULT);
1049 	ficlDictionarySetPrimitive(dp, "pnphandlers", ficlPnphandlers,
1050 	    FICL_WORD_DEFAULT);
1051 #endif
1052 #ifdef __i386__
1053 	ficlDictionarySetPrimitive(dp, "pcibios-device-count",
1054 	    ficlPciBiosCountDevices, FICL_WORD_DEFAULT);
1055 	ficlDictionarySetPrimitive(dp, "pcibios-read-config",
1056 	    ficlPciBiosReadConfig, FICL_WORD_DEFAULT);
1057 	ficlDictionarySetPrimitive(dp, "pcibios-write-config",
1058 	    ficlPciBiosWriteConfig, FICL_WORD_DEFAULT);
1059 	ficlDictionarySetPrimitive(dp, "pcibios-find-devclass",
1060 	    ficlPciBiosFindDevclass, FICL_WORD_DEFAULT);
1061 	ficlDictionarySetPrimitive(dp, "pcibios-find-device",
1062 	    ficlPciBiosFindDevice, FICL_WORD_DEFAULT);
1063 	ficlDictionarySetPrimitive(dp, "pcibios-locator", ficlPciBiosLocator,
1064 	    FICL_WORD_DEFAULT);
1065 #endif
1066 #endif
1067 
1068 #if defined(__i386__) || defined(__amd64__)
1069 	ficlDictionarySetConstant(env, "arch-i386", FICL_TRUE);
1070 	ficlDictionarySetConstant(env, "arch-sparc", FICL_FALSE);
1071 #endif
1072 #ifdef __sparc
1073 	ficlDictionarySetConstant(env, "arch-i386", FICL_FALSE);
1074 	ficlDictionarySetConstant(env, "arch-sparc", FICL_TRUE);
1075 #endif
1076 }
1077