background image

Vol. 1 D-15

GUIDELINES FOR WRITING X87 FPU EXCEPTION HANDLERS

D.3.5  

Need for Storing State of IGNNE# Circuit If Using x87 FPU and SMM

The recommended circuit (see Figure D-1) for MS-DOS compatibility x87 FPU exception handling for Intel486 
processors and beyond contains two flip flops. When the x87 FPU exception handler accesses I/O port 0F0H it 
clears the IRQ13 interrupt request output from Flip Flop #1 and also clocks out the IGNNE# signal (active) from 
Flip Flop #2. 
The assertion of IGNNE# may be used by the handler if needed to execute any x87 FPU instruction while ignoring 
the pending x87 FPU errors. The problem here is that the state of Flip Flop #2 is effectively an additional (but 
hidden) status bit that can affect processor behavior, and so ideally should be saved upon entering SMM, and 
restored before resuming to normal operation. If this is not done, and also the SMM code saves the x87 FPU state, 
AND an x87 FPU error handler is being used which relies on IGNNE# assertion, then (very rarely) the x87 FPU 
handler will nest inside itself and malfunction. The following example shows how this can happen.
Suppose that the x87 FPU exception handler includes the following sequence:

FNSTSW save_sw 

; save the x87 FPU status word 
; using a no-wait x87 FPU instruction

OUT

0F0H, AL 

; clears IRQ13 & activates IGNNE#

 . . . .
FLDCW new_cw

; loads new CW ignoring x87 FPU errors, 

 

; since IGNNE# is assumed active; or any 
; other x87 FPU instruction that is not a no-wait 
; type will cause the same problem

 . . . .
FCLEX

; clear the x87 FPU error conditions & thus 
; turn off FERR# & reset the IGNNE# FF

The problem will only occur if the processor enters SMM between the OUT and the FLDCW instructions. But if that 
happens, AND the SMM code saves the x87 FPU state using FNSAVE, then the IGNNE# Flip Flop will be cleared 
(because FNSAVE clears the x87 FPU errors and thus de-asserts FERR#). When the processor returns from SMM it 
will restore the x87 FPU state with FRSTOR, which will re-assert FERR#, but the IGNNE# Flip Flop will not get set. 
Then when the x87 FPU error handler executes the FLDCW instruction, the active error condition will cause the 
processor to re-enter the x87 FPU error handler from the beginning. This may cause the handler to malfunction.
To avoid this problem, Intel recommends two measures:
1. Do not use the x87 FPU for calculations inside SMM code. (The normal power management, and sometimes 

security, functions provided by SMM have no need for x87 FPU calculations; if they are needed for some special 
case, use scaling or emulation instead.) This eliminates the need to do FNSAVE/FRSTOR inside SMM code, 
except when going into a 0 V suspend state (in which, in order to save power, the CPU is turned off completely, 
requiring its complete state to be saved).

2. The system should not call upon SMM code to put the processor into 0 V suspend while the processor is running 

x87 FPU calculations, or just after an interrupt has occurred. Normal power management protocol avoids this 
by going into power down states only after timed intervals in which no system activity occurs.

D.3.6  

Considerations When x87 FPU Shared Between Tasks

The IA-32 architecture allows speculative deferral of floating-point state swaps on task switches. This feature 
allows postponing an x87 FPU state swap until an x87 FPU instruction is actually encountered in another task. Since 
kernel tasks rarely use floating-point, and some applications do not use floating-point or use it infrequently, the 
amount of time saved by avoiding unnecessary stores of the floating-point state is significant. Speculative deferral 
of x87 FPU saves does, however, place an extra burden on the kernel in three key ways:
1. The kernel must keep track of which thread owns the x87 FPU, which may be different from the currently 

executing thread.

2. The kernel must associate any floating-point exceptions with the generating task. This requires special 

handling since floating-point exceptions are delivered asynchronous with other system activity.