Прерывания для самых маленьких

в 15:21, , рубрики: IDT, прерывания, системное программирование, метки:

Сегодня мы поговорим о прерываниях процессоров семейства x86 (-64). Подробнее под катом.
Прерывания — это как бы сигнал процессору, что надо прервать выполнение (их поэтому и назвали прерываниями) текущего кода и срочно сделать то, что указано в обработчике.

IDT

Все адреса обработчиков прерываний хранятся в IDT. Это таблица, в которой хранятся 256 (можно больше или меньше, но большие значения просто игнорируются) ячеек (векторы прерываний) с типом и атрибутами прерывания, одним просто нулевым значением, собственно адресом обработчика прерываний и селектором кода в GDT или LDT, который будет использовать данный вектор прерываний. Теперь немного о типе и атрибутах.
Тип прерывания и атрибуты занимают 8 бит. Первые 4 бита занимают тип:

  • 0b0101: 32-битный гейт задачи, при появлении такого прерывания происходит хардверное переключение задачи (да-да, есть и такое, но его уже давно не используют)
  • 0b0110: 16-битный гейт прерывания
  • 0b0111: 16-битный гейт trap'a (я не знаю, как это перевести на русский язык, извините)
  • 0b1110: 32-битный гейт прерывания
  • 0b1111: 32-битный гейт trap'a

Далее идут атрибуты. Первым атрибутом является 1 бит, который задан в 0 для гейтов прерывания и в 1 для остальных. Далее идет уровень привилегий дескриптора — 2 бита, задающие минимальный уровень привилегий для вызова прерываний, и 1 бит, заданный в 0 для неиспользуемых прерываний.
Теперь о том, как процессор вызывает обработчики.
Допустим, что вы вызвали инструкцию int 0 в ассемблере. Это даст сигнал процессору, что надо вызвать прерывание 0, если это возможно. Вот последовательность действий, которые происходят при этом.

  1. Поиск вектора №0 в IDT.
  2. Сравнение уровня привилегий дескриптора и текущего уровня привилегий процессора.
  3. Если текущий уровень привилегий процессора меньше уровня привилегий дескриптора, то просто вызвать генеральную ошибку защиты и не вызывать прерывание.
  4. Происходит сохранение адреса возвращения, регистра (E)FLAGS и другой информации.
  5. Происходит переход на адрес, указанный в векторе №0 IDT.
  6. После выполнения обработчика инструкция iret возвращает управление прерванному коду.

Исключения

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

  • Деление на ноль. Генерируется при, собственно, делении на ноль.
  • Отладочное исключение. Генерироваться само не может, используется для, собственно, отладки.
  • Немаскируемое прерывание. Генерируется при ошибках ОЗУ и невосстановимых ошибках «железа». Их невозможно замаскировать с помощью PIC (Programmable Interrupt Controller — программируемый контроллер прерываний), так как оно идет сразу в процессор, минуя PIC, но можно просто отключить.
  • Точка останова. Тоже используется для отладки, потому что его опкод занимает всего 1 байт, в отличии от остальных INT N. Переназначалось DOS-отладчиками для своих целей.
  • Переполнение. Генерируется инструкцией INTO, если в (E)FLAGS включен бит переполнения.
  • Выход за пределы. Генерируется при ошибке инструкции BOUND.
  • Недопустимый опкод. Генерируется при попытке выполнения недопустимого кода операции.
  • Устройство недоступно. Сейчас не используется, генерировался при попытке использования операций с плавающей точкой на процессорах без FPU.
  • Double fault. Сложно перевести название. Ошибка невосстановима, происходит при невозможности вызвать обработчик исключения.
  • Переполнение сегмента сопроцессора. Больше не используется.
  • Недопустимый TSS. Сегмент состояния задачи задан неправильно.
  • Сегмент отсутствует. Возникает при попытке загрузки сегмента с битом Present == 0.
  • Ошибка сегмента стека. Возникает при попытке загрузки сегмента с битом Present == 0 или переполнении стека.
  • Генеральная ошибка защиты. Генерируется в очень большом числе случаев, среди них есть ошибка сегмента, попытка выполнения инструкции без необходимых прав, запись туда, куда не надо, попытка доступа к нулевому дескриптору GDT и многое другое.
  • Ошибка страницы. Происходит при чтении или записи в несуществующую страницу памяти, попытке доступа к данным без необходимых прав или другом.
  • Ошибка с плавающей точкой. Происходит при выполнении инструкции FWAIT или WAIT с битом №5 в CR0 == 0.
  • Ошибка при проверке на выравнивание. Происходит только в третьем кольце привилегий процессора, если эта ошибка, конечно, включена.
  • Ошибка при проверке машины. Генерируется процессором при обнаружении «железных» ошибок.
  • Исключение с плавающей точкой SIMD. Генерируется при ошибках с 128-битными числами с плавающей точкой.
  • Ошибка виртуализации.
  • Ошибка безопасности.
  • Тройная ошибка. По сути исключением не является, это даже не прерывание. Происходит при невозможности вызвать Double Fault. Вызывает немедленную перезагрузку компьютера.

IRQ

Существует особый тип прерываний — IRQ (Interrupt ReQuest), или же аппаратные прерывания, но я буду их для краткости называть просто IRQ. Технически они почти не отличаются от любых других прерываний, но генерируются не процессором или самим кодом, а устройствами, подключенными к компьютеру. К примеру, IRQ №0 генерируется PIT (таймер с программируемым интервалом), IRQ 1 генерируется при нажатии клавиши на клавиатуре, а IRQ 12 — при действии с PS/2-мышью.

Программные прерывания

Еще есть так называемые программные прерывания. Их, как понятно из названия, программа должна вызывать сама — никто их за нее не вызывает. Таковыми являются, например, системные вызовы в некоторых системах. В Linux, например, они висят на векторе 0x80. Во многих хобби-ОС они тоже висят на векторе 0x80. Теперь немного отсебятины — я думаю, что сисвызовы сделаны в виде прерываний из-за того, что 1) их так очень легко вызывать, 2) их можно вызвать из любого кода, работающего в ОС — IDT-то одна на всю систему.
Информация взята с OSDev Wiki.

Автор: catnikita255

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js