+// SPDX-License-Identifier: GPL-2.0-or-later
+
/***************************************************************************
* Copyright (C) 2008 by Spencer Oliver *
* spen@spen-soft.co.uk *
* *
* Copyright (C) 2011 by Drasko DRASKOVIC *
* drasko.draskovic@gmail.com *
- * *
- * This program 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 of the License, or *
- * (at your option) any later version. *
- * *
- * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#ifdef HAVE_CONFIG_H
static int mips_m4k_halt(struct target *target);
static int mips_m4k_bulk_write_memory(struct target *target, target_addr_t address,
uint32_t count, const uint8_t *buffer);
+static int mips_m4k_bulk_read_memory(struct target *target, target_addr_t address,
+ uint32_t count, uint8_t *buffer);
static int mips_m4k_examine_debug_reason(struct target *target)
{
/* attempt to find halt reason */
mips_m4k_examine_debug_reason(target);
+ mips32_cpu_probe(target);
+
mips32_read_config_regs(target);
/* default to mips32 isa, it will be changed below if required */
mips32->isa_mode = MIPS32_ISA_MIPS32;
/* other than mips32 only and isa bit set ? */
- if (mips32->isa_imp && buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 1))
+ if (mips32->isa_imp && buf_get_u32(mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].value, 0, 1))
mips32->isa_mode = mips32->isa_imp == 2 ? MIPS32_ISA_MIPS16E : MIPS32_ISA_MMIPS32;
LOG_DEBUG("entered debug state at PC 0x%" PRIx32 ", target->state: %s",
- buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32),
+ buf_get_u32(mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].value, 0, 32),
target_state_name(target));
return ERROR_OK;
static struct target *get_mips_m4k(struct target *target, int32_t coreid)
{
struct target_list *head;
- struct target *curr;
- head = target->head;
- while (head != (struct target_list *)NULL) {
- curr = head->target;
+ foreach_smp_target(head, target->smp_targets) {
+ struct target *curr = head->target;
if ((curr->coreid == coreid) && (curr->state == TARGET_HALTED))
return curr;
- head = head->next;
}
return target;
}
{
int retval = ERROR_OK;
struct target_list *head;
- struct target *curr;
- head = target->head;
- while (head != (struct target_list *)NULL) {
+
+ foreach_smp_target(head, target->smp_targets) {
int ret = ERROR_OK;
- curr = head->target;
+ struct target *curr = head->target;
if ((curr != target) && (curr->state != TARGET_HALTED))
ret = mips_m4k_halt(curr);
if (ret != ERROR_OK) {
- LOG_ERROR("halt failed target->coreid: %" PRId32, curr->coreid);
+ LOG_TARGET_ERROR(curr, "halt failed.");
retval = ret;
}
- head = head->next;
}
return retval;
}
{
int retval = ERROR_OK;
struct target_list *head;
- struct target *curr;
- head = target->head;
- while (head != (struct target_list *)NULL) {
+ foreach_smp_target(head, target->smp_targets) {
int ret = ERROR_OK;
- curr = head->target;
+ struct target *curr = head->target;
if ((curr != target) && (curr->state != TARGET_RUNNING)) {
/* resume current address , not in step mode */
ret = mips_m4k_internal_restore(curr, 1, address,
handle_breakpoints, 0);
if (ret != ERROR_OK) {
- LOG_ERROR("target->coreid :%" PRId32 " failed to resume at address :0x%" PRIx32,
- curr->coreid, address);
+ LOG_TARGET_ERROR(curr, "failed to resume at address: 0x%" PRIx32,
+ address);
retval = ret;
}
}
- head = head->next;
}
return retval;
}
/* current = 1: continue on current pc, otherwise continue at <address> */
if (!current) {
mips_m4k_isa_filter(mips32->isa_imp, &address);
- buf_set_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32, address);
- mips32->core_cache->reg_list[MIPS32_PC].dirty = true;
- mips32->core_cache->reg_list[MIPS32_PC].valid = true;
+ buf_set_u32(mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].value, 0, 32, address);
+ mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].dirty = true;
+ mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].valid = true;
}
if ((mips32->isa_imp > 1) && debug_execution) /* if more than one isa supported */
- buf_set_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 1, mips32->isa_mode);
+ buf_set_u32(mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].value, 0, 1, mips32->isa_mode);
if (!current)
resume_pc = address;
else
- resume_pc = buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32);
+ resume_pc = buf_get_u32(mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].value, 0, 32);
mips32_restore_context(target);
/* current = 1: continue on current pc, otherwise continue at <address> */
if (!current) {
mips_m4k_isa_filter(mips32->isa_imp, &address);
- buf_set_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32, address);
- mips32->core_cache->reg_list[MIPS32_PC].dirty = true;
- mips32->core_cache->reg_list[MIPS32_PC].valid = true;
+ buf_set_u32(mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].value, 0, 32, address);
+ mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].dirty = true;
+ mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].valid = true;
}
/* the front-end may request us not to handle breakpoints */
if (handle_breakpoints) {
breakpoint = breakpoint_find(target,
- buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32));
+ buf_get_u32(mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].value, 0, 32));
if (breakpoint)
mips_m4k_unset_breakpoint(target, breakpoint);
}
/* set any pending breakpoints */
while (breakpoint) {
- if (breakpoint->set == 0)
+ if (!breakpoint->is_set)
mips_m4k_set_breakpoint(target, breakpoint);
breakpoint = breakpoint->next;
}
struct mips32_comparator *comparator_list = mips32->inst_break_list;
int retval;
- if (breakpoint->set) {
+ if (breakpoint->is_set) {
LOG_WARNING("breakpoint already set");
return ERROR_OK;
}
breakpoint->unique_id);
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
- breakpoint->set = bp_num + 1;
+ breakpoint_hw_set(breakpoint, bp_num);
comparator_list[bp_num].used = 1;
comparator_list[bp_num].bp_value = breakpoint->address;
}
}
- breakpoint->set = 20; /* Any nice value but 0 */
+ breakpoint->is_set = true;
}
return ERROR_OK;
struct mips32_comparator *comparator_list = mips32->inst_break_list;
int retval;
- if (!breakpoint->set) {
+ if (!breakpoint->is_set) {
LOG_WARNING("breakpoint not set");
return ERROR_OK;
}
if (breakpoint->type == BKPT_HARD) {
- int bp_num = breakpoint->set - 1;
- if ((bp_num < 0) || (bp_num >= mips32->num_inst_bpoints)) {
+ int bp_num = breakpoint->number;
+ if (bp_num >= mips32->num_inst_bpoints) {
LOG_DEBUG("Invalid FP Comparator number in breakpoint (bpid: %" PRIu32 ")",
breakpoint->unique_id);
return ERROR_OK;
}
}
- breakpoint->set = 0;
+ breakpoint->is_set = false;
return ERROR_OK;
}
return ERROR_TARGET_NOT_HALTED;
}
- if (breakpoint->set)
+ if (breakpoint->is_set)
mips_m4k_unset_breakpoint(target, breakpoint);
if (breakpoint->type == BKPT_HARD)
int enable = EJTAG_DBCN_NOSB | EJTAG_DBCN_NOLB | EJTAG_DBCN_BE |
(0xff << EJTAG_DBCN_BLM_SHIFT);
- if (watchpoint->set) {
+ if (watchpoint->is_set) {
LOG_WARNING("watchpoint already set");
return ERROR_OK;
}
LOG_ERROR("BUG: watchpoint->rw neither read, write nor access");
}
- watchpoint->set = wp_num + 1;
+ watchpoint_set(watchpoint, wp_num);
comparator_list[wp_num].used = 1;
comparator_list[wp_num].bp_value = watchpoint->address;
struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
struct mips32_comparator *comparator_list = mips32->data_break_list;
- if (!watchpoint->set) {
+ if (!watchpoint->is_set) {
LOG_WARNING("watchpoint not set");
return ERROR_OK;
}
- int wp_num = watchpoint->set - 1;
- if ((wp_num < 0) || (wp_num >= mips32->num_data_bpoints)) {
+ int wp_num = watchpoint->number;
+ if (wp_num >= mips32->num_data_bpoints) {
LOG_DEBUG("Invalid FP Comparator number in watchpoint");
return ERROR_OK;
}
comparator_list[wp_num].bp_value = 0;
target_write_u32(target, comparator_list[wp_num].reg_address +
ejtag_info->ejtag_dbc_offs, 0);
- watchpoint->set = 0;
+ watchpoint->is_set = false;
return ERROR_OK;
}
return ERROR_TARGET_NOT_HALTED;
}
- if (watchpoint->set)
+ if (watchpoint->is_set)
mips_m4k_unset_watchpoint(target, watchpoint);
mips32->num_data_bpoints_avail++;
/* set any pending watchpoints */
while (watchpoint) {
- if (watchpoint->set == 0)
+ if (!watchpoint->is_set)
mips_m4k_set_watchpoint(target, watchpoint);
watchpoint = watchpoint->next;
}
if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u)))
return ERROR_TARGET_UNALIGNED_ACCESS;
+ if (size == 4 && count > 32) {
+ int retval = mips_m4k_bulk_read_memory(target, address, count, buffer);
+ if (retval == ERROR_OK)
+ return ERROR_OK;
+ LOG_WARNING("Falling back to non-bulk read");
+ }
/* since we don't know if buffer is aligned, we allocate new mem that is always aligned */
void *t = NULL;
fast_data_area = mips32->fast_data_area;
- if (address <= fast_data_area->address + fast_data_area->size &&
- fast_data_area->address <= address + count) {
+ if (address < (fast_data_area->address + fast_data_area->size) &&
+ fast_data_area->address < (address + count)) {
LOG_ERROR("fast_data (" TARGET_ADDR_FMT ") is within write area "
"(" TARGET_ADDR_FMT "-" TARGET_ADDR_FMT ").",
fast_data_area->address, address, address + count);
return retval;
}
+static int mips_m4k_bulk_read_memory(struct target *target, target_addr_t address,
+ uint32_t count, uint8_t *buffer)
+{
+ struct mips32_common *mips32 = target_to_mips32(target);
+ struct mips_ejtag *ejtag_info = &mips32->ejtag_info;
+ struct working_area *fast_data_area;
+ int retval;
+ int write_t = 0;
+
+ LOG_DEBUG("address: " TARGET_ADDR_FMT ", count: 0x%8.8" PRIx32 "",
+ address, count);
+
+ /* check alignment */
+ if (address & 0x3u)
+ return ERROR_TARGET_UNALIGNED_ACCESS;
+
+ if (!mips32->fast_data_area) {
+ /* Get memory for block read handler
+ * we preserve this area between calls and gain a speed increase
+ * of about 3kb/sec when reading flash
+ * this will be released/nulled by the system when the target is resumed or reset */
+ retval = target_alloc_working_area(target,
+ MIPS32_FASTDATA_HANDLER_SIZE,
+ &mips32->fast_data_area);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("No working area available");
+ return retval;
+ }
+
+ /* reset fastadata state so the algo get reloaded */
+ ejtag_info->fast_access_save = -1;
+ }
+
+ fast_data_area = mips32->fast_data_area;
+
+ if (address < (fast_data_area->address + fast_data_area->size) &&
+ fast_data_area->address < (address + count)) {
+ LOG_ERROR("fast_data (" TARGET_ADDR_FMT ") is within read area "
+ "(" TARGET_ADDR_FMT "-" TARGET_ADDR_FMT ").",
+ fast_data_area->address, address, address + count);
+ LOG_ERROR("Change work-area-phys or load_image address!");
+ return ERROR_FAIL;
+ }
+
+ /* mips32_pracc_fastdata_xfer requires uint32_t in host endianness, */
+ /* but byte array represents target endianness */
+ uint32_t *t = malloc(count * sizeof(uint32_t));
+ if (!t) {
+ LOG_ERROR("Out of memory");
+ return ERROR_FAIL;
+ }
+
+ retval = mips32_pracc_fastdata_xfer(ejtag_info, mips32->fast_data_area, write_t, address,
+ count, t);
+
+ target_buffer_set_u32_array(target, buffer, count, t);
+
+ free(t);
+
+ if (retval != ERROR_OK)
+ LOG_ERROR("Fastdata access Failed");
+
+ return retval;
+}
+
static int mips_m4k_verify_pointer(struct command_invocation *cmd,
struct mips_m4k_common *mips_m4k)
{
COMMAND_REGISTRATION_DONE
};
-const struct command_registration mips_m4k_command_handlers[] = {
+static const struct command_registration mips_m4k_command_handlers[] = {
{
.chain = mips32_command_handlers,
},