高级会员
- 积分
- 565
- 金钱
- 565
- 注册时间
- 2013-10-16
- 在线时间
- 52 小时
|
;********************************************************************************************************
; HANDLE PendSV EXCEPTION
; void OS_CPU_PendSVHandler(void)
; ( PendSV 中断服务函数 ==== 太重要了,执行任务切换就在这里 )
; Note(s) : 1) PendSV is used to cause a context switch. This is a recommended method for performing
; context switches with Cortex-M0. This is because the Cortex-M0 auto-saves half of the
; processor context on any exception, and restores same on return from exception. So only
; saving of R4-R7 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-R7 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-R7 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 ; 这里搞了这么久,真的什么都有可能的,
PendSV_Handler ; ( PendSV 中断处理函数 )
CPSID I ; 失能中断
MRS R0, PSP ; R0=PSP,
CMP R0, #0 ; if(PSP == 0) 第一次任务切换
BEQ OS_CPU_PendSVHandler_nosave ; (BEQ =相等或为0则跳转 ) saving part (first context switch)
; 保存R4,R5,R6,R7到线程堆栈PSP
SUBS R0, R0, #0x10 ; (R0=R0-16(byte)) Adjust stack pointer to where memory needs to be stored to avoid overwriting
STM R0!, {R4-R7} ; ( store multiple registers(16byte) ),Stores 4 4-byte registers, default increments SP after each storing
SUBS R0, R0, #0x10 ; STM does not automatically call back the SP to initial location so we must do this manually
; OSTCBCur->OSTCBStkPtr = SP;
LDR R1, =OSTCBCur ; R1 = &OSTCBCur,
LDR R1, [R1] ; R1 = *R1 (R1 = OSTCBCur)
STR R0, [R1] ; *R1 = R0 (*OSTCBCur = SP)
OS_CPU_PendSVHandler_nosave ; At this point, entire context of process has been saved
; 调用OSTaskSwHook()
PUSH {R14} ; 保存R14,因为后面要调用函数
LDR R0, =OSTaskSwHook ; R0 = &OSTaskSwHook
BLX R0 ; 调用 OSTaskSwHook()
POP {R0} ; 出栈
MOV R14, R0 ; 恢复R14, LR = R0
; OSPrioCur = OSPrioHighRdy;
LDR R0, =OSPrioCur ; R0 = &OSPrioCur
LDR R1, =OSPrioHighRdy ; R1 = &OSPrioHighRdy
LDRB R2, [R1] ; R2 = *R1 (R2 = OSPrioHighRdy)
STRB R2, [R0] ; *R0 = R2 (OSPrioCur = OSPrioHighRdy)
; OSTCBCur = OSTCBHighRdy;
LDR R0, =OSTCBCur ; R0 = &OSTCBCur
LDR R1, =OSTCBHighRdy ; R1 = &OSTCBHighRdy
LDR R2, [R1] ; R2 = *R1 (R2 = OSTCBHighRdy)
STR R2, [R0] ; *R0 = R2 (OSTCBCur = OSTCBHighRdy)
LDR R0, [R2] ; R0 = *R2 (R0 = OSTCBHighRdy), R0 is new process SP; ((SP = OSTCBHighRdy->OSTCBStkPtr;))
LDM R0!, {R4-R7} ; Restore R4-R7 from new process stack
MSR PSP, R0 ; Load PSP with new process SP
; 确认使用进程堆栈
MOV R0, R14 ; R0=LR,
MOVS R1, #0x04 ; Immediate move to register
ORRS R0, R1 ; Ensure exception return uses process stack
MOV R14, R0 ; 确认LR位2为1,返回后使用进程堆栈
CPSIE I ; 使能中断
BX LR ; Exception return will restore remaining context
ALIGN ; Ensures that ARM instructions start on four-byte boundary
END
代码分析分享
2, PendSV中断服务函数,
21,关闭中断
22,判断PSP==0(如果第一次任务切换就跳过)
23,保存R4/5/6/7到线程堆栈PSP
24,保存现场,OSTCBCur->OSTCBStrPtr=PSP
25,OS_CPU_PendSVHandler_nosave
26,调用OSTaskSwHook()
27,OSPrioCur = OSPrioHighRdy;
28,OSTCBCur = OSTCBHighRdy;
29,SP = OSTCBHighRdy->OSTCBStkPtr;
30,恢复R4-R7,
31,PSP = OSTCBHighRdy->OSTCBStkPtr;恢复PSP
32,确认使用进程堆栈
33,根据LR程序执行跳转
|
|