source: rtems/cpukit/score/cpu/i386/sse_test.c @ 42e243e

4.104.115
Last change on this file since 42e243e was 42e243e, checked in by Ralf Corsepius <ralf.corsepius@…>, on 12/04/09 at 04:27:21

Whitespace removal.

  • Property mode set to 100644
File size: 25.5 KB
Line 
1/* $Id$ */
2
3/*
4 * Authorship
5 * ----------
6 * This software was created by
7 *     Till Straumann <strauman@slac.stanford.edu>, 2009,
8 *     Stanford Linear Accelerator Center, Stanford University.
9 *
10 * Acknowledgement of sponsorship
11 * ------------------------------
12 * This software was produced by
13 *     the Stanford Linear Accelerator Center, Stanford University,
14 *     under Contract DE-AC03-76SFO0515 with the Department of Energy.
15 *
16 * Government disclaimer of liability
17 * ----------------------------------
18 * Neither the United States nor the United States Department of Energy,
19 * nor any of their employees, makes any warranty, express or implied, or
20 * assumes any legal liability or responsibility for the accuracy,
21 * completeness, or usefulness of any data, apparatus, product, or process
22 * disclosed, or represents that its use would not infringe privately owned
23 * rights.
24 *
25 * Stanford disclaimer of liability
26 * --------------------------------
27 * Stanford University makes no representations or warranties, express or
28 * implied, nor assumes any liability for the use of this software.
29 *
30 * Stanford disclaimer of copyright
31 * --------------------------------
32 * Stanford University, owner of the copyright, hereby disclaims its
33 * copyright and all other rights in this software.  Hence, anyone may
34 * freely use it for any purpose without restriction.
35 *
36 * Maintenance of notices
37 * ----------------------
38 * In the interest of clarity regarding the origin and status of this
39 * SLAC software, this and all the preceding Stanford University notices
40 * are to remain affixed to any copy or derivative of this software made
41 * or distributed by the recipient and are to be affixed to any copy of
42 * software made or distributed by the recipient that contains a copy or
43 * derivative of this software.
44 *
45 * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
46 */
47
48
49/* Code for testing FPU/SSE context save/restore across exceptions
50 * (including interrupts).
51 *
52 * There are two tasks and an IRQ/EXC handler involved. One task (LP)
53 * is of lower priority than the other (HP) task.
54 *
55 * 1) LP task sets up a context area in memory (known contents; every
56 *    register is loaded with different values)
57 *
58 * 2) LP task
59 *       2a saves original FP/SSE context
60 *       2b loads context from 1) into FPU/SSE
61 *       2c raises an exception or interrupt
62 *
63 *   *  (2d save FPU/SSE context after irq/exception returns to
64 *          separate area for verification
65 *       2e reload original FP/SSE context.)
66 *
67 *   * All these five steps are coded in assembly to prevent
68 *     gcc from manipulating the FP/SSE state. The last two steps,
69 *     however, are effectively executed during 6 when control is
70 *     returned to the LP task.
71 *
72 * 3) IRQ/EXC handler OS wrapper saves context, initializes FPU and
73 *    MXCSR.
74 *
75 * 4) user (our) irq/exc handler clears exception condition, clobbers
76 *    FPU and XMM regs and finally releases a semaphore on which HP
77 *    task is waiting.
78 *
79 * 5) context switch to HP task. HP task clobbers FPU and XMM regs.
80 *    Then it tries to re-acquire the synchronization semaphore and
81 *    blocks.
82 *
83 * 6) task switch back to (interrupted) LP task. Original context is
84 *    restored and verified against the context that was setup in 1).
85 *
86 *
87 * Three methods for interrupting the LP task are tested
88 *
89 *  a) FP exception (by setting an exception status in the context from 1)
90 *  b) SSE exception (by computing the square root of a vector of negative
91 *     numbers.
92 *  c) IRQ (software IRQ via 'INT xx' instruction)
93 *
94 */
95#ifdef __rtems__
96
97#include <rtems.h>
98#include <rtems/score/cpu.h>
99#include <rtems/irq.h>
100#include <rtems/error.h>
101
102#endif
103
104#include <inttypes.h>
105#include <stdio.h>
106#include <stdlib.h>
107#include <string.h>
108#include <math.h>
109
110/* This is currently hardcoded (int xx opcode requires immediate operand) */
111#define SSE_TEST_IRQ  10
112
113typedef uint8_t   __v8  __attribute__((vector_size(16)));
114typedef uint32_t __v32  __attribute__((vector_size(16)));
115typedef float     __vf  __attribute__((vector_size(16)));
116
117#ifndef __rtems__
118/* Clone of what is defined in rtems/score/cpu.h (for testing under linux) */
119typedef struct Context_Control_sse {
120  uint16_t  fcw;
121  uint16_t  fsw;
122  uint8_t   ftw;
123  uint8_t   res_1;
124  uint16_t  fop;
125  uint32_t  fpu_ip;
126  uint16_t  cs;
127  uint16_t  res_2;
128  uint32_t  fpu_dp;
129  uint16_t  ds;
130  uint16_t  res_3;
131  uint32_t  mxcsr;
132  uint32_t  mxcsr_mask;
133  struct {
134    uint8_t fpreg[10];
135    uint8_t res_4[ 6];
136  } fp_mmregs[8];
137  uint8_t   xmmregs[8][16];
138  uint8_t   res_5[224];
139} Context_Control_sse
140__attribute__((aligned(16)))
141;
142#endif
143
144#define MXCSR_FZ          (1<<15)   /* Flush to zero */
145#define MXCSR_RC(x) (((x)&3)<<13)   /* Rounding ctrl */
146#define MXCSR_PM          (1<<12)   /* Precision msk */
147#define MXCSR_UM          (1<<11)   /* Underflow msk */
148#define MXCSR_OM          (1<<10)   /* Overflow  msk */
149#define MXCSR_ZM          (1<< 9)   /* Divbyzero msk */
150#define MXCSR_DM          (1<< 8)   /* Denormal  msk */
151#define MXCSR_IM          (1<< 7)   /* Invalidop msk */
152#define MXCSR_DAZ         (1<< 6)   /* Denorml are 0 */
153#define MXCSR_PE          (1<< 5)   /* Precision flg */
154#define MXCSR_UE          (1<< 4)   /* Underflow flg */
155#define MXCSR_OE          (1<< 3)   /* Overflow  flg */
156#define MXCSR_ZE          (1<< 2)   /* Divbyzero flg */
157#define MXCSR_DE          (1<< 1)   /* Denormal  flg */
158#define MXCSR_IE          (1<< 0)   /* Invalidop flg */
159
160#define MXCSR_ALLM (MXCSR_PM | MXCSR_UM | MXCSR_OM | MXCSR_ZM | MXCSR_DM | MXCSR_IM)
161#define MXCSR_ALLE (MXCSR_PE | MXCSR_UE | MXCSR_OE | MXCSR_ZE | MXCSR_DE | MXCSR_IE)
162
163#define FPSR_B            (1<<15)   /* FPU busy      */
164#define FPSR_C3           (1<<14)   /* Cond code C3  */
165#define FPSR_TOP(x) (((x)&7)<<11)   /* TOP           */
166#define FPSR_C2           (1<<10)   /* Cond code C2  */
167#define FPSR_C1           (1<< 9)   /* Cond code C1  */
168#define FPSR_C0           (1<< 8)   /* Cond code C0  */
169#define FPSR_ES           (1<< 7)   /* Error summary */
170#define FPSR_SF           (1<< 6)   /* Stack fault   */
171#define FPSR_PE           (1<< 5)   /* Precision flg */
172#define FPSR_UE           (1<< 4)   /* Underflow flg */
173#define FPSR_OE           (1<< 3)   /* Overflow  flg */
174#define FPSR_ZE           (1<< 2)   /* Divbyzero flg */
175#define FPSR_DE           (1<< 1)   /* Denormal  flg */
176#define FPSR_IE           (1<< 0)   /* Invalidop flg */
177
178#define FPCW_X            (1<<12)   /* Infinity ctrl */
179#define FPCW_RC(x)  (((x)&3)<<10)   /* Rounding ctrl */
180#define FPCW_PC(x)  (((x)&3)<< 8)   /* Precision ctl */
181#define FPCW_PM           (1<< 5)   /* Precision msk */
182#define FPCW_UM           (1<< 4)   /* Underflow msk */
183#define FPCW_OM           (1<< 3)   /* Overflow  msk */
184#define FPCW_ZM           (1<< 2)   /* Divbyzero msk */
185#define FPCW_DM           (1<< 1)   /* Denormal  msk */
186#define FPCW_IM           (1<< 0)   /* Invalidop msk */
187
188#define FPCW_ALLM (FPCW_PM | FPCW_UM | FPCW_OM | FPCW_ZM | FPCW_DM | FPCW_IM)
189#define FPSR_ALLE (FPSR_ES | FPSR_SF | FPSR_PE | FPSR_UE | FPSR_OE | FPSR_ZE | FPSR_DE | FPSR_IE)
190
191/* Store 'double' into 80-bit register image */
192void
193fp_st1(uint8_t (*p_dst)[10], double v)
194{
195        asm volatile("fstpt %0":"=m"(*p_dst):"t"(v):"st");
196}
197
198/* Store 'double' into 80-bit register image #i in context */
199void
200fp_st(Context_Control_sse *p_ctxt, int i, double v)
201{
202        fp_st1(&p_ctxt->fp_mmregs[i].fpreg,v);
203}
204
205/* Load 'double' from 80-bit register image */
206double
207fp_ld1(uint8_t (*p_src)[10])
208{
209double v;
210
211        asm volatile("fldt %1":"=t"(v):"m"((*p_src)[0]),"m"(*p_src));
212        return v;
213}
214
215/* Load 'double' from 80-bit register image #i in context */
216double
217fp_ld(Context_Control_sse *p_ctxt, int i)
218{
219        return fp_ld1(&p_ctxt->fp_mmregs[i].fpreg);
220}
221
222#define FPUCLOBBER \
223        "st","st(1)","st(2)","st(3)",   \
224        "st(4)","st(5)","st(6)","st(7)",\
225        "fpsr","fpcr"
226
227/* There seems to be no way to say that mxcsr was clobbered */
228
229#define SSECLOBBER \
230        "xmm0","xmm1","xmm2","xmm3",    \
231        "xmm4","xmm5","xmm6","xmm7"
232
233static void
234sse_clobber(uint32_t x)
235{
236__v32 v = { x, x, x, x };
237        asm volatile (
238                "       movdqa %0,     %%xmm0      \n"
239                "       movdqa %%xmm0, %%xmm1      \n"
240                "       movdqa %%xmm0, %%xmm2      \n"
241                "       movdqa %%xmm0, %%xmm3      \n"
242                "       movdqa %%xmm0, %%xmm4      \n"
243                "       movdqa %%xmm0, %%xmm5      \n"
244                "       movdqa %%xmm0, %%xmm6      \n"
245                "       movdqa %%xmm0, %%xmm7      \n"
246                :
247                :"m"(v)
248                :SSECLOBBER
249        );
250}
251
252void
253all_clobber(uint32_t v1, uint32_t v2);
254
255asm(
256"all_clobber:               \n"
257"   finit                   \n"
258"       movq  0(%esp), %xmm0    \n"
259"   punpcklqdq %xmm0, %xmm0 \n"
260"       movdqa %xmm0, %xmm1     \n"
261"       movdqa %xmm0, %xmm2     \n"
262"       movdqa %xmm0, %xmm3     \n"
263"       movdqa %xmm0, %xmm4     \n"
264"       movdqa %xmm0, %xmm5     \n"
265"       movdqa %xmm0, %xmm6     \n"
266"       movdqa %xmm0, %xmm7     \n"
267"       ret                     \n"
268);
269
270/* Clear FPU and save FPU/SSE registers to context area */
271
272void
273init_ctxt(Context_Control_sse *p_ctxt);
274
275asm(
276"init_ctxt:            \n"
277"       finit              \n"
278"   mov    4(%esp), %eax\n"
279"   fxsave (%eax)      \n"
280"   fwait              \n"
281"   ret                \n"
282);
283
284/* Save FPU/SSE registers to context area */
285
286static void
287stor_ctxt(Context_Control_sse *p_ctxt)
288{
289        memset(p_ctxt, 0, sizeof(*p_ctxt));
290        asm volatile(
291/*              "       finit                \n" */
292                "       fxsave %0            \n"
293                "   fwait                \n"
294                : "=m"(*p_ctxt)
295                :
296                : FPUCLOBBER
297        );
298}
299
300#define H08 "0x%02"PRIx8
301#define H16 "0x%04"PRIx16
302#define H32 "0x%08"PRIx32
303
304#define F16 "mismatch ("H16" != "H16")\n"
305
306#define FLDCMP(fld, fmt) \
307        if ( a->fld != b->fld ) { \
308                rval = 1;             \
309                if ( !quiet )         \
310           fprintf(stderr,#fld" mismatch ("fmt" != "fmt")\n",a->fld, b->fld); \
311        }
312
313#define FLTCMP(i)                                   \
314        do {                                            \
315                if (   ( (a->ftw ^ b->ftw) & (1<<i))        \
316                        || ( (a->ftw & b->ftw  & (1<<i)) &&     \
317                 memcmp(a->fp_mmregs[i].fpreg,      \
318                    b->fp_mmregs[i].fpreg,          \
319                    sizeof(a->fp_mmregs[i].fpreg))  \
320               )                                    \
321           ) {                                      \
322            rval = 1;                               \
323            if ( !quiet ) {                         \
324              double fa = fp_ld(a, i);              \
325              double fb = fp_ld(b, i);              \
326                          if ( ((a->ftw ^ b->ftw) & (1<<i)) )   \
327                fprintf(stderr,"fpreg[%u] TAG mismatch (%u != %u)\n",i,(a->ftw & (1<<i)) ? 1 : 0,(b->ftw & (1<<i)) ? 1 : 0); \
328                          else                                  \
329                fprintf(stderr,"fpreg[%u] mismatch (%g != %g)\n",i,fa,fb); \
330                }                                       \
331            }                                           \
332    } while (0)
333
334#define XMMCMP(i)                                   \
335        do {                                            \
336                if ( memcmp(&a->xmmregs[i],                 \
337                    &b->xmmregs[i],                 \
338                    sizeof(a->xmmregs[i]))          \
339           ) {                                      \
340            rval = 1;                               \
341            if ( !quiet ) {                         \
342              int _jj;                              \
343              fprintf(stderr,"xmmreg[%u] mismatch:\n", i); \
344              fprintf(stderr,"    ");               \
345              for (_jj=0; _jj<16; _jj++)            \
346                fprintf(stderr,"%02x ",a->xmmregs[i][_jj]); \
347              fprintf(stderr,"\n !=\n");            \
348              fprintf(stderr,"    ");               \
349              for (_jj=0; _jj<16; _jj++)            \
350                fprintf(stderr,"%02x ",b->xmmregs[i][_jj]); \
351              fprintf(stderr,"\n");                 \
352                }                                       \
353            }                                           \
354    } while (0)
355
356
357/* Compare two FPU/SSE context areas and flag differences;
358 * RETURNS: zero if the contexts match and nonzero otherwise
359 */
360static int
361cmp_ctxt(Context_Control_sse *a, Context_Control_sse *b, int quiet)
362{
363int rval = 0;
364int i;
365        FLDCMP(fcw,H16);
366        FLDCMP(fsw,H16);
367        FLDCMP(ftw,H08);
368        FLDCMP(fop,H16);
369        FLDCMP(fpu_ip,H32);
370        FLDCMP(cs,H16);
371        FLDCMP(fpu_dp,H32);
372        FLDCMP(ds,H16);
373        FLDCMP(mxcsr,H32);
374        FLDCMP(mxcsr_mask,H32);
375        for ( i=0; i<8; i++ ) {
376                FLTCMP(i);
377        }
378        for ( i=0; i<8; i++ ) {
379                XMMCMP(i);
380        }
381        return rval;
382}
383
384/* Possible arguments to exc_raise() */
385
386#define FP_EXC   0
387#define IRQ_EXC  1
388#define SSE_EXC -1
389
390/* Check stack alignment by raising the interrupt from a
391 * non-16-byte aligned section of code. The exception/IRQ
392 * handler must align the stack and SSE context area
393 * properly or it will crash.
394 */
395#define __INTRAISE(x) " int  $32+"#x" \n"
396#define INTRAISE(x)   __INTRAISE(x)
397
398asm(
399"do_raise:               \n"
400"   fwait                \n"
401"       test    %eax, %eax   \n"
402"   je      2f           \n"
403"   jl      1f           \n"
404INTRAISE(SSE_TEST_IRQ)
405"   jmp     2f           \n"
406"1: sqrtps  %xmm0, %xmm0 \n"
407"2:                      \n"
408"   ret                  \n"
409);
410
411#define SSE_TEST_HP_FAILED       1
412#define SSE_TEST_FSPR_FAILED     2
413#define SSE_TEST_CTXTCMP_FAILED  4
414
415static const char *fail_msgs[] = {
416        "Seems that HP task was not executing",
417        "FPSR 'Invalid-operation' flag should be clear",
418        "Restored context does NOT match the saved one",
419};
420
421static void prstat(int st, const char *where)
422{
423int i,msk;
424        for ( i=0, msk=1; i<sizeof(fail_msgs)/sizeof(fail_msgs[0]); i++, msk<<=1 ) {
425                if ( (st & msk) ) {
426                        fprintf(stderr,"sse_test ERROR: %s (testing: %s)\n", fail_msgs[i], where);
427                }
428        }
429}
430
431int                 sse_test_debug   = 0;
432
433static int
434exc_raise(int kind)
435{
436Context_Control_sse nctxt;
437Context_Control_sse octxt;
438Context_Control_sse orig_ctxt;
439int                 i,j,rval;
440double              s2;
441uint16_t            fsw;
442__vf                f4  = { -1., -2., -3., -4. };
443__vf                tmp;
444__v32               sgn = { (1<<31), (1<<31), (1<<31), (1<<31) };
445
446        stor_ctxt(&octxt);
447
448        octxt.fsw   &= ~FPSR_ALLE;
449        octxt.mxcsr &= ~MXCSR_ALLE;
450
451        for ( i=0; i<8; i++ ) {
452                fp_st(&octxt, i, (double)i+0.1);
453                for (j=0; j<16; j++) {
454                        octxt.xmmregs[i][j]=(i<<4)+j;
455                }
456        }
457
458
459        if ( SSE_EXC == kind ) {
460                memcpy(octxt.xmmregs[0], &f4, sizeof(f4));
461                octxt.mxcsr &= ~MXCSR_IM;
462        }
463
464        /* set tags to 'valid'            */
465        octxt.ftw = 0xff;
466
467        /* enable 'invalid arg' exception */
468        octxt.fcw &= ~ ( FPCW_IM );
469       
470        if ( FP_EXC == kind ) {
471                octxt.fsw |=   ( FPSR_IE | FPSR_ES );
472        }
473
474        if ( sse_test_debug )
475                printk("RAISE (fsw was 0x%04x)\n", orig_ctxt.fsw);
476        asm volatile(
477                "       fxsave  %2           \n"
478#ifdef __rtems__
479                "   movl    %4, sse_test_check\n"
480#endif
481                "       fxrstor %3           \n"
482                "   call    do_raise     \n"
483#ifdef __rtems__
484                "   movl    sse_test_check, %1\n"
485#else
486                "   movl    $0, %1       \n"
487#endif
488#ifdef TEST_MISMATCH
489                "       pxor %%xmm0, %%xmm0  \n"
490#endif
491                "       fxsave  %0           \n"
492                "       fxrstor %2           \n"
493        : "=m"(nctxt),"=&r"(rval),"=m"(orig_ctxt)
494        : "m"(octxt), "i"(SSE_TEST_HP_FAILED),"a"(kind)
495        : "xmm0"
496        );
497
498        if ( ( FPSR_IE & nctxt.fsw ) ) {
499                rval |= SSE_TEST_FSPR_FAILED;
500        }
501        if ( FP_EXC == kind )
502                nctxt.fsw |= (FPSR_IE | FPSR_ES);
503        else if ( SSE_EXC == kind ) {
504                tmp = __builtin_ia32_sqrtps( (__vf)(~sgn & (__v32)f4) );
505                /* sqrt raises PE; just clear it */
506                nctxt.mxcsr &= ~MXCSR_PE;
507                memcpy( octxt.xmmregs[0], &tmp, sizeof(tmp) );
508        }
509
510        if ( cmp_ctxt(&nctxt, &octxt, 0) ) {
511                rval |= SSE_TEST_CTXTCMP_FAILED;
512        }
513
514        s2 = sqrt(2.0);
515
516        asm volatile("fstsw %0":"=m"(fsw));
517
518        if ( sse_test_debug )
519                printf("sqrt(2): %f (FSTW: 0x%02"PRIx16")\n", sqrt(2.0), fsw);
520
521        return rval;
522}
523
524#ifdef __rtems__
525static void
526sse_test_ehdl(CPU_Exception_frame *p_f);
527
528rtems_id            sse_test_sync    = 0;
529cpuExcHandlerType   sse_test_ohdl    = 0;
530
531CPU_Exception_frame *sse_test_frame  = 0;
532volatile int        sse_test_check   = SSE_TEST_HP_FAILED;
533unsigned            sse_tests        = 0;
534
535rtems_task
536sse_test_hp_task(rtems_task_argument arg)
537{
538rtems_id sync = (rtems_id)arg;
539
540uint16_t                        fp_cw;
541uint32_t                        mxcsr;
542rtems_status_code   sc;
543const char *        msgs[] = {"FPU_EXC", "SSE_EXC", "IRQ_EXC"};
544int                 i;
545
546        /* verify that FPU control word is default value */
547        asm volatile("fstcw %0":"=m"(fp_cw));
548        if ( fp_cw != _CPU_Null_fp_context.fpucw ) {
549                fprintf(
550                        stderr,
551                        "ERROR: FPU CW initialization mismatch: got 0x%04"PRIx16"; expected 0x%04"PRIx16"\n",
552                        fp_cw,
553                        _CPU_Null_fp_context.fpucw
554                );
555        }
556
557        /* check MXCSR default value                     */
558        asm volatile("stmxcsr %0":"=m"(mxcsr));
559        if ( mxcsr != _CPU_Null_fp_context.mxcsr ) {
560                fprintf(
561                        stderr,
562                        "ERROR: MXCSR initialization mismatch: got 0x%08"PRIx32"; expected 0x%08"PRIx32"\n",
563                        mxcsr,
564                        _CPU_Null_fp_context.mxcsr
565                );
566        }
567
568
569        for (i=0; i<sizeof(msgs)/sizeof(msgs[0]); i++ ) {
570                if ( ( sse_tests & (1<<i) ) ) {
571                        if ( sse_test_debug )
572                                printk("HP task will now block for %s\n",msgs[i]);
573
574                        /* Blocking here lets the low-priority task continue */
575                        sc = rtems_semaphore_obtain(sync, RTEMS_WAIT, 500);
576
577                        all_clobber(0xaffeaffe, 0xcafecafe);
578
579                        if ( RTEMS_SUCCESSFUL != sc ) {
580                                rtems_error(sc,"ERROR: sse_test hp task wasn't notified of exception\n");
581                                goto bail;
582                        }
583
584                        /* set flag indicating that we executed until here */
585                        sse_test_check = 0;
586                }
587        }
588
589bail:
590        rtems_task_suspend(RTEMS_SELF);
591}
592
593/* Flags to skip individual tests */
594#define SSE_TEST_FPU_EXC  (1<<0)
595#define SSE_TEST_SSE_EXC  (1<<1)
596#define SSE_TEST_IRQ_EXC  (1<<2)
597
598#define SSE_TEST_ALL      7
599
600/* If this flag is given the executing task is not deleted
601 * when the test finishes. This is useful if you want to
602 * execute from a shell or similar.
603 */
604#define SSE_TEST_NO_DEL    (1<<0)
605
606/* Task arg is bitmask of these flags */
607rtems_task
608sse_test_lp_task(rtems_task_argument arg)
609{
610rtems_id                hp_task = 0;
611rtems_status_code       sc;
612rtems_task_priority     pri;
613uint16_t                fp_cw,fp_cw_set;
614uint32_t                mxcsr, mxcsr_set;
615rtems_irq_connect_data  irqd;
616int                     flags = (int)arg;
617int                     st;
618int                     errs = 0;
619
620        sse_tests = SSE_TEST_ALL & ~(flags>>1);
621
622        sse_test_ohdl = 0;
623
624        fp_cw_set = _CPU_Null_fp_context.fpucw | FPCW_RC(3) ;
625        mxcsr_set = _CPU_Null_fp_context.mxcsr | MXCSR_RC(3) ;
626        asm volatile("ldmxcsr %0"::"m"(mxcsr_set));
627        asm volatile("fldcw   %0"::"m"(fp_cw_set));
628
629        sc = rtems_semaphore_create(
630                        rtems_build_name('s','s','e','S'),
631                        0,
632                        RTEMS_SIMPLE_BINARY_SEMAPHORE,
633                        0,
634                        &sse_test_sync
635                );
636        if ( RTEMS_SUCCESSFUL != sc ) {
637                rtems_error(sc, "sse_test ERROR: creation of 'sync' semaphore failed");
638                errs++;
639                goto bail;
640        }
641
642        rtems_task_set_priority( RTEMS_SELF, RTEMS_CURRENT_PRIORITY, &pri );
643
644        sc = rtems_task_create(
645                        rtems_build_name('s','s','e','H'),
646                        pri - 2,
647                        20000,
648                        RTEMS_DEFAULT_MODES,
649                        RTEMS_FLOATING_POINT,
650                        &hp_task
651                );
652        if ( RTEMS_SUCCESSFUL != sc ) {
653                hp_task = 0;
654                rtems_error( sc, "sse_test ERROR: creation of high-priority task failed");
655                errs++;
656                goto bail;
657        }
658
659        sc = rtems_task_start( hp_task, sse_test_hp_task, (rtems_task_argument)sse_test_sync );
660        if ( RTEMS_SUCCESSFUL != sc ) {
661                rtems_error( sc, "sse_test ERROR: start of high-priority task failed");
662                goto bail;
663        }
664
665        /* Test if FP/SSE context is saved/restored across an exception */
666        sse_test_ohdl      = _currentExcHandler;
667        _currentExcHandler = sse_test_ehdl;
668
669        if ( (sse_tests & SSE_TEST_FPU_EXC) ) {
670                if ( (st = exc_raise(FP_EXC)) ) {
671                        prstat(st,"FP_EXC");
672                        errs++;
673                }
674
675                /* Test modified FPCW/MXCSR */
676                asm volatile("fstcw   %0":"=m"(fp_cw));
677                asm volatile("stmxcsr %0":"=m"(mxcsr));
678                mxcsr &= ~(MXCSR_ALLE);
679                if ( fp_cw != fp_cw_set ) {
680                        fprintf(stderr,"sse_test ERROR: FPCW mismatch (after FP_EXC): expected 0x%04"PRIx16", got 0x%04"PRIx16"\n", fp_cw_set, fp_cw);
681                        errs++;
682                }
683                if ( mxcsr != mxcsr_set ) {
684                        fprintf(stderr,"sse_test ERROR: MXCSR mismatch (after FP_EXC): expected 0x%08"PRIx32", got 0x%08"PRIx32"\n", mxcsr_set, mxcsr);
685                        errs++;
686                }
687        }
688
689        if ( (sse_tests & SSE_TEST_SSE_EXC) ) {
690                if ( (st = exc_raise(SSE_EXC)) ) {
691                        prstat(st, "SSE_EXC");
692                        errs++;
693                }
694
695                /* Test modified FPCW/MXCSR */
696                asm volatile("fstcw   %0":"=m"(fp_cw));
697                asm volatile("stmxcsr %0":"=m"(mxcsr));
698                mxcsr &= ~(MXCSR_ALLE);
699                if ( fp_cw != fp_cw_set ) {
700                        fprintf(stderr,"sse_test ERROR: FPCW mismatch (after SSE_EXC): expected 0x%04"PRIx16", got 0x%04"PRIx16"\n", fp_cw_set, fp_cw);
701                        errs++;
702                }
703                if ( mxcsr != mxcsr_set ) {
704                        fprintf(stderr,"sse_test ERROR: MXCSR mismatch (after SSE_EXC): expected 0x%08"PRIx32", got 0x%08"PRIx32"\n", mxcsr_set, mxcsr);
705                        errs++;
706                }
707        }
708
709
710        if ( (sse_tests & SSE_TEST_IRQ_EXC) ) {
711                memset( &irqd, 0, sizeof(irqd) );
712                irqd.name   = SSE_TEST_IRQ;
713                irqd.hdl    = (void*)sse_test_ehdl;
714                irqd.handle = 0;
715
716                if ( ! BSP_install_rtems_irq_handler( &irqd ) ) {
717                        fprintf(stderr, "sse_test ERROR: Unable to install ISR\n");
718                        errs++;
719                        goto bail;
720                }
721
722                /* Test if FP/SSE context is saved/restored across an interrupt */
723                if ( (st = exc_raise(IRQ_EXC)) ) {
724                        prstat(st, "IRQ");
725                        errs++;
726                }
727
728                if ( ! BSP_remove_rtems_irq_handler( &irqd ) ) {
729                        fprintf(stderr, "sse_test ERROR: Unable to uninstall ISR\n");
730                }
731
732                /* Test modified FPCW/MXCSR */
733                asm volatile("fstcw   %0":"=m"(fp_cw));
734                asm volatile("stmxcsr %0":"=m"(mxcsr));
735                mxcsr &= ~(MXCSR_ALLE);
736                if ( fp_cw != fp_cw_set ) {
737                        fprintf(stderr,"sse_test ERROR: FPCW mismatch (after IRQ): expected 0x%04"PRIx16", got 0x%04"PRIx16"\n", fp_cw_set, fp_cw);
738                        errs++;
739                }
740                if ( mxcsr != mxcsr_set ) {
741                        fprintf(stderr,"sse_test ERROR: MXCSR mismatch (after IRQ): expected 0x%08"PRIx32", got 0x%08"PRIx32"\n", mxcsr_set, mxcsr);
742                        errs++;
743                }
744        }
745
746
747bail:
748        /* Wait for console to calm down... */
749        rtems_task_wake_after(5);
750        fprintf(stderr,"SSE/FPU Test %s (%u errors)\n", errs ? "FAILED":"PASSED", errs);
751        if ( sse_test_ohdl ) {
752                _currentExcHandler = sse_test_ohdl;
753                sse_test_ohdl      = 0;
754        }
755        if ( sse_test_sync )
756                rtems_semaphore_delete( sse_test_sync );
757        sse_test_sync = 0;
758        if ( hp_task )
759                rtems_task_delete( hp_task );
760
761        if ( ! (flags & SSE_TEST_NO_DEL) )
762                rtems_task_delete( RTEMS_SELF );
763}
764
765static void
766sse_test_ehdl(CPU_Exception_frame *p_f)
767{
768int i,j,start = 0;
769int mismatch;
770__vf    f4;
771
772        if ( p_f ) {
773                printk("Got exception #%u\n",        p_f->idtIndex);
774                printk("EIP: 0x%08x, ESP: 0x%08x\n", p_f->eip, p_f->esp0);
775                printk("TID: 0x%08x\n",              _Thread_Executing->Object.id);
776
777                if ( ! p_f->fp_ctxt ) {
778                        printk("ERROR: NO FP/SSE CONTEXT ATTACHED ??\n");
779                        sse_test_ohdl(p_f);
780                }
781                if ( 16 == p_f->idtIndex ) {
782                        printk("Resetting FP status (0x%04"PRIx16")\n", p_f->fp_ctxt->fsw);
783                        p_f->fp_ctxt->fsw = 0;
784                } else if ( 19 == p_f->idtIndex ) {
785                        start = 1;
786                        memcpy(&f4, p_f->fp_ctxt->xmmregs[0], sizeof(f4));
787                        f4 = -f4;
788                        memcpy(p_f->fp_ctxt->xmmregs[0], &f4, sizeof(f4));
789                        p_f->fp_ctxt->mxcsr &= ~MXCSR_ALLE;
790                } else {
791                        printk("(skipping non-FP exception)\n");
792                        sse_test_ohdl(p_f);
793                }
794
795                printk("Checking XMM regs -- ");
796                for ( mismatch=0, i=start; i<8; i++ ) {
797                        for ( j=0; j<16; j++ ) {
798                                if ( p_f->fp_ctxt->xmmregs[i][j] != ((i<<4) | j) )
799                                        mismatch++;
800                        }
801                }
802                if ( mismatch ) {
803                        printk("%u mismatches; dump:\n", mismatch);
804                        for ( i=0; i<8; i++ ) {
805                                for ( j=0; j<16; j++ ) {
806                                        printk("0x%02x ", p_f->fp_ctxt->xmmregs[i][j]);
807                                }
808                                printk("\n");
809                        }
810                } else {
811                        printk("OK\n");
812                }
813        } else {
814                printk("IRQ %u\n", SSE_TEST_IRQ);
815        }
816        printk("Clobbering FPU/SSE state\n");
817        asm volatile("finit");
818        sse_clobber(0xdeadbeef);
819        printk("Notifying task\n");
820        rtems_semaphore_release( sse_test_sync );       
821}
822
823#else
824
825/* Code using signals for testing under linux; unfortunately, 32-bit
826 * linux seems to pass no SSE context info to the sigaction...
827 */
828
829#include <signal.h>
830#include <ucontext.h>
831
832#define MKCASE(X) case FPE_##X: msg="FPE_"#X; break;
833
834#define CLRXMM(i) asm volatile("pxor %%xmm"#i", %%xmm"#i:::"xmm"#i)
835
836static void
837fpe_act(int signum, siginfo_t *p_info, void *arg3)
838{
839ucontext_t *p_ctxt = arg3;
840const char *msg    = "FPE_UNKNOWN";
841uint16_t   *p_fst;
842
843        if ( SIGFPE != signum ) {
844                fprintf(stderr,"WARNING: fpe_act handles SIGFPE\n");
845                return;
846        }
847        switch ( p_info->si_code ) {
848                default:
849                        fprintf(stderr,"WARNING: fpe_act got unkown code %u\n", p_info->si_code);
850                        return;
851                MKCASE(INTDIV);
852                MKCASE(INTOVF);
853                MKCASE(FLTDIV);
854                MKCASE(FLTOVF);
855                MKCASE(FLTUND);
856                MKCASE(FLTRES);
857                MKCASE(FLTINV);
858                MKCASE(FLTSUB);
859        }
860        fprintf(stderr,"Got SIGFPE (%s) @%p\n", msg, p_info->si_addr);
861#ifdef __linux__
862        fprintf(stderr,"Resetting FP status 0x%02lx\n", p_ctxt->uc_mcontext.fpregs->sw);
863        p_ctxt->uc_mcontext.fpregs->sw = 0;
864#ifdef TEST_MISMATCH
865        fp_st1((void*)&p_ctxt->uc_mcontext.fpregs->_st[3],2.345);
866#endif
867#endif
868
869        /* Clear FPU; if context is properly saved/restored around exception
870         * then this shouldn't disturb the register contents of the interrupted
871         * task/process.
872         */
873        asm volatile("finit");
874        sse_clobber(0xdeadbeef);
875}
876
877static void
878test(void)
879{
880Context_Control_sse ctxt;
881
882        stor_ctxt(&ctxt);
883        printf("FPCW: 0x%"PRIx16"\nFPSW: 0x%"PRIx16"\n", ctxt.fcw, ctxt.fsw);
884        printf("FTAG: 0x%"PRIx8"\n",ctxt.ftw);
885}
886
887int
888main(int argc, char **argv)
889{
890struct sigaction a1, a2;
891uint32_t         mxcsr;
892
893        memset(&a1, 0, sizeof(a1));
894
895        a1.sa_sigaction = fpe_act;
896        a1.sa_flags     = SA_SIGINFO;   
897
898        if ( sigaction(SIGFPE, &a1, &a2) ) {
899                perror("sigaction");
900                return 1;
901        }
902
903        asm volatile("stmxcsr %0":"=m"(mxcsr));
904        printf("MXCSR: 0x%08"PRIx32"\n", mxcsr);
905
906        test();
907        exc_raise(0);
908        return 0;
909}
910#endif
911
912/* Helpers to access CR4 and MXCSR */
913
914uint32_t
915mfcr4()
916{
917uint32_t rval;
918        asm volatile("mov %%cr4, %0":"=r"(rval));
919        return rval;
920}
921
922void
923mtcr4(uint32_t rval)
924{
925        asm volatile("mov %0, %%cr4"::"r"(rval));
926}
927
928uint32_t
929mfmxcsr()
930{
931uint32_t rval;
932        asm volatile("stmxcsr %0":"=m"(rval));
933        return rval;
934}
935
936void
937mtmxcsr(uint32_t rval)
938{
939        asm volatile("ldmxcsr %0"::"m"(rval));
940}
941
942
943float
944sseraise()
945{
946__vf f4={-2., -2., -2. -2.};
947float f;
948     f4 = __builtin_ia32_sqrtps( f4 );
949        memcpy(&f,&f4,sizeof(f));
950        return f;
951}
Note: See TracBrowser for help on using the repository browser.