4. Обработка прерываний.

4.1 Общие принципы.

4.2 Рестарт команд.

4.3 Приоритеты одновременно происходящих прерываний.

4.4 Механизмы передачи управления обработчикам прерываний.

4.5 Защита в процедурах прерываний.

4.6 Код ошибки.

4.7 Условия возникновения исключений.

 

4.1 Общие принципы.

 

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

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

Аппаратные прерывания подразделяются на маскируемые и немаскируемые. Процессор может воспринимать прерывания после выполнения каждой коман­ды, длинные строковые команды имеют для восприятия прерываний специаль­ные окна. Аппаратные прерывания вызываются электрическими сигналами на входах INTR и NMI.

Маскируемые прерывания вызываются переходом в высокий уровень сиг­нала на входе INTR (Interrupt Request) при установленном флаге разрешения (IF=1). В этом случае процессор сохраняет в стеке регистр флагов, сбрасы­вает флаг IF и вырабатывает два следующих друг за другом (back to back) цикла подтверждения прерывания, в которых генерируются управляющие сиг­налы INTA# (Interrupt Acknowledge). Высокий уровень сигнала INTR должен сохраняться по крайней мере до подтверждения прерывания. Первый цикл подтверждения холостой, по второму импульсу внешний контроллер прерыва­ний передает по шине номер вектора, обслуживающего данный тип аппарат­ного прерывания. Прерывание с полученным номером вектора выполняется процессором так же, как и программное. Обработка текущего прерывания может быть в свою очередь прервана немаскируемым прерыванием, а если обработчик установит флаг IF, то и другим маскируемым аппаратным прерыванием.

Немаскируемые прерывания выполняются независимо от состояния флага IF по сигналу NMI (Non Mascable Interrupt). Высокий уровень на этом входе вы­зовет прерывание с типом (вектором) 2, которое выполняется так же, как и маскируемое. Его обработка не может прерываться под действием сигнала на входе NMI до выполнения команды IRET.

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

Отказ (fault) — это исключение, которое обнаруживается и обслуживается до выполнения инструкции, вызывающей ошибку. После обслуживания этого исключения управление возвращается снова на ту же инструкцию (включая все префиксы), которая вызвала отказ. Отказы, использующиеся в системе вирту­альной памяти, позволяют, например, подкачать с диска в оперативную память, затребованную страницу или сегмент.

Ловушка (trap) — это исключение, которое обнаруживается и обслуживает­ся после выполнения инструкции, его вызывающей. После обслуживания этого исключения управление возвращается на инструкцию, следующую за вызвав­шей ловушку. К классу ловушек относятся и программные прерывания.

Аварийное завершение (abort) - это исключение, которое не позволяет точно установить инструкцию, его вызвавшую. Оно используется для сообще­ния о серьезной ошибке, такой как аппаратная ошибка или повреждение сис­темных таблиц.

 

Обработка прерываний и исключений в защищенном режиме базируется на таблице дескрипторов  прерываний (шлюзов прерываний) IDT – адрес начала и размер которой хранятся в регистре IDTR. Его формат аналогичен формату регистра GDTR (рис. 4.1).

Рис. 4.1 Формат регистра IDTR

 

Таблица прерываний может содержать до 256 дескрипторов. При попытке обслуживания прерывания с номером, выходящим за размер таблицы, генери­руется исключение #DF. Под исключения отданы первые 32 номера (0 ¸31).

Не все из этих векторов используются процессором в настоящее время; не назначенные векторы из этого диапазона резервируются для возможного использования в будущем. Использовать не назначенные векторы не следует.

Векторы маскируемых прерываний определяются аппаратно. Контроллеры внешних прерываний (например, Intel 8259, программируемый контроллер прерываний) передают вектор на шину процессора во время цикла квитирования прерывания. Использоваться могут любые векторы в диапазоне значений от 32 до 255. В реальном режиме диапазон номеров для обработки аппаратных прерываний находился: IRQ0¸IRQ7 номера прерываний 08h¸0Fh и  IRQ8¸IRQ15 – 70h¸77h. В связи с тем, что, как отмечалось выше, первые 32 номера заняты под исключения, возникает необходимость перепрограммировать контроллер прерываний на другие номера. Изначальным программирование контроллера для реального режима занимается BIOS. Итого в защищенном режиме остается 208 номеров под программные прерывания. Назначения векторов исключений и прерываний показаны в Таблице 4.1 .

 

