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