summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common.c4769
-rw-r--r--src/st-flash/flash.c181
-rw-r--r--src/st-flash/flash.h40
-rw-r--r--src/st-flash/flash_opts.c118
-rw-r--r--src/st-flash/flash_opts.h40
-rw-r--r--src/st-info/info.c93
-rw-r--r--src/st-info/info.h18
-rw-r--r--src/st-trace/trace.c244
-rw-r--r--src/st-trace/trace.h24
-rw-r--r--src/st-util/gdb-remote.c42
-rw-r--r--src/st-util/gdb-remote.h14
-rw-r--r--src/st-util/gdb-server.c606
-rw-r--r--src/st-util/gdb-server.h6
-rw-r--r--src/st-util/memory-map.h217
-rw-r--r--src/st-util/semihosting.c149
-rw-r--r--src/st-util/semihosting.h10
-rw-r--r--src/stlink-gui/CMakeLists.txt21
-rw-r--r--src/stlink-gui/gui.c75
-rw-r--r--src/stlink-gui/gui.h9
-rw-r--r--src/stlink-lib/calculate.c81
-rw-r--r--src/stlink-lib/calculate.h15
-rw-r--r--src/stlink-lib/chipid.c1032
-rw-r--r--src/stlink-lib/chipid.h99
-rw-r--r--src/stlink-lib/commands.h34
-rw-r--r--src/stlink-lib/common.c1372
-rw-r--r--src/stlink-lib/common_flash.c1566
-rw-r--r--src/stlink-lib/common_flash.h53
-rw-r--r--src/stlink-lib/flash_loader.c839
-rw-r--r--src/stlink-lib/flash_loader.h39
-rw-r--r--src/stlink-lib/helper.c29
-rw-r--r--src/stlink-lib/helper.h15
-rw-r--r--src/stlink-lib/lib_md5.c281
-rw-r--r--src/stlink-lib/lib_md5.h65
-rw-r--r--src/stlink-lib/libusb_settings.h45
-rw-r--r--src/stlink-lib/logging.c42
-rw-r--r--src/stlink-lib/logging.h38
-rw-r--r--src/stlink-lib/map_file.c110
-rw-r--r--src/stlink-lib/map_file.h33
-rw-r--r--[-rwxr-xr-x]src/stlink-lib/md5.c295
-rw-r--r--[-rwxr-xr-x]src/stlink-lib/md5.h66
-rw-r--r--src/stlink-lib/option_bytes.c1180
-rw-r--r--src/stlink-lib/option_bytes.h47
-rw-r--r--src/stlink-lib/read_write.c154
-rw-r--r--src/stlink-lib/read_write.h27
-rw-r--r--src/stlink-lib/register.h (renamed from src/stlink-lib/reg.h)12
-rw-r--r--src/stlink-lib/sg.c304
-rw-r--r--src/stlink-lib/sg.h78
-rw-r--r--src/stlink-lib/spdlog_wrapper.h14
-rw-r--r--src/stlink-lib/usb.c829
-rw-r--r--src/stlink-lib/usb.h97
-rw-r--r--src/win32/getopt/getopt.c37
-rw-r--r--src/win32/getopt/getopt.h24
-rw-r--r--src/win32/mmap.c21
-rw-r--r--src/win32/mmap.h22
-rw-r--r--src/win32/sys_time.c15
-rw-r--r--src/win32/sys_time.h26
-rw-r--r--src/win32/unistd/unistd.h14
-rw-r--r--src/win32/win32_socket.c76
-rw-r--r--src/win32/win32_socket.h30
59 files changed, 8024 insertions, 7808 deletions
diff --git a/src/common.c b/src/common.c
deleted file mode 100644
index 4541aa3..0000000
--- a/src/common.c
+++ /dev/null
@@ -1,4769 +0,0 @@
-#define DEBUG_FLASH 0
-#include <stdarg.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <helper.h>
-#include <logging.h>
-#include <md5.h>
-#include <stlink.h>
-
-#ifdef STLINK_HAVE_SYS_MMAN_H
-#include <sys/mman.h>
-#else
-#include <mmap.h>
-#endif
-
-#ifndef O_BINARY
-#define O_BINARY 0
-#endif
-
-#ifdef _MSC_VER
-#define __attribute__(x)
-#endif
-
-#define BANK_1 0
-#define BANK_2 1
-
-/* stm32f FPEC flash controller interface, pm0063 manual */
-// TODO - all of this needs to be abstracted out....
-// STM32F05x is identical, based on RM0091 (DM00031936, Doc ID 018940 Rev 2,
-// August 2012)
-#define FLASH_REGS_ADDR 0x40022000
-#define FLASH_REGS_SIZE 0x28
-
-#define FLASH_ACR (FLASH_REGS_ADDR + 0x00)
-#define FLASH_KEYR (FLASH_REGS_ADDR + 0x04)
-#define FLASH_OPTKEYR (FLASH_REGS_ADDR + 0x08)
-#define FLASH_SR (FLASH_REGS_ADDR + 0x0c)
-#define FLASH_CR (FLASH_REGS_ADDR + 0x10)
-#define FLASH_AR (FLASH_REGS_ADDR + 0x14)
-#define FLASH_OBR (FLASH_REGS_ADDR + 0x1c)
-#define FLASH_WRPR (FLASH_REGS_ADDR + 0x20)
-
-// STM32F10x_XL has two flash memory banks with separate registers to control
-// the second bank.
-#define FLASH_KEYR2 (FLASH_REGS_ADDR + 0x44)
-#define FLASH_SR2 (FLASH_REGS_ADDR + 0x4c)
-#define FLASH_CR2 (FLASH_REGS_ADDR + 0x50)
-#define FLASH_AR2 (FLASH_REGS_ADDR + 0x54)
-
-// For STM32F05x, the RDPTR_KEY may be wrong, but as it is not used anywhere...
-#define FLASH_RDPTR_KEY 0x00a5
-#define FLASH_KEY1 0x45670123
-#define FLASH_KEY2 0xcdef89ab
-
-#define FLASH_L0_PRGKEY1 0x8c9daebf
-#define FLASH_L0_PRGKEY2 0x13141516
-
-#define FLASH_L0_PEKEY1 0x89abcdef
-#define FLASH_L0_PEKEY2 0x02030405
-
-#define FLASH_OPTKEY1 0x08192A3B
-#define FLASH_OPTKEY2 0x4C5D6E7F
-
-#define FLASH_F0_OPTKEY1 0x45670123
-#define FLASH_F0_OPTKEY2 0xCDEF89AB
-
-#define FLASH_L0_OPTKEY1 0xFBEAD9C8
-#define FLASH_L0_OPTKEY2 0x24252627
-
-#define FLASH_SR_BSY 0
-#define FLASH_SR_PG_ERR 2
-#define FLASH_SR_WRPRT_ERR 4
-#define FLASH_SR_EOP 5
-
-#define FLASH_SR_ERROR_MASK ((1 << FLASH_SR_PG_ERR) | (1 << FLASH_SR_WRPRT_ERR))
-
-#define FLASH_CR_PG 0
-#define FLASH_CR_PER 1
-#define FLASH_CR_MER 2
-#define FLASH_CR_OPTPG 4
-#define FLASH_CR_STRT 6
-#define FLASH_CR_LOCK 7
-#define FLASH_CR_OPTWRE 9
-
-#define STM32L_FLASH_REGS_ADDR ((uint32_t)0x40023c00)
-#define STM32L_FLASH_ACR (STM32L_FLASH_REGS_ADDR + 0x00)
-#define STM32L_FLASH_PECR (STM32L_FLASH_REGS_ADDR + 0x04)
-#define STM32L_FLASH_PDKEYR (STM32L_FLASH_REGS_ADDR + 0x08)
-#define STM32L_FLASH_PEKEYR (STM32L_FLASH_REGS_ADDR + 0x0c)
-#define STM32L_FLASH_PRGKEYR (STM32L_FLASH_REGS_ADDR + 0x10)
-#define STM32L_FLASH_OPTKEYR (STM32L_FLASH_REGS_ADDR + 0x14)
-#define STM32L_FLASH_SR (STM32L_FLASH_REGS_ADDR + 0x18)
-#define STM32L_FLASH_OBR (STM32L_FLASH_REGS_ADDR + 0x1c)
-#define STM32L_FLASH_WRPR (STM32L_FLASH_REGS_ADDR + 0x20)
-#define FLASH_L1_FPRG 10
-#define FLASH_L1_PROG 3
-
-// Flash registers common to STM32G0 and STM32G4 series.
-#define STM32Gx_FLASH_REGS_ADDR ((uint32_t)0x40022000)
-#define STM32Gx_FLASH_ACR (STM32Gx_FLASH_REGS_ADDR + 0x00)
-#define STM32Gx_FLASH_KEYR (STM32Gx_FLASH_REGS_ADDR + 0x08)
-#define STM32Gx_FLASH_OPTKEYR (STM32Gx_FLASH_REGS_ADDR + 0x0c)
-#define STM32Gx_FLASH_SR (STM32Gx_FLASH_REGS_ADDR + 0x10)
-#define STM32Gx_FLASH_CR (STM32Gx_FLASH_REGS_ADDR + 0x14)
-#define STM32Gx_FLASH_ECCR (STM32Gx_FLASH_REGS_ADDR + 0x18)
-#define STM32Gx_FLASH_OPTR (STM32Gx_FLASH_REGS_ADDR + 0x20)
-
-// G0 (RM0444 Table 1, sec 3.7)
-// Mostly the same as G4 chips, but the notation
-// varies a bit after the 'OPTR' register.
-#define STM32G0_FLASH_REGS_ADDR (STM32Gx_FLASH_REGS_ADDR)
-#define STM32G0_FLASH_PCROP1ASR (STM32G0_FLASH_REGS_ADDR + 0x24)
-#define STM32G0_FLASH_PCROP1AER (STM32G0_FLASH_REGS_ADDR + 0x28)
-#define STM32G0_FLASH_WRP1AR (STM32G0_FLASH_REGS_ADDR + 0x2C)
-#define STM32G0_FLASH_WRP1BR (STM32G0_FLASH_REGS_ADDR + 0x30)
-#define STM32G0_FLASH_PCROP1BSR (STM32G0_FLASH_REGS_ADDR + 0x34)
-#define STM32G0_FLASH_PCROP1BER (STM32G0_FLASH_REGS_ADDR + 0x38)
-#define STM32G0_FLASH_SECR (STM32G0_FLASH_REGS_ADDR + 0x80)
-
-// G4 (RM0440 Table 17, sec 3.7.19)
-// Mostly the same as STM32G0 chips, but there are a few extra
-// registers because 'cat 3' devices can have two Flash banks.
-#define STM32G4_FLASH_REGS_ADDR (STM32Gx_FLASH_REGS_ADDR)
-#define STM32G4_FLASH_PDKEYR (STM32G4_FLASH_REGS_ADDR + 0x04)
-#define STM32G4_FLASH_PCROP1SR (STM32G4_FLASH_REGS_ADDR + 0x24)
-#define STM32G4_FLASH_PCROP1ER (STM32G4_FLASH_REGS_ADDR + 0x28)
-#define STM32G4_FLASH_WRP1AR (STM32G4_FLASH_REGS_ADDR + 0x2C)
-#define STM32G4_FLASH_WRP1BR (STM32G4_FLASH_REGS_ADDR + 0x30)
-#define STM32G4_FLASH_PCROP2SR (STM32G4_FLASH_REGS_ADDR + 0x44)
-#define STM32G4_FLASH_PCROP2ER (STM32G4_FLASH_REGS_ADDR + 0x48)
-#define STM32G4_FLASH_WRP2AR (STM32G4_FLASH_REGS_ADDR + 0x4C)
-#define STM32G4_FLASH_WRP2BR (STM32G4_FLASH_REGS_ADDR + 0x50)
-#define STM32G4_FLASH_SEC1R (STM32G4_FLASH_REGS_ADDR + 0x70)
-#define STM32G4_FLASH_SEC2R (STM32G4_FLASH_REGS_ADDR + 0x74)
-
-// G0/G4 FLASH control register
-#define STM32Gx_FLASH_CR_PG (0) /* Program */
-#define STM32Gx_FLASH_CR_PER (1) /* Page erase */
-#define STM32Gx_FLASH_CR_MER1 (2) /* Mass erase */
-#define STM32Gx_FLASH_CR_PNB (3) /* Page number */
-#define STM32G0_FLASH_CR_PNG_LEN (5) /* STM32G0: 5 page number bits */
-#define STM32G4_FLASH_CR_PNG_LEN (7) /* STM32G4: 7 page number bits */
-#define STM32Gx_FLASH_CR_MER2 (15) /* Mass erase (2nd bank)*/
-#define STM32Gx_FLASH_CR_STRT (16) /* Start */
-#define STM32Gx_FLASH_CR_OPTSTRT \
- (17) /* Start of modification of option bytes */
-#define STM32Gx_FLASH_CR_FSTPG (18) /* Fast programming */
-#define STM32Gx_FLASH_CR_EOPIE (24) /* End of operation interrupt enable */
-#define STM32Gx_FLASH_CR_ERRIE (25) /* Error interrupt enable */
-#define STM32Gx_FLASH_CR_OBL_LAUNCH (27) /* Forces the option byte loading */
-#define STM32Gx_FLASH_CR_OPTLOCK (30) /* Options Lock */
-#define STM32Gx_FLASH_CR_LOCK (31) /* FLASH_CR Lock */
-
-// G0/G4 FLASH status register
-#define STM32Gx_FLASH_SR_ERROR_MASK (0x3fa)
-#define STM32Gx_FLASH_SR_PROGERR (3)
-#define STM32Gx_FLASH_SR_WRPERR (4)
-#define STM32Gx_FLASH_SR_PGAERR (5)
-#define STM32Gx_FLASH_SR_BSY (16) /* FLASH_SR Busy */
-#define STM32Gx_FLASH_SR_EOP (0) /* FLASH_EOP End of Operation */
-
-// G4 FLASH option register
-#define STM32G4_FLASH_OPTR_DBANK (22) /* FLASH_OPTR Dual Bank Mode */
-
-// WB (RM0434)
-#define STM32WB_FLASH_REGS_ADDR ((uint32_t)0x58004000)
-#define STM32WB_FLASH_ACR (STM32WB_FLASH_REGS_ADDR + 0x00)
-#define STM32WB_FLASH_KEYR (STM32WB_FLASH_REGS_ADDR + 0x08)
-#define STM32WB_FLASH_OPT_KEYR (STM32WB_FLASH_REGS_ADDR + 0x0C)
-#define STM32WB_FLASH_SR (STM32WB_FLASH_REGS_ADDR + 0x10)
-#define STM32WB_FLASH_CR (STM32WB_FLASH_REGS_ADDR + 0x14)
-#define STM32WB_FLASH_ECCR (STM32WB_FLASH_REGS_ADDR + 0x18)
-#define STM32WB_FLASH_OPTR (STM32WB_FLASH_REGS_ADDR + 0x20)
-#define STM32WB_FLASH_PCROP1ASR (STM32WB_FLASH_REGS_ADDR + 0x24)
-#define STM32WB_FLASH_PCROP1AER (STM32WB_FLASH_REGS_ADDR + 0x28)
-#define STM32WB_FLASH_WRP1AR (STM32WB_FLASH_REGS_ADDR + 0x2C)
-#define STM32WB_FLASH_WRP1BR (STM32WB_FLASH_REGS_ADDR + 0x30)
-#define STM32WB_FLASH_PCROP1BSR (STM32WB_FLASH_REGS_ADDR + 0x34)
-#define STM32WB_FLASH_PCROP1BER (STM32WB_FLASH_REGS_ADDR + 0x38)
-#define STM32WB_FLASH_IPCCBR (STM32WB_FLASH_REGS_ADDR + 0x3C)
-#define STM32WB_FLASH_C2ACR (STM32WB_FLASH_REGS_ADDR + 0x5C)
-#define STM32WB_FLASH_C2SR (STM32WB_FLASH_REGS_ADDR + 0x60)
-#define STM32WB_FLASH_C2CR (STM32WB_FLASH_REGS_ADDR + 0x64)
-#define STM32WB_FLASH_SFR (STM32WB_FLASH_REGS_ADDR + 0x80)
-#define STM32WB_FLASH_SRRVR (STM32WB_FLASH_REGS_ADDR + 0x84)
-
-// WB Flash control register.
-#define STM32WB_FLASH_CR_STRT (16) /* Start */
-#define STM32WB_FLASH_CR_OPTLOCK (30) /* Option Lock */
-#define STM32WB_FLASH_CR_LOCK (31) /* Lock */
-// WB Flash status register.
-#define STM32WB_FLASH_SR_ERROR_MASK (0x3f8) /* SR [9:3] */
-#define STM32WB_FLASH_SR_PROGERR (3) /* Programming alignment error */
-#define STM32WB_FLASH_SR_WRPERR (4) /* Write protection error */
-#define STM32WB_FLASH_SR_PGAERR (5) /* Programming error */
-#define STM32WB_FLASH_SR_BSY (16) /* Busy */
-
-// 32L4 register base is at FLASH_REGS_ADDR (0x40022000)
-#define STM32L4_FLASH_KEYR (FLASH_REGS_ADDR + 0x08)
-#define STM32L4_FLASH_OPTKEYR (FLASH_REGS_ADDR + 0x0C)
-#define STM32L4_FLASH_SR (FLASH_REGS_ADDR + 0x10)
-#define STM32L4_FLASH_CR (FLASH_REGS_ADDR + 0x14)
-#define STM32L4_FLASH_OPTR (FLASH_REGS_ADDR + 0x20)
-
-#define STM32L4_FLASH_SR_ERROR_MASK 0x3f8 /* SR [9:3] */
-#define STM32L4_FLASH_SR_PROGERR 3
-#define STM32L4_FLASH_SR_WRPERR 4
-#define STM32L4_FLASH_SR_PGAERR 5
-#define STM32L4_FLASH_SR_BSY 16
-
-#define STM32L4_FLASH_CR_LOCK 31 /* Lock control register */
-#define STM32L4_FLASH_CR_OPTLOCK 30 /* Lock option bytes */
-#define STM32L4_FLASH_CR_PG 0 /* Program */
-#define STM32L4_FLASH_CR_PER 1 /* Page erase */
-#define STM32L4_FLASH_CR_MER1 2 /* Bank 1 erase */
-#define STM32L4_FLASH_CR_MER2 15 /* Bank 2 erase */
-#define STM32L4_FLASH_CR_STRT 16 /* Start command */
-#define STM32L4_FLASH_CR_OPTSTRT 17 /* Start writing option bytes */
-#define STM32L4_FLASH_CR_BKER 11 /* Bank select for page erase */
-#define STM32L4_FLASH_CR_PNB 3 /* Page number (8 bits) */
-#define STM32L4_FLASH_CR_OBL_LAUNCH 27 /* Option bytes reload */
-// Bits requesting flash operations (useful when we want to clear them)
-#define STM32L4_FLASH_CR_OPBITS \
- (uint32_t)((1lu << STM32L4_FLASH_CR_PG) | (1lu << STM32L4_FLASH_CR_PER) | \
- (1lu << STM32L4_FLASH_CR_MER1) | (1lu << STM32L4_FLASH_CR_MER1))
-// Page is fully specified by BKER and PNB
-#define STM32L4_FLASH_CR_PAGEMASK (uint32_t)(0x1fflu << STM32L4_FLASH_CR_PNB)
-
-#define STM32L4_FLASH_OPTR_DUALBANK 21
-
-// STM32L0x flash register base and offsets RM0090 - DM00031020.pdf
-#define STM32L0_FLASH_REGS_ADDR ((uint32_t)0x40022000)
-#define STM32L1_FLASH_REGS_ADDR ((uint32_t)0x40023c00)
-
-#define STM32L0_FLASH_PELOCK (0)
-#define STM32L0_FLASH_OPTLOCK (2)
-#define STM32L0_FLASH_OBL_LAUNCH (18)
-
-#define STM32L0_FLASH_SR_ERROR_MASK 0x00013F00
-#define STM32L0_FLASH_SR_WRPERR 8
-#define STM32L0_FLASH_SR_PGAERR 9
-#define STM32L0_FLASH_SR_NOTZEROERR 16
-
-#define FLASH_ACR_OFF ((uint32_t)0x00)
-#define FLASH_PECR_OFF ((uint32_t)0x04)
-#define FLASH_PDKEYR_OFF ((uint32_t)0x08)
-#define FLASH_PEKEYR_OFF ((uint32_t)0x0c)
-#define FLASH_PRGKEYR_OFF ((uint32_t)0x10)
-#define FLASH_OPTKEYR_OFF ((uint32_t)0x14)
-#define FLASH_SR_OFF ((uint32_t)0x18)
-#define FLASH_OBR_OFF ((uint32_t)0x1c)
-#define FLASH_WRPR_OFF ((uint32_t)0x20)
-
-// STM32F7
-#define FLASH_F7_REGS_ADDR ((uint32_t)0x40023c00)
-#define FLASH_F7_KEYR (FLASH_F7_REGS_ADDR + 0x04)
-#define FLASH_F7_OPT_KEYR (FLASH_F7_REGS_ADDR + 0x08)
-#define FLASH_F7_SR (FLASH_F7_REGS_ADDR + 0x0c)
-#define FLASH_F7_CR (FLASH_F7_REGS_ADDR + 0x10)
-#define FLASH_F7_OPTCR (FLASH_F7_REGS_ADDR + 0x14)
-#define FLASH_F7_OPTCR1 (FLASH_F7_REGS_ADDR + 0x18)
-#define FLASH_F7_OPTCR_LOCK 0
-#define FLASH_F7_OPTCR_START 1
-#define FLASH_F7_CR_STRT 16
-#define FLASH_F7_CR_LOCK 31
-#define FLASH_F7_CR_SER 1
-#define FLASH_F7_CR_SNB 3
-#define FLASH_F7_CR_SNB_MASK 0xf8
-#define FLASH_F7_SR_BSY 16
-#define FLASH_F7_SR_ERS_ERR 7 /* Erase Sequence Error */
-#define FLASH_F7_SR_PGP_ERR 6 /* Programming parallelism error */
-#define FLASH_F7_SR_PGA_ERR 5 /* Programming alignment error */
-#define FLASH_F7_SR_WRP_ERR 4 /* Write protection error */
-#define FLASH_F7_SR_OP_ERR 1 /* Operation error */
-#define FLASH_F7_SR_EOP 0 /* End of operation */
-#define FLASH_F7_OPTCR1_BOOT_ADD0 0
-#define FLASH_F7_OPTCR1_BOOT_ADD1 16
-
-#define FLASH_F7_SR_ERROR_MASK \
- ((1 << FLASH_F7_SR_ERS_ERR) | (1 << FLASH_F7_SR_PGP_ERR) | \
- (1 << FLASH_F7_SR_PGA_ERR) | (1 << FLASH_F7_SR_WRP_ERR) | \
- (1 << FLASH_F7_SR_OP_ERR))
-
-// STM32F4
-#define FLASH_F4_REGS_ADDR ((uint32_t)0x40023c00)
-#define FLASH_F4_KEYR (FLASH_F4_REGS_ADDR + 0x04)
-#define FLASH_F4_OPT_KEYR (FLASH_F4_REGS_ADDR + 0x08)
-#define FLASH_F4_SR (FLASH_F4_REGS_ADDR + 0x0c)
-#define FLASH_F4_CR (FLASH_F4_REGS_ADDR + 0x10)
-#define FLASH_F4_OPTCR (FLASH_F4_REGS_ADDR + 0x14)
-#define FLASH_F4_OPTCR_LOCK 0
-#define FLASH_F4_OPTCR_START 1
-#define FLASH_F4_CR_STRT 16
-#define FLASH_F4_CR_LOCK 31
-#define FLASH_F4_CR_SER 1
-#define FLASH_F4_CR_SNB 3
-#define FLASH_F4_CR_SNB_MASK 0xf8
-#define FLASH_F4_SR_ERROR_MASK 0x000000F0
-#define FLASH_F4_SR_PGAERR 5
-#define FLASH_F4_SR_WRPERR 4
-#define FLASH_F4_SR_BSY 16
-
-// STM32F2
-#define FLASH_F2_REGS_ADDR ((uint32_t)0x40023c00)
-#define FLASH_F2_KEYR (FLASH_F2_REGS_ADDR + 0x04)
-#define FLASH_F2_OPT_KEYR (FLASH_F2_REGS_ADDR + 0x08)
-#define FLASH_F2_SR (FLASH_F2_REGS_ADDR + 0x0c)
-#define FLASH_F2_CR (FLASH_F2_REGS_ADDR + 0x10)
-#define FLASH_F2_OPT_CR (FLASH_F2_REGS_ADDR + 0x14)
-#define FLASH_F2_OPT_LOCK_BIT (1u << 0)
-#define FLASH_F2_CR_STRT 16
-#define FLASH_F2_CR_LOCK 31
-
-#define FLASH_F2_CR_SER 1
-#define FLASH_F2_CR_SNB 3
-#define FLASH_F2_CR_SNB_MASK 0x78
-#define FLASH_F2_SR_BSY 16
-
-// STM32H7xx
-#define FLASH_H7_CR_LOCK 0
-#define FLASH_H7_CR_PG 1
-#define FLASH_H7_CR_SER 2
-#define FLASH_H7_CR_BER 3
-#define FLASH_H7_CR_PSIZE 4
-#define FLASH_H7_CR_START(chipid) (chipid == STLINK_CHIPID_STM32_H7AX ? 5 : 7)
-#define FLASH_H7_CR_SNB 8
-#define FLASH_H7_CR_SNB_MASK 0x700
-
-#define FLASH_H7_SR_QW 2
-#define FLASH_H7_SR_WRPERR 17
-#define FLASH_H7_SR_PGSERR 18
-#define FLASH_H7_SR_STRBERR 19
-#define FLASH_H7_SR_ERROR_MASK \
- ((1 << FLASH_H7_SR_PGSERR) | (1 << FLASH_H7_SR_STRBERR) | \
- (1 << FLASH_H7_SR_WRPERR))
-
-#define FLASH_H7_OPTCR_OPTLOCK 0
-#define FLASH_H7_OPTCR_OPTSTART 1
-#define FLASH_H7_OPTCR_MER 4
-
-#define FLASH_H7_OPTSR_OPT_BUSY 0
-#define FLASH_H7_OPTSR_OPTCHANGEERR 30
-
-#define FLASH_H7_OPTCCR_CLR_OPTCHANGEERR 30
-
-#define FLASH_H7_REGS_ADDR ((uint32_t)0x52002000)
-#define FLASH_H7_KEYR1 (FLASH_H7_REGS_ADDR + 0x04)
-#define FLASH_H7_KEYR2 (FLASH_H7_REGS_ADDR + 0x104)
-#define FLASH_H7_OPT_KEYR (FLASH_H7_REGS_ADDR + 0x08)
-#define FLASH_H7_OPT_KEYR2 (FLASH_H7_REGS_ADDR + 0x108)
-#define FLASH_H7_CR1 (FLASH_H7_REGS_ADDR + 0x0c)
-#define FLASH_H7_CR2 (FLASH_H7_REGS_ADDR + 0x10c)
-#define FLASH_H7_SR1 (FLASH_H7_REGS_ADDR + 0x10)
-#define FLASH_H7_SR2 (FLASH_H7_REGS_ADDR + 0x110)
-#define FLASH_H7_CCR1 (FLASH_H7_REGS_ADDR + 0x14)
-#define FLASH_H7_CCR2 (FLASH_H7_REGS_ADDR + 0x114)
-#define FLASH_H7_OPTCR (FLASH_H7_REGS_ADDR + 0x18)
-#define FLASH_H7_OPTCR2 (FLASH_H7_REGS_ADDR + 0x118)
-#define FLASH_H7_OPTSR_CUR (FLASH_H7_REGS_ADDR + 0x1c)
-#define FLASH_H7_OPTCCR (FLASH_H7_REGS_ADDR + 0x24)
-
-#define STM32F0_DBGMCU_CR 0xE0042004
-#define STM32F0_DBGMCU_CR_IWDG_STOP 8
-#define STM32F0_DBGMCU_CR_WWDG_STOP 9
-
-#define STM32F4_DBGMCU_APB1FZR1 0xE0042008
-#define STM32F4_DBGMCU_APB1FZR1_WWDG_STOP 11
-#define STM32F4_DBGMCU_APB1FZR1_IWDG_STOP 12
-
-#define STM32L0_DBGMCU_APB1_FZ 0x40015808
-#define STM32L0_DBGMCU_APB1_FZ_WWDG_STOP 11
-#define STM32L0_DBGMCU_APB1_FZ_IWDG_STOP 12
-
-#define STM32H7_DBGMCU_APB1HFZ 0x5C001054
-#define STM32H7_DBGMCU_APB1HFZ_IWDG_STOP 18
-
-#define STM32WB_DBGMCU_APB1FZR1 0xE004203C
-#define STM32WB_DBGMCU_APB1FZR1_WWDG_STOP 11
-#define STM32WB_DBGMCU_APB1FZR1_IWDG_STOP 12
-
-#define STM32F1_RCC_AHBENR 0x40021014
-#define STM32F1_RCC_DMAEN 0x00000003 // DMA2EN | DMA1EN
-
-#define STM32F4_RCC_AHB1ENR 0x40023830
-#define STM32F4_RCC_DMAEN 0x00600000 // DMA2EN | DMA1EN
-
-#define STM32G0_RCC_AHBENR 0x40021038
-#define STM32G0_RCC_DMAEN 0x00000003 // DMA2EN | DMA1EN
-
-#define STM32G4_RCC_AHB1ENR 0x40021048
-#define STM32G4_RCC_DMAEN 0x00000003 // DMA2EN | DMA1EN
-
-#define STM32L0_RCC_AHBENR 0x40021030
-#define STM32L0_RCC_DMAEN 0x00000001 // DMAEN
-
-#define STM32H7_RCC_AHB1ENR 0x58024538
-#define STM32H7_RCC_DMAEN 0x00000003 // DMA2EN | DMA1EN
-
-#define STM32WB_RCC_AHB1ENR 0x58000048
-#define STM32WB_RCC_DMAEN 0x00000003 // DMA2EN | DMA1EN
-
-#define L1_WRITE_BLOCK_SIZE 0x80
-#define L0_WRITE_BLOCK_SIZE 0x40
-
-// Endianness
-// https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html
-// These functions encode and decode little endian uint16 and uint32 values.
-
-void write_uint32(unsigned char *buf, uint32_t ui) {
- buf[0] = ui;
- buf[1] = ui >> 8;
- buf[2] = ui >> 16;
- buf[3] = ui >> 24;
-}
-
-void write_uint16(unsigned char *buf, uint16_t ui) {
- buf[0] = ui;
- buf[1] = ui >> 8;
-}
-
-uint32_t read_uint32(const unsigned char *c, const int pt) {
- return ((uint32_t)c[pt]) | ((uint32_t)c[pt + 1] << 8) |
- ((uint32_t)c[pt + 2] << 16) | ((uint32_t)c[pt + 3] << 24);
-}
-
-uint16_t read_uint16(const unsigned char *c, const int pt) {
- return ((uint16_t)c[pt]) | ((uint16_t)c[pt + 1] << 8);
-}
-
-static uint32_t get_stm32l0_flash_base(stlink_t *sl) {
- switch (sl->chip_id) {
- case STLINK_CHIPID_STM32_L0:
- case STLINK_CHIPID_STM32_L0_CAT5:
- case STLINK_CHIPID_STM32_L0_CAT2:
- case STLINK_CHIPID_STM32_L011:
- return (STM32L0_FLASH_REGS_ADDR);
-
- case STLINK_CHIPID_STM32_L1_CAT2:
- case STLINK_CHIPID_STM32_L1_MEDIUM:
- case STLINK_CHIPID_STM32_L1_MEDIUM_PLUS:
- case STLINK_CHIPID_STM32_L1_HIGH:
- return (STM32L1_FLASH_REGS_ADDR);
-
- default:
- WLOG("Flash base use default L0 address");
- return (STM32L0_FLASH_REGS_ADDR);
- }
-}
-
-static uint32_t __attribute__((unused)) read_flash_rdp(stlink_t *sl) {
- uint32_t rdp;
- stlink_read_debug32(sl, FLASH_WRPR, &rdp);
- return (rdp & 0xff);
-}
-
-static inline uint32_t read_flash_cr(stlink_t *sl, unsigned bank) {
- uint32_t reg, res;
-
- if (sl->flash_type == STLINK_FLASH_TYPE_F4) {
- reg = FLASH_F4_CR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) {
- reg = FLASH_F7_CR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) {
- reg = STM32L4_FLASH_CR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 ||
- sl->flash_type == STLINK_FLASH_TYPE_G4) {
- reg = STM32Gx_FLASH_CR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) {
- reg = STM32WB_FLASH_CR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) {
- reg = (bank == BANK_1) ? FLASH_H7_CR1 : FLASH_H7_CR2;
- } else {
- reg = (bank == BANK_1) ? FLASH_CR : FLASH_CR2;
- }
-
- stlink_read_debug32(sl, reg, &res);
-
-#if DEBUG_FLASH
- fprintf(stdout, "CR:0x%x\n", res);
-#endif
- return (res);
-}
-
-static inline unsigned int is_flash_locked(stlink_t *sl) {
- /* return non zero for true */
- uint32_t cr_lock_shift;
- uint32_t cr_reg;
- uint32_t n;
-
- if ((sl->flash_type == STLINK_FLASH_TYPE_F0) ||
- (sl->flash_type == STLINK_FLASH_TYPE_F1_XL)) {
- cr_reg = FLASH_CR;
- cr_lock_shift = FLASH_CR_LOCK;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F4) {
- cr_reg = FLASH_F4_CR;
- cr_lock_shift = FLASH_F4_CR_LOCK;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) {
- cr_reg = FLASH_F7_CR;
- cr_lock_shift = FLASH_F7_CR_LOCK;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) {
- cr_reg = get_stm32l0_flash_base(sl) + FLASH_PECR_OFF;
- cr_lock_shift = STM32L0_FLASH_PELOCK;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) {
- cr_reg = STM32L4_FLASH_CR;
- cr_lock_shift = STM32L4_FLASH_CR_LOCK;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 ||
- sl->flash_type == STLINK_FLASH_TYPE_G4) {
- cr_reg = STM32Gx_FLASH_CR;
- cr_lock_shift = STM32Gx_FLASH_CR_LOCK;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) {
- cr_reg = STM32WB_FLASH_CR;
- cr_lock_shift = STM32WB_FLASH_CR_LOCK;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) {
- cr_reg = FLASH_H7_CR1;
- cr_lock_shift = FLASH_H7_CR_LOCK;
- } else {
- ELOG("unsupported flash method, abort\n");
- return (-1);
- }
-
- stlink_read_debug32(sl, cr_reg, &n);
- return (n & (1u << cr_lock_shift));
-}
-
-static void unlock_flash(stlink_t *sl) {
- uint32_t key_reg, key2_reg = 0;
- uint32_t flash_key1 = FLASH_KEY1;
- uint32_t flash_key2 = FLASH_KEY2;
- /* The unlock sequence consists of 2 write cycles where 2 key values are
- * written to the FLASH_KEYR register. An invalid sequence results in a
- * definitive lock of the FPEC block until next reset.
- */
-
- if (sl->flash_type == STLINK_FLASH_TYPE_F0) {
- key_reg = FLASH_KEYR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F1_XL) {
- key_reg = FLASH_KEYR;
- key2_reg = FLASH_KEYR2;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F4) {
- key_reg = FLASH_F4_KEYR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) {
- key_reg = FLASH_F7_KEYR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) {
- key_reg = get_stm32l0_flash_base(sl) + FLASH_PEKEYR_OFF;
- flash_key1 = FLASH_L0_PEKEY1;
- flash_key2 = FLASH_L0_PEKEY2;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) {
- key_reg = STM32L4_FLASH_KEYR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 ||
- sl->flash_type == STLINK_FLASH_TYPE_G4) {
- key_reg = STM32Gx_FLASH_KEYR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) {
- key_reg = STM32WB_FLASH_KEYR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) {
- key_reg = FLASH_H7_KEYR1;
- if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) {
- key2_reg = FLASH_H7_KEYR2;
- }
- } else {
- ELOG("unsupported flash method, abort\n");
- return;
- }
-
- stlink_write_debug32(sl, key_reg, flash_key1);
- stlink_write_debug32(sl, key_reg, flash_key2);
-
- if (key2_reg) {
- stlink_write_debug32(sl, key2_reg, flash_key1);
- stlink_write_debug32(sl, key2_reg, flash_key2);
- }
-}
-
-/* unlock flash if already locked */
-static int unlock_flash_if(stlink_t *sl) {
- if (is_flash_locked(sl)) {
- unlock_flash(sl);
-
- if (is_flash_locked(sl)) {
- WLOG("Failed to unlock flash!\n");
- return (-1);
- }
- }
-
- DLOG("Successfully unlocked flash\n");
- return (0);
-}
-
-static void lock_flash(stlink_t *sl) {
- uint32_t cr_lock_shift, cr_reg, n, cr2_reg = 0;
- uint32_t cr_mask = 0xffffffffu;
-
- if (sl->flash_type == STLINK_FLASH_TYPE_F0) {
- cr_reg = FLASH_CR;
- cr_lock_shift = FLASH_CR_LOCK;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F1_XL) {
- cr_reg = FLASH_CR;
- cr2_reg = FLASH_CR2;
- cr_lock_shift = FLASH_CR_LOCK;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F4) {
- cr_reg = FLASH_F4_CR;
- cr_lock_shift = FLASH_F4_CR_LOCK;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) {
- cr_reg = FLASH_F7_CR;
- cr_lock_shift = FLASH_F7_CR_LOCK;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) {
- cr_reg = get_stm32l0_flash_base(sl) + FLASH_PECR_OFF;
- cr_lock_shift = STM32L0_FLASH_PELOCK;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) {
- cr_reg = STM32L4_FLASH_CR;
- cr_lock_shift = STM32L4_FLASH_CR_LOCK;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 ||
- sl->flash_type == STLINK_FLASH_TYPE_G4) {
- cr_reg = STM32Gx_FLASH_CR;
- cr_lock_shift = STM32Gx_FLASH_CR_LOCK;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) {
- cr_reg = STM32WB_FLASH_CR;
- cr_lock_shift = STM32WB_FLASH_CR_LOCK;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) {
- cr_reg = FLASH_H7_CR1;
- if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) {
- cr2_reg = FLASH_H7_CR2;
- }
- cr_lock_shift = FLASH_H7_CR_LOCK;
- cr_mask = ~(1u << FLASH_H7_CR_SER);
- } else {
- ELOG("unsupported flash method, abort\n");
- return;
- }
-
- stlink_read_debug32(sl, cr_reg, &n);
- n &= cr_mask;
- n |= (1u << cr_lock_shift);
- stlink_write_debug32(sl, cr_reg, n);
-
- if (cr2_reg) {
- n = read_flash_cr(sl, BANK_2) | (1u << cr_lock_shift);
- stlink_write_debug32(sl, cr2_reg, n);
- }
-}
-
-static bool is_flash_option_locked(stlink_t *sl) {
- uint32_t optlock_shift, optcr_reg;
- int active_bit_level = 1;
- uint32_t n;
-
- switch (sl->flash_type) {
- case STLINK_FLASH_TYPE_F0:
- case STLINK_FLASH_TYPE_F1_XL:
- optcr_reg = FLASH_CR;
- optlock_shift = FLASH_CR_OPTWRE;
- active_bit_level = 0; /* bit is "option write enable", not lock */
- break;
- case STLINK_FLASH_TYPE_F4:
- optcr_reg = FLASH_F4_OPTCR;
- optlock_shift = FLASH_F4_OPTCR_LOCK;
- break;
- case STLINK_FLASH_TYPE_F7:
- optcr_reg = FLASH_F7_OPTCR;
- optlock_shift = FLASH_F7_OPTCR_LOCK;
- break;
- case STLINK_FLASH_TYPE_L0:
- optcr_reg = get_stm32l0_flash_base(sl) + FLASH_PECR_OFF;
- optlock_shift = STM32L0_FLASH_OPTLOCK;
- break;
- case STLINK_FLASH_TYPE_L4:
- optcr_reg = STM32L4_FLASH_CR;
- optlock_shift = STM32L4_FLASH_CR_OPTLOCK;
- break;
- case STLINK_FLASH_TYPE_G0:
- case STLINK_FLASH_TYPE_G4:
- optcr_reg = STM32Gx_FLASH_CR;
- optlock_shift = STM32Gx_FLASH_CR_OPTLOCK;
- break;
- case STLINK_FLASH_TYPE_WB:
- optcr_reg = STM32WB_FLASH_CR;
- optlock_shift = STM32WB_FLASH_CR_OPTLOCK;
- break;
- case STLINK_FLASH_TYPE_H7:
- optcr_reg = FLASH_H7_OPTCR;
- optlock_shift = FLASH_H7_OPTCR_OPTLOCK;
- break;
- default:
- ELOG("unsupported flash method, abort\n");
- return -1;
- }
-
- stlink_read_debug32(sl, optcr_reg, &n);
-
- if (active_bit_level == 0) {
- return (!(n & (1u << optlock_shift)));
- }
-
- return (n & (1u << optlock_shift));
-}
-
-static int lock_flash_option(stlink_t *sl) {
- uint32_t optlock_shift, optcr_reg, n, optcr2_reg = 0;
- int active_bit_level = 1;
-
- switch (sl->flash_type) {
- case STLINK_FLASH_TYPE_F0:
- case STLINK_FLASH_TYPE_F1_XL:
- optcr_reg = FLASH_CR;
- optlock_shift = FLASH_CR_OPTWRE;
- active_bit_level = 0;
- break;
- case STLINK_FLASH_TYPE_F4:
- optcr_reg = FLASH_F4_OPTCR;
- optlock_shift = FLASH_F4_OPTCR_LOCK;
- break;
- case STLINK_FLASH_TYPE_F7:
- optcr_reg = FLASH_F7_OPTCR;
- optlock_shift = FLASH_F7_OPTCR_LOCK;
- break;
- case STLINK_FLASH_TYPE_L0:
- optcr_reg = get_stm32l0_flash_base(sl) + FLASH_PECR_OFF;
- optlock_shift = STM32L0_FLASH_OPTLOCK;
- break;
- case STLINK_FLASH_TYPE_L4:
- optcr_reg = STM32L4_FLASH_CR;
- optlock_shift = STM32L4_FLASH_CR_OPTLOCK;
- break;
- case STLINK_FLASH_TYPE_G0:
- case STLINK_FLASH_TYPE_G4:
- optcr_reg = STM32Gx_FLASH_CR;
- optlock_shift = STM32Gx_FLASH_CR_OPTLOCK;
- break;
- case STLINK_FLASH_TYPE_WB:
- optcr_reg = STM32WB_FLASH_CR;
- optlock_shift = STM32WB_FLASH_CR_OPTLOCK;
- break;
- case STLINK_FLASH_TYPE_H7:
- optcr_reg = FLASH_H7_OPTCR;
- optlock_shift = FLASH_H7_OPTCR_OPTLOCK;
- if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK)
- optcr2_reg = FLASH_H7_OPTCR2;
- break;
- default:
- ELOG("unsupported flash method, abort\n");
- return -1;
- }
-
- stlink_read_debug32(sl, optcr_reg, &n);
-
- if (active_bit_level == 0) {
- n &= ~(1u << optlock_shift);
- } else {
- n |= (1u << optlock_shift);
- }
-
- stlink_write_debug32(sl, optcr_reg, n);
-
- if (optcr2_reg) {
- stlink_read_debug32(sl, optcr2_reg, &n);
-
- if (active_bit_level == 0) {
- n &= ~(1u << optlock_shift);
- } else {
- n |= (1u << optlock_shift);
- }
-
- stlink_write_debug32(sl, optcr2_reg, n);
- }
-
- return (0);
-}
-
-static int unlock_flash_option(stlink_t *sl) {
- uint32_t optkey_reg, optkey2_reg = 0;
- uint32_t optkey1 = FLASH_OPTKEY1;
- uint32_t optkey2 = FLASH_OPTKEY2;
-
- switch (sl->flash_type) {
- case STLINK_FLASH_TYPE_F0:
- case STLINK_FLASH_TYPE_F1_XL:
- optkey_reg = FLASH_OPTKEYR;
- optkey1 = FLASH_F0_OPTKEY1;
- optkey2 = FLASH_F0_OPTKEY2;
- break;
- case STLINK_FLASH_TYPE_F4:
- optkey_reg = FLASH_F4_OPT_KEYR;
- break;
- case STLINK_FLASH_TYPE_F7:
- optkey_reg = FLASH_F7_OPT_KEYR;
- break;
- case STLINK_FLASH_TYPE_L0:
- optkey_reg = get_stm32l0_flash_base(sl) + FLASH_OPTKEYR_OFF;
- optkey1 = FLASH_L0_OPTKEY1;
- optkey2 = FLASH_L0_OPTKEY2;
- break;
- case STLINK_FLASH_TYPE_L4:
- optkey_reg = STM32L4_FLASH_OPTKEYR;
- break;
- case STLINK_FLASH_TYPE_G0:
- case STLINK_FLASH_TYPE_G4:
- optkey_reg = STM32Gx_FLASH_OPTKEYR;
- break;
- case STLINK_FLASH_TYPE_WB:
- optkey_reg = STM32WB_FLASH_OPT_KEYR;
- break;
- case STLINK_FLASH_TYPE_H7:
- optkey_reg = FLASH_H7_OPT_KEYR;
- if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK)
- optkey2_reg = FLASH_H7_OPT_KEYR2;
- break;
- default:
- ELOG("unsupported flash method, abort\n");
- return (-1);
- }
-
- stlink_write_debug32(sl, optkey_reg, optkey1);
- stlink_write_debug32(sl, optkey_reg, optkey2);
-
- if (optkey2_reg) {
- stlink_write_debug32(sl, optkey2_reg, optkey1);
- stlink_write_debug32(sl, optkey2_reg, optkey2);
- }
-
- return (0);
-}
-
-static int unlock_flash_option_if(stlink_t *sl) {
- if (is_flash_option_locked(sl)) {
- if (unlock_flash_option(sl)) {
- ELOG("Could not unlock flash option!\n");
- return (-1);
- }
-
- if (is_flash_option_locked(sl)) {
- ELOG("Failed to unlock flash option!\n");
- return (-1);
- }
- }
-
- DLOG("Successfully unlocked flash option\n");
- return (0);
-}
-
-static void set_flash_cr_pg(stlink_t *sl, unsigned bank) {
- uint32_t cr_reg, x;
-
- x = read_flash_cr(sl, bank);
-
- if (sl->flash_type == STLINK_FLASH_TYPE_F4) {
- cr_reg = FLASH_F4_CR;
- x |= 1 << FLASH_CR_PG;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) {
- cr_reg = FLASH_F7_CR;
- x |= 1 << FLASH_CR_PG;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) {
- cr_reg = STM32L4_FLASH_CR;
- x &= ~STM32L4_FLASH_CR_OPBITS;
- x |= (1 << STM32L4_FLASH_CR_PG);
- } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 ||
- sl->flash_type == STLINK_FLASH_TYPE_G4) {
- cr_reg = STM32Gx_FLASH_CR;
- x |= (1 << FLASH_CR_PG);
- } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) {
- cr_reg = STM32WB_FLASH_CR;
- x |= (1 << FLASH_CR_PG);
- } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) {
- cr_reg = (bank == BANK_1) ? FLASH_H7_CR1 : FLASH_H7_CR2;
- x |= (1 << FLASH_H7_CR_PG);
- } else {
- cr_reg = FLASH_CR;
- x = (1 << FLASH_CR_PG);
- }
-
- stlink_write_debug32(sl, cr_reg, x);
-}
-
-static void clear_flash_cr_pg(stlink_t *sl, unsigned bank) {
- uint32_t cr_reg, n;
- uint32_t bit = FLASH_CR_PG;
-
- if (sl->flash_type == STLINK_FLASH_TYPE_F4) {
- cr_reg = FLASH_F4_CR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) {
- cr_reg = FLASH_F7_CR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) {
- cr_reg = STM32L4_FLASH_CR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 ||
- sl->flash_type == STLINK_FLASH_TYPE_G4) {
- cr_reg = STM32Gx_FLASH_CR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) {
- cr_reg = STM32WB_FLASH_CR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) {
- cr_reg = (bank == BANK_1) ? FLASH_H7_CR1 : FLASH_H7_CR2;
- bit = FLASH_H7_CR_PG;
- } else {
- cr_reg = FLASH_CR;
- }
-
- n = read_flash_cr(sl, bank) & ~(1 << bit);
- stlink_write_debug32(sl, cr_reg, n);
-}
-
-static void set_flash_cr_per(stlink_t *sl, unsigned bank) {
- uint32_t cr_reg, val;
-
- if (sl->flash_type == STLINK_FLASH_TYPE_G0 ||
- sl->flash_type == STLINK_FLASH_TYPE_G4) {
- cr_reg = STM32Gx_FLASH_CR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) {
- cr_reg = STM32WB_FLASH_CR;
- } else {
- cr_reg = (bank == BANK_1) ? FLASH_CR : FLASH_CR2;
- }
-
- stlink_read_debug32(sl, cr_reg, &val);
- val |= (1 << FLASH_CR_PER);
- stlink_write_debug32(sl, cr_reg, val);
-}
-
-static void clear_flash_cr_per(stlink_t *sl, unsigned bank) {
- uint32_t cr_reg;
-
- if (sl->flash_type == STLINK_FLASH_TYPE_G0 ||
- sl->flash_type == STLINK_FLASH_TYPE_G4) {
- cr_reg = STM32Gx_FLASH_CR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) {
- cr_reg = STM32WB_FLASH_CR;
- } else {
- cr_reg = (bank == BANK_1) ? FLASH_CR : FLASH_CR2;
- }
-
- const uint32_t n = read_flash_cr(sl, bank) & ~(1 << FLASH_CR_PER);
- stlink_write_debug32(sl, cr_reg, n);
-}
-
-static void set_flash_cr_mer(stlink_t *sl, bool v, unsigned bank) {
- uint32_t val, cr_reg, cr_mer, cr_pg;
-
- if (sl->flash_type == STLINK_FLASH_TYPE_F4) {
- cr_reg = FLASH_F4_CR;
- cr_mer = 1 << FLASH_CR_MER;
- cr_pg = 1 << FLASH_CR_PG;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) {
- cr_reg = FLASH_F7_CR;
- cr_mer = 1 << FLASH_CR_MER;
- cr_pg = 1 << FLASH_CR_PG;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) {
- cr_reg = STM32L4_FLASH_CR;
- cr_mer = (1 << STM32L4_FLASH_CR_MER1) | (1 << STM32L4_FLASH_CR_MER2);
- cr_pg = (1 << STM32L4_FLASH_CR_PG);
- } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 ||
- sl->flash_type == STLINK_FLASH_TYPE_G4) {
- cr_reg = STM32Gx_FLASH_CR;
- cr_mer = (1 << STM32Gx_FLASH_CR_MER1);
-
- if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) {
- cr_mer |= (1 << STM32Gx_FLASH_CR_MER2);
- }
-
- cr_pg = (1 << FLASH_CR_PG);
- } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) {
- cr_reg = STM32WB_FLASH_CR;
- cr_mer = (1 << FLASH_CR_MER);
- cr_pg = (1 << FLASH_CR_PG);
- } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) {
- cr_reg = (bank == BANK_1) ? FLASH_H7_CR1 : FLASH_H7_CR2;
- cr_mer = (1 << FLASH_H7_CR_BER);
- cr_pg = (1 << FLASH_H7_CR_PG);
- } else {
- cr_reg = (bank == BANK_1) ? FLASH_CR : FLASH_CR2;
- cr_mer = (1 << FLASH_CR_MER);
- cr_pg = (1 << FLASH_CR_PG);
- }
-
- stlink_read_debug32(sl, cr_reg, &val);
-
- if (val & cr_pg) {
- // STM32F030 will drop MER bit if PG was set
- val &= ~cr_pg;
- stlink_write_debug32(sl, cr_reg, val);
- }
-
- if (v) {
- val |= cr_mer;
- } else {
- val &= ~cr_mer;
- }
-
- stlink_write_debug32(sl, cr_reg, val);
-}
-
-static void set_flash_cr_strt(stlink_t *sl, unsigned bank) {
- uint32_t val, cr_reg, cr_strt;
-
- if (sl->flash_type == STLINK_FLASH_TYPE_F4) {
- cr_reg = FLASH_F4_CR;
- cr_strt = 1 << FLASH_F4_CR_STRT;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) {
- cr_reg = FLASH_F7_CR;
- cr_strt = 1 << FLASH_F7_CR_STRT;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) {
- cr_reg = STM32L4_FLASH_CR;
- cr_strt = (1 << STM32L4_FLASH_CR_STRT);
- } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 ||
- sl->flash_type == STLINK_FLASH_TYPE_G4) {
- cr_reg = STM32Gx_FLASH_CR;
- cr_strt = (1 << STM32Gx_FLASH_CR_STRT);
- } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) {
- cr_reg = STM32WB_FLASH_CR;
- cr_strt = (1 << STM32WB_FLASH_CR_STRT);
- } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) {
- cr_reg = (bank == BANK_1) ? FLASH_H7_CR1 : FLASH_H7_CR2;
- cr_strt = 1 << FLASH_H7_CR_START(sl->chip_id);
- } else {
- cr_reg = (bank == BANK_1) ? FLASH_CR : FLASH_CR2;
- cr_strt = (1 << FLASH_CR_STRT);
- }
-
- stlink_read_debug32(sl, cr_reg, &val);
- val |= cr_strt;
- stlink_write_debug32(sl, cr_reg, val);
-}
-
-static inline uint32_t read_flash_sr(stlink_t *sl, unsigned bank) {
- uint32_t res, sr_reg;
-
- if ((sl->flash_type == STLINK_FLASH_TYPE_F0) ||
- (sl->flash_type == STLINK_FLASH_TYPE_F1_XL)) {
- sr_reg = (bank == BANK_1) ? FLASH_SR : FLASH_SR2;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) {
- sr_reg = get_stm32l0_flash_base(sl) + FLASH_SR_OFF;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F4) {
- sr_reg = FLASH_F4_SR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) {
- sr_reg = FLASH_F7_SR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) {
- sr_reg = STM32L4_FLASH_SR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 ||
- sl->flash_type == STLINK_FLASH_TYPE_G4) {
- sr_reg = STM32Gx_FLASH_SR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) {
- sr_reg = STM32WB_FLASH_SR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) {
- sr_reg = (bank == BANK_1) ? FLASH_H7_SR1 : FLASH_H7_SR2;
- } else {
- ELOG("method 'read_flash_sr' is unsupported\n");
- return (-1);
- }
-
- stlink_read_debug32(sl, sr_reg, &res);
- return (res);
-}
-
-static inline int write_flash_sr(stlink_t *sl, unsigned bank, uint32_t val) {
- uint32_t sr_reg;
-
- if ((sl->flash_type == STLINK_FLASH_TYPE_F0) ||
- (sl->flash_type == STLINK_FLASH_TYPE_F1_XL)) {
- sr_reg = (bank == BANK_1) ? FLASH_SR : FLASH_SR2;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) {
- sr_reg = get_stm32l0_flash_base(sl) + FLASH_SR_OFF;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F4) {
- sr_reg = FLASH_F4_SR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) {
- sr_reg = FLASH_F7_SR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) {
- sr_reg = STM32L4_FLASH_SR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 ||
- sl->flash_type == STLINK_FLASH_TYPE_G4) {
- sr_reg = STM32Gx_FLASH_SR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) {
- sr_reg = STM32WB_FLASH_SR;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) {
- sr_reg = (bank == BANK_1) ? FLASH_H7_SR1 : FLASH_H7_SR2;
- } else {
- ELOG("method 'write_flash_sr' is unsupported\n");
- return (-1);
- }
-
- return stlink_write_debug32(sl, sr_reg, val);
-}
-
-static inline unsigned int is_flash_busy(stlink_t *sl) {
- uint32_t sr_busy_shift;
- unsigned int res;
-
- if ((sl->flash_type == STLINK_FLASH_TYPE_F0) ||
- (sl->flash_type == STLINK_FLASH_TYPE_F1_XL) ||
- (sl->flash_type == STLINK_FLASH_TYPE_L0)) {
- sr_busy_shift = FLASH_SR_BSY;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F4) {
- sr_busy_shift = FLASH_F4_SR_BSY;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F7) {
- sr_busy_shift = FLASH_F7_SR_BSY;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) {
- sr_busy_shift = STM32L4_FLASH_SR_BSY;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_G0 ||
- sl->flash_type == STLINK_FLASH_TYPE_G4) {
- sr_busy_shift = STM32Gx_FLASH_SR_BSY;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) {
- sr_busy_shift = STM32WB_FLASH_SR_BSY;
- } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) {
- sr_busy_shift = FLASH_H7_SR_QW;
- } else {
- ELOG("method 'is_flash_busy' is unsupported\n");
- return (-1);
- }
-
- res = read_flash_sr(sl, BANK_1) & (1 << sr_busy_shift);
-
- if (sl->flash_type == STLINK_FLASH_TYPE_F1_XL ||
- (sl->flash_type == STLINK_FLASH_TYPE_H7 &&
- sl->chip_flags & CHIP_F_HAS_DUAL_BANK)) {
- res |= read_flash_sr(sl, BANK_2) & (1 << sr_busy_shift);
- }
-
- return (res);
-}
-
-static void wait_flash_busy(stlink_t *sl) {
- // TODO: add some delays here
- while (is_flash_busy(sl))
- ;
-}
-
-static void wait_flash_busy_progress(stlink_t *sl) {
- int i = 0;
- fprintf(stdout, "Mass erasing");
- fflush(stdout);
-
- while (is_flash_busy(sl)) {
- usleep(10000);
- i++;
-
- if (i % 100 == 0) {
- fprintf(stdout, ".");
- fflush(stdout);
- }
- }
-
- fprintf(stdout, "\n");
-}
-
-static void clear_flash_error(stlink_t *sl) {
- switch (sl->flash_type) {
- case STLINK_FLASH_TYPE_F0:
- write_flash_sr(sl, BANK_1, FLASH_SR_ERROR_MASK);
- break;
- case STLINK_FLASH_TYPE_F4:
- write_flash_sr(sl, BANK_1, FLASH_F4_SR_ERROR_MASK);
- break;
- case STLINK_FLASH_TYPE_F7:
- write_flash_sr(sl, BANK_1, FLASH_F7_SR_ERROR_MASK);
- break;
- case STLINK_FLASH_TYPE_G0:
- case STLINK_FLASH_TYPE_G4:
- write_flash_sr(sl, BANK_1, STM32Gx_FLASH_SR_ERROR_MASK);
- break;
- case STLINK_FLASH_TYPE_L0:
- write_flash_sr(sl, BANK_1, STM32L0_FLASH_SR_ERROR_MASK);
- break;
- case STLINK_FLASH_TYPE_L4:
- write_flash_sr(sl, BANK_1, STM32L4_FLASH_SR_ERROR_MASK);
- break;
- case STLINK_FLASH_TYPE_H7:
- write_flash_sr(sl, BANK_1, FLASH_H7_SR_ERROR_MASK);
- if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) {
- write_flash_sr(sl, BANK_2, FLASH_H7_SR_ERROR_MASK);
- }
- break;
- case STLINK_FLASH_TYPE_WB:
- write_flash_sr(sl, BANK_1, STM32WB_FLASH_SR_ERROR_MASK);
- break;
- default:
- break;
- }
-}
-
-static int check_flash_error(stlink_t *sl) {
- uint32_t res = 0;
- uint32_t WRPERR, PROGERR, PGAERR;
-
- WRPERR = PROGERR = PGAERR = 0;
-
- switch (sl->flash_type) {
- case STLINK_FLASH_TYPE_F0:
- case STLINK_FLASH_TYPE_F1_XL:
- res = read_flash_sr(sl, BANK_1) & FLASH_SR_ERROR_MASK;
- if (sl->flash_type == STLINK_FLASH_TYPE_F1_XL) {
- res |= read_flash_sr(sl, BANK_2) & FLASH_SR_ERROR_MASK;
- }
- WRPERR = (1 << FLASH_SR_WRPRT_ERR);
- PROGERR = (1 << FLASH_SR_PG_ERR);
- break;
- case STLINK_FLASH_TYPE_F4:
- res = read_flash_sr(sl, BANK_1) & FLASH_F4_SR_ERROR_MASK;
- WRPERR = (1 << FLASH_F4_SR_WRPERR);
- PGAERR = (1 << FLASH_F4_SR_PGAERR);
- break;
- case STLINK_FLASH_TYPE_F7:
- res = read_flash_sr(sl, BANK_1) & FLASH_F7_SR_ERROR_MASK;
- WRPERR = (1 << FLASH_F7_SR_WRP_ERR);
- PROGERR = (1 << FLASH_F7_SR_PGP_ERR);
- break;
- case STLINK_FLASH_TYPE_G0:
- case STLINK_FLASH_TYPE_G4:
- res = read_flash_sr(sl, BANK_1) & STM32Gx_FLASH_SR_ERROR_MASK;
- WRPERR = (1 << STM32Gx_FLASH_SR_WRPERR);
- PROGERR = (1 << STM32Gx_FLASH_SR_PROGERR);
- PGAERR = (1 << STM32Gx_FLASH_SR_PGAERR);
- break;
- case STLINK_FLASH_TYPE_L0:
- res = read_flash_sr(sl, BANK_1) & STM32L0_FLASH_SR_ERROR_MASK;
- WRPERR = (1 << STM32L0_FLASH_SR_WRPERR);
- PROGERR = (1 << STM32L0_FLASH_SR_NOTZEROERR);
- PGAERR = (1 << STM32L0_FLASH_SR_PGAERR);
- break;
- case STLINK_FLASH_TYPE_L4:
- res = read_flash_sr(sl, BANK_1) & STM32L4_FLASH_SR_ERROR_MASK;
- WRPERR = (1 << STM32L4_FLASH_SR_WRPERR);
- PROGERR = (1 << STM32L4_FLASH_SR_PROGERR);
- PGAERR = (1 << STM32L4_FLASH_SR_PGAERR);
- break;
- case STLINK_FLASH_TYPE_H7:
- res = read_flash_sr(sl, BANK_1) & FLASH_H7_SR_ERROR_MASK;
- if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) {
- res |= read_flash_sr(sl, BANK_2) & FLASH_H7_SR_ERROR_MASK;
- }
- WRPERR = (1 << FLASH_H7_SR_WRPERR);
- break;
- case STLINK_FLASH_TYPE_WB:
- res = read_flash_sr(sl, BANK_1) & STM32WB_FLASH_SR_ERROR_MASK;
- WRPERR = (1 << STM32WB_FLASH_SR_WRPERR);
- PROGERR = (1 << STM32WB_FLASH_SR_PROGERR);
- PGAERR = (1 << STM32WB_FLASH_SR_PGAERR);
- break;
- default:
- break;
- }
-
- if (res) {
- if (WRPERR && (WRPERR & res) == WRPERR) {
- ELOG("Flash memory is write protected\n");
- res &= ~WRPERR;
- } else if (PROGERR && (PROGERR & res) == PROGERR) {
- ELOG("Flash memory contains a non-erased value\n");
- res &= ~PROGERR;
- } else if (PGAERR && (PGAERR & res) == PGAERR) {
- ELOG("Invalid flash address\n");
- res &= ~PGAERR;
- }
-
- if (res) {
- ELOG("Flash programming error: %#010x\n", res);
- }
- return (-1);
- }
-
- return (0);
-}
-
-static void stop_wdg_in_debug(stlink_t *sl) {
- uint32_t dbgmcu_cr;
- uint32_t set;
- uint32_t value;
-
- switch (sl->flash_type) {
- case STLINK_FLASH_TYPE_F0:
- case STLINK_FLASH_TYPE_F1_XL:
- case STLINK_FLASH_TYPE_G4:
- dbgmcu_cr = STM32F0_DBGMCU_CR;
- set =
- (1 << STM32F0_DBGMCU_CR_IWDG_STOP) | (1 << STM32F0_DBGMCU_CR_WWDG_STOP);
- break;
- case STLINK_FLASH_TYPE_F4:
- case STLINK_FLASH_TYPE_F7:
- case STLINK_FLASH_TYPE_L4:
- dbgmcu_cr = STM32F4_DBGMCU_APB1FZR1;
- set = (1 << STM32F4_DBGMCU_APB1FZR1_IWDG_STOP) |
- (1 << STM32F4_DBGMCU_APB1FZR1_WWDG_STOP);
- break;
- case STLINK_FLASH_TYPE_L0:
- case STLINK_FLASH_TYPE_G0:
- dbgmcu_cr = STM32L0_DBGMCU_APB1_FZ;
- set = (1 << STM32L0_DBGMCU_APB1_FZ_IWDG_STOP) |
- (1 << STM32L0_DBGMCU_APB1_FZ_WWDG_STOP);
- break;
- case STLINK_FLASH_TYPE_H7:
- dbgmcu_cr = STM32H7_DBGMCU_APB1HFZ;
- set = (1 << STM32H7_DBGMCU_APB1HFZ_IWDG_STOP);
- break;
- case STLINK_FLASH_TYPE_WB:
- dbgmcu_cr = STM32WB_DBGMCU_APB1FZR1;
- set = (1 << STM32WB_DBGMCU_APB1FZR1_IWDG_STOP) |
- (1 << STM32WB_DBGMCU_APB1FZR1_WWDG_STOP);
- break;
- default:
- return;
- }
-
- if (!stlink_read_debug32(sl, dbgmcu_cr, &value)) {
- stlink_write_debug32(sl, dbgmcu_cr, value | set);
- }
-}
-
-static void set_dma_state(stlink_t *sl, flash_loader_t *fl, int bckpRstr) {
- uint32_t rcc, rcc_dma_mask, value;
-
- rcc = rcc_dma_mask = value = 0;
-
- switch (sl->flash_type) {
- case STLINK_FLASH_TYPE_F0:
- case STLINK_FLASH_TYPE_F1_XL:
- rcc = STM32F1_RCC_AHBENR;
- rcc_dma_mask = STM32F1_RCC_DMAEN;
- break;
- case STLINK_FLASH_TYPE_F4:
- case STLINK_FLASH_TYPE_F7:
- rcc = STM32F4_RCC_AHB1ENR;
- rcc_dma_mask = STM32F4_RCC_DMAEN;
- break;
- case STLINK_FLASH_TYPE_G0:
- rcc = STM32G0_RCC_AHBENR;
- rcc_dma_mask = STM32G0_RCC_DMAEN;
- break;
- case STLINK_FLASH_TYPE_G4:
- case STLINK_FLASH_TYPE_L4:
- rcc = STM32G4_RCC_AHB1ENR;
- rcc_dma_mask = STM32G4_RCC_DMAEN;
- break;
- case STLINK_FLASH_TYPE_L0:
- rcc = STM32L0_RCC_AHBENR;
- rcc_dma_mask = STM32L0_RCC_DMAEN;
- break;
- case STLINK_FLASH_TYPE_H7:
- rcc = STM32H7_RCC_AHB1ENR;
- rcc_dma_mask = STM32H7_RCC_DMAEN;
- break;
- case STLINK_FLASH_TYPE_WB:
- rcc = STM32WB_RCC_AHB1ENR;
- rcc_dma_mask = STM32WB_RCC_DMAEN;
- break;
- default:
- return;
- }
-
- if (!stlink_read_debug32(sl, rcc, &value)) {
- if (bckpRstr) {
- value = (value & (~rcc_dma_mask)) | fl->rcc_dma_bkp;
- } else {
- fl->rcc_dma_bkp = value & rcc_dma_mask;
- value &= ~rcc_dma_mask;
- }
- stlink_write_debug32(sl, rcc, value);
- }
-}
-
-static inline void write_flash_ar(stlink_t *sl, uint32_t n, unsigned bank) {
- stlink_write_debug32(sl, (bank == BANK_1) ? FLASH_AR : FLASH_AR2, n);
-}
-
-static inline void write_flash_cr_psiz(stlink_t *sl, uint32_t n,
- unsigned bank) {
- uint32_t cr_reg, psize_shift;
- uint32_t x = read_flash_cr(sl, bank);
-
- if (sl->flash_type == STLINK_FLASH_TYPE_H7) {
- cr_reg = (bank == BANK_1) ? FLASH_H7_CR1 : FLASH_H7_CR2;
- psize_shift = FLASH_H7_CR_PSIZE;
- } else {
- cr_reg = FLASH_F4_CR;
- psize_shift = 8;
- }
-
- x &= ~(0x03 << psize_shift);
- x |= (n << psize_shift);
-#if DEBUG_FLASH
- fprintf(stdout, "PSIZ:0x%x 0x%x\n", x, n);
-#endif
- stlink_write_debug32(sl, cr_reg, x);
-}
-
-static inline void write_flash_cr_snb(stlink_t *sl, uint32_t n, unsigned bank) {
- uint32_t cr_reg, snb_mask, snb_shift, ser_shift;
- uint32_t x = read_flash_cr(sl, bank);
-
- if (sl->flash_type == STLINK_FLASH_TYPE_H7) {
- cr_reg = (bank == BANK_1) ? FLASH_H7_CR1 : FLASH_H7_CR2;
- snb_mask = FLASH_H7_CR_SNB_MASK;
- snb_shift = FLASH_H7_CR_SNB;
- ser_shift = FLASH_H7_CR_SER;
- } else {
- cr_reg = FLASH_F4_CR;
- snb_mask = FLASH_F4_CR_SNB_MASK;
- snb_shift = FLASH_F4_CR_SNB;
- ser_shift = FLASH_F4_CR_SER;
- }
-
- x &= ~snb_mask;
- x |= (n << snb_shift);
- x |= (1 << ser_shift);
-#if DEBUG_FLASH
- fprintf(stdout, "SNB:0x%x 0x%x\n", x, n);
-#endif
- stlink_write_debug32(sl, cr_reg, x);
-}
-
-static inline void write_flash_cr_bker_pnb(stlink_t *sl, uint32_t n) {
- stlink_write_debug32(sl, STM32L4_FLASH_SR,
- 0xFFFFFFFF & ~(1 << STM32L4_FLASH_SR_BSY));
- uint32_t x = read_flash_cr(sl, BANK_1);
- x &= ~STM32L4_FLASH_CR_OPBITS;
- x &= ~STM32L4_FLASH_CR_PAGEMASK;
- x &= ~(1 << STM32L4_FLASH_CR_MER1);
- x &= ~(1 << STM32L4_FLASH_CR_MER2);
- x |= (n << STM32L4_FLASH_CR_PNB);
- x |= (uint32_t)(1lu << STM32L4_FLASH_CR_PER);
-#if DEBUG_FLASH
- fprintf(stdout, "BKER:PNB:0x%x 0x%x\n", x, n);
-#endif
- stlink_write_debug32(sl, STM32L4_FLASH_CR, x);
-}
-
-// Delegates to the backends...
-
-void stlink_close(stlink_t *sl) {
- DLOG("*** stlink_close ***\n");
-
- if (!sl) {
- return;
- }
-
- sl->backend->close(sl);
- free(sl);
-}
-
-int stlink_exit_debug_mode(stlink_t *sl) {
- int ret;
-
- DLOG("*** stlink_exit_debug_mode ***\n");
- ret = stlink_write_debug32(sl, STLINK_REG_DHCSR, STLINK_REG_DHCSR_DBGKEY);
-
- if (ret == -1) {
- return (ret);
- }
-
- return (sl->backend->exit_debug_mode(sl));
-}
-
-int stlink_enter_swd_mode(stlink_t *sl) {
- DLOG("*** stlink_enter_swd_mode ***\n");
- return (sl->backend->enter_swd_mode(sl));
-}
-
-// Force the core into the debug mode -> halted state.
-int stlink_force_debug(stlink_t *sl) {
- DLOG("*** stlink_force_debug_mode ***\n");
- int res = sl->backend->force_debug(sl);
- // Stop the watchdogs in the halted state for suppress target reboot
- stop_wdg_in_debug(sl);
- return (res);
-}
-
-int stlink_exit_dfu_mode(stlink_t *sl) {
- DLOG("*** stlink_exit_dfu_mode ***\n");
- return (sl->backend->exit_dfu_mode(sl));
-}
-
-int stlink_core_id(stlink_t *sl) {
- int ret;
-
- DLOG("*** stlink_core_id ***\n");
- ret = sl->backend->core_id(sl);
-
- if (ret == -1) {
- ELOG("Failed to read core_id\n");
- return (ret);
- }
-
- if (sl->verbose > 2) {
- stlink_print_data(sl);
- }
-
- DLOG("core_id = 0x%08x\n", sl->core_id);
- return (ret);
-}
-
-// stlink_chip_id() is called by stlink_load_device_params()
-// do not call this procedure directly.
-int stlink_chip_id(stlink_t *sl, uint32_t *chip_id) {
- int ret;
- cortex_m3_cpuid_t cpu_id;
-
- // Read the CPU ID to determine where to read the core id
- if (stlink_cpu_id(sl, &cpu_id) ||
- cpu_id.implementer_id != STLINK_REG_CMx_CPUID_IMPL_ARM) {
- ELOG("Can not connect to target. Please use \'connect under reset\' and "
- "try again\n");
- return -1;
- }
-
- /*
- * the chip_id register in the reference manual have
- * DBGMCU_IDCODE / DBG_IDCODE name
- *
- */
-
- if ((sl->core_id == STM32H7_CORE_ID || sl->core_id == STM32H7_CORE_ID_JTAG) &&
- cpu_id.part == STLINK_REG_CMx_CPUID_PARTNO_CM7) {
- // STM32H7 chipid in 0x5c001000 (RM0433 pg3189)
- ret = stlink_read_debug32(sl, 0x5c001000, chip_id);
- } else if (cpu_id.part == STLINK_REG_CMx_CPUID_PARTNO_CM0 ||
- cpu_id.part == STLINK_REG_CMx_CPUID_PARTNO_CM0P) {
- // STM32F0 (RM0091, pg914; RM0360, pg713)
- // STM32L0 (RM0377, pg813; RM0367, pg915; RM0376, pg917)
- // STM32G0 (RM0444, pg1367)
- ret = stlink_read_debug32(sl, 0x40015800, chip_id);
- } else if (cpu_id.part == STLINK_REG_CMx_CPUID_PARTNO_CM33) {
- // STM32L5 (RM0438, pg2157)
- ret = stlink_read_debug32(sl, 0xE0044000, chip_id);
- } else /* ДM3, ДM4, CM7 */ {
- // default chipid address
-
- // STM32F1 (RM0008, pg1087; RM0041, pg681)
- // STM32F2 (RM0033, pg1326)
- // STM32F3 (RM0316, pg1095; RM0313, pg874)
- // STM32F7 (RM0385, pg1676; RM0410, pg1912)
- // STM32L1 (RM0038, pg861)
- // STM32L4 (RM0351, pg1840; RM0394, pg1560)
- // STM32G4 (RM0440, pg2086)
- // STM32WB (RM0434, pg1406)
- ret = stlink_read_debug32(sl, 0xE0042000, chip_id);
- }
-
- if (ret || !(*chip_id)) {
- *chip_id = 0;
- ELOG("Could not find chip id!\n");
- } else {
- *chip_id = (*chip_id) & 0xfff;
-
- // Fix chip_id for F4 rev A errata, read CPU ID, as CoreID is the same for
- // F2/F4
- if (*chip_id == 0x411 && cpu_id.part == STLINK_REG_CMx_CPUID_PARTNO_CM4) {
- *chip_id = 0x413;
- }
- }
-
- return (ret);
-}
-
-/**
- * Cortex M tech ref manual, CPUID register description
- * @param sl stlink context
- * @param cpuid pointer to the result object
- */
-int stlink_cpu_id(stlink_t *sl, cortex_m3_cpuid_t *cpuid) {
- uint32_t raw;
-
- if (stlink_read_debug32(sl, STLINK_REG_CM3_CPUID, &raw)) {
- cpuid->implementer_id = 0;
- cpuid->variant = 0;
- cpuid->part = 0;
- cpuid->revision = 0;
- return (-1);
- }
-
- cpuid->implementer_id = (raw >> 24) & 0x7f;
- cpuid->variant = (raw >> 20) & 0xf;
- cpuid->part = (raw >> 4) & 0xfff;
- cpuid->revision = raw & 0xf;
- return (0);
-}
-
-/**
- * Reads and decodes the flash parameters, as dynamically as possible
- * @param sl
- * @return 0 for success, or -1 for unsupported core type.
- */
-int stlink_load_device_params(stlink_t *sl) {
- // This seems to normally work so is unnecessary info for a normal user.
- // Demoted to debug. -- REW
- DLOG("Loading device parameters....\n");
- const struct stlink_chipid_params *params = NULL;
- stlink_core_id(sl);
- uint32_t flash_size;
-
- if (stlink_chip_id(sl, &sl->chip_id)) {
- return (-1);
- }
-
- params = stlink_chipid_get_params(sl->chip_id);
-
- if (params == NULL) {
- WLOG("unknown chip id! %#x\n", sl->chip_id);
- return (-1);
- }
-
- if (params->flash_type == STLINK_FLASH_TYPE_UNKNOWN) {
- WLOG("Invalid flash type, please check device declaration\n");
- sl->flash_size = 0;
- return (0);
- }
-
- // These are fixed...
- sl->flash_base = STM32_FLASH_BASE;
- sl->sram_base = STM32_SRAM_BASE;
- stlink_read_debug32(sl, (params->flash_size_reg) & ~3, &flash_size);
-
- if (params->flash_size_reg & 2) {
- flash_size = flash_size >> 16;
- }
-
- flash_size = flash_size & 0xffff;
-
- if ((sl->chip_id == STLINK_CHIPID_STM32_L1_MEDIUM ||
- sl->chip_id == STLINK_CHIPID_STM32_F1_VL_MEDIUM_LOW ||
- sl->chip_id == STLINK_CHIPID_STM32_L1_MEDIUM_PLUS) &&
- (flash_size == 0)) {
- sl->flash_size = 128 * 1024;
- } else if (sl->chip_id == STLINK_CHIPID_STM32_L1_CAT2) {
- sl->flash_size = (flash_size & 0xff) * 1024;
- } else if ((sl->chip_id & 0xFFF) == STLINK_CHIPID_STM32_L1_HIGH) {
- // 0 is 384k and 1 is 256k
- if (flash_size == 0) {
- sl->flash_size = 384 * 1024;
- } else {
- sl->flash_size = 256 * 1024;
- }
- } else {
- sl->flash_size = flash_size * 1024;
- }
-
- sl->flash_type = params->flash_type;
- sl->flash_pgsz = params->flash_pagesize;
- sl->sram_size = params->sram_size;
- sl->sys_base = params->bootrom_base;
- sl->sys_size = params->bootrom_size;
- sl->option_base = params->option_base;
- sl->option_size = params->option_size;
- sl->chip_flags = params->flags;
-
- // medium and low devices have the same chipid. ram size depends on flash
- // size. STM32F100xx datasheet Doc ID 16455 Table 2
- if (sl->chip_id == STLINK_CHIPID_STM32_F1_VL_MEDIUM_LOW &&
- sl->flash_size < 64 * 1024) {
- sl->sram_size = 0x1000;
- }
-
- if (sl->chip_id == STLINK_CHIPID_STM32_G4_CAT3) {
- uint32_t flash_optr;
- stlink_read_debug32(sl, STM32Gx_FLASH_OPTR, &flash_optr);
-
- if (!(flash_optr & (1 << STM32G4_FLASH_OPTR_DBANK))) {
- sl->flash_pgsz <<= 1;
- }
- }
-
- // H7 devices with small flash has one bank
- if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK &&
- sl->flash_type == STLINK_FLASH_TYPE_H7) {
- if ((flash_size / sl->flash_pgsz) <= 1)
- sl->chip_flags &= ~CHIP_F_HAS_DUAL_BANK;
- }
-
- ILOG("%s: %u KiB SRAM, %u KiB flash in at least %u %s pages.\n",
- params->description, (unsigned)(sl->sram_size / 1024),
- (unsigned)(sl->flash_size / 1024),
- (sl->flash_pgsz < 1024) ? (unsigned)(sl->flash_pgsz)
- : (unsigned)(sl->flash_pgsz / 1024),
- (sl->flash_pgsz < 1024) ? "byte" : "KiB");
-
- return (0);
-}
-
-int stlink_jtag_reset(stlink_t *sl, int value) {
- DLOG("*** stlink_jtag_reset ***\n");
- return (sl->backend->jtag_reset(sl, value));
-}
-
-int stlink_soft_reset(stlink_t *sl, int halt_on_reset) {
- int ret;
- unsigned timeout;
- uint32_t dhcsr, dfsr;
-
- DLOG("*** stlink_soft_reset %s***\n", halt_on_reset ? "(halt) " : "");
-
- // halt core and enable debugging (if not already done)
- // C_DEBUGEN is required to Halt on reset (DDI0337E, p. 10-6)
- stlink_write_debug32(sl, STLINK_REG_DHCSR,
- STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_HALT |
- STLINK_REG_DHCSR_C_DEBUGEN);
-
- // enable Halt on reset by set VC_CORERESET and TRCENA (DDI0337E, p. 10-10)
- if (halt_on_reset) {
- stlink_write_debug32(
- sl, STLINK_REG_CM3_DEMCR,
- STLINK_REG_CM3_DEMCR_TRCENA | STLINK_REG_CM3_DEMCR_VC_HARDERR |
- STLINK_REG_CM3_DEMCR_VC_BUSERR | STLINK_REG_CM3_DEMCR_VC_CORERESET);
-
- // clear VCATCH in the DFSR register
- stlink_write_debug32(sl, STLINK_REG_DFSR, STLINK_REG_DFSR_VCATCH);
- } else {
- stlink_write_debug32(sl, STLINK_REG_CM3_DEMCR,
- STLINK_REG_CM3_DEMCR_TRCENA |
- STLINK_REG_CM3_DEMCR_VC_HARDERR |
- STLINK_REG_CM3_DEMCR_VC_BUSERR);
- }
-
- // clear S_RESET_ST in the DHCSR register
- stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr);
-
- // soft reset (core reset) by SYSRESETREQ (DDI0337E, p. 8-23)
- ret = stlink_write_debug32(sl, STLINK_REG_AIRCR,
- STLINK_REG_AIRCR_VECTKEY |
- STLINK_REG_AIRCR_SYSRESETREQ);
- if (ret) {
- ELOG("Soft reset failed: error write to AIRCR\n");
- return (ret);
- }
-
- // waiting for a reset within 500ms
- // DDI0337E, p. 10-4, Debug Halting Control and Status Register
- timeout = time_ms() + 500;
- while (time_ms() < timeout) {
- // DDI0337E, p. 10-4, Debug Halting Control and Status Register
- dhcsr = STLINK_REG_DHCSR_S_RESET_ST;
- stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr);
- if ((dhcsr & STLINK_REG_DHCSR_S_RESET_ST) == 0) {
- if (halt_on_reset) {
- // waiting halt by the SYSRESETREQ exception
- // DDI0403E, p. C1-699, Debug Fault Status Register
- dfsr = 0;
- stlink_read_debug32(sl, STLINK_REG_DFSR, &dfsr);
- if ((dfsr & STLINK_REG_DFSR_VCATCH) == 0) {
- continue;
- }
- }
- timeout = 0;
- break;
- }
- }
-
- // reset DFSR register. DFSR is power-on reset only (DDI0337H, p. 7-5)
- stlink_write_debug32(sl, STLINK_REG_DFSR, STLINK_REG_DFSR_CLEAR);
-
- if (timeout) {
- ELOG("Soft reset failed: timeout\n");
- return (-1);
- }
-
- return (0);
-}
-
-int stlink_reset(stlink_t *sl, enum reset_type type) {
- uint32_t dhcsr;
- unsigned timeout;
-
- DLOG("*** stlink_reset ***\n");
-
- if (type == RESET_AUTO) {
- // clear S_RESET_ST in DHCSR register for reset state detection
- stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr);
- }
-
- if (type == RESET_HARD || type == RESET_AUTO) {
- // hardware target reset
- if (sl->version.stlink_v > 1) {
- stlink_jtag_reset(sl, STLINK_JTAG_DRIVE_NRST_LOW);
- // minimum reset pulse duration of 20 us (RM0008, 8.1.2 Power reset)
- usleep(100);
- stlink_jtag_reset(sl, STLINK_JTAG_DRIVE_NRST_HIGH);
- }
- if (sl->backend->reset(sl)) {
- return (-1);
- }
- usleep(10000);
- }
-
- if (type == RESET_AUTO) {
- /* Check if the S_RESET_ST bit is set in DHCSR
- * This means that a reset has occurred
- * DDI0337E, p. 10-4, Debug Halting Control and Status Register */
-
- dhcsr = 0;
- stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr);
- if ((dhcsr & STLINK_REG_DHCSR_S_RESET_ST) == 0) {
- // reset not done yet
- // try reset through AIRCR so that NRST does not need to be connected
-
- WLOG("NRST is not connected\n");
- DLOG("Using reset through SYSRESETREQ\n");
- return stlink_soft_reset(sl, 0);
- }
-
- // waiting for reset the S_RESET_ST bit within 500ms
- timeout = time_ms() + 500;
- while (time_ms() < timeout) {
- dhcsr = STLINK_REG_DHCSR_S_RESET_ST;
- stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr);
- if ((dhcsr & STLINK_REG_DHCSR_S_RESET_ST) == 0)
- return (0);
- }
-
- return (-1);
- }
-
- if (type == RESET_SOFT || type == RESET_SOFT_AND_HALT) {
- return stlink_soft_reset(sl, (type == RESET_SOFT_AND_HALT));
- }
-
- return (0);
-}
-
-int stlink_run(stlink_t *sl, enum run_type type) {
- struct stlink_reg rr;
- DLOG("*** stlink_run ***\n");
-
- /* Make sure we are in Thumb mode
- * Cortex-M chips don't support ARM mode instructions
- * xPSR may be incorrect if the vector table has invalid data */
- stlink_read_reg(sl, 16, &rr);
- if ((rr.xpsr & (1 << 24)) == 0) {
- ILOG("Go to Thumb mode\n");
- stlink_write_reg(sl, rr.xpsr | (1 << 24), 16);
- }
-
- return (sl->backend->run(sl, type));
-}
-
-int stlink_set_swdclk(stlink_t *sl, int freq_khz) {
- DLOG("*** set_swdclk ***\n");
- return (sl->backend->set_swdclk(sl, freq_khz));
-}
-
-int stlink_status(stlink_t *sl) {
- int ret;
-
- DLOG("*** stlink_status ***\n");
- ret = sl->backend->status(sl);
- stlink_core_stat(sl);
- return (ret);
-}
-
-/**
- * Decode the version bits, originally from -sg, verified with usb
- * @param sl stlink context, assumed to contain valid data in the buffer
- * @param slv output parsed version object
- */
-void _parse_version(stlink_t *sl, stlink_version_t *slv) {
- sl->version.flags = 0;
-
- if (sl->version.stlink_v < 3) {
- uint32_t b0 = sl->q_buf[0]; // lsb
- uint32_t b1 = sl->q_buf[1];
- uint32_t b2 = sl->q_buf[2];
- uint32_t b3 = sl->q_buf[3];
- uint32_t b4 = sl->q_buf[4];
- uint32_t b5 = sl->q_buf[5]; // msb
-
- // b0 b1 || b2 b3 | b4 b5
- // 4b | 6b | 6b || 2B | 2B
- // stlink_v | jtag_v | swim_v || st_vid | stlink_pid
-
- slv->stlink_v = (b0 & 0xf0) >> 4;
- slv->jtag_v = ((b0 & 0x0f) << 2) | ((b1 & 0xc0) >> 6);
- slv->swim_v = b1 & 0x3f;
- slv->st_vid = (b3 << 8) | b2;
- slv->stlink_pid = (b5 << 8) | b4;
-
- // ST-LINK/V1 from J11 switch to api-v2 (and support SWD)
- if (slv->stlink_v == 1) {
- slv->jtag_api =
- slv->jtag_v > 11 ? STLINK_JTAG_API_V2 : STLINK_JTAG_API_V1;
- } else {
- slv->jtag_api = STLINK_JTAG_API_V2;
-
- // preferred API to get last R/W status from J15
- if (sl->version.jtag_v >= 15) {
- sl->version.flags |= STLINK_F_HAS_GETLASTRWSTATUS2;
- }
-
- if (sl->version.jtag_v >= 13) {
- sl->version.flags |= STLINK_F_HAS_TRACE;
- sl->max_trace_freq = STLINK_V2_MAX_TRACE_FREQUENCY;
- }
- }
- } else {
- // V3 uses different version format, for reference see OpenOCD source
- // (that was written from docs available from ST under NDA):
- // https://github.com/ntfreak/openocd/blob/a6dacdff58ef36fcdac00c53ec27f19de1fbce0d/src/jtag/drivers/stlink_usb.c#L965
- slv->stlink_v = sl->q_buf[0];
- slv->swim_v = sl->q_buf[1];
- slv->jtag_v = sl->q_buf[2];
- slv->st_vid = (uint32_t)((sl->q_buf[9] << 8) | sl->q_buf[8]);
- slv->stlink_pid = (uint32_t)((sl->q_buf[11] << 8) | sl->q_buf[10]);
- slv->jtag_api = STLINK_JTAG_API_V3;
- /* preferred API to get last R/W status */
- sl->version.flags |= STLINK_F_HAS_GETLASTRWSTATUS2;
- sl->version.flags |= STLINK_F_HAS_TRACE;
- sl->max_trace_freq = STLINK_V3_MAX_TRACE_FREQUENCY;
- }
-
- return;
-}
-
-int stlink_version(stlink_t *sl) {
- DLOG("*** looking up stlink version\n");
-
- if (sl->backend->version(sl)) {
- return (-1);
- }
-
- _parse_version(sl, &sl->version);
-
- DLOG("st vid = 0x%04x (expect 0x%04x)\n", sl->version.st_vid,
- STLINK_USB_VID_ST);
- DLOG("stlink pid = 0x%04x\n", sl->version.stlink_pid);
- DLOG("stlink version = 0x%x\n", sl->version.stlink_v);
- DLOG("jtag version = 0x%x\n", sl->version.jtag_v);
- DLOG("swim version = 0x%x\n", sl->version.swim_v);
-
- if (sl->version.jtag_v == 0) {
- DLOG(" notice: the firmware doesn't support a jtag/swd interface\n");
- }
-
- if (sl->version.swim_v == 0) {
- DLOG(" notice: the firmware doesn't support a swim interface\n");
- }
-
- return (0);
-}
-
-int stlink_target_voltage(stlink_t *sl) {
- int voltage = -1;
- DLOG("*** reading target voltage\n");
-
- if (sl->backend->target_voltage != NULL) {
- voltage = sl->backend->target_voltage(sl);
-
- if (voltage != -1) {
- DLOG("target voltage = %imV\n", voltage);
- } else {
- DLOG("error reading target voltage\n");
- }
- } else {
- DLOG("reading voltage not supported by backend\n");
- }
-
- return (voltage);
-}
-
-int stlink_read_debug32(stlink_t *sl, uint32_t addr, uint32_t *data) {
- int ret;
-
- ret = sl->backend->read_debug32(sl, addr, data);
- if (!ret)
- DLOG("*** stlink_read_debug32 %#010x at %#010x\n", *data, addr);
-
- return (ret);
-}
-
-int stlink_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data) {
- DLOG("*** stlink_write_debug32 %#010x to %#010x\n", data, addr);
- return sl->backend->write_debug32(sl, addr, data);
-}
-
-int stlink_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
- DLOG("*** stlink_write_mem32 %u bytes to %#x\n", len, addr);
-
- if (len % 4 != 0) {
- ELOG("Data length doesn't have a 32 bit alignment: +%d byte.\n", len % 4);
- return (-1);
- }
-
- return (sl->backend->write_mem32(sl, addr, len));
-}
-
-int stlink_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
- DLOG("*** stlink_read_mem32 ***\n");
-
- if (len % 4 != 0) { // !!! never ever: fw gives just wrong values
- ELOG("Data length doesn't have a 32 bit alignment: +%d byte.\n", len % 4);
- return (-1);
- }
-
- return (sl->backend->read_mem32(sl, addr, len));
-}
-
-int stlink_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len) {
- DLOG("*** stlink_write_mem8 ***\n");
-
- if (len > 0x40) { // !!! never ever: Writing more then 0x40 bytes gives
- // unexpected behaviour
- ELOG("Data length > 64: +%d byte.\n", len);
- return (-1);
- }
-
- return (sl->backend->write_mem8(sl, addr, len));
-}
-
-int stlink_read_all_regs(stlink_t *sl, struct stlink_reg *regp) {
- DLOG("*** stlink_read_all_regs ***\n");
- return (sl->backend->read_all_regs(sl, regp));
-}
-
-int stlink_read_all_unsupported_regs(stlink_t *sl, struct stlink_reg *regp) {
- DLOG("*** stlink_read_all_unsupported_regs ***\n");
- return (sl->backend->read_all_unsupported_regs(sl, regp));
-}
-
-int stlink_write_reg(stlink_t *sl, uint32_t reg, int idx) {
- DLOG("*** stlink_write_reg\n");
- return (sl->backend->write_reg(sl, reg, idx));
-}
-
-int stlink_read_reg(stlink_t *sl, int r_idx, struct stlink_reg *regp) {
- DLOG("*** stlink_read_reg\n");
- DLOG(" (%d) ***\n", r_idx);
-
- if (r_idx > 20 || r_idx < 0) {
- fprintf(stderr, "Error: register index must be in [0..20]\n");
- return (-1);
- }
-
- return (sl->backend->read_reg(sl, r_idx, regp));
-}
-
-int stlink_read_unsupported_reg(stlink_t *sl, int r_idx,
- struct stlink_reg *regp) {
- int r_convert;
-
- DLOG("*** stlink_read_unsupported_reg\n");
- DLOG(" (%d) ***\n", r_idx);
-
- /* Convert to values used by STLINK_REG_DCRSR */
- if (r_idx >= 0x1C &&
- r_idx <= 0x1F) { // primask, basepri, faultmask, or control
- r_convert = 0x14;
- } else if (r_idx == 0x40) { // FPSCR
- r_convert = 0x21;
- } else if (r_idx >= 0x20 && r_idx < 0x40) {
- r_convert = 0x40 + (r_idx - 0x20);
- } else {
- fprintf(stderr, "Error: register address must be in [0x1C..0x40]\n");
- return (-1);
- }
-
- return (sl->backend->read_unsupported_reg(sl, r_convert, regp));
-}
-
-int stlink_write_unsupported_reg(stlink_t *sl, uint32_t val, int r_idx,
- struct stlink_reg *regp) {
- int r_convert;
-
- DLOG("*** stlink_write_unsupported_reg\n");
- DLOG(" (%d) ***\n", r_idx);
-
- /* Convert to values used by STLINK_REG_DCRSR */
- if (r_idx >= 0x1C &&
- r_idx <= 0x1F) { /* primask, basepri, faultmask, or control */
- r_convert = r_idx; // the backend function handles this
- } else if (r_idx == 0x40) { // FPSCR
- r_convert = 0x21;
- } else if (r_idx >= 0x20 && r_idx < 0x40) {
- r_convert = 0x40 + (r_idx - 0x20);
- } else {
- fprintf(stderr, "Error: register address must be in [0x1C..0x40]\n");
- return (-1);
- }
-
- return (sl->backend->write_unsupported_reg(sl, val, r_convert, regp));
-}
-
-bool stlink_is_core_halted(stlink_t *sl) {
- stlink_status(sl);
- return (sl->core_stat == TARGET_HALTED);
-}
-
-int stlink_step(stlink_t *sl) {
- DLOG("*** stlink_step ***\n");
- return (sl->backend->step(sl));
-}
-
-int stlink_current_mode(stlink_t *sl) {
- int mode = sl->backend->current_mode(sl);
-
- switch (mode) {
- case STLINK_DEV_DFU_MODE:
- DLOG("stlink current mode: dfu\n");
- return (mode);
- case STLINK_DEV_DEBUG_MODE:
- DLOG("stlink current mode: debug (jtag or swd)\n");
- return (mode);
- case STLINK_DEV_MASS_MODE:
- DLOG("stlink current mode: mass\n");
- return (mode);
- }
-
- DLOG("stlink mode: unknown!\n");
- return (STLINK_DEV_UNKNOWN_MODE);
-}
-
-int stlink_trace_enable(stlink_t *sl, uint32_t frequency) {
- DLOG("*** stlink_trace_enable ***\n");
- return (sl->backend->trace_enable(sl, frequency));
-}
-
-int stlink_trace_disable(stlink_t *sl) {
- DLOG("*** stlink_trace_disable ***\n");
- return (sl->backend->trace_disable(sl));
-}
-
-int stlink_trace_read(stlink_t *sl, uint8_t *buf, size_t size) {
- return (sl->backend->trace_read(sl, buf, size));
-}
-
-// End of delegates.... Common code below here...
-
-// same as above with entrypoint.
-
-void stlink_run_at(stlink_t *sl, stm32_addr_t addr) {
- stlink_write_reg(sl, addr, 15); /* pc register */
- stlink_run(sl, RUN_NORMAL);
-
- while (stlink_is_core_halted(sl)) {
- usleep(3000000);
- }
-}
-
-// this function is called by stlink_status()
-// do not call stlink_core_stat() directly, always use stlink_status()
-void stlink_core_stat(stlink_t *sl) {
- switch (sl->core_stat) {
- case TARGET_RUNNING:
- DLOG(" core status: running\n");
- return;
- case TARGET_HALTED:
- DLOG(" core status: halted\n");
- return;
- case TARGET_RESET:
- DLOG(" core status: reset\n");
- return;
- case TARGET_DEBUG_RUNNING:
- DLOG(" core status: debug running\n");
- return;
- default:
- DLOG(" core status: unknown\n");
- }
-}
-
-void stlink_print_data(stlink_t *sl) {
- if (sl->q_len <= 0 || sl->verbose < UDEBUG) {
- return;
- }
-
- if (sl->verbose > 2) {
- DLOG("data_len = %d 0x%x\n", sl->q_len, sl->q_len);
- }
-
- for (int i = 0; i < sl->q_len; i++) {
- if (i % 16 == 0) {
- /*
- if (sl->q_data_dir == Q_DATA_OUT) {
- fprintf(stdout, "\n<- 0x%08x ", sl->q_addr + i);
- } else {
- fprintf(stdout, "\n-> 0x%08x ", sl->q_addr + i);
- }
- */
- }
- // DLOG(" %02x", (unsigned int) sl->q_buf[i]);
- fprintf(stderr, " %02x", (unsigned int)sl->q_buf[i]);
- }
- // DLOG("\n\n");
- fprintf(stderr, "\n");
-}
-
-/* Memory mapped file */
-typedef struct mapped_file {
- uint8_t *base;
- size_t len;
-} mapped_file_t;
-
-#define MAPPED_FILE_INITIALIZER \
- { NULL, 0 }
-
-static int map_file(mapped_file_t *mf, const char *path) {
- int error = -1;
- struct stat st;
-
- const int fd = open(path, O_RDONLY | O_BINARY);
-
- if (fd == -1) {
- fprintf(stderr, "open(%s) == -1\n", path);
- return (-1);
- }
-
- if (fstat(fd, &st) == -1) {
- fprintf(stderr, "fstat(%s) == -1\n", path);
- goto on_error;
- }
-
- if (sizeof(st.st_size) != sizeof(size_t)) {
- // on 32 bit systems, check if there is an overflow
- if (st.st_size > (off_t)INT32_MAX) {
- fprintf(stderr, "mmap() size_t overflow for file %s\n", path);
- goto on_error;
- }
- }
-
- mf->base =
- (uint8_t *)mmap(NULL, (size_t)(st.st_size), PROT_READ, MAP_SHARED, fd, 0);
-
- if (mf->base == MAP_FAILED) {
- fprintf(stderr, "mmap() == MAP_FAILED for file %s\n", path);
- goto on_error;
- }
-
- mf->len = st.st_size;
- error = 0; // success
-
-on_error:
- close(fd);
- return (error);
-}
-
-static void unmap_file(mapped_file_t *mf) {
- munmap((void *)mf->base, mf->len);
- mf->base = (unsigned char *)MAP_FAILED;
- mf->len = 0;
-}
-
-/* Limit the block size to compare to 0x1800 as anything larger will stall the
- * STLINK2 Maybe STLINK V1 needs smaller value!
- */
-static int check_file(stlink_t *sl, mapped_file_t *mf, stm32_addr_t addr) {
- size_t off;
- size_t n_cmp = sl->flash_pgsz;
-
- if (n_cmp > 0x1800) {
- n_cmp = 0x1800;
- }
-
- for (off = 0; off < mf->len; off += n_cmp) {
- size_t aligned_size;
-
- size_t cmp_size = n_cmp; // adjust last page size
-
- if ((off + n_cmp) > mf->len) {
- cmp_size = mf->len - off;
- }
-
- aligned_size = cmp_size;
-
- if (aligned_size & (4 - 1)) {
- aligned_size = (cmp_size + 4) & ~(4 - 1);
- }
-
- stlink_read_mem32(sl, addr + (uint32_t)off, aligned_size);
-
- if (memcmp(sl->q_buf, mf->base + off, cmp_size)) {
- return (-1);
- }
- }
-
- return (0);
-}
-
-static void md5_calculate(mapped_file_t *mf) {
- // calculate md5 checksum of given binary file
- Md5Context md5Context;
- MD5_HASH md5Hash;
- Md5Initialise(&md5Context);
- Md5Update(&md5Context, mf->base, (uint32_t)mf->len);
- Md5Finalise(&md5Context, &md5Hash);
- printf("md5 checksum: ");
-
- for (int i = 0; i < (int)sizeof(md5Hash); i++) {
- printf("%x", md5Hash.bytes[i]);
- }
-
- printf(", ");
-}
-
-static void stlink_checksum(mapped_file_t *mp) {
- /* checksum that backward compatible with official ST tools */
- uint32_t sum = 0;
- uint8_t *mp_byte = (uint8_t *)mp->base;
-
- for (size_t i = 0; i < mp->len; ++i) {
- sum += mp_byte[i];
- }
-
- printf("stlink checksum: 0x%08x\n", sum);
-}
-
-static void stlink_fwrite_finalize(stlink_t *sl, stm32_addr_t addr) {
- unsigned int val;
- // set stack
- stlink_read_debug32(sl, addr, &val);
- stlink_write_reg(sl, val, 13);
- // set PC to the reset routine
- stlink_read_debug32(sl, addr + 4, &val);
- stlink_write_reg(sl, val, 15);
- stlink_run(sl, RUN_NORMAL);
-}
-
-int stlink_mwrite_sram(stlink_t *sl, uint8_t *data, uint32_t length,
- stm32_addr_t addr) {
- // write the file in sram at addr
-
- int error = -1;
- size_t off;
- size_t len;
-
- // check addr range is inside the sram
- if (addr < sl->sram_base) {
- fprintf(stderr, "addr too low\n");
- goto on_error;
- } else if ((addr + length) < addr) {
- fprintf(stderr, "addr overruns\n");
- goto on_error;
- } else if ((addr + length) > (sl->sram_base + sl->sram_size)) {
- fprintf(stderr, "addr too high\n");
- goto on_error;
- } else if (addr & 3) {
- fprintf(stderr, "unaligned addr\n");
- goto on_error;
- }
-
- len = length;
-
- if (len & 3) {
- len -= len & 3;
- }
-
- // do the copy by 1kB blocks
- for (off = 0; off < len; off += 1024) {
- size_t size = 1024;
-
- if ((off + size) > len) {
- size = len - off;
- }
-
- memcpy(sl->q_buf, data + off, size);
-
- if (size & 3) {
- size += 2;
- } // round size if needed
-
- stlink_write_mem32(sl, addr + (uint32_t)off, size);
- }
-
- if (length > len) {
- memcpy(sl->q_buf, data + len, length - len);
- stlink_write_mem8(sl, addr + (uint32_t)len, length - len);
- }
-
- error = 0; // success
- stlink_fwrite_finalize(sl, addr);
-
-on_error:
- return (error);
-}
-
-int stlink_fwrite_sram(stlink_t *sl, const char *path, stm32_addr_t addr) {
- // write the file in sram at addr
-
- int error = -1;
- size_t off;
- size_t len;
- mapped_file_t mf = MAPPED_FILE_INITIALIZER;
-
- if (map_file(&mf, path) == -1) {
- fprintf(stderr, "map_file() == -1\n");
- return (-1);
- }
-
- printf("file %s ", path);
- md5_calculate(&mf);
- stlink_checksum(&mf);
-
- // check if addr range is inside the SRAM
- if (addr < sl->sram_base) {
- fprintf(stderr, "addr too low\n");
- goto on_error;
- } else if ((addr + mf.len) < addr) {
- fprintf(stderr, "addr overruns\n");
- goto on_error;
- } else if ((addr + mf.len) > (sl->sram_base + sl->sram_size)) {
- fprintf(stderr, "addr too high\n");
- goto on_error;
- } else if (addr & 3) {
- fprintf(stderr, "unaligned addr\n");
- goto on_error;
- }
-
- len = mf.len;
-
- if (len & 3) {
- len -= len & 3;
- }
-
- // do the copy by 1kB blocks
- for (off = 0; off < len; off += 1024) {
- size_t size = 1024;
-
- if ((off + size) > len) {
- size = len - off;
- }
-
- memcpy(sl->q_buf, mf.base + off, size);
-
- if (size & 3) {
- size += 2;
- } // round size if needed
-
- stlink_write_mem32(sl, addr + (uint32_t)off, size);
- }
-
- if (mf.len > len) {
- memcpy(sl->q_buf, mf.base + len, mf.len - len);
- stlink_write_mem8(sl, addr + (uint32_t)len, mf.len - len);
- }
-
- // check the file has been written
- if (check_file(sl, &mf, addr) == -1) {
- fprintf(stderr, "check_file() == -1\n");
- goto on_error;
- }
-
- error = 0; // success
- stlink_fwrite_finalize(sl, addr);
-
-on_error:
- unmap_file(&mf);
- return (error);
-}
-
-typedef bool (*save_block_fn)(void *arg, uint8_t *block, ssize_t len);
-
-static int stlink_read(stlink_t *sl, stm32_addr_t addr, size_t size,
- save_block_fn fn, void *fn_arg) {
-
- int error = -1;
-
- if (size < 1) {
- size = sl->flash_size;
- }
-
- if (size > sl->flash_size) {
- size = sl->flash_size;
- }
-
- size_t cmp_size = (sl->flash_pgsz > 0x1800) ? 0x1800 : sl->flash_pgsz;
-
- for (size_t off = 0; off < size; off += cmp_size) {
- size_t aligned_size;
-
- // adjust last page size
- if ((off + cmp_size) > size) {
- cmp_size = size - off;
- }
-
- aligned_size = cmp_size;
-
- if (aligned_size & (4 - 1)) {
- aligned_size = (cmp_size + 4) & ~(4 - 1);
- }
-
- stlink_read_mem32(sl, addr + (uint32_t)off, aligned_size);
-
- if (!fn(fn_arg, sl->q_buf, aligned_size)) {
- goto on_error;
- }
- }
-
- error = 0; // success
-
-on_error:
- return (error);
-}
-
-struct stlink_fread_worker_arg {
- int fd;
-};
-
-static bool stlink_fread_worker(void *arg, uint8_t *block, ssize_t len) {
- struct stlink_fread_worker_arg *the_arg =
- (struct stlink_fread_worker_arg *)arg;
-
- if (write(the_arg->fd, block, len) != len) {
- fprintf(stderr, "write() != aligned_size\n");
- return (false);
- } else {
- return (true);
- }
-}
-
-struct stlink_fread_ihex_worker_arg {
- FILE *file;
- uint32_t addr;
- uint32_t lba;
- uint8_t buf[16];
- uint8_t buf_pos;
-};
-
-static bool
-stlink_fread_ihex_newsegment(struct stlink_fread_ihex_worker_arg *the_arg) {
- uint32_t addr = the_arg->addr;
- uint8_t sum = 2 + 4 + (uint8_t)((addr & 0xFF000000) >> 24) +
- (uint8_t)((addr & 0x00FF0000) >> 16);
-
- if (17 != fprintf(the_arg->file, ":02000004%04X%02X\r\n",
- (addr & 0xFFFF0000) >> 16, (uint8_t)(0x100 - sum))) {
- return (false);
- }
-
- the_arg->lba = (addr & 0xFFFF0000);
- return (true);
-}
-
-static bool
-stlink_fread_ihex_writeline(struct stlink_fread_ihex_worker_arg *the_arg) {
- uint8_t count = the_arg->buf_pos;
-
- if (count == 0) {
- return (true);
- }
-
- uint32_t addr = the_arg->addr;
-
- if (the_arg->lba != (addr & 0xFFFF0000)) { // segment changed
- if (!stlink_fread_ihex_newsegment(the_arg)) {
- return (false);
- }
- }
-
- uint8_t sum = count + (uint8_t)((addr & 0x0000FF00) >> 8) +
- (uint8_t)(addr & 0x000000FF);
-
- if (9 != fprintf(the_arg->file, ":%02X%04X00", count, (addr & 0x0000FFFF))) {
- return (false);
- }
-
- for (uint8_t i = 0; i < count; ++i) {
- uint8_t b = the_arg->buf[i];
- sum += b;
-
- if (2 != fprintf(the_arg->file, "%02X", b)) {
- return (false);
- }
- }
-
- if (4 != fprintf(the_arg->file, "%02X\r\n", (uint8_t)(0x100 - sum))) {
- return (false);
- }
-
- the_arg->addr += count;
- the_arg->buf_pos = 0;
-
- return (true);
-}
-
-static bool stlink_fread_ihex_init(struct stlink_fread_ihex_worker_arg *the_arg,
- int fd, stm32_addr_t addr) {
- the_arg->file = fdopen(fd, "w");
- the_arg->addr = addr;
- the_arg->lba = 0;
- the_arg->buf_pos = 0;
-
- return (the_arg->file != NULL);
-}
-
-static bool stlink_fread_ihex_worker(void *arg, uint8_t *block, ssize_t len) {
- struct stlink_fread_ihex_worker_arg *the_arg =
- (struct stlink_fread_ihex_worker_arg *)arg;
-
- for (ssize_t i = 0; i < len; ++i) {
- if (the_arg->buf_pos == sizeof(the_arg->buf)) { // line is full
- if (!stlink_fread_ihex_writeline(the_arg)) {
- return (false);
- }
- }
-
- the_arg->buf[the_arg->buf_pos++] = block[i];
- }
-
- return (true);
-}
-
-static bool
-stlink_fread_ihex_finalize(struct stlink_fread_ihex_worker_arg *the_arg) {
- if (!stlink_fread_ihex_writeline(the_arg)) {
- return (false);
- }
-
- // FIXME: do we need the Start Linear Address?
-
- if (13 != fprintf(the_arg->file, ":00000001FF\r\n")) { // EoF
- return (false);
- }
-
- return (0 == fclose(the_arg->file));
-}
-
-int stlink_fread(stlink_t *sl, const char *path, bool is_ihex,
- stm32_addr_t addr, size_t size) {
- // read size bytes from addr to file
- ILOG("read from address %#010x size %u\n", addr, (unsigned)size);
-
- int error;
- int fd = open(path, O_RDWR | O_TRUNC | O_CREAT | O_BINARY, 00700);
-
- if (fd == -1) {
- fprintf(stderr, "open(%s) == -1\n", path);
- return (-1);
- }
-
- if (is_ihex) {
- struct stlink_fread_ihex_worker_arg arg;
-
- if (stlink_fread_ihex_init(&arg, fd, addr)) {
- error = stlink_read(sl, addr, size, &stlink_fread_ihex_worker, &arg);
-
- if (!stlink_fread_ihex_finalize(&arg)) {
- error = -1;
- }
- } else {
- error = -1;
- }
- } else {
- struct stlink_fread_worker_arg arg = {fd};
- error = stlink_read(sl, addr, size, &stlink_fread_worker, &arg);
- }
-
- close(fd);
- return (error);
-}
-
-int write_buffer_to_sram(stlink_t *sl, flash_loader_t *fl, const uint8_t *buf,
- size_t size) {
- // write the buffer right after the loader
- size_t chunk = size & ~0x3;
- size_t rem = size & 0x3;
-
- if (chunk) {
- memcpy(sl->q_buf, buf, chunk);
- stlink_write_mem32(sl, fl->buf_addr, chunk);
- }
-
- if (rem) {
- memcpy(sl->q_buf, buf + chunk, rem);
- stlink_write_mem8(sl, (fl->buf_addr) + (uint32_t)chunk, rem);
- }
-
- return (0);
-}
-
-uint32_t calculate_F4_sectornum(uint32_t flashaddr) {
- uint32_t offset = 0;
- flashaddr &= ~STM32_FLASH_BASE; // page now holding the actual flash address
-
- if (flashaddr >= 0x100000) {
- offset = 12;
- flashaddr -= 0x100000;
- }
-
- if (flashaddr < 0x4000) {
- return (offset + 0);
- } else if (flashaddr < 0x8000) {
- return (offset + 1);
- } else if (flashaddr < 0xc000) {
- return (offset + 2);
- } else if (flashaddr < 0x10000) {
- return (offset + 3);
- } else if (flashaddr < 0x20000) {
- return (offset + 4);
- } else {
- return (offset + (flashaddr / 0x20000) + 4);
- }
-}
-
-uint32_t calculate_F7_sectornum(uint32_t flashaddr) {
- flashaddr &= ~STM32_FLASH_BASE; // Page now holding the actual flash address
-
- if (flashaddr < 0x20000) {
- return (flashaddr / 0x8000);
- } else if (flashaddr < 0x40000) {
- return (4);
- } else {
- return ((flashaddr / 0x40000) + 4);
- }
-}
-
-uint32_t calculate_H7_sectornum(stlink_t *sl, uint32_t flashaddr,
- unsigned bank) {
- flashaddr &=
- ~((bank == BANK_1)
- ? STM32_FLASH_BASE
- : STM32_H7_FLASH_BANK2_BASE); // sector holding the flash address
- return (flashaddr / sl->flash_pgsz);
-}
-
-// returns BKER:PNB for the given page address
-uint32_t calculate_L4_page(stlink_t *sl, uint32_t flashaddr) {
- uint32_t bker = 0;
- uint32_t flashopt;
- stlink_read_debug32(sl, STM32L4_FLASH_OPTR, &flashopt);
- flashaddr -= STM32_FLASH_BASE;
-
- if (sl->chip_id == STLINK_CHIPID_STM32_L4 ||
- sl->chip_id == STLINK_CHIPID_STM32_L496X ||
- sl->chip_id == STLINK_CHIPID_STM32_L4RX) {
- // this chip use dual banked flash
- if (flashopt & (uint32_t)(1lu << STM32L4_FLASH_OPTR_DUALBANK)) {
- uint32_t banksize = (uint32_t)sl->flash_size / 2;
-
- if (flashaddr >= banksize) {
- flashaddr -= banksize;
- bker = 0x100;
- }
- }
- }
-
- // For 1MB chips without the dual-bank option set, the page address will
- // overflow into the BKER bit, which gives us the correct bank:page value.
- return (bker | flashaddr / (uint32_t)sl->flash_pgsz);
-}
-
-uint32_t stlink_calculate_pagesize(stlink_t *sl, uint32_t flashaddr) {
- if ((sl->chip_id == STLINK_CHIPID_STM32_F2) ||
- (sl->chip_id == STLINK_CHIPID_STM32_F4) ||
- (sl->chip_id == STLINK_CHIPID_STM32_F4_DE) ||
- (sl->chip_id == STLINK_CHIPID_STM32_F4_LP) ||
- (sl->chip_id == STLINK_CHIPID_STM32_F4_HD) ||
- (sl->chip_id == STLINK_CHIPID_STM32_F411RE) ||
- (sl->chip_id == STLINK_CHIPID_STM32_F446) ||
- (sl->chip_id == STLINK_CHIPID_STM32_F4_DSI) ||
- (sl->chip_id == STLINK_CHIPID_STM32_F72XXX) ||
- (sl->chip_id == STLINK_CHIPID_STM32_F412)) {
- uint32_t sector = calculate_F4_sectornum(flashaddr);
-
- if (sector >= 12) {
- sector -= 12;
- }
-
- if (sector < 4) {
- sl->flash_pgsz = 0x4000;
- } else if (sector < 5) {
- sl->flash_pgsz = 0x10000;
- } else {
- sl->flash_pgsz = 0x20000;
- }
- } else if (sl->chip_id == STLINK_CHIPID_STM32_F7 ||
- sl->chip_id == STLINK_CHIPID_STM32_F7XXXX) {
- uint32_t sector = calculate_F7_sectornum(flashaddr);
-
- if (sector < 4) {
- sl->flash_pgsz = 0x8000;
- } else if (sector < 5) {
- sl->flash_pgsz = 0x20000;
- } else {
- sl->flash_pgsz = 0x40000;
- }
- }
-
- return ((uint32_t)sl->flash_pgsz);
-}
-
-/**
- * Erase a page of flash, assumes sl is fully populated with things like
- * chip/core ids
- * @param sl stlink context
- * @param flashaddr an address in the flash page to erase
- * @return 0 on success -ve on failure
- */
-int stlink_erase_flash_page(stlink_t *sl, stm32_addr_t flashaddr) {
- // wait for ongoing op to finish
- wait_flash_busy(sl);
- // clear flash IO errors
- clear_flash_error(sl);
-
- if (sl->flash_type == STLINK_FLASH_TYPE_F4 ||
- sl->flash_type == STLINK_FLASH_TYPE_F7 ||
- sl->flash_type == STLINK_FLASH_TYPE_L4) {
- // unlock if locked
- unlock_flash_if(sl);
-
- // select the page to erase
- if ((sl->chip_id == STLINK_CHIPID_STM32_L4) ||
- (sl->chip_id == STLINK_CHIPID_STM32_L43X) ||
- (sl->chip_id == STLINK_CHIPID_STM32_L46X) ||
- (sl->chip_id == STLINK_CHIPID_STM32_L496X) ||
- (sl->chip_id == STLINK_CHIPID_STM32_L4RX)) {
- // calculate the actual bank+page from the address
- uint32_t page = calculate_L4_page(sl, flashaddr);
-
- fprintf(stderr, "EraseFlash - Page:0x%x Size:0x%x ", page,
- stlink_calculate_pagesize(sl, flashaddr));
-
- write_flash_cr_bker_pnb(sl, page);
- } else if (sl->chip_id == STLINK_CHIPID_STM32_F7 ||
- sl->chip_id == STLINK_CHIPID_STM32_F7XXXX) {
- // calculate the actual page from the address
- uint32_t sector = calculate_F7_sectornum(flashaddr);
-
- fprintf(stderr, "EraseFlash - Sector:0x%x Size:0x%x ", sector,
- stlink_calculate_pagesize(sl, flashaddr));
- write_flash_cr_snb(sl, sector, BANK_1);
- } else {
- // calculate the actual page from the address
- uint32_t sector = calculate_F4_sectornum(flashaddr);
-
- fprintf(stderr, "EraseFlash - Sector:0x%x Size:0x%x ", sector,
- stlink_calculate_pagesize(sl, flashaddr));
-
- // the SNB values for flash sectors in the second bank do not directly
- // follow the values for the first bank on 2mb devices...
- if (sector >= 12) {
- sector += 4;
- }
-
- write_flash_cr_snb(sl, sector, BANK_1);
- }
-
- set_flash_cr_strt(sl, BANK_1); // start erase operation
- wait_flash_busy(sl); // wait for completion
- lock_flash(sl); // TODO: fails to program if this is in
-#if DEBUG_FLASH
- fprintf(stdout, "Erase Final CR:0x%x\n", read_flash_cr(sl, BANK_1));
-#endif
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) {
-
- uint32_t val;
- uint32_t flash_regs_base = get_stm32l0_flash_base(sl);
-
- // check if the locks are set
- stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
-
- if ((val & (1 << 0)) || (val & (1 << 1))) {
- // disable pecr protection
- stlink_write_debug32(sl, flash_regs_base + FLASH_PEKEYR_OFF,
- FLASH_L0_PEKEY1);
- stlink_write_debug32(sl, flash_regs_base + FLASH_PEKEYR_OFF,
- FLASH_L0_PEKEY2);
-
- // check pecr.pelock is cleared
- stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
-
- if (val & (1 << 0)) {
- WLOG("pecr.pelock not clear (%#x)\n", val);
- return (-1);
- }
-
- // unlock program memory
- stlink_write_debug32(sl, flash_regs_base + FLASH_PRGKEYR_OFF,
- FLASH_L0_PRGKEY1);
- stlink_write_debug32(sl, flash_regs_base + FLASH_PRGKEYR_OFF,
- FLASH_L0_PRGKEY2);
-
- // check pecr.prglock is cleared
- stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
-
- if (val & (1 << 1)) {
- WLOG("pecr.prglock not clear (%#x)\n", val);
- return (-1);
- }
- }
-
- // set pecr.{erase,prog}
- val |= (1 << 9) | (1 << 3);
- stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val);
-
- // write 0 to the first word of the page to be erased
- stlink_write_debug32(sl, flashaddr, 0);
-
- /* MP: It is better to wait for clearing the busy bit after issuing page
- * erase command, even though PM0062 recommends to wait before it.
- * Test shows that a few iterations is performed in the following loop
- * before busy bit is cleared.
- */
- wait_flash_busy(sl);
-
- // reset lock bits
- stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
- val |= (1 << 0) | (1 << 1) | (1 << 2);
- stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val);
- } else if (sl->flash_type == STLINK_FLASH_TYPE_WB ||
- sl->flash_type == STLINK_FLASH_TYPE_G0 ||
- sl->flash_type == STLINK_FLASH_TYPE_G4) {
- uint32_t val;
- unlock_flash_if(sl);
- set_flash_cr_per(sl, BANK_1); // set the 'enable Flash erase' bit
-
- // set the page to erase
- if (sl->flash_type == STLINK_FLASH_TYPE_WB) {
- uint32_t flash_page =
- ((flashaddr - STM32_FLASH_BASE) / (uint32_t)(sl->flash_pgsz));
- stlink_read_debug32(sl, STM32WB_FLASH_CR, &val);
-
- // sec 3.10.5 - PNB[7:0] is offset by 3.
- val &= ~(0xFF << 3); // Clear previously set page number (if any)
- val |= ((flash_page & 0xFF) << 3);
-
- stlink_write_debug32(sl, STM32WB_FLASH_CR, val);
- } else if (sl->flash_type == STLINK_FLASH_TYPE_G0) {
- uint32_t flash_page =
- ((flashaddr - STM32_FLASH_BASE) / (uint32_t)(sl->flash_pgsz));
- stlink_read_debug32(sl, STM32Gx_FLASH_CR, &val);
- // sec 3.7.5 - PNB[5:0] is offset by 3. PER is 0x2.
- val &= ~(0x3F << 3);
- val |= ((flash_page & 0x3F) << 3) | (1 << FLASH_CR_PER);
- stlink_write_debug32(sl, STM32Gx_FLASH_CR, val);
- } else if (sl->flash_type == STLINK_FLASH_TYPE_G4) {
- uint32_t flash_page =
- ((flashaddr - STM32_FLASH_BASE) / (uint32_t)(sl->flash_pgsz));
- stlink_read_debug32(sl, STM32Gx_FLASH_CR, &val);
- // sec 3.7.5 - PNB[6:0] is offset by 3. PER is 0x2.
- val &= ~(0x7F << 3);
- val |= ((flash_page & 0x7F) << 3) | (1 << FLASH_CR_PER);
- stlink_write_debug32(sl, STM32Gx_FLASH_CR, val);
- }
-
- set_flash_cr_strt(sl, BANK_1); // set the 'start operation' bit
- wait_flash_busy(sl); // wait for the 'busy' bit to clear
- clear_flash_cr_per(sl, BANK_1); // clear the 'enable page erase' bit
- lock_flash(sl);
- } else if (sl->flash_type == STLINK_FLASH_TYPE_F0 ||
- sl->flash_type == STLINK_FLASH_TYPE_F1_XL) {
- unsigned bank = (flashaddr < STM32_F1_FLASH_BANK2_BASE) ? BANK_1 : BANK_2;
- unlock_flash_if(sl);
- clear_flash_cr_pg(sl, bank); // clear the pg bit
- set_flash_cr_per(sl, bank); // set the page erase bit
- write_flash_ar(sl, flashaddr, bank); // select the page to erase
- set_flash_cr_strt(sl,
- bank); // start erase operation, reset by hw with busy bit
- wait_flash_busy(sl);
- clear_flash_cr_per(sl, bank); // clear the page erase bit
- lock_flash(sl);
- } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) {
- unsigned bank = (flashaddr < STM32_H7_FLASH_BANK2_BASE) ? BANK_1 : BANK_2;
- unlock_flash_if(sl); // unlock if locked
- uint32_t sector = calculate_H7_sectornum(
- sl, flashaddr, bank); // calculate the actual page from the address
- write_flash_cr_snb(sl, sector, bank); // select the page to erase
- set_flash_cr_strt(sl, bank); // start erase operation
- wait_flash_busy(sl); // wait for completion
- lock_flash(sl);
- } else {
- WLOG("unknown coreid %x, page erase failed\n", sl->core_id);
- return (-1);
- }
-
- return check_flash_error(sl);
-}
-
-int stlink_erase_flash_mass(stlink_t *sl) {
- int err = 0;
-
- // TODO: User MER bit to mass-erase WB series.
- if (sl->flash_type == STLINK_FLASH_TYPE_L0 ||
- sl->flash_type == STLINK_FLASH_TYPE_WB) {
- // erase each page
- int i = 0, num_pages = (int)(sl->flash_size / sl->flash_pgsz);
-
- for (i = 0; i < num_pages; i++) {
- // addr must be an addr inside the page
- stm32_addr_t addr =
- (stm32_addr_t)sl->flash_base + i * (stm32_addr_t)sl->flash_pgsz;
-
- if (stlink_erase_flash_page(sl, addr)) {
- WLOG("Failed to erase_flash_page(%#x) == -1\n", addr);
- return (-1);
- }
-
- fprintf(stdout, "-> Flash page at %5d/%5d erased\n", i, num_pages);
- fflush(stdout);
- }
-
- fprintf(stdout, "\n");
- } else {
- wait_flash_busy(sl);
- clear_flash_error(sl);
- unlock_flash_if(sl);
-
- if (sl->flash_type == STLINK_FLASH_TYPE_H7 &&
- sl->chip_id != STLINK_CHIPID_STM32_H7AX) {
- // set parallelism
- write_flash_cr_psiz(sl, 3 /*64it*/, BANK_1);
- if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) {
- write_flash_cr_psiz(sl, 3 /*64bit*/, BANK_2);
- }
- }
-
- set_flash_cr_mer(sl, 1, BANK_1); // set the mass erase bit
- set_flash_cr_strt(
- sl, BANK_1); // start erase operation, reset by hw with busy bit
-
- if (sl->flash_type == STLINK_FLASH_TYPE_F1_XL ||
- (sl->flash_type == STLINK_FLASH_TYPE_H7 &&
- sl->chip_flags & CHIP_F_HAS_DUAL_BANK)) {
- set_flash_cr_mer(sl, 1, BANK_2); // set the mass erase bit in bank 2
- set_flash_cr_strt(sl, BANK_2); // start erase operation in bank 2
- }
-
- wait_flash_busy_progress(sl);
- lock_flash(sl);
-
- // reset the mass erase bit
- set_flash_cr_mer(sl, 0, BANK_1);
- if (sl->flash_type == STLINK_FLASH_TYPE_F1_XL ||
- (sl->flash_type == STLINK_FLASH_TYPE_H7 &&
- sl->chip_flags & CHIP_F_HAS_DUAL_BANK)) {
- set_flash_cr_mer(sl, 0, BANK_2);
- }
-
- err = check_flash_error(sl);
- }
-
- return (err);
-}
-
-int stlink_fcheck_flash(stlink_t *sl, const char *path, stm32_addr_t addr) {
- // check the contents of path are at addr
-
- int res;
- mapped_file_t mf = MAPPED_FILE_INITIALIZER;
-
- if (map_file(&mf, path) == -1) {
- return (-1);
- }
-
- res = check_file(sl, &mf, addr);
- unmap_file(&mf);
- return (res);
-}
-
-/**
- * Verify addr..addr+len is binary identical to base...base+len
- * @param sl stlink context
- * @param address stm device address
- * @param data host side buffer to check against
- * @param length how much
- * @return 0 for success, -ve for failure
- */
-int stlink_verify_write_flash(stlink_t *sl, stm32_addr_t address, uint8_t *data,
- unsigned length) {
- size_t off;
- size_t cmp_size = (sl->flash_pgsz > 0x1800) ? 0x1800 : sl->flash_pgsz;
- ILOG("Starting verification of write complete\n");
-
- for (off = 0; off < length; off += cmp_size) {
- size_t aligned_size;
-
- // adjust last page size
- if ((off + cmp_size) > length) {
- cmp_size = length - off;
- }
-
- aligned_size = cmp_size;
-
- if (aligned_size & (4 - 1)) {
- aligned_size = (cmp_size + 4) & ~(4 - 1);
- }
-
- stlink_read_mem32(sl, address + (uint32_t)off, aligned_size);
-
- if (memcmp(sl->q_buf, data + off, cmp_size)) {
- ELOG("Verification of flash failed at offset: %u\n", (unsigned int)off);
- return (-1);
- }
- }
-
- ILOG("Flash written and verified! jolly good!\n");
- return (0);
-}
-
-int stm32l1_write_half_pages(stlink_t *sl, stm32_addr_t addr, uint8_t *base,
- uint32_t len, uint32_t pagesize) {
- unsigned int count;
- unsigned int num_half_pages = len / pagesize;
- uint32_t val;
- uint32_t flash_regs_base = get_stm32l0_flash_base(sl);
- flash_loader_t fl;
-
- ILOG("Starting Half page flash write for STM32L core id\n");
-
- /* Flash loader initialisation */
- if (stlink_flash_loader_init(sl, &fl) == -1) {
- WLOG("stlink_flash_loader_init() == -1\n");
- return (-1);
- }
-
- // unlock already done
- stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
- val |= (1 << FLASH_L1_FPRG);
- stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val);
-
- val |= (1 << FLASH_L1_PROG);
- stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val);
-
- wait_flash_busy(sl);
-
- for (count = 0; count < num_half_pages; count++) {
- if (stlink_flash_loader_run(sl, &fl, addr + count * pagesize,
- base + count * pagesize, pagesize) == -1) {
- WLOG("l1_stlink_flash_loader_run(%#x) failed! == -1\n",
- addr + count * pagesize);
- stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
- val &= ~((1 << FLASH_L1_FPRG) | (1 << FLASH_L1_PROG));
- stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val);
- return (-1);
- }
-
- // wait for sr.busy to be cleared
- if (sl->verbose >= 1) {
- // show progress; writing procedure is slow and previous errors are
- // misleading
- fprintf(stdout, "\r%3u/%u halfpages written", count + 1, num_half_pages);
- fflush(stdout);
- }
-
- wait_flash_busy(sl);
- }
-
- stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
- val &= ~(1 << FLASH_L1_PROG);
- stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val);
- stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
- val &= ~(1 << FLASH_L1_FPRG);
- stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val);
- return (0);
-}
-
-int stlink_flashloader_start(stlink_t *sl, flash_loader_t *fl) {
-
- // According to DDI0419C, Table C1-7 firstly force halt
- stlink_write_debug32(sl, STLINK_REG_DHCSR,
- STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_DEBUGEN |
- STLINK_REG_DHCSR_C_HALT);
- // and only then disable interrupts
- stlink_write_debug32(sl, STLINK_REG_DHCSR,
- STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_DEBUGEN |
- STLINK_REG_DHCSR_C_HALT |
- STLINK_REG_DHCSR_C_MASKINTS);
-
- // disable DMA
- set_dma_state(sl, fl, 0);
-
- // wait for ongoing op to finish
- wait_flash_busy(sl);
- // Clear errors
- clear_flash_error(sl);
-
- if ((sl->flash_type == STLINK_FLASH_TYPE_F4) ||
- (sl->flash_type == STLINK_FLASH_TYPE_F7) ||
- (sl->flash_type == STLINK_FLASH_TYPE_L4)) {
- ILOG("Starting Flash write for F2/F4/F7/L4\n");
-
- // Flash loader initialisation
- if (stlink_flash_loader_init(sl, fl) == -1) {
- ELOG("stlink_flash_loader_init() == -1\n");
- return (-1);
- }
-
- unlock_flash_if(sl); // first unlock the cr
-
- int voltage;
- if (sl->version.stlink_v == 1) {
- WLOG("STLINK V1 cannot read voltage, use default voltage 3.2V\n");
- voltage = 3200;
- } else {
- voltage = stlink_target_voltage(sl);
- }
-
- if (voltage == -1) {
- ELOG("Failed to read Target voltage\n");
- return (-1);
- }
-
- if (sl->flash_type == STLINK_FLASH_TYPE_L4) {
- // L4 does not have a byte-write mode
- if (voltage < 1710) {
- ELOG("Target voltage (%d mV) too low for flash writes!\n", voltage);
- return (-1);
- }
- } else {
- if (voltage > 2700) {
- ILOG("enabling 32-bit flash writes\n");
- write_flash_cr_psiz(sl, 2, BANK_1);
- } else {
- ILOG("Target voltage (%d mV) too low for 32-bit flash, "
- "using 8-bit flash writes\n",
- voltage);
- write_flash_cr_psiz(sl, 0, BANK_1);
- }
- }
-
- // set programming mode
- set_flash_cr_pg(sl, BANK_1);
- } else if (sl->flash_type == STLINK_FLASH_TYPE_WB ||
- sl->flash_type == STLINK_FLASH_TYPE_G0 ||
- sl->flash_type == STLINK_FLASH_TYPE_G4) {
- ILOG("Starting Flash write for WB/G0/G4\n");
-
- unlock_flash_if(sl); // unlock flash if necessary
- set_flash_cr_pg(sl, BANK_1); // set PG 'allow programming' bit
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) {
- ILOG("Starting Flash write for L0\n");
-
- uint32_t val;
- uint32_t flash_regs_base;
- if (sl->chip_id == STLINK_CHIPID_STM32_L0 ||
- sl->chip_id == STLINK_CHIPID_STM32_L0_CAT5 ||
- sl->chip_id == STLINK_CHIPID_STM32_L0_CAT2 ||
- sl->chip_id == STLINK_CHIPID_STM32_L011) {
- flash_regs_base = STM32L0_FLASH_REGS_ADDR;
- } else {
- flash_regs_base = STM32L_FLASH_REGS_ADDR;
- }
-
- // disable pecr protection
- stlink_write_debug32(sl, flash_regs_base + FLASH_PEKEYR_OFF,
- FLASH_L0_PEKEY1);
- stlink_write_debug32(sl, flash_regs_base + FLASH_PEKEYR_OFF,
- FLASH_L0_PEKEY2);
-
- // check pecr.pelock is cleared
- stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
- if (val & (1 << 0)) {
- ELOG("pecr.pelock not clear\n");
- return (-1);
- }
-
- // unlock program memory
- stlink_write_debug32(sl, flash_regs_base + FLASH_PRGKEYR_OFF,
- FLASH_L0_PRGKEY1);
- stlink_write_debug32(sl, flash_regs_base + FLASH_PRGKEYR_OFF,
- FLASH_L0_PRGKEY2);
-
- // check pecr.prglock is cleared
- stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
- if (val & (1 << 1)) {
- ELOG("pecr.prglock not clear\n");
- return (-1);
- }
- } else if ((sl->flash_type == STLINK_FLASH_TYPE_F0) ||
- (sl->flash_type == STLINK_FLASH_TYPE_F1_XL)) {
- ILOG("Starting Flash write for VL/F0/F3/F1_XL\n");
-
- // flash loader initialisation
- if (stlink_flash_loader_init(sl, fl) == -1) {
- ELOG("stlink_flash_loader_init() == -1\n");
- return (-1);
- }
- } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) {
- ILOG("Starting Flash write for H7\n");
-
- unlock_flash_if(sl); // unlock the cr
- set_flash_cr_pg(sl, BANK_1); // set programming mode
- if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) {
- set_flash_cr_pg(sl, BANK_2);
- }
- if (sl->chip_id != STLINK_CHIPID_STM32_H7AX) {
- // set parallelism
- write_flash_cr_psiz(sl, 3 /*64it*/, BANK_1);
- if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) {
- write_flash_cr_psiz(sl, 3 /*64bit*/, BANK_2);
- }
- }
- } else {
- ELOG("unknown coreid, not sure how to write: %x\n", sl->core_id);
- return (-1);
- }
-
- return (0);
-}
-
-int stlink_flashloader_write(stlink_t *sl, flash_loader_t *fl,
- stm32_addr_t addr, uint8_t *base, uint32_t len) {
- size_t off;
- if ((sl->flash_type == STLINK_FLASH_TYPE_F4) ||
- (sl->flash_type == STLINK_FLASH_TYPE_F7) ||
- (sl->flash_type == STLINK_FLASH_TYPE_L4)) {
- size_t buf_size = (sl->sram_size > 0x8000) ? 0x8000 : 0x4000;
- for (off = 0; off < len;) {
- size_t size = len - off > buf_size ? buf_size : len - off;
- if (stlink_flash_loader_run(sl, fl, addr + (uint32_t)off, base + off,
- size) == -1) {
- ELOG("stlink_flash_loader_run(%#x) failed! == -1\n",
- (unsigned)(addr + off));
- check_flash_error(sl);
- return (-1);
- }
-
- off += size;
- }
- } else if (sl->flash_type == STLINK_FLASH_TYPE_WB ||
- sl->flash_type == STLINK_FLASH_TYPE_G0 ||
- sl->flash_type == STLINK_FLASH_TYPE_G4) {
- DLOG("Starting %3u page write\r\n", (unsigned int)(len / sl->flash_pgsz));
- for (off = 0; off < len; off += sizeof(uint32_t)) {
- uint32_t data;
-
- if ((off % sl->flash_pgsz) > (sl->flash_pgsz - 5)) {
- fprintf(stdout, "\r%3u/%3u pages written",
- (unsigned int)(off / sl->flash_pgsz),
- (unsigned int)(len / sl->flash_pgsz));
- fflush(stdout);
- }
-
- write_uint32((unsigned char *)&data, *(uint32_t *)(base + off));
- stlink_write_debug32(sl, addr + (uint32_t)off, data);
- wait_flash_busy(sl); // wait for 'busy' bit in FLASH_SR to clear
- }
- fprintf(stdout, "\n");
-
- // flash writes happen as 2 words at a time
- if ((off / sizeof(uint32_t)) % 2 != 0) {
- stlink_write_debug32(sl, addr + (uint32_t)off,
- 0); // write a single word of zeros
- wait_flash_busy(sl); // wait for 'busy' bit in FLASH_SR to clear
- }
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) {
- uint32_t val;
- uint32_t flash_regs_base;
- uint32_t pagesize;
-
- if (sl->chip_id == STLINK_CHIPID_STM32_L0 ||
- sl->chip_id == STLINK_CHIPID_STM32_L0_CAT5 ||
- sl->chip_id == STLINK_CHIPID_STM32_L0_CAT2 ||
- sl->chip_id == STLINK_CHIPID_STM32_L011) {
- flash_regs_base = STM32L0_FLASH_REGS_ADDR;
- pagesize = L0_WRITE_BLOCK_SIZE;
- } else {
- flash_regs_base = STM32L_FLASH_REGS_ADDR;
- pagesize = L1_WRITE_BLOCK_SIZE;
- }
-
- off = 0;
-
- if (len > pagesize) {
- if (stm32l1_write_half_pages(sl, addr, base, len, pagesize) == -1) {
- // this may happen on a blank device!
- WLOG("\nwrite_half_pages failed == -1\n");
- } else {
- off = (size_t)(len / pagesize) * pagesize;
- }
- }
-
- // write remaining word in program memory
- for (; off < len; off += sizeof(uint32_t)) {
- uint32_t data;
-
- if ((off % sl->flash_pgsz) > (sl->flash_pgsz - 5)) {
- fprintf(stdout, "\r%3u/%3u pages written",
- (unsigned int)(off / sl->flash_pgsz),
- (unsigned int)(len / sl->flash_pgsz));
- fflush(stdout);
- }
-
- write_uint32((unsigned char *)&data, *(uint32_t *)(base + off));
- stlink_write_debug32(sl, addr + (uint32_t)off, data);
-
- // wait for sr.busy to be cleared
- do {
- stlink_read_debug32(sl, flash_regs_base + FLASH_SR_OFF, &val);
- } while ((val & (1 << 0)) != 0);
-
- // TODO: check redo write operation
- }
- fprintf(stdout, "\n");
- } else if ((sl->flash_type == STLINK_FLASH_TYPE_F0) ||
- (sl->flash_type == STLINK_FLASH_TYPE_F1_XL)) {
- int write_block_count = 0;
- for (off = 0; off < len; off += sl->flash_pgsz) {
- // adjust last write size
- size_t size = len - off > sl->flash_pgsz ? sl->flash_pgsz : len - off;
-
- // unlock and set programming mode
- unlock_flash_if(sl);
-
- DLOG("Finished unlocking flash, running loader!\n");
-
- if (stlink_flash_loader_run(sl, fl, addr + (uint32_t)off, base + off,
- size) == -1) {
- ELOG("stlink_flash_loader_run(%#x) failed! == -1\n",
- (unsigned)(addr + off));
- check_flash_error(sl);
- return (-1);
- }
-
- lock_flash(sl);
-
- if (sl->verbose >= 1) {
- // show progress; writing procedure is slow and previous errors are
- // misleading
- fprintf(stdout, "\r%3u/%3u pages written", ++write_block_count,
- (unsigned int)((len + sl->flash_pgsz - 1) / sl->flash_pgsz));
- fflush(stdout);
- }
- }
- if (sl->verbose >= 1) {
- fprintf(stdout, "\n");
- }
- } else if (sl->flash_type == STLINK_FLASH_TYPE_H7) {
- for (off = 0; off < len;) {
- // Program STM32H7x with 64-byte Flash words
- size_t chunk = (len - off > 64) ? 64 : len - off;
- memcpy(sl->q_buf, base + off, chunk);
- stlink_write_mem32(sl, addr + (uint32_t)off, 64);
- wait_flash_busy(sl);
-
- off += chunk;
-
- if (sl->verbose >= 1) {
- // show progress
- fprintf(stdout, "\r%u/%u bytes written", (unsigned int)off,
- (unsigned int)len);
- fflush(stdout);
- }
- }
- if (sl->verbose >= 1) {
- fprintf(stdout, "\n");
- }
- } else {
- return (-1);
- }
-
- return check_flash_error(sl);
-}
-
-int stlink_flashloader_stop(stlink_t *sl, flash_loader_t *fl) {
- uint32_t dhcsr;
-
- if ((sl->flash_type == STLINK_FLASH_TYPE_F4) ||
- (sl->flash_type == STLINK_FLASH_TYPE_F7) ||
- (sl->flash_type == STLINK_FLASH_TYPE_L4) ||
- (sl->flash_type == STLINK_FLASH_TYPE_WB) ||
- (sl->flash_type == STLINK_FLASH_TYPE_G0) ||
- (sl->flash_type == STLINK_FLASH_TYPE_G4) ||
- (sl->flash_type == STLINK_FLASH_TYPE_H7)) {
-
- clear_flash_cr_pg(sl, BANK_1);
- if (sl->flash_type == STLINK_FLASH_TYPE_H7 &&
- sl->chip_flags & CHIP_F_HAS_DUAL_BANK) {
- clear_flash_cr_pg(sl, BANK_2);
- }
- lock_flash(sl);
- } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) {
- uint32_t val;
- uint32_t flash_regs_base;
- if (sl->chip_id == STLINK_CHIPID_STM32_L0 ||
- sl->chip_id == STLINK_CHIPID_STM32_L0_CAT5 ||
- sl->chip_id == STLINK_CHIPID_STM32_L0_CAT2 ||
- sl->chip_id == STLINK_CHIPID_STM32_L011) {
- flash_regs_base = STM32L0_FLASH_REGS_ADDR;
- } else {
- flash_regs_base = STM32L_FLASH_REGS_ADDR;
- }
- // reset lock bits
- stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
- val |= (1 << 0) | (1 << 1) | (1 << 2);
- stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val);
- }
-
- // enable interrupt
- if (!stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr)) {
- stlink_write_debug32(sl, STLINK_REG_DHCSR,
- STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_DEBUGEN |
- (dhcsr & (~STLINK_REG_DHCSR_C_MASKINTS)));
- }
-
- // restore DMA state
- set_dma_state(sl, fl, 1);
-
- return (0);
-}
-
-int stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t *base,
- uint32_t len, uint8_t eraseonly) {
- size_t off;
- int ret;
- flash_loader_t fl;
- ILOG("Attempting to write %d (%#x) bytes to stm32 address: %u (%#x)\n", len,
- len, addr, addr);
- // check addr range is inside the flash
- stlink_calculate_pagesize(sl, addr);
-
- if (addr < sl->flash_base) {
- ELOG("addr too low %#x < %#x\n", addr, sl->flash_base);
- return (-1);
- } else if ((addr + len) < addr) {
- ELOG("addr overruns\n");
- return (-1);
- } else if ((addr + len) > (sl->flash_base + sl->flash_size)) {
- ELOG("addr too high\n");
- return (-1);
- } else if (addr & 1) {
- ELOG("unaligned addr 0x%x\n", addr);
- return (-1);
- } else if (len & 1) {
- WLOG("unaligned len 0x%x -- padding with zero\n", len);
- len += 1;
- } else if (addr & (sl->flash_pgsz - 1)) {
- ELOG("addr not a multiple of current pagesize (%u bytes), not supported, "
- "check page start address and compare with flash module organisation "
- "in related ST reference manual of your device.\n",
- (unsigned)(sl->flash_pgsz));
- return (-1);
- }
-
- // make sure we've loaded the context with the chip details
- stlink_core_id(sl);
-
- // Erase each page
- int page_count = 0;
-
- for (off = 0; off < len;
- off += stlink_calculate_pagesize(sl, addr + (uint32_t)off)) {
- // addr must be an addr inside the page
- if (stlink_erase_flash_page(sl, addr + (uint32_t)off) == -1) {
- ELOG("Failed to erase_flash_page(%#x) == -1\n", (unsigned)(addr + off));
- return (-1);
- }
-
- ILOG("Flash page at addr: 0x%08lx erased\n", (unsigned long)(addr + off));
- page_count++;
- }
-
- ILOG("Finished erasing %d pages of %u (%#x) bytes\n", page_count,
- (unsigned)(sl->flash_pgsz), (unsigned)(sl->flash_pgsz));
-
- if (eraseonly) {
- return (0);
- }
-
- ret = stlink_flashloader_start(sl, &fl);
- if (ret)
- return ret;
- ret = stlink_flashloader_write(sl, &fl, addr, base, len);
- if (ret)
- return ret;
- ret = stlink_flashloader_stop(sl, &fl);
- if (ret)
- return ret;
-
- return (stlink_verify_write_flash(sl, addr, base, len));
-}
-
-// TODO: length not checked
-static uint8_t stlink_parse_hex(const char *hex) {
- uint8_t d[2];
-
- for (int i = 0; i < 2; ++i) {
- char c = *(hex + i);
-
- if (c >= '0' && c <= '9') {
- d[i] = c - '0';
- } else if (c >= 'A' && c <= 'F') {
- d[i] = c - 'A' + 10;
- } else if (c >= 'a' && c <= 'f') {
- d[i] = c - 'a' + 10;
- } else {
- return (0); // error
- }
- }
-
- return ((d[0] << 4) | (d[1]));
-}
-
-int stlink_parse_ihex(const char *path, uint8_t erased_pattern, uint8_t **mem,
- size_t *size, uint32_t *begin) {
- int res = 0;
- *begin = UINT32_MAX;
- uint8_t *data = NULL;
- uint32_t end = 0;
- bool eof_found = false;
-
- for (int scan = 0; (res == 0) && (scan < 2); ++scan) {
- // parse file two times - first to find memory range, second - to fill it
- if (scan == 1) {
- if (!eof_found) {
- ELOG("No EoF recond\n");
- res = -1;
- break;
- }
-
- if (*begin >= end) {
- ELOG("No data found in file\n");
- res = -1;
- break;
- }
-
- *size = (end - *begin) + 1;
- data = calloc(*size, 1); // use calloc to get NULL if out of memory
-
- if (!data) {
- ELOG("Cannot allocate %u bytes\n", (unsigned)(*size));
- res = -1;
- break;
- }
-
- memset(data, erased_pattern, *size);
- }
-
- FILE *file = fopen(path, "r");
-
- if (!file) {
- ELOG("Cannot open file\n");
- res = -1;
- break;
- }
-
- uint32_t lba = 0;
- char line[1 + 5 * 2 + 255 * 2 + 2];
-
- while (fgets(line, sizeof(line), file)) {
- if (line[0] == '\n' || line[0] == '\r') {
- continue;
- } // skip empty lines
-
- if (line[0] != ':') { // no marker - wrong file format
- ELOG("Wrong file format - no marker\n");
- res = -1;
- break;
- }
-
- size_t l = strlen(line);
-
- while (l > 0 && (line[l - 1] == '\n' || line[l - 1] == '\r')) {
- --l;
- } // trim EoL
-
- if ((l < 11) ||
- (l ==
- (sizeof(line) - 1))) { // line too short or long - wrong file format
- ELOG("Wrong file format - wrong line length\n");
- res = -1;
- break;
- }
-
- uint8_t chksum = 0; // check sum
-
- for (size_t i = 1; i < l; i += 2) {
- chksum += stlink_parse_hex(line + i);
- }
-
- if (chksum != 0) {
- ELOG("Wrong file format - checksum mismatch\n");
- res = -1;
- break;
- }
-
- uint8_t reclen = stlink_parse_hex(line + 1);
-
- if (((uint32_t)reclen + 5) * 2 + 1 != l) {
- ELOG("Wrong file format - record length mismatch\n");
- res = -1;
- break;
- }
-
- uint16_t offset = ((uint16_t)stlink_parse_hex(line + 3) << 8) |
- ((uint16_t)stlink_parse_hex(line + 5));
- uint8_t rectype = stlink_parse_hex(line + 7);
-
- switch (rectype) {
- case 0: /* Data */
- if (scan == 0) {
- uint32_t b = lba + offset;
- uint32_t e = b + reclen - 1;
-
- if (b < *begin) {
- *begin = b;
- }
-
- if (e > end) {
- end = e;
- }
- } else {
- for (uint8_t i = 0; i < reclen; ++i) {
- uint8_t b = stlink_parse_hex(line + 9 + i * 2);
- uint32_t addr = lba + offset + i;
-
- if (addr >= *begin && addr <= end) {
- data[addr - *begin] = b;
- }
- }
- }
- break;
- case 1: /* EoF */
- eof_found = true;
- break;
- case 2: /* Extended Segment Address, unexpected */
- res = -1;
- break;
- case 3: /* Start Segment Address, unexpected */
- res = -1;
- break;
- case 4: /* Extended Linear Address */
- if (reclen == 2) {
- lba = ((uint32_t)stlink_parse_hex(line + 9) << 24) |
- ((uint32_t)stlink_parse_hex(line + 11) << 16);
- } else {
- ELOG("Wrong file format - wrong LBA length\n");
- res = -1;
- }
- break;
- case 5: /* Start Linear Address - expected, but ignore */
- break;
- default:
- ELOG("Wrong file format - unexpected record type %d\n", rectype);
- res = -1;
- }
-
- if (res != 0) {
- break;
- }
- }
-
- fclose(file);
- }
-
- if (res == 0) {
- *mem = data;
- } else {
- free(data);
- }
-
- return (res);
-}
-
-uint8_t stlink_get_erased_pattern(stlink_t *sl) {
- if (sl->flash_type == STLINK_FLASH_TYPE_L0) {
- return (0x00);
- } else {
- return (0xff);
- }
-}
-
-int stlink_mwrite_flash(stlink_t *sl, uint8_t *data, uint32_t length,
- stm32_addr_t addr) {
- /* Write the block in flash at addr */
- int err;
- unsigned int num_empty, idx;
- uint8_t erased_pattern = stlink_get_erased_pattern(sl);
-
- /*
- * This optimisation may cause unexpected garbage data remaining.
- * Therfore it is turned off by default.
- */
- if (sl->opt) {
- idx = (unsigned int)length;
-
- for (num_empty = 0; num_empty != length; ++num_empty)
- if (data[--idx] != erased_pattern) {
- break;
- }
-
- num_empty -= (num_empty & 3); // Round down to words
-
- if (num_empty != 0) {
- ILOG("Ignoring %d bytes of 0x%02x at end of file\n", num_empty,
- erased_pattern);
- }
- } else {
- num_empty = 0;
- }
-
- /*
- * TODO: investigate a kind of weird behaviour here:
- * If the file is identified to be all-empty and four-bytes aligned,
- * still flash the whole file even if ignoring message is printed.
- */
- err = stlink_write_flash(sl, addr, data,
- (num_empty == length) ? (uint32_t)length
- : (uint32_t)length - num_empty,
- num_empty == length);
- stlink_fwrite_finalize(sl, addr);
- return (err);
-}
-
-/**
- * Write the given binary file into flash at address "addr"
- * @param sl
- * @param path readable file path, should be binary image
- * @param addr where to start writing
- * @return 0 on success, -ve on failure.
- */
-int stlink_fwrite_flash(stlink_t *sl, const char *path, stm32_addr_t addr) {
- /* Write the file in flash at addr */
- int err;
- unsigned int num_empty, idx;
- uint8_t erased_pattern = stlink_get_erased_pattern(sl);
- mapped_file_t mf = MAPPED_FILE_INITIALIZER;
-
- if (map_file(&mf, path) == -1) {
- ELOG("map_file() == -1\n");
- return (-1);
- }
-
- printf("file %s ", path);
- md5_calculate(&mf);
- stlink_checksum(&mf);
-
- if (sl->opt) {
- idx = (unsigned int)mf.len;
-
- for (num_empty = 0; num_empty != mf.len; ++num_empty) {
- if (mf.base[--idx] != erased_pattern) {
- break;
- }
- }
-
- num_empty -= (num_empty & 3); // round down to words
-
- if (num_empty != 0) {
- ILOG("Ignoring %d bytes of 0x%02x at end of file\n", num_empty,
- erased_pattern);
- }
- } else {
- num_empty = 0;
- }
-
- /*
- * TODO: investigate a kind of weird behaviour here:
- * If the file is identified to be all-empty and four-bytes aligned,
- * still flash the whole file even if ignoring message is printed.
- */
- err = stlink_write_flash(sl, addr, mf.base,
- (num_empty == mf.len) ? (uint32_t)mf.len
- : (uint32_t)mf.len - num_empty,
- num_empty == mf.len);
- stlink_fwrite_finalize(sl, addr);
- unmap_file(&mf);
- return (err);
-}
-
-/**
- * Write option bytes
- * @param sl
- * @param addr of the memory mapped option bytes
- * @param base option bytes to write
- * @return 0 on success, -ve on failure.
- */
-static int stlink_write_option_bytes_gx(stlink_t *sl, uint8_t *base,
- stm32_addr_t addr, uint32_t len) {
- /* Write options bytes */
- uint32_t val;
- int ret = 0;
- (void)len;
- uint32_t data;
-
- clear_flash_error(sl);
-
- write_uint32((unsigned char *)&data, *(uint32_t *)(base));
- WLOG("Writing option bytes %#10x to %#10x\n", data, addr);
- stlink_write_debug32(sl, STM32Gx_FLASH_OPTR, data);
-
- // Set Options Start bit
- stlink_read_debug32(sl, STM32Gx_FLASH_CR, &val);
- val |= (1 << STM32Gx_FLASH_CR_OPTSTRT);
- stlink_write_debug32(sl, STM32Gx_FLASH_CR, val);
-
- wait_flash_busy(sl);
-
- ret = check_flash_error(sl);
-
- // Reload options
- stlink_read_debug32(sl, STM32Gx_FLASH_CR, &val);
- val |= (1 << STM32Gx_FLASH_CR_OBL_LAUNCH);
- stlink_write_debug32(sl, STM32Gx_FLASH_CR, val);
-
- return (ret);
-}
-
-/**
- * Write option bytes
- * @param sl
- * @param addr of the memory mapped option bytes
- * @param base option bytes to write
- * @return 0 on success, -ve on failure.
- */
-static int stlink_write_option_bytes_l0(stlink_t *sl, uint8_t *base,
- stm32_addr_t addr, uint32_t len) {
- uint32_t flash_base = get_stm32l0_flash_base(sl);
- uint32_t val;
- uint32_t data;
- int ret = 0;
-
- // Clear errors
- clear_flash_error(sl);
-
- while (len != 0) {
- write_uint32((unsigned char *)&data,
- *(uint32_t *)(base)); // write options bytes
-
- WLOG("Writing option bytes %#10x to %#10x\n", data, addr);
- stlink_write_debug32(sl, addr, data);
- wait_flash_busy(sl);
-
- if ((ret = check_flash_error(sl))) {
- break;
- }
-
- len -= 4;
- addr += 4;
- base += 4;
- }
-
- // Reload options
- stlink_read_debug32(sl, flash_base + FLASH_PECR_OFF, &val);
- val |= (1 << STM32L0_FLASH_OBL_LAUNCH);
- stlink_write_debug32(sl, flash_base + FLASH_PECR_OFF, val);
-
- return (ret);
-}
-
-/**
- * Write option bytes
- * @param sl
- * @param addr of the memory mapped option bytes
- * @param base option bytes to write
- * @return 0 on success, -ve on failure.
- */
-static int stlink_write_option_bytes_l4(stlink_t *sl, uint8_t *base,
- stm32_addr_t addr, uint32_t len) {
-
- uint32_t val;
- int ret = 0;
- (void)addr;
- (void)len;
-
- // Clear errors
- clear_flash_error(sl);
-
- // write options bytes
- uint32_t data;
- write_uint32((unsigned char *)&data, *(uint32_t *)(base));
- WLOG("Writing option bytes 0x%04x\n", data);
- stlink_write_debug32(sl, STM32L4_FLASH_OPTR, data);
-
- // set options start bit
- stlink_read_debug32(sl, STM32L4_FLASH_CR, &val);
- val |= (1 << STM32L4_FLASH_CR_OPTSTRT);
- stlink_write_debug32(sl, STM32L4_FLASH_CR, val);
-
- wait_flash_busy(sl);
- ret = check_flash_error(sl);
-
- // apply options bytes immediate
- stlink_read_debug32(sl, STM32L4_FLASH_CR, &val);
- val |= (1 << STM32L4_FLASH_CR_OBL_LAUNCH);
- stlink_write_debug32(sl, STM32L4_FLASH_CR, val);
-
- return (ret);
-}
-
-/**
- * Write option bytes
- * @param sl
- * @param option_byte value to write
- * @return 0 on success, -ve on failure.
- */
-static int stlink_write_option_bytes_f4(stlink_t *sl, uint8_t *base,
- stm32_addr_t addr, uint32_t len) {
- uint32_t option_byte;
- int ret = 0;
- (void)addr;
- (void)len;
-
- // Clear errors
- clear_flash_error(sl);
-
- write_uint32((unsigned char *)&option_byte, *(uint32_t *)(base));
-
- // write option byte, ensuring we dont lock opt, and set strt bit
- stlink_write_debug32(sl, FLASH_F4_OPTCR,
- (option_byte & ~(1 << FLASH_F4_OPTCR_LOCK)) |
- (1 << FLASH_F4_OPTCR_START));
-
- wait_flash_busy(sl);
- ret = check_flash_error(sl);
-
- // option bytes are reloaded at reset only, no obl. */
- return (ret);
-}
-
-/**
- * Write option bytes
- * @param sl
- * @param option_byte value to write
- * @return 0 on success, -ve on failure.
- */
-static int stlink_write_option_bytes_f7(stlink_t *sl, uint8_t *base,
- stm32_addr_t addr, uint32_t len) {
- uint32_t option_byte;
- int ret = 0;
-
- // Clear errors
- clear_flash_error(sl);
-
- ILOG("Asked to write option byte %#10x to %#010x.\n", *(uint32_t *)(base),
- addr);
- write_uint32((unsigned char *)&option_byte, *(uint32_t *)(base));
- ILOG("Write %d option bytes %#010x to %#010x!\n", len, option_byte, addr);
-
- if (addr == 0) {
- addr = FLASH_F7_OPTCR;
- ILOG("No address provided, using %#10x\n", addr);
- }
-
- if (addr == FLASH_F7_OPTCR) {
- /* write option byte, ensuring we dont lock opt, and set strt bit */
- stlink_write_debug32(sl, FLASH_F7_OPTCR,
- (option_byte & ~(1 << FLASH_F7_OPTCR_LOCK)) |
- (1 << FLASH_F7_OPTCR_START));
- } else if (addr == FLASH_F7_OPTCR1) {
- // Read FLASH_F7_OPTCR
- uint32_t oldvalue;
- stlink_read_debug32(sl, FLASH_F7_OPTCR, &oldvalue);
- /* write option byte */
- stlink_write_debug32(sl, FLASH_F7_OPTCR1, option_byte);
- // Write FLASH_F7_OPTCR lock and start address
- stlink_write_debug32(sl, FLASH_F7_OPTCR,
- (oldvalue & ~(1 << FLASH_F7_OPTCR_LOCK)) |
- (1 << FLASH_F7_OPTCR_START));
- } else {
- WLOG("WIP: write %#010x to address %#010x\n", option_byte, addr);
- stlink_write_debug32(sl, addr, option_byte);
- }
-
- wait_flash_busy(sl);
-
- ret = check_flash_error(sl);
- if (!ret)
- ILOG("Wrote %d option bytes %#010x to %#010x!\n", len, *(uint32_t *)base,
- addr);
-
- /* option bytes are reloaded at reset only, no obl. */
-
- return ret;
-}
-
-/**
- * Write STM32H7xx option bytes
- * @param sl
- * @param base option bytes to write
- * @param addr of the memory mapped option bytes
- * @param len number of bytes to write (must be multiple of 4)
- * @return 0 on success, -ve on failure.
- */
-static int stlink_write_option_bytes_h7(stlink_t *sl, uint8_t *base,
- stm32_addr_t addr, uint32_t len) {
- uint32_t val;
- uint32_t data;
-
- // Wait until previous flash option has completed
- wait_flash_busy(sl);
-
- // Clear previous error
- stlink_write_debug32(sl, FLASH_H7_OPTCCR,
- 1 << FLASH_H7_OPTCCR_CLR_OPTCHANGEERR);
-
- while (len != 0) {
- switch (addr) {
- case FLASH_H7_REGS_ADDR + 0x20: // FLASH_OPTSR_PRG
- case FLASH_H7_REGS_ADDR + 0x2c: // FLASH_PRAR_PRG1
- case FLASH_H7_REGS_ADDR + 0x34: // FLASH_SCAR_PRG1
- case FLASH_H7_REGS_ADDR + 0x3c: // FLASH_WPSN_PRG1
- case FLASH_H7_REGS_ADDR + 0x44: // FLASH_BOOT_PRG
- /* Write to FLASH_xxx_PRG registers */
- write_uint32((unsigned char *)&data,
- *(uint32_t *)(base)); // write options bytes
-
- WLOG("Writing option bytes %#10x to %#10x\n", data, addr);
-
- /* Skip if the value in the CUR register is identical */
- stlink_read_debug32(sl, addr - 4, &val);
- if (val == data) {
- break;
- }
-
- /* Write new option byte values and start modification */
- stlink_write_debug32(sl, addr, data);
- stlink_read_debug32(sl, FLASH_H7_OPTCR, &val);
- val |= (1 << FLASH_H7_OPTCR_OPTSTART);
- stlink_write_debug32(sl, FLASH_H7_OPTCR, val);
-
- /* Wait for the option bytes modification to complete */
- do {
- stlink_read_debug32(sl, FLASH_H7_OPTSR_CUR, &val);
- } while ((val & (1 << FLASH_H7_OPTSR_OPT_BUSY)) != 0);
-
- /* Check for errors */
- if ((val & (1 << FLASH_H7_OPTSR_OPTCHANGEERR)) != 0) {
- stlink_write_debug32(sl, FLASH_H7_OPTCCR,
- 1 << FLASH_H7_OPTCCR_CLR_OPTCHANGEERR);
- return -1;
- }
- break;
-
- default:
- /* Skip non-programmable registers */
- break;
- }
-
- len -= 4;
- addr += 4;
- base += 4;
- }
-
- return 0;
-}
-
-/**
- * Read option bytes
- * @param sl
- * @param option_byte value to write
- * @return 0 on success, -ve on failure.
- */
-int stlink_read_option_control_register_Gx(stlink_t *sl,
- uint32_t *option_byte) {
- return stlink_read_debug32(sl, STM32Gx_FLASH_OPTR, option_byte);
-}
-
-/**
- * Read option bytes
- * @param sl
- * @param option_byte value to write
- * @return 0 on success, -ve on failure.
- */
-int stlink_read_option_bytes_Gx(stlink_t *sl, uint32_t *option_byte) {
- return stlink_read_option_control_register_Gx(sl, option_byte);
-}
-
-/**
- * Read option bytes
- * @param sl
- * @param option_byte value to write
- * @return 0 on success, -ve on failure.
- */
-int stlink_read_option_control_register_f2(stlink_t *sl,
- uint32_t *option_byte) {
- return stlink_read_debug32(sl, FLASH_F2_OPT_CR, option_byte);
-}
-
-/**
- * Read option bytes
- * @param sl
- * @param option_byte value to write
- * @return 0 on success, -ve on failure.
- */
-int stlink_read_option_bytes_f2(stlink_t *sl, uint32_t *option_byte) {
- return stlink_read_option_control_register_f2(sl, option_byte);
-}
-
-/**
- * Read option bytes
- * @param sl
- * @param option_byte value to read
- * @return 0 on success, -ve on failure.
- */
-int stlink_read_option_control_register_f4(stlink_t *sl,
- uint32_t *option_byte) {
- return stlink_read_debug32(sl, FLASH_F4_OPTCR, option_byte);
-}
-
-/**
- * Read option bytes
- * @param sl
- * @param option_byte value to read
- * @return 0 on success, -ve on failure.
- */
-int stlink_read_option_bytes_f4(stlink_t *sl, uint32_t *option_byte) {
- return stlink_read_option_control_register_f4(sl, option_byte);
-}
-
-/**
- * Read option bytes
- * @param sl
- * @param option_byte value to read
- * @return 0 on success, -ve on failure.
- */
-int stlink_read_option_control_register_f7(stlink_t *sl,
- uint32_t *option_byte) {
- DLOG("@@@@ Read option control register byte from %#10x\n", FLASH_F7_OPTCR);
- return stlink_read_debug32(sl, FLASH_F7_OPTCR, option_byte);
-}
-
-/**
- * Read option bytes
- * @param sl
- * @param option_byte value to read
- * @return 0 on success, -ve on failure.
- */
-int stlink_read_option_control_register1_f7(stlink_t *sl,
- uint32_t *option_byte) {
- DLOG("@@@@ Read option control register 1 byte from %#10x\n",
- FLASH_F7_OPTCR1);
- return stlink_read_debug32(sl, FLASH_F7_OPTCR1, option_byte);
-}
-
-/**
- * Read option bytes
- * @param sl
- * @param option_byte value to read
- * @return 0 on success, -ve on failure.
- */
-int stlink_read_option_bytes_boot_add_f7(stlink_t *sl, uint32_t *option_byte) {
- DLOG("@@@@ Read option byte boot address\n");
- return stlink_read_option_control_register1_f7(sl, option_byte);
-}
-
-/**
- * Read option bytes
- * @param sl
- * @param option_byte value to read
- * @return 0 on success, -ve on failure.
- *
- * Since multiple bytes can be read, we read and print all but one here
- * and then return the last one just like other devices
- */
-int stlink_read_option_bytes_f7(stlink_t *sl, uint32_t *option_byte) {
- int err = -1;
- for (uint32_t counter = 0; counter < (sl->option_size / 4 - 1); counter++) {
- err = stlink_read_debug32(sl, sl->option_base + counter * sizeof(uint32_t),
- option_byte);
- if (err == -1) {
- return err;
- } else {
- printf("%08x\n", *option_byte);
- }
- }
-
- return stlink_read_debug32(
- sl,
- sl->option_base + (uint32_t)(sl->option_size / 4 - 1) * sizeof(uint32_t),
- option_byte);
-}
-
-/**
- * Read first option bytes
- * @param sl
- * @param option_byte option value
- * @return 0 on success, -ve on failure.
- */
-int stlink_read_option_bytes_generic(stlink_t *sl, uint32_t *option_byte) {
- DLOG("@@@@ Read option bytes boot address from %#10x\n", sl->option_base);
- return stlink_read_debug32(sl, sl->option_base, option_byte);
-}
-
-/**
- * Read option bytes
- * @param sl
- * @param option_byte value to read
- * @return 0 on success, -ve on failure.
- */
-// int stlink_read_option_bytes_boot_add_generic(stlink_t *sl, uint32_t*
-// option_byte) {
-// DLOG("@@@@ Read option bytes boot address from %#10x\n", sl->option_base);
-// return stlink_read_debug32(sl, sl->option_base, option_byte);
-//}
-
-/**
- * Read option bytes
- * @param sl
- * @param option_byte value to read
- * @return 0 on success, -ve on failure.
- */
-// int stlink_read_option_control_register_generic(stlink_t *sl, uint32_t*
-// option_byte) {
-// DLOG("@@@@ Read option control register byte from %#10x\n",
-// sl->option_base); return stlink_read_debug32(sl, sl->option_base,
-// option_byte);
-//}
-
-/**
- * Read option bytes
- * @param sl
- * @param option_byte value to read
- * @return 0 on success, -ve on failure.
- */
-// int stlink_read_option_control_register1_generic(stlink_t *sl, uint32_t*
-// option_byte) {
-// DLOG("@@@@ Read option control register 1 byte from %#10x\n",
-// sl->option_base); return stlink_read_debug32(sl, sl->option_base,
-// option_byte);
-//}
-
-/**
- * Read option bytes
- * @param sl
- * @param option_byte option value
- * @return 0 on success, -ve on failure.
- */
-int stlink_read_option_bytes32(stlink_t *sl, uint32_t *option_byte) {
- if (sl->option_base == 0) {
- ELOG("Option bytes read is currently not supported for connected chip\n");
- return (-1);
- }
-
- switch (sl->chip_id) {
- case STLINK_CHIPID_STM32_F2:
- return stlink_read_option_bytes_f2(sl, option_byte);
- case STLINK_CHIPID_STM32_F4:
- case STLINK_CHIPID_STM32_F446:
- return stlink_read_option_bytes_f4(sl, option_byte);
- case STLINK_CHIPID_STM32_F7XXXX:
- return stlink_read_option_bytes_f7(sl, option_byte);
- case STLINK_CHIPID_STM32_G0_CAT1:
- case STLINK_CHIPID_STM32_G0_CAT2:
- case STLINK_CHIPID_STM32_G4_CAT2:
- case STLINK_CHIPID_STM32_G4_CAT3:
- return stlink_read_option_bytes_Gx(sl, option_byte);
- default:
- return stlink_read_option_bytes_generic(sl, option_byte);
- }
-}
-
-/**
- * Read option bytes
- * @param sl
- * @param option_byte option value
- * @return 0 on success, -ve on failure.
- */
-int stlink_read_option_bytes_boot_add32(stlink_t *sl, uint32_t *option_byte) {
- if (sl->option_base == 0) {
- ELOG("Option bytes boot address read is currently not supported for "
- "connected chip\n");
- return -1;
- }
-
- switch (sl->chip_id) {
- case STLINK_CHIPID_STM32_F7XXXX:
- return stlink_read_option_bytes_boot_add_f7(sl, option_byte);
- default:
- return -1;
- // return stlink_read_option_bytes_boot_add_generic(sl, option_byte);
- }
-}
-
-/**
- * Read option bytes
- * @param sl
- * @param option_byte option value
- * @return 0 on success, -ve on failure.
- */
-int stlink_read_option_control_register32(stlink_t *sl, uint32_t *option_byte) {
- if (sl->option_base == 0) {
- ELOG("Option bytes read is currently not supported for connected chip\n");
- return -1;
- }
-
- switch (sl->chip_id) {
- case STLINK_CHIPID_STM32_F7XXXX:
- return stlink_read_option_control_register_f7(sl, option_byte);
- default:
- return -1;
- // return stlink_read_option_control_register_generic(sl, option_byte);
- }
-}
-
-/**
- * Read option bytes
- * @param sl
- * @param option_byte option value
- * @return 0 on success, -ve on failure.
- */
-int stlink_read_option_control_register1_32(stlink_t *sl,
- uint32_t *option_byte) {
- if (sl->option_base == 0) {
- ELOG("Option bytes read is currently not supported for connected chip\n");
- return -1;
- }
-
- switch (sl->chip_id) {
- case STLINK_CHIPID_STM32_F7XXXX:
- return stlink_read_option_control_register1_f7(sl, option_byte);
- default:
- return -1;
- // return stlink_read_option_control_register1_generic(sl, option_byte);
- }
-}
-
-/**
- * Write option bytes
- * @param sl
- * @param option_byte value to write
- * @return 0 on success, -ve on failure.
- */
-int stlink_write_option_bytes32(stlink_t *sl, uint32_t option_byte) {
- WLOG("About to write option byte %#10x to %#10x.\n", option_byte,
- sl->option_base);
- return stlink_write_option_bytes(sl, sl->option_base, (uint8_t *)&option_byte,
- 4);
-}
-
-/**
- * Write option bytes
- * @param sl
- * @param addr of the memory mapped option bytes
- * @param base option bytes to write
- * @return 0 on success, -ve on failure.
- */
-int stlink_write_option_bytes(stlink_t *sl, stm32_addr_t addr, uint8_t *base,
- uint32_t len) {
- int ret = -1;
-
- if (sl->option_base == 0) {
- ELOG(
- "Option bytes writing is currently not supported for connected chip\n");
- return (-1);
- }
-
- if ((addr < sl->option_base) || addr > sl->option_base + sl->option_size) {
- ELOG("Option bytes start address out of Option bytes range\n");
- return (-1);
- }
-
- if (addr + len > sl->option_base + sl->option_size) {
- ELOG("Option bytes data too long\n");
- return (-1);
- }
-
- wait_flash_busy(sl);
-
- if (unlock_flash_if(sl)) {
- ELOG("Flash unlock failed! System reset required to be able to unlock it "
- "again!\n");
- return (-1);
- }
-
- if (unlock_flash_option_if(sl)) {
- ELOG("Flash option unlock failed!\n");
- return (-1);
- }
-
- switch (sl->flash_type) {
- case STLINK_FLASH_TYPE_F4:
- ret = stlink_write_option_bytes_f4(sl, base, addr, len);
- break;
- case STLINK_FLASH_TYPE_F7:
- ret = stlink_write_option_bytes_f7(sl, base, addr, len);
- break;
- case STLINK_FLASH_TYPE_L0:
- ret = stlink_write_option_bytes_l0(sl, base, addr, len);
- break;
- case STLINK_FLASH_TYPE_L4:
- ret = stlink_write_option_bytes_l4(sl, base, addr, len);
- break;
- case STLINK_FLASH_TYPE_G0:
- case STLINK_FLASH_TYPE_G4:
- ret = stlink_write_option_bytes_gx(sl, base, addr, len);
- break;
- case STLINK_FLASH_TYPE_H7:
- ret = stlink_write_option_bytes_h7(sl, base, addr, len);
- break;
- default:
- ELOG("Option bytes writing is currently not implemented for connected "
- "chip\n");
- break;
- }
-
- if (ret) {
- ELOG("Flash option write failed!\n");
- } else {
- ILOG("Wrote %d option bytes to %#010x!\n", len, addr);
- }
-
- /* Re-lock flash. */
- lock_flash_option(sl);
- lock_flash(sl);
-
- return ret;
-}
-
-/**
- * Write option bytes
- * @param sl
- * @param option_byte value to write
- * @return 0 on success, -ve on failure.
- */
-static int
-stlink_write_option_control_register_f7(stlink_t *sl,
- uint32_t option_control_register) {
- int ret = 0;
-
- // Clear errors
- clear_flash_error(sl);
-
- ILOG("Asked to write option control register 1 %#10x to %#010x.\n",
- option_control_register, FLASH_F7_OPTCR);
-
- /* write option byte, ensuring we dont lock opt, and set strt bit */
- stlink_write_debug32(sl, FLASH_F7_OPTCR,
- (option_control_register & ~(1 << FLASH_F7_OPTCR_LOCK)) |
- (1 << FLASH_F7_OPTCR_START));
-
- wait_flash_busy(sl);
-
- ret = check_flash_error(sl);
- if (!ret)
- ILOG("Wrote option bytes %#010x to %#010x!\n", option_control_register,
- FLASH_F7_OPTCR);
-
- return ret;
-}
-
-/**
- * Write option bytes
- * @param sl
- * @param option_byte value to write
- * @return 0 on success, -ve on failure.
- */
-static int
-stlink_write_option_control_register1_f7(stlink_t *sl,
- uint32_t option_control_register1) {
- int ret = 0;
-
- // Clear errors
- clear_flash_error(sl);
-
- ILOG("Asked to write option control register 1 %#010x to %#010x.\n",
- option_control_register1, FLASH_F7_OPTCR1);
-
- /* write option byte, ensuring we dont lock opt, and set strt bit */
- uint32_t current_control_register_value;
- stlink_read_debug32(sl, FLASH_F7_OPTCR, &current_control_register_value);
-
- /* write option byte */
- stlink_write_debug32(sl, FLASH_F7_OPTCR1, option_control_register1);
- stlink_write_debug32(
- sl, FLASH_F7_OPTCR,
- (current_control_register_value & ~(1 << FLASH_F7_OPTCR_LOCK)) |
- (1 << FLASH_F7_OPTCR_START));
-
- wait_flash_busy(sl);
-
- ret = check_flash_error(sl);
- if (!ret)
- ILOG("Wrote option bytes %#010x to %#010x!\n", option_control_register1,
- FLASH_F7_OPTCR1);
-
- return ret;
-}
-
-/**
- * Write option bytes
- * @param sl
- * @param option_byte value to write
- * @return 0 on success, -ve on failure.
- */
-static int
-stlink_write_option_bytes_boot_add_f7(stlink_t *sl,
- uint32_t option_byte_boot_add) {
- ILOG("Asked to write option byte boot add %#010x.\n", option_byte_boot_add);
- return stlink_write_option_control_register1_f7(sl, option_byte_boot_add);
-}
-
-/**
- * Write option bytes
- * @param sl
- * @param option bytes boot address to write
- * @return 0 on success, -ve on failure.
- */
-int stlink_write_option_bytes_boot_add32(stlink_t *sl,
- uint32_t option_bytes_boot_add) {
- int ret = -1;
-
- wait_flash_busy(sl);
-
- if (unlock_flash_if(sl)) {
- ELOG("Flash unlock failed! System reset required to be able to unlock it "
- "again!\n");
- return -1;
- }
-
- if (unlock_flash_option_if(sl)) {
- ELOG("Flash option unlock failed!\n");
- return -1;
- }
-
- switch (sl->flash_type) {
- case STLINK_FLASH_TYPE_F7:
- ret = stlink_write_option_bytes_boot_add_f7(sl, option_bytes_boot_add);
- break;
- default:
- ELOG("Option bytes boot address writing is currently not implemented for "
- "connected chip\n");
- break;
- }
-
- if (ret)
- ELOG("Flash option write failed!\n");
- else
- ILOG("Wrote option bytes boot address %#010x!\n", option_bytes_boot_add);
-
- /* Re-lock flash. */
- lock_flash_option(sl);
- lock_flash(sl);
-
- return ret;
-}
-
-/**
- * Write option bytes
- * @param sl
- * @param option bytes boot address to write
- * @return 0 on success, -ve on failure.
- */
-int stlink_write_option_control_register32(stlink_t *sl,
- uint32_t option_control_register) {
- int ret = -1;
-
- wait_flash_busy(sl);
-
- if (unlock_flash_if(sl)) {
- ELOG("Flash unlock failed! System reset required to be able to unlock it "
- "again!\n");
- return -1;
- }
-
- if (unlock_flash_option_if(sl)) {
- ELOG("Flash option unlock failed!\n");
- return -1;
- }
-
- switch (sl->flash_type) {
- case STLINK_FLASH_TYPE_F7:
- ret = stlink_write_option_control_register_f7(sl, option_control_register);
- break;
- default:
- ELOG("Option control register writing is currently not implemented for "
- "connected chip\n");
- break;
- }
-
- if (ret)
- ELOG("Flash option write failed!\n");
- else
- ILOG("Wrote option control register %#010x!\n", option_control_register);
-
- /* Re-lock flash. */
- lock_flash_option(sl);
- lock_flash(sl);
-
- return ret;
-}
-
-/**
- * Write option bytes
- * @param sl
- * @param option bytes boot address to write
- * @return 0 on success, -ve on failure.
- */
-int stlink_write_option_control_register1_32(
- stlink_t *sl, uint32_t option_control_register1) {
- int ret = -1;
-
- wait_flash_busy(sl);
-
- if (unlock_flash_if(sl)) {
- ELOG("Flash unlock failed! System reset required to be able to unlock it "
- "again!\n");
- return -1;
- }
-
- if (unlock_flash_option_if(sl)) {
- ELOG("Flash option unlock failed!\n");
- return -1;
- }
-
- switch (sl->flash_type) {
- case STLINK_FLASH_TYPE_F7:
- ret =
- stlink_write_option_control_register1_f7(sl, option_control_register1);
- break;
- default:
- ELOG("Option control register 1 writing is currently not implemented for "
- "connected chip\n");
- break;
- }
-
- if (ret)
- ELOG("Flash option write failed!\n");
- else
- ILOG("Wrote option control register 1 %#010x!\n", option_control_register1);
-
- lock_flash_option(sl);
- lock_flash(sl);
-
- return (ret);
-}
-
-/**
- * Write the given binary file with option bytes
- * @param sl
- * @param path readable file path, should be binary image
- * @param addr of the memory mapped option bytes
- * @return 0 on success, -ve on failure.
- */
-int stlink_fwrite_option_bytes(stlink_t *sl, const char *path,
- stm32_addr_t addr) {
- /* Write the file in flash at addr */
- int err;
- mapped_file_t mf = MAPPED_FILE_INITIALIZER;
-
- if (map_file(&mf, path) == -1) {
- ELOG("map_file() == -1\n");
- return (-1);
- }
-
- printf("file %s ", path);
- md5_calculate(&mf);
- stlink_checksum(&mf);
-
- err = stlink_write_option_bytes(sl, addr, mf.base, (uint32_t)mf.len);
- stlink_fwrite_finalize(sl, addr);
- unmap_file(&mf);
-
- return (err);
-}
-
-int stlink_target_connect(stlink_t *sl, enum connect_type connect) {
- uint32_t dhcsr;
-
- if (connect == CONNECT_UNDER_RESET) {
- stlink_jtag_reset(sl, STLINK_JTAG_DRIVE_NRST_LOW);
-
- // minimum reset pulse duration of 20 us (RM0008, 8.1.2 Power reset)
- usleep(20);
-
- if (stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE) {
- stlink_enter_swd_mode(sl);
- }
- stlink_force_debug(sl);
-
- // clear S_RESET_ST in DHCSR register
- stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr);
-
- stlink_jtag_reset(sl, STLINK_JTAG_DRIVE_NRST_HIGH);
- usleep(10000);
-
- // check NRST connection
- dhcsr = 0;
- stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr);
- if ((dhcsr & STLINK_REG_DHCSR_S_RESET_ST) == 0) {
- WLOG("NRST is not connected\n");
- }
-
- // addition soft reset for halt before the first instruction
- stlink_soft_reset(sl, 1 /* halt on reset */);
- }
-
- if (stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE) {
- stlink_enter_swd_mode(sl);
- }
-
- if (connect == CONNECT_NORMAL) {
- stlink_reset(sl, RESET_AUTO);
- }
-
- return stlink_load_device_params(sl);
-}
diff --git a/src/st-flash/flash.c b/src/st-flash/flash.c
index ede0f11..0b7c0cf 100644
--- a/src/st-flash/flash.c
+++ b/src/st-flash/flash.c
@@ -1,19 +1,37 @@
-/* Simple wrapper around the stlink_flash_write function */
+/*
+ * File: flash.c
+ *
+ * Tool st-flash - Simple wrapper around the stlink_flash_write function
+ */
-// TODO - this should be done as just a simple flag to the st-util command line...
-
-#include <signal.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/types.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#if defined(_WIN32)
+#include <win32_socket.h>
+#else
+#include <unistd.h>
+#endif // _WIN32
+
+#include <stm32.h>
#include <stlink.h>
#include "flash.h"
+#include "flash_opts.h"
+
+#include <chipid.h>
+#include <common_flash.h>
+#include <map_file.h>
+#include <option_bytes.h>
+#include <usb.h>
static stlink_t *connected_stlink = NULL;
-static void cleanup(int signum) {
+static void cleanup(int32_t signum) {
(void)signum;
if (connected_stlink) { // switch back to mass storage mode before closing
@@ -26,9 +44,9 @@ static void cleanup(int signum) {
}
static void usage(void) {
- puts("command line: ./st-flash [--debug] [--reset] [--connect-under-reset] [--hot-plug] [--opt] [--serial <serial>] [--format <format>] [--flash=<fsize>] [--freq=<KHz>] [--area=<area>] {read|write} [path] [addr] [size]");
- puts("command line: ./st-flash [--debug] [--connect-under-reset] [--hot-plug] [--freq=<KHz>] [--serial <serial>] erase");
- puts("command line: ./st-flash [--debug] [--freq=<KHz>] [--serial <serial>] reset");
+ puts("command line: ./st-flash [--debug] [--reset] [--connect-under-reset] [--hot-plug] [--opt] [--serial <serial>] [--format <format>] [--flash=<fsize>] [--freq=<kHz>] [--area=<area>] {read|write} [path] [addr] [size]");
+ puts("command line: ./st-flash [--debug] [--connect-under-reset] [--hot-plug] [--freq=<kHz>] [--serial <serial>] erase [addr] [size]");
+ puts("command line: ./st-flash [--debug] [--freq=<kHz>] [--serial <serial>] reset");
puts(" <addr>, <serial> and <size>: Use hex format.");
puts(" <fsize>: Use decimal, octal or hex (prefix 0xXXX) format, optionally followed by k=KB, or m=MB (eg. --flash=128k)");
puts(" <format>: Can be 'binary' (default) or 'ihex', although <addr> must be specified for binary format only.");
@@ -43,12 +61,14 @@ static void usage(void) {
puts("example write option control register1 byte: ./st-flash --area=optcr write 0xXXXXXXXX");
puts("example read option control register1 byte: ./st-flash --area=optcr1 read");
puts("example write option control register1 byte: ./st-flash --area=optcr1 write 0xXXXXXXXX");
+ puts("example read OTP area: ./st-flash --area=otp read [path]");
+ puts("example write OTP area: ./st-flash --area=otp write [path] 0xXXXXXXXX");
}
-int main(int ac, char** av) {
+int32_t main(int32_t ac, char** av) {
stlink_t* sl = NULL;
struct flash_opts o;
- int err = -1;
+ int32_t err = -1;
uint8_t * mem = NULL;
o.size = 0;
@@ -57,23 +77,25 @@ int main(int ac, char** av) {
if (flash_get_opts(&o, ac - 1, av + 1) == -1) {
printf("invalid command line\n");
usage();
- return(-1);
+ return (-1);
}
printf("st-flash %s\n", STLINK_VERSION);
+ init_chipids (STLINK_CHIPS_DIR);
sl = stlink_open_usb(o.log_level, o.connect, (char *)o.serial, o.freq);
- if (sl == NULL) { return(-1); }
+ if (sl == NULL) { return (-1); }
- if (sl->flash_type == STLINK_FLASH_TYPE_UNKNOWN) {
+ if (sl->flash_type == STM32_FLASH_TYPE_UNKNOWN) {
printf("Failed to connect to target\n");
- return(-1);
+ fprintf(stderr, "Failed to parse flash type or unrecognized flash type\n");
+ goto on_error;
}
if ( o.flash_size != 0u && o.flash_size != sl->flash_size ) {
sl->flash_size = o.flash_size;
- printf("Forcing flash size: --flash=0x%08X\n", (unsigned int)sl->flash_size);
+ printf("Forcing flash size: --flash=0x%08X\n", sl->flash_size);
}
sl->verbose = o.log_level;
@@ -84,20 +106,6 @@ int main(int ac, char** av) {
signal(SIGTERM, &cleanup);
signal(SIGSEGV, &cleanup);
- if (stlink_current_mode(sl) == STLINK_DEV_DFU_MODE) {
- if (stlink_exit_dfu_mode(sl)) {
- printf("Failed to exit DFU mode\n");
- goto on_error;
- }
- }
-
- if (stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE) {
- if (stlink_enter_swd_mode(sl)) {
- printf("Failed to enter SWD mode\n");
- goto on_error;
- }
- }
-
// core must be halted to use RAM based flashloaders
if (stlink_force_debug(sl)) {
printf("Failed to halt the core\n");
@@ -109,8 +117,10 @@ int main(int ac, char** av) {
goto on_error;
}
- if (o.cmd == FLASH_CMD_WRITE) { // write
- size_t size = 0;
+ if (o.cmd == FLASH_CMD_WRITE) {
+ uint32_t size = 0;
+
+ // write
if (o.format == FLASH_FORMAT_IHEX) {
err = stlink_parse_ihex(o.filename, stlink_get_erased_pattern(sl), &mem, &size, &o.addr);
@@ -119,10 +129,9 @@ int main(int ac, char** av) {
goto on_error;
}
}
- if ((o.addr >= sl->flash_base) &&
- (o.addr < sl->flash_base + sl->flash_size)) {
+ if ((o.addr >= sl->flash_base) && (o.addr < sl->flash_base + sl->flash_size)) {
if (o.format == FLASH_FORMAT_IHEX) {
- err = stlink_mwrite_flash(sl, mem, (uint32_t)size, o.addr);
+ err = stlink_mwrite_flash(sl, mem, size, o.addr);
} else {
err = stlink_fwrite_flash(sl, o.filename, o.addr);
}
@@ -131,10 +140,9 @@ int main(int ac, char** av) {
printf("stlink_fwrite_flash() == -1\n");
goto on_error;
}
- } else if ((o.addr >= sl->sram_base) &&
- (o.addr < sl->sram_base + sl->sram_size)) {
+ } else if ((o.addr >= sl->sram_base) && (o.addr < sl->sram_base + sl->sram_size)) {
if (o.format == FLASH_FORMAT_IHEX) {
- err = stlink_mwrite_sram(sl, mem, (uint32_t)size, o.addr);
+ err = stlink_mwrite_sram(sl, mem, size, o.addr);
} else {
err = stlink_fwrite_sram(sl, o.filename, o.addr);
}
@@ -143,8 +151,7 @@ int main(int ac, char** av) {
printf("stlink_fwrite_sram() == -1\n");
goto on_error;
}
- } else if ((o.addr >= sl->option_base) &&
- (o.addr < sl->option_base + sl->option_size)) {
+ } else if ((o.addr >= sl->option_base) && (o.addr < sl->option_base + sl->option_size)) {
err = stlink_fwrite_option_bytes(sl, o.filename, o.addr);
if (err == -1) {
@@ -165,34 +172,65 @@ int main(int ac, char** av) {
}
} else if (o.area == FLASH_OPTCR) {
DLOG("@@@@ Write %d (%0#10x) to option control register\n", o.val, o.val);
-
+
err = stlink_write_option_control_register32(sl, o.val);
} else if (o.area == FLASH_OPTCR1) {
DLOG("@@@@ Write %d (%0#10x) to option control register 1\n", o.val, o.val);
-
+
err = stlink_write_option_control_register1_32(sl, o.val);
} else if (o.area == FLASH_OPTION_BYTES_BOOT_ADD) {
DLOG("@@@@ Write %d (%0#10x) to option bytes boot address\n", o.val, o.val);
-
+
err = stlink_write_option_bytes_boot_add32(sl, o.val);
+ } else if (o.area == FLASH_OTP) {
+ if(sl->otp_base == 0) {
+ err = -1;
+ printf("OTP Write NOT implemented\n");
+ goto on_error;
+ }
+ err = stlink_fwrite_flash(sl, o.filename, o.addr);
+
+ if (err == -1) {
+ printf("stlink_fwrite_flash() == -1\n");
+ goto on_error;
+ }
} else {
err = -1;
printf("Unknown memory region\n");
goto on_error;
}
+
} else if (o.cmd == FLASH_CMD_ERASE) {
- err = stlink_erase_flash_mass(sl);
+ // erase
+ if (o.size > 0 && o.addr > 0) {
+ err = stlink_erase_flash_section(sl, o.addr, o.size, false);
+ } else {
+ err = stlink_erase_flash_mass(sl);
+ }
if (err == -1) {
printf("stlink_erase_flash_mass() == -1\n");
goto on_error;
}
+ printf("Mass erase completed successfully.\n");
+
+ // reset after erase
+ if (stlink_reset(sl, RESET_AUTO)) {
+ printf("Failed to reset device\n");
+ goto on_error;
+ }
+
} else if (o.cmd == CMD_RESET) {
+
+ // reset
if (stlink_reset(sl, RESET_AUTO)) {
printf("Failed to reset device\n");
goto on_error;
}
- } else { // read
+
+ } else {
+
+ // read
if ((o.area == FLASH_MAIN_MEMORY) || (o.area == FLASH_SYSTEM_MEMORY)) {
if ((o.size == 0) && (o.addr >= sl->flash_base) && (o.addr < sl->flash_base + sl->flash_size)) {
o.size = sl->flash_size;
@@ -207,23 +245,31 @@ int main(int ac, char** av) {
goto on_error;
}
} else if (o.area == FLASH_OPTION_BYTES) {
- uint8_t remaining_option_length = sl->option_size / 4;
- DLOG("@@@@ Read %d (%#x) option bytes from %#10x\n", remaining_option_length, remaining_option_length, sl->option_base);
-
- if (NULL != o.filename) {
- if (0 == o.size) {
- o.size = sl->option_size;
+ uint32_t remaining_option_length = sl->option_size / 4;
+ DLOG("@@@@ Read %u (%#x) option bytes from %#10x\n",
+ remaining_option_length,
+ remaining_option_length,
+ sl->option_base);
+
+ uint32_t option_byte = 0;
+ err = stlink_read_option_bytes32(sl, &option_byte);
+ if (err == -1) {
+ printf("could not read option bytes (%d)\n", err);
+ goto on_error;
+ } else if (NULL != o.filename) {
+ int32_t fd = open(o.filename, O_RDWR | O_TRUNC | O_CREAT | O_BINARY, 00700);
+ if (fd == -1) {
+ fprintf(stderr, "open(%s) == -1\n", o.filename);
+ goto on_error;
}
- err = stlink_fread(sl, o.filename, o.format == FLASH_FORMAT_IHEX, sl->option_base, o.size);
- } else {
- uint32_t option_byte = 0;
- err = stlink_read_option_bytes32(sl, &option_byte);
+ err = (uint32_t)write(fd, &option_byte, 4);
if (err == -1) {
- printf("could not read option bytes (%d)\n", err);
+ printf("could not write buffer to file (%d)\n", err);
goto on_error;
- } else {
- printf("%08x\n", option_byte);
}
+ close(fd);
+ } else {
+ printf("%08x\n", option_byte);
}
} else if (o.area == FLASH_OPTION_BYTES_BOOT_ADD) {
uint32_t option_byte = 0;
@@ -252,12 +298,23 @@ int main(int ac, char** av) {
} else {
printf("%08x\n",option_byte);
}
+ } else if (o.area == FLASH_OTP) {
+ if(sl->otp_base == 0) {
+ err = -1;
+ printf("OTP Read NOT implemented\n");
+ goto on_error;
+ }
+ err = stlink_fread(sl, o.filename, 0, sl->otp_base, sl->otp_size);
+ if (err == -1) {
+ printf("could not read OTP area (%d)\n", err);
+ goto on_error;
+ }
}
}
- if (o.reset) {
- stlink_reset(sl, RESET_AUTO);
- }
+ if (o.reset) stlink_reset(sl, RESET_AUTO);
+
+ stlink_run(sl, RUN_NORMAL);
err = 0; // success
@@ -266,5 +323,5 @@ on_error:
stlink_close(sl);
free(mem);
- return(err);
+ return (err);
}
diff --git a/src/st-flash/flash.h b/src/st-flash/flash.h
index cd08db7..889b2e4 100644
--- a/src/st-flash/flash.h
+++ b/src/st-flash/flash.h
@@ -1,36 +1,18 @@
-#ifndef STLINK_TOOLS_FLASH_H_
-#define STLINK_TOOLS_FLASH_H_
+/*
+ * File: flash.h
+ *
+ * Tool st-flash
+ */
-#include <stdint.h>
-
-#include <stlink.h>
+#ifndef FLASH_H
+#define FLASH_H
#define DEBUG_LOG_LEVEL 100
#define STND_LOG_LEVEL 50
#define ENABLE_OPT 1
-enum flash_cmd {FLASH_CMD_NONE = 0, FLASH_CMD_WRITE = 1, FLASH_CMD_READ = 2, FLASH_CMD_ERASE = 3, CMD_RESET = 4};
-enum flash_format {FLASH_FORMAT_BINARY = 0, FLASH_FORMAT_IHEX = 1};
-enum flash_area {FLASH_MAIN_MEMORY = 0, FLASH_SYSTEM_MEMORY = 1, FLASH_OTP = 2, FLASH_OPTION_BYTES = 3, FLASH_OPTION_BYTES_BOOT_ADD = 4, FLASH_OPTCR = 5, FLASH_OPTCR1 = 6};
-struct flash_opts {
- enum flash_cmd cmd;
- uint8_t serial[STLINK_SERIAL_BUFFER_SIZE];
- const char* filename;
- stm32_addr_t addr;
- size_t size;
- int reset;
- int log_level;
- enum flash_format format;
- enum flash_area area;
- uint32_t val;
- size_t flash_size; // --flash=n[k][m]
- int opt; // enable empty tail data drop optimization
- int freq; // --freq=n[k][m] frequency of JTAG/SWD
- enum connect_type connect;
-};
-
-#define FLASH_OPTS_INITIALIZER {0, { 0 }, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
-
-int flash_get_opts(struct flash_opts* o, int ac, char** av);
+// static stlink_t *connected_stlink = NULL;
+// static void cleanup(int32_t signum);
+// static void usage(void);
-#endif // STLINK_FLASH_H_
+#endif // FLASH_H
diff --git a/src/st-flash/flash_opts.c b/src/st-flash/flash_opts.c
index 172a244..e2d4154 100644
--- a/src/st-flash/flash_opts.c
+++ b/src/st-flash/flash_opts.c
@@ -1,15 +1,25 @@
-#include <stdlib.h>
+/*
+ * File: flash_opts.c
+ *
+ * Flash Options
+ */
+
+#include <stdint.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
-#include <helper.h>
-
+#include <stm32.h>
+#include <stlink.h>
+#include "flash_opts.h"
#include "flash.h"
+#include <helper.h>
+
static bool starts_with(const char * str, const char * prefix) {
- size_t n = strlen(prefix);
+ uint32_t n = strlen(prefix);
- if (strlen(str) < n) { return(false); }
+ if (strlen(str) < n) { return (false); }
return (0 == strncmp(str, prefix, n));
}
@@ -18,7 +28,7 @@ static bool starts_with(const char * str, const char * prefix) {
// support decimal, hexadecimal, octal, binary format like 0xff 12 1k 1M, 0b1001
// negative numbers are not supported
// return 0 if success else return -1
-static int get_long_integer_from_char_array (const char *const str, uint64_t *read_value) {
+static int32_t get_long_integer_from_char_array (const char *const str, uint64_t *read_value) {
uint64_t value;
char *tail;
@@ -39,50 +49,50 @@ static int get_long_integer_from_char_array (const char *const str, uint64_t *re
} else if (tail[0] == '\0') {
/* value not changed */
} else {
- return(-1);
+ return (-1);
}
*read_value = value;
- return(0);
+ return (0);
}
// support positive integer from 0 to UINT32_MAX
// support decimal, hexadecimal, octal, binary format like 0xff 12 1k 1M, 0b1001
// negative numbers are not supported
// return 0 if success else return -1
-static int get_integer_from_char_array (const char *const str, uint32_t *read_value) {
+static int32_t get_integer_from_char_array (const char *const str, uint32_t *read_value) {
uint64_t value;
- int result = get_long_integer_from_char_array (str, &value);
+ int32_t result = get_long_integer_from_char_array (str, &value);
if (result != 0) {
- return(result);
+ return (result);
} else if (value > UINT32_MAX) {
fprintf (stderr, "*** Error: Integer greater than UINT32_MAX, cannot convert to int32_t\n");
- return(-1);
+ return (-1);
} else {
- *read_value = (uint32_t)value;
- return(0);
+ *read_value = value;
+ return (0);
}
}
-static int invalid_args(const char *expected) {
+static int32_t invalid_args(const char *expected) {
fprintf(stderr, "*** Error: Expected args for this command: %s\n", expected);
- return(-1);
+ return (-1);
}
-static int bad_arg(const char *arg) {
+static int32_t bad_arg(const char *arg) {
fprintf(stderr, "*** Error: Invalid value for %s\n", arg);
- return(-1);
+ return (-1);
}
-int flash_get_opts(struct flash_opts* o, int ac, char** av) {
+int32_t flash_get_opts(struct flash_opts* o, int32_t ac, char** av) {
// defaults
memset(o, 0, sizeof(*o));
o->log_level = STND_LOG_LEVEL;
// options
- int result;
+ int32_t result;
while (ac >= 1) {
if (strcmp(av[0], "--version") == 0) {
@@ -101,7 +111,7 @@ int flash_get_opts(struct flash_opts* o, int ac, char** av) {
ac--;
av++;
- if (ac < 1) { return(-1); }
+ if (ac < 1) { return (-1); }
serial = av[0];
} else {
@@ -117,7 +127,7 @@ int flash_get_opts(struct flash_opts* o, int ac, char** av) {
ac--;
av++;
- if (ac < 1) { return(-1); }
+ if (ac < 1) { return (-1); }
area = av[0];
} else {
@@ -139,7 +149,7 @@ int flash_get_opts(struct flash_opts* o, int ac, char** av) {
} else if (strcmp(area, "optcr1") == 0) {
o->area = FLASH_OPTCR1;
} else {
- return(-1);
+ return (-1);
}
} else if (strcmp(av[0], "--freq") == 0) {
@@ -147,17 +157,17 @@ int flash_get_opts(struct flash_opts* o, int ac, char** av) {
av++;
if (ac < 1) {
- return(-1);
+ return (-1);
}
o->freq = arg_parse_freq(av[0]);
if (o->freq < 0) {
- return(-1);
+ return (-1);
}
} else if (starts_with(av[0], "--freq=")) {
o->freq = arg_parse_freq(av[0] + strlen("--freq="));
if (o->freq < 0) {
- return(-1);
+ return (-1);
}
} else if (strcmp(av[0], "--format") == 0 || starts_with(av[0], "--format=")) {
const char * format;
@@ -166,7 +176,7 @@ int flash_get_opts(struct flash_opts* o, int ac, char** av) {
ac--;
av++;
- if (ac < 1) { return(-1); }
+ if (ac < 1) { return (-1); }
format = av[0];
} else {
@@ -178,7 +188,7 @@ int flash_get_opts(struct flash_opts* o, int ac, char** av) {
} else if (strcmp(format, "ihex") == 0) {
o->format = FLASH_FORMAT_IHEX;
} else {
- return(bad_arg("format"));
+ return (bad_arg("format"));
}
} else if ( starts_with(av[0], "--flash=")) {
const char *arg = av[0] + strlen("--flash=");
@@ -187,7 +197,7 @@ int flash_get_opts(struct flash_opts* o, int ac, char** av) {
result = get_integer_from_char_array(arg, &flash_size);
if (result != 0) {
- return(bad_arg ("--flash"));
+ return (bad_arg ("--flash"));
} else {
o->flash_size = (size_t)flash_size;
}
@@ -207,18 +217,18 @@ int flash_get_opts(struct flash_opts* o, int ac, char** av) {
// command and (optional) device name
while (ac >= 1) {
if (strcmp(av[0], "erase") == 0) {
- if (o->cmd != FLASH_CMD_NONE) { return(-1); }
+ if (o->cmd != FLASH_CMD_NONE) { return (-1); }
o->cmd = FLASH_CMD_ERASE;
} else if (strcmp(av[0], "read") == 0) {
- if (o->cmd != FLASH_CMD_NONE) { return(-1); }
+ if (o->cmd != FLASH_CMD_NONE) { return (-1); }
o->cmd = FLASH_CMD_READ;
} else if (strcmp(av[0], "write") == 0) {
- if (o->cmd != FLASH_CMD_NONE) { return(-1); }
+ if (o->cmd != FLASH_CMD_NONE) { return (-1); }
o->cmd = FLASH_CMD_WRITE;
} else if (strcmp(av[0], "reset") == 0) {
- if (o->cmd != FLASH_CMD_NONE) { return(-1); }
+ if (o->cmd != FLASH_CMD_NONE) { return (-1); }
o->cmd = CMD_RESET;
} else {
@@ -231,10 +241,27 @@ int flash_get_opts(struct flash_opts* o, int ac, char** av) {
switch (o->cmd) {
case FLASH_CMD_NONE: // no command found
- return(-1);
+ return (-1);
case FLASH_CMD_ERASE: // no more arguments expected
- if (ac != 0) { return(-1); }
+ if (ac != 0 && ac != 2) { return (-1); }
+ if (ac == 2) {
+ uint32_t address;
+ result = get_integer_from_char_array(av[0], &address);
+ if (result != 0) {
+ return bad_arg ("addr");
+ } else {
+ o->addr = (stm32_addr_t) address;
+ }
+
+ uint32_t size;
+ result = get_integer_from_char_array(av[1], &size);
+ if (result != 0) {
+ return bad_arg ("size");
+ } else {
+ o->size = (size_t) size;
+ }
+ }
break;
@@ -261,8 +288,7 @@ int flash_get_opts(struct flash_opts* o, int ac, char** av) {
break;
} else if (o->area == FLASH_OTP) {
- return bad_arg("TODO: otp not implemented yet");
- if (ac > 1) { return invalid_args("otp read: [path]"); }
+ if (ac > 1 || ac ==0 ) { return invalid_args("otp read: [path]"); }
if (ac > 0) { o->filename = av[0]; }
break;
} else if (o->area == FLASH_OPTION_BYTES) {
@@ -300,7 +326,7 @@ int flash_get_opts(struct flash_opts* o, int ac, char** av) {
if (result != 0) {
return bad_arg ("val");
} else {
- o->val = (uint32_t) val;
+ o->val = val;
}
} else if (o->area == FLASH_OPTION_BYTES_BOOT_ADD) { // expect option bytes boot address
if (ac != 1) { return invalid_args("option bytes boot_add write <value>"); }
@@ -309,9 +335,9 @@ int flash_get_opts(struct flash_opts* o, int ac, char** av) {
result = get_integer_from_char_array(av[0], &val);
if (result != 0) {
- return(bad_arg ("val"));
+ return (bad_arg ("val"));
} else {
- o->val = (uint32_t)val;
+ o->val = val;
}
} else if (o->area == FLASH_OPTCR) { // expect option control register value
if (ac != 1) { return invalid_args("option control register write <value>"); }
@@ -322,7 +348,7 @@ int flash_get_opts(struct flash_opts* o, int ac, char** av) {
if (result != 0) {
return bad_arg ("val");
} else {
- o->val = (uint32_t) val;
+ o->val = val;
}
} else if (o->area == FLASH_OPTCR1) { // expect option control register 1 value
if (ac != 1) { return invalid_args("option control register 1 write <value>"); }
@@ -332,7 +358,7 @@ int flash_get_opts(struct flash_opts* o, int ac, char** av) {
if (result != 0) {
return bad_arg ("val");
} else {
- o->val = (uint32_t) val;
+ o->val = val;
}
} else if (o->format == FLASH_FORMAT_BINARY) { // expect filename and addr
if (ac != 2) { return invalid_args("write <path> <addr>"); }
@@ -342,16 +368,16 @@ int flash_get_opts(struct flash_opts* o, int ac, char** av) {
result = get_integer_from_char_array(av[1], &addr);
if (result != 0) {
- return(bad_arg ("addr"));
+ return (bad_arg ("addr"));
} else {
o->addr = (stm32_addr_t)addr;
}
} else if (o->format == FLASH_FORMAT_IHEX) { // expect filename
- if (ac != 1) { return(invalid_args("write <path>")); }
+ if (ac != 1) { return (invalid_args("write <path>")); }
o->filename = av[0];
} else {
- return(-1); // should have been caught during format parsing
+ return (-1); // should have been caught during format parsing
}
break;
@@ -359,5 +385,5 @@ int flash_get_opts(struct flash_opts* o, int ac, char** av) {
default: break;
}
- return(0);
+ return (0);
}
diff --git a/src/st-flash/flash_opts.h b/src/st-flash/flash_opts.h
new file mode 100644
index 0000000..0c0083d
--- /dev/null
+++ b/src/st-flash/flash_opts.h
@@ -0,0 +1,40 @@
+/*
+ * File: flash_opts.h
+ *
+ * Flash Options
+ */
+
+#ifndef FLASH_OPTS_H
+#define FLASH_OPTS_H
+
+#define FLASH_OPTS_INITIALIZER {0, { 0 }, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+
+enum flash_cmd {FLASH_CMD_NONE = 0, FLASH_CMD_WRITE = 1, FLASH_CMD_READ = 2, FLASH_CMD_ERASE = 3, CMD_RESET = 4};
+enum flash_format {FLASH_FORMAT_BINARY = 0, FLASH_FORMAT_IHEX = 1};
+enum flash_area {FLASH_MAIN_MEMORY = 0, FLASH_SYSTEM_MEMORY = 1, FLASH_OTP = 2, FLASH_OPTION_BYTES = 3, FLASH_OPTION_BYTES_BOOT_ADD = 4, FLASH_OPTCR = 5, FLASH_OPTCR1 = 6};
+
+struct flash_opts {
+ enum flash_cmd cmd;
+ uint8_t serial[STLINK_SERIAL_BUFFER_SIZE];
+ const char* filename;
+ stm32_addr_t addr;
+ uint32_t size;
+ int32_t reset;
+ int32_t log_level;
+ enum flash_format format;
+ enum flash_area area;
+ uint32_t val;
+ uint32_t flash_size; // --flash=n[k, M]
+ int32_t opt; // enable empty tail data drop optimization
+ int32_t freq; // --freq=n[k, M] frequency of JTAG/SWD
+ enum connect_type connect;
+};
+
+// static bool starts_with(const char * str, const char * prefix);
+// static int32_t get_long_integer_from_char_array (const char *const str, uint64_t *read_value);
+// static int32_t get_integer_from_char_array (const char *const str, uint32_t *read_value);
+// static int32_t invalid_args(const char *expected);
+// static int32_t bad_arg(const char *arg);
+int32_t flash_get_opts(struct flash_opts* o, int32_t ac, char** av);
+
+#endif // FLASH_OPTS_H
diff --git a/src/st-info/info.c b/src/st-info/info.c
index a6b4e85..ffdf521 100644
--- a/src/st-info/info.c
+++ b/src/st-info/info.c
@@ -1,20 +1,29 @@
+/*
+ * File: stinfo.c
+ *
+ * Tool st-info
+ */
+
+#include <stdint.h>
#include <stdio.h>
-#include <stdlib.h>
#include <string.h>
-#include <sys/types.h>
#include <stlink.h>
+#include "info.h"
+
+#include <chipid.h>
#include <helper.h>
+#include <usb.h>
static void usage(void) {
puts("st-info --version");
- puts("st-info --probe [--connect-under-reset] [--hot-plug] [--freq=<KHz>]");
+ puts("st-info --probe [--connect-under-reset] [--hot-plug] [--freq=<kHz>]");
puts("st-info --serial");
- puts("st-info --flash [--connect-under-reset] [--hot-plug] [--freq=<KHz>]");
- puts("st-info --pagesize [--connect-under-reset] [--hot-plug] [--freq=<KHz>]");
- puts("st-info --sram [--connect-under-reset] [--hot-plug] [--freq=<KHz>]");
- puts("st-info --chipid [--connect-under-reset] [--hot-plug] [--freq=<KHz>]");
- puts("st-info --descr [--connect-under-reset] [--hot-plug] [--freq=<KHz>]");
+ puts("st-info --flash [--connect-under-reset] [--hot-plug] [--freq=<kHz>]");
+ puts("st-info --pagesize [--connect-under-reset] [--hot-plug] [--freq=<kHz>]");
+ puts("st-info --sram [--connect-under-reset] [--hot-plug] [--freq=<kHz>]");
+ puts("st-info --chipid [--connect-under-reset] [--hot-plug] [--freq=<kHz>]");
+ puts("st-info --descr [--connect-under-reset] [--hot-plug] [--freq=<kHz>]");
}
static void stlink_print_version(stlink_t *sl) {
@@ -30,49 +39,47 @@ static void stlink_print_version(stlink_t *sl) {
static void stlink_print_info(stlink_t *sl) {
const struct stlink_chipid_params *params = NULL;
-
if (!sl) { return; }
- printf(" version: ");
- stlink_print_version(sl);
+ printf(" version: "); stlink_print_version(sl);
printf(" serial: %s\n", sl->serial);
- printf(" flash: %u (pagesize: %u)\n",
- (uint32_t)sl->flash_size, (uint32_t)sl->flash_pgsz);
- printf(" sram: %u\n", (uint32_t)sl->sram_size);
- printf(" chipid: 0x%.4x\n", sl->chip_id);
+ printf(" flash: %u (pagesize: %u)\n", sl->flash_size, sl->flash_pgsz);
+ printf(" sram: %u\n", sl->sram_size);
+ printf(" chipid: 0x%.3x\n", sl->chip_id);
params = stlink_chipid_get_params(sl->chip_id);
-
- if (params) { printf(" descr: %s\n", params->description); }
+ if (params) { printf(" dev-type: %s\n", params->dev_type); }
}
-static void stlink_probe(enum connect_type connect, int freq) {
+static void stlink_probe(enum connect_type connect, int32_t freq) {
stlink_t **stdevs;
- size_t size;
+ uint32_t size;
size = stlink_probe_usb(&stdevs, connect, freq);
- printf("Found %u stlink programmers\n", (unsigned int)size);
+ printf("Found %u stlink programmers\n", size);
- for (size_t n = 0; n < size; n++) {
- if (size > 1) printf("%u.\n", (unsigned int)n+1);
+ for (uint32_t n = 0; n < size; n++) {
+ if (size > 1) printf("%u.\n", n+1);
stlink_print_info(stdevs[n]);
}
stlink_probe_usb_free(&stdevs, size);
}
-static int print_data(int ac, char **av) {
+static int32_t print_data(int32_t ac, char **av) {
stlink_t* sl = NULL;
enum connect_type connect = CONNECT_NORMAL;
- int freq = 0;
+ int32_t freq = 0;
if (strcmp(av[1], "--version") == 0) {
printf("v%s\n", STLINK_VERSION);
- return(0);
+ return (0);
}
- for (int i=2; i<ac; i++) {
+ init_chipids(STLINK_CHIPS_DIR);
+
+ for (int32_t i=2; i<ac; i++) {
if (strcmp(av[i], "--connect-under-reset") == 0) {
connect = CONNECT_UNDER_RESET;
@@ -92,42 +99,34 @@ static int print_data(int ac, char **av) {
printf("Incorrect argument: %s\n\n", av[i]);
usage();
- return(-1);
+ return (-1);
}
// probe needs all devices unclaimed
if (strcmp(av[1], "--probe") == 0) {
stlink_probe(connect, freq);
- return(0);
+ return (0);
}
// open first st-link device
sl = stlink_open_usb(0, connect, NULL, freq);
-
- if (sl == NULL) { return(-1); }
-
- sl->verbose = 0;
-
- if (stlink_current_mode(sl) == STLINK_DEV_DFU_MODE) { stlink_exit_dfu_mode(sl); }
-
- if (stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE) { stlink_enter_swd_mode(sl); }
+ if (sl == NULL) { return (-1); }
if (strcmp(av[1], "--serial") == 0) {
printf("%s\n", sl->serial);
} else if (strcmp(av[1], "--flash") == 0) {
- printf("0x%x\n", (uint32_t)sl->flash_size);
+ printf("0x%x\n", sl->flash_size);
} else if (strcmp(av[1], "--pagesize") == 0) {
- printf("0x%x\n", (uint32_t)sl->flash_pgsz);
+ printf("0x%x\n", sl->flash_pgsz);
} else if (strcmp(av[1], "--sram") == 0) {
- printf("0x%x\n", (uint32_t)sl->sram_size);
+ printf("0x%x\n", sl->sram_size);
} else if (strcmp(av[1], "--chipid") == 0) {
printf("0x%.4x\n", sl->chip_id);
} else if (strcmp(av[1], "--descr") == 0) {
const struct stlink_chipid_params *params = stlink_chipid_get_params(sl->chip_id);
+ if (params == NULL) { return (-1); }
- if (params == NULL) { return(-1); }
-
- printf("%s\n", params->description);
+ printf("%s\n", params->dev_type);
}
if (sl) {
@@ -135,18 +134,18 @@ static int print_data(int ac, char **av) {
stlink_close(sl);
}
- return(0);
+ return (0);
}
-int main(int ac, char** av) {
- int err = -1;
+int32_t main(int32_t ac, char** av) {
+ int32_t err = -1;
if (ac < 2) {
usage();
- return(-1);
+ return (-1);
}
err = print_data(ac, av);
- return(err);
+ return (err);
}
diff --git a/src/st-info/info.h b/src/st-info/info.h
new file mode 100644
index 0000000..8e978e6
--- /dev/null
+++ b/src/st-info/info.h
@@ -0,0 +1,18 @@
+/*
+ * File: info.h
+ *
+ * Tool st-info
+ */
+
+#ifndef INFO_H
+#define INFO_H
+
+// static void usage(void);
+// static void stlink_print_version(stlink_t *sl);
+// static void stlink_print_info(stlink_t *sl);
+
+// static void stlink_probe(enum connect_type connect, int32_t freq) { };
+static int32_t print_data(int32_t ac, char **av);
+int32_t main(int32_t ac, char** av);
+
+#endif // INFO_H \ No newline at end of file
diff --git a/src/st-trace/trace.c b/src/st-trace/trace.c
index a02c647..591e292 100644
--- a/src/st-trace/trace.c
+++ b/src/st-trace/trace.c
@@ -3,16 +3,21 @@
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
+#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
-#include <logging.h>
-#include <reg.h>
#include <stlink.h>
+#include <chipid.h>
+#include <logging.h>
+#include <read_write.h>
+#include <register.h>
+#include <usb.h>
+
#define DEFAULT_LOGGING_LEVEL 50
#define DEBUG_LOGGING_LEVEL 100
@@ -41,7 +46,7 @@
typedef struct {
bool show_help;
bool show_version;
- int logging_level;
+ int32_t logging_level;
uint32_t core_frequency;
uint32_t trace_frequency;
bool reset_board;
@@ -88,24 +93,76 @@ static void abort_trace() { g_abort_trace = true; }
BOOL WINAPI CtrlHandler(DWORD fdwCtrlType) {
(void)fdwCtrlType;
abort_trace();
- return FALSE;
+ return TRUE;
}
#endif
+int32_t stlink_trace_enable(stlink_t *sl, uint32_t frequency) {
+ DLOG("*** stlink_trace_enable ***\n");
+ return (sl->backend->trace_enable(sl, frequency));
+}
+
+int32_t stlink_trace_disable(stlink_t *sl) {
+ DLOG("*** stlink_trace_disable ***\n");
+ return (sl->backend->trace_disable(sl));
+}
+
+int32_t stlink_trace_read(stlink_t *sl, uint8_t *buf, uint32_t size) {
+ return (sl->backend->trace_read(sl, buf, size));
+}
+
static void usage(void) {
puts("st-trace - usage:");
puts(" -h, --help Print this help");
puts(" -V, --version Print this version");
puts(" -vXX, --verbose=XX Specify a specific verbosity level (0..99)");
puts(" -v, --verbose Specify a generally verbose logging");
- puts(" -cXX, --clock=XX Specify the core frequency in MHz");
- puts(" -tXX, --trace=XX Specify the trace frequency in Hz");
+ puts(" -cXX, --clock=XX Specify the core frequency, optionally followed by");
+ puts(" k=kHz, m=MHz, or g=GHz (eg. --clock=180m)");
+ puts(" -tXX, --trace=XX Specify the trace frequency, optionally followed by");
+ puts(" k=kHz, m=MHz, or g=GHz (eg. --trace=2m)");
puts(" -n, --no-reset Do not reset board on connection");
puts(" -sXX, --serial=XX Use a specific serial number");
puts(" -f, --force Ignore most initialization errors");
}
-bool parse_options(int argc, char **argv, st_settings_t *settings) {
+static bool parse_frequency(char* text, uint32_t* result) {
+ if (text == NULL) {
+ ELOG("Invalid frequency.\n");
+ return false;
+ }
+
+ char* suffix = text;
+ double value = strtod(text, &suffix);
+
+ if (value == 0.0) {
+ ELOG("Invalid frequency.\n");
+ return false;
+ }
+
+ double scale = 1.0;
+ if (*suffix == 'k')
+ scale = 1000;
+ else if (*suffix == 'm')
+ scale = 1000000;
+ else if (*suffix == 'g')
+ scale = 1000000000;
+ else if (*suffix != '\0') {
+ ELOG("Unknown frequency suffix '%s'.\n", suffix);
+ return false;
+ }
+
+ value *= scale;
+ if (value <= 0 || value > 0xFFFFFFFFul) {
+ ELOG("Frequency is out of valid range.\n");
+ return false;
+ }
+
+ *result = (uint32_t)value;
+ return true;
+}
+
+bool parse_options(int32_t argc, char **argv, st_settings_t *settings) {
static struct option long_options[] = {
{"help", no_argument, NULL, 'h'},
@@ -118,8 +175,8 @@ bool parse_options(int argc, char **argv, st_settings_t *settings) {
{"force", no_argument, NULL, 'f'},
{0, 0, 0, 0},
};
- int option_index = 0;
- int c;
+ int32_t option_index = 0;
+ int32_t c;
bool error = false;
settings->show_help = false;
@@ -132,8 +189,7 @@ bool parse_options(int argc, char **argv, st_settings_t *settings) {
settings->serial_number = NULL;
ugly_init(settings->logging_level);
- while ((c = getopt_long(argc, argv, "hVv::c:ns:f", long_options,
- &option_index)) != -1) {
+ while ((c = getopt_long(argc, argv, "hVv::c:ns:f", long_options, &option_index)) != -1) {
switch (c) {
case 'h':
settings->show_help = true;
@@ -150,10 +206,10 @@ bool parse_options(int argc, char **argv, st_settings_t *settings) {
ugly_init(settings->logging_level);
break;
case 'c':
- settings->core_frequency = atoi(optarg) * 1000000;
+ if (!parse_frequency(optarg, &settings->core_frequency)) error = true;
break;
case 't':
- settings->trace_frequency = atoi(optarg);
+ if (!parse_frequency(optarg, &settings->trace_frequency)) error = true;
break;
case 'n':
settings->reset_board = false;
@@ -181,30 +237,24 @@ bool parse_options(int argc, char **argv, st_settings_t *settings) {
error = true;
}
- if (error && !settings->force)
- return false;
+ if (error && !settings->force) return false;
return true;
}
static stlink_t *stlink_connect(const st_settings_t *settings) {
- return stlink_open_usb(settings->logging_level, false,
- settings->serial_number, 0);
+ return stlink_open_usb(settings->logging_level, false, settings->serial_number, 0);
}
-static bool enable_trace(stlink_t *stlink, const st_settings_t *settings,
- uint32_t trace_frequency) {
+static bool enable_trace(stlink_t *stlink, const st_settings_t *settings, uint32_t trace_frequency) {
if (stlink_force_debug(stlink)) {
ELOG("Unable to debug device\n");
- if (!settings->force)
- return false;
+ if (!settings->force) return false;
}
-
- if (settings->reset_board && stlink_reset(stlink, RESET_AUTO)) {
+ if (settings->reset_board && stlink_reset(stlink, RESET_SOFT_AND_HALT)) {
ELOG("Unable to reset device\n");
- if (!settings->force)
- return false;
+ if (!settings->force) return false;
}
stlink_write_debug32(stlink, STLINK_REG_DHCSR,
@@ -218,29 +268,24 @@ static bool enable_trace(stlink_t *stlink, const st_settings_t *settings,
stlink_write_debug32(stlink, STLINK_REG_DWT_FUNCTION2, 0);
stlink_write_debug32(stlink, STLINK_REG_DWT_FUNCTION3, 0);
stlink_write_debug32(stlink, STLINK_REG_DWT_CTRL, 0);
- stlink_write_debug32(
- stlink, STLINK_REG_DBGMCU_CR,
+ stlink_write_debug32(stlink, STLINK_REG_DBGMCU_CR,
STLINK_REG_DBGMCU_CR_DBG_SLEEP | STLINK_REG_DBGMCU_CR_DBG_STOP |
STLINK_REG_DBGMCU_CR_DBG_STANDBY | STLINK_REG_DBGMCU_CR_TRACE_IOEN |
STLINK_REG_DBGMCU_CR_TRACE_MODE_ASYNC);
if (stlink_trace_enable(stlink, trace_frequency)) {
ELOG("Unable to turn on tracing in stlink\n");
- if (!settings->force)
- return false;
+ if (!settings->force) return false;
}
- stlink_write_debug32(stlink, STLINK_REG_TPI_CSPSR,
- STLINK_REG_TPI_CSPSR_PORT_SIZE_1);
+ stlink_write_debug32(stlink, STLINK_REG_TPI_CSPSR, STLINK_REG_TPI_CSPSR_PORT_SIZE_1);
if (settings->core_frequency) {
uint32_t prescaler = settings->core_frequency / trace_frequency - 1;
if (prescaler > STLINK_REG_TPI_ACPR_MAX) {
- ELOG("Trace frequency prescaler %d out of range. Try setting a faster "
- "trace frequency.\n",
- prescaler);
- if (!settings->force)
- return false;
+ ELOG("Trace frequency prescaler %d out of range. Try setting a faster "
+ "trace frequency.\n", prescaler);
+ if (!settings->force) return false;
}
stlink_write_debug32(stlink, STLINK_REG_TPI_ACPR,
prescaler); // Set TPIU_ACPR clock divisor
@@ -250,12 +295,11 @@ static bool enable_trace(stlink_t *stlink, const st_settings_t *settings,
stlink_write_debug32(stlink, STLINK_REG_TPI_SPPR,
STLINK_REG_TPI_SPPR_SWO_NRZ);
stlink_write_debug32(stlink, STLINK_REG_ITM_LAR, STLINK_REG_ITM_LAR_KEY);
- stlink_write_debug32(stlink, STLINK_REG_ITM_TCC,
- 0x00000400); // Set sync counter
+ stlink_write_debug32(stlink, STLINK_REG_ITM_TCC, 0x00000400); // Set sync counter
stlink_write_debug32(stlink, STLINK_REG_ITM_TCR,
STLINK_REG_ITM_TCR_TRACE_BUS_ID_1 |
- STLINK_REG_ITM_TCR_TS_ENA |
- STLINK_REG_ITM_TCR_ITM_ENA);
+ STLINK_REG_ITM_TCR_TS_ENA |
+ STLINK_REG_ITM_TCR_ITM_ENA);
stlink_write_debug32(stlink, STLINK_REG_ITM_TER,
STLINK_REG_ITM_TER_PORTS_ALL);
stlink_write_debug32(stlink, STLINK_REG_ITM_TPR,
@@ -268,13 +312,12 @@ static bool enable_trace(stlink_t *stlink, const st_settings_t *settings,
STLINK_REG_DWT_CTRL_CYCCNT_ENA);
stlink_write_debug32(stlink, STLINK_REG_DEMCR, STLINK_REG_DEMCR_TRCENA);
- uint32_t prescaler;
- stlink_read_debug32(stlink, STLINK_REG_TPI_ACPR_MAX, &prescaler);
+ uint32_t prescaler = 0;
+ stlink_read_debug32(stlink, STLINK_REG_TPI_ACPR, &prescaler);
if (prescaler) {
uint32_t system_clock_speed = (prescaler + 1) * trace_frequency;
- uint32_t system_clock_speed_mhz = (system_clock_speed + 500000) / 1000000;
- ILOG("Trace Port Interface configured to expect a %d MHz system clock.\n",
- system_clock_speed_mhz);
+ ILOG("Trace Port Interface configured to expect a %d Hz system clock.\n",
+ system_clock_speed);
} else {
WLOG("Trace Port Interface not configured. Specify the system clock with "
"a --clock=XX command\n");
@@ -290,9 +333,7 @@ static bool enable_trace(stlink_t *stlink, const st_settings_t *settings,
static trace_state update_trace_idle(st_trace_t *trace, uint8_t c) {
// Handle a trace byte when we are in the idle state.
- if (TRACE_OP_IS_TARGET_SOURCE(c)) {
- return TRACE_STATE_TARGET_SOURCE;
- }
+ if (TRACE_OP_IS_TARGET_SOURCE(c)) return TRACE_STATE_TARGET_SOURCE;
if (TRACE_OP_IS_SOURCE(c)) {
uint8_t size = TRACE_OP_GET_SOURCE_SIZE(c);
@@ -302,36 +343,28 @@ static trace_state update_trace_idle(st_trace_t *trace, uint8_t c) {
WLOG("Unsupported source 0x%x size %d\n", addr, size);
trace->unknown_sources |= (1 << addr);
}
- if (size == 1)
- return TRACE_STATE_SKIP_1;
- if (size == 2)
- return TRACE_STATE_SKIP_2;
- if (size == 3)
- return TRACE_STATE_SKIP_4;
+ if (size == 1) return TRACE_STATE_SKIP_1;
+ if (size == 2) return TRACE_STATE_SKIP_2;
+ if (size == 3) return TRACE_STATE_SKIP_4;
}
if (TRACE_OP_IS_LOCAL_TIME(c) || TRACE_OP_IS_GLOBAL_TIME(c)) {
trace->count_time_packets++;
- return TRACE_OP_GET_CONTINUATION(c) ? TRACE_STATE_SKIP_FRAME
- : TRACE_STATE_IDLE;
+ return TRACE_OP_GET_CONTINUATION(c) ? TRACE_STATE_SKIP_FRAME : TRACE_STATE_IDLE;
}
if (TRACE_OP_IS_EXTENSION(c)) {
- return TRACE_OP_GET_CONTINUATION(c) ? TRACE_STATE_SKIP_FRAME
- : TRACE_STATE_IDLE;
+ return TRACE_OP_GET_CONTINUATION(c) ? TRACE_STATE_SKIP_FRAME : TRACE_STATE_IDLE;
}
- if (TRACE_OP_IS_OVERFLOW(c)) {
- trace->count_hw_overflow++;
- }
+ if (TRACE_OP_IS_OVERFLOW(c)) trace->count_hw_overflow++;
if (!(trace->unknown_opcodes[c / 8] & (1 << c % 8)))
WLOG("Unknown opcode 0x%02x\n", c);
trace->unknown_opcodes[c / 8] |= (1 << c % 8);
trace->count_error++;
- return TRACE_OP_GET_CONTINUATION(c) ? TRACE_STATE_SKIP_FRAME
- : TRACE_STATE_IDLE;
+ return TRACE_OP_GET_CONTINUATION(c) ? TRACE_STATE_SKIP_FRAME : TRACE_STATE_IDLE;
}
static trace_state update_trace(st_trace_t *trace, uint8_t c) {
@@ -340,8 +373,7 @@ static trace_state update_trace(st_trace_t *trace, uint8_t c) {
// Parse the input using a state machine.
if (trace->state == TRACE_STATE_UNKNOWN) {
- if (TRACE_OP_IS_TARGET_SOURCE(c) || TRACE_OP_IS_LOCAL_TIME(c) ||
- TRACE_OP_IS_GLOBAL_TIME(c))
+ if (TRACE_OP_IS_TARGET_SOURCE(c) || TRACE_OP_IS_LOCAL_TIME(c) || TRACE_OP_IS_GLOBAL_TIME(c))
trace->state = TRACE_STATE_IDLE;
}
@@ -351,14 +383,12 @@ static trace_state update_trace(st_trace_t *trace, uint8_t c) {
case TRACE_STATE_TARGET_SOURCE:
putchar(c);
- if (c == '\n')
- fflush(stdout);
+ if (c == '\n') fflush(stdout);
trace->count_target_data++;
return TRACE_STATE_IDLE;
case TRACE_STATE_SKIP_FRAME:
- return TRACE_OP_GET_CONTINUATION(c) ? TRACE_STATE_SKIP_FRAME
- : TRACE_STATE_IDLE;
+ return TRACE_OP_GET_CONTINUATION(c) ? TRACE_STATE_SKIP_FRAME : TRACE_STATE_IDLE;
case TRACE_STATE_SKIP_4:
return TRACE_STATE_SKIP_3;
@@ -382,8 +412,8 @@ static trace_state update_trace(st_trace_t *trace, uint8_t c) {
}
static bool read_trace(stlink_t *stlink, st_trace_t *trace) {
- uint8_t buffer[STLINK_TRACE_BUF_LEN];
- int length = stlink_trace_read(stlink, buffer, sizeof(buffer));
+ uint8_t* buffer = 0;
+ int32_t length = stlink_trace_read(stlink, buffer, sizeof(buffer));
if (length < 0) {
ELOG("Error reading trace (%d)\n", length);
@@ -403,15 +433,14 @@ static bool read_trace(stlink_t *stlink, st_trace_t *trace) {
trace->state = TRACE_STATE_UNKNOWN;
}
- for (int i = 0; i < length; i++) {
+ for (int32_t i = 0; i < length; i++) {
trace->state = update_trace(trace, buffer[i]);
}
return true;
}
-static void check_for_configuration_error(stlink_t *stlink, st_trace_t *trace,
- uint32_t trace_frequency) {
+static void check_for_configuration_error(stlink_t *stlink, st_trace_t *trace, uint32_t trace_frequency) {
// Only check configuration one time after the first 10 seconds of running.
time_t elapsed_time_s = time(NULL) - trace->start_time;
if (trace->configuration_checked || elapsed_time_s < 10) {
@@ -426,8 +455,7 @@ static void check_for_configuration_error(stlink_t *stlink, st_trace_t *trace,
bool error_bad_data = (trace->count_error > 1 || trace->unknown_sources > 0);
bool error_dropped_data = (trace->count_sw_overflow > 0);
- if (!error_no_data && !error_low_data && !error_bad_data &&
- !error_dropped_data)
+ if (!error_no_data && !error_low_data && !error_bad_data && !error_dropped_data)
return;
WLOG("****\n");
@@ -440,13 +468,11 @@ static void check_for_configuration_error(stlink_t *stlink, st_trace_t *trace,
}
if (error_no_data || error_low_data || error_bad_data) {
- uint32_t prescaler;
+ uint32_t prescaler = 0;
stlink_read_debug32(stlink, STLINK_REG_TPI_ACPR, &prescaler);
if (prescaler) {
uint32_t system_clock_speed = (prescaler + 1) * trace_frequency;
- uint32_t system_clock_speed_mhz = (system_clock_speed + 500000) / 1000000;
- WLOG("Verify the system clock is running at %d MHz.\n",
- system_clock_speed_mhz);
+ WLOG("Verify the system clock is running at %d Hz.\n", system_clock_speed);
}
WLOG("Try specifying the system clock with the --clock=XX command line "
"option.\n");
@@ -468,11 +494,8 @@ static void check_for_configuration_error(stlink_t *stlink, st_trace_t *trace,
uint32_t offset = 0;
for (uint32_t i = 0; i <= 0xFF; i++)
if (trace->unknown_opcodes[i / 8] & (1 << i % 8)) {
- uint32_t n =
- snprintf(buffer + offset, sizeof(buffer) - offset, "%02x, ", i);
- if (n >= sizeof(buffer) - offset) {
- break;
- }
+ uint32_t n = snprintf(buffer + offset, sizeof(buffer) - offset, "%02x, ", i);
+ if (n >= sizeof(buffer) - offset) break;
offset += n;
}
WLOG("Unknown Opcodes: %s\n", buffer);
@@ -481,11 +504,8 @@ static void check_for_configuration_error(stlink_t *stlink, st_trace_t *trace,
offset = 0;
for (uint32_t i = 0; i < 32; i++)
if (trace->unknown_sources & (1 << i)) {
- uint32_t n =
- snprintf(buffer + offset, sizeof(buffer) - offset, "%d, ", i);
- if (n >= sizeof(buffer) - offset) {
- break;
- }
+ uint32_t n = snprintf(buffer + offset, sizeof(buffer) - offset, "%d, ", i);
+ if (n >= sizeof(buffer) - offset) break;
offset += n;
}
WLOG("Unknown Sources: %s\n", buffer);
@@ -494,7 +514,7 @@ static void check_for_configuration_error(stlink_t *stlink, st_trace_t *trace,
WLOG("****\n");
}
-int main(int argc, char **argv) {
+int32_t main(int32_t argc, char **argv) {
#if defined(_WIN32)
SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE);
#else
@@ -509,6 +529,7 @@ int main(int argc, char **argv) {
usage();
return APP_RESULT_INVALID_PARAMS;
}
+ init_chipids (STLINK_CHIPS_DIR);
DLOG("show_help = %s\n", settings.show_help ? "true" : "false");
DLOG("show_version = %s\n", settings.show_version ? "true" : "false");
@@ -538,40 +559,40 @@ int main(int argc, char **argv) {
stlink->verbose = settings.logging_level;
- if (stlink->chip_id == STLINK_CHIPID_UNKNOWN) {
+ if (stlink->chip_id == STM32_CHIPID_UNKNOWN) {
ELOG("Your stlink is not connected to a device\n");
- if (!settings.force)
- return APP_RESULT_STLINK_MISSING_DEVICE;
+ if (!settings.force) return APP_RESULT_STLINK_MISSING_DEVICE;
}
if (!(stlink->version.flags & STLINK_F_HAS_TRACE)) {
ELOG("Your stlink does not support tracing\n");
- if (!settings.force)
- return APP_RESULT_STLINK_UNSUPPORTED_LINK;
+ if (!settings.force) return APP_RESULT_STLINK_UNSUPPORTED_LINK;
}
if (!(stlink->chip_flags & CHIP_F_HAS_SWO_TRACING)) {
- const struct stlink_chipid_params *params =
- stlink_chipid_get_params(stlink->chip_id);
- ELOG("We do not support SWO output for device '%s'\n", params->description);
- if (!settings.force)
- return APP_RESULT_STLINK_UNSUPPORTED_DEVICE;
+ const struct stlink_chipid_params *params = stlink_chipid_get_params(stlink->chip_id);
+ ELOG("We do not support SWO output for device '%s'\n", params ? params->dev_type : "");
+ if (!settings.force) return APP_RESULT_STLINK_UNSUPPORTED_DEVICE;
}
uint32_t trace_frequency = settings.trace_frequency;
- if (!trace_frequency)
- trace_frequency = STLINK_DEFAULT_TRACE_FREQUENCY;
- if (trace_frequency > stlink->max_trace_freq) {
- ELOG("Invalid trace frequency %d (max %d)\n", trace_frequency,
- stlink->max_trace_freq);
- if (!settings.force)
- return APP_RESULT_UNSUPPORTED_TRACE_FREQUENCY;
+ if (!trace_frequency) trace_frequency = STLINK_DEFAULT_TRACE_FREQUENCY;
+ uint32_t max_trace_freq = stlink->max_trace_freq;
+ uint32_t min_trace_freq = 0;
+
+ if (settings.core_frequency != 0) {
+ if (max_trace_freq > settings.core_frequency / 5) max_trace_freq = settings.core_frequency / 5;
+ min_trace_freq = settings.core_frequency / (STLINK_REG_TPI_ACPR_MAX + 1);
+ }
+ if (trace_frequency > max_trace_freq || trace_frequency < min_trace_freq) {
+ ELOG("Invalid trace frequency %d (min %d max %d)\n", trace_frequency, min_trace_freq,
+ max_trace_freq);
+ if (!settings.force) return APP_RESULT_UNSUPPORTED_TRACE_FREQUENCY;
}
if (!enable_trace(stlink, &settings, trace_frequency)) {
ELOG("Unable to enable trace mode\n");
- if (!settings.force)
- return APP_RESULT_STLINK_STATE_ERROR;
+ if (!settings.force) return APP_RESULT_STLINK_STATE_ERROR;
}
ILOG("Reading Trace\n");
@@ -581,8 +602,7 @@ int main(int argc, char **argv) {
if (stlink_run(stlink, RUN_NORMAL)) {
ELOG("Unable to run device\n");
- if (!settings.force)
- return APP_RESULT_STLINK_STATE_ERROR;
+ if (!settings.force) return APP_RESULT_STLINK_STATE_ERROR;
}
while (!g_abort_trace && read_trace(stlink, &trace)) {
diff --git a/src/st-trace/trace.h b/src/st-trace/trace.h
new file mode 100644
index 0000000..8dfc7e4
--- /dev/null
+++ b/src/st-trace/trace.h
@@ -0,0 +1,24 @@
+/*
+ * File: trace.h
+ *
+ * Tool st-trace
+ */
+
+#ifndef TRACE_H
+#define TRACE_H
+
+int32_t stlink_trace_enable(stlink_t* sl, uint32_t frequency);
+int32_t stlink_trace_disable(stlink_t* sl);
+int32_t stlink_trace_read(stlink_t* sl, uint8_t* buf, uint32_t size);
+
+static void usage(void);
+static bool parse_frequency(char* text, uint32_t* result);
+bool parse_options(int32_t argc, char **argv, st_settings_t *settings);
+static stlink_t *stlink_connect(const st_settings_t *settings);
+static bool enable_trace(stlink_t *stlink, const st_settings_t *settings, uint32_t trace_frequency);
+static trace_state update_trace_idle(st_trace_t *trace, uint8_t c);
+static trace_state update_trace(st_trace_t *trace, uint8_t c);
+static bool read_trace(stlink_t *stlink, st_trace_t *trace);
+static void check_for_configuration_error(stlink_t *stlink, st_trace_t *trace, uint32_t trace_frequency);
+
+#endif // TRACE_H \ No newline at end of file
diff --git a/src/st-util/gdb-remote.c b/src/st-util/gdb-remote.c
index bdf8afd..25ca4da 100644
--- a/src/st-util/gdb-remote.c
+++ b/src/st-util/gdb-remote.c
@@ -5,8 +5,8 @@
#include <stdio.h>
#include <string.h>
-#include <stdlib.h>
#include <stdint.h>
+#include <stdlib.h>
#if defined(_WIN32)
#include <win32_socket.h>
@@ -19,9 +19,9 @@
static const char hex[] = "0123456789abcdef";
-int gdb_send_packet(int fd, char* data) {
- unsigned int data_length = (unsigned int)strlen(data);
- int length = data_length + 4;
+int32_t gdb_send_packet(int32_t fd, char* data) {
+ uint32_t data_length = (uint32_t)strlen(data);
+ int32_t length = data_length + 4;
char* packet = malloc(length); // '$' data (hex) '#' cksum (hex)
memset(packet, 0, length);
@@ -30,7 +30,7 @@ int gdb_send_packet(int fd, char* data) {
uint8_t cksum = 0;
- for (unsigned int i = 0; i < data_length; i++) {
+ for (uint32_t i = 0; i < data_length; i++) {
packet[i + 1] = data[i];
cksum += data[i];
}
@@ -42,34 +42,34 @@ int gdb_send_packet(int fd, char* data) {
while (1) {
if (write(fd, packet, length) != length) {
free(packet);
- return(-2);
+ return (-2);
}
char ack;
if (read(fd, &ack, 1) != 1) {
free(packet);
- return(-2);
+ return (-2);
}
if (ack == '+') {
free(packet);
- return(0);
+ return (0);
}
}
}
#define ALLOC_STEP 1024
-int gdb_recv_packet(int fd, char** buffer) {
- unsigned packet_size = ALLOC_STEP + 1, packet_idx = 0;
+int32_t gdb_recv_packet(int32_t fd, char** buffer) {
+ uint32_t packet_size = ALLOC_STEP + 1, packet_idx = 0;
uint8_t cksum = 0;
char recv_cksum[3] = {0};
char* packet_buffer = malloc(packet_size);
- unsigned state;
+ uint32_t state;
if (packet_buffer == NULL) {
- return(-2);
+ return (-2);
}
start:
@@ -88,7 +88,7 @@ start:
while (state != 4) {
if (read(fd, &c, 1) != 1) {
free(packet_buffer);
- return(-2);
+ return (-2);
}
switch (state) {
@@ -117,7 +117,7 @@ start:
packet_buffer = p;
} else {
free(packet_buffer);
- return(-2);
+ return (-2);
}
}
}
@@ -143,7 +143,7 @@ start:
if (write(fd, &nack, 1) != 1) {
free(packet_buffer);
- return(-2);
+ return (-2);
}
goto start;
@@ -152,14 +152,14 @@ start:
if (write(fd, &ack, 1) != 1) {
free(packet_buffer);
- return(-2);
+ return (-2);
}
}
packet_buffer[packet_idx] = 0;
*buffer = packet_buffer;
- return(packet_idx);
+ return (packet_idx);
}
/*
@@ -167,7 +167,7 @@ start:
* As we use the mode with ACK, in a (very unlikely) situation of a packet lost
* because of this skipping, it will be resent anyway.
*/
-int gdb_check_for_interrupt(int fd) {
+int32_t gdb_check_for_interrupt(int32_t fd) {
struct pollfd pfd;
pfd.fd = fd;
pfd.events = POLLIN;
@@ -176,13 +176,13 @@ int gdb_check_for_interrupt(int fd) {
char c;
if (read(fd, &c, 1) != 1) {
- return(-2);
+ return (-2);
}
if (c == '\x03') {
- return(1); // ^C
+ return (1); // ^C
}
}
- return(0);
+ return (0);
}
diff --git a/src/st-util/gdb-remote.h b/src/st-util/gdb-remote.h
index 6e76746..ec99045 100644
--- a/src/st-util/gdb-remote.h
+++ b/src/st-util/gdb-remote.h
@@ -1,8 +1,10 @@
-#ifndef _GDB_REMOTE_H_
-#define _GDB_REMOTE_H_
+#ifndef GDB_REMOTE_H
+#define GDB_REMOTE_H
-int gdb_send_packet(int fd, char* data);
-int gdb_recv_packet(int fd, char** buffer);
-int gdb_check_for_interrupt(int fd);
+#include <stdint.h>
-#endif // _GDB_REMOTE_H_
+int32_t gdb_send_packet(int32_t fd, char* data);
+int32_t gdb_recv_packet(int32_t fd, char** buffer);
+int32_t gdb_check_for_interrupt(int32_t fd);
+
+#endif // GDB_REMOTE_H
diff --git a/src/st-util/gdb-server.c b/src/st-util/gdb-server.c
index 006a0e3..28e0623 100644
--- a/src/st-util/gdb-server.c
+++ b/src/st-util/gdb-server.c
@@ -8,6 +8,7 @@
#include <signal.h>
#include <stdio.h>
#include <string.h>
+#include <stdint.h>
#include <stdlib.h>
#include <sys/types.h>
@@ -26,12 +27,20 @@
#endif
#include <stlink.h>
-#include <helper.h>
-#include <logging.h>
-#include "gdb-remote.h"
#include "gdb-server.h"
+#include "gdb-remote.h"
+#include "memory-map.h"
#include "semihosting.h"
+#include <chipid.h>
+#include <common_flash.h>
+#include <flash_loader.h>
+#include <helper.h>
+#include <logging.h>
+#include <read_write.h>
+#include <register.h>
+#include <usb.h>
+
#define FLASH_BASE 0x08000000
// Semihosting doesn't have a short option, we define a value to identify it
@@ -56,18 +65,18 @@ static const char hex[] = "0123456789abcdef";
typedef struct _st_state_t {
// things from command line, bleh
- int logging_level;
- int listen_port;
- int persistent;
+ int32_t logging_level;
+ int32_t listen_port;
+ int32_t persistent;
enum connect_type connect_mode;
- int freq;
+ int32_t freq;
char serialnumber[STLINK_SERIAL_BUFFER_SIZE];
bool semihosting;
const char* current_memory_map;
} st_state_t;
-int serve(stlink_t *sl, st_state_t *st);
+int32_t serve(stlink_t *sl, st_state_t *st);
char* make_memory_map(stlink_t *sl);
static void init_cache(stlink_t *sl);
@@ -80,7 +89,7 @@ static void _cleanup() {
}
}
-static void cleanup(int signum) {
+static void cleanup(int32_t signum) {
printf("Receive signal %i. Exiting...\n", signum);
_cleanup();
exit(1);
@@ -89,13 +98,13 @@ static void cleanup(int signum) {
#if defined(_WIN32)
BOOL WINAPI CtrlHandler(DWORD fdwCtrlType) {
- printf("Receive signal %i. Exiting...\r\n", (int)fdwCtrlType);
+ printf("Receive signal %i. Exiting...\r\n", (int32_t)fdwCtrlType);
_cleanup();
return FALSE;
}
#endif
-int parse_options(int argc, char** argv, st_state_t *st) {
+int32_t parse_options(int32_t argc, char** argv, st_state_t *st) {
static struct option long_options[] = {
{"help", no_argument, NULL, 'h'},
{"verbose", optional_argument, NULL, 'v'},
@@ -113,7 +122,7 @@ int parse_options(int argc, char** argv, st_state_t *st) {
const char * help_str = "%s - usage:\n\n"
" -h, --help\t\tPrint this help\n"
" -V, --version\t\tPrint the version\n"
- " -vXX, --verbose=XX\tSpecify a specific verbosity level (0..99)\n"
+ " -vXX, --verbose=XX\tSpecify a specific verbosity level (0...99)\n"
" -v, --verbose\t\tSpecify generally verbose logging\n"
" -p 4242, --listen_port=1234\n"
"\t\t\tSet the gdb server listen port. "
@@ -124,8 +133,8 @@ int parse_options(int argc, char** argv, st_state_t *st) {
" -n, --no-reset, --hot-plug\n"
"\t\t\tDo not reset board on connection.\n"
" -u, --connect-under-reset\n"
- "\t\t\tConnect to the board before executing any instructions.\n"
- " -F 1800K, --freq=1M\n"
+ "\t\t\tConnect to the board before executing any instructions.\n"
+ " -F 1800k, --freq=1M\n"
"\t\t\tSet the frequency of the SWD/JTAG interface.\n"
" --semihosting\n"
"\t\t\tEnable semihosting support.\n"
@@ -138,11 +147,11 @@ int parse_options(int argc, char** argv, st_state_t *st) {
;
- int option_index = 0;
- int c;
- int q;
+ int32_t option_index = 0;
+ int32_t c;
+ int32_t q;
- while ((c = getopt_long(argc, argv, "hv::p:mn", long_options, &option_index)) != -1)
+ while ((c = getopt_long(argc, argv, "hv::p:mnu", long_options, &option_index)) != -1)
switch (c) {
case 0:
break;
@@ -159,15 +168,17 @@ int parse_options(int argc, char** argv, st_state_t *st) {
break;
case 'p':
- sscanf(optarg, "%i", &q);
- if (q < 0) {
+ if (sscanf(optarg, "%i", &q) != 1) {
+ fprintf(stderr, "Invalid port %s\n", optarg);
+ exit(EXIT_FAILURE);
+ } else if (q < 0) {
fprintf(stderr, "Can't use a negative port to listen on: %d\n", q);
exit(EXIT_FAILURE);
}
st->listen_port = q;
break;
-
+
case 'm':
st->persistent = true;
break;
@@ -205,10 +216,10 @@ int parse_options(int argc, char** argv, st_state_t *st) {
printf("\n");
}
- return(0);
+ return (0);
}
-int main(int argc, char** argv) {
+int32_t main(int32_t argc, char** argv) {
stlink_t *sl = NULL;
st_state_t state;
memset(&state, 0, sizeof(state));
@@ -219,14 +230,16 @@ int main(int argc, char** argv) {
state.connect_mode = CONNECT_NORMAL; // by default, reset board
parse_options(argc, argv, &state);
- printf("st-util\n");
+ printf("st-util %s\n", STLINK_VERSION);
+
+ init_chipids (STLINK_CHIPS_DIR);
sl = stlink_open_usb(state.logging_level, state.connect_mode, state.serialnumber, state.freq);
- if (sl == NULL) { return(1); }
+ if (sl == NULL) { return (1); }
- if (sl->chip_id == STLINK_CHIPID_UNKNOWN) {
+ if (sl->chip_id == STM32_CHIPID_UNKNOWN) {
ELOG("Unsupported Target (Chip ID is %#010x, Core ID is %#010x).\n", sl->chip_id, sl->core_id);
- return(1);
+ return (1);
}
sl->verbose = 0;
@@ -264,7 +277,7 @@ winsock_error:
stlink_exit_debug_mode(sl);
stlink_close(sl);
- return(0);
+ return (0);
}
static const char* const target_description =
@@ -332,248 +345,59 @@ static const char* const target_description =
" </feature>"
"</target>";
-static const char* const memory_map_template_F4 =
- "<?xml version=\"1.0\"?>"
- "<!DOCTYPE memory-map PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\""
- " \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"
- "<memory-map>"
- " <memory type=\"rom\" start=\"0x00000000\" length=\"0x100000\"/>" // code = sram, bootrom or flash; flash is bigger
- " <memory type=\"ram\" start=\"0x10000000\" length=\"0x10000\"/>" // ccm ram
- " <memory type=\"ram\" start=\"0x20000000\" length=\"0x20000\"/>" // sram
- " <memory type=\"flash\" start=\"0x08000000\" length=\"0x10000\">" // Sectors 0..3
- " <property name=\"blocksize\">0x4000</property>" // 16kB
- " </memory>"
- " <memory type=\"flash\" start=\"0x08010000\" length=\"0x10000\">" // Sector 4
- " <property name=\"blocksize\">0x10000</property>" // 64kB
- " </memory>"
- " <memory type=\"flash\" start=\"0x08020000\" length=\"0xE0000\">" // Sectors 5..11
- " <property name=\"blocksize\">0x20000</property>" // 128kB
- " </memory>"
- " <memory type=\"ram\" start=\"0x40000000\" length=\"0x1fffffff\"/>" // peripheral regs
- " <memory type=\"ram\" start=\"0x60000000\" length=\"0x7fffffff\"/>" // AHB3 Peripherals
- " <memory type=\"ram\" start=\"0xe0000000\" length=\"0x1fffffff\"/>" // cortex regs
- " <memory type=\"rom\" start=\"0x1fff0000\" length=\"0x7800\"/>" // bootrom
- " <memory type=\"rom\" start=\"0x1fffc000\" length=\"0x10\"/>" // option byte area
- "</memory-map>";
-
-static const char* const memory_map_template_F4_HD =
- "<?xml version=\"1.0\"?>"
- "<!DOCTYPE memory-map PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\""
- " \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"
- "<memory-map>"
- " <memory type=\"rom\" start=\"0x00000000\" length=\"0x100000\"/>" // code = sram, bootrom or flash; flash is bigger
- " <memory type=\"ram\" start=\"0x10000000\" length=\"0x10000\"/>" // ccm ram
- " <memory type=\"ram\" start=\"0x20000000\" length=\"0x40000\"/>" // sram
- " <memory type=\"ram\" start=\"0x60000000\" length=\"0x10000000\"/>" // fmc bank 1 (nor/psram/sram)
- " <memory type=\"ram\" start=\"0x70000000\" length=\"0x20000000\"/>" // fmc bank 2 & 3 (nand flash)
- " <memory type=\"ram\" start=\"0x90000000\" length=\"0x10000000\"/>" // fmc bank 4 (pc card)
- " <memory type=\"ram\" start=\"0xC0000000\" length=\"0x20000000\"/>" // fmc sdram bank 1 & 2
- " <memory type=\"flash\" start=\"0x08000000\" length=\"0x10000\">" // Sectors 0..3
- " <property name=\"blocksize\">0x4000</property>" // 16kB
- " </memory>"
- " <memory type=\"flash\" start=\"0x08010000\" length=\"0x10000\">" // Sector 4
- " <property name=\"blocksize\">0x10000</property>" // 64kB
- " </memory>"
- " <memory type=\"flash\" start=\"0x08020000\" length=\"0xE0000\">" // Sectors 5..11
- " <property name=\"blocksize\">0x20000</property>" // 128kB
- " </memory>"
- " <memory type=\"ram\" start=\"0x40000000\" length=\"0x1fffffff\"/>" // peripheral regs
- " <memory type=\"ram\" start=\"0xe0000000\" length=\"0x1fffffff\"/>" // cortex regs
- " <memory type=\"rom\" start=\"0x1fff0000\" length=\"0x7800\"/>" // bootrom
- " <memory type=\"rom\" start=\"0x1fffc000\" length=\"0x10\"/>" // option byte area
- "</memory-map>";
-
-static const char* const memory_map_template_F2 =
- "<?xml version=\"1.0\"?>"
- "<!DOCTYPE memory-map PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\""
- " \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"
- "<memory-map>"
- " <memory type=\"rom\" start=\"0x00000000\" length=\"0x%x\"/>" // code = sram, bootrom or flash; flash is bigger
- " <memory type=\"ram\" start=\"0x20000000\" length=\"0x%x\"/>" // sram
- " <memory type=\"flash\" start=\"0x08000000\" length=\"0x10000\">" // Sectors 0..3
- " <property name=\"blocksize\">0x4000</property>" // 16kB
- " </memory>"
- " <memory type=\"flash\" start=\"0x08010000\" length=\"0x10000\">" // Sector 4
- " <property name=\"blocksize\">0x10000</property>" // 64kB
- " </memory>"
- " <memory type=\"flash\" start=\"0x08020000\" length=\"0x%x\">" // Sectors 5..
- " <property name=\"blocksize\">0x20000</property>" // 128kB
- " </memory>"
- " <memory type=\"ram\" start=\"0x40000000\" length=\"0x1fffffff\"/>" // peripheral regs
- " <memory type=\"ram\" start=\"0xe0000000\" length=\"0x1fffffff\"/>" // cortex regs
- " <memory type=\"rom\" start=\"0x%08x\" length=\"0x%x\"/>" // bootrom
- " <memory type=\"rom\" start=\"0x1fffc000\" length=\"0x10\"/>" // option byte area
- "</memory-map>";
-
-static const char* const memory_map_template_L4 =
- "<?xml version=\"1.0\"?>"
- "<!DOCTYPE memory-map PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\""
- " \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"
- "<memory-map>"
- " <memory type=\"rom\" start=\"0x00000000\" length=\"0x%x\"/>" // code = sram, bootrom or flash; flash is bigger
- " <memory type=\"ram\" start=\"0x10000000\" length=\"0x8000\"/>" // SRAM2 (32kB)
- " <memory type=\"ram\" start=\"0x20000000\" length=\"0x18000\"/>" // SRAM1 (96kB)
- " <memory type=\"flash\" start=\"0x08000000\" length=\"0x%x\">"
- " <property name=\"blocksize\">0x800</property>"
- " </memory>"
- " <memory type=\"ram\" start=\"0x40000000\" length=\"0x1fffffff\"/>" // peripheral regs
- " <memory type=\"ram\" start=\"0x60000000\" length=\"0x7fffffff\"/>" // AHB3 Peripherals
- " <memory type=\"ram\" start=\"0xe0000000\" length=\"0x1fffffff\"/>" // cortex regs
- " <memory type=\"rom\" start=\"0x1fff0000\" length=\"0x7000\"/>" // bootrom
- " <memory type=\"rom\" start=\"0x1fff7800\" length=\"0x10\"/>" // option byte area
- " <memory type=\"rom\" start=\"0x1ffff800\" length=\"0x10\"/>" // option byte area
- "</memory-map>";
-
-static const char* const memory_map_template_L496 =
- "<?xml version=\"1.0\"?>"
- "<!DOCTYPE memory-map PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\""
- " \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"
- "<memory-map>"
- " <memory type=\"rom\" start=\"0x00000000\" length=\"0x%x\"/>" // code = sram, bootrom or flash; flash is bigger
- " <memory type=\"ram\" start=\"0x10000000\" length=\"0x10000\"/>" // SRAM2 (64kB)
- " <memory type=\"ram\" start=\"0x20000000\" length=\"0x50000\"/>" // SRAM1 + aliased SRAM2 (256 + 64 = 320kB)
- " <memory type=\"flash\" start=\"0x08000000\" length=\"0x%x\">"
- " <property name=\"blocksize\">0x800</property>"
- " </memory>"
- " <memory type=\"ram\" start=\"0x40000000\" length=\"0x1fffffff\"/>" // peripheral regs
- " <memory type=\"ram\" start=\"0x60000000\" length=\"0x7fffffff\"/>" // AHB3 Peripherals
- " <memory type=\"ram\" start=\"0xe0000000\" length=\"0x1fffffff\"/>" // cortex regs
- " <memory type=\"rom\" start=\"0x1fff0000\" length=\"0x7000\"/>" // bootrom
- " <memory type=\"rom\" start=\"0x1fff7800\" length=\"0x10\"/>" // option byte area
- " <memory type=\"rom\" start=\"0x1ffff800\" length=\"0x10\"/>" // option byte area
- "</memory-map>";
-
-static const char* const memory_map_template =
- "<?xml version=\"1.0\"?>"
- "<!DOCTYPE memory-map PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\""
- " \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"
- "<memory-map>"
- " <memory type=\"rom\" start=\"0x00000000\" length=\"0x%x\"/>" // code = sram, bootrom or flash; flash is bigger
- " <memory type=\"ram\" start=\"0x20000000\" length=\"0x%x\"/>" // sram 8kB
- " <memory type=\"flash\" start=\"0x08000000\" length=\"0x%x\">"
- " <property name=\"blocksize\">0x%x</property>"
- " </memory>"
- " <memory type=\"ram\" start=\"0x40000000\" length=\"0x1fffffff\"/>" // peripheral regs
- " <memory type=\"ram\" start=\"0xe0000000\" length=\"0x1fffffff\"/>" // cortex regs
- " <memory type=\"rom\" start=\"0x%08x\" length=\"0x%x\"/>" // bootrom
- " <memory type=\"rom\" start=\"0x1ffff800\" length=\"0x10\"/>" // option byte area
- "</memory-map>";
-
-static const char* const memory_map_template_F7 =
- "<?xml version=\"1.0\"?>"
- "<!DOCTYPE memory-map PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\""
- " \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"
- "<memory-map>"
- " <memory type=\"ram\" start=\"0x00000000\" length=\"0x4000\"/>" // ITCM ram 16kB
- " <memory type=\"rom\" start=\"0x00200000\" length=\"0x100000\"/>" // ITCM flash
- " <memory type=\"ram\" start=\"0x20000000\" length=\"0x%x\"/>" // sram
- " <memory type=\"flash\" start=\"0x08000000\" length=\"0x20000\">" // Sectors 0..3
- " <property name=\"blocksize\">0x8000</property>" // 32kB
- " </memory>"
- " <memory type=\"flash\" start=\"0x08020000\" length=\"0x20000\">" // Sector 4
- " <property name=\"blocksize\">0x20000</property>" // 128kB
- " </memory>"
- " <memory type=\"flash\" start=\"0x08040000\" length=\"0xC0000\">" // Sectors 5..7
- " <property name=\"blocksize\">0x40000</property>" // 128kB
- " </memory>"
- " <memory type=\"ram\" start=\"0x40000000\" length=\"0x1fffffff\"/>" // peripheral regs
- " <memory type=\"ram\" start=\"0x60000000\" length=\"0x7fffffff\"/>" // AHB3 Peripherals
- " <memory type=\"ram\" start=\"0xe0000000\" length=\"0x1fffffff\"/>" // cortex regs
- " <memory type=\"rom\" start=\"0x00100000\" length=\"0xEDC0\"/>" // bootrom
- " <memory type=\"rom\" start=\"0x1fff0000\" length=\"0x20\"/>" // option byte area
- "</memory-map>";
-
-static const char* const memory_map_template_H7 =
- "<?xml version=\"1.0\"?>"
- "<!DOCTYPE memory-map PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\""
- " \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"
- "<memory-map>"
- " <memory type=\"rom\" start=\"0x00000000\" length=\"0x10000\"/>" // ITCMRAM 64kB
- " <memory type=\"ram\" start=\"0x20000000\" length=\"0x20000\"/>" // DTCMRAM 128kB
- " <memory type=\"ram\" start=\"0x24000000\" length=\"0x80000\"/>" // RAM D1 512kB
- " <memory type=\"ram\" start=\"0x30000000\" length=\"0x48000\"/>" // RAM D2 288kB
- " <memory type=\"ram\" start=\"0x38000000\" length=\"0x10000\"/>" // RAM D3 64kB
- " <memory type=\"flash\" start=\"0x08000000\" length=\"0x%x\">"
- " <property name=\"blocksize\">0x%x</property>"
- " </memory>"
- " <memory type=\"ram\" start=\"0x40000000\" length=\"0x1fffffff\"/>" // peripheral regs
- " <memory type=\"ram\" start=\"0xe0000000\" length=\"0x1fffffff\"/>" // cortex regs
- " <memory type=\"rom\" start=\"0x1ff00000\" length=\"0x20000\"/>" // bootrom
- "</memory-map>";
-
-
-static const char* const memory_map_template_F4_DE =
- "<?xml version=\"1.0\"?>"
- "<!DOCTYPE memory-map PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\""
- " \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"
- "<memory-map>"
- " <memory type=\"rom\" start=\"0x00000000\" length=\"0x80000\"/>" // code = sram, bootrom or flash; flash is bigger
- " <memory type=\"ram\" start=\"0x20000000\" length=\"0x18000\"/>" // sram
- " <memory type=\"flash\" start=\"0x08000000\" length=\"0x10000\">" // Sectors 0..3
- " <property name=\"blocksize\">0x4000</property>" // 16kB
- " </memory>"
- " <memory type=\"flash\" start=\"0x08010000\" length=\"0x10000\">" // Sector 4
- " <property name=\"blocksize\">0x10000</property>" // 64kB
- " </memory>"
- " <memory type=\"flash\" start=\"0x08020000\" length=\"0x60000\">" // Sectors 5..7
- " <property name=\"blocksize\">0x20000</property>" // 128kB
- " </memory>"
- " <memory type=\"ram\" start=\"0x40000000\" length=\"0x1fffffff\"/>" // peripheral regs
- " <memory type=\"ram\" start=\"0xe0000000\" length=\"0x1fffffff\"/>" // cortex regs
- " <memory type=\"rom\" start=\"0x1fff0000\" length=\"0x7800\"/>" // bootrom
- " <memory type=\"rom\" start=\"0x1fff7800\" length=\"0x210\"/>" // otp
- " <memory type=\"rom\" start=\"0x1fffc000\" length=\"0x10\"/>" // option byte area
- "</memory-map>";
-
char* make_memory_map(stlink_t *sl) {
// this will be freed in serve()
- const size_t sz = 4096;
+ const uint32_t sz = 4096;
char* map = malloc(sz);
map[0] = '\0';
- if (sl->chip_id == STLINK_CHIPID_STM32_F4 ||
- sl->chip_id == STLINK_CHIPID_STM32_F446 ||
- sl->chip_id == STLINK_CHIPID_STM32_F411RE) {
+ if (sl->chip_id == STM32_CHIPID_F4 ||
+ sl->chip_id == STM32_CHIPID_F446 ||
+ sl->chip_id == STM32_CHIPID_F411xx) {
strcpy(map, memory_map_template_F4);
- } else if (sl->chip_id == STLINK_CHIPID_STM32_F4_DE) {
+ } else if (sl->chip_id == STM32_CHIPID_F4_DE) {
strcpy(map, memory_map_template_F4_DE);
- } else if (sl->core_id == STM32F7_CORE_ID) {
+ } else if (sl->core_id == STM32_CORE_ID_M7F_SWD) {
snprintf(map, sz, memory_map_template_F7,
- (unsigned int)sl->sram_size);
- } else if (sl->chip_id == STLINK_CHIPID_STM32_H74XXX) {
+ sl->sram_size);
+ } else if (sl->chip_id == STM32_CHIPID_H74xxx) {
snprintf(map, sz, memory_map_template_H7,
- (unsigned int)sl->flash_size,
- (unsigned int)sl->flash_pgsz);
- } else if (sl->chip_id == STLINK_CHIPID_STM32_F4_HD) {
+ sl->flash_size,
+ sl->flash_pgsz);
+ } else if (sl->chip_id == STM32_CHIPID_F4_HD) {
strcpy(map, memory_map_template_F4_HD);
- } else if (sl->chip_id == STLINK_CHIPID_STM32_F2) {
+ } else if (sl->chip_id == STM32_CHIPID_F2) {
snprintf(map, sz, memory_map_template_F2,
- (unsigned int)sl->flash_size,
- (unsigned int)sl->sram_size,
- (unsigned int)sl->flash_size - 0x20000,
- (unsigned int)sl->sys_base,
- (unsigned int)sl->sys_size);
- } else if ((sl->chip_id == STLINK_CHIPID_STM32_L4) ||
- (sl->chip_id == STLINK_CHIPID_STM32_L43X) ||
- (sl->chip_id == STLINK_CHIPID_STM32_L46X)) {
+ sl->flash_size,
+ sl->sram_size,
+ sl->flash_size - 0x20000,
+ sl->sys_base,
+ sl->sys_size);
+ } else if ((sl->chip_id == STM32_CHIPID_L4) ||
+ (sl->chip_id == STM32_CHIPID_L43x_L44x) ||
+ (sl->chip_id == STM32_CHIPID_L45x_L46x)) {
snprintf(map, sz, memory_map_template_L4,
- (unsigned int)sl->flash_size,
- (unsigned int)sl->flash_size);
- } else if (sl->chip_id == STLINK_CHIPID_STM32_L496X) {
+ sl->flash_size,
+ sl->flash_size);
+ } else if (sl->chip_id == STM32_CHIPID_L496x_L4A6x) {
snprintf(map, sz, memory_map_template_L496,
- (unsigned int)sl->flash_size,
- (unsigned int)sl->flash_size);
- } else {
+ sl->flash_size,
+ sl->flash_size);
+ } else if (sl->chip_id == STM32_CHIPID_H72x) {
+ snprintf(map, sz, memory_map_template_H72x3x,
+ sl->flash_size,
+ sl->flash_pgsz);
+ } else {
snprintf(map, sz, memory_map_template,
- (unsigned int)sl->flash_size,
- (unsigned int)sl->sram_size,
- (unsigned int)sl->flash_size,
- (unsigned int)sl->flash_pgsz,
- (unsigned int)sl->sys_base,
- (unsigned int)sl->sys_size);
+ sl->flash_size,
+ sl->sram_size,
+ sl->flash_size,
+ sl->flash_pgsz,
+ sl->sys_base,
+ sl->sys_size);
}
- return(map);
+ return (map);
}
#define DATA_WATCH_NUM 4
@@ -598,14 +422,14 @@ static void init_data_watchpoints(stlink_t *sl) {
stlink_write_debug32(sl, STLINK_REG_CM3_DEMCR, data);
// make sure all watchpoints are cleared
- for (int i = 0; i < DATA_WATCH_NUM; i++) {
+ for (int32_t i = 0; i < DATA_WATCH_NUM; i++) {
data_watches[i].fun = WATCHDISABLED;
stlink_write_debug32(sl, STLINK_REG_CM3_DWT_FUNn(i), 0);
}
}
-static int add_data_watchpoint(stlink_t *sl, enum watchfun wf, stm32_addr_t addr, unsigned int len) {
- int i = 0;
+static int32_t add_data_watchpoint(stlink_t *sl, enum watchfun wf, stm32_addr_t addr, uint32_t len) {
+ int32_t i = 0;
uint32_t mask, dummy;
// computer mask
@@ -641,16 +465,16 @@ static int add_data_watchpoint(stlink_t *sl, enum watchfun wf, stm32_addr_t addr
// just to make sure the matched bit is clear !
stlink_read_debug32(sl, STLINK_REG_CM3_DWT_FUNn(i), &dummy);
- return(0);
+ return (0);
}
}
DLOG("failure: add watchpoints addr %x wf %u len %u\n", addr, wf, len);
- return(-1);
+ return (-1);
}
-static int delete_data_watchpoint(stlink_t *sl, stm32_addr_t addr) {
- int i;
+static int32_t delete_data_watchpoint(stlink_t *sl, stm32_addr_t addr) {
+ int32_t i;
for (i = 0; i < DATA_WATCH_NUM; i++) {
if ((data_watches[i].addr == addr) && (data_watches[i].fun != WATCHDISABLED)) {
@@ -659,18 +483,18 @@ static int delete_data_watchpoint(stlink_t *sl, stm32_addr_t addr) {
data_watches[i].fun = WATCHDISABLED;
stlink_write_debug32(sl, STLINK_REG_CM3_DWT_FUNn(i), 0);
- return(0);
+ return (0);
}
}
DLOG("failure: delete watchpoint addr %x\n", addr);
- return(-1);
+ return (-1);
}
-static int code_break_num;
-static int code_lit_num;
-static int code_break_rev;
+static int32_t code_break_num;
+static int32_t code_lit_num;
+static int32_t code_break_rev;
#define CODE_BREAK_NUM_MAX 15
#define CODE_BREAK_LOW 0x01
#define CODE_BREAK_HIGH 0x02
@@ -680,13 +504,13 @@ static int code_break_rev;
struct code_hw_breakpoint {
stm32_addr_t addr;
- int type;
+ int32_t type;
};
static struct code_hw_breakpoint code_breaks[CODE_BREAK_NUM_MAX];
static void init_code_breakpoints(stlink_t *sl) {
- unsigned int val;
+ uint32_t val;
memset(sl->q_buf, 0, 4);
stlink_write_debug32(sl, STLINK_REG_CM3_FP_CTRL, 0x03 /* KEY | ENABLE */);
stlink_read_debug32(sl, STLINK_REG_CM3_FP_CTRL, &val);
@@ -702,28 +526,28 @@ static void init_code_breakpoints(stlink_t *sl) {
// IHI0029D, p. 48, Lock Access Register
stlink_write_debug32(sl, STLINK_REG_CM7_FP_LAR, STLINK_REG_CM7_FP_LAR_KEY);
}
-
- for (int i = 0; i < code_break_num; i++) {
+
+ for (int32_t i = 0; i < code_break_num; i++) {
code_breaks[i].type = 0;
stlink_write_debug32(sl, STLINK_REG_CM3_FP_COMPn(i), 0);
}
}
-static int has_breakpoint(stm32_addr_t addr) {
- for (int i = 0; i < code_break_num; i++)
- if (code_breaks[i].addr == addr) { return(1); }
+static int32_t has_breakpoint(stm32_addr_t addr) {
+ for (int32_t i = 0; i < code_break_num; i++)
+ if (code_breaks[i].addr == addr) { return (1); }
- return(0);
+ return (0);
}
-static int update_code_breakpoint(stlink_t *sl, stm32_addr_t addr, int set) {
+static int32_t update_code_breakpoint(stlink_t *sl, stm32_addr_t addr, int32_t set) {
uint32_t mask;
- int type;
+ int32_t type;
stm32_addr_t fpb_addr;
if (addr & 1) {
ELOG("update_code_breakpoint: unaligned address %08x\n", addr);
- return(-1);
+ return (-1);
}
if (code_break_rev == CODE_BREAK_REV_V1) {
@@ -733,9 +557,9 @@ static int update_code_breakpoint(stlink_t *sl, stm32_addr_t addr, int set) {
type = CODE_BREAK_REMAP;
fpb_addr = addr;
}
-
- int id = -1;
- for (int i = 0; i < code_break_num; i++)
+
+ int32_t id = -1;
+ for (int32_t i = 0; i < code_break_num; i++)
if (fpb_addr == code_breaks[i].addr || (set && code_breaks[i].type == 0)) {
id = i;
break;
@@ -743,9 +567,9 @@ static int update_code_breakpoint(stlink_t *sl, stm32_addr_t addr, int set) {
if (id == -1) {
if (set)
- return(-1); // free slot not found
+ return (-1); // free slot not found
else
- return(0); // breakpoint is already removed
+ return (0); // breakpoint is already removed
}
struct code_hw_breakpoint* bp = &code_breaks[id];
@@ -754,7 +578,7 @@ static int update_code_breakpoint(stlink_t *sl, stm32_addr_t addr, int set) {
bp->type |= type;
else
bp->type &= ~type;
-
+
// DDI0403E, p. 759, FP_COMPn register description
mask = ((bp->type&0x03) << 30) | bp->addr | 1;
@@ -767,13 +591,13 @@ static int update_code_breakpoint(stlink_t *sl, stm32_addr_t addr, int set) {
stlink_write_debug32(sl, STLINK_REG_CM3_FP_COMPn(id), mask);
}
- return(0);
+ return (0);
}
struct flash_block {
stm32_addr_t addr;
- unsigned length;
+ uint32_t length;
uint8_t* data;
struct flash_block* next;
@@ -781,18 +605,18 @@ struct flash_block {
static struct flash_block* flash_root;
-static int flash_add_block(stm32_addr_t addr, unsigned length, stlink_t *sl) {
+static int32_t flash_add_block(stm32_addr_t addr, uint32_t length, stlink_t *sl) {
if (addr < FLASH_BASE || addr + length > FLASH_BASE + sl->flash_size) {
ELOG("flash_add_block: incorrect bounds\n");
- return(-1);
+ return (-1);
}
stlink_calculate_pagesize(sl, addr);
if (addr % FLASH_PAGE != 0 || length % FLASH_PAGE != 0) {
ELOG("flash_add_block: unaligned block\n");
- return(-1);
+ return (-1);
}
struct flash_block* new = malloc(sizeof(struct flash_block));
@@ -803,11 +627,11 @@ static int flash_add_block(stm32_addr_t addr, unsigned length, stlink_t *sl) {
memset(new->data, stlink_get_erased_pattern(sl), length);
flash_root = new;
- return(0);
+ return (0);
}
-static int flash_populate(stm32_addr_t addr, uint8_t* data, unsigned length) {
- unsigned int fit_blocks = 0, fit_length = 0;
+static int32_t flash_populate(stm32_addr_t addr, uint8_t* data, uint32_t length) {
+ uint32_t fit_blocks = 0, fit_length = 0;
for (struct flash_block* fb = flash_root; fb; fb = fb->next) {
/*
@@ -819,13 +643,13 @@ static int flash_populate(stm32_addr_t addr, uint8_t* data, unsigned length) {
* a < Y && b > x
*/
- unsigned X = fb->addr, Y = fb->addr + fb->length;
- unsigned a = addr, b = addr + length;
+ uint32_t X = fb->addr, Y = fb->addr + fb->length;
+ uint32_t a = addr, b = addr + length;
if (a < Y && b > X) {
// from start of the block
- unsigned start = (a > X ? a : X) - X;
- unsigned end = (b > Y ? Y : b) - X;
+ uint32_t start = (a > X ? a : X) - X;
+ uint32_t end = (b > Y ? Y : b) - X;
memcpy(fb->data + start, data, end - start);
@@ -836,7 +660,7 @@ static int flash_populate(stm32_addr_t addr, uint8_t* data, unsigned length) {
if (fit_blocks == 0) {
ELOG("Unfit data block %08x -> %04x\n", addr, length);
- return(-1);
+ return (-1);
}
if (fit_length != length) {
@@ -844,12 +668,12 @@ static int flash_populate(stm32_addr_t addr, uint8_t* data, unsigned length) {
WLOG("(this is not an error, just a GDB glitch)\n");
}
- return(0);
+ return (0);
}
-static int flash_go(stlink_t *sl, st_state_t *st) {
- int error = -1;
- int ret;
+static int32_t flash_go(stlink_t *sl, st_state_t *st) {
+ int32_t error = -1;
+ int32_t ret;
flash_loader_t fl;
stlink_target_connect(sl, st->connect_mode);
@@ -875,13 +699,13 @@ static int flash_go(stlink_t *sl, st_state_t *st) {
ILOG("flash_do: block %08x -> %04x\n", fb->addr, fb->length);
for (stm32_addr_t page = fb->addr; page < fb->addr + fb->length; page += (uint32_t)FLASH_PAGE) {
- unsigned length = fb->length - (page - fb->addr);
+ uint32_t length = fb->length - (page - fb->addr);
// update FLASH_PAGE
stlink_calculate_pagesize(sl, page);
ILOG("flash_do: page %08x\n", page);
- unsigned len = (length > FLASH_PAGE) ? (unsigned int)FLASH_PAGE : length;
+ uint32_t len = (length > FLASH_PAGE) ? (uint32_t)FLASH_PAGE : length;
ret = stlink_flashloader_write(sl, &fl, page, fb->data + (page - fb->addr), len);
if (ret) { goto error; }
}
@@ -900,25 +724,25 @@ error:
}
flash_root = NULL;
- return(error);
+ return (error);
}
struct cache_level_desc {
- unsigned int nsets;
- unsigned int nways;
- unsigned int log2_nways;
- unsigned int width;
+ uint32_t nsets;
+ uint32_t nways;
+ uint32_t log2_nways;
+ uint32_t width;
};
struct cache_desc_t {
- unsigned used;
-
+ uint32_t used;
+
// minimal line size in bytes
- unsigned int dminline;
- unsigned int iminline;
+ uint32_t dminline;
+ uint32_t iminline;
// last level of unification (uniprocessor)
- unsigned int louu;
+ uint32_t louu;
struct cache_level_desc icache[7];
struct cache_level_desc dcache[7];
@@ -927,17 +751,17 @@ struct cache_desc_t {
static struct cache_desc_t cache_desc;
// return the smallest R so that V <= (1 << R); not performance critical
-static unsigned ceil_log2(unsigned v) {
- unsigned res;
+static uint32_t ceil_log2(uint32_t v) {
+ uint32_t res;
for (res = 0; (1U << res) < v; res++);
- return(res);
+ return (res);
}
static void read_cache_level_desc(stlink_t *sl, struct cache_level_desc *desc) {
- unsigned int ccsidr;
- unsigned int log2_nsets;
+ uint32_t ccsidr;
+ uint32_t log2_nsets;
stlink_read_debug32(sl, STLINK_REG_CM7_CCSIDR, &ccsidr);
desc->nsets = ((ccsidr >> 13) & 0x3fff) + 1;
@@ -950,10 +774,10 @@ static void read_cache_level_desc(stlink_t *sl, struct cache_level_desc *desc) {
}
static void init_cache (stlink_t *sl) {
- unsigned int clidr;
- unsigned int ccr;
- unsigned int ctr;
- int i;
+ uint32_t clidr;
+ uint32_t ccr;
+ uint32_t ctr;
+ int32_t i;
// Check have cache
stlink_read_debug32(sl, STLINK_REG_CM7_CTR, &ctr);
@@ -964,7 +788,7 @@ static void init_cache (stlink_t *sl) {
cache_desc.used = 1;
cache_desc.dminline = 4 << ((ctr >> 16) & 0x0f);
cache_desc.iminline = 4 << (ctr & 0x0f);
-
+
stlink_read_debug32(sl, STLINK_REG_CM7_CLIDR, &clidr);
cache_desc.louu = (clidr >> 27) & 7;
@@ -977,7 +801,7 @@ static void init_cache (stlink_t *sl) {
cache_desc.dminline, cache_desc.iminline);
for (i = 0; i < 7; i++) {
- unsigned int ct = (clidr >> (3 * i)) & 0x07;
+ uint32_t ct = (clidr >> (3 * i)) & 0x07;
cache_desc.dcache[i].width = 0;
cache_desc.icache[i].width = 0;
@@ -995,19 +819,19 @@ static void init_cache (stlink_t *sl) {
}
}
-static void cache_flush(stlink_t *sl, unsigned ccr) {
- int level;
+static void cache_flush(stlink_t *sl, uint32_t ccr) {
+ int32_t level;
if (ccr & STLINK_REG_CM7_CCR_DC) {
for (level = cache_desc.louu - 1; level >= 0; level--) {
struct cache_level_desc *desc = &cache_desc.dcache[level];
- unsigned addr;
- unsigned max_addr = 1 << desc->width;
- unsigned way_sh = 32 - desc->log2_nways;
+ uint32_t addr;
+ uint32_t max_addr = 1 << desc->width;
+ uint32_t way_sh = 32 - desc->log2_nways;
// D-cache clean by set-ways.
for (addr = (level << 1); addr < max_addr; addr += cache_desc.dminline) {
- unsigned int way;
+ uint32_t way;
for (way = 0; way < desc->nways; way++) {
stlink_write_debug32(sl, STLINK_REG_CM7_DCCSW, addr | (way << way_sh));
@@ -1022,9 +846,9 @@ static void cache_flush(stlink_t *sl, unsigned ccr) {
}
}
-static int cache_modified;
+static int32_t cache_modified;
-static void cache_change(stm32_addr_t start, unsigned count) {
+static void cache_change(stm32_addr_t start, uint32_t count) {
if (count == 0) { return; }
(void)start;
@@ -1032,7 +856,7 @@ static void cache_change(stm32_addr_t start, unsigned count) {
}
static void cache_sync(stlink_t *sl) {
- unsigned ccr;
+ uint32_t ccr;
if (!cache_desc.used) { return; }
@@ -1043,28 +867,28 @@ static void cache_sync(stlink_t *sl) {
if (ccr & (STLINK_REG_CM7_CCR_IC | STLINK_REG_CM7_CCR_DC)) { cache_flush(sl, ccr); }
}
-static size_t unhexify(const char *in, char *out, size_t out_count) {
- size_t i;
- unsigned int c;
+static uint32_t unhexify(const char *in, char *out, uint32_t out_count) {
+ uint32_t i;
+ uint32_t c;
for (i = 0; i < out_count; i++) {
- if (sscanf(in + (2 * i), "%02x", &c) != 1) { return(i); }
+ if (sscanf(in + (2 * i), "%02x", &c) != 1) { return (i); }
out[i] = (char)c;
}
- return(i);
+ return (i);
}
-int serve(stlink_t *sl, st_state_t *st) {
+int32_t serve(stlink_t *sl, st_state_t *st) {
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
if (!IS_SOCK_VALID(sock)) {
perror("socket");
- return(1);
+ return (1);
}
- unsigned int val = 1;
+ uint32_t val = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
struct sockaddr_in serv_addr;
@@ -1076,13 +900,13 @@ int serve(stlink_t *sl, st_state_t *st) {
if (bind(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
perror("bind");
close_socket(sock);
- return(1);
+ return (1);
}
if (listen(sock, 5) < 0) {
perror("listen");
close_socket(sock);
- return(1);
+ return (1);
}
ILOG("Listening at *:%d...\n", st->listen_port);
@@ -1093,7 +917,7 @@ int serve(stlink_t *sl, st_state_t *st) {
if (!IS_SOCK_VALID(client)) {
perror("accept");
close_socket(sock);
- return(1);
+ return (1);
}
close_socket(sock);
@@ -1120,21 +944,21 @@ int serve(stlink_t *sl, st_state_t *st) {
* To allow resetting the chip from GDB it is required to emulate attaching
* and detaching to target.
*/
- unsigned int attached = 1;
+ uint32_t attached = 1;
// if a critical error is detected, break from the loop
- int critical_error = 0;
- int ret;
+ int32_t critical_error = 0;
+ int32_t ret;
while (1) {
ret = 0;
char* packet;
- int status = gdb_recv_packet(client, &packet);
+ int32_t status = gdb_recv_packet(client, &packet);
if (status < 0) {
ELOG("cannot recv: %d\n", status);
close_socket(client);
- return(1);
+ return (1);
}
DLOG("recv: %s\n", packet);
@@ -1157,7 +981,7 @@ int serve(stlink_t *sl, st_state_t *st) {
params = separator + 1;
}
- unsigned queryNameLength = (unsigned int)(separator - &packet[1]);
+ uint32_t queryNameLength = (uint32_t)(separator - &packet[1]);
char* queryName = calloc(queryNameLength + 1, 1);
strncpy(queryName, &packet[1], queryNameLength);
@@ -1176,8 +1000,8 @@ int serve(stlink_t *sl, st_state_t *st) {
__s_addr = strsep(&tok, ",");
s_length = tok;
- unsigned addr = (unsigned int)strtoul(__s_addr, NULL, 16),
- length = (unsigned int)strtoul(s_length, NULL, 16);
+ uint32_t addr = (uint32_t)strtoul(__s_addr, NULL, 16),
+ length = (uint32_t)strtoul(s_length, NULL, 16);
DLOG("Xfer: type:%s;op:%s;annex:%s;addr:%d;length:%d\n",
type, op, annex, addr, length);
@@ -1194,7 +1018,7 @@ int serve(stlink_t *sl, st_state_t *st) {
}
if (data) {
- unsigned data_length = (unsigned int)strlen(data);
+ uint32_t data_length = (uint32_t)strlen(data);
if (addr + length > data_length) { length = data_length - addr; }
@@ -1217,9 +1041,9 @@ int serve(stlink_t *sl, st_state_t *st) {
params = separator + 1;
}
- size_t hex_len = strlen(params);
- size_t alloc_size = (hex_len / 2) + 1;
- size_t cmd_len;
+ uint32_t hex_len = strlen(params);
+ uint32_t alloc_size = (hex_len / 2) + 1;
+ uint32_t cmd_len;
char *cmd = malloc(alloc_size);
if (cmd == NULL) {
@@ -1282,7 +1106,7 @@ int serve(stlink_t *sl, st_state_t *st) {
reply = strdup("E00");
}
- ret = stlink_reset(sl, RESET_AUTO);
+ ret = stlink_reset(sl, RESET_SOFT_AND_HALT);
if (ret) {
DLOG("Rcmd: reset failed with reset\n");
reply = strdup("E00");
@@ -1337,8 +1161,8 @@ int serve(stlink_t *sl, st_state_t *st) {
__s_addr = strsep(&tok, ",");
s_length = tok;
- unsigned addr = (unsigned int)strtoul(__s_addr, NULL, 16),
- length = (unsigned int)strtoul(s_length, NULL, 16);
+ uint32_t addr = (uint32_t)strtoul(__s_addr, NULL, 16),
+ length = (uint32_t)strtoul(s_length, NULL, 16);
DLOG("FlashErase: addr:%08x,len:%04x\n",
addr, length);
@@ -1355,15 +1179,15 @@ int serve(stlink_t *sl, st_state_t *st) {
__s_addr = strsep(&tok, ":");
data = tok;
- unsigned addr = (unsigned int)strtoul(__s_addr, NULL, 16);
- unsigned data_length = status - (unsigned int)(data - packet);
+ uint32_t addr = (uint32_t)strtoul(__s_addr, NULL, 16);
+ uint32_t data_length = status - (uint32_t)(data - packet);
// Length of decoded data cannot be more than encoded, as escapes are removed.
// Additional byte is reserved for alignment fix.
uint8_t *decoded = calloc(data_length + 1, 1);
- unsigned dec_index = 0;
+ uint32_t dec_index = 0;
- for (unsigned int i = 0; i < data_length; i++) {
+ for (uint32_t i = 0; i < data_length; i++) {
if (data[i] == 0x7d) {
i++;
decoded[dec_index++] = data[i] ^ 0x20;
@@ -1412,7 +1236,7 @@ int serve(stlink_t *sl, st_state_t *st) {
if (status < 0) {
ELOG("cannot check for int: %d\n", status);
close_socket(client);
- return(1);
+ return (1);
}
if (status == 1) {
@@ -1428,7 +1252,7 @@ int serve(stlink_t *sl, st_state_t *st) {
struct stlink_reg reg;
stm32_addr_t pc;
stm32_addr_t addr;
- int offset = 0;
+ int32_t offset = 0;
uint16_t insn;
if (!st->semihosting) { break; }
@@ -1518,15 +1342,15 @@ int serve(stlink_t *sl, st_state_t *st) {
reply = calloc(8 * 16 + 1, 1);
- for (int i = 0; i < 16; i++) {
+ for (int32_t i = 0; i < 16; i++) {
sprintf(&reply[i * 8], "%08x", (uint32_t)htonl(regp.r[i]));
}
break;
case 'p': {
- unsigned id = (unsigned int)strtoul(&packet[1], NULL, 16);
- unsigned myreg = 0xDEADDEAD;
+ uint32_t id = (uint32_t)strtoul(&packet[1], NULL, 16);
+ uint32_t myreg = 0xDEADDEAD;
if (id < 16) {
ret = stlink_read_reg(sl, id, &regp);
@@ -1578,8 +1402,8 @@ int serve(stlink_t *sl, st_state_t *st) {
char* s_reg = &packet[1];
char* s_value = strstr(&packet[1], "=") + 1;
- unsigned reg = (unsigned int)strtoul(s_reg, NULL, 16);
- unsigned value = (unsigned int)strtoul(s_value, NULL, 16);
+ uint32_t reg = (uint32_t)strtoul(s_reg, NULL, 16);
+ uint32_t value = (uint32_t)strtoul(s_value, NULL, 16);
if (reg < 16) {
@@ -1616,7 +1440,7 @@ int serve(stlink_t *sl, st_state_t *st) {
case 'G':
- for (int i = 0; i < 16; i++) {
+ for (int32_t i = 0; i < 16; i++) {
char str[9] = {0};
strncpy(str, &packet[1 + i * 8], 8);
uint32_t reg = (uint32_t)strtoul(str, NULL, 16);
@@ -1633,12 +1457,12 @@ int serve(stlink_t *sl, st_state_t *st) {
char* s_count = strstr(&packet[1], ",") + 1;
stm32_addr_t start = (stm32_addr_t)strtoul(s_start, NULL, 16);
- unsigned count = (unsigned int)strtoul(s_count, NULL, 16);
+ uint32_t count = (uint32_t)strtoul(s_count, NULL, 16);
- unsigned adj_start = start % 4;
- unsigned count_rnd = (count + adj_start + 4 - 1) / 4 * 4;
+ uint32_t adj_start = start % 4;
+ uint32_t count_rnd = (count + adj_start + 4 - 1) / 4 * 4;
- if (count_rnd > sl->flash_pgsz) { count_rnd = (unsigned int)sl->flash_pgsz; }
+ if (count_rnd > sl->flash_pgsz) { count_rnd = sl->flash_pgsz; }
if (count_rnd > 0x1800) { count_rnd = 0x1800; }
@@ -1650,7 +1474,7 @@ int serve(stlink_t *sl, st_state_t *st) {
reply = calloc(count * 2 + 1, 1);
- for (unsigned int i = 0; i < count; i++) {
+ for (uint32_t i = 0; i < count; i++) {
reply[i * 2 + 0] = hex[sl->q_buf[i + adj_start] >> 4];
reply[i * 2 + 1] = hex[sl->q_buf[i + adj_start] & 0xf];
}
@@ -1664,17 +1488,17 @@ int serve(stlink_t *sl, st_state_t *st) {
char* hexdata = strstr(packet, ":") + 1;
stm32_addr_t start = (stm32_addr_t)strtoul(s_start, NULL, 16);
- unsigned count = (unsigned int)strtoul(s_count, NULL, 16);
- int err = 0;
+ uint32_t count = (uint32_t)strtoul(s_count, NULL, 16);
+ int32_t err = 0;
if (start % 4) {
- unsigned align_count = 4 - start % 4;
+ uint32_t align_count = 4 - start % 4;
if (align_count > count) { align_count = count; }
- for (unsigned int i = 0; i < align_count; i++) {
+ for (uint32_t i = 0; i < align_count; i++) {
char hextmp[3] = { hexdata[i * 2], hexdata[i * 2 + 1], 0 };
- uint8_t byte = strtoul(hextmp, NULL, 16);
+ uint8_t byte = (uint8_t)strtoul(hextmp, NULL, 16);
sl->q_buf[i] = byte;
}
@@ -1686,11 +1510,11 @@ int serve(stlink_t *sl, st_state_t *st) {
}
if (count - count % 4) {
- unsigned aligned_count = count - count % 4;
+ uint32_t aligned_count = count - count % 4;
- for (unsigned int i = 0; i < aligned_count; i++) {
+ for (uint32_t i = 0; i < aligned_count; i++) {
char hextmp[3] = { hexdata[i * 2], hexdata[i * 2 + 1], 0 };
- uint8_t byte = strtoul(hextmp, NULL, 16);
+ uint8_t byte = (uint8_t)strtoul(hextmp, NULL, 16);
sl->q_buf[i] = byte;
}
@@ -1702,9 +1526,9 @@ int serve(stlink_t *sl, st_state_t *st) {
}
if (count) {
- for (unsigned int i = 0; i < count; i++) {
+ for (uint32_t i = 0; i < count; i++) {
char hextmp[3] = { hexdata[i * 2], hexdata[i * 2 + 1], 0 };
- uint8_t byte = strtoul(hextmp, NULL, 16);
+ uint8_t byte = (uint8_t)strtoul(hextmp, NULL, 16);
sl->q_buf[i] = byte;
}
@@ -1799,7 +1623,7 @@ int serve(stlink_t *sl, st_state_t *st) {
case 'R': {
// reset the core.
- ret = stlink_reset(sl, RESET_AUTO);
+ ret = stlink_reset(sl, RESET_SOFT_AND_HALT);
if (ret) { DLOG("R packet : stlink_reset failed\n"); }
init_code_breakpoints(sl);
@@ -1821,7 +1645,7 @@ int serve(stlink_t *sl, st_state_t *st) {
stlink_close(sl);
sl = stlink_open_usb(st->logging_level, st->connect_mode, st->serialnumber, st->freq);
- if (sl == NULL || sl->chip_id == STLINK_CHIPID_UNKNOWN) { cleanup(0); }
+ if (sl == NULL || sl->chip_id == STM32_CHIPID_UNKNOWN) { cleanup(0); }
connected_stlink = sl;
@@ -1842,14 +1666,14 @@ int serve(stlink_t *sl, st_state_t *st) {
if (reply) {
DLOG("send: %s\n", reply);
- int result = gdb_send_packet(client, reply);
+ int32_t result = gdb_send_packet(client, reply);
if (result != 0) {
ELOG("cannot send: %d\n", result);
free(reply);
free(packet);
close_socket(client);
- return(1);
+ return (1);
}
free(reply);
@@ -1857,12 +1681,12 @@ int serve(stlink_t *sl, st_state_t *st) {
if (critical_error) {
close_socket(client);
- return(1);
+ return (1);
}
free(packet);
}
close_socket(client);
- return(0);
+ return (0);
}
diff --git a/src/st-util/gdb-server.h b/src/st-util/gdb-server.h
index b50a794..03c37e4 100644
--- a/src/st-util/gdb-server.h
+++ b/src/st-util/gdb-server.h
@@ -1,5 +1,5 @@
-#ifndef _GDB_SERVER_H
-#define _GDB_SERVER_H
+#ifndef GDB_SERVER_H
+#define GDB_SERVER_H
#define STRINGIFY_inner(name) #name
#define STRINGIFY(name) STRINGIFY_inner(name)
@@ -8,4 +8,4 @@
#define DEBUG_LOGGING_LEVEL 100
#define DEFAULT_GDB_LISTEN_PORT 4242
-#endif // _GDB_SERVER_H
+#endif // GDB_SERVER_H
diff --git a/src/st-util/memory-map.h b/src/st-util/memory-map.h
new file mode 100644
index 0000000..6f34eed
--- /dev/null
+++ b/src/st-util/memory-map.h
@@ -0,0 +1,217 @@
+#ifndef MEMORY_MAP_H
+#define MEMORY_MAP_H
+
+static const char* const memory_map_template_F4 =
+ "<?xml version=\"1.0\"?>"
+ "<!DOCTYPE memory-map PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\""
+ " \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"
+ "<memory-map>"
+ " <memory type=\"rom\" start=\"0x00000000\" length=\"0x100000\"/>" // code = sram, bootrom or flash; flash is bigger
+ " <memory type=\"ram\" start=\"0x10000000\" length=\"0x10000\"/>" // ccm ram
+ " <memory type=\"ram\" start=\"0x20000000\" length=\"0x20000\"/>" // sram
+ " <memory type=\"flash\" start=\"0x08000000\" length=\"0x10000\">" // Sectors 0...3
+ " <property name=\"blocksize\">0x4000</property>" // 16 kB
+ " </memory>"
+ " <memory type=\"flash\" start=\"0x08010000\" length=\"0x10000\">" // Sector 4
+ " <property name=\"blocksize\">0x10000</property>" // 64 kB
+ " </memory>"
+ " <memory type=\"flash\" start=\"0x08020000\" length=\"0xE0000\">" // Sectors 5...11
+ " <property name=\"blocksize\">0x20000</property>" // 128 kB
+ " </memory>"
+ " <memory type=\"ram\" start=\"0x40000000\" length=\"0x1fffffff\"/>" // peripheral regs
+ " <memory type=\"ram\" start=\"0x60000000\" length=\"0x7fffffff\"/>" // AHB3 Peripherals
+ " <memory type=\"ram\" start=\"0xe0000000\" length=\"0x1fffffff\"/>" // cortex regs
+ " <memory type=\"rom\" start=\"0x1fff0000\" length=\"0x7800\"/>" // bootrom
+ " <memory type=\"rom\" start=\"0x1fffc000\" length=\"0x10\"/>" // option byte area
+ "</memory-map>";
+
+static const char* const memory_map_template_F4_HD =
+ "<?xml version=\"1.0\"?>"
+ "<!DOCTYPE memory-map PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\""
+ " \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"
+ "<memory-map>"
+ " <memory type=\"rom\" start=\"0x00000000\" length=\"0x100000\"/>" // code = sram, bootrom or flash; flash is bigger
+ " <memory type=\"ram\" start=\"0x10000000\" length=\"0x10000\"/>" // ccm ram
+ " <memory type=\"ram\" start=\"0x20000000\" length=\"0x40000\"/>" // sram
+ " <memory type=\"ram\" start=\"0x60000000\" length=\"0x10000000\"/>" // fmc bank 1 (nor/psram/sram)
+ " <memory type=\"ram\" start=\"0x70000000\" length=\"0x20000000\"/>" // fmc bank 2 & 3 (nand flash)
+ " <memory type=\"ram\" start=\"0x90000000\" length=\"0x10000000\"/>" // fmc bank 4 (pc card)
+ " <memory type=\"ram\" start=\"0xC0000000\" length=\"0x20000000\"/>" // fmc sdram bank 1 & 2
+ " <memory type=\"flash\" start=\"0x08000000\" length=\"0x10000\">" // Sectors 0...3
+ " <property name=\"blocksize\">0x4000</property>" // 16 kB
+ " </memory>"
+ " <memory type=\"flash\" start=\"0x08010000\" length=\"0x10000\">" // Sector 4
+ " <property name=\"blocksize\">0x10000</property>" // 64 kB
+ " </memory>"
+ " <memory type=\"flash\" start=\"0x08020000\" length=\"0xE0000\">" // Sectors 5...11
+ " <property name=\"blocksize\">0x20000</property>" // 128 kB
+ " </memory>"
+ " <memory type=\"ram\" start=\"0x40000000\" length=\"0x1fffffff\"/>" // peripheral regs
+ " <memory type=\"ram\" start=\"0xe0000000\" length=\"0x1fffffff\"/>" // cortex regs
+ " <memory type=\"rom\" start=\"0x1fff0000\" length=\"0x7800\"/>" // bootrom
+ " <memory type=\"rom\" start=\"0x1fffc000\" length=\"0x10\"/>" // option byte area
+ "</memory-map>";
+
+static const char* const memory_map_template_F2 =
+ "<?xml version=\"1.0\"?>"
+ "<!DOCTYPE memory-map PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\""
+ " \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"
+ "<memory-map>"
+ " <memory type=\"rom\" start=\"0x00000000\" length=\"0x%x\"/>" // code = sram, bootrom or flash; flash is bigger
+ " <memory type=\"ram\" start=\"0x20000000\" length=\"0x%x\"/>" // SRAM
+ " <memory type=\"flash\" start=\"0x08000000\" length=\"0x10000\">" // Sectors 0...3
+ " <property name=\"blocksize\">0x4000</property>" // 16 kB
+ " </memory>"
+ " <memory type=\"flash\" start=\"0x08010000\" length=\"0x10000\">" // Sector 4
+ " <property name=\"blocksize\">0x10000</property>" // 64 kB
+ " </memory>"
+ " <memory type=\"flash\" start=\"0x08020000\" length=\"0x%x\">" // Sectors 5...
+ " <property name=\"blocksize\">0x20000</property>" // 128 kB
+ " </memory>"
+ " <memory type=\"ram\" start=\"0x40000000\" length=\"0x1fffffff\"/>" // peripheral regs
+ " <memory type=\"ram\" start=\"0xe0000000\" length=\"0x1fffffff\"/>" // cortex regs
+ " <memory type=\"rom\" start=\"0x%08x\" length=\"0x%x\"/>" // bootrom
+ " <memory type=\"rom\" start=\"0x1fffc000\" length=\"0x10\"/>" // option byte area
+ "</memory-map>";
+
+static const char* const memory_map_template_L4 =
+ "<?xml version=\"1.0\"?>"
+ "<!DOCTYPE memory-map PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\""
+ " \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"
+ "<memory-map>"
+ " <memory type=\"rom\" start=\"0x00000000\" length=\"0x%x\"/>" // code = sram, bootrom or flash; flash is bigger
+ " <memory type=\"ram\" start=\"0x10000000\" length=\"0x8000\"/>" // SRAM2 (32 kB)
+ " <memory type=\"ram\" start=\"0x20000000\" length=\"0x18000\"/>" // SRAM1 (96 kB)
+ " <memory type=\"flash\" start=\"0x08000000\" length=\"0x%x\">"
+ " <property name=\"blocksize\">0x800</property>"
+ " </memory>"
+ " <memory type=\"ram\" start=\"0x40000000\" length=\"0x1fffffff\"/>" // peripheral regs
+ " <memory type=\"ram\" start=\"0x60000000\" length=\"0x7fffffff\"/>" // AHB3 Peripherals
+ " <memory type=\"ram\" start=\"0xe0000000\" length=\"0x1fffffff\"/>" // cortex regs
+ " <memory type=\"rom\" start=\"0x1fff0000\" length=\"0x7000\"/>" // bootrom
+ " <memory type=\"rom\" start=\"0x1fff7800\" length=\"0x10\"/>" // option byte area
+ " <memory type=\"rom\" start=\"0x1ffff800\" length=\"0x10\"/>" // option byte area
+ "</memory-map>";
+
+static const char* const memory_map_template_L496 =
+ "<?xml version=\"1.0\"?>"
+ "<!DOCTYPE memory-map PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\""
+ " \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"
+ "<memory-map>"
+ " <memory type=\"rom\" start=\"0x00000000\" length=\"0x%x\"/>" // code = sram, bootrom or flash; flash is bigger
+ " <memory type=\"ram\" start=\"0x10000000\" length=\"0x10000\"/>" // SRAM2 (64 kB)
+ " <memory type=\"ram\" start=\"0x20000000\" length=\"0x50000\"/>" // SRAM1 + aliased SRAM2 (256 + 64 = 320 kB)
+ " <memory type=\"flash\" start=\"0x08000000\" length=\"0x%x\">"
+ " <property name=\"blocksize\">0x800</property>"
+ " </memory>"
+ " <memory type=\"ram\" start=\"0x40000000\" length=\"0x1fffffff\"/>" // peripheral regs
+ " <memory type=\"ram\" start=\"0x60000000\" length=\"0x7fffffff\"/>" // AHB3 Peripherals
+ " <memory type=\"ram\" start=\"0xe0000000\" length=\"0x1fffffff\"/>" // cortex regs
+ " <memory type=\"rom\" start=\"0x1fff0000\" length=\"0x7000\"/>" // bootrom
+ " <memory type=\"rom\" start=\"0x1fff7800\" length=\"0x10\"/>" // option byte area
+ " <memory type=\"rom\" start=\"0x1ffff800\" length=\"0x10\"/>" // option byte area
+ "</memory-map>";
+
+static const char* const memory_map_template =
+ "<?xml version=\"1.0\"?>"
+ "<!DOCTYPE memory-map PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\""
+ " \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"
+ "<memory-map>"
+ " <memory type=\"rom\" start=\"0x00000000\" length=\"0x%x\"/>" // code = sram, bootrom or flash; flash is bigger
+ " <memory type=\"ram\" start=\"0x20000000\" length=\"0x%x\"/>" // SRAM (8 kB)
+ " <memory type=\"flash\" start=\"0x08000000\" length=\"0x%x\">"
+ " <property name=\"blocksize\">0x%x</property>"
+ " </memory>"
+ " <memory type=\"ram\" start=\"0x40000000\" length=\"0x1fffffff\"/>" // peripheral regs
+ " <memory type=\"ram\" start=\"0xe0000000\" length=\"0x1fffffff\"/>" // cortex regs
+ " <memory type=\"rom\" start=\"0x%08x\" length=\"0x%x\"/>" // bootrom
+ " <memory type=\"rom\" start=\"0x1ffff800\" length=\"0x10\"/>" // option byte area
+ "</memory-map>";
+
+static const char* const memory_map_template_F7 =
+ "<?xml version=\"1.0\"?>"
+ "<!DOCTYPE memory-map PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\""
+ " \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"
+ "<memory-map>"
+ " <memory type=\"ram\" start=\"0x00000000\" length=\"0x4000\"/>" // ITCM ram 16 kB
+ " <memory type=\"rom\" start=\"0x00200000\" length=\"0x100000\"/>" // ITCM flash
+ " <memory type=\"ram\" start=\"0x20000000\" length=\"0x%x\"/>" // SRAM
+ " <memory type=\"flash\" start=\"0x08000000\" length=\"0x20000\">" // Sectors 0...3
+ " <property name=\"blocksize\">0x8000</property>" // 32 kB
+ " </memory>"
+ " <memory type=\"flash\" start=\"0x08020000\" length=\"0x20000\">" // Sector 4
+ " <property name=\"blocksize\">0x20000</property>" // 128 kB
+ " </memory>"
+ " <memory type=\"flash\" start=\"0x08040000\" length=\"0xC0000\">" // Sectors 5...7
+ " <property name=\"blocksize\">0x40000</property>" // 128 kB
+ " </memory>"
+ " <memory type=\"ram\" start=\"0x40000000\" length=\"0x1fffffff\"/>" // peripheral regs
+ " <memory type=\"ram\" start=\"0x60000000\" length=\"0x7fffffff\"/>" // AHB3 Peripherals
+ " <memory type=\"ram\" start=\"0xe0000000\" length=\"0x1fffffff\"/>" // cortex regs
+ " <memory type=\"rom\" start=\"0x00100000\" length=\"0xEDC0\"/>" // bootrom
+ " <memory type=\"rom\" start=\"0x1fff0000\" length=\"0x20\"/>" // option byte area
+ "</memory-map>";
+
+static const char* const memory_map_template_H7 =
+ "<?xml version=\"1.0\"?>"
+ "<!DOCTYPE memory-map PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\""
+ " \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"
+ "<memory-map>"
+ " <memory type=\"rom\" start=\"0x00000000\" length=\"0x10000\"/>" // ITCMRAM 64 kB
+ " <memory type=\"ram\" start=\"0x20000000\" length=\"0x20000\"/>" // DTCMRAM 128 kB
+ " <memory type=\"ram\" start=\"0x24000000\" length=\"0x80000\"/>" // RAM D1 512 kB
+ " <memory type=\"ram\" start=\"0x30000000\" length=\"0x48000\"/>" // RAM D2 288 kB
+ " <memory type=\"ram\" start=\"0x38000000\" length=\"0x10000\"/>" // RAM D3 64 kB
+ " <memory type=\"flash\" start=\"0x08000000\" length=\"0x%x\">"
+ " <property name=\"blocksize\">0x%x</property>"
+ " </memory>"
+ " <memory type=\"ram\" start=\"0x40000000\" length=\"0x1fffffff\"/>" // peripheral regs
+ " <memory type=\"ram\" start=\"0xe0000000\" length=\"0x1fffffff\"/>" // cortex regs
+ " <memory type=\"rom\" start=\"0x1ff00000\" length=\"0x20000\"/>" // bootrom
+ "</memory-map>";
+
+static const char* const memory_map_template_H72x3x =
+ "<?xml version=\"1.0\"?>"
+ "<!DOCTYPE memory-map PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\""
+ " \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"
+ "<memory-map>"
+ " <memory type=\"rom\" start=\"0x00000000\" length=\"0x40000\"/>" // ITCMRAM 64 kB + Optional remap
+ " <memory type=\"ram\" start=\"0x20000000\" length=\"0x20000\"/>" // DTCMRAM 128 kB
+ " <memory type=\"ram\" start=\"0x24000000\" length=\"0x80000\"/>" // RAM D1 320 kB
+ " <memory type=\"ram\" start=\"0x30000000\" length=\"0x08000\"/>" // RAM D2 23 kB
+ " <memory type=\"ram\" start=\"0x38000000\" length=\"0x04000\"/>" // RAM D3 16 kB
+ " <memory type=\"ram\" start=\"0x38800000\" length=\"0x01000\"/>" // Backup RAM 4 kB
+ " <memory type=\"flash\" start=\"0x08000000\" length=\"0x%x\">"
+ " <property name=\"blocksize\">0x%x</property>"
+ " </memory>"
+ " <memory type=\"ram\" start=\"0x40000000\" length=\"0x1fffffff\"/>" // peripheral regs
+ " <memory type=\"ram\" start=\"0x60000000\" length=\"0x3fffffff\"/>" // External Memory
+ " <memory type=\"ram\" start=\"0xC0000000\" length=\"0x1fffffff\"/>" // External device
+ " <memory type=\"ram\" start=\"0xe0000000\" length=\"0x1fffffff\"/>" // cortex regs
+ " <memory type=\"rom\" start=\"0x1ff00000\" length=\"0x20000\"/>" // bootrom
+ "</memory-map>";
+
+static const char* const memory_map_template_F4_DE =
+ "<?xml version=\"1.0\"?>"
+ "<!DOCTYPE memory-map PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\""
+ " \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"
+ "<memory-map>"
+ " <memory type=\"rom\" start=\"0x00000000\" length=\"0x80000\"/>" // code = sram, bootrom or flash; flash is bigger
+ " <memory type=\"ram\" start=\"0x20000000\" length=\"0x18000\"/>" // SRAM
+ " <memory type=\"flash\" start=\"0x08000000\" length=\"0x10000\">" // Sectors 0..3
+ " <property name=\"blocksize\">0x4000</property>" // 16 kB
+ " </memory>"
+ " <memory type=\"flash\" start=\"0x08010000\" length=\"0x10000\">" // Sector 4
+ " <property name=\"blocksize\">0x10000</property>" // 64 kB
+ " </memory>"
+ " <memory type=\"flash\" start=\"0x08020000\" length=\"0x60000\">" // Sectors 5..7
+ " <property name=\"blocksize\">0x20000</property>" // 128 kB
+ " </memory>"
+ " <memory type=\"ram\" start=\"0x40000000\" length=\"0x1fffffff\"/>" // peripheral regs
+ " <memory type=\"ram\" start=\"0xe0000000\" length=\"0x1fffffff\"/>" // cortex regs
+ " <memory type=\"rom\" start=\"0x1fff0000\" length=\"0x7800\"/>" // bootrom
+ " <memory type=\"rom\" start=\"0x1fff7800\" length=\"0x210\"/>" // otp
+ " <memory type=\"rom\" start=\"0x1fffc000\" length=\"0x10\"/>" // option byte area
+ "</memory-map>";
+
+#endif // MEMORY_MAP_H \ No newline at end of file
diff --git a/src/st-util/semihosting.c b/src/st-util/semihosting.c
index 32169c8..8e9828c 100644
--- a/src/st-util/semihosting.c
+++ b/src/st-util/semihosting.c
@@ -1,72 +1,76 @@
#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
#include <string.h>
+
+#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
-#include <stdlib.h>
-#include <errno.h>
#include <stlink.h>
-#include <logging.h>
#include "semihosting.h"
-static int mem_read_u8(stlink_t *sl, uint32_t addr, uint8_t *data) {
- int offset = addr % 4;
- int len = 4;
+#include <logging.h>
+#include <read_write.h>
+
+static int32_t mem_read_u8(stlink_t *sl, uint32_t addr, uint8_t *data) {
+ int32_t offset = addr % 4;
+ int32_t len = 4;
- if (sl == NULL || data == NULL) { return(-1); }
+ if (sl == NULL || data == NULL) { return (-1); }
// read address and length must be aligned
- if (stlink_read_mem32(sl, addr - offset, len) != 0) { return(-1); }
+ if (stlink_read_mem32(sl, addr - offset, len) != 0) { return (-1); }
*data = sl->q_buf[offset];
- return(0);
+ return (0);
}
#ifdef UNUSED
-static int mem_read_u16(stlink_t *sl, uint32_t addr, uint16_t *data) {
- int offset = addr % 4;
- int len = (offset > 2 ? 8 : 4);
+static int32_t mem_read_u16(stlink_t *sl, uint32_t addr, uint16_t *data) {
+ int32_t offset = addr % 4;
+ int32_t len = (offset > 2 ? 8 : 4);
- if (sl == NULL || data == NULL) { return(-1); }
+ if (sl == NULL || data == NULL) { return (-1); }
// read address and length must be aligned
- if (stlink_read_mem32(sl, addr - offset, len) != 0) { return(-1); }
+ if (stlink_read_mem32(sl, addr - offset, len) != 0) { return (-1); }
memcpy(data, &sl->q_buf[offset], sizeof(*data));
- return(0);
+ return (0);
}
-static int mem_read_u32(stlink_t *sl, uint32_t addr, uint32_t *data) {
- int offset = addr % 4;
- int len = (offset > 0 ? 8 : 4);
+static int32_t mem_read_u32(stlink_t *sl, uint32_t addr, uint32_t *data) {
+ int32_t offset = addr % 4;
+ int32_t len = (offset > 0 ? 8 : 4);
- if (sl == NULL || data == NULL) { return(-1); }
+ if (sl == NULL || data == NULL) { return (-1); }
// read address and length must be aligned
- if (stlink_read_mem32(sl, addr - offset, len) != 0) { return(-1); }
+ if (stlink_read_mem32(sl, addr - offset, len) != 0) { return (-1); }
memcpy(data, &sl->q_buf[offset], sizeof(*data));
- return(0);
+ return (0);
}
#endif
-static int mem_read(stlink_t *sl, uint32_t addr, void *data, uint16_t len) {
- int offset = addr % 4;
- int read_len = len + offset;
+static int32_t mem_read(stlink_t *sl, uint32_t addr, void *data, uint16_t len) {
+ int32_t offset = addr % 4;
+ int32_t read_len = len + offset;
- if (sl == NULL || data == NULL) { return(-1); }
+ if (sl == NULL || data == NULL) { return (-1); }
// align read size
if ((read_len % 4) != 0) { read_len += 4 - (read_len % 4); }
// address and length must be aligned
- if (stlink_read_mem32(sl, addr - offset, read_len) != 0) { return(-1); }
+ if (stlink_read_mem32(sl, addr - offset, read_len) != 0) { return (-1); }
memcpy(data, &sl->q_buf[offset], len);
- return(0);
+ return (0);
}
-static int mem_write(stlink_t *sl, uint32_t addr, void *data, uint16_t len) {
+static int32_t mem_write(stlink_t *sl, uint32_t addr, void *data, uint16_t len) {
/* Note: this function can write more than it is asked to!
* If addr is not an even 32 bit boundary, or len is not a multiple of 4.
* If only 32 bit values can be written to the target, then this function should read
@@ -74,12 +78,12 @@ static int mem_write(stlink_t *sl, uint32_t addr, void *data, uint16_t len) {
* the requested bytes. (perhaps reading the whole area is faster??).
* If 16 and 8 bit writes are available, then they could be used instead.
* Just return when the length is zero avoiding unneeded work. */
- if (len == 0) { return(0); }
+ if (len == 0) { return (0); }
- int offset = addr % 4;
- int write_len = len + offset;
+ int32_t offset = addr % 4;
+ int32_t write_len = len + offset;
- if (sl == NULL || data == NULL) { return(-1); }
+ if (sl == NULL || data == NULL) { return (-1); }
// align read size
if ((write_len % 4) != 0) { write_len += 4 - (write_len % 4); }
@@ -87,9 +91,9 @@ static int mem_write(stlink_t *sl, uint32_t addr, void *data, uint16_t len) {
memcpy(&sl->q_buf[offset], data, len);
// address and length must be aligned
- if (stlink_write_mem32(sl, addr - offset, write_len) != 0) { return(-1); }
+ if (stlink_write_mem32(sl, addr - offset, write_len) != 0) { return (-1); }
- return(0);
+ return (0);
}
/* For the SYS_WRITE0 call, we don't know the size of the null-terminated buffer
@@ -110,7 +114,7 @@ static int mem_write(stlink_t *sl, uint32_t addr, void *data, uint16_t len) {
#define O_BINARY 0
#endif
-static int open_mode_flags[12] = {
+static int32_t open_mode_flags[12] = {
O_RDONLY,
O_RDONLY | O_BINARY,
O_RDWR,
@@ -125,11 +129,11 @@ static int open_mode_flags[12] = {
O_RDWR | O_CREAT | O_APPEND | O_BINARY
};
-static int saved_errno = 0;
+static int32_t saved_errno = 0;
-int do_semihosting (stlink_t *sl, uint32_t r0, uint32_t r1, uint32_t *ret) {
+int32_t do_semihosting (stlink_t *sl, uint32_t r0, uint32_t r1, uint32_t *ret) {
- if (sl == NULL || ret == NULL) { return(-1); }
+ if (sl == NULL || ret == NULL) { return (-1); }
DLOG("Do semihosting R0=0x%08x R1=0x%08x\n", r0, r1);
@@ -145,7 +149,7 @@ int do_semihosting (stlink_t *sl, uint32_t r0, uint32_t r1, uint32_t *ret) {
if (mem_read(sl, r1, args, sizeof(args)) != 0) {
DLOG("Semihosting SYS_OPEN error: cannot read args from target memory\n");
*ret = -1;
- return(-1);
+ return (-1);
}
name_address = args[0];
@@ -156,7 +160,7 @@ int do_semihosting (stlink_t *sl, uint32_t r0, uint32_t r1, uint32_t *ret) {
/* Invalid mode */
DLOG("Semihosting SYS_OPEN error: invalid mode %d\n", mode);
*ret = -1;
- return(-1);
+ return (-1);
}
/* Add the trailing zero that is not counted in the length argument (see
@@ -167,7 +171,7 @@ int do_semihosting (stlink_t *sl, uint32_t r0, uint32_t r1, uint32_t *ret) {
if (name_len > MAX_BUFFER_SIZE) {
DLOG("Semihosting SYS_OPEN error: name buffer size is too big %d\n", name_len);
*ret = -1;
- return(-1);
+ return (-1);
}
name = malloc(name_len);
@@ -175,14 +179,14 @@ int do_semihosting (stlink_t *sl, uint32_t r0, uint32_t r1, uint32_t *ret) {
if (name == NULL) {
DLOG("Semihosting SYS_OPEN error: cannot allocate name buffer\n");
*ret = -1;
- return(-1);
+ return (-1);
}
if (mem_read(sl, name_address, name, name_len) != 0) {
free(name);
*ret = -1;
DLOG("Semihosting SYS_OPEN error: cannot read name from target memory\n");
- return(-1);
+ return (-1);
}
DLOG("Semihosting: open('%s', (SH open mode)%d, 0644)\n", name, mode);
@@ -198,15 +202,15 @@ int do_semihosting (stlink_t *sl, uint32_t r0, uint32_t r1, uint32_t *ret) {
case SEMIHOST_SYS_CLOSE:
{
uint32_t args[1];
- int fd;
+ int32_t fd;
if (mem_read(sl, r1, args, sizeof(args)) != 0) {
DLOG("Semihosting SYS_CLOSE error: cannot read args from target memory\n");
*ret = -1;
- return(-1);
+ return (-1);
}
- fd = (int)args[0];
+ fd = (int32_t)args[0];
DLOG("Semihosting: close(%d)\n", fd);
@@ -220,17 +224,17 @@ int do_semihosting (stlink_t *sl, uint32_t r0, uint32_t r1, uint32_t *ret) {
{
uint32_t args[3];
uint32_t buffer_address;
- int fd;
+ int32_t fd;
uint32_t buffer_len;
void *buffer;
if (mem_read(sl, r1, args, sizeof(args)) != 0) {
DLOG("Semihosting SYS_WRITE error: cannot read args from target memory\n");
*ret = -1;
- return(-1);
+ return (-1);
}
- fd = (int)args[0];
+ fd = (int32_t)args[0];
buffer_address = args[1];
buffer_len = args[2];
@@ -238,7 +242,7 @@ int do_semihosting (stlink_t *sl, uint32_t r0, uint32_t r1, uint32_t *ret) {
DLOG("Semihosting SYS_WRITE error: buffer size is too big %d\n",
buffer_len);
*ret = buffer_len;
- return(-1);
+ return (-1);
}
buffer = malloc(buffer_len);
@@ -246,18 +250,17 @@ int do_semihosting (stlink_t *sl, uint32_t r0, uint32_t r1, uint32_t *ret) {
if (buffer == NULL) {
DLOG("Semihosting SYS_WRITE error: cannot allocate buffer\n");
*ret = buffer_len;
- return(-1);
+ return (-1);
}
if (mem_read(sl, buffer_address, buffer, buffer_len) != 0) {
DLOG("Semihosting SYS_WRITE error: cannot read buffer from target memory\n");
free(buffer);
*ret = buffer_len;
- return(-1);
+ return (-1);
}
- DLOG("Semihosting: write(%d, target_addr:0x%08x, %u)\n", fd, buffer_address,
- buffer_len);
+ DLOG("Semihosting: write(%d, target_addr:0x%08x, %u)\n", fd, buffer_address, buffer_len);
*ret = (uint32_t)write(fd, buffer, buffer_len);
saved_errno = errno;
@@ -276,7 +279,7 @@ int do_semihosting (stlink_t *sl, uint32_t r0, uint32_t r1, uint32_t *ret) {
{
uint32_t args[3];
uint32_t buffer_address;
- int fd;
+ int32_t fd;
uint32_t buffer_len;
void *buffer;
ssize_t read_result;
@@ -284,17 +287,17 @@ int do_semihosting (stlink_t *sl, uint32_t r0, uint32_t r1, uint32_t *ret) {
if (mem_read(sl, r1, args, sizeof(args)) != 0) {
DLOG("Semihosting SYS_READ error: cannot read args from target memory\n");
*ret = -1;
- return(-1);
+ return (-1);
}
- fd = (int)args[0];
+ fd = (int32_t)args[0];
buffer_address = args[1];
buffer_len = args[2];
if (buffer_len > MAX_BUFFER_SIZE) {
DLOG("Semihosting SYS_READ error: buffer size is too big %d\n", buffer_len);
*ret = buffer_len;
- return(-1);
+ return (-1);
}
buffer = malloc(buffer_len);
@@ -302,7 +305,7 @@ int do_semihosting (stlink_t *sl, uint32_t r0, uint32_t r1, uint32_t *ret) {
if (buffer == NULL) {
DLOG("Semihosting SYS_READ error: cannot allocatebuffer\n");
*ret = buffer_len;
- return(-1);
+ return (-1);
}
DLOG("Semihosting: read(%d, target_addr:0x%08x, %u)\n", fd, buffer_address,
@@ -318,7 +321,7 @@ int do_semihosting (stlink_t *sl, uint32_t r0, uint32_t r1, uint32_t *ret) {
DLOG("Semihosting SYS_READ error: cannot write buffer to target memory\n");
free(buffer);
*ret = buffer_len;
- return(-1);
+ return (-1);
} else {
*ret = buffer_len - (uint32_t)read_result;
}
@@ -344,7 +347,7 @@ int do_semihosting (stlink_t *sl, uint32_t r0, uint32_t r1, uint32_t *ret) {
if (mem_read(sl, r1, args, sizeof(args)) != 0) {
DLOG("Semihosting SYS_REMOVE error: cannot read args from target memory\n");
*ret = -1;
- return(-1);
+ return (-1);
}
name_address = args[0];
@@ -359,7 +362,7 @@ int do_semihosting (stlink_t *sl, uint32_t r0, uint32_t r1, uint32_t *ret) {
DLOG("Semihosting SYS_REMOVE error: name buffer size is too big %d\n",
name_len);
*ret = -1;
- return(-1);
+ return (-1);
}
name = malloc(name_len);
@@ -367,14 +370,14 @@ int do_semihosting (stlink_t *sl, uint32_t r0, uint32_t r1, uint32_t *ret) {
if (name == NULL) {
DLOG("Semihosting SYS_REMOVE error: cannot allocate name buffer\n");
*ret = -1;
- return(-1);
+ return (-1);
}
if (mem_read(sl, name_address, name, name_len) != 0) {
free(name);
*ret = -1;
DLOG("Semihosting SYS_REMOVE error: cannot read name from target memory\n");
- return(-1);
+ return (-1);
}
DLOG("Semihosting: unlink('%s')\n", name);
@@ -387,19 +390,19 @@ int do_semihosting (stlink_t *sl, uint32_t r0, uint32_t r1, uint32_t *ret) {
case SEMIHOST_SYS_SEEK:
{
uint32_t args[2];
- int fd;
+ int32_t fd;
off_t offset;
if (mem_read(sl, r1, args, sizeof(args)) != 0) {
DLOG("Semihosting SYS_SEEK error: cannot read args from target memory\n");
*ret = -1;
- return(-1);
+ return (-1);
}
- fd = (int)args[0];
+ fd = (int32_t)args[0];
offset = (off_t)args[1];
- DLOG("Semihosting: lseek(%d, %d, SEEK_SET)\n", fd, (int)offset);
+ DLOG("Semihosting: lseek(%d, %d, SEEK_SET)\n", fd, (int32_t)offset);
*ret = (uint32_t)lseek(fd, offset, SEEK_SET);
saved_errno = errno;
@@ -433,11 +436,11 @@ int do_semihosting (stlink_t *sl, uint32_t r0, uint32_t r1, uint32_t *ret) {
while (true) {
if (mem_read(sl, r1, buf, WRITE0_BUFFER_SIZE) != 0) {
DLOG("Semihosting WRITE0: cannot read target memory at 0x%08x\n", r1);
- return(-1);
+ return (-1);
}
- for (int i = 0; i < WRITE0_BUFFER_SIZE; i++) {
- if (buf[i] == 0) { return(0); }
+ for (int32_t i = 0; i < WRITE0_BUFFER_SIZE; i++) {
+ if (buf[i] == 0) { return (0); }
fprintf(stderr, "%c", buf[i]);
}
@@ -449,7 +452,7 @@ int do_semihosting (stlink_t *sl, uint32_t r0, uint32_t r1, uint32_t *ret) {
}
default:
fprintf(stderr, "semihosting: unsupported call %#x\n", r0);
- return(-1);
+ return (-1);
}
- return(0);
+ return (0);
}
diff --git a/src/st-util/semihosting.h b/src/st-util/semihosting.h
index 8c1ac15..fd3990b 100644
--- a/src/st-util/semihosting.h
+++ b/src/st-util/semihosting.h
@@ -1,5 +1,7 @@
-#ifndef _SEMIHOSTING_H_
-#define _SEMIHOSTING_H_
+#ifndef SEMIHOSTING_H
+#define SEMIHOSTING_H
+
+#include <stdint.h>
#include <stlink.h>
@@ -29,6 +31,6 @@
#define SEMIHOST_SYS_ELAPSED 0x30
#define SEMIHOST_SYS_TICKFREQ 0x31
-int do_semihosting(stlink_t *sl, uint32_t r0, uint32_t r1, uint32_t *ret);
+int32_t do_semihosting(stlink_t *sl, uint32_t r0, uint32_t r1, uint32_t *ret);
-#endif // _SEMIHOSTING_H_
+#endif // SEMIHOSTING_H
diff --git a/src/stlink-gui/CMakeLists.txt b/src/stlink-gui/CMakeLists.txt
index 80e3762..062814e 100644
--- a/src/stlink-gui/CMakeLists.txt
+++ b/src/stlink-gui/CMakeLists.txt
@@ -16,27 +16,20 @@ if (NOT WIN32)
# Install desktop application entry
install(FILES stlink-gui.desktop
- DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications)
+ DESTINATION ${CMAKE_INSTALL_FULL_DATADIR}/applications)
# Install icons
install(FILES icons/stlink-gui.svg
- DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/scalable/apps)
+ DESTINATION ${CMAKE_INSTALL_FULL_DATADIR}/icons/hicolor/scalable/apps)
set(GUI_SOURCES gui.c gui.h)
- ## stlink-gui-local
- add_executable(stlink-gui-local ${GUI_SOURCES})
- file(COPY stlink-gui.ui DESTINATION ${CMAKE_BINARY_DIR}/bin)
- set_target_properties(stlink-gui-local PROPERTIES
- COMPILE_DEFINITIONS STLINK_UI_DIR="${CMAKE_BINARY_DIR}/bin")
- target_link_libraries(stlink-gui-local ${STLINK_LIB_SHARED} ${SSP_LIB} ${GTK3_LDFLAGS})
-
## stlink-gui
add_executable(stlink-gui ${GUI_SOURCES})
- install(FILES stlink-gui.ui DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME})
+ install(FILES stlink-gui.ui DESTINATION ${CMAKE_INSTALL_FULL_DATADIR}/${PROJECT_NAME})
set_target_properties(stlink-gui PROPERTIES
- COMPILE_DEFINITIONS STLINK_UI_DIR="${CMAKE_INSTALL_FULL_DATAROOTDIR}/${PROJECT_NAME}")
+ COMPILE_DEFINITIONS STLINK_UI_DIR="${CMAKE_INSTALL_FULL_DATADIR}/${PROJECT_NAME}")
target_link_libraries(stlink-gui ${STLINK_LIB_SHARED} ${SSP_LIB} ${GTK3_LDFLAGS})
- install(TARGETS stlink-gui DESTINATION ${CMAKE_INSTALL_BINDIR})
- endif ()
-endif ()
+ install(TARGETS stlink-gui DESTINATION ${CMAKE_BINDIR})
+ endif()
+endif()
diff --git a/src/stlink-gui/gui.c b/src/stlink-gui/gui.c
index 03e999b..51ee293 100644
--- a/src/stlink-gui/gui.c
+++ b/src/stlink-gui/gui.c
@@ -7,6 +7,11 @@
#include <stlink.h>
#include "gui.h"
+#include <chipid.h>
+#include <common_flash.h>
+#include <read_write.h>
+#include <usb.h>
+
#define MEM_READ_SIZE 1024
#ifndef G_VALUE_INIT
@@ -59,7 +64,7 @@ static gboolean set_info_error_message_idle(STlinkGUI *gui) {
gui->error_message = NULL;
}
- return(FALSE);
+ return (FALSE);
}
static void stlink_gui_set_info_error_message(STlinkGUI *gui, const gchar *message) {
@@ -152,15 +157,15 @@ static guint32 hexstr_to_guint32(const gchar *str, GError **err) {
if ((errno == ERANGE && val == UINT_MAX) || (errno != 0 && val == 0)) {
g_set_error(err, g_quark_from_string("hextou32"), 1, "Invalid hexstring");
- return(UINT32_MAX);
+ return (UINT32_MAX);
}
if (end_ptr == str) {
g_set_error(err, g_quark_from_string("hextou32"), 2, "Invalid hexstring");
- return(UINT32_MAX);
+ return (UINT32_MAX);
}
- return(val);
+ return (val);
}
static void stlink_gui_update_mem_view(STlinkGUI *gui, struct mem_t *mem, GtkTreeView *view) {
@@ -178,7 +183,7 @@ static void stlink_gui_update_mem_view(STlinkGUI *gui, struct mem_t *mem, GtkTre
static gboolean stlink_gui_update_devmem_view(STlinkGUI *gui) {
stlink_gui_update_mem_view(gui, &gui->flash_mem, gui->devmem_treeview);
- return(FALSE);
+ return (FALSE);
}
static gpointer stlink_gui_populate_devmem_view(gpointer data) {
@@ -216,7 +221,7 @@ static gpointer stlink_gui_populate_devmem_view(gpointer data) {
stlink_gui_set_info_error_message(gui, "Failed to read memory");
g_free(gui->flash_mem.memory);
gui->flash_mem.memory = NULL;
- return(NULL);
+ return (NULL);
}
memcpy(gui->flash_mem.memory + off, gui->sl->q_buf, n_read);
@@ -224,7 +229,7 @@ static gpointer stlink_gui_populate_devmem_view(gpointer data) {
}
g_idle_add((GSourceFunc)stlink_gui_update_devmem_view, gui);
- return(NULL);
+ return (NULL);
}
static gboolean stlink_gui_update_filemem_view(STlinkGUI *gui) {
@@ -236,7 +241,7 @@ static gboolean stlink_gui_update_filemem_view(STlinkGUI *gui) {
g_free(basename);
stlink_gui_update_mem_view(gui, &gui->file_mem, gui->filemem_treeview);
- return(FALSE);
+ return (FALSE);
}
static gpointer stlink_gui_populate_filemem_view(gpointer data) {
@@ -261,9 +266,9 @@ static gpointer stlink_gui_populate_filemem_view(gpointer data) {
*/
uint8_t* mem = NULL;
- size_t size = 0;
+ uint32_t size = 0;
uint32_t begin = 0;
- int res = stlink_parse_ihex(gui->filename, 0, &mem, &size, &begin);
+ int32_t res = stlink_parse_ihex(gui->filename, 0, &mem, &size, &begin);
if (res == 0) {
if (gui->file_mem.memory) {
@@ -301,7 +306,14 @@ static gpointer stlink_gui_populate_filemem_view(gpointer data) {
if (gui->file_mem.memory) { g_free(gui->file_mem.memory); }
- gui->file_mem.size = g_file_info_get_size(file_info);
+ goffset file_size = g_file_info_get_size(file_info);
+
+ if ((0 > file_size) && ((goffset)G_MAXSIZE <= file_size)) {
+ stlink_gui_set_info_error_message(gui, "File too large.");
+ goto out_input;
+ }
+
+ gui->file_mem.size = file_size;
gui->file_mem.memory = g_malloc(gui->file_mem.size);
for (off = 0; off < (gint)gui->file_mem.size; off += MEM_READ_SIZE) {
@@ -327,7 +339,7 @@ out: g_object_unref(file);
}
g_idle_add((GSourceFunc)stlink_gui_update_filemem_view, gui);
- return(NULL);
+ return (NULL);
}
static void mem_jmp(GtkTreeView *view,
@@ -427,13 +439,13 @@ static gchar *dev_format_chip_id(guint32 chip_id) {
params = stlink_chipid_get_params(chip_id);
- if (!params) { return(g_strdup_printf("0x%x", chip_id)); }
+ if (!params) { return (g_strdup_printf("0x%x", chip_id)); }
- return(g_strdup(params->description));
+ return (g_strdup(params->dev_type));
}
static gchar *dev_format_mem_size(gsize flash_size) {
- return(g_strdup_printf("%u kB", (unsigned int)(flash_size / 1024)));
+ return (g_strdup_printf("%u kB", (uint32_t)(flash_size / 1024)));
}
@@ -495,24 +507,13 @@ static void connect_button_cb(GtkWidget *widget, gpointer data) {
if (gui->sl != NULL) { return; }
- gui->sl = stlink_v1_open(0, 1); // try version 1 then version 2
-
- if (gui->sl == NULL) { gui->sl = stlink_open_usb(0, 1, NULL, 0); }
+ gui->sl = stlink_open_usb(0, 1, NULL, 0);
if (gui->sl == NULL) {
stlink_gui_set_info_error_message(gui, "Failed to connect to STLink.");
return;
}
- // code below taken from flash/main.c, refactoring might be in order
- if (stlink_current_mode(gui->sl) == STLINK_DEV_DFU_MODE) {
- stlink_exit_dfu_mode(gui->sl);
- }
-
- if (stlink_current_mode(gui->sl) != STLINK_DEV_DEBUG_MODE) {
- stlink_enter_swd_mode(gui->sl);
- }
-
stlink_gui_set_connected(gui);
}
@@ -585,7 +586,7 @@ static gboolean stlink_gui_write_flash_update(STlinkGUI *gui) {
stlink_gui_set_sensitivity(gui, TRUE);
gui->progress.activity_mode = FALSE;
gtk_widget_hide(GTK_WIDGET(gui->progress.bar));
- return(FALSE);
+ return (FALSE);
}
static gpointer stlink_gui_write_flash(gpointer data) {
@@ -601,7 +602,7 @@ static gpointer stlink_gui_write_flash(gpointer data) {
}
g_idle_add((GSourceFunc)stlink_gui_write_flash_update, gui);
- return(NULL);
+ return (NULL);
}
static void flash_button_cb(GtkWidget *widget, gpointer data) {
@@ -644,17 +645,17 @@ static void flash_button_cb(GtkWidget *widget, gpointer data) {
}
}
-int export_to_file(const char*filename, const struct mem_t flash_mem) {
+int32_t export_to_file(const char*filename, const struct mem_t flash_mem) {
printf("%s\n", filename);
FILE * f = fopen(filename, "w");
- if (f == NULL) { return(-1); }
+ if (f == NULL) { return (-1); }
for (gsize i = 0; i < flash_mem.size; i++)
- if (fputc(flash_mem.memory[i], f) == EOF) { return(-1); }
+ if (fputc(flash_mem.memory[i], f) == EOF) { return (-1); }
fclose(f);
- return(0);
+ return (0);
}
static void export_button_cb(GtkWidget *widget, gpointer data) {
@@ -697,7 +698,7 @@ static gboolean progress_pulse_timeout(STlinkGUI *gui) {
gtk_progress_bar_set_fraction(gui->progress.bar, gui->progress.fraction);
}
- return(TRUE);
+ return (TRUE);
}
static void notebook_switch_page_cb(GtkNotebook *notebook,
@@ -889,15 +890,17 @@ static void stlink_gui_build_ui(STlinkGUI *gui) {
stlink_gui_set_disconnected(gui);
}
-int main(int argc, char **argv) {
+int32_t main(int32_t argc, char **argv) {
STlinkGUI *gui;
gtk_init(&argc, &argv);
+ init_chipids (STLINK_CHIPS_DIR);
+
gui = g_object_new(STLINK_TYPE_GUI, NULL);
stlink_gui_build_ui(gui);
stlink_gui_init_dnd(gui);
gtk_main();
- return(0);
+ return (0);
}
diff --git a/src/stlink-gui/gui.h b/src/stlink-gui/gui.h
index b3d5dff..2d7f319 100644
--- a/src/stlink-gui/gui.h
+++ b/src/stlink-gui/gui.h
@@ -1,6 +1,7 @@
-#ifndef __STLINK_GUI_H__
-#define __STLINK_GUI_H__
+#ifndef GUI_H
+#define GUI_H
+#include <stdint.h>
#include <glib-object.h>
#define STLINK_TYPE_GUI (stlink_gui_get_type())
@@ -87,6 +88,6 @@ struct _STlinkGUIClass {
};
GType stlink_gui_get_type(void);
-int export_to_file(const char*filename, const struct mem_t flash_mem);
+int32_t export_to_file(const char*filename, const struct mem_t flash_mem);
-#endif // __STLINK_GUI_H__
+#endif // GUI_H
diff --git a/src/stlink-lib/calculate.c b/src/stlink-lib/calculate.c
new file mode 100644
index 0000000..95a9414
--- /dev/null
+++ b/src/stlink-lib/calculate.c
@@ -0,0 +1,81 @@
+/*
+ * File: calculate.c
+ *
+ * Calculation of sector numbers and pages
+ */
+
+#include <stdint.h>
+
+#include <stlink.h>
+#include "calculate.h"
+
+#include "common_flash.h"
+#include "read_write.h"
+
+uint32_t calculate_F4_sectornum(uint32_t flashaddr) {
+ uint32_t offset = 0;
+ flashaddr &= ~STM32_FLASH_BASE; // page now holding the actual flash address
+
+ if (flashaddr >= 0x100000) {
+ offset = 12;
+ flashaddr -= 0x100000;
+ }
+
+ if (flashaddr < 0x4000) {
+ return (offset + 0);
+ } else if (flashaddr < 0x8000) {
+ return (offset + 1);
+ } else if (flashaddr < 0xc000) {
+ return (offset + 2);
+ } else if (flashaddr < 0x10000) {
+ return (offset + 3);
+ } else if (flashaddr < 0x20000) {
+ return (offset + 4);
+ } else {
+ return (offset + (flashaddr / 0x20000) + 4);
+ }
+}
+
+uint32_t calculate_F7_sectornum(uint32_t flashaddr) {
+ flashaddr &= ~STM32_FLASH_BASE; // Page now holding the actual flash address
+
+ if (flashaddr < 0x20000) {
+ return (flashaddr / 0x8000);
+ } else if (flashaddr < 0x40000) {
+ return (4);
+ } else {
+ return ((flashaddr / 0x40000) + 4);
+ }
+}
+
+uint32_t calculate_H7_sectornum(stlink_t *sl, uint32_t flashaddr, uint32_t bank) {
+ // sector holding the flash address
+ flashaddr &= ~((bank == BANK_1) ? STM32_FLASH_BASE : STM32_H7_FLASH_BANK2_BASE);
+ return (flashaddr / sl->flash_pgsz);
+}
+
+// returns BKER:PNB for the given page address
+uint32_t calculate_L4_page(stlink_t *sl, uint32_t flashaddr) {
+ uint32_t bker = 0;
+ uint32_t flashopt;
+ stlink_read_debug32(sl, FLASH_L4_OPTR, &flashopt);
+ flashaddr -= STM32_FLASH_BASE;
+
+ if (sl->chip_id == STM32_CHIPID_L4 ||
+ sl->chip_id == STM32_CHIPID_L496x_L4A6x ||
+ sl->chip_id == STM32_CHIPID_L4Rx) {
+ // these chips use dual bank flash
+ if (flashopt & (uint32_t)(1lu << FLASH_L4_OPTR_DUALBANK)) {
+ uint32_t banksize = sl->flash_size / 2;
+
+ if (flashaddr >= banksize) {
+ flashaddr -= banksize;
+ bker = 0x100;
+ }
+ }
+ }
+
+ // For 1MB chips without the dual-bank option set, the page address will
+ // overflow into the BKER bit, which gives us the correct bank:page value.
+ return (bker | flashaddr / sl->flash_pgsz);
+}
diff --git a/src/stlink-lib/calculate.h b/src/stlink-lib/calculate.h
new file mode 100644
index 0000000..ca0a39d
--- /dev/null
+++ b/src/stlink-lib/calculate.h
@@ -0,0 +1,15 @@
+/*
+ * File: calculate.h
+ *
+ * Calculation of sector numbers and pages
+ */
+
+#ifndef CALCULATE_H
+#define CALCULATE_H
+
+uint32_t calculate_F4_sectornum(uint32_t);
+uint32_t calculate_F7_sectornum(uint32_t);
+uint32_t calculate_H7_sectornum(stlink_t *, uint32_t, uint32_t);
+uint32_t calculate_L4_page(stlink_t *, uint32_t);
+
+#endif // CALCULATE_H
diff --git a/src/stlink-lib/chipid.c b/src/stlink-lib/chipid.c
index 187a6d9..c115089 100644
--- a/src/stlink-lib/chipid.c
+++ b/src/stlink-lib/chipid.c
@@ -1,769 +1,279 @@
+/*
+ * File: chipid.c
+ *
+ * Chip-ID parametres
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <stm32.h>
#include <stlink.h>
#include "chipid.h"
-static const struct stlink_chipid_params devices[] = {
- {
- // RM0410 document was used to find these paramaters
- .chip_id = STLINK_CHIPID_STM32_F7XXXX,
- .description = "F76xxx",
- .flash_type = STLINK_FLASH_TYPE_F7,
- .flash_size_reg = 0x1ff0f442, // section 45.2
- .flash_pagesize = 0x800, // No flash pages
- .sram_size = 0x80000, // "SRAM" byte size in hex from
- .bootrom_base = 0x00200000, // ! "System memory" starting address from
- .bootrom_size = 0xEDC0, // ! @todo "System memory" byte size in hex from
- .option_base =
- STM32_F7_OPTION_BYTES_BASE, // Used for reading back the option
- // bytes, writing uses FLASH_F7_OPTCR
- // and FLASH_F7_OPTCR1
- .option_size = 0x20,
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- // RM0385 and DS10916 document was used to find these paramaters
- .chip_id = STLINK_CHIPID_STM32_F7,
- .description = "F7xx",
- .flash_type = STLINK_FLASH_TYPE_F4,
- .flash_size_reg = 0x1ff0f442, // section 41.2
- .flash_pagesize = 0x800, // No flash pages
- .sram_size = 0x50000, // "SRAM" byte size in hex from DS Fig 18
- .bootrom_base =
- 0x00100000, // "System memory" starting address from DS Fig 18
- .bootrom_size =
- 0xEDC0, // "System memory" byte size in hex from DS Fig 18
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- // RM0431 and DS document was used to find these paramaters
- .chip_id = STLINK_CHIPID_STM32_F72XXX,
- .description = "F72x/F73x",
- .flash_type = STLINK_FLASH_TYPE_F4,
- .flash_size_reg = 0x1ff07a22, // section 35.2
- .flash_pagesize = 0x800, // No flash pages
- .sram_size = 0x40000, // "SRAM" byte size in hex from DS Fig 24
- .bootrom_base =
- 0x00100000, // "System memory" starting address from DS Fig 24
- .bootrom_size =
- 0xEDC0, // "System memory" byte size in hex from DS Fig 24
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- // table 2, PM0063
- .chip_id = STLINK_CHIPID_STM32_F1_MEDIUM,
- .description = "F1xx Medium-density",
- .flash_type = STLINK_FLASH_TYPE_F0,
- .flash_size_reg = 0x1ffff7e0,
- .flash_pagesize = 0x400,
- .sram_size = 0x5000,
- .bootrom_base = 0x1ffff000,
- .bootrom_size = 0x800,
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- // table 1, PM0059
- .chip_id = STLINK_CHIPID_STM32_F2,
- .description = "F2xx",
- .flash_type = STLINK_FLASH_TYPE_F4,
- .flash_size_reg = 0x1fff7a22, // as in RM0033 Rev 5
- .flash_pagesize = 0x20000,
- .sram_size = 0x20000,
- .bootrom_base = 0x1fff0000,
- .bootrom_size = 0x7800,
- .option_base = 0x1FFFC000,
- .option_size = 4,
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- // PM0063
- .chip_id = STLINK_CHIPID_STM32_F1_LOW,
- .description = "F1 Low-density device",
- .flash_type = STLINK_FLASH_TYPE_F0,
- .flash_size_reg = 0x1ffff7e0,
- .flash_pagesize = 0x400,
- .sram_size = 0x2800,
- .bootrom_base = 0x1ffff000,
- .bootrom_size = 0x800,
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- .chip_id = STLINK_CHIPID_STM32_F4,
- .description = "F4xx",
- .flash_type = STLINK_FLASH_TYPE_F4,
- .flash_size_reg = 0x1FFF7A22, // As in rm0090 since Rev 2
- .flash_pagesize = 0x4000,
- .sram_size = 0x30000,
- .bootrom_base = 0x1fff0000,
- .bootrom_size = 0x7800,
- .option_base = STM32_F4_OPTION_BYTES_BASE,
- .option_size = 4,
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- .chip_id = STLINK_CHIPID_STM32_F4_DSI,
- .description = "F46x/F47x",
- .flash_type = STLINK_FLASH_TYPE_F4,
- .flash_size_reg = 0x1FFF7A22, // As in rm0090 since Rev 2
- .flash_pagesize = 0x4000,
- .sram_size = 0x40000,
- .bootrom_base = 0x1fff0000,
- .bootrom_size = 0x7800,
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- .chip_id = STLINK_CHIPID_STM32_F4_HD,
- .description = "F42x/F43x",
- .flash_type = STLINK_FLASH_TYPE_F4,
- .flash_size_reg = 0x1FFF7A22, // As in rm0090 since Rev 2
- .flash_pagesize = 0x4000,
- .sram_size = 0x40000,
- .bootrom_base = 0x1fff0000,
- .bootrom_size = 0x7800,
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- .chip_id = STLINK_CHIPID_STM32_F4_LP,
- .description = "F4xx (low power)",
- .flash_type = STLINK_FLASH_TYPE_F4,
- .flash_size_reg = 0x1FFF7A22,
- .flash_pagesize = 0x4000,
- .sram_size = 0x10000,
- .bootrom_base = 0x1fff0000,
- .bootrom_size = 0x7800,
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- .chip_id = STLINK_CHIPID_STM32_F411RE,
- .description = "stm32f411re",
- .flash_type = STLINK_FLASH_TYPE_F4,
- .flash_size_reg = 0x1FFF7A22,
- .flash_pagesize = 0x4000,
- .sram_size = 0x20000,
- .bootrom_base = 0x1fff0000,
- .bootrom_size = 0x7800,
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- .chip_id = STLINK_CHIPID_STM32_F4_DE,
- .description = "F4xx (Dynamic Efficency)",
- .flash_type = STLINK_FLASH_TYPE_F4,
- .flash_size_reg = 0x1FFF7A22,
- .flash_pagesize = 0x4000,
- .sram_size = 0x18000,
- .bootrom_base = 0x1fff0000,
- .bootrom_size = 0x7800,
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- .chip_id = STLINK_CHIPID_STM32_F1_HIGH,
- .description = "F1xx High-density",
- .flash_type = STLINK_FLASH_TYPE_F0,
- .flash_size_reg = 0x1ffff7e0,
- .flash_pagesize = 0x800,
- .sram_size = 0x10000,
- .bootrom_base = 0x1ffff000,
- .bootrom_size = 0x800,
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- // This ignores the EEPROM! (and uses the page erase size,
- // not the sector write protection...)
- .chip_id = STLINK_CHIPID_STM32_L1_MEDIUM,
- .description = "L1xx Medium-density",
- .flash_type = STLINK_FLASH_TYPE_L0,
- .flash_size_reg = 0x1ff8004c,
- .flash_pagesize = 0x100,
- .sram_size = 0x4000,
- .bootrom_base = 0x1ff00000,
- .bootrom_size = 0x1000,
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- .chip_id = STLINK_CHIPID_STM32_L1_CAT2,
- .description = "L1xx Cat.2",
- .flash_type = STLINK_FLASH_TYPE_L0,
- .flash_size_reg = 0x1ff8004c,
- .flash_pagesize = 0x100,
- .sram_size = 0x8000,
- .bootrom_base = 0x1ff00000,
- .bootrom_size = 0x1000,
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- .chip_id = STLINK_CHIPID_STM32_L1_MEDIUM_PLUS,
- .description = "L1xx Medium-Plus-density",
- .flash_type = STLINK_FLASH_TYPE_L0,
- .flash_size_reg = 0x1ff800cc,
- .flash_pagesize = 0x100,
- .sram_size = 0x8000, // not completely clear if there are some with 48k
- .bootrom_base = 0x1ff00000,
- .bootrom_size = 0x1000,
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- .chip_id = STLINK_CHIPID_STM32_L1_HIGH,
- .description = "L1xx High-density",
- .flash_type = STLINK_FLASH_TYPE_L0,
- .flash_size_reg = 0x1ff800cc,
- .flash_pagesize = 0x100,
- .sram_size = 0xC000, // not completely clear if there are some with 32k
- .bootrom_base = 0x1ff00000,
- .bootrom_size = 0x1000,
- .option_base = STM32_L1_OPTION_BYTES_BASE,
- .option_size = 8,
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- .chip_id = STLINK_CHIPID_STM32_L152_RE,
- .description = "L152RE",
- .flash_type = STLINK_FLASH_TYPE_L0,
- .flash_size_reg = 0x1ff800cc,
- .flash_pagesize = 0x100,
- .sram_size = 0x14000, // not completely clear if there are some with 32k
- .bootrom_base = 0x1ff00000,
- .bootrom_size = 0x1000,
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- .chip_id = STLINK_CHIPID_STM32_F1_CONN,
- .description = "F1 Connectivity line",
- .flash_type = STLINK_FLASH_TYPE_F0,
- .flash_size_reg = 0x1ffff7e0,
- .flash_pagesize = 0x800,
- .sram_size = 0x10000,
- .bootrom_base = 0x1fffb000,
- .bootrom_size = 0x4800,
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- // Low and Medium density VL have same chipid. RM0041 25.6.1
- .chip_id = STLINK_CHIPID_STM32_F1_VL_MEDIUM_LOW,
- .description = "F1xx Value Line",
- .flash_type = STLINK_FLASH_TYPE_F0,
- .flash_size_reg = 0x1ffff7e0,
- .flash_pagesize = 0x400,
- .sram_size = 0x2000, // 0x1000 for low density devices
- .bootrom_base = 0x1ffff000,
- .bootrom_size = 0x800,
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- // STM32F446x family. Support based on DM00135183.pdf (RM0390) document.
- .chip_id = STLINK_CHIPID_STM32_F446,
- .description = "F446",
- .flash_type = STLINK_FLASH_TYPE_F4,
- .flash_size_reg = 0x1fff7a22,
- .flash_pagesize = 0x20000,
- .sram_size = 0x20000,
- .bootrom_base = 0x1fff0000,
- .bootrom_size = 0x7800,
- .option_base = 0x1FFFC000,
- .option_size = 4,
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- // STM32F410 MCUs. Support based on DM00180366.pdf (RM0401) document.
- .chip_id = STLINK_CHIPID_STM32_F410,
- .description = "F410",
- .flash_type = STLINK_FLASH_TYPE_F4,
- .flash_size_reg = 0x1fff7a22,
- .flash_pagesize = 0x4000,
- .sram_size = 0x8000,
- .bootrom_base = 0x1fff0000,
- .bootrom_size = 0x7800,
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- // This is STK32F303VCT6 device from STM32 F3 Discovery board.
- // Support based on DM00043574.pdf (RM0316) document.
- .chip_id = STLINK_CHIPID_STM32_F3,
- .description = "F3xx",
- .flash_type = STLINK_FLASH_TYPE_F0,
- .flash_size_reg = 0x1ffff7cc,
- .flash_pagesize = 0x800,
- .sram_size = 0xa000,
- .bootrom_base = 0x1ffff000,
- .bootrom_size = 0x800,
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- // This is STK32F373VCT6 device from STM32 F373 eval board
- // Support based on 303 above (37x and 30x have same memory map)
- .chip_id = STLINK_CHIPID_STM32_F37x,
- .description = "F3xx",
- .flash_type = STLINK_FLASH_TYPE_F0,
- .flash_size_reg = 0x1ffff7cc,
- .flash_pagesize = 0x800,
- .sram_size = 0xa000,
- .bootrom_base = 0x1ffff000,
- .bootrom_size = 0x800,
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- .chip_id = STLINK_CHIPID_STM32_F1_VL_HIGH,
- .description = "F1xx High-density value line",
- .flash_type = STLINK_FLASH_TYPE_F0,
- .flash_size_reg = 0x1ffff7e0,
- .flash_pagesize = 0x800,
- .sram_size = 0x8000,
- .bootrom_base = 0x1ffff000,
- .bootrom_size = 0x800,
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- .chip_id = STLINK_CHIPID_STM32_F1_XL,
- .description = "F1xx XL-density",
- .flash_type = STLINK_FLASH_TYPE_F1_XL,
- .flash_size_reg = 0x1ffff7e0,
- .flash_pagesize = 0x800,
- .sram_size = 0x18000,
- .bootrom_base = 0x1fffe000,
- .bootrom_size = 0x1800,
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- // Use this as an example for mapping future chips:
- // RM0091 document was used to find these paramaters
- .chip_id = STLINK_CHIPID_STM32_F0_CAN,
- .description = "F07x",
- .flash_type = STLINK_FLASH_TYPE_F0,
- .flash_size_reg = 0x1ffff7cc, // "Flash size data register" (pg735)
- .flash_pagesize = 0x800, // Page sizes listed in Table 4
- .sram_size = 0x4000, // "SRAM" byte size in hex from Table 2
- .bootrom_base =
- 0x1fffC800, // "System memory" starting address from Table 2
- .bootrom_size = 0x3000, // "System memory" byte size in hex from Table 2
- },
- {
- // Use this as an example for mapping future chips:
- // RM0091 document was used to find these paramaters
- .chip_id = STLINK_CHIPID_STM32_F0,
- .description = "F0xx",
- .flash_type = STLINK_FLASH_TYPE_F0,
- .flash_size_reg = 0x1ffff7cc, // "Flash size data register" (pg735)
- .flash_pagesize = 0x400, // Page sizes listed in Table 4
- .sram_size = 0x2000, // "SRAM" byte size in hex from Table 2
- .bootrom_base =
- 0x1fffec00, // "System memory" starting address from Table 2
- .bootrom_size = 0xC00, // "System memory" byte size in hex from Table 2
- },
- {
- // RM0402 document was used to find these parameters
- // Table 4.
- .chip_id = STLINK_CHIPID_STM32_F412,
- .description = "F412",
- .flash_type = STLINK_FLASH_TYPE_F4,
- .flash_size_reg = 0x1FFF7A22, // "Flash size data register" (pg1135)
- .flash_pagesize = 0x4000, // Table 5. Flash module organization ?
- .sram_size = 0x40000, // "SRAM" byte size in hex from Table 4
- .bootrom_base =
- 0x1FFF0000, // "System memory" starting address from Table 4
- .bootrom_size = 0x7800, // "System memory" byte size in hex from Table 4
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- // RM0430 DocID029473 Rev 2 document was used to find these parameters
- // Figure 2, Table 4, Table 5, Section 35.2
- .chip_id = STLINK_CHIPID_STM32_F413,
- .description = "F413",
- .flash_type = STLINK_FLASH_TYPE_F4,
- .flash_size_reg = 0x1FFF7A22, // "Flash size data register" Section 35.2
- .flash_pagesize =
- 0x4000, // Table 5. Flash module organization (variable sector
- // sizes, but 0x4000 is smallest)
- .sram_size = 0x50000, // "SRAM" byte size in hex from Figure 2 (Table 4
- // only says 0x40000)
- .bootrom_base =
- 0x1FFF0000, // "System memory" starting address from Table 4
- .bootrom_size = 0x7800, // "System memory" byte size in hex from Table 4
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- .chip_id = STLINK_CHIPID_STM32_F09X,
- .description = "F09X",
- .flash_type = STLINK_FLASH_TYPE_F0,
- .flash_size_reg = 0x1ffff7cc, // "Flash size data register" (pg735)
- .flash_pagesize = 0x800, // Page sizes listed in Table 4 (pg 56)
- .sram_size = 0x8000, // "SRAM" byte size in hex from Table 2 (pg 50)
- .bootrom_base =
- 0x1fffd800, // "System memory" starting address from Table 2
- .bootrom_size = 0x2000, // "System memory" byte size in hex from Table 2
- },
- {
- // Use this as an example for mapping future chips:
- // RM0091 document was used to find these paramaters
- .chip_id = STLINK_CHIPID_STM32_F04,
- .description = "F04x",
- .flash_type = STLINK_FLASH_TYPE_F0,
- .flash_size_reg = 0x1ffff7cc, // "Flash size data register" (pg735)
- .flash_pagesize = 0x400, // Page sizes listed in Table 4
- .sram_size = 0x1800, // "SRAM" byte size in hex from Table 2
- .bootrom_base =
- 0x1fffec00, // "System memory" starting address from Table 2
- .bootrom_size = 0xC00, // "System memory" byte size in hex from Table 2
- },
- {
- // Use this as an example for mapping future chips:
- // RM0091 document was used to find these paramaters
- .chip_id = STLINK_CHIPID_STM32_F0_SMALL,
- .description = "F0xx small",
- .flash_type = STLINK_FLASH_TYPE_F0,
- .flash_size_reg = 0x1ffff7cc, // "Flash size data register" (pg735)
- .flash_pagesize = 0x400, // Page sizes listed in Table 4
- .sram_size = 0x1000, // "SRAM" byte size in hex from Table 2
- .bootrom_base =
- 0x1fffec00, // "System memory" starting address from Table 2
- .bootrom_size = 0xC00, // "System memory" byte size in hex from Table 2
- },
- {
- // STM32F30x
- .chip_id = STLINK_CHIPID_STM32_F3_SMALL,
- .description = "F3xx small",
- .flash_type = STLINK_FLASH_TYPE_F0,
- .flash_size_reg = 0x1ffff7cc,
- .flash_pagesize = 0x800,
- .sram_size = 0xa000,
- .bootrom_base = 0x1fffd800,
- .bootrom_size = 0x2000,
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- // STM32L0x
- // RM0367,RM0377 documents was used to find these parameters
- .chip_id = STLINK_CHIPID_STM32_L0,
- .description = "L0x3",
- .flash_type = STLINK_FLASH_TYPE_L0,
- .flash_size_reg = 0x1ff8007c,
- .flash_pagesize = 0x80,
- .sram_size = 0x2000,
- .bootrom_base = 0x1ff0000,
- .bootrom_size = 0x1000,
- .option_base = STM32_L0_OPTION_BYTES_BASE,
- .option_size = 20,
- },
- {
- // STM32L0x Category 5
- // RM0367,RM0377 documents was used to find these parameters
- .chip_id = STLINK_CHIPID_STM32_L0_CAT5,
- .description = "L0xx Category 5",
- .flash_type = STLINK_FLASH_TYPE_L0,
- .flash_size_reg = 0x1ff8007c,
- .flash_pagesize = 0x80,
- .sram_size = 0x5000,
- .bootrom_base = 0x1ff0000,
- .bootrom_size = 0x2000,
- .option_base = STM32_L0_OPTION_BYTES_BASE,
- .option_size = 20,
- },
- {
- // STM32L0x Category 2
- // RM0367,RM0377 documents was used to find these parameters
- .chip_id = STLINK_CHIPID_STM32_L0_CAT2,
- .description = "L0xx Category 2",
- .flash_type = STLINK_FLASH_TYPE_L0,
- .flash_size_reg = 0x1ff8007c,
- .flash_pagesize = 0x80,
- .sram_size = 0x2000,
- .bootrom_base = 0x1ff0000,
- .bootrom_size = 0x1000,
- .option_base = STM32_L0_OPTION_BYTES_BASE,
- .option_size = 20,
- },
- {
- // STM32F334, STM32F303x6/8, and STM32F328
- // From RM0364 and RM0316
- .chip_id = STLINK_CHIPID_STM32_F334,
- .description = "F334 medium density", // (RM0316 sec 33.6.1)
- .flash_type = STLINK_FLASH_TYPE_F0,
- .flash_size_reg = 0x1ffff7cc,
- .flash_pagesize = 0x800,
- .sram_size = 0x3000,
- .bootrom_base = 0x1fffd800,
- .bootrom_size = 0x2000,
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- // This is STK32F303RET6 device from STM32 F3 Nucelo board.
- // Support based on DM00043574.pdf (RM0316) document rev 5.
- .chip_id = STLINK_CHIPID_STM32_F303_HIGH,
- .description = "F303 high density",
- .flash_type = STLINK_FLASH_TYPE_F0,
- .flash_size_reg = 0x1ffff7cc, // 34.2.1 Flash size data register
- .flash_pagesize = 0x800, // 4.2.1 Flash memory organization
- .sram_size = 0x10000, // 3.3 Embedded SRAM
- .bootrom_base = 0x1fffd800, // 3.3.2 / Table 4 System Memory
- .bootrom_size = 0x2000,
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- // STM32L4x6
- // From RM0351.
- .chip_id = STLINK_CHIPID_STM32_L4,
- .description = "L4xx",
- .flash_type = STLINK_FLASH_TYPE_L4,
- .flash_size_reg =
- 0x1FFF75e0, // "Flash size data register" (sec 45.2, page 1671)
- .flash_pagesize =
- 0x800, // 2k (sec 3.2, page 78; also appears in sec 3.3.1
- // and tables 4-6 on pages 79-81)
- // SRAM1 is "up to" 96k in the standard Cortex-M memory map;
- // SRAM2 is 32k mapped at at 0x10000000 (sec 2.3, page 73 for
- // sizes; table 2, page 74 for SRAM2 location)
- .sram_size = 0x18000,
- .bootrom_base =
- 0x1fff0000, // Tables 4-6, pages 80-81 (Bank 1 system memory)
- .bootrom_size = 0x7000, // 28k (per bank), same source as base
- .option_base = STM32_L4_OPTION_BYTES_BASE,
- .option_size = 4,
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- // STM32L4RX
- // From DM00310109.pdf
- .chip_id = STLINK_CHIPID_STM32_L4RX,
- .description = "L4Rx",
- .flash_type = STLINK_FLASH_TYPE_L4,
- .flash_size_reg =
- 0x1fff75e0, // "Flash size data register" (sec 52.2, page 2049)
- .flash_pagesize = 0x1000, // 4k, section 3.3, pg 97
- .sram_size =
- 0xa0000, // 192k (SRAM1) + 64k SRAM2 + 384k SRAM3 = 640k, or 0xA0000
- .bootrom_base = 0x1fff0000, // 3.3.1, pg 99
- .bootrom_size = 0x7000, // 28k (per bank), same source as base (pg 99)
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- // STLINK_CHIPID_STM32_L41X
- // From RM0394 Rev 4 and DS12469 Rev 5
- .chip_id = STLINK_CHIPID_STM32_L41X,
- .description = "L41x",
- .flash_type = STLINK_FLASH_TYPE_L4,
- .flash_size_reg = 0x1fff75e0, // "Flash size data register" (RM0394,
- // sec 47.2, page 1586)
- .flash_pagesize = 0x800, // 2k (DS12469, sec 3.4, page 17)
- // SRAM1 is 32k at 0x20000000
- // SRAM2 is 8k at 0x10000000 and 0x20008000
- // (DS12469, sec 3.5, page 18)
- .sram_size = 0xa000, // 40k (DS12469, sec 3.5, page 18)
- .bootrom_base =
- 0x1fff0000, // System Memory (RM0394, sec 3.3.1, table 8)
- .bootrom_size = 0x7000, // 28k, same source as base
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- // STLINK_CHIPID_STM32_L43X
- // From RM0392.
- .chip_id = STLINK_CHIPID_STM32_L43X,
- .description = "L43x/L44x",
- .flash_type = STLINK_FLASH_TYPE_L4,
- .flash_size_reg =
- 0x1fff75e0, // "Flash size data register" (sec 43.2, page 1410)
- .flash_pagesize =
- 0x800, // 2k (sec 3.2, page 74; also appears in sec 3.3.1
- // and tables 7-8 on pages 75-76)
- // SRAM1 is "up to" 64k in the standard Cortex-M memory map;
- // SRAM2 is 16k mapped at 0x10000000 (sec 2.3, page 73 for
- // sizes; table 2, page 74 for SRAM2 location)
- .sram_size = 0xc000,
- .bootrom_base =
- 0x1fff0000, // Tables 4-6, pages 80-81 (Bank 1 system memory)
- .bootrom_size = 0x7000, // 28k (per bank), same source as base
- .option_base = STM32_L4_OPTION_BYTES_BASE,
- .option_size = 4,
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- // STLINK_CHIPID_STM32_L496X
- // Support based on en.DM00083560.pdf (RM0351) document rev 5.
- .chip_id = STLINK_CHIPID_STM32_L496X,
- .description = "L496x/L4A6x",
- .flash_type = STLINK_FLASH_TYPE_L4,
- .flash_size_reg =
- 0x1fff75e0, // "Flash size data register" (sec 49.2, page 1809)
- .flash_pagesize =
- 0x800, // Page erase (2 Kbyte) (sec 3.2, page 93)
- // SRAM1 is 256k at 0x20000000
- // SRAM2 is 64k at 0x20040000 (sec 2.2.1, fig 2, page 74)
- .sram_size = 0x40000, // Embedded SRAM (sec 2.4, page 84)
- .bootrom_base = 0x1fff0000, // System Memory (Bank 1) (sec 3.3.1)
- .bootrom_size = 0x7000, // 28k (per bank), same source as base
- .option_base = STM32_L4_OPTION_BYTES_BASE,
- .option_size = 4,
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- // STLINK_CHIPID_STM32_L46X
- // From RM0394 (updated version of RM0392?).
- .chip_id = STLINK_CHIPID_STM32_L46X,
- .description = "L45x/46x",
- .flash_type = STLINK_FLASH_TYPE_L4,
- .flash_size_reg =
- 0x1fff75e0, // "Flash size data register" (sec 45.2, page 1463)
- .flash_pagesize =
- 0x800, // 2k (sec 3.2, page 73; also appears in sec 3.3.1
- // and tables 7 on pages 73-74)
- // SRAM1 is 128k at 0x20000000;
- // SRAM2 is 32k mapped at 0x10000000 (sec 2.4.2, table 3-4,
- // page 68, also fig 2 on page 63)
- .sram_size = 0x20000,
- .bootrom_base = 0x1fff0000, // Tables 6, pages 71-72 (Bank 1 system
- // memory, also fig 2 on page 63)
- .bootrom_size = 0x7000, // 28k (per bank), same source as base
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- // STM32L011
- .chip_id = STLINK_CHIPID_STM32_L011,
- .description = "L011",
- .flash_type = STLINK_FLASH_TYPE_L0,
- .flash_size_reg = 0x1ff8007c,
- .flash_pagesize = 0x80,
- .sram_size = 0x2000,
- .bootrom_base = 0x1ff00000,
- .bootrom_size = 0x2000,
- },
- {
- // STM32G030/031/041 (from RM0454 & RM0444)
- .chip_id = STLINK_CHIPID_STM32_G0_CAT1,
- .description = "G030/G031/G041",
- .flash_type = STLINK_FLASH_TYPE_G0,
- .flash_size_reg = 0x1FFF75E0, // Section 38.2
- .flash_pagesize = 0x800, // 2k (sec 3.2)
- .sram_size = 0x2000, // 8k (sec 2.3)
- .bootrom_base = 0x1fff0000,
- .bootrom_size = 0x2000, // 8k (sec 2.2.2 table 3)
- .option_base = STM32_G0_OPTION_BYTES_BASE,
- .option_size = 4,
- },
- {
- // STM32G071/081 (from RM0444)
- .chip_id = STLINK_CHIPID_STM32_G0_CAT2,
- .description = "G070/G071/G081",
- .flash_type = STLINK_FLASH_TYPE_G0,
- .flash_size_reg = 0x1FFF75E0, // Section 38.2
- .flash_pagesize = 0x800, // 2k (sec 3.2)
- .sram_size = 0x9000, // 36k (sec 2.3)
- .bootrom_base = 0x1fff0000,
- .bootrom_size = 0x7000, // 28k (sec 2.2.2 table 2)
- .option_base = STM32_G0_OPTION_BYTES_BASE,
- .option_size = 4,
- },
- {
- // STM32G431/441 (from RM0440)
- .chip_id = STLINK_CHIPID_STM32_G4_CAT2,
- .description = "G4 Category-2",
- .flash_type = STLINK_FLASH_TYPE_G4,
- .flash_size_reg = 0x1FFF75E0, // Section 47.2
- .flash_pagesize =
- 0x800, // 2k (sec 3.3.1)
- // SRAM1 is 16k at 0x20000000
- // SRAM2 is 6k at 0x20014000
- // SRAM3/CCM is 10k at 0x10000000, aliased at 0x20018000
- .sram_size = 0x8000, // 32k (sec 2.4)
- .bootrom_base = 0x1fff0000,
- .bootrom_size = 0x7000, // 28k (table 2)
- .option_base = STM32_G4_OPTION_BYTES_BASE,
- .option_size = 4,
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- // STM32G471/473/474/483/484 (from RM0440)
- .chip_id = STLINK_CHIPID_STM32_G4_CAT3,
- .description = "G4 Category-3",
- .flash_type = STLINK_FLASH_TYPE_G4,
- .flash_size_reg = 0x1FFF75E0, // Section 47.2
- .flash_pagesize =
- 0x800, // 2k (sec 3.3.1)
- // SRAM1 is 80k at 0x20000000
- // SRAM2 is 16k at 0x20014000
- // SRAM3/CCM is 32k at 0x10000000, aliased at 0x20018000
- .sram_size = 0x18000, // 128k (sec 2.4)
- .bootrom_base = 0x1fff0000,
- .bootrom_size = 0x7000, // 28k (table 2)
- .option_base = STM32_G4_OPTION_BYTES_BASE,
- .option_size = 4,
- .flags = CHIP_F_HAS_DUAL_BANK | CHIP_F_HAS_SWO_TRACING,
- },
- {
- // STM32WB55 (from RM0434)
- .chip_id = STLINK_CHIPID_STM32_WB55,
- .description = "WB55",
- .flash_type = STLINK_FLASH_TYPE_WB,
- .flash_size_reg = 0x1FFF75E0,
- .flash_pagesize = 0x1000, // 4k
- .sram_size = 0x40000,
- .bootrom_base = 0x1fff0000, // see the memory map
- .bootrom_size = 0x7000,
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
- {
- // STM32H742/743/753 (from RM0433)
- .chip_id = STLINK_CHIPID_STM32_H74XXX,
- .description = "H74x/H75x",
- .flash_type = STLINK_FLASH_TYPE_H7,
- .flash_size_reg = 0x1ff1e880, // "Flash size register" (pg3272)
- .flash_pagesize = 0x20000, // 128k sector (pg147)
- .sram_size = 0x20000, // 128k "DTCM" from Table 7
- .bootrom_base =
- 0x1ff00000, // "System memory" starting address from Table 7
- .bootrom_size =
- 0x20000, // "System memory" byte size in hex from Table 7
- .option_base = STM32_H7_OPTION_BYTES_BASE,
- .option_size = 44, // FLASH_OPTSR_CUR to FLASH_BOOT_PRGR from Table 28
- .flags = CHIP_F_HAS_DUAL_BANK | CHIP_F_HAS_SWO_TRACING,
- },
- {
- // STM32H7A3/7B3 (from RM0455)
- .chip_id = STLINK_CHIPID_STM32_H7AX,
- .description = "H7Ax/H7Bx",
- .flash_type = STLINK_FLASH_TYPE_H7,
- .flash_size_reg = 0x08FFF80C, // "Flash size register" (p.2949)
- .flash_pagesize = 0x2000, // 8k sector (p.146)
- .sram_size = 0x20000, // 128k "DTCM" (Figure 1)
- .bootrom_base =
- 0x1FF00000, // "System memory" starting address (Table 12-14)
- .bootrom_size = 0x20000, // "System memory" byte size in hex splitted to
- // two banks (Table 12-14)
- .option_base = STM32_H7_OPTION_BYTES_BASE,
- .option_size = 44,
- .flags = CHIP_F_HAS_DUAL_BANK | CHIP_F_HAS_SWO_TRACING,
- },
- {
- // STM32H72x/H73x (from RM0468)
- .chip_id = STLINK_CHIPID_STM32_H72X,
- .description = "H72x/H73x",
- .flash_type = STLINK_FLASH_TYPE_H7,
- .flash_size_reg = 0x1FF1E880, // "Flash size register" (p.3286)
- .flash_pagesize = 0x20000, // 128k sector (p.152)
- .sram_size = 0x20000, // 128k "DTCM" (Figure 1)
- .bootrom_base =
- 0x1FF00000, // "System memory" starting address (Table 6)
- .bootrom_size = 0x20000, // "System memory" byte size in hex (Table 6)
- .option_base = STM32_H7_OPTION_BYTES_BASE,
- .option_size = 44,
- .flags = CHIP_F_HAS_SWO_TRACING,
- },
-
- {
- // unknown
- .chip_id = STLINK_CHIPID_UNKNOWN,
- .description = "unknown device",
- .flash_type = STLINK_FLASH_TYPE_UNKNOWN,
- .flash_size_reg = 0x0,
- .flash_pagesize = 0x0,
- .sram_size = 0x0,
- .bootrom_base = 0x0,
- .bootrom_size = 0x0,
- },
-};
-
-const struct stlink_chipid_params *stlink_chipid_get_params(uint32_t chipid) {
- const struct stlink_chipid_params *params = NULL;
-
- for (size_t n = 0; n < STLINK_ARRAY_SIZE(devices); n++)
- if (devices[n].chip_id == chipid) {
- params = &devices[n];
+#include "logging.h"
+
+// #include <ctype.h> // TODO: Check use
+// #include <errno.h> // TODO: Check use
+
+static struct stlink_chipid_params *devicelist;
+
+void dump_a_chip(struct stlink_chipid_params *dev) {
+ DLOG("# Device Type: %s\n", dev->dev_type);
+ DLOG("# Reference Manual: RM%s\n", dev->ref_manual_id);
+ DLOG("#\n");
+ DLOG("chip_id 0x%x\n", dev->chip_id);
+ DLOG("flash_type %d\n", dev->flash_type);
+ DLOG("flash_size_reg 0x%x\n", dev->flash_size_reg);
+ DLOG("flash_pagesize 0x%x\n", dev->flash_pagesize);
+ DLOG("sram_size 0x%x\n", dev->sram_size);
+ DLOG("bootrom_base 0x%x\n", dev->bootrom_base);
+ DLOG("bootrom_size 0x%x\n", dev->bootrom_size);
+ DLOG("option_base 0x%x\n", dev->option_base);
+ DLOG("option_size 0x%x\n", dev->option_size);
+ DLOG("flags %d\n\n", dev->flags);
+ DLOG("otp_base %d\n\n", dev->otp_base);
+ DLOG("otp_size %d\n\n", dev->otp_size);
+}
+
+struct stlink_chipid_params *stlink_chipid_get_params(uint32_t chip_id) {
+ struct stlink_chipid_params *params = NULL;
+ for (params = devicelist; params != NULL; params = params->next)
+ if (params->chip_id == chip_id) {
+ DLOG("detected chip_id parameters\n\n");
+ dump_a_chip(params);
break;
}
return (params);
}
+
+void process_chipfile(char *fname) {
+ FILE *fp;
+ char *p, buf[256];
+ char word[64], value[64];
+ struct stlink_chipid_params *ts;
+ int32_t nc;
+
+ // fprintf (stderr, "processing chip-id file %s.\n", fname);
+ fp = fopen(fname, "r");
+
+ if (!fp) {
+ perror(fname);
+ return;
+ }
+
+ ts = calloc(sizeof(struct stlink_chipid_params), 1);
+
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+
+ if (strncmp(buf, "#", strlen("#")) == 0)
+ continue; // ignore comments
+
+ if ((strncmp(buf, "\n", strlen("\n")) == 0) ||
+ (strncmp(buf, " ", strlen(" ")) == 0))
+ continue; // ignore empty lines
+
+ if (sscanf(buf, "%63s %63s", word, value) != 2) {
+ fprintf(stderr, "Failed to read keyword or value\n");
+ continue;
+ }
+
+ if (strcmp(word, "dev_type") == 0) {
+ buf[strlen(buf) - 1] = 0; // chomp newline
+ sscanf(buf, "%*s %n", &nc);
+ ts->dev_type = strdup(buf + nc);
+ } else if (strcmp(word, "ref_manual_id") == 0) {
+ buf[strlen(buf) - 1] = 0; // chomp newline
+ sscanf(buf, "%*s %n", &nc);
+ ts->ref_manual_id = strdup(buf + nc);
+ } else if (strcmp(word, "chip_id") == 0) {
+ buf[strlen(buf) - 1] = 0; // chomp newline
+ sscanf(buf, "%*s %n", &nc);
+ if (sscanf(value, "%i", &ts->chip_id) < 1) {
+ fprintf(stderr, "Failed to parse chip-id\n");
+ }
+ } else if (strcmp(word, "flash_type") == 0) {
+ buf[strlen(buf) - 1] = 0; // chomp newline
+ sscanf(buf, "%*s %n", &nc);
+ // Match human readable flash_type with enum stm32_flash_type { }.
+ if(strcmp(value, "C0") == 0) {
+ ts->flash_type = STM32_FLASH_TYPE_C0;
+ } else if (strcmp(value, "F0_F1_F3") == 0) {
+ ts->flash_type = STM32_FLASH_TYPE_F0_F1_F3;
+ } else if (strcmp(value, "F1_XL") == 0) {
+ ts->flash_type = STM32_FLASH_TYPE_F1_XL;
+ } else if (strcmp(value, "F2_F4") == 0) {
+ ts->flash_type = STM32_FLASH_TYPE_F2_F4;
+ } else if (strcmp(value, "F7") == 0) {
+ ts->flash_type = STM32_FLASH_TYPE_F7;
+ } else if (strcmp(value, "G0") == 0) {
+ ts->flash_type = STM32_FLASH_TYPE_G0;
+ } else if (strcmp(value, "G4") == 0) {
+ ts->flash_type = STM32_FLASH_TYPE_G4;
+ } else if (strcmp(value, "H7") == 0) {
+ ts->flash_type = STM32_FLASH_TYPE_H7;
+ } else if (strcmp(value, "L0_L1") == 0) {
+ ts->flash_type = STM32_FLASH_TYPE_L0_L1;
+ } else if (strcmp(value, "L4") == 0) {
+ ts->flash_type = STM32_FLASH_TYPE_L4;
+ } else if (strcmp(value, "L5_U5_H5") == 0) {
+ ts->flash_type = STM32_FLASH_TYPE_L5_U5_H5;
+ } else if (strcmp(value, "WB_WL") == 0) {
+ ts->flash_type = STM32_FLASH_TYPE_WB_WL;
+ } else {
+ ts->flash_type = STM32_FLASH_TYPE_UNKNOWN;
+ }
+ } else if (strcmp(word, "flash_size_reg") == 0) {
+ buf[strlen(buf) - 1] = 0; // chomp newline
+ sscanf(buf, "%*s %n", &nc);
+ if (sscanf(value, "%i", &ts->flash_size_reg) < 1) {
+ fprintf(stderr, "Failed to parse flash size reg\n");
+ }
+ } else if (strcmp(word, "flash_pagesize") == 0) {
+ buf[strlen(buf) - 1] = 0; // chomp newline
+ sscanf(buf, "%*s %n", &nc);
+ if (sscanf(value, "%i", &ts->flash_pagesize) < 1) {
+ fprintf(stderr, "Failed to parse flash page size\n");
+ }
+ } else if (strcmp(word, "sram_size") == 0) {
+ buf[strlen(buf) - 1] = 0; // chomp newline
+ sscanf(buf, "%*s %n", &nc);
+ if (sscanf(value, "%i", &ts->sram_size) < 1) {
+ fprintf(stderr, "Failed to parse SRAM size\n");
+ }
+ } else if (strcmp(word, "bootrom_base") == 0) {
+ buf[strlen(buf) - 1] = 0; // chomp newline
+ sscanf(buf, "%*s %n", &nc);
+ if (sscanf(value, "%i", &ts->bootrom_base) < 1) {
+ fprintf(stderr, "Failed to parse BootROM base\n");
+ }
+ } else if (strcmp(word, "bootrom_size") == 0) {
+ buf[strlen(buf) - 1] = 0; // chomp newline
+ sscanf(buf, "%*s %n", &nc);
+ if (sscanf(value, "%i", &ts->bootrom_size) < 1) {
+ fprintf(stderr, "Failed to parse BootROM size\n");
+ }
+ } else if (strcmp(word, "option_base") == 0) {
+ buf[strlen(buf) - 1] = 0; // chomp newline
+ sscanf(buf, "%*s %n", &nc);
+ if (sscanf(value, "%i", &ts->option_base) < 1) {
+ fprintf(stderr, "Failed to parse option base\n");
+ }
+ } else if (strcmp(word, "option_size") == 0) {
+ buf[strlen(buf) - 1] = 0; // chomp newline
+ sscanf(buf, "%*s %n", &nc);
+ if (sscanf(value, "%i", &ts->option_size) < 1) {
+ fprintf(stderr, "Failed to parse option size\n");
+ }
+ } else if (strcmp(word, "flags") == 0) {
+ buf[strlen(buf) - 1] = 0; // chomp newline
+ sscanf(buf, "%*s %n", &nc);
+ p = strtok(buf, " \t\n");
+
+ while ((p = strtok(NULL, " \t\n"))) {
+ if (strcmp(p, "none") == 0) {
+ // NOP
+ } else if (strcmp(p, "dualbank") == 0) {
+ ts->flags |= CHIP_F_HAS_DUAL_BANK;
+ } else if (strcmp(p, "swo") == 0) {
+ ts->flags |= CHIP_F_HAS_SWO_TRACING;
+ } else {
+ fprintf(stderr, "Unknown flags word in %s: '%s'\n", fname, p);
+ }
+ }
+
+ sscanf(value, "%x", &ts->flags);
+ } else if (strcmp(word, "otp_base") == 0) {
+ buf[strlen(buf) - 1] = 0; // chomp newline
+ sscanf(buf, "%*s %n", &nc);
+ if (sscanf(value, "%i", &ts->otp_base) < 1) {
+ fprintf(stderr, "Failed to parse option size\n");
+ }
+ } else if (strcmp(word, "otp_size") == 0) {
+ buf[strlen(buf) - 1] = 0; // chomp newline
+ sscanf(buf, "%*s %n", &nc);
+ if (sscanf(value, "%i", &ts->otp_size) < 1) {
+ fprintf(stderr, "Failed to parse option size\n");
+ }
+ } else {
+ fprintf(stderr, "Unknown keyword in %s: %s\n", fname, word);
+ }
+ }
+ fclose(fp);
+ ts->next = devicelist;
+ devicelist = ts;
+}
+
+#if defined(STLINK_HAVE_DIRENT_H)
+#include <dirent.h>
+
+void init_chipids(char *dir_to_scan) {
+ DIR *d;
+ uint32_t nl; // namelen
+ struct dirent *dir;
+
+ if (!dir_to_scan) {
+ dir_to_scan = "./";
+ }
+
+ devicelist = NULL;
+ d = opendir(dir_to_scan);
+
+ if (d) {
+ while ((dir = readdir(d)) != NULL) {
+ nl = strlen(dir->d_name);
+
+ if (strcmp(dir->d_name + nl - 5, ".chip") == 0) {
+ char buf[1024];
+ sprintf(buf, "%s/%s", dir_to_scan, dir->d_name);
+ process_chipfile(buf);
+ }
+ }
+
+ closedir(d);
+ } else {
+ perror(dir_to_scan);
+ return;
+ }
+}
+
+#endif // STLINK_HAVE_DIRENT_H
+
+#if defined(_WIN32) && !defined(STLINK_HAVE_DIRENT_H)
+#include <fileapi.h>
+#include <strsafe.h>
+
+void init_chipids(char *dir_to_scan) {
+ HANDLE hFind = INVALID_HANDLE_VALUE;
+ WIN32_FIND_DATAA ffd;
+ char filepath[MAX_PATH] = {0};
+ StringCchCopyA(filepath, STLINK_ARRAY_SIZE(filepath), dir_to_scan);
+
+ if (FAILED(
+ StringCchCatA(filepath, STLINK_ARRAY_SIZE(filepath), "\\*.chip"))) {
+ ELOG("Path to chips's dir too long.\n");
+ return;
+ }
+
+ hFind = FindFirstFileA(filepath, &ffd);
+
+ if (INVALID_HANDLE_VALUE == hFind) {
+ ELOG("Can't find any chip description file in %s.\n", filepath);
+ return;
+ }
+
+ do {
+ memset(filepath, 0, STLINK_ARRAY_SIZE(filepath));
+ StringCchCopyA(filepath, STLINK_ARRAY_SIZE(filepath), dir_to_scan);
+ StringCchCatA(filepath, STLINK_ARRAY_SIZE(filepath), "\\");
+ StringCchCatA(filepath, STLINK_ARRAY_SIZE(filepath), ffd.cFileName);
+ process_chipfile(filepath);
+ } while (FindNextFileA(hFind, &ffd) != 0);
+
+ FindClose(hFind);
+}
+
+#endif // defined(_WIN32) && !defined(STLINK_HAVE_DIRENT_H)
diff --git a/src/stlink-lib/chipid.h b/src/stlink-lib/chipid.h
index f790e78..cf97e66 100644
--- a/src/stlink-lib/chipid.h
+++ b/src/stlink-lib/chipid.h
@@ -1,84 +1,18 @@
-#ifndef STLINK_CHIPID_H_
-#define STLINK_CHIPID_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * Chip IDs are explained in the appropriate programming manual for the
- * DBGMCU_IDCODE register (0xE0042000)
- * stm32 chipids, only lower 12 bits...
+/*
+ * File: chipid.h
+ *
+ * Chip-ID parametres
*/
-enum stlink_stm32_chipids {
- STLINK_CHIPID_UNKNOWN = 0x000,
-
- STLINK_CHIPID_STM32_F1_MEDIUM = 0x410,
- STLINK_CHIPID_STM32_F2 = 0x411,
- STLINK_CHIPID_STM32_F1_LOW = 0x412,
- STLINK_CHIPID_STM32_F4 = 0x413,
- STLINK_CHIPID_STM32_F1_HIGH = 0x414,
- STLINK_CHIPID_STM32_L4 = 0x415,
- STLINK_CHIPID_STM32_L1_MEDIUM = 0x416,
- STLINK_CHIPID_STM32_L0 = 0x417,
- STLINK_CHIPID_STM32_F1_CONN = 0x418,
- STLINK_CHIPID_STM32_F4_HD = 0x419,
- STLINK_CHIPID_STM32_F1_VL_MEDIUM_LOW = 0x420,
- STLINK_CHIPID_STM32_F446 = 0x421,
- STLINK_CHIPID_STM32_F3 = 0x422,
- STLINK_CHIPID_STM32_F4_LP = 0x423,
- STLINK_CHIPID_STM32_L0_CAT2 = 0x425,
- STLINK_CHIPID_STM32_L1_MEDIUM_PLUS = 0x427, /* assigned to some L1 "Medium-plus" chips */
- STLINK_CHIPID_STM32_F1_VL_HIGH = 0x428,
- STLINK_CHIPID_STM32_L1_CAT2 = 0x429,
- STLINK_CHIPID_STM32_F1_XL = 0x430,
- STLINK_CHIPID_STM32_F411RE = 0x431,
- STLINK_CHIPID_STM32_F37x = 0x432,
- STLINK_CHIPID_STM32_F4_DE = 0x433,
- STLINK_CHIPID_STM32_F4_DSI = 0x434,
- STLINK_CHIPID_STM32_L43X = 0x435, /* covers STM32L43xxx and STM32L44xxx devices */
- STLINK_CHIPID_STM32_L496X = 0x461, /* covers STM32L496xx and STM32L4A6xx devices */
- STLINK_CHIPID_STM32_L46X = 0x462, /* covers STM32L45xxx and STM32L46xxx devices */
- STLINK_CHIPID_STM32_L41X = 0x464, /* covers STM32L41xxx and STM32L42xxx devices */
- STLINK_CHIPID_STM32_L1_HIGH = 0x436, /* assigned to some L1 "Medium-Plus" and "High" chips */
- STLINK_CHIPID_STM32_L152_RE = 0x437,
- STLINK_CHIPID_STM32_F334 = 0x438,
- STLINK_CHIPID_STM32_F3_SMALL = 0x439,
- STLINK_CHIPID_STM32_F0 = 0x440,
- STLINK_CHIPID_STM32_F412 = 0x441,
- STLINK_CHIPID_STM32_F09X = 0x442,
- STLINK_CHIPID_STM32_F0_SMALL = 0x444,
- STLINK_CHIPID_STM32_F04 = 0x445,
- STLINK_CHIPID_STM32_F303_HIGH = 0x446,
- STLINK_CHIPID_STM32_L0_CAT5 = 0x447,
- STLINK_CHIPID_STM32_F0_CAN = 0x448,
- STLINK_CHIPID_STM32_F7 = 0x449, /* ID found on the NucleoF746ZG board */
- STLINK_CHIPID_STM32_H74XXX = 0x450, /* Found on page 3189 in the RM0433*/
- STLINK_CHIPID_STM32_F7XXXX = 0x451,
- STLINK_CHIPID_STM32_F72XXX = 0x452, /* ID found on the NucleoF722ZE board */
- STLINK_CHIPID_STM32_L011 = 0x457,
- STLINK_CHIPID_STM32_F410 = 0x458,
- STLINK_CHIPID_STM32_G0_CAT2 = 0x460, /* G070/G071/081 */
- STLINK_CHIPID_STM32_F413 = 0x463,
- STLINK_CHIPID_STM32_G0_CAT1 = 0x466, /* G030/G031/041 */
- STLINK_CHIPID_STM32_G4_CAT2 = 0x468, /* See: RM 0440 s46.6.1 "MCU device ID code" */
- STLINK_CHIPID_STM32_G4_CAT3 = 0x469,
- STLINK_CHIPID_STM32_L4RX = 0x470, /* ID found on the STM32L4R9I-DISCO board */
- STLINK_CHIPID_STM32_H7AX = 0x480, /* RM0455, p. 2863 */
- STLINK_CHIPID_STM32_H72X = 0x483, /* RM0468, p. 3199 */
- STLINK_CHIPID_STM32_WB55 = 0x495
-};
-
-
-#define CHIP_F_HAS_DUAL_BANK (1 << 0)
-#define CHIP_F_HAS_SWO_TRACING (1 << 1)
+#ifndef CHIPID_H
+#define CHIPID_H
-/** Chipid parameters */
+/* Chipid parametres */
struct stlink_chipid_params {
+ char *dev_type;
+ char *ref_manual_id;
uint32_t chip_id;
- char *description;
- enum stlink_flash_type flash_type;
+ enum stm32_flash_type flash_type;
uint32_t flash_size_reg;
uint32_t flash_pagesize;
uint32_t sram_size;
@@ -87,12 +21,15 @@ struct stlink_chipid_params {
uint32_t option_base;
uint32_t option_size;
uint32_t flags;
+ uint32_t otp_base;
+ uint32_t otp_size;
+ struct stlink_chipid_params *next;
};
-const struct stlink_chipid_params *stlink_chipid_get_params(uint32_t chipid);
+struct stlink_chipid_params *stlink_chipid_get_params(uint32_t chipid);
-#ifdef __cplusplus
-}
-#endif
+void dump_a_chip(struct stlink_chipid_params *dev);
+void process_chipfile(char *fname);
+void init_chipids(char *dir_to_scan);
-#endif // STLINK_CHIPID_H_
+#endif // CHIPID_H
diff --git a/src/stlink-lib/commands.h b/src/stlink-lib/commands.h
index dac82b8..64cecce 100644
--- a/src/stlink-lib/commands.h
+++ b/src/stlink-lib/commands.h
@@ -1,8 +1,23 @@
-#ifndef STLINK_COMMANDS_H_
-#define STLINK_COMMANDS_H_
+/*
+ * File: commands.h
+ *
+ * stlink commands
+ */
+
+#ifndef COMMANDS_H
+#define COMMANDS_H
+
+enum stlink_commands {
+ STLINK_GET_VERSION = 0xF1,
+ STLINK_DEBUG_COMMAND = 0xF2,
+ STLINK_DFU_COMMAND = 0xF3,
+ STLINK_GET_CURRENT_MODE = 0xF5,
+ STLINK_GET_TARGET_VOLTAGE = 0xF7,
+ STLINK_GET_VERSION_APIV3 = 0xFB
+};
enum stlink_debug_commands {
- STLINK_DEBUG_ENTER_JTAG = 0x00,
+ STLINK_DEBUG_ENTER_JTAG_RESET = 0x00,
STLINK_DEBUG_GETSTATUS = 0x01,
STLINK_DEBUG_FORCEDEBUG = 0x02,
STLINK_DEBUG_APIV1_RESETSYS = 0x03,
@@ -29,11 +44,20 @@ enum stlink_debug_commands {
STLINK_DEBUG_APIV2_READDEBUGREG = 0x36,
STLINK_DEBUG_APIV2_READALLREGS = 0x3A,
STLINK_DEBUG_APIV2_GETLASTRWSTATUS = 0x3B,
+ STLINK_DEBUG_APIV2_DRIVE_NRST = 0x3C,
STLINK_DEBUG_APIV2_GETLASTRWSTATUS2 = 0x3E,
STLINK_DEBUG_APIV2_START_TRACE_RX = 0x40,
STLINK_DEBUG_APIV2_STOP_TRACE_RX = 0x41,
STLINK_DEBUG_APIV2_GET_TRACE_NB = 0x42,
- STLINK_DEBUG_ENTER_SWD = 0xa3
+ STLINK_DEBUG_APIV2_SWD_SET_FREQ = 0x43,
+ STLINK_DEBUG_APIV3_SET_COM_FREQ = 0x61,
+ STLINK_DEBUG_APIV3_GET_COM_FREQ = 0x62,
+ STLINK_DEBUG_ENTER_SWD = 0xa3,
+ STLINK_DEBUG_ENTER_JTAG_NO_RESET = 0xa4,
+};
+
+enum stlink_dfu_commands {
+ STLINK_DFU_EXIT = 0x07
};
-#endif // STLINK_COMMANDS_H_
+#endif // COMMANDS_H
diff --git a/src/stlink-lib/common.c b/src/stlink-lib/common.c
new file mode 100644
index 0000000..3e49a77
--- /dev/null
+++ b/src/stlink-lib/common.c
@@ -0,0 +1,1372 @@
+/* == nightwalker-87: TODO: CONTENT AND USE OF THIS SOURCE FILE IS TO BE VERIFIED (07.06.2023) == */
+/* TODO: This file should be split up into new or existing modules. */
+
+/*
+ * File: common.c
+ *
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+// #include <sys/stat.h> // TODO: Check use
+// #include <sys/types.h> // TODO: Check use
+
+#include <stlink.h>
+
+#include "calculate.h"
+#include "chipid.h"
+#include "common_flash.h"
+#include "helper.h"
+#include "logging.h"
+#include "map_file.h"
+#include "md5.h"
+#include "read_write.h"
+#include "register.h"
+#include "usb.h"
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#ifdef _MSC_VER
+#define __attribute__(x)
+#endif
+
+// Private structs and functions defines
+struct stlink_fread_worker_arg {
+ int32_t fd;
+};
+
+struct stlink_fread_ihex_worker_arg {
+ FILE *file;
+ uint32_t addr;
+ uint32_t lba;
+ uint8_t buf[16];
+ uint8_t buf_pos;
+};
+
+typedef bool (*save_block_fn)(void *arg, uint8_t *block, ssize_t len);
+
+static void stop_wdg_in_debug(stlink_t *);
+int32_t stlink_jtag_reset(stlink_t *, int32_t);
+int32_t stlink_soft_reset(stlink_t *, int32_t);
+void _parse_version(stlink_t *, stlink_version_t *);
+static uint8_t stlink_parse_hex(const char *);
+static int32_t stlink_read(stlink_t *, stm32_addr_t, uint32_t, save_block_fn, void *);
+static bool stlink_fread_ihex_init(struct stlink_fread_ihex_worker_arg *, int32_t, stm32_addr_t);
+static bool stlink_fread_ihex_worker(void *, uint8_t *, ssize_t);
+static bool stlink_fread_ihex_finalize(struct stlink_fread_ihex_worker_arg *);
+static bool stlink_fread_worker(void *, uint8_t *, ssize_t);
+// End of private structs and functions defines
+
+// Functions below are defined in stlink.h (see line num before function)
+// 252
+void stlink_close(stlink_t *sl) {
+ DLOG("*** stlink_close ***\n");
+
+ if (!sl) {
+ return;
+ }
+
+ sl->backend->close(sl);
+ free(sl);
+}
+
+// 250
+int32_t stlink_exit_debug_mode(stlink_t *sl) {
+ DLOG("*** stlink_exit_debug_mode ***\n");
+
+ if (sl->flash_type != STM32_FLASH_TYPE_UNKNOWN &&
+ sl->core_stat != TARGET_RESET) {
+ // stop debugging if the target has been identified
+ stlink_write_debug32(sl, STLINK_REG_DHCSR, STLINK_REG_DHCSR_DBGKEY);
+ }
+
+ return (sl->backend->exit_debug_mode(sl));
+}
+
+//248
+int32_t stlink_enter_swd_mode(stlink_t *sl) {
+ DLOG("*** stlink_enter_swd_mode ***\n");
+ return (sl->backend->enter_swd_mode(sl));
+}
+
+// 271
+// Force the core into the debug mode -> halted state.
+int32_t stlink_force_debug(stlink_t *sl) {
+ DLOG("*** stlink_force_debug_mode ***\n");
+ int32_t res = sl->backend->force_debug(sl);
+ if (res) {
+ return (res);
+ }
+ // Stop the watchdogs in the halted state for suppress target reboot
+ stop_wdg_in_debug(sl);
+ return (0);
+}
+
+// 251
+int32_t stlink_exit_dfu_mode(stlink_t *sl) {
+ DLOG("*** stlink_exit_dfu_mode ***\n");
+ return (sl->backend->exit_dfu_mode(sl));
+}
+
+// 253
+int32_t stlink_core_id(stlink_t *sl) {
+ int32_t ret;
+
+ DLOG("*** stlink_core_id ***\n");
+ ret = sl->backend->core_id(sl);
+
+ if (ret == -1) {
+ ELOG("Failed to read core_id\n");
+ return (ret);
+ }
+
+ if (sl->verbose > 2) {
+ stlink_print_data(sl);
+ }
+
+ DLOG("core_id = 0x%08x\n", sl->core_id);
+ return (ret);
+}
+
+// 287
+// stlink_chip_id() is called by stlink_load_device_params()
+// do not call this procedure directly.
+int32_t stlink_chip_id(stlink_t *sl, uint32_t *chip_id) {
+ int32_t ret;
+ cortex_m3_cpuid_t cpu_id;
+
+ // Read the CPU ID to determine where to read the core id
+ if (stlink_cpu_id(sl, &cpu_id) ||
+ cpu_id.implementer_id != STLINK_REG_CMx_CPUID_IMPL_ARM) {
+ ELOG("Can not connect to target. Please use \'connect under reset\' and try again\n");
+ return -1;
+ }
+
+ /*
+ * the chip_id register in the reference manual have
+ * DBGMCU_IDCODE / DBG_IDCODE name
+ */
+
+ if ((sl->core_id == STM32_CORE_ID_M7F_M33_SWD || sl->core_id == STM32_CORE_ID_M7F_M33_JTAG) &&
+ cpu_id.part == STLINK_REG_CMx_CPUID_PARTNO_CM7) {
+ // STM32H7 chipid in 0x5c001000 (RM0433 pg3189)
+ ret = stlink_read_debug32(sl, 0x5c001000, chip_id);
+ } else if (cpu_id.part == STLINK_REG_CMx_CPUID_PARTNO_CM0 ||
+ cpu_id.part == STLINK_REG_CMx_CPUID_PARTNO_CM0P) {
+ // STM32F0 (RM0091, pg914; RM0360, pg713)
+ // STM32L0 (RM0377, pg813; RM0367, pg915; RM0376, pg917)
+ // STM32G0 (RM0444, pg1367)
+ ret = stlink_read_debug32(sl, 0x40015800, chip_id);
+ } else if (cpu_id.part == STLINK_REG_CMx_CPUID_PARTNO_CM33) {
+ // STM32L5 (RM0438, pg2157)
+ ret = stlink_read_debug32(sl, 0xE0044000, chip_id);
+ } else /* ДM3, ДM4, CM7 */ {
+ // default chipid address
+
+ // STM32F1 (RM0008, pg1087; RM0041, pg681)
+ // STM32F2 (RM0033, pg1326)
+ // STM32F3 (RM0316, pg1095; RM0313, pg874)
+ // STM32F7 (RM0385, pg1676; RM0410, pg1912)
+ // STM32L1 (RM0038, pg861)
+ // STM32L4 (RM0351, pg1840; RM0394, pg1560)
+ // STM32G4 (RM0440, pg2086)
+ // STM32WB (RM0434, pg1406)
+ ret = stlink_read_debug32(sl, 0xE0042000, chip_id);
+ }
+
+ if (ret || !(*chip_id)) {
+ *chip_id = 0;
+ ret = ret?ret:-1;
+ ELOG("Could not find chip id!\n");
+ } else {
+ *chip_id = (*chip_id) & 0xfff;
+
+ // Fix chip_id for F4 rev A errata, read CPU ID, as CoreID is the same for
+ // F2/F4
+ if (*chip_id == 0x411 && cpu_id.part == STLINK_REG_CMx_CPUID_PARTNO_CM4) {
+ *chip_id = 0x413;
+ }
+ }
+
+ return (ret);
+}
+
+// 288
+/**
+ * Cortex M tech ref manual, CPUID register description
+ * @param sl stlink context
+ * @param cpuid pointer to the result object
+ */
+int32_t stlink_cpu_id(stlink_t *sl, cortex_m3_cpuid_t *cpuid) {
+ uint32_t raw;
+
+ if (stlink_read_debug32(sl, STLINK_REG_CM3_CPUID, &raw)) {
+ cpuid->implementer_id = 0;
+ cpuid->variant = 0;
+ cpuid->part = 0;
+ cpuid->revision = 0;
+ return (-1);
+ }
+
+ cpuid->implementer_id = (raw >> 24) & 0x7f;
+ cpuid->variant = (raw >> 20) & 0xf;
+ cpuid->part = (raw >> 4) & 0xfff;
+ cpuid->revision = raw & 0xf;
+ return (0);
+}
+
+// 303
+/**
+ * Reads and decodes the flash parameters, as dynamically as possible
+ * @param sl
+ * @return 0 for success, or -1 for unsupported core type.
+ */
+int32_t stlink_load_device_params(stlink_t *sl) {
+ // This seems to normally work so is unnecessary info for a normal user.
+ // Demoted to debug. -- REW
+ DLOG("Loading device parameters....\n");
+ const struct stlink_chipid_params *params = NULL;
+ stlink_core_id(sl);
+ uint32_t flash_size;
+
+ if (stlink_chip_id(sl, &sl->chip_id)) {
+ return (-1);
+ }
+
+ params = stlink_chipid_get_params(sl->chip_id);
+
+ if (params == NULL) {
+ WLOG("unknown chip id! %#x\n", sl->chip_id);
+ return (-1);
+ }
+
+ if (params->flash_type == STM32_FLASH_TYPE_UNKNOWN) {
+ WLOG("Invalid flash type, please check device declaration\n");
+ sl->flash_size = 0;
+ return (0);
+ }
+
+ // These are fixed...
+ sl->flash_base = STM32_FLASH_BASE;
+ sl->sram_base = STM32_SRAM_BASE;
+ stlink_read_debug32(sl, (params->flash_size_reg) & ~3, &flash_size);
+
+ if (params->flash_size_reg & 2) {
+ flash_size = flash_size >> 16;
+ }
+
+ flash_size = flash_size & 0xffff;
+
+ if ((sl->chip_id == STM32_CHIPID_L1_MD ||
+ sl->chip_id == STM32_CHIPID_F1_VL_MD_LD ||
+ sl->chip_id == STM32_CHIPID_L1_MD_PLUS) &&
+ (flash_size == 0)) {
+ sl->flash_size = 128 * 1024;
+ } else if (sl->chip_id == STM32_CHIPID_L1_CAT2) {
+ sl->flash_size = (flash_size & 0xff) * 1024;
+ } else if ((sl->chip_id & 0xFFF) == STM32_CHIPID_L1_MD_PLUS_HD) {
+ // 0 is 384k and 1 is 256k
+ if (flash_size == 0) {
+ sl->flash_size = 384 * 1024;
+ } else {
+ sl->flash_size = 256 * 1024;
+ }
+ } else {
+ sl->flash_size = flash_size * 1024;
+ }
+
+ sl->flash_type = params->flash_type;
+ sl->flash_pgsz = params->flash_pagesize;
+ sl->sram_size = params->sram_size;
+ sl->sys_base = params->bootrom_base;
+ sl->sys_size = params->bootrom_size;
+ sl->option_base = params->option_base;
+ sl->option_size = params->option_size;
+ sl->chip_flags = params->flags;
+ sl->otp_base = params->otp_base;
+ sl->otp_size = params->otp_size;
+
+ // medium and low devices have the same chipid. ram size depends on flash
+ // size. STM32F100xx datasheet Doc ID 16455 Table 2
+ if (sl->chip_id == STM32_CHIPID_F1_VL_MD_LD && sl->flash_size < 64 * 1024) {
+ sl->sram_size = 0x1000;
+ }
+
+ if (sl->chip_id == STM32_CHIPID_G4_CAT3 ||
+ sl->chip_id == STM32_CHIPID_G4_CAT4) {
+ uint32_t flash_optr;
+ stlink_read_debug32(sl, FLASH_Gx_OPTR, &flash_optr);
+
+ if (!(flash_optr & (1 << FLASH_G4_OPTR_DBANK))) {
+ sl->flash_pgsz <<= 1;
+ }
+ }
+
+ if (sl->chip_id == STM32_CHIPID_L5x2xx) {
+ uint32_t flash_optr;
+ stlink_read_debug32(sl, FLASH_L5_OPTR, &flash_optr);
+
+ if (sl->flash_size == 512*1024 && (flash_optr & (1 << 22)) != 0) {
+ sl->flash_pgsz = 0x800;
+ }
+ }
+
+ // H7 devices with small flash has one bank
+ if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK &&
+ sl->flash_type == STM32_FLASH_TYPE_H7) {
+ if ((sl->flash_size / sl->flash_pgsz) <= 1)
+ sl->chip_flags &= ~CHIP_F_HAS_DUAL_BANK;
+ }
+
+ ILOG("%s: %u KiB SRAM, %u KiB flash in at least %u %s pages.\n",
+ params->dev_type, (sl->sram_size / 1024), (sl->flash_size / 1024),
+ (sl->flash_pgsz < 1024) ? sl->flash_pgsz : (sl->flash_pgsz / 1024),
+ (sl->flash_pgsz < 1024) ? "byte" : "KiB");
+
+ return (0);
+}
+
+// 254
+int32_t stlink_reset(stlink_t *sl, enum reset_type type) {
+ uint32_t dhcsr;
+ uint32_t timeout;
+
+ DLOG("*** stlink_reset ***\n");
+
+ sl->core_stat = TARGET_RESET;
+
+ if (type == RESET_AUTO) {
+ // clear S_RESET_ST in DHCSR register for reset state detection
+ stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr);
+ }
+
+ if (type == RESET_HARD || type == RESET_AUTO) {
+ // hardware target reset
+ if (sl->version.stlink_v > 1) {
+ stlink_jtag_reset(sl, STLINK_DEBUG_APIV2_DRIVE_NRST_LOW);
+ // minimum reset pulse duration of 20 us (RM0008, 8.1.2 Power reset)
+ usleep(100);
+ stlink_jtag_reset(sl, STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH);
+ }
+ sl->backend->reset(sl);
+ usleep(10000);
+ }
+
+ if (type == RESET_AUTO) {
+ /* Check if the S_RESET_ST bit is set in DHCSR
+ * This means that a reset has occurred
+ * DDI0337E, p. 10-4, Debug Halting Control and Status Register
+ */
+
+ dhcsr = 0;
+ int32_t res = stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr);
+ if ((dhcsr & STLINK_REG_DHCSR_S_RESET_ST) == 0 && !res) {
+ // reset not done yet --> try reset through AIRCR so that NRST does not need to be connected
+ ILOG("NRST is not connected --> using software reset via AIRCR\n");
+ DLOG("NRST not connected --> Reset through SYSRESETREQ\n");
+ return stlink_soft_reset(sl, 0);
+ }
+
+ // waiting for reset the S_RESET_ST bit within 500ms
+ timeout = time_ms() + 500;
+ while (time_ms() < timeout) {
+ dhcsr = STLINK_REG_DHCSR_S_RESET_ST;
+ stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr);
+ if ((dhcsr & STLINK_REG_DHCSR_S_RESET_ST) == 0) {
+ return (0);
+ }
+ }
+
+ return (-1);
+ }
+
+ if (type == RESET_SOFT || type == RESET_SOFT_AND_HALT) {
+ return stlink_soft_reset(sl, (type == RESET_SOFT_AND_HALT));
+ }
+
+ return (0);
+}
+
+int32_t stlink_soft_reset(stlink_t *sl, int32_t halt_on_reset) {
+ int32_t ret;
+ uint32_t timeout;
+ uint32_t dhcsr, dfsr;
+
+ DLOG("*** stlink_soft_reset %s***\n", halt_on_reset ? "(halt) " : "");
+
+ // halt core and enable debugging (if not already done)
+ // C_DEBUGEN is required to Halt on reset (DDI0337E, p. 10-6)
+ stlink_write_debug32(sl, STLINK_REG_DHCSR,
+ STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_HALT |
+ STLINK_REG_DHCSR_C_DEBUGEN);
+
+ // enable Halt on reset by set VC_CORERESET and TRCENA (DDI0337E, p. 10-10)
+ if (halt_on_reset) {
+ stlink_write_debug32(
+ sl, STLINK_REG_CM3_DEMCR,
+ STLINK_REG_CM3_DEMCR_TRCENA | STLINK_REG_CM3_DEMCR_VC_HARDERR |
+ STLINK_REG_CM3_DEMCR_VC_BUSERR | STLINK_REG_CM3_DEMCR_VC_CORERESET);
+
+ // clear VCATCH in the DFSR register
+ stlink_write_debug32(sl, STLINK_REG_DFSR, STLINK_REG_DFSR_VCATCH);
+ } else {
+ stlink_write_debug32(sl, STLINK_REG_CM3_DEMCR,
+ STLINK_REG_CM3_DEMCR_TRCENA |
+ STLINK_REG_CM3_DEMCR_VC_HARDERR |
+ STLINK_REG_CM3_DEMCR_VC_BUSERR);
+ }
+
+ // clear S_RESET_ST in the DHCSR register
+ stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr);
+
+ // soft reset (core reset) by SYSRESETREQ (DDI0337E, p. 8-23)
+ ret = stlink_write_debug32(sl, STLINK_REG_AIRCR,
+ STLINK_REG_AIRCR_VECTKEY |
+ STLINK_REG_AIRCR_SYSRESETREQ);
+ if (ret) {
+ ELOG("Soft reset failed: error write to AIRCR\n");
+ return (ret);
+ }
+
+ // waiting for a reset within 500ms
+ // DDI0337E, p. 10-4, Debug Halting Control and Status Register
+ timeout = time_ms() + 500;
+ while (time_ms() < timeout) {
+ // DDI0337E, p. 10-4, Debug Halting Control and Status Register
+ dhcsr = STLINK_REG_DHCSR_S_RESET_ST;
+ stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr);
+ if ((dhcsr & STLINK_REG_DHCSR_S_RESET_ST) == 0) {
+ if (halt_on_reset) {
+ // waiting halt by the SYSRESETREQ exception
+ // DDI0403E, p. C1-699, Debug Fault Status Register
+ dfsr = 0;
+ stlink_read_debug32(sl, STLINK_REG_DFSR, &dfsr);
+ if ((dfsr & STLINK_REG_DFSR_VCATCH) == 0) {
+ continue;
+ }
+ }
+ timeout = 0;
+ break;
+ }
+ }
+
+ // reset DFSR register. DFSR is power-on reset only (DDI0337H, p. 7-5)
+ stlink_write_debug32(sl, STLINK_REG_DFSR, STLINK_REG_DFSR_CLEAR);
+
+ if (timeout) {
+ ELOG("Soft reset failed: timeout\n");
+ return (-1);
+ }
+
+ return (0);
+}
+
+// 255
+int32_t stlink_run(stlink_t *sl, enum run_type type) {
+ struct stlink_reg rr;
+ DLOG("*** stlink_run ***\n");
+
+ /* Make sure we are in Thumb mode
+ * Cortex-M chips don't support ARM mode instructions
+ * xPSR may be incorrect if the vector table has invalid data */
+ stlink_read_reg(sl, 16, &rr);
+ if ((rr.xpsr & (1 << 24)) == 0) {
+ ILOG("Go to Thumb mode\n");
+ stlink_write_reg(sl, rr.xpsr | (1 << 24), 16);
+ }
+
+ return (sl->backend->run(sl, type));
+}
+
+// 273
+int32_t stlink_set_swdclk(stlink_t *sl, int32_t freq_khz) {
+ DLOG("*** set_swdclk ***\n");
+ return (sl->backend->set_swdclk(sl, freq_khz));
+}
+
+// 293
+// this function is called by stlink_status()
+// do not call stlink_core_stat() directly, always use stlink_status()
+void stlink_core_stat(stlink_t *sl) {
+ switch (sl->core_stat) {
+ case TARGET_RUNNING:
+ DLOG(" core status: running\n");
+ return;
+ case TARGET_HALTED:
+ DLOG(" core status: halted\n");
+ return;
+ case TARGET_RESET:
+ DLOG(" core status: reset\n");
+ return;
+ case TARGET_DEBUG_RUNNING:
+ DLOG(" core status: debug running\n");
+ return;
+ default:
+ DLOG(" core status: unknown\n");
+ }
+}
+
+// 256
+int32_t stlink_status(stlink_t *sl) {
+ int32_t ret;
+
+ DLOG("*** stlink_status ***\n");
+ ret = sl->backend->status(sl);
+ stlink_core_stat(sl);
+ return (ret);
+}
+
+// 257
+int32_t stlink_version(stlink_t *sl) {
+ DLOG("*** looking up stlink version ***\n");
+
+ if (sl->backend->version(sl)) {
+ return (-1);
+ }
+
+ _parse_version(sl, &sl->version);
+
+ DLOG("st vid = 0x%04x (expect 0x%04x)\n", sl->version.st_vid,
+ STLINK_USB_VID_ST);
+ DLOG("stlink pid = 0x%04x\n", sl->version.stlink_pid);
+ DLOG("stlink version = 0x%x\n", sl->version.stlink_v);
+ DLOG("jtag version = 0x%x\n", sl->version.jtag_v);
+ DLOG("swim version = 0x%x\n", sl->version.swim_v);
+
+ if (sl->version.jtag_v == 0) {
+ WLOG(" warning: stlink doesn't support JTAG/SWD interface\n");
+ }
+
+ return (0);
+}
+
+// 272
+int32_t stlink_target_voltage(stlink_t *sl) {
+ int32_t voltage = -1;
+ DLOG("*** reading target voltage\n");
+
+ if (sl->backend->target_voltage != NULL) {
+ voltage = sl->backend->target_voltage(sl);
+
+ if (voltage != -1) {
+ DLOG("target voltage = %imV\n", voltage);
+ } else {
+ DLOG("error reading target voltage\n");
+ }
+ } else {
+ DLOG("reading voltage not supported by backend\n");
+ }
+
+ return (voltage);
+}
+
+// 299
+bool stlink_is_core_halted(stlink_t *sl) {
+ stlink_status(sl);
+ return (sl->core_stat == TARGET_HALTED);
+}
+
+// 269
+int32_t stlink_step(stlink_t *sl) {
+ DLOG("*** stlink_step ***\n");
+ return (sl->backend->step(sl));
+}
+
+// 270
+int32_t stlink_current_mode(stlink_t *sl) {
+ int32_t mode = sl->backend->current_mode(sl);
+
+ switch (mode) {
+ case STLINK_DEV_DFU_MODE:
+ DLOG("stlink current mode: dfu\n");
+ return (mode);
+ case STLINK_DEV_DEBUG_MODE:
+ DLOG("stlink current mode: debug (jtag or swd)\n");
+ return (mode);
+ case STLINK_DEV_MASS_MODE:
+ DLOG("stlink current mode: mass\n");
+ return (mode);
+ }
+
+ DLOG("stlink mode: unknown!\n");
+ return (STLINK_DEV_UNKNOWN_MODE);
+}
+
+// 294
+void stlink_print_data(stlink_t *sl) {
+ if (sl->q_len <= 0 || sl->verbose < UDEBUG) {
+ return;
+ }
+
+ if (sl->verbose > 2) {
+ DLOG("data_len = %d 0x%x\n", sl->q_len, sl->q_len);
+ }
+
+ for (int32_t i = 0; i < sl->q_len; i++) {
+ if (i % 16 == 0) {
+ /*
+ if (sl->q_data_dir == Q_DATA_OUT) {
+ fprintf(stdout, "\n<- 0x%08x ", sl->q_addr + i);
+ } else {
+ fprintf(stdout, "\n-> 0x%08x ", sl->q_addr + i);
+ }
+ */
+ }
+ // DLOG(" %02x", (uint32_t) sl->q_buf[i]);
+ fprintf(stderr, " %02x", (uint32_t)sl->q_buf[i]);
+ }
+ // DLOG("\n\n");
+ fprintf(stderr, "\n");
+}
+
+// 283
+int32_t stlink_mwrite_sram(stlink_t *sl, uint8_t *data, uint32_t length, stm32_addr_t addr) {
+ // write the file in sram at addr
+
+ int32_t error = -1;
+ uint32_t off;
+ uint32_t len;
+
+ // check addr range is inside the sram
+ if (addr < sl->sram_base) {
+ fprintf(stderr, "addr too low\n");
+ goto on_error;
+ } else if ((addr + length) < addr) {
+ fprintf(stderr, "addr overruns\n");
+ goto on_error;
+ } else if ((addr + length) > (sl->sram_base + sl->sram_size)) {
+ fprintf(stderr, "addr too high\n");
+ goto on_error;
+ } else if (addr & 3) {
+ fprintf(stderr, "unaligned addr\n");
+ goto on_error;
+ }
+
+ len = length;
+
+ if (len & 3) {
+ len -= len & 3;
+ }
+
+ // do the copy by 1kB blocks
+ for (off = 0; off < len; off += 1024) {
+ uint32_t size = 1024;
+
+ if ((off + size) > len) {
+ size = len - off;
+ }
+
+ memcpy(sl->q_buf, data + off, size);
+
+ if (size & 3) {
+ size += 2;
+ } // round size if needed
+
+ stlink_write_mem32(sl, addr + off, (uint16_t)size);
+ }
+
+ if (length > len) {
+ memcpy(sl->q_buf, data + len, length - len);
+ stlink_write_mem8(sl, addr + len, (uint16_t)(length - len));
+ }
+
+ error = 0; // success
+ stlink_fwrite_finalize(sl, addr);
+
+on_error:
+ return (error);
+}
+
+//284
+int32_t stlink_fwrite_sram(stlink_t *sl, const char *path, stm32_addr_t addr) {
+ // write the file in sram at addr
+
+ int32_t error = -1;
+ uint32_t off;
+ uint32_t len;
+ mapped_file_t mf = MAPPED_FILE_INITIALIZER;
+
+ if (map_file(&mf, path) == -1) {
+ fprintf(stderr, "map_file() == -1\n");
+ return (-1);
+ }
+
+ printf("file %s ", path);
+ md5_calculate(&mf);
+ stlink_checksum(&mf);
+
+ // check if addr range is inside the SRAM
+ if (addr < sl->sram_base) {
+ fprintf(stderr, "addr too low\n");
+ goto on_error;
+ } else if ((addr + mf.len) < addr) {
+ fprintf(stderr, "addr overruns\n");
+ goto on_error;
+ } else if ((addr + mf.len) > (sl->sram_base + sl->sram_size)) {
+ fprintf(stderr, "addr too high\n");
+ goto on_error;
+ } else if (addr & 3) {
+ fprintf(stderr, "unaligned addr\n");
+ goto on_error;
+ }
+
+ len = mf.len;
+
+ if (len & 3) {
+ len -= len & 3;
+ }
+
+ // do the copy by 1kB blocks
+ for (off = 0; off < len; off += 1024) {
+ uint32_t size = 1024;
+
+ if ((off + size) > len) {
+ size = len - off;
+ }
+
+ memcpy(sl->q_buf, mf.base + off, size);
+
+ if (size & 3) {
+ size += 2;
+ } // round size if needed
+
+ stlink_write_mem32(sl, addr + off, (uint16_t)size);
+ }
+
+ if (mf.len > len) {
+ memcpy(sl->q_buf, mf.base + len, mf.len - len);
+ stlink_write_mem8(sl, addr + len, (uint16_t)(mf.len - len));
+ }
+
+ // check the file has been written
+ if (check_file(sl, &mf, addr) == -1) {
+ fprintf(stderr, "check_file() == -1\n");
+ goto on_error;
+ }
+
+ error = 0; // success
+ stlink_fwrite_finalize(sl, addr);
+
+on_error:
+ unmap_file(&mf);
+ return (error);
+}
+
+// 302
+int32_t stlink_fread(stlink_t *sl, const char *path, bool is_ihex, stm32_addr_t addr, uint32_t size) {
+ // read size bytes from addr to file
+ ILOG("read from address %#010x size %u\n", addr, size);
+
+ int32_t error;
+ int32_t fd = open(path, O_RDWR | O_TRUNC | O_CREAT | O_BINARY, 00700);
+
+ if (fd == -1) {
+ fprintf(stderr, "open(%s) == -1\n", path);
+ return (-1);
+ }
+
+ if (is_ihex) {
+ struct stlink_fread_ihex_worker_arg arg;
+
+ if (stlink_fread_ihex_init(&arg, fd, addr)) {
+ error = stlink_read(sl, addr, size, &stlink_fread_ihex_worker, &arg);
+
+ if (!stlink_fread_ihex_finalize(&arg)) {
+ error = -1;
+ }
+ } else {
+ error = -1;
+ }
+ } else {
+ struct stlink_fread_worker_arg arg = {fd};
+ error = stlink_read(sl, addr, size, &stlink_fread_worker, &arg);
+ }
+
+ close(fd);
+ return (error);
+}
+
+// 300
+int32_t write_buffer_to_sram(stlink_t *sl, flash_loader_t *fl, const uint8_t *buf, uint16_t size) {
+ // write the buffer right after the loader
+ int32_t ret = 0;
+ uint16_t chunk = size & ~0x3;
+ uint16_t rem = size & 0x3;
+
+ if (chunk) {
+ memcpy(sl->q_buf, buf, chunk);
+ ret = stlink_write_mem32(sl, fl->buf_addr, chunk);
+ }
+
+ if (rem && !ret) {
+ memcpy(sl->q_buf, buf + chunk, rem);
+ ret = stlink_write_mem8(sl, (fl->buf_addr) + chunk, rem);
+ }
+
+ return (ret);
+}
+
+// 291
+uint32_t stlink_calculate_pagesize(stlink_t *sl, uint32_t flashaddr) {
+
+ if ((sl->chip_id == STM32_CHIPID_F2) ||
+ (sl->chip_id == STM32_CHIPID_F4) ||
+ (sl->chip_id == STM32_CHIPID_F4_DE) ||
+ (sl->chip_id == STM32_CHIPID_F4_LP) ||
+ (sl->chip_id == STM32_CHIPID_F4_HD) ||
+ (sl->chip_id == STM32_CHIPID_F411xx) ||
+ (sl->chip_id == STM32_CHIPID_F446) ||
+ (sl->chip_id == STM32_CHIPID_F4_DSI) ||
+ (sl->chip_id == STM32_CHIPID_F72xxx) ||
+ (sl->chip_id == STM32_CHIPID_F412)) {
+ uint32_t sector = calculate_F4_sectornum(flashaddr);
+
+ if (sector >= 12) {
+ sector -= 12;
+ }
+
+ if (sector < 4) {
+ sl->flash_pgsz = 0x4000;
+ } else if (sector < 5) {
+ sl->flash_pgsz = 0x10000;
+ } else {
+ sl->flash_pgsz = 0x20000;
+ }
+ } else if (sl->chip_id == STM32_CHIPID_F7 ||
+ sl->chip_id == STM32_CHIPID_F76xxx) {
+ uint32_t sector = calculate_F7_sectornum(flashaddr);
+
+ if (sector < 4) {
+ sl->flash_pgsz = 0x8000;
+ } else if (sector < 5) {
+ sl->flash_pgsz = 0x20000;
+ } else {
+ sl->flash_pgsz = 0x40000;
+ }
+ }
+
+ return (sl->flash_pgsz);
+}
+
+// 279
+int32_t stlink_parse_ihex(const char *path, uint8_t erased_pattern, uint8_t **mem,
+ uint32_t *size, uint32_t *begin) {
+ int32_t res = 0;
+ *begin = UINT32_MAX;
+ uint8_t *data = NULL;
+ uint32_t end = 0;
+ bool eof_found = false;
+
+ for (int32_t scan = 0; (res == 0) && (scan < 2); ++scan) {
+ // parse file two times - first to find memory range, second - to fill it
+ if (scan == 1) {
+ if (!eof_found) {
+ ELOG("No EoF recond\n");
+ res = -1;
+ break;
+ }
+
+ if (*begin >= end) {
+ ELOG("No data found in file\n");
+ res = -1;
+ break;
+ }
+
+ *size = (end - *begin) + 1;
+ data = calloc(*size, 1); // use calloc to get NULL if out of memory
+
+ if (!data) {
+ ELOG("Cannot allocate %u bytes\n", (*size));
+ res = -1;
+ break;
+ }
+
+ memset(data, erased_pattern, *size);
+ }
+
+ FILE *file = fopen(path, "r");
+
+ if (!file) {
+ ELOG("Cannot open file\n");
+ res = -1;
+ break;
+ }
+
+ uint32_t lba = 0;
+ char line[1 + 5 * 2 + 255 * 2 + 2];
+
+ while (fgets(line, sizeof(line), file)) {
+ if (line[0] == '\n' || line[0] == '\r') {
+ continue;
+ } // skip empty lines
+
+ if (line[0] != ':') { // no marker - wrong file format
+ ELOG("Wrong file format - no marker\n");
+ res = -1;
+ break;
+ }
+
+ uint32_t l = strlen(line);
+
+ while (l > 0 && (line[l - 1] == '\n' || line[l - 1] == '\r')) {
+ --l;
+ } // trim EoL
+
+ if ((l < 11) ||
+ (l ==
+ (sizeof(line) - 1))) { // line too short or long - wrong file format
+ ELOG("Wrong file format - wrong line length\n");
+ res = -1;
+ break;
+ }
+
+ uint8_t chksum = 0; // check sum
+
+ for (uint32_t i = 1; i < l; i += 2) {
+ chksum += stlink_parse_hex(line + i);
+ }
+
+ if (chksum != 0) {
+ ELOG("Wrong file format - checksum mismatch\n");
+ res = -1;
+ break;
+ }
+
+ uint8_t reclen = stlink_parse_hex(line + 1);
+
+ if (((uint32_t)reclen + 5) * 2 + 1 != l) {
+ ELOG("Wrong file format - record length mismatch\n");
+ res = -1;
+ break;
+ }
+
+ uint16_t offset = ((uint16_t)stlink_parse_hex(line + 3) << 8) |
+ ((uint16_t)stlink_parse_hex(line + 5));
+ uint8_t rectype = stlink_parse_hex(line + 7);
+
+ switch (rectype) {
+ case 0: /* Data */
+ if (scan == 0) {
+ uint32_t b = lba + offset;
+ uint32_t e = b + reclen - 1;
+
+ if (b < *begin) {
+ *begin = b;
+ }
+
+ if (e > end) {
+ end = e;
+ }
+ } else {
+ for (uint8_t i = 0; i < reclen; ++i) {
+ uint8_t b = stlink_parse_hex(line + 9 + i * 2);
+ uint32_t addr = lba + offset + i;
+
+ if (addr >= *begin && addr <= end) {
+ data[addr - *begin] = b;
+ }
+ }
+ }
+ break;
+ case 1: /* EoF */
+ eof_found = true;
+ break;
+ case 2: /* Extended Segment Address, unexpected */
+ res = -1;
+ break;
+ case 3: /* Start Segment Address, unexpected */
+ res = -1;
+ break;
+ case 4: /* Extended Linear Address */
+ if (reclen == 2) {
+ lba = ((uint32_t)stlink_parse_hex(line + 9) << 24) |
+ ((uint32_t)stlink_parse_hex(line + 11) << 16);
+ } else {
+ ELOG("Wrong file format - wrong LBA length\n");
+ res = -1;
+ }
+ break;
+ case 5: /* Start Linear Address - expected, but ignore */
+ break;
+ default:
+ ELOG("Wrong file format - unexpected record type %d\n", rectype);
+ res = -1;
+ }
+
+ if (res != 0) {
+ break;
+ }
+ }
+
+ fclose(file);
+ }
+
+ if (res == 0) {
+ *mem = data;
+ } else {
+ free(data);
+ }
+
+ return (res);
+}
+
+// 280
+uint8_t stlink_get_erased_pattern(stlink_t *sl) {
+ if (sl->flash_type == STM32_FLASH_TYPE_L0_L1) {
+ return (0x00);
+ } else {
+ return (0xff);
+ }
+}
+
+// 322
+int32_t stlink_target_connect(stlink_t *sl, enum connect_type connect) {
+ if (connect == CONNECT_UNDER_RESET) {
+ stlink_enter_swd_mode(sl);
+
+ stlink_jtag_reset(sl, STLINK_DEBUG_APIV2_DRIVE_NRST_LOW);
+
+ // try to halt the core before reset
+ // this is useful if the NRST pin is not connected
+ sl->backend->force_debug(sl);
+
+ // minimum reset pulse duration of 20 us (RM0008, 8.1.2 Power reset)
+ usleep(20);
+
+ stlink_jtag_reset(sl, STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH);
+
+ // try to halt the core after reset
+ uint32_t timeout = time_ms() + 10;
+ while (time_ms() < timeout) {
+ sl->backend->force_debug(sl);
+ usleep(100);
+ }
+
+ // check NRST connection
+ uint32_t dhcsr = 0;
+ stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr);
+ if ((dhcsr & STLINK_REG_DHCSR_S_RESET_ST) == 0) {
+ WLOG("NRST is not connected\n");
+ }
+
+ // addition soft reset for halt before the first instruction
+ stlink_soft_reset(sl, 1 /* halt on reset */);
+ }
+
+ if (stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE &&
+ stlink_enter_swd_mode(sl)) {
+ printf("Failed to enter SWD mode\n");
+ return -1;
+ }
+
+ if (connect == CONNECT_NORMAL) {
+ stlink_reset(sl, RESET_AUTO);
+ }
+
+ return stlink_load_device_params(sl);
+}
+
+// End of delegates.... functions below are private to this module
+// same as above with entrypoint.
+
+static void stop_wdg_in_debug(stlink_t *sl) {
+ uint32_t dbgmcu_cr;
+ uint32_t set;
+ uint32_t value;
+
+ switch (sl->flash_type) {
+ case STM32_FLASH_TYPE_F0_F1_F3:
+ case STM32_FLASH_TYPE_F1_XL:
+ case STM32_FLASH_TYPE_G4:
+ dbgmcu_cr = STM32F0_DBGMCU_CR;
+ set = (1 << STM32F0_DBGMCU_CR_IWDG_STOP) |
+ (1 << STM32F0_DBGMCU_CR_WWDG_STOP);
+ break;
+ case STM32_FLASH_TYPE_F2_F4:
+ case STM32_FLASH_TYPE_F7:
+ case STM32_FLASH_TYPE_L4:
+ dbgmcu_cr = STM32F4_DBGMCU_APB1FZR1;
+ set = (1 << STM32F4_DBGMCU_APB1FZR1_IWDG_STOP) |
+ (1 << STM32F4_DBGMCU_APB1FZR1_WWDG_STOP);
+ break;
+ case STM32_FLASH_TYPE_L0_L1:
+ case STM32_FLASH_TYPE_G0:
+ if (get_stm32l0_flash_base(sl) == FLASH_Lx_REGS_ADDR) {
+ dbgmcu_cr = STM32L1_DBGMCU_APB1_FZ;
+ set = (1 << STM32L1_DBGMCU_APB1_FZ_IWDG_STOP) |
+ (1 << STM32L1_DBGMCU_APB1_FZ_WWDG_STOP);
+ } else {
+ dbgmcu_cr = STM32L0_DBGMCU_APB1_FZ;
+ set = (1 << STM32L0_DBGMCU_APB1_FZ_IWDG_STOP) |
+ (1 << STM32L0_DBGMCU_APB1_FZ_WWDG_STOP);
+ }
+ break;
+ case STM32_FLASH_TYPE_H7:
+ dbgmcu_cr = STM32H7_DBGMCU_APB1HFZ;
+ set = (1 << STM32H7_DBGMCU_APB1HFZ_IWDG_STOP);
+ break;
+ case STM32_FLASH_TYPE_WB_WL:
+ dbgmcu_cr = STM32WB_DBGMCU_APB1FZR1;
+ set = (1 << STM32WB_DBGMCU_APB1FZR1_IWDG_STOP) |
+ (1 << STM32WB_DBGMCU_APB1FZR1_WWDG_STOP);
+ break;
+ default:
+ return;
+ }
+
+ if (!stlink_read_debug32(sl, dbgmcu_cr, &value)) {
+ stlink_write_debug32(sl, dbgmcu_cr, value | set);
+ }
+}
+
+int32_t stlink_jtag_reset(stlink_t *sl, int32_t value) {
+ DLOG("*** stlink_jtag_reset %d ***\n", value);
+ return (sl->backend->jtag_reset(sl, value));
+}
+
+/**
+ * Decode the version bits, originally from -sg, verified with usb
+ * @param sl stlink context, assumed to contain valid data in the buffer
+ * @param slv output parsed version object
+ */
+void _parse_version(stlink_t *sl, stlink_version_t *slv) {
+ sl->version.flags = 0;
+
+ if (sl->version.stlink_v < 3) {
+ uint32_t b0 = sl->q_buf[0]; // lsb
+ uint32_t b1 = sl->q_buf[1];
+ uint32_t b2 = sl->q_buf[2];
+ uint32_t b3 = sl->q_buf[3];
+ uint32_t b4 = sl->q_buf[4];
+ uint32_t b5 = sl->q_buf[5]; // msb
+
+ // b0 b1 || b2 b3 | b4 b5
+ // 4b | 6b | 6b || 2B | 2B
+ // stlink_v | jtag_v | swim_v || st_vid | stlink_pid
+
+ slv->stlink_v = (b0 & 0xf0) >> 4;
+ slv->jtag_v = ((b0 & 0x0f) << 2) | ((b1 & 0xc0) >> 6);
+ slv->swim_v = b1 & 0x3f;
+ slv->st_vid = (b3 << 8) | b2;
+ slv->stlink_pid = (b5 << 8) | b4;
+
+ // ST-LINK/V1 from J11 switch to api-v2 (and support SWD)
+ if (slv->stlink_v == 1) {
+ slv->jtag_api =
+ slv->jtag_v > 11 ? STLINK_JTAG_API_V2 : STLINK_JTAG_API_V1;
+ } else {
+ slv->jtag_api = STLINK_JTAG_API_V2;
+
+ // preferred API to get last R/W status from J15
+ if (sl->version.jtag_v >= 15) {
+ sl->version.flags |= STLINK_F_HAS_GETLASTRWSTATUS2;
+ }
+
+ if (sl->version.jtag_v >= 13) {
+ sl->version.flags |= STLINK_F_HAS_TRACE;
+ sl->max_trace_freq = STLINK_V2_MAX_TRACE_FREQUENCY;
+ }
+ }
+ } else {
+ // V3 uses different version format, for reference see OpenOCD source
+ // (that was written from docs available from ST under NDA):
+ // https://github.com/ntfreak/openocd/blob/a6dacdff58ef36fcdac00c53ec27f19de1fbce0d/src/jtag/drivers/stlink_usb.c#L965
+ slv->stlink_v = sl->q_buf[0];
+ slv->swim_v = sl->q_buf[1];
+ slv->jtag_v = sl->q_buf[2];
+ slv->st_vid = (uint32_t)((sl->q_buf[9] << 8) | sl->q_buf[8]);
+ slv->stlink_pid = (uint32_t)((sl->q_buf[11] << 8) | sl->q_buf[10]);
+ slv->jtag_api = STLINK_JTAG_API_V3;
+ /* preferred API to get last R/W status */
+ sl->version.flags |= STLINK_F_HAS_GETLASTRWSTATUS2;
+ sl->version.flags |= STLINK_F_HAS_TRACE;
+ sl->max_trace_freq = STLINK_V3_MAX_TRACE_FREQUENCY;
+ }
+
+ return;
+}
+
+void stlink_run_at(stlink_t *sl, stm32_addr_t addr) {
+ stlink_write_reg(sl, addr, 15); /* pc register */
+ stlink_run(sl, RUN_NORMAL);
+
+ while (stlink_is_core_halted(sl)) {
+ usleep(3000000);
+ }
+}
+
+static int32_t stlink_read(stlink_t *sl, stm32_addr_t addr, uint32_t size, save_block_fn fn, void *fn_arg) {
+
+ int32_t error = -1;
+
+ if (size < 1) {
+ size = sl->flash_size;
+ }
+
+ if (size > sl->flash_size) {
+ size = sl->flash_size;
+ }
+
+ uint32_t cmp_size = (sl->flash_pgsz > 0x1800) ? 0x1800 : sl->flash_pgsz;
+
+ for (uint32_t off = 0; off < size; off += cmp_size) {
+ uint32_t aligned_size;
+
+ // adjust last page size
+ if ((off + cmp_size) > size) {
+ cmp_size = size - off;
+ }
+
+ aligned_size = cmp_size;
+
+ if (aligned_size & (4 - 1)) {
+ aligned_size = (cmp_size + 4) & ~(4 - 1);
+ }
+
+ stlink_read_mem32(sl, addr + off, (uint16_t)aligned_size);
+
+ if (!fn(fn_arg, sl->q_buf, aligned_size)) {
+ goto on_error;
+ }
+ }
+
+ error = 0; // success
+
+on_error:
+ return (error);
+}
+
+static bool stlink_fread_worker(void *arg, uint8_t *block, ssize_t len) {
+ struct stlink_fread_worker_arg *the_arg = (struct stlink_fread_worker_arg *)arg;
+
+ if (write(the_arg->fd, block, len) != len) {
+ fprintf(stderr, "write() != aligned_size\n");
+ return (false);
+ } else {
+ return (true);
+ }
+}
+
+// TODO: length not checked
+static uint8_t stlink_parse_hex(const char *hex) {
+ uint8_t d[2];
+
+ for (int32_t i = 0; i < 2; ++i) {
+ char c = *(hex + i);
+
+ if (c >= '0' && c <= '9') {
+ d[i] = c - '0';
+ } else if (c >= 'A' && c <= 'F') {
+ d[i] = c - 'A' + 10;
+ } else if (c >= 'a' && c <= 'f') {
+ d[i] = c - 'a' + 10;
+ } else {
+ return (0); // error
+ }
+ }
+
+ return ((d[0] << 4) | (d[1]));
+}
+
+static bool stlink_fread_ihex_newsegment(struct stlink_fread_ihex_worker_arg *the_arg) {
+ uint32_t addr = the_arg->addr;
+ uint8_t sum = 2 + 4 + (uint8_t)((addr & 0xFF000000) >> 24) +
+ (uint8_t)((addr & 0x00FF0000) >> 16);
+
+ if (17 != fprintf(the_arg->file, ":02000004%04X%02X\r\n",
+ (addr & 0xFFFF0000) >> 16, (uint8_t)(0x100 - sum))) {
+ return (false);
+ }
+
+ the_arg->lba = (addr & 0xFFFF0000);
+ return (true);
+}
+
+static bool stlink_fread_ihex_writeline(struct stlink_fread_ihex_worker_arg *the_arg) {
+ uint8_t count = the_arg->buf_pos;
+
+ if (count == 0) {
+ return (true);
+ }
+
+ uint32_t addr = the_arg->addr;
+
+ if (the_arg->lba != (addr & 0xFFFF0000)) { // segment changed
+ if (!stlink_fread_ihex_newsegment(the_arg)) {
+ return (false);
+ }
+ }
+
+ uint8_t sum = count + (uint8_t)((addr & 0x0000FF00) >> 8) +
+ (uint8_t)(addr & 0x000000FF);
+
+ if (9 != fprintf(the_arg->file, ":%02X%04X00", count, (addr & 0x0000FFFF))) {
+ return (false);
+ }
+
+ for (uint8_t i = 0; i < count; ++i) {
+ uint8_t b = the_arg->buf[i];
+ sum += b;
+
+ if (2 != fprintf(the_arg->file, "%02X", b)) {
+ return (false);
+ }
+ }
+
+ if (4 != fprintf(the_arg->file, "%02X\r\n", (uint8_t)(0x100 - sum))) {
+ return (false);
+ }
+
+ the_arg->addr += count;
+ the_arg->buf_pos = 0;
+
+ return (true);
+}
+
+static bool stlink_fread_ihex_init(struct stlink_fread_ihex_worker_arg *the_arg,
+ int32_t fd, stm32_addr_t addr) {
+ the_arg->file = fdopen(fd, "w");
+ the_arg->addr = addr;
+ the_arg->lba = 0;
+ the_arg->buf_pos = 0;
+
+ return (the_arg->file != NULL);
+}
+
+static bool stlink_fread_ihex_worker(void *arg, uint8_t *block, ssize_t len) {
+ struct stlink_fread_ihex_worker_arg *the_arg =
+ (struct stlink_fread_ihex_worker_arg *)arg;
+
+ for (ssize_t i = 0; i < len; ++i) {
+ if (the_arg->buf_pos == sizeof(the_arg->buf)) { // line is full
+ if (!stlink_fread_ihex_writeline(the_arg)) {
+ return (false);
+ }
+ }
+
+ the_arg->buf[the_arg->buf_pos++] = block[i];
+ }
+
+ return (true);
+}
+
+static bool stlink_fread_ihex_finalize(struct stlink_fread_ihex_worker_arg *the_arg) {
+ if (!stlink_fread_ihex_writeline(the_arg)) {
+ return (false);
+ }
+
+ // FIXME: do we need the Start Linear Address?
+
+ if (13 != fprintf(the_arg->file, ":00000001FF\r\n")) { // EoF
+ return (false);
+ }
+
+ return (0 == fclose(the_arg->file));
+}
diff --git a/src/stlink-lib/common_flash.c b/src/stlink-lib/common_flash.c
new file mode 100644
index 0000000..aa8db5b
--- /dev/null
+++ b/src/stlink-lib/common_flash.c
@@ -0,0 +1,1566 @@
+/*
+ * File: common_flash.c
+ *
+ * Flash operations
+ */
+
+#include <stdint.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <stlink.h>
+#include "common_flash.h"
+
+#include "calculate.h"
+#include "flash_loader.h"
+#include "logging.h"
+#include "map_file.h"
+#include "md5.h"
+#include "read_write.h"
+
+#define DEBUG_FLASH 0
+
+uint32_t get_stm32l0_flash_base(stlink_t *sl) {
+ switch (sl->chip_id) {
+ case STM32_CHIPID_L0_CAT1:
+ case STM32_CHIPID_L0_CAT2:
+ case STM32_CHIPID_L0_CAT3:
+ case STM32_CHIPID_L0_CAT5:
+ return (FLASH_L0_REGS_ADDR);
+
+ case STM32_CHIPID_L1_CAT2:
+ case STM32_CHIPID_L1_MD:
+ case STM32_CHIPID_L1_MD_PLUS:
+ case STM32_CHIPID_L1_MD_PLUS_HD:
+ case STM32_CHIPID_L152_RE:
+ return (FLASH_Lx_REGS_ADDR);
+
+ default:
+ WLOG("Flash base use default L0 address\n");
+ return (FLASH_L0_REGS_ADDR);
+ }
+}
+
+uint32_t read_flash_cr(stlink_t *sl, uint32_t bank) {
+ uint32_t reg, res;
+
+ if (sl->flash_type == STM32_FLASH_TYPE_C0) {
+ reg = FLASH_C0_CR;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_F2_F4) {
+ reg = FLASH_F4_CR;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_F7) {
+ reg = FLASH_F7_CR;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_G0 ||
+ sl->flash_type == STM32_FLASH_TYPE_G4) {
+ reg = FLASH_Gx_CR;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_H7) {
+ reg = (bank == BANK_1) ? FLASH_H7_CR1 : FLASH_H7_CR2;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_L4) {
+ reg = FLASH_L4_CR;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5) {
+ reg = FLASH_L5_NSCR;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) {
+ reg = FLASH_WB_CR;
+ } else {
+ reg = (bank == BANK_1) ? FLASH_CR : FLASH_CR2;
+ }
+
+ stlink_read_debug32(sl, reg, &res);
+
+#if DEBUG_FLASH
+ fprintf(stdout, "CR:0x%x\n", res);
+#endif
+ return (res);
+}
+
+void lock_flash(stlink_t *sl) {
+ uint32_t cr_lock_shift = 0, cr_reg = 0, n = 0, cr2_reg = 0;
+ uint32_t cr_mask = 0xffffffffu;
+
+ if (sl->flash_type == STM32_FLASH_TYPE_C0) {
+ cr_reg = FLASH_C0_CR;
+ cr_lock_shift = FLASH_C0_CR_LOCK;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_F0_F1_F3) {
+ cr_reg = FLASH_CR;
+ cr_lock_shift = FLASH_CR_LOCK;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_F1_XL) {
+ cr_reg = FLASH_CR;
+ cr2_reg = FLASH_CR2;
+ cr_lock_shift = FLASH_CR_LOCK;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_F2_F4) {
+ cr_reg = FLASH_F4_CR;
+ cr_lock_shift = FLASH_F4_CR_LOCK;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_F7) {
+ cr_reg = FLASH_F7_CR;
+ cr_lock_shift = FLASH_F7_CR_LOCK;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_G0 ||
+ sl->flash_type == STM32_FLASH_TYPE_G4) {
+ cr_reg = FLASH_Gx_CR;
+ cr_lock_shift = FLASH_Gx_CR_LOCK;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_H7) {
+ cr_reg = FLASH_H7_CR1;
+ if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) {
+ cr2_reg = FLASH_H7_CR2;
+ }
+ cr_lock_shift = FLASH_H7_CR_LOCK;
+ cr_mask = ~(1u << FLASH_H7_CR_SER);
+ } else if (sl->flash_type == STM32_FLASH_TYPE_L0_L1) {
+ cr_reg = get_stm32l0_flash_base(sl) + FLASH_PECR_OFF;
+ cr_lock_shift = FLASH_L0_PELOCK;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_L4) {
+ cr_reg = FLASH_L4_CR;
+ cr_lock_shift = FLASH_L4_CR_LOCK;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5) {
+ cr_reg = FLASH_L5_NSCR;
+ cr_lock_shift = FLASH_L5_NSCR_NSLOCK;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) {
+ cr_reg = FLASH_WB_CR;
+ cr_lock_shift = FLASH_WB_CR_LOCK;
+ } else {
+ ELOG("unsupported flash method, abort\n");
+ return;
+ }
+
+ stlink_read_debug32(sl, cr_reg, &n);
+ n &= cr_mask;
+ n |= (1u << cr_lock_shift);
+ stlink_write_debug32(sl, cr_reg, n);
+
+ if (cr2_reg) {
+ n = read_flash_cr(sl, BANK_2) | (1u << cr_lock_shift);
+ stlink_write_debug32(sl, cr2_reg, n);
+ }
+}
+
+static inline int32_t write_flash_sr(stlink_t *sl, uint32_t bank, uint32_t val) {
+ uint32_t sr_reg;
+
+ if (sl->flash_type == STM32_FLASH_TYPE_C0) {
+ sr_reg = FLASH_C0_SR;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_F0_F1_F3 ||
+ sl->flash_type == STM32_FLASH_TYPE_F1_XL) {
+ sr_reg = (bank == BANK_1) ? FLASH_SR : FLASH_SR2;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_F2_F4) {
+ sr_reg = FLASH_F4_SR;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_F7) {
+ sr_reg = FLASH_F7_SR;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_G0 ||
+ sl->flash_type == STM32_FLASH_TYPE_G4) {
+ sr_reg = FLASH_Gx_SR;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_H7) {
+ sr_reg = (bank == BANK_1) ? FLASH_H7_SR1 : FLASH_H7_SR2;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_L0_L1) {
+ sr_reg = get_stm32l0_flash_base(sl) + FLASH_SR_OFF;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_L4) {
+ sr_reg = FLASH_L4_SR;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5) {
+ sr_reg = FLASH_L5_NSSR;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) {
+ sr_reg = FLASH_WB_SR;
+ } else {
+ ELOG("method 'write_flash_sr' is unsupported\n");
+ return (-1);
+ }
+
+ return stlink_write_debug32(sl, sr_reg, val);
+}
+
+void clear_flash_error(stlink_t *sl) {
+ switch (sl->flash_type) {
+ case STM32_FLASH_TYPE_C0:
+ write_flash_sr(sl, BANK_1, FLASH_C0_SR_ERROR_MASK);
+ break;
+ case STM32_FLASH_TYPE_F0_F1_F3:
+ write_flash_sr(sl, BANK_1, FLASH_SR_ERROR_MASK);
+ break;
+ case STM32_FLASH_TYPE_F2_F4:
+ write_flash_sr(sl, BANK_1, FLASH_F4_SR_ERROR_MASK);
+ break;
+ case STM32_FLASH_TYPE_F7:
+ write_flash_sr(sl, BANK_1, FLASH_F7_SR_ERROR_MASK);
+ break;
+ case STM32_FLASH_TYPE_G0:
+ case STM32_FLASH_TYPE_G4:
+ write_flash_sr(sl, BANK_1, FLASH_Gx_SR_ERROR_MASK);
+ break;
+ case STM32_FLASH_TYPE_H7:
+ write_flash_sr(sl, BANK_1, FLASH_H7_SR_ERROR_MASK);
+ if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) {
+ write_flash_sr(sl, BANK_2, FLASH_H7_SR_ERROR_MASK);
+ }
+ break;
+ case STM32_FLASH_TYPE_L0_L1:
+ if (get_stm32l0_flash_base(sl) == FLASH_Lx_REGS_ADDR) {
+ write_flash_sr(sl, BANK_1, FLASH_L1_SR_ERROR_MASK);
+ } else {
+ write_flash_sr(sl, BANK_1, FLASH_L0_SR_ERROR_MASK);
+ }
+ break;
+ case STM32_FLASH_TYPE_L4:
+ write_flash_sr(sl, BANK_1, FLASH_L4_SR_ERROR_MASK);
+ break;
+ case STM32_FLASH_TYPE_L5_U5_H5:
+ write_flash_sr(sl, BANK_1, FLASH_L5_NSSR_ERROR_MASK);
+ break;
+ case STM32_FLASH_TYPE_WB_WL:
+ write_flash_sr(sl, BANK_1, FLASH_WB_SR_ERROR_MASK);
+ break;
+ default:
+ break;
+ }
+}
+
+uint32_t read_flash_sr(stlink_t *sl, uint32_t bank) {
+ uint32_t res, sr_reg;
+
+ if (sl->flash_type == STM32_FLASH_TYPE_C0) {
+ sr_reg = FLASH_C0_SR;
+ } else if ((sl->flash_type == STM32_FLASH_TYPE_F0_F1_F3) ||
+ (sl->flash_type == STM32_FLASH_TYPE_F1_XL)) {
+ sr_reg = (bank == BANK_1) ? FLASH_SR : FLASH_SR2;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_F2_F4) {
+ sr_reg = FLASH_F4_SR;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_F7) {
+ sr_reg = FLASH_F7_SR;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_G0 ||
+ sl->flash_type == STM32_FLASH_TYPE_G4) {
+ sr_reg = FLASH_Gx_SR;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_H7) {
+ sr_reg = (bank == BANK_1) ? FLASH_H7_SR1 : FLASH_H7_SR2;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_L0_L1) {
+ sr_reg = get_stm32l0_flash_base(sl) + FLASH_SR_OFF;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_L4) {
+ sr_reg = FLASH_L4_SR;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5) {
+ sr_reg = FLASH_L5_NSSR;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) {
+ sr_reg = FLASH_WB_SR;
+ } else {
+ ELOG("method 'read_flash_sr' is unsupported\n");
+ return (-1);
+ }
+
+ stlink_read_debug32(sl, sr_reg, &res);
+ return (res);
+}
+
+uint32_t is_flash_busy(stlink_t *sl) {
+ uint32_t sr_busy_shift;
+ uint32_t res;
+
+ if (sl->flash_type == STM32_FLASH_TYPE_C0) {
+ sr_busy_shift = FLASH_C0_SR_BSY;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_F0_F1_F3 ||
+ sl->flash_type == STM32_FLASH_TYPE_F1_XL ||
+ sl->flash_type == STM32_FLASH_TYPE_L0_L1) {
+ sr_busy_shift = FLASH_SR_BSY;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_F2_F4) {
+ sr_busy_shift = FLASH_F4_SR_BSY;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_F7) {
+ sr_busy_shift = FLASH_F7_SR_BSY;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_G0 ||
+ sl->flash_type == STM32_FLASH_TYPE_G4) {
+ sr_busy_shift = FLASH_Gx_SR_BSY;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_H7) {
+ sr_busy_shift = FLASH_H7_SR_QW;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_L4) {
+ sr_busy_shift = FLASH_L4_SR_BSY;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5) {
+ sr_busy_shift = FLASH_L5_NSSR_BSY;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) {
+ sr_busy_shift = FLASH_WB_SR_BSY;
+ } else {
+ ELOG("method 'is_flash_busy' is unsupported\n");
+ return (-1);
+ }
+
+ res = read_flash_sr(sl, BANK_1) & (1 << sr_busy_shift);
+
+ if (sl->flash_type == STM32_FLASH_TYPE_F1_XL ||
+ (sl->flash_type == STM32_FLASH_TYPE_H7 &&
+ sl->chip_flags & CHIP_F_HAS_DUAL_BANK)) {
+ res |= read_flash_sr(sl, BANK_2) & (1 << sr_busy_shift);
+ }
+
+ return (res);
+}
+
+void wait_flash_busy(stlink_t *sl) {
+ // TODO: add some delays here
+ while (is_flash_busy(sl))
+ ;
+}
+
+int32_t check_flash_error(stlink_t *sl) {
+ uint32_t res = 0;
+ uint32_t WRPERR, PROGERR, PGAERR;
+
+ WRPERR = PROGERR = PGAERR = 0;
+
+ switch (sl->flash_type) {
+ case STM32_FLASH_TYPE_C0:
+ res = read_flash_sr(sl, BANK_1) & FLASH_C0_SR_ERROR_MASK;
+ WRPERR = (1 << FLASH_C0_SR_WRPERR);
+ PROGERR = (1 << FLASH_C0_SR_PROGERR);
+ PGAERR = (1 << FLASH_C0_SR_PGAERR);
+ break;
+ case STM32_FLASH_TYPE_F0_F1_F3:
+ case STM32_FLASH_TYPE_F1_XL:
+ res = read_flash_sr(sl, BANK_1) & FLASH_SR_ERROR_MASK;
+ if (sl->flash_type == STM32_FLASH_TYPE_F1_XL) {
+ res |= read_flash_sr(sl, BANK_2) & FLASH_SR_ERROR_MASK;
+ }
+ WRPERR = (1 << FLASH_SR_WRPRT_ERR);
+ PROGERR = (1 << FLASH_SR_PG_ERR);
+ break;
+ case STM32_FLASH_TYPE_F2_F4:
+ res = read_flash_sr(sl, BANK_1) & FLASH_F4_SR_ERROR_MASK;
+ WRPERR = (1 << FLASH_F4_SR_WRPERR);
+ PGAERR = (1 << FLASH_F4_SR_PGAERR);
+ break;
+ case STM32_FLASH_TYPE_F7:
+ res = read_flash_sr(sl, BANK_1) & FLASH_F7_SR_ERROR_MASK;
+ WRPERR = (1 << FLASH_F7_SR_WRP_ERR);
+ PROGERR = (1 << FLASH_F7_SR_PGP_ERR);
+ break;
+ case STM32_FLASH_TYPE_G0:
+ case STM32_FLASH_TYPE_G4:
+ res = read_flash_sr(sl, BANK_1) & FLASH_Gx_SR_ERROR_MASK;
+ if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) {
+ res |= read_flash_sr(sl, BANK_2) & FLASH_Gx_SR_ERROR_MASK;
+ }
+ WRPERR = (1 << FLASH_Gx_SR_WRPERR);
+ PROGERR = (1 << FLASH_Gx_SR_PROGERR);
+ PGAERR = (1 << FLASH_Gx_SR_PGAERR);
+ break;
+ case STM32_FLASH_TYPE_H7:
+ res = read_flash_sr(sl, BANK_1) & FLASH_H7_SR_ERROR_MASK;
+ if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) {
+ res |= read_flash_sr(sl, BANK_2) & FLASH_H7_SR_ERROR_MASK;
+ }
+ WRPERR = (1 << FLASH_H7_SR_WRPERR);
+ break;
+ case STM32_FLASH_TYPE_L0_L1:
+ res = read_flash_sr(sl, BANK_1);
+ if (get_stm32l0_flash_base(sl) == FLASH_Lx_REGS_ADDR) {
+ res &= FLASH_L1_SR_ERROR_MASK;
+ } else {
+ res &= FLASH_L0_SR_ERROR_MASK;
+ PROGERR = (1 << FLASH_L0_SR_NOTZEROERR);
+ }
+ WRPERR = (1 << FLASH_L0_SR_WRPERR);
+ PGAERR = (1 << FLASH_L0_SR_PGAERR);
+ break;
+ case STM32_FLASH_TYPE_L4:
+ res = read_flash_sr(sl, BANK_1) & FLASH_L4_SR_ERROR_MASK;
+ WRPERR = (1 << FLASH_L4_SR_WRPERR);
+ PROGERR = (1 << FLASH_L4_SR_PROGERR);
+ PGAERR = (1 << FLASH_L4_SR_PGAERR);
+ break;
+ case STM32_FLASH_TYPE_L5_U5_H5:
+ res = read_flash_sr(sl, BANK_1) & FLASH_L5_NSSR_ERROR_MASK;
+ WRPERR = (1 << FLASH_L5_NSSR_NSWRPERR);
+ PROGERR = (1 << FLASH_L5_NSSR_NSPROGERR);
+ PGAERR = (1 << FLASH_L5_NSSR_NSPGAERR);
+ break;
+ case STM32_FLASH_TYPE_WB_WL:
+ res = read_flash_sr(sl, BANK_1) & FLASH_WB_SR_ERROR_MASK;
+ WRPERR = (1 << FLASH_WB_SR_WRPERR);
+ PROGERR = (1 << FLASH_WB_SR_PROGERR);
+ PGAERR = (1 << FLASH_WB_SR_PGAERR);
+ break;
+ default:
+ break;
+ }
+
+ if (res) {
+ if (WRPERR && (WRPERR & res) == WRPERR) {
+ ELOG("Flash memory is write protected\n");
+ res &= ~WRPERR;
+ } else if (PROGERR && (PROGERR & res) == PROGERR) {
+ ELOG("Flash memory contains a non-erased value\n");
+ res &= ~PROGERR;
+ } else if (PGAERR && (PGAERR & res) == PGAERR) {
+ ELOG("Invalid flash address\n");
+ res &= ~PGAERR;
+ }
+
+ if (res) ELOG("Flash programming error: %#010x\n", res);
+ return (-1);
+ }
+
+ return (0);
+}
+
+static inline uint32_t is_flash_locked(stlink_t *sl) {
+ /* return non zero for true */
+ uint32_t cr_lock_shift;
+ uint32_t cr_reg;
+ uint32_t n;
+
+ if (sl->flash_type == STM32_FLASH_TYPE_C0) {
+ cr_reg = FLASH_C0_CR;
+ cr_lock_shift = FLASH_C0_CR_LOCK;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_F0_F1_F3 ||
+ sl->flash_type == STM32_FLASH_TYPE_F1_XL) {
+ cr_reg = FLASH_CR;
+ cr_lock_shift = FLASH_CR_LOCK;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_F2_F4) {
+ cr_reg = FLASH_F4_CR;
+ cr_lock_shift = FLASH_F4_CR_LOCK;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_F7) {
+ cr_reg = FLASH_F7_CR;
+ cr_lock_shift = FLASH_F7_CR_LOCK;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_G0 ||
+ sl->flash_type == STM32_FLASH_TYPE_G4) {
+ cr_reg = FLASH_Gx_CR;
+ cr_lock_shift = FLASH_Gx_CR_LOCK;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_H7) {
+ cr_reg = FLASH_H7_CR1;
+ cr_lock_shift = FLASH_H7_CR_LOCK;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_L0_L1) {
+ cr_reg = get_stm32l0_flash_base(sl) + FLASH_PECR_OFF;
+ cr_lock_shift = FLASH_L0_PELOCK;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_L4) {
+ cr_reg = FLASH_L4_CR;
+ cr_lock_shift = FLASH_L4_CR_LOCK;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5) {
+ cr_reg = FLASH_L5_NSCR;
+ cr_lock_shift = FLASH_L5_NSCR_NSLOCK;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) {
+ cr_reg = FLASH_WB_CR;
+ cr_lock_shift = FLASH_WB_CR_LOCK;
+ } else {
+ ELOG("unsupported flash method, abort\n");
+ return (-1);
+ }
+
+ stlink_read_debug32(sl, cr_reg, &n);
+ return (n & (1u << cr_lock_shift));
+}
+
+static void unlock_flash(stlink_t *sl) {
+ uint32_t key_reg, key2_reg = 0;
+ uint32_t flash_key1 = FLASH_KEY1;
+ uint32_t flash_key2 = FLASH_KEY2;
+ /* The unlock sequence consists of 2 write cycles where 2 key values are
+ * written to the FLASH_KEYR register. An invalid sequence results in a
+ * definitive lock of the FPEC block until next reset.
+ */
+
+ if (sl->flash_type == STM32_FLASH_TYPE_C0) {
+ key_reg = FLASH_C0_KEYR;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_F0_F1_F3) {
+ key_reg = FLASH_KEYR;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_F1_XL) {
+ key_reg = FLASH_KEYR;
+ key2_reg = FLASH_KEYR2;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_F2_F4) {
+ key_reg = FLASH_F4_KEYR;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_F7) {
+ key_reg = FLASH_F7_KEYR;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_G0 ||
+ sl->flash_type == STM32_FLASH_TYPE_G4) {
+ key_reg = FLASH_Gx_KEYR;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_H7) {
+ key_reg = FLASH_H7_KEYR1;
+ if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) {
+ key2_reg = FLASH_H7_KEYR2;
+ }
+ } else if (sl->flash_type == STM32_FLASH_TYPE_L0_L1) {
+ key_reg = get_stm32l0_flash_base(sl) + FLASH_PEKEYR_OFF;
+ flash_key1 = FLASH_L0_PEKEY1;
+ flash_key2 = FLASH_L0_PEKEY2;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_L4) {
+ key_reg = FLASH_L4_KEYR;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5) {
+ // Set voltage scaling to range 0 to perform flash operations (RM0438 p. 183)
+ uint32_t mask = (0b11 << STM32L5_PWR_CR1_VOS);
+ uint32_t val;
+ if (!stlink_read_debug32(sl, STM32L5_PWR_CR1, &val) && (val & mask) > (1 << STM32L5_PWR_CR1_VOS)) {
+ val &= ~mask;
+ stlink_write_debug32(sl, STM32L5_PWR_CR1, val);
+ }
+ key_reg = FLASH_L5_NSKEYR;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) {
+ key_reg = FLASH_WB_KEYR;
+ } else {
+ ELOG("unsupported flash method, abort\n");
+ return;
+ }
+
+ stlink_write_debug32(sl, key_reg, flash_key1);
+ stlink_write_debug32(sl, key_reg, flash_key2);
+
+ if (key2_reg) {
+ stlink_write_debug32(sl, key2_reg, flash_key1);
+ stlink_write_debug32(sl, key2_reg, flash_key2);
+ }
+}
+
+/* unlock flash if already locked */
+int32_t unlock_flash_if(stlink_t *sl) {
+ if (is_flash_locked(sl)) {
+ unlock_flash(sl);
+
+ if (is_flash_locked(sl)) {
+ WLOG("Failed to unlock flash!\n");
+ return (-1);
+ }
+ }
+
+ DLOG("Successfully unlocked flash\n");
+ return (0);
+}
+
+int32_t lock_flash_option(stlink_t *sl) {
+ uint32_t optlock_shift, optcr_reg, n, optcr2_reg = 0;
+ int32_t active_bit_level = 1;
+
+ switch (sl->flash_type) {
+ case STM32_FLASH_TYPE_C0:
+ optcr_reg = FLASH_C0_CR;
+ optlock_shift = FLASH_C0_CR_OPTLOCK;
+ break;
+ case STM32_FLASH_TYPE_F0_F1_F3:
+ case STM32_FLASH_TYPE_F1_XL:
+ optcr_reg = FLASH_CR;
+ optlock_shift = FLASH_CR_OPTWRE;
+ active_bit_level = 0;
+ break;
+ case STM32_FLASH_TYPE_F2_F4:
+ optcr_reg = FLASH_F4_OPTCR;
+ optlock_shift = FLASH_F4_OPTCR_LOCK;
+ break;
+ case STM32_FLASH_TYPE_F7:
+ optcr_reg = FLASH_F7_OPTCR;
+ optlock_shift = FLASH_F7_OPTCR_LOCK;
+ break;
+ case STM32_FLASH_TYPE_G0:
+ case STM32_FLASH_TYPE_G4:
+ optcr_reg = FLASH_Gx_CR;
+ optlock_shift = FLASH_Gx_CR_OPTLOCK;
+ break;
+ case STM32_FLASH_TYPE_H7:
+ optcr_reg = FLASH_H7_OPTCR;
+ optlock_shift = FLASH_H7_OPTCR_OPTLOCK;
+ if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK)
+ optcr2_reg = FLASH_H7_OPTCR2;
+ break;
+ case STM32_FLASH_TYPE_L0_L1:
+ optcr_reg = get_stm32l0_flash_base(sl) + FLASH_PECR_OFF;
+ optlock_shift = FLASH_L0_OPTLOCK;
+ break;
+ case STM32_FLASH_TYPE_L4:
+ optcr_reg = FLASH_L4_CR;
+ optlock_shift = FLASH_L4_CR_OPTLOCK;
+ break;
+ case STM32_FLASH_TYPE_L5_U5_H5:
+ optcr_reg = FLASH_L5_NSCR;
+ optlock_shift = FLASH_L5_NSCR_OPTLOCK;
+ break;
+ case STM32_FLASH_TYPE_WB_WL:
+ optcr_reg = FLASH_WB_CR;
+ optlock_shift = FLASH_WB_CR_OPTLOCK;
+ break;
+ default:
+ ELOG("unsupported flash method, abort\n");
+ return -1;
+ }
+
+ stlink_read_debug32(sl, optcr_reg, &n);
+
+ if (active_bit_level == 0) {
+ n &= ~(1u << optlock_shift);
+ } else {
+ n |= (1u << optlock_shift);
+ }
+
+ stlink_write_debug32(sl, optcr_reg, n);
+
+ if (optcr2_reg) {
+ stlink_read_debug32(sl, optcr2_reg, &n);
+
+ if (active_bit_level == 0) {
+ n &= ~(1u << optlock_shift);
+ } else {
+ n |= (1u << optlock_shift);
+ }
+
+ stlink_write_debug32(sl, optcr2_reg, n);
+ }
+
+ return (0);
+}
+
+static bool is_flash_option_locked(stlink_t *sl) {
+ uint32_t optlock_shift, optcr_reg;
+ int32_t active_bit_level = 1;
+ uint32_t n;
+
+ switch (sl->flash_type) {
+ case STM32_FLASH_TYPE_C0:
+ optcr_reg = FLASH_C0_CR;
+ optlock_shift = FLASH_C0_CR_OPTLOCK;
+ break;
+ case STM32_FLASH_TYPE_F0_F1_F3:
+ case STM32_FLASH_TYPE_F1_XL:
+ optcr_reg = FLASH_CR;
+ optlock_shift = FLASH_CR_OPTWRE;
+ active_bit_level = 0; /* bit is "option write enable", not lock */
+ break;
+ case STM32_FLASH_TYPE_F2_F4:
+ optcr_reg = FLASH_F4_OPTCR;
+ optlock_shift = FLASH_F4_OPTCR_LOCK;
+ break;
+ case STM32_FLASH_TYPE_F7:
+ optcr_reg = FLASH_F7_OPTCR;
+ optlock_shift = FLASH_F7_OPTCR_LOCK;
+ break;
+ case STM32_FLASH_TYPE_G0:
+ case STM32_FLASH_TYPE_G4:
+ optcr_reg = FLASH_Gx_CR;
+ optlock_shift = FLASH_Gx_CR_OPTLOCK;
+ break;
+ case STM32_FLASH_TYPE_H7:
+ optcr_reg = FLASH_H7_OPTCR;
+ optlock_shift = FLASH_H7_OPTCR_OPTLOCK;
+ break;
+ case STM32_FLASH_TYPE_L0_L1:
+ optcr_reg = get_stm32l0_flash_base(sl) + FLASH_PECR_OFF;
+ optlock_shift = FLASH_L0_OPTLOCK;
+ break;
+ case STM32_FLASH_TYPE_L4:
+ optcr_reg = FLASH_L4_CR;
+ optlock_shift = FLASH_L4_CR_OPTLOCK;
+ break;
+ case STM32_FLASH_TYPE_L5_U5_H5:
+ optcr_reg = FLASH_L5_NSCR;
+ optlock_shift = FLASH_L5_NSCR_OPTLOCK;
+ break;
+ case STM32_FLASH_TYPE_WB_WL:
+ optcr_reg = FLASH_WB_CR;
+ optlock_shift = FLASH_WB_CR_OPTLOCK;
+ break;
+ default:
+ ELOG("unsupported flash method, abort\n");
+ return -1;
+ }
+
+ stlink_read_debug32(sl, optcr_reg, &n);
+
+ if (active_bit_level == 0) {
+ return (!(n & (1u << optlock_shift)));
+ }
+
+ return (n & (1u << optlock_shift));
+}
+
+static int32_t unlock_flash_option(stlink_t *sl) {
+ uint32_t optkey_reg, optkey2_reg = 0;
+ uint32_t optkey1 = FLASH_OPTKEY1;
+ uint32_t optkey2 = FLASH_OPTKEY2;
+
+ switch (sl->flash_type) {
+ case STM32_FLASH_TYPE_C0:
+ optkey_reg = FLASH_C0_OPT_KEYR;
+ break;
+ case STM32_FLASH_TYPE_F0_F1_F3:
+ case STM32_FLASH_TYPE_F1_XL:
+ optkey_reg = FLASH_OPTKEYR;
+ optkey1 = FLASH_F0_OPTKEY1;
+ optkey2 = FLASH_F0_OPTKEY2;
+ break;
+ case STM32_FLASH_TYPE_F2_F4:
+ optkey_reg = FLASH_F4_OPT_KEYR;
+ break;
+ case STM32_FLASH_TYPE_F7:
+ optkey_reg = FLASH_F7_OPT_KEYR;
+ break;
+ case STM32_FLASH_TYPE_G0:
+ case STM32_FLASH_TYPE_G4:
+ optkey_reg = FLASH_Gx_OPTKEYR;
+ break;
+ case STM32_FLASH_TYPE_H7:
+ optkey_reg = FLASH_H7_OPT_KEYR;
+ if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK)
+ optkey2_reg = FLASH_H7_OPT_KEYR2;
+ break;
+ case STM32_FLASH_TYPE_L0_L1:
+ optkey_reg = get_stm32l0_flash_base(sl) + FLASH_OPTKEYR_OFF;
+ optkey1 = FLASH_L0_OPTKEY1;
+ optkey2 = FLASH_L0_OPTKEY2;
+ break;
+ case STM32_FLASH_TYPE_L4:
+ optkey_reg = FLASH_L4_OPTKEYR;
+ break;
+ case STM32_FLASH_TYPE_L5_U5_H5:
+ optkey_reg = FLASH_L5_OPTKEYR;
+ break;
+ case STM32_FLASH_TYPE_WB_WL:
+ optkey_reg = FLASH_WB_OPT_KEYR;
+ break;
+ default:
+ ELOG("unsupported flash method, abort\n");
+ return (-1);
+ }
+
+ stlink_write_debug32(sl, optkey_reg, optkey1);
+ stlink_write_debug32(sl, optkey_reg, optkey2);
+
+ if (optkey2_reg) {
+ stlink_write_debug32(sl, optkey2_reg, optkey1);
+ stlink_write_debug32(sl, optkey2_reg, optkey2);
+ }
+
+ return (0);
+}
+
+int32_t unlock_flash_option_if(stlink_t *sl) {
+ if (is_flash_option_locked(sl)) {
+ if (unlock_flash_option(sl)) {
+ ELOG("Could not unlock flash option!\n");
+ return (-1);
+ }
+
+ if (is_flash_option_locked(sl)) {
+ ELOG("Failed to unlock flash option!\n");
+ return (-1);
+ }
+ }
+
+ DLOG("Successfully unlocked flash option\n");
+ return (0);
+}
+
+void write_flash_cr_psiz(stlink_t *sl, uint32_t n,
+ uint32_t bank) {
+ uint32_t cr_reg, psize_shift;
+ uint32_t x = read_flash_cr(sl, bank);
+
+ if (sl->flash_type == STM32_FLASH_TYPE_H7) {
+ cr_reg = (bank == BANK_1) ? FLASH_H7_CR1 : FLASH_H7_CR2;
+ psize_shift = FLASH_H7_CR_PSIZE;
+ } else {
+ cr_reg = FLASH_F4_CR;
+ psize_shift = 8;
+ }
+
+ x &= ~(0x03 << psize_shift);
+ x |= (n << psize_shift);
+#if DEBUG_FLASH
+ fprintf(stdout, "PSIZ:0x%x 0x%x\n", x, n);
+#endif
+ stlink_write_debug32(sl, cr_reg, x);
+}
+
+void clear_flash_cr_pg(stlink_t *sl, uint32_t bank) {
+ uint32_t cr_reg, n;
+ uint32_t bit = FLASH_CR_PG;
+
+ if (sl->flash_type == STM32_FLASH_TYPE_C0) {
+ cr_reg = FLASH_C0_CR;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_F2_F4) {
+ cr_reg = FLASH_F4_CR;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_F7) {
+ cr_reg = FLASH_F7_CR;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_G0 ||
+ sl->flash_type == STM32_FLASH_TYPE_G4) {
+ cr_reg = FLASH_Gx_CR;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_H7) {
+ cr_reg = (bank == BANK_1) ? FLASH_H7_CR1 : FLASH_H7_CR2;
+ bit = FLASH_H7_CR_PG;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_L4) {
+ cr_reg = FLASH_L4_CR;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5) {
+ cr_reg = FLASH_L5_NSCR;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) {
+ cr_reg = FLASH_WB_CR;
+ } else {
+ cr_reg = FLASH_CR;
+ }
+
+ n = read_flash_cr(sl, bank) & ~(1 << bit);
+ stlink_write_debug32(sl, cr_reg, n);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static void wait_flash_busy_progress(stlink_t *sl) {
+ int32_t i = 0;
+ fprintf(stdout, "Mass erasing...");
+ fflush(stdout);
+
+ while (is_flash_busy(sl)) {
+ usleep(10000);
+ i++;
+
+ if (i % 100 == 0) {
+ fprintf(stdout, ".");
+ fflush(stdout);
+ }
+ }
+
+ fprintf(stdout, "\n");
+}
+
+static inline void write_flash_ar(stlink_t *sl, uint32_t n, uint32_t bank) {
+ stlink_write_debug32(sl, (bank == BANK_1) ? FLASH_AR : FLASH_AR2, n);
+}
+
+static inline void write_flash_cr_snb(stlink_t *sl, uint32_t n, uint32_t bank) {
+ uint32_t cr_reg, snb_mask, snb_shift, ser_shift;
+ uint32_t x = read_flash_cr(sl, bank);
+
+ if (sl->flash_type == STM32_FLASH_TYPE_H7) {
+ cr_reg = (bank == BANK_1) ? FLASH_H7_CR1 : FLASH_H7_CR2;
+ snb_mask = FLASH_H7_CR_SNB_MASK;
+ snb_shift = FLASH_H7_CR_SNB;
+ ser_shift = FLASH_H7_CR_SER;
+ } else {
+ cr_reg = FLASH_F4_CR;
+ snb_mask = FLASH_F4_CR_SNB_MASK;
+ snb_shift = FLASH_F4_CR_SNB;
+ ser_shift = FLASH_F4_CR_SER;
+ }
+
+ x &= ~snb_mask;
+ x |= (n << snb_shift);
+ x |= (1 << ser_shift);
+#if DEBUG_FLASH
+ fprintf(stdout, "SNB:0x%x 0x%x\n", x, n);
+#endif
+ stlink_write_debug32(sl, cr_reg, x);
+}
+
+static void set_flash_cr_per(stlink_t *sl, uint32_t bank) {
+ uint32_t cr_reg, val;
+
+ if (sl->flash_type == STM32_FLASH_TYPE_C0) {
+ cr_reg = FLASH_C0_CR;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_G0 ||
+ sl->flash_type == STM32_FLASH_TYPE_G4) {
+ cr_reg = FLASH_Gx_CR;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5) {
+ cr_reg = FLASH_L5_NSCR;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) {
+ cr_reg = FLASH_WB_CR;
+ } else {
+ cr_reg = (bank == BANK_1) ? FLASH_CR : FLASH_CR2;
+ }
+
+ stlink_read_debug32(sl, cr_reg, &val);
+ val |= (1 << FLASH_CR_PER);
+ stlink_write_debug32(sl, cr_reg, val);
+}
+
+static void clear_flash_cr_per(stlink_t *sl, uint32_t bank) {
+ uint32_t cr_reg;
+
+ if (sl->flash_type == STM32_FLASH_TYPE_C0) {
+ cr_reg = FLASH_C0_CR;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_G0 ||
+ sl->flash_type == STM32_FLASH_TYPE_G4) {
+ cr_reg = FLASH_Gx_CR;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5) {
+ cr_reg = FLASH_L5_NSCR;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) {
+ cr_reg = FLASH_WB_CR;
+ } else {
+ cr_reg = (bank == BANK_1) ? FLASH_CR : FLASH_CR2;
+ }
+
+ const uint32_t n = read_flash_cr(sl, bank) & ~(1 << FLASH_CR_PER);
+ stlink_write_debug32(sl, cr_reg, n);
+}
+
+static inline void write_flash_cr_bker_pnb(stlink_t *sl, uint32_t n) {
+ stlink_write_debug32(sl, FLASH_L4_SR,
+ 0xFFFFFFFF & ~(1 << FLASH_L4_SR_BSY));
+ uint32_t x = read_flash_cr(sl, BANK_1);
+ x &= ~FLASH_L4_CR_OPBITS;
+ x &= ~FLASH_L4_CR_PAGEMASK;
+ x &= ~(1 << FLASH_L4_CR_MER1);
+ x &= ~(1 << FLASH_L4_CR_MER2);
+ x |= (n << FLASH_L4_CR_PNB);
+ x |= (uint32_t)(1lu << FLASH_L4_CR_PER);
+#if DEBUG_FLASH
+ fprintf(stdout, "BKER:PNB:0x%x 0x%x\n", x, n);
+#endif
+ stlink_write_debug32(sl, FLASH_L4_CR, x);
+}
+
+static void set_flash_cr_strt(stlink_t *sl, uint32_t bank) {
+ uint32_t val, cr_reg, cr_strt;
+
+ if (sl->flash_type == STM32_FLASH_TYPE_C0) {
+ cr_reg = FLASH_C0_CR;
+ cr_strt = 1 << FLASH_C0_CR_STRT;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_F2_F4) {
+ cr_reg = FLASH_F4_CR;
+ cr_strt = 1 << FLASH_F4_CR_STRT;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_F7) {
+ cr_reg = FLASH_F7_CR;
+ cr_strt = 1 << FLASH_F7_CR_STRT;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_G0 ||
+ sl->flash_type == STM32_FLASH_TYPE_G4) {
+ cr_reg = FLASH_Gx_CR;
+ cr_strt = (1 << FLASH_Gx_CR_STRT);
+ } else if (sl->flash_type == STM32_FLASH_TYPE_H7) {
+ cr_reg = (bank == BANK_1) ? FLASH_H7_CR1 : FLASH_H7_CR2;
+ cr_strt = 1 << FLASH_H7_CR_START(sl->chip_id);
+ } else if (sl->flash_type == STM32_FLASH_TYPE_L4) {
+ cr_reg = FLASH_L4_CR;
+ cr_strt = (1 << FLASH_L4_CR_STRT);
+ } else if (sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5) {
+ cr_reg = FLASH_L5_NSCR;
+ cr_strt = (1 << FLASH_L5_NSCR_NSSTRT);
+ } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) {
+ cr_reg = FLASH_WB_CR;
+ cr_strt = (1 << FLASH_WB_CR_STRT);
+ } else {
+ cr_reg = (bank == BANK_1) ? FLASH_CR : FLASH_CR2;
+ cr_strt = (1 << FLASH_CR_STRT);
+ }
+
+ stlink_read_debug32(sl, cr_reg, &val);
+ val |= cr_strt;
+ stlink_write_debug32(sl, cr_reg, val);
+}
+
+static void set_flash_cr_mer(stlink_t *sl, bool v, uint32_t bank) {
+ uint32_t val, cr_reg, cr_mer, cr_pg;
+
+ if (sl->flash_type == STM32_FLASH_TYPE_C0) {
+ cr_reg = FLASH_C0_CR;
+ cr_mer = 1 << FLASH_CR_MER;
+ cr_pg = 1 << FLASH_CR_PG;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_F2_F4) {
+ cr_reg = FLASH_F4_CR;
+ cr_mer = 1 << FLASH_CR_MER;
+ cr_pg = 1 << FLASH_CR_PG;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_F7) {
+ cr_reg = FLASH_F7_CR;
+ cr_mer = 1 << FLASH_CR_MER;
+ cr_pg = 1 << FLASH_CR_PG;
+ } else if (sl->flash_type == STM32_FLASH_TYPE_G0 ||
+ sl->flash_type == STM32_FLASH_TYPE_G4) {
+ cr_reg = FLASH_Gx_CR;
+ cr_mer = (1 << FLASH_Gx_CR_MER1);
+ if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) {
+ cr_mer |= (1 << FLASH_Gx_CR_MER2);
+ }
+ cr_pg = (1 << FLASH_CR_PG);
+ } else if (sl->flash_type == STM32_FLASH_TYPE_H7) {
+ cr_reg = (bank == BANK_1) ? FLASH_H7_CR1 : FLASH_H7_CR2;
+ cr_mer = (1 << FLASH_H7_CR_BER);
+ cr_pg = (1 << FLASH_H7_CR_PG);
+ } else if (sl->flash_type == STM32_FLASH_TYPE_L4) {
+ cr_reg = FLASH_L4_CR;
+ cr_mer = (1 << FLASH_L4_CR_MER1) | (1 << FLASH_L4_CR_MER2);
+ cr_pg = (1 << FLASH_L4_CR_PG);
+ } else if (sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5) {
+ cr_reg = FLASH_L5_NSCR;
+ cr_mer = (1 << FLASH_L5_NSCR_NSMER1) | (1 << FLASH_L5_NSCR_NSMER2);
+ cr_pg = (1 << FLASH_L5_NSCR_NSPG);
+ } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) {
+ cr_reg = FLASH_WB_CR;
+ cr_mer = (1 << FLASH_CR_MER);
+ cr_pg = (1 << FLASH_CR_PG);
+ } else {
+ cr_reg = (bank == BANK_1) ? FLASH_CR : FLASH_CR2;
+ cr_mer = (1 << FLASH_CR_MER);
+ cr_pg = (1 << FLASH_CR_PG);
+ }
+
+ stlink_read_debug32(sl, cr_reg, &val);
+
+ if (val & cr_pg) {
+ // STM32F030 will drop MER bit if PG was set
+ val &= ~cr_pg;
+ stlink_write_debug32(sl, cr_reg, val);
+ }
+
+ if (v) {
+ val |= cr_mer;
+ } else {
+ val &= ~cr_mer;
+ }
+
+ stlink_write_debug32(sl, cr_reg, val);
+}
+
+/**
+ * Erase a page of flash, assumes sl is fully populated with things like
+ * chip/core ids
+ * @param sl stlink context
+ * @param flashaddr an address in the flash page to erase
+ * @return 0 on success -ve on failure
+ */
+int32_t stlink_erase_flash_page(stlink_t *sl, stm32_addr_t flashaddr) {
+ // wait for ongoing op to finish
+ wait_flash_busy(sl);
+ // clear flash IO errors
+ clear_flash_error(sl);
+
+ if (sl->flash_type == STM32_FLASH_TYPE_F2_F4 ||
+ sl->flash_type == STM32_FLASH_TYPE_F7 ||
+ sl->flash_type == STM32_FLASH_TYPE_L4) {
+ // unlock if locked
+ unlock_flash_if(sl);
+
+ // select the page to erase
+ if (sl->flash_type == STM32_FLASH_TYPE_L4) {
+ // calculate the actual bank+page from the address
+ uint32_t page = calculate_L4_page(sl, flashaddr);
+
+ fprintf(stderr, "EraseFlash - Page:0x%x Size:0x%x ", page,
+ stlink_calculate_pagesize(sl, flashaddr));
+
+ write_flash_cr_bker_pnb(sl, page);
+ } else if (sl->chip_id == STM32_CHIPID_F7 ||
+ sl->chip_id == STM32_CHIPID_F76xxx) {
+ // calculate the actual page from the address
+ uint32_t sector = calculate_F7_sectornum(flashaddr);
+
+ fprintf(stderr, "EraseFlash - Sector:0x%x Size:0x%x ", sector,
+ stlink_calculate_pagesize(sl, flashaddr));
+ write_flash_cr_snb(sl, sector, BANK_1);
+ } else {
+ // calculate the actual page from the address
+ uint32_t sector = calculate_F4_sectornum(flashaddr);
+
+ fprintf(stderr, "EraseFlash - Sector:0x%x Size:0x%x ", sector,
+ stlink_calculate_pagesize(sl, flashaddr));
+
+ // the SNB values for flash sectors in the second bank do not directly
+ // follow the values for the first bank on 2mb devices...
+ if (sector >= 12) {
+ sector += 4;
+ }
+
+ write_flash_cr_snb(sl, sector, BANK_1);
+ }
+
+ set_flash_cr_strt(sl, BANK_1); // start erase operation
+ wait_flash_busy(sl); // wait for completion
+ lock_flash(sl); // TODO: fails to program if this is in
+#if DEBUG_FLASH
+ fprintf(stdout, "Erase Final CR:0x%x\n", read_flash_cr(sl, BANK_1));
+#endif
+ } else if (sl->flash_type == STM32_FLASH_TYPE_L0_L1) {
+
+ uint32_t val;
+ uint32_t flash_regs_base = get_stm32l0_flash_base(sl);
+
+ // check if the locks are set
+ stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
+
+ if ((val & (1 << 0)) || (val & (1 << 1))) {
+ // disable pecr protection
+ stlink_write_debug32(sl, flash_regs_base + FLASH_PEKEYR_OFF, FLASH_L0_PEKEY1);
+ stlink_write_debug32(sl, flash_regs_base + FLASH_PEKEYR_OFF, FLASH_L0_PEKEY2);
+
+ // check pecr.pelock is cleared
+ stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
+
+ if (val & (1 << 0)) {
+ WLOG("pecr.pelock not clear (%#x)\n", val);
+ return (-1);
+ }
+
+ // unlock program memory
+ stlink_write_debug32(sl, flash_regs_base + FLASH_PRGKEYR_OFF, FLASH_L0_PRGKEY1);
+ stlink_write_debug32(sl, flash_regs_base + FLASH_PRGKEYR_OFF, FLASH_L0_PRGKEY2);
+
+ // check pecr.prglock is cleared
+ stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
+
+ if (val & (1 << 1)) {
+ WLOG("pecr.prglock not clear (%#x)\n", val);
+ return (-1);
+ }
+ }
+
+ // set pecr.{erase,prog}
+ val |= (1 << 9) | (1 << 3);
+ stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val);
+
+ // write 0 to the first word of the page to be erased
+ stlink_write_debug32(sl, flashaddr, 0);
+
+ /* MP: It is better to wait for clearing the busy bit after issuing page
+ * erase command, even though PM0062 recommends to wait before it.
+ * Test shows that a few iterations is performed in the following loop
+ * before busy bit is cleared.
+ */
+ wait_flash_busy(sl);
+
+ // reset lock bits
+ stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
+ val |= (1 << 0) | (1 << 1) | (1 << 2);
+ stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val);
+ } else if (sl->flash_type == STM32_FLASH_TYPE_G0 ||
+ sl->flash_type == STM32_FLASH_TYPE_G4 ||
+ sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5 ||
+ sl->flash_type == STM32_FLASH_TYPE_WB_WL ||
+ sl->flash_type == STM32_FLASH_TYPE_C0) {
+ uint32_t val;
+ unlock_flash_if(sl);
+ set_flash_cr_per(sl, BANK_1); // set the 'enable Flash erase' bit
+
+ // set the page to erase
+ if (sl->flash_type == STM32_FLASH_TYPE_G0) {
+ uint32_t flash_page = ((flashaddr - STM32_FLASH_BASE) / sl->flash_pgsz);
+ stlink_read_debug32(sl, FLASH_Gx_CR, &val);
+ // sec 3.7.5 - PNB[9:0] is offset by 3. PER is 0x2.
+ val &= ~(0x3FF << 3);
+ val |= ((flash_page & 0x3FF) << 3) | (1 << FLASH_CR_PER);
+ stlink_write_debug32(sl, FLASH_Gx_CR, val);
+ } else if (sl->flash_type == STM32_FLASH_TYPE_G4) {
+ uint32_t flash_page = ((flashaddr - STM32_FLASH_BASE) / sl->flash_pgsz);
+ stlink_read_debug32(sl, FLASH_Gx_CR, &val);
+ // sec 3.7.5 - PNB[9:0] is offset by 3. PER is 0x2.
+ val &= ~(0x7FF << 3);
+ val |= ((flash_page & 0x7FF) << 3) | (1 << FLASH_CR_PER);
+ stlink_write_debug32(sl, FLASH_Gx_CR, val);
+ // STM32L5x2xx has two banks with 2k pages or single with 4k pages
+ // STM32H5xx, STM32U535, STM32U545, STM32U575 or STM32U585 have 2 banks with 8k pages
+ } else if (sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5) {
+ uint32_t flash_page;
+ stlink_read_debug32(sl, FLASH_L5_NSCR, &val);
+ if ((sl->flash_pgsz == 0x800 || sl->flash_pgsz == 0x2000) && (flashaddr - STM32_FLASH_BASE) >= sl->flash_size/2) {
+ flash_page = (flashaddr - STM32_FLASH_BASE - sl->flash_size/2) / sl->flash_pgsz;
+ // set bank 2 for erasure
+ val |= (1 << FLASH_L5_NSCR_NSBKER);
+ } else {
+ flash_page = ((flashaddr - STM32_FLASH_BASE) / sl->flash_pgsz);
+ // set bank 1 for erasure
+ val &= ~(1 << FLASH_L5_NSCR_NSBKER);
+ }
+ // sec 7.9.9 for U5, 6.9.9 for L5 (for L7 we have 7 bits instead of 8 bits for U5 but
+ // the bit position for 8th bit reserved.
+ // Maybe the best solution is to handle each one separately.
+ val &= ~(0xFF << 3);
+ val |= ((flash_page & 0xFF) << 3) | (1 << FLASH_CR_PER);
+ stlink_write_debug32(sl, FLASH_L5_NSCR, val);
+ } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) {
+ uint32_t flash_page = ((flashaddr - STM32_FLASH_BASE) / sl->flash_pgsz);
+ stlink_read_debug32(sl, FLASH_WB_CR, &val);
+
+ // sec 3.10.5 - PNB[7:0] is offset by 3.
+ val &= ~(0xFF << 3); // Clear previously set page number (if any)
+ val |= ((flash_page & 0xFF) << 3);
+
+ stlink_write_debug32(sl, FLASH_WB_CR, val);
+ } else if (sl->flash_type == STM32_FLASH_TYPE_C0) {
+ uint32_t flash_page = ((flashaddr - STM32_FLASH_BASE) / sl->flash_pgsz);
+ stlink_read_debug32(sl, FLASH_C0_CR, &val);
+
+ val &= ~(0xF << FLASH_C0_CR_PNB);
+ val |= ((flash_page & 0xF) << FLASH_C0_CR_PNB);
+
+ stlink_write_debug32(sl, FLASH_C0_CR, val);
+ }
+
+ set_flash_cr_strt(sl, BANK_1); // set the 'start operation' bit
+ wait_flash_busy(sl); // wait for the 'busy' bit to clear
+ clear_flash_cr_per(sl, BANK_1); // clear the 'enable page erase' bit
+ lock_flash(sl);
+ } else if (sl->flash_type == STM32_FLASH_TYPE_F0_F1_F3 ||
+ sl->flash_type == STM32_FLASH_TYPE_F1_XL) {
+ uint32_t bank = (flashaddr < STM32_F1_FLASH_BANK2_BASE) ? BANK_1 : BANK_2;
+ unlock_flash_if(sl);
+ clear_flash_cr_pg(sl, bank); // clear the pg bit
+ set_flash_cr_per(sl, bank); // set the page erase bit
+ write_flash_ar(sl, flashaddr, bank); // select the page to erase
+ set_flash_cr_strt(sl, bank); // start erase operation, reset by hw with busy bit
+ wait_flash_busy(sl);
+ clear_flash_cr_per(sl, bank); // clear the page erase bit
+ lock_flash(sl);
+ } else if (sl->flash_type == STM32_FLASH_TYPE_H7) {
+ uint32_t bank = (flashaddr < STM32_H7_FLASH_BANK2_BASE) ? BANK_1 : BANK_2;
+ unlock_flash_if(sl); // unlock if locked
+ uint32_t sector = calculate_H7_sectornum(sl, flashaddr, bank); // calculate the actual page from the address
+ write_flash_cr_snb(sl, sector, bank); // select the page to erase
+ set_flash_cr_strt(sl, bank); // start erase operation
+ wait_flash_busy(sl); // wait for completion
+ lock_flash(sl);
+ } else {
+ WLOG("unknown coreid %x, page erase failed\n", sl->core_id);
+ return (-1);
+ }
+
+ return check_flash_error(sl);
+}
+
+int32_t stlink_erase_flash_section(stlink_t *sl, stm32_addr_t base_addr, uint32_t size, bool align_size) {
+ // Check the address and size validity
+ if (stlink_check_address_range_validity(sl, base_addr, size) < 0) {
+ return -1;
+ }
+
+ // Make sure the requested address is aligned with the beginning of a page
+ if (stlink_check_address_alignment(sl, base_addr) < 0) {
+ ELOG("The address to erase is not aligned with the beginning of a page\n");
+ return -1;
+ }
+
+ stm32_addr_t addr = base_addr;
+ do {
+ uint32_t page_size = stlink_calculate_pagesize(sl, addr);
+
+ // Check if size is aligned with a page, unless we want to completely erase the last page
+ if ((addr + page_size) > (base_addr + size) && !align_size) {
+ ELOG("Invalid size (not aligned with a page). Page size at address %#x is %#x\n", addr, page_size);
+ return (-1);
+ }
+
+ if (stlink_erase_flash_page(sl, addr)) {
+ WLOG("Failed to erase_flash_page(%#x) == -1\n", addr);
+ return (-1);
+ }
+
+ fprintf(stdout, "-> Flash page at %#x erased (size: %#x)\r", addr, page_size);
+ fflush(stdout);
+
+ // check the next page is within the range to erase
+ addr += page_size;
+ } while (addr < (base_addr + size));
+
+ fprintf(stdout, "\n");
+ return 0;
+}
+
+int32_t stlink_erase_flash_mass(stlink_t *sl) {
+ int32_t err = 0;
+
+ // TODO: Use MER bit to mass-erase WB series.
+ if (sl->flash_type == STM32_FLASH_TYPE_L0_L1 ||
+ sl->flash_type == STM32_FLASH_TYPE_WB_WL) {
+
+ err = stlink_erase_flash_section(sl, sl->flash_base, sl->flash_size, false);
+
+ } else {
+ wait_flash_busy(sl);
+ clear_flash_error(sl);
+ unlock_flash_if(sl);
+
+ if (sl->flash_type == STM32_FLASH_TYPE_H7 && sl->chip_id != STM32_CHIPID_H7Ax) {
+ // set parallelism
+ write_flash_cr_psiz(sl, 3 /*64bit*/, BANK_1);
+ if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) {
+ write_flash_cr_psiz(sl, 3 /*64bit*/, BANK_2);
+ }
+ }
+
+ set_flash_cr_mer(sl, 1, BANK_1); // set the mass erase bit
+ set_flash_cr_strt(sl, BANK_1); // start erase operation, reset by hw with busy bit
+
+ if (sl->flash_type == STM32_FLASH_TYPE_F1_XL ||
+ (sl->flash_type == STM32_FLASH_TYPE_H7 && sl->chip_flags & CHIP_F_HAS_DUAL_BANK)) {
+ set_flash_cr_mer(sl, 1, BANK_2); // set the mass erase bit in bank 2
+ set_flash_cr_strt(sl, BANK_2); // start erase operation in bank 2
+ }
+
+ wait_flash_busy_progress(sl);
+ lock_flash(sl);
+
+ // reset the mass erase bit
+ set_flash_cr_mer(sl, 0, BANK_1);
+ if (sl->flash_type == STM32_FLASH_TYPE_F1_XL ||
+ (sl->flash_type == STM32_FLASH_TYPE_H7 && sl->chip_flags & CHIP_F_HAS_DUAL_BANK)) {
+ set_flash_cr_mer(sl, 0, BANK_2);
+ }
+
+ err = check_flash_error(sl);
+ }
+
+ return (err);
+}
+
+int32_t stlink_mwrite_flash(stlink_t *sl, uint8_t *data, uint32_t length, stm32_addr_t addr) {
+ /* Write the block in flash at addr */
+ int32_t err;
+ uint32_t num_empty, idx;
+ uint8_t erased_pattern = stlink_get_erased_pattern(sl);
+
+ /*
+ * This optimisation may cause unexpected garbage data remaining.
+ * Therfore it is turned off by default.
+ */
+ if (sl->opt) {
+ idx = length;
+
+ for (num_empty = 0; num_empty != length; ++num_empty)
+ if (data[--idx] != erased_pattern) {
+ break;
+ }
+
+ num_empty -= (num_empty & 3); // Round down to words
+
+ if (num_empty != 0) {
+ ILOG("Ignoring %d bytes of 0x%02x at end of file\n", num_empty, erased_pattern);
+ }
+ } else {
+ num_empty = 0;
+ }
+
+ /*
+ * TODO: investigate a kind of weird behaviour here:
+ * If the file is identified to be all-empty and four-bytes aligned,
+ * still flash the whole file even if ignoring message is printed.
+ */
+ err = stlink_write_flash(sl, addr, data,
+ (num_empty == length) ? length : length - num_empty,
+ num_empty == length);
+ stlink_fwrite_finalize(sl, addr);
+ return (err);
+}
+
+/**
+ * Write the given binary file into flash at address "addr"
+ * @param sl
+ * @param path readable file path, should be binary image
+ * @param addr where to start writing
+ * @return 0 on success, -ve on failure.
+ */
+int32_t stlink_fwrite_flash(stlink_t *sl, const char *path, stm32_addr_t addr) {
+ /* Write the file in flash at addr */
+ int32_t err;
+ uint32_t num_empty, idx;
+ uint8_t erased_pattern = stlink_get_erased_pattern(sl);
+ mapped_file_t mf = MAPPED_FILE_INITIALIZER;
+
+ if (map_file(&mf, path) == -1) {
+ ELOG("map_file() == -1\n");
+ return (-1);
+ }
+
+ printf("file %s ", path);
+ md5_calculate(&mf);
+ stlink_checksum(&mf);
+
+ if (sl->opt) {
+ idx = (uint32_t)mf.len;
+
+ for (num_empty = 0; num_empty != mf.len; ++num_empty) {
+ if (mf.base[--idx] != erased_pattern) {
+ break;
+ }
+ }
+
+ num_empty -= (num_empty & 3); // round down to words
+
+ if (num_empty != 0) {
+ ILOG("Ignoring %d bytes of 0x%02x at end of file\n", num_empty, erased_pattern);
+ }
+ } else {
+ num_empty = 0;
+ }
+
+ /*
+ * TODO: investigate a kind of weird behaviour here:
+ * If the file is identified to be all-empty and four-bytes aligned,
+ * still flash the whole file even if ignoring message is printed.
+ */
+
+ /* In case the address is within the OTP area we use a different flash method */
+ if(addr >= sl->otp_base && addr < sl->otp_base + sl->otp_size) {
+ err = stlink_write_otp(sl, addr, mf.base,
+ (num_empty == mf.len) ? (uint32_t)mf.len : (uint32_t)mf.len - num_empty);
+ } else {
+ err = stlink_write_flash(sl, addr, mf.base,
+ (num_empty == mf.len) ? (uint32_t)mf.len : (uint32_t)mf.len - num_empty,
+ num_empty == mf.len);
+ }
+ stlink_fwrite_finalize(sl, addr);
+ unmap_file(&mf);
+ return (err);
+}
+
+
+int32_t stlink_fcheck_flash(stlink_t *sl, const char *path, stm32_addr_t addr) {
+ // check the contents of path are at addr
+
+ int32_t res;
+ mapped_file_t mf = MAPPED_FILE_INITIALIZER;
+
+ if (map_file(&mf, path) == -1) {
+ return (-1);
+ }
+
+ res = check_file(sl, &mf, addr);
+ unmap_file(&mf);
+ return (res);
+}
+
+/**
+ * Verify addr..addr+len is binary identical to base...base+len
+ * @param sl stlink context
+ * @param address stm device address
+ * @param data host side buffer to check against
+ * @param length how much
+ * @return 0 for success, -ve for failure
+ */
+int32_t stlink_verify_write_flash(stlink_t *sl, stm32_addr_t address, uint8_t *data, uint32_t length) {
+ uint32_t off;
+ uint32_t cmp_size = (sl->flash_pgsz > 0x1800) ? 0x1800 : sl->flash_pgsz;
+ ILOG("Starting verification of write complete\n");
+
+ for (off = 0; off < length; off += cmp_size) {
+ uint32_t aligned_size;
+
+ // adjust last page size
+ if ((off + cmp_size) > length) {
+ cmp_size = length - off;
+ }
+
+ aligned_size = cmp_size;
+
+ if (aligned_size & (4 - 1)) {
+ aligned_size = (cmp_size + 4) & ~(4 - 1);
+ }
+
+ stlink_read_mem32(sl, address + off, (uint16_t)aligned_size);
+
+ if (memcmp(sl->q_buf, data + off, cmp_size)) {
+ ELOG("Verification of flash failed at offset: %u\n", off);
+ return (-1);
+ }
+ }
+
+ ILOG("Flash written and verified! jolly good!\n");
+ return (0);
+}
+
+// Check if an address and size are within the flash
+int32_t stlink_check_address_range_validity(stlink_t *sl, stm32_addr_t addr, uint32_t size) {
+ uint32_t logvar;
+ if (addr < sl->flash_base || addr >= (sl->flash_base + sl->flash_size)) {
+ logvar = sl->flash_base + sl->flash_size - 1;
+ ELOG("Invalid address, it should be within 0x%08x - 0x%08x\n", sl->flash_base, logvar);
+ return (-1);
+ }
+ if ((addr + size) > (sl->flash_base + sl->flash_size)) {
+ logvar = sl->flash_base + sl->flash_size - addr;
+ ELOG("The size exceeds the size of the flash (0x%08x bytes available)\n", logvar);
+ return (-1);
+ }
+ return 0;
+}
+
+// Check if an address and size are within the flash (otp area)
+int32_t stlink_check_address_range_validity_otp(stlink_t *sl, stm32_addr_t addr, uint32_t size) {
+ uint32_t logvar;
+ if (addr < sl->otp_base || addr >= (sl->otp_base + sl->otp_size)) {
+ logvar = sl->otp_base + sl->otp_size - 1;
+ ELOG("Invalid address, it should be within 0x%08x - 0x%08x\n", sl->otp_base, logvar);
+ return (-1);
+ }
+ if ((addr + size) >= (sl->otp_base + sl->otp_size)) {
+ logvar = sl->otp_base + sl->otp_size - addr;
+ ELOG("The size exceeds the size of the OTP Area (0x%08x bytes available)\n", logvar);
+ return (-1);
+ }
+ return 0;
+}
+
+// Check if an address is aligned with the beginning of a page
+int32_t stlink_check_address_alignment(stlink_t *sl, stm32_addr_t addr) {
+ stm32_addr_t page = sl->flash_base;
+
+ while (page < addr) {
+ page += stlink_calculate_pagesize(sl, page);
+ }
+
+ if (page != addr) {
+ return -1;
+ }
+
+ return 0;
+}
+
+int32_t stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len, uint8_t eraseonly) {
+ int32_t ret;
+ flash_loader_t fl;
+ ILOG("Attempting to write %d (%#x) bytes to stm32 address: %u (%#x)\n", len, len, addr, addr);
+
+ // check addr range is inside the flash
+ stlink_calculate_pagesize(sl, addr);
+
+ // Check the address and size validity
+ if (stlink_check_address_range_validity(sl, addr, len) < 0) {
+ return (-1);
+ } else if (len & 1) {
+ WLOG("unaligned len 0x%x -- padding with zero\n", len);
+ len += 1;
+ } else if (stlink_check_address_alignment(sl, addr) < 0) {
+ ELOG("addr not a multiple of current pagesize (%u bytes), not supported, "
+ "check page start address and compare with flash module organisation "
+ "in related ST reference manual of your device.\n",
+ sl->flash_pgsz);
+ return (-1);
+ }
+
+ // make sure we've loaded the context with the chip details
+ stlink_core_id(sl);
+
+ // Erase this section of the flash
+ if (stlink_erase_flash_section(sl, addr, len, true) < 0) {
+ ELOG("Failed to erase the flash prior to writing\n");
+ return (-1);
+ }
+
+ if (eraseonly) {
+ return (0);
+ }
+
+ ret = stlink_flashloader_start(sl, &fl);
+ if (ret)
+ return ret;
+ ret = stlink_flashloader_write(sl, &fl, addr, base, len);
+ if (ret)
+ return ret;
+ ret = stlink_flashloader_stop(sl, &fl);
+ if (ret)
+ return ret;
+
+ return (stlink_verify_write_flash(sl, addr, base, len));
+}
+
+int32_t stlink_write_otp(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) {
+ int32_t ret;
+ flash_loader_t fl;
+ ILOG("Attempting to write %d (%#x) bytes to stm32 address: %u (%#x)\n", len, len, addr, addr);
+
+ // Check the address and size validity
+ if (stlink_check_address_range_validity_otp(sl, addr, len) < 0) {
+ return (-1);
+ }
+
+ // make sure we've loaded the context with the chip details
+ stlink_core_id(sl);
+
+ ret = stlink_flashloader_start(sl, &fl);
+ if (ret)
+ return ret;
+ ret = stlink_flashloader_write(sl, &fl, addr, base, len);
+ if (ret)
+ return ret;
+ ret = stlink_flashloader_stop(sl, &fl);
+ if (ret)
+ return ret;
+
+ return (stlink_verify_write_flash(sl, addr, base, len));
+}
+
+void stlink_fwrite_finalize(stlink_t *sl, stm32_addr_t addr) {
+ uint32_t val;
+ // set PC to the reset routine
+ stlink_read_debug32(sl, addr + 4, &val);
+ stlink_write_reg(sl, val, 15);
+ stlink_run(sl, RUN_NORMAL);
+}
diff --git a/src/stlink-lib/common_flash.h b/src/stlink-lib/common_flash.h
new file mode 100644
index 0000000..238f040
--- /dev/null
+++ b/src/stlink-lib/common_flash.h
@@ -0,0 +1,53 @@
+/*
+ * File: common_flash.h
+ *
+ * Flash operations
+ */
+
+#ifndef COMMON_FLASH_H
+#define COMMON_FLASH_H
+
+#define BANK_1 0
+#define BANK_2 1
+
+uint32_t get_stm32l0_flash_base(stlink_t *);
+uint32_t read_flash_cr(stlink_t *, uint32_t);
+void lock_flash(stlink_t *);
+// static inline int32_t write_flash_sr(stlink_t *sl, uint32_t bank, uint32_t val);
+void clear_flash_error(stlink_t *);
+uint32_t read_flash_sr(stlink_t *sl, uint32_t bank);
+uint32_t is_flash_busy(stlink_t *sl);
+void wait_flash_busy(stlink_t *);
+int32_t check_flash_error(stlink_t *);
+// static inline uint32_t is_flash_locked(stlink_t *sl);
+// static void unlock_flash(stlink_t *sl);
+int32_t unlock_flash_if(stlink_t *);
+int32_t lock_flash_option(stlink_t *);
+// static bool is_flash_option_locked(stlink_t *sl);
+// static int32_t unlock_flash_option(stlink_t *sl);
+int32_t unlock_flash_option_if(stlink_t *);
+void write_flash_cr_psiz(stlink_t *, uint32_t, uint32_t);
+void clear_flash_cr_pg(stlink_t *, uint32_t);
+// static void wait_flash_busy_progress(stlink_t *sl);
+// static inline void write_flash_ar(stlink_t *sl, uint32_t n, uint32_t bank);
+// static inline void write_flash_cr_snb(stlink_t *sl, uint32_t n, uint32_t bank);
+// static void set_flash_cr_per(stlink_t *sl, uint32_t bank);
+// static void clear_flash_cr_per(stlink_t *sl, uint32_t bank);
+// static inline void write_flash_cr_bker_pnb(stlink_t *sl, uint32_t n);
+// static void set_flash_cr_strt(stlink_t *sl, uint32_t bank);
+// static void set_flash_cr_mer(stlink_t *sl, bool v, uint32_t bank);
+int32_t stlink_erase_flash_page(stlink_t *sl, stm32_addr_t flashaddr);
+int32_t stlink_erase_flash_section(stlink_t *sl, stm32_addr_t base_addr, uint32_t size, bool align_size);
+int32_t stlink_erase_flash_mass(stlink_t *sl);
+int32_t stlink_mwrite_flash(stlink_t *sl, uint8_t *data, uint32_t length, stm32_addr_t addr);
+int32_t stlink_fwrite_flash(stlink_t *sl, const char *path, stm32_addr_t addr);
+int32_t stlink_fcheck_flash(stlink_t *sl, const char *path, stm32_addr_t addr);
+int32_t stlink_verify_write_flash(stlink_t *sl, stm32_addr_t address, uint8_t *data, uint32_t length);
+int32_t stlink_check_address_range_validity(stlink_t *sl, stm32_addr_t addr, uint32_t size);
+int32_t stlink_check_address_range_validity_otp(stlink_t *sl, stm32_addr_t addr, uint32_t size);
+int32_t stlink_check_address_alignment(stlink_t *sl, stm32_addr_t addr);
+int32_t stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len, uint8_t eraseonly);
+int32_t stlink_write_otp(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len);
+void stlink_fwrite_finalize(stlink_t *, stm32_addr_t);
+
+#endif // COMMON_FLASH_H
diff --git a/src/stlink-lib/flash_loader.c b/src/stlink-lib/flash_loader.c
index ba5efdb..16c717c 100644
--- a/src/stlink-lib/flash_loader.c
+++ b/src/stlink-lib/flash_loader.c
@@ -1,78 +1,85 @@
+/*
+ * File: flash_loader.c
+ *
+ * Flash loaders
+ */
+
+#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
+#include <stm32.h>
#include <stlink.h>
-#include <helper.h>
#include "flash_loader.h"
-#define FLASH_REGS_BANK2_OFS 0x40
-#define FLASH_BANK2_START_ADDR 0x08080000
+#include "common_flash.h"
+#include "helper.h"
+#include "logging.h"
+#include "read_write.h"
+#include "register.h"
+
+#define FLASH_REGS_BANK2_OFS 0x40
+#define FLASH_BANK2_START_ADDR 0x08080000
#define STM32F0_WDG_KR 0x40003000
#define STM32H7_WDG_KR 0x58004800
#define STM32F0_WDG_KR_KEY_RELOAD 0xAAAA
-/* DO NOT MODIFY SOURCECODE DIRECTLY, EDIT ASSEMBLY FILES INSTEAD */
+/*
+ * !!! DO NOT MODIFY FLASH LOADERS DIRECTLY !!!
+ *
+ * Edit assembly files in the '/flashloaders' instead. The sizes of binary
+ * flash loaders must be aligned by 4 (it's written by stlink_write_mem32)
+ */
-/* flashloaders/stm32f0.s -- compiled with thumb2 */
+// flashloaders/stm32f0.s -- compiled with thumb2
static const uint8_t loader_code_stm32vl[] = {
0x00, 0xbf, 0x00, 0xbf,
- 0x0e, 0x4f, 0x1f, 0x44,
- 0x0e, 0x4e, 0x3e, 0x44,
- 0x0e, 0x4d, 0x3d, 0x44,
- 0x4f, 0xf0, 0x01, 0x04,
- 0x34, 0x60, 0x04, 0x88,
- 0x0c, 0x80, 0x02, 0x30,
- 0x02, 0x31, 0x4f, 0xf0,
- 0x01, 0x07, 0x2c, 0x68,
- 0x3c, 0x42, 0xfc, 0xd1,
- 0x4f, 0xf0, 0x14, 0x07,
- 0x3c, 0x42, 0x01, 0xd1,
- 0x02, 0x3a, 0xf0, 0xdc,
+ 0x09, 0x4f, 0x1f, 0x44,
+ 0x09, 0x4d, 0x3d, 0x44,
+ 0x04, 0x88, 0x0c, 0x80,
+ 0x02, 0x30, 0x02, 0x31,
0x4f, 0xf0, 0x01, 0x07,
- 0x34, 0x68, 0xbc, 0x43,
- 0x34, 0x60, 0x00, 0xbe,
+ 0x2c, 0x68, 0x3c, 0x42,
+ 0xfc, 0xd1, 0x4f, 0xf0,
+ 0x14, 0x07, 0x3c, 0x42,
+ 0x01, 0xd1, 0x02, 0x3a,
+ 0xf0, 0xdc, 0x00, 0xbe,
0x00, 0x20, 0x02, 0x40,
- 0x10, 0x00, 0x00, 0x00,
0x0c, 0x00, 0x00, 0x00
};
-/* flashloaders/stm32f0.s -- thumb1 only, same sequence as for STM32VL, bank ignored */
+// flashloaders/stm32f0.s -- thumb1 only, same sequence as for STM32VL, bank ignored
static const uint8_t loader_code_stm32f0[] = {
0xc0, 0x46, 0xc0, 0x46,
- 0x0c, 0x4f, 0x1f, 0x44,
- 0x0c, 0x4e, 0x3e, 0x44,
- 0x0c, 0x4d, 0x3d, 0x44,
- 0x0c, 0x4c, 0x34, 0x60,
+ 0x08, 0x4f, 0x1f, 0x44,
+ 0x08, 0x4d, 0x3d, 0x44,
0x04, 0x88, 0x0c, 0x80,
0x02, 0x30, 0x02, 0x31,
- 0x09, 0x4f, 0x2c, 0x68,
+ 0x06, 0x4f, 0x2c, 0x68,
0x3c, 0x42, 0xfc, 0xd1,
- 0x08, 0x4f, 0x3c, 0x42,
+ 0x05, 0x4f, 0x3c, 0x42,
0x01, 0xd1, 0x02, 0x3a,
- 0xf2, 0xdc, 0x05, 0x4f,
- 0x34, 0x68, 0xbc, 0x43,
- 0x34, 0x60, 0x00, 0xbe,
+ 0xf2, 0xdc, 0x00, 0xbe,
0x00, 0x20, 0x02, 0x40,
- 0x10, 0x00, 0x00, 0x00,
0x0c, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00,
0x14, 0x00, 0x00, 0x00
};
+// flashloaders/stm32lx.s -- compiled for armv6-m for compatibility with both
+// armv6-m cores (STM32L0) and armv7-m cores (STM32L1)
static const uint8_t loader_code_stm32lx[] = {
- // flashloaders/stm32lx.s
0x04, 0x68, 0x0c, 0x60,
- 0x00, 0xf1, 0x04, 0x00,
- 0x01, 0xf1, 0x04, 0x01,
- 0x04, 0x3a, 0xf7, 0xdc,
+ 0x04, 0x30, 0x04, 0x31,
+ 0x04, 0x3a, 0xf9, 0xdc,
0x00, 0xbe, 0x00, 0x00
};
+// flashloaders/stm32f4.s
static const uint8_t loader_code_stm32f4[] = {
- // flashloaders/stm32f4.s
0xdf, 0xf8, 0x24, 0xc0,
0xdf, 0xf8, 0x24, 0xa0,
0xe2, 0x44, 0x04, 0x68,
@@ -87,8 +94,8 @@ static const uint8_t loader_code_stm32f4[] = {
0x0e, 0x00, 0x00, 0x00
};
+// flashloaders/stm32f4lv.s
static const uint8_t loader_code_stm32f4_lv[] = {
- // flashloaders/stm32f4lv.s
0xdf, 0xf8, 0x24, 0xc0,
0xdf, 0xf8, 0x24, 0xa0,
0xe2, 0x44, 0x04, 0x78,
@@ -103,8 +110,8 @@ static const uint8_t loader_code_stm32f4_lv[] = {
0x0e, 0x00, 0x00, 0x00
};
+// flashloaders/stm32l4.s
static const uint8_t loader_code_stm32l4[] = {
- // flashloaders/stm32l4.s
0xdf, 0xf8, 0x28, 0xc0,
0xdf, 0xf8, 0x28, 0xa0,
0xe2, 0x44, 0x05, 0x68,
@@ -120,8 +127,8 @@ static const uint8_t loader_code_stm32l4[] = {
0x10, 0x00, 0x00, 0x00
};
+// flashloaders/stm32f7.s
static const uint8_t loader_code_stm32f7[] = {
- // flashloaders/stm32f7.s
0xdf, 0xf8, 0x28, 0xc0,
0xdf, 0xf8, 0x28, 0xa0,
0xe2, 0x44, 0x04, 0x68,
@@ -137,8 +144,8 @@ static const uint8_t loader_code_stm32f7[] = {
0x0e, 0x00, 0x00, 0x00
};
+// flashloaders/stm32f7lv.s
static const uint8_t loader_code_stm32f7_lv[] = {
- // flashloaders/stm32f7lv.s
0xdf, 0xf8, 0x28, 0xc0,
0xdf, 0xf8, 0x28, 0xa0,
0xe2, 0x44, 0x04, 0x78,
@@ -155,22 +162,31 @@ static const uint8_t loader_code_stm32f7_lv[] = {
};
-int stlink_flash_loader_init(stlink_t *sl, flash_loader_t *fl) {
- size_t size = 0;
+int32_t stlink_flash_loader_init(stlink_t *sl, flash_loader_t *fl) {
+ uint32_t size = 0;
uint32_t dfsr, cfsr, hfsr;
+ /* Interrupt masking according to DDI0419C, Table C1-7 firstly force halt */
+ stlink_write_debug32(sl, STLINK_REG_DHCSR,
+ STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_DEBUGEN |
+ STLINK_REG_DHCSR_C_HALT);
+ /* and only then disable interrupts */
+ stlink_write_debug32(sl, STLINK_REG_DHCSR,
+ STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_DEBUGEN |
+ STLINK_REG_DHCSR_C_HALT | STLINK_REG_DHCSR_C_MASKINTS);
+
// allocate the loader in SRAM
if (stlink_flash_loader_write_to_sram(sl, &fl->loader_addr, &size) == -1) {
WLOG("Failed to write flash loader to sram!\n");
- return(-1);
+ return (-1);
}
// allocate a one page buffer in SRAM right after loader
- fl->buf_addr = fl->loader_addr + (uint32_t)size;
+ fl->buf_addr = fl->loader_addr + size;
ILOG("Successfully loaded flash loader in sram\n");
// set address of IWDG key register for reset it
- if (sl->flash_type == STLINK_FLASH_TYPE_H7) {
+ if (sl->flash_type == STM32_FLASH_TYPE_H7) {
fl->iwdg_kr = STM32H7_WDG_KR;
} else {
fl->iwdg_kr = STM32F0_WDG_KR;
@@ -190,21 +206,21 @@ int stlink_flash_loader_init(stlink_t *sl, flash_loader_t *fl) {
stlink_write_debug32(sl, STLINK_REG_HFSR, hfsr);
}
- return(0);
+ return (0);
}
-static int loader_v_dependent_assignment(stlink_t *sl,
- const uint8_t **loader_code, size_t *loader_size,
- const uint8_t *high_v_loader, size_t high_v_loader_size,
- const uint8_t *low_v_loader, size_t low_v_loader_size) {
- int retval = 0;
+static int32_t loader_v_dependent_assignment(stlink_t *sl,
+ const uint8_t **loader_code, uint32_t *loader_size,
+ const uint8_t *high_v_loader, uint32_t high_v_loader_size,
+ const uint8_t *low_v_loader, uint32_t low_v_loader_size) {
+ int32_t retval = 0;
if ( sl->version.stlink_v == 1) {
printf("STLINK V1 cannot read voltage, defaulting to 32-bit writes\n");
*loader_code = high_v_loader;
*loader_size = high_v_loader_size;
} else {
- int voltage = stlink_target_voltage(sl);
+ int32_t voltage = stlink_target_voltage(sl);
if (voltage == -1) {
retval = -1;
@@ -220,136 +236,135 @@ static int loader_v_dependent_assignment(stlink_t *sl,
}
}
- return(retval);
+ return (retval);
}
-int stlink_flash_loader_write_to_sram(stlink_t *sl, stm32_addr_t* addr, size_t* size) {
+int32_t stlink_flash_loader_write_to_sram(stlink_t *sl, stm32_addr_t* addr, uint32_t* size) {
const uint8_t* loader_code;
- size_t loader_size;
-
- if (sl->chip_id == STLINK_CHIPID_STM32_L1_MEDIUM ||
- sl->chip_id == STLINK_CHIPID_STM32_L1_CAT2 ||
- sl->chip_id == STLINK_CHIPID_STM32_L1_MEDIUM_PLUS ||
- sl->chip_id == STLINK_CHIPID_STM32_L1_HIGH ||
- sl->chip_id == STLINK_CHIPID_STM32_L152_RE ||
- sl->chip_id == STLINK_CHIPID_STM32_L011 ||
- sl->chip_id == STLINK_CHIPID_STM32_L0 ||
- sl->chip_id == STLINK_CHIPID_STM32_L0_CAT5 ||
- sl->chip_id == STLINK_CHIPID_STM32_L0_CAT2) { // STM32l
+ uint32_t loader_size;
+
+ if (sl->chip_id == STM32_CHIPID_L1_MD ||
+ sl->chip_id == STM32_CHIPID_L1_CAT2 ||
+ sl->chip_id == STM32_CHIPID_L1_MD_PLUS ||
+ sl->chip_id == STM32_CHIPID_L1_MD_PLUS_HD ||
+ sl->chip_id == STM32_CHIPID_L152_RE ||
+ sl->chip_id == STM32_CHIPID_L0_CAT1 ||
+ sl->chip_id == STM32_CHIPID_L0_CAT2 ||
+ sl->chip_id == STM32_CHIPID_L0_CAT3 ||
+ sl->chip_id == STM32_CHIPID_L0_CAT5) {
loader_code = loader_code_stm32lx;
loader_size = sizeof(loader_code_stm32lx);
- } else if (sl->core_id == STM32VL_CORE_ID ||
- sl->chip_id == STLINK_CHIPID_STM32_F1_MEDIUM ||
- sl->chip_id == STLINK_CHIPID_STM32_F1_HIGH ||
- sl->chip_id == STLINK_CHIPID_STM32_F1_LOW ||
- sl->chip_id == STLINK_CHIPID_STM32_F1_VL_MEDIUM_LOW ||
- sl->chip_id == STLINK_CHIPID_STM32_F1_VL_HIGH ||
- sl->chip_id == STLINK_CHIPID_STM32_F1_XL ||
- sl->chip_id == STLINK_CHIPID_STM32_F1_CONN ||
- sl->chip_id == STLINK_CHIPID_STM32_F3 ||
- sl->chip_id == STLINK_CHIPID_STM32_F3_SMALL ||
- sl->chip_id == STLINK_CHIPID_STM32_F303_HIGH ||
- sl->chip_id == STLINK_CHIPID_STM32_F37x ||
- sl->chip_id == STLINK_CHIPID_STM32_F334) {
+ } else if (sl->core_id == STM32_CORE_ID_M3_r1p1_SWD ||
+ sl->chip_id == STM32_CHIPID_F1_MD ||
+ sl->chip_id == STM32_CHIPID_F1_HD ||
+ sl->chip_id == STM32_CHIPID_F1_LD ||
+ sl->chip_id == STM32_CHIPID_F1_VL_MD_LD ||
+ sl->chip_id == STM32_CHIPID_F1_VL_HD ||
+ sl->chip_id == STM32_CHIPID_F1_XLD ||
+ sl->chip_id == STM32_CHIPID_F1_CONN ||
+ sl->chip_id == STM32_CHIPID_F3 ||
+ sl->chip_id == STM32_CHIPID_F3xx_SMALL ||
+ sl->chip_id == STM32_CHIPID_F303_HD ||
+ sl->chip_id == STM32_CHIPID_F37x ||
+ sl->chip_id == STM32_CHIPID_F334) {
loader_code = loader_code_stm32vl;
loader_size = sizeof(loader_code_stm32vl);
- } else if (sl->chip_id == STLINK_CHIPID_STM32_F2 ||
- sl->chip_id == STLINK_CHIPID_STM32_F4 ||
- sl->chip_id == STLINK_CHIPID_STM32_F4_DE ||
- sl->chip_id == STLINK_CHIPID_STM32_F4_LP ||
- sl->chip_id == STLINK_CHIPID_STM32_F4_HD ||
- sl->chip_id == STLINK_CHIPID_STM32_F4_DSI ||
- sl->chip_id == STLINK_CHIPID_STM32_F410 ||
- sl->chip_id == STLINK_CHIPID_STM32_F411RE ||
- sl->chip_id == STLINK_CHIPID_STM32_F412 ||
- sl->chip_id == STLINK_CHIPID_STM32_F413 ||
- sl->chip_id == STLINK_CHIPID_STM32_F446) {
- int retval;
+ } else if (sl->chip_id == STM32_CHIPID_F2 ||
+ sl->chip_id == STM32_CHIPID_F4 ||
+ sl->chip_id == STM32_CHIPID_F4_DE ||
+ sl->chip_id == STM32_CHIPID_F4_LP ||
+ sl->chip_id == STM32_CHIPID_F4_HD ||
+ sl->chip_id == STM32_CHIPID_F4_DSI ||
+ sl->chip_id == STM32_CHIPID_F410 ||
+ sl->chip_id == STM32_CHIPID_F411xx ||
+ sl->chip_id == STM32_CHIPID_F412 ||
+ sl->chip_id == STM32_CHIPID_F413 ||
+ sl->chip_id == STM32_CHIPID_F446) {
+ int32_t retval;
retval = loader_v_dependent_assignment(sl,
&loader_code, &loader_size,
loader_code_stm32f4, sizeof(loader_code_stm32f4),
loader_code_stm32f4_lv, sizeof(loader_code_stm32f4_lv));
- if (retval == -1) { return(retval); }
- } else if (sl->core_id == STM32F7_CORE_ID ||
- sl->chip_id == STLINK_CHIPID_STM32_F7 ||
- sl->chip_id == STLINK_CHIPID_STM32_F7XXXX ||
- sl->chip_id == STLINK_CHIPID_STM32_F72XXX) {
- int retval;
+ if (retval == -1) { return (retval); }
+ } else if (sl->core_id == STM32_CORE_ID_M7F_SWD ||
+ sl->chip_id == STM32_CHIPID_F7 ||
+ sl->chip_id == STM32_CHIPID_F76xxx ||
+ sl->chip_id == STM32_CHIPID_F72xxx) {
+ int32_t retval;
retval = loader_v_dependent_assignment(sl,
&loader_code, &loader_size,
loader_code_stm32f7, sizeof(loader_code_stm32f7),
loader_code_stm32f7_lv, sizeof(loader_code_stm32f7_lv));
- if (retval == -1) { return(retval); }
- } else if (sl->chip_id == STLINK_CHIPID_STM32_F0 ||
- sl->chip_id == STLINK_CHIPID_STM32_F04 ||
- sl->chip_id == STLINK_CHIPID_STM32_F0_CAN ||
- sl->chip_id == STLINK_CHIPID_STM32_F0_SMALL ||
- sl->chip_id == STLINK_CHIPID_STM32_F09X) {
+ if (retval == -1) { return (retval); }
+ } else if (sl->chip_id == STM32_CHIPID_F0 ||
+ sl->chip_id == STM32_CHIPID_F04 ||
+ sl->chip_id == STM32_CHIPID_F0_CAN ||
+ sl->chip_id == STM32_CHIPID_F0xx_SMALL ||
+ sl->chip_id == STM32_CHIPID_F09x) {
loader_code = loader_code_stm32f0;
loader_size = sizeof(loader_code_stm32f0);
- } else if ((sl->chip_id == STLINK_CHIPID_STM32_L4) ||
- (sl->chip_id == STLINK_CHIPID_STM32_L41X) ||
- (sl->chip_id == STLINK_CHIPID_STM32_L43X) ||
- (sl->chip_id == STLINK_CHIPID_STM32_L46X) ||
- (sl->chip_id == STLINK_CHIPID_STM32_L4RX) ||
- (sl->chip_id == STLINK_CHIPID_STM32_L496X)) {
+ } else if ((sl->chip_id == STM32_CHIPID_L4) ||
+ (sl->chip_id == STM32_CHIPID_L41x_L42x) ||
+ (sl->chip_id == STM32_CHIPID_L43x_L44x) ||
+ (sl->chip_id == STM32_CHIPID_L45x_L46x) ||
+ (sl->chip_id == STM32_CHIPID_L4Rx) ||
+ (sl->chip_id == STM32_CHIPID_L496x_L4A6x)) {
loader_code = loader_code_stm32l4;
loader_size = sizeof(loader_code_stm32l4);
} else {
ELOG("unknown coreid, not sure what flash loader to use, aborting! coreid: %x, chipid: %x\n",
sl->core_id, sl->chip_id);
- return(-1);
+ return (-1);
}
memcpy(sl->q_buf, loader_code, loader_size);
- int ret = stlink_write_mem32(sl, sl->sram_base, loader_size);
+ int32_t ret = stlink_write_mem32(sl, sl->sram_base, (uint16_t)loader_size);
- if (ret) { return(ret); }
+ if (ret) { return (ret); }
*addr = sl->sram_base;
*size = loader_size;
- return(0); // success
+ return (0); // success
}
-int stlink_flash_loader_run(stlink_t *sl, flash_loader_t* fl, stm32_addr_t target, const uint8_t* buf, size_t size) {
+int32_t stlink_flash_loader_run(stlink_t *sl, flash_loader_t* fl, stm32_addr_t target, const uint8_t* buf, uint32_t size) {
struct stlink_reg rr;
- unsigned timeout;
+ uint32_t timeout;
uint32_t flash_base = 0;
uint32_t dhcsr, dfsr, cfsr, hfsr;
- DLOG("Running flash loader, write address:%#x, size: %u\n", target, (unsigned int)size);
+ DLOG("Running flash loader, write address:%#x, size: %u\n", target, size);
- // TODO: This can never return -1
if (write_buffer_to_sram(sl, fl, buf, size) == -1) {
- // IMPOSSIBLE!
ELOG("write_buffer_to_sram() == -1\n");
- return(-1);
+ return (-1);
}
- if ((sl->flash_type == STLINK_FLASH_TYPE_F1_XL) && (target >= FLASH_BANK2_START_ADDR)) {
+ if ((sl->flash_type == STM32_FLASH_TYPE_F1_XL) && (target >= FLASH_BANK2_START_ADDR)) {
flash_base = FLASH_REGS_BANK2_OFS;
}
- /* Setup core */
- stlink_write_reg(sl, fl->buf_addr, 0); // source
- stlink_write_reg(sl, target, 1); // target
- stlink_write_reg(sl, (uint32_t)size, 2); // count
- stlink_write_reg(sl, flash_base, 3); // flash register base
- // only used on VL/F1_XL, but harmless for others
- stlink_write_reg(sl, fl->loader_addr, 15); // pc register
+ /* Setup core */
+ stlink_write_reg(sl, fl->buf_addr, 0); // source
+ stlink_write_reg(sl, target, 1); // target
+ stlink_write_reg(sl, size, 2); // count
+ stlink_write_reg(sl, flash_base, 3); // flash register base
+ // only used on VL/F1_XL, but harmless for others
+ stlink_write_reg(sl, fl->loader_addr, 15); // pc register
- /* Reset IWDG */
- if (fl->iwdg_kr) {
- stlink_write_debug32(sl, fl->iwdg_kr, STM32F0_WDG_KR_KEY_RELOAD);
- }
+ /* Reset IWDG */
+ if (fl->iwdg_kr) {
+ stlink_write_debug32(sl, fl->iwdg_kr, STM32F0_WDG_KR_KEY_RELOAD);
+ }
- /* Run loader */
- stlink_run(sl, RUN_FLASH_LOADER);
+ /* Run loader */
+ stlink_run(sl, RUN_FLASH_LOADER);
-/* This piece of code used to try to spin for .1 second by waiting doing 10000 rounds of 10 µs.
+/*
+ * This piece of code used to try to spin for .1 second by waiting doing 10000 rounds of 10 µs.
* But because this usually runs on Unix-like OSes, the 10 µs get rounded up to the "tick"
* (actually almost two ticks) of the system. 1 ms. Thus, the ten thousand attempts, when
* "something goes wrong" that requires the error message "flash loader run error" would wait
@@ -359,51 +374,539 @@ int stlink_flash_loader_run(stlink_t *sl, flash_loader_t* fl, stm32_addr_t targe
* as what was intended. -- REW.
*/
- // wait until done (reaches breakpoint)
- timeout = time_ms() + 500;
- while (time_ms() < timeout) {
- usleep(10000);
+ // wait until done (reaches breakpoint)
+ timeout = time_ms() + 500;
+ while (time_ms() < timeout) {
+ usleep(10000);
+
+ if (stlink_is_core_halted(sl)) {
+ timeout = 0;
+ break;
+ }
+ }
+
+ if (timeout) {
+ ELOG("Flash loader run error\n");
+ goto error;
+ }
+
+ // check written byte count
+ stlink_read_reg(sl, 2, &rr);
+
+ /*
+ * The chunk size for loading is not rounded. The flash loader
+ * subtracts the size of the written block (1-8 bytes) from
+ * the remaining size each time. A negative value may mean that
+ * several bytes garbage have been written due to the unaligned
+ * firmware size.
+ */
+ if ((int32_t)rr.r[2] > 0 || (int32_t)rr.r[2] < -7) {
+ ELOG("Flash loader write error\n");
+ goto error;
+ }
+
+ return (0);
+
+ error:
+ dhcsr = dfsr = cfsr = hfsr = 0;
+ stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr);
+ stlink_read_debug32(sl, STLINK_REG_DFSR, &dfsr);
+ stlink_read_debug32(sl, STLINK_REG_CFSR, &cfsr);
+ stlink_read_debug32(sl, STLINK_REG_HFSR, &hfsr);
+ stlink_read_all_regs(sl, &rr);
+
+ WLOG("Loader state: R2 0x%X R15 0x%X\n", rr.r[2], rr.r[15]);
+ if (dhcsr != 0x3000B || dfsr || cfsr || hfsr) {
+ WLOG("MCU state: DHCSR 0x%X DFSR 0x%X CFSR 0x%X HFSR 0x%X\n", dhcsr, dfsr, cfsr, hfsr);
+ }
+
+ return (-1);
+}
- if (stlink_is_core_halted(sl)) {
- timeout = 0;
- break;
- }
+
+/* === Content from old source file flashloader.c === */
+
+#define L1_WRITE_BLOCK_SIZE 0x80
+#define L0_WRITE_BLOCK_SIZE 0x40
+
+int32_t stm32l1_write_half_pages(stlink_t *sl, flash_loader_t *fl, stm32_addr_t addr, uint8_t *base, uint32_t len, uint32_t pagesize) {
+ uint32_t count, off;
+ uint32_t num_half_pages = len / pagesize;
+ uint32_t val;
+ uint32_t flash_regs_base = get_stm32l0_flash_base(sl);
+ bool use_loader = true;
+ int32_t ret = 0;
+
+ // enable half page write
+ stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
+ val |= (1 << FLASH_L1_FPRG);
+ stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val);
+ val |= (1 << FLASH_L1_PROG);
+ stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val);
+
+ wait_flash_busy(sl);
+
+ for (count = 0; count < num_half_pages; count++) {
+ if (use_loader) {
+ ret = stlink_flash_loader_run(sl, fl, addr + count * pagesize, base + count * pagesize, pagesize);
+ if (ret && count == 0) {
+ /* It seems that stm32lx devices have a problem when it is blank */
+ WLOG("Failed to use flash loader, fallback to soft write\n");
+ use_loader = false;
+ }
+ }
+ if (!use_loader) {
+ ret = 0;
+ for (off = 0; off < pagesize && !ret; off += 64) {
+ uint32_t chunk = (pagesize - off > 64) ? 64 : pagesize - off;
+ memcpy(sl->q_buf, base + count * pagesize + off, chunk);
+ ret = stlink_write_mem32(sl, addr + count * pagesize + off, (uint16_t)chunk);
+ }
}
- if (timeout) {
- ELOG("Flash loader run error\n");
- goto error;
+ if (ret) {
+ WLOG("l1_stlink_flash_loader_run(%#x) failed! == -1\n", addr + count * pagesize);
+ break;
}
- // check written byte count
- stlink_read_reg(sl, 2, &rr);
+ if (sl->verbose >= 1) {
+ // show progress; writing procedure is slow and previous errors are misleading
+ fprintf(stdout, "\r%3u/%3u halfpages written", count + 1, num_half_pages);
+ fflush(stdout);
+ }
- /* The chunk size for loading is not rounded. The flash loader
- * subtracts the size of the written block (1-8 bytes) from
- * the remaining size each time. A negative value may mean that
- * several bytes garbage has been written due to the unaligned
- * firmware size.
- */
- if ((int32_t)rr.r[2] > 0 || (int32_t)rr.r[2] < -7) {
- ELOG("Write error\n");
- goto error;
+ // wait for sr.busy to be cleared
+ wait_flash_busy(sl);
+ }
+
+ // disable half page write
+ stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
+ val &= ~((1 << FLASH_L1_FPRG) | (1 << FLASH_L1_PROG));
+ stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val);
+ return (ret);
+}
+
+static void set_flash_cr_pg(stlink_t *sl, uint32_t bank) {
+ uint32_t cr_reg, x;
+
+ x = read_flash_cr(sl, bank);
+
+ if (sl->flash_type == STM32_FLASH_TYPE_C0) {
+ cr_reg = FLASH_C0_CR;
+ x |= (1 << FLASH_CR_PG);
+ } else if (sl->flash_type == STM32_FLASH_TYPE_F2_F4) {
+ cr_reg = FLASH_F4_CR;
+ x |= (1 << FLASH_CR_PG);
+ } else if (sl->flash_type == STM32_FLASH_TYPE_F7) {
+ cr_reg = FLASH_F7_CR;
+ x |= (1 << FLASH_CR_PG);
+ } else if (sl->flash_type == STM32_FLASH_TYPE_L4) {
+ cr_reg = FLASH_L4_CR;
+ x &= ~FLASH_L4_CR_OPBITS;
+ x |= (1 << FLASH_L4_CR_PG);
+ } else if (sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5) {
+ cr_reg = FLASH_L5_NSCR;
+ x |= (1 << FLASH_CR_PG);
+ } else if (sl->flash_type == STM32_FLASH_TYPE_G0 ||
+ sl->flash_type == STM32_FLASH_TYPE_G4) {
+ cr_reg = FLASH_Gx_CR;
+ x |= (1 << FLASH_CR_PG);
+ } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) {
+ cr_reg = FLASH_WB_CR;
+ x |= (1 << FLASH_CR_PG);
+ } else if (sl->flash_type == STM32_FLASH_TYPE_H7) {
+ cr_reg = (bank == BANK_1) ? FLASH_H7_CR1 : FLASH_H7_CR2;
+ x |= (1 << FLASH_H7_CR_PG);
+ } else {
+ cr_reg = (bank == BANK_1) ? FLASH_CR : FLASH_CR2;
+ x = (1 << FLASH_CR_PG);
+ }
+
+ stlink_write_debug32(sl, cr_reg, x);
+}
+
+static void set_dma_state(stlink_t *sl, flash_loader_t *fl, int32_t bckpRstr) {
+ uint32_t rcc, rcc_dma_mask, value;
+
+ rcc = rcc_dma_mask = value = 0;
+
+ switch (sl->flash_type) {
+ case STM32_FLASH_TYPE_C0:
+ rcc = STM32C0_RCC_AHBENR;
+ rcc_dma_mask = STM32C0_RCC_DMAEN;
+ break;
+ case STM32_FLASH_TYPE_F0_F1_F3:
+ case STM32_FLASH_TYPE_F1_XL:
+ rcc = STM32F1_RCC_AHBENR;
+ rcc_dma_mask = STM32F1_RCC_DMAEN;
+ break;
+ case STM32_FLASH_TYPE_F2_F4:
+ case STM32_FLASH_TYPE_F7:
+ rcc = STM32F4_RCC_AHB1ENR;
+ rcc_dma_mask = STM32F4_RCC_DMAEN;
+ break;
+ case STM32_FLASH_TYPE_G0:
+ rcc = STM32G0_RCC_AHBENR;
+ rcc_dma_mask = STM32G0_RCC_DMAEN;
+ break;
+ case STM32_FLASH_TYPE_G4:
+ case STM32_FLASH_TYPE_L4:
+ rcc = STM32G4_RCC_AHB1ENR;
+ rcc_dma_mask = STM32G4_RCC_DMAEN;
+ break;
+ case STM32_FLASH_TYPE_L0_L1:
+ if (get_stm32l0_flash_base(sl) == FLASH_Lx_REGS_ADDR) {
+ rcc = STM32L1_RCC_AHBENR;
+ rcc_dma_mask = STM32L1_RCC_DMAEN;
+ } else {
+ rcc = STM32L0_RCC_AHBENR;
+ rcc_dma_mask = STM32L0_RCC_DMAEN;
+ }
+ break;
+ case STM32_FLASH_TYPE_L5_U5_H5:
+ rcc = STM32L5_RCC_AHB1ENR;
+ rcc_dma_mask = STM32L5_RCC_DMAEN;
+ break;
+ case STM32_FLASH_TYPE_H7:
+ rcc = STM32H7_RCC_AHB1ENR;
+ rcc_dma_mask = STM32H7_RCC_DMAEN;
+ break;
+ case STM32_FLASH_TYPE_WB_WL:
+ rcc = STM32WB_RCC_AHB1ENR;
+ rcc_dma_mask = STM32WB_RCC_DMAEN;
+ break;
+ default:
+ return;
+ }
+
+ if (!stlink_read_debug32(sl, rcc, &value)) {
+ if (bckpRstr) {
+ value = (value & (~rcc_dma_mask)) | fl->rcc_dma_bkp;
+ } else {
+ fl->rcc_dma_bkp = value & rcc_dma_mask;
+ value &= ~rcc_dma_mask;
+ }
+ stlink_write_debug32(sl, rcc, value);
+ }
+}
+
+int32_t stlink_flashloader_start(stlink_t *sl, flash_loader_t *fl) {
+ // disable DMA
+ set_dma_state(sl, fl, 0);
+
+ // wait for ongoing op to finish
+ wait_flash_busy(sl);
+ // Clear errors
+ clear_flash_error(sl);
+
+ if ((sl->flash_type == STM32_FLASH_TYPE_F2_F4) ||
+ (sl->flash_type == STM32_FLASH_TYPE_F7) ||
+ (sl->flash_type == STM32_FLASH_TYPE_L4)) {
+ ILOG("Starting Flash write for F2/F4/F7/L4\n");
+
+ // Flash loader initialisation
+ if (stlink_flash_loader_init(sl, fl) == -1) {
+ ELOG("stlink_flash_loader_init() == -1\n");
+ return (-1);
}
- return(0);
+ unlock_flash_if(sl); // first unlock the cr
-error:
- dhcsr = dfsr = cfsr = hfsr = 0;
- stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr);
- stlink_read_debug32(sl, STLINK_REG_DFSR, &dfsr);
- stlink_read_debug32(sl, STLINK_REG_CFSR, &cfsr);
- stlink_read_debug32(sl, STLINK_REG_HFSR, &hfsr);
- stlink_read_all_regs(sl, &rr);
+ int32_t voltage;
+ if (sl->version.stlink_v == 1) {
+ WLOG("STLINK V1 cannot read voltage, use default voltage 3.2V\n");
+ voltage = 3200;
+ } else {
+ voltage = stlink_target_voltage(sl);
+ }
- WLOG("Loader state: R2 0x%X R15 0x%X\n", rr.r[2], rr.r[15]);
- if (dhcsr != 0x3000B || dfsr || cfsr || hfsr) {
- WLOG("MCU state: DHCSR 0x%X DFSR 0x%X CFSR 0x%X HFSR 0x%X\n",
- dhcsr, dfsr, cfsr, hfsr);
+ if (voltage == -1) {
+ ELOG("Failed to read Target voltage\n");
+ return (-1);
}
- return(-1);
+ if (sl->flash_type == STM32_FLASH_TYPE_L4) {
+ // L4 does not have a byte-write mode
+ if (voltage < 1710) {
+ ELOG("Target voltage (%d mV) too low for flash writes!\n", voltage);
+ return (-1);
+ }
+ } else {
+ if (voltage > 2700) {
+ ILOG("enabling 32-bit flash writes\n");
+ write_flash_cr_psiz(sl, 2, BANK_1);
+ } else {
+ ILOG("Target voltage (%d mV) too low for 32-bit flash, using 8-bit flash writes\n", voltage);
+ write_flash_cr_psiz(sl, 0, BANK_1);
+ }
+ }
+
+ // set programming mode
+ set_flash_cr_pg(sl, BANK_1);
+ } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL ||
+ sl->flash_type == STM32_FLASH_TYPE_G0 ||
+ sl->flash_type == STM32_FLASH_TYPE_G4 ||
+ sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5 ||
+ sl->flash_type == STM32_FLASH_TYPE_C0) {
+ ILOG("Starting Flash write for WB/G0/G4/L5/U5/H5/C0\n");
+
+ unlock_flash_if(sl); // unlock flash if necessary
+ set_flash_cr_pg(sl, BANK_1); // set PG 'allow programming' bit
+ } else if (sl->flash_type == STM32_FLASH_TYPE_L0_L1) {
+ ILOG("Starting Flash write for L0\n");
+
+ uint32_t val;
+ uint32_t flash_regs_base = get_stm32l0_flash_base(sl);
+
+ // disable pecr protection
+ stlink_write_debug32(sl, flash_regs_base + FLASH_PEKEYR_OFF, FLASH_L0_PEKEY1);
+ stlink_write_debug32(sl, flash_regs_base + FLASH_PEKEYR_OFF, FLASH_L0_PEKEY2);
+
+ // check pecr.pelock is cleared
+ stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
+ if (val & (1 << 0)) {
+ ELOG("pecr.pelock not clear\n");
+ return (-1);
+ }
+
+ // unlock program memory
+ stlink_write_debug32(sl, flash_regs_base + FLASH_PRGKEYR_OFF, FLASH_L0_PRGKEY1);
+ stlink_write_debug32(sl, flash_regs_base + FLASH_PRGKEYR_OFF, FLASH_L0_PRGKEY2);
+
+ // check pecr.prglock is cleared
+ stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
+ if (val & (1 << 1)) {
+ ELOG("pecr.prglock not clear\n");
+ return (-1);
+ }
+
+ /* Flash loader initialisation */
+ if (stlink_flash_loader_init(sl, fl) == -1) {
+ // L0/L1 have fallback to soft write
+ WLOG("stlink_flash_loader_init() == -1\n");
+ }
+ } else if ((sl->flash_type == STM32_FLASH_TYPE_F0_F1_F3) ||
+ (sl->flash_type == STM32_FLASH_TYPE_F1_XL)) {
+ ILOG("Starting Flash write for VL/F0/F3/F1_XL\n");
+
+ // flash loader initialisation
+ if (stlink_flash_loader_init(sl, fl) == -1) {
+ ELOG("stlink_flash_loader_init() == -1\n");
+ return (-1);
+ }
+
+ // unlock flash
+ unlock_flash_if(sl);
+
+ // set programming mode
+ set_flash_cr_pg(sl, BANK_1);
+ if (sl->flash_type == STM32_FLASH_TYPE_F1_XL) {
+ set_flash_cr_pg(sl, BANK_2);
+ }
+ } else if (sl->flash_type == STM32_FLASH_TYPE_H7) {
+ ILOG("Starting Flash write for H7\n");
+
+ unlock_flash_if(sl); // unlock the cr
+ set_flash_cr_pg(sl, BANK_1); // set programming mode
+ if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) {
+ set_flash_cr_pg(sl, BANK_2);
+ }
+ if (sl->chip_id != STM32_CHIPID_H7Ax) {
+ // set parallelism
+ write_flash_cr_psiz(sl, 3 /* 64bit */, BANK_1);
+ if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) {
+ write_flash_cr_psiz(sl, 3 /* 64bit */, BANK_2);
+ }
+ }
+ } else {
+ ELOG("unknown coreid, not sure how to write: %x\n", sl->core_id);
+ return (-1);
+ }
+
+ return (0);
+}
+
+int32_t stlink_flashloader_write(stlink_t *sl, flash_loader_t *fl, stm32_addr_t addr, uint8_t *base, uint32_t len) {
+ uint32_t off;
+
+ if ((sl->flash_type == STM32_FLASH_TYPE_F2_F4) ||
+ (sl->flash_type == STM32_FLASH_TYPE_F7) ||
+ (sl->flash_type == STM32_FLASH_TYPE_L4)) {
+ uint32_t buf_size = (sl->sram_size > 0x8000) ? 0x8000 : 0x4000;
+ for (off = 0; off < len;) {
+ uint32_t size = len - off > buf_size ? buf_size : len - off;
+ if (stlink_flash_loader_run(sl, fl, addr + off, base + off, size) == -1) {
+ ELOG("stlink_flash_loader_run(%#x) failed! == -1\n", (addr + off));
+ check_flash_error(sl);
+ return (-1);
+ }
+
+ off += size;
+ }
+ } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL ||
+ sl->flash_type == STM32_FLASH_TYPE_G0 ||
+ sl->flash_type == STM32_FLASH_TYPE_G4 ||
+ sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5 ||
+ sl->flash_type == STM32_FLASH_TYPE_C0) {
+
+ if (sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5 && (len % 16)) {
+ WLOG("Data size is aligned to 16 byte");
+ len += 16 - len%16;
+ }
+ DLOG("Starting %3u page write\n", len / sl->flash_pgsz);
+ for (off = 0; off < len; off += sizeof(uint32_t)) {
+ uint32_t data;
+
+ if ((off % sl->flash_pgsz) > (sl->flash_pgsz - 5)) {
+ fprintf(stdout, "\r%3u/%-3u pages written", (off / sl->flash_pgsz + 1), (len / sl->flash_pgsz));
+ fflush(stdout);
+ }
+
+ // write_uint32((unsigned char *)&data, *(uint32_t *)(base + off));
+ data = 0;
+ memcpy(&data, base + off, (len - off) < 4 ? (len - off) : 4);
+ stlink_write_debug32(sl, addr + off, data);
+ wait_flash_busy(sl); // wait for 'busy' bit in FLASH_SR to clear
+ }
+ fprintf(stdout, "\n");
+
+ // flash writes happen as 2 words at a time
+ if ((off / sizeof(uint32_t)) % 2 != 0) {
+ stlink_write_debug32(sl, addr + off, 0); // write a single word of zeros
+ wait_flash_busy(sl); // wait for 'busy' bit in FLASH_SR to clear
+ }
+ } else if (sl->flash_type == STM32_FLASH_TYPE_L0_L1) {
+ uint32_t val;
+ uint32_t flash_regs_base = get_stm32l0_flash_base(sl);
+ uint32_t pagesize = (flash_regs_base == FLASH_L0_REGS_ADDR)? L0_WRITE_BLOCK_SIZE : L1_WRITE_BLOCK_SIZE;
+
+ DLOG("Starting %3u page write\r\n", len / sl->flash_pgsz);
+
+ off = 0;
+
+ if (len > pagesize) {
+ if (stm32l1_write_half_pages(sl, fl, addr, base, len, pagesize)) {
+ return (-1);
+ } else {
+ off = (size_t)(len / pagesize) * pagesize;
+ }
+ }
+
+ // write remaining word in program memory
+ for (; off < len; off += sizeof(uint32_t)) {
+ uint32_t data;
+
+ if ((off % sl->flash_pgsz) > (sl->flash_pgsz - 5)) {
+ fprintf(stdout, "\r%3u/%-3u pages written", (off / sl->flash_pgsz + 1), (len / sl->flash_pgsz));
+ fflush(stdout);
+ }
+
+ write_uint32((unsigned char *)&data, *(uint32_t *)(base + off));
+ stlink_write_debug32(sl, addr + off, data);
+
+ // wait for sr.busy to be cleared
+ do {
+ stlink_read_debug32(sl, flash_regs_base + FLASH_SR_OFF, &val);
+ } while ((val & (1 << 0)) != 0);
+
+ // TODO: check redo write operation
+ }
+ fprintf(stdout, "\n");
+ } else if ((sl->flash_type == STM32_FLASH_TYPE_F0_F1_F3) || (sl->flash_type == STM32_FLASH_TYPE_F1_XL)) {
+ int32_t write_block_count = 0;
+ for (off = 0; off < len; off += sl->flash_pgsz) {
+ // adjust last write size
+ uint32_t size = len - off > sl->flash_pgsz ? sl->flash_pgsz : len - off;
+
+ // unlock and set programming mode
+ unlock_flash_if(sl);
+
+ DLOG("Finished unlocking flash, running loader!\n");
+
+ if (stlink_flash_loader_run(sl, fl, addr + off, base + off, size) == -1) {
+ ELOG("stlink_flash_loader_run(%#x) failed! == -1\n", (addr + off));
+ check_flash_error(sl);
+ return (-1);
+ }
+
+ lock_flash(sl);
+
+ if (sl->verbose >= 1) {
+ // show progress; writing procedure is slow and previous errors are
+ // misleading
+ fprintf(stdout, "\r%3u/%-3u pages written", ++write_block_count,
+ (len + sl->flash_pgsz - 1) / sl->flash_pgsz);
+ fflush(stdout);
+ }
+ }
+ if (sl->verbose >= 1) {
+ fprintf(stdout, "\n");
+ }
+ } else if (sl->flash_type == STM32_FLASH_TYPE_H7) {
+ for (off = 0; off < len;) {
+ // Program STM32H7x with 64-byte Flash words
+ uint32_t chunk = (len - off > 64) ? 64 : len - off;
+ memcpy(sl->q_buf, base + off, chunk);
+ stlink_write_mem32(sl, addr + off, 64);
+ wait_flash_busy(sl);
+
+ off += chunk;
+
+ if (sl->verbose >= 1) {
+ // show progress
+ fprintf(stdout, "\r%u/%u bytes written", off, len);
+ fflush(stdout);
+ }
+ }
+ if (sl->verbose >= 1) {
+ fprintf(stdout, "\n");
+ }
+ } else {
+ return (-1);
+ }
+
+ return check_flash_error(sl);
+}
+
+int32_t stlink_flashloader_stop(stlink_t *sl, flash_loader_t *fl) {
+ uint32_t dhcsr;
+
+ if ((sl->flash_type == STM32_FLASH_TYPE_C0) ||
+ (sl->flash_type == STM32_FLASH_TYPE_F0_F1_F3) ||
+ (sl->flash_type == STM32_FLASH_TYPE_F1_XL) ||
+ (sl->flash_type == STM32_FLASH_TYPE_F2_F4) ||
+ (sl->flash_type == STM32_FLASH_TYPE_F7) ||
+ (sl->flash_type == STM32_FLASH_TYPE_G0) ||
+ (sl->flash_type == STM32_FLASH_TYPE_G4) ||
+ (sl->flash_type == STM32_FLASH_TYPE_H7) ||
+ (sl->flash_type == STM32_FLASH_TYPE_L4) ||
+ (sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5) ||
+ (sl->flash_type == STM32_FLASH_TYPE_WB_WL)) {
+
+ clear_flash_cr_pg(sl, BANK_1);
+ if ((sl->flash_type == STM32_FLASH_TYPE_H7 && sl->chip_flags & CHIP_F_HAS_DUAL_BANK) ||
+ sl->flash_type == STM32_FLASH_TYPE_F1_XL) {
+ clear_flash_cr_pg(sl, BANK_2);
+ }
+ lock_flash(sl);
+ } else if (sl->flash_type == STM32_FLASH_TYPE_L0_L1) {
+ uint32_t val;
+ uint32_t flash_regs_base = get_stm32l0_flash_base(sl);
+
+ // reset lock bits
+ stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
+ val |= (1 << 0) | (1 << 1) | (1 << 2);
+ stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val);
+ }
+
+ // enable interrupt
+ if (!stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr)) {
+ stlink_write_debug32(sl, STLINK_REG_DHCSR, STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_DEBUGEN |
+ (dhcsr & (~STLINK_REG_DHCSR_C_MASKINTS)));
+ }
+
+ // restore DMA state
+ set_dma_state(sl, fl, 1);
+
+ return (0);
}
diff --git a/src/stlink-lib/flash_loader.h b/src/stlink-lib/flash_loader.h
index 29fd5b0..6ac2e4f 100644
--- a/src/stlink-lib/flash_loader.h
+++ b/src/stlink-lib/flash_loader.h
@@ -1,27 +1,28 @@
/*
- * File: stlink.h
+ * File: flash_loader.h
*
- * This should contain all the common top level stlink interfaces,
- * regardless of how the backend does the work....
+ * Flash loaders
*/
-#ifndef STLINK_FLASH_LOADER_H_
-#define STLINK_FLASH_LOADER_H_
+
+#ifndef FLASH_LOADER_H
+#define FLASH_LOADER_H
-#include <stdint.h>
-#include <stddef.h>
+int32_t stlink_flash_loader_init(stlink_t *sl, flash_loader_t* fl);
+// static int32_t loader_v_dependent_assignment(stlink_t *sl,
+// const uint8_t **loader_code, uint32_t *loader_size,
+// const uint8_t *high_v_loader, uint32_t high_v_loader_size,
+// const uint8_t *low_v_loader, uint32_t low_v_loader_size);
+int32_t stlink_flash_loader_write_to_sram(stlink_t *sl, stm32_addr_t* addr, uint32_t* size);
+int32_t stlink_flash_loader_run(stlink_t *sl, flash_loader_t* fl, stm32_addr_t target, const uint8_t* buf, uint32_t size);
-#include <stlink.h>
-#ifdef __cplusplus
-extern "C" {
-#endif
+/* === Functions from old header file flashloader.h === */
-int stlink_flash_loader_init(stlink_t *sl, flash_loader_t* fl);
-int stlink_flash_loader_write_to_sram(stlink_t *sl, stm32_addr_t* addr, size_t* size);
-int stlink_flash_loader_run(stlink_t *sl, flash_loader_t* fl, stm32_addr_t target, const uint8_t* buf, size_t size);
+int32_t stm32l1_write_half_pages(stlink_t *sl, flash_loader_t *fl, stm32_addr_t addr, uint8_t *base, uint32_t len, uint32_t pagesize);
+// static void set_flash_cr_pg(stlink_t *sl, uint32_t bank);
+// static void set_dma_state(stlink_t *sl, flash_loader_t *fl, int32_t bckpRstr);
+int32_t stlink_flashloader_start(stlink_t *sl, flash_loader_t *fl);
+int32_t stlink_flashloader_write(stlink_t *sl, flash_loader_t *fl, stm32_addr_t addr, uint8_t *base, uint32_t len);
+int32_t stlink_flashloader_stop(stlink_t *sl, flash_loader_t *fl);
-#ifdef __cplusplus
-}
-#endif
-
-#endif // STLINK_FLASH_LOADER_H_
+#endif // FLASH_LOADER_H
diff --git a/src/stlink-lib/helper.c b/src/stlink-lib/helper.c
index 1f0f71b..1e756f1 100644
--- a/src/stlink-lib/helper.c
+++ b/src/stlink-lib/helper.c
@@ -1,27 +1,34 @@
-#include <helper.h>
-
-#include <stddef.h>
-#include <stdlib.h>
+/*
+ * File: helper.c
+ *
+ * General helper functions
+ */
#ifdef STLINK_HAVE_SYS_TIME_H
#include <sys/time.h>
#else
#include <sys_time.h>
-#endif
+#endif // STLINK_HAVE_SYS_TIME_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "helper.h"
-unsigned time_ms() {
+uint32_t time_ms() {
struct timeval tv;
gettimeofday(&tv, NULL);
- return (unsigned)(tv.tv_sec * 1000 + tv.tv_usec / 1000);
+ return (uint32_t)(tv.tv_sec * 1000 + tv.tv_usec / 1000);
}
-int arg_parse_freq(const char *str) {
+int32_t arg_parse_freq(const char *str) {
char *tail;
- int value = (int)strtol(str, &tail, 10);
+ int32_t value = (int32_t)strtol(str, &tail, 10);
- if ((tail[0] == 'm' || tail[0] == 'M') && tail[1] == '\0') {
+ if (tail[0] == 'M' && tail[1] == '\0') {
value = value*1000;
- } else if (((tail[0] != 'k' && tail[0] != 'K') || tail[1] != '\0') && tail[0] != '\0') {
+ } else if ((tail[0] != 'k' || tail[1] != '\0') && tail[0] != '\0') {
return -1;
}
diff --git a/src/stlink-lib/helper.h b/src/stlink-lib/helper.h
index 9646737..ef374a5 100644
--- a/src/stlink-lib/helper.h
+++ b/src/stlink-lib/helper.h
@@ -1,8 +1,13 @@
-#ifndef SYS_HELPER_H
-#define SYS_HELPER_H
+/*
+ * File: helper.h
+ *
+ * General helper functions
+ */
-unsigned time_ms();
+#ifndef HELPER_H
+#define HELPER_H
-int arg_parse_freq(const char *str);
+uint32_t time_ms();
+int32_t arg_parse_freq(const char *str);
-#endif /* SYS_HELPER_H */
+#endif // HELPER_H
diff --git a/src/stlink-lib/lib_md5.c b/src/stlink-lib/lib_md5.c
new file mode 100644
index 0000000..62e7725
--- /dev/null
+++ b/src/stlink-lib/lib_md5.c
@@ -0,0 +1,281 @@
+/*
+ * WjCryptLib_Md5 (https://github.com/WaterJuice/WjCryptLib)
+ * Implementation of MD5 hash function. Originally written by Alexander Peslyak.
+ * Modified by WaterJuice retaining Public Domain license.
+ * This is free and unencumbered software released into the public domain - June 2013 - waterjuice.org
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <memory.h>
+
+#include "lib_md5.h"
+
+/* INTERNAL FUNCTIONS */
+
+/* F, G, H, I
+ *
+ * The basic MD5 functions.
+ * F and G are optimised compared to their RFC 1321 definitions for architectures
+ * that lack an AND-NOT instruction, just like in Colin Plumb's implementation.
+ */
+#define F( x, y, z ) ((z) ^ ((x) & ((y) ^ (z))))
+#define G( x, y, z ) ((y) ^ ((z) & ((x) ^ (y))))
+#define H( x, y, z ) ((x) ^ (y) ^ (z))
+#define I( x, y, z ) ((y) ^ ((x) | ~(z)))
+
+/* STEP: The MD5 transformation for all four rounds. */
+#define STEP( f, a, b, c, d, x, t, s ) \
+ (a) += f((b), (c), (d)) + (x) + (t); \
+ (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
+ (a) += (b);
+
+/* TransformFunction
+ * This processes one or more 64-byte data blocks, but does NOT update the bit counters.
+ * There are no alignment requirements.
+ */
+static void* TransformFunction(Md5Context* ctx, void const* data, uintmax_t size) {
+ uint8_t* ptr;
+ uint32_t a;
+ uint32_t b;
+ uint32_t c;
+ uint32_t d;
+ uint32_t saved_a;
+ uint32_t saved_b;
+ uint32_t saved_c;
+ uint32_t saved_d;
+
+ #define GET(n) (ctx->block[(n)])
+ #define SET(n) (ctx->block[(n)] = ((uint32_t)ptr[(n) * 4 + 0] << 0) | \
+ ((uint32_t)ptr[(n) * 4 + 1] << 8) | \
+ ((uint32_t)ptr[(n) * 4 + 2] << 16) | \
+ ((uint32_t)ptr[(n) * 4 + 3] << 24))
+
+ ptr = (uint8_t*)data;
+
+ a = ctx->a;
+ b = ctx->b;
+ c = ctx->c;
+ d = ctx->d;
+
+ do {
+ saved_a = a;
+ saved_b = b;
+ saved_c = c;
+ saved_d = d;
+
+ // Round 1
+ STEP( F, a, b, c, d, SET(0), 0xd76aa478, 7 )
+ STEP( F, d, a, b, c, SET(1), 0xe8c7b756, 12 )
+ STEP( F, c, d, a, b, SET(2), 0x242070db, 17 )
+ STEP( F, b, c, d, a, SET(3), 0xc1bdceee, 22 )
+ STEP( F, a, b, c, d, SET(4), 0xf57c0faf, 7 )
+ STEP( F, d, a, b, c, SET(5), 0x4787c62a, 12 )
+ STEP( F, c, d, a, b, SET(6), 0xa8304613, 17 )
+ STEP( F, b, c, d, a, SET(7), 0xfd469501, 22 )
+ STEP( F, a, b, c, d, SET(8 ), 0x698098d8, 7 )
+ STEP( F, d, a, b, c, SET(9 ), 0x8b44f7af, 12 )
+ STEP( F, c, d, a, b, SET(10 ), 0xffff5bb1, 17 )
+ STEP( F, b, c, d, a, SET(11 ), 0x895cd7be, 22 )
+ STEP( F, a, b, c, d, SET(12 ), 0x6b901122, 7 )
+ STEP( F, d, a, b, c, SET(13 ), 0xfd987193, 12 )
+ STEP( F, c, d, a, b, SET(14 ), 0xa679438e, 17 )
+ STEP( F, b, c, d, a, SET(15 ), 0x49b40821, 22 )
+
+ // Round 2
+ STEP( G, a, b, c, d, GET(1), 0xf61e2562, 5 )
+ STEP( G, d, a, b, c, GET(6), 0xc040b340, 9 )
+ STEP( G, c, d, a, b, GET(11), 0x265e5a51, 14 )
+ STEP( G, b, c, d, a, GET(0), 0xe9b6c7aa, 20 )
+ STEP( G, a, b, c, d, GET(5), 0xd62f105d, 5 )
+ STEP( G, d, a, b, c, GET(10), 0x02441453, 9 )
+ STEP( G, c, d, a, b, GET(15), 0xd8a1e681, 14 )
+ STEP( G, b, c, d, a, GET(4), 0xe7d3fbc8, 20 )
+ STEP( G, a, b, c, d, GET(9), 0x21e1cde6, 5 )
+ STEP( G, d, a, b, c, GET(14), 0xc33707d6, 9 )
+ STEP( G, c, d, a, b, GET(3), 0xf4d50d87, 14 )
+ STEP( G, b, c, d, a, GET(8), 0x455a14ed, 20 )
+ STEP( G, a, b, c, d, GET(13), 0xa9e3e905, 5 )
+ STEP( G, d, a, b, c, GET(2), 0xfcefa3f8, 9 )
+ STEP( G, c, d, a, b, GET(7), 0x676f02d9, 14 )
+ STEP( G, b, c, d, a, GET(12), 0x8d2a4c8a, 20 )
+
+ // Round 3
+ STEP( H, a, b, c, d, GET(5), 0xfffa3942, 4 )
+ STEP( H, d, a, b, c, GET(8), 0x8771f681, 11 )
+ STEP( H, c, d, a, b, GET(11), 0x6d9d6122, 16 )
+ STEP( H, b, c, d, a, GET(14), 0xfde5380c, 23 )
+ STEP( H, a, b, c, d, GET(1), 0xa4beea44, 4 )
+ STEP( H, d, a, b, c, GET(4), 0x4bdecfa9, 11 )
+ STEP( H, c, d, a, b, GET(7), 0xf6bb4b60, 16 )
+ STEP( H, b, c, d, a, GET(10), 0xbebfbc70, 23 )
+ STEP( H, a, b, c, d, GET(13), 0x289b7ec6, 4 )
+ STEP( H, d, a, b, c, GET(0), 0xeaa127fa, 11 )
+ STEP( H, c, d, a, b, GET(3), 0xd4ef3085, 16 )
+ STEP( H, b, c, d, a, GET(6), 0x04881d05, 23 )
+ STEP( H, a, b, c, d, GET(9), 0xd9d4d039, 4 )
+ STEP( H, d, a, b, c, GET(12), 0xe6db99e5, 11 )
+ STEP( H, c, d, a, b, GET(15), 0x1fa27cf8, 16 )
+ STEP( H, b, c, d, a, GET(2), 0xc4ac5665, 23 )
+
+ // Round 4
+ STEP( I, a, b, c, d, GET(0), 0xf4292244, 6 )
+ STEP( I, d, a, b, c, GET(7), 0x432aff97, 10 )
+ STEP( I, c, d, a, b, GET(14), 0xab9423a7, 15 )
+ STEP( I, b, c, d, a, GET(5), 0xfc93a039, 21 )
+ STEP( I, a, b, c, d, GET(12), 0x655b59c3, 6 )
+ STEP( I, d, a, b, c, GET(3), 0x8f0ccc92, 10 )
+ STEP( I, c, d, a, b, GET(10), 0xffeff47d, 15 )
+ STEP( I, b, c, d, a, GET(1), 0x85845dd1, 21 )
+ STEP( I, a, b, c, d, GET(8), 0x6fa87e4f, 6 )
+ STEP( I, d, a, b, c, GET(15), 0xfe2ce6e0, 10 )
+ STEP( I, c, d, a, b, GET(6), 0xa3014314, 15 )
+ STEP( I, b, c, d, a, GET(13), 0x4e0811a1, 21 )
+ STEP( I, a, b, c, d, GET(4), 0xf7537e82, 6 )
+ STEP( I, d, a, b, c, GET(11), 0xbd3af235, 10 )
+ STEP( I, c, d, a, b, GET(2), 0x2ad7d2bb, 15 )
+ STEP( I, b, c, d, a, GET(9), 0xeb86d391, 21 )
+
+ a += saved_a;
+ b += saved_b;
+ c += saved_c;
+ d += saved_d;
+
+ ptr += 64;
+ } while ( size -= 64 );
+
+ ctx->a = a;
+ ctx->b = b;
+ ctx->c = c;
+ ctx->d = d;
+
+ #undef GET
+ #undef SET
+
+ return (ptr);
+}
+
+/* EXPORTED FUNCTIONS */
+
+/* Md5Initialise
+ * Initialises an MD5 Context.
+ * Use this to initialise/reset a context.
+ */
+void Md5Initialise(Md5Context* Context /* [out] */) {
+ Context->a = 0x67452301;
+ Context->b = 0xefcdab89;
+ Context->c = 0x98badcfe;
+ Context->d = 0x10325476;
+
+ Context->lo = 0;
+ Context->hi = 0;
+}
+
+/* Md5Update
+ * Adds data to the MD5 context.
+ * This will process the data and update the internal state of the context.
+ * Keep on calling this function until all the data has been added.
+ * Then call Md5Finalise to calculate the hash.
+ */
+void Md5Update(Md5Context* Context /* [in out] */, void const* Buffer /* [in] */, uint32_t BufferSize /* [in] */) {
+ uint32_t saved_lo;
+ uint32_t used;
+ uint32_t free;
+
+ saved_lo = Context->lo;
+
+ if ((Context->lo = (saved_lo + BufferSize) & 0x1fffffff) < saved_lo) {
+ Context->hi++;
+ }
+
+ Context->hi += (uint32_t)(BufferSize >> 29);
+
+ used = saved_lo & 0x3f;
+
+ if ( used ) {
+ free = 64 - used;
+
+ if ( BufferSize < free ) {
+ memcpy( &Context->buffer[used], Buffer, BufferSize );
+ return;
+ }
+
+ memcpy( &Context->buffer[used], Buffer, free );
+ Buffer = (uint8_t*)Buffer + free;
+ BufferSize -= free;
+ TransformFunction(Context, Context->buffer, 64);
+ }
+
+ if ( BufferSize >= 64 ) {
+ Buffer = TransformFunction( Context, Buffer, BufferSize & ~(uint32_t)0x3f );
+ BufferSize &= 0x3f;
+ }
+
+ memcpy( Context->buffer, Buffer, BufferSize );
+}
+
+/* Md5Finalise
+ * Performs the final calculation of the hash and returns the digest
+ * (16 byte buffer containing 128bit hash).
+ * After calling this, Md5Initialised must be used to reuse the context.
+ */
+void Md5Finalise(Md5Context* Context /* [in out] */, MD5_HASH* Digest /* [in] */) {
+ uint32_t used;
+ uint32_t free;
+
+ used = Context->lo & 0x3f;
+
+ Context->buffer[used++] = 0x80;
+
+ free = 64 - used;
+
+ if (free < 8) {
+ memset( &Context->buffer[used], 0, free );
+ TransformFunction( Context, Context->buffer, 64 );
+ used = 0;
+ free = 64;
+ }
+
+ memset( &Context->buffer[used], 0, free - 8 );
+
+ Context->lo <<= 3;
+ Context->buffer[56] = (uint8_t)(Context->lo);
+ Context->buffer[57] = (uint8_t)(Context->lo >> 8);
+ Context->buffer[58] = (uint8_t)(Context->lo >> 16);
+ Context->buffer[59] = (uint8_t)(Context->lo >> 24);
+ Context->buffer[60] = (uint8_t)(Context->hi);
+ Context->buffer[61] = (uint8_t)(Context->hi >> 8);
+ Context->buffer[62] = (uint8_t)(Context->hi >> 16);
+ Context->buffer[63] = (uint8_t)(Context->hi >> 24);
+
+ TransformFunction( Context, Context->buffer, 64 );
+
+ Digest->bytes[0] = (uint8_t)(Context->a);
+ Digest->bytes[1] = (uint8_t)(Context->a >> 8);
+ Digest->bytes[2] = (uint8_t)(Context->a >> 16);
+ Digest->bytes[3] = (uint8_t)(Context->a >> 24);
+ Digest->bytes[4] = (uint8_t)(Context->b);
+ Digest->bytes[5] = (uint8_t)(Context->b >> 8);
+ Digest->bytes[6] = (uint8_t)(Context->b >> 16);
+ Digest->bytes[7] = (uint8_t)(Context->b >> 24);
+ Digest->bytes[8] = (uint8_t)(Context->c);
+ Digest->bytes[9] = (uint8_t)(Context->c >> 8);
+ Digest->bytes[10] = (uint8_t)(Context->c >> 16);
+ Digest->bytes[11] = (uint8_t)(Context->c >> 24);
+ Digest->bytes[12] = (uint8_t)(Context->d);
+ Digest->bytes[13] = (uint8_t)(Context->d >> 8);
+ Digest->bytes[14] = (uint8_t)(Context->d >> 16);
+ Digest->bytes[15] = (uint8_t)(Context->d >> 24);
+}
+
+/* Md5Calculate
+ * Combines Md5Initialise, Md5Update, and Md5Finalise into one function.
+ * Calculates the MD5 hash of the buffer.
+ */
+void Md5Calculate(void const* Buffer /* [in] */, uint32_t BufferSize /* [in] */, MD5_HASH* Digest /* [in] */) {
+ Md5Context context;
+
+ Md5Initialise( &context );
+ Md5Update( &context, Buffer, BufferSize );
+ Md5Finalise( &context, Digest );
+}
diff --git a/src/stlink-lib/lib_md5.h b/src/stlink-lib/lib_md5.h
new file mode 100644
index 0000000..7275fd0
--- /dev/null
+++ b/src/stlink-lib/lib_md5.h
@@ -0,0 +1,65 @@
+/*
+ * WjCryptLib_Md5 (https://github.com/WaterJuice/WjCryptLib)
+ * Implementation of MD5 hash function. Originally written by Alexander Peslyak.
+ * Modified by WaterJuice retaining Public Domain license.
+ * This is free and unencumbered software released into the public domain - June 2013 - waterjuice.org
+ */
+
+#ifndef LIB_MD5_H
+#define LIB_MD5_H
+
+#pragma once
+
+/* TYPES */
+
+/* Md5Context
+ * This must be initialised using Md5Initialised.
+ * Do not modify the contents of this structure directly.
+ */
+typedef struct {
+ uint32_t lo;
+ uint32_t hi;
+ uint32_t a;
+ uint32_t b;
+ uint32_t c;
+ uint32_t d;
+ uint8_t buffer[64];
+ uint32_t block[16];
+} Md5Context;
+
+#define MD5_HASH_SIZE (128 / 8)
+
+typedef struct {
+ uint8_t bytes [MD5_HASH_SIZE];
+} MD5_HASH;
+
+/* PUBLIC FUNCTIONS */
+
+/* Md5Initialise
+ * Initialises an MD5 Context.
+ * Use this to initialise/reset a context.
+ */
+void Md5Initialise(Md5Context* Context /* [out] */);
+
+/* Md5Update
+ * Adds data to the MD5 context.
+ * This will process the data and update the internal state of the context.
+ * Keep on calling this function until all the data has been added.
+ * Then call Md5Finalise to calculate the hash.
+ */
+void Md5Update(Md5Context* Context /* [in out] */, void const* Buffer /* [in] */, uint32_t BufferSize /* [in] */);
+
+/* Md5Finalise
+ * Performs the final calculation of the hash and returns the digest
+ * (16 byte buffer containing 128bit hash).
+ * After calling this, Md5Initialised must be used to reuse the context.
+ */
+void Md5Finalise(Md5Context* Context /* [in out] */, MD5_HASH* Digest /* [in] */);
+
+/* Md5Calculate
+ * Combines Md5Initialise, Md5Update, and Md5Finalise into one function.
+ * Calculates the MD5 hash of the buffer.
+ */
+void Md5Calculate(void const* Buffer /* [in] */, uint32_t BufferSize /* [in] */, MD5_HASH* Digest /* [in] */);
+
+#endif // LIB_MD5_H \ No newline at end of file
diff --git a/src/stlink-lib/libusb_settings.h b/src/stlink-lib/libusb_settings.h
index fea2823..b0a51ad 100644
--- a/src/stlink-lib/libusb_settings.h
+++ b/src/stlink-lib/libusb_settings.h
@@ -1,24 +1,31 @@
+/*
+ * File: libusb_settings.h
+ *
+ * Settings for libusb library
+ */
+
#ifndef LIBUSB_SETTINGS_H
#define LIBUSB_SETTINGS_H
#include <libusb.h>
/*
-
- libusb ver | LIBUSB_API_VERSION
- -----------+--------------------
- v1.0.13 | 0x01000100
- v1.0.14 | 0x010000FF
- v1.0.15 | 0x01000101
- v1.0.16 | 0x01000102
- v1.0.17 | 0x01000102
- v1.0.18 | 0x01000102
- v1.0.19 | 0x01000103
- v1.0.20 | 0x01000104
- v1.0.21 | 0x01000105
- v1.0.22 | 0x01000106
- v1.0.23 | 0x01000107
-
+ * libusb ver | LIBUSB_API_VERSION
+ * -----------+--------------------
+ * v1.0.13 | 0x01000100
+ * v1.0.14 | 0x010000FF
+ * v1.0.15 | 0x01000101
+ * v1.0.16 | 0x01000102
+ * v1.0.17 | 0x01000102
+ * v1.0.18 | 0x01000102
+ * v1.0.19 | 0x01000103
+ * v1.0.20 | 0x01000104
+ * v1.0.21 | 0x01000105
+ * v1.0.22 | 0x01000106
+ * v1.0.23 | 0x01000107
+ * v1.0.24 | 0x01000108
+ * v1.0.25 | 0x01000109
+ * v1.0.26 | 0x01000110
*/
#if defined (__FreeBSD__)
@@ -31,12 +38,12 @@
#if defined (__FreeBSD__)
#define MINIMAL_API_VERSION 0x01000102 // v1.0.16
+#elif defined (__OpenBSD__)
+ #define MINIMAL_API_VERSION 0x01000106 // v1.0.22
#elif defined (__linux__)
- #define MINIMAL_API_VERSION 0x01000104 // v1.0.20
-#elif defined (__APPLE__)
- #define MINIMAL_API_VERSION 0x01000104 // v1.0.20
+ #define MINIMAL_API_VERSION 0x01000106 // v1.0.22
#elif defined (_WIN32)
- #define MINIMAL_API_VERSION 0x01000104 // v1.0.20
+ #define MINIMAL_API_VERSION 0x01000109 // v1.0.25
#endif
#if (LIBUSB_API_VERSION < MINIMAL_API_VERSION)
diff --git a/src/stlink-lib/logging.c b/src/stlink-lib/logging.c
index 8797823..92092f3 100644
--- a/src/stlink-lib/logging.c
+++ b/src/stlink-lib/logging.c
@@ -1,25 +1,27 @@
/*
- * UglyLogging
+ * File: logging.c
*
- * Slow, yet another wheel reinvented, but enough to make the rest of our code
- * pretty enough.
+ * UglyLogging: Slow, yet another wheel reinvented, but enough to make the rest of our code pretty enough.
*/
-#include <stdarg.h>
-#include <stddef.h>
+
+#define __STDC_WANT_LIB_EXT1__ 1
+
+#include <stdint.h>
#include <stdio.h>
-#include <stdlib.h>
+
+#include <stdarg.h>
#include <time.h>
#include "logging.h"
-static int max_level = UDEBUG;
+static int32_t max_level = UDEBUG;
-int ugly_init(int maximum_threshold) {
+int32_t ugly_init(int32_t maximum_threshold) {
max_level = maximum_threshold;
return (0);
}
-int ugly_log(int level, const char *tag, const char *format, ...) {
+int32_t ugly_log(int32_t level, const char *tag, const char *format, ...) {
if (level > max_level) {
return (0);
}
@@ -29,10 +31,22 @@ int ugly_log(int level, const char *tag, const char *format, ...) {
va_list args;
va_start(args, format);
time_t mytt = time(NULL);
- struct tm *tt;
- tt = localtime(&mytt);
- fprintf(stderr, "%d-%02d-%02dT%02d:%02d:%02d ", tt->tm_year + 1900,
- tt->tm_mon + 1, tt->tm_mday, tt->tm_hour, tt->tm_min, tt->tm_sec);
+
+ struct tm *ptt;
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) // C11
+ struct tm tt;
+ ptt = &tt;
+# if defined (_WIN32) || defined(__STDC_LIB_EXT1__)
+ localtime_s(&tt, &mytt);
+# else
+ localtime_r(&mytt, &tt);
+# endif
+#else
+ ptt = localtime(&mytt);
+#endif
+
+ fprintf(stderr, "%d-%02d-%02dT%02d:%02d:%02d ", ptt->tm_year + 1900,
+ ptt->tm_mon + 1, ptt->tm_mday, ptt->tm_hour, ptt->tm_min, ptt->tm_sec);
switch (level) {
case UDEBUG:
@@ -70,7 +84,7 @@ int ugly_log(int level, const char *tag, const char *format, ...) {
* - LIBUSB_LOG_LEVEL_DEBUG (4) : debug and informational messages are
* printed to stderr
*/
-int ugly_libusb_log_level(enum ugly_loglevel v) {
+int32_t ugly_libusb_log_level(enum ugly_loglevel v) {
#ifdef __FreeBSD__
// FreeBSD includes its own reimplementation of libusb.
// Its libusb_set_debug() function expects a lib_debug_level
diff --git a/src/stlink-lib/logging.h b/src/stlink-lib/logging.h
index 7f39944..560e20e 100644
--- a/src/stlink-lib/logging.h
+++ b/src/stlink-lib/logging.h
@@ -1,13 +1,22 @@
/*
+ * File: logging.h
+ *
+ * UglyLogging: Slow, yet another wheel reinvented, but enough to make the rest of our code pretty enough.
* Ugly, low performance, configurable level, logging "framework"
*/
-#ifndef UGLYLOGGING_H
-#define UGLYLOGGING_H
+#ifndef LOGGING_H
+#define LOGGING_H
+
+#include <stdint.h>
+#include "spdlog_wrapper.h"
#ifdef __cplusplus
extern "C" {
-#endif
+#endif // __cplusplus
+
+/* Optional: Enable interface for SPDLOG to replace UglyLogging */
+// #define SPDLOG_LOGGING
enum ugly_loglevel {
UDEBUG = 90,
@@ -20,11 +29,11 @@ enum ugly_loglevel {
#define PRINTF_ARRT __attribute__ ((format (printf, 3, 4)))
#else
#define PRINTF_ARRT
-#endif
+#endif // __GNUC__
-int ugly_init(int maximum_threshold);
-int ugly_log(int level, const char *tag, const char *format, ...) PRINTF_ARRT;
-int ugly_libusb_log_level(enum ugly_loglevel v);
+int32_t ugly_init(int32_t maximum_threshold);
+int32_t ugly_log(int32_t level, const char *tag, const char *format, ...) PRINTF_ARRT;
+int32_t ugly_libusb_log_level(enum ugly_loglevel v);
#define UGLY_LOG_FILE (strstr(__FILE__, "/") != NULL ? \
strrchr(__FILE__, '/') + 1 : strstr(__FILE__, "\\") != NULL ? \
@@ -41,8 +50,19 @@ int ugly_libusb_log_level(enum ugly_loglevel v);
#define ELOG_HELPER(format, ...) ugly_log(UERROR, UGLY_LOG_FILE, format, __VA_ARGS__)
#define ELOG(...) ugly_log(UERROR, UGLY_LOG_FILE, __VA_ARGS__)
+#if defined(SPDLOG_LOGGING)
+#undef DLOG_HELPER
+#undef ILOG_HELPER
+#undef WLOG_HELPER
+#undef ELOG_HELPER
+#define DLOG(...) spdlogLog(UDEBUG, __VA_ARGS__)
+#define ILOG(...) spdlogLog(UINFO, __VA_ARGS__)
+#define WLOG(...) spdlogLog(UWARN, __VA_ARGS__)
+#define ELOG(...) spdlogLog(UERROR, __VA_ARGS__)
+#endif // SPDLOG_LOGGING
+
#ifdef __cplusplus
}
-#endif
+#endif // __cplusplus
-#endif // UGLYLOGGING_H
+#endif // LOGGING_H
diff --git a/src/stlink-lib/map_file.c b/src/stlink-lib/map_file.c
new file mode 100644
index 0000000..118c80d
--- /dev/null
+++ b/src/stlink-lib/map_file.c
@@ -0,0 +1,110 @@
+/*
+ * File: map_file.c
+ *
+ * File mapping
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include <stlink.h>
+#include "map_file.h"
+
+#include "read_write.h"
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+// 1 GB max file size
+#ifndef MAX_FILE_SIZE
+#define MAX_FILE_SIZE (1<<20)
+#endif
+
+/* Limit the block size to compare to 0x1800 as anything larger will stall the
+ * STLINK2 Maybe STLINK V1 needs smaller value!
+ */
+int32_t check_file(stlink_t *sl, mapped_file_t *mf, stm32_addr_t addr) {
+ uint32_t off;
+ uint32_t n_cmp = sl->flash_pgsz;
+
+ if (n_cmp > 0x1800) {
+ n_cmp = 0x1800;
+ }
+
+ for (off = 0; off < mf->len; off += n_cmp) {
+ uint32_t aligned_size;
+
+ uint32_t cmp_size = n_cmp; // adjust last page size
+
+ if ((off + n_cmp) > mf->len) {
+ cmp_size = mf->len - off;
+ }
+
+ aligned_size = cmp_size;
+
+ if (aligned_size & (4 - 1)) {
+ aligned_size = (cmp_size + 4) & ~(4 - 1);
+ }
+
+ stlink_read_mem32(sl, addr + off, (uint16_t)aligned_size);
+
+ if (memcmp(sl->q_buf, mf->base + off, cmp_size)) {
+ return (-1);
+ }
+ }
+
+ return (0);
+}
+
+int32_t map_file(mapped_file_t *mf, const char *path) {
+ int32_t error = -1;
+ struct stat st;
+
+ const int32_t fd = open(path, O_RDONLY | O_BINARY);
+
+ if (fd == -1) {
+ fprintf(stderr, "open(%s) == -1\n", path);
+ return (-1);
+ }
+
+ if (fstat(fd, &st) == -1) {
+ fprintf(stderr, "fstat(%s) == -1\n", path);
+ goto on_error;
+ }
+
+ if (sizeof(st.st_size) != sizeof(size_t)) {
+ // on 32 bit systems, check if there is an overflow
+ if (st.st_size > (off_t)MAX_FILE_SIZE /*1 GB*/ ) {
+ // limit file size to 1 GB
+ fprintf(stderr, "mmap() uint32_t overflow for file %s\n", path);
+ goto on_error;
+ }
+ }
+
+ mf->base =
+ (uint8_t *)mmap(NULL, (size_t)(st.st_size), PROT_READ, MAP_SHARED, fd, 0);
+
+ if (mf->base == MAP_FAILED) {
+ fprintf(stderr, "mmap() == MAP_FAILED for file %s\n", path);
+ goto on_error;
+ }
+
+ mf->len = (size_t)st.st_size;
+ error = 0; // success
+
+on_error:
+ close(fd);
+ return (error);
+}
+
+void unmap_file(mapped_file_t *mf) {
+ munmap((void *)mf->base, mf->len);
+ mf->base = (unsigned char *)MAP_FAILED;
+ mf->len = 0;
+}
diff --git a/src/stlink-lib/map_file.h b/src/stlink-lib/map_file.h
new file mode 100644
index 0000000..f25602d
--- /dev/null
+++ b/src/stlink-lib/map_file.h
@@ -0,0 +1,33 @@
+/*
+ * File: map_file.h
+ *
+ * File mapping
+ */
+
+#ifndef MAP_FILE_H
+#define MAP_FILE_H
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif // O_BINARY
+
+#ifdef STLINK_HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#else
+#include <mmap.h>
+#endif // STLINK_HAVE_SYS_MMAN_H
+
+/* Memory mapped file */
+typedef struct mapped_file {
+ uint8_t *base;
+ uint32_t len;
+} mapped_file_t;
+
+#define MAPPED_FILE_INITIALIZER \
+ { NULL, 0 }
+
+int32_t check_file(stlink_t *, mapped_file_t *, stm32_addr_t);
+int32_t map_file(mapped_file_t *, const char *);
+void unmap_file(mapped_file_t *);
+
+#endif // MAP_FILE_H
diff --git a/src/stlink-lib/md5.c b/src/stlink-lib/md5.c
index 4c353bf..a5347de 100755..100644
--- a/src/stlink-lib/md5.c
+++ b/src/stlink-lib/md5.c
@@ -1,279 +1,42 @@
/*
- * WjCryptLib_Md5 (https://github.com/WaterJuice/WjCryptLib)
- * Implementation of MD5 hash function. Originally written by Alexander Peslyak.
- * Modified by WaterJuice retaining Public Domain license.
- * This is free and unencumbered software released into the public domain - June 2013 - waterjuice.org
- */
-
-#include <memory.h>
-
-#include "md5.h"
-
-/* INTERNAL FUNCTIONS */
-
-/* F, G, H, I
+ * File: md5.c
*
- * The basic MD5 functions.
- * F and G are optimised compared to their RFC 1321 definitions for architectures
- * that lack an AND-NOT instruction, just like in Colin Plumb's implementation.
- */
-#define F( x, y, z ) ((z) ^ ((x) & ((y) ^ (z))))
-#define G( x, y, z ) ((y) ^ ((z) & ((x) ^ (y))))
-#define H( x, y, z ) ((x) ^ (y) ^ (z))
-#define I( x, y, z ) ((y) ^ ((x) | ~(z)))
-
-/* STEP: The MD5 transformation for all four rounds. */
-#define STEP( f, a, b, c, d, x, t, s ) \
- (a) += f((b), (c), (d)) + (x) + (t); \
- (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
- (a) += (b);
-
-/* TransformFunction
- * This processes one or more 64-byte data blocks, but does NOT update the bit counters.
- * There are no alignment requirements.
- */
-static void* TransformFunction(Md5Context* ctx, void const* data, uintmax_t size) {
- uint8_t* ptr;
- uint32_t a;
- uint32_t b;
- uint32_t c;
- uint32_t d;
- uint32_t saved_a;
- uint32_t saved_b;
- uint32_t saved_c;
- uint32_t saved_d;
-
- #define GET(n) (ctx->block[(n)])
- #define SET(n) (ctx->block[(n)] = ((uint32_t)ptr[(n) * 4 + 0] << 0) | \
- ((uint32_t)ptr[(n) * 4 + 1] << 8) | \
- ((uint32_t)ptr[(n) * 4 + 2] << 16) | \
- ((uint32_t)ptr[(n) * 4 + 3] << 24))
-
- ptr = (uint8_t*)data;
-
- a = ctx->a;
- b = ctx->b;
- c = ctx->c;
- d = ctx->d;
-
- do {
- saved_a = a;
- saved_b = b;
- saved_c = c;
- saved_d = d;
-
- // Round 1
- STEP( F, a, b, c, d, SET(0), 0xd76aa478, 7 )
- STEP( F, d, a, b, c, SET(1), 0xe8c7b756, 12 )
- STEP( F, c, d, a, b, SET(2), 0x242070db, 17 )
- STEP( F, b, c, d, a, SET(3), 0xc1bdceee, 22 )
- STEP( F, a, b, c, d, SET(4), 0xf57c0faf, 7 )
- STEP( F, d, a, b, c, SET(5), 0x4787c62a, 12 )
- STEP( F, c, d, a, b, SET(6), 0xa8304613, 17 )
- STEP( F, b, c, d, a, SET(7), 0xfd469501, 22 )
- STEP( F, a, b, c, d, SET(8 ), 0x698098d8, 7 )
- STEP( F, d, a, b, c, SET(9 ), 0x8b44f7af, 12 )
- STEP( F, c, d, a, b, SET(10 ), 0xffff5bb1, 17 )
- STEP( F, b, c, d, a, SET(11 ), 0x895cd7be, 22 )
- STEP( F, a, b, c, d, SET(12 ), 0x6b901122, 7 )
- STEP( F, d, a, b, c, SET(13 ), 0xfd987193, 12 )
- STEP( F, c, d, a, b, SET(14 ), 0xa679438e, 17 )
- STEP( F, b, c, d, a, SET(15 ), 0x49b40821, 22 )
-
- // Round 2
- STEP( G, a, b, c, d, GET(1), 0xf61e2562, 5 )
- STEP( G, d, a, b, c, GET(6), 0xc040b340, 9 )
- STEP( G, c, d, a, b, GET(11), 0x265e5a51, 14 )
- STEP( G, b, c, d, a, GET(0), 0xe9b6c7aa, 20 )
- STEP( G, a, b, c, d, GET(5), 0xd62f105d, 5 )
- STEP( G, d, a, b, c, GET(10), 0x02441453, 9 )
- STEP( G, c, d, a, b, GET(15), 0xd8a1e681, 14 )
- STEP( G, b, c, d, a, GET(4), 0xe7d3fbc8, 20 )
- STEP( G, a, b, c, d, GET(9), 0x21e1cde6, 5 )
- STEP( G, d, a, b, c, GET(14), 0xc33707d6, 9 )
- STEP( G, c, d, a, b, GET(3), 0xf4d50d87, 14 )
- STEP( G, b, c, d, a, GET(8), 0x455a14ed, 20 )
- STEP( G, a, b, c, d, GET(13), 0xa9e3e905, 5 )
- STEP( G, d, a, b, c, GET(2), 0xfcefa3f8, 9 )
- STEP( G, c, d, a, b, GET(7), 0x676f02d9, 14 )
- STEP( G, b, c, d, a, GET(12), 0x8d2a4c8a, 20 )
-
- // Round 3
- STEP( H, a, b, c, d, GET(5), 0xfffa3942, 4 )
- STEP( H, d, a, b, c, GET(8), 0x8771f681, 11 )
- STEP( H, c, d, a, b, GET(11), 0x6d9d6122, 16 )
- STEP( H, b, c, d, a, GET(14), 0xfde5380c, 23 )
- STEP( H, a, b, c, d, GET(1), 0xa4beea44, 4 )
- STEP( H, d, a, b, c, GET(4), 0x4bdecfa9, 11 )
- STEP( H, c, d, a, b, GET(7), 0xf6bb4b60, 16 )
- STEP( H, b, c, d, a, GET(10), 0xbebfbc70, 23 )
- STEP( H, a, b, c, d, GET(13), 0x289b7ec6, 4 )
- STEP( H, d, a, b, c, GET(0), 0xeaa127fa, 11 )
- STEP( H, c, d, a, b, GET(3), 0xd4ef3085, 16 )
- STEP( H, b, c, d, a, GET(6), 0x04881d05, 23 )
- STEP( H, a, b, c, d, GET(9), 0xd9d4d039, 4 )
- STEP( H, d, a, b, c, GET(12), 0xe6db99e5, 11 )
- STEP( H, c, d, a, b, GET(15), 0x1fa27cf8, 16 )
- STEP( H, b, c, d, a, GET(2), 0xc4ac5665, 23 )
-
- // Round 4
- STEP( I, a, b, c, d, GET(0), 0xf4292244, 6 )
- STEP( I, d, a, b, c, GET(7), 0x432aff97, 10 )
- STEP( I, c, d, a, b, GET(14), 0xab9423a7, 15 )
- STEP( I, b, c, d, a, GET(5), 0xfc93a039, 21 )
- STEP( I, a, b, c, d, GET(12), 0x655b59c3, 6 )
- STEP( I, d, a, b, c, GET(3), 0x8f0ccc92, 10 )
- STEP( I, c, d, a, b, GET(10), 0xffeff47d, 15 )
- STEP( I, b, c, d, a, GET(1), 0x85845dd1, 21 )
- STEP( I, a, b, c, d, GET(8), 0x6fa87e4f, 6 )
- STEP( I, d, a, b, c, GET(15), 0xfe2ce6e0, 10 )
- STEP( I, c, d, a, b, GET(6), 0xa3014314, 15 )
- STEP( I, b, c, d, a, GET(13), 0x4e0811a1, 21 )
- STEP( I, a, b, c, d, GET(4), 0xf7537e82, 6 )
- STEP( I, d, a, b, c, GET(11), 0xbd3af235, 10 )
- STEP( I, c, d, a, b, GET(2), 0x2ad7d2bb, 15 )
- STEP( I, b, c, d, a, GET(9), 0xeb86d391, 21 )
-
- a += saved_a;
- b += saved_b;
- c += saved_c;
- d += saved_d;
-
- ptr += 64;
- } while ( size -= 64 );
-
- ctx->a = a;
- ctx->b = b;
- ctx->c = c;
- ctx->d = d;
-
- #undef GET
- #undef SET
-
- return(ptr);
-}
-
-/* EXPORTED FUNCTIONS */
-
-/* Md5Initialise
- * Initialises an MD5 Context.
- * Use this to initialise/reset a context.
- */
-void Md5Initialise(Md5Context* Context /* [out] */) {
- Context->a = 0x67452301;
- Context->b = 0xefcdab89;
- Context->c = 0x98badcfe;
- Context->d = 0x10325476;
-
- Context->lo = 0;
- Context->hi = 0;
-}
-
-/* Md5Update
- * Adds data to the MD5 context.
- * This will process the data and update the internal state of the context.
- * Keep on calling this function until all the data has been added.
- * Then call Md5Finalise to calculate the hash.
+ * MD5 hash function
*/
-void Md5Update(Md5Context* Context /* [in out] */, void const* Buffer /* [in] */, uint32_t BufferSize /* [in] */) {
- uint32_t saved_lo;
- uint32_t used;
- uint32_t free;
-
- saved_lo = Context->lo;
-
- if ((Context->lo = (saved_lo + BufferSize) & 0x1fffffff) < saved_lo) {
- Context->hi++;
- }
- Context->hi += (uint32_t)(BufferSize >> 29);
+#include <stdint.h>
+#include <stdio.h>
- used = saved_lo & 0x3f;
-
- if ( used ) {
- free = 64 - used;
+#include <stlink.h>
+#include "md5.h"
- if ( BufferSize < free ) {
- memcpy( &Context->buffer[used], Buffer, BufferSize );
- return;
- }
+#include "map_file.h"
+#include "lib_md5.h"
- memcpy( &Context->buffer[used], Buffer, free );
- Buffer = (uint8_t*)Buffer + free;
- BufferSize -= free;
- TransformFunction(Context, Context->buffer, 64);
- }
+void md5_calculate(mapped_file_t *mf) {
+ // calculate md5 checksum of given binary file
+ Md5Context md5Context;
+ MD5_HASH md5Hash;
+ Md5Initialise(&md5Context);
+ Md5Update(&md5Context, mf->base, (uint32_t)mf->len);
+ Md5Finalise(&md5Context, &md5Hash);
+ printf("md5 checksum: ");
- if ( BufferSize >= 64 ) {
- Buffer = TransformFunction( Context, Buffer, BufferSize & ~(unsigned long)0x3f );
- BufferSize &= 0x3f;
- }
+ for (int32_t i = 0; i < (int32_t)sizeof(md5Hash); i++) {
+ printf("%x", md5Hash.bytes[i]);
+ }
- memcpy( Context->buffer, Buffer, BufferSize );
+ printf(", ");
}
-/* Md5Finalise
- * Performs the final calculation of the hash and returns the digest
- * (16 byte buffer containing 128bit hash).
- * After calling this, Md5Initialised must be used to reuse the context.
- */
-void Md5Finalise(Md5Context* Context /* [in out] */, MD5_HASH* Digest /* [in] */) {
- uint32_t used;
- uint32_t free;
+void stlink_checksum(mapped_file_t *mp) {
+ /* checksum that backward compatible with official ST tools */
+ uint32_t sum = 0;
+ uint8_t *mp_byte = (uint8_t *)mp->base;
- used = Context->lo & 0x3f;
+ for (uint32_t i = 0; i < mp->len; ++i) {
+ sum += mp_byte[i];
+ }
- Context->buffer[used++] = 0x80;
-
- free = 64 - used;
-
- if (free < 8) {
- memset( &Context->buffer[used], 0, free );
- TransformFunction( Context, Context->buffer, 64 );
- used = 0;
- free = 64;
- }
-
- memset( &Context->buffer[used], 0, free - 8 );
-
- Context->lo <<= 3;
- Context->buffer[56] = (uint8_t)(Context->lo);
- Context->buffer[57] = (uint8_t)(Context->lo >> 8);
- Context->buffer[58] = (uint8_t)(Context->lo >> 16);
- Context->buffer[59] = (uint8_t)(Context->lo >> 24);
- Context->buffer[60] = (uint8_t)(Context->hi);
- Context->buffer[61] = (uint8_t)(Context->hi >> 8);
- Context->buffer[62] = (uint8_t)(Context->hi >> 16);
- Context->buffer[63] = (uint8_t)(Context->hi >> 24);
-
- TransformFunction( Context, Context->buffer, 64 );
-
- Digest->bytes[0] = (uint8_t)(Context->a);
- Digest->bytes[1] = (uint8_t)(Context->a >> 8);
- Digest->bytes[2] = (uint8_t)(Context->a >> 16);
- Digest->bytes[3] = (uint8_t)(Context->a >> 24);
- Digest->bytes[4] = (uint8_t)(Context->b);
- Digest->bytes[5] = (uint8_t)(Context->b >> 8);
- Digest->bytes[6] = (uint8_t)(Context->b >> 16);
- Digest->bytes[7] = (uint8_t)(Context->b >> 24);
- Digest->bytes[8] = (uint8_t)(Context->c);
- Digest->bytes[9] = (uint8_t)(Context->c >> 8);
- Digest->bytes[10] = (uint8_t)(Context->c >> 16);
- Digest->bytes[11] = (uint8_t)(Context->c >> 24);
- Digest->bytes[12] = (uint8_t)(Context->d);
- Digest->bytes[13] = (uint8_t)(Context->d >> 8);
- Digest->bytes[14] = (uint8_t)(Context->d >> 16);
- Digest->bytes[15] = (uint8_t)(Context->d >> 24);
-}
-
-/* Md5Calculate
- * Combines Md5Initialise, Md5Update, and Md5Finalise into one function.
- * Calculates the MD5 hash of the buffer.
- */
-void Md5Calculate(void const* Buffer /* [in] */, uint32_t BufferSize /* [in] */, MD5_HASH* Digest /* [in] */) {
- Md5Context context;
-
- Md5Initialise( &context );
- Md5Update( &context, Buffer, BufferSize );
- Md5Finalise( &context, Digest );
-}
+ printf("stlink checksum: 0x%08x\n", sum);
+} \ No newline at end of file
diff --git a/src/stlink-lib/md5.h b/src/stlink-lib/md5.h
index a69d7fc..f5591e2 100755..100644
--- a/src/stlink-lib/md5.h
+++ b/src/stlink-lib/md5.h
@@ -1,63 +1,15 @@
/*
- * WjCryptLib_Md5 (https://github.com/WaterJuice/WjCryptLib)
- * Implementation of MD5 hash function. Originally written by Alexander Peslyak.
- * Modified by WaterJuice retaining Public Domain license.
- * This is free and unencumbered software released into the public domain - June 2013 - waterjuice.org
+ * File: md5.h
+ *
+ * MD5 hash function
*/
-#pragma once
+#ifndef MD5_H
+#define MD5_H
-#include <stdint.h>
-#include <stdio.h>
+#include "map_file.h"
-/* TYPES */
+void md5_calculate(mapped_file_t *);
+void stlink_checksum(mapped_file_t *);
-/* Md5Context
- * This must be initialised using Md5Initialised.
- * Do not modify the contents of this structure directly.
- */
-typedef struct {
- uint32_t lo;
- uint32_t hi;
- uint32_t a;
- uint32_t b;
- uint32_t c;
- uint32_t d;
- uint8_t buffer[64];
- uint32_t block[16];
-} Md5Context;
-
-#define MD5_HASH_SIZE (128 / 8)
-
-typedef struct {
- uint8_t bytes [MD5_HASH_SIZE];
-} MD5_HASH;
-
-/* PUBLIC FUNCTIONS */
-
-/* Md5Initialise
- * Initialises an MD5 Context.
- * Use this to initialise/reset a context.
- */
-void Md5Initialise(Md5Context* Context /* [out] */);
-
-/* Md5Update
- * Adds data to the MD5 context.
- * This will process the data and update the internal state of the context.
- * Keep on calling this function until all the data has been added.
- * Then call Md5Finalise to calculate the hash.
- */
-void Md5Update(Md5Context* Context /* [in out] */, void const* Buffer /* [in] */, uint32_t BufferSize /* [in] */);
-
-/* Md5Finalise
- * Performs the final calculation of the hash and returns the digest
- * (16 byte buffer containing 128bit hash).
- * After calling this, Md5Initialised must be used to reuse the context.
- */
-void Md5Finalise(Md5Context* Context /* [in out] */, MD5_HASH* Digest /* [in] */);
-
-/* Md5Calculate
- * Combines Md5Initialise, Md5Update, and Md5Finalise into one function.
- * Calculates the MD5 hash of the buffer.
- */
-void Md5Calculate(void const* Buffer /* [in] */, uint32_t BufferSize /* [in] */, MD5_HASH* Digest /* [in] */);
+#endif // MD5_H \ No newline at end of file
diff --git a/src/stlink-lib/option_bytes.c b/src/stlink-lib/option_bytes.c
new file mode 100644
index 0000000..d49c346
--- /dev/null
+++ b/src/stlink-lib/option_bytes.c
@@ -0,0 +1,1180 @@
+/*
+ * File: option_bytes.c
+ *
+ * Read and write option bytes and option control registers
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <stlink.h>
+#include "option_bytes.h"
+
+#include "common_flash.h"
+#include "flash_loader.h"
+#include "logging.h"
+#include "map_file.h"
+#include "md5.h"
+#include "read_write.h"
+
+/**
+ * Read option control register C0
+ * @param sl
+ * @param option_byte
+ * @return 0 on success, -ve on failure.
+ */
+static int32_t stlink_read_option_control_register_c0(stlink_t *sl, uint32_t *option_byte) {
+ return stlink_read_debug32(sl, FLASH_C0_OPTR, option_byte);
+}
+
+/**
+ * Read option bytes C0
+ * @param sl
+ * @param option_byte
+ * @return 0 on success, -ve on failure.
+ */
+static int32_t stlink_read_option_bytes_c0(stlink_t *sl, uint32_t *option_byte) {
+ return stlink_read_option_control_register_c0(sl, option_byte);
+}
+
+/**
+ * Write option control register C0
+ * @param sl
+ * @param option_cr
+ * @return 0 on success, -ve on failure.
+ */
+static int32_t stlink_write_option_control_register_c0(stlink_t *sl, uint32_t option_cr) {
+ int32_t ret = 0;
+
+ clear_flash_error(sl);
+
+ if ((ret = stlink_write_debug32(sl, FLASH_C0_OPTR, option_cr)))
+ return ret;
+
+ wait_flash_busy(sl);
+
+ uint32_t cr_reg = (1 << FLASH_C0_CR_OPTSTRT);
+ if ((ret = stlink_write_debug32(sl, FLASH_C0_CR, cr_reg)))
+ return ret;
+
+ wait_flash_busy(sl);
+
+ if ((ret = check_flash_error(sl)))
+ return ret;
+
+ // trigger the load of option bytes into option registers
+ cr_reg = (1 << FLASH_C0_CR_OBL_LAUNCH);
+ stlink_write_debug32(sl, FLASH_C0_CR, cr_reg);
+
+ return ret;
+}
+
+/**
+ * Write option bytes C0
+ * @param sl
+ * @param addr of the memory mapped option bytes
+ * @param base option bytes
+ * @param len of option bytes
+ * @return 0 on success, -ve on failure.
+ */
+static int32_t stlink_write_option_bytes_c0(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) {
+ (void)addr;
+ (void)len;
+
+ return stlink_write_option_control_register_c0(sl, *(uint32_t*)base);
+}
+
+/**
+ * Read option control register F0
+ * @param sl
+ * @param option_byte
+ * @return 0 on success, -ve on failure.
+ */
+int32_t stlink_read_option_control_register_f0(stlink_t *sl, uint32_t *option_byte) {
+ DLOG("@@@@ Read option control register byte from %#10x\n", FLASH_OBR);
+ return stlink_read_debug32(sl, FLASH_OBR, option_byte);
+}
+
+/**
+ * Write option bytes F0
+ * @param sl
+ * @param addr of the memory mapped option bytes
+ * @param base option bytes
+ * @param len of option bytes
+ * @return 0 on success, -ve on failure.
+ */
+static int32_t stlink_write_option_bytes_f0(stlink_t *sl, stm32_addr_t addr, uint8_t* base, uint32_t len) {
+ int32_t ret = 0;
+
+ if (len < 12 || addr != STM32_F0_OPTION_BYTES_BASE) {
+ WLOG("Only full write of option bytes area is supported\n");
+ return -1;
+ }
+
+ clear_flash_error(sl);
+
+ WLOG("Erasing option bytes\n");
+
+ /* erase option bytes */
+ stlink_write_debug32(sl, FLASH_CR, (1 << FLASH_CR_OPTER) | (1 << FLASH_CR_OPTWRE));
+ ret = stlink_write_debug32(sl, FLASH_CR, (1 << FLASH_CR_OPTER) | (1 << FLASH_CR_STRT) | (1 << FLASH_CR_OPTWRE));
+ if (ret) {
+ return ret;
+ }
+
+ wait_flash_busy(sl);
+
+ ret = check_flash_error(sl);
+ if (ret) {
+ return ret;
+ }
+
+ WLOG("Writing option bytes to %#10x\n", addr);
+
+ /* Set the Option PG bit to enable programming */
+ stlink_write_debug32(sl, FLASH_CR, (1 << FLASH_CR_OPTPG) | (1 << FLASH_CR_OPTWRE));
+
+ /* Use flash loader for write OP
+ * because flash memory writable by half word */
+ flash_loader_t fl;
+ ret = stlink_flash_loader_init(sl, &fl);
+ if (ret) {
+ return ret;
+ }
+ ret = stlink_flash_loader_run(sl, &fl, addr, base, len);
+ if (ret) {
+ return ret;
+ }
+
+ /* Reload option bytes */
+ stlink_write_debug32(sl, FLASH_CR, (1 << FLASH_CR_OBL_LAUNCH));
+
+ return check_flash_error(sl);
+}
+
+/**
+ * Write option control register F0
+ * @param sl
+ * @param option_cr
+ * @return 0 on success, -ve on failure.
+ */
+static int32_t stlink_write_option_control_register_f0(stlink_t *sl, uint32_t option_cr) {
+ int32_t ret = 0;
+ uint16_t opt_val[8];
+ uint32_t protection, optiondata;
+ uint16_t user_options, user_data, rdp;
+ uint32_t option_offset, user_data_offset;
+
+ ILOG("Asked to write option control register %#10x to %#010x.\n", option_cr, FLASH_OBR);
+
+ /* Clear errors */
+ clear_flash_error(sl);
+
+ /* Retrieve current values */
+ ret = stlink_read_debug32(sl, FLASH_OBR, &optiondata);
+ if (ret) {
+ return ret;
+ }
+ ret = stlink_read_debug32(sl, FLASH_WRPR, &protection);
+ if (ret) {
+ return ret;
+ }
+
+ /* Translate OBR value to flash store structure
+ * F0: RM0091, Option byte description, pp. 75-78
+ * F1: PM0075, Option byte description, pp. 19-22
+ * F3: RM0316, Option byte description, pp. 85-87 */
+ switch(sl->chip_id)
+ {
+ case 0x422: /* STM32F30x */
+ case 0x432: /* STM32F37x */
+ case 0x438: /* STM32F303x6/8 and STM32F328 */
+ case 0x446: /* STM32F303xD/E and STM32F398xE */
+ case 0x439: /* STM32F302x6/8 */
+ case 0x440: /* STM32F05x */
+ case 0x444: /* STM32F03x */
+ case 0x445: /* STM32F04x */
+ case 0x448: /* STM32F07x */
+ case 0x442: /* STM32F09x */
+ option_offset = 6;
+ user_data_offset = 16;
+ rdp = 0x55AA;
+ break;
+ default:
+ option_offset = 0;
+ user_data_offset = 10;
+ rdp = 0x5AA5;
+ break;
+ }
+
+ user_options = (option_cr >> option_offset >> 2) & 0xFFFF;
+ user_data = (option_cr >> user_data_offset) & 0xFFFF;
+
+#define VAL_WITH_COMPLEMENT(v) (uint16_t)(((v)&0xFF) | (((~(v))<<8)&0xFF00))
+
+ opt_val[0] = (option_cr & (1 << 1/*OPT_READOUT*/)) ? 0xFFFF : rdp;
+ opt_val[1] = VAL_WITH_COMPLEMENT(user_options);
+ opt_val[2] = VAL_WITH_COMPLEMENT(user_data);
+ opt_val[3] = VAL_WITH_COMPLEMENT(user_data >> 8);
+ opt_val[4] = VAL_WITH_COMPLEMENT(protection);
+ opt_val[5] = VAL_WITH_COMPLEMENT(protection >> 8);
+ opt_val[6] = VAL_WITH_COMPLEMENT(protection >> 16);
+ opt_val[7] = VAL_WITH_COMPLEMENT(protection >> 24);
+
+#undef VAL_WITH_COMPLEMENT
+
+ /* Write bytes and check errors */
+ ret = stlink_write_option_bytes_f0(sl, STM32_F0_OPTION_BYTES_BASE, (uint8_t*)opt_val, sizeof(opt_val));
+ if (ret)
+ return ret;
+
+ ret = check_flash_error(sl);
+ if (!ret) {
+ ILOG("Wrote option bytes %#010x to %#010x!\n", option_cr,
+ FLASH_OBR);
+ }
+
+ return ret;
+}
+
+/**
+ * Read option control register F2
+ * @param sl
+ * @param option_byte
+ * @return 0 on success, -ve on failure.
+ */
+int32_t stlink_read_option_control_register_f2(stlink_t *sl, uint32_t *option_byte) {
+ return stlink_read_debug32(sl, FLASH_F2_OPT_CR, option_byte);
+}
+
+/**
+ * Read option bytes F2
+ * @param sl
+ * @param option_byte
+ * @return 0 on success, -ve on failure.
+ */
+int32_t stlink_read_option_bytes_f2(stlink_t *sl, uint32_t *option_byte) {
+ return stlink_read_option_control_register_f2(sl, option_byte);
+}
+
+/**
+ * Read option control register F4
+ * @param sl
+ * @param option_byte
+ * @return 0 on success, -ve on failure.
+ */
+int32_t stlink_read_option_control_register_f4(stlink_t *sl, uint32_t *option_byte) {
+ return stlink_read_debug32(sl, FLASH_F4_OPTCR, option_byte);
+}
+
+/**
+ * Read option bytes F4
+ * @param sl
+ * @param option_byte
+ * @return 0 on success, -ve on failure.
+ */
+int32_t stlink_read_option_bytes_f4(stlink_t *sl, uint32_t *option_byte) {
+ return stlink_read_option_control_register_f4(sl, option_byte);
+}
+
+/**
+ * Write option bytes F4
+ * @param sl
+ * @param addr of the memory mapped option bytes
+ * @param base option bytes
+ * @param len of option bytes
+ * @return 0 on success, -ve on failure.
+ */
+static int32_t stlink_write_option_bytes_f4(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) {
+ uint32_t option_byte;
+ int32_t ret = 0;
+ (void)addr;
+ (void)len;
+
+ // Clear errors
+ clear_flash_error(sl);
+
+ write_uint32((unsigned char *)&option_byte, *(uint32_t *)(base));
+
+ // write option byte, ensuring we dont lock opt, and set strt bit
+ stlink_write_debug32(sl, FLASH_F4_OPTCR,
+ (option_byte & ~(1 << FLASH_F4_OPTCR_LOCK)) |
+ (1 << FLASH_F4_OPTCR_START));
+
+ wait_flash_busy(sl);
+ ret = check_flash_error(sl);
+
+ // option bytes are reloaded at reset only, no obl. */
+ return (ret);
+}
+
+/**
+ * Read option bytes F7
+ * @param sl
+ * @param option_byte
+ * @return 0 on success, -ve on failure.
+ */
+// Since multiple bytes can be read, we read and print32_t all, but one here
+// and then return the last one just like other devices.
+int32_t stlink_read_option_bytes_f7(stlink_t *sl, uint32_t *option_byte) {
+ int32_t err = -1;
+ for (uint32_t counter = 0; counter < (sl->option_size / 4 - 1); counter++) {
+ err = stlink_read_debug32(sl, sl->option_base + counter * sizeof(uint32_t), option_byte);
+ if (err == -1) {
+ return err;
+ } else {
+ printf("%08x\n", *option_byte);
+ }
+ }
+
+ return stlink_read_debug32(
+ sl,
+ sl->option_base + (uint32_t)(sl->option_size / 4 - 1) * sizeof(uint32_t),
+ option_byte);
+}
+
+/**
+ * Write option bytes F7
+ * @param sl
+ * @param addr of the memory mapped option bytes
+ * @param base option bytes
+ * @param len of option bytes
+ * @return 0 on success, -ve on failure.
+ */
+static int32_t stlink_write_option_bytes_f7(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) {
+ uint32_t option_byte;
+ int32_t ret = 0;
+
+ // Clear errors
+ clear_flash_error(sl);
+
+ ILOG("Asked to write option byte %#10x to %#010x.\n", *(uint32_t *)(base), addr);
+ write_uint32((unsigned char *)&option_byte, *(uint32_t *)(base));
+ ILOG("Write %d option bytes %#010x to %#010x!\n", len, option_byte, addr);
+
+ if (addr == 0) {
+ addr = FLASH_F7_OPTCR;
+ ILOG("No address provided, using %#10x\n", addr);
+ }
+
+ if (addr == FLASH_F7_OPTCR) {
+ /* write option byte, ensuring we dont lock opt, and set strt bit */
+ stlink_write_debug32(sl, FLASH_F7_OPTCR,
+ (option_byte & ~(1 << FLASH_F7_OPTCR_LOCK)) |
+ (1 << FLASH_F7_OPTCR_START));
+ } else if (addr == FLASH_F7_OPTCR1) {
+ // Read FLASH_F7_OPTCR
+ uint32_t oldvalue;
+ stlink_read_debug32(sl, FLASH_F7_OPTCR, &oldvalue);
+ /* write option byte */
+ stlink_write_debug32(sl, FLASH_F7_OPTCR1, option_byte);
+ // Write FLASH_F7_OPTCR lock and start address
+ stlink_write_debug32(sl, FLASH_F7_OPTCR,
+ (oldvalue & ~(1 << FLASH_F7_OPTCR_LOCK)) |
+ (1 << FLASH_F7_OPTCR_START));
+ } else {
+ WLOG("WIP: write %#010x to address %#010x\n", option_byte, addr);
+ stlink_write_debug32(sl, addr, option_byte);
+ }
+
+ wait_flash_busy(sl);
+
+ ret = check_flash_error(sl);
+ if (!ret)
+ ILOG("Wrote %d option bytes %#010x to %#010x!\n", len, *(uint32_t *)base, addr);
+
+ /* option bytes are reloaded at reset only, no obl. */
+
+ return ret;
+}
+
+/**
+ * Read option control register F7
+ * @param sl
+ * @param option_byte
+ * @return 0 on success, -ve on failure.
+ */
+int32_t stlink_read_option_control_register_f7(stlink_t *sl, uint32_t *option_byte) {
+ DLOG("@@@@ Read option control register byte from %#10x\n", FLASH_F7_OPTCR);
+ return stlink_read_debug32(sl, FLASH_F7_OPTCR, option_byte);
+}
+
+/**
+ * Write option control register F7
+ * @param sl
+ * @param option_cr
+ * @return 0 on success, -ve on failure.
+ */
+static int32_t stlink_write_option_control_register_f7(stlink_t *sl, uint32_t option_cr) {
+ int32_t ret = 0;
+
+ // Clear errors
+ clear_flash_error(sl);
+
+ ILOG("Asked to write option control register 1 %#10x to %#010x.\n",
+ option_cr, FLASH_F7_OPTCR);
+
+ /* write option byte, ensuring we dont lock opt, and set strt bit */
+ stlink_write_debug32(sl, FLASH_F7_OPTCR,
+ (option_cr & ~(1 << FLASH_F7_OPTCR_LOCK)) |
+ (1 << FLASH_F7_OPTCR_START));
+
+ wait_flash_busy(sl);
+
+ ret = check_flash_error(sl);
+ if (!ret)
+ ILOG("Wrote option bytes %#010x to %#010x!\n", option_cr,
+ FLASH_F7_OPTCR);
+
+ return ret;
+}
+
+/**
+ * Read option control register1 F7
+ * @param sl
+ * @param option_byte
+ * @return 0 on success, -ve on failure.
+ */
+int32_t stlink_read_option_control_register1_f7(stlink_t *sl, uint32_t *option_byte) {
+ DLOG("@@@@ Read option control register 1 byte from %#10x\n",
+ FLASH_F7_OPTCR1);
+ return stlink_read_debug32(sl, FLASH_F7_OPTCR1, option_byte);
+}
+
+/**
+ * Write option control register1 F7
+ * @param sl
+ * @param option_cr1
+ * @return 0 on success, -ve on failure.
+ */
+static int32_t stlink_write_option_control_register1_f7(stlink_t *sl, uint32_t option_cr1) {
+ int32_t ret = 0;
+
+ // Clear errors
+ clear_flash_error(sl);
+
+ ILOG("Asked to write option control register 1 %#010x to %#010x.\n",
+ option_cr1, FLASH_F7_OPTCR1);
+
+ /* write option byte, ensuring we dont lock opt, and set strt bit */
+ uint32_t current_control_register_value;
+ stlink_read_debug32(sl, FLASH_F7_OPTCR, &current_control_register_value);
+
+ /* write option byte */
+ stlink_write_debug32(sl, FLASH_F7_OPTCR1, option_cr1);
+ stlink_write_debug32(
+ sl, FLASH_F7_OPTCR,
+ (current_control_register_value & ~(1 << FLASH_F7_OPTCR_LOCK)) |
+ (1 << FLASH_F7_OPTCR_START));
+
+ wait_flash_busy(sl);
+
+ ret = check_flash_error(sl);
+ if (!ret)
+ ILOG("Wrote option bytes %#010x to %#010x!\n", option_cr1, FLASH_F7_OPTCR1);
+
+ return ret;
+}
+
+/**
+ * Read option bytes boot address F7
+ * @param sl
+ * @param option_byte
+ * @return 0 on success, -ve on failure.
+ */
+int32_t stlink_read_option_bytes_boot_add_f7(stlink_t *sl, uint32_t *option_byte) {
+ DLOG("@@@@ Read option byte boot address\n");
+ return stlink_read_option_control_register1_f7(sl, option_byte);
+}
+
+/**
+ * Write option bytes boot address F7
+ * @param sl
+ * @param option_byte
+ * @return 0 on success, -ve on failure.
+ */
+static int32_t stlink_write_option_bytes_boot_add_f7(stlink_t *sl, uint32_t option_byte_boot_add) {
+ ILOG("Asked to write option byte boot add %#010x.\n", option_byte_boot_add);
+ return stlink_write_option_control_register1_f7(sl, option_byte_boot_add);
+}
+
+/**
+ * Read option control register Gx
+ * @param sl
+ * @param option_byte
+ * @return 0 on success, -ve on failure.
+ */
+int32_t stlink_read_option_control_register_gx(stlink_t *sl, uint32_t *option_byte) {
+ return stlink_read_debug32(sl, FLASH_Gx_OPTR, option_byte);
+}
+
+/**
+ * Read option bytes Gx
+ * @param sl
+ * @param option_byte
+ * @return 0 on success, -ve on failure.
+ */
+int32_t stlink_read_option_bytes_gx(stlink_t *sl, uint32_t *option_byte) {
+ return stlink_read_option_control_register_gx(sl, option_byte);
+}
+
+/**
+ * Write option bytes Gx
+ * @param sl
+ * @param addr of the memory mapped option bytes
+ * @param base option bytes
+ * @param len of option bytes
+ * @return 0 on success, -ve on failure.
+ */
+static int32_t stlink_write_option_bytes_gx(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) {
+ /* Write options bytes */
+ uint32_t val;
+ int32_t ret = 0;
+ (void)len;
+ uint32_t data;
+
+ clear_flash_error(sl);
+
+ write_uint32((unsigned char *)&data, *(uint32_t *)(base));
+ WLOG("Writing option bytes %#10x to %#10x\n", data, addr);
+ stlink_write_debug32(sl, FLASH_Gx_OPTR, data);
+
+ // Set Options Start bit
+ stlink_read_debug32(sl, FLASH_Gx_CR, &val);
+ val |= (1 << FLASH_Gx_CR_OPTSTRT);
+ stlink_write_debug32(sl, FLASH_Gx_CR, val);
+
+ wait_flash_busy(sl);
+
+ ret = check_flash_error(sl);
+
+ // Reload options
+ stlink_read_debug32(sl, FLASH_Gx_CR, &val);
+ val |= (1 << FLASH_Gx_CR_OBL_LAUNCH);
+ stlink_write_debug32(sl, FLASH_Gx_CR, val);
+
+ return (ret);
+}
+
+/**
+ * Write option bytes H7
+ * @param sl
+ * @param addr of the memory mapped option bytes
+ * @param base option bytes
+ * @param len of option bytes
+ * @return 0 on success, -ve on failure.
+ */
+static int32_t stlink_write_option_bytes_h7(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) {
+ uint32_t val;
+ uint32_t data;
+
+ // Wait until previous flash option has completed
+ wait_flash_busy(sl);
+
+ // Clear previous error
+ stlink_write_debug32(sl, FLASH_H7_OPTCCR,
+ 1 << FLASH_H7_OPTCCR_CLR_OPTCHANGEERR);
+
+ while (len != 0) {
+ switch (addr) {
+ case FLASH_H7_REGS_ADDR + 0x20: // FLASH_OPTSR_PRG
+ case FLASH_H7_REGS_ADDR + 0x2c: // FLASH_PRAR_PRG1
+ case FLASH_H7_REGS_ADDR + 0x34: // FLASH_SCAR_PRG1
+ case FLASH_H7_REGS_ADDR + 0x3c: // FLASH_WPSN_PRG1
+ case FLASH_H7_REGS_ADDR + 0x44: // FLASH_BOOT_PRG
+ /* Write to FLASH_xxx_PRG registers */
+ write_uint32((unsigned char *)&data, *(uint32_t *)(base)); // write options bytes
+
+ WLOG("Writing option bytes %#10x to %#10x\n", data, addr);
+
+ /* Skip if the value in the CUR register is identical */
+ stlink_read_debug32(sl, addr - 4, &val);
+ if (val == data) {
+ break;
+ }
+
+ /* Write new option byte values and start modification */
+ stlink_write_debug32(sl, addr, data);
+ stlink_read_debug32(sl, FLASH_H7_OPTCR, &val);
+ val |= (1 << FLASH_H7_OPTCR_OPTSTART);
+ stlink_write_debug32(sl, FLASH_H7_OPTCR, val);
+
+ /* Wait for the option bytes modification to complete */
+ do {
+ stlink_read_debug32(sl, FLASH_H7_OPTSR_CUR, &val);
+ } while ((val & (1 << FLASH_H7_OPTSR_OPT_BUSY)) != 0);
+
+ /* Check for errors */
+ if ((val & (1 << FLASH_H7_OPTSR_OPTCHANGEERR)) != 0) {
+ stlink_write_debug32(sl, FLASH_H7_OPTCCR, 1 << FLASH_H7_OPTCCR_CLR_OPTCHANGEERR);
+ return -1;
+ }
+ break;
+
+ default:
+ /* Skip non-programmable registers */
+ break;
+ }
+
+ len -= 4;
+ addr += 4;
+ base += 4;
+ }
+
+ return 0;
+}
+
+/**
+ * Write option bytes L0
+ * @param sl
+ * @param addr of the memory mapped option bytes
+ * @param base option bytes
+ * @param len of option bytes
+ * @return 0 on success, -ve on failure.
+ */
+static int32_t stlink_write_option_bytes_l0(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) {
+ uint32_t flash_base = get_stm32l0_flash_base(sl);
+ uint32_t val;
+ uint32_t data;
+ int32_t ret = 0;
+
+ // Clear errors
+ clear_flash_error(sl);
+
+ while (len != 0) {
+ write_uint32((unsigned char *)&data,
+ *(uint32_t *)(base)); // write options bytes
+
+ WLOG("Writing option bytes %#10x to %#10x\n", data, addr);
+ stlink_write_debug32(sl, addr, data);
+ wait_flash_busy(sl);
+
+ if ((ret = check_flash_error(sl))) {
+ break;
+ }
+
+ len -= 4;
+ addr += 4;
+ base += 4;
+ }
+
+ // Reload options
+ stlink_read_debug32(sl, flash_base + FLASH_PECR_OFF, &val);
+ val |= (1 << FLASH_L0_OBL_LAUNCH);
+ stlink_write_debug32(sl, flash_base + FLASH_PECR_OFF, val);
+
+ return (ret);
+}
+
+/**
+ * Write option bytes L4
+ * @param sl
+ * @param addr of the memory mapped option bytes
+ * @param base option bytes
+ * @param len of option bytes
+ * @return 0 on success, -ve on failure.
+ */
+static int32_t stlink_write_option_bytes_l4(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) {
+
+ uint32_t val;
+ int32_t ret = 0;
+ (void)addr;
+ (void)len;
+
+ // Clear errors
+ clear_flash_error(sl);
+
+ // write options bytes
+ uint32_t data;
+ write_uint32((unsigned char *)&data, *(uint32_t *)(base));
+ WLOG("Writing option bytes 0x%04x\n", data);
+ stlink_write_debug32(sl, FLASH_L4_OPTR, data);
+
+ // set options start bit
+ stlink_read_debug32(sl, FLASH_L4_CR, &val);
+ val |= (1 << FLASH_L4_CR_OPTSTRT);
+ stlink_write_debug32(sl, FLASH_L4_CR, val);
+
+ wait_flash_busy(sl);
+ ret = check_flash_error(sl);
+
+ // apply options bytes immediate
+ stlink_read_debug32(sl, FLASH_L4_CR, &val);
+ val |= (1 << FLASH_L4_CR_OBL_LAUNCH);
+ stlink_write_debug32(sl, FLASH_L4_CR, val);
+
+ return (ret);
+}
+
+/**
+ * Write option bytes WB
+ * @param sl
+ * @param addr of the memory mapped option bytes
+ * @param base option bytes
+ * @param len of option bytes
+ * @return 0 on success, -ve on failure.
+ */
+static int32_t stlink_write_option_bytes_wb(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) {
+ /* Write options bytes */
+ uint32_t val;
+ int32_t ret = 0;
+ (void)len;
+ uint32_t data;
+
+ clear_flash_error(sl);
+
+ while (len != 0) {
+ write_uint32((unsigned char *)&data, *(uint32_t *)(base)); // write options bytes
+
+ WLOG("Writing option bytes %#10x to %#10x\n", data, addr);
+ stlink_write_debug32(sl, addr, data);
+ wait_flash_busy(sl);
+
+ if ((ret = check_flash_error(sl))) {
+ break;
+ }
+
+ len -= 4;
+ addr += 4;
+ base += 4;
+ }
+
+ // Set Options Start bit
+ stlink_read_debug32(sl, FLASH_WB_CR, &val);
+ val |= (1 << FLASH_WB_CR_OPTSTRT);
+ stlink_write_debug32(sl, FLASH_WB_CR, val);
+
+ wait_flash_busy(sl);
+
+ ret = check_flash_error(sl);
+
+ // Reload options
+ stlink_read_debug32(sl, FLASH_WB_CR, &val);
+ val |= (1 << FLASH_WB_CR_OBL_LAUNCH);
+ stlink_write_debug32(sl, FLASH_WB_CR, val);
+
+ return (ret);
+}
+
+/**
+ * Read option control register WB
+ * @param sl
+ * @param option_byte
+ * @return 0 on success, -ve on failure.
+ */
+int32_t stlink_read_option_control_register_wb(stlink_t *sl, uint32_t *option_byte) {
+ DLOG("@@@@ Read option control register byte from %#10x\n", FLASH_WB_OPTR);
+ return stlink_read_debug32(sl, FLASH_WB_OPTR, option_byte);
+}
+
+/**
+ * Write option control register WB
+ * @param sl
+ * @param option_cr
+ * @return 0 on success, -ve on failure.
+ */
+static int32_t stlink_write_option_control_register_wb(stlink_t *sl, uint32_t option_cr) {
+ int32_t ret = 0;
+
+ // Clear errors
+ clear_flash_error(sl);
+
+ ILOG("Asked to write option control register 1 %#10x to %#010x.\n",
+ option_cr, FLASH_WB_OPTR);
+
+ /* write option byte, ensuring we dont lock opt, and set strt bit */
+ stlink_write_debug32(sl, FLASH_WB_OPTR, option_cr);
+
+ wait_flash_busy(sl);
+
+ // Set Options Start bit
+ uint32_t val = (1 << FLASH_WB_CR_OPTSTRT);
+ stlink_write_debug32(sl, FLASH_WB_CR, val);
+
+ wait_flash_busy(sl);
+
+ ret = check_flash_error(sl);
+ if (!ret)
+ ILOG("Wrote option bytes %#010x to %#010x!\n", option_cr, FLASH_WB_OPTR);
+
+ return ret;
+}
+
+/**
+ * Read option bytes generic
+ * @param sl
+ * @param option_byte
+ * @return 0 on success, -ve on failure.
+ */
+int32_t stlink_read_option_bytes_generic(stlink_t *sl, uint32_t *option_byte) {
+ DLOG("@@@@ Read option bytes boot address from %#10x\n", sl->option_base);
+ return stlink_read_debug32(sl, sl->option_base, option_byte);
+}
+
+/**
+ * Write option bytes
+ * @param sl
+ * @param addr of the memory mapped option bytes
+ * @param base option bytes
+ * @param len of option bytes
+ * @return 0 on success, -ve on failure.
+ */
+int32_t stlink_write_option_bytes(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) {
+ int32_t ret = -1;
+
+ if (sl->option_base == 0) {
+ ELOG("Option bytes writing is currently not supported for connected chip\n");
+ return (-1);
+ }
+
+ if ((addr < sl->option_base) || addr > sl->option_base + sl->option_size) {
+ ELOG("Option bytes start address out of Option bytes range\n");
+ return (-1);
+ }
+
+ if (addr + len > sl->option_base + sl->option_size) {
+ ELOG("Option bytes data too long\n");
+ return (-1);
+ }
+
+ wait_flash_busy(sl);
+
+ if (unlock_flash_if(sl)) {
+ ELOG("Flash unlock failed! System reset required to be able to unlock it again!\n");
+ return (-1);
+ }
+
+ if (unlock_flash_option_if(sl)) {
+ ELOG("Flash option unlock failed!\n");
+ return (-1);
+ }
+
+ switch (sl->flash_type) {
+ case STM32_FLASH_TYPE_C0:
+ ret = stlink_write_option_bytes_c0(sl, addr, base, len);
+ break;
+ case STM32_FLASH_TYPE_F0_F1_F3:
+ case STM32_FLASH_TYPE_F1_XL:
+ ret = stlink_write_option_bytes_f0(sl, addr, base, len);
+ break;
+ case STM32_FLASH_TYPE_F2_F4:
+ ret = stlink_write_option_bytes_f4(sl, addr, base, len);
+ break;
+ case STM32_FLASH_TYPE_F7:
+ ret = stlink_write_option_bytes_f7(sl, addr, base, len);
+ break;
+ case STM32_FLASH_TYPE_L0_L1:
+ ret = stlink_write_option_bytes_l0(sl, addr, base, len);
+ break;
+ case STM32_FLASH_TYPE_L4:
+ ret = stlink_write_option_bytes_l4(sl, addr, base, len);
+ break;
+ case STM32_FLASH_TYPE_G0:
+ case STM32_FLASH_TYPE_G4:
+ ret = stlink_write_option_bytes_gx(sl, addr, base, len);
+ break;
+ case STM32_FLASH_TYPE_H7:
+ ret = stlink_write_option_bytes_h7(sl, addr, base, len);
+ break;
+ case STM32_FLASH_TYPE_WB_WL:
+ ret = stlink_write_option_bytes_wb(sl, addr, base, len);
+ break;
+ default:
+ ELOG("Option bytes writing is currently not implemented for connected chip\n");
+ break;
+ }
+
+ if (ret) {
+ ELOG("Flash option write failed!\n");
+ } else {
+ ILOG("Wrote %d option bytes to %#010x!\n", len, addr);
+ }
+
+ /* Re-lock flash. */
+ lock_flash_option(sl);
+ lock_flash(sl);
+
+ return ret;
+}
+
+/**
+ * Write the given binary file with option bytes
+ * @param sl
+ * @param path readable file path, should be binary image
+ * @param addr of the memory mapped option bytes
+ * @return 0 on success, -ve on failure.
+ */
+int32_t stlink_fwrite_option_bytes(stlink_t *sl, const char *path, stm32_addr_t addr) {
+ /* Write the file in flash at addr */
+ int32_t err;
+ mapped_file_t mf = MAPPED_FILE_INITIALIZER;
+
+ if (map_file(&mf, path) == -1) {
+ ELOG("map_file() == -1\n");
+ return (-1);
+ }
+
+ printf("file %s ", path);
+ md5_calculate(&mf);
+ stlink_checksum(&mf);
+
+ err = stlink_write_option_bytes(sl, addr, mf.base, (uint32_t)mf.len);
+ stlink_fwrite_finalize(sl, addr);
+ unmap_file(&mf);
+
+ return (err);
+}
+
+/**
+ * Read option control register 32
+ * @param sl
+ * @param option_byte
+ * @return 0 on success, -ve on failure.
+ */
+int32_t stlink_read_option_control_register32(stlink_t *sl, uint32_t *option_byte) {
+ if (sl->option_base == 0) {
+ ELOG("Option bytes read is currently not supported for connected chip\n");
+ return -1;
+ }
+
+ switch (sl->flash_type) {
+ case STM32_FLASH_TYPE_C0:
+ return stlink_read_option_control_register_c0(sl, option_byte);
+ case STM32_FLASH_TYPE_F0_F1_F3:
+ case STM32_FLASH_TYPE_F1_XL:
+ return stlink_read_option_control_register_f0(sl, option_byte);
+ case STM32_FLASH_TYPE_F7:
+ return stlink_read_option_control_register_f7(sl, option_byte);
+ case STM32_FLASH_TYPE_WB_WL:
+ return stlink_read_option_control_register_wb(sl, option_byte);
+ default:
+ return -1;
+ }
+}
+
+/**
+ * Write option control register 32
+ * @param sl
+ * @param option_cr
+ * @return 0 on success, -ve on failure.
+ */
+int32_t stlink_write_option_control_register32(stlink_t *sl, uint32_t option_cr) {
+ int32_t ret = -1;
+
+ wait_flash_busy(sl);
+
+ if (unlock_flash_if(sl)) {
+ ELOG("Flash unlock failed! System reset required to be able to unlock it again!\n");
+ return -1;
+ }
+
+ if (unlock_flash_option_if(sl)) {
+ ELOG("Flash option unlock failed!\n");
+ return -1;
+ }
+
+ switch (sl->flash_type) {
+ case STM32_FLASH_TYPE_C0:
+ ret = stlink_write_option_control_register_c0(sl, option_cr);
+ break;
+ case STM32_FLASH_TYPE_F0_F1_F3:
+ case STM32_FLASH_TYPE_F1_XL:
+ ret = stlink_write_option_control_register_f0(sl, option_cr);
+ break;
+ case STM32_FLASH_TYPE_F7:
+ ret = stlink_write_option_control_register_f7(sl, option_cr);
+ break;
+ case STM32_FLASH_TYPE_WB_WL:
+ ret =
+ stlink_write_option_control_register_wb(sl, option_cr);
+ break;
+ default:
+ ELOG("Option control register writing is currently not implemented for connected chip\n");
+ break;
+ }
+
+ if (ret)
+ ELOG("Flash option write failed!\n");
+ else
+ ILOG("Wrote option control register %#010x!\n", option_cr);
+
+ /* Re-lock flash. */
+ lock_flash_option(sl);
+ lock_flash(sl);
+
+ return ret;
+}
+
+/**
+ * Read option control register1 32
+ * @param sl
+ * @param option_byte
+ * @return 0 on success, -ve on failure.
+ */
+int32_t stlink_read_option_control_register1_32(stlink_t *sl, uint32_t *option_byte) {
+ if (sl->option_base == 0) {
+ ELOG("Option bytes read is currently not supported for connected chip\n");
+ return -1;
+ }
+
+ switch (sl->flash_type) {
+ case STM32_FLASH_TYPE_F7:
+ return stlink_read_option_control_register1_f7(sl, option_byte);
+ default:
+ return -1;
+ // return stlink_read_option_control_register1_generic(sl, option_byte);
+ }
+}
+
+/**
+ * Write option control register1 32
+ * @param sl
+ * @param option_cr
+ * @return 0 on success, -ve on failure.
+ */
+int32_t stlink_write_option_control_register1_32(stlink_t *sl, uint32_t option_cr1) {
+ int32_t ret = -1;
+
+ wait_flash_busy(sl);
+
+ if (unlock_flash_if(sl)) {
+ ELOG("Flash unlock failed! System reset required to be able to unlock it again!\n");
+ return -1;
+ }
+
+ if (unlock_flash_option_if(sl)) {
+ ELOG("Flash option unlock failed!\n");
+ return -1;
+ }
+
+ switch (sl->flash_type) {
+ case STM32_FLASH_TYPE_F7:
+ ret =
+ stlink_write_option_control_register1_f7(sl, option_cr1);
+ break;
+ default:
+ ELOG("Option control register 1 writing is currently not implemented for "
+ "connected chip\n");
+ break;
+ }
+
+ if (ret)
+ ELOG("Flash option write failed!\n");
+ else
+ ILOG("Wrote option control register 1 %#010x!\n", option_cr1);
+
+ lock_flash_option(sl);
+ lock_flash(sl);
+
+ return (ret);
+}
+
+/**
+ * Read option bytes 32
+ * @param sl
+ * @param option_byte
+ * @return 0 on success, -ve on failure.
+ */
+int32_t stlink_read_option_bytes32(stlink_t *sl, uint32_t *option_byte) {
+ if (sl->option_base == 0) {
+ ELOG("Option bytes read is currently not supported for connected chip\n");
+ return (-1);
+ }
+
+ switch (sl->chip_id) {
+ case STM32_CHIPID_C011xx:
+ case STM32_CHIPID_C031xx:
+ return stlink_read_option_bytes_c0(sl, option_byte);
+ case STM32_CHIPID_F2:
+ return stlink_read_option_bytes_f2(sl, option_byte);
+ case STM32_CHIPID_F4:
+ case STM32_CHIPID_F446:
+ return stlink_read_option_bytes_f4(sl, option_byte);
+ case STM32_CHIPID_F76xxx:
+ return stlink_read_option_bytes_f7(sl, option_byte);
+ case STM32_CHIPID_G0_CAT1:
+ case STM32_CHIPID_G0_CAT2:
+ case STM32_CHIPID_G4_CAT2:
+ case STM32_CHIPID_G4_CAT3:
+ case STM32_CHIPID_G4_CAT4:
+ return stlink_read_option_bytes_gx(sl, option_byte);
+ default:
+ return stlink_read_option_bytes_generic(sl, option_byte);
+ }
+}
+
+/**
+ * Write option bytes 32
+ * @param sl
+ * @param option_byte
+ * @return 0 on success, -ve on failure.
+ */
+int32_t stlink_write_option_bytes32(stlink_t *sl, uint32_t option_byte) {
+ WLOG("About to write option byte %#10x to %#10x.\n", option_byte,
+ sl->option_base);
+ return stlink_write_option_bytes(sl, sl->option_base, (uint8_t *)&option_byte, 4);
+}
+
+/**
+ * Read option bytes boot address 32
+ * @param sl
+ * @param option_byte
+ * @return 0 on success, -ve on failure.
+ */
+int32_t stlink_read_option_bytes_boot_add32(stlink_t *sl, uint32_t *option_byte) {
+ if (sl->option_base == 0) {
+ ELOG("Option bytes boot address read is currently not supported for connected chip\n");
+ return -1;
+ }
+
+ switch (sl->flash_type) {
+ case STM32_FLASH_TYPE_F7:
+ return stlink_read_option_bytes_boot_add_f7(sl, option_byte);
+ default:
+ return -1;
+ // return stlink_read_option_bytes_boot_add_generic(sl, option_byte);
+ }
+}
+
+/**
+ * Write option bytes boot address 32
+ * @param sl
+ * @param option_bytes_boot_add
+ * @return 0 on success, -ve on failure.
+ */
+int32_t stlink_write_option_bytes_boot_add32(stlink_t *sl, uint32_t option_bytes_boot_add) {
+ int32_t ret = -1;
+
+ wait_flash_busy(sl);
+
+ if (unlock_flash_if(sl)) {
+ ELOG("Flash unlock failed! System reset required to be able to unlock it again!\n");
+ return -1;
+ }
+
+ if (unlock_flash_option_if(sl)) {
+ ELOG("Flash option unlock failed!\n");
+ return -1;
+ }
+
+ switch (sl->flash_type) {
+ case STM32_FLASH_TYPE_F7:
+ ret = stlink_write_option_bytes_boot_add_f7(sl, option_bytes_boot_add);
+ break;
+ default:
+ ELOG("Option bytes boot address writing is currently not implemented for connected chip\n");
+ break;
+ }
+
+ if (ret)
+ ELOG("Flash option write failed!\n");
+ else
+ ILOG("Wrote option bytes boot address %#010x!\n", option_bytes_boot_add);
+
+ /* Re-lock flash. */
+ lock_flash_option(sl);
+ lock_flash(sl);
+
+ return ret;
+}
diff --git a/src/stlink-lib/option_bytes.h b/src/stlink-lib/option_bytes.h
new file mode 100644
index 0000000..7ab3e29
--- /dev/null
+++ b/src/stlink-lib/option_bytes.h
@@ -0,0 +1,47 @@
+/*
+ * File: option_bytes.h
+ *
+ * Read and write option bytes and option control registers
+ */
+
+#ifndef OPTION_BYTES_H
+#define OPTION_BYTES_H
+
+int32_t stlink_read_option_control_register_f0(stlink_t *sl, uint32_t *option_byte);
+// static int32_t stlink_write_option_bytes_f0(stlink_t *sl, stm32_addr_t addr, uint8_t* base, uint32_t len);
+// static int32_t stlink_write_option_control_register_f0(stlink_t *sl, uint32_t option_cr);
+int32_t stlink_read_option_control_register_f2(stlink_t *sl, uint32_t *option_byte);
+int32_t stlink_read_option_bytes_f2(stlink_t *sl, uint32_t *option_byte);
+int32_t stlink_read_option_control_register_f4(stlink_t *sl, uint32_t *option_byte);
+int32_t stlink_read_option_bytes_f4(stlink_t *sl, uint32_t *option_byte);
+// static int32_t stlink_write_option_bytes_f4(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len);
+int32_t stlink_read_option_bytes_f7(stlink_t *sl, uint32_t *option_byte);
+// static int32_t stlink_write_option_bytes_f7(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len);
+int32_t stlink_read_option_control_register_f7(stlink_t *sl, uint32_t *option_byte);
+// static int32_t stlink_write_option_control_register_f7(stlink_t *sl, uint32_t option_cr);
+int32_t stlink_read_option_control_register1_f7(stlink_t *sl, uint32_t *option_byte);
+// static int32_t stlink_write_option_control_register1_f7(stlink_t *sl, uint32_t option_cr1);
+int32_t stlink_read_option_bytes_boot_add_f7(stlink_t *sl, uint32_t *option_byte);
+// static int32_t stlink_write_option_bytes_boot_add_f7(stlink_t *sl, uint32_t option_byte_boot_add);
+int32_t stlink_read_option_control_register_gx(stlink_t *sl, uint32_t *option_byte);
+int32_t stlink_read_option_bytes_gx(stlink_t *sl, uint32_t *option_byte);
+// static int32_t stlink_write_option_bytes_gx(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len);
+// static int32_t stlink_write_option_bytes_h7(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len);
+// static int32_t stlink_write_option_bytes_l0(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len);
+// static int32_t stlink_write_option_bytes_l4(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len);
+// static int32_t stlink_write_option_bytes_wb(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len);
+int32_t stlink_read_option_control_register_wb(stlink_t *sl, uint32_t *option_byte);
+// static int32_t stlink_write_option_control_register_wb(stlink_t *sl, uint32_t option_cr);
+int32_t stlink_read_option_bytes_generic(stlink_t *sl, uint32_t *option_byte);
+int32_t stlink_write_option_bytes(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len);
+int32_t stlink_fwrite_option_bytes(stlink_t *sl, const char *path, stm32_addr_t addr);
+int32_t stlink_read_option_control_register32(stlink_t *sl, uint32_t *option_byte);
+int32_t stlink_write_option_control_register32(stlink_t *sl, uint32_t option_cr);
+int32_t stlink_read_option_control_register1_32(stlink_t *sl, uint32_t *option_byte);
+int32_t stlink_write_option_control_register1_32(stlink_t *sl, uint32_t option_cr1);
+int32_t stlink_read_option_bytes32(stlink_t *sl, uint32_t* option_byte);
+int32_t stlink_write_option_bytes32(stlink_t *sl, uint32_t option_byte);
+int32_t stlink_read_option_bytes_boot_add32(stlink_t *sl, uint32_t* option_byte);
+int32_t stlink_write_option_bytes_boot_add32(stlink_t *sl, uint32_t option_bytes_boot_add);
+
+#endif // OPTION_BYTES_H
diff --git a/src/stlink-lib/read_write.c b/src/stlink-lib/read_write.c
new file mode 100644
index 0000000..4e43d8a
--- /dev/null
+++ b/src/stlink-lib/read_write.c
@@ -0,0 +1,154 @@
+/*
+ * File: read_write.c
+ *
+ * Read and write operations
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <stlink.h>
+#include "read_write.h"
+
+#include "logging.h"
+
+// Endianness
+// https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html
+// These functions encode and decode little endian uint16 and uint32 values.
+
+uint16_t read_uint16(const unsigned char *c, const int32_t pt) {
+ return ((uint16_t)c[pt]) | ((uint16_t)c[pt + 1] << 8);
+}
+
+void write_uint16(unsigned char *buf, uint16_t ui) {
+ buf[0] = (uint8_t)ui;
+ buf[1] = (uint8_t)(ui >> 8);
+}
+
+uint32_t read_uint32(const unsigned char *c, const int32_t pt) {
+ return ((uint32_t)c[pt]) | ((uint32_t)c[pt + 1] << 8) |
+ ((uint32_t)c[pt + 2] << 16) | ((uint32_t)c[pt + 3] << 24);
+}
+
+void write_uint32(unsigned char *buf, uint32_t ui) {
+ buf[0] = ui;
+ buf[1] = ui >> 8;
+ buf[2] = ui >> 16;
+ buf[3] = ui >> 24;
+}
+
+int32_t stlink_read_debug32(stlink_t *sl, uint32_t addr, uint32_t *data) {
+ int32_t ret;
+
+ ret = sl->backend->read_debug32(sl, addr, data);
+ if (!ret)
+ DLOG("*** stlink_read_debug32 %#010x at %#010x\n", *data, addr);
+
+ return (ret);
+}
+
+int32_t stlink_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data) {
+ DLOG("*** stlink_write_debug32 %#010x to %#010x\n", data, addr);
+ return sl->backend->write_debug32(sl, addr, data);
+}
+
+int32_t stlink_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
+ DLOG("*** stlink_read_mem32 ***\n");
+
+ if (len % 4 != 0) { // !!! never ever: fw gives just wrong values
+ ELOG("Data length doesn't have a 32 bit alignment: +%d byte.\n", len % 4);
+ return (-1);
+ }
+
+ return (sl->backend->read_mem32(sl, addr, len));
+}
+
+int32_t stlink_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
+ DLOG("*** stlink_write_mem32 %u bytes to %#x\n", len, addr);
+
+ if (len % 4 != 0) {
+ ELOG("Data length doesn't have a 32 bit alignment: +%d byte.\n", len % 4);
+ return (-1);
+ }
+
+ return (sl->backend->write_mem32(sl, addr, len));
+}
+
+int32_t stlink_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len) {
+ DLOG("*** stlink_write_mem8 ***\n");
+ return (sl->backend->write_mem8(sl, addr, len));
+}
+
+int32_t stlink_read_reg(stlink_t *sl, int32_t r_idx, struct stlink_reg *regp) {
+ DLOG("*** stlink_read_reg\n");
+ DLOG(" (%d) ***\n", r_idx);
+
+ if (r_idx > 20 || r_idx < 0) {
+ fprintf(stderr, "Error: register index must be in [0..20]\n");
+ return (-1);
+ }
+
+ return (sl->backend->read_reg(sl, r_idx, regp));
+}
+
+int32_t stlink_write_reg(stlink_t *sl, uint32_t reg, int32_t idx) {
+ DLOG("*** stlink_write_reg\n");
+ return (sl->backend->write_reg(sl, reg, idx));
+}
+
+int32_t stlink_read_unsupported_reg(stlink_t *sl, int32_t r_idx,
+ struct stlink_reg *regp) {
+ int32_t r_convert;
+
+ DLOG("*** stlink_read_unsupported_reg\n");
+ DLOG(" (%d) ***\n", r_idx);
+
+ /* Convert to values used by STLINK_REG_DCRSR */
+ if (r_idx >= 0x1C &&
+ r_idx <= 0x1F) { // primask, basepri, faultmask, or control
+ r_convert = 0x14;
+ } else if (r_idx == 0x40) { // FPSCR
+ r_convert = 0x21;
+ } else if (r_idx >= 0x20 && r_idx < 0x40) {
+ r_convert = 0x40 + (r_idx - 0x20);
+ } else {
+ fprintf(stderr, "Error: register address must be in [0x1C..0x40]\n");
+ return (-1);
+ }
+
+ return (sl->backend->read_unsupported_reg(sl, r_convert, regp));
+}
+
+int32_t stlink_write_unsupported_reg(stlink_t *sl, uint32_t val, int32_t r_idx,
+ struct stlink_reg *regp) {
+ int32_t r_convert;
+
+ DLOG("*** stlink_write_unsupported_reg\n");
+ DLOG(" (%d) ***\n", r_idx);
+
+ /* Convert to values used by STLINK_REG_DCRSR */
+ if (r_idx >= 0x1C &&
+ r_idx <= 0x1F) { /* primask, basepri, faultmask, or control */
+ r_convert = r_idx; // the backend function handles this
+ } else if (r_idx == 0x40) { // FPSCR
+ r_convert = 0x21;
+ } else if (r_idx >= 0x20 && r_idx < 0x40) {
+ r_convert = 0x40 + (r_idx - 0x20);
+ } else {
+ fprintf(stderr, "Error: register address must be in [0x1C..0x40]\n");
+ return (-1);
+ }
+
+ return (sl->backend->write_unsupported_reg(sl, val, r_convert, regp));
+}
+
+int32_t stlink_read_all_regs(stlink_t *sl, struct stlink_reg *regp) {
+ DLOG("*** stlink_read_all_regs ***\n");
+ return (sl->backend->read_all_regs(sl, regp));
+}
+
+int32_t stlink_read_all_unsupported_regs(stlink_t *sl, struct stlink_reg *regp) {
+ DLOG("*** stlink_read_all_unsupported_regs ***\n");
+ return (sl->backend->read_all_unsupported_regs(sl, regp));
+}
diff --git a/src/stlink-lib/read_write.h b/src/stlink-lib/read_write.h
new file mode 100644
index 0000000..b9ca082
--- /dev/null
+++ b/src/stlink-lib/read_write.h
@@ -0,0 +1,27 @@
+/*
+ * File: read_write.h
+ *
+ * Read and write operations
+ */
+
+#ifndef READ_WRITE_H
+#define READ_WRITE_H
+
+uint16_t read_uint16(const unsigned char *c, const int32_t pt);
+void write_uint16(unsigned char *buf, uint16_t ui);
+uint32_t read_uint32(const unsigned char *c, const int32_t pt);
+void write_uint32(unsigned char *buf, uint32_t ui);
+
+int32_t stlink_read_debug32(stlink_t *sl, uint32_t addr, uint32_t *data);
+int32_t stlink_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data);
+int32_t stlink_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len);
+int32_t stlink_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len);
+int32_t stlink_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len);
+int32_t stlink_read_reg(stlink_t *sl, int32_t r_idx, struct stlink_reg *regp);
+int32_t stlink_write_reg(stlink_t *sl, uint32_t reg, int32_t idx);
+int32_t stlink_read_unsupported_reg(stlink_t *sl, int32_t r_idx, struct stlink_reg *regp);
+int32_t stlink_write_unsupported_reg(stlink_t *sl, uint32_t value, int32_t r_idx, struct stlink_reg *regp);
+int32_t stlink_read_all_regs(stlink_t *sl, struct stlink_reg *regp);
+int32_t stlink_read_all_unsupported_regs(stlink_t *sl, struct stlink_reg *regp);
+
+#endif // READ_WRITE_H
diff --git a/src/stlink-lib/reg.h b/src/stlink-lib/register.h
index b581a26..f1e9574 100644
--- a/src/stlink-lib/reg.h
+++ b/src/stlink-lib/register.h
@@ -1,5 +1,11 @@
-#ifndef STLINK_REG_H_
-#define STLINK_REG_H_
+/*
+ * File: register.h
+ *
+ * Common STM32 registers
+ */
+
+#ifndef REGISTER_H
+#define REGISTER_H
#define STLINK_REG_CM3_CPUID 0xE000ED00
@@ -123,4 +129,4 @@
#define STLINK_REG_CM7_ICIALLU 0xE000EF50
#define STLINK_REG_CM7_CCSIDR 0xE000ED80
-#endif // STLINK_REG_H_
+#endif // REGISTER_H
diff --git a/src/stlink-lib/sg.c b/src/stlink-lib/sg.c
index 0797128..b1d5d76 100644
--- a/src/stlink-lib/sg.c
+++ b/src/stlink-lib/sg.c
@@ -1,3 +1,5 @@
+/* == nightwalker-87: TODO: CONTENT AND USE OF THIS SOURCE FILE IS TO BE VERIFIED (07.06.2023) == */
+
/*
* Copyright (c) 2010 "Capt'ns Missing Link" Authors. All rights reserved.
* Use of this source code is governed by a BSD-style
@@ -74,23 +76,35 @@
* part to an existing options line for usb-storage).
*/
+/*
+ * File: sg.c
+ *
+ *
+ */
#define __USE_GNU
-#include <assert.h>
+
+#include <stdint.h>
#include <stdio.h>
-#include <string.h>
#include <stdlib.h>
-#include <sys/types.h>
+#include <string.h>
+#include <assert.h>
+// #include <sys/types.h> // TODO: Check use
-#include <stlink.h>
-#include "logging.h"
#include "sg.h"
+#include "commands.h"
+#include "logging.h"
+#include "read_write.h"
+#include "register.h"
+#include "usb.h"
+// #include <stlink.h> // TODO: Check use
+
#define STLINK_OK 0x80
#define STLINK_FALSE 0x81
static void clear_cdb(struct stlink_libsg *sl) {
- for (size_t i = 0; i < sizeof(sl->cdb_cmd_blk); i++) { sl->cdb_cmd_blk[i] = 0; }
+ for (uint32_t i = 0; i < sizeof(sl->cdb_cmd_blk); i++) { sl->cdb_cmd_blk[i] = 0; }
// set default
sl->cdb_cmd_blk[0] = STLINK_DEBUG_COMMAND;
@@ -110,12 +124,12 @@ void _stlink_sg_close(stlink_t *sl) {
}
}
-static int get_usb_mass_storage_status(libusb_device_handle *handle, uint8_t endpoint, uint32_t *tag) {
+static int32_t get_usb_mass_storage_status(libusb_device_handle *handle, uint8_t endpoint, uint32_t *tag) {
unsigned char csw[13];
memset(csw, 0, sizeof(csw));
- int transferred;
- int ret;
- int try = 0;
+ int32_t transferred;
+ int32_t ret;
+ int32_t try = 0;
do {
ret = libusb_bulk_transfer(handle, endpoint, (unsigned char *)&csw, sizeof(csw),
@@ -128,41 +142,42 @@ static int get_usb_mass_storage_status(libusb_device_handle *handle, uint8_t end
if (ret != LIBUSB_SUCCESS) {
WLOG("%s: receiving failed: %d\n", __func__, ret);
- return(-1);
+ return (-1);
}
if (transferred != sizeof(csw)) {
WLOG("%s: received unexpected amount: %d\n", __func__, transferred);
- return(-1);
+ return (-1);
}
uint32_t rsig = read_uint32(csw, 0);
uint32_t rtag = read_uint32(csw, 4);
/* uint32_t residue = read_uint32(csw, 8); */
+
#define USB_CSW_SIGNATURE 0x53425355 // 'U' 'S' 'B' 'S' (reversed)
if (rsig != USB_CSW_SIGNATURE) {
WLOG("status signature was invalid: %#x\n", rsig);
- return(-1);
+ return (-1);
}
*tag = rtag;
uint8_t rstatus = csw[12];
- return(rstatus);
+ return (rstatus);
}
-static int dump_CDB_command(uint8_t *cdb, uint8_t cdb_len) {
+static int32_t dump_CDB_command(uint8_t *cdb, uint8_t cdb_len) {
char dbugblah[100];
char *dbugp = dbugblah;
dbugp += sprintf(dbugp, "Sending CDB [");
for (uint8_t i = 0; i < cdb_len; i++) {
- dbugp += sprintf(dbugp, " %#02x", (unsigned int)cdb[i]);
+ dbugp += sprintf(dbugp, " 0x%02x", (uint32_t)cdb[i]);
}
sprintf(dbugp, "]\n");
DLOG("%s",dbugblah);
- return(0);
+ return (0);
}
/**
@@ -176,9 +191,8 @@ static int dump_CDB_command(uint8_t *cdb, uint8_t cdb_len) {
* @param expected_rx_size
* @return
*/
-int send_usb_mass_storage_command(libusb_device_handle *handle, uint8_t endpoint_out,
- uint8_t *cdb, uint8_t cdb_length,
- uint8_t lun, uint8_t flags, uint32_t expected_rx_size) {
+int32_t send_usb_mass_storage_command(libusb_device_handle *handle, uint8_t endpoint_out, uint8_t *cdb, uint8_t cdb_length,
+ uint8_t lun, uint8_t flags, uint32_t expected_rx_size) {
DLOG("Sending usb m-s cmd: cdblen:%d, rxsize=%d\n", cdb_length, expected_rx_size);
dump_CDB_command(cdb, cdb_length);
@@ -186,10 +200,10 @@ int send_usb_mass_storage_command(libusb_device_handle *handle, uint8_t endpoint
if (tag == 0) { tag = 1; }
- int try = 0;
- int ret = 0;
- int real_transferred;
- int i = 0;
+ int32_t try = 0;
+ int32_t ret = 0;
+ int32_t real_transferred;
+ int32_t i = 0;
uint8_t c_buf[STLINK_SG_SIZE];
// tag is allegedly ignored... TODO - verify
@@ -210,7 +224,7 @@ int send_usb_mass_storage_command(libusb_device_handle *handle, uint8_t endpoint
assert(cdb_length <= CDB_SL);
memcpy(&(c_buf[i]), cdb, cdb_length);
- int sending_length = STLINK_SG_SIZE;
+ int32_t sending_length = STLINK_SG_SIZE;
// send....
do {
@@ -226,10 +240,10 @@ int send_usb_mass_storage_command(libusb_device_handle *handle, uint8_t endpoint
if (ret != LIBUSB_SUCCESS) {
WLOG("sending failed: %d\n", ret);
- return(-1);
+ return (-1);
}
- return(this_tag);
+ return (this_tag);
}
/**
@@ -255,9 +269,9 @@ static void get_sense(libusb_device_handle *handle, uint8_t endpoint_in, uint8_t
}
unsigned char sense[REQUEST_SENSE_LENGTH];
- int transferred;
- int ret;
- int try = 0;
+ int32_t transferred;
+ int32_t ret;
+ int32_t try = 0;
do {
ret = libusb_bulk_transfer(handle, endpoint_in, sense, sizeof(sense),
@@ -274,11 +288,11 @@ static void get_sense(libusb_device_handle *handle, uint8_t endpoint_in, uint8_t
}
if (transferred != sizeof(sense)) {
- WLOG("received unexpected amount of sense: %d != %u\n", transferred, (unsigned)sizeof(sense));
+ WLOG("received unexpected amount of sense: %d != %u\n", transferred, (uint32_t)sizeof(sense));
}
uint32_t received_tag;
- int status = get_usb_mass_storage_status(handle, endpoint_in, &received_tag);
+ int32_t status = get_usb_mass_storage_status(handle, endpoint_in, &received_tag);
if (status != 0) {
WLOG("receiving sense failed with status: %02x\n", status);
@@ -302,11 +316,11 @@ static void get_sense(libusb_device_handle *handle, uint8_t endpoint_in, uint8_t
* @param length how much to send
* @return number of bytes actually sent, or -1 for failures.
*/
-int send_usb_data_only(libusb_device_handle *handle, unsigned char endpoint_out,
- unsigned char endpoint_in, unsigned char *cbuf, unsigned int length) {
- int ret;
- int real_transferred;
- int try = 0;
+int32_t send_usb_data_only(libusb_device_handle *handle, unsigned char endpoint_out,
+ unsigned char endpoint_in, unsigned char *cbuf, uint32_t length) {
+ int32_t ret;
+ int32_t real_transferred;
+ int32_t try = 0;
do {
ret = libusb_bulk_transfer(handle, endpoint_out, cbuf, length,
@@ -319,17 +333,17 @@ int send_usb_data_only(libusb_device_handle *handle, unsigned char endpoint_out,
if (ret != LIBUSB_SUCCESS) {
WLOG("sending failed: %d\n", ret);
- return(-1);
+ return (-1);
}
// now, swallow up the status, so that things behave nicely...
uint32_t received_tag;
// -ve is for my errors, 0 is good, +ve is libusb sense status bytes
- int status = get_usb_mass_storage_status(handle, endpoint_in, &received_tag);
+ int32_t status = get_usb_mass_storage_status(handle, endpoint_in, &received_tag);
if (status < 0) {
WLOG("receiving status failed: %d\n", status);
- return(-1);
+ return (-1);
}
if (status != 0) {
@@ -338,13 +352,13 @@ int send_usb_data_only(libusb_device_handle *handle, unsigned char endpoint_out,
if (status == 1) {
get_sense(handle, endpoint_in, endpoint_out);
- return(-1);
+ return (-1);
}
- return(real_transferred);
+ return (real_transferred);
}
-int stlink_q(stlink_t *sl) {
+int32_t stlink_q(stlink_t *sl) {
struct stlink_libsg* sg = sl->backend_data;
// uint8_t cdb_len = 6; // FIXME varies!!!
uint8_t cdb_len = 10; // FIXME varies!!!
@@ -356,10 +370,10 @@ int stlink_q(stlink_t *sl) {
// now wait for our response...
// length copied from stlink-usb...
- int rx_length = sl->q_len;
- int try = 0;
- int real_transferred;
- int ret;
+ int32_t rx_length = sl->q_len;
+ int32_t try = 0;
+ int32_t real_transferred;
+ int32_t ret;
if (rx_length > 0) {
do {
@@ -373,7 +387,7 @@ int stlink_q(stlink_t *sl) {
if (ret != LIBUSB_SUCCESS) {
WLOG("Receiving failed: %d\n", ret);
- return(-1);
+ return (-1);
}
if (real_transferred != rx_length) {
@@ -383,11 +397,11 @@ int stlink_q(stlink_t *sl) {
uint32_t received_tag;
// -ve is for my errors, 0 is good, +ve is libusb sense status bytes
- int status = get_usb_mass_storage_status(sg->usb_handle, sg->ep_rep, &received_tag);
+ int32_t status = get_usb_mass_storage_status(sg->usb_handle, sg->ep_rep, &received_tag);
if (status < 0) {
WLOG("receiving status failed: %d\n", status);
- return(-1);
+ return (-1);
}
if (status != 0) {
@@ -396,7 +410,7 @@ int stlink_q(stlink_t *sl) {
if (status == 1) {
get_sense(sg->usb_handle, sg->ep_rep, sg->ep_req);
- return(-1);
+ return (-1);
}
if (received_tag != tag) {
@@ -405,10 +419,10 @@ int stlink_q(stlink_t *sl) {
}
if (rx_length > 0 && real_transferred != rx_length) {
- return(-1);
+ return (-1);
}
- return(0);
+ return (0);
}
// TODO: thinking, cleanup
@@ -429,62 +443,62 @@ void stlink_stat(stlink_t *stl, char *txt) {
}
}
-int _stlink_sg_version(stlink_t *stl) {
+int32_t _stlink_sg_version(stlink_t *stl) {
struct stlink_libsg *sl = stl->backend_data;
clear_cdb(sl);
sl->cdb_cmd_blk[0] = STLINK_GET_VERSION;
stl->q_len = 6;
sl->q_addr = 0;
- return(stlink_q(stl));
+ return (stlink_q(stl));
}
// Get stlink mode:
// STLINK_DEV_DFU_MODE || STLINK_DEV_MASS_MODE || STLINK_DEV_DEBUG_MODE
// usb dfu || usb mass || jtag or swd
-int _stlink_sg_current_mode(stlink_t *stl) {
+int32_t _stlink_sg_current_mode(stlink_t *stl) {
struct stlink_libsg *sl = stl->backend_data;
clear_cdb(sl);
sl->cdb_cmd_blk[0] = STLINK_GET_CURRENT_MODE;
stl->q_len = 2;
sl->q_addr = 0;
- if (stlink_q(stl)) { return(-1); }
+ if (stlink_q(stl)) { return (-1); }
- return(stl->q_buf[0]);
+ return (stl->q_buf[0]);
}
// exit the mass mode and enter the swd debug mode.
-int _stlink_sg_enter_swd_mode(stlink_t *sl) {
+int32_t _stlink_sg_enter_swd_mode(stlink_t *sl) {
struct stlink_libsg *sg = sl->backend_data;
clear_cdb(sg);
sg->cdb_cmd_blk[1] = STLINK_DEBUG_APIV1_ENTER;
sg->cdb_cmd_blk[2] = STLINK_DEBUG_ENTER_SWD;
sl->q_len = 0; // >0 -> aboard
- return(stlink_q(sl));
+ return (stlink_q(sl));
}
// exit the mass mode and enter the jtag debug mode.
// (jtag is disabled in the discovery's stlink firmware)
-int _stlink_sg_enter_jtag_mode(stlink_t *sl) {
+int32_t _stlink_sg_enter_jtag_mode(stlink_t *sl) {
struct stlink_libsg *sg = sl->backend_data;
DLOG("\n*** stlink_enter_jtag_mode ***\n");
clear_cdb(sg);
sg->cdb_cmd_blk[1] = STLINK_DEBUG_APIV1_ENTER;
- sg->cdb_cmd_blk[2] = STLINK_DEBUG_ENTER_JTAG;
+ sg->cdb_cmd_blk[2] = STLINK_DEBUG_ENTER_JTAG_RESET;
sl->q_len = 0;
- return(stlink_q(sl));
+ return (stlink_q(sl));
}
// XXX kernel driver performs reset, the device temporally disappears
// Suspect this is no longer the case when we have ignore on? RECHECK
-int _stlink_sg_exit_dfu_mode(stlink_t *sl) {
+int32_t _stlink_sg_exit_dfu_mode(stlink_t *sl) {
struct stlink_libsg *sg = sl->backend_data;
DLOG("\n*** stlink_exit_dfu_mode ***\n");
clear_cdb(sg);
sg->cdb_cmd_blk[0] = STLINK_DFU_COMMAND;
sg->cdb_cmd_blk[1] = STLINK_DFU_EXIT;
sl->q_len = 0; // ??
- return(stlink_q(sl));
+ return (stlink_q(sl));
/*
[135121.844564] sd 19:0:0:0: [sdb] Unhandled error code
[135121.844569] sd 19:0:0:0: [sdb] Result: hostbyte=DID_ERROR driverbyte=DRIVER_OK
@@ -530,84 +544,84 @@ int _stlink_sg_exit_dfu_mode(stlink_t *sl) {
*/
}
-int _stlink_sg_core_id(stlink_t *sl) {
+int32_t _stlink_sg_core_id(stlink_t *sl) {
struct stlink_libsg *sg = sl->backend_data;
- int ret;
+ int32_t ret;
clear_cdb(sg);
sg->cdb_cmd_blk[1] = STLINK_DEBUG_READCOREID;
sl->q_len = 4;
sg->q_addr = 0;
ret = stlink_q(sl);
- if (ret) { return(ret); }
+ if (ret) { return (ret); }
sl->core_id = read_uint32(sl->q_buf, 0);
- return(0);
+ return (0);
}
// arm-core reset -> halted state.
-int _stlink_sg_reset(stlink_t *sl) {
+int32_t _stlink_sg_reset(stlink_t *sl) {
struct stlink_libsg *sg = sl->backend_data;
clear_cdb(sg);
sg->cdb_cmd_blk[1] = STLINK_DEBUG_APIV1_RESETSYS;
sl->q_len = 2;
sg->q_addr = 0;
- if (stlink_q(sl)) { return(-1); }
+ if (stlink_q(sl)) { return (-1); }
// Reset through AIRCR so NRST does not need to be connected
if (stlink_write_debug32(sl, STLINK_REG_AIRCR,
STLINK_REG_AIRCR_VECTKEY | \
STLINK_REG_AIRCR_SYSRESETREQ)) {
- return(-1);
+ return (-1);
}
stlink_stat(sl, "core reset");
- return(0);
+ return (0);
}
// arm-core reset -> halted state.
-int _stlink_sg_jtag_reset(stlink_t *sl, int value) {
+int32_t _stlink_sg_jtag_reset(stlink_t *sl, int32_t value) {
struct stlink_libsg *sg = sl->backend_data;
clear_cdb(sg);
- sg->cdb_cmd_blk[1] = STLINK_JTAG_DRIVE_NRST;
+ sg->cdb_cmd_blk[1] = STLINK_DEBUG_APIV2_DRIVE_NRST;
sg->cdb_cmd_blk[2] = (value) ? 0 : 1;
sl->q_len = 3;
sg->q_addr = 2;
- if (stlink_q(sl)) { return(-1); }
+ if (stlink_q(sl)) { return (-1); }
stlink_stat(sl, "core reset");
- return(0);
+ return (0);
}
// arm-core status: halted or running.
-int _stlink_sg_status(stlink_t *sl) {
+int32_t _stlink_sg_status(stlink_t *sl) {
struct stlink_libsg *sg = sl->backend_data;
clear_cdb(sg);
sg->cdb_cmd_blk[1] = STLINK_DEBUG_GETSTATUS;
sl->q_len = 2;
sg->q_addr = 0;
- return(stlink_q(sl));
+ return (stlink_q(sl));
}
// force the core into the debug mode -> halted state.
-int _stlink_sg_force_debug(stlink_t *sl) {
+int32_t _stlink_sg_force_debug(stlink_t *sl) {
struct stlink_libsg *sg = sl->backend_data;
clear_cdb(sg);
sg->cdb_cmd_blk[1] = STLINK_DEBUG_FORCEDEBUG;
sl->q_len = 2;
sg->q_addr = 0;
- if (stlink_q(sl)) { return(-1); }
+ if (stlink_q(sl)) { return (-1); }
stlink_stat(sl, "force debug");
- return(0);
+ return (0);
}
// read all arm-core registers.
-int _stlink_sg_read_all_regs(stlink_t *sl, struct stlink_reg *regp) {
+int32_t _stlink_sg_read_all_regs(stlink_t *sl, struct stlink_reg *regp) {
struct stlink_libsg *sg = sl->backend_data;
clear_cdb(sg);
@@ -615,7 +629,7 @@ int _stlink_sg_read_all_regs(stlink_t *sl, struct stlink_reg *regp) {
sl->q_len = 84;
sg->q_addr = 0;
- if (stlink_q(sl)) { return(-1); }
+ if (stlink_q(sl)) { return (-1); }
stlink_print_data(sl);
@@ -623,7 +637,7 @@ int _stlink_sg_read_all_regs(stlink_t *sl, struct stlink_reg *regp) {
// 0-3 | 4-7 | ... | 60-63 | 64-67 | 68-71 | 72-75 | 76-79 | 80-83
// r0 | r1 | ... | r15 | xpsr | main_sp | process_sp | rw | rw2
- for (int i = 0; i < 16; i++) {
+ for (int32_t i = 0; i < 16; i++) {
regp->r[i] = read_uint32(sl->q_buf, 4 * i);
if (sl->verbose > 1) { DLOG("r%2d = 0x%08x\n", i, regp->r[i]); }
@@ -635,7 +649,7 @@ int _stlink_sg_read_all_regs(stlink_t *sl, struct stlink_reg *regp) {
regp->rw = read_uint32(sl->q_buf, 76);
regp->rw2 = read_uint32(sl->q_buf, 80);
- if (sl->verbose < 2) { return(0); }
+ if (sl->verbose < 2) { return (0); }
DLOG("xpsr = 0x%08x\n", regp->xpsr);
DLOG("main_sp = 0x%08x\n", regp->main_sp);
@@ -643,14 +657,14 @@ int _stlink_sg_read_all_regs(stlink_t *sl, struct stlink_reg *regp) {
DLOG("rw = 0x%08x\n", regp->rw);
DLOG("rw2 = 0x%08x\n", regp->rw2);
- return(0);
+ return (0);
}
// read an arm-core register, the index must be in the range 0..20.
// 0 | 1 | ... | 15 | 16 | 17 | 18 | 19 | 20
// r0 | r1 | ... | r15 | xpsr | main_sp | process_sp | rw | rw2
-int _stlink_sg_read_reg(stlink_t *sl, int r_idx, struct stlink_reg *regp) {
+int32_t _stlink_sg_read_reg(stlink_t *sl, int32_t r_idx, struct stlink_reg *regp) {
struct stlink_libsg *sg = sl->backend_data;
clear_cdb(sg);
sg->cdb_cmd_blk[1] = STLINK_DEBUG_APIV1_READREG;
@@ -658,7 +672,7 @@ int _stlink_sg_read_reg(stlink_t *sl, int r_idx, struct stlink_reg *regp) {
sl->q_len = 4;
sg->q_addr = 0;
- if (stlink_q(sl)) { return(-1); }
+ if (stlink_q(sl)) { return (-1); }
// 0 | 1 | ... | 15 | 16 | 17 | 18 | 19 | 20
// 0-3 | 4-7 | ... | 60-63 | 64-67 | 68-71 | 72-75 | 76-79 | 80-83
@@ -688,14 +702,14 @@ int _stlink_sg_read_reg(stlink_t *sl, int r_idx, struct stlink_reg *regp) {
regp->r[r_idx] = r;
}
- return(0);
+ return (0);
}
// write an arm-core register. Index:
// 0 | 1 | ... | 15 | 16 | 17 | 18 | 19 | 20
// r0 | r1 | ... | r15 | xpsr | main_sp | process_sp | rw | rw2
-int _stlink_sg_write_reg(stlink_t *sl, uint32_t reg, int idx) {
+int32_t _stlink_sg_write_reg(stlink_t *sl, uint32_t reg, int32_t idx) {
struct stlink_libsg *sg = sl->backend_data;
clear_cdb(sg);
sg->cdb_cmd_blk[1] = STLINK_DEBUG_APIV1_WRITEREG;
@@ -706,10 +720,10 @@ int _stlink_sg_write_reg(stlink_t *sl, uint32_t reg, int idx) {
sl->q_len = 2;
sg->q_addr = 0;
- if (stlink_q(sl)) { return(-1); }
+ if (stlink_q(sl)) { return (-1); }
stlink_stat(sl, "write reg");
- return(0);
+ return (0);
}
// write a register of the debug module of the core.
@@ -731,7 +745,7 @@ void stlink_write_dreg(stlink_t *sl, uint32_t reg, uint32_t addr) {
}
// force the core exit the debug mode.
-int _stlink_sg_run(stlink_t *sl, enum run_type type) {
+int32_t _stlink_sg_run(stlink_t *sl, enum run_type type) {
struct stlink_libsg *sg = sl->backend_data;
(void)(type); //unused
clear_cdb(sg);
@@ -739,30 +753,30 @@ int _stlink_sg_run(stlink_t *sl, enum run_type type) {
sl->q_len = 2;
sg->q_addr = 0;
- if (stlink_q(sl)) { return(-1); }
+ if (stlink_q(sl)) { return (-1); }
stlink_stat(sl, "run core");
- return(0);
+ return (0);
}
// step the arm-core.
-int _stlink_sg_step(stlink_t *sl) {
+int32_t _stlink_sg_step(stlink_t *sl) {
struct stlink_libsg *sg = sl->backend_data;
clear_cdb(sg);
sg->cdb_cmd_blk[1] = STLINK_DEBUG_STEPCORE;
sl->q_len = 2;
sg->q_addr = 0;
- if (stlink_q(sl)) { return(-1); }
+ if (stlink_q(sl)) { return (-1); }
stlink_stat(sl, "step core");
- return(0);
+ return (0);
}
// TODO: test and make delegate!
// see Cortex-M3 Technical Reference Manual
-void stlink_set_hw_bp(stlink_t *sl, int fp_nr, uint32_t addr, int fp) {
+void stlink_set_hw_bp(stlink_t *sl, int32_t fp_nr, uint32_t addr, int32_t fp) {
DLOG("\n*** stlink_set_hw_bp ***\n");
struct stlink_libsg *sg = sl->backend_data;
clear_cdb(sg);
@@ -780,7 +794,7 @@ void stlink_set_hw_bp(stlink_t *sl, int fp_nr, uint32_t addr, int fp) {
}
// TODO: test and make delegate!
-void stlink_clr_hw_bp(stlink_t *sl, int fp_nr) {
+void stlink_clr_hw_bp(stlink_t *sl, int32_t fp_nr) {
struct stlink_libsg *sg = sl->backend_data;
DLOG("\n*** stlink_clr_hw_bp ***\n");
clear_cdb(sg);
@@ -793,7 +807,7 @@ void stlink_clr_hw_bp(stlink_t *sl, int fp_nr) {
}
// read a "len" bytes to the sl->q_buf from the memory, max 6kB (6144 bytes)
-int _stlink_sg_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
+int32_t _stlink_sg_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
struct stlink_libsg *sg = sl->backend_data;
clear_cdb(sg);
sg->cdb_cmd_blk[1] = STLINK_DEBUG_READMEM_32BIT;
@@ -810,16 +824,16 @@ int _stlink_sg_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
sl->q_len = len;
sg->q_addr = addr;
- if (stlink_q(sl)) { return(-1); }
+ if (stlink_q(sl)) { return (-1); }
stlink_print_data(sl);
- return(0);
+ return (0);
}
// write a "len" bytes from the sl->q_buf to the memory, max 64 Bytes.
-int _stlink_sg_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len) {
+int32_t _stlink_sg_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len) {
struct stlink_libsg *sg = sl->backend_data;
- int ret;
+ int32_t ret;
clear_cdb(sg);
sg->cdb_cmd_blk[1] = STLINK_DEBUG_WRITEMEM_8BIT;
@@ -832,22 +846,22 @@ int _stlink_sg_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len) {
ret = send_usb_mass_storage_command(sg->usb_handle,
sg->ep_req, sg->cdb_cmd_blk, CDB_SL, 0, 0, 0);
- if (ret == -1) { return(ret); }
+ if (ret == -1) { return (ret); }
// This sends the data...
ret = send_usb_data_only(sg->usb_handle,
sg->ep_req, sg->ep_rep, sl->q_buf, len);
- if (ret == -1) { return(ret); }
+ if (ret == -1) { return (ret); }
stlink_print_data(sl);
- return(0);
+ return (0);
}
// write a "len" bytes from the sl->q_buf to the memory, max Q_BUF_LEN bytes.
-int _stlink_sg_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
+int32_t _stlink_sg_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
struct stlink_libsg *sg = sl->backend_data;
- int ret;
+ int32_t ret;
clear_cdb(sg);
sg->cdb_cmd_blk[1] = STLINK_DEBUG_WRITEMEM_32BIT;
@@ -860,56 +874,56 @@ int _stlink_sg_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
ret = send_usb_mass_storage_command(sg->usb_handle,
sg->ep_req, sg->cdb_cmd_blk, CDB_SL, 0, 0, 0);
- if (ret == -1) { return(ret); }
+ if (ret == -1) { return (ret); }
// This sends the data...
ret = send_usb_data_only(sg->usb_handle,
sg->ep_req, sg->ep_rep, sl->q_buf, len);
- if (ret == -1) { return(ret); }
+ if (ret == -1) { return (ret); }
stlink_print_data(sl);
- return(0);
+ return (0);
}
// write one DWORD data to memory
-int _stlink_sg_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data) {
+int32_t _stlink_sg_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data) {
struct stlink_libsg *sg = sl->backend_data;
clear_cdb(sg);
- sg->cdb_cmd_blk[1] = STLINK_JTAG_WRITEDEBUG_32BIT;
+ sg->cdb_cmd_blk[1] = STLINK_DEBUG_APIV2_WRITEDEBUGREG;
// 2-5: addr
write_uint32(sg->cdb_cmd_blk + 2, addr);
write_uint32(sg->cdb_cmd_blk + 6, data);
sl->q_len = 2;
- return(stlink_q(sl));
+ return (stlink_q(sl));
}
// read one DWORD data from memory
-int _stlink_sg_read_debug32(stlink_t *sl, uint32_t addr, uint32_t *data) {
+int32_t _stlink_sg_read_debug32(stlink_t *sl, uint32_t addr, uint32_t *data) {
struct stlink_libsg *sg = sl->backend_data;
clear_cdb(sg);
- sg->cdb_cmd_blk[1] = STLINK_JTAG_READDEBUG_32BIT;
+ sg->cdb_cmd_blk[1] = STLINK_DEBUG_APIV2_READDEBUGREG;
// 2-5: addr
write_uint32(sg->cdb_cmd_blk + 2, addr);
sl->q_len = 8;
- if (stlink_q(sl)) { return(-1); }
+ if (stlink_q(sl)) { return (-1); }
*data = read_uint32(sl->q_buf, 4);
- return(0);
+ return (0);
}
// exit the jtag or swd mode and enter the mass mode.
-int _stlink_sg_exit_debug_mode(stlink_t *stl) {
+int32_t _stlink_sg_exit_debug_mode(stlink_t *stl) {
if (stl) {
struct stlink_libsg* sl = stl->backend_data;
clear_cdb(sl);
sl->cdb_cmd_blk[1] = STLINK_DEBUG_EXIT;
stl->q_len = 0; // >0 -> aboard
- return(stlink_q(stl));
+ return (stlink_q(stl));
}
- return(0);
+ return (0);
}
// 1) open a sg device, switch the stlink from dfu to mass mode
@@ -951,7 +965,7 @@ static stlink_backend_t _stlink_sg_backend = {
NULL, // trace_read
};
-static stlink_t* stlink_open(const int verbose) {
+static stlink_t* stlink_open(const int32_t verbose) {
stlink_t *sl = malloc(sizeof(stlink_t));
struct stlink_libsg *slsg = malloc(sizeof(struct stlink_libsg));
@@ -962,7 +976,7 @@ static stlink_t* stlink_open(const int verbose) {
if (slsg != NULL) { free(slsg); }
- return(NULL);
+ return (NULL);
}
memset(sl, 0, sizeof(stlink_t));
@@ -971,7 +985,7 @@ static stlink_t* stlink_open(const int verbose) {
WLOG("failed to init libusb context, wrong version of libraries?\n");
free(sl);
free(slsg);
- return(NULL);
+ return (NULL);
}
#if LIBUSB_API_VERSION < 0x01000106
@@ -988,13 +1002,13 @@ static stlink_t* stlink_open(const int verbose) {
libusb_exit(slsg->libusb_ctx);
free(sl);
free(slsg);
- return(NULL);
+ return (NULL);
}
// TODO: Could read the interface config descriptor, and assert lots of the assumptions
// assumption: numInterfaces is always 1...
if (libusb_kernel_driver_active(slsg->usb_handle, 0) == 1) {
- int r = libusb_detach_kernel_driver(slsg->usb_handle, 0);
+ int32_t r = libusb_detach_kernel_driver(slsg->usb_handle, 0);
if (r < 0) {
WLOG("libusb_detach_kernel_driver(() error %s\n", strerror(-r));
@@ -1002,13 +1016,13 @@ static stlink_t* stlink_open(const int verbose) {
libusb_exit(slsg->libusb_ctx);
free(sl);
free(slsg);
- return(NULL);
+ return (NULL);
}
DLOG("Kernel driver was successfully detached\n");
}
- int config;
+ int32_t config;
if (libusb_get_configuration(slsg->usb_handle, &config)) {
/* this may fail for a previous configured device */
@@ -1017,7 +1031,7 @@ static stlink_t* stlink_open(const int verbose) {
libusb_exit(slsg->libusb_ctx);
free(sl);
free(slsg);
- return(NULL);
+ return (NULL);
}
@@ -1033,7 +1047,7 @@ static stlink_t* stlink_open(const int verbose) {
libusb_exit(slsg->libusb_ctx);
free(sl);
free(slsg);
- return(NULL);
+ return (NULL);
}
}
@@ -1043,7 +1057,7 @@ static stlink_t* stlink_open(const int verbose) {
libusb_exit(slsg->libusb_ctx);
free(sl);
free(slsg);
- return(NULL);
+ return (NULL);
}
// assumption: endpoint config is fixed mang. really.
@@ -1059,34 +1073,34 @@ static stlink_t* stlink_open(const int verbose) {
sl->core_stat = TARGET_UNKNOWN;
slsg->q_addr = 0;
- return(sl);
+ return (sl);
}
-stlink_t* stlink_v1_open_inner(const int verbose) {
+stlink_t* stlink_v1_open_inner(const int32_t verbose) {
ugly_init(verbose);
stlink_t *sl = stlink_open(verbose);
if (sl == NULL) {
ELOG("Could not open stlink device\n");
- return(NULL);
+ return (NULL);
}
stlink_version(sl);
if ((sl->version.st_vid != STLINK_USB_VID_ST) || (sl->version.stlink_pid != STLINK_USB_PID_STLINK)) {
ELOG("WTF? successfully opened, but unable to read version details. BROKEN!\n");
- return(NULL);
+ return (NULL);
}
DLOG("Reading current mode...\n");
switch (stlink_current_mode(sl)) {
case STLINK_DEV_MASS_MODE:
- return(sl);
+ return (sl);
case STLINK_DEV_DEBUG_MODE:
// TODO go to mass?
- return(sl);
+ return (sl);
default:
ILOG("Current mode unusable, trying to get back to a useful state...\n");
break;
@@ -1100,16 +1114,16 @@ stlink_t* stlink_v1_open_inner(const int verbose) {
if ((sl->version.st_vid != STLINK_USB_VID_ST) || (sl->version.stlink_pid != STLINK_USB_PID_STLINK)) {
ELOG("WTF? successfully opened, but unable to read version details. BROKEN!\n");
- return(NULL);
+ return (NULL);
}
- return(sl);
+ return (sl);
}
-stlink_t* stlink_v1_open(const int verbose, int reset) {
+stlink_t* stlink_v1_open(const int32_t verbose, int32_t reset) {
stlink_t *sl = stlink_v1_open_inner(verbose);
- if (sl == NULL) { return(NULL); }
+ if (sl == NULL) { return (NULL); }
// by now, it _must_ be fully open and in a useful mode....
stlink_enter_swd_mode(sl);
@@ -1119,5 +1133,5 @@ stlink_t* stlink_v1_open(const int verbose, int reset) {
stlink_load_device_params(sl);
ILOG("Successfully opened a stlink v1 debugger\n");
- return(sl);
+ return (sl);
}
diff --git a/src/stlink-lib/sg.h b/src/stlink-lib/sg.h
index f34b2e1..b10d0f6 100644
--- a/src/stlink-lib/sg.h
+++ b/src/stlink-lib/sg.h
@@ -1,17 +1,19 @@
+/* == nightwalker-87: TODO: CONTENT AND USE OF THIS SOURCE FILE IS TO BE VERIFIED (07.06.2023) == */
+
/*
- * File: sg.h
- * Author: karl
+ * File: sg.h
+ *
+ *
*/
-#ifndef STLINK_SG_H
-#define STLINK_SG_H
+#ifndef SG_H
+#define SG_H
+
+#include <stdint.h>
#include <stlink.h>
-#include <libusb_settings.h>
-#ifdef __cplusplus
-extern "C" {
-#endif
+#include "libusb_settings.h"
/* Device access */
#define RDWR 0
@@ -39,15 +41,15 @@ extern "C" {
struct stlink_libsg {
libusb_context* libusb_ctx;
libusb_device_handle *usb_handle;
- unsigned ep_rep;
- unsigned ep_req;
+ uint32_t ep_rep;
+ uint32_t ep_req;
- int sg_fd;
- int do_scsi_pt_err;
+ int32_t sg_fd;
+ int32_t do_scsi_pt_err;
unsigned char cdb_cmd_blk[CDB_SL];
- int q_data_dir; // Q_DATA_IN, Q_DATA_OUT
+ int32_t q_data_dir; // Q_DATA_IN, Q_DATA_OUT
// the start of the query data in the device memory space
uint32_t q_addr;
@@ -58,10 +60,46 @@ struct stlink_libsg {
struct stlink_reg reg;
};
-stlink_t* stlink_v1_open(const int verbose, int reset);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // STLINK_SG_H
+// static void clear_cdb(struct stlink_libsg *sl);
+void _stlink_sg_close(stlink_t *sl);
+// static int32_t get_usb_mass_storage_status(libusb_device_handle *handle, uint8_t endpoint, uint32_t *tag);
+// static int32_t dump_CDB_command(uint8_t *cdb, uint8_t cdb_len);
+int32_t send_usb_mass_storage_command(libusb_device_handle *handle, uint8_t endpoint_out, uint8_t *cdb, uint8_t cdb_length,
+ uint8_t lun, uint8_t flags, uint32_t expected_rx_size);
+// static void get_sense(libusb_device_handle *handle, uint8_t endpoint_in, uint8_t endpoint_out);
+int32_t send_usb_data_only(libusb_device_handle *handle, unsigned char endpoint_out,
+ unsigned char endpoint_in, unsigned char *cbuf, uint32_t length);
+int32_t stlink_q(stlink_t *sl);
+void stlink_stat(stlink_t *stl, char *txt);
+int32_t _stlink_sg_version(stlink_t *stl);
+int32_t _stlink_sg_current_mode(stlink_t *stl);
+int32_t _stlink_sg_enter_swd_mode(stlink_t *sl);
+int32_t _stlink_sg_enter_jtag_mode(stlink_t *sl);
+int32_t _stlink_sg_exit_dfu_mode(stlink_t *sl);
+int32_t _stlink_sg_core_id(stlink_t *sl);
+int32_t _stlink_sg_reset(stlink_t *sl);
+int32_t _stlink_sg_jtag_reset(stlink_t *sl, int32_t value);
+int32_t _stlink_sg_status(stlink_t *sl);
+int32_t _stlink_sg_force_debug(stlink_t *sl);
+int32_t _stlink_sg_read_all_regs(stlink_t *sl, struct stlink_reg *regp);
+int32_t _stlink_sg_read_reg(stlink_t *sl, int32_t r_idx, struct stlink_reg *regp);
+int32_t _stlink_sg_write_reg(stlink_t *sl, uint32_t reg, int32_t idx);
+void stlink_write_dreg(stlink_t *sl, uint32_t reg, uint32_t addr);
+int32_t _stlink_sg_run(stlink_t *sl, enum run_type type);
+int32_t _stlink_sg_step(stlink_t *sl);
+void stlink_set_hw_bp(stlink_t *sl, int32_t fp_nr, uint32_t addr, int32_t fp);
+void stlink_clr_hw_bp(stlink_t *sl, int32_t fp_nr);
+int32_t _stlink_sg_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len);
+int32_t _stlink_sg_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len);
+int32_t _stlink_sg_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len);
+int32_t _stlink_sg_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data);
+int32_t _stlink_sg_read_debug32(stlink_t *sl, uint32_t addr, uint32_t *data);
+int32_t _stlink_sg_exit_debug_mode(stlink_t *stl);
+
+// static stlink_backend_t _stlink_sg_backend = { };
+
+// static stlink_t* stlink_open(const int32_t verbose);
+stlink_t* stlink_v1_open_inner(const int32_t verbose);
+stlink_t* stlink_v1_open(const int32_t verbose, int32_t reset);
+
+#endif // SG_H
diff --git a/src/stlink-lib/spdlog_wrapper.h b/src/stlink-lib/spdlog_wrapper.h
new file mode 100644
index 0000000..26f34c8
--- /dev/null
+++ b/src/stlink-lib/spdlog_wrapper.h
@@ -0,0 +1,14 @@
+#ifndef _SPDLOG_WRAPPER_
+#define _SPDLOG_WRAPPER_
+
+#ifdef __cplusplus
+#define EXTERNC extern "C"
+#else
+#define EXTERNC
+#endif
+
+EXTERNC int spdlogLog(int level, const char *str, ...);
+
+#undef EXTERNC
+
+#endif \ No newline at end of file
diff --git a/src/stlink-lib/usb.c b/src/stlink-lib/usb.c
index 2754db0..83e2652 100644
--- a/src/stlink-lib/usb.c
+++ b/src/stlink-lib/usb.c
@@ -1,36 +1,44 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <limits.h>
+/*
+ * File: usb.c
+ *
+ * USB commands & interaction with ST-LINK devices
+ */
#if !defined(_MSC_VER)
#include <sys/time.h>
-#endif
-
-#include <sys/types.h>
-#include <errno.h>
-#include <unistd.h>
+#endif // _MSC_VER
#if defined(_WIN32)
#include <win32_socket.h>
-#endif
+#endif // _WIN32
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <unistd.h>
#include <stlink.h>
-#include <helper.h>
#include "usb.h"
-enum SCSI_Generic_Direction {SG_DXFER_TO_DEV = 0, SG_DXFER_FROM_DEV = 0x80};
+#include "commands.h"
+#include "logging.h"
+#include "read_write.h"
+#include "register.h"
static inline uint32_t le_to_h_u32(const uint8_t* buf) {
- return((uint32_t)((uint32_t)buf[0] | (uint32_t)buf[1] << 8 | (uint32_t)buf[2] << 16 | (uint32_t)buf[3] << 24));
+ return ((uint32_t)((uint32_t)buf[0] | (uint32_t)buf[1] << 8 | (uint32_t)buf[2] << 16 | (uint32_t)buf[3] << 24));
}
-static int _stlink_match_speed_map(const uint32_t *map, unsigned int map_size, uint32_t khz) {
- unsigned int i;
- int speed_index = -1;
- int speed_diff = INT_MAX;
- int last_valid_speed = -1;
+static int32_t _stlink_match_speed_map(const uint32_t *map, uint32_t map_size, uint32_t khz) {
+ uint32_t i;
+ int32_t speed_index = -1;
+ int32_t speed_diff = INT_MAX;
+ int32_t last_valid_speed = -1;
bool match = true;
for (i = 0; i < map_size; i++) {
@@ -42,7 +50,7 @@ static int _stlink_match_speed_map(const uint32_t *map, unsigned int map_size, u
speed_index = i;
break;
} else {
- int current_diff = khz - map[i];
+ int32_t current_diff = khz - map[i];
// get abs value for comparison
current_diff = (current_diff > 0) ? current_diff : -current_diff;
@@ -66,7 +74,7 @@ static int _stlink_match_speed_map(const uint32_t *map, unsigned int map_size, u
ILOG("Unable to match requested speed %d kHz, using %d kHz\n", khz, map[speed_index]);
}
- return(speed_index);
+ return (speed_index);
}
void _stlink_usb_close(stlink_t* sl) {
@@ -83,58 +91,92 @@ void _stlink_usb_close(stlink_t* sl) {
}
}
-ssize_t send_recv(struct stlink_libusb* handle, int terminate,
- unsigned char* txbuf, size_t txsize, unsigned char* rxbuf, size_t rxsize) {
+ssize_t send_recv(struct stlink_libusb* handle, int32_t terminate, unsigned char* txbuf, uint32_t txsize,
+ unsigned char* rxbuf, uint32_t rxsize, int32_t check_error, const char *cmd) {
// Note: txbuf and rxbuf can point to the same area
- int res = 0;
- int t;
+ int32_t res, t, retry = 0;
- t = libusb_bulk_transfer(handle->usb_handle, handle->ep_req, txbuf, (int)txsize, &res, 3000);
+ while (1) {
+ res = 0;
+ t = libusb_bulk_transfer(handle->usb_handle, handle->ep_req, txbuf, (int32_t)txsize, &res, 3000);
- if (t) {
- printf("[!] send_recv send request failed: %s\n", libusb_error_name(t));
- return(-1);
- } else if ((size_t)res != txsize) {
- printf("[!] send_recv send request wrote %u bytes (instead of %u).\n",
- (unsigned int)res, (unsigned int)txsize);
- }
+ if (t) {
+ ELOG("%s send request failed: %s\n", cmd, libusb_error_name(t));
+ return (-1);
+ } else if ((size_t)res != txsize) {
+ ELOG("%s send request wrote %u bytes, instead of %u\n", cmd, (uint32_t)res, (uint32_t)txsize);
+ }
- if (rxsize != 0) {
- t = libusb_bulk_transfer(handle->usb_handle, handle->ep_rep, rxbuf, (int)rxsize, &res, 3000);
+ if (rxsize != 0) {
+ t = libusb_bulk_transfer(handle->usb_handle, handle->ep_rep, rxbuf, (int32_t)rxsize, &res, 3000);
- if (t) {
- printf("[!] send_recv read reply failed: %s\n", libusb_error_name(t));
- return(-1);
+ if (t) {
+ ELOG("%s read reply failed: %s\n", cmd, libusb_error_name(t));
+ return (-1);
+ }
+
+ /* Checking the command execution status stored in the first byte of the response */
+ if (handle->protocoll != 1 && check_error >= CMD_CHECK_STATUS &&
+ rxbuf[0] != STLINK_DEBUG_ERR_OK) {
+ switch(rxbuf[0]) {
+ case STLINK_DEBUG_ERR_AP_WAIT:
+ case STLINK_DEBUG_ERR_DP_WAIT:
+ if (check_error == CMD_CHECK_RETRY && retry < 3) {
+ uint32_t delay_us = (1<<retry) * 1000;
+ DLOG("%s wait error (0x%02X), delaying %u us and retry\n", cmd, rxbuf[0], delay_us);
+ usleep(delay_us);
+ retry++;
+ continue;
+ }
+ DLOG("%s wait error (0x%02X)\n", cmd, rxbuf[0]);
+ break;
+ case STLINK_DEBUG_ERR_FAULT: DLOG("%s response fault\n", cmd); break;
+ case STLINK_DEBUG_ERR_AP_FAULT: DLOG("%s access port fault\n", cmd); break;
+ case STLINK_DEBUG_ERR_DP_FAULT: DLOG("%s debug port fault\n", cmd); break;
+ case STLINK_DEBUG_ERR_AP_ERROR: DLOG("%s access port error\n", cmd); break;
+ case STLINK_DEBUG_ERR_DP_ERROR: DLOG("%s debug port error\n", cmd); break;
+ case STLINK_DEBUG_ERR_WRITE_VERIFY: DLOG("%s verification error\n", cmd); break;
+ case STLINK_DEBUG_ERR_WRITE: DLOG("%s write error\n", cmd); break;
+ default: DLOG("%s error (0x%02X)\n", cmd, rxbuf[0]); break;
+ }
+
+ return (-1);
+ }
+
+ if (check_error == CMD_CHECK_REP_LEN && res != (int32_t)rxsize) {
+ ELOG("%s wrong reply length\n", cmd);
+ res = -1;
+ }
}
- }
- if ((handle->protocoll == 1) && terminate) {
- // read the SG reply
- unsigned char sg_buf[13];
- t = libusb_bulk_transfer(handle->usb_handle, handle->ep_rep, sg_buf, 13, &res, 3000);
+ if ((handle->protocoll == 1) && terminate) {
+ // read the SG reply
+ unsigned char sg_buf[13];
+ t = libusb_bulk_transfer(handle->usb_handle, handle->ep_rep, sg_buf, 13, &res, 3000);
- if (t) {
- printf("[!] send_recv read storage failed: %s\n", libusb_error_name(t));
- return(-1);
+ if (t) {
+ ELOG("%s read storage failed: %s\n", cmd, libusb_error_name(t));
+ return (-1);
+ }
+
+ // The STLink doesn't seem to evaluate the sequence number.
+ handle->sg_transfer_idx++;
}
- // The STLink doesn't seem to evaluate the sequence number.
- handle->sg_transfer_idx++;
+ return (res);
}
-
- return(res);
}
-static inline int send_only(struct stlink_libusb* handle, int terminate,
- unsigned char* txbuf, size_t txsize) {
- return((int)send_recv(handle, terminate, txbuf, txsize, NULL, 0));
+static inline int32_t send_only(struct stlink_libusb* handle, int32_t terminate, unsigned char* txbuf,
+ uint32_t txsize, const char *cmd) {
+ return ((int32_t)send_recv(handle, terminate, txbuf, txsize, NULL, 0, CMD_CHECK_NO, cmd));
}
-static int fill_command(stlink_t * sl, enum SCSI_Generic_Direction dir, uint32_t len) {
+static int32_t fill_command(stlink_t * sl, enum SCSI_Generic_Direction dir, uint32_t len) {
struct stlink_libusb * const slu = sl->backend_data;
unsigned char* const cmd = sl->c_buf;
- int i = 0;
+ int32_t i = 0;
memset(cmd, 0, sizeof(sl->c_buf));
if (slu->protocoll == 1) {
@@ -149,42 +191,31 @@ static int fill_command(stlink_t * sl, enum SCSI_Generic_Direction dir, uint32_t
cmd[i++] = 0; // logical unit
cmd[i++] = 0xa; // command length
}
-
- return(i);
+ return (i);
}
-int _stlink_usb_version(stlink_t *sl) {
+int32_t _stlink_usb_version(stlink_t *sl) {
struct stlink_libusb * const slu = sl->backend_data;
unsigned char* const data = sl->q_buf;
unsigned char* const cmd = sl->c_buf;
ssize_t size;
- uint32_t rep_len = 6;
- int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
+ uint32_t rep_len;
+ int32_t i;
- cmd[i++] = STLINK_GET_VERSION;
-
- size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
-
- if (size == -1) {
- printf("[!] send_recv STLINK_GET_VERSION\n");
- return((int)size);
- }
-
- /* STLINK-V3 requires a specific command */
if (sl->version.stlink_v == 3) {
+ // STLINK-V3 version is determined by another command
rep_len = 12;
i = fill_command(sl, SG_DXFER_FROM_DEV, 16);
- cmd[i++] = STLINK_APIV3_GET_VERSION_EX;
-
- size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
-
- if (size != (ssize_t)rep_len) {
- printf("[!] send_recv STLINK_APIV3_GET_VERSION_EX\n");
- return((int)size);
- }
+ cmd[i++] = STLINK_GET_VERSION_APIV3;
+ } else {
+ rep_len = 6;
+ i = fill_command(sl, SG_DXFER_FROM_DEV, 6);
+ cmd[i++] = STLINK_GET_VERSION;
}
- return(0);
+ size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_REP_LEN, "GET_VERSION");
+
+ return (size < 0 ? -1 : 0);
}
int32_t _stlink_usb_target_voltage(stlink_t *sl) {
@@ -193,81 +224,77 @@ int32_t _stlink_usb_target_voltage(stlink_t *sl) {
unsigned char* const cmd = sl->c_buf;
ssize_t size;
uint32_t rep_len = 8;
- int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
+ int32_t i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
uint32_t factor, reading;
- int voltage;
+ int32_t voltage;
cmd[i++] = STLINK_GET_TARGET_VOLTAGE;
- size = send_recv(slu, 1, cmd, slu->cmd_len, rdata, rep_len);
+ size = send_recv(slu, 1, cmd, slu->cmd_len, rdata, rep_len, CMD_CHECK_REP_LEN, "GET_TARGET_VOLTAGE");
- if (size == -1) {
- printf("[!] send_recv STLINK_GET_TARGET_VOLTAGE\n");
- return(-1);
- } else if (size != 8) {
- printf("[!] wrong length STLINK_GET_TARGET_VOLTAGE\n");
- return(-1);
+ if (size < 0) {
+ return (-1);
}
factor = (rdata[3] << 24) | (rdata[2] << 16) | (rdata[1] << 8) | (rdata[0] << 0);
reading = (rdata[7] << 24) | (rdata[6] << 16) | (rdata[5] << 8) | (rdata[4] << 0);
- voltage = 2400 * reading / factor;
+ DLOG("target voltage factor=%08x reading=%08x\n", factor, reading);
+ if (factor != 0 && reading != 0) {
+ voltage = 2400 * reading / factor;
+ } else {
+ DLOG("voltage reading failed at device side, bad STLink chip?\n");
+ voltage = 0;
+ }
- return(voltage);
+ return (voltage);
}
-int _stlink_usb_read_debug32(stlink_t *sl, uint32_t addr, uint32_t *data) {
+int32_t _stlink_usb_read_debug32(stlink_t *sl, uint32_t addr, uint32_t *data) {
struct stlink_libusb * const slu = sl->backend_data;
unsigned char* const rdata = sl->q_buf;
unsigned char* const cmd = sl->c_buf;
ssize_t size;
- const int rep_len = 8;
+ const int32_t rep_len = 8;
- int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
+ int32_t i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
cmd[i++] = STLINK_DEBUG_COMMAND;
- cmd[i++] = STLINK_JTAG_READDEBUG_32BIT;
+ cmd[i++] = STLINK_DEBUG_APIV2_READDEBUGREG;
write_uint32(&cmd[i], addr);
- size = send_recv(slu, 1, cmd, slu->cmd_len, rdata, rep_len);
+ size = send_recv(slu, 1, cmd, slu->cmd_len, rdata, rep_len, CMD_CHECK_RETRY, "READDEBUGREG");
- if (size == -1) {
- printf("[!] send_recv STLINK_JTAG_READDEBUG_32BIT\n");
- return((int)size);
+ if (size < 0) {
+ return (-1);
}
*data = read_uint32(rdata, 4);
- return(0);
+ return (0);
}
-int _stlink_usb_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data) {
+int32_t _stlink_usb_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data) {
struct stlink_libusb * const slu = sl->backend_data;
unsigned char* const rdata = sl->q_buf;
unsigned char* const cmd = sl->c_buf;
ssize_t size;
- const int rep_len = 2;
+ const int32_t rep_len = 2;
- int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
+ int32_t i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
cmd[i++] = STLINK_DEBUG_COMMAND;
- cmd[i++] = STLINK_JTAG_WRITEDEBUG_32BIT;
+ cmd[i++] = STLINK_DEBUG_APIV2_WRITEDEBUGREG;
write_uint32(&cmd[i], addr);
write_uint32(&cmd[i + 4], data);
- size = send_recv(slu, 1, cmd, slu->cmd_len, rdata, rep_len);
+ size = send_recv(slu, 1, cmd, slu->cmd_len, rdata, rep_len, CMD_CHECK_RETRY, "WRITEDEBUGREG");
- if (size == -1) {
- printf("[!] send_recv STLINK_JTAG_WRITEDEBUG_32BIT\n");
- return((int)size);
- }
-
- return(0);
+ return (size < 0 ? -1 : 0);
}
-int _stlink_usb_get_rw_status(stlink_t *sl) {
- if (sl->version.jtag_api == STLINK_JTAG_API_V1) { return(0); }
+int32_t _stlink_usb_get_rw_status(stlink_t *sl) {
+ if (sl->version.jtag_api == STLINK_JTAG_API_V1) { return (0); }
unsigned char* const rdata = sl->q_buf;
struct stlink_libusb * const slu = sl->backend_data;
unsigned char* const cmd = sl->c_buf;
- int i;
+ int32_t i;
int16_t ret = 0;
i = fill_command(sl, SG_DXFER_FROM_DEV, 12);
@@ -275,88 +302,90 @@ int _stlink_usb_get_rw_status(stlink_t *sl) {
if (sl->version.flags & STLINK_F_HAS_GETLASTRWSTATUS2) {
cmd[i++] = STLINK_DEBUG_APIV2_GETLASTRWSTATUS2;
- ret = send_recv(slu, 1, cmd, slu->cmd_len, rdata, 12);
+ ret = send_recv(slu, 1, cmd, slu->cmd_len, rdata, 12, CMD_CHECK_STATUS, "GETLASTRWSTATUS2");
} else {
cmd[i++] = STLINK_DEBUG_APIV2_GETLASTRWSTATUS;
- ret = send_recv(slu, 1, cmd, slu->cmd_len, rdata, 2);
+ ret = send_recv(slu, 1, cmd, slu->cmd_len, rdata, 2, CMD_CHECK_STATUS, "GETLASTRWSTATUS");
}
- if (ret < 0) { return(-1); }
-
- return(0);
+ return (ret < 0 ? -1 : 0);
}
-int _stlink_usb_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
+int32_t _stlink_usb_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
struct stlink_libusb * const slu = sl->backend_data;
unsigned char* const data = sl->q_buf;
unsigned char* const cmd = sl->c_buf;
- int i, ret;
+ int32_t i, ret;
i = fill_command(sl, SG_DXFER_TO_DEV, len);
cmd[i++] = STLINK_DEBUG_COMMAND;
cmd[i++] = STLINK_DEBUG_WRITEMEM_32BIT;
write_uint32(&cmd[i], addr);
write_uint16(&cmd[i + 4], len);
- ret = send_only(slu, 0, cmd, slu->cmd_len);
+ ret = send_only(slu, 0, cmd, slu->cmd_len, "WRITEMEM_32BIT");
- if (ret == -1) { return(ret); }
+ if (ret == -1) { return (ret); }
- ret = send_only(slu, 1, data, len);
+ ret = send_only(slu, 1, data, len, "WRITEMEM_32BIT");
- if (ret == -1) { return(ret); }
+ if (ret == -1) { return (ret); }
- return(_stlink_usb_get_rw_status(sl));
+ return (_stlink_usb_get_rw_status(sl));
}
-int _stlink_usb_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len) {
+int32_t _stlink_usb_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len) {
struct stlink_libusb * const slu = sl->backend_data;
unsigned char* const data = sl->q_buf;
unsigned char* const cmd = sl->c_buf;
- int i, ret;
+ int32_t i, ret;
+
+ if ((sl->version.jtag_api < STLINK_JTAG_API_V3 && len > 64) ||
+ (sl->version.jtag_api >= STLINK_JTAG_API_V3 && len > 512)) {
+ ELOG("WRITEMEM_8BIT: bulk packet limits exceeded (data len %d byte)\n", len);
+ return (-1);
+ }
i = fill_command(sl, SG_DXFER_TO_DEV, 0);
cmd[i++] = STLINK_DEBUG_COMMAND;
cmd[i++] = STLINK_DEBUG_WRITEMEM_8BIT;
write_uint32(&cmd[i], addr);
write_uint16(&cmd[i + 4], len);
- ret = send_only(slu, 0, cmd, slu->cmd_len);
+ ret = send_only(slu, 0, cmd, slu->cmd_len, "WRITEMEM_8BIT");
- if (ret == -1) { return(ret); }
+ if (ret == -1) { return (ret); }
- ret = send_only(slu, 1, data, len);
+ ret = send_only(slu, 1, data, len, "WRITEMEM_8BIT");
- if (ret == -1) { return(ret); }
+ if (ret == -1) { return (ret); }
- return(0);
+ return (0);
}
-
-int _stlink_usb_current_mode(stlink_t * sl) {
+int32_t _stlink_usb_current_mode(stlink_t * sl) {
struct stlink_libusb * const slu = sl->backend_data;
unsigned char* const cmd = sl->c_buf;
unsigned char* const data = sl->q_buf;
ssize_t size;
- int rep_len = 2;
- int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
+ int32_t rep_len = 2;
+ int32_t i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
cmd[i++] = STLINK_GET_CURRENT_MODE;
- size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
+ size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_NO, "GET_CURRENT_MODE");
- if (size == -1) {
- printf("[!] send_recv STLINK_GET_CURRENT_MODE\n");
- return(-1);
+ if (size < 0) {
+ return (-1);
}
- return(sl->q_buf[0]);
+ return (sl->q_buf[0]);
}
-int _stlink_usb_core_id(stlink_t * sl) {
+int32_t _stlink_usb_core_id(stlink_t * sl) {
struct stlink_libusb * const slu = sl->backend_data;
unsigned char* const cmd = sl->c_buf;
unsigned char* const data = sl->q_buf;
ssize_t size;
- int offset, rep_len = sl->version.jtag_api == STLINK_JTAG_API_V1 ? 4 : 12;
- int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
+ int32_t offset, rep_len = sl->version.jtag_api == STLINK_JTAG_API_V1 ? 4 : 12;
+ int32_t i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
cmd[i++] = STLINK_DEBUG_COMMAND;
@@ -368,20 +397,19 @@ int _stlink_usb_core_id(stlink_t * sl) {
offset = 4;
}
- size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
+ size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_STATUS, "READ_IDCODES");
- if (size == -1) {
- printf("[!] send_recv STLINK_DEBUG_READCOREID\n");
- return(-1);
+ if (size < 0) {
+ return (-1);
}
sl->core_id = read_uint32(data, offset);
- return(0);
+ return (0);
}
-int _stlink_usb_status_v2(stlink_t *sl) {
- int result;
+int32_t _stlink_usb_status_v2(stlink_t *sl) {
+ int32_t result;
uint32_t status = 0;
result = _stlink_usb_read_debug32(sl, STLINK_REG_DHCSR, &status);
@@ -399,31 +427,24 @@ int _stlink_usb_status_v2(stlink_t *sl) {
}
}
- return(result);
+ return (result);
}
-int _stlink_usb_status(stlink_t * sl) {
- if (sl->version.jtag_api != STLINK_JTAG_API_V1) { return(_stlink_usb_status_v2(sl)); }
+int32_t _stlink_usb_status(stlink_t * sl) {
+ if (sl->version.jtag_api != STLINK_JTAG_API_V1) { return (_stlink_usb_status_v2(sl)); }
struct stlink_libusb * const slu = sl->backend_data;
unsigned char* const data = sl->q_buf;
unsigned char* const cmd = sl->c_buf;
ssize_t size;
- int rep_len = 2;
- int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
+ int32_t rep_len = 2;
+ int32_t i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
cmd[i++] = STLINK_DEBUG_COMMAND;
cmd[i++] = STLINK_DEBUG_GETSTATUS;
- size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
+ size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_NO, "GETSTATUS");
- if (size == -1) {
- printf("[!] send_recv STLINK_DEBUG_GETSTATUS\n");
- return((int)size);
- }
-
- sl->q_len = (int)size;
-
- if (sl->q_len > 1) {
+ if (size > 1) {
if (sl->q_buf[0] == STLINK_CORE_RUNNING) {
sl->core_stat = TARGET_RUNNING;
} else if (sl->q_buf[0] == STLINK_CORE_HALTED) {
@@ -435,84 +456,69 @@ int _stlink_usb_status(stlink_t * sl) {
sl->core_stat = TARGET_UNKNOWN;
}
- return(0);
+ return (size < 0 ? -1 : 0);
}
-int _stlink_usb_force_debug(stlink_t *sl) {
+int32_t _stlink_usb_force_debug(stlink_t *sl) {
struct stlink_libusb *slu = sl->backend_data;
- int res;
+ int32_t res;
if (sl->version.jtag_api != STLINK_JTAG_API_V1) {
res = _stlink_usb_write_debug32(sl, STLINK_REG_DHCSR, STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_HALT | STLINK_REG_DHCSR_C_DEBUGEN);
- return(res);
+ return (res);
}
unsigned char* const data = sl->q_buf;
unsigned char* const cmd = sl->c_buf;
ssize_t size;
- int rep_len = 2;
- int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
+ int32_t rep_len = 2;
+ int32_t i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
cmd[i++] = STLINK_DEBUG_COMMAND;
cmd[i++] = STLINK_DEBUG_FORCEDEBUG;
- size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
-
- if (size == -1) {
- printf("[!] send_recv STLINK_DEBUG_FORCEDEBUG\n");
- return((int)size);
- }
+ size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_RETRY, "FORCEDEBUG");
- return(0);
+ return (size < 0 ? -1 : 0);
}
-int _stlink_usb_enter_swd_mode(stlink_t * sl) {
+int32_t _stlink_usb_enter_swd_mode(stlink_t * sl) {
struct stlink_libusb * const slu = sl->backend_data;
unsigned char* const cmd = sl->c_buf;
ssize_t size;
unsigned char* const data = sl->q_buf;
const uint32_t rep_len = sl->version.jtag_api == STLINK_JTAG_API_V1 ? 0 : 2;
- int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
+ int32_t i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
cmd[i++] = STLINK_DEBUG_COMMAND;
// select correct API-Version for entering SWD mode: V1 API (0x20) or V2 API (0x30).
cmd[i++] = sl->version.jtag_api == STLINK_JTAG_API_V1 ? STLINK_DEBUG_APIV1_ENTER : STLINK_DEBUG_APIV2_ENTER;
cmd[i++] = STLINK_DEBUG_ENTER_SWD;
- size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
-
- if (size == -1) {
- printf("[!] send_recv STLINK_DEBUG_ENTER\n");
- return((int)size);
- }
+ size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_RETRY, "ENTER_SWD");
- return(0);
+ return (size < 0 ? -1 : 0);
}
-int _stlink_usb_exit_dfu_mode(stlink_t* sl) {
+int32_t _stlink_usb_exit_dfu_mode(stlink_t* sl) {
struct stlink_libusb * const slu = sl->backend_data;
unsigned char* const cmd = sl->c_buf;
ssize_t size;
- int i = fill_command(sl, SG_DXFER_FROM_DEV, 0);
+ int32_t i = fill_command(sl, SG_DXFER_FROM_DEV, 0);
cmd[i++] = STLINK_DFU_COMMAND;
cmd[i++] = STLINK_DFU_EXIT;
- size = send_only(slu, 1, cmd, slu->cmd_len);
+ size = send_only(slu, 1, cmd, slu->cmd_len, "DFU_EXIT");
- if (size == -1) {
- printf("[!] send_recv STLINK_DFU_EXIT\n");
- return((int)size);
- }
-
- return(0);
+ return (size < 0 ? -1 : 0);
}
-int _stlink_usb_reset(stlink_t * sl) {
+int32_t _stlink_usb_reset(stlink_t * sl) {
struct stlink_libusb * const slu = sl->backend_data;
unsigned char* const data = sl->q_buf;
unsigned char* const cmd = sl->c_buf;
ssize_t size;
- int i, rep_len = 2;
+ int32_t i, rep_len = 2;
// send reset command
i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
@@ -524,39 +530,29 @@ int _stlink_usb_reset(stlink_t * sl) {
cmd[i++] = STLINK_DEBUG_APIV2_RESETSYS;
}
- size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
-
- if (size == -1) {
- printf("[!] send_recv STLINK_DEBUG_RESETSYS\n");
- return((int)size);
- }
+ size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_RETRY, "RESETSYS");
- return(0);
+ return (size < 0 ? -1 : 0);
}
-int _stlink_usb_jtag_reset(stlink_t * sl, int value) {
+int32_t _stlink_usb_jtag_reset(stlink_t * sl, int32_t value) {
struct stlink_libusb * const slu = sl->backend_data;
unsigned char* const data = sl->q_buf;
unsigned char* const cmd = sl->c_buf;
ssize_t size;
- int rep_len = 2;
- int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
+ int32_t rep_len = 2;
+ int32_t i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
cmd[i++] = STLINK_DEBUG_COMMAND;
- cmd[i++] = STLINK_JTAG_DRIVE_NRST;
+ cmd[i++] = STLINK_DEBUG_APIV2_DRIVE_NRST;
cmd[i++] = value;
- size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
+ size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_RETRY, "DRIVE_NRST");
- if (size == -1) {
- printf("[!] send_recv STLINK_JTAG_DRIVE_NRST\n");
- return((int)size);
- }
-
- return(0);
+ return (size < 0 ? -1 : 0);
}
-int _stlink_usb_step(stlink_t* sl) {
+int32_t _stlink_usb_step(stlink_t* sl) {
struct stlink_libusb * const slu = sl->backend_data;
if (sl->version.jtag_api != STLINK_JTAG_API_V1) {
@@ -566,25 +562,20 @@ int _stlink_usb_step(stlink_t* sl) {
_stlink_usb_write_debug32(sl, STLINK_REG_DHCSR, STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_STEP |
STLINK_REG_DHCSR_C_MASKINTS | STLINK_REG_DHCSR_C_DEBUGEN);
return _stlink_usb_write_debug32(sl, STLINK_REG_DHCSR, STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_HALT |
- STLINK_REG_DHCSR_C_DEBUGEN);
+ STLINK_REG_DHCSR_C_DEBUGEN);
}
unsigned char* const data = sl->q_buf;
unsigned char* const cmd = sl->c_buf;
ssize_t size;
- int rep_len = 2;
- int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
+ int32_t rep_len = 2;
+ int32_t i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
cmd[i++] = STLINK_DEBUG_COMMAND;
cmd[i++] = STLINK_DEBUG_STEPCORE;
- size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
-
- if (size == -1) {
- printf("[!] send_recv STLINK_DEBUG_STEPCORE\n");
- return((int)size);
- }
+ size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_RETRY, "STEPCORE");
- return(0);
+ return (size < 0 ? -1 : 0);
}
/**
@@ -592,51 +583,45 @@ int _stlink_usb_step(stlink_t* sl) {
* @param sl
* @param type
*/
-int _stlink_usb_run(stlink_t* sl, enum run_type type) {
+int32_t _stlink_usb_run(stlink_t* sl, enum run_type type) {
struct stlink_libusb * const slu = sl->backend_data;
- int res;
+ int32_t res;
if (sl->version.jtag_api != STLINK_JTAG_API_V1) {
- res = _stlink_usb_write_debug32(sl, STLINK_REG_DHCSR,
- STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_DEBUGEN |
+ res = _stlink_usb_write_debug32(sl, STLINK_REG_DHCSR, STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_DEBUGEN |
((type==RUN_FLASH_LOADER)?STLINK_REG_DHCSR_C_MASKINTS:0));
- return(res);
+ return (res);
}
unsigned char* const data = sl->q_buf;
unsigned char* const cmd = sl->c_buf;
ssize_t size;
- int rep_len = 2;
- int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
+ int32_t rep_len = 2;
+ int32_t i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
cmd[i++] = STLINK_DEBUG_COMMAND;
cmd[i++] = STLINK_DEBUG_RUNCORE;
- size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
+ size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_RETRY, "RUNCORE");
- if (size == -1) {
- printf("[!] send_recv STLINK_DEBUG_RUNCORE\n");
- return((int)size);
- }
-
- return(0);
+ return (size < 0 ? -1 : 0);
}
-int _stlink_usb_set_swdclk(stlink_t* sl, int clk_freq) {
+int32_t _stlink_usb_set_swdclk(stlink_t* sl, int32_t clk_freq) {
struct stlink_libusb * const slu = sl->backend_data;
unsigned char* const data = sl->q_buf;
unsigned char* const cmd = sl->c_buf;
ssize_t size;
- int rep_len = 2;
- int i;
+ int32_t rep_len = 2;
+ int32_t i;
// clock speed only supported by stlink/v2 and for firmware >= 22
if (sl->version.stlink_v == 2 && sl->version.jtag_v >= 22) {
uint16_t clk_divisor;
if (clk_freq) {
const uint32_t map[] = {5, 15, 25, 50, 100, 125, 240, 480, 950, 1200, 1800, 4000};
- int speed_index = _stlink_match_speed_map(map, STLINK_ARRAY_SIZE(map), clk_freq);
+ int32_t speed_index = _stlink_match_speed_map(map, STLINK_ARRAY_SIZE(map), clk_freq);
switch (map[speed_index]) {
case 5: clk_divisor = STLINK_SWDCLK_5KHZ_DIVISOR; break;
case 15: clk_divisor = STLINK_SWDCLK_15KHZ_DIVISOR; break;
@@ -661,30 +646,24 @@ int _stlink_usb_set_swdclk(stlink_t* sl, int clk_freq) {
cmd[i++] = STLINK_DEBUG_APIV2_SWD_SET_FREQ;
cmd[i++] = clk_divisor & 0xFF;
cmd[i++] = (clk_divisor >> 8) & 0xFF;
- size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
-
- if (size == -1) {
- printf("[!] send_recv STLINK_DEBUG_APIV2_SWD_SET_FREQ\n");
- return((int)size);
- }
+ size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_RETRY, "SWD_SET_FREQ");
- return(0);
+ return (size < 0 ? -1 : 0);
} else if (sl->version.stlink_v == 3) {
- int speed_index;
+ int32_t speed_index;
uint32_t map[STLINK_V3_MAX_FREQ_NB];
i = fill_command(sl, SG_DXFER_FROM_DEV, 16);
cmd[i++] = STLINK_DEBUG_COMMAND;
- cmd[i++] = STLINK_APIV3_GET_COM_FREQ;
+ cmd[i++] = STLINK_DEBUG_APIV3_GET_COM_FREQ;
cmd[i++] = 0; // SWD mode
- size = send_recv(slu, 1, cmd, slu->cmd_len, data, 52);
+ size = send_recv(slu, 1, cmd, slu->cmd_len, data, 52, CMD_CHECK_STATUS, "GET_COM_FREQ");
- if (size == -1) {
- printf("[!] send_recv STLINK_APIV3_GET_COM_FREQ\n");
- return((int)size);
+ if (size < 0) {
+ return (-1);
}
- int speeds_size = data[8];
+ int32_t speeds_size = data[8];
if (speeds_size > STLINK_V3_MAX_FREQ_NB) {
speeds_size = STLINK_V3_MAX_FREQ_NB;
}
@@ -694,13 +673,13 @@ int _stlink_usb_set_swdclk(stlink_t* sl, int clk_freq) {
// Set to zero all the next entries
for (i = speeds_size; i < STLINK_V3_MAX_FREQ_NB; i++) map[i] = 0;
- if (!clk_freq) clk_freq = 1800; // set default frequency
+ if (!clk_freq) clk_freq = 1000; // set default frequency
speed_index = _stlink_match_speed_map(map, STLINK_ARRAY_SIZE(map), clk_freq);
i = fill_command(sl, SG_DXFER_FROM_DEV, 16);
cmd[i++] = STLINK_DEBUG_COMMAND;
- cmd[i++] = STLINK_APIV3_SET_COM_FREQ;
+ cmd[i++] = STLINK_DEBUG_APIV3_SET_COM_FREQ;
cmd[i++] = 0; // SWD mode
cmd[i++] = 0;
cmd[i++] = (uint8_t)((map[speed_index] >> 0) & 0xFF);
@@ -708,71 +687,60 @@ int _stlink_usb_set_swdclk(stlink_t* sl, int clk_freq) {
cmd[i++] = (uint8_t)((map[speed_index] >> 16) & 0xFF);
cmd[i++] = (uint8_t)((map[speed_index] >> 24) & 0xFF);
- size = send_recv(slu, 1, cmd, slu->cmd_len, data, 8);
-
- if (size == -1) {
- printf("[!] send_recv STLINK_APIV3_SET_COM_FREQ\n");
- return((int)size);
- }
+ size = send_recv(slu, 1, cmd, slu->cmd_len, data, 8, CMD_CHECK_STATUS, "SET_COM_FREQ");
- return(0);
+ return (size < 0 ? -1 : 0);
} else if (clk_freq) {
WLOG("ST-Link firmware does not support frequency setup\n");
}
- return(-1);
+ return (-1);
}
-int _stlink_usb_exit_debug_mode(stlink_t *sl) {
+int32_t _stlink_usb_exit_debug_mode(stlink_t *sl) {
struct stlink_libusb * const slu = sl->backend_data;
unsigned char* const cmd = sl->c_buf;
ssize_t size;
- int i = fill_command(sl, SG_DXFER_FROM_DEV, 0);
+ int32_t i = fill_command(sl, SG_DXFER_FROM_DEV, 0);
cmd[i++] = STLINK_DEBUG_COMMAND;
cmd[i++] = STLINK_DEBUG_EXIT;
- size = send_only(slu, 1, cmd, slu->cmd_len);
+ size = send_only(slu, 1, cmd, slu->cmd_len, "DEBUG_EXIT");
- if (size == -1) {
- printf("[!] send_only STLINK_DEBUG_EXIT\n");
- return((int)size);
- }
-
- return(0);
+ return (size < 0 ? -1 : 0);
}
-int _stlink_usb_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
+int32_t _stlink_usb_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
struct stlink_libusb * const slu = sl->backend_data;
unsigned char* const data = sl->q_buf;
unsigned char* const cmd = sl->c_buf;
ssize_t size;
- int i = fill_command(sl, SG_DXFER_FROM_DEV, len);
+ int32_t i = fill_command(sl, SG_DXFER_FROM_DEV, len);
cmd[i++] = STLINK_DEBUG_COMMAND;
cmd[i++] = STLINK_DEBUG_READMEM_32BIT;
write_uint32(&cmd[i], addr);
write_uint16(&cmd[i + 4], len);
- size = send_recv(slu, 1, cmd, slu->cmd_len, data, len);
+ size = send_recv(slu, 1, cmd, slu->cmd_len, data, len, CMD_CHECK_NO, "READMEM_32BIT");
- if (size == -1) {
- printf("[!] send_recv STLINK_DEBUG_READMEM_32BIT\n");
- return((int)size);
+ if (size < 0) {
+ return (-1);
}
- sl->q_len = (int)size;
+ sl->q_len = (int32_t)size;
stlink_print_data(sl);
- return(0);
+ return (0);
}
-int _stlink_usb_read_all_regs(stlink_t *sl, struct stlink_reg *regp) {
+int32_t _stlink_usb_read_all_regs(stlink_t *sl, struct stlink_reg *regp) {
struct stlink_libusb * const slu = sl->backend_data;
unsigned char* const cmd = sl->c_buf;
unsigned char* const data = sl->q_buf;
ssize_t size;
uint32_t rep_len = sl->version.jtag_api == STLINK_JTAG_API_V1 ? 84 : 88;
- int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
+ int32_t i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
cmd[i++] = STLINK_DEBUG_COMMAND;
@@ -782,17 +750,16 @@ int _stlink_usb_read_all_regs(stlink_t *sl, struct stlink_reg *regp) {
cmd[i++] = STLINK_DEBUG_APIV2_READALLREGS;
}
- size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
+ size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_STATUS, "READALLREGS");
- if (size == -1) {
- printf("[!] send_recv STLINK_DEBUG_READALLREGS\n");
- return((int)size);
+ if (size < 0) {
+ return (-1);
}
/* V1: regs data from offset 0 */
/* V2: status at offset 0, regs data from offset 4 */
- int reg_offset = sl->version.jtag_api == STLINK_JTAG_API_V1 ? 0 : 4;
- sl->q_len = (int)size;
+ int32_t reg_offset = sl->version.jtag_api == STLINK_JTAG_API_V1 ? 0 : 4;
+ sl->q_len = (int32_t)size;
stlink_print_data(sl);
for (i = 0; i < 16; i++) regp->r[i] = read_uint32(sl->q_buf, reg_offset + i * 4);
@@ -803,7 +770,7 @@ int _stlink_usb_read_all_regs(stlink_t *sl, struct stlink_reg *regp) {
regp->rw = read_uint32(sl->q_buf, reg_offset + 76);
regp->rw2 = read_uint32(sl->q_buf, reg_offset + 80);
- if (sl->verbose < 2) { return(0); }
+ if (sl->verbose < 2) { return (0); }
DLOG("xpsr = 0x%08x\n", regp->xpsr);
DLOG("main_sp = 0x%08x\n", regp->main_sp);
@@ -811,18 +778,18 @@ int _stlink_usb_read_all_regs(stlink_t *sl, struct stlink_reg *regp) {
DLOG("rw = 0x%08x\n", regp->rw);
DLOG("rw2 = 0x%08x\n", regp->rw2);
- return(0);
+ return (0);
}
-int _stlink_usb_read_reg(stlink_t *sl, int r_idx, struct stlink_reg *regp) {
+int32_t _stlink_usb_read_reg(stlink_t *sl, int32_t r_idx, struct stlink_reg *regp) {
struct stlink_libusb * const slu = sl->backend_data;
unsigned char* const data = sl->q_buf;
unsigned char* const cmd = sl->c_buf;
ssize_t size;
uint32_t r;
uint32_t rep_len = sl->version.jtag_api == STLINK_JTAG_API_V1 ? 4 : 8;
- int reg_offset = sl->version.jtag_api == STLINK_JTAG_API_V1 ? 0 : 4;
- int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
+ int32_t reg_offset = sl->version.jtag_api == STLINK_JTAG_API_V1 ? 0 : 4;
+ int32_t i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
cmd[i++] = STLINK_DEBUG_COMMAND;
@@ -833,14 +800,13 @@ int _stlink_usb_read_reg(stlink_t *sl, int r_idx, struct stlink_reg *regp) {
}
cmd[i++] = (uint8_t)r_idx;
- size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
+ size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_RETRY, "READREG");
- if (size == -1) {
- printf("[!] send_recv STLINK_DEBUG_READREG\n");
- return((int)size);
+ if (size < 0) {
+ return (-1);
}
- sl->q_len = (int)size;
+ sl->q_len = (int32_t)size;
stlink_print_data(sl);
r = read_uint32(sl->q_buf, reg_offset);
DLOG("r_idx (%2d) = 0x%08x\n", r_idx, r);
@@ -865,25 +831,25 @@ int _stlink_usb_read_reg(stlink_t *sl, int r_idx, struct stlink_reg *regp) {
regp->r[r_idx] = r;
}
- return(0);
+ return (0);
}
/* See section C1.6 of the ARMv7-M Architecture Reference Manual */
-int _stlink_usb_read_unsupported_reg(stlink_t *sl, int r_idx, struct stlink_reg *regp) {
+int32_t _stlink_usb_read_unsupported_reg(stlink_t *sl, int32_t r_idx, struct stlink_reg *regp) {
uint32_t r;
- int ret;
+ int32_t ret;
sl->q_buf[0] = (unsigned char)r_idx;
- for (int i = 1; i < 4; i++) sl->q_buf[i] = 0;
+ for (int32_t i = 1; i < 4; i++) sl->q_buf[i] = 0;
ret = _stlink_usb_write_mem32(sl, STLINK_REG_DCRSR, 4);
- if (ret == -1) { return(ret); }
+ if (ret == -1) { return (ret); }
ret = _stlink_usb_read_mem32(sl, STLINK_REG_DCRDR, 4);
- if (ret == -1) { return(ret); }
+ if (ret == -1) { return (ret); }
r = read_uint32(sl->q_buf, 0);
DLOG("r_idx (%2d) = 0x%08x\n", r_idx, r);
@@ -903,38 +869,38 @@ int _stlink_usb_read_unsupported_reg(stlink_t *sl, int r_idx, struct stlink_reg
break;
}
- return(0);
+ return (0);
}
-int _stlink_usb_read_all_unsupported_regs(stlink_t *sl, struct stlink_reg *regp) {
- int ret;
+int32_t _stlink_usb_read_all_unsupported_regs(stlink_t *sl, struct stlink_reg *regp) {
+ int32_t ret;
ret = _stlink_usb_read_unsupported_reg(sl, 0x14, regp);
- if (ret == -1) { return(ret); }
+ if (ret == -1) { return (ret); }
ret = _stlink_usb_read_unsupported_reg(sl, 0x21, regp);
- if (ret == -1) { return(ret); }
+ if (ret == -1) { return (ret); }
- for (int i = 0; i < 32; i++) {
+ for (int32_t i = 0; i < 32; i++) {
ret = _stlink_usb_read_unsupported_reg(sl, 0x40 + i, regp);
- if (ret == -1) { return(ret); }
+ if (ret == -1) { return (ret); }
}
- return(0);
+ return (0);
}
/* See section C1.6 of the ARMv7-M Architecture Reference Manual */
-int _stlink_usb_write_unsupported_reg(stlink_t *sl, uint32_t val, int r_idx, struct stlink_reg *regp) {
- int ret;
+int32_t _stlink_usb_write_unsupported_reg(stlink_t *sl, uint32_t val, int32_t r_idx, struct stlink_reg *regp) {
+ int32_t ret;
if (r_idx >= 0x1C && r_idx <= 0x1F) { // primask, basepri, faultmask, or control
/* These are held in the same register */
ret = _stlink_usb_read_unsupported_reg(sl, 0x14, regp);
- if (ret == -1) { return(ret); }
+ if (ret == -1) { return (ret); }
val = (uint8_t)(val >> 24);
@@ -972,23 +938,23 @@ int _stlink_usb_write_unsupported_reg(stlink_t *sl, uint32_t val, int r_idx, str
ret = _stlink_usb_write_mem32(sl, STLINK_REG_DCRDR, 4);
- if (ret == -1) { return(ret); }
+ if (ret == -1) { return (ret); }
sl->q_buf[0] = (unsigned char)r_idx;
sl->q_buf[1] = 0;
sl->q_buf[2] = 0x01;
sl->q_buf[3] = 0;
- return(_stlink_usb_write_mem32(sl, STLINK_REG_DCRSR, 4));
+ return (_stlink_usb_write_mem32(sl, STLINK_REG_DCRSR, 4));
}
-int _stlink_usb_write_reg(stlink_t *sl, uint32_t reg, int idx) {
+int32_t _stlink_usb_write_reg(stlink_t *sl, uint32_t reg, int32_t idx) {
struct stlink_libusb * const slu = sl->backend_data;
unsigned char* const data = sl->q_buf;
unsigned char* const cmd = sl->c_buf;
ssize_t size;
uint32_t rep_len = 2;
- int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
+ int32_t i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
cmd[i++] = STLINK_DEBUG_COMMAND;
@@ -1000,87 +966,68 @@ int _stlink_usb_write_reg(stlink_t *sl, uint32_t reg, int idx) {
cmd[i++] = idx;
write_uint32(&cmd[i], reg);
- size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
-
- if (size == -1) {
- printf("[!] send_recv STLINK_DEBUG_WRITEREG\n");
- return((int)size);
- }
+ size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_RETRY, "WRITEREG");
- sl->q_len = (int)size;
- stlink_print_data(sl);
-
- return(0);
+ return (size < 0 ? -1 : 0);
}
-int _stlink_usb_enable_trace(stlink_t* sl, uint32_t frequency) {
+int32_t _stlink_usb_enable_trace(stlink_t* sl, uint32_t frequency) {
struct stlink_libusb * const slu = sl->backend_data;
unsigned char* const data = sl->q_buf;
unsigned char* const cmd = sl->c_buf;
ssize_t size;
uint32_t rep_len = 2;
+ uint32_t max_trace_buf_len = 0;
+
+ if(sl->version.stlink_v == 2) {
+ max_trace_buf_len = STLINK_V2_TRACE_BUF_LEN;
+ } else if (sl->version.stlink_v == 3) {
+ max_trace_buf_len = STLINK_V3_TRACE_BUF_LEN;
+ };
- int i = fill_command(sl, SG_DXFER_TO_DEV, rep_len);
+ int32_t i = fill_command(sl, SG_DXFER_TO_DEV, rep_len);
cmd[i++] = STLINK_DEBUG_COMMAND;
cmd[i++] = STLINK_DEBUG_APIV2_START_TRACE_RX;
- write_uint16(&cmd[i + 0], 2 * STLINK_TRACE_BUF_LEN);
+ write_uint16(&cmd[i + 0], 2 * max_trace_buf_len);
write_uint32(&cmd[i + 2], frequency);
- size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
-
- if (size == -1) {
- printf("[!] send_only STLINK_DEBUG_APIV2_START_TRACE_RX\n");
- return((int)size);
- }
-
- sl->q_len = (int)size;
- stlink_print_data(sl);
+ size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_STATUS, "START_TRACE_RX");
- return(0);
+ return (size < 0 ? -1 : 0);
}
-int _stlink_usb_disable_trace(stlink_t* sl) {
+int32_t _stlink_usb_disable_trace(stlink_t* sl) {
struct stlink_libusb * const slu = sl->backend_data;
unsigned char* const data = sl->q_buf;
unsigned char* const cmd = sl->c_buf;
ssize_t size;
uint32_t rep_len = 2;
- int i = fill_command(sl, SG_DXFER_TO_DEV, rep_len);
+ int32_t i = fill_command(sl, SG_DXFER_TO_DEV, rep_len);
cmd[i++] = STLINK_DEBUG_COMMAND;
cmd[i++] = STLINK_DEBUG_APIV2_STOP_TRACE_RX;
- size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
+ size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_STATUS, "STOP_TRACE_RX");
- if (size == -1) {
- printf("[!] send_only STLINK_DEBUG_APIV2_STOP_TRACE_RX\n");
- return((int)size);
- }
-
- sl->q_len = (int)size;
- stlink_print_data(sl);
-
- return(0);
+ return (size < 0 ? -1 : 0);
}
-int _stlink_usb_read_trace(stlink_t* sl, uint8_t* buf, size_t size) {
+int32_t _stlink_usb_read_trace(stlink_t* sl, uint8_t* buf, uint32_t size) {
struct stlink_libusb * const slu = sl->backend_data;
unsigned char* const data = sl->q_buf;
unsigned char* const cmd = sl->c_buf;
uint32_t rep_len = 2;
- int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
+ int32_t i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
cmd[i++] = STLINK_DEBUG_COMMAND;
cmd[i++] = STLINK_DEBUG_APIV2_GET_TRACE_NB;
- ssize_t send_size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
+ ssize_t send_size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_NO, "GET_TRACE_NB");
- if (send_size == -1) {
- printf("[!] send_recv STLINK_DEBUG_APIV2_GET_TRACE_NB\n");
- return((int)send_size);
- }
- if (send_size != 2) {
- printf("[!] send_recv STLINK_DEBUG_APIV2_GET_TRACE_NB %d\n", (int)send_size);
- return -1;
+ if (send_size < 0) {
+ return (-1);
+ } else if (send_size != 2) {
+ ELOG("STLINK_DEBUG_APIV2_GET_TRACE_NB reply size %d\n", (int32_t)send_size);
+ return (-1);
}
uint16_t trace_count = read_uint16(sl->q_buf, 0);
@@ -1091,12 +1038,12 @@ int _stlink_usb_read_trace(stlink_t* sl, uint8_t* buf, size_t size) {
}
if (trace_count != 0) {
- int res = 0;
- int t = libusb_bulk_transfer(slu->usb_handle, slu->ep_trace, buf, trace_count, &res, 3000);
+ int32_t res = 0;
+ int32_t t = libusb_bulk_transfer(slu->usb_handle, slu->ep_trace, buf, trace_count, &res, 3000);
- if (t || res != (int)trace_count) {
+ if (t || res != (int32_t)trace_count) {
ELOG("read_trace read error %d\n", t);
- return(-1);
+ return (-1);
}
}
@@ -1144,7 +1091,7 @@ size_t stlink_serial(struct libusb_device_handle *handle, struct libusb_device_d
serial[0] = '\0';
/* get the LANGID from String Descriptor Zero */
- int ret = libusb_get_string_descriptor(handle, 0, 0, desc_serial, sizeof(desc_serial));
+ int32_t ret = libusb_get_string_descriptor(handle, 0, 0, desc_serial, sizeof(desc_serial));
if (ret < 4) return 0;
uint32_t langid = desc_serial[2] | (desc_serial[3] << 8);
@@ -1163,7 +1110,7 @@ size_t stlink_serial(struct libusb_device_handle *handle, struct libusb_device_d
if (ret < 0) return 0;
} else if (len == ((STLINK_SERIAL_LENGTH / 2 + 1) * 2)) { /* len == 26 */
/* fix-up the buggy serial */
- for (unsigned int i = 0; i < STLINK_SERIAL_LENGTH; i += 2)
+ for (uint32_t i = 0; i < STLINK_SERIAL_LENGTH; i += 2)
sprintf(serial + i, "%02X", desc_serial[i + 2]);
serial[STLINK_SERIAL_LENGTH] = '\0';
} else {
@@ -1173,17 +1120,24 @@ size_t stlink_serial(struct libusb_device_handle *handle, struct libusb_device_d
return strlen(serial);
}
-stlink_t *stlink_open_usb(enum ugly_loglevel verbose, enum connect_type connect, char serial[STLINK_SERIAL_BUFFER_SIZE], int freq) {
+/**
+ * Open a stlink
+ * @param verbose Verbosity loglevel
+ * @param connect Type of connect to target
+ * @param serial Serial number to search for, when NULL the first stlink found is opened (binary format)
+ * @retval NULL Error while opening the stlink
+ * @retval !NULL Stlink found and ready to use
+ */
+stlink_t *stlink_open_usb(enum ugly_loglevel verbose, enum connect_type connect, char serial[STLINK_SERIAL_BUFFER_SIZE], int32_t freq) {
stlink_t* sl = NULL;
struct stlink_libusb* slu = NULL;
- int ret = -1;
- int config;
+ int32_t ret = -1;
+ int32_t config;
sl = calloc(1, sizeof(stlink_t));
- slu = calloc(1, sizeof(struct stlink_libusb));
-
if (sl == NULL) { goto on_malloc_error; }
+ slu = calloc(1, sizeof(struct stlink_libusb));
if (slu == NULL) { goto on_malloc_error; }
ugly_init(verbose);
@@ -1203,54 +1157,22 @@ stlink_t *stlink_open_usb(enum ugly_loglevel verbose, enum connect_type connect,
libusb_set_option(slu->libusb_ctx, LIBUSB_OPTION_LOG_LEVEL, ugly_libusb_log_level(verbose));
#endif
- libusb_device **list;
- // TODO: We should use ssize_t and use it as a counter if > 0.
- // As per libusb API: ssize_t libusb_get_device_list (libusb_context *ctx, libusb_device ***list)
- int cnt = (int)libusb_get_device_list(slu->libusb_ctx, &list);
+ libusb_device **list = NULL;
+ ssize_t cnt = libusb_get_device_list(slu->libusb_ctx, &list);
struct libusb_device_descriptor desc;
- int devBus = 0;
- int devAddr = 0;
-
- // TODO: Reading a environment variable in a usb open function is not very nice, this should
- // be refactored and moved into the CLI tools, and instead of giving USB_BUS:USB_ADDR a real
- // stlink serial string should be passed to this function. Probably people are using this
- // but this is very odd because as programmer can change to multiple busses and it is better
- // to detect them based on serial.
- char *device = getenv("STLINK_DEVICE");
-
- if (device) {
- char *c = strchr(device, ':');
-
- if (c == NULL) {
- WLOG("STLINK_DEVICE must be <USB_BUS>:<USB_ADDR> format\n");
- goto on_error;
- }
-
- devBus = atoi(device);
- *c++ = 0;
- devAddr = atoi(c);
- ILOG("bus %03d dev %03d\n", devBus, devAddr);
- }
- while (cnt--) {
+ while (cnt-- > 0) {
struct libusb_device_handle *handle;
libusb_get_device_descriptor(list[cnt], &desc);
if (desc.idVendor != STLINK_USB_VID_ST) { continue; }
- if (devBus && devAddr) {
- if ((libusb_get_bus_number(list[cnt]) != devBus) ||
- (libusb_get_device_address(list[cnt]) != devAddr)) {
- continue;
- }
- }
-
ret = libusb_open(list[cnt], &handle);
if (ret) { continue; } // could not open device
- size_t serial_len = stlink_serial(handle, &desc, sl->serial);
+ uint32_t serial_len = stlink_serial(handle, &desc, sl->serial);
libusb_close(handle);
@@ -1272,7 +1194,8 @@ stlink_t *stlink_open_usb(enum ugly_loglevel verbose, enum connect_type connect,
}
if (cnt < 0) {
- WLOG ("Couldn't find %s ST-Link devices\n", (devBus && devAddr) ? "matched" : "any");
+ WLOG ("Couldn't find any ST-Link devices\n");
+ libusb_free_device_list(list, 1);
goto on_error;
} else {
ret = libusb_open(list[cnt], &slu->usb_handle);
@@ -1290,6 +1213,8 @@ stlink_t *stlink_open_usb(enum ugly_loglevel verbose, enum connect_type connect,
libusb_free_device_list(list, 1);
+// libusb_kernel_driver_active is not available on Windows.
+#if !defined(_WIN32)
if (libusb_kernel_driver_active(slu->usb_handle, 0) == 1) {
ret = libusb_detach_kernel_driver(slu->usb_handle, 0);
@@ -1298,6 +1223,7 @@ stlink_t *stlink_open_usb(enum ugly_loglevel verbose, enum connect_type connect,
goto on_libusb_error;
}
}
+#endif // NOT _WIN32
if (libusb_get_configuration(slu->usb_handle, &config)) {
// this may fail for a previous configured device
@@ -1329,7 +1255,8 @@ stlink_t *stlink_open_usb(enum ugly_loglevel verbose, enum connect_type connect,
desc.idProduct == STLINK_USB_PID_STLINK_V3_USBLOADER ||
desc.idProduct == STLINK_USB_PID_STLINK_V3E_PID ||
desc.idProduct == STLINK_USB_PID_STLINK_V3S_PID ||
- desc.idProduct == STLINK_USB_PID_STLINK_V3_2VCP_PID) {
+ desc.idProduct == STLINK_USB_PID_STLINK_V3_2VCP_PID ||
+ desc.idProduct == STLINK_USB_PID_STLINK_V3_NO_MSD_PID) {
slu->ep_req = 1 /* ep req */ | LIBUSB_ENDPOINT_OUT;
slu->ep_trace = 2 | LIBUSB_ENDPOINT_IN;
} else {
@@ -1343,11 +1270,22 @@ stlink_t *stlink_open_usb(enum ugly_loglevel verbose, enum connect_type connect,
// initialize stlink version (sl->version)
stlink_version(sl);
- if (stlink_current_mode(sl) == STLINK_DEV_DFU_MODE) {
- // this seems to work, and is unnecessary information for the user.
- // demoted to debug -- REW
+ int32_t mode = stlink_current_mode(sl);
+ if (mode == STLINK_DEV_DFU_MODE) {
DLOG("-- exit_dfu_mode\n");
- stlink_exit_dfu_mode(sl);
+ _stlink_usb_exit_dfu_mode(sl);
+ }
+
+ if (connect == CONNECT_UNDER_RESET) {
+ // for the connect under reset only
+ // OpenOДD says (official documentation is not available) that
+ // the NRST pin must be pull down before selecting the SWD/JTAG mode
+ if (mode == STLINK_DEV_DEBUG_MODE) {
+ DLOG("-- exit_debug_mode\n");
+ _stlink_usb_exit_debug_mode(sl);
+ }
+
+ _stlink_usb_jtag_reset(sl, STLINK_DEBUG_APIV2_DRIVE_NRST_LOW);
}
sl->freq = freq;
@@ -1355,39 +1293,36 @@ stlink_t *stlink_open_usb(enum ugly_loglevel verbose, enum connect_type connect,
// should be done at this speed too
// set the stlink clock speed (default is 1800kHz)
DLOG("JTAG/SWD freq set to %d\n", freq);
- stlink_set_swdclk(sl, freq);
+ _stlink_usb_set_swdclk(sl, freq);
stlink_target_connect(sl, connect);
- return(sl);
+ return (sl);
on_libusb_error:
stlink_close(sl);
- return(NULL);
+ return (NULL);
on_error:
-
if (slu->libusb_ctx) { libusb_exit(slu->libusb_ctx); }
on_malloc_error:
-
if (sl != NULL) { free(sl); }
-
if (slu != NULL) { free(slu); }
- return(NULL);
+ return (NULL);
}
-static size_t stlink_probe_usb_devs(libusb_device **devs, stlink_t **sldevs[], enum connect_type connect, int freq) {
+static uint32_t stlink_probe_usb_devs(libusb_device **devs, stlink_t **sldevs[], enum connect_type connect, int32_t freq) {
stlink_t **_sldevs;
libusb_device *dev;
- int i = 0;
- size_t slcnt = 0;
- size_t slcur = 0;
+ int32_t i = 0;
+ uint32_t slcnt = 0;
+ uint32_t slcur = 0;
/* Count STLINKs */
while ((dev = devs[i++]) != NULL) {
struct libusb_device_descriptor desc;
- int ret = libusb_get_device_descriptor(dev, &desc);
+ int32_t ret = libusb_get_device_descriptor(dev, &desc);
if (ret < 0) {
WLOG("failed to get libusb device descriptor (libusb error: %d)\n", ret);
@@ -1408,7 +1343,7 @@ static size_t stlink_probe_usb_devs(libusb_device **devs, stlink_t **sldevs[], e
if (!_sldevs) {
*sldevs = NULL;
- return(0);
+ return (0);
}
/* Open STLINKS and attach them to list */
@@ -1416,7 +1351,7 @@ static size_t stlink_probe_usb_devs(libusb_device **devs, stlink_t **sldevs[], e
while ((dev = devs[i++]) != NULL) {
struct libusb_device_descriptor desc;
- int ret = libusb_get_device_descriptor(dev, &desc);
+ int32_t ret = libusb_get_device_descriptor(dev, &desc);
if (ret < 0) {
WLOG("failed to get libusb device descriptor (libusb error: %d)\n", ret);
@@ -1440,7 +1375,7 @@ static size_t stlink_probe_usb_devs(libusb_device **devs, stlink_t **sldevs[], e
break;
}
- size_t serial_len = stlink_serial(handle, &desc, serial);
+ uint32_t serial_len = stlink_serial(handle, &desc, serial);
libusb_close(handle);
@@ -1458,24 +1393,24 @@ static size_t stlink_probe_usb_devs(libusb_device **devs, stlink_t **sldevs[], e
*sldevs = _sldevs;
- return(slcur);
+ return (slcur);
}
-size_t stlink_probe_usb(stlink_t **stdevs[], enum connect_type connect, int freq) {
+size_t stlink_probe_usb(stlink_t **stdevs[], enum connect_type connect, int32_t freq) {
libusb_device **devs;
stlink_t **sldevs;
- size_t slcnt = 0;
- int r;
+ uint32_t slcnt = 0;
+ int32_t r;
ssize_t cnt;
r = libusb_init(NULL);
- if (r < 0) { return(0); }
+ if (r < 0) { return (0); }
cnt = libusb_get_device_list(NULL, &devs);
- if (cnt < 0) { return(0); }
+ if (cnt < 0) { return (0); }
slcnt = stlink_probe_usb_devs(devs, &sldevs, connect, freq);
libusb_free_device_list(devs, 1);
@@ -1484,13 +1419,13 @@ size_t stlink_probe_usb(stlink_t **stdevs[], enum connect_type connect, int freq
*stdevs = sldevs;
- return(slcnt);
+ return (slcnt);
}
-void stlink_probe_usb_free(stlink_t ***stdevs, size_t size) {
+void stlink_probe_usb_free(stlink_t ***stdevs, uint32_t size) {
if (stdevs == NULL || *stdevs == NULL || size == 0) { return; }
- for (size_t n = 0; n < size; n++) { stlink_close((*stdevs)[n]); }
+ for (uint32_t n = 0; n < size; n++) { stlink_close((*stdevs)[n]); }
free(*stdevs);
*stdevs = NULL;
diff --git a/src/stlink-lib/usb.h b/src/stlink-lib/usb.h
index 27de327..2ec7490 100644
--- a/src/stlink-lib/usb.h
+++ b/src/stlink-lib/usb.h
@@ -1,21 +1,17 @@
/*
- * File: usb.h
- * Author: karl
+ * File: usb.h
+ *
+ * USB commands & interaction with ST-LINK devices
*/
-#ifndef STLINK_USB_H
-#define STLINK_USB_H
+#ifndef USB_H
+#define USB_H
-#include <stdbool.h>
+#include <stdint.h>
-#include <stlink.h>
-#include <libusb_settings.h>
+#include "libusb_settings.h"
#include "logging.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#define STLINK_USB_VID_ST 0x0483
#define STLINK_USB_PID_STLINK 0x3744
#define STLINK_USB_PID_STLINK_32L 0x3748
@@ -26,6 +22,7 @@ extern "C" {
#define STLINK_USB_PID_STLINK_V3E_PID 0x374e
#define STLINK_USB_PID_STLINK_V3S_PID 0x374f
#define STLINK_USB_PID_STLINK_V3_2VCP_PID 0x3753
+#define STLINK_USB_PID_STLINK_V3_NO_MSD_PID 0x3754
#define STLINK_V1_USB_PID(pid) ((pid) == STLINK_USB_PID_STLINK)
@@ -38,7 +35,8 @@ extern "C" {
#define STLINK_V3_USB_PID(pid) ((pid) == STLINK_USB_PID_STLINK_V3_USBLOADER || \
(pid) == STLINK_USB_PID_STLINK_V3E_PID || \
(pid) == STLINK_USB_PID_STLINK_V3S_PID || \
- (pid) == STLINK_USB_PID_STLINK_V3_2VCP_PID)
+ (pid) == STLINK_USB_PID_STLINK_V3_2VCP_PID || \
+ (pid) == STLINK_USB_PID_STLINK_V3_NO_MSD_PID)
#define STLINK_SUPPORTED_USB_PID(pid) (STLINK_V1_USB_PID(pid) || \
STLINK_V2_USB_PID(pid) || \
@@ -48,31 +46,64 @@ extern "C" {
#define STLINK_SG_SIZE 31
#define STLINK_CMD_SIZE 16
+enum SCSI_Generic_Direction {SG_DXFER_TO_DEV = 0, SG_DXFER_FROM_DEV = 0x80};
+
struct stlink_libusb {
libusb_context* libusb_ctx;
libusb_device_handle* usb_handle;
- unsigned int ep_req;
- unsigned int ep_rep;
- unsigned int ep_trace;
- int protocoll;
- unsigned int sg_transfer_idx;
- unsigned int cmd_len;
+ uint32_t ep_req;
+ uint32_t ep_rep;
+ uint32_t ep_trace;
+ int32_t protocoll;
+ uint32_t sg_transfer_idx;
+ uint32_t cmd_len;
};
-/**
- * Open a stlink
- * @param verbose Verbosity loglevel
- * @param connect Type of connect to target
- * @param serial Serial number to search for, when NULL the first stlink found is opened (binary format)
- * @retval NULL Error while opening the stlink
- * @retval !NULL Stlink found and ready to use
- */
-stlink_t *stlink_open_usb(enum ugly_loglevel verbose, enum connect_type connect, char serial[STLINK_SERIAL_BUFFER_SIZE], int freq);
-size_t stlink_probe_usb(stlink_t **stdevs[], enum connect_type connect, int freq);
-void stlink_probe_usb_free(stlink_t **stdevs[], size_t size);
+// static inline uint32_t le_to_h_u32(const uint8_t* buf);
+// static int32_t _stlink_match_speed_map(const uint32_t *map, uint32_t map_size, uint32_t khz);
+void _stlink_usb_close(stlink_t* sl);
+ssize_t send_recv(struct stlink_libusb* handle, int32_t terminate, unsigned char* txbuf, uint32_t txsize,
+ unsigned char* rxbuf, uint32_t rxsize, int32_t check_error, const char *cmd);
+// static inline int32_t send_only(struct stlink_libusb* handle, int32_t terminate, unsigned char* txbuf,
+// uint32_t txsize, const char *cmd);
+// static int32_t fill_command(stlink_t * sl, enum SCSI_Generic_Direction dir, uint32_t len);
+int32_t _stlink_usb_version(stlink_t *sl);
+int32_t _stlink_usb_target_voltage(stlink_t *sl);
+int32_t _stlink_usb_read_debug32(stlink_t *sl, uint32_t addr, uint32_t *data);
+int32_t _stlink_usb_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data);
+int32_t _stlink_usb_get_rw_status(stlink_t *sl);
+int32_t _stlink_usb_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len);
+int32_t _stlink_usb_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len);
+int32_t _stlink_usb_current_mode(stlink_t * sl);
+int32_t _stlink_usb_core_id(stlink_t * sl);
+int32_t _stlink_usb_status_v2(stlink_t *sl);
+int32_t _stlink_usb_status(stlink_t * sl);
+int32_t _stlink_usb_force_debug(stlink_t *sl);
+int32_t _stlink_usb_enter_swd_mode(stlink_t * sl);
+int32_t _stlink_usb_exit_dfu_mode(stlink_t* sl);
+int32_t _stlink_usb_reset(stlink_t * sl);
+int32_t _stlink_usb_jtag_reset(stlink_t * sl, int32_t value);
+int32_t _stlink_usb_step(stlink_t* sl);
+int32_t _stlink_usb_run(stlink_t* sl, enum run_type type);
+int32_t _stlink_usb_set_swdclk(stlink_t* sl, int32_t clk_freq);
+int32_t _stlink_usb_exit_debug_mode(stlink_t *sl);
+int32_t _stlink_usb_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len);
+int32_t _stlink_usb_read_all_regs(stlink_t *sl, struct stlink_reg *regp);
+int32_t _stlink_usb_read_reg(stlink_t *sl, int32_t r_idx, struct stlink_reg *regp);
+int32_t _stlink_usb_read_unsupported_reg(stlink_t *sl, int32_t r_idx, struct stlink_reg *regp);
+int32_t _stlink_usb_read_all_unsupported_regs(stlink_t *sl, struct stlink_reg *regp);
+int32_t _stlink_usb_write_unsupported_reg(stlink_t *sl, uint32_t val, int32_t r_idx, struct stlink_reg *regp);
+int32_t _stlink_usb_write_reg(stlink_t *sl, uint32_t reg, int32_t idx);
+int32_t _stlink_usb_enable_trace(stlink_t* sl, uint32_t frequency);
+int32_t _stlink_usb_disable_trace(stlink_t* sl);
+int32_t _stlink_usb_read_trace(stlink_t* sl, uint8_t* buf, uint32_t size);
+
+// static stlink_backend_t _stlink_usb_backend = { };
-#ifdef __cplusplus
-}
-#endif
+size_t stlink_serial(struct libusb_device_handle *handle, struct libusb_device_descriptor *desc, char *serial);
+stlink_t *stlink_open_usb(enum ugly_loglevel verbose, enum connect_type connect, char serial[STLINK_SERIAL_BUFFER_SIZE], int32_t freq);
+// static uint32_t stlink_probe_usb_devs(libusb_device **devs, stlink_t **sldevs[], enum connect_type connect, int32_t freq);
+size_t stlink_probe_usb(stlink_t **stdevs[], enum connect_type connect, int32_t freq);
+void stlink_probe_usb_free(stlink_t **stdevs[], uint32_t size);
-#endif // STLINK_USB_H
+#endif // USB_H
diff --git a/src/win32/getopt/getopt.c b/src/win32/getopt/getopt.c
index 85e8804..3347da3 100644
--- a/src/win32/getopt/getopt.c
+++ b/src/win32/getopt/getopt.c
@@ -1,18 +1,19 @@
#include <stddef.h>
+#include <stdint.h>
#include <string.h>
#include "getopt.h"
#if !defined(_MSC_VER)
-const int no_argument = 0;
-const int required_argument = 1;
-const int optional_argument = 2;
+const int32_t no_argument = 0;
+const int32_t required_argument = 1;
+const int32_t optional_argument = 2;
#endif
char* optarg;
-int optopt;
-int optind = 1; // The variable optind [...] shall be initialized to 1 by the system
-int opterr;
+int32_t optopt;
+int32_t optind = 1; // The variable optind [...] shall be initialized to 1 by the system
+int32_t opterr;
static char* optcursor = NULL;
@@ -24,8 +25,8 @@ static char* optcursor = NULL;
* [2] http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html
* [3] http://www.freebsd.org/cgi/man.cgi?query=getopt&sektion=3&manpath=FreeBSD+9.0-RELEASE
*/
-int getopt(int argc, char* const argv[], const char* optstring) {
- int optchar = -1;
+int32_t getopt(int32_t argc, char* const argv[], const char* optstring) {
+ int32_t optchar = -1;
const char* optdecl = NULL;
optarg = NULL;
@@ -117,33 +118,33 @@ int getopt(int argc, char* const argv[], const char* optstring) {
if (optcursor == NULL || *++optcursor == '\0') { ++optind; }
- return(optchar);
+ return (optchar);
no_more_optchars:
optcursor = NULL;
- return(-1);
+ return (-1);
}
/* Implementation based on http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html */
-int getopt_long(int argc,
+int32_t getopt_long(int32_t argc,
char* const argv[],
const char* optstring,
const struct option* longopts,
int* longindex) {
const struct option* o = longopts;
const struct option* match = NULL;
- int num_matches = 0;
- size_t argument_name_length = 0;
+ int32_t num_matches = 0;
+ uint32_t argument_name_length = 0;
const char* current_argument = NULL;
- int retval = -1;
+ int32_t retval = -1;
optarg = NULL;
optopt = 0;
- if (optind >= argc) { return(-1); }
+ if (optind >= argc) { return (-1); }
if (strlen(argv[optind]) < 3 || strncmp(argv[optind], "--", 2) != 0) {
- return(getopt(argc, argv, optstring));
+ return (getopt(argc, argv, optstring));
}
// it's an option; starts with -- and is longer than two chars
@@ -179,7 +180,7 @@ int getopt_long(int argc,
if (match->has_arg == required_argument) {
/* Only scan the next argv for required arguments. Behavior is not
- specified, but has been observed with Ubuntu and macOS. */
+ specified, but has been observed with Ubuntu. */
if (optarg == NULL && ++optind < argc) { optarg = argv[optind]; }
if (optarg == NULL) { retval = ':'; }
@@ -197,5 +198,5 @@ int getopt_long(int argc,
}
++optind;
- return(retval);
+ return (retval);
}
diff --git a/src/win32/getopt/getopt.h b/src/win32/getopt/getopt.h
index 3aaf73b..4f21e69 100644
--- a/src/win32/getopt/getopt.h
+++ b/src/win32/getopt/getopt.h
@@ -1,5 +1,7 @@
-#ifndef INCLUDED_GETOPT_PORT_H
-#define INCLUDED_GETOPT_PORT_H
+#ifndef GETOPT_H
+#define GETOPT_H
+
+#include <stdint.h>
#if defined(__cplusplus)
extern "C" {
@@ -11,24 +13,24 @@ extern "C" {
#define required_argument 1
#define optional_argument 2
#else
-extern const int no_argument;
-extern const int required_argument;
-extern const int optional_argument;
+extern const int32_t no_argument;
+extern const int32_t required_argument;
+extern const int32_t optional_argument;
#endif
extern char* optarg;
-extern int optind, opterr, optopt;
+extern int32_t optind, opterr, optopt;
struct option {
const char* name;
- int has_arg;
+ int32_t has_arg;
int* flag;
- int val;
+ int32_t val;
};
-int getopt(int argc, char* const argv[], const char* optstring);
+int32_t getopt(int32_t argc, char* const argv[], const char* optstring);
-int getopt_long(int argc,
+int32_t getopt_long(int32_t argc,
char* const argv[],
const char* optstring,
const struct option* longopts,
@@ -38,4 +40,4 @@ int getopt_long(int argc,
}
#endif
-#endif // INCLUDED_GETOPT_PORT_H
+#endif // GETOPT_H
diff --git a/src/win32/mmap.c b/src/win32/mmap.c
index d702a78..8bddb50 100644
--- a/src/win32/mmap.c
+++ b/src/win32/mmap.c
@@ -1,38 +1,39 @@
-#include <string.h>
-#include <sys/types.h>
+#include <stdint.h>
#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
+#include <sys/types.h>
#include "mmap.h"
-void *mmap (void *addr, size_t len, int prot, int flags, int fd, long long offset) {
+void *mmap (void *addr, uint32_t len, int32_t prot, int32_t flags, int32_t fd, int64_t offset) {
void *buf;
ssize_t count;
- if ( addr || fd == -1 || (prot & PROT_WRITE)) { return(MAP_FAILED); }
+ if ( addr || fd == -1 || (prot & PROT_WRITE)) { return (MAP_FAILED); }
buf = malloc(len);
- if ( NULL == buf ) { return(MAP_FAILED); }
+ if ( NULL == buf ) { return (MAP_FAILED); }
if (lseek(fd, offset, SEEK_SET) != offset) {
free(buf);
- return(MAP_FAILED);
+ return (MAP_FAILED);
}
count = read(fd, buf, len);
if (count != (ssize_t)len) {
free (buf);
- return(MAP_FAILED);
+ return (MAP_FAILED);
}
- return(buf);
+ return (buf);
(void)flags;
}
-int munmap (void *addr, size_t len) {
+int32_t munmap (void *addr, uint32_t len) {
free (addr);
- return(0);
+ return (0);
(void)len;
}
diff --git a/src/win32/mmap.h b/src/win32/mmap.h
index 1f2e756..633816b 100644
--- a/src/win32/mmap.h
+++ b/src/win32/mmap.h
@@ -1,5 +1,7 @@
-#ifndef STLINK_MMAP_H
-#define STLINK_MMAP_H
+#ifndef MMAP_H
+#define MMAP_H
+
+#include <stdint.h>
#ifdef STLINK_HAVE_SYS_MMAN_H
#include <sys/mman.h>
@@ -13,17 +15,9 @@
#define MAP_ANONYMOUS (1 << 5)
#define MAP_FAILED ((void *)-1)
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void *mmap(void *addr, size_t len, int prot, int flags, int fd, long long offset);
-int munmap(void *addr, size_t len);
-
-#ifdef __cplusplus
-}
-#endif
+void *mmap(void *addr, uint32_t len, int32_t prot, int32_t flags, int32_t fd, int64_t offset);
+int32_t munmap(void *addr, uint32_t len);
-#endif /* HAVE_SYS_MMAN_H */
+#endif // STLINK_HAVE_SYS_MMAN_H
-#endif /* STLINK_MMAP_H */
+#endif // MMAP_H
diff --git a/src/win32/sys_time.c b/src/win32/sys_time.c
index 08da60b..f1ebd63 100644
--- a/src/win32/sys_time.c
+++ b/src/win32/sys_time.c
@@ -1,3 +1,5 @@
+#include <stdint.h>
+
#include "sys_time.h"
#ifndef STLINK_HAVE_SYS_TIME_H
@@ -5,21 +7,21 @@
#include <time.h>
/* Simple gettimeofday implementation without converting Windows time to Linux time */
-int gettimeofday(struct timeval *tv, struct timezone *tz) {
+int32_t gettimeofday(struct timeval *tv, struct timezone *tz) {
FILETIME ftime;
ULARGE_INTEGER ulint;
- static int tzflag = 0;
+ static int32_t tzflag = 0;
- if(NULL != tv) {
+ if (NULL != tv) {
GetSystemTimeAsFileTime(&ftime);
ulint.LowPart = ftime.dwLowDateTime;
ulint.HighPart = ftime.dwHighDateTime;
- tv->tv_sec = (long)(ulint.QuadPart / 10000000L);
- tv->tv_usec = (long)(ulint.QuadPart % 10000000L);
+ tv->tv_sec = (int32_t)(ulint.QuadPart / 10000000L);
+ tv->tv_usec = (int32_t)(ulint.QuadPart % 10000000L);
}
- if(NULL != tz) {
+ if (NULL != tz) {
if (!tzflag) {
_tzset();
tzflag++;
@@ -30,4 +32,5 @@ int gettimeofday(struct timeval *tv, struct timezone *tz) {
return 0;
}
+
#endif //STLINK_HAVE_SYS_TIME_H
diff --git a/src/win32/sys_time.h b/src/win32/sys_time.h
index 39f97f7..ca6e0a7 100644
--- a/src/win32/sys_time.h
+++ b/src/win32/sys_time.h
@@ -1,27 +1,23 @@
-#ifndef STLINK_TIME_H
-#define STLINK_TIME_H
+#ifndef SYS_TIME_H
+#define SYS_TIME_H
+
+#include <stdint.h>
#ifdef STLINK_HAVE_SYS_TIME_H
+
#include <sys/time.h>
+
#else
#include <windows.h>
struct timezone {
- int tz_minuteswest;
- int tz_dsttime;
+ int32_t tz_minuteswest;
+ int32_t tz_dsttime;
};
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-int gettimeofday(struct timeval *tv, struct timezone *tz);
-
-#ifdef __cplusplus
-}
-#endif
+int32_t gettimeofday(struct timeval *tv, struct timezone *tz);
-#endif /* STLINK_HAVE_SYS_TIME_H */
+#endif // STLINK_HAVE_SYS_TIME_H
-#endif /* STLINK_TIME_H */
+#endif // SYS_TIME_H
diff --git a/src/win32/unistd/unistd.h b/src/win32/unistd/unistd.h
index ac9d0ad..d61b75b 100644
--- a/src/win32/unistd/unistd.h
+++ b/src/win32/unistd/unistd.h
@@ -1,13 +1,14 @@
-#ifndef _UNISTD_H
-#define _UNISTD_H 1
+#ifndef UNISTD_H
+#define UNISTD_H
/*
* This file intended to serve as a drop-in replacement for unistd.h on Windows
* Please add functionality as needed.
*/
-#include <stdlib.h>
+#include <stdint.h>
#include <stdio.h>
+#include <stdlib.h>
#if defined(_MSC_VER)
#pragma warning(push)
@@ -51,6 +52,9 @@
*/
#define ssize_t int
+#ifndef SSIZE_MAX
+#define SSIZE_MAX ((sizeof(ssize_t) == 4) ? 2147483647 : 9223372036854775807)
+#endif
#define STDIN_FILENO 0
#define STDOUT_FILENO 1
@@ -66,7 +70,7 @@ typedef unsigned __int32 uint32_t;
typedef unsigned __int64 uint64_t;
#ifndef STLINK_HAVE_UNISTD_H
-int usleep(unsigned int waitTime);
+int32_t usleep(uint32_t waitTime);
#endif
-#endif // _UNISTD_H
+#endif // UNISTD_H
diff --git a/src/win32/win32_socket.c b/src/win32/win32_socket.c
index 9138a76..d303888 100644
--- a/src/win32/win32_socket.c
+++ b/src/win32/win32_socket.c
@@ -1,5 +1,7 @@
#if defined(_WIN32)
+#include <stdint.h>
+
#include "win32_socket.h"
#undef socket
@@ -11,11 +13,11 @@
#include <errno.h>
#include <assert.h>
-int win32_poll(struct pollfd *fds, unsigned int nfds, int timo) {
+int32_t win32_poll(struct pollfd *fds, uint32_t nfds, int32_t timo) {
struct timeval timeout, *toptr;
fd_set ifds, ofds, efds, *ip, *op;
- unsigned int i;
- int rc;
+ uint32_t i;
+ int32_t rc;
#ifdef _MSC_VER
#pragma warning(disable: 4548)
@@ -66,11 +68,11 @@ int win32_poll(struct pollfd *fds, unsigned int nfds, int timo) {
printf("Exiting select rc=%d\n", rc);
#endif
- if (rc <= 0) { return(rc); }
+ if (rc <= 0) { return (rc); }
if (rc > 0) {
for ( i = 0; i < nfds; ++i) {
- int fd = fds[i].fd;
+ SOCKET fd = fds[i].fd;
if (fds[i].events & (POLLIN | POLLPRI) && FD_ISSET(fd, &ifds)) {
fds[i].revents |= POLLIN;
@@ -96,10 +98,10 @@ int win32_poll(struct pollfd *fds, unsigned int nfds, int timo) {
}
}
- return(rc);
+ return (rc);
}
-static void set_connect_errno(int winsock_err) {
+static void set_connect_errno(int32_t winsock_err) {
switch (winsock_err) {
case WSAEINVAL:
case WSAEALREADY:
@@ -112,7 +114,7 @@ static void set_connect_errno(int winsock_err) {
}
}
-static void set_socket_errno(int winsock_err) {
+static void set_socket_errno(int32_t winsock_err) {
switch (winsock_err) {
case WSAEWOULDBLOCK:
errno = EAGAIN;
@@ -123,29 +125,31 @@ static void set_socket_errno(int winsock_err) {
}
}
-/* A wrapper around the socket() function.
+/*
+ * A wrapper around the socket() function.
* The purpose of this wrapper is to ensure that the global errno symbol is set if an error occurs,
* even if we are using winsock.
*/
-SOCKET win32_socket(int domain, int type, int protocol) {
+SOCKET win32_socket(int32_t domain, int32_t type, int32_t protocol) {
SOCKET fd = socket(domain, type, protocol);
if (fd == INVALID_SOCKET) { set_socket_errno(WSAGetLastError()); }
- return(fd);
+ return (fd);
}
-/* A wrapper around the connect() function.
+/*
+ * A wrapper around the connect() function.
* The purpose of this wrapper is to ensure that the global errno symbol is set if an error occurs,
* even if we are using winsock.
*/
-int win32_connect(SOCKET fd, struct sockaddr *addr, socklen_t addr_len) {
- int rc = connect(fd, addr, addr_len);
+int32_t win32_connect(SOCKET fd, struct sockaddr *addr, socklen_t addr_len) {
+ int32_t rc = connect(fd, addr, addr_len);
assert(rc == 0 || rc == SOCKET_ERROR);
if (rc == SOCKET_ERROR) { set_connect_errno(WSAGetLastError()); }
- return(rc);
+ return (rc);
}
/* A wrapper around the accept() function.
@@ -160,50 +164,50 @@ SOCKET win32_accept(SOCKET fd, struct sockaddr *addr, socklen_t *addr_len) {
newfd = (SOCKET)-1;
}
- return(newfd);
+ return (newfd);
}
/* A wrapper around the shutdown() function.
* The purpose of this wrapper is to ensure that the global errno symbol is set if an error occurs,
* even if we are using winsock.
*/
-int win32_shutdown(SOCKET fd, int mode) {
- int rc = shutdown(fd, mode);
+int32_t win32_shutdown(SOCKET fd, int32_t mode) {
+ int32_t rc = shutdown(fd, mode);
assert(rc == 0 || rc == SOCKET_ERROR);
if (rc == SOCKET_ERROR) { set_socket_errno(WSAGetLastError()); }
- return(rc);
+ return (rc);
}
-int win32_close_socket(SOCKET fd) {
- int rc = closesocket(fd);
+int32_t win32_close_socket(SOCKET fd) {
+ int32_t rc = closesocket(fd);
if (rc == SOCKET_ERROR) { set_socket_errno(WSAGetLastError()); }
- return(rc);
+ return (rc);
}
-ssize_t win32_write_socket(SOCKET fd, void *buf, int n) {
- int rc = send(fd, buf, n, 0);
+ssize_t win32_write_socket(SOCKET fd, void *buf, int32_t n) {
+ int32_t rc = send(fd, buf, n, 0);
if (rc == SOCKET_ERROR) { set_socket_errno(WSAGetLastError()); }
- return(rc);
+ return (rc);
}
-ssize_t win32_read_socket(SOCKET fd, void *buf, int n) {
- int rc = recv(fd, buf, n, 0);
+ssize_t win32_read_socket(SOCKET fd, void *buf, int32_t n) {
+ int32_t rc = recv(fd, buf, n, 0);
if (rc == SOCKET_ERROR) { set_socket_errno(WSAGetLastError()); }
- return(rc);
+ return (rc);
}
char * win32_strtok_r(char *s, const char *delim, char **lasts) {
register char *spanp;
- register int c, sc;
+ register int32_t c, sc;
char *tok;
@@ -240,7 +244,7 @@ cont:
}
*lasts = s;
- return(tok);
+ return (tok);
}
} while (sc != 0);
@@ -252,11 +256,11 @@ cont:
char *win32_strsep (char **stringp, const char *delim) {
register char *s;
register const char *spanp;
- register int c, sc;
+ register int32_t c, sc;
char *tok;
if ((s = *stringp) == NULL) {
- return(NULL);
+ return (NULL);
}
for (tok = s; ;) {
@@ -272,7 +276,7 @@ char *win32_strsep (char **stringp, const char *delim) {
}
*stringp = s;
- return(tok);
+ return (tok);
}
} while (sc != 0);
@@ -282,7 +286,7 @@ char *win32_strsep (char **stringp, const char *delim) {
}
#ifndef STLINK_HAVE_UNISTD_H
-int usleep(unsigned int waitTime) {
+int32_t usleep(uint32_t waitTime) {
if (waitTime >= 1000) {
/* Don't do long busy-waits.
* However much it seems like the QPC code would be more accurate,
@@ -297,7 +301,7 @@ int usleep(unsigned int waitTime) {
WaitForSingleObject(timer, INFINITE);
CloseHandle(timer);
- return(0);
+ return (0);
}
LARGE_INTEGER perf_cnt, start, now;
@@ -309,7 +313,7 @@ int usleep(unsigned int waitTime) {
QueryPerformanceCounter((LARGE_INTEGER*)&now);
} while ((now.QuadPart - start.QuadPart) / (float)perf_cnt.QuadPart * 1000 * 1000 < waitTime);
- return(0);
+ return (0);
}
#endif
diff --git a/src/win32/win32_socket.h b/src/win32/win32_socket.h
index 5f8f095..fb622f5 100644
--- a/src/win32/win32_socket.h
+++ b/src/win32/win32_socket.h
@@ -1,5 +1,7 @@
#if defined(_WIN32)
+#include <stdint.h>
+
#define _USE_W32_SOCKETS 1
#if defined(_MSC_VER)
@@ -20,7 +22,8 @@
#pragma warning(pop)
#endif
-/* winsock doesn't feature poll(), so there is a version implemented in terms of select() in win32_socket.c.
+/*
+ * winsock doesn't feature poll(), so there is a version implemented in terms of select() in win32_socket.c.
* The following definitions are copied from linux man pages.
* A poll() macro is defined to call the version in win32_socket.c.
*/
@@ -34,13 +37,14 @@
#define POLLNVAL 0x0020 /* Invalid request: fd not open */
struct pollfd {
SOCKET fd; /* file descriptor */
- short events; /* requested events */
- short revents; /* returned events */
+ int16_t events; /* requested events */
+ int16_t revents; /* returned events */
};
#endif
#define poll(x, y, z) win32_poll(x, y, z)
-/* These wrappers do nothing special except set the global errno variable if an error occurs
+/*
+ * These wrappers do nothing special except set the global errno variable if an error occurs
* (winsock doesn't do this by default).
* They set errno to unix-like values (i.e. WSAEWOULDBLOCK is mapped to EAGAIN),
* so code outside of this file "shouldn't" have to worry about winsock specific error handling.
@@ -52,15 +56,15 @@ struct pollfd {
#define read(x, y, z) win32_read_socket(x, y, z)
#define write(x, y, z) win32_write_socket(x, y, z)
-/* Winsock uses int instead of the usual socklen_t */
-typedef int socklen_t;
+/* Winsock uses int32_t instead of the usual socklen_t */
+typedef int32_t socklen_t;
-int win32_poll(struct pollfd *, unsigned int, int);
-SOCKET win32_socket(int, int, int);
-int win32_connect(SOCKET, struct sockaddr*, socklen_t);
+int32_t win32_poll(struct pollfd *, uint32_t, int32_t);
+SOCKET win32_socket(int32_t, int32_t, int32_t);
+int32_t win32_connect(SOCKET, struct sockaddr*, socklen_t);
SOCKET win32_accept(SOCKET, struct sockaddr*, socklen_t *);
-int win32_shutdown(SOCKET, int);
-int win32_close_socket(SOCKET fd);
+int32_t win32_shutdown(SOCKET, int32_t);
+int32_t win32_close_socket(SOCKET fd);
#define strtok_r(x, y, z) win32_strtok_r(x, y, z)
#define strsep(x,y) win32_strsep(x,y)
@@ -68,7 +72,7 @@ int win32_close_socket(SOCKET fd);
char *win32_strtok_r(char *s, const char *delim, char **lasts);
char *win32_strsep(char **stringp, const char *delim);
-ssize_t win32_read_socket(SOCKET fd, void *buf, int n);
-ssize_t win32_write_socket(SOCKET fd, void *buf, int n);
+ssize_t win32_read_socket(SOCKET fd, void *buf, int32_t n);
+ssize_t win32_write_socket(SOCKET fd, void *buf, int32_t n);
#endif // defined(_WIN32)