原创 uCOS运行时堆栈管理

2013-2-20 20:23 1756 13 13 分类: 消费电子

 

/*-------------------------------------------------------------------------------------------------------------------------*/
堆管理
 
而这里的内存管理,实质是预先分配固定大小的内存,
使用时只能使用相应大小的内存。
因为在裸机上做内存管理,固定分配的要优于动态分配。(应该说是,uCOS使用固定分配来模拟动态分配)
因为一般使用uCOS的地方,内存都不多,这时固定分配反而是更优的选择。
(对于内存受限系统(memory constrainted system)的嵌入式编程,这种方式应该说是最合适的方式了)
 
/*-------------------------------------------------------------------------------------------------------------------------*/
栈管理
 
那么在uCOS中一个任务操作超过了其堆栈设置会有什么样的后果呢?
从uCOS中os_tcb 结构体中发现默认的只有一个栈顶指针,这里的栈顶指针是如何使用的。
 
OSCtxSw(uCOS_II_V2.86/uC_Port/os_cpu_a.asm)这个函数,是由汇编语言写成的,为了触发pendsv中断引起切换。
 
`~uCOS_II_V2.86/
|     |+Core/
|     |+uC_CPU/
|     |+uC_LIB/
|     |~uC_Port/
|     | |+ini/
|     | `~src/
|     |   |-os_cpu_a.asm
|     |   |-os_cpu_c.c
|     |   `-os_dbg.c
|     `+uCOS-II/
 
这里边在第一次切换时,使用的是最高优先级的代码。
对于栈空间的使用,方法如下:
首先由Task_Create函数设置好栈顶指针,
在任务切换时,将这个栈顶指针(而这里的这个栈顶指针既是在创建任务时,传入的一个数组的首地址,拿来当做栈使用)传递给sp,实现sp的切换。
 
当任务切换时,
除了保存所有寄存器意外,
最重要的就是要
 
在OSStartHighRdy函数中,将OSRunning置位TRUE,表示系统开始执行。
 
问题是,这个修改的栈指针,是什么时候修改的?
在切换时,sp保存在当前任务的OS_TCB结构体中,此时sp和OSTCBCur->OSTCBStkPtr指向的是任务堆栈的都一个内存位置。
里边有第一次切换的判断。第一次切换时,不保存堆栈,如果是以后切换需要保存堆栈。
 
这里确实没有关于栈溢出的操作,因为如果栈溢出,将覆盖其他任务的栈内容,修改备份的寄存器内容。
会造成其他任务运行异常,这样就会引起错误。
(栈空间的大小至少要能保存,芯片体系结构要求保存的所有寄存器内容)
 
//STM32F103CBT6任务切换代码
Note(s) : 1) PendSV is used to cause a context switch.  This is a recommended method for performing
;              context switches with Cortex-M3.  This is because the Cortex-M3 auto-saves half of the
;              processor context on any exception, and restores same on return from exception.  So only
;              saving of R4-R11 is required and fixing up the stack pointers.  Using the PendSV exception
;              this way means that context saving and restoring is identical whether it is initiated from
;              a thread or occurs due to an interrupt or exception.
;
;           2) Pseudo-code is:
;              a) Get the process SP, if 0 then skip (goto d) the saving part (first context switch);
;              b) Save remaining regs r4-r11 on process stack;
;              c) Save the process SP in its TCB, OSTCBCur->OSTCBStkPtr = SP;
;              d) Call OSTaskSwHook();
;              e) Get current high priority, OSPrioCur = OSPrioHighRdy;
;              f) Get current ready thread TCB, OSTCBCur = OSTCBHighRdy;
;              g) Get new process SP from TCB, SP = OSTCBHighRdy->OSTCBStkPtr;
;              h) Restore R4-R11 from new process stack;
;              i) Perform exception return which will restore remaining context.
;
;           3) On entry into PendSV handler:
;              a) The following have been saved on the process stack (by processor):
;                 xPSR, PC, LR, R12, R0-R3
;              b) Processor mode is switched to Handler mode (from Thread mode)
;              c) Stack is Main stack (switched from Process stack)
;              d) OSTCBCur      points to the OS_TCB of the task to suspend
;                 OSTCBHighRdy  points to the OS_TCB of the task to resume
;
;           4) Since PendSV is set to lowest priority in the system (by OSStartHighRdy() above), we
;              know that it will only be run when no other exception or interrupt is active, and
;              therefore safe to assume that context being switched out was using the process stack (PSP).
OS_CPU_PendSVHandler
    CPSID   I                                                   ; Prevent interruption during context switch
    MRS     R0, PSP                                             ; PSP is process stack pointer
    CBZ     R0, OS_CPU_PendSVHandler_nosave                     ; Skip register save the first time

    SUBS    R0, R0, #0x20                                       ; Save remaining regs r4-11 on process stack
    STM     R0, {R4-R11}

    LDR     R1, =OSTCBCur                                       ; OSTCBCur->OSTCBStkPtr = SP;
    LDR     R1, [R1]
    STR     R0, [R1]                                            ; R0 is SP of process being switched out

                                                                ; At this point, entire context of process has been saved
OS_CPU_PendSVHandler_nosave
    PUSH    {R14}                                               ; Save LR exc_return value
    LDR     R0, =OSTaskSwHook                                   ; OSTaskSwHook();
    BLX     R0
    POP     {R14}

    LDR     R0, =OSPrioCur                                      ; OSPrioCur = OSPrioHighRdy;
    LDR     R1, =OSPrioHighRdy
    LDRB    R2, [R1]
    STRB    R2, [R0]

    LDR     R0, =OSTCBCur                                       ; OSTCBCur  = OSTCBHighRdy;
    LDR     R1, =OSTCBHighRdy
    LDR     R2, [R1]
    STR     R2, [R0]

    LDR     R0, [R2]                                            ; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;
    LDM     R0, {R4-R11}                                        ; Restore r4-11 from new process stack
    ADDS    R0, R0, #0x20
    MSR     PSP, R0                                             ; Load PSP with new process SP
    ORR     LR, LR, #0x04                                       ; Ensure exception return uses process stack
    CPSIE   I
    BX      LR                                                  ; Exception return will restore remaining context

    END
 
关于切换的具体实现,
到这里感觉清楚很多。

文章评论0条评论)

登录后参与讨论
我要评论
0
13
关闭 站长推荐上一条 /2 下一条