Система команд x86 |
|
Программирование - Архитектура и система команд микропроцессоров x86 |
INT01
Влияние команды на флаги и форматы команды:
|
|
0 |
0 |
|
|
|
|
|
F1 |
INT01 (ICEBP) |
Вызов прерывания 1 (#DB, отладка) |
386 |
(недокументированная мнемоника) |
Описание:
Команда INT01 (ее также называют ICEBP) была впервые упомянута в документации на процессор Pentium Pro, но полного описания действия этой команды не было опубликовано никогда. По-видимому, эта команда поддерживается всеми моделями процессоров, начиная c Intel386, и предназначена для генерации прерывания 1. То есть по форме действия команда INT01 идентична команде INT n за исключением того, что номер прерывания задается неявно равным 1 (это в целом похоже на команду INT 3, где номер прерывания неявно равен 3).
Само название ICEBP появилось из словосочетания In-circuit emulation breakpoint (точка останова внутрисхемного эмулятора). Функционал внутрисхемной эмуляции (In-Circuit Emulator – ICE) предназначен для отладки программ на аппаратном уровне на специальных отладочных стендах (ICE-стенд). До появления защищенного режима в процессорах Intel286 аппаратным отладчикам (отладочным стендам) в целом хватало возможности пошагового исполнения с одновременным контролем сигналов на шинах процессора. Но с появлением Intel286 оказалось, что таких возможностей нехватает для эффективной отладки сложного программного обеспечения в защищенном режиме. Как следствие, в процессорах начиная с Intel386 были реализованы специальные расширения архитектуры (отладочные регистры и специальные команды), которые позволяют разработчикам как осуществлять пошаговое исполнение отлаживаемого кода, так и устанавливать точки останова по определенным событиям. Специальный режим внутрисхемной эмуляции (ICE) в этих процессорах также был существенно доработан, что позволило создавать отладочные стенды, в которых аппаратные возможности отладки существенно переплетались с соответствующими программными расширениями системы команд процессора.
В последующих моделях процессоров функционал режима внутрисхемной эмуляции (ICE) подвергался определенным доработкам. Так что и порядок возможного использования команды ICEBP также трансформировался. Само название ICEBP со временем не прижилось. По факту, производители чипов стали выпускать специальные модификации процессоров с аппаратной поддержкой ICE для использования в составе программно-аппаратных отладочных стендов, исключив эти функции из обычных потребительских продуктов. Но если аппаратный функционал подразумевает наличие специальных выводов, которые можно подключать или не подключать к кристаллу процессора, то программная составляющая, реализуемая на уровне микроархитектуры, присутствует во всех модификациях. Так что более адекватным оказалось название INT01, поскольку именно оно отражает обычное действие данной команды — вызов прерывания 1.
В целом использование команды INT01 (ICEBP) зависит от того, какая архитектура внутрисхемного эмулятора (ICE) поддерживается данным конкретным процессором. Определенные различия имеются между процессорами до Pentium (Intel386, Intel486) и после (Pentium, Pentium Pro ... ), а для процессоров AMD — начиная с K6.
Действие команды INT01 в процессорах младших моделей может давать разный эффект в зависимости от значения специального бита перенаправления прерывания DR7.IR.
Если перенаправление прерывания неактивно (DR7.IR = 0), то INT01 в точности отвечает свой аббревиатуре и срабатывает как простой вызов программного прерывания с вектором 1 (аналогично двухбайтовой команде INT 1). То есть при встрече данной команды происходит переход к обработчику прерываний по заданному вектору. В отличие случая, когда генерируется особая ситуация отладки #DB (которая может возникнуть при установленном флаге трассировки EFLAGS.TF = 1), команда INT01 не устанавливает (и вообще никак не изменяет) значение флага трассировки EFLAGS.TF при записи образа регистра флагов EFLAGS в стек. Таким образом, после обработки прерывания и возврата управления в код прерванной процедуры не происходит последующей генерации особой ситуации отладки #DB как при пошаговом режиме работы.
Если же перенаправление прерывания установлено (DR7.IR = 1), то при поступлении команды INT01 процессор пытается взаимодействовать с оборудованием отладочного стенда для перехода к обработчику эмулятора. Но такое взаимодействие, как правило, возможно только для специальных отладочных версий микропроцессоров. Обычные тиражные (production) модели не имеют соответствующих активных выводов для взаимодействия с оборудованием стенда и могут просто зависать в данной ситуации.
Существует два способа включения перенаправления прерывания. Это можно сделать прямой установкой бита IR при записи нового значения в отладочный регистр DR7. Либо данный бит может быть установлен самим оборудованием отладочного стенда при определенных условиях.
В процессорах старших моделей (начиная с Pentium и AMD K6) эффект команды INT01 совершенно аналогичен, но сама архитектура работы отладчика была изменена и взаимодействие процессора с отладочным стендом стало осуществляться через специальный отладочный порт. В этих процессорах режим перенаправления прерывания включается и выключается через запись в специальный регистр модели Probe Mode Control Register (PMCR). При этом запись и чтение данного регистра возможны только через отладочный порт и нет никакого программного механизма для этого. Такая архитектура добавила гибкости в механизм отладки, так как она позволяет вкллючать перенаправление прерывания и переходить к эмуляции в любой момент исполнения программного кода.
Операция:
Представленный здесь алгоритм описывает не только поведение процессора при выполнении команды INT01, но и при поступлении любого внешнего прерывания или генерации особой ситуации.
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;
Особые ситуации защищенного режима:
Представленный здесь перечень особых ситуаций характеризует поведение процессора не только при выполнении команды INT01, но и при поступлении любого внешнего прерывания или генерации особой ситуации. Бит EXT в коде ошибки используется для индикации внешнего по отношению к прерванной программе события (внешнего прерывания).
#GP(индекс прерывания * 8 + 2 + EXT), если:
- дескриптор, соответствующий обрабатываемому вектору (индексу) прерывания, не находится в пределах таблицы дескрипторов прерываний (IDT);
- дескриптор, соответствующий обрабатываемому вектору (индексу) прерывания, не является дескриптором шлюза ловушки, шлюза прерывания или шлюза задачи;
- имеет место программное прерывание или программная особая ситуация (то есть один из случаев: INT n, INT 3, INT01, BOUND или INTO) и при этом текущий уровень привилегий (CPL) задачи больше уровня привилегий (DPL) дескриптора шлюза из таблицы IDT —
#GP(0 + EXT), если указатель команды (OFFSET) в дескрипторе шлюза из таблицы IDT не попадает в пределы кодового сегмента.
#GP(код ошибки), если:
- селектор сегмента в соответствующем обрабатываемому вектору (индексу) прерывания дескрипторе шлюза ловушки, шлюза прерывания или шлюза задачи является нулевым селектором;
- индекс селектора сегмента из соответствующего прерыванию дескриптора шлюза ловушки или дескриптора шлюза прерывания не попадает в пределы соответствующей таблицы дескрипторов;
- индекс селектора TSS из соответствующего прерыванию дескриптора шлюза задачи не попадает в пределы глобальной таблицы дескрипторов (GDT);
- дескриптор нового кодового сегмента не является дескриптором сегмента кода;
- уровень привилегий дескриптора (DPL) нового согласованного кодового сегмента больше текущего уровеня привилегий (CPL) задачи –
- уровень привилегий дескриптора (DPL) нового несогласованного кодового сегмента не равен текущему уровеню привилегий (CPL) задачи –
- селектор TSS из соответствующего прерыванию дескриптора шлюза задачи указывает на локальную таблицу дескрипторов (LDT);
- дескриптор TSS новой задачи отмечен как занятый – TYPE.B ≠ 1.
#TS(код ошибки), если:
- адрес, по которому должно считываться новое значение для указателя стека (SS:eSP), выходит за пределы сегмента TSS;
- селектор нового сегмента стека является нулевым селектором;
- индекс селектора нового сегмента стека не попадает в пределы соответствующей таблицы дескрипторов;
- запрашиваемый уровень привилегий (RPL) селектора нового сегмента стека не равен уровню привилегий дескриптора (DPL) нового сегмента кода –
- уровень привилегий дескриптора (DPL) нового сегмента стека не равен уровню привилегий дескриптора (DPL) нового сегмента кода –
- новый стековый сегмент не является сегментом данных доступным для записи –
[TSS(SSx)].W) ≠ 1.
#NP(код ошибки), если:
- соответствующий прерыванию дескриптор шлюза ловушки, шлюза прерывания, шлюза задачи либо дескриптор TSS отмечен как неприсутствующий (бит P дескриптора сброшен);
- новый сегмент кода не присутствует (бит P дескриптора сегмента сброшен).
#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).
Особые ситуации режима реальной адресации:
Представленный здесь перечень особых ситуаций характеризует поведение процессора не только при выполнении команды INT01, но и при поступлении любого внешнего прерывания или генерации особой ситуации.
#GP, если вектор прерывания превышает предел таблицы векторов прерываний (IVT) (предел таблицы векторов прерываний может быть задан при программировании регистра IDTR).
#SS, при нарушении границ стекового сегмента во время сохранения данных в стеке.
#BP, если исполняется команда INT 3.
#OF, если исполняется команда INTO и флаг EFLAGS.OF = 1.
Intel386 … :
#UD при использовании префикса LOCK.
#DB, если исполняется команда INT01.
Особые ситуации режима V86:
Представленный здесь перечень особых ситуаций характеризует поведение процессора не только при выполнении команды INT01, но и при поступлении любого внешнего прерывания или генерации особой ситуации. Бит EXT в коде ошибки используется для индикации внешнего по отношению к прерванной программе события (внешнего прерывания).
#GP(индекс прерывания * 8 + 2 + EXT), если:
- дескриптор, соответствующий обрабатываемому вектору (индексу) прерывания, не находится в пределах таблицы дескрипторов прерываний (IDT);
- дескриптор, соответствующий обрабатываемому вектору (индексу) прерывания, не является дескриптором шлюза ловушки, шлюза прерывания или шлюза задачи.
- имеет место программное прерывание или программная особая ситуация (то есть один из случаев: INT n, INT 3, INT01, BOUND или INTO) и при этом уровень привилегий (DPL) дескриптора шлюза из таблицы IDT не равен 3 —
DPLшлюз ≠ 3.
#GP(0), если исполняется команда INT n когда текущий уровень привилегий ввода/вывода EFLAGS.IOPL < 3 (кроме режима EV86).
#GP(0 + EXT), если указатель команды (OFFSET) в дескрипторе шлюза из таблицы IDT не попадает в пределы кодового сегмента.
#GP(код ошибки), если:
- селектор сегмента в соответствующем обрабатываемому вектору (индексу) прерывания дескрипторе шлюза ловушки, шлюза прерывания или шлюза задачи является нулевым селектором;
- индекс селектора сегмента из соответствующего прерыванию дескриптора шлюза ловушки или дескриптора шлюза прерывания не попадает в пределы соответствующей таблицы дескрипторов;
- индекс селектора TSS из соответствующего прерыванию дескриптора шлюза задачи не попадает в пределы глобальной таблицы дескрипторов (GDT);
- дескриптор нового кодового сегмента не является дескриптором сегмента кода;
- уровень привилегий дескриптора (DPL) нового несогласованного кодового сегмента не равен нулю —
- селектор TSS из соответствующего прерыванию дескриптора шлюза задачи указывает на локальную таблицу дескрипторов (LDT);
- дескриптор TSS новой задачи отмечен как занятый – TYPE.B ≠ 1.
#TS(код ошибки), если:
- адрес, по которому должно считываться новое значение для указателя стека (SS0:ESP0), выходит за пределы сегмента TSS;
- селектор нового сегмента стека является нулевым селектором;
- индекс селектора нового сегмента стека не попадает в пределы соответствующей таблицы дескрипторов;
- запрашиваемый уровень привилегий (RPL) селектора нового сегмента стека не равен нулю —
TSS(SS0.RPL) ≠ 0;
- уровень привилегий дескриптора (DPL) нового сегмента стека не равен нулю —
[TSS(SS0)].DPL) ≠ 0;
- новый стековый сегмент не является сегментом данных доступным для записи –
[TSS(SS0)].W) ≠ 1.
#NP(код ошибки), если:
- соответствующий прерыванию дескриптор шлюза ловушки, шлюза прерывания, шлюза задачи либо дескриптор TSS отмечен как неприсутствующий (бит P дескриптора сброшен);
- новый сегмент кода не присутствует (бит P дескриптора сегмента сброшен).
#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.
Замечание:
Команды INT 1 и INT01 (ICEBP) вызывают генерацию особой ситуации типа ошибки трассировки (Fault) (не ловушки – Trap). При этом, в отличие от пошагового исполнения через установку флага EFLAGS.TF, не происходит записи в отладочный регистр DR6 служебной информации о точке останова.
Все права защищены © Алексей Ровдо, 1994-2023. Перепечатка возможна только по согласованию с владельцем авторских прав. admin@club155.ru