📄 arm_stub.c
字号:
//========================================================================//// arm_stub.c//// Helper functions for stub, generic to all ARM processors////========================================================================//####ECOSGPLCOPYRIGHTBEGIN####// -------------------------------------------// This file is part of eCos, the Embedded Configurable Operating System.// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.//// eCos is free software; you can redistribute it and/or modify it under// the terms of the GNU General Public License as published by the Free// Software Foundation; either version 2 or (at your option) any later version.//// eCos is distributed in the hope that it will be useful, but WITHOUT ANY// WARRANTY; without even the implied warranty of MERCHANTABILITY or// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License// for more details.//// You should have received a copy of the GNU General Public License along// with eCos; if not, write to the Free Software Foundation, Inc.,// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.//// As a special exception, if other files instantiate templates or use macros// or inline functions from this file, or you compile this file and link it// with other works to produce a work based on this file, this file does not// by itself cause the resulting work to be covered by the GNU General Public// License. However the source code for this file must still be made available// in accordance with section (3) of the GNU General Public License.//// This exception does not invalidate any other reasons why a work based on// this file might be covered by the GNU General Public License.//// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.// at http://sources.redhat.com/ecos/ecos-license/// -------------------------------------------//####ECOSGPLCOPYRIGHTEND####//========================================================================//#####DESCRIPTIONBEGIN####//// Author(s): Red Hat, gthomas// Contributors: Red Hat, gthomas, jskov// Date: 1998-11-26// Purpose: // Description: Helper functions for stub, generic to all ARM processors// Usage: ////####DESCRIPTIONEND####////========================================================================#include <stddef.h>#include <pkgconf/hal.h>#ifdef CYGPKG_REDBOOT#include <pkgconf/redboot.h>#endif#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS#ifdef CYGPKG_HAL_ARM_SIM#error "GDB Stub support not implemented for ARM SIM"#endif#include <cyg/hal/hal_stub.h>#include <cyg/hal/hal_arch.h>#include <cyg/hal/hal_intr.h>#ifndef FALSE#define FALSE 0#define TRUE 1#endif// Use bit 0 as a thumb-mode flag for next address to be executed.// Alternative would be to keep track of it using a C variable, but// since bit 0 is used by the BX instruction, we might as well do the// same thing and thus avoid checking two different flags.#define IS_THUMB_ADDR(addr) ((addr) & 1)#define MAKE_THUMB_ADDR(addr) ((addr) | 1)#define UNMAKE_THUMB_ADDR(addr) ((addr) & ~1)#ifdef CYGDBG_HAL_DEBUG_GDB_THREAD_SUPPORT#include <cyg/hal/dbg-threads-api.h> // dbg_currthread_id#endif#if defined(CYGNUM_HAL_BREAKPOINT_LIST_SIZE) && (CYGNUM_HAL_BREAKPOINT_LIST_SIZE > 0)cyg_uint32 __arm_breakinst = HAL_BREAKINST_ARM;cyg_uint16 __thumb_breakinst = HAL_BREAKINST_THUMB;#endif/* Given a trap value TRAP, return the corresponding signal. */int __computeSignal (unsigned int trap_number){ // Check to see if we stopped because of a hw watchpoint/breakpoint.#ifdef HAL_STUB_IS_STOPPED_BY_HARDWARE { void *daddr; if (HAL_STUB_IS_STOPPED_BY_HARDWARE(daddr)) return SIGTRAP; }#endif // should also catch CYGNUM_HAL_VECTOR_UNDEF_INSTRUCTION here but we // can't tell the different between a real one and a breakpoint :-( switch (trap_number) { case CYGNUM_HAL_VECTOR_ABORT_PREFETCH: // Fall through case CYGNUM_HAL_VECTOR_ABORT_DATA: // Fall through case CYGNUM_HAL_VECTOR_reserved: return SIGBUS; case CYGNUM_HAL_VECTOR_IRQ: case CYGNUM_HAL_VECTOR_FIQ: return SIGINT; default: return SIGTRAP; }}/* 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;}#if defined(CYGSEM_REDBOOT_BSP_SYSCALLS)int __is_bsp_syscall(void) { unsigned long pc = get_register(PC); unsigned long cpsr = get_register(PS); // condition codes if (_hal_registers->vector == CYGNUM_HAL_EXCEPTION_INTERRUPT) { if (cpsr & CPSR_THUMB_ENABLE) return *(unsigned short *)pc == 0xdf18; else return *(unsigned *)pc == 0xef180001; } return 0;}#endif/* Set the currently-saved pc register value to PC. */void set_pc (target_register_t pc){ put_register (PC, pc);}// Calculate byte offset a given register from start of register save area.static intreg_offset(regnames_t reg){ int base_offset; if (reg < F0) return reg * 4; base_offset = 16 * 4; if (reg < FPS) return base_offset + ((reg - F0) * 12); base_offset += (8 * 12); if (reg <= PS) return base_offset + ((reg - FPS) * 4); return -1; // Should never happen!}// Return the currently-saved value corresponding to register REG of// the exception context.target_register_t get_register (regnames_t reg){ target_register_t val; int offset = reg_offset(reg); if (REGSIZE(reg) > sizeof(target_register_t) || offset == -1) return -1; val = _registers[offset/sizeof(target_register_t)]; return val;}// Store VALUE in the register corresponding to WHICH in the exception// context.void put_register (regnames_t which, target_register_t value){ int offset = reg_offset(which); if (REGSIZE(which) > sizeof(target_register_t) || offset == -1) return; _registers[offset/sizeof(target_register_t)] = value;}// Write the contents of register WHICH into VALUE as raw bytes. This// is only used for registers larger than sizeof(target_register_t).// Return non-zero if it is a valid register.intget_register_as_bytes (regnames_t which, char *value){ int offset = reg_offset(which); if (offset != -1) { memcpy (value, (char *)_registers + offset, REGSIZE(which)); return 1; } return 0;}// Alter the contents of saved register WHICH to contain VALUE. This// is only used for registers larger than sizeof(target_register_t).// Return non-zero if it is a valid register.intput_register_as_bytes (regnames_t which, char *value){ int offset = reg_offset(which); if (offset != -1) { memcpy ((char *)_registers + offset, value, REGSIZE(which)); return 1; } return 0;}/*---------------------------------------------------------------------- * 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 unsigned long ss_saved_pc = 0;static unsigned long ss_saved_instr;static unsigned short ss_saved_thumb_instr;#define FIXME() {diag_printf("FIXME - %s\n", __FUNCTION__); }// return non-zero for v5 and laterstatic intv5T_semantics(void){ unsigned id; asm volatile ("mrc p15,0,%0,c0,c0,0\n" : "=r" (id) : /* no inputs */); return ((id >> 16) & 0xff) >= 5;}static intins_will_execute(unsigned long ins){ unsigned long psr = get_register(PS); // condition codes int res = 0; switch ((ins & 0xF0000000) >> 28) { case 0x0: // EQ res = (psr & PS_Z) != 0; break; case 0x1: // NE res = (psr & PS_Z) == 0; break; case 0x2: // CS res = (psr & PS_C) != 0; break; case 0x3: // CC res = (psr & PS_C) == 0; break; case 0x4: // MI res = (psr & PS_N) != 0; break; case 0x5: // PL res = (psr & PS_N) == 0; break; case 0x6: // VS res = (psr & PS_V) != 0; break; case 0x7: // VC res = (psr & PS_V) == 0; break; case 0x8: // HI res = ((psr & PS_C) != 0) && ((psr & PS_Z) == 0); break; case 0x9: // LS res = ((psr & PS_C) == 0) || ((psr & PS_Z) != 0); break; case 0xA: // GE res = ((psr & (PS_N|PS_V)) == (PS_N|PS_V)) || ((psr & (PS_N|PS_V)) == 0); break; case 0xB: // LT res = ((psr & (PS_N|PS_V)) == PS_N) || ((psr & (PS_N|PS_V)) == PS_V); break; case 0xC: // GT res = ((psr & (PS_N|PS_V)) == (PS_N|PS_V)) || ((psr & (PS_N|PS_V)) == 0); res = ((psr & PS_Z) == 0) && res; break; case 0xD: // LE res = ((psr & (PS_N|PS_V)) == PS_N) || ((psr & (PS_N|PS_V)) == PS_V); res = ((psr & PS_Z) == PS_Z) || res; break; case 0xE: // AL res = TRUE; break; case 0xF: // NV if (((ins & 0x0E000000) >> 24) == 0xA) res = TRUE; else res = FALSE; break; } return res;}static unsigned longRmShifted(int shift){ unsigned long Rm = get_register(shift & 0x00F); int shift_count; if ((shift & 0x010) == 0) { shift_count = (shift & 0xF80) >> 7; } else { shift_count = get_register((shift & 0xF00) >> 8); } switch ((shift & 0x060) >> 5) { case 0x0: // Logical left Rm <<= shift_count; break; case 0x1: // Logical right Rm >>= shift_count; break; case 0x2: // Arithmetic right Rm = (unsigned long)((long)Rm >> shift_count); break; case 0x3: // Rotate right if (shift_count == 0) { // Special case, RORx Rm >>= 1; if (get_register(PS) & PS_C) Rm |= 0x80000000; } else { Rm = (Rm >> shift_count) | (Rm << (32-shift_count)); } break; } return Rm;}// Decide the next instruction to be executed for a given instructionstatic unsigned long *target_ins(unsigned long *pc, unsigned long ins){ unsigned long new_pc, offset, op2; unsigned long Rn; int i, reg_count, c; switch ((ins & 0x0C000000) >> 26) { case 0x0: // BX or BLX if ((ins & 0x0FFFFFD0) == 0x012FFF10) { new_pc = (unsigned long)get_register(ins & 0x0000000F); return ((unsigned long *)new_pc); } // Data processing new_pc = (unsigned long)(pc+1); if ((ins & 0x0000F000) == 0x0000F000) { // Destination register is PC if ((ins & 0x0FBF0000) != 0x010F0000) { Rn = (unsigned long)get_register((ins & 0x000F0000) >> 16); if ((ins & 0x000F0000) == 0x000F0000) Rn += 8; // PC prefetch! if ((ins & 0x02000000) == 0) { op2 = RmShifted(ins & 0x00000FFF); } else { op2 = ins & 0x000000FF; i = (ins & 0x00000F00) >> 8; // Rotate count op2 = (op2 >> (i*2)) | (op2 << (32-(i*2))); } switch ((ins & 0x01E00000) >> 21) { case 0x0: // AND new_pc = Rn & op2; break; case 0x1: // EOR new_pc = Rn ^ op2; break; case 0x2: // SUB new_pc = Rn - op2; break; case 0x3: // RSB new_pc = op2 - Rn; break; case 0x4: // ADD new_pc = Rn + op2; break; case 0x5: // ADC c = (get_register(PS) & PS_C) != 0; new_pc = Rn + op2 + c; break; case 0x6: // SBC c = (get_register(PS) & PS_C) != 0; new_pc = Rn - op2 + c - 1; break; case 0x7: // RSC c = (get_register(PS) & PS_C) != 0; new_pc = op2 - Rn +c - 1; break; case 0x8: // TST case 0x9: // TEQ case 0xA: // CMP case 0xB: // CMN break; // PC doesn't change case 0xC: // ORR new_pc = Rn | op2; break; case 0xD: // MOV new_pc = op2; break; case 0xE: // BIC new_pc = Rn & ~op2; break; case 0xF: // MVN new_pc = ~op2; break; } } } return ((unsigned long *)new_pc); case 0x1: if ((ins & 0x02000010) == 0x02000010) { // Undefined! return (pc+1); } else { if ((ins & 0x00100000) == 0) { // STR return (pc+1); } else { // LDR if ((ins & 0x0000F000) != 0x0000F000) { // Rd not PC return (pc+1); } else { Rn = (unsigned long)get_register((ins & 0x000F0000) >> 16);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -