📄 serlasm.s
字号:
; Reset the SVC Stack Pointer (if the new task is an SVC task, ; the correct sp will be set later) LDR sp, =Angel_StackBase LDR sp, [sp] ADD sp, sp, #Angel_SVCStackOffset angel_StartTask_NonSVCEntry ; Put CPSR, r8-r12, r14, (SPSR), r0, r1, PC on the Appl stack ; Note that SPSR is only VALID if moving to non USR mode LDR r1, [r0, #Angel_RegBlock_R0offset + (13*4)] ; Appl sp LDR r2, [r0, #Angel_RegBlock_CPSRoffset] ADD r0, r0, #Angel_RegBlock_R0offset + (8*4) LDMIA r0, {r3,r4,r5,r6,r7} ; r8-r12 go in r3-r7 SUB r0, r0, #Angel_RegBlock_R0offset + (8*4) LDR r8, [r0, #Angel_RegBlock_R0offset + (14*4)] LDR r9, [r0, #Angel_RegBlock_SPSRoffset] LDR r10, [r0, #Angel_RegBlock_R0offset] LDR r11, [r0, #Angel_RegBlock_R0offset + (1*4)] LDR r12, [r0, #Angel_RegBlock_R0offset + (15*4)] STMFD r1!, {r2-r12} ; Restore r2-r7 from regblock ADD r0, r0, #Angel_RegBlock_R0offset + (2*4) LDMFD r0, {r2-r7} ; Get r2-r7 from regblock ; Now we have lost the ptr to regblock, but still have stuff ; on the Appl stack. LDMFD r1, {r0} ; Get CPSR from Application stack IF :DEF: THUMB_SUPPORT :LAND: THUMB_SUPPORT<>0 BIC r0, r0, #Tbit ; Ensure T bit is never set here! ENDIF ; If we need to start a USR mode task, we cannot disable interrupts ; to set up USR sp safely, as we won't be able to reenable interrupts ; later. ; Instead we must set up USR sp now, before switching to USR mode. AND r14, r0, #ModeMask CMP r14, #USRmode BNE ProtectAndChangeMode MOV r14, r1 STMFD r1!, {r14} ; save USR sp LDMFD r1, {sp}^ ; get USR sp ADD r1, r1, #4 ; reset r1 B ChangeMode ProtectAndChangeMode ; We are in a privileged mode. ; Disable interrupts until the last minute to give us a chance ; to set up the stack pointer safely for our new task IF (FIQ_SAFETYLEVEL >= FIQ_NeverUsesSerialiser_DoesNotReschedule) ORR r0, r0, #IRQDisable ELSE ORR r0, r0, #IRQDisable + FIQDisable ENDIF ChangeMode ; Change mode ; Also set up Appl sp and r8-12, r14 MSR CPSR_cxsf, r0 NOP MOV sp, r1 ; already done if USR mode, but that's okay LDMFD sp!, {r0} ; Get CPSR from Application stack LDMFD sp!, {r8-r12,r14} ; restore r8-r12 + r14 ; Decide whether to restore SPSR (not in USR / SYS mode) ; But don't forget this corrupts the flag bits in CPSR! AND r1, r0, #ModeMask CMP r1, #USRmode CMPNE r1, #SYSmode ADDEQ sp, sp, #4 ; If USR or SYS skip over SPSR on stack LDMNEFD sp!, {r1} ; Do next (NE) instrs only if not SYS or USR MSRNE SPSR_cxsf, r1 IF :DEF: THUMB_SUPPORT :LAND: THUMB_SUPPORT<>0 TST r0, #Tbit BEQ ResumeARM BIC r0, r0, #Tbit MSR CPSR_cxsf, r0 ; Restore flags & IF bits corrupted since mode change ADR r0, NextInstructionLabel+1 BX r0 ; Switch into Thumb state !NextInstructionLabel CODE16 NOP POP {r0, r1, pc} ; And the application executes in Thumb state ! CODE32 ALIGN ENDIFResumeARM AND r1, r0, #ModeMask CMP r1, #USRmode BEQ UserResumeARM CMP r1, #SYSmode BEQ UserResumeARM ; Privileged Mode resume - we must not enable interrupts until ; the very last instruction! MSR SPSR_cxsf, r0 ADD sp, sp, #(3 * 4) LDMDB sp, {r0, r1, pc}^ ; and the task resumes ... UserResumeARM MSR CPSR_cxsf, r0 ; Restore the flags & IF bits corrupted above NOP LDMFD sp!, {r0, r1, pc} ; And the task executes! ; **************************************************************** EXPORT Angel_Yield IMPORT Angel_YieldCore ; For the interface details of this pseudo function refer to ; serlock.h ; Note that this an APCS conformant fn from the callers point ; of view, so we (only) have to preserve r4-r11, r13 and the ; mode we were called in.Angel_Yield ; See what mode we are in and get into SVC and disable interrupts MRS r0, CPSR AND r0, r0, #ModeMask CMP r0, #USRmode BNE NotEnteredInUSR STMFD sp!, {r0, r14} ; Save the original CPSR and r14 BL Angel_EnterSVC ; This keeps the stacks the same LDMFD sp!, {r0, r14} B InSVCInterruptsDisabledNotEnteredInUSR CMP r0, #SVCmode BEQ YieldInUsrOrSvcMode ; Not USR or SVC - Oh dear!!! ADR a1, serlusrsvcmsg B __rt_asm_fatalerrorserlusrsvcmsg DCB "Yield not USR or SVC mode\n" ALIGNYieldInUsrOrSvcMode IF (FIQ_SAFETYLEVEL >= FIQ_NeverUsesSerialiser_DoesNotReschedule) ORR r1, r0, #IRQDisable ELSE ORR r1, r0, #IRQDisable + FIQDisable ENDIF MSR cpsr_cxsf, r1 ; Now in SVC with interrupts disabled, r0 = original CPSRInSVCInterruptsDisabled ; Save the caller's regs into our shared regblock ; We only have to save r4-r11, r13, cpsr, pc (says the APCS) LDR r1, =Angel_MutexSharedTempRegBlocks STR r0, [r1, #Angel_RegBlock_CPSRoffset] ; cpsr STR r13, [r1, #Angel_RegBlock_R0offset + (13*4)] ; sp STR r14, [r1, #Angel_RegBlock_R0offset + (15*4)] ; pc ADD r1, r1, #Angel_RegBlock_R0offset + (4*4) STMIA r1, {r4-r11} SUB r0, r1, #Angel_RegBlock_R0offset + (4*4) ; Now prepare to call Angel_SerialiseTask ; r0 = called_by_yield ; r1 = fn ; r2 = state ; r3 = empty_stack MOV r0, #1 LDR r1, =Angel_YieldCore MOV r2, #0 LDR r3, =Angel_StackBase ; Empty SVC Stack LDR r3, [r3] ADD r3, r3, #Angel_SVCStackOffset B Angel_SerialiseTask ; and Angel_YieldCore will execute when SerialiseTask allows it to ; **************************************************************** IMPORT angel_SelectNextTask EXPORT angel_NextTask angel_NextTask ; This can be "called" from SVC or USR. It must get into SVC and ; disable interrupts and grab the empty SVC stack. ; Then it must call angel_SelectNextTask with no arguments. ; ; See what mode we are in and get into SVC and disable interrupts MRS r0, CPSR AND r0, r0, #ModeMask CMP r0, #USRmode BNE NotEnteredInUSR2 BL Angel_EnterSVC ; This keeps the stacks the same B InSVCInterruptsDisabled2NotEnteredInUSR2 CMP r0, #SVCmode BEQ NextTaskUsrOrSvcMode ; Not USR or SVC - Oh dear!!! ADR a1, serlusrsvcmsg B __rt_asm_fatalerrorntusrsvcmsg DCB "NextTask not USR or SVC mode\n" ALIGN NextTaskUsrOrSvcMode IF (FIQ_SAFETYLEVEL >= FIQ_NeverUsesSerialiser_DoesNotReschedule) ORR r1, r0, #IRQDisable ELSE ORR r1, r0, #IRQDisable + FIQDisable ENDIF MSR cpsr_cxsf, r1 ; Now in SVC with interrupts disabledInSVCInterruptsDisabled2 ; Grab an empty SVC stack and call angel_SelectNextTask LDR sl, =Angel_StackBase LDR sl, [sl] ADD sp, sl, #Angel_SVCStackOffset ADD sl, sl, #Angel_SVCStackLimitOffset LDR r0, =angel_SelectNextTask MOV pc, r0 ; **************************************************************** EXPORT angel_IdleLoopangel_IdleLoop ; Reset the SVC stack LDR sp, =Angel_StackBase LDR sp, [sp] ADD sp, sp, #Angel_SVCStackOffset ; Reenable interrupts MRS r0, CPSR BIC r0, r0, #IRQDisable + FIQDisable MSR CPSR_cxsf, r0 ; Repeatedly call Angel_YieldIdleLoop BL Angel_Yield B IdleLoop ENDIF ; ... else not minimal angel ... END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -