Система команд x86 |
|
Программирование - Архитектура и система команд микропроцессоров x86 |
INT 3
Влияние команды на флаги и форматы команды:
|
|
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 3 предназначена для генерации прерывания 3 и по описанию операции идентична команде INT n за исключением того, что номер прерывания здесь не присутствует непосредственно в коде операции, но неявно задается равным 3.
Данное прерывание предназначено для использования отладчиком, который размещает специальную однобайтную команду INT 3 (код CCh) вместо первого байта команд или вместо однобайтных команд.
Существует второй способ вызова данного прерывания с помощью двухбайтного кода INT 3 (код CD03h). Однако данный метод на практике не применяется, все ассемблеры x86 по умолчанию интерпретируют мнемонику INT 3 как однобайтную команду с кодом CCh (но это не исключает возможность ручного программирования двухбайтного кода). Помимо размера кода, отличается и процесс обработки одно- и двухбайтных команд INT 3. Прерывание, сгенерированное однобайтной командой в режиме EV86 (CR4.VME = 1), не подвергается перенаправлению по карте перенаправления прерываний (как это описано для Режима 2, Режима 3, Режима 5) и всегда обрабатывается обработчиком защищенного режима через дескриптор в таблице IDT. Кроме того, в режиме V86 для данного прерывания не осуществляется проверок поля IOPL и, соответственно, не может быть сгенерирована ошибка общей защиты #GP когда EFLAGS.IOPL < 3, то есть однобайтная команда не является IOPL-чувствительной.
Операция:
Представленный здесь алгоритм описывает не только поведение процессора при выполнении команды INT 3, но и при поступлении любого внешнего прерывания или генерации особой ситуации.
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 3, но и при поступлении любого внешнего прерывания или генерации особой ситуации. Бит 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).
Особые ситуации режима реальной адресации:
Представленный здесь перечень особых ситуаций характеризует поведение процессора не только при выполнении команды INT 3, но и при поступлении любого внешнего прерывания или генерации особой ситуации.
#GP, если вектор прерывания превышает предел таблицы векторов прерываний (IVT) (предел таблицы векторов прерываний может быть задан при программировании регистра IDTR).
#SS, при нарушении границ стекового сегмента во время сохранения данных в стеке.
#BP, если исполняется команда INT 3.
#OF, если исполняется команда INTO и флаг EFLAGS.OF = 1.
Intel386 … :
#UD при использовании префикса LOCK.
#DB, если исполняется команда INT01.
Особые ситуации режима V86:
Представленный здесь перечень особых ситуаций характеризует поведение процессора не только при выполнении команды INT 3, но и при поступлении любого внешнего прерывания или генерации особой ситуации. Бит 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.
Все права защищены © Алексей Ровдо, 1994-2023. Перепечатка возможна только по согласованию с владельцем авторских прав. admin@club155.ru