Cortex M3 - вызов SV C внутри функции C и возврат в режим потока - PullRequest
0 голосов
/ 18 марта 2020

Я пишу системные вызовы в соответствии с рекомендациями Джозефа Йиу (Руководство по M3), используя аргументы из стека. Обработчик SV C сборки выглядит так:

     SVC_Handler:
     MOV R0, #0
     MSR CONTROL, R0
     CMP LR, #0xFFFFFFFD
     BEQ KernelEntry
     B   KernelExit

    KernelEntry: 
    <save current user stack>
    B svchandler_main

    KernelExit:
    <code to restore the very same saved user stack saved before>
    MOV LR, #0xFFFFFFFFD
    BX      LR 

Итак, функция svchandler_main is C, которая восстанавливает непосредственные значения (аргументы системного вызова), создает ядро стек и ветви до 0xFFFFFFFF9 (привилегированный MSP). Сам системный вызов сделан как:

#define svc(code) asm volatile ("svc %[immediate]"::[immediate] "I" (code))
void SysCall_MyCall(int32_t args)
{
  svc(CallBack_Number);
}

Тем не менее, функция обратного вызова, работающая в режиме обработчика:

void SysCallBack(void* args)
{
  /* <my c routine>*/
  asm volatile("svc #0"); //to exit the kernel mode
}

Последний вызов SV выполняется так, чтобы SVC_Handler в сборке определит, что это происходит из режима обработчика (привилегированный MSP) и выйдет из ядра - своего рода совместное планирование на ядре. Проблема в том, что контекст сохраняется с указанием PSP внутри SysCall_MyCall, и он возвращается туда и никогда не завершается. Если я использую встроенные функции, я потеряю удобный svchandler_main . Любые идеи? Я не писал здесь svchandler_main , потому что это код classi c, найденный в примечаниях к приложениям ARM. Спасибо.

Редактировать, чтобы уточнить: Я не использую функцию обратного вызова INSIDE SV C Обработчик. Он создает стек обратного вызова, изменяет LR на 0xFFFFFFF9 и выполняет LX BX, выходя из прерывания и переходя к указанному MSP. Для выхода из ядра вызывается другой SV C, и пользовательский поток возобновляется.

1 Ответ

1 голос
/ 19 марта 2020

Кажется, вы неправильно понимаете, как ввод и возврат исключений работает в Cortex-M. Когда вы запускаете инструкцию SVC из потокового режима, процессор переходит в режим обработчика, как и для любого другого исключения.

Режим обработчика всегда привилегирован и всегда использует основной стек (MSP). Режим потока может быть либо привилегированным, либо непривилегированным в зависимости от бита nPRIV (бит 0) в регистре CONTROL, и может быть настроен на использование стека процессов (PSP), установив бит SPSEL (бит 1) в регистр CONTROL из потокового режима.

При входе в режим обработчика r0-r3, r12, lr, pc и xPSR помещаются в активный стек (PSP или MSP (в зависимости от того, что используется) и возвращаемое значение исключения загружается в lr. Стек переключен на MSP. В конце обработчика инструкция BX lr (или эквивалентная) заставляет это значение использоваться в качестве цели ветвления, что автоматически вызывает восстановление предыдущего режима и стека, и выдает r0-r3, r12, lr, pc и xPSR. Всплывающее окно pc восстанавливает выполнение с того места, где произошло прерывание.

Важной особенностью этого механизма является то, что он на 100% совместим с ARM ABI. Другими словами, можно написать обычную функцию и использовать ее в качестве обработчика исключений, просто поместив адрес функции в соответствующее место в таблице векторов прерываний. Это потому, что возвращение в конце функции выполняется с помощью BX lr или его эквивалента, который является точно такой же инструкцией, которая запускает возврат из режима обработчика.

Итак, чтобы написать обработчик SV C, который делает При использовании обратных вызовов необходимо:

  • Определить, какой стек использовался, когда была выдана инструкция SV C
  • Выкопать сложенную pc, чтобы найти адрес самой инструкции SV C и извлечение 8-битной константы из инструкции SV C
  • Используйте константу, чтобы определить, какой обратный вызов вызывать
  • Ветвь к ( не вызов) соответствующий обратный вызов

обратный вызов может быть совершенно обычной функцией. Когда он возвращается, он запускает возврат из режима обработчика, потому что соответствующий код возврата исключения все еще будет в lr.

Обработчик, который делает все это, представлен в Руководстве M3, глава 10.

Если требуется, чтобы обратный вызов получал аргументы, это немного сложнее, но я могу расширить свой ответ, если хотите. Обычно обратные вызовы обработчика выполняются в режиме обработчика (в этом и заключается смысл SV C). Если по какой-то причине вам требуется, чтобы обратный вызов выполнялся без привилегий, это еще более сложно; хотя есть пример в главе 23 руководства M3. В комментариях вы говорите, что не хотите «управлять вложенными прерываниями», но действительно вложенные прерывания просто управляют собой.

...