问题
我正在为 ARM Cortex-M3 处理器开发定制操作系统。为了与我的内核交互,用户线程必须生成 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"
);
}
但我在文档中没有找到任何这样的选项,并且我无法解释如何实现这样的功能,所以它可能不存在。我该怎么做?