xscale_stub.c
来自「eCos操作系统源码」· C语言 代码 · 共 785 行 · 第 1/2 页
C
785 行
return wa0; else if (val == wd1) return wa1; } } } return wa0; // 50% chance of being right } else addr = get_register(Rn) - size; break; case 0x6000: // STR Rd, [Rn, #5bit] case 0x7000: // STRB Rd, [Rn, #5bit] case 0x8000: // STRH Rd, [Rn, #5bit] is_store = 1; case 0x6800: // LDR Rd, [Rn, #5bit] case 0x7800: // LDRB Rd, [Rn, #5bit] case 0x8800: // LDRH Rd, [Rn, #5bit] Rd = opcode & 7; Rn = (opcode >> 3) & 7; if ((opcode & 0xf000) == 0x6000) size = 4; else if ((opcode & 0xf000) == 0x8000) size = 2; else size = 1; if (!is_store && Rd == Rn) { // We can't reconstruct address from opcode because base // or offset register was destroyed. Best we can do is try // to match data at watchpoint addresses with data in Rd. use_val = 1; val = get_register(Rd); } else { offset = ((opcode >> 6) & 0x1f) * size; addr = get_register(Rn) + offset; } break; case 0x4800: // LDR Rd, [PC, #8bit] size = 4; addr = pc + 4 + ((opcode & 0xff) * 4); break; case 0x9000: // STR Rd, [SP, #8bit] is_store = 1; case 0x9800: // LDR Rd, [SP, #8bit] size = 4; addr = get_register(SP) + ((opcode & 0xff) * 4); break; default: switch (opcode_fe) { case 0x5000: // STR Rd, [Rn, Rm] case 0x5400: // STRB Rd, [Rn, Rm] case 0x5200: // STRH Rd, [Rn, Rm] is_store = 1; case 0x5600: // LDRSB Rd, [Rn, Rm] case 0x5800: // LDR Rd, [Rn, Rm] case 0x5c00: // LDRB Rd, [Rn, Rm] case 0x5a00: // LDRH Rd, [Rn, Rm] case 0x5e00: // LDRSH Rd, [Rn, Rm] Rd = opcode & 7; Rn = (opcode >> 3) & 7; Rm = (opcode >> 6) & 7; size = _sztab[(opcode >> 9) & 7]; if (!is_store && (Rd == Rn || Rd == Rm)) { // We can't reconstruct address from opcode because base // or offset register was destroyed. Best we can do is try // to match data at watchpoint addresses with data in Rd. use_val = 1; val = get_register(Rd); } else addr = Rn + Rm; break; case 0xb400: // PUSH is_store = 1; case 0xbc00: // POP for (i = 0; i < 9; i++) if (opcode & (1 << i)) size += 4; addr = get_register(SP); if (!is_store) addr -= size; break; } break; } if (use_val) { // We can read from watchpoint addresses and compare against // whatever is in the Rd from a load. This is not perfect, // but its the best we can do. if (wval_match(wa0, val, size)) return wa0; if (wval_match(wa1, val, size)) return wa1; } else if (size) { if (waddr_match(wa0, addr, size)) return wa0; if (waddr_match(wa1, addr, size)) return wa1; } return wa0; // should never happen, but return valid address}// Given the watch addresses and watch modes for each of the enabled// watchpoints, figure out which one triggered the current exception.static unsignedfind_watch_address(unsigned wa0, int mode0, unsigned wa1, int mode1){ unsigned pc = get_register(PC) - 4; unsigned cpsr = get_register(PS); unsigned opcode, Rn, Rd, Rm, base, addr, val = 0, wd0, wd1; int is_store, use_val, i, offset, shift, size; if (cpsr & CPSR_THUMB_ENABLE) is_store = is_thumb_store_insn(pc); else is_store = is_store_insn(pc); // First try the easy cases where all we need to know is whether or // not the instruction is a load or store. if ((mode0 == WATCH_MODE_READ && mode1 == WATCH_MODE_WRITE) || (mode1 == WATCH_MODE_READ && mode0 == WATCH_MODE_WRITE)) { if (is_store) return (mode0 == WATCH_MODE_WRITE) ? wa0 : wa1; else return (mode0 == WATCH_MODE_READ) ? wa0 : wa1; } if ((mode0 == WATCH_MODE_READ && is_store) || (mode0 == WATCH_MODE_WRITE && !is_store)) return wa1; if ((mode1 == WATCH_MODE_READ && is_store) || (mode1 == WATCH_MODE_WRITE && !is_store)) return wa0; // Okay. Now try to figure out address by decoding the opcode. if (cpsr & CPSR_THUMB_ENABLE) return find_thumb_watch_address(wa0, mode0, wa1, mode1); opcode = *(unsigned *)pc; Rn = (opcode >> 16) & 15; Rd = (opcode >> 12) & 15; Rm = opcode & 15; size = use_val = 0; addr = 0; if ((opcode & 0x0fb00ff0) == 0x01000090) { // SWP xxxx 0001 0B00 _Rn_ _Rd_ 0000 1001 _Rm_ addr = get_register(Rn); size = (opcode & B_bit) ? 1 : 4; } else 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 size = (opcode & B_bit) ? 1 : 4; if ((opcode & (P_bit | W_bit)) == (P_bit | W_bit)) { // This is easy because address is written back to Rn addr = get_register(Rn); } else if (!is_store && (Rd == Rn || ((opcode & I_bit) && Rd == Rm))) { // We can't reconstruct address from opcode because base // or offset register was destroyed. Best we can do is try // to match data at watchpoint addresses with data in Rd. use_val = 1; val = get_register(Rd); } else { if (opcode & I_bit) { shift = (opcode >> 7) & 0x1f; offset = get_register(Rm); switch ((opcode >> 5) & 3) { case 0: offset <<= shift; break; case 1: offset >>= shift; offset &= (0xffffffffU >> shift); break; case 2: offset >>= shift; break; case 3: if (shift) { for (i = 0; i < shift; i++) offset = ((offset >> 1) & 0x7fffffff) | ((offset & 1) << 31); } else { offset >>= 1; offset &= 0x80000000; offset |= ((cpsr & 0x20000000) << 2); } break; } } else offset = opcode & 0xfff; if ((opcode & U_bit) == 0) offset = -offset; if (Rn == 15) base = pc + 8; else base = get_register(Rn); if (opcode & P_bit) addr = base + offset; // pre-index else addr = base - offset; // post-index writeback size = (opcode & B_bit) ? 1 : 4; } } else 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 size = (opcode & (1 << 5)) ? 2 : 1; if ((opcode & (P_bit | W_bit)) == (P_bit | W_bit)) { // This is easy because address is written back to Rn addr = get_register(Rn); } if (!is_store && (Rd == Rn || ((opcode & (1 << 22)) && Rd == Rm))) { // We can't reconstruct address from opcode because base // or offset register was destroyed. Best we can do is try // to match data at watchpoint addresses with data in Rd. use_val = 1; val = get_register(Rd); } else { if (opcode & (1 << 22)) offset = ((opcode >> 4) & 0xf0) | (opcode & 0x0f); else offset = get_register(opcode & 15); if ((opcode & U_bit) == 0) offset = -offset; if (Rn == 15) base = pc + 8; else base = get_register(Rn); if (opcode & P_bit) addr = base + offset; // pre-index else addr = base - offset; // post-index writeback } } else if ((opcode & 0x0e000000) == 0x08000000) { // LDM/STM xxxx 100P USWL _Rn_ rrrr rrrr rrrr rrrr for (i = size = 0; i < 16; i++) if (opcode & (1 << i)) size += 4; base = get_register(Rn); 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 < 16; i++) { if (opcode & (1 << i)) { val = get_register(i); if (val == wd0) return wa0; else if (val == wd1) return wa1; } } } return wa0; // 50% chance of being right } else { if (opcode & U_bit){ if (opcode & W_bit) addr = base - size; else addr = base; if (opcode & P_bit) addr += 4; } else { if (opcode & W_bit) addr = base; else addr = base - size; if ((opcode & P_bit) == 0) addr += 4; } } } else if ((opcode & 0x0e000000) == 0x0c000000) { // LDC/STC xxxx 110P UNWL _Rn_ CRd_ CP#_ iiii iiii size = 4; offset = (opcode & 0xff) * 4; if ((opcode & U_bit) == 0) offset = -offset; if ((opcode & P_bit) && (opcode & W_bit)) addr = get_register(Rn); else addr = get_register(Rn) + offset; } if (use_val) { // We can read from watchpoint addresses and compare against // whatever is in the Rd from a load. This is not perfect, // but its the best we can do. if (wval_match(wa0, val, size)) return wa0; if (wval_match(wa1, val, size)) return wa1; } else { if (waddr_match(wa0, addr, size)) return wa0; if (waddr_match(wa1, addr, size)) return wa1; } return wa0; // should never happen, but return valid address}#endif// Return indication of whether or not we stopped because of a// watchpoint or hardware breakpoint. If stopped by a watchpoint,// also set '*data_addr_p' to the data address which triggered the// watchpoint.int cyg_hal_plf_is_stopped_by_hardware(void **data_addr_p){ unsigned fsr, dcsr, dbcon, kind = 0; // Check for debug event asm volatile ("mrc p15,0,%0,c5,c0,0" : "=r"(fsr) : ); if ((fsr & 0x200) == 0) return HAL_STUB_HW_STOP_NONE; // There was a debug event. Check the MOE for details dcsr = get_dcsr(); switch ((dcsr >> 2) & 7) { case 1: // HW breakpoint case 3: // BKPT breakpoint return HAL_STUB_HW_STOP_BREAK; case 2: // Watchpoint dbcon = get_dbcon();#if HAL_STUB_HW_WATCHPOINT_LIST_SIZE == 2 if (dbcon & 0x100) {#endif if ((kind = (dbcon & 3)) != WATCH_MODE_NONE) *data_addr_p = (void *)get_dbr0();#if HAL_STUB_HW_WATCHPOINT_LIST_SIZE == 2 } else { // This can get tricky because the debug unit offers no way to // tell which watchpoint triggered. if ((kind = (dbcon & 3)) == WATCH_MODE_NONE) { if ((kind = ((dbcon >> 2) & 3)) != WATCH_MODE_NONE) *data_addr_p = (void *)get_dbr1(); } else if ((kind = ((dbcon >> 2) & 3)) == WATCH_MODE_NONE) { if ((kind = (dbcon & 3)) != WATCH_MODE_NONE) *data_addr_p = (void *)get_dbr0(); } else { // This is the tricky part. We have to look at the trapping // opcode (which has already issued) to try to see if we can // tell which watchpoint triggered. Turn off watchpoints while // we figure this out. set_dcsr(dcsr & ~0x80000000); *data_addr_p = (void *)find_watch_address(get_dbr0(), dbcon & 3, get_dbr1(), (dbcon >> 2) & 3); set_dcsr(dcsr); if (*data_addr_p == (void *)get_dbr0()) kind = dbcon & 3; else if (*data_addr_p == (void *)get_dbr1()) kind = (dbcon >> 2) & 3; else kind = WATCH_MODE_NONE; } }#endif if (kind == WATCH_MODE_WRITE) return HAL_STUB_HW_STOP_WATCH; if (kind == WATCH_MODE_ACCESS) return HAL_STUB_HW_STOP_AWATCH; if (kind == WATCH_MODE_READ) return HAL_STUB_HW_STOP_RWATCH; // should never get here break; } return HAL_STUB_HW_STOP_NONE;}#endif // CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS/*------------------------------------------------------------------------*/// EOF xscale_stub.c
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?