Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: Old firmware BMP identification via libusb #1989

Merged
merged 6 commits into from
Nov 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 69 additions & 13 deletions src/platforms/hosted/bmp_libusb.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ typedef int_least16_t char16_t;
#include "utils.h"
#include "hex_utils.h"

#define NO_SERIAL_NUMBER "<no serial number>"
#define NO_SERIAL_NUMBER "<no serial number>"
#define BMP_PRODUCT_STRING "Black Magic Probe"
#define BMP_PRODUCT_STRING_LENGTH ARRAY_LENGTH(BMP_PRODUCT_STRING)

void bmp_read_product_version(libusb_device_descriptor_s *device_descriptor, libusb_device *device,
libusb_device_handle *handle, char **product, char **manufacturer, char **serial, char **version);
Expand Down Expand Up @@ -80,6 +82,23 @@ static const debugger_device_s debugger_devices[] = {
{0, 0, PROBE_TYPE_NONE, NULL, ""},
};

#if defined(_WIN32) || defined(__CYGWIN__)
static char *strndup(const char *const src, const size_t size)
{
/* Determine how many bytes to copy to the new string, including the NULL terminator */
const size_t length = MIN(size, strlen(src)) + 1U;
/* Try to allocate storage for the new string */
char *result = malloc(length);
if (!result)
return NULL;
/* Now we have storage, copy the bytes over */
memcpy(result, src, length - 1U);
/* And finally terminate the string to return */
result[length - 1U] = '\0';
return result;
}
#endif

