调用高优先级就绪任务启动函数OSStartHighRdy。OSStartHighRdy函数与选择的微处理器相关,也就是与移植相关,实际上,函数OSStartHighRdy是将任务栈中保存的值弹回到CPU寄存器中,然后执行一条中断返回指令,中断返回指令强制执行该任务代码,该函数永远不会返回到OSStart 软中断: 中断不返回形式:void _swi(swi_num) swi_name(arguments) 返回一个结果到R0中 int _swi(swi_num) swi_name(arguments); 最多可以返回四个结果R0-R3到一个结构 struct type{ int a,b,c,d}中 type(返回类型) _value_in_regs(返回多个结果的修饰符) _swi(swi_num) swi_name(arguments); 比如在程序运行到调用OS_TASK_SW(void)函数时,就产生软件中断,然后就进入中断服务子程序,按照什么指令走呢?恩,就按照下面这个代码,这个代码是将软件中断异常处理程序挂接到内核的作用的,是在启动代码中实现的: LDR PC,SWI_Addr
SWI_Addr DCD SoftwareInterrupt 因此当产生软中断之后PC就跳到了SoftwareInterrupt,这时就算真正进入了软件异常中断处理部分了,然后就是执行下面的汇编代码 SoftwareInterrupt
LDR SP, StackSvc ; 重新设置堆栈指针
STMFD SP!, {R0-R3, R12, LR}
MOV R1, SP ; R1指向参数存储位置 MRS R3, SPSR
TST R3, #T_bit ; 中断前是否是Thumb状态,判断SPSR的T位是不是为零 LDRNEH R0, [LR,#-2] ; 不为零即THUMB指令集: 取得Thumb状态SWI号
BICNE R0, R0, #0xff00 ;在THUMB指令集中软中断功能号为8位,所以取低八位即为功能号
LDREQ R0, [LR,#-4] ; 为零即ARM指令集: 取得arm状态SWI号
BICEQ R0, R0, #0xFF000000 ;在ARM指令集中软中断功能号为24位,所以取低6位即为功能号
; r0 = SWI号,R1指向参数存储位置
CMP R0, #1
LDRLO PC, =OSIntCtxSw ;功能号为0到OSIntCtxSw执行中断任务切换函数
LDREQ PC, =__OSStartHighRdy ; SWI 0x01为第一次任务切换 BL SWI_Exception ;否则进入c编写的中断服务函数
LDMFD SP!, {R0-R3, R12, PC}^
StackSvc DCD (SvcStackSpace + SVC_STACK_LEGTH * 4 - 4) 怎么进入c编写的中断服务子程序SWI_Exception呢?通过下面的申明 IMPORT SWI_Exception ;软中断异常处理程序,表示将c程序中的该函数挂接到此段汇编代码中 同样的道理 EXPORT __OSStartHighRdy
EXPORT OSIntCtxSw ;中断退出时的入口,参见startup.s中的IRQ_Handler EXPORT SoftwareInterrupt ;软中断入口 上面的申明是将该段汇编代码挂接到外面,因此在外部可以直接调用函数名
继续看OS_CPU_A.S的其他部分代码,就是两个软件异常中断处理函数OSIntCtxSw和OSStarHighRdy OSIntCtxSw代码是中断服务子程序使得更高优先级的任务进入就绪状态后,中断返回后需要切换到该任务时调用的,这是被切换的任务的CPU寄存器的值已经在响应中断后存入了堆栈中,因此,这里不需要重复保存了直接切换任务即可,具体过程看代码 OSIntCtxSw
;下面为保存任务环境 ;当响应软件异常中断后进入了系统模式,在上面的代码中我们可以看到,进入系统模式时保存的堆栈结构从顶到底依次是:R0,R1,R2,R3,R12,LR,而在用户模式中任务的堆栈结构应该是:OsEnterSum,CPSR,RO-12,LR,PC,所以在进行软件中断任务切换之前先要保存原来任务的堆栈结构。
LDR R2, [SP, #20] ;获取PC
LDR R12, [SP, #16] ;获取R12
MRS R0, CPSR MSR CPSR_c, #(NoInt | SYS32Mode)
MOV R1, LR
STMFD SP!, {R1-R2} ;保存LR,PC
STMFD SP!, {R4-R12} ;保存R4-R12 MSR CPSR_c, R0
LDMFD SP!, {R4-R7} ;获取R0-R3
ADD SP, SP, #8 ;出栈R12,PC
MSR CPSR_c, #(NoInt | SYS32Mode)
STMFD SP!, {R4-R7} ;保存R0-R3
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]
;OSTCBCur <= OSTCBHighRdy
LDR R6, =OSTCBHighRdy
LDR R6, [R6]
LDR R4, =OSTCBCur
STR R6, [R4]
OSIntCtxSw_1
;获取新任务堆栈指针
LDR R4, [R6]
ADD SP, R4, #68 ;17寄存器CPSR,OsEnterSum,R0-R12,LR,SP
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 }^ ;运行新任务
-------------------------------------------------------------------------------- -------------------------------------------------------------------------------- |