Mercurial > ecos
diff packages/hal/common/current/src/hal_stub.c @ 2:443894e2e912 ecos-v1_2_1-release
Block commit of eCos version 1.2.1
| author | jlarmour |
|---|---|
| date | Tue, 11 May 1999 12:24:34 +0000 |
| parents | |
| children | d376b777e2ce |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/packages/hal/common/current/src/hal_stub.c @@ -0,0 +1,525 @@ +//============================================================================= +// +// hal_stub.c +// +// Helper functions for stub, specific to eCos HAL +// +//============================================================================= +//####COPYRIGHTBEGIN#### +// +// ------------------------------------------- +// The contents of this file are subject to the Cygnus eCos Public License +// Version 1.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://sourceware.cygnus.com/ecos +// +// 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 Cygnus Operating System, released +// September 30, 1998. +// +// The Initial Developer of the Original Code is Cygnus. Portions created +// by Cygnus are Copyright (C) 1998, 1999 Cygnus Solutions. +// All Rights Reserved. +// ------------------------------------------- +// +//####COPYRIGHTEND#### +//============================================================================= +//#####DESCRIPTIONBEGIN#### +// +// Author(s): jskov (based on powerpc/cogent hal_stub.c) +// Contributors:jskov +// 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 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 + +#ifdef CYGDBG_HAL_DEBUG_GDB_THREAD_SUPPORT +#include <cyg/hal/dbg-threads-api.h> // dbg_currthread_id +#endif + + +//----------------------------------------------------------------------------- +// Extra eCos data. + +// Saved registers. +HAL_SavedRegisters *_hal_registers; +target_register_t * _registers; // Pointer to current set of registers +target_register_t registers[NUMREGS]; +target_register_t alt_registers[NUMREGS] ; // Thread or saved process state + +// Interrupt control. +static volatile __PFI __interruptible_control; + +//----------------------------------------------------------------------------- +// 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]; +} + +// 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 + +// Write C to the current serial port. +void +putDebugChar (int c) +{ + HAL_STUB_PLATFORM_PUT_CHAR(c); +} + +// Read one character from the current serial port. +int +getDebugChar (void) +{ + return HAL_STUB_PLATFORM_GET_CHAR(); +} + +// Set the baud rate for the current serial port. +void +__set_baud_rate (int baud) +{ + HAL_STUB_PLATFORM_SET_BAUD_RATE(baud); +} + +//----------------------------------------------------------------------------- +// GDB interrupt (BREAK) support. + +#ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT + +typedef unsigned long t_inst; + +typedef struct +{ + t_inst *targetAddr; + t_inst savedInstr; +} instrBuffer; + +static instrBuffer break_buffer; + +void +cyg_hal_gdb_interrupt (target_register_t pc) +{ + 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); + } +} + +int +cyg_hal_gdb_remove_break (target_register_t pc) +{ + 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; +} + +#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 (__interruptible_control) { + if (state) { + __interrupts_suspended--; + if (0 >= __interrupts_suspended) { + __interrupts_suspended = 0; + __interruptible_control(1); + } + } else { + __interrupts_suspended++; + if (1 == __interrupts_suspended) + __interruptible_control(0); + } + } +} + +//----------------------------------------------------------------------------- +// eCos stub entry and exit magic. + +#ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT +int cyg_hal_gdb_break; +#endif + +// Called at stub *entry* +static void +handle_exception_cleanup( void ) +{ + interruptible(0); + + // Expand the HAL_SavedRegisters structure into the GDB register + // array format. + HAL_GET_GDB_REGISTERS(®isters[0], _hal_registers); + _registers = ®isters[0]; + +#ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT + // 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. + if (cyg_hal_gdb_remove_break(get_register (PC))) + cyg_hal_gdb_break = 1; + else + cyg_hal_gdb_break = 0; +#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; + + __cleanup_vec = &handle_exception_cleanup; + __init_vec = &handle_exception_init; + +#ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT + // Control of GDB interrupts. + __interruptible_control = HAL_STUB_PLATFORM_INTERRUPTIBLE; +#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) { + initialized = 1; + + // Get serial port initialized. + HAL_STUB_PLATFORM_INIT_SERIAL(); + +#ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT + // Get interrupt handler initialized. + HAL_STUB_PLATFORM_INIT_BREAK_IRQ(); +#endif + +#ifdef CYG_HAL_STARTUP_STUBS + // There may be extra initialization required when configured + // for stubs startup. + HAL_STUB_PLATFORM_STUBS_INIT(); +#endif + } +} + +// Reset the board. +void +__reset (void) +{ + HAL_STUB_PLATFORM_RESET(); +} + +//----------------------------------------------------------------------------- +// Breakpoint support. + +#ifndef CYGPKG_HAL_ARM +// This function will generate a breakpoint exception. It is used at +// the beginning of a program to sync up with a debugger and can be +// used otherwise as a quick means to stop program execution and +// "break" into the debugger. +void +breakpoint() +{ + HAL_BREAKPOINT(_breakinst); +} + +// This function returns the opcode for a 'trap' instruction. +unsigned long +__break_opcode () +{ + return HAL_BREAKINST; +} +#endif + +// FIXME: Add support for multiple breakpoints (libstub/bplist-dynamic.c) +int __set_breakpoint (target_register_t addr) { return 0; } +int __remove_breakpoint (target_register_t addr) { return 0; } + +//----------------------------------------------------------------------------- +// Write the 'T' packet in BUFFER. SIGVAL is the signal the program received. +void +__build_t_packet (int sigval, char *buf) +{ + target_register_t addr; + char *ptr = buf; + target_register_t *sp; + + sp = (target_register_t *) get_register (SP); + + *ptr++ = 'T'; + *ptr++ = __tohex (sigval >> 4); + *ptr++ = __tohex (sigval); + +#ifdef CYGDBG_HAL_DEBUG_GDB_THREAD_SUPPORT + // Include thread ID if thread manipulation is required. + { + int id; + + *ptr++ = 't'; + *ptr++ = 'h'; + *ptr++ = 'r'; + *ptr++ = 'e'; + *ptr++ = 'a'; + *ptr++ = 'd'; + *ptr++ = ':'; + +#if (CYG_BYTEORDER == CYG_MSBFIRST) + id = dbg_currthread_id (); +#else + // FIXME: Temporary workaround for PR 18903. Thread ID must be + // big-endian in the T packet. + { + unsigned char* bep = (unsigned char*)&id; + int be_id; + + be_id = dbg_currthread_id (); + *bep++ = (be_id >> 24) & 0xff ; + *bep++ = (be_id >> 16) & 0xff ; + *bep++ = (be_id >> 8) & 0xff ; + *bep++ = (be_id & 0xff) ; + } +#endif + ptr = __mem2hex((char *)&id, ptr, sizeof(id), 0); + *ptr++ = ';'; + } +#endif + + *ptr++ = __tohex (PC >> 4); + *ptr++ = __tohex (PC); + *ptr++ = ':'; + addr = get_register (PC); + ptr = __mem2hex((char *)&addr, ptr, sizeof(addr), 0); + *ptr++ = ';'; + + *ptr++ = __tohex (SP >> 4); + *ptr++ = __tohex (SP); + *ptr++ = ':'; + ptr = __mem2hex((char *)&sp, ptr, sizeof(sp), 0); + *ptr++ = ';'; + + *ptr++ = 0; +} + + +//----------------------------------------------------------------------------- +// Cache functions. + +// Perform the specified operation on the instruction cache. +// Returns 1 if the cache is enabled, 0 otherwise. +int +__instruction_cache (cache_control_t request) +{ + int state = 1; + + switch (request) { + case CACHE_ENABLE: + HAL_ICACHE_ENABLE(); + break; + case CACHE_DISABLE: + HAL_ICACHE_DISABLE(); + state = 0; + break; + case CACHE_FLUSH: + HAL_ICACHE_SYNC(); + HAL_ICACHE_INVALIDATE_ALL(); + break; + case CACHE_NOOP: + /* fall through */ + default: + break; + } + +#ifdef HAL_ICACHE_IS_ENABLED + HAL_ICACHE_IS_ENABLED(state); +#endif + + return state; +} + +// Perform the specified operation on the data cache. +// Returns 1 if the cache is enabled, 0 otherwise. +int +__data_cache (cache_control_t request) +{ + int state = 1; + + switch (request) { + case CACHE_ENABLE: + HAL_DCACHE_ENABLE(); + break; + case CACHE_DISABLE: + HAL_DCACHE_DISABLE(); + state = 0; + break; + case CACHE_FLUSH: + HAL_DCACHE_SYNC(); + HAL_DCACHE_INVALIDATE_ALL(); + break; + case CACHE_NOOP: + /* fall through */ + default: + break; + } + +#ifdef HAL_DCACHE_IS_ENABLED + HAL_DCACHE_IS_ENABLED(state); +#endif + + return state; +} + +//----------------------------------------------------------------------------- +// Memory accessor functions. + +void *__mem_fault_handler = (void *)0; + +/* These are the "arguments" to __do_read_mem and __do_write_mem, + which are passed as globals to avoid squeezing them thru + __set_mem_fault_trap. */ + +static volatile target_register_t memCount; + +static void +__do_copy_mem (unsigned char* src, unsigned char* dst) +{ + __mem_fault = 1; // Defaults to 'fail'. Is cleared + // when the copy loop completes. + __mem_fault_handler = &&err; + + while (memCount) + { + *dst++ = *src++; + memCount--; + } + + __mem_fault = 0; + + err: + __mem_fault_handler = (void *)0; +} + +/* + * __read_mem_safe: + * Get contents of target memory, abort on error. + */ + +int +__read_mem_safe (unsigned char *dst, target_register_t src, int count) +{ + memCount = count; + __do_copy_mem((unsigned char*) src, (unsigned char*) dst); + return count - memCount; // return number of bytes successfully read +} + +/* + * __write_mem_safe: + * Set contents of target memory, abort on error. + */ + +int +__write_mem_safe (unsigned char *src, target_register_t dst, int count) +{ + memCount = count; + __do_copy_mem((unsigned char*) src, (unsigned char*) dst); + return count - memCount; // return number of bytes successfully written +} + +//----------------------------------------------------------------------------- +// Target extras?! +int +__process_target_query(char * pkt, char * out, int maxOut) +{ return 0 ; } +int +__process_target_set(char * pkt, char * out, int maxout) +{ return 0 ; } +int +__process_target_packet(char * pkt, char * out, int maxout) +{ return 0 ; } + +// GDB string output, making sure interrupts are disabled. +// This function gets used by some diag output functions. +void +hal_output_gdb_string(target_register_t str, int string_len) +{ + unsigned long __state; + HAL_DISABLE_INTERRUPTS(__state) + __output_gdb_string(str, string_len); + HAL_RESTORE_INTERRUPTS(__state); +} + +#endif // CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
