Cortex-M3利用SVC中断调用系统服务的例子

2023-05-16

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函数的:

https://www.keil.com/support/docs/4022.htm

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Cortex-M3利用SVC中断调用系统服务的例子 的相关文章

随机推荐