/* Copyright (C) 1994, 1995 Charles Sandmann (sandmann@clio.rice.edu) * Copyright (C) 1996-1998 Ilya Ryzhenkov (orangy@inetlab.com) * FPU setup and emulation hooks for DLM * This file maybe freely distributed, no warranty. */ #include #include #include #include #include #include #include #include #include #include #include /* for _8087 */ #include "dlmimage.h" #include "dlm_sym.h" /* crt0.o references __emu387_load_hook, so we must do the same to avoid loading npxsetup.o from libc.a */ int __emu387_load_hook; /* _emu_entry is found in emu387.dlm, which is loaded when needed */ int (*_emu_entry)(jmp_buf exc); int _8087; /* The environment variable 387 can be used to disable a 387 which is present (for testing) by setting it to "n". The presence can be reported to stderr by setting 387 to "q" (query). Unlike GO32, "y" is not supported since it can hang the machine if a coprocessor is not really present. If a 387 is not present under DPMI, we call a V1.0 DPMI extension to ask that Exception 7 be sent to our process. If we don't have a 387, we attempt to load the EMU387.DLM and call it from the signal. */ static void restore_DPMI_fpu_state(void) { __dpmi_set_coprocessor_emulation(1); /* Enable Coprocessor, no exceptions */ } static void nofpsig(int sig) { if ((unsigned)_emu_entry != 0xFFFFFFFF) /* is emu387.dlm loaded ? */ if(!_emu_entry(__djgpp_exception_state)) /* if successful emulation continue execution */ longjmp(__djgpp_exception_state, __djgpp_exception_state->__eax); /* Emulation failed - raise signal and (hopefuly) exit We should also restore FPU state in case signal handler will not return */ restore_DPMI_fpu_state(); raise(SIGFPE); /* should we reattempt to emulate if we returned from signal ? may be someone would like to introduce load-on-use ? For now we just abort. */ abort(); } extern int _detect_80387(void); // from fpu.S from libc.a void _npxsetup(char *argv0) { /* Fake _npxsetup to fool linker We will initialize FPU later, after general DLM startup done. DLM engine code doesn't use floating point itself, so no problem here ... */ } void _dlm_npxsetup() { char *cp; char have_80387; static int veryfirst = 1; cp = getenv("387"); if (cp && (tolower(cp[0]) == 'y')) { _control87(0x033f, 0xffff); /* mask all numeric exceptions */ return; } if (cp && (tolower(cp[0]) == 'n')) have_80387 = 0; else { /* This next function may fail, but that's OK. This may fix the nested FPU client fault - DJ */ __dpmi_set_coprocessor_emulation(1); have_80387 = _detect_80387(); _8087 = (have_80387 ? 3 : 0); } if (cp && (tolower(cp[0]) == 'q')) { if (!have_80387) _write(2, "No ", 3); _write(2, "80387 detected.\r\n", 17); } if (have_80387) { /* mask all exceptions */ _control87(0x033f, 0xffff); } else { /* Flags value 3 means coprocessor emulation, exceptions to us */ if (__dpmi_set_coprocessor_emulation(3)) { _write(2, "Warning: Coprocessor not present and DPMI setup failed!\r\n", 57); _write(2, " If application attempts floating operations system may hang!\r\n", 71); } else { /* Emulation mode - DPMI ready, now load emu387.dlm or whatever EMU387DLM env points to */ char *emudlm; emudlm=getenv("EMU387DLM"); if (!emudlm) emudlm="emu387.dlm"; /* We are not using floating point ourself, we just need to get address of emu entry */ if (!_dlm_load(emudlm)) { _write(2, "Warning: Coprocessor not present (or disabled) and emulation DLM not found!\r\n", 77); _emu_entry=(int (*)(jmp_buf))0xFFFFFFFF; } else _emu_entry=_dlm_lookup("__emu_entry"); if (veryfirst) { veryfirst = 0; atexit(restore_DPMI_fpu_state); } signal(SIGNOFP, nofpsig); } } }