Код, на который вы смотрите, имеет свои достоинства.Вероятно, тот, кто написал это, знает, что POPF
не обрабатывает флаг прерывания ( IF ) одинаково во всех различных режимах работы.
Вероятно, они пытаются избежать этих двух шаблонов кода:
sti
pushf ; Save flags including interrupts (IF)
cli
; Do work here with interrupts off
popf ; Restore interrupts (re-enable IF)
; Interrupts may still be off at this point depending on mode and IO Privileges
или
cli
pushf ; Save flags including interrupts (IF)
sti
; Do work here with interrupts on
popf ; Restore interrupts to previous state
; Interrupts may still be on at this point depending on mode and IO privileges
В этих двух случаях IF фактически был изменен, и POPF , как ожидается, восстановит IF до его предыдущего значения.Если вы просматриваете первую диаграмму, я обвел ее N .Это те случаи, когда вы находитесь в защищенном режиме, режиме совместимости или 64-битном режиме, и текущий уровень привилегий (CPL) равен 1,2,3, а IOPL (уровень привилегий IO) POPF не будет генерировать общую ошибку защиты и будет молча игнорировать изменение на IF .
Поскольку ошибки нет, ядро не имеетлюбая идея, что была попытка изменить IF , поэтому не имеет шансов виртуализировать IF . STI и CLI действуют как привилегированные инструкции, когда они не имеют надлежащих привилегий IOPL, и будут вызывать ошибки в ядре, где IF может быть виртуализирован процессором.
На вопрос, почему в исходном коде делается явное STI / CLI ? STI / CLI гарантирует ошибку, которую ядро может перехватить в случаях, когда у вас нет надлежащих привилегий IOPL для обновления IF . POPF может позволить IF стать не синхронизированным с понятием того, что программа думает, что флаг должен быть.Используя STI и CLI для изменения IF , вы позволяете ядру более легко поддерживать синхронизацию.
DPMI (DOSИнтерфейс защищенного режима) спецификация обсуждает эту проблему и описывается следующим образом:
2.3 Управление флагом прерывания Команды popf и iret могут не изменять состояние флага прерывания, так как большинство DPMIРеализации будут запускать программы с IOPL
Это означает, что следующая последовательность кода будет оставлять прерывания отключенными:
;
; (Assume interrupts are enabled at this point)
;
pushf
cli
.
.
popf ; Interrupts are still OFF!
Обратите внимание, что, поскольку некоторые реализации DPMI будут поддерживатьВиртуальное состояние прерывания для программ DOS защищенного режима, текущее значение флага прерывания может не отражать текущее состояние виртуального прерывания.Программы защищенного режима должны использовать службы состояния виртуального прерывания для определения текущего состояния флага прерывания (см. Стр. 99).
Поскольку cli и sti являются привилегированными инструкциями, они вызовут нарушение защиты, и поставщик DPMI будет имитироватьинструкция.Из-за накладных расходов, связанных с обработкой исключения, cli и sti следует использовать как можно меньше.В целом, вы должны ожидать, что любая из этих инструкций потребует не менее 300 часов.