const debugger_device_s *get_debugger_device_from_vid_pid(const uint16_t probe_vid, const uint16_t probe_pid)
{
/* Iterate over the list excluding the last entry (PROBE_TYPE_NONE) */
Expand Down Expand Up @@ -140,21 +159,58 @@ void bmp_read_product_version(libusb_device_descriptor_s *device_descriptor, lib
(void)device;
(void)serial;
(void)manufacturer;
*product = get_device_descriptor_string(handle, device_descriptor->iProduct);
const char *const description = get_device_descriptor_string(handle, device_descriptor->iProduct);
const size_t description_len = strlen(description) + 1U;

char *start_of_version = strrchr(*product, ' ');
if (start_of_version == NULL) {
*version = NULL;
return;
/*
* Black Magic Debug product strings are in one of the following forms:
* Recent: Black Magic Probe v1.10.0-1273-g2b1ce9aee
* : Black Magic Probe (ST-Link v2) v1.10.0-1273-g2b1ce9aee
* Old : Black Magic Probe
* From this we want to extract two main things: version (if available), and the product name
*/

/* Let's start out easy - check to see if the string contains an opening paren (alternate platform) */
const char *const opening_paren = strchr(description + BMP_PRODUCT_STRING_LENGTH, '(');
/* If there isn't one, we're dealing with nominally a native probe */
if (!opening_paren) {
/* Knowing this, let's see if there are enough bytes for a version string, and if there are.. extract it */
if (description_len > BMP_PRODUCT_STRING_LENGTH) {
const char *version_begin = strrchr(description, ' ');
/* Thankfully, this can't fail, so just grab the version string from what we got */
*version = strdup(version_begin + 1U);
/* Now extract the remaining chunk of the description as the product string */
*product = strndup(description, version_begin - description);
} else {
/* We don't know the version (pre v1.7) and the description string is the product string */
*version = strdup("Unknown");
*product = strdup(description);
}
} else {
/* Otherwise, we've got a non-native probe, so find the closing paren for the probe type */
const char *const closing_paren = strchr(opening_paren, ')');
/* If we didn't find one, we've got a problem */
if (!closing_paren) {
DEBUG_ERROR("Production description for device is invalid, founding opening '(' but no closing ')'\n");
*version = strdup("Unknown");
*product = strdup("Invalid");
} else {
/* If we did find the closing ')', then see if we've got a version string*/
const char *const version_begin = strchr(closing_paren, ' ');
/* If we do, then extract whatever's left of the string as the version string */
if (version_begin)
*version = strdup(version_begin + 1U);
else
*version = strdup("Unknown");
/* Now we've dealt with the version information, use everything up to the ')' as the product string */
*product = strndup(description, (closing_paren - description) + 1U);
}
}

while (start_of_version[0] == ' ' && start_of_version != *product)
--start_of_version;
start_of_version[1U] = '\0';
start_of_version += 2U;
while (start_of_version[0] == ' ')
++start_of_version;
*version = strdup(start_of_version);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
free((void *)description);
#pragma GCC diagnostic pop
}

/*
Expand Down
9 changes: 5 additions & 4 deletions src/target/efm32.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
* * EFR32BG13P532F512GM32 (EFR Blue Gecko)
*/

/* Refer to the family reference manuals:
/*
* Refer to the family reference manuals:
*
* Also refer to AN0062 "Programming Internal Flash Over the Serial Wire Debug Interface"
* http://www.silabs.com/Support%20Documents/TechnicalDocs/an0062.pdf
Expand Down Expand Up @@ -98,7 +99,7 @@ const command_s efm32_cmd_list[] = {
/* Flash Information Area */
/* -------------------------------------------------------------------------- */

#define EFM32_INFO 0x0fe00000U
#define EFM32_INFO UINT32_C(0x0fe00000)
#define EFM32_USER_DATA (EFM32_INFO + 0x0000U)
#define EFM32_LOCK_BITS (EFM32_INFO + 0x4000U)
#define EFM32_V1_DI (EFM32_INFO + 0x8000U)
Expand Down Expand Up @@ -766,11 +767,11 @@ static bool efm32_cmd_efm_info(target_s *t, int argc, const char **argv)

switch (di_version) {
case 1:
tc_printf(t, "DI version 1 (silabs remix?) base 0x%08" PRIx16 "\n\n", EFM32_V1_DI);
tc_printf(t, "DI version 1 (silabs remix?) base 0x%08" PRIx32 "\n\n", EFM32_V1_DI);
break;

case 2:
tc_printf(t, "DI version 2 (energy micro remix?) base 0x%08" PRIx16 "\n\n", EFM32_V2_DI);
tc_printf(t, "DI version 2 (energy micro remix?) base 0x%08" PRIx32 "\n\n", EFM32_V2_DI);
break;

default:
Expand Down
14 changes: 7 additions & 7 deletions src/target/stm32l0.c
Original file line number Diff line number Diff line change
Expand Up @@ -765,16 +765,16 @@ static bool stm32lx_cmd_option(target_s *const target, const int argc, const cha
const size_t read_protection = stm32lx_prot_level(options);
if (stm32lx_is_stm32l1(target)) {
tc_printf(target,
"OPTR: 0x%08" PRIx32 ", RDPRT %" PRIu32 ", SPRMD %u, BOR %" PRIu32 " , WDG_SW %u"
"OPTR: 0x%08" PRIx32 ", RDPRT %" PRIu32 ", SPRMD %u, BOR %" PRIu32 ", WDG_SW %u"
", nRST_STP %u, nRST_STBY %u, nBFB2 %u\n",
options, (uint32_t)read_protection, (options & STM32L1_FLASH_OPTR_SPRMOD) ? 1 : 0,
options, (uint32_t)read_protection, (options & STM32L1_FLASH_OPTR_SPRMOD) ? 1U : 0U,
(options >> STM32L1_FLASH_OPTR_BOR_LEV_SHIFT) & STM32L1_FLASH_OPTR_BOR_LEV_MASK,
(options & STM32Lx_FLASH_OPTR_WDG_SW) ? 1 : 0, (options & STM32L1_FLASH_OPTR_nRST_STOP) ? 1 : 0,
(options & STM32L1_FLASH_OPTR_nRST_STDBY) ? 1 : 0, (options & STM32L1_FLASH_OPTR_nBFB2) ? 1 : 0);
(options & STM32Lx_FLASH_OPTR_WDG_SW) ? 1U : 0U, (options & STM32L1_FLASH_OPTR_nRST_STOP) ? 1U : 0U,
(options & STM32L1_FLASH_OPTR_nRST_STDBY) ? 1U : 0U, (options & STM32L1_FLASH_OPTR_nBFB2) ? 1U : 0U);
} else {
tc_printf(target, "OPTR: 0x%08" PRIx32 ", RDPROT %" PRIu32 ", WPRMOD %" PRIu16 ", WDG_SW %u, BOOT1 %u\n",
options, (uint32_t)read_protection, (options & STM32L0_FLASH_OPTR_WPRMOD) ? 1 : 0,
(options & STM32Lx_FLASH_OPTR_WDG_SW) ? 1 : 0, (options & STM32L0_FLASH_OPTR_BOOT1) ? 1 : 0);
tc_printf(target, "OPTR: 0x%08" PRIx32 ", RDPROT %" PRIu32 ", WPRMOD %u, WDG_SW %u, BOOT1 %u\n", options,
(uint32_t)read_protection, (options & STM32L0_FLASH_OPTR_WPRMOD) ? 1U : 0U,
(options & STM32Lx_FLASH_OPTR_WDG_SW) ? 1U : 0U, (options & STM32L0_FLASH_OPTR_BOOT1) ? 1U : 0U);
}

goto done;
Expand Down
4 changes: 2 additions & 2 deletions src/target/stm32l4.c
Original file line number Diff line number Diff line change
Expand Up @@ -744,8 +744,8 @@ static bool stm32l4_attach(target_s *const target)
if (!cortexm_attach(target) || !stm32l4_configure_dbgmcu(target, NULL))
return false;

/* Retrieve device information, and locate the device ID register */
const stm32l4_device_info_s *device = stm32l4_get_device_info(target->part_id);
/* Extract the device structure from the priv storage and enable the Flash if on an L55 part */
const stm32l4_device_info_s *const device = ((stm32l4_priv_s *)target->priv)->device;
if (device->family == STM32L4_FAMILY_L55x)
stm32l5_flash_enable(target);

Expand Down
Loading