Обработка прерываний в защищённом режиме 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Обработка прерываний в защищённом режиме



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

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

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

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

Таблица 17.1. Распределение прерываний в защищенном и реальном режимах

Номер вектора Реальный режим Защищенный режим Тип прерывания Код ошибки
  Деление на ноль Деление на ноль Ошибка Не формируется
  Пошаговой работы Пошаговой работы Ошибка Не формируется
  Сигнал на входе NMI Сигнал на входе NMI Ловушка Не формируется
  Контрольная точка Контрольная точка Ловушка Не формируется
  Переполнение Переполнение Ловушка Не формируется
  BIOS: печать экрана/нарушение границ массива Нарушение границ массива Ошибка Не формируется
  Недопустимая команда Недопустимая команда Ошибка Не формируется
  Обращение к отсутствующему сопроцессору Обращение к отсутствующему сопроцессору Ошибка Не формируется
  Микросхема таймера/двойная ошибка Двойная ошибка Авария Формируется (всегда 0)
  Клавиатура Не используется Формируется
10(0Ah) Сигнал на линии IRQ_2 Ошибочный TSS Ошибка Формируется
11(0Bh) Сигнал на линии IRQ_3 Отсутствие сегмента Ошибка Формируется
12 (0Ch) Сигнал на линии IRQ_4/выход за пределы стека Выход за пределы стека или отсутствие стека Ошибка Формируется
13 (0Dh) Сигнал на линии IRQ_5/нарушение общей защиты Нарушение общей защиты Ошибка Формируется
14 (0Eh) Контроллер НГМД - сигнал на линии IRQ_6 Отсутствие страницы памяти Ошибка Формируется
15 (0Fh) Сигнал на линии IRQ_7 Не используется
16(10h) BIOS: функции видеосистемы/ошибка сопроцессора Ошибка сопроцессора Ошибка Не формируется
17(11h) Используется для прерываний BIOS и DOS Ошибка выравнивания Ошибка Формируется (всегда 0)
18-31(12h-19h) Используется для прерываний BIOS и DOS Зарезервировано
32-255(20h-0ffh) Используется для прерываний BIOS и DOS Аппаратные прерывания; прерывания. определяемые пользователем и ОС Ловушка Не формируется

Обратите внимание на то, что для некоторых прерываний в столбце для реально­го режима наблюдается двойственность источников прерываний (два возможных источника прерывания приведены через косую черту). Это объясняется тем, что изначально в микропроцессоре i8086/88 были жестко определены всего 5 преры­ваний (типа исключений, см. урок 15) с номерами 0...4. В последующих моделях микропроцессора разработчики зарезервировали номера в таблице прерываний 0...31. Но, как мы узнали на уроке 15, программы BIOS тоже настроены на обра­ботку аппаратных прерываний с определенными номерами, которые, в свою оче­редь, накладываются на номера исключений из диапазона 0...31. Это может быть источником конфликтов, суть которых в том, что непонятно, от какого источни­ка пришло прерывание. Это обстоятельство нужно учитывать программисту, ко­торый самостоятельно пишет какой-либо из обработчиков прерываний для заме­ны системного. Системные обработчики прерываний для предотвращения таких конфликтов выполняют дополнительные действия по идентификации источни­ка прерывания и лишь затем осуществляют непосредственно обработку преры­вания.

Для того чтобы разобраться со второй причиной несовместимости механизмов обработки прерываний в реальном и защищенном режимах, рассмотрим схему обработки прерывания в защищенном режиме (рис. 17.1).

Ключевыми компонентами в этой схеме являются дескрипторная таблица пре­рываний IDT и системный регистр idtr. При возникновении прерывания от источника с номером N микропроцессор, находясь в защищенном режиме, выпол­няет следующие действия (см. рис. 17.1):

  1. Определяет местонахождение таблицы IDT, адрес и размер которой содержится в регистре idtr.
  2. Складывает значение адреса, по которому размещена IDT, и значение n*8.
    По данному смещению в таблице IDT должен находиться 8-байтовый дескриптор, определяющий местоположение процедуры обработки прерывания.
  3. Переключается на процедуру обработки прерывания.

