zephyr/arch/arm/core/gdb_stub.S

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