/* * (C) Copyright 1992, ..., 2007 the "DOSEMU-Development-Team". * * for details see file COPYING.DOSEMU in the DOSEMU distribution */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "emu.h" #include "vm86plus.h" #include "bios.h" #include "mouse.h" #include "video.h" #include "vgaemu.h" #include "vgatext.h" #include "timers.h" #include "int.h" #include "lowmem.h" #include "coopth.h" #include "dpmi.h" #include "pic.h" #include "ipx.h" #include "pktdrvr.h" #include "iodev.h" #include "serial.h" #include "debug.h" #include "utilities.h" #include "dosemu_config.h" #include "keyb_clients.h" #include "keyb_server.h" #ifdef USE_SBEMU #include "sound.h" #endif #include "cpu-emu.h" /* Variables for keeping track of signals */ #define MAX_SIG_QUEUE_SIZE 50 #define MAX_SIG_DATA_SIZE 128 static u_short SIGNAL_head=0; u_short SIGNAL_tail=0; struct SIGNAL_queue { void (*signal_handler)(void *); char arg[MAX_SIG_DATA_SIZE]; size_t arg_size; const char *name; }; static struct SIGNAL_queue signal_queue[MAX_SIG_QUEUE_SIZE]; #define MAX_SIGCHLD_HANDLERS 10 struct sigchld_hndl { pid_t pid; void (*handler)(void); int enabled; }; static struct sigchld_hndl chld_hndl[MAX_SIGCHLD_HANDLERS]; static int chd_hndl_num; static int sh_tid; static int in_handle_signals; static void handle_signals_force_enter(int tid); static void handle_signals_force_leave(int tid); static struct { unsigned long eflags; unsigned short fs, gs; #ifdef __x86_64__ unsigned char *fsbase, *gsbase; #define ARCH_SET_GS 0x1001 #define ARCH_SET_FS 0x1002 #define ARCH_GET_FS 0x1003 #define ARCH_GET_GS 0x1004 #endif } eflags_fs_gs; static void (*sighandlers[NSIG])(struct sigcontext *); static void sigquit(struct sigcontext *); static void sigalrm(struct sigcontext *); static void sigio(struct sigcontext *); static void sigasync(int sig, siginfo_t *si, void *uc); static void dosemu_sigaction_wrapper(int sig, void *fun, int flags) { struct sigaction sa; sigset_t mask; sa.sa_flags = flags; sigemptyset(&mask); addset_signals_that_queue(&mask); sa.sa_mask = mask; if (sa.sa_flags & SA_ONSTACK) { sa.sa_flags |= SA_SIGINFO; sa.sa_sigaction = fun; } else sa.sa_handler = fun; sigaction(sig, &sa, NULL); } /* DANG_BEGIN_FUNCTION NEWSETQSIG * * arguments: * sig - the signal to have a handler installed to. * fun - the signal handler function to install * * description: * All signals that wish to be handled properly in context with the * execution of vm86() mode, and signals that wish to use non-reentrant * functions should add themselves to the ADDSET_SIGNALS_THAT_QUEUE define * and use SETQSIG(). To that end they will also need to be set up in an * order such as SIGIO. * * DANG_END_FUNCTION * */ void addset_signals_that_queue(sigset_t *x) { sigaddset(x, SIGIO); sigaddset(x, SIGALRM); sigaddset(x, SIGPROF); sigaddset(x, SIGWINCH); sigaddset(x, SIG_RELEASE); sigaddset(x, SIG_ACQUIRE); } static void newsetqsig(int sig, void *fun) { dosemu_sigaction_wrapper(sig, fun, SA_RESTART|SA_ONSTACK); } void registersig(int sig, void (*fun)(struct sigcontext *)) { sighandlers[sig] = fun; } static void setsig(int sig, void *fun) { dosemu_sigaction_wrapper(sig, fun, SA_RESTART); } static void newsetsig(int sig, void *fun) { int flags = SA_RESTART|SA_ONSTACK; if (kernel_version_code >= 0x20600+14) flags |= SA_NODEFER; dosemu_sigaction_wrapper(sig, fun, flags); } #ifdef __x86_64__ static int dosemu_arch_prctl(int code, void *addr) { return syscall(SYS_arch_prctl, code, addr); } /* Check if fs or gs point to the base without always needing a syscall (12 vs. 800 CPU cycles last time I measured). The DPMI client code may have changed fs/gs and then restored it to 0, and that way the long base is gone (its base is still equal to the fs/gs base used by the DPMI client; 64bit code doesn't trap NULL selector references). There is a very small chance that the mov from %fs:0 page faults. In that case we fix it up in dosemu_fault0->check_fix_fs_gs_base. */ #define getfs0(byte) asm volatile ("movb %%fs:0, %0" : "=r"(byte)) #define getgs0(byte) asm volatile ("movb %%gs:0, %0" : "=r"(byte)) #define fix_fs_gs_base(seg,SEG) \ static void fix_##seg##base(void) \ { \ unsigned char segbyte, basebyte; \ \ /* always fix fsbase/gsbase the DPMI client changed fs or gs */ \ if (getsegment(seg) == eflags_fs_gs.seg) { \ volatile unsigned char *base = eflags_fs_gs.seg##base; \ \ /* if the two locations have different bytes they must be different */ \ get##seg##0(segbyte); \ basebyte = *base; \ if (segbyte == basebyte) { \ \ /* else we must modify one to make sure it's ok */ \ *base = basebyte + 1; \ get##seg##0(segbyte); \ *base = basebyte; \ if (segbyte != basebyte) \ return; \ } \ } \ dosemu_arch_prctl(ARCH_SET_##SEG, eflags_fs_gs.fsbase); \ D_printf("DPMI: Set " #seg "base in signal handler\n"); \ } fix_fs_gs_base(fs,FS); fix_fs_gs_base(gs,GS); /* this function is called from dosemu_fault0 to check if fsbase/gsbase need to be fixed up, if the above asm codes cause a page fault. */ int check_fix_fs_gs_base(unsigned char prefix) { unsigned char *addr, *base; int getcode, setcode; if (prefix == 0x65) { /* gs: */ getcode = ARCH_GET_GS; setcode = ARCH_SET_GS; base = eflags_fs_gs.gsbase; } else { getcode = ARCH_GET_FS; setcode = ARCH_SET_FS; base = eflags_fs_gs.fsbase; } if (dosemu_arch_prctl(getcode, &addr) != 0) return 0; /* already fine, not fixing it up, but then the dosemu fault is fatal */ if (addr == base) return 0; dosemu_arch_prctl(setcode, base); D_printf("DPMI: Fixed up %csbase in fault handler\n", prefix + 2); return 1; } #endif /* init_handler puts the handler in a sane state that glibc expects. That means restoring fs and gs for vm86 (necessary for 2.4 kernels) and fs, gs and eflags for DPMI. */ __attribute__((no_instrument_function)) void init_handler(struct sigcontext_struct *scp) { /* * FIRST thing to do in signal handlers - to avoid being trapped into int0x11 * forever, we must restore the eflags. */ loadflags(eflags_fs_gs.eflags); #ifdef __x86_64__ /* ds,es, and ss are ignored in 64-bit mode and not present or saved in the sigcontext, so we need to do it ourselves (using the 3 high words of the trapno field). fs and gs are set to 0 in the sigcontext, so we also need to save those ourselves */ if (scp) { _ds = getsegment(ds); _es = getsegment(es); _ss = getsegment(ss); _fs = getsegment(fs); _gs = getsegment(gs); if (config.cpuemu > 3) { _cs = getsegment(cs); } else if (_cs == 0) { if (config.dpmi) { fprintf(stderr, "Cannot run DPMI code natively "); if (kernel_version_code < 0x20600 + 15) fprintf(stderr, "because your Linux kernel is older than version 2.6.15.\n"); else fprintf(stderr, "for unknown reasons.\nPlease contact linux-msdos@vger.kernel.org.\n"); fprintf(stderr, "Set $_cpu_emu=\"full\" or \"fullsim\" to avoid this message.\n"); } config.cpuemu = 4; _cs = getsegment(cs); } } #endif if (in_vm86) { #ifdef __i386__ #ifdef X86_EMULATOR if (!config.cpuemu) #endif { if (getsegment(fs) != eflags_fs_gs.fs) loadregister(fs, eflags_fs_gs.fs); if (getsegment(gs) != eflags_fs_gs.gs) loadregister(gs, eflags_fs_gs.gs); } #endif return; } if (scp && !DPMIValidSelector(_cs)) return; /* else interrupting DPMI code with an LDT %cs */ /* restore %fs and %gs for compatibility with NPTL. */ #ifdef __x86_64__ if (eflags_fs_gs.fsbase) if (mem_base) /* too many faults in fix_fsbase() with the 0-page unmapped... */ dosemu_arch_prctl(ARCH_SET_FS, eflags_fs_gs.fsbase); else fix_fsbase(); else #endif if (getsegment(fs) != eflags_fs_gs.fs) loadregister(fs, eflags_fs_gs.fs); #ifdef __x86_64__ if (eflags_fs_gs.gsbase) if (mem_base) dosemu_arch_prctl(ARCH_SET_GS, eflags_fs_gs.gsbase); else fix_gsbase(); else #endif if (getsegment(gs) != eflags_fs_gs.gs) loadregister(gs, eflags_fs_gs.gs); } static int ld_sig; static void leavedos_call(void *arg) { int *sig = arg; leavedos(*sig); } int sigchld_register_handler(pid_t pid, void (*handler)(void)) { assert(chd_hndl_num < MAX_SIGCHLD_HANDLERS); chld_hndl[chd_hndl_num].handler = handler; chld_hndl[chd_hndl_num].pid = pid; chld_hndl[chd_hndl_num].enabled = 1; chd_hndl_num++; return 0; } int sigchld_enable_handler(pid_t pid, int on) { int i; for (i = 0; i < chd_hndl_num; i++) { if (chld_hndl[i].pid == pid) break; } if (i >= chd_hndl_num) return -1; chld_hndl[i].enabled = on; return 0; } static void cleanup_child(void *arg) { int i, status; pid_t pid2, pid = *(pid_t *)arg; for (i = 0; i < chd_hndl_num; i++) { if (chld_hndl[i].pid == pid) break; } if (i >= chd_hndl_num) return; if (!chld_hndl[i].enabled) return; pid2 = waitpid(pid, &status, WNOHANG); if (pid2 != pid) return; chld_hndl[i].handler(); } /* this cleaning up is necessary to avoid the port server becoming a zombie process */ __attribute__((no_instrument_function)) static void sig_child(int sig, siginfo_t *si, void *uc) { struct sigcontext_struct *scp = (struct sigcontext_struct *)&((ucontext_t *)uc)->uc_mcontext; init_handler(scp); SIGNAL_save(cleanup_child, &si->si_pid, sizeof(si->si_pid), __func__); } __attribute__((no_instrument_function)) static void leavedos_signal(int sig) { init_handler(NULL); if (ld_sig) { error("gracefull exit failed, aborting (sig=%i)\n", sig); _exit(sig); } dbug_printf("Terminating on signal %i\n", sig); ld_sig = sig; SIGNAL_save(leavedos_call, &sig, sizeof(sig), __func__); /* abort current sighandlers */ if (in_handle_signals) { g_printf("Interrupting active signal handlers\n"); in_handle_signals = 0; } } /* Silly Interrupt Generator Initialization/Closedown */ #ifdef SIG SillyG_t *SillyG = 0; static SillyG_t SillyG_[16 + 1]; #endif /* * DANG_BEGIN_FUNCTION SIG_init * * description: Allow DOSEMU to be made aware when a hard interrupt occurs * The IRQ numbers to monitor are taken from config.sillyint, each bit * corresponding to one IRQ. The higher 16 bit are defining the use of * SIGIO * * DANG_END_FUNCTION */ void SIG_init(void) { #if defined(SIG) PRIV_SAVE_AREA /* Get in touch with Silly Interrupt Handling */ if (config.sillyint) { char prio_table[] = {8, 9, 10, 11, 12, 14, 15, 3, 4, 5, 6, 7}; int i, irq; SillyG_t *sg = SillyG_; for (i = 0; i < sizeof(prio_table); i++) { irq = prio_table[i]; if (config.sillyint & (1 << irq)) { int ret; enter_priv_on(); ret = vm86_plus(VM86_REQUEST_IRQ, (SIGIO << 8) | irq); leave_priv_setting(); if ( ret > 0) { g_printf("Gonna monitor the IRQ %d you requested\n", irq); sg->fd = -1; sg->irq = irq; g_printf("SIG: IRQ%d, enabling PIC-level %ld\n", irq, pic_irq_list[irq]); sg++; } } } sg->fd = 0; if (sg != SillyG_) SillyG = SillyG_; } #endif } void SIG_close(void) { #if defined(SIG) if (SillyG) { SillyG_t *sg = SillyG; while (sg->fd) { vm86_plus(VM86_FREE_IRQ, sg->irq); sg++; } g_printf("Closing all IRQ you opened!\n"); } #endif } void sig_ctx_prepare(int tid) { rm_stack_enter(); clear_IF(); } void sig_ctx_restore(int tid) { rm_stack_leave(); } static void signal_thr_post(int tid) { in_handle_signals--; } static void signal_thr(void *arg) { struct SIGNAL_queue *sig = &signal_queue[SIGNAL_head]; struct SIGNAL_queue sig_c; // local copy for signal-safety sig_c.signal_handler = signal_queue[SIGNAL_head].signal_handler; sig_c.arg_size = sig->arg_size; if (sig->arg_size) memcpy(sig_c.arg, sig->arg, sig->arg_size); sig_c.name = sig->name; SIGNAL_head = (SIGNAL_head + 1) % MAX_SIG_QUEUE_SIZE; g_printf("Processing signal %s\n", sig_c.name); sig_c.signal_handler(sig_c.arg); } /* DANG_BEGIN_FUNCTION signal_pre_init * * description: * Initialize the signals to have NONE being blocked. * Currently this is NOT of much use to DOSEMU. * * DANG_END_FUNCTION * */ void signal_pre_init(void) { /* reserve 1024 uncommitted pages for stack */ #define SIGSTACK_SIZE (1024 * getpagesize()) sigset_t set; struct sigaction oldact; stack_t ss; void *cstack; cstack = mmap(NULL, SIGSTACK_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); if (cstack == MAP_FAILED) { error("Unable to allocate stack\n"); config.exitearly = 1; return; } ss.ss_sp = cstack; ss.ss_size = SIGSTACK_SIZE; ss.ss_flags = SS_ONSTACK; sigaltstack(&ss, NULL); /* initialize user data & code selector values (used by DPMI code) */ /* And save %fs, %gs for NPTL */ eflags_fs_gs.fs = getsegment(fs); eflags_fs_gs.gs = getsegment(gs); eflags_fs_gs.eflags = getflags(); #ifdef __x86_64__ /* get long fs and gs bases. If they are in the first 32 bits normal 386-style fs/gs switching can happen so we can ignore fsbase/gsbase */ dosemu_arch_prctl(ARCH_GET_FS, &eflags_fs_gs.fsbase); if ((unsigned long)eflags_fs_gs.fsbase <= 0xffffffff) eflags_fs_gs.fsbase = 0; dosemu_arch_prctl(ARCH_GET_GS, &eflags_fs_gs.gsbase); if ((unsigned long)eflags_fs_gs.gsbase <= 0xffffffff) eflags_fs_gs.gsbase = 0; #endif /* init signal handlers - these are the defined signals: --------------------------------------------- SIGHUP 1 S leavedos SIGINT 2 S leavedos SIGQUIT 3 N sigquit SIGILL 4 N dosemu_fault SIGTRAP 5 N dosemu_fault SIGABRT 6 S leavedos SIGBUS 7 N dosemu_fault SIGFPE 8 N dosemu_fault SIGKILL 9 na SIGUSR1 10 NQ (SIG_RELEASE)sigasync SIGSEGV 11 N dosemu_fault SIGUSR2 12 NQ (SIG_ACQUIRE)sigasync SIGPIPE 13 S SIG_IGN SIGALRM 14 NQ (SIG_TIME)sigasync SIGTERM 15 S leavedos SIGSTKFLT 16 SIGCHLD 17 NQ sig_child SIGCONT 18 SIGSTOP 19 SIGTSTP 20 SIGTTIN 21 unused was SIG_SER?? SIGTTOU 22 SIGURG 23 SIGXCPU 24 SIGXFSZ 25 SIGVTALRM 26 SIGPROF 27 NQ (cpuemu,sigprof)sigasync SIGWINCH 28 NQ (sigwinch)sigasync SIGIO 29 NQ (sigio)sigasync SIGPWR 30 SIGUNUSED 31 na ------------------------------------------------ */ newsetsig(SIGILL, dosemu_fault); newsetqsig(SIGALRM, sigasync); registersig(SIGALRM, sigalrm); newsetsig(SIGFPE, dosemu_fault); newsetsig(SIGTRAP, dosemu_fault); #ifdef SIGBUS /* for newer kernels */ newsetsig(SIGBUS, dosemu_fault); #endif setsig(SIGINT, leavedos_signal); /* for "graceful" shutdown for ^C too*/ setsig(SIGHUP, leavedos_signal); /* for "graceful" shutdown */ setsig(SIGTERM, leavedos_signal); #if 0 /* Richard Stevens says it can't be caught. It's returning an * error anyway */ setsig(SIGKILL, leavedos_signal); #endif newsetsig(SIGQUIT, sigasync); registersig(SIGQUIT, sigquit); setsig(SIGPIPE, SIG_IGN); /* setsig(SIGUNUSED, timint); */ newsetqsig(SIGIO, sigasync); registersig(SIGIO, sigio); newsetqsig(SIGUSR1, sigasync); newsetqsig(SIGUSR2, sigasync); sigaction(SIGPROF, NULL, &oldact); /* don't set SIGPROF if already used via -pg */ if (oldact.sa_handler == SIG_DFL) newsetqsig(SIGPROF, sigasync); newsetqsig(SIGWINCH, sigasync); newsetsig(SIGSEGV, dosemu_fault); newsetqsig(SIGCHLD, sig_child); /* unblock SIGIO, SIG_ACQUIRE, SIG_RELEASE */ sigemptyset(&set); addset_signals_that_queue(&set); /* dont unblock SIGALRM for now */ sigdelset(&set, SIGALRM); sigprocmask(SIG_UNBLOCK, &set, NULL); } void signal_init(void) { sh_tid = coopth_create("signal handling"); coopth_set_ctx_handlers(sh_tid, sig_ctx_prepare, sig_ctx_restore); coopth_set_sleep_handlers(sh_tid, handle_signals_force_enter, handle_signals_force_leave); coopth_set_permanent_post_handler(sh_tid, signal_thr_post); coopth_set_detached(sh_tid); } void signal_late_init(void) { sigset_t set; /* unblock SIGALRM */ sigemptyset(&set); sigaddset(&set, SIGALRM); sigprocmask(SIG_UNBLOCK, &set, NULL); } static void handle_signals_force_enter(int tid) { if (!in_handle_signals) { dosemu_error("in_handle_signals=0\n"); return; } in_handle_signals--; } static void handle_signals_force_leave(int tid) { in_handle_signals++; } int signal_pending(void) { return (SIGNAL_head != SIGNAL_tail); } /* * DANG_BEGIN_FUNCTION handle_signals * * description: * Due to signals happening at any time, the actual work to be done * because a signal occurs is done here in a serial fashion. * * The concept, should this eventualy work, is that a signal should only * flag that it has occurred and let DOSEMU deal with it in an orderly * fashion as it executes the rest of it's code. * * DANG_END_FUNCTION * */ void handle_signals(void) { if (in_handle_signals) return; if (signal_pending()) { in_handle_signals++; coopth_start(sh_tid, signal_thr, NULL); } } /* ============================================================== * * This is called by default at around 100Hz. * (see timer_interrupt_init() in init.c) * * The actual formulas, starting with the configurable parameter * config.freq, are: * config.freq default=18 * config.update = 1E6/config.freq default=54945 * timer tick(us) = config.update/6 default=9157.5us * = 166667/config.freq * timer tick(Hz) = 6*config.freq default=100Hz * * 6 is the magical TIMER_DIVISOR macro used to get 100Hz * * This call should NOT be used if you need timing accuracy - many * signals can get lost e.g. when kernel accesses disk, and the whole * idea of timing-by-counting is plain wrong. We'll need the Pentium * counter here. * ============================================================== */ static void SIGALRM_call(void *arg) { static int first = 0; static hitimer_t cnt200 = 0; static hitimer_t cnt1000 = 0; static volatile int running = 0; #if VIDEO_CHECK_DIRTY static int update_pending = 0; #endif int retval; if (first==0) { cnt200 = cnt1000 = pic_sys_time; /* initialize */ first = 1; } /* update mouse cursor before updating the screen */ mouse_curtick(); /* If it is running in termcap mode, then update the screen. * First it sets a running flag, so as to avoid re-entrancy of * update_screen while it is in use. After update_screen is done, * it returns a nonzero value if there was any updates to the screen. * If there were any updates to the screen, then set a countdown value * in order to give DOSEMU more CPU time, between screen updates. * This increases the DOSEMU-to-termcap update efficiency greatly. * The countdown counter is currently at a value of 2. */ /* This now (again) tests screen_bitmap, i.e. checks if the screen * was written to at all. This doesn't seem to achieve much for now, * but it will be helpful when implementing X graphics. * It's a bit tricky, however, because previous calls of update_screen * might not have updated the entire screen. Therefore update_pending * is set to 1 if only part of the screen was updated (update_screen * returns 2), meaning that update_screen will in any case be called * next time. * (*** this only applies if VIDEO_CHECK_DIRTY is set, which is * currently not the default! ***) * * return vales for update_screen are now: * 0 nothing changed * 1 changed, entire screen updated * 2 changed, only partially updated * * note that update_screen also updates the cursor. */ if (Video->update_screen && config.X_blinkrate) { blink_cursor(); } if (!running) { if (Video->update_screen #if VIDEO_CHECK_DIRTY && (update_pending || vm86s.screen_bitmap&screen_mask) #endif ) { running = -1; retval = Video->update_screen(); #if 0 v_printf("update_screen returned %d\n",retval); #endif running = retval ? (config.X?config.X_updatefreq:config.term_updatefreq) : 0; #if VIDEO_CHECK_DIRTY update_pending=(retval==2); vm86s.screen_bitmap=0; #endif } else if (Video->update_cursor) { v_printf("update cursor\n"); Video->update_cursor(); } } else if (running > 0) { running--; } if (Video->handle_events) Video->handle_events(); /* for the SLang terminal we'll delay the release of shift, ctrl, ... keystrokes a bit */ /* although actually the event handler handles the keyboard in X, keyb_client_run * still needs to be called in order to handle pasting. */ if (!config.console_keyb) keyb_client_run(); #ifdef USE_SBEMU /* This is a macro */ run_sb(); #endif serial_run(); /* TRB - perform processing for the IPX Asynchronous Event Service */ #ifdef IPX if (config.ipxsup) AESTimerTick(); #endif if (config.rdtsc) update_cputime_TSCBase(); timer_tick(); #if 0 /* * DANG_BEGIN_REMARK * Check for keyboard coming from client * For now, first byte is interrupt requests from Client * DANG_END_REMARK */ if (*(u_char *)(shared_qf_memory + CLIENT_REQUEST_FLAG_AREA) & 0x40) { k_printf("KBD: Client sent key\n"); pic_request (PIC_IRQ1); *(u_char *)(shared_qf_memory + CLIENT_REQUEST_FLAG_AREA) &= ~0x40; } #endif io_select(fds_sigio); /* we need this in order to catch lost SIGIOs */ if (not_use_sigio) io_select(fds_no_sigio); alarm_idle(); /* Here we 'type in' prestrokes from commandline, as long as there are any * Were won't overkill dosemu, hence we type at a speed of 14cps */ if (config.pre_stroke) { static int count=-1; if (--count < 0) { count = type_in_pre_strokes(); if (count <0) count =7; /* with HZ=100 we have a stroke rate of 14cps */ } } /* this should be for per-second activities, it is actually at * 200ms more or less (PARTIALS=5) */ if ((pic_sys_time-cnt200) >= (PIT_TICK_RATE/PARTIALS)) { cnt200 = pic_sys_time; /* g_printf("**** ALRM: %dms\n",(1000/PARTIALS)); */ printer_tick(0); if (config.fastfloppy) floppy_tick(); } /* We update the RTC from here if it has not been defined as a thread */ /* this is for EXACT per-second activities (can produce bursts) */ if ((pic_sys_time-cnt1000) >= PIT_TICK_RATE) { cnt1000 += PIT_TICK_RATE; /* g_printf("**** ALRM: 1sec\n"); */ rtc_update(); } } /* DANG_BEGIN_FUNCTION SIGNAL_save * * arguments: * context - signal context to save. * signal_call - signal handling routine to be called. * * description: * Save into an array structure queue the signal context of the current * signal as well as the function to call for dealing with this signal. * This is a queue because any signal may occur multiple times before * DOSEMU deals with it down the road. * * DANG_END_FUNCTION * */ void SIGNAL_save(void (*signal_call)(void *), void *arg, size_t len, const char *name) { signal_queue[SIGNAL_tail].signal_handler = signal_call; signal_queue[SIGNAL_tail].arg_size = len; assert(len <= MAX_SIG_DATA_SIZE); if (len) memcpy(signal_queue[SIGNAL_tail].arg, arg, len); signal_queue[SIGNAL_tail].name = name; SIGNAL_tail = (SIGNAL_tail + 1) % MAX_SIG_QUEUE_SIZE; if (in_dpmi) dpmi_return_request(); } /* * DANG_BEGIN_FUNCTION SIGIO_call * * description: * Whenever I/O occurs on devices allowing SIGIO to occur, DOSEMU * will be flagged to run this call which inturn checks which * fd(s) was set and execute the proper routine to get the I/O * from that device. * * DANG_END_FUNCTION * */ static void SIGIO_call(void *arg){ /* Call select to see if any I/O is ready on devices */ io_select(fds_sigio); } #ifdef __linux__ static void sigio(struct sigcontext_struct *scp) { SIGNAL_save(SIGIO_call, NULL, 0, __func__); if (in_dpmi && !in_vm86) dpmi_sigio(scp); } static void sigalrm(struct sigcontext_struct *scp) { if(e_gen_sigalrm(scp)) { SIGNAL_save(SIGALRM_call, NULL, 0, __func__); if (in_dpmi && !in_vm86) dpmi_sigio(scp); } } __attribute__((no_instrument_function)) static void sigasync0(int sig, struct sigcontext_struct *scp) { init_handler(scp); if (sighandlers[sig]) sighandlers[sig](scp); dpmi_iret_setup(scp); } __attribute__((no_instrument_function)) static void sigasync(int sig, siginfo_t *si, void *uc) { sigasync0(sig, (struct sigcontext_struct *) &((ucontext_t *)uc)->uc_mcontext); } #endif static void sigquit(struct sigcontext_struct *scp) { in_vm86 = 0; error("sigquit called\n"); show_ints(0, 0x33); show_regs(__FILE__, __LINE__); WRITE_BYTE(BIOS_KEYBOARD_FLAGS, 0x80); /* ctrl-break flag */ do_soft_int(0x1b); }