1 /* tag: hosted forth environment, executable code
2  *
3  * Copyright (C) 2003-2005 Patrick Mauritz, Stefan Reinauer
4  *
5  * See the file "COPYING" for further information about
6  * the copyright and warranty status of this work.
7  */
8 
9 #include <stdio.h>
10 #include <stdint.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <signal.h>
14 #define __USE_LARGEFILE64
15 #include <fcntl.h>
16 #include <unistd.h>
17 #include <termios.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <stdarg.h>
21 
22 #ifdef __GLIBC__
23 #define _GNU_SOURCE
24 #include <getopt.h>
25 #endif
26 
27 #include "sysinclude.h"
28 #include "mconfig.h"
29 #include "config.h"
30 #include "kernel/kernel.h"
31 #include "dict.h"
32 #include "kernel/stack.h"
33 #include "arch/unix/plugins.h"
34 #include "libopenbios/bindings.h"
35 #include "libopenbios/console.h"
36 #include "libopenbios/openbios.h"
37 #include "openbios-version.h"
38 
39 #include "blk.h"
40 #include "libopenbios/ofmem.h"
41 
42 #define MEMORY_SIZE	(4*1024*1024)	/* 4M ram for hosted system */
43 #define DICTIONARY_SIZE	(256*1024)	/* 256k for the dictionary   */
44 
45 #if defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS==64)
46 #define lseek lseek64
47 #define __LFS O_LARGEFILE
48 #else
49 #define __LFS 0
50 #endif
51 
52 /* prototypes */
53 static void exit_terminal(void);
54 void boot(void);
55 
56 unsigned long virt_offset = 0;
57 
58 /* local variables */
59 
60 static ucell *memory;
61 
62 static int diskemu;
63 
64 static int segfault = 0;
65 static int verbose = 0;
66 
67 #if defined(CONFIG_PPC) || defined(CONFIG_SPARC64)
68 unsigned long isa_io_base;
69 #endif
70 
71 int errno_int;	/* implement for fs drivers, needed to build on Mac OS X */
72 
ofmem_claim(ucell addr,ucell size,ucell align)73 ucell ofmem_claim(ucell addr, ucell size, ucell align)
74 {
75     return 0;
76 }
77 
78 #ifdef CONFIG_PPC
79 extern void flush_icache_range(char *start, char *stop);
80 
flush_icache_range(char * start,char * stop)81 void flush_icache_range(char *start, char *stop)
82 {
83 }
84 #endif
85 
86 #ifdef CONFIG_PPC
87 /* Expose system level is_machine helpers to make generic code easier */
88 
89 #include "drivers/drivers.h"
is_apple(void)90 int is_apple(void)
91 {
92     return 0;
93 }
94 
is_oldworld(void)95 int is_oldworld(void)
96 {
97     return 0;
98 }
99 
is_newworld(void)100 int is_newworld(void)
101 {
102     return 0;
103 }
104 #endif
105 
106 #if 0
107 static void write_dictionary(char *filename)
108 {
109 	FILE *f;
110 	xt_t initxt;
111 
112 	initxt = findword("initialize-of");
113 	if (!initxt)
114 		printk("warning: dictionary needs word called initialize-of\n");
115 
116 	f = fopen(filename, "w");
117 	if (!f) {
118 		printk("panic: can't open dictionary.\n");
119 		exit_terminal();
120 		exit(1);
121 	}
122 
123 	fwrite(DICTID, 16, 1, f);
124 	fwrite(dict, dicthead, 1, f);
125 
126 	/* Write start address and last to relocate on load */
127 	fwrite(&dict, sizeof(ucell), 1, f);
128 	fwrite(&last, sizeof(ucell), 1, f);
129 
130 	fclose(f);
131 
132 #ifdef CONFIG_DEBUG_DICTIONARY
133 	printk("wrote dictionary to file %s.\n", filename);
134 #endif
135 }
136 #endif
137 
read_dictionary(char * fil)138 static ucell read_dictionary(char *fil)
139 {
140 	int ilen;
141 	ucell ret;
142 	char *mem;
143 	FILE *f;
144 	struct stat finfo;
145 
146 	if (stat(fil, &finfo))
147 		return 0;
148 
149 	ilen = finfo.st_size;
150 
151 	if ((mem = malloc(ilen)) == NULL) {
152 		printk("panic: not enough memory.\n");
153 		exit_terminal();
154 		exit(1);
155 	}
156 
157 	f = fopen(fil, "r");
158 	if (!f) {
159 		printk("panic: can't open dictionary.\n");
160 		exit_terminal();
161 		exit(1);
162 	}
163 
164 	if (fread(mem, ilen, 1, f) != 1) {
165 		printk("panic: can't read dictionary.\n");
166 		fclose(f);
167 		exit_terminal();
168 		exit(1);
169 	}
170 	fclose(f);
171 
172 	ret = load_dictionary(mem, ilen);
173 
174 	free(mem);
175 	return ret;
176 }
177 
178 
179 /*
180  * functions used by primitives
181  */
182 
unix_availchar(void)183 static int unix_availchar(void)
184 {
185 	int tmp = getc(stdin);
186 	if (tmp != EOF) {
187 		ungetc(tmp, stdin);
188 		return -1;
189 	}
190 	return 0;
191 }
192 
unix_putchar(int c)193 static int unix_putchar(int c)
194 {
195 	putc(c, stdout);
196 	return c;
197 }
198 
unix_getchar(void)199 static int unix_getchar(void)
200 {
201 	return getc(stdin);
202 }
203 
204 static struct _console_ops unix_console_ops = {
205 	.putchar = unix_putchar,
206 	.availchar = unix_availchar,
207 	.getchar = unix_getchar
208 };
209 
inb(u32 reg)210 u8 inb(u32 reg)
211 {
212 #ifdef CONFIG_PLUGINS
213 	io_ops_t *ior = find_iorange(reg);
214 	if (ior)
215 		return ior->inb(reg);
216 #endif
217 
218 	printk("TRAP: io byte read @0x%x", reg);
219 	return 0xff;
220 }
221 
inw(u32 reg)222 u16 inw(u32 reg)
223 {
224 #ifdef CONFIG_PLUGINS
225 	io_ops_t *ior = find_iorange(reg);
226 	if (ior)
227 		return ior->inw(reg);
228 #endif
229 
230 	printk("TRAP: io word read @0x%x", reg);
231 	return 0xffff;
232 }
233 
inl(u32 reg)234 u32 inl(u32 reg)
235 {
236 #ifdef CONFIG_PLUGINS
237 	io_ops_t *ior = find_iorange(reg);
238 	if (ior)
239 		return ior->inl(reg);
240 #endif
241 
242 	printk("TRAP: io long read @0x%x", reg);
243 	return 0xffffffff;
244 }
245 
outb(u32 reg,u8 val)246 void outb(u32 reg, u8 val)
247 {
248 #ifdef CONFIG_PLUGINS
249 	io_ops_t *ior = find_iorange(reg);
250 	if (ior) {
251 		ior->outb(reg, val);
252 		return;
253 	}
254 #endif
255 
256 	printk("TRAP: io byte write 0x%x -> 0x%x", val, reg);
257 }
258 
outw(u32 reg,u16 val)259 void outw(u32 reg, u16 val)
260 {
261 #ifdef CONFIG_PLUGINS
262 	io_ops_t *ior = find_iorange(reg);
263 	if (ior) {
264 		ior->outw(reg, val);
265 		return;
266 	}
267 #endif
268 	printk("TRAP: io word write 0x%x -> 0x%x", val, reg);
269 }
270 
outl(u32 reg,u32 val)271 void outl(u32 reg, u32 val)
272 {
273 #ifdef CONFIG_PLUGINS
274 	io_ops_t *ior = find_iorange(reg);
275 	if (ior) {
276 		ior->outl(reg, val);
277 		return;
278 	}
279 #endif
280 	printk("TRAP: io long write 0x%x -> 0x%x", val, reg);
281 }
282 
283 /*
284  * terminal initialization and cleanup.
285  */
286 
287 static struct termios saved_termios;
288 
init_terminal(void)289 static void init_terminal(void)
290 {
291 	struct termios termios;
292 
293 	tcgetattr(0, &saved_termios);
294 	tcgetattr(0, &termios);
295 	termios.c_lflag &= ~(ICANON | ECHO);
296         termios.c_cc[VMIN] = 1;
297         termios.c_cc[VTIME] = 3; // 300 ms
298 	tcsetattr(0, 0, &termios);
299 }
300 
exit_terminal(void)301 static void exit_terminal(void)
302 {
303 	tcsetattr(0, 0, &saved_termios);
304 }
305 
306 /*
307  *  segmentation fault handler. linux specific?
308  */
309 
310 static void
segv_handler(int signo,siginfo_t * si,void * context)311 segv_handler(int signo __attribute__ ((unused)),
312 	     siginfo_t * si, void *context __attribute__ ((unused)))
313 {
314 	static int count = 0;
315 	ucell addr = 0xdeadbeef;
316 
317 	if (count) {
318 		printk("Died while dumping forth dictionary core.\n");
319 		goto out;
320 	}
321 
322 	count++;
323 
324 	if (PC >= (ucell) dict && PC <= (ucell) dict + dicthead)
325 		addr = *(ucell *) PC;
326 
327 	printk("panic: segmentation violation at %x\n", (ucell)si->si_addr);
328 	printk("dict=0x%x here=0x%x(dict+0x%x) pc=0x%x(dict+0x%x)\n",
329 	       (ucell)dict, (ucell)dict + dicthead, dicthead, PC, PC - (ucell) dict);
330 	printk("dstackcnt=%d rstackcnt=%d instruction=%x\n",
331 	       dstackcnt, rstackcnt, addr);
332 
333 #ifdef CONFIG_DEBUG_DSTACK
334 	printdstack();
335 #endif
336 #ifdef CONFIG_DEBUG_RSTACK
337 	printrstack();
338 #endif
339 #if 0
340 	printk("Writing dictionary core file\n");
341 	write_dictionary("forth.dict.core");
342 #endif
343 
344       out:
345 	exit_terminal();
346 	exit(1);
347 }
348 
349 /*
350  *  Interrupt handler. linux specific?
351  *  Restore terminal state on ctrl-C.
352  */
353 
354 static void
int_handler(int signo,siginfo_t * si,void * context)355 int_handler(int signo __attribute__ ((unused)),
356             siginfo_t * si __attribute__ ((unused)),
357             void *context __attribute__ ((unused)))
358 {
359     printk("\n");
360     exit_terminal();
361     exit(1);
362 }
363 
364 /*
365  * allocate memory and prepare engine for memory management.
366  */
367 
init_memory(void)368 static void init_memory(void)
369 {
370 	memory = malloc(MEMORY_SIZE);
371 	if (!memory) {
372 		printk("panic: not enough memory on host system.\n");
373 		exit_terminal();
374 		exit(1);
375 	}
376 
377 	memset (memory, 0, MEMORY_SIZE);
378 	/* we push start and end of memory to the stack
379 	 * so that it can be used by the forth word QUIT
380 	 * to initialize the memory allocator
381 	 */
382 
383 	PUSH((ucell) memory);
384 	PUSH((ucell) memory + MEMORY_SIZE);
385 }
386 
exception(cell no)387 void exception(__attribute__((unused)) cell no)
388 {
389 	/*
390 	 * this is a noop since the dictionary has to take care
391 	 * itself of errors it generates outside of the bootstrap
392 	 */
393 }
394 
395 static void
arch_init(void)396 arch_init( void )
397 {
398 	openbios_init();
399 	modules_init();
400 	if(diskemu!=-1)
401 		blk_init();
402 
403 	device_end();
404         bind_func("platform-boot", boot);
405 }
406 
407 int
read_from_disk(int channel,int unit,int blk,unsigned long mphys,int size)408 read_from_disk( int channel, int unit, int blk, unsigned long mphys, int size )
409 {
410 	// channels and units not supported yet.
411 	unsigned char *buf=(unsigned char *)mphys;
412 
413 	if(diskemu==-1)
414 		return -1;
415 
416 	//printk("read: ch=%d, unit=%d, blk=%ld, phys=%lx, size=%d\n",
417 	//		channel, unit, blk, mphys, size);
418 
419 	lseek(diskemu, (ducell)blk*512, SEEK_SET);
420 	read(diskemu, buf, size);
421 
422 	return 0;
423 }
424 
425 /*
426  * main loop
427  */
428 
429 #define BANNER	"OpenBIOS core. (C) 2003-2006 Patrick Mauritz, Stefan Reinauer\n"\
430 		"This software comes with absolutely no warranty. "\
431 		"All rights reserved.\n\n"
432 
433 
434 #define USAGE   "usage: %s [options] [dictionary file|source file]\n\n"
435 
main(int argc,char * argv[])436 int main(int argc, char *argv[])
437 {
438 	struct sigaction sa;
439 #if 0
440 	unsigned char *dictname = NULL;
441 #endif
442 	int c;
443 
444 	const char *optstring = "VvhsD:P:p:f:?";
445 
446 	while (1) {
447 #ifdef __GLIBC__
448 		int option_index = 0;
449 		static struct option long_options[] = {
450 			{"version", 0, NULL, 'V'},
451 			{"verbose", 0, NULL, 'v'},
452 			{"help", 0, NULL, 'h'},
453 //			{"dictionary", 1, NULL, 'D'},
454 			{"segfault", 0, NULL, 's'},
455 #ifdef CONFIG_PLUGINS
456 			{"plugin-path", 1, NULL, 'P'},
457 			{"plugin", 1, NULL, 'p'},
458 #endif
459 			{"file", 1, NULL, 'f'}
460 		};
461 
462 		c = getopt_long(argc, argv, optstring, long_options,
463 				&option_index);
464 #else
465 		c = getopt(argc, argv, optstring);
466 #endif
467 		if (c == -1)
468 			break;
469 
470 		switch (c) {
471 		case 'V':
472                         printk(BANNER "Version " OPENBIOS_VERSION_STR "\n");
473 			return 0;
474 		case 'h':
475 		case '?':
476                         printk(BANNER "Version " OPENBIOS_VERSION_STR "\n"
477                                USAGE, argv[0]);
478 			return 0;
479 		case 'v':
480 			verbose = 1;
481 			break;
482 		case 's':
483 			segfault = 1;
484 			break;
485 #if 0
486 		case 'D':
487 			printk("Dumping final dictionary to '%s'\n", optarg);
488 			dictname = optarg;
489 			break;
490 #endif
491 #ifdef CONFIG_PLUGINS
492 		case 'P':
493 			printk("Plugin search path is now '%s'\n", optarg);
494 			plugindir = optarg;
495 			break;
496 		case 'p':
497 			printk("Loading plugin %s\n", optarg);
498 			load_plugin(optarg);
499 			break;
500 #endif
501 		case 'f':
502 			diskemu=open(optarg, O_RDONLY|__LFS);
503 			if(diskemu!=-1)
504 				printk("Using %s as harddisk.\n", optarg);
505 			else
506 				printk("%s not found. no harddisk node.\n",
507 						optarg);
508 			break;
509 		default:
510 			return 1;
511 		}
512 	}
513 
514 	if (argc < optind + 1) {
515 		printk(USAGE, argv[0]);
516 		return 1;
517 	}
518 
519 	/* Initialise console */
520 	init_console(unix_console_ops);
521 
522 	if ((dict = (unsigned char *) malloc(DICTIONARY_SIZE)) == NULL) {
523 		printk("panic: not enough memory.\n");
524 		return 1;
525 	}
526 
527 	dictlimit = DICTIONARY_SIZE;
528 	memset(dict, 0, DICTIONARY_SIZE);
529 
530 	if (!segfault) {
531 		if (verbose)
532 			printk("Installing SIGSEGV handler...");
533 
534 		sa.sa_sigaction = segv_handler;
535 		sigemptyset(&sa.sa_mask);
536 		sa.sa_flags = SA_SIGINFO | SA_NODEFER;
537 		sigaction(SIGSEGV, &sa, NULL);
538 
539 		if (verbose)
540 			printk("done.\n");
541 	}
542 
543 	/* set terminal to do non blocking reads */
544 	init_terminal();
545 
546         if (verbose)
547             printk("Installing SIGINT handler...");
548 
549         sa.sa_sigaction = int_handler;
550         sigemptyset(&sa.sa_mask);
551         sa.sa_flags = SA_SIGINFO | SA_NODEFER;
552         sigaction(SIGINT, &sa, NULL);
553 
554         if (verbose)
555             printk("done.\n");
556 
557 	read_dictionary(argv[optind]);
558 	forth_init();
559 
560 	PUSH_xt( bind_noname_func(arch_init) );
561 	fword("PREPOST-initializer");
562 
563 	PC = (cell)findword("initialize-of");
564 	if (PC) {
565 		if (verbose) {
566 			if (optind + 1 != argc)
567 				printk("Warning: only first dictionary used.\n");
568 
569 			printk("dictionary loaded (%d bytes).\n", dicthead);
570 			printk("Initializing memory...");
571 		}
572 		init_memory();
573 
574 		if (verbose) {
575 			printk("done\n");
576 
577 			printk("Jumping to dictionary...");
578 		}
579 
580 		enterforth((xt_t)PC);
581 #if 0
582 		if (dictname != NULL)
583 			write_dictionary(dictname);
584 #endif
585 
586 		free(memory);
587 
588 	} else {		/* input file is not a dictionary */
589 		printk("not supported.\n");
590 	}
591 
592 	exit_terminal();
593 	if (diskemu!=-1)
594 		close(diskemu);
595 
596 	free(dict);
597 	return 0;
598 }
599 
600 #undef printk
601 int
printk(const char * fmt,...)602 printk( const char *fmt, ... )
603 {
604 	int i;
605 
606 	va_list args;
607 	va_start( args, fmt );
608 	i = vprintf(fmt, args );
609 	va_end( args );
610 	return i;
611 }
612