Открыть сервис

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

Таблица дескрипторов прерываний (Interrupt Descriptor Table, IDT) — это структура данных, используемая в архитектуре x86 и x86-64 для хранения дескрипторов, определяющих обработчики прерываний, исключений и системных вызовов. IDT является ключевым элементом системы управления прерываниями в защищённом и длинном режимах работы процессора, обеспечивая диспетчеризацию событий, требующих немедленного вмешательства ядра операционной системы или гипервизора.

Назначение и принцип работы

IDT представляет собой массив из 256 записей (дескрипторов), каждая из которых соответствует одному из 256 возможных векторов прерываний. Векторы с номерами от 0 до 31 зарезервированы для исключений и прерываний, генерируемых самим процессором (например, деление на ноль, страничная ошибка, общая защита). Векторы с 32 по 255 используются для аппаратных прерываний (от контроллеров прерываний, таких как PIC или APIC) и программных прерываний (например, системных вызовов через int 0x80 или syscall).

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

  1. Определяет номер вектора (от 0 до 255).
  2. Обращается к IDT, расположенной в памяти по адресу, заданному в регистре IDTR (Interrupt Descriptor Table Register).
  3. Извлекает соответствующий дескриптор и проверяет его корректность (наличие, уровень привилегий, тип).
  4. Если дескриптор является шлюзом задачи (Task Gate), процессор выполняет переключение задач. В противном случае (шлюз прерывания или ловушки) он сохраняет контекст (флаги, адрес возврата) и передаёт управление обработчику, адрес которого указан в дескрипторе.

Структура дескриптора

В режиме защищённого 32-битного режима (Protected Mode) каждый дескриптор IDT занимает 8 байт и имеет следующую структуру:

Смещение (байты)ПолеОписание
0–1Offset LowМладшие 16 бит адреса обработчика (сегментный сдвиг)
2–3Segment SelectorСелектор сегмента кода, в котором находится обработчик
4FlagsБайт флагов (см. ниже)
5Flags (старший)Дополнительные флаги и тип шлюза
6–7Offset HighСтаршие 16 бит адреса обработчика

В 64-битном режиме (Long Mode) размер дескриптора увеличен до 16 байт, чтобы вместить 64-битный адрес обработчика. Структура 64-битного дескриптора:

Смещение (байты)ПолеОписание
0–1Offset LowМладшие 16 бит адреса
2–3Segment SelectorСелектор сегмента кода
4ISTИндекс стека прерываний (Interrupt Stack Table)
5FlagsБайт флагов
6–7Offset MiddleБиты 16–31 адреса
8–11Offset HighБиты 32–63 адреса
12–15ReservedЗарезервированы (должны быть равны 0)

Поле флагов (Flags)

Байт флагов (смещение 5) содержит биты, определяющие тип и свойства шлюза:

  • Биты 0–3 (Gate Type): Тип шлюза. Возможные значения:
  • 0x05 — шлюз задачи (Task Gate, только в 32-битном режиме).
  • 0x06 — шлюз прерывания (Interrupt Gate).
  • 0x07 — шлюз ловушки (Trap Gate).
  • В 64-битном режиме используются только шлюзы прерывания и ловушки.
  • Бит 4 (Segment Present): Флаг присутствия. Если равен 0, при попытке обращения к этому дескриптору генерируется исключение.
  • Биты 5–6 (Descriptor Privilege Level, DPL): Уровень привилегий дескриптора (0–3). Определяет, с какого уровня привилегий можно вызвать данный шлюз через программное прерывание (например, int).
  • Бит 7 (Reserved): В 32-битном режиме зарезервирован; в 64-битном режиме используется для указания, что дескриптор является 64-битным (должен быть равен 1).

Регистр IDTR

Регистр IDTR (Interrupt Descriptor Table Register) хранит базовый адрес и размер IDT. Он загружается инструкцией LIDT (Load IDT) и сохраняется инструкцией SIDT (Store IDT). В защищённом режиме IDTR содержит 48 бит: 32 бита — линейный адрес базы, 16 бит — лимит (размер таблицы в байтах минус 1). В 64-битном режиме база расширена до 64 бит, а лимит остаётся 16-битным.

Типы шлюзов

Шлюз прерывания (Interrupt Gate)

При входе в шлюз прерывания процессор автоматически запрещает (маскирует) прерывания, сбрасывая флаг IF (Interrupt Flag) в регистре EFLAGS/RFLAGS. Это предотвращает вложенные прерывания во время обработки текущего. Шлюзы прерывания используются для обработки аппаратных прерываний и критических исключений.

Шлюз ловушки (Trap Gate)

Шлюз ловушки не изменяет флаг IF, то есть прерывания остаются разрешёнными. Это позволяет обрабатывать исключения, которые могут быть вызваны отладчиком или программными средствами, без блокировки других прерываний. Шлюзы ловушки часто используются для системных вызовов и отладки.

Шлюз задачи (Task Gate)

Шлюз задачи (доступен только в 32-битном режиме) вызывает переключение задач через механизм аппаратного переключения контекста (TSS). В современных операционных системах (например, Linux, Windows) этот тип шлюза практически не используется, так как переключение задач реализуется программно.

Инициализация и управление

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

В многопроцессорных системах каждый процессор может иметь собственную IDT, но на практике часто используется одна общая таблица. В современных ОС (Linux, Windows) IDT обычно размещается в области памяти, защищённой от записи, чтобы предотвратить её модификацию злонамеренным кодом.

Примеры использования

  • Исключения процессора: Вектор 0 (деление на ноль), вектор 13 (общая защита), вектор 14 (страничная ошибка) — для каждого из них ядро устанавливает специальный обработчик, который может завершить процесс, выдать сообщение об ошибке или попытаться восстановить выполнение.
  • Аппаратные прерывания: Вектор 32 (IRQ0 — таймер), вектор 33 (IRQ1 — клавиатура) — обработчики вызываются контроллером прерываний (PIC или APIC) для обслуживания устройств.
  • Системные вызовы: В Linux для 32-битных систем используется программное прерывание int 0x80 (вектор 128), а в 64-битных — инструкция syscall, которая не использует IDT напрямую, но в некоторых архитектурах (например, в x86) может быть реализована через шлюз.

Критические аспекты безопасности

Некорректная настройка IDT может привести к уязвимостям. Например, если дескриптор имеет DPL, равный 3, то любой пользовательский процесс может вызвать соответствующий шлюз через инструкцию int. Это может быть использовано для атак на ядро. Поэтому в современных ОС дескрипторы, доступные из пользовательского пространства, строго ограничены (обычно только системные вызовы). Кроме того, атаки типа «двойное извлечение» (double fetch) могут быть применены для модификации IDT во время её чтения процессором, что требует аппаратной защиты (например, SMEP/SMAP).

Источники

  • Intel 64 and IA-32 Architectures Software Developer’s Manual, Volume 3A: System Programming Guide, Chapter 6: Interrupt and Exception Handling.
  • AMD64 Architecture Programmer’s Manual, Volume 2: System Programming, Chapter 8: Interrupts and Exceptions.
  • Таненбаум Э., Бос Х. Современные операционные системы. 4-е издание. — СПб.: Питер, 2015. — Глава 3.4: Обработка прерываний.
  • Кормен Т., Лейзерсон Ч., Ривест Р., Штайн К. Алгоритмы: построение и анализ. — М.: Вильямс, 2013. — Раздел о системных вызовах.

BFOmetr — база данных и аналитика по компаниям России.

На главную BFOmetr →