home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #30 / NN_1992_30.iso / spool / comp / unix / bsd / 10264 < prev    next >
Encoding:
Text File  |  1992-12-15  |  6.1 KB  |  193 lines

  1. Newsgroups: comp.unix.bsd
  2. Path: sparky!uunet!munnari.oz.au!metro!ipso!runxtsa!bde
  3. From: bde@runx.oz.au (Bruce Evans)
  4. Subject: Re: [386bsd]  How To Nuke 386bsd!!!
  5. Message-ID: <1992Dec15.210710.28798@runx.oz.au>
  6. Organization: RUNX Un*x Timeshare.  Sydney, Australia.
  7. References: <ByntK9.1D6@news.chalmers.se> <1992Dec7.000113.20304@mel.dit.csiro.au> <1992Dec7.034604.14841@netcom.com>
  8. Date: Tue, 15 Dec 92 21:07:10 GMT
  9. Lines: 182
  10.  
  11. In article <1992Dec7.034604.14841@netcom.com> hasty@netcom.com (Amancio Hasty Jr) writes:
  12. >[...]
  13. >The problem maybe related to the way that you motherboard handles
  14. >floating point exception. Try a simple program that does a floating
  15. >point divide by 0.0. If the system re-boots you got a bad motherboard.
  16.  
  17. There are so many bugs in the kernel and libraries involving floating
  18. point exceptions that it's hard to tell if the motherboard is bad.  I
  19. seem to have a "bad" 486 motherboard (386BSD-0.1 panics) but I have
  20. rewritten the exception handler so that there are no problems.
  21.  
  22. Here is a test program that does a lot of floating point divides by 0.0
  23. and panics 386BSD-0.1 on a bad (any?) motherboard fairly quickly.  Compile
  24. it with -DMAX_FAILURES=16 to limit the output.  Comment out any test that
  25. always fails to emphasize the other tests.
  26.  
  27. I am interested in how non-386BSD 386-486 systems handle this test.  It
  28. requires gcc to compile so I haven't been able to run it on any, but
  29. previous tests suggest that failure of all the "no-wait" tests except
  30. the one for fnclex is typical, and when the fnclex test doesn't fail all
  31. the time, it fails intermittently.
  32.  
  33. ---
  34. #include <signal.h>
  35. #include <stdio.h>
  36.  
  37. #define TEST(x, y) ( ++tests, setup(), ({ asm(x); 0; }), check(x, y) )
  38. #define CW_ZM    (1 << 2)    /* divide by zero mask */
  39. #define SW_BUSY    (1 << 15)    /* FPU busy */
  40. #define SW_ES    (1 << 7)    /* exception summary */
  41. #define SW_ZE    (1 << 2)    /* divide by zero (pending) exception seen */
  42.  
  43. static double double_in_mem;
  44. static unsigned short fp_cw;
  45. static unsigned fp_env[7];
  46. static unsigned fp_state[7 + 8 * 10 / sizeof(unsigned)];
  47. static unsigned short fp_sw;
  48. static unsigned failures;
  49. static unsigned long tests;
  50. static volatile /* sig_atomic_t */ int sigfpe_handled;
  51. static volatile /* sig_atomic_t */ int sigint_handled;
  52.  
  53. static void delay(void);
  54. static int check(char *insn, int sigfpe_expected);
  55. static void setup(void);
  56. static void sigfpe_handler(int sig_num);
  57. static void sigint_handler(int sig_num);
  58.  
  59. static int check(char *insn, int sigfpe_expected)
  60. {
  61.     if (sigfpe_handled)
  62.     {
  63.     signal(SIGFPE, sigfpe_handler);
  64.     sigfpe_handled = 0;
  65.     if (sigfpe_expected)
  66.         return 1;
  67.     }
  68.     else if (!sigfpe_expected)
  69.     return 1;
  70.     ++failures;
  71.     fprintf(stderr, "T %lu F %u: %s SIGFPE for `%s'\n",
  72.         tests, failures, sigfpe_expected ? "no" : "  ", insn);
  73.     return 0;
  74. }
  75.  
  76. static void delay(void)
  77. {
  78.     volatile unsigned countdown;
  79.  
  80.     for (countdown = 100; countdown != 0; --countdown)
  81.     ;
  82. }
  83.  
  84. int main(argc, argv)
  85. int argc;
  86. char **argv;
  87. {
  88.     signal(SIGINT, sigint_handler);
  89. #ifdef MAX_FAILURES
  90.     while (failures < MAX_FAILURES && !sigint_handled)
  91. #else
  92.     while (!sigint_handled)
  93. #endif
  94.     {
  95.     /*
  96.      * Cause a divide by zero error.  This should not trigger an exception.
  97.      * The next no-wait FP instruction should trigger the exception.
  98.      */
  99.     if (TEST("fldz; fld1; fdiv %st,%st(1)", 0))
  100.     {
  101.         /*
  102.          * The wait instruction should always trigger a pending exception.
  103.          *
  104.          * One way for this to fail is if the kernel uses CR0_EM instead
  105.          * of CR0_TS | CR0_MP to handle FP context switching.  This fails
  106.          * to trap fwaits immeditatly after an FP context switch.  It is
  107.          * especially bad when FP is being emulated.  Then all fwaits are
  108.          * ignored!
  109.          */
  110.         TEST("fldz; fld1; fdiv %st,%st(1); call _delay; fwait", 1);
  111.  
  112.         /*
  113.          * No-wait instructions should never trigger a pending exception.
  114.          *
  115.          * On my 486 system, they are all broken when the IRQ13 FP
  116.          * exception reporting method is used.  On at least one 386 system,
  117.          * fnclex usually works but some of the others are broken, and
  118.          * fnclex fails after a context switch, presumably because frstor
  119.          * fails in the kernel.
  120.          */
  121.         TEST("fldz; fld1; fdiv %st,%st(1); fninit", 0);
  122.         TEST("fldz; fld1; fdiv %st,%st(1); fnstcw _fp_cw", 0);
  123.         TEST("fldz; fld1; fdiv %st,%st(1); fnstsw _fp_sw", 0);
  124.         TEST("fldz; fld1; fdiv %st,%st(1); fnclex", 0);
  125.         TEST("fldz; fld1; fdiv %st,%st(1); fnstenv _fp_env", 0);
  126.         TEST("fldz; fld1; fdiv %st,%st(1); fnsave _fp_state", 0);
  127.     }
  128.  
  129.     /*
  130.      * fldenv and frstor of an error state should not trigger an exception,
  131.      * and they should not lose the pending exception.  Fake the pending
  132.      * exception so that these tests can be done even if the tests for
  133.      * fnstenv and fnsave of the pending exception failed.
  134.      */
  135.     setup();
  136.     asm("fnstenv _fp_env");    /* an almost clean env */
  137.     fp_env[1] |= SW_BUSY | SW_ES | SW_ZE;    /* fake excepttion */
  138.     ++tests;
  139.     asm("fldenv _fp_env");
  140.     if (check("fldenv of pending exception", 0))
  141.     {
  142.         delay();
  143.         asm("fwait");
  144.         ++tests;
  145.         check("fwait after fldenv of pending exception", 1);
  146.     }
  147.     setup();
  148.     asm("fnsave _fp_state");    /* an almost clean state */
  149.     fp_state[1] |= SW_BUSY | SW_ES | SW_ZE;    /* fake excepttion */
  150.     ++tests;
  151.     asm("frstor _fp_state");
  152.     if (check("frstor of pending exception", 0))
  153.     {
  154.         delay();
  155.         asm("fwait");
  156.         ++tests;
  157.         check("fwait after frstor of pending exception", 1);
  158.     }
  159.  
  160.     /*
  161.      * fstpl to memory when the FP stack is empty sometimes causes an
  162.      * IRQ13 a little after the intstruction.  When the fstpl is traced,
  163.      * the exception appears to come from the trace trap handler!  frstor
  164.      * of a pending error may also cause an IRQ13 after the instruction.
  165.      */
  166.     TEST("fstpl _double_in_mem", 0);
  167.     }
  168.     fprintf(stderr, "%lu tests, %u failures\n", tests, failures);
  169.     return failures ? 1 : 0;
  170. }
  171.  
  172. static void setup(void)
  173. {
  174.     asm("fwait; fninit; fnstcw _fp_cw");
  175.     fp_cw &= ~CW_ZM;
  176.     asm("fldcw _fp_cw");
  177.     signal(SIGFPE, sigfpe_handler);
  178.     sigfpe_handled = 0;
  179. }
  180.  
  181. static void sigfpe_handler(int sig_num)
  182. {
  183.     sigfpe_handled = 1;
  184. }
  185.  
  186. static void sigint_handler(int sig_num)
  187. {
  188.     sigint_handled = 1;
  189. }
  190. ---
  191. -- 
  192. Bruce Evans  (bde@runx.oz.au)
  193.