From 6a98fb7076f8b49561d4250d4c0ebce1e3473be5 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 26 Jan 2018 16:39:58 -0800 Subject: [PATCH] Detect hartsellen, limiting which harts we probe Tested with doctored spike with hartsellens of 0, 1, 3, and 10. Change-Id: I97f57c7d03b076792d5ecd66545d9b9e853ed515 --- src/target/riscv/debug_defines.h | 127 +++++++++++++++++-------------- src/target/riscv/riscv-013.c | 80 ++++++++++--------- 2 files changed, 116 insertions(+), 91 deletions(-) diff --git a/src/target/riscv/debug_defines.h b/src/target/riscv/debug_defines.h index e970293bf..04500e572 100644 --- a/src/target/riscv/debug_defines.h +++ b/src/target/riscv/debug_defines.h @@ -441,12 +441,6 @@ #define CSR_MCONTROL_M_LENGTH 1 #define CSR_MCONTROL_M (0x1ULL << CSR_MCONTROL_M_OFFSET) /* -* When set, enable this trigger in H mode. - */ -#define CSR_MCONTROL_H_OFFSET 5 -#define CSR_MCONTROL_H_LENGTH 1 -#define CSR_MCONTROL_H (0x1ULL << CSR_MCONTROL_H_OFFSET) -/* * When set, enable this trigger in S mode. */ #define CSR_MCONTROL_S_OFFSET 4 @@ -487,7 +481,7 @@ /* * When count is decremented to 0, the trigger fires. Instead of * changing \Fcount from 1 to 0, it is also acceptable for hardware to -* clear \Fm, \Fh, \Fs, and \Fu. This allows \Fcount to be hard-wired +* clear \Fm, \Fs, and \Fu. This allows \Fcount to be hard-wired * to 1 if this register just exists for single step. */ #define CSR_ICOUNT_COUNT_OFFSET 10 @@ -501,13 +495,6 @@ #define CSR_ICOUNT_M_LENGTH 1 #define CSR_ICOUNT_M (0x1ULL << CSR_ICOUNT_M_OFFSET) /* -* When set, every instruction completed or exception taken in in H mode decrements \Fcount -* by 1. - */ -#define CSR_ICOUNT_H_OFFSET 8 -#define CSR_ICOUNT_H_LENGTH 1 -#define CSR_ICOUNT_H (0x1ULL << CSR_ICOUNT_H_OFFSET) -/* * When set, every instruction completed or exception taken in S mode decrements \Fcount * by 1. */ @@ -544,19 +531,6 @@ #define CSR_ICOUNT_ACTION (0x3fULL << CSR_ICOUNT_ACTION_OFFSET) #define DMI_DMSTATUS 0x11 /* -* Gets set if the Debug Module was accessed incorrectly. -* -* 0 (none): No error. -* -* 1 (badaddr): There was an access to an unimplemented Debug Module -* address. -* -* 7 (other): An access failed for another reason. - */ -#define DMI_DMSTATUS_DMERR_OFFSET 24 -#define DMI_DMSTATUS_DMERR_LENGTH 3 -#define DMI_DMSTATUS_DMERR (0x7U << DMI_DMSTATUS_DMERR_OFFSET) -/* * If 1, then there is an implicit {\tt ebreak} instruction at the * non-existent word immediately after the Program Buffer. This saves * the debugger from having to write the {\tt ebreak} itself, and @@ -700,7 +674,7 @@ */ #define DMI_DMCONTROL_HALTREQ_OFFSET 31 #define DMI_DMCONTROL_HALTREQ_LENGTH 1 -#define DMI_DMCONTROL_HALTREQ (0x1U << DMI_DMCONTROL_HALTREQ_OFFSET) +#define DMI_DMCONTROL_HALTREQ (0x1ULL << DMI_DMCONTROL_HALTREQ_OFFSET) /* * Writes the resume request bit for all currently selected harts. * When set to 1, each selected hart will resume if it is currently @@ -713,7 +687,7 @@ */ #define DMI_DMCONTROL_RESUMEREQ_OFFSET 30 #define DMI_DMCONTROL_RESUMEREQ_LENGTH 1 -#define DMI_DMCONTROL_RESUMEREQ (0x1U << DMI_DMCONTROL_RESUMEREQ_OFFSET) +#define DMI_DMCONTROL_RESUMEREQ (0x1ULL << DMI_DMCONTROL_RESUMEREQ_OFFSET) /* * This optional field writes the reset bit for all the currently * selected harts. To perform a reset the debugger writes 1, and then @@ -727,7 +701,7 @@ */ #define DMI_DMCONTROL_HARTRESET_OFFSET 29 #define DMI_DMCONTROL_HARTRESET_LENGTH 1 -#define DMI_DMCONTROL_HARTRESET (0x1U << DMI_DMCONTROL_HARTRESET_OFFSET) +#define DMI_DMCONTROL_HARTRESET (0x1ULL << DMI_DMCONTROL_HARTRESET_OFFSET) /* * Writing 1 to this bit clears the {\tt havereset} bits for * any selected harts. @@ -736,7 +710,7 @@ */ #define DMI_DMCONTROL_ACKHAVERESET_OFFSET 28 #define DMI_DMCONTROL_ACKHAVERESET_LENGTH 1 -#define DMI_DMCONTROL_ACKHAVERESET (0x1U << DMI_DMCONTROL_ACKHAVERESET_OFFSET) +#define DMI_DMCONTROL_ACKHAVERESET (0x1ULL << DMI_DMCONTROL_ACKHAVERESET_OFFSET) /* * Selects the definition of currently selected harts. * @@ -752,14 +726,14 @@ */ #define DMI_DMCONTROL_HASEL_OFFSET 26 #define DMI_DMCONTROL_HASEL_LENGTH 1 -#define DMI_DMCONTROL_HASEL (0x1U << DMI_DMCONTROL_HASEL_OFFSET) +#define DMI_DMCONTROL_HASEL (0x1ULL << DMI_DMCONTROL_HASEL_OFFSET) /* * The DM-specific index of the hart to select. This hart is always part of the * currently selected harts. */ #define DMI_DMCONTROL_HARTSEL_OFFSET 16 -#define DMI_DMCONTROL_HARTSEL_LENGTH 10 -#define DMI_DMCONTROL_HARTSEL (0x3ffU << DMI_DMCONTROL_HARTSEL_OFFSET) +#define DMI_DMCONTROL_HARTSEL_LENGTH HARTSELLEN +#define DMI_DMCONTROL_HARTSEL (((1L<arch_info; + return (riscv013_info_t *) info->version_specific; +} + +static uint32_t hartsel_mask(const struct target *target) +{ + RISCV013_INFO(info); + return ((1L<hartsellen)-1) << DMI_DMCONTROL_HARTSEL_OFFSET; +} + static void decode_dmi(char *text, unsigned address, unsigned data) { static const struct { @@ -192,7 +207,7 @@ static void decode_dmi(char *text, unsigned address, unsigned data) { DMI_DMCONTROL, DMI_DMCONTROL_RESUMEREQ, "resumereq" }, { DMI_DMCONTROL, DMI_DMCONTROL_HARTRESET, "hartreset" }, { DMI_DMCONTROL, DMI_DMCONTROL_HASEL, "hasel" }, - { DMI_DMCONTROL, DMI_DMCONTROL_HARTSEL, "hartsel" }, + { DMI_DMCONTROL, ((1L<<10)-1) << DMI_DMCONTROL_HARTSEL_OFFSET, "hartsel" }, { DMI_DMCONTROL, DMI_DMCONTROL_NDMRESET, "ndmreset" }, { DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE, "dmactive" }, @@ -275,12 +290,6 @@ static void dump_field(const struct scan_field *field) } } -static riscv013_info_t *get_info(const struct target *target) -{ - riscv_info_t *info = (riscv_info_t *) target->arch_info; - return (riscv013_info_t *) info->version_specific; -} - /*** Utility functions. ***/ static void select_dmi(struct target *target) @@ -1155,54 +1164,50 @@ static int examine(struct target *target) } /* Reset the Debug Module. */ - dmi_write(target, DMI_DMCONTROL, 0); - dmi_write(target, DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE); + uint32_t max_hartsel_mask = ((1L<<10)-1) << DMI_DMCONTROL_HARTSEL_OFFSET; + dmi_write(target, DMI_DMCONTROL, max_hartsel_mask); + dmi_write(target, DMI_DMCONTROL, max_hartsel_mask | DMI_DMCONTROL_DMACTIVE); uint32_t dmcontrol = dmi_read(target, DMI_DMCONTROL); - uint32_t hartinfo = dmi_read(target, DMI_HARTINFO); - - LOG_DEBUG("dmcontrol: 0x%08x", dmcontrol); - LOG_DEBUG("dmstatus: 0x%08x", dmstatus); - LOG_DEBUG("hartinfo: 0x%08x", hartinfo); - - info->datasize = get_field(hartinfo, DMI_HARTINFO_DATASIZE); - info->dataaccess = get_field(hartinfo, DMI_HARTINFO_DATAACCESS); - info->dataaddr = get_field(hartinfo, DMI_HARTINFO_DATAADDR); - if (!get_field(dmcontrol, DMI_DMCONTROL_DMACTIVE)) { LOG_ERROR("Debug Module did not become active. dmcontrol=0x%x", dmcontrol); return ERROR_FAIL; } + uint32_t hartsel = get_field(dmcontrol, max_hartsel_mask); + info->hartsellen = 0; + while (hartsel & 1) { + info->hartsellen++; + hartsel >>= 1; + } + LOG_DEBUG("hartsellen=%d", info->hartsellen); + + uint32_t hartinfo = dmi_read(target, DMI_HARTINFO); + + info->datasize = get_field(hartinfo, DMI_HARTINFO_DATASIZE); + info->dataaccess = get_field(hartinfo, DMI_HARTINFO_DATAACCESS); + info->dataaddr = get_field(hartinfo, DMI_HARTINFO_DATAADDR); + if (!get_field(dmstatus, DMI_DMSTATUS_AUTHENTICATED)) { LOG_ERROR("Authentication required by RISC-V core but not " "supported by OpenOCD. dmcontrol=0x%x", dmcontrol); return ERROR_FAIL; } - if (get_field(dmstatus, DMI_DMSTATUS_ANYUNAVAIL)) { - LOG_ERROR("The hart is unavailable."); - return ERROR_FAIL; - } - - if (get_field(dmstatus, DMI_DMSTATUS_ANYNONEXISTENT)) { - LOG_ERROR("The hart doesn't exist."); - return ERROR_FAIL; - } - /* Check that abstract data registers are accessible. */ uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS); info->datacount = get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); info->progbufsize = get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE); - /* Before doing anything else we must first enumerate the harts. */ RISCV_INFO(r); r->impebreak = get_field(dmstatus, DMI_DMSTATUS_IMPEBREAK); + /* Before doing anything else we must first enumerate the harts. */ + /* Don't call any riscv_* functions until after we've counted the number of * cores and initialized registers. */ - for (int i = 0; i < RISCV_MAX_HARTS; ++i) { + for (int i = 0; i < MIN(RISCV_MAX_HARTS, 1 << info->hartsellen); ++i) { if (!riscv_rtos_enabled(target) && i != target->coreid) continue; @@ -1248,6 +1253,11 @@ static int examine(struct target *target) LOG_DEBUG("Enumerated %d harts", r->hart_count); + if (r->hart_count == 0) { + LOG_ERROR("No harts found!"); + return ERROR_FAIL; + } + /* Then we check the number of triggers availiable to each hart. */ riscv_enumerate_triggers(target); @@ -1297,7 +1307,7 @@ static int assert_reset(struct target *target) if (!riscv_hart_enabled(target, i)) continue; - control = set_field(control_base, DMI_DMCONTROL_HARTSEL, i); + control = set_field(control_base, hartsel_mask(target), i); control = set_field(control, DMI_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0); dmi_write(target, DMI_DMCONTROL, control); @@ -1308,7 +1318,7 @@ static int assert_reset(struct target *target) } else { /* Reset just this hart. */ - uint32_t control = set_field(control_base, DMI_DMCONTROL_HARTSEL, + uint32_t control = set_field(control_base, hartsel_mask(target), r->current_hartid); control = set_field(control, DMI_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0); @@ -1342,7 +1352,7 @@ static int deassert_reset(struct target *target) /* Clear the reset, but make sure haltreq is still set */ uint32_t control = 0; control = set_field(control, DMI_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0); - control = set_field(control, DMI_DMCONTROL_HARTSEL, r->current_hartid); + control = set_field(control, hartsel_mask(target), r->current_hartid); control = set_field(control, DMI_DMCONTROL_DMACTIVE, 1); dmi_write(target, DMI_DMCONTROL, control); @@ -1948,7 +1958,7 @@ static void riscv013_select_current_hart(struct target *target) RISCV_INFO(r); uint64_t dmcontrol = dmi_read(target, DMI_DMCONTROL); - dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_HARTSEL, r->current_hartid); + dmcontrol = set_field(dmcontrol, hartsel_mask(target), r->current_hartid); dmi_write(target, DMI_DMCONTROL, dmcontrol); }