1 В реальном режиме — вектор прерывания не попадает в таблицу.

2 В реальном режиме не возникают, но возможны в V86.

3 В реальном режиме — нарушение границы сегмента стека.

4 В реальном режиме — нарушение границы сегмента данных или кода.

 

Таблица 4.1 Назначения векторов исключений и прерываний

 

4.2 Рестарт команды.

 

Для большей части исключений и прерываний передача управления не происходит до конца текущей команды. Тем самым регистр EIP устанавливается таким образом, чтобы указывать на команду, следующую за командой, которая выполнялась в момент генерации исключения или прерывания. Если эта команда имеет префикс повторения, то передача управления происходит в конце текущей итерации, причем все регистры будут находиться в состоянии для выполнения следующей итерации. Однако, если данная ситуация относится по типу к сбоям, то регистры процессора восстанавливаются в состояние, предшествующее выполнению вызвавшей сбой команды. Тем самым допускается рестарт команды.

Рестарт команды используется для обработки исключений, блокирующих доступ к операндам. Например, прикладная программа могла обратиться к данным в сегменте, не присутствующем в памяти. В случае такого исключения обработчик исключения должен загрузить отсутствующий нужный сегмент (возможно, с жесткого диска) и возобновить выполнение, начиная с команды, вызвавшей данное исключение. Во время исключения команда могла изменить содержимое некоторых регистров процессора. При считывании командой значения из стека необходимо восстановить прежнее значение указателя стека. Все эти восстановительные операции выполняются процессором способом, совершенно прозрачным для прикладной программы.

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

 

4.3 Приоритеты одновременно происходящих прерываний.

 

Анализ условий обслуживания прерываний и исключений выполняется в следующем порядке (по убыванию приоритета):

 

