logo

Главная Система команд x86 Базовая система команд CPU POPF

Система команд x86

Программирование - Архитектура и система команд микропроцессоров x86
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

POPF

Восстановить из стека регистр FLAGS

Влияние команды на флаги и форматы команды:

OF

DF

IF

TF

SF

ZF

AF

PF

CF

*

*

*

*

*

*

*

*

*

 

Код

Команда

Описание

Проц.

Пример

9D

POPF

Загрузить из стека регистр FLAGS

8086

popf

9D

POPFD

Загрузить из стека регистр EFLAGS

Intel386

popfd

Описание:

Команда POPF/POPFD считывает слово или двойное слово из вершины стека и сохраняет его в регистре флагов (E)FLAGS. Если атрибут размера операнда этой команды равен 16 бит (команда POPF), то считывается слово в регистр FLAGS, если атрибут размера операнда равен 32 бита (команда POPFD), то считывается двойное слово в регистр EFLAGS. Обратное действие может быть выполнено командой PUSHF/PUSHFD.

Мнемоники POPF и POPFD имеют один код операции. Конкретная выполняемая команда определяется атрибутом размера операнда. Некоторые ассемблеры могут автоматически вставлять соответствующий префикс размера операнда перед кодом операции при трансляции мнемоник POPF и POPFD. Другие же ассемблеры воспринимают эти мнемоники одинаково и программируют только код операции. Работа команды в этом случае определяется текущей установкой размера операнда для кодового сегмента (бит D дескриптора сегмента).

При обращении к стеку для формирования логического адреса используются регистровые пары SS:SP при 16-битной адресации или SS:ESP при 32-битной адресации. Размерность адреса определяется текущей разрядностью стекового сегмента (бит B дескриптора сегмента) и не может быть переопределена префиксом размера адреса перед кодом операции.

В общем случае действие команды POPF/POPFD на многие флаги регистра (E)FLAGS зависит от текущего режима работы процессора, текущего уровня привилегий (CPL) и уровня привилегий ввода/вывода EFLAGS.IOPL).

В режиме реальной адресации могут свободно изменяться следующие флаги (поля): ID, AC, IOPL, IF, NT, OF, DF, TF, SF, ZF, AF, PF, CF. Флаг RF в результате исполнения команды сбрасывается. Флаги VM, VIF, VIP, а также все зарезервированные флаги не изменяются вне зависимости от того, какое значение соответствующего бита считывается из образа в стеке.

При работе в защищенном режиме уровень привилегий ввода/вывода IOPL может изменяться только при выполнении команды POPF/POPFD на нулевом текущем уровне привилегий (CPL = 0), а флаг IF — на уровене привилегий по крайней мере таком же, как и текущий уровень привилегий ввода/вывода (CPL ≤ IOPL). Если команда POPF/POPFD выполняется с недостаточным уровнем привилегий, то генерации особой ситуации не происходит, а привилегированные биты IOPL и IF, а также бит VM не изменяются, биты VIP и VIF могут сбрасываться.

