/** * Checks for and processes an ARM semihosting request. This is meant * to be called when the target is stopped due to a debug mode entry. * If the value 0 is returned then there was nothing to process. A non-zero * return value signifies that a request was processed and the target resumed, * or an error was encountered, in which case the caller must return * immediately. * * @param target Pointer to the ARM target to process. This target must * not represent an ARMv6-M or ARMv7-M processor. * @param retval Pointer to a location where the return code will be stored * @return non-zero value if a request was processed or an error encountered */ int arm_semihosting(struct target *target, int *retval) { struct arm *arm = target_to_arm(target); uint32_t pc, lr, spsr; struct reg *r; if (!arm->is_semihosting) return 0; if (is_arm7_9(target_to_arm7_9(target))) { if (arm->core_mode != ARM_MODE_SVC) return 0; /* Check for PC == 0x00000008 or 0xffff0008: Supervisor Call vector. */ r = arm->pc; pc = buf_get_u32(r->value, 0, 32); if (pc != 0x00000008 && pc != 0xffff0008) return 0; r = arm_reg_current(arm, 14); lr = buf_get_u32(r->value, 0, 32); /* Core-specific code should make sure SPSR is retrieved * when the above checks pass... */ if (!arm->spsr->valid) { LOG_ERROR("SPSR not valid!"); *retval = ERROR_FAIL; return 1; } spsr = buf_get_u32(arm->spsr->value, 0, 32); /* check instruction that triggered this trap */ if (spsr & (1 << 5)) { /* was in Thumb (or ThumbEE) mode */ uint8_t insn_buf[2]; uint16_t insn; *retval = target_read_memory(target, lr-2, 2, 1, insn_buf); if (*retval != ERROR_OK) return 1; insn = target_buffer_get_u16(target, insn_buf); /* SVC 0xab */ if (insn != 0xDFAB) return 0; } else if (spsr & (1 << 24)) { /* was in Jazelle mode */ return 0; } else { /* was in ARM mode */ uint8_t insn_buf[4]; uint32_t insn; *retval = target_read_memory(target, lr-4, 4, 1, insn_buf); if (*retval != ERROR_OK) return 1; insn = target_buffer_get_u32(target, insn_buf); /* SVC 0x123456 */ if (insn != 0xEF123456) return 0; } } else if (is_armv7m(target_to_armv7m(target))) { uint16_t insn; if (target->debug_reason != DBG_REASON_BREAKPOINT) return 0; r = arm->pc; pc = buf_get_u32(r->value, 0, 32); pc &= ~1; *retval = target_read_u16(target, pc, &insn); if (*retval != ERROR_OK) return 1; /* bkpt 0xAB */ if (insn != 0xBEAB) return 0; } else { LOG_ERROR("Unsupported semi-hosting Target"); return 0; } *retval = do_semihosting(target); return 1; }
/** * Checks for and processes an ARM semihosting request. This is meant * to be called when the target is stopped due to a debug mode entry. * If the value 0 is returned then there was nothing to process. A non-zero * return value signifies that a request was processed and the target resumed, * or an error was encountered, in which case the caller must return * immediately. * * @param target Pointer to the ARM target to process. This target must * not represent an ARMv6-M or ARMv7-M processor. * @param retval Pointer to a location where the return code will be stored * @return non-zero value if a request was processed or an error encountered */ int arm_semihosting(struct target *target, int *retval) { struct arm *arm = target_to_arm(target); struct armv7a_common *armv7a = target_to_armv7a(target); uint32_t pc, lr, spsr; struct reg *r; if (!arm->is_semihosting) return 0; if (is_arm7_9(target_to_arm7_9(target)) || is_armv7a(armv7a)) { uint32_t vbar = 0x00000000; if (arm->core_mode != ARM_MODE_SVC) return 0; if (is_armv7a(armv7a)) { struct arm_dpm *dpm = armv7a->arm.dpm; *retval = dpm->prepare(dpm); if (*retval == ERROR_OK) { *retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 0, 0, 12, 0, 0), &vbar); dpm->finish(dpm); if (*retval != ERROR_OK) return 1; } else { return 1; } } /* Check for PC == 0x00000008 or 0xffff0008: Supervisor Call vector. */ r = arm->pc; pc = buf_get_u32(r->value, 0, 32); if (pc != (vbar + 0x00000008) && pc != 0xffff0008) return 0; r = arm_reg_current(arm, 14); lr = buf_get_u32(r->value, 0, 32); /* Core-specific code should make sure SPSR is retrieved * when the above checks pass... */ if (!arm->spsr->valid) { LOG_ERROR("SPSR not valid!"); *retval = ERROR_FAIL; return 1; } spsr = buf_get_u32(arm->spsr->value, 0, 32); /* check instruction that triggered this trap */ if (spsr & (1 << 5)) { /* was in Thumb (or ThumbEE) mode */ uint8_t insn_buf[2]; uint16_t insn; *retval = target_read_memory(target, lr-2, 2, 1, insn_buf); if (*retval != ERROR_OK) return 1; insn = target_buffer_get_u16(target, insn_buf); /* SVC 0xab */ if (insn != 0xDFAB) return 0; } else if (spsr & (1 << 24)) { /* was in Jazelle mode */ return 0; } else { /* was in ARM mode */ uint8_t insn_buf[4]; uint32_t insn; *retval = target_read_memory(target, lr-4, 4, 1, insn_buf); if (*retval != ERROR_OK) return 1; insn = target_buffer_get_u32(target, insn_buf); /* SVC 0x123456 */ if (insn != 0xEF123456) return 0; } } else if (is_armv7m(target_to_armv7m(target))) { uint16_t insn; if (target->debug_reason != DBG_REASON_BREAKPOINT) return 0; r = arm->pc; pc = buf_get_u32(r->value, 0, 32); pc &= ~1; *retval = target_read_u16(target, pc, &insn); if (*retval != ERROR_OK) return 1; /* bkpt 0xAB */ if (insn != 0xBEAB) return 0; } else { LOG_ERROR("Unsupported semi-hosting Target"); return 0; } /* Perform semihosting if we are not waiting on a fileio * operation to complete. */ if (!arm->semihosting_hit_fileio) { *retval = do_semihosting(target); if (*retval != ERROR_OK) { LOG_ERROR("Failed semihosting operation"); return 0; } } /* Post result to target if we are not waiting on a fileio * operation to complete: */ if (!arm->semihosting_hit_fileio) { *retval = post_result(target); if (*retval != ERROR_OK) { LOG_ERROR("Failed to post semihosting result"); return 0; } *retval = target_resume(target, 1, 0, 0, 0); if (*retval != ERROR_OK) { LOG_ERROR("Failed to resume target"); return 0; } return 1; } return 0; }