int mips32_configure_break_unit(struct target *target) { /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); int retval; uint32_t dcr, bpinfo; int i; if (mips32->bp_scanned) return ERROR_OK; /* get info about breakpoint support */ retval = target_read_u32(target, EJTAG_DCR, &dcr); if (retval != ERROR_OK) return retval; if (dcr & EJTAG_DCR_IB) { /* get number of inst breakpoints */ retval = target_read_u32(target, EJTAG_IBS, &bpinfo); if (retval != ERROR_OK) return retval; mips32->num_inst_bpoints = (bpinfo >> 24) & 0x0F; mips32->num_inst_bpoints_avail = mips32->num_inst_bpoints; mips32->inst_break_list = calloc(mips32->num_inst_bpoints, sizeof(struct mips32_comparator)); for (i = 0; i < mips32->num_inst_bpoints; i++) mips32->inst_break_list[i].reg_address = EJTAG_IBA1 + (0x100 * i); /* clear IBIS reg */ retval = target_write_u32(target, EJTAG_IBS, 0); if (retval != ERROR_OK) return retval; }
static int mips32_configure_dbs(struct target *target) { struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; int retval, i; uint32_t bpinfo; /* get number of data breakpoints */ retval = target_read_u32(target, ejtag_info->ejtag_dbs_addr, &bpinfo); if (retval != ERROR_OK) return retval; mips32->num_data_bpoints = (bpinfo >> 24) & 0x0F; mips32->num_data_bpoints_avail = mips32->num_data_bpoints; mips32->data_break_list = calloc(mips32->num_data_bpoints, sizeof(struct mips32_comparator)); for (i = 0; i < mips32->num_data_bpoints; i++) mips32->data_break_list[i].reg_address = ejtag_info->ejtag_dba0_addr + (ejtag_info->ejtag_dba_step_size * i); /* clear DBIS reg */ retval = target_write_u32(target, ejtag_info->ejtag_dbs_addr, 0); return retval; }
int mips32_configure_break_unit(struct target *target) { /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; int retval; uint32_t dcr; if (mips32->bp_scanned) return ERROR_OK; /* get info about breakpoint support */ retval = target_read_u32(target, EJTAG_DCR, &dcr); if (retval != ERROR_OK) return retval; /* EJTAG 2.0 defines IB and DB bits in IMP instead of DCR. */ if (ejtag_info->ejtag_version == EJTAG_VERSION_20) { ejtag_info->debug_caps = dcr & EJTAG_DCR_ENM; if (!(ejtag_info->impcode & EJTAG_V20_IMP_NOIB)) ejtag_info->debug_caps |= EJTAG_DCR_IB; if (!(ejtag_info->impcode & EJTAG_V20_IMP_NODB)) ejtag_info->debug_caps |= EJTAG_DCR_DB; } else /* keep debug caps for later use */ ejtag_info->debug_caps = dcr & (EJTAG_DCR_ENM | EJTAG_DCR_IB | EJTAG_DCR_DB); if (ejtag_info->debug_caps & EJTAG_DCR_IB) { retval = mips32_configure_ibs(target); if (retval != ERROR_OK) return retval; } if (ejtag_info->debug_caps & EJTAG_DCR_DB) { retval = mips32_configure_dbs(target); if (retval != ERROR_OK) return retval; } /* check if target endianness settings matches debug control register */ if (((ejtag_info->debug_caps & EJTAG_DCR_ENM) && (target->endianness == TARGET_LITTLE_ENDIAN)) || (!(ejtag_info->debug_caps & EJTAG_DCR_ENM) && (target->endianness == TARGET_BIG_ENDIAN))) LOG_WARNING("DCR endianness settings does not match target settings"); LOG_DEBUG("DCR 0x%" PRIx32 " numinst %i numdata %i", dcr, mips32->num_inst_bpoints, mips32->num_data_bpoints); mips32->bp_scanned = 1; return ERROR_OK; }
int mips32_arch_state(struct target *target) { struct mips32_common *mips32 = target_to_mips32(target); LOG_USER("target halted in %s mode due to %s, pc: 0x%8.8" PRIx32 "", mips_isa_strings[mips32->isa_mode], debug_reason_name(target), buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32)); return ERROR_OK; }
static int mips32_get_core_reg(struct reg *reg) { int retval; struct mips32_core_reg *mips32_reg = reg->arch_info; struct target *target = mips32_reg->target; struct mips32_common *mips32_target = target_to_mips32(target); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; retval = mips32_target->read_core_reg(target, mips32_reg->num); return retval; }
int mips32_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class) { /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); unsigned int i; /* include floating point registers */ *reg_list_size = MIPS32_NUM_REGS; *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); for (i = 0; i < MIPS32_NUM_REGS; i++) (*reg_list)[i] = &mips32->core_cache->reg_list[i]; return ERROR_OK; }
static int mips32_read_core_reg(struct target *target, int num) { uint32_t reg_value; /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); if ((num < 0) || (num >= MIPS32NUMCOREREGS)) return ERROR_COMMAND_SYNTAX_ERROR; reg_value = mips32->core_regs[num]; buf_set_u32(mips32->core_cache->reg_list[num].value, 0, 32, reg_value); mips32->core_cache->reg_list[num].valid = 1; mips32->core_cache->reg_list[num].dirty = 0; return ERROR_OK; }
int mips32_examine(struct target *target) { struct mips32_common *mips32 = target_to_mips32(target); if (!target_was_examined(target)) { target_set_examined(target); /* we will configure later */ mips32->bp_scanned = 0; mips32->num_inst_bpoints = 0; mips32->num_data_bpoints = 0; mips32->num_inst_bpoints_avail = 0; mips32->num_data_bpoints_avail = 0; } return ERROR_OK; }
int mips32_configure_break_unit(struct target *target) { /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; int retval; uint32_t dcr; if (mips32->bp_scanned) return ERROR_OK; /* get info about breakpoint support */ retval = target_read_u32(target, EJTAG_DCR, &dcr); if (retval != ERROR_OK) return retval; /* EJTAG 2.0 does not specify EJTAG_DCR_IB and EJTAG_DCR_DB bits, * assume IB and DB registers are always present. */ if (ejtag_info->ejtag_version == EJTAG_VERSION_20) dcr |= EJTAG_DCR_IB | EJTAG_DCR_DB; if (dcr & EJTAG_DCR_IB) { retval = mips32_configure_ibs(target); if (retval != ERROR_OK) return retval; } if (dcr & EJTAG_DCR_DB) { retval = mips32_configure_dbs(target); if (retval != ERROR_OK) return retval; } /* check if target endianness settings matches debug control register */ if (((dcr & EJTAG_DCR_ENM) && (target->endianness == TARGET_LITTLE_ENDIAN)) || (!(dcr & EJTAG_DCR_ENM) && (target->endianness == TARGET_BIG_ENDIAN))) LOG_WARNING("DCR endianness settings does not match target settings"); LOG_DEBUG("DCR 0x%" PRIx32 " numinst %i numdata %i", dcr, mips32->num_inst_bpoints, mips32->num_data_bpoints); mips32->bp_scanned = 1; return ERROR_OK; }
static int mips32_write_core_reg(struct target *target, int num) { uint32_t reg_value; /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); if ((num < 0) || (num >= MIPS32NUMCOREREGS)) return ERROR_COMMAND_SYNTAX_ERROR; reg_value = buf_get_u32(mips32->core_cache->reg_list[num].value, 0, 32); mips32->core_regs[num] = reg_value; LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num , reg_value); mips32->core_cache->reg_list[num].valid = 1; mips32->core_cache->reg_list[num].dirty = 0; return ERROR_OK; }
int mips32_restore_context(struct target *target) { int i; /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; for (i = 0; i < MIPS32NUMCOREREGS; i++) { if (mips32->core_cache->reg_list[i].dirty) mips32->write_core_reg(target, i); } /* write core regs */ mips32_pracc_write_regs(ejtag_info, mips32->core_regs); return ERROR_OK; }
int mips32_save_context(struct target *target) { int i; /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; /* read core registers */ mips32_pracc_read_regs(ejtag_info, mips32->core_regs); for (i = 0; i < MIPS32NUMCOREREGS; i++) { if (!mips32->core_cache->reg_list[i].valid) mips32->read_core_reg(target, i); } return ERROR_OK; }
int mips32_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size) { /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); int i; /* include floating point registers */ *reg_list_size = MIPS32NUMCOREREGS + MIPS32NUMFPREGS; *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); for (i = 0; i < MIPS32NUMCOREREGS; i++) (*reg_list)[i] = &mips32->core_cache->reg_list[i]; /* add dummy floating points regs */ for (i = MIPS32NUMCOREREGS; i < (MIPS32NUMCOREREGS + MIPS32NUMFPREGS); i++) (*reg_list)[i] = &mips32_gdb_dummy_fp_reg; return ERROR_OK; }
struct reg_cache *mips32_build_reg_cache(struct target *target) { /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); int num_regs = MIPS32NUMCOREREGS; struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); struct reg_cache *cache = malloc(sizeof(struct reg_cache)); struct reg *reg_list = malloc(sizeof(struct reg) * num_regs); struct mips32_core_reg *arch_info = malloc(sizeof(struct mips32_core_reg) * num_regs); int i; register_init_dummy(&mips32_gdb_dummy_fp_reg); /* Build the process context cache */ cache->name = "mips32 registers"; cache->next = NULL; cache->reg_list = reg_list; cache->num_regs = num_regs; (*cache_p) = cache; mips32->core_cache = cache; for (i = 0; i < num_regs; i++) { arch_info[i] = mips32_core_reg_list_arch_info[i]; arch_info[i].target = target; arch_info[i].mips32_common = mips32; reg_list[i].name = mips32_core_reg_list[i]; reg_list[i].size = 32; reg_list[i].value = calloc(1, 4); reg_list[i].dirty = 0; reg_list[i].valid = 0; reg_list[i].type = &mips32_reg_type; reg_list[i].arch_info = &arch_info[i]; } return cache; }
static int ath79_spi_bitbang_chunk(struct flash_bank *bank, uint8_t *data, int len, int *transferred) { struct target *target = bank->target; struct ath79_flash_bank *ath79_info = bank->driver_priv; struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; int pracc_words; /* * These constants must match the worst case in the above code * generator function ath79_spi_bitbang_codegen. */ const int pracc_pre_post = 26; const int pracc_loop_byte = 8 * 2 + 2; struct pracc_queue_info ctx = { .ejtag_info = ejtag_info }; int max_len = (PRACC_MAX_INSTRUCTIONS - pracc_pre_post) / pracc_loop_byte; int to_xfer = len > max_len ? max_len : len; int partial_xfer = len != to_xfer; int padded_len = (to_xfer + 3) & ~3; uint32_t *out = malloc(padded_len); if (!out) { LOG_ERROR("not enough memory"); return ERROR_FAIL; } *transferred = 0; pracc_queue_init(&ctx); LOG_DEBUG("ath79_spi_bitbang_bytes(%p, %08x, %p, %d)", target, ath79_info->io_base, data, len); LOG_DEBUG("max code %d => max len %d. to_xfer %d", PRACC_MAX_INSTRUCTIONS, max_len, to_xfer); pracc_words = ath79_spi_bitbang_codegen( ath79_info, &ctx, data, to_xfer, partial_xfer); LOG_DEBUG("Assembled %d instructions, %d stores", ctx.code_count, ctx.store_count); ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, out, 1); if (ctx.retval != ERROR_OK) goto exit; if (to_xfer & 3) { /* Not a multiple of 4 bytes. */ /* * Need to realign last word since we didn't shift the * full 32 bits. */ int missed_bytes = 4 - (to_xfer & 3); out[pracc_words - 1] <<= BITS_PER_BYTE * missed_bytes; } /* * pracc reads return uint32_t in host endianness, convert to * target endianness. * Since we know the ATH79 target is big endian and the SPI * shift register has the bytes in highest to lowest bit order, * this will ensure correct memory byte order regardless of host * endianness. */ target_buffer_set_u32_array(target, (uint8_t *)out, pracc_words, out); if (LOG_LEVEL_IS(LOG_LVL_DEBUG)) { for (int i = 0; i < to_xfer; i++) { LOG_DEBUG("bitbang %02x => %02x", data[i], ((uint8_t *)out)[i]); } } memcpy(data, out, to_xfer); *transferred = to_xfer; exit: pracc_queue_free(&ctx); free(out); return ctx.retval; }
int mips32_configure_break_unit(struct target *target) { /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); int retval; uint32_t dcr, bpinfo; int i; if (mips32->bp_scanned) return ERROR_OK; /* get info about breakpoint support */ if ((retval = target_read_u32(target, EJTAG_DCR, &dcr)) != ERROR_OK) return retval; if (dcr & EJTAG_DCR_IB) { /* get number of inst breakpoints */ if ((retval = target_read_u32(target, EJTAG_IBS, &bpinfo)) != ERROR_OK) return retval; mips32->num_inst_bpoints = (bpinfo >> 24) & 0x0F; mips32->num_inst_bpoints_avail = mips32->num_inst_bpoints; mips32->inst_break_list = calloc(mips32->num_inst_bpoints, sizeof(struct mips32_comparator)); for (i = 0; i < mips32->num_inst_bpoints; i++) { mips32->inst_break_list[i].reg_address = EJTAG_IBA1 + (0x100 * i); } /* clear IBIS reg */ if ((retval = target_write_u32(target, EJTAG_IBS, 0)) != ERROR_OK) return retval; } if (dcr & EJTAG_DCR_DB) { /* get number of data breakpoints */ if ((retval = target_read_u32(target, EJTAG_DBS, &bpinfo)) != ERROR_OK) return retval; mips32->num_data_bpoints = (bpinfo >> 24) & 0x0F; mips32->num_data_bpoints_avail = mips32->num_data_bpoints; mips32->data_break_list = calloc(mips32->num_data_bpoints, sizeof(struct mips32_comparator)); for (i = 0; i < mips32->num_data_bpoints; i++) { mips32->data_break_list[i].reg_address = EJTAG_DBA1 + (0x100 * i); } /* clear DBIS reg */ if ((retval = target_write_u32(target, EJTAG_DBS, 0)) != ERROR_OK) return retval; } /* check if target endianness settings matches debug control register */ if ( ( (dcr & EJTAG_DCR_ENM) && (target->endianness == TARGET_LITTLE_ENDIAN) ) || ( !(dcr & EJTAG_DCR_ENM) && (target->endianness == TARGET_BIG_ENDIAN) ) ) { LOG_WARNING("DCR endianness settings does not match target settings"); } LOG_DEBUG("DCR 0x%" PRIx32 " numinst %i numdata %i", dcr, mips32->num_inst_bpoints, mips32->num_data_bpoints); mips32->bp_scanned = 1; return ERROR_OK; }
int mips32_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, uint32_t entry_point, uint32_t exit_point, int timeout_ms, void *arch_info) { struct mips32_common *mips32 = target_to_mips32(target); struct mips32_algorithm *mips32_algorithm_info = arch_info; enum mips32_isa_mode isa_mode = mips32->isa_mode; uint32_t context[MIPS32NUMCOREREGS]; int i; int retval = ERROR_OK; LOG_DEBUG("Running algorithm"); /* NOTE: mips32_run_algorithm requires that each algorithm uses a software breakpoint * at the exit point */ if (mips32->common_magic != MIPS32_COMMON_MAGIC) { LOG_ERROR("current target isn't a MIPS32 target"); return ERROR_TARGET_INVALID; } if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* refresh core register cache */ for (i = 0; i < MIPS32NUMCOREREGS; i++) { if (!mips32->core_cache->reg_list[i].valid) mips32->read_core_reg(target, i); context[i] = buf_get_u32(mips32->core_cache->reg_list[i].value, 0, 32); } for (i = 0; i < num_mem_params; i++) { if ((retval = target_write_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value)) != ERROR_OK) { return retval; } } for (i = 0; i < num_reg_params; i++) { struct reg *reg = register_get_by_name(mips32->core_cache, reg_params[i].reg_name, 0); if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } if (reg->size != reg_params[i].size) { LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } mips32_set_core_reg(reg, reg_params[i].value); } mips32->isa_mode = mips32_algorithm_info->isa_mode; retval = mips32_run_and_wait(target, entry_point, timeout_ms, exit_point, mips32); if (retval != ERROR_OK) return retval; for (i = 0; i < num_mem_params; i++) { if (mem_params[i].direction != PARAM_OUT) { if ((retval = target_read_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value)) != ERROR_OK) { return retval; } } } for (i = 0; i < num_reg_params; i++) { if (reg_params[i].direction != PARAM_OUT) { struct reg *reg = register_get_by_name(mips32->core_cache, reg_params[i].reg_name, 0); if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } if (reg->size != reg_params[i].size) { LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } buf_set_u32(reg_params[i].value, 0, 32, buf_get_u32(reg->value, 0, 32)); } } /* restore everything we saved before */ for (i = 0; i < MIPS32NUMCOREREGS; i++) { uint32_t regvalue; regvalue = buf_get_u32(mips32->core_cache->reg_list[i].value, 0, 32); if (regvalue != context[i]) { LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32, mips32->core_cache->reg_list[i].name, context[i]); buf_set_u32(mips32->core_cache->reg_list[i].value, 0, 32, context[i]); mips32->core_cache->reg_list[i].valid = 1; mips32->core_cache->reg_list[i].dirty = 1; } } mips32->isa_mode = isa_mode; return ERROR_OK; }
struct reg_cache *mips32_build_reg_cache(struct target *target) { /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); int num_regs = MIPS32_NUM_REGS; struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); struct reg_cache *cache = malloc(sizeof(struct reg_cache)); struct reg *reg_list = calloc(num_regs, sizeof(struct reg)); struct mips32_core_reg *arch_info = malloc(sizeof(struct mips32_core_reg) * num_regs); struct reg_feature *feature; int i; /* Build the process context cache */ cache->name = "mips32 registers"; cache->next = NULL; cache->reg_list = reg_list; cache->num_regs = num_regs; (*cache_p) = cache; mips32->core_cache = cache; for (i = 0; i < num_regs; i++) { arch_info[i].num = mips32_regs[i].id; arch_info[i].target = target; arch_info[i].mips32_common = mips32; reg_list[i].name = mips32_regs[i].name; reg_list[i].size = 32; if (mips32_regs[i].flag == MIPS32_GDB_DUMMY_FP_REG) { reg_list[i].value = mips32_gdb_dummy_fp_value; reg_list[i].valid = 1; reg_list[i].arch_info = NULL; register_init_dummy(®_list[i]); } else { reg_list[i].value = calloc(1, 4); reg_list[i].valid = 0; reg_list[i].type = &mips32_reg_type; reg_list[i].arch_info = &arch_info[i]; reg_list[i].reg_data_type = calloc(1, sizeof(struct reg_data_type)); if (reg_list[i].reg_data_type) reg_list[i].reg_data_type->type = mips32_regs[i].type; else LOG_ERROR("unable to allocate reg type list"); } reg_list[i].dirty = 0; reg_list[i].group = mips32_regs[i].group; reg_list[i].number = i; reg_list[i].exist = true; reg_list[i].caller_save = true; /* gdb defaults to true */ feature = calloc(1, sizeof(struct reg_feature)); if (feature) { feature->name = mips32_regs[i].feature; reg_list[i].feature = feature; } else LOG_ERROR("unable to allocate feature list"); } return cache; }