fppArchLib.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:21k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* fppArchLib.c - floating-point coprocessor support library */
  2. /* Copyright 1984-2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01j,25mar02,hdn  added two APIs to detect illegal FPU usage (spr 70187)
  8. 01i,20nov01,hdn  doc clean up for 5.5
  9. 01h,21aug01,hdn  imported SSE support from T31 ver 01k
  10. 01g,21apr99,hdn  changed selector of the emulator exception handler.
  11. 01f,14jun95,hdn  added support for fpp emulation library from USS.
  12. 01e,25may95,ms   added fppRegsToCtx and fppCtxToRegs.
  13. 01d,10aug93,hdn  added two global variables for fppProbeSup().
  14. 01c,03jun93,hdn  updated to 5.1
  15.   - moved fppInit(), fppCreateHook(), fppSwapHook(),
  16.     fppTaskRegsShow() to src/all/fppLib.c.  
  17.   - changed to pointer to floating-point register to 
  18.     fppTasksRegs{S,G}et().
  19.   - added arrays fpRegIndex[], fpCtlRegIndex[].
  20.   - added fppArchTastInit().  
  21.   - included regs.h, intLib.h.
  22.                   - changed functions to ansi style
  23.   - changed VOID to void
  24. 01b,29sep92,hdn  fixed a bug.
  25. 01a,07apr92,hdn  written based on TRON version.
  26. */
  27. /*
  28. DESCRIPTION
  29. This library provides a low-level interface to the Intel Architecture
  30. Floating-Point Unit (FPU).  Routines fppTaskRegsShow(), fppTaskRegsSet(),
  31. and fppTaskRegsGet() inspect and set coprocessor registers on a per task
  32. basis.  The routine fppProbe() checks for the presence of the
  33. Intel Architecture FPU.  With the exception of fppProbe(), the higher
  34. level facilities in dbgLib and usrLib should be used instead of these
  35. routines.
  36. There are two kind of floating-point contexts and set of routines for 
  37. each kind.  One is 108 bytes for older FPU (i80387, i80487, Pentium) 
  38. and older MMX technology and fppSave(), fppRestore(), fppRegsToCtx(), 
  39. and fppCtxToRegs() are used to save and restore the context, convert to 
  40. or from the FPPREG_SET.
  41. The other is 512 bytes for newer FPU, newer MMX technology and streaming 
  42. SIMD technology (PentiumII, III, 4) and fppXsave(), fppXrestore(), 
  43. fppXregsToCtx(), and fppXctxToRegs() are used to save and restore 
  44. the context, convert to or from the FPPREG_SET.  
  45. Which to use is automatically detected by checking CPUID information in 
  46. fppArchInit().  And fppTaskRegsSet() and fppTaskRegsGet() access the 
  47. appropriate floating-point context.  The bit interrogated for the 
  48. automatic detection is the "Fast Save and Restore" feature flag.
  49. INITIALIZATION
  50. To activate floating-point support, fppInit() must be called before any
  51. tasks using the coprocessor are spawned.  If INCLUDE_FLOATING_POINT is
  52. defined in configAll.h, this is done by the root task, usrRoot(), in
  53. usrConfig.c.
  54. VX_FP_TASK OPTION 
  55. Saving and restoring floating-point registers adds to the context switch
  56. time of a task.
  57. Therefore, floating-point registers are f2notfP saved and restored for 
  58. f2everyfP task.  Only those tasks spawned with the task option VX_FP_TASK
  59. will have floating-point state, MMX technology state, and streaming SIMD 
  60. state saved and restored.  
  61. f3NOTE:fP  If a task does any floating-point operations, MMX operations,
  62. and streaming SIMD operation, it must be spawned with VX_FP_TASK.
  63. It is deadly to execute any floating-point operations in a task spawned 
  64. without VX_FP_TASK option, and very difficult to find.  To detect that
  65. illegal/unintentional/accidental floating-point operations, a new API and
  66. mechanism is added.  The mechanism is to enable or disable the FPU by 
  67. toggling the TS flag in the CR0 in the new task switch hook routine -
  68. fppArchSwitchHook() - respecting the VX_FP_TASK option.  If VX_FP_TASK
  69. option is not set in the switching-in task, the FPU is disabled.  Thus
  70. the device-not-available exception will be raised if that task does any 
  71. floating-point operations.  This mechanism is disabled in the default.
  72. To enable, call the enabler - fppArchSwitchHookEnable() - with a 
  73. parameter TRUE(1).  A parameter FALSE(0) disables the mechanism.
  74. MIXING MMX AND FPU INSTRUCTIONS
  75. A task with VX_FP_TASK option saves and restores the FPU and MMX state
  76. when performing a context switch.  Therefore, the application does not
  77. have to save or restore the FPU and MMX state if the FPU and MMX 
  78. instructions are not mixed within a task.  Because the MMX registers
  79. are aliased to the FPU registers, care must be taken when making
  80. transitions between FPU instructions and MMX instructions to prevent
  81. the loss of data in the FPU and MMX registers and to prevent incoherent
  82. or unexpected result.  When mixing MMX and FPU instructions within a 
  83. task, follow these guidelines from Intel:
  84.     - Keep the code in separate modules, procedures, or routines.
  85.     - Do not rely on register contents across transitions between FPU
  86.       and MMX code modules.
  87.     - When transitioning between MMX code and FPU code, save the MMX
  88.       register state (if it will be needed in the future) and execute
  89.       an EMMS instruction to empty the MMX state.
  90.     - When transitioning between FPU and MMX code, save the FPU state,
  91.       if it will be needed in the future.
  92. MIXING SSE/SSE2 AND FPU/MMX INSTRUCTIONS
  93. The XMM registers and the FPU/MMX registers represent separate 
  94. execution environments, which has certain ramifications when executing
  95. SSE, SSE2, MMX and FPU instructions in the same task context:
  96.     - Those SSE and SSE2 instruction that operate only on the XMM 
  97.       registers (such as the packed and scalar floating-point
  98.       instructions and the 128-bit SIMD integer instructions) can be
  99.       executed in the same instruction stream with 64-bit SIMD integer
  100.       or FPU instructions without any restrictions.  For example, an
  101.       application can perform the majority of its floating-point 
  102.       computations in the XMM registers, using the packed and scalar
  103.       floating-point instructions, and at the same time use the FPU
  104.       to perform trigonometric and other transcendental computations.
  105.       Likewise, an application can perform packed 64-bit and 128-bit
  106.       SIMD integer operations can be executed together without
  107.       restrictions.
  108.     - Those SSE and SSE2 instructions that operate on MMX registers
  109.       (such as the CVTPS2PI, CVTTPS2PI, CVTPI2PS, CVTPD2PI, CVTTPD2PI,
  110.       CVTPI2PD, MOVDQ2Q, MOVQ2DQ, PADDQ, and PSUBQ instructions) can
  111.       also be executed in the same instruction stream as 64-bit SIMD
  112.       integer or FPU instructions, however, here they subject to the
  113.       restrictions on the simultaneous use of MMX and FPU instructions,
  114.       which mentioned in the previous paragraph.
  115. INTERRUPT LEVEL
  116. Floating-point registers are f2notfP saved and restored for interrupt
  117. service routines connected with intConnect().  However, if necessary,
  118. an interrupt service routine can save and restore floating-point registers
  119. by calling routines in fppALib.  See the manual entry for intConnect() for
  120. more information.
  121. EXCEPTIONS
  122. There are six FPU exceptions that can send an exception to the CPU.  They 
  123. are controlled by Exception Mask bits of the Control Word register.  VxWorks 
  124. disables them in the default configuration.  They
  125. are:
  126.     - Precision
  127.     - Overflow
  128.     - Underflow
  129.     - Division by zero
  130.     - Denormalized operand
  131.     - Invalid Operation
  132.   
  133. SEE ALSO: fppALib, intConnect(), Intel Architecture Software Developer's Manual
  134. */
  135. #include "vxWorks.h"
  136. #include "objLib.h"
  137. #include "taskLib.h"
  138. #include "taskArchLib.h"
  139. #include "memLib.h"
  140. #include "string.h"
  141. #include "iv.h"
  142. #include "intLib.h"
  143. #include "regs.h"
  144. #include "fppLib.h"
  145. #include "vxLib.h"
  146. #include "taskHookLib.h"
  147. /* externals */
  148. IMPORT CPUID sysCpuId;
  149. IMPORT int sysCsExc;
  150. IMPORT void intVecSet2 (FUNCPTR * vec, FUNCPTR func, int idtGate, 
  151.     int idtSelector);
  152. /* globals */
  153. REG_INDEX fpRegName [] = /* FP non-control register name and offset */
  154.     {
  155.     {"st/mm0", FPREG_FPX(0)},
  156.     {"st/mm1", FPREG_FPX(1)},
  157.     {"st/mm2", FPREG_FPX(2)},
  158.     {"st/mm3", FPREG_FPX(3)},
  159.     {"st/mm4", FPREG_FPX(4)},
  160.     {"st/mm5", FPREG_FPX(5)},
  161.     {"st/mm6", FPREG_FPX(6)},
  162.     {"st/mm7", FPREG_FPX(7)},
  163.     {NULL, 0},
  164.     };
  165. REG_INDEX fpCtlRegName [] = /* FP control register name and offset */
  166.     {
  167.     {"fpcr", FPREG_FPCR},
  168.     {"fpsr", FPREG_FPSR},
  169.     {"fptag", FPREG_FPTAG},
  170.     {"op", FPREG_OP},
  171.     {"ip", FPREG_IP},
  172.     {"cs", FPREG_CS},
  173.     {"dp", FPREG_DP},
  174.     {"ds", FPREG_DS},
  175.     {NULL, 0},
  176.     };
  177. int fppFsw = 0;
  178. int fppFcw = 0;
  179. VOIDFUNCPTR emu387Func = NULL; /* func ptr to trap handler */
  180. VOIDFUNCPTR emuInitFunc = NULL; /* func ptr to initializer */
  181. VOIDFUNCPTR _func_fppSaveRtn = NULL; /* func ptr to fppSave/fppXsave */
  182. VOIDFUNCPTR _func_fppRestoreRtn = NULL; /* func ptr to fppRestore/fppXrestore */
  183. /* locals */
  184. LOCAL FP_CONTEXT * pFppInitContext; /* pointer to initial FP context */
  185. /*******************************************************************************
  186. *
  187. * fppArchInit - initialize floating-point coprocessor support
  188. *
  189. * This routine must be called before using the floating-point coprocessor.
  190. * It is typically called from fppInit().  
  191. *
  192. * NOMANUAL
  193. */
  194. void fppArchInit (void)
  195.     {
  196.     
  197.     /* initialize the function pointer and the CR4 OSFXSR bit */
  198.     if (sysCpuId.featuresEdx & CPUID_FXSR)
  199. {
  200. _func_fppSaveRtn = fppXsave; /* new FP save routine */
  201. _func_fppRestoreRtn = fppXrestore; /* new FP restore routine */
  202. vxCr4Set (vxCr4Get () | CR4_OSFXSR); /* set OSFXSR bit */
  203. }
  204.     else
  205. {
  206. _func_fppSaveRtn = fppSave; /* old FP save routine */
  207. _func_fppRestoreRtn = fppRestore; /* old FP restore routine */
  208. vxCr4Set (vxCr4Get () & ~CR4_OSFXSR); /* clear OSFXSR bit */
  209. }
  210.     fppCreateHookRtn = (FUNCPTR) NULL;
  211.     /* allocate and initialize the initial FP_CONTEXT */
  212.     pFppInitContext = (FP_CONTEXT *) memalign 
  213.      (_CACHE_ALIGN_SIZE, sizeof (FP_CONTEXT));
  214.     (*_func_fppSaveRtn) (pFppInitContext);
  215.     }
  216. /*******************************************************************************
  217. *
  218. * fppArchTaskCreateInit - initialize floating-point coprocessor support for task
  219. *
  220. * INTERNAL
  221. * It might seem odd that we use a bcopy() to initialize the floating point
  222. * context when a fppSave() of an idle frame would accomplish the same thing
  223. * without the cost of a 108/512 byte data structure.  The problem is that we
  224. * are not guaranteed to have an idle frame.  Consider the following scenario:
  225. * a floating point task is midway through a floating point instruction when
  226. * it is preempted by a *non-floting point* task.  In this case the swap-in
  227. * hook does not save the coprocessor state as an optimization.  Now if we
  228. * create a floating point task the initial coprocessor frame would not be
  229. * idle but rather mid-instruction.  To make matters worse when get around
  230. * to saving the original fp task's floating point context frame, it would be
  231. * incorrectly saved as idle!  One solution would be to fppSave() once to
  232. * the original fp task's context, then fppSave() an idle frame to the new task,
  233. * and finally restore the old fp task's context (in case we return to it
  234. * before another fp task).  The problem with this approach is that it is
  235. * *slow* and considering the fact that preemption is locked, the 108/512 bytes
  236. * don't look so bad anymore.  Indeed, when this approach is adopted by all
  237. * architectures we will not need to lock out preemption anymore.
  238. *
  239. * NOMANUAL
  240. */
  241. void fppArchTaskCreateInit
  242.     (
  243.     FP_CONTEXT * pFpContext /* pointer to FP_CONTEXT */
  244.     )
  245.     {
  246.     if (sysCpuId.featuresEdx & CPUID_FXSR)
  247. {
  248. bcopyLongs ((char *) pFppInitContext, (char *)pFpContext,
  249.             (sizeof (FPX_CONTEXT) >> 2)); /* copy 512>>2 longs */
  250. }
  251.     else
  252. {
  253. bcopyLongs ((char *) pFppInitContext, (char *)pFpContext,
  254.             (sizeof (FPO_CONTEXT) >> 2)); /* copy 108>>2 longs */
  255. }
  256.     }
  257. /******************************************************************************
  258. *
  259. * fppRegsToCtx - convert FPREG_SET to FPO_CONTEXT.
  260. */ 
  261. void fppRegsToCtx
  262.     (
  263.     FPREG_SET *  pFpRegSet,             /* input -  fpp reg set */
  264.     FP_CONTEXT * pFpContext             /* output - fpp context */
  265.     )
  266.     {
  267.     int ix;
  268.     for (ix = 0; ix < FP_NUM_REGS; ix++)
  269.         fppDtoDx ((DOUBLEX *)&pFpContext->u.o.fpx[ix], 
  270.                   (double *)&pFpRegSet->fpx[ix]);
  271.     pFpContext->u.o.fpcr  = pFpRegSet->fpcr;
  272.     pFpContext->u.o.fpsr  = pFpRegSet->fpsr;
  273.     pFpContext->u.o.fptag = pFpRegSet->fptag;
  274.     pFpContext->u.o.op    = pFpRegSet->op;
  275.     pFpContext->u.o.ip    = pFpRegSet->ip;
  276.     pFpContext->u.o.cs    = pFpRegSet->cs;
  277.     pFpContext->u.o.dp    = pFpRegSet->dp;
  278.     pFpContext->u.o.ds    = pFpRegSet->ds;
  279.     }
  280. /******************************************************************************
  281. *
  282. * fppCtxToRegs - convert FPO_CONTEXT to FPREG_SET.
  283. */ 
  284. void fppCtxToRegs
  285.     (
  286.     FP_CONTEXT * pFpContext,            /* input -  fpp context */
  287.     FPREG_SET *  pFpRegSet              /* output - fpp register set */
  288.     )
  289.     {
  290.     int ix;
  291.     for (ix = 0; ix < FP_NUM_REGS; ix++)
  292.         fppDxtoD ((double *)&pFpRegSet->fpx[ix], 
  293.                   (DOUBLEX *)&pFpContext->u.o.fpx[ix]);
  294.     pFpRegSet->fpcr  = pFpContext->u.o.fpcr;
  295.     pFpRegSet->fpsr  = pFpContext->u.o.fpsr;
  296.     pFpRegSet->fptag = pFpContext->u.o.fptag;
  297.     pFpRegSet->op    = pFpContext->u.o.op;
  298.     pFpRegSet->ip    = pFpContext->u.o.ip;
  299.     pFpRegSet->cs    = pFpContext->u.o.cs;
  300.     pFpRegSet->dp    = pFpContext->u.o.dp;
  301.     pFpRegSet->ds    = pFpContext->u.o.ds;
  302.     }
  303. /******************************************************************************
  304. *
  305. * fppXregsToCtx - convert FPREG_SET to FPX_CONTEXT.
  306. */ 
  307. void fppXregsToCtx
  308.     (
  309.     FPREG_SET *  pFpRegSet,             /* input -  fpp reg set */
  310.     FP_CONTEXT * pFpContext             /* output - fpp context */
  311.     )
  312.     {
  313.     int ix;
  314.     for (ix = 0; ix < FP_NUM_REGS; ix++)
  315.         fppDtoDx ((DOUBLEX *)&pFpContext->u.x.fpx[ix], 
  316.                   (double *)&pFpRegSet->fpx[ix]);
  317.     pFpContext->u.x.fpcr  = pFpRegSet->fpcr;
  318.     pFpContext->u.x.fpsr  = pFpRegSet->fpsr;
  319.     pFpContext->u.x.fptag = pFpRegSet->fptag;
  320.     pFpContext->u.x.op    = pFpRegSet->op;
  321.     pFpContext->u.x.ip    = pFpRegSet->ip;
  322.     pFpContext->u.x.cs    = pFpRegSet->cs;
  323.     pFpContext->u.x.dp    = pFpRegSet->dp;
  324.     pFpContext->u.x.ds    = pFpRegSet->ds;
  325.     }
  326. /******************************************************************************
  327. *
  328. * fppXctxToRegs - convert FPX_CONTEXT to FPREG_SET.
  329. */ 
  330. void fppXctxToRegs
  331.     (
  332.     FP_CONTEXT * pFpContext,            /* input -  fpp context */
  333.     FPREG_SET *  pFpRegSet              /* output - fpp register set */
  334.     )
  335.     {
  336.     int ix;
  337.     for (ix = 0; ix < FP_NUM_REGS; ix++)
  338.         fppDxtoD ((double *)&pFpRegSet->fpx[ix], 
  339.                   (DOUBLEX *)&pFpContext->u.x.fpx[ix]);
  340.     pFpRegSet->fpcr  = pFpContext->u.x.fpcr;
  341.     pFpRegSet->fpsr  = pFpContext->u.x.fpsr;
  342.     pFpRegSet->fptag = pFpContext->u.x.fptag;
  343.     pFpRegSet->op    = pFpContext->u.x.op;
  344.     pFpRegSet->ip    = pFpContext->u.x.ip;
  345.     pFpRegSet->cs    = pFpContext->u.x.cs;
  346.     pFpRegSet->dp    = pFpContext->u.x.dp;
  347.     pFpRegSet->ds    = pFpContext->u.x.ds;
  348.     }
  349. /*******************************************************************************
  350. *
  351. * fppTaskRegsGet - get the floating-point registers from a task TCB
  352. *
  353. * This routine copies the floating-point registers of a task
  354. * (control, status, and tag) to the locations whose pointers are passed as
  355. * parameters.  The floating-point registers are copied in
  356. * an array containing the 8 registers.
  357. *
  358. * NOTE
  359. * This routine only works well if <task> is not the calling task.  
  360. * If a task tries to get its own registers, the values will be stale 
  361. * (i.e., left over from the last task switch).
  362. *
  363. * RETURNS: OK, or ERROR if there is no floating-point 
  364. * support or there is an invalid state.
  365. *
  366. * SEE ALSO: fppTaskRegsSet()
  367. */
  368. STATUS fppTaskRegsGet
  369.     (
  370.     int task, /* task to get info about          */
  371.     FPREG_SET * pFpRegSet /* pointer to floating-point register set */
  372.     )
  373.     {
  374.     WIND_TCB * pTcb = taskTcb (task);
  375.     FP_CONTEXT * pFpContext;
  376.     if ((pTcb == NULL) ||
  377.         ((pFpContext = pTcb->pFpContext) == (FP_CONTEXT *)NULL))
  378. return (ERROR); /* no coprocessor support */
  379.     if (sysCpuId.featuresEdx & CPUID_FXSR)
  380. fppXctxToRegs (pFpContext, pFpRegSet);
  381.     else
  382. fppCtxToRegs (pFpContext, pFpRegSet);
  383.     return (OK);
  384.     }
  385. /*******************************************************************************
  386. *
  387. * fppTaskRegsSet - set the floating-point registers of a task 
  388. *
  389. * This routine loads the specified values into the specified task TCB.
  390. * The 8 registers st/mm0 - st/mm7 are copied to the array <fpregs>.
  391. *
  392. * RETURNS: OK, or ERROR if there is no floating-point
  393. * support or there is an invalid state.
  394. *
  395. * SEE ALSO: fppTaskRegsGet()
  396. */
  397. STATUS fppTaskRegsSet
  398.     (
  399.     int task, /* task whose registers are to be set */
  400.     FPREG_SET * pFpRegSet /* pointer to floating-point register set */
  401.     )
  402.     {
  403.     WIND_TCB * pTcb = taskTcb (task);
  404.     FP_CONTEXT * pFpContext;
  405.     if ((pTcb == NULL) ||
  406.         ((pFpContext = pTcb->pFpContext) == (FP_CONTEXT *)NULL))
  407. return (ERROR); /* no coprocessor support */
  408.     if (sysCpuId.featuresEdx & CPUID_FXSR)
  409. fppXregsToCtx (pFpRegSet, pFpContext);
  410.     else
  411. fppRegsToCtx (pFpRegSet, pFpContext);
  412.     return (OK);
  413.     }
  414. /*******************************************************************************
  415. *
  416. * fppProbe - probe for the presence of a floating-point coprocessor
  417. *
  418. * This routine determines whether there is an Intel Architecture 
  419. * Floating-Point Unit (FPU) in the system.
  420. *
  421. * IMPLEMENTATION
  422. * This routine sets the illegal coprocessor op-code trap vector and executes
  423. * a coprocessor instruction.  If the instruction causes an exception,
  424. * fppProbe() will return ERROR.  Note that this routine saves and restores
  425. * the illegal coprocessor op-code trap vector that was present prior to this
  426. * call.
  427. *
  428. * The probe is only performed the first time this routine is called.
  429. * The result is stored in a static and returned on subsequent
  430. * calls without actually probing.
  431. *
  432. * RETURNS:
  433. * OK if the floating-point coprocessor is present, otherwise ERROR.
  434. */
  435. STATUS fppProbe (void)
  436.     {
  437.     static int fppProbed = -2; /* -2 = not done, -1 = ERROR, 0 = OK */
  438.     if (fppProbed == -2)
  439. {
  440. fppProbed = fppProbeSup (); /* check ET bit in %cr0 */
  441.         if (fppProbed == ERROR)
  442.             {
  443.             if ((emuInitFunc != NULL) && (emu387Func != NULL))
  444.                 {
  445.                 intVecSet2 ((FUNCPTR *)IV_NO_DEVICE, (FUNCPTR)emu387Func,
  446.     IDT_TRAP_GATE, sysCsExc);
  447.                 (* emuInitFunc) ();             /* initialize the emulator */
  448.                 fppProbed = OK;                 /* pretend as we have 80387 */
  449.                 }
  450.             }
  451. }
  452.     return (fppProbed);
  453.     }
  454. /*******************************************************************************
  455. *
  456. * fppArchSwitchHook - switch hook routine to set or clear the TS flag in CR0
  457. *
  458. * This routine is a switch hook routine to set or clear the TS flag in CR0.
  459. * The purpose of toggling the TS bit is to detect an illegal FPU/MMX 
  460. * instruction usage without the task option VX_FP_TASK.  The TS flag is set 
  461. * when the new task's VX_FP_TASK bit is set, and cleared otherwise.
  462. * Setting the TS flag generates the device-not-available exception prior 
  463. * to the execution of a FPU/MMX instruction.  Since the MP flag in CR0 is 
  464. * cleared in the default, the execution of WAIT/FWAIT instruction does not 
  465. * raise the exception.  The swap hook routines or switch hook routines that 
  466. * are executed prior to this routine may need to clear the TS bit by itself 
  467. * before using the FPU/MMX instructions.
  468. *
  469. * RETURNS: N/A
  470. */
  471. void fppArchSwitchHook
  472.     (
  473.     WIND_TCB * pOldTcb, /* pointer to old task's WIND_TCB */
  474.     WIND_TCB * pNewTcb /* pointer to new task's WIND_TCB */
  475.     )
  476.     {
  477.     INT32 tempReg; 
  478.     /* enable(clear the TS flag) or disbale(set the TS flag) FPU */
  479.     if (pNewTcb->options & VX_FP_TASK)
  480. {
  481. WRS_ASM ("clts"); /* clear TS */
  482. }
  483.     else
  484. {
  485. WRS_ASM ("movl %%cr0,%0; orl $0x8,%0; movl %0,%%cr0;" 
  486.  : "=r" (tempReg) : : "memory"); /* set TS */
  487. }
  488.     }
  489. /*******************************************************************************
  490. *
  491. * fppArchSwitchHookEnable - enable or disable the switch hook routine 
  492. *
  493. * This routine is enables or disables the architecture specific FPU switch
  494. * hook routine that detect the illegal FPU/MMX usage.  
  495. * Ths usage of this mechanism is optional, and disabled in the default.
  496. *
  497. * RETURNS: OK, or ERROR if the associated Add/Delete routine failed.
  498. */
  499. STATUS fppArchSwitchHookEnable
  500.     (
  501.     BOOL enable /* TRUE to enable, FALSE to disable */
  502.     )
  503.     {
  504.     static INT32 oldCr0 = 0; /* default: TS flag cleared */
  505.     INT32 tempReg; 
  506.     if (enable)
  507. {
  508. if (taskSwitchHookAdd ((FUNCPTR) fppArchSwitchHook) != OK)
  509.     return (ERROR);
  510. /* save the TS flag */
  511.         oldCr0 = vxCr0Get ();
  512. /* enable(clear the TS flag) or disbale(set the TS flag) FPU */
  513. if (taskIdCurrent->options & VX_FP_TASK)
  514.     {
  515.     WRS_ASM ("clts"); /* clear TS */
  516.     }
  517. else
  518.     {
  519.     WRS_ASM ("movl %%cr0,%0; orl $0x8,%0; movl %0,%%cr0;" 
  520.      : "=r" (tempReg) : : "memory"); /* set TS */
  521.     }
  522. }
  523.     else
  524. {
  525. if (taskSwitchHookDelete ((FUNCPTR) fppArchSwitchHook) != OK)
  526.     return (ERROR);
  527. /* restore the TS flag */
  528. if (oldCr0 & CR0_TS)
  529.     {
  530.     WRS_ASM ("movl %%cr0,%0; orl $0x8,%0; movl %0,%%cr0;" 
  531.      : "=r" (tempReg) : : "memory"); /* set TS */
  532.     }
  533. else
  534.     {
  535.     WRS_ASM ("clts"); /* clear TS */
  536.     }
  537. }
  538.     return (OK);
  539.     }