|
|
1.1 root 1: /* tag: forth bootstrap environment
2: *
3: * Copyright (C) 2003-2006 Stefan Reinauer, Patrick Mauritz
4: *
5: * See the file "COPYING" for further information about
6: * the copyright and warranty status of this work.
7: */
8:
9: #include "sysinclude.h"
10: #include <stdio.h>
11: #include <stdlib.h>
12: #include <string.h>
13: #include <signal.h>
14: #include <fcntl.h>
15: #include <unistd.h>
16: #include <termios.h>
17: #include <sys/stat.h>
18:
19: #ifdef __GLIBC__
20: #define _GNU_SOURCE
21: #include <getopt.h>
22: #endif
23:
24: #include "config.h"
25: #include "kernel/stack.h"
26: #include "sysinclude.h"
27: #include "kernel/kernel.h"
28: #include "dict.h"
29: #include "cross.h"
30: #include "openbios-version.h"
31:
32: #define MAX_PATH_LEN 256
33:
34: #define MEMORY_SIZE (1024*1024) /* 1M ram for hosted system */
35: #define DICTIONARY_SIZE (256*1024) /* 256k for the dictionary */
36: #define TRAMPOLINE_SIZE (4*sizeof(cell)) /* 4 cells for the trampoline */
37:
38: /* state variables */
39: static ucell *latest, *state, *base;
40: static ucell *memory;
41: ucell *trampoline;
42:
43: /* local variables */
44: static int errors = 0;
45: static int segfault = 0;
46: static int verbose = 0;
47:
48: #define MAX_SRC_FILES 128
49:
50: static FILE *srcfiles[MAX_SRC_FILES];
51: static char *srcfilenames[MAX_SRC_FILES];
52: static int srclines[MAX_SRC_FILES];
53: static unsigned int cursrc = 0;
54:
55: static char *srcbasedict;
56:
57: /* console variables */
58: static FILE *console;
59:
60: #ifdef NATIVE_BITWIDTH_SMALLER_THAN_HOST_BITWIDTH
61: unsigned long base_address;
62: #endif
63:
64: /* include path handling */
65: typedef struct include_path include;
66: struct include_path {
67: const char *path;
68: include *next;
69: };
70:
71: static include includes = { ".", NULL };
72: static FILE *depfile;
73:
74: static ucell * relocation_address=NULL;
75: static int relocation_length=0;
76:
77: /* the word names are used to generate the prim words in the
78: * dictionary. This is done by the C written interpreter.
79: */
80: static const char *wordnames[] = {
81: "(semis)", "", "(lit)", "", "", "", "", "(do)", "(?do)", "(loop)",
82: "(+loop)", "", "", "", "dup", "2dup", "?dup", "over", "2over", "pick", "drop",
83: "2drop", "nip", "roll", "rot", "-rot", "swap", "2swap", ">r", "r>",
84: "r@", "depth", "depth!", "rdepth", "rdepth!", "+", "-", "*", "u*",
85: "mu/mod", "abs", "negate", "max", "min", "lshift", "rshift", ">>a",
86: "and", "or", "xor", "invert", "d+", "d-", "m*", "um*", "@", "c@",
87: "w@", "l@", "!", "+!", "c!", "w!", "l!", "=", ">", "<", "u>", "u<",
88: "sp@", "move", "fill", "(emit)", "(key?)", "(key)", "execute",
89: "here", "here!", "dobranch", "do?branch", "unaligned-w@",
90: "unaligned-w!", "unaligned-l@", "unaligned-l!", "ioc@", "iow@",
91: "iol@", "ioc!", "iow!", "iol!", "i", "j", "call", "sys-debug",
92: "$include", "$encode-file", "(debug", "(debug-off)"
93: };
94:
95: /*
96: * dictionary related functions.
97: */
98:
99: /*
100: * Compare two dictionaries constructed at different addresses. When
101: * the cells don't match, a need for relocation is detected and the
102: * corresponding bit in reloc_table bitmap is set.
103: */
104: static void relocation_table(unsigned char * dict_one, unsigned char *dict_two, int length)
105: {
106: ucell *d1=(ucell *)dict_one, *d2=(ucell *)dict_two;
107: ucell *reloc_table;
108: int pos, bit;
109: int l=(length+(sizeof(cell)-1))/sizeof(ucell), i;
110:
111: /* prepare relocation table */
112: relocation_length=(length+BITS-1)/BITS;
113: reloc_table = malloc(relocation_length*sizeof(cell));
114: memset(reloc_table,0,relocation_length*sizeof(cell));
115:
116: for (i=0; i<l; i++) {
117:
118: pos=i/BITS;
119: bit=i&~(-BITS);
120:
121: if(d1[i]==d2[i]) {
122: reloc_table[pos] &= target_ucell(~((ucell)1ULL << bit));
123:
124: // This check might bring false positives in data.
125: //if(d1[i] >= pointer2cell(dict_one) &&
126: // d1[i] <= pointer2cell(dict_one+length))
127: // printk("\nWARNING: inconsistent relocation (%x:%x)!\n", d1[i], d2[i]);
128: } else {
129: /* This is a pointer, it needs relocation, d2==dict */
130: reloc_table[pos] |= target_ucell((ucell)1ULL << bit);
131: d2[i] = target_ucell(target_ucell(d2[i]) - pointer2cell(d2));
132: }
133: }
134:
135: #ifdef CONFIG_DEBUG_DICTIONARY
136: printk("dict1 %lx dict2 %lx dict %lx\n",dict_one, dict_two, dict);
137: for (i=0; i< relocation_length ; i++)
138: printk("reloc %d %lx\n",i+1, reloc_table[i]);
139: #endif
140: relocation_address=reloc_table;
141: }
142:
143: static void write_dictionary(const char *filename)
144: {
145: FILE *f;
146: unsigned char *write_data, *walk_data;
147: int write_len;
148: dictionary_header_t *header;
149: u32 checksum=0;
150:
151: /*
152: * get memory for dictionary
153: */
154:
155: write_len = sizeof(dictionary_header_t)+dicthead+relocation_length*sizeof(cell);
156: write_data = malloc(write_len);
157: if(!write_data) {
158: printk("panic: can't allocate memory for output dictionary (%d"
159: " bytes\n", write_len);
160: exit(1);
161: }
162: memset(write_data, 0, write_len);
163:
164: /*
165: * prepare dictionary header
166: */
167:
168: header = (dictionary_header_t *)write_data;
169: *header = (dictionary_header_t){
170: .signature = DICTID,
171: .version = 2,
172: .cellsize = sizeof(ucell),
173: #ifdef CONFIG_BIG_ENDIAN
174: .endianess = -1,
175: #else
176: .endianess = 0,
177: #endif
178: .checksum = 0,
179: .compression = 0,
180: .relocation = -1,
181: .length = target_ulong((uint32_t)dicthead),
182: .last = target_ucell((ucell)((unsigned long)last
183: - (unsigned long)dict)),
184: };
185:
186: /*
187: * prepare dictionary data
188: */
189:
190: walk_data=write_data+sizeof(dictionary_header_t);
191: memcpy (walk_data, dict, dicthead);
192:
193: /*
194: * prepare relocation data.
195: * relocation_address is zero when writing a dictionary core.
196: */
197:
198: if (relocation_address) {
199: #ifdef CONFIG_DEBUG_DICTIONARY
200: printk("writing %d reloc cells \n",relocation_length);
201: #endif
202: walk_data += dicthead;
203: memcpy(walk_data, relocation_address,
204: relocation_length*sizeof(cell));
205: /* free relocation information */
206: free(relocation_address);
207: relocation_address=NULL;
208: } else {
209: header->relocation=0;
210: }
211:
212: /*
213: * Calculate Checksum
214: */
215:
216: walk_data=write_data;
217: while (walk_data<write_data+write_len) {
218: checksum+=read_long(walk_data);
219: walk_data+=sizeof(u32);
220: }
221: checksum=(u32)-checksum;
222:
223: header->checksum=target_long(checksum);
224:
225: if (verbose) {
226: dump_header(header);
227: }
228:
229: f = fopen(filename, "w");
230: if (!f) {
231: printk("panic: can't write to dictionary '%s'.\n", filename);
232: exit(1);
233: }
234:
235: fwrite(write_data, write_len, 1, f);
236:
237: free(write_data);
238: fclose(f);
239:
240: #ifdef CONFIG_DEBUG_DICTIONARY
241: printk("wrote dictionary to file %s.\n", filename);
242: #endif
243: }
244:
245: /*
246: * Write dictionary as a list of ucell hex values to filename. Array
247: * header and end lines are not generated.
248: *
249: * Cells with relocations are output using the expression
250: * DICTIONARY_BASE + value.
251: *
252: * Define some helpful constants.
253: */
254: static void write_dictionary_hex(const char *filename)
255: {
256: FILE *f;
257: ucell *walk;
258:
259: f = fopen(filename, "w");
260: if (!f) {
261: printk("panic: can't write to dictionary '%s'.\n", filename);
262: exit(1);
263: }
264:
265: for (walk = (ucell *)dict; walk < (ucell *)(dict + dicthead); walk++) {
266: int pos, bit, l;
267: ucell val;
268:
269: l = (walk - (ucell *)dict);
270: pos = l / BITS;
271: bit = l & ~(-BITS);
272:
273: val = read_ucell(walk);
274: if (relocation_address[pos] & target_ucell((ucell)1ULL << bit)) {
275: fprintf(f, "DICTIONARY_BASE + 0x%" FMT_CELL_x
276: ",\n", val);
277: } else {
278: fprintf(f, "0x%" FMT_CELL_x",\n", val);
279: }
280: }
281:
282: fprintf(f, "#define FORTH_DICTIONARY_LAST 0x%" FMT_CELL_x"\n",
283: (ucell)((unsigned long)last - (unsigned long)dict));
284: fprintf(f, "#define FORTH_DICTIONARY_END 0x%" FMT_CELL_x"\n",
285: (ucell)dicthead);
286: fclose(f);
287:
288: #ifdef CONFIG_DEBUG_DICTIONARY
289: printk("wrote dictionary to file %s.\n", filename);
290: #endif
291: }
292:
293: static ucell read_dictionary(char *fil)
294: {
295: int ilen;
296: ucell ret;
297: char *mem;
298: FILE *f;
299: struct stat finfo;
300:
301: if (stat(fil, &finfo))
302: return 0;
303:
304: ilen = finfo.st_size;
305:
306: if ((mem = malloc(ilen)) == NULL) {
307: printk("panic: not enough memory.\n");
308: exit(1);
309: }
310:
311: f = fopen(fil, "r");
312: if (!f) {
313: printk("panic: can't open dictionary.\n");
314: exit(1);
315: }
316:
317: if (fread(mem, ilen, 1, f) != 1) {
318: printk("panic: can't read dictionary.\n");
319: fclose(f);
320: exit(1);
321: }
322: fclose(f);
323:
324: ret = load_dictionary(mem, ilen);
325:
326: free(mem);
327: return ret;
328: }
329:
330:
331: /*
332: * C Parser related functions
333: */
334:
335: /*
336: * skipws skips all whitespaces (space, tab, newline) from the input file
337: */
338:
339: static void skipws(FILE * f)
340: {
341: int c;
342: while (!feof(f)) {
343: c = getc(f);
344:
345: if (c == ' ' || c == '\t')
346: continue;
347:
348: if (c == '\n') {
349: srclines[cursrc - 1]++;
350: continue;
351: }
352:
353: ungetc(c, f);
354: break;
355: }
356: }
357:
358: /*
359: * parse gets the next word from the input stream, delimited by
360: * delim. If delim is 0, any word delimiter will end the stream
361: * word delimiters are space, tab and newline. The resulting word
362: * will be put zero delimited to the char array line.
363: */
364:
365: static int parse(FILE * f, char *line, char delim)
366: {
367: int cnt = 0, c = 0;
368:
369: while (!feof(f)) {
370: c = getc(f);
371:
372: if (delim && c == delim)
373: break;
374:
375: if ((!delim) && (c == ' ' || c == '\t' || c == '\n'))
376: break;
377:
378: line[cnt++] = c;
379: }
380:
381: /* Update current line number */
382: if (c == '\n') {
383: srclines[cursrc - 1]++;
384: }
385:
386: line[cnt] = 0;
387:
388: return cnt;
389: }
390:
391: /*
392: * parse_word is a small helper that skips whitespaces before a word.
393: * it's behaviour is similar to the forth version parse-word.
394: */
395:
396: static void parse_word(FILE * f, char *line)
397: {
398: skipws(f);
399: parse(f, line, 0);
400: }
401:
402:
403: static void writestring(const char *str)
404: {
405: unsigned int i;
406: for (i = 0; i < strlen(str); i++) {
407: dict[dicthead + i] = str[i];
408: }
409: dicthead += i + 1;
410: dict[dicthead - 1] = (char) strlen(str) + 128;
411: }
412:
413: #define writebyte(value) {write_byte(dict+dicthead,value); dicthead++;}
414: #define writecell(value) {write_cell(dict+dicthead, value); dicthead+=sizeof(cell);}
415:
416: /*
417: * reveal a word, ie. make it visible.
418: */
419:
420: static void reveal(void)
421: {
422: *last = *latest;
423: }
424:
425: /*
426: * dictionary padding
427: */
428:
429: static void paddict(ucell align)
430: {
431: while (dicthead % align != 0)
432: writebyte(0);
433: }
434:
435: /*
436: * generic forth word creator function.
437: */
438:
439: static void fcreate(const char *word, ucell cfaval)
440: {
441: if (strlen(word) == 0) {
442: printk("WARNING: tried to create unnamed word.\n");
443: return;
444: }
445:
446: writestring(word);
447: /* get us at least 1 byte for flags */
448: writebyte(0);
449: paddict(sizeof(cell));
450: /* set flags high bit. */
451: dict[dicthead - 1] = 128;
452: /* lfa and cfa */
453: writecell(read_ucell(latest));
454: *latest = target_ucell(pointer2cell(dict) + dicthead - sizeof(cell));
455: writecell(cfaval);
456: }
457:
458:
459: static ucell *buildvariable(const char *name, cell defval)
460: {
461: fcreate(name, DOVAR); /* see dict.h for DOVAR and other CFA ids */
462: writecell(defval);
463: return (ucell *) (dict + dicthead - sizeof(cell));
464: }
465:
466: static void buildconstant(const char *name, cell defval)
467: {
468: fcreate(name, DOCON); /* see dict.h for DOCON and other CFA ids */
469: writecell(defval);
470: }
471:
472: static void builddefer(const char *name)
473: {
474: fcreate(name, DODFR); /* see dict.h for DODFR and other CFA ids */
475: writecell((ucell)0);
476: writecell((ucell)findword("(semis)"));
477: }
478:
479: /*
480: * Include file handling
481: */
482:
483: static void add_includepath(char *path)
484: {
485: include *incl = &includes;
486: include *newpath;
487:
488: while (incl->next)
489: incl = incl->next;
490:
491: newpath = malloc(sizeof(include));
492: if (!newpath) {
493: printk("panic: not enough memory for include path.\n");
494: exit(1);
495: }
496:
497: incl->next = newpath;
498: newpath->path = path;
499: newpath->next = NULL;
500: }
501:
502:
503: static FILE *fopen_include(const char *fil)
504: {
505: char fullpath[MAX_PATH_LEN];
506: FILE *ret;
507: include *incl = &includes;
508:
509: while (incl) {
510: snprintf(fullpath, sizeof(fullpath), "%s/%s", incl->path, fil);
511:
512: ret = fopen(fullpath, "r");
513: if (ret != NULL) {
514:
515: #ifdef CONFIG_DEBUG_INTERPRETER
516: printk("Including '%s'\n", name );
517: #endif
518: srcfilenames[cursrc] = strdup(fil);
519: srclines [ cursrc ] = 1;
520: srcfiles [ cursrc++ ] = ret;
521:
522: if (depfile) {
523: fprintf(depfile, " %s", fullpath);
524: }
525:
526: return ret;
527: }
528:
529: incl = incl->next;
530: }
531: return NULL;
532: }
533:
534:
535: /*
536: * Forth exception handler
537: */
538:
539: void exception(cell no)
540: {
541: printk("%s:%d: ", srcfilenames[cursrc - 1], srclines[cursrc - 1]);
542:
543: /* See also forth/bootstrap/interpreter.fs */
544: switch (no) {
545: case -1:
546: case -2:
547: printk("Aborted.\n");
548: break;
549: case -3:
550: printk("Stack Overflow.\n");
551: break;
552: case -4:
553: printk("Stack Underflow.\n");
554: break;
555: case -5:
556: printk("Return Stack Overflow.\n");
557: break;
558: case -6:
559: printk("Return Stack Underflow.\n");
560: break;
561: case -19:
562: printk("undefined word.\n");
563: break;
564: case -21:
565: printk("out of memory.\n");
566: break;
567: case -33:
568: printk("undefined method.\n");
569: break;
570: case -34:
571: printk("no such device.\n");
572: break;
573: default:
574: printk("error %" FMT_CELL_d " occured.\n", no);
575: }
576: exit(1);
577: }
578:
579:
580: /*
581: * This is the C version of the forth interpreter
582: */
583:
584: static int interpret_source(char *fil)
585: {
586: FILE *f;
587: char tib[160];
588: cell num;
589: char *test;
590:
591: const ucell SEMIS = (ucell)findword("(semis)");
592: const ucell LIT = (ucell)findword("(lit)");
593: const ucell DOBRANCH = (ucell)findword("dobranch");
594:
595: if ((f = fopen_include(fil)) == NULL) {
596: printk("error while loading source file '%s'\n", fil);
597: errors++;
598: exit(1);
599: }
600:
601: /* FIXME: We should read this file at
602: * once. No need to get it char by char
603: */
604:
605: while (!feof(f)) {
606: xt_t res;
607: parse_word(f, tib);
608:
609: /* if there is actually no word, we continue right away */
610: if (strlen(tib) == 0) {
611: continue;
612: }
613:
614: /* Checking for builtin words that are needed to
615: * bootstrap the forth base dictionary.
616: */
617:
618: if (!strcmp(tib, "(")) {
619: parse(f, tib, ')');
620: continue;
621: }
622:
623: if (!strcmp(tib, "\\")) {
624: parse(f, tib, '\n');
625: continue;
626: }
627:
628: if (!strcmp(tib, ":")) {
629: parse_word(f, tib);
630:
631: #ifdef CONFIG_DEBUG_INTERPRETER
632: printk("create colon word %s\n\n", tib);
633: #endif
634: fcreate(tib, DOCOL); /* see dict.h for DOCOL and other CFA ids */
635: *state = (ucell) (-1);
636: continue;
637: }
638:
639: if (!strcmp(tib, ";")) {
640: #ifdef CONFIG_DEBUG_INTERPRETER
641: printk("finish colon definition\n\n");
642: #endif
643: writecell((cell)SEMIS);
644: *state = (ucell) 0;
645: reveal();
646: continue;
647: }
648:
649: if (!strcasecmp(tib, "variable")) {
650: parse_word(f, tib);
651: #ifdef CONFIG_DEBUG_INTERPRETER
652: printk("defining variable %s\n\n", tib);
653: #endif
654: buildvariable(tib, 0);
655: reveal();
656: continue;
657: }
658:
659: if (!strcasecmp(tib, "constant")) {
660: parse_word(f, tib);
661: #ifdef CONFIG_DEBUG_INTERPRETER
662: printk("defining constant %s\n\n", tib);
663: #endif
664: buildconstant(tib, POP());
665: reveal();
666: continue;
667: }
668:
669: if (!strcasecmp(tib, "value")) {
670: parse_word(f, tib);
671: #ifdef CONFIG_DEBUG_INTERPRETER
672: printk("defining value %s\n\n", tib);
673: #endif
674: buildconstant(tib, POP());
675: reveal();
676: continue;
677: }
678:
679: if (!strcasecmp(tib, "defer")) {
680: parse_word(f, tib);
681: #ifdef CONFIG_DEBUG_INTERPRETER
682: printk("defining defer word %s\n\n", tib);
683: #endif
684: builddefer(tib);
685: reveal();
686: continue;
687: }
688:
689: if (!strcasecmp(tib, "include")) {
690: parse_word(f, tib);
691: #ifdef CONFIG_DEBUG_INTERPRETER
692: printk("including file %s\n\n", tib);
693: #endif
694: interpret_source(tib);
695: continue;
696: }
697:
698: if (!strcmp(tib, "[']")) {
699: xt_t xt;
700: parse_word(f, tib);
701: xt = findword(tib);
702: if (*state == 0) {
703: #ifdef CONFIG_DEBUG_INTERPRETER
704: printk
705: ("writing address of %s to stack\n\n",
706: tib);
707: #endif
708: PUSH_xt(xt);
709: } else {
710: #ifdef CONFIG_DEBUG_INTERPRETER
711: printk("writing lit, addr(%s) to dict\n\n",
712: tib);
713: #endif
714: writecell(LIT); /* lit */
715: writecell((cell)xt);
716: }
717: continue;
718: /* we have no error detection here */
719: }
720:
721: if (!strcasecmp(tib, "s\"")) {
722: int cnt;
723: cell loco;
724:
725: cnt = parse(f, tib, '"');
726: #ifdef CONFIG_DEBUG_INTERPRETER
727: printk("compiling string %s\n", tib);
728: #endif
729: loco = dicthead + (6 * sizeof(cell));
730: writecell(LIT);
731: writecell(pointer2cell(dict) + loco);
732: writecell(LIT);
733: writecell((ucell)cnt);
734: writecell(DOBRANCH);
735: loco = cnt + sizeof(cell) - 1;
736: loco &= ~(sizeof(cell) - 1);
737: writecell(loco);
738: memcpy(dict + dicthead, tib, cnt);
739: dicthead += cnt;
740: paddict(sizeof(cell));
741: continue;
742: }
743:
744: /* look if tib is in dictionary. */
745: /* should the dictionary be searched before the builtins ? */
746: res = findword(tib);
747: if (res) {
748: u8 flags = read_byte((u8*)cell2pointer(res) -
749: sizeof(cell) - 1);
750: #ifdef CONFIG_DEBUG_INTERPRETER
751: printk("%s is 0x%" FMT_CELL_x "\n", tib, (ucell) res);
752: #endif
753: if (!(*state) || (flags & 3)) {
754: #ifdef CONFIG_DEBUG_INTERPRETER
755: printk("executing %s, %" FMT_CELL_d
756: " (flags: %s %s)\n",
757: tib, res,
758: (flags & 1) ? "immediate" : "",
759: (flags & 2) ? "compile-only" : "");
760: #endif
761: PC = (ucell)res;
762: enterforth(res);
763: } else {
764: #ifdef CONFIG_DEBUG_INTERPRETER
765: printk("writing %s to dict\n\n", tib);
766: #endif
767: writecell((cell)res);
768: }
769: continue;
770: }
771:
772: /* if not look if it's a number */
773: if (tib[0] == '-')
774: num = strtoll(tib, &test, read_ucell(base));
775: else
776: num = strtoull(tib, &test, read_ucell(base));
777:
778:
779: if (*test != 0) {
780: /* what is it?? */
781: printk("%s:%d: %s is not defined.\n\n", srcfilenames[cursrc - 1], srclines[cursrc - 1], tib);
782: errors++;
783: #ifdef CONFIG_DEBUG_INTERPRETER
784: continue;
785: #else
786: return -1;
787: #endif
788: }
789:
790: if (*state == 0) {
791: #ifdef CONFIG_DEBUG_INTERPRETER
792: printk("pushed %" FMT_CELL_x " to stack\n\n", num);
793: #endif
794: PUSH(num);
795: } else {
796: #ifdef CONFIG_DEBUG_INTERPRETER
797: printk("writing lit, %" FMT_CELL_x " to dict\n\n", num);
798: #endif
799: writecell(LIT); /* lit */
800: writecell(num);
801: }
802: }
803:
804: fclose(f);
805: cursrc--;
806:
807: return 0;
808: }
809:
810: static int build_dictionary(void)
811: {
812: ucell lfa = 0;
813: unsigned int i;
814:
815: /* we need a temporary place for latest outside the dictionary */
816: latest = &lfa;
817:
818: /* starting a new dictionary: clear dicthead */
819: dicthead = 0;
820:
821: #ifdef CONFIG_DEBUG_DICTIONARY
822: printk("building dictionary, %d primitives.\nbuilt words:",
823: sizeof(wordnames) / sizeof(void *));
824: #endif
825:
826: for (i = 0; i < sizeof(wordnames) / sizeof(void *); i++) {
827: if (strlen(wordnames[i]) != 0) {
828: fcreate((char *) wordnames[i], i);
829: #ifdef CONFIG_DEBUG_DICTIONARY
830: printk(" %s", wordnames[i]);
831: #endif
832: }
833: }
834: #ifdef CONFIG_DEBUG_DICTIONARY
835: printk(".\n");
836: #endif
837:
838: /* get last/latest and state */
839: state = buildvariable("state", 0);
840: last = buildvariable("forth-last", 0);
841: latest = buildvariable("latest", 0);
842:
843: *latest = target_ucell(pointer2cell(latest)-2*sizeof(cell));
844:
845: base=buildvariable("base", 10);
846:
847: buildconstant("/c", sizeof(u8));
848: buildconstant("/w", sizeof(u16));
849: buildconstant("/l", sizeof(u32));
850: buildconstant("/n", sizeof(ucell));
851: buildconstant("/x", sizeof(u64));
852:
853: reveal();
854: if (verbose) {
855: printk("Dictionary initialization finished.\n");
856: }
857: return 0;
858: }
859:
860: /*
861: * functions used by primitives
862: */
863:
864: int availchar(void)
865: {
866: int tmp;
867: if( cursrc < 1 ) {
868: interruptforth |= FORTH_INTSTAT_STOP;
869: /* return -1 in order to exit the loop in key() */
870: return -1;
871: }
872:
873: tmp = getc( srcfiles[cursrc-1] );
874: if (tmp != EOF) {
875: ungetc(tmp, srcfiles[cursrc-1]);
876: return -1;
877: }
878:
879: fclose(srcfiles[--cursrc]);
880:
881: return availchar();
882: }
883:
884: int get_inputbyte( void )
885: {
886: int tmp;
887:
888: if( cursrc < 1 ) {
889: interruptforth |= FORTH_INTSTAT_STOP;
890: return 0;
891: }
892:
893: tmp = getc( srcfiles[cursrc-1] );
894:
895: /* Update current line number */
896: if (tmp == '\n') {
897: srclines[cursrc - 1]++;
898: }
899:
900: if (tmp != EOF) {
901: return tmp;
902: }
903:
904: fclose(srcfiles[--cursrc]);
905:
906: return get_inputbyte();
907: }
908:
909: void put_outputbyte( int c )
910: {
911: if (console)
912: fputc(c, console);
913: }
914:
915: /*
916: * segmentation fault handler. linux specific?
917: */
918:
919: static void
920: segv_handler(int signo __attribute__ ((unused)),
921: siginfo_t * si, void *context __attribute__ ((unused)))
922: {
923: static int count = 0;
924: ucell addr = 0xdeadbeef;
925:
926: if (count) {
927: printk("Died while dumping forth dictionary core.\n");
928: goto out;
929: }
930:
931: count++;
932:
933: if (PC >= pointer2cell(dict) && PC <= pointer2cell(dict) + dicthead)
934: addr = read_cell(cell2pointer(PC));
935:
936: printk("panic: segmentation violation at %p\n", (char *)si->si_addr);
937: printk("dict=%p here=%p(dict+0x%" FMT_CELL_x ") pc=0x%" FMT_CELL_x "(dict+0x%" FMT_CELL_x ")\n",
938: dict, dict + dicthead, dicthead, PC, PC - pointer2cell(dict));
939: printk("dstackcnt=%d rstackcnt=%d instruction=%" FMT_CELL_x "\n",
940: dstackcnt, rstackcnt, addr);
941:
942: printdstack();
943: printrstack();
944:
945: printk("Writing dictionary core file\n");
946: write_dictionary("forth.dict.core");
947:
948: out:
949: exit(1);
950: }
951:
952: /*
953: * allocate memory and prepare engine for memory management.
954: */
955:
956: static void init_memory(void)
957: {
958: memset(memory, 0, MEMORY_SIZE);
959:
960: /* we push start and end of memory to the stack
961: * so that it can be used by the forth word QUIT
962: * to initialize the memory allocator.
963: * Add a cell to the start address so we don't end
964: * up with a start address of zero during bootstrap
965: */
966:
967: PUSH(pointer2cell(memory)+sizeof(cell));
968: PUSH(pointer2cell(memory) + MEMORY_SIZE-1);
969: }
970:
971:
972: void
973: include_file( const char *name )
974: {
975: FILE *file;
976:
977: if( cursrc >= sizeof(srcfiles)/sizeof(srcfiles[0]) ) {
978: printk("\npanic: Maximum include depth reached!\n");
979: exit(1);
980: }
981:
982: file = fopen_include( name );
983: if( !file ) {
984: printk("\npanic: Failed opening file '%s'\n", name );
985: exit(1);
986: }
987: }
988:
989:
990: void
991: encode_file( const char *name )
992: {
993: FILE *file = fopen_include(name);
994: int size;
995:
996: if( !file ) {
997: printk("\npanic: Can't open '%s'\n", name );
998: exit(1);
999: }
1000: fseek( file, 0, SEEK_END );
1001: size = ftell( file );
1002: fseek( file, 0, SEEK_SET );
1003:
1004: if (verbose) {
1005: printk("\nEncoding %s [%d bytes]\n", name, size );
1006: }
1007: fread( dict + dicthead, size, 1, file );
1008: PUSH( pointer2cell(dict + dicthead) );
1009: PUSH( size );
1010: dicthead += size;
1011: }
1012:
1013:
1014: static void run_dictionary(char *basedict, char *confile)
1015: {
1016: if(!basedict)
1017: return;
1018:
1019: read_dictionary(basedict);
1020: PC = (ucell)findword("initialize");
1021:
1022: if (!PC) {
1023: if (verbose) {
1024: printk("Unable to find initialize word in dictionary %s; ignoring\n", basedict);
1025: }
1026: return;
1027: }
1028:
1029: if(!srcfiles[0]) {
1030: cursrc = 1;
1031: srcfiles[cursrc-1] = stdin;
1032: }
1033:
1034: dstackcnt=0;
1035: rstackcnt=0;
1036:
1037: init_memory();
1038: if (verbose)
1039: printk("Jumping to dictionary %s...\n", basedict);
1040:
1041: /* If a console file has been specified, open it */
1042: if (confile)
1043: console = fopen(confile, "w");
1044:
1045: srcbasedict = basedict;
1046:
1047: enterforth((xt_t)PC);
1048:
1049: /* Close the console file */
1050: if (console)
1051: fclose(console);
1052: }
1053:
1054: static void new_dictionary(const char *source)
1055: {
1056: build_dictionary();
1057:
1058: interpret_source((char *)source);
1059:
1060: if (verbose || errors > 0) {
1061: printk("interpretion finished. %d errors occured.\n",
1062: errors);
1063: }
1064: }
1065:
1066: /*
1067: * main loop
1068: */
1069:
1070: #define BANNER "OpenBIOS bootstrap kernel. (C) 2003-2006 Patrick Mauritz, Stefan Reinauer\n"\
1071: "This software comes with absolutely no warranty. "\
1072: "All rights reserved.\n\n"
1073:
1074: #ifdef __GLIBC__
1075: #define USAGE "Usage: %s [options] [dictionary file|source file]\n\n" \
1076: " -h|--help show this help\n" \
1077: " -V|--version print version and exit\n" \
1078: " -v|--verbose print debugging information\n" \
1079: " -I|--include dir add dir to include path\n" \
1080: " -d|--source-dictionary bootstrap.dict\n" \
1081: " use this dictionary as base\n" \
1082: " -D|--target-dictionary output.dict\n" \
1083: " write to output.dict\n" \
1084: " -c|--console output.log\n" \
1085: " write kernel console output to log file\n" \
1086: " -s|--segfault install segfault handler\n" \
1087: " -M|--dependency-dump file\n" \
1088: " dump dependencies in Makefile format\n\n" \
1089: " -x|--hexdump output format is C language hex dump\n"
1090: #else
1091: #define USAGE "Usage: %s [options] [dictionary file|source file]\n\n" \
1092: " -h show this help\n" \
1093: " -V print version and exit\n" \
1094: " -v print debugging information\n" \
1095: " -I add dir to include path\n" \
1096: " -d bootstrap.dict\n" \
1097: " use this dictionary as base\n" \
1098: " -D output.dict\n" \
1099: " write to output.dict\n" \
1100: " -c output.log\n" \
1101: " write kernel console output to log file\n" \
1102: " -s install segfault handler\n\n" \
1103: " -M file dump dependencies in Makefile format\n\n" \
1104: " -x output format is C language hex dump\n"
1105: #endif
1106:
1107: int main(int argc, char *argv[])
1108: {
1109: struct sigaction sa;
1110:
1111: unsigned char *ressources=NULL; /* All memory used by us */
1112: const char *dictname = NULL;
1113: char *basedict = NULL;
1114: char *consolefile = NULL;
1115: char *depfilename = NULL;
1116:
1117: unsigned char *bootstrapdict[2];
1118: int c, cnt, hexdump = 0;
1119:
1120: const char *optstring = "VvhsI:d:D:c:M:x?";
1121:
1122: while (1) {
1123: #ifdef __GLIBC__
1124: int option_index = 0;
1125: static struct option long_options[] = {
1126: {"version", 0, NULL, 'V'},
1127: {"verbose", 0, NULL, 'v'},
1128: {"help", 0, NULL, 'h'},
1129: {"segfault", 0, NULL, 's'},
1130: {"include", 1, NULL, 'I'},
1131: {"source-dictionary", 1, NULL, 'd'},
1132: {"target-dictionary", 1, NULL, 'D'},
1133: {"console", 1, NULL, 'c'},
1134: {"dependency-dump", 1, NULL, 'M'},
1135: {"hexdump", 0, NULL, 'x'},
1136: };
1137:
1138: /*
1139: * option handling
1140: */
1141:
1142: c = getopt_long(argc, argv, optstring, long_options,
1143: &option_index);
1144: #else
1145: c = getopt(argc, argv, optstring);
1146: #endif
1147: if (c == -1)
1148: break;
1149:
1150: switch (c) {
1151: case 'V':
1152: printk("Version " OPENBIOS_VERSION_STR "\n");
1153: return 0;
1154: case 'h':
1155: case '?':
1156: printk("Version " OPENBIOS_VERSION_STR "\n" USAGE,
1157: argv[0]);
1158: return 0;
1159: case 'v':
1160: verbose = 1;
1161: break;
1162: case 's':
1163: segfault = 1;
1164: break;
1165: case 'I':
1166: #ifdef CONFIG_DEBUG_INTERPRETER
1167: printk("adding '%s' to include path\n", optarg);
1168: #endif
1169: add_includepath(optarg);
1170: break;
1171: case 'd':
1172: if (!basedict) {
1173: basedict = optarg;
1174: }
1175: break;
1176: case 'D':
1177: if(!dictname) {
1178: dictname = optarg;
1179: }
1180: break;
1181: case 'c':
1182: if (!consolefile) {
1183: consolefile = optarg;
1184: }
1185: break;
1186: case 'M':
1187: if (!depfilename) {
1188: depfilename = optarg;
1189: }
1190: break;
1191: case 'x':
1192: hexdump = 1;
1193: break;
1194: default:
1195: return 1;
1196: }
1197: }
1198:
1199: if (!dictname) {
1200: dictname = "bootstrap.dict";
1201: }
1202: if (verbose) {
1203: printk(BANNER);
1204: printk("Using source dictionary '%s'\n", basedict);
1205: printk("Dumping final dictionary to '%s'\n", dictname);
1206: printk("Dumping dependencies to '%s'\n", depfilename);
1207: }
1208:
1209: if (argc < optind) {
1210: printk(USAGE, argv[0]);
1211: return 1;
1212: }
1213:
1214: if (depfilename) {
1215: depfile = fopen(depfilename, "w");
1216: if (!depfile) {
1217: printk("panic: can't write to dependency file '%s'.\n",
1218: depfilename);
1219: exit(1);
1220: }
1221: fprintf(depfile, "%s:", dictname);
1222: }
1223:
1224: /*
1225: * Get all required resources
1226: */
1227:
1228:
1229: ressources = malloc(MEMORY_SIZE + (2 * DICTIONARY_SIZE) + TRAMPOLINE_SIZE);
1230: if (!ressources) {
1231: printk("panic: not enough memory on host system.\n");
1232: return 1;
1233: }
1234:
1235: #ifdef NATIVE_BITWIDTH_SMALLER_THAN_HOST_BITWIDTH
1236: base_address=(unsigned long)ressources;
1237: #endif
1238:
1239: memory = (ucell *)ressources;
1240:
1241: bootstrapdict[0] = ressources + MEMORY_SIZE;
1242: bootstrapdict[1] = ressources + MEMORY_SIZE + DICTIONARY_SIZE;
1243: trampoline = (ucell *)(ressources + MEMORY_SIZE + DICTIONARY_SIZE + DICTIONARY_SIZE);
1244:
1245: #ifdef CONFIG_DEBUG_INTERPRETER
1246: printf("memory: %p\n",memory);
1247: printf("dict1: %p\n",bootstrapdict[0]);
1248: printf("dict2: %p\n",bootstrapdict[1]);
1249: printf("trampoline: %p\n",trampoline);
1250: printf("size=%d, trampoline_size=%d\n",MEMORY_SIZE + (2 *
1251: DICTIONARY_SIZE) + TRAMPOLINE_SIZE,
1252: TRAMPOLINE_SIZE);
1253: #endif
1254:
1255: if (trampoline == NULL) {
1256: /* We're using side effects which is to some extent nasty */
1257: printf("WARNING: no trampoline!\n");
1258: } else {
1259: init_trampoline(trampoline);
1260: }
1261:
1262: if (!segfault) {
1263: if (verbose)
1264: printk("Installing SIGSEGV handler...");
1265:
1266: sa.sa_sigaction = segv_handler;
1267: sigemptyset(&sa.sa_mask);
1268: sa.sa_flags = SA_SIGINFO | SA_NODEFER;
1269: sigaction(SIGSEGV, &sa, NULL);
1270:
1271: if (verbose)
1272: printk("done.\n");
1273: }
1274:
1275: /*
1276: * Now do the real work
1277: */
1278:
1279: for (cnt=0; cnt<2; cnt++) {
1280: if (verbose) {
1281: printk("Compiling dictionary %d/%d\n", cnt+1, 2);
1282: }
1283: dict=bootstrapdict[cnt];
1284: if(!basedict) {
1285: new_dictionary(argv[optind]);
1286: } else {
1287: for (c=argc-1; c>=optind; c--)
1288: include_file(argv[c]);
1289:
1290: run_dictionary(basedict, consolefile);
1291: }
1292: if (depfile) {
1293: fprintf(depfile, "\n");
1294: fclose(depfile);
1295: depfile = NULL;
1296: }
1297: if(errors)
1298: break;
1299: }
1300:
1301: #ifndef CONFIG_DEBUG_INTERPRETER
1302: if (errors)
1303: printk("dictionary not dumped to file.\n");
1304: else
1305: #endif
1306: {
1307: relocation_table( bootstrapdict[0], bootstrapdict[1], dicthead);
1308: if (hexdump) {
1309: write_dictionary_hex(dictname);
1310: } else {
1311: write_dictionary(dictname);
1312: }
1313: }
1314:
1315: free(ressources);
1316:
1317: if (errors)
1318: return 1;
1319: else
1320: return 0;
1321: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.