xscale_stub.c
来自「eCos操作系统源码」· C语言 代码 · 共 785 行 · 第 1/2 页
C
785 行
//==========================================================================//// xscale_stub.c//// HAL stub support code for Intel XScale cores.////==========================================================================//####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): msalter// Contributors: msalter// Date: 2002-10-18// Purpose: XScale core stub support// Description: Implementations of HW debugging support.////####DESCRIPTIONEND####////========================================================================*/#include <pkgconf/hal.h>#include <pkgconf/system.h>#include <cyg/infra/diag.h>#include <cyg/hal/hal_stub.h> // Stub macros#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS/*------------------------------------------------------------------------*/// HW Debug support// Define this to support two watchpoints. If not defined, one watchpoint with// a power of two range is supported.#define USE_TWO_WATCHPOINTS 1static inline void set_ibcr0(unsigned x){ asm volatile ("mcr p15,0,%0,c14,c8,0" : : "r"(x) );}static inline unsigned get_ibcr0(void){ unsigned x; asm volatile ("mrc p15,0,%0,c14,c8,0" : "=r"(x) : ); return x;}static inline void set_ibcr1(unsigned x){ asm volatile ("mcr p15,0,%0,c14,c9,0" : : "r"(x) );}static inline unsigned get_ibcr1(void){ unsigned x; asm volatile ("mrc p15,0,%0,c14,c9,0" : "=r"(x) : ); return x;}static inline void set_dbr0(unsigned x){ asm volatile ("mcr p15,0,%0,c14,c0,0" : : "r"(x) );}static inline unsigned get_dbr0(void){ unsigned x; asm volatile ("mrc p15,0,%0,c14,c0,0" : "=r"(x) : ); return x;}static inline void set_dbr1(unsigned x){ asm volatile ("mcr p15,0,%0,c14,c3,0" : : "r"(x) );}static inline unsigned get_dbr1(void){ unsigned x; asm volatile ("mrc p15,0,%0,c14,c3,0" : "=r"(x) : ); return x;}static inline void set_dbcon(unsigned x){ asm volatile ("mcr p15,0,%0,c14,c4,0" : : "r"(x) );}static inline unsigned get_dbcon(void){ unsigned x; asm volatile ("mrc p15,0,%0,c14,c4,0" : "=r"(x) : ); return x;}static inline void set_dcsr(unsigned x){ asm volatile ("mcr p14,0,%0,c10,c0,0" : : "r"(x) );}static inline unsigned get_dcsr(void){ unsigned x; asm volatile ("mrc p14,0,%0,c10,c0,0" : "=r"(x) : ); return x;}int cyg_hal_plf_hw_breakpoint(int setflag, void *vaddr, int len){ unsigned int addr = (unsigned)vaddr; if (setflag) { if (!(get_ibcr0() & 1)) set_ibcr0(addr | 1); else if (!(get_ibcr1() & 1)) set_ibcr1(addr | 1); else return -1; } else { unsigned x = (addr | 1); if (get_ibcr0() == x) set_ibcr0(0); else if (get_ibcr1() == x) set_ibcr1(0); else return -1; } return 0;}#define WATCH_MODE_NONE 0#define WATCH_MODE_WRITE 1#define WATCH_MODE_ACCESS 2#define WATCH_MODE_READ 3#ifndef HAL_STUB_HW_WATCHPOINT_LIST_SIZE#error#endifint cyg_hal_plf_hw_watchpoint(int setflag, void *vaddr, int len, int type){ unsigned int mode, addr = (unsigned)vaddr; unsigned dbcon = get_dbcon();#if HAL_STUB_HW_WATCHPOINT_LIST_SIZE == 1 unsigned int mask, bit_nr; mask = 0x80000000; bit_nr = 31; while (bit_nr) { if (len & mask) break; bit_nr--; mask >>= 1; } mask = ~(0xffffffff << bit_nr);#endif if (setflag) { /* set a watchpoint */ if (type == 2) mode = WATCH_MODE_WRITE; // break on write else if (type == 3) mode = WATCH_MODE_READ; // break on read else if (type == 4) mode = WATCH_MODE_ACCESS; // break on any access else return 1;#if HAL_STUB_HW_WATCHPOINT_LIST_SIZE == 1 mode |= 0x100;#endif if (!(dbcon & 3)) { set_dbr0(addr);#if HAL_STUB_HW_WATCHPOINT_LIST_SIZE == 1 set_dbr1(mask);#endif set_dbcon(dbcon | mode);#if HAL_STUB_HW_WATCHPOINT_LIST_SIZE == 2 } else if (!(dbcon & (3 << 2))) { set_dbr1(addr); set_dbcon(dbcon | (mode << 2));#endif } else return 1; } else { /* clear a watchpoint */ if ((dbcon & 3) && get_dbr0() == addr) set_dbcon(dbcon & ~3);#if HAL_STUB_HW_WATCHPOINT_LIST_SIZE == 2 else if ((dbcon & (3 << 2)) && get_dbr1() == addr) set_dbcon(dbcon & ~(3 << 2));#endif else return 1; } return 0;}#if HAL_STUB_HW_WATCHPOINT_LIST_SIZE == 2// The XScale hardware does not provide a way of positively identinfying// which of the two watchpoints triggered and exception. The following// code makes a best effort at determining this by decoding the opcode// of the instruction which caused the watchpoint trigger. It is *not*// 100% reliable.// Some bits common to most ld/st instructions.#define I_bit (1 << 25)#define P_bit (1 << 24)#define U_bit (1 << 23)#define B_bit (1 << 22)#define W_bit (1 << 21)#define L_bit (1 << 20)// Return non-zero if opcode at given PC is a store instruction for// purposes of triggering watchpoints.static intis_store_insn(unsigned pc){ unsigned opcode = *(unsigned *)pc; if ((opcode & 0x0fb00ff0) == 0x01000090) { // SWP xxxx 0001 0B00 _Rn_ _Rd_ 0000 1001 _Rm_ return 1; } if ((opcode & 0x0c000000) == 0x04000000) { // LDR/STR xxxx 010P UBWL _Rn_ _Rd_ iiii iiii iiii // LDR/STR xxxx 011P UBWL _Rn_ _Rd_ ssss sSh0 _Rm_ // Addressing mode 2, Load/Store word or unsigned byte return (opcode & L_bit) == 0; } if ((opcode & 0x0e000090) == 0x00000090 && (opcode & 0x00000060) && ((opcode & (1 << 22)) || (opcode & 0x00000f00) == 0) && ((opcode & (P_bit | W_bit)) != W_bit)) { // LDR/STR xxxx 000P U1WL _Rn_ _Rd_ iiii 1SH1 iiii // LDR/STR xxxx 000P U0WL _Rn_ _Rd_ 0000 1SH1 _Rm_ // Addressing Mode 3, Load/Store halfword, load signed byte return (opcode & L_bit) == 0; } if ((opcode & 0x0e000000) == 0x08000000) { // LDM/STM xxxx 100P USWL _Rn_ rrrr rrrr rrrr rrrr return (opcode & L_bit) == 0; } if ((opcode & 0x0e000000) == 0x0c000000) { // LDC/STC xxxx 110P UNWL _Rn_ CRd_ CP#_ iiii iiii return (opcode & L_bit) == 0; } return 0;}static intis_thumb_store_insn(unsigned pc){ unsigned short opcode = *(unsigned short *)pc; opcode &= 0xfe00; if (opcode == 0xb400) return 1; // PUSH if (opcode == 0x5000) return 1; // STR Rd, [Rn, Rm] if (opcode == 0x5400) return 1; // STRB Rd, [Rn, Rm] if (opcode == 0x5200) return 1; // STRH Rd, [Rn, Rm] opcode &= 0xf800; if (opcode == 0xc000) return 1; // STM if (opcode == 0x6000) return 1; // STR Rd, [Rn, #5bit_offset] if (opcode == 0x9000) return 1; // STR Rd, [SP, #8bit_offset] if (opcode == 0x7000) return 1; // STRB Rd, [Rn, #5bit_offset] if (opcode == 0x8000) return 1; // STRH Rd, [Rn, #5bit_offset] return 0;}// Return non-zero if given waddr matches an access at addr.static intwaddr_match(unsigned waddr, unsigned addr, int size){ if (addr <= waddr && waddr < (addr + size)) return 1; return 0;}// Return non-zero if given value matches value at watchpoint address.static intwval_match(unsigned waddr, unsigned val, int size){ unsigned wval = *(unsigned *)(waddr & ~3); int i; if (size == 4) return (wval == val); if (size == 2) { val &= 0xffff; return ((wval & 0xffff) == val || ((wval >> 16) == val)); } if (size == 1) { val &= 0xff; for (i = 0; i < 4; i++) { if ((wval & 0xff) == val) return 1; wval >>= 8; } } return 0;}static char _sztab[8] = { 4, 2, 1, 1, 4, 2, 1, 2 };// Given the watch addresses and watch modes for each of the enabled// watchpoints, figure out which one triggered the current exception.static unsignedfind_thumb_watch_address(unsigned wa0, int mode0, unsigned wa1, int mode1){ unsigned pc = get_register(PC) - 4; unsigned short opcode = *(unsigned short *)pc; unsigned short opcode_f8, opcode_fe; unsigned val, wd0, wd1, addr = 0; int is_store, use_val, i, offset, size, Rn, Rd, Rm; opcode_f8 = opcode & 0xf800; opcode_fe = opcode & 0xfe00; size = 0; is_store = 0; val = use_val = 0; switch (opcode_f8) { case 0xc000: // STMIA Rn!, <list> is_store = 1; case 0xc800: // LDMIA Rn!, <list> Rn = (opcode >> 8) & 7; is_store = (opcode & 0x800) == 0; for (i = 0; i < 8; i++) if (opcode & (1 << i)) size += 4; if (!is_store && (opcode & (1 << Rn))) { // We can't reconstruct address from opcode because base // was destroyed. Best we can do is try to match data at // watchpoint addresses with data in one of the registers. wd0 = *(unsigned *)(wa0 & ~3); wd1 = *(unsigned *)(wa1 & ~3); if (wd0 != wd1) { for (i = size = 0; i < 8; i++) { if (opcode & (1 << i)) { val = get_register(i); if (val == wd0)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?