Cortex-M核 SVC系统服务的使用(ARM AC6环境下)

SVC系统服务的使用(ARM AC6环境下)

1、熟悉内嵌汇编

__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]");
}

上述是一段调用svc 4服务的接口,期望功能是 res = x + y.

针对 __asm volatile("SVC #4" :: "r" (r0), "r" (r1), "r" (r2));解释。

  • "SVC #4"是触发SVC中断,设置服务号为4
  • 第一个 :后面一般跟随可以从汇编指令中反赋值到C代码变量中
  • 第二个 :后面一般跟随仅从C代码输入到汇编指令的的变量
  • "r" (r0)中的 "r"目测没什么特殊含义,更换成其他字符也是可以的

上述代码在运行第一段内嵌汇编时,会将SVC机器码(包含服务号)、r0、r1、r2压入栈中,同时触发SVC中断,进入内核服务中

举个例子:

void testASM(void)
{
    register uint32_t val = 12, res;

    __ASM volatile (
		".syntax unified\n"
        "mov %[val],%[res]" 

		: [res] "=&l" (res)
		: [val] "l"   (val)
    );

    printf("res = %d\n", res);
}
// 结果 res = 12

2、编写SVC中断服务函数(使用汇编实现)

        .syntax  unified									;使用GNU语法
        .section ".rodata"									;定义只读数据段
															;这里没有定义只读数据,如有需要,可在此处定义
        .thumb												;使用thumb指令集
        .section ".text"									;定义代码段
        .align   2											;定义字节对齐为 2^2 = 4
        .eabi_attribute Tag_ABI_align_preserved, 1			;不知道,这样抄过来的

        .thumb_func											;不知道,抄过来的,目测定义函数需要
        .type    SVC_Handler, %function						;不知道,抄过来的,目测定义为 (一个类型名为SVC_Handler, 描述为函数)
        .global  SVC_Handler								;不知道,抄过来的,目测允许此函数对外声明
        .fnstart											;不知道,抄过来的,目测为函数的开始标志,和 .fnend 成对使用
        .cantunwind											;不知道,抄过来的,目测定义函数需要
SVC_Handler:												;标号,在此处范围内获取lr寄存器的值,判断SVC服务的触发在主堆栈还是线程堆栈下
        mov      r0, lr
        lsrs     r0, r0, #3
	    bcc      SVC_MSP									;合成指令,为B + CC,跳转和识别C符号的混合使用,意为当C标号为0时跳转
        mrs      r0, psp

SVC_Number:
        push     {r0,lr}        // Save EXC_RETURN
		bl       SVC_Handler_C								;此时r0里的内容时sp指针,调用C函数,同时r0会成为第一个入口参数参与解析
        pop      {r0,r1}        // Restore EXC_RETURN		;不是很理解,压栈时时r0,lr,出栈时时r0,r1
        mov      lr,r1 

        bx       lr

SVC_MSP:
        mrs      r0, msp
        b        SVC_Number
   

        .fnend												;不知道,抄过来的,目测为函数的结束标志,和 .fnstart 成对使用
        .size    SVC_Handler, .-SVC_Handler					;不知道,抄过来的,目测定义函数需要


        .end												;汇编文件的截至

3、解析SVC服务

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:
            printf("SVC 4\r\n");
            break;
        case 5:
            printf("SVC 5\r\n");
            break;
        default:
            break;
    }    
    
    return;
}

svc_args是传入的sp堆栈地址,由于压栈顺序依次是从左到右(R0, R1, R2, R3, R12, LR, PC, xPSR),因此,svc_args[6]= PC,即保存机器指令码在flash上的地址,又由于在取指令后PC自动偏移,因此此处的PC指向即将运行的指令,而我们需要的指令在 当前PC - 4的地址上。由于SVC机器码为 0xDF00 | 服务号(服务号是8bit的数据),因此 ((uint8_t*)svc_args[6])[-2]为当前实际触发的服务号。

  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值