diff options
Diffstat (limited to 'src')
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, ¤t_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, ®p); @@ -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, ¤t_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) |