diff options
author | Tim Newsome <tim@sifive.com> | 2023-12-21 09:23:11 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-12-21 09:23:11 -0800 |
commit | 62758f20871f2de7df4a62aff7e987acb92b4d58 (patch) | |
tree | 3a8b4ba00c816048a7489688aa558dca41804b7e /src/target | |
parent | feff8e005482ce3a070131e62a14b3bc0b9fbdf9 (diff) | |
parent | 1f512eac32e614e893565741f93ea3739a522797 (diff) | |
download | riscv-openocd-62758f20871f2de7df4a62aff7e987acb92b4d58.zip riscv-openocd-62758f20871f2de7df4a62aff7e987acb92b4d58.tar.gz riscv-openocd-62758f20871f2de7df4a62aff7e987acb92b4d58.tar.bz2 |
Merge pull request #976 from riscv/from_upstream
Merge up to d4575b647a3603200a9bb4a784d170f792ab88d0 from upstream
Diffstat (limited to 'src/target')
-rw-r--r-- | src/target/arc.c | 16 | ||||
-rw-r--r-- | src/target/arm.h | 11 | ||||
-rw-r--r-- | src/target/arm_dpm.c | 48 | ||||
-rw-r--r-- | src/target/arm_dpm.h | 13 | ||||
-rw-r--r-- | src/target/arm_opcodes.h | 22 | ||||
-rw-r--r-- | src/target/armv4_5.c | 122 | ||||
-rw-r--r-- | src/target/armv8_dpm.c | 11 | ||||
-rw-r--r-- | src/target/breakpoints.c | 104 | ||||
-rw-r--r-- | src/target/breakpoints.h | 1 | ||||
-rw-r--r-- | src/target/cortex_a.c | 47 | ||||
-rw-r--r-- | src/target/cortex_m.c | 5 | ||||
-rw-r--r-- | src/target/cortex_m.h | 27 | ||||
-rw-r--r-- | src/target/etm.c | 4 | ||||
-rw-r--r-- | src/target/image.c | 38 | ||||
-rw-r--r-- | src/target/mips32.c | 392 | ||||
-rw-r--r-- | src/target/mips32.h | 386 | ||||
-rw-r--r-- | src/target/mips32_pracc.c | 196 | ||||
-rw-r--r-- | src/target/mips32_pracc.h | 6 | ||||
-rw-r--r-- | src/target/mips64.c | 16 | ||||
-rw-r--r-- | src/target/mips_ejtag.h | 11 | ||||
-rw-r--r-- | src/target/mips_m4k.c | 22 | ||||
-rw-r--r-- | src/target/mips_mips64.c | 8 | ||||
-rw-r--r-- | src/target/target.c | 65 |
23 files changed, 1289 insertions, 282 deletions
diff --git a/src/target/arc.c b/src/target/arc.c index 2ca6be1..0f7b110 100644 --- a/src/target/arc.c +++ b/src/target/arc.c @@ -1265,8 +1265,8 @@ static int arc_resume(struct target *target, int current, target_addr_t address, /* current = 1: continue on current PC, otherwise continue at <address> */ if (!current) { target_buffer_set_u32(target, pc->value, address); - pc->dirty = 1; - pc->valid = 1; + pc->dirty = true; + pc->valid = true; LOG_DEBUG("Changing the value of current PC to 0x%08" TARGET_PRIxADDR, address); } @@ -1281,7 +1281,7 @@ static int arc_resume(struct target *target, int current, target_addr_t address, resume_pc, pc->dirty, pc->valid); /* check if GDB tells to set our PC where to continue from */ - if ((pc->valid == 1) && (resume_pc == target_buffer_get_u32(target, pc->value))) { + if (pc->valid && resume_pc == target_buffer_get_u32(target, pc->value)) { value = target_buffer_get_u32(target, pc->value); LOG_DEBUG("resume Core (when start-core) with PC @:0x%08" PRIx32, value); CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_PC_REG, value)); @@ -1573,9 +1573,6 @@ static int arc_set_breakpoint(struct target *target, return ERROR_FAIL; } - /* core instruction cache is now invalid. */ - CHECK_RETVAL(arc_cache_invalidate(target)); - return ERROR_OK; } @@ -1658,9 +1655,6 @@ static int arc_unset_breakpoint(struct target *target, return ERROR_FAIL; } - /* core instruction cache is now invalid. */ - CHECK_RETVAL(arc_cache_invalidate(target)); - return retval; } @@ -2013,8 +2007,8 @@ static int arc_step(struct target *target, int current, target_addr_t address, /* current = 1: continue on current pc, otherwise continue at <address> */ if (!current) { buf_set_u32(pc->value, 0, 32, address); - pc->dirty = 1; - pc->valid = 1; + pc->dirty = true; + pc->valid = true; } LOG_DEBUG("Target steps one instruction from PC=0x%" PRIx32, diff --git a/src/target/arm.h b/src/target/arm.h index 28e5330..d5053af 100644 --- a/src/target/arm.h +++ b/src/target/arm.h @@ -61,6 +61,7 @@ enum arm_arch { /** Known ARM implementor IDs */ enum arm_implementor { ARM_IMPLEMENTOR_ARM = 0x41, + ARM_IMPLEMENTOR_INFINEON = 0x49, ARM_IMPLEMENTOR_REALTEK = 0x72, }; @@ -230,12 +231,22 @@ struct arm { uint32_t crn, uint32_t crm, uint32_t *value); + /** Read coprocessor to two registers. */ + int (*mrrc)(struct target *target, int cpnum, + uint32_t op, uint32_t crm, + uint64_t *value); + /** Write coprocessor register. */ int (*mcr)(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t value); + /** Write coprocessor from two registers. */ + int (*mcrr)(struct target *target, int cpnum, + uint32_t op, uint32_t crm, + uint64_t value); + void *arch_info; /** For targets conforming to ARM Debug Interface v5, diff --git a/src/target/arm_dpm.c b/src/target/arm_dpm.c index ab9b50e..9f3a444 100644 --- a/src/target/arm_dpm.c +++ b/src/target/arm_dpm.c @@ -63,6 +63,29 @@ static int dpm_mrc(struct target *target, int cpnum, return retval; } +static int dpm_mrrc(struct target *target, int cpnum, + uint32_t op, uint32_t crm, uint64_t *value) +{ + struct arm *arm = target_to_arm(target); + struct arm_dpm *dpm = arm->dpm; + int retval; + + retval = dpm->prepare(dpm); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("MRRC p%d, %d, r0, r1, c%d", cpnum, + (int)op, (int)crm); + + /* read coprocessor register into R0, R1; return via DCC */ + retval = dpm->instr_read_data_r0_r1(dpm, + ARMV5_T_MRRC(cpnum, op, 0, 1, crm), + value); + + /* (void) */ dpm->finish(dpm); + return retval; +} + static int dpm_mcr(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t value) @@ -88,6 +111,29 @@ static int dpm_mcr(struct target *target, int cpnum, return retval; } +static int dpm_mcrr(struct target *target, int cpnum, + uint32_t op, uint32_t crm, uint64_t value) +{ + struct arm *arm = target_to_arm(target); + struct arm_dpm *dpm = arm->dpm; + int retval; + + retval = dpm->prepare(dpm); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("MCRR p%d, %d, r0, r1, c%d", cpnum, + (int)op, (int)crm); + + /* read DCC into r0, r1; then write coprocessor register from R0, R1 */ + retval = dpm->instr_write_data_r0_r1(dpm, + ARMV5_T_MCRR(cpnum, op, 0, 1, crm), value); + + /* (void) */ dpm->finish(dpm); + + return retval; +} + /*----------------------------------------------------------------------*/ /* @@ -1070,6 +1116,8 @@ int arm_dpm_setup(struct arm_dpm *dpm) /* coprocessor access setup */ arm->mrc = dpm_mrc; arm->mcr = dpm_mcr; + arm->mrrc = dpm_mrrc; + arm->mcrr = dpm_mcrr; /* breakpoint setup -- optional until it works everywhere */ if (!target->type->add_breakpoint) { diff --git a/src/target/arm_dpm.h b/src/target/arm_dpm.h index d35e9f6..2da4631 100644 --- a/src/target/arm_dpm.h +++ b/src/target/arm_dpm.h @@ -72,6 +72,12 @@ struct arm_dpm { int (*instr_write_data_r0)(struct arm_dpm *dpm, uint32_t opcode, uint32_t data); + /** + * Runs two instructions, writing data to R0 and R1 before execution. + */ + int (*instr_write_data_r0_r1)(struct arm_dpm *dpm, + uint32_t opcode, uint64_t data); + /** Runs one instruction, writing data to R0 before execution. */ int (*instr_write_data_r0_64)(struct arm_dpm *dpm, uint32_t opcode, uint64_t data); @@ -92,6 +98,13 @@ struct arm_dpm { int (*instr_read_data_r0)(struct arm_dpm *dpm, uint32_t opcode, uint32_t *data); + /** + * Runs two instructions, reading data from r0 and r1 after + * execution. + */ + int (*instr_read_data_r0_r1)(struct arm_dpm *dpm, + uint32_t opcode, uint64_t *data); + int (*instr_read_data_r0_64)(struct arm_dpm *dpm, uint32_t opcode, uint64_t *data); diff --git a/src/target/arm_opcodes.h b/src/target/arm_opcodes.h index c182f41..c8ce51f 100644 --- a/src/target/arm_opcodes.h +++ b/src/target/arm_opcodes.h @@ -187,6 +187,17 @@ (0xee100010 | (crm) | ((op2) << 5) | ((cp) << 8) \ | ((rd) << 12) | ((crn) << 16) | ((op1) << 21)) +/* Move to two ARM registers from coprocessor + * cp: Coprocessor number + * op: Coprocessor opcode + * rt: destination register 1 + * rt2: destination register 2 + * crm: coprocessor source register + */ +#define ARMV5_T_MRRC(cp, op, rt, rt2, crm) \ + (0xec500000 | (crm) | ((op) << 4) | ((cp) << 8) \ + | ((rt) << 12) | ((rt2) << 16)) + /* Move to coprocessor from ARM register * cp: Coprocessor number * op1: Coprocessor opcode @@ -199,6 +210,17 @@ (0xee000010 | (crm) | ((op2) << 5) | ((cp) << 8) \ | ((rd) << 12) | ((crn) << 16) | ((op1) << 21)) +/* Move to coprocessor from two ARM registers + * cp: Coprocessor number + * op: Coprocessor opcode + * rt: destination register 1 + * rt2: destination register 2 + * crm: coprocessor source register + */ +#define ARMV5_T_MCRR(cp, op, rt, rt2, crm) \ + (0xec400000 | (crm) | ((op) << 4) | ((cp) << 8) \ + | ((rt) << 12) | ((rt2) << 16)) + /* Breakpoint instruction (ARMv5) * im: 16-bit immediate */ diff --git a/src/target/armv4_5.c b/src/target/armv4_5.c index 8e3f224..7debb94 100644 --- a/src/target/armv4_5.c +++ b/src/target/armv4_5.c @@ -1093,6 +1093,94 @@ COMMAND_HANDLER(handle_armv4_5_mcrmrc) return ERROR_OK; } +COMMAND_HANDLER(handle_armv4_5_mcrrmrrc) +{ + bool is_mcrr = false; + unsigned int arg_cnt = 3; + + if (!strcmp(CMD_NAME, "mcrr")) { + is_mcrr = true; + arg_cnt = 4; + } + + if (arg_cnt != CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct target *target = get_current_target(CMD_CTX); + if (!target) { + command_print(CMD, "no current target"); + return ERROR_FAIL; + } + if (!target_was_examined(target)) { + command_print(CMD, "%s: not yet examined", target_name(target)); + return ERROR_TARGET_NOT_EXAMINED; + } + + struct arm *arm = target_to_arm(target); + if (!is_arm(arm)) { + command_print(CMD, "%s: not an ARM", target_name(target)); + return ERROR_FAIL; + } + + if (target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + int cpnum; + uint32_t op1; + uint32_t crm; + uint64_t value; + + /* NOTE: parameter sequence matches ARM instruction set usage: + * MCRR pNUM, op1, rX1, rX2, CRm ; write CP from rX1 and rX2 + * MREC pNUM, op1, rX1, rX2, CRm ; read CP into rX1 and rX2 + * The "rXn" are necessarily omitted; they use Tcl mechanisms. + */ + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], cpnum); + if (cpnum & ~0xf) { + command_print(CMD, "coprocessor %d out of range", cpnum); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], op1); + if (op1 & ~0xf) { + command_print(CMD, "op1 %d out of range", op1); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], crm); + if (crm & ~0xf) { + command_print(CMD, "CRm %d out of range", crm); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + /* + * FIXME change the call syntax here ... simplest to just pass + * the MRC() or MCR() instruction to be executed. That will also + * let us support the "mrrc2" and "mcrr2" opcodes (toggling one bit) + * if that's ever needed. + */ + if (is_mcrr) { + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[3], value); + + /* NOTE: parameters reordered! */ + /* ARMV5_T_MCRR(cpnum, op1, crm) */ + int retval = arm->mcrr(target, cpnum, op1, crm, value); + if (retval != ERROR_OK) + return retval; + } else { + value = 0; + /* NOTE: parameters reordered! */ + /* ARMV5_T_MRRC(cpnum, op1, crm) */ + int retval = arm->mrrc(target, cpnum, op1, crm, &value); + if (retval != ERROR_OK) + return retval; + + command_print(CMD, "0x%" PRIx64, value); + } + + return ERROR_OK; +} + static const struct command_registration arm_exec_command_handlers[] = { { .name = "reg", @@ -1116,6 +1204,20 @@ static const struct command_registration arm_exec_command_handlers[] = { .usage = "cpnum op1 CRn CRm op2", }, { + .name = "mcrr", + .mode = COMMAND_EXEC, + .handler = handle_armv4_5_mcrrmrrc, + .help = "write coprocessor 64-bit register", + .usage = "cpnum op1 CRm value", + }, + { + .name = "mrrc", + .mode = COMMAND_EXEC, + .handler = handle_armv4_5_mcrrmrrc, + .help = "read coprocessor 64-bit register", + .usage = "cpnum op1 CRm", + }, + { .chain = arm_all_profiles_command_handlers, }, COMMAND_REGISTRATION_DONE @@ -1669,6 +1771,14 @@ static int arm_default_mrc(struct target *target, int cpnum, return ERROR_FAIL; } +static int arm_default_mrrc(struct target *target, int cpnum, + uint32_t op, uint32_t crm, + uint64_t *value) +{ + LOG_ERROR("%s doesn't implement MRRC", target_type_name(target)); + return ERROR_FAIL; +} + static int arm_default_mcr(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, @@ -1678,6 +1788,14 @@ static int arm_default_mcr(struct target *target, int cpnum, return ERROR_FAIL; } +static int arm_default_mcrr(struct target *target, int cpnum, + uint32_t op, uint32_t crm, + uint64_t value) +{ + LOG_ERROR("%s doesn't implement MCRR", target_type_name(target)); + return ERROR_FAIL; +} + int arm_init_arch_info(struct target *target, struct arm *arm) { target->arch_info = arm; @@ -1697,8 +1815,12 @@ int arm_init_arch_info(struct target *target, struct arm *arm) if (!arm->mrc) arm->mrc = arm_default_mrc; + if (!arm->mrrc) + arm->mrrc = arm_default_mrrc; if (!arm->mcr) arm->mcr = arm_default_mcr; + if (!arm->mcrr) + arm->mcrr = arm_default_mcrr; return ERROR_OK; } diff --git a/src/target/armv8_dpm.c b/src/target/armv8_dpm.c index 9ba6b54..552bcfa 100644 --- a/src/target/armv8_dpm.c +++ b/src/target/armv8_dpm.c @@ -725,7 +725,8 @@ static int dpmv8_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) } /** - * Read basic registers of the current context: R0 to R15, and CPSR; + * Read basic registers of the current context: R0 to R15, and CPSR in AArch32 + * state or R0 to R31, PC and CPSR in AArch64 state; * sets the core mode (such as USR or IRQ) and state (such as ARM or Thumb). * In normal operation this is called on entry to halting debug state, * possibly after some other operations supporting restore of debug state @@ -772,9 +773,15 @@ int armv8_dpm_read_current_registers(struct arm_dpm *dpm) /* update core mode and state */ armv8_set_cpsr(arm, cpsr); - for (unsigned int i = ARMV8_PC; i < cache->num_regs ; i++) { + /* read the remaining registers that would be required by GDB 'g' packet */ + for (unsigned int i = ARMV8_R2; i <= ARMV8_PC ; i++) { struct arm_reg *arm_reg; + /* in AArch32 skip AArch64 registers */ + /* TODO: this should be detected below through arm_reg->mode */ + if (arm->core_state != ARM_STATE_AARCH64 && i > ARMV8_R14 && i < ARMV8_PC) + continue; + r = armv8_reg_current(arm, i); if (!r->exist || r->valid) continue; diff --git a/src/target/breakpoints.c b/src/target/breakpoints.c index 7d2a9da..d069c6b 100644 --- a/src/target/breakpoints.c +++ b/src/target/breakpoints.c @@ -18,6 +18,11 @@ #include "rtos/rtos.h" #include "smp.h" +enum breakpoint_watchpoint { + BREAKPOINT, + WATCHPOINT, +}; + static const char * const breakpoint_type_strings[] = { "hardware", "software" @@ -418,26 +423,90 @@ int breakpoint_remove(struct target *target, target_addr_t address) return retval; } -int breakpoint_remove_all(struct target *target) +static int watchpoint_free(struct target *target, struct watchpoint *watchpoint_to_remove) { + struct watchpoint *watchpoint = target->watchpoints; + struct watchpoint **watchpoint_p = &target->watchpoints; + int retval; + + while (watchpoint) { + if (watchpoint == watchpoint_to_remove) + break; + watchpoint_p = &watchpoint->next; + watchpoint = watchpoint->next; + } + + if (!watchpoint) + return ERROR_WATCHPOINT_NOT_FOUND; + retval = target_remove_watchpoint(target, watchpoint); + if (retval != ERROR_OK) { + LOG_TARGET_ERROR(target, "could not remove watchpoint #%d on this target", + watchpoint->number); + return retval; + } + + LOG_DEBUG("free WPID: %d --> %d", watchpoint->unique_id, retval); + (*watchpoint_p) = watchpoint->next; + free(watchpoint); + + return ERROR_OK; +} + +static int watchpoint_remove_all_internal(struct target *target) +{ + struct watchpoint *watchpoint = target->watchpoints; + int retval = ERROR_OK; + + while (watchpoint) { + struct watchpoint *tmp = watchpoint; + watchpoint = watchpoint->next; + int status = watchpoint_free(target, tmp); + if (status != ERROR_OK) + retval = status; + } + + return retval; +} + +static int breakpoint_watchpoint_remove_all(struct target *target, enum breakpoint_watchpoint bp_wp) +{ + assert(bp_wp == BREAKPOINT || bp_wp == WATCHPOINT); int retval = ERROR_OK; if (target->smp) { struct target_list *head; foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; - int status = breakpoint_remove_all_internal(curr); + + int status = ERROR_OK; + if (bp_wp == BREAKPOINT) + status = breakpoint_remove_all_internal(curr); + else + status = watchpoint_remove_all_internal(curr); if (status != ERROR_OK) retval = status; } } else { - retval = breakpoint_remove_all_internal(target); + if (bp_wp == BREAKPOINT) + retval = breakpoint_remove_all_internal(target); + else + retval = watchpoint_remove_all_internal(target); } return retval; } +int breakpoint_remove_all(struct target *target) +{ + return breakpoint_watchpoint_remove_all(target, BREAKPOINT); +} + +int watchpoint_remove_all(struct target *target) +{ + return breakpoint_watchpoint_remove_all(target, WATCHPOINT); +} + int breakpoint_clear_target(struct target *target) { int retval = ERROR_OK; @@ -562,35 +631,6 @@ int watchpoint_add(struct target *target, target_addr_t address, } } -static int watchpoint_free(struct target *target, struct watchpoint *watchpoint_to_remove) -{ - struct watchpoint *watchpoint = target->watchpoints; - struct watchpoint **watchpoint_p = &target->watchpoints; - int retval; - - while (watchpoint) { - if (watchpoint == watchpoint_to_remove) - break; - watchpoint_p = &watchpoint->next; - watchpoint = watchpoint->next; - } - - if (!watchpoint) - return ERROR_WATCHPOINT_NOT_FOUND; - retval = target_remove_watchpoint(target, watchpoint); - if (retval != ERROR_OK) { - LOG_TARGET_ERROR(target, "could not remove watchpoint #%d on this target", - watchpoint->number); - return retval; - } - - LOG_DEBUG("free WPID: %d --> %d", watchpoint->unique_id, retval); - (*watchpoint_p) = watchpoint->next; - free(watchpoint); - - return ERROR_OK; -} - static int watchpoint_remove_internal(struct target *target, target_addr_t address) { struct watchpoint *watchpoint = target->watchpoints; diff --git a/src/target/breakpoints.h b/src/target/breakpoints.h index 950283e..0ec65de 100644 --- a/src/target/breakpoints.h +++ b/src/target/breakpoints.h @@ -73,6 +73,7 @@ int watchpoint_add(struct target *target, target_addr_t address, uint32_t length, enum watchpoint_rw rw, uint64_t value, uint64_t mask); int watchpoint_remove(struct target *target, target_addr_t address); +int watchpoint_remove_all(struct target *target); /* report type and address of just hit watchpoint */ int watchpoint_hit(struct target *target, enum watchpoint_rw *rw, diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index abfd6ac..ba3349d 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -471,6 +471,28 @@ static int cortex_a_instr_write_data_r0(struct arm_dpm *dpm, return retval; } +static int cortex_a_instr_write_data_r0_r1(struct arm_dpm *dpm, + uint32_t opcode, uint64_t data) +{ + struct cortex_a_common *a = dpm_to_a(dpm); + uint32_t dscr = DSCR_INSTR_COMP; + int retval; + + retval = cortex_a_instr_write_data_rt_dcc(dpm, 0, data & 0xffffffffULL); + if (retval != ERROR_OK) + return retval; + + retval = cortex_a_instr_write_data_rt_dcc(dpm, 1, data >> 32); + if (retval != ERROR_OK) + return retval; + + /* then the opcode, taking data from R0, R1 */ + retval = cortex_a_exec_opcode(a->armv7a_common.arm.target, + opcode, + &dscr); + return retval; +} + static int cortex_a_instr_cpsr_sync(struct arm_dpm *dpm) { struct target *target = dpm->arm->target; @@ -539,6 +561,29 @@ static int cortex_a_instr_read_data_r0(struct arm_dpm *dpm, return cortex_a_instr_read_data_rt_dcc(dpm, 0, data); } +static int cortex_a_instr_read_data_r0_r1(struct arm_dpm *dpm, + uint32_t opcode, uint64_t *data) +{ + uint32_t lo, hi; + int retval; + + /* the opcode, writing data to RO, R1 */ + retval = cortex_a_instr_read_data_r0(dpm, opcode, &lo); + if (retval != ERROR_OK) + return retval; + + *data = lo; + + /* write R1 to DCC */ + retval = cortex_a_instr_read_data_rt_dcc(dpm, 1, &hi); + if (retval != ERROR_OK) + return retval; + + *data |= (uint64_t)hi << 32; + + return retval; +} + static int cortex_a_bpwp_enable(struct arm_dpm *dpm, unsigned index_t, uint32_t addr, uint32_t control) { @@ -612,10 +657,12 @@ static int cortex_a_dpm_setup(struct cortex_a_common *a, uint32_t didr) dpm->instr_write_data_dcc = cortex_a_instr_write_data_dcc; dpm->instr_write_data_r0 = cortex_a_instr_write_data_r0; + dpm->instr_write_data_r0_r1 = cortex_a_instr_write_data_r0_r1; dpm->instr_cpsr_sync = cortex_a_instr_cpsr_sync; dpm->instr_read_data_dcc = cortex_a_instr_read_data_dcc; dpm->instr_read_data_r0 = cortex_a_instr_read_data_r0; + dpm->instr_read_data_r0_r1 = cortex_a_instr_read_data_r0_r1; dpm->bpwp_enable = cortex_a_bpwp_enable; dpm->bpwp_disable = cortex_a_bpwp_disable; diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 854e8eb..3eafee0 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -112,6 +112,11 @@ static const struct cortex_m_part_info cortex_m_parts[] = { .flags = CORTEX_M_F_HAS_FPV5, }, { + .impl_part = INFINEON_SLX2_PARTNO, + .name = "Infineon-SLx2", + .arch = ARM_ARCH_V8M, + }, + { .impl_part = REALTEK_M200_PARTNO, .name = "Real-M200 (KM0)", .arch = ARM_ARCH_V8M, diff --git a/src/target/cortex_m.h b/src/target/cortex_m.h index 065e4d4..0bc1399 100644 --- a/src/target/cortex_m.h +++ b/src/target/cortex_m.h @@ -45,19 +45,20 @@ */ enum cortex_m_impl_part { CORTEX_M_PARTNO_INVALID, - STAR_MC1_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0x132), /* FIXME - confirm implementor! */ - CORTEX_M0_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC20), - CORTEX_M1_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC21), - CORTEX_M3_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC23), - CORTEX_M4_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC24), - CORTEX_M7_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC27), - CORTEX_M0P_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC60), - CORTEX_M23_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD20), - CORTEX_M33_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD21), - CORTEX_M35P_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD31), - CORTEX_M55_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD22), - REALTEK_M200_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_REALTEK, 0xd20), - REALTEK_M300_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_REALTEK, 0xd22), + STAR_MC1_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0x132), /* FIXME - confirm implementor! */ + CORTEX_M0_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC20), + CORTEX_M1_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC21), + CORTEX_M3_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC23), + CORTEX_M4_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC24), + CORTEX_M7_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC27), + CORTEX_M0P_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC60), + CORTEX_M23_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD20), + CORTEX_M33_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD21), + CORTEX_M35P_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD31), + CORTEX_M55_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD22), + INFINEON_SLX2_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_INFINEON, 0xDB0), + REALTEK_M200_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_REALTEK, 0xd20), + REALTEK_M300_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_REALTEK, 0xd22), }; /* Relevant Cortex-M flags, used in struct cortex_m_part_info.flags */ diff --git a/src/target/etm.c b/src/target/etm.c index 6718875..d083017 100644 --- a/src/target/etm.c +++ b/src/target/etm.c @@ -552,8 +552,8 @@ static int etm_set_reg(struct reg *reg, uint32_t value) } buf_set_u32(reg->value, 0, reg->size, value); - reg->valid = 1; - reg->dirty = 0; + reg->valid = true; + reg->dirty = false; return ERROR_OK; } diff --git a/src/target/image.c b/src/target/image.c index ad2d856..9175c20 100644 --- a/src/target/image.c +++ b/src/target/image.c @@ -96,20 +96,22 @@ static int autodetect_image_type(struct image *image, const char *url) static int identify_image_type(struct image *image, const char *type_string, const char *url) { if (type_string) { - if (!strcmp(type_string, "bin")) + if (!strcmp(type_string, "bin")) { image->type = IMAGE_BINARY; - else if (!strcmp(type_string, "ihex")) + } else if (!strcmp(type_string, "ihex")) { image->type = IMAGE_IHEX; - else if (!strcmp(type_string, "elf")) + } else if (!strcmp(type_string, "elf")) { image->type = IMAGE_ELF; - else if (!strcmp(type_string, "mem")) + } else if (!strcmp(type_string, "mem")) { image->type = IMAGE_MEMORY; - else if (!strcmp(type_string, "s19")) + } else if (!strcmp(type_string, "s19")) { image->type = IMAGE_SRECORD; - else if (!strcmp(type_string, "build")) + } else if (!strcmp(type_string, "build")) { image->type = IMAGE_BUILDER; - else + } else { + LOG_ERROR("Unknown image type: %s, use one of: bin, ihex, elf, mem, s19, build", type_string); return ERROR_IMAGE_TYPE_UNKNOWN; + } } else return autodetect_image_type(image, url); @@ -966,12 +968,13 @@ int image_open(struct image *image, const char *url, const char *type_string) retval = fileio_open(&image_binary->fileio, url, FILEIO_READ, FILEIO_BINARY); if (retval != ERROR_OK) - return retval; + goto free_mem_on_error; + size_t filesize; retval = fileio_size(image_binary->fileio, &filesize); if (retval != ERROR_OK) { fileio_close(image_binary->fileio); - return retval; + goto free_mem_on_error; } image->num_sections = 1; @@ -986,14 +989,14 @@ int image_open(struct image *image, const char *url, const char *type_string) retval = fileio_open(&image_ihex->fileio, url, FILEIO_READ, FILEIO_TEXT); if (retval != ERROR_OK) - return retval; + goto free_mem_on_error; retval = image_ihex_buffer_complete(image); if (retval != ERROR_OK) { LOG_ERROR( "failed buffering IHEX image, check server output for additional information"); fileio_close(image_ihex->fileio); - return retval; + goto free_mem_on_error; } } else if (image->type == IMAGE_ELF) { struct image_elf *image_elf; @@ -1002,12 +1005,12 @@ int image_open(struct image *image, const char *url, const char *type_string) retval = fileio_open(&image_elf->fileio, url, FILEIO_READ, FILEIO_BINARY); if (retval != ERROR_OK) - return retval; + goto free_mem_on_error; retval = image_elf_read_headers(image); if (retval != ERROR_OK) { fileio_close(image_elf->fileio); - return retval; + goto free_mem_on_error; } } else if (image->type == IMAGE_MEMORY) { struct target *target = get_target(url); @@ -1037,14 +1040,14 @@ int image_open(struct image *image, const char *url, const char *type_string) retval = fileio_open(&image_mot->fileio, url, FILEIO_READ, FILEIO_TEXT); if (retval != ERROR_OK) - return retval; + goto free_mem_on_error; retval = image_mot_buffer_complete(image); if (retval != ERROR_OK) { LOG_ERROR( "failed buffering S19 image, check server output for additional information"); fileio_close(image_mot->fileio); - return retval; + goto free_mem_on_error; } } else if (image->type == IMAGE_BUILDER) { image->num_sections = 0; @@ -1065,6 +1068,11 @@ int image_open(struct image *image, const char *url, const char *type_string) } return retval; + +free_mem_on_error: + free(image->type_private); + image->type_private = NULL; + return retval; }; int image_read_section(struct image *image, diff --git a/src/target/mips32.c b/src/target/mips32.c index 4e6d251..5c346c4 100644 --- a/src/target/mips32.c +++ b/src/target/mips32.c @@ -27,7 +27,7 @@ static const char *mips_isa_strings[] = { "MIPS32", "MIPS16", "", "MICRO MIPS32", }; -#define MIPS32_GDB_DUMMY_FP_REG 1 +#define MIPS32_GDB_FP_REG 1 /* * GDB registers @@ -39,7 +39,7 @@ static const struct { enum reg_type type; const char *group; const char *feature; - int flag; + int size; } mips32_regs[] = { { 0, "r0", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 1, "r1", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, @@ -73,88 +73,93 @@ static const struct { { 29, "r29", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 30, "r30", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 31, "r31", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, - { 32, "status", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cp0", 0 }, - { 33, "lo", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, - { 34, "hi", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, - { 35, "badvaddr", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cp0", 0 }, - { 36, "cause", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cp0", 0 }, - { 37, "pc", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, - - { 38, "f0", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 39, "f1", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 40, "f2", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 41, "f3", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 42, "f4", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 43, "f5", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 44, "f6", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 45, "f7", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 46, "f8", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 47, "f9", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 48, "f10", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 49, "f11", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 50, "f12", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 51, "f13", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 52, "f14", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 53, "f15", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 54, "f16", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 55, "f17", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 56, "f18", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 57, "f19", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 58, "f20", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 59, "f21", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 60, "f22", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 61, "f23", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 62, "f24", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 63, "f25", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 64, "f26", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 65, "f27", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 66, "f28", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 67, "f29", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 68, "f30", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 69, "f31", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 70, "fcsr", REG_TYPE_INT, "float", - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 71, "fir", REG_TYPE_INT, "float", - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, + { 32, "lo", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 33, "hi", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, + + { MIPS32_REGLIST_FP_INDEX + 0, "f0", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 1, "f1", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 2, "f2", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 3, "f3", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 4, "f4", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 5, "f5", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 6, "f6", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 7, "f7", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 8, "f8", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 9, "f9", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 10, "f10", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 11, "f11", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 12, "f12", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 13, "f13", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 14, "f14", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 15, "f15", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 16, "f16", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 17, "f17", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 18, "f18", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 19, "f19", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 20, "f20", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 21, "f21", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 22, "f22", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 23, "f23", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 24, "f24", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 25, "f25", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 26, "f26", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 27, "f27", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 28, "f28", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 29, "f29", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 30, "f30", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 31, "f31", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + + { MIPS32_REGLIST_FPC_INDEX + 0, "fcsr", REG_TYPE_INT, "float", + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS32_REGLIST_FPC_INDEX + 1, "fir", REG_TYPE_INT, "float", + "org.gnu.gdb.mips.fpu", 0 }, + + { MIPS32_REGLIST_C0_STATUS_INDEX, "status", REG_TYPE_INT, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS32_REGLIST_C0_BADVADDR_INDEX, "badvaddr", REG_TYPE_INT, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS32_REGLIST_C0_CAUSE_INDEX, "cause", REG_TYPE_INT, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS32_REGLIST_C0_PC_INDEX, "pc", REG_TYPE_INT, NULL, + "org.gnu.gdb.mips.cpu", 0 }, + { MIPS32_REGLIST_C0_GUESTCTL1_INDEX, "guestCtl1", REG_TYPE_INT, NULL, + "org.gnu.gdb.mips.cp0", 0 }, }; - #define MIPS32_NUM_REGS ARRAY_SIZE(mips32_regs) -static uint8_t mips32_gdb_dummy_fp_value[] = {0, 0, 0, 0}; - static int mips32_get_core_reg(struct reg *reg) { int retval; @@ -174,12 +179,21 @@ static int mips32_set_core_reg(struct reg *reg, uint8_t *buf) { struct mips32_core_reg *mips32_reg = reg->arch_info; struct target *target = mips32_reg->target; - uint32_t value = buf_get_u32(buf, 0, 32); + uint64_t value; + + if (reg->size == 64) + value = buf_get_u64(buf, 0, 64); + else + value = buf_get_u32(buf, 0, 32); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; - buf_set_u32(reg->value, 0, 32, value); + if (reg->size == 64) + buf_set_u64(reg->value, 0, 64, value); + else + buf_set_u32(reg->value, 0, 32, value); + reg->dirty = true; reg->valid = true; @@ -188,7 +202,8 @@ static int mips32_set_core_reg(struct reg *reg, uint8_t *buf) static int mips32_read_core_reg(struct target *target, unsigned int num) { - uint32_t reg_value; + unsigned int cnum; + uint64_t reg_value = 0; /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); @@ -196,17 +211,40 @@ static int mips32_read_core_reg(struct target *target, unsigned int num) if (num >= MIPS32_NUM_REGS) 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); + if (num >= MIPS32_REGLIST_C0_INDEX) { + /* CP0 */ + cnum = num - MIPS32_REGLIST_C0_INDEX; + reg_value = mips32->core_regs.cp0[cnum]; + buf_set_u32(mips32->core_cache->reg_list[num].value, 0, 32, reg_value); + } else if (num >= MIPS32_REGLIST_FPC_INDEX) { + /* FPCR */ + cnum = num - MIPS32_REGLIST_FPC_INDEX; + reg_value = mips32->core_regs.fpcr[cnum]; + buf_set_u32(mips32->core_cache->reg_list[num].value, 0, 32, reg_value); + } else if (num >= MIPS32_REGLIST_FP_INDEX) { + /* FPR */ + cnum = num - MIPS32_REGLIST_FP_INDEX; + reg_value = mips32->core_regs.fpr[cnum]; + buf_set_u64(mips32->core_cache->reg_list[num].value, 0, 64, reg_value); + } else { + /* GPR */ + cnum = num - MIPS32_REGLIST_GP_INDEX; + reg_value = mips32->core_regs.gpr[cnum]; + buf_set_u32(mips32->core_cache->reg_list[num].value, 0, 32, reg_value); + } + mips32->core_cache->reg_list[num].valid = true; mips32->core_cache->reg_list[num].dirty = false; + LOG_DEBUG("read core reg %i value 0x%" PRIx64 "", num, reg_value); + return ERROR_OK; } static int mips32_write_core_reg(struct target *target, unsigned int num) { - uint32_t reg_value; + unsigned int cnum; + uint64_t reg_value; /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); @@ -214,9 +252,29 @@ static int mips32_write_core_reg(struct target *target, unsigned int num) if (num >= MIPS32_NUM_REGS) 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); + if (num >= MIPS32_REGLIST_C0_INDEX) { + /* CP0 */ + cnum = num - MIPS32_REGLIST_C0_INDEX; + reg_value = buf_get_u32(mips32->core_cache->reg_list[num].value, 0, 32); + mips32->core_regs.cp0[cnum] = (uint32_t)reg_value; + } else if (num >= MIPS32_REGLIST_FPC_INDEX) { + /* FPCR */ + cnum = num - MIPS32_REGLIST_FPC_INDEX; + reg_value = buf_get_u32(mips32->core_cache->reg_list[num].value, 0, 32); + mips32->core_regs.fpcr[cnum] = (uint32_t)reg_value; + } else if (num >= MIPS32_REGLIST_FP_INDEX) { + /* FPR */ + cnum = num - MIPS32_REGLIST_FP_INDEX; + reg_value = buf_get_u64(mips32->core_cache->reg_list[num].value, 0, 64); + mips32->core_regs.fpr[cnum] = reg_value; + } else { + /* GPR */ + cnum = num - MIPS32_REGLIST_GP_INDEX; + reg_value = buf_get_u32(mips32->core_cache->reg_list[num].value, 0, 32); + mips32->core_regs.gpr[cnum] = (uint32_t)reg_value; + } + + LOG_DEBUG("write core reg %i value 0x%" PRIx64 "", num, reg_value); mips32->core_cache->reg_list[num].valid = true; mips32->core_cache->reg_list[num].dirty = false; @@ -246,10 +304,13 @@ int mips32_save_context(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; /* read core registers */ - mips32_pracc_read_regs(ejtag_info, mips32->core_regs); + int retval = mips32_pracc_read_regs(mips32); + if (retval != ERROR_OK) { + LOG_ERROR("Could not read core registers from target"); + return retval; + } for (i = 0; i < MIPS32_NUM_REGS; i++) { if (!mips32->core_cache->reg_list[i].valid) @@ -265,7 +326,6 @@ int mips32_restore_context(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; for (i = 0; i < MIPS32_NUM_REGS; i++) { if (mips32->core_cache->reg_list[i].dirty) @@ -273,7 +333,7 @@ int mips32_restore_context(struct target *target) } /* write core regs */ - mips32_pracc_write_regs(ejtag_info, mips32->core_regs); + mips32_pracc_write_regs(mips32); return ERROR_OK; } @@ -285,7 +345,7 @@ int mips32_arch_state(struct target *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)); + buf_get_u32(mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].value, 0, 32)); return ERROR_OK; } @@ -322,25 +382,19 @@ struct reg_cache *mips32_build_reg_cache(struct 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 = true; - reg_list[i].arch_info = NULL; - register_init_dummy(®_list[i]); - } else { - reg_list[i].value = calloc(1, 4); - reg_list[i].valid = false; - 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].size = mips32_regs[i].size ? 64 : 32; + + reg_list[i].value = mips32_regs[i].size ? calloc(1, 8) : calloc(1, 4); + reg_list[i].valid = false; + 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 = false; @@ -407,7 +461,7 @@ static int mips32_run_and_wait(struct target *target, target_addr_t entry_point, return ERROR_TARGET_TIMEOUT; } - pc = buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32); + pc = buf_get_u32(mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].value, 0, 32); if (exit_point && (pc != exit_point)) { LOG_DEBUG("failed algorithm halted at 0x%" PRIx32 " ", pc); return ERROR_TARGET_TIMEOUT; @@ -751,15 +805,82 @@ int mips32_cpu_probe(struct target *target) return ERROR_OK; } +/* reads dsp implementation info from CP0 Config3 register {DSPP, DSPREV}*/ +void mips32_read_config_dsp(struct mips32_common *mips32, struct mips_ejtag *ejtag_info) +{ + uint32_t dsp_present = ((ejtag_info->config[3] & MIPS32_CONFIG3_DSPP_MASK) >> MIPS32_CONFIG3_DSPP_SHIFT); + if (dsp_present) { + mips32->dsp_imp = ((ejtag_info->config[3] & MIPS32_CONFIG3_DSPREV_MASK) >> MIPS32_CONFIG3_DSPREV_SHIFT) + 1; + LOG_USER("DSP implemented: %s, rev %d", "yes", mips32->dsp_imp); + } else { + LOG_USER("DSP implemented: %s", "no"); + } +} + +/* read fpu implementation info from CP0 Config1 register {CU1, FP}*/ +int mips32_read_config_fpu(struct mips32_common *mips32, struct mips_ejtag *ejtag_info) +{ + int retval; + uint32_t fp_imp = (ejtag_info->config[1] & MIPS32_CONFIG1_FP_MASK) >> MIPS32_CONFIG1_FP_SHIFT; + char buf[60] = {0}; + if (!fp_imp) { + LOG_USER("FPU implemented: %s", "no"); + mips32->fp_imp = MIPS32_FP_IMP_NONE; + return ERROR_OK; + } + uint32_t status_value; + bool status_fr, status_cu1; + + retval = mips32_cp0_read(ejtag_info, &status_value, MIPS32_C0_STATUS, 0); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read cp0 status register"); + return retval; + } + + status_fr = (status_value >> MIPS32_CP0_STATUS_FR_SHIFT) & 0x1; + status_cu1 = (status_value >> MIPS32_CP0_STATUS_CU1_SHIFT) & 0x1; + if (status_cu1) { + /* TODO: read fpu(cp1) config register for current operating mode. + * Now its set to 32 bits by default. */ + snprintf(buf, sizeof(buf), "yes"); + fp_imp = MIPS32_FP_IMP_32; + } else { + snprintf(buf, sizeof(buf), "yes, disabled"); + fp_imp = MIPS32_FP_IMP_UNKNOWN; + } + + mips32->fpu_in_64bit = status_fr; + mips32->fpu_enabled = status_cu1; + + LOG_USER("FPU implemented: %s", buf); + mips32->fp_imp = fp_imp; + + return ERROR_OK; +} + +/* Checks if current target implements Common Device Memory Map and therefore Fast Debug Channel (MD00090) */ +void mips32_read_config_fdc(struct mips32_common *mips32, struct mips_ejtag *ejtag_info, uint32_t dcr) +{ + if (((ejtag_info->config[3] & MIPS32_CONFIG3_CDMM_MASK) != 0) && ((dcr & EJTAG_DCR_FDC) != 0)) { + mips32->fdc = 1; + mips32->semihosting = 1; + } else { + mips32->fdc = 0; + mips32->semihosting = 0; + } +} + /* read config to config3 cp0 registers and log isa implementation */ int mips32_read_config_regs(struct target *target) { struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; + char buf[60] = {0}; + int retval; if (ejtag_info->config_regs == 0) for (int i = 0; i != 4; i++) { - int retval = mips32_cp0_read(ejtag_info, &ejtag_info->config[i], 16, i); + retval = mips32_cp0_read(ejtag_info, &ejtag_info->config[i], 16, i); if (retval != ERROR_OK) { LOG_ERROR("isa info not available, failed to read cp0 config register: %" PRId32, i); ejtag_info->config_regs = 0; @@ -774,27 +895,56 @@ int mips32_read_config_regs(struct target *target) LOG_DEBUG("read %"PRIu32" config registers", ejtag_info->config_regs); + mips32->isa_rel = (ejtag_info->config[0] & MIPS32_CONFIG0_AR_MASK) >> MIPS32_CONFIG0_AR_SHIFT; + snprintf(buf, sizeof(buf), ", release %s(AR=%d)", + mips32->isa_rel == MIPS32_RELEASE_1 ? "1" + : mips32->isa_rel == MIPS32_RELEASE_2 ? "2" + : mips32->isa_rel == MIPS32_RELEASE_6 ? "6" + : "unknown", mips32->isa_rel); + if (ejtag_info->impcode & EJTAG_IMP_MIPS16) { mips32->isa_imp = MIPS32_MIPS16; - LOG_USER("MIPS32 with MIPS16 support implemented"); - + LOG_USER("ISA implemented: %s%s", "MIPS32, MIPS16", buf); } else if (ejtag_info->config_regs >= 4) { /* config3 implemented */ unsigned isa_imp = (ejtag_info->config[3] & MIPS32_CONFIG3_ISA_MASK) >> MIPS32_CONFIG3_ISA_SHIFT; if (isa_imp == 1) { mips32->isa_imp = MMIPS32_ONLY; - LOG_USER("MICRO MIPS32 only implemented"); + LOG_USER("ISA implemented: %s%s", "microMIPS32", buf); } else if (isa_imp != 0) { mips32->isa_imp = MIPS32_MMIPS32; - LOG_USER("MIPS32 and MICRO MIPS32 implemented"); + LOG_USER("ISA implemented: %s%s", "MIPS32, microMIPS32", buf); } + } else if (mips32->isa_imp == MIPS32_ONLY) { + /* initial default value */ + LOG_USER("ISA implemented: %s%s", "MIPS32", buf); + } + + /* Retrieve DSP info */ + mips32_read_config_dsp(mips32, ejtag_info); + + /* Retrieve if Float Point CoProcessor Implemented */ + retval = mips32_read_config_fpu(mips32, ejtag_info); + if (retval != ERROR_OK) { + LOG_ERROR("fpu info is not available, error while reading cp0 status"); + mips32->fp_imp = MIPS32_FP_IMP_NONE; + return retval; } - if (mips32->isa_imp == MIPS32_ONLY) /* initial default value */ - LOG_USER("MIPS32 only implemented"); + uint32_t dcr; + + retval = target_read_u32(target, EJTAG_DCR, &dcr); + if (retval != ERROR_OK) { + LOG_ERROR("failed to read EJTAG_DCR register"); + return retval; + } + + /* Determine if FDC and CDMM are implemented for this core */ + mips32_read_config_fdc(mips32, ejtag_info, dcr); return ERROR_OK; } + int mips32_checksum_memory(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum) { diff --git a/src/target/mips32.h b/src/target/mips32.h index 3d03e98..d072eb9 100644 --- a/src/target/mips32.h +++ b/src/target/mips32.h @@ -46,9 +46,21 @@ #define MIPS32_CONFIG0_AR_SHIFT 10 #define MIPS32_CONFIG0_AR_MASK (0x7 << MIPS32_CONFIG0_AR_SHIFT) +#define MIPS32_CONFIG1_FP_SHIFT 0 +#define MIPS32_CONFIG1_FP_MASK BIT(MIPS32_CONFIG1_FP_SHIFT) + #define MIPS32_CONFIG1_DL_SHIFT 10 #define MIPS32_CONFIG1_DL_MASK (0x7 << MIPS32_CONFIG1_DL_SHIFT) +#define MIPS32_CONFIG3_CDMM_SHIFT 3 +#define MIPS32_CONFIG3_CDMM_MASK BIT(MIPS32_CONFIG3_CDMM_SHIFT) + +#define MIPS32_CONFIG3_DSPP_SHIFT 10 +#define MIPS32_CONFIG3_DSPP_MASK BIT(MIPS32_CONFIG3_DSPP_SHIFT) + +#define MIPS32_CONFIG3_DSPREV_SHIFT 11 +#define MIPS32_CONFIG3_DSPREV_MASK BIT(MIPS32_CONFIG3_DSPREV_SHIFT) + #define MIPS32_CONFIG3_ISA_SHIFT 14 #define MIPS32_CONFIG3_ISA_MASK (3 << MIPS32_CONFIG3_ISA_SHIFT) @@ -57,6 +69,141 @@ #define MIPS32_SCAN_DELAY_LEGACY_MODE 2000000 +#define MIPS32_NUM_DSPREGS 9 + +/* Bit Mask indicating CP0 register supported by this core */ +#define MIPS_CP0_MK4 0x0001 +#define MIPS_CP0_MAPTIV_UC 0x0002 +#define MIPS_CP0_MAPTIV_UP 0x0004 +#define MIPS_CP0_IAPTIV 0x0008 + +/* CP0 Status register fields */ +#define MIPS32_CP0_STATUS_FR_SHIFT 26 +#define MIPS32_CP0_STATUS_CU1_SHIFT 29 + +/* CP1 FIR register fields */ +#define MIPS32_CP1_FIR_F64_SHIFT 22 + +static const struct { + unsigned int reg; + unsigned int sel; + const char *name; + const unsigned int core; +} mips32_cp0_regs[] = { + {0, 0, "index", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP}, + {0, 1, "mvpcontrol", MIPS_CP0_IAPTIV}, + {0, 2, "mvpconf0", MIPS_CP0_IAPTIV}, + {0, 3, "mvpconf1", MIPS_CP0_IAPTIV}, + {1, 0, "random", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP}, + {1, 1, "vpecontrol", MIPS_CP0_IAPTIV}, + {1, 2, "vpeconf0", MIPS_CP0_IAPTIV}, + {1, 3, "vpeconf1", MIPS_CP0_IAPTIV}, + {1, 4, "yqmask", MIPS_CP0_IAPTIV}, + {1, 5, "vpeschedule", MIPS_CP0_IAPTIV}, + {1, 6, "vpeschefback", MIPS_CP0_IAPTIV}, + {1, 7, "vpeopt", MIPS_CP0_IAPTIV}, + {2, 0, "entrylo0", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP}, + {2, 1, "tcstatus", MIPS_CP0_IAPTIV}, + {2, 2, "tcbind", MIPS_CP0_IAPTIV}, + {2, 3, "tcrestart", MIPS_CP0_IAPTIV}, + {2, 4, "tchalt", MIPS_CP0_IAPTIV}, + {2, 5, "tccontext", MIPS_CP0_IAPTIV}, + {2, 6, "tcschedule", MIPS_CP0_IAPTIV}, + {2, 7, "tcschefback", MIPS_CP0_IAPTIV}, + {3, 0, "entrylo1", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP}, + {3, 7, "tcopt", MIPS_CP0_IAPTIV}, + {4, 0, "context", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP}, + {4, 2, "userlocal", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {5, 0, "pagemask", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP}, + {5, 1, "pagegrain", MIPS_CP0_MAPTIV_UP}, + {5, 2, "segctl0", MIPS_CP0_IAPTIV}, + {5, 3, "segctl1", MIPS_CP0_IAPTIV}, + {5, 4, "segctl2", MIPS_CP0_IAPTIV}, + {6, 0, "wired", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP}, + {6, 1, "srsconf0", MIPS_CP0_IAPTIV}, + {6, 2, "srsconf1", MIPS_CP0_IAPTIV}, + {6, 3, "srsconf2", MIPS_CP0_IAPTIV}, + {6, 4, "srsconf3", MIPS_CP0_IAPTIV}, + {6, 5, "srsconf4", MIPS_CP0_IAPTIV}, + {7, 0, "hwrena", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {8, 0, "badvaddr", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {8, 1, "badinstr", MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP}, + {8, 2, "badinstrp", MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP}, + {9, 0, "count", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {10, 0, "entryhi", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP}, + {10, 4, "guestctl1", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MK4}, + {10, 5, "guestctl2", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MK4}, + {10, 6, "guestctl3", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MK4}, + {11, 0, "compare", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {11, 4, "guestctl0ext", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MK4}, + {12, 0, "status", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {12, 1, "intctl", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {12, 2, "srsctl", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {12, 3, "srsmap", MIPS_CP0_IAPTIV}, + {12, 3, "srsmap1", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP}, + {12, 4, "view_ipl", MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {12, 5, "srsmap2", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP}, + {12, 6, "guestctl0", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MK4}, + {12, 7, "gtoffset", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MK4}, + {13, 0, "cause", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {13, 5, "nestedexc", MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {14, 0, "epc", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {14, 2, "nestedepc", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {15, 0, "prid", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {15, 1, "ebase", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {15, 2, "cdmmbase", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {15, 3, "cmgcrbase", MIPS_CP0_IAPTIV}, + {16, 0, "config", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {16, 1, "config1", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {16, 2, "config2", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {16, 3, "config3", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {16, 4, "config4", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {16, 5, "config5", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {16, 7, "config7", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {17, 0, "lladdr", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {18, 0, "watchlo0", MIPS_CP0_IAPTIV}, + {18, 1, "watchlo1", MIPS_CP0_IAPTIV}, + {18, 2, "watchlo2", MIPS_CP0_IAPTIV}, + {18, 3, "watchlo3", MIPS_CP0_IAPTIV}, + {19, 0, "watchhi0", MIPS_CP0_IAPTIV}, + {19, 1, "watchhi1", MIPS_CP0_IAPTIV}, + {19, 2, "watchhi2", MIPS_CP0_IAPTIV}, + {19, 3, "watchhi3", MIPS_CP0_IAPTIV}, + {23, 0, "debug", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {23, 1, "tracecontrol", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {23, 2, "tracecontrol2", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {23, 3, "usertracedata1", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {23, 4, "tracebpc", MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {23, 4, "traceibpc", MIPS_CP0_IAPTIV}, + {23, 5, "tracedbpc", MIPS_CP0_IAPTIV}, + {24, 0, "depc", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {24, 2, "tracecontrol3", MIPS_CP0_IAPTIV}, + {24, 3, "usertracedata2", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {25, 0, "perfctl0", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {25, 1, "perfcnt0", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {25, 2, "perfctl1", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {25, 3, "perfcnt1", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {26, 0, "errctl", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {27, 0, "cacheerr", MIPS_CP0_IAPTIV}, + {28, 0, "itaglo", MIPS_CP0_IAPTIV}, + {28, 0, "taglo", MIPS_CP0_IAPTIV}, + {28, 1, "idatalo", MIPS_CP0_IAPTIV}, + {28, 1, "datalo", MIPS_CP0_IAPTIV}, + {28, 2, "dtaglo", MIPS_CP0_IAPTIV}, + {28, 3, "ddatalo", MIPS_CP0_IAPTIV}, + {28, 4, "l23taglo", MIPS_CP0_IAPTIV}, + {28, 5, "l23datalo", MIPS_CP0_IAPTIV}, + {29, 1, "idatahi", MIPS_CP0_IAPTIV}, + {29, 2, "dtaghi", MIPS_CP0_IAPTIV}, + {29, 5, "l23datahi", MIPS_CP0_IAPTIV}, + {30, 0, "errorepc", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {31, 0, "desave", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {31, 2, "kscratch1", MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP}, + {31, 3, "kscratch2", MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP}, +}; + +#define MIPS32NUMCP0REGS ((int)ARRAY_SIZE(mips32_cp0_regs)) + /* Insert extra NOPs after the DRET instruction on exit from debug. */ #define EJTAG_QUIRK_PAD_DRET BIT(0) @@ -67,6 +214,30 @@ enum { MIPS32NUMCOREREGS }; +/* offsets into mips32 core register cache */ + +#define MIPS32_REG_GP_COUNT 34 +#define MIPS32_REG_FP_COUNT 32 +#define MIPS32_REG_FPC_COUNT 2 +#define MIPS32_REG_C0_COUNT 5 + +#define MIPS32_REGLIST_GP_INDEX 0 +#define MIPS32_REGLIST_FP_INDEX (MIPS32_REGLIST_GP_INDEX + MIPS32_REG_GP_COUNT) +#define MIPS32_REGLIST_FPC_INDEX (MIPS32_REGLIST_FP_INDEX + MIPS32_REG_FP_COUNT) +#define MIPS32_REGLIST_C0_INDEX (MIPS32_REGLIST_FPC_INDEX + MIPS32_REG_FPC_COUNT) + +#define MIPS32_REGLIST_C0_STATUS_INDEX (MIPS32_REGLIST_C0_INDEX + 0) +#define MIPS32_REGLIST_C0_BADVADDR_INDEX (MIPS32_REGLIST_C0_INDEX + 1) +#define MIPS32_REGLIST_C0_CAUSE_INDEX (MIPS32_REGLIST_C0_INDEX + 2) +#define MIPS32_REGLIST_C0_PC_INDEX (MIPS32_REGLIST_C0_INDEX + 3) +#define MIPS32_REGLIST_C0_GUESTCTL1_INDEX (MIPS32_REGLIST_C0_INDEX + 4) + +#define MIPS32_REG_C0_STATUS_INDEX 0 +#define MIPS32_REG_C0_BADVADDR_INDEX 1 +#define MIPS32_REG_C0_CAUSE_INDEX 2 +#define MIPS32_REG_C0_PC_INDEX 3 +#define MIPS32_REG_C0_GUESTCTL1_INDEX 4 + enum mips32_isa_mode { MIPS32_ISA_MIPS32 = 0, MIPS32_ISA_MIPS16E = 1, @@ -80,21 +251,67 @@ enum mips32_isa_imp { MIPS32_MMIPS32 = 3, }; +/* Release 2~5 does not have much change regarding to the ISA under User mode, +* therefore no new Architecture Revision(AR) level is assigned to them. +* Release 6 changed some instruction's encoding/mnemonic, removed instructions that +* has lost its purposes/none are using, and added some new instructions as well. +*/ +enum mips32_isa_rel { + MIPS32_RELEASE_1 = 0, + MIPS32_RELEASE_2 = 1, + MIPS32_RELEASE_6 = 2, + MIPS32_RELEASE_UNKNOWN, +}; + +enum mips32_fp_imp { + MIPS32_FP_IMP_NONE = 0, + MIPS32_FP_IMP_32 = 1, + MIPS32_FP_IMP_64 = 2, + MIPS32_FP_IMP_UNKNOWN = 3, +}; + +enum mips32_dsp_imp { + MIPS32_DSP_IMP_NONE = 0, + MIPS32_DSP_IMP_REV1 = 1, + MIPS32_DSP_IMP_REV2 = 2, +}; + struct mips32_comparator { int used; uint32_t bp_value; uint32_t reg_address; }; +struct mips32_core_regs { + uint32_t gpr[MIPS32_REG_GP_COUNT]; + uint64_t fpr[MIPS32_REG_FP_COUNT]; + uint32_t fpcr[MIPS32_REG_FPC_COUNT]; + uint32_t cp0[MIPS32_REG_C0_COUNT]; +}; + struct mips32_common { unsigned int common_magic; void *arch_info; struct reg_cache *core_cache; struct mips_ejtag ejtag_info; - uint32_t core_regs[MIPS32NUMCOREREGS]; + + struct mips32_core_regs core_regs; + enum mips32_isa_mode isa_mode; enum mips32_isa_imp isa_imp; + enum mips32_isa_rel isa_rel; + enum mips32_fp_imp fp_imp; + enum mips32_dsp_imp dsp_imp; + + int fdc; + int semihosting; + uint32_t cp0_mask; + + /* FPU enabled (cp0.status.cu1) */ + bool fpu_enabled; + /* FPU mode (cp0.status.fr) */ + bool fpu_in_64bit; /* processor identification register */ uint32_t prid; @@ -394,6 +611,173 @@ struct mips32_algorithm { #define MIPS16_SDBBP(isa) (isa ? MMIPS16_SDBBP : MIPS16_ISA_SDBBP) +/* + * MIPS32 Config1 Register (CP0 Register 16, Select 1) + */ +#define MIPS32_CFG1_M 0x80000000 /* Config2 implemented */ +#define MIPS32_CFG1_MMUSMASK 0x7e000000 /* mmu size - 1 */ +#define MIPS32_CFG1_MMUSSHIFT 25 +#define MIPS32_CFG1_ISMASK 0x01c00000 /* icache lines 64<<n */ +#define MIPS32_CFG1_ISSHIFT 22 +#define MIPS32_CFG1_ILMASK 0x00380000 /* icache line size 2<<n */ +#define MIPS32_CFG1_ILSHIFT 19 +#define MIPS32_CFG1_IAMASK 0x00070000 /* icache ways - 1 */ +#define MIPS32_CFG1_IASHIFT 16 +#define MIPS32_CFG1_DSMASK 0x0000e000 /* dcache lines 64<<n */ +#define MIPS32_CFG1_DSSHIFT 13 +#define MIPS32_CFG1_DLMASK 0x00001c00 /* dcache line size 2<<n */ +#define MIPS32_CFG1_DLSHIFT 10 +#define MIPS32_CFG1_DAMASK 0x00000380 /* dcache ways - 1 */ +#define MIPS32_CFG1_DASHIFT 7 +#define MIPS32_CFG1_C2 0x00000040 /* Coprocessor 2 present */ +#define MIPS32_CFG1_MD 0x00000020 /* MDMX implemented */ +#define MIPS32_CFG1_PC 0x00000010 /* performance counters implemented */ +#define MIPS32_CFG1_WR 0x00000008 /* watch registers implemented */ +#define MIPS32_CFG1_CA 0x00000004 /* compression (mips16) implemented */ +#define MIPS32_CFG1_EP 0x00000002 /* ejtag implemented */ +#define MIPS32_CFG1_FP 0x00000001 /* fpu implemented */ + +/* + * MIPS32 Coprocessor 0 register numbers + */ +#define MIPS32_C0_INDEX 0 +#define MIPS32_C0_INX 0 +#define MIPS32_C0_RANDOM 1 +#define MIPS32_C0_RAND 1 +#define MIPS32_C0_ENTRYLO0 2 +#define MIPS32_C0_TLBLO0 2 +#define MIPS32_C0_ENTRYLO1 3 +#define MIPS32_C0_TLBLO1 3 +#define MIPS32_C0_CONTEXT 4 +#define MIPS32_C0_CTXT 4 +#define MIPS32_C0_PAGEMASK 5 +#define MIPS32_C0_PAGEGRAIN (5, 1) +#define MIPS32_C0_WIRED 6 +#define MIPS32_C0_HWRENA 7 +#define MIPS32_C0_BADVADDR 8 +#define MIPS32_C0_VADDR 8 +#define MIPS32_C0_COUNT 9 +#define MIPS32_C0_ENTRYHI 10 +#define MIPS32_C0_TLBHI 10 +#define MIPS32_C0_GUESTCTL1 10 +#define MIPS32_C0_COMPARE 11 +#define MIPS32_C0_STATUS 12 +#define MIPS32_C0_SR 12 +#define MIPS32_C0_INTCTL (12, 1) +#define MIPS32_C0_SRSCTL (12, 2) +#define MIPS32_C0_SRSMAP (12, 3) +#define MIPS32_C0_CAUSE 13 +#define MIPS32_C0_CR 13 +#define MIPS32_C0_EPC 14 +#define MIPS32_C0_PRID 15 +#define MIPS32_C0_EBASE (15, 1) +#define MIPS32_C0_CONFIG 16 +#define MIPS32_C0_CONFIG0 (16, 0) +#define MIPS32_C0_CONFIG1 (16, 1) +#define MIPS32_C0_CONFIG2 (16, 2) +#define MIPS32_C0_CONFIG3 (16, 3) +#define MIPS32_C0_LLADDR 17 +#define MIPS32_C0_WATCHLO 18 +#define MIPS32_C0_WATCHHI 19 +#define MIPS32_C0_DEBUG 23 +#define MIPS32_C0_DEPC 24 +#define MIPS32_C0_PERFCNT 25 +#define MIPS32_C0_ERRCTL 26 +#define MIPS32_C0_CACHEERR 27 +#define MIPS32_C0_TAGLO 28 +#define MIPS32_C0_ITAGLO 28 +#define MIPS32_C0_DTAGLO (28, 2) +#define MIPS32_C0_TAGLO2 (28, 4) +#define MIPS32_C0_DATALO (28, 1) +#define MIPS32_C0_IDATALO (28, 1) +#define MIPS32_C0_DDATALO (28, 3) +#define MIPS32_C0_DATALO2 (28, 5) +#define MIPS32_C0_TAGHI 29 +#define MIPS32_C0_ITAGHI 29 +#define MIPS32_C0_DATAHI (29, 1) +#define MIPS32_C0_ERRPC 30 +#define MIPS32_C0_DESAVE 31 + +/* + * MIPS32 MMU types + */ +#define MIPS32_MMU_TLB 1 +#define MIPS32_MMU_BAT 2 +#define MIPS32_MMU_FIXED 3 +#define MIPS32_MMU_DUAL_VTLB_FTLB 4 + +enum mips32_cpu_vendor { + MIPS32_CPU_VENDOR_MTI, + MIPS32_CPU_VENDOR_ALCHEMY, + MIPS32_CPU_VENDOR_BROADCOM, + MIPS32_CPU_VENDOR_ALTERA, + MIPS32_CPU_VENDOR_LEXRA, +}; + +enum mips32_isa_supported { + MIPS16, + MIPS32, + MIPS64, + MICROMIPS_ONLY, + MIPS32_AT_RESET_AND_MICROMIPS, + MICROMIPS_AT_RESET_AND_MIPS32, +}; + +struct mips32_cpu_features { + /* Type of CPU (4Kc, 24Kf, etc.) */ + uint32_t cpu_core; + + /* Internal representation of cpu type */ + uint32_t cpu_type; + + /* Processor vendor */ + enum mips32_cpu_vendor vendor; + + /* Supported ISA and boot config */ + enum mips32_isa_supported isa; + + /* PRID */ + uint32_t prid; + + /* Processor implemented the MultiThreading ASE */ + bool mtase; + + /* Processor implemented the DSP ASE */ + bool dspase; + + /* Processor implemented the SmartMIPS ASE */ + bool smase; + + /* Processor implemented the MIPS16[e] ASE */ + bool m16ase; + + /* Processor implemented the microMIPS ASE */ + bool micromipsase; + + /* Processor implemented the Virtualization ASE */ + uint32_t vzase; + + uint32_t vz_guest_id_width; + + /* ebase.cpuid number */ + uint32_t cpuid; + + uint32_t inst_cache_size; + uint32_t data_cache_size; + uint32_t mmu_type; + uint32_t tlb_entries; + uint32_t num_shadow_regs; + + /* Processor implemented the MSA module */ + bool msa; + + /* Processor implemented mfhc0 and mthc0 instructions */ + bool mvh; + + bool guest_ctl1_present; + bool cdmm; +}; + extern const struct command_registration mips32_command_handlers[]; int mips32_arch_state(struct target *target); diff --git a/src/target/mips32_pracc.c b/src/target/mips32_pracc.c index c4704b5..9f0d87c 100644 --- a/src/target/mips32_pracc.c +++ b/src/target/mips32_pracc.c @@ -823,9 +823,13 @@ int mips32_pracc_write_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int siz return retval; } -int mips32_pracc_write_regs(struct mips_ejtag *ejtag_info, uint32_t *regs) +int mips32_pracc_write_regs(struct mips32_common *mips32) { + struct mips_ejtag *ejtag_info = &mips32->ejtag_info; struct pracc_queue_info ctx = {.ejtag_info = ejtag_info}; + uint32_t *gprs = mips32->core_regs.gpr; + uint32_t *c0rs = mips32->core_regs.cp0; + pracc_queue_init(&ctx); uint32_t cp0_write_code[] = { @@ -837,66 +841,178 @@ int mips32_pracc_write_regs(struct mips_ejtag *ejtag_info, uint32_t *regs) MIPS32_MTC0(ctx.isa, 1, 24, 0), /* move $1 to depc (pc) */ }; + uint32_t cp0_write_data[] = { + /* lo */ + gprs[32], + /* hi */ + gprs[33], + /* status */ + c0rs[0], + /* badvaddr */ + c0rs[1], + /* cause */ + c0rs[2], + /* depc (pc) */ + c0rs[3], + }; + + for (size_t i = 0; i < ARRAY_SIZE(cp0_write_code); i++) { + /* load CP0 value in $1 */ + pracc_add_li32(&ctx, 1, cp0_write_data[i], 0); + /* write value from $1 to CP0 register */ + pracc_add(&ctx, 0, cp0_write_code[i]); + } + /* load registers 2 to 31 with li32, optimize */ for (int i = 2; i < 32; i++) - pracc_add_li32(&ctx, i, regs[i], 1); + pracc_add_li32(&ctx, i, gprs[i], 1); - for (int i = 0; i != 6; i++) { - pracc_add_li32(&ctx, 1, regs[i + 32], 0); /* load CPO value in $1 */ - pracc_add(&ctx, 0, cp0_write_code[i]); /* write value from $1 to CPO register */ - } - pracc_add(&ctx, 0, MIPS32_MTC0(ctx.isa, 15, 31, 0)); /* load $15 in DeSave */ - pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 1, UPPER16((regs[1])))); /* load upper half word in $1 */ - pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); /* jump to start */ - pracc_add(&ctx, 0, MIPS32_ORI(ctx.isa, 1, 1, LOWER16((regs[1])))); /* load lower half word in $1 */ + /* load $15 in DeSave */ + pracc_add(&ctx, 0, MIPS32_MTC0(ctx.isa, 15, 31, 0)); + /* load upper half word in $1 */ + pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 1, UPPER16((gprs[1])))); + /* jump to start */ + pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); + /* load lower half word in $1 */ + pracc_add(&ctx, 0, MIPS32_ORI(ctx.isa, 1, 1, LOWER16((gprs[1])))); ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL, 1); - ejtag_info->reg8 = regs[8]; - ejtag_info->reg9 = regs[9]; + ejtag_info->reg8 = gprs[8]; + ejtag_info->reg9 = gprs[9]; pracc_queue_free(&ctx); return ctx.retval; } -int mips32_pracc_read_regs(struct mips_ejtag *ejtag_info, uint32_t *regs) +/* Saves content in `$1` to `DeSave(cp0.31.0)` and loads `MIPS32_PRACC_BASE_ADDR` into `$1` */ +static void mips32_pracc_store_regs_set_base_addr(struct pracc_queue_info *ctx) { - struct pracc_queue_info ctx = {.ejtag_info = ejtag_info}; - pracc_queue_init(&ctx); + /* move $1 to COP0 DeSave */ + pracc_add(ctx, 0, MIPS32_MTC0(ctx->isa, 1, 31, 0)); + /* $1 = MIP32_PRACC_BASE_ADDR */ + pracc_add(ctx, 0, MIPS32_LUI(ctx->isa, 1, PRACC_UPPER_BASE_ADDR)); +} - uint32_t cp0_read_code[] = { - MIPS32_MFC0(ctx.isa, 8, 12, 0), /* move status to $8 */ - MIPS32_MFLO(ctx.isa, 8), /* move lo to $8 */ - MIPS32_MFHI(ctx.isa, 8), /* move hi to $8 */ - MIPS32_MFC0(ctx.isa, 8, 8, 0), /* move badvaddr to $8 */ - MIPS32_MFC0(ctx.isa, 8, 13, 0), /* move cause to $8 */ - MIPS32_MFC0(ctx.isa, 8, 24, 0), /* move depc (pc) to $8 */ +/* This function assumes the address for saving is stored in `$1`. + * And that action is performed in `mips32_pracc_set_save_base_addr`. + */ +static void mips32_pracc_store_regs_gpr(struct pracc_queue_info *ctx, unsigned int offset_gpr) +{ + for (int i = 2; i != 32; i++) + pracc_add(ctx, MIPS32_PRACC_PARAM_OUT + offset_gpr + (i * 4), + MIPS32_SW(ctx->isa, i, PRACC_OUT_OFFSET + offset_gpr + (i * 4), 1)); +} + +static void mips32_pracc_store_regs_lohi(struct pracc_queue_info *ctx) +{ + uint32_t lohi_read_code[] = { + MIPS32_MFLO(ctx->isa, 8), /* move lo to $8 */ + MIPS32_MFHI(ctx->isa, 8), /* move hi to $8 */ }; - pracc_add(&ctx, 0, MIPS32_MTC0(ctx.isa, 1, 31, 0)); /* move $1 to COP0 DeSave */ - pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 1, PRACC_UPPER_BASE_ADDR)); /* $1 = MIP32_PRACC_BASE_ADDR */ + /* store lo & hi */ + for (int i = 0; i < 2; i++) { + /* load COP0 needed registers to $8 */ + pracc_add(ctx, 0, lohi_read_code[i]); + /* store $8 at PARAM OUT */ + pracc_add(ctx, MIPS32_PRACC_PARAM_OUT + (i + 32) * 4, + MIPS32_SW(ctx->isa, 8, PRACC_OUT_OFFSET + (i + 32) * 4, 1)); + } +} - for (int i = 2; i != 32; i++) /* store GPR's 2 to 31 */ - pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + (i * 4), - MIPS32_SW(ctx.isa, i, PRACC_OUT_OFFSET + (i * 4), 1)); +/* Saves CP0 registers [status, badvaddr, cause, depc] */ +static void mips32_pracc_store_regs_cp0_context(struct pracc_queue_info *ctx, unsigned int offset_cp0) +{ + uint32_t cp0_read_code[] = { + MIPS32_MFC0(ctx->isa, 8, 12, 0), /* move status to $8 */ + MIPS32_MFC0(ctx->isa, 8, 8, 0), /* move badvaddr to $8 */ + MIPS32_MFC0(ctx->isa, 8, 13, 0), /* move cause to $8 */ + MIPS32_MFC0(ctx->isa, 8, 24, 0), /* move depc (pc) to $8 */ + }; - for (int i = 0; i != 6; i++) { - pracc_add(&ctx, 0, cp0_read_code[i]); /* load COP0 needed registers to $8 */ - pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + (i + 32) * 4, /* store $8 at PARAM OUT */ - MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET + (i + 32) * 4, 1)); + /* store cp0 */ + for (size_t i = 0; i < ARRAY_SIZE(cp0_read_code); i++) { + size_t offset = offset_cp0 + (i * 4); + + /* load COP0 needed registers to $8 */ + pracc_add(ctx, 0, cp0_read_code[i]); + /* store $8 at PARAM OUT */ + pracc_add(ctx, MIPS32_PRACC_PARAM_OUT + offset, + MIPS32_SW(ctx->isa, 8, PRACC_OUT_OFFSET + offset, 1)); } - pracc_add(&ctx, 0, MIPS32_MFC0(ctx.isa, 8, 31, 0)); /* move DeSave to $8, reg1 value */ - pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + 4, /* store reg1 value from $8 to param out */ - MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET + 4, 1)); +} - pracc_add(&ctx, 0, MIPS32_MFC0(ctx.isa, 1, 31, 0)); /* move COP0 DeSave to $1, restore reg1 */ - pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); /* jump to start */ - pracc_add(&ctx, 0, MIPS32_MTC0(ctx.isa, 15, 31, 0)); /* load $15 in DeSave */ +/* Loads original content of $1 into $8, + * then store it to the batch data access address. + * Finally it restores $1 from DeSave. + */ +static void mips32_pracc_store_regs_restore(struct pracc_queue_info *ctx) +{ + /* move DeSave to $8, reg1 value */ + pracc_add(ctx, 0, MIPS32_MFC0(ctx->isa, 8, 31, 0)); + /* store reg1 value from $8 to param out */ + pracc_add(ctx, MIPS32_PRACC_PARAM_OUT + 4, + MIPS32_SW(ctx->isa, 8, PRACC_OUT_OFFSET + 4, 1)); + + /* move COP0 DeSave to $1, restore reg1 */ + pracc_add(ctx, 0, MIPS32_MFC0(ctx->isa, 1, 31, 0)); +} + +/* This function performs following actions: + * Saves `$1` to `DeSave`, + * then load `PRACC_UPPER_BASE_ADDR` for saving the register data structure into `$1`, + * Saves `$2` ~ `$31` to `PRACC_UPPER_BASE_ADDR + offset_gpr` + * Saves HI and LO, + * Saves necessary cp0 registers. +*/ +static void mips32_pracc_store_regs(struct pracc_queue_info *ctx, + unsigned int offset_gpr, unsigned int offset_cp0) +{ + mips32_pracc_store_regs_set_base_addr(ctx); + mips32_pracc_store_regs_gpr(ctx, offset_gpr); + mips32_pracc_store_regs_lohi(ctx); + mips32_pracc_store_regs_cp0_context(ctx, offset_cp0); + mips32_pracc_store_regs_restore(ctx); +} + +int mips32_pracc_read_regs(struct mips32_common *mips32) +{ + struct mips_ejtag *ejtag_info = &mips32->ejtag_info; + struct pracc_queue_info ctx = {.ejtag_info = ejtag_info}; + struct mips32_core_regs *core_regs = &mips32->core_regs; + unsigned int offset_gpr = ((uint8_t *)&core_regs->gpr[0]) - (uint8_t *)core_regs; + unsigned int offset_cp0 = ((uint8_t *)&core_regs->cp0[0]) - (uint8_t *)core_regs; + + /* + * This procedure has to be in 2 distinctive steps, because we can + * only know whether FP is enabled after reading CP0. + * + * Step 1: Read everything except CP1 stuff + * Step 2: Read CP1 stuff if FP is implemented + */ + + pracc_queue_init(&ctx); - ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, regs, 1); + mips32_pracc_store_regs(&ctx, offset_gpr, offset_cp0); + + /* jump to start */ + pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); + /* load $15 in DeSave */ + pracc_add(&ctx, 0, MIPS32_MTC0(ctx.isa, 15, 31, 0)); + + ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, (uint32_t *)&mips32->core_regs, 1); - ejtag_info->reg8 = regs[8]; /* reg8 is saved but not restored, next called function should restore it */ - ejtag_info->reg9 = regs[9]; pracc_queue_free(&ctx); + + /* reg8 is saved but not restored, next called function should restore it */ + ejtag_info->reg8 = mips32->core_regs.gpr[8]; + ejtag_info->reg9 = mips32->core_regs.gpr[9]; + + /* we only care if FP is actually impl'd and if cp1 is enabled */ + /* since we already read cp0 in the prev step */ + /* now we know what's in cp0.status */ + /* TODO: Read FPRs */ + return ctx.retval; } diff --git a/src/target/mips32_pracc.h b/src/target/mips32_pracc.h index 1b00768..587a446 100644 --- a/src/target/mips32_pracc.h +++ b/src/target/mips32_pracc.h @@ -36,6 +36,8 @@ #define PRACC_BLOCK 128 /* 1 Kbyte */ +struct mips32_common; + struct pa_list { uint32_t instr; uint32_t addr; @@ -64,8 +66,8 @@ int mips32_pracc_write_mem(struct mips_ejtag *ejtag_info, int mips32_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, struct working_area *source, int write_t, uint32_t addr, int count, uint32_t *buf); -int mips32_pracc_read_regs(struct mips_ejtag *ejtag_info, uint32_t *regs); -int mips32_pracc_write_regs(struct mips_ejtag *ejtag_info, uint32_t *regs); +int mips32_pracc_read_regs(struct mips32_common *mips32); +int mips32_pracc_write_regs(struct mips32_common *mips32); /** * \b mips32_cp0_read diff --git a/src/target/mips64.c b/src/target/mips64.c index 37f3685..48f4563 100644 --- a/src/target/mips64.c +++ b/src/target/mips64.c @@ -247,8 +247,8 @@ static int mips64_set_core_reg(struct reg *reg, uint8_t *buf) return ERROR_TARGET_NOT_HALTED; buf_set_u64(reg->value, 0, 64, value); - reg->dirty = 1; - reg->valid = 1; + reg->dirty = true; + reg->valid = true; return ERROR_OK; } @@ -265,8 +265,8 @@ static int mips64_read_core_reg(struct target *target, int num) reg_value = mips64->core_regs[num]; buf_set_u64(mips64->core_cache->reg_list[num].value, 0, 64, reg_value); - mips64->core_cache->reg_list[num].valid = 1; - mips64->core_cache->reg_list[num].dirty = 0; + mips64->core_cache->reg_list[num].valid = true; + mips64->core_cache->reg_list[num].dirty = false; return ERROR_OK; } @@ -284,8 +284,8 @@ static int mips64_write_core_reg(struct target *target, int num) reg_value = buf_get_u64(mips64->core_cache->reg_list[num].value, 0, 64); mips64->core_regs[num] = reg_value; LOG_DEBUG("write core reg %i value 0x%" PRIx64 "", num, reg_value); - mips64->core_cache->reg_list[num].valid = 1; - mips64->core_cache->reg_list[num].dirty = 0; + mips64->core_cache->reg_list[num].valid = true; + mips64->core_cache->reg_list[num].dirty = false; return ERROR_OK; } @@ -297,8 +297,8 @@ int mips64_invalidate_core_regs(struct target *target) unsigned int i; for (i = 0; i < mips64->core_cache->num_regs; i++) { - mips64->core_cache->reg_list[i].valid = 0; - mips64->core_cache->reg_list[i].dirty = 0; + mips64->core_cache->reg_list[i].valid = false; + mips64->core_cache->reg_list[i].dirty = false; } return ERROR_OK; diff --git a/src/target/mips_ejtag.h b/src/target/mips_ejtag.h index eb80742..852444a 100644 --- a/src/target/mips_ejtag.h +++ b/src/target/mips_ejtag.h @@ -123,11 +123,12 @@ /* Debug Control Register DCR */ #define EJTAG_DCR 0xFF300000 -#define EJTAG_DCR_ENM (1 << 29) -#define EJTAG_DCR_DB (1 << 17) -#define EJTAG_DCR_IB (1 << 16) -#define EJTAG_DCR_INTE (1 << 4) -#define EJTAG_DCR_MP (1 << 2) +#define EJTAG_DCR_ENM BIT(29) +#define EJTAG_DCR_FDC BIT(18) +#define EJTAG_DCR_DB BIT(17) +#define EJTAG_DCR_IB BIT(16) +#define EJTAG_DCR_INTE BIT(4) +#define EJTAG_DCR_MP BIT(2) /* breakpoint support */ /* EJTAG_V20_* was tested on Broadcom BCM7401 diff --git a/src/target/mips_m4k.c b/src/target/mips_m4k.c index 46d241c..0a06bb1 100644 --- a/src/target/mips_m4k.c +++ b/src/target/mips_m4k.c @@ -108,11 +108,11 @@ static int mips_m4k_debug_entry(struct target *target) 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; @@ -443,18 +443,18 @@ static int mips_m4k_internal_restore(struct target *target, int current, /* 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); @@ -537,15 +537,15 @@ static int mips_m4k_step(struct target *target, int current, /* 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); } diff --git a/src/target/mips_mips64.c b/src/target/mips_mips64.c index bf60953..9921e93 100644 --- a/src/target/mips_mips64.c +++ b/src/target/mips_mips64.c @@ -625,8 +625,8 @@ static int mips_mips64_resume(struct target *target, int current, /* current = 1: continue on current pc, otherwise continue at <address> */ if (!current) { buf_set_u64(pc->value, 0, 64, address); - pc->dirty = 1; - pc->valid = 1; + pc->dirty = true; + pc->valid = true; } resume_pc = buf_get_u64(pc->value, 0, 64); @@ -717,8 +717,8 @@ static int mips_mips64_step(struct target *target, int current, * <address> */ if (!current) { buf_set_u64(pc->value, 0, 64, address); - pc->dirty = 1; - pc->valid = 1; + pc->dirty = true; + pc->valid = true; } /* the front-end may request us not to handle breakpoints */ diff --git a/src/target/target.c b/src/target/target.c index 167b1ea..cfd0641 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -3053,6 +3053,10 @@ COMMAND_HANDLER(handle_reg_command) LOG_DEBUG("-"); struct target *target = get_current_target(CMD_CTX); + if (!target_was_examined(target)) { + LOG_ERROR("Target not examined yet"); + return ERROR_TARGET_NOT_EXAMINED; + } struct reg *reg = NULL; /* list all available registers for the current target */ @@ -3117,7 +3121,7 @@ COMMAND_HANDLER(handle_reg_command) if (!reg) { command_print(CMD, "%i is out of bounds, the current target " "has only %i registers (0 - %i)", num, count, count - 1); - return ERROR_OK; + return ERROR_FAIL; } } else { /* access a single register by its name */ @@ -3136,9 +3140,9 @@ COMMAND_HANDLER(handle_reg_command) if ((CMD_ARGC == 1) || ((CMD_ARGC == 2) && !((CMD_ARGV[1][0] >= '0') && (CMD_ARGV[1][0] <= '9')))) { if ((CMD_ARGC == 2) && (strcmp(CMD_ARGV[1], "force") == 0)) - reg->valid = 0; + reg->valid = false; - if (reg->valid == 0) { + if (!reg->valid) { int retval = reg->type->get(reg); if (retval != ERROR_OK) { LOG_ERROR("Could not read register '%s'", reg->name); @@ -3176,7 +3180,7 @@ COMMAND_HANDLER(handle_reg_command) not_found: command_print(CMD, "register %s not found in current target", CMD_ARGV[0]); - return ERROR_OK; + return ERROR_FAIL; } COMMAND_HANDLER(handle_poll_command) @@ -4071,13 +4075,14 @@ COMMAND_HANDLER(handle_wp_command) struct watchpoint *watchpoint = target->watchpoints; while (watchpoint) { + char wp_type = (watchpoint->rw == WPT_READ ? 'r' : (watchpoint->rw == WPT_WRITE ? 'w' : 'a')); command_print(CMD, "address: " TARGET_ADDR_FMT ", len: 0x%8.8" PRIx32 - ", r/w/a: %i, value: 0x%8.8" PRIx64 + ", r/w/a: %c, value: 0x%8.8" PRIx64 ", mask: 0x%8.8" PRIx64, watchpoint->address, watchpoint->length, - (int)watchpoint->rw, + wp_type, watchpoint->value, watchpoint->mask); watchpoint = watchpoint->next; @@ -4138,17 +4143,28 @@ COMMAND_HANDLER(handle_wp_command) COMMAND_HANDLER(handle_rwp_command) { + int retval; + if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - target_addr_t addr; - COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); - struct target *target = get_current_target(CMD_CTX); - int retval = watchpoint_remove(target, addr); + if (!strcmp(CMD_ARGV[0], "all")) { + retval = watchpoint_remove_all(target); - if (retval != ERROR_OK) - command_print(CMD, "Error during removal of watchpoint at address " TARGET_ADDR_FMT, addr); + if (retval != ERROR_OK) { + command_print(CMD, "Error encountered during removal of all watchpoints."); + command_print(CMD, "Some watchpoints may have remained set."); + } + } else { + target_addr_t addr; + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); + + retval = watchpoint_remove(target, addr); + + if (retval != ERROR_OK) + command_print(CMD, "Error during removal of watchpoint at address " TARGET_ADDR_FMT, addr); + } return retval; } @@ -5135,7 +5151,7 @@ static int target_jim_get_reg(Jim_Interp *interp, int argc, return JIM_ERR; } - if (force) { + if (force || !reg->valid) { int retval = reg->type->get(reg); if (retval != ERROR_OK) { @@ -5860,6 +5876,18 @@ COMMAND_HANDLER(handle_target_current_state) return ERROR_OK; } +COMMAND_HANDLER(handle_target_debug_reason) +{ + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct target *target = get_current_target(CMD_CTX); + + command_print(CMD, "%s", debug_reason_name(target)); + + return ERROR_OK; +} + static int jim_target_invoke_event(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { struct jim_getopt_info goi; @@ -6012,6 +6040,13 @@ static const struct command_registration target_instance_command_handlers[] = { .usage = "", }, { + .name = "debug_reason", + .mode = COMMAND_EXEC, + .handler = handle_target_debug_reason, + .help = "displays the debug reason of this target", + .usage = "", + }, + { .name = "arp_examine", .mode = COMMAND_EXEC, .handler = handle_target_examine, @@ -6110,7 +6145,7 @@ static int target_create(struct jim_getopt_info *goi) if (e != JIM_OK) return e; struct transport *tr = get_current_transport(); - if (tr->override_target) { + if (tr && tr->override_target) { e = tr->override_target(&cp); if (e != ERROR_OK) { LOG_ERROR("The selected transport doesn't support this target"); @@ -7067,7 +7102,7 @@ static const struct command_registration target_exec_command_handlers[] = { .handler = handle_rwp_command, .mode = COMMAND_EXEC, .help = "remove watchpoint", - .usage = "address", + .usage = "'all' | address", }, { .name = "load_image", |