Внутренние регистры: Регистр флагов

Печать
Программирование - Архитектура и система команд микропроцессоров x86

 

Регистр флагов EFLAGS отражает текущее состояние процессора, многие из его битов устанавливаются после выполнения операций и индицируют тип, полученного результата. Формат регистра флагов приведен на рис. 1.3.

 

Формат регистра флагов

Рис. 1.3. Формат регистра флагов

 

CF (Флаг переноса, бит 0)

Флаг переноса фиксирует значение переноса (заема), возникающего при сложении (вычитании). Иногда используется и в других ситуациях.

 

PF (Флаг четности, бит 2)

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

 

AF (Флаг вспомогательного переноса, бит 4)

Флаг вспомогательного переноса фиксирует перенос (заем) из младшей тетрады, т.е. из бита 3 в старшую тетраду при сложении (вычитании). Используется только для двоично-десятичной арифметики, которая оперирует исключительно младшими байтами.

 

ZF (Флаг нуля, бит 6)

Флаг нуля сигнализирует о получении нулевого (ZF = 1) или ненулевого (ZF = 0) результата операции.

 

SF (Флаг знака, бит 7)

Флаг знака дублирует значение старшего бита результата, который при использовании дополнительного кода соответствует знаку числа (0 – положительное число, 1 – отрицательное).

 

TF (Флаг трассировки, бит 8)