Это очень обобщенная схема. На практике все гораздо глубже, интереснее и сложнее.

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

  • сбой;
  • ловушка;
  • аварийное завершение.

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

  • какая информация сохраняется о месте возникновения прерывания или ис­ключения?
  • возможно ли возобновление прерванной программы?

Рис. 17.1. Схема обработки прерывания в защищенном режиме

Исходя из этих признаков, можно дать следующие характеристики вышеперечисленным группам:

  • Сбой (ошибка) — прерывание или исключение, при возникновении которого в стек записываются значения регистров сs:iр, указывающие на команду, вы­звавшую данное прерывание. Это позволяет, получив доступ к сегменту кода, исправить ошибочную команду в обработчике прерывания и, вернув управление программе, фактически осуществить ее рестарт (вспомните, что в реальном режиме при возникновении прерывания в стеке всегда запоминается адрес команды, следующей за той, которая вызвана это прерывание).
  • Ловушка — прерывание или исключение, при возникновении которого в стек записываются значения регистров сs:iр, указывающие на команду, следующую за командой, вызвавшей данное прерывание. Так же, как и в случае ошибок возможен рестарт программы. Для этого необходимо лишь исправить в обработчике прерывания соответствующие код или данные, послужившие источником ошибки. После этого перед возвратом управления нужно скорректировать значение ip в стеке на длину команды, вызвавшей данное прерывание. Как видим, механизм ловушек похож на механизм прерываний в реальном режиме, хотя не во всем. Здесь есть один тонкий момент. Если прерывание типа ловушки возникло в команде передачи управления jmp, то содержимое пары сs:ip в стеке будет отражать результат этого перехода, то есть соответствовать команде назначения.
  • Аварийное завершение — прерывание, при котором информация о месте его возникновения недоступна или неполна, и поэтому рестарт практически не­возможен, если только данная ситуация не была запланирована заранее.

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

Но в табл. 17.1 присутствует еще один столбец. Его наличие объясняется существованием еще одной особенности: некоторые прерывания при своем возникновении дополнительно генерируют и записывают в стек так называемый код ошибки. Этот код может впоследствии использоваться для установления источника прерывания. Код ошибки, если он генерируется для данного прерывания (см. табл. 17.1), записывается в стек вслед за содержимым регистров eflags, сs и eip (pиc. 17.2).

Рис. 17.2. Стек для прерываний с кодом и без кода ошибки

Какую информацию можно извлечь из кода ошибки? Код ошибки структурно представляет собой совокупность четырех полей и имеет размерность 16 бит. Если установлен режим адресации в сегменте use32, то при помещении в стек код ошиб­ки расширяется нулями до 32 бит в сторону старших разрядов. Поля кода ошиб­ки перечислены в табл. 17.2.

Теперь вам понятно, каким образом обработчик прерывания может распознать, что послужило истинной причиной прерывания, в случае, если возможна неоднозначность (см. табл. 17.1).

Что представляет собой дескрипторная таблица прерываний IDТ?

Посмотрите еще раз на рис. 17.1. На нем показаны роль и, соответственно, функциональное назначение таблицы прерываний защищенного режима IDT. Она свя­зывает каждый вектор прерывания с дескриптором процедуры или задачи. кото-

рая будет обрабатывать это прерывание. Формат таблицы IDT подобен формату GDT и LDT, то есть представляет собой совокупность 8-байтовых дескрипторов.

Таблица 17.2. Структура кода ошибки

