From dd532e87c038ecd988b8bf83d6b1cf4515d5d2c9 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Tue, 16 Nov 2021 17:51:09 +0100 Subject: [PATCH 01/24] flash/nor/stm32f1x: allow write fallback for flash options Mostly refactoring. Rename original stm32x_write_block() to stm32x_write_block_async() as it uses target async algo. Introduce new stm32x_write_block() and move slow, host controlled fallback flash write there. The change allows stm32x_write_options() to use slow flash write fallback. While on it rename variables where halfword count is stored. Change-Id: I386ae15cf052b1490461ed8f7eea5b4403d466f7 Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/6706 Tested-by: jenkins Reviewed-by: Tarek BOCHKATI --- src/flash/nor/stm32f1x.c | 84 ++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 34 deletions(-) diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c index 6972bae2d..139f10ea8 100644 --- a/src/flash/nor/stm32f1x.c +++ b/src/flash/nor/stm32f1x.c @@ -131,7 +131,7 @@ struct stm32x_flash_bank { static int stm32x_mass_erase(struct flash_bank *bank); static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id); static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, - uint32_t address, uint32_t count); + uint32_t address, uint32_t hwords_count); /* flash bank stm32x 0 0 */ @@ -329,12 +329,14 @@ static int stm32x_write_options(struct flash_bank *bank) target_buffer_set_u16(target, opt_bytes + 12, (stm32x_info->option_bytes.protection >> 16) & 0xff); target_buffer_set_u16(target, opt_bytes + 14, (stm32x_info->option_bytes.protection >> 24) & 0xff); + /* Block write is preferred in favour of operation with ancient ST-Link + * firmwares without 16-bit memory access. See + * 480: flash: stm32f1x: write option bytes using the loader + * https://review.openocd.org/c/openocd/+/480 + */ retval = stm32x_write_block(bank, opt_bytes, STM32_OB_RDP, sizeof(opt_bytes) / 2); - if (retval != ERROR_OK) { - if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) - LOG_ERROR("working area required to erase options bytes"); + if (retval != ERROR_OK) return retval; - } retval = target_write_u32(target, STM32_FLASH_CR_B0, FLASH_LOCK); if (retval != ERROR_OK) @@ -442,8 +444,8 @@ static int stm32x_protect(struct flash_bank *bank, int set, unsigned int first, return stm32x_write_options(bank); } -static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, - uint32_t address, uint32_t count) +static int stm32x_write_block_async(struct flash_bank *bank, const uint8_t *buffer, + uint32_t address, uint32_t hwords_count) { struct stm32x_flash_bank *stm32x_info = bank->driver_priv; struct target *target = bank->target; @@ -493,7 +495,7 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, init_reg_param(®_params[4], "r4", 32, PARAM_IN_OUT); /* target address */ buf_set_u32(reg_params[0].value, 0, 32, stm32x_info->register_base); - buf_set_u32(reg_params[1].value, 0, 32, count); + buf_set_u32(reg_params[1].value, 0, 32, hwords_count); buf_set_u32(reg_params[2].value, 0, 32, source->address); buf_set_u32(reg_params[3].value, 0, 32, source->address + source->size); buf_set_u32(reg_params[4].value, 0, 32, address); @@ -501,7 +503,7 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; - retval = target_run_flash_async_algorithm(target, buffer, count, 2, + retval = target_run_flash_async_algorithm(target, buffer, hwords_count, 2, 0, NULL, 5, reg_params, source->address, source->size, @@ -537,6 +539,40 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, return retval; } +/** Writes a block to flash either using target algorithm + * or use fallback, host controlled halfword-by-halfword access. + * Flash controller must be unlocked before this call. + */ +static int stm32x_write_block(struct flash_bank *bank, + const uint8_t *buffer, uint32_t address, uint32_t hwords_count) +{ + struct target *target = bank->target; + + /* try using a block write - on ARM architecture or... */ + int retval = stm32x_write_block_async(bank, buffer, address, hwords_count); + + if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { + /* if block write failed (no sufficient working area), + * we use normal (slow) single halfword accesses */ + LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); + + while (hwords_count > 0) { + retval = target_write_memory(target, address, 2, 1, buffer); + if (retval != ERROR_OK) + return retval; + + retval = stm32x_wait_status_busy(bank, 5); + if (retval != ERROR_OK) + return retval; + + hwords_count--; + buffer += 2; + address += 2; + } + } + return retval; +} + static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { @@ -568,7 +604,6 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, new_buffer[count++] = 0xff; } - uint32_t words_remaining = count / 2; int retval, retval2; /* unlock flash registers */ @@ -577,34 +612,15 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, goto cleanup; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY2); if (retval != ERROR_OK) - goto cleanup; + goto reset_pg_and_lock; + /* enable flash programming */ retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PG); if (retval != ERROR_OK) - goto cleanup; + goto reset_pg_and_lock; - /* try using a block write */ - retval = stm32x_write_block(bank, buffer, bank->base + offset, words_remaining); - - if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { - /* if block write failed (no sufficient working area), - * we use normal (slow) single halfword accesses */ - LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); - - while (words_remaining > 0) { - retval = target_write_memory(target, bank->base + offset, 2, 1, buffer); - if (retval != ERROR_OK) - goto reset_pg_and_lock; - - retval = stm32x_wait_status_busy(bank, 5); - if (retval != ERROR_OK) - goto reset_pg_and_lock; - - words_remaining--; - buffer += 2; - offset += 2; - } - } + /* write to flash */ + retval = stm32x_write_block(bank, buffer, bank->base + offset, count / 2); reset_pg_and_lock: retval2 = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); From 10f933915d3234cda56f55752a14ec6c4734a6fd Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Tue, 16 Nov 2021 18:26:53 +0100 Subject: [PATCH 02/24] flash/nor/stm32f1x: remove write alignment code Use flash infrastructure to ensure writes are halfword aligned. Change-Id: Iddca3a256ace3486a23e1a9cb6a31c7a91ee58bf Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/6707 Tested-by: jenkins Reviewed-by: Tarek BOCHKATI --- src/flash/nor/stm32f1x.c | 37 ++++++++++++++----------------------- 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c index 139f10ea8..664524b03 100644 --- a/src/flash/nor/stm32f1x.c +++ b/src/flash/nor/stm32f1x.c @@ -151,6 +151,9 @@ FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command) stm32x_info->register_base = FLASH_REG_BASE_B0; stm32x_info->user_bank_size = bank->size; + /* The flash write must be aligned to a halfword boundary */ + bank->write_start_alignment = bank->write_end_alignment = 2; + return ERROR_OK; } @@ -548,6 +551,11 @@ static int stm32x_write_block(struct flash_bank *bank, { struct target *target = bank->target; + /* The flash write must be aligned to a halfword boundary. + * The flash infrastructure ensures it, do just a security check + */ + assert(address % 2 == 0); + /* try using a block write - on ARM architecture or... */ int retval = stm32x_write_block_async(bank, buffer, address, hwords_count); @@ -577,39 +585,24 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; - uint8_t *new_buffer = NULL; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } - if (offset & 0x1) { - LOG_ERROR("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset); - return ERROR_FLASH_DST_BREAKS_ALIGNMENT; - } - - /* If there's an odd number of bytes, the data has to be padded. Duplicate - * the buffer and use the normal code path with a single block write since - * it's probably cheaper than to special case the last odd write using - * discrete accesses. */ - if (count & 1) { - new_buffer = malloc(count + 1); - if (!new_buffer) { - LOG_ERROR("odd number of bytes to write and no memory for padding buffer"); - return ERROR_FAIL; - } - LOG_INFO("odd number of bytes to write, padding with 0xff"); - buffer = memcpy(new_buffer, buffer, count); - new_buffer[count++] = 0xff; - } + /* The flash write must be aligned to a halfword boundary. + * The flash infrastructure ensures it, do just a security check + */ + assert(offset % 2 == 0); + assert(count % 2 == 0); int retval, retval2; /* unlock flash registers */ retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY1); if (retval != ERROR_OK) - goto cleanup; + return retval; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY2); if (retval != ERROR_OK) goto reset_pg_and_lock; @@ -627,8 +620,6 @@ reset_pg_and_lock: if (retval == ERROR_OK) retval = retval2; -cleanup: - free(new_buffer); return retval; } From e3f4ea0b574d952672d57792895a91065aa7a569 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Tue, 16 Nov 2021 19:04:05 +0100 Subject: [PATCH 03/24] flash/nor/stm32f1x: tidy up async algo supporting code Use target_get_working_area_avail() instead of try-fail iteration. Call destroy_reg_param() in a for cycle. Change-Id: I1891d1ffdea99010c6ab66b9578400b9d7922e20 Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/6708 Tested-by: jenkins Reviewed-by: Tarek BOCHKATI --- src/flash/nor/stm32f1x.c | 45 ++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c index 664524b03..f4b1daa56 100644 --- a/src/flash/nor/stm32f1x.c +++ b/src/flash/nor/stm32f1x.c @@ -452,12 +452,11 @@ static int stm32x_write_block_async(struct flash_bank *bank, const uint8_t *buff { struct stm32x_flash_bank *stm32x_info = bank->driver_priv; struct target *target = bank->target; - uint32_t buffer_size = 16384; + uint32_t buffer_size; struct working_area *write_algorithm; struct working_area *source; - struct reg_param reg_params[5]; struct armv7m_algorithm armv7m_info; - int retval = ERROR_OK; + int retval; static const uint8_t stm32x_flash_write_code[] = { #include "../../../contrib/loaders/flash/stm32/stm32f1x.inc" @@ -478,19 +477,28 @@ static int stm32x_write_block_async(struct flash_bank *bank, const uint8_t *buff } /* memory buffer */ - while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { - buffer_size /= 2; - buffer_size &= ~3UL; /* Make sure it's 4 byte aligned */ - if (buffer_size <= 256) { - /* we already allocated the writing code, but failed to get a - * buffer, free the algorithm */ - target_free_working_area(target, write_algorithm); + buffer_size = target_get_working_area_avail(target); + buffer_size = MIN(hwords_count * 2, MAX(buffer_size, 256)); + /* Normally we allocate all available working area. + * MIN shrinks buffer_size if the size of the written block is smaller. + * MAX prevents using async algo if the available working area is smaller + * than 256, the following allocation fails with + * ERROR_TARGET_RESOURCE_NOT_AVAILABLE and slow flashing takes place. + */ - LOG_WARNING("no large enough working area available, can't do block memory writes"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } + retval = target_alloc_working_area(target, buffer_size, &source); + /* Allocated size is always 32-bit word aligned */ + if (retval != ERROR_OK) { + target_free_working_area(target, write_algorithm); + LOG_WARNING("no large enough working area available, can't do block memory writes"); + /* target_alloc_working_area() may return ERROR_FAIL if area backup fails: + * convert any error to ERROR_TARGET_RESOURCE_NOT_AVAILABLE + */ + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } + struct reg_param reg_params[5]; + init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* flash base (in), status (out) */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* count (halfword-16bit) */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* buffer start */ @@ -508,7 +516,7 @@ static int stm32x_write_block_async(struct flash_bank *bank, const uint8_t *buff retval = target_run_flash_async_algorithm(target, buffer, hwords_count, 2, 0, NULL, - 5, reg_params, + ARRAY_SIZE(reg_params), reg_params, source->address, source->size, write_algorithm->address, 0, &armv7m_info); @@ -530,15 +538,12 @@ static int stm32x_write_block_async(struct flash_bank *bank, const uint8_t *buff } } + for (unsigned int i = 0; i < ARRAY_SIZE(reg_params); i++) + destroy_reg_param(®_params[i]); + target_free_working_area(target, source); target_free_working_area(target, write_algorithm); - destroy_reg_param(®_params[0]); - destroy_reg_param(®_params[1]); - destroy_reg_param(®_params[2]); - destroy_reg_param(®_params[3]); - destroy_reg_param(®_params[4]); - return retval; } From b801452d42c189a13f6cc1ff769fc98bededc7c5 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Tue, 16 Nov 2021 19:41:05 +0100 Subject: [PATCH 04/24] flash/nor/stm32f1x: unify flash error reporting stm32x_wait_status_busy() has two side effects in case of flash programming error: - reports error - clears error bit in status register Use stm32x_wait_status_busy() to report also flash error during target algo flash write. While on it use more descriptive error codes in stm32x_wait_status_busy(). Change-Id: I6e1cffc2aa5411b918a23ed62d5194910888a9d1 Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/6709 Tested-by: jenkins Reviewed-by: Tarek BOCHKATI --- src/flash/nor/stm32f1x.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c index f4b1daa56..26231e9cb 100644 --- a/src/flash/nor/stm32f1x.c +++ b/src/flash/nor/stm32f1x.c @@ -185,19 +185,19 @@ static int stm32x_wait_status_busy(struct flash_bank *bank, int timeout) break; if (timeout-- <= 0) { LOG_ERROR("timed out waiting for flash"); - return ERROR_FAIL; + return ERROR_FLASH_BUSY; } alive_sleep(1); } if (status & FLASH_WRPRTERR) { LOG_ERROR("stm32x device protected"); - retval = ERROR_FAIL; + retval = ERROR_FLASH_PROTECTED; } if (status & FLASH_PGERR) { - LOG_ERROR("stm32x device programming failed"); - retval = ERROR_FAIL; + LOG_ERROR("stm32x device programming failed / flash not erased"); + retval = ERROR_FLASH_OPERATION_FAILED; } /* Clear but report errors */ @@ -522,20 +522,18 @@ static int stm32x_write_block_async(struct flash_bank *bank, const uint8_t *buff &armv7m_info); if (retval == ERROR_FLASH_OPERATION_FAILED) { - LOG_ERROR("flash write failed at address 0x%"PRIx32, + /* Actually we just need to check for programming errors + * stm32x_wait_status_busy also reports error and clears status bits. + * + * Target algo returns flash status in r0 only if properly finished. + * It is safer to re-read status register. + */ + int retval2 = stm32x_wait_status_busy(bank, 5); + if (retval2 != ERROR_OK) + retval = retval2; + + LOG_ERROR("flash write failed just before address 0x%"PRIx32, buf_get_u32(reg_params[4].value, 0, 32)); - - if (buf_get_u32(reg_params[0].value, 0, 32) & FLASH_PGERR) { - LOG_ERROR("flash memory not erased before writing"); - /* Clear but report errors */ - target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_SR), FLASH_PGERR); - } - - if (buf_get_u32(reg_params[0].value, 0, 32) & FLASH_WRPRTERR) { - LOG_ERROR("flash memory write protected"); - /* Clear but report errors */ - target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_SR), FLASH_WRPRTERR); - } } for (unsigned int i = 0; i < ARRAY_SIZE(reg_params); i++) From e83eeb44aa96e380f46d37980b8b76a908757dc6 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Tue, 16 Nov 2021 20:12:53 +0100 Subject: [PATCH 05/24] flash/nor/stm32f1x: lock flash in case of error The current code locks the flash controller in case of error during flash write only. An error in other flash operations may cause the flash is left unlocked. Implement locking also after error in erase, mass erase, options write and erase. Change-Id: I26c2ed7914e7847122306f29b777b9eefd1dc580 Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/6710 Tested-by: jenkins Reviewed-by: Tarek BOCHKATI --- src/flash/nor/stm32f1x.c | 85 ++++++++++++++++++++++------------------ 1 file changed, 46 insertions(+), 39 deletions(-) diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c index 26231e9cb..8e66af368 100644 --- a/src/flash/nor/stm32f1x.c +++ b/src/flash/nor/stm32f1x.c @@ -261,36 +261,39 @@ static int stm32x_erase_options(struct flash_bank *bank) int retval = target_write_u32(target, STM32_FLASH_KEYR_B0, KEY1); if (retval != ERROR_OK) return retval; - retval = target_write_u32(target, STM32_FLASH_KEYR_B0, KEY2); if (retval != ERROR_OK) - return retval; + goto flash_lock; /* unlock option flash registers */ retval = target_write_u32(target, STM32_FLASH_OPTKEYR_B0, KEY1); if (retval != ERROR_OK) - return retval; + goto flash_lock; retval = target_write_u32(target, STM32_FLASH_OPTKEYR_B0, KEY2); if (retval != ERROR_OK) - return retval; + goto flash_lock; /* erase option bytes */ retval = target_write_u32(target, STM32_FLASH_CR_B0, FLASH_OPTER | FLASH_OPTWRE); if (retval != ERROR_OK) - return retval; + goto flash_lock; retval = target_write_u32(target, STM32_FLASH_CR_B0, FLASH_OPTER | FLASH_STRT | FLASH_OPTWRE); if (retval != ERROR_OK) - return retval; + goto flash_lock; retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); if (retval != ERROR_OK) - return retval; + goto flash_lock; /* clear read protection option byte * this will also force a device unlock if set */ stm32x_info->option_bytes.rdp = stm32x_info->default_rdp; return ERROR_OK; + +flash_lock: + target_write_u32(target, STM32_FLASH_CR_B0, FLASH_LOCK); + return retval; } static int stm32x_write_options(struct flash_bank *bank) @@ -306,20 +309,20 @@ static int stm32x_write_options(struct flash_bank *bank) return retval; retval = target_write_u32(target, STM32_FLASH_KEYR_B0, KEY2); if (retval != ERROR_OK) - return retval; + goto flash_lock; /* unlock option flash registers */ retval = target_write_u32(target, STM32_FLASH_OPTKEYR_B0, KEY1); if (retval != ERROR_OK) - return retval; + goto flash_lock; retval = target_write_u32(target, STM32_FLASH_OPTKEYR_B0, KEY2); if (retval != ERROR_OK) - return retval; + goto flash_lock; /* program option bytes */ retval = target_write_u32(target, STM32_FLASH_CR_B0, FLASH_OPTPG | FLASH_OPTWRE); if (retval != ERROR_OK) - return retval; + goto flash_lock; uint8_t opt_bytes[16]; @@ -338,14 +341,14 @@ static int stm32x_write_options(struct flash_bank *bank) * https://review.openocd.org/c/openocd/+/480 */ retval = stm32x_write_block(bank, opt_bytes, STM32_OB_RDP, sizeof(opt_bytes) / 2); - if (retval != ERROR_OK) - return retval; - retval = target_write_u32(target, STM32_FLASH_CR_B0, FLASH_LOCK); - if (retval != ERROR_OK) - return retval; - - return ERROR_OK; +flash_lock: + { + int retval2 = target_write_u32(target, STM32_FLASH_CR_B0, FLASH_LOCK); + if (retval == ERROR_OK) + retval = retval2; + } + return retval; } static int stm32x_protect_check(struct flash_bank *bank) @@ -389,31 +392,33 @@ static int stm32x_erase(struct flash_bank *bank, unsigned int first, return retval; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY2); if (retval != ERROR_OK) - return retval; + goto flash_lock; for (unsigned int i = first; i <= last; i++) { retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PER); if (retval != ERROR_OK) - return retval; + goto flash_lock; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_AR), bank->base + bank->sectors[i].offset); if (retval != ERROR_OK) - return retval; + goto flash_lock; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PER | FLASH_STRT); if (retval != ERROR_OK) - return retval; + goto flash_lock; retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); if (retval != ERROR_OK) - return retval; + goto flash_lock; } - retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); - if (retval != ERROR_OK) - return retval; - - return ERROR_OK; +flash_lock: + { + int retval2 = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); + if (retval == ERROR_OK) + retval = retval2; + } + return retval; } static int stm32x_protect(struct flash_bank *bank, int set, unsigned int first, @@ -1483,8 +1488,10 @@ COMMAND_HANDLER(stm32x_handle_options_load_command) if (retval != ERROR_OK) return retval; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY2); - if (retval != ERROR_OK) + if (retval != ERROR_OK) { + (void)target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); return retval; + } /* force re-load of option bytes - generates software reset */ retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_OBL_LAUNCH); @@ -1509,26 +1516,26 @@ static int stm32x_mass_erase(struct flash_bank *bank) return retval; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY2); if (retval != ERROR_OK) - return retval; + goto flash_lock; /* mass erase flash memory */ retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_MER); if (retval != ERROR_OK) - return retval; + goto flash_lock; retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_MER | FLASH_STRT); if (retval != ERROR_OK) - return retval; + goto flash_lock; retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); - if (retval != ERROR_OK) - return retval; - retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); - if (retval != ERROR_OK) - return retval; - - return ERROR_OK; +flash_lock: + { + int retval2 = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); + if (retval == ERROR_OK) + retval = retval2; + } + return retval; } COMMAND_HANDLER(stm32x_handle_mass_erase_command) From 2e5df83de7f2bceeeab762f24d1a15a850d75d9e Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Thu, 24 Mar 2022 15:30:16 +0100 Subject: [PATCH 06/24] nds32: deprecate it, together with aice adapter driver The target nds32 and its companion adapter aice have not received any real improvement since 2013. It has been hard to keep them aligned during the evolution of OpenOCD code, with no way for maintainers to really check if they are still working. No real documentation is present for them in OpenOCD. The arch nds32 has been dropped from Linux kernel v5.18-rc1. Deprecate both nds32 target and aice adapter with the target of dropping them for v0.13.0. Remove automatic build of aice, forcing user to select it. Change-Id: Ib465d676246fa3b4e95c3d399ba9a5cf1f8b3baf Signed-off-by: Antonio Borneo Reviewed-on: https://review.openocd.org/c/openocd/+/6887 Reviewed-by: Tomas Vanek Tested-by: jenkins --- configure.ac | 10 ++++++++-- doc/openocd.texi | 6 +++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 15d7229a4..7037656ae 100644 --- a/configure.ac +++ b/configure.ac @@ -122,8 +122,10 @@ m4_define([USB1_ADAPTERS], [[opendous], [eStick/opendous JTAG Programmer], [OPENDOUS]], [[armjtagew], [Olimex ARM-JTAG-EW Programmer], [ARMJTAGEW]], [[rlink], [Raisonance RLink JTAG Programmer], [RLINK]], - [[usbprog], [USBProg JTAG Programmer], [USBPROG]], - [[aice], [Andes JTAG Programmer], [AICE]]]) + [[usbprog], [USBProg JTAG Programmer], [USBPROG]]]) + +m4_define([DEPRECATED_USB1_ADAPTERS], + [[[aice], [Andes JTAG Programmer (deprecated)], [AICE]]]) m4_define([HIDAPI_ADAPTERS], [[[cmsis_dap], [CMSIS-DAP Compliant Debugger], [CMSIS_DAP_HID]], @@ -256,6 +258,8 @@ AC_ARG_ADAPTERS([ LIBJAYLINK_ADAPTERS ],[auto]) +AC_ARG_ADAPTERS([DEPRECATED_USB1_ADAPTERS],[no]) + AC_ARG_ENABLE([parport], AS_HELP_STRING([--enable-parport], [Enable building the pc parallel port driver]), [build_parport=$enableval], [build_parport=no]) @@ -660,6 +664,7 @@ m4_define([PROCESS_ADAPTERS], [ ]) PROCESS_ADAPTERS([USB1_ADAPTERS], ["x$use_libusb1" = "xyes"], [libusb-1.x]) +PROCESS_ADAPTERS([DEPRECATED_USB1_ADAPTERS], ["x$use_libusb1" = "xyes"], [libusb-1.x]) PROCESS_ADAPTERS([HIDAPI_ADAPTERS], ["x$use_hidapi" = "xyes"], [hidapi]) PROCESS_ADAPTERS([HIDAPI_USB1_ADAPTERS], ["x$use_hidapi" = "xyes" -a "x$use_libusb1" = "xyes"], [hidapi and libusb-1.x]) PROCESS_ADAPTERS([LIBFTDI_ADAPTERS], ["x$use_libftdi" = "xyes"], [libftdi]) @@ -798,6 +803,7 @@ echo echo OpenOCD configuration summary echo -------------------------------------------------- m4_foreach([adapter], [USB1_ADAPTERS, + DEPRECATED_USB1_ADAPTERS, HIDAPI_ADAPTERS, HIDAPI_USB1_ADAPTERS, LIBFTDI_ADAPTERS, LIBFTDI_USB1_ADAPTERS, LIBGPIOD_ADAPTERS, diff --git a/doc/openocd.texi b/doc/openocd.texi index 1b6d06302..121873522 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -4728,9 +4728,9 @@ specified, @xref{gdbportoverride,,option -gdb-port}.), and a fake ARM core will be emulated to comply to GDB remote protocol. @item @code{mips_m4k} -- a MIPS core. @item @code{mips_mips64} -- a MIPS64 core. -@item @code{nds32_v2} -- this is an Andes NDS32 v2 core. -@item @code{nds32_v3} -- this is an Andes NDS32 v3 core. -@item @code{nds32_v3m} -- this is an Andes NDS32 v3m core. +@item @code{nds32_v2} -- this is an Andes NDS32 v2 core (deprecated; would be removed in v0.13.0). +@item @code{nds32_v3} -- this is an Andes NDS32 v3 core (deprecated; would be removed in v0.13.0). +@item @code{nds32_v3m} -- this is an Andes NDS32 v3m core (deprecated; would be removed in v0.13.0). @item @code{or1k} -- this is an OpenRISC 1000 core. The current implementation supports three JTAG TAP cores: @itemize @minus From a5035849d671fc7821b7b864f0e103d6a0521915 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sat, 16 Apr 2022 18:59:49 +0200 Subject: [PATCH 07/24] tcl/target/stm32f4x: fix name Change-Id: I9baa79d8cf402991e6638c255a91728b8a77020c Signed-off-by: Markus Reiter Reviewed-on: https://review.openocd.org/c/openocd/+/6930 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Tarek BOCHKATI Reviewed-by: Antonio Borneo --- tcl/target/stm32f4x.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcl/target/stm32f4x.cfg b/tcl/target/stm32f4x.cfg index 2228de72f..aa2816e76 100644 --- a/tcl/target/stm32f4x.cfg +++ b/tcl/target/stm32f4x.cfg @@ -1,7 +1,7 @@ # script for stm32f4x family # -# stm32 devices support both JTAG and SWD transports. +# stm32f4 devices support both JTAG and SWD transports. # source [find target/swj-dp.tcl] source [find mem_helper.tcl] From d47aaf6d92788efc90c6d3379d58132e7ddfa781 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sat, 16 Apr 2022 19:02:21 +0200 Subject: [PATCH 08/24] tcl/target/stm32l4x: set default WORKAREASIZE to smallest device Change-Id: Ia8bfb664ff28bd0579492032ce513b010e71c593 Signed-off-by: Markus Reiter Reviewed-on: https://review.openocd.org/c/openocd/+/6931 Tested-by: jenkins Reviewed-by: Tarek BOCHKATI Reviewed-by: Antonio Borneo Reviewed-by: Tomas Vanek --- tcl/target/stm32l4x.cfg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tcl/target/stm32l4x.cfg b/tcl/target/stm32l4x.cfg index 589979193..103d741e2 100644 --- a/tcl/target/stm32l4x.cfg +++ b/tcl/target/stm32l4x.cfg @@ -15,11 +15,11 @@ if { [info exists CHIPNAME] } { set _ENDIAN little # Work-area is a space in RAM used for flash programming -# Smallest current target has 64kB ram, use 32kB by default to avoid surprises +# By default use 40kB (Available RAM in smallest device STM32L412) if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { - set _WORKAREASIZE 0x8000 + set _WORKAREASIZE 0xa000 } #jtag scan chain From 7ca770cbf9ecda1fe603379f6973a70ec9e913a7 Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sat, 16 Apr 2022 19:04:50 +0200 Subject: [PATCH 09/24] tcl/target/stm32l4x: switch to new TPIU/SWO support Change-Id: I3362fa7292eae7a3ba119cf6183f8bc4cbd5cbd4 Signed-off-by: Markus Reiter Reviewed-on: https://review.openocd.org/c/openocd/+/6932 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/target/stm32l4x.cfg | 40 +++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/tcl/target/stm32l4x.cfg b/tcl/target/stm32l4x.cfg index 103d741e2..dec2b2760 100644 --- a/tcl/target/stm32l4x.cfg +++ b/tcl/target/stm32l4x.cfg @@ -38,6 +38,8 @@ if { [info exists CPUTAPID] } { swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu +tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000 + if {[using_jtag]} { jtag newtap $_CHIPNAME bs -irlen 5 } @@ -88,6 +90,37 @@ if {![using_hla]} { cortex_m reset_config sysresetreq } +proc proc_post_enable {_chipname} { + targets $_chipname.cpu + + if { [$_chipname.tpiu cget -protocol] eq "sync" } { + switch [$_chipname.tpiu cget -port-width] { + 1 { + mmw 0xE0042004 0x00000060 0x000000c0 + mmw 0x48001020 0x00000000 0x0000ff00 + mmw 0x48001000 0x000000a0 0x000000f0 + mmw 0x48001008 0x000000f0 0x00000000 + } + 2 { + mmw 0xE0042004 0x000000a0 0x000000c0 + mmw 0x48001020 0x00000000 0x000fff00 + mmw 0x48001000 0x000002a0 0x000003f0 + mmw 0x48001008 0x000003f0 0x00000000 + } + 4 { + mmw 0xE0042004 0x000000e0 0x000000c0 + mmw 0x48001020 0x00000000 0x0fffff00 + mmw 0x48001000 0x00002aa0 0x00003ff0 + mmw 0x48001008 0x00003ff0 0x00000000 + } + } + } else { + mmw 0xE0042004 0x00000020 0x000000c0 + } +} + +$_CHIPNAME.tpiu configure -event post-enable "proc_post_enable $_CHIPNAME" + $_TARGETNAME configure -event reset-init { # CPU comes out of reset with MSI_ON | MSI_RDY | MSI Range 6 (4 MHz). # Use MSI 24 MHz clock, compliant even with VOS == 2. @@ -111,10 +144,3 @@ $_TARGETNAME configure -event examine-end { # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP mmw 0xE0042008 0x00001800 0 } - -$_TARGETNAME configure -event trace-config { - # Set TRACE_IOEN; TRACE_MODE is set to async; when using sync - # change this value accordingly to configure trace pins - # assignment - mmw 0xE0042004 0x00000020 0 -} From d8c81d72540a9e6a9f59412686332379ece1618f Mon Sep 17 00:00:00 2001 From: Markus Reiter Date: Sun, 17 Apr 2022 16:01:24 +0200 Subject: [PATCH 10/24] tcl/target/stm32l4x: align format/order/comments with stm32f4x Change-Id: Ie97bb2f56b582bc735c238af5f160fcb28a61eb0 Signed-off-by: Markus Reiter Reviewed-on: https://review.openocd.org/c/openocd/+/6933 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/target/stm32l4x.cfg | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/tcl/target/stm32l4x.cfg b/tcl/target/stm32l4x.cfg index dec2b2760..9bd7e37ba 100644 --- a/tcl/target/stm32l4x.cfg +++ b/tcl/target/stm32l4x.cfg @@ -49,8 +49,9 @@ target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 -flash bank $_CHIPNAME.flash stm32l4x 0x08000000 0 0 0 $_TARGETNAME -flash bank $_CHIPNAME.otp stm32l4x 0x1fff7000 0 0 0 $_TARGETNAME +set _FLASHNAME $_CHIPNAME.flash +flash bank $_FLASHNAME stm32l4x 0x08000000 0 0 0 $_TARGETNAME +flash bank $_CHIPNAME.otp stm32l4x 0x1fff7000 0 0 0 $_TARGETNAME if { [info exists QUADSPI] && $QUADSPI } { set a [llength [flash list]] @@ -90,6 +91,16 @@ if {![using_hla]} { cortex_m reset_config sysresetreq } +$_TARGETNAME configure -event examine-end { + # Enable debug during low power modes (uses more power) + # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP + mmw 0xE0042004 0x00000007 0 + + # Stop watchdog counters during halt + # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP + mmw 0xE0042008 0x00001800 0 +} + proc proc_post_enable {_chipname} { targets $_chipname.cpu @@ -127,6 +138,7 @@ $_TARGETNAME configure -event reset-init { # 3 WS compliant with VOS == 2 and 24 MHz. mww 0x40022000 0x00000103 ;# FLASH_ACR = PRFTBE | 3(Latency) mww 0x40021000 0x00000099 ;# RCC_CR = MSI_ON | MSIRGSEL | MSI Range 9 + # Boost JTAG frequency adapter speed 4000 } @@ -135,12 +147,3 @@ $_TARGETNAME configure -event reset-start { # Reset clock is MSI (4 MHz) adapter speed 500 } - -$_TARGETNAME configure -event examine-end { - # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP - mmw 0xE0042004 0x00000007 0 - - # Stop watchdog counters during halt - # DBGMCU_APB1_FZ |= DBG_IWDG_STOP | DBG_WWDG_STOP - mmw 0xE0042008 0x00001800 0 -} From 5ebb1bdea1dfff9cce430bd17d08e340eea38e03 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Wed, 30 Mar 2022 23:55:04 +0200 Subject: [PATCH 11/24] server/gdb: fix return of gdb remote monitor command Current implementation for gdb remote monitor command uses the command_run_line() to execute the command. While command_run_line() has several advantages, it unfortunately hides the error codes and outputs the result of the command through LOG_USER(), which is not what gdb requires. See 'qRcmd' in https://sourceware.org/gdb/onlinedocs/gdb/General-Query-Packets.html Replace command_run_line() with Jim_EvalObj() and parse the output to provide the proper result to gdb. Can be tested by defining in OpenOCD: proc a {} {return hello} proc b {} {return -code 4} proc c {} {return -code 4 "This is an error!"} then by executing in gdb console: monitor a monitor b monitor c monitor foo Change-Id: I1b85554d59221560e97861a499e16764e70c1172 Signed-off-by: Antonio Borneo Reported-by: Torbjorn Svensson Reviewed-on: https://review.openocd.org/c/openocd/+/6886 Tested-by: jenkins --- src/server/gdb_server.c | 43 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 82c8ce92b..fcc87fba1 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -2761,11 +2761,52 @@ static int gdb_query_packet(struct connection *connection, /* some commands need to know the GDB connection, make note of current * GDB connection. */ current_gdb_connection = gdb_connection; - command_run_line(cmd_ctx, cmd); + struct target *saved_target_override = cmd_ctx->current_target_override; + cmd_ctx->current_target_override = target; + + int retval = Jim_EvalObj(cmd_ctx->interp, Jim_NewStringObj(cmd_ctx->interp, cmd, -1)); + + cmd_ctx->current_target_override = saved_target_override; current_gdb_connection = NULL; target_call_timer_callbacks_now(); gdb_connection->output_flag = GDB_OUTPUT_NO; free(cmd); + if (retval == JIM_RETURN) + retval = cmd_ctx->interp->returnCode; + int lenmsg; + const char *cretmsg = Jim_GetString(Jim_GetResult(cmd_ctx->interp), &lenmsg); + char *retmsg; + if (lenmsg && cretmsg[lenmsg - 1] != '\n') { + retmsg = alloc_printf("%s\n", cretmsg); + lenmsg++; + } else { + retmsg = strdup(cretmsg); + } + if (!retmsg) + return ERROR_GDB_BUFFER_TOO_SMALL; + + if (retval == JIM_OK) { + if (lenmsg) { + char *hex_buffer = malloc(lenmsg * 2 + 1); + if (!hex_buffer) { + free(retmsg); + return ERROR_GDB_BUFFER_TOO_SMALL; + } + + size_t pkt_len = hexify(hex_buffer, (const uint8_t *)retmsg, lenmsg, + lenmsg * 2 + 1); + gdb_put_packet(connection, hex_buffer, pkt_len); + free(hex_buffer); + } else { + gdb_put_packet(connection, "OK", 2); + } + } else { + if (lenmsg) + gdb_output_con(connection, retmsg); + gdb_send_error(connection, retval); + } + free(retmsg); + return ERROR_OK; } gdb_put_packet(connection, "OK", 2); return ERROR_OK; From a213397323585188ad2622de7eb9d5fcddee7a02 Mon Sep 17 00:00:00 2001 From: Jan Matyas Date: Tue, 12 Apr 2022 13:33:51 +0200 Subject: [PATCH 12/24] target/image: fix - p_flags field in ELF64 segment headers is 64 bits wide Fixed the reading of p_flags in ELF64 segment headers - that field is 64 bits wide. Change-Id: I053ca57d36efb54b7c638484acd6c7a2fbcbd05a Signed-off-by: Jan Matyas Reviewed-on: https://review.openocd.org/c/openocd/+/6927 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/image.c | 4 ++-- src/target/image.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/target/image.c b/src/target/image.c index eafa73eaa..130ea6c1f 100644 --- a/src/target/image.c +++ b/src/target/image.c @@ -596,7 +596,7 @@ static int image_elf64_read_headers(struct image *image) image->sections[j].base_address = field64(elf, elf->segments64[i].p_paddr); image->sections[j].private = &elf->segments64[i]; - image->sections[j].flags = field32(elf, elf->segments64[i].p_flags); + image->sections[j].flags = field64(elf, elf->segments64[i].p_flags); j++; } } @@ -1168,7 +1168,7 @@ int image_read_section(struct image *image, return ERROR_OK; } -int image_add_section(struct image *image, target_addr_t base, uint32_t size, int flags, uint8_t const *data) +int image_add_section(struct image *image, target_addr_t base, uint32_t size, uint64_t flags, uint8_t const *data) { struct imagesection *section; diff --git a/src/target/image.h b/src/target/image.h index 5b5d11f6b..bf06064ac 100644 --- a/src/target/image.h +++ b/src/target/image.h @@ -52,7 +52,7 @@ enum image_type { struct imagesection { target_addr_t base_address; uint32_t size; - int flags; + uint64_t flags; void *private; /* private data */ }; @@ -108,7 +108,7 @@ int image_read_section(struct image *image, int section, target_addr_t offset, void image_close(struct image *image); int image_add_section(struct image *image, target_addr_t base, uint32_t size, - int flags, uint8_t const *data); + uint64_t flags, uint8_t const *data); int image_calculate_checksum(const uint8_t *buffer, uint32_t nbytes, uint32_t *checksum); From a26ee5344cf70e068265ac2f03a2915fae070e14 Mon Sep 17 00:00:00 2001 From: Julien Massot Date: Fri, 4 Feb 2022 09:11:39 +0100 Subject: [PATCH 13/24] rtos: zephyr: do not use deprecated symbols name Zephyr plan to remove openocd specific symbols in favour of more generic one. These generic symbols has been introduced in Zephyr 2.6. Signed-off-by: Julien Massot Change-Id: I89418c9c378fb8b8baa29763fc6f1b6e652dc7ef Reviewed-on: https://review.openocd.org/c/openocd/+/6844 Tested-by: jenkins Reviewed-by: Stephanos Ioannidis Reviewed-by: Antonio Borneo --- src/rtos/zephyr.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rtos/zephyr.c b/src/rtos/zephyr.c index 630511636..7f3325fea 100644 --- a/src/rtos/zephyr.c +++ b/src/rtos/zephyr.c @@ -375,15 +375,15 @@ static const struct symbol_table_elem zephyr_symbol_list[] = { .optional = false }, { - .symbol_name = "_kernel_openocd_offsets", + .symbol_name = "_kernel_thread_info_offsets", .optional = false }, { - .symbol_name = "_kernel_openocd_size_t_size", + .symbol_name = "_kernel_thread_info_size_t_size", .optional = false }, { - .symbol_name = "_kernel_openocd_num_offsets", + .symbol_name = "_kernel_thread_info_num_offsets", .optional = true }, { From f2b4897773a1c9db185dfb61d474055559fd507a Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Tue, 16 Nov 2021 12:23:48 +0100 Subject: [PATCH 14/24] flash/stm32f1x: add support for RISC-V GigaDevice GD32VF103 The device has compatible flash macro with STM32F1 family, reuse stm32f1x driver code. Detect non-ARM target - for simplicy test target type name 'riscv' and the address has 32 bits. In case of RISC-V CPU use simple chunked write algo - async algo cannot be used as the core implemented in this device doesn't allow memory access while running. Change-Id: Ie3886fbd8573652691f91a02335812a7300689f7 Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/6704 Tested-by: jenkins Reviewed-by: Tim Newsome --- contrib/loaders/flash/gd32vf103/Makefile | 28 +++ contrib/loaders/flash/gd32vf103/gd32vf103.c | 33 +++ contrib/loaders/flash/gd32vf103/gd32vf103.inc | 4 + doc/openocd.texi | 1 + src/flash/nor/stm32f1x.c | 205 ++++++++++++++---- 5 files changed, 227 insertions(+), 44 deletions(-) create mode 100644 contrib/loaders/flash/gd32vf103/Makefile create mode 100644 contrib/loaders/flash/gd32vf103/gd32vf103.c create mode 100644 contrib/loaders/flash/gd32vf103/gd32vf103.inc diff --git a/contrib/loaders/flash/gd32vf103/Makefile b/contrib/loaders/flash/gd32vf103/Makefile new file mode 100644 index 000000000..2c34e08c0 --- /dev/null +++ b/contrib/loaders/flash/gd32vf103/Makefile @@ -0,0 +1,28 @@ +BIN2C = ../../../../src/helper/bin2char.sh + +CROSS_COMPILE ?= riscv-none-embed- + +CC=$(CROSS_COMPILE)gcc +OBJCOPY=$(CROSS_COMPILE)objcopy +OBJDUMP=$(CROSS_COMPILE)objdump + +CFLAGS = -march=rv32i -mabi=ilp32 -static -nostartfiles -nostdlib -Os -g -fPIC + +all: gd32vf103.inc + +.PHONY: clean + +%.elf: %.c + $(CC) $(CFLAGS) $< -o $@ + +%.lst: %.elf + $(OBJDUMP) -S $< > $@ + +%.bin: %.elf + $(OBJCOPY) -Obinary $< $@ + +%.inc: %.bin + $(BIN2C) < $< > $@ + +clean: + -rm -f *.elf *.lst *.bin *.inc diff --git a/contrib/loaders/flash/gd32vf103/gd32vf103.c b/contrib/loaders/flash/gd32vf103/gd32vf103.c new file mode 100644 index 000000000..69225a026 --- /dev/null +++ b/contrib/loaders/flash/gd32vf103/gd32vf103.c @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include + +#define FLASH_BSY (1 << 0) +#define FLASH_PGERR (1 << 2) +#define FLASH_WRPRTERR (1 << 4) + +void flash_write(volatile uint32_t *flash_sr, + uint32_t hwords_count, + uint16_t *buffer, + uint16_t *target_addr) __attribute__((naked)); + +void flash_write(volatile uint32_t *flash_sr, + uint32_t hwords_count, + uint16_t *buffer, + uint16_t *target_addr) +{ + do { + *target_addr = *buffer++; + + register uint32_t sr; + do { + sr = *flash_sr; + } while (sr & FLASH_BSY); + + if (sr & (FLASH_PGERR | FLASH_WRPRTERR)) + break; + + target_addr++; + } while (--hwords_count); + asm("ebreak"); +} diff --git a/contrib/loaders/flash/gd32vf103/gd32vf103.inc b/contrib/loaders/flash/gd32vf103/gd32vf103.inc new file mode 100644 index 000000000..05eabff21 --- /dev/null +++ b/contrib/loaders/flash/gd32vf103/gd32vf103.inc @@ -0,0 +1,4 @@ +/* Autogenerated with ../../../../src/helper/bin2char.sh */ +0x83,0x57,0x06,0x00,0x13,0x06,0x26,0x00,0x23,0x90,0xf6,0x00,0x83,0x27,0x05,0x00, +0x13,0xf7,0x17,0x00,0xe3,0x1c,0x07,0xfe,0x93,0xf7,0x47,0x01,0x63,0x98,0x07,0x00, +0x93,0x85,0xf5,0xff,0x93,0x86,0x26,0x00,0xe3,0x9c,0x05,0xfc,0x73,0x00,0x10,0x00, diff --git a/doc/openocd.texi b/doc/openocd.texi index 121873522..d55002733 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -7293,6 +7293,7 @@ applied to all of them. All members of the STM32F0, STM32F1 and STM32F3 microcontroller families from STMicroelectronics and all members of the GD32F1x0, GD32F3x0 and GD32E23x microcontroller families from GigaDevice include internal flash and use ARM Cortex-M0/M3/M4/M23 cores. +The driver also works with GD32VF103 powered by RISC-V core. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c index 8e66af368..dea8df759 100644 --- a/src/flash/nor/stm32f1x.c +++ b/src/flash/nor/stm32f1x.c @@ -26,6 +26,8 @@ #include "config.h" #endif +#include + #include "imp.h" #include #include @@ -129,7 +131,6 @@ struct stm32x_flash_bank { }; static int stm32x_mass_erase(struct flash_bank *bank); -static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id); static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t address, uint32_t hwords_count); @@ -550,6 +551,109 @@ static int stm32x_write_block_async(struct flash_bank *bank, const uint8_t *buff return retval; } +static int stm32x_write_block_riscv(struct flash_bank *bank, const uint8_t *buffer, + uint32_t address, uint32_t hwords_count) +{ + struct target *target = bank->target; + uint32_t buffer_size; + struct working_area *write_algorithm; + struct working_area *source; + static const uint8_t gd32vf103_flash_write_code[] = { +#include "../../../contrib/loaders/flash/gd32vf103/gd32vf103.inc" + }; + + /* flash write code */ + if (target_alloc_working_area(target, sizeof(gd32vf103_flash_write_code), + &write_algorithm) != ERROR_OK) { + LOG_WARNING("no working area available, can't do block memory writes"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + int retval = target_write_buffer(target, write_algorithm->address, + sizeof(gd32vf103_flash_write_code), gd32vf103_flash_write_code); + if (retval != ERROR_OK) { + target_free_working_area(target, write_algorithm); + return retval; + } + + /* memory buffer */ + buffer_size = target_get_working_area_avail(target); + buffer_size = MIN(hwords_count * 2, MAX(buffer_size, 256)); + + retval = target_alloc_working_area(target, buffer_size, &source); + /* Allocated size is always word aligned */ + if (retval != ERROR_OK) { + target_free_working_area(target, write_algorithm); + LOG_WARNING("no large enough working area available, can't do block memory writes"); + /* target_alloc_working_area() may return ERROR_FAIL if area backup fails: + * convert any error to ERROR_TARGET_RESOURCE_NOT_AVAILABLE + */ + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + struct reg_param reg_params[4]; + + init_reg_param(®_params[0], "a0", 32, PARAM_OUT); /* poiner to FLASH_SR */ + init_reg_param(®_params[1], "a1", 32, PARAM_OUT); /* count (halfword-16bit) */ + init_reg_param(®_params[2], "a2", 32, PARAM_OUT); /* buffer start */ + init_reg_param(®_params[3], "a3", 32, PARAM_IN_OUT); /* target address */ + + while (hwords_count > 0) { + uint32_t thisrun_hwords = source->size / 2; + + /* Limit to the amount of data we actually want to write */ + if (thisrun_hwords > hwords_count) + thisrun_hwords = hwords_count; + + /* Write data to buffer */ + retval = target_write_buffer(target, source->address, + thisrun_hwords * 2, buffer); + if (retval != ERROR_OK) + break; + + buf_set_u32(reg_params[0].value, 0, 32, stm32x_get_flash_reg(bank, STM32_FLASH_SR)); + buf_set_u32(reg_params[1].value, 0, 32, thisrun_hwords); + buf_set_u32(reg_params[2].value, 0, 32, source->address); + buf_set_u32(reg_params[3].value, 0, 32, address); + + retval = target_run_algorithm(target, + 0, NULL, + ARRAY_SIZE(reg_params), reg_params, + write_algorithm->address, + write_algorithm->address + sizeof(gd32vf103_flash_write_code) - 4, + 10000, NULL); + + if (retval != ERROR_OK) { + LOG_ERROR("Failed to execute algorithm at 0x%" TARGET_PRIxADDR ": %d", + write_algorithm->address, retval); + break; + } + + /* Actually we just need to check for programming errors + * stm32x_wait_status_busy also reports error and clears status bits + */ + retval = stm32x_wait_status_busy(bank, 5); + if (retval != ERROR_OK) { + LOG_ERROR("flash write failed at address 0x%"PRIx32, + buf_get_u32(reg_params[3].value, 0, 32)); + break; + } + + /* Update counters */ + buffer += thisrun_hwords * 2; + address += thisrun_hwords * 2; + hwords_count -= thisrun_hwords; + } + + for (unsigned int i = 0; i < ARRAY_SIZE(reg_params); i++) + destroy_reg_param(®_params[i]); + + target_free_working_area(target, source); + target_free_working_area(target, write_algorithm); + + return retval; +} + /** Writes a block to flash either using target algorithm * or use fallback, host controlled halfword-by-halfword access. * Flash controller must be unlocked before this call. @@ -564,8 +668,15 @@ static int stm32x_write_block(struct flash_bank *bank, */ assert(address % 2 == 0); - /* try using a block write - on ARM architecture or... */ - int retval = stm32x_write_block_async(bank, buffer, address, hwords_count); + int retval; + struct arm *arm = target_to_arm(target); + if (is_arm(arm)) { + /* try using a block write - on ARM architecture or... */ + retval = stm32x_write_block_async(bank, buffer, address, hwords_count); + } else { + /* ... RISC-V architecture */ + retval = stm32x_write_block_riscv(bank, buffer, address, hwords_count); + } if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* if block write failed (no sufficient working area), @@ -631,11 +742,13 @@ reset_pg_and_lock: return retval; } -static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id) -{ - struct target *target = bank->target; - uint32_t device_id_register = 0; +struct stm32x_property_addr { + uint32_t device_id; + uint32_t flash_size; +}; +static int stm32x_get_property_addr(struct target *target, struct stm32x_property_addr *addr) +{ if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_TARGET_NOT_EXAMINED; @@ -643,63 +756,61 @@ static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id) switch (cortex_m_get_partno_safe(target)) { case CORTEX_M0_PARTNO: /* STM32F0x devices */ - device_id_register = 0x40015800; - break; + addr->device_id = 0x40015800; + addr->flash_size = 0x1FFFF7CC; + return ERROR_OK; case CORTEX_M3_PARTNO: /* STM32F1x devices */ - device_id_register = 0xE0042000; - break; + addr->device_id = 0xE0042000; + addr->flash_size = 0x1FFFF7E0; + return ERROR_OK; case CORTEX_M4_PARTNO: /* STM32F3x devices */ - device_id_register = 0xE0042000; - break; + addr->device_id = 0xE0042000; + addr->flash_size = 0x1FFFF7CC; + return ERROR_OK; case CORTEX_M23_PARTNO: /* GD32E23x devices */ - device_id_register = 0x40015800; - break; + addr->device_id = 0x40015800; + addr->flash_size = 0x1FFFF7E0; + return ERROR_OK; + case CORTEX_M_PARTNO_INVALID: + /* Check for GD32VF103 with RISC-V CPU */ + if (strcmp(target_type_name(target), "riscv") == 0 + && target_address_bits(target) == 32) { + /* There is nothing like arm common_magic in riscv_info_t + * check text name of target and if target is 32-bit + */ + addr->device_id = 0xE0042000; + addr->flash_size = 0x1FFFF7E0; + return ERROR_OK; + } + /* fallthrough */ default: LOG_ERROR("Cannot identify target as a stm32x"); return ERROR_FAIL; } +} - /* read stm32 device id register */ - int retval = target_read_u32(target, device_id_register, device_id); +static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id) +{ + struct target *target = bank->target; + struct stm32x_property_addr addr; + + int retval = stm32x_get_property_addr(target, &addr); if (retval != ERROR_OK) return retval; - return retval; + return target_read_u32(target, addr.device_id, device_id); } static int stm32x_get_flash_size(struct flash_bank *bank, uint16_t *flash_size_in_kb) { struct target *target = bank->target; - uint32_t flash_size_reg; + struct stm32x_property_addr addr; - if (!target_was_examined(target)) { - LOG_ERROR("Target not examined yet"); - return ERROR_TARGET_NOT_EXAMINED; - } - - switch (cortex_m_get_partno_safe(target)) { - case CORTEX_M0_PARTNO: /* STM32F0x devices */ - flash_size_reg = 0x1FFFF7CC; - break; - case CORTEX_M3_PARTNO: /* STM32F1x devices */ - flash_size_reg = 0x1FFFF7E0; - break; - case CORTEX_M4_PARTNO: /* STM32F3x devices */ - flash_size_reg = 0x1FFFF7CC; - break; - case CORTEX_M23_PARTNO: /* GD32E23x devices */ - flash_size_reg = 0x1FFFF7E0; - break; - default: - LOG_ERROR("Cannot identify target as a stm32x"); - return ERROR_FAIL; - } - - int retval = target_read_u16(target, flash_size_reg, flash_size_in_kb); + int retval = stm32x_get_property_addr(target, &addr); if (retval != ERROR_OK) return retval; - return retval; + return target_read_u16(target, addr.flash_size, flash_size_in_kb); } static int stm32x_probe(struct flash_bank *bank) @@ -790,6 +901,8 @@ static int stm32x_probe(struct flash_bank *bank) stm32x_info->user_data_offset = 16; stm32x_info->option_offset = 6; break; + case 0x1906: /* gd32vf103 */ + break; case 0x1909: /* gd32e23x */ stm32x_info->user_data_offset = 16; stm32x_info->option_offset = 6; @@ -1005,6 +1118,10 @@ static int get_stm32x_info(struct flash_bank *bank, struct command_invocation *c device_str = "GD32F3x0"; break; + case 0x1906: + device_str = "GD32VF103"; + break; + case 0x1909: /* gd32e23x */ device_str = "GD32E23x"; break; From 1c07229f8ca72e0f244e2289cefa28b65e21e774 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Wed, 17 Nov 2021 17:33:29 +0100 Subject: [PATCH 15/24] tcl/target/gd32vf103: add flash bank The flash is compatible with stm32f1x, reuse the driver. Extend the size of work area to RAM size of the smallest device. Stop watchdogs before flash programming. Change-Id: I67a7654a6e196f9d4b2409edaa7990c53334437e Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/6711 Tested-by: jenkins Reviewed-by: Tim Newsome --- tcl/target/gd32vf103.cfg | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tcl/target/gd32vf103.cfg b/tcl/target/gd32vf103.cfg index 0f4dcf375..cfc64783f 100644 --- a/tcl/target/gd32vf103.cfg +++ b/tcl/target/gd32vf103.cfg @@ -4,6 +4,8 @@ # https://www.gigadevice.com/products/microcontrollers/gd32/risc-v/ # +source [find mem_helper.tcl] + transport select jtag if { [info exists CHIPNAME] } { @@ -12,10 +14,11 @@ if { [info exists CHIPNAME] } { set _CHIPNAME gd32vf103 } +# The smallest RAM size 6kB (GD32VF103C4/T4/R4) if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { - set _WORKAREASIZE 0x800 + set _WORKAREASIZE 0x1800 } jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x1000563d @@ -24,3 +27,14 @@ set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME riscv -chain-position $_TARGETNAME $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +set _FLASHNAME $_CHIPNAME.flash +flash bank $_FLASHNAME stm32f1x 0x08000000 0 0 0 $_TARGETNAME + +# DBGMCU_CR register cannot be set in examine-end event as the running RISC-V CPU +# does not allow the debugger to access memory. +# Stop watchdogs at least before flash programming. +$_TARGETNAME configure -event reset-init { + # DBGMCU_CR |= DBG_WWDG_STOP | DBG_IWDG_STOP + mmw 0xE0042004 0x00000300 0 +} From 9de084e0067a86b8040f8ea2c3f46dff0b9e6a70 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Tue, 30 Nov 2021 10:33:41 +0100 Subject: [PATCH 16/24] flash/nor/stm32f1x: add can_load_options flag for GD32F1x0, F3x0 and E23x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to GigaDevice user manuals the devices have OBRLD bit in FMC_CTL register which is functionally compatible with OBL_LAUNCH @ FLASH_CR of STM32 counterparts. Change-Id: I84d231b38815fcb6452fd73b9153b269cce3b737 Signed-off-by: Tomas Vanek Reviewed-on: https://review.openocd.org/c/openocd/+/6759 Tested-by: jenkins Reviewed-by: Andrzej Sierżęga --- src/flash/nor/stm32f1x.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c index dea8df759..c750ff080 100644 --- a/src/flash/nor/stm32f1x.c +++ b/src/flash/nor/stm32f1x.c @@ -896,10 +896,12 @@ static int stm32x_probe(struct flash_bank *bank) stm32x_info->user_data_offset = 16; stm32x_info->option_offset = 6; max_flash_size_in_kb = 64; + stm32x_info->can_load_options = true; break; case 0x1704: /* gd32f3x0 */ stm32x_info->user_data_offset = 16; stm32x_info->option_offset = 6; + stm32x_info->can_load_options = true; break; case 0x1906: /* gd32vf103 */ break; @@ -907,6 +909,7 @@ static int stm32x_probe(struct flash_bank *bank) stm32x_info->user_data_offset = 16; stm32x_info->option_offset = 6; max_flash_size_in_kb = 64; + stm32x_info->can_load_options = true; break; } break; From 20adf85f3484ee7137f2c11a491a6929b342d1f5 Mon Sep 17 00:00:00 2001 From: Steve Marple Date: Tue, 12 Apr 2022 18:25:40 +0100 Subject: [PATCH 17/24] linuxgpiod: add SWDIO buffer The SWDIO buffer requires a direction pin to select input or output direction. Output is selected by a high logic level (matches bcm2835gpio driver). Change-Id: I240cb99a5dfea08121bb33d4b5e2108ce7597468 Signed-off-by: Steve Marple Reviewed-on: https://review.openocd.org/c/openocd/+/6936 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/jtag/drivers/linuxgpiod.c | 47 +++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/jtag/drivers/linuxgpiod.c b/src/jtag/drivers/linuxgpiod.c index 9f9f27a9f..288035f2e 100644 --- a/src/jtag/drivers/linuxgpiod.c +++ b/src/jtag/drivers/linuxgpiod.c @@ -27,6 +27,7 @@ static int trst_gpio = -1; static int srst_gpio = -1; static int swclk_gpio = -1; static int swdio_gpio = -1; +static int swdio_dir_gpio = -1; static int led_gpio = -1; static int gpiochip = -1; static int tck_gpiochip = -1; @@ -37,6 +38,7 @@ static int trst_gpiochip = -1; static int srst_gpiochip = -1; static int swclk_gpiochip = -1; static int swdio_gpiochip = -1; +static int swdio_dir_gpiochip = -1; static int led_gpiochip = -1; static struct gpiod_chip *gpiod_chip_tck; @@ -47,6 +49,7 @@ static struct gpiod_chip *gpiod_chip_trst; static struct gpiod_chip *gpiod_chip_srst; static struct gpiod_chip *gpiod_chip_swclk; static struct gpiod_chip *gpiod_chip_swdio; +static struct gpiod_chip *gpiod_chip_swdio_dir; static struct gpiod_chip *gpiod_chip_led; static struct gpiod_line *gpiod_tck; @@ -56,6 +59,7 @@ static struct gpiod_line *gpiod_tdo; static struct gpiod_line *gpiod_trst; static struct gpiod_line *gpiod_swclk; static struct gpiod_line *gpiod_swdio; +static struct gpiod_line *gpiod_swdio_dir; static struct gpiod_line *gpiod_srst; static struct gpiod_line *gpiod_led; @@ -63,6 +67,7 @@ static int last_swclk; static int last_swdio; static bool last_stored; static bool swdio_input; +static bool swdio_dir_is_active_high = true; /* Bitbang interface read of TDO */ static bb_value_t linuxgpiod_read(void) @@ -152,6 +157,11 @@ static void linuxgpiod_swdio_drive(bool is_output) gpiod_line_release(gpiod_swdio); if (is_output) { + if (gpiod_swdio_dir) { + retval = gpiod_line_set_value(gpiod_swdio_dir, swdio_dir_is_active_high ? 1 : 0); + if (retval < 0) + LOG_WARNING("Fail set swdio_dir"); + } retval = gpiod_line_request_output(gpiod_swdio, "OpenOCD", 1); if (retval < 0) LOG_WARNING("Fail request_output line swdio"); @@ -159,6 +169,11 @@ static void linuxgpiod_swdio_drive(bool is_output) retval = gpiod_line_request_input(gpiod_swdio, "OpenOCD"); if (retval < 0) LOG_WARNING("Fail request_input line swdio"); + if (gpiod_swdio_dir) { + retval = gpiod_line_set_value(gpiod_swdio_dir, swdio_dir_is_active_high ? 0 : 1); + if (retval < 0) + LOG_WARNING("Fail set swdio_dir"); + } } last_stored = false; @@ -297,6 +312,8 @@ static int linuxgpiod_quit(void) gpiod_chip_close(gpiod_chip_srst); if (gpiod_chip_swdio != NULL) gpiod_chip_close(gpiod_chip_swdio); + if (gpiod_chip_swdio_dir != NULL) + gpiod_chip_close(gpiod_chip_swdio_dir); if (gpiod_chip_swclk != NULL) gpiod_chip_close(gpiod_chip_swclk); if (gpiod_chip_trst != NULL) @@ -451,10 +468,26 @@ static int linuxgpiod_init(void) goto out_error; } + if (is_gpio_valid(swdio_dir_gpio)) { + gpiod_chip_swdio_dir = gpiod_chip_open_by_number(swdio_dir_gpiochip); + if (!gpiod_chip_swdio_dir) { + LOG_ERROR("Cannot open LinuxGPIOD swdio_dir_gpiochip %d", swdio_dir_gpiochip); + goto out_error; + } + } + gpiod_swclk = helper_get_output_line("swclk", gpiod_chip_swclk, swclk_gpio, 1); if (!gpiod_swclk) goto out_error; + /* Set buffer direction before making SWDIO an output */ + if (is_gpio_valid(swdio_dir_gpio)) { + gpiod_swdio_dir = helper_get_output_line("swdio_dir", gpiod_chip_swdio_dir, swdio_dir_gpio, + swdio_dir_is_active_high ? 1 : 0); + if (!gpiod_swdio_dir) + goto out_error; + } + gpiod_swdio = helper_get_output_line("swdio", gpiod_chip_swdio, swdio_gpio, 1); if (!gpiod_swdio) goto out_error; @@ -593,6 +626,12 @@ COMMAND_HANDLER(linuxgpiod_handle_swd_gpionum_swdio) &swdio_gpio); } +COMMAND_HANDLER(linuxgpiod_handle_swd_gpionum_swdio_dir) +{ + return CALL_COMMAND_HANDLER(linuxgpiod_helper_gpionum, "swdio_dir", &swdio_dir_gpiochip, + &swdio_dir_gpio); +} + COMMAND_HANDLER(linuxgpiod_handle_gpionum_led) { return CALL_COMMAND_HANDLER(linuxgpiod_helper_gpionum, "led", &led_gpiochip, @@ -611,6 +650,7 @@ COMMAND_HANDLER(linuxgpiod_handle_gpiochip) srst_gpiochip = gpiochip; swclk_gpiochip = gpiochip; swdio_gpiochip = gpiochip; + swdio_dir_gpiochip = gpiochip; led_gpiochip = gpiochip; } @@ -689,6 +729,13 @@ static const struct command_registration linuxgpiod_subcommand_handlers[] = { .help = "gpio chip number (optional) and gpio number for swdio.", .usage = "[chip] swdio", }, + { + .name = "swdio_dir_num", + .handler = linuxgpiod_handle_swd_gpionum_swdio_dir, + .mode = COMMAND_CONFIG, + .help = "gpio chip number (optional) and gpio number for swdio_dir.", + .usage = "[chip] swdio_dir", + }, { .name = "led_num", .handler = linuxgpiod_handle_gpionum_led, From 9eddc21a585a813d7675d9d4ad07c5d8c97dee9b Mon Sep 17 00:00:00 2001 From: Steve Marple Date: Tue, 19 Apr 2022 23:29:55 +0100 Subject: [PATCH 18/24] bcm2835gpio: Make buffer an output before the GPIO connected to it The correct ordering is required to prevent two outputs connected together. Change-Id: I634a9ca7e0ccf337d1723011b8aee1f2d81efbcf Signed-off-by: Steve Marple Reviewed-on: https://review.openocd.org/c/openocd/+/6937 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/jtag/drivers/bcm2835gpio.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/jtag/drivers/bcm2835gpio.c b/src/jtag/drivers/bcm2835gpio.c index fd6c28b96..b7a4d998c 100644 --- a/src/jtag/drivers/bcm2835gpio.c +++ b/src/jtag/drivers/bcm2835gpio.c @@ -565,6 +565,13 @@ static int bcm2835gpio_init(void) } if (transport_is_swd()) { + /* Make buffer an output before the GPIO connected to it */ + if (swdio_dir_gpio != -1) { + swdio_dir_gpio_mode = MODE_GPIO(swdio_dir_gpio); + GPIO_SET = 1 << swdio_dir_gpio; + OUT_GPIO(swdio_dir_gpio); + } + swclk_gpio_mode = MODE_GPIO(swclk_gpio); swdio_gpio_mode = MODE_GPIO(swdio_gpio); @@ -580,12 +587,6 @@ static int bcm2835gpio_init(void) OUT_GPIO(srst_gpio); } - if (swdio_dir_gpio != -1) { - swdio_dir_gpio_mode = MODE_GPIO(swdio_dir_gpio); - GPIO_SET = 1 << swdio_dir_gpio; - OUT_GPIO(swdio_dir_gpio); - } - LOG_DEBUG("saved pinmux settings: tck %d tms %d tdi %d " "tdo %d trst %d srst %d", tck_gpio_mode, tms_gpio_mode, tdi_gpio_mode, tdo_gpio_mode, trst_gpio_mode, srst_gpio_mode); From 8789513fa94ff54f08eaffedce0cc6c38f44311d Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Sat, 23 Apr 2022 13:13:06 +0200 Subject: [PATCH 19/24] target/arm_cti: Fix error handling in 'cti create' Handle JIM_CONTINUE return value of adiv5_jim_mem_ap_spot_configure(), otherwise OpenOCD silently quits when an unknown option is provided. Change-Id: I9b1351c0911e74999d8dd1260ede9760088510d7 Signed-off-by: Marc Schink Reviewed-on: https://review.openocd.org/c/openocd/+/6944 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/arm_cti.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/target/arm_cti.c b/src/target/arm_cti.c index c776e9c2a..96927bf94 100644 --- a/src/target/arm_cti.c +++ b/src/target/arm_cti.c @@ -435,8 +435,13 @@ static int cti_configure(struct jim_getopt_info *goi, struct arm_cti *cti) /* parse config or cget options ... */ while (goi->argc > 0) { int e = adiv5_jim_mem_ap_spot_configure(&cti->spot, goi); + + if (e == JIM_CONTINUE) + Jim_SetResultFormatted(goi->interp, "unknown option '%s'", + Jim_String(goi->argv[0])); + if (e != JIM_OK) - return e; + return JIM_ERR; } if (!cti->spot.dap) { From 12d1ad0c75298d56827debcacc83c679bfbe9ac2 Mon Sep 17 00:00:00 2001 From: fatalc Date: Mon, 25 Apr 2022 12:06:10 +0800 Subject: [PATCH 20/24] target/disassembler: update capstone include path to on macos (homebrew base) `pkg-config --cflags capstone` output with `-I/opt/homebrew/Cellar/capstone/4.0.2/include/capstone` gcc not find headers on parent "include" path, causes build error `fatal error: 'capstone/capstone.h' file not found` it's ok to change to for all platforms. Signed-off-by: fatalc Change-Id: Ia2e2058024d4fc1a57a8b4ea847c664d74f67efb Reviewed-on: https://review.openocd.org/c/openocd/+/6946 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/target/a64_disassembler.c | 2 +- src/target/arm_disassembler.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/target/a64_disassembler.c b/src/target/a64_disassembler.c index bd78129dd..58ddf603e 100644 --- a/src/target/a64_disassembler.c +++ b/src/target/a64_disassembler.c @@ -26,7 +26,7 @@ #if HAVE_CAPSTONE -#include +#include static void print_opcode(struct command_invocation *cmd, const cs_insn *insn) { diff --git a/src/target/arm_disassembler.c b/src/target/arm_disassembler.c index 661859379..d3d27a93c 100644 --- a/src/target/arm_disassembler.c +++ b/src/target/arm_disassembler.c @@ -27,7 +27,7 @@ #include #if HAVE_CAPSTONE -#include +#include #endif /* From 66335683fec62ac89da48d64932fd9d082314225 Mon Sep 17 00:00:00 2001 From: jihongbin Date: Fri, 29 Apr 2022 17:03:15 +0800 Subject: [PATCH 21/24] drivers/cmsis-dap: Correct the DAP protocol parameter parsing error Fixes: 01030fb89354 (drivers/cmsis-dap: tidy up buffer access) Change-Id: Id192d3930a89980d641058b6444d12caec19ce6f Signed-off-by: Hongbin Ji Reviewed-on: https://review.openocd.org/c/openocd/+/6954 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Antonio Borneo Reviewed-by: jihongbin --- src/jtag/drivers/cmsis_dap.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/jtag/drivers/cmsis_dap.c b/src/jtag/drivers/cmsis_dap.c index 63407be42..eaa65abc6 100644 --- a/src/jtag/drivers/cmsis_dap.c +++ b/src/jtag/drivers/cmsis_dap.c @@ -1405,18 +1405,18 @@ static void debug_parse_cmsis_buf(const uint8_t *cmd, int cmdlen) for (int i = 0; i < cmdlen; ++i) printf(" %02x", cmd[i]); printf("\n"); - switch (cmd[1]) { + switch (cmd[0]) { case CMD_DAP_JTAG_SEQ: { - printf("cmsis-dap jtag sequence command %02x (n=%d)\n", cmd[1], cmd[2]); + printf("cmsis-dap jtag sequence command %02x (n=%d)\n", cmd[0], cmd[1]); /* - * #2 = number of sequences - * #3 = sequence info 1 - * #4...4+n_bytes-1 = sequence 1 + * #1 = number of sequences + * #2 = sequence info 1 + * #3...4+n_bytes-1 = sequence 1 * #4+n_bytes = sequence info 2 * #5+n_bytes = sequence 2 (single bit) */ - int pos = 3; - for (int seq = 0; seq < cmd[2]; ++seq) { + int pos = 2; + for (int seq = 0; seq < cmd[1]; ++seq) { uint8_t info = cmd[pos++]; int len = info & DAP_JTAG_SEQ_TCK; if (len == 0) From 8e1064f1fec5b15957c552526c49f42c41be5b6d Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 3 May 2022 13:44:25 -0700 Subject: [PATCH 22/24] Remove gd32vf103 flash driver. Per mainline, use stm32f1x instead. Tested that this is working. Change-Id: Icda4b2a39e06e2adf9bbfb984bd578347f43d7d1 Signed-off-by: Tim Newsome --- src/flash/nor/Makefile.am | 1 - src/flash/nor/drivers.c | 2 - src/flash/nor/gd32vf103.c | 1344 ------------------------------------- 3 files changed, 1347 deletions(-) delete mode 100644 src/flash/nor/gd32vf103.c diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index a09174448..a5ef42210 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -66,7 +66,6 @@ NOR_DRIVERS = \ %D%/stm32lx.c \ %D%/stm32l4x.c \ %D%/stm32h7x.c \ - %D%/gd32vf103.c \ %D%/str7x.c \ %D%/str9x.c \ %D%/str9xpec.c \ diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index dc966ed94..3e35c0954 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -44,7 +44,6 @@ extern const struct flash_driver faux_flash; extern const struct flash_driver fm3_flash; extern const struct flash_driver fm4_flash; extern const struct flash_driver fespi_flash; -extern const struct flash_driver gd32vf103_flash; extern const struct flash_driver jtagspi_flash; extern const struct flash_driver kinetis_flash; extern const struct flash_driver kinetis_ke_flash; @@ -153,7 +152,6 @@ static const struct flash_driver * const flash_drivers[] = { &stm32lx_flash, &stm32l4x_flash, &stm32h7x_flash, - &gd32vf103_flash, &stmsmi_flash, &stmqspi_flash, &str7x_flash, diff --git a/src/flash/nor/gd32vf103.c b/src/flash/nor/gd32vf103.c deleted file mode 100644 index 562f41e7b..000000000 --- a/src/flash/nor/gd32vf103.c +++ /dev/null @@ -1,1344 +0,0 @@ -/*************************************************************************** - * - * 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 * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see . * - ***************************************************************************/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "imp.h" -#include -#include - -/* gd32vf103 register locations */ - -#define FLASH_REG_BASE_B0 0x40022000 -#define FLASH_REG_BASE_B1 0x40022040 - -#define FMC_WS 0x00 -#define FMC_KEY 0x04 -#define FMC_OBKEY 0x08 -#define FMC_STAT 0x0C -#define FMC_CTL 0x10 -#define FMC_ADDR 0x14 -#define FMC_OBSTAT 0x1C - -/* TODO: Check if code using these really should be hard coded to bank 0. - * There are valid cases, on dual flash devices the protection of the - * second bank is done on the bank0 reg's. */ -#define FMC_WS_B0 0x40022000 -#define FMC_KEY_B0 0x40022004 -#define FMC_OBKEY_B0 0x40022008 -#define FMC_STAT_B0 0x4002200C -#define FMC_CTL_B0 0x40022010 -#define FMC_ADDR_B0 0x40022014 -#define FMC_OBSTAT_B0 0x4002201C -#define FMC_WP_B0 0x40022020 - -/* option byte location */ - -#define FMC_OB_RDP 0x1FFFF800 - -/* FMC_CTL register bits */ - -#define FMC_CTL_PG (1 << 0) -#define FMC_CTL_PER (1 << 1) -#define FMC_CTL_MER (1 << 2) -#define FMC_CTL_OBPG (1 << 4) -#define FMC_CTL_OBER (1 << 5) -#define FMC_CTL_START (1 << 6) -#define FMC_CTL_LK (1 << 7) -#define FMC_CTL_OBWEN (1 << 9) - -/* FMC_STAT register bits */ - -#define FMC_STAT_BUSY (1 << 0) -#define FMC_STAT_PGERR (1 << 2) -#define FMC_STAT_WPERR (1 << 4) -#define FMC_STAT_ENDF (1 << 5) - -/* FMC_OBSTAT bit definitions (reading) */ - -#define FMC_OBSTAT_OBERR 0 -#define FMC_OBSTAT_SPC 1 -#define FMC_OBSTAT_WDG_SW 2 -#define FMC_OBSTAT_RST_DSLEEP 3 -#define FMC_OBSTAT_RST_STDBY 4 -#define FMC_OBSTAT_BB 5 /* dual flash bank only */ - -/* register unlock keys */ - -#define UNLOCK_KEY0 0x45670123 -#define UNLOCK_KEY1 0xCDEF89AB - -/* timeout values */ - -#define FLASH_WRITE_TIMEOUT 500 -#define FLASH_ERASE_TIMEOUT 5000 - -struct gd32vf103_options { - uint16_t RDP; - uint16_t user_options; - uint16_t user_data; - uint16_t protection[4]; -}; - -struct gd32vf103_flash_bank { - struct gd32vf103_options option_bytes; - int ppage_size; - int probed; - - bool has_dual_banks; - /* used to access dual flash bank gd32vf103 */ - uint32_t register_base; - uint16_t default_rdp; - int user_data_offset; - int option_offset; - uint32_t user_bank_size; -}; - -static int gd32vf103_mass_erase(struct flash_bank *bank); -static int get_gd32vf103_info(struct flash_bank *bank, struct command_invocation *cmd); -static int gd32vf103_write_block(struct flash_bank *bank, const uint8_t *buffer, - uint32_t offset, uint32_t count); - -/* flash bank gd32vf103 0 0 - */ -FLASH_BANK_COMMAND_HANDLER(gd32vf103_flash_bank_command) -{ - struct gd32vf103_flash_bank *gd32vf103_info; - - if (CMD_ARGC < 6) - return ERROR_COMMAND_SYNTAX_ERROR; - - gd32vf103_info = malloc(sizeof(struct gd32vf103_flash_bank)); - - bank->driver_priv = gd32vf103_info; - gd32vf103_info->probed = 0; - gd32vf103_info->has_dual_banks = false; - gd32vf103_info->register_base = FLASH_REG_BASE_B0; - gd32vf103_info->user_bank_size = bank->size; - - return ERROR_OK; -} - -static inline int gd32vf103_get_flash_reg(struct flash_bank *bank, uint32_t reg) -{ - struct gd32vf103_flash_bank *gd32vf103_info = bank->driver_priv; - return reg + gd32vf103_info->register_base; -} - -static inline int gd32vf103_get_flash_status(struct flash_bank *bank, uint32_t *status) -{ - struct target *target = bank->target; - return target_read_u32(target, gd32vf103_get_flash_reg(bank, FMC_STAT), status); -} - -static int gd32vf103_wait_status_busy(struct flash_bank *bank, int timeout) -{ - struct target *target = bank->target; - uint32_t status; - int retval = ERROR_OK; - - /* wait for busy to clear */ - for (;;) { - retval = gd32vf103_get_flash_status(bank, &status); - if (retval != ERROR_OK) - return retval; - LOG_DEBUG("status: 0x%" PRIx32 "", status); - if ((status & FMC_STAT_BUSY) == 0) - break; - if (timeout-- <= 0) { - LOG_ERROR("timed out waiting for flash"); - return ERROR_FAIL; - } - alive_sleep(1); - } - - if (status & FMC_STAT_WPERR) { - LOG_ERROR("gd32vf103 device protected"); - retval = ERROR_FAIL; - } - - if (status & FMC_STAT_PGERR) { - LOG_ERROR("gd32vf103 device programming failed"); - retval = ERROR_FAIL; - } - - /* Clear but report errors */ - if (status & (FMC_STAT_WPERR | FMC_STAT_PGERR)) { - /* If this operation fails, we ignore it and report the original - * retval - */ - target_write_u32(target, gd32vf103_get_flash_reg(bank, FMC_STAT), - FMC_STAT_WPERR | FMC_STAT_PGERR); - } - return retval; -} - -static int gd32vf103_check_operation_supported(struct flash_bank *bank) -{ - struct gd32vf103_flash_bank *gd32vf103_info = bank->driver_priv; - - /* if we have a dual flash bank device then - * we need to perform option byte stuff on bank0 only */ - if (gd32vf103_info->register_base != FLASH_REG_BASE_B0) { - LOG_ERROR("Option Byte Operation's must use bank0"); - return ERROR_FLASH_OPERATION_FAILED; - } - - return ERROR_OK; -} - -static int gd32vf103_read_options(struct flash_bank *bank) -{ - uint32_t optiondata; - struct gd32vf103_flash_bank *gd32vf103_info = NULL; - struct target *target = bank->target; - - gd32vf103_info = bank->driver_priv; - - /* read current option bytes */ - int retval = target_read_u32(target, FMC_OBSTAT_B0, &optiondata); - if (retval != ERROR_OK) - return retval; - - gd32vf103_info->option_bytes.user_options = (optiondata >> gd32vf103_info->option_offset >> 2) & 0xffff; - gd32vf103_info->option_bytes.user_data = (optiondata >> gd32vf103_info->user_data_offset) & 0xffff; - gd32vf103_info->option_bytes.RDP = (optiondata & (1 << FMC_OBSTAT_SPC)) ? 0xFFFF : 0x5AA5; - - if (optiondata & (1 << FMC_OBSTAT_SPC)) - LOG_INFO("Device Security Bit Set"); - - /* each bit refers to a 4bank protection */ - retval = target_read_u32(target, FMC_WP_B0, &optiondata); - if (retval != ERROR_OK) - return retval; - - gd32vf103_info->option_bytes.protection[0] = (uint16_t)optiondata; - gd32vf103_info->option_bytes.protection[1] = (uint16_t)(optiondata >> 8); - gd32vf103_info->option_bytes.protection[2] = (uint16_t)(optiondata >> 16); - gd32vf103_info->option_bytes.protection[3] = (uint16_t)(optiondata >> 24); - - return ERROR_OK; -} - -static int gd32vf103_erase_options(struct flash_bank *bank) -{ - struct gd32vf103_flash_bank *gd32vf103_info = NULL; - struct target *target = bank->target; - - gd32vf103_info = bank->driver_priv; - - /* read current options */ - gd32vf103_read_options(bank); - - /* unlock flash registers */ - int retval = target_write_u32(target, FMC_KEY_B0, UNLOCK_KEY0); - if (retval != ERROR_OK) - return retval; - - retval = target_write_u32(target, FMC_KEY_B0, UNLOCK_KEY1); - if (retval != ERROR_OK) - return retval; - - /* unlock option flash registers */ - retval = target_write_u32(target, FMC_OBKEY_B0, UNLOCK_KEY0); - if (retval != ERROR_OK) - return retval; - retval = target_write_u32(target, FMC_OBKEY_B0, UNLOCK_KEY1); - if (retval != ERROR_OK) - return retval; - - /* erase option bytes */ - retval = target_write_u32(target, FMC_CTL_B0, FMC_CTL_OBER | FMC_CTL_OBWEN); - if (retval != ERROR_OK) - return retval; - retval = target_write_u32(target, FMC_CTL_B0, FMC_CTL_OBER | FMC_CTL_START | FMC_CTL_OBWEN); - if (retval != ERROR_OK) - return retval; - - retval = gd32vf103_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); - if (retval != ERROR_OK) - return retval; - - /* clear readout protection and complementary option bytes - * this will also force a device unlock if set */ - gd32vf103_info->option_bytes.RDP = gd32vf103_info->default_rdp; - - return ERROR_OK; -} - -static int gd32vf103_write_options(struct flash_bank *bank) -{ - struct gd32vf103_flash_bank *gd32vf103_info = NULL; - struct target *target = bank->target; - - gd32vf103_info = bank->driver_priv; - - /* unlock flash registers */ - int retval = target_write_u32(target, FMC_KEY_B0, UNLOCK_KEY0); - if (retval != ERROR_OK) - return retval; - retval = target_write_u32(target, FMC_KEY_B0, UNLOCK_KEY1); - if (retval != ERROR_OK) - return retval; - - /* unlock option flash registers */ - retval = target_write_u32(target, FMC_OBKEY_B0, UNLOCK_KEY0); - if (retval != ERROR_OK) - return retval; - retval = target_write_u32(target, FMC_OBKEY_B0, UNLOCK_KEY1); - if (retval != ERROR_OK) - return retval; - - /* program option bytes */ - retval = target_write_u32(target, FMC_CTL_B0, FMC_CTL_OBPG | FMC_CTL_OBWEN); - if (retval != ERROR_OK) - return retval; - - uint8_t opt_bytes[16]; - - target_buffer_set_u16(target, opt_bytes, gd32vf103_info->option_bytes.RDP); /* SPC */ - target_buffer_set_u16(target, opt_bytes + 2, gd32vf103_info->option_bytes.user_options); /* USER */ - target_buffer_set_u16(target, opt_bytes + 4, gd32vf103_info->option_bytes.user_data & 0xff); /* DATA[7:0] */ - target_buffer_set_u16(target, opt_bytes + 6, (gd32vf103_info->option_bytes.user_data >> 8) & 0xff); /* DATA[15:8] */ - target_buffer_set_u16(target, opt_bytes + 8, gd32vf103_info->option_bytes.protection[0]); /* WP[7:0] */ - target_buffer_set_u16(target, opt_bytes + 10, gd32vf103_info->option_bytes.protection[1]); /* WP[15:8] */ - target_buffer_set_u16(target, opt_bytes + 12, gd32vf103_info->option_bytes.protection[2]); /* WP[23:16] */ - target_buffer_set_u16(target, opt_bytes + 14, gd32vf103_info->option_bytes.protection[3]); /* WP[31:24] */ - - uint32_t offset = FMC_OB_RDP - bank->base; - retval = gd32vf103_write_block(bank, opt_bytes, offset, sizeof(opt_bytes) / 2); - if (retval != ERROR_OK) { - if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) - LOG_ERROR("working area required to erase options bytes"); - return retval; - } - - retval = target_write_u32(target, FMC_CTL_B0, FMC_CTL_LK); - if (retval != ERROR_OK) - return retval; - - return ERROR_OK; -} - -static int gd32vf103_protect_check(struct flash_bank *bank) -{ - struct target *target = bank->target; - struct gd32vf103_flash_bank *gd32vf103_info = bank->driver_priv; - - uint32_t protection; - int i; - int num_bits; - int set; - - int retval = gd32vf103_check_operation_supported(bank); - if (ERROR_OK != retval) - return retval; - - /* medium density - each bit refers to a 4bank protection - * high density - each bit refers to a 2bank protection */ - retval = target_read_u32(target, FMC_WP_B0, &protection); - if (retval != ERROR_OK) - return retval; - - /* medium density - each protection bit is for 4 * 1K pages - * high density - each protection bit is for 2 * 2K pages */ - num_bits = (bank->num_sectors / gd32vf103_info->ppage_size); - - if (gd32vf103_info->ppage_size == 2) { - /* high density flash/connectivity line protection */ - - set = 1; - - if (protection & (1 << 31)) - set = 0; - - /* bit 31 controls sector 62 - 255 protection for high density - * bit 31 controls sector 62 - 127 protection for connectivity line */ - for (unsigned s = 62; s < bank->num_sectors; s++) - bank->sectors[s].is_protected = set; - - if (bank->num_sectors > 61) - num_bits = 31; - - for (i = 0; i < num_bits; i++) { - set = 1; - - if (protection & (1 << i)) - set = 0; - - for (int s = 0; s < gd32vf103_info->ppage_size; s++) - bank->sectors[(i * gd32vf103_info->ppage_size) + s].is_protected = set; - } - } else { - /* low/medium density flash protection */ - for (i = 0; i < num_bits; i++) { - set = 1; - - if (protection & (1 << i)) - set = 0; - - for (int s = 0; s < gd32vf103_info->ppage_size; s++) - bank->sectors[(i * gd32vf103_info->ppage_size) + s].is_protected = set; - } - } - - return ERROR_OK; -} - -static int gd32vf103_erase(struct flash_bank *bank, unsigned first, unsigned last) -{ - struct target *target = bank->target; - uint32_t optiondata; - uint32_t obstat; - - struct gd32vf103_flash_bank *gd32vf103_info = NULL; - gd32vf103_info = bank->driver_priv; - - if (bank->target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - target_read_u32(target, FMC_WP_B0, &optiondata); - target_read_u32(target, FMC_OBSTAT_B0, &obstat); - if ((0xFFFFFFFF != optiondata) || ((obstat & 0x2) != 0)) { - gd32vf103_erase_options(bank); - optiondata = 0xFFFFFFFF; - gd32vf103_info->option_bytes.RDP = 0x5AA5; - gd32vf103_info->option_bytes.protection[0] = (uint16_t)optiondata; - gd32vf103_info->option_bytes.protection[1] = (uint16_t)(optiondata >> 8); - gd32vf103_info->option_bytes.protection[2] = (uint16_t)(optiondata >> 16); - gd32vf103_info->option_bytes.protection[3] = (uint16_t)(optiondata >> 24); - - gd32vf103_write_options(bank); - LOG_INFO(" Unlock flash Sucess !!! Pls Reset Platfrom !!\n"); - return ERROR_FAIL; - } - if ((first == 0) && (last == (bank->num_sectors - 1))) - return gd32vf103_mass_erase(bank); - - /* unlock flash registers */ - int retval = target_write_u32(target, gd32vf103_get_flash_reg(bank, FMC_KEY), UNLOCK_KEY0); - if (retval != ERROR_OK) - return retval; - retval = target_write_u32(target, gd32vf103_get_flash_reg(bank, FMC_KEY), UNLOCK_KEY1); - if (retval != ERROR_OK) - return retval; - - for (unsigned i = first; i <= last; i++) { - retval = target_write_u32(target, gd32vf103_get_flash_reg(bank, FMC_CTL), FMC_CTL_PER); - if (retval != ERROR_OK) - return retval; - retval = target_write_u32(target, gd32vf103_get_flash_reg(bank, FMC_ADDR), - bank->base + bank->sectors[i].offset); - if (retval != ERROR_OK) - return retval; - retval = target_write_u32(target, - gd32vf103_get_flash_reg(bank, FMC_CTL), FMC_CTL_PER | FMC_CTL_START); - if (retval != ERROR_OK) - return retval; - - retval = gd32vf103_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); - if (retval != ERROR_OK) - return retval; - - bank->sectors[i].is_erased = 1; - } - - retval = target_write_u32(target, gd32vf103_get_flash_reg(bank, FMC_CTL), FMC_CTL_LK); - if (retval != ERROR_OK) - return retval; - - return ERROR_OK; -} - -static int gd32vf103_protect(struct flash_bank *bank, int set, unsigned first, unsigned last) -{ - struct gd32vf103_flash_bank *gd32vf103_info = NULL; - struct target *target = bank->target; - uint16_t prot_reg[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}; - int reg, bit; - int status; - uint32_t protection; - - gd32vf103_info = bank->driver_priv; - - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - int retval = gd32vf103_check_operation_supported(bank); - if (ERROR_OK != retval) - return retval; - - if ((first % gd32vf103_info->ppage_size) != 0) { - LOG_WARNING("aligned start protect sector to a %d sector boundary", - gd32vf103_info->ppage_size); - first = first - (first % gd32vf103_info->ppage_size); - } - if (((last + 1) % gd32vf103_info->ppage_size) != 0) { - LOG_WARNING("aligned end protect sector to a %d sector boundary", - gd32vf103_info->ppage_size); - last++; - last = last - (last % gd32vf103_info->ppage_size); - last--; - } - - /* medium density - each bit refers to a 4bank protection - * high density - each bit refers to a 2bank protection */ - retval = target_read_u32(target, FMC_WP_B0, &protection); - if (retval != ERROR_OK) - return retval; - - prot_reg[0] = (uint16_t)protection; - prot_reg[1] = (uint16_t)(protection >> 8); - prot_reg[2] = (uint16_t)(protection >> 16); - prot_reg[3] = (uint16_t)(protection >> 24); - - if (gd32vf103_info->ppage_size == 2) { - /* high density flash */ - - /* bit 7 controls sector 62 - 255 protection */ - if (last > 61) { - if (set) - prot_reg[3] &= ~(1 << 7); - else - prot_reg[3] |= (1 << 7); - } - - if (first > 61) - first = 62; - if (last > 61) - last = 61; - - for (unsigned i = first; i <= last; i++) { - reg = (i / gd32vf103_info->ppage_size) / 8; - bit = (i / gd32vf103_info->ppage_size) - (reg * 8); - - if (set) - prot_reg[reg] &= ~(1 << bit); - else - prot_reg[reg] |= (1 << bit); - } - } else { - /* medium density flash */ - for (unsigned i = first; i <= last; i++) { - reg = (i / gd32vf103_info->ppage_size) / 8; - bit = (i / gd32vf103_info->ppage_size) - (reg * 8); - - if (set) - prot_reg[reg] &= ~(1 << bit); - else - prot_reg[reg] |= (1 << bit); - } - } - - status = gd32vf103_erase_options(bank); - if (status != ERROR_OK) - return status; - - gd32vf103_info->option_bytes.protection[0] = prot_reg[0]; - gd32vf103_info->option_bytes.protection[1] = prot_reg[1]; - gd32vf103_info->option_bytes.protection[2] = prot_reg[2]; - gd32vf103_info->option_bytes.protection[3] = prot_reg[3]; - - return gd32vf103_write_options(bank); -} - -static int gd32vf103_write_block(struct flash_bank *bank, const uint8_t *buffer, - uint32_t offset, uint32_t count) -{ - struct gd32vf103_flash_bank *gd32vf103_info = bank->driver_priv; - struct target *target = bank->target; - uint32_t buffer_size = 16384; - struct working_area *write_algorithm; - struct working_area *source; - uint32_t address = bank->base + offset; - struct reg_param reg_params[5]; - int retval = ERROR_OK; - - static const uint8_t gd32vf103_flash_write_code[] = { -#include "../../../contrib/loaders/flash/gd32v/gd32vf103.inc" - }; - - /* flash write code */ - if (target_alloc_working_area(target, sizeof(gd32vf103_flash_write_code), - &write_algorithm) != ERROR_OK) { - LOG_WARNING("no working area available, can't do block memory writes"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - - retval = target_write_buffer(target, write_algorithm->address, - sizeof(gd32vf103_flash_write_code), gd32vf103_flash_write_code); - if (retval != ERROR_OK) { - target_free_working_area(target, write_algorithm); - return retval; - } - - /* memory buffer */ - while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { - buffer_size /= 2; - buffer_size &= ~3UL; /* Make sure it's 4 byte aligned */ - if (buffer_size <= 256) { - /* we already allocated the writing code, but failed to get a - * buffer, free the algorithm */ - target_free_working_area(target, write_algorithm); - - LOG_WARNING("no large enough working area available, can't do block memory writes"); - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } - } - - init_reg_param(®_params[0], "a0", 32, PARAM_IN_OUT); /* flash base (in), status (out) */ - init_reg_param(®_params[1], "a1", 32, PARAM_OUT); /* count (halfword-16bit) */ - init_reg_param(®_params[2], "a2", 32, PARAM_OUT); /* buffer start */ - init_reg_param(®_params[3], "a3", 32, PARAM_OUT); /* buffer end */ - init_reg_param(®_params[4], "a4", 32, PARAM_IN_OUT); /* target address */ - - - uint32_t wp_addr = source->address; - uint32_t rp_addr = source->address + 4; - uint32_t fifo_start_addr = source->address + 8; - uint32_t fifo_end_addr = source->address + source->size; - - uint32_t wp = fifo_start_addr; - uint32_t rp = fifo_start_addr; - uint32_t thisrun_bytes = fifo_end_addr-fifo_start_addr-2; /* (2:block size) */ - - retval = target_write_u32(target, rp_addr, rp); - if (retval != ERROR_OK) - return retval; - - while (count > 0) { - retval = target_read_u32(target, rp_addr, &rp); - if (retval != ERROR_OK) { - LOG_ERROR("failed to get read pointer"); - break; - } - - if (wp != rp) { - LOG_ERROR("Failed to write flash ;; rp = 0x%x ;;; wp = 0x%x", rp, wp); - break; - } - wp = fifo_start_addr; - rp = fifo_start_addr; - retval = target_write_u32(target, rp_addr, rp); - if (retval != ERROR_OK) - break; - /* Limit to the amount of data we actually want to write */ - if (thisrun_bytes > count * 2) - thisrun_bytes = count * 2; - - /* Write data to fifo */ - retval = target_write_buffer(target, wp, thisrun_bytes, buffer); - if (retval != ERROR_OK) - break; - - /* Update counters and wrap write pointer */ - buffer += thisrun_bytes; - count -= thisrun_bytes / 2; - rp = fifo_start_addr; - wp = fifo_start_addr+thisrun_bytes; - - /* Store updated write pointer to target */ - retval = target_write_u32(target, wp_addr, wp); - if (retval != ERROR_OK) - break; - retval = target_write_u32(target, rp_addr, rp); - if (retval != ERROR_OK) - return retval; - - buf_set_u32(reg_params[0].value, 0, 32, gd32vf103_info->register_base); - buf_set_u32(reg_params[1].value, 0, 32, thisrun_bytes/2); - buf_set_u32(reg_params[2].value, 0, 32, source->address); - buf_set_u32(reg_params[3].value, 0, 32, source->address + source->size); - buf_set_u32(reg_params[4].value, 0, 32, address); - - retval = target_run_algorithm(target, 0, NULL, 5, reg_params, - write_algorithm->address, write_algorithm->address+4, - 10000, NULL); - - if (retval != ERROR_OK) { - LOG_ERROR("Failed to execute algorithm at 0x%" TARGET_PRIxADDR ": %d", - write_algorithm->address, retval); - return retval; - } - address += thisrun_bytes; - - } - - - if (retval == ERROR_FLASH_OPERATION_FAILED) { - LOG_ERROR("flash write failed at address 0x%"PRIx32, - buf_get_u32(reg_params[4].value, 0, 32)); - - if (buf_get_u32(reg_params[0].value, 0, 32) & FMC_STAT_PGERR) { - LOG_ERROR("flash memory not erased before writing"); - /* Clear but report errors */ - target_write_u32(target, gd32vf103_get_flash_reg(bank, FMC_STAT), FMC_STAT_PGERR); - } - - if (buf_get_u32(reg_params[0].value, 0, 32) & FMC_STAT_WPERR) { - LOG_ERROR("flash memory write protected"); - /* Clear but report errors */ - target_write_u32(target, gd32vf103_get_flash_reg(bank, FMC_STAT), FMC_STAT_WPERR); - } - } - - target_free_working_area(target, source); - target_free_working_area(target, write_algorithm); - - destroy_reg_param(®_params[0]); - destroy_reg_param(®_params[1]); - destroy_reg_param(®_params[2]); - destroy_reg_param(®_params[3]); - destroy_reg_param(®_params[4]); - - return retval; -} - -static int gd32vf103_write(struct flash_bank *bank, const uint8_t *buffer, - uint32_t offset, uint32_t count) -{ - struct target *target = bank->target; - uint8_t *new_buffer = NULL; - - - if (bank->target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - if (offset & 0x1) { - LOG_ERROR("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset); - return ERROR_FLASH_DST_BREAKS_ALIGNMENT; - } - - /* If there's an odd number of bytes, the data has to be padded. Duplicate - * the buffer and use the normal code path with a single block write since - * it's probably cheaper than to special case the last odd write using - * discrete accesses. */ - if (count & 1) { - new_buffer = malloc(count + 1); - if (new_buffer == NULL) { - LOG_ERROR("odd number of bytes to write and no memory for padding buffer"); - return ERROR_FAIL; - } - LOG_INFO("odd number of bytes to write, padding with 0xff"); - buffer = memcpy(new_buffer, buffer, count); - new_buffer[count++] = 0xff; - } - - uint32_t words_remaining = count / 2; - int retval, retval2; - - /* unlock flash registers */ - retval = target_write_u32(target, gd32vf103_get_flash_reg(bank, FMC_KEY), UNLOCK_KEY0); - if (retval != ERROR_OK) - goto cleanup; - retval = target_write_u32(target, gd32vf103_get_flash_reg(bank, FMC_KEY), UNLOCK_KEY1); - if (retval != ERROR_OK) - goto cleanup; - - retval = target_write_u32(target, gd32vf103_get_flash_reg(bank, FMC_CTL), FMC_CTL_PG); - if (retval != ERROR_OK) - goto cleanup; - - /* try using a block write */ - retval = gd32vf103_write_block(bank, buffer, offset, words_remaining); - - if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { - /* if block write failed (no sufficient working area), - * we use normal (slow) single halfword accesses */ - LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); - - while (words_remaining > 0) { - uint16_t value; - memcpy(&value, buffer, sizeof(uint16_t)); - - retval = target_write_u16(target, bank->base + offset, value); - if (retval != ERROR_OK) - goto reset_pg_and_lock; - - retval = gd32vf103_wait_status_busy(bank, 5); - if (retval != ERROR_OK) - goto reset_pg_and_lock; - - words_remaining--; - buffer += 2; - offset += 2; - } - } - -reset_pg_and_lock: - retval2 = target_write_u32(target, gd32vf103_get_flash_reg(bank, FMC_CTL), FMC_CTL_LK); - if (retval == ERROR_OK) - retval = retval2; - -cleanup: - if (new_buffer) - free(new_buffer); - - return retval; -} - -static int gd32vf103_get_device_id(struct flash_bank *bank, uint32_t *device_id) -{ - - struct target *target = bank->target; - uint32_t device_id_register = 0xE0042000; - /* read GD32VF103 device id register */ - int retval = target_read_u32(target, device_id_register, device_id); - if (retval != ERROR_OK) - return retval; - - return retval; -} - -static int gd32vf103_get_flash_size(struct flash_bank *bank, uint16_t *flash_size_in_kb) -{ - struct target *target = bank->target; - uint32_t flash_size_reg = 0x1FFFF7E0; - - int retval = target_read_u16(target, flash_size_reg, flash_size_in_kb); - if (retval != ERROR_OK) - return retval; - - return retval; -} - -static int gd32vf103_probe(struct flash_bank *bank) -{ - struct gd32vf103_flash_bank *gd32vf103_info = bank->driver_priv; - int i; - uint16_t flash_size_in_kb; - uint16_t max_flash_size_in_kb; - uint32_t device_id; - int page_size; - uint32_t base_address = 0x08000000; - - gd32vf103_info->probed = 0; - gd32vf103_info->register_base = FLASH_REG_BASE_B0; - gd32vf103_info->user_data_offset = 10; - gd32vf103_info->option_offset = 0; - - /* default factory protection level */ - gd32vf103_info->default_rdp = 0x5AA5; - - /* read gd32vf103 device id register */ - int retval = gd32vf103_get_device_id(bank, &device_id); - if (retval != ERROR_OK) - return retval; - - LOG_INFO("device id = 0x%08" PRIx32 "", device_id); - - /* set page size, protection granularity and max flash size depending on family */ - switch (device_id & 0xfff) { - case 0x410: - case 0x418: /* connectivity line density */ - page_size = 1024; - gd32vf103_info->ppage_size = 4; - max_flash_size_in_kb = 128; - break; - default: - LOG_WARNING("Cannot identify target as a gd32vf103 family."); - return ERROR_FAIL; - } - - /* get flash size from target. */ - retval = gd32vf103_get_flash_size(bank, &flash_size_in_kb); - LOG_INFO("flash_size_in_kb = 0x%08" PRIx32 "", flash_size_in_kb); - /* failed reading flash size or flash size invalid, default to max target family */ - if (retval != ERROR_OK || flash_size_in_kb == 0xffff || flash_size_in_kb == 0) { - LOG_WARNING("gd32vf103 flash size failed, probe inaccurate - assuming %dk flash", - max_flash_size_in_kb); - flash_size_in_kb = max_flash_size_in_kb; - } - - if (gd32vf103_info->has_dual_banks) { - /* split reported size into matching bank */ - if (bank->base != 0x08080000) { - /* bank 0 will be fixed 512k */ - flash_size_in_kb = 512; - } else { - flash_size_in_kb -= 512; - /* bank1 also uses a register offset */ - gd32vf103_info->register_base = FLASH_REG_BASE_B1; - base_address = 0x08080000; - } - } - - /* if the user sets the size manually then ignore the probed value - * this allows us to work around devices that have a invalid flash size register value */ - if (gd32vf103_info->user_bank_size) { - LOG_INFO("ignoring flash probed value, using configured bank size"); - flash_size_in_kb = gd32vf103_info->user_bank_size / 1024; - } - - LOG_INFO("flash size = %dkbytes", flash_size_in_kb); - - /* did we assign flash size? */ - assert(flash_size_in_kb != 0xffff); - - /* calculate numbers of pages */ - int num_pages = flash_size_in_kb * 1024 / page_size; - - /* check that calculation result makes sense */ - assert(num_pages > 0); - - if (bank->sectors) { - free(bank->sectors); - bank->sectors = NULL; - } - - bank->base = base_address; - bank->size = (num_pages * page_size); - bank->num_sectors = num_pages; - bank->sectors = malloc(sizeof(struct flash_sector) * num_pages); - - for (i = 0; i < num_pages; i++) { - bank->sectors[i].offset = i * page_size; - bank->sectors[i].size = page_size; - bank->sectors[i].is_erased = -1; - bank->sectors[i].is_protected = 1; - } - - gd32vf103_info->probed = 1; - - return ERROR_OK; -} - -static int gd32vf103_auto_probe(struct flash_bank *bank) -{ - struct gd32vf103_flash_bank *gd32vf103_info = bank->driver_priv; - if (gd32vf103_info->probed) - return ERROR_OK; - return gd32vf103_probe(bank); -} - -static int get_gd32vf103_info(struct flash_bank *bank, struct command_invocation *cmd) -{ - uint32_t dbgmcu_idcode; - - /* read gd32vf103 device id register */ - int retval = gd32vf103_get_device_id(bank, &dbgmcu_idcode); - if (retval != ERROR_OK) - return retval; - - uint16_t device_id = dbgmcu_idcode & 0xfff; - uint16_t rev_id = dbgmcu_idcode >> 16; - const char *device_str; - const char *rev_str = NULL; - - switch (device_id) { - - case 0x418: - device_str = "gd32vf103 (gdm32501)"; - - switch (rev_id) { - case 0x1000: - rev_str = "A"; - break; - - case 0x1001: - rev_str = "B"; - break; - } - break; - default: - command_print_sameline(cmd, "Cannot identify target as a GD32VF103 x\n"); - return ERROR_FAIL; - } - - if (rev_str != NULL) - command_print_sameline(cmd, "%s - Rev: %s\n", device_str, rev_str); - else - command_print_sameline(cmd, "%s - Rev: unknown (0x%04x)\n", device_str, rev_id); - - return ERROR_OK; -} - -COMMAND_HANDLER(gd32vf103_handle_lock_command) -{ - struct target *target = NULL; - struct gd32vf103_flash_bank *gd32vf103_info = NULL; - - if (CMD_ARGC < 1) - return ERROR_COMMAND_SYNTAX_ERROR; - - struct flash_bank *bank; - int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) - return retval; - - gd32vf103_info = bank->driver_priv; - - target = bank->target; - - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - retval = gd32vf103_check_operation_supported(bank); - if (ERROR_OK != retval) - return retval; - - if (gd32vf103_erase_options(bank) != ERROR_OK) { - command_print(CMD, "gd32vf103 failed to erase options"); - return ERROR_OK; - } - - /* set readout protection */ - gd32vf103_info->option_bytes.RDP = 0; - - if (gd32vf103_write_options(bank) != ERROR_OK) { - command_print(CMD, "gd32vf103 failed to lock device"); - return ERROR_OK; - } - - command_print(CMD, "gd32vf103 locked"); - - return ERROR_OK; -} - -COMMAND_HANDLER(gd32vf103_handle_unlock_command) -{ - struct target *target = NULL; - - if (CMD_ARGC < 1) - return ERROR_COMMAND_SYNTAX_ERROR; - - struct flash_bank *bank; - int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) - return retval; - - target = bank->target; - - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - retval = gd32vf103_check_operation_supported(bank); - if (ERROR_OK != retval) - return retval; - - if (gd32vf103_erase_options(bank) != ERROR_OK) { - command_print(CMD, "gd32vf103 failed to unlock device"); - return ERROR_OK; - } - - if (gd32vf103_write_options(bank) != ERROR_OK) { - command_print(CMD, "gd32vf103 failed to lock device"); - return ERROR_OK; - } - - command_print(CMD, "gd32vf103 unlocked.\n" - "INFO: a reset or power cycle is required " - "for the new settings to take effect."); - - return ERROR_OK; -} - -COMMAND_HANDLER(gd32vf103_handle_options_read_command) -{ - uint32_t optionbyte; - struct target *target = NULL; - struct gd32vf103_flash_bank *gd32vf103_info = NULL; - - if (CMD_ARGC < 1) - return ERROR_COMMAND_SYNTAX_ERROR; - - struct flash_bank *bank; - int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) - return retval; - - gd32vf103_info = bank->driver_priv; - - target = bank->target; - - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - retval = gd32vf103_check_operation_supported(bank); - if (ERROR_OK != retval) - return retval; - - retval = target_read_u32(target, FMC_OBSTAT_B0, &optionbyte); - if (retval != ERROR_OK) - return retval; - command_print(CMD, "Option Byte: 0x%" PRIx32 "", optionbyte); - - int user_data = optionbyte; - - if (optionbyte >> FMC_OBSTAT_OBERR & 1) - command_print(CMD, "Option Byte Complement Error"); - - if (optionbyte >> FMC_OBSTAT_SPC & 1) - command_print(CMD, "Readout Protection On"); - else - command_print(CMD, "Readout Protection Off"); - - /* user option bytes are offset depending on variant */ - optionbyte >>= gd32vf103_info->option_offset; - - if (optionbyte >> FMC_OBSTAT_WDG_SW & 1) - command_print(CMD, "Software Watchdog"); - else - command_print(CMD, "Hardware Watchdog"); - - if (optionbyte >> FMC_OBSTAT_RST_DSLEEP & 1) - command_print(CMD, "Stop: No reset generated"); - else - command_print(CMD, "Stop: Reset generated"); - - if (optionbyte >> FMC_OBSTAT_RST_STDBY & 1) - command_print(CMD, "Standby: No reset generated"); - else - command_print(CMD, "Standby: Reset generated"); - - if (gd32vf103_info->has_dual_banks) { - if (optionbyte >> FMC_OBSTAT_BB & 1) - command_print(CMD, "Boot: Bank 0"); - else - command_print(CMD, "Boot: Bank 1"); - } - - command_print(CMD, "User Option0: 0x%02" PRIx8, - (uint8_t)((user_data >> gd32vf103_info->user_data_offset) & 0xff)); - command_print(CMD, "User Option1: 0x%02" PRIx8, - (uint8_t)((user_data >> (gd32vf103_info->user_data_offset + 8)) & 0xff)); - - return ERROR_OK; -} - -COMMAND_HANDLER(gd32vf103_handle_options_write_command) -{ - struct target *target = NULL; - struct gd32vf103_flash_bank *gd32vf103_info = NULL; - uint16_t optionbyte; - - if (CMD_ARGC < 2) - return ERROR_COMMAND_SYNTAX_ERROR; - - struct flash_bank *bank; - int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) - return retval; - - gd32vf103_info = bank->driver_priv; - - target = bank->target; - - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - retval = gd32vf103_check_operation_supported(bank); - if (ERROR_OK != retval) - return retval; - - retval = gd32vf103_read_options(bank); - if (ERROR_OK != retval) - return retval; - - /* start with current options */ - optionbyte = gd32vf103_info->option_bytes.user_options; - - /* skip over flash bank */ - CMD_ARGC--; - CMD_ARGV++; - - while (CMD_ARGC) { - if (strcmp("SWWDG", CMD_ARGV[0]) == 0) - optionbyte |= (1 << 0); - else if (strcmp("HWWDG", CMD_ARGV[0]) == 0) - optionbyte &= ~(1 << 0); - else if (strcmp("NORSTSTOP", CMD_ARGV[0]) == 0) - optionbyte |= (1 << 1); - else if (strcmp("RSTSTOP", CMD_ARGV[0]) == 0) - optionbyte &= ~(1 << 1); - else if (strcmp("NORSTSTNDBY", CMD_ARGV[0]) == 0) - optionbyte |= (1 << 2); - else if (strcmp("RSTSTNDBY", CMD_ARGV[0]) == 0) - optionbyte &= ~(1 << 2); - else if (gd32vf103_info->has_dual_banks) { - if (strcmp("BOOT0", CMD_ARGV[0]) == 0) - optionbyte |= (1 << 3); - else if (strcmp("BOOT1", CMD_ARGV[0]) == 0) - optionbyte &= ~(1 << 3); - else - return ERROR_COMMAND_SYNTAX_ERROR; - } else - return ERROR_COMMAND_SYNTAX_ERROR; - CMD_ARGC--; - CMD_ARGV++; - } - - if (gd32vf103_erase_options(bank) != ERROR_OK) { - command_print(CMD, "gd32vf103 failed to erase options"); - return ERROR_OK; - } - - gd32vf103_info->option_bytes.user_options = optionbyte; - - if (gd32vf103_write_options(bank) != ERROR_OK) { - command_print(CMD, "gd32vf103 failed to write options"); - return ERROR_OK; - } - - command_print(CMD, "gd32vf103 write options complete.\n" - "INFO: a reset or power cycle is required " - "for the new settings to take effect."); - - return ERROR_OK; -} - -static int gd32vf103_mass_erase(struct flash_bank *bank) -{ - struct target *target = bank->target; - - if (target->state != TARGET_HALTED) { - LOG_ERROR("Target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - - /* unlock option flash registers */ - int retval = target_write_u32(target, gd32vf103_get_flash_reg(bank, FMC_KEY), UNLOCK_KEY0); - if (retval != ERROR_OK) - return retval; - retval = target_write_u32(target, gd32vf103_get_flash_reg(bank, FMC_KEY), UNLOCK_KEY1); - if (retval != ERROR_OK) - return retval; - - /* mass erase flash memory */ - retval = target_write_u32(target, gd32vf103_get_flash_reg(bank, FMC_CTL), FMC_CTL_MER); - if (retval != ERROR_OK) - return retval; - retval = target_write_u32(target, gd32vf103_get_flash_reg(bank, FMC_CTL), - FMC_CTL_MER | FMC_CTL_START); - if (retval != ERROR_OK) - return retval; - - retval = gd32vf103_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); - if (retval != ERROR_OK) - return retval; - - retval = target_write_u32(target, gd32vf103_get_flash_reg(bank, FMC_CTL), FMC_CTL_LK); - if (retval != ERROR_OK) - return retval; - - return ERROR_OK; -} - -COMMAND_HANDLER(gd32vf103_handle_mass_erase_command) -{ - if (CMD_ARGC < 1) - return ERROR_COMMAND_SYNTAX_ERROR; - - struct flash_bank *bank; - int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); - if (ERROR_OK != retval) - return retval; - - retval = gd32vf103_mass_erase(bank); - if (retval == ERROR_OK) { - /* set all sectors as erased */ - for (unsigned i = 0; i < bank->num_sectors; i++) - bank->sectors[i].is_erased = 1; - - command_print(CMD, "gd32vf103 mass erase complete"); - } else - command_print(CMD, "gd32vf103 mass erase failed"); - - return retval; -} - -static const struct command_registration gd32vf103_exec_command_handlers[] = { - { - .name = "lock", - .handler = gd32vf103_handle_lock_command, - .mode = COMMAND_EXEC, - .usage = "bank_id", - .help = "Lock entire flash device.", - }, - { - .name = "unlock", - .handler = gd32vf103_handle_unlock_command, - .mode = COMMAND_EXEC, - .usage = "bank_id", - .help = "Unlock entire protected flash device.", - }, - { - .name = "mass_erase", - .handler = gd32vf103_handle_mass_erase_command, - .mode = COMMAND_EXEC, - .usage = "bank_id", - .help = "Erase entire flash device.", - }, - { - .name = "options_read", - .handler = gd32vf103_handle_options_read_command, - .mode = COMMAND_EXEC, - .usage = "bank_id", - .help = "Read and display device option byte.", - }, - { - .name = "options_write", - .handler = gd32vf103_handle_options_write_command, - .mode = COMMAND_EXEC, - .usage = "bank_id ('SWWDG'|'HWWDG') " - "('RSTSTNDBY'|'NORSTSTNDBY') " - "('RSTSTOP'|'NORSTSTOP')", - .help = "Replace bits in device option byte.", - }, - COMMAND_REGISTRATION_DONE -}; - -static const struct command_registration gd32vf103_command_handlers[] = { - { - .name = "gd32vf103", - .mode = COMMAND_ANY, - .help = "gd32vf103 flash command group", - .usage = "", - .chain = gd32vf103_exec_command_handlers, - }, - COMMAND_REGISTRATION_DONE -}; - -struct flash_driver gd32vf103_flash = { - .name = "gd32vf103", - .commands = gd32vf103_command_handlers, - .flash_bank_command = gd32vf103_flash_bank_command, - .erase = gd32vf103_erase, - .protect = gd32vf103_protect, - .write = gd32vf103_write, - .read = default_flash_read, - .probe = gd32vf103_probe, - .auto_probe = gd32vf103_auto_probe, - .erase_check = default_flash_blank_check, - .protect_check = gd32vf103_protect_check, - .info = get_gd32vf103_info, - .free_driver_priv = default_flash_free_driver_priv, -}; From 3cac5d279eefc7a0300745dc48d7704527a93b6b Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Wed, 4 May 2022 16:17:08 +0200 Subject: [PATCH 23/24] server/gdb: fix gdb remote monitor cmd on multi-target Commit 5ebb1bdea1df ("server/gdb: fix return of gdb remote monitor command") replaces the call to command_run_line() with call to Jim_EvalObj() but does not properly set the "context". In multi-target environment, his can cause the erroneously execution of the command on the wrong target. Copy from the code in command_run_line() the proper setup before executing Jim_EvalObj(). Change-Id: I56738c80779082ca146a06c01bc30e28bc835fd3 Signed-off-by: Antonio Borneo Reported-by: Bohdan Tymkiv Fixes: 5ebb1bdea1df ("server/gdb: fix return of gdb remote monitor command") --- src/server/gdb_server.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index da6552703..cdb26f245 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -2756,6 +2756,7 @@ static int gdb_query_packet(struct connection *connection, if (strncmp(packet, "qRcmd,", 6) == 0) { if (packet_size > 6) { + Jim_Interp *interp = cmd_ctx->interp; char *cmd; cmd = malloc((packet_size - 6) / 2 + 1); size_t len = unhexify((uint8_t *)cmd, packet + 6, (packet_size - 6) / 2); @@ -2768,20 +2769,31 @@ static int gdb_query_packet(struct connection *connection, /* some commands need to know the GDB connection, make note of current * GDB connection. */ current_gdb_connection = gdb_connection; - struct target *saved_target_override = cmd_ctx->current_target_override; - cmd_ctx->current_target_override = target; - int retval = Jim_EvalObj(cmd_ctx->interp, Jim_NewStringObj(cmd_ctx->interp, cmd, -1)); + struct target *saved_target_override = cmd_ctx->current_target_override; + cmd_ctx->current_target_override = NULL; + + struct command_context *old_context = Jim_GetAssocData(interp, "context"); + Jim_DeleteAssocData(interp, "context"); + int retval = Jim_SetAssocData(interp, "context", NULL, cmd_ctx); + if (retval == JIM_OK) { + retval = Jim_EvalObj(interp, Jim_NewStringObj(interp, cmd, -1)); + Jim_DeleteAssocData(interp, "context"); + } + int inner_retval = Jim_SetAssocData(interp, "context", NULL, old_context); + if (retval == JIM_OK) + retval = inner_retval; cmd_ctx->current_target_override = saved_target_override; + current_gdb_connection = NULL; target_call_timer_callbacks_now(); gdb_connection->output_flag = GDB_OUTPUT_NO; free(cmd); if (retval == JIM_RETURN) - retval = cmd_ctx->interp->returnCode; + retval = interp->returnCode; int lenmsg; - const char *cretmsg = Jim_GetString(Jim_GetResult(cmd_ctx->interp), &lenmsg); + const char *cretmsg = Jim_GetString(Jim_GetResult(interp), &lenmsg); char *retmsg; if (lenmsg && cretmsg[lenmsg - 1] != '\n') { retmsg = alloc_printf("%s\n", cretmsg); From a2c569f3be430ca4b75d4e02297f34801c3e2741 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 4 May 2022 10:11:39 -0700 Subject: [PATCH 24/24] Try to fix capstone build for win32. Change-Id: I77dd0679c24ca8cec2158ec4da71faa4a7740491 Signed-off-by: Tim Newsome --- .github/workflows/snapshot.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index c53b1944b..d4749d6d3 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -55,6 +55,7 @@ jobs: LIBUSB1_CONFIG: --enable-shared --disable-static HIDAPI_CONFIG: --enable-shared --disable-static --disable-testgui CAPSTONE_CONFIG: "CAPSTONE_BUILD_CORE_ONLY=yes CAPSTONE_STATIC=yes CAPSTONE_SHARED=no" + CAPSTONE_CFLAGS: -I$(CAPSTONE_SRC)/include/capstone run: | # check if there is tag pointing at HEAD, otherwise take the HEAD SHA-1 as OPENOCD_TAG OPENOCD_TAG="`git tag --points-at HEAD`"