- fixed several MSVC compilation warnings
[bochs-mirror.git] / main.cc
blob52d3d0dfbc85c83bc4885a630c5857c0e80b1843
1 /////////////////////////////////////////////////////////////////////////
2 // $Id: main.cc,v 1.362 2007/11/01 18:03:48 sshwarts Exp $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (C) 2002 MandrakeSoft S.A.
6 //
7 // MandrakeSoft S.A.
8 // 43, rue d'Aboukir
9 // 75002 Paris - France
10 // http://www.linux-mandrake.com/
11 // http://www.mandrakesoft.com/
13 // This library is free software; you can redistribute it and/or
14 // modify it under the terms of the GNU Lesser General Public
15 // License as published by the Free Software Foundation; either
16 // version 2 of the License, or (at your option) any later version.
18 // This library is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 // Lesser General Public License for more details.
23 // You should have received a copy of the GNU Lesser General Public
24 // License along with this library; if not, write to the Free Software
25 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include "bochs.h"
28 #include "cpu/cpu.h"
29 #include "iodev/iodev.h"
31 #ifdef HAVE_LOCALE_H
32 #include <locale.h>
33 #endif
35 #if BX_WITH_SDL
36 // since SDL redefines main() to SDL_main(), we must include SDL.h so that the
37 // C language prototype is found. Otherwise SDL_main() will get its name
38 // mangled and not match what the SDL library is expecting.
39 #include <SDL.h>
41 #if defined(macintosh)
42 // Work around a bug in SDL 1.2.4 on MacOS X, which redefines getenv to
43 // SDL_getenv, but then neglects to provide SDL_getenv. It happens
44 // because we are defining -Dmacintosh.
45 #undef getenv
46 #endif
47 #endif
49 #if BX_WITH_CARBON
50 #define Float32 KLUDGE_Float32
51 #define Float64 KLUDGE_Float64
52 #include <Carbon/Carbon.h>
53 #undef Float32
54 #undef Float64
55 #endif
58 extern "C" {
59 #include <signal.h>
62 #if defined(__MINGW32__) || defined(_MSC_VER)
63 void alarm(int);
64 #endif
66 #if BX_GUI_SIGHANDLER
67 bx_bool bx_gui_sighandler = 0;
68 #endif
70 #if BX_PROVIDE_DEVICE_MODELS==1
71 // some prototypes from iodev/
72 // I want to stay away from including iodev/iodev.h here
73 Bit32u bx_unmapped_io_read_handler(Bit32u address, unsigned io_len);
74 void bx_unmapped_io_write_handler(Bit32u address, Bit32u value,
75 unsigned io_len);
76 #endif
78 void bx_init_hardware(void);
79 void bx_init_options(void);
80 void bx_init_bx_dbg(void);
82 static const char *divider = "========================================================================";
83 static logfunctions thePluginLog;
84 logfunctions *pluginlog = &thePluginLog;
86 bx_startup_flags_t bx_startup_flags;
87 bx_bool bx_user_quit;
88 Bit8u bx_cpu_count;
90 /* typedefs */
92 #define LOG_THIS genlog->
94 #if ( BX_PROVIDE_DEVICE_MODELS==1 )
95 bx_pc_system_c bx_pc_system;
96 #endif
98 bx_debug_t bx_dbg;
100 typedef BX_CPU_C *BX_CPU_C_PTR;
102 #if BX_SUPPORT_SMP
103 // multiprocessor simulation, we need an array of cpus
104 BOCHSAPI BX_CPU_C_PTR *bx_cpu_array = NULL;
105 #else
106 // single processor simulation, so there's one of everything
107 BOCHSAPI BX_CPU_C bx_cpu;
108 #endif
110 #if BX_PROVIDE_CPU_MEMORY==1
111 BOCHSAPI BX_MEM_C bx_mem;
112 #endif
114 char *bochsrc_filename = NULL;
116 void bx_print_header ()
118 fprintf (stderr, "%s\n", divider);
119 char buffer[128];
120 sprintf (buffer, "Bochs x86 Emulator %s\n", VER_STRING);
121 bx_center_print (stderr, buffer, 72);
122 if (REL_STRING[0]) {
123 sprintf (buffer, "%s\n", REL_STRING);
124 bx_center_print (stderr, buffer, 72);
126 fprintf (stderr, "%s\n", divider);
129 #if BX_WITH_CARBON
130 /* Original code by Darrell Walisser - dwaliss1@purdue.edu */
132 static void setupWorkingDirectory (char *path)
134 char parentdir[MAXPATHLEN];
135 char *c;
137 strncpy ( parentdir, path, MAXPATHLEN );
138 c = (char*) parentdir;
140 while (*c != '\0') /* go to end */
141 c++;
143 while (*c != '/') /* back up to parent */
144 c--;
146 *c = '\0'; /* cut off last part (binary name) */
148 /* chdir to the binary app's parent */
149 int n;
150 n = chdir (parentdir);
151 if (n) BX_PANIC (("failed to change dir to parent"));
152 /* chdir to the .app's parent */
153 n = chdir ("../../../");
154 if (n) BX_PANIC (("failed to change to ../../.."));
157 /* Panic button to display fatal errors.
158 Completely self contained, can't rely on carbon.cc being available */
159 static void carbonFatalDialog(const char *error, const char *exposition)
161 DialogRef alertDialog;
162 CFStringRef cfError;
163 CFStringRef cfExposition;
164 DialogItemIndex index;
165 AlertStdCFStringAlertParamRec alertParam = {0};
166 fprintf(stderr, "Entering carbonFatalDialog: %s\n", error);
168 // Init libraries
169 InitCursor();
170 // Assemble dialog
171 cfError = CFStringCreateWithCString(NULL, error, kCFStringEncodingASCII);
172 if(exposition != NULL)
174 cfExposition = CFStringCreateWithCString(NULL, exposition, kCFStringEncodingASCII);
176 else { cfExposition = NULL; }
177 alertParam.version = kStdCFStringAlertVersionOne;
178 alertParam.defaultText = CFSTR("Quit");
179 alertParam.position = kWindowDefaultPosition;
180 alertParam.defaultButton = kAlertStdAlertOKButton;
181 // Display Dialog
182 CreateStandardAlert(
183 kAlertStopAlert,
184 cfError,
185 cfExposition, /* can be NULL */
186 &alertParam, /* can be NULL */
187 &alertDialog);
188 RunStandardAlert( alertDialog, NULL, &index);
189 // Cleanup
190 CFRelease( cfError );
191 if( cfExposition != NULL ) { CFRelease( cfExposition ); }
193 #endif
195 #if BX_DEBUGGER
196 void print_tree(bx_param_c *node, int level)
198 int i;
199 char tmpstr[BX_PATHNAME_LEN], tmpbyte[4];
201 for (i=0; i<level; i++)
202 dbg_printf(" ");
203 if (node == NULL) {
204 dbg_printf("NULL pointer\n");
205 return;
207 switch (node->get_type()) {
208 case BXT_PARAM_NUM:
209 if (((bx_param_num_c*)node)->get_base() == BASE_DEC) {
210 dbg_printf("%s = " FMT_LL "d (number)\n", node->get_name(), ((bx_param_num_c*)node)->get64());
211 } else {
212 dbg_printf("%s = 0x" FMT_LL "x (hex number)\n", node->get_name(), ((bx_param_num_c*)node)->get64());
214 break;
215 case BXT_PARAM_BOOL:
216 dbg_printf("%s = %s (boolean)\n", node->get_name(), ((bx_param_bool_c*)node)->get()?"true":"false");
217 break;
218 case BXT_PARAM_ENUM:
219 dbg_printf("%s = '%s' (enum)\n", node->get_name(), ((bx_param_enum_c*)node)->get_selected());
220 break;
221 case BXT_PARAM_STRING:
222 if (((bx_param_string_c*)node)->get_options()->get() & bx_param_string_c::RAW_BYTES) {
223 tmpstr[0] = 0;
224 for (i = 0; i < ((bx_param_string_c*)node)->get_maxsize(); i++) {
225 if (i > 0) {
226 tmpbyte[0] = ((bx_param_string_c*)node)->get_separator();
227 tmpbyte[1] = 0;
228 strcat(tmpstr, tmpbyte);
230 sprintf(tmpbyte, "%02x", (Bit8u)((bx_param_string_c*)node)->getptr()[i]);
231 strcat(tmpstr, tmpbyte);
233 dbg_printf("%s = '%s' (raw byte string)\n", node->get_name(), tmpstr);
234 } else {
235 dbg_printf("%s = '%s' (string)\n", node->get_name(), ((bx_param_string_c*)node)->getptr());
237 break;
238 case BXT_LIST:
240 dbg_printf("%s = \n", node->get_name());
241 bx_list_c *list = (bx_list_c*)node;
242 for (i=0; i < list->get_size(); i++) {
243 print_tree(list->get(i), level+1);
245 break;
247 case BXT_PARAM_DATA:
248 dbg_printf("%s = 'size=%d' (binary data)\n", node->get_name(), ((bx_shadow_data_c*)node)->get_size());
249 break;
250 default:
251 dbg_printf("%s (unknown parameter type)\n", node->get_name());
254 #endif
256 int bxmain () {
257 #ifdef HAVE_LOCALE_H
258 // Initialize locale (for isprint() and other functions)
259 setlocale (LC_ALL, "");
260 #endif
261 bx_user_quit = 0;
262 bx_init_siminterface(); // create the SIM object
263 static jmp_buf context;
264 if (setjmp (context) == 0) {
265 SIM->set_quit_context (&context);
266 if (bx_init_main(bx_startup_flags.argc, bx_startup_flags.argv) < 0)
267 return 0;
268 // read a param to decide which config interface to start.
269 // If one exists, start it. If not, just begin.
270 bx_param_enum_c *ci_param = SIM->get_param_enum(BXPN_SEL_CONFIG_INTERFACE);
271 const char *ci_name = ci_param->get_selected();
272 if (!strcmp(ci_name, "textconfig")) {
273 #if BX_USE_TEXTCONFIG
274 init_text_config_interface(); // in textconfig.h
275 #else
276 BX_PANIC(("configuration interface 'textconfig' not present"));
277 #endif
279 #if BX_WITH_WX
280 else if (!strcmp(ci_name, "wx")) {
281 PLUG_load_plugin(wx, PLUGTYPE_CORE);
283 #endif
284 else {
285 BX_PANIC(("unsupported configuration interface '%s'", ci_name));
287 ci_param->set_enabled(0);
288 int status = SIM->configuration_interface(ci_name, CI_START);
289 if (status == CI_ERR_NO_TEXT_CONSOLE)
290 BX_PANIC(("Bochs needed the text console, but it was not usable"));
291 // user quit the config interface, so just quit
292 } else {
293 // quit via longjmp
295 SIM->set_quit_context(NULL);
296 #if defined(WIN32)
297 if (!bx_user_quit) {
298 // ask user to press ENTER before exiting, so that they can read messages
299 // before the console window is closed. This isn't necessary after pressing
300 // the power button.
301 fprintf(stderr, "\nBochs is exiting. Press ENTER when you're ready to close this window.\n");
302 char buf[16];
303 fgets(buf, sizeof(buf), stdin);
305 #endif
306 return SIM->get_exit_code();
309 #if defined(__WXMSW__)
311 // win32 applications get the whole command line in one long string.
312 // This function is used to split up the string into argc and argv,
313 // so that the command line can be used on win32 just like on every
314 // other platform.
316 // I'm sure other people have written this same function, and they may have
317 // done it better, but I don't know where to find it. -BBD
318 #ifndef MAX_ARGLEN
319 #define MAX_ARGLEN 80
320 #endif
321 int split_string_into_argv (
322 char *string,
323 int *argc_out,
324 char **argv,
325 int max_argv)
327 char *buf0 = new char[strlen(string)+1];
328 strcpy (buf0, string);
329 char *buf = buf0;
330 int in_double_quote = 0, in_single_quote = 0;
331 for (int i=0; i<max_argv; i++)
332 argv[i] = NULL;
333 argv[0] = new char[6];
334 strcpy (argv[0], "bochs");
335 int argc = 1;
336 argv[argc] = new char[MAX_ARGLEN];
337 char *outp = &argv[argc][0];
338 // trim leading and trailing spaces
339 while (*buf==' ') buf++;
340 char *p;
341 char *last_nonspace = buf;
342 for (p=buf; *p; p++) {
343 if (*p!=' ') last_nonspace = p;
345 if (last_nonspace != buf) *(last_nonspace+1) = 0;
346 p = buf;
347 bx_bool done = false;
348 while (!done) {
349 //fprintf (stderr, "parsing '%c' with singlequote=%d, dblquote=%d\n", *p, in_single_quote, in_double_quote);
350 switch (*p) {
351 case '\0':
352 done = true;
353 // fall through into behavior for space
354 case ' ':
355 if (in_double_quote || in_single_quote)
356 goto do_default;
357 *outp = 0;
358 //fprintf (stderr, "completed arg %d = '%s'\n", argc, argv[argc]);
359 argc++;
360 if (argc >= max_argv) {
361 fprintf (stderr, "too many arguments. Increase MAX_ARGUMENTS\n");
362 return -1;
364 argv[argc] = new char[MAX_ARGLEN];
365 outp = &argv[argc][0];
366 while (*p==' ') p++;
367 break;
368 case '"':
369 if (in_single_quote) goto do_default;
370 in_double_quote = !in_double_quote;
371 p++;
372 break;
373 case '\'':
374 if (in_double_quote) goto do_default;
375 in_single_quote = !in_single_quote;
376 p++;
377 break;
378 do_default:
379 default:
380 if (outp-&argv[argc][0] >= MAX_ARGLEN) {
381 //fprintf (stderr, "command line arg %d exceeded max size %d\n", argc, MAX_ARGLEN);
382 return -1;
384 *(outp++) = *(p++);
387 if (in_single_quote) {
388 fprintf (stderr, "end of string with mismatched single quote (')\n");
389 return -1;
391 if (in_double_quote) {
392 fprintf (stderr, "end of string with mismatched double quote (\")\n");
393 return -1;
395 *argc_out = argc;
396 return 0;
398 #endif /* if defined(__WXMSW__) */
400 #if defined(__WXMSW__) || (BX_WITH_SDL && defined(WIN32))
401 // The RedirectIOToConsole() function is copied from an article called "Adding
402 // Console I/O to a Win32 GUI App" in Windows Developer Journal, December 1997.
403 // It creates a console window.
405 // NOTE: It could probably be written so that it can safely be called for all
406 // win32 builds.
407 int RedirectIOToConsole()
409 int hConHandle;
410 long lStdHandle;
411 FILE *fp;
412 // allocate a console for this app
413 if (!AllocConsole()) {
414 MessageBox(NULL, "Failed to create text console", "Error", MB_ICONERROR);
415 return 0;
417 // redirect unbuffered STDOUT to the console
418 lStdHandle = (long)GetStdHandle(STD_OUTPUT_HANDLE);
419 hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
420 fp = _fdopen(hConHandle, "w");
421 *stdout = *fp;
422 setvbuf( stdout, NULL, _IONBF, 0 );
423 // redirect unbuffered STDIN to the console
424 lStdHandle = (long)GetStdHandle(STD_INPUT_HANDLE);
425 hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
426 fp = _fdopen(hConHandle, "r");
427 *stdin = *fp;
428 setvbuf( stdin, NULL, _IONBF, 0 );
429 // redirect unbuffered STDERR to the console
430 lStdHandle = (long)GetStdHandle(STD_ERROR_HANDLE);
431 hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
432 fp = _fdopen( hConHandle, "w" );
433 *stderr = *fp;
434 setvbuf(stderr, NULL, _IONBF, 0);
435 return 1;
437 #endif /* if defined(__WXMSW__) || (BX_WITH_SDL && defined(WIN32)) */
439 #if defined(__WXMSW__)
440 // only used for wxWidgets/win32.
441 // This works ok in Cygwin with a standard wxWidgets compile. In
442 // VC++ wxWidgets must be compiled with -DNOMAIN=1.
443 int WINAPI WinMain(
444 HINSTANCE hInstance,
445 HINSTANCE hPrevInstance,
446 LPSTR m_lpCmdLine, int nCmdShow)
448 bx_startup_flags.hInstance = hInstance;
449 bx_startup_flags.hPrevInstance = hPrevInstance;
450 bx_startup_flags.m_lpCmdLine = m_lpCmdLine;
451 bx_startup_flags.nCmdShow = nCmdShow;
452 if (!RedirectIOToConsole()) {
453 return 1;
455 SetConsoleTitle("Bochs for Windows (wxWidgets port) - Console");
456 int max_argv = 20;
457 bx_startup_flags.argv = (char**) malloc (max_argv * sizeof (char*));
458 split_string_into_argv(m_lpCmdLine, &bx_startup_flags.argc, bx_startup_flags.argv, max_argv);
459 return bxmain();
461 #endif
463 #if !defined(__WXMSW__)
464 // normal main function, presently in for all cases except for
465 // wxWidgets under win32.
466 int main (int argc, char *argv[])
468 bx_startup_flags.argc = argc;
469 bx_startup_flags.argv = argv;
470 #if BX_WITH_SDL && defined(WIN32)
471 // if SDL/win32, try to create a console window.
472 if (!RedirectIOToConsole()) {
473 return 1;
475 #endif
476 #if defined(WIN32)
477 SetConsoleTitle("Bochs for Windows - Console");
478 #endif
479 return bxmain();
481 #endif
483 void print_usage()
485 fprintf(stderr,
486 "Usage: bochs [flags] [bochsrc options]\n\n"
487 " -n no configuration file\n"
488 " -f configfile specify configuration file\n"
489 " -q quick start (skip configuration interface)\n"
490 " -benchmark n run bochs in benchmark mode for millions of emulated ticks\n"
491 " -r path restore the Bochs state from path\n"
492 #if BX_DEBUGGER
493 " -rc filename execute debugger commands stored in file\n"
494 #endif
495 " --help display this help and exit\n\n"
496 "For information on Bochs configuration file arguments, see the\n"
497 #if (!defined(WIN32)) && !BX_WITH_MACOS
498 "bochsrc section in the user documentation or the man page of bochsrc.\n");
499 #else
500 "bochsrc section in the user documentation.\n");
501 #endif
504 int bx_init_main(int argc, char *argv[])
506 // To deal with initialization order problems inherent in C++, use the macros
507 // SAFE_GET_IOFUNC and SAFE_GET_GENLOG to retrieve "io" and "genlog" in all
508 // constructors or functions called by constructors. The macros test for
509 // NULL and create the object if necessary, then return it. Ensure that io
510 // and genlog get created, by making one reference to each macro right here.
511 // All other code can reference io and genlog directly. Because these
512 // objects are required for logging, and logging is so fundamental to
513 // knowing what the program is doing, they are never free()d.
514 SAFE_GET_IOFUNC(); // never freed
515 SAFE_GET_GENLOG(); // never freed
517 // initalization must be done early because some destructors expect
518 // the bochs config options to exist by the time they are called.
519 bx_init_bx_dbg();
520 bx_init_options();
522 bx_print_header();
524 SIM->get_param_enum(BXPN_BOCHS_START)->set(BX_RUN_START);
526 // interpret the args that start with -, like -q, -f, etc.
527 int arg = 1, load_rcfile=1;
528 while (arg < argc) {
529 // parse next arg
530 if (!strcmp("--help", argv[arg]) || !strncmp("-h", argv[arg], 2)
531 #if defined(WIN32)
532 || !strncmp("/?", argv[arg], 2)
533 #endif
535 print_usage();
536 SIM->quit_sim(0);
538 else if (!strcmp("-n", argv[arg])) {
539 load_rcfile = 0;
541 else if (!strcmp("-q", argv[arg])) {
542 SIM->get_param_enum(BXPN_BOCHS_START)->set(BX_QUICK_START);
544 else if (!strcmp("-f", argv[arg])) {
545 if (++arg >= argc) BX_PANIC(("-f must be followed by a filename"));
546 else bochsrc_filename = argv[arg];
548 else if (!strcmp("-qf", argv[arg])) {
549 SIM->get_param_enum(BXPN_BOCHS_START)->set(BX_QUICK_START);
550 if (++arg >= argc) BX_PANIC(("-qf must be followed by a filename"));
551 else bochsrc_filename = argv[arg];
553 else if (!strcmp("-benchmark", argv[arg])) {
554 SIM->get_param_enum(BXPN_BOCHS_START)->set(BX_QUICK_START);
555 if (++arg >= argc) BX_PANIC(("-benchmark must be followed by a number"));
556 else SIM->get_param_num(BXPN_BOCHS_BENCHMARK)->set(atoi(argv[arg]));
558 else if (!strcmp("-r", argv[arg])) {
559 if (++arg >= argc) BX_PANIC(("-r must be followed by a path"));
560 else {
561 SIM->get_param_enum(BXPN_BOCHS_START)->set(BX_QUICK_START);
562 SIM->get_param_bool(BXPN_RESTORE_FLAG)->set(1);
563 SIM->get_param_string(BXPN_RESTORE_PATH)->set(argv[arg]);
566 #if BX_WITH_CARBON
567 else if (!strncmp("-psn", argv[arg], 4)) {
568 // "-psn" is passed if we are launched by double-clicking
569 // ugly hack. I don't know how to open a window to print messages in,
570 // so put them in /tmp/early-bochs-out.txt. Sorry. -bbd
571 io->init_log("/tmp/early-bochs-out.txt");
572 BX_INFO (("I was launched by double clicking. Fixing home directory."));
573 arg = argc; // ignore all other args.
574 setupWorkingDirectory (argv[0]);
575 // there is no stdin/stdout so disable the text-based config interface.
576 SIM->get_param_enum(BXPN_BOCHS_START)->set(BX_QUICK_START);
577 char cwd[MAXPATHLEN];
578 getwd (cwd);
579 BX_INFO (("Now my working directory is %s", cwd));
580 // if it was started from command line, there could be some args still.
581 for (int a=0; a<argc; a++) {
582 BX_INFO (("argument %d is %s", a, argv[a]));
585 #endif
586 #if BX_DEBUGGER
587 else if (!strcmp("-rc", argv[arg])) {
588 // process "-rc filename" option, if it exists
589 if (++arg >= argc) BX_PANIC(("-rc must be followed by a filename"));
590 else bx_dbg_set_rcfile(argv[arg]);
592 #endif
593 else if (argv[arg][0] == '-') {
594 print_usage();
595 BX_PANIC (("command line arg '%s' was not understood", argv[arg]));
597 else {
598 // the arg did not start with -, so stop interpreting flags
599 break;
601 arg++;
603 #if BX_WITH_CARBON
604 if(!getenv("BXSHARE"))
606 CFBundleRef mainBundle;
607 CFURLRef bxshareDir;
608 char bxshareDirPath[MAXPATHLEN];
609 BX_INFO (("fixing default bxshare location ..."));
610 // set bxshare to the directory that contains our application
611 mainBundle = CFBundleGetMainBundle();
612 BX_ASSERT(mainBundle != NULL);
613 bxshareDir = CFBundleCopyBundleURL(mainBundle);
614 BX_ASSERT(bxshareDir != NULL);
615 // translate this to a unix style full path
616 if(!CFURLGetFileSystemRepresentation(bxshareDir, true, (UInt8 *)bxshareDirPath, MAXPATHLEN))
618 BX_PANIC(("Unable to work out bxshare path! (Most likely path too long!)"));
619 return -1;
621 char *c;
622 c = (char*) bxshareDirPath;
623 while (*c != '\0') /* go to end */
624 c++;
625 while (*c != '/') /* back up to parent */
626 c--;
627 *c = '\0'; /* cut off last part (binary name) */
628 setenv("BXSHARE", bxshareDirPath, 1);
629 BX_INFO (("now my BXSHARE is %s", getenv("BXSHARE")));
630 CFRelease(bxshareDir);
632 #endif
633 #if BX_PLUGINS
634 // set a default plugin path, in case the user did not specify one
635 #if BX_WITH_CARBON
636 // if there is no stdin, then we must create our own LTDL_LIBRARY_PATH.
637 // also if there is no LTDL_LIBRARY_PATH, but we have a bundle since we're here
638 // This is here so that it is available whenever --with-carbon is defined but
639 // the above code might be skipped, as in --with-sdl --with-carbon
640 if(!isatty(STDIN_FILENO) || !getenv("LTDL_LIBRARY_PATH"))
642 CFBundleRef mainBundle;
643 CFURLRef libDir;
644 char libDirPath[MAXPATHLEN];
645 if(!isatty(STDIN_FILENO))
647 // there is no stdin/stdout so disable the text-based config interface.
648 SIM->get_param_enum(BXPN_BOCHS_START)->set(BX_QUICK_START);
650 BX_INFO (("fixing default lib location ..."));
651 // locate the lib directory within the application bundle.
652 // our libs have been placed in bochs.app/Contents/(current platform aka MacOS)/lib
653 // This isn't quite right, but they are platform specific and we haven't put
654 // our plugins into true frameworks and bundles either
655 mainBundle = CFBundleGetMainBundle();
656 BX_ASSERT(mainBundle != NULL);
657 libDir = CFBundleCopyAuxiliaryExecutableURL( mainBundle, CFSTR("lib"));
658 BX_ASSERT(libDir != NULL);
659 // translate this to a unix style full path
660 if(!CFURLGetFileSystemRepresentation(libDir, true, (UInt8 *)libDirPath, MAXPATHLEN))
662 BX_PANIC(("Unable to work out ltdl library path within bochs bundle! (Most likely path too long!)"));
663 return -1;
665 setenv("LTDL_LIBRARY_PATH", libDirPath, 1);
666 BX_INFO (("now my LTDL_LIBRARY_PATH is %s", getenv("LTDL_LIBRARY_PATH")));
667 CFRelease(libDir);
669 #elif BX_HAVE_GETENV && BX_HAVE_SETENV
670 if (getenv("LTDL_LIBRARY_PATH") != NULL) {
671 BX_INFO (("LTDL_LIBRARY_PATH is set to '%s'", getenv("LTDL_LIBRARY_PATH")));
672 } else {
673 BX_INFO (("LTDL_LIBRARY_PATH not set. using compile time default '%s'",
674 BX_PLUGIN_PATH));
675 setenv("LTDL_LIBRARY_PATH", BX_PLUGIN_PATH, 1);
677 if (getenv("BXSHARE") != NULL) {
678 BX_INFO (("BXSHARE is set to '%s'", getenv("BXSHARE")));
679 } else {
680 BX_INFO (("BXSHARE not set. using compile time default '%s'",
681 BX_SHARE_PATH));
682 setenv("BXSHARE", BX_SHARE_PATH, 1);
684 #else
685 // we don't have getenv or setenv. Do nothing.
686 #endif
687 #endif /* if BX_PLUGINS */
689 int norcfile = 1;
691 if (SIM->get_param_bool(BXPN_RESTORE_FLAG)->get()) {
692 load_rcfile = 0;
693 norcfile = 0;
695 if (load_rcfile) {
696 /* parse configuration file and command line arguments */
697 #ifdef WIN32
698 int length;
699 if (bochsrc_filename != NULL) {
700 lstrcpy(bx_startup_flags.initial_dir, bochsrc_filename);
701 length = lstrlen(bx_startup_flags.initial_dir);
702 while ((length > 1) && (bx_startup_flags.initial_dir[length-1] != 92)) length--;
703 bx_startup_flags.initial_dir[length] = 0;
704 } else {
705 bx_startup_flags.initial_dir[0] = 0;
707 #endif
708 if (bochsrc_filename == NULL) bochsrc_filename = bx_find_bochsrc ();
709 if (bochsrc_filename)
710 norcfile = bx_read_configuration(bochsrc_filename);
713 if (norcfile) {
714 // No configuration was loaded, so the current settings are unusable.
715 // Switch off quick start so that we will drop into the configuration
716 // interface.
717 if (SIM->get_param_enum(BXPN_BOCHS_START)->get() == BX_QUICK_START) {
718 if (!SIM->test_for_text_console())
719 BX_PANIC(("Unable to start Bochs without a bochsrc.txt and without a text console"));
720 else
721 BX_ERROR(("Switching off quick start, because no configuration file was found."));
723 SIM->get_param_enum(BXPN_BOCHS_START)->set(BX_LOAD_START);
726 if (SIM->get_param_bool(BXPN_RESTORE_FLAG)->get()) {
727 if (arg < argc) {
728 BX_ERROR(("WARNING: bochsrc options are ignored in restore mode!"));
731 else {
732 // parse the rest of the command line. This is done after reading the
733 // configuration file so that the command line arguments can override
734 // the settings from the file.
735 if (bx_parse_cmdline(arg, argc, argv)) {
736 BX_PANIC(("There were errors while parsing the command line"));
737 return -1;
740 // initialize plugin system. This must happen before we attempt to
741 // load any modules.
742 plugin_startup();
743 return 0;
746 bx_bool load_and_init_display_lib()
748 if (bx_gui != NULL) {
749 // bx_gui has already been filled in. This happens when you start
750 // the simulation for the second time.
751 // Also, if you load wxWidgets as the configuration interface. Its
752 // plugin_init will install wxWidgets as the bx_gui.
753 return true;
755 BX_ASSERT(bx_gui == NULL);
756 bx_param_enum_c *ci_param = SIM->get_param_enum(BXPN_SEL_CONFIG_INTERFACE);
757 const char *ci_name = ci_param->get_selected();
758 bx_param_enum_c *gui_param = SIM->get_param_enum(BXPN_SEL_DISPLAY_LIBRARY);
759 const char *gui_name = gui_param->get_selected();
760 if (!strcmp(ci_name, "wx")) {
761 BX_ERROR(("change of the config interface to wx not implemented yet"));
763 if (!strcmp(gui_name, "wx")) {
764 // they must not have used wx as the configuration interface, or bx_gui
765 // would already be initialized. Sorry, it doesn't work that way.
766 BX_ERROR(("wxWidgets was not used as the configuration interface, so it cannot be used as the display library"));
767 // choose another, hopefully different!
768 gui_param->set (0);
769 gui_name = gui_param->get_selected();
770 if (!strcmp (gui_name, "wx")) {
771 BX_PANIC(("no alternative display libraries are available"));
772 return false;
774 BX_ERROR(("changing display library to '%s' instead", gui_name));
776 #if BX_WITH_AMIGAOS
777 if (!strcmp(gui_name, "amigaos"))
778 PLUG_load_plugin (amigaos, PLUGTYPE_OPTIONAL);
779 #endif
780 #if BX_WITH_BEOS
781 if (!strcmp(gui_name, "beos"))
782 PLUG_load_plugin (beos, PLUGTYPE_OPTIONAL);
783 #endif
784 #if BX_WITH_CARBON
785 if (!strcmp(gui_name, "carbon"))
786 PLUG_load_plugin (carbon, PLUGTYPE_OPTIONAL);
787 #endif
788 #if BX_WITH_MACOS
789 if (!strcmp(gui_name, "macos"))
790 PLUG_load_plugin (macintosh, PLUGTYPE_OPTIONAL);
791 #endif
792 #if BX_WITH_NOGUI
793 if (!strcmp(gui_name, "nogui"))
794 PLUG_load_plugin (nogui, PLUGTYPE_OPTIONAL);
795 #endif
796 #if BX_WITH_RFB
797 if (!strcmp(gui_name, "rfb"))
798 PLUG_load_plugin (rfb, PLUGTYPE_OPTIONAL);
799 #endif
800 #if BX_WITH_SDL
801 if (!strcmp(gui_name, "sdl"))
802 PLUG_load_plugin (sdl, PLUGTYPE_OPTIONAL);
803 #endif
804 #if BX_WITH_SVGA
805 if (!strcmp(gui_name, "svga"))
806 PLUG_load_plugin (svga, PLUGTYPE_OPTIONAL);
807 #endif
808 #if BX_WITH_TERM
809 if (!strcmp(gui_name, "term"))
810 PLUG_load_plugin (term, PLUGTYPE_OPTIONAL);
811 #endif
812 #if BX_WITH_WIN32
813 if (!strcmp(gui_name, "win32"))
814 PLUG_load_plugin (win32, PLUGTYPE_OPTIONAL);
815 #endif
816 #if BX_WITH_X11
817 if (!strcmp(gui_name, "x"))
818 PLUG_load_plugin (x, PLUGTYPE_OPTIONAL);
819 #endif
821 #if BX_GUI_SIGHANDLER
822 // set the flag for guis requiring a GUI sighandler.
823 // useful when guis are compiled as plugins
824 // only term for now
825 if (!strcmp(gui_name, "term")) {
826 bx_gui_sighandler = 1;
828 #endif
830 BX_ASSERT(bx_gui != NULL);
831 return true;
834 int bx_begin_simulation (int argc, char *argv[])
836 SIM->init_save_restore();
837 if (SIM->get_param_bool(BXPN_RESTORE_FLAG)->get()) {
838 if (!SIM->restore_config()) {
839 BX_PANIC(("cannot restore configuration"));
840 SIM->get_param_bool(BXPN_RESTORE_FLAG)->set(0);
844 // deal with gui selection
845 if (!load_and_init_display_lib ()) {
846 BX_PANIC (("no gui module was loaded"));
847 return 0;
850 bx_cpu_count = SIM->get_param_num(BXPN_CPU_NPROCESSORS)->get() *
851 SIM->get_param_num(BXPN_CPU_NCORES)->get() *
852 SIM->get_param_num(BXPN_CPU_NTHREADS)->get();
854 BX_ASSERT(bx_cpu_count <= BX_MAX_SMP_THREADS_SUPPORTED);
855 BX_ASSERT(bx_cpu_count > 0);
857 bx_init_hardware();
859 if (SIM->get_param_enum(BXPN_LOAD32BITOS_WHICH)->get()) {
860 void bx_load32bitOSimagehack(void);
861 bx_load32bitOSimagehack();
864 SIM->set_init_done(1);
866 // update headerbar buttons since drive status can change during init
867 bx_gui->update_drive_status_buttons();
869 // iniialize statusbar and set all items inactive
870 if (!SIM->get_param_bool(BXPN_RESTORE_FLAG)->get())
872 bx_gui->statusbar_setitem(-1, 0);
875 // The set handler for mouse_enabled does not actually update the gui
876 // until init_done is set. This forces the set handler to be called,
877 // which sets up the mouse enabled GUI-specific stuff correctly.
878 // Not a great solution but it works. BBD
879 SIM->get_param_bool(BXPN_MOUSE_ENABLED)->set(SIM->get_param_bool(BXPN_MOUSE_ENABLED)->get());
881 #if BX_DEBUGGER
882 // If using the debugger, it will take control and call
883 // bx_init_hardware() and cpu_loop()
884 bx_dbg_main();
885 #else
886 #if BX_GDBSTUB
887 // If using gdbstub, it will take control and call
888 // bx_init_hardware() and cpu_loop()
889 if (bx_dbg.gdbstub_enabled) bx_gdbstub_init();
890 else
891 #endif
893 if (BX_SMP_PROCESSORS == 1) {
894 // only one processor, run as fast as possible by not messing with
895 // quantums and loops.
896 while (1) {
897 BX_CPU(0)->cpu_loop(0);
898 if (bx_pc_system.kill_bochs_request)
899 break;
901 // for one processor, the only reason for cpu_loop to return is
902 // that kill_bochs_request was set by the GUI interface.
904 else {
905 // SMP simulation: do a few instructions on each processor, then switch
906 // to another. Increasing quantum speeds up overall performance, but
907 // reduces granularity of synchronization between processors.
908 int processor = 0;
909 int quantum = SIM->get_param_num(BXPN_SMP_QUANTUM)->get();
910 while (1) {
911 // do some instructions in each processor
912 BX_CPU(processor)->cpu_loop(quantum);
913 processor = (processor+1) % BX_SMP_PROCESSORS;
914 if (bx_pc_system.kill_bochs_request)
915 break;
916 if (processor == 0)
917 BX_TICKN(quantum);
921 #endif /* BX_DEBUGGER == 0 */
922 BX_INFO(("cpu loop quit, shutting down simulator"));
923 bx_atexit();
924 return(0);
927 void bx_stop_simulation()
929 // in wxWidgets, the whole simulator is running in a separate thread.
930 // our only job is to end the thread as soon as possible, NOT to shut
931 // down the whole application with an exit.
932 BX_CPU(0)->async_event = 1;
933 bx_pc_system.kill_bochs_request = 1;
934 // the cpu loop will exit very soon after this condition is set.
937 void bx_sr_after_restore_state(void)
939 #if BX_SUPPORT_SMP == 0
940 BX_CPU(0)->after_restore_state();
941 #else
942 for (unsigned i=0; i<BX_SMP_PROCESSORS; i++) {
943 BX_CPU(i)->after_restore_state();
945 #endif
946 DEV_after_restore_state();
949 void bx_init_hardware()
951 // all configuration has been read, now initialize everything.
953 if (SIM->get_param_enum(BXPN_BOCHS_START)->get()==BX_QUICK_START) {
954 for (int level=0; level<N_LOGLEV; level++) {
955 int action = SIM->get_default_log_action(level);
956 io->set_log_action(level, action);
960 bx_pc_system.initialize(SIM->get_param_num(BXPN_IPS)->get());
962 if (SIM->get_param_string(BXPN_LOG_FILENAME)->getptr()[0]!='-') {
963 BX_INFO (("using log file %s", SIM->get_param_string(BXPN_LOG_FILENAME)->getptr()));
964 io->init_log(SIM->get_param_string(BXPN_LOG_FILENAME)->getptr());
967 io->set_log_prefix(SIM->get_param_string(BXPN_LOG_PREFIX)->getptr());
969 // Output to the log file the cpu and device settings
970 // This will by handy for bug reports
971 BX_INFO(("Bochs x86 Emulator %s", VER_STRING));
972 BX_INFO((" %s", REL_STRING));
973 BX_INFO(("System configuration"));
974 BX_INFO((" processors: %d (cores=%u, HT threads=%u)", BX_SMP_PROCESSORS,
975 SIM->get_param_num(BXPN_CPU_NCORES)->get(), SIM->get_param_num(BXPN_CPU_NTHREADS)->get()));
976 BX_INFO((" A20 line support: %s",BX_SUPPORT_A20?"yes":"no"));
977 BX_INFO((" APIC support: %s",BX_SUPPORT_APIC?"yes":"no"));
978 BX_INFO(("CPU configuration"));
979 BX_INFO((" level: %d",BX_CPU_LEVEL));
980 BX_INFO((" TLB enabled: %s",BX_USE_TLB?"yes":"no"));
981 #if BX_SUPPORT_SMP
982 BX_INFO((" SMP support: yes, quantum=%d", SIM->get_param_num(BXPN_SMP_QUANTUM)->get()));
983 #else
984 BX_INFO((" SMP support: no"));
985 #endif
986 BX_INFO((" FPU support: %s",BX_SUPPORT_FPU?"yes":"no"));
987 BX_INFO((" MMX support: %s",BX_SUPPORT_MMX?"yes":"no"));
988 if (BX_SUPPORT_SSE == 0)
989 BX_INFO((" SSE support: no"));
990 else
991 BX_INFO((" SSE support: %d",BX_SUPPORT_SSE));
992 BX_INFO((" CLFLUSH support: %s",BX_SUPPORT_CLFLUSH?"yes":"no"));
993 BX_INFO((" v8086 mode support: %s",BX_SUPPORT_V8086_MODE?"yes":"no"));
994 BX_INFO((" VME support: %s",BX_SUPPORT_VME?"yes":"no"));
995 BX_INFO((" 3dnow! support: %s",BX_SUPPORT_3DNOW?"yes":"no"));
996 BX_INFO((" PAE support: %s",BX_SUPPORT_PAE?"yes":"no"));
997 BX_INFO((" PGE support: %s",BX_SUPPORT_GLOBAL_PAGES?"yes":"no"));
998 BX_INFO((" PSE support: %s",BX_SUPPORT_LARGE_PAGES?"yes":"no"));
999 BX_INFO((" x86-64 support: %s",BX_SUPPORT_X86_64?"yes":"no"));
1000 BX_INFO((" SEP support: %s",BX_SUPPORT_SEP?"yes":"no"));
1001 BX_INFO((" MWAIT support: %s",BX_SUPPORT_MONITOR_MWAIT?"yes":"no"));
1002 BX_INFO(("Optimization configuration"));
1003 BX_INFO((" Guest2HostTLB support: %s",BX_SupportGuest2HostTLB?"yes":"no"));
1004 BX_INFO((" RepeatSpeedups support: %s",BX_SupportRepeatSpeedups?"yes":"no"));
1005 BX_INFO((" Icache support: %s",BX_SUPPORT_ICACHE?"yes":"no"));
1006 BX_INFO((" Fast function calls: %s",BX_FAST_FUNC_CALL?"yes":"no"));
1007 BX_INFO(("Devices configuration"));
1008 BX_INFO((" ACPI support: %s",BX_SUPPORT_ACPI?"yes":"no"));
1009 BX_INFO((" NE2000 support: %s",BX_SUPPORT_NE2K?"yes":"no"));
1010 BX_INFO((" PCI support: %s",BX_SUPPORT_PCI?"yes":"no"));
1011 BX_INFO((" SB16 support: %s",BX_SUPPORT_SB16?"yes":"no"));
1012 BX_INFO((" USB support: %s",BX_SUPPORT_PCIUSB?"yes":"no"));
1013 BX_INFO((" VGA extension support: %s %s",BX_SUPPORT_VBE?"vbe":"",
1014 BX_SUPPORT_CLGD54XX?"cirrus":""));
1016 // Check if there is a romimage
1017 if (strcmp(SIM->get_param_string(BXPN_ROM_PATH)->getptr(),"") == 0) {
1018 BX_ERROR(("No romimage to load. Is your bochsrc file loaded/valid ?"));
1021 // set one shot timer for benchmark mode if needed, the timer will fire
1022 // once and kill Bochs simulation after predefined amount of emulated
1023 // ticks
1024 int benchmark_mode = SIM->get_param_num(BXPN_BOCHS_BENCHMARK)->get();
1025 if (benchmark_mode) {
1026 BX_INFO(("Bochs benchmark mode is ON (~%d millions of ticks)", benchmark_mode));
1027 bx_pc_system.register_timer_ticks(&bx_pc_system, bx_pc_system_c::benchmarkTimer,
1028 (Bit64u) benchmark_mode * 1000000, 0, 1, "benchmark.timer");
1031 // set up memory and CPU objects
1032 bx_param_num_c *bxp_memsize = SIM->get_param_num(BXPN_MEM_SIZE);
1033 Bit32u memSize = bxp_memsize->get() * 1024*1024;
1035 #if BX_SUPPORT_ICACHE
1036 pageWriteStampTable.alloc(memSize);
1037 #endif
1039 BX_MEM(0)->init_memory(memSize);
1041 // First load the BIOS and VGABIOS
1042 BX_MEM(0)->load_ROM(SIM->get_param_string(BXPN_ROM_PATH)->getptr(),
1043 SIM->get_param_num(BXPN_ROM_ADDRESS)->get(), 0);
1044 BX_MEM(0)->load_ROM(SIM->get_param_string(BXPN_VGA_ROM_PATH)->getptr(), 0xc0000, 1);
1046 // Then load the optional ROM images
1047 if (strcmp(SIM->get_param_string(BXPN_OPTROM1_PATH)->getptr(), "") !=0)
1048 BX_MEM(0)->load_ROM(SIM->get_param_string(BXPN_OPTROM1_PATH)->getptr(), SIM->get_param_num(BXPN_OPTROM1_ADDRESS)->get(), 2);
1049 if (strcmp(SIM->get_param_string(BXPN_OPTROM2_PATH)->getptr(), "") !=0)
1050 BX_MEM(0)->load_ROM(SIM->get_param_string(BXPN_OPTROM2_PATH)->getptr(), SIM->get_param_num(BXPN_OPTROM2_ADDRESS)->get(), 2);
1051 if (strcmp(SIM->get_param_string(BXPN_OPTROM3_PATH)->getptr(), "") !=0)
1052 BX_MEM(0)->load_ROM(SIM->get_param_string(BXPN_OPTROM3_PATH)->getptr(), SIM->get_param_num(BXPN_OPTROM3_ADDRESS)->get(), 2);
1053 if (strcmp(SIM->get_param_string(BXPN_OPTROM4_PATH)->getptr(), "") !=0)
1054 BX_MEM(0)->load_ROM(SIM->get_param_string(BXPN_OPTROM4_PATH)->getptr(), SIM->get_param_num(BXPN_OPTROM4_ADDRESS)->get(), 2);
1056 // Then load the optional RAM images
1057 if (strcmp(SIM->get_param_string(BXPN_OPTRAM1_PATH)->getptr(), "") !=0)
1058 BX_MEM(0)->load_RAM(SIM->get_param_string(BXPN_OPTRAM1_PATH)->getptr(), SIM->get_param_num(BXPN_OPTRAM1_ADDRESS)->get(), 2);
1059 if (strcmp(SIM->get_param_string(BXPN_OPTRAM2_PATH)->getptr(), "") !=0)
1060 BX_MEM(0)->load_RAM(SIM->get_param_string(BXPN_OPTRAM2_PATH)->getptr(), SIM->get_param_num(BXPN_OPTRAM2_ADDRESS)->get(), 2);
1061 if (strcmp(SIM->get_param_string(BXPN_OPTRAM3_PATH)->getptr(), "") !=0)
1062 BX_MEM(0)->load_RAM(SIM->get_param_string(BXPN_OPTRAM3_PATH)->getptr(), SIM->get_param_num(BXPN_OPTRAM3_ADDRESS)->get(), 2);
1063 if (strcmp(SIM->get_param_string(BXPN_OPTRAM4_PATH)->getptr(), "") !=0)
1064 BX_MEM(0)->load_RAM(SIM->get_param_string(BXPN_OPTRAM4_PATH)->getptr(), SIM->get_param_num(BXPN_OPTRAM4_ADDRESS)->get(), 2);
1066 #if BX_SUPPORT_SMP == 0
1067 BX_CPU(0)->initialize(BX_MEM(0));
1068 BX_CPU(0)->sanity_checks();
1069 BX_CPU(0)->register_state();
1070 BX_INSTR_INIT(0);
1071 #else
1072 bx_cpu_array = new BX_CPU_C_PTR[BX_SMP_PROCESSORS];
1074 for (unsigned i=0; i<BX_SMP_PROCESSORS; i++) {
1075 BX_CPU(i) = new BX_CPU_C(i);
1076 BX_CPU(i)->initialize(BX_MEM(0)); // assign local apic id in 'initialize' method
1077 BX_CPU(i)->sanity_checks();
1078 BX_CPU(i)->register_state();
1079 BX_INSTR_INIT(i);
1081 #endif
1083 DEV_init_devices();
1084 bx_pc_system.register_state();
1085 DEV_register_state();
1086 if (SIM->get_param_bool(BXPN_RESTORE_FLAG)->get()) {
1087 if (!SIM->restore_logopts()) {
1088 BX_PANIC(("cannot restore log options"));
1089 SIM->get_param_bool(BXPN_RESTORE_FLAG)->set(0);
1093 // will enable A20 line and reset CPU and devices
1094 bx_pc_system.Reset(BX_RESET_HARDWARE);
1096 if (SIM->get_param_bool(BXPN_RESTORE_FLAG)->get()) {
1097 if (SIM->restore_hardware()) {
1098 bx_sr_after_restore_state();
1099 } else {
1100 BX_PANIC(("cannot restore hardware state"));
1101 SIM->get_param_bool(BXPN_RESTORE_FLAG)->set(0);
1105 bx_gui->init_signal_handlers();
1106 bx_pc_system.start_timers();
1108 BX_DEBUG(("bx_init_hardware is setting signal handlers"));
1109 // if not using debugger, then we can take control of SIGINT.
1110 #if !BX_DEBUGGER
1111 signal(SIGINT, bx_signal_handler);
1112 #endif
1114 #if BX_SHOW_IPS
1115 #if !defined(__MINGW32__) && !defined(_MSC_VER)
1116 signal(SIGALRM, bx_signal_handler);
1117 #endif
1118 alarm( 1 );
1119 #endif
1122 void bx_init_bx_dbg(void)
1124 #if BX_DEBUGGER
1125 bx_dbg_init_infile();
1126 #endif
1127 bx_dbg.floppy = 0;
1128 bx_dbg.keyboard = 0;
1129 bx_dbg.video = 0;
1130 bx_dbg.disk = 0;
1131 bx_dbg.pit = 0;
1132 bx_dbg.pic = 0;
1133 bx_dbg.bios = 0;
1134 bx_dbg.cmos = 0;
1135 bx_dbg.a20 = 0;
1136 bx_dbg.interrupts = 0;
1137 bx_dbg.exceptions = 0;
1138 bx_dbg.unsupported = 0;
1139 bx_dbg.temp = 0;
1140 bx_dbg.reset = 0;
1141 bx_dbg.mouse = 0;
1142 bx_dbg.io = 0;
1143 bx_dbg.debugger = 0;
1144 bx_dbg.xms = 0;
1145 bx_dbg.v8086 = 0;
1146 bx_dbg.paging = 0;
1147 bx_dbg.creg = 0;
1148 bx_dbg.dreg = 0;
1149 bx_dbg.dma = 0;
1150 bx_dbg.unsupported_io = 0;
1151 bx_dbg.record_io = 0;
1152 bx_dbg.serial = 0;
1153 bx_dbg.cdrom = 0;
1154 #if BX_MAGIC_BREAKPOINT
1155 bx_dbg.magic_break_enabled = 0;
1156 #endif
1157 #if BX_GDBSTUB
1158 bx_dbg.gdbstub_enabled = 0;
1159 #endif
1162 int bx_atexit(void)
1164 if (!SIM->get_init_done()) return 1; // protect from reentry
1166 // in case we ended up in simulation mode, change back to config mode
1167 // so that the user can see any messages left behind on the console.
1168 SIM->set_display_mode(DISP_MODE_CONFIG);
1170 #if BX_DEBUGGER == 0
1171 if (SIM && SIM->get_init_done()) {
1172 for (int cpu=0; cpu<BX_SMP_PROCESSORS; cpu++)
1173 #if BX_SUPPORT_SMP
1174 if (BX_CPU(cpu))
1175 #endif
1176 BX_CPU(cpu)->atexit();
1178 #endif
1180 BX_MEM(0)->cleanup_memory();
1182 #if BX_PROVIDE_DEVICE_MODELS==1
1183 bx_pc_system.exit();
1184 #endif
1186 // restore signal handling to defaults
1187 #if !BX_DEBUGGER
1188 BX_INFO(("restoring default signal behavior"));
1189 signal(SIGINT, SIG_DFL);
1190 #endif
1192 #if BX_SHOW_IPS
1193 #ifndef __MINGW32__
1194 signal(SIGALRM, SIG_DFL);
1195 #endif
1196 #endif
1198 SIM->set_init_done(0);
1200 return 0;
1203 void bx_signal_handler(int signum)
1205 // in a multithreaded environment, a signal such as SIGINT can be sent to all
1206 // threads. This function is only intended to handle signals in the
1207 // simulator thread. It will simply return if called from any other thread.
1208 // Otherwise the BX_PANIC() below can be called in multiple threads at
1209 // once, leading to multiple threads trying to display a dialog box,
1210 // leading to GUI deadlock.
1211 if (!SIM->is_sim_thread()) {
1212 BX_INFO (("bx_signal_handler: ignored sig %d because it wasn't called from the simulator thread", signum));
1213 return;
1215 #if BX_GUI_SIGHANDLER
1216 if (bx_gui_sighandler) {
1217 // GUI signal handler gets first priority, if the mask says it's wanted
1218 if ((1<<signum) & bx_gui->get_sighandler_mask()) {
1219 bx_gui->sighandler(signum);
1220 return;
1223 #endif
1225 #if BX_SHOW_IPS
1226 static Bit64u ticks_count = 0;
1228 if (signum == SIGALRM)
1230 // amount of system ticks passed from last time the handler was called
1231 Bit64u ips_count = bx_pc_system.time_ticks() - ticks_count;
1232 if (ips_count) {
1233 bx_gui->show_ips((Bit32u) ips_count);
1234 ticks_count = bx_pc_system.time_ticks();
1236 #if !defined(__MINGW32__) && !defined(_MSC_VER)
1237 signal(SIGALRM, bx_signal_handler);
1238 alarm( 1 );
1239 #endif
1240 return;
1242 #endif
1244 #if BX_GUI_SIGHANDLER
1245 if (bx_gui_sighandler) {
1246 if ((1<<signum) & bx_gui->get_sighandler_mask ()) {
1247 bx_gui->sighandler(signum);
1248 return;
1251 #endif
1253 BX_PANIC(("SIGNAL %u caught", signum));