summaryrefslogtreecommitdiff
path: root/usr/src/common/ficl/loader.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/common/ficl/loader.c')
-rw-r--r--usr/src/common/ficl/loader.c1076
1 files changed, 1076 insertions, 0 deletions
diff --git a/usr/src/common/ficl/loader.c b/usr/src/common/ficl/loader.c
new file mode 100644
index 0000000000..4000e5aabc
--- /dev/null
+++ b/usr/src/common/ficl/loader.c
@@ -0,0 +1,1076 @@
+/*
+ * Copyright (c) 2000 Daniel Capo Sobral
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * l o a d e r . c
+ * Additional FICL words designed for FreeBSD's loader
+ */
+
+#ifndef STAND
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <strings.h>
+#include <termios.h>
+#else
+#include <stand.h>
+#ifdef __i386__
+#include <machine/cpufunc.h>
+#endif
+#include "bootstrap.h"
+#endif
+#include <string.h>
+#include "ficl.h"
+
+extern int biospci_count_device_type(uint32_t);
+extern int biospci_write_config(uint32_t, int, int, uint32_t);
+extern int biospci_read_config(uint32_t, int, int, uint32_t *);
+extern int biospci_find_devclass(uint32_t, int, uint32_t *);
+extern int biospci_find_device(uint32_t, int, uint32_t *);
+extern uint32_t biospci_locator(uint8_t, uint8_t, uint8_t);
+
+/*
+ * FreeBSD's loader interaction words and extras
+ *
+ * setenv ( value n name n' -- )
+ * setenv? ( value n name n' flag -- )
+ * getenv ( addr n -- addr' n' | -1 )
+ * unsetenv ( addr n -- )
+ * copyin ( addr addr' len -- )
+ * copyout ( addr addr' len -- )
+ * findfile ( name len type len' -- addr )
+ * pnpdevices ( -- addr )
+ * pnphandlers ( -- addr )
+ * ccall ( [[...[p10] p9] ... p1] n addr -- result )
+ * .# ( value -- )
+ */
+
+void
+ficlSetenv(ficlVm *pVM)
+{
+ char *name, *value;
+ char *namep, *valuep;
+ int names, values;
+
+ FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 4, 0);
+
+ names = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+ namep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM));
+ values = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+ valuep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM));
+
+ name = (char *)ficlMalloc(names+1);
+ if (!name)
+ ficlVmThrowError(pVM, "Error: out of memory");
+ strncpy(name, namep, names);
+ name[names] = '\0';
+ value = (char *)ficlMalloc(values+1);
+ if (!value)
+ ficlVmThrowError(pVM, "Error: out of memory");
+ strncpy(value, valuep, values);
+ value[values] = '\0';
+
+ setenv(name, value, 1);
+ ficlFree(name);
+ ficlFree(value);
+}
+
+void
+ficlSetenvq(ficlVm *pVM)
+{
+ char *name, *value;
+ char *namep, *valuep;
+ int names, values, overwrite;
+
+ FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 5, 0);
+
+ overwrite = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+ names = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+ namep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM));
+ values = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+ valuep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM));
+
+ name = (char *)ficlMalloc(names+1);
+ if (!name)
+ ficlVmThrowError(pVM, "Error: out of memory");
+ strncpy(name, namep, names);
+ name[names] = '\0';
+ value = (char *)ficlMalloc(values+1);
+ if (!value)
+ ficlVmThrowError(pVM, "Error: out of memory");
+ strncpy(value, valuep, values);
+ value[values] = '\0';
+
+ setenv(name, value, overwrite);
+ ficlFree(name);
+ ficlFree(value);
+}
+
+void
+ficlGetenv(ficlVm *pVM)
+{
+ char *name, *value;
+ char *namep;
+ int names;
+
+ FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 2);
+
+ names = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+ namep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM));
+
+ name = (char *)ficlMalloc(names+1);
+ if (!name)
+ ficlVmThrowError(pVM, "Error: out of memory");
+ strncpy(name, namep, names);
+ name[names] = '\0';
+
+ value = getenv(name);
+ ficlFree(name);
+
+ if (value != NULL) {
+ ficlStackPushPointer(ficlVmGetDataStack(pVM), value);
+ ficlStackPushInteger(ficlVmGetDataStack(pVM), strlen(value));
+ } else
+ ficlStackPushInteger(ficlVmGetDataStack(pVM), -1);
+}
+
+void
+ficlUnsetenv(ficlVm *pVM)
+{
+ char *name;
+ char *namep;
+ int names;
+
+ FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 0);
+
+ names = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+ namep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM));
+
+ name = (char *)ficlMalloc(names+1);
+ if (!name)
+ ficlVmThrowError(pVM, "Error: out of memory");
+ strncpy(name, namep, names);
+ name[names] = '\0';
+
+ unsetenv(name);
+ ficlFree(name);
+}
+
+void
+ficlCopyin(ficlVm *pVM)
+{
+#ifdef STAND
+ void* src;
+ vm_offset_t dest;
+ size_t len;
+#endif
+
+ FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 0);
+
+#ifdef STAND
+ len = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+ dest = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+ src = ficlStackPopPointer(ficlVmGetDataStack(pVM));
+ archsw.arch_copyin(src, dest, len);
+#else
+ (void) ficlStackPopInteger(ficlVmGetDataStack(pVM));
+ (void) ficlStackPopInteger(ficlVmGetDataStack(pVM));
+ (void) ficlStackPopPointer(ficlVmGetDataStack(pVM));
+#endif
+}
+
+void
+ficlCopyout(ficlVm *pVM)
+{
+#ifdef STAND
+ void* dest;
+ vm_offset_t src;
+ size_t len;
+#endif
+
+ FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 0);
+
+#ifdef STAND
+ len = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+ dest = ficlStackPopPointer(ficlVmGetDataStack(pVM));
+ src = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+ archsw.arch_copyout(src, dest, len);
+#else
+ (void) ficlStackPopInteger(ficlVmGetDataStack(pVM));
+ (void) ficlStackPopPointer(ficlVmGetDataStack(pVM));
+ (void) ficlStackPopInteger(ficlVmGetDataStack(pVM));
+#endif
+}
+
+void
+ficlFindfile(ficlVm *pVM)
+{
+#ifdef STAND
+ char *name, *type;
+ char *namep, *typep;
+ int names, types;
+#endif
+ struct preloaded_file *fp;
+
+ FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 4, 1);
+
+#ifdef STAND
+ types = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+ typep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM));
+ names = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+ namep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM));
+
+ name = (char *)ficlMalloc(names+1);
+ if (!name)
+ ficlVmThrowError(pVM, "Error: out of memory");
+ strncpy(name, namep, names);
+ name[names] = '\0';
+ type = (char *)ficlMalloc(types+1);
+ if (!type)
+ ficlVmThrowError(pVM, "Error: out of memory");
+ strncpy(type, typep, types);
+ type[types] = '\0';
+
+ fp = file_findfile(name, type);
+#else
+ (void) ficlStackPopInteger(ficlVmGetDataStack(pVM));
+ (void) ficlStackPopPointer(ficlVmGetDataStack(pVM));
+ (void) ficlStackPopInteger(ficlVmGetDataStack(pVM));
+ (void) ficlStackPopPointer(ficlVmGetDataStack(pVM));
+
+ fp = NULL;
+#endif
+ ficlStackPushPointer(ficlVmGetDataStack(pVM), fp);
+}
+
+#ifdef STAND
+#ifdef HAVE_PNP
+
+void
+ficlPnpdevices(ficlVm *pVM)
+{
+ static int pnp_devices_initted = 0;
+
+ FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 0, 1);
+
+ if (!pnp_devices_initted) {
+ STAILQ_INIT(&pnp_devices);
+ pnp_devices_initted = 1;
+ }
+
+ ficlStackPushPointer(ficlVmGetDataStack(pVM), &pnp_devices);
+}
+
+void
+ficlPnphandlers(ficlVm *pVM)
+{
+ FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 0, 1);
+
+ ficlStackPushPointer(ficlVmGetDataStack(pVM), pnphandlers);
+}
+
+#endif
+#endif /* ifdef STAND */
+
+void
+ficlCcall(ficlVm *pVM)
+{
+ int (*func)(int, ...);
+ int result, p[10];
+ int nparam, i;
+
+ FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 0);
+
+ func = (int (*)(int, ...))ficlStackPopPointer(ficlVmGetDataStack(pVM));
+ nparam = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+
+ FICL_STACK_CHECK(ficlVmGetDataStack(pVM), nparam, 1);
+
+ for (i = 0; i < nparam; i++)
+ p[i] = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+
+ result = func(p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8],
+ p[9]);
+
+ ficlStackPushInteger(ficlVmGetDataStack(pVM), result);
+}
+
+/*
+ * f i c l E x e c F D
+ * reads in text from file fd and passes it to ficlExec()
+ * returns FICL_VM_STATUS_OUT_OF_TEXT on success or the ficlExec() error
+ * code on failure.
+ */
+#define nLINEBUF 256
+int
+ficlExecFD(ficlVm *pVM, int fd)
+{
+ char cp[nLINEBUF];
+ int nLine = 0, rval = FICL_VM_STATUS_OUT_OF_TEXT;
+ char ch;
+ ficlCell id;
+ ficlString s;
+
+ id = pVM->sourceId;
+ pVM->sourceId.i = fd+1; /* in loader we can get 0, there is no stdin */
+
+ /* feed each line to ficlExec */
+ while (1) {
+ int status, i;
+
+ i = 0;
+ while ((status = read(fd, &ch, 1)) > 0 && ch != '\n')
+ cp[i++] = ch;
+ nLine++;
+ if (!i) {
+ if (status < 1)
+ break;
+ continue;
+ }
+ if (cp[i] == '\n')
+ cp[i] = '\0';
+
+ FICL_STRING_SET_POINTER(s, cp);
+ FICL_STRING_SET_LENGTH(s, i);
+
+ rval = ficlVmExecuteString(pVM, s);
+ if (rval != FICL_VM_STATUS_QUIT &&
+ rval != FICL_VM_STATUS_USER_EXIT &&
+ rval != FICL_VM_STATUS_OUT_OF_TEXT) {
+ pVM->sourceId = id;
+ (void) ficlVmEvaluate(pVM, "");
+ return (rval);
+ }
+ }
+ pVM->sourceId = id;
+
+ /*
+ * Pass an empty line with SOURCE-ID == -1 to flush
+ * any pending REFILLs (as required by FILE wordset)
+ */
+ (void) ficlVmEvaluate(pVM, "");
+
+ if (rval == FICL_VM_STATUS_USER_EXIT)
+ ficlVmThrow(pVM, FICL_VM_STATUS_USER_EXIT);
+
+ return (rval);
+}
+
+static void displayCellNoPad(ficlVm *pVM)
+{
+ ficlCell c;
+ FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0);
+
+ c = ficlStackPop(ficlVmGetDataStack(pVM));
+ ficlLtoa((c).i, pVM->pad, pVM->base);
+ ficlVmTextOut(pVM, pVM->pad);
+}
+
+/*
+ * isdir? - Return whether an fd corresponds to a directory.
+ *
+ * isdir? ( fd -- bool )
+ */
+static void
+isdirQuestion(ficlVm *pVM)
+{
+ struct stat sb;
+ ficlInteger flag;
+ int fd;
+
+ FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 1);
+
+ fd = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+ flag = FICL_FALSE;
+ do {
+ if (fd < 0)
+ break;
+ if (fstat(fd, &sb) < 0)
+ break;
+ if (!S_ISDIR(sb.st_mode))
+ break;
+ flag = FICL_TRUE;
+ } while (0);
+ ficlStackPushInteger(ficlVmGetDataStack(pVM), flag);
+}
+
+/*
+ * fopen - open a file and return new fd on stack.
+ *
+ * fopen ( ptr count mode -- fd )
+ */
+extern char *get_dev(const char *);
+
+static void
+pfopen(ficlVm *pVM)
+{
+ int mode, fd, count;
+ char *ptr, *name;
+#ifndef STAND
+ char *tmp;
+#endif
+
+ FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 1);
+
+ mode = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get mode */
+ count = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get count */
+ ptr = ficlStackPopPointer(ficlVmGetDataStack(pVM)); /* get ptr */
+
+ if ((count < 0) || (ptr == NULL)) {
+ ficlStackPushInteger(ficlVmGetDataStack(pVM), -1);
+ return;
+ }
+
+ /* ensure that the string is null terminated */
+ name = (char *)malloc(count+1);
+ bcopy(ptr, name, count);
+ name[count] = 0;
+#ifndef STAND
+ tmp = get_dev(name);
+ free(name);
+ name = tmp;
+#endif
+
+ /* open the file */
+ fd = open(name, mode);
+ free(name);
+ ficlStackPushInteger(ficlVmGetDataStack(pVM), fd);
+}
+
+/*
+ * fclose - close a file who's fd is on stack.
+ * fclose ( fd -- )
+ */
+static void
+pfclose(ficlVm *pVM)
+{
+ int fd;
+
+ FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0);
+
+ fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get fd */
+ if (fd != -1)
+ close(fd);
+}
+
+/*
+ * fread - read file contents
+ * fread ( fd buf nbytes -- nread )
+ */
+static void
+pfread(ficlVm *pVM)
+{
+ int fd, len;
+ char *buf;
+
+ FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 1);
+
+ len = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+ buf = ficlStackPopPointer(ficlVmGetDataStack(pVM)); /* get buffer */
+ fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get fd */
+ if (len > 0 && buf && fd != -1)
+ ficlStackPushInteger(ficlVmGetDataStack(pVM),
+ read(fd, buf, len));
+ else
+ ficlStackPushInteger(ficlVmGetDataStack(pVM), -1);
+}
+
+/*
+ * fopendir - open directory
+ *
+ * fopendir ( addr len -- ptr TRUE | FALSE )
+ */
+static void pfopendir(ficlVm *pVM)
+{
+#ifndef STAND
+ DIR *dir;
+ char *tmp;
+#else
+ struct stat sb;
+ int fd;
+#endif
+ int count;
+ char *ptr, *name;
+ ficlInteger flag = FICL_FALSE;
+
+ FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 1);
+
+ count = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+ ptr = ficlStackPopPointer(ficlVmGetDataStack(pVM)); /* get ptr */
+
+ if ((count < 0) || (ptr == NULL)) {
+ ficlStackPushInteger(ficlVmGetDataStack(pVM), -1);
+ return;
+ }
+ /* ensure that the string is null terminated */
+ name = (char *)malloc(count+1);
+ bcopy(ptr, name, count);
+ name[count] = 0;
+#ifndef STAND
+ tmp = get_dev(name);
+ free(name);
+ name = tmp;
+#else
+ fd = open(name, O_RDONLY);
+ free(name);
+ do {
+ if (fd < 0)
+ break;
+ if (fstat(fd, &sb) < 0)
+ break;
+ if (!S_ISDIR(sb.st_mode))
+ break;
+ flag = FICL_TRUE;
+ ficlStackPushInteger(ficlVmGetDataStack(pVM), fd);
+ ficlStackPushInteger(ficlVmGetDataStack(pVM), flag);
+ return;
+ } while (0);
+
+ if (fd >= 0)
+ close(fd);
+
+ ficlStackPushInteger(ficlVmGetDataStack(pVM), flag);
+ return;
+#endif
+#ifndef STAND
+ dir = opendir(name);
+ if (dir == NULL) {
+ ficlStackPushInteger(ficlVmGetDataStack(pVM), flag);
+ return;
+ } else
+ flag = FICL_TRUE;
+
+ ficlStackPushPointer(ficlVmGetDataStack(pVM), dir);
+ ficlStackPushInteger(ficlVmGetDataStack(pVM), flag);
+#endif
+}
+
+/*
+ * freaddir - read directory contents
+ * freaddir ( fd -- ptr len TRUE | FALSE )
+ */
+static void
+pfreaddir(ficlVm *pVM)
+{
+#ifndef STAND
+ static DIR *dir = NULL;
+#else
+ int fd;
+#endif
+ struct dirent *d = NULL;
+
+ FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 3);
+ /*
+ * libstand readdir does not always return . nor .. so filter
+ * them out to have consistent behaviour.
+ */
+#ifndef STAND
+ dir = ficlStackPopPointer(ficlVmGetDataStack(pVM));
+ if (dir != NULL)
+ do {
+ d = readdir(dir);
+ if (d != NULL && strcmp(d->d_name, ".") == 0)
+ continue;
+ if (d != NULL && strcmp(d->d_name, "..") == 0)
+ continue;
+ break;
+ } while (d != NULL);
+#else
+ fd = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+ if (fd != -1)
+ do {
+ d = readdirfd(fd);
+ if (d != NULL && strcmp(d->d_name, ".") == 0)
+ continue;
+ if (d != NULL && strcmp(d->d_name, "..") == 0)
+ continue;
+ break;
+ } while (d != NULL);
+#endif
+ if (d != NULL) {
+ ficlStackPushPointer(ficlVmGetDataStack(pVM), d->d_name);
+ ficlStackPushInteger(ficlVmGetDataStack(pVM),
+ strlen(d->d_name));
+ ficlStackPushInteger(ficlVmGetDataStack(pVM), FICL_TRUE);
+ } else {
+ ficlStackPushInteger(ficlVmGetDataStack(pVM), FICL_FALSE);
+ }
+}
+
+/*
+ * fclosedir - close a dir on stack.
+ *
+ * fclosedir ( fd -- )
+ */
+static void
+pfclosedir(ficlVm *pVM)
+{
+#ifndef STAND
+ DIR *dir;
+#else
+ int fd;
+#endif
+
+ FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0);
+
+#ifndef STAND
+ dir = ficlStackPopPointer(ficlVmGetDataStack(pVM)); /* get dir */
+ if (dir != NULL)
+ closedir(dir);
+#else
+ fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get fd */
+ if (fd != -1)
+ close(fd);
+#endif
+}
+
+/*
+ * fload - interpret file contents
+ *
+ * fload ( fd -- )
+ */
+static void pfload(ficlVm *pVM)
+{
+ int fd;
+
+ FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0);
+
+ fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get fd */
+ if (fd != -1)
+ ficlExecFD(pVM, fd);
+}
+
+/*
+ * fwrite - write file contents
+ *
+ * fwrite ( fd buf nbytes -- nwritten )
+ */
+static void
+pfwrite(ficlVm *pVM)
+{
+ int fd, len;
+ char *buf;
+
+ FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 1);
+
+ len = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* bytes to read */
+ buf = ficlStackPopPointer(ficlVmGetDataStack(pVM)); /* get buffer */
+ fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get fd */
+ if (len > 0 && buf && fd != -1)
+ ficlStackPushInteger(ficlVmGetDataStack(pVM),
+ write(fd, buf, len));
+ else
+ ficlStackPushInteger(ficlVmGetDataStack(pVM), -1);
+}
+
+/*
+ * fseek - seek to a new position in a file
+ *
+ * fseek ( fd ofs whence -- pos )
+ */
+static void
+pfseek(ficlVm *pVM)
+{
+ int fd, pos, whence;
+
+ FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 1);
+
+ whence = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+ pos = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+ fd = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+ ficlStackPushInteger(ficlVmGetDataStack(pVM), lseek(fd, pos, whence));
+}
+
+/*
+ * key - get a character from stdin
+ *
+ * key ( -- char )
+ */
+static void
+key(ficlVm *pVM)
+{
+ FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 0, 1);
+
+ ficlStackPushInteger(ficlVmGetDataStack(pVM), getchar());
+}
+
+/*
+ * key? - check for a character from stdin (FACILITY)
+ * key? ( -- flag )
+ */
+static void
+keyQuestion(ficlVm *pVM)
+{
+#ifndef STAND
+ char ch = -1;
+ struct termios oldt;
+ struct termios newt;
+#endif
+
+ FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 0, 1);
+
+#ifndef STAND
+ tcgetattr(STDIN_FILENO, &oldt);
+ newt = oldt;
+ newt.c_lflag &= ~(ICANON | ECHO);
+ newt.c_cc[VMIN] = 0;
+ newt.c_cc[VTIME] = 0;
+ tcsetattr(STDIN_FILENO, TCSANOW, &newt);
+ ch = getchar();
+ tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
+
+ if (ch != -1)
+ (void) ungetc(ch, stdin);
+
+ ficlStackPushInteger(ficlVmGetDataStack(pVM),
+ ch != -1? FICL_TRUE : FICL_FALSE);
+#else
+ ficlStackPushInteger(ficlVmGetDataStack(pVM),
+ ischar()? FICL_TRUE : FICL_FALSE);
+#endif
+}
+
+/*
+ * seconds - gives number of seconds since beginning of time
+ *
+ * beginning of time is defined as:
+ *
+ * BTX - number of seconds since midnight
+ * FreeBSD - number of seconds since Jan 1 1970
+ *
+ * seconds ( -- u )
+ */
+static void
+pseconds(ficlVm *pVM)
+{
+ FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 0, 1);
+
+ ficlStackPushUnsigned(ficlVmGetDataStack(pVM),
+ (ficlUnsigned) time(NULL));
+}
+
+/*
+ * ms - wait at least that many milliseconds (FACILITY)
+ * ms ( u -- )
+ */
+static void
+ms(ficlVm *pVM)
+{
+ FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0);
+
+#ifndef STAND
+ usleep(ficlStackPopUnsigned(ficlVmGetDataStack(pVM)) * 1000);
+#else
+ delay(ficlStackPopUnsigned(ficlVmGetDataStack(pVM)) * 1000);
+#endif
+}
+
+/*
+ * fkey - get a character from a file
+ * fkey ( file -- char )
+ */
+static void
+fkey(ficlVm *pVM)
+{
+ int i, fd;
+ char ch;
+
+ FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 1);
+
+ fd = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+ i = read(fd, &ch, 1);
+ ficlStackPushInteger(ficlVmGetDataStack(pVM), i > 0 ? ch : -1);
+}
+
+
+#ifdef STAND
+#ifdef __i386__
+
+/*
+ * outb ( port# c -- )
+ * Store a byte to I/O port number port#
+ */
+void
+ficlOutb(ficlVm *pVM)
+{
+ uint8_t c;
+ uint32_t port;
+
+ port = ficlStackPopUnsigned(ficlVmGetDataStack(pVM));
+ c = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+ outb(port, c);
+}
+
+/*
+ * inb ( port# -- c )
+ * Fetch a byte from I/O port number port#
+ */
+void
+ficlInb(ficlVm *pVM)
+{
+ uint8_t c;
+ uint32_t port;
+
+ port = ficlStackPopUnsigned(ficlVmGetDataStack(pVM));
+ c = inb(port);
+ ficlStackPushInteger(ficlVmGetDataStack(pVM), c);
+}
+
+/*
+ * pcibios-device-count (devid -- count)
+ *
+ * Returns the PCI BIOS' count of how many devices matching devid are
+ * in the system. devid is the 32-bit vendor + device.
+ */
+static void
+ficlPciBiosCountDevices(ficlVm *pVM)
+{
+ uint32_t devid;
+ int i;
+
+ devid = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+
+ i = biospci_count_device_type(devid);
+
+ ficlStackPushInteger(ficlVmGetDataStack(pVM), i);
+}
+
+/*
+ * pcibios-write-config (locator offset width value -- )
+ *
+ * Writes the specified config register.
+ * Locator is bus << 8 | device << 3 | fuction
+ * offset is the pci config register
+ * width is 0 for byte, 1 for word, 2 for dword
+ * value is the value to write
+ */
+static void
+ficlPciBiosWriteConfig(ficlVm *pVM)
+{
+ uint32_t value, width, offset, locator;
+
+ value = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+ width = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+ offset = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+ locator = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+
+ biospci_write_config(locator, offset, width, value);
+}
+
+/*
+ * pcibios-read-config (locator offset width -- value)
+ *
+ * Reads the specified config register.
+ * Locator is bus << 8 | device << 3 | fuction
+ * offset is the pci config register
+ * width is 0 for byte, 1 for word, 2 for dword
+ * value is the value to read from the register
+ */
+static void
+ficlPciBiosReadConfig(ficlVm *pVM)
+{
+ uint32_t value, width, offset, locator;
+
+ width = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+ offset = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+ locator = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+
+ biospci_read_config(locator, offset, width, &value);
+
+ ficlStackPushInteger(ficlVmGetDataStack(pVM), value);
+}
+
+/*
+ * pcibios-find-devclass (class index -- locator)
+ *
+ * Finds the index'th instance of class in the pci tree.
+ * must be an exact match.
+ * class is the class to search for.
+ * index 0..N (set to 0, increment until error)
+ *
+ * Locator is bus << 8 | device << 3 | fuction (or -1 on error)
+ */
+static void
+ficlPciBiosFindDevclass(ficlVm *pVM)
+{
+ uint32_t index, class, locator;
+
+ index = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+ class = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+
+ if (biospci_find_devclass(class, index, &locator))
+ locator = 0xffffffff;
+
+ ficlStackPushInteger(ficlVmGetDataStack(pVM), locator);
+}
+
+/*
+ * pcibios-find-device(devid index -- locator)
+ *
+ * Finds the index'th instance of devid in the pci tree.
+ * must be an exact match.
+ * class is the class to search for.
+ * index 0..N (set to 0, increment until error)
+ *
+ * Locator is bus << 8 | device << 3 | fuction (or -1 on error)
+ */
+static void
+ficlPciBiosFindDevice(ficlVm *pVM)
+{
+ uint32_t index, devid, locator;
+
+ index = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+ devid = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+
+ if (biospci_find_device(devid, index, &locator))
+ locator = 0xffffffff;
+
+ ficlStackPushInteger(ficlVmGetDataStack(pVM), locator);
+}
+
+/*
+ * pcibios-find-device(bus device function -- locator)
+ *
+ * converts bus, device, function to locator.
+ *
+ * Locator is bus << 8 | device << 3 | fuction
+ */
+static void
+ficlPciBiosLocator(ficlVm *pVM)
+{
+ uint32_t bus, device, function, locator;
+
+ function = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+ device = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+ bus = ficlStackPopInteger(ficlVmGetDataStack(pVM));
+
+ locator = biospci_locator(bus, device, function);
+
+ ficlStackPushInteger(ficlVmGetDataStack(pVM), locator);
+}
+#endif
+#endif
+
+/*
+ * Retrieves free space remaining on the dictionary
+ */
+static void
+freeHeap(ficlVm *pVM)
+{
+ ficlStackPushInteger(ficlVmGetDataStack(pVM),
+ ficlDictionaryCellsAvailable(ficlVmGetDictionary(pVM)));
+}
+
+/*
+ * f i c l C o m p i l e P l a t f o r m
+ * Build FreeBSD platform extensions into the system dictionary
+ */
+void
+ficlSystemCompilePlatform(ficlSystem *pSys)
+{
+ ficlDictionary *dp = ficlSystemGetDictionary(pSys);
+ ficlDictionary *env = ficlSystemGetEnvironment(pSys);
+
+ FICL_SYSTEM_ASSERT(pSys, dp);
+ FICL_SYSTEM_ASSERT(pSys, env);
+
+ ficlDictionarySetPrimitive(dp, ".#", displayCellNoPad,
+ FICL_WORD_DEFAULT);
+ ficlDictionarySetPrimitive(dp, "isdir?", isdirQuestion,
+ FICL_WORD_DEFAULT);
+ ficlDictionarySetPrimitive(dp, "fopen", pfopen, FICL_WORD_DEFAULT);
+ ficlDictionarySetPrimitive(dp, "fclose", pfclose, FICL_WORD_DEFAULT);
+ ficlDictionarySetPrimitive(dp, "fread", pfread, FICL_WORD_DEFAULT);
+ ficlDictionarySetPrimitive(dp, "fopendir", pfopendir,
+ FICL_WORD_DEFAULT);
+ ficlDictionarySetPrimitive(dp, "freaddir", pfreaddir,
+ FICL_WORD_DEFAULT);
+ ficlDictionarySetPrimitive(dp, "fclosedir", pfclosedir,
+ FICL_WORD_DEFAULT);
+ ficlDictionarySetPrimitive(dp, "fload", pfload, FICL_WORD_DEFAULT);
+ ficlDictionarySetPrimitive(dp, "fkey", fkey, FICL_WORD_DEFAULT);
+ ficlDictionarySetPrimitive(dp, "fseek", pfseek, FICL_WORD_DEFAULT);
+ ficlDictionarySetPrimitive(dp, "fwrite", pfwrite, FICL_WORD_DEFAULT);
+ ficlDictionarySetPrimitive(dp, "key", key, FICL_WORD_DEFAULT);
+ ficlDictionarySetPrimitive(dp, "key?", keyQuestion, FICL_WORD_DEFAULT);
+ ficlDictionarySetPrimitive(dp, "ms", ms, FICL_WORD_DEFAULT);
+ ficlDictionarySetPrimitive(dp, "seconds", pseconds, FICL_WORD_DEFAULT);
+ ficlDictionarySetPrimitive(dp, "heap?", freeHeap, FICL_WORD_DEFAULT);
+
+ ficlDictionarySetPrimitive(dp, "setenv", ficlSetenv, FICL_WORD_DEFAULT);
+ ficlDictionarySetPrimitive(dp, "setenv?", ficlSetenvq,
+ FICL_WORD_DEFAULT);
+ ficlDictionarySetPrimitive(dp, "getenv", ficlGetenv, FICL_WORD_DEFAULT);
+ ficlDictionarySetPrimitive(dp, "unsetenv", ficlUnsetenv,
+ FICL_WORD_DEFAULT);
+ ficlDictionarySetPrimitive(dp, "copyin", ficlCopyin, FICL_WORD_DEFAULT);
+ ficlDictionarySetPrimitive(dp, "copyout", ficlCopyout,
+ FICL_WORD_DEFAULT);
+ ficlDictionarySetPrimitive(dp, "findfile", ficlFindfile,
+ FICL_WORD_DEFAULT);
+ ficlDictionarySetPrimitive(dp, "ccall", ficlCcall, FICL_WORD_DEFAULT);
+#ifdef STAND
+#ifdef __i386__
+ ficlDictionarySetPrimitive(dp, "outb", ficlOutb, FICL_WORD_DEFAULT);
+ ficlDictionarySetPrimitive(dp, "inb", ficlInb, FICL_WORD_DEFAULT);
+#endif
+#ifdef HAVE_PNP
+ ficlDictionarySetPrimitive(dp, "pnpdevices", ficlPnpdevices,
+ FICL_WORD_DEFAULT);
+ ficlDictionarySetPrimitive(dp, "pnphandlers", ficlPnphandlers,
+ FICL_WORD_DEFAULT);
+#endif
+#ifdef __i386__
+ ficlDictionarySetPrimitive(dp, "pcibios-device-count",
+ ficlPciBiosCountDevices, FICL_WORD_DEFAULT);
+ ficlDictionarySetPrimitive(dp, "pcibios-read-config",
+ ficlPciBiosReadConfig, FICL_WORD_DEFAULT);
+ ficlDictionarySetPrimitive(dp, "pcibios-write-config",
+ ficlPciBiosWriteConfig, FICL_WORD_DEFAULT);
+ ficlDictionarySetPrimitive(dp, "pcibios-find-devclass",
+ ficlPciBiosFindDevclass, FICL_WORD_DEFAULT);
+ ficlDictionarySetPrimitive(dp, "pcibios-find-device",
+ ficlPciBiosFindDevice, FICL_WORD_DEFAULT);
+ ficlDictionarySetPrimitive(dp, "pcibios-locator", ficlPciBiosLocator,
+ FICL_WORD_DEFAULT);
+#endif
+#endif
+
+#if defined(__i386__) || defined(__amd64__)
+ ficlDictionarySetConstant(env, "arch-i386", FICL_TRUE);
+ ficlDictionarySetConstant(env, "arch-sparc", FICL_FALSE);
+#endif
+#ifdef __sparc
+ ficlDictionarySetConstant(env, "arch-i386", FICL_FALSE);
+ ficlDictionarySetConstant(env, "arch-sparc", FICL_TRUE);
+#endif
+}