// Copyright (C) 2001 MandrakeSoft S.A. // // MandrakeSoft S.A. // 43, rue d'Aboukir // 75002 Paris - France // http://www.linux-mandrake.com/ // http://www.mandrakesoft.com/ // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "bochs.h" #include #include "state_file.h" extern "C" { #include } #ifdef __MINGW32__ void alarm(int); #endif #if BX_PROVIDE_DEVICE_MODELS==1 // some prototypes from iodev/ // I want to stay away from including iodev/iodev.h here Bit32u bx_unmapped_io_read_handler(Bit32u address, unsigned io_len); void bx_unmapped_io_write_handler(Bit32u address, Bit32u value, unsigned io_len); void bx_close_harddrive(void); #endif void bx_init_debug(void); void bx_emulate_hga_dumps_timer(void); /* typedefs */ #if ( BX_PROVIDE_DEVICE_MODELS==1 ) bx_pc_system_c bx_pc_system; class state_file state_stuff("state_file.out", "options"); #endif bx_debug_t bx_dbg; bx_options_t bx_options = { { "", BX_FLOPPY_NONE, BX_EJECTED }, { "", BX_FLOPPY_NONE, BX_EJECTED }, { 0, "", 0, 0, 0 }, { 0, "", 0, 0, 0 }, { 0, "", 0 }, { NULL, 0 }, { NULL }, { BX_DEFAULT_MEM_MEGS }, { NULL, NULL, NULL, 0, 0, 0, 0 }, // SB16 options "a", 300000, 20000, // default keyboard serial path delay (usec) 50000, // default floppy command delay (usec) 500000, // default ips (instructions-per-second) 0, // default mouse_enabled 0, // default private_colormap 0, // default i440FXSupport {NULL, 0}, // cmos path, cmos image boolean { 0, 0, 0, {0,0,0,0,0,0}, NULL, NULL }, // ne2k 0, // newHardDriveSupport { 0, NULL, NULL, NULL } // load32bitOSImage hack stuff }; static char bochsrc_path[512]; static char logfilename[512] = "-"; static void parse_line_unformatted(char *line); static void parse_line_formatted(int num_params, char *params[]); static void parse_bochsrc(void); // Just for the iofunctions #define LOG_THIS this->log-> int Allocio=0; void iofunctions::flush(void) { if(logfd && magic == MAGIC_LOGNUM) { fflush(logfd); } } void iofunctions::init(void) { // iofunctions methods must not be called before this magic // number is set. magic=MAGIC_LOGNUM; showtick = 1; init_log(stderr); log = new logfunc_t(this); LOG_THIS setprefix("[IO ]"); LOG_THIS settype(IOLOG); BX_DEBUG(("Init(log file: '%s').\n",logfn)); } void iofunctions::init_log(char *fn) { assert (magic==MAGIC_LOGNUM); // use newfd/newfn so that we can log the message to the OLD log // file descriptor. FILE *newfd = stderr; char *newfn = "/dev/stderr"; if( strcmp( fn, "-" ) != 0 ) { newfd = fopen(fn, "w"); if(newfd != NULL) { newfn = strdup(fn); BX_DEBUG(("Opened log file '%s'.\n", fn )); } else { BX_DEBUG(("Log file '%s' not there?\n", fn)); newfd = NULL; logfn = "(none)"; } } logfd = newfd; logfn = newfn; } void iofunctions::init_log(FILE *fs) { assert (magic==MAGIC_LOGNUM); logfd = fs; if(fs == stderr) { logfn = "/dev/stderr"; } else if(fs == stdout) { logfn = "/dev/stdout"; } else { logfn = "(unknown)"; } } void iofunctions::init_log(int fd) { assert (magic==MAGIC_LOGNUM); FILE *tmpfd; if( (tmpfd = fdopen(fd,"w")) == NULL ) { fprintf(stderr, "Couldn't open fd %d as a stream for writing\n", fd); return; } init_log(tmpfd); return; }; // iofunctions::out( class, level, prefix, fmt, ap) // DO NOT nest out() from ::info() and the like. // fmt and ap retained for direct printinf from iofunctions only! void iofunctions::out(int f, int l, char *prefix, char *fmt, va_list ap) { assert (magic==MAGIC_LOGNUM); assert (this != NULL); assert (logfd != NULL); if( showtick ) fprintf(logfd, "%011lld ", bx_pc_system.time_ticks()); if(prefix != NULL) fprintf(logfd, "%s ", prefix); if(l==LOGLEV_PANIC) fprintf(logfd, ">>PANIC<< "); vfprintf(logfd, fmt, ap); fflush(logfd); return; } iofunctions::iofunctions(FILE *fs) { init(); init_log(fs); } iofunctions::iofunctions(char *fn) { init(); init_log(fn); } iofunctions::iofunctions(int fd) { init(); init_log(fd); } iofunctions::iofunctions(void) { this->init(); } iofunctions::~iofunctions(void) { // flush before erasing magic number, or flush does nothing. this->flush(); this->magic=0; } #undef LOG_THIS #define LOG_THIS genlog-> logfunctions::logfunctions(void) { setprefix("[GEN ]"); settype(GENLOG); if(io == NULL && Allocio == 0) { Allocio = 1; io = new iofunc_t(stderr); } setio(io); onoff[LOGLEV_DEBUG]=0; onoff[LOGLEV_ERROR]=1; onoff[LOGLEV_PANIC]=1; // XXX careful, disable this, and you disable panics! onoff[LOGLEV_INFO]=1; } logfunctions::logfunctions(iofunc_t *iofunc) { setprefix("[GEN ]"); settype(GENLOG); setio(iofunc); onoff[LOGLEV_DEBUG]=0; onoff[LOGLEV_ERROR]=1; onoff[LOGLEV_PANIC]=1; // XXX careful, disable this, and you disable panics! onoff[LOGLEV_INFO]=1; } logfunctions::~logfunctions(void) { } void logfunctions::setio(iofunc_t *i) { this->logio = i; } void logfunctions::setprefix(char *p) { this->prefix=strdup(p); } void logfunctions::settype(int t) { type=t; } void logfunctions::info(char *fmt, ...) { va_list ap; FILE *fs; assert (this != NULL); assert (this->logio != NULL); if(!onoff[LOGLEV_INFO]) return; va_start(ap, fmt); this->logio->out(this->type,LOGLEV_INFO,this->prefix, fmt, ap); va_end(ap); } void logfunctions::error(char *fmt, ...) { va_list ap; FILE *fs; assert (this != NULL); assert (this->logio != NULL); if(!onoff[LOGLEV_ERROR]) return; va_start(ap, fmt); this->logio->out(this->type,LOGLEV_ERROR,this->prefix, fmt, ap); va_end(ap); } void logfunctions::panic(char *fmt, ...) { va_list ap; FILE *fs; assert (this != NULL); assert (this->logio != NULL); if(onoff[LOGLEV_PANIC]) { // XXX to return or not to return? va_start(ap, fmt); this->logio->out(this->type,LOGLEV_PANIC,this->prefix, fmt, ap); va_end(ap); } #if !BX_PANIC_IS_FATAL return; #endif bx_atexit(); #if !BX_DEBUGGER exit(1); #else static Boolean dbg_exit_called = 0; if (dbg_exit_called == 0) { dbg_exit_called = 1; bx_dbg_exit(1); } #endif } void logfunctions::ldebug(char *fmt, ...) { va_list ap; FILE *fs; assert (this != NULL); assert (this->logio != NULL); if(!onoff[LOGLEV_DEBUG]) return; va_start(ap, fmt); this->logio->out(this->type,LOGLEV_DEBUG,this->prefix, fmt, ap); va_end(ap); } iofunc_t *io = NULL; logfunc_t *genlog = NULL; int main(int argc, char *argv[]) { // To deal with initialization order problems inherent in C++, use // the macros SAFE_GET_IOFUNC and SAFE_GET_GENLOG to retrieve "io" and "genlog" // in all constructors or functions called by constructors. The macros // test for NULL and create the object if necessary, then return it. // Ensure that io and genlog get created, by making one reference to // each macro right here. All other code can call them directly. SAFE_GET_IOFUNC(); SAFE_GET_GENLOG(); #if BX_DEBUGGER // If using the debugger, it will take control and call // bx_bochs_init() and cpu_loop() bx_dbg_main(argc, argv); #else // If not using the debugger, pass control on normally bx_bochs_init(argc, argv); if (bx_options.load32bitOSImage.whichOS) { void bx_load32bitOSimagehack(void); bx_load32bitOSimagehack(); } BX_CPU.cpu_loop(); #endif fprintf(stderr,"genlog is at 0x%x\n",genlog); return(0); } int bx_bochs_init(int argc, char *argv[]) { int n; #ifdef MAGIC_BREAKPOINT bx_dbg.magic_break_enabled = 0; #endif /* read the .bochsrc file */ parse_bochsrc(); //#if BX_PROVIDE_CPU_MEMORY==1 // else if (!strcmp(argv[n-1], "-sanity-check")) { // BX_CPU.sanity_checks(); // n += 1; // exit(0); // } //#endif // Pass all command line options to be parsed, // just like they came from the .bochsrc. Thus // command line options will override .bochsrc options. n = 2; while (n <= argc) { parse_line_unformatted(argv[n-1]); n++; } bx_pc_system.init_ips(bx_options.ips); if(logfilename[0]!='-') io->init_log(logfilename); #if BX_DEBUGGER == 0 // debugger will do this work, if enabled BX_CPU.reset(BX_RESET_HARDWARE); BX_MEM.init_memory(bx_options.memory.megs * 1024*1024); BX_MEM.load_ROM(bx_options.rom.path, bx_options.rom.address); BX_MEM.load_ROM(bx_options.vgarom.path, 0xc0000); #endif bx_init_debug(); #if BX_DEBUGGER == 0 bx_devices.init(); bx_gui.init_signal_handlers (); bx_pc_system.start_timers(); #endif BX_INFO(("bx_bochs_init is setting signal handlers\n")); // if not using debugger, then we can take control of SIGINT. // If using debugger, it needs control of this. #if BX_DEBUGGER==0 signal(SIGINT, bx_signal_handler); #endif #if BX_SHOW_IPS #ifndef __MINGW32__ signal(SIGALRM, bx_signal_handler); #endif alarm( 1 ); #endif return(0); } void bx_init_debug(void) { bx_dbg.floppy = 0; bx_dbg.keyboard = 0; bx_dbg.video = 0; bx_dbg.disk = 0; bx_dbg.pit = 0; bx_dbg.pic = 0; bx_dbg.bios = 0; bx_dbg.cmos = 0; bx_dbg.a20 = 0; bx_dbg.interrupts = 0; bx_dbg.exceptions = 0; bx_dbg.unsupported = 0; bx_dbg.temp = 0; bx_dbg.reset = 0; bx_dbg.mouse = 0; bx_dbg.io = 0; bx_dbg.debugger = 0; bx_dbg.xms = 0; bx_dbg.v8086 = 0; bx_dbg.paging = 0; bx_dbg.creg = 0; bx_dbg.dreg = 0; bx_dbg.dma = 0; bx_dbg.unsupported_io = 0; bx_dbg.record_io = 0; bx_dbg.serial = 0; bx_dbg.cdrom = 0; } void bx_atexit(void) { static Boolean been_here = 0; #if BX_PROVIDE_DEVICE_MODELS==1 if (been_here == 0) { bx_pc_system.exit(); } #endif #if BX_DEBUGGER == 0 BX_CPU.atexit(); #endif #if BX_PCI_SUPPORT if (bx_options.i440FXSupport) { bx_devices.pci->print_i440fx_state(); } #endif BX_INFO(("bochs exited, log file was '%s'\n", logfilename)); } #if (BX_PROVIDE_CPU_MEMORY==1) && (BX_EMULATE_HGA_DUMPS>0) void bx_emulate_hga_dumps_timer(void) { void bx_hga_set_video_memory(Bit8u *ptr); bx_hga_set_video_memory(&bx_phy_memory[0xb0000]); } #endif #if BX_PROVIDE_MAIN static void parse_bochsrc(void) { FILE *fd; char *ret; char line[512]; #if (!defined(WIN32) && !defined(macintosh)) char *ptr; ptr = getenv("HOME"); if (!ptr) { BX_PANIC(( "could not get environment variable 'HOME'.\n" )); } strcpy(bochsrc_path, ".bochsrc"); fd = fopen(bochsrc_path, "r"); if (!fd) { BX_DEBUG(( "could not open file '%s', trying home directory.\n", bochsrc_path)); strcpy(bochsrc_path, ptr); strcat(bochsrc_path, "/"); strcat(bochsrc_path, ".bochsrc"); fd = fopen(bochsrc_path, "r"); if (!fd) { BX_DEBUG(( "could not open file '%s'.\n", bochsrc_path )); // no file used, nothing left to do. This is now valid, // as you can pass everything on the command line. return; } else BX_INFO(("using rc file '%s'.\n", bochsrc_path)); } else BX_INFO(("using rc file '%s'.\n", bochsrc_path)); #else // try opening file bochsrc only in current directory for win32 strcpy(bochsrc_path, "bochsrc"); fd = fopen(bochsrc_path, "r"); if (!fd) { BX_INFO(( "could not open file '%s' in current directory.\n", bochsrc_path )); exit(1); } #endif // #if (!defined(WIN32) && !defined(macintosh)) do { ret = fgets(line, sizeof(line)-1, fd); line[sizeof(line) - 1] = '\0'; line[strlen(line) - 1] = '\0'; if ((ret != NULL) && strlen(line)) { parse_line_unformatted(line); } } while (!feof(fd)); } static void parse_line_unformatted(char *line) { char *ptr; unsigned i, string_i; char string[512]; char *params[40]; int num_params; Boolean inquotes = 0; if (line == NULL) return; // if passed nothing but whitespace, just return for (i=0; i=strlen(line)) return; num_params = 0; ptr = strtok(line, ":"); while (ptr) { string_i = 0; for (i=0; i 6)) { fprintf(stderr, ".bochsrc: ne2k directive malformed.\n"); exit(1); } bx_options.ne2k.ethmod = "null"; if (strncmp(params[1], "ioaddr=", 7)) { fprintf(stderr, ".bochsrc: ne2k directive malformed.\n"); exit(1); } if (strncmp(params[2], "irq=", 4)) { fprintf(stderr, ".bochsrc: ne2k directive malformed.\n"); exit(1); } if (strncmp(params[3], "mac=", 4)) { fprintf(stderr, ".bochsrc: ne2k directive malformed.\n"); exit(1); } bx_options.ne2k.ioaddr = strtoul(¶ms[1][7], NULL, 16); bx_options.ne2k.irq = atol(¶ms[2][4]); i = sscanf(¶ms[3][4], "%x:%x:%x:%x:%x:%x", &tmp[0],&tmp[1],&tmp[2],&tmp[3],&tmp[4],&tmp[5]); if (i != 6) { fprintf(stderr, ".bochsrc: ne2k mac address malformed.\n"); exit(1); } for (i=0;i<6;i++) bx_options.ne2k.macaddr[i] = tmp[i]; if (num_params > 4) { if (strncmp(params[4], "ethmod=", 7)) { fprintf(stderr, ".bochsrc: ne2k directive malformed.\n"); exit(1); } bx_options.ne2k.ethmod = strdup(¶ms[4][7]); if (num_params == 6) { if (strncmp(params[5], "ethdev=", 7)) { fprintf(stderr, ".bochsrc: ne2k directive malformed.\n"); exit(1); } bx_options.ne2k.ethdev = strdup(¶ms[5][7]); } } bx_options.ne2k.valid = 1; } else if (!strcmp(params[0], "load32bitOSImage")) { if ( (num_params!=4) && (num_params!=5) ) { fprintf(stderr, ".bochsrc: load32bitOSImage directive: wrong # args.\n"); exit(1); } if (strncmp(params[1], "os=", 3)) { fprintf(stderr, ".bochsrc: load32bitOSImage: directive malformed.\n"); exit(1); } if (!strcmp(¶ms[1][3], "nullkernel")) { bx_options.load32bitOSImage.whichOS = Load32bitOSNullKernel; } else if (!strcmp(¶ms[1][3], "linux")) { bx_options.load32bitOSImage.whichOS = Load32bitOSLinux; } else { fprintf(stderr, ".bochsrc: load32bitOSImage: unsupported OS.\n"); exit(1); } if (strncmp(params[2], "path=", 5)) { fprintf(stderr, ".bochsrc: load32bitOSImage: directive malformed.\n"); exit(1); } if (strncmp(params[3], "iolog=", 6)) { fprintf(stderr, ".bochsrc: load32bitOSImage: directive malformed.\n"); exit(1); } bx_options.load32bitOSImage.path = strdup(¶ms[2][5]); bx_options.load32bitOSImage.iolog = strdup(¶ms[3][6]); if (num_params == 5) { if (strncmp(params[4], "initrd=", 7)) { fprintf(stderr, ".bochsrc: load32bitOSImage: directive malformed.\n"); exit(1); } bx_options.load32bitOSImage.initrd = strdup(¶ms[4][7]); } } else { BX_PANIC(( ".bochsrc: directive '%s' not understood\n", params[0])); } if (bx_options.diskd.present && bx_options.cdromd.present) BX_PANIC(("At present, using both diskd and cdromd at once is not supported.")); } #endif // #if BX_PROVIDE_MAIN void bx_signal_handler( int signum) { #if BX_GUI_SIGHANDLER // GUI signal handler gets first priority, if the mask says it's wanted if ((1<