Обработчик ошибок страницы сборки не может быть вызван из-за недопустимого указателя стека

Когда вызывается прерывание моего обработчика сбоя страницы (предполагается, что оно зависает в системе), в стек перед его вызовом помещаются некоторые переменные. У меня включена виртуальная память, и когда я устанавливаю недопустимый указатель стека (esp) и вызывается обработчик int14, это немедленно вызывает еще одну ошибку страницы и так далее и тому подобное. Как мне разрешить эту ситуацию?

Мой код int14:

isr14:
    ; interrupt handler for isr14
    jmp $
    iretd

Код, из-за которого он ломается:

mov esp, 0x1000 ; 0x1000 is not mapped in the VM directory
push dword 'A'
jmp $

Раздел моей таблицы IDT:

irq14:
    dw isr14
    dw 0x0008
    db 0x00
    db 10101110b
    dw 0x0000

irq15:
........

person DrCarnivore    schedule 14.03.2020    source источник
comment
Я не очень хорошо знаком с этим, но я помню, что решение состоит в том, чтобы иметь отдельный безопасный стек, на который переключается дескриптор прерывания при обработке ошибок страницы.   -  person fuz    schedule 15.03.2020
comment
Я понимаю, но как я должен переключиться на этот стек до вызова прерывания?   -  person DrCarnivore    schedule 15.03.2020
comment
Я немного не уверен в деталях, но я помню, что вы можете закодировать это где-то в дескрипторе прерывания. Позвольте мне проверить документацию.   -  person fuz    schedule 15.03.2020
comment
это было бы прекрасно!   -  person DrCarnivore    schedule 15.03.2020
comment
Определите стек для переключения в TSS. Затем настройте шлюз прерывания с ненулевым полем, ссылающимся на сегмент/указатель стека, сохраненный в вашем TSS. Это должно решить проблему.   -  person fuz    schedule 15.03.2020
comment
попробую позже спасибо!   -  person DrCarnivore    schedule 15.03.2020
comment
У меня раньше не было ТС, так что мне нужно его сделать   -  person DrCarnivore    schedule 15.03.2020
comment
Если вам удалось решить вашу программу таким образом, пожалуйста, напишите ответ!   -  person fuz    schedule 15.03.2020
comment
@fuz: кажется, я припоминаю, что Майкл Петч публиковал ответ с этим. Может быть, просто тот факт, что TSS - это механизм, который позволяет ядрам обрабатывать прерывания в стеке ядра, не позволяя пользовательскому пространству падать или владеть машиной. например Создание правильной структуры сегмента состояния задачи (TSS) с растровым изображением ввода-вывода и без него? / Когда во время программного прерывания x86 происходит переключение контекста?. wiki.osdev.org/Getting_to_Ring_3 выглядит актуальным.   -  person Peter Cordes    schedule 15.03.2020


Ответы (1)


Как мне разрешить эту ситуацию?

Я бы разрешил ситуацию, используя избегание — в первую очередь не позволяйте ядру иметь хитрый указатель стека (и не позволяйте стеку ядра отправляться в пространство подкачки, не используйте ошибку страницы для «авторастущего ядра»). стек" и др.). Обратите внимание, что ЦП автоматически переключится на стек ядра, если в пользовательском пространстве произойдет ошибка страницы (при CPL = 3), поэтому не имеет значения, есть ли в пользовательском пространстве хитрый указатель стека.

Альтернативы:

  • принудительное переключение стека ядра, когда код ядра (CPL=0) вызывает ошибку страницы. Это можно сделать с помощью аппаратного переключателя задач (защищенный режим) или механизма IST (длинный режим) для обработчика исключений сбоя страницы. Это был бы лучший вариант для восстановления (например, проще понять, в чем была проблема, исправить ее, а затем вернуться).

  • принудительное переключение стека ядра, когда код ядра (CPL=0) вызывает двойную ошибку. Это можно сделать с помощью аппаратного переключателя задач (защищенный режим) или механизма IST (длинный режим) для обработчика исключения двойной ошибки. Это был бы лучший вариант для производительности (без дополнительных накладных расходов для обычных сбоев страниц).

