logo

Воскресенье 11 Декабрь 2016 (GMT+0300)

Главная Система команд x86 Базовая система команд CPU INT n
Система команд 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

INT n

Вызов процедуры прерывания

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

OF

DF

IF

TF

SF

ZF

AF

PF

CF

 

 

0

0

 

 

 

 

 

 

Код

Команда

Описание

Проц.

Пример

CC

INT 3

Вызов прерывания 3 (#BP, точка останова)

8086

int 3

CD ib

INT imm8

Вызов прерывания imm8

8086

int 13

CE

INTO

Вызов прерывания 4 (#OF, переполнение), если EFLAGS.OF=1

8086

into

Операция:

Представленный здесь алгоритм описывает не только поведение процессора при выполнении команды INT n, но и при поступлении любого внешнего прерывания или генерации особой ситуации.

 

IF CR0.PE = 0

   THEN GOTO REAL-ADDRESS-MODE;

   ELSE

      IF ( EFLAGS.VM = 1 AND EFLAGS.IOPL < 3 AND

          ( INT n ) AND

          ( CR4.VME = 0 OR CR4.VME = 1 AND IRB[n] = 1 ) 

         ) (* IRB[n] - бит, соответствующий прерыванию n в карте перенаправления прерываний *)

         THEN

            #GP(0); (Программное прерывание INT n в режиме: (1) V86 при EFLAGS.IOPL < 3, (2) EV86 Режим 2 *)

         ELSE (* Защищенный режим или режим V86/EV86 *)

            IF ( EFLAGS.VM = 1 AND CR4.VME = 1 AND

                ( INT n ) AND IRB[n] = 0 )

               THEN GOTO EV86-MODE; (* EV86: Режим 3 или Режим 5 *)

               ELSE GOTO PROTECTED-MODE; (* Аппаратные прерывания, особые ситуации; программные прерывания INT n в режиме: (1) Защищенный режим, (2) V86 при EFLAGS.IOPL = 3, (3) EV86 Режим 1 или Режим 4 *)

            FI;

      FI;

FI;

END;

 

REAL-ADDRES-MODE:

IF ( (Номер прерывания * 4) + 3 выходит за пределы сегмента при обращении к таблице векторов прерываний IVT ) THEN #GP; FI;

IF ( В стеке нет места для 6 байт ) THEN #SS; FI;

Push(FLAGS);

EFLAGS.IF = 0; (* Сброс флага прерываний *)

EFLAGS.TF = 0; (* Сброс флага ловушки *)

EFLAGS.AC = 0; (* Сброс флага режима контроля выравнивания *)

Push(CS);

Push(IP);

(* В стек не заносятся коды ошибок *)

CS = IVT[Номер прерывания * 4].selector;

EIP = IVT[Номер прерывания * 4].offset AND 0x0000FFFFh; (* старшие 16-бит регистра EIP обнуляются *)

(* Продолжение работы в режиме реальной адресации ... *)

END;

 

EV86-MODE: (* CR0.PE = 1, EFLAGS.VM = 1, CR4.VME = 1, Режим EV86 - программное прерывание INT n, при IRB[n] = 0 - Режим 3 или Режим 5 *)

IF (В стеке задачи V86 нет места для 6 байт) THEN #SS(0); FI;

tempFLAGS = FLAGS;

tempFLAGS.IOPL = 0; (* см. Примечание *)

tempFLAGS.NT = 0;

IF EFLAGS.IOPL = 3 (* Режим 3 *)

   THEN EFLAGS.IF = 0; (* Сброс флага разрешения прерываний *)

   ELSE (* EFLAGS.IOPL < 3 - Режим 5 *)

      tempFLAGS.IF = EFLAGS.VIF;

      EFLAGS.VIF = 0; (* Сброс виртуального флага прерываний *)

FI;

EFLAGS.TF = 0; (* Сброс флага ловушки *)

Push(tempFLAGS);

Push(CS);

Push(IP);

(* В стек не заносятся коды ошибок *)

CS = IVT_V86[Номер прерывания * 4].selector; (* Таблица векторов прерываний IVT_V86 располагается в начале адресного пространства задачи V86 *)

EIP = IVT_V86[Номер прерывания * 4].offset AND 0x0000FFFFh; (* старшие 16-бит регистра EIP обнуляются *)

(* Продолжение работы в режиме EV86 ... *)

END;

 

PROTECTED-MODE: (* CR0.PE = 1, Аппаратные прерывания, особые ситуации; программные прерывания INT n в режиме: (1) Защищенный режим, (2) V86 при EFLAGS.IOPL = 3, (3) EV86 Режим 1 или Режим 4 *)

IF ( (Номер прерывания * 8) + 7 не попадает в пределы таблицы IDT ) THEN #GP(номер прерывания * 8 + 2 + EXT); FI;

(* Здесь и далее в параметрах кода ошибки слагаемое +2 означает установку бита IDT кода ошибки, а слагаемое +EXT - означает установку бита EXT кода ошибки в соответствии с тем, было ли вызвавшее ошибку прерывание программным EXT = 0 или внешним EXT = 1 *)

Байт AR дескриптора должен задавать шлюз прерывания, шлюз ловушки или шлюз задачи, иначе #GP(номер прерывания * 8 + 2 + EXT);

IF (Программное прерывание или особая ситуация) (* Т.е. один из случаев INT n, INT 3, INT01, BOUND или INTO *)

   THEN

      IF ( CPL > DPL шлюза )

         THEN

            #GP(номер прерывания * 8 + 2); (* CR0.PE = 1, DPL шлюза < CPL, программное прерывание *)

      FI;

FI;

Шлюз должен присутствовать, иначе #NP(номер прерывания * 8 + 2 + EXT);

IF (Шлюз задачи)

   THEN GOTO TASK-GATE;

   ELSE

      GOTO TRAP-OR-INT-GATE; (* CR0.PE = 1, шлюз прерывания или ловушки *)

FI;

END;

 

TRAP-OR-INT-GATE: (* Защищенный режим или режим V86/EV86, шлюз ловушки или прерывания *)

Проверка нового селектора CS, заданного в дескрипторе шлюза, и соответствующего ему дескриптора из LDT или GDT:

   Селектор должен быть не нулевым, иначе #GP(EXT);

   Индекс селектора должен попадать в пределы таблицы дескрипторов, иначе #GP(селектор + EXT);

   Выбранный дескриптор должен быть дескриптором сегмента кода, иначе #GP(селектор + EXT);

   Сегмент должен присутствовать (P = 1), иначе #NP(селектор + EXT);

IF (Кодовый сегмент несогласованный) AND (DPL сегмента кода < CPL) 

   THEN

      IF EFLAGS.VM = 0

         THEN GOTO INT-TO-INTER-PRIV; (* CR0.PE = 1, EFLAGS.VM = 0, шлюз прерывания или ловушки, несогласованный кодовый сегмент, DPL сегмента кода < CPL *)

         ELSE (* EFLAGS.VM = 1 *)

            IF ( DPL нового сегмента кода ≠ 0 ) THEN #GP(Селектор кодового сегмента + EXT); FI;

            GOTO INT-FROM-V86-MODE;(* CR0.PE = 1, EFLAGS.VM = 1, шлюз прерывания или ловушки, DPL сегмента кода = 0, CPL = 3 *)

      FI;

   ELSE (* CR0.PE = 1, шлюз прерывания или ловушки, согласованный кодовый сегмент или несогласованный кодовый сегмент с DPL = CPL *)

      IF EFLAGS.VM = 1 THEN #GP(Селектор кодового сегмента + EXT); FI;

      IF ( (Кодовый сегмент согласованный) OR (DPL сегмента кода = CPL) )

         THEN GOTO INT-TO-INTRA-PRIV; (* CR0.PE = 1, шлюз прерывания или ловушки, DPL сегмента кода ≤ CPL для согласованного сегмента, DPL сегмента кода = CPL для несогласованного сегмента *)

         ELSE #GP(Селектор кодового сегмента + EXT); (* DPL > CPL для согласованного сегмента или DPL ≠ CPL для несогласованного сегмента *)

      FI;

FI;

END;

 

INT-TO-INTER-PRIV: (* Защищенный режим, шлюз прерывания или ловушки, несогласованный кодовый сегмент, DPL сегмента кода < CPL *)

IF ( Текущий TSS 32-битный )

   THEN

      TSSstackAddress = (new code segment DPL * 8) + 4

      IF ( (TSSstackAddress + 5) > Предел TSS ) (* (TSSstackAddress + 7) > Предел TSS - для некоторых моделей процессоров *)

         THEN #TS(Селектор текущего TSS + EXT);

      FI;

      NewSS = [База TSS + TSSstackAddress + 4]; (* загружается 2 байта *)

      NewESP = [База TSS + TSSstackAddress]; (* загружается 4 байта *)

   ELSE (* Текущий TSS 16-битный *)

      TSSstackAddress = (new code segment DPL * 4) + 2

      IF ( (TSSstackAddress + 3) > Предел TSS ) (* (TSSstackAddress + 4) > Предел TSS - для некоторых моделей процессоров *)

         THEN #TS(Селектор текущего TSS + EXT);

      FI;

      NewESP = [База TSS + TSSstackAddress]; (* загружается 2 байта *)

      NewSS = [База TSS + TSSstackAddress + 2]; (* загружается 2 байта *)

FI;

Проверка селектора нового стекового сегмента NewSS и соответствующего ему дескриптора из LDT или GDT:

   Селектор должен быть не нулевым, иначе #TS(EXT);

   Индекс селектора должен попадать в пределы таблицы дескрипторов, иначе #TS(SS селектор + EXT);

   RPL селектора должен быть равен DPL нового кодового сегмента, иначе #TS(SS селектор + EXT);

   DPL стекового сегмента должен быть равен DPL нового кодового сегмента, иначе #TS(SS селектор + EXT);

   Дескриптор должен иметь формат дескриптора сегмента данных, разрешенного для записи (W = 1), иначе #TS(SS селектор + EXT);

   Сегмент должен присутствовать (P = 1), иначе #SS(SS селектор + EXT);

IF (32-битный шлюз)

   THEN Новый стек должен иметь место для 20 байт (24 байт, если есть код ошибки), иначе #SS(EXT)

   ELSE Новый стек должен иметь место для 10 байт (12 байт, если есть код ошибки), иначе #SS(EXT)

FI;

Новый указатель инструкции должен попадать в пределы нового кодового сегмента, иначе #GP(EXT); (* указатель инструкции определяется значением поля OFFSET из дескриптора шлюза *)

SS:ESP = TSS(NewSS:NewESP); (* Загрузить новые значения SS и eSP из TSS *)

IF (32-битный шлюз)

   THEN CS:EIP = Gate(SELECTOR:OFFSET); (* Загрузить селектор:смещение из дескриптора 32-битного шлюза *)

   ELSE CS:IP = Gate(SELECTOR:OFFSET); (* Загрузить селектор:смещение из дескриптора 16-битного шлюза *)

FI;

Загрузить дескриптор CS в скрытую часть регистра CS;

Загрузить дескриптор SS в скрытую часть регистра SS;

IF (32-битный шлюз)

   THEN

      Push(Длинный указатель на старый стек - SS:ESP); (* 3 слова дополняются до 4 *)

      Push(EFLAGS);

      Push(Длинный указатель на точку возврата - CS:EIP); (* 3 слова дополняются до 4 *)

      Push(Код ошибки); (* Если присутствует, 4 байта *)

   ELSE

      Push(Длинный указатель на старый стек - SS:SP); (* 2 слова *)

      Push(FLAGS);

      Push(Длинный указатель на точку возврата - CS:IP); (* 2 слова *)

      Push(Код ошибки); (* Если присутствует, 2 байта *)

FI;

CPL = DPL нового кодового сегмента;

CS.RPL = CPL;

IF (Шлюз прерывания) THEN EFLAGS.IF = 0 FI; (* Сбросить флаг прерывания *)

EFLAGS.TF = 0;

EFLAGS.NT = 0;

EFLAGS.RF = 0;

(* Продолжение работы в защищенном режиме на уровне с большими привилегиями ... *)

END;

 

INT-FROM-V86-MODE: (* Режим V86/EV86, шлюз прерывания или ловушки, DPL = 0, CPL = 3 *)

(* Текущий TSS всегда 32-битный в режиме V86 *)

IF ( Предел TSS < 9 ) (* Предел TSS < 11 - для некоторых моделей процессоров *)

   THEN #TS(Селектор текущего TSS + EXT);

FI;

NewSS = [База TSS + 8]; (* загружается 2 байта *)

NewESP = [База TSS + 4]; (* загружается 4 байта *)

 

Проверка селектора нового стекового сегмента NewSS и соответствующего ему дескриптора из LDT или GDT:

   Селектор должен быть не нулевым, иначе #TS(EXT);

   Индекс селектора должен попадать в пределы таблицы дескрипторов, иначе #TS(SS селектор + EXT);

   RPL селектора должен быть равен нулю, иначе #TS(SS селектор + EXT);

   DPL стекового сегмента должен быть равен нулю, иначе #TS(SS селектор + EXT);

   Дескриптор должен иметь формат дескриптора сегмента данных, разрешенного для записи (W = 1), иначе #TS(SS селектор + EXT);

   Сегмент должен присутствовать (P = 1), иначе #SS(SS селектор + EXT);

IF (32-битный шлюз)

   THEN

      Новый стек должен иметь место для 36 байт (40 байт, если есть код ошибки), иначе #SS(EXT)   

      Новый указатель инструкции должен попадать в пределы нового кодового сегмента, иначе #GP(EXT); (* указатель инструкции определяется значением поля OFFSET из дескриптора шлюза *)

      TempEflags = EFLAGS;

      EFLAGS.VM = 0; (* Процессор выходит из режима V86 для обработки прерывания в защищенном режиме *)

      EFLAGS.NT = 0;

      EFLAGS.TF = 0;

      EFLAGS.RF = 0;

      IF (Шлюз прерывания)

         THEN EFLAGS.IF = 0;

      FI;

      TempSS = SS;

      TempESP = ESP;

      CPL = 0; (* Переключение на нулевой уровень привилегий *)

      SS:ESP = TSS(NewSS:NewESP); (* Загрузить значения SS0 и ESP0 из TSS *)

      Push(GS); (* расширяется до двух слов *)

      Push(FS); (* расширяется до двух слов *)

      Push(DS); (* расширяется до двух слов *)

      Push(ES); (* расширяется до двух слов *)

      GS = 0; (* Сегментные регистры обнуляются. Недопустимо последующее использование нулевых селекторов в защищенном режиме *)

      FS = 0;

      DS = 0;

      ES = 0;

      Push(TempSS); (* расширяется до двух слов *)

      Push(TempESP);

      Push(TempEflags);

      Push(CS); (* расширяется до двух слов *)

      Push(EIP);

      Push(Код ошибки); (* Если присутствует, 4 байта *)

      CS:EIP = Gate(SELECTOR:OFFSET); (* Загрузить селектор:смещение из дескриптора 32-битного шлюза *)

 

   ELSE (* 16-битный шлюз *)

      Новый стек должен иметь место для 18 байт (20 байт, если есть код ошибки), иначе #SS(EXT)

      (* сохранение в стеке 16-битных значений регистров происходит аналогично 32-битному шлюзу *)

      (* Возврат из прерывания командой IRET обратно в режим V86 из 16-битного сегмента будет невозможен, так как флаг VM не сохранится в стеке и не восстановится из образа EFLAGS при возврате *)

FI;

(* Продолжение работы в защищенном режиме на нулевом уровне привилегий ... *)

END;

 

INT-TO-INTRA-PRIV: (* CR0.PE = 1, DPL = CPL или согласованный сегмент с DPL ≤ CPL *)

IF (32-битный шлюз)

   THEN Новый стек должен иметь место для 12 байт (16 байт, если есть код ошибки), иначе #SS(EXT)

   ELSE Новый стек должен иметь место для 6 байт (8 байт, если есть код ошибки), иначе #SS(EXT)

FI;

Новый указатель инструкции должен попадать в пределы нового кодового сегмента, иначе #GP(EXT);

IF (32-битный шлюз)

   THEN

      Push(EFLAGS);

      Push(Длинный указатель на точку возврата); (* 3 слова дополняются до 4 *)

      CS:EIP = Gate(SELECTOR:OFFSET); (* Загрузить селектор:смещение из дескриптора 32-битного шлюза *)

      Push(Код ошибки); (* Если присутствует, 4 байта *)

   ELSE

      Push(FLAGS);

      Push(Длинный указатель на точку возврата); (* 2 слова *)

      CS:IP = Gate(SELECTOR:OFFSET); (* Загрузить селектор:смещение из дескриптора 16-битного шлюза *)

      Push(Код ошибки); (* Если присутствует, 2 байта *)

FI;

Загрузить дескриптор CS в скрытую часть регистра CS;

CS.RPL = CPL;

IF (Шлюз прерывания) THEN EFLAGS.IF = 0; FI;

EFLAGS.TF = 0;

EFLAGS.NT = 0;

EFLAGS.RF = 0;

(* Продолжение работы в защищенном режиме без изменения уровня привилегий ... *)

END;

 

TASK-GATE: (* CR0.PE = 1, шлюз задачи *)

Проверка селектора TSS из дескриптора шлюза задачи:

   Селектор должен задавать GDT (бит TI = 0), иначе #GP(TSS селектор + EXT);

   Индекс селектора должен попадать в пределы таблицы GDT, иначе #GP(TSS селектор + EXT);

Проверка соответствующего выбранному селектору дескриптора TSS:

   Дескриптор TSS должен иметь тип свободного TSS (TYPE.B = 0), иначе #GP(TSS селектор + EXT);

   TSS должен присутствовать (P = 1), иначе #NP(TSS селектор + EXT);

SWITCH-TASKS(С вложением) в TSS; (* здесь "С вложением" означает тот факт, что при инициализации контекста новой задачи будет установлен флаг EFLAGS.NT = 1, а в поле LINK ее сегмента TSS будет скопирован селектор TSS прерываемой (старой) задачи – см. Адресация и многозадачность: Средства поддержки мультизадачности *)

IF (Прерывание представляет собой особую ситуацию с кодом ошибки)

   THEN

      В стеке должно быть место для кода ошибки, иначе #SS(EXT);

      Push(код ошибки);

FI;

Указатель инструкции EIP должен попадать в пределы сегмента CS, иначе #GP(EXT);

(* Загрузка контекста новой задачи сопровождается дополнительными проверками как это описано в разделе Адресация и многозадачность: Средства поддержки мультизадачности *)

(* Продолжение работы в контексте новой задачи ... *)

END;

Описание:

Команда INT n обеспечивает программную генерацию прерывания и передачу управления в соответствующий обработчик. Непосредственный операнд команды может принимать значения от 0 до 255, что задает вектор (индекс) вызываемого прерывания по таблице дескрипторов прерываний (IDT) или по таблице векторов прерываний (IVT). При этом первые 32 вектора прерываний (от 0 до 31) зарезервированы Intel для системного использования. Большинство из них используется для обработки генерируемых процессором особых ситуаций. Команда INT n предназначена для программной генерации прерываний с номерами от 32 до 255, но технически возможно вызвать и прерывания с меньшими (любыми) векторами. В этом случае процессор ведет себя не так, как это описано для соответствующего внешнего прерывания или особой ситуации, а так, как это предусмотрено именно для генерируемых программно прерываний пользователя (то есть не записываются никакие коды ошибок, не соблюдаются приоритеты и т.п.).

Команда INT n в общем ведет себя как дальний вызов командой CALL, за исключением того, что регистр флагов помещается в стек перед адресом возврата. Процедуры обработки прерываний завершаются командой IRET/IRETD, которая выбирает из стека флаги и адрес возврата. В деталях же реакция процессора на поступление программного прерывания определяется его текущим режимом работы (см. Прерывания и особые ситуации: Реальный режим, Защищенный режим, Режим V86).

В режиме реальной адресации таблица векторов прерываний (IVT), которую иногда называют просто таблицей прерываний, является массивом 4-байтных дальних указателей (см. рис. 3.1). Конечным результатом исполнения команды INT n в этом случае и является переход (передача управления) по заданному адресу. Процессор автоматически выбирает из памяти соответствующий указатель, затем сохраняет в стеке текущие (16-битные) значения FLAGS, CS, IP (см. рис. 3.2.), очищает биты IF, TF, AC регистра FLAGS и передает управление по считанному адресу. Линейный базовый адрес таблицы прерываний определяется содержимым регистра IDTR. Первоначальное значение IDTR при сбросе процессора или переходе в режим реальной адресации является нулевым.

 

Таблица векторов прерываний в реальном режиме работы

Рис. 3.1. Таблица векторов прерываний в реальном режиме работы

 

Стек после вызова прерывания или особой ситуации в реальном режиме работы

Рис. 3.2. Стек после вызова прерывания или особой ситуации в реальном режиме работы

 

В защищенном режиме таблица дескрипторов прерываний (IDT) состоит из множества 8-байтных дескрипторов (см. рис. 3.3). Дескрипторы в таблице могут иметь разные типы. Допустимы: шлюз прерывания, шлюз ловушки или шлюз задачи. При поступлении команды прерывания процессор сохраняет текущие значения EFLAGS, CS и EIP в стеке. Когда передача управления в обработчик связана с изменением уровня привилегий на более высокий (меньшее числовое значение), это сопровождается переключением стека. Новые значения для SS и ESP берутся из TSS текущей задачи в соответствии с уровнем привилегий обработчика. Переключение стека производится до сохранения указанных выше регистров, причем в новом стеке в первую очередь сохраняются значения SS и ESP, указывающие на старый стек (см. рис. 6.10.).

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

При передаче управления через шлюз прерывания или шлюз ловушки процессор сбрасывает флаги EFLAGS.TF, EFLAGS.RF и EFLAGS.NT, чтобы отключить трассировку прерываний и некоторые особенности обработки вложенных задач. Кроме того, при использовании шлюза прерывания сбрасывается также и флаг разрешения прерываний EFLAGS.IF.

В защищенном режиме (как в и режиме реальной адресации) линейный базовый адрес таблицы IDT определяется содержимым регистра IDTR (см. рис. 3.3).

 

Таблица дескрипторов прерываний (IDT) в защищенном режиме работы

Рис. 3.3. Таблица дескрипторов прерываний (IDT) в защищенном режиме работы

 

Стек после вызова программного прерывания в защищенном режиме

Рис. 6.10. Стек после вызова программного прерывания в защищенном режиме

 

При поступлении программного прерывания в режиме V86 процессор автоматически переключается в защищенный режим с уровнем привилегий CPL = 0 (в связи с этим происходит замена указателя стека SS:ESP на стек нулевого уровня привилегий из сегмента состояния задачи TSS) и обращается к соответствующему дескриптору прерывания в таблице IDT. Если в качестве такого дескриптора используется 32-битный шлюз ловушки или шлюз прерывания, то он должен указывать на несогласованный кодовый сегмент с нулевым уровнем привилегий (уровень привилегий DPL соответствующего шлюза должен быть установлен в 3, а CPL процедуры обработки прерывания должен быть равен 0, чтобы обеспечить обработку прерывания защищенного режима на нулевом уровне привилегий), в противном случае генерируется ошибка общей защиты (#GP) с селектором этого сегмента в коде ошибки.

После переключения на нулевой уровень привилегий и загрузки новых значений указателя стека SS:ESP процессор сохраняет в стеке текущие значения сегментных регистров GS, FS, DS, ES, а затем очищает эти регистры, помещая в них нулевые селекторы. Далее действия процессора идентичны процедуре обработки прерываний защищенного режима — он сохраняет в стеке старые значения SS, ESP, EFLAGS, CS и EIP, сбрасывает флаги VM, NT, TF, RF и IF (последний сбрасывается, только если используется шлюз прерывания) регистра флагов EFLAGS и передает управление в обработчик прерывания (см. рис. 6.11.).

Если при вызове программных прерываний командой INT n текущий уровень привилегий ввода/вывода EFLAGS.IOPL меньше текущего уровня привилегий задачи (то есть EFLAGS.IOPL < 3), то генерируется ошибка общей защиты (#GP) и управление передается в обработчик этой ошибки. Такое поведение называется IOPL-чувствительностью и в режиме V86 характерно также для команд CLI, STI, POPF/POPFD, PUSHF/PUSHFD, IRET/IRETD.

При возврате из прерывания по завершении работы программы обработчика защищенного режима процессор получает команду IRETD. Последовательно загружая сохраненные в стеке значения, он считывает и значение флага EFLAGS.VM. При обнаружении единицы в этом флаге производится обратное переключение в режим V86 и восстановление из стека сегментных регистров ES, DS, FS, GS, после чего управление передается в прерванную программу. Если команда IRETD будет получена на уровне привилегий, отличном от нуля, то процессор не сможет установить флаг EFLAGS.VM – и соответственно – не переключится в режим V86 — возврат будет произведен некорректно.

 

Стек после вызова прерывания в режиме V86

Рис. 6.11. Стек после вызова прерывания в режиме V86

 

В процессорах, начиная с Pentium, реализуются специальные расширения системы обработки прерываний в защищенном режиме и режиме V86. Это так называемые виртуальные прерывания защищенного режима (включаются при CR4.PVI = 1) и режим EV86 (включается при CR4.VME = 1). В защищенном режиме активация виртуальных прерываний никак не влияет на порядок обработки программных прерываний и особых ситуаций, генерируемых командой INT n (равно как и командами INTOINT 3, INT01, BOUND). А вот в режиме EV86 включается совершенно другой механизм обработки программных прерываний, который подразумевает наличие четырех разных режимов, определяемых текущими установками флагов и управляющих параметров процессора и конкретной задачи V86:

 

Указанные режимы действуют только для команд генерации программных прерываний INT n, имеющих двухбайтный код операции (CD ib). Однобайтные команды INTOINT 3INT01, а также команда BOUND относятся к командам генерации программных особых ситуаций и на них не распространяется действие расширений режима EV86.

 

Таблица 6.54. показывает, какое действие из нижней части таблицы происходит в случае выполнения условий из верхней части таблицы. Каждый символ "+" в нижней части указывает на то, что выполняется соответствующая процедура, как это определено в подпункте Операция, в противном случае имеет место ошибка общей защиты #GP(0).

 

Таблица 6.54. Возможные варианты обработки прерываний
(согласно подпункта Операция)

Режим реальной адресации   Защищенный режим Режим V86
      Режим EV86

CR0.PE

0 1 1 1 1 1 1 1 1 1 1 1 1

EFLAGS.VM

x x x x x 0 1 1 1 1 1 1 1
CR4.VME x x x x x x 0 0 1 1 1 1 1
IRB[n] x x x x x x x x 0 x 0 1 1

EFLAGS.IOPL

x x x x x x < 3 = 3 < 3 x = 3 < 3 = 3

CPL

x > DPLш 3 3 x x x x x
DPL шлюза x < CPL x x x x x x x
DPL нового кодового сегмента > CPL = CPL < CPL
Тип прерывания П1 П П АО1 П П П

Тип дескриптора (шлюза) прерывания

IVT З Л, П Л, П Л, П Л, П Л, П IVT Л, П IVT Л, П Л, П
Режим реальной адресации:
REAL-ADDRESS-MODE
+                        
Защищенный режим:
PROTECTED-MODE
  + + + + + + +   +     +

Шлюз ловушки или прерывания:
TRAP-OR-INT-GATE

      + + + + +   +     +
Прерывание на уровень с большими привилегиями: 
INT-TO-INTER-PRIV
          +              
Прерывание без изменения привилегий: 
INT-TO-INTRA-PRIV
        +                

Прерывание из режима V86: 
INT-FROM-V86-MODE

              +  

+
(р.1)

   

+
(р.4)

Прерывание в режиме EV86:
EV86-MODE
                +
(р.5)

 

+
(р.3)

 

 

Шлюз задачи: 
TASK-GATE
    +                    
Ошибка общей защиты (#GP)   +   +     +        

+
(р.2)

 

1 — включая особые ситуации, генерируемые командами INTO, INT 3, INT01, BOUND;

x — флаг или битовое поле может иметь любое значение;

+ — переход к соответствующей процедуре согласно подпункта Операция.

 

Условно-выраженная команда INTO в основном идентична команде INT n за исключением того, что номер прерывания задается неявно равным 4 и программная особая ситуация Переполнение (#OF) генерируется, только если установлен флаг переполнения OF

Аналогичным образом, командой INT 3 генерируется Прерывание 3 — Точка останова (#BP). Это прерывание предназначено для использования отладчиком, который размещает специальную однобайтную команду INT 3 (код CCh) вместо первого байта команд или вместо однобайтных команд. Существует второй способ вызова такого прерывания — с помощью двухбайтного кода INT 3 (код CD03h). Однако данный метод на практике не применяется, все ассемблеры x86 по умолчанию интерпретируют мнемонику INT 3 как однобайтную команду с кодом CCh (но это не исключает возможность ручного программирования двухбайтного кода). Помимо размера кода, отличается и процесс обработки одно- и двухбайтных команд INT 3.

Прерывание, сгенерированное любой однобайтной командой (INTO, INT 3, INT01) или командой BOUND, в режиме EV86 (CR4.VME = 1) не подвергается перенаправлению по карте перенаправления прерываний (как это описано для Режима 2Режима 3Режима 5) и всегда обрабатывается обработчиком защищенного режима через обращение к соответствующему дескриптору в таблице IDT (то есть перманентно используется Режим 4). Кроме того, в режиме V86 для таких прерываний не осуществляется проверка поля EFLAGS.IOPL и, соответственно, не генерируется ошибка общей защиты #GP, когда EFLAGS.IOPL < 3 (то есть указанные команды не являются IOPL-чувствительными).

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

Представленный здесь перечень особых ситуаций характеризует поведение процессора не только при выполнении команды INT n, но и при поступлении любого внешнего прерывания или генерации особой ситуации. Бит EXT в коде ошибки используется для индикации внешнего по отношению к прерванной программе события (внешнего прерывания).

#GP(индекс прерывания * 8 + 2 + EXT), если:

#GP(0 + EXT), если указатель команды (OFFSET) в дескрипторе шлюза из таблицы IDT не попадает в пределы кодового сегмента.

#GP(код ошибки), если:

#TS(код ошибки), если:

#NP(код ошибки), если:

#SS(0 + EXT), если:

  • при записи в стек (в том числе в новый стек, если имело место переключение стека) значений адреса возврата, указателя стека, флагов или кода ошибки просходит выход за допустимую границу стекового сегмента;
  • новый сегмент стека не присутствует (бит P дескриптора сегмента сброшен).

#BP, если исполняется команда INT 3.
#OF, если исполняется команда INTO и флаг EFLAGS.OF = 1.

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

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

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

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

#GP, если вектор прерывания превышает предел таблицы векторов прерываний (IVT) (предел таблицы векторов прерываний может быть задан при программировании регистра IDTR).
#SS, при нарушении границ стекового сегмента во время сохранения данных в стеке.
#BP, если исполняется команда INT 3.
#OF, если исполняется команда INTO и флаг EFLAGS.OF = 1.

Intel386 … :
#UD при использовании префикса LOCK.
#DB, если исполняется команда INT01.

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

Представленный здесь перечень особых ситуаций характеризует поведение процессора не только при выполнении команды INT n, но и при поступлении любого внешнего прерывания или генерации особой ситуации. Бит EXT в коде ошибки используется для индикации внешнего по отношению к прерванной программе события (внешнего прерывания).

#GP(индекс прерывания * 8 + 2 + EXT), если:

#GP(0), если исполняется команда INT n когда текущий уровень привилегий ввода/вывода EFLAGS.IOPL < 3 (кроме режима EV86).

#GP(0 + EXT), если указатель команды (OFFSET) в дескрипторе шлюза из таблицы IDT не попадает в пределы кодового сегмента.

#GP(код ошибки), если:

#TS(код ошибки), если:

#NP(код ошибки), если:

#SS(0 + EXT), если:

  • при записи в стек (в том числе в новый стек, после переключения стека) значений адреса возврата, указателя стека, сегментных регистров, флагов или кода ошибки просходит выход за допустимую границу стекового сегмента;
  • новый сегмент стека не присутствует (бит P дескриптора сегмента сброшен).

#BP, если исполняется команда INT 3.
#OF, если исполняется команда INTO и флаг EFLAGS.OF = 1.

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

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

Pentium (в режиме EV86):
#GP(0), если исполняется команда INT n когда текущий уровень привилегий ввода/вывода EFLAGS.IOPL < 3, а соответствующий прерыванию бит карты перенаправления прерываний IRB равен 1.


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



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

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

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