linux中断机制与RTOS中断机制,浅析FreeRTOS_v4.5.0的任务切换原理和栈结构

浅析FreeRTOS_v4.5.0的任务切换原理和栈结构

文章来源:http://gliethttp.cublog.cn[转载请声明出处]

FreeRTOS的更新速度很快,基本2、3个月就会出现一个新版本,看来一直在完善和各种功能增加中,截止

2007/09/27日为止,FreeRTOS_v4.5.0是最新版本,下面研究一下FreeRTOS_v4.5.0在at91sam7s64处理器

上的任务切换代码.

当有更高优先级的task任务就绪或者当前task任务因为vTaskDelay()延时或者消息事件等待而主动让出cpu

时,FreeRTOS_v4.5.0会在适当的位置执行taskYIELD();进行task进程调度,让更应该持有cpu的task获得

持有权.

1.触发软中断执行处理器对应的swi处理函数

//在/source/include/Task.h中有如下定义:

#define taskENTER_CRITICAL()        portENTER_CRITICAL()

//在/source/portable/iar/atmelsam7s64/Portmacro.h中有如下定义:

//只是借壳下蛋,中断号0,其值本身没有意义,因为swi处理函数中,并不会使用到中断号值,

//这和linux的系统调用有些出入,linux的系统调用,中断号值对应了相应系统调用处理函数

//的索引值,可以参看《浅析arm-linux系统调用的流程 》//文章地址:http://blog.chinaunix.net/u1/38994/showart_331915.html#define portYIELD()                    asm ( "SWI 0" )

因此可以看出来FreeRTOS_v4.5.0使用软中断触发task的调度函数,来看看软中断入口函数:

//在/demo/arm7_at91sma7s64_iar/srciar/Cstratup.s79中有中断向量处理代码:                B InitReset ; 0x00 Reset handler

undefvec:

B undefvec ; 0x04 Undefined Instruction

swivec://很明显portYIELD()调用之后将直接导致cpu去进一步执行vPortYieldProcessor                B vPortYieldProcessor ; 0x08 Software Interrupt

pabtvec:

B pabtvec ; 0x0C Prefetch Abort

dabtvec:

B dabtvec ; 0x10 Data Abort

rsvdvec:

B rsvdvec ; 0x14 reserved

irqvec:

LDR   PC, [PC, #-0xF20]    ; Jump directly to the address given by the AIC

//在/source/portable/iar/atmelsam7s64/Portasm.s79中定义了vPortYieldProcessor处理函数vPortYieldProcessor:

//lr+4是为了调整lr的值,使其和IRQ中断进入的模式值一致    ADD        LR, LR, #4

//接下来就可以安全的认为是由于IRQ中断引起的任务进、出栈(gliethttp)    portSAVE_CONTEXT//保存上、下文    LDR R0,    =vTaskSwitchContext

mov lr,    pc

BX R0//计算出优先级最高的任务//恢复vTaskSwitchContext函数计算出的优先级最高任务的上、下文,进而在cpu中运行优先级最高任务.    portRESTORE_CONTEXT

2.FreeRTOS_v4.5.0在at91sam7s64上的任务切换出、入栈汇编代码分析

///source/portable/iar/atmelsam7s64/ISR_Support.h中定义了这两个汇编子函数<2.1>portSAVE_CONTEXT入栈宏

在进行分析下面这段代码之前,首先必须清楚FreeRTOS_v4.5.0在at91sam7s64上使用的模式情况

首先,上电之后sam64工作在svc模式,当完成所有sam64自身的初始化工作以及xTaskCreate()之后,

仍然处于svc模式,只有当调用vTaskStartScheduler()->xPortStartScheduler()->vPortStartFirstTask()

之后sam64就随着portRESTORE_CONTEXT()的执行使得task进入sys模式下执行了,

所以其实最后任务将在sys模式下执行,这也是pxPortInitialiseStack()所定义的spsr的模式值

portSAVE_CONTEXT MACRO

STMDB      SP!,{R0}//R0推入swi专用栈    STMDB      SP, {SP}^//将sys模式下的sp值推入当前swi模式下的sp中    NOP

SUB        SP, SP, #4//swi堆栈调整到执行STMDB SP!, {SP}^之后的值    LDMIA      SP!,{R0}//把swi栈中存放的sys模式下的sp值转存到r0中    STMDB      R0!,{LR}//将swi模式中的lr推入sys模式下的堆栈(gliethttp)    MOV        LR, R0//将sys模式下的堆栈值转用lr临时存储    LDMIA      SP!,{R0}//现在sys模式下的sp堆栈已经使用swi下的lr代替,所以r0已经不再被使用,     //swi模式下的sp已经释放,r0恢复到了sys模式下的r0值    STMDB      LR, {R0-LR}^//把sys下的r0-lr的数据推入sys模式下的sp堆栈中    NOP

SUB        LR, LR, #60//调整lr,使其等于sys模式下的sp堆栈位置    MRS        R0, SPSR//r0已经入栈,所以可以使用;spsr中含有IRQ和FIQ的中断时能否标志以及sys模式标志    STMDB      LR!,{R0}//将spsr入栈    LDR        R0, =ulCriticalNesting

LDR        R0, [R0]

STMDB      LR!,{R0} //将ulCriticalNesting入栈    LDR        R1, =pxCurrentTCB

LDR        R0, [R1]

STR        LR, [R0]//pxCurrentTCB为task进程的上下文存储单元,其中第一项为pxTopOfStack本task的栈顶值    ENDM

所以入栈后sys栈中的数据为:

pc //task被抢占执行到的地址值r14

...

r0

spsr

ulCriticalNesting

pxCurrentTCB->pxTopOfStack

一共18项

<2.2>portRESTORE_CONTEXT出栈宏

portRESTORE_CONTEXT MACRO

LDR        R1, =pxCurrentTCB//pxCurrentTCB对应当前切换出去之后需要执行的task的上下文                                //它的数据结构体偏移0处就是task的pxTopOfStack堆栈顶值    LDR        R0, [R1]

LDR        LR, [R0]//task的sp存放到swi的lr    LDR        R0, =ulCriticalNesting

LDMFD      LR!,{R1}

STR        R1, [R0]//恢复新task栈中的ulCriticalNesting到全局量ulCriticalNesting    LDMFD      LR!,{R0}

MSR        SPSR_cxsf, R0//将新task的spsr恢复到SPSR_cxsf中    LDMFD      LR, {R0-R14}^//恢复新task的r0-r14寄存器    NOP

LDR        LR, [LR, #+60]//调整sp指针,并读取pc值    SUBS       PC, LR, #4//因为是在ISR模式下的lr,所以需要+4调整,执行新task,同时恢复SPSR_cxsf到CPSR    ENDM

以上汇编设计的很精巧,短短几行就完成了数据的保存与恢复,还有一个设计的很精巧的地方就是第一次

启动FreeRTOS的启动函数vTaskStartScheduler()->xPortStartScheduler()->vPortStartFirstTask()

//在source/portable/iar/atmelsam7s64/Portasm.s79中定义vPortStartFirstTask:

portRESTORE_CONTEXT//很巧妙,先将task从TCB中恢复,之后r0~lr、spsr、ulCriticalNesting

//和pxCurrentTCB->pxTopOfStack就真的是那个task执行起来的环境值了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值