Nucleus源代码分析 - Task(2)
来源:互联网 发布:js储存key和value 编辑:程序博客网 时间:2024/05/08 18:50
Nucleus Task的中断与恢复
以下是以TI的源代码进行的分析
一般来说最有可能中断Task的就是irq中断了。在ARM下到有中断发生时,ARM会自动切换到IRQ模式,此时ARM的寄存器已经是IRQ模式下的寄存器了。
- INT_IRQ
- STMDB sp!,{r0-r5} ; Save a1-a4 on temporary IRQ stack
- MRS a1,spsr ; check for the IRQ bug:
- TST a1,#080h ; if the I - flag is set,
- BNE IRQBUG ; then postpone execution of this IRQ
- SUB r4,lr,#4 ; Save IRQ's lr (return address)
- <strong>注意r4的内容lr-4(被中断的PC,-4是因为ARM放入的是下一条指令+4)</strong>
- BL _TCT_Interrupt_Context_Save ; Call context save routine
- BL _IQ_IRQ_isr ; Call int. service routine
- B _TCT_Interrupt_Context_Restore
- ;BUG correction 2nd part ------------------
- IRQBUG: LDMFD sp!,{r0-r5} ; return from interrup. Fix for locosto reset problem. We have pushed 6 regs and popping 4.
- SUBS pc,r14,#4
- ;BUG correction 2nd part end --------------
以上就是一个irq的完整的处理过程了,我们慢慢来分析。
- ;VOID TCT_Interrupt_Context_Save(vector)
.def _TCT_Interrupt_Context_Save
_TCT_Interrupt_Context_Save
……….
LDR r1,TCT_Int_Count ; Pickup address of interrupt count
LDR r2,[r1] ; Pickup interrupt counter
ADD r2,r2,#1 ; Add 1 to interrupt counter
STR r2,[r1] ; Store new interrupt counter value
CMP r2,#1 ; Is this first interrupt?
BNE TCT_Nested_Save ; If not first interrupt, do nested save
.if NU_FIQ_SUPPORT
; Check for a special nested case. A special nested case occurs when
; a second interrupt goes off before TCT_Int_Count is incremented.
……….
.else
B TCT_Normal_Save
.endif ; NU_FIQ_SUPPORT
TCT_Nested_Save
……
TCT_Normal_Save
; Determine if a thread was interrupted.
LDR r1,TCT_Current_Thread1 ; Pickup current thread ptr address
LDR r1,[r1] ; Pickup the current thread pointer
CMP r1,#0 ; Is it NU_NULL?
BEQ TCT_Idle_Context_Save ; If no, no real save is necessary
以下就是Task被中断时所做的操作…
TCT_Thread_Save
MOV r1,sp ; Put the exception sp into r1
MOV r2,lr ; Move the return address for the caller
; of this function into r2
MRS r3,spsr ; Put the exception spsr into r3
; Adjust the exception stack pointer for future exceptions
24是因为 STMDB sp!,{r0-r5} ?
ADD sp,sp,#24 ; sp will point to interrupt mask register(s)
; Switch CPU modes to save context on thread’s stack
这个是进行Task上下文保护的关键,切回svc模式,是因为Task的运行是在svc模式下进行的,在irq模式下要取得Task运行是ARM的各个寄存器的值然后进行保护,唯一的途径就是在切回svc模式下,只有这样才能取得.
MRS r5,CPSR ; Pickup the current CPSR
BIC r5,r5,#MODE_MASK ; Clear the mode bits
ORR r5,r5,#SUP_MODE ; Change to supervisor mode (SVC)
MSR CPSR,r5 ; Switch modes
; Store the thread’s sp into r5 so the sp can be saved as is
MOV r5,sp
; Save the exception return address on the stack (PC)
R4就是我们在irq模式下的那个放pc的r4,ARM的R0-R7寄存器是unbanked register,也就是说各个模式下都是同一个寄存器。
STMDB r5!,{r4}
; Save r6-r14 on stack
STMDB r5!,{r6-r14}
; Switch back to using sp now that the original sp has been saved.
MOV sp,r5
; Get r0-r5 off exception stack and save on thread’s stack
LDMIA r1!,{r5-r10}
STMDB sp!,{r5-r10}
此时Task运行模式时的R0-PC已经储存在了相应的堆栈上.
; Save the SPSR on the system stack (CPSR)
STMDB sp!,{r3}
; Save stack type to the task stack (1=interrupt stack)
设置中断原因,为如何恢复设置变量。
MOV r1,#1
STMDB sp!,{r1}
; Save the thread’s stack pointer in the control block.
将新的sp地址放到Task的结构中,这个在恢复时会做相应的读取。
LDR r1,TCT_Current_Thread1 ; Pickup current thread ptr address
LDR r3,[r1] ; Pickup current thread pointer
STR sp,[r3, #TC_STACK_POINTER] ; Save stack pointer
; Switch to the system stack / system stack limit
切换回svc模式下的系统堆栈,注意这个堆栈是和task的堆栈是不一样的。Task的堆栈是task创建是需指定的一个内存区域,供task函数调用用到,task在运行时会先将task的堆栈赋值给arm的sp,此时task函数调用就使用的是指定的那块内存了。而各个模式下都必须设置一个系统堆栈以作为系统使用。
LDR r1,TCT_System_Stack ; Pickup address of stack pointer
LDR r3,TCT_System_Limit1 ; Pickup address of stack limit ptr
LDR sp,[r1] ; Switch to system stack
LDR r10,[r3] ; Setup system stack limit
…..
TCT_Save_Exit
; Return to caller ISR.
BX r2
到此task的上下文保护完成。
运行对应的中断函数.
- BL _IQ_IRQ_isr ; Call int. service routine
Task的恢复。
- B _TCT_Interrupt_Context_Restore
;VOID TCT_Interrupt_Context_Restore(VOID)
.def _TCT_Interrupt_Context_Restore
_TCT_Interrupt_Context_Restore
LDR r0,TCT_Current_Thread1 ; Pickup current thread ptr address
LDR r0,[r0] ; Pickup current thread pointer
CMP r0,#0 ; Determine if a thread is active
BEQ TCT_Nested_Restore ; If not, just do a nested restore
; A thread was active during this special situation
; Switch to this thread’s stack
LDR sp,[r0,#TC_STACK_POINTER]
; Adjust the SP below the stack type
ADD sp,sp,#4
LDR r1,[sp], #4 ; Pickup the saved CPSR
MSR SPSR,r1 ; Place into saved SPSR
; Return to the point of interrupt.
将原来储存的各个寄存器恢复,task就从中断的地方继续运行了。
LDMIA sp,{r0-r15}^
- Nucleus源代码分析 - Task(2)
- Nucleus源代码分析 - Task(1)
- Nucleus event函数分析
- Nucleus timer分析
- Hadoop源代码分析(类Task)
- Nucleus 实时操作系统分析报告
- Nucleus
- Nucleus Task切换及中断之上下文保存
- JBoss 系列五十八:jBPM Human Task 源代码分析 - I
- JBoss 系列五十九:jBPM Human Task 源代码分析 - II
- Nucleus系统源码分析与学习
- Task运行过程分析2
- CASSINI源代码分析(2)
- vivi源代码分析2
- vivi源代码分析2
- KeePass源代码分析2
- TCPMP 源代码分析2
- Nuplayer源代码分析2
- Master Data Service调用API创建Model
- 便捷的php代码收藏
- Nucleus event函数分析
- 阿Q正传原文
- Nucleus timer分析
- Nucleus源代码分析 - Task(2)
- 设置ProgressBar为水平
- POJ 1125 Stockbroker Grapevine (Floyd)
- 使用微软Kinect进行手势识别操作的一个简单范例(2)(WPF-C#)
- 立体视觉
- windows程序设计(2)
- WPF学习笔记(一)
- QEvent 子类化一例
- Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析