Примечание 1. Имейте в виду, что ни аппаратное переключение задач, ни шлюзы задач, ни IST не являются повторными. Для аппаратного переключения задач, если ошибка второй страницы возникает во время обработки ошибки первой страницы, вы получите общую ошибку защиты (поскольку «задача ошибки страницы» занята); а для IST, если ошибка второй страницы возникает во время обработки ошибки первой страницы, ошибка второй страницы испортит/перепишет стек ошибки первой страницы и сделает невозможным восстановление. Теоретически вы можете смягчить эти проблемы, как можно скорее переключившись на другую задачу или другой стек, но это сложно/запутанно и может вызвать еще больше проблем.

Примечание 2. Скорее всего, вы столкнетесь с комбинацией избегания и двойной ошибки при использовании аппаратного переключателя задач или IST; с обработчиком двойных ошибок, выполняющим «замораживание системы и дамп информации / панику» в качестве общего запасного варианта для катастрофических сбоев ядра (которых предполагалось избегать, но этого не произошло).

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

person Brendan    schedule 15.03.2020
comment
Спасибо! Я читал, что наличие TSS (которого я еще не настроил, я переключаю задачи без него) заставит процессор переключаться на стек ядра, когда происходит прерывание. Я постараюсь это сделать. - person DrCarnivore; 15.03.2020
comment
Или мне нужно иметь TSS для этого? Достаточно ли просто переключать кольца перед входом в ошибочный процесс? - person DrCarnivore; 15.03.2020
comment
Обратите внимание, что механизм IST также можно использовать в 16- и 32-битном защищенном режиме. Это может быть даже проще в использовании, чем ворота задач. - person fuz; 15.03.2020
comment
как мне настроить TSS? Я создал запись, но как мне добавить ее в GDT, а затем загрузить, чтобы процессор знал esp0 при переключении колец? - person DrCarnivore; 15.03.2020
comment
@DrCarnivore: для защищенного режима; если вы используете другие уровни привилегий (например, CPL=3), вам нужен как минимум один TSS для обработки изменений уровня привилегий (потому что именно оттуда ЦП будет загружать SS:ESP при переходе на более привилегированный уровень — например, с CPL=3 на CPL). =0 из-за прерывания или системного вызова). Как правило, вы получаете несколько аппаратных задач на ЦП — одну основную аппаратную задачу (которая использует переключение программных задач для переключения между обычными задачами), затем несколько аппаратных задач специального назначения, которые не выполняют переключение программных задач (для двойной ошибки, NMI и/или или для исключения машинной проверки). - person Brendan; 16.03.2020
comment
@fuz: Нет, вы не можете использовать IST в защищенном режиме. Вы можете запускать 32-битный код в длинном режиме (и можете использовать IST в длинном режиме), но ядру делать это неудобно (дизайн длинного режима предполагает, что ядро ​​будет 64-битным, поэтому вы получите некоторые thunking в точках входа ядра). - person Brendan; 16.03.2020
comment
@ Брендан Хач? Но та же функция доступна для 32-битных дескрипторов прерываний, и аналогичная таблица существует в 32-битном TSS. Или я неправильно понял, как это работает? - person fuz; 16.03.2020
comment
@fuz: Самое близкое к IST (в длинном режиме) — аппаратное переключение задач (в защищенном режиме). В частности, когда AMD решила, что аппаратное переключение задач не будет поддерживаться в длительном режиме, им пришлось изобрести жизнеспособную замену для использования в обработчиках критических исключений (например, двойной ошибки), чтобы обеспечить переключение на заведомо исправный стек, поэтому они изобрели IST. Он не был обратно перенесен из длинного режима в защищенный (в TSS просто нет места для новой таблицы, и нет причин оправдывать усилия, учитывая, что защищенный режим в основном предназначен для обратной совместимости со старыми вещами, которые не будут поддерживать новые). Особенности). - person Brendan; 16.03.2020