Номер бита Обозначение Назначение и содержимое
  EXTENT Если EXTENT = 1, ИС вызвана аппаратным прерыванием;
  IDT Если IDT - 1, в поле INDEX содержится индекс дескриптора в таблице IDT;
  TI Если TI = 0, значение в поле INDEX соответствует номеру дескриптора в таблице GDT; если TI = 1, значение в поле INDEX соответствует номеру дескриптора в таблице LDT
  INDEX Номер дескриптора в одной из таблиц IDT, GDT или LDT в соответствии с состояниями полей EXTENT, IDT или TI; 0 — для некоторых исключений

Отличия таблицы IDT от указанных таблиц состоят в следующем:

  • нулевой дескриптор, в отличие от таблицы GDT, используется; он описывает шлюз для программы обработки исключительной ситуации 0 (ошибка деления);
  • дескрипторы в таблице IDT строго упорядочены в соответствии с номерами прерываний. В таблицах GDT и LDT, как помните, порядок описания дескрипторов роли не играет, хотя и допускается наличие некоторых соглашений по их упорядоченности;
  • размерность таблицы IDT — не более 256 элементов размером по восемь байт, по числу возможных источников прерываний. В отдельных случаях есть смысл описывать все 256 дескрипторов этой таблицы, формируя для неиспользуемых номеров прерываний шлюзы-заглушки. Это позволит корректно обрабатывать все прерывания, даже если они и не планируются к использованию в данной задаче. Если этого не сделать, то при незапланированном прерывании с номером, превышающим пределы IDT для данной задачи, будет возникать исклю­чительная ситуация общей защиты (с номером 13 (0Dh));
  • при работе с прерываниями микропроцессор всегда определяет местоположение таблицы IDT по полю базового адреса в регистре idtr (см. табл. 17.2). Это он делает независимо от режима, в котором работает. В реальном режиме содер­жимое поля базового адреса в регистре idtr равно нулю, поэтому работа с таб­лицей векторов прерываний выполняется без проблем (структура ее в данном случае не имеет значения). Из вышесказанного следует, что возможно произ­вольное размещение в памяти этой таблицы не только в защищенном режиме, но и и реальном.

При описании этих отличий вы встретили новое понятие — шлюз. Так обычно называют дескрипторы в таблице прерываний IDT для того, чтобы подчеркнуть их специфику по сравнению с дескрипторами в таблицах GDT и LDT. Шлюзы предназначены для указания точки входа в программу обработки прерывания. В дескрипторной таблице прерываний IDT могут содержаться шлюзы трех типов. Их существование объясняется наличием разных по характеру источников прерывания и особенностями передачи управления в программу обработки. По формату шлюзы похожи на дескрипторы в таблицах GDT и LDT. Физически микро­процессор отличает их по значению в поле типа и содержимому остальных полей. Возможны три типа шлюзов:

  • шлюз ловушки;
  • шлюз прерывания;
  • шлюз задачи.

Дадим им более подробную характеристику.

Шлюз ловушки

Шлюз ловушки — элемент таблицы IDT, имеющий формат, показанный на рис. 17.3.

Рис. 17.3. Формат шлюза ловушки

В табл. 17.3 приведены назначения полей в формате шлюза ловушки.

Когда возникает прерывание, и его вектор выбирает в таблице IDT дескриптор шлюза с типом ловушки, микропроцессор сохраняет в стеке информацию о месте, где он прервал работу текущей программы (см. рис. 17.2). После этого он передает управление в соответствии с полями indicator и offset. Поле indicator представляет селектор одной из таблиц, GDT или LDT, в зависимости от состояния бита TI в нем. Поле offset определяет смещение в сегменте кода. Этот сегмент кода описывается дескриптором, на который указывает селектор в поле indicator. После того как управление было передано обработчику прерывания, он выполняет свою работу до тех пор, пока не встретит команду iret. Эта команда восстанавливает из стека состояние регистров eflags, cs и eip на момент возникновения прерывания, и работа приостановленной программы продолжается. При подготовке выхода из программы обработки прерывания имейте в виду, что команда iret ничего не знает о возможности наличия в стеке кода ошибки, поэтому для корректного возврата управления не забудьте при необходимости предварительно удалить командой pop код ошибки из стека.

Номера битов Обозначение Значение Назначение
0...15 offset_l nn...nn Смещение в сегменте (первая половина)
16...31 indicator mm....mm Селектор, указывающий на дескриптор в LDT или GDT
32...36   Не используется
37...39     Постоянное значение
40...43 type   Тип шлюза — ловушка
      Постоянное значение
45...46 dpl nn (обычно dpi = 112) Определение минимального уровня привилегий задачи, которая может передать управление обработчику прерываний через данный шлюз
  p 0 или 1 Бит присутствия
48...63 offset_2 nn...nn Смещение в сегменте (вторая половина)

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

Шлюз прерывания — элемент таблицы IDT, имеющий формат, показанный на рис. 17.4.

Рис. 17.4. Формат шлюза прерывания

Если внимательно посмотреть на этот формат, то можно сделать вывод, что его отличие по сравнению с форматом шлюза ловушки только в поле типа (type). Это имеет свою причину. При возникновении прерывания, которому соответствует шлюз прерывания, микропроцессор выполняет те же действия, что и для шлюза ловушки, но с одним важным отличием. Когда микропроцессор передает управление обработчику прерывания через шлюз прерывания, то он сбрасывает флаг прерывания в регистре eflags в 0, запрещая тем самым обработку аппаратных прерываний. Этот факт имеет важное значение для программирования обработчиков аппаратных и программных прерываний (см. обсуждение прерываний реального режима в уроке 15). Если у вас есть сомнение в том, какой из двух рассмотрен­ных типов шлюзов использовать, — применяйте шлюз прерывания.

Шлюз задачи

Шлюз задачи — элемент таблицы IDT, имеющий формат, показанный на рис. 17.5.

Рис. 17.5. Формат шлюза задачи

Когда микропроцессор при выполнении прерывания встречает в таблице IDT шлюз задачи, это означает, что он должен осуществить переход на особый объект. С подобными объектами, называемыми задачами, мы пока еще не встречались. Задача является частью механизма многозадачности. На самом деле, многозадачность не означает того, что в некоторый момент времени микропроцессор может одновременно выполнять несколько командных потоков. Микропроцессор занят в каждый конкретный момент времени выполнением команд только одного по­тока. Поэтому многозадачность в случае нашего микропроцессора на самом деле является псевдомногозадачностью. Это означает, что микропроцессор, выполняя команды одного потока, по истечении некоторого времени должен переключиться на выполнение команд другого потока и т. д. За счет высокого быстродействия микропроцессора создается иллюзия того, что несколько задач выполняются одновременно. Но как быть с ресурсами, которые эти потоки команд разделяют? Такими ресурсами являются, в частности, регистры. Их нужно где-то сохранять на то время, пока работает другая задача. В микропроцессорах Intel эта проблема решена следующим образом. Для каждой задачи определяется сегмент состояния задачи (TSS, Task Segment Status) со строго определенной структурой. В этом сегменте есть поля для сохранения всех регистров общего назначения, некоторых системных регистров и другой информации. Всю совокупность этой информации называют контекстом задачи. Этот сегмент описывается, подобно другим сегментам, дескриптором в таблице GDT или LDT. Если с помощью некоторого селектора обратиться к такому дескриптору, то микропроцессор осуществит переключение на соответствующую задачу. Подобные переключения могут, в частности, осуществляться операционной системой, поддерживающей многозадачность, в соответствии с некоторой дисциплиной разделения времени между задачами. Переключение задач может производиться обычными командами межсегментной передачи управления либо по возникновению прерывания при переходе к обработчику прерывания через шлюз задачи.

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

которую задачу, которая будет осуществлять обработку прерывания. Поле indicator в шлюзе задачи содержит селектор, который определяет местонахождение дескриптора сегмента TSS — в таблице GDT или LDT (в зависимости от состояния бита ТI селектора). В этой книге мы, к сожалению, не имеем возможности более подробно рассмотреть реализацию многозадачности для микропроцессоров Intel.

