diff --git a/src/platforms/hosted/bmp_libusb.c b/src/platforms/hosted/bmp_libusb.c index c0d060cbb13..577ef834cbf 100644 --- a/src/platforms/hosted/bmp_libusb.c +++ b/src/platforms/hosted/bmp_libusb.c @@ -2,7 +2,7 @@ * This file is part of the Black Magic Debug project. * * Copyright (C) 2020 - 2022 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de) - * Copyright (C) 2022-2023 1BitSquared + * Copyright (C) 2022-2025 1BitSquared * Written by Sid Price * Written by Rachel Mant * @@ -285,7 +285,10 @@ static probe_info_s *process_ftdi_probe(void) if (probe_skip) { // Clean up any previous serial number to skip use_serial = true; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-qual" free((void *)probe_skip); +#pragma GCC diagnostic pop probe_skip = NULL; } @@ -323,7 +326,10 @@ static probe_info_s *process_ftdi_probe(void) } } if (probe_skip) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-qual" free((void *)probe_skip); +#pragma GCC diagnostic pop free(dev_info); return probe_list; } diff --git a/src/platforms/hosted/cmsis_dap.c b/src/platforms/hosted/cmsis_dap.c index c5556bca351..6d8fac0f5a5 100644 --- a/src/platforms/hosted/cmsis_dap.c +++ b/src/platforms/hosted/cmsis_dap.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2013-2019, Alex Taradov - * Copyright (C) 2023-2024 1BitSquared + * Copyright (C) 2023-2025 1BitSquared * Modified by Rachel Mant * All rights reserved. * @@ -107,7 +107,6 @@ static uint8_t buffer[1025U]; * https://arm-software.github.io/CMSIS-DAP/latest/group__DAP__Config__Debug__gr.html#gaa28bb1da2661291634c4a8fb3e227404 */ static size_t dap_packet_size = 64U; -bool dap_has_swd_sequence = false; dap_version_s dap_adaptor_version(dap_info_e version_kind); @@ -201,7 +200,7 @@ static void dap_hid_print_permissions(const uint16_t vid, const uint16_t pid, co static bool dap_init_hid(void) { /* Initialise HIDAPI */ - DEBUG_INFO("Using hid transfer\n"); + DEBUG_INFO("Using HID transfer\n"); if (hid_init()) return false; @@ -222,9 +221,9 @@ static bool dap_init_hid(void) /* * Base the report length information for the device on the max packet length from its descriptors. - * Add 1 to account for HIDAPI's need to prefix with a report type byte. Limit to at most 512 bytes. + * Add 1 to account for HIDAPI's need to prefix with a report type byte. Limit to at most 513 bytes. */ - dap_packet_size = MIN(bmda_probe_info.max_packet_length + 1U, 512U); + dap_packet_size = MIN(bmda_probe_info.max_packet_length + 1U, 513U); /* Handle the NXP LPC11U3x CMSIS-DAP v1.0.7 implementation needing a 64 byte report length */ if (bmda_probe_info.vid == 0x1fc9U && bmda_probe_info.pid == 0x0132U) @@ -284,10 +283,8 @@ bool dap_init(bool allow_fallback) } } - if (type == CMSIS_TYPE_HID) { - if (!dap_init_hid()) - return false; - } + if (type == CMSIS_TYPE_HID && !dap_init_hid()) + return false; /* Ensure the adaptor is idle and not prepared for any protocol in particular */ dap_disconnect(); @@ -301,8 +298,6 @@ bool dap_init(bool allow_fallback) if ((cmsis_version.major == 1 && cmsis_version.minor >= 3) || (cmsis_version.major == 2 && cmsis_version.minor >= 1) || cmsis_version.major > 2) adaptor_version = dap_adaptor_version(DAP_INFO_ADAPTOR_VERSION); - /* Look for CMSIS-DAP v1.2+ */ - dap_has_swd_sequence = dap_version_compare_ge(cmsis_version, (dap_version_s){1, 2, 0}); /* Try to get the actual packet size information from the adaptor */ uint16_t dap_packet_size; @@ -323,12 +318,12 @@ bool dap_init(bool allow_fallback) } /* Having got the capabilities, decode and print an informitive string about them */ - const bool supportsJTAG = dap_caps & DAP_CAP_JTAG; - const bool supportsSWD = dap_caps & DAP_CAP_SWD; + const bool supports_jtag = dap_caps & DAP_CAP_JTAG; + const bool supports_swd = dap_caps & DAP_CAP_SWD; DEBUG_INFO("Capabilities: %02x (", dap_caps); - if (supportsJTAG) - DEBUG_INFO("JTAG%s", supportsSWD ? "/" : ""); - if (supportsSWD) + if (supports_jtag) + DEBUG_INFO("JTAG%s", supports_swd ? "/" : ""); + if (supports_swd) DEBUG_INFO("SWD"); if (dap_caps & DAP_CAP_SWO_ASYNC) DEBUG_INFO(", Async SWO"); @@ -338,8 +333,6 @@ bool dap_init(bool allow_fallback) DEBUG_INFO(", Atomic commands"); DEBUG_INFO(")\n"); - DEBUG_INFO("Adaptor %s DAP SWD sequences\n", dap_has_swd_sequence ? "supports" : "does not support"); - dap_quirks = 0; /* Handle multi-TAP JTAG on older (pre-v1.3) ORBTrace gateware being broken */ if (strcmp(bmda_probe_info.product, "Orbtrace") == 0 && @@ -355,6 +348,12 @@ bool dap_init(bool allow_fallback) if (strcmp(bmda_probe_info.product, "Orbtrace") == 0) dap_quirks |= DAP_QUIRK_NEEDS_EXTRA_ZLP_READ; + /* Pre-CMSIS-DAP v1.2.0 adaptors do not have DAP_SWD_Sequence and must use alternate means to do the same thing */ + if (!dap_version_compare_ge(cmsis_version, (dap_version_s){1, 2, 0})) { + DEBUG_INFO("Adaptor does not support DAP_SWD_Sequence, using fallbacks\n"); + dap_quirks |= DAP_QUIRK_NO_SWD_SEQUENCE; + } + return true; } @@ -431,9 +430,8 @@ void dap_dp_abort(adiv5_debug_port_s *const target_dp, const uint32_t abort) uint32_t dap_dp_raw_access( adiv5_debug_port_s *const target_dp, const uint8_t rnw, const uint16_t addr, const uint32_t value) { - const bool APnDP = addr & ADIV5_APnDP; uint32_t res = 0; - const uint8_t reg = (addr & 0xcU) | (APnDP ? 1U : 0U); + const uint8_t reg = (addr & 0xcU) | (addr & ADIV5_APnDP ? 1U : 0U); if (rnw) res = dap_read_reg(target_dp, reg); else @@ -468,37 +466,81 @@ void dap_exit_function(void) } } -ssize_t dbg_dap_cmd_hid(const uint8_t *const request_data, const size_t request_length, uint8_t *const response_data, +ssize_t dbg_dap_cmd_hid_io(const uint8_t *const request_data, const size_t request_length, uint8_t *const response_data, const size_t response_length) { - // Need room to prepend HID Report ID byte - if (request_length + 1U > dap_packet_size) { - DEBUG_ERROR("Attempted to make over-long request of %zu bytes, max length is %zu\n", request_length + 1U, - dap_packet_size); - exit(-1); - } - + /* Make the unused part of the request buffer all 0xff */ memset(buffer + request_length + 1U, 0xff, dap_packet_size - (request_length + 1U)); - buffer[0] = 0x00; // Report ID - memcpy(buffer + 1, request_data, request_length); + /* Then copy in the report ID and request data */ + buffer[0] = 0x00U; + memcpy(buffer + 1U, request_data, request_length); + /* Send the request to the adaptor, checking for errors */ const int result = hid_write(handle, buffer, dap_packet_size); if (result < 0) { DEBUG_ERROR("CMSIS-DAP write error: %ls\n", hid_error(handle)); + return result; + } + + /* Now try and read back the response */ + const int response = hid_read_timeout(handle, buffer, dap_packet_size - 1U, 1000); + /* hid_read_timeout returns -1, 0, or the number of bytes read */ + if (response < 0) { + DEBUG_ERROR("CMSIS-DAP read error: %ls\n", hid_error(handle)); + /* As the read failed, return -1 here */ + return result; + } + if (response == 0) { + DEBUG_ERROR("CMSIS-DAP read timeout\n"); + /* Signal timeout with 0 */ + return response; + } + /* If we got a good response, copy the data for it to the response buffer */ + const size_t bytes_transferred = MIN((size_t)response, response_length); + memcpy(response_data, buffer, bytes_transferred); + return (int)bytes_transferred; +} + +ssize_t dbg_dap_cmd_hid(const uint8_t *const request_data, const size_t request_length, uint8_t *const response_data, + const size_t response_length) +{ + /* Need room to prepend HID Report ID byte */ + if (request_length + 1U > dap_packet_size) { + DEBUG_ERROR("Attempted to make over-long request of %zu bytes, max length is %zu\n", request_length + 1U, + dap_packet_size); exit(-1); } - int response = 0; - do { - response = hid_read_timeout(handle, response_data, response_length, 1000); - if (response < 0) { - DEBUG_ERROR("CMSIS-DAP read error: %ls\n", hid_error(handle)); - exit(-1); - } else if (response == 0) { - DEBUG_ERROR("CMSIS-DAP read timeout\n"); - exit(-1); + /* Ensure that the response data type byte is something valid */ + response_data[0] = ~request_data[0]; + + size_t tries = 0U; + ssize_t response = 0; + /* Try up to 3 times to make the request and get the response */ + while (response == 0 && tries < 3U) { + response = dbg_dap_cmd_hid_io(request_data, request_length, response_data, response_length); + ++tries; + /* If this try succeeded, make sure the data read back was sane */ + while (response_data[0] != request_data[0]) { + /* it was not, so try the read back again */ + response = hid_read_timeout(handle, buffer, dap_packet_size, 1000); + /* hid_read_timeout returns -1, 0, or the number of bytes read */ + if (response < 0) { + DEBUG_ERROR("CMSIS-DAP read error: %ls\n", hid_error(handle)); + /* As the read failed, return -1 here */ + return response; + } + if (response == 0) { + DEBUG_ERROR("CMSIS-DAP read timeout\n"); + /* Signal timeout with -2 */ + return -2; + } + /* If we got a good response, copy the data for it to the response buffer */ + memcpy(response_data, buffer, response_length); } - } while (response_data[0] != request_data[0]); + } + if (response > 0) + return MIN((size_t)response, response_length); return response; } @@ -527,7 +569,7 @@ ssize_t dbg_dap_cmd_bulk(const uint8_t *const request_data, const size_t request } while (response_data[0] != request_data[0]); /* If the response requested is the size of the packet size for the adaptor, generate a ZLP read to clean state */ - if ((dap_quirks & DAP_QUIRK_NEEDS_EXTRA_ZLP_READ) && transferred == (int)dap_packet_size) { + if ((dap_quirks & DAP_QUIRK_NEEDS_EXTRA_ZLP_READ) && (size_t)transferred == dap_packet_size) { uint8_t zlp; int zlp_read = 0; libusb_bulk_transfer(usb_handle, in_ep, &zlp, sizeof(zlp), &zlp_read, TRANSFER_TIMEOUT_MS); @@ -554,7 +596,7 @@ static ssize_t dap_run_cmd_raw(const uint8_t *const request_data, const size_t r ssize_t response = -1; if (type == CMSIS_TYPE_HID) - response = dbg_dap_cmd_hid(request_data, request_length, data, dap_packet_size); + response = dbg_dap_cmd_hid(request_data, request_length, data, MIN(response_length + 1U, dap_packet_size)); else if (type == CMSIS_TYPE_BULK) response = dbg_dap_cmd_bulk(request_data, request_length, data, dap_packet_size); if (response < 0) @@ -567,7 +609,7 @@ static ssize_t dap_run_cmd_raw(const uint8_t *const request_data, const size_t r DEBUG_WIRE("\n"); if (response_length) - memcpy(response_data, data + 1, MIN(response_length, result)); + memcpy(response_data, data + 1, MIN(response_length, result - 1U)); return response; } diff --git a/src/platforms/hosted/dap.c b/src/platforms/hosted/dap.c index 815721cde51..bcb92692ebd 100644 --- a/src/platforms/hosted/dap.c +++ b/src/platforms/hosted/dap.c @@ -1,7 +1,7 @@ /* * Copyright (C) 2013-2015 Alex Taradov * Copyright (C) 2020-2021 Uwe Bonnes - * Copyright (C) 2023-2024 1BitSquared + * Copyright (C) 2023-2025 1BitSquared * Modified by Rachel Mant * All rights reserved. * @@ -38,11 +38,6 @@ #include "jtag_scan.h" #include "buffer_utils.h" -#define DAP_TRANSFER_APnDP (1U << 0U) -#define DAP_TRANSFER_RnW (1U << 1U) - -#define DAP_TRANSFER_WAIT (1U << 1U) - #define SWD_DP_R_IDCODE 0x00U #define SWD_DP_W_ABORT 0x00U #define SWD_DP_R_CTRL_STAT 0x04U @@ -263,7 +258,7 @@ void dap_write_reg(adiv5_debug_port_s *target_dp, const uint8_t reg, const uint3 }; do { - if (perform_dap_transfer(target_dp, &request, 1U, NULL, 0)) + if (perform_dap_transfer(target_dp, &request, 1U, NULL, 0U)) return; } while (target_dp->fault == DAP_TRANSFER_WAIT); } diff --git a/src/platforms/hosted/dap.h b/src/platforms/hosted/dap.h index e698ca6de0d..df6a7d6af05 100644 --- a/src/platforms/hosted/dap.h +++ b/src/platforms/hosted/dap.h @@ -2,7 +2,7 @@ * This file is part of the Black Magic Debug project. * * Copyright (c) 2013-2015, Alex Taradov - * Copyright (C) 2023-2024 1BitSquared + * Copyright (C) 2023-2025 1BitSquared * Modified by Rachel Mant * All rights reserved. * @@ -73,11 +73,11 @@ typedef enum dap_led_type { #define DAP_QUIRK_BAD_SWD_NO_RESP_DATA_PHASE (1U << 1U) #define DAP_QUIRK_BROKEN_SWD_SEQUENCE (1U << 2U) #define DAP_QUIRK_NEEDS_EXTRA_ZLP_READ (1U << 3U) +#define DAP_QUIRK_NO_SWD_SEQUENCE (1U << 4U) extern uint8_t dap_caps; extern dap_cap_e dap_mode; extern uint8_t dap_quirks; -extern bool dap_has_swd_sequence; bool dap_connect(void); bool dap_disconnect(void); diff --git a/src/platforms/hosted/dap_command.c b/src/platforms/hosted/dap_command.c index 30c363e9e80..9b51b96736d 100644 --- a/src/platforms/hosted/dap_command.c +++ b/src/platforms/hosted/dap_command.c @@ -1,7 +1,7 @@ /* * This file is part of the Black Magic Debug project. * - * Copyright (C) 2022-2024 1BitSquared + * Copyright (C) 2022-2025 1BitSquared * Written by Rachel Mant * All rights reserved. * @@ -130,6 +130,39 @@ bool perform_dap_transfer(adiv5_debug_port_s *const target_dp, const dap_transfe return false; } +bool perform_dap_transfer_swd_unchecked(const dap_transfer_request_s *const transfer_requests, const size_t requests, + uint32_t *const response_data, const size_t responses) +{ + /* Validate that the number of requests this transfer is valid. We artificially limit it to 12 (from 256) */ + if (!requests || requests > 12 || (responses && !response_data)) + return false; + + DEBUG_PROBE("-> dap_transfer (%zu requests)\n", requests); + /* 63 is 3 + (12 * 5) where 5 is the max length of each transfer request */ + uint8_t request[63] = { + DAP_TRANSFER, + 0U, + requests, + }; + /* Encode the transfers into the buffer and detect if we're doing any reads */ + size_t offset = 3U; + for (size_t i = 0; i < requests; ++i) + offset += dap_encode_transfer(&transfer_requests[i], request, offset); + + dap_transfer_response_s response = {.processed = 0, .status = DAP_TRANSFER_OK}; + /* Run the request */ + if (!dap_run_cmd(request, offset, &response, 2U + (responses * 4U))) + return false; + + /* Look at the response and decipher what went on */ + if (response.processed == requests && (response.status & DAP_TRANSFER_STATUS_MASK) == DAP_TRANSFER_OK) { + for (size_t i = 0; i < responses; ++i) + response_data[i] = read_le4(response.data[i], 0); + return true; + } + return false; +} + bool perform_dap_transfer_recoverable(adiv5_debug_port_s *const target_dp, const dap_transfer_request_s *const transfer_requests, const size_t requests, uint32_t *const response_data, const size_t responses) @@ -321,7 +354,7 @@ bool perform_dap_jtag_sequence( memcpy(data_out, response + 1U, sequence_length); /* And the final bit from the second response LSb */ if (sequences == 2U) - data_out[final_byte] = (response[1 + sequence_length] & 1U) << final_bit; + data_out[final_byte] |= (response[1 + sequence_length] & 1U) << final_bit; } /* And check that it succeeded */ return response[0] == DAP_RESPONSE_OK; @@ -362,6 +395,24 @@ bool perform_dap_jtag_tms_sequence(const uint64_t tms_states, const size_t clock return response == DAP_RESPONSE_OK; } +static bool dap_swd_sequence_as_swj_sequences(dap_swd_sequence_s *const sequences, const uint8_t sequence_count) +{ + /* Loop through each of the sequences being requested */ + for (uint8_t index = 0U; index < sequence_count; ++index) { + const dap_swd_sequence_s *const sequence = &sequences[index]; + /* If it's an output sequence, perform it */ + if (sequence->direction == DAP_SWD_OUT_SEQUENCE) { + /* And check if doing so as a SWJ sequence suceeded or not */ + if (!perform_dap_swj_sequence(sequence->cycles, sequence->data)) + return false; + } + /* Otherwise, if it's an input sequence - headache.. */ + else + return false; + } + return true; +} + static size_t dap_encode_swd_sequence( const dap_swd_sequence_s *const sequence, uint8_t *const buffer, const size_t offset) { @@ -388,6 +439,12 @@ bool perform_dap_swd_sequences(dap_swd_sequence_s *const sequences, const uint8_ { if (sequence_count > 5U) return false; + /* + * If this adaptor doesn't support the DAP_SWD_Sequence command, rewrite these to a series of + * DAP_SWJ_Sequence commands and perform them to net the same effect as we'd have gotten otherwise. + */ + if (dap_quirks & DAP_QUIRK_NO_SWD_SEQUENCE) + return dap_swd_sequence_as_swj_sequences(sequences, sequence_count); DEBUG_PROBE("-> dap_swd_sequence (%u sequences)\n", sequence_count); /* 47 is 2 + (5 * 9) where 9 is the max length of each sequence request */ diff --git a/src/platforms/hosted/dap_command.h b/src/platforms/hosted/dap_command.h index ecc298f1a9e..54231892dc2 100644 --- a/src/platforms/hosted/dap_command.h +++ b/src/platforms/hosted/dap_command.h @@ -91,6 +91,11 @@ typedef enum dap_info_status { #define DAP_SWJ_nTRST (1U << 5U) #define DAP_SWJ_nRST (1U << 7U) +#define DAP_TRANSFER_APnDP (1U << 0U) +#define DAP_TRANSFER_RnW (1U << 1U) + +#define DAP_TRANSFER_WAIT (1U << 1U) + typedef struct dap_transfer_request { uint8_t request; uint32_t data; @@ -147,6 +152,8 @@ typedef struct dap_swj_pins_request { bool perform_dap_transfer(adiv5_debug_port_s *target_dp, const dap_transfer_request_s *transfer_requests, size_t requests, uint32_t *response_data, size_t responses); +bool perform_dap_transfer_swd_unchecked( + const dap_transfer_request_s *transfer_requests, size_t requests, uint32_t *response_data, size_t responses); bool perform_dap_transfer_recoverable(adiv5_debug_port_s *target_dp, const dap_transfer_request_s *transfer_requests, size_t requests, uint32_t *response_data, size_t responses); bool perform_dap_transfer_block_read( diff --git a/src/platforms/hosted/dap_jtag.c b/src/platforms/hosted/dap_jtag.c index fcf5bf8a26a..bc677128618 100644 --- a/src/platforms/hosted/dap_jtag.c +++ b/src/platforms/hosted/dap_jtag.c @@ -44,7 +44,7 @@ static bool dap_jtag_next(bool tms, bool tdi); bool dap_jtag_init(void) { - /* If we are not able to talk SWD with this adaptor, make this insta-fail */ + /* If we are not able to talk JTAG with this adaptor, make this insta-fail */ if (!(dap_caps & DAP_CAP_JTAG)) return false; @@ -113,7 +113,7 @@ static void dap_jtag_tdi_seq(const bool final_tms, const uint8_t *const data_in, static bool dap_jtag_next(const bool tms, const bool tdi) { -#if ENABLE_DEBUG == 1 +#ifndef DEBUG_PROBE_IS_NOOP const uint8_t tms_byte = tms ? 1 : 0; #endif const uint8_t tdi_byte = tdi ? 1 : 0; diff --git a/src/platforms/hosted/dap_swd.c b/src/platforms/hosted/dap_swd.c index 6dc7c6fd8fc..b0c3edfbf3c 100644 --- a/src/platforms/hosted/dap_swd.c +++ b/src/platforms/hosted/dap_swd.c @@ -1,7 +1,7 @@ /* * This file is part of the Black Magic Debug project. * - * Copyright (C) 2023-2024 1BitSquared + * Copyright (C) 2023-2025 1BitSquared * Written by Rachel Mant * All rights reserved. * @@ -76,15 +76,9 @@ bool dap_swd_init(adiv5_debug_port_s *target_dp) swd_proc.seq_out = dap_swd_seq_out; swd_proc.seq_out_parity = dap_swd_seq_out_parity; - /* If we have SWD sequences available, make use of them */ - if (dap_has_swd_sequence) { - target_dp->write_no_check = dap_write_reg_no_check; - target_dp->read_no_check = dap_read_reg_no_check; - } else { - target_dp->write_no_check = NULL; - target_dp->read_no_check = NULL; - } /* Set up the accelerated SWD functions for basic target operations */ + target_dp->write_no_check = dap_write_reg_no_check; + target_dp->read_no_check = dap_read_reg_no_check; target_dp->dp_read = dap_dp_read_reg; target_dp->low_access = dap_dp_raw_access; target_dp->abort = dap_dp_abort; @@ -178,64 +172,63 @@ static bool dap_swd_seq_in_parity(uint32_t *const result, const size_t clock_cyc static bool dap_write_reg_no_check(const uint16_t addr, const uint32_t data) { DEBUG_PROBE("dap_write_reg_no_check %04x <- %08" PRIx32 "\n", addr, data); - /* Setup the sequences */ - dap_swd_sequence_s sequences[5] = { - /* Write the 8 byte request */ - { - 8U, - DAP_SWD_OUT_SEQUENCE, - {make_packet_request(ADIV5_LOW_WRITE, addr)}, - }, - /* Perform one turn-around cycle then read the 3 bit ACK */ - {4U, DAP_SWD_IN_SEQUENCE}, - /* Perform another turnaround cycle */ - {1U, DAP_SWD_OUT_SEQUENCE, {0}}, - /* Now write out the 32b of data to send and the 1b of parity */ - { - 33U, - DAP_SWD_OUT_SEQUENCE, - /* The 4 data bytes are filled in below with write_le4() */ - {0U, 0U, 0U, 0U, calculate_odd_parity(data)}, - }, - /* Finished up by performing a sequence of 8 idle bits */ - {8U, DAP_SWD_OUT_SEQUENCE, {0U}}, - }; - write_le4(sequences[3].data, 0, data); - /* Now perform the sequences */ - if (!perform_dap_swd_sequences(sequences, 5U)) { - DEBUG_ERROR("dap_write_reg_no_check failed\n"); - return false; + /* Check for writes to TARGETSEL */ + if (addr == ADIV5_DP_TARGETSEL) { + /* Check for the SWD sequence quirk, and fail if it's present */ + if (dap_quirks & DAP_QUIRK_NO_SWD_SEQUENCE) + return false; + /* Otherwise, setup the sequences */ + dap_swd_sequence_s sequences[5] = { + /* Write the 8 byte request */ + { + 8U, + DAP_SWD_OUT_SEQUENCE, + {make_packet_request(ADIV5_LOW_WRITE, addr)}, + }, + /* Perform one turn-around cycle then read the 3 bit ACK */ + {4U, DAP_SWD_IN_SEQUENCE}, + /* Perform another turnaround cycle */ + {1U, DAP_SWD_OUT_SEQUENCE, {0}}, + /* Now write out the 32b of data to send and the 1b of parity */ + { + 33U, + DAP_SWD_OUT_SEQUENCE, + /* The 4 data bytes are filled in below with write_le4() */ + {0U, 0U, 0U, 0U, calculate_odd_parity(data)}, + }, + /* Finished up by performing a sequence of 8 idle bits */ + {8U, DAP_SWD_OUT_SEQUENCE, {0U}}, + }; + write_le4(sequences[3].data, 0, data); + /* Now perform the sequences */ + if (!perform_dap_swd_sequences(sequences, 5U)) { + DEBUG_ERROR("dap_write_reg_no_check failed\n"); + return false; + } + /* Check the ack state */ + const uint8_t ack = sequences[1].data[0] & 7U; + return ack != SWD_ACK_OK; } - /* Check the ack state */ - const uint8_t ack = sequences[1].data[0] & 7U; - return ack != SWD_ACK_OK; + /* For all other writes, set up a write transfer */ + const dap_transfer_request_s request = { + .request = addr & ~DAP_TRANSFER_RnW, + .data = data, + }; + /* Try to perform it and return if it was a success or not */ + return perform_dap_transfer_swd_unchecked(&request, 1U, NULL, 0U); } static uint32_t dap_read_reg_no_check(const uint16_t addr) { - /* Setup the sequences */ - dap_swd_sequence_s sequences[4] = { - /* Write the 8 byte request */ - { - 8U, - DAP_SWD_OUT_SEQUENCE, - {make_packet_request(ADIV5_LOW_READ, addr)}, - }, - /* Perform one turn-around cycle then read the 3 bit ACK */ - {3U, DAP_SWD_IN_SEQUENCE}, - /* Perform a read for the 32b of data and the 1b of parity */ - {33U, DAP_SWD_IN_SEQUENCE}, - /* Finished up by performing a sequence of 8 idle bits */ - {8U, DAP_SWD_OUT_SEQUENCE, {0U}}, - }; - /* Now perform the sequences */ - if (!perform_dap_swd_sequences(sequences, 4U)) { - DEBUG_ERROR("dap_read_reg_no_check failed\n"); - return false; + /* Set up a read transfer */ + const dap_transfer_request_s request = {.request = addr | DAP_TRANSFER_RnW}; + uint32_t value = 0; + /* Try to perform it, and return the value that results if it suceeds */ + if (perform_dap_transfer_swd_unchecked(&request, 1U, &value, 1U)) { + DEBUG_PROBE("dap_read_reg_no_check %04x -> %08" PRIx32 "\n", addr, value); + return value; } - const uint32_t data = read_le4(sequences[2].data, 0); - DEBUG_PROBE("dap_read_reg_no_check %04x -> %08" PRIx32 "\n", addr, data); - /* Check the ack state */ - const uint8_t ack = sequences[1].data[0] & 7U; - return ack == SWD_ACK_OK ? data : 0; + /* If it failed, show a fallback value and return it */ + DEBUG_PROBE("dap_read_reg_no_check %04x -> %08x\n", addr, 0U); + return 0U; } diff --git a/src/platforms/hosted/windows/ftdi.c b/src/platforms/hosted/windows/ftdi.c index 5254c3411df..d92e16bd41f 100644 --- a/src/platforms/hosted/windows/ftdi.c +++ b/src/platforms/hosted/windows/ftdi.c @@ -1,8 +1,9 @@ /* * This file is part of the Black Magic Debug project. * - * Copyright (C) 2023 1BitSquared + * Copyright (C) 2023,2025 1BitSquared * Written by Sid Price + * Modified by Rachel Mant * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -151,7 +152,10 @@ int ftdi_write_data(struct ftdi_context *ftdi, const unsigned char *buf, int siz { (void)ftdi; DWORD bytes_written; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-qual" if (FT_Write(ftdi_handle, (unsigned char *)buf, size, &bytes_written) != FT_OK) +#pragma GCC diagnostic pop return 0; return bytes_written; } diff --git a/src/target/jtag_scan.c b/src/target/jtag_scan.c index 141e75305e1..09cadba4807 100644 --- a/src/target/jtag_scan.c +++ b/src/target/jtag_scan.c @@ -170,9 +170,16 @@ static bool jtag_read_idcodes(void) /* Try to read out 32 bits, while shifting in 1's */ uint32_t idcode = 0; jtag_proc.jtagtap_tdi_tdo_seq((uint8_t *)&idcode, false, ones, 32); - /* If the IDCode read is all 1's, we've reached the end */ + /* + * If the IDCode read is all 1's, we've reached the end, similarly if it's all 0's + * then something's wrong or we hit a bugged device in the chain and we're done. + */ if (idcode == 0xffffffffU) break; + if (idcode == 0U) { + DEBUG_WARN("Bugged all-0 ID code found, considering scan complete\n"); + break; + } /* Check if the max supported chain length is exceeded */ if (device == JTAG_MAX_DEVS) { DEBUG_ERROR("jtag_scan: Maximum chain length exceeded\n"); @@ -280,7 +287,7 @@ static bool jtag_read_irs(void) if (ir_len > JTAG_MAX_IR_LEN) { DEBUG_ERROR("jtag_scan: Maximum IR length exceeded\n"); jtag_dev_count = 0; - return 0; + return false; } return true; }