📄 os_cpu_a.s
字号:
;-+---+---++-+--+-++-+++--++--+++
;* File: os_cpu_a.s
;* (c) Copyright ARM Limited 1999. All rights reserved.
;* ARM Specific code
; Functions defined in this module:
;
; void ARMDisableInt(void) /* disable interrupts when in SVC */
; void ARMEnableInt(void) /* enable interrupts when in SVC */
; void OSStartHighRdy(void) /* start highest priority task */
; OS_TASK_SW /* Context Switch*/
; ARMDisableINT & ARMEnableINT
; OSIntCtxSw
AREA OS_CPU_A, CODE, READONLY
; External symbols we need the addresses of
IMPORT OSTCBCur
addr_OSTCBCur DCD OSTCBCur
IMPORT OSTCBHighRdy
addr_OSTCBHighRdy DCD OSTCBHighRdy
IMPORT OSPrioCur
addr_OSPrioCur DCD OSPrioCur
IMPORT OSPrioHighRdy
addr_OSPrioHighRdy DCD OSPrioHighRdy
;-+---+---++-+--+-++-+++--++--+++
EXPORT OSStartHighRdy
;示例
;SP=OSTCBHighRdy->OSTCBStkPtr
;OSTCBCur=OSTCBHighRdy
;弹出现场
OSStartHighRdy
LDR r4, addr_OSTCBCur ; Get current task TCB address
LDR r5, addr_OSTCBHighRdy ; Get highest priority task TCB address
LDR r5, [r5] ; get stack pointer
LDR sp, [r5] ; switch to the new stack
;SP=OSTCBHighRdy->OSTCBStkPtr
STR r5, [r4] ; set new current task TCB address
;OSTCBCur=OSTCBHighRdy
LDMFD sp!, {r4} ; YYY
MSR CPSR_cxsf, r4
LDMFD sp!, {r4} ; get new state from top of the stack
MSR CPSR_cxsf, r4 ; CPSR should be SYS32Mode
LDMFD sp!, {r0-r12, lr, pc } ; start the new task
;-+---+---++-+--+-++-+++--++--+++
EXPORT OS_TASK_SW
;示例
;现场压栈
;OSPrioCur = OSPrioHighRdy
;OSTCBCur->OSTCBStkPtr=SP 保存SP到当前任务控制块
;SP=OSTCBHighRdy->OSTCBStkPtr
;OSTCBCur=OSTCBHighRdy
;弹出现场
OS_TASK_SW
STMFD sp!, {lr} ; save pc
STMFD sp!, {lr} ; save lr
;分析:OS_TASK_SW是个函数,在任务间接的调用它时会在最后失去CPU,再次
;获得CPU时,其恰好在OS_TASK_SW调用完毕后的那个位置,因此,lr被放入pc
;在栈中的位置;此外,lr放入lr在栈中的位置也是无关紧要的,因为,子函数
;返回时的lr是无意义的。
STMFD sp!, {r0-r12} ; save register file and ret address
MRS r4, CPSR
STMFD sp!, {r4} ; save current PSR
;MRS r4, SPSR ; YYY+ 这里屏蔽掉是因为任务运行的
;模式是SYS,没有SPSR,栈中的CPSR与SPSR相同
STMFD sp!, {r4} ; YYY+ save SPSR
LDR r4, addr_OSPrioCur
LDR r5, addr_OSPrioHighRdy
LDRB r6, [r5]
STRB r6, [r4]
; OSPrioCur = OSPrioHighRdy
; Get current task TCB address
LDR r4, addr_OSTCBCur
LDR r5, [r4]
STR sp, [r5] ; store sp in preempted tasks's TCB
;OSTCBCur->OSTCBStkPtr=SP 保存SP到当前任务控制块
; Get highest priority task TCB address
LDR r6, addr_OSTCBHighRdy
LDR r6, [r6]
LDR sp, [r6] ; get new task's stack pointer
;SP=OSTCBHighRdy->OSTCBStkPtr 更新SP为即将运行的任务
STR r6, [r4] ; set new current task TCB address
; OSTCBCur = OSTCBHighRdy
LDMFD sp!, {r4} ; YYY+
;MSR SPSR_cxsf, r4 ; YYY+运行在sys模式下,无需SPSR的更新
LDMFD sp!, {r4} ; YYY+
MSR CPSR_cxsf, r4 ; YYY+
LDMFD sp!, {r0-r12, lr, pc} ; YYY+
;现场恢复完毕
;-+---+---++-+--+-++-+++--++--+++
EXPORT ARMDisableInt
ARMDisableInt
STMFD sp!, {r0}
MRS r0, CPSR
ORR r0, r0, #0x80
MSR CPSR_c, r0
LDMFD sp!, {r0}
MOV pc, lr
EXPORT ARMEnableInt
ARMEnableInt
STMFD sp!, {r0}
MRS r0, CPSR
BIC r0, r0, #0x80
MSR CPSR_c, r0
LDMFD sp!, {r0}
MOV pc, lr
;-+---+---++-+--+-++-+++--++--+++
IMPORT IRQ_STACK
EXPORT OSIntCtxSw
OSIntCtxSw
;新的代码,实现了中断的嵌套
;该函数被OSIntExit调用,OSIntExit在ISR_IrqHandler中被
;调用(而不是以前在安装后的向量中,这是为了简化堆栈处理)
;该函数运行依赖于调用ISR_IrqHandler之前的模式转换和栈构造
;运行于SYS模式,其首先调整SP_sys指针到下图中SPSR处
;后半部分与OSCtxSw相同
;
;该函数是不返回的,进入时堆栈结构是已知的,除了原来的构造的
;标准栈,还压入了r4 r14(可以参看编译后的汇编代码)
;irq的栈结构,进入OSIntExit()时,sp指向的恰好是标准栈顶,但是,由于
;函数中又调用了函数,起始第一句便是一个stmfd sp!,{r4,r14},于是进入
;OSIntCtxSw后还得我们来调整
;-+---+---++-+--+-++-+++--++--+++-+---+---++-+--+-++-+++--++--+++
;低 r4 r14 spsr cpsr r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 lr PC 高
;-+---+---++-+--+-++-+++--++--+++-+---+---++-+--+-++-+++--++--+++
ldmfd sp!,{r0,r1} ;我们的sp_sys已经指向标准栈结构
;后面的内容和OSCtxSw的后半部分相同,依次为
;OSPrioCur = OSPrioHighRdy
;OSTCBCur->OSTCBStkPtr=SP 保存SP到当前任务控制块
;SP=OSTCBHighRdy->OSTCBStkPtr
;OSTCBCur=OSTCBHighRdy
;弹出现场
LDR r4, addr_OSPrioCur
LDR r5, addr_OSPrioHighRdy
LDRB r6, [r5]
STRB r6, [r4]
; OSPrioCur = OSPrioHighRdy
; Get current task TCB address
LDR r4, addr_OSTCBCur
LDR r5, [r4]
STR sp, [r5] ; store sp in preempted tasks's TCB
;OSTCBCur->OSTCBStkPtr=SP 保存SP到当前任务控制块
; Get highest priority task TCB address
LDR r6, addr_OSTCBHighRdy
LDR r6, [r6]
LDR sp, [r6] ; get new task's stack pointer
;SP=OSTCBHighRdy->OSTCBStkPtr 更新SP为即将运行的任务
STR r6, [r4] ; set new current task TCB address
; OSTCBCur = OSTCBHighRdy
LDMFD sp!, {r4} ; YYY+
;MSR SPSR_cxsf, r4 ; YYY+运行在sys模式下,无需SPSR的更新
LDMFD sp!, {r4} ; YYY+
MSR CPSR_cxsf, r4 ; YYY+
LDMFD sp!, {r0-r12, lr, pc} ; YYY+
;现场恢复完毕
END
;-+---+---++-+--+-++-+++--++--+++
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -