Фантазии о Вселенной и мой личный сайт
Дескрипторы прерываний

Дескрипторы прерываний

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

Адрес, по которому произойдёт переход на обработчик прерывания, находится в дескрипторе прерывания. Каждому вектору прерыванию соответствует свой дескриптор, все они (до 256) объединяются в специальную таблицу дескрипторов прерываний IDT и по формату похожи на дескрипторы сегментов, которые мы рассматривали в разделе "Защищённый режим".

Таблица дескрипторов прерываний (IDT) в любой системе - одна. Программ (задач, процедур, приложений и пр.) - много. IDT реализуется на нулевом уровне привилегий и, следовательно, непосредственно к ней обратиться могут только программы, работающие на том же уровне. Для того, чтобы программы с других уровней (1, 2 и 3) могли пользоваться прерываниями, предусмотрены специальные системные объекты - так называемые шлюзы (gates). При вызове прерывания, процессор, прежде, чем передать управление обработчику, "опускается" через шлюз на его уровень привилегий, а после завершения обработки - "поднимается" обратно.

IDT может содержать три типа дескрипторов шлюзов:

  1. Шлюз задачи
  2. Шлюз прерывания
  3. Шлюз ловушки

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

Исключения и прерывания работают в основном через два типа шлюзов - задач и прерываний. Шлюз прерывания запускает обработчик в контексте текущей программы, т.е. просто передаёт управление по адресу, указанному в дескрипторе. Такой подход хорош только в простых операционных системах, когда работают заранее определённые программы, от которых не нужно защищать ядро ОС.

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

Далее приводятся форматы дескрипторов шлюзов:

1. Шлюз задачи.

    dw    0
    dw    TSS_sel        ; Селектор TSS
    db    0
    db    access_rights  ; Права доступа сегмента TSS
    dw    0

Рисунок 2-1. Схема шлюза задачи.

Обратите внимание на то, что бит 4 в access_rights, соответствующий биту S в формате дескриптора, равен 0. Это значит, что дескриптор описывает системный объект и биты 0..3 в access_rights определяют тип этого объекта.

Первое и последнее слова (dw) в формате дескриптора содержат 0, т.к. любая задача определяется своим дескриптором, на который и ссылается селектор TSS (подробно о задачах см. в разделе "Мультизадачность").

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

    dw    offset_low    ; Младшая часть смещения
    dw    selector      ; Селектор сегмента кода
    db    0
    db    access_rights ; Права доступа
    dw    offset_hi     ; Старшая часть смещения

Шлюз прерывания через селектор и смещение задаёт адрес обработчика прерывания.

Рисунок 2-2. Схема шлюза прерывания.

3. Шлюз ловушки.

    dw    offset_low    ; Младшая часть смещения
    dw    selector      ; Селектор сегмента кода
    db    0
    db    access_rights ; Права доступа
    dw    offset_hi     ; Старшая часть смещения

Шлюз ловушки через селектор и смещение задаёт адрес обработчика прерывания.

Рисунок 2-3. Схема шлюза ловушки.

Примечание.

D - это размер шлюза: 1 = 32 бита; 0 = 16 бит. Размер шлюза определяет размер стека, используемый процессором по умолчанию. Перед вызовом обработчика, процессор помещает в стек значения регистров CS, EIP, EFLAGS и иногда SS, ESP и dw-код ошибки. Если размер шлюза - 32 бита, то значения размером в 16 бит будут расширены нулями до 32-х.