Mercurial > flash_v2
diff packages/hal/powerpc/arch/current/src/ppc_stub.c @ 0:3111d98ba7b3 ecos-v1_1-release
Initial commit of eCos version 1.1
| author | jlarmour |
|---|---|
| date | Tue, 11 May 1999 11:16:07 +0000 |
| parents | |
| children | 443894e2e912 |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/packages/hal/powerpc/arch/current/src/ppc_stub.c @@ -0,0 +1,303 @@ +/* ppc_stub.c - helper functions for stub, generic to all PowerPC processors + * + * Copyright (c) 1998 Cygnus Support + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + */ + +#include <stddef.h> + +#include <pkgconf/hal.h> + +#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS + +#ifdef CYG_HAL_POWERPC_SIM +#error "GDB Stub support not implemented for PPC SIM" +#endif + +#include <cyg/hal/hal_stub.h> +#include <cyg/hal/hal_arch.h> +#include <cyg/hal/hal_intr.h> +#include <cyg/hal/ppc_regs.h> + +#ifdef CYGDBG_HAL_DEBUG_GDB_THREAD_SUPPORT +#include <cyg/hal/dbg-threads-api.h> // dbg_currthread_id +#endif + +#define SIGHUP 1 /* hangup */ +#define SIGINT 2 /* interrupt */ +#define SIGQUIT 3 /* quit */ +#define SIGILL 4 /* illegal instruction (not reset when caught) */ +#define SIGTRAP 5 /* trace trap (not reset when caught) */ +#define SIGIOT 6 /* IOT instruction */ +#define SIGABRT 6 /* used by abort, replace SIGIOT in the future */ +#define SIGEMT 7 /* EMT instruction */ +#define SIGFPE 8 /* floating point exception */ +#define SIGKILL 9 /* kill (cannot be caught or ignored) */ +#define SIGBUS 10 /* bus error */ +#define SIGSEGV 11 /* segmentation violation */ +#define SIGSYS 12 /* bad argument to system call */ +#define SIGPIPE 13 /* write on a pipe with no one to read it */ +#define SIGALRM 14 /* alarm clock */ +#define SIGTERM 15 /* software termination signal from kill */ + +/* Saved registers. */ + +HAL_SavedRegisters *_hal_registers; + +target_register_t * _registers; /* A pointer to the current set of registers */ +target_register_t registers[NUMREGS]; +target_register_t alt_registers[NUMREGS] ; /* Thread or saved process state */ + + +/* Given a trap value TRAP, return the corresponding signal. */ + +int __computeSignal (unsigned int trap_number) +{ + switch (trap_number) + { + case CYG_VECTOR_MACHINE_CHECK: + /* Machine check */ + case CYG_VECTOR_DSI: + /* Data access */ + return SIGSEGV; + + case CYG_VECTOR_ISI: + /* Instruction access (Ifetch) */ + case CYG_VECTOR_ALIGNMENT: + /* Data access */ + return SIGBUS; + + case CYG_VECTOR_INTERRUPT: + /* External interrupt */ + return SIGINT; + + case CYG_VECTOR_TRACE: + /* Instruction trace */ + return SIGTRAP; + + case CYG_VECTOR_PROGRAM: + switch ((get_register (PS) >> 17) & 0xf){ + case 1: /* trap */ + return SIGTRAP; + case 2: /* privileged instruction */ + case 4: /* illegal instruction */ + return SIGILL; + case 8: /* floating point */ + return SIGFPE; + default: /* should never happen! */ + return SIGTERM; + } + + case CYG_VECTOR_RESERVED_A: + case CYG_VECTOR_RESERVED_B: + return SIGILL; + + case CYG_VECTOR_FP_UNAVAILABLE: + /* FPU disabled */ + case CYG_VECTOR_FP_ASSIST: + /* FPU assist */ + return SIGFPE; + + case CYG_VECTOR_DECREMENTER: + /* Decrementer alarm */ + return SIGALRM; + + case CYG_VECTOR_SYSTEM_CALL: + /* System call */ + return SIGSYS; + +#ifdef CYG_HAL_POWERPC_MP860 + case CYG_VECTOR_SW_EMUL: + /* A SW_EMUL is generated instead of PROGRAM for illegal + instructions. */ + return SIGILL; + + case CYG_VECTOR_DATA_BP: + case CYG_VECTOR_INSTRUCTION_BP: + case CYG_VECTOR_PERIPHERAL_BP: + case CYG_VECTOR_NMI: + /* Developer port debugging exceptions. */ + return SIGTRAP; + + case CYG_VECTOR_ITLB_MISS: + case CYG_VECTOR_DTLB_MISS: + /* Software reload of TLB required. */ + return SIGTRAP; + + case CYG_VECTOR_ITLB_ERROR: + /* Invalid instruction access. */ + return SIGBUS; + + case CYG_VECTOR_DTLB_ERROR: + /* Invalid data access. */ + return SIGSEGV; +#endif + + default: + return SIGTERM; + } +} + + +/* Return the trap number corresponding to the last-taken trap. */ + +int __get_trap_number (void) +{ + // The vector is not not part of the GDB register set so get it + // directly from the save context. + return _hal_registers->vector >> 8; +} + +// 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; +} + + +/* Set the currently-saved pc register value to PC. This also updates NPC + as needed. */ + +void set_pc (target_register_t pc) +{ + put_register (PC, pc); +} + + +/*---------------------------------------------------------------------- + * Single-step support + */ + +/* Set things up so that the next user resume will execute one instruction. + This may be done by setting breakpoints or setting a single step flag + in the saved user registers, for example. */ + +static target_register_t irq_state; + +void single_step (void) +{ + target_register_t msr = get_register (PS); + + // Set single-step flag in the exception context. + msr |= (MSR_SE | MSR_BE); + // Disable interrupts. + irq_state = msr & MSR_EE; + msr &= ~MSR_EE; + + put_register (PS, msr); +} + +/* Clear the single-step state. */ + +void clear_single_step (void) +{ + target_register_t msr = get_register (PS); + + // Clear single-step flag in the exception context. + msr &= ~(MSR_SE | MSR_BE); + // Restore interrupt state. + // FIXME: Should check whether the executed instruction changed the + // interrupt state - or single-stepping a MSR changing instruction + // may result in a wrong EE. Not a very likely scenario though. + msr |= irq_state; + + put_register (PS, msr); +} + + +void install_breakpoints (void) +{ + /* NOP since single-step HW exceptions are used instead of + breakpoints. */ +} + + +/* If the breakpoint we hit is in the breakpoint() instruction, return a + non-zero value. */ + +int +__is_breakpoint_function () +{ + return get_register (PC) == (target_register_t)&_breakinst; +} + + +/* Skip the current instruction. Since this is only called by the + stub when the PC points to a breakpoint or trap instruction, + we can safely just skip 4. */ + +void __skipinst (void) +{ + put_register (PC, get_register (PC) + 4); +} + + +/* 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++ = ':'; + + id = dbg_currthread_id (); + 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; +} + +#endif // CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