Итак, еще раз подчеркнем отличия перечисленных типов шлюзов. Шлюзы ловушки и прерывания с помощью полей indicator и offset определяют адрес, по которому находится точка входа в программу обработки прерывания. Шлюз задачи предназначен для реализации принципиально иного перехода к обработчику прерываний — с использованием механизма переключения задач.

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

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

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

  • инициализировать таблицу IDT;
  • составить процедуры обработчиков прерываний;
  • запретить аппаратные прерывания;
  • перепрограммировать контроллер прерываний i8259A;
  • загрузить регистр IDTR адресом и размером таблицы IDT;
  • перейти в защищенный режим;
  • разрешить обработку прерываний.

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

  • запретить аппаратные прерывания;
  • выполнить обратное перепрограммирование контроллера прерываний;
  • перейти в реальный режим работы микропроцессора;
  • разрешить обработку аппаратных прерываний.

Обсудим эти действия подробнее.

Инициализация таблицы IDT

Ранее мы уже определились с тем, что так же, как и в реальном режиме, все прерывания защищенного режима имеют свои номера от 0 до 255. Отличие их от прерываний реального режима в том, что под цели микропроцессора (исключительные ситуации, или просто исключения) отдано гораздо большее количество номеров — первые 32 вектора с номерами 0...31. Из этих 32 векторов реально используются только 0...17, остальные вектора 18...31 пока зарезервированы для будущих разработок. Для того чтобы сформировать таблицу IDT в целом, необходимо определиться с описанием отдельных ее дескрипторов — шлюзов. Можно предложить следующий, оформленный в виде структуры, шаблон для описания дескрипторов в таблице IDT:

descrjdt struc offs_l dw 0;младшая часть адреса смещения обработчика прерывания seldw 30;селектор на сегмент команд в таблице GDT no_use db 0 typeattr db 8eh;по умолчанию шлюз прерывания,;для ловушки - 8fh offs_2 dw 0;старшая часть адреса смещения обработчика прерывания ends

Теперь можно приступить к формированию таблицы IDT. Это можно делать как в отдельном сегменте, так и в сегменте данных. Чтобы не загромождать сегмент данных, оформим таблицу IDT в виде отдельного сегмента.

descrjdt struc int00h descr_idt <dummy,,,,> rept 5 descr_idt <dummy,,,,> endm int05h descr_idt <int_05h,,,,> rept 7 descr_idt <dummy_err,,,,> endm int0dh descr_idt <int_0dh,,,,> rept 3 descr_idt <dummy,,,,> endm int11h descr_idt <dummy_err,,,,> rept 14 descr_idt <dummy,,,,> endm int20h descr_idt <new_08h,,,,> int21h descr_idt <sirena,38h,,,> rept 221 descr_idt <dummy,,,,> endm idt_size = $-int00h-1 idt_seg ends

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

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

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

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

  1. Снять со стека и проанализировать код ошибки (если он есть).
  2. Сохранить в стеке используемые в обработчике регистры микропроцессора.
  3. Выполнить необходимые действия, в том числе подготовить возможный рестарт команды, вызвавшей прерывание. Подобный рестарт подразумевает возобновление выполнения прерванной программы, начиная с команды, инициировавшей процесс прерывания.
  4. Восстановить сохраненные на шаге 2 регистры.
  5. Выдать команду iret.

Прерываний, для которых микропроцессор формирует код ошибки, немного — всего 8. В программе (см. текст программы prgl7_l.asm на дискете в каталоге данного урока) приведены все возможные типы прерываний защищенного режима. Так, для исследования исключений типа ошибок взяты исключения 5 и 13 (0Dh), а для ловушек — 3 и обработка прерывания пользователя.



Поделиться:


Последнее изменение этой страницы: 2017-02-05; просмотров: 1114; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.221.129.145 (0.026 с.)