/* tag: hosted forth environment, executable code * * Copyright (C) 2003-2005 Patrick Mauritz, Stefan Reinauer * * See the file "COPYING" for further information about * the copyright and warranty status of this work. */ #include #include #include #include #include #define __USE_LARGEFILE64 #include #include #include #include #include #include #ifdef __GLIBC__ #define _GNU_SOURCE #include #endif #include "sysinclude.h" #include "mconfig.h" #include "config.h" #include "kernel/kernel.h" #include "dict.h" #include "kernel/stack.h" #include "arch/unix/plugins.h" #include "libopenbios/bindings.h" #include "libopenbios/console.h" #include "libopenbios/openbios.h" #include "openbios-version.h" #include "blk.h" #include "libopenbios/ofmem.h" #define MEMORY_SIZE (4*1024*1024) /* 4M ram for hosted system */ #define DICTIONARY_SIZE (256*1024) /* 256k for the dictionary */ #if defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS==64) #define lseek lseek64 #define __LFS O_LARGEFILE #else #define __LFS 0 #endif /* prototypes */ static void exit_terminal(void); void boot(void); unsigned long virt_offset = 0; /* local variables */ static ucell *memory; static int diskemu; static int segfault = 0; static int verbose = 0; #if defined(CONFIG_PPC) || defined(CONFIG_SPARC64) unsigned long isa_io_base; #endif int errno_int; /* implement for fs drivers, needed to build on Mac OS X */ ucell ofmem_claim(ucell addr, ucell size, ucell align) { return 0; } #ifdef CONFIG_PPC extern void flush_icache_range(char *start, char *stop); void flush_icache_range(char *start, char *stop) { } #endif #ifdef CONFIG_PPC /* Expose system level is_machine helpers to make generic code easier */ #include "drivers/drivers.h" int is_apple(void) { return 0; } int is_oldworld(void) { return 0; } int is_newworld(void) { return 0; } #endif #if 0 static void write_dictionary(char *filename) { FILE *f; xt_t initxt; initxt = findword("initialize-of"); if (!initxt) printk("warning: dictionary needs word called initialize-of\n"); f = fopen(filename, "w"); if (!f) { printk("panic: can't open dictionary.\n"); exit_terminal(); exit(1); } fwrite(DICTID, 16, 1, f); fwrite(dict, dicthead, 1, f); /* Write start address and last to relocate on load */ fwrite(&dict, sizeof(ucell), 1, f); fwrite(&last, sizeof(ucell), 1, f); fclose(f); #ifdef CONFIG_DEBUG_DICTIONARY printk("wrote dictionary to file %s.\n", filename); #endif } #endif static ucell read_dictionary(char *fil) { int ilen; ucell ret; char *mem; FILE *f; struct stat finfo; if (stat(fil, &finfo)) return 0; ilen = finfo.st_size; if ((mem = malloc(ilen)) == NULL) { printk("panic: not enough memory.\n"); exit_terminal(); exit(1); } f = fopen(fil, "r"); if (!f) { printk("panic: can't open dictionary.\n"); exit_terminal(); exit(1); } if (fread(mem, ilen, 1, f) != 1) { printk("panic: can't read dictionary.\n"); fclose(f); exit_terminal(); exit(1); } fclose(f); ret = load_dictionary(mem, ilen); free(mem); return ret; } /* * functions used by primitives */ static int unix_availchar(void) { int tmp = getc(stdin); if (tmp != EOF) { ungetc(tmp, stdin); return -1; } return 0; } static int unix_putchar(int c) { putc(c, stdout); return c; } static int unix_getchar(void) { return getc(stdin); } static struct _console_ops unix_console_ops = { .putchar = unix_putchar, .availchar = unix_availchar, .getchar = unix_getchar }; u8 inb(u32 reg) { #ifdef CONFIG_PLUGINS io_ops_t *ior = find_iorange(reg); if (ior) return ior->inb(reg); #endif printk("TRAP: io byte read @0x%x", reg); return 0xff; } u16 inw(u32 reg) { #ifdef CONFIG_PLUGINS io_ops_t *ior = find_iorange(reg); if (ior) return ior->inw(reg); #endif printk("TRAP: io word read @0x%x", reg); return 0xffff; } u32 inl(u32 reg) { #ifdef CONFIG_PLUGINS io_ops_t *ior = find_iorange(reg); if (ior) return ior->inl(reg); #endif printk("TRAP: io long read @0x%x", reg); return 0xffffffff; } void outb(u32 reg, u8 val) { #ifdef CONFIG_PLUGINS io_ops_t *ior = find_iorange(reg); if (ior) { ior->outb(reg, val); return; } #endif printk("TRAP: io byte write 0x%x -> 0x%x", val, reg); } void outw(u32 reg, u16 val) { #ifdef CONFIG_PLUGINS io_ops_t *ior = find_iorange(reg); if (ior) { ior->outw(reg, val); return; } #endif printk("TRAP: io word write 0x%x -> 0x%x", val, reg); } void outl(u32 reg, u32 val) { #ifdef CONFIG_PLUGINS io_ops_t *ior = find_iorange(reg); if (ior) { ior->outl(reg, val); return; } #endif printk("TRAP: io long write 0x%x -> 0x%x", val, reg); } /* * terminal initialization and cleanup. */ static struct termios saved_termios; static void init_terminal(void) { struct termios termios; tcgetattr(0, &saved_termios); tcgetattr(0, &termios); termios.c_lflag &= ~(ICANON | ECHO); termios.c_cc[VMIN] = 1; termios.c_cc[VTIME] = 3; // 300 ms tcsetattr(0, 0, &termios); } static void exit_terminal(void) { tcsetattr(0, 0, &saved_termios); } /* * segmentation fault handler. linux specific? */ static void segv_handler(int signo __attribute__ ((unused)), siginfo_t * si, void *context __attribute__ ((unused))) { static int count = 0; ucell addr = 0xdeadbeef; if (count) { printk("Died while dumping forth dictionary core.\n"); goto out; } count++; if (PC >= (ucell) dict && PC <= (ucell) dict + dicthead) addr = *(ucell *) PC; printk("panic: segmentation violation at %x\n", (ucell)si->si_addr); printk("dict=0x%x here=0x%x(dict+0x%x) pc=0x%x(dict+0x%x)\n", (ucell)dict, (ucell)dict + dicthead, dicthead, PC, PC - (ucell) dict); printk("dstackcnt=%d rstackcnt=%d instruction=%x\n", dstackcnt, rstackcnt, addr); #ifdef CONFIG_DEBUG_DSTACK printdstack(); #endif #ifdef CONFIG_DEBUG_RSTACK printrstack(); #endif #if 0 printk("Writing dictionary core file\n"); write_dictionary("forth.dict.core"); #endif out: exit_terminal(); exit(1); } /* * Interrupt handler. linux specific? * Restore terminal state on ctrl-C. */ static void int_handler(int signo __attribute__ ((unused)), siginfo_t * si __attribute__ ((unused)), void *context __attribute__ ((unused))) { printk("\n"); exit_terminal(); exit(1); } /* * allocate memory and prepare engine for memory management. */ static void init_memory(void) { memory = malloc(MEMORY_SIZE); if (!memory) { printk("panic: not enough memory on host system.\n"); exit_terminal(); exit(1); } memset (memory, 0, MEMORY_SIZE); /* we push start and end of memory to the stack * so that it can be used by the forth word QUIT * to initialize the memory allocator */ PUSH((ucell) memory); PUSH((ucell) memory + MEMORY_SIZE); } void exception(__attribute__((unused)) cell no) { /* * this is a noop since the dictionary has to take care * itself of errors it generates outside of the bootstrap */ } static void arch_init( void ) { openbios_init(); modules_init(); if(diskemu!=-1) blk_init(); device_end(); bind_func("platform-boot", boot); } int read_from_disk( int channel, int unit, int blk, unsigned long mphys, int size ) { // channels and units not supported yet. unsigned char *buf=(unsigned char *)mphys; if(diskemu==-1) return -1; //printk("read: ch=%d, unit=%d, blk=%ld, phys=%lx, size=%d\n", // channel, unit, blk, mphys, size); lseek(diskemu, (ducell)blk*512, SEEK_SET); read(diskemu, buf, size); return 0; } /* * main loop */ #define BANNER "OpenBIOS core. (C) 2003-2006 Patrick Mauritz, Stefan Reinauer\n"\ "This software comes with absolutely no warranty. "\ "All rights reserved.\n\n" #define USAGE "usage: %s [options] [dictionary file|source file]\n\n" int main(int argc, char *argv[]) { struct sigaction sa; #if 0 unsigned char *dictname = NULL; #endif int c; const char *optstring = "VvhsD:P:p:f:?"; while (1) { #ifdef __GLIBC__ int option_index = 0; static struct option long_options[] = { {"version", 0, NULL, 'V'}, {"verbose", 0, NULL, 'v'}, {"help", 0, NULL, 'h'}, // {"dictionary", 1, NULL, 'D'}, {"segfault", 0, NULL, 's'}, #ifdef CONFIG_PLUGINS {"plugin-path", 1, NULL, 'P'}, {"plugin", 1, NULL, 'p'}, #endif {"file", 1, NULL, 'f'} }; c = getopt_long(argc, argv, optstring, long_options, &option_index); #else c = getopt(argc, argv, optstring); #endif if (c == -1) break; switch (c) { case 'V': printk(BANNER "Version " OPENBIOS_VERSION_STR "\n"); return 0; case 'h': case '?': printk(BANNER "Version " OPENBIOS_VERSION_STR "\n" USAGE, argv[0]); return 0; case 'v': verbose = 1; break; case 's': segfault = 1; break; #if 0 case 'D': printk("Dumping final dictionary to '%s'\n", optarg); dictname = optarg; break; #endif #ifdef CONFIG_PLUGINS case 'P': printk("Plugin search path is now '%s'\n", optarg); plugindir = optarg; break; case 'p': printk("Loading plugin %s\n", optarg); load_plugin(optarg); break; #endif case 'f': diskemu=open(optarg, O_RDONLY|__LFS); if(diskemu!=-1) printk("Using %s as harddisk.\n", optarg); else printk("%s not found. no harddisk node.\n", optarg); break; default: return 1; } } if (argc < optind + 1) { printk(USAGE, argv[0]); return 1; } /* Initialise console */ init_console(unix_console_ops); if ((dict = (unsigned char *) malloc(DICTIONARY_SIZE)) == NULL) { printk("panic: not enough memory.\n"); return 1; } dictlimit = DICTIONARY_SIZE; memset(dict, 0, DICTIONARY_SIZE); if (!segfault) { if (verbose) printk("Installing SIGSEGV handler..."); sa.sa_sigaction = segv_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_SIGINFO | SA_NODEFER; sigaction(SIGSEGV, &sa, NULL); if (verbose) printk("done.\n"); } /* set terminal to do non blocking reads */ init_terminal(); if (verbose) printk("Installing SIGINT handler..."); sa.sa_sigaction = int_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_SIGINFO | SA_NODEFER; sigaction(SIGINT, &sa, NULL); if (verbose) printk("done.\n"); read_dictionary(argv[optind]); forth_init(); PUSH_xt( bind_noname_func(arch_init) ); fword("PREPOST-initializer"); PC = (cell)findword("initialize-of"); if (PC) { if (verbose) { if (optind + 1 != argc) printk("Warning: only first dictionary used.\n"); printk("dictionary loaded (%d bytes).\n", dicthead); printk("Initializing memory..."); } init_memory(); if (verbose) { printk("done\n"); printk("Jumping to dictionary..."); } enterforth((xt_t)PC); #if 0 if (dictname != NULL) write_dictionary(dictname); #endif free(memory); } else { /* input file is not a dictionary */ printk("not supported.\n"); } exit_terminal(); if (diskemu!=-1) close(diskemu); free(dict); return 0; } #undef printk int printk( const char *fmt, ... ) { int i; va_list args; va_start( args, fmt ); i = vprintf(fmt, args ); va_end( args ); return i; }