zephyr/arch/arm/core/gdb_stub.S

149 lines
4.3 KiB
ArmAsm

/* 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 <offsets.h>
#include <toolchain.h>
#include <sections.h>
#include <nano_private.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, =_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