/* gdb_stub.S - extra work performed upon exception entry/exit for GDB */ /* * Copyright (c) 2014 Wind River Systems, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* DESCRIPTION Prep work done when entering exceptions consists of saving the callee-saved registers before they get used by exception handlers, and recording the fact that we are running in an exception. Upon exception exit, it must be recorded that the task is not in an exception anymore. */ #define _ASMLANGUAGE #include #include #include #include #include _ASM_FILE_PROLOGUE /** * * @brief Exception entry extra work when GDB_INFO is enabled * * During normal system operation, the callee-saved registers are saved lazily * only when a context switch is required. To allow looking at the current * threads registers while debugging an exception/interrupt, they must be saved * upon entry since the handler could be using them: thus, looking at the CPU * registers would show the current system state and not the current *thread*'s * state. * * Also, record the fact that the thread is currently interrupted so that VQEMU * looks into the TCS and not the CPU registers to obtain the current thread's * register values. * * NOTE: * - must be called with interrupts locked * - cannot use r0 without saving it first * * @return N/A */ SECTION_FUNC(TEXT, _GdbStubExcEntry) ldr r1, =_nanokernel ldr r2, [r1, #__tNANO_flags_OFFSET] /* already in an exception, do not update the registers */ ands r3, r2, #EXC_ACTIVE it ne bxne lr orrs r2, #EXC_ACTIVE str r2, [r1, #__tNANO_flags_OFFSET] ldr r1, [r1, #__tNANO_current_OFFSET] str r2, [r1, #__tTCS_flags_OFFSET] /* save callee-saved + psp in TCS */ adds r1, #__tTCS_preempReg_OFFSET mrs ip, PSP stmia r1, {v1-v8, ip} bx lr /** * * @brief Exception exit extra clean up when GDB_INFO is enabled * * Record the fact that the thread is not interrupted anymore so that VQEMU * looks at the CPU registers and not into the TCS to obtain the current * thread's register values. Only do this if this is not a nested exception. * * NOTE: * - must be called with interrupts locked * - cannot use r0 without saving it first * * @return N/A */ SECTION_FUNC(TEXT, _GdbStubExcExit) /* if we're nested (ie. !RETTOBASE), do not reset EXC_ACTIVE */ ldr r1, =_SCS_ICSR ldr r1, [r1] ands r1, #_SCS_ICSR_RETTOBASE it eq bxeq lr ldr r1, =_nanokernel ldr r2, [r1, #__tNANO_flags_OFFSET] bic r2, #EXC_ACTIVE str r2, [r1, #__tNANO_flags_OFFSET] ldr r1, [r1, #__tNANO_current_OFFSET] str r2, [r1, #__tTCS_flags_OFFSET] bx lr /** * * @brief Stub for ISRs installed directly in vector table * * The kernel on Cortex-M3/4 can be configured so that ISRs * are installed directly in the vector table for maximum efficiency. * * When OS-awareness is enabled, a stub must be inserted to invoke * _GdbStubExcEntry() before the user ISR runs, to save the current task's * registers. This stub thus gets inserted in the vector table instead of the * user's ISR. The user's IRQ vector table gets pushed after the vector table * automatically by the linker script: this is all transparent to the user. * This stub must also act as a demuxer that find the running exception and * invoke the user's real ISR. * * @return N/A */ SECTION_FUNC(TEXT, _irq_vector_table_entry_with_gdb_stub) _GDB_STUB_EXC_ENTRY mrs r0, IPSR /* get exception number */ sub r0, r0, #16 /* get IRQ number */ ldr r1, =_irq_vector_table /* grab real ISR at address: r1 + (r0 << 2) (table is 4-byte wide) */ ldr r1, [r1, r0, LSL #2] /* jump to ISR, no return: ISR is responsible for calling _IntExit */ bx r1