/* *---------------------------------------------------------------------- * micro T-Kernel * * Copyright (C) 2006-2011 by Ken Sakamura. All rights reserved. * micro T-Kernel is distributed under the T-License 2.0. *---------------------------------------------------------------------- * * Version: 1.01.01 * Released by T-Engine Forum(http://www.t-engine.org) at 2011/12/12. * *---------------------------------------------------------------------- */ /* * cpu_support.S (AT91) * Device-Dependent CPU Operation */ #define _in_asm_source_ #include #include #include #include #include #include "config.h" #include "utk_config.h" #if USE_TRAP | (USE_DBGSPT & USE_HOOK_TRACE) #include "isysconf.h" #endif #include "tkdev_conf.h" #include "offset.h" #if USE_TRAP | USE_DBGSPT | USE_HOOK_TRACE #error ouch! #endif /* ------------------------------------------------------------------------ */ /* * Dispatcher * dispatch_to_schedtsk: * Throw away the current contexts and forcibly dispatch * to 'schedtsk.' * Called directly by jump (bx) but do not return. * Called on the undefined stack state (undefined 'ssp'). * Called on the interrupt disable state. * dispatch_entry: * Normal dispatch processing. * _ret_int_dispatch: * Called when dispatch is required by 'tk_ret_int().' * * Contexts to save * Save registers except for ssp(R13_svc) to a stack. Save 'ssp' to TCB. * * +---------------+ * ssp -> | R0 - R11 | * | taskmode | * | R13_usr = usp | Available only for RNG 1-3 * | R14_usr | * +---------------+ * | R14_svc | R14_svc before interrupt * | | (Available only for tk_ret_int) * +---------------+ - * | SPSR_svc | | Save by interrupt * | R12 = ip | | entry routine * | R14_svc = lr | Return address (pc) | * +---------------+ - */ .text .balign 4 .globl Csym(knl_dispatch_to_schedtsk) .globl Csym(knl_dispatch_entry) Csym(knl_dispatch_to_schedtsk): /* Interrupt is disabled(CPSR.I=1 F=1),during SVC mode */ ldr sp, =(Csym(knl_tmp_stack) + TMP_STACK_SZ) // Set temporal stack ldr ip, =Csym(knl_dispatch_disabled) ldr r0, =1 str r0, [ip] // Dispatch disable ldr r4, =Csym(knl_ctxtsk) // R4 = &ctxtsk ldr r0, =0 str r0, [r4] // ctxtsk = NULL msr cpsr_c, #PSR_SVC // Interrupt enable b l_dispatch0 Csym(knl_dispatch_entry): /* Interrupt is disabled(CPSR.I=1 F=1),during SVC mode */ stmfd sp!, {ip, lr} mrs ip, cpsr bic ip, ip, #PSR_DI stmfd sp!, {ip} stmfd sp!, {lr} // Context save (R14_svc) // The contents are invalid due to number adjustment _ret_int_dispatch: /* Interrupt is disabled(CPSR.I=1 F=1),during SVC mode */ ldr ip, =Csym(knl_dispatch_disabled) ldr lr, =1 str lr, [ip] // Dispatch disable msr cpsr_c, #PSR_SVC // Interrupt enable ldr ip, =Csym(knl_taskmode) ldr ip, [ip] sub sp, sp, #15*4 stmia sp, {r0-r11, ip, sp, lr}^ // Context save ldr r4, =Csym(knl_ctxtsk) // R4 = &ctxtsk ldr r0, =0 ldr r8, [r4] str sp, [r8, #TCB_tskctxb + CTXB_ssp] // Save 'ssp' to TCB str r0, [r4] // ctxtsk = NULL l_dispatch0: /* During interrupt enable CPSR.I=0 F=0 */ ldr r5, =Csym(knl_schedtsk) // R5 = &schedtsk ldr r6, =Csym(knl_lowpow_discnt) // R6 = &lowpow_discnt l_dispatch1: msr cpsr_c, #PSR_SVC|PSR_DI // Interrupt disable ldr r8, [r5] // R8 = schedtsk cmp r8, #0 // Is there 'schedtsk'? bne l_dispatch2 /* Because there is no task that should be executed, move to the power-saving mode */ ldr ip, [r6] // Is 'low_pow' disabled? cmp ip, #0 bleq Csym(knl_low_pow) // call low_pow() msr cpsr_c, #PSR_SVC // Interrupt enable b l_dispatch1 l_dispatch2: // Switch to 'schedtsk' /* During interrupt disable CPSR.I=1 F=1 */ str r8, [r4] // ctxtsk = schedtsk ldr sp, [r8, #TCB_tskctxb + CTXB_ssp] // Restore 'ssp' from TCB ldr ip, =Csym(knl_dispatch_disabled) ldr lr, =0 str lr, [ip] // Dispatch enable ldmia sp, {r0-r11, ip, sp, lr}^ // Context restore nop add sp, sp, #15*4 ldr lr, =Csym(knl_taskmode) str ip, [lr] ldmfd sp!, {lr} // R14_svc restore EXC_RETURN #if USE_HLL_INTHDR /* ------------------------------------------------------------------------ */ /* * High level programming language routine for interrupt handler * Called by interrupt entry routine on the state saved in the interrupt * stack as shown below. * +---------------+ * ssp -> | R3 | Only FIQ, IRQ * +---------------+ * ssp -> | SPSR | * | R12 = ip | * | R14 = lr | * +---------------+ * * The vector table address is set in 'ip.' * (ip - EIT_VECTBL) / 4 = Vector number */ .text .balign 4 .globl Csym(knl_inthdr_startup) .globl Csym(knl_exchdr_startup) Csym(knl_exchdr_startup): /* Unknown mode/During interrupt disable CPSR.I=1 F=? */ stmfd sp!, {r3} // Register save b l_inthdr1 Csym(knl_inthdr_startup): /* Unknown mode/During interrupt disable CPSR.I=1 F=? */ mrs lr, cpsr and lr, lr, #PSR_M(31) cmp lr, #PSR_SVC stmeqfd sp!, {r3} // If it is SWI, also save 'r3' l_inthdr1: stmfd sp!, {r0-r2} // Register save ldr r3, =Csym(knl_intvec) sub r3, ip, r3 // r3 = Vector table offset // Argument of handler mov r0, r3, lsr #2 // r0 = dintno add r1, sp, #4*4 // r1 = sp l_inthdr2: mrs r2, cpsr // r2 = CPSR save msr cpsr_c, #PSR_IRQ|PSR_DI // Move to IRQ mode/Interrupt disable stmfd sp!, {r2, lr} stmfd sp!, {ip} ldr ip, =Csym(knl_taskindp) // Task independent part ldr lr, [ip] add lr, lr, #1 str lr, [ip] ldr ip, =Csym(knl_hll_inthdr) ldr ip, [ip, r3] mov lr, pc bx ip // call hll_inthdr[n](dintno, sp) ldmfd sp!, {ip} // IRQ mode register restore ldmfd sp!, {r2, r3} // r2 = Original mode // r3 = R14_irq orr r2, r2, #PSR_DI msr cpsr_c, r2 ldr ip, =Csym(knl_taskindp) ldr lr, [ip] sub lr, lr, #1 str lr, [ip] ldmfd sp!, {r0-r2} // Register restore swp r3, r3, [sp] // r3 restore, R14_svc/irq save bl tk_ret_int_impl #endif /* USE_HLL_INTHDR */ /* * tk_ret_int_impl() * * When called, the interrupt stack is configured as shown below. * +---------------+ * ssp -> | SPSR_svc | Save by 'swi SWI_RETINT' * | R12_usr | * | R14_svc | * +---------------+ * * +---------------+ * isp -> | R14_svc | Save when calling 'tk_ret_int' * +---------------+ * | SPSR_xxx | Save when the interrupt occurs * | R12_xxx | * | R14_xxx | <- Return address * +---------------+ */ .text .balign 4 .globl Csym(tk_ret_int_impl) Csym(tk_ret_int_impl): mrs ip, cpsr and lr, ip, #PSR_M(31) cmp lr, #PSR_SVC beq l_retint_svc // Is it 'tk_ret_int' from SWI? /* from IRQ/FIQ mode */ msr cpsr, #PSR_SVC|PSR_DI // Save 'r2, lr' for work (Save 'r3-' for acquiring location) stmfd sp!, {r4, r5, r6} stmfd sp!, {lr} stmfd sp!, {r2} add r2, sp, #4 /* r2 -> lr_svc */ msr cpsr, ip orr ip, ip, #PSR_DI bic ip, ip, #PSR_T cmp lr, #PSR_FIQ msr cpsr_c, ip // Move to interrupted mode/Interrupt disable /* r2=ssp, sp=isp*/ ldmfd sp!, {ip, lr} // Copy from 'isp' to 'ssp'/Free 'isp' // trash R14_irq str lr, [r2, #1*4] // SPSR_xxx ldmfd sp!, {ip, lr} strne ip, [r2, #2*4] // R12_xxx (except for FIQ) str lr, [r2, #3*4] // R14_xxx (Return address) msr cpsr_c, #PSR_SVC|PSR_DI // Move to SVC mode/Interrupt disable ldmfd sp!, {r2} // r2 restore b l_retint1 l_retint_svc: msr cpsr_c, #PSR_SVC|PSR_DI // Interrupt disable l_retint1: ldr ip, =Csym(knl_taskindp) // Is it a nesting interrupt? ldr ip, [ip] cmp ip, #0 bne l_nodispatch ldr ip, =Csym(knl_dispatch_disabled) // Is it during dispatch disable? ldr ip, [ip] cmp ip, #0 bne l_nodispatch ldr ip, [sp, #4] // SPSR tst ip, #PSR_I|PSR_F // Is it an exception during interrupt disable? bne l_nodispatch ldr ip, =Csym(knl_ctxtsk) // Is dispatch required? ldr lr, =Csym(knl_schedtsk) ldr ip, [ip] ldr lr, [lr] cmp ip, lr bne _ret_int_dispatch // To dispatch processing l_nodispatch: ldmfd sp!, {lr} // lr restore EXC_RETURN /* ------------------------------------------------------------------------ */ /* * High level programming language routine for timer handler */ .text .balign 4 .globl Csym(knl_timer_handler_startup) Csym(knl_timer_handler_startup): /* IRQ mode/During interrupt disable CPSR.I=1 F=? */ msr cpsr_c, #PSR_IRQ|PSR_DI // Move to IRQ mode/Interrupt disable stmfd sp!, {r0-r2, r4-r5, lr} // Register save ldr r4, =Csym(knl_taskindp) // Enter task independent part ldr r5, [r4] add r0, r5, #1 str r0, [r4] bl Csym(knl_timer_handler) // call timer_handler() /* Return by interrupt disable CPSR.I=1 F=1 */ str r5, [r4] // Leave task independent part ldmfd sp!, {r0-r2, r4-r5, lr} // Register restore swp r3, lr, [sp] // r3 restore, R14_irq save bl tk_ret_int_impl /* ------------------------------------------------------------------------ */