diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c index 79f10f10e..95328037b 100644 --- a/src/target/riscv/riscv-011.c +++ b/src/target/riscv/riscv-011.c @@ -764,10 +764,10 @@ static void cache_set32(struct target *target, unsigned int index, uint32_t data if (info->dram_cache[index].valid && info->dram_cache[index].data == data) { // This is already preset on the target. - LOG_DEBUG("cache[0x%x] = 0x%x (hit)", index, data); + LOG_DEBUG("cache[0x%x] = 0x%08x: DASM(0x%x) (hit)", index, data, data); return; } - LOG_DEBUG("cache[0x%x] = 0x%x", index, data); + LOG_DEBUG("cache[0x%x] = 0x%08x: DASM(0x%x)", index, data, data); info->dram_cache[index].data = data; info->dram_cache[index].valid = true; info->dram_cache[index].dirty = true; @@ -1033,6 +1033,7 @@ static int wait_for_state(struct target *target, enum target_state state) static int read_csr(struct target *target, uint64_t *value, uint32_t csr) { + riscv011_info_t *info = get_info(target); cache_set32(target, 0, csrr(S0, csr)); cache_set_store(target, 1, S0, SLOT0); cache_set_jump(target, 2); @@ -1042,6 +1043,13 @@ static int read_csr(struct target *target, uint64_t *value, uint32_t csr) *value = cache_get(target, SLOT0); LOG_DEBUG("csr 0x%x = 0x%" PRIx64, csr, *value); + uint32_t exception = cache_get32(target, info->dramsize-1); + if (exception) { + LOG_ERROR("Got exception 0x%x when reading CSR 0x%x", exception, csr); + *value = ~0; + return ERROR_FAIL; + } + return ERROR_OK; } @@ -1496,6 +1504,104 @@ static void deinit_target(struct target *target) info->version_specific = NULL; } +static int maybe_add_trigger_t1(struct target *target, struct trigger *trigger, + uint64_t tdata1) +{ + riscv011_info_t *info = get_info(target); + + const uint32_t bpcontrol_x = 1<<0; + const uint32_t bpcontrol_w = 1<<1; + const uint32_t bpcontrol_r = 1<<2; + const uint32_t bpcontrol_u = 1<<3; + const uint32_t bpcontrol_s = 1<<4; + const uint32_t bpcontrol_h = 1<<5; + const uint32_t bpcontrol_m = 1<<6; + const uint32_t bpcontrol_bpmatch = 0xf << 7; + const uint32_t bpcontrol_bpaction = 0xff << 11; + + if (tdata1 & (bpcontrol_r | bpcontrol_w | bpcontrol_x)) { + // Trigger is already in use, presumably by user code. + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + tdata1 = set_field(tdata1, bpcontrol_r, trigger->read); + tdata1 = set_field(tdata1, bpcontrol_w, trigger->write); + tdata1 = set_field(tdata1, bpcontrol_x, trigger->execute); + tdata1 = set_field(tdata1, bpcontrol_u, !!(info->misa & (1 << ('U' - 'A')))); + tdata1 = set_field(tdata1, bpcontrol_s, !!(info->misa & (1 << ('S' - 'A')))); + tdata1 = set_field(tdata1, bpcontrol_h, !!(info->misa & (1 << ('H' - 'A')))); + tdata1 |= bpcontrol_m; + tdata1 = set_field(tdata1, bpcontrol_bpmatch, 0); // exact match + tdata1 = set_field(tdata1, bpcontrol_bpaction, 0); // cause bp exception + + write_csr(target, CSR_TDATA1, tdata1); + + uint64_t tdata1_rb; + read_csr(target, &tdata1_rb, CSR_TDATA1); + LOG_DEBUG("tdata1=0x%" PRIx64, tdata1_rb); + + if (tdata1 != tdata1_rb) { + LOG_DEBUG("Trigger doesn't support what we need; After writing 0x%" + PRIx64 " to tdata1 it contains 0x%" PRIx64, + tdata1, tdata1_rb); + write_csr(target, CSR_TDATA1, 0); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + write_csr(target, CSR_TDATA2, trigger->address); + + return ERROR_OK; +} + +static int maybe_add_trigger_t2(struct target *target, struct trigger *trigger, + uint64_t tdata1) +{ + riscv011_info_t *info = get_info(target); + // tselect is already set + if (tdata1 & (MCONTROL_EXECUTE | MCONTROL_STORE | MCONTROL_LOAD)) { + // Trigger is already in use, presumably by user code. + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + // address/data match trigger + tdata1 |= MCONTROL_DMODE(riscv_xlen(target)); + tdata1 = set_field(tdata1, MCONTROL_ACTION, + MCONTROL_ACTION_DEBUG_MODE); + tdata1 = set_field(tdata1, MCONTROL_MATCH, MCONTROL_MATCH_EQUAL); + tdata1 |= MCONTROL_M; + if (info->misa & (1 << ('H' - 'A'))) + tdata1 |= MCONTROL_H; + if (info->misa & (1 << ('S' - 'A'))) + tdata1 |= MCONTROL_S; + if (info->misa & (1 << ('U' - 'A'))) + tdata1 |= MCONTROL_U; + + if (trigger->execute) + tdata1 |= MCONTROL_EXECUTE; + if (trigger->read) + tdata1 |= MCONTROL_LOAD; + if (trigger->write) + tdata1 |= MCONTROL_STORE; + + write_csr(target, CSR_TDATA1, tdata1); + + uint64_t tdata1_rb; + read_csr(target, &tdata1_rb, CSR_TDATA1); + LOG_DEBUG("tdata1=0x%" PRIx64, tdata1_rb); + + if (tdata1 != tdata1_rb) { + LOG_DEBUG("Trigger doesn't support what we need; After writing 0x%" + PRIx64 " to tdata1 it contains 0x%" PRIx64, + tdata1, tdata1_rb); + write_csr(target, CSR_TDATA1, 0); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + write_csr(target, CSR_TDATA2, trigger->address); + + return ERROR_OK; +} + static int add_trigger(struct target *target, struct trigger *trigger) { riscv011_info_t *info = get_info(target); @@ -1514,51 +1620,23 @@ static int add_trigger(struct target *target, struct trigger *trigger) read_csr(target, &tdata1, CSR_TDATA1); int type = get_field(tdata1, MCONTROL_TYPE(riscv_xlen(target))); - if (type != 2) { - continue; + int result; + switch (type) { + case 1: + result = maybe_add_trigger_t1(target, trigger, tdata1); + break; + case 2: + result = maybe_add_trigger_t2(target, trigger, tdata1); + break; + default: + LOG_DEBUG("trigger %d has unknown type %d", i, type); + continue; } - if (tdata1 & (MCONTROL_EXECUTE | MCONTROL_STORE | MCONTROL_LOAD)) { - // Trigger is already in use, presumably by user code. + if (result != ERROR_OK) { continue; } - // address/data match trigger - tdata1 |= MCONTROL_DMODE(riscv_xlen(target)); - tdata1 = set_field(tdata1, MCONTROL_ACTION, - MCONTROL_ACTION_DEBUG_MODE); - tdata1 = set_field(tdata1, MCONTROL_MATCH, MCONTROL_MATCH_EQUAL); - tdata1 |= MCONTROL_M; - if (info->misa & (1 << ('H' - 'A'))) - tdata1 |= MCONTROL_H; - if (info->misa & (1 << ('S' - 'A'))) - tdata1 |= MCONTROL_S; - if (info->misa & (1 << ('U' - 'A'))) - tdata1 |= MCONTROL_U; - - if (trigger->execute) - tdata1 |= MCONTROL_EXECUTE; - if (trigger->read) - tdata1 |= MCONTROL_LOAD; - if (trigger->write) - tdata1 |= MCONTROL_STORE; - - write_csr(target, CSR_TDATA1, tdata1); - - uint64_t tdata1_rb; - read_csr(target, &tdata1_rb, CSR_TDATA1); - LOG_DEBUG("tdata1=0x%" PRIx64, tdata1_rb); - - if (tdata1 != tdata1_rb) { - LOG_DEBUG("Trigger %d doesn't support what we need; After writing 0x%" - PRIx64 " to tdata1 it contains 0x%" PRIx64, - i, tdata1, tdata1_rb); - write_csr(target, CSR_TDATA1, 0); - continue; - } - - write_csr(target, CSR_TDATA2, trigger->address); - LOG_DEBUG("Using resource %d for bp %d", i, trigger->unique_id); info->trigger_unique_id[i] = trigger->unique_id; @@ -1898,8 +1976,13 @@ static int examine(struct target *target) update_reg_list(target); if (read_csr(target, &info->misa, CSR_MISA) != ERROR_OK) { - LOG_ERROR("Failed to read misa."); - return ERROR_FAIL; + LOG_WARNING("Failed to read misa at 0x%x.", CSR_MISA); + if (read_csr(target, &info->misa, 0xf10) != ERROR_OK) { + // Maybe this is an old core that still has $misa at the old + // address. + LOG_ERROR("Failed to read misa at 0x%x.", 0xf10); + return ERROR_FAIL; + } } info->never_halted = true; @@ -2129,6 +2212,9 @@ static int handle_halt(struct target *target, bool announce) write_csr(target, CSR_TSELECT, info->trigger_count); uint64_t tselect_rb; read_csr(target, &tselect_rb, CSR_TSELECT); + // Mask off the top bit, which is used as tdrmode in old + // implementations. + tselect_rb &= ~(1ULL << (riscv_xlen(target)-1)); if (info->trigger_count != tselect_rb) break; uint64_t tdata1; diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 4b9e3e735..8672853e7 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -707,7 +707,7 @@ static int init_target(struct command_context *cmd_ctx, LOG_DEBUG("init"); riscv_info_t *generic_info = (riscv_info_t *) target->arch_info; - riscv_info_init(generic_info); + riscv_info_init(target, generic_info); generic_info->get_register = &riscv013_get_register; generic_info->set_register = &riscv013_set_register; generic_info->select_current_hart = &riscv013_select_current_hart; @@ -834,6 +834,9 @@ static int add_trigger(struct target *target, struct trigger *trigger) uint64_t tdata1_rb; for (int hartid = 0; hartid < riscv_count_harts(target); ++hartid) { + if (!riscv_hart_enabled(target, hartid)) + continue; + riscv_set_current_hartid(target, hartid); if (hartid > 0) { @@ -920,6 +923,9 @@ static int remove_trigger(struct target *target, struct trigger *trigger) } LOG_DEBUG("Stop using resource %d for bp %d", i, trigger->unique_id); for (int hartid = 0; hartid < riscv_count_harts(target); ++hartid) { + if (!riscv_hart_enabled(target, hartid)) + continue; + riscv_set_current_hartid(target, hartid); register_write_direct(target, GDB_REGNO_TSELECT, i); register_write_direct(target, GDB_REGNO_TDATA1, 0); @@ -1125,17 +1131,23 @@ static int examine(struct target *target) /* Before doing anything else we must first enumerate the harts. */ RISCV_INFO(r); - if (riscv_rtos_enabled(target)) { - for (int i = 0; i < RISCV_MAX_HARTS; ++i) { - riscv_set_current_hartid(target, i); - uint32_t s = dmi_read(target, DMI_DMSTATUS); - if (get_field(s, DMI_DMSTATUS_ANYNONEXISTENT)) - break; - r->hart_count = i + 1; + int original_coreid = target->coreid; + for (int i = 0; i < RISCV_MAX_HARTS; ++i) { + /* Fake being a non-RTOS targeted to this core so we can see if + * it exists. This avoids the assertion in + * riscv_set_current_hartid() that ensures non-RTOS targets + * don't touch the harts they're not assigned to. */ + target->coreid = i; + r->hart_count = i + 1; + riscv_set_current_hartid(target, i); + + uint32_t s = dmi_read(target, DMI_DMSTATUS); + if (get_field(s, DMI_DMSTATUS_ANYNONEXISTENT)) { + r->hart_count--; + break; } - } else { - r->hart_count = 1; } + target->coreid = original_coreid; LOG_DEBUG("Enumerated %d harts", r->hart_count); @@ -1145,6 +1157,9 @@ static int examine(struct target *target) /* Find the address of the program buffer, which must be done without * knowing anything about the target. */ for (int i = 0; i < riscv_count_harts(target); ++i) { + if (!riscv_hart_enabled(target, i)) + continue; + riscv_set_current_hartid(target, i); /* Without knowing anything else we can at least mess with the @@ -1177,6 +1192,16 @@ static int examine(struct target *target) * In order to make this work we first need to */ int offset = (progbuf_addr % 8 == 0) ? -4 : 0; + /* This program uses a temporary register. If the core can not + * execute 64 bit instruction, the original value of temporary + * register (s0) will not be restored due to an exception. + * So we have to save it and restore manually in that case. + * If the core can execute 64 bit instruction, the saved value + * is wrong, because it was read with 32 bit lw instruction, + * but the value of s0 will be restored by the reverse swap + * of s0 and dscratch registers. */ + uint64_t s0 = riscv_get_register(target, GDB_REGNO_S0); + struct riscv_program program64; riscv_program_init(&program64, target); riscv_program_csrrw(&program64, GDB_REGNO_S0, GDB_REGNO_S0, GDB_REGNO_DSCRATCH); @@ -1192,6 +1217,8 @@ static int examine(struct target *target) + dmi_read(target, DMI_PROGBUF0 + (4 + offset) / 4) - 4; r->xlen[i] = 64; + } else { + riscv_set_register(target, GDB_REGNO_S0, s0); } /* Display this as early as possible to help people who are using @@ -1215,6 +1242,9 @@ static int examine(struct target *target) /* Then we check the number of triggers availiable to each hart. */ for (int i = 0; i < riscv_count_harts(target); ++i) { + if (!riscv_hart_enabled(target, i)) + continue; + for (uint32_t t = 0; t < RISCV_MAX_TRIGGERS; ++t) { riscv_set_current_hartid(target, i); @@ -1229,6 +1259,7 @@ static int examine(struct target *target) /* Resumes all the harts, so the debugger can later pause them. */ riscv_resume_all_harts(target); + target->state = TARGET_RUNNING; target_set_examined(target); if (target->rtos) { @@ -1323,9 +1354,6 @@ static int read_memory(struct target *target, target_addr_t address, size, address); select_dmi(target); - /* There was a bug in the memory system and only accesses from hart 0 actually - * worked correctly. This should be obselete now. -palmer */ - riscv_set_current_hartid(target, 0); /* This program uses two temporary registers. A word of data and the * associated address are stored at some location in memory. The @@ -1521,9 +1549,6 @@ static int write_memory(struct target *target, target_addr_t address, LOG_DEBUG("writing %d words of %d bytes to 0x%08lx", count, size, (long)address); select_dmi(target); - /* There was a bug in the memory system and only accesses from hart 0 actually - * worked correctly. This should be obselete now. -palmer */ - riscv_set_current_hartid(target, 0); /* This program uses two temporary registers. A word of data and the * associated address are stored at some location in memory. The diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index e5f4fe3e0..3b914b9e2 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -448,11 +448,12 @@ static int riscv_get_gdb_reg_list(struct target *target, { RISCV_INFO(r); LOG_DEBUG("reg_class=%d", reg_class); - LOG_DEBUG("riscv_get_gdb_reg_list: rtos_hartid=%d current_hartid=%d", r->rtos_hartid, r->current_hartid); - if (r->rtos_hartid != -1) + LOG_DEBUG("rtos_hartid=%d current_hartid=%d", r->rtos_hartid, r->current_hartid); + + if (r->rtos_hartid != -1 && riscv_rtos_enabled(target)) riscv_set_current_hartid(target, r->rtos_hartid); else - riscv_set_current_hartid(target, 0); + riscv_set_current_hartid(target, target->coreid); switch (reg_class) { case REG_CLASS_GENERAL: @@ -877,11 +878,12 @@ struct target_type riscv_target = /*** RISC-V Interface ***/ -void riscv_info_init(riscv_info_t *r) +void riscv_info_init(struct target *target, riscv_info_t *r) { memset(r, 0, sizeof(*r)); r->dtm_version = 1; r->registers_initialized = false; + r->current_hartid = target->coreid; for (size_t h = 0; h < RISCV_MAX_HARTS; ++h) { r->xlen[h] = -1; @@ -894,11 +896,11 @@ void riscv_info_init(riscv_info_t *r) int riscv_halt_all_harts(struct target *target) { - if (riscv_rtos_enabled(target)) { - for (int i = 0; i < riscv_count_harts(target); ++i) - riscv_halt_one_hart(target, i); - } else { - riscv_halt_one_hart(target, riscv_current_hartid(target)); + for (int i = 0; i < riscv_count_harts(target); ++i) { + if (!riscv_hart_enabled(target, i)) + continue; + + riscv_halt_one_hart(target, i); } return ERROR_OK; @@ -920,11 +922,11 @@ int riscv_halt_one_hart(struct target *target, int hartid) int riscv_resume_all_harts(struct target *target) { - if (riscv_rtos_enabled(target)) { - for (int i = 0; i < riscv_count_harts(target); ++i) - riscv_resume_one_hart(target, i); - } else { - riscv_resume_one_hart(target, riscv_current_hartid(target)); + for (int i = 0; i < riscv_count_harts(target); ++i) { + if (!riscv_hart_enabled(target, i)) + continue; + + riscv_resume_one_hart(target, i); } riscv_invalidate_register_cache(target); @@ -948,11 +950,11 @@ int riscv_resume_one_hart(struct target *target, int hartid) int riscv_reset_all_harts(struct target *target) { - if (riscv_rtos_enabled(target)) { - for (int i = 0; i < riscv_count_harts(target); ++i) - riscv_reset_one_hart(target, i); - } else { - riscv_reset_one_hart(target, riscv_current_hartid(target)); + for (int i = 0; i < riscv_count_harts(target); ++i) { + if (!riscv_hart_enabled(target, i)) + continue; + + riscv_reset_one_hart(target, i); } riscv_invalidate_register_cache(target); @@ -1022,10 +1024,9 @@ void riscv_set_current_hartid(struct target *target, int hartid) int previous_hartid = riscv_current_hartid(target); r->current_hartid = hartid; - assert(riscv_rtos_enabled(target) || target->coreid == hartid); + assert(riscv_hart_enabled(target, hartid)); LOG_DEBUG("setting hartid to %d, was %d", hartid, previous_hartid); - if (riscv_rtos_enabled(target)) - r->select_current_hart(target); + r->select_current_hart(target); /* This might get called during init, in which case we shouldn't be * setting up the register cache. */ @@ -1073,10 +1074,7 @@ void riscv_invalidate_register_cache(struct target *target) int riscv_current_hartid(const struct target *target) { RISCV_INFO(r); - if (riscv_rtos_enabled(target)) - return r->current_hartid; - else - return target->coreid; + return r->current_hartid; } void riscv_set_all_rtos_harts(struct target *target) @@ -1242,6 +1240,15 @@ int riscv_dmi_write_u64_bits(struct target *target) return r->dmi_write_u64_bits(target); } +bool riscv_hart_enabled(struct target *target, int hartid) +{ + /* FIXME: Add a hart mask to the RTOS. */ + if (riscv_rtos_enabled(target)) + return hartid < riscv_count_harts(target); + + return hartid == target->coreid; +} + /* Command Handlers */ COMMAND_HANDLER(riscv_test_compliance) { diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 1c4b7ed92..745e4c9a2 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -135,7 +135,7 @@ int riscv_openocd_deassert_reset(struct target *target); /*** RISC-V Interface ***/ /* Initializes the shared RISC-V structure. */ -void riscv_info_init(riscv_info_t *r); +void riscv_info_init(struct target *target, riscv_info_t *r); /* Run control, possibly for multiple harts. The _all_harts versions resume * all the enabled harts, which when running in RTOS mode is all the harts on @@ -216,4 +216,7 @@ int riscv_dmi_write_u64_bits(struct target *target); /* Invalidates the register cache. */ void riscv_invalidate_register_cache(struct target *target); +/* Returns TRUE when a hart is enabled in this target. */ +bool riscv_hart_enabled(struct target *target, int hartid); + #endif