SVC(系统服务调用,亦简称系统调用)和PendSV(可悬起系统调用),它们多用在上了操作系统的软件开发中。SVC用于产生系统函数的调用请求。例如,操作系统通常不让用户程序直接访问硬件,而是通过提供一些系统服务函数,让用户程序使用SVC发出对系统服务函数的呼叫请求,以这种方法调用它们来间接访问硬件。因此,当用户程序想要控制特定的硬件时,它就要产生一个SVC异常,然后操作系统提供的SVC异常服务例程得到执行,它再调用相关的操作系统函数,后者完成用户程序请求的服务。
下面的代码是利用SVC异常来请求系统服务的例子,这个例子仅适用于MDK ARM Compiler 5,在ARM Compiler 6里取消了__svc()这个关键字,需要用户自己实现
__svc(4) uint32_t svc_service_add(uint32_t x, uint32_t y); //__svc是编译器关键字,编译器会插入svc指令,触发svc异常
__svc(5) uint32_t svc_service_sub(uint32_t x, uint32_t y);
void SVC_Handler_C(uint32_t* svc_args) //这里的svc_args是栈指针SP的值
{
uint32_t svc_number;
svc_number = ((uint8_t*)svc_args[6])[-2]; //svc_args[6]是栈里保存的PC值,倒数2字节,得到svc编号
switch(svc_number) //根据svc编号执行需要的功能
{
case 4:
svc_args[0] = svc_args[0] + svc_args[1];
break;
case 5:
svc_args[0] = svc_args[0] - svc_args[1];
break;
default:
break;
}
return;
}
__asm void SVC_Handler(void)
{
IMPORT SVC_Handler_C //导入外部函数
TST LR, #4 //检查LR的bit2,这里LR的值是异常返回值EXC_RETURN
ITE EQ
MRSEQ R0, MSP //如果bit2是0,说明进异常前使用的是MSP,把MSP值赋给R0
MRSNE R0, PSP //否则说明进异常前使用的是PSP,把PSP值赋给R0
B SVC_Handler_C //跳转到函数SVC_Handler_C()
}
uint32_t x = 13;
uint32_t y = 6;
uint32_t z1, z2;
int main(void)
{
z1 = svc_service_add(x, y);
z2 = svc_service_sub(x, y);
printf("x + y = %d \r\n", z1);
printf("x - y = %d \r\n", z2);
while(1);
}
下面这个是使用ARM Compiler 6的例子,本人水平有限,不会写带有返回值的C嵌汇编函数,只好用一个指针参数来传递结果。注意ARM编译器6的C嵌汇编语法格式与编译器5不同
__attribute__((always_inline)) void svc_service_add(uint32_t x, uint32_t y, uint32_t* res)
{
register unsigned r0 __asm("r0") = x;
register unsigned r1 __asm("r1") = y;
register unsigned r2 __asm("r2") = (uint32_t)res;
__asm volatile("SVC #4" :: "r" (r0), "r" (r1), "r" (r2));
__asm volatile("STR R0, [R2]");
}
__attribute__((always_inline)) void svc_service_sub(uint32_t x, uint32_t y, uint32_t* res)
{
register unsigned r0 __asm("r0") = x;
register unsigned r1 __asm("r1") = y;
register unsigned r2 __asm("r2") = (uint32_t)res;
__asm volatile("SVC #5" :: "r" (r0), "r" (r1), "r" (r2));
__asm volatile("STR R0, [R2]");
}
void SVC_Handler_C(uint32_t* svc_args)
{
uint32_t svc_number;
svc_number = ((uint8_t*)svc_args[6])[-2];
switch(svc_number)
{
case 4:
svc_args[0] = svc_args[0] + svc_args[1];
break;
case 5:
svc_args[0] = svc_args[0] - svc_args[1];
break;
default:
break;
}
return;
}
void SVC_Handler(void)
{
__asm volatile
(
"TST LR, #4 \n"
"ITE EQ \n"
"MRSEQ R0, MSP \n"
"MRSNE R0, PSP \n"
"B SVC_Handler_C \n"
);
}
uint32_t x = 13;
uint32_t y = 6;
uint32_t z1, z2;
int main(void)
{
svc_service_add(x, y, &z1);
svc_service_sub(x, y, &z2);
printf("x + y = %d \r\n", z1);
printf("x - y = %d \r\n", z2);
while(1);
}
这里有一篇文章,是Keil官方关于ARM Compiler 6如何实现svc函数的: