ucos-15-osintctxsw分析

OS_CPU_a.s:
;定义系统模式堆栈的大小
SVC_STACK_LEGTH EQU 32
 
NoInt EQU 0x80
 
USR32Mode EQU 0x10
SVC32Mode EQU 0x13
SYS32Mode EQU 0x1f
IRQ32Mode EQU 0x12
FIQ32Mode EQU 0x11
 
;T_bit用于检测进入异常前cpu是否处于THUMB状态
T_bit EQU 0x20
 
CODE32
 
AREA |subr|, CODE, READONLY
 
IMPORT OSTCBCur  ;指向当前任务 TCB的指针
IMPORT OSTCBHighRdy  ;指向将要运行的任务 TCB的指针
IMPORT OSPrioCur  ;当前任务的优先级
IMPORT OSPrioHighRdy  ;将要运行的任务的优先级
IMPORT OSTaskSwHook  ;任务切换的钩子函数
IMPORT OSRunning  ;uC/OS-II运行标志
 
IMPORT OsEnterSum  ;关中断计数器(关中断信号量)
IMPORT SWI_Exception  ;软中断异常处理程序
 
EXPORT __OSStartHighRdy
EXPORT OSIntCtxSw  ;中断退出时的入口,参见 startup.s中的 IRQ_Handler
EXPORT SoftwareInterrupt  ;软中断入口
 
;软件中断
// CPU发现有软中断信号出现时, CPU PC马上指到软中断服务地址处【见 Startup.s】,然后通过跳转到下面这段软中断处理程序,进入后,首先要设置好管理模式下的堆栈,保存好用户任务的几个寄存器,其它寄存器系统会自动保存,然后取出 SWI号。
SoftwareInterrupt
LDR SP, StackSvc  重新设置堆栈指针
STMFD SP!, {R0-R3, R12, LR}  //为什么只保存这几个寄存器,见上面的解释
MOV R1, SP  ; R1指向参数存储位置
 
MRS R3, SPSR  //保存管理模式的状态寄存器
TST R3, #T_bit  中断前是否是 Thumb状态
LDRNEH R0, [LR,#-2]  取得 Thumb状态 SWI
BICNE R0, R0, #0xff00
LDREQ R0, [LR,#-4]  取得 arm状态 SWI
BICEQ R0, R0, #0xFF000000
; r0 = SWI号, R1指向参数存储位置
CMP R0, #1
LDRLO PC, =OSIntCtxSw
LDREQ PC, =__OSStartHighRdy  ; SWI 0x01为第一次任务切换
 
BL SWI_Exception
 
LDMFD SP!, {R0-R3, R12, PC}^
 
StackSvc DCD (SvcStackSpace + SVC_STACK_LEGTH * 4 - 4)
 
OSIntCtxSw
;下面为保存任务环境
LDR R2, [SP, #20]  ;获取 PC //其实他就是管理模式下的 LR寄存器的值,也就是用户任务的 PC值,为什么是 SP+20,因为该栈是满栈递减,保存了 R0-R3, R12, LR,所以 LR的值为 [SP+#20]
LDR R12, [SP, #16]  ;获取 R12
MRS R0, CPSR  //用通用寄存器 R0保存该管理模式下的 CPSR
 
MSR CPSR_c, #(NoInt | SYS32Mode) //切换到系统模式
MOV R1, LR  //把用户的 LR保存在通用寄存器 R1
STMFD SP!, {R1-R2}  ;保存 LR,PC //把系统模式的 LR,PC压入用户任务的栈中
STMFD SP!, {R4-R12}  ;保存 R4-R12 //把系统模式的 R4-R12压入用户栈中
 
MSR CPSR_c, R0  //重新回到管理模式
LDMFD SP!, {R4-R7}  ;获取 R0-R3 //实际上把用户的R0~R3放到管理模式下的R4-R7
ADD SP, SP, #8  ;出栈 R12,PC //这两个已经保存了,所以SP要往上8个字节
 
MSR CPSR_c, #(NoInt | SYS32Mode //系统模式
STMFD SP!, {R4-R7}  ;保存 R0-R3//因为管理模式的R4-R11和系统模式的R4-R11是一样的,保存在用户任务的栈中
LDR R1, =OsEnterSum  ;获取 OsEnterSum
LDR R2, [R1]
STMFD SP!, {R2, R3}  ;保存 CPSR,OsEnterSum
 
;保存当前任务堆栈指针到当前任务的 TCB
LDR R1, =OSTCBCur
LDR R1, [R1]
STR SP, [R1]
 
BL OSTaskSwHook  ;调用钩子函数
;OSPrioCur <= OSPrioHighRdy
LDR R4, =OSPrioCur
LDR R5, =OSPrioHighRdy
LDRB R6, [R5]
STRB R6, [R4]   ;r4内为最高任务的优先级
;OSTCBCur <= OSTCBHighRdy
LDR R6, =OSTCBHighRdy
LDR R6, [R6]
LDR R4, =OSTCBCur 
STR R6, [R4] ;ostcbcur指向将要运行的任务
OSIntCtxSw_1
;获取新任务堆栈指针
LDR R4, [R6]
ADD SP, R4, #68  ;先调整堆栈 因为等会从管理模式下直接恢复到系统模式下开始
                 运行任务,无法修改指针了。 
LDR LR, [SP, #-8]
MSR CPSR_c, #(NoInt | SVC32Mode)  ;进入管理模式
MOV SP, R4  ;设置堆栈指针(是没修改过的指针,即保存了上下文的指针)
 
LDMFD SP!, {R4, R5}  ;CPSR,OsEnterSum
;恢复新任务的 OsEnterSum
LDR R3, =OsEnterSum
STR R4, [R3]
 
MSR SPSR_cxsf, R5  ;恢复 CPSR
LDMFD SP!, {R0-R12, LR, PC }^  ;运行新任务
 
 
__OSStartHighRdy
MSR CPSR_c, #(NoInt | SYS32Mode)
;告诉 uC/OS-II自身已经运行
LDR R4, =OSRunning
MOV R5, #1
STRB R5, [R4]
 
BL OSTaskSwHook  ;调用钩子函数
 
LDR R6, =OSTCBHighRdy
LDR R6, [R6]
B OSIntCtxSw_1
 
AREA SWIStacks, DATA, NOINIT,ALIGN=2
SvcStackSpace SPACE SVC_STACK_LEGTH * 4  ;管理模式堆栈空间
 
END

你可能感兴趣的:(分析,ucos,osintctxsw)