При установке флага трассировки TF = 1, микропроцессор переходит в пошаговый режим работы, применяемый при отладке программ, когда автоматически генерируется особая ситуация отладки (#DB) после выполнения каждой команды. Прерывание отладки начнет генерироваться, если прикладная программа установит флаг TF с помощью команд POPF/POPFD или IRET/IRETD.

 

IF (Флаг разрешения прерываний, бит 9)

При установке флага разрешения прерываний IF = 1, микропроцессор воспринимает (распознает) и соответственно реагирует на запрос прерывания по входу INTR# (внешние маскируемые прерывания). При IF = 0, прерывания по этому входу запрещаются и микропроцессор игнорирует поступающие запросы прерываний.

Значение флага IF не влияет на восприятие внешних немаскируемых прерываний по входу NMI#, а также внутренних программных прерываний, выполняемых по команде INT.

Изменение этого флага командами CLI, STI, POPF/POPFD и IRET/IRETD возможно не всегда и определяется текущими:

 

При обычной обработке прерываний (CR4.PVI = 0 в защищенном режиме или CR4.VME = 0 в режиме V86), когда IOPL < CPL ( IOPL < 3 в режиме V86), все попытки изменения флага IF командами STI, CLI, POPF/POPFD и IRET/IRETD вызывают генерацию ошибки общей защиты (#GP).

Когда же виртуальные прерывания инициализированы (CR4.PVI = 1 в защищенном режиме или CR4.VME = 1 в режиме V86) при выполнении того же условия IOPL < CPL ( IOPL < 3 в режиме V86) команды CLI и STI оказывают влияние на флаг EFLAGS.VIF, а флаг IF при этом остается неизменным. Флаг VIF используется всеми командами (в т.ч. PUSHF, POPF), которые пытаются изменять или считывать значение флага IF. Только значение флага VIF будет всякий раз изменяться и считываться программой. При поступлении внешнего маскируемого прерывания процессор производит стандартное обращение к обработчику прерываний защищенного режима через таблицу дескрипторов прерываний (IDT). При этом, при записи в стек значения регистра EFLAGS процессор записывает поле IOPL равным 3 и флаг IF равным VIF.

 

DF (Флаг направления, бит 10)

Флаг направления определяет порядок обработки цепочек в соответствующих командах (строковые команды: STOS, LODS, CMPSOUTS и т.д.) — от меньших адресов к большим (DF = 0) или от больших к меньшим (DF = 1).

 

OF (Флаг переполнения, бит 11)

Флаг переполнения сигнализирует о потере старшего бита результата в связи с переполнением разрядной сетки при работе со знаковыми числами. При сложении этот флаг устанавливается в 1, если происходит перенос в старший бит и нет переноса из старшего бита, или имеется перенос из старшего бита, но отсутствует перенос в него; в противном случае, флаг OF устанавливается в 0. При вычитании он устанавливается в 1, когда возникает заем из старшего бита, но заем в старший бит отсутствует, либо имеется заем в старший бит, но отсутствует заем из него.

 

IOPL (Уровень привилегий ввода/вывода, биты 13 и 12: Intel286 …)

Поле уровня привилегий ввода/вывода (Input/output Privilege Level – IOPL) используется механизмом защиты для управления доступом к адресному пространству ввода/вывода и программным прерываниям. Ряд команд, называемых IOPL-чувствительными командами (IOPL-sensitive instructions), могут выполняться по-разному в зависимости от текущего режима работы процессора и значения поля IOPL.

В защищенном режиме к IOPL-чувствительным командам относятся команды IN, OUT, INS/NSB/INSW/INSD, OUTS/OUTSB/OUTSW/OUTSD, CLISTI и префикс LOCK (только на процессоре Intel286). Всякий раз, когда программа осуществляет чтение/запись в порты ввода/вывода либо разрешение/запрещение прерываний указанными командами, процессор осуществляет специальную проверку привилегий. В зависимости от текущего значения поля IOPL и текущего уровня привилегий (CPL), механизмом защиты может генерироваться особая ситуация общей защиты (#GP). Если CPLIOPL, то команда исполняется в соответствии со своим назначением (как и в режиме реальной адресации). Если CPL > IOPL в защищенном режиме (а также всегда в режиме V86), производится дополнительная проверка доступности соответствующего порта ввода/вывода при любых операциях с ним. Такая проверка использует специальную карту разрешения ввода/вывода, которая расположена в верхней части сегмента состояния задачи TSS и определяет доступность всех портов ввода/вывода. В случае недоступности порта или при попытках разрешения/запрещения прерываний командами CLISTI, когда CPL > IOPL, процессор генерирует ошибку общей защиты (#GP).

Изменение уровня привилегий ввода/вывода IOPL возможно командами POPF/POPFD и IRET/IRETD в защищенном режиме и только при выполнении команды на уровне привилегий, по крайней мере таком же (а для команды POPF/POPFD только на нулевом), как и текущий уровень привилегий ввода/вывода (режим реальной адресации эквивалентен нулевому уровню привилегий).

При работе в режиме V86 (EFLAGS.VM = 1) IOPL-чувствительными являются команды CLISTIPOPF/POPFDPUSHF/PUSHFDIRET/IRETDINT n. У каждой из этих команд имеется аналогичная зависимость от текущего значения поля IOPL. Например, команда INT n вызывает генерацию особой ситуации общей защиты (#GP), если IOPL < 3, или выполняется программное прерывание (при IOPL = 3).

В защищенном режиме команда POPF/POPFD является одновременно зависимой и от уровня привилегий ввода/вывода IOPL, и от текущего уровня привилегий (CPL), позволяя изменять поле IOPL только при выполнении на нулевом уровне привилегий (CPL = 0), а флаг разрешения прерываний IF — только при условии CPL ≤ IOPL. Однако, если эта команда не может изменить указанное поле или флаг из-за недостаточности текущих привилегий, то генерации особой ситуации общей защиты (#GP) не происходит — продолжается выполнение последующих команд. Это поведение меняется в режиме V86 — здесь попытка использования команды POPF/POPFD при IOPL < 3 (кроме режима EV86) всегда вызывает генерацию особой ситуации общей защиты (#GP).

В процессорах, начиная с Pentium, имеется специальный режим EV86 (включается установкой флага CR4.VME = 1 в режиме V86), в котором возникает дополнительная специфика для IOPL-чувствительных команд. Во-первых, команда IRET в этом режиме вообще перестает быть IOPL-чувствительной и не генерирует особую ситуацию общей защиты (#GP) при IOPL < 3. Команды CLISTI при IOPL <  3, вместо генерации указанной особой ситуации, оказывают влияние на флаг виртуального прерывания VIF (также как и команда POPF), а для команды INT n вообще возникает несколько режимов, которые зависят от текущего контекста конкретной задачи V86. И наконец, команда PUSHF (16-битная), выполняемая в режиме EV86 при IOPL < 3, также не генериует особую ситуацию общей защиты (#GP), а записывает в стек образ регистра флагов FLAGS, у которого биты, соответствующие полю IOPL, устанавливаются равными 3, а бит IF записывается из текущего значения флага VIF.

В ранних моделях процессоров до Intel286 (8086/8088, Intel186) биты 12 и 13 регистра флагов FLAGS, соответствующие полю IOPL, считались зарезервированными, а их значения всегда были равны единице. В процессоре Intel286 в режиме реальной адресации невозможно изменять значения этих битов — они всегда остаются нулевыми (они сбрасываются в момент инициализации процессора), а вот более поздние модели процессоров, начиная с Intel386, такого ограничения уже не имеют, то есть поле IOPL можно изменять и в режиме реальной адресации. Указанная особенность использовалась в процедурах идентификации процессоров вплоть до появления команды CPUID в процессоре Pentium.

 

NT (Вложенная задача, бит 14: Intel286 …)

Процессор устанавливает и проверяет флаг вложенной задачи для контроля за прерванными задачами (задачи, во время исполнения которых имело место прерывание) и при вызове процедур. Флаг NT влияет на действия, производимые командой IRET/IRETD. Этот флаг может быть изменен командой POPF/POPFD и IRET/IRETD. Некорректные изменения этого флага могут привести к возникновению различных особых ситуаций в прикладных программах.

 

RF (Флаг возобновления, бит 16: Intel386 …)

Флаг возобновления RF временно выключает обработку особых ситуаций отладки (DB#) для того, чтобы команда, вызвавшая такую ситуацию, могла быть перезапущена и не стала бы причиной новой особой ситуации. Отладчик устанавливает этот флаг командой IRETD при возврате в прерванную программу. Команды POPF, POPFD (в режиме V86) и IRET на этот флаг не влияют.

 

VM (Виртуальный режим, бит 17: Intel386 …)

Установка флага виртуального режима VM переключает процессор в режим виртуального-8086 (специальный случай защищенного режима).

 

AC (Режим контроля выравнивания, бит 18: Intel486 …)

Установка флага режима контроля выравнивания (AC = 1) и бита AM регистра CR0 (CR0.AM = 1) включает контроль выравнивания при обращении к памяти. При этом только при текущем уровне привилегий равном 3 (CPL = 3) генерируется особая ситуация контроля выравнивания (#AC), если происходит обращение к невыровненному операнду (например, к слову по нечетному адресу или к двойному слову по адресу не кратному четырем).

Таблица 3.5. Условия контроля выравнивания

Тип данных

Адрес должен быть кратен

WORD (Слово) – m16, m16int, moffs16

2

DWORD (Двойное слово) – m32, m32int, moffs32

4

QUADWORD (Учетверенное слово) – m64, m64int

8

DOUBLE QUADWORD (Двойное учетверенное слово) – m128

16

Short-real (Короткое вещественное – 32 бита) – m32real

4

Long-real (Длинное вещественное – 64 бита) – m64real

8

Temp-real (Временное вещественное – 80 бит) – m80real

8

Селектор

2

32-битный дальний указатель – m16:16

2

32-битный указатель – m16:16

4

48-битный дальний указатель – m16:32

4

Содержимое GDTR, IDTR, LDTR или TRm16&32

4

Область сохранения для FSTENV/FNSTENV/FLDENVmNbyte

4 или 2 – определяется размером операнда

Область сохранения для FSAVE/FNSAVE/FRSTORmNbyte

4 или 2 – определяется размером операнда

Строка бит

4 или 2 – определяется размером операнда

 

VIF (Виртуальное прерывание, бит 19: Pentium …)

Флаг виртуального прерывания VIF используется совместно с флагом VIP и позволяет обеспечить нормальное выполнение старого ПО, использующего команды управления внешними маскируемыми прерываниями (векторы от 32 до 255), в современной мультипроцессорной и мультизадачной программно-аппаратной среде.

Для этого в процессорах, начиная с Pentium, поддерживаются специальные расширенные режимы обработки прерываний:

 

В этих режимах флаг виртуального прерывания VIF выступает виртуальным подобием флага IF. При условии, что виртуальные прерывания инициализированы (CR4.PVI = 1 в защищенном режиме, CR4.VME = 1 в режиме V86), команды CLI и STI оказывают влияние на флаг EFLAGS.VIF, а флаг IF при этом остается неизменным. При поступлении внешнего маскируемого прерывания процессор производит стандартное обращение к обработчику прерываний защищенного режима через таблицу дескрипторов прерываний (IDT). При этом, при записи в стек значения регистра EFLAGS процессор записывает поле IOPL равным 3 и флаг IF равным VIF.

 

VIP (Ожидание виртуального прерывания, бит 20: Pentium …)

Флаг ожидания виртуального прерывания VIP используется совместно с флагом VIF и позволяет прикладным программам в режиме поддержки виртуальных прерываний отслеживать внешние вызовы прерываний даже тогда, когда программа замаскирует их выполнение (индикация отложенных виртуальных прерываний). За дополнительной информацией по использованию этих флагов обратитесь к описанию прерываний и особых ситуаций.

 

ID (Флаг идентификации, бит 21: Pentium …)

Флаг идентификации ID предназначен для проверки — поддерживается ли процессором команда CPUID. Если в программе можно установить и сбросить этот флаг, значит команда CPUID данным процессором поддерживается.