/* ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio. This file is part of ChibiOS. ChibiOS is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. ChibiOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /** * @file ARM/compilers/GCC/chcoreasm.S * @brief ARM architecture port low level code. * * @addtogroup ARM_CORE * @{ */ #define _FROM_ASM_ #include "chlicense.h" #include "chconf.h" #include "armparams.h" #define FALSE 0 #define TRUE 1 #if !defined(__DOXYGEN__) /* * RTOS-specific context offset. */ #if defined(_CHIBIOS_RT_CONF_) #define CONTEXT_OFFSET 12 #elif defined(_CHIBIOS_NIL_CONF_) #define CONTEXT_OFFSET 0 #else #error "invalid chconf.h" #endif .set MODE_USR, 0x10 .set MODE_FIQ, 0x11 .set MODE_IRQ, 0x12 .set MODE_SVC, 0x13 .set MODE_ABT, 0x17 .set MODE_UND, 0x1B .set MODE_SYS, 0x1F .equ I_BIT, 0x80 .equ F_BIT, 0x40 .text /* * The following functions are only present if there is THUMB code in * the system. */ #if defined(THUMB_PRESENT) .balign 16 .code 16 .thumb_func .global _port_get_cpsr _port_get_cpsr: mov r0, pc bx r0 .code 32 mrs r0, CPSR bx lr .balign 16 .code 16 .thumb_func .global _port_disable_thumb _port_disable_thumb: mov r3, pc bx r3 .code 32 mrs r3, CPSR orr r3, #I_BIT msr CPSR_c, r3 orr r3, #F_BIT msr CPSR_c, r3 bx lr .balign 16 .code 16 .thumb_func .global _port_suspend_thumb _port_suspend_thumb: // Goes into _port_unlock_thumb .code 16 .global _port_lock_thumb _port_lock_thumb: mov r3, pc bx r3 .code 32 msr CPSR_c, #MODE_SYS | I_BIT bx lr .balign 16 .code 16 .thumb_func .global _port_enable_thumb _port_enable_thumb: // Goes into _port_unlock_thumb .code 16 .global _port_unlock_thumb _port_unlock_thumb: mov r3, pc bx r3 .code 32 msr CPSR_c, #MODE_SYS bx lr #endif /* defined(THUMB_PRESENT) */ .balign 16 #if defined(THUMB_PRESENT) .code 16 .thumb_func .global _port_switch_thumb _port_switch_thumb: mov r2, pc bx r2 // Goes into _port_switch_arm in ARM mode #endif /* defined(THUMB_PRESENT) */ .code 32 .global _port_switch_arm _port_switch_arm: stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr} str sp, [r1, #12] ldr sp, [r0, #12] #if defined(THUMB_PRESENT) ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr} bx lr #else /* !defined(THUMB_PRESENT)T */ ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc} #endif /* !defined(THUMB_PRESENT) */ /* * Common IRQ code. It expects a macro ARM_IRQ_VECTOR_REG with the address * of a register holding the address of the ISR to be invoked, the ISR * then returns in the common epilogue code where the context switch will * be performed, if required. * System stack frame structure after a context switch in the * interrupt handler: * * High +------------+ * | LR_USR | -+ * | r12 | | * | r3 | | * | r2 | | External context: IRQ handler frame * | r1 | | * | r0 | | * | LR_IRQ | | (user code return address) * | PSR_USR | -+ (user code status) * | .... | <- chSchDoReschedule() stack frame, optimize it for space * | LR | -+ (system code return address) * | r11 | | * | r10 | | * | r9 | | * | r8 | | Internal context: chSysSwitch() frame * | r7 | | * | r6 | | * | r5 | | * SP-> | r4 | -+ * Low +------------+ */ .balign 16 .code 32 .global Irq_Handler Irq_Handler: stmfd sp!, {r0-r3, r12, lr} ldr r0, =ARM_IRQ_VECTOR_REG ldr r0, [r0] #if !defined(THUMB_NO_INTERWORKING) ldr lr, =_irq_ret_arm // ISR return point. bx r0 // Calling the ISR. _irq_ret_arm: #else /* defined(THUMB_NO_INTERWORKING) */ add r1, pc, #1 bx r1 .code 16 bl _bxr0 // Calling the ISR. mov lr, pc bx lr .code 32 #endif /* defined(THUMB_NO_INTERWORKING) */ cmp r0, #0 ldmfd sp!, {r0-r3, r12, lr} subeqs pc, lr, #4 // No reschedule, returns. // Now the frame is created in the system stack, the IRQ // stack is empty. msr CPSR_c, #MODE_SYS | I_BIT stmfd sp!, {r0-r3, r12, lr} msr CPSR_c, #MODE_IRQ | I_BIT mrs r0, SPSR mov r1, lr msr CPSR_c, #MODE_SYS | I_BIT stmfd sp!, {r0, r1} // Push R0=SPSR, R1=LR_IRQ. // Context switch. #if defined(THUMB_NO_INTERWORKING) add r0, pc, #1 bx r0 .code 16 #if CH_DBG_SYSTEM_STATE_CHECK bl _dbg_check_lock #endif bl chSchDoReschedule #if CH_DBG_SYSTEM_STATE_CHECK bl _dbg_check_unlock #endif mov lr, pc bx lr .code 32 #else /* !defined(THUMB_NO_INTERWORKING) */ #if CH_DBG_SYSTEM_STATE_CHECK bl _dbg_check_lock #endif bl chSchDoReschedule #if CH_DBG_SYSTEM_STATE_CHECK bl _dbg_check_unlock #endif #endif /* !defined(THUMB_NO_INTERWORKING) */ // Re-establish the IRQ conditions again. ldmfd sp!, {r0, r1} // Pop R0=SPSR, R1=LR_IRQ. msr CPSR_c, #MODE_IRQ | I_BIT msr SPSR_fsxc, r0 mov lr, r1 msr CPSR_c, #MODE_SYS | I_BIT ldmfd sp!, {r0-r3, r12, lr} msr CPSR_c, #MODE_IRQ | I_BIT subs pc, lr, #4 #if defined(THUMB_NO_INTERWORKING) .code 16 _bxr0: bx r0 #endif /* * Threads trampoline code. * NOTE: The threads always start in ARM mode and then switches to the * thread-function mode. */ .balign 16 .code 32 .globl _port_thread_start _port_thread_start: #if defined(THUMB_NO_INTERWORKING) add r0, pc, #1 bx r0 .code 16 #if CH_DBG_SYSTEM_STATE_CHECK bl _dbg_check_unlock #endif bl _port_unlock_thumb mov r0, r5 bl _bxr4 #if defined(_CHIBIOS_RT_CONF_) mov r0, #0 /* MSG_OK */ bl chThdExit _zombies: b _zombies #endif #if defined(_CHIBIOS_NIL_CONF_) mov r0, #0 bl chSysHalt #endif _bxr4: bx r4 #else /* !defined(THUMB_NO_INTERWORKING) */ #if CH_DBG_SYSTEM_STATE_CHECK bl _dbg_check_unlock #endif msr CPSR_c, #MODE_SYS mov r0, r5 mov lr, pc bx r4 #if defined(_CHIBIOS_RT_CONF_) mov r0, #0 /* MSG_OK */ bl chThdExit _zombies: b _zombies #endif #if defined(_CHIBIOS_NIL_CONF_) mov r0, #0 bl chSysHalt #endif #endif /* !defined(THUMB_NO_INTERWORKING) */ #endif /* !defined(__DOXYGEN__) */ /** @} */