11

問題

ARM Cortex-M3 プロセッサ用のカスタム OS に取り組んでいます。カーネルとやり取りするには、ユーザー スレッドは SuperVisor Call (SVC) 命令 (以前はソフトウェア割り込みの SWI と呼ばれていました) を生成する必要があります。ARM ARM でのこの命令の定義は次のとおりです。

ここに画像の説明を入力

つまり、命令にはレジスタ値ではなく、 即時引数が必要です。

これにより、インターフェイスを読みやすい方法で設計することが難しくなっています。次のようなコードが必要です。

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

このケース ステートメントは急速に手に負えなくなりつつありますが、この問題を回避する方法はありません。どんな提案でも大歓迎です。

私が試したこと

レジスター引数を持つ 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;
  }
}

しかし、それには厄介なコードの匂いがあります。確かにこれはもっとうまくできる。

オンザフライで命令エンコーディングを生成する

最後の試みは、RAM で命令を生成し (残りのコードは読み取り専用フラッシュから実行されます)、それを実行することでした。

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
      );
}

しかし、これも気分が悪いだけです。また、機能しません - ここで間違っていることがあります。おそらく、私の命令が適切に配置されていないか、この場所で RAM からコードを実行できるようにプロセッサを設定していません。

私は何をすべきか?

私はその最後の選択肢に取り組まなければなりません。それでも、次のようなことができるはずだと感じています。

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

しかし、ドキュメントにそのようなオプションが見つからず、そのような機能がどのように実装されるかを説明するのに途方に暮れているため、おそらく存在しません。どうすればいいですか?

4

5 に答える 5

24

制約を使用して、オペランドを8ビットのイミディエートとして強制的に割り当てる必要があります。ARMの場合、それは制約Iです。あなたが望んでいるのは

#define SVC(code) asm volatile ("svc %0" : : "I" (code) )

すべての内容の概要については、GCCのドキュメントを参照してください。特定のプラットフォームの制約を確認するには、プロセッサ固有の注意事項を確認する必要があります。場合によっては、.md完全な情報について、gccソースのアーキテクチャの(マシン記述)ファイルを調べる必要があります。

ここには、ARM固有の優れたgccドキュメントもいくつかあります。「入力および出力オペランド」という見出しの下の数ページは、すべてのARM制約の表を提供します。

于 2012-07-07T20:42:15.807 に答える
2

マクロの使用について:

#define SVC(i)  asm volatile("svc #"#i)
于 2012-07-07T18:15:49.433 に答える
2

マクロのコメントで Chris Dodd が指摘したように、うまくいきませんが、これはうまくいきます:

#define STRINGIFY0(v) #v
#define STRINGIFY(v) STRINGIFY0(v)
#define SVC(i)  asm volatile("svc #" STRINGIFY(i))

ただし、enum 値を渡すと機能しないことに注意してください。#defined 値のみを渡してください。

したがって、上記の Chris の回答は、少なくとも親指の指示に必要な即時値を使用するため、最適です。

于 2014-06-06T10:53:20.430 に答える