diff --git a/src/target/mips32.c b/src/target/mips32.c index 4e6d25118e..18160b2373 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,9 @@ 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); + mips32_pracc_read_regs(mips32); for (i = 0; i < MIPS32_NUM_REGS; i++) { if (!mips32->core_cache->reg_list[i].valid) @@ -265,7 +322,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 +329,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 +341,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 +378,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 +457,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; diff --git a/src/target/mips32.h b/src/target/mips32.h index 3d03e98c58..7bf6384582 100644 --- a/src/target/mips32.h +++ b/src/target/mips32.h @@ -57,6 +57,139 @@ #define MIPS32_SCAN_DELAY_LEGACY_MODE 2000000 +/* 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 +200,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, @@ -86,13 +243,22 @@ struct mips32_comparator { 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; diff --git a/src/target/mips32_pracc.c b/src/target/mips32_pracc.c index c4704b5a5d..9f0d87cd98 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 1b00768676..587a446918 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/mips_ejtag.h b/src/target/mips_ejtag.h index eb80742d65..852444a519 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 46d241cb30..0a06bb1604 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
*/ 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
*/ 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); }