Updates to the initial scanchain validation code:
[openocd.git] / src / jtag / core.c
index bf4a9cc7f69a54c27a46d2d5d22e07c0977d8aea..b1d3ca0f1abb107b0aa1d4067ed7b83b79fe9151 100644 (file)
@@ -837,13 +837,21 @@ void jtag_sleep(uint32_t us)
        alive_sleep(us/1000);
 }
 
-/// maximum number of JTAG devices expected in the chain
+/* Maximum number of enabled JTAG devices we expect in the scan chain,
+ * plus one (to detect garbage at the end).  Devices that don't support
+ * IDCODE take up fewer bits, possibly allowing a few more devices.
+ */
 #define JTAG_MAX_CHAIN_SIZE 20
 
 #define EXTRACT_MFG(X)  (((X) & 0xffe) >> 1)
 #define EXTRACT_PART(X) (((X) & 0xffff000) >> 12)
 #define EXTRACT_VER(X)  (((X) & 0xf0000000) >> 28)
 
+/* A reserved manufacturer ID is used in END_OF_CHAIN_FLAG, so we
+ * know that no valid TAP will have it as an IDCODE value.
+ */
+#define END_OF_CHAIN_FLAG      0x000000ff
+
 static int jtag_examine_chain_execute(uint8_t *idcode_buffer, unsigned num_idcode)
 {
        scan_field_t field = {
@@ -855,7 +863,7 @@ static int jtag_examine_chain_execute(uint8_t *idcode_buffer, unsigned num_idcod
 
        // initialize to the end of chain ID value
        for (unsigned i = 0; i < JTAG_MAX_CHAIN_SIZE; i++)
-               buf_set_u32(idcode_buffer, i * 32, 32, 0x000000FF);
+               buf_set_u32(idcode_buffer, i * 32, 32, END_OF_CHAIN_FLAG);
 
        jtag_add_plain_dr_scan(1, &field, TAP_DRPAUSE);
        jtag_add_tlr();
@@ -899,7 +907,12 @@ static void jtag_examine_chain_display(enum log_levels level, const char *msg,
 
 static bool jtag_idcode_is_final(uint32_t idcode)
 {
-               return idcode == 0x000000FF || idcode == 0xFFFFFFFF;
+       /*
+        * Some devices, such as AVR8, will output all 1's instead
+        * of TDI input value at end of chain.  Allow those values
+        * instead of failing.
+        */
+       return idcode == END_OF_CHAIN_FLAG || idcode == 0xFFFFFFFF;
 }
 
 /**
@@ -907,8 +920,9 @@ static bool jtag_idcode_is_final(uint32_t idcode)
  * all as expected, but a single JTAG device requires only 64 bits to be
  * read back correctly.  This can help identify and diagnose problems
  * with the JTAG chain earlier, gives more helpful/explicit error messages.
+ * Returns TRUE iff garbage was found.
  */
-static void jtag_examine_chain_end(uint8_t *idcodes, unsigned count, unsigned max)
+static bool jtag_examine_chain_end(uint8_t *idcodes, unsigned count, unsigned max)
 {
        bool triggered = false;
        for (; count < max - 31; count += 32)
@@ -921,19 +935,14 @@ static void jtag_examine_chain_end(uint8_t *idcodes, unsigned count, unsigned ma
                                        count, (unsigned int)idcode);
                triggered = true;
        }
+       return triggered;
 }
 
 static bool jtag_examine_chain_match_tap(const struct jtag_tap_s *tap)
 {
-       if (0 == tap->expected_ids_cnt)
-       {
-               /// @todo Enable LOG_INFO to ask for reports about unknown TAP IDs.
-#if 0
-               LOG_INFO("Uknown JTAG TAP ID: 0x%08x", tap->idcode)
-               LOG_INFO("Please report the chip name and reported ID code to the openocd project");
-#endif
+       /* ignore expected BYPASS codes; warn otherwise */
+       if (0 == tap->expected_ids_cnt && !tap->idcode)
                return true;
-       }
 
        /* Loop over the expected identification codes and test for a match */
        uint8_t ii;
@@ -944,7 +953,7 @@ static bool jtag_examine_chain_match_tap(const struct jtag_tap_s *tap)
        }
 
        /* If none of the expected ids matched, log an error */
-       jtag_examine_chain_display(LOG_LVL_ERROR, "got",
+       jtag_examine_chain_display(LOG_LVL_ERROR, "UNEXPECTED",
                        tap->dotted_name, tap->idcode);
        for (ii = 0; ii < tap->expected_ids_cnt; ii++)
        {
@@ -958,14 +967,17 @@ static bool jtag_examine_chain_match_tap(const struct jtag_tap_s *tap)
 }
 
 /* Try to examine chain layout according to IEEE 1149.1 ยง12
+ * This is called a "blind interrogation" of the scan chain.
  */
 static int jtag_examine_chain(void)
 {
        uint8_t idcode_buffer[JTAG_MAX_CHAIN_SIZE * 4];
-       unsigned device_count = 0;
+       unsigned bit_count;
 
+       /* DR scan to collect BYPASS or IDCODE register contents.
+        * Then make sure the scan data has both ones and zeroes.
+        */
        jtag_examine_chain_execute(idcode_buffer, JTAG_MAX_CHAIN_SIZE);
-
        if (!jtag_examine_chain_check(idcode_buffer, JTAG_MAX_CHAIN_SIZE))
                return ERROR_JTAG_INIT_FAILED;
 
@@ -977,7 +989,7 @@ static int jtag_examine_chain(void)
                return ERROR_JTAG_INIT_FAILED;
        }
 
-       for (unsigned bit_count = 0;
+       for (bit_count = 0;
                        tap && bit_count < (JTAG_MAX_CHAIN_SIZE * 32) - 31;
                        tap = jtag_tap_next_enabled(tap))
        {
@@ -995,26 +1007,13 @@ static int jtag_examine_chain(void)
                }
                else
                {
+                       /* Friendly devices support IDCODE */
                        tap->hasidcode = true;
-
-                       /*
-                        * End of chain (invalid manufacturer ID) some devices, such
-                        * as AVR will output all 1's instead of TDI input value at
-                        * end of chain.
-                        */
-                       if (jtag_idcode_is_final(idcode))
-                       {
-                               jtag_examine_chain_end(idcode_buffer,
-                                               bit_count + 32, JTAG_MAX_CHAIN_SIZE * 32);
-                               break;
-                       }
-
                        jtag_examine_chain_display(LOG_LVL_INFO, "tap/device found",
                                        tap->dotted_name, idcode);
 
                        bit_count += 32;
                }
-               device_count++;
                tap->idcode = idcode;
 
                // ensure the TAP ID does matches what was expected
@@ -1022,21 +1021,32 @@ static int jtag_examine_chain(void)
                        return ERROR_JTAG_INIT_FAILED;
        }
 
-       /* see if number of discovered devices matches configuration */
-       if (device_count != jtag_tap_count_enabled())
-       {
-               LOG_ERROR("number of discovered devices in JTAG chain (%i) "
-                               "does not match (enabled) configuration (%i), total taps: %d",
-                               device_count, jtag_tap_count_enabled(), jtag_tap_count());
-               LOG_ERROR("check the config file and ensure proper JTAG communication"
-                               " (connections, speed, ...)");
+       /* Fail if too many TAPs were enabled for us to verify them all. */
+       if (tap) {
+               LOG_ERROR("Too many TAPs enabled; '%s' ignored.",
+                               tap->dotted_name);
+               return ERROR_JTAG_INIT_FAILED;
+       }
+
+       /* After those IDCODE or BYPASS register values should be
+        * only the data we fed into the scan chain.
+        */
+       if (jtag_examine_chain_end(idcode_buffer, bit_count,
+                       8 * sizeof(idcode_buffer))) {
+               LOG_ERROR("double-check your JTAG setup (interface, "
+                               "speed, TAPs, ...)");
                return ERROR_JTAG_INIT_FAILED;
        }
 
        return ERROR_OK;
 }
 
-int jtag_validate_chain(void)
+/*
+ * Validate the date loaded by entry to the Capture-IR state, to help
+ * find errors related to scan chain configuration (wrong IR lengths)
+ * or communication.
+ */
+static int jtag_validate_ircapture(void)
 {
        jtag_tap_t *tap;
        int total_ir_length = 0;
@@ -1055,7 +1065,11 @@ int jtag_validate_chain(void)
        }
 
        total_ir_length += 2;
+
        ir_test = malloc(CEIL(total_ir_length, 8));
+       if (ir_test == NULL)
+               return ERROR_FAIL;
+
        buf_set_ones(ir_test, total_ir_length);
 
        field.tap = NULL;
@@ -1081,24 +1095,37 @@ int jtag_validate_chain(void)
                        break;
                }
 
+               /* Validate the two LSBs, which must be 01 per JTAG spec.
+                * REVISIT we might be able to verify some MSBs too, using
+                * ircapture/irmask attributes.
+                */
                val = buf_get_u32(ir_test, chain_pos, 2);
-               /* Only fail this check if we have IDCODE for this device */
-               if ((val != 0x1)&&(tap->hasidcode))
-               {
+               if (val != 1) {
                        char *cbuf = buf_to_str(ir_test, total_ir_length, 16);
-                       LOG_ERROR("Could not validate JTAG scan chain, IR mismatch, scan returned 0x%s. tap=%s pos=%d expected 0x1 got %0x", cbuf, jtag_tap_name(tap), chain_pos, val);
-                       free(cbuf);
-                       free(ir_test);
-                       return ERROR_JTAG_INIT_FAILED;
+
+                       LOG_ERROR("%s: IR capture error; saw 0x%s not 0x..1",
+                                       jtag_tap_name(tap), cbuf);
+
+                       /* Fail only if we have IDCODE for this device.
+                        * REVISIT -- why not fail-always?
+                        */
+                       if (tap->hasidcode) {
+                               free(cbuf);
+                               free(ir_test);
+                               return ERROR_JTAG_INIT_FAILED;
+                       }
                }
                chain_pos += tap->ir_length;
        }
 
+       /* verify the '11' sentinel we wrote is returned at the end */
        val = buf_get_u32(ir_test, chain_pos, 2);
        if (val != 0x3)
        {
                char *cbuf = buf_to_str(ir_test, total_ir_length, 16);
-               LOG_ERROR("Could not validate end of JTAG scan chain, IR mismatch, scan returned 0x%s. pos=%d expected 0x3 got %0x", cbuf, chain_pos, val);
+
+               LOG_ERROR("IR capture error at bit %d, saw 0x%s not 0x...3",
+                               chain_pos, cbuf);
                free(cbuf);
                free(ir_test);
                return ERROR_JTAG_INIT_FAILED;
@@ -1114,6 +1141,7 @@ void jtag_tap_init(jtag_tap_t *tap)
 {
        assert(0 != tap->ir_length);
 
+       /// @todo fix, this allocates one byte per bit for all three fields!
        tap->expected = malloc(tap->ir_length);
        tap->expected_mask = malloc(tap->ir_length);
        tap->cur_instr = malloc(tap->ir_length);
@@ -1131,7 +1159,8 @@ void jtag_tap_init(jtag_tap_t *tap)
        LOG_DEBUG("Created Tap: %s @ abs position %d, "
                        "irlen %d, capture: 0x%x mask: 0x%x", tap->dotted_name,
                                tap->abs_chain_position, tap->ir_length,
-                         (unsigned int)(tap->ir_capture_value), (unsigned int)(tap->ir_capture_mask));
+                               (unsigned) tap->ir_capture_value,
+                               (unsigned) tap->ir_capture_mask);
        jtag_tap_add(tap);
 }
 
@@ -1140,6 +1169,7 @@ void jtag_tap_free(jtag_tap_t *tap)
        jtag_unregister_event_callback(&jtag_reset_callback, tap);
 
        /// @todo is anything missing? no memory leaks please
+       free((void *)tap->expected);
        free((void *)tap->expected_ids);
        free((void *)tap->chip);
        free((void *)tap->tapname);
@@ -1211,9 +1241,9 @@ static int jtag_init_inner(struct command_context_s *cmd_ctx)
                LOG_ERROR("trying to validate configured JTAG chain anyway...");
        }
 
-       if (jtag_validate_chain() != ERROR_OK)
+       if (jtag_validate_ircapture() != ERROR_OK)
        {
-               LOG_WARNING("Could not validate JTAG chain, continuing anyway...");
+               LOG_WARNING("Errors during IR capture, continuing anyway...");
        }
 
        return ERROR_OK;

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)