問題
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"
);
}
しかし、ドキュメントにそのようなオプションが見つからず、そのような機能がどのように実装されるかを説明するのに途方に暮れているため、おそらく存在しません。どうすればいいですか?