Есть ли в ISR (подпрограмме обработки прерываний) отдельный стек?
При использовании RTOS (например, FreeRTOS) у нас есть отдельные стековые пространства для каждого потока. Так что насчет ISR (процедур обработки прерываний), у них есть отдельный стек в памяти? Или это настраивается?
Если у них нет стека, в котором хранятся локальные переменные, объявленные в ISR?
1 ответ
У меня точно такой же вопрос, и многие поиски приводят меня к такому выводу: ответ зависит от вашего чипа и от того, как ОС, которую вы используете, конфигурирует этот чип.
Итак, глядя на один из моих любимых чипов ARM Cortex-M3 (для которого прерывания являются формой исключения), документация в разных местах гласит:
Режимы работы
Cortex-M3 поддерживает привилегированное и пользовательское (непривилегированное) выполнение. Код, выполняемый как Привилегированный, имеет полные права доступа, тогда как код, выполняемый как Пользователь, имеет ограниченные права доступа. Ограничения включают ограничения на использование инструкций, таких как поля MSR, доступ к памяти и периферийным устройствам на основе конструкции системы, и ограничения, налагаемые конфигурацией MPU.
Процессор поддерживает два режима работы: режим потока и режим обработчика. Режим резьбы вводится при сбросе и обычно при возврате из исключения. В режиме потока код может быть выполнен как привилегированный или непривилегированный.
Режим обработчика будет введен в результате исключения. Код в режиме обработчика всегда выполняется как привилегированный, поэтому ядро автоматически переключается в привилегированный режим при возникновении исключений. При возврате из исключения вы можете переключаться между режимом "Привилегированный поток" и режимом "Пользовательский поток", изменив значение EXC_RETURN в регистре ссылок (R14). Вы также можете перейти из привилегированного потока в режим пользовательского потока, очистив CONTROL[0] с помощью инструкции MSR. Однако вы не можете напрямую перейти в привилегированный режим из непривилегированного режима без прохождения исключения, например SVC.
Основные и технологические стеки
Cortex-M3 поддерживает два разных стека: основной стек и стек процессов. Для поддержки этого Cortex-M3 имеет два указателя стека (R13). Один из них выводится в зависимости от используемого стека. Это означает, что только один указатель стека за раз виден как R13. Однако к обоим указателям стека можно получить доступ, используя инструкции MRS и MSR. Основной стек используется при сбросе и всегда используется в режиме обработчика (при вводе обработчика исключений). Указатель стека процессов доступен в качестве текущего указателя стека только в режиме Thread. Вы можете выбрать, какой указатель стека (основной или процесс) используется в режиме потока одним из двух способов: либо с помощью значения EXC_RETURN при выходе из режима обработчика, либо в режиме потока, записав в CONTROL[1] инструкцию MSR.
А также...
Когда процессор принимает исключение, если исключение не является хвостовым или опоздавшим исключением, процессор помещает информацию в текущий стек. Эта операция называется укладкой, а структура из восьми слов данных называется кадром стека. ...
Сразу после укладки указатель стека указывает самый низкий адрес в кадре стека
Из книги "Полное руководство по ARM Cortex-M3":
MSP, также называемый SP_main в документации ARM, является SP по умолчанию после включения питания; он используется кодом ядра и обработчиками исключений. PSP, или SP_process в документации ARM, обычно используется потоковыми процессами в системе с работающей встроенной ОС.
Поскольку обработчики исключений всегда используют указатель основного стека, в памяти основного стека должно быть достаточно места для наибольшего числа вложенных прерываний.
Когда возникает исключение, регистры R0–R3, R12, LR, PC и Program Status (PSR) помещаются в стек. Если выполняемый код использует указатель стека процессов (PSP), будет использоваться стек процессов; если в выполняемом коде используется указатель основного стека (MSP), будет использован основной стек. После этого основной стек всегда будет использоваться во время обработки, поэтому все вложенные прерывания будут использовать основной стек.
ОБНОВЛЕНИЕ 6/2017:
Мой предыдущий ответ был неверным, я проанализировал FreeRTOS для процессоров Cortex и переписал свой ответ:
Стандартная версия FreeRTOS для Cortex-M3 фактически настраивает и использует как MSP, так и PSP. Когда выполняется самая первая задача, она изменяет MSP так, чтобы она указывала на первый адрес, указанный в таблице векторов (0x00000000), это, как правило, самое последнее слово в SRAM, затем она запускает системный вызов в обработчике исключений системного вызова, который он устанавливает PSP к следующему местоположению стека задач, затем он изменяет значение LR исключения таким образом, чтобы "вернуться в режим потока и при возврате использовать стек процесса".
Это означает, что стек подпрограммы обработки прерываний (обработчик исключений AKA) растет по адресу, указанному в таблице векторов.
Вы можете сконфигурировать ваш компоновщик и код запуска, чтобы найти стек обработчика исключений в любом месте, убедиться, что ваша куча или другие области памяти не перекрывают область обработчика исключений, и убедиться, что эта область достаточно велика.
Ответ для других чипов и операционных систем может быть совершенно другим!
Чтобы убедиться, что ваше приложение имеет соответствующее пространство в стеке ISR (MSP), вот дополнительный код для проверки фактического использования стека ISR. В дополнение к проверке, которую вы уже выполняете в стеке задач FreeRTOS, используйте:
https://sourceforge.net/p/freertos/discussion/382005/thread/8418dd523e/
Обновление: я разместил свою версию port.c, которая включает проверку использования стека ISR на github: