📄 kern600.s
字号:
; ; out: Thread context restored. This will either be the ; processor state at the instance of the interrupt, or a ; previously stored interrupted or de-scheduled thread ; context. ; ; This implementation does not perform any interrupt source ; masking before calling ISRs, resulting in IRQs being ; disabled for the WHOLE of the IRQ and ISR handler ; execution. If IRQs were to be enabled before the source has ; been cleared then this system would get stuck in an infinite ; loop. ; SUB lr,lr,#4 ; modify to form true return address ; The registers we *HAVE* to save as those that are not ; preserved as part of the APCS-3 calling sequence: STMFD sp!,{a1,a2,a3,a4,fp,ip,lr} ; preserve work registers ; If we change this code to allow re-entrant interrupts ; (i.e. we mask the source before calling the ISR with IRQs ; enabled), we would also *NEED* to save the SPSR register ; before enabling IRQs. At the moment this code simply ; executes ISRs with IRQs disabled. ; MOV fp,#0x00000000 ; empty call-frame pointer BL OSIntEnter ; keep track of active interrupt handlers ; getIRQsource a1,a2 ; architecture specific IRQ status load TEQ a1,#0x00000000 ; check that we have at least one bit BEQ IgnoreIRQ ; if zero we do not know the source ; decodeIRQ a1,a2,a3 ; get a vector number for the sources ; a1 = bit number of the highest priority pending ; interrupt. NOTE: There is no check at the moment that the ; bit number describes a slot in the IRQvectors table. It is ; assumed that the NUMIRQS manifest within the architecture ; description file is one greated than the maximum bit ; position ever returned by the decodeIRQ macro. The check for ; this SHOULD be in the target description header file. ; LDR a2,=IRQvectors ; reference the IRQ handler table MOV lr,pc ; assumes next instruction is PC load LDR pc,[a2,a1,LSL #2] ; vector through handler table ; We return here after the ISR has completed. ; BL OSIntExit ; check if we need to re-schedule TEQ a1,#0 ; if !FALSE we need to perform a context switch LDMEQFD sp!,{a1,a2,a3,a4,fp,ip,pc}^ ; else return to caller, restoring PSR state ; ; We have our own special version of the SAVECONTEXT code ; here, since we need to de-stack the description of the ; interrupted task, and ensure that the saved context ; describes the interrupted stack and *NOT* this interrupt ; handler thread. ; ; The SPSR register describes the processor mode of the ; interrupted thread. NOTE: If the interrupted thread was in ; the same mode as this interrupt handler is executing then we ; will have lost some information (since the vector entry ; overwrites the lr and SPSR values). Unless there has been ; special code to cope with this, then it is more than likely ; that such an occurrence will have corrupted the system. ; ; We have a1,a2,a3,a4,fp,ip and lr available as work registers. ; MRS a1,SPSR ; get interrupted thread description ANDS a2,a1,#SubModeMask ; get the mode information BEQ interruptedUSR ; simpler code required for USR tasks ; ; We now know that we were executing in a priviledged mode: TEQ a2,#(FIQmode :AND: SubModeMask) ; check for FIQ mode BEQ interruptedFIQ ; special code to save more banked registers ; ; We now know that we are executing in a normal priviledged mode: SUB sp,sp,#(3 * 4) ; we will store 3 words of information MOV a3,sp ; take a copy of the IRQ stack pointer MRS a4,CPSR ; get our current PSR state ORR a2,a1,#IRQint ; set IRQ disable flag MSR CPSR,a2 ; switch to interrupted mode (ensuring IRQs stay disabled) ; MRS a2,SPSR ; get a copy of the SPSR for this mode STMIA a3,{a2,sp,lr} ; stack the banked registers ; MSR CPSR,a4 ; and return to the interrupt handler state ; ; We now have on the IRQ stack the banked registers for the ; mode of the interrupted task. ; LDMFD sp!,{a2,a3,a4} ; a1 = CPSR of interrupted thread ; a2 = SPSR of interrupted thread ; a3 = stack-pointer of interrupted thread ; a4 = link-register of interrupted thread ; SUB lr,a3,#Ctx_sizeof ; context save area for the task STR a4,[lr,#Ctx_lr] ; link-register ADD a4,lr,#Ctx_CPSR ; reference the PSR fields STMIA a4,{a1,a2} ; preserve the CPSR and SPSR for the task LDMFD sp!,{a1,a2,a3,a4,fp,ip} STMIA lr,{a1-ip} ; preserve most of the register state MOV v1,lr ; keep a copy of the context pointer LDMFD sp!,{lr} ; recover the interrupted task program counter STR lr,[v1,#Ctx_pc] ; preserve the program counter ADD a4,v1,#Ctx_USR_sp ; reference the banked USR fields STMIA a4,{sp,lr}^ ; store the banked USR registers B referenceCtx ; and ensure we reference the saved contextinterruptedFIQ ; We reach this point if the interrupted task was executing in ; FIQ mode. Such tasks have their own context save due to the ; extra banked registers. ; SUB sp,sp,#(8 * 4) ; we will store 8 words of information MOV a3,sp ; take a copy of the IRQ stack pointer MRS a4,CPSR ; get our current PSR state ORR a2,a1,#IRQint ; set IRQ disable flag MSR CPSR,a2 ; switch to FIQ mode (ensuring IRQs stay disabled) ; MRS a2,SPSR ; get a copy of the SPSR for this mode STMIA a3,{a2,v5-lr} ; stack the banked registers ; MSR CPSR,a4 ; and return to the interrupt handler state ; ; We now have on the IRQ stack the FIQ banked registers. ; The following is NASTY since we are peeking into the stack ; to load the FIQ stack-pointer: LDR lr,[sp,#(6 * 4)] ; load the FIQ stack-pointer SUB lr,lr,#Ctx_sizeof ; context save area for the task LDMFD sp!,{a2,a4,fp,ip} ; load some FIQ registers ADD a3,lr,#Ctx_CPSR ; reference the PSR fields STMIA a3,{a1,a2} ; store the CPSR and SPSR ADD a3,lr,#Ctx_v5 ; reference fields in context STMIA a3!,{a4,fp,ip} ; stack v5,v6 and sl LDMFD sp!,{a1,a2,a4,fp} ; load fp, ip, sp and lr STMIA a3,{a1,a2,a4,fp} ; and store into the context LDMFD sp!,{a1,a2,a3,a4,fp,ip} STMIA lr,{a1-v4} ; store rest of FIQ registers MOV v1,lr ; keep a copy of the context pointer LDMFD sp!,{lr} ; recover the interrupted task program counter STR lr,[v1,#Ctx_pc] ; preserve the program counter ADD a4,v1,#Ctx_USR_v5 ; reference the banked USR fields STMIA a4,{v5-lr}^ ; store the banked USR registers B referenceCtx ; and ensure we reference the saved contextinterruptedUSR ; we reach here when de-scheduling a USR task SUB sp,sp,#4 ; create a temporary holder on our stack STMIA sp,{sp}^ ; and force a USR transfer LDMFD sp!,{lr} ; we now have a pointer into the USR stack SUB lr,lr,#Ctx_sizeof ; make space for the context state [ {FALSE} ; this is not actually required, since the stack pointer is implicit in the context pointer STMFD sp!,{lr} ; push back onto our local stack LDMIA sp,{sp}^ ; and ensure the USR stack pointer is updated ] STR a1,[lr,#Ctx_CPSR] ; store IRQ SPSR into CPSR for task ADD a1,lr,#Ctx_v1 ; reference the variable registers STMIA a1,{v1-sl}^ ; force USR banked register save MOV v1,lr ; move the context state pointer LDMFD sp!,{a1,a2,a3,a4,fp,ip,lr} ; recover preserved interrupt state STMIA v1,{a1,a2,a3,a4} ; store argument registers ADD a1,v1,#Ctx_fp STMIA a1,{fp,ip,sp,lr}^ ; store more USR banked registers STR lr,[v1,#Ctx_pc] ; return address when re-starting taskreferenceCtx ; We reach this point when we have stored the complete ; processor register state required. LDR a2,=OSTCBCur ; reference the current TCB holder LDR a2,[a2,#0x00] ; get pointer to context pointer save location STR v1,[a2,#0x00] ; save context pointer for task ; ; We have now saved the processor state at the instance of the ; interrupt, and we know we are in a priviledged mode: STARTNEXTTASK ; startup the highest priority taskIgnoreIRQ ; This point is reached if we did not find a source or a ; handler routine for the interrupt. This is normally fatal ; since it means that the source has probably not been ; cleared, and we are about to re-enter the IRQ handler. LDMFD sp!,{a1,a2,pc}^ ; return to caller, restoring PSR state ; --------------------------------------------------------------------- ; These are simple (do nothing) routines that is attached by ; default to the IRQvectors and FIQvectors. They conform to ; the following prototype: ; IRQHandlerFn DummyIRQ ; ; FIQHandlerFn DummyFIQ ;DummyIRQDummyFIQ MOV pc,lr ; --------------------------------------------------------------------- ; -- Context manipulation --------------------------------------------- ; --------------------------------------------------------------------- ; void OSStartHighRdy(void) ; ; ; Start the task with the highest priority:OSStartHighRdy ; NOTE: The "ucos.c" OSStart routine expects this code to also ; enable interrupts. STARTNEXTTASK ; startup the highest priority task ; --------------------------------------------------------------------- ; void OSCtxSw(void) ; ; ; Perform a context switch from the current task, to the ; highest priority pending task. ; ; If a MMU is available and non-direct physical-to-logical ; mapping is being used then we need to flush the cache (and ; possibly the TLB) as part of the context switch to avoid ; address aliasing. At the moment the ARM600 C-Demon does not ; provide non-direct memory mapping.OSCtxSw ; We first create a context on the stack of the current task, ; and then switch to the pending task: SAVECONTEXT ; save current context onto stack STARTNEXTTASK ; startup the highest priority task ; --------------------------------------------------------------------- ; void *InitTask(void *stack,void *data,PTV task) ; ; ; This routine constructs a starting thread context on the ; given stack, returning the new stack pointer. The code ; assumes that *ALL* threads start in USR mode. Even though ; this is a new task being created, it is made to look like a ; context switched task so that the standard routines can be used.InitTask SUB a1,a1,#Ctx_sizeof ; allocate memory on the new stack for the context STR a2,[a1,#Ctx_a1] ; argument for the new task STR a3,[a1,#Ctx_pc] ; starting address for new task MOV a2,#USRmode ; with IRQs and FIQs enabled STR a2,[a1,#Ctx_CPSR] ; and this will be the starting PSR MOV a2,#0x00000000 STR a2,[a1,#Ctx_fp] ; ensure an empty call-frame ; We do not care what the majority of the new tasks registers ; look like, as long as the starting state is a valid APCS-3 ; one. NOTE: This code does *NOT* initialise the stack ; pointer, since that is implicitly derived from the address ; of the stored context (i.e. plus Ctx_sizeof). MOV pc,lr ; return to caller ; --------------------------------------------------------------------- END ; EOF kern600.s
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -