ea3c3dd245
bootloader. Implement the following routines: pcibios-device-count count the number of instances of a devid pcibios-read-config read pci config space pcibios-write-config write pci config space pcibios-find-devclass find the nth device with a given devclass pcibios-find-device find the nth device with a given devid pcibios-locator convert bus device function ti pcibios locator These commands are thin wrappers over their PCI BIOS 2.1 counterparts. More informaiton, such as it is, can be found in the standard. Export a nunmber of pcibios.X variables into the environment to report what the PCI IDENTIFY command returned. Also implmenet a new command line primitive (pci-device-count), but don't include it by default just yet, since it depends on the recently added words and any errors here can render a system unbootable. This is intended to allow the boot loader to do special things based on the hardware it finds. This could be have special settings that are optimized for the specific cards, or even loading special drivers. It goes without saying that writing to pci config space should not be done without a just cause and a sound mind. Sponsored by: Netflix
954 lines
21 KiB
C
954 lines
21 KiB
C
/*-
|
|
* 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
|
|
**
|
|
*******************************************************************/
|
|
|
|
#ifdef TESTMAIN
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <dirent.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#else
|
|
#include <stand.h>
|
|
#endif
|
|
#include "bootstrap.h"
|
|
#include <string.h>
|
|
#include "ficl.h"
|
|
|
|
/* 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(FICL_VM *pVM)
|
|
{
|
|
#ifndef TESTMAIN
|
|
char *name, *value;
|
|
#endif
|
|
char *namep, *valuep;
|
|
int names, values;
|
|
|
|
#if FICL_ROBUST > 1
|
|
vmCheckStack(pVM, 4, 0);
|
|
#endif
|
|
names = stackPopINT(pVM->pStack);
|
|
namep = (char*) stackPopPtr(pVM->pStack);
|
|
values = stackPopINT(pVM->pStack);
|
|
valuep = (char*) stackPopPtr(pVM->pStack);
|
|
|
|
#ifndef TESTMAIN
|
|
name = (char*) ficlMalloc(names+1);
|
|
if (!name)
|
|
vmThrowErr(pVM, "Error: out of memory");
|
|
strncpy(name, namep, names);
|
|
name[names] = '\0';
|
|
value = (char*) ficlMalloc(values+1);
|
|
if (!value)
|
|
vmThrowErr(pVM, "Error: out of memory");
|
|
strncpy(value, valuep, values);
|
|
value[values] = '\0';
|
|
|
|
setenv(name, value, 1);
|
|
ficlFree(name);
|
|
ficlFree(value);
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
void
|
|
ficlSetenvq(FICL_VM *pVM)
|
|
{
|
|
#ifndef TESTMAIN
|
|
char *name, *value;
|
|
#endif
|
|
char *namep, *valuep;
|
|
int names, values, overwrite;
|
|
|
|
#if FICL_ROBUST > 1
|
|
vmCheckStack(pVM, 5, 0);
|
|
#endif
|
|
overwrite = stackPopINT(pVM->pStack);
|
|
names = stackPopINT(pVM->pStack);
|
|
namep = (char*) stackPopPtr(pVM->pStack);
|
|
values = stackPopINT(pVM->pStack);
|
|
valuep = (char*) stackPopPtr(pVM->pStack);
|
|
|
|
#ifndef TESTMAIN
|
|
name = (char*) ficlMalloc(names+1);
|
|
if (!name)
|
|
vmThrowErr(pVM, "Error: out of memory");
|
|
strncpy(name, namep, names);
|
|
name[names] = '\0';
|
|
value = (char*) ficlMalloc(values+1);
|
|
if (!value)
|
|
vmThrowErr(pVM, "Error: out of memory");
|
|
strncpy(value, valuep, values);
|
|
value[values] = '\0';
|
|
|
|
setenv(name, value, overwrite);
|
|
ficlFree(name);
|
|
ficlFree(value);
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
void
|
|
ficlGetenv(FICL_VM *pVM)
|
|
{
|
|
#ifndef TESTMAIN
|
|
char *name, *value;
|
|
#endif
|
|
char *namep;
|
|
int names;
|
|
|
|
#if FICL_ROBUST > 1
|
|
vmCheckStack(pVM, 2, 2);
|
|
#endif
|
|
names = stackPopINT(pVM->pStack);
|
|
namep = (char*) stackPopPtr(pVM->pStack);
|
|
|
|
#ifndef TESTMAIN
|
|
name = (char*) ficlMalloc(names+1);
|
|
if (!name)
|
|
vmThrowErr(pVM, "Error: out of memory");
|
|
strncpy(name, namep, names);
|
|
name[names] = '\0';
|
|
|
|
value = getenv(name);
|
|
ficlFree(name);
|
|
|
|
if(value != NULL) {
|
|
stackPushPtr(pVM->pStack, value);
|
|
stackPushINT(pVM->pStack, strlen(value));
|
|
} else
|
|
#endif
|
|
stackPushINT(pVM->pStack, -1);
|
|
|
|
return;
|
|
}
|
|
|
|
void
|
|
ficlUnsetenv(FICL_VM *pVM)
|
|
{
|
|
#ifndef TESTMAIN
|
|
char *name;
|
|
#endif
|
|
char *namep;
|
|
int names;
|
|
|
|
#if FICL_ROBUST > 1
|
|
vmCheckStack(pVM, 2, 0);
|
|
#endif
|
|
names = stackPopINT(pVM->pStack);
|
|
namep = (char*) stackPopPtr(pVM->pStack);
|
|
|
|
#ifndef TESTMAIN
|
|
name = (char*) ficlMalloc(names+1);
|
|
if (!name)
|
|
vmThrowErr(pVM, "Error: out of memory");
|
|
strncpy(name, namep, names);
|
|
name[names] = '\0';
|
|
|
|
unsetenv(name);
|
|
ficlFree(name);
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
void
|
|
ficlCopyin(FICL_VM *pVM)
|
|
{
|
|
void* src;
|
|
vm_offset_t dest;
|
|
size_t len;
|
|
|
|
#if FICL_ROBUST > 1
|
|
vmCheckStack(pVM, 3, 0);
|
|
#endif
|
|
|
|
len = stackPopINT(pVM->pStack);
|
|
dest = stackPopINT(pVM->pStack);
|
|
src = stackPopPtr(pVM->pStack);
|
|
|
|
#ifndef TESTMAIN
|
|
archsw.arch_copyin(src, dest, len);
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
void
|
|
ficlCopyout(FICL_VM *pVM)
|
|
{
|
|
void* dest;
|
|
vm_offset_t src;
|
|
size_t len;
|
|
|
|
#if FICL_ROBUST > 1
|
|
vmCheckStack(pVM, 3, 0);
|
|
#endif
|
|
|
|
len = stackPopINT(pVM->pStack);
|
|
dest = stackPopPtr(pVM->pStack);
|
|
src = stackPopINT(pVM->pStack);
|
|
|
|
#ifndef TESTMAIN
|
|
archsw.arch_copyout(src, dest, len);
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
void
|
|
ficlFindfile(FICL_VM *pVM)
|
|
{
|
|
#ifndef TESTMAIN
|
|
char *name, *type;
|
|
#endif
|
|
char *namep, *typep;
|
|
struct preloaded_file* fp;
|
|
int names, types;
|
|
|
|
#if FICL_ROBUST > 1
|
|
vmCheckStack(pVM, 4, 1);
|
|
#endif
|
|
|
|
types = stackPopINT(pVM->pStack);
|
|
typep = (char*) stackPopPtr(pVM->pStack);
|
|
names = stackPopINT(pVM->pStack);
|
|
namep = (char*) stackPopPtr(pVM->pStack);
|
|
#ifndef TESTMAIN
|
|
name = (char*) ficlMalloc(names+1);
|
|
if (!name)
|
|
vmThrowErr(pVM, "Error: out of memory");
|
|
strncpy(name, namep, names);
|
|
name[names] = '\0';
|
|
type = (char*) ficlMalloc(types+1);
|
|
if (!type)
|
|
vmThrowErr(pVM, "Error: out of memory");
|
|
strncpy(type, typep, types);
|
|
type[types] = '\0';
|
|
|
|
fp = file_findfile(name, type);
|
|
#else
|
|
fp = NULL;
|
|
#endif
|
|
stackPushPtr(pVM->pStack, fp);
|
|
|
|
return;
|
|
}
|
|
|
|
#ifndef TESTMAIN
|
|
#ifdef HAVE_PNP
|
|
|
|
void
|
|
ficlPnpdevices(FICL_VM *pVM)
|
|
{
|
|
static int pnp_devices_initted = 0;
|
|
#if FICL_ROBUST > 1
|
|
vmCheckStack(pVM, 0, 1);
|
|
#endif
|
|
|
|
if(!pnp_devices_initted) {
|
|
STAILQ_INIT(&pnp_devices);
|
|
pnp_devices_initted = 1;
|
|
}
|
|
|
|
stackPushPtr(pVM->pStack, &pnp_devices);
|
|
|
|
return;
|
|
}
|
|
|
|
void
|
|
ficlPnphandlers(FICL_VM *pVM)
|
|
{
|
|
#if FICL_ROBUST > 1
|
|
vmCheckStack(pVM, 0, 1);
|
|
#endif
|
|
|
|
stackPushPtr(pVM->pStack, pnphandlers);
|
|
|
|
return;
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif /* ndef TESTMAIN */
|
|
|
|
void
|
|
ficlCcall(FICL_VM *pVM)
|
|
{
|
|
int (*func)(int, ...);
|
|
int result, p[10];
|
|
int nparam, i;
|
|
|
|
#if FICL_ROBUST > 1
|
|
vmCheckStack(pVM, 2, 0);
|
|
#endif
|
|
|
|
func = stackPopPtr(pVM->pStack);
|
|
nparam = stackPopINT(pVM->pStack);
|
|
|
|
#if FICL_ROBUST > 1
|
|
vmCheckStack(pVM, nparam, 1);
|
|
#endif
|
|
|
|
for (i = 0; i < nparam; i++)
|
|
p[i] = stackPopINT(pVM->pStack);
|
|
|
|
result = func(p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8],
|
|
p[9]);
|
|
|
|
stackPushINT(pVM->pStack, result);
|
|
|
|
return;
|
|
}
|
|
|
|
/**************************************************************************
|
|
f i c l E x e c F D
|
|
** reads in text from file fd and passes it to ficlExec()
|
|
* returns VM_OUTOFTEXT on success or the ficlExec() error code on
|
|
* failure.
|
|
*/
|
|
#define nLINEBUF 256
|
|
int ficlExecFD(FICL_VM *pVM, int fd)
|
|
{
|
|
char cp[nLINEBUF];
|
|
int nLine = 0, rval = VM_OUTOFTEXT;
|
|
char ch;
|
|
CELL id;
|
|
|
|
id = pVM->sourceID;
|
|
pVM->sourceID.i = fd;
|
|
|
|
/* 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;
|
|
}
|
|
rval = ficlExecC(pVM, cp, i);
|
|
if(rval != VM_QUIT && rval != VM_USEREXIT && rval != VM_OUTOFTEXT)
|
|
{
|
|
pVM->sourceID = id;
|
|
return rval;
|
|
}
|
|
}
|
|
/*
|
|
** Pass an empty line with SOURCE-ID == -1 to flush
|
|
** any pending REFILLs (as required by FILE wordset)
|
|
*/
|
|
pVM->sourceID.i = -1;
|
|
ficlExec(pVM, "");
|
|
|
|
pVM->sourceID = id;
|
|
return rval;
|
|
}
|
|
|
|
static void displayCellNoPad(FICL_VM *pVM)
|
|
{
|
|
CELL c;
|
|
#if FICL_ROBUST > 1
|
|
vmCheckStack(pVM, 1, 0);
|
|
#endif
|
|
c = stackPop(pVM->pStack);
|
|
ltoa((c).i, pVM->pad, pVM->base);
|
|
vmTextOut(pVM, pVM->pad, 0);
|
|
return;
|
|
}
|
|
|
|
/* isdir? - Return whether an fd corresponds to a directory.
|
|
*
|
|
* isdir? ( fd -- bool )
|
|
*/
|
|
static void isdirQuestion(FICL_VM *pVM)
|
|
{
|
|
struct stat sb;
|
|
FICL_INT flag;
|
|
int fd;
|
|
|
|
#if FICL_ROBUST > 1
|
|
vmCheckStack(pVM, 1, 1);
|
|
#endif
|
|
|
|
fd = stackPopINT(pVM->pStack);
|
|
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);
|
|
stackPushINT(pVM->pStack, flag);
|
|
}
|
|
|
|
/* fopen - open a file and return new fd on stack.
|
|
*
|
|
* fopen ( ptr count mode -- fd )
|
|
*/
|
|
static void pfopen(FICL_VM *pVM)
|
|
{
|
|
int mode, fd, count;
|
|
char *ptr, *name;
|
|
|
|
#if FICL_ROBUST > 1
|
|
vmCheckStack(pVM, 3, 1);
|
|
#endif
|
|
|
|
mode = stackPopINT(pVM->pStack); /* get mode */
|
|
count = stackPopINT(pVM->pStack); /* get count */
|
|
ptr = stackPopPtr(pVM->pStack); /* get ptr */
|
|
|
|
if ((count < 0) || (ptr == NULL)) {
|
|
stackPushINT(pVM->pStack, -1);
|
|
return;
|
|
}
|
|
|
|
/* ensure that the string is null terminated */
|
|
name = (char *)malloc(count+1);
|
|
bcopy(ptr,name,count);
|
|
name[count] = 0;
|
|
|
|
/* open the file */
|
|
fd = open(name, mode);
|
|
free(name);
|
|
stackPushINT(pVM->pStack, fd);
|
|
return;
|
|
}
|
|
|
|
/* fclose - close a file who's fd is on stack.
|
|
*
|
|
* fclose ( fd -- )
|
|
*/
|
|
static void pfclose(FICL_VM *pVM)
|
|
{
|
|
int fd;
|
|
|
|
#if FICL_ROBUST > 1
|
|
vmCheckStack(pVM, 1, 0);
|
|
#endif
|
|
fd = stackPopINT(pVM->pStack); /* get fd */
|
|
if (fd != -1)
|
|
close(fd);
|
|
return;
|
|
}
|
|
|
|
/* fread - read file contents
|
|
*
|
|
* fread ( fd buf nbytes -- nread )
|
|
*/
|
|
static void pfread(FICL_VM *pVM)
|
|
{
|
|
int fd, len;
|
|
char *buf;
|
|
|
|
#if FICL_ROBUST > 1
|
|
vmCheckStack(pVM, 3, 1);
|
|
#endif
|
|
len = stackPopINT(pVM->pStack); /* get number of bytes to read */
|
|
buf = stackPopPtr(pVM->pStack); /* get buffer */
|
|
fd = stackPopINT(pVM->pStack); /* get fd */
|
|
if (len > 0 && buf && fd != -1)
|
|
stackPushINT(pVM->pStack, read(fd, buf, len));
|
|
else
|
|
stackPushINT(pVM->pStack, -1);
|
|
return;
|
|
}
|
|
|
|
/* freaddir - read directory contents
|
|
*
|
|
* freaddir ( fd -- ptr len TRUE | FALSE )
|
|
*/
|
|
static void pfreaddir(FICL_VM *pVM)
|
|
{
|
|
#ifdef TESTMAIN
|
|
static struct dirent dirent;
|
|
struct stat sb;
|
|
char *buf;
|
|
off_t off, ptr;
|
|
u_int blksz;
|
|
int bufsz;
|
|
#endif
|
|
struct dirent *d;
|
|
int fd;
|
|
|
|
#if FICL_ROBUST > 1
|
|
vmCheckStack(pVM, 1, 3);
|
|
#endif
|
|
|
|
fd = stackPopINT(pVM->pStack);
|
|
#if TESTMAIN
|
|
/*
|
|
* The readdirfd() function is specific to the loader environment.
|
|
* We do the best we can to make freaddir work, but it's not at
|
|
* all guaranteed.
|
|
*/
|
|
d = NULL;
|
|
buf = NULL;
|
|
do {
|
|
if (fd == -1)
|
|
break;
|
|
if (fstat(fd, &sb) == -1)
|
|
break;
|
|
blksz = (sb.st_blksize) ? sb.st_blksize : getpagesize();
|
|
if ((blksz & (blksz - 1)) != 0)
|
|
break;
|
|
buf = malloc(blksz);
|
|
if (buf == NULL)
|
|
break;
|
|
off = lseek(fd, 0LL, SEEK_CUR);
|
|
if (off == -1)
|
|
break;
|
|
ptr = off;
|
|
if (lseek(fd, 0, SEEK_SET) == -1)
|
|
break;
|
|
bufsz = getdents(fd, buf, blksz);
|
|
while (bufsz > 0 && bufsz <= ptr) {
|
|
ptr -= bufsz;
|
|
bufsz = getdents(fd, buf, blksz);
|
|
}
|
|
if (bufsz <= 0)
|
|
break;
|
|
d = (void *)(buf + ptr);
|
|
dirent = *d;
|
|
off += d->d_reclen;
|
|
d = (lseek(fd, off, SEEK_SET) != off) ? NULL : &dirent;
|
|
} while (0);
|
|
if (buf != NULL)
|
|
free(buf);
|
|
#else
|
|
d = readdirfd(fd);
|
|
#endif
|
|
if (d != NULL) {
|
|
stackPushPtr(pVM->pStack, d->d_name);
|
|
stackPushINT(pVM->pStack, strlen(d->d_name));
|
|
stackPushINT(pVM->pStack, FICL_TRUE);
|
|
} else {
|
|
stackPushINT(pVM->pStack, FICL_FALSE);
|
|
}
|
|
}
|
|
|
|
/* fload - interpret file contents
|
|
*
|
|
* fload ( fd -- )
|
|
*/
|
|
static void pfload(FICL_VM *pVM)
|
|
{
|
|
int fd;
|
|
|
|
#if FICL_ROBUST > 1
|
|
vmCheckStack(pVM, 1, 0);
|
|
#endif
|
|
fd = stackPopINT(pVM->pStack); /* get fd */
|
|
if (fd != -1)
|
|
ficlExecFD(pVM, fd);
|
|
return;
|
|
}
|
|
|
|
/* fwrite - write file contents
|
|
*
|
|
* fwrite ( fd buf nbytes -- nwritten )
|
|
*/
|
|
static void pfwrite(FICL_VM *pVM)
|
|
{
|
|
int fd, len;
|
|
char *buf;
|
|
|
|
#if FICL_ROBUST > 1
|
|
vmCheckStack(pVM, 3, 1);
|
|
#endif
|
|
len = stackPopINT(pVM->pStack); /* get number of bytes to read */
|
|
buf = stackPopPtr(pVM->pStack); /* get buffer */
|
|
fd = stackPopINT(pVM->pStack); /* get fd */
|
|
if (len > 0 && buf && fd != -1)
|
|
stackPushINT(pVM->pStack, write(fd, buf, len));
|
|
else
|
|
stackPushINT(pVM->pStack, -1);
|
|
return;
|
|
}
|
|
|
|
/* fseek - seek to a new position in a file
|
|
*
|
|
* fseek ( fd ofs whence -- pos )
|
|
*/
|
|
static void pfseek(FICL_VM *pVM)
|
|
{
|
|
int fd, pos, whence;
|
|
|
|
#if FICL_ROBUST > 1
|
|
vmCheckStack(pVM, 3, 1);
|
|
#endif
|
|
whence = stackPopINT(pVM->pStack);
|
|
pos = stackPopINT(pVM->pStack);
|
|
fd = stackPopINT(pVM->pStack);
|
|
stackPushINT(pVM->pStack, lseek(fd, pos, whence));
|
|
return;
|
|
}
|
|
|
|
/* key - get a character from stdin
|
|
*
|
|
* key ( -- char )
|
|
*/
|
|
static void key(FICL_VM *pVM)
|
|
{
|
|
#if FICL_ROBUST > 1
|
|
vmCheckStack(pVM, 0, 1);
|
|
#endif
|
|
stackPushINT(pVM->pStack, getchar());
|
|
return;
|
|
}
|
|
|
|
/* key? - check for a character from stdin (FACILITY)
|
|
*
|
|
* key? ( -- flag )
|
|
*/
|
|
static void keyQuestion(FICL_VM *pVM)
|
|
{
|
|
#if FICL_ROBUST > 1
|
|
vmCheckStack(pVM, 0, 1);
|
|
#endif
|
|
#ifdef TESTMAIN
|
|
/* XXX Since we don't fiddle with termios, let it always succeed... */
|
|
stackPushINT(pVM->pStack, FICL_TRUE);
|
|
#else
|
|
/* But here do the right thing. */
|
|
stackPushINT(pVM->pStack, ischar()? FICL_TRUE : FICL_FALSE);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
/* 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(FICL_VM *pVM)
|
|
{
|
|
#if FICL_ROBUST > 1
|
|
vmCheckStack(pVM,0,1);
|
|
#endif
|
|
stackPushUNS(pVM->pStack, (FICL_UNS) time(NULL));
|
|
return;
|
|
}
|
|
|
|
/* ms - wait at least that many milliseconds (FACILITY)
|
|
*
|
|
* ms ( u -- )
|
|
*
|
|
*/
|
|
static void ms(FICL_VM *pVM)
|
|
{
|
|
#if FICL_ROBUST > 1
|
|
vmCheckStack(pVM,1,0);
|
|
#endif
|
|
#ifdef TESTMAIN
|
|
usleep(stackPopUNS(pVM->pStack)*1000);
|
|
#else
|
|
delay(stackPopUNS(pVM->pStack)*1000);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
/* fkey - get a character from a file
|
|
*
|
|
* fkey ( file -- char )
|
|
*/
|
|
static void fkey(FICL_VM *pVM)
|
|
{
|
|
int i, fd;
|
|
char ch;
|
|
|
|
#if FICL_ROBUST > 1
|
|
vmCheckStack(pVM, 1, 1);
|
|
#endif
|
|
fd = stackPopINT(pVM->pStack);
|
|
i = read(fd, &ch, 1);
|
|
stackPushINT(pVM->pStack, i > 0 ? ch : -1);
|
|
return;
|
|
}
|
|
|
|
|
|
#ifdef __i386__
|
|
/*
|
|
* 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(FICL_VM *pVM)
|
|
{
|
|
uint32_t devid;
|
|
int i;
|
|
|
|
devid = stackPopINT(pVM->pStack);
|
|
|
|
i = biospci_count_device_type(devid);
|
|
|
|
stackPushINT(pVM->pStack, 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(FICL_VM *pVM)
|
|
{
|
|
uint32_t value, width, offset, locator;
|
|
|
|
value = stackPopINT(pVM->pStack);
|
|
width = stackPopINT(pVM->pStack);
|
|
offset = stackPopINT(pVM->pStack);
|
|
locator = stackPopINT(pVM->pStack);
|
|
|
|
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(FICL_VM *pVM)
|
|
{
|
|
uint32_t value, width, offset, locator;
|
|
|
|
width = stackPopINT(pVM->pStack);
|
|
offset = stackPopINT(pVM->pStack);
|
|
locator = stackPopINT(pVM->pStack);
|
|
|
|
biospci_read_config(locator, offset, width, &value);
|
|
|
|
stackPushINT(pVM->pStack, 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(FICL_VM *pVM)
|
|
{
|
|
uint32_t index, class, locator;
|
|
|
|
index = stackPopINT(pVM->pStack);
|
|
class = stackPopINT(pVM->pStack);
|
|
|
|
if (biospci_find_devclass(class, index, &locator))
|
|
locator = 0xffffffff;
|
|
|
|
stackPushINT(pVM->pStack, 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(FICL_VM *pVM)
|
|
{
|
|
uint32_t index, devid, locator;
|
|
|
|
index = stackPopINT(pVM->pStack);
|
|
devid = stackPopINT(pVM->pStack);
|
|
|
|
if (biospci_find_device(devid, index, &locator))
|
|
locator = 0xffffffff;
|
|
|
|
stackPushINT(pVM->pStack, locator);
|
|
}
|
|
|
|
/*
|
|
* pcibios-find-device(bus device function -- locator)
|
|
*
|
|
* converts bus, device, function to locator.
|
|
*
|
|
* Locator is bus << 8 | device << 3 | fuction
|
|
*/
|
|
static void
|
|
ficlPciBiosLocator(FICL_VM *pVM)
|
|
{
|
|
uint32_t bus, device, function, locator;
|
|
|
|
function = stackPopINT(pVM->pStack);
|
|
device = stackPopINT(pVM->pStack);
|
|
bus = stackPopINT(pVM->pStack);
|
|
|
|
locator = biospci_locator(bus, device, function);
|
|
|
|
stackPushINT(pVM->pStack, locator);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
** Retrieves free space remaining on the dictionary
|
|
*/
|
|
|
|
static void freeHeap(FICL_VM *pVM)
|
|
{
|
|
stackPushINT(pVM->pStack, dictCellsAvail(ficlGetDict(pVM->pSys)));
|
|
}
|
|
|
|
|
|
/******************* Increase dictionary size on-demand ******************/
|
|
|
|
static void ficlDictThreshold(FICL_VM *pVM)
|
|
{
|
|
stackPushPtr(pVM->pStack, &dictThreshold);
|
|
}
|
|
|
|
static void ficlDictIncrease(FICL_VM *pVM)
|
|
{
|
|
stackPushPtr(pVM->pStack, &dictIncrease);
|
|
}
|
|
|
|
/**************************************************************************
|
|
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 ficlCompilePlatform(FICL_SYSTEM *pSys)
|
|
{
|
|
FICL_DICT *dp = pSys->dp;
|
|
assert (dp);
|
|
|
|
dictAppendWord(dp, ".#", displayCellNoPad, FW_DEFAULT);
|
|
dictAppendWord(dp, "isdir?", isdirQuestion, FW_DEFAULT);
|
|
dictAppendWord(dp, "fopen", pfopen, FW_DEFAULT);
|
|
dictAppendWord(dp, "fclose", pfclose, FW_DEFAULT);
|
|
dictAppendWord(dp, "fread", pfread, FW_DEFAULT);
|
|
dictAppendWord(dp, "freaddir", pfreaddir, FW_DEFAULT);
|
|
dictAppendWord(dp, "fload", pfload, FW_DEFAULT);
|
|
dictAppendWord(dp, "fkey", fkey, FW_DEFAULT);
|
|
dictAppendWord(dp, "fseek", pfseek, FW_DEFAULT);
|
|
dictAppendWord(dp, "fwrite", pfwrite, FW_DEFAULT);
|
|
dictAppendWord(dp, "key", key, FW_DEFAULT);
|
|
dictAppendWord(dp, "key?", keyQuestion, FW_DEFAULT);
|
|
dictAppendWord(dp, "ms", ms, FW_DEFAULT);
|
|
dictAppendWord(dp, "seconds", pseconds, FW_DEFAULT);
|
|
dictAppendWord(dp, "heap?", freeHeap, FW_DEFAULT);
|
|
dictAppendWord(dp, "dictthreshold", ficlDictThreshold, FW_DEFAULT);
|
|
dictAppendWord(dp, "dictincrease", ficlDictIncrease, FW_DEFAULT);
|
|
|
|
dictAppendWord(dp, "setenv", ficlSetenv, FW_DEFAULT);
|
|
dictAppendWord(dp, "setenv?", ficlSetenvq, FW_DEFAULT);
|
|
dictAppendWord(dp, "getenv", ficlGetenv, FW_DEFAULT);
|
|
dictAppendWord(dp, "unsetenv", ficlUnsetenv, FW_DEFAULT);
|
|
dictAppendWord(dp, "copyin", ficlCopyin, FW_DEFAULT);
|
|
dictAppendWord(dp, "copyout", ficlCopyout, FW_DEFAULT);
|
|
dictAppendWord(dp, "findfile", ficlFindfile, FW_DEFAULT);
|
|
dictAppendWord(dp, "ccall", ficlCcall, FW_DEFAULT);
|
|
#ifndef TESTMAIN
|
|
#ifdef __i386__
|
|
dictAppendWord(dp, "outb", ficlOutb, FW_DEFAULT);
|
|
dictAppendWord(dp, "inb", ficlInb, FW_DEFAULT);
|
|
#endif
|
|
#ifdef HAVE_PNP
|
|
dictAppendWord(dp, "pnpdevices",ficlPnpdevices, FW_DEFAULT);
|
|
dictAppendWord(dp, "pnphandlers",ficlPnphandlers, FW_DEFAULT);
|
|
#endif
|
|
#endif
|
|
#ifdef __i386__
|
|
dictAppendWord(dp, "pcibios-device-count", ficlPciBiosCountDevices, FW_DEFAULT);
|
|
dictAppendWord(dp, "pcibios-read-config", ficlPciBiosReadConfig, FW_DEFAULT);
|
|
dictAppendWord(dp, "pcibios-write-config", ficlPciBiosWriteConfig, FW_DEFAULT);
|
|
dictAppendWord(dp, "pcibios-find-devclass", ficlPciBiosFindDevclass, FW_DEFAULT);
|
|
dictAppendWord(dp, "pcibios-find-device", ficlPciBiosFindDevice, FW_DEFAULT);
|
|
dictAppendWord(dp, "pcibios-locator", ficlPciBiosLocator, FW_DEFAULT);
|
|
#endif
|
|
|
|
#if defined(PC98)
|
|
ficlSetEnv(pSys, "arch-pc98", FICL_TRUE);
|
|
#elif defined(__i386__)
|
|
ficlSetEnv(pSys, "arch-i386", FICL_TRUE);
|
|
ficlSetEnv(pSys, "arch-powerpc", FICL_FALSE);
|
|
#elif defined(__powerpc__)
|
|
ficlSetEnv(pSys, "arch-i386", FICL_FALSE);
|
|
ficlSetEnv(pSys, "arch-powerpc", FICL_TRUE);
|
|
#endif
|
|
|
|
return;
|
|
}
|