loader.c revision 82941
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: head/sys/boot/ficl/loader.c 82941 2001-09-04 08:51:15Z dfr $
27 */
28
29/*******************************************************************
30** l o a d e r . c
31** Additional FICL words designed for FreeBSD's loader
32**
33*******************************************************************/
34
35#include <stand.h>
36#include "bootstrap.h"
37#include <string.h>
38#include "ficl.h"
39
40/*		FreeBSD's loader interaction words and extras
41 *
42 * 		setenv      ( value n name n' -- )
43 * 		setenv?     ( value n name n' flag -- )
44 * 		getenv      ( addr n -- addr' n' | -1 )
45 * 		unsetenv    ( addr n -- )
46 * 		copyin      ( addr addr' len -- )
47 * 		copyout     ( addr addr' len -- )
48 * 		findfile    ( name len type len' -- addr )
49 * 		pnpdevices  ( -- addr )
50 * 		pnphandlers ( -- addr )
51 * 		ccall       ( [[...[p10] p9] ... p1] n addr -- result )
52 * 		.#	    ( value -- )
53 */
54
55#ifndef TESTMAIN
56void
57ficlSetenv(FICL_VM *pVM)
58{
59	char	*namep, *valuep, *name, *value;
60	int	names, values;
61
62#if FICL_ROBUST > 1
63	vmCheckStack(pVM, 4, 0);
64#endif
65	names = stackPopINT(pVM->pStack);
66	namep = (char*) stackPopPtr(pVM->pStack);
67	values = stackPopINT(pVM->pStack);
68	valuep = (char*) stackPopPtr(pVM->pStack);
69
70	name = (char*) ficlMalloc(names+1);
71	if (!name)
72		vmThrowErr(pVM, "Error: out of memory");
73	strncpy(name, namep, names);
74	name[names] = '\0';
75	value = (char*) ficlMalloc(values+1);
76	if (!value)
77		vmThrowErr(pVM, "Error: out of memory");
78	strncpy(value, valuep, values);
79	value[values] = '\0';
80
81	setenv(name, value, 1);
82	ficlFree(name);
83	ficlFree(value);
84
85	return;
86}
87
88void
89ficlSetenvq(FICL_VM *pVM)
90{
91	char	*namep, *valuep, *name, *value;
92	int	names, values, overwrite;
93
94#if FICL_ROBUST > 1
95	vmCheckStack(pVM, 5, 0);
96#endif
97	overwrite = stackPopINT(pVM->pStack);
98	names = stackPopINT(pVM->pStack);
99	namep = (char*) stackPopPtr(pVM->pStack);
100	values = stackPopINT(pVM->pStack);
101	valuep = (char*) stackPopPtr(pVM->pStack);
102
103	name = (char*) ficlMalloc(names+1);
104	if (!name)
105		vmThrowErr(pVM, "Error: out of memory");
106	strncpy(name, namep, names);
107	name[names] = '\0';
108	value = (char*) ficlMalloc(values+1);
109	if (!value)
110		vmThrowErr(pVM, "Error: out of memory");
111	strncpy(value, valuep, values);
112	value[values] = '\0';
113
114	setenv(name, value, overwrite);
115	ficlFree(name);
116	ficlFree(value);
117
118	return;
119}
120
121void
122ficlGetenv(FICL_VM *pVM)
123{
124	char	*namep, *name, *value;
125	int	names;
126
127#if FICL_ROBUST > 1
128	vmCheckStack(pVM, 2, 2);
129#endif
130	names = stackPopINT(pVM->pStack);
131	namep = (char*) stackPopPtr(pVM->pStack);
132
133	name = (char*) ficlMalloc(names+1);
134	if (!name)
135		vmThrowErr(pVM, "Error: out of memory");
136	strncpy(name, namep, names);
137	name[names] = '\0';
138
139	value = getenv(name);
140	ficlFree(name);
141
142	if(value != NULL) {
143		stackPushPtr(pVM->pStack, value);
144		stackPushINT(pVM->pStack, strlen(value));
145	} else
146		stackPushINT(pVM->pStack, -1);
147
148	return;
149}
150
151void
152ficlUnsetenv(FICL_VM *pVM)
153{
154	char	*namep, *name;
155	int	names;
156
157#if FICL_ROBUST > 1
158	vmCheckStack(pVM, 2, 0);
159#endif
160	names = stackPopINT(pVM->pStack);
161	namep = (char*) stackPopPtr(pVM->pStack);
162
163	name = (char*) ficlMalloc(names+1);
164	if (!name)
165		vmThrowErr(pVM, "Error: out of memory");
166	strncpy(name, namep, names);
167	name[names] = '\0';
168
169	unsetenv(name);
170	ficlFree(name);
171
172	return;
173}
174
175void
176ficlCopyin(FICL_VM *pVM)
177{
178	void*		src;
179	vm_offset_t	dest;
180	size_t		len;
181
182#if FICL_ROBUST > 1
183	vmCheckStack(pVM, 3, 0);
184#endif
185
186	len = stackPopINT(pVM->pStack);
187	dest = stackPopINT(pVM->pStack);
188	src = stackPopPtr(pVM->pStack);
189
190	archsw.arch_copyin(src, dest, len);
191
192	return;
193}
194
195void
196ficlCopyout(FICL_VM *pVM)
197{
198	void*		dest;
199	vm_offset_t	src;
200	size_t		len;
201
202#if FICL_ROBUST > 1
203	vmCheckStack(pVM, 3, 0);
204#endif
205
206	len = stackPopINT(pVM->pStack);
207	dest = stackPopPtr(pVM->pStack);
208	src = stackPopINT(pVM->pStack);
209
210	archsw.arch_copyout(src, dest, len);
211
212	return;
213}
214
215void
216ficlFindfile(FICL_VM *pVM)
217{
218	char	*name, *type, *namep, *typep;
219	struct	preloaded_file* fp;
220	int	names, types;
221
222#if FICL_ROBUST > 1
223	vmCheckStack(pVM, 4, 1);
224#endif
225
226	types = stackPopINT(pVM->pStack);
227	typep = (char*) stackPopPtr(pVM->pStack);
228	names = stackPopINT(pVM->pStack);
229	namep = (char*) stackPopPtr(pVM->pStack);
230	name = (char*) ficlMalloc(names+1);
231	if (!name)
232		vmThrowErr(pVM, "Error: out of memory");
233	strncpy(name, namep, names);
234	name[names] = '\0';
235	type = (char*) ficlMalloc(types+1);
236	if (!type)
237		vmThrowErr(pVM, "Error: out of memory");
238	strncpy(type, typep, types);
239	type[types] = '\0';
240
241	fp = file_findfile(name, type);
242	stackPushPtr(pVM->pStack, fp);
243
244	return;
245}
246
247#ifdef HAVE_PNP
248
249void
250ficlPnpdevices(FICL_VM *pVM)
251{
252	static int pnp_devices_initted = 0;
253#if FICL_ROBUST > 1
254	vmCheckStack(pVM, 0, 1);
255#endif
256
257	if(!pnp_devices_initted) {
258		STAILQ_INIT(&pnp_devices);
259		pnp_devices_initted = 1;
260	}
261
262	stackPushPtr(pVM->pStack, &pnp_devices);
263
264	return;
265}
266
267void
268ficlPnphandlers(FICL_VM *pVM)
269{
270#if FICL_ROBUST > 1
271	vmCheckStack(pVM, 0, 1);
272#endif
273
274	stackPushPtr(pVM->pStack, pnphandlers);
275
276	return;
277}
278
279#endif
280
281#endif /* ndef TESTMAIN */
282
283void
284ficlCcall(FICL_VM *pVM)
285{
286	int (*func)(int, ...);
287	int result, p[10];
288	int nparam, i;
289
290#if FICL_ROBUST > 1
291	vmCheckStack(pVM, 2, 0);
292#endif
293
294	func = stackPopPtr(pVM->pStack);
295	nparam = stackPopINT(pVM->pStack);
296
297#if FICL_ROBUST > 1
298	vmCheckStack(pVM, nparam, 1);
299#endif
300
301	for (i = 0; i < nparam; i++)
302		p[i] = stackPopINT(pVM->pStack);
303
304	result = func(p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8],
305	    p[9]);
306
307	stackPushINT(pVM->pStack, result);
308
309	return;
310}
311
312/**************************************************************************
313                        f i c l E x e c F D
314** reads in text from file fd and passes it to ficlExec()
315 * returns VM_OUTOFTEXT on success or the ficlExec() error code on
316 * failure.
317 */
318#define nLINEBUF 256
319int ficlExecFD(FICL_VM *pVM, int fd)
320{
321    char    cp[nLINEBUF];
322    int     nLine = 0, rval = VM_OUTOFTEXT;
323    char    ch;
324    CELL    id;
325
326    id = pVM->sourceID;
327    pVM->sourceID.i = fd;
328
329    /* feed each line to ficlExec */
330    while (1) {
331	int status, i;
332
333	i = 0;
334	while ((status = read(fd, &ch, 1)) > 0 && ch != '\n')
335	    cp[i++] = ch;
336        nLine++;
337	if (!i) {
338	    if (status < 1)
339		break;
340	    continue;
341	}
342        rval = ficlExecC(pVM, cp, i);
343	if(rval != VM_QUIT && rval != VM_USEREXIT && rval != VM_OUTOFTEXT)
344        {
345            pVM->sourceID = id;
346            return rval;
347        }
348    }
349    /*
350    ** Pass an empty line with SOURCE-ID == -1 to flush
351    ** any pending REFILLs (as required by FILE wordset)
352    */
353    pVM->sourceID.i = -1;
354    ficlExec(pVM, "");
355
356    pVM->sourceID = id;
357    return rval;
358}
359
360static void displayCellNoPad(FICL_VM *pVM)
361{
362    CELL c;
363#if FICL_ROBUST > 1
364    vmCheckStack(pVM, 1, 0);
365#endif
366    c = stackPop(pVM->pStack);
367    ltoa((c).i, pVM->pad, pVM->base);
368    vmTextOut(pVM, pVM->pad, 0);
369    return;
370}
371
372/*          fopen - open a file and return new fd on stack.
373 *
374 * fopen ( count ptr  -- fd )
375 */
376static void pfopen(FICL_VM *pVM)
377{
378    int     fd;
379    char    *p;
380
381#if FICL_ROBUST > 1
382    vmCheckStack(pVM, 2, 1);
383#endif
384    (void)stackPopINT(pVM->pStack); /* don't need count value */
385    p = stackPopPtr(pVM->pStack);
386    fd = open(p, O_RDONLY);
387    stackPushINT(pVM->pStack, fd);
388    return;
389 }
390
391/*          fclose - close a file who's fd is on stack.
392 *
393 * fclose ( fd -- )
394 */
395static void pfclose(FICL_VM *pVM)
396{
397    int fd;
398
399#if FICL_ROBUST > 1
400    vmCheckStack(pVM, 1, 0);
401#endif
402    fd = stackPopINT(pVM->pStack); /* get fd */
403    if (fd != -1)
404	close(fd);
405    return;
406}
407
408/*          fread - read file contents
409 *
410 * fread  ( fd buf nbytes  -- nread )
411 */
412static void pfread(FICL_VM *pVM)
413{
414    int     fd, len;
415    char *buf;
416
417#if FICL_ROBUST > 1
418    vmCheckStack(pVM, 3, 1);
419#endif
420    len = stackPopINT(pVM->pStack); /* get number of bytes to read */
421    buf = stackPopPtr(pVM->pStack); /* get buffer */
422    fd = stackPopINT(pVM->pStack); /* get fd */
423    if (len > 0 && buf && fd != -1)
424	stackPushINT(pVM->pStack, read(fd, buf, len));
425    else
426	stackPushINT(pVM->pStack, -1);
427    return;
428}
429
430/*          fload - interpret file contents
431 *
432 * fload  ( fd -- )
433 */
434static void pfload(FICL_VM *pVM)
435{
436    int     fd;
437
438#if FICL_ROBUST > 1
439    vmCheckStack(pVM, 1, 0);
440#endif
441    fd = stackPopINT(pVM->pStack); /* get fd */
442    if (fd != -1)
443	ficlExecFD(pVM, fd);
444    return;
445}
446
447/*           key - get a character from stdin
448 *
449 * key ( -- char )
450 */
451static void key(FICL_VM *pVM)
452{
453#if FICL_ROBUST > 1
454    vmCheckStack(pVM, 0, 1);
455#endif
456    stackPushINT(pVM->pStack, getchar());
457    return;
458}
459
460/*           key? - check for a character from stdin (FACILITY)
461 *
462 * key? ( -- flag )
463 */
464static void keyQuestion(FICL_VM *pVM)
465{
466#if FICL_ROBUST > 1
467    vmCheckStack(pVM, 0, 1);
468#endif
469#ifdef TESTMAIN
470    /* XXX Since we don't fiddle with termios, let it always succeed... */
471    stackPushINT(pVM->pStack, FICL_TRUE);
472#else
473    /* But here do the right thing. */
474    stackPushINT(pVM->pStack, ischar()? FICL_TRUE : FICL_FALSE);
475#endif
476    return;
477}
478
479/* seconds - gives number of seconds since beginning of time
480 *
481 * beginning of time is defined as:
482 *
483 *	BTX	- number of seconds since midnight
484 *	FreeBSD	- number of seconds since Jan 1 1970
485 *
486 * seconds ( -- u )
487 */
488static void pseconds(FICL_VM *pVM)
489{
490#if FICL_ROBUST > 1
491    vmCheckStack(pVM,0,1);
492#endif
493    stackPushUNS(pVM->pStack, (FICL_UNS) time(NULL));
494    return;
495}
496
497/* ms - wait at least that many milliseconds (FACILITY)
498 *
499 * ms ( u -- )
500 *
501 */
502static void ms(FICL_VM *pVM)
503{
504#if FICL_ROBUST > 1
505    vmCheckStack(pVM,1,0);
506#endif
507#ifdef TESTMAIN
508    usleep(stackPopUNS(pVM->pStack)*1000);
509#else
510    delay(stackPopUNS(pVM->pStack)*1000);
511#endif
512    return;
513}
514
515/*           fkey - get a character from a file
516 *
517 * fkey ( file -- char )
518 */
519static void fkey(FICL_VM *pVM)
520{
521    int i, fd;
522    char ch;
523
524#if FICL_ROBUST > 1
525    vmCheckStack(pVM, 1, 1);
526#endif
527    fd = stackPopINT(pVM->pStack);
528    i = read(fd, &ch, 1);
529    stackPushINT(pVM->pStack, i > 0 ? ch : -1);
530    return;
531}
532
533/*
534** Retrieves free space remaining on the dictionary
535*/
536
537static void freeHeap(FICL_VM *pVM)
538{
539    stackPushINT(pVM->pStack, dictCellsAvail(ficlGetDict()));
540}
541
542
543/******************* Increase dictionary size on-demand ******************/
544
545static void ficlDictThreshold(FICL_VM *pVM)
546{
547    stackPushPtr(pVM->pStack, &dictThreshold);
548}
549
550static void ficlDictIncrease(FICL_VM *pVM)
551{
552    stackPushPtr(pVM->pStack, &dictIncrease);
553}
554
555
556/**************************************************************************
557                        f i c l C o m p i l e P l a t f o r m
558** Build FreeBSD platform extensions into the system dictionary
559**************************************************************************/
560void ficlCompilePlatform(FICL_SYSTEM *pSys)
561{
562    FICL_DICT *dp = pSys->dp;
563    assert (dp);
564
565    dictAppendWord(dp, ".#",        displayCellNoPad,    FW_DEFAULT);
566    dictAppendWord(dp, "fopen",	    pfopen,	    FW_DEFAULT);
567    dictAppendWord(dp, "fclose",    pfclose,	    FW_DEFAULT);
568    dictAppendWord(dp, "fread",	    pfread,	    FW_DEFAULT);
569    dictAppendWord(dp, "fload",	    pfload,	    FW_DEFAULT);
570    dictAppendWord(dp, "fkey",	    fkey,	    FW_DEFAULT);
571    dictAppendWord(dp, "key",	    key,	    FW_DEFAULT);
572    dictAppendWord(dp, "key?",	    keyQuestion,    FW_DEFAULT);
573    dictAppendWord(dp, "ms",        ms,             FW_DEFAULT);
574    dictAppendWord(dp, "seconds",   pseconds,       FW_DEFAULT);
575    dictAppendWord(dp, "heap?",     freeHeap,       FW_DEFAULT);
576    dictAppendWord(dp, "dictthreshold", ficlDictThreshold, FW_DEFAULT);
577    dictAppendWord(dp, "dictincrease", ficlDictIncrease, FW_DEFAULT);
578
579#ifndef TESTMAIN
580#ifdef __i386__
581    dictAppendWord(dp, "outb",      ficlOutb,       FW_DEFAULT);
582    dictAppendWord(dp, "inb",       ficlInb,        FW_DEFAULT);
583#endif
584    dictAppendWord(dp, "setenv",    ficlSetenv,	    FW_DEFAULT);
585    dictAppendWord(dp, "setenv?",   ficlSetenvq,    FW_DEFAULT);
586    dictAppendWord(dp, "getenv",    ficlGetenv,	    FW_DEFAULT);
587    dictAppendWord(dp, "unsetenv",  ficlUnsetenv,   FW_DEFAULT);
588    dictAppendWord(dp, "copyin",    ficlCopyin,	    FW_DEFAULT);
589    dictAppendWord(dp, "copyout",   ficlCopyout,    FW_DEFAULT);
590    dictAppendWord(dp, "findfile",  ficlFindfile,   FW_DEFAULT);
591#ifdef HAVE_PNP
592    dictAppendWord(dp, "pnpdevices",ficlPnpdevices, FW_DEFAULT);
593    dictAppendWord(dp, "pnphandlers",ficlPnphandlers, FW_DEFAULT);
594#endif
595    dictAppendWord(dp, "ccall",	    ficlCcall,	    FW_DEFAULT);
596#endif
597
598#if defined(__i386__)
599    ficlSetEnv("arch-i386",         FICL_TRUE);
600    ficlSetEnv("arch-alpha",        FICL_FALSE);
601    ficlSetEnv("arch-ia64",         FICL_FALSE);
602#elif defined(__alpha__)
603    ficlSetEnv("arch-i386",         FICL_FALSE);
604    ficlSetEnv("arch-alpha",        FICL_TRUE);
605    ficlSetEnv("arch-ia64",         FICL_FALSE);
606#elif defined(__ia64__)
607    ficlSetEnv("arch-i386",         FICL_FALSE);
608    ficlSetEnv("arch-alpha",        FICL_FALSE);
609    ficlSetEnv("arch-ia64",         FICL_TRUE);
610#endif
611
612    return;
613}
614
615