169 lines
4.7 KiB
ArmAsm
169 lines
4.7 KiB
ArmAsm
/*
|
|
* 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.
|
|
*/
|
|
|
|
/**
|
|
* @file
|
|
* @brief Extra work performed upon exception entry/exit for GDB
|
|
*
|
|
*
|
|
* 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 <offsets_short.h>
|
|
#include <toolchain.h>
|
|
#include <sections.h>
|
|
#include <kernel_structs.h>
|
|
#include <arch/cpu.h>
|
|
|
|
_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, =_kernel
|
|
ldr r2, [r1, #__tNANO_flags_OFFSET]
|
|
|
|
/* already in an exception, do not update the registers */
|
|
ldr r3, =EXC_ACTIVE
|
|
ands r3, r2
|
|
beq _GdbStubEditReg
|
|
bx lr
|
|
|
|
_GdbStubEditReg:
|
|
ldr r3, =EXC_ACTIVE
|
|
orrs r2, r3
|
|
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
|
|
#if defined(CONFIG_CPU_CORTEX_M0_M0PLUS)
|
|
/* Store current r4-r7 */
|
|
stmea r1!, {r4-r7}
|
|
/* copy r8-r12 into r3-r7 */
|
|
mov r3, r8
|
|
mov r4, r9
|
|
mov r5, r10
|
|
mov r6, r11
|
|
mov r7, ip
|
|
/* store r8-12 */
|
|
stmea r1!, {r3-r7}
|
|
#else /* CONFIG_CPU_CORTEX_M0_M0PLUS */
|
|
stmia r1, {v1-v8, ip}
|
|
#endif
|
|
|
|
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 !defined(CONFIG_CPU_CORTEX_M0_M0PLUS)
|
|
/* 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
|
|
#endif
|
|
|
|
ldr r1, =_kernel
|
|
ldr r2, [r1, #__tNANO_flags_OFFSET]
|
|
|
|
ldr r3, =EXC_ACTIVE
|
|
bics r2, r3
|
|
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 */
|
|
subs r0, #16 /* get IRQ number */
|
|
ldr r1, =_irq_vector_table
|
|
|
|
/* grab real ISR at address: r1 + (r0 << 2) (table is 4-byte wide) */
|
|
lsls r3, r0, #2
|
|
ldr r1, [r1, r3]
|
|
|
|
/* jump to ISR, no return: ISR is responsible for calling _IntExit */
|
|
bx r1
|