Skip to content

Inconsistent jtagtap_cycle() implementations #2180

@ALTracer

Description

@ALTracer

A method to generate N cycles of TCK with fixed values of TMS and TDI, jtagtap_cycles(), was added somewhat later than the other base methods to jtag_proc structure of function pointers. I have identified four places where this is used.

  1. jtagtap_init() and equivalents, for emitting SWD LINERESET (50 cycles with TMS high), sometimes coded as a literal for-loop around jtagtap_next() or a prepared byte buffer.
    /* Ensure we're in JTAG mode. Start by issuing a complete SWD reset of at least 50 reset cycles */
    jtagtap_cycle(true, false, 51U);
    /* Having achieved reset, try the deprecated 16-bit SWD-to-JTAG sequence */
    jtagtap_tms_seq(ADIV5_SWD_TO_JTAG_SELECT_SEQUENCE, 16U);
    /* Next, to complete that sequence, do a full 50+ cycle reset again */
    jtagtap_cycle(true, false, 51U);
  2. jtag_scan.c:jtag_sanity_check(), called as early as jtag_scan() => jtag_discover() => jtag_sanity_check(). I have touched this recently in Fix JTAG sanity check in BYPASS device counting #2178.
    /* Preload entire DR chain of BYPASS with known 0 value */
    jtag_proc.jtagtap_cycle(false, false, jtag_dev_count);
  3. adiv5_jtag.c:adiv5_jtag_raw_access(), for 8 idle cycles but only for ADI v6 JTAG-DP targets. Never encountered with ADI v5.
    /* ADIv6 needs 8 idle cycles run after we get done to ensure the state machine is idle */
    if (dp->version > 2)
    jtag_proc.jtagtap_cycle(false, false, 8);
    return result;
    }
  4. icepick.c:icepick_router_handler(), for 10 idle cycles after reconfiguring type-D controller. Very target-specific.
    /* Go to an idle state instruction and then run 10 idle cycles to complete reconfiguration */
    icepick_write_ir(device, IR_IDCODE);
    jtag_proc.jtagtap_cycle(false, false, 10U);
    /* Now re-scan the bus to pick up all the new TAPs */
    jtag_discover();
    }

None of these places are particularly hot code (intensively called during debug). The problem is that BMDA backends for FTDI MPSSE, J-Link, CMSIS-DAP never set the pointer, so it stays NULL (in a calloc()'ed struct), allowing one to inadvertently segfault BMDA mid-scan.

The obvious solutions are a) null-check the pointer at all callsites and fall back to jtagtap_next(); b) code the wrappers which invoke corresponding methods bound to jtagtap_next(). Which can then evolve into proper functions optimized for bit-packing and buffering characteristic for the protocols of these low-level adapters.

I've started at it in #2179 just to fix it until other usable or optimized implementations arrive. The CMSIS-DAP protocol is too convoluted for me to do it properly. J-Link HW_JTAG3 and FTDI MPSSE are easier.

Metadata

Metadata

Assignees

No one assigned

    Labels

    BMD AppBlack Magic Debug App (aka. PC hosted) (not firmware)BugConfirmed bug

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions