mirror of
https://gitlab.com/qemu-project/openbios.git
synced 2024-02-13 08:34:06 +08:00
initial import of openbios--main--1.0--patch-26
git-svn-id: svn://coreboot.org/openbios/openbios-devel@1 f158a5a8-5612-0410-a976-696ce0be7e32
This commit is contained in:
517
arch/unix/unix.c
Normal file
517
arch/unix/unix.c
Normal file
@@ -0,0 +1,517 @@
|
||||
/* 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 "openbios/sysinclude.h"
|
||||
#include "mconfig.h"
|
||||
#include "openbios/config.h"
|
||||
#include "openbios/kernel.h"
|
||||
#include "dict.h"
|
||||
#include "openbios/stack.h"
|
||||
#include "unix/plugins.h"
|
||||
#include "openbios/bindings.h"
|
||||
|
||||
#include "blk.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);
|
||||
|
||||
/* local variables */
|
||||
|
||||
ucell *latest, *state;
|
||||
ucell *memory;
|
||||
|
||||
int diskemu;
|
||||
|
||||
static int segfault = 0;
|
||||
int verbose = 0;
|
||||
|
||||
int errno_int; /* implement for fs drivers, needed to build on Mac OS X */
|
||||
|
||||
#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
|
||||
*/
|
||||
|
||||
int availchar(void)
|
||||
{
|
||||
int tmp = getc(stdin);
|
||||
if (tmp != EOF) {
|
||||
ungetc(tmp, stdin);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 void init_terminal(void)
|
||||
{
|
||||
struct termios termios;
|
||||
|
||||
tcgetattr(0, &termios);
|
||||
termios.c_lflag &= ~(ICANON | ECHO);
|
||||
tcsetattr(0, 0, &termios);
|
||||
}
|
||||
|
||||
static void exit_terminal(void)
|
||||
{
|
||||
struct termios termios;
|
||||
|
||||
tcgetattr(0, &termios);
|
||||
termios.c_lflag |= (ICANON | ECHO);
|
||||
tcsetattr(0, 0, &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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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(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 )
|
||||
{
|
||||
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-2005 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 " VERSION "\n");
|
||||
return 0;
|
||||
case 'h':
|
||||
case '?':
|
||||
printk(BANNER "Version " VERSION "\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;
|
||||
}
|
||||
|
||||
if ((dict = (unsigned char *) malloc(DICTIONARY_SIZE)) == NULL) {
|
||||
printk("panic: not enough memory.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
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, 0);
|
||||
|
||||
if (verbose)
|
||||
printk("done.\n");
|
||||
}
|
||||
|
||||
/* set terminal to do non blocking reads */
|
||||
init_terminal();
|
||||
read_dictionary(argv[optind]);
|
||||
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user