From 618a03a5dfe4a91d4174dba1b2bfcdcf75ae4d7d Mon Sep 17 00:00:00 2001 From: hydroconstructor Date: Sat, 29 Jan 2022 00:36:16 +0400 Subject: [PATCH 1/3] common c refactor Try to resolve conflicts with chipid_cleanup branch --- CHANGELOG.md | 18 +- CMakeLists.txt | 10 +- README.md | 2 +- cmake/modules/Findlibusb.cmake | 2 +- cmake/packaging/cpack_config.cmake | 2 +- cmake/packaging/deb/control | 2 +- contributors.txt | 3 - doc/compiling.md | 4 +- doc/version_support.md | 155 +- inc/stlink.h | 8 +- inc/stm32.h | 345 +- inc/stm32flash.h | 338 ++ src/calculate.c | 74 + src/calculate.h | 15 + src/common.c | 4380 +++-------------- src/common.h | 15 + src/common_flash.c | 1375 ++++++ src/common_flash.h | 27 + src/flashloader.c | 482 ++ src/map_file.c | 62 + src/map_file.h | 32 + src/option.c | 1027 ++++ src/read_write.c | 143 + src/stlink-lib/chipid.h | 5 +- src/stlink-lib/usb.c | 41 +- src/stlink-lib/usb.c.bak | 1410 ++++++ src/win32/unistd/unistd.h | 2 +- src/win32/unistd/unistd.h.bak | 76 + src/Описание.txt | 129 + stlinkv1_macos_driver/install.sh | 3 + .../Contents/Info.plist | 82 + .../Contents/MacOS/stlink_shield_10_14 | Bin 0 -> 33840 bytes .../stlink_shield_10_14.kext/Contents/PkgInfo | 1 + .../Contents/_CodeSignature/CodeResources | 115 + .../stlink_shield.xcodeproj/project.pbxproj | 50 + 35 files changed, 6171 insertions(+), 4264 deletions(-) create mode 100644 inc/stm32flash.h create mode 100644 src/calculate.c create mode 100644 src/calculate.h create mode 100644 src/common.h create mode 100644 src/common_flash.c create mode 100644 src/common_flash.h create mode 100644 src/flashloader.c create mode 100644 src/map_file.c create mode 100644 src/map_file.h create mode 100644 src/option.c create mode 100644 src/read_write.c create mode 100644 src/stlink-lib/usb.c.bak create mode 100644 src/win32/unistd/unistd.h.bak create mode 100644 src/Описание.txt create mode 100644 stlinkv1_macos_driver/stlink_shield_10_14.kext/Contents/Info.plist create mode 100644 stlinkv1_macos_driver/stlink_shield_10_14.kext/Contents/MacOS/stlink_shield_10_14 create mode 100644 stlinkv1_macos_driver/stlink_shield_10_14.kext/Contents/PkgInfo create mode 100644 stlinkv1_macos_driver/stlink_shield_10_14.kext/Contents/_CodeSignature/CodeResources diff --git a/CHANGELOG.md b/CHANGELOG.md index d744ff5..06f995d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,14 +2,10 @@ # v1.7.1 -Release date: 2022-xx-xx +Release date: 2021-xx-xx This release drops support for some older operating systems. Check project README for details. - -Updated system requirements: -- `cmake` >= 3.10.2 -- `libusb` >= 1.0.21 -- `libgtk-dev` >= 3.22.30 +Updated system requirements: Raised minimum version for `cmake` to 3.7.2. Features: @@ -19,9 +15,6 @@ Features: - Expanded and revised list of chips ([#1145](https://github.com/stlink-org/stlink/pull/1145), [#1164](https://github.com/stlink-org/stlink/pull/1164)) - [STM32H72X/3X]: Added full access to all device memory ([#1158](https://github.com/stlink-org/stlink/pull/1158), [#1159](https://github.com/stlink-org/stlink/pull/1159)) - Added support for STM32WLEx ([#1173](https://github.com/stlink-org/stlink/pull/1173)) -- Added support for STLINK-V3 devices with no MSD ([#1185](https://github.com/stlink-org/stlink/pull/1185)) -- Updated gdb-server.c to allow external memory access on STM32H73xx ([#1196](https://github.com/stlink-org/stlink/pull/1196), [#1197](https://github.com/stlink-org/stlink/pull/1197)) -- Erase addr size / section of the flash memory with st-flash ([#1213](https://github.com/stlink-org/stlink/pull/1213)) Updates & changes: @@ -29,12 +22,10 @@ Updates & changes: - Added instructions for bug-reports and feature-requests to contribution guidelines ([#906](https://github.com/stlink-org/stlink/pull/906)) - Added travis CI configuration for macOS 10.14 to maintain capability for 32-bit compilation ([#f5ada94](https://github.com/stlink-org/stlink/commit/f5ada9474cdb87ff37de0d4eb9e75622b5870646)) - Updated description of chip id 0x0457 to L01x/L02x ([#1143](https://github.com/stlink-org/stlink/pull/1143), [#1144](https://github.com/stlink-org/stlink/pull/1144)) -- Dropped execute bits from source code files ([#1167](https://github.com/stlink-org/stlink/pull/1167)) +- Drop execute bits from source code files ([#1167](https://github.com/stlink-org/stlink/pull/1167)) - Use proper Markdown headers for supported MCUs ([#1168](https://github.com/stlink-org/stlink/pull/1168)) - Removed redundant array ([#1178](https://github.com/stlink-org/stlink/pull/1178)) - Updated chip config files from the library structs ([#1181](https://github.com/stlink-org/stlink/pull/1181)) -- [doc] Corrected file path in tutorial ([#1186](https://github.com/stlink-org/stlink/pull/1186)) -- Improved chipid checks and printouts ([#1188](https://github.com/stlink-org/stlink/pull/1188)) Fixes: - cmake: Install shared libraries in proper directories ([#1142](https://github.com/stlink-org/stlink/pull/1142)) @@ -50,9 +41,6 @@ Fixes: - Fixed few warnings for msvc about type conversion with possible lost data ([#1179](https://github.com/stlink-org/stlink/pull/1179)) - st-flash and other utilities search for chip files in the wrong directory ([#1180](https://github.com/stlink-org/stlink/pull/1180), commit [#c8fc656](https://github.com/stlink-org/stlink/commit/c8fc6561fead79ad49c09d82bab864745086792c)) - Fixed broken build on 32 bit systems ([#985](https://github.com/stlink-org/stlink/pull/985), [#1175](https://github.com/stlink-org/stlink/pull/1175), commit [#c8fc656](https://github.com/stlink-org/stlink/commit/c8fc6561fead79ad49c09d82bab864745086792c)) -- Define 'SSIZE_MAX' if not defined ([#1183](https://github.com/stlink-org/stlink/pull/1183)) -- Fixed compliation for OpenBSD 7.0 ([#1202](https://github.com/stlink-org/stlink/pull/1202)) -- Included 'SSIZE_MAX' from 'limits.h' in 'src/common.c' ([#1207](https://github.com/stlink-org/stlink/pull/1207)) # v1.7.0 diff --git a/CMakeLists.txt b/CMakeLists.txt index 66bf34e..a3338df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ # General cmake settings ### -cmake_minimum_required(VERSION 3.10.2) +cmake_minimum_required(VERSION 3.7.2) cmake_policy(SET CMP0042 NEW) set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) @@ -110,6 +110,8 @@ add_subdirectory(inc) set(STLINK_HEADERS inc/backend.h inc/stlink.h + src/common_flash.h + src/calculate.h src/stlink-lib/commands.h src/stlink-lib/libusb_settings.h src/stlink-lib/reg.h @@ -123,7 +125,13 @@ set(STLINK_HEADERS ) set(STLINK_SOURCE + src/read_write.c src/common.c + src/option.c + src/common_flash.c + src/map_file.c + src/flashloader.c + src/calculate.c src/stlink-lib/chipid.c src/stlink-lib/flash_loader.c src/stlink-lib/logging.c diff --git a/README.md b/README.md index bc49118..7f797a7 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ It supports several so called STLINK programmer boards (and clones thereof) whic - stand-alone programmer (STLINK-V3SET, STLINK-V3MINI, STLINK-V3MODS) - on-board on some STM32 Nucleo boards (STLINK-V3E) -_\*)_ *Note: Support for the STLINK/V1 on macOS is limited to 10.15. Due to the deprecation and removal of macOS Kernel Extensions (KEXT) there will be no support for this programmer on macOS 11 or any later version.* +_\*)_ **Note: Support for the STLINK/V1 on macOS is limited to 10.14 - 10.15. Due to the deprecation and removal of macOS Kernel Extensions (KEXT) there will be no support for this programmer on macOS 11 or any later version.** On the user level there is no difference in handling or operation between these different revisions. diff --git a/cmake/modules/Findlibusb.cmake b/cmake/modules/Findlibusb.cmake index bc04f84..cd52026 100644 --- a/cmake/modules/Findlibusb.cmake +++ b/cmake/modules/Findlibusb.cmake @@ -72,7 +72,7 @@ elseif (WIN32 OR (EXISTS "/etc/debian_version" AND MINGW)) # Windows or MinGW-to if (WIN32 AND NOT EXISTS "/etc/debian_version") # Skip this for Debian... # Preparations for installing libusb library - set(LIBUSB_WIN_VERSION 1.0.24) # set libusb version + set(LIBUSB_WIN_VERSION 1.0.23) # set libusb version set(LIBUSB_WIN_ARCHIVE libusb-${LIBUSB_WIN_VERSION}.7z) if (WIN32 AND NOT EXISTS "/etc/debian_version") # ... on native Windows systems set(LIBUSB_WIN_ARCHIVE_PATH ${CMAKE_BINARY_DIR}/${LIBUSB_WIN_ARCHIVE}) diff --git a/cmake/packaging/cpack_config.cmake b/cmake/packaging/cpack_config.cmake index 587ff5f..acd5630 100644 --- a/cmake/packaging/cpack_config.cmake +++ b/cmake/packaging/cpack_config.cmake @@ -53,7 +53,7 @@ elseif (EXISTS "/etc/debian_version" AND NOT EXISTS WIN32) # Package-build is av set(CPACK_DEBIAN_PACKAGE_RELEASE "1") # CPACK_DEBIAN_PACKAGE_ARCHITECTURE --> Default: Output of dpkg --print-architecture - set(CPACK_DEBIAN_PACKAGE_DEPENDS "pkg-config, build-essential, debhelper (>=9), cmake (>= 3.10.2), libusb-1.0-0-dev (>= 1.0.21)") + set(CPACK_DEBIAN_PACKAGE_DEPENDS "pkg-config, build-essential, debhelper (>=9), cmake (>= 3.4.2), libusb-1.0-0-dev (>= 1.0.20)") set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Nightwalker-87 ") # CPACK_DEBIAN_PACKAGE_DESCRIPTION --> Default: CPACK_DEBIAN_PACKAGE_DESCRIPTION (as it is set) # CPACK_DEBIAN_PACKAGE_SECTION --> Default: “devel” diff --git a/cmake/packaging/deb/control b/cmake/packaging/deb/control index 7c8d13e..ef51a6c 100644 --- a/cmake/packaging/deb/control +++ b/cmake/packaging/deb/control @@ -1,7 +1,7 @@ Source: stlink Priority: optional Maintainer: Nightwalker-87 -Build-Depends: cmake (>= 3.10.2), dh-cmake, debhelper (>= 9), libusb-1.0-0-dev (>= 1.0.21), libgtk-3-dev (>= 3.22.30) +Build-Depends: cmake, dh-cmake, debhelper (>= 9), libusb-1.0-0-dev, libgtk-3-dev Standards-Version: 4.5.0 Rules-Requires-Root: no Section: electronics diff --git a/contributors.txt b/contributors.txt index cffef89..bcaa0b5 100644 --- a/contributors.txt +++ b/contributors.txt @@ -7,8 +7,6 @@ Andrea Mucignat Andrew Andrianov [necromant] Andrey Yurovsky Andy Isaacson -Andreas Sandberg [andysan] -Antoine Faure [antoinefaure] Anton [Ant-ON] Áron Radics A. Sheaff @@ -26,7 +24,6 @@ Chris Samuelson Christian Deussen [nullsub] Christophe Levantis Craig Lilley -Crest [Crest] Dan Dev Dan Hepler Daniel Campoverde [alx741] diff --git a/doc/compiling.md b/doc/compiling.md index 0931c27..eef207f 100644 --- a/doc/compiling.md +++ b/doc/compiling.md @@ -7,7 +7,7 @@ On Windows users should ensure that the following software is installed: - `git` (_optional, but recommended_) -- `cmake` +- `cmake` (3.17.0 or later) - `MinGW-w64` (7.0.0 or later) with GCC toolchain 8.1.0 ### Installation @@ -95,7 +95,7 @@ Install the following packages from your package repository: - `git` - `gcc` or `clang` or `mingw32-gcc` or `mingw64-gcc` (C-compiler; very likely gcc is already present) - `build-essential` (on Debian based distros (Debian, Ubuntu)) -- `cmake` +- `cmake` (3.4.2 or later, use the latest version available from the repository) - `rpm` (on Debian based distros (Debian, Ubuntu), needed for package build with `make package`) - `libusb-1.0` - `libusb-1.0-0-dev` (development headers for building) diff --git a/doc/version_support.md b/doc/version_support.md index d7ba5c1..2c5df74 100644 --- a/doc/version_support.md +++ b/doc/version_support.md @@ -1,104 +1,97 @@ -_Source:_ [pkgs.org](https://pkgs.org/search) - libusb, cmake, gtk, libgtk) (as of Jan 2022) +_Source:_ pkgs.org - [libusb](https://pkgs.org/search/?q=libusb); [cmake](https://pkgs.org/search/?q=cmake); [gtk](https://pkgs.org/search/?q=gtk) (as of May 2021) ## Supported Operating Systems ### Microsoft Windows -On Windows users should ensure that cmake **3.10.2** or any later version is installed.
-Up on compiling c-make will **automatically** download and install the latest compatible version of `libusb`. +On Windows users should ensure that cmake 3.20.2 or any later version is installed.
+Up on compiling c-make will **automatically** download and install the latest compatible version of `libusb` (1.0.23 at the time of writing). - Windows 10 - Windows 8.1 ### Apple macOS -| Package Repository | libusb | cmake | gtk-3-dev | Supported macOS versions | -| ------------------ | ------ | ------ | ------------------ | ------------------------ | -| homebrew | 1.0.24 | 3.22.1 | 3.24.30
gtk+3 | **10.10 - 12.x** | -| MacPorts | 1.0.24 | 3.22.1 | 3.24.31
gtk3 | **10.4 - 12.x** | +| Package Repository | libusb
version | cmake
version | gtk-3
version | Supported macOS versions | +| ------------------ | ------------------- | ------------------ | ------------------ | ------------------------ | +| homebrew | 1.0.24 | 3.20.2 | 3.24.29
gtk+3 | 10.9 - 11.x | +| MacPorts | 1.0.24 | 3.20.2 | 3.24.29
gtk3 | 10.4 - 11.x | -NOTE: In order to use a STLINK/V1 programmer on macOS, version 10.15 is required. +NOTE: In order to use a STLINK/V1 programmer on macOS, versions 10.14 or 10.15 are required. ### Linux-/Unix-based: -| Operating System | libusb | cmake | libgtk-dev | Notes | -| ------------------------- | ------------------------------ | ---------- | ----------- | ------------------------ | -| Debian Sid | 1.0.24 | 3.22.1 | 3.24.31 | | -| Debian 11 (Bullseye) | 1.0.24 | 3.18.4 | 3.24.24 | | -| Debian 10 (Buster) | 1.0.**22** | **3.13.4** | 3.24.**5** | | -| | | | | | -| Ubuntu 20.04 LTS (Focal) | 1.0.23 | 3.16.3 | 3.24.**18** | | -| Ubuntu 18.04 LTS (Bionic) | 1.0.**21** | **3.10.2** | 3.**22.30** | End of Support: Apr 2023 | -| | | | | | -| Fedora Rawhide [x64] | 1.0.24 | 3.22.3 | 3.24.31 | | -| Fedora 35 [x64] | 1.0.24 | 3.21.3 | 3.24.30 | | -| Fedora 34 [x64] | 1.0.24 (`libusbx`) | 3.19.7 | 3.24.28 | | -| | | | | | -| openSUSE Tumbleweed [x64] | 1.0.24 | 3.22.1 | 3.24.31 | | -| openSUSE Leap 15.3 [x64] | 1.0.**21** | 3.17.0 | 3.24.20 | End of Support: Dec 2022 | -| | | | | | -| Alpine 3.15 | 1.0.24 | 3.21.3 | 3.24.30 | | -| Alpine 3.14 | 1.0.24 | 3.20.3 | 3.24.28 | | -| Alpine 3.13 | 1.0.24 | 3.18.4 | 3.24.23 | End of Support: Nov 2022 | -| Alpine 3.12 | 1.0.23 | 3.17.2 | 3.24.22 | End of Support: May 2022 | -| | | | | | -| FreeBSD 13.x | 1.0.**16-18** (API 0x01000102) | 3.22.1 | 3.24.31 | | -| FreeBSD 12.x | 1.0.**16-18** (API 0x01000102) | 3.22.1 | 3.24.31 | | -| | | | | | -| NetBSD 9.x | 1.0.24 | 3.21.2 | 3.24.30 | | -| NetBSD 8.x | 1.0.24 | 3.19.7 | 3.24.27 | | -| | | | | | -| CentOS 9 Stream [x64] | 1.0.24 (`libusbx`) | 3.20.3 | 3.24.30 | | -| CentOS 8 Stream [x64] | 1.0.23 (`libusbx`) | 3.20.2 | 3.**22.30** | | -| | | | | | -| ALT Linux Sisyphus | 1.0.24 | 3.22.1 | 3.24.31 | | -| ALT Linux P10 | 1.0.24 | 3.20.5 | 3.24.31 | | -| ALT Linux P9 | 1.0.**22** | 3.16.3 | 3.24.29 | | -| | | | | | -| OpenMandriva Rolling | 1.0.24 | 3.22.1 | 3.24.31 | | -| OpenMandriva Cooker | 1.0.24 | 3.22.1 | 3.24.31 | | -| OpenMandriva Lx 4.2 | 1.0.24 | 3.19.3 | 3.24.24 | | -| | | | | | -| Arch Linux | 1.0.24 | 3.22.1 | - | | -| KaOS [x64] | 1.0.24 | 3.22.1 | 3.24.31 | | -| Mageia Cauldron | 1.0.24 | 3.22.1 | 3.24.31 | | -| PCLinuxOS [x64] | ? | 3.22.1 | 3.24.31 | | -| Solus [x64] | 1.0.24 | 3.22.1 | 3.24.30 | | -| Void Linux | 1.0.24 | 3.22.1 | 3.24.31 | | -| Slackware Current | 1.0.24 | 3.21.4 | 3.24.31 | | -| AlmaLinux 8 | 1.0.23 (`libusbx`) | 3.20.2 | 3.**22.30** | | -| Rocky Linux 8 [x64] | 1.0.23 | 3.20.2 | 3.**22.30** | | -| Mageia 8 | 1.0.24 | 3.19.2 | 3.24.24 | End of Support: Aug 2022 | -| Adélie 1.0 | 1.0.23 | 3.16.4 | 3.24.23 | | +| Operating System | libusb | cmake | gtk-3 | Notes | +| ------------------------- | -------------------------------- | --------- | ----------- | ------------------------ | +| Debian Sid | 1.0.24 | 3.18.4 | 3.24.24 | | +| Debian 11 (Bullseye) | 1.0.24 | 3.18.4 | 3.24.24 | | +| Debian 10 (Buster) | 1.0.**22** | 3.13.4 | 3.24.**5** | | +| Debian 9 (Stretch) | 1.0.**21** | **3.7.2** | **3.22.11** | End of Support: Jun 2022 | +| | | | | | +| Ubuntu 21.04 (Hirsute) | 1.0.24 | 3.18.4 | 3.24.25 | End of Support: Jan 2022 | +| Ubuntu 20.04 LTS (Focal) | 1.0.23 | 3.16.3 | 3.24.**18** | | +| Ubuntu 18.04 LTS (Bionic) | 1.0.**21** | 3.10.2 | **3.22.30** | End of Support: Apr 2023 | +| | | | | | +| Fedora Rawhide [x64] | 1.0.24 (`libusbx`) | 3.20.2 | 3.24.29 | | +| Fedora 34 [x64] | 1.0.24 (`libusbx`) | 3.19.7 | 3.24.28 | | +| Fedora 33 [x64] | 1.0.23 (`libusbx`) | 3.18.3 | 3.24.23 | | +| | | | | | +| openSUSE Tumbleweed [x64] | 1.0.24 | 3.20.1 | 3.24.29 | | +| openSUSE Leap 15.3 [x64] | 1.0.**21** | 3.17.0 | 3.24.20 | | +| openSUSE Leap 15.2 [x64] | 1.0.**21** | 3.17.0 | 3.24.**14** | End of Support: Dec 2021 | +| | | | | | +| Alpine 3.14 | 1.0.24 | 3.20.3 | 4.2.1 | | +| Alpine 3.13 | 1.0.24 | 3.18.4 | 3.24.23 | End of Support: Nov 2022 | +| Alpine 3.12 | 1.0.23 | 3.17.2 | 3.24.22 | End of Support: May 2022 | +| Alpine 3.11 | 1.0.23 | 3.15.5 | 3.24.**13** | End of Support: Nov 2021 | +| | | | | | +| FreeBSD 13.x | 1.0.**16 - 18** (API 0x01000102) | 3.20.2 | 3.24.27 | | +| FreeBSD 12.x | 1.0.**16 - 18** (API 0x01000102) | 3.19.6 | 3.24.27 | | +| FreeBSD 11.x | 1.0.**16 - 18** (API 0x01000102) | 3.15.5 | 3.24.27 | End of Support: Sep 2021 | +| | | | | | +| Arch Linux | 1.0.24 | 3.20.2 | 3.24.29 | | +| KaOS [x64] | 1.0.24 | 3.20.2 | 3.24.29 | | +| Mageia Cauldron | 1.0.24 | 3.20.2 | 3.24.29 | | +| OpenMandriva Cooker | 1.0.24 | 3.20.2 | 3.24.29 | | +| PCLinuxOS [x64] | 1.0.24 | 3.20.2 | 3.24.29 | | +| Slackware Current | 1.0.24 | 3.20.2 | 3.24.28 | | +| Solus [x64] | 1.0.24 | 3.20.2 | 3.24.29 | | +| ALT Linux Sisyphus | 1.0.24 | 3.19.7 | 3.24.29 | | +| NetBSD 9.x | 1.0.24 | 3.19.7 | 3.24.27 | | +| NetBSD 8.x | 1.0.24 | 3.19.7 | 3.24.27 | | +| OpenMandriva Lx 4.2 | 1.0.24 | 3.19.3 | 3.24.24 | | +| Mageia 8 | 1.0.24 | 3.19.2 | 3.24.24 | End of Support: Aug 2022 | +| CentOS 8 Stream [x64] | 1.0.23 (`libusbx`) | 3.18.2 | **3.22.30** | | +| Adélie 1.0 | 1.0.23 | 3.16.4 | 3.24.23 | | +| ALT Linux P9 | 1.0.**22** | 3.16.3 | 3.24.**11** | | +| AlmaLinux 8 | 1.0.23 (`libusbx`) | 3.11.4 | 3.24.32 | | +| CentOS 8 [x64] | 1.0.23 (`libusbx`) | 3.11.4 | **3.22.30** | End of Support: Dec 2021 | ## Unsupported Operating Systems (as of Release v1.7.1) Systems with highlighted versions remain compatible with this toolset. -| Operating System | libusb | cmake | End of
OS-Support | -| ------------------------ | ------------------------------ | ---------- | ---------------------- | -| CentOS 8 [x64] | 1.0.**23** (`libusbx`) | 3.**20.3** | Dec 2021 | -| Ubuntu 21.04 (Hirsute) | 1.0.**24** | 3.**18.4** | Jan 2022 | -| Fedora 33 [x64] | 1.0.**23** (`libusbx`) | 3.**18.3** | Nov 2021 | -| Fedora 32 [x64] | 1.0.**23** (`libusbx`) | 3.**17.0** | May 2021 | -| openSUSE Leap 15.2 [x64] | 1.0.**21** | 3.**17.0** | Dec 2021 | -| Ubuntu 20.10 (Groovy) | 1.0.**23** | 3.**16.3** | Jul 2021 | -| NetBSD 7.x | 1.0.**22** | 3.**16.1** | Jun 2020 | -| Alpine 3.11 | 1.0.**23** | 3.**15.5** | Nov 2021 | -| FreeBSD 11.x | 1.0.**16-18** (API 0x01000102) | 3.**15.5** | Sep 2021 | -| Alpine 3.10 | 1.0.**22** | 3.**14.5** | May 2021 | -| Fedora 31 [x64] | 1.0.**22**(`libusbx`) | 3.**14.5** | Nov 2020 | -| Mageia 7.1 | 1.0.**22** | 3.**14.3** | Jun 2021 | -| Fedora 30 | 1.0.**22**(`libusbx`) | 3.**14.2** | May 2020 | -| Ubuntu 19.10 (Eoan) | 1.0.**23** | 3.**13.4** | Jul 2020 | -| Alpine 3.9 | 1.0.**22** | 3.**13.0** | Jan 2021 | -| openSUSE Leap 15.1 [x64] | 1.0.**21** | 3.**10.2** | Jan 2021 | -| Debian 9 (Stretch) | 1.0.**21** | 3.7.2 | Jun 2022 | -| Slackware 14.2 | 1.0.20 | 3.5.2 | | -| OpenMandriva Lx 3.0x | 1.0.20 | 3.4.2 | | -| CentOS 7 [x64] | 1.0.**21** (`libusbx`) | 2.8.12.2 | Jun 2024 | -| Slackware 14.1 | 1.0.9 | 2.8.12 | | -| Slackware 14.0 | 1.0.9 | 2.8.8 | | +| Operating System | libusb | cmake | End of
OS-Support | +| ------------------------- | ---------------------- | ---------- | ---------------------- | +| Fedora 32 [x64] | **1.0.23** (`libusbx`) | **3.17.0** | May 2021 | +| Ubuntu 20.10 (Groovy) | **1.0.23** | **3.16.3** | Jul 2021 | +| NetBSD 7.x | **1.0.22** | **3.16.1** | Jun 2020 | +| Alpine 3.10 | **1.0.22** | **3.14.5** | May 2021 | +| Fedora 31 [x64] | **1.0.22** (`libusbx`) | **3.14.5** | Nov 2020 | +| Mageia 7.1 | **1.0.22** | **3.14.3** | Jun 2021 | +| Fedora 30 | **1.0.22** (`libusbx`) | **3.14.2** | May 2020 | +| Ubuntu 19.10 (Eoan) | **1.0.23** | **3.13.4** | Jul 2020 | +| Alpine 3.9 | **1.0.22** | **3.13.0** | Jan 2021 | +| openSUSE Leap 15.1 [x64] | **1.0.21** | **3.10.2** | Jan 2021 | +| Slackware 14.2 | 1.0.20 | 3.5.2 | | +| Ubuntu 16.04 LTS (Xenial) | 1.0.20 | 3.5.1 | Apr 2021 | +| OpenMandriva Lx 3.0x | 1.0.20 | 3.4.2 | | +| Debian 8 (Jessie) | 1.0.19 | 3.0.2 | Jun 2020 | +| CentOS 7 [x64] | 1.0.21 (`libusbx`) | 2.8.12.2 | Jun 2024 | +| Ubuntu 14.04 LTS (Trusty) | 1.0.17 | 2.8.12.2 | Apr 2019 | +| CentOS 6 | 1.0.9 (`libusbx`) | 2.8.12.2 | Nov 2020 | +| Slackware 14.1 | 1.0.9 | 2.8.12 | | +| Slackware 14.0 | 1.0.9 | 2.8.8 | | _All other operating systems which are not listed are unsupported._ diff --git a/inc/stlink.h b/inc/stlink.h index 2d0fa50..e3fd632 100644 --- a/inc/stlink.h +++ b/inc/stlink.h @@ -1,6 +1,5 @@ /* * File: stlink.h - * * This should contain all the common top level stlink interfaces, * regardless of how the backend does the work.... */ @@ -13,6 +12,7 @@ #include #include "stm32.h" +#include "stm32flash.h" #ifdef __cplusplus extern "C" { @@ -183,7 +183,7 @@ enum run_type { typedef struct _stlink stlink_t; -#include +#include // Is it really need? #include struct _stlink { @@ -274,7 +274,7 @@ int stlink_mwrite_sram(stlink_t *sl, uint8_t* data, uint32_t length, stm32_addr_ int stlink_fwrite_sram(stlink_t *sl, const char* path, stm32_addr_t addr); int stlink_verify_write_flash(stlink_t *sl, stm32_addr_t address, uint8_t *data, uint32_t length); -int stlink_chip_id(stlink_t *sl, uint32_t *chip_id); +//int stlink_chip_id(stlink_t *sl, uint32_t *chip_id); int stlink_cpu_id(stlink_t *sl, cortex_m3_cpuid_t *cpuid); int stlink_erase_flash_page(stlink_t* sl, stm32_addr_t flashaddr); @@ -282,7 +282,7 @@ uint32_t stlink_calculate_pagesize(stlink_t *sl, uint32_t flashaddr); int stlink_check_address_range_validity(stlink_t *sl, stm32_addr_t addr, size_t size); int stlink_check_address_alignment(stlink_t *sl, stm32_addr_t addr); uint16_t read_uint16(const unsigned char *c, const int pt); -void stlink_core_stat(stlink_t *sl); +//void stlink_core_stat(stlink_t *sl); void stlink_print_data(stlink_t *sl); unsigned int is_bigendian(void); uint32_t read_uint32(const unsigned char *c, const int pt); diff --git a/inc/stm32.h b/inc/stm32.h index d6bbe50..19ba3fc 100644 --- a/inc/stm32.h +++ b/inc/stm32.h @@ -149,345 +149,11 @@ enum stm32_chipids { /* ============ */ /* Constant STM32 memory address */ -#define STM32_SRAM_BASE ((uint32_t)0x20000000) -#define STM32_FLASH_BASE ((uint32_t)0x08000000) +#define STM32_SRAM_BASE ((uint32_t)0x20000000) +#define STM32_FLASH_BASE ((uint32_t)0x08000000) -#define STM32_F1_FLASH_BANK2_BASE ((uint32_t)0x08080000) -#define STM32_H7_FLASH_BANK2_BASE ((uint32_t)0x08100000) - -/* stm32f FPEC flash controller interface, pm0063 manual */ -// 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_OPTER 5 -#define FLASH_CR_STRT 6 -#define FLASH_CR_LOCK 7 -#define FLASH_CR_OPTWRE 9 -#define FLASH_CR_OBL_LAUNCH 13 - -#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 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 == STM32_CHIPID_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 STM32_F1_FLASH_BANK2_BASE ((uint32_t)0x08080000) +#define STM32_H7_FLASH_BANK2_BASE ((uint32_t)0x08100000) #define STM32F0_DBGMCU_CR 0xE0042004 #define STM32F0_DBGMCU_CR_IWDG_STOP 8 @@ -529,7 +195,4 @@ enum stm32_chipids { #define STM32WB_RCC_AHB1ENR 0x58000048 #define STM32WB_RCC_DMAEN 0x00000003 // DMA2EN | DMA1EN -#define L1_WRITE_BLOCK_SIZE 0x80 -#define L0_WRITE_BLOCK_SIZE 0x40 - #endif // STM32_H diff --git a/inc/stm32flash.h b/inc/stm32flash.h new file mode 100644 index 0000000..c28d67c --- /dev/null +++ b/inc/stm32flash.h @@ -0,0 +1,338 @@ +#ifndef STM32FLASH_H +#define STM32FLASH_H + +/* stm32f FPEC flash controller interface, pm0063 manual */ +// 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_OPTER 5 +#define FLASH_CR_STRT 6 +#define FLASH_CR_LOCK 7 +#define FLASH_CR_OPTWRE 9 +#define FLASH_CR_OBL_LAUNCH 13 + +#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 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 == STM32_CHIPID_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) + +#endif // STM32FLASH_H diff --git a/src/calculate.c b/src/calculate.c new file mode 100644 index 0000000..ed3b658 --- /dev/null +++ b/src/calculate.c @@ -0,0 +1,74 @@ +#include +#include "calculate.h" +#include "common_flash.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, + 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 == STM32_CHIPID_L4 || + sl->chip_id == STM32_CHIPID_L496x_L4A6x || + sl->chip_id == STM32_CHIPID_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); +} diff --git a/src/calculate.h b/src/calculate.h new file mode 100644 index 0000000..68c1fb9 --- /dev/null +++ b/src/calculate.h @@ -0,0 +1,15 @@ +/* + * File: calculate.h + * + * TODO: add a description + */ + +#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, unsigned); +uint32_t calculate_L4_page(stlink_t *, uint32_t); + +#endif // CALCULATE_H diff --git a/src/common.c b/src/common.c index 266722b..97f41a5 100644 --- a/src/common.c +++ b/src/common.c @@ -1,1058 +1,52 @@ -#define DEBUG_FLASH 0 -#include -#include -#include -#include -#include - -#include +#include #include -#include #include #include #include - -#include -#include +#include #include -#include #include - -#ifdef STLINK_HAVE_SYS_MMAN_H -#include -#else -#include -#endif - -#ifndef O_BINARY -#define O_BINARY 0 -#endif +#include +#include +#include +#include "common_flash.h" +#include "calculate.h" +#include "map_file.h" +#include "common.h" #ifdef _MSC_VER #define __attribute__(x) #endif -#define BANK_1 0 -#define BANK_2 1 - - - -// 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] = (uint8_t)ui; - buf[1] = (uint8_t)(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 STM32_CHIPID_L0: - case STM32_CHIPID_L0_CAT5: - case STM32_CHIPID_L0_CAT2: - case STM32_CHIPID_L011: - return (STM32L0_FLASH_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: - return (STM32L_FLASH_REGS_ADDR); - - default: - WLOG("Flash base use default L0 address\n"); - 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 == 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_L4_L4P) { - reg = STM32L4_FLASH_CR; - } else if (sl->flash_type == STM32_FLASH_TYPE_G0 || - sl->flash_type == STM32_FLASH_TYPE_G4) { - reg = STM32Gx_FLASH_CR; - } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { - reg = STM32WB_FLASH_CR; - } else if (sl->flash_type == STM32_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 == 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_L0_L1) { - cr_reg = get_stm32l0_flash_base(sl) + FLASH_PECR_OFF; - cr_lock_shift = STM32L0_FLASH_PELOCK; - } else if (sl->flash_type == STM32_FLASH_TYPE_L4_L4P) { - cr_reg = STM32L4_FLASH_CR; - cr_lock_shift = STM32L4_FLASH_CR_LOCK; - } else if (sl->flash_type == STM32_FLASH_TYPE_G0 || - sl->flash_type == STM32_FLASH_TYPE_G4) { - cr_reg = STM32Gx_FLASH_CR; - cr_lock_shift = STM32Gx_FLASH_CR_LOCK; - } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { - cr_reg = STM32WB_FLASH_CR; - cr_lock_shift = STM32WB_FLASH_CR_LOCK; - } else if (sl->flash_type == STM32_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 == 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_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_L4P) { - key_reg = STM32L4_FLASH_KEYR; - } else if (sl->flash_type == STM32_FLASH_TYPE_G0 || - sl->flash_type == STM32_FLASH_TYPE_G4) { - key_reg = STM32Gx_FLASH_KEYR; - } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { - key_reg = STM32WB_FLASH_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 { - 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 == 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_L0_L1) { - cr_reg = get_stm32l0_flash_base(sl) + FLASH_PECR_OFF; - cr_lock_shift = STM32L0_FLASH_PELOCK; - } else if (sl->flash_type == STM32_FLASH_TYPE_L4_L4P) { - cr_reg = STM32L4_FLASH_CR; - cr_lock_shift = STM32L4_FLASH_CR_LOCK; - } else if (sl->flash_type == STM32_FLASH_TYPE_G0 || - sl->flash_type == STM32_FLASH_TYPE_G4) { - cr_reg = STM32Gx_FLASH_CR; - cr_lock_shift = STM32Gx_FLASH_CR_LOCK; - } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { - cr_reg = STM32WB_FLASH_CR; - cr_lock_shift = STM32WB_FLASH_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 { - 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 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_L0_L1: - optcr_reg = get_stm32l0_flash_base(sl) + FLASH_PECR_OFF; - optlock_shift = STM32L0_FLASH_OPTLOCK; - break; - case STM32_FLASH_TYPE_L4_L4P: - optcr_reg = STM32L4_FLASH_CR; - optlock_shift = STM32L4_FLASH_CR_OPTLOCK; - break; - case STM32_FLASH_TYPE_G0: - case STM32_FLASH_TYPE_G4: - optcr_reg = STM32Gx_FLASH_CR; - optlock_shift = STM32Gx_FLASH_CR_OPTLOCK; - break; - case STM32_FLASH_TYPE_WB_WL: - optcr_reg = STM32WB_FLASH_CR; - optlock_shift = STM32WB_FLASH_CR_OPTLOCK; - break; - case STM32_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 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_L0_L1: - optcr_reg = get_stm32l0_flash_base(sl) + FLASH_PECR_OFF; - optlock_shift = STM32L0_FLASH_OPTLOCK; - break; - case STM32_FLASH_TYPE_L4_L4P: - optcr_reg = STM32L4_FLASH_CR; - optlock_shift = STM32L4_FLASH_CR_OPTLOCK; - break; - case STM32_FLASH_TYPE_G0: - case STM32_FLASH_TYPE_G4: - optcr_reg = STM32Gx_FLASH_CR; - optlock_shift = STM32Gx_FLASH_CR_OPTLOCK; - break; - case STM32_FLASH_TYPE_WB_WL: - optcr_reg = STM32WB_FLASH_CR; - optlock_shift = STM32WB_FLASH_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; - 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 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_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_L4P: - optkey_reg = STM32L4_FLASH_OPTKEYR; - break; - case STM32_FLASH_TYPE_G0: - case STM32_FLASH_TYPE_G4: - optkey_reg = STM32Gx_FLASH_OPTKEYR; - break; - case STM32_FLASH_TYPE_WB_WL: - optkey_reg = STM32WB_FLASH_OPT_KEYR; - 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; - 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 == 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_L4P) { - cr_reg = STM32L4_FLASH_CR; - x &= ~STM32L4_FLASH_CR_OPBITS; - x |= (1 << STM32L4_FLASH_CR_PG); - } else if (sl->flash_type == STM32_FLASH_TYPE_G0 || - sl->flash_type == STM32_FLASH_TYPE_G4) { - cr_reg = STM32Gx_FLASH_CR; - x |= (1 << FLASH_CR_PG); - } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { - cr_reg = STM32WB_FLASH_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 = 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 == 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_L4_L4P) { - cr_reg = STM32L4_FLASH_CR; - } else if (sl->flash_type == STM32_FLASH_TYPE_G0 || - sl->flash_type == STM32_FLASH_TYPE_G4) { - cr_reg = STM32Gx_FLASH_CR; - } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { - cr_reg = STM32WB_FLASH_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 { - 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 == STM32_FLASH_TYPE_G0 || - sl->flash_type == STM32_FLASH_TYPE_G4) { - cr_reg = STM32Gx_FLASH_CR; - } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { - 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 == STM32_FLASH_TYPE_G0 || - sl->flash_type == STM32_FLASH_TYPE_G4) { - cr_reg = STM32Gx_FLASH_CR; - } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { - 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 == 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_L4_L4P) { - 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 == STM32_FLASH_TYPE_G0 || - sl->flash_type == STM32_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 == STM32_FLASH_TYPE_WB_WL) { - cr_reg = STM32WB_FLASH_CR; - cr_mer = (1 << FLASH_CR_MER); - 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 { - 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 == 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_L4_L4P) { - cr_reg = STM32L4_FLASH_CR; - cr_strt = (1 << STM32L4_FLASH_CR_STRT); - } else if (sl->flash_type == STM32_FLASH_TYPE_G0 || - sl->flash_type == STM32_FLASH_TYPE_G4) { - cr_reg = STM32Gx_FLASH_CR; - cr_strt = (1 << STM32Gx_FLASH_CR_STRT); - } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { - cr_reg = STM32WB_FLASH_CR; - cr_strt = (1 << STM32WB_FLASH_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 { - 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 == 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_L0_L1) { - sr_reg = get_stm32l0_flash_base(sl) + FLASH_SR_OFF; - } 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_L4_L4P) { - sr_reg = STM32L4_FLASH_SR; - } else if (sl->flash_type == STM32_FLASH_TYPE_G0 || - sl->flash_type == STM32_FLASH_TYPE_G4) { - sr_reg = STM32Gx_FLASH_SR; - } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { - sr_reg = STM32WB_FLASH_SR; - } else if (sl->flash_type == STM32_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 == 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_L0_L1) { - sr_reg = get_stm32l0_flash_base(sl) + FLASH_SR_OFF; - } 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_L4_L4P) { - sr_reg = STM32L4_FLASH_SR; - } else if (sl->flash_type == STM32_FLASH_TYPE_G0 || - sl->flash_type == STM32_FLASH_TYPE_G4) { - sr_reg = STM32Gx_FLASH_SR; - } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { - sr_reg = STM32WB_FLASH_SR; - } else if (sl->flash_type == STM32_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 == 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_L4_L4P) { - sr_busy_shift = STM32L4_FLASH_SR_BSY; - } else if (sl->flash_type == STM32_FLASH_TYPE_G0 || - sl->flash_type == STM32_FLASH_TYPE_G4) { - sr_busy_shift = STM32Gx_FLASH_SR_BSY; - } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { - sr_busy_shift = STM32WB_FLASH_SR_BSY; - } else if (sl->flash_type == STM32_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 == 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); -} - -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 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, STM32Gx_FLASH_SR_ERROR_MASK); - break; - case STM32_FLASH_TYPE_L0_L1: - write_flash_sr(sl, BANK_1, STM32L0_FLASH_SR_ERROR_MASK); - break; - case STM32_FLASH_TYPE_L4_L4P: - write_flash_sr(sl, BANK_1, STM32L4_FLASH_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_WB_WL: - 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 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) & 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 STM32_FLASH_TYPE_L0_L1: - 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 STM32_FLASH_TYPE_L4_L4P: - 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 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_WB_WL: - 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 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_L4P: - 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: - 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); - } -} - -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 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_L4P: - rcc = STM32G4_RCC_AHB1ENR; - rcc_dma_mask = STM32G4_RCC_DMAEN; - break; - case STM32_FLASH_TYPE_L0_L1: - rcc = STM32L0_RCC_AHBENR; - rcc_dma_mask = STM32L0_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); - } -} - -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 == 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); -} - -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 == 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 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... - +// Private structs and functions defines +struct stlink_fread_worker_arg { + int 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 *); +int stlink_jtag_reset(stlink_t *, int); +int stlink_soft_reset(stlink_t *, int); +void _parse_version(stlink_t *, stlink_version_t *); +static uint8_t stlink_parse_hex(const char *); +static int stlink_read(stlink_t *, stm32_addr_t, size_t, save_block_fn, void *); +static bool stlink_fread_ihex_init(struct stlink_fread_ihex_worker_arg *, int, 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"); @@ -1063,7 +57,7 @@ void stlink_close(stlink_t *sl) { sl->backend->close(sl); free(sl); } - +// 250 int stlink_exit_debug_mode(stlink_t *sl) { DLOG("*** stlink_exit_debug_mode ***\n"); @@ -1075,12 +69,12 @@ int stlink_exit_debug_mode(stlink_t *sl) { return (sl->backend->exit_debug_mode(sl)); } - +//248 int 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. int stlink_force_debug(stlink_t *sl) { DLOG("*** stlink_force_debug_mode ***\n"); @@ -1092,12 +86,12 @@ int stlink_force_debug(stlink_t *sl) { stop_wdg_in_debug(sl); return (0); } - +// 251 int stlink_exit_dfu_mode(stlink_t *sl) { DLOG("*** stlink_exit_dfu_mode ***\n"); return (sl->backend->exit_dfu_mode(sl)); } - +// 253 int stlink_core_id(stlink_t *sl) { int ret; @@ -1203,186 +197,107 @@ int stlink_cpu_id(stlink_t *sl, cortex_m3_cpuid_t *cpuid) { 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. */ -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; + 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); - } + if (stlink_chip_id(sl, &sl->chip_id)) { + return (-1); + } - params = stlink_chipid_get_params(sl->chip_id); + params = stlink_chipid_get_params(sl->chip_id); - if (params == NULL) { - WLOG("unknown chip id! %#x\n", sl->chip_id); - return (-1); - } + 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); - } + 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); + // 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; - } + if (params->flash_size_reg & 2) { + flash_size = flash_size >> 16; + } - flash_size = flash_size & 0xffff; + 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; - } + 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->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 == STM32_CHIPID_F1_VL_MD_LD && - sl->flash_size < 64 * 1024) { - sl->sram_size = 0x1000; - } + // 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) { - uint32_t flash_optr; - stlink_read_debug32(sl, STM32Gx_FLASH_OPTR, &flash_optr); + if (sl->chip_id == STM32_CHIPID_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; - } - } + 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 == STM32_FLASH_TYPE_H7) { - if ((sl->flash_size / sl->flash_pgsz) <= 1) - sl->chip_flags &= ~CHIP_F_HAS_DUAL_BANK; - } + // 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, (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"); + ILOG("%s: %u KiB SRAM, %u KiB flash in at least %u %s pages.\n", + params->dev_type, (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 %d ***\n", value); - 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); -} + return (0); + } int stlink_reset(stlink_t *sl, enum reset_type type) { uint32_t dhcsr; @@ -1444,7 +359,7 @@ int stlink_reset(stlink_t *sl, enum reset_type type) { return (0); } - +// 255 int stlink_run(stlink_t *sl, enum run_type type) { struct stlink_reg rr; DLOG("*** stlink_run ***\n"); @@ -1460,12 +375,33 @@ int stlink_run(stlink_t *sl, enum run_type type) { return (sl->backend->run(sl, type)); } - +// 273 int stlink_set_swdclk(stlink_t *sl, int 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 int stlink_status(stlink_t *sl) { int ret; @@ -1474,69 +410,7 @@ int stlink_status(stlink_t *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; -} - +// 257 int stlink_version(stlink_t *sl) { DLOG("*** looking up stlink version\n"); @@ -1559,7 +433,7 @@ int stlink_version(stlink_t *sl) { return (0); } - +// 272 int stlink_target_voltage(stlink_t *sl) { int voltage = -1; DLOG("*** reading target voltage\n"); @@ -1578,132 +452,17 @@ int stlink_target_voltage(stlink_t *sl) { 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"); - 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)); -} - +// 299 bool stlink_is_core_halted(stlink_t *sl) { stlink_status(sl); return (sl->core_stat == TARGET_HALTED); } - +// 269 int stlink_step(stlink_t *sl) { DLOG("*** stlink_step ***\n"); return (sl->backend->step(sl)); } - +// 270 int stlink_current_mode(stlink_t *sl) { int mode = sl->backend->current_mode(sl); @@ -1722,55 +481,21 @@ int stlink_current_mode(stlink_t *sl) { DLOG("stlink mode: unknown!\n"); return (STLINK_DEV_UNKNOWN_MODE); } - +// 274 int stlink_trace_enable(stlink_t *sl, uint32_t frequency) { DLOG("*** stlink_trace_enable ***\n"); return (sl->backend->trace_enable(sl, frequency)); } - +// 275 int stlink_trace_disable(stlink_t *sl) { DLOG("*** stlink_trace_disable ***\n"); return (sl->backend->trace_disable(sl)); } - +// 276 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"); - } -} - +// 294 void stlink_print_data(stlink_t *sl) { if (sl->q_len <= 0 || sl->verbose < UDEBUG) { return; @@ -1796,134 +521,7 @@ void stlink_print_data(stlink_t *sl) { // 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)SSIZE_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 = (size_t)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, (uint16_t)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 PC to the reset routine - stlink_read_debug32(sl, addr + 4, &val); - stlink_write_reg(sl, val, 15); - stlink_run(sl, RUN_NORMAL); -} - +// 283 int stlink_mwrite_sram(stlink_t *sl, uint8_t *data, uint32_t length, stm32_addr_t addr) { // write the file in sram at addr @@ -1981,7 +579,7 @@ int stlink_mwrite_sram(stlink_t *sl, uint8_t *data, uint32_t length, on_error: return (error); } - +//284 int stlink_fwrite_sram(stlink_t *sl, const char *path, stm32_addr_t addr) { // write the file in sram at addr @@ -2055,174 +653,7 @@ 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, (uint16_t)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)); -} - +// 302 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 @@ -2256,7 +687,7 @@ int stlink_fread(stlink_t *sl, const char *path, bool is_ihex, close(fd); return (error); } - +// 300 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 @@ -2276,78 +707,7 @@ int write_buffer_to_sram(stlink_t *sl, flash_loader_t *fl, const uint8_t *buf, return (ret); } - -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 == STM32_CHIPID_L4 || - sl->chip_id == STM32_CHIPID_L496x_L4A6x || - sl->chip_id == STM32_CHIPID_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); -} - +// 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) || @@ -2387,826 +747,7 @@ uint32_t stlink_calculate_pagesize(stlink_t *sl, uint32_t flashaddr) { 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 == STM32_FLASH_TYPE_F2_F4 || - sl->flash_type == STM32_FLASH_TYPE_F7 || - sl->flash_type == STM32_FLASH_TYPE_L4_L4P) { - // unlock if locked - unlock_flash_if(sl); - - // select the page to erase - if ((sl->chip_id == STM32_CHIPID_L4) || - (sl->chip_id == STM32_CHIPID_L43x_L44x) || - (sl->chip_id == STM32_CHIPID_L45x_L46x) || - (sl->chip_id == STM32_CHIPID_L496x_L4A6x) || - (sl->chip_id == STM32_CHIPID_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 == 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_WB_WL || - sl->flash_type == STM32_FLASH_TYPE_G0 || - sl->flash_type == STM32_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 == STM32_FLASH_TYPE_WB_WL) { - 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 == STM32_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 == STM32_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 == STM32_FLASH_TYPE_F0_F1_F3 || - sl->flash_type == STM32_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 == STM32_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); -} - -// Check if an address and size are within the flash -int stlink_check_address_range_validity(stlink_t *sl, stm32_addr_t addr, size_t size) { - if (addr < sl->flash_base || addr >= (sl->flash_base + sl->flash_size)) { - ELOG("Invalid address, it should be within 0x%08x - 0x%08lx\n", sl->flash_base, (sl->flash_base + sl->flash_size -1)); - return (-1); - } - if ((addr + size) > (sl->flash_base + sl->flash_size)) { - ELOG("The size exceeds the size of the flash (0x%08lx bytes available)\n", (sl->flash_base + sl->flash_size - addr)); - return (-1); - } - return 0; -} - -// Check if an address is aligned with the beginning of a page -int 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; -} - -int stlink_erase_flash_section(stlink_t *sl, stm32_addr_t base_addr, size_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 { - size_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 %#lx\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: %#lx)\n", 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; -} - -int stlink_erase_flash_mass(stlink_t *sl) { - int err = 0; - - // TODO: User 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 /*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 == 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); -} - -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, (uint16_t)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, off; - unsigned int num_half_pages = len / pagesize; - uint32_t val; - uint32_t flash_regs_base = get_stm32l0_flash_base(sl); - flash_loader_t fl; - bool use_loader = true; - int 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) { - size_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 (ret) { - WLOG("l1_stlink_flash_loader_run(%#x) failed! == -1\n", - addr + count * pagesize); - break; - } - - 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 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); -} - -int 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_L4P)) { - 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 == STM32_FLASH_TYPE_L4_L4P) { - // 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) { - 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 == 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 /*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 == STM32_FLASH_TYPE_F2_F4) || - (sl->flash_type == STM32_FLASH_TYPE_F7) || - (sl->flash_type == STM32_FLASH_TYPE_L4_L4P)) { - 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 == STM32_FLASH_TYPE_WB_WL || - sl->flash_type == STM32_FLASH_TYPE_G0 || - sl->flash_type == STM32_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 == STM32_FLASH_TYPE_L0_L1) { - uint32_t val; - uint32_t flash_regs_base = get_stm32l0_flash_base(sl); - uint32_t pagesize = (flash_regs_base==STM32L0_FLASH_REGS_ADDR)? - L0_WRITE_BLOCK_SIZE:L1_WRITE_BLOCK_SIZE; - - DLOG("Starting %3u page write\r\n", (unsigned int)(len / sl->flash_pgsz)); - - off = 0; - - if (len > pagesize) { - if (stm32l1_write_half_pages(sl, 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", - (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 == STM32_FLASH_TYPE_F0_F1_F3) || - (sl->flash_type == STM32_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 == STM32_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 == 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_L4_L4P) || - (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_H7)) { - - 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); -} - -int stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t *base, - uint32_t len, uint8_t eraseonly) { - 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); - - // 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", - (unsigned)(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)); -} - -// 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])); -} - +// 279 int stlink_parse_ihex(const char *path, uint8_t erased_pattern, uint8_t **mem, size_t *size, uint32_t *begin) { int res = 0; @@ -3376,1159 +917,6 @@ uint8_t stlink_get_erased_pattern(stlink_t *sl) { } } -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 base option bytes to write - * @param addr of the memory mapped option bytes - * @param len of options bytes to write - * @return 0 on success, -ve on failure. - */ -static int stlink_write_option_bytes_f0( - stlink_t *sl, uint8_t* base, stm32_addr_t addr, uint32_t len) { - int 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 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_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); -} - -/** - * 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 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: - 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->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); - } -} - -/** - * 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->flash_type) { - 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); - default: - return -1; - } -} - -/** - * 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->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 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 STM32_FLASH_TYPE_F0_F1_F3: - case STM32_FLASH_TYPE_F1_XL: - ret = stlink_write_option_bytes_f0(sl, base, addr, len); - break; - case STM32_FLASH_TYPE_F2_F4: - ret = stlink_write_option_bytes_f4(sl, base, addr, len); - break; - case STM32_FLASH_TYPE_F7: - ret = stlink_write_option_bytes_f7(sl, base, addr, len); - break; - case STM32_FLASH_TYPE_L0_L1: - ret = stlink_write_option_bytes_l0(sl, base, addr, len); - break; - case STM32_FLASH_TYPE_L4_L4P: - ret = stlink_write_option_bytes_l4(sl, base, addr, len); - break; - case STM32_FLASH_TYPE_G0: - case STM32_FLASH_TYPE_G4: - ret = stlink_write_option_bytes_gx(sl, base, addr, len); - break; - case STM32_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_register_f0(stlink_t *sl, - uint32_t option_control_register) { - int ret = 0; - uint16_t opt_val[8]; - unsigned protection, optiondata; - uint16_t user_options, user_data, rdp; - unsigned option_offset, user_data_offset; - - ILOG("Asked to write option control register %#10x to %#010x.\n", - option_control_register, 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_control_register >> option_offset >> 2) & 0xFFFF; - user_data = (option_control_register >> user_data_offset) & 0xFFFF; - -#define VAL_WITH_COMPLEMENT(v) (uint16_t)(((v)&0xFF) | (((~(v))<<8)&0xFF00)) - - opt_val[0] = (option_control_register & (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, (uint8_t*)opt_val, STM32_F0_OPTION_BYTES_BASE, sizeof(opt_val)); - if (ret) - return ret; - - ret = check_flash_error(sl); - if (!ret) { - ILOG("Wrote option bytes %#010x to %#010x!\n", option_control_register, - FLASH_OBR); - } - - 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 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; -} - -/** - * 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 STM32_FLASH_TYPE_F0_F1_F3: - case STM32_FLASH_TYPE_F1_XL: - ret = stlink_write_option_control_register_f0(sl, option_control_register); - break; - case STM32_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 STM32_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) { if (connect == CONNECT_UNDER_RESET) { stlink_enter_swd_mode(sl); @@ -4574,3 +962,445 @@ int stlink_target_connect(stlink_t *sl, enum connect_type connect) { 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_L4P: + 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: + 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); + } +} + +int stlink_jtag_reset(stlink_t *sl, int value) { + DLOG("*** stlink_jtag_reset %d ***\n", value); + 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); +} +/** + * 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); + } +} + +/* Limit the block size to compare to 0x1800 as anything larger will stall the + * STLINK2 Maybe STLINK V1 needs smaller value! + */ +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, (uint16_t)aligned_size); + + if (memcmp(sl->q_buf, mf->base + off, cmp_size)) { + return (-1); + } + } + + return (0); +} + +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(", "); +} + +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); +} + +void stlink_fwrite_finalize(stlink_t *sl, stm32_addr_t addr) { + unsigned int 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); +} + +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, (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 (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])); +} + +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)); +} diff --git a/src/common.h b/src/common.h new file mode 100644 index 0000000..6c22d58 --- /dev/null +++ b/src/common.h @@ -0,0 +1,15 @@ +/* + * File: common.h + * + * TODO: add a description + */ + +#ifndef COMMON_H +#define COMMON_H + +int check_file(stlink_t *, mapped_file_t *, stm32_addr_t); +void md5_calculate(mapped_file_t *); +void stlink_checksum(mapped_file_t *); +void stlink_fwrite_finalize(stlink_t *, stm32_addr_t); + +#endif // COMMON_H diff --git a/src/common_flash.c b/src/common_flash.c new file mode 100644 index 0000000..e2a9ebb --- /dev/null +++ b/src/common_flash.c @@ -0,0 +1,1375 @@ +#include +#include +#include +#include +#include "calculate.h" +#include "common_flash.h" +#include "map_file.h" +#include "common.h" + +#define DEBUG_FLASH 0 + +uint32_t get_stm32l0_flash_base(stlink_t *sl) { + switch (sl->chip_id) { + case STM32_CHIPID_L0: + case STM32_CHIPID_L0_CAT5: + case STM32_CHIPID_L0_CAT2: + case STM32_CHIPID_L011: + return (STM32L0_FLASH_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: + return (STM32L_FLASH_REGS_ADDR); + + default: + WLOG("Flash base use default L0 address\n"); + return (STM32L0_FLASH_REGS_ADDR); + } +} + +uint32_t read_flash_cr(stlink_t *sl, unsigned bank) { + uint32_t reg, res; + + 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_L4_L4P) { + reg = STM32L4_FLASH_CR; + } else if (sl->flash_type == STM32_FLASH_TYPE_G0 || + sl->flash_type == STM32_FLASH_TYPE_G4) { + reg = STM32Gx_FLASH_CR; + } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { + reg = STM32WB_FLASH_CR; + } else if (sl->flash_type == STM32_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); +} + +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 == 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_L0_L1) { + cr_reg = get_stm32l0_flash_base(sl) + FLASH_PECR_OFF; + cr_lock_shift = STM32L0_FLASH_PELOCK; + } else if (sl->flash_type == STM32_FLASH_TYPE_L4_L4P) { + cr_reg = STM32L4_FLASH_CR; + cr_lock_shift = STM32L4_FLASH_CR_LOCK; + } else if (sl->flash_type == STM32_FLASH_TYPE_G0 || + sl->flash_type == STM32_FLASH_TYPE_G4) { + cr_reg = STM32Gx_FLASH_CR; + cr_lock_shift = STM32Gx_FLASH_CR_LOCK; + } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { + cr_reg = STM32WB_FLASH_CR; + cr_lock_shift = STM32WB_FLASH_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 { + 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 int write_flash_sr(stlink_t *sl, unsigned bank, uint32_t val) { + uint32_t sr_reg; + + 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_L0_L1) { + sr_reg = get_stm32l0_flash_base(sl) + FLASH_SR_OFF; + } 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_L4_L4P) { + sr_reg = STM32L4_FLASH_SR; + } else if (sl->flash_type == STM32_FLASH_TYPE_G0 || + sl->flash_type == STM32_FLASH_TYPE_G4) { + sr_reg = STM32Gx_FLASH_SR; + } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { + sr_reg = STM32WB_FLASH_SR; + } else if (sl->flash_type == STM32_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); +} + +void clear_flash_error(stlink_t *sl) { + switch (sl->flash_type) { + 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, STM32Gx_FLASH_SR_ERROR_MASK); + break; + case STM32_FLASH_TYPE_L0_L1: + write_flash_sr(sl, BANK_1, STM32L0_FLASH_SR_ERROR_MASK); + break; + case STM32_FLASH_TYPE_L4_L4P: + write_flash_sr(sl, BANK_1, STM32L4_FLASH_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_WB_WL: + write_flash_sr(sl, BANK_1, STM32WB_FLASH_SR_ERROR_MASK); + break; + default: + break; + } +} + +uint32_t read_flash_sr(stlink_t *sl, unsigned bank) { + uint32_t res, sr_reg; + + 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_L0_L1) { + sr_reg = get_stm32l0_flash_base(sl) + FLASH_SR_OFF; + } 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_L4_L4P) { + sr_reg = STM32L4_FLASH_SR; + } else if (sl->flash_type == STM32_FLASH_TYPE_G0 || + sl->flash_type == STM32_FLASH_TYPE_G4) { + sr_reg = STM32Gx_FLASH_SR; + } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { + sr_reg = STM32WB_FLASH_SR; + } else if (sl->flash_type == STM32_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); +} + +unsigned int is_flash_busy(stlink_t *sl) { + uint32_t sr_busy_shift; + unsigned int res; + + 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_L4_L4P) { + sr_busy_shift = STM32L4_FLASH_SR_BSY; + } else if (sl->flash_type == STM32_FLASH_TYPE_G0 || + sl->flash_type == STM32_FLASH_TYPE_G4) { + sr_busy_shift = STM32Gx_FLASH_SR_BSY; + } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { + sr_busy_shift = STM32WB_FLASH_SR_BSY; + } else if (sl->flash_type == STM32_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 == 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)) + ; +} + +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 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) & 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 STM32_FLASH_TYPE_L0_L1: + 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 STM32_FLASH_TYPE_L4_L4P: + 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 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_WB_WL: + 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 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 == 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_L0_L1) { + cr_reg = get_stm32l0_flash_base(sl) + FLASH_PECR_OFF; + cr_lock_shift = STM32L0_FLASH_PELOCK; + } else if (sl->flash_type == STM32_FLASH_TYPE_L4_L4P) { + cr_reg = STM32L4_FLASH_CR; + cr_lock_shift = STM32L4_FLASH_CR_LOCK; + } else if (sl->flash_type == STM32_FLASH_TYPE_G0 || + sl->flash_type == STM32_FLASH_TYPE_G4) { + cr_reg = STM32Gx_FLASH_CR; + cr_lock_shift = STM32Gx_FLASH_CR_LOCK; + } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { + cr_reg = STM32WB_FLASH_CR; + cr_lock_shift = STM32WB_FLASH_CR_LOCK; + } else if (sl->flash_type == STM32_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 == 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_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_L4P) { + key_reg = STM32L4_FLASH_KEYR; + } else if (sl->flash_type == STM32_FLASH_TYPE_G0 || + sl->flash_type == STM32_FLASH_TYPE_G4) { + key_reg = STM32Gx_FLASH_KEYR; + } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { + key_reg = STM32WB_FLASH_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 { + 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 */ +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); +} + +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 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_L0_L1: + optcr_reg = get_stm32l0_flash_base(sl) + FLASH_PECR_OFF; + optlock_shift = STM32L0_FLASH_OPTLOCK; + break; + case STM32_FLASH_TYPE_L4_L4P: + optcr_reg = STM32L4_FLASH_CR; + optlock_shift = STM32L4_FLASH_CR_OPTLOCK; + break; + case STM32_FLASH_TYPE_G0: + case STM32_FLASH_TYPE_G4: + optcr_reg = STM32Gx_FLASH_CR; + optlock_shift = STM32Gx_FLASH_CR_OPTLOCK; + break; + case STM32_FLASH_TYPE_WB_WL: + optcr_reg = STM32WB_FLASH_CR; + optlock_shift = STM32WB_FLASH_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; + 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; + int active_bit_level = 1; + uint32_t n; + + switch (sl->flash_type) { + 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_L0_L1: + optcr_reg = get_stm32l0_flash_base(sl) + FLASH_PECR_OFF; + optlock_shift = STM32L0_FLASH_OPTLOCK; + break; + case STM32_FLASH_TYPE_L4_L4P: + optcr_reg = STM32L4_FLASH_CR; + optlock_shift = STM32L4_FLASH_CR_OPTLOCK; + break; + case STM32_FLASH_TYPE_G0: + case STM32_FLASH_TYPE_G4: + optcr_reg = STM32Gx_FLASH_CR; + optlock_shift = STM32Gx_FLASH_CR_OPTLOCK; + break; + case STM32_FLASH_TYPE_WB_WL: + optcr_reg = STM32WB_FLASH_CR; + optlock_shift = STM32WB_FLASH_CR_OPTLOCK; + break; + case STM32_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 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_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_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_L4P: + optkey_reg = STM32L4_FLASH_OPTKEYR; + break; + case STM32_FLASH_TYPE_G0: + case STM32_FLASH_TYPE_G4: + optkey_reg = STM32Gx_FLASH_OPTKEYR; + break; + case STM32_FLASH_TYPE_WB_WL: + optkey_reg = STM32WB_FLASH_OPT_KEYR; + 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; + 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); +} + +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); +} + +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 == 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, unsigned bank) { + uint32_t cr_reg, n; + uint32_t bit = FLASH_CR_PG; + + 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_L4_L4P) { + cr_reg = STM32L4_FLASH_CR; + } else if (sl->flash_type == STM32_FLASH_TYPE_G0 || + sl->flash_type == STM32_FLASH_TYPE_G4) { + cr_reg = STM32Gx_FLASH_CR; + } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { + cr_reg = STM32WB_FLASH_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 { + 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) { + 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 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_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 == 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, unsigned bank) { + uint32_t cr_reg, val; + + if (sl->flash_type == STM32_FLASH_TYPE_G0 || + sl->flash_type == STM32_FLASH_TYPE_G4) { + cr_reg = STM32Gx_FLASH_CR; + } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { + 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 == STM32_FLASH_TYPE_G0 || + sl->flash_type == STM32_FLASH_TYPE_G4) { + cr_reg = STM32Gx_FLASH_CR; + } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { + 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 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); +} + +static void set_flash_cr_strt(stlink_t *sl, unsigned bank) { + uint32_t val, cr_reg, cr_strt; + + 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_L4_L4P) { + cr_reg = STM32L4_FLASH_CR; + cr_strt = (1 << STM32L4_FLASH_CR_STRT); + } else if (sl->flash_type == STM32_FLASH_TYPE_G0 || + sl->flash_type == STM32_FLASH_TYPE_G4) { + cr_reg = STM32Gx_FLASH_CR; + cr_strt = (1 << STM32Gx_FLASH_CR_STRT); + } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { + cr_reg = STM32WB_FLASH_CR; + cr_strt = (1 << STM32WB_FLASH_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 { + 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, unsigned bank) { + uint32_t val, cr_reg, cr_mer, cr_pg; + + 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_L4_L4P) { + 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 == STM32_FLASH_TYPE_G0 || + sl->flash_type == STM32_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 == STM32_FLASH_TYPE_WB_WL) { + cr_reg = STM32WB_FLASH_CR; + cr_mer = (1 << FLASH_CR_MER); + 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 { + 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 + */ +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 == STM32_FLASH_TYPE_F2_F4 || + sl->flash_type == STM32_FLASH_TYPE_F7 || + sl->flash_type == STM32_FLASH_TYPE_L4_L4P) { + // unlock if locked + unlock_flash_if(sl); + + // select the page to erase + if ((sl->chip_id == STM32_CHIPID_L4) || + (sl->chip_id == STM32_CHIPID_L43x_L44x) || + (sl->chip_id == STM32_CHIPID_L45x_L46x) || + (sl->chip_id == STM32_CHIPID_L496x_L4A6x) || + (sl->chip_id == STM32_CHIPID_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 == 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_WB_WL || + sl->flash_type == STM32_FLASH_TYPE_G0 || + sl->flash_type == STM32_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 == STM32_FLASH_TYPE_WB_WL) { + 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 == STM32_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 == STM32_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 == STM32_FLASH_TYPE_F0_F1_F3 || + sl->flash_type == STM32_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 == STM32_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_section(stlink_t *sl, stm32_addr_t base_addr, size_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 { + long unsigned int 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 %#lx\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: %#lx)\n", 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; +} + +int stlink_erase_flash_mass(stlink_t *sl) { + int err = 0; + + // TODO: User 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 /*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 == 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); +} + +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); +} + + +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, (uint16_t)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); +} + +// Check if an address and size are within the flash +int stlink_check_address_range_validity(stlink_t *sl, stm32_addr_t addr, size_t size) { + long unsigned int 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%08lx\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%08lx bytes available)\n", logvar); + return (-1); + } + return 0; +} + +// Check if an address is aligned with the beginning of a page +int 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; +} + +int stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t *base, + uint32_t len, uint8_t eraseonly) { + 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); + + // 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", + (unsigned)(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)); +} diff --git a/src/common_flash.h b/src/common_flash.h new file mode 100644 index 0000000..70a6f0e --- /dev/null +++ b/src/common_flash.h @@ -0,0 +1,27 @@ +/* + * File: common_flash.h + * + * TODO: add a description + */ + +#ifndef COMMON_FLASH_H +#define COMMON_FLASH_H + +void lock_flash(stlink_t *); +void clear_flash_error(stlink_t *); +void wait_flash_busy(stlink_t *); +int check_flash_error(stlink_t *); +int unlock_flash_if(stlink_t *); +int lock_flash_option(stlink_t *); +int unlock_flash_option_if(stlink_t *); +void write_flash_cr_psiz(stlink_t *, uint32_t, unsigned); +void clear_flash_cr_pg(stlink_t *, unsigned); + +// TODO: move to private defines if possible + +#define BANK_1 0 +#define BANK_2 1 + +uint32_t read_flash_cr(stlink_t *, unsigned); +uint32_t get_stm32l0_flash_base(stlink_t *); +#endif // STLINK_H diff --git a/src/flashloader.c b/src/flashloader.c new file mode 100644 index 0000000..ce230d7 --- /dev/null +++ b/src/flashloader.c @@ -0,0 +1,482 @@ +#include +#include +#include +#include "common_flash.h" + +#define L1_WRITE_BLOCK_SIZE 0x80 +#define L0_WRITE_BLOCK_SIZE 0x40 + +int stm32l1_write_half_pages(stlink_t *sl, stm32_addr_t addr, uint8_t *base, + uint32_t len, uint32_t pagesize) { + unsigned int count, off; + unsigned int num_half_pages = len / pagesize; + uint32_t val; + uint32_t flash_regs_base = get_stm32l0_flash_base(sl); + flash_loader_t fl; + bool use_loader = true; + int 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) { + size_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 (ret) { + WLOG("l1_stlink_flash_loader_run(%#x) failed! == -1\n", + addr + count * pagesize); + break; + } + + 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 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, unsigned bank) { + uint32_t cr_reg, x; + + x = read_flash_cr(sl, bank); + + 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_L4P) { + cr_reg = STM32L4_FLASH_CR; + x &= ~STM32L4_FLASH_CR_OPBITS; + x |= (1 << STM32L4_FLASH_CR_PG); + } else if (sl->flash_type == STM32_FLASH_TYPE_G0 || + sl->flash_type == STM32_FLASH_TYPE_G4) { + cr_reg = STM32Gx_FLASH_CR; + x |= (1 << FLASH_CR_PG); + } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { + cr_reg = STM32WB_FLASH_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 = FLASH_CR; + x = (1 << FLASH_CR_PG); + } + + stlink_write_debug32(sl, cr_reg, x); +} + +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 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_L4P: + rcc = STM32G4_RCC_AHB1ENR; + rcc_dma_mask = STM32G4_RCC_DMAEN; + break; + case STM32_FLASH_TYPE_L0_L1: + rcc = STM32L0_RCC_AHBENR; + rcc_dma_mask = STM32L0_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); + } +} + +int 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_L4P)) { + 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 == STM32_FLASH_TYPE_L4_L4P) { + // 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) { + 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 == 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 /*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 == STM32_FLASH_TYPE_F2_F4) || + (sl->flash_type == STM32_FLASH_TYPE_F7) || + (sl->flash_type == STM32_FLASH_TYPE_L4_L4P)) { + 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 == STM32_FLASH_TYPE_WB_WL || + sl->flash_type == STM32_FLASH_TYPE_G0 || + sl->flash_type == STM32_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 == STM32_FLASH_TYPE_L0_L1) { + uint32_t val; + uint32_t flash_regs_base = get_stm32l0_flash_base(sl); + uint32_t pagesize = (flash_regs_base==STM32L0_FLASH_REGS_ADDR)? + L0_WRITE_BLOCK_SIZE:L1_WRITE_BLOCK_SIZE; + + DLOG("Starting %3u page write\r\n", (unsigned int)(len / sl->flash_pgsz)); + + off = 0; + + if (len > pagesize) { + if (stm32l1_write_half_pages(sl, 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", + (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 == STM32_FLASH_TYPE_F0_F1_F3) || + (sl->flash_type == STM32_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 == STM32_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 == 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_L4_L4P) || + (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_H7)) { + + 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/map_file.c b/src/map_file.c new file mode 100644 index 0000000..17697c1 --- /dev/null +++ b/src/map_file.c @@ -0,0 +1,62 @@ +#include +#include +#include +#include +#include + +#include "map_file.h" + +#ifndef MAX_FILE_SIZE +#define MAX_FILE_SIZE (1<<20) // 1 GB max file size +#endif + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +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)MAX_FILE_SIZE /*1 GB*/ ) { + // limit file size to 1 GB + 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 = (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/map_file.h b/src/map_file.h new file mode 100644 index 0000000..9cdd745 --- /dev/null +++ b/src/map_file.h @@ -0,0 +1,32 @@ +/* + * File: map_file.h + * + * TODO: add a description + */ + +#ifndef MAP_FILE_H +#define MAP_FILE_H + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#ifdef STLINK_HAVE_SYS_MMAN_H +#include +#else +#include +#endif + +/* Memory mapped file */ +typedef struct mapped_file { + uint8_t *base; + size_t len; +} mapped_file_t; + +#define MAPPED_FILE_INITIALIZER \ + { NULL, 0 } + +int map_file(mapped_file_t *, const char *); +void unmap_file(mapped_file_t *); + +#endif // MAP_FILE_H diff --git a/src/option.c b/src/option.c new file mode 100644 index 0000000..bd792b4 --- /dev/null +++ b/src/option.c @@ -0,0 +1,1027 @@ +#include +#include +#include +#include "common_flash.h" +#include "map_file.h" +#include "common.h" + +/** + * 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 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 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. + * + * 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 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 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: + return stlink_read_option_bytes_Gx(sl, option_byte); + default: + return stlink_read_option_bytes_generic(sl, option_byte); + } +} + + +/** + * Write option bytes + * @param sl + * @param base option bytes to write + * @param addr of the memory mapped option bytes + * @param len of options bytes to write + * @return 0 on success, -ve on failure. + */ +static int stlink_write_option_bytes_f0( + stlink_t *sl, uint8_t* base, stm32_addr_t addr, uint32_t len) { + int 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 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; +} + +/** + * 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 STM32_FLASH_TYPE_F0_F1_F3: + case STM32_FLASH_TYPE_F1_XL: + ret = stlink_write_option_bytes_f0(sl, base, addr, len); + break; + case STM32_FLASH_TYPE_F2_F4: + ret = stlink_write_option_bytes_f4(sl, base, addr, len); + break; + case STM32_FLASH_TYPE_F7: + ret = stlink_write_option_bytes_f7(sl, base, addr, len); + break; + case STM32_FLASH_TYPE_L0_L1: + ret = stlink_write_option_bytes_l0(sl, base, addr, len); + break; + case STM32_FLASH_TYPE_L4_L4P: + ret = stlink_write_option_bytes_l4(sl, base, addr, len); + break; + case STM32_FLASH_TYPE_G0: + case STM32_FLASH_TYPE_G4: + ret = stlink_write_option_bytes_gx(sl, base, addr, len); + break; + case STM32_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_f0(stlink_t *sl, + uint32_t option_control_register) { + int ret = 0; + uint16_t opt_val[8]; + unsigned protection, optiondata; + uint16_t user_options, user_data, rdp; + unsigned option_offset, user_data_offset; + + ILOG("Asked to write option control register %#10x to %#010x.\n", + option_control_register, 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_control_register >> option_offset >> 2) & 0xFFFF; + user_data = (option_control_register >> user_data_offset) & 0xFFFF; + +#define VAL_WITH_COMPLEMENT(v) (uint16_t)(((v)&0xFF) | (((~(v))<<8)&0xFF00)) + + opt_val[0] = (option_control_register & (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, (uint8_t*)opt_val, STM32_F0_OPTION_BYTES_BASE, sizeof(opt_val)); + if (ret) + return ret; + + ret = check_flash_error(sl); + if (!ret) { + ILOG("Wrote option bytes %#010x to %#010x!\n", option_control_register, + FLASH_OBR); + } + + 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_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 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 STM32_FLASH_TYPE_F0_F1_F3: + case STM32_FLASH_TYPE_F1_XL: + ret = stlink_write_option_control_register_f0(sl, option_control_register); + break; + case STM32_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 STM32_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 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 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; +} + +/** + * 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 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); +} + +/** + * 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 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->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); + } +} + + +/** + * 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 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->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); + } +} + +/** + * 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_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); +} + +/** + * 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->flash_type) { + 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); + default: + return -1; + } +} diff --git a/src/read_write.c b/src/read_write.c new file mode 100644 index 0000000..f20d76a --- /dev/null +++ b/src/read_write.c @@ -0,0 +1,143 @@ +#include +#include +#include + +// 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] = (uint8_t)ui; + buf[1] = (uint8_t)(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); +} + +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"); + 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)); +} diff --git a/src/stlink-lib/chipid.h b/src/stlink-lib/chipid.h index 458e7c3..f8e1b34 100644 --- a/src/stlink-lib/chipid.h +++ b/src/stlink-lib/chipid.h @@ -4,7 +4,8 @@ #include #include -/** Chipid parametres */ + +/** Chipid parameters */ struct stlink_chipid_params { char *dev_type; char *ref_manual_id; @@ -22,6 +23,6 @@ struct stlink_chipid_params { }; struct stlink_chipid_params *stlink_chipid_get_params(uint32_t chipid); - void init_chipids(char *dir_to_scan); + void init_chipids(char *dir_to_scan); #endif // STLINK_CHIPID_H_ diff --git a/src/stlink-lib/usb.c b/src/stlink-lib/usb.c index e079188..2e99e82 100644 --- a/src/stlink-lib/usb.c +++ b/src/stlink-lib/usb.c @@ -1134,33 +1134,8 @@ stlink_t *stlink_open_usb(enum ugly_loglevel verbose, enum connect_type connect, #endif libusb_device **list = NULL; - // 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); + 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 : format\n"); - goto on_error; - } - - devBus = atoi(device); - *c++ = 0; - devAddr = atoi(c); - ILOG("bus %03d dev %03d\n", devBus, devAddr); - } while (cnt-- > 0) { struct libusb_device_handle *handle; @@ -1169,13 +1144,6 @@ stlink_t *stlink_open_usb(enum ugly_loglevel verbose, enum connect_type connect, 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 @@ -1202,7 +1170,7 @@ 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 { @@ -1221,6 +1189,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); @@ -1229,6 +1199,7 @@ stlink_t *stlink_open_usb(enum ugly_loglevel verbose, enum connect_type connect, goto on_libusb_error; } } +#endif if (libusb_get_configuration(slu->usb_handle, &config)) { // this may fail for a previous configured device @@ -1287,7 +1258,7 @@ stlink_t *stlink_open_usb(enum ugly_loglevel verbose, enum connect_type connect, // 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_dfu_mode(sl); + _stlink_usb_exit_debug_mode(sl); } _stlink_usb_jtag_reset(sl, STLINK_DEBUG_APIV2_DRIVE_NRST_LOW); diff --git a/src/stlink-lib/usb.c.bak b/src/stlink-lib/usb.c.bak new file mode 100644 index 0000000..32ceff7 --- /dev/null +++ b/src/stlink-lib/usb.c.bak @@ -0,0 +1,1410 @@ +#include +#include +#include +#include +#include + +#if !defined(_MSC_VER) +#include +#endif + +#include +#include +#include + +#if defined(_WIN32) +#include +#endif + +#include +#include +#include "usb.h" + +enum SCSI_Generic_Direction {SG_DXFER_TO_DEV = 0, SG_DXFER_FROM_DEV = 0x80}; + +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)); +} + +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; + bool match = true; + + for (i = 0; i < map_size; i++) { + if (!map[i]) { continue; } + + last_valid_speed = i; + + if (khz == map[i]) { + speed_index = i; + break; + } else { + int current_diff = khz - map[i]; + // get abs value for comparison + current_diff = (current_diff > 0) ? current_diff : -current_diff; + + if (current_diff < speed_diff) { + speed_diff = current_diff; + speed_index = i; + } + } + } + + if (speed_index == -1) { + // This will only be here if we cannot match the slow speed. + // Use the slowest speed we support. + speed_index = last_valid_speed; + match = false; + } else if (i == map_size) { + match = false; + } + + if (!match) { + ILOG("Unable to match requested speed %d kHz, using %d kHz\n", khz, map[speed_index]); + } + + return(speed_index); +} + +void _stlink_usb_close(stlink_t* sl) { + if (!sl) { return; } + + struct stlink_libusb * const handle = sl->backend_data; + + // maybe we couldn't even get the usb device? + if (handle != NULL) { + if (handle->usb_handle != NULL) { libusb_close(handle->usb_handle); } + + libusb_exit(handle->libusb_ctx); + free(handle); + } +} + +ssize_t send_recv(struct stlink_libusb* handle, int terminate, + unsigned char* txbuf, size_t txsize, unsigned char* rxbuf, + size_t rxsize, int check_error, const char *cmd) { + // Note: txbuf and rxbuf can point to the same area + int res, t, retry = 0; + + while (1) { + res = 0; + t = libusb_bulk_transfer(handle->usb_handle, handle->ep_req, txbuf, (int)txsize, &res, 3000); + + 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, (unsigned int)res, (unsigned int)txsize); + } + + if (rxsize != 0) { + t = libusb_bulk_transfer(handle->usb_handle, handle->ep_rep, rxbuf, (int)rxsize, &res, 3000); + + 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) { + unsigned int delay_us = (1<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) { + 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++; + } + + return(res); + } +} + +static inline int send_only(struct stlink_libusb* handle, int terminate, + unsigned char* txbuf, size_t txsize, + const char *cmd) { + return((int)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) { + struct stlink_libusb * const slu = sl->backend_data; + unsigned char* const cmd = sl->c_buf; + int i = 0; + memset(cmd, 0, sizeof(sl->c_buf)); + + if (slu->protocoll == 1) { + cmd[i++] = 'U'; + cmd[i++] = 'S'; + cmd[i++] = 'B'; + cmd[i++] = 'C'; + write_uint32(&cmd[i], slu->sg_transfer_idx); + write_uint32(&cmd[i + 4], len); + i += 8; + cmd[i++] = (dir == SG_DXFER_FROM_DEV) ? 0x80 : 0; + cmd[i++] = 0; // logical unit + cmd[i++] = 0xa; // command length + } + return(i); +} + +int _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; + int i; + + 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_GET_VERSION_APIV3; + } else { + rep_len = 6; + i = fill_command(sl, SG_DXFER_FROM_DEV, 6); + cmd[i++] = STLINK_GET_VERSION; + } + + 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) { + 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; + uint32_t rep_len = 8; + int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len); + uint32_t factor, reading; + int voltage; + + cmd[i++] = STLINK_GET_TARGET_VOLTAGE; + + size = send_recv(slu, 1, cmd, slu->cmd_len, rdata, rep_len, CMD_CHECK_REP_LEN, "GET_TARGET_VOLTAGE"); + + 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; + + return(voltage); +} + +int _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; + + int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len); + cmd[i++] = STLINK_DEBUG_COMMAND; + cmd[i++] = STLINK_DEBUG_APIV2_READDEBUGREG; + write_uint32(&cmd[i], addr); + size = send_recv(slu, 1, cmd, slu->cmd_len, rdata, rep_len, CMD_CHECK_RETRY, "READDEBUGREG"); + + if (size < 0) { + return(-1); + } + + *data = read_uint32(rdata, 4); + + return(0); +} + +int _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; + + int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len); + cmd[i++] = STLINK_DEBUG_COMMAND; + 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, CMD_CHECK_RETRY, "WRITEDEBUGREG"); + + 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); } + + unsigned char* const rdata = sl->q_buf; + struct stlink_libusb * const slu = sl->backend_data; + unsigned char* const cmd = sl->c_buf; + int i; + int16_t ret = 0; + + i = fill_command(sl, SG_DXFER_FROM_DEV, 12); + cmd[i++] = STLINK_DEBUG_COMMAND; + + 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, CMD_CHECK_STATUS, "GETLASTRWSTATUS2"); + } else { + cmd[i++] = STLINK_DEBUG_APIV2_GETLASTRWSTATUS; + ret = send_recv(slu, 1, cmd, slu->cmd_len, rdata, 2, CMD_CHECK_STATUS, "GETLASTRWSTATUS"); + } + + return(ret<0?-1:0); +} + +int _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; + + 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, "WRITEMEM_32BIT"); + + if (ret == -1) { return(ret); } + + ret = send_only(slu, 1, data, len, "WRITEMEM_32BIT"); + + if (ret == -1) { return(ret); } + + return(_stlink_usb_get_rw_status(sl)); +} + +int _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; + + 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, "WRITEMEM_8BIT"); + + if (ret == -1) { return(ret); } + + ret = send_only(slu, 1, data, len, "WRITEMEM_8BIT"); + + if (ret == -1) { return(ret); } + + return(0); +} + + +int _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); + + cmd[i++] = STLINK_GET_CURRENT_MODE; + size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_NO, "GET_CURRENT_MODE"); + + if (size < 0) { + return(-1); + } + + return(sl->q_buf[0]); +} + +int _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); + + cmd[i++] = STLINK_DEBUG_COMMAND; + + if (sl->version.jtag_api == STLINK_JTAG_API_V1) { + cmd[i++] = STLINK_DEBUG_READCOREID; + offset = 0; + } else { + cmd[i++] = STLINK_DEBUG_APIV2_READ_IDCODES; + offset = 4; + } + + size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_STATUS, "READ_IDCODES"); + + if (size < 0) { + return(-1); + } + + sl->core_id = read_uint32(data, offset); + + return(0); +} + +int _stlink_usb_status_v2(stlink_t *sl) { + int result; + uint32_t status = 0; + + result = _stlink_usb_read_debug32(sl, STLINK_REG_DHCSR, &status); + DLOG("core status: %08X\n", status); + + if (result != 0) { + sl->core_stat = TARGET_UNKNOWN; + } else { + if (status & STLINK_REG_DHCSR_C_HALT) { + sl->core_stat = TARGET_HALTED; + } else if (status & STLINK_REG_DHCSR_S_RESET_ST) { + sl->core_stat = TARGET_RESET; + } else { + sl->core_stat = TARGET_RUNNING; + } + } + + return(result); +} + +int _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); + + cmd[i++] = STLINK_DEBUG_COMMAND; + cmd[i++] = STLINK_DEBUG_GETSTATUS; + size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_NO, "GETSTATUS"); + + 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) { + sl->core_stat = TARGET_HALTED; + } else { + sl->core_stat = TARGET_UNKNOWN; + } + } else { + sl->core_stat = TARGET_UNKNOWN; + } + + return(size<0?-1:0); +} + +int _stlink_usb_force_debug(stlink_t *sl) { + struct stlink_libusb *slu = sl->backend_data; + + int 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); + } + + 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); + + cmd[i++] = STLINK_DEBUG_COMMAND; + cmd[i++] = STLINK_DEBUG_FORCEDEBUG; + size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_RETRY, "FORCEDEBUG"); + + return(size<0?-1:0); +} + +int _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); + + 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, CMD_CHECK_RETRY, "ENTER_SWD"); + + return(size<0?-1:0); +} + +int _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); + + cmd[i++] = STLINK_DFU_COMMAND; + cmd[i++] = STLINK_DFU_EXIT; + size = send_only(slu, 1, cmd, slu->cmd_len, "DFU_EXIT"); + + return(size<0?-1:0); +} + + +int _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; + + // send reset command + i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len); + cmd[i++] = STLINK_DEBUG_COMMAND; + + if (sl->version.jtag_api == STLINK_JTAG_API_V1) { + cmd[i++] = STLINK_DEBUG_APIV1_RESETSYS; + } else { + cmd[i++] = STLINK_DEBUG_APIV2_RESETSYS; + } + + size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_RETRY, "RESETSYS"); + + return(size<0?-1:0); +} + +int _stlink_usb_jtag_reset(stlink_t * sl, int 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); + + cmd[i++] = STLINK_DEBUG_COMMAND; + cmd[i++] = STLINK_DEBUG_APIV2_DRIVE_NRST; + cmd[i++] = value; + size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_RETRY, "DRIVE_NRST"); + + return(size<0?-1:0); +} + + +int _stlink_usb_step(stlink_t* sl) { + struct stlink_libusb * const slu = sl->backend_data; + + if (sl->version.jtag_api != STLINK_JTAG_API_V1) { + // emulates the JTAG v1 API by using DHCSR + _stlink_usb_write_debug32(sl, STLINK_REG_DHCSR, STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_HALT | + STLINK_REG_DHCSR_C_MASKINTS | STLINK_REG_DHCSR_C_DEBUGEN); + _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); + } + + 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); + + cmd[i++] = STLINK_DEBUG_COMMAND; + cmd[i++] = STLINK_DEBUG_STEPCORE; + size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_RETRY, "STEPCORE"); + + return(size<0?-1:0); +} + +/** + * This seems to do a good job of restarting things from the beginning? + * @param sl + * @param type + */ +int _stlink_usb_run(stlink_t* sl, enum run_type type) { + struct stlink_libusb * const slu = sl->backend_data; + + int 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 | + ((type==RUN_FLASH_LOADER)?STLINK_REG_DHCSR_C_MASKINTS:0)); + 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); + + cmd[i++] = STLINK_DEBUG_COMMAND; + cmd[i++] = STLINK_DEBUG_RUNCORE; + size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_RETRY, "RUNCORE"); + + return(size<0?-1:0); +} + +int _stlink_usb_set_swdclk(stlink_t* sl, int 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; + + // 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); + switch (map[speed_index]) { + case 5: clk_divisor = STLINK_SWDCLK_5KHZ_DIVISOR; break; + case 15: clk_divisor = STLINK_SWDCLK_15KHZ_DIVISOR; break; + case 25: clk_divisor = STLINK_SWDCLK_25KHZ_DIVISOR; break; + case 50: clk_divisor = STLINK_SWDCLK_50KHZ_DIVISOR; break; + case 100: clk_divisor = STLINK_SWDCLK_100KHZ_DIVISOR; break; + case 125: clk_divisor = STLINK_SWDCLK_125KHZ_DIVISOR; break; + case 240: clk_divisor = STLINK_SWDCLK_240KHZ_DIVISOR; break; + case 480: clk_divisor = STLINK_SWDCLK_480KHZ_DIVISOR; break; + case 950: clk_divisor = STLINK_SWDCLK_950KHZ_DIVISOR; break; + case 1200: clk_divisor = STLINK_SWDCLK_1P2MHZ_DIVISOR; break; + default: + case 1800: clk_divisor = STLINK_SWDCLK_1P8MHZ_DIVISOR; break; + case 4000: clk_divisor = STLINK_SWDCLK_4MHZ_DIVISOR; break; + } + } else + clk_divisor = STLINK_SWDCLK_1P8MHZ_DIVISOR; + + i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len); + + cmd[i++] = STLINK_DEBUG_COMMAND; + 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, CMD_CHECK_RETRY, "SWD_SET_FREQ"); + + return(size<0?-1:0); + } else if (sl->version.stlink_v == 3) { + int 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_DEBUG_APIV3_GET_COM_FREQ; + cmd[i++] = 0; // SWD mode + size = send_recv(slu, 1, cmd, slu->cmd_len, data, 52, CMD_CHECK_STATUS, "GET_COM_FREQ"); + + if (size < 0) { + return(-1); + } + + int speeds_size = data[8]; + if (speeds_size > STLINK_V3_MAX_FREQ_NB) { + speeds_size = STLINK_V3_MAX_FREQ_NB; + } + + for (i = 0; i < speeds_size; i++) map[i] = le_to_h_u32(&data[12 + 4 * i]); + + // 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 = 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_DEBUG_APIV3_SET_COM_FREQ; + cmd[i++] = 0; // SWD mode + cmd[i++] = 0; + cmd[i++] = (uint8_t)((map[speed_index] >> 0) & 0xFF); + cmd[i++] = (uint8_t)((map[speed_index] >> 8) & 0xFF); + 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, CMD_CHECK_STATUS, "SET_COM_FREQ"); + + return(size<0?-1:0); + } else if (clk_freq) { + WLOG("ST-Link firmware does not support frequency setup\n"); + } + + return(-1); +} + +int _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); + + cmd[i++] = STLINK_DEBUG_COMMAND; + cmd[i++] = STLINK_DEBUG_EXIT; + + size = send_only(slu, 1, cmd, slu->cmd_len, "DEBUG_EXIT"); + + return(size<0?-1:0); +} + +int _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); + + 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, CMD_CHECK_NO, "READMEM_32BIT"); + + if (size < 0) { + return(-1); + } + + sl->q_len = (int)size; + stlink_print_data(sl); + + return(0); +} + +int _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); + + cmd[i++] = STLINK_DEBUG_COMMAND; + + if (sl->version.jtag_api == STLINK_JTAG_API_V1) { + cmd[i++] = STLINK_DEBUG_APIV1_READALLREGS; + } else { + cmd[i++] = STLINK_DEBUG_APIV2_READALLREGS; + } + + size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_STATUS, "READALLREGS"); + + 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; + stlink_print_data(sl); + + for (i = 0; i < 16; i++) regp->r[i] = read_uint32(sl->q_buf, reg_offset + i * 4); + + regp->xpsr = read_uint32(sl->q_buf, reg_offset + 64); + regp->main_sp = read_uint32(sl->q_buf, reg_offset + 68); + regp->process_sp = read_uint32(sl->q_buf, reg_offset + 72); + 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); } + + DLOG("xpsr = 0x%08x\n", regp->xpsr); + DLOG("main_sp = 0x%08x\n", regp->main_sp); + DLOG("process_sp = 0x%08x\n", regp->process_sp); + DLOG("rw = 0x%08x\n", regp->rw); + DLOG("rw2 = 0x%08x\n", regp->rw2); + + return(0); +} + +int _stlink_usb_read_reg(stlink_t *sl, int 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); + + cmd[i++] = STLINK_DEBUG_COMMAND; + + if (sl->version.jtag_api == STLINK_JTAG_API_V1) { + cmd[i++] = STLINK_DEBUG_APIV1_READREG; + } else { + cmd[i++] = STLINK_DEBUG_APIV2_READREG; + } + + cmd[i++] = (uint8_t)r_idx; + size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_RETRY, "READREG"); + + if (size < 0) { + return(-1); + } + + sl->q_len = (int)size; + stlink_print_data(sl); + r = read_uint32(sl->q_buf, reg_offset); + DLOG("r_idx (%2d) = 0x%08x\n", r_idx, r); + + switch (r_idx) { + case 16: + regp->xpsr = r; + break; + case 17: + regp->main_sp = r; + break; + case 18: + regp->process_sp = r; + break; + case 19: + regp->rw = r; // XXX ?(primask, basemask etc.) + break; + case 20: + regp->rw2 = r; // XXX ?(primask, basemask etc.) + break; + default: + regp->r[r_idx] = r; + } + + 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) { + uint32_t r; + int ret; + + sl->q_buf[0] = (unsigned char)r_idx; + + for (int 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); } + + ret = _stlink_usb_read_mem32(sl, STLINK_REG_DCRDR, 4); + + if (ret == -1) { return(ret); } + + r = read_uint32(sl->q_buf, 0); + DLOG("r_idx (%2d) = 0x%08x\n", r_idx, r); + + switch (r_idx) { + case 0x14: + regp->primask = (uint8_t)(r & 0xFF); + regp->basepri = (uint8_t)((r >> 8) & 0xFF); + regp->faultmask = (uint8_t)((r >> 16) & 0xFF); + regp->control = (uint8_t)((r >> 24) & 0xFF); + break; + case 0x21: + regp->fpscr = r; + break; + default: + regp->s[r_idx - 0x40] = r; + break; + } + + return(0); +} + +int _stlink_usb_read_all_unsupported_regs(stlink_t *sl, struct stlink_reg *regp) { + int ret; + + ret = _stlink_usb_read_unsupported_reg(sl, 0x14, regp); + + if (ret == -1) { return(ret); } + + ret = _stlink_usb_read_unsupported_reg(sl, 0x21, regp); + + if (ret == -1) { return(ret); } + + for (int i = 0; i < 32; i++) { + ret = _stlink_usb_read_unsupported_reg(sl, 0x40 + i, regp); + + if (ret == -1) { return(ret); } + } + + 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; + + 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); } + + val = (uint8_t)(val >> 24); + + switch (r_idx) { + case 0x1C: /* control */ + val = (((uint32_t)val) << 24) | + (((uint32_t)regp->faultmask) << 16) | + (((uint32_t)regp->basepri) << 8) | + ((uint32_t)regp->primask); + break; + case 0x1D: /* faultmask */ + val = (((uint32_t)regp->control) << 24) | + (((uint32_t)val) << 16) | + (((uint32_t)regp->basepri) << 8) | + ((uint32_t)regp->primask); + break; + case 0x1E: /* basepri */ + val = (((uint32_t)regp->control) << 24) | + (((uint32_t)regp->faultmask) << 16) | + (((uint32_t)val) << 8) | + ((uint32_t)regp->primask); + break; + case 0x1F: /* primask */ + val = (((uint32_t)regp->control) << 24) | + (((uint32_t)regp->faultmask) << 16) | + (((uint32_t)regp->basepri) << 8) | + ((uint32_t)val); + break; + } + + r_idx = 0x14; + } + + write_uint32(sl->q_buf, val); + + ret = _stlink_usb_write_mem32(sl, STLINK_REG_DCRDR, 4); + + 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)); +} + +int _stlink_usb_write_reg(stlink_t *sl, uint32_t reg, int 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); + + cmd[i++] = STLINK_DEBUG_COMMAND; + + if (sl->version.jtag_api == STLINK_JTAG_API_V1) { + cmd[i++] = STLINK_DEBUG_APIV1_WRITEREG; + } else { + cmd[i++] = STLINK_DEBUG_APIV2_WRITEREG; + } + + cmd[i++] = idx; + write_uint32(&cmd[i], reg); + size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_RETRY, "WRITEREG"); + + return(size<0?-1:0); +} + +int _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; + + int 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_uint32(&cmd[i + 2], frequency); + + size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_STATUS, "START_TRACE_RX"); + + return(size<0?-1:0); +} + +int _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); + 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, CMD_CHECK_STATUS, "STOP_TRACE_RX"); + + return(size<0?-1:0); +} + +int _stlink_usb_read_trace(stlink_t* sl, uint8_t* buf, size_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); + + 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, CMD_CHECK_NO, "GET_TRACE_NB"); + + if (send_size < 0) { + return(-1); + } else if (send_size != 2) { + ELOG("STLINK_DEBUG_APIV2_GET_TRACE_NB reply size %d\n", (int)send_size); + return(-1); + } + + uint16_t trace_count = read_uint16(sl->q_buf, 0); + + if (trace_count > size) { + ELOG("read_trace insufficient buffer length\n"); + return -1; + } + + if (trace_count != 0) { + int res = 0; + int t = libusb_bulk_transfer(slu->usb_handle, slu->ep_trace, buf, trace_count, &res, 3000); + + if (t || res != (int)trace_count) { + ELOG("read_trace read error %d\n", t); + return(-1); + } + } + + return trace_count; +} + +static stlink_backend_t _stlink_usb_backend = { + _stlink_usb_close, + _stlink_usb_exit_debug_mode, + _stlink_usb_enter_swd_mode, + NULL, // don't enter_jtag_mode here... + _stlink_usb_exit_dfu_mode, + _stlink_usb_core_id, + _stlink_usb_reset, + _stlink_usb_jtag_reset, + _stlink_usb_run, + _stlink_usb_status, + _stlink_usb_version, + _stlink_usb_read_debug32, + _stlink_usb_read_mem32, + _stlink_usb_write_debug32, + _stlink_usb_write_mem32, + _stlink_usb_write_mem8, + _stlink_usb_read_all_regs, + _stlink_usb_read_reg, + _stlink_usb_read_all_unsupported_regs, + _stlink_usb_read_unsupported_reg, + _stlink_usb_write_unsupported_reg, + _stlink_usb_write_reg, + _stlink_usb_step, + _stlink_usb_current_mode, + _stlink_usb_force_debug, + _stlink_usb_target_voltage, + _stlink_usb_set_swdclk, + _stlink_usb_enable_trace, + _stlink_usb_disable_trace, + _stlink_usb_read_trace +}; + +/* return the length of serial or (0) in case of errors */ +size_t stlink_serial(struct libusb_device_handle *handle, struct libusb_device_descriptor *desc, char *serial) { + unsigned char desc_serial[(STLINK_SERIAL_LENGTH) * 2]; + + /* truncate the string in the serial buffer */ + serial[0] = '\0'; + + /* get the LANGID from String Descriptor Zero */ + int 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); + + /* get the serial */ + ret = libusb_get_string_descriptor(handle, desc->iSerialNumber, langid, desc_serial, + sizeof(desc_serial)); + if (ret < 0) return 0; // could not read serial + + unsigned char len = desc_serial[0]; + + if (len == ((STLINK_SERIAL_LENGTH + 1) * 2)) { /* len == 50 */ + /* good ST-Link adapter */ + ret = libusb_get_string_descriptor_ascii( + handle, desc->iSerialNumber, (unsigned char *)serial, STLINK_SERIAL_BUFFER_SIZE); + 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) + sprintf(serial + i, "%02X", desc_serial[i + 2]); + serial[STLINK_SERIAL_LENGTH] = '\0'; + } else { + return 0; + } + + return strlen(serial); +} + +stlink_t *stlink_open_usb(enum ugly_loglevel verbose, enum connect_type connect, char serial[STLINK_SERIAL_BUFFER_SIZE], int freq) { + stlink_t* sl = NULL; + struct stlink_libusb* slu = NULL; + int ret = -1; + int config; + + sl = calloc(1, sizeof(stlink_t)); + if (sl == NULL) { goto on_malloc_error; } + + slu = calloc(1, sizeof(struct stlink_libusb)); + if (slu == NULL) { goto on_malloc_error; } + + ugly_init(verbose); + sl->backend = &_stlink_usb_backend; + sl->backend_data = slu; + + sl->core_stat = TARGET_UNKNOWN; + + if (libusb_init(&(slu->libusb_ctx))) { + WLOG("failed to init libusb context, wrong version of libraries?\n"); + goto on_error; + } + +#if LIBUSB_API_VERSION < 0x01000106 + libusb_set_debug(slu->libusb_ctx, ugly_libusb_log_level(verbose)); +#else + libusb_set_option(slu->libusb_ctx, LIBUSB_OPTION_LOG_LEVEL, ugly_libusb_log_level(verbose)); +#endif + + libusb_device **list = NULL; + // 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) + ssize_t cnt = libusb_get_device_list(slu->libusb_ctx, &list); + struct libusb_device_descriptor desc; + + while (cnt-- > 0) { + struct libusb_device_handle *handle; + + libusb_get_device_descriptor(list[cnt], &desc); + + if (desc.idVendor != STLINK_USB_VID_ST) { continue; } + + ret = libusb_open(list[cnt], &handle); + + if (ret) { continue; } // could not open device + + size_t serial_len = stlink_serial(handle, &desc, sl->serial); + + libusb_close(handle); + + if (serial_len != STLINK_SERIAL_LENGTH) { continue; } // could not read the serial + + // if no serial provided, or if serial match device, fixup version and protocol + if (((serial == NULL) || (*serial == 0)) || (memcmp(serial, &sl->serial, STLINK_SERIAL_LENGTH) == 0)) { + if (STLINK_V1_USB_PID(desc.idProduct)) { + slu->protocoll = 1; + sl->version.stlink_v = 1; + } else if (STLINK_V2_USB_PID(desc.idProduct) || STLINK_V2_1_USB_PID(desc.idProduct)) { + sl->version.stlink_v = 2; + } else if (STLINK_V3_USB_PID(desc.idProduct)) { + sl->version.stlink_v = 3; + } + + break; + } + } + + if (cnt < 0) { + 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); + + if (ret != 0) { + WLOG("Error %d (%s) opening ST-Link v%d device %03d:%03d\n", ret, + strerror(errno), + sl->version.stlink_v, + libusb_get_bus_number(list[cnt]), + libusb_get_device_address(list[cnt])); + libusb_free_device_list(list, 1); + goto on_error; + } + } + + 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); + + if (ret < 0) { + WLOG("libusb_detach_kernel_driver(() error %s\n", strerror(-ret)); + goto on_libusb_error; + } + } +#endif + + if (libusb_get_configuration(slu->usb_handle, &config)) { + // this may fail for a previous configured device + WLOG("libusb_get_configuration()\n"); + goto on_libusb_error; + } + + if (config != 1) { + printf("setting new configuration (%d -> 1)\n", config); + + if (libusb_set_configuration(slu->usb_handle, 1)) { + // this may fail for a previous configured device + WLOG("libusb_set_configuration() failed\n"); + goto on_libusb_error; + } + } + + if (libusb_claim_interface(slu->usb_handle, 0)) { + WLOG("Stlink usb device found, but unable to claim (probably already in use?)\n"); + goto on_libusb_error; + } + + // TODO: Could use the scanning technique from STM8 code here... + slu->ep_rep = 1 /* ep rep */ | LIBUSB_ENDPOINT_IN; + + if (desc.idProduct == STLINK_USB_PID_STLINK_NUCLEO || + desc.idProduct == STLINK_USB_PID_STLINK_32L_AUDIO || + desc.idProduct == STLINK_USB_PID_STLINK_V2_1 || + 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_NO_MSD_PID) { + slu->ep_req = 1 /* ep req */ | LIBUSB_ENDPOINT_OUT; + slu->ep_trace = 2 | LIBUSB_ENDPOINT_IN; + } else { + slu->ep_req = 2 /* ep req */ | LIBUSB_ENDPOINT_OUT; + slu->ep_trace = 3 | LIBUSB_ENDPOINT_IN; + } + + slu->sg_transfer_idx = 0; + slu->cmd_len = (slu->protocoll == 1) ? STLINK_SG_SIZE : STLINK_CMD_SIZE; + + // initialize stlink version (sl->version) + stlink_version(sl); + + int mode = stlink_current_mode(sl); + if (mode == STLINK_DEV_DFU_MODE) { + DLOG("-- exit_dfu_mode\n"); + _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; + // set the speed before entering the mode as the chip discovery phase + // 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_usb_set_swdclk(sl, freq); + + stlink_target_connect(sl, connect); + return(sl); + +on_libusb_error: + stlink_close(sl); + 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); +} + +static size_t stlink_probe_usb_devs(libusb_device **devs, stlink_t **sldevs[], enum connect_type connect, int freq) { + stlink_t **_sldevs; + libusb_device *dev; + int i = 0; + size_t slcnt = 0; + size_t slcur = 0; + + /* Count STLINKs */ + while ((dev = devs[i++]) != NULL) { + struct libusb_device_descriptor desc; + int ret = libusb_get_device_descriptor(dev, &desc); + + if (ret < 0) { + WLOG("failed to get libusb device descriptor (libusb error: %d)\n", ret); + break; + } + + if (desc.idVendor != STLINK_USB_VID_ST) { continue; } + + if (!STLINK_SUPPORTED_USB_PID(desc.idProduct)) { + WLOG("skipping ST device : %#04x:%#04x)\n", desc.idVendor, desc.idProduct); + continue; + } + + slcnt++; + } + + _sldevs = calloc(slcnt, sizeof(stlink_t *)); // allocate list of pointers + + if (!_sldevs) { + *sldevs = NULL; + return(0); + } + + /* Open STLINKS and attach them to list */ + i = 0; + + while ((dev = devs[i++]) != NULL) { + struct libusb_device_descriptor desc; + int ret = libusb_get_device_descriptor(dev, &desc); + + if (ret < 0) { + WLOG("failed to get libusb device descriptor (libusb error: %d)\n", ret); + break; + } + + if (!STLINK_SUPPORTED_USB_PID(desc.idProduct)) { continue; } + + struct libusb_device_handle* handle; + char serial[STLINK_SERIAL_BUFFER_SIZE] = {0, }; + + ret = libusb_open(dev, &handle); + + if (ret < 0) { + if (ret == LIBUSB_ERROR_ACCESS) { + ELOG("Could not open USB device %#06x:%#06x, access error.\n", desc.idVendor, desc.idProduct); + } else { + ELOG("Failed to open USB device %#06x:%#06x, libusb error: %d)\n", desc.idVendor, desc.idProduct, ret); + } + + break; + } + + size_t serial_len = stlink_serial(handle, &desc, serial); + + libusb_close(handle); + + if (serial_len != STLINK_SERIAL_LENGTH) { continue; } + + stlink_t *sl = stlink_open_usb(0, connect, serial, freq); + + if (!sl) { + ELOG("Failed to open USB device %#06x:%#06x\n", desc.idVendor, desc.idProduct); + continue; + } + + _sldevs[slcur++] = sl; + } + + *sldevs = _sldevs; + + return(slcur); +} + +size_t stlink_probe_usb(stlink_t **stdevs[], enum connect_type connect, int freq) { + libusb_device **devs; + stlink_t **sldevs; + + size_t slcnt = 0; + int r; + ssize_t cnt; + + r = libusb_init(NULL); + + if (r < 0) { return(0); } + + cnt = libusb_get_device_list(NULL, &devs); + + if (cnt < 0) { return(0); } + + slcnt = stlink_probe_usb_devs(devs, &sldevs, connect, freq); + libusb_free_device_list(devs, 1); + + libusb_exit(NULL); + + *stdevs = sldevs; + + return(slcnt); +} + +void stlink_probe_usb_free(stlink_t ***stdevs, size_t size) { + if (stdevs == NULL || *stdevs == NULL || size == 0) { return; } + + for (size_t n = 0; n < size; n++) { stlink_close((*stdevs)[n]); } + + free(*stdevs); + *stdevs = NULL; +} diff --git a/src/win32/unistd/unistd.h b/src/win32/unistd/unistd.h index 389c446..cb6da4b 100644 --- a/src/win32/unistd/unistd.h +++ b/src/win32/unistd/unistd.h @@ -52,7 +52,7 @@ #define ssize_t int #ifndef SSIZE_MAX -#define SSIZE_MAX ((sizeof(ssize_t) == 4) ? 2147483647 : 9223372036854775807) +#define SSIZE_MAX ((sizeof(ssize_t) == 4) ? 1073741824 : ‭4611686018427387904‬) #endif #define STDIN_FILENO 0 diff --git a/src/win32/unistd/unistd.h.bak b/src/win32/unistd/unistd.h.bak new file mode 100644 index 0000000..47967e4 --- /dev/null +++ b/src/win32/unistd/unistd.h.bak @@ -0,0 +1,76 @@ +#ifndef _UNISTD_H +#define _UNISTD_H 1 + +/* + * This file intended to serve as a drop-in replacement for unistd.h on Windows + * Please add functionality as needed. + */ + +#include +#include + +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning(disable: 4820) +#endif + +#include + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +#include // getopt at: https://gist.github.com/ashelly/7776712 +#include // for getpid() and the exec..() family +#include // for _getcwd() and _chdir() + +#define srandom srand +#define random rand + +/* Values for the second argument to access. These may be OR'd together. */ +#define R_OK 4 // Test for read permission +#define W_OK 2 // Test for write permission +// #define X_OK 1 // execute permission - unsupported in windows +#define F_OK 0 // Test for existence + +#define access _access +#define dup2 _dup2 +#define execve _execve +#define ftruncate _chsize +#define unlink _unlink +#define fileno _fileno +#define getcwd _getcwd +#define chdir _chdir +#define isatty _isatty +#define lseek _lseek + +/* + * Read, write, and close are NOT being defined here, + * because while there are file handle specific versions for Windows, they probably don't work for sockets. + * You need to look at your app and consider whether to call e.g. closesocket(). + */ + +#define ssize_t int +#ifndef SSIZE_MAX +//#define SSIZE_MAX ((sizeof(ssize_t) == 4) ? 2147483647 : 9223372036854775807) +#define SSIZE_MAX ((sizeof(ssize_t) == 4) ? 1073741824 : ‭4611686018427387904‬) +#endif + +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 +// should be in some equivalent to +typedef __int8 int8_t; +typedef __int16 int16_t; +typedef __int32 int32_t; +typedef __int64 int64_t; +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; + +#ifndef STLINK_HAVE_UNISTD_H +int usleep(unsigned int waitTime); +#endif + +#endif // _UNISTD_H diff --git a/src/Описание.txt b/src/Описание.txt new file mode 100644 index 0000000..d4111a8 --- /dev/null +++ b/src/Описание.txt @@ -0,0 +1,129 @@ +--------------------------------------------------------------------------------- +Файл info.c: + +main: +- проверяю количество параметров +- инициализирую список структур devicelist, объявленный в файле chipid.c +- вызываю функцию print_data (и передаю ей параметры программы). + +print_data: +Смотрю, какие параметры переданы программе. +Если параметр --probe - вызываю функцию stlink_probe с параметрами по умолчанию +(connect: NORMAL, freq: 0) + +stlink_probe: +Объявляю список структур для каждого подключенного ST-LINK'a +(stdevs: указатель на список указателей, указывающих на структуры). +Вызываю stlink_probe_usb с параметрами: +- адрес stdevs'а (тройной указатель), +- connect, +- freq + +Функция stlink_probe_usb заполняет stdevs и возвращает его размер. +Для каждого указателя вызываю функцию stlink_print_info. + +Потом освобождаю память, отведённую под stdevs. + +stlink_print_info: просто печатаю в терминал информацию из переданной структуры +ST-LINK'а. + +--------------------------------------------------------------------------------- +Файл usb.c: + +stlink_probe_usb: +Инициализирую libusb +Получаю список USB-устройств (libusb_get_device_list). +Для полученного списка вызываю функцию stlink_probe_usb_devs. +Передаю ей: +- указатель на список указателей на структуры libusb_device (двойной указатель) devs +- адрес указателя на список указателей на структуры ST-LINK (тройной указатель) sldevs +- connect, freq. +Потом освобождаю память, занятую структурами libusb_device. +Список указателей на структуры ST-LINK возвращаю на выход (в функцию stlink_probe). + +stlink_probe_usb_devs: +Определяю количество подключенных ST-LINK'ов: +Прохожу по списку USB-устройств. +Для каждого USB-устройства получаю дескриптор desc. +Если в дескрипторе указаны idVendor и idProduct, соответствующие ST-LINK'у - увеличиваю счётчик. +Выделяю память под нужное количество структур ST-LINK'ов. + +Ещё раз прохожу по списку USB-устройств и получаю дескриптор каждого. +Если idProduct соответствует ST-LINK'у: +- открываю ST-LINK (libusb_open), +- читаю его серийник (stlink_serial); +- закрываю (libusb_close). + +Если длина серийника правильная - открываю его функцией stlink_open_usb. +Она возвращает ссылку на структуру stlink_t. Пристёгиваю эту ссылку к списку структур. +Перехожу к следюущему USB-устройству. Потом записываю ссылку на список структур stlink_t +в указатель и возвращаю количество структур по списку. + +stlink_serial: +Получаю дескриптор нулевой строки USB-устройства, беру из него LANGID (libusb_get_string_descriptor). +Получаю дескриптор строки серийника (для него нужен LANGID) (libusb_get_string_descriptor). +Если серийник длиной 50 символов - беру его же в формате ascii. +Если серийник длиной 26 символов - для каждого символа выполняю строку: +sprintf(serial + i, "%02X", desc_serial[i + 2]) +В конце ставлю ноль. +Возвращаю длину серийника и сам серийник, записанный в память по адресу из параметра. + +stlink_open_usb: +Выделяю в куче память под структуры sl (stlink_t) и slu (stlink_libusb). +Записываю в sl ссылку на список каких-то функций и ссылку на slu, указываю статус ядра +целевого MCU: TARGET_UNKNOWN. +Инициализирую libusb с контекстом, указываю LOG_LEVEL. +Получаю список USB-устройств. +Для каждого устройства получаю дескриптор и проверяю его idVendor. +Открываю устройство и пытаюсь получить серийник. +Если не получил серийник либо получил серийник, соответствующий заданному в параметре - +- выставляю в структуре sl версию и протокол по idProduct, после чего заканчиваю просмотр +устройств USB. + +Просмотрев все устройства, открываю найденный ST-LINK и освобождаю память, занятую +списком USB-устройств. + +Читаю конфигурацию ST-LINK'а, потом устанавливаю её. Делаю заявку на интерфейс (libusb_claim_interface). +Потом выставляю поля ep_rep, ep_req, ep_trace, sg_transfer_idx и cmd_len. +Инициализирую версию ST-LINK'а (stlink_version). +Получаю режим работы ST-LINK'а. Если он в режиме dfu - выхожу из него. +Если CONNECT_UNDER_RESET: выхожу из debug mode, если в нём. Выполняю JTAG reset. +Выставляю поле freq по параметру функции, устанавливаю SWD clock (_stlink_usb_set_swdclk). +Выполняю stlink_target_connect и возвращаю структуру sl. + +_stlink_usb_version: +Заполняю структуру stlink командой fill_command (по-разному для ST-LINK v. 3 и предыдущих версий) +Выполняю функцию send_recv + + +_stlink_usb_current_mode: +Заполняю структуру stlink командой fill_command, ставлю в i-тую позицию команду STLINK_GET_CURRENT_MODE +Вызываю функцию send_recv +Возвращаю первый символ буфера, или -1 при ошибке. + +_stlink_usb_exit_debug_mode, _stlink_usb_exit_debug_mode: +Заполняю структуру stlink командой fill_command, ставлю в i-тую позицию команды: +STLINK_DFU_COMMAND +STLINK_DFU_EXIT +Вызываю функцию send_only +Возвращаю 0, или -1 при ошибке. +То же самое для debug + +fill_command: +Для ST-LINK v. 1 заполняю поле c_buf структуры stlink. Для всех остальных заполняю его нулями. + +send_recv: +Отправляю функцией libusb_bulk_transfer данные в параметре txbuf и команду в cmd. +Проверяю ответ на ошибки и если указан rxsize - принимаю данные той же функцией. +Возвращаю количество принятого после проверки на ошибки. + +--------------------------------------------------------------------------------- +Файл common.c: + +stlink_version: +Запускаю функцию version из backend (вызывается _stlink_usb_version из usb.c) +Выполняю _parse_version. + +stlink_current_mode: +возвращаю результат выполнения функции sl->backend->current_mode(sl) после проверки на ошибки. +При этом запускается функция _stlink_usb_current_mode. \ No newline at end of file diff --git a/stlinkv1_macos_driver/install.sh b/stlinkv1_macos_driver/install.sh index f9878bd..5716281 100644 --- a/stlinkv1_macos_driver/install.sh +++ b/stlinkv1_macos_driver/install.sh @@ -2,6 +2,9 @@ ISMACOS=$(sw_vers -productVersion) case $ISMACOS in +10.14*) + KEXT="stlink_shield_10_14.kext" + ;; 10.15*) KEXT="stlink_shield_10_15.kext" ;; diff --git a/stlinkv1_macos_driver/stlink_shield_10_14.kext/Contents/Info.plist b/stlinkv1_macos_driver/stlink_shield_10_14.kext/Contents/Info.plist new file mode 100644 index 0000000..fd424ea --- /dev/null +++ b/stlinkv1_macos_driver/stlink_shield_10_14.kext/Contents/Info.plist @@ -0,0 +1,82 @@ + + + + + BuildMachineOSBuild + 18G7016 + CFBundleDevelopmentRegion + English + CFBundleIdentifier + com.libusb.stlink-shield + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + KEXT + CFBundleSignature + ???? + CFBundleSupportedPlatforms + + MacOSX + + CFBundleVersion + 1.0.0 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 11C504 + DTPlatformVersion + GM + DTSDKBuild + 19B90 + DTSDKName + macosx10.15 + DTXcode + 1130 + DTXcodeBuild + 11C504 + IOKitPersonalities + + DeviceDriver + + CFBundleIdentifier + com.apple.kpi.iokit + IOClass + IOService + IOProviderClass + IOUSBDevice + bcdDevice + 256 + idProduct + 14148 + idVendor + 1155 + + InterfaceDriver + + CFBundleIdentifier + com.apple.kpi.iokit + IOClass + IOService + IOProviderClass + IOUSBInterface + bConfigurationValue + 1 + bInterfaceNumber + 0 + idProduct + 14148 + idVendor + 1155 + + + LSMinimumSystemVersion + 10.14 + OSBundleLibraries + + com.apple.iokit.IOUSBFamily + 1.8 + com.apple.kpi.libkern + 11.2.0 + + + diff --git a/stlinkv1_macos_driver/stlink_shield_10_14.kext/Contents/MacOS/stlink_shield_10_14 b/stlinkv1_macos_driver/stlink_shield_10_14.kext/Contents/MacOS/stlink_shield_10_14 new file mode 100644 index 0000000000000000000000000000000000000000..6a32aa4615953f6afe16047f73da9a3bced9b3a3 GIT binary patch literal 33840 zcmeHOdwf$>p1)}uC}>G^QR*WS>I=j+ty12BhPH46DO6ez1iYqA3Yj)ZNp7Gx=tfJ` zYp8Tb@dY}d4$kQ4>aHsfUv;V!Mn}FxJ?&-tC-@0{;B_mTT}_t-ZldkcagQxJr+uw`Qtvjm|fYCuj9F2HsdvXWF?KC7A) zb^mAWP6f`5D5edrSdt{!+az-WNcUGrfss1TQIWXTmX%})QME?>FG;n*Ksf0z-Jfuw zYA0%qz`Oa=$~nScSPuCD^Ao)Lct!3nn4ubITyw*VHHz_h7f5v>x8JK4rT1^c#oP}G zk3^hj)q=GDG!GxMc_?#KJ5nmGJa6Wh#>ppbG#8X4X?`%N8u6a}Y3^t~f2m)Ril00tNoyxoS&x-bx-c~^%o~}KwVnFM}?+*sF zvh?vDKzmAsDzN{l{WGMLQ&y5{!r_#%bbr=CYGq}L%`f?*d8IWfNiOHqDdlBOZ6DJ* zbQ5>Pc_FW-ex>$}G|0tfgt59afrX>q9#Lc78r^#BWj=BQ60{@p4m?0{EbzJY5 z>6qcDt`eK~=Q@-RoyrlXazbpqxur$GP?^8J_kJ&SOZngh>W^P*c3>+$*d*6n2%>E%tMP(-+mGL8T-D&&) zKndCRlG%57HfnzoIYVT~Yjg(Fnm&Ot*soze8onJG2?;rP#(*zP)@KZ zD;5&oTZ_NI!5pf)l!KU}3T2O|yv~)}Z2TP24CwSOASGnK)Uq+lSICOD9T$X?@kmxt zyz5HwwvKo_6J=jh8JzNdb&87dcVw(s)&bbiSyj}23%DUNUW{4pBZJn`EOCtSHe?qK zg||%7h;Xj3Iosun% z$+-Y*(KU$EyIY)Nq*gLc7o(Q_Ohe;0401jMIAQ~o{#b{WPpC`{^A56QN@QEq{y1{U zP|t$(5NZXrOooawYPpRdX1tw2PCXztV;hBPHu^!b#O610=Q!p%<~eS3Nb@?Flx&`} z`%}YQSFHFF*s1Eb7EkC$L1>1PbKCV2+uvu>o^BSK?LVQVU|N>fiyT<8(K>4XlFH<% zd{Xvj>d=X^d3YIrMjC}0uT(PwZ6La2bu-lHJ zX01FzHE%u|mv6%ONB0f0^mUVh0Kx&4&$TnR2dKRC0!pJH?U*=*+^=Kv;_&_NPL168lg^`F^^B zjoP=P7s+|t4c5avc2ZZ93T$B1vXLNW+{7T~aX@Uwes#&LqcSzxDr6B2!4S<4l8n{_ z)%Wh657OMp2m>tpM3XH2NKrjCK}S57GA1MNcx? z4n{3I31Y_28RTpMB%-}VWooo`WTSSvY)USVC%}3L(?YG1VHPoJSxgW!HZjO?13I(l zi267VShZBB#+gMG+9BjBkmRU}!FmXHJ~d8;>&>Von;>TF!yxA%&KrDG&Bh-ou4ETgbdY|UPBX2=j%>OV(@gfEvw~@08LFD?55fW`nVA>?Kl?=O zOUWU-0JxX6FU5)37)6#{0CYbwyU8Ni>FJDGst97nG6p#n1h@jAxMHk$9MR^@I5iYs z%M9!n1EO{#{u?3##aK=ja+^p~^>i7tAIFGTzAFp|7OKX|P>bk#au};*=i3L*rXX~_ zeO7A(1)jmr@bvR7t~(!RN)^*}r5dW!xEy&(xUPC$%f{>>%_3&M9s&0L8!q+GevVcQ z>nWObr%~itnh;oB4$4H=&hM?p3>2Z4V#{`Uu&cFr45(?K;2L$Ue3lrSV@7%8U{}AQ z_BhU=VBas;l7SS#-=98z;8Je|GZWOj`j zFAtz!5X$EiWq;R%q=j?LIC-FR%&pmSUPa3;+2~Z}US?K>QLSI?>hDx8A&bb)3Z*U^ zR*_G;cF=_nyX;B2V(W|gS5+yt8Z*^Nq2XSTv}x-$zJpkw*>mP~q||pG->bO2(tUhc z{{Z82%&c-Mhe`A)qH_E-x^&@+&B_)#OK6#57tEQB&WlPma=j_ndL8CEViAvVdik8E&m~`e+8dIH}opAP4-!pI)wSNUOK{m1#wAuIpm_cl{ zKXNi2SNqy(fBvUreg^Vn%GPXKO48<|s?w>P6k8>OD`qdmCE4AXV{MVMy3As{gR*k( zW$lsgyUuIdoGCa=>qoehBP`73Ok3AyY?js4(#HI;>s_mIysoo+H}-<-+f75tw=sLA z{0kKB$`oAqrE3~kBH)K8q6xTa=0AsM-@lmIHjm7bzfcFGyuKlh)I6#}&R|D9D;u}A zznnH+#{X_S{C+3B4m*`NG%v@2gLkt7bb>~mow&@$C2=R+FT_vF?efr~tQ@B zG~w4MYgM$hrQPJ*;!sec{*-eny}B}rwu{QgDax7#M#+sfU$}eVRNi$eABf8Ln7Q(n z_FEk|O&N-|CU-W{*Yu(}ddw#0E_+`dB*xpzM!mjtf7gJdP5gBcHwV;;|HQ1aI|;{F z$4aA1$Hr}PcIoD!H|MX@IeImPj5f+Hh#FPsdMe9H9RWD0+Wy-@juS z9y%D0&)O#)jmMLr+3{rGTbS2mSsR*fLi?;4;eRFb zAOA7c*O~awfq#+|2edpopTyWLfXsREFN)gdb?_SV&ubEWDj9s~kjm-PCQWx#j1J2U zzCgVcUf}aKc%-62sc4whipt65rPbXl^J(YpmO?{ogvHnzL%}*9+{_CQ^QHY4l}g>8%c`4MDnW!`YT9Bj1t-L=!Ito3*}X6vqhQ*F@Wwbev? z4W8~b1!`HDwbdyP70ynY%}ESw(*hWzdZThqwl((qwD*-MMiuY&ot9=CASHHE|e zfjjC8)CJX!3i$2KlHum*f}zQ5FrVE!yA9W8SEH03t$M>Ccj{mge{l;-rR zXzsndSF7=!tQD;0GE};-H`You#IO4GRC(xlyL z6#xFPYFEmP@K5u{?Wmt`VB5y+{w3XRQgg56iC(Jle}GNN5!G*Ty8VP^HXb&9^lcWm zI}^Vy*l*$XyVCvg{+>#2(uMSH!l8@OwDk59o7pJHt_<56Zs$+8OVPOjb$idi?mpNR z;*d;fNxDBCm-KiU+g;r5(R8~soliAR8Y69Aa6f}m{7{za#$r3b>$T^tR7Z*G=VH^^ z<0eYCbh@}(P80Xz)5O)?pevv&pevv&pevv&pevv&pevv&pevv& z@c&f-vz7g(@0H7O7st;ydhmn)5^UQ0`8RWJJzHSuH=MWOMF>jkIM;5_y~H`an?vby z&I|GG5KFiTPX4!XZsxolFI`b8NbO5FzmRj0^Gi9esgN8t4YCX9Em6&WPD|7PkP6)v+969l{tE|}2g68=2}-4i3O zeXnsVariTHe{J9hcM`zTL-?P{A4}uUr1Aeq<1eN0jx_$~H2!`X|1^z%oyPa2@dIi6 zNE)Y`SgGUb4U)=9>r_4|S+00eBUb z;u<_D8Y~F;nZO~yE<7hDoP!&Ygx6!gC3JJ_fXuHNX=b=}ko9_v5%k zxE}tl1$F?30k45wF)$nb7!Dl3aVX-C0AIzi32S*IxPo?sE$9c~Uic-X7fuO3$`yoB zKm(35gvU{ieI@@Jv>OAw4)Jh*IsXx$9r!x@jsyO{@haF6{}lem11CUd!e=;!F>c}! zyw*YZHOK4l;tKJXInrxE#2@6?%dB#l<5wIj&r!?QbEH@4sNHssYtgR~@ImO014yr1 z5Qfoz!T{;-km>?bgAX5kN%iUnM|D9#YM`f$ zWxh}ao|FkvxBJlQqp+EHvgHc~rbhfV-q0^uRH@&7NsB{1*&B@DV~>;YC6u5AuzI{g2Yu*hZ9_1Oj?~o#}?=p7Fm$ydu4B65yM8GN09L7t|5res{CGmZQ~MPy~l?>`2B8#_tUdSKqSDZ z8ZPAJP4GRNCju)V?>TaK;0fIt7WpBu$BjC72!r)CphGF85%>=+!Dn4e<%G32;7PSj ziiP%J?!e=1zz|Y|#8+W5=77&03&L%fF6^_hbOSd1^idh9&6=psmAz8PTN}ZgF7j$h zur=Tc*49siT8zvHK(Qp9c@!2`8&)EA>S9bapr*4reJK-FfT!m8*bPt3z32jrL*9Ta(Hi0ti#>{ZT%aymDdeWLiNLCR z+VPN%?L503U+C2%t3ATP;ZDfFSqO(oDl_2lgM)xzI7TNX*w&&A>V=<#3=|m1R-n^x zAvW@XONP)%MN4 zvoO@_{`3FxcG005{qm*R{-)89!`qE5L;By-f5)wBUkI&ke{^g3g@1pb!TG1lZ(0BH z_d7P#4_bZcO2_U)V};IVb;N8b}nfv}ayujY;jokN} z%Kmxsqbshyev4Rh?xY13H%?l8NyT?35AS@o-?-HqXDiRW6AQ1AuW9<7so>+kV(=sb z8{Dy-3l}2)%GmKu{st>OR>#7(=iymbp4A(`^L)G)Vb7aUJu!b|-uQ8S#||o+R$4u~ zvfSE8hc;{Fj0rAhsWmU(W}^k_wb{z5%dC|yXH~ToK5Vw~sd?7C1+v^Y+Gbn4cyWQ7 ztO_6}8HR0@Ashih@)8%E<)cA?NA~0)jOx8xcTno_)yg)Yja859tIndqmokg{Fqm$$ zXw5i-S^Q?r*Ump=zW?jTUwH49?P1TCBVNA!H;@+`i zx9!V|hQGDJ|JEP3T>0)Be>eJqSk*4Lw$!ngQKJ{18 z*E%nJJpae{N30uAdi0KsMOPG^xZSZ!dMwa?&bo==CmRjtm(QqpuJ8I6+h2aY>GkN)Ri8Y(zj5ZJ9Y_AO+kfc7Ref*2 zbIRJevgxUH|N6+A`<~oTaNl)rKaly6!Le<}n_bs>X1~5+ + + + + files + + files2 + + rules + + ^Resources/ + + ^Resources/.*\.lproj/ + + optional + + weight + 1000 + + ^Resources/.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Resources/Base\.lproj/ + + weight + 1010 + + ^version.plist$ + + + rules2 + + .*\.dSYM($|/) + + weight + 11 + + ^(.*/)?\.DS_Store$ + + omit + + weight + 2000 + + ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/ + + nested + + weight + 10 + + ^.* + + ^Info\.plist$ + + omit + + weight + 20 + + ^PkgInfo$ + + omit + + weight + 20 + + ^Resources/ + + weight + 20 + + ^Resources/.*\.lproj/ + + optional + + weight + 1000 + + ^Resources/.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Resources/Base\.lproj/ + + weight + 1010 + + ^[^/]+$ + + nested + + weight + 10 + + ^embedded\.provisionprofile$ + + weight + 20 + + ^version\.plist$ + + weight + 20 + + + + diff --git a/stlinkv1_macos_driver/stlink_shield_xcode/stlink_shield.xcodeproj/project.pbxproj b/stlinkv1_macos_driver/stlink_shield_xcode/stlink_shield.xcodeproj/project.pbxproj index 373600c..4f2b802 100644 --- a/stlinkv1_macos_driver/stlink_shield_xcode/stlink_shield.xcodeproj/project.pbxproj +++ b/stlinkv1_macos_driver/stlink_shield_xcode/stlink_shield.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXFileReference section */ 8CD33C31149BB80D0033D618 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 8F9084FD24786F0F009109AD /* stlink_shield_10_14.kext */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = stlink_shield_10_14.kext; sourceTree = BUILT_PRODUCTS_DIR; }; 8F90850924786F39009109AD /* stlink_shield_10_15.kext */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = stlink_shield_10_15.kext; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -33,6 +34,7 @@ 19C28FB6FE9D52B211CA2CBB /* Products */ = { isa = PBXGroup; children = ( + 8F9084FD24786F0F009109AD /* stlink_shield_10_14.kext */, 8F90850924786F39009109AD /* stlink_shield_10_15.kext */, ); name = Products; @@ -58,6 +60,26 @@ /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ + 8F9084F324786F0F009109AD /* stlink_shield_10_14 */ = { + isa = PBXNativeTarget; + buildConfigurationList = 8F9084FA24786F0F009109AD /* Build configuration list for PBXNativeTarget "stlink_shield_10_14" */; + buildPhases = ( + 8F9084F424786F0F009109AD /* ShellScript */, + 8F9084F524786F0F009109AD /* Headers */, + 8F9084F624786F0F009109AD /* Resources */, + 8F9084F824786F0F009109AD /* Sources */, + 8F9084F924786F0F009109AD /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = stlink_shield_10_14; + productInstallPath = "$(SYSTEM_LIBRARY_DIR)/Extensions"; + productName = NanosMouse; + productReference = 8F9084FD24786F0F009109AD /* stlink_shield_10_14.kext */; + productType = "com.apple.product-type.kernel-extension.iokit"; + }; 8F9084FF24786F39009109AD /* stlink_shield_10_15 */ = { isa = PBXNativeTarget; buildConfigurationList = 8F90850624786F39009109AD /* Build configuration list for PBXNativeTarget "stlink_shield_10_15" */; @@ -98,6 +120,7 @@ projectDirPath = ""; projectRoot = ""; targets = ( + 8F9084F324786F0F009109AD /* stlink_shield_10_14 */, 8F9084FF24786F39009109AD /* stlink_shield_10_15 */, ); }; @@ -435,6 +458,24 @@ }; name = Release; }; + 8F9084FB24786F0F009109AD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = "-"; + MACOSX_DEPLOYMENT_TARGET = 10.14; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 8F9084FC24786F0F009109AD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = "-"; + MACOSX_DEPLOYMENT_TARGET = 10.14; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; 8F90850724786F39009109AD /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -465,6 +506,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 8F9084FA24786F0F009109AD /* Build configuration list for PBXNativeTarget "stlink_shield_10_14" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8F9084FB24786F0F009109AD /* Debug */, + 8F9084FC24786F0F009109AD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 8F90850624786F39009109AD /* Build configuration list for PBXNativeTarget "stlink_shield_10_15" */ = { isa = XCConfigurationList; buildConfigurations = ( From 5b320357a64458d102e190e4aeff2d58a3011e60 Mon Sep 17 00:00:00 2001 From: nightwalker-87 <15526941+Nightwalker-87@users.noreply.github.com> Date: Sat, 29 Jan 2022 17:56:26 +0100 Subject: [PATCH 2/3] Minor formatting fixes & clean-up --- CMakeLists.txt | 6 +- src/calculate.h | 2 +- src/common.h | 2 +- src/common_flash.h | 2 +- src/map_file.h | 2 +- src/{option.c => option_bytes.c} | 0 src/Описание.txt | 129 ------------------------------- 7 files changed, 7 insertions(+), 136 deletions(-) rename src/{option.c => option_bytes.c} (100%) delete mode 100644 src/Описание.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index a3338df..abfc0be 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ # General cmake settings ### -cmake_minimum_required(VERSION 3.7.2) +cmake_minimum_required(VERSION 3.10.2) cmake_policy(SET CMP0042 NEW) set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) @@ -127,8 +127,8 @@ set(STLINK_HEADERS set(STLINK_SOURCE src/read_write.c src/common.c - src/option.c - src/common_flash.c + src/option_bytes.c + src/common_flash.c src/map_file.c src/flashloader.c src/calculate.c diff --git a/src/calculate.h b/src/calculate.h index 68c1fb9..64dfb51 100644 --- a/src/calculate.h +++ b/src/calculate.h @@ -1,7 +1,7 @@ /* * File: calculate.h * - * TODO: add a description + * Calculation of sector numbers and pages */ #ifndef CALCULATE_H diff --git a/src/common.h b/src/common.h index 6c22d58..dd6cf95 100644 --- a/src/common.h +++ b/src/common.h @@ -1,7 +1,7 @@ /* * File: common.h * - * TODO: add a description + * General helper functions */ #ifndef COMMON_H diff --git a/src/common_flash.h b/src/common_flash.h index 70a6f0e..3b6b040 100644 --- a/src/common_flash.h +++ b/src/common_flash.h @@ -1,7 +1,7 @@ /* * File: common_flash.h * - * TODO: add a description + * Flash operations */ #ifndef COMMON_FLASH_H diff --git a/src/map_file.h b/src/map_file.h index 9cdd745..f50a201 100644 --- a/src/map_file.h +++ b/src/map_file.h @@ -1,7 +1,7 @@ /* * File: map_file.h * - * TODO: add a description + * File mapping */ #ifndef MAP_FILE_H diff --git a/src/option.c b/src/option_bytes.c similarity index 100% rename from src/option.c rename to src/option_bytes.c diff --git a/src/Описание.txt b/src/Описание.txt deleted file mode 100644 index d4111a8..0000000 --- a/src/Описание.txt +++ /dev/null @@ -1,129 +0,0 @@ ---------------------------------------------------------------------------------- -Файл info.c: - -main: -- проверяю количество параметров -- инициализирую список структур devicelist, объявленный в файле chipid.c -- вызываю функцию print_data (и передаю ей параметры программы). - -print_data: -Смотрю, какие параметры переданы программе. -Если параметр --probe - вызываю функцию stlink_probe с параметрами по умолчанию -(connect: NORMAL, freq: 0) - -stlink_probe: -Объявляю список структур для каждого подключенного ST-LINK'a -(stdevs: указатель на список указателей, указывающих на структуры). -Вызываю stlink_probe_usb с параметрами: -- адрес stdevs'а (тройной указатель), -- connect, -- freq - -Функция stlink_probe_usb заполняет stdevs и возвращает его размер. -Для каждого указателя вызываю функцию stlink_print_info. - -Потом освобождаю память, отведённую под stdevs. - -stlink_print_info: просто печатаю в терминал информацию из переданной структуры -ST-LINK'а. - ---------------------------------------------------------------------------------- -Файл usb.c: - -stlink_probe_usb: -Инициализирую libusb -Получаю список USB-устройств (libusb_get_device_list). -Для полученного списка вызываю функцию stlink_probe_usb_devs. -Передаю ей: -- указатель на список указателей на структуры libusb_device (двойной указатель) devs -- адрес указателя на список указателей на структуры ST-LINK (тройной указатель) sldevs -- connect, freq. -Потом освобождаю память, занятую структурами libusb_device. -Список указателей на структуры ST-LINK возвращаю на выход (в функцию stlink_probe). - -stlink_probe_usb_devs: -Определяю количество подключенных ST-LINK'ов: -Прохожу по списку USB-устройств. -Для каждого USB-устройства получаю дескриптор desc. -Если в дескрипторе указаны idVendor и idProduct, соответствующие ST-LINK'у - увеличиваю счётчик. -Выделяю память под нужное количество структур ST-LINK'ов. - -Ещё раз прохожу по списку USB-устройств и получаю дескриптор каждого. -Если idProduct соответствует ST-LINK'у: -- открываю ST-LINK (libusb_open), -- читаю его серийник (stlink_serial); -- закрываю (libusb_close). - -Если длина серийника правильная - открываю его функцией stlink_open_usb. -Она возвращает ссылку на структуру stlink_t. Пристёгиваю эту ссылку к списку структур. -Перехожу к следюущему USB-устройству. Потом записываю ссылку на список структур stlink_t -в указатель и возвращаю количество структур по списку. - -stlink_serial: -Получаю дескриптор нулевой строки USB-устройства, беру из него LANGID (libusb_get_string_descriptor). -Получаю дескриптор строки серийника (для него нужен LANGID) (libusb_get_string_descriptor). -Если серийник длиной 50 символов - беру его же в формате ascii. -Если серийник длиной 26 символов - для каждого символа выполняю строку: -sprintf(serial + i, "%02X", desc_serial[i + 2]) -В конце ставлю ноль. -Возвращаю длину серийника и сам серийник, записанный в память по адресу из параметра. - -stlink_open_usb: -Выделяю в куче память под структуры sl (stlink_t) и slu (stlink_libusb). -Записываю в sl ссылку на список каких-то функций и ссылку на slu, указываю статус ядра -целевого MCU: TARGET_UNKNOWN. -Инициализирую libusb с контекстом, указываю LOG_LEVEL. -Получаю список USB-устройств. -Для каждого устройства получаю дескриптор и проверяю его idVendor. -Открываю устройство и пытаюсь получить серийник. -Если не получил серийник либо получил серийник, соответствующий заданному в параметре - -- выставляю в структуре sl версию и протокол по idProduct, после чего заканчиваю просмотр -устройств USB. - -Просмотрев все устройства, открываю найденный ST-LINK и освобождаю память, занятую -списком USB-устройств. - -Читаю конфигурацию ST-LINK'а, потом устанавливаю её. Делаю заявку на интерфейс (libusb_claim_interface). -Потом выставляю поля ep_rep, ep_req, ep_trace, sg_transfer_idx и cmd_len. -Инициализирую версию ST-LINK'а (stlink_version). -Получаю режим работы ST-LINK'а. Если он в режиме dfu - выхожу из него. -Если CONNECT_UNDER_RESET: выхожу из debug mode, если в нём. Выполняю JTAG reset. -Выставляю поле freq по параметру функции, устанавливаю SWD clock (_stlink_usb_set_swdclk). -Выполняю stlink_target_connect и возвращаю структуру sl. - -_stlink_usb_version: -Заполняю структуру stlink командой fill_command (по-разному для ST-LINK v. 3 и предыдущих версий) -Выполняю функцию send_recv - - -_stlink_usb_current_mode: -Заполняю структуру stlink командой fill_command, ставлю в i-тую позицию команду STLINK_GET_CURRENT_MODE -Вызываю функцию send_recv -Возвращаю первый символ буфера, или -1 при ошибке. - -_stlink_usb_exit_debug_mode, _stlink_usb_exit_debug_mode: -Заполняю структуру stlink командой fill_command, ставлю в i-тую позицию команды: -STLINK_DFU_COMMAND -STLINK_DFU_EXIT -Вызываю функцию send_only -Возвращаю 0, или -1 при ошибке. -То же самое для debug - -fill_command: -Для ST-LINK v. 1 заполняю поле c_buf структуры stlink. Для всех остальных заполняю его нулями. - -send_recv: -Отправляю функцией libusb_bulk_transfer данные в параметре txbuf и команду в cmd. -Проверяю ответ на ошибки и если указан rxsize - принимаю данные той же функцией. -Возвращаю количество принятого после проверки на ошибки. - ---------------------------------------------------------------------------------- -Файл common.c: - -stlink_version: -Запускаю функцию version из backend (вызывается _stlink_usb_version из usb.c) -Выполняю _parse_version. - -stlink_current_mode: -возвращаю результат выполнения функции sl->backend->current_mode(sl) после проверки на ошибки. -При этом запускается функция _stlink_usb_current_mode. \ No newline at end of file From 0011064797cd710f9b684e07c0083b5464e9a031 Mon Sep 17 00:00:00 2001 From: nightwalker-87 <15526941+Nightwalker-87@users.noreply.github.com> Date: Sun, 30 Jan 2022 15:47:55 +0100 Subject: [PATCH 3/3] Rolled-back deletion of recent changes --- CHANGELOG.md | 18 +- README.md | 2 +- cmake/modules/Findlibusb.cmake | 2 +- cmake/packaging/cpack_config.cmake | 2 +- cmake/packaging/deb/control | 2 +- contributors.txt | 3 + doc/compiling.md | 4 +- doc/version_support.md | 155 +- inc/stlink.h | 3 +- inc/stm32.h | 8 +- src/stlink-lib/chipid.h | 3 +- src/stlink-lib/usb.c.bak | 1410 ----------------- src/win32/unistd/unistd.h | 2 +- src/win32/unistd/unistd.h.bak | 76 - stlinkv1_macos_driver/install.sh | 3 - .../Contents/Info.plist | 82 - .../Contents/MacOS/stlink_shield_10_14 | Bin 33840 -> 0 bytes .../stlink_shield_10_14.kext/Contents/PkgInfo | 1 - .../Contents/_CodeSignature/CodeResources | 115 -- .../stlink_shield.xcodeproj/project.pbxproj | 50 - 20 files changed, 113 insertions(+), 1828 deletions(-) delete mode 100644 src/stlink-lib/usb.c.bak delete mode 100644 src/win32/unistd/unistd.h.bak delete mode 100644 stlinkv1_macos_driver/stlink_shield_10_14.kext/Contents/Info.plist delete mode 100644 stlinkv1_macos_driver/stlink_shield_10_14.kext/Contents/MacOS/stlink_shield_10_14 delete mode 100644 stlinkv1_macos_driver/stlink_shield_10_14.kext/Contents/PkgInfo delete mode 100644 stlinkv1_macos_driver/stlink_shield_10_14.kext/Contents/_CodeSignature/CodeResources diff --git a/CHANGELOG.md b/CHANGELOG.md index 06f995d..71188af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,10 +2,14 @@ # v1.7.1 -Release date: 2021-xx-xx +Release date: 2022-xx-xx This release drops support for some older operating systems. Check project README for details. -Updated system requirements: Raised minimum version for `cmake` to 3.7.2. + +Updated system requirements: +- `cmake` >= 3.10.2 +- `libusb` >= 1.0.21 +- `libgtk-dev` >= 3.22.30 Features: @@ -15,6 +19,9 @@ Features: - Expanded and revised list of chips ([#1145](https://github.com/stlink-org/stlink/pull/1145), [#1164](https://github.com/stlink-org/stlink/pull/1164)) - [STM32H72X/3X]: Added full access to all device memory ([#1158](https://github.com/stlink-org/stlink/pull/1158), [#1159](https://github.com/stlink-org/stlink/pull/1159)) - Added support for STM32WLEx ([#1173](https://github.com/stlink-org/stlink/pull/1173)) +- Added support for STLINK-V3 devices with no MSD ([#1185](https://github.com/stlink-org/stlink/pull/1185)) +- Updated gdb-server.c to allow external memory access on STM32H73xx ([#1196](https://github.com/stlink-org/stlink/pull/1196), [#1197](https://github.com/stlink-org/stlink/pull/1197)) +- Erase addr size / section of the flash memory with st-flash ([#1213](https://github.com/stlink-org/stlink/pull/1213)) Updates & changes: @@ -22,10 +29,12 @@ Updates & changes: - Added instructions for bug-reports and feature-requests to contribution guidelines ([#906](https://github.com/stlink-org/stlink/pull/906)) - Added travis CI configuration for macOS 10.14 to maintain capability for 32-bit compilation ([#f5ada94](https://github.com/stlink-org/stlink/commit/f5ada9474cdb87ff37de0d4eb9e75622b5870646)) - Updated description of chip id 0x0457 to L01x/L02x ([#1143](https://github.com/stlink-org/stlink/pull/1143), [#1144](https://github.com/stlink-org/stlink/pull/1144)) -- Drop execute bits from source code files ([#1167](https://github.com/stlink-org/stlink/pull/1167)) +- Dropped execute bits from source code files ([#1167](https://github.com/stlink-org/stlink/pull/1167)) - Use proper Markdown headers for supported MCUs ([#1168](https://github.com/stlink-org/stlink/pull/1168)) - Removed redundant array ([#1178](https://github.com/stlink-org/stlink/pull/1178)) - Updated chip config files from the library structs ([#1181](https://github.com/stlink-org/stlink/pull/1181)) +- [doc] Corrected file path in tutorial ([#1186](https://github.com/stlink-org/stlink/pull/1186)) +- Improved chipid checks and printouts ([#1188](https://github.com/stlink-org/stlink/pull/1188)) Fixes: - cmake: Install shared libraries in proper directories ([#1142](https://github.com/stlink-org/stlink/pull/1142)) @@ -41,6 +50,9 @@ Fixes: - Fixed few warnings for msvc about type conversion with possible lost data ([#1179](https://github.com/stlink-org/stlink/pull/1179)) - st-flash and other utilities search for chip files in the wrong directory ([#1180](https://github.com/stlink-org/stlink/pull/1180), commit [#c8fc656](https://github.com/stlink-org/stlink/commit/c8fc6561fead79ad49c09d82bab864745086792c)) - Fixed broken build on 32 bit systems ([#985](https://github.com/stlink-org/stlink/pull/985), [#1175](https://github.com/stlink-org/stlink/pull/1175), commit [#c8fc656](https://github.com/stlink-org/stlink/commit/c8fc6561fead79ad49c09d82bab864745086792c)) +- Define 'SSIZE_MAX' if not defined ([#1183](https://github.com/stlink-org/stlink/pull/1183)) +- Fixed compliation for OpenBSD 7.0 ([#1202](https://github.com/stlink-org/stlink/pull/1202)) +- Included 'SSIZE_MAX' from 'limits.h' in 'src/common.c' ([#1207](https://github.com/stlink-org/stlink/pull/1207)) # v1.7.0 diff --git a/README.md b/README.md index 7f797a7..bc49118 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ It supports several so called STLINK programmer boards (and clones thereof) whic - stand-alone programmer (STLINK-V3SET, STLINK-V3MINI, STLINK-V3MODS) - on-board on some STM32 Nucleo boards (STLINK-V3E) -_\*)_ **Note: Support for the STLINK/V1 on macOS is limited to 10.14 - 10.15. Due to the deprecation and removal of macOS Kernel Extensions (KEXT) there will be no support for this programmer on macOS 11 or any later version.** +_\*)_ *Note: Support for the STLINK/V1 on macOS is limited to 10.15. Due to the deprecation and removal of macOS Kernel Extensions (KEXT) there will be no support for this programmer on macOS 11 or any later version.* On the user level there is no difference in handling or operation between these different revisions. diff --git a/cmake/modules/Findlibusb.cmake b/cmake/modules/Findlibusb.cmake index cd52026..bc04f84 100644 --- a/cmake/modules/Findlibusb.cmake +++ b/cmake/modules/Findlibusb.cmake @@ -72,7 +72,7 @@ elseif (WIN32 OR (EXISTS "/etc/debian_version" AND MINGW)) # Windows or MinGW-to if (WIN32 AND NOT EXISTS "/etc/debian_version") # Skip this for Debian... # Preparations for installing libusb library - set(LIBUSB_WIN_VERSION 1.0.23) # set libusb version + set(LIBUSB_WIN_VERSION 1.0.24) # set libusb version set(LIBUSB_WIN_ARCHIVE libusb-${LIBUSB_WIN_VERSION}.7z) if (WIN32 AND NOT EXISTS "/etc/debian_version") # ... on native Windows systems set(LIBUSB_WIN_ARCHIVE_PATH ${CMAKE_BINARY_DIR}/${LIBUSB_WIN_ARCHIVE}) diff --git a/cmake/packaging/cpack_config.cmake b/cmake/packaging/cpack_config.cmake index acd5630..587ff5f 100644 --- a/cmake/packaging/cpack_config.cmake +++ b/cmake/packaging/cpack_config.cmake @@ -53,7 +53,7 @@ elseif (EXISTS "/etc/debian_version" AND NOT EXISTS WIN32) # Package-build is av set(CPACK_DEBIAN_PACKAGE_RELEASE "1") # CPACK_DEBIAN_PACKAGE_ARCHITECTURE --> Default: Output of dpkg --print-architecture - set(CPACK_DEBIAN_PACKAGE_DEPENDS "pkg-config, build-essential, debhelper (>=9), cmake (>= 3.4.2), libusb-1.0-0-dev (>= 1.0.20)") + set(CPACK_DEBIAN_PACKAGE_DEPENDS "pkg-config, build-essential, debhelper (>=9), cmake (>= 3.10.2), libusb-1.0-0-dev (>= 1.0.21)") set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Nightwalker-87 ") # CPACK_DEBIAN_PACKAGE_DESCRIPTION --> Default: CPACK_DEBIAN_PACKAGE_DESCRIPTION (as it is set) # CPACK_DEBIAN_PACKAGE_SECTION --> Default: “devel” diff --git a/cmake/packaging/deb/control b/cmake/packaging/deb/control index ef51a6c..7c8d13e 100644 --- a/cmake/packaging/deb/control +++ b/cmake/packaging/deb/control @@ -1,7 +1,7 @@ Source: stlink Priority: optional Maintainer: Nightwalker-87 -Build-Depends: cmake, dh-cmake, debhelper (>= 9), libusb-1.0-0-dev, libgtk-3-dev +Build-Depends: cmake (>= 3.10.2), dh-cmake, debhelper (>= 9), libusb-1.0-0-dev (>= 1.0.21), libgtk-3-dev (>= 3.22.30) Standards-Version: 4.5.0 Rules-Requires-Root: no Section: electronics diff --git a/contributors.txt b/contributors.txt index bcaa0b5..cffef89 100644 --- a/contributors.txt +++ b/contributors.txt @@ -7,6 +7,8 @@ Andrea Mucignat Andrew Andrianov [necromant] Andrey Yurovsky Andy Isaacson +Andreas Sandberg [andysan] +Antoine Faure [antoinefaure] Anton [Ant-ON] Áron Radics A. Sheaff @@ -24,6 +26,7 @@ Chris Samuelson Christian Deussen [nullsub] Christophe Levantis Craig Lilley +Crest [Crest] Dan Dev Dan Hepler Daniel Campoverde [alx741] diff --git a/doc/compiling.md b/doc/compiling.md index eef207f..0931c27 100644 --- a/doc/compiling.md +++ b/doc/compiling.md @@ -7,7 +7,7 @@ On Windows users should ensure that the following software is installed: - `git` (_optional, but recommended_) -- `cmake` (3.17.0 or later) +- `cmake` - `MinGW-w64` (7.0.0 or later) with GCC toolchain 8.1.0 ### Installation @@ -95,7 +95,7 @@ Install the following packages from your package repository: - `git` - `gcc` or `clang` or `mingw32-gcc` or `mingw64-gcc` (C-compiler; very likely gcc is already present) - `build-essential` (on Debian based distros (Debian, Ubuntu)) -- `cmake` (3.4.2 or later, use the latest version available from the repository) +- `cmake` - `rpm` (on Debian based distros (Debian, Ubuntu), needed for package build with `make package`) - `libusb-1.0` - `libusb-1.0-0-dev` (development headers for building) diff --git a/doc/version_support.md b/doc/version_support.md index 2c5df74..d7ba5c1 100644 --- a/doc/version_support.md +++ b/doc/version_support.md @@ -1,97 +1,104 @@ -_Source:_ pkgs.org - [libusb](https://pkgs.org/search/?q=libusb); [cmake](https://pkgs.org/search/?q=cmake); [gtk](https://pkgs.org/search/?q=gtk) (as of May 2021) +_Source:_ [pkgs.org](https://pkgs.org/search) - libusb, cmake, gtk, libgtk) (as of Jan 2022) ## Supported Operating Systems ### Microsoft Windows -On Windows users should ensure that cmake 3.20.2 or any later version is installed.
-Up on compiling c-make will **automatically** download and install the latest compatible version of `libusb` (1.0.23 at the time of writing). +On Windows users should ensure that cmake **3.10.2** or any later version is installed.
+Up on compiling c-make will **automatically** download and install the latest compatible version of `libusb`. - Windows 10 - Windows 8.1 ### Apple macOS -| Package Repository | libusb
version | cmake
version | gtk-3
version | Supported macOS versions | -| ------------------ | ------------------- | ------------------ | ------------------ | ------------------------ | -| homebrew | 1.0.24 | 3.20.2 | 3.24.29
gtk+3 | 10.9 - 11.x | -| MacPorts | 1.0.24 | 3.20.2 | 3.24.29
gtk3 | 10.4 - 11.x | +| Package Repository | libusb | cmake | gtk-3-dev | Supported macOS versions | +| ------------------ | ------ | ------ | ------------------ | ------------------------ | +| homebrew | 1.0.24 | 3.22.1 | 3.24.30
gtk+3 | **10.10 - 12.x** | +| MacPorts | 1.0.24 | 3.22.1 | 3.24.31
gtk3 | **10.4 - 12.x** | -NOTE: In order to use a STLINK/V1 programmer on macOS, versions 10.14 or 10.15 are required. +NOTE: In order to use a STLINK/V1 programmer on macOS, version 10.15 is required. ### Linux-/Unix-based: -| Operating System | libusb | cmake | gtk-3 | Notes | -| ------------------------- | -------------------------------- | --------- | ----------- | ------------------------ | -| Debian Sid | 1.0.24 | 3.18.4 | 3.24.24 | | -| Debian 11 (Bullseye) | 1.0.24 | 3.18.4 | 3.24.24 | | -| Debian 10 (Buster) | 1.0.**22** | 3.13.4 | 3.24.**5** | | -| Debian 9 (Stretch) | 1.0.**21** | **3.7.2** | **3.22.11** | End of Support: Jun 2022 | -| | | | | | -| Ubuntu 21.04 (Hirsute) | 1.0.24 | 3.18.4 | 3.24.25 | End of Support: Jan 2022 | -| Ubuntu 20.04 LTS (Focal) | 1.0.23 | 3.16.3 | 3.24.**18** | | -| Ubuntu 18.04 LTS (Bionic) | 1.0.**21** | 3.10.2 | **3.22.30** | End of Support: Apr 2023 | -| | | | | | -| Fedora Rawhide [x64] | 1.0.24 (`libusbx`) | 3.20.2 | 3.24.29 | | -| Fedora 34 [x64] | 1.0.24 (`libusbx`) | 3.19.7 | 3.24.28 | | -| Fedora 33 [x64] | 1.0.23 (`libusbx`) | 3.18.3 | 3.24.23 | | -| | | | | | -| openSUSE Tumbleweed [x64] | 1.0.24 | 3.20.1 | 3.24.29 | | -| openSUSE Leap 15.3 [x64] | 1.0.**21** | 3.17.0 | 3.24.20 | | -| openSUSE Leap 15.2 [x64] | 1.0.**21** | 3.17.0 | 3.24.**14** | End of Support: Dec 2021 | -| | | | | | -| Alpine 3.14 | 1.0.24 | 3.20.3 | 4.2.1 | | -| Alpine 3.13 | 1.0.24 | 3.18.4 | 3.24.23 | End of Support: Nov 2022 | -| Alpine 3.12 | 1.0.23 | 3.17.2 | 3.24.22 | End of Support: May 2022 | -| Alpine 3.11 | 1.0.23 | 3.15.5 | 3.24.**13** | End of Support: Nov 2021 | -| | | | | | -| FreeBSD 13.x | 1.0.**16 - 18** (API 0x01000102) | 3.20.2 | 3.24.27 | | -| FreeBSD 12.x | 1.0.**16 - 18** (API 0x01000102) | 3.19.6 | 3.24.27 | | -| FreeBSD 11.x | 1.0.**16 - 18** (API 0x01000102) | 3.15.5 | 3.24.27 | End of Support: Sep 2021 | -| | | | | | -| Arch Linux | 1.0.24 | 3.20.2 | 3.24.29 | | -| KaOS [x64] | 1.0.24 | 3.20.2 | 3.24.29 | | -| Mageia Cauldron | 1.0.24 | 3.20.2 | 3.24.29 | | -| OpenMandriva Cooker | 1.0.24 | 3.20.2 | 3.24.29 | | -| PCLinuxOS [x64] | 1.0.24 | 3.20.2 | 3.24.29 | | -| Slackware Current | 1.0.24 | 3.20.2 | 3.24.28 | | -| Solus [x64] | 1.0.24 | 3.20.2 | 3.24.29 | | -| ALT Linux Sisyphus | 1.0.24 | 3.19.7 | 3.24.29 | | -| NetBSD 9.x | 1.0.24 | 3.19.7 | 3.24.27 | | -| NetBSD 8.x | 1.0.24 | 3.19.7 | 3.24.27 | | -| OpenMandriva Lx 4.2 | 1.0.24 | 3.19.3 | 3.24.24 | | -| Mageia 8 | 1.0.24 | 3.19.2 | 3.24.24 | End of Support: Aug 2022 | -| CentOS 8 Stream [x64] | 1.0.23 (`libusbx`) | 3.18.2 | **3.22.30** | | -| Adélie 1.0 | 1.0.23 | 3.16.4 | 3.24.23 | | -| ALT Linux P9 | 1.0.**22** | 3.16.3 | 3.24.**11** | | -| AlmaLinux 8 | 1.0.23 (`libusbx`) | 3.11.4 | 3.24.32 | | -| CentOS 8 [x64] | 1.0.23 (`libusbx`) | 3.11.4 | **3.22.30** | End of Support: Dec 2021 | +| Operating System | libusb | cmake | libgtk-dev | Notes | +| ------------------------- | ------------------------------ | ---------- | ----------- | ------------------------ | +| Debian Sid | 1.0.24 | 3.22.1 | 3.24.31 | | +| Debian 11 (Bullseye) | 1.0.24 | 3.18.4 | 3.24.24 | | +| Debian 10 (Buster) | 1.0.**22** | **3.13.4** | 3.24.**5** | | +| | | | | | +| Ubuntu 20.04 LTS (Focal) | 1.0.23 | 3.16.3 | 3.24.**18** | | +| Ubuntu 18.04 LTS (Bionic) | 1.0.**21** | **3.10.2** | 3.**22.30** | End of Support: Apr 2023 | +| | | | | | +| Fedora Rawhide [x64] | 1.0.24 | 3.22.3 | 3.24.31 | | +| Fedora 35 [x64] | 1.0.24 | 3.21.3 | 3.24.30 | | +| Fedora 34 [x64] | 1.0.24 (`libusbx`) | 3.19.7 | 3.24.28 | | +| | | | | | +| openSUSE Tumbleweed [x64] | 1.0.24 | 3.22.1 | 3.24.31 | | +| openSUSE Leap 15.3 [x64] | 1.0.**21** | 3.17.0 | 3.24.20 | End of Support: Dec 2022 | +| | | | | | +| Alpine 3.15 | 1.0.24 | 3.21.3 | 3.24.30 | | +| Alpine 3.14 | 1.0.24 | 3.20.3 | 3.24.28 | | +| Alpine 3.13 | 1.0.24 | 3.18.4 | 3.24.23 | End of Support: Nov 2022 | +| Alpine 3.12 | 1.0.23 | 3.17.2 | 3.24.22 | End of Support: May 2022 | +| | | | | | +| FreeBSD 13.x | 1.0.**16-18** (API 0x01000102) | 3.22.1 | 3.24.31 | | +| FreeBSD 12.x | 1.0.**16-18** (API 0x01000102) | 3.22.1 | 3.24.31 | | +| | | | | | +| NetBSD 9.x | 1.0.24 | 3.21.2 | 3.24.30 | | +| NetBSD 8.x | 1.0.24 | 3.19.7 | 3.24.27 | | +| | | | | | +| CentOS 9 Stream [x64] | 1.0.24 (`libusbx`) | 3.20.3 | 3.24.30 | | +| CentOS 8 Stream [x64] | 1.0.23 (`libusbx`) | 3.20.2 | 3.**22.30** | | +| | | | | | +| ALT Linux Sisyphus | 1.0.24 | 3.22.1 | 3.24.31 | | +| ALT Linux P10 | 1.0.24 | 3.20.5 | 3.24.31 | | +| ALT Linux P9 | 1.0.**22** | 3.16.3 | 3.24.29 | | +| | | | | | +| OpenMandriva Rolling | 1.0.24 | 3.22.1 | 3.24.31 | | +| OpenMandriva Cooker | 1.0.24 | 3.22.1 | 3.24.31 | | +| OpenMandriva Lx 4.2 | 1.0.24 | 3.19.3 | 3.24.24 | | +| | | | | | +| Arch Linux | 1.0.24 | 3.22.1 | - | | +| KaOS [x64] | 1.0.24 | 3.22.1 | 3.24.31 | | +| Mageia Cauldron | 1.0.24 | 3.22.1 | 3.24.31 | | +| PCLinuxOS [x64] | ? | 3.22.1 | 3.24.31 | | +| Solus [x64] | 1.0.24 | 3.22.1 | 3.24.30 | | +| Void Linux | 1.0.24 | 3.22.1 | 3.24.31 | | +| Slackware Current | 1.0.24 | 3.21.4 | 3.24.31 | | +| AlmaLinux 8 | 1.0.23 (`libusbx`) | 3.20.2 | 3.**22.30** | | +| Rocky Linux 8 [x64] | 1.0.23 | 3.20.2 | 3.**22.30** | | +| Mageia 8 | 1.0.24 | 3.19.2 | 3.24.24 | End of Support: Aug 2022 | +| Adélie 1.0 | 1.0.23 | 3.16.4 | 3.24.23 | | ## Unsupported Operating Systems (as of Release v1.7.1) Systems with highlighted versions remain compatible with this toolset. -| Operating System | libusb | cmake | End of
OS-Support | -| ------------------------- | ---------------------- | ---------- | ---------------------- | -| Fedora 32 [x64] | **1.0.23** (`libusbx`) | **3.17.0** | May 2021 | -| Ubuntu 20.10 (Groovy) | **1.0.23** | **3.16.3** | Jul 2021 | -| NetBSD 7.x | **1.0.22** | **3.16.1** | Jun 2020 | -| Alpine 3.10 | **1.0.22** | **3.14.5** | May 2021 | -| Fedora 31 [x64] | **1.0.22** (`libusbx`) | **3.14.5** | Nov 2020 | -| Mageia 7.1 | **1.0.22** | **3.14.3** | Jun 2021 | -| Fedora 30 | **1.0.22** (`libusbx`) | **3.14.2** | May 2020 | -| Ubuntu 19.10 (Eoan) | **1.0.23** | **3.13.4** | Jul 2020 | -| Alpine 3.9 | **1.0.22** | **3.13.0** | Jan 2021 | -| openSUSE Leap 15.1 [x64] | **1.0.21** | **3.10.2** | Jan 2021 | -| Slackware 14.2 | 1.0.20 | 3.5.2 | | -| Ubuntu 16.04 LTS (Xenial) | 1.0.20 | 3.5.1 | Apr 2021 | -| OpenMandriva Lx 3.0x | 1.0.20 | 3.4.2 | | -| Debian 8 (Jessie) | 1.0.19 | 3.0.2 | Jun 2020 | -| CentOS 7 [x64] | 1.0.21 (`libusbx`) | 2.8.12.2 | Jun 2024 | -| Ubuntu 14.04 LTS (Trusty) | 1.0.17 | 2.8.12.2 | Apr 2019 | -| CentOS 6 | 1.0.9 (`libusbx`) | 2.8.12.2 | Nov 2020 | -| Slackware 14.1 | 1.0.9 | 2.8.12 | | -| Slackware 14.0 | 1.0.9 | 2.8.8 | | +| Operating System | libusb | cmake | End of
OS-Support | +| ------------------------ | ------------------------------ | ---------- | ---------------------- | +| CentOS 8 [x64] | 1.0.**23** (`libusbx`) | 3.**20.3** | Dec 2021 | +| Ubuntu 21.04 (Hirsute) | 1.0.**24** | 3.**18.4** | Jan 2022 | +| Fedora 33 [x64] | 1.0.**23** (`libusbx`) | 3.**18.3** | Nov 2021 | +| Fedora 32 [x64] | 1.0.**23** (`libusbx`) | 3.**17.0** | May 2021 | +| openSUSE Leap 15.2 [x64] | 1.0.**21** | 3.**17.0** | Dec 2021 | +| Ubuntu 20.10 (Groovy) | 1.0.**23** | 3.**16.3** | Jul 2021 | +| NetBSD 7.x | 1.0.**22** | 3.**16.1** | Jun 2020 | +| Alpine 3.11 | 1.0.**23** | 3.**15.5** | Nov 2021 | +| FreeBSD 11.x | 1.0.**16-18** (API 0x01000102) | 3.**15.5** | Sep 2021 | +| Alpine 3.10 | 1.0.**22** | 3.**14.5** | May 2021 | +| Fedora 31 [x64] | 1.0.**22**(`libusbx`) | 3.**14.5** | Nov 2020 | +| Mageia 7.1 | 1.0.**22** | 3.**14.3** | Jun 2021 | +| Fedora 30 | 1.0.**22**(`libusbx`) | 3.**14.2** | May 2020 | +| Ubuntu 19.10 (Eoan) | 1.0.**23** | 3.**13.4** | Jul 2020 | +| Alpine 3.9 | 1.0.**22** | 3.**13.0** | Jan 2021 | +| openSUSE Leap 15.1 [x64] | 1.0.**21** | 3.**10.2** | Jan 2021 | +| Debian 9 (Stretch) | 1.0.**21** | 3.7.2 | Jun 2022 | +| Slackware 14.2 | 1.0.20 | 3.5.2 | | +| OpenMandriva Lx 3.0x | 1.0.20 | 3.4.2 | | +| CentOS 7 [x64] | 1.0.**21** (`libusbx`) | 2.8.12.2 | Jun 2024 | +| Slackware 14.1 | 1.0.9 | 2.8.12 | | +| Slackware 14.0 | 1.0.9 | 2.8.8 | | _All other operating systems which are not listed are unsupported._ diff --git a/inc/stlink.h b/inc/stlink.h index 7dfd8a7..17601fd 100644 --- a/inc/stlink.h +++ b/inc/stlink.h @@ -1,6 +1,7 @@ /* * File: stlink.h + * * This should contain all the common top level stlink interfaces, * regardless of how the backend does the work.... */ @@ -184,7 +185,7 @@ enum run_type { typedef struct _stlink stlink_t; -#include // Is it really need? +#include #include struct _stlink { diff --git a/inc/stm32.h b/inc/stm32.h index 19ba3fc..473f65a 100644 --- a/inc/stm32.h +++ b/inc/stm32.h @@ -149,11 +149,11 @@ enum stm32_chipids { /* ============ */ /* Constant STM32 memory address */ -#define STM32_SRAM_BASE ((uint32_t)0x20000000) -#define STM32_FLASH_BASE ((uint32_t)0x08000000) +#define STM32_SRAM_BASE ((uint32_t)0x20000000) +#define STM32_FLASH_BASE ((uint32_t)0x08000000) -#define STM32_F1_FLASH_BANK2_BASE ((uint32_t)0x08080000) -#define STM32_H7_FLASH_BANK2_BASE ((uint32_t)0x08100000) +#define STM32_F1_FLASH_BANK2_BASE ((uint32_t)0x08080000) +#define STM32_H7_FLASH_BANK2_BASE ((uint32_t)0x08100000) #define STM32F0_DBGMCU_CR 0xE0042004 #define STM32F0_DBGMCU_CR_IWDG_STOP 8 diff --git a/src/stlink-lib/chipid.h b/src/stlink-lib/chipid.h index f8e1b34..1eae2cc 100644 --- a/src/stlink-lib/chipid.h +++ b/src/stlink-lib/chipid.h @@ -4,8 +4,7 @@ #include #include - -/** Chipid parameters */ +/* Chipid parametres */ struct stlink_chipid_params { char *dev_type; char *ref_manual_id; diff --git a/src/stlink-lib/usb.c.bak b/src/stlink-lib/usb.c.bak deleted file mode 100644 index 32ceff7..0000000 --- a/src/stlink-lib/usb.c.bak +++ /dev/null @@ -1,1410 +0,0 @@ -#include -#include -#include -#include -#include - -#if !defined(_MSC_VER) -#include -#endif - -#include -#include -#include - -#if defined(_WIN32) -#include -#endif - -#include -#include -#include "usb.h" - -enum SCSI_Generic_Direction {SG_DXFER_TO_DEV = 0, SG_DXFER_FROM_DEV = 0x80}; - -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)); -} - -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; - bool match = true; - - for (i = 0; i < map_size; i++) { - if (!map[i]) { continue; } - - last_valid_speed = i; - - if (khz == map[i]) { - speed_index = i; - break; - } else { - int current_diff = khz - map[i]; - // get abs value for comparison - current_diff = (current_diff > 0) ? current_diff : -current_diff; - - if (current_diff < speed_diff) { - speed_diff = current_diff; - speed_index = i; - } - } - } - - if (speed_index == -1) { - // This will only be here if we cannot match the slow speed. - // Use the slowest speed we support. - speed_index = last_valid_speed; - match = false; - } else if (i == map_size) { - match = false; - } - - if (!match) { - ILOG("Unable to match requested speed %d kHz, using %d kHz\n", khz, map[speed_index]); - } - - return(speed_index); -} - -void _stlink_usb_close(stlink_t* sl) { - if (!sl) { return; } - - struct stlink_libusb * const handle = sl->backend_data; - - // maybe we couldn't even get the usb device? - if (handle != NULL) { - if (handle->usb_handle != NULL) { libusb_close(handle->usb_handle); } - - libusb_exit(handle->libusb_ctx); - free(handle); - } -} - -ssize_t send_recv(struct stlink_libusb* handle, int terminate, - unsigned char* txbuf, size_t txsize, unsigned char* rxbuf, - size_t rxsize, int check_error, const char *cmd) { - // Note: txbuf and rxbuf can point to the same area - int res, t, retry = 0; - - while (1) { - res = 0; - t = libusb_bulk_transfer(handle->usb_handle, handle->ep_req, txbuf, (int)txsize, &res, 3000); - - 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, (unsigned int)res, (unsigned int)txsize); - } - - if (rxsize != 0) { - t = libusb_bulk_transfer(handle->usb_handle, handle->ep_rep, rxbuf, (int)rxsize, &res, 3000); - - 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) { - unsigned int delay_us = (1<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) { - 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++; - } - - return(res); - } -} - -static inline int send_only(struct stlink_libusb* handle, int terminate, - unsigned char* txbuf, size_t txsize, - const char *cmd) { - return((int)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) { - struct stlink_libusb * const slu = sl->backend_data; - unsigned char* const cmd = sl->c_buf; - int i = 0; - memset(cmd, 0, sizeof(sl->c_buf)); - - if (slu->protocoll == 1) { - cmd[i++] = 'U'; - cmd[i++] = 'S'; - cmd[i++] = 'B'; - cmd[i++] = 'C'; - write_uint32(&cmd[i], slu->sg_transfer_idx); - write_uint32(&cmd[i + 4], len); - i += 8; - cmd[i++] = (dir == SG_DXFER_FROM_DEV) ? 0x80 : 0; - cmd[i++] = 0; // logical unit - cmd[i++] = 0xa; // command length - } - return(i); -} - -int _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; - int i; - - 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_GET_VERSION_APIV3; - } else { - rep_len = 6; - i = fill_command(sl, SG_DXFER_FROM_DEV, 6); - cmd[i++] = STLINK_GET_VERSION; - } - - 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) { - 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; - uint32_t rep_len = 8; - int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len); - uint32_t factor, reading; - int voltage; - - cmd[i++] = STLINK_GET_TARGET_VOLTAGE; - - size = send_recv(slu, 1, cmd, slu->cmd_len, rdata, rep_len, CMD_CHECK_REP_LEN, "GET_TARGET_VOLTAGE"); - - 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; - - return(voltage); -} - -int _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; - - int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len); - cmd[i++] = STLINK_DEBUG_COMMAND; - cmd[i++] = STLINK_DEBUG_APIV2_READDEBUGREG; - write_uint32(&cmd[i], addr); - size = send_recv(slu, 1, cmd, slu->cmd_len, rdata, rep_len, CMD_CHECK_RETRY, "READDEBUGREG"); - - if (size < 0) { - return(-1); - } - - *data = read_uint32(rdata, 4); - - return(0); -} - -int _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; - - int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len); - cmd[i++] = STLINK_DEBUG_COMMAND; - 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, CMD_CHECK_RETRY, "WRITEDEBUGREG"); - - 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); } - - unsigned char* const rdata = sl->q_buf; - struct stlink_libusb * const slu = sl->backend_data; - unsigned char* const cmd = sl->c_buf; - int i; - int16_t ret = 0; - - i = fill_command(sl, SG_DXFER_FROM_DEV, 12); - cmd[i++] = STLINK_DEBUG_COMMAND; - - 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, CMD_CHECK_STATUS, "GETLASTRWSTATUS2"); - } else { - cmd[i++] = STLINK_DEBUG_APIV2_GETLASTRWSTATUS; - ret = send_recv(slu, 1, cmd, slu->cmd_len, rdata, 2, CMD_CHECK_STATUS, "GETLASTRWSTATUS"); - } - - return(ret<0?-1:0); -} - -int _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; - - 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, "WRITEMEM_32BIT"); - - if (ret == -1) { return(ret); } - - ret = send_only(slu, 1, data, len, "WRITEMEM_32BIT"); - - if (ret == -1) { return(ret); } - - return(_stlink_usb_get_rw_status(sl)); -} - -int _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; - - 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, "WRITEMEM_8BIT"); - - if (ret == -1) { return(ret); } - - ret = send_only(slu, 1, data, len, "WRITEMEM_8BIT"); - - if (ret == -1) { return(ret); } - - return(0); -} - - -int _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); - - cmd[i++] = STLINK_GET_CURRENT_MODE; - size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_NO, "GET_CURRENT_MODE"); - - if (size < 0) { - return(-1); - } - - return(sl->q_buf[0]); -} - -int _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); - - cmd[i++] = STLINK_DEBUG_COMMAND; - - if (sl->version.jtag_api == STLINK_JTAG_API_V1) { - cmd[i++] = STLINK_DEBUG_READCOREID; - offset = 0; - } else { - cmd[i++] = STLINK_DEBUG_APIV2_READ_IDCODES; - offset = 4; - } - - size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_STATUS, "READ_IDCODES"); - - if (size < 0) { - return(-1); - } - - sl->core_id = read_uint32(data, offset); - - return(0); -} - -int _stlink_usb_status_v2(stlink_t *sl) { - int result; - uint32_t status = 0; - - result = _stlink_usb_read_debug32(sl, STLINK_REG_DHCSR, &status); - DLOG("core status: %08X\n", status); - - if (result != 0) { - sl->core_stat = TARGET_UNKNOWN; - } else { - if (status & STLINK_REG_DHCSR_C_HALT) { - sl->core_stat = TARGET_HALTED; - } else if (status & STLINK_REG_DHCSR_S_RESET_ST) { - sl->core_stat = TARGET_RESET; - } else { - sl->core_stat = TARGET_RUNNING; - } - } - - return(result); -} - -int _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); - - cmd[i++] = STLINK_DEBUG_COMMAND; - cmd[i++] = STLINK_DEBUG_GETSTATUS; - size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_NO, "GETSTATUS"); - - 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) { - sl->core_stat = TARGET_HALTED; - } else { - sl->core_stat = TARGET_UNKNOWN; - } - } else { - sl->core_stat = TARGET_UNKNOWN; - } - - return(size<0?-1:0); -} - -int _stlink_usb_force_debug(stlink_t *sl) { - struct stlink_libusb *slu = sl->backend_data; - - int 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); - } - - 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); - - cmd[i++] = STLINK_DEBUG_COMMAND; - cmd[i++] = STLINK_DEBUG_FORCEDEBUG; - size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_RETRY, "FORCEDEBUG"); - - return(size<0?-1:0); -} - -int _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); - - 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, CMD_CHECK_RETRY, "ENTER_SWD"); - - return(size<0?-1:0); -} - -int _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); - - cmd[i++] = STLINK_DFU_COMMAND; - cmd[i++] = STLINK_DFU_EXIT; - size = send_only(slu, 1, cmd, slu->cmd_len, "DFU_EXIT"); - - return(size<0?-1:0); -} - - -int _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; - - // send reset command - i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len); - cmd[i++] = STLINK_DEBUG_COMMAND; - - if (sl->version.jtag_api == STLINK_JTAG_API_V1) { - cmd[i++] = STLINK_DEBUG_APIV1_RESETSYS; - } else { - cmd[i++] = STLINK_DEBUG_APIV2_RESETSYS; - } - - size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_RETRY, "RESETSYS"); - - return(size<0?-1:0); -} - -int _stlink_usb_jtag_reset(stlink_t * sl, int 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); - - cmd[i++] = STLINK_DEBUG_COMMAND; - cmd[i++] = STLINK_DEBUG_APIV2_DRIVE_NRST; - cmd[i++] = value; - size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_RETRY, "DRIVE_NRST"); - - return(size<0?-1:0); -} - - -int _stlink_usb_step(stlink_t* sl) { - struct stlink_libusb * const slu = sl->backend_data; - - if (sl->version.jtag_api != STLINK_JTAG_API_V1) { - // emulates the JTAG v1 API by using DHCSR - _stlink_usb_write_debug32(sl, STLINK_REG_DHCSR, STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_HALT | - STLINK_REG_DHCSR_C_MASKINTS | STLINK_REG_DHCSR_C_DEBUGEN); - _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); - } - - 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); - - cmd[i++] = STLINK_DEBUG_COMMAND; - cmd[i++] = STLINK_DEBUG_STEPCORE; - size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_RETRY, "STEPCORE"); - - return(size<0?-1:0); -} - -/** - * This seems to do a good job of restarting things from the beginning? - * @param sl - * @param type - */ -int _stlink_usb_run(stlink_t* sl, enum run_type type) { - struct stlink_libusb * const slu = sl->backend_data; - - int 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 | - ((type==RUN_FLASH_LOADER)?STLINK_REG_DHCSR_C_MASKINTS:0)); - 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); - - cmd[i++] = STLINK_DEBUG_COMMAND; - cmd[i++] = STLINK_DEBUG_RUNCORE; - size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_RETRY, "RUNCORE"); - - return(size<0?-1:0); -} - -int _stlink_usb_set_swdclk(stlink_t* sl, int 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; - - // 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); - switch (map[speed_index]) { - case 5: clk_divisor = STLINK_SWDCLK_5KHZ_DIVISOR; break; - case 15: clk_divisor = STLINK_SWDCLK_15KHZ_DIVISOR; break; - case 25: clk_divisor = STLINK_SWDCLK_25KHZ_DIVISOR; break; - case 50: clk_divisor = STLINK_SWDCLK_50KHZ_DIVISOR; break; - case 100: clk_divisor = STLINK_SWDCLK_100KHZ_DIVISOR; break; - case 125: clk_divisor = STLINK_SWDCLK_125KHZ_DIVISOR; break; - case 240: clk_divisor = STLINK_SWDCLK_240KHZ_DIVISOR; break; - case 480: clk_divisor = STLINK_SWDCLK_480KHZ_DIVISOR; break; - case 950: clk_divisor = STLINK_SWDCLK_950KHZ_DIVISOR; break; - case 1200: clk_divisor = STLINK_SWDCLK_1P2MHZ_DIVISOR; break; - default: - case 1800: clk_divisor = STLINK_SWDCLK_1P8MHZ_DIVISOR; break; - case 4000: clk_divisor = STLINK_SWDCLK_4MHZ_DIVISOR; break; - } - } else - clk_divisor = STLINK_SWDCLK_1P8MHZ_DIVISOR; - - i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len); - - cmd[i++] = STLINK_DEBUG_COMMAND; - 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, CMD_CHECK_RETRY, "SWD_SET_FREQ"); - - return(size<0?-1:0); - } else if (sl->version.stlink_v == 3) { - int 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_DEBUG_APIV3_GET_COM_FREQ; - cmd[i++] = 0; // SWD mode - size = send_recv(slu, 1, cmd, slu->cmd_len, data, 52, CMD_CHECK_STATUS, "GET_COM_FREQ"); - - if (size < 0) { - return(-1); - } - - int speeds_size = data[8]; - if (speeds_size > STLINK_V3_MAX_FREQ_NB) { - speeds_size = STLINK_V3_MAX_FREQ_NB; - } - - for (i = 0; i < speeds_size; i++) map[i] = le_to_h_u32(&data[12 + 4 * i]); - - // 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 = 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_DEBUG_APIV3_SET_COM_FREQ; - cmd[i++] = 0; // SWD mode - cmd[i++] = 0; - cmd[i++] = (uint8_t)((map[speed_index] >> 0) & 0xFF); - cmd[i++] = (uint8_t)((map[speed_index] >> 8) & 0xFF); - 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, CMD_CHECK_STATUS, "SET_COM_FREQ"); - - return(size<0?-1:0); - } else if (clk_freq) { - WLOG("ST-Link firmware does not support frequency setup\n"); - } - - return(-1); -} - -int _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); - - cmd[i++] = STLINK_DEBUG_COMMAND; - cmd[i++] = STLINK_DEBUG_EXIT; - - size = send_only(slu, 1, cmd, slu->cmd_len, "DEBUG_EXIT"); - - return(size<0?-1:0); -} - -int _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); - - 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, CMD_CHECK_NO, "READMEM_32BIT"); - - if (size < 0) { - return(-1); - } - - sl->q_len = (int)size; - stlink_print_data(sl); - - return(0); -} - -int _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); - - cmd[i++] = STLINK_DEBUG_COMMAND; - - if (sl->version.jtag_api == STLINK_JTAG_API_V1) { - cmd[i++] = STLINK_DEBUG_APIV1_READALLREGS; - } else { - cmd[i++] = STLINK_DEBUG_APIV2_READALLREGS; - } - - size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_STATUS, "READALLREGS"); - - 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; - stlink_print_data(sl); - - for (i = 0; i < 16; i++) regp->r[i] = read_uint32(sl->q_buf, reg_offset + i * 4); - - regp->xpsr = read_uint32(sl->q_buf, reg_offset + 64); - regp->main_sp = read_uint32(sl->q_buf, reg_offset + 68); - regp->process_sp = read_uint32(sl->q_buf, reg_offset + 72); - 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); } - - DLOG("xpsr = 0x%08x\n", regp->xpsr); - DLOG("main_sp = 0x%08x\n", regp->main_sp); - DLOG("process_sp = 0x%08x\n", regp->process_sp); - DLOG("rw = 0x%08x\n", regp->rw); - DLOG("rw2 = 0x%08x\n", regp->rw2); - - return(0); -} - -int _stlink_usb_read_reg(stlink_t *sl, int 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); - - cmd[i++] = STLINK_DEBUG_COMMAND; - - if (sl->version.jtag_api == STLINK_JTAG_API_V1) { - cmd[i++] = STLINK_DEBUG_APIV1_READREG; - } else { - cmd[i++] = STLINK_DEBUG_APIV2_READREG; - } - - cmd[i++] = (uint8_t)r_idx; - size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_RETRY, "READREG"); - - if (size < 0) { - return(-1); - } - - sl->q_len = (int)size; - stlink_print_data(sl); - r = read_uint32(sl->q_buf, reg_offset); - DLOG("r_idx (%2d) = 0x%08x\n", r_idx, r); - - switch (r_idx) { - case 16: - regp->xpsr = r; - break; - case 17: - regp->main_sp = r; - break; - case 18: - regp->process_sp = r; - break; - case 19: - regp->rw = r; // XXX ?(primask, basemask etc.) - break; - case 20: - regp->rw2 = r; // XXX ?(primask, basemask etc.) - break; - default: - regp->r[r_idx] = r; - } - - 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) { - uint32_t r; - int ret; - - sl->q_buf[0] = (unsigned char)r_idx; - - for (int 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); } - - ret = _stlink_usb_read_mem32(sl, STLINK_REG_DCRDR, 4); - - if (ret == -1) { return(ret); } - - r = read_uint32(sl->q_buf, 0); - DLOG("r_idx (%2d) = 0x%08x\n", r_idx, r); - - switch (r_idx) { - case 0x14: - regp->primask = (uint8_t)(r & 0xFF); - regp->basepri = (uint8_t)((r >> 8) & 0xFF); - regp->faultmask = (uint8_t)((r >> 16) & 0xFF); - regp->control = (uint8_t)((r >> 24) & 0xFF); - break; - case 0x21: - regp->fpscr = r; - break; - default: - regp->s[r_idx - 0x40] = r; - break; - } - - return(0); -} - -int _stlink_usb_read_all_unsupported_regs(stlink_t *sl, struct stlink_reg *regp) { - int ret; - - ret = _stlink_usb_read_unsupported_reg(sl, 0x14, regp); - - if (ret == -1) { return(ret); } - - ret = _stlink_usb_read_unsupported_reg(sl, 0x21, regp); - - if (ret == -1) { return(ret); } - - for (int i = 0; i < 32; i++) { - ret = _stlink_usb_read_unsupported_reg(sl, 0x40 + i, regp); - - if (ret == -1) { return(ret); } - } - - 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; - - 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); } - - val = (uint8_t)(val >> 24); - - switch (r_idx) { - case 0x1C: /* control */ - val = (((uint32_t)val) << 24) | - (((uint32_t)regp->faultmask) << 16) | - (((uint32_t)regp->basepri) << 8) | - ((uint32_t)regp->primask); - break; - case 0x1D: /* faultmask */ - val = (((uint32_t)regp->control) << 24) | - (((uint32_t)val) << 16) | - (((uint32_t)regp->basepri) << 8) | - ((uint32_t)regp->primask); - break; - case 0x1E: /* basepri */ - val = (((uint32_t)regp->control) << 24) | - (((uint32_t)regp->faultmask) << 16) | - (((uint32_t)val) << 8) | - ((uint32_t)regp->primask); - break; - case 0x1F: /* primask */ - val = (((uint32_t)regp->control) << 24) | - (((uint32_t)regp->faultmask) << 16) | - (((uint32_t)regp->basepri) << 8) | - ((uint32_t)val); - break; - } - - r_idx = 0x14; - } - - write_uint32(sl->q_buf, val); - - ret = _stlink_usb_write_mem32(sl, STLINK_REG_DCRDR, 4); - - 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)); -} - -int _stlink_usb_write_reg(stlink_t *sl, uint32_t reg, int 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); - - cmd[i++] = STLINK_DEBUG_COMMAND; - - if (sl->version.jtag_api == STLINK_JTAG_API_V1) { - cmd[i++] = STLINK_DEBUG_APIV1_WRITEREG; - } else { - cmd[i++] = STLINK_DEBUG_APIV2_WRITEREG; - } - - cmd[i++] = idx; - write_uint32(&cmd[i], reg); - size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_RETRY, "WRITEREG"); - - return(size<0?-1:0); -} - -int _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; - - int 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_uint32(&cmd[i + 2], frequency); - - size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_STATUS, "START_TRACE_RX"); - - return(size<0?-1:0); -} - -int _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); - 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, CMD_CHECK_STATUS, "STOP_TRACE_RX"); - - return(size<0?-1:0); -} - -int _stlink_usb_read_trace(stlink_t* sl, uint8_t* buf, size_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); - - 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, CMD_CHECK_NO, "GET_TRACE_NB"); - - if (send_size < 0) { - return(-1); - } else if (send_size != 2) { - ELOG("STLINK_DEBUG_APIV2_GET_TRACE_NB reply size %d\n", (int)send_size); - return(-1); - } - - uint16_t trace_count = read_uint16(sl->q_buf, 0); - - if (trace_count > size) { - ELOG("read_trace insufficient buffer length\n"); - return -1; - } - - if (trace_count != 0) { - int res = 0; - int t = libusb_bulk_transfer(slu->usb_handle, slu->ep_trace, buf, trace_count, &res, 3000); - - if (t || res != (int)trace_count) { - ELOG("read_trace read error %d\n", t); - return(-1); - } - } - - return trace_count; -} - -static stlink_backend_t _stlink_usb_backend = { - _stlink_usb_close, - _stlink_usb_exit_debug_mode, - _stlink_usb_enter_swd_mode, - NULL, // don't enter_jtag_mode here... - _stlink_usb_exit_dfu_mode, - _stlink_usb_core_id, - _stlink_usb_reset, - _stlink_usb_jtag_reset, - _stlink_usb_run, - _stlink_usb_status, - _stlink_usb_version, - _stlink_usb_read_debug32, - _stlink_usb_read_mem32, - _stlink_usb_write_debug32, - _stlink_usb_write_mem32, - _stlink_usb_write_mem8, - _stlink_usb_read_all_regs, - _stlink_usb_read_reg, - _stlink_usb_read_all_unsupported_regs, - _stlink_usb_read_unsupported_reg, - _stlink_usb_write_unsupported_reg, - _stlink_usb_write_reg, - _stlink_usb_step, - _stlink_usb_current_mode, - _stlink_usb_force_debug, - _stlink_usb_target_voltage, - _stlink_usb_set_swdclk, - _stlink_usb_enable_trace, - _stlink_usb_disable_trace, - _stlink_usb_read_trace -}; - -/* return the length of serial or (0) in case of errors */ -size_t stlink_serial(struct libusb_device_handle *handle, struct libusb_device_descriptor *desc, char *serial) { - unsigned char desc_serial[(STLINK_SERIAL_LENGTH) * 2]; - - /* truncate the string in the serial buffer */ - serial[0] = '\0'; - - /* get the LANGID from String Descriptor Zero */ - int 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); - - /* get the serial */ - ret = libusb_get_string_descriptor(handle, desc->iSerialNumber, langid, desc_serial, - sizeof(desc_serial)); - if (ret < 0) return 0; // could not read serial - - unsigned char len = desc_serial[0]; - - if (len == ((STLINK_SERIAL_LENGTH + 1) * 2)) { /* len == 50 */ - /* good ST-Link adapter */ - ret = libusb_get_string_descriptor_ascii( - handle, desc->iSerialNumber, (unsigned char *)serial, STLINK_SERIAL_BUFFER_SIZE); - 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) - sprintf(serial + i, "%02X", desc_serial[i + 2]); - serial[STLINK_SERIAL_LENGTH] = '\0'; - } else { - return 0; - } - - return strlen(serial); -} - -stlink_t *stlink_open_usb(enum ugly_loglevel verbose, enum connect_type connect, char serial[STLINK_SERIAL_BUFFER_SIZE], int freq) { - stlink_t* sl = NULL; - struct stlink_libusb* slu = NULL; - int ret = -1; - int config; - - sl = calloc(1, sizeof(stlink_t)); - if (sl == NULL) { goto on_malloc_error; } - - slu = calloc(1, sizeof(struct stlink_libusb)); - if (slu == NULL) { goto on_malloc_error; } - - ugly_init(verbose); - sl->backend = &_stlink_usb_backend; - sl->backend_data = slu; - - sl->core_stat = TARGET_UNKNOWN; - - if (libusb_init(&(slu->libusb_ctx))) { - WLOG("failed to init libusb context, wrong version of libraries?\n"); - goto on_error; - } - -#if LIBUSB_API_VERSION < 0x01000106 - libusb_set_debug(slu->libusb_ctx, ugly_libusb_log_level(verbose)); -#else - libusb_set_option(slu->libusb_ctx, LIBUSB_OPTION_LOG_LEVEL, ugly_libusb_log_level(verbose)); -#endif - - libusb_device **list = NULL; - // 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) - ssize_t cnt = libusb_get_device_list(slu->libusb_ctx, &list); - struct libusb_device_descriptor desc; - - while (cnt-- > 0) { - struct libusb_device_handle *handle; - - libusb_get_device_descriptor(list[cnt], &desc); - - if (desc.idVendor != STLINK_USB_VID_ST) { continue; } - - ret = libusb_open(list[cnt], &handle); - - if (ret) { continue; } // could not open device - - size_t serial_len = stlink_serial(handle, &desc, sl->serial); - - libusb_close(handle); - - if (serial_len != STLINK_SERIAL_LENGTH) { continue; } // could not read the serial - - // if no serial provided, or if serial match device, fixup version and protocol - if (((serial == NULL) || (*serial == 0)) || (memcmp(serial, &sl->serial, STLINK_SERIAL_LENGTH) == 0)) { - if (STLINK_V1_USB_PID(desc.idProduct)) { - slu->protocoll = 1; - sl->version.stlink_v = 1; - } else if (STLINK_V2_USB_PID(desc.idProduct) || STLINK_V2_1_USB_PID(desc.idProduct)) { - sl->version.stlink_v = 2; - } else if (STLINK_V3_USB_PID(desc.idProduct)) { - sl->version.stlink_v = 3; - } - - break; - } - } - - if (cnt < 0) { - 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); - - if (ret != 0) { - WLOG("Error %d (%s) opening ST-Link v%d device %03d:%03d\n", ret, - strerror(errno), - sl->version.stlink_v, - libusb_get_bus_number(list[cnt]), - libusb_get_device_address(list[cnt])); - libusb_free_device_list(list, 1); - goto on_error; - } - } - - 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); - - if (ret < 0) { - WLOG("libusb_detach_kernel_driver(() error %s\n", strerror(-ret)); - goto on_libusb_error; - } - } -#endif - - if (libusb_get_configuration(slu->usb_handle, &config)) { - // this may fail for a previous configured device - WLOG("libusb_get_configuration()\n"); - goto on_libusb_error; - } - - if (config != 1) { - printf("setting new configuration (%d -> 1)\n", config); - - if (libusb_set_configuration(slu->usb_handle, 1)) { - // this may fail for a previous configured device - WLOG("libusb_set_configuration() failed\n"); - goto on_libusb_error; - } - } - - if (libusb_claim_interface(slu->usb_handle, 0)) { - WLOG("Stlink usb device found, but unable to claim (probably already in use?)\n"); - goto on_libusb_error; - } - - // TODO: Could use the scanning technique from STM8 code here... - slu->ep_rep = 1 /* ep rep */ | LIBUSB_ENDPOINT_IN; - - if (desc.idProduct == STLINK_USB_PID_STLINK_NUCLEO || - desc.idProduct == STLINK_USB_PID_STLINK_32L_AUDIO || - desc.idProduct == STLINK_USB_PID_STLINK_V2_1 || - 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_NO_MSD_PID) { - slu->ep_req = 1 /* ep req */ | LIBUSB_ENDPOINT_OUT; - slu->ep_trace = 2 | LIBUSB_ENDPOINT_IN; - } else { - slu->ep_req = 2 /* ep req */ | LIBUSB_ENDPOINT_OUT; - slu->ep_trace = 3 | LIBUSB_ENDPOINT_IN; - } - - slu->sg_transfer_idx = 0; - slu->cmd_len = (slu->protocoll == 1) ? STLINK_SG_SIZE : STLINK_CMD_SIZE; - - // initialize stlink version (sl->version) - stlink_version(sl); - - int mode = stlink_current_mode(sl); - if (mode == STLINK_DEV_DFU_MODE) { - DLOG("-- exit_dfu_mode\n"); - _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; - // set the speed before entering the mode as the chip discovery phase - // 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_usb_set_swdclk(sl, freq); - - stlink_target_connect(sl, connect); - return(sl); - -on_libusb_error: - stlink_close(sl); - 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); -} - -static size_t stlink_probe_usb_devs(libusb_device **devs, stlink_t **sldevs[], enum connect_type connect, int freq) { - stlink_t **_sldevs; - libusb_device *dev; - int i = 0; - size_t slcnt = 0; - size_t slcur = 0; - - /* Count STLINKs */ - while ((dev = devs[i++]) != NULL) { - struct libusb_device_descriptor desc; - int ret = libusb_get_device_descriptor(dev, &desc); - - if (ret < 0) { - WLOG("failed to get libusb device descriptor (libusb error: %d)\n", ret); - break; - } - - if (desc.idVendor != STLINK_USB_VID_ST) { continue; } - - if (!STLINK_SUPPORTED_USB_PID(desc.idProduct)) { - WLOG("skipping ST device : %#04x:%#04x)\n", desc.idVendor, desc.idProduct); - continue; - } - - slcnt++; - } - - _sldevs = calloc(slcnt, sizeof(stlink_t *)); // allocate list of pointers - - if (!_sldevs) { - *sldevs = NULL; - return(0); - } - - /* Open STLINKS and attach them to list */ - i = 0; - - while ((dev = devs[i++]) != NULL) { - struct libusb_device_descriptor desc; - int ret = libusb_get_device_descriptor(dev, &desc); - - if (ret < 0) { - WLOG("failed to get libusb device descriptor (libusb error: %d)\n", ret); - break; - } - - if (!STLINK_SUPPORTED_USB_PID(desc.idProduct)) { continue; } - - struct libusb_device_handle* handle; - char serial[STLINK_SERIAL_BUFFER_SIZE] = {0, }; - - ret = libusb_open(dev, &handle); - - if (ret < 0) { - if (ret == LIBUSB_ERROR_ACCESS) { - ELOG("Could not open USB device %#06x:%#06x, access error.\n", desc.idVendor, desc.idProduct); - } else { - ELOG("Failed to open USB device %#06x:%#06x, libusb error: %d)\n", desc.idVendor, desc.idProduct, ret); - } - - break; - } - - size_t serial_len = stlink_serial(handle, &desc, serial); - - libusb_close(handle); - - if (serial_len != STLINK_SERIAL_LENGTH) { continue; } - - stlink_t *sl = stlink_open_usb(0, connect, serial, freq); - - if (!sl) { - ELOG("Failed to open USB device %#06x:%#06x\n", desc.idVendor, desc.idProduct); - continue; - } - - _sldevs[slcur++] = sl; - } - - *sldevs = _sldevs; - - return(slcur); -} - -size_t stlink_probe_usb(stlink_t **stdevs[], enum connect_type connect, int freq) { - libusb_device **devs; - stlink_t **sldevs; - - size_t slcnt = 0; - int r; - ssize_t cnt; - - r = libusb_init(NULL); - - if (r < 0) { return(0); } - - cnt = libusb_get_device_list(NULL, &devs); - - if (cnt < 0) { return(0); } - - slcnt = stlink_probe_usb_devs(devs, &sldevs, connect, freq); - libusb_free_device_list(devs, 1); - - libusb_exit(NULL); - - *stdevs = sldevs; - - return(slcnt); -} - -void stlink_probe_usb_free(stlink_t ***stdevs, size_t size) { - if (stdevs == NULL || *stdevs == NULL || size == 0) { return; } - - for (size_t n = 0; n < size; n++) { stlink_close((*stdevs)[n]); } - - free(*stdevs); - *stdevs = NULL; -} diff --git a/src/win32/unistd/unistd.h b/src/win32/unistd/unistd.h index cb6da4b..389c446 100644 --- a/src/win32/unistd/unistd.h +++ b/src/win32/unistd/unistd.h @@ -52,7 +52,7 @@ #define ssize_t int #ifndef SSIZE_MAX -#define SSIZE_MAX ((sizeof(ssize_t) == 4) ? 1073741824 : ‭4611686018427387904‬) +#define SSIZE_MAX ((sizeof(ssize_t) == 4) ? 2147483647 : 9223372036854775807) #endif #define STDIN_FILENO 0 diff --git a/src/win32/unistd/unistd.h.bak b/src/win32/unistd/unistd.h.bak deleted file mode 100644 index 47967e4..0000000 --- a/src/win32/unistd/unistd.h.bak +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef _UNISTD_H -#define _UNISTD_H 1 - -/* - * This file intended to serve as a drop-in replacement for unistd.h on Windows - * Please add functionality as needed. - */ - -#include -#include - -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable: 4820) -#endif - -#include - -#if defined(_MSC_VER) -#pragma warning(pop) -#endif - -#include // getopt at: https://gist.github.com/ashelly/7776712 -#include // for getpid() and the exec..() family -#include // for _getcwd() and _chdir() - -#define srandom srand -#define random rand - -/* Values for the second argument to access. These may be OR'd together. */ -#define R_OK 4 // Test for read permission -#define W_OK 2 // Test for write permission -// #define X_OK 1 // execute permission - unsupported in windows -#define F_OK 0 // Test for existence - -#define access _access -#define dup2 _dup2 -#define execve _execve -#define ftruncate _chsize -#define unlink _unlink -#define fileno _fileno -#define getcwd _getcwd -#define chdir _chdir -#define isatty _isatty -#define lseek _lseek - -/* - * Read, write, and close are NOT being defined here, - * because while there are file handle specific versions for Windows, they probably don't work for sockets. - * You need to look at your app and consider whether to call e.g. closesocket(). - */ - -#define ssize_t int -#ifndef SSIZE_MAX -//#define SSIZE_MAX ((sizeof(ssize_t) == 4) ? 2147483647 : 9223372036854775807) -#define SSIZE_MAX ((sizeof(ssize_t) == 4) ? 1073741824 : ‭4611686018427387904‬) -#endif - -#define STDIN_FILENO 0 -#define STDOUT_FILENO 1 -#define STDERR_FILENO 2 -// should be in some equivalent to -typedef __int8 int8_t; -typedef __int16 int16_t; -typedef __int32 int32_t; -typedef __int64 int64_t; -typedef unsigned __int8 uint8_t; -typedef unsigned __int16 uint16_t; -typedef unsigned __int32 uint32_t; -typedef unsigned __int64 uint64_t; - -#ifndef STLINK_HAVE_UNISTD_H -int usleep(unsigned int waitTime); -#endif - -#endif // _UNISTD_H diff --git a/stlinkv1_macos_driver/install.sh b/stlinkv1_macos_driver/install.sh index 5716281..f9878bd 100644 --- a/stlinkv1_macos_driver/install.sh +++ b/stlinkv1_macos_driver/install.sh @@ -2,9 +2,6 @@ ISMACOS=$(sw_vers -productVersion) case $ISMACOS in -10.14*) - KEXT="stlink_shield_10_14.kext" - ;; 10.15*) KEXT="stlink_shield_10_15.kext" ;; diff --git a/stlinkv1_macos_driver/stlink_shield_10_14.kext/Contents/Info.plist b/stlinkv1_macos_driver/stlink_shield_10_14.kext/Contents/Info.plist deleted file mode 100644 index fd424ea..0000000 --- a/stlinkv1_macos_driver/stlink_shield_10_14.kext/Contents/Info.plist +++ /dev/null @@ -1,82 +0,0 @@ - - - - - BuildMachineOSBuild - 18G7016 - CFBundleDevelopmentRegion - English - CFBundleIdentifier - com.libusb.stlink-shield - CFBundleInfoDictionaryVersion - 6.0 - CFBundlePackageType - KEXT - CFBundleSignature - ???? - CFBundleSupportedPlatforms - - MacOSX - - CFBundleVersion - 1.0.0 - DTCompiler - com.apple.compilers.llvm.clang.1_0 - DTPlatformBuild - 11C504 - DTPlatformVersion - GM - DTSDKBuild - 19B90 - DTSDKName - macosx10.15 - DTXcode - 1130 - DTXcodeBuild - 11C504 - IOKitPersonalities - - DeviceDriver - - CFBundleIdentifier - com.apple.kpi.iokit - IOClass - IOService - IOProviderClass - IOUSBDevice - bcdDevice - 256 - idProduct - 14148 - idVendor - 1155 - - InterfaceDriver - - CFBundleIdentifier - com.apple.kpi.iokit - IOClass - IOService - IOProviderClass - IOUSBInterface - bConfigurationValue - 1 - bInterfaceNumber - 0 - idProduct - 14148 - idVendor - 1155 - - - LSMinimumSystemVersion - 10.14 - OSBundleLibraries - - com.apple.iokit.IOUSBFamily - 1.8 - com.apple.kpi.libkern - 11.2.0 - - - diff --git a/stlinkv1_macos_driver/stlink_shield_10_14.kext/Contents/MacOS/stlink_shield_10_14 b/stlinkv1_macos_driver/stlink_shield_10_14.kext/Contents/MacOS/stlink_shield_10_14 deleted file mode 100644 index 6a32aa4615953f6afe16047f73da9a3bced9b3a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33840 zcmeHOdwf$>p1)}uC}>G^QR*WS>I=j+ty12BhPH46DO6ez1iYqA3Yj)ZNp7Gx=tfJ` zYp8Tb@dY}d4$kQ4>aHsfUv;V!Mn}FxJ?&-tC-@0{;B_mTT}_t-ZldkcagQxJr+uw`Qtvjm|fYCuj9F2HsdvXWF?KC7A) zb^mAWP6f`5D5edrSdt{!+az-WNcUGrfss1TQIWXTmX%})QME?>FG;n*Ksf0z-Jfuw zYA0%qz`Oa=$~nScSPuCD^Ao)Lct!3nn4ubITyw*VHHz_h7f5v>x8JK4rT1^c#oP}G zk3^hj)q=GDG!GxMc_?#KJ5nmGJa6Wh#>ppbG#8X4X?`%N8u6a}Y3^t~f2m)Ril00tNoyxoS&x-bx-c~^%o~}KwVnFM}?+*sF zvh?vDKzmAsDzN{l{WGMLQ&y5{!r_#%bbr=CYGq}L%`f?*d8IWfNiOHqDdlBOZ6DJ* zbQ5>Pc_FW-ex>$}G|0tfgt59afrX>q9#Lc78r^#BWj=BQ60{@p4m?0{EbzJY5 z>6qcDt`eK~=Q@-RoyrlXazbpqxur$GP?^8J_kJ&SOZngh>W^P*c3>+$*d*6n2%>E%tMP(-+mGL8T-D&&) zKndCRlG%57HfnzoIYVT~Yjg(Fnm&Ot*soze8onJG2?;rP#(*zP)@KZ zD;5&oTZ_NI!5pf)l!KU}3T2O|yv~)}Z2TP24CwSOASGnK)Uq+lSICOD9T$X?@kmxt zyz5HwwvKo_6J=jh8JzNdb&87dcVw(s)&bbiSyj}23%DUNUW{4pBZJn`EOCtSHe?qK zg||%7h;Xj3Iosun% z$+-Y*(KU$EyIY)Nq*gLc7o(Q_Ohe;0401jMIAQ~o{#b{WPpC`{^A56QN@QEq{y1{U zP|t$(5NZXrOooawYPpRdX1tw2PCXztV;hBPHu^!b#O610=Q!p%<~eS3Nb@?Flx&`} z`%}YQSFHFF*s1Eb7EkC$L1>1PbKCV2+uvu>o^BSK?LVQVU|N>fiyT<8(K>4XlFH<% zd{Xvj>d=X^d3YIrMjC}0uT(PwZ6La2bu-lHJ zX01FzHE%u|mv6%ONB0f0^mUVh0Kx&4&$TnR2dKRC0!pJH?U*=*+^=Kv;_&_NPL168lg^`F^^B zjoP=P7s+|t4c5avc2ZZ93T$B1vXLNW+{7T~aX@Uwes#&LqcSzxDr6B2!4S<4l8n{_ z)%Wh657OMp2m>tpM3XH2NKrjCK}S57GA1MNcx? z4n{3I31Y_28RTpMB%-}VWooo`WTSSvY)USVC%}3L(?YG1VHPoJSxgW!HZjO?13I(l zi267VShZBB#+gMG+9BjBkmRU}!FmXHJ~d8;>&>Von;>TF!yxA%&KrDG&Bh-ou4ETgbdY|UPBX2=j%>OV(@gfEvw~@08LFD?55fW`nVA>?Kl?=O zOUWU-0JxX6FU5)37)6#{0CYbwyU8Ni>FJDGst97nG6p#n1h@jAxMHk$9MR^@I5iYs z%M9!n1EO{#{u?3##aK=ja+^p~^>i7tAIFGTzAFp|7OKX|P>bk#au};*=i3L*rXX~_ zeO7A(1)jmr@bvR7t~(!RN)^*}r5dW!xEy&(xUPC$%f{>>%_3&M9s&0L8!q+GevVcQ z>nWObr%~itnh;oB4$4H=&hM?p3>2Z4V#{`Uu&cFr45(?K;2L$Ue3lrSV@7%8U{}AQ z_BhU=VBas;l7SS#-=98z;8Je|GZWOj`j zFAtz!5X$EiWq;R%q=j?LIC-FR%&pmSUPa3;+2~Z}US?K>QLSI?>hDx8A&bb)3Z*U^ zR*_G;cF=_nyX;B2V(W|gS5+yt8Z*^Nq2XSTv}x-$zJpkw*>mP~q||pG->bO2(tUhc z{{Z82%&c-Mhe`A)qH_E-x^&@+&B_)#OK6#57tEQB&WlPma=j_ndL8CEViAvVdik8E&m~`e+8dIH}opAP4-!pI)wSNUOK{m1#wAuIpm_cl{ zKXNi2SNqy(fBvUreg^Vn%GPXKO48<|s?w>P6k8>OD`qdmCE4AXV{MVMy3As{gR*k( zW$lsgyUuIdoGCa=>qoehBP`73Ok3AyY?js4(#HI;>s_mIysoo+H}-<-+f75tw=sLA z{0kKB$`oAqrE3~kBH)K8q6xTa=0AsM-@lmIHjm7bzfcFGyuKlh)I6#}&R|D9D;u}A zznnH+#{X_S{C+3B4m*`NG%v@2gLkt7bb>~mow&@$C2=R+FT_vF?efr~tQ@B zG~w4MYgM$hrQPJ*;!sec{*-eny}B}rwu{QgDax7#M#+sfU$}eVRNi$eABf8Ln7Q(n z_FEk|O&N-|CU-W{*Yu(}ddw#0E_+`dB*xpzM!mjtf7gJdP5gBcHwV;;|HQ1aI|;{F z$4aA1$Hr}PcIoD!H|MX@IeImPj5f+Hh#FPsdMe9H9RWD0+Wy-@juS z9y%D0&)O#)jmMLr+3{rGTbS2mSsR*fLi?;4;eRFb zAOA7c*O~awfq#+|2edpopTyWLfXsREFN)gdb?_SV&ubEWDj9s~kjm-PCQWx#j1J2U zzCgVcUf}aKc%-62sc4whipt65rPbXl^J(YpmO?{ogvHnzL%}*9+{_CQ^QHY4l}g>8%c`4MDnW!`YT9Bj1t-L=!Ito3*}X6vqhQ*F@Wwbev? z4W8~b1!`HDw
bdyP70ynY%}ESw(*hWzdZThqwl((qwD*-MMiuY&ot9=CASHHE|e zfjjC8)CJX!3i$2KlHum*f}zQ5FrVE!yA9W8SEH03t$M>Ccj{mge{l;-rR zXzsndSF7=!tQD;0GE};-H`You#IO4GRC(xlyL z6#xFPYFEmP@K5u{?Wmt`VB5y+{w3XRQgg56iC(Jle}GNN5!G*Ty8VP^HXb&9^lcWm zI}^Vy*l*$XyVCvg{+>#2(uMSH!l8@OwDk59o7pJHt_<56Zs$+8OVPOjb$idi?mpNR z;*d;fNxDBCm-KiU+g;r5(R8~soliAR8Y69Aa6f}m{7{za#$r3b>$T^tR7Z*G=VH^^ z<0eYCbh@}(P80Xz)5O)?pevv&pevv&pevv&pevv&pevv&pevv& z@c&f-vz7g(@0H7O7st;ydhmn)5^UQ0`8RWJJzHSuH=MWOMF>jkIM;5_y~H`an?vby z&I|GG5KFiTPX4!XZsxolFI`b8NbO5FzmRj0^Gi9esgN8t4YCX9Em6&WPD|7PkP6)v+969l{tE|}2g68=2}-4i3O zeXnsVariTHe{J9hcM`zTL-?P{A4}uUr1Aeq<1eN0jx_$~H2!`X|1^z%oyPa2@dIi6 zNE)Y`SgGUb4U)=9>r_4|S+00eBUb z;u<_D8Y~F;nZO~yE<7hDoP!&Ygx6!gC3JJ_fXuHNX=b=}ko9_v5%k zxE}tl1$F?30k45wF)$nb7!Dl3aVX-C0AIzi32S*IxPo?sE$9c~Uic-X7fuO3$`yoB zKm(35gvU{ieI@@Jv>OAw4)Jh*IsXx$9r!x@jsyO{@haF6{}lem11CUd!e=;!F>c}! zyw*YZHOK4l;tKJXInrxE#2@6?%dB#l<5wIj&r!?QbEH@4sNHssYtgR~@ImO014yr1 z5Qfoz!T{;-km>?bgAX5kN%iUnM|D9#YM`f$ zWxh}ao|FkvxBJlQqp+EHvgHc~rbhfV-q0^uRH@&7NsB{1*&B@DV~>;YC6u5AuzI{g2Yu*hZ9_1Oj?~o#}?=p7Fm$ydu4B65yM8GN09L7t|5res{CGmZQ~MPy~l?>`2B8#_tUdSKqSDZ z8ZPAJP4GRNCju)V?>TaK;0fIt7WpBu$BjC72!r)CphGF85%>=+!Dn4e<%G32;7PSj ziiP%J?!e=1zz|Y|#8+W5=77&03&L%fF6^_hbOSd1^idh9&6=psmAz8PTN}ZgF7j$h zur=Tc*49siT8zvHK(Qp9c@!2`8&)EA>S9bapr*4reJK-FfT!m8*bPt3z32jrL*9Ta(Hi0ti#>{ZT%aymDdeWLiNLCR z+VPN%?L503U+C2%t3ATP;ZDfFSqO(oDl_2lgM)xzI7TNX*w&&A>V=<#3=|m1R-n^x zAvW@XONP)%MN4 zvoO@_{`3FxcG005{qm*R{-)89!`qE5L;By-f5)wBUkI&ke{^g3g@1pb!TG1lZ(0BH z_d7P#4_bZcO2_U)V};IVb;N8b}nfv}ayujY;jokN} z%Kmxsqbshyev4Rh?xY13H%?l8NyT?35AS@o-?-HqXDiRW6AQ1AuW9<7so>+kV(=sb z8{Dy-3l}2)%GmKu{st>OR>#7(=iymbp4A(`^L)G)Vb7aUJu!b|-uQ8S#||o+R$4u~ zvfSE8hc;{Fj0rAhsWmU(W}^k_wb{z5%dC|yXH~ToK5Vw~sd?7C1+v^Y+Gbn4cyWQ7 ztO_6}8HR0@Ashih@)8%E<)cA?NA~0)jOx8xcTno_)yg)Yja859tIndqmokg{Fqm$$ zXw5i-S^Q?r*Ump=zW?jTUwH49?P1TCBVNA!H;@+`i zx9!V|hQGDJ|JEP3T>0)Be>eJqSk*4Lw$!ngQKJ{18 z*E%nJJpae{N30uAdi0KsMOPG^xZSZ!dMwa?&bo==CmRjtm(QqpuJ8I6+h2aY>GkN)Ri8Y(zj5ZJ9Y_AO+kfc7Ref*2 zbIRJevgxUH|N6+A`<~oTaNl)rKaly6!Le<}n_bs>X1~5+ - - - - files - - files2 - - rules - - ^Resources/ - - ^Resources/.*\.lproj/ - - optional - - weight - 1000 - - ^Resources/.*\.lproj/locversion.plist$ - - omit - - weight - 1100 - - ^Resources/Base\.lproj/ - - weight - 1010 - - ^version.plist$ - - - rules2 - - .*\.dSYM($|/) - - weight - 11 - - ^(.*/)?\.DS_Store$ - - omit - - weight - 2000 - - ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/ - - nested - - weight - 10 - - ^.* - - ^Info\.plist$ - - omit - - weight - 20 - - ^PkgInfo$ - - omit - - weight - 20 - - ^Resources/ - - weight - 20 - - ^Resources/.*\.lproj/ - - optional - - weight - 1000 - - ^Resources/.*\.lproj/locversion.plist$ - - omit - - weight - 1100 - - ^Resources/Base\.lproj/ - - weight - 1010 - - ^[^/]+$ - - nested - - weight - 10 - - ^embedded\.provisionprofile$ - - weight - 20 - - ^version\.plist$ - - weight - 20 - - - - diff --git a/stlinkv1_macos_driver/stlink_shield_xcode/stlink_shield.xcodeproj/project.pbxproj b/stlinkv1_macos_driver/stlink_shield_xcode/stlink_shield.xcodeproj/project.pbxproj index 4f2b802..373600c 100644 --- a/stlinkv1_macos_driver/stlink_shield_xcode/stlink_shield.xcodeproj/project.pbxproj +++ b/stlinkv1_macos_driver/stlink_shield_xcode/stlink_shield.xcodeproj/project.pbxproj @@ -8,7 +8,6 @@ /* Begin PBXFileReference section */ 8CD33C31149BB80D0033D618 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 8F9084FD24786F0F009109AD /* stlink_shield_10_14.kext */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = stlink_shield_10_14.kext; sourceTree = BUILT_PRODUCTS_DIR; }; 8F90850924786F39009109AD /* stlink_shield_10_15.kext */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = stlink_shield_10_15.kext; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -34,7 +33,6 @@ 19C28FB6FE9D52B211CA2CBB /* Products */ = { isa = PBXGroup; children = ( - 8F9084FD24786F0F009109AD /* stlink_shield_10_14.kext */, 8F90850924786F39009109AD /* stlink_shield_10_15.kext */, ); name = Products; @@ -60,26 +58,6 @@ /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ - 8F9084F324786F0F009109AD /* stlink_shield_10_14 */ = { - isa = PBXNativeTarget; - buildConfigurationList = 8F9084FA24786F0F009109AD /* Build configuration list for PBXNativeTarget "stlink_shield_10_14" */; - buildPhases = ( - 8F9084F424786F0F009109AD /* ShellScript */, - 8F9084F524786F0F009109AD /* Headers */, - 8F9084F624786F0F009109AD /* Resources */, - 8F9084F824786F0F009109AD /* Sources */, - 8F9084F924786F0F009109AD /* ShellScript */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = stlink_shield_10_14; - productInstallPath = "$(SYSTEM_LIBRARY_DIR)/Extensions"; - productName = NanosMouse; - productReference = 8F9084FD24786F0F009109AD /* stlink_shield_10_14.kext */; - productType = "com.apple.product-type.kernel-extension.iokit"; - }; 8F9084FF24786F39009109AD /* stlink_shield_10_15 */ = { isa = PBXNativeTarget; buildConfigurationList = 8F90850624786F39009109AD /* Build configuration list for PBXNativeTarget "stlink_shield_10_15" */; @@ -120,7 +98,6 @@ projectDirPath = ""; projectRoot = ""; targets = ( - 8F9084F324786F0F009109AD /* stlink_shield_10_14 */, 8F9084FF24786F39009109AD /* stlink_shield_10_15 */, ); }; @@ -458,24 +435,6 @@ }; name = Release; }; - 8F9084FB24786F0F009109AD /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_IDENTITY = "-"; - MACOSX_DEPLOYMENT_TARGET = 10.14; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 8F9084FC24786F0F009109AD /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_IDENTITY = "-"; - MACOSX_DEPLOYMENT_TARGET = 10.14; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; 8F90850724786F39009109AD /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -506,15 +465,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 8F9084FA24786F0F009109AD /* Build configuration list for PBXNativeTarget "stlink_shield_10_14" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 8F9084FB24786F0F009109AD /* Debug */, - 8F9084FC24786F0F009109AD /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; 8F90850624786F39009109AD /* Build configuration list for PBXNativeTarget "stlink_shield_10_15" */ = { isa = XCConfigurationList; buildConfigurations = (