- •8. Прерывания и исключения
- •Прерывания и исключения защищенного режима
- •Приоритеты событий, вызывающих прерывания
- •Обработка прерываний в реальном режиме
- •Обработка прерываний в защищенном режиме
- •Возможности последовательной обработки исключений различных классов
- •Условия недостоверности сегмента tss
- •Приоритеты sse-исключений операций с плавающей точкой
- •Варианты обработки прерываний в режиме виртуального 8086
- •Виртуальные прерывания в режиме виртуального 8086
- •Обработка прерываний с использованием idt (защищенный режим)
- •Обработка прерываний с помощью таблицы векторов прерываний (реальный режим).
- •Обработка прерываний с использованием признаков vif и vip
Обработка прерываний в защищенном режиме
В защищенном режиме вызов подпрограмм обслуживания прерываний осуществляется через дескрипторную таблицу прерываний IDT (Interrupt Descriptor Table), которая может располагаться в любом месте адресного пространства. Базовый линейный адрес этой таблицы хранится в регистре IDTR (рис.??).
Загрузка содержимого регистра IDTR осуществляется с помощью инструкции LIDT, а его сохранение в памяти - с помощью инструкции SIDT. Инструкция LIDT является привилегированной и может выполняться только программой, имеющей высший уровень привилегий CPL=0. Инструкция SIDT может быть выполнена при любом уровне привилегий программы.
Элементами таблицы IDT являются системные дескрипторы прерываний, имеющие размер по 8 байт. Поэтому максимальный размер таблицы IDT составляет 2 Кбайт при использовании всех 256 видов прерываний (исключений). В таблице могут содержаться три вида системных дескрипторов: шлюз прерывания, шлюз ловушки и шлюз задачи.
Форматы содержимого шлюзов прерывания и ловушки приведены на рис 8.4,а,б. Они содержат селектор вызываемого при обслуживании сегмента, который поступает в регистр CS, и относительный адрес первой инструкции подпрограммы обслуживания, который загружается в регистр EIP. В дескрипторе также содержится бит P, указывающий на присутствие (при значении P=1) в памяти сегмента, в котором находится соответствующая подпрограмма обслуживания, и 2-битовое поле gDPL, определяющее уровень привилегий шлюза (см. раздел 7.1). Бит D в байте доступа определяет режим работы процессора при обслуживании прерываний если значение D=0, то процессор функционирует как 16-разрядный процессор 80286, если D=1, то обеспечивается нормальный 32-разрядный режим функционирования.
Передача управления через шлюз прерывания или шлюз ловушки может сопровождаться изменением уровня привилегий. Процессор проверяет значение gDPL в дескрипторе шлюза при выполнении программных прерываний, вызываемых инструкциями INT n, INT3, INTO. Переход к выполнению подпрограммы обслуживания в этих случаях производится, если CPLgDPL, т.е. численное значение уровня привилегий текущей программы меньше или равно значению уровня привилегий шлюза. Таким образом, величина gDPL ограничивает уровень привилегий программ, которые могут вызывать процедуру обслуживания программного прерывания. При выполнении других видов прерываний и исключений процессор игнорирует gDPL шлюза.
Привилегированность сегмента инструкций, в котором размещается подпрограмма обслуживания, должна быть выше привилегированности текущей программы (DPLCPL). Нарушение этого правила приводит к исключению типа #GP. Поэтому рекомендуется подпрограммы обслуживания прерываний и исключений располагать в сегментах с уровнем привилегий DPL=0, чтобы избежать ситуации, когда при поступлении запроса прерывания или исключения уровень текущей программы CPL окажется меньше, чем DPL сегмента инструкций обработчика прерывания.
При возникновении прерывания процессор сохраняет в стеке следующую информацию:
Содержимое регистра SS прерванной процедуры (если имеет место изменение уровня привилегий).
Содержимое регистра ESP прерванной процедуры (если имеет место изменение уровня привилегий).
Содержимое регистра EFLAGS.
Содержимое регистра CS.
Содержимое регистра EIP.
Код ошибки (если он формируется для данного исключения).
Далее процессор устанавливает в регистре EFLAGS значения признаков TF=VM=NT=0.
Единственное различие между использованием шлюза ловушки и шлюза прерывания состоит в том, как процессор поступает с признаком IF. Если вызов подпрограммы обслуживания производится через шлюз прерывания, то после сохранения в стеке содержимого регистра EFLAGS, процессор устанавливает значение признака IF=0, запрещая маскируемые прерывания. Если переход к подпрограмме обслуживания осуществляется через шлюз ловушки, то значение признака IF не изменяется.
Возврат из подпрограммы обслуживания прерывания осуществляется с помощью инструкции IRET. При восстановлении из стека содержимого регистра EFLAGS действуют следующие правила:
поле IOPL восстанавливается только, если CPL=0,
флаг IF изменяется только, если CPLIOPL.
Формат дескриптора шлюза задачи при реализации прерываний и исключений имеет обычный вид (рис.7.16). Когда прерывание обрабатывается через шлюз задачи, то процессор выполняет обычную процедуру переключения задач, как это описано в разд. 7.4.
При реализации некоторых исключений процессор заносит в стек код ошибки, формат которого приведен на рис. $.2. Заметим, что формат кода ошибки #PF несколько другой и описан в следующем разделе.
31 |
16 |
15 |
3 |
2 |
1 |
0 |
Резервировано |
Индекс селектора |
TI |
IDT |
EXT |
||
Рис. $.2. Формат кода ошибки
Индекс селектора (биты 15-3) - указывает на дескриптор, использование которого вызвало исключение. Биты IDT, TI указывают на таблицу, в которой находится неверный дескриптор. Если IDT=1, то дескриптор находится в таблице IDT. Если IDT=0, то размещение дескриптора определяется битом TI: если TI=0, то дескриптор находится в таблице GDT, если ТI=1 - в таблице LDT. Если ЕХТ=1, то исключение вызвано не выполняемой программой, а внешним сигналом прерывания.
$.2. Причины возникновения исключений
В предыдущих главах рассмотрены основные случаи, при которых реализуются различные виды исключений (табл. $.1). Поэтому в данном разделе ограничимся кратким обзором причин их возникновения.
Исключение 0 - деление на нуль (#DE). Возникает при выполнении инструкций DIV, IDIV, если делитель равен нулю, или если результат не может разместиться в операнд-приемник (превышает разрядность приемника).
Исключение 1 - исключение для отладки (#DB). В зависимости от типа аппаратной точки останова исключение #DB может обслуживаться как ошибка или как ловушка. Возникает и обрабатывается как ловушка:
обращении к данным или портам ввода вывода;
в пошаговом режиме (при значении признака TF=1 в регистре EFLAGS) после выполнения каждой инструкции;
при переключении на задачу, в сегменте TSS которой, установлен бит Т=1 (см. раздел 7.4);
при выполнении инструкции INT 1;
Возникает и обрабатывается как ошибка при достижении контрольной точки при выборке инструкций и в режиме внутрисхемной эмуляции.
Прерывание 2 - немаскируемое прерывание. Возникает при поступлении внешнего сигнала NMI=1 на вход NMI процессора или приеме соответствующего сообщения по шине APIC. Это прерывание может быть вызвано как программное с помощью инструкции INT 2.
Исключение 3 - исключение программной точки останова (#BP). Имеет место при выполнении однобайтной инструкции INT 3. Инструкция INT 3 обычно вводится в текст отлаживаемой программы для ее останова и контроля текущих результатов выполнения.
Исключение 4 - переполнение (#OF). Это исключение вызывается с помощью инструкции INTO. Инструкция INTO проверяет признак OF в регистре EFLAQS и реализует исключение #OF если значение этого признака OF=1.
Исключение 5 - превышение границы массива (#BR). Имеет место при выполнении инструкции BOUND, если содержимое проверяемого регистра выходит за указанные пределы (см. раздел 3.2).
Исключение 6 - недействительный код операции (#UD). Возникает при попытке выполнить инструкцию, в коде которой обнаружено какое-либо из следующих нарушений:
указан неиспользуемый (резервированный) код операции;
используется неправильный способ адресации операнда;
указан код ММХ- или SSE- инструкций при установленном в регистре CR0 значении бита ЕМ=1;
выбраны коды инструкций LLDT, SLOT, LTR, STR, LSL, ARPL, VERR, VERW при работе процессора в реальном режиме или режиме виртуального 8086;
префикс LOCK используется с инструкцией, при выполнении которой не должен производиться захват шины;
выбран код инструкции UD2, которая служит для вызова подпрограммы обслуживания данного исключения.
Исключение 7 - процессор FPU недоступен (#NM). Реализуется в следующих случаях:
при попытке выполнить FPU инструкцию, когда в регистре CR0 установлено значение бита ЕМ=1;
при попытке выполнить FPU-, MMX- или SSE-инструкцию, когда в регистре CR0 установлено значение бита TS=1;
попытка выполнить инструкцию WAIT или FWAIT, когда в регистре CR0 установлено значение битов МР=ТS=1.
Исключение 8 - двойная ошибка (#DF). Реализуется в случае, когда при вызове подпрограммы обслуживания одного исключения выявляется другое. Если процессор не может обработать такие исключения последовательно, то генерируется исключение #DF. При этом в стек заносится код ошибки с нулевым значением всех битов. Чтобы определить исключения, которые могут обрабатываться последовательно, они разбиты на три класса (см. табл. $.1): B (benign - безвредные), C (contributory - усугубляющие) и P (page - страничные). В табл. $.3 указано, какие классы исключений могут обрабатываться последовательно, а какие вызовут исключение #DF. Если при вызове исключения #DF обнаруживается другое исключение, то процессор переходит в отключенное состояние (shutdown).
Таблица $.3.
