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