2015-06-08 2 views
3

Я использую процессор Cortex-M0 с голым металлическим исполнением (без ОС). У нас есть приложение прошивки, в котором мы хотим разрешить третьей стороне писать функцию C, которая будет построена отдельно от остальной части прошивки и загружена в память (вроде библиотеки DLL) и вызывается основной микропрограммой, если она обнаружена.Функция kill из ISR на cortex-m0

Проблема в том, что я хочу запустить эту внешнюю функцию в защищенной среде, чтобы она не нарушала основную прошивку, если она создает исключение сбоя или занимает слишком много времени для выполнения. Так что я хочу сделать, либо из-за жесткой ошибки ISR (для исключений сбоев), либо по таймеру ISR (для проблем с временем выполнения), манипулировать стеком, чтобы убить внешнюю функцию и вернуть выполнение в основную прошивку. Я понимаю, что это будет прямо в RTOS, но основная прошивка уже разработана, и на этот момент потребуются значительные усилия по ее переключению.

Я посмотрел на использование try-catch в C++, но компилятор, похоже, не поддерживает его. Поэтому другой вариант, который я вижу, заключается в том, чтобы написать некоторую сборку, чтобы сохранить указатель стека перед вызовом внешней функции, а из ISR восстановить SP и контекст и перейти к точке возврата в основной прошивке. Может ли кто-нибудь дать какие-либо указания о том, как это сделать, или есть ли более простой способ сделать это?

+0

В RTOS не будет проще, поскольку у них нет положений для динамической загрузки/выполнения.Вам все равно придется предоставить свою собственную оболочку для этой функции. Проблема заключается в том, чтобы уловить исключение и откатить стек, но не допустить, чтобы эта функция находилась в чистом ОЗУ. Если MPU достаточно полностью зависит от вашего макета памяти и того, что вы хотите разрешить функции. Например, он может повредить стек, если он имеет не только его собственный. – Olaf

+0

Вы можете использовать крошечный интерпретируемый язык вместо собственного кода, чтобы предотвратить прямой доступ к ЦП/памяти к стороннему коду? –

+0

Брайан - мы действительно сделали первоначальную реализацию с интерпретируемой сборкой, такой как язык, который использовал excel в качестве ассемблера. Однако логические требования стали такими, что писать на ассемблере было обременительно. Таким образом, мы решили перейти на C. Третья часть не будет иметь прямого доступа к какой-либо статической памяти. Им будут предоставлены функции доступа к массиву фиксированного размера контрольных значений. Их использование локальных переменных в стеке вызывает озабоченность. Cortex-m0 имеет стек процесса, который я мог бы использовать только для этого, но на данный момент я думаю, что мы предоставим некоторые правила использования локальной переменной. – jdbk

ответ

0

Вот реализация, в которой я закончил использовать. Я использовал встроенные функции CMSIS __get_MSP() и __set_MSP() для доступа к SP. Перед вызовом защищенной функции я сохранил текущий SP. Обратный адрес - это первый элемент, который функция нажимает на стек, поэтому я увеличиваю сохраненный SP на одно место, поэтому он будет указывать адрес возврата, который будет использоваться в ситуации восстановления.

Таймер таймера ISR отслеживает, как долго работает защищенная функция, и если это произошло из-за сбоя или возникло затруднительное прерывание сбоя, выполняется обработчик ошибок. Первое, что требуется, это выйти из контекста прерывания (иначе вы будете выполнять основной код из контекста прерывания, предотвращая дальнейшие прерывания), поэтому я определил, какое местоположение стека относительно SP содержит адрес возврата ISR, и я перезаписываю его адрес функции восстановления неисправностей. Обратите внимание, что ISR таймера с типом имеет самый низкий приоритет, поэтому обратный адрес всегда будет иметь код без прерывания. Если приоритет ISR выше, это может быть не так, но я не проверял его.

При выходе из ISR выполняется функция восстановления отказа. Есть две команды, которые он требует:

__set_MSP(StackPtrSave); 
__asm volatile ("pop {pc}"); 

Это восстанавливает SP и PC в надлежащем состоянии, если защищенная функция только вышла. Однако он не восстанавливает никаких других регистров. Если точка возврата находится в конце функции (и компилятор не пытается ее встроить), все должно быть в порядке. В моем случае мне нужно было установить StackPtrSave = 0, как это знают ISR, когда защищенная функция запущена. Я попытался использовать volatile pointer, чтобы заставить компилятор перезагрузить адрес переменной в регистр после восстановления, но я не мог заставить его работать. В конце я установил атрибут для отключения оптимизации функции, чтобы он всегда загружал адрес перед записью в StackPtrSave.

Как отмечено в комментариях, это не обеспечивает полностью защищенную среду. Защищенная функция все равно может использовать указатель на повреждение статических переменных или стека. Я не вижу способа избежать этого, поскольку Cortex-m0 не имеет блока защиты памяти. В моем случае у третьей стороны, ответственной за защищенную функцию, есть заинтересованные в функциональности продукта, поэтому я дал рекомендации о том, что их код избегает использования указателей или массивов. Я думаю, что это обеспечивает самый высокий уровень защиты, который можно предложить на этой платформе.