/* * Main program for Un*x-hosted v9t9. * */ #include #include #include #include #include #include #include "v9t9_common.h" #include "system.h" #include "timer.h" #include "v9t9.h" #include "command_rl.h" #include "debugger.h" #include "moduleconfig.h" #include "v9t9_module.h" #include #include "gtkloop.h" #include "gtkinterface.h" #include "unixmain.h" #define _L LOG_INTERNAL | LOG_INFO static int unix_v9t9_initialized; int console_fd; int gdb_debugging = 0; static void system_initlog(void); static void system_termlog(void); int (*frontend_loop)(void) = 0L; void (*frontend_getcommands)(void); void (*frontend_log)(u32 srcflags, const char *text) = 0L; void (*frontend_report_status)(status_item item, va_list va) = 0L; void (*frontend_debugger_enabled)(bool enabled) = 0L; void (*frontend_execution_paused)(bool paused) = 0L; static void sigsegv(int x) { //v9t9_restop(); if (linuxKeyboard.runtimeflags & vmRTInUse) linuxKeyboard.restop(); if (!gdb_debugging) { signal(SIGSEGV, SIG_DFL); logger(_L | LOG_FATAL, "SIGSEGV caught.\n"); exit(23); } else { signal(SIGSEGV, SIG_DFL); *(char *) 0 = 0; } } #if defined(LINUX_SVGA_KEYBOARD) && defined(LINUX_SVGA_VIDEO) #define HAS_SVGA 1 #endif #if defined(X_WIN_KEYBOARD) && defined(X_WIN_VIDEO) #define HAS_XLIB 1 #endif #if defined(GTK_KEYBOARD) && defined(GTK_VIDEO) #define HAS_GTK 1 #endif int main(int argc, char **argv) { enum { FE_UNKNOWN, #if HAS_SVGA FE_SVGA, #endif #if HAS_XLIB FE_XLIB, #endif #if HAS_GTK FE_GTK, #endif } frontend = FE_UNKNOWN; Display *display; int ret; int status; v9t9_config(argc, argv); unix_v9t9_initialized = 0; system_initlog(); initlog(); console_fd = open("/dev/console", O_RDWR); // sound_fd = open("/dev/dsp", O_RDWR); if (argc > 1 && strcmp(argv[1], "--debug") == 0) { gdb_debugging = 1; argc--; argv++; } if (!gdb_debugging) signal(SIGSEGV, sigsegv); else signal(SIGSEGV, SIG_DFL); #ifdef LINUX_SVGA_VIDEO if (argc > 1 && strcmp(argv[1], "--no-video") == 0) { svgaVideo.runtimeflags |= vmRTUnselected; argc--; argv++; } #endif #ifdef LINUX_SVGA_KEYBOARD if (argc > 1 && strcmp(argv[1], "--no-kbd") == 0) { linuxKeyboard.runtimeflags |= vmRTUnselected; argc--; argv++; } #endif /* Look for explicit choice of frontend */ if (argc > 2 && strcmp(argv[1], "-fe") == 0) { #if HAS_SVGA if (strcasecmp(argv[2], "svga") == 0) { frontend = FE_SVGA; argv += 2; argc -= 2; } else #endif #if HAS_XLIB if (strcasecmp(argv[2], "xlib") == 0) { frontend = FE_XLIB; argv += 2; argc -= 2; } else #endif #if HAS_GTK if (strcasecmp(argv[2], "gtk") == 0) { frontend = FE_GTK; svgaVideo.runtimeflags |= vmRTUnselected; linuxKeyboard.runtimeflags |= vmRTUnselected; argv += 2; argc -= 2; } else #endif { logger(_L|LOG_USER|LOG_ERROR, "Unknown option '%s %s';\n" "expected one of " #if HAS_SVGA "svga|" #endif #if HAS_XLIB "xlib|" #endif #if HAS_GTK "gtk" #endif "\n", argv[1], argv[2]); return 1; } } argv[0] = v9t9_argv[0]; v9t9_argv = argv; v9t9_argc = argc; #if HAS_GTK || HAS_XLIB /* Check for X connection before assuming GTK will work; it ABORTS if it can't open a connection. */ if ((display = XOpenDisplay(NULL)) == NULL) { if (frontend == FE_UNKNOWN #if HAS_GTK || frontend == FE_GTK #endif ) frontend = FE_SVGA; } else { XrmInitialize(); XCloseDisplay(display); } #endif #if HAS_GTK if ((frontend == FE_UNKNOWN || frontend == FE_GTK) && GTK_system_init()) { frontend = FE_GTK; frontend_log = GTK_system_log; frontend_getcommands = unix_system_getcommands; frontend_report_status = GTK_system_report_status; frontend_debugger_enabled = GTK_system_debugger_enabled; frontend_execution_paused = GTK_system_execution_paused; frontend_loop = GTK_system_loop; #if HAS_SVGA svgaVideo.runtimeflags |= vmRTUnselected; linuxKeyboard.runtimeflags |= vmRTUnselected; #endif #if HAS_XLIB X_Video.runtimeflags |= vmRTUnselected; X_Keyboard.runtimeflags |= vmRTUnselected; #endif logger(_L|LOG_USER, "Using GTK\n"); v9t9_window = create_v9t9_window(); v9t9_drawing_area = gtk_object_get_data(GTK_OBJECT(v9t9_window), "v9t9_drawing_area"); gtk_widget_show(v9t9_window); } else #endif #if HAS_XLIB if ((frontend == FE_UNKNOWN || frontend == FE_XLIB) && xlib_system_init()) { frontend = FE_XLIB; frontend_log = unix_system_log; frontend_getcommands = unix_system_getcommands; frontend_report_status = unix_system_report_status; frontend_loop = xlib_system_loop; frontend_debugger_enabled = unix_system_debugger_enabled; frontend_execution_paused = unix_system_execution_paused; #if HAS_SVGA svgaVideo.runtimeflags |= vmRTUnselected; linuxKeyboard.runtimeflags |= vmRTUnselected; #endif #if HAS_GTK gtkVideo.runtimeflags |= vmRTUnselected; gtkKeyboard.runtimeflags |= vmRTUnselected; #endif logger(_L|LOG_USER, "Using Xlib\n"); } else #endif #if HAS_SVGA if ((frontend == FE_UNKNOWN || frontend == FE_SVGA) && svga_system_init()) { frontend = FE_SVGA; frontend_log = unix_system_log; frontend_getcommands = unix_system_getcommands; frontend_report_status = unix_system_report_status; frontend_loop = svga_system_loop; frontend_debugger_enabled = unix_system_debugger_enabled; frontend_execution_paused = unix_system_execution_paused; #if HAS_XLIB X_Video.runtimeflags |= vmRTUnselected; X_Keyboard.runtimeflags |= vmRTUnselected; #endif #if HAS_GTK gtkVideo.runtimeflags |= vmRTUnselected; gtkKeyboard.runtimeflags |= vmRTUnselected; #endif logger(_L|LOG_USER, "Using SVGAlib\n"); } else #endif { logger(_L|LOG_FATAL, "Could not find a frontend\n"); return 2; } if (!v9t9_init()) return 3; if (!v9t9_restart()) return 4; signal(SIGINT, v9t9_sigint); signal(SIGTERM, v9t9_sigterm); unix_v9t9_initialized = 1; ret = frontend_loop(); v9t9_restop(); v9t9_term(ret); termlog(); system_termlog(); wait(&status); exit(ret); } void unix_system_pause(void) { /* Recommended way from glibc info pages for waiting until a certain signal arrives. */ sigset_t mask, oldmask; sigemptyset(&mask); sigaddset(&mask, SIGINT); sigprocmask(SIG_BLOCK, &mask, &oldmask); sigsuspend(&oldmask); sigprocmask(SIG_UNBLOCK, &mask, NULL); } void system_getcommands(void) { if (frontend_getcommands) frontend_getcommands(); else unix_system_getcommands(); } void unix_system_getcommands(void) { FILE *cmdsin = fopen("/dev/tty", "r"); FILE *cmdsout = fopen("/dev/tty", "w"); logger(_L|LOG_INFO, "Entering interactive mode\n"); if (cmdsin == NULL || cmdsout == NULL || feof(cmdsin)) { logger(_L|LOG_ERROR, "FAILED: could not open terminal\n"); return; } // this leaves sound and timer going! // if (X_Video.runtimeflags & vmRTInUse) // MODULE_ITERATE(vmKeyboard, vmRestopModule); // else v9t9_restop(); // system_task(); // eat up X events readline_getcommands(cmdsin, cmdsout); // this leaves sound and timer going! // if (X_Video.runtimeflags & vmRTInUse) // MODULE_ITERATE(vmKeyboard, vmRestartModule); // else v9t9_restart(); } static struct itimerval my_timer; unsigned int TM_Ticked; static void unix_system_timer_handler(int unused) { TM_Ticked++; if (TM_Ticked > 10) TM_Ticked = 10; if (!(stateflag & ST_PAUSE)) stateflag |= ST_STOP; } void system_timer_init(void) { TM_Ticked = 0; } void system_timer_install(void) { struct sigaction s; // s.sa_handler = TM_TickHandler; s.sa_handler = unix_system_timer_handler; sigemptyset(&s.sa_mask); s.sa_flags = SA_RESTART; s.sa_restorer = NULL; sigaction(SIGALRM, &s, NULL); my_timer.it_value.tv_sec = 0; my_timer.it_value.tv_usec = 1000000 / TM_HZ; /* Hz */ my_timer.it_interval.tv_sec = 0; my_timer.it_interval.tv_usec = 1000000 / TM_HZ; setitimer(ITIMER_REAL, &my_timer, NULL); } void system_timer_uninstall(void) { struct itimerval t; /* turn off and save current timer */ memset((void *) &t, 0, sizeof(t)); setitimer(ITIMER_REAL, &t, &my_timer); } // We emit text to both stdout and a logfile. static FILE *logfile; // to disk static FILE *loguser; // to tty static void system_initlog(void) { if ((logfile = fopen("log.unix.txt", "w")) == NULL) { fprintf(stderr, "Could not create log file\n"); exit(1); } if ((loguser = fopen("/dev/tty", "w")) == NULL) { fprintf(stderr, "Could not create user log file\n"); exit(1); } setbuf(logfile, NULL); setbuf(loguser, NULL); atexit(system_termlog); } static void system_termlog(void) { fclose(logfile); fclose(loguser); } void system_log(u32 srcflags, const char *text) { fwrite(text, 1, strlen(text), logfile); fflush(logfile); if (!unix_v9t9_initialized && (srcflags & LOG_TYPE_MASK) == LOG_ERROR) { fwrite(text, 1, strlen(text), stdout); fflush(stdout); } if (frontend_log) frontend_log(srcflags, text); } void unix_system_log(u32 srcflags, const char *text) { if (LOG_IS_VISIBLE(srcflags)) { const char *cptr = strchr(text, ':'); if (!cptr || (srcflags & LOG_SRC_MASK) == 0) cptr = text; else cptr += 2; if (*text == '\n' && cptr != text) fwrite("\n", 1, 1, loguser); fwrite(cptr, 1, strlen(cptr), loguser); fflush(loguser); } } #define ITEM_ON_CODE_LINE(item) \ ((item) >= STATUS_CPU_PC && \ (item) <= STATUS_CPU_INSTRUCTION_LAST && \ (item) != STATUS_CPU_REGISTER_VIEW) void system_report_status(status_item item, va_list va) { char buffer[1024], *bptr = buffer+1; static bool last_item_on_code_line; bool item_on_code_line; report_status_text(item, va, bptr, sizeof(buffer)-1); if (*bptr) { item_on_code_line = ITEM_ON_CODE_LINE(item); if (last_item_on_code_line != item_on_code_line) { buffer[0] = '\n'; bptr--; } system_log(LOG_USER, bptr); last_item_on_code_line = item_on_code_line; } if (frontend_report_status) frontend_report_status(item, va); } void unix_system_report_status(status_item item, va_list va) { } void system_debugger_enabled(bool enabled) { if (frontend_debugger_enabled) frontend_debugger_enabled(enabled); } void unix_system_debugger_enabled(bool enabled) { } void system_execution_paused(bool paused) { if (frontend_execution_paused) frontend_execution_paused(paused); } void unix_system_execution_paused(bool paused) { logger(LOG_USER, "Execution is %s\n", paused ? "paused" : "resumed"); }