В режиме V86, когда EFLAGS.IOPL < 3, команда POPF/POPFD вызывает генерацию особой ситуации общей защиты (#GP). Когда EFLAGS.IOPL = 3 команда срабатывает, но биты VM, RF, IOPL, VIP и VIF регистра EFLAGS в этом режиме не изменяются.

Бит EFLAGS.VM не может модифицироваться командой POPF/POPFD ни при каких условиях. Биты VIP и VIF могут только сбрасываться.

В процессорах, начиная с Pentium, поддерживаются специальные расширенные режимы обработки прерываний (виртуальные прерывания). Это позволяет обеспечить нормальное выполнение старого ПО, использующего команды управления внешними маскируемыми прерываниями (векторы от 32 до 255), в современной мультипроцессорной и мультизадачной программно-аппаратной среде. Указанные режимы управляются флагами CR4.PVI и CR4.VME и включают:

 

В частности, в режиме EV86, когда EFLAGS.IOPL < 3, команда POPF не вызывает генерации особой ситуации общей защиты (#GP) и не оказывает влияния на флаг EFLAGS.IF — вместо этого значение из стека, соответствующее биту IF, записывается во флаг EFLAGS.VIF. Если же при этом осуществляется попытка установки данного флага, а флаг EFLAGS.VIP = 1 (был установлен ранее), то генерируется особая ситуация общей защиты (#GP), которая должна обработать отложенное прерывание, как это описано для режима EV86. Аналогично, и попытка установки флага TF данной командой вызовет генерацию особой ситуации общей защиты (#GP) (см. Замечание). Специальный функционал для режима EV86 имеют также команды PUSHF, CLI, STI, IRET и команда вызова программных прерываний INT n.

В таблицах 6.2, 6.3, 6.4 показано, какое влияние команды POPF/POPFD оказывают на разные флаги регистра EFLAGS.

Таблица 6.2. Действие команды POPF (OperandSize = 16) на флаги регистра EFLAGS в реальном и защищенном (кроме V86) режимах работы процессора и условия их выполнения

CR0.PE

0 1 1 1 1 1 1 1

EFLAGS.VM

x 0 0 0 0 0 0 0

CR4.PVI

x x 0 0 1 1 1 1

CPL

x 0 > IOPL > 0 1, 2 1, 2 3 3

EFLAGS.IOPL

x x < CPL ≥ CPL ≥ CPL < CPL < 3 3
NT, OF, DF, TF, SF, ZF, AF, PF, CF + + + + + + + +
IOPL + +

IF

+ + + + +
RF 0 0 0 0 0 0 0 0
VM

VIF (см. Замечание)

0 0
VIP (см. Замечание)
ID, AC

+ — Флаг устанавливаетмя по значению, загружаемому из стека.

0 — Флаг сбрасывается вне зависимости от значения из стека.

 — Команда не оказывает влияние на текущее значение флага.

Таблица 6.3. Действие команды POPFD (OperandSize = 32) на флаги регистра EFLAGS в реальном и защищенном (кроме V86) режимах работы процессора и условия их выполнения

CR0.PE

0 1 1 1 1 1 1 1

EFLAGS.VM

x 0 0 0 0 0 0 0

CR4.PVI

x x 0 0 1 1 1 1

CPL

x 0 > IOPL > 0 1, 2 1, 2 3 3

EFLAGS.IOPL

x x < CPL ≥ CPL ≥ CPL < CPL < 3 3
NT, OF, DF, TF, SF, ZF, AF, PF, CF + + + + + + + +
IOPL + +

IF

+ + + + +
RF 0 0 0 0 0 0 0 0
VM

VIF (см. Замечание)

0 0
VIP (см. Замечание)
ID, AC + + + + + + + +

+ — Флаг устанавливаетмя по значению, загружаемому из стека.

0 — Флаг сбрасывается вне зависимости от значения из стека.

 — Команда не оказывает влияние на текущее значение флага.

Таблица 6.4. Действие команды POPF (OperandSize = 16) или POPFD (OperandSize = 32) на флаги регистра EFLAGS в виртуальном 8086 (V86) режиме работы процессора (CR0.PE = 1, EFLAGS.VM = 1) и условия их выполнения

OperandSize 32 16 32 16 16 16
CR4.VME x x x 0 1 1
EFLAGS.VIP x x x x 0 1
EFLAGS.IOPL 3 3 < 3 < 3 < 3 < 3
NTOFDFSFZFAFPFCF + + #GP(0) #GP(0) + +
TF (см. Замечание) + + [SP].TF = 1 → #GP(0)
[SP].TF = 0 → 0
[SP].TF = 1 → #GP(0)
[SP].TF = 0 → 0
IOPL
IF + +
RF 0 0 0 0
VM
VIF [SP].IF [SP].IF = 1 → #GP(0)
[SP].IF = 0 → 0
VIP
IDAC +

+ — Флаг устанавливаетмя по значению, загружаемому из стека.

0 — Флаг сбрасывается вне зависимости от значения из стека.

 — Команда не оказывает влияние на текущее значение флага.

[SP].IF — Значение в стеке, соответствующее флагу IF.

Операция:

IF EFLAGS.VM = 0 (* Не V86 режим *)

THEN

   IF CPL = 0 (* Реальный режим или Защищенный режим *)

   THEN

      IF OperandSize = 32 (* команда POPFD *)

      THEN

         EFLAGS[31:0] = Pop();

         (* Все незарезервированные биты,
           кроме RF, VIP, VIF, VM, могут модифицироваться.
           • VIP, VIF, VM и все зарезервированные биты не изменяются,
           • RF сбрасывается. *)

      ELSE (* OperandSize = 16 - команда POPF *)

         EFLAGS[15:0] = Pop();

         (* Все незарезервированные биты могут модифицироваться. 
           • RF сбрасывается. *)

      FI;

   ELSE (* Защищенный режим, CPL > 0 *)

      IF OperandSize = 32 (* команда POPFD *)

      THEN

         IF CPL > EFLAGS.IOPL

         THEN

            EFLAGS[31:0] = Pop();

            (* Все незарезервированные биты, кроме
              IF, IOPL, VIP, VIF, VM и RF, могут модифицироваться.
              • IF, IOPL, VIP, VIF, VM и все зарезервированные биты не изменяются,
              • RF сбрасывается. *)

         ELSE (* Защищенный режим, CPL ≤ EFLAGS.IOPL *)

            EFLAGS[31:0] = Pop();

            (* Все незарезервированные биты, кроме
              IOPL, VIP, VIF, VM и RF, могут модифицироваться.
              • IOPL, VIP, VIF, VM и все зарезервированные биты не изменяются (см. Замечание),
              • RF сбрасывается. *)

            FI;

         FI;

      ELSE (* OperandSize = 16 - команда POPF *)

         EFLAGS[15:0] = Pop();

         (* Все незарезервированные биты, кроме IOPL и IF, могут модифицироваться без ограничений. 
           • IF модифицируется если CPL ≤ IOPL,
           • RF сбрасывается. *)

      FI;

   FI;

 

ELSE (* Режим V86 *)

   IF EFLAGS.IOPL = 3

   THEN

      IF OperandSize = 32 (* команда POPFD *)

      THEN

         EFLAGS[31:0] = Pop();

         (* Все незарезервированные биты,
           кроме VM, RF, IOPL, VIP, VIF, могут модифицироваться.
           • VM, RF, IOPL, VIP, VIF не изменяются,
           • RF сбрасывается. *)

      ELSE (* OperandSize = 16 - команда POPF *)

         EFLAGS[15:0] = Pop();

         (* Все незарезервированные биты кроме IOPL могут модифицироваться. 
           • IOPL не изменяется,
           • RF сбрасывается. *)

      FI;

   ELSE (* EFLAGS.IOPL < 3 *)

      IF ( CR4.VME = 0 or OperandSize = 32 )

      THEN #GP(0); (* Ловушка монитора V86 *)

      ELSE (* CR4.VME = 1 and OperandSize = 16 *)

         IF [SP].TF = 1 (* Значение в стеке содержит флаг TF = 1 *)

         THEN #GP(0); (* Ловушка монитора V86 *)

         ELSE

            IF ( EFLAGS.VIP = 1 and [SP].IF = 1 )

               (* [SP].IF - значение в стеке для флага IF *)

            THEN #GP(0); (* Ловушка монитора V86 *)

            ELSE (* EFLAGS.VIP = 0 или [SP].IF = 0 *)

               EFLAGS[15:0] = Pop();

               (* Все незарезервированные биты, кроме IOPL и IF, могут модифицироваться.
                 • IOPL, IF не изменяются,
                 • EFLAGS.VIF устанавливается согласно значения для
                    флага IF из стека (EFLAGS.VIF = [SP].IF),
                 • RF сбрасывается. *)

            FI;

         FI;

      FI;

   FI;

FI;

Особые ситуации защищенного режима:

#SS(0), если вершина стека не попадает в пределы сегмента стека.

Intel386 … :
#PF(Код ошибки) при страничной ошибке.
#UD при использовании префикса LOCK.

Intel486 … :
#AC(0) при невыровненной ссылке в память, если активирован контроль выравнивания (CR0.AM = 1, EFLAGS.AC = 1, CPL = 3).

Особые ситуации режима реальной адресации:

#SS, если вершина стека не попадает в пределы сегмента стека.

Intel386 … :
#UD при использовании префикса LOCK.

Особые ситуации режима V86:

#GP(0), если текущий уровень привилегий ввода/вывода меньше 3 (EFLAGS.IOPL ≤ 3), когда CR4.VME = 0 или OperandSize = 32.
#GP(0), при использовании префикса изменения размера операнда.
#SS(0), если вершина стека не попадает в пределы сегмента стека.
#UD при использовании префикса LOCK.

Intel486 … :
#PF(Код ошибки) при страничной ошибке.
#AC(0) при невыровненной ссылке в память, если активирован контроль выравнивания (CR0.AM = 1, EFLAGS.AC = 1, CPL = 3).

Pentium … :
#GP(0) при попытке установки флага EFLAGS.TF в активном режиме виртуальных прерываний (CR4.VME = 1), если текущий уровень привилегий ввода/вывода меньше 3 (EFLAGS.IOPL ≤ 3).
#GP(0) при попытке установки флага EFLAGS.IF в активном режиме виртуальных прерываний (CR4.VME = 1) при установленном флаге EFLAGS.VIP, если текущий уровень привилегий ввода/вывода меньше 3 (EFLAGS.IOPL ≤ 3).

Замечание:

С момента появления в микропроцессорах, начиная с Pentium, режимов с поддержкой виртуальных прерываний (управляются флагами CR4.PVI и CR4.VME) производители старались напустить вокруг этой темы побольше тумана. Так, например, детальная информация в отношении этих режимов для микропроцессора Pentium вошла в так называемый Appendix H — приложение к документации, которое предоставлялось только партнерам Intel при условии подписания соглашения о конфиденциальности. В более позних моделях процессоров, таинственности, хотя и стало поменьше, но вот определенности в ряде случаев не добавилось.

По факту, все производители постоянно меняли описания этого режима в разных версиях своей документации, даже в рамках одной модели микропроцессоров. Причем такие изменения никак не анонсировались и не было сообщений о выявленных ошибках. Одновременно с этим, разработчики и тестировщики сталкивались с различиями в работе некоторых команд для процессоров различных выпусков, равно как и с несоответствиями получаемых экспериментальным путем данных и предоставленной документации.

Можно предполагать, что такая непоследовательность была продиктована как неуверенностью самих производителей в корректности выбранных микроалгоритмов исполнения различных команд, так и их желанием неявно поддержать аффилированных разработчиков ПО для виртуализации.

В отношении команд POPF/POPFD подобная неопределенность и разночтения документации сохраняются и поныне в отношении их влияния на флаги VIP и VIF.

Согласно документации Intel в режиме реальной адресации и в защищенном режиме (кроме режима V86) при 32-битном размере операнда возможен сброс обоих флагов VIP и VIF. Судя по всему, в некоторых моделях процессоров такой сброс, вообще говоря, имеет обязательный характер и не зависит от значения этих флагов в образе из стека. Можно, однако, предполагать, что и попытка установки этих флагов командой POPFD в указанных режимах для определенных (других) моделей процессоров может срабатывать успешно. Тот факт, что флаги VIP и VIF могли измениться даже при поступлении команды POPF при 16-битном размере операнда в процессоре Pentium, по всей видимости помешал продуктивному использованию режимов виртуальных прерываний в соответствующем программном обеспечении. Только начиная с Pentium Pro компания Intel без лишних анонсов исправила внутренние микроалгоритмы и в последующих моделях процессоров, во всяком случае при 16-битном размере операнда, флаги VIP и VIF командой POPF не изменяются. В свою очередь, для процессоров AMD заявляется, что в защищенном режиме (кроме режима V86) команды POPF/POPFD не оказывают никакого влияния на флаг VIP, а сброс флага VIF имеет место только при условии OperandSize = 32, CPL = 3 и CR4.PVI = 1 (как это указано в таблице 6.3).

Объясняется это странное многообразие в поведении разных моделей процессоров тем, что любое изменение значений флагов VIP и VIF командами POPF/POPFD с самого появления этих флагов не рассматривалось как штатная функция. По первоначальной задумке разработчиков виртуальных прерываний предполагалось, что указанные флаги, если они были установлены, должны сбрасываться непосредственно обработчиком прерывания или особой ситуации через подстановку (очистку) соответствующего образа регистра EFLAGS в стеке перед возвратом управления командой IRETD. Для флага VIF также возможно использование команд CLI/STI для сброса/установки флага при активном режиме с поддержкой виртуальных флагов прерываний (включается установкой CR4.PVI = 1 в защищенном режиме).

Казалось бы, что вопрос можно считать несущественным. Но при въедливом анализе выясняется, что от поведения флагов VIP и VIF некоторым образом зависит вероятность нештатной генерации командой POPF/POPFD особой ситуации общей защиты (#GP). При работе в защищенном режиме (кроме режима V86) любые значения, выбираемые из стека, по идее разработчиков не должны приводить к возникновению особой ситуации общей защиты (#GP) – некорректные (недоступные для изменения) флаги должны просто маскироваться. Но параллельно существует и другое правило, которое утверждает, что особая ситуация общей защиты (#GP) должна генерироваться для обработки отложенного прерывания в режиме V86, когда оба флага виртуальных прерываний оказываются установленными (VIP = 1, VIF = 1). Но если команда POPF/POPFD сможет установить флаг VIF при уже установленном флаге VIP, то потребуются дополнительные проверки (кнужно ли генерировать особую ситуацию или нет), которые, по всей видимости, в ряде старых моделей процессоров и не реализовывались вовсе. Отсекая все лишнее и несущественное, производители и пришли к тому, что команды POPF/POPFD просто не оказывают никакого влияния (или могут только сбрасывать) на флаги VIP и VIF, кроме совершенно конкретных ситуаций в режиме V86 (см. таблицу 6.4).

В конечном итоге оказалось, что режим с поддержкой виртуальных флагов прерываний (включается установкой CR4.PVI = 1 в защищенном режиме) не находит практического применения, в отличие от вполне востребованного режима виртуальных прерываний (включается установкой CR4.VME = 1 в режиме V86). Последний стали называть EV86 (Enhanced V86), и в отношении этого режима документация производителей микропроцессоров всегда была более полна и достоверна. Но и здесь имеются некотрые «тонкости», проявляющиеся при попытке установки флага трассировки TF.

Дело в том, что программа-монитор режима V86 предусматривает, что привилегированные команды, нарушающие модель защиты при текущем уровне привилегий ввода/вывода EFLAGS.IOPL < 3, обрабатываются через вызов особой ситуации общей защиты (#GP). Но если флаг TF будет установлен командой POPF, то после ее выполнения будет сгенерирована особая ситуация отладки (#DB). Чтобы предотвратить несанкционированный монитором V86 переход к обработчику особой ситуации отладки (#DB), процессор проверяет образ, извлекаемый из стека, и при попытке установки флага TFрежиме V86 когда EFLAGS.IOPL< 3) генерирует особую ситуации общей защиты (#GP). По всей видимости, эта «фича» существует с самого момента появления режима виртуальных прерываний в процессоре Pentium, хотя о ней и не было информации в официальной документации. Вместе с тем, замечено, что аналогичное изменение флага TF командой IRET в некоторых моделях процессоров может отрабатываться иначе и не приводить к генерации особой ситуации общей защиты (#GP) (это, похоже, является ошибкой или еще одной «фичей», которая также никогда официально не описывалась).


Входит в группу команд: Базовая система команд CPU




Все права защищены © Алексей Ровдо, 1994-2023. Перепечатка возможна только по согласованию с владельцем авторских прав. admin@club155.ru

Top.Mail.Ru       Сервер радиолюбителей России - схемы, документация,

 соревнования, дипломы, программы, форумы и многое другое!   схемы новости электроники