Windows in 386 enhanced mode runs at input and output (I/O) privilege level 0 (IOPL0). At this level, the popf and iret instructions will not change the state of the interrupt flag. (Other flags will still be saved and restored.) This means, for example, that the following code will leave interrupts disabled upon completion:
pushf ; This is no longer valid code
cli
.
.
.
popf ; Leaves interrupts disabled
In this IOPL0 environment, sti and cli are the only instructions that will change the interrupt flag. Upon exiting a critical section of code in which you require interrupts to be disabled, you cannot rely on the popf instruction to restore the state of the interrupt flag. Instead, upon examining the interrupt flag, you should explicitly set it to its saved value (saved by a previous pushf instruction). The following example illustrates the proper method for restoring the interrupt flag:
pushf ; This code illustrates the proper technique
cli
.
.
.
pop ax
test ah,2
jz SkipSTI
sti
SkipSTI:
.
.
.
If you have used a software interrupt hook that calls the next interrupt handler in the chain, you similarly cannot rely on the iret instruction of the next interrupt handler to return the state of the interrupt flag. The following code, for example, is incorrect:
My_SW_Int_Hook: ; The following is incorrect
sti
.
.
.
pushf ; Simulate interrupt call with a pushf
cli ; and a cli
call [Next_Handler_In_Chain]
; The IRET of the next interrupt handler will not restore
; the interrupt flag, so it may be left cleared
; (interrupts disabled)
.
.
.
iret
The proper technique is to place an sti instruction immediately after the call to the next interrupt handler, to enable interrupts again in case the next interrupt handler leaves interrupts disabled. This technique is shown in the following example:
My_SW_Int_Hook: ; The following is correct
sti
.
.
.
pushf ; Simulate interrupt call with a pushf
cli ; and a cli
call [Next_Handler_In_Chain]
sti ; Enable interrupts again in case next handler disables them
.
.
.
iret