📄 hal_stub.c
字号:
//=============================================================================
//
// hal_stub.c
//
// Helper functions for stub, specific to eCos HAL
//
//=============================================================================
//####COPYRIGHTBEGIN####
//
// -------------------------------------------
// The contents of this file are subject to the Red Hat eCos Public License
// Version 1.1 (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.redhat.com/
//
// Software distributed under the License is distributed on an "AS IS"
// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
// License for the specific language governing rights and limitations under
// the License.
//
// The Original Code is eCos - Embedded Configurable Operating System,
// released September 30, 1998.
//
// The Initial Developer of the Original Code is Red Hat.
// Portions created by Red Hat are
// Copyright (C) 1998, 1999, 2000, 2001 Red Hat, Inc.
// All Rights Reserved.
// -------------------------------------------
//
//####COPYRIGHTEND####
//=============================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): jskov (based on powerpc/cogent hal_stub.c)
// Contributors:jskov, dmoseley
// Date: 1999-02-12
// Purpose: Helper functions for stub, specific to eCos HAL
// Description: Parts of the GDB stub requirements are provided by
// the eCos HAL, rather than target and/or board specific
// code.
//
//####DESCRIPTIONEND####
//
//=============================================================================
#include <pkgconf/hal.h>
#ifdef CYGPKG_CYGMON
#include <pkgconf/cygmon.h>
#endif
#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
#include <cyg/hal/hal_stub.h> // Our header
#include <cyg/hal/hal_arch.h> // HAL_BREAKINST
#include <cyg/hal/hal_cache.h> // HAL_xCACHE_x
#include <cyg/hal/hal_intr.h> // interrupt disable/restore
#include <cyg/hal/hal_if.h> // ROM calling interface
#include <cyg/hal/hal_misc.h> // Helper functions
#ifdef CYGDBG_HAL_DEBUG_GDB_THREAD_SUPPORT
#include <cyg/hal/dbg-threads-api.h> // dbg_currthread_id
#endif
#ifdef USE_LONG_NAMES_FOR_ENUM_REGNAMES
#ifndef PC
#define PC REG_PC
#endif
#ifndef SP
#define SP REG_SP
#endif
#endif
//-----------------------------------------------------------------------------
// Extra eCos data.
// Saved registers.
HAL_SavedRegisters *_hal_registers;
target_register_t registers[NUMREGS];
target_register_t alt_registers[NUMREGS] ; // Thread or saved process state
target_register_t * _registers = registers; // Pointer to current set of registers
target_register_t orig_registers[NUMREGS]; // Registers to get back to original state
#if defined(HAL_STUB_HW_WATCHPOINT) || defined(HAL_STUB_HW_BREAKPOINT)
static int _hw_stop_reason; // Reason we were stopped by hw.
// strings indexed by hw stop reasons defined in hal_stub.h
static const char * const _hw_stop_str[] = {
"",
"hbreak",
"watch",
"rwatch",
"awatch"
};
static void *_watch_data_addr; // The data address if stopped by watchpoint
#endif
// Register validity checking
#ifdef CYGHWR_REGISTER_VALIDITY_CHECKING
int registers_valid[NUMREGS];
int *_registers_valid = registers_valid;
#endif
#ifndef CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT // this should go away
// Interrupt control.
static volatile __PFI __interruptible_control;
#endif
// Some architectures need extras regs reported in T packet
#ifndef HAL_STUB_ARCH_T_PACKET_EXTRAS
#define HAL_STUB_ARCH_T_PACKET_EXTRAS(x)
#endif
//-----------------------------------------------------------------------------
// Register access
// Return the currently-saved value corresponding to register REG of
// the exception context.
target_register_t
get_register (regnames_t reg)
{
return _registers[reg];
}
#ifdef CYGHWR_REGISTER_VALIDITY_CHECKING
// Return the validity of register REG.
int
get_register_valid (regnames_t reg)
{
return _registers_valid[reg];
}
#endif
// Store VALUE in the register corresponding to WHICH in the exception
// context.
void
put_register (regnames_t which, target_register_t value)
{
_registers[which] = value;
}
//-----------------------------------------------------------------------------
// Serial stuff
#ifdef CYGPKG_CYGMON
extern void ecos_bsp_console_putc(char);
extern char ecos_bsp_console_getc(void);
#endif
// Write C to the current serial port.
void
putDebugChar (int c)
{
#ifdef CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT
__call_if_debug_procs_t __debug_procs = CYGACC_CALL_IF_DEBUG_PROCS();
CYGACC_COMM_IF_PUTC(*__debug_procs, c);
#elif defined(CYGPKG_CYGMON)
ecos_bsp_console_putc(c);
#else
HAL_STUB_PLATFORM_PUT_CHAR(c);
#endif
}
// Read one character from the current serial port.
int
getDebugChar (void)
{
#ifdef CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT
__call_if_debug_procs_t __debug_procs = CYGACC_CALL_IF_DEBUG_PROCS();
return CYGACC_COMM_IF_GETC(*__debug_procs);
#elif defined(CYGPKG_CYGMON)
return ecos_bsp_console_getc();
#else
return HAL_STUB_PLATFORM_GET_CHAR();
#endif
}
// Flush output channel
void
hal_flush_output(void)
{
#ifdef CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT
__call_if_debug_procs_t __debug_procs = CYGACC_CALL_IF_DEBUG_PROCS();
CYGACC_COMM_IF_CONTROL(*__debug_procs, __COMMCTL_FLUSH_OUTPUT);
#endif
}
// Set the baud rate for the current serial port.
void
__set_baud_rate (int baud)
{
#ifdef CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT
__call_if_debug_procs_t __debug_procs = CYGACC_CALL_IF_DEBUG_PROCS();
CYGACC_COMM_IF_CONTROL(*__debug_procs, __COMMCTL_SETBAUD, baud);
#elif defined(CYGPKG_CYGMON)
// FIXME!
#else
HAL_STUB_PLATFORM_SET_BAUD_RATE(baud);
#endif
}
//-----------------------------------------------------------------------------
// GDB interrupt (BREAK) support.
#ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
#ifndef CYGPKG_HAL_ARM
#if (HAL_BREAKINST_SIZE == 1)
typedef cyg_uint8 t_inst;
#elif (HAL_BREAKINST_SIZE == 2)
typedef cyg_uint16 t_inst;
#elif (HAL_BREAKINST_SIZE == 4)
typedef cyg_uint32 t_inst;
#else
#error "Don't know how to handle that size"
#endif
typedef struct
{
t_inst *targetAddr;
t_inst savedInstr;
} instrBuffer;
static instrBuffer break_buffer;
volatile int cyg_hal_gdb_running_step = 0;
void
cyg_hal_gdb_place_break (target_register_t pc)
{
cyg_hal_gdb_interrupt( pc ); // Let's hope this becomes a drop-through:
}
void
cyg_hal_gdb_interrupt (target_register_t pc)
{
CYGARC_HAL_SAVE_GP();
// Clear flag that we Continued instead of Stepping
cyg_hal_gdb_running_step = 0;
// and override existing break? So that a ^C takes effect...
if (NULL != break_buffer.targetAddr)
cyg_hal_gdb_remove_break( (target_register_t)break_buffer.targetAddr );
if (NULL == break_buffer.targetAddr) {
break_buffer.targetAddr = (t_inst*) pc;
break_buffer.savedInstr = *(t_inst*)pc;
*(t_inst*)pc = (t_inst)HAL_BREAKINST;
__data_cache(CACHE_FLUSH);
__instruction_cache(CACHE_FLUSH);
}
CYGARC_HAL_RESTORE_GP();
}
int
cyg_hal_gdb_remove_break (target_register_t pc)
{
if ( cyg_hal_gdb_running_step )
return 0;
if ((t_inst*)pc == break_buffer.targetAddr) {
*(t_inst*)pc = break_buffer.savedInstr;
break_buffer.targetAddr = NULL;
__data_cache(CACHE_FLUSH);
__instruction_cache(CACHE_FLUSH);
return 1;
}
return 0;
}
int
cyg_hal_gdb_break_is_set (void)
{
if (NULL != break_buffer.targetAddr) {
return 1;
}
return 0;
}
#endif // CYGPKG_HAL_ARM
#endif // CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
// Use this function to disable serial interrupts whenever reply
// characters are expected from GDB. The reason we want to control
// whether the target can be interrupted or not is simply that GDB on
// the host will be sending acknowledge characters/commands while the
// stub is running - if serial interrupts were still active, the
// characters would never reach the (polling) getDebugChar.
static void
interruptible(int state)
{
static int __interrupts_suspended = 0;
if (state) {
__interrupts_suspended--;
if (0 >= __interrupts_suspended) {
__interrupts_suspended = 0;
#ifdef CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT // this _check_ should go away
{
hal_virtual_comm_table_t* __chan;
__chan = CYGACC_CALL_IF_DEBUG_PROCS();
CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_IRQ_ENABLE);
}
#else
if (__interruptible_control)
__interruptible_control(1);
#endif
}
} else {
__interrupts_suspended++;
if (1 == __interrupts_suspended)
#ifdef CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT // this _check_ should go away
{
hal_virtual_comm_table_t* __chan;
__chan = CYGACC_CALL_IF_DEBUG_PROCS();
CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_IRQ_DISABLE);
}
#else
if (__interruptible_control)
__interruptible_control(0);
#endif
}
}
//-----------------------------------------------------------------------------
// eCos stub entry and exit magic.
#ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
int cyg_hal_gdb_break;
#endif
// Called at stub *kill*
static void
handle_exception_exit( void )
{
int i;
for (i = 0; i < (sizeof(registers)/sizeof(registers[0])); i++)
registers[i] = orig_registers[i];
}
// Called at stub *entry*
static void
handle_exception_cleanup( void )
{
static int orig_registers_set = 0;
interruptible(0);
// Expand the HAL_SavedRegisters structure into the GDB register
// array format.
HAL_GET_GDB_REGISTERS(®isters[0], _hal_registers);
_registers = ®isters[0];
if (!orig_registers_set) {
int i;
for (i = 0; i < (sizeof(registers)/sizeof(registers[0])); i++)
orig_registers[i] = registers[i];
_registers = &orig_registers[0];
if (__is_breakpoint_function ())
__skipinst ();
_registers = ®isters[0];
orig_registers_set = 1;
}
#ifdef HAL_STUB_PLATFORM_STUBS_FIXUP
// Some architectures may need to fix the PC in case of a partial
// or fully executed trap instruction. GDB only takes correct action
// when the PC is pointing to the breakpoint instruction it set.
//
// Most architectures would leave PC pointing at the trap
// instruction itself though, and so do not need to do anything
// special.
HAL_STUB_PLATFORM_STUBS_FIXUP();
#endif
#ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
// If we continued instead of stepping, when there was a break set
// ie. we were stepping within a critical region, clear the break, and
// that flag. If we stopped for some other reason, this has no effect.
if ( cyg_hal_gdb_running_step ) {
cyg_hal_gdb_running_step = 0;
cyg_hal_gdb_remove_break(get_register (PC));
}
// FIXME: (there may be a better way to do this)
// If we hit a breakpoint set by the gdb interrupt stub, make it
// seem like an interrupt rather than having hit a breakpoint.
cyg_hal_gdb_break = cyg_hal_gdb_remove_break(get_register (PC));
#endif
#if defined(HAL_STUB_HW_WATCHPOINT) || defined(HAL_STUB_HW_BREAKPOINT)
// For HW watchpoint/breakpoint support, we need to know if we
// stopped because of watchpoint or hw break. We do that here
// before GDB has a chance to remove the watchpoints and save
// the information for later use in building response packets.
_hw_stop_reason = HAL_STUB_IS_STOPPED_BY_HARDWARE(_watch_data_addr);
#endif
}
// Called at stub *exit*
static void
handle_exception_init( void )
{
// Compact register array again.
HAL_SET_GDB_REGISTERS(_hal_registers, ®isters[0]);
interruptible(1);
}
//-----------------------------------------------------------------------------
// Initialization.
// Signal handler.
int
cyg_hal_process_signal (int signal)
{
// We don't care about the signal (atm).
return 0;
}
// Install the standard set of trap handlers for the stub.
void
__install_traps (void)
{
// Set signal handling vector so we can treat 'C<signum>' as 'c'.
__process_signal_vec = &cyg_hal_process_signal;
__process_exit_vec = &handle_exception_exit;
__cleanup_vec = &handle_exception_cleanup;
__init_vec = &handle_exception_init;
#ifndef CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT // this should go away
#ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
// Control of GDB interrupts.
__interruptible_control = HAL_STUB_PLATFORM_INTERRUPTIBLE;
#endif
#endif
// Nothing further to do, handle_exception will be called when an
// exception occurs.
}
// Initialize the hardware.
void
initHardware (void)
{
static int initialized = 0;
if (initialized)
return;
initialized = 1;
// Get serial port initialized.
HAL_STUB_PLATFORM_INIT_SERIAL();
#ifdef HAL_STUB_PLATFORM_INIT
// If the platform defines any initialization code, call it here.
HAL_STUB_PLATFORM_INIT();
#endif
#ifndef CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT // this should go away
#ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
// Get interrupt handler initialized.
HAL_STUB_PLATFORM_INIT_BREAK_IRQ();
#endif
#endif // !CYGSEM_HAL_VIRTUAL_VECTOR_SUPPORT
}
// Reset the board.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -