【FreeRTOS】2. SVC系统调用

SVC系统调用

问题

  1. RTOS内核在何时去产生一个SVC系统调用?
  2. SVC中断服务里面使用的是MSP堆栈指针,内核在何时切换为PSP指针?

1. 产生SVC系统调用

FreeRTOS启动调度器的时候,会调用void vTaskStartScheduler(void);

void vTaskStartScheduler(void)
{
    
    
    pxCurrentTCB = &Task1TCB;	//手动指定第一个运行的任务
	if(xPortStartScheduler() != pdFALSE)	//启动调度
    {
    
    
        //调度后不会进入这里
    }
}

其中调用了BaseType_t xPortStartScheduler(void);

BaseType_t xPortStartScheduler(void)
{
    
    
    //配置PendSV和SysTick中断优先级最低
    portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI;
    protNVIC_SYSPRI2_REG |= portVNIC_SYSTICK_PRI;
    prvStartFirstTask();	//启动第一个任务,不再返回
    return 0;	//不会执行该行
}

其中又调用了_asm void prvStartFirstTask(void);

_asm void prvStartFirstTask(void)	//_ASM为C中内嵌汇编的前缀声明
{
    
    
    PRESERVE8 	//8字节对齐
    ldr r0, =0xE0000ED08	//加载SCB_VTOR寄存器地址到R0
    ldr r0, [r0]	//加载SCB_VTOR寄存器的值:0x00000000
    ldr r0, [r0]	//加载0X00000000地址上的内容,为向量表的起始地址即MSP的值
    msr msp, r0		//R0存入MSP	
    cpsie i			//开启中断
    cpsie f			//开启异常
    dsb
    isb
    svc 0			//调用SVC
    nop
    nop
}

可以看到在第12行执行了一句:SVC 0,即产生一次SVC系统调用, 服务号0表示SVC中断。

2. MSP切换为PSP

随后执行SVC中断服务函数_ASM void vPortSVCHandler(void);

__asm void vPortSVCHandler(void)
{
    
    
    extern pxCurrentTCB	//外部变量
    PRESERVE8			//8字节对齐
    ldr	r3, pxCurrentTCB	//加载TCB指针的地址
    ldr r1, [r3]			//加载TCB指针
    ldr r0, [r1]			//加载TCB指向的任务块到R0,任务快的第一成员是栈顶指针,下图1
    ldmia r0!, {
    
    r4-r11}		//将R0指向的值依次赋给{R4~R11}并自增地址	
    msr psp, r0	    		//寄存器R4~R11加载完后,将此时R0的值赋给PSP 下图2
    isb	
    mov r0, #0 			//R0 = 0
    msr	basepri, r0		//BASEPRI = 0 不屏蔽任何中断
    orr r14, #0xd		//R14|=0X0D使得硬件在退出时使用PSP完成出栈操作并返回后进入任务模式Thumb状态,在SVC中断服务里面使用的是MSP,ARM状态 
    bx r14		//异常返回,由于上一句指令切换到PSP,返回时会自动出栈。因此PSP指针自动将栈中剩下的内容加载到CPU寄存器:xPSR, PC(任务入口地址),R14,R12,R3,R2,R1,R0(任务形参)。出栈操作完成后,PSP指向任务栈的栈顶。 下图3
}

图1:

图1

图2:
图2

图3:
图3

图片来源

猜你喜欢

转载自blog.csdn.net/weixin_45636061/article/details/121460820
今日推荐