diff options
Diffstat (limited to 'qemu/roms/openbios/arch/unix/unix.c')
-rw-r--r-- | qemu/roms/openbios/arch/unix/unix.c | 611 |
1 files changed, 611 insertions, 0 deletions
diff --git a/qemu/roms/openbios/arch/unix/unix.c b/qemu/roms/openbios/arch/unix/unix.c new file mode 100644 index 000000000..1f628eb78 --- /dev/null +++ b/qemu/roms/openbios/arch/unix/unix.c @@ -0,0 +1,611 @@ +/* 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 <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#define __USE_LARGEFILE64 +#include <fcntl.h> +#include <unistd.h> +#include <termios.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <stdarg.h> + +#ifdef __GLIBC__ +#define _GNU_SOURCE +#include <getopt.h> +#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; +} |