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

StackOverflow https://stackoverflow.com/questions/491613

Вопрос

Я загрузил таблицу idt с 256 записями, все из которых указывают на аналогичные обработчики:

  • для исключений 8 и 10–14 введите номер исключения (эти исключения автоматически передают код ошибки)
  • для остальных введите «фиктивный» код ошибки и номер исключения;
  • затем перейдите к общему обработчику

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

Мой вопрос касается возврата из обработчика прерывания.я использую iret вернуться после извлечения номера исключения и кода ошибки из стека, но для исключения № 8 это не работает;если я оставлю код ошибки в стеке, он вернется нормально!

Вопросы:

  • нужно ли мне оставлять код ошибки в стеке для исключений, которые помещают туда код ошибки?Если да, то как iret определить, должен ли он выдать код ошибки или нет?
  • как только я разрешаю прерывания, я всегда получаю исключение 8 (двойная ошибка), но потом все работает нормально (я разрабатываю ОС для хобби).Это нормальное поведение или у меня где-то ошибка?
Это было полезно?

Решение

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

Цитата из SDM (Руководства разработчика программного обеспечения), том 3, глава 5, раздел 5.13 под названием «Код ошибки»:

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

Вы можете найти Руководство разработчика программного обеспечения IA-32 здесь: http://www.intel.com/products/processor/manuals/

Том 3, часть 1, глава 5, описывает обработку исключений и прерываний.Том 2, часть 1, содержит спецификации для iret инструкция.

Другие советы

Я написал небольшая ОС x86 Некоторое время назад.Взгляните на файл isr.asm в репозитории cvs.

Обратите внимание, как мы настраиваем обработчики: большинство из них помещают в стек фиктивное двойное слово, чтобы учесть несколько обработчиков, которые автоматически отправляют код ошибки.Затем, когда мы возвращаемся через iret, мы всегда можем принять 2 dword в стеке независимо от прерывания и выполнить добавление esp, 8 перед iret, чтобы хорошо очистить ситуацию.

Это должно ответить на ваш первый вопрос.

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

У меня возникла аналогичная проблема с «двойными ошибками», как только я включил прерывания.Ну, они смотрел как двойные ошибки, но на самом деле это были прерывания по таймеру!

Двойные ошибки — это номер прерывания. 8.

К сожалению, конфигурация PIC по умолчанию сигнализирует о прерываниях таймера как номер прерывания. (DEFAULT_PIC_BASE + TIMER_OFFSET) = (8 + 0) = 8.

Маскирование всех моих прерываний PIC (пока я не был готов правильно настроить PIC) заставило замолчать эти прерывания таймера, похожие на двойные сбои.

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

Должен ли я оставлять код ошибки в стеке для исключений, которые помещают туда код ошибки?

Как уже упоминалось, вам нужно сделать либо:

pop %eax
/* Do something with %eax */
iret

Или, если вы хотите игнорировать код ошибки:

add $4, %esp
iret

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

Минимальный рабочий обработчик этой страницы который я создал, чтобы проиллюстрировать это.Попробуйте закомментировать pop и увидеть, как он взрывается.

Сравните вышеизложенное с Исключение ошибки деления который не выталкивает стек.

Обратите внимание, что если вы сделаете просто int $14, никакой дополнительный байт не будет отправлен:это происходит только при реальном исключении.

Руководство Intel, том 3, Руководство по системному программированию — 325384-056US, сентябрь 2015 г. Таблица 6-1.Столбец «Исключения и прерывания защищенного режима» «Код ошибки» содержит список прерываний, которые передают код ошибки или нет.

38.9.2.2 «Коды ошибок страницы» объясняет, что означает ошибка.

Отличный способ справиться с этой проблемой — отправить фиктивный код ошибки. 0 в стеке для прерываний, которые этого не делают, чтобы сделать вещи единообразными.Учебник Джеймса Моллоя делает именно это.

Ядро Linux 4.2, похоже, делает нечто подобное.Под арка/x86/запись/entry64.S он моделирует прерывания с помощью has_error_code:

trace_idtentry page_fault do_page_fault has_error_code=1

а затем использует его в том же файле, что и:

.ifeq \has_error_code
pushq $-1 /* ORIG_RAX: no syscall to restart */
.endif

который толкает, когда has_error_code=0.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top