X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Ftarget%2Fetm.c;h=7384764aa1f4f1ed9b46077f898743420fbdd131;hb=89fa8ce2d8c58707f3dfda397138f8ee336e1a47;hp=a506d1c4cb193e822c9bc2b9fa23878179c0ede2;hpb=64934d9204dc854d40893634a66e29ece09ad578;p=openocd diff --git a/src/target/etm.c b/src/target/etm.c index a506d1c4..7384764a 100644 --- a/src/target/etm.c +++ b/src/target/etm.c @@ -446,12 +446,15 @@ int etm_setup(struct target *target) etm_ctrl_value = (etm_ctrl_value & ~ETM_PORT_WIDTH_MASK & ~ETM_PORT_MODE_MASK + & ~ETM_CTRL_DBGRQ & ~ETM_PORT_CLOCK_MASK) | etm_ctx->control; buf_set_u32(etm_ctrl_reg->value, 0, 32, etm_ctrl_value); etm_store_reg(etm_ctrl_reg); + etm_ctx->control = etm_ctrl_value; + if ((retval = jtag_execute_queue()) != ERROR_OK) return retval; @@ -493,6 +496,7 @@ static int etm_read_reg_w_check(struct reg *reg, const struct etm_reg_info *r = etm_reg->reg_info; uint8_t reg_addr = r->addr & 0x7f; struct scan_field fields[3]; + int retval; if (etm_reg->reg_info->mode == WO) { LOG_ERROR("BUG: can't read write-only register %s", r->name); @@ -501,43 +505,42 @@ static int etm_read_reg_w_check(struct reg *reg, LOG_DEBUG("%s (%u)", r->name, reg_addr); - jtag_set_end_state(TAP_IDLE); - arm_jtag_scann(etm_reg->jtag_info, 0x6); - arm_jtag_set_instr(etm_reg->jtag_info, etm_reg->jtag_info->intest_instr, NULL); + retval = arm_jtag_scann(etm_reg->jtag_info, 0x6, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + retval = arm_jtag_set_instr(etm_reg->jtag_info, etm_reg->jtag_info->intest_instr, NULL, TAP_IDLE); + if (retval != ERROR_OK) + return retval; - fields[0].tap = etm_reg->jtag_info->tap; fields[0].num_bits = 32; fields[0].out_value = reg->value; fields[0].in_value = NULL; fields[0].check_value = NULL; fields[0].check_mask = NULL; - fields[1].tap = etm_reg->jtag_info->tap; fields[1].num_bits = 7; - fields[1].out_value = malloc(1); - buf_set_u32(fields[1].out_value, 0, 7, reg_addr); + uint8_t temp1; + fields[1].out_value = &temp1; + buf_set_u32(&temp1, 0, 7, reg_addr); fields[1].in_value = NULL; fields[1].check_value = NULL; fields[1].check_mask = NULL; - fields[2].tap = etm_reg->jtag_info->tap; fields[2].num_bits = 1; - fields[2].out_value = malloc(1); - buf_set_u32(fields[2].out_value, 0, 1, 0); + uint8_t temp2; + fields[2].out_value = &temp2; + buf_set_u32(&temp2, 0, 1, 0); fields[2].in_value = NULL; fields[2].check_value = NULL; fields[2].check_mask = NULL; - jtag_add_dr_scan(3, fields, jtag_get_end_state()); + jtag_add_dr_scan(etm_reg->jtag_info->tap, 3, fields, TAP_IDLE); fields[0].in_value = reg->value; fields[0].check_value = check_value; fields[0].check_mask = check_mask; - jtag_add_dr_scan_check(3, fields, jtag_get_end_state()); - - free(fields[1].out_value); - free(fields[2].out_value); + jtag_add_dr_scan_check(etm_reg->jtag_info->tap, 3, fields, TAP_IDLE); return ERROR_OK; } @@ -579,6 +582,7 @@ static int etm_write_reg(struct reg *reg, uint32_t value) const struct etm_reg_info *r = etm_reg->reg_info; uint8_t reg_addr = r->addr & 0x7f; struct scan_field fields[3]; + int retval; if (etm_reg->reg_info->mode == RO) { LOG_ERROR("BUG: can't write read--only register %s", r->name); @@ -587,32 +591,32 @@ static int etm_write_reg(struct reg *reg, uint32_t value) LOG_DEBUG("%s (%u): 0x%8.8" PRIx32 "", r->name, reg_addr, value); - jtag_set_end_state(TAP_IDLE); - arm_jtag_scann(etm_reg->jtag_info, 0x6); - arm_jtag_set_instr(etm_reg->jtag_info, etm_reg->jtag_info->intest_instr, NULL); + retval = arm_jtag_scann(etm_reg->jtag_info, 0x6, TAP_IDLE); + if (retval != ERROR_OK) + return retval; + retval = arm_jtag_set_instr(etm_reg->jtag_info, etm_reg->jtag_info->intest_instr, NULL, TAP_IDLE); + if (retval != ERROR_OK) + return retval; - fields[0].tap = etm_reg->jtag_info->tap; fields[0].num_bits = 32; uint8_t tmp1[4]; fields[0].out_value = tmp1; - buf_set_u32(fields[0].out_value, 0, 32, value); + buf_set_u32(tmp1, 0, 32, value); fields[0].in_value = NULL; - fields[1].tap = etm_reg->jtag_info->tap; fields[1].num_bits = 7; uint8_t tmp2; fields[1].out_value = &tmp2; - buf_set_u32(fields[1].out_value, 0, 7, reg_addr); + buf_set_u32(&tmp2, 0, 7, reg_addr); fields[1].in_value = NULL; - fields[2].tap = etm_reg->jtag_info->tap; fields[2].num_bits = 1; uint8_t tmp3; fields[2].out_value = &tmp3; - buf_set_u32(fields[2].out_value, 0, 1, 1); + buf_set_u32(&tmp3, 0, 1, 1); fields[2].in_value = NULL; - jtag_add_dr_scan(3, fields, jtag_get_end_state()); + jtag_add_dr_scan(etm_reg->jtag_info->tap, 3, fields, TAP_IDLE); return ERROR_OK; } @@ -665,7 +669,7 @@ static int etm_read_instruction(struct etm_context *ctx, struct arm_instruction ctx->current_pc - ctx->image->sections[section].base_address, 4, buf, &size_read)) != ERROR_OK) { - LOG_ERROR("error while reading instruction: %i", retval); + LOG_ERROR("error while reading instruction"); return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; } opcode = target_buffer_get_u32(ctx->target, buf); @@ -678,7 +682,7 @@ static int etm_read_instruction(struct etm_context *ctx, struct arm_instruction ctx->current_pc - ctx->image->sections[section].base_address, 2, buf, &size_read)) != ERROR_OK) { - LOG_ERROR("error while reading instruction: %i", retval); + LOG_ERROR("error while reading instruction"); return ERROR_TRACE_INSTRUCTION_UNAVAILABLE; } opcode = target_buffer_get_u16(ctx->target, buf); @@ -888,6 +892,11 @@ static int etmv1_analyze_trace(struct etm_context *ctx, struct command_context * if (ctx->trace_depth == 0) ctx->capture_driver->read_trace(ctx); + if (ctx->trace_depth == 0) { + command_print(cmd_ctx, "Trace is empty."); + return ERROR_OK; + } + /* start at the beginning of the captured trace */ ctx->pipe_index = 0; ctx->data_index = 0; @@ -1256,12 +1265,16 @@ COMMAND_HANDLER(handle_etm_tracemode_command) case 0: break; case 4: - CALL_COMMAND_HANDLER(handle_etm_tracemode_command_update, &tracemode); + CALL_COMMAND_HANDLER(handle_etm_tracemode_command_update, + &tracemode); break; default: - command_print(CMD_CTX, "usage: configure trace mode " - " " - " "); + command_print(CMD_CTX, "usage: tracemode " + "('none'|'data'|'address'|'all') " + "context_id_bits " + "('enable'|'disable') " + "('enable'|'disable')" + ); return ERROR_FAIL; } @@ -1338,8 +1351,6 @@ COMMAND_HANDLER(handle_etm_tracemode_command) if (!etm_ctrl_reg) return ERROR_FAIL; - etm_get_reg(etm_ctrl_reg); - etm->control &= ~TRACEMODE_MASK; etm->control |= tracemode & TRACEMODE_MASK; @@ -1762,7 +1773,7 @@ COMMAND_HANDLER(handle_etm_image_command) if (CMD_ARGC >= 2) { etm_ctx->image->base_address_set = 1; - COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], etm_ctx->image->base_address); + COMMAND_PARSE_NUMBER(llong, CMD_ARGV[1], etm_ctx->image->base_address); } else { @@ -1886,7 +1897,15 @@ COMMAND_HANDLER(handle_etm_load_command) return ERROR_FAIL; } - if (file.size % 4) + int filesize; + int retval = fileio_size(&file, &filesize); + if (retval != ERROR_OK) + { + fileio_close(&file); + return retval; + } + + if (filesize % 4) { command_print(CMD_CTX, "size isn't a multiple of 4, no valid trace data"); fileio_close(&file); @@ -2016,6 +2035,56 @@ COMMAND_HANDLER(handle_etm_stop_command) return ERROR_OK; } +COMMAND_HANDLER(handle_etm_trigger_debug_command) +{ + struct target *target; + struct arm *arm; + struct etm_context *etm; + + target = get_current_target(CMD_CTX); + arm = target_to_arm(target); + if (!is_arm(arm)) + { + command_print(CMD_CTX, "ETM: %s isn't an ARM", + target_name(target)); + return ERROR_FAIL; + } + + etm = arm->etm; + if (!etm) + { + command_print(CMD_CTX, "ETM: no ETM configured for %s", + target_name(target)); + return ERROR_FAIL; + } + + if (CMD_ARGC == 1) { + struct reg *etm_ctrl_reg; + bool dbgrq; + + etm_ctrl_reg = etm_reg_lookup(etm, ETM_CTRL); + if (!etm_ctrl_reg) + return ERROR_FAIL; + + COMMAND_PARSE_ENABLE(CMD_ARGV[0], dbgrq); + if (dbgrq) + etm->control |= ETM_CTRL_DBGRQ; + else + etm->control &= ~ETM_CTRL_DBGRQ; + + /* etm->control will be written to hardware + * the next time an "etm start" is issued. + */ + buf_set_u32(etm_ctrl_reg->value, 0, 32, etm->control); + } + + command_print(CMD_CTX, "ETM: %s debug halt", + (etm->control & ETM_CTRL_DBGRQ) + ? "triggers" + : "does not trigger"); + return ERROR_OK; +} + COMMAND_HANDLER(handle_etm_analyze_command) { struct target *target; @@ -2040,6 +2109,7 @@ COMMAND_HANDLER(handle_etm_analyze_command) if ((retval = etmv1_analyze_trace(etm_ctx, CMD_CTX)) != ERROR_OK) { + /* FIX! error should be reported inside etmv1_analyze_trace() */ switch (retval) { case ERROR_ETM_ANALYSIS_FAILED: @@ -2052,7 +2122,7 @@ COMMAND_HANDLER(handle_etm_analyze_command) command_print(CMD_CTX, "no image available for trace analysis"); break; default: - command_print(CMD_CTX, "unknown error: %i", retval); + command_print(CMD_CTX, "unknown error"); } } @@ -2061,11 +2131,16 @@ COMMAND_HANDLER(handle_etm_analyze_command) static const struct command_registration etm_config_command_handlers[] = { { + /* NOTE: with ADIv5, ETMs are accessed by DAP operations, + * possibly over SWD, not JTAG scanchain 6 of 'target'. + * + * Also, these parameters don't match ETM v3+ modules... + */ .name = "config", - .handler = &handle_etm_config_command, + .handler = handle_etm_config_command, .mode = COMMAND_CONFIG, - .usage = " " - " ", + .help = "Set up ETM output port.", + .usage = "target port_width port_mode clocking capture_driver", }, COMMAND_REGISTRATION_DONE }; @@ -2081,57 +2156,69 @@ const struct command_registration etm_command_handlers[] = { static const struct command_registration etm_exec_command_handlers[] = { { - .name = "tracemode", handle_etm_tracemode_command, + .name = "tracemode", + .handler = handle_etm_tracemode_command, .mode = COMMAND_EXEC, .help = "configure/display trace mode", - .usage = " " - " ", + .usage = "('none'|'data'|'address'|'all') " + "context_id_bits " + "['enable'|'disable'] " + "['enable'|'disable']", }, { .name = "info", - .handler = &handle_etm_info_command, + .handler = handle_etm_info_command, .mode = COMMAND_EXEC, .help = "display info about the current target's ETM", }, { .name = "status", - .handler = &handle_etm_status_command, + .handler = handle_etm_status_command, .mode = COMMAND_EXEC, .help = "display current target's ETM status", }, { .name = "start", - .handler = &handle_etm_start_command, + .handler = handle_etm_start_command, .mode = COMMAND_EXEC, .help = "start ETM trace collection", }, { .name = "stop", - .handler = &handle_etm_stop_command, + .handler = handle_etm_stop_command, .mode = COMMAND_EXEC, .help = "stop ETM trace collection", }, + { + .name = "trigger_debug", + .handler = handle_etm_trigger_debug_command, + .mode = COMMAND_EXEC, + .help = "enable/disable debug entry on trigger", + .usage = "['enable'|'disable']", + }, { .name = "analyze", - .handler = &handle_etm_analyze_command, + .handler = handle_etm_analyze_command, .mode = COMMAND_EXEC, - .help = "anaylze collected ETM trace", + .help = "analyze collected ETM trace", }, { .name = "image", - .handler = &handle_etm_image_command, + .handler = handle_etm_image_command, .mode = COMMAND_EXEC, - .help = "load image from [base address]", + .help = "load image from file with optional offset", + .usage = "filename [offset]", }, { .name = "dump", - .handler = &handle_etm_dump_command, + .handler = handle_etm_dump_command, .mode = COMMAND_EXEC, - .help = "dump captured trace data ", + .help = "dump captured trace data to file", + .usage = "filename", }, { .name = "load", - .handler = &handle_etm_load_command, + .handler = handle_etm_load_command, .mode = COMMAND_EXEC, .help = "load trace data for analysis ", },