1.   Проверка на исключение-ловушку отладки (#DS) по выполненной инструкции (пошаговый режим через флаг TF или точка останова по данным через регистры отладки).

2.           Проверка на исключение-отказ отладки (#DB) по последующей инструк­ции (точка останова по инструкции через регистр отладки).

3.           Немаскируемое прерывание (аппаратное по входу NMI).

4.           Маскируемое прерывание (аппаратное по входу INTR при IF=1).

5.           Проверка на исключение-отказ сегментации (#NP или #GP) при выборке следующей инструкции.

6.           Проверка на исключение-отказ страницы (#PF) при выборке следующей инструкции.

7.           Проверка на отказ декодирования следующей инструкции (#UD или #GP).

8.           Для операции WAIT проверка TS и МР (исключение #NM, если TS=1 и МР=1).

9.           Для операции ESCAPE (инструкция математического сопроцессора) про­верка ЕМ и TS (исключение #NМ, если EМ=1 или TS=1).

10.      Для операции WAIT или ESCAPE проверка на исключение #MF от сопро­цессора.

11.        Проверка на отказ сегментации (#NР, #SS, #GP) или отказ страницы (#PF) для операндов, используемых в инструкции.

 

Двойной отказ (Double Fault) — исключение #DF — возникает, когда при обработке исключения, связанного с сегментацией (#TS, #NP, #SS или #GP), процессор обнаруживает исключение, отличное от отказа страницы (#PF). Также двойной отказ возникает, если при обработке исключения отказа страни­цы #PF обнаруживается исключение другого типа. В этом случае тоже исполня­ется исключение #DF.

Если во время обслуживания исключения отказа страницы произойдет еще один отказ страницы, то происходит аварийный останов (Shutdown) процессо­ра. Во время аварийного останова никакие новые инструкции не выполняются. Из этого состояния процессор можно вывести только аппаратно сигналом NMI, оставляя его в защищенном режиме, или сигналом RESET, переводящим процессор в реальный режим.

Прерывания и исключения процессора, работающего в защищенном режиме, приведены в таблице. В примечаниях отмечены случаи, когда исключение ре­ального режима отличается от защищенного.

 

4.4 Механизмы передачи управления обработчикам прерываний.

 

Дескрипторная таблица прерываний (IDT) содержит шлюзы (рис 4.2).

 

 

Рис. 4.2 Формат шлюза IDT

 

Поле «TYPE» в байте доступа определяет тип шлюза:

 

· 4 - шлюз вызова 80286 (Call Gate);

· 5 - шлюз задачи 80286 (Task Gate);

· 6 - шлюз прерывания 80286 (Interrupt Gate);

· 7 - шлюз ловушки 80286 (Trap Gate);

· C - шлюз вызова 386+ (Call Gate);

· D - шлюз задачи 386+ (Task Gate);

· Е - шлюз прерывания 386+ (Interrupt Gate);

· F - шлюз ловушки 386+ (Trap Gate).

 

Шлюз прерывания содержит адрес входа в обработчик прерывания в виде «селектор сегмента» и «смещение».

Шлюзы вызова (Call Gates) используются для вы­зовов процедур со сменой уровня привилегий, шлюзы задач (Task Gates) исполь­зуются для переключения задач, шлюзы прерываний (Interrupt Gates) и ловушек (Trap Gates) определяют процедуры обслуживания прерываний. Шлюзы вызова позволяют автоматически копировать заданное число слов из старого стека в новый. Шлюзы прерываний отличаются от шлюзов ловушек только тем, что они запрещают прерывания (сбрасывают IF), а шлюзы ловушек — нет.

 

Аналогично тому, как команда CALL вызывает процедуру или задачу, так и исключение или прерывание может "вызвать" обработчик прерывания, представленный в виде процедуры или задачи. Реагируя на исключение или прерывание, процессор использует вектор особого прерывания или прерывания в качестве индекса дескриптора в IDT. Если процессор индексирует шлюз прерывания или шлюз ловушки, то вызов обработчика происходит аналогично вызову при помощи CALL шлюза вызова. Если процессор индексирует шлюз задачи, это приводит к переключению задачи аналогично вызову при помощи CALL шлюза задачи.

 

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

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

 

4.5 Защита в процедурах прерываний.

 

Правило привилегированности, управляющее процедурами прерывания, аналогично правилу, действующему при вызове процедуры: процессор не разрешает прерыванию передавать управление процедуре в менее привилегированный сегмент (с численно большим номером уровня привилегированности). Попытка нарушить это правило ведет к генерации исключения защиты.

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

 

· Обработчик исключения или прерывания должен быть помещен в конформный кодовый сегмент. Этот способ может использоваться  для обработчиков некоторых конкретных исключений (например,  деления на ноль). Такие обработчики должны использовать только данные, доступные через стек. Если обработчику требуются данные из сегмента данных, этот сегмент данных должен иметь уровень привилегированности 3, то есть он должен быть незащищенным.

· Обработчик может быть помещен в кодовый сегмент с уровнем   привилегированности 0. Такой обработчик будет выполняться  всегда, независимо от CPL программы.

 

4.6 Код ошибки.

 

При отработке исключения в защищенном режиме процессор сохраняет в стеке слово кода ошибки (Error Code). Если оно отлично от нуля, то в нем содержится селектор дескриптора, с которым связана ошибка.

Код ошибки имеет формат, показанный на Рисунке 4.3 .

Рис. 4.3 Формат кода ошибки

 

 Код ошибки похож на селектор сегмента, однако вместо поля RPL код ошибки содержит два однобитовых поля:

 

1.           Процессор устанавливает бит EXT, если исключение вызвано событием, внешним по отношению к программе.

2.           Процессор устанавливает бит IDT, если индексная часть кода ошибки ссылается к дескриптору шлюза в IDT.

 

Если бит IDT не установлен, то бит TI указывает на то, ссылается ли код ошибки к GDT (бит TI очищен), или же к LDT (бит TI установлен). Остальные 13 битов - это старшие биты селектора сегмента. В некоторых случаях код ошибки является пустым (т.е. все биты его младшего слова очищены.) Код ошибки помещается в стек в виде двойного слова. Это делается для выравнивания стека по адресам, кратным четырем. Старшая половина двойного слова резервируется.

 

4.7 Условия возникновения исключений.

 

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

 

Сбои - Сохраненное содержимое регистров CS и EIP указывает на  команду, сгенерировавшую сбой.

Ловушки - Сохраненное содержимое регистров CS и EIP,  записанное в момент срабатывания ловушки, указывает на  команду, которая должна быть выполнена после команды,  сгенерировавшей ловушку. Если ловушка обнаружена в команде  передачи управления, сохраненное содержимое регистров CS и EIP  отражает эту передачу управления. Например, если ловушка  сработала в команде JMP, то сохраненное значение регистров CS  и EIP указывает на адрес назначения перехода команды JMP, а не  на команду в следующем адресе после команды JMP.

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

 

Исключение 0 - Ошибка деления

 

Сбой типа "ошибки деления" встречается в командах DIV или IDIV, при делителе равном 0.

 

Исключение 1 - Отладочные исключения

 

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

 

· Сбой в контрольной точке адреса команды;

· Ловушка в контрольной точке адреса данных;

· Ловушка шага выполнения;

· Ловушка контрольной точки переключения задачи.

 

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

 

Исключение 3 - Контрольная точка

 

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

Сохраненное содержимое регистров CS и EIP указывает на байт, следующий за контрольной точкой. Если отладчик позволяет возобновление приостановленной программы, он заменяет команду INT 3 исходным кодом операции по адресу контрольной точки, а также декрементирует сохраненное содержимое регистра EIP перед возвратом.

 

Исключение 4 - Переполнение

 

Ловушка переполнения происходит, когда процессор выполняет команду INTO при установленном флаге IF. Поскольку арифметические операции со знаком и без знака используют некоторые общие команды, процессор не в состоянии определить, когда фактически происходит переполнение. Вместо этого он устанавливает флаг OF, когда результаты, интерпретируемые как числа со знаком, выходят за пределы допустимого диапазона. При выполнении арифметических операций с операндами, имеющими знак, флаг OF можно тестировать непосредственно, либо при помощи команды INTO.

 

Исключение 5  -  Контроль диапазона

 

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

 

Исключение 6  -  Неверный код операции

 

Сбой "неверного кода операции" генерируется, когда исполнительный модуль обнаруживает неверный код операции. (Данное исключение не будет обнаружено до тех пор, пока не будет сделана попытка выполнить неверный код операции; т.е. предварительная выборка неверного кода операции, без выполнения, не ведет к данному исключению). Код ошибки в данном случае на стек не помещается. Такое исключение может обрабатываться в пределах той же задачи.

Это исключение происходит также при неверном типе операнда для данного кода операции. Примером может служить команда межсегментного перехода JMP, использующая регистровый операнд, либо команда LES с регистровым исходным операндом.

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

Неопределенные коды операций:

-----------------------------------------------------------------

Однобайтовые

-----------------------------------------------------------------

82

D6

F1

-----------------------------------------------------------------

Двухбайтовые

-----------------------------------------------------------------

0F 07

0F 10

0F 11

0F 12

0F 13

 

F6 XX

F7 XX

 

C0 XX

C1 XX

D0 XX

D1 XX

D2 XX

D3 XX

-----------------------------------------------------------------

Выше приведенные инструкции зарезервированы «на будущее». Эти коды операций прерывания 6 не генерируют.

 

Исключение 7  -  Устройство недоступно

 

Сбой типа "устройство недоступно" генерируется при одном из двух следующих условий:

 

· Процессор выполняет команду ESC при установленном бите EM регистра CR0;

· Процессор выполняет команду WAIT или ESC при установленном  бите TS регистра CR0.

 

Таким образом, прерывание 7 происходит, когда программист хочет, чтобы команда ESC обрабатывалась программно (бит EM установлен), либо когда встречена команда WAIT или ESC, а контекст модуля операций с плавающей точкой отличен от контекста для текущей задачи.

Для процессоров 80286 и 386 бит MP регистра CR0 используется с битом TS для определения того, должна ли команда WAIT генерировать исключение. Для программ, выполняемых на процессоре i486, бит MP должен быть установлен всегда.

 

Исключение 8 - Двойной сбой

 

Обычно когда процессор обнаруживает исключение при попытке вызвать обработчик исключения, происшедшей ранее, эти два исключения могут обрабатываться последовательно. Однако, если процессор не в состоянии этого сделать, он генерирует исключение двойного сбоя. Для того, чтобы определить, когда о двух сбоях следует сообщить как о двойном сбое, процессор делит исключения на три класса: незначительные исключения (1-7,16), значительные исключения (0,10-13) и страничные сбои (14).

Когда происходит два незначительных исключения или прерывания, либо одно незначительное и одно значительное, то два таких события могут обрабатываться последовательно. В случае двух значительных событий они не могут быть обработаны, и тогда генерируется исключение двойного сбоя.

Если за незначительным или значительным исключением следует страничный сбой, то два таких события могут быть обработаны последовательно. Это также справедливо и в том случае, когда сначала следует страничный сбой, а за ним незначительное исключение. Однако, если за страничным сбоем следует значительное исключение или еще один страничный сбой, то генерируется аварийное завершение типа "двойной сбой".    

Любые последующие сбои, генерируемые при попытках процессора передать управление соответствующему обработчику прерывания, могут также привести к ситуации двойного сбоя.

Процессор всегда помещает код ошибки в стек обработчика двойного сбоя, однако этот код ошибки всегда равен 0. Рестарт вызвавшей сбой команды невозможен. Если при попытке вызвать обработчик двойного сбоя произойдет еще одно исключение, процессор входит в режим закрытия системы. Этот режим аналогичен состоянию, следующему за выполнением команды HLT. Никакие дальнейшие команды не выполняются до приема немаскируемого прерывания или сигнала сброса системы RESET. Если закрытие системы происходит во время выполнения процессором обработчика немаскируемого прерывания, то рестарт процессора возможен только при помощи сигнала RESET. Процессор генерирует специальный цикл шины, указывающий на вхождение процессора в режим закрытия.

 

Исключение 9  -  (Резервируется Intel. Не использовать!)

 

Прерывание 9, аварийное завершение выхода за границы сегмента сопроцессора, генерируется в системе центрального процессора 386/математического сопроцессора 387, когда процессор 386 обнаруживает нарушение границы страницы или сегмента при пересылке средней части операнда математического сопроцессора 387. Это прерывание процессором i486+ не генерируется; вместо него происходит прерывание 13.

 

Исключение 10  -  Неверный TSS

 

Сбой типа "неверный TSS" генерируется при попытке переключения задачи на сегмент с неверным TSS. TSS является неверным в случаях, описанных в таблице ниже. Код ошибки помещается в стек обработчика исключений, что помогает идентифицировать причину сбоя. Бит EXT указывает, что исключение было вызвано условием вне управления программы (например, внешнее прерывание, используя шлюз задачи, попыталось выполнить переключение задачи на неверный TSS).

--------------------------------------------------------------------------------------------------------------------------

Индекс кода ошибки     Описание

--------------------------------------------------------------------------------------------------------------------------

Сегмент TSS         Граница сегмента TSS меньше 67H

Сегмент LDT        Неверная LDT или LDT не присутствует

Сегмент стека      Селектор сегмента стека превышает границу таблицы дескрипторов

Сегмент стека      Сегмент стека не доступен для записи

Сегмент стека      DPL сегмента стека не совместим с CPL

Сегмент стека      RPL селектора сегмента стека не совместим с CPL

Сегмент кода       Селектор сегмента кода превышает границу таблицы дескрипторов

Сегмент кода       Сегмент кода не является выполняемым

Сегмент кода       DPL не конформного сегмента кода  не равен CPL

Сегмент кода       DPL конформного  сегмента кода больше  CPL

Сегмент данных Селектор сегмента данных превышает границу таблицы дескрипторов

Сегмент данных Сегмент данных не доступен для чтения

--------------------------------------------------------------------------------------------------------------------------

 

Данный сбой может происходить как в контексте исходной задачи, так и в контексте новой задачи. До тех пор, пока процессор полностью не убедится в присутствии нового TSS, исключение происходит в контексте исходной задачи. Как только присутствие нового TSS будет подтверждено, переключение задачи считается завершенным, т.е. регистр TR загружен селектором нового TSS, и если переключение задачи является следствием CALL или прерывания, то поле Компоновки нового TSS будет содержать ссылку на старый TSS. Любые ошибки, обнаруженные процессором после этой точки, обрабатываются в контексте новой задачи.

Чтобы гарантировать доступность TSS для обработки исключения, обработчик исключения типа "неверный TSS" должен вызываться как задача посредством шлюза задачи.

 

Исключение 11  -  Сегмент не присутствует

 

Сбой типа "сегмент не присутствует" генерируется, когда процессор обнаруживает, что бит Присутствия в дескрипторе очищен. Процессор может генерировать данный сбой в одном из следующих случаев:

 

· При попытке загрузить регистры CS, DS, ES, FS или GS; однако,  загрузка регистра SS вызывает сбой стека.

· При попытке загрузить регистр LDT при помощи команды LLDT,  однако, загрузка регистра LDT во время операции переключения  задачи вызывает исключение "неверный TSS".

· При попытке использовать дескриптор шлюза, помеченный  признаком "сегмент не присутствует".

 

Данный сбой позволяет выполнение рестарта. Если обработчик исключений загружает сегмент и возвращается, то прерванная программа продолжает выполнение.

Если исключение "сегмент не присутствует" происходит во время переключения задачи, то не все шаги переключения задачи завершаются. При переключении задачи процессор сначала загружает все сегментные регистры, а затем проверяет допустимость их содержимого. При обнаружении исключения "сегмент не присутствует" остальные сегментные регистры не проверяются, и следовательно, не могут быть использованы для ссылок к памяти. Обработчик исключения "сегмент не присутствует" не должен полагаться на возможность использования селекторов сегментов, находящихся в регистрах CS, SS. DS, ES, FS и GS без возникновения еще одного исключения. Обработчик должен проверять все сегментные регистры перед тем, как пытаться возобновить выполнение новой задачи; в противном случае, далее могут произойти сбои общей защиты, причем в условиях, которые сделают диагностирование еще более затруднительным. Для обработки этого случая имеется три способа:

 

1.           Обработка сбоя "сегмент не присутствует" в задаче. Обратное   переключение на прерванную задачу заставит процессор   проверить все регистры при загрузке их из TSS.

2.           Использование для всех сегментных регистров команд PUSH и   POP. Каждая команда POP заставит процессор проверить новое   содержимое сегментного регистра.

3.           Проверка сохраненного в TSS значения каждого сегментного   регистра при помощи симуляции теста, выполняемого процессором   при загрузке сегментного регистра.

 

Данное исключение помещает в стек код ошибки. Бит EXT кода ошибки устанавливается в том случае, если внешнее по отношению к программе событие вызвало прерывание, которое затем привело к ссылке на не присутствующий сегмент. Бит IDT устанавливается, если код ошибки выполняет ссылку на элемент IDT (например, команда INT, ссылающаяся на не присутствующий шлюз).

Операционная система обычно использует исключение "сегмент не присутствует" для реализации на сегментном уровне виртуальной памяти. Однако, обозначение не присутствия сегмента в дескрипторе шлюза обычно не означает, что сегмент не присутствует (поскольку шлюзы не обязательно должны соответствовать сегментам). Не присутствующие шлюзы могут использоваться операционной системой для переключения исключений, имеющих специальное значение для операционной системы.

 

Исключение 12 - Исключение в стеке

 

Сбой в стеке генерируется в двух следующих случаях:

 

· В результате нарушения границы операцией, ссылающейся к   регистру SS. Сюда входят стеко-ориентированные команды, такие  как POP, PUSH, ENTER и LEAVE, а также прочие ссылки к памяти,  неявно использующие стек (например, MOV AX,[BP+6]). Команда  ENTER генерирует данное исключение, когда не хватает памяти  для распределения локальных переменных.

· При попытке загрузить регистр SS дескриптором, отмеченным   признаком "сегмент не присутствует", и допустимым во всех  прочих отношениях. Это может произойти при переключении  задачи, при выполнении команды CALL к другому уровню  привилегированности, при возврате к другому уровню  привилегированности, команде LSS, либо MOV или POP для  регистра SS.

 

Когда процессор обнаруживает исключение в стеке, он помещает код ошибки в стек обработчика исключений. Если исключение произошло в следствии не присутствующего сегмента стека или переполнения нового стека во время выполнения межуровневой команды CALL, то код ошибки содержит селектор сегмента, вызвавшего исключение (обработчик исключений может проверять бит Присутствия в дескрипторе для того, чтобы определить, какое исключение имело место); в противном случае код ошибки равен 0.

Команда, генерирующая данный сбой, позволяет рестарт во всех случаях. Адрес возврата, помещенный в стек обработчика исключений, указывает на команду, рестарт которой требуется выполнить. Эта команда обычно та, что вызвала исключение; однако, в случае исключительной ситуации в стеке вследствие загрузки дескриптора не присутствующего сегмента стека во время переключения задачи указанная команда представляет собой первую команду новой задачи.

Когда исключение в стеке происходит при переключении задачи, сегментные регистры не могут служить для адресации памяти. Во время переключения задачи значения селекторов загружаются до проверки дескрипторов. При генерации исключения стека остальные сегментные регистры остаются непроверенными, что может привести при их использовании к исключениям. Обработчик сбоев стека должен проверить все сегментные регистры, прежде чем пытаться возобновить выполнение новой задачи; в противном случае могут быть сгенерированы исключения общей защиты в условиях, когда диагностирование более затруднительно.

 

Исключение 13  -  Общая защита

 

Исключение общей защиты генерируется для всех нарушений памяти, не вызывающих прочих исключений. Сюда входят (но не ограничивают перечень):

 

· Превышение границы сегмента при использовании сегментов CS,  DS, ES, FS или GS.

· Превышение границы сегмента при ссылке к таблице дескрипторов.

· Передача выполнения сегменту, не являющемуся выполняемым  (кодовым) сегментом.

· Попытка записи в сегмент данных, доступный только для чтения,  или в кодовый сегмент.

· Чтение из кодового сегмента, доступного только для выполнения.

· Загрузка регистра SS селектором сегмента, доступного только  для чтения (если только этот селектор не берется из TSS при переключении задачи, так как в этом случае происходит  исключение "неверный TSS").

· Загрузка регистра SS, DS, ES, FS или GS селектором системного  сегмента.

· Загрузка регистра DS, ES, FS или GS селектором кодового  сегмента, доступного только для выполнения.

· Загрузка регистра SS селектором выполняемого сегмента.

· Доступ к памяти при помощи регистров DS, ES, FS или GS, когда  в них содержится пустой селектор.

· Переключение на Занятую задачу.

· Нарушение правил привилегированности.

· Превышение длины команды предельного значения 15 байтов  (это может случиться только при использовании перед командой  избыточных префиксов).

· Загрузка регистра CR0 при установленном бите PG (подкачка  страниц разрешена) и очищенном бите PE (защита запрещена).

· Прерывание или исключение через шлюз прерывания или ловушки  из виртуального режима 8086 к обработчику с уровнем  привилегированности иному, нежели 0.

 

Исключение общей защиты по типу относится к сбою. В ответ на исключение общей защиты процессор помещает в стек обработчика исключений код ошибки. Если исключение вызвано загрузкой дескриптора, то код ошибки содержит селектор для данного дескриптора; в противном случае код ошибки является пустым. Источник для селектора в коде ошибки может представлять собой одно из:

 

1.           Операнд команды.

2.           Селектор из шлюза, являющегося операндом команды.

3.           Селектор из TSS, участвующего в переключении задачи.

 

Исключение 14  -  Страничный сбой

 

Страничный сбой происходит, когда подкачка страниц разрешена (бит PG регистра CR0 установлен) и процессор обнаруживает одно из следующих условий во время трансляции линейного адреса в физический:

 

· Элемент каталога страниц или таблицы страниц, необходимый для   трансляции адреса, имеет очищенный бит Присутствия, что  означает, что таблица страниц или страница, содержащая  операнд, не присутствует в физической памяти;

· Процедура не имеет достаточного уровня привилегированности  для доступа к указанной странице.

 

Процессор обеспечивает для обработчика страничного сбоя два информационных элемента, помогающих диагностировать исключение и восстановить нормальные условия:

 

· Код ошибки в стеке. Код ошибки для страничного сбоя имеет   формат, отличный от формата для других особых ситуаций (см. выше). Код ошибки сообщает обработчику исключения  следующие три вещи:

 

1.           Произошло ли данное исключение вследствие того, что  страница не присутствует, или из-за нарушения прав доступа к странице.

2.           Работал ли процессор в момент исключения в режиме     пользователя, или в режиме супервизора.

3.           Состоял ли доступ к памяти, вызвавший данное исключения, в     чтении или в записи.

 

· Содержимое регистра CR2. Процессор загружает в регистр CR2 32 - разрядный линейный адрес, сгенерировавший исключение.  Обработчик исключения может использовать данный адрес для  нахождения соответствующих элементов каталога страниц и  таблицы страниц. Если во время выполнения обработчика  страничного сбоя произойдет еще один страничный сбой, то  обработчик должен поместить содержимое регистра CR2 в стек.

 

Страничный сбой при переключении задачи

 

Следующие операции выполняют доступ к памяти при переключении задачи:

 

1.           Запись состояния исходной задачи в TSS для этой задачи.

2.           Чтение GDT для нахождения дескриптора TSS новой задачи.

3.           Чтение TSS новой задачи для проверки типов дескрипторов   сегмента из TSS.

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

 

Страничный сбой может являться результатом обращения к одной из этих операций. В двух последних случаях исключение происходит в контексте новой задачи. Указатель команд указывает на следующую команду новой задачи, а не на команду вызвавшую переключение задачи (или на последнюю выполняемую команду в случае прерывания). Если устройство операционной системы позволяет страничным сбоям происходить вовремя переключения задач, то обработчик страничного сбоя должен вызываться через шлюз задачи.

 

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

 

Следует обращать особое внимание на то, чтобы страничный сбой не приводил к использованию процессором неверного указателя стека (SS:ESP). Программное обеспечение, написанное для 16-битовых процессоров Intel, часто использует для переключения на новый стек пару команд, например,

 

     MOV SS, AX

     MOV SP, StackTop

 

В случае процессора i486+, поскольку вторая команда обращается к памяти, можно получить в данном случае страничный сбой после того, как был изменен селектор сегментного регистра SS, но перед тем, как соответственно было изменено содержимое регистра SP. В этой точке две части указателя стека SS:SP (разумеется, для 32-разрядных программ это SS:ESP) противоречивы друг с другом. Новый стековый сегмент используется со старым указателем стека.

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

В системах, использующих подкачку страниц и обрабатывающих страничные сбои в пределах задач, содержащих сбой (посредством шлюзов ловушки или прерывания), программное обеспечение, выполняемое на том же уровне привилегированности, что и обработчик страничного сбоя, должно инициализировать новый стек командой LSS, а не парой команд, показанной выше. Если обработчик страничного сбоя работает на уровне привилегированности 0 (нормальный случай), проблема ограничивается программами, работающими на уровне привилегированности 0, т.е. обычно ядром операционной системы.

 

Исключение 16  -  Ошибка операции с плавающей точкой

 

Сбой операции с плавающей точкой говорит об ошибке, генерируемой командой арифметической операции с плавающей точкой. Прерывание 16 может произойти, только если бит NE регистра CR0 установлен.

 

Исключение 17  -  Проверка выравнивания

 

Сбой проверки выравнивания может генерироваться при доступе к невыравненным операндам. Например, слово, записанное по нечетному адресу памяти, или двойное слово, записанное по адресу, не кратному четырем. В таблице ниже приводятся требования к выравниванию по типам данных. Для разрешения контроля выравнивания должны выполняться следующие условия:

 

· Бит AM регистра CR0 должен быть установлен;

· Флаг AC должен быть установлен;

· CPL должен быть равен 3 (уровень пользователя).

 

-----------------------------------------------------------------

Тип данных                        Адрес должен нацело делиться на

-----------------------------------------------------------------

Слово                                           2

Двойное слово                                   4

Короткое вещественное                           4

Длинное вещественное                            8

Временное вещественное                          8

Селектор                                        2

48-разрядный сегментированный указатель         4

32-разрядный плоский указатель                  4

32-разрядный сегментированный указатель         2

48-разрядный "Псевдо-дескриптор"                4

Область хранения FSTENV/FLDENV          4 или 2, в зависимости от

                                           размера операнда

Область хранения FSAVE/FRSTOR           4 или 2, в зависимости от

                                           размера операнда

Битовая строка                                  4

-----------------------------------------------------------------

 

Проверку выравнивания полезно использовать в программах, в которых два младших бита указателей служат для идентификации адресуемой ими структуры данных. Например, подпрограмма в библиотеке математических функций может принимать указатели на числовые структуры данных. Если типу этой структуры в двух младших битах указателей на этот тип назначен код 10 (двоичный), математические подпрограммы могут выполнить для этого кода типа коррекцию, добавляя смещение -10 (двоичное). Если подпрограмма получит неверный тип указателя, то произойдет невыравненная ссылка, что приведет к генерации исключения.

Сбои проверки выравнивания генерируются только в режиме пользователя (уровень привилегированности 3). Ссылки к памяти с уровнем привилегированности по умолчанию 0, такие как загрузка дескриптора сегмента, не генерируют сбоев проверки выравнивания, даже если они вызваны ссылками к памяти, выполненными в пользовательском режиме.

Запись 48-разрядного псевдо-дескриптора (образа памяти для содержимого базового регистра таблицы дескрипторов) в режиме пользователя может генерировать сбой проверки выравнивания. Хотя программы режима пользователя обычно не сохраняют псевдодескрипторов, такого сбоя можно избежать, выравнивая псевдодескриптор по адресу нечетного слова (т.е. адресу, являющемуся 2 MOD 4).

Команды FSAVE и FRSTOR генерируют невыравненные ссылки, которые могут вызвать сбой проверки выравнивания. Прикладным программам эти команды нужны редко.