Использование встроенного ассемблера GCC с инструкциями, принимающими немедленные значения

Проблема

Я работаю над пользовательской ОС для процессора ARM Cortex -M3. Чтобы взаимодействовать с моим ядром, пользовательские потоки должны генерировать команду SuperVisor Call (SVC )(, ранее известную как SWI, для прерывания SoftWare ). Определение этой инструкции в ARM ARM::

enter image description here

Это означает, что инструкции требуется непосредственный аргумент, а не значение регистра.

Это усложняет мне разработку моего интерфейса в удобочитаемой форме. Требуется такой код, как:

asm volatile( "svc #0");

когда я бы предпочел что-то вроде

svc(SVC_YIELD);

Однако я затрудняюсь построить эту функцию, потому что инструкция SVC требует немедленного аргумента, а я не могу предоставить его, когда значение передается через регистр.

Ядро:

Для фона инструкция svc декодируется в ядре следующим образом

#define SVC_YIELD   0
// Other SVC codes

// Called by the SVC interrupt handler (not shown)
void handleSVC(char code)
{
  switch (code) {

    case SVC_YIELD:
      svc_yield();
      break;
    // Other cases follow

Этот оператор case быстро выходит из-под контроля, но я не вижу пути решения этой проблемы. Любые предложения приветствуются.

Что я пробовал

SVC с аргументом регистра

Сначала я считал

__attribute__((naked)) svc(char code)
{
    asm volatile ("scv r0"); 
}

но это, конечно, не работает, так как SVC требует регистрового аргумента.

Грубая сила

Попытка грубой -решить проблему выглядит так:

void svc(char code)
  switch (code) {
    case 0:
      asm volatile("svc #0");
      break;
    case 1:
      asm volatile("svc #1");
      break;
    /* 253 cases omitted */
    case 255:
      asm volatile("svc #255");
      break;
  }
}

но это имеет неприятный запах кода. Наверняка это можно сделать лучше.

Генерация кодировки инструкций на лету

Последней попыткой было сгенерировать инструкцию в ОЗУ (, остальная часть кода выполняется только для чтения -во флэш-памяти ), а затем запустить ее :

void svc(char code)
{
  asm volatile (
      "orr r0, 0xDF00  \n\t" // Bitwise-OR the code with the SVC encoding
      "push {r1, r0}   \n\t" // Store the instruction to RAM (on the stack)
      "mov r0, sp      \n\t" // Copy the stack pointer to an ordinary register
      "add r0, #1      \n\t" // Add 1 to the address to specify THUMB mode
      "bx r0           \n\t" // Branch to newly created instruction
      "pop {r1, r0}    \n\t" // Restore the stack
      "bx lr           \n\t" // Return to caller
      );
}

. но это тоже не кажется правильным. Кроме того, это не работает -Здесь я что-то делаю не так;возможно, моя инструкция не выровнена должным образом, или я не настроил процессор для запуска кода из ОЗУ в этом месте.

Что я должен делать?

Я должен работать над этим последним вариантом. Но все же мне кажется, что я должен уметь делать что-то вроде:

__attribute__((naked)) svc(char code)
{
    asm volatile ("scv %1"
         : /* No outputs */
         : "i" (code)    // Imaginary directive specifying an immediate argument
                         // as opposed to conventional "r"
          ); 
}

но я не нахожу такой опции в документации и затрудняюсь объяснить, как такая функция будет реализована, поэтому, вероятно, ее не существует. Как мне это сделать?

10
задан reuben 7 July 2012 в 18:17
поделиться