pax_global_header00006660000000000000000000000064152602754310014517gustar00rootroot0000000000000052 comment=0697e5668df5f4f191c4d9f11803d5e995eb90df stlink-1.9.0/000077500000000000000000000000001526027543100130325ustar00rootroot00000000000000stlink-1.9.0/.github/000077500000000000000000000000001526027543100143725ustar00rootroot00000000000000stlink-1.9.0/.github/ISSUE_TEMPLATE/000077500000000000000000000000001526027543100165555ustar00rootroot00000000000000stlink-1.9.0/.github/ISSUE_TEMPLATE/bug-report.md000066400000000000000000000027711526027543100211740ustar00rootroot00000000000000--- name: "Bug Report" about: "Report a bug" title: "[STM32 device name]: $YourTitle" labels: "" --- **Thank you for giving feedback to the stlink project.** --- **NOTE: In order to offer sufficient and the best possible support, please read /CONTRIBUTING.md and follow the given instructions _before_ submitting a ticket.** **Bug reports and/or feature requests will be deleted, if they violate our contribution guidelines and if no issue-template is used!** Thank you for your support. --- - [ ] I made serious effort to avoid creating duplicate or nearly similar issue In order to allow developers to isolate and target your respective issue, please take some time to select the check boxes below and fill out each of the following items appropriate to your specific problem. - [ ] Programmer/board type: [enter here] (e.g STLINK /V1, /V2, /V2-onboard, /V2-clone, /V3) - [ ] Operating system an version: [enter here] (e.g Linux, Windows) - [ ] **stlink tools version** and/or git commit hash: [enter here] (e.g v1.6.1/git-d0416149) - [ ] stlink commandline tool name: [enter here] (e.g `st-info`, `st-flash`, `st-trace`, `st-util`) - [ ] Target chip (and board, if applicable): [enter here] (e.g STM32F103C8T6 (NUCLEO-F103RB)) Further we kindly ask you to describe the detected problem as detailed as possible and to add debug output if available, by using the following template: Commandline output: ``` OUTPUT/ERROR of the commandline tool(s) ``` Expected/description: `short description of the expected value` stlink-1.9.0/.github/ISSUE_TEMPLATE/feature-request.md000066400000000000000000000030311526027543100222150ustar00rootroot00000000000000--- name: "Feature Request" about: "Suggest an idea for this project" title: "[feature] $YourTitle" labels: code/feature-request --- **Thank you for giving feedback to the stlink project.** --- **NOTE: In order to offer sufficient and the best possible support, please read /CONTRIBUTING.md and follow the given instructions _before_ submitting a ticket.** **Bug reports and/or feature requests will be deleted, if they violate our contribution guidelines and if no issue-template is used!** Thank you for your support. --- - [ ] I made serious effort to avoid creating duplicate or nearly similar issue In order to allow developers to isolate and target your respective issue, please take some time to select the check boxes below and fill out each of the following items appropriate to your specific request. - [ ] Programmer/board type: [enter here] (e.g STLINK /V1, /V2, /V2-onboard, /V2-clone, /V3) - [ ] Operating system an version: [enter here] (e.g Linux, Windows) - [ ] **stlink tools version** and/or git commit hash: [enter here] (e.g v1.6.1/git-d0416149) - [ ] stlink commandline tool name: [enter here] (e.g `st-info`, `st-flash`, `st-trace`, `st-util`) - [ ] Target chip (and board, if applicable): [enter here] (e.g STM32F103C8T6 (NUCLEO-F103RB)) Further we kindly ask you to describe the detected problem as detailed as possible and to add debug output if available, by using the following template: Commandline output: ``` OUTPUT/ERROR of the commandline tool(s) ``` Expected/description: `short description of the expected value` stlink-1.9.0/.github/workflows/000077500000000000000000000000001526027543100164275ustar00rootroot00000000000000stlink-1.9.0/.github/workflows/c-cpp.yml000066400000000000000000000165171526027543100201660ustar00rootroot00000000000000name: C/C++ CI on: push: branches: [master, develop, testing] pull_request: branches: [master, develop, testing] jobs: # Linux builds with GCC and Clang on Ubuntu 22.04 and 24.04 linux_64_bit: strategy: fail-fast: false matrix: config: # === Ubuntu 22.04 (Jammy Jellyfish) === # GCC versions - name: Ubuntu22.04_x64 gcc11 os: ubuntu-22.04 cc: gcc-11 cxx: g++-11 packages: gcc-11 g++-11 - name: Ubuntu22.04_x64 gcc12 os: ubuntu-22.04 cc: gcc-12 cxx: g++-12 packages: gcc-12 g++-12 # Clang versions - name: Ubuntu22.04_x64 clang14 os: ubuntu-22.04 cc: clang-14 cxx: clang++-14 packages: clang-14 - name: Ubuntu22.04_x64 clang15 os: ubuntu-22.04 cc: clang-15 cxx: clang++-15 packages: clang-15 # === Ubuntu 24.04 (Noble Numbat) === # GCC versions - name: Ubuntu24.04_x64 gcc13 os: ubuntu-24.04 cc: gcc-13 cxx: g++-13 packages: gcc-13 g++-13 - name: Ubuntu24.04_x64 gcc14 os: ubuntu-24.04 cc: gcc-14 cxx: g++-14 packages: gcc-14 g++-14 # Clang versions - name: Ubuntu24.04_x64 clang16 os: ubuntu-24.04 cc: clang-16 cxx: clang++-16 packages: clang-16 - name: Ubuntu24.04_x64 clang17 os: ubuntu-24.04 cc: clang-17 cxx: clang++-17 packages: clang-17 - name: Ubuntu24.04_x64 clang18 os: ubuntu-24.04 cc: clang-18 cxx: clang++-18 packages: clang-18 name: ${{ matrix.config.name }} runs-on: ${{ matrix.config.os }} env: CC: ${{ matrix.config.cc }} CXX: ${{ matrix.config.cxx }} steps: - uses: actions/checkout@v4 - name: Install dependencies run: sudo apt update && sudo apt-get install ${{ matrix.config.packages }} cmake libusb-1.0.0-dev libgtk-3-dev - name: Verify CMake version run: cmake --version - name: Prepare build directories run: mkdir -p ./build/{debug,release} - name: Configure project (Debug) working-directory: ./build/debug run: cmake ../.. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug - name: Build project (Debug) working-directory: ./build/debug run: cmake --build . --target all --parallel 4 - name: Run tests (Debug) working-directory: ./build/debug run: ctest --force-new-ctest-process --parallel 4 - name: Configure project (Release) working-directory: ./build/release run: cmake ../.. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release - name: Build project (Release) working-directory: ./build/release run: cmake --build . --target all --parallel 4 - name: Install project working-directory: ./build/release run: sudo cmake --build . --target install - name: Package project working-directory: ./build/release run: sudo cpack --config ./CPackSourceConfig.cmake ../debug/CPackSourceConfig.cmake - name: Uninstall project working-directory: ./build/release run: sudo cmake --build . --target uninstall # macOS builds with Clang (latest) macos_build: strategy: fail-fast: false matrix: config: - name: macOS-latest clang15 os: macos-latest cc: clang cxx: clang++ packages: "" name: ${{ matrix.config.name }} runs-on: ${{ matrix.config.os }} env: CC: ${{ matrix.config.cc }} CXX: ${{ matrix.config.cxx }} steps: - uses: actions/checkout@v4 - name: Install dependencies run: brew install libusb cmake - name: Verify CMake version run: cmake --version - name: Prepare build directories run: mkdir -p ./build/{debug,release} - name: Configure project (Debug) working-directory: ./build/debug run: cmake ../.. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug - name: Build project (Debug) working-directory: ./build/debug run: cmake --build . --target all --parallel 4 - name: Run tests (Debug) working-directory: ./build/debug run: ctest --force-new-ctest-process --parallel 4 - name: Configure project (Release) working-directory: ./build/release run: cmake ../.. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release - name: Build project (Release) working-directory: ./build/release run: cmake --build . --target all --parallel 4 - name: Install project working-directory: ./build/release run: sudo cmake --build . --target install - name: Package project working-directory: ./build/release run: sudo cpack --config ./CPackSourceConfig.cmake ../debug/CPackSourceConfig.cmake - name: Uninstall project working-directory: ./build/release run: sudo cmake --build . --target uninstall # Windows builds with MSVC windows_build: name: Windows MSVC runs-on: windows-latest steps: - uses: actions/checkout@v4 - name: Verify CMake version run: cmake --version - name: Prepare build directories run: New-Item -ItemType Directory -Force -Path ./build/debug, ./build/release - name: Configure project (Debug) working-directory: ./build/debug run: > cmake ../.. -A x64 -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake" - name: Build project (Debug) working-directory: ./build/debug run: cmake --build . --config Debug --parallel 4 - name: Run tests (Debug) working-directory: ./build/debug run: ctest --output-on-failure --build-config Debug --parallel 4 - name: Configure project (Release) working-directory: ./build/release run: > cmake ../.. -A x64 -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}/stage" -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake" - name: Build project (Release) working-directory: ./build/release run: cmake --build . --config Release --parallel 4 - name: Install project working-directory: ./build/release run: cmake --build . --config Release --target install - name: Package project working-directory: ./build/release run: cmake --build . --config Release --target package - name: Uninstall project working-directory: ./build/release run: cmake --build . --config Release --target uninstall # Cross-compilation for MinGW (Windows) mingw_cross_compile: name: MinGW Cross-Compilation (Windows) runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 - name: Install MinGW toolchain and dependencies run: | sudo apt-get update sudo apt-get install -y gcc-mingw-w64 cmake autotools-dev libtool libusb-1.0-0-dev - name: Cross-compile for Windows run: | sudo sh ./gen_binaries_win.sh stlink-1.9.0/.github/workflows/codeql-analysis.yml000066400000000000000000000047771526027543100222610ustar00rootroot00000000000000# For most projects, this workflow file will not need changing; you simply need # to commit it to your repository. # # You may wish to alter this file to override the set of languages analyzed, # or to provide custom queries or build logic. # # ******** NOTE ******** # We have attempted to detect the languages in your repository. Please check # the `language` matrix defined below to confirm you have the correct set of # supported CodeQL languages. # name: "CodeQL" on: push: branches: [testing, develop, master] pull_request: # The branches below must be a subset of the branches above branches: [testing, develop] schedule: - cron: "00 20 * * 1" jobs: analyze: name: Analyze runs-on: ubuntu-latest strategy: fail-fast: false matrix: language: ["cpp"] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] # Learn more: # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed steps: - name: Install dependencies run: sudo apt update && sudo apt-get install gcc-14 libusb-1.0.0-dev libgtk-4-dev rpm - name: Checkout repository uses: actions/checkout@v4 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v4 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. # By default, queries listed here will override any specified in a config file. # Prefix the list here with "+" to use these queries and those in the config file. # queries: ./path/to/local/query, your-org/your-repo/queries@main # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild uses: github/codeql-action/autobuild@v4 # ℹ� Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl # �� If the Autobuild fails above, remove it and uncomment the following three lines # and modify them (or add more) to build your code if your project # uses a compiled language #- run: | # make bootstrap # make release - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v4 stlink-1.9.0/.gitignore000066400000000000000000000002101526027543100150130ustar00rootroot00000000000000build build-mingw build-mingw-32 build-mingw-64 3rdparty .project .cmake/ .vscode/ obj-* *.user* *.swp build-winsock/ALL_BUILD.vcxprojstlink-1.9.0/.version000066400000000000000000000000061526027543100145140ustar00rootroot000000000000001.9.0 stlink-1.9.0/CHANGELOG.md000066400000000000000000002234721526027543100146550ustar00rootroot00000000000000# stlink Changelog # v1.9.0 Release date: 2026-10-04 This release drops support for some older operating systems. Check project README for details. Updated system requirements: - C-Standard: C17 (ISO/IEC 9899:2018) - `cmake` >= 3.21.0 - `libusb` >= 1.0.24 - `libgtk-3-dev` >= 3.24.30 Features: - Show all info during full erase ([#1363](https://github.com/stlink-org/stlink/pull/1363), commit [#6a6718b](https://github.com/stlink-org/stlink/commit/6a6718b3342b6c5e282a4e33325b9f97908a0692)) - Support for STM32H5 series (erase, read and write) ([#1384](https://github.com/stlink-org/stlink/pull/13824), [#1407](https://github.com/stlink-org/stlink/pull/1407), [#1492](https://github.com/stlink-org/stlink/pull/1492)) - Support for STM32C5 series (erase, read and write) ([#1505](https://github.com/stlink-org/stlink/pull/1505)) - Added support for STLINK-V3PWR ([#1388](https://github.com/stlink-org/stlink/pull/1388), [#1389](https://github.com/stlink-org/stlink/pull/1389)) - Dynamic SRAM size for F4 memory map ([#1390](https://github.com/stlink-org/stlink/pull/1390)) - Modifications to allow building of toolset in OpenBSD ([#1392](https://github.com/stlink-org/stlink/pull/1392)) - --mass-erase for st-flash write commands ([#1397](https://github.com/stlink-org/stlink/pull/1397)) - Support for setting option bytes to STM32L41x_L42x (according to RM0394) ([#1405](https://github.com/stlink-org/stlink/pull/1405), [#1412](https://github.com/stlink-org/stlink/pull/1412), [#1413](https://github.com/stlink-org/stlink/pull/1413)) - Improvements for stlink-gui ([#1411](https://github.com/stlink-org/stlink/pull/1411)) - [STM32U575/585]: Added support for OTP bytes ([#1419](https://github.com/stlink-org/stlink/pull/1419)) - [STM32Gx]: Added erase support for multi-bank products ([#1420](https://github.com/stlink-org/stlink/pull/1420)) - libusb-cmake as libusb provider and added support for MSVC ([#1424](https://github.com/stlink-org/stlink/pull/1424), [#1440](https://github.com/stlink-org/stlink/pull/1440)) - Added support for STM32U073 ([#1436](https://github.com/stlink-org/stlink/pull/1436), commit [#11e357a](https://github.com/stlink-org/stlink/commit/11e357ae2a34c5f5911c0051fa513659b9bbd7fa)) - Added support for STM32L4Q5CG ([#1438](https://github.com/stlink-org/stlink/pull/1438), [#1439](https://github.com/stlink-org/stlink/pull/1439)) - Make SYS_OPEN in semihosting recognize ":tt" ([#1447](https://github.com/stlink-org/stlink/pull/1447)) - Implementation of flash erase in stlink-gui ([#1452](https://github.com/stlink-org/stlink/pull/1452), [#1486](https://github.com/stlink-org/stlink/pull/1486)) - [STM32G4]: Erase pages on flash bank 2 ([#1456](https://github.com/stlink-org/stlink/pull/1456), [#1457](https://github.com/stlink-org/stlink/pull/1457)) - STM32 flash type implementation for WB05, WB06/07, WB09, WL3x ([#1466](https://github.com/stlink-org/stlink/pull/1466)) - Make st-info --probe run probes in parallel ([#1483](https://github.com/stlink-org/stlink/pull/1483)) - Added voltage printout and query for st-info ([#1487](https://github.com/stlink-org/stlink/pull/1487)) - Added st-server (and remote backend) to support remote control of an STLINK programmer ([#1496](https://github.com/stlink-org/stlink/pull/1496)) - Added suport for STM32H533 and trace support for H5/U5/L5 (commit [#6a1d365](https://github.com/stlink-org/stlink/commit/6a1d36530b7ec0004498fb80c947c46e6c537134)) [special credits to Piotr Wasilewski (klonyyy)] Updates & changes: - [stlink-lib] Clarified warning message for data alignment ([#1371](https://github.com/stlink-org/stlink/pull/1371), commit [#40ee5f4](https://github.com/stlink-org/stlink/commit/40ee5f4bd1151cec65f291f0166429b061c6e5c0)) - Rewrite commandline usage text for st-flash tool ([#1372](https://github.com/stlink-org/stlink/pull/1372), commit [#95862cc](https://github.com/stlink-org/stlink/commit/95862cc687203ca20e328804f149959c51da2947)) - Debian 11 x64 doesn't work with v1.8.0 because of incompatible glibc ([#1376](https://github.com/stlink-org/stlink/pull/1376), commit [#ece34ef](https://github.com/stlink-org/stlink/commit/ece34efbce579ca7d367c58f903ffa6dc7bd96e6)) - [STM32L4R5ZI]: gdb-multiarch uses wrong osabi ([#1386](https://github.com/stlink-org/stlink/pull/1386), [#1387](https://github.com/stlink-org/stlink/pull/1387), [#1394](https://github.com/stlink-org/stlink/pull/1394)) - [doc] STM32H573 reports chipid 0x000 ([#1398](https://github.com/stlink-org/stlink/pull/1398), commit [#3655871](https://github.com/stlink-org/stlink/commit/3655871f8dd97294bbee191c1c7341c8a129af2f)) - Corrected and unified GitHub-Actions C/C++ CI workflow ([#1446](https://github.com/stlink-org/stlink/pull/1446), [#1449](https://github.com/stlink-org/stlink/pull/1449)) - [doc] Updated README.md ([#1453](https://github.com/stlink-org/stlink/pull/1453)) - [doc] Corrected libusb package name in installation instructions ([#1455](https://github.com/stlink-org/stlink/pull/1455)) - [st-util] Use remote backend when reconnecting to st-server ([#1498](https://github.com/stlink-org/stlink/pull/1498)) - [stlink-lib] Separate request and response buffers for register access in remote backend ([#1499](https://github.com/stlink-org/stlink/pull/1499)) - Explicit typing for main header files ([#1502](https://github.com/stlink-org/stlink/pull/1502)) - Disable halting debug and disarm fault catches on detach after a reset ([#1503](https://github.com/stlink-org/stlink/pull/1503)) - Use vcpkg with MSVC and added Windows MSVC job to CI ([#1507](https://github.com/stlink-org/stlink/pull/1507), [#1508](https://github.com/stlink-org/stlink/pull/1508)) Fixes: - Can't build stlink 1.8.0 for Fedora ([#1365](https://github.com/stlink-org/stlink/pull/1365), [#1444](https://github.com/stlink-org/stlink/pull/1444), commit [#6a6718b](https://github.com/stlink-org/stlink/commit/6a6718b3342b6c5e282a4e33325b9f97908a0692)) - Fixed include path for header file poll.h ([#1370](https://github.com/stlink-org/stlink/pull/1370), commit [#710e1d3](https://github.com/stlink-org/stlink/commit/710e1d3c3b72187769fcc6a4878c73e35ce03f9b)) - Cmake minimal version mismatch ([#1374](https://github.com/stlink-org/stlink/pull/1374), [#1375](https://github.com/stlink-org/stlink/pull/1375), commit [#1ee7f6b](https://github.com/stlink-org/stlink/commit/1ee7f6b6c05e305112bb070ae571ebbe26c55946)) - Added a graceful way to terminate st-util ([#1395](https://github.com/stlink-org/stlink/pull/1395), [#1396](https://github.com/stlink-org/stlink/pull/1396)) - [st-trace] Bug in function static bool read_trace( ) ([#1400](https://github.com/stlink-org/stlink/pull/1400), commit [#32ce4bf](https://github.com/stlink-org/stlink/commit/32ce4bf88a816fb6a9841a33e6c5f6b593a9b927)) - Fixed STM32H7 FLASH_OPTCR unlock sequence ([#1401](https://github.com/stlink-org/stlink/pull/1401), [#1416](https://github.com/stlink-org/stlink/pull/1416)) - Restored support for STM32G4 Cat4 device STM32G491 ([#1403](https://github.com/stlink-org/stlink/pull/1403), [#1414](https://github.com/stlink-org/stlink/pull/1414)) - Target reset is less reliable on testing branch ([#1409](https://github.com/stlink-org/stlink/pull/1409), commit [#733893a](https://github.com/stlink-org/stlink/commit/733893a50b1cc9323765a62c456c129ed6807886)) - Fixed STM32H7 option byte programming ([#1417](https://github.com/stlink-org/stlink/pull/1417)) - Latest release stlink-1.8.0-win32 doesn't run ([#1364](https://github.com/stlink-org/stlink/pull/1364), [#1410](https://github.com/stlink-org/stlink/pull/1410), commit [#e493109](https://github.com/stlink-org/stlink/commit/e4931097f887d8a048d1d188388b82ced918cf08)) - Fixed STLINK-V3 programmer lock up when no target connected ([#1399](https://github.com/stlink-org/stlink/pull/1399), [#1467](https://github.com/stlink-org/stlink/pull/1467)) - Make path to .chip files relative to installation directory on Windows ([#1421](https://github.com/stlink-org/stlink/pull/1421)) - Re-add support for STM32F411xC/xE option bytes read/write ([#1422](https://github.com/stlink-org/stlink/pull/1422)) - Replaced deprecated cmd to fix package uninstall ([#1426](https://github.com/stlink-org/stlink/pull/1426)) - Fixed compilation error -Wshorten-64-to-32 in stlink-lib/usb.c ([#1427](https://github.com/stlink-org/stlink/pull/1427)) - st-util cannot parse -V and -F options and --freq option results in a segmentation fault ([#1428](https://github.com/stlink-org/stlink/pull/1428), [#1429](https://github.com/stlink-org/stlink/pull/1429)) - st-util: $--freq parameter case sensitive in 1.8.0 but not on previous versions ([#1445](https://github.com/stlink-org/stlink/pull/1445), commit [#7900006](https://github.com/stlink-org/stlink/commit/7900006619ce22cb900151120f9aeebe022cd3ec)) - [STM32F205]: st-flash broken due to introduced bug in stlink-lib/usb.c ([#1451](https://github.com/stlink-org/stlink/pull/1451), commit [#9446bf5](https://github.com/stlink-org/stlink/commit/9446bf570d23f2c1329abd313ae81197b4df4210)) - Compilation: Multiple 64 bit to 32 bit narrowing problems in source code ([#1463](https://github.com/stlink-org/stlink/pull/1463), commit [#54d6de5](https://github.com/stlink-org/stlink/commit/54d6de5ae20cbdec1da49ab97c05406612276ebb)) - Fixed STLINK-V3 programmer lock up when no target connected ([#1467](https://github.com/stlink-org/stlink/pull/1467), commit [#1894b70](https://github.com/stlink-org/stlink/commit/1894b700dee05a031958371ff593bf53d30a93ca)) - Fixed Win32 gettimeofday implementation ([#1468](https://github.com/stlink-org/stlink/pull/1468), commit [#db953ea](https://github.com/stlink-org/stlink/commit/db953eaf0b7b49e84ee3c556e3e4b974b3ebbb38)) - Fixes for MinGW cross compilation on Linux to generate Windows binaries and MSVC compatibility ([#1472](https://github.com/stlink-org/stlink/pull/1472), [#1478](https://github.com/stlink-org/stlink/pull/1478), [#1497](https://github.com/stlink-org/stlink/pull/1497), [#1501](https://github.com/stlink-org/stlink/pull/1501), [#1504](https://github.com/stlink-org/stlink/pull/1504)) - [STM32G0]: st-flash failures ([#1473](https://github.com/stlink-org/stlink/pull/1473), [#1491](https://github.com/stlink-org/stlink/pull/1491), [#1506](https://github.com/stlink-org/stlink/pull/1506)) - [STM32L4R5ZIT6]: STM will halt unless flashed even number of times ([#1482](https://github.com/stlink-org/stlink/pull/1482), commit [#eff714f](https://github.com/stlink-org/stlink/commit/eff714f235c3c361171a89a5b4b6c7602f9d406f)) - Calling NVIC_SystemReset post flashing with st-flash causes STM32 MCU to hang ([#1489](https://github.com/stlink-org/stlink/pull/1489), [#1500](https://github.com/stlink-org/stlink/pull/1500)) - Use bounded strlcpy/snprintf in gdb-server.c ([#1495](https://github.com/stlink-org/stlink/pull/1495)) - `st-info --probe` intermittently misses connected adapters ([#1509](https://github.com/stlink-org/stlink/pull/1509), [#1511](https://github.com/stlink-org/stlink/pull/1511)) - [STM32H7]: Flash errors can never be cleared ([#1512](https://github.com/stlink-org/stlink/pull/1512), commit [#62d8d55](https://github.com/stlink-org/stlink/commit/62d8d550adbe1e283ab606f41481a7231fd6dfd6)) - Fix: Added missing sys/types.h include in semihosting.c ([#1514](https://github.com/stlink-org/stlink/pull/1514)) # v1.8.0 Release date: 2024-02-01 This release drops support for some older operating systems. Check project README for details. Removed Travis CI integration as it is no longer functional. Updated system requirements: - C-Standard: C11 (ISO/IEC 9899:2011) - `cmake` >= 3.13.0 - `libusb` >= 1.0.22 - `libgtk-dev` >= 3.22.30 Features: - Support for writing option bytes on STM32F0/F1/F3 ([#346](https://github.com/stlink-org/stlink/pull/346), [#458](https://github.com/stlink-org/stlink/pull/458), [#808](https://github.com/stlink-org/stlink/pull/808), [#1084](https://github.com/stlink-org/stlink/pull/1084), [#1112](https://github.com/stlink-org/stlink/pull/1112)) - Initial support for STM32 L5 & U5 devices and minor changes ([#1005](https://github.com/stlink-org/stlink/pull/1005), [#1096](https://github.com/stlink-org/stlink/pull/1096), [#1247](https://github.com/stlink-org/stlink/pull/1247), [#1300](https://github.com/stlink-org/stlink/pull/1300), [#1301](https://github.com/stlink-org/stlink/pull/1301)) - Added chip-IDs for STM32G0B0/G0B1/G0C1/G050/G051/G061 ([#1140](https://github.com/stlink-org/stlink/pull/1140), [#1359](https://github.com/stlink-org/stlink/pull/1359)) - Added option byte info for STM32F411XX ([#1141](https://github.com/stlink-org/stlink/pull/1141)) - 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), [#1273](https://github.com/stlink-org/stlink/pull/1273)) - 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)) - Added support for STM32L4Q5 ([#1224](https://github.com/stlink-org/stlink/pull/1224), [#1295](https://github.com/stlink-org/stlink/pull/1295)) - Added writing and reading for STM32WL option bytes ([#1226](https://github.com/stlink-org/stlink/pull/1226), [#1227](https://github.com/stlink-org/stlink/pull/1227)) - Added parametres option_base, option_size for F401xD_xE ([#1235](https://github.com/stlink-org/stlink/pull/1235)) - Added support for option bytes to F1xx_XLD (GD32F30x) ([#1250](https://github.com/stlink-org/stlink/pull/1250)) - Added option byte address for L4Rx devices ([#1254](https://github.com/stlink-org/stlink/pull/1254)) - Added udev-rule rule for the STLink v3 MINIE programmer ([#1274](https://github.com/stlink-org/stlink/pull/1274), [#1281](https://github.com/stlink-org/stlink/pull/1281), [#1358](https://github.com/stlink-org/stlink/pull/1358)) - Added support for STM32C0x1 devices ([#1329](https://github.com/stlink-org/stlink/pull/1329), [#1354](https://github.com/stlink-org/stlink/pull/1354)) - First Implementation of the OTP Read/Write function ([#1352](https://github.com/stlink-org/stlink/pull/1352), [#1353](https://github.com/stlink-org/stlink/pull/1353)) Updates & changes: - [refactoring] Moved chip-specific parameters into separate files ([#237](https://github.com/stlink-org/stlink/pull/237), [#1129](https://github.com/stlink-org/stlink/pull/1129)) - [refactoring] General maintenance for code structure ([#903](https://github.com/stlink-org/stlink/pull/903), [#1090](https://github.com/stlink-org/stlink/pull/1090), [#1199](https://github.com/stlink-org/stlink/pull/1199), [#1212](https://github.com/stlink-org/stlink/pull/1212), [#1216](https://github.com/stlink-org/stlink/pull/1216), [#1228](https://github.com/stlink-org/stlink/pull/1228)) - 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 (commit [#f5ada94](https://github.com/stlink-org/stlink/commit/f5ada9474cdb87ff37de0d4eb9e75622b5870646)) - [refactoring] Clean code with unified variable type ([#909](https://github.com/stlink-org/stlink/pull/909), commit [#5e85fd0](https://github.com/stlink-org/stlink/commit/5e85fd063908f89499180c28fe5e9ba74868b272)) - 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)) - [doc] Human-readable flash_type in chip-id files ([#1155](https://github.com/stlink-org/stlink/pull/1155), commit [#1745bf5](https://github.com/stlink-org/stlink/commit/1745bf5193c4d3186d4f6fde59cc86e9bad6e61b)) - 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)) - Ability to flash F7 devices when in dual-bank mode ([#1174](https://github.com/stlink-org/stlink/pull/1174)) - 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)) - [refactoring] Sourcefile 'common.c' ([#1218](https://github.com/stlink-org/stlink/pull/1218), [#1220](https://github.com/stlink-org/stlink/pull/1220)) - [STM32H735]: Set hardware breakpoints for external bus ([#1219](https://github.com/stlink-org/stlink/pull/1219)) - Set C standard through cmake variables ([#1221](https://github.com/stlink-org/stlink/pull/1221)) - [doc] Added make install to the macOS compiling instructions ([#1259](https://github.com/stlink-org/stlink/pull/1259)) - [doc] Linux Install from code Documentation improvement ([#1263](https://github.com/stlink-org/stlink/pull/1263), commit [#43498de](https://github.com/stlink-org/stlink/commit/43498dedf651260ef34197e512d35e3ad7142401)) - End of support for macOS ([#1269](https://github.com/stlink-org/stlink/pull/1269), [#1296](https://github.com/stlink-org/stlink/pull/1296), commit [#61ff09e](https://github.com/stlink-org/stlink/commit/61ff09e5274d46a46ae58bc4ffe44fe90a887ea6)) - [doc] Added device ID for GD32F303VET6 ([#1288](https://github.com/stlink-org/stlink/pull/1288)) - [doc] Fixed broken links ([#1312](https://github.com/stlink-org/stlink/pull/1312)) - [doc] Updated package source link for Arch Linux ([#1318](https://github.com/stlink-org/stlink/pull/1318)) - CMake: Avoid hard-wired /usr/local/share ([#1325](https://github.com/stlink-org/stlink/pull/1325)) - [doc] Provide access to the UART via virtual com port ([#1334](https://github.com/stlink-org/stlink/pull/1334), commit [#32e8dcc](https://github.com/stlink-org/stlink/commit/32e8dcc8b5dbed7b6412e7838ea1b2c41f0247fd)) Fixes: - Fixed some flashing issues on STM32L0 ([#681](https://github.com/stlink-org/stlink/pull/681), [#1203](https://github.com/stlink-org/stlink/pull/1203), [#1225](https://github.com/stlink-org/stlink/pull/1225), [#1253](https://github.com/stlink-org/stlink/pull/1253), [#1289](https://github.com/stlink-org/stlink/pull/1289), [#1330](https://github.com/stlink-org/stlink/pull/1330)) - cmake: Install shared libraries in proper directories ([#1098](https://github.com/stlink-org/stlink/pull/1098), [#1138](https://github.com/stlink-org/stlink/pull/1138), [#1154](https://github.com/stlink-org/stlink/pull/1154)) - cmake: Install shared libraries in proper directories ([#1142](https://github.com/stlink-org/stlink/pull/1142)) - Fixed clearance of the H7 dual bank flag ([#1146](https://github.com/stlink-org/stlink/pull/1146), [#1147](https://github.com/stlink-org/stlink/pull/1147), [#1342](https://github.com/stlink-org/stlink/pull/1342)) - Fix for 'libusb_devices were leaked' when no ST-LINK programmer was found ([#1150](https://github.com/stlink-org/stlink/pull/1150)) - Set of fixes and improvements ([#1153](https://github.com/stlink-org/stlink/pull/1153), [#1154](https://github.com/stlink-org/stlink/pull/1154)) - Removed limit check for WRITEMEM_32BIT ([#1157](https://github.com/stlink-org/stlink/pull/1157)) - Fixed get_stm32l0_flash_base address for STM32L152RE ([#1161](https://github.com/stlink-org/stlink/pull/1161), [#1162](https://github.com/stlink-org/stlink/pull/1162)) - Fixed segfault if chip was not found in chip config files ([#1138](https://github.com/stlink-org/stlink/pull/1138), [#1163](https://github.com/stlink-org/stlink/pull/1163), [#1165](https://github.com/stlink-org/stlink/pull/1165), [#1166](https://github.com/stlink-org/stlink/pull/1166), [#1170](https://github.com/stlink-org/stlink/pull/1170)) - Fixed parsing hex numbers in chip config files ([#1156](https://github.com/stlink-org/stlink/pull/1156), commit [#1d301a5](https://github.com/stlink-org/stlink/commit/1d301a5498433900250fe2a8c0e10dfb7f44d7a4)) - Fixed parsing hex numbers in chip config files ([#1169](https://github.com/stlink-org/stlink/pull/1169)) - Corrected flash_pagesize to use hex format ([#1172](https://github.com/stlink-org/stlink/pull/1172)) - Fixed compilation for MSVC ([#1176](https://github.com/stlink-org/stlink/pull/1176)) - 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)) - [STM32G031G8]: BOOT_LOCK is not possible to change on option bytes address 0x1FFF7870 ([#1194](https://github.com/stlink-org/stlink/pull/1194)) - 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)) - Fix for libusb_kernel_driver_active & error handling for st.st_size () ([#1210](https://github.com/stlink-org/stlink/pull/1210), [#1211](https://github.com/stlink-org/stlink/pull/1211), [#1214](https://github.com/stlink-org/stlink/pull/1214)) - General fixes and improvements ([#1240](https://github.com/stlink-org/stlink/pull/1240), [#1242](https://github.com/stlink-org/stlink/pull/1242), [#1290](https://github.com/stlink-org/stlink/pull/1290), [#1291](https://github.com/stlink-org/stlink/pull/1291), [#1295](https://github.com/stlink-org/stlink/pull/1295)) - Fixes for project compilation ([#1241](https://github.com/stlink-org/stlink/pull/1241), [#1271](https://github.com/stlink-org/stlink/pull/1271), [#1283](https://github.com/stlink-org/stlink/pull/1283), [#1286](https://github.com/stlink-org/stlink/pull/1286),commit [#f93adb9](https://github.com/stlink-org/stlink/commit/f93adb92f2e4ecf05a9361cb723c98693586929d)) - st-trace: Fixed clock issues ([#1248](https://github.com/stlink-org/stlink/pull/1248), [#1251](https://github.com/stlink-org/stlink/pull/1251), [#1252](https://github.com/stlink-org/stlink/pull/1252)) - Fixed compilation with gcc-12 ([#1257](https://github.com/stlink-org/stlink/pull/1257), [#1267](https://github.com/stlink-org/stlink/pull/1267)) - Fixed flash regs addr for STM32L152RET6 in common_flash.c ([#1265](https://github.com/stlink-org/stlink/pull/1265)) - Fixed flash, dbgmcu and rcc registers for STM32L1 ([#1266](https://github.com/stlink-org/stlink/pull/1266)) - Fixed incorrect SRAM size for L496x and L4A6x ([#1268](https://github.com/stlink-org/stlink/pull/1268), commit [#ff81148](https://github.com/stlink-org/stlink/commit/ff8114895a9fc32cae6a9374e58eac6256d68183)) - Fixed st-trace reconnect on Windows ([#1272](https://github.com/stlink-org/stlink/pull/1272), [#1292](https://github.com/stlink-org/stlink/pull/1292)) - [compilation] Corrected path to stlink/chips subdirectory ([#1276](https://github.com/stlink-org/stlink/pull/1276), [#1279](https://github.com/stlink-org/stlink/pull/1279)) - [compilation] Fixed GUI compilation failure on OpenBSD i386 ([#1284](https://github.com/stlink-org/stlink/pull/1284)) - [STM32U5x5]: Last bytes are not written (flashed) when len()%16 <= 8 ([#1303](https://github.com/stlink-org/stlink/pull/1303), [#1315](https://github.com/stlink-org/stlink/pull/1315)) - [STM32WLE]: Erase flash fails on second page ([#1305](https://github.com/stlink-org/stlink/pull/1305), commit [#7dcb130](https://github.com/stlink-org/stlink/commit/7dcb1302d8b91b2217c4ce50cb255aa8e78ab001)) - Fixed unbounded write and check return values of sscanf ([#1306](https://github.com/stlink-org/stlink/pull/1306)) - Added null check for return value of stlink_chipid_get_params() ([#1307](https://github.com/stlink-org/stlink/pull/1307)) - Fixed warning in a few *.cmake files ([#1309](https://github.com/stlink-org/stlink/pull/1309)) - Fixed support for STM32U5 chips ([#1320](https://github.com/stlink-org/stlink/pull/1320), [#1355](https://github.com/stlink-org/stlink/pull/1355)) - [STM32G0B1]: Erase fails starting page 64 ([#1321](https://github.com/stlink-org/stlink/pull/1321)) - Notification "unknown option -- u" in tool st-util ([#1326](https://github.com/stlink-org/stlink/pull/1326), [#1327](https://github.com/stlink-org/stlink/pull/1327)) - Do not crash when the STLink chip returns a voltage factor of zero ([#1343](https://github.com/stlink-org/stlink/pull/1343)) - stlink-gui: failed to allocate 139988352155568 bytes ([#1356](https://github.com/stlink-org/stlink/pull/1356)) - [STM32U575RGT6]: Verification failed at offset 43008 ([#1362](https://github.com/stlink-org/stlink/pull/1362), commit [#0145bae](https://github.com/stlink-org/stlink/commit/0145baeb2e3bac31bf9d3cbd0dab38d70618d46b)) - Use real F4 sector sizes for STM32F410/F413 erase ([#1494](https://github.com/stlink-org/stlink/pull/1494)) # v1.7.0 Release date: 2021-04-25 This release drops support for the STLINK/V1 programmer on macOS 10.13. Features: - Extended set of cmd line arguments for st-info and st-util ([#332](https://github.com/stlink-org/stlink/pull/332), [#990](https://github.com/stlink-org/stlink/pull/990), [#1091](https://github.com/stlink-org/stlink/pull/1091), [#1114](https://github.com/stlink-org/stlink/pull/1114)) - Extended support for STM32H7 & rework of software reset ([#532](https://github.com/stlink-org/stlink/pull/532), [#801](https://github.com/stlink-org/stlink/pull/801), [#868](https://github.com/stlink-org/stlink/pull/868), [#1008](https://github.com/stlink-org/stlink/pull/1008), [#1059](https://github.com/stlink-org/stlink/pull/1059), [#1063](https://github.com/stlink-org/stlink/pull/1063), [#1071](https://github.com/stlink-org/stlink/pull/1071)) - Added support for STM32H742/743/753 ([#671](https://github.com/stlink-org/stlink/pull/671), [#793](https://github.com/stlink-org/stlink/pull/793), [#823](https://github.com/stlink-org/stlink/pull/823), [#998](https://github.com/stlink-org/stlink/pull/998), [#1052](https://github.com/stlink-org/stlink/pull/1052), [#1184](https://github.com/stlink-org/stlink/pull/1184), [#1324](https://github.com/stlink-org/stlink/pull/1324)) - Official support for STLINK-V3 programmers (commit [#5e0a502](https://github.com/stlink-org/stlink/commit/5e0a502df812495bfa96fa9116a19f1306152b17), [#820](https://github.com/stlink-org/stlink/pull/820), [#1022](https://github.com/stlink-org/stlink/pull/1022), [#1025](https://github.com/stlink-org/stlink/pull/1025)) - Added preliminary support for STM32L5x2 ([#904](https://github.com/stlink-org/stlink/pull/904), [#999](https://github.com/stlink-org/stlink/pull/999)) - Option bytes on the STM32F767 ZIT6 Nucleo-144 ([#968](https://github.com/stlink-org/stlink/pull/968), [#997](https://github.com/stlink-org/stlink/pull/997)) - Use SetConsoleCtrlHandler for Windows ([#1021](https://github.com/stlink-org/stlink/pull/1021)) - Increase STM32L0 `option_size` to 20 ([#1046](https://github.com/stlink-org/stlink/pull/1046)) - `st-util`: Add specialized memory map for STM32H7 devices ([#1060](https://github.com/stlink-org/stlink/pull/1060)) - Support for STM32F4 option bytes ([#1062](https://github.com/stlink-org/stlink/pull/1062)) - Link for WIN32 & APPLE with stlink-static ([#1069](https://github.com/stlink-org/stlink/pull/1069)) - ITM functionality for STLink/V2 and STM32Fxx chipsets ([#136](https://github.com/stlink-org/stlink/pull/136), [#179](https://github.com/stlink-org/stlink/pull/179), [#815](https://github.com/stlink-org/stlink/pull/815), [#1072](https://github.com/stlink-org/stlink/pull/1072)) - Included ITM functionality for building with MSVC ([#1080](https://github.com/stlink-org/stlink/pull/1080)) - Update for CI integration (commit [#0eebc9a](https://github.com/stlink-org/stlink/commit/0eebc9a74506e84d5c460ec325ae98064a81885e), [#1118](https://github.com/stlink-org/stlink/pull/1118)) Updates & changes: - [doc] Added tutorial section on unknown chip id error (commit [#229c721](https://github.com/stlink-org/stlink/commit/229c721189587760db5509c59b3c02e93e7035c8), [#107](https://github.com/stlink-org/stlink/pull/107), [#568](https://github.com/stlink-org/stlink/pull/568)) - [doc] Updated documentation on target resetting ([#261](https://github.com/stlink-org/stlink/pull/261), [#533](https://github.com/stlink-org/stlink/pull/533), [#1107](https://github.com/stlink-org/stlink/pull/1107)) - [doc] Added note on `(gdb) run` command (commit [#03793d4](https://github.com/stlink-org/stlink/commit/03793d42b6078344a9ef8ad55f1d5d0fc19e486e), [#267](https://github.com/stlink-org/stlink/pull/267)) - [doc] `st-flash --reset` parameter (one solution for #356) ([#642](https://github.com/stlink-org/stlink/pull/642)) - [refactoring] General maintenance ([#864](https://github.com/stlink-org/stlink/pull/864). [#978](https://github.com/stlink-org/stlink/pull/978)) - Imported debian pkg-settings ([#986](https://github.com/stlink-org/stlink/pull/986)) - Add support for FreeBSD's `libusb` reimplementation ([#992](https://github.com/stlink-org/stlink/pull/992), [#993](https://github.com/stlink-org/stlink/pull/993)) - [doc] Added explanation about STM32F103 fake chips (commit [#a66557a](https://github.com/stlink-org/stlink/commit/a66557a102d48e69feb0a9746e8e42c4baf31fe2), [#1024](https://github.com/stlink-org/stlink/pull/1024)) - [doc] Added example for output of `st-info --probe` ([#1007](https://github.com/stlink-org/stlink/pull/1007), [#1049](https://github.com/stlink-org/stlink/pull/1049)) - [refactoring] Correctly handle endianness without reference to host platform ([#1081](https://github.com/stlink-org/stlink/pull/1081)) - Check format string for log messages ([#1093](https://github.com/stlink-org/stlink/pull/1093)) - Removed abort() from stlink-lib ([#1116](https://github.com/stlink-org/stlink/pull/1116)) Fixes: - Improvements and fixes of the flash loaders, unification of the reset function ([#244](https://github.com/stlink-org/stlink/pull/244), [#382](https://github.com/stlink-org/stlink/pull/382), [#705](https://github.com/stlink-org/stlink/pull/705), [#724](https://github.com/stlink-org/stlink/pull/724), [#980](https://github.com/stlink-org/stlink/pull/980), [#995](https://github.com/stlink-org/stlink/pull/995), [#1008](https://github.com/stlink-org/stlink/pull/1008), [#1115](https://github.com/stlink-org/stlink/pull/1115), [#1117](https://github.com/stlink-org/stlink/pull/1117), [#1122](https://github.com/stlink-org/stlink/pull/1122), [#1124](https://github.com/stlink-org/stlink/pull/1124)) - Flash loader rework ([#356](https://github.com/stlink-org/stlink/pull/356), [#556](https://github.com/stlink-org/stlink/pull/556), [#593](https://github.com/stlink-org/stlink/pull/593), [#597](https://github.com/stlink-org/stlink/pull/597), [#607](https://github.com/stlink-org/stlink/pull/607), [#612](https://github.com/stlink-org/stlink/pull/612), [#638](https://github.com/stlink-org/stlink/pull/638), [#661](https://github.com/stlink-org/stlink/pull/661), [#690](https://github.com/stlink-org/stlink/pull/690), [#724](https://github.com/stlink-org/stlink/pull/724), [#807](https://github.com/stlink-org/stlink/pull/807), [#817](https://github.com/stlink-org/stlink/pull/817), [#818](https://github.com/stlink-org/stlink/pull/818), [#854](https://github.com/stlink-org/stlink/pull/854), [#868](https://github.com/stlink-org/stlink/pull/868), [#967](https://github.com/stlink-org/stlink/pull/967), [#979](https://github.com/stlink-org/stlink/pull/979), [#1008](https://github.com/stlink-org/stlink/pull/1008), [#1043](https://github.com/stlink-org/stlink/pull/1043), [#1054](https://github.com/stlink-org/stlink/pull/1054), [#1092](https://github.com/stlink-org/stlink/pull/1092), [#1105](https://github.com/stlink-org/stlink/pull/1105), [#1113](https://github.com/stlink-org/stlink/pull/1113)) - Fixed old DFU serial number for STLINK programmers ([#417](https://github.com/stlink-org/stlink/pull/417), [#494](https://github.com/stlink-org/stlink/pull/494), [#1106](https://github.com/stlink-org/stlink/pull/1106), [#1121](https://github.com/stlink-org/stlink/pull/1121)) - Improvements for Chip_ID read ([#620](https://github.com/stlink-org/stlink/pull/620), [#1008](https://github.com/stlink-org/stlink/pull/1008), [#1120](https://github.com/stlink-org/stlink/pull/1120)) - Use vl flashloader for all STM32F1 series ([#724](https://github.com/stlink-org/stlink/pull/724), [#769](https://github.com/stlink-org/stlink/pull/769), [#1041](https://github.com/stlink-org/stlink/pull/1041), [#1044](https://github.com/stlink-org/stlink/pull/1044)) - [regression] Changed timeout on flash write ([#787](https://github.com/stlink-org/stlink/pull/787), [#981](https://github.com/stlink-org/stlink/pull/981), [#987](https://github.com/stlink-org/stlink/pull/987)) - cmake compile failure with external `CMAKE_MODULE_PATH` set ([#962](https://github.com/stlink-org/stlink/pull/962)) - doc/man: Fixed installation directory ([#970](https://github.com/stlink-org/stlink/pull/970)) - Fixed installation path for desktop-file and icons ([#972](https://github.com/stlink-org/stlink/pull/972)) - Fix for static linking of `libssp` ([#973](https://github.com/stlink-org/stlink/pull/973), [#974](https://github.com/stlink-org/stlink/pull/974)) - [regression] Fixed wrong formatting for library install path ([#978](https://github.com/stlink-org/stlink/pull/978), [#1089](https://github.com/stlink-org/stlink/pull/1089), [#1277](https://github.com/stlink-org/stlink/pull/1277)) - Fixed installation of header files needed for compiling with `libstlink.so.1.6.1` (commit [#31b1fa1](https://github.com/stlink-org/stlink/commit/31b1fa16201521e2aaf464576f2f169981abede0), [#982](https://github.com/stlink-org/stlink/pull/982)) - Fixed `connect under reset` for `st-flash` and `st-util` ([#983](https://github.com/stlink-org/stlink/pull/983)) - Fix for `mmap() size_t overflow` in `st-flash` ([#988](https://github.com/stlink-org/stlink/pull/988), [#989](https://github.com/stlink-org/stlink/pull/989)) - [regression] `stlink-gui` installation issue on Ubuntu-18.04 ([#1001](https://github.com/stlink-org/stlink/pull/1001), [#1004](https://github.com/stlink-org/stlink/pull/1004), [#1006](https://github.com/stlink-org/stlink/pull/1006)) - `st-util`: wrong register values passed to `gdb` (STLink/V2) ([#1002](https://github.com/stlink-org/stlink/pull/1002), [#1011](https://github.com/stlink-org/stlink/pull/1011), [#1026](https://github.com/stlink-org/stlink/pull/1026), [#1027](https://github.com/stlink-org/stlink/pull/1027), [#1038](https://github.com/stlink-org/stlink/pull/1038), [#1064](https://github.com/stlink-org/stlink/pull/1064), [#1065](https://github.com/stlink-org/stlink/pull/1065)) - GDB: Fixed problems with target description ([#1013](https://github.com/stlink-org/stlink/pull/1013), [#1088](https://github.com/stlink-org/stlink/pull/1088), [#1109](https://github.com/stlink-org/stlink/pull/1109)) - [doc] Fixed wrong path for `rules.d` folder ([#1020](https://github.com/stlink-org/stlink/pull/1020)) - Fixed support for STLINK/V1 programmer ([#1045](https://github.com/stlink-org/stlink/pull/1045), [#1105](https://github.com/stlink-org/stlink/pull/1105)) - st-util v1.6.1 does not recognize option --freq (commit [#e576768](https://github.com/stlink-org/stlink/commit/e5767681f14de9851aa970a9299930ca68b2ed92), [#1055](https://github.com/stlink-org/stlink/pull/1055)) - Fixed `gettimeofday` for MSVC ([#1074](https://github.com/stlink-org/stlink/pull/1074)) - Bugfixes for compilation with clang ([#1076](https://github.com/stlink-org/stlink/pull/1076), [#1078](https://github.com/stlink-org/stlink/pull/1078)) - Fixed compilation with GCC 11 ([#1077](https://github.com/stlink-org/stlink/pull/1077)) - [regression] Flash_loader: increased wait rounds for slow boards ([#1085](https://github.com/stlink-org/stlink/pull/1085)) - Fixed support for writing option bytes ([#1102](https://github.com/stlink-org/stlink/pull/1102), [#1128](https://github.com/stlink-org/stlink/pull/1128)) - [doc] Corrected spelling mistake in bug report template ([#1103](https://github.com/stlink-org/stlink/pull/1103)) - Fixed STM32WB55 reading DEBUG IDCODE from the wrong address ([#1100](https://github.com/stlink-org/stlink/pull/1100), [#1101](https://github.com/stlink-org/stlink/pull/1101)) - Applied missing changes to tests ([#1119](https://github.com/stlink-org/stlink/pull/1119)) - Fixed reading of chip ID on Cortex-M0+ core ([#1017](https://github.com/stlink-org/stlink/pull/1017), [#1125](https://github.com/stlink-org/stlink/pull/1125), [#1126](https://github.com/stlink-org/stlink/pull/1126), [#1133](https://github.com/stlink-org/stlink/pull/1133)) # v1.6.1 Release date: 2020-06-01 This release drops support for some older operating systems. Check project README for details. Features: - Basic compatibility for STLink/V3 programmer ([#271](https://github.com/stlink-org/stlink/pull/271), [#863](https://github.com/stlink-org/stlink/pull/863), [#954](https://github.com/stlink-org/stlink/pull/954), [#1023](https://github.com/stlink-org/stlink/pull/1023)) - Added support for JTAG command API v2 & distinguish protocol versions v1 and v2 - Compatibility with the STLink/V3 firmware which dropped support for the previous API v1 - As of firmware version J11 the STLink/V1 programmer supports API v2 commands as well - Display programmer serial when no target is connected ([#432](https://github.com/stlink-org/stlink/pull/432), [#933](https://github.com/stlink-org/stlink/pull/933), [#943](https://github.com/stlink-org/stlink/pull/943)) - Added `connect under reset` to `stlink_open_usb( )` ([#577](https://github.com/stlink-org/stlink/pull/577), [#963](https://github.com/stlink-org/stlink/pull/963)) - Support for STM32L1, SM32L4 option bytes write ([#596](https://github.com/stlink-org/stlink/pull/596), [#844](https://github.com/stlink-org/stlink/pull/844), [#847](https://github.com/stlink-org/stlink/pull/847)) - Added `CMAKEFLAGS` and install target ([#804](https://github.com/stlink-org/stlink/pull/804), [#935](https://github.com/stlink-org/stlink/pull/935)) - Support for STM32G4 ([#822](https://github.com/stlink-org/stlink/pull/822)) - Added aliased SRAM2 region in the L496 memory map ([#824](https://github.com/stlink-org/stlink/pull/824)) - Improved support for STM32G0 ([#825](https://github.com/stlink-org/stlink/pull/825), [#850](https://github.com/stlink-org/stlink/pull/850), [#856](https://github.com/stlink-org/stlink/pull/856), [#857](https://github.com/stlink-org/stlink/pull/857)) - Added postinst script with `depmod -a` for `make package` ([#845](https://github.com/stlink-org/stlink/pull/845), [#931](https://github.com/stlink-org/stlink/pull/931)) - Calculate checksums for flash operations ([#862](https://github.com/stlink-org/stlink/pull/862), [#924](https://github.com/stlink-org/stlink/pull/924)) - Adjust the JTAG/SWD frequency via cmdline option ([#893](https://github.com/stlink-org/stlink/pull/893), [#953](https://github.com/stlink-org/stlink/pull/953)) - Added usb PID and udev rules for STLink/V2.1 found on Nucleo-L432KC and Nucleo-L552ze boards ([#900](https://github.com/stlink-org/stlink/pull/900)) - STM32G0/G4 improvements ([#910](https://github.com/stlink-org/stlink/pull/910)) - Enable mass erase with a flash programming check - Handle G4 Cat3 devices with configurable dual bank flash by using a helper Updates & changes: - [doc] Updated compiling instructions ([#113](https://github.com/stlink-org/stlink/pull/113), commit [#10ae529](https://github.com/stlink-org/stlink/commit/10ae5294cd03aacfc07312010f026d3cb12ea56c)) - Defined `libusb` version compatibility for supported systems via `LIBUSB_API_VERSION` ([#211](https://github.com/stlink-org/stlink/pull/211), [#782](https://github.com/stlink-org/stlink/pull/782), [#895](https://github.com/stlink-org/stlink/pull/895)) - Improved argument parsing for CLI tools ([#378](https://github.com/stlink-org/stlink/pull/378), [#922](https://github.com/stlink-org/stlink/pull/922)) - [doc] Updated tutorial: macOS STLink/V1 detection ([#574](https://github.com/stlink-org/stlink/pull/574), [#587](https://github.com/stlink-org/stlink/pull/587)) - Enhanced error log with file path for `map_file()` ([#650](https://github.com/stlink-org/stlink/pull/650), [#879](https://github.com/stlink-org/stlink/pull/879), [#921](https://github.com/stlink-org/stlink/pull/921)) - Enhanced output for error msg `addr not a multiple of pagesize, not supported` ([#663](https://github.com/stlink-org/stlink/pull/663), [#945](https://github.com/stlink-org/stlink/pull/945)) - Updated STLink/V1 driver for macOS ([#735](https://github.com/stlink-org/stlink/pull/735), [#964](https://github.com/stlink-org/stlink/pull/964)) - Package distribution: Provide Windows binaries via Debian-based cross-build ([#738](https://github.com/stlink-org/stlink/pull/738), [#795](https://github.com/stlink-org/stlink/pull/795), [#798](https://github.com/stlink-org/stlink/pull/798), [#870](https://github.com/stlink-org/stlink/pull/870), [#955](https://github.com/stlink-org/stlink/pull/955)) - [refactoring] Update, corrections & cleanup for build settings (see #955 for details) - New `cpack` package-config for DEB and RPM build - Update for travis build configuration: builds for `clang -m32`, `clang-9`, MinGW-cross on linux - Updated steps for release preparation - Project contributors now listed in separate file - Test files & gui now use shared `stlink-library` - [doc] Verify correct udev configuration for device access ([#764](https://github.com/stlink-org/stlink/pull/764)) - Added more error info to `WLOGs` during probe ([#883](https://github.com/stlink-org/stlink/pull/883)) - [doc] Added missing documentation for stlink-gui ([#884](https://github.com/stlink-org/stlink/pull/884)) - Added check for `libssp` during compilation ([#885](https://github.com/stlink-org/stlink/pull/885)) - Silenced unnecessary messages ([#886](https://github.com/stlink-org/stlink/pull/886)) - [doc] Defined `libusb` & `cmake` version compatibility ([#896](https://github.com/stlink-org/stlink/pull/896), [#897](https://github.com/stlink-org/stlink/pull/897), [#899](https://github.com/stlink-org/stlink/pull/899), commit [#27aa888](https://github.com/stlink-org/stlink/commit/27aa88821197d3ffe82baff4e971c3488ec39899)) - Update for STM32G471/473/474/483/484 devices ([#901](https://github.com/stlink-org/stlink/pull/901)) - [doc] `st-flash --flash=n[k][m]` command line option to override device model ([#902](https://github.com/stlink-org/stlink/pull/902)) - [refactoring] Improved cmake build process ([#912](https://github.com/stlink-org/stlink/pull/912)) - Set up a `libusb` log level accordingly to verbosity ([#894](https://github.com/stlink-org/stlink/pull/894) - [compatibility] Updated `libusb` to v1.0.23 ([#895](https://github.com/stlink-org/stlink/pull/895) - Updated compiling doc & version support ([#896](https://github.com/stlink-org/stlink/pull/896), [#897](https://github.com/stlink-org/stlink/pull/897), [#899](https://github.com/stlink-org/stlink/pull/899)) - Version requirements & pkg-maintainer - Fixed install paths in build script - Updated C-flag `-std=gnu99` to `gnu11`) - Added `cmake` uninstall target ([#619](https://github.com/stlink-org/stlink/pull/619), [#907](https://github.com/stlink-org/stlink/pull/907)) - Integrated module `GNUInstallDirs.cmake` ([#557](https://github.com/stlink-org/stlink/pull/557)) - [doc] Defined version compatibility and installation instructions for macOS - [refactoring] `libusb` detection - Deprecated old `appveyor-mingw` script - [refactoring] BSD-License-compliant rewrite of flashloader source files ([#915](https://github.com/stlink-org/stlink/pull/915), [#932](https://github.com/stlink-org/stlink/pull/932)) - [refactoring] Overall option code rework ([#927](https://github.com/stlink-org/stlink/pull/927)) - [refactoring] Build settings / GUI-Build on UNIX-based systems if `GTK3` is detected ([#929](https://github.com/stlink-org/stlink/pull/929)) - [refactoring] Reconfiguration of package build process ([#931](https://github.com/stlink-org/stlink/pull/931), [#936](https://github.com/stlink-org/stlink/pull/936), [#940](https://github.com/stlink-org/stlink/pull/940), commit [#9b19f92](https://github.com/stlink-org/stlink/commit/9b19f9225460472af9d98959b7217d0a840ee972)) - [refactoring] `st-util`: Removed now useless v1/v2 STLink version stuff ([#934](https://github.com/stlink-org/stlink/pull/934)) - [refactoring] Cleanup for option bytes and flash settings ([#941](https://github.com/stlink-org/stlink/pull/941)) - Added compilation guideline for MSVC toolchain ([#942](https://github.com/stlink-org/stlink/pull/942)) - [refactoring] Cleanup of `cmake` build process ([#944](https://github.com/stlink-org/stlink/pull/944), [#946](https://github.com/stlink-org/stlink/pull/946), [#947](https://github.com/stlink-org/stlink/pull/947)) - `libusb` package extraction no longer requires `7zip` as an external unarchiver Fixes: - Fixed wait-loop for `flash_loader_run()` ([#290](https://github.com/stlink-org/stlink/pull/290)) - Better argument parsing for CLI tools: `stlink_open_usb` can address v1, v2, v3 ([#378](https://github.com/stlink-org/stlink/pull/378), [#922](https://github.com/stlink-org/stlink/pull/922)) - Clear the PG bit before setting the `PER` bit ([#579](https://github.com/stlink-org/stlink/pull/579), [#876](https://github.com/stlink-org/stlink/pull/876)) - Fixed compilation issues with int length on 32-bit platforms ([#629](https://github.com/stlink-org/stlink/pull/629), [#908](https://github.com/stlink-org/stlink/pull/908)) - Fixed `st-info --probe` mechanism ([#679](https://github.com/stlink-org/stlink/pull/679), [#918](https://github.com/stlink-org/stlink/pull/918)) - [regression] Fixed sign-compare (`size != rep_len`) in `usb.c` ([#772](https://github.com/stlink-org/stlink/pull/772), [#869](https://github.com/stlink-org/stlink/pull/869), [#872](https://github.com/stlink-org/stlink/pull/872), [#891](https://github.com/stlink-org/stlink/pull/891)) - Fixed dead loop after an unexpected unplug ([#780](https://github.com/stlink-org/stlink/pull/780), [#812](https://github.com/stlink-org/stlink/pull/812), [#913](https://github.com/stlink-org/stlink/pull/913)) - Avoid re-define of `O_BINARY` on Windows ([#788](https://github.com/stlink-org/stlink/pull/788)) - Fixed stlink lock-up when not connected to a device via JTAG / SWD ([#835](https://github.com/stlink-org/stlink/pull/835), [#943](https://github.com/stlink-org/stlink/pull/943)) - Fixed `st-flash` manpage read example ([#858](https://github.com/stlink-org/stlink/pull/858)) - Fixed stlink support with no mass storage ([#861](https://github.com/stlink-org/stlink/pull/861)) - Make `version.cmake` more error-resistant ([#872](https://github.com/stlink-org/stlink/pull/872)) - Error return in failed probe ([#887](https://github.com/stlink-org/stlink/pull/887), [#890](https://github.com/stlink-org/stlink/pull/890)) - Fixed broken build on 32-bit systems ([#919](https://github.com/stlink-org/stlink/pull/919), [#920](https://github.com/stlink-org/stlink/pull/920)) - `st-flash`: Minor usage fix and make cmdline parsing more user friendly ([#925](https://github.com/stlink-org/stlink/pull/925)) - [regression] Restored functionality of make test builds ([#926](https://github.com/stlink-org/stlink/pull/926), [#929](https://github.com/stlink-org/stlink/pull/929)) - Fixed compilation error due to uninitialized cpuid ([#937](https://github.com/stlink-org/stlink/pull/937), [#938](https://github.com/stlink-org/stlink/pull/938)) - Fixes for STM32F0 flashloader ([#958](https://github.com/stlink-org/stlink/pull/958), [#959](https://github.com/stlink-org/stlink/pull/959)) - Set static link for `libssp` (stack-smashing protection) ([#960](https://github.com/stlink-org/stlink/pull/960), [#961](https://github.com/stlink-org/stlink/pull/961)) - Fixed udev rules installing to wrong directory ([#966](https://github.com/stlink-org/stlink/pull/966)) - Fixed formatting for options display in `st-flash` & `st-info` (commits [#c783d0e](https://github.com/stlink-org/stlink/commit/c783d0e777ccc83a7a8be26a4f4d3414e0478560) and [#562cd24](https://github.com/stlink-org/stlink/commit/562cd2496e696dbd22950925866aac662d81ee5f)) # v1.6.0 Release date: 2020-02-20 Major changes and added features: - Initial support for STM32L41X ([#754](https://github.com/stlink-org/stlink/pull/754), [#799](https://github.com/stlink-org/stlink/pull/799)) - Verified support for CKS32F103C8T6 and related CKS devices with Core-ID 0x2ba01477 ([#756](https://github.com/stlink-org/stlink/pull/756), [#757](https://github.com/stlink-org/stlink/pull/757), [#805](https://github.com/stlink-org/stlink/pull/805), [#834](https://github.com/stlink-org/stlink/pull/834), Regression-Fixes: [#761](https://github.com/stlink-org/stlink/pull/761), [#766](https://github.com/stlink-org/stlink/pull/766)) - Added preliminary support for some STM32G0 chips ([#759](https://github.com/stlink-org/stlink/pull/759), [#760](https://github.com/stlink-org/stlink/pull/760), [#797](https://github.com/stlink-org/stlink/pull/797)) - Added support for mass erasing second bank on `STM32F10x_XL` ([#767](https://github.com/stlink-org/stlink/pull/767), [#768](https://github.com/stlink-org/stlink/pull/768)) - Added call to clear `PG` bit after writing to flash ([#773](https://github.com/stlink-org/stlink/pull/773)) - Added support to write option bytes for the STM32G0 ([#778](https://github.com/stlink-org/stlink/pull/778)) - Added support for STM32WB55 chips ([#786](https://github.com/stlink-org/stlink/pull/786), [#810](https://github.com/stlink-org/stlink/pull/810), [#816](https://github.com/stlink-org/stlink/pull/816)) - Added `STLink V3SET` VID:PIDs to the udev rules ([#789](https://github.com/stlink-org/stlink/pull/789)) - Support for `STM32+Audio` v2-1 firmware ([#790](https://github.com/stlink-org/stlink/pull/790)) - Build for Windows under Debian/Ubuntu ([#802](https://github.com/stlink-org/stlink/pull/802)) - Allow for 64 bytes serials ([#809](https://github.com/stlink-org/stlink/pull/809)) - Added full support for STLINK CHIP ID L4RX ([#814](https://github.com/stlink-org/stlink/pull/814), [#839](https://github.com/stlink-org/stlink/pull/839)) - Added support for the STLink/V2.1 when flashed with no mass storage (PID 0x3752) ([#819](https://github.com/stlink-org/stlink/pull/819), [#861](https://github.com/stlink-org/stlink/pull/861)) - Added support for writing option bytes on STM32L0xx ([#830](https://github.com/stlink-org/stlink/pull/830)) - Added support to read and write option bytes for STM32F2 series ([#836](https://github.com/stlink-org/stlink/pull/836), [#837](https://github.com/stlink-org/stlink/pull/837)) - Added support to read and write option bytes for STM32F446 ([#843](https://github.com/stlink-org/stlink/pull/843)) Updates and fixes: - Fixed an issue with versioning stuck at 1.4.0 for versions cloned with git ([#563](https://github.com/stlink-org/stlink/pull/563), [#762](https://github.com/stlink-org/stlink/pull/762), [#772](https://github.com/stlink-org/stlink/pull/772)) - Fixed `unkown chip id`, piped output and `st-util -v` ([#665](https://github.com/stlink-org/stlink/pull/665), [#763](https://github.com/stlink-org/stlink/pull/763)) - Updated STM32F3xx chip ID that covers a few different devices ([#685](https://github.com/stlink-org/stlink/pull/685), [#758](https://github.com/stlink-org/stlink/pull/758)) - Made udev rules and modprobe conf installation optional ([#741](https://github.com/stlink-org/stlink/pull/741)) - Fixed case when `__FILE__` doesn't contain either `/` nor `\\` ([#745](https://github.com/stlink-org/stlink/pull/745)) - Fixed double dash issue in doc/man ([#746](https://github.com/stlink-org/stlink/pull/746), [#747](https://github.com/stlink-org/stlink/pull/747)) - Compiling documentation: package is called `libusb-1.0-0-dev` on Debian ([#748](https://github.com/stlink-org/stlink/pull/748)) - Only do bank calculation on STM32L4 devices with dual banked flash / Added chip-ID 0x464 for STM32L41xxx/L42xxx devices ([#751](https://github.com/stlink-org/stlink/pull/751)) - Added `O_BINARY` option to open file ([#753](https://github.com/stlink-org/stlink/pull/753)) - Fixed versioning when compiling from the checked out git-repo ([#762](https://github.com/stlink-org/stlink/pull/762), [#772](https://github.com/stlink-org/stlink/pull/772)) - win32: move usleep definition to `unistd.h` ([#765](https://github.com/stlink-org/stlink/pull/765)) - Fixed relative path to the UI files needed by `stlink-gui-local` (GUI) ([#770](https://github.com/stlink-org/stlink/pull/770), [#771](https://github.com/stlink-org/stlink/pull/771)) - Added howto for sending `NRST` signal through GDB ([#774](https://github.com/stlink-org/stlink/pull/774), [#776](https://github.com/stlink-org/stlink/pull/776), [#779](https://github.com/stlink-org/stlink/pull/779)) - Fixed package name `devscripts` in doc/compiling.md ([#775](https://github.com/stlink-org/stlink/pull/775)) - Fixed few potential memory/resource leaks ([#803](https://github.com/stlink-org/stlink/pull/803), [#831](https://github.com/stlink-org/stlink/pull/831)) - Updated Linux source repositories in README.md: Debian and Ubuntu ([#821](https://github.com/stlink-org/stlink/pull/821), [#835](https://github.com/stlink-org/stlink/pull/835), [#859](https://github.com/stlink-org/stlink/pull/859)) - Do not issue JTAG reset on STLink/V1 ([#828](https://github.com/stlink-org/stlink/pull/828)) - Fixed flash size of STM32 Discovery VL ([#829](https://github.com/stlink-org/stlink/pull/829)) - Updated documentation on software structure ([#851](https://github.com/stlink-org/stlink/pull/851)) General project updates: - Updated `README.md`, `CHANGELOG.md` and issue templates (Nightwalker-87) - Fixed travis build config file (Nightwalker-87) - Added `CODE_OF_CONDUCT` (Nightwalker-87) - Archived page from github project wiki to doc/wiki_old.md (Nightwalker-87) # v1.5.1 Release date: 2018-09-13 Major changes and added features: - Added reset through `AIRCR` ([#254](https://github.com/stlink-org/stlink/pull/254), [#540](https://github.com/stlink-org/stlink/pull/540), [#712](https://github.com/stlink-org/stlink/pull/712)) - Added creation of icons for `.desktop` file ([#684](https://github.com/stlink-org/stlink/pull/684), [#708](https://github.com/stlink-org/stlink/pull/708)) - Added desktop file for linux ([#688](https://github.com/stlink-org/stlink/pull/688)) - Added button to export STM32 flash memory to a file ([#691](https://github.com/stlink-org/stlink/pull/691)) - Updated `libusb` to 1.0.22 ([#695](https://github.com/stlink-org/stlink/pull/695)) - (related Bugs: [#438](https://github.com/stlink-org/stlink/pull/438), [#632](https://github.com/stlink-org/stlink/pull/632)) - Added icons for stlink GUI ([#697](https://github.com/stlink-org/stlink/pull/697)) - Added support for STM32L4R9 target ([#694](https://github.com/stlink-org/stlink/pull/694), [#699](https://github.com/stlink-org/stlink/pull/699)) - Added memory map for STM32F411RE target ([#709](https://github.com/stlink-org/stlink/pull/709)) - Implemented intel hex support for `GTK` GUI ([#713](https://github.com/stlink-org/stlink/pull/713), [#718](https://github.com/stlink-org/stlink/pull/718)) Updates and fixes: - Fixed missing flash_loader for STM32L0x ([#269](https://github.com/stlink-org/stlink/pull/269), [#274](https://github.com/stlink-org/stlink/pull/274), [#654](https://github.com/stlink-org/stlink/pull/654), [#675](https://github.com/stlink-org/stlink/pull/675)) - Fix for stlink library calls `exit()` or `_exit()` ([#634](https://github.com/stlink-org/stlink/pull/634), [#696](https://github.com/stlink-org/stlink/pull/696)) - Added semihosting parameter documentation in doc/man ([#674](https://github.com/stlink-org/stlink/pull/674)) - Fixed reference to non-exisiting `st-term` tool in doc/man ([#676](https://github.com/stlink-org/stlink/pull/676)) - Fixed serial number size mismatch with `stlink_open_usb()` ([#680](https://github.com/stlink-org/stlink/pull/680)) - Debian packaging, `cmake` and `README.md` fixes ([#682](https://github.com/stlink-org/stlink/pull/682), [#683](https://github.com/stlink-org/stlink/pull/683)) - Disabled static library installation by default ([#702](https://github.com/stlink-org/stlink/pull/702)) - Fix for `libusb` deprecation ([#703](https://github.com/stlink-org/stlink/pull/703), [#704](https://github.com/stlink-org/stlink/pull/704)) - Renamed `STLINK_CHIPID_STM32_L4R9` to `STLINK_CHIPID_STM32_L4Rx` ([#706](https://github.com/stlink-org/stlink/pull/706)) - [regression] stlink installation under Linux (Debian 9) is broken since #695 ([#700](https://github.com/stlink-org/stlink/pull/700), [#701](https://github.com/stlink-org/stlink/pull/701), [#707](https://github.com/stlink-org/stlink/pull/707)) - Fixed flash memory map for STM32F72xxx target ([#711](https://github.com/stlink-org/stlink/pull/711)) - Proper flash page size calculation for STM32F412xx target ([#721](https://github.com/stlink-org/stlink/pull/721)) - Return correct value on `EOF` for semihosting `SYS_READ` ([#726](https://github.com/stlink-org/stlink/pull/726), [#727](https://github.com/stlink-org/stlink/pull/727), [#728](https://github.com/stlink-org/stlink/pull/728), [#729](https://github.com/stlink-org/stlink/pull/729), [#730](https://github.com/stlink-org/stlink/pull/730), [#731](https://github.com/stlink-org/stlink/pull/731), [#732](https://github.com/stlink-org/stlink/pull/732)) - FreeBSD defines `LIBUSB_API_VERSION` instead of `LIBUSBX_API_VERSION` ([#733](https://github.com/stlink-org/stlink/pull/733)) # v1.5.0 Release date: 2018-02-16 Major changes and added features: - Added support of STM32L496xx/4A6xx devices ([#615](https://github.com/stlink-org/stlink/pull/615), [#657](https://github.com/stlink-org/stlink/pull/657)) - Added unknown chip dummy to obtain the serial of the STlink by a call to `st-info --probe` ([#641](https://github.com/stlink-org/stlink/pull/641)) - Added support for STM32F72xx (chip-ID: 0x452) devices (commit [#1969148](https://github.com/stlink-org/stlink/commit/19691485359afef1a256964afcbb8dcf4b733209)) Updates and fixes: - Fixed verification of flash error for STM32L496x device ([#617](https://github.com/stlink-org/stlink/pull/617), [#618](https://github.com/stlink-org/stlink/pull/618)) - Updated Linux source repositories in README.md: Gentoo, Fedora and RedHat/CentOS ([#622](https://github.com/stlink-org/stlink/pull/622), [#635](https://github.com/stlink-org/stlink/pull/635)) - Updated changelog in debian package ([#630](https://github.com/stlink-org/stlink/pull/630)) - Added `LIB_INSTALL_DIR` to correct libs install on 64-bit systems ([#633](https://github.com/stlink-org/stlink/pull/633), [#636](https://github.com/stlink-org/stlink/pull/636)) - Fixed write for microcontroller with RAM size less or equal to 32K ([#637](https://github.com/stlink-org/stlink/pull/637)) - Fixed memory map for STM32L496xx boards ([#639](https://github.com/stlink-org/stlink/pull/639)) - Fixed `__FILE__` base name extraction ([#624](https://github.com/stlink-org/stlink/pull/624), [#628](https://github.com/stlink-org/stlink/pull/628), [#648](https://github.com/stlink-org/stlink/pull/648)) - Added debian/triggers to run `ldconfig` ([#664](https://github.com/stlink-org/stlink/pull/664)) - Fixed build on Fedora with GCC 8 ([#666](https://github.com/stlink-org/stlink/pull/666), [#667](https://github.com/stlink-org/stlink/pull/667), [#668](https://github.com/stlink-org/stlink/pull/668)) # v1.4.0 Release date: 2017-07-01 Major changes and added features: - Allow building of debian package with CPack ([#554](https://github.com/stlink-org/stlink/pull/554), commit [#5b69f25](https://github.com/stlink-org/stlink/commit/5b69f25198a1a8f34e2ee48d1ad20f79447e3d55)) - Added support for STM32L011 target ([#564](https://github.com/stlink-org/stlink/pull/564), [#565](https://github.com/stlink-org/stlink/pull/565), [#572](https://github.com/stlink-org/stlink/pull/572)) - Added support for flashing second bank on STM32F10x_XL ([#592](https://github.com/stlink-org/stlink/pull/592)) - Initial support to compile with Microsoft Visual Studio 2017 ([#602](https://github.com/stlink-org/stlink/pull/602)) - Added support for STM32L452 target ([#603](https://github.com/stlink-org/stlink/pull/603), [#608](https://github.com/stlink-org/stlink/pull/608)) Updates and fixes: - Added `--flash=n[k][m]` command line option to override device model ([#305](https://github.com/stlink-org/stlink/pull/305), [#516](https://github.com/stlink-org/stlink/pull/516), [#576](https://github.com/stlink-org/stlink/pull/576)) - Updated `libusb` to 1.0.21 for Windows ([#562](https://github.com/stlink-org/stlink/pull/562)) - Fixed low-voltage flashing on STM32F7 devices ([#566](https://github.com/stlink-org/stlink/pull/566), [#567](https://github.com/stlink-org/stlink/pull/567)) - Fixed building with mingw64 ([#569](https://github.com/stlink-org/stlink/pull/569), [#573](https://github.com/stlink-org/stlink/pull/573), [#578](https://github.com/stlink-org/stlink/pull/578), [#582](https://github.com/stlink-org/stlink/pull/582), [#584](https://github.com/stlink-org/stlink/pull/584), [#610](https://github.com/stlink-org/stlink/pull/610), [#846](https://github.com/stlink-org/stlink/pull/846)) - Fixed possible memory leak ([#570](https://github.com/stlink-org/stlink/pull/570), [#571](https://github.com/stlink-org/stlink/pull/571)) - Fixed installation path for shared objects ([#581](https://github.com/stlink-org/stlink/pull/581)) - Fixed a few `-Wformat` warnings ([#582](https://github.com/stlink-org/stlink/pull/582)) - Removed unused defines in `mingw.h` ([#583](https://github.com/stlink-org/stlink/pull/583)) - Skip `GTK` detection when cross-compiling ([#588](https://github.com/stlink-org/stlink/pull/588)) - Fixed compilation with GCC 7 ([#590](https://github.com/stlink-org/stlink/pull/590), [#591](https://github.com/stlink-org/stlink/pull/591)) - Fixed flashing to `F0 device` targets ([#594](https://github.com/stlink-org/stlink/pull/594), [#595](https://github.com/stlink-org/stlink/pull/595)) - Fixed wrong counting when flashing ([#605](https://github.com/stlink-org/stlink/pull/605)) # v1.3.1 Release date: 2017-02-25 Major changes and added features: - Added support for Semihosting `SYS_READC` ([#546](https://github.com/stlink-org/stlink/pull/546)) - Added support for STM32F413 ([#549](https://github.com/stlink-org/stlink/pull/549), [#550](https://github.com/stlink-org/stlink/pull/550), [#758](https://github.com/stlink-org/stlink/pull/758)) - Added preliminary support for STM32L011 to see it after probe (chip-ID 0x457) ([#558](https://github.com/stlink-org/stlink/pull/558), [#598](https://github.com/stlink-org/stlink/pull/598)) Updates and fixes: - `cmake/CPackConfig.cmake`: Fixup OSX zip filename - Updated source repositories in README.md: Windows, macOS, Alpine Linux - Compilation fixes ([#547](https://github.com/stlink-org/stlink/pull/547), [#551](https://github.com/stlink-org/stlink/pull/551), [#552](https://github.com/stlink-org/stlink/pull/552)) - Stripped full paths to source files in log ([#548](https://github.com/stlink-org/stlink/pull/548)) - Fixed incorrect release folder name in docs ([#560](https://github.com/stlink-org/stlink/pull/560)) - Fixed compilation when path includes spaces ([#561](https://github.com/stlink-org/stlink/pull/561)) # v1.3.0 Release date: 2017-01-28 Major changes and added features: - Deprecation of autotools (`autoconf`, `automake`) and fixed build with MinGW ([#83](https://github.com/stlink-org/stlink/pull/83), [#431](https://github.com/stlink-org/stlink/pull/431), [#434](https://github.com/stlink-org/stlink/pull/434), [#465](https://github.com/stlink-org/stlink/pull/465)) - Added intel hex file reading for `st-flash` ([#110](https://github.com/stlink-org/stlink/pull/110), [#157](https://github.com/stlink-org/stlink/pull/157), [#457](https://github.com/stlink-org/stlink/pull/547), [#459](https://github.com/stlink-org/stlink/pull/549)) - Added support for ARM semihosting to `st-util` ([#147](https://github.com/stlink-org/stlink/pull/147), [#227](https://github.com/stlink-org/stlink/pull/227), [#454](https://github.com/stlink-org/stlink/pull/454), [#455](https://github.com/stlink-org/stlink/pull/455)) - Added manpages (generated with `pandoc` from Markdown) ([#208](https://github.com/stlink-org/stlink/pull/208), [#464](https://github.com/stlink-org/stlink/pull/464), [#466](https://github.com/stlink-org/stlink/pull/466), [#467](https://github.com/stlink-org/stlink/pull/467)) - Removal of undocumented `st-term` utility, which is now replaced by `st-util` ARM semihosting feature ([#228](https://github.com/stlink-org/stlink/pull/228), [#507](https://github.com/stlink-org/stlink/pull/507), commit [#3fd0f09](https://github.com/stlink-org/stlink/commit/3fd0f099782506532198473b24f643a3f68d5ff9)) - Support serial numbers argument for `st-util` and `st-flash` to probe and control multiple connected programmers ([#318](https://github.com/stlink-org/stlink/pull/318), [#398](https://github.com/stlink-org/stlink/pull/398), [#541](https://github.com/stlink-org/stlink/pull/541)) - Added 'k' (kill) command to gdb-server, which resets the connection ([#358](https://github.com/stlink-org/stlink/pull/358), [#525](https://github.com/stlink-org/stlink/pull/525), [#527](https://github.com/stlink-org/stlink/pull/527), [#528](https://github.com/stlink-org/stlink/pull/528)) - Merge `st-probe` tool into `st-info` ([#398](https://github.com/stlink-org/stlink/pull/398)) - Added support for native debian packaging ([#444](https://github.com/stlink-org/stlink/pull/444), [#472](https://github.com/stlink-org/stlink/pull/472), [#473](https://github.com/stlink-org/stlink/pull/473), [#482](https://github.com/stlink-org/stlink/pull/482), [#483](https://github.com/stlink-org/stlink/pull/483), [#484](https://github.com/stlink-org/stlink/pull/484), [#485](https://github.com/stlink-org/stlink/pull/485)) - Rewritten commandline parsing for `st-flash` ([#459](https://github.com/stlink-org/stlink/pull/459)) - Added `--reset` command to `st-flash` ([#505](https://github.com/stlink-org/stlink/pull/505)) Chip support added for: - STM32F401XE: Added memory map for device ([#460](https://github.com/stlink-org/stlink/pull/460)) - STM32F410RBTx ([#418](https://github.com/stlink-org/stlink/pull/418)) - STM32F412 ([#537](https://github.com/stlink-org/stlink/pull/537), [#538](https://github.com/stlink-org/stlink/pull/538)) - STM32F7xx ([#324](https://github.com/stlink-org/stlink/pull/324), [#326](https://github.com/stlink-org/stlink/pull/326), [#327](https://github.com/stlink-org/stlink/pull/327), [#337](https://github.com/stlink-org/stlink/pull/337)) - STM32F7x7x ([#433](https://github.com/stlink-org/stlink/pull/433), [#435](https://github.com/stlink-org/stlink/pull/435), [#436](https://github.com/stlink-org/stlink/pull/436), [#509](https://github.com/stlink-org/stlink/pull/509)) - STM32L0xx Cat2 devices (chip-ID: 0x425) ([#414](https://github.com/stlink-org/stlink/pull/414)) - STM32L0xx Cat5 devices (chip-ID: 0x447) ([#387](https://github.com/stlink-org/stlink/pull/387), [#406](https://github.com/stlink-org/stlink/pull/406)) - STM32L4xx ([#321](https://github.com/stlink-org/stlink/pull/321)) - STM32L432 ([#500](https://github.com/stlink-org/stlink/pull/500), [#501](https://github.com/stlink-org/stlink/pull/501)) Updates and fixes: - Do a JTAG reset prior to reading CPU information when processor is in deep sleep ([#291](https://github.com/stlink-org/stlink/pull/291), [#428](https://github.com/stlink-org/stlink/pull/428), [#430](https://github.com/stlink-org/stlink/pull/430), [#451](https://github.com/stlink-org/stlink/pull/451)) - Fixed `unaligned addr or size` when trying to write a program in RAM ([#323](https://github.com/stlink-org/stlink/pull/323)) - Fixed flashing on `STM32_F3_SMALL` ([#325](https://github.com/stlink-org/stlink/pull/325)) - Fixed STM32L-problem with flash loader ([#390](https://github.com/stlink-org/stlink/pull/390), [#407](https://github.com/stlink-org/stlink/pull/407), [#408](https://github.com/stlink-org/stlink/pull/408)) - Don't read the target voltage on startup, because it crashes STM32F100 ([#423](https://github.com/stlink-org/stlink/pull/423), [#424](https://github.com/stlink-org/stlink/pull/424)) - Added a useful error message instead of `[!] send_recv` ([#425](https://github.com/stlink-org/stlink/pull/425), [#426](https://github.com/stlink-org/stlink/pull/426)) - Fixed STM32F030 erase error ([#442](https://github.com/stlink-org/stlink/pull/442)) - Fixed memory map for STM32F7xx ([#453](https://github.com/stlink-org/stlink/pull/453), [#456](https://github.com/stlink-org/stlink/pull/456)) - Redesign of `st-flash` commandline options parsing ([#459](https://github.com/stlink-org/stlink/pull/459)) - Set `SWDCLK` and fixed `jtag_reset` bug ([#462](https://github.com/stlink-org/stlink/pull/462), [#475](https://github.com/stlink-org/stlink/pull/475), [#534](https://github.com/stlink-org/stlink/pull/534)) - doc/compiling.md: Add note about installation and `ldconfig` ([#478](https://github.com/stlink-org/stlink/pull/478), commit [#be66bbf](https://github.com/stlink-org/stlink/commit/be66bbf200c718904514b044ba84d64a36456218)) - Fixed Release target to generate the man-pages with `pandoc` ([#479](https://github.com/stlink-org/stlink/pull/479)) - Fixed Cygwin build ([#487](https://github.com/stlink-org/stlink/pull/487), ([#506](https://github.com/stlink-org/stlink/pull/506)) - Reset flash mass erase (MER) bit after mass erase for safety ([#489](https://github.com/stlink-org/stlink/pull/489)) - Wrong extract command in `FindLibUSB.cmake` ([#510](https://github.com/stlink-org/stlink/pull/510), [#511](https://github.com/stlink-org/stlink/pull/511)) - Fixed compilation error on Ubuntu 16.10 ([#514](https://github.com/stlink-org/stlink/pull/514), [#525](https://github.com/stlink-org/stlink/pull/525)) # v1.2.0 Release date: 2016-05-16 Features added: - Added multiple stlink probing (`st-info --probe`, `st-info --hla-serial`) with printing serial in hex and OpenOCD `hla_serial` format (Jerry Jacobs) - Added stlink usb probe API functions (Jerry Jacobs) - Added parameter to specify one stlink v2 of many (Georg von Zengen) Updates and fixes: - Refactoring/fixes of flash loader (Maxime Coquelin) - Synchronized cache for STM32F7 (Tristan Gingold) - Allow flashing of STM32L4 down to 1.71 V (Greg Meiste) - Fix on STM32L4 to clear flash mass erase flags on CR (Bruno Dal Bo) - Proper writing of page 0 of second bank for STM32L476xe (Tobias Badertscher) - Trace the read data in `stlink_read_debug32` and not the address of the variable (Tobias Badertscher) - Mac OS X El Capitan platform support confirmation (Nikolay) - Do not send a `NULL` at end of packets to `gdb` (Tristan Gingold) - Correctly compute flash write size for partial pages (Dave Vandervies) - `_stlink_usb_reset` use hardreset (mlundinse) - Make sure MCU is halted before running RAM based flashloaders (mlundinse) - Could not flash `STM32_F3_SMALL` (Max Chen) - STM32F4 8-bit support for 1.8v operation (Andy Isaacson) - Fixed STM32F2xx memory map (Nicolas Schodet) - Memory map for STM32F42xxx and STM32F43xxx devices (Craig Lilley) - Stm32l0x flash loader (Robin Kreis) - Modified determination of erased byte pattern when flashing ([#193](https://github.com/stlink-org/stlink/pull/193), [#377](https://github.com/stlink-org/stlink/pull/377)) - Use libusb synchronous api ([#194](https://github.com/stlink-org/stlink/pull/194), [#225](https://github.com/stlink-org/stlink/pull/225), [#374](https://github.com/stlink-org/stlink/pull/374)) - Fixed segfault when programmer is already busy and `NULL` pointers are in the list ([#256](https://github.com/stlink-org/stlink/pull/256), [#394](https://github.com/stlink-org/stlink/pull/394)) - Fixed gdb-server: Cortex M0 chips have no `FP_CTRL` register for breakpoints ([#266](https://github.com/stlink-org/stlink/pull/266), [#273](https://github.com/stlink-org/stlink/pull/273), [#341](https://github.com/stlink-org/stlink/pull/341)) - Fixed issue where "unknown chip id!" was seen every other time ([#352](https://github.com/stlink-org/stlink/pull/352), [#367](https://github.com/stlink-org/stlink/pull/367), [#381](https://github.com/stlink-org/stlink/pull/381)) - Send F4 memory-map and features for STM32F429 ([#188](https://github.com/stlink-org/stlink/pull/188), [#196](https://github.com/stlink-org/stlink/pull/196), [#250](https://github.com/stlink-org/stlink/pull/250), [#251](https://github.com/stlink-org/stlink/pull/251)) (Release v1.1.0) - Added AHB3 Peripherals definition for STM32F4 ([#218](https://github.com/stlink-org/stlink/pull/218), [#288](https://github.com/stlink-org/stlink/pull/288)) (Release v1.1.0) - Reset: st-flash does not work when CPU is in sleep mode ([#62](https://github.com/stlink-org/stlink/pull/62)) (Release v1.0.0) - Ensure USB device search succeeds if the matched device is at index 0 ([#126](https://github.com/stlink-org/stlink/pull/126), [#151](https://github.com/stlink-org/stlink/pull/151)) (Release v1.0.0) - Corrected flash size register address for STM32F2 devices ([#278](https://github.com/stlink-org/stlink/pull/278)) (Release v1.0.0) Chip support added for: - STM32L053R8 (Jean-Luc Béchennec) - STM32F7 Support (mlundinse) - Added STM32L4 to CHIPID #defines and devices[], flash driver and loader (Dave Vandervies) - Basic support for STM32F446 (Pavel Kirienko) - STM32F303 High Density - STM32F469/STM32F479 ([#345](https://github.com/stlink-org/stlink/pull/345), [#555](https://github.com/stlink-org/stlink/pull/555)) (Release v1.2.0) - STM32L1xx Cat.2 devices (Nicolas Schodet) - STM32L1xx (chip-ID 0x427) ([#152](https://github.com/stlink-org/stlink/pull/152), [#163](https://github.com/stlink-org/stlink/pull/163), [#165](https://github.com/stlink-org/stlink/pull/165)) (Release v1.0.0) - Added `SIGINT` handler for stlink cleanup ([#31](https://github.com/stlink-org/stlink/pull/31), [#135](https://github.com/stlink-org/stlink/pull/135)) (Release v1.0.0) Board support added for: - Nucleo-F303RE (Kyle Manna) - Nucleo-F411RE (texane) Build system: - Travis: Initial support for Travis continues integration on Linux & Mac OS X (Jerry Jacobs) - CMake: Document in README.md and add extra strict compiler flags (Jerry Jacobs) - CMake: First stab at a `cmake` build (Josh Bialkowski) stlink-1.9.0/CMakeLists.txt000066400000000000000000000311751526027543100156010ustar00rootroot00000000000000### # General cmake settings ### cmake_minimum_required(VERSION 3.21) # Enable modern install destination normalization (fixes CMP0177 warning) cmake_policy(SET CMP0063 NEW) if(POLICY CMP0177) cmake_policy(SET CMP0177 NEW) endif() set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(CMAKE_C_STANDARD 17) set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_EXTENSIONS ON) ### # General Project Settings ### project(stlink C) set(PROJECT_DESCRIPTION "Open source version of the STMicroelectronics ST-LINK Tools") include(${CMAKE_MODULE_PATH}/get_version.cmake) # Determine project version include(GNUInstallDirs) # Define GNU standard installation directories ## Include test execution for test-targets for target Debug if (${CMAKE_BUILD_TYPE} MATCHES "Debug") include(CTest) endif() # Check operating system cmake_host_system_information(RESULT OS_NAME QUERY OS_NAME) message(STATUS "Checking for OS_NAME: ${OS_NAME}") # Threading support # pthreads on Unix; on Windows the Win32 API is used directly, so that neither # PThreads4W (MSVC) nor winpthread (MinGW) has to be found, linked or shipped. if (WIN32) # Nothing to link here: _beginthreadex comes from the CRT, and # WaitForSingleObject and CloseHandle from kernel32, both of which MSVC and # MinGW link by default. Deliberately no find_package(Threads): with # THREADS_PREFER_PTHREAD_FLAG it would pick winpthread on MinGW and add # -pthread, restoring the libwinpthread-1.dll dependency. set(STLINK_THREAD_LIBRARY "") else () set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) set(STLINK_THREAD_LIBRARY Threads::Threads) endif() # Set C build flags if (NOT MSVC) include(${CMAKE_MODULE_PATH}/c_flags.cmake) endif() # MSVC runtime selection is left to CMAKE_MSVC_RUNTIME_LIBRARY/the toolchain. ### # Dependencies ### # Set source and header file variables set(STLINK_HEADERS) set(STLINK_SOURCES) # Subordinate CMakeLists # for system-specific definitions, external libraries, source and header files add_subdirectory(src/stlink-env) include_directories(src/stlink-env) include_directories(${STLINK_INCLUDE_DIRS}) add_definitions(${STLINK_DEFINITIONS}) add_compile_options(${STLINK_COMPILE_OPTIONS}) ### # Main build process ### # Set system-specific installation directory for header files if (WIN32) set(STLINK_INCLUDE_PATH ${CMAKE_INSTALL_INCLUDEDIR} CACHE PATH "Main include install directory") else () set(STLINK_INCLUDE_PATH ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME} CACHE PATH "Main include install directory") endif() # Define include directories to avoid absolute paths for header defines include_directories(${LIBUSB_INCLUDE_DIR}) # Include directories containing header files include_directories(src/stlink-lib) include_directories(inc) # contains top-level header files # Project version file include_directories(${PROJECT_BINARY_DIR}/inc) # contains version.h configure_file("${PROJECT_SOURCE_DIR}/inc/version.h.in" "${CMAKE_BINARY_DIR}/inc/version.h") # Define source- and headerfiles for stlink library file(GLOB STLINK_LIB_HEADERS "${CMAKE_SOURCE_DIR}/inc/*.h" "${CMAKE_SOURCE_DIR}/src/stlink-env/*.h" "${CMAKE_SOURCE_DIR}/src/stlink-lib/*.h" "${CMAKE_BINARY_DIR}/inc/version.h") list(APPEND STLINK_HEADERS ${STLINK_LIB_HEADERS}) file(GLOB STLINK_LIB_SOURCES "${CMAKE_SOURCE_DIR}/src/stlink-lib/*.c") list(APPEND STLINK_SOURCES ${STLINK_LIB_SOURCES}) # Install library header files install(FILES ${STLINK_HEADERS} DESTINATION ${STLINK_INCLUDE_PATH}) if (MSVC) # libusb_settings.h and unistd.h (both installed above) include these, # so downstream consumers of stlink-static.lib need them too - v1.8.0 # shipped them, the vcpkg switch stopped bundling them (issue #2). install(FILES "${LIBUSB_INCLUDE_DIR}/libusb.h" DESTINATION "${STLINK_INCLUDE_PATH}/libusb-1.0") install(FILES src/stlink-env/getopt/getopt.h DESTINATION ${STLINK_INCLUDE_PATH}) endif() ### # Shared library ### # Set library name set(STLINK_LIB_SHARED ${PROJECT_NAME}-shared) add_library(${STLINK_LIB_SHARED} SHARED ${STLINK_HEADERS} ${STLINK_SOURCES}) set(STLINK_SHARED_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}) message(STATUS "STLINK_LIB_SHARED: ${STLINK_LIB_SHARED}") message(STATUS "VERSION: ${STLINK_SHARED_VERSION}") set_target_properties(${STLINK_LIB_SHARED} PROPERTIES SOVERSION ${PROJECT_VERSION_MAJOR} VERSION ${STLINK_SHARED_VERSION} OUTPUT_NAME ${PROJECT_NAME} ) # Since we're not using __declspec(dllexport), WINDOWS_EXPORT_ALL_SYMBOLS is mandatory for MSVC. # This call will only affect MSVC, compilers/OSes ignore it. set_target_properties(${STLINK_LIB_SHARED} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON) # Link shared library using modern imported target if (WIN32) target_link_libraries(${STLINK_LIB_SHARED} libusb::libusb ${STLINK_THREAD_LIBRARY} ${SSP_LIB} wsock32 ws2_32 ) else () target_link_libraries(${STLINK_LIB_SHARED} libusb::libusb ${STLINK_THREAD_LIBRARY} ${SSP_LIB} ) endif() # Installation rules for shared library (DLL vs. SO) if (MSVC) # For MSVC: # shared libraries (.dll) go to `bin` # their Import Libraries (aka: ImpLibs; .lib files) go to `lib` install(TARGETS ${STLINK_LIB_SHARED} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_BINDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) else() # For non-MSVC: # shared libraries go to `lib` # Archive destination is set to `lib` as failsafe install(TARGETS ${STLINK_LIB_SHARED} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) endif() ### # Static library ### # Set library name set(STLINK_LIB_STATIC ${PROJECT_NAME}-static) set(STLINK_LIB_STATIC_OUTPUT_NAME ${PROJECT_NAME}) if (MSVC) set(STLINK_LIB_STATIC_OUTPUT_NAME ${PROJECT_NAME}-static) endif() add_library(${STLINK_LIB_STATIC} STATIC ${STLINK_HEADERS} ${STLINK_SOURCES}) set(STLINK_STATIC_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}) message(STATUS "STLINK_LIB_STATIC: ${STLINK_LIB_STATIC}") message(STATUS "VERSION: ${STLINK_STATIC_VERSION}") set_target_properties(${STLINK_LIB_STATIC} PROPERTIES SOVERSION ${PROJECT_VERSION_MAJOR} VERSION ${STLINK_STATIC_VERSION} OUTPUT_NAME ${STLINK_LIB_STATIC_OUTPUT_NAME} ) # Link static library using modern imported target if (WIN32) target_link_libraries(${STLINK_LIB_STATIC} libusb::libusb ${STLINK_THREAD_LIBRARY} ${SSP_LIB} wsock32 ws2_32 ) else () target_link_libraries(${STLINK_LIB_STATIC} libusb::libusb ${STLINK_THREAD_LIBRARY} ${SSP_LIB} ) endif() install(TARGETS ${STLINK_LIB_STATIC} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) ### # Build toolset executables ### # Set source files for tools set(ST-INFO_SOURCES src/st-info/info.c) set(ST-TRACE_SOURCES src/st-trace/trace.c) set(ST-SERVER_SOURCES src/st-server/server.c) set(ST-FLASH_SOURCES src/st-flash/flash.c src/st-flash/flash_opts.c ) set(ST-UTIL_SOURCES src/st-util/gdb-remote.c src/st-util/gdb-server.c src/st-util/semihosting.c ) if (WIN32 OR MSVC OR MINGW) # Add getopt to sources include_directories(src/stlink-env/getopt) list(APPEND ST-UTIL_SOURCES src/stlink-env/getopt/getopt.c) list(APPEND ST-TRACE_SOURCES src/stlink-env/getopt/getopt.c) list(APPEND ST-SERVER_SOURCES src/stlink-env/getopt/getopt.c) endif() # Create tool executables add_executable(st-info ${ST-INFO_SOURCES}) add_executable(st-trace ${ST-TRACE_SOURCES}) add_executable(st-server ${ST-SERVER_SOURCES}) add_executable(st-flash ${ST-FLASH_SOURCES}) add_executable(st-util ${ST-UTIL_SOURCES}) # Include directories containing header files target_include_directories(st-info PRIVATE src/st-info) target_include_directories(st-trace PRIVATE src/st-trace) target_include_directories(st-server PRIVATE src/st-server) target_include_directories(st-flash PRIVATE src/st-flash) target_include_directories(st-util PRIVATE src/st-util) # Platform-specific library linking if (WIN32) set(STLINK_LIB_TO_LINK ${STLINK_LIB_STATIC}) else () set(STLINK_LIB_TO_LINK ${STLINK_LIB_SHARED}) endif() message(STATUS "STLINK_LIB_TO_LINK: ${STLINK_LIB_TO_LINK}") target_link_libraries(st-info PRIVATE ${STLINK_LIB_TO_LINK}) target_link_libraries(st-trace PRIVATE ${STLINK_LIB_TO_LINK}) target_link_libraries(st-server PRIVATE ${STLINK_LIB_TO_LINK}) target_link_libraries(st-flash PRIVATE ${STLINK_LIB_TO_LINK}) target_link_libraries(st-util PRIVATE ${STLINK_LIB_TO_LINK}) # Install tools install(TARGETS st-info RUNTIME_DEPENDENCY_SET stlink_deps DESTINATION ${CMAKE_INSTALL_BINDIR}) install(TARGETS st-trace RUNTIME_DEPENDENCY_SET stlink_deps DESTINATION ${CMAKE_INSTALL_BINDIR}) install(TARGETS st-server RUNTIME_DEPENDENCY_SET stlink_deps DESTINATION ${CMAKE_INSTALL_BINDIR}) install(TARGETS st-flash RUNTIME_DEPENDENCY_SET stlink_deps DESTINATION ${CMAKE_INSTALL_BINDIR}) install(TARGETS st-util RUNTIME_DEPENDENCY_SET stlink_deps DESTINATION ${CMAKE_INSTALL_BINDIR}) install(TARGETS stlink-shared RUNTIME_DEPENDENCY_SET stlink_deps DESTINATION ${CMAKE_INSTALL_BINDIR}) if (MSVC) # vcpkg links libusb as a DLL on Windows; without this, an installed exe imports libusb-1.0.dll # that was never installed and fails to start. # # Resolution does not rely solely on VCPKG_APPLOCAL_DEPS having already copied the DLL next # to the exe at build time (that in turn relies on applocal.ps1 finding dumpbin/objdump # on PATH, which is not guaranteed outside a VS developer shell, e.g. plain Ninja builds); # the vcpkg triplet's own bin directory is searched directly as a second source. # Anything still unresolved is reported instead of aborting the install. install(RUNTIME_DEPENDENCY_SET stlink_deps PRE_EXCLUDE_REGEXES "api-ms-" "ext-ms-" POST_EXCLUDE_REGEXES ".*[Ss][Yy][Ss][Tt][Ee][Mm]32.*" DIRECTORIES "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}$<$:/debug>/bin" UNRESOLVED_DEPENDENCIES_VAR stlink_unresolved_deps DESTINATION ${CMAKE_INSTALL_BINDIR} ) install(CODE " if(stlink_unresolved_deps) message(WARNING \"cmake --install: unresolved runtime dependencies, not installed: \${stlink_unresolved_deps}\") endif() ") endif() ### # Device configuration (Linux only) ### if (CMAKE_SYSTEM_NAME STREQUAL "Linux") ## Install modprobe.d conf files to /etc/modprobe.d/ (explicitly hardcoded) set(STLINK_MODPROBED_DIR "/etc/modprobe.d" CACHE PATH "modprobe.d directory") install(FILES ${CMAKE_SOURCE_DIR}/config/modprobe.d/stlink_v1.conf DESTINATION ${STLINK_MODPROBED_DIR}) ## Install udev rules files to /lib/udev/rules.d/ (explicitly hardcoded) set(STLINK_UDEV_RULES_DIR "/lib/udev/rules.d" CACHE PATH "udev rules directory") file(GLOB RULES_FILES ${CMAKE_SOURCE_DIR}/config/udev/rules.d/*.rules) install(FILES ${RULES_FILES} DESTINATION ${STLINK_UDEV_RULES_DIR}) endif() ### # Additional build tasks ### # MCU chip configuration files add_compile_definitions( $<$:STLINK_CHIPS_SRC_DIR="${CMAKE_SOURCE_DIR}/config/chips"> ) file(GLOB CHIP_FILES ${CMAKE_SOURCE_DIR}/config/chips/*.chip) install(FILES ${CHIP_FILES} DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/config/chips) # Documentation / manpages option(STLINK_GENERATE_MANPAGES "Generate manpages with pandoc" OFF) add_subdirectory(doc/man) # contains subordinate CMakeLists to generate manpages # Optional build components add_subdirectory(src/stlink-gui) # contains subordinate CMakeLists to build GUI add_subdirectory(cmake/packaging) # contains subordinate CMakeLists to build packages add_subdirectory(tests) # contains subordinate CMakeLists to build test executables ### # Uninstall target ### if (NOT TARGET uninstall) configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake/cmake_uninstall.cmake" IMMEDIATE @ONLY ) add_custom_target( uninstall COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake/cmake_uninstall.cmake ) endif() stlink-1.9.0/CODE_OF_CONDUCT.md000066400000000000000000000064711526027543100156410ustar00rootroot00000000000000# Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team [here](https://github.com/stlink-org/stlink/discussions). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq stlink-1.9.0/CONTRIBUTING.md000066400000000000000000000115551526027543100152720ustar00rootroot00000000000000# Contribution guidelines ## Contributing to the stlink project We love your input! We want to make contributing to this project as easy and transparent as possible, whether it's: - Reporting a bug - Discussing the current state of the code - Submitting a fix - Proposing new features - Assistance with maintaining We use GitHub to host code, to track issues and feature requests, as well as accept pull requests. Report a bug by [opening a new issue]() with one of the available templates. It's that easy! **NOTE: In order to offer sufficient and the best possible support, please read and follow the instructions below before submitting a ticket:** 1) If using a ST-Link-v2 programmer: Convince yourself that it is recognised as an USB device by your computer, thus reporting device and manufacturer ID. Use a diagnostic tool to probe for enumerated USB devices, e.g [`lsusb -v`](https://linux.die.net/man/8/lsusb) on unix-based systems. 2) **Use the [ST-Link firmware upgrade tool](https://www.st.com/en/development-tools/stsw-link007.html) based on Java to read out the current firmware version and update to the latest available version. This also works for _non-genuine_ ST programmers and boards.** 3) Try to make sure you have a working toolchain before starting to build. 4) **Update to the _latest_ release version or maybe even use the `testing` branch.** 5) Search for your problem in the available open issues, _before_ opening a new ticket. 6) Make sure to **use the available issue templates** to submit a bug-report or a feature-request. **Do not replace the prepared text, edit the placeholders instead. _Describe_ your problem.** 7) Avoid to add new comments to closed issues unless they confirm a solution already available. 8) Don't comment on tickets which do not specifically address your device or hardware - open a new ticket instead. 9) Consider if you can help to solve other issues (e.g. you have the same hardware) ## Coding conventions To read code written by other contributors can turn out to be quite demanding - a variable which seems to self-explaining, may appear cryptic to other readers. If you plan to contribute, please take this into account and feel encouraged to help others understand your code. In order to help you along, we have composed some contribution guidelines for this project. As this project already has a history you may find parts in the codebase that do not seem to comply with these guidelines, but we are trying to improve continuosly. However we can do even better, if every contributor considers the following points: * Naming of all source code elements as well as comments should exclusively be written in English. * All functions and global variables should be fully explained. This includes a short description on _what_ the respective function does (but not necessarily _how_ this is achieved), an explantion of transfer parameters and/or return values (if applicable). * Use [fixed width integer types](http://en.cppreference.com/w/c/types/integer) wherever possible and size-appropiate datatypes. * Only make use of the datatype `char` for specific characters, otherwise use `int8_t` or `uint8_t` respectively. ### Coding Style * Use 4 spaces for indentation rather than tabs (the latter results in inconsistent appearance on different platforms) * Use `/* your comment */` formatting for multi-line comments or section titles and `// your comment` for inline comments. * Please try to avoid special characters where possible, as they are interpreted differently on particular platforms and systems. Otherwise these may result in mojibake within the sourcecode or cause translation errors when compiling. * Use state-of-the-art UTF-8 encoding whereever possible. ## Github Flow We Use [Github Flow](https://guides.github.com/introduction/flow/index.html) which implies that all code changes happen through Pull Requests (PRs). They are the best way to propose changes to the codebase and we actively welcome your own ones: 1. PRs should focus on _one_ single topic. 2. Fork the repo and create your branch from `develop`. 3. Begin to implement your changes on a local or personal branch. 4. Take a look at existing PR and check if these target the same part of the codebase. Should this be the case, you are encouraged to get in touch with the respective author and discuss on how to proceed. 5. Keep your personal feature-branch up to date with the current development branch, by merging in recent changes regularly. 6. Don't open a PR unless your contribution has evolved to a somehow completed set of changes. 7. If you've changed major features, update the documentation. 8. Ensure your PR passes our travis CI tests. 9. Issue that pull request! ## License When you submit code changes, your submissions are understood to be under the same [BSD-3 License](LICENSE.md) that covers this project.
Feel free to contact the project maintainers should there be any related questions. stlink-1.9.0/LICENSE.md000066400000000000000000000027561526027543100144500ustar00rootroot00000000000000BSD 3-Clause License Copyright (c) 2020, stlink-org All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. stlink-1.9.0/Makefile000066400000000000000000000027371526027543100145030ustar00rootroot00000000000000## # This Makefile is used to drive building of CMake build targets ## MAKEFLAGS += -s # additional flags for cmake, e.g. install path -DCMAKE_INSTALL_PREFIX=$(HOME)/.local CMAKEFLAGS += all: release ci: debug release test help: @echo " debug: Run a debug build" @echo " release: Run a release build" @echo " install: Install release build" @echo " uninstall: Uninstall release build" @echo " package: Package release build" @echo " lint: Lint check all source-code" @echo " test: Build and run tests" @echo " clean: Clean all build output" @echo "rebuild_cache: Rebuild all CMake caches" rebuild_cache: build/Debug build/Release @$(MAKE) -C build/Debug rebuild_cache @$(MAKE) -C build/Release rebuild_cache debug: build/Debug @echo "[DEBUG]" @$(MAKE) -C build/Debug release: build/Release @echo "[RELEASE]" @$(MAKE) -C build/Release install: build/Release @echo "[INSTALL] Release" @$(MAKE) -C build/Release install uninstall: build/Release @echo "[UNINSTALL] Release" @$(MAKE) -C build/Release uninstall package: build/Release @echo "[PACKAGE] Release" @$(MAKE) -C build/Release package test: debug @echo "[TEST] Debug" @$(MAKE) -C build/Debug test build/Debug: @mkdir -p $@ @cd $@ && cmake -DCMAKE_BUILD_TYPE=Debug $(CMAKEFLAGS) ../../ build/Release: @mkdir -p $@ @cd $@ && cmake -DCMAKE_BUILD_TYPE=Release $(CMAKEFLAGS) ../../ clean: @echo "[CLEAN]" @rm -Rf build .PHONY: clean stlink-1.9.0/README.md000066400000000000000000000147731526027543100143250ustar00rootroot00000000000000# Open source version of the STMicroelectronics STLINK Tools [![BSD licensed](https://img.shields.io/badge/license-BSD-blue.svg)](https://raw.githubusercontent.com/hyperium/hyper/master/LICENSE) [![GitHub release](https://img.shields.io/github/release/stlink-org/stlink.svg)](https://github.com/stlink-org/stlink/releases/latest) [![Downloads](https://img.shields.io/github/downloads/stlink-org/stlink/total)](https://github.com/stlink-org/stlink/releases/latest) ![GitHub commits](https://img.shields.io/github/commits-since/stlink-org/stlink/v1.9.0/develop) ![GitHub activity](https://img.shields.io/github/commit-activity/m/stlink-org/stlink) ![GitHub contributors](https://img.shields.io/github/contributors/stlink-org/stlink) [![CodeQL](https://github.com/stlink-org/stlink/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/stlink-org/stlink/actions/workflows/codeql-analysis.yml) [![C/C++ CI](https://github.com/stlink-org/stlink/actions/workflows/c-cpp.yml/badge.svg?branch=testing)](https://github.com/stlink-org/stlink/actions/workflows/c-cpp.yml) Recent new features and bugfixes can be found in the [Changelog](CHANGELOG.md) of this software project. ## License The stlink library and tools are licensed under the **[BSD-3 License](LICENSE.md)**. ## Introduction stlink is an open source toolset to program and debug STM32 devices and boards manufactured by STMicroelectronics. It supports several so called STLINK programmer boards (and clones thereof) which use a microcontroller chip to translate commands from USB to JTAG/SWD. There are four generations available on the market which are _all_ supported by this toolset: - **STLINK/V1** _[obsolete as of 21-11-2019, continued support by this toolset]_ - transport layer: SCSI passthru commands over USB - stand-alone programmer - on-board on STM32VL DISCOVERY boards - **STLINK/V2** - transport layer: raw USB commands - stand-alone programmer - on-board on STM32 DISCOVERY and some STM32 EVAL boards - **STLINK/V2-1** - transport layer: raw USB commands - on-board on older STM32 Nucleo boards - **STLINK-V3** - transport layer: raw USB commands - stand-alone programmer (STLINK-V3SET, STLINK-V3MINI, STLINK-V3MODS) - on-board on STM32 Nucleo boards (STLINK-V3E) On the user level there is no difference in handling or operation between these different revisions. The STlink toolset includes: - `st-info` - a programmer and chip information tool - `st-flash` - a flash manipulation tool - `st-trace` - a logging tool to record information on execution - `st-server` - serves a local ST-LINK over TCP for remote stlink tools - `st-util` - a GDB server (supported in Visual Studio Code / VSCodium via the [Cortex-Debug](https://github.com/Marus/cortex-debug) plugin) - `stlink-lib` - a communication library - `stlink-gui` - a GUI-Interface _[optional]_ ## Supported operating systems and hardware combinations Currently known working MCU targets are listed in [supported_devices.md](doc/supported_devices.md). A list of supported operating can be found in [version_support.md](doc/version_support.md). ## Tutorial & HOWTO Our [tutorial](doc/tutorial.md) may help you along with some advanced tasks and additional info. ## Installation **Windows**: As of Release v1.6.1 stand-alone Windows binaries are made available (again). Please ensure to select the correct version for your system (i686 or x86_64). The archive file can be unzipped to any desired location as it does not contain any hardcoded paths. However we suggest to move the unzipped application folder to `C:\Program Files\` on 32-bit and to `C:\Program Files (x86)\` on 64-bit systems. Alternatively one may compile and install from source as described in our [compiling manual](doc/compiling.md#Windows). Build testing occurs via CI only. **Linux / Unix**: We recommend to install `stlink-tools` from the package repository of the used distribution: **Note:** As packages distributed via the [Debian](https://packages.debian.org/buster/stlink-tools) and [Ubuntu](https://packages.ubuntu.com/stlink-tools) repositories differ from our self-maintained deb-package, we recommend to use the latter instead (see link below). It provides the opportunity to handle and fix user-reported package issues directly within the project and is not redundant to any limitations deriving from external maintenance guidelines. - Debian Linux: [(Link)](https://github.com/stlink-org/stlink/releases) - Ubuntu Linux: [(Link)](https://github.com/stlink-org/stlink/releases) - Arch Linux: [(Link)](https://archlinux.org/packages/extra/x86_64/stlink/) - Alpine Linux: [(Link)](https://pkgs.alpinelinux.org/packages?name=stlink) - Fedora: [(Link)](https://src.fedoraproject.org/rpms/stlink) - FreeBSD: Users can install from [freshports](https://www.freshports.org/devel/stlink) **macOS** The `stlink-tools` toolset has to be compiled from source. No binaries are provided. Build testing occurs via CI only. ## Installation from source (advanced users) When there is no executable available for your platform or you need the latest (possible unstable) version you need to compile the toolset yourself. This procedure is explained in the [compiling manual](doc/compiling.md). ## Contributing and versioning - The semantic versioning scheme is used. Read more at [semver.org](http://semver.org) - Before creating a pull request, please _ALWAYS_ open a new issue for the discussion of the intended new features. Bugfixes don't require a discussion via a ticket-issue. However they should always be described in a few words as soon as they appear to help others as well. - Contributors and/or maintainers may submit comments or request changes to patch-proposals and/or pull-requests. - **ATTENTION: _NEVER EVER_ use the '#' character to count-up single points within a listing as '#' is _exclusively_ reserved for referencing GitHub issues and pull-requests. Otherwise you accidentally introduce false cross references within the project.** - Please start new forks from the develop branch, as pull requests will go into this branch as well. Please also refer to our [Contribution Guidelines](CONTRIBUTING.md). ## User Reviews *I hope it's not to out of topic, but I've been so frustrated with AVR related things on OpenBSD, the fact that stlink built out of the box without needing to touch anything was so relieving. Literally made my whole weekend better! I take it's thanks to @Crest and also to the stlink-org team (@Nightwalker-87 and @xor-gate it seems) to have made a software that's not unfriendly to the "fringe" OSes. Thank you <3"* - nbonfils, 11.12.2021 stlink-1.9.0/SECURITY.md000066400000000000000000000014211526027543100146210ustar00rootroot00000000000000# Security Policy ## Supported Versions The following versions of the stlink toolset are currently being supported.
As this is a development toolset, please note that bugfixes will only be applied to the latest version. | Version | Supported | | ------- | ------------------ | | develop | :white_check_mark: | | 1.9.0 | :white_check_mark: | | 1.8.0 | :x: | | 1.7.0 | :x: | | 1.6.x | :x: | | 1.5.x | :x: | | 1.4.0 | :x: | | 1.3.x | :x: | | 1.2.0 | :x: | | 1.1.0 | :x: | | 1.0.0 | :x: | ## Reporting a Vulnerability Detected vulnerabilities in the toolset should be reported by opening a regular bugreport issue. stlink-1.9.0/cmake/000077500000000000000000000000001526027543100141125ustar00rootroot00000000000000stlink-1.9.0/cmake/modules/000077500000000000000000000000001526027543100155625ustar00rootroot00000000000000stlink-1.9.0/cmake/modules/Findlibusb.cmake000066400000000000000000000165221526027543100206530ustar00rootroot00000000000000# Findlibusb.cmake # Modern CMake 3.20+ Find module for libusb-1.0 # # Defines: # - Imported Target: libusb::libusb # - Variables: LIBUSB_FOUND, LIBUSB_INCLUDE_DIR, LIBUSB_LIBRARY # include(FetchContent) include(FindPackageHandleStandardArgs) set(LIBUSB_FOUND FALSE) # Default: libusb not found # --- Platform-specific configurations --- # vcpkg installs Release and Debug libraries with the same name in separate directories. # A single find_library() can select the Debug library for every VS configuration. if(WIN32 AND VCPKG_TARGET_TRIPLET) set(_LIBUSB_VCPKG_PREFIX "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}") find_path(LIBUSB_INCLUDE_DIR NAMES libusb.h PATHS "${_LIBUSB_VCPKG_PREFIX}/include" PATH_SUFFIXES libusb-1.0 NO_DEFAULT_PATH ) find_library(LIBUSB_LIBRARY_RELEASE NAMES usb-1.0 libusb-1.0 PATHS "${_LIBUSB_VCPKG_PREFIX}/lib" NO_DEFAULT_PATH ) find_library(LIBUSB_LIBRARY_DEBUG NAMES usb-1.0 libusb-1.0 PATHS "${_LIBUSB_VCPKG_PREFIX}/debug/lib" NO_DEFAULT_PATH ) include(SelectLibraryConfigurations) select_library_configurations(LIBUSB) # FreeBSD: libusb is part of the base system elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") find_path(LIBUSB_INCLUDE_DIR NAMES libusb.h HINTS /usr/include) find_library(LIBUSB_LIBRARY NAMES usb HINTS /usr /usr/local /opt) # OpenBSD: libusb available via ports/packages elseif(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") find_path(LIBUSB_INCLUDE_DIR NAMES libusb.h HINTS /usr/local/include PATH_SUFFIXES libusb-1.0) find_library(LIBUSB_LIBRARY NAMES usb-1.0 HINTS /usr/local) # MSVC without the mandatory vcpkg toolchain: unsupported per project policy. # Fail early with a clear pointer instead of falling through to a stray # system libusb install, which can predate 1.0.30 and reintroduce the # winsock.h/winsock2.h conflict this project no longer supports. elseif(MSVC) message(FATAL_ERROR "libusb-1.0 was not found via vcpkg (VCPKG_TARGET_TRIPLET is unset).\n" "MSVC builds require the vcpkg toolchain file - see doc/compiling.md." ) # Windows (native MinGW build on Windows itself, not cross-compiling) elseif(WIN32 AND NOT EXISTS "/etc/debian_version") # Try to locate an existing Windows installation of libusb find_path(LIBUSB_INCLUDE_DIR NAMES libusb.h HINTS "C:/Program Files/libusb-1.0/include" "C:/Program Files (x86)/libusb-1.0/include" PATH_SUFFIXES libusb-1.0 ) find_library(LIBUSB_LIBRARY NAMES usb-1.0 libusb-1.0 HINTS "C:/Program Files/libusb-1.0" "C:/Program Files (x86)/libusb-1.0" ) # Windows-Build with MinGW via cross-compiling on Debian-Linux elseif(MINGW AND EXISTS "/etc/debian_version") message(STATUS "=== Building for Windows (${TOOLCHAIN_PREFIX}) ===") # Download and build libusb via FetchContent if(NOT LIBUSB_FOUND) message(STATUS "libusb-1.0 not found locally. Downloading and building from source via FetchContent...") FetchContent_Declare( libusb GIT_REPOSITORY "https://github.com/libusb/libusb.git" GIT_TAG "v1.0.30" ) FetchContent_MakeAvailable(libusb) # Run bootstrap.sh (if available) if(EXISTS "${libusb_SOURCE_DIR}/bootstrap.sh") execute_process( COMMAND ./bootstrap.sh WORKING_DIRECTORY ${libusb_SOURCE_DIR} RESULT_VARIABLE BOOTSTRAP_RESULT ) if(NOT BOOTSTRAP_RESULT EQUAL 0) message(FATAL_ERROR "libusb bootstrap.sh failed with code ${BOOTSTRAP_RESULT}") endif() endif() # Configure execute_process( COMMAND ./configure --host=${TOOLCHAIN_PREFIX} --prefix=${libusb_BINARY_DIR}/install --enable-static --disable-shared --disable-udev WORKING_DIRECTORY ${libusb_SOURCE_DIR} RESULT_VARIABLE CONFIGURE_RESULT ) if(NOT CONFIGURE_RESULT EQUAL 0) message(FATAL_ERROR "libusb configure failed with code ${CONFIGURE_RESULT}") endif() # Build library execute_process( COMMAND make WORKING_DIRECTORY ${libusb_SOURCE_DIR} RESULT_VARIABLE MAKE_RESULT ) if(NOT MAKE_RESULT EQUAL 0) message(FATAL_ERROR "libusb make failed with code ${MAKE_RESULT}") endif() # Install library execute_process( COMMAND make install WORKING_DIRECTORY ${libusb_SOURCE_DIR} RESULT_VARIABLE INSTALL_RESULT ) if(NOT INSTALL_RESULT EQUAL 0) message(FATAL_ERROR "libusb make install failed with code ${INSTALL_RESULT}") endif() # Get include dir and library path from the target set(LIBUSB_INCLUDE_DIR "${libusb_SOURCE_DIR}/libusb") set(LIBUSB_LIBRARY "${libusb_SOURCE_DIR}/../libusb-build/install/lib/libusb-1.0.a") # Create a CMake target if(NOT TARGET libusb::libusb) add_library(libusb::libusb UNKNOWN IMPORTED GLOBAL) set_target_properties(libusb::libusb PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${LIBUSB_INCLUDE_DIR}" IMPORTED_LOCATION "${LIBUSB_LIBRARY}" ) endif() endif() # All other Unix-based systems (Linux, macOS, etc.) else() # Use pkg-config to find libusb (if available) find_package(PkgConfig QUIET) if(PKG_CONFIG_FOUND) pkg_search_module(PC_LIBUSB QUIET libusb-1.0) endif() # Locate include directory and library using pkg-config hints or defaults find_path(LIBUSB_INCLUDE_DIR NAMES libusb.h HINTS ${PC_LIBUSB_INCLUDE_DIRS} PATH_SUFFIXES libusb-1.0 ) find_library(LIBUSB_LIBRARY NAMES usb-1.0 HINTS ${PC_LIBUSB_LIBRARY_DIRS} ) endif() # Finalize the imported target # Only proceed if both include dir and library path were found if(LIBUSB_INCLUDE_DIR AND LIBUSB_LIBRARY) set(LIBUSB_FOUND TRUE) # Update found status # Create the imported target if it doesn't exist yet if(NOT TARGET libusb::libusb) # Create an imported target (type UNKNOWN = static or shared library) add_library(libusb::libusb UNKNOWN IMPORTED GLOBAL) # Set the target's properties: # - INTERFACE_INCLUDE_DIRECTORIES: Where to find libusb.h # - IMPORTED_LOCATION: Path to the compiled library (e.g., libusb-1.0.a/.so/.lib) set_target_properties(libusb::libusb PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${LIBUSB_INCLUDE_DIR}" ) if(LIBUSB_LIBRARY_RELEASE OR LIBUSB_LIBRARY_DEBUG) foreach(_LIBUSB_CONFIG RELEASE DEBUG) if(LIBUSB_LIBRARY_${_LIBUSB_CONFIG}) set_property(TARGET libusb::libusb APPEND PROPERTY IMPORTED_CONFIGURATIONS ${_LIBUSB_CONFIG}) set_target_properties(libusb::libusb PROPERTIES IMPORTED_LOCATION_${_LIBUSB_CONFIG} "${LIBUSB_LIBRARY_${_LIBUSB_CONFIG}}") endif() endforeach() else() set_target_properties(libusb::libusb PROPERTIES IMPORTED_LOCATION "${LIBUSB_LIBRARY}") endif() endif() endif() # Handle standard REQUIRED/QUIET arguments for find_package() find_package_handle_standard_args(libusb REQUIRED_VARS LIBUSB_FOUND) stlink-1.9.0/cmake/modules/c_flags.cmake000066400000000000000000000033471526027543100201710ustar00rootroot00000000000000# c_flags.cmake # Configure C compiler flags # include(CheckCCompilerFlag) function(add_cflag_if_supported flag) string(REPLACE "-" "_" flagclean ${flag}) string(REPLACE "=" "_" flagclean ${flagclean}) string(REPLACE "+" "_" flagclean ${flagclean}) string(REPLACE "," "_" flagclean ${flagclean}) string(TOUPPER ${flagclean} flagclean) check_c_compiler_flag(${flag} C_SUPPORTS${flagclean}) if (C_SUPPORTS${flagclean}) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${flag}" PARENT_SCOPE) endif() endfunction() add_cflag_if_supported("-Wall") add_cflag_if_supported("-Wextra") add_cflag_if_supported("-Wshadow") add_cflag_if_supported("-Wundef") add_cflag_if_supported("-Wformat") add_cflag_if_supported("-Wformat-security") add_cflag_if_supported("-Wmaybe-uninitialized") add_cflag_if_supported("-Wmissing-variable-declarations") add_cflag_if_supported("-Wimplicit-function-declaration") add_cflag_if_supported("-Wshorten-64-to-32") add_cflag_if_supported("-O") add_cflag_if_supported("-D_FORTIFY_SOURCE=2") add_cflag_if_supported("-fstrict-aliasing") # OpenBSD: # The system headers suck, so we need to disable redundant declaration check. # /usr/include/unistd.h:429: warning: redundant redeclaration of 'truncate' # /usr/include/sys/types.h:218: warning: previous declaration of 'truncate' was here if (NOT CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") add_cflag_if_supported("-Wredundant-decls") endif() # UNIX-based systems: if (NOT (WIN32 OR MSVC OR (MINGW AND EXISTS "/etc/debian_version"))) add_cflag_if_supported("-fPIC") # Generate Position Independent Code endif() # Debugging mode: if (${CMAKE_BUILD_TYPE} MATCHES "Debug") add_cflag_if_supported("-ggdb") else () add_cflag_if_supported("-Werror") endif() stlink-1.9.0/cmake/modules/cpack_config.cmake000066400000000000000000000105601526027543100211740ustar00rootroot00000000000000# cpack_config.cmake # Configure and generate packages for distribution ### # Configure package ### set(CPACK_PACKAGE_NAME ${PROJECT_NAME}) set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION}) set(CPACK_PACKAGE_DESCRIPTION "Open source STM32 MCU programming toolset") set(CPACK_PACKAGE_VENDOR "stlink-org") set(CMAKE_PROJECT_HOMEPAGE_URL "https://github.com/stlink-org/stlink") set(CPACK_SET_DESTDIR "ON") file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/dist) set(CPACK_OUTPUT_FILE_PREFIX "${CMAKE_BINARY_DIR}/dist") if (WIN32 AND (NOT EXISTS "/etc/debian_version")) # Windows set(CPACK_GENERATOR "ZIP") set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION}-win32") set(CPACK_INSTALL_PREFIX "") elseif (WIN32) # Windows cross-build on Debian/Ubuntu set(CPACK_GENERATOR "ZIP") set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${PROJECT_VERSION}-${TOOLCHAIN_PREFIX}") set(CPACK_INSTALL_PREFIX "") elseif (EXISTS "/etc/debian_version" AND (NOT EXISTS WIN32)) # Package-build on Debian/Ubuntu message(STATUS "Debian-based Linux OS detected") set(CPACK_GENERATOR "DEB;RPM") # RPM requires package `rpm` ### # Debian (DEB) ### # CPACK_DEB_PACKAGE_NAME --> Default: CPACK_PACKAGE_NAME ## DEB package file name # CPack DEB generator generates package file name in deb format: # _-_.deb set(CPACK_DEBIAN_FILE_NAME DEB-DEFAULT) # CPACK_DEBIAN_PACKAGE_VERSION --> Default: CPACK_PACKAGE_VERSION ## Set debian_revision number # Convention: Restart the debian_revision at 1 each time the upstream_version is increased. 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.19), libusb-1.0-0-dev (>= 1.0.24)") 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� # CPACK_DEBIAN_ARCHIVE_TYPE --> Default: “gnutar� # CPACK_DEBIAN_COMPRESSION_TYPE --> Default: “gzip� # CPACK_DEBIAN_PACKAGE_PRIORITY --> Default: “optional� # CPACK_DEBIAN_PACKAGE_HOMEPAGE --> Default: CMAKE_PROJECT_HOMEPAGE_URL set(CPACK_DEBIAN_PACKAGE_SUGGESTS "libgtk-3-dev, pandoc") ## Additional package files in Debian-specific format: # * changelog (package changelog) # * copyright (license file) # * rules # * postinst-script set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_SOURCE_DIR}/cmake/packaging/deb/changelog" "${CMAKE_SOURCE_DIR}/cmake/packaging/deb/copyright" "${CMAKE_SOURCE_DIR}/cmake/packaging/deb/rules" "${CMAKE_SOURCE_DIR}/cmake/packaging/deb/postinst" ) ### # Slackware & Redhat (RPM) ### set(CPACK_SET_DESTDIR "OFF") # Required for relocatable package # CPACK_RPM_PACKAGE_SUMMARY --> Default: CPACK_PACKAGE_DESCRIPTION_SUMMARY # CPACK_RPM_PACKAGE_NAME --> Default: CPACK_PACKAGE_NAME ## RPM package file name # Allow rpmbuild to generate package file name set(CPACK_RPM_FILE_NAME RPM-DEFAULT) # CPACK_RPM_PACKAGE_VERSION --> Default: CPACK_PACKAGE_VERSION # CPACK_RPM_PACKAGE_ARCHITECTURE --> Default: Native architecture output by uname -m ## Set rpm revision number # Convention: Restart the debian_revision at 1 each time the upstream_version is increased. set(CPACK_RPM_PACKAGE_RELEASE "1") set(CPACK_RPM_PACKAGE_LICENSE "BSD-3") # CPACK_RPM_PACKAGE_GROUP --> Default: “unknown� (RPM Groups are deprecated on Fedora) # CPACK_RPM_PACKAGE_VENDOR --> Default: CPACK_PACKAGE_VENDOR (as it is set) # CPACK_RPM_PACKAGE_URL --> Default: CMAKE_PROJECT_HOMEPAGE_URL set(CPACK_RPM_PACKAGE_DESCRIPTION CPACK_DEBIAN_PACKAGE_DESCRIPTION) ## Add package changelog in rpm-specific format set(CPACK_RPM_CHANGELOG_FILE "${CMAKE_SOURCE_DIR}/cmake/packaging/rpm/changelog") else () # No package configuration on other platforms ... endif() ### # Build packages ### include(CPack) stlink-1.9.0/cmake/modules/get_version.cmake000066400000000000000000000110601526027543100211060ustar00rootroot00000000000000# get_version.cmake # Determine project version by using Git or a local .version file set(__detect_version 0) find_package(Git) set(ERROR_FLAG "0") if (GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git") # Working off a git repo, using git versioning # Check if HEAD is pointing to a tag execute_process ( COMMAND "${GIT_EXECUTABLE}" describe --always --tag WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" OUTPUT_VARIABLE PROJECT_VERSION RESULT_VARIABLE GIT_DESCRIBE_RESULT ERROR_VARIABLE GIT_DESCRIBE_ERROR OUTPUT_STRIP_TRAILING_WHITESPACE ) if (GIT_DESCRIBE_RESULT EQUAL 0) # If the sources have been changed locally, add -dirty to the version. execute_process ( COMMAND "${GIT_EXECUTABLE}" diff --quiet WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" RESULT_VARIABLE res ) if (res EQUAL 1) set(PROJECT_VERSION "${PROJECT_VERSION}-dirty") endif() # Strip a leading v off of the version as proceeding code expects just the version numbering. string(REGEX REPLACE "^v" "" PROJECT_VERSION ${PROJECT_VERSION}) # Read version string string(REGEX REPLACE "^(0|[1-9][0-9]*)[.](0|[1-9][0-9]*)[.](0|[1-9][0-9]*)(-[.0-9A-Za-z-]+)?([+][.0-9A-Za-z-]+)?$" "\\1;\\2;\\3" PROJECT_VERSION_LIST ${PROJECT_VERSION}) list(LENGTH PROJECT_VERSION_LIST len) if (len EQUAL 3) list(GET PROJECT_VERSION_LIST 0 PROJECT_VERSION_MAJOR) list(GET PROJECT_VERSION_LIST 1 PROJECT_VERSION_MINOR) list(GET PROJECT_VERSION_LIST 2 PROJECT_VERSION_PATCH) set(__detect_version 1) set(__version_str "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") # Compare git-Version with version read from .version file in source folder if (EXISTS "${PROJECT_SOURCE_DIR}/.version") # Local .version file found, read version string... file(READ "${PROJECT_SOURCE_DIR}/.version" __version_file) # ...the version does not match with git-version string if (NOT __version_str STREQUAL __version_file) message(STATUS "Rewrite ${PROJECT_SOURCE_DIR}/.version with ${__version_str}!") endif() elseif (NOT EXISTS "${PROJECT_SOURCE_DIR}/.version") # No local .version file found: Create a new one... file(WRITE "${PROJECT_SOURCE_DIR}/.version" ${__version_str}) endif() message(STATUS "stlink version: ${PROJECT_VERSION}") message(STATUS "Major ${PROJECT_VERSION_MAJOR} Minor ${PROJECT_VERSION_MINOR} Patch ${PROJECT_VERSION_PATCH}") else (len EQUAL 3) message(STATUS "Failed to extract version parts from \"${PROJECT_VERSION}\"") set(ERROR_FLAG "1") endif(len EQUAL 3) else (GIT_DESCRIBE_RESULT EQUAL 0) message(WARNING "git describe failed: ${GIT_DESCRIBE_ERROR}") set(ERROR_FLAG "1") endif(GIT_DESCRIBE_RESULT EQUAL 0) endif() ## # Failure to read version via git # Possible cases: # -> git is not found or # -> /.git does not exist or # -> GIT_DESCRIBE failed or # -> version string is of invalid format ## if (NOT GIT_FOUND OR NOT EXISTS "${PROJECT_SOURCE_DIR}/.git" OR ERROR_FLAG EQUAL 1) message(STATUS "Git and/or repository not found.") # e.g. when building from source package message(STATUS "Try to detect version from \"${PROJECT_SOURCE_DIR}/.version\" file instead...") if (EXISTS ${PROJECT_SOURCE_DIR}/.version) file(STRINGS .version PROJECT_VERSION) # Read version string string(REGEX REPLACE "^(0|[1-9][0-9]*)[.](0|[1-9][0-9]*)[.](0|[1-9][0-9]*)(-[.0-9A-Za-z-]+)?([+][.0-9A-Za-z-]+)?$" "\\1;\\2;\\3" PROJECT_VERSION_LIST ${PROJECT_VERSION}) list(LENGTH PROJECT_VERSION_LIST len) if (len EQUAL 3) list(GET PROJECT_VERSION_LIST 0 PROJECT_VERSION_MAJOR) list(GET PROJECT_VERSION_LIST 1 PROJECT_VERSION_MINOR) list(GET PROJECT_VERSION_LIST 2 PROJECT_VERSION_PATCH) set(__detect_version 1) else () message(STATUS "Fail to extract version parts from \"${PROJECT_VERSION}\"") endif() else (EXISTS ${PROJECT_SOURCE_DIR}/.version) message(STATUS "File \"${PROJECT_SOURCE_DIR}/.version\" does not exist.") message(FATAL_ERROR "Unable to determine project version") endif() endif() stlink-1.9.0/cmake/modules/pandocology.cmake000066400000000000000000000433241526027543100211100ustar00rootroot00000000000000################################################################################ ## ## Provide Pandoc compilation support for the CMake build system ## ## Version: 0.0.1-dirty ## Author: Jeet Sukumatan (jeetsukumaran@gmail.com) ## Jerry Jacobs (jerry.jacobs@xor-gate.org) ## ## Copyright 2015 Jeet Sukumaran. ## Copyright 2016 Jerry Jacobs ## ## This software is released under the BSD 3-Clause License. ## ## Redistribution and use in source and binary forms, with or without ## modification, are permitted provided that the following conditions are ## met: ## ## 1. Redistributions of source code must retain the above copyright notice, ## this list of conditions and the following disclaimer. ## ## 2. Redistributions in binary form must reproduce the above copyright ## notice, this list of conditions and the following disclaimer in the ## documentation and/or other materials provided with the distribution. ## ## 3. Neither the name of the copyright holder nor the names of its ## contributors may be used to endorse or promote products derived from this ## software without specific prior written permission. ## ## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS ## IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, ## THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, ## EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, ## PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR ## PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ## LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ## NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ## SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ## ################################################################################ include(CMakeParseArguments) if (NOT EXISTS ${PANDOC_EXECUTABLE}) find_program(PANDOC_EXECUTABLE pandoc) mark_as_advanced(PANDOC_EXECUTABLE) endif() ############################################################################### # Based on code from UseLATEX # Author: Kenneth Moreland # Copyright 2004 Sandia Corporation. # Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive # license for use of this work by or on behalf of the # U.S. Government. Redistribution and use in source and binary forms, with # or without modification, are permitted provided that this Notice and any # statement of authorship are reproduced on all copies. # Adds command to copy file from the source directory to the destination # directory: used to move source files from source directory into build # directory before main build function(pandocology_add_input_file source_path dest_dir dest_filelist_var) set(dest_filelist) file(GLOB globbed_source_paths "${source_path}") foreach(globbed_source_path ${globbed_source_paths}) # MESSAGE(FATAL_ERROR "${globbed_source_path}") get_filename_component(filename ${globbed_source_path} NAME) get_filename_component(absolute_dest_path ${dest_dir}/${filename} ABSOLUTE) file(RELATIVE_PATH relative_dest_path ${CMAKE_CURRENT_BINARY_DIR} ${absolute_dest_path}) list(APPEND dest_filelist ${absolute_dest_path}) ADD_CUSTOM_COMMAND( OUTPUT ${relative_dest_path} COMMAND ${CMAKE_COMMAND} -E copy ${globbed_source_path} ${dest_dir}/${filename} DEPENDS ${globbed_source_path} ) set(${dest_filelist_var} ${${dest_filelist_var}} ${dest_filelist} PARENT_SCOPE) endforeach() endfunction() # A version of GET_FILENAME_COMPONENT that treats extensions after the last # period rather than the first. function(pandocology_get_file_stemname varname filename) SET(result) GET_FILENAME_COMPONENT(name ${filename} NAME) STRING(REGEX REPLACE "\\.[^.]*\$" "" result "${name}") SET(${varname} "${result}" PARENT_SCOPE) endfunction() function(pandocology_get_file_extension varname filename) SET(result) GET_FILENAME_COMPONENT(name ${filename} NAME) STRING(REGEX MATCH "\\.[^.]*\$" result "${name}") SET(${varname} "${result}" PARENT_SCOPE) endfunction() ############################################################################### function(pandocology_add_input_dir source_dir dest_parent_dir dir_dest_filelist_var) set(dir_dest_filelist) get_filename_component(dir_name ${source_dir} NAME) get_filename_component(absolute_dest_dir ${dest_parent_dir}/${dir_name} ABSOLUTE) file(RELATIVE_PATH relative_dest_dir ${CMAKE_CURRENT_BINARY_DIR} ${absolute_dest_dir}) add_custom_command( OUTPUT ${relative_dest_dir} COMMAND ${CMAKE_COMMAND} -E make_directory ${absolute_dest_dir} DEPENDS ${source_dir} ) file(GLOB source_files "${source_dir}/*") foreach(source_file ${source_files}) # get_filename_component(absolute_source_path ${CMAKE_CURRENT_SOURCE_DIR}/${source_file} ABSOLUTE) pandocology_add_input_file(${source_file} ${absolute_dest_dir} dir_dest_filelist) endforeach() set(${dir_dest_filelist_var} ${${dir_dest_filelist_var}} ${dir_dest_filelist} PARENT_SCOPE) endfunction() function(add_to_make_clean filepath) get_directory_property(make_clean_files ADDITIONAL_MAKE_CLEAN_FILES) set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${make_clean_files};${filepath}") endfunction() function(disable_insource_build) IF ( CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR AND NOT MSVC_IDE ) MESSAGE(FATAL_ERROR "The build directory must be different from the main project source " "directory. Please create a directory such as '${CMAKE_SOURCE_DIR}/build', " "and run CMake from there, passing the path to this source directory as " "the path argument. E.g.: $ cd ${CMAKE_SOURCE_DIR} $ mkdir build $ cd build $ cmake .. && make && sudo make install This process created the file `CMakeCache.txt' and the directory `CMakeFiles'. Please delete them: $ rm -r CMakeFiles/ CmakeCache.txt ") endif() endfunction() # This builds a document # # Usage: # # # INCLUDE(pandocology) # # add_document( # figures.tex # SOURCES figures.md # RESOURCE_DIRS figs # PANDOC_DIRECTIVES -t latex # NO_EXPORT_PRODUCT # ) # # add_document( # opus.pdf # SOURCES opus.md # RESOURCE_FILES opus.bib systbiol.template.latex systematic-biology.csl # RESOURCE_DIRS figs # PANDOC_DIRECTIVES -t latex # --smart # --template systbiol.template.latex # --filter pandoc-citeproc # --csl systematic-biology.csl # --bibliography opus.bib # --include-after-body=figures.tex # DEPENDS figures.tex # EXPORT_ARCHIVE # ) # function(add_document target_name) if (NOT PANDOC_EXECUTABLE) message(WARNING "Pandoc not found. Install Pandoc (http://johnmacfarlane.net/pandoc/) or set cache variable PANDOC_EXECUTABLE.") return() endif() set(options EXPORT_ARCHIVE NO_EXPORT_PRODUCT EXPORT_PDF DIRECT_TEX_TO_PDF VERBOSE) set(oneValueArgs PRODUCT_DIRECTORY) set(multiValueArgs SOURCES RESOURCE_FILES RESOURCE_DIRS PANDOC_DIRECTIVES DEPENDS) cmake_parse_arguments(ADD_DOCUMENT "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) # this is because `make clean` will dangerously clean up source files disable_insource_build() # get the stem of the target name pandocology_get_file_stemname(target_stemname ${target_name}) pandocology_get_file_extension(target_extension ${target_name}) if (${ADD_DOCUMENT_EXPORT_PDF}) if (NOT "${target_extension}" STREQUAL ".tex" AND NOT "${target_extension}" STREQUAL ".latex") # if (NOT "${target_extension}" STREQUAL ".tex") MESSAGE(FATAL_ERROR "Target '${target_name}': Cannot use 'EXPORT_PDF' for target of type '${target_extension}': target type must be '.tex' or '.latex'") endif() endif() if (${ADD_DOCUMENT_DIRECT_TEX_TO_PDF}) list(LENGTH ${ADD_DOCUMENT_SOURCES} SOURCE_LEN) if (SOURCE_LEN GREATER 1) MESSAGE(FATAL_ERROR "Target '${target_name}': Only one source can be specified when using the 'DIRECT_TEX_TO_PDF' option") endif() # set(ADD_DOCUMENT_SOURCES, list(GET ${ADD_DOCUMENT_SOURCES} 1)) pandocology_get_file_stemname(source_stemname ${ADD_DOCUMENT_SOURCES}) pandocology_get_file_extension(source_extension ${ADD_DOCUMENT_SOURCES}) if (NOT "${source_extension}" STREQUAL ".tex" AND NOT "${source_extension}" STREQUAL ".latex") MESSAGE(FATAL_ERROR "Target '${target_name}': Cannot use 'DIRECT_TEX_TO_PDF' for source of type '${source_extension}': source type must be '.tex' or '.latex'") endif() SET(check_target ${source_stemname}.pdf) IF (NOT ${check_target} STREQUAL ${target_name}) MESSAGE(FATAL_ERROR "Target '${target_name}': Must use target name of '${check_target}' if using 'DIRECT_TEX_TO_PDF'") endif() endif() ## set up output directory if ("${ADD_DOCUMENT_PRODUCT_DIRECTORY}" STREQUAL "") set(ADD_DOCUMENT_PRODUCT_DIRECTORY "product") endif() get_filename_component(product_directory ${CMAKE_BINARY_DIR}/${ADD_DOCUMENT_PRODUCT_DIRECTORY} ABSOLUTE) # get_filename_component(absolute_product_path ${product_directory}/${target_name} ABSOLUTE) ## get primary source set(build_sources) foreach(input_file ${ADD_DOCUMENT_SOURCES} ) pandocology_add_input_file(${CMAKE_CURRENT_SOURCE_DIR}/${input_file} ${CMAKE_CURRENT_BINARY_DIR} build_sources) endforeach() ## get resource files set(build_resources) foreach(resource_file ${ADD_DOCUMENT_RESOURCE_FILES}) pandocology_add_input_file(${CMAKE_CURRENT_SOURCE_DIR}/${resource_file} ${CMAKE_CURRENT_BINARY_DIR} build_resources) endforeach() ## get resource dirs set(exported_resources) foreach(resource_dir ${ADD_DOCUMENT_RESOURCE_DIRS}) pandocology_add_input_dir(${CMAKE_CURRENT_SOURCE_DIR}/${resource_dir} ${CMAKE_CURRENT_BINARY_DIR} build_resources) if (${ADD_DOCUMENT_EXPORT_ARCHIVE}) pandocology_add_input_dir(${CMAKE_CURRENT_SOURCE_DIR}/${resource_dir} ${product_directory} exported_resources) endif() endforeach() ## primary command if (${ADD_DOCUMENT_DIRECT_TEX_TO_PDF}) if (${ADD_DOCUMENT_VERBOSE}) add_custom_command( OUTPUT ${target_name} # note that this is in the build directory DEPENDS ${build_sources} ${build_resources} ${ADD_DOCUMENT_DEPENDS} # WORKING_DIRECTORY ${working_directory} COMMAND ${CMAKE_COMMAND} -E make_directory ${product_directory} # we produce the target in the source directory, in case other build targets require it as a source COMMAND latexmk -gg -halt-on-error -interaction=nonstopmode -file-line-error -pdf ${build_sources} ) else() add_custom_command( OUTPUT ${target_name} # note that this is in the build directory DEPENDS ${build_sources} ${build_resources} ${ADD_DOCUMENT_DEPENDS} # WORKING_DIRECTORY ${working_directory} COMMAND ${CMAKE_COMMAND} -E make_directory ${product_directory} # we produce the target in the source directory, in case other build targets require it as a source COMMAND latexmk -gg -halt-on-error -interaction=nonstopmode -file-line-error -pdf ${build_sources} 2>/dev/null >/dev/null || (grep --no-messages -A8 ".*:[0-9]*:.*" ${target_stemname}.log && false) ) endif() add_to_make_clean(${CMAKE_CURRENT_BINARY_DIR}/${target_name}) else() add_custom_command( OUTPUT ${target_name} # note that this is in the build directory DEPENDS ${build_sources} ${build_resources} ${ADD_DOCUMENT_DEPENDS} # WORKING_DIRECTORY ${working_directory} COMMAND ${CMAKE_COMMAND} -E make_directory ${product_directory} # we produce the target in the source directory, in case other build targets require it as a source COMMAND ${PANDOC_EXECUTABLE} ${build_sources} ${ADD_DOCUMENT_PANDOC_DIRECTIVES} -o ${target_name} ) add_to_make_clean(${CMAKE_CURRENT_BINARY_DIR}/${target_name}) endif() ## figure out what all is going to be produced by this build set, and set ## those as dependencies of the primary target set(primary_target_dependencies) set(primary_target_dependencies ${primary_target_dependencies} ${CMAKE_CURRENT_BINARY_DIR}/${target_name}) if (NOT ${ADD_DOCUMENT_NO_EXPORT_PRODUCT}) set(primary_target_dependencies ${primary_target_dependencies} ${product_directory}/${target_name}) endif() if (${ADD_DOCUMENT_EXPORT_PDF}) set(primary_target_dependencies ${primary_target_dependencies} ${CMAKE_CURRENT_BINARY_DIR}/${target_stemname}.pdf) set(primary_target_dependencies ${primary_target_dependencies} ${product_directory}/${target_stemname}.pdf) endif() if (${ADD_DOCUMENT_EXPORT_ARCHIVE}) set(primary_target_dependencies ${primary_target_dependencies} ${product_directory}/${target_stemname}.tbz) endif() ## primary target # # target cannot have same (absolute name) as dependencies: # # http://www.cmake.org/pipermail/cmake/2011-March/043378.html add_custom_target( ${target_name} ALL DEPENDS ${primary_target_dependencies} ${ADD_DOCUMENT_DEPENDS} ) # run post-pdf if (${ADD_DOCUMENT_EXPORT_PDF}) # get_filename_component(target_stemname ${target_name} NAME_WE) add_custom_command( OUTPUT ${product_directory}/${target_stemname}.pdf ${CMAKE_CURRENT_BINARY_DIR}/${target_stemname}.pdf DEPENDS ${target_name} ${build_sources} ${build_resources} ${ADD_DOCUMENT_DEPENDS} # Does not work: custom template used to generate tex is ignored # COMMAND ${PANDOC_EXECUTABLE} ${target_name} -f latex -o ${target_stemname}.pdf # (1) Apparently, both nonstopmode and batchmode produce an output file # even if there was an error. This tricks latexmk into believing # the file is actually up-to-date. # So we use `-halt-on-error` or `-interaction=errorstopmode` # instead. # (2) `grep` returns a non-zero error code if the pattern is not # found. So, in our scheme below to filter the output of # `pdflatex`, it is precisely when there is NO error that # grep returns a non-zero code, which fools CMake into thinking # tex'ing failed. # Hence the need for `| grep ...| cat` or `| grep || true`. # But we can go better: # latexmk .. || (grep .. && false) # So we can have our cake and eat it too: here we want to # re-raise the error after a successful grep if there was an # error in `latexmk`. # COMMAND latexmk -gg -halt-on-error -interaction=nonstopmode -file-line-error -pdf ${target_name} 2>&1 | grep -A8 ".*:[0-9]*:.*" || true COMMAND latexmk -gg -halt-on-error -interaction=nonstopmode -file-line-error -pdf ${target_name} 2>/dev/null >/dev/null || (grep --no-messages -A8 ".*:[0-9]*:.*" ${target_stemname}.log && false) COMMAND ${CMAKE_COMMAND} -E copy ${target_stemname}.pdf ${product_directory} ) add_to_make_clean(${CMAKE_CURRENT_BINARY_DIR}/${target_stemname}.pdf) add_to_make_clean(${product_directory}/${target_stemname}.pdf) endif() ## copy products if (NOT ${ADD_DOCUMENT_NO_EXPORT_PRODUCT}) add_custom_command( OUTPUT ${product_directory}/${target_name} DEPENDS ${build_sources} ${build_resources} ${ADD_DOCUMENT_DEPENDS} COMMAND ${CMAKE_COMMAND} -E copy ${target_name} ${product_directory} ) add_to_make_clean(${product_directory}/${target_name}) endif() ## copy resources if (${ADD_DOCUMENT_EXPORT_ARCHIVE}) # get_filename_component(target_stemname ${target_name} NAME_WE) # add_custom_command( # TARGET ${target_name} POST_BUILD # DEPENDS ${build_sources} ${build_resources} ${ADD_DOCUMENT_DEPENDS} # # COMMAND cp ${build_resources} ${ADD_DOCUMENT_DEPENDS} ${product_directory} # COMMAND ${CMAKE_COMMAND} -E tar cjf ${product_directory}/${target_stemname}.tbz ${target_name} ${build_resources} ${ADD_DOCUMENT_DEPENDS} # ) add_custom_command( OUTPUT ${product_directory}/${target_stemname}.tbz DEPENDS ${target_name} # COMMAND cp ${build_resources} ${ADD_DOCUMENT_DEPENDS} ${product_directory} COMMAND ${CMAKE_COMMAND} -E tar cjf ${product_directory}/${target_stemname}.tbz ${target_name} ${build_resources} ${ADD_DOCUMENT_DEPENDS} ) add_to_make_clean(${product_directory}/${target_stemname}.tbz) # add_custom_target( # ${target_stemname}.ARCHIVE # ALL # DEPENDS ${product_directory}/${target_stemname}.tbz # ) endif() endfunction(add_document) function(add_tex_document) add_document(${ARGV} DIRECT_TEX_TO_PDF) endfunction() # LEGACY SUPPORT function(add_pandoc_document) add_document(${ARGV}) endfunction() stlink-1.9.0/cmake/modules/set_toolchain.cmake000066400000000000000000000015561526027543100214260ustar00rootroot00000000000000# set_toolchain.cmake # Toolchain file for building on Windows (native) or cross-building on a Debian/Ubuntu Linux system # ### # Set toolchain and configure target environment on the build host system ### # Set cross compilers to use for C and C++ set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc) set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++) set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres) # Set path to directory with headers and libraries of the cross compiler set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX}) # Modify default behavior of FIND_XXX() commands to search for headers and libraries # in the target environment and search for programs in the build host environment set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) # Set target system name set(CMAKE_SYSTEM_NAME Windows)stlink-1.9.0/cmake/packaging/000077500000000000000000000000001526027543100160365ustar00rootroot00000000000000stlink-1.9.0/cmake/packaging/CMakeLists.txt000066400000000000000000000001361526027543100205760ustar00rootroot00000000000000add_subdirectory(deb) add_subdirectory(rpm) include(${CMAKE_MODULE_PATH}/cpack_config.cmake) stlink-1.9.0/cmake/packaging/deb/000077500000000000000000000000001526027543100165705ustar00rootroot00000000000000stlink-1.9.0/cmake/packaging/deb/CMakeLists.txt000066400000000000000000000000001526027543100213160ustar00rootroot00000000000000stlink-1.9.0/cmake/packaging/deb/changelog000066400000000000000000000010421526027543100204370ustar00rootroot00000000000000stlink (1.9.0) unstable; urgency=medium * Release v1.9.0 -- Nightwalker-87 Thu, 04 Oct 2026 00:00:00 +0100 stlink (1.8.0) unstable; urgency=medium * Release v1.8.0 -- Nightwalker-87 Thu, 01 Feb 2024 00:00:00 +0100 stlink (1.7.0) unstable; urgency=medium * Release v1.7.0 -- Nightwalker-87 Sun, 25 Apr 2021 00:00:00 +0100 stlink (1.6.1) unstable; urgency=medium * Initial cpack-based package release for Debian/Ubuntu -- Nightwalker-87 Mon, 01 Jun 2020 00:00:00 +0100 stlink-1.9.0/cmake/packaging/deb/control000066400000000000000000000006211526027543100201720ustar00rootroot00000000000000Source: stlink Priority: optional Maintainer: Nightwalker-87 Build-Depends: debhelper, pkgconf, systemd-dev, cmake (>= 3.20.0), libusb-1.0-0-dev (>= 1.0.24), libgtk-3-dev Standards-Version: 4.6.2 Rules-Requires-Root: no Section: electronics Homepage: https://github.com/stlink-org/stlink Vcs-Git: https://github.com/stlink-org/stlink.git Vcs-Browser: https://github.com/stlink-org/stlink stlink-1.9.0/cmake/packaging/deb/copyright000066400000000000000000000037031526027543100205260ustar00rootroot00000000000000Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: stlink Upstream-Contact: Nightwalker-87 Source: https://github.com/stlink-org/stlink Files: * Copyright: 2011-2020 stlink-org Martin Capitanio [capnm] Fabien Le Mentec [texane] Jerry Jacobs [xor-gate] [Nightwalker-87] and many others... An extended list of contributors can be found in "contributors.txt". License: BSD-3-clause Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: . 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. . THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. stlink-1.9.0/cmake/packaging/deb/postinst000066400000000000000000000001201526027543100203670ustar00rootroot00000000000000#!/bin/bash # This `DEBIAN/postinst` script is run post-installation depmod -a stlink-1.9.0/cmake/packaging/deb/rules000077500000000000000000000007671526027543100176620ustar00rootroot00000000000000#!/usr/bin/make -f # See debhelper(7) (uncomment to enable) # output every command that modifies files on the build system. #DH_VERBOSE = 1 # see EXAMPLES in dpkg-buildflags(1) and read /usr/share/dpkg/* DPKG_EXPORT_BUILDFLAGS = 1 include /usr/share/dpkg/default.mk # see FEATURE AREAS in dpkg-buildflags(1) export DEB_BUILD_MAINT_OPTIONS = hardening=+all %: dh $@ --buildsystem cmake --with cpack override_dh_auto_configure: dh_auto_configure -- \ -DSTLINK_UDEV_RULES_DIR='/lib/udev/rules.d' stlink-1.9.0/cmake/packaging/rpm/000077500000000000000000000000001526027543100166345ustar00rootroot00000000000000stlink-1.9.0/cmake/packaging/rpm/CMakeLists.txt000066400000000000000000000000001526027543100213620ustar00rootroot00000000000000stlink-1.9.0/cmake/packaging/rpm/changelog000066400000000000000000000004701526027543100205070ustar00rootroot00000000000000* Sun Oct 04 2026 Nightwalker-87 - 1.9.0 - Release v1.9.0 * Thu Feb 01 2024 Nightwalker-87 - 1.8.0 - Release v1.8.0 * Sun Apr 25 2021 Nightwalker-87 - 1.7.0 - Release v1.7.0 * Mon Jun 01 2020 Nightwalker-87 - 1.6.1 - Initial cpack-based RPM package release stlink-1.9.0/cmake_uninstall.cmake.in000066400000000000000000000023571526027543100176210ustar00rootroot00000000000000if (NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt") message(FATAL_ERROR "Cannot find install manifest: @CMAKE_BINARY_DIR@/install_manifest.txt") endif () file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files) string(REGEX REPLACE "\n" ";" files "${files}") foreach (file ${files}) message(STATUS "Uninstalling $ENV{DESTDIR}${file}") if (IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") execute_process( # remove deprecated: use rm instead, # because it does not check the file path, even return an error. COMMAND "@CMAKE_COMMAND@" -E rm "$ENV{DESTDIR}${file}" RESULT_VARIABLE rm_retval ERROR_VARIABLE rm_err ) if (NOT "${rm_retval}" STREQUAL 0) message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}\n${rm_err}") # Detect whether the file has been removed. elseif (IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") message(FATAL_ERROR "File has not been removed.\n${rm_err}") else () message(STATUS "File has been removed.") endif () else () message(STATUS "File $ENV{DESTDIR}${file} does not exist.") endif () endforeach () stlink-1.9.0/config/000077500000000000000000000000001526027543100142775ustar00rootroot00000000000000stlink-1.9.0/config/chips/000077500000000000000000000000001526027543100154055ustar00rootroot00000000000000stlink-1.9.0/config/chips/C011xx.chip000066400000000000000000000006371526027543100172440ustar00rootroot00000000000000# Chip-ID file for STM32C011xx device # dev_type STM32C011xx ref_manual_id 0490 chip_id 0x443 // STM32_CHIPID_C011xx flash_type C0 flash_size_reg 0x1fff75a0 flash_pagesize 0x800 // 2 KB sram_size 0x1800 // 6 KB bootrom_base 0x1fff0000 bootrom_size 0x1800 // 6 KB option_base 0x1fff7800 // STM32_OPTION_BYTES_BASE_C0 option_size 0x80 // 128 B flags none stlink-1.9.0/config/chips/C031xx.chip000066400000000000000000000006401526027543100172400ustar00rootroot00000000000000# Chip-ID file for STM32C031xx device # dev_type STM32C031xx ref_manual_id 0490 chip_id 0x453 // STM32_CHIPID_C031xx flash_type C0 flash_size_reg 0x1fff75a0 flash_pagesize 0x800 // 2 KB sram_size 0x3000 // 12 KB bootrom_base 0x1fff0000 bootrom_size 0x1800 // 6 KB option_base 0x1fff7800 // STM32_OPTION_BYTES_BASE_C0 option_size 0x80 // 128 B flags none stlink-1.9.0/config/chips/C051xx.chip000066400000000000000000000006401526027543100172420ustar00rootroot00000000000000# Chip-ID file for STM32C051xx device # dev_type STM32C051xx ref_manual_id 0490 chip_id 0x44C // STM32_CHIPID_C051xx flash_type C0 flash_size_reg 0x1fff75a0 flash_pagesize 0x800 // 2 KB sram_size 0x3000 // 12 KB bootrom_base 0x1fff0000 bootrom_size 0x1800 // 6 KB option_base 0x1fff7800 // STM32_OPTION_BYTES_BASE_C0 option_size 0x80 // 128 B flags none stlink-1.9.0/config/chips/C071xx.chip000066400000000000000000000006401526027543100172440ustar00rootroot00000000000000# Chip-ID file for STM32C071xx device # dev_type STM32C071xx ref_manual_id 0490 chip_id 0x493 // STM32_CHIPID_C071xx flash_type C0 flash_size_reg 0x1fff75a0 flash_pagesize 0x800 // 2 KB sram_size 0x6000 // 24 KB bootrom_base 0x1fff0000 bootrom_size 0x1800 // 6 KB option_base 0x1fff7800 // STM32_OPTION_BYTES_BASE_C0 option_size 0x80 // 128 B flags none stlink-1.9.0/config/chips/C091xx.chip000066400000000000000000000007571526027543100172570ustar00rootroot00000000000000# Chip-ID file for STM32_C091xx_C92xx device # dev_type STM32_C091xx_C92xx ref_manual_id 0490 chip_id 0x44D // STM32_CHIPID_C091xx_C92xx flash_type C0 flash_size_reg 0x1fff75a0 flash_pagesize 0x800 // 2 KB sram_size 0x9000 // 36 KB: C92xx: 30 KB + 6KB FDCAN RAM (RM490 rev. 5 2.4 FDCAN RAM) bootrom_base 0x1fff0000 bootrom_size 0x1800 // 6 KB option_base 0x1fff7800 // STM32_OPTION_BYTES_BASE_C0 option_size 0x80 // 128 B flags none stlink-1.9.0/config/chips/C53x_C54x.chip000066400000000000000000000005641526027543100176040ustar00rootroot00000000000000# Chip-ID file for STM32C53x / STM32C54x device # dev_type STM32C53x_C54x ref_manual_id 0522 chip_id 0x44f // STM32_CHIPID_C53x_C54x flash_type C5 flash_size_reg 0x08fff80c flash_pagesize 0x2000 // 8 KB sram_size 0x10000 // 64 KB bootrom_base 0x0bf80080 bootrom_size 0x8400 // 33 KB option_base 0 option_size 0 flags swo dualbank stlink-1.9.0/config/chips/C55x_C56x.chip000066400000000000000000000005651526027543100176110ustar00rootroot00000000000000# Chip-ID file for STM32C55x / STM32C56x device # dev_type STM32C55x_C56x ref_manual_id 0522 chip_id 0x44e // STM32_CHIPID_C55x_C56x flash_type C5 flash_size_reg 0x08fff80c flash_pagesize 0x2000 // 8 KB sram_size 0x20000 // 128 KB bootrom_base 0x0bf80080 bootrom_size 0x8400 // 33 KB option_base 0 option_size 0 flags swo dualbank stlink-1.9.0/config/chips/C59x_C5Ax.chip000066400000000000000000000005651526027543100176300ustar00rootroot00000000000000# Chip-ID file for STM32C59x / STM32C5Ax device # dev_type STM32C59x_C5Ax ref_manual_id 0522 chip_id 0x45a // STM32_CHIPID_C59x_C5Ax flash_type C5 flash_size_reg 0x08fff80c flash_pagesize 0x2000 // 8 KB sram_size 0x40000 // 256 KB bootrom_base 0x0bf80080 bootrom_size 0x8400 // 33 KB option_base 0 option_size 0 flags swo dualbank stlink-1.9.0/config/chips/F03x.chip000066400000000000000000000006441526027543100167760ustar00rootroot00000000000000# Chip-ID file for STM32F03x device # dev_type STM32F03x ref_manual_id 0091 chip_id 0x444 // STM32_CHIPID_F0xx_SMALL flash_type F0_F1_F3 flash_size_reg 0x1ffff7cc flash_pagesize 0x400 // 1 KB sram_size 0x1000 // 4 KB bootrom_base 0x1fffec00 bootrom_size 0xc00 // 3 KB option_base 0x1ffff800 // STM32_OPTION_BYTES_BASE_F0 option_size 0x10 // 16 B flags none stlink-1.9.0/config/chips/F04x.chip000066400000000000000000000006351526027543100167770ustar00rootroot00000000000000# Chip-ID file for STM32F04x device # dev_type STM32F04x ref_manual_id 0091 chip_id 0x445 // STM32_CHIPID_F04 flash_type F0_F1_F3 flash_size_reg 0x1ffff7cc flash_pagesize 0x400 // 1 KB sram_size 0x1800 // 6 KB bootrom_base 0x1fffec00 bootrom_size 0xc00 // 3 KB option_base 0x1ffff800 // STM32_OPTION_BYTES_BASE_F0 option_size 0x10 // 16 B flags none stlink-1.9.0/config/chips/F05x.chip000066400000000000000000000006341526027543100167770ustar00rootroot00000000000000# Chip-ID file for STM32F05x device # dev_type STM32F05x ref_manual_id 0091 chip_id 0x440 // STM32_CHIPID_F0 flash_type F0_F1_F3 flash_size_reg 0x1ffff7cc flash_pagesize 0x400 // 1 KB sram_size 0x2000 // 8 KB bootrom_base 0x1fffec00 bootrom_size 0xc00 // 3 KB option_base 0x1ffff800 // STM32_OPTION_BYTES_BASE_F0 option_size 0x10 // 16 B flags none stlink-1.9.0/config/chips/F07x.chip000066400000000000000000000006421526027543100170000ustar00rootroot00000000000000# Chip-ID file for STM32F07x device # dev_type STM32F07x ref_manual_id 0091 chip_id 0x448 // STM32_CHIPID_F0_CAN flash_type F0_F1_F3 flash_size_reg 0x1ffff7cc flash_pagesize 0x800 // 2 KB sram_size 0x4000 // 16 KB bootrom_base 0x1fffc800 bootrom_size 0x3000 // 12 KB option_base 0x1ffff800 // STM32_OPTION_BYTES_BASE_F0 option_size 0x10 // 16 B flags none stlink-1.9.0/config/chips/F09x.chip000066400000000000000000000006371526027543100170060ustar00rootroot00000000000000# Chip-ID file for STM32F09x device # dev_type STM32F09x ref_manual_id 0091 chip_id 0x442 // STM32_CHIPID_F09x flash_type F0_F1_F3 flash_size_reg 0x1ffff7cc flash_pagesize 0x800 // 2 KB sram_size 0x8000 // 32 KB bootrom_base 0x1fffd800 bootrom_size 0x2000 // 8 KB option_base 0x1ffff800 // STM32_OPTION_BYTES_BASE_F0 option_size 0x10 // 16 B flags none stlink-1.9.0/config/chips/F1xx_CL.chip000066400000000000000000000007051526027543100174600ustar00rootroot00000000000000# Chip-ID file for STM32F1xx Connectivity Line device (F105 / F107) # dev_type STM32F1xx_CL ref_manual_id 0008 chip_id 0x418 // STM32_CHIPID_F1_CONN flash_type F0_F1_F3 flash_size_reg 0x1ffff7e0 flash_pagesize 0x800 // 2 KB sram_size 0x10000 // 64 KB bootrom_base 0x1fffb000 bootrom_size 0x4800 // 18 KB option_base 0x1ffff800 // STM32_OPTION_BYTES_BASE_F0 option_size 0x10 // 16 B flags swo stlink-1.9.0/config/chips/F1xx_HD.chip000066400000000000000000000006521526027543100174560ustar00rootroot00000000000000# Chip-ID file for STM32F1xx high density device # dev_type F1xx_HD ref_manual_id 0008 chip_id 0x414 // STM32_CHIPID_F1_HD flash_type F0_F1_F3 flash_size_reg 0x1ffff7e0 flash_pagesize 0x800 // 2 KB sram_size 0x10000 // 64 KB bootrom_base 0x1ffff000 bootrom_size 0x800 // 2 KB option_base 0x1ffff800 // STM32_OPTION_BYTES_BASE_F0 option_size 0x10 // 16 B flags swo stlink-1.9.0/config/chips/F1xx_LD.chip000066400000000000000000000006541526027543100174640ustar00rootroot00000000000000# Chip-ID file for STM32F1 low density device # dev_type STM32F1xx_LD ref_manual_id 0008 chip_id 0x412 // STM32_CHIPID_F1_LD flash_type F0_F1_F3 flash_size_reg 0x1ffff7e0 flash_pagesize 0x400 // 1 KB sram_size 0x2800 // 10 KB bootrom_base 0x1ffff000 bootrom_size 0x800 // 2 KB option_base 0x1ffff800 // STM32_OPTION_BYTES_BASE_F0 option_size 0x10 // 16 B flags swo stlink-1.9.0/config/chips/F1xx_MD.chip000066400000000000000000000006611526027543100174630ustar00rootroot00000000000000# Chip-ID file for STM32F1xx medium density device # dev_type STM32F1xx_MD ref_manual_id 0008 chip_id 0x410 // STM32_CHIPID_F1_MD flash_type F0_F1_F3 flash_size_reg 0x1ffff7e0 flash_pagesize 0x400 // 1 KB sram_size 0x5000 // 20 KB bootrom_base 0x1ffff000 bootrom_size 0x800 // 2 KB option_base 0x1ffff800 // STM32_OPTION_BYTES_BASE_F0 option_size 0x10 // 16 B flags swo stlink-1.9.0/config/chips/F1xx_VL_HD.chip000066400000000000000000000007001526027543100200510ustar00rootroot00000000000000# Chip-ID file for STM32F1xx high density Value Line device # dev_type STM32F1xx_VL_HD ref_manual_id 0041 chip_id 0x428 // STM32_CHIPID_F1_VL_HD flash_type F0_F1_F3 flash_size_reg 0x1ffff7e0 flash_pagesize 0x800 // 2 KB sram_size 0x8000 // 32 KB bootrom_base 0x1ffff000 bootrom_size 0x800 // 2 KB option_base 0x1ffff800 // STM32_OPTION_BYTES_BASE_F0 option_size 0x10 // 16 B flags swo stlink-1.9.0/config/chips/F1xx_VL_MD_LD.chip000066400000000000000000000007601526027543100204430ustar00rootroot00000000000000# Chip-ID file for STMF1xx Value Line medium & low density device # dev_type STM32F1xx_VL_MD_LD ref_manual_id 0041 chip_id 0x420 // STM32_CHIPID_F1_VL_MD_LD flash_type F0_F1_F3 flash_size_reg 0x1ffff7e0 flash_pagesize 0x400 // 1 KB sram_size 0x2000 // 8 KB /* 0x1000 for low density devices */ bootrom_base 0x1ffff000 bootrom_size 0x800 // 2 KB option_base 0x1ffff800 // STM32_OPTION_BYTES_BASE_F0 option_size 0x10 // 16 B flags swo stlink-1.9.0/config/chips/F1xx_XLD.chip000066400000000000000000000006541526027543100176140ustar00rootroot00000000000000# Chip-ID file for STM32F1xx XL density device # dev_type STM32F1xx_XLD ref_manual_id 0008 chip_id 0x430 // STM32_CHIPID_F1_XLD flash_type F1_XL flash_size_reg 0x1ffff7e0 flash_pagesize 0x800 // 2 KB sram_size 0x18000 // 96 KB bootrom_base 0x1fffe000 bootrom_size 0x1800 // 6 KB option_base 0x1ffff800 // STM32_OPTION_BYTES_BASE_F0 option_size 0x10 // 16 B flags swo stlink-1.9.0/config/chips/F2xx.chip000066400000000000000000000006341526027543100171040ustar00rootroot00000000000000# Chip-ID file for STM32F2xx device # dev_type STM32F2xx ref_manual_id 0033 chip_id 0x411 // STM32_CHIPID_F2 flash_type F2_F4 flash_size_reg 0x1fff7a22 flash_pagesize 0x20000 // 128 KB sram_size 0x20000 // 128 KB bootrom_base 0x1fff0000 bootrom_size 0x7800 // 30 KB option_base 0x1fffc000 // STM32_OPTION_BYTES_BASE_F2 option_size 0x4 // 4 B flags swo stlink-1.9.0/config/chips/F301_F302_F318.chip000066400000000000000000000007441526027543100200630ustar00rootroot00000000000000# Chip-ID file for STM32F3xx device (F301x6/8, F302x6x8, F318x8) # dev_type STM32F301_F302_F318 ref_manual_id 0365 // also RM0366 chip_id 0x439 // STM32_CHIPID_F3xx_SMALL flash_type F0_F1_F3 flash_size_reg 0x1ffff7cc flash_pagesize 0x800 // 2 KB sram_size 0xa000 // 40 KB bootrom_base 0x1fffd800 bootrom_size 0x2000 // 8 KB option_base 0x1ffff800 // STM32_OPTION_BYTES_BASE_F0 option_size 0x10 // 16 B flags swo stlink-1.9.0/config/chips/F302_F303_F358.chip000066400000000000000000000007311526027543100200650ustar00rootroot00000000000000# Chip-ID file for STM32F3xx device (F302xBxC, F303xB/C, F358) # dev_type STM32F302_F303_358 ref_manual_id 0365 // also RM0316 chip_id 0x422 // STM32_CHIPID_F3 flash_type F0_F1_F3 flash_size_reg 0x1ffff7cc flash_pagesize 0x800 // 2 KB sram_size 0xa000 // 40 KB bootrom_base 0x1ffff000 bootrom_size 0x800 // 2 KB option_base 0x1ffff800 // STM32_OPTION_BYTES_BASE_F0 option_size 0x10 // 16 B flags swo stlink-1.9.0/config/chips/F302_F303_F398_HD.chip000066400000000000000000000007711526027543100204500ustar00rootroot00000000000000# Chip-ID file for STM32F3xx high density device (F302xD/E, F303xD/E, F398xE) # dev_type STM32F302_F303_F398_HD ref_manual_id 0365 // also RM0316 (Rev 5) chip_id 0x446 // STM32_CHIPID_F303_HD flash_type F0_F1_F3 flash_size_reg 0x1ffff7cc flash_pagesize 0x800 // 2 KB sram_size 0x10000 // 64 KB bootrom_base 0x1fffd800 bootrom_size 0x2000 // 8 KB option_base 0x1ffff800 // STM32_OPTION_BYTES_BASE_F0 option_size 0x10 // 16 B flags swo stlink-1.9.0/config/chips/F303_F328_F334.chip000066400000000000000000000007301526027543100200660ustar00rootroot00000000000000# Chip-ID file for STM32F3xx device (F303x6/8, F328, F334) # dev_type STM32F303_F328_F334 ref_manual_id 0364 // also RM0316 chip_id 0x438 // STM32_CHIPID_F334 flash_type F0_F1_F3 flash_size_reg 0x1ffff7cc flash_pagesize 0x800 // 2 KB sram_size 0x3000 // 12 KB bootrom_base 0x1fffd800 bootrom_size 0x2000 // 8 KB option_base 0x1ffff800 // STM32_OPTION_BYTES_BASE_F0 option_size 0x10 // 16 B flags swo stlink-1.9.0/config/chips/F37x.chip000066400000000000000000000006361526027543100170060ustar00rootroot00000000000000# Chip-ID file for STM32F37x device # dev_type STM32F37x ref_manual_id 0313 chip_id 0x432 // STM32_CHIPID_F37x flash_type F0_F1_F3 flash_size_reg 0x1ffff7cc flash_pagesize 0x800 // 2 KB sram_size 0xa000 // 40 KB bootrom_base 0x1ffff000 bootrom_size 0x800 // 2 KB option_base 0x1ffff800 // STM32_OPTION_BYTES_BASE_F0 option_size 0x10 // 16 B flags swo stlink-1.9.0/config/chips/F401xB_xC.chip000066400000000000000000000005501526027543100176100ustar00rootroot00000000000000# Chip-ID file for STM32F401xB/xC device # dev_type STM32F401xB_xC ref_manual_id 0368 chip_id 0x423 // STM32_CHIPID_F4_LP flash_type F2_F4 flash_size_reg 0x1fff7a22 flash_pagesize 0x4000 // 16 KB sram_size 0x10000 // 64 KB bootrom_base 0x1fff0000 bootrom_size 0x7800 // 30 KB option_base 0x0 option_size 0x0 flags swo stlink-1.9.0/config/chips/F401xD_xE.chip000066400000000000000000000006471526027543100176230ustar00rootroot00000000000000# Chip-ID file for STM32F401xD/xE device # dev_type STM32F401xD_xE ref_manual_id 0368 chip_id 0x433 // STM32_CHIPID_F4_DE flash_type F2_F4 flash_size_reg 0x1fff7a22 flash_pagesize 0x4000 // 16 KB sram_size 0x18000 // 96 KB bootrom_base 0x1fff0000 bootrom_size 0x7800 // 30 KB option_base 0x40023C14 // STM32_OPTION_BYTES_BASE_F4 option_size 0x4 // 4 B flags swo stlink-1.9.0/config/chips/F410.chip000066400000000000000000000005351526027543100166670ustar00rootroot00000000000000# Chip-ID file for STM32F410 device # dev_type STM32F410 ref_manual_id 0401 chip_id 0x458 // STM32_CHIPID_F410 flash_type F2_F4 flash_size_reg 0x1fff7a22 flash_pagesize 0x4000 // 16 KB sram_size 0x8000 // 32 KB bootrom_base 0x1fff0000 bootrom_size 0x7800 // 30 KB option_base 0x0 option_size 0x0 flags swo stlink-1.9.0/config/chips/F411xC_xE.chip000066400000000000000000000005621526027543100176170ustar00rootroot00000000000000# Chip-ID file for STM32F411xC/xE device # dev_type STM32F411xC_xE ref_manual_id 0383 chip_id 0x431 // STM32_CHIPID_F411xx flash_type F2_F4 flash_size_reg 0x1fff7a22 flash_pagesize 0x4000 // 16 KB sram_size 0x20000 // 128 KB bootrom_base 0x1fff0000 bootrom_size 0x7800 // 30 KB option_base 0x40023c14 option_size 0x04 flags swo stlink-1.9.0/config/chips/F412.chip000066400000000000000000000005361526027543100166720ustar00rootroot00000000000000# Chip-ID file for STM32F412 device # dev_type STM32F412 ref_manual_id 0402 chip_id 0x441 // STM32_CHIPID_F412 flash_type F2_F4 flash_size_reg 0x1fff7a22 flash_pagesize 0x4000 // 16 KB sram_size 0x40000 // 256 KB bootrom_base 0x1fff0000 bootrom_size 0x7800 // 30 KB option_base 0x0 option_size 0x0 flags swo stlink-1.9.0/config/chips/F413_F423.chip000066400000000000000000000006131526027543100173650ustar00rootroot00000000000000# Chip-ID file for STM32F413 / STM32F423 device # dev_type STM32F413_F423 ref_manual_id 0430 // RM0430 (Rev 2) chip_id 0x463 // STM32_CHIPID_F413 flash_type F2_F4 flash_size_reg 0x1fff7a22 flash_pagesize 0x4000 // 16 KB sram_size 0x50000 // 320 KB bootrom_base 0x1fff0000 bootrom_size 0x7800 // 30 KB option_base 0x0 option_size 0x0 flags swo stlink-1.9.0/config/chips/F42x_F43x.chip000066400000000000000000000006151526027543100176030ustar00rootroot00000000000000# Chip-ID file for STM32F42x / STM32F43x device # dev_type STM32F42x_F43x ref_manual_id 0090 // RM0090 (Rev. 2) chip_id 0x419 // STM32_CHIPID_F4_HD flash_type F2_F4 flash_size_reg 0x1fff7a22 flash_pagesize 0x4000 // 16 KB sram_size 0x40000 // 256 KB bootrom_base 0x1fff0000 bootrom_size 0x7800 // 30 KB option_base 0x0 option_size 0x0 flags swo stlink-1.9.0/config/chips/F446.chip000066400000000000000000000006371526027543100167030ustar00rootroot00000000000000# Chip-ID file for STM32F446 device # dev_type STM32F446 ref_manual_id 0390 chip_id 0x421 // STM32_CHIPID_F446 flash_type F2_F4 flash_size_reg 0x1fff7a22 flash_pagesize 0x20000 // 128 KB sram_size 0x20000 // 128 KB bootrom_base 0x1fff0000 bootrom_size 0x7800 // 30 KB option_base 0x40023c14 // STM32_OPTION_BYTES_BASE_F4 option_size 0x10 // 16 B flags swo stlink-1.9.0/config/chips/F46x_F47x.chip000066400000000000000000000006161526027543100176140ustar00rootroot00000000000000# Chip-ID file for STM32F46x / STM32F47x device # dev_type STM32F46x_F47x ref_manual_id 0090 // RM0090 (Rev. 2) chip_id 0x434 // STM32_CHIPID_F4_DSI flash_type F2_F4 flash_size_reg 0x1fff7a22 flash_pagesize 0x4000 // 16 KB sram_size 0x40000 // 256 KB bootrom_base 0x1fff0000 bootrom_size 0x7800 // 30 KB option_base 0x0 option_size 0x0 flags swo stlink-1.9.0/config/chips/F4x5_F4x7.chip000066400000000000000000000007111526027543100176070ustar00rootroot00000000000000# Chip-ID file for STM32F4x5 / STM32F4x7 device # dev_type STM32F4x5_F4x7 ref_manual_id 0090 // RM0090 (Rev. 2) chip_id 0x413 // STM32_CHIPID_F4 flash_type F2_F4 flash_size_reg 0x1fff7a22 flash_pagesize 0x4000 // 16 KB sram_size 0x30000 // 192 KB bootrom_base 0x1fff0000 bootrom_size 0x7800 // 30 KB option_base 0x40023c14 // STM32_OPTION_BYTES_BASE_F4 option_size 0x4 // 4 B flags swo stlink-1.9.0/config/chips/F72x_F73x.chip000066400000000000000000000006601526027543100176110ustar00rootroot00000000000000# Chip-ID file for STM32F72x / STM32F73x device # dev_type STM32F72x_F73x ref_manual_id 0431 chip_id 0x452 // STM32_CHIPID_F72xxx flash_type F7 flash_size_reg 0x1ff07a22 flash_pagesize 0x800 // 2 KB sram_size 0x40000 // 256 KB bootrom_base 0x100000 bootrom_size 0xedc0 // 59.4375 KB option_base 0x1fff0000 // STM32_OPTION_BYTES_BASE_F7 option_size 0x20 // 32 B flags swo stlink-1.9.0/config/chips/F74x_F75x.chip000066400000000000000000000006541526027543100176200ustar00rootroot00000000000000# Chip-ID file for STM32F74x / STM32F75x device # dev_type STM32F74x_F75x ref_manual_id 0385 chip_id 0x449 // STM32_CHIPID_F7 flash_type F7 flash_size_reg 0x1ff0f442 flash_pagesize 0x800 // 2 KB sram_size 0x50000 // 320 KB bootrom_base 0x100000 bootrom_size 0xedc0 // 59.4375 KB option_base 0x1fff0000 // STM32_OPTION_BYTES_BASE_F7 option_size 0x20 // 32 B flags swo stlink-1.9.0/config/chips/F76x_F77x.chip000066400000000000000000000010371526027543100176200ustar00rootroot00000000000000# Chip-ID file for STM32F76x / STM32F77x device # dev_type STM32F76x_F77x ref_manual_id 0410 chip_id 0x451 // STM32_CHIPID_F76xxx flash_type F7 flash_size_reg 0x1ff0f442 flash_pagesize 0x800 // 2 KB sram_size 0x80000 // 512 KB bootrom_base 0x200000 bootrom_size 0xedc0 // 59.4375 KB option_base 0x1fff0000 // STM32_OPTION_BYTES_BASE_F7 /* Used for reading back option bytes, writing uses STM32_FLASH_F7_OPTCR and STM32_FLASH_F7_OPTCR1 */ option_size 0x20 // 32 B flags swo dualbank stlink-1.9.0/config/chips/G03x_G04x.chip000066400000000000000000000007211526027543100175750ustar00rootroot00000000000000# Chip-ID file for STM32G030 / STM32G031 / STM32G041 device # dev_type STM32G03x_G04x ref_manual_id 0444 // also RM454 chip_id 0x466 // STM32_CHIPID_G0_CAT1 flash_type G0 flash_size_reg 0x1fff75e0 flash_pagesize 0x800 // 2 KB sram_size 0x2000 // 8 KB bootrom_base 0x1fff0000 bootrom_size 0x2000 // 8 KB option_base 0x1fff7800 // STM32_OPTION_BYTES_BASE_G0 option_size 0x80 // 128 B flags none stlink-1.9.0/config/chips/G05x_G06x.chip000066400000000000000000000007071526027543100176050ustar00rootroot00000000000000# Chip-ID file for STM32G05x / STM32G06x device # dev_type STM32G05x_G06x ref_manual_id 0444 // also RM454 chip_id 0x456 // STM32_CHIPID_G0_CAT4 flash_type G0 flash_size_reg 0x1fff75e0 flash_pagesize 0x800 // 2 KB sram_size 0x4800 // 18 KB bootrom_base 0x1fff0000 bootrom_size 0x7000 // 28 KB option_base 0x1fff7800 // STM32_OPTION_BYTES_BASE_G0 option_size 0x80 // 128 B flags none stlink-1.9.0/config/chips/G07x_G08x.chip000066400000000000000000000007071526027543100176110ustar00rootroot00000000000000# Chip-ID file for STM32G07x / STM32G08x device # dev_type STM32G07x_G08x ref_manual_id 0444 // also RM454 chip_id 0x460 // STM32_CHIPID_G0_CAT2 flash_type G0 flash_size_reg 0x1fff75e0 flash_pagesize 0x800 // 2 KB sram_size 0x9000 // 36 KB bootrom_base 0x1fff0000 bootrom_size 0x7000 // 28 KB option_base 0x1fff7800 // STM32_OPTION_BYTES_BASE_G0 option_size 0x80 // 128 B flags none stlink-1.9.0/config/chips/G0Bx_G0Cx.chip000066400000000000000000000007141526027543100176350ustar00rootroot00000000000000# Chip-ID file for STM32G0Bx / STM32G0Cx device # dev_type STM32G0Bx_G0Cx ref_manual_id 0444 // also RM454 chip_id 0x467 // STM32_CHIPID_G0_CAT3 flash_type G0 flash_size_reg 0x1fff75e0 flash_pagesize 0x800 // 2 KB sram_size 0x24000 // 144 KB bootrom_base 0x1fff0000 bootrom_size 0x7000 // 28 KB option_base 0x1fff7800 // STM32_OPTION_BYTES_BASE_G0 option_size 0x80 // 128 B flags dualbank stlink-1.9.0/config/chips/G43x_G44x.chip000066400000000000000000000006541526027543100176120ustar00rootroot00000000000000# Chip-ID file for STM32G43x / STM32G44x device # dev_type STM32G43x_G44x ref_manual_id 0440 chip_id 0x468 // STM32_CHIPID_G4_CAT2 flash_type G4 flash_size_reg 0x1fff75e0 flash_pagesize 0x800 // 2 KB sram_size 0x8000 // 32 KB bootrom_base 0x1fff0000 bootrom_size 0x7000 // 28 KB option_base 0x1ffff800 // STM32_OPTION_BYTES_BASE_G4 option_size 0x4 // 4 B flags swo stlink-1.9.0/config/chips/G47x_G48x.chip000066400000000000000000000006661526027543100176250ustar00rootroot00000000000000# Chip-ID file for STM32G47x / STM32G48x device # dev_type STM32G47x_G48x ref_manual_id 0440 chip_id 0x469 // STM32_CHIPID_G4_CAT3 flash_type G4 flash_size_reg 0x1fff75e0 flash_pagesize 0x800 // 2 KB sram_size 0x20000 // 128 KB bootrom_base 0x1fff0000 bootrom_size 0x7000 // 28 KB option_base 0x1ffff800 // STM32_OPTION_BYTES_BASE_G4 option_size 0x4 // 4 B flags swo dualbank stlink-1.9.0/config/chips/G49x_G4Ax.chip000066400000000000000000000006551526027543100176360ustar00rootroot00000000000000# Chip-ID file for STM32G49x / STM32G4Ax device # dev_type STM32G49x_G4Ax ref_manual_id 0440 chip_id 0x479 // STM32_CHIPID_G4_CAT4 flash_type G4 flash_size_reg 0x1fff75e0 flash_pagesize 0x800 // 2 KB sram_size 0x1c000 // 112 KB bootrom_base 0x1fff0000 bootrom_size 0x7000 // 28 KB option_base 0x1ffff800 // STM32_OPTION_BYTES_BASE_G4 option_size 0x4 // 4 B flags swo stlink-1.9.0/config/chips/H52_H53xx.chip000066400000000000000000000006061526027543100176110ustar00rootroot00000000000000# Chip-ID file for STM32H52xx/H53xx devices (e.g. STM32H533RET6) # dev_type STM32H52_H53xx ref_manual_id 0481 chip_id 0x478 // STM32_CHIPID_H52_H53xx flash_type H5 flash_size_reg 0x08fff80c flash_pagesize 0x2000 // 8 KB sram_size 0x44000 // 272 KB bootrom_base 0x0bf80000 bootrom_size 0x8000 // 32 KB option_base 0x0 option_size 0x0 flags dualbank stlink-1.9.0/config/chips/H5xx.chip000066400000000000000000000005371526027543100171130ustar00rootroot00000000000000# Chip-ID file for STM32H5xx device # dev_type STM32H5xx ref_manual_id 0481 chip_id 0x484 // STM32_CHIPID_H5xx flash_type H5 flash_size_reg 0x08fff80c flash_pagesize 0x2000 // 8 KB sram_size 0xa0000 // 640 KB bootrom_base 0x0bf80000 bootrom_size 0x8000 // 32 KB option_base 0x0 option_size 0x0 flags dualbank stlink-1.9.0/config/chips/H72x_H73x.chip000066400000000000000000000006651526027543100176220ustar00rootroot00000000000000# Chip-ID file for STM32H72x / STM32H73x device # dev_type STM32H72x_H73x ref_manual_id 0468 chip_id 0x483 // STM32_CHIPID_H72x flash_type H7 flash_size_reg 0x1ff1e880 flash_pagesize 0x20000 // 128 KB sram_size 0x20000 // 128 KB "DTCM" bootrom_base 0x1ff00000 bootrom_size 0x20000 // 128 KB option_base 0x52002020 // STM32_OPTION_BYTES_BASE_H7 option_size 0x2c // 44 B flags swo stlink-1.9.0/config/chips/H74x_H75x.chip000066400000000000000000000007511526027543100176220ustar00rootroot00000000000000# Chip-ID file for STM32H74x / STM32H75x device # dev_type STM32H74x_H75x ref_manual_id 0433 chip_id 0x450 // STM32_CHIPID_H74xxx flash_type H7 flash_size_reg 0x1ff1e880 flash_pagesize 0x20000 // 128 KB sram_size 0x20000 // 128 KB "DTCM" bootrom_base 0x1ff00000 bootrom_size 0x20000 // 128 KB option_base 0x52002020 // STM32_OPTION_BYTES_BASE_H7 option_size 0x2c // 44 B /* FLASH_OPTSR_CUR to FLASH_BOOT_PRGR */ flags swo dualbank stlink-1.9.0/config/chips/H7Ax_H7Bx.chip000066400000000000000000000006761526027543100176620ustar00rootroot00000000000000# Chip-ID file for STM32H7Ax / STM32H7Bx device # dev_type STM32H7Ax_H7Bx ref_manual_id 0455 chip_id 0x480 // STM32_CHIPID_H7Ax flash_type H7 flash_size_reg 0x08fff80c flash_pagesize 0x20000 // 128 KB sram_size 0x20000 // 128 KB "DTCM" bootrom_base 0x1ff00000 bootrom_size 0x20000 // 128 KB option_base 0x52002020 // STM32_OPTION_BYTES_BASE_H7 option_size 0x2c // 44 B flags swo dualbank stlink-1.9.0/config/chips/L0xxx_Cat_1.chip000066400000000000000000000007521526027543100203100ustar00rootroot00000000000000# Chip-ID file for STM32L0xxx (Cat.1) device (L010x3 / L010x4 / L011x / L021x) # dev_type STM32L0xxx_Cat_1 ref_manual_id 0451 // also RM0377 chip_id 0x457 // STM32_CHIPID_L0_CAT1 flash_type L0_L1 flash_size_reg 0x1ff8007c flash_pagesize 0x80 // 128 B sram_size 0x2000 // 8 KB bootrom_base 0x1ff00000 bootrom_size 0x2000 // 8 KB option_base 0x1ff80000 // STM32_OPTION_BYTES_BASE_L0 option_size 0x20 // 32 B flags none stlink-1.9.0/config/chips/L0xxx_Cat_2.chip000066400000000000000000000007411526027543100203070ustar00rootroot00000000000000# Chip-ID file for STM32L0xxx (Cat.2) device (L010x6 / L031x / L041x) # dev_type STM32L0xxx_Cat_2 ref_manual_id 0451 // also RM0377 chip_id 0x425 // STM32_CHIPID_L0_CAT2 flash_type L0_L1 flash_size_reg 0x1ff8007c flash_pagesize 0x80 // 128 B sram_size 0x2000 // 8 KB bootrom_base 0x1ff00000 bootrom_size 0x1000 // 4 KB option_base 0x1ff80000 // STM32_OPTION_BYTES_BASE_L0 option_size 0x20 // 32 B flags none stlink-1.9.0/config/chips/L0xxx_Cat_3.chip000066400000000000000000000007621526027543100203130ustar00rootroot00000000000000# Chip-ID file for STM32L0xxx (Cat.3) device (L010x8 / L051x / L053x / L063x) # dev_type STM32L0xxx_Cat_3 ref_manual_id 0451 // also RM0367 & RM0377 chip_id 0x417 // STM32_CHIPID_L0_CAT3 flash_type L0_L1 flash_size_reg 0x1ff8007c flash_pagesize 0x80 // 128 B sram_size 0x2000 // 8 KB bootrom_base 0x1ff00000 bootrom_size 0x1000 // 4 KB option_base 0x1ff80000 // STM32_OPTION_BYTES_BASE_L0 option_size 0x20 // 32 B flags none stlink-1.9.0/config/chips/L0xxx_Cat_5.chip000066400000000000000000000007771526027543100203230ustar00rootroot00000000000000# Chip-ID file for STM32L0xxx (Cat.5) device (L010xB / L071x / L081x / L073x / L083x) # dev_type STM32L0xxx_Cat_5 ref_manual_id 0451 // also RM0367 & RM0377 chip_id 0x447 // STM32_CHIPID_L0_CAT5 flash_type L0_L1 flash_size_reg 0x1ff8007c flash_pagesize 0x80 // 128 B sram_size 0x5000 // 20 KB bootrom_base 0x1ff00000 bootrom_size 0x2000 // 8 KB option_base 0x1ff80000 // STM32_OPTION_BYTES_BASE_L0 option_size 0x20 // 32 B flags dualbank stlink-1.9.0/config/chips/L1xx_Cat_1.chip000066400000000000000000000006061526027543100201170ustar00rootroot00000000000000# Chip-ID file for STM32L1xx (Cat.1) device (L100C6 / L100R8 / L100RB) # dev_type STM32L1xx_Cat_1 ref_manual_id 0038 chip_id 0x416 // STM32_CHIPID_L1_MD flash_type L0_L1 flash_size_reg 0x1ff8004c flash_pagesize 0x100 // 128 B sram_size 0x4000 // 16 KB bootrom_base 0x1ff00000 bootrom_size 0x1000 // 4 KB option_base 0x0 option_size 0x0 flags swo stlink-1.9.0/config/chips/L1xx_Cat_2.chip000066400000000000000000000006161526027543100201210ustar00rootroot00000000000000# Chip-ID file for STM32L1xx (Cat.2) device (L100C6-A / L100R8-A / L100RB-A) # dev_type STM32L1xx_Cat_2 ref_manual_id 0038 chip_id 0x429 // STM32_CHIPID_L1_CAT2 flash_type L0_L1 flash_size_reg 0x1ff8004c flash_pagesize 0x100 // 128 B sram_size 0x8000 // 32 KB bootrom_base 0x1ff00000 bootrom_size 0x1000 // 4 KB option_base 0x0 option_size 0x0 flags swo stlink-1.9.0/config/chips/L1xx_Cat_3.chip000066400000000000000000000006021526027543100201150ustar00rootroot00000000000000# Chip-ID file for STM32L1xx (Cat.3) device (L100RC / L15xxC) # dev_type STM32L1xx_Cat_3 ref_manual_id 0038 chip_id 0x427 // STM32_CHIPID_L1_MD_PLUS flash_type L0_L1 flash_size_reg 0x1ff800cc flash_pagesize 0x100 // 128 B sram_size 0x8000 // 32 KB bootrom_base 0x1ff00000 bootrom_size 0x1000 // 4 KB option_base 0x0 option_size 0x0 flags swo stlink-1.9.0/config/chips/L1xx_Cat_4.chip000066400000000000000000000007041526027543100201210ustar00rootroot00000000000000# Chip-ID file for STM32L1xx (Cat.4) device (L15xxD / L162xD) # dev_type STM32L1xx_Cat_4 ref_manual_id 0038 chip_id 0x436 // STM32_CHIPID_L1_MD_PLUS_HD flash_type L0_L1 flash_size_reg 0x1ff800cc flash_pagesize 0x100 // 128 B sram_size 0xc000 // 48 KB bootrom_base 0x1ff00000 bootrom_size 0x1000 // 4 KB option_base 0x1ff80000 // STM32_OPTION_BYTES_BASE_L1 option_size 0x8 // 8 B flags swo stlink-1.9.0/config/chips/L1xx_Cat_5.chip000066400000000000000000000005771526027543100201320ustar00rootroot00000000000000# Chip-ID file for STM32L1xx (Cat.5) device (L15xxE / L162xE) # dev_type STM32L1xx_Cat_5 ref_manual_id 0038 chip_id 0x437 // STM32_CHIPID_L152_RE flash_type L0_L1 flash_size_reg 0x1ff800cc flash_pagesize 0x100 // 128 B sram_size 0x14000 // 80 KB bootrom_base 0x1ff00000 bootrom_size 0x1000 // 4 KB option_base 0x0 option_size 0x0 flags swo stlink-1.9.0/config/chips/L41x_L42x.chip000066400000000000000000000006561526027543100176220ustar00rootroot00000000000000# Chip-ID file for STM32L41x / STM32L42x device # dev_type STM32L41x_L42x ref_manual_id 0394 chip_id 0x464 // STM32_CHIPID_L41x_L42x flash_type L4 flash_size_reg 0x1fff75e0 flash_pagesize 0x800 // 2 KB sram_size 0xa000 // 40 KB bootrom_base 0x1fff0000 bootrom_size 0x7000 // 28 KB option_base 0x1fff7800 // STM32_OPTION_BYTES_BASE_L4 option_size 0x4 // 4 B flags swo stlink-1.9.0/config/chips/L43x_L44x.chip000066400000000000000000000006561526027543100176260ustar00rootroot00000000000000# Chip-ID file for STM32L43x / STM32L44x device # dev_type STM32L41x_L42x ref_manual_id 0392 chip_id 0x435 // STM32_CHIPID_L43x_L44x flash_type L4 flash_size_reg 0x1fff75e0 flash_pagesize 0x800 // 2 KB sram_size 0xc000 // 48 KB bootrom_base 0x1fff0000 bootrom_size 0x7000 // 28 KB option_base 0x1fff7800 // STM32_OPTION_BYTES_BASE_L4 option_size 0x4 // 4 B flags swo stlink-1.9.0/config/chips/L45x_L46x.chip000066400000000000000000000006511526027543100176250ustar00rootroot00000000000000# Chip-ID file for STM32L45x / STM32L46x device # dev_type STM32L45x_L46x ref_manual_id 0394 chip_id 0x462 // STM32_CHIPID_L45x_L46x flash_type L4 flash_size_reg 0x1fff75e0 flash_pagesize 0x800 // 2 KB sram_size 0x20000 // 128 KB bootrom_base 0x1fff0000 bootrom_size 0x7000 // 28 KB option_base 0x0 option_size 0x0 flags swo otp_base 0x1fff7000 otp_size 0x400 // 1 KB stlink-1.9.0/config/chips/L47x_L48x.chip000066400000000000000000000006471526027543100176360ustar00rootroot00000000000000# Chip-ID file for STM32L47x / STM32L48x device # dev_type STM32L47x_L48x ref_manual_id 0351 chip_id 0x415 // STM32_CHIPID_L4 flash_type L4 flash_size_reg 0x1fff75e0 flash_pagesize 0x800 // 2 KB sram_size 0x18000 // 96 KB bootrom_base 0x1fff0000 bootrom_size 0x7000 // 28 KB option_base 0x1fff7800 // STM32_OPTION_BYTES_BASE_L4 option_size 0x4 // 4 B flags swo stlink-1.9.0/config/chips/L496x_L4A6x.chip000066400000000000000000000007501526027543100200200ustar00rootroot00000000000000# Chip-ID file for STM32L496x / STM32L4A6x device # dev_type STM32L496x_L4A6x ref_manual_id 0351 chip_id 0x461 // STM32_CHIPID_L496x_L4A6x flash_type L4 flash_size_reg 0x1fff75e0 flash_pagesize 0x800 // 2 KB sram_size 0x50000 // 320 KB bootrom_base 0x1fff0000 bootrom_size 0x7000 // 28 KB option_base 0x1fff7800 // STM32_OPTION_BYTES_BASE_L4 option_size 0x4 // 4 B flags swo otp_base 0x1fff7000 otp_size 0x400 // 1 KB stlink-1.9.0/config/chips/L4Px_L4Qx.chip000066400000000000000000000006061526027543100177130ustar00rootroot00000000000000# Chip-ID file for STM32L4Px / STM32L4Qx device # dev_type STM32L4Px_L4Qx ref_manual_id 0432 chip_id 0x471 // STM32_CHIPID_L4PX flash_type L4 flash_size_reg 0x1fff75e0 flash_pagesize 0x1000 // 4 KB sram_size 0x50000 // 320 KB bootrom_base 0x1fff0000 bootrom_size 0x7000 // 28 KB option_base 0x1ff00000 option_size 0x4 // 4 B flags swo stlink-1.9.0/config/chips/L4Rx.chip000066400000000000000000000005651526027543100170510ustar00rootroot00000000000000# Chip-ID file for STM32L4Rx device # dev_type STM32L4Rx ref_manual_id 0432 chip_id 0x470 // STM32_CHIPID_L4RX flash_type L4 flash_size_reg 0x1fff75e0 flash_pagesize 0x1000 // 4 KB sram_size 0xa0000 // 640 KB bootrom_base 0x1fff0000 bootrom_size 0x7000 // 28 KB option_base 0x1ff00000 option_size 0x4 // 4 B flags swo stlink-1.9.0/config/chips/L5x2xx.chip000066400000000000000000000005501526027543100173640ustar00rootroot00000000000000# Chip-ID file for STM32L5x2xx device # dev_type STM32L5x2xx ref_manual_id 0438 chip_id 0x472 // STM32_CHIPID_L5x2xx flash_type L5_U5 flash_size_reg 0x0bfa05e0 flash_pagesize 0x1000 // 4 KB sram_size 0x40000 // 256 KB bootrom_base 0x0bf90000 bootrom_size 0x8000 // 32 KB option_base 0x0 option_size 0x0 flags dualbank stlink-1.9.0/config/chips/U031xx.chip000066400000000000000000000006361526027543100172670ustar00rootroot00000000000000# Chip-ID file for STM32U031xx device # dev_type STM32U031xx ref_manual_id 0503 chip_id 0x459 // STM32_CHIPID_U031xx flash_type C0 flash_size_reg 0x1fff3ea0 flash_pagesize 0x800 // 2 KB sram_size 0x3000 // 12 KB bootrom_base 0x1fff0000 bootrom_size 0x1400 // 5 KB option_base 0x1fff7000 // STM32_U0_OPTION_BYTES_BASE option_size 0x1000 // 4 KB flags swo stlink-1.9.0/config/chips/U073xx_083xx.chip000066400000000000000000000006721526027543100202470ustar00rootroot00000000000000# Chip-ID file for STM32U073xx / STM32U083xx device # dev_type STM32U073xx_U083xx ref_manual_id 0503 chip_id 0x489 // STM32_CHIPID_U073xx_U083xx flash_type C0 flash_size_reg 0x1fff6ea0 flash_pagesize 0x800 // 2 KB sram_size 0xa000 // 40 KB bootrom_base 0x1fff0000 bootrom_size 0x1400 // 5 KB option_base 0x1fff7000 // STM32_U0_OPTION_BYTES_BASE option_size 0x1000 // 4 KB flags swo stlink-1.9.0/config/chips/U535_U545.chip000066400000000000000000000005731526027543100174420ustar00rootroot00000000000000# Chip-ID file for STM32U535 / STM32U545 device # dev_type STM32U535_U545 ref_manual_id 0456 chip_id 0x455 // STM32_CHIPID_U535_545 flash_type L5_U5 flash_size_reg 0x0bfa07a0 flash_pagesize 0x2000 // 8 KB sram_size 0x44800 // 274 KB bootrom_base 0x0bf90000 bootrom_size 0x8000 // 32 KB option_base 0x0 option_size 0x0 flags swo dualbank stlink-1.9.0/config/chips/U575_U585.chip000066400000000000000000000006401526027543100174450ustar00rootroot00000000000000# Chip-ID file for STM32U575 / STM32U585 device # dev_type STM32U575_U585 ref_manual_id 0456 chip_id 0x482 // STM32_CHIPID_U575_U585 flash_type L5_U5 flash_size_reg 0x0bfa07a0 flash_pagesize 0x2000 // 8 KB sram_size 0xc4800 // 786 KB bootrom_base 0x0bf90000 bootrom_size 0x10000 // 64 KB option_base 0x0 option_size 0x0 flags swo dualbank otp_base 0x0bfa0000 otp_size 0x200 stlink-1.9.0/config/chips/U59x_U5Ax.chip000066400000000000000000000006041526027543100176660ustar00rootroot00000000000000# Chip-ID file for STM32U59x / STM32U5Ax device # dev_type STM32U59x_U5Ax ref_manual_id 0456 chip_id 0x481 // STM32_CHIPID_U59x_5Ax flash_type L5_U5 flash_size_reg 0x0bfa07a0 flash_pagesize 0x2000 // 8 KB sram_size 0x274800 // 2514 KB bootrom_base 0x0bf90000 bootrom_size 0x8000 // 32 KB option_base 0x40022040 option_size 0x04 flags swo dualbank stlink-1.9.0/config/chips/U5Fx_U5Gx.chip000066400000000000000000000005751526027543100177200ustar00rootroot00000000000000# Chip-ID file for STM32U5Fx / STM32U5Gx device # dev_type STM32U5Fx_U5Gx ref_manual_id 0456 chip_id 0x476 // STM32_CHIPID_U5Fx5_5Gx flash_type L5_U5 flash_size_reg 0x0bfa07a0 flash_pagesize 0x2000 // 8 KB sram_size 0x2f4800 // 3026 KB bootrom_base 0x0bf90000 bootrom_size 0x8000 // 32 KB option_base 0x0 option_size 0x0 flags swo dualbank stlink-1.9.0/config/chips/WB05.chip000066400000000000000000000007371526027543100167360ustar00rootroot00000000000000# Chip-ID file for STM32WB05 (formerly BlueNRG-LPS) device # dev_type STM32WB05 ref_manual_id 0491 chip_id 0x028 // STM32_CHIPID_WB05 flash_type WB0 flash_size_reg 0x40001014 flash_pagesize 0x800 // 2 KB sram_size 0x6000 // 24 KB (no variants) bootrom_base 0x0 bootrom_size 0x4000 // 16 KB option_base 0x0 // protection via FLASH controller commands option_size 0x0 otp_base 0x10001800 otp_size 0x400 // 1 KBstlink-1.9.0/config/chips/WB06_WB07.chip000066400000000000000000000007771526027543100175020ustar00rootroot00000000000000# Chip-ID file for STM32WB06 / STM32WB07 (formerly BlueNRG-LP) device # dev_type STM32WB06_WB07 ref_manual_id 0530 // also RM0479 chip_id 0x01e // STM32_CHIPID_WB06_WB07 flash_type WB0 flash_size_reg 0x40001014 flash_pagesize 0x800 // 2 KB sram_size 0x10000 // 64 KB bootrom_base 0x0 bootrom_size 0x4000 // 16 KB option_base 0x0 // protection via FLASH controller commands option_size 0x0 otp_base 0x10001800 otp_size 0x400 // 1 KBstlink-1.9.0/config/chips/WB09.chip000066400000000000000000000006771526027543100167450ustar00rootroot00000000000000# Chip-ID file for STM32WB09 device # dev_type STM32WB06_WB07 ref_manual_id 0505 chip_id 0x032 // STM32_CHIPID_WB09 flash_type WB0 flash_size_reg 0x40001014 flash_pagesize 0x800 // 2 KB sram_size 0x10000 // 64 KB bootrom_base 0x0 bootrom_size 0x4000 // 16 KB option_base 0x0 // protection via FLASH controller commands option_size 0x0 otp_base 0x10001800 otp_size 0x400 // 1 KBstlink-1.9.0/config/chips/WBx0_WBx5.chip000066400000000000000000000006441526027543100177030ustar00rootroot00000000000000# Chip-ID file for STM32WBx0 / STM32WBx5 device # dev_type STM32WBx0_WBx5 ref_manual_id 0434 // also RM0471 chip_id 0x495 // STM32_CHIPID_WB55 flash_type WB_WL flash_size_reg 0x1fff75e0 flash_pagesize 0x1000 // 4 KB sram_size 0x40000 // 256 KB bootrom_base 0x1fff0000 bootrom_size 0x7000 // 28 KB option_base 0x1fff8000 option_size 0x80 // 128 B flags swo stlink-1.9.0/config/chips/WL3x.chip000066400000000000000000000006651526027543100170560ustar00rootroot00000000000000# Chip-ID file for STM32WL3x device # dev_type WL3x ref_manual_id 0491 chip_id 0x027 // STM32_CHIPID_WL3x flash_type WB0 flash_size_reg 0x40001014 flash_pagesize 0x800 // 2 KB sram_size 0x8000 // 32 KB bootrom_base 0x0 bootrom_size 0x4000 // 16 KB option_base 0x0 // protection via FLASH controller commands option_size 0x0 otp_base 0x10001800 otp_size 0x400 // 1 KBstlink-1.9.0/config/chips/WLEx.chip000066400000000000000000000006001526027543100170650ustar00rootroot00000000000000# Chip-ID file for STM32WLEx device # dev_type STM32WLEx ref_manual_id 0033 chip_id 0x497 // STM32_CHIPID_WLE flash_type WB_WL flash_size_reg 0x1fff75e0 flash_pagesize 0x800 // 2 KB sram_size 0x10000 // 64 KB bootrom_base 0x1fff0000 bootrom_size 0x7000 // 28 KB option_base 0x1fff7800 option_size 0x10 // 16 B flags swo dualbank stlink-1.9.0/config/chips/unknown_device.chip000066400000000000000000000004211526027543100212650ustar00rootroot00000000000000# Chip-ID file for unknown device # dev_type unknown ref_manual_id 0000 chip_id 0x0 // STM32_CHIPID_UNKNOWN flash_type UNKNOWN flash_size_reg 0x0 flash_pagesize 0x0 sram_size 0x0 bootrom_base 0x0 bootrom_size 0x0 option_base 0x0 option_size 0x0 flags none stlink-1.9.0/config/code_style.cfg000066400000000000000000003610131526027543100171160ustar00rootroot00000000000000# Uncrustify-0.71.0 # # General options # # The type of line endings. # # Default: auto newlines = auto # lf/crlf/cr/auto # The original size of tabs in the input. # # Default: 8 input_tab_size = 4 # unsigned number # The size of tabs in the output (only used if align_with_tabs=true). # # Default: 8 output_tab_size = 4 # unsigned number # The ASCII value of the string escape char, usually 92 (\) or (Pawn) 94 (^). # # Default: 92 string_escape_char = 92 # unsigned number # Alternate string escape char (usually only used for Pawn). # Only works right before the quote char. string_escape_char2 = 0 # unsigned number # Replace tab characters found in string literals with the escape sequence \t # instead. string_replace_tab_chars = false # true/false # Allow interpreting '>=' and '>>=' as part of a template in code like # 'void f(list>=val);'. If true, 'assert(x<0 && y>=3)' will be broken. # Improvements to template detection may make this option obsolete. tok_split_gte = false # true/false # Disable formatting of NL_CONT ('\\n') ended lines (e.g. multiline macros) #disable_processing_nl_cont = false # true/false ### not 0.69 # Specify the marker used in comments to disable processing of part of the # file. # The comment should be used alone in one line. # # Default: *INDENT-OFF* disable_processing_cmt = " *INDENT-OFF*" # string # Specify the marker used in comments to (re)enable processing in a file. # The comment should be used alone in one line. # # Default: *INDENT-ON* enable_processing_cmt = " *INDENT-ON*" # string # Enable parsing of digraphs. enable_digraphs = false # true/false # Add or remove the UTF-8 BOM (recommend 'remove'). utf8_bom = ignore # ignore/add/remove/force # If the file contains bytes with values between 128 and 255, but is not # UTF-8, then output as UTF-8. utf8_byte = false # true/false # Force the output encoding to UTF-8. utf8_force = true # true/false # Add or remove space between 'do' and '{'. #sp_do_brace_open = add # ignore/add/remove/force ### not 0.69 # Add or remove space between '}' and 'while'. #sp_brace_close_while = add # ignore/add/remove/force ### not 0.69 # Add or remove space between 'while' and '('. #sp_while_paren_open = add # ignore/add/remove/force ### not 0.69 # # Spacing options # # Add or remove space around non-assignment symbolic operators ('+', '/', '%', # '<<', and so forth). sp_arith = add # ignore/add/remove/force # Add or remove space around arithmetic operators '+' and '-'. # # Overrides sp_arith. sp_arith_additive = add # ignore/add/remove/force # Add or remove space around assignment operator '=', '+=', etc. sp_assign = add # ignore/add/remove/force # Add or remove space around '=' in C++11 lambda capture specifications. # # Overrides sp_assign. sp_cpp_lambda_assign = add # ignore/add/remove/force # Add or remove space after the capture specification of a C++11 lambda when # an argument list is present, as in '[] (int x){ ... }'. #sp_cpp_lambda_square_paren = add # ignore/add/remove/force ### not 0.69 # Add or remove space after the capture specification of a C++11 lambda with # no argument list is present, as in '[] { ... }'. #sp_cpp_lambda_square_brace = add # ignore/add/remove/force ### not 0.69 # Add or remove space after the argument list of a C++11 lambda, as in # '[](int x) { ... }'. #sp_cpp_lambda_paren_brace = add # ignore/add/remove/force ### not 0.69 # Add or remove space between a lambda body and its call operator of an # immediately invoked lambda, as in '[]( ... ){ ... } ( ... )'. #sp_cpp_lambda_fparen = add # ignore/add/remove/force ### not 0.69 # Add or remove space around assignment operator '=' in a prototype. # # If set to ignore, use sp_assign. sp_assign_default = add # ignore/add/remove/force # Add or remove space before assignment operator '=', '+=', etc. # # Overrides sp_assign. sp_before_assign = add # ignore/add/remove/force # Add or remove space after assignment operator '=', '+=', etc. # # Overrides sp_assign. sp_after_assign = add # ignore/add/remove/force # Add or remove space in 'NS_ENUM ('. sp_enum_paren = add # ignore/add/remove/force # Add or remove space around assignment '=' in enum. sp_enum_assign = add # ignore/add/remove/force # Add or remove space before assignment '=' in enum. # # Overrides sp_enum_assign. sp_enum_before_assign = add # ignore/add/remove/force # Add or remove space after assignment '=' in enum. # # Overrides sp_enum_assign. sp_enum_after_assign = add # ignore/add/remove/force # Add or remove space around assignment ':' in enum. sp_enum_colon = add # ignore/add/remove/force # Add or remove space around preprocessor '##' concatenation operator. # # Default: add sp_pp_concat = add # ignore/add/remove/force # Add or remove space after preprocessor '#' stringify operator. # Also affects the '#@' charizing operator. sp_pp_stringify = ignore # ignore/add/remove/force # Add or remove space before preprocessor '#' stringify operator # as in '#define x(y) L#y'. sp_before_pp_stringify = ignore # ignore/add/remove/force # Add or remove space around boolean operators '&&' and '||'. sp_bool = add # ignore/add/remove/force # Add or remove space around compare operator '<', '>', '==', etc. sp_compare = add # ignore/add/remove/force # Add or remove space inside '(' and ')'. sp_inside_paren = remove # ignore/add/remove/force # Add or remove space between nested parentheses, i.e. '((' vs. ') )'. sp_paren_paren = remove # ignore/add/remove/force # Add or remove space between back-to-back parentheses, i.e. ')(' vs. ') ('. sp_cparen_oparen = add # ignore/add/remove/force # Whether to balance spaces inside nested parentheses. sp_balance_nested_parens = false # true/false # Add or remove space between ')' and '{'. sp_paren_brace = add # ignore/add/remove/force # Add or remove space between nested braces, i.e. '{{' vs '{ {'. sp_brace_brace = remove # ignore/add/remove/force # Add or remove space before pointer star '*'. sp_before_ptr_star = ignore # ignore/add/remove/force # Add or remove space before pointer star '*' that isn't followed by a # variable name. If set to ignore, sp_before_ptr_star is used instead. sp_before_unnamed_ptr_star = ignore # ignore/add/remove/force # Add or remove space between pointer stars '*'. sp_between_ptr_star = ignore # ignore/add/remove/force # Add or remove space after pointer star '*', if followed by a word. # # Overrides sp_type_func. sp_after_ptr_star = ignore # ignore/add/remove/force # Add or remove space after pointer caret '^', if followed by a word. sp_after_ptr_block_caret = ignore # ignore/add/remove/force # Add or remove space after pointer star '*', if followed by a qualifier. sp_after_ptr_star_qualifier = ignore # ignore/add/remove/force # Add or remove space after a pointer star '*', if followed by a function # prototype or function definition. # # Overrides sp_after_ptr_star and sp_type_func. sp_after_ptr_star_func = ignore # ignore/add/remove/force # Add or remove space after a pointer star '*', if followed by an open # parenthesis, as in 'void* (*)(). sp_ptr_star_paren = ignore # ignore/add/remove/force # Add or remove space before a pointer star '*', if followed by a function # prototype or function definition. sp_before_ptr_star_func = ignore # ignore/add/remove/force # Add or remove space before a reference sign '&'. sp_before_byref = ignore # ignore/add/remove/force # Add or remove space before a reference sign '&' that isn't followed by a # variable name. If set to ignore, sp_before_byref is used instead. sp_before_unnamed_byref = ignore # ignore/add/remove/force # Add or remove space after reference sign '&', if followed by a word. # # Overrides sp_type_func. sp_after_byref = ignore # ignore/add/remove/force # Add or remove space after a reference sign '&', if followed by a function # prototype or function definition. # # Overrides sp_after_byref and sp_type_func. sp_after_byref_func = ignore # ignore/add/remove/force # Add or remove space before a reference sign '&', if followed by a function # prototype or function definition. sp_before_byref_func = ignore # ignore/add/remove/force # Add or remove space between type and word. # # Default: force sp_after_type = force # ignore/add/remove/force # Add or remove space between 'decltype(...)' and word. sp_after_decltype = ignore # ignore/add/remove/force # (D) Add or remove space before the parenthesis in the D constructs # 'template Foo(' and 'class Foo('. sp_before_template_paren = ignore # ignore/add/remove/force # Add or remove space between 'template' and '<'. # If set to ignore, sp_before_angle is used. sp_template_angle = ignore # ignore/add/remove/force # Add or remove space before '<'. sp_before_angle = ignore # ignore/add/remove/force # Add or remove space inside '<' and '>'. sp_inside_angle = ignore # ignore/add/remove/force # Add or remove space inside '<>'. sp_inside_angle_empty = add # ignore/add/remove/force # Add or remove space between '>' and ':'. sp_angle_colon = ignore # ignore/add/remove/force # Add or remove space after '>'. sp_after_angle = ignore # ignore/add/remove/force # Add or remove space between '>' and '(' as found in 'new List(foo);'. sp_angle_paren = remove # ignore/add/remove/force # Add or remove space between '>' and '()' as found in 'new List();'. sp_angle_paren_empty = remove # ignore/add/remove/force # Add or remove space between '>' and a word as in 'List m;' or # 'template static ...'. sp_angle_word = add # ignore/add/remove/force # Add or remove space between '>' and '>' in '>>' (template stuff). # # Default: add sp_angle_shift = add # ignore/add/remove/force # (C++11) Permit removal of the space between '>>' in 'foo >'. Note # that sp_angle_shift cannot remove the space without this option. sp_permit_cpp11_shift = false # true/false # Add or remove space before '(' of control statements ('if', 'for', 'switch', # 'while', etc.). sp_before_sparen = add # ignore/add/remove/force # Add or remove space inside '(' and ')' of control statements. sp_inside_sparen = ignore # ignore/add/remove/force # Add or remove space after '(' of control statements. # # Overrides sp_inside_sparen. sp_inside_sparen_open = ignore # ignore/add/remove/force # Add or remove space before ')' of control statements. # # Overrides sp_inside_sparen. sp_inside_sparen_close = ignore # ignore/add/remove/force # Add or remove space after ')' of control statements. sp_after_sparen = ignore # ignore/add/remove/force # Add or remove space between ')' and '{' of of control statements. sp_sparen_brace = add # ignore/add/remove/force # (D) Add or remove space between 'invariant' and '('. sp_invariant_paren = ignore # ignore/add/remove/force # (D) Add or remove space after the ')' in 'invariant (C) c'. sp_after_invariant_paren = ignore # ignore/add/remove/force # Add or remove space before empty statement ';' on 'if', 'for' and 'while'. sp_special_semi = add # ignore/add/remove/force # Add or remove space before ';'. # # Default: remove sp_before_semi = remove # ignore/add/remove/force # Add or remove space before ';' in non-empty 'for' statements. sp_before_semi_for = remove # ignore/add/remove/force # Add or remove space before a semicolon of an empty part of a for statement. sp_before_semi_for_empty = add # ignore/add/remove/force # Add or remove space after ';', except when followed by a comment. # # Default: add sp_after_semi = add # ignore/add/remove/force # Add or remove space after ';' in non-empty 'for' statements. # # Default: force sp_after_semi_for = force # ignore/add/remove/force # Add or remove space after the final semicolon of an empty part of a for # statement, as in 'for ( ; ; )'. sp_after_semi_for_empty = ignore # ignore/add/remove/force # Add or remove space before '[' (except '[]'). sp_before_square = ignore # ignore/add/remove/force # Add or remove space before '[' for a variable definition. # # Default: remove #sp_before_vardef_square = remove # ignore/add/remove/force ### not 0.69 # Add or remove space before '[' for asm block. #sp_before_square_asm_block = ignore # ignore/add/remove/force ### not 0.69 # Add or remove space before '[]'. sp_before_squares = ignore # ignore/add/remove/force # Add or remove space before C++17 structured bindings. sp_cpp_before_struct_binding = ignore # ignore/add/remove/force # Add or remove space inside a non-empty '[' and ']'. sp_inside_square = ignore # ignore/add/remove/force # (OC) Add or remove space inside a non-empty Objective-C boxed array '@[' and # ']'. If set to ignore, sp_inside_square is used. sp_inside_square_oc_array = ignore # ignore/add/remove/force # Add or remove space after ',', i.e. 'a,b' vs. 'a, b'. sp_after_comma = add # ignore/add/remove/force # Add or remove space before ','. # # Default: remove sp_before_comma = remove # ignore/add/remove/force # (C#) Add or remove space between ',' and ']' in multidimensional array type # like 'int[,,]'. sp_after_mdatype_commas = ignore # ignore/add/remove/force # (C#) Add or remove space between '[' and ',' in multidimensional array type # like 'int[,,]'. sp_before_mdatype_commas = ignore # ignore/add/remove/force # (C#) Add or remove space between ',' in multidimensional array type # like 'int[,,]'. sp_between_mdatype_commas = ignore # ignore/add/remove/force # Add or remove space between an open parenthesis and comma, # i.e. '(,' vs. '( ,'. # # Default: force sp_paren_comma = force # ignore/add/remove/force # Add or remove space before the variadic '...' when preceded by a # non-punctuator. sp_before_ellipsis = ignore # ignore/add/remove/force # Add or remove space between a type and '...'. sp_type_ellipsis = ignore # ignore/add/remove/force # (D) Add or remove space between a type and '?'. sp_type_question = ignore # ignore/add/remove/force # Add or remove space between ')' and '...'. sp_paren_ellipsis = ignore # ignore/add/remove/force # Add or remove space between ')' and a qualifier such as 'const'. sp_paren_qualifier = ignore # ignore/add/remove/force # Add or remove space between ')' and 'noexcept'. sp_paren_noexcept = ignore # ignore/add/remove/force # Add or remove space after class ':'. sp_after_class_colon = ignore # ignore/add/remove/force # Add or remove space before class ':'. sp_before_class_colon = ignore # ignore/add/remove/force # Add or remove space after class constructor ':'. sp_after_constr_colon = ignore # ignore/add/remove/force # Add or remove space before class constructor ':'. sp_before_constr_colon = ignore # ignore/add/remove/force # Add or remove space before case ':'. # # Default: remove sp_before_case_colon = remove # ignore/add/remove/force # Add or remove space between 'operator' and operator sign. sp_after_operator = ignore # ignore/add/remove/force # Add or remove space between the operator symbol and the open parenthesis, as # in 'operator ++('. sp_after_operator_sym = ignore # ignore/add/remove/force # Overrides sp_after_operator_sym when the operator has no arguments, as in # 'operator *()'. sp_after_operator_sym_empty = ignore # ignore/add/remove/force # Add or remove space after C/D cast, i.e. 'cast(int)a' vs. 'cast(int) a' or # '(int)a' vs. '(int) a'. sp_after_cast = remove # ignore/add/remove/force # Add or remove spaces inside cast parentheses. sp_inside_paren_cast = ignore # ignore/add/remove/force # Add or remove space between the type and open parenthesis in a C++ cast, # i.e. 'int(exp)' vs. 'int (exp)'. sp_cpp_cast_paren = remove # ignore/add/remove/force # Add or remove space between 'sizeof' and '('. sp_sizeof_paren = remove # ignore/add/remove/force # Add or remove space between 'sizeof' and '...'. sp_sizeof_ellipsis = add # ignore/add/remove/force # Add or remove space between 'sizeof...' and '('. sp_sizeof_ellipsis_paren = add # ignore/add/remove/force # Add or remove space between 'decltype' and '('. sp_decltype_paren = ignore # ignore/add/remove/force # (Pawn) Add or remove space after the tag keyword. sp_after_tag = ignore # ignore/add/remove/force # Add or remove space inside enum '{' and '}'. sp_inside_braces_enum = ignore # ignore/add/remove/force # Add or remove space inside struct/union '{' and '}'. sp_inside_braces_struct = ignore # ignore/add/remove/force # (OC) Add or remove space inside Objective-C boxed dictionary '{' and '}' sp_inside_braces_oc_dict = ignore # ignore/add/remove/force # Add or remove space after open brace in an unnamed temporary # direct-list-initialization. sp_after_type_brace_init_lst_open = ignore # ignore/add/remove/force # Add or remove space before close brace in an unnamed temporary # direct-list-initialization. sp_before_type_brace_init_lst_close = ignore # ignore/add/remove/force # Add or remove space inside an unnamed temporary direct-list-initialization. sp_inside_type_brace_init_lst = ignore # ignore/add/remove/force # Add or remove space inside '{' and '}'. sp_inside_braces = ignore # ignore/add/remove/force # Add or remove space inside '{}'. sp_inside_braces_empty = ignore # ignore/add/remove/force # Add or remove space around trailing return operator '->'. #sp_trailing_return = ignore # ignore/add/remove/force ### not 0.69 # Add or remove space between return type and function name. A minimum of 1 # is forced except for pointer return types. sp_type_func = ignore # ignore/add/remove/force # Add or remove space between type and open brace of an unnamed temporary # direct-list-initialization. sp_type_brace_init_lst = ignore # ignore/add/remove/force # Add or remove space between function name and '(' on function declaration. sp_func_proto_paren = remove # ignore/add/remove/force # Add or remove space between function name and '()' on function declaration # without parameters. sp_func_proto_paren_empty = remove # ignore/add/remove/force # Add or remove space between function name and '(' with a typedef specifier. #sp_func_type_paren = ignore # ignore/add/remove/force ### not 0.69 # Add or remove space between alias name and '(' of a non-pointer function type typedef. sp_func_def_paren = ignore # ignore/add/remove/force # Add or remove space between function name and '()' on function definition # without parameters. sp_func_def_paren_empty = remove # ignore/add/remove/force # Add or remove space inside empty function '()'. # Overrides sp_after_angle unless use_sp_after_angle_always is set to true. sp_inside_fparens = ignore # ignore/add/remove/force # Add or remove space inside function '(' and ')'. sp_inside_fparen = ignore # ignore/add/remove/force # Add or remove space inside the first parentheses in a function type, as in # 'void (*x)(...)'. sp_inside_tparen = ignore # ignore/add/remove/force # Add or remove space between the ')' and '(' in a function type, as in # 'void (*x)(...)'. sp_after_tparen_close = ignore # ignore/add/remove/force # Add or remove space between ']' and '(' when part of a function call. sp_square_fparen = add # ignore/add/remove/force # Add or remove space between ')' and '{' of function. sp_fparen_brace = add # ignore/add/remove/force # Add or remove space between ')' and '{' of s function call in object # initialization. # # Overrides sp_fparen_brace. sp_fparen_brace_initializer = ignore # ignore/add/remove/force # (Java) Add or remove space between ')' and '{{' of double brace initializer. sp_fparen_dbrace = ignore # ignore/add/remove/force # Add or remove space between function name and '(' on function calls. sp_func_call_paren = ignore # ignore/add/remove/force # Add or remove space between function name and '()' on function calls without # parameters. If set to ignore (the default), sp_func_call_paren is used. sp_func_call_paren_empty = ignore # ignore/add/remove/force # Add or remove space between the user function name and '(' on function # calls. You need to set a keyword to be a user function in the config file, # like: # set func_call_user tr _ i18n sp_func_call_user_paren = ignore # ignore/add/remove/force # Add or remove space inside user function '(' and ')'. sp_func_call_user_inside_fparen = ignore # ignore/add/remove/force # Add or remove space between nested parentheses with user functions, # i.e. '((' vs. '( ('. sp_func_call_user_paren_paren = ignore # ignore/add/remove/force # Add or remove space between a constructor/destructor and the open # parenthesis. sp_func_class_paren = ignore # ignore/add/remove/force # Add or remove space between a constructor without parameters or destructor # and '()'. sp_func_class_paren_empty = ignore # ignore/add/remove/force # Add or remove space between 'return' and '('. sp_return_paren = ignore # ignore/add/remove/force # Add or remove space between 'return' and '{'. sp_return_brace = ignore # ignore/add/remove/force # Add or remove space between '__attribute__' and '('. sp_attribute_paren = ignore # ignore/add/remove/force # Add or remove space between 'defined' and '(' in '#if defined (FOO)'. sp_defined_paren = ignore # ignore/add/remove/force # Add or remove space between 'throw' and '(' in 'throw (something)'. sp_throw_paren = ignore # ignore/add/remove/force # Add or remove space between 'throw' and anything other than '(' as in # '@throw [...];'. sp_after_throw = ignore # ignore/add/remove/force # Add or remove space between 'catch' and '(' in 'catch (something) { }'. # If set to ignore, sp_before_sparen is used. sp_catch_paren = ignore # ignore/add/remove/force # (OC) Add or remove space between '@catch' and '(' # in '@catch (something) { }'. If set to ignore, sp_catch_paren is used. sp_oc_catch_paren = ignore # ignore/add/remove/force # (OC) Add or remove space before Objective-C protocol list # as in '@protocol Protocol' or '@interface MyClass : NSObject'. #sp_before_oc_proto_list = ignore # ignore/add/remove/force ### not 0.69 # (OC) Add or remove space between class name and '(' # in '@interface className(categoryName):BaseClass' sp_oc_classname_paren = ignore # ignore/add/remove/force # (D) Add or remove space between 'version' and '(' # in 'version (something) { }'. If set to ignore, sp_before_sparen is used. sp_version_paren = ignore # ignore/add/remove/force # (D) Add or remove space between 'scope' and '(' # in 'scope (something) { }'. If set to ignore, sp_before_sparen is used. sp_scope_paren = ignore # ignore/add/remove/force # Add or remove space between 'super' and '(' in 'super (something)'. # # Default: remove sp_super_paren = remove # ignore/add/remove/force # Add or remove space between 'this' and '(' in 'this (something)'. # # Default: remove sp_this_paren = remove # ignore/add/remove/force # Add or remove space between a macro name and its definition. sp_macro = ignore # ignore/add/remove/force # Add or remove space between a macro function ')' and its definition. sp_macro_func = ignore # ignore/add/remove/force # Add or remove space between 'else' and '{' if on the same line. sp_else_brace = add # ignore/add/remove/force # Add or remove space between '}' and 'else' if on the same line. sp_brace_else = add # ignore/add/remove/force # Add or remove space between '}' and the name of a typedef on the same line. sp_brace_typedef = add # ignore/add/remove/force # Add or remove space before the '{' of a 'catch' statement, if the '{' and # 'catch' are on the same line, as in 'catch (decl) {'. sp_catch_brace = add # ignore/add/remove/force # (OC) Add or remove space before the '{' of a '@catch' statement, if the '{' # and '@catch' are on the same line, as in '@catch (decl) {'. # If set to ignore, sp_catch_brace is used. sp_oc_catch_brace = ignore # ignore/add/remove/force # Add or remove space between '}' and 'catch' if on the same line. sp_brace_catch = add # ignore/add/remove/force # (OC) Add or remove space between '}' and '@catch' if on the same line. # If set to ignore, sp_brace_catch is used. sp_oc_brace_catch = ignore # ignore/add/remove/force # Add or remove space between 'finally' and '{' if on the same line. sp_finally_brace = add # ignore/add/remove/force # Add or remove space between '}' and 'finally' if on the same line. sp_brace_finally = add # ignore/add/remove/force # Add or remove space between 'try' and '{' if on the same line. sp_try_brace = add # ignore/add/remove/force # Add or remove space between get/set and '{' if on the same line. sp_getset_brace = add # ignore/add/remove/force # Add or remove space between a variable and '{' for C++ uniform # initialization. #sp_word_brace_init_lst = add # ignore/add/remove/force ### not 0.69 # Add or remove space between a variable and '{' for a namespace. # # Default: add sp_word_brace_ns = add # ignore/add/remove/force # Add or remove space before the '::' operator. sp_before_dc = ignore # ignore/add/remove/force # Add or remove space after the '::' operator. sp_after_dc = ignore # ignore/add/remove/force # (D) Add or remove around the D named array initializer ':' operator. sp_d_array_colon = ignore # ignore/add/remove/force # Add or remove space after the '!' (not) unary operator. # # Default: remove sp_not = remove # ignore/add/remove/force # Add or remove space after the '~' (invert) unary operator. # # Default: remove sp_inv = remove # ignore/add/remove/force # Add or remove space after the '&' (address-of) unary operator. This does not # affect the spacing after a '&' that is part of a type. # # Default: remove sp_addr = remove # ignore/add/remove/force # Add or remove space around the '.' or '->' operators. # # Default: remove sp_member = remove # ignore/add/remove/force # Add or remove space after the '*' (dereference) unary operator. This does # not affect the spacing after a '*' that is part of a type. # # Default: remove sp_deref = remove # ignore/add/remove/force # Add or remove space after '+' or '-', as in 'x = -5' or 'y = +7'. # # Default: remove sp_sign = remove # ignore/add/remove/force # Add or remove space between '++' and '--' the word to which it is being # applied, as in '(--x)' or 'y++;'. # # Default: remove sp_incdec = remove # ignore/add/remove/force # Add or remove space before a backslash-newline at the end of a line. # # Default: add sp_before_nl_cont = add # ignore/add/remove/force # (OC) Add or remove space after the scope '+' or '-', as in '-(void) foo;' # or '+(int) bar;'. sp_after_oc_scope = ignore # ignore/add/remove/force # (OC) Add or remove space after the colon in message specs, # i.e. '-(int) f:(int) x;' vs. '-(int) f: (int) x;'. sp_after_oc_colon = ignore # ignore/add/remove/force # (OC) Add or remove space before the colon in message specs, # i.e. '-(int) f: (int) x;' vs. '-(int) f : (int) x;'. sp_before_oc_colon = ignore # ignore/add/remove/force # (OC) Add or remove space after the colon in immutable dictionary expression # 'NSDictionary *test = @{@"foo" :@"bar"};'. sp_after_oc_dict_colon = ignore # ignore/add/remove/force # (OC) Add or remove space before the colon in immutable dictionary expression # 'NSDictionary *test = @{@"foo" :@"bar"};'. sp_before_oc_dict_colon = ignore # ignore/add/remove/force # (OC) Add or remove space after the colon in message specs, # i.e. '[object setValue:1];' vs. '[object setValue: 1];'. sp_after_send_oc_colon = ignore # ignore/add/remove/force # (OC) Add or remove space before the colon in message specs, # i.e. '[object setValue:1];' vs. '[object setValue :1];'. sp_before_send_oc_colon = ignore # ignore/add/remove/force # (OC) Add or remove space after the (type) in message specs, # i.e. '-(int)f: (int) x;' vs. '-(int)f: (int)x;'. sp_after_oc_type = ignore # ignore/add/remove/force # (OC) Add or remove space after the first (type) in message specs, # i.e. '-(int) f:(int)x;' vs. '-(int)f:(int)x;'. sp_after_oc_return_type = ignore # ignore/add/remove/force # (OC) Add or remove space between '@selector' and '(', # i.e. '@selector(msgName)' vs. '@selector (msgName)'. # Also applies to '@protocol()' constructs. sp_after_oc_at_sel = ignore # ignore/add/remove/force # (OC) Add or remove space between '@selector(x)' and the following word, # i.e. '@selector(foo) a:' vs. '@selector(foo)a:'. sp_after_oc_at_sel_parens = ignore # ignore/add/remove/force # (OC) Add or remove space inside '@selector' parentheses, # i.e. '@selector(foo)' vs. '@selector( foo )'. # Also applies to '@protocol()' constructs. sp_inside_oc_at_sel_parens = ignore # ignore/add/remove/force # (OC) Add or remove space before a block pointer caret, # i.e. '^int (int arg){...}' vs. ' ^int (int arg){...}'. sp_before_oc_block_caret = ignore # ignore/add/remove/force # (OC) Add or remove space after a block pointer caret, # i.e. '^int (int arg){...}' vs. '^ int (int arg){...}'. sp_after_oc_block_caret = ignore # ignore/add/remove/force # (OC) Add or remove space between the receiver and selector in a message, # as in '[receiver selector ...]'. sp_after_oc_msg_receiver = ignore # ignore/add/remove/force # (OC) Add or remove space after '@property'. sp_after_oc_property = ignore # ignore/add/remove/force # (OC) Add or remove space between '@synchronized' and the open parenthesis, # i.e. '@synchronized(foo)' vs. '@synchronized (foo)'. sp_after_oc_synchronized = ignore # ignore/add/remove/force # Add or remove space around the ':' in 'b ? t : f'. sp_cond_colon = add # ignore/add/remove/force # Add or remove space before the ':' in 'b ? t : f'. # # Overrides sp_cond_colon. sp_cond_colon_before = ignore # ignore/add/remove/force # Add or remove space after the ':' in 'b ? t : f'. # # Overrides sp_cond_colon. sp_cond_colon_after = ignore # ignore/add/remove/force # Add or remove space around the '?' in 'b ? t : f'. sp_cond_question = add # ignore/add/remove/force # Add or remove space before the '?' in 'b ? t : f'. # # Overrides sp_cond_question. sp_cond_question_before = ignore # ignore/add/remove/force # Add or remove space after the '?' in 'b ? t : f'. # # Overrides sp_cond_question. sp_cond_question_after = ignore # ignore/add/remove/force # In the abbreviated ternary form '(a ?: b)', add or remove space between '?' # and ':'. # # Overrides all other sp_cond_* options. sp_cond_ternary_short = ignore # ignore/add/remove/force # Fix the spacing between 'case' and the label. Only 'ignore' and 'force' make # sense here. sp_case_label = ignore # ignore/add/remove/force # (D) Add or remove space around the D '..' operator. sp_range = ignore # ignore/add/remove/force # Add or remove space after ':' in a Java/C++11 range-based 'for', # as in 'for (Type var : expr)'. sp_after_for_colon = ignore # ignore/add/remove/force # Add or remove space before ':' in a Java/C++11 range-based 'for', # as in 'for (Type var : expr)'. sp_before_for_colon = ignore # ignore/add/remove/force # (D) Add or remove space between 'extern' and '(' as in 'extern (C)'. sp_extern_paren = ignore # ignore/add/remove/force # Add or remove space after the opening of a C++ comment, # i.e. '// A' vs. '//A'. sp_cmt_cpp_start = add # ignore/add/remove/force # If true, space is added with sp_cmt_cpp_start will be added after doxygen # sequences like '///', '///<', '//!' and '//!<'. sp_cmt_cpp_doxygen = false # true/false # If true, space is added with sp_cmt_cpp_start will be added after Qt # translator or meta-data comments like '//:', '//=', and '//~'. sp_cmt_cpp_qttr = false # true/false # Add or remove space between #else or #endif and a trailing comment. sp_endif_cmt = add # ignore/add/remove/force # Add or remove space after 'new', 'delete' and 'delete[]'. sp_after_new = ignore # ignore/add/remove/force # Add or remove space between 'new' and '(' in 'new()'. sp_between_new_paren = ignore # ignore/add/remove/force # Add or remove space between ')' and type in 'new(foo) BAR'. sp_after_newop_paren = ignore # ignore/add/remove/force # Add or remove space inside parenthesis of the new operator # as in 'new(foo) BAR'. sp_inside_newop_paren = ignore # ignore/add/remove/force # Add or remove space after the open parenthesis of the new operator, # as in 'new(foo) BAR'. # # Overrides sp_inside_newop_paren. sp_inside_newop_paren_open = ignore # ignore/add/remove/force # Add or remove space before the close parenthesis of the new operator, # as in 'new(foo) BAR'. # # Overrides sp_inside_newop_paren. sp_inside_newop_paren_close = ignore # ignore/add/remove/force # Add or remove space before a trailing or embedded comment. sp_before_tr_emb_cmt = ignore # ignore/add/remove/force # Number of spaces before a trailing or embedded comment. sp_num_before_tr_emb_cmt = 0 # unsigned number # (Java) Add or remove space between an annotation and the open parenthesis. sp_annotation_paren = ignore # ignore/add/remove/force # If true, vbrace tokens are dropped to the previous token and skipped. sp_skip_vbrace_tokens = false # true/false # Add or remove space after 'noexcept'. sp_after_noexcept = ignore # ignore/add/remove/force # Add or remove space after '_'. sp_vala_after_translation = ignore # ignore/add/remove/force # If true, a is inserted after #define. force_tab_after_define = false # true/false # # Indenting options # # The number of columns to indent per level. Usually 2, 3, 4, or 8. # # Default: 8 indent_columns = 4 # unsigned number # The continuation indent. If non-zero, this overrides the indent of '(', '[' # and '=' continuation indents. Negative values are OK; negative value is # absolute and not increased for each '(' or '[' level. # # For FreeBSD, this is set to 4. indent_continue = 0 # number # The continuation indent, only for class header line(s). If non-zero, this # overrides the indent of 'class' continuation indents. indent_continue_class_head = 0 # unsigned number # Whether to indent empty lines (i.e. lines which contain only spaces before # the newline character). indent_single_newlines = false # true/false # The continuation indent for func_*_param if they are true. If non-zero, this # overrides the indent. indent_param = 0 # unsigned number # How to use tabs when indenting code. # # 0: Spaces only # 1: Indent with tabs to brace level, align with spaces (default) # 2: Indent and align with tabs, using spaces when not on a tabstop # # Default: 1 indent_with_tabs = 0 # unsigned number # Whether to indent comments that are not at a brace level with tabs on a # tabstop. Requires indent_with_tabs=2. If false, will use spaces. indent_cmt_with_tabs = false # true/false # Whether to indent strings broken by '\' so that they line up. indent_align_string = false # true/false # The number of spaces to indent multi-line XML strings. # Requires indent_align_string=true. indent_xml_string = 0 # unsigned number # Spaces to indent '{' from level. indent_brace = 0 # unsigned number # Whether braces are indented to the body level. indent_braces = false # true/false # Whether to disable indenting function braces if indent_braces=true. indent_braces_no_func = false # true/false # Whether to disable indenting class braces if indent_braces=true. indent_braces_no_class = false # true/false # Whether to disable indenting struct braces if indent_braces=true. indent_braces_no_struct = false # true/false # Whether to indent based on the size of the brace parent, # i.e. 'if' => 3 spaces, 'for' => 4 spaces, etc. indent_brace_parent = false # true/false # Whether to indent based on the open parenthesis instead of the open brace # in '({\n'. indent_paren_open_brace = false # true/false # (C#) Whether to indent the brace of a C# delegate by another level. indent_cs_delegate_brace = false # true/false # (C#) Whether to indent a C# delegate (to handle delegates with no brace) by # another level. indent_cs_delegate_body = false # true/false # Whether to indent the body of a 'namespace'. indent_namespace = false # true/false # Whether to indent only the first namespace, and not any nested namespaces. # Requires indent_namespace=true. indent_namespace_single_indent = false # true/false # The number of spaces to indent a namespace block. # If set to zero, use the value indent_columns indent_namespace_level = 0 # unsigned number # If the body of the namespace is longer than this number, it won't be # indented. Requires indent_namespace=true. 0 means no limit. indent_namespace_limit = 0 # unsigned number # Whether the 'extern "C"' body is indented. indent_extern = false # true/false # Whether the 'class' body is indented. indent_class = false # true/false # Whether to indent the stuff after a leading base class colon. indent_class_colon = false # true/false # Whether to indent based on a class colon instead of the stuff after the # colon. Requires indent_class_colon=true. indent_class_on_colon = false # true/false # Whether to indent the stuff after a leading class initializer colon. indent_constr_colon = false # true/false # Virtual indent from the ':' for member initializers. # # Default: 2 indent_ctor_init_leading = 2 # unsigned number # Additional indent for constructor initializer list. # Negative values decrease indent down to the first column. indent_ctor_init = 0 # number # Whether to indent 'if' following 'else' as a new block under the 'else'. # If false, 'else\nif' is treated as 'else if' for indenting purposes. indent_else_if = false # true/false # Amount to indent variable declarations after a open brace. # # <0: Relative # >=0: Absolute indent_var_def_blk = 0 # number # Whether to indent continued variable declarations instead of aligning. indent_var_def_cont = false # true/false # Whether to indent continued shift expressions ('<<' and '>>') instead of # aligning. Set align_left_shift=false when enabling this. indent_shift = false # true/false # Whether to force indentation of function definitions to start in column 1. indent_func_def_force_col1 = false # true/false # Whether to indent continued function call parameters one indent level, # rather than aligning parameters under the open parenthesis. indent_func_call_param = false # true/false # Whether to indent continued function definition parameters one indent level, # rather than aligning parameters under the open parenthesis. indent_func_def_param = false # true/false # for function definitions, only if indent_func_def_param is false # Allows to align params when appropriate and indent them when not # behave as if it was true if paren position is more than this value # if paren position is more than the option value #indent_func_def_param_paren_pos_threshold = 0 # unsigned number ### not 0.69 # Whether to indent continued function call prototype one indent level, # rather than aligning parameters under the open parenthesis. indent_func_proto_param = false # true/false # Whether to indent continued function call declaration one indent level, # rather than aligning parameters under the open parenthesis. indent_func_class_param = false # true/false # Whether to indent continued class variable constructors one indent level, # rather than aligning parameters under the open parenthesis. indent_func_ctor_var_param = false # true/false # Whether to indent continued template parameter list one indent level, # rather than aligning parameters under the open parenthesis. indent_template_param = false # true/false # Double the indent for indent_func_xxx_param options. # Use both values of the options indent_columns and indent_param. indent_func_param_double = false # true/false # Indentation column for standalone 'const' qualifier on a function # prototype. indent_func_const = 0 # unsigned number # Indentation column for standalone 'throw' qualifier on a function # prototype. indent_func_throw = 0 # unsigned number # How to indent within a macro followed by a brace on the same line # This allows reducing the indent in macros that have (for example) # `do { ... } while (0)` blocks bracketing them. # # true: add an indent for the brace on the same line as the macro # false: do not add an indent for the brace on the same line as the macro # # Default: true #indent_macro_brace = true # true/false ### not 0.69 # The number of spaces to indent a continued '->' or '.'. # Usually set to 0, 1, or indent_columns. indent_member = 0 # unsigned number # Whether lines broken at '.' or '->' should be indented by a single indent. # The indent_member option will not be effective if this is set to true. indent_member_single = false # true/false # Spaces to indent single line ('//') comments on lines before code. indent_sing_line_comments = 0 # unsigned number # When opening a paren for a control statement (if, for, while, etc), increase # the indent level by this value. Negative values decrease the indent level. #indent_sparen_extra = 0 # number ### not 0.69 # Whether to indent trailing single line ('//') comments relative to the code # instead of trying to keep the same absolute column. indent_relative_single_line_comments = false # true/false # Spaces to indent 'case' from 'switch'. Usually 0 or indent_columns. indent_switch_case = 0 # unsigned number # indent 'break' with 'case' from 'switch'. #indent_switch_break_with_case = false # true/false ### not 0.69 # Whether to indent preprocessor statements inside of switch statements. # # Default: true indent_switch_pp = true # true/false # Spaces to shift the 'case' line, without affecting any other lines. # Usually 0. indent_case_shift = 0 # unsigned number # Spaces to indent '{' from 'case'. By default, the brace will appear under # the 'c' in case. Usually set to 0 or indent_columns. Negative values are OK. indent_case_brace = 0 # number # Whether to indent comments found in first column. indent_col1_comment = false # true/false # Whether to indent multi string literal in first column. indent_col1_multi_string_literal = false # true/false # How to indent goto labels. # # >0: Absolute column where 1 is the leftmost column # <=0: Subtract from brace indent # # Default: 1 indent_label = 1 # number # How to indent access specifiers that are followed by a # colon. # # >0: Absolute column where 1 is the leftmost column # <=0: Subtract from brace indent # # Default: 1 indent_access_spec = 1 # number # Whether to indent the code after an access specifier by one level. # If true, this option forces 'indent_access_spec=0'. indent_access_spec_body = false # true/false # If an open parenthesis is followed by a newline, whether to indent the next # line so that it lines up after the open parenthesis (not recommended). indent_paren_nl = false # true/false # How to indent a close parenthesis after a newline. # # 0: Indent to body level (default) # 1: Align under the open parenthesis # 2: Indent to the brace level indent_paren_close = 0 # unsigned number # Whether to indent the open parenthesis of a function definition, # if the parenthesis is on its own line. indent_paren_after_func_def = false # true/false # Whether to indent the open parenthesis of a function declaration, # if the parenthesis is on its own line. indent_paren_after_func_decl = false # true/false # Whether to indent the open parenthesis of a function call, # if the parenthesis is on its own line. indent_paren_after_func_call = false # true/false # Whether to indent a comma when inside a parenthesis. # If true, aligns under the open parenthesis. indent_comma_paren = false # true/false # Whether to indent a Boolean operator when inside a parenthesis. # If true, aligns under the open parenthesis. indent_bool_paren = false # true/false # Whether to indent a semicolon when inside a for parenthesis. # If true, aligns under the open for parenthesis. indent_semicolon_for_paren = false # true/false # Whether to align the first expression to following ones # if indent_bool_paren=true. indent_first_bool_expr = false # true/false # Whether to align the first expression to following ones # if indent_semicolon_for_paren=true. indent_first_for_expr = false # true/false # If an open square is followed by a newline, whether to indent the next line # so that it lines up after the open square (not recommended). indent_square_nl = false # true/false # (ESQL/C) Whether to preserve the relative indent of 'EXEC SQL' bodies. indent_preserve_sql = false # true/false # Whether to align continued statements at the '='. If false or if the '=' is # followed by a newline, the next line is indent one tab. # # Default: true indent_align_assign = true # true/false # If true, the indentation of the chunks after a '=' sequence will be set at # LHS token indentation column before '='. #indent_off_after_assign = false # true/false ### not 0.69 # Whether to align continued statements at the '('. If false or the '(' is # followed by a newline, the next line indent is one tab. # # Default: true indent_align_paren = true # true/false # (OC) Whether to indent Objective-C code inside message selectors. #indent_oc_inside_msg_sel = false # true/false ### not 0.69 # (OC) Whether to indent Objective-C blocks at brace level instead of usual # rules. indent_oc_block = false # true/false # (OC) Indent for Objective-C blocks in a message relative to the parameter # name. # # =0: Use indent_oc_block rules # >0: Use specified number of spaces to indent indent_oc_block_msg = 0 # unsigned number # (OC) Minimum indent for subsequent parameters indent_oc_msg_colon = 0 # unsigned number # (OC) Whether to prioritize aligning with initial colon (and stripping spaces # from lines, if necessary). # # Default: true indent_oc_msg_prioritize_first_colon = true # true/false # (OC) Whether to indent blocks the way that Xcode does by default # (from the keyword if the parameter is on its own line; otherwise, from the # previous indentation level). Requires indent_oc_block_msg=true. indent_oc_block_msg_xcode_style = false # true/false # (OC) Whether to indent blocks from where the brace is, relative to a # message keyword. Requires indent_oc_block_msg=true. indent_oc_block_msg_from_keyword = false # true/false # (OC) Whether to indent blocks from where the brace is, relative to a message # colon. Requires indent_oc_block_msg=true. indent_oc_block_msg_from_colon = false # true/false # (OC) Whether to indent blocks from where the block caret is. # Requires indent_oc_block_msg=true. indent_oc_block_msg_from_caret = false # true/false # (OC) Whether to indent blocks from where the brace caret is. # Requires indent_oc_block_msg=true. indent_oc_block_msg_from_brace = false # true/false # When indenting after virtual brace open and newline add further spaces to # reach this minimum indent. indent_min_vbrace_open = 0 # unsigned number # Whether to add further spaces after regular indent to reach next tabstop # when identing after virtual brace open and newline. indent_vbrace_open_on_tabstop = false # true/false # How to indent after a brace followed by another token (not a newline). # true: indent all contained lines to match the token # false: indent all contained lines to match the brace # # Default: true indent_token_after_brace = true # true/false # Whether to indent the body of a C++11 lambda. indent_cpp_lambda_body = false # true/false # How to indent compound literals that are being returned. # true: add both the indent from return & the compound literal open brace (ie: # 2 indent levels) # false: only indent 1 level, don't add the indent for the open brace, only add # the indent for the return. # # Default: true #indent_compound_literal_return = true # true/false ### not 0.69 # (C#) Whether to indent a 'using' block if no braces are used. # # Default: true indent_using_block = true # true/false # How to indent the continuation of ternary operator. # # 0: Off (default) # 1: When the `if_false` is a continuation, indent it under `if_false` # 2: When the `:` is a continuation, indent it under `?` indent_ternary_operator = 0 # unsigned number # Whether to indent the statments inside ternary operator. #indent_inside_ternary_operator = false # true/false ### not 0.69 # If true, the indentation of the chunks after a `return` sequence will be set at return indentation column. #indent_off_after_return = false # true/false ### not 0.69 # If true, the indentation of the chunks after a `return new` sequence will be set at return indentation column. indent_off_after_return_new = false # true/false # If true, the tokens after return are indented with regular single indentation. By default (false) the indentation is after the return token. indent_single_after_return = false # true/false # Whether to ignore indent and alignment for 'asm' blocks (i.e. assume they # have their own indentation). indent_ignore_asm_block = false # true/false # # Newline adding and removing options # # Whether to collapse empty blocks between '{' and '}'. nl_collapse_empty_body = false # true/false # Don't split one-line braced assignments, as in 'foo_t f = { 1, 2 };'. nl_assign_leave_one_liners = false # true/false # Don't split one-line braced statements inside a 'class xx { }' body. nl_class_leave_one_liners = false # true/false # Don't split one-line enums, as in 'enum foo { BAR = 15 };' nl_enum_leave_one_liners = false # true/false # Don't split one-line get or set functions. nl_getset_leave_one_liners = false # true/false # (C#) Don't split one-line property get or set functions. nl_cs_property_leave_one_liners = false # true/false # Don't split one-line function definitions, as in 'int foo() { return 0; }'. # might modify nl_func_type_name nl_func_leave_one_liners = false # true/false # Don't split one-line C++11 lambdas, as in '[]() { return 0; }'. nl_cpp_lambda_leave_one_liners = false # true/false # Don't split one-line if/else statements, as in 'if(...) b++;'. nl_if_leave_one_liners = false # true/false # Don't split one-line while statements, as in 'while(...) b++;'. nl_while_leave_one_liners = false # true/false # Don't split one-line for statements, as in 'for(...) b++;'. nl_for_leave_one_liners = false # true/false # (OC) Don't split one-line Objective-C messages. nl_oc_msg_leave_one_liner = false # true/false # (OC) Add or remove newline between method declaration and '{'. nl_oc_mdef_brace = ignore # ignore/add/remove/force # (OC) Add or remove newline between Objective-C block signature and '{'. nl_oc_block_brace = ignore # ignore/add/remove/force # (OC) Add or remove blank line before '@interface' statement. #nl_oc_before_interface = ignore # ignore/add/remove/force ### not 0.69 # (OC) Add or remove blank line before '@implementation' statement. #nl_oc_before_implementation = ignore # ignore/add/remove/force ### not 0.69 # (OC) Add or remove blank line before '@end' statement. #nl_oc_before_end = ignore # ignore/add/remove/force ### not 0.69 # (OC) Add or remove newline between '@interface' and '{'. nl_oc_interface_brace = ignore # ignore/add/remove/force # (OC) Add or remove newline between '@implementation' and '{'. nl_oc_implementation_brace = ignore # ignore/add/remove/force # Add or remove newlines at the start of the file. nl_start_of_file = remove # ignore/add/remove/force # The minimum number of newlines at the start of the file (only used if # nl_start_of_file is 'add' or 'force'). nl_start_of_file_min = 0 # unsigned number # Add or remove newline at the end of the file. nl_end_of_file = ignore # ignore/add/remove/force # The minimum number of newlines at the end of the file (only used if # nl_end_of_file is 'add' or 'force'). nl_end_of_file_min = 0 # unsigned number # Add or remove newline between '=' and '{'. nl_assign_brace = ignore # ignore/add/remove/force # (D) Add or remove newline between '=' and '['. nl_assign_square = ignore # ignore/add/remove/force # Add or remove newline between '[]' and '{'. nl_tsquare_brace = ignore # ignore/add/remove/force # (D) Add or remove newline after '= ['. Will also affect the newline before # the ']'. nl_after_square_assign = ignore # ignore/add/remove/force # Add or remove newline between a function call's ')' and '{', as in # 'list_for_each(item, &list) { }'. nl_fcall_brace = ignore # ignore/add/remove/force # Add or remove newline between 'enum' and '{'. nl_enum_brace = remove # ignore/add/remove/force # Add or remove newline between 'enum' and 'class'. nl_enum_class = ignore # ignore/add/remove/force # Add or remove newline between 'enum class' and the identifier. nl_enum_class_identifier = ignore # ignore/add/remove/force # Add or remove newline between 'enum class' type and ':'. nl_enum_identifier_colon = ignore # ignore/add/remove/force # Add or remove newline between 'enum class identifier :' and type. nl_enum_colon_type = ignore # ignore/add/remove/force # Add or remove newline between 'struct and '{'. nl_struct_brace = remove # ignore/add/remove/force # Add or remove newline between 'union' and '{'. nl_union_brace = remove # ignore/add/remove/force # Add or remove newline between 'if' and '{'. nl_if_brace = remove # ignore/add/remove/force # Add or remove newline between '}' and 'else'. nl_brace_else = remove # ignore/add/remove/force # Add or remove newline between 'else if' and '{'. If set to ignore, # nl_if_brace is used instead. nl_elseif_brace = remove # ignore/add/remove/force # Add or remove newline between 'else' and '{'. nl_else_brace = remove # ignore/add/remove/force # Add or remove newline between 'else' and 'if'. nl_else_if = remove # ignore/add/remove/force # Add or remove newline before '{' opening brace #nl_before_opening_brace_func_class_def = remove # ignore/add/remove/force ### not 0.69 # Add or remove newline before 'if'/'else if' closing parenthesis. nl_before_if_closing_paren = remove # ignore/add/remove/force # Add or remove newline between '}' and 'finally'. nl_brace_finally = remove # ignore/add/remove/force # Add or remove newline between 'finally' and '{'. nl_finally_brace = remove # ignore/add/remove/force # Add or remove newline between 'try' and '{'. nl_try_brace = remove # ignore/add/remove/force # Add or remove newline between get/set and '{'. nl_getset_brace = remove # ignore/add/remove/force # Add or remove newline between 'for' and '{'. nl_for_brace = remove # ignore/add/remove/force # Add or remove newline before the '{' of a 'catch' statement, as in # 'catch (decl) {'. nl_catch_brace = remove # ignore/add/remove/force # (OC) Add or remove newline before the '{' of a '@catch' statement, as in # '@catch (decl) {'. If set to ignore, nl_catch_brace is used. nl_oc_catch_brace = ignore # ignore/add/remove/force # Add or remove newline between '}' and 'catch'. nl_brace_catch = remove # ignore/add/remove/force # (OC) Add or remove newline between '}' and '@catch'. If set to ignore, # nl_brace_catch is used. nl_oc_brace_catch = ignore # ignore/add/remove/force # Add or remove newline between '}' and ']'. nl_brace_square = ignore # ignore/add/remove/force # Add or remove newline between '}' and ')' in a function invocation. nl_brace_fparen = ignore # ignore/add/remove/force # Add or remove newline between 'while' and '{'. nl_while_brace = remove # ignore/add/remove/force # (D) Add or remove newline between 'scope (x)' and '{'. nl_scope_brace = ignore # ignore/add/remove/force # (D) Add or remove newline between 'unittest' and '{'. nl_unittest_brace = ignore # ignore/add/remove/force # (D) Add or remove newline between 'version (x)' and '{'. nl_version_brace = ignore # ignore/add/remove/force # (C#) Add or remove newline between 'using' and '{'. nl_using_brace = ignore # ignore/add/remove/force # Add or remove newline between two open or close braces. Due to general # newline/brace handling, REMOVE may not work. nl_brace_brace = add # ignore/add/remove/force # Add or remove newline between 'do' and '{'. nl_do_brace = remove # ignore/add/remove/force # Add or remove newline between '}' and 'while' of 'do' statement. nl_brace_while = remove # ignore/add/remove/force # Add or remove newline between 'switch' and '{'. nl_switch_brace = remove # ignore/add/remove/force # Add or remove newline between 'synchronized' and '{'. nl_synchronized_brace = remove # ignore/add/remove/force # Add a newline between ')' and '{' if the ')' is on a different line than the # if/for/etc. # # Overrides nl_for_brace, nl_if_brace, nl_switch_brace, nl_while_switch and # nl_catch_brace. nl_multi_line_cond = false # true/false # Add a newline after '(' if an if/for/while/switch condition spans multiple # lines #nl_multi_line_sparen_open = ignore # ignore/add/remove/force ### not 0.69 # Add a newline before ')' if an if/for/while/switch condition spans multiple # lines. Overrides nl_before_if_closing_paren if both are specified. #nl_multi_line_sparen_close = ignore # ignore/add/remove/force ### not 0.69 # Force a newline in a define after the macro name for multi-line defines. nl_multi_line_define = false # true/false # Whether to add a newline before 'case', and a blank line before a 'case' # statement that follows a ';' or '}'. nl_before_case = false # true/false # Whether to add a newline after a 'case' statement. nl_after_case = false # true/false # Add or remove newline between a case ':' and '{'. # # Overrides nl_after_case. nl_case_colon_brace = ignore # ignore/add/remove/force # Add or remove newline between ')' and 'throw'. nl_before_throw = ignore # ignore/add/remove/force # Add or remove newline between 'namespace' and '{'. nl_namespace_brace = ignore # ignore/add/remove/force # Add or remove newline after 'template<...>' of a template class. nl_template_class = ignore # ignore/add/remove/force # Add or remove newline after 'template<...>' of a template class declaration. # # Overrides nl_template_class. #nl_template_class_decl = ignore # ignore/add/remove/force ### not 0.69 # Add or remove newline after 'template<>' of a specialized class declaration. # # Overrides nl_template_class_decl. #nl_template_class_decl_special = ignore # ignore/add/remove/force ### not 0.69 # Add or remove newline after 'template<...>' of a template class definition. # # Overrides nl_template_class. #nl_template_class_def = ignore # ignore/add/remove/force ### not 0.69 # Add or remove newline after 'template<>' of a specialized class definition. # # Overrides nl_template_class_def. #nl_template_class_def_special = ignore # ignore/add/remove/force ### not 0.69 # Add or remove newline after 'template<...>' of a template function. #nl_template_func = ignore # ignore/add/remove/force ### not 0.69 # Add or remove newline after 'template<...>' of a template function # declaration. # # Overrides nl_template_func. #nl_template_func_decl = ignore # ignore/add/remove/force ### not 0.69 # Add or remove newline after 'template<>' of a specialized function # declaration. # # Overrides nl_template_func_decl. #nl_template_func_decl_special = ignore # ignore/add/remove/force ### not 0.69 # Add or remove newline after 'template<...>' of a template function # definition. # # Overrides nl_template_func. #nl_template_func_def = ignore # ignore/add/remove/force ### not 0.69 # Add or remove newline after 'template<>' of a specialized function # definition. # # Overrides nl_template_func_def. #nl_template_func_def_special = ignore # ignore/add/remove/force ### not 0.69 # Add or remove newline after 'template<...>' of a template variable. #nl_template_var = ignore # ignore/add/remove/force ### not 0.69 # Add or remove newline between 'template<...>' and 'using' of a templated # type alias. #nl_template_using = ignore # ignore/add/remove/force ### not 0.69 # Add or remove newline between 'class' and '{'. nl_class_brace = ignore # ignore/add/remove/force # Add or remove newline before or after (depending on pos_class_comma, # may not be IGNORE) each',' in the base class list. nl_class_init_args = ignore # ignore/add/remove/force # Add or remove newline after each ',' in the constructor member # initialization. Related to nl_constr_colon, pos_constr_colon and # pos_constr_comma. nl_constr_init_args = ignore # ignore/add/remove/force # Add or remove newline before first element, after comma, and after last # element, in 'enum'. nl_enum_own_lines = ignore # ignore/add/remove/force # Add or remove newline between return type and function name in a function # definition. # might be modified by nl_func_leave_one_liners nl_func_type_name = ignore # ignore/add/remove/force # Add or remove newline between return type and function name inside a class # definition. If set to ignore, nl_func_type_name or nl_func_proto_type_name # is used instead. nl_func_type_name_class = ignore # ignore/add/remove/force # Add or remove newline between class specification and '::' # in 'void A::f() { }'. Only appears in separate member implementation (does # not appear with in-line implementation). nl_func_class_scope = ignore # ignore/add/remove/force # Add or remove newline between function scope and name, as in # 'void A :: f() { }'. nl_func_scope_name = ignore # ignore/add/remove/force # Add or remove newline between return type and function name in a prototype. nl_func_proto_type_name = ignore # ignore/add/remove/force # Add or remove newline between a function name and the opening '(' in the # declaration. nl_func_paren = remove # ignore/add/remove/force # Overrides nl_func_paren for functions with no parameters. nl_func_paren_empty = ignore # ignore/add/remove/force # Add or remove newline between a function name and the opening '(' in the # definition. nl_func_def_paren = remove # ignore/add/remove/force # Overrides nl_func_def_paren for functions with no parameters. nl_func_def_paren_empty = ignore # ignore/add/remove/force # Add or remove newline between a function name and the opening '(' in the # call. nl_func_call_paren = ignore # ignore/add/remove/force # Overrides nl_func_call_paren for functions with no parameters. nl_func_call_paren_empty = ignore # ignore/add/remove/force # Add or remove newline after '(' in a function declaration. nl_func_decl_start = remove # ignore/add/remove/force # Add or remove newline after '(' in a function definition. nl_func_def_start = remove # ignore/add/remove/force # Overrides nl_func_decl_start when there is only one parameter. nl_func_decl_start_single = ignore # ignore/add/remove/force # Overrides nl_func_def_start when there is only one parameter. nl_func_def_start_single = ignore # ignore/add/remove/force # Whether to add a newline after '(' in a function declaration if '(' and ')' # are in different lines. If false, nl_func_decl_start is used instead. nl_func_decl_start_multi_line = false # true/false # Whether to add a newline after '(' in a function definition if '(' and ')' # are in different lines. If false, nl_func_def_start is used instead. nl_func_def_start_multi_line = false # true/false # Add or remove newline after each ',' in a function declaration. nl_func_decl_args = ignore # ignore/add/remove/force # Add or remove newline after each ',' in a function definition. nl_func_def_args = ignore # ignore/add/remove/force # Add or remove newline after each ',' in a function call. #nl_func_call_args = ignore # ignore/add/remove/force ### not 0.69 # Whether to add a newline after each ',' in a function declaration if '(' # and ')' are in different lines. If false, nl_func_decl_args is used instead. nl_func_decl_args_multi_line = false # true/false # Whether to add a newline after each ',' in a function definition if '(' # and ')' are in different lines. If false, nl_func_def_args is used instead. nl_func_def_args_multi_line = false # true/false # Add or remove newline before the ')' in a function declaration. nl_func_decl_end = remove # ignore/add/remove/force # Add or remove newline before the ')' in a function definition. nl_func_def_end = remove # ignore/add/remove/force # Overrides nl_func_decl_end when there is only one parameter. nl_func_decl_end_single = ignore # ignore/add/remove/force # Overrides nl_func_def_end when there is only one parameter. nl_func_def_end_single = ignore # ignore/add/remove/force # Whether to add a newline before ')' in a function declaration if '(' and ')' # are in different lines. If false, nl_func_decl_end is used instead. nl_func_decl_end_multi_line = false # true/false # Whether to add a newline before ')' in a function definition if '(' and ')' # are in different lines. If false, nl_func_def_end is used instead. nl_func_def_end_multi_line = false # true/false # Add or remove newline between '()' in a function declaration. nl_func_decl_empty = remove # ignore/add/remove/force # Add or remove newline between '()' in a function definition. nl_func_def_empty = remove # ignore/add/remove/force # Add or remove newline between '()' in a function call. nl_func_call_empty = remove # ignore/add/remove/force # Whether to add a newline after '(' in a function call, # has preference over nl_func_call_start_multi_line. nl_func_call_start = ignore # ignore/add/remove/force # Whether to add a newline before ')' in a function call. #nl_func_call_end = ignore # ignore/add/remove/force ### not 0.69 # Whether to add a newline after '(' in a function call if '(' and ')' are in # different lines. nl_func_call_start_multi_line = false # true/false # Whether to add a newline after each ',' in a function call if '(' and ')' # are in different lines. nl_func_call_args_multi_line = false # true/false # Whether to add a newline before ')' in a function call if '(' and ')' are in # different lines. nl_func_call_end_multi_line = false # true/false # Whether to respect nl_func_call_XXX option incase of closure args. #nl_func_call_args_multi_line_ignore_closures = false # true/false ### not 0.69 # Whether to add a newline after '<' of a template parameter list. #nl_template_start = false # true/false ### not 0.69 # Whether to add a newline after each ',' in a template parameter list. #nl_template_args = false # true/false ### not 0.69 # Whether to add a newline before '>' of a template parameter list. #nl_template_end = false # true/false ### not 0.69 # (OC) Whether to put each Objective-C message parameter on a separate line. # See nl_oc_msg_leave_one_liner. nl_oc_msg_args = false # true/false # Add or remove newline between function signature and '{'. nl_fdef_brace = ignore # ignore/add/remove/force # Add or remove newline between function signature and '{', # if signature ends with ')'. Overrides nl_fdef_brace. nl_fdef_brace_cond = ignore # ignore/add/remove/force # Add or remove newline between C++11 lambda signature and '{'. nl_cpp_ldef_brace = ignore # ignore/add/remove/force # Add or remove newline between 'return' and the return expression. nl_return_expr = ignore # ignore/add/remove/force # Whether to add a newline after semicolons, except in 'for' statements. nl_after_semicolon = false # true/false # (Java) Add or remove newline between the ')' and '{{' of the double brace # initializer. nl_paren_dbrace_open = ignore # ignore/add/remove/force # Whether to add a newline after the type in an unnamed temporary # direct-list-initialization. nl_type_brace_init_lst = ignore # ignore/add/remove/force # Whether to add a newline after the open brace in an unnamed temporary # direct-list-initialization. nl_type_brace_init_lst_open = ignore # ignore/add/remove/force # Whether to add a newline before the close brace in an unnamed temporary # direct-list-initialization. nl_type_brace_init_lst_close = ignore # ignore/add/remove/force # Whether to add a newline after '{'. This also adds a newline before the # matching '}'. nl_after_brace_open = false # true/false # Whether to add a newline between the open brace and a trailing single-line # comment. Requires nl_after_brace_open=true. nl_after_brace_open_cmt = false # true/false # Whether to add a newline after a virtual brace open with a non-empty body. # These occur in un-braced if/while/do/for statement bodies. nl_after_vbrace_open = false # true/false # Whether to add a newline after a virtual brace open with an empty body. # These occur in un-braced if/while/do/for statement bodies. nl_after_vbrace_open_empty = false # true/false # Whether to add a newline after '}'. Does not apply if followed by a # necessary ';'. nl_after_brace_close = false # true/false # Whether to add a newline after a virtual brace close, # as in 'if (foo) a++; return;'. nl_after_vbrace_close = false # true/false # Add or remove newline between the close brace and identifier, # as in 'struct { int a; } b;'. Affects enumerations, unions and # structures. If set to ignore, uses nl_after_brace_close. nl_brace_struct_var = ignore # ignore/add/remove/force # Whether to alter newlines in '#define' macros. nl_define_macro = false # true/false # Whether to alter newlines between consecutive parenthesis closes. The number # of closing parentheses in a line will depend on respective open parenthesis # lines. nl_squeeze_paren_close = false # true/false # Whether to remove blanks after '#ifxx' and '#elxx', or before '#elxx' and # '#endif'. Does not affect top-level #ifdefs. nl_squeeze_ifdef = false # true/false # Makes the nl_squeeze_ifdef option affect the top-level #ifdefs as well. nl_squeeze_ifdef_top_level = false # true/false # Add or remove blank line before 'if'. nl_before_if = add # ignore/add/remove/force # Add or remove blank line after 'if' statement. Add/Force work only if the # next token is not a closing brace. nl_after_if = add # ignore/add/remove/force # Add or remove blank line before 'for'. nl_before_for = add # ignore/add/remove/force # Add or remove blank line after 'for' statement. nl_after_for = add # ignore/add/remove/force # Add or remove blank line before 'while'. nl_before_while = add # ignore/add/remove/force # Add or remove blank line after 'while' statement. nl_after_while = add # ignore/add/remove/force # Add or remove blank line before 'switch'. nl_before_switch = add # ignore/add/remove/force # Add or remove blank line after 'switch' statement. nl_after_switch = add # ignore/add/remove/force # Add or remove blank line before 'synchronized'. nl_before_synchronized = add # ignore/add/remove/force # Add or remove blank line after 'synchronized' statement. nl_after_synchronized = add # ignore/add/remove/force # Add or remove blank line before 'do'. nl_before_do = add # ignore/add/remove/force # Add or remove blank line after 'do/while' statement. nl_after_do = add # ignore/add/remove/force # Whether to put a blank line before 'return' statements, unless after an open # brace. nl_before_return = false # true/false # Whether to put a blank line after 'return' statements, unless followed by a # close brace. nl_after_return = false # true/false # Whether to put a blank line before a member '.' or '->' operators. #nl_before_member = ignore # ignore/add/remove/force ### not 0.69 # (Java) Whether to put a blank line after a member '.' or '->' operators. #nl_after_member = ignore # ignore/add/remove/force ### not 0.69 # Whether to double-space commented-entries in 'struct'/'union'/'enum'. nl_ds_struct_enum_cmt = false # true/false # Whether to force a newline before '}' of a 'struct'/'union'/'enum'. # (Lower priority than eat_blanks_before_close_brace.) nl_ds_struct_enum_close_brace = false # true/false # Add or remove newline before or after (depending on pos_class_colon) a class # colon, as in 'class Foo : public Bar'. nl_class_colon = ignore # ignore/add/remove/force # Add or remove newline around a class constructor colon. The exact position # depends on nl_constr_init_args, pos_constr_colon and pos_constr_comma. nl_constr_colon = ignore # ignore/add/remove/force # Whether to collapse a two-line namespace, like 'namespace foo\n{ decl; }' # into a single line. If true, prevents other brace newline rules from turning # such code into four lines. nl_namespace_two_to_one_liner = false # true/false # Whether to remove a newline in simple unbraced if statements, turning them # into one-liners, as in 'if(b)\n i++;' => 'if(b) i++;'. nl_create_if_one_liner = false # true/false # Whether to remove a newline in simple unbraced for statements, turning them # into one-liners, as in 'for (...)\n stmt;' => 'for (...) stmt;'. nl_create_for_one_liner = false # true/false # Whether to remove a newline in simple unbraced while statements, turning # them into one-liners, as in 'while (expr)\n stmt;' => 'while (expr) stmt;'. nl_create_while_one_liner = false # true/false # Whether to collapse a function definition whose body (not counting braces) # is only one line so that the entire definition (prototype, braces, body) is # a single line. nl_create_func_def_one_liner = false # true/false # Whether to collapse a function definition whose body (not counting braces) # is only one line so that the entire definition (prototype, braces, body) is # a single line. #nl_create_list_one_liner = false # true/false ### not 0.69 # Whether to split one-line simple unbraced if statements into two lines by # adding a newline, as in 'if(b) i++;'. nl_split_if_one_liner = false # true/false # Whether to split one-line simple unbraced for statements into two lines by # adding a newline, as in 'for (...) stmt;'. nl_split_for_one_liner = false # true/false # Whether to split one-line simple unbraced while statements into two lines by # adding a newline, as in 'while (expr) stmt;'. nl_split_while_one_liner = false # true/false # # Blank line options # # The maximum number of consecutive newlines (3 = 2 blank lines). nl_max = 0 # unsigned number # The maximum number of consecutive newlines in a function. nl_max_blank_in_func = 0 # unsigned number # The number of newlines before a function prototype. nl_before_func_body_proto = 0 # unsigned number # The number of newlines before a multi-line function definition. nl_before_func_body_def = 0 # unsigned number # The number of newlines before a class constructor/destructor prototype. nl_before_func_class_proto = 0 # unsigned number # The number of newlines before a class constructor/destructor definition. nl_before_func_class_def = 0 # unsigned number # The number of newlines after a function prototype. nl_after_func_proto = 0 # unsigned number # The number of newlines after a function prototype, if not followed by # another function prototype. nl_after_func_proto_group = 0 # unsigned number # The number of newlines after a class constructor/destructor prototype. nl_after_func_class_proto = 0 # unsigned number # The number of newlines after a class constructor/destructor prototype, # if not followed by another constructor/destructor prototype. nl_after_func_class_proto_group = 0 # unsigned number # Whether one-line method definitions inside a class body should be treated # as if they were prototypes for the purposes of adding newlines. # # Requires nl_class_leave_one_liners=true. Overrides nl_before_func_body_def # and nl_before_func_class_def for one-liners. nl_class_leave_one_liner_groups = false # true/false # The number of newlines after '}' of a multi-line function body. nl_after_func_body = 0 # unsigned number # The number of newlines after '}' of a multi-line function body in a class # declaration. Also affects class constructors/destructors. # # Overrides nl_after_func_body. nl_after_func_body_class = 0 # unsigned number # The number of newlines after '}' of a single line function body. Also # affects class constructors/destructors. # # Overrides nl_after_func_body and nl_after_func_body_class. nl_after_func_body_one_liner = 0 # unsigned number # The number of blank lines after a block of variable definitions at the top # of a function body. # # 0: No change (default). nl_func_var_def_blk = 0 # unsigned number # The number of newlines before a block of typedefs. If nl_after_access_spec # is non-zero, that option takes precedence. # # 0: No change (default). nl_typedef_blk_start = 0 # unsigned number # The number of newlines after a block of typedefs. # # 0: No change (default). nl_typedef_blk_end = 0 # unsigned number # The maximum number of consecutive newlines within a block of typedefs. # # 0: No change (default). nl_typedef_blk_in = 0 # unsigned number # The number of newlines before a block of variable definitions not at the top # of a function body. If nl_after_access_spec is non-zero, that option takes # precedence. # # 0: No change (default). nl_var_def_blk_start = 0 # unsigned number # The number of newlines after a block of variable definitions not at the top # of a function body. # # 0: No change (default). nl_var_def_blk_end = 0 # unsigned number # The maximum number of consecutive newlines within a block of variable # definitions. # # 0: No change (default). nl_var_def_blk_in = 0 # unsigned number # The minimum number of newlines before a multi-line comment. # Doesn't apply if after a brace open or another multi-line comment. nl_before_block_comment = 0 # unsigned number # The minimum number of newlines before a single-line C comment. # Doesn't apply if after a brace open or other single-line C comments. nl_before_c_comment = 0 # unsigned number # The minimum number of newlines before a CPP comment. # Doesn't apply if after a brace open or other CPP comments. nl_before_cpp_comment = 0 # unsigned number # Whether to force a newline after a multi-line comment. nl_after_multiline_comment = false # true/false # Whether to force a newline after a label's colon. nl_after_label_colon = false # true/false # The number of newlines after '}' or ';' of a struct/enum/union definition. nl_after_struct = 0 # unsigned number # The number of newlines before a class definition. nl_before_class = 0 # unsigned number # The number of newlines after '}' or ';' of a class definition. nl_after_class = 0 # unsigned number # The number of newlines before a namespace. #nl_before_namespace = 0 # unsigned number ### not 0.69 # The number of newlines after '{' of a namespace. This also adds newlines # before the matching '}'. # # 0: Apply eat_blanks_after_open_brace or eat_blanks_before_close_brace if # applicable, otherwise no change. # # Overrides eat_blanks_after_open_brace and eat_blanks_before_close_brace. nl_inside_namespace = 0 # unsigned number # The number of newlines after '}' of a namespace. #nl_after_namespace = 0 # unsigned number ### not 0.69 # The number of newlines before an access specifier label. This also includes # the Qt-specific 'signals:' and 'slots:'. Will not change the newline count # if after a brace open. # # 0: No change (default). nl_before_access_spec = 0 # unsigned number # The number of newlines after an access specifier label. This also includes # the Qt-specific 'signals:' and 'slots:'. Will not change the newline count # if after a brace open. # # 0: No change (default). # # Overrides nl_typedef_blk_start and nl_var_def_blk_start. nl_after_access_spec = 0 # unsigned number # The number of newlines between a function definition and the function # comment, as in '// comment\n void foo() {...}'. # # 0: No change (default). nl_comment_func_def = 0 # unsigned number # The number of newlines after a try-catch-finally block that isn't followed # by a brace close. # # 0: No change (default). nl_after_try_catch_finally = 0 # unsigned number # (C#) The number of newlines before and after a property, indexer or event # declaration. # # 0: No change (default). nl_around_cs_property = 0 # unsigned number # (C#) The number of newlines between the get/set/add/remove handlers. # # 0: No change (default). nl_between_get_set = 0 # unsigned number # (C#) Add or remove newline between property and the '{'. nl_property_brace = ignore # ignore/add/remove/force # Whether to remove blank lines after '{'. eat_blanks_after_open_brace = false # true/false # Whether to remove blank lines before '}'. eat_blanks_before_close_brace = false # true/false # How aggressively to remove extra newlines not in preprocessor. # # 0: No change (default) # 1: Remove most newlines not handled by other config # 2: Remove all newlines and reformat completely by config nl_remove_extra_newlines = 0 # unsigned number # (Java) Add or remove newline after an annotation statement. Only affects # annotations that are after a newline. nl_after_annotation = ignore # ignore/add/remove/force # (Java) Add or remove newline between two annotations. nl_between_annotation = ignore # ignore/add/remove/force # The number of newlines before a whole-file #ifdef. # # 0: No change (default). #nl_before_whole_file_ifdef = 0 # unsigned number ### not 0.69 # The number of newlines after a whole-file #ifdef. # # 0: No change (default). #nl_after_whole_file_ifdef = 0 # unsigned number ### not 0.69 # The number of newlines before a whole-file #endif. # # 0: No change (default). #nl_before_whole_file_endif = 0 # unsigned number ### not 0.69 # The number of newlines after a whole-file #endif. # # 0: No change (default). #nl_after_whole_file_endif = 0 # unsigned number ### not 0.69 # # Positioning options # # The position of arithmetic operators in wrapped expressions. pos_arith = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force # The position of assignment in wrapped expressions. Do not affect '=' # followed by '{'. pos_assign = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force # The position of Boolean operators in wrapped expressions. pos_bool = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force # The position of comparison operators in wrapped expressions. pos_compare = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force # The position of conditional operators, as in the '?' and ':' of # 'expr ? stmt : stmt', in wrapped expressions. pos_conditional = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force # The position of the comma in wrapped expressions. pos_comma = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force # The position of the comma in enum entries. pos_enum_comma = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force # The position of the comma in the base class list if there is more than one # line. Affects nl_class_init_args. pos_class_comma = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force # The position of the comma in the constructor initialization list. # Related to nl_constr_colon, nl_constr_init_args and pos_constr_colon. pos_constr_comma = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force # The position of trailing/leading class colon, between class and base class # list. Affects nl_class_colon. pos_class_colon = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force # The position of colons between constructor and member initialization. # Related to nl_constr_colon, nl_constr_init_args and pos_constr_comma. pos_constr_colon = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force # # Line splitting options # # Try to limit code width to N columns. code_width = 0 # unsigned number # Whether to fully split long 'for' statements at semi-colons. ls_for_split_full = false # true/false # Whether to fully split long function prototypes/calls at commas. # The option ls_code_width has priority over the option ls_func_split_full. ls_func_split_full = false # true/false # Whether to split lines as close to code_width as possible and ignore some # groupings. # The option ls_code_width has priority over the option ls_func_split_full. ls_code_width = false # true/false # # Code alignment options (not left column spaces/tabs) # # Whether to keep non-indenting tabs. align_keep_tabs = false # true/false # Whether to use tabs for aligning. align_with_tabs = false # true/false # Whether to bump out to the next tab when aligning. align_on_tabstop = false # true/false # Whether to right-align numbers. align_number_right = false # true/false # Whether to keep whitespace not required for alignment. align_keep_extra_space = false # true/false # Whether to align variable definitions in prototypes and functions. align_func_params = false # true/false # The span for aligning parameter definitions in function on parameter name. # # 0: Don't align (default). align_func_params_span = 0 # unsigned number # The threshold for aligning function parameter definitions. # Use a negative number for absolute thresholds. # # 0: No limit (default). align_func_params_thresh = 0 # number # The gap for aligning function parameter definitions. align_func_params_gap = 0 # unsigned number # The span for aligning constructor value. # # 0: Don't align (default). align_constr_value_span = 0 # unsigned number # The threshold for aligning constructor value. # Use a negative number for absolute thresholds. # # 0: No limit (default). align_constr_value_thresh = 0 # number # The gap for aligning constructor value. align_constr_value_gap = 0 # unsigned number # Whether to align parameters in single-line functions that have the same # name. The function names must already be aligned with each other. align_same_func_call_params = false # true/false # The span for aligning function-call parameters for single line functions. # # 0: Don't align (default). align_same_func_call_params_span = 0 # unsigned number # The threshold for aligning function-call parameters for single line # functions. # Use a negative number for absolute thresholds. # # 0: No limit (default). align_same_func_call_params_thresh = 0 # number # The span for aligning variable definitions. # # 0: Don't align (default). align_var_def_span = 0 # unsigned number # How to consider (or treat) the '*' in the alignment of variable definitions. # # 0: Part of the type 'void * foo;' (default) # 1: Part of the variable 'void *foo;' # 2: Dangling 'void *foo;' # Dangling: the '*' will not be taken into account when aligning. align_var_def_star_style = 0 # unsigned number # How to consider (or treat) the '&' in the alignment of variable definitions. # # 0: Part of the type 'long & foo;' (default) # 1: Part of the variable 'long &foo;' # 2: Dangling 'long &foo;' # Dangling: the '&' will not be taken into account when aligning. align_var_def_amp_style = 0 # unsigned number # The threshold for aligning variable definitions. # Use a negative number for absolute thresholds. # # 0: No limit (default). align_var_def_thresh = 0 # number # The gap for aligning variable definitions. align_var_def_gap = 0 # unsigned number # Whether to align the colon in struct bit fields. align_var_def_colon = false # true/false # The gap for aligning the colon in struct bit fields. align_var_def_colon_gap = 0 # unsigned number # Whether to align any attribute after the variable name. align_var_def_attribute = false # true/false # Whether to align inline struct/enum/union variable definitions. align_var_def_inline = false # true/false # The span for aligning on '=' in assignments. # # 0: Don't align (default). align_assign_span = 0 # unsigned number # The span for aligning on '=' in function prototype modifier. # # 0: Don't align (default). align_assign_func_proto_span = 0 # unsigned number # The threshold for aligning on '=' in assignments. # Use a negative number for absolute thresholds. # # 0: No limit (default). align_assign_thresh = 0 # number # How to apply align_assign_span to function declaration "assignments", i.e. # 'virtual void foo() = 0' or '~foo() = {default|delete}'. # # 0: Align with other assignments (default) # 1: Align with each other, ignoring regular assignments # 2: Don't align align_assign_decl_func = 0 # unsigned number # The span for aligning on '=' in enums. # # 0: Don't align (default). align_enum_equ_span = 0 # unsigned number # The threshold for aligning on '=' in enums. # Use a negative number for absolute thresholds. # # 0: no limit (default). align_enum_equ_thresh = 0 # number # The span for aligning class member definitions. # # 0: Don't align (default). align_var_class_span = 0 # unsigned number # The threshold for aligning class member definitions. # Use a negative number for absolute thresholds. # # 0: No limit (default). align_var_class_thresh = 0 # number # The gap for aligning class member definitions. align_var_class_gap = 0 # unsigned number # The span for aligning struct/union member definitions. # # 0: Don't align (default). align_var_struct_span = 0 # unsigned number # The threshold for aligning struct/union member definitions. # Use a negative number for absolute thresholds. # # 0: No limit (default). align_var_struct_thresh = 0 # number # The gap for aligning struct/union member definitions. align_var_struct_gap = 0 # unsigned number # The span for aligning struct initializer values. # # 0: Don't align (default). align_struct_init_span = 0 # unsigned number # The span for aligning single-line typedefs. # # 0: Don't align (default). align_typedef_span = 0 # unsigned number # The minimum space between the type and the synonym of a typedef. align_typedef_gap = 0 # unsigned number # How to align typedef'd functions with other typedefs. # # 0: Don't mix them at all (default) # 1: Align the open parenthesis with the types # 2: Align the function type name with the other type names align_typedef_func = 0 # unsigned number # How to consider (or treat) the '*' in the alignment of typedefs. # # 0: Part of the typedef type, 'typedef int * pint;' (default) # 1: Part of type name: 'typedef int *pint;' # 2: Dangling: 'typedef int *pint;' # Dangling: the '*' will not be taken into account when aligning. align_typedef_star_style = 0 # unsigned number # How to consider (or treat) the '&' in the alignment of typedefs. # # 0: Part of the typedef type, 'typedef int & intref;' (default) # 1: Part of type name: 'typedef int &intref;' # 2: Dangling: 'typedef int &intref;' # Dangling: the '&' will not be taken into account when aligning. align_typedef_amp_style = 0 # unsigned number # The span for aligning comments that end lines. # # 0: Don't align (default). align_right_cmt_span = 0 # unsigned number # Minimum number of columns between preceding text and a trailing comment in # order for the comment to qualify for being aligned. Must be non-zero to have # an effect. align_right_cmt_gap = 0 # unsigned number # If aligning comments, whether to mix with comments after '}' and #endif with # less than three spaces before the comment. align_right_cmt_mix = false # true/false # Whether to only align trailing comments that are at the same brace level. align_right_cmt_same_level = false # true/false # Minimum column at which to align trailing comments. Comments which are # aligned beyond this column, but which can be aligned in a lesser column, # may be "pulled in". # # 0: Ignore (default). align_right_cmt_at_col = 0 # unsigned number # The span for aligning function prototypes. # # 0: Don't align (default). align_func_proto_span = 0 # unsigned number # The threshold for aligning function prototypes. # Use a negative number for absolute thresholds. # # 0: No limit (default). align_func_proto_thresh = 0 # number # Minimum gap between the return type and the function name. align_func_proto_gap = 0 # unsigned number # Whether to align function prototypes on the 'operator' keyword instead of # what follows. align_on_operator = false # true/false # Whether to mix aligning prototype and variable declarations. If true, # align_var_def_XXX options are used instead of align_func_proto_XXX options. align_mix_var_proto = false # true/false # Whether to align single-line functions with function prototypes. # Uses align_func_proto_span. align_single_line_func = false # true/false # Whether to align the open brace of single-line functions. # Requires align_single_line_func=true. Uses align_func_proto_span. align_single_line_brace = false # true/false # Gap for align_single_line_brace. align_single_line_brace_gap = 0 # unsigned number # (OC) The span for aligning Objective-C message specifications. # # 0: Don't align (default). align_oc_msg_spec_span = 0 # unsigned number # Whether to align macros wrapped with a backslash and a newline. This will # not work right if the macro contains a multi-line comment. align_nl_cont = false # true/false # Whether to align macro functions and variables together. align_pp_define_together = false # true/false # The span for aligning on '#define' bodies. # # =0: Don't align (default) # >0: Number of lines (including comments) between blocks align_pp_define_span = 0 # unsigned number # The minimum space between label and value of a preprocessor define. align_pp_define_gap = 0 # unsigned number # Whether to align lines that start with '<<' with previous '<<'. # # Default: true align_left_shift = true # true/false # Whether to align text after 'asm volatile ()' colons. align_asm_colon = false # true/false # (OC) Span for aligning parameters in an Objective-C message call # on the ':'. # # 0: Don't align. align_oc_msg_colon_span = 0 # unsigned number # (OC) Whether to always align with the first parameter, even if it is too # short. align_oc_msg_colon_first = false # true/false # (OC) Whether to align parameters in an Objective-C '+' or '-' declaration # on the ':'. align_oc_decl_colon = false # true/false # (OC) Whether to not align parameters in an Objectve-C message call if first # colon is not on next line of the message call (the same way Xcode does # aligment) #align_oc_msg_colon_xcode_like = false # true/false ### not 0.69 # # Comment modification options # # Try to wrap comments at N columns. cmt_width = 0 # unsigned number # How to reflow comments. # # 0: No reflowing (apart from the line wrapping due to cmt_width) (default) # 1: No touching at all # 2: Full reflow cmt_reflow_mode = 0 # unsigned number # Whether to convert all tabs to spaces in comments. If false, tabs in # comments are left alone, unless used for indenting. cmt_convert_tab_to_spaces = false # true/false # Whether to apply changes to multi-line comments, including cmt_width, # keyword substitution and leading chars. # # Default: true cmt_indent_multi = true # true/false # Whether to group c-comments that look like they are in a block. cmt_c_group = false # true/false # Whether to put an empty '/*' on the first line of the combined c-comment. cmt_c_nl_start = false # true/false # Whether to add a newline before the closing '*/' of the combined c-comment. cmt_c_nl_end = false # true/false # Whether to change cpp-comments into c-comments. cmt_cpp_to_c = false # true/false # Whether to group cpp-comments that look like they are in a block. Only # meaningful if cmt_cpp_to_c=true. cmt_cpp_group = false # true/false # Whether to put an empty '/*' on the first line of the combined cpp-comment # when converting to a c-comment. # # Requires cmt_cpp_to_c=true and cmt_cpp_group=true. cmt_cpp_nl_start = false # true/false # Whether to add a newline before the closing '*/' of the combined cpp-comment # when converting to a c-comment. # # Requires cmt_cpp_to_c=true and cmt_cpp_group=true. cmt_cpp_nl_end = false # true/false # Whether to put a star on subsequent comment lines. cmt_star_cont = false # true/false # The number of spaces to insert at the start of subsequent comment lines. cmt_sp_before_star_cont = 0 # unsigned number # The number of spaces to insert after the star on subsequent comment lines. cmt_sp_after_star_cont = 0 # unsigned number # For multi-line comments with a '*' lead, remove leading spaces if the first # and last lines of the comment are the same length. # # Default: true cmt_multi_check_last = true # true/false # For multi-line comments with a '*' lead, remove leading spaces if the first # and last lines of the comment are the same length AND if the length is # bigger as the first_len minimum. # # Default: 4 cmt_multi_first_len_minimum = 4 # unsigned number # Path to a file that contains text to insert at the beginning of a file if # the file doesn't start with a C/C++ comment. If the inserted text contains # '$(filename)', that will be replaced with the current file's name. cmt_insert_file_header = "" # string # Path to a file that contains text to insert at the end of a file if the # file doesn't end with a C/C++ comment. If the inserted text contains # '$(filename)', that will be replaced with the current file's name. cmt_insert_file_footer = "" # string # Path to a file that contains text to insert before a function definition if # the function isn't preceded by a C/C++ comment. If the inserted text # contains '$(function)', '$(javaparam)' or '$(fclass)', these will be # replaced with, respectively, the name of the function, the javadoc '@param' # and '@return' stuff, or the name of the class to which the member function # belongs. cmt_insert_func_header = "" # string # Path to a file that contains text to insert before a class if the class # isn't preceded by a C/C++ comment. If the inserted text contains '$(class)', # that will be replaced with the class name. cmt_insert_class_header = "" # string # Path to a file that contains text to insert before an Objective-C message # specification, if the method isn't preceded by a C/C++ comment. If the # inserted text contains '$(message)' or '$(javaparam)', these will be # replaced with, respectively, the name of the function, or the javadoc # '@param' and '@return' stuff. cmt_insert_oc_msg_header = "" # string # Whether a comment should be inserted if a preprocessor is encountered when # stepping backwards from a function name. # # Applies to cmt_insert_oc_msg_header, cmt_insert_func_header and # cmt_insert_class_header. cmt_insert_before_preproc = false # true/false # Whether a comment should be inserted if a function is declared inline to a # class definition. # # Applies to cmt_insert_func_header. # # Default: true cmt_insert_before_inlines = true # true/false # Whether a comment should be inserted if the function is a class constructor # or destructor. # # Applies to cmt_insert_func_header. cmt_insert_before_ctor_dtor = false # true/false # # Code modifying options (non-whitespace) # # Add or remove braces on a single-line 'do' statement. mod_full_brace_do = remove # ignore/add/remove/force # Add or remove braces on a single-line 'for' statement. mod_full_brace_for = remove # ignore/add/remove/force # (Pawn) Add or remove braces on a single-line function definition. mod_full_brace_function = ignore # ignore/add/remove/force # Add or remove braces on a single-line 'if' statement. Braces will not be # removed if the braced statement contains an 'else'. mod_full_brace_if = add # ignore/add/remove/force # Whether to enforce that all blocks of an 'if'/'else if'/'else' chain either # have, or do not have, braces. If true, braces will be added if any block # needs braces, and will only be removed if they can be removed from all # blocks. # # Overrides mod_full_brace_if. mod_full_brace_if_chain = false # true/false # Whether to add braces to all blocks of an 'if'/'else if'/'else' chain. # If true, mod_full_brace_if_chain will only remove braces from an 'if' that # does not have an 'else if' or 'else'. mod_full_brace_if_chain_only = true # true/false # Add or remove braces on single-line 'while' statement. mod_full_brace_while = remove # ignore/add/remove/force # Add or remove braces on single-line 'using ()' statement. mod_full_brace_using = remove # ignore/add/remove/force # Don't remove braces around statements that span N newlines mod_full_brace_nl = 0 # unsigned number # Whether to prevent removal of braces from 'if'/'for'/'while'/etc. blocks # which span multiple lines. # # Affects: # mod_full_brace_for # mod_full_brace_if # mod_full_brace_if_chain # mod_full_brace_if_chain_only # mod_full_brace_while # mod_full_brace_using # # Does not affect: # mod_full_brace_do # mod_full_brace_function mod_full_brace_nl_block_rem_mlcond = false # true/false # Add or remove unnecessary parenthesis on 'return' statement. mod_paren_on_return = add # ignore/add/remove/force # (Pawn) Whether to change optional semicolons to real semicolons. mod_pawn_semicolon = false # true/false # Whether to fully parenthesize Boolean expressions in 'while' and 'if' # statement, as in 'if (a && b > c)' => 'if (a && (b > c))'. mod_full_paren_if_bool = false # true/false # Whether to remove superfluous semicolons. mod_remove_extra_semicolon = false # true/false # If a function body exceeds the specified number of newlines and doesn't have # a comment after the close brace, a comment will be added. mod_add_long_function_closebrace_comment = 0 # unsigned number # If a namespace body exceeds the specified number of newlines and doesn't # have a comment after the close brace, a comment will be added. mod_add_long_namespace_closebrace_comment = 0 # unsigned number # If a class body exceeds the specified number of newlines and doesn't have a # comment after the close brace, a comment will be added. mod_add_long_class_closebrace_comment = 0 # unsigned number # If a switch body exceeds the specified number of newlines and doesn't have a # comment after the close brace, a comment will be added. mod_add_long_switch_closebrace_comment = 0 # unsigned number # If an #ifdef body exceeds the specified number of newlines and doesn't have # a comment after the #endif, a comment will be added. mod_add_long_ifdef_endif_comment = 0 # unsigned number # If an #ifdef or #else body exceeds the specified number of newlines and # doesn't have a comment after the #else, a comment will be added. mod_add_long_ifdef_else_comment = 0 # unsigned number # Whether to take care of the case by the mod_sort_xx options. #mod_sort_case_sensitive = false # true/false ### not 0.69 # Whether to sort consecutive single-line 'import' statements. mod_sort_import = false # true/false # (C#) Whether to sort consecutive single-line 'using' statements. mod_sort_using = false # true/false # Whether to sort consecutive single-line '#include' statements (C/C++) and # '#import' statements (Objective-C). Be aware that this has the potential to # break your code if your includes/imports have ordering dependencies. mod_sort_include = false # true/false # Whether to prioritize '#include' and '#import' statements that contain # filename without extension when sorting is enabled. #mod_sort_incl_import_prioritize_filename = false # true/false ### not 0.69 # Whether to prioritize '#include' and '#import' statements that does not # contain extensions when sorting is enabled. #mod_sort_incl_import_prioritize_extensionless = false # true/false ### not 0.69 # Whether to prioritize '#include' and '#import' statements that contain # angle over quotes when sorting is enabled. #mod_sort_incl_import_prioritize_angle_over_quotes = false # true/false ### not 0.69 # Whether to ignore file extension in '#include' and '#import' statements # for sorting comparison. #mod_sort_incl_import_ignore_extension = false # true/false ### not 0.69 # Whether to group '#include' and '#import' statements when sorting is enabled. #mod_sort_incl_import_grouping_enabled = false # true/false ### not 0.69 # Whether to move a 'break' that appears after a fully braced 'case' before # the close brace, as in 'case X: { ... } break;' => 'case X: { ... break; }'. mod_move_case_break = false # true/false # Add or remove braces around a fully braced case statement. Will only remove # braces if there are no variable declarations in the block. mod_case_brace = ignore # ignore/add/remove/force # Whether to remove a void 'return;' that appears as the last statement in a # function. mod_remove_empty_return = false # true/false # Add or remove the comma after the last value of an enumeration. mod_enum_last_comma = ignore # ignore/add/remove/force # (OC) Whether to organize the properties. If true, properties will be # rearranged according to the mod_sort_oc_property_*_weight factors. mod_sort_oc_properties = false # true/false # (OC) Weight of a class property modifier. mod_sort_oc_property_class_weight = 0 # number # (OC) Weight of 'atomic' and 'nonatomic'. mod_sort_oc_property_thread_safe_weight = 0 # number # (OC) Weight of 'readwrite' when organizing properties. mod_sort_oc_property_readwrite_weight = 0 # number # (OC) Weight of a reference type specifier ('retain', 'copy', 'assign', # 'weak', 'strong') when organizing properties. mod_sort_oc_property_reference_weight = 0 # number # (OC) Weight of getter type ('getter=') when organizing properties. mod_sort_oc_property_getter_weight = 0 # number # (OC) Weight of setter type ('setter=') when organizing properties. mod_sort_oc_property_setter_weight = 0 # number # (OC) Weight of nullability type ('nullable', 'nonnull', 'null_unspecified', # 'null_resettable') when organizing properties. mod_sort_oc_property_nullability_weight = 0 # number # # Preprocessor options # # Add or remove indentation of preprocessor directives inside #if blocks # at brace level 0 (file-level). pp_indent = ignore # ignore/add/remove/force # Whether to indent #if/#else/#endif at the brace level. If false, these are # indented from column 1. pp_indent_at_level = false # true/false # Specifies the number of columns to indent preprocessors per level # at brace level 0 (file-level). If pp_indent_at_level=false, also specifies # the number of columns to indent preprocessors per level # at brace level > 0 (function-level). # # Default: 1 pp_indent_count = 1 # unsigned number # Add or remove space after # based on pp_level of #if blocks. pp_space = ignore # ignore/add/remove/force # Sets the number of spaces per level added with pp_space. pp_space_count = 0 # unsigned number # The indent for '#region' and '#endregion' in C# and '#pragma region' in # C/C++. Negative values decrease indent down to the first column. pp_indent_region = 0 # number # Whether to indent the code between #region and #endregion. pp_region_indent_code = false # true/false # If pp_indent_at_level=true, sets the indent for #if, #else and #endif when # not at file-level. Negative values decrease indent down to the first column. # # =0: Indent preprocessors using output_tab_size # >0: Column at which all preprocessors will be indented pp_indent_if = 0 # number # Whether to indent the code between #if, #else and #endif. pp_if_indent_code = false # true/false # Whether to indent '#define' at the brace level. If false, these are # indented from column 1. pp_define_at_level = false # true/false # Whether to ignore the '#define' body while formatting. pp_ignore_define_body = false # true/false # Whether to indent case statements between #if, #else, and #endif. # Only applies to the indent of the preprocesser that the case statements # directly inside of. # # Default: true pp_indent_case = true # true/false # Whether to indent whole function definitions between #if, #else, and #endif. # Only applies to the indent of the preprocesser that the function definition # is directly inside of. # # Default: true pp_indent_func_def = true # true/false # Whether to indent extern C blocks between #if, #else, and #endif. # Only applies to the indent of the preprocesser that the extern block is # directly inside of. # # Default: true pp_indent_extern = true # true/false # Whether to indent braces directly inside #if, #else, and #endif. # Only applies to the indent of the preprocesser that the braces are directly # inside of. # # Default: true pp_indent_brace = true # true/false # # Sort includes options # # The regex for include category with priority 0. include_category_0 = "" # string # The regex for include category with priority 1. include_category_1 = "" # string # The regex for include category with priority 2. include_category_2 = "" # string # # Use or Do not Use options # # true: indent_func_call_param will be used (default) # false: indent_func_call_param will NOT be used # # Default: true use_indent_func_call_param = true # true/false # The value of the indentation for a continuation line is calculated # differently if the statement is: # - a declaration: your case with QString fileName ... # - an assignment: your case with pSettings = new QSettings( ... # # At the second case the indentation value might be used twice: # - at the assignment # - at the function call (if present) # # To prevent the double use of the indentation value, use this option with the # value 'true'. # # true: indent_continue will be used only once # false: indent_continue will be used every time (default) use_indent_continue_only_once = false # true/false # The value might be used twice: # - at the assignment # - at the opening brace # # To prevent the double use of the indentation value, use this option with the # value 'true'. # # true: indentation will be used only once # false: indentation will be used every time (default) indent_cpp_lambda_only_once = false # true/false # Whether sp_after_angle takes precedence over sp_inside_fparen. This was the # historic behavior, but is probably not the desired behavior, so this is off # by default. #use_sp_after_angle_always = false # true/false ### not 0.69 # Whether to apply special formatting for Qt SIGNAL/SLOT macros. Essentially, # this tries to format these so that they match Qt's normalized form (i.e. the # result of QMetaObject::normalizedSignature), which can slightly improve the # performance of the QObject::connect call, rather than how they would # otherwise be formatted. # # See options_for_QT.cpp for details. # # Default: true use_options_overriding_for_qt_macros = true # true/false # If true: the form feed character is removed from the list # of whitespace characters. # See https://en.cppreference.com/w/cpp/string/byte/isspace #use_form_feed_no_more_as_whitespace_character = false # true/false ### not 0.69 # # Warn levels - 1: error, 2: warning (default), 3: note # # (C#) Warning is given if doing tab-to-\t replacement and we have found one # in a C# verbatim string literal. # # Default: 2 warn_level_tabs_found_in_verbatim_string_literals = 2 # unsigned number # Limit the number of loops. # Used by uncrustify.cpp to exit from infinite loop. # 0: no limit. #debug_max_number_of_loops = 0 # number ### not 0.69 # Set the number of the line to protocol; # Used in the function prot_the_line if the 2. parameter is zero. # 0: nothing protocol. #debug_line_number_to_protocol = 0 # number ### not 0.69 # Meaning of the settings: # Ignore - do not do any changes # Add - makes sure there is 1 or more space/brace/newline/etc # Force - makes sure there is exactly 1 space/brace/newline/etc, # behaves like Add in some contexts # Remove - removes space/brace/newline/etc # # # - Token(s) can be treated as specific type(s) with the 'set' option: # `set tokenType tokenString [tokenString...]` # # Example: # `set BOOL __AND__ __OR__` # # tokenTypes are defined in src/token_enum.h, use them without the # 'CT_' prefix: 'CT_BOOL' => 'BOOL' # # # - Token(s) can be treated as type(s) with the 'type' option. # `type tokenString [tokenString...]` # # Example: # `type int c_uint_8 Rectangle` # # This can also be achieved with `set TYPE int c_uint_8 Rectangle` # # # To embed whitespace in tokenStrings use the '\' escape character, or quote # the tokenStrings. These quotes are supported: "'` # # # - Support for the auto detection of languages through the file ending can be # added using the 'file_ext' command. # `file_ext langType langString [langString..]` # # Example: # `file_ext CPP .ch .cxx .cpp.in` # # langTypes are defined in uncrusify_types.h in the lang_flag_e enum, use # them without the 'LANG_' prefix: 'LANG_CPP' => 'CPP' # # # - Custom macro-based indentation can be set up using 'macro-open', # 'macro-else' and 'macro-close'. # `(macro-open | macro-else | macro-close) tokenString` # # Example: # `macro-open BEGIN_TEMPLATE_MESSAGE_MAP` # `macro-open BEGIN_MESSAGE_MAP` # `macro-close END_MESSAGE_MAP` # # # option(s) with 'not default' value: 0 # stlink-1.9.0/config/modprobe.d/000077500000000000000000000000001526027543100163305ustar00rootroot00000000000000stlink-1.9.0/config/modprobe.d/stlink_v1.conf000066400000000000000000000000461526027543100211110ustar00rootroot00000000000000options usb-storage quirks=483:3744:i stlink-1.9.0/config/udev/000077500000000000000000000000001526027543100152425ustar00rootroot00000000000000stlink-1.9.0/config/udev/rules.d/000077500000000000000000000000001526027543100166165ustar00rootroot00000000000000stlink-1.9.0/config/udev/rules.d/49-stlinkv1.rules000066400000000000000000000007271526027543100217050ustar00rootroot00000000000000# STM32 discovery boards, with onboard st/linkv1 # ie, STM32VL SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3744", \ MODE:="0666", \ SYMLINK+="stlinkv1_%n" # If you share your linux system with other users, or just don't like the # idea of write permission for everybody, you can replace MODE:="0666" with # OWNER:="yourusername" to create the device owned by you, or with # GROUP:="somegroupname" and mange access using standard unix groups. stlink-1.9.0/config/udev/rules.d/49-stlinkv2-1.rules000066400000000000000000000014101526027543100220320ustar00rootroot00000000000000# STM32 nucleo boards, with onboard st/linkv2-1 # ie, STM32F0, STM32F4. # STM32VL has st/linkv1, which is quite different SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374a", \ MODE:="0666", \ SYMLINK+="stlinkv2-1_%n" SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374b", \ MODE:="0666", \ SYMLINK+="stlinkv2-1_%n" SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3752", \ MODE:="0666", \ SYMLINK+="stlinkv2-1_%n" # If you share your linux system with other users, or just don't like the # idea of write permission for everybody, you can replace MODE:="0666" with # OWNER:="yourusername" to create the device owned by you, or with # GROUP:="somegroupname" and mange access using standard unix groups. stlink-1.9.0/config/udev/rules.d/49-stlinkv2.rules000066400000000000000000000010221526027543100216730ustar00rootroot00000000000000# STM32 discovery boards, with onboard st/linkv2 # ie, STM32L, STM32F4. # STM32VL has st/linkv1, which is quite different SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3748", \ MODE:="0666", \ SYMLINK+="stlinkv2_%n" # If you share your linux system with other users, or just don't like the # idea of write permission for everybody, you can replace MODE:="0666" with # OWNER:="yourusername" to create the device owned by you, or with # GROUP:="somegroupname" and mange access using standard unix groups. stlink-1.9.0/config/udev/rules.d/49-stlinkv3.rules000066400000000000000000000024161526027543100217040ustar00rootroot00000000000000# STLink V3SET in Dual CDC mode SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3752", \ MODE:="0666", \ SYMLINK+="stlinkv3_%n" # STLink V3SET in Dual CDC mode SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3753", \ MODE:="0666", \ SYMLINK+="stlinkv3_%n" # STLink V3SET MINIE SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3754", \ MODE:="0666", \ SYMLINK+="stlinkv3_%n" # STLink V3SET SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374d", \ MODE:="0666", \ SYMLINK+="stlinkv3_%n" # STLink V3SET SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374e", \ MODE:="0666", \ SYMLINK+="stlinkv3_%n" # STLink V3SET in normal mode SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374f", \ MODE:="0666", \ SYMLINK+="stlinkv3_%n" # STLink V3PWR SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3757", \ MODE:="0666", \ SYMLINK+="stlinkv3_%n" # If you share your linux system with other users, or just don't like the # idea of write permission for everybody, you can replace MODE:="0666" with # OWNER:="yourusername" to create the device owned by you, or with # GROUP:="somegroupname" and mange access using standard unix groups. stlink-1.9.0/contributors.txt000066400000000000000000000011041526027543100163240ustar00rootroot00000000000000List of contributors to the stlink project: [texane] Karl Palsson [karlp] Jerry Jacobs [xor-gate] Anton [Ant-ON] Uwe Bonnes [UweBonnes] Oleksiy Slyshyk [slyshykO] Guillaume Revaillot [grevaillot] John Hall [simplerobot] Cheng Guokai (Xim) [chenguokai] Peter Zotov [whitequark] Dave Murphy [WinterMute] James Walmsley [jameswalmsley] Andreas Michelis [a-michelis] Michael Pratt [prattmic] Jerry Nosky [jnosky] Roger Wolff [rewolff] Maxime Coquelin [mcoquelin-stm32] [hydroconstructor] Grzegorz Szymaszek [gszy] Hsu Pu [hsupu] Rutger Hendriks [rutgerhendriks] ... and many others stlink-1.9.0/debian/000077500000000000000000000000001526027543100142545ustar00rootroot00000000000000stlink-1.9.0/debian/.gitignore000066400000000000000000000001551526027543100162450ustar00rootroot00000000000000.debhelper *.log *.substvars debhelper-build-stamp files libstlink-dev libstlink stlink-gui stlink-tools tmp stlink-1.9.0/debian/changelog000066400000000000000000000200231526027543100161230ustar00rootroot00000000000000stlink (1.8.0-1~bpo12+1) bookworm-backports; urgency=medium * Rebuild for bookworm-backports. -- Luca Boccassi Mon, 27 May 2024 23:04:19 +0100 stlink (1.8.0-1) unstable; urgency=medium * Switch to gbp workflow, binary OSX blobs no longer included upstream * Merge tag 'upstream/1.8.0' into debian * Drop cross.patch, merged upstream * Install chips definitions in stlink-tools * Update symbols files for 1.8.0 -- Luca Boccassi Thu, 08 Feb 2024 19:28:19 +0000 stlink (1.7.0+ds-2) unstable; urgency=medium [ Debian Janitor ] * Remove constraints unnecessary since buster * Set upstream metadata fields: Bug-Database, Bug-Submit, Repository- Browse. * Update standards version to 4.6.2, no changes needed. [ Chris Hofstaedtler ] * use udev.pc to place udev rules (Closes: #1058829) -- Luca Boccassi Mon, 18 Dec 2023 15:01:19 +0100 stlink (1.7.0+ds-1) unstable; urgency=medium * Merge tag 'v1.7.0' into debian. (Closes: #984356) * Bump Standards-Version to 4.5.1, no changes. * Bump debhelper-compat to 13, no changes. * Update install files, paths have been fixed upstream. * Update symbols file for 1.7.0. -- Luca Boccassi Sun, 15 Aug 2021 14:23:25 +0100 stlink (1.6.1+ds-3) unstable; urgency=medium * Add cross.patch to fix cross-compilation. Thanks Helmut! (Closes: #973339) -- Luca Boccassi Thu, 29 Oct 2020 18:06:39 +0000 stlink (1.6.1+ds-2) unstable; urgency=medium * Update d/copyright to remove GPL-2+ stanza about flashloaders * Update upstream URLs for new Github org * Patch CMake's hard-coded define of XML gui file location (Closes: #963219) -- Luca Boccassi Sun, 21 Jun 2020 13:41:37 +0100 stlink (1.6.1+ds-1) unstable; urgency=medium * Merge tag 'v1.6.1' into debian * Update Files-Excluded in d/copyright for new layout * Fix d/watch intermediary file name * Drop cross.patch, merged upstream in v1.6.1 * Bump Build-Depends to cmake >= 3.4.2 * Add new symbols from upstream version 1.6.1 * Adjust install files, some files moved * Remove unused variable from d/rules * Generate pkgconfig file from d/rules, upstream doesn't do it * Switch to debhelper-compat 12 -- Luca Boccassi Sat, 06 Jun 2020 14:44:54 +0100 stlink (1.6.0+ds-1) unstable; urgency=medium * Merge tag 'v1.6.0' into debian * Bump Standards-Version to 4.5.0, no changes. * Update libstlink1 symbols file for 1.6.0. -- Luca Boccassi Tue, 25 Feb 2020 22:08:33 +0000 stlink (1.5.1+ds-2) unstable; urgency=medium * Mark library packages as Multi-Arch: same. * Apply cross.patch to fix cross-compiling the GUI. Thanks Helmut for the patch! (Closes: #941320) * Vcs-Git: add -b debian * Set Rules-Requires-Root: no * Bump Standards-Version to 4.4.0 -- Luca Boccassi Sun, 29 Sep 2019 12:50:58 +0100 stlink (1.5.1+ds-1) unstable; urgency=medium * Merge tag 'v1.5.1' into debian. See upstream changelog for info: https://github.com/texane/stlink/releases/tag/v1.5.1 * Mark packages as linux-any, other systems not supported. -- Luca Boccassi Fri, 28 Sep 2018 10:26:39 +0100 stlink (1.5.0+ds-1) unstable; urgency=medium * Upload to unstable. (Closes: #869421) -- Luca Boccassi Fri, 16 Mar 2018 16:56:17 +0000 stlink (1.5.0) unstable; urgency=medium [ Jerry Jacobs ] * README.md: Update version badge to v1.4.0 [ Viallard Anthony ] * Add support of STM32L496xx/4A6xx devices (#615) [ rdlim ] * Fix verification of flash error for STM32L496x device (#617) (#618) [ dflogeras ] * Add note about availability in Gentoo package manager (#622) [ yaofei zheng ] * update debian package version (#630) [ Lyle Cheatham ] * Minor formatting fix in FAQ section of README.md (#631) [ Vasiliy Glazov ] * README.md: Added information about Fedora and RedHat/CentOS packages. (#635) * Added LIB_INSTALL_DIR to correct libs install on 64-bit systems (#636) [ Gwenhael Goavec-Merou ] * fix write for microcontroler with RAM size less or equal to 32K (#637) [ Mateusz Krawiec ] * Fix memory map for stm32l496xx boards. (#639) [ Rüdiger Fortanier ] * Add unknown chip output (#641) [ Slyshyk Oleksiy ] * fix __FILE__ base name extraction, #628 (#648) [ texane ] * STM32F72xx73xx support, from bob.feretich@rafresearch.com [ Kirill Kolyshkin ] * debian/triggers: add (to run ldconfig) (#664) [ Slyshyk Oleksiy ] * Try to fix #666 issue (#667) * Try to fix 666 issue (#668) [ Jerry Jacobs ] * Update ChangeLog.md * Update README.md [ texane ] * STM32F042K6 Nucleo-32 Board reported to work, by frank@bauernoeppel.de [ Anatol Pomozov ] * Update .version file to match release number (#670) -- Anatol Pomozov Mon, 19 Feb 2018 11:00:29 -0800 libstlink (1.4.0) unstable; urgency=low * Major changes and added features - Add support for STM32L452 target (#608) - Initial support to compile with Microsoft Visual Studio 2017 (#602) - Added support for flashing second bank on STM32F10x_XL (#592) - Add support for STM32L011 target (#572) - Allow building of debian package with CPack (@xor-gate) * Updates and fixes - Fix compilation with GCC 7 (#590) - Skip GTK detection if we're cross-compiling (#588) - Fix possible memory leak (#570) - Fix building with mingw64 (#569, #610) - Update libusb to 1.0.21 for Windows (#562) - Fixing low-voltage flashing on STM32F7 parts. (#567) - Update libusb to 1.0.21 for Windows (#562) -- Andrew 'Necromant' Andrianov Sat, 01 Jul 2017 00:00:00 +0000 libstlink (1.3.1) unstable; urgency=low * Major changes and added features: - Add preliminary support for STM32L011 to see it after probe (chipid 0x457) (@xor-gate) - Strip full paths to source files in log (commit #2c0ab7f) - Add support for STM32F413 target (#549) - Add support for Semihosting SYS_READC (#546) * Updates and fixes: - Update documentation markdown files - Compilation fixes (#552) - Fix compilation when path includes spaces (#561) -- Andrew 'Necromant' Andrianov Sat, 25 Feb 2017 00:00:00 +0000 libstlink (1.3.0) unstable; urgency=low * Major changes and added features: - Deprecation of autotools (autoconf, automake) (@xor-gate) - Removal of undocumented st-term utility, which is now replaced by st-util ARM semihosting feature (#3fd0f09) - Add support for native debian packaging (#444, #485) - Add intel hex file reading for st-flash (#459) - Add --reset command to st-flash (#505) - Support serial numbers argument for st-util and st-flash for multi-programmer setups (#541) - Add kill ('k') command to gdb-server for st-util (#9804416) - Add manpages (generated with pandoc from Markdown) (#464) - Rewrite commandline parsing for st-flash (#459) - Add support for ARM semihosting to st-util (#454, #455) * Chip support added for: - STM32L432 (#501) - STM32F412 (#538) - STM32F410 (#9c635e4) - Add memory map for STM32F401XE (#460) - L0x Category 5 devices (#406) - Add L0 Category 2 device (chip id: 0x425) (#72b8e5e) * Updates and fixes: - Fixed STM32F030 erase error (#442) - Fixed Cygwin build (#68b0f3b) - Reset flash mass erase (MER) bit after mass erase for safety (#489) - Fix memory map for STM32F4 (@zulusw) - Fix STM32L-problem with flash loader (issue #390) (Tom de Boer) - st-util don't read target voltage on startup as it crashes STM32F100 (probably stlink/v1) (Greg Alexander) - Do a JTAG reset prior to reading CPU information when processor is in deep sleep (@andyg24) - Redesign of st-flash commandline options parsing (pull-request #459) (@dev26th) -- Andrew 'Necromant' Andrianov Sat, 28 Jan 2017 00:00:00 +0000 libstlink (1.2.1) unstable; urgency=low * Initial Debian-Packaged Release. -- Andrew 'Necromant' Andrianov Sat, 09 Jul 2016 23:16:07 +0300 stlink-1.9.0/debian/control000066400000000000000000000027241526027543100156640ustar00rootroot00000000000000Source: stlink Priority: optional Maintainer: Luca Boccassi Build-Depends: debhelper, pkgconf, systemd-dev, cmake (>= 3.20.0), libusb-1.0-0-dev (>= 1.0.24), libgtk-3-dev Standards-Version: 4.6.2 Rules-Requires-Root: no Section: electronics Homepage: https://github.com/stlink-org/stlink Vcs-Git: https://github.com/bluca/stlink.git -b debian Vcs-Browser: https://github.com/bluca/stlink Package: libstlink-dev Section: libdevel Architecture: linux-any Multi-Arch: same Depends: libstlink1 (= ${binary:Version}), ${misc:Depends} Description: Open source version of the STMicroelectronics STLINK Tools . This package contains the development files for stlink. Package: libstlink1 Section: libs Architecture: linux-any Multi-Arch: same Depends: ${shlibs:Depends}, ${misc:Depends} Description: Open source version of the STMicroelectronics STLINK Tools . This package contains the shared library for stlink. Package: stlink-tools Architecture: linux-any Depends: libstlink1 (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} Description: Open source version of the STMicroelectronics STLINK Tools . This package contains commandline utilities for stlink, modprobe and udev rules. Package: stlink-gui Architecture: linux-any Depends: libstlink1 (= ${binary:Version}), stlink-tools (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} Description: Open source version of the STMicroelectronics STLINK Tools . This package contains a GUI tool for stlink. stlink-1.9.0/debian/copyright000066400000000000000000000040071526027543100162100ustar00rootroot00000000000000Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: stlink Upstream-Contact: Nightwalker-87 <15526941+Nightwalker-87@users.noreply.github.com> Source: https://github.com/stlink-org/stlink Files: * Copyright: 2011-2024 The stlink project maintainers Martin Capitanio Fabien Lementec Jerry Jacobs Nightwalker-87 <15526941+Nightwalker-87@users.noreply.github.com> and many other contributors... License: BSD-3-clause Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: . * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Intel Corporation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. . THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.stlink-1.9.0/debian/gbp.conf000066400000000000000000000003641526027543100156760ustar00rootroot00000000000000[DEFAULT] debian-branch = debian upstream-branch = upstream pristine-tar = True sign-tags = True [import-orig] upstream-vcs-tag = v%(version)s [dch] customizations = /usr/share/doc/git-buildpackage/examples/wrap_cl.py git-log = --first-parentstlink-1.9.0/debian/libstlink-dev.install000066400000000000000000000001101526027543100204030ustar00rootroot00000000000000usr/include/* usr/lib/*/lib*.a usr/lib/*/pkgconfig/* usr/lib/*/lib*.so stlink-1.9.0/debian/libstlink1.install000066400000000000000000000000241526027543100177140ustar00rootroot00000000000000usr/lib/*/lib*.so.* stlink-1.9.0/debian/libstlink1.symbols000066400000000000000000000153541526027543100177520ustar00rootroot00000000000000libstlink.so.1 libstlink1 #MINVER# Md5Calculate@Base 1.6.1 Md5Finalise@Base 1.6.1 Md5Initialise@Base 1.6.1 Md5Update@Base 1.6.1 _parse_version@Base 1.5.0 _stlink_sg_close@Base 1.5.0 _stlink_sg_core_id@Base 1.5.0 _stlink_sg_current_mode@Base 1.5.0 _stlink_sg_enter_jtag_mode@Base 1.5.0 _stlink_sg_enter_swd_mode@Base 1.5.0 _stlink_sg_exit_debug_mode@Base 1.5.0 _stlink_sg_exit_dfu_mode@Base 1.5.0 _stlink_sg_force_debug@Base 1.5.0 _stlink_sg_jtag_reset@Base 1.5.0 _stlink_sg_read_all_regs@Base 1.5.0 _stlink_sg_read_debug32@Base 1.5.0 _stlink_sg_read_mem32@Base 1.5.0 _stlink_sg_read_reg@Base 1.5.0 _stlink_sg_reset@Base 1.5.0 _stlink_sg_run@Base 1.5.0 _stlink_sg_status@Base 1.5.0 _stlink_sg_step@Base 1.5.0 _stlink_sg_version@Base 1.5.0 _stlink_sg_write_debug32@Base 1.5.0 _stlink_sg_write_mem32@Base 1.5.0 _stlink_sg_write_mem8@Base 1.5.0 _stlink_sg_write_reg@Base 1.5.0 _stlink_usb_close@Base 1.5.0 _stlink_usb_core_id@Base 1.5.0 _stlink_usb_current_mode@Base 1.5.0 _stlink_usb_disable_trace@Base 1.7.0 _stlink_usb_enable_trace@Base 1.7.0 _stlink_usb_enter_swd_mode@Base 1.5.0 _stlink_usb_exit_debug_mode@Base 1.5.0 _stlink_usb_exit_dfu_mode@Base 1.5.0 _stlink_usb_force_debug@Base 1.5.0 _stlink_usb_get_rw_status@Base 1.6.1 _stlink_usb_jtag_reset@Base 1.5.0 _stlink_usb_read_all_regs@Base 1.5.0 _stlink_usb_read_all_unsupported_regs@Base 1.5.0 _stlink_usb_read_debug32@Base 1.5.0 _stlink_usb_read_mem32@Base 1.5.0 _stlink_usb_read_reg@Base 1.5.0 _stlink_usb_read_trace@Base 1.7.0 _stlink_usb_read_unsupported_reg@Base 1.5.0 _stlink_usb_reset@Base 1.5.0 _stlink_usb_run@Base 1.5.0 _stlink_usb_set_swdclk@Base 1.5.0 _stlink_usb_status@Base 1.5.0 _stlink_usb_status_v2@Base 1.6.1 _stlink_usb_step@Base 1.5.0 _stlink_usb_target_voltage@Base 1.5.0 _stlink_usb_version@Base 1.5.0 _stlink_usb_write_debug32@Base 1.5.0 _stlink_usb_write_mem32@Base 1.5.0 _stlink_usb_write_mem8@Base 1.5.0 _stlink_usb_write_reg@Base 1.5.0 _stlink_usb_write_unsupported_reg@Base 1.5.0 arg_parse_freq@Base 1.7.0 calculate_F4_sectornum@Base 1.5.0 calculate_F7_sectornum@Base 1.5.0 calculate_H7_sectornum@Base 1.7.0 calculate_L4_page@Base 1.5.0 check_file@Base 1.8.0 check_flash_error@Base 1.8.0 clear_flash_cr_pg@Base 1.8.0 clear_flash_error@Base 1.8.0 dump_a_chip@Base 1.8.0 get_stm32l0_flash_base@Base 1.8.0 init_chipids@Base 1.8.0 #MISSING: 1.7.0# is_bigendian@Base 1.5.0 is_flash_busy@Base 1.8.0 lock_flash@Base 1.8.0 lock_flash_option@Base 1.8.0 map_file@Base 1.8.0 md5_calculate@Base 1.8.0 process_chipfile@Base 1.8.0 read_flash_cr@Base 1.8.0 read_flash_sr@Base 1.8.0 read_uint16@Base 1.5.0 read_uint32@Base 1.5.0 send_recv@Base 1.5.0 send_usb_data_only@Base 1.5.0 send_usb_mass_storage_command@Base 1.5.0 stlink_calculate_pagesize@Base 1.5.0 stlink_check_address_alignment@Base 1.8.0 stlink_check_address_range_validity@Base 1.8.0 stlink_check_address_range_validity_otp@Base 1.8.0 stlink_checksum@Base 1.8.0 stlink_chip_id@Base 1.5.0 stlink_chipid_get_params@Base 1.5.0 stlink_close@Base 1.5.0 stlink_clr_hw_bp@Base 1.5.0 stlink_core_id@Base 1.5.0 stlink_core_stat@Base 1.5.0 stlink_cpu_id@Base 1.5.0 stlink_current_mode@Base 1.5.0 stlink_enter_swd_mode@Base 1.5.0 stlink_erase_flash_mass@Base 1.5.0 stlink_erase_flash_page@Base 1.5.0 stlink_erase_flash_section@Base 1.8.0 stlink_exit_debug_mode@Base 1.5.0 stlink_exit_dfu_mode@Base 1.5.0 stlink_fcheck_flash@Base 1.5.0 stlink_flash_loader_init@Base 1.5.0 stlink_flash_loader_run@Base 1.5.0 stlink_flash_loader_write_to_sram@Base 1.5.0 stlink_flashloader_start@Base 1.7.0 stlink_flashloader_stop@Base 1.7.0 stlink_flashloader_write@Base 1.7.0 stlink_force_debug@Base 1.5.0 stlink_fread@Base 1.5.0 stlink_fwrite_finalize@Base 1.8.0 stlink_fwrite_flash@Base 1.5.0 stlink_fwrite_option_bytes@Base 1.6.0 #MISSING: 1.6.1# stlink_fwrite_option_bytes_32bit@Base 1.6.0 stlink_fwrite_sram@Base 1.5.0 stlink_get_erased_pattern@Base 1.5.0 stlink_is_core_halted@Base 1.5.0 stlink_jtag_reset@Base 1.5.0 stlink_load_device_params@Base 1.5.0 stlink_mwrite_flash@Base 1.5.0 stlink_mwrite_sram@Base 1.5.0 stlink_open_usb@Base 1.5.0 stlink_parse_ihex@Base 1.5.0 stlink_print_data@Base 1.5.0 stlink_probe_usb@Base 1.5.0 stlink_probe_usb_free@Base 1.5.0 stlink_q@Base 1.5.0 stlink_read_all_regs@Base 1.5.0 stlink_read_all_unsupported_regs@Base 1.5.0 stlink_read_debug32@Base 1.5.0 stlink_read_mem32@Base 1.5.0 stlink_read_option_bytes32@Base 1.6.1 #MISSING: 1.8.0# stlink_read_option_bytes_Gx@Base 1.6.1 stlink_read_option_bytes_boot_add32@Base 1.7.0 stlink_read_option_bytes_boot_add_f7@Base 1.7.0 stlink_read_option_bytes_f2@Base 1.6.0 stlink_read_option_bytes_f4@Base 1.6.0 stlink_read_option_bytes_f7@Base 1.7.0 stlink_read_option_bytes_generic@Base 1.6.1 stlink_read_option_bytes_gx@Base 1.8.0 stlink_read_option_control_register1_32@Base 1.7.0 stlink_read_option_control_register1_f7@Base 1.7.0 stlink_read_option_control_register32@Base 1.7.0 #MISSING: 1.8.0# stlink_read_option_control_register_Gx@Base 1.7.0 stlink_read_option_control_register_f0@Base 1.8.0 stlink_read_option_control_register_f2@Base 1.7.0 stlink_read_option_control_register_f4@Base 1.7.0 stlink_read_option_control_register_f7@Base 1.7.0 stlink_read_option_control_register_gx@Base 1.8.0 stlink_read_option_control_register_wb@Base 1.8.0 stlink_read_reg@Base 1.5.0 stlink_read_unsupported_reg@Base 1.5.0 stlink_reset@Base 1.5.0 stlink_run@Base 1.5.0 stlink_run_at@Base 1.5.0 stlink_serial@Base 1.7.0 stlink_set_hw_bp@Base 1.5.0 stlink_set_swdclk@Base 1.5.0 stlink_soft_reset@Base 1.7.0 stlink_stat@Base 1.5.0 stlink_status@Base 1.5.0 stlink_step@Base 1.5.0 stlink_target_connect@Base 1.7.0 stlink_target_voltage@Base 1.5.0 #MISSING: 1.8.0# stlink_trace_disable@Base 1.7.0 #MISSING: 1.8.0# stlink_trace_enable@Base 1.7.0 #MISSING: 1.8.0# stlink_trace_read@Base 1.7.0 stlink_v1_open@Base 1.5.0 stlink_v1_open_inner@Base 1.5.0 stlink_verify_write_flash@Base 1.5.0 stlink_version@Base 1.5.0 stlink_write_debug32@Base 1.5.0 stlink_write_dreg@Base 1.5.0 stlink_write_flash@Base 1.5.0 stlink_write_mem32@Base 1.5.0 stlink_write_mem8@Base 1.5.0 stlink_write_option_bytes32@Base 1.6.1 stlink_write_option_bytes@Base 1.6.0 stlink_write_option_bytes_boot_add32@Base 1.7.0 stlink_write_option_control_register1_32@Base 1.7.0 stlink_write_option_control_register32@Base 1.7.0 stlink_write_otp@Base 1.8.0 stlink_write_reg@Base 1.5.0 stlink_write_unsupported_reg@Base 1.5.0 stm32l1_write_half_pages@Base 1.5.0 time_ms@Base 1.7.0 ugly_init@Base 1.5.0 ugly_libusb_log_level@Base 1.6.1 ugly_log@Base 1.5.0 unlock_flash_if@Base 1.8.0 unlock_flash_option_if@Base 1.8.0 unmap_file@Base 1.8.0 wait_flash_busy@Base 1.8.0 write_buffer_to_sram@Base 1.5.0 write_flash_cr_psiz@Base 1.8.0 write_uint16@Base 1.5.0 write_uint32@Base 1.5.0stlink-1.9.0/debian/rules000077500000000000000000000016431526027543100153400ustar00rootroot00000000000000#!/usr/bin/make -f # See debhelper(7) (uncomment to enable) # output every command that modifies files on the build system. #DH_VERBOSE = 1 # see EXAMPLES in dpkg-buildflags(1) and read /usr/share/dpkg/* DPKG_EXPORT_BUILDFLAGS = 1 include /usr/share/dpkg/default.mk # see FEATURE AREAS in dpkg-buildflags(1) export DEB_BUILD_MAINT_OPTIONS = hardening=+all export deb_udevdir = $(shell pkg-config --variable=udevdir udev | sed s,^/,,) %: dh $@ --buildsystem cmake override_dh_auto_configure: dh_auto_configure -- \ -DSTLINK_UDEV_RULES_DIR='/lib/udev/rules.d' -DSTLINK_UDEV_RULES_DIR=/$(deb_udevdir)/rules.d override_dh_auto_install: dh_auto_install mkdir -p $(CURDIR)/debian/tmp/usr/lib/$(DEB_HOST_MULTIARCH)/pkgconfig sed -e "s/@VERSION@/$(DEB_VERSION_UPSTREAM)/" -e "s/@DEB_HOST_MULTIARCH@/$(DEB_HOST_MULTIARCH)/" $(CURDIR)/debian/stlink.pc.in > $(CURDIR)/debian/tmp/usr/lib/$(DEB_HOST_MULTIARCH)/pkgconfig/stlink.pc stlink-1.9.0/debian/source/000077500000000000000000000000001526027543100155545ustar00rootroot00000000000000stlink-1.9.0/debian/source/format000066400000000000000000000000141526027543100167620ustar00rootroot000000000000003.0 (quilt) stlink-1.9.0/debian/source/options000066400000000000000000000000511526027543100171660ustar00rootroot00000000000000extend-diff-ignore=stlinkv1_macos_driver stlink-1.9.0/debian/stlink-gui.install000066400000000000000000000002251526027543100177310ustar00rootroot00000000000000/usr/bin/stlink-gui /usr/share/applications/stlink-gui.desktop /usr/share/icons/hicolor/scalable/apps/stlink-gui.svg /usr/share/stlink/stlink-gui.ui stlink-1.9.0/debian/stlink-tools.install000066400000000000000000000001351526027543100203050ustar00rootroot00000000000000/usr/bin/st-* ${env:deb_udevdir}/rules.d/*.rules etc/modprobe.d/*.conf usr/share/stlink/chipsstlink-1.9.0/debian/stlink-tools.manpages000066400000000000000000000001671526027543100204370ustar00rootroot00000000000000usr/share/man/man1/st-flash.1 usr/share/man/man1/st-info.1 usr/share/man/man1/st-util.1 usr/share/man/man1/st-server.1 stlink-1.9.0/debian/stlink.pc.in000066400000000000000000000004141526027543100165100ustar00rootroot00000000000000prefix=/usr includedir=${prefix}/include/stlink libdir=${prefix}/lib/@DEB_HOST_MULTIARCH@ Name: stlink Description: Open source version of the STMicroelectronics ST-LINK Tools Version: @VERSION@ Requires: libusb-1.0 Libs: -L${libdir} -lstlink Cflags: -I${includedir} stlink-1.9.0/debian/upstream/000077500000000000000000000000001526027543100161145ustar00rootroot00000000000000stlink-1.9.0/debian/upstream/metadata000066400000000000000000000002611526027543100176160ustar00rootroot00000000000000--- Bug-Database: https://github.com/stlink-org/stlink/issues Bug-Submit: https://github.com/stlink-org/stlink/issues/new Repository-Browse: https://github.com/stlink-org/stlinkstlink-1.9.0/debian/watch000066400000000000000000000002171526027543100153050ustar00rootroot00000000000000version=3 opts=filenamemangle=s/.+\/v?(\d\S+)\.tar\.gz/stlink-$1\.tar\.gz/ \ https://github.com/stlink-org/stlink/tags .*/v?(\d\S+)\.tar\.gz stlink-1.9.0/doc/000077500000000000000000000000001526027543100135775ustar00rootroot00000000000000stlink-1.9.0/doc/backend.md000066400000000000000000000154351526027543100155200ustar00rootroot00000000000000# stlink-lib backend notes This directory contains the transport backends used by the common stlink code. The common code drives targets through `stlink_backend_t` function pointers; backend implementations translate those operations into the actual transport. The main backends are: - `usb.c`: native USB/libusb ST-LINK backend. - `sg_legacy.c`: legacy SCSI passthrough backend. - `remote.c`: TCP backend used by `st-server` and client-side `--remote`. ## Remote Backend The remote backend lets a client tool drive an ST-LINK attached to another machine. The server process owns the real USB connection. The client runs the normal stlink logic: connect mode, chip detection, flash erase, program, verify, and GDB server behavior. `st-server` only forwards backend operations. Target policy remains in the client. Typical flow: 1. `st-server` opens a local ST-LINK with the USB backend. 2. A client opens `st-flash --remote HOST:PORT`, `st-info --remote HOST:PORT`, or `st-util --remote HOST:PORT`. 3. The server sends a handshake with protocol and ST-LINK version data. 4. The client creates a `stlink_t` using the remote backend. 5. Common code calls backend operations on the client. 6. `remote.c` serializes those calls over TCP. 7. The server dispatches each RPC to the real USB backend and sends the result back. ## Device Ownership One `st-server` serves one already-open ST-LINK. To serve multiple probes, run multiple server processes on different ports: ```sh st-server --serial aaa --port 4500 st-server --serial bbb --port 4501 ``` This keeps each probe independent. A long `st-util` session or flash operation on one probe cannot block another probe behind the same server process. ## Protocol All integer fields are little-endian and encoded with `read_uint32()` and `write_uint32()`. Handshake, server to client: ```text magic u32 protocol_version u32 capabilities u32 stlink_v u32 jtag_v u32 swim_v u32 st_vid u32 stlink_pid u32 jtag_api u32 flags u32 max_trace_freq u32 serial char[STLINK_REMOTE_SERIAL_WIRE_LEN] ``` `protocol_version` is currently `STLINK_REMOTE_PROTOCOL_VERSION`. `capabilities` is reserved for future optional protocol features and is currently sent as zero. The `serial` field has a fixed on-wire size, `STLINK_REMOTE_SERIAL_WIRE_LEN`. This is separate from the internal `STLINK_SERIAL_BUFFER_SIZE`, so the protocol layout does not change if the internal buffer changes. The server zero-pads the field and a compile-time check (`remote.h`) guarantees the buffer fits. If the wire size ever has to grow, bump `STLINK_REMOTE_PROTOCOL_VERSION`. Request, client to server: ```text op u32 ap u32 arg0 u32 arg1 u32 payload_len u32 payload bytes ``` Reply, server to client: ```text status u32 ret i32 payload_len u32 payload bytes ``` `status` describes the remote protocol result. `ret` is the backend return value and is valid when `status == REMOTE_REPLY_OK`, even when the backend returned `-1`. Protocol errors use `REMOTE_REPLY_PROTOCOL_ERROR`. Transport errors are not represented in the protocol. Once the TCP stream has failed, it cannot reliably carry a reply. `send_all()` and `recv_all()` log TCP errors locally. ## Register Encoding The remote protocol does not send C structs directly. `struct stlink_reg` is encoded field-by-field as fixed little-endian `u32` values. This avoids depending on compiler padding, host ABI, or host endianness. If `struct stlink_reg` changes, update both `reg_to_wire()` and `reg_from_wire()` in `remote.c`. If the wire layout changes incompatibly, bump `STLINK_REMOTE_PROTOCOL_VERSION`. ## Access Ports The client owns the logical AP state. Each RPC carries the client's current `sl->ap`, and the server applies it before dispatching the backend operation. When common code calls `backend->init_ap()`, the remote backend sends `RPC_INIT_AP`; the server then calls the real USB backend's `init_ap()`. Therefore AP selection decisions stay client-side, while ST-LINK USB commands are executed server-side. ## Connect Mode And Reset Connect mode (normal, hot-plug, connect-under-reset) is handled by the client over RPC. `st-server` has no `--connect-under-reset` flag: - The server's `stlink_open_usb()` opens the *ST-LINK USB device* and returns a valid handle even when the target connection fails. Target firmware cannot stop the server from claiming the probe; it can only fail the *target* connect, which the server does not need. - The connect sequence is transport-agnostic and runs on the client over RPC. When a client uses `--connect-under-reset`, `stlink_open_remote()` mirrors the tail of `stlink_open_usb()`: it asserts `NRST` low (`RPC_JTAG_RESET`), then runs `stlink_target_connect()` (enter SWD, probe AP, halt/reset). The reset sequence is issued on the real probe, over RPC. Use client-side `--connect-under-reset` when firmware prevents normal attach: ```sh st-flash --remote HOST:PORT --connect-under-reset write firmware.bin 0x08000000 ``` Server-side reset policy would duplicate client connect logic and reset the target on each server start. This still relies on `NRST` being wired, as local `--connect-under-reset` does. ## Trace (SWO) SWO/SWV trace works over the remote backend. `trace_enable`/`trace_disable` are plain RPCs; `trace_read` is a variable-length read where the reply's `ret` is the captured byte count and the payload carries the bytes (0 = none available). `st-trace --remote HOST:PORT` then behaves like the local tool. Unlike flash and debug, trace is **best-effort**. It is a continuous stream and the ST-LINK has a finite trace FIFO, so every `trace_read` poll is a network round trip. On a LAN or SSH tunnel (with `TCP_NODELAY`, which the backend sets) polling keeps up with typical SWO rates; on a high-latency link the FIFO can overflow and trace bytes are dropped silently. Use trace over remote on low-latency links only. ## Bind Address And Security The protocol has no authentication or encryption. Any client that can reach the port has full debug/flash control of the probe. `st-server` defaults to the loopback bind `127.0.0.1:4500`. Use an SSH tunnel to keep the server bound to loopback while adding authentication and encryption. ```sh # on the host with the probe: st-server # on the client: ssh -N -L 4500:127.0.0.1:4500 user@probe-host & st-flash --remote 127.0.0.1:4500 write fw.bin 0x08000000 ``` Only bind to `0.0.0.0` (or `--bind=:PORT`) on a trusted, isolated network. ## Shutdown And Recovery `st-server` handles `SIGINT` and `SIGTERM` by leaving the accept loop and closing the ST-LINK handle through the normal `stlink_close()` path. This keeps normal shutdowns clean. Forced termination, crashes, or a killed process during a USB transfer can still leave the ST-LINK firmware or USB endpoint unresponsive. If local tools such as `st-info --probe` also hang, reset the USB device with `usbreset` or physically replug the probe. stlink-1.9.0/doc/compiling.md000066400000000000000000000201411526027543100161000ustar00rootroot00000000000000# Compiling from sources ## Microsoft Windows - MSVC ### Common Requirements Install the following tools: - `git`, available on `PATH`. - [CMake](https://cmake.org/download/), available on `PATH`: 4.2 or newer for the [Visual Studio 2026 generator](https://cmake.org/cmake/help/latest/generator/Visual%20Studio%2018%202026.html), or 3.21 or newer for the [Visual Studio 2022 generator](https://cmake.org/cmake/help/latest/generator/Visual%20Studio%2017%202022.html). - Visual Studio 2026 (VS 18) or Visual Studio 2022 (VS 17), including their Build Tools editions, with the **Desktop development with C++** workload, MSVC x64/x86 tools and a Windows SDK. - [vcpkg](https://learn.microsoft.com/en-us/vcpkg/get_started/get-started-vs), to install the dependencies listed in the project's `vcpkg.json`. ### Installation The following commands use PowerShell. Use directories you can write to; building does not require an administrator terminal. If vcpkg is not installed, clone and bootstrap it: ```powershell $env:VCPKG_ROOT = "$env:USERPROFILE\vcpkg" git clone https://github.com/microsoft/vcpkg.git "$env:VCPKG_ROOT" & "$env:VCPKG_ROOT\bootstrap-vcpkg.bat" ``` If you already have vcpkg, set `VCPKG_ROOT` to that installation instead, for example: ```powershell $env:VCPKG_ROOT = "D:\vcpkg" ``` Set `VCPKG_ROOT` in each new terminal session, or save it as a user environment variable. Fetch the project source files and enter the repository root: ```powershell git clone https://github.com/stlink-org/stlink.git cd stlink ``` ### Building From the repository root, run: ```powershell .\gen_binaries_msvc.bat ``` The script uses `vswhere`, supplied by the Visual Studio Installer, to detect VS 18 with the C++ tools installed. It prefers VS 18; if none is found, it tries VS 17. It configures x64 and builds Release. Each version uses a separate build directory so that switching versions does not conflict with a cached CMake generator: | Visual Studio | Build directory | | --- | --- | | VS 18 (2026) | `build/msvc-vcpkg-vs18` | | VS 17 (2022) | `build/msvc-vcpkg-vs17` | During configuration, vcpkg installs `libusb` and `pthreads` from `vcpkg.json` into the selected build directory's `vcpkg_installed` subdirectory. CMake selects PThreads4W for MSVC and links the matching Release or Debug dependency libraries. The Windows compatibility headers supply the required POSIX types. The equivalent manual commands for VS 18 are below. For VS 17, replace the generator with `Visual Studio 17 2022` and use `build/msvc-vcpkg-vs17` in the commands below. ```powershell cmake -S . -B build/msvc-vcpkg-vs18 -G "Visual Studio 18 2026" -A x64 "-DCMAKE_TOOLCHAIN_FILE=$env:VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake" cmake --build build/msvc-vcpkg-vs18 --config Release ``` Visual Studio uses `--config` to select the build configuration. To build Debug using the same configured tree: ```powershell cmake --build build/msvc-vcpkg-vs18 --config Debug ``` The executables are in the selected build directory's `bin/Release` or `bin/Debug` subdirectory. With vcpkg's default settings, the required dependency DLLs are copied beside them during the build. For example, check the Release build with: ```powershell .\build\msvc-vcpkg-vs18\bin\Release\st-info.exe --version ``` If an existing build directory was configured with a different generator, architecture or toolchain, use a new build directory for the manual commands. **NOTE:** 1. [ST-LINK drivers](https://www.st.com/en/development-tools/stsw-link009.html) are required for programmers to work with `stlink`. 2. Package generation for MSVC is not yet implemented/tested. ## Linux ### Common requirements Install the following packages from your package repository: - `git` - `gcc` and `g++` or `clang` (C-compiler) - `make` (Build tool) - `build-essential` (_recommended_, on Debian based distros, contains `gcc`, `g++`, `libc6-dev`, `make`) - `cmake` (Software development tool) - `libusb-1.0-0` and `libusb-1.0-0-dev` (libusb and related development headers) - `libgtk-3-dev` (_optional_, needed for `stlink-gui`) - `rpm` (on Debian based distros, needed for package build with `make package`) - `pandoc` (_optional_, needed for generating manpages from markdown) ### Installation 1. Open a new terminal console 2. Create a new destination folder at a place of your choice e.g. at `~/git`: `mkdir $HOME/git` 3. Change to this directory: `cd ~/git` 4. Fetch the project sourcefiles by running `git clone https://github.com/stlink-org/stlink.git` ### Building #### Installation: 1. Change into the project source directory: `cd stlink` 2. Run `make clean` -- required by some linux variants. 3. Run `make release` to create the _Release_ target. 4. Run `make install` to full install the package with complete system integration. This might require sudo permissions. 5. Run `make debug` to create the _Debug_ target (_optional_)
The debug target is only necessary in order to modify the sources and to run under a debugger. 6. Run `make package`to build a Debian Package. The generated packages can be found in the subdirectory `./build/Release/dist`. 7. Installing system-wide (`sudo make install`) requires the dynamic library cache to be updated with `sudo ldconfig` afterwards. As an option you may also install to an individual user-defined folder e.g `$HOME` with `make install DESTDIR=$HOME`. #### Removal: 1. Run `make uninstall` to perform a clean uninstall of the package from the system. 2. Run `make clean` to clean the build-folder within the project source and remove all compiled and linked files and libraries. ### Cross-Building for Windows Install the following packages from your package repository: - `mingw-w64`, `autotools-dev` and `libtool` After following the steps for installation above, proceed with from the build dircetory itself: ```sh $ sudo sh ./gen_binaries_win.sh ``` The generated zip-packages can be found in the subdirectory `./build/dist`. ### Set device access permissions and the role of udev By default most distributions don't allow access to USB devices. In this context udev rules, which create devices nodes, are necessary to run the tools without root permissions. To achieve this you need to ensure that the group `plugdev` exists and the user who is trying to access these devices is a member of this group. Within the sourcefolder of the project, these rules are located in the subdirectory `config/udev/rules.d` and are automatically installed along with `sudo make install` on linux. Afterwards it may be necessary to reload the udev rules: ```sh $ sudo cp -a config/udev/rules.d/* /lib/udev/rules.d/ $ sudo udevadm control --reload-rules $ sudo udevadm trigger ``` udev will now create device node files, e.g. `/dev/stlinkv3_XX`, `/dev/stlinkv2_XX`, `/dev/stlinkv1_XX`. ### Special note on the use of STLink/V1 programmers (legacy): As the STLINKV1's SCSI emulation is somehow broken, the best advice possibly is to tell your operating system to completely ignore it.
Choose one of the following options _before_ connecting the device to your computer: - `modprobe -r usb-storage && modprobe usb-storage quirks=483:3744:i` - _OR_ 1. `echo "options usb-storage quirks=483:3744:i" >> /etc/modprobe.conf` 2. `modprobe -r usb-storage && modprobe usb-storage` - _OR_ 1. `cp stlink_v1.modprobe.conf /etc/modprobe.d` 2. `modprobe -r usb-storage && modprobe usb-storage` ## Build options ### Build using a different directory for shared libs To put the compiled shared libs into a different directory during installation, you can use the cmake option `cmake -DLIB_INSTALL_DIR:PATH="/usr/lib64" ..`. ### Standard installation directories The cmake build system of this toolset includes `GNUInstallDirs` to define GNU standard installation directories. This module provides install directory variables as defined by the GNU Coding Standards. Below are the preset default cmake options, which apply if none of these options are redefined: - `-DCMAKE_INSTALL_SYSCONFDIR=/etc` - `-DCMAKE_INSTALL_PREFIX=/usr/local` Please refer to the related [cmake documentation](https://cmake.org/cmake/help/latest/variable/CMAKE_INSTALL_PREFIX.html) for details. Author: nightwalker-87 stlink-1.9.0/doc/flashloaders.md000066400000000000000000000073361526027543100166010ustar00rootroot00000000000000# Flashloaders ## What do flashloaders do The on-chip FLASH of STM32 needs to be written once a byte/half word/word/double word, which would lead to a unbearably long flashing time if the process is solely done by `stlink` from the host side. Flashloaders are introduced to cooperate with `stlink` so that the flashing process is divided into two stages. In the first stage, `stlink` loads flashloaders and flash data to SRAM where busy check is not applied. In the second stage, flashloaders are kick-started, writing data from SRAM to FLASH, where a busy check is applied. Thus the write-check\_if\_busy cycle of flashing is done solely by STM32 chip, which saves considerable time in communications between `stlink` and STM32. As SRAM is usually less in size than FLASH, `stlink` only flashes one page (may be less if SRAM is insufficient) at a time. The whole flashing process may consist of server launches of flashloaders. ## The flashing process 1. `st-flash` loads compiled binary of corresponding flashloader to SRAM by calling `stlink_flash_loader_init` in `src/flash_loader.c` 2. `st-flash` erases corresponding flash page by calling `stlink_erase_flash_page` in `common_legacy.c`. 3. `st-flash` calls `stlink_flash_loader_run` in `flash_loader.c`. In this function + buffer of one flash page is written to SRAM following the flashloader + the buffer start address (in SRAM) is written to register `r0` + the target start address (in FLASH, page aligned) is written to register `r1` + the buffer size is written to register `r2` + the start address (for now 0x20000000) of flash loader is written to `r15` (`pc`) + After that, launching the flashloader and waiting for a halted core (triggered by our flashloader) and confirming that flashing is completed with a zeroed `r2` 4. flashloader part: much like a `memcpy` with busy check + copy a single unit of data from SRAM to FLASH + (for most devices) wait until flash is not busy + trigger a breakpoint which halts the core when finished ## Constraints Thus for developers who want to modify flashloaders, the following constraints should be satisfied. * only thumb-1 (for stm32f0 etc) or (thumb-1 and thumb-2) (for stm32f1 etc) instructions can be used, no ARM instructions. * no stack, since it may overwrite buffer data. * for most devices, after writing a single unit data, wait until FLASH is not busy. * for some devices, check if there are any errors during flashing process. * respect unit size of a single copy. * after flashing, trigger a breakpint to halt the core. * a sucessful run ends with `r2` set to zero when halted. * be sure that flashloaders are at least be capable of running at 0x20000000 (the base address of SRAM) For devices that need to wait until the flash is not busy, check FLASH_SR_BUSY bit. For devices that need to check if there is any errors during flash, check FLASH\_SR\_(X)ERR where `X` can be any error state FLASH_SR related offset and copy unit size may be found in ST official reference manuals and/or some header files in other open source projects. Clean room document provides some of them. ## Debug tricks If you find some flashloaders to be broken or you need to write a new flashloader for new devices, the following tricks may help. 1. Modify `WAIT_ROUNDS` marco to a bigger value so that you will have time to kill st-flash when it is waiting for a halted core. 2. run `st-flash` and kill it after the flashloader is loaded to SRAM 3. launch `st-util` and `gdb`/`lldb` 4. set a breakpoint at the base address of SRAM 5. jump to the base address and start your debug The tricks work because by this means, most work (flash unlock, flash erase, load flashloader to SRAM) would have been done automatically, saving time to construct a debug environment.stlink-1.9.0/doc/man/000077500000000000000000000000001526027543100143525ustar00rootroot00000000000000stlink-1.9.0/doc/man/.gitignore000066400000000000000000000000211526027543100163330ustar00rootroot00000000000000*.1 !st-server.1 stlink-1.9.0/doc/man/CMakeLists.txt000066400000000000000000000020371526027543100171140ustar00rootroot00000000000000### # Generate manpages ### set(MANPAGES st-info st-flash st-util st-server) # Only generate manpages with pandoc in Debug builds if (${STLINK_GENERATE_MANPAGES}) include(pandocology) foreach (manpage ${MANPAGES}) add_document( ${manpage}.1 SOURCES ${manpage}.md PANDOC_DIRECTIVES -s -t man PRODUCT_DIRECTORY ${CMAKE_INSTALL_FULL_DATADIR} ) endforeach () else () message(STATUS "Manpage generation disabled") endif() # Install from output folder or this folder foreach (manpage ${MANPAGES}) if (EXISTS ${CMAKE_INSTALL_FULL_DATADIR}/${manpage}.1) set(f "${CMAKE_INSTALL_FULL_DATADIR}/${manpage}.1") elseif (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${manpage}.1) set(f "${CMAKE_CURRENT_SOURCE_DIR}/${manpage}.1") else () message(AUTHOR_WARNING "Manpage ${manpage} not generated") endif() if (f AND NOT WIN32) install(FILES ${f} DESTINATION ${CMAKE_INSTALL_FULL_DATADIR}/man/man1) unset(f) endif() endforeach () stlink-1.9.0/doc/man/st-flash.1000066400000000000000000000035601526027543100161610ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.9 .\" .TH "st-flash" "1" "Feb 2018" "Open Source STMicroelectronics Stlink Tools" "stlink" .hy .SH NAME .PP st-flash - Flash binary files to STM32 device .SH SYNOPSIS .PP \f[I]st-flash\f[R] [\f[I]OPTIONS\f[R]] {read|write|erase} [\f[I]FILE\f[R]] .SH DESCRIPTION .PP Flash binary files to arbitrary sections of memory, or read arbitrary addresses of memory out to a binary file. .PP You can use this instead of st-util(1) if you prefer, but remember to use the \f[B].bin\f[R] image, rather than the \f[B].elf\f[R] file. .PP Use hexadecimal format for the \f[I]ADDR\f[R] and \f[I]SIZE\f[R]. .SH COMMANDS .TP write \f[I]FILE\f[R] \f[I]ADDR\f[R] Write firmware \f[I]FILE\f[R] to device starting from \f[I]ADDR\f[R] .TP read \f[I]FILE\f[R] \f[I]ADDR\f[R] \f[I]SIZE\f[R] Read firmware from device starting from \f[I]ADDR\f[R] up to \f[I]SIZE\f[R] bytes to \f[I]FILE\f[R] .TP erase Perform a mass erasing of the device firmware .TP reset Reset the target .SH OPTIONS .TP --version Print version information .TP --debug TODO .TP --reset Trigger a reset both before and after flashing .TP --opt Enable ignore ending empty bytes optimization .TP --serial \f[I]iSerial\f[R] TODO .TP --flash=fsize Where fsize is the size in decimal, octal, or hex followed by an optional multiplier `k' for KB, or `m' for MB. Use a leading \[lq]0x\[rq] to specify hexadecimal, or a leading zero for octal. .SH EXAMPLES .PP Flash \f[C]firmware.bin\f[R] to device .IP .nf \f[C] $ st-flash write firmware.bin 0x8000000 \f[R] .fi .PP Read firmware from device (4096 bytes) .IP .nf \f[C] $ st-flash read firmware.bin 0x8000000 0x1000 \f[R] .fi .PP Erase firmware from device .IP .nf \f[C] $ st-flash erase \f[R] .fi .SH SEE ALSO .PP st-util(1), st-info(1) .SH COPYRIGHT .PP This work is copyrighted. Stlink contributors. See \f[I]LICENSE\f[R] file in the stlink source distribution. stlink-1.9.0/doc/man/st-flash.md000066400000000000000000000033131526027543100164150ustar00rootroot00000000000000% st-flash(1) Open source version of the STMicroelectronics STLINK Tools | stlink % % Feb 2023 # NAME st-flash - Flash binary files to STM32 device # SYNOPSIS *st-flash* \[*OPTIONS*\] \{read|write|erase\} \[*FILE*\] \ \ # DESCRIPTION Flash binary files to arbitrary sections of memory, or read arbitrary addresses of memory out to a binary file. You can use this instead of st-util(1) if you prefer, but remember to use the **.bin** image, rather than the **.elf** file. Use hexadecimal format for the *ADDR* and *SIZE*. The STLink device to use can be specified using the --serial parameter. # COMMANDS write *FILE* *ADDR* : Write firmware *FILE* to device starting from *ADDR* read *FILE* *ADDR* *SIZE* : Read firmware from device starting from *ADDR* up to *SIZE* bytes to *FILE* erase : Perform a mass erasing of the device firmware reset : Reset the target # OPTIONS \--version : Print version information \--debug : TODO \--reset : Trigger a reset both before and after flashing \--opt : Enable ignore ending empty bytes optimization \--serial *iSerial* : Serial number of ST-LINK device to use \--flash=fsize : Where fsize is the size in decimal, octal, or hex followed by an optional multiplier 'k' for KB, or 'm' for MB. Use a leading "0x" to specify hexadecimal, or a leading zero for octal. # EXAMPLES Flash `firmware.bin` to device $ st-flash write firmware.bin 0x8000000 Read firmware from device (4096 bytes) $ st-flash read firmware.bin 0x8000000 0x1000 Erase firmware from device $ st-flash erase # SEE ALSO st-util(1), st-info(1) # COPYRIGHT This work is copyrighted. Stlink contributors. See *LICENSE* file in the stlink source distribution. stlink-1.9.0/doc/man/st-info.1000066400000000000000000000023351526027543100160160ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.4 .\" .TH "st\-flash" "1" "Feb 2018" "Open Source STMicroelectronics Stlink Tools" "stlink" .hy .SH NAME .PP st\-info \- Provides information about connected STLink and STM32 devices .SH SYNOPSIS .PP \f[I]st\-info\f[R] [\f[I]OPTIONS\f[R]] .SH DESCRIPTION .PP Provides information about connected STLink programmers and STM32 devices: Serial code, openocd, flash, sram, page size, chipid, description. .SH OPTIONS .TP .B \[en]version Print version information .TP .B \-\-flash Display amount of flash memory available in the device .TP .B \-\-sram Display amount of sram memory available in device .TP .B \-\-descr Display textual description of the device .TP .B \-\-pagesize Display the page size of the device .TP .B \-\-chipid Display the chip ID of the device .TP .B \-\-serial Display the serial code of the device .TP .B \-\-probe Display the summarized information of the connected programmers and devices .SH EXAMPLES .PP Display information about connected programmers and devices .IP .nf \f[C] $ st\-info \-\-probe \f[R] .fi .SH SEE ALSO .PP st\-util(1), st\-flash(1) .SH COPYRIGHT .PP This work is copyrighted. Stlink contributors. See \f[I]LICENSE\f[R] file in the stlink source distribution. stlink-1.9.0/doc/man/st-info.md000066400000000000000000000024111526027543100162510ustar00rootroot00000000000000% st-flash(1) Open source version of the STMicroelectronics STLINK Tools | stlink % % Feb 2023 # NAME st-info - Provides information about connected STLink and STM32 devices # SYNOPSIS *st-info* \[*OPTIONS*\] # DESCRIPTION Provides information about connected STLink programmers and STM32 devices: Serial code, flash, page size, sram, chipid, description. # OPTIONS \--version : Print version information \--probe : Display the summarized information of the connected programmers and devices \--serial : Display the serial code of the device \--flash : Display amount of flash memory available in the device \--pagesize : Display the page size of the device \--sram : Display amount of sram memory available in device \--chipid : Display the chip ID of the device \--descr : Display textual description of the device # EXAMPLES Display information about connected programmers and devices $ st-info --probe Found 1 stlink programmers serial: 57FF72067265575742132067 flash: 131072 (pagesize: 128) sram: 20480 chipid: 0x0447 descr: L0xx Category 5 # SEE ALSO st-util(1), st-flash(1) # COPYRIGHT This work is copyrighted. Stlink contributors. See *LICENSE* file in the stlink source distribution. stlink-1.9.0/doc/man/st-server.1000066400000000000000000000074261526027543100163770ustar00rootroot00000000000000.\" Automatically generated by Pandoc 3.10 .\" .TH "st\-server" "1" "Jun 2026" "Open source version of the STMicroelectronics STLINK Tools" "stlink" .SH NAME st\-server \- Serve a local ST\-LINK over TCP for remote stlink tools .SH SYNOPSIS \f[I]st\-server\f[R] [\f[I]OPTIONS\f[R]] .SH DESCRIPTION \f[I]st\-server\f[R] opens one locally attached ST\-LINK probe and exposes the stlink backend operations over TCP. A remote \f[I]st\-flash\f[R](1), \f[I]st\-info\f[R](1), or \f[I]st\-util\f[R](1) client can then use \f[I]\(enremote\f[R] to drive the probe from another machine. .PP The server owns the USB connection to the ST\-LINK. The client runs the normal stlink target logic such as target connection, chip detection, erase, program, verify, and GDB server behavior. .PP By default \f[I]st\-server\f[R] listens only on the loopback address \f[I]127.0.0.1:4500\f[R]. Use \f[I]\(enbind\f[R] to listen on another IPv4 address. Binding to \f[I]0.0.0.0\f[R] or using \f[I]\(enbind=:PORT\f[R] exposes the probe to the network; only do this on trusted networks or behind another access\-control layer such as SSH. .SH OPTIONS .TP \-\-bind \f[I]ADDR\f[R][:\f[I]PORT\f[R]] IPv4 address and optional port to listen on. The default is \f[I]127.0.0.1:4500\f[R]. Use \f[I]0.0.0.0\f[R] to listen on all IPv4 interfaces. The shorthand \f[I]:4500\f[R] is accepted and means \f[I]0.0.0.0:4500\f[R]. .TP \-\-port \f[I]PORT\f[R] TCP port to listen on. This is kept for compatibility and can be combined with \f[I]\(enbind\f[R] when the bind address does not include a port. .TP \-\-serial \f[I]iSerial\f[R] Serial number of the local ST\-LINK device to serve. To serve multiple probes concurrently, run one \f[I]st\-server\f[R] process per probe on different ports. .TP \-\-freq \f[I]kHz\f[R] SWD/JTAG frequency in kHz used by the server when opening the local probe. Client commands may still set their own frequency during the remote connect sequence. .TP \-\-verbose[=\f[I]LEVEL\f[R]] Enable verbose logging. If \f[I]LEVEL\f[R] is omitted, debug logging is enabled. .TP \-\-help Print usage information. .SH EXAMPLES Serve the first local ST\-LINK on the default loopback address: .IP .EX $ st\-server .EE .PP Serve a specific probe on all IPv4 interfaces: .IP .EX $ st\-server \-\-serial 57FF72067265575742132067 \-\-bind=:4500 .EE .PP Use an SSH tunnel to keep \f[I]st\-server\f[R] bound to loopback. On the host with the probe, run: .IP .EX $ st\-server .EE .PP On the laptop, forward the port and use the tunnel: .IP .EX $ ssh \-N \-L 4500:127.0.0.1:4500 pi\(atraspberrypi & $ st\-flash \-\-remote 127.0.0.1:4500 write firmware.bin 0x08000000 $ st\-info \-\-probe \-\-remote 127.0.0.1:4500 $ st\-util \-\-remote 127.0.0.1:4500 .EE .PP Serve two probes concurrently (one \f[I]st\-server\f[R] per probe, on different ports): .IP .EX $ st\-server \-\-serial aaa \-\-port 4500 $ st\-server \-\-serial bbb \-\-port 4501 .EE .SH SECURITY The protocol has no authentication or encryption: a client that can reach the port has full debug and flash control of the probe. The default loopback bind (\f[I]127.0.0.1\f[R]) avoids exposing the probe to the network. Use an SSH tunnel for remote access, or use \f[I]\(enbind=0.0.0.0\f[R] only on a trusted, isolated network. .SH RECOVERY If \f[I]st\-server\f[R] is killed during a flash operation, normal \f[I]SIGINT\f[R] and \f[I]SIGTERM\f[R] shutdown paths close the ST\-LINK handle cleanly. A forced kill, process crash, or USB firmware fault can still leave the ST\-LINK unresponsive. If local tools such as \f[I]st\-info \(enprobe\f[R] also hang, reset the USB device with a tool such as \f[I]usbreset\f[R] or physically replug the probe. .SH SEE ALSO st\-flash(1), st\-info(1), st\-util(1), st\-trace(1) .SH COPYRIGHT This work is copyrighted. Stlink contributors. See \f[I]LICENSE\f[R] file in the stlink source distribution. stlink-1.9.0/doc/man/st-server.md000066400000000000000000000065771526027543100166450ustar00rootroot00000000000000% st-server(1) Open source version of the STMicroelectronics STLINK Tools | stlink % % Jun 2026 # NAME st-server - Serve a local ST-LINK over TCP for remote stlink tools # SYNOPSIS *st-server* \[*OPTIONS*\] # DESCRIPTION *st-server* opens one locally attached ST-LINK probe and exposes the stlink backend operations over TCP. A remote *st-flash*(1), *st-info*(1), or *st-util*(1) client can then use *--remote* to drive the probe from another machine. The server owns the USB connection to the ST-LINK. The client runs the normal stlink target logic such as target connection, chip detection, erase, program, verify, and GDB server behavior. By default *st-server* listens only on the loopback address *127.0.0.1:4500*. Use *--bind* to listen on another IPv4 address. Binding to *0.0.0.0* or using *--bind=:PORT* exposes the probe to the network; only do this on trusted networks or behind another access-control layer such as SSH. # OPTIONS \--bind *ADDR*\[:*PORT*\] : IPv4 address and optional port to listen on. The default is *127.0.0.1:4500*. Use *0.0.0.0* to listen on all IPv4 interfaces. The shorthand *:4500* is accepted and means *0.0.0.0:4500*. \--port *PORT* : TCP port to listen on. This is kept for compatibility and can be combined with *--bind* when the bind address does not include a port. \--serial *iSerial* : Serial number of the local ST-LINK device to serve. To serve multiple probes concurrently, run one *st-server* process per probe on different ports. \--freq *kHz* : SWD/JTAG frequency in kHz used by the server when opening the local probe. Client commands may still set their own frequency during the remote connect sequence. \--verbose\[=*LEVEL*\] : Enable verbose logging. If *LEVEL* is omitted, debug logging is enabled. \--help : Print usage information. # EXAMPLES Serve the first local ST-LINK on the default loopback address: $ st-server Serve a specific probe on all IPv4 interfaces: $ st-server --serial 57FF72067265575742132067 --bind=:4500 Use an SSH tunnel to keep *st-server* bound to loopback. On the host with the probe, run: $ st-server On the laptop, forward the port and use the tunnel: $ ssh -N -L 4500:127.0.0.1:4500 pi@raspberrypi & $ st-flash --remote 127.0.0.1:4500 write firmware.bin 0x08000000 $ st-info --probe --remote 127.0.0.1:4500 $ st-util --remote 127.0.0.1:4500 Serve two probes concurrently (one *st-server* per probe, on different ports): $ st-server --serial aaa --port 4500 $ st-server --serial bbb --port 4501 # SECURITY The protocol has no authentication or encryption: a client that can reach the port has full debug and flash control of the probe. The default loopback bind (*127.0.0.1*) avoids exposing the probe to the network. Use an SSH tunnel for remote access, or use *--bind=0.0.0.0* only on a trusted, isolated network. # RECOVERY If *st-server* is killed during a flash operation, normal *SIGINT* and *SIGTERM* shutdown paths close the ST-LINK handle cleanly. A forced kill, process crash, or USB firmware fault can still leave the ST-LINK unresponsive. If local tools such as *st-info --probe* also hang, reset the USB device with a tool such as *usbreset* or physically replug the probe. # SEE ALSO st-flash(1), st-info(1), st-util(1), st-trace(1) # COPYRIGHT This work is copyrighted. Stlink contributors. See *LICENSE* file in the stlink source distribution. stlink-1.9.0/doc/man/st-util.1000066400000000000000000000031771526027543100160450ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.4 .\" .TH "st\-util" "1" "Feb 2018" "Open Source STMicroelectronics Stlink Tools" "stlink" .hy .SH NAME .PP st\-util \- Run GDB server to interact with STM32 device .SH SYNOPSIS .PP \f[I]st\-util\f[R] [\&...] .SH DESCRIPTION .PP Start a GDB server to interact with a STM32 device Run the main binary of the local package (src/main.rs). .PP If a port number is not specified using the \f[B]\[en]listen_port\f[R] option, the default \f[B]4242\f[R] port will be used. .PP Stlink version 2 is used by default unless the option \f[B]\[en]stlinkv1\f[R] is given. .SH OPTIONS .TP .B \-h, \-\-help Print this message. .TP .B \-\-version Print version information .TP .B \-v \f[I]XX\f[R], \-\-verbose=XX Specify a specific verbosity level (0..99) .TP .B \-v, \-\-verbose Specify generally verbose logging .TP .B \-s \f[I]X\f[R], \-\-stlink_version=X Choose what version of stlink to use, (defaults to 2) .TP .B \-1, \-\-stlinkv1 Force stlink version 1 .TP .B \-p \f[I]4242\f[R], \-\-listen_port=1234 Set the gdb server listen port. (default port: 4242) .TP .B \-m, \-\-multi Set gdb server to extended mode. st\-util will continue listening for connections after disconnect. .TP .B \-n, \-\-no\-reset Do not reset board on connection. .TP .B \-\-semihosting Enable ARM Semihosting output on stdout .SH EXAMPLES .PP Run GDB server on port 4500 and connect to it .IP .nf \f[C] $ st\-util \-p 4500 $ gdb (gdb) target extended\-remote localhost:4500 \f[R] .fi .SH SEE ALSO .PP st\-flash(1), st\-info(1) .SH COPYRIGHT .PP This work is copyrighted. Stlink contributors. See \f[I]LICENSE\f[R] file in the stlink source distribution. stlink-1.9.0/doc/man/st-util.md000066400000000000000000000024631526027543100163020ustar00rootroot00000000000000% st-util(1) Open source version of the STMicroelectronics STLINK Tools | stlink % % Feb 2023 # NAME st-util - Run GDB server to interact with STM32 device # SYNOPSIS *st-util* \[\...] # DESCRIPTION Start a GDB server to interact with a STM32 device Run the main binary of the local package (src/main.rs). If a port number is not specified using the **--listen_port** option, the default **4242** port will be used. The STLink device to use can be specified using the --serial parameter. # OPTIONS -h, \--help : Print this message. \--version : Print version information -v *XX*, \--verbose=*XX* : Specify a specific verbosity level (0..99) -v, \--verbose : Specify generally verbose logging -p *4242*, \--listen_port=1234 : Set the gdb server listen port. (default port: 4242) -m, \--multi : Set gdb server to extended mode. st-util will continue listening for connections after disconnect. -n, \--no-reset : Do not reset board on connection. \--semihosting : Enable ARM Semihosting output on stdout # EXAMPLES Run GDB server on port 4500 and connect to it $ st-util -p 4500 $ gdb (gdb) target extended-remote localhost:4500 # SEE ALSO st-flash(1), st-info(1) # COPYRIGHT This work is copyrighted. Stlink contributors. See *LICENSE* file in the stlink source distribution. stlink-1.9.0/doc/release.md000066400000000000000000000013201526027543100155350ustar00rootroot00000000000000Release ======= This document describes the necessary steps for developers to create a release: 1. Update changelog (`CHANGELOG.md`, `cmake/packaging/deb/changelog` & `cmake/packaging/rpm/changelog`) 2. Update `.version` with semantic version: `x.x.x` 3. Update `README.md` with semantic version `x.x.x` in commits badge 4. Update GitHub security policy (`SECURITY.md`) 5. Merge `develop` into `master` 6. Create and push git tag and commits `git tag x.x.x` 7. Create binary packages (.rpm / .deb / .zip) with `make package && sh ./gen_binaries_win.sh` 8. Upload packages to the [release page](https://github.com/stlink-org/stlink/releases) of this project 9. Merge `master` into `develop` and `develop` into `testing`stlink-1.9.0/doc/supported_devices.md000066400000000000000000000114541526027543100176550ustar00rootroot00000000000000# MCUs supported by the STlink toolset A list of devices supported by the stlink toolset can be found in */inc/stm32.h*. More commonly these are: | Product-Family | ARM Cortex Core | Product Line | | -------------- | --------------- | ---------------------------------------------------------- | | STM32F0 | M0 | | | STM32C0 | M0+ | | | STM32G0 | M0+ | | | STM32L0 | M0+ | | | STM32U0 | M0+ | *preliminary, limited and partial support only!* | | STM32F10**0** | M3 | Value line | | STM32F10**1** | M3 | Access line | | STM32F10**2** | M3 | USB Access line | | STM32F10**3** | M3 | Performance line | | STM32F10**5** | M3 | Connectivity line | | STM32F10**7** | M3 | Connectivity line | | STM32L1 | M3 | | | STM32F2 | M3 | | | STM32F3**01** | M4F | Access line | | STM32F3**02** | M4F | USB & CAN line | | STM32F3**03** | M4F | Performance line | | STM32F3**34** | M4F | Digital Power line | | STM32F3**73** | M4F | Precision Measurement line (64k/16k / 128k/24k / 265k/32k) | | STM32F3**18** | M4F | General Purpose line (64k/16k) | | STM32F3**28** | M4F | General Purpose line (64k/16k) | | STM32F3**58** | M4F | General Purpose line (265k/48k) | | STM32F3**78** | M4F | Precision Measurement line (265k/32k) | | STM32F3**98** | M4F | General Purpose line (512k/80k) | | STM32F4 | M4F | | | STM32G4 | M4F | | | STM32L4 | M4F | | | STM32F7 | M7F | | | STM32H7 | M7F | | | STM32WB | M4F | | | STM32WL | M4 | | | STM32L5 | M33 | *preliminary, limited and partial support only!* | | STM32H5 | M33 | | | STM32U5 | M33 | *preliminary, limited and partial support only!* | | STM32C5 | M33 | *preliminary, limited and partial support only!* | # Chinese Clone-Chips [may work, but without support!] ## STM32F1 Clone / ARM Cortex M3 (Core-ID: 0x2ba01477) (mostly on Bluepill-Boards) **(!) Attention:** Some MCUs may come with with _**Fake-STM32-Marking !**_ **(!) Attention:** The Core-ID of these MCUs is in conflict with the one of the original STM32F1-devices. | Product-Code | Chip-ID | Comment | | ------------- | ------- | ------------------------------------------------------------------------- | | CKS32F103C8T6 | 0x410 | STM32F103C8T6 clone from China Key Systems (CKS) | | CH32F103C8T6 | 0x410 | STM32F103C8T6 clone from Nanjing Qinheng Microelectronics Co., Ltd. (WCH) | ## STM32F3 Clone / ARM Cortex M4F (Core-ID: 0x2ba01477) **(!) Attention:** The Chip-IDs of these MCUs are in conflict with such of original STM32F1-devices. | Product-Code | Chip-ID | Comment | | ------------ | ------- | ------------------------------------ | | GD32F303VET6 | 0x414 | STM32F303 clone from GigaDevice (GD) | | GD32F303CGT6 | 0x430 | STM32F303 clone from GigaDevice (GD) | | GD32F303VGT6 | 0x430 | STM32F303 clone from GigaDevice (GD) | stlink-1.9.0/doc/tutorial.md000066400000000000000000000631311526027543100157700ustar00rootroot00000000000000# stlink Tools Tutorial ## Available tools and options | Option | Tool | Description | Available
since | | --------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------- | | --flash=n[k, M] | st-flash | One can specify `--flash=128k` for example, to override the default value of 64k for the STM32F103C8T6 to assume 128k of flash being present. This option accepts decimal (128k), octal 0200k, or hex 0x80k values.
Leaving the multiplier out is equally valid, e.g.: `--flash=0x20000`. The size may be followed by an optional "k" or "M" to multiply the given value by 1k (1024) or 1M (1024 x 1024) respectively.
One can read arbitary addresses of memory out to a binary file with: `st-flash read out.bin 0x8000000 4096`. In this example `4096 bytes` are read and subsequently written to `out.bin`.
Binary files (here: `in.bin`) are written into flash memory with: `st-flash write in.bin 0x8000000` | v1.4.0 | | --format | st-flash | Specify file image format to read or write.
Valid formats are `binary` and `ihex`. | v1.3.0 | | --freq=n[k, M] | st-info
st-flash
st-util | The frequency of the SWD/JTAG interface can be specified, to override the default 1800 kHz configuration.
This option solely accepts decimal values representing kHz. The prefix "k" may be added for better understanding, but has no effect. In addition, values can be interpreted as thousands of kHz thus representing MHz. This is achieved by using the prefix "M".
Valid frequencies are: `5k, 15k, 25k, 50k, 100k, 125k, 240k, 480k, 950k, 1200k (1.2M), 1800k (1.8M), 4000k (4M)`. | v1.6.1 | | --opt | st-flash | Optimisation can be enabled in order to skip flashing empty (0x00 or 0xff) bytes at the end of binary file.
This may cause some garbage data left after a flash operation. This option was enabled by default in earlier releases. | v1.6.1 | | --reset | st-flash | Trigger a reset after flashing. The default uses the hardware reset through `NRST` pin.
A software reset (via `AIRCR`; since v1.5.1) is used, if the hardware reset failed (`NRST` pin not connected). | v1.0.0 | | --connect-under-reset | st-info
st-flash
st-util | Connect under reset. Option makes it possible to connect to the device before code execution. This is useful when the target contains code that lets the device go to sleep, disables debug pins or other special code. | v1.6.1 | | --hot-plug | st-info
st-flash
st-util | Connect to the target without reset. | v1.6.2 | | --probe | st-info | Display hardware information about the connected programmer and target MCU. | v1.2.0 | | --version | st-info
st-flash
st-util | Print version information. | v1.3.0 | | --help | st-flash
st-util | Print list of available commands. | | ### Reading & Writing Option Bytes Example to read and write option bytes: ``` ./st-flash --debug read option_bytes_dump.bin 0x1FFF7800 4 ./st-flash --debug write option_bytes_dump.bin 0x1FFF7800 ``` ### st-flash: Checksum for binary files When flashing a file, a checksum is calculated for the binary file, both in md5 and the sum algorithm. The latter is also used by the official ST-LINK utility tool from STMicroelectronics as described in the document: [`UM0892 - User manual STM32 ST-LINK utility software description`](https://www.st.com/resource/en/user_manual/cd00262073-stm32-stlink-utility-software-description-stmicroelectronics.pdf). ### stlink-gui The `stlink` toolset also provides a GUI which is an optional feature. It is only installed if a gtk3 toolset has been detected during package installation or compilation from source. It is not available for Windows. If you prefer to have an user interface on the latter system, please use the official `ST-LINK Utility` instead. The stlink-gui offers the following features: - Connect/disconnect to a present STlink programmer - Display basic device information - Select a binary file from the local filesystem to flash it to the detected device connected to the programmer - Export the memory of the connected chip to a file which can be saved to the local filesystem - Display of the memory address map in the main window for each, the device memory and a loaded binary file Within the GUI main window tooltips explain the available user elements. ## HowTos & solutions to common problems ### a) Verify if udev rules are set correctly (by Dave Hylands) To investigate, start by plugging your STLINK device into the usb port. Then run `lsusb`. You should see an entry something like the following: ``` Bus 005 Device 017: ID 0483:374b STMicroelectronics ST-LINK/V2.1 (Nucleo-F103RB) ``` Note the bus number (005) and the Device (017). You should then do: `ls -l /dev/bus/usb/005/017` (replacing 005 and 017 appropriately). On my system I see the following: ``` crw-rw-rw- 1 root root 189, 528 Jan 24 17:52 /dev/bus/usb/005/017 ``` which is world writable (this is from the `MODE:="0666"` below). I have several files in my `/lib/udev/rules.d` directory. In this particular case, the `49-stlinkv2-1.rules` file contains the following: ``` # STM32 nucleo boards, with onboard STLINK/V2-1 # ie, STM32F0, STM32F4. # STM32VL has STLINK/V1, which is quite different SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="374b", \ MODE:="0666", \ SYMLINK+="stlinkv2-1_%n" # If you share your linux system with other users, or just don't like the # idea of write permission for everybody, you can replace MODE:="0666" with # OWNER:="yourusername" to create the device owned by you, or with # GROUP:="somegroupname" and mange access using standard unix groups. ``` and the `idVendor` of `0483` and `idProduct` of `374b` matches the vendor id from the `lsusb` output. Make sure that you have all 3 files from [/config/udev/rules.d](https://github.com/stlink-org/stlink/tree/master/config/udev/rules.d) in your `/lib/udev/rules.d` directory. After copying new files or editing existing files in `/lib/udev/rules.d` you should run the following: ``` sudo udevadm control --reload-rules sudo udevadm trigger ``` to ensure that the rules actually take effect. Using the trigger command means that you shouldn't need to unplug and replug the device, but you might want to try that for good measure as well. If the VID:PID of your device doesn't match those in any of the 3 files, then you may need to create a custom rule file to match your VID:PID. ### b) NOTE: Chinese Fake-Chips CKS32F103C8T6 or CS32F103C8T6 being marked as "STM32F103C8T6" In contrast to "Clone chips" which identify themselves as such by their official marking (manufacturer, model, etc.), so called "Fake chips" do not. Instead counterfeiters try to copy the outer appearance of the original and thus are very hard to detect. Possible malfunction then may lead to various effects and issues during operation also in in connection with this toolset. As of December 2019 several so called "Bluepill-Boards" with a STM32F103C8T6 appeared on the market that do not hold the original part. In this known example one finds the counterfeited "STM32F103C8T6" MCUs to identify themselves with chip-id `0x2ba01477` instead of `0x1ba01477`. In the following you find some hints on how to identify your chip and track down fraud: - [How to Detect STM32 Fakes](https://www.cnx-software.com/2020/03/22/how-to-detect-stm32-fakes/) - [Confirmation by STMicroelectronics](https://www.mikrocontroller.net/attachment/442839/couterfeit_STM.PNG) (Marking: 991KA 93 MYS 807) - [STM32 Clones: The Good, The Bad And The Ugly](https://hackaday.com/2020/10/22/stm32-clones-the-good-the-bad-and-the-ugly/) However it appears that not all counterfeited parts cause problems during operation, but some are known to not even being able to execute a basic "blinky" example binary. Further there can be problems that may not even show up or affect you directly, but somewhen later in time (or maybe never). This demonstrates there is no guarantee for a proper working chip with equal functionality compared to the original. Please keep this in mind and be sceptical when facing problems with this type of boards. Check your hardware and try to identify what you have in front of you before assuming a bug in the `stlink` toolset. Please let us know, if you come across any further websites or tutorials that help to identify STM32 fake chips so we can list them here to help others. ### c) Appearance of the warning message `WARN src/common_legacy.c: unknown chip id!` The chip ID is the main identifier for STM32 MCU and their specific type and provides primary information on flash and SRAM architecture. This so called `DBGMCU_IDCODE` register is allocated either at memory address `0xE0042000` or `0x40015800`. A failure of chip identification results in the error `WARN src/common_legacy.c: unknown chip id!`. There are different variants of this message that refer to different issues: - `unknown chip id! 0` --> Target chip (board) is unknown. 1. Microcontroller is in stop/standby mode. 2. The signals `DIO` and `CLK` are reversed on the SWD-Interface. - `unknown chip id! 0x3748` --> A target chip (board) cannot be detected. 1. No target is connected --> In this case `st-info --probe` displays `chip id 0x0748` with STLINK/V2 and `chip id 0x03e8` with STLINK-V3. 2. The chip is connected but has gone into an undefined state of operation where the SWD pins are unresponsive. --> Try to use `--connect-under-reset` while pressing the reset button on the target board. 3. A firmware-issue prevents the programmer from normal operation. --> Ensure that your programmer runs the latest firmware version and consider to upgrade any older version by using the official firmware upgrade tool provided by STMicroelectronics. - `unknown chip id! 0xe0042000` --> The memory register holding the information on the chip ID could not be read. The following problems may lead to this case: 1. This problem is caused by the SWDIO and SWCLK being configured for other purpose (GPIO, etc) other than Serial Wire configuration or Jtag --> A possible solution to this is to short the `BOOT0` pin with `VDD` (1) and to reset the chip / board by the execuing `st-flash erase` in order to return the MCU back to normal operation. Afterwards `BOOT0` should be set back to `GND` (0). 2. There is a hardware defect in the connection between the MCU and the used programmer (solder points, cables, connectors). ### d) Understanding hardware and software reset functionality for `st-flash` and reset-related device recovery Typically a reset signal is sent via the reset pin `NRST`. Using `st-flash` for flashing results in the following behaviour: - without the `--reset` option: `st-flash write` results in one reset signal on the `NRST` line - with the `--reset` option: `st-flash write --reset` results in two subsequent reset signals on the `NRST` line Depending on the used programmer the hardware reset line is not always connected. This is especially the case for low-cost STLINK/V2 clone programmers. Here the SWD connector consists of only 4 pins: `VCC`, `SWCLK`, `GND` and `SWDATA`. When the physical reset line `NRST` is not connected, a reset is initiated by software via `SWD_SWDIO/JTAG_TMS` (software reset). Just as mentioned above, flashing is possible here eiher with and without the `--reset` option. Configuring the STM32 pin `JTAG_TMS/SWD_SWDIO` as an output now also prevents the SWD interface from flashing and resetting the device. In consequence this constellation typically requires a _hard reset_ to allow for the ST-Link/V2 programmer to reconnect to the target at all. As soon as the device is in DFU mode, the `JTAG_TMS/SWD_SWDIO` pin is left in the default state with all JTAG pins available. Here flashing of the device is now possible with and without the `--reset` option. The debug command `(gdb) monitor jtag_reset` sends a _hard reset_ signal via the `NRST` pin to reset the device and allows for flashing it (again). ### e) Note on setting hardware breakpoints for external bus (Example: STM32H735-DK) GDB is setting breakpoints based on the XML memory map designation of `rom` or `ram`, which is hardcoded in st-util for a given processor. However the external bus can be *RAM* or *ROM* depending on design. The STM32H735-DK has external FLASH at address 0x90000000. As a result, because the entire external memory range is `ram` as it could be either, software breakpoints (Z0) get sent when a breakpoint is created and they never get tripped as the memory area is read only. ### f) UART-Access via a virtual COM port Access to the Universal Asynchronous Receiver Transmitter (UART) via a virtual COM port is not related to the stlink toolset itself. It is an independent feature that should natively be available on UNIX-based operating systems. Windows operating systems require the installation of a virtual COM device driver. The appropriate device driver is downloaded and installed automatically via Windows Update in the background as soon as the device is plugged-in for the first time. A connected ST-LINK programmer with UART functionality is detected as a CDC (ACM) USB device. After each reset the device will be reloaded and will pop up as `/dev/ttyACM0` or `/dev/ttyACM1` depending on the specific design. UART connections to the interface are typically initiated with a serial terminal. For UNIX operating systems we recommend to use either [minicom](https://en.wikipedia.org/wiki/Minicom) (terminal-based) or [cutecom](https://cutecom.sourceforge.net/) (GUI-based). Windows users should have a look at [Teraterm](https://github.com/TeraTermProject/teraterm). Most common and established settings for the interface are 115200 or 9600 baud together with the `8-N-1` configuration, standing for (8) data bits, no parity bit (N) and (1) stop bit. Please refer to relevant literature on the UART interface for more detailed technical information and limitations. Note: On some debian-based UNIX-based systems the `modemmanager` package is installed by default. In has been reported that this tool unfortunately may delay the release of the serial port to applications which is handled by the operating system in the background. Subseqently the CDC/ACM device is also delayed after each reset. This typically includes not only the connection itself, but also some programming operations (at least those using the mass storage emulation). However one can not predict the behaviour exactly - in some cases the boards may be essentially useless or even working fairly well. Proper determined functionality can be achieved by uninstalling the `modemmanager` package or by setting an appropriate `udev` device rule. --- ( Content below is currently unrevised and may be outdated as of Mar 2021. ) ## Using the GDB server This assumes you have got the [libopencm3](http://www.libopencm3.org) project downloaded in `ocm3`. The libopencm3 project provides a firmware library, with solid examples for Cortex M3, M4 and M0 processors from any vendor. It has some good, reliable examples for each of the Discovery boards. Even if you don’t plan on using libopencm3, the examples they provide will help you verify that: - Your installed toolchain is capable of compiling for cortex M3/M4 targets - stlink is functional - Your arm-none-eabi-gdb is functional - Your board is functional A GDB server must be started to interact with the STM32 by running st-util tool : ``` $> st-util # Full help for other options (listen port, version) $> st-util --help ``` Then, GDB can be used to interact with the kit: ``` $> $TOOLCHAIN_PATH/bin/arm-none-eabi-gdb example_file.elf ``` From GDB, connect to the server using: ``` (gdb) target extended localhost:4242 ``` GDB has memory maps for as many chips as it knows about, and will load your project into either flash or SRAM based on how the project was linked. Linking projects to boot from SRAM is beyond the scope of this document. Because of these built in memory maps, after specifying the .elf at the command line, now we can simply “load� the target: ``` (gdb) load ``` st-util will load all sections into their appropriate addresses, and “correctly� set the PC register. So, to run your freshly loaded program, simply “continue� ``` (gdb) continue ``` Your program should now be running, and, if you used one of the blinking examples from libopencm3, the LEDs on the board should be blinking for you. ## Using the gdb server To run the gdb server: ``` $ make && [sudo] ./st-util There are a few options: ./st-util - usage: -h, --help Print this help -vXX, --verbose=XX Specify a specific verbosity level (0..99) -v, --verbose Specify general verbose logging -p 4242, --listen_port=1234 Set the listen port for the gdb server (default: 4242)- -m, --multi Set gdb server to extended mode. st-util will continue listening for connections after disconnect. -n, --no-reset, --hot-plug Do not reset board on connection. ``` The STLink device to use can be specified using the --serial parameter. Then, in your project directory, someting like this... (remember, you need to run an _ARM_ gdb, not an x86 gdb) ``` $ arm-none-eabi-gdb fancyblink.elf ... (gdb) tar extended-remote :4242 ... (gdb) load Loading section .text, size 0x458 lma 0x8000000 Loading section .data, size 0x8 lma 0x8000458 Start address 0x80001c1, load size 1120 Transfer rate: 1 KB/sec, 560 bytes/write. (gdb) ... (gdb) continue ``` ## Resetting the chip from GDB You may reset the chip using GDB if you want. You'll need to use `target extended-remote' command like in this session: ``` (gdb) target extended-remote localhost:4242 Remote debugging using localhost:4242 0x080007a8 in _startup () (gdb) kill Kill the program being debugged? (y or n) y (gdb) run Starting program: /home/whitequark/ST/apps/bally/firmware.elf ``` Note that st-link does not support 'run', as it does not load arbitrary programs without explicit commands. In order to continue, one can use 'monitor reset' to reset the MCU. Remember that you can shorten the commands. `tar ext :4242` is good enough for GDB. If you need to send a reset signal, you can use the following command: ``` (gdb) monitor jtag_reset ``` ## Disassembling THUMB code in GDB By default, the disassemble command in GDB operates in ARM mode. The programs running on CORTEX-M3 are compiled in THUMB mode. To correctly disassemble them under GDB, uses an odd address. For instance, if you want to disassemble the code at 0x20000000, use: ``` (gdb) disassemble 0x20000001 ``` ## Running programs from SRAM You can run your firmware directly from SRAM if you want to. Just link it at 0x20000000 and do ``` (gdb) load firmware.elf ``` It will be loaded, and pc will be adjusted to point to start of the code, if it is linked correctly (i.e. ELF has correct entry point). ## Writing to flash The GDB stub ships with a correct memory map, including the flash area. If you would link your executable to `0x08000000` and then do ``` (gdb) load firmware.elf ``` then it would be written to the memory. stlink-1.9.0/doc/version_support.md000066400000000000000000000032261526027543100174050ustar00rootroot00000000000000## Supported Operating Systems ### Microsoft Windows Up on compiling c-make will **automatically** download and install the latest compatible version of `libusb`. - Windows 11 (GitHub-Actions CI-test environment) - Windows 10 ### Apple macOS: - macOS 26 [Tahoe] (GitHub-Actions CI-test environment) ### Linux-/Unix-based: Actively maintained versions of: - Debian - Ubuntu - Fedora - openSUSE - OpenMandriva - Arch Linux - FreeBSD - NetBSD - OpenBSD - KaOS - Solus - Void Linux Other Linux-/Unix-based Operating Systems: | Operating System | libusb | cmake | libgtk-dev | End of
OS-Support | | ------------------------ | ----------- | ---------- | ----------- | ---------------------- | | CentOS Stream 9 [x64] | 1.0.26 | 3.**26.5** | 3.24.31 | May 2027 | | Mageia 9 [x64] | 1.0.26 | 3.**26.4** | 3.24.38 | | | Slackware 15 [x64] | 1.0.**24** | 3.**24.1** | 3.24.31 | | | NetBSD 9.x | 1.0.**24** | 3.**21.2** | 3.24.30 | | ## Unsupported Operating Systems (as of Release v1.8.1) Systems with highlighted versions remain compatible with this toolset until further notice. | Operating System | libusb | cmake | End of
OS-Support | | ---------------- | ----------- | ---------- | ---------------------- | | Alpine 3.15 | 1.0.**24** | 3.**21.3** | Nov 2023 | | Fedora 35 [x64] | 1.0.**24** | 3.**21.3** | Dec 2022 | | FreeBSD 13.x | 1.0.**24** | 3.**22.1** | Jan 2026 | _All other operating systems which are not listed are unsupported._ stlink-1.9.0/flashloaders/000077500000000000000000000000001526027543100155015ustar00rootroot00000000000000stlink-1.9.0/flashloaders/Makefile000066400000000000000000000022271526027543100171440ustar00rootroot00000000000000# The flash loader code cannot be compiled by the system gcc. # This makefile uses arm-none-eabi-gcc for this purpose. CROSS_COMPILE ?= arm-none-eabi- CC = $(CROSS_COMPILE)gcc OBJCOPY = $(CROSS_COMPILE)objcopy XXD = xxd XXDFLAGS = -i -c 4 CFLAGS_ARMV6_M = -mcpu=Cortex-M0 -Tlinker.ld -ffreestanding -nostdlib CFLAGS_ARMV7_M = -mcpu=Cortex-M3 -Tlinker.ld -ffreestanding -nostdlib all: stm32vl.h stm32f0.h stm32wb0.h stm32lx.h stm32f4.h stm32f4lv.h stm32l4.h stm32f7.h stm32f7lv.h stm32h5.h %.h: %.bin $(XXD) $(XXDFLAGS) $< $@ %.bin: %.o $(OBJCOPY) -O binary $< $@ rm $< # separate rule for STM32F0 stm32f0.o: stm32f0.s $(CC) stm32f0.s $(CFLAGS_ARMV6_M) -o stm32f0.o # separate rule for STM32WB0 (Cortex M0+) stm32wb0.o: stm32wb0.s $(CC) stm32wb0.s $(CFLAGS_ARMV6_M) -o stm32wb0.o # separate rule for STM32F1/F3 stm32vl.o: stm32f0.s $(CC) stm32f0.s $(CFLAGS_ARMV7_M) -o stm32vl.o # separate rule for STM32Lx. # Built for ARMv6-M target to be compatible with both Cortex M0 and Cortex M3. stm32lx.o: stm32lx.s $(CC) stm32lx.s $(CFLAGS_ARMV6_M) -o stm32lx.o # generic rule for all other ARMv7-M %.o: %.s $(CC) $< $(CFLAGS_ARMV7_M) -o $@ clean: rm -f *.h stlink-1.9.0/flashloaders/cleanroom.md000066400000000000000000000156171526027543100200140ustar00rootroot00000000000000# Flash Loader Documentation Code is situated in section `.text` Shall add a compile directive at the head: `.syntax unified` **Calling convention**: All parameters would be passed over registers `r0`: the base address of the copy source `r1`: the base address of the copy destination `r2`: the count of byte to be copied `r3`: flash register offset (used to support two banks) **What the program is expected to do**: Copy data from source to destination, after which trigger a breakpint to exit. Before exit, `r2` must be less or equal to zero to indicate that the copy is done. **Limitation**: No stack operations are permitted. Registers ranging from `r3` to `r12` are free to use. Note that `r13` is `sp`(stack pointer), `r14` is `lr`(commonly used to store jump address), `r15` is `pc`(program counter). **Requirement**: After every single copy, wait until the flash finishes. The detailed single copy length and the way to check can be found below. Address of `flash_base` shall be two-bytes aligned. ## stm32f0.s `flash_base`: 0x40022000 `FLASH_CR`: offset from `flash_base` is 16 `FLASH_SR`: offset from `flash_base` is 12 **Reference**: [https://chromium.googlesource.com/chromiumos/platform/ec/+/master/chip/stm32/registers-stm32f0.h](https://chromium.googlesource.com/chromiumos/platform/ec/+/master/chip/stm32/registers-stm32f0.h) [https://www.st.com/resource/en/reference_manual/dm00031936-stm32f0x1stm32f0x2stm32f0x8-advanced-armbased-32bit-mcus-stmicroelectronics.pdf](https://www.st.com/resource/en/reference_manual/dm00031936-stm32f0x1stm32f0x2stm32f0x8-advanced-armbased-32bit-mcus-stmicroelectronics.pdf) **Special requirements**: Before every copy, read a word from FLASH_CR, set the PG bit to 1 and write back. Copy one half word each time. How to wait for the write process: Read a word from FLASH_SR, loop until the busy bit is reset. After that, FLASH_SR is checked. The process is interrupted if the error bit (0x04) is set. Exit: After the copying process and before triggering the breakpoint, clear the PG bit in FLASH_CR. ## stm32wb0.s `flash_origin`: 0x10040000 (start of flash in memory map) `flash_base`: 0x40001000 (base address of the `FLASH` controller peripheral) **Reference**: [STM32WB05 RM0491](https://www.st.com/resource/en/reference_manual/rm0491-the-bluenrglps-arm-cortex-m0based-stmicroelectronics.pdf) [STM32WB06/07 RM0530](https://www.st.com/resource/en/reference_manual/rm0530--stm32wb07xc-and-stm32wb06xc-ultralow-power-wireless-32bit-mcus-armbased-cortexm0-with-bluetooth-low-energy-and-24-ghz-radio-solution-stmicroelectronics.pdf) [STM32WB09 RM0505](https://www.st.com/resource/en/reference_manual/rm0505-stm32wb09xe-ultralow-power-wireless-32bit-mcu-armbased-cortexm0-with-bluetooth-low-energy-and-24-ghz-radio-solution-stmicroelectronics.pdf) [STM32WL3x RM0511](https://www.st.com/resource/en/reference_manual/rm0511-stm32wl33xx-armbased-wireless-mcus-with-subghz-radio-solution-stmicroelectronics.pdf) **Special requirements**: Data is flashed in blocks of 16 bytes, so the destination address must be aligned to 16, and the length must be a multiple of 16 bytes. In contrast to other STM32 devices, writing happens through registers of the `FLASH` peripheral. The loader exits early if an error is encountered - `r2` holds the number that didn't get written. ## stm32f4.s `flash_base`: 0x40023c00 `FLASH_SR`: offset from `flash_base` is 0xe (14) **Reference**: [https://chromium.googlesource.com/chromiumos/platform/ec/+/master/chip/stm32/registers-stm32f4.h](https://chromium.googlesource.com/chromiumos/platform/ec/+/master/chip/stm32/registers-stm32f4.h) [https://www.st.com/content/ccc/resource/technical/document/reference_manual/3d/6d/5a/66/b4/99/40/d4/DM00031020.pdf/files/DM00031020.pdf/jcr:content/translations/en.DM00031020.pdf](https://www.st.com/content/ccc/resource/technical/document/reference_manual/3d/6d/5a/66/b4/99/40/d4/DM00031020.pdf/files/DM00031020.pdf/jcr:content/translations/en.DM00031020.pdf) **Special requirements**: Copy one word each time. How to wait for the write process: Read a word from FLASH_SR, loop until the busy bit is reset. ## stm32f4lv.s `flash_base`: 0x40023c00 `FLASH_SR`: offset from `flash_base` is 0xe (14) **Reference**: [https://chromium.googlesource.com/chromiumos/platform/ec/+/master/chip/stm32/registers-stm32f4.h](https://chromium.googlesource.com/chromiumos/platform/ec/+/master/chip/stm32/registers-stm32f4.h) [https://www.st.com/content/ccc/resource/technical/document/reference_manual/3d/6d/5a/66/b4/99/40/d4/DM00031020.pdf/files/DM00031020.pdf/jcr:content/translations/en.DM00031020.pdf](https://www.st.com/content/ccc/resource/technical/document/reference_manual/3d/6d/5a/66/b4/99/40/d4/DM00031020.pdf/files/DM00031020.pdf/jcr:content/translations/en.DM00031020.pdf) **Special Requirements**: Copy one byte each time. How to wait from the write process: read a half word from FLASH_SR, loop until the busy bit is reset. ## stm32f7.s **Reference**: [https://chromium.googlesource.com/chromiumos/platform/ec/+/master/chip/stm32/registers-stm32f7.h](https://chromium.googlesource.com/chromiumos/platform/ec/+/master/chip/stm32/registers-stm32f7.h) [https://www.st.com/resource/en/reference_manual/dm00124865-stm32f75xxx-and-stm32f74xxx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf](https://www.st.com/resource/en/reference_manual/dm00124865-stm32f75xxx-and-stm32f74xxx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf) Mostly same with `stm32f4.s`. Require establishing a memory barrier after every copy and before checking for finished writing by `dsb sy` ## stm32f7lv.s **Reference**: [https://chromium.googlesource.com/chromiumos/platform/ec/+/master/chip/stm32/registers-stm32f7.h](https://chromium.googlesource.com/chromiumos/platform/ec/+/master/chip/stm32/registers-stm32f7.h) [https://www.st.com/resource/en/reference_manual/dm00124865-stm32f75xxx-and-stm32f74xxx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf](https://www.st.com/resource/en/reference_manual/dm00124865-stm32f75xxx-and-stm32f74xxx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf) **Special Requirements**: Mostly same with `stm32f7.s`. Copy one byte each time. ## stm32lx.s **Special Requirements**: Copy one word each time. No wait for write. ## stm32l4.s `flash_base`: 0x40022000 `FLASH_BSY`: offset from `flash_base` is 0x12 **Reference**: [https://chromium.googlesource.com/chromiumos/platform/ec/+/master/chip/stm32/registers-stm32l4.h](https://chromium.googlesource.com/chromiumos/platform/ec/+/master/chip/stm32/registers-stm32l4.h) [https://www.st.com/resource/en/reference_manual/dm00310109-stm32l4-series-advanced-armbased-32bit-mcus-stmicroelectronics.pdf](https://www.st.com/resource/en/reference_manual/dm00310109-stm32l4-series-advanced-armbased-32bit-mcus-stmicroelectronics.pdf) **Special Requirements**: Copy one double word each time (More than one register is allowed). How to wait for the write process: read a half word from `FLASH_BSY`, loop until the busy bit is reset.stlink-1.9.0/flashloaders/linker.ld000066400000000000000000000001751526027543100173110ustar00rootroot00000000000000/* Entry Point */ ENTRY(copy) /* Specify the memory areas */ MEMORY { RAM (xrw) : ORIGIN = 0x20000000 , LENGTH = 64K } stlink-1.9.0/flashloaders/stm32f0.s000066400000000000000000000031571526027543100170710ustar00rootroot00000000000000 .syntax unified .text /* * Arguments: * r0 - source memory ptr * r1 - target memory ptr * r2 - count of bytes * r3 - flash register offset */ .global copy copy: /* * These two NOPs here are a safety precaution, added by Pekka Nikander * while debugging the STM32F05x support. They may not be needed, but * there were strange problems with simpler programs, like a program * that had just a breakpoint or a program that first moved zero to register r2 * and then had a breakpoint. So, it appears safest to have these two nops. * * Feel free to remove them, if you dare, but then please do test the result * rigorously. Also, if you remove these, it may be a good idea first to * #if 0 them out, with a comment when these were taken out, and to remove * these only a few months later... But YMMV. */ nop nop # load flash control register address # add r3 to flash_base for support dual bank (see flash_loader.c) ldr r7, flash_base add r7, r7, r3 ldr r5, flash_off_sr add r5, r5, r7 loop: # copy 2 bytes ldrh r4, [r0] strh r4, [r1] # increment address adds r0, r0, #0x2 adds r1, r1, #0x2 # BUSY flag ldr r7, =0x01 wait: # get FLASH_SR ldr r4, [r5] # wait until BUSY flag is reset tst r4, r7 bne wait # test PGERR or WRPRTERR flag is reset ldr r7, =0x14 tst r4, r7 bne exit # loop if count > 0 subs r2, r2, #0x2 bgt loop exit: bkpt .align 2 flash_base: .word 0x40022000 flash_off_sr: .word 0x0c stlink-1.9.0/flashloaders/stm32f4.s000066400000000000000000000012421526027543100170660ustar00rootroot00000000000000 .syntax unified .text /* * Arguments: * r0 - source memory ptr * r1 - target memory ptr * r2 - count of bytes * r3 - flash register offset */ .global copy copy: ldr r12, flash_base ldr r10, flash_off_sr add r10, r10, r12 loop: # copy 4 bytes ldr r4, [r0] str r4, [r1] # increment address add r0, r0, #4 add r1, r1, #4 wait: # get FLASH_SR ldrh r4, [r10] # wait until BUSY flag is reset tst r4, #0x1 bne wait # loop if count > 0 subs r2, r2, #4 bgt loop exit: bkpt .align 2 flash_base: .word 0x40023c00 flash_off_sr: .word 0x0e stlink-1.9.0/flashloaders/stm32f4lv.s000066400000000000000000000012431526027543100174310ustar00rootroot00000000000000 .syntax unified .text /* * Arguments: * r0 - source memory ptr * r1 - target memory ptr * r2 - count of bytes * r3 - flash register offset */ .global copy copy: ldr r12, flash_base ldr r10, flash_off_sr add r10, r10, r12 loop: # copy 1 byte ldrb r4, [r0] strb r4, [r1] # increment address add r0, r0, #1 add r1, r1, #1 wait: # get FLASH_SR ldrh r4, [r10] # wait until BUSY flag is reset tst r4, #0x1 bne wait # loop if count > 0 subs r2, r2, #1 bgt loop exit: bkpt .align 2 flash_base: .word 0x40023c00 flash_off_sr: .word 0x0e stlink-1.9.0/flashloaders/stm32f7.s000066400000000000000000000013071526027543100170730ustar00rootroot00000000000000 .syntax unified .text /* * Arguments: * r0 - source memory ptr * r1 - target memory ptr * r2 - count of bytes * r3 - flash register offset */ .global copy copy: ldr r12, flash_base ldr r10, flash_off_sr add r10, r10, r12 loop: # copy 4 bytes ldr r4, [r0] str r4, [r1] # increment address add r0, r0, #4 add r1, r1, #4 # memory barrier dsb sy wait: # get FLASH_SR ldrh r4, [r10] # wait until BUSY flag is reset tst r4, #0x1 bne wait # loop if count > 0 subs r2, r2, #4 bgt loop exit: bkpt .align 2 flash_base: .word 0x40023c00 flash_off_sr: .word 0x0e stlink-1.9.0/flashloaders/stm32f7lv.s000066400000000000000000000013041526027543100174320ustar00rootroot00000000000000 .syntax unified .text /* * Arguments: * r0 - source memory ptr * r1 - target memory ptr * r2 - count of bytes * r3 - flash register offset */ .global copy copy: ldr r12, flash_base ldr r10, flash_off_sr add r10, r10, r12 loop: # copy 1 byte ldrb r4, [r0] strb r4, [r1] # increment address add r0, r0, #1 add r1, r1, #1 # memory barrier dsb sy wait: # get FLASH_SR ldrh r4, [r10] # wait until BUSY flag is reset tst r4, #0x1 bne wait # loop if count > 0 subs r2, r2, #1 bgt loop exit: bkpt .align 2 flash_base: .word 0x40023c00 flash_off_sr: .word 0x0e stlink-1.9.0/flashloaders/stm32h5.s000066400000000000000000000024101526027543100170670ustar00rootroot00000000000000 .syntax unified .text /* * STM32H5 flash loader. * * Arguments: * r0 - source memory ptr (SRAM staging buffer) * r1 - target memory ptr (flash) * r2 - count of bytes (padded to a multiple of 16 by the host) * r3 - flash register base (unused: the host unlocks flash and sets the * NSCR PG bit before running, and clears it afterwards) * * The H5 NVM is programmed one 128-bit quad-word (16 bytes) at a time. * FLASH_NSSR is at 0x40022020, with BSY in bit 0 (RM0481). */ .global copy copy: ldr r12, flash_base ldr r10, flash_off_sr add r10, r10, r12 loop: # copy one 16-byte quad-word ldr r4, [r0] ldr r5, [r0, #4] ldr r6, [r0, #8] ldr r7, [r0, #12] str r4, [r1] str r5, [r1, #4] str r6, [r1, #8] str r7, [r1, #12] # increment addresses add r0, r0, #16 add r1, r1, #16 # ensure the quad-word write has been issued before polling status dsb sy wait: # get FLASH_NSSR ldr r4, [r10] # wait until the BUSY flag (bit 0) is reset tst r4, #0x1 bne wait # loop while bytes remain subs r2, r2, #16 bgt loop exit: bkpt .align 2 flash_base: .word 0x40022000 flash_off_sr: .word 0x20 stlink-1.9.0/flashloaders/stm32l4.s000066400000000000000000000013171526027543100170770ustar00rootroot00000000000000 .syntax unified .text /* * Arguments: * r0 - source memory ptr * r1 - target memory ptr * r2 - count of bytes * r3 - flash register offset */ .global copy copy: ldr r12, flash_base ldr r10, flash_off_sr add r10, r10, r12 loop: # copy 8 bytes ldr r5, [r0] ldr r4, [r0, #4] str r5, [r1] str r4, [r1, #4] # increment address add r0, r0, #8 add r1, r1, #8 wait: # get FLASH_SR ldr r4, [r10] # wait until BUSY flag is reset tst r4, #0x10000 bne wait # loop if count > 0 subs r2, r2, #8 bgt loop exit: bkpt .align 2 flash_base: .word 0x40022000 flash_off_sr: .word 0x10 stlink-1.9.0/flashloaders/stm32lx.s000066400000000000000000000006371526027543100172070ustar00rootroot00000000000000 .syntax unified .text /* * Arguments: * r0 - source memory ptr * r1 - target memory ptr * r2 - count of bytes * r3 - flash register offset */ .global copy copy: loop: # copy 4 bytes ldr r4, [r0] str r4, [r1] # increment address adds r0, r0, #4 adds r1, r1, #4 # loop if count > 0 subs r2, r2, #4 bgt loop exit: bkpt stlink-1.9.0/flashloaders/stm32wb0.s000066400000000000000000000027331526027543100172530ustar00rootroot00000000000000 .syntax unified .text /* * Arguments: * r0 - source memory ptr * r1 - target memory ptr * r2 - count of bytes * Register usage: * r0 - SRAM source pointer (incrementing) * r1 - FLASH word address (incrementing) * r2 - remaining bytes count (decrementing) * r3 - scratch * r4 - scratch * r5 - scratch * r6 - scratch * r7 - FLASH peripheral pointer */ .global copy copy: # subtract flash_origin and divide by 4, to get a FLASH word address ldr r3, flash_origin subs r1, r3 lsrs r1, #2 # load address of FLASH peripheral ldr r7, flash_base loop: # fill ADDRESS (@ 0x18) str r1, [r7, #0x18] # fill DATA0-3 (@ 0x40 - 0x4C) adds r7, #0x40 ldmia r0!, { r3, r4, r5, r6 } stmia r7!, { r3, r4, r5, r6 } subs r7, #0x50 # clear CMDDONE, CMDERR and ILLCMD in IRQRAW (@0x10) movs r5, #0x0D str r5, [r7, #0x10] # write BURSTWRITE to COMMAND (@ 0x00) movs r4, #0xCC str r4, [r7] wait: # wait until CMDDONE, CMDERR or ILLCMD is set in IRQRAW ldr r4, [r7, #0x10] ands r4, r5 beq wait # remove the lowest bit (CMDDONE), exit if error bits remain lsrs r4, #1 bne exit # add 4 words to ADDRESS, subtract 16 bytes from count adds r1, #4 subs r2, #16 # loop if count > 0 bgt loop exit: bkpt .align 2 flash_base: .word 0x40001000 flash_origin: .word 0x10040000 stlink-1.9.0/gen_binaries_msvc.bat000066400000000000000000000036621526027543100172060ustar00rootroot00000000000000@echo off echo Building stlink binaries for MSVC with vcpkg dependencies setlocal set "STLINK_GENERATOR=Visual Studio 17 2022" set "STLINK_BUILD_DIR=build/msvc-vcpkg-vs17" set "STLINK_CMAKE_MIN=3.21" set "STLINK_VSWHERE=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" if exist "%STLINK_VSWHERE%" ( for /f "delims=" %%I in ('call "%STLINK_VSWHERE%" -latest ^ -products * -version "[17.0,18.0,19.0)" ^ -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 ^ -property installationPath') do ( set "STLINK_GENERATOR=Visual Studio 18 2026" set "STLINK_BUILD_DIR=build/msvc-vcpkg-vs18" set "STLINK_CMAKE_MIN=4.2" ) ) for /f "tokens=3" %%V in ('cmake --version ^| findstr /b /c:"cmake version"') do set "STLINK_CMAKE_VERSION=%%V" if not defined STLINK_CMAKE_VERSION ( echo ERROR: could not determine the installed CMake version. Is cmake on PATH? exit /b 1 ) call :version_less "%STLINK_CMAKE_VERSION%" "%STLINK_CMAKE_MIN%" STLINK_CMAKE_TOO_OLD if "%STLINK_CMAKE_TOO_OLD%"=="1" ( echo ERROR: %STLINK_GENERATOR% requires CMake %STLINK_CMAKE_MIN%+, found %STLINK_CMAKE_VERSION%. echo Install a matching CMake version, or install a Visual Studio version echo supported by your current CMake - see doc/compiling.md. exit /b 1 ) echo Using %STLINK_GENERATOR% cmake -S . -B "%STLINK_BUILD_DIR%" -G "%STLINK_GENERATOR%" -A x64 ^ "-DCMAKE_TOOLCHAIN_FILE=%VCPKG_ROOT%\scripts\buildsystems\vcpkg.cmake" || goto :error cmake --build "%STLINK_BUILD_DIR%" --config Release || goto :error :ok exit /b 0 :error exit /b %errorlevel% :version_less setlocal for /f "tokens=1,2 delims=." %%A in ("%~1") do (set "A_MAJ=%%A" & set "A_MIN=%%B") for /f "tokens=1,2 delims=." %%A in ("%~2") do (set "B_MAJ=%%A" & set "B_MIN=%%B") set "RESULT=0" if %A_MAJ% LSS %B_MAJ% set "RESULT=1" if %A_MAJ% EQU %B_MAJ% if %A_MIN% LSS %B_MIN% set "RESULT=1" endlocal & set "%~3=%RESULT%" exit /b 0 stlink-1.9.0/gen_binaries_win.sh000066400000000000000000000015601526027543100166720ustar00rootroot00000000000000### # Build package with binaries for Windows ### # Ensure the target distribution directory exists before copying mkdir -p build/Release/dist # i686 (32-bit) mkdir -p build-mingw-32 cd build-mingw-32 cmake -DTOOLCHAIN_PREFIX=i686-w64-mingw32 \ -DCMAKE_TOOLCHAIN_FILE=../cmake/modules/set_toolchain.cmake \ -DCMAKE_SYSTEM_PROCESSOR="i686" \ -DCMAKE_C_FLAGS="-D_WIN32" \ -DSTLINK_GENERATE_GUI=OFF \ .. make package sudo cp dist/*.zip ../build/Release/dist make clean cd .. # x86_64 (64-bit) mkdir -p build-mingw-64 cd build-mingw-64 cmake -DTOOLCHAIN_PREFIX=x86_64-w64-mingw32 \ -DCMAKE_TOOLCHAIN_FILE=../cmake/modules/set_toolchain.cmake \ -DCMAKE_SYSTEM_PROCESSOR="x86_64" \ -DCMAKE_C_FLAGS="-D_WIN32 -D_AMD64_" \ -DSTLINK_GENERATE_GUI=OFF \ .. make package sudo cp dist/*.zip ../build/Release/dist make clean cd ..stlink-1.9.0/inc/000077500000000000000000000000001526027543100136035ustar00rootroot00000000000000stlink-1.9.0/inc/stlink.h000066400000000000000000000232351526027543100152650ustar00rootroot00000000000000/** ****************************************************************************** * @file : stlink.h * @brief : Common top level stlink interfaces * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #ifndef STLINK_H #define STLINK_H #include #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif #define STLINK_ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) /* Max data transfer size */ // 6 kB = max mem32_read block, 8 kB sram // #define Q_BUF_LEN 96 #define Q_BUF_LEN (1024 * 100) /* Statuses of core */ enum target_state { TARGET_UNKNOWN = 0, TARGET_RUNNING = 1, TARGET_HALTED = 2, TARGET_RESET = 3, TARGET_DEBUG_RUNNING = 4, }; #define STLINK_CORE_RUNNING 0x80 #define STLINK_CORE_HALTED 0x81 /* STLINK modes */ #define STLINK_DEV_DFU_MODE 0 #define STLINK_DEV_MASS_MODE 1 #define STLINK_DEV_DEBUG_MODE 2 #define STLINK_DEV_UNKNOWN_MODE -1 /* NRST pin states */ #define STLINK_DEBUG_APIV2_DRIVE_NRST_LOW 0x00 #define STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH 0x01 /* Baud rate divisors for SWDCLK */ #define STLINK_SWDCLK_4MHZ_DIVISOR 0 #define STLINK_SWDCLK_1P8MHZ_DIVISOR 1 #define STLINK_SWDCLK_1P2MHZ_DIVISOR 2 #define STLINK_SWDCLK_950KHZ_DIVISOR 3 #define STLINK_SWDCLK_480KHZ_DIVISOR 7 #define STLINK_SWDCLK_240KHZ_DIVISOR 15 #define STLINK_SWDCLK_125KHZ_DIVISOR 31 #define STLINK_SWDCLK_100KHZ_DIVISOR 40 #define STLINK_SWDCLK_50KHZ_DIVISOR 79 #define STLINK_SWDCLK_25KHZ_DIVISOR 158 #define STLINK_SWDCLK_15KHZ_DIVISOR 265 #define STLINK_SWDCLK_5KHZ_DIVISOR 798 #define STLINK_SERIAL_LENGTH 24 #define STLINK_SERIAL_BUFFER_SIZE (STLINK_SERIAL_LENGTH + 1) #define STLINK_V3_MAX_FREQ_NB 10 #define STLINK_V2_TRACE_BUF_LEN 2048 #define STLINK_V3_TRACE_BUF_LEN 8192 #define STLINK_V2_MAX_TRACE_FREQUENCY 2000000 #define STLINK_V3_MAX_TRACE_FREQUENCY 24000000 #define STLINK_DEFAULT_TRACE_FREQUENCY 2000000 /* Map the relevant features, quirks and workaround for specific firmware version of stlink */ #define STLINK_F_HAS_TRACE (1U << 0) #define STLINK_F_HAS_SWD_SET_FREQ (1U << 1) #define STLINK_F_HAS_JTAG_SET_FREQ (1U << 2) #define STLINK_F_HAS_MEM_16BIT (1U << 3) #define STLINK_F_HAS_GETLASTRWSTATUS2 (1U << 4) #define STLINK_F_HAS_DAP_REG (1U << 5) #define STLINK_F_QUIRK_JTAG_DP_READ (1U << 6) #define STLINK_F_HAS_AP_INIT (1U << 7) #define STLINK_F_HAS_DPBANKSEL (1U << 8) #define STLINK_F_HAS_RW8_512BYTES (1U << 9) /* Additional MCU features */ #define CHIP_F_HAS_DUAL_BANK (1U << 0) #define CHIP_F_HAS_SWO_TRACING (1U << 1) /* Error code */ #define STLINK_DEBUG_ERR_OK 0x80 #define STLINK_DEBUG_ERR_FAULT 0x81 #define STLINK_DEBUG_ERR_WRITE 0x0c #define STLINK_DEBUG_ERR_WRITE_VERIFY 0x0d #define STLINK_DEBUG_ERR_AP_WAIT 0x10 #define STLINK_DEBUG_ERR_AP_FAULT 0x11 #define STLINK_DEBUG_ERR_AP_ERROR 0x12 #define STLINK_DEBUG_ERR_DP_WAIT 0x14 #define STLINK_DEBUG_ERR_DP_FAULT 0x15 #define STLINK_DEBUG_ERR_DP_ERROR 0x16 #define CMD_CHECK_NO 0 #define CMD_CHECK_REP_LEN 1 #define CMD_CHECK_STATUS 2 #define CMD_CHECK_RETRY 3 // check status and retry if wait error #define C_BUF_LEN 32 struct stlink_reg { uint32_t r[16]; uint32_t s[32]; uint32_t xpsr; uint32_t main_sp; uint32_t process_sp; uint32_t rw; uint32_t rw2; uint8_t control; uint8_t faultmask; uint8_t basepri; uint8_t primask; uint32_t fpscr; }; typedef uint32_t stm32_addr_t; typedef struct flash_loader { stm32_addr_t loader_addr; // loader sram addr stm32_addr_t buf_addr; // buffer sram address uint32_t rcc_dma_bkp; // backup RCC DMA enable state uint32_t iwdg_kr; // IWDG key register address } flash_loader_t; typedef struct _cortex_m3_cpuid_ { uint16_t implementer_id; uint16_t variant; uint16_t part; uint8_t revision; } cortex_m3_cpuid_t; enum stlink_jtag_api_version { STLINK_JTAG_API_V1 = 1, STLINK_JTAG_API_V2, STLINK_JTAG_API_V3, }; typedef struct stlink_version_ { uint32_t stlink_v; uint32_t jtag_v; uint32_t swim_v; uint32_t st_vid; uint32_t stlink_pid; // jtag api version supported enum stlink_jtag_api_version jtag_api; // one bit for each feature supported. See macros STLINK_F_* uint32_t flags; } stlink_version_t; enum transport_type { TRANSPORT_TYPE_ZERO = 0, TRANSPORT_TYPE_LIBSG, TRANSPORT_TYPE_LIBUSB, TRANSPORT_TYPE_INVALID }; enum connect_type { CONNECT_HOT_PLUG = 0, CONNECT_NORMAL = 1, CONNECT_UNDER_RESET = 2, }; enum reset_type { RESET_AUTO = 0, RESET_HARD = 1, RESET_SOFT = 2, RESET_SOFT_AND_HALT = 3, }; enum run_type { RUN_NORMAL = 0, RUN_FLASH_LOADER = 1, }; typedef struct _stlink stlink_t; #include "stm32.h" #include "stlink_backend.h" struct _stlink { struct _stlink_backend *backend; void *backend_data; // room for the command header unsigned char c_buf[C_BUF_LEN]; // data transferred from or to device unsigned char q_buf[Q_BUF_LEN]; int32_t q_len; // transport layer verboseness: 0 for no debug info, 10 for lots int32_t verbose; int32_t opt; uint32_t core_id; // set by stlink_core_id(), result from STLINK_DEBUGREADCOREID uint32_t chip_id; // set by stlink_load_device_params(), used to identify flash and sram uint8_t ap; // set by stlink_probe_ap(), access port for debug/memory access (0 = AP0) enum target_state core_stat; // set by stlink_status() char serial[STLINK_SERIAL_BUFFER_SIZE]; int32_t freq; // set by stlink_open_usb(), values: STLINK_SWDCLK_xxx_DIVISOR enum stm32_flash_type flash_type; // stlink_chipid_params.flash_type, set by stlink_load_device_params(), values: STM32_FLASH_TYPE_xx stm32_addr_t flash_base; // STM32_FLASH_BASE, set by stlink_load_device_params() uint32_t flash_size; // calculated by stlink_load_device_params() uint32_t flash_pgsz; // stlink_chipid_params.flash_pagesize, set by stlink_load_device_params() /* sram settings */ stm32_addr_t sram_base; // STM32_SRAM_BASE, set by stlink_load_device_params() uint32_t sram_size; // stlink_chipid_params.sram_size, set by stlink_load_device_params() /* option settings */ stm32_addr_t option_base; uint32_t option_size; // bootloader // sys_base and sys_size are not used by the tools, but are only there to download the bootloader code // (see tests/sg_legacy.c) stm32_addr_t sys_base; // stlink_chipid_params.bootrom_base, set by stlink_load_device_params() uint32_t sys_size; // stlink_chipid_params.bootrom_size, set by stlink_load_device_params() struct stlink_version_ version; uint32_t chip_flags; // stlink_chipid_params.flags, set by stlink_load_device_params(), values: CHIP_F_xxx uint32_t max_trace_freq; // set by stlink_open_usb() uint32_t otp_base; uint32_t otp_size; }; /* === Declaration of functions defined in common_legacy.c and sg_legacy.c === */ uint32_t stlink_calculate_pagesize(stlink_t *sl, uint32_t flashaddr); int32_t stlink_chip_id(stlink_t *sl, uint32_t *chip_id); void stlink_close(stlink_t *sl); int32_t stlink_core_id(stlink_t *sl); void stlink_core_stat(stlink_t *sl); int32_t stlink_cpu_id(stlink_t *sl, cortex_m3_cpuid_t *cpuid); int32_t stlink_current_mode(stlink_t *sl); int32_t stlink_enter_jtag_mode(stlink_t *sl); int32_t stlink_enter_swd_mode(stlink_t *sl); int32_t stlink_exit_debug_mode(stlink_t *sl); int32_t stlink_exit_dfu_mode(stlink_t *sl); int32_t stlink_force_debug(stlink_t *sl); int32_t stlink_fread(stlink_t* sl, const char* path, bool is_ihex, stm32_addr_t addr, uint32_t size); int32_t stlink_fwrite_sram(stlink_t *sl, const char* path, stm32_addr_t addr); uint8_t stlink_get_erased_pattern(stlink_t *sl); bool stlink_is_core_halted(stlink_t *sl); int32_t stlink_load_device_params(stlink_t *sl); int32_t stlink_mwrite_sram(stlink_t *sl, uint8_t* data, uint32_t length, stm32_addr_t addr); int32_t stlink_parse_ihex(const char* path, uint8_t erased_pattern, uint8_t* *mem, uint32_t* size, uint32_t* begin); void stlink_print_data(stlink_t *sl); int32_t stlink_reset(stlink_t *sl, enum reset_type type); int32_t stlink_run(stlink_t *sl, enum run_type type); void stlink_run_at(stlink_t *sl, stm32_addr_t addr); int32_t stlink_set_swdclk(stlink_t *sl, int32_t freq_khz); int32_t stlink_status(stlink_t *sl); int32_t stlink_step(stlink_t *sl); int32_t stlink_target_connect(stlink_t *sl, enum connect_type connect); int32_t stlink_target_voltage(stlink_t *sl); int32_t stlink_version(stlink_t *sl); int32_t stlink_write_buffer_to_sram(stlink_t *sl, flash_loader_t* fl, const uint8_t* buf, uint16_t size, uint16_t padded_size); #ifdef __cplusplus } #endif #endif // STLINK_H stlink-1.9.0/inc/stlink_backend.h000066400000000000000000000052311526027543100167300ustar00rootroot00000000000000/** ****************************************************************************** * @file : stlink_backend.h * @brief : stlink backend * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #ifndef STLINK_BACKEND_H #define STLINK_BACKEND_H #include typedef struct _stlink_backend { void (*close) (stlink_t * sl); int32_t (*exit_debug_mode) (stlink_t * sl); int32_t (*enter_swd_mode) (stlink_t * sl); int32_t (*enter_jtag_mode) (stlink_t * stl); int32_t (*exit_dfu_mode) (stlink_t * stl); int32_t (*core_id) (stlink_t * stl); int32_t (*reset) (stlink_t * stl); int32_t (*jtag_reset) (stlink_t * stl, int32_t value); int32_t (*run) (stlink_t * stl, enum run_type type); int32_t (*status) (stlink_t * stl); int32_t (*version) (stlink_t *sl); int32_t (*read_debug32) (stlink_t *sl, uint32_t addr, uint32_t *data); int32_t (*read_mem32) (stlink_t *sl, uint32_t addr, uint16_t len); int32_t (*write_debug32) (stlink_t *sl, uint32_t addr, uint32_t data); int32_t (*write_mem32) (stlink_t *sl, uint32_t addr, uint16_t len); int32_t (*write_mem8) (stlink_t *sl, uint32_t addr, uint16_t len); int32_t (*read_all_regs) (stlink_t *sl, struct stlink_reg * regp); int32_t (*read_reg) (stlink_t *sl, int32_t r_idx, struct stlink_reg * regp); int32_t (*read_all_unsupported_regs) (stlink_t *sl, struct stlink_reg *regp); int32_t (*read_unsupported_reg) (stlink_t *sl, int32_t r_idx, struct stlink_reg *regp); int32_t (*write_unsupported_reg) (stlink_t *sl, uint32_t value, int32_t idx, struct stlink_reg *regp); int32_t (*write_reg) (stlink_t *sl, uint32_t reg, int32_t idx); int32_t (*step) (stlink_t * stl); int32_t (*current_mode) (stlink_t * stl); int32_t (*force_debug) (stlink_t *sl); int32_t (*target_voltage) (stlink_t *sl); int32_t (*set_swdclk) (stlink_t * stl, int32_t freq_khz); int32_t (*trace_enable) (stlink_t * sl, uint32_t frequency); int32_t (*trace_disable) (stlink_t * sl); int32_t (*trace_read) (stlink_t * sl, uint8_t* buf, uint32_t size); int32_t (*init_ap) (stlink_t * sl, uint8_t ap); // select/initialise an access port (NULL if unsupported) } stlink_backend_t; #endif // STLINK_BACKEND_H stlink-1.9.0/inc/stlink_cmd.h000066400000000000000000000055311526027543100161070ustar00rootroot00000000000000/** ****************************************************************************** * @file : stlink_cmd.h * @brief : stlink commands * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #ifndef STLINK_CMD_H #define STLINK_CMD_H enum stlink_commands { STLINK_GET_VERSION = 0xF1, STLINK_DEBUG_COMMAND = 0xF2, STLINK_DFU_COMMAND = 0xF3, STLINK_GET_CURRENT_MODE = 0xF5, STLINK_GET_TARGET_VOLTAGE = 0xF7, STLINK_GET_VERSION_APIV3 = 0xFB }; enum stlink_debug_commands { STLINK_DEBUG_ENTER_JTAG_RESET = 0x00, STLINK_DEBUG_GETSTATUS = 0x01, STLINK_DEBUG_FORCEDEBUG = 0x02, STLINK_DEBUG_APIV1_RESETSYS = 0x03, STLINK_DEBUG_APIV1_READALLREGS = 0x04, STLINK_DEBUG_APIV1_READREG = 0x05, STLINK_DEBUG_APIV1_WRITEREG = 0x06, STLINK_DEBUG_READMEM_32BIT = 0x07, STLINK_DEBUG_WRITEMEM_32BIT = 0x08, STLINK_DEBUG_RUNCORE = 0x09, STLINK_DEBUG_STEPCORE = 0x0a, STLINK_DEBUG_APIV1_SETFP = 0x0b, STLINK_DEBUG_WRITEMEM_8BIT = 0x0d, STLINK_DEBUG_APIV1_CLEARFP = 0x0e, STLINK_DEBUG_APIV1_WRITEDEBUGREG = 0x0f, STLINK_DEBUG_APIV1_ENTER = 0x20, STLINK_DEBUG_EXIT = 0x21, STLINK_DEBUG_READCOREID = 0x22, STLINK_DEBUG_APIV2_ENTER = 0x30, STLINK_DEBUG_APIV2_READ_IDCODES = 0x31, STLINK_DEBUG_APIV2_RESETSYS = 0x32, STLINK_DEBUG_APIV2_READREG = 0x33, STLINK_DEBUG_APIV2_WRITEREG = 0x34, STLINK_DEBUG_APIV2_WRITEDEBUGREG = 0x35, STLINK_DEBUG_APIV2_READDEBUGREG = 0x36, STLINK_DEBUG_APIV2_READALLREGS = 0x3A, STLINK_DEBUG_APIV2_GETLASTRWSTATUS = 0x3B, STLINK_DEBUG_APIV2_DRIVE_NRST = 0x3C, STLINK_DEBUG_APIV2_GETLASTRWSTATUS2 = 0x3E, STLINK_DEBUG_APIV2_START_TRACE_RX = 0x40, STLINK_DEBUG_APIV2_STOP_TRACE_RX = 0x41, STLINK_DEBUG_APIV2_GET_TRACE_NB = 0x42, STLINK_DEBUG_APIV2_SWD_SET_FREQ = 0x43, STLINK_DEBUG_APIV2_INIT_AP = 0x4b, STLINK_DEBUG_APIV3_SET_COM_FREQ = 0x61, STLINK_DEBUG_APIV3_GET_COM_FREQ = 0x62, STLINK_DEBUG_ENTER_SWD = 0xa3, STLINK_DEBUG_ENTER_JTAG_NO_RESET = 0xa4, }; enum stlink_dfu_commands { STLINK_DFU_EXIT = 0x07 }; #endif // STLINK_CMD_H stlink-1.9.0/inc/stm32.h000066400000000000000000000337651526027543100147420ustar00rootroot00000000000000/** ****************************************************************************** * @file : stm32.h * @brief : STM32-specific defines & identification parametres * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #ifndef STM32_H #define STM32_H #include /* STM32 Cortex-M core ids (CPUTAPID) */ enum stm32_core_id { STM32_CORE_ID_M0_SWD = ((uint32_t) 0x0bb11477), // (RM0091 Section 32.5.3) F0 SW-DP STM32_CORE_ID_M0P_SWD = ((uint32_t) 0x0bc11477), // (RM0444 Section 40.5.3) G0 SW-DP // (RM0377 Section 27.5.3) L0 SW-DP STM32_CORE_ID_M3_r1p1_SWD = ((uint32_t) 0x1ba01477), // (RM0008 Section 31.8.3) F1 SW-DP STM32_CORE_ID_M3_r1p1_JTAG = ((uint32_t) 0x3ba00477), // (RM0008 Section 31.6.3) F1 JTAG STM32_CORE_ID_M3_r2p0_SWD = ((uint32_t) 0x2ba01477), // (RM0033 Section 32.8.3) F2 SW-DP // (RM0038 Section 30.8.3) L1 SW-DP STM32_CORE_ID_M3_r2p0_JTAG = ((uint32_t) 0x0ba00477), // (RM0033 Section 32.6.3) F2 JTAG // (RM0038 Section 30.6.2) L1 JTAG STM32_CORE_ID_M4_r0p1_SWD = ((uint32_t) 0x1ba01477), // (RM0316 Section 33.8.3) F3 SW-DP // (RM0351 Section 48.8.3) L4 SW-DP // (RM0432 Section 57.8.3) L4+ SW-DP STM32_CORE_ID_M4_r0p1_JTAG = ((uint32_t) 0x4ba00477), // (RM0316 Section 33.6.3) F3 JTAG // (RM0351 Section 48.6.3) L4 JTAG // (RM0432 Section 57.6.3) L4+ JTAG STM32_CORE_ID_M4F_r0p1_SWD = ((uint32_t) 0x2ba01477), // (RM0090 Section 38.8.3) F4 SW-DP // (RM0090 Section 47.8.3) G4 SW-DP STM32_CORE_ID_M4F_r0p1_JTAG = ((uint32_t) 0x4ba00477), // (RM0090 Section 38.6.3) F4 JTAG // (RM0090 Section 47.6.3) G4 JTAG STM32_CORE_ID_M7F_SWD = ((uint32_t) 0x5ba02477), // (RM0385 Section 40.8.3) F7 SW-DP // (RM0473 Section 33.4.4) WB SW-DP // (RM0453 Section 38.4.1) WL SW-DP STM32_CORE_ID_M7F_JTAG = ((uint32_t) 0x5ba00477), // (RM0385 Section 40.6.3) F7 JTAG STM32_CORE_ID_M7F_M33_SWD = ((uint32_t) 0x6ba02477), // (RM0481 Section 58.3.3) H5 SW-DP // (RM0433 Section 60.4.1) H7 SW-DP STM32_CORE_ID_M7F_M33_JTAG = ((uint32_t) 0x6ba00477), // (RM0481 Section 58.3.1) H5 JTAG // (RM0433 Section 60.4.1) H7 JTAG // (RM0473 Section 33.4.1) WB JTAG // (RM0453 Section 38.3.8) WL JTAG STM32_CORE_ID_M33_SWD = ((uint32_t) 0x0be02477), // (RM0438 Section 52.2.10) L5 SW-DP // (RM0456 Section 65.3.3) U5 SW-DP STM32_CORE_ID_M33_JTAGD = ((uint32_t) 0x0be01477), // (RM0438 Section 52.2.10) L5 JTAG-DP // (RM0456 Section 65.3.3) U5 JTAG-DP STM32_CORE_ID_M33_JTAG = ((uint32_t) 0x0ba04477), // (RM0438 Section 52.2.8) L5 JTAG // (RM0456 Section 56.3.1) U5 JTAG }; /* STM32 flash types */ enum stm32_flash_type { STM32_FLASH_TYPE_UNKNOWN = 0, STM32_FLASH_TYPE_C0 = 1, STM32_FLASH_TYPE_F0_F1_F3 = 2, STM32_FLASH_TYPE_F1_XL = 3, STM32_FLASH_TYPE_F2_F4 = 4, STM32_FLASH_TYPE_F7 = 5, STM32_FLASH_TYPE_G0 = 6, STM32_FLASH_TYPE_G4 = 7, STM32_FLASH_TYPE_H7 = 8, STM32_FLASH_TYPE_L0_L1 = 9, STM32_FLASH_TYPE_L4 = 10, STM32_FLASH_TYPE_L5_U5 = 11, STM32_FLASH_TYPE_WB_WL = 12, STM32_FLASH_TYPE_WB0 = 13, STM32_FLASH_TYPE_H5 = 14, STM32_FLASH_TYPE_C5 = 15, }; /* STM32 chip-ids */ // See DBGMCU_IDCODE register (0xE0042000) in appropriate programming manual // stm32 chipids, only lower 12 bits... enum stm32_chipids { STM32_CHIPID_UNKNOWN = 0x000, STM32_CHIPID_WL3x = 0x027, /* RM0511, p.176 PART_NUMBER in JTAG_ID */ STM32_CHIPID_WB05 = 0x028, /* RM0491, p.116 PART_NUMBER in JTAG_ID */ STM32_CHIPID_WB06_WB07 = 0x01e, /* RM0530, p.125 PART_NUMBER in JTAG_ID */ STM32_CHIPID_WB09 = 0x032, /* RM0505, p.167 PART_NUMBER in JTAG_ID */ STM32_CHIPID_F1_MD = 0x410, /* medium density */ STM32_CHIPID_F2 = 0x411, STM32_CHIPID_F1_LD = 0x412, /* low density */ STM32_CHIPID_F4 = 0x413, STM32_CHIPID_F1_HD = 0x414, /* high density */ STM32_CHIPID_L4 = 0x415, STM32_CHIPID_L1_MD = 0x416, /* medium density */ STM32_CHIPID_L0_CAT3 = 0x417, STM32_CHIPID_F1_CONN = 0x418, /* connectivity line */ STM32_CHIPID_F4_HD = 0x419, /* high density */ STM32_CHIPID_F1_VL_MD_LD = 0x420, /* value line medium & low density */ STM32_CHIPID_F446 = 0x421, STM32_CHIPID_F3 = 0x422, STM32_CHIPID_F4_LP = 0x423, STM32_CHIPID_L0_CAT2 = 0x425, STM32_CHIPID_L1_MD_PLUS = 0x427, /* medium density plus */ STM32_CHIPID_F1_VL_HD = 0x428, /* value line high density */ STM32_CHIPID_L1_CAT2 = 0x429, STM32_CHIPID_F1_XLD = 0x430, /* extra low density plus */ STM32_CHIPID_F411xx = 0x431, STM32_CHIPID_F37x = 0x432, STM32_CHIPID_F4_DE = 0x433, STM32_CHIPID_F4_DSI = 0x434, STM32_CHIPID_L43x_L44x = 0x435, STM32_CHIPID_L1_MD_PLUS_HD = 0x436, /* medium density plus & high density */ STM32_CHIPID_L152_RE = 0x437, STM32_CHIPID_F334 = 0x438, STM32_CHIPID_F3xx_SMALL = 0x439, STM32_CHIPID_F0 = 0x440, STM32_CHIPID_F412 = 0x441, STM32_CHIPID_F09x = 0x442, STM32_CHIPID_C011xx = 0x443, /* RM0490 (Rev. 5), section 30.10.1 "DBG device ID code register (DBG_IDCODE)" */ STM32_CHIPID_F0xx_SMALL = 0x444, STM32_CHIPID_F04 = 0x445, STM32_CHIPID_F303_HD = 0x446, /* high density */ STM32_CHIPID_L0_CAT5 = 0x447, STM32_CHIPID_F0_CAN = 0x448, STM32_CHIPID_F7 = 0x449, /* Nucleo F746ZG board */ STM32_CHIPID_C051xx = 0x44C, /* RM0490 (Rev. 5), section 30.10.1 "DBG device ID code register (DBG_IDCODE)" */ STM32_CHIPID_C091xx_C92xx = 0x44D, /* RM0490 (Rev. 5), section 30.10.1 "DBG device ID code register (DBG_IDCODE)" */ STM32_CHIPID_C55x_C56x = 0x44E, /* RM0522, DBGMCU_IDCODE DEV_ID */ STM32_CHIPID_C53x_C54x = 0x44F, /* RM0522, DBGMCU_IDCODE DEV_ID */ STM32_CHIPID_H74xxx = 0x450, /* RM0433, p.3189 */ STM32_CHIPID_F76xxx = 0x451, STM32_CHIPID_F72xxx = 0x452, /* Nucleo F722ZE board */ STM32_CHIPID_C031xx = 0x453, /* RM0490 (Rev. 5), section 30.10.1 "DBG device ID code register (DBG_IDCODE)" */ STM32_CHIPID_U535_U545 = 0x455, /* RM0456, p.3604 */ STM32_CHIPID_G0_CAT4 = 0x456, /* G051/G061 */ STM32_CHIPID_L0_CAT1 = 0x457, STM32_CHIPID_F410 = 0x458, STM32_CHIPID_U031xx = 0x459, STM32_CHIPID_C59x_C5Ax = 0x45A, /* RM0522, DBGMCU_IDCODE DEV_ID */ STM32_CHIPID_G0_CAT2 = 0x460, /* G07x/G08x */ STM32_CHIPID_L496x_L4A6x = 0x461, STM32_CHIPID_L45x_L46x = 0x462, STM32_CHIPID_F413 = 0x463, STM32_CHIPID_L41x_L42x = 0x464, STM32_CHIPID_G0_CAT1 = 0x466, /* G03x/G04x */ STM32_CHIPID_G0_CAT3 = 0x467, /* G0Bx/G0Cx */ STM32_CHIPID_G4_CAT2 = 0x468, /* RM0440, section 46.6.1 "MCU device ID code" */ STM32_CHIPID_G4_CAT3 = 0x469, STM32_CHIPID_L4Rx = 0x470, /* RM0432, p.2247, found on the STM32L4R9I-DISCO board */ STM32_CHIPID_L4PX = 0x471, /* RM0432, p.2247 */ STM32_CHIPID_L5x2xx = 0x472, /* RM0438, p.2157 */ STM32_CHIPID_U5Fx_U5Gx = 0x476, /* RM0456, p.3604 */ STM32_CHIPID_H52_H53xx = 0x478, /* RM0481, p.3085 */ STM32_CHIPID_G4_CAT4 = 0x479, STM32_CHIPID_H7Ax = 0x480, /* RM0455, p.2863 */ STM32_CHIPID_U59x_U5Ax = 0x481, /* RM0456, p.3604 */ STM32_CHIPID_U575_U585 = 0x482, /* RM0456, p.3604 */ STM32_CHIPID_H72x = 0x483, /* RM0468, p.3199 */ STM32_CHIPID_H5xx = 0x484, /* RM0481, p.3085 */ STM32_CHIPID_U073xx_U083xx = 0x489, STM32_CHIPID_C071xx = 0x493, /* RM0490 (Rev. 5), section 30.10.1 "DBG device ID code register (DBG_IDCODE)" */ STM32_CHIPID_WB55 = 0x495, STM32_CHIPID_WLE = 0x497, }; /* Constant STM32 option bytes base memory address */ #define STM32_OPTION_BYTES_BASE_C0 ((uint32_t) 0x1fff7800) #define STM32_OPTION_BYTES_BASE_F4 ((uint32_t) 0x40023c14) #define STM32_OPTION_BYTES_BASE_H7 ((uint32_t) 0x52002020) #define STM32_OPTION_BYTES_BASE_L0 ((uint32_t) 0x1ff80000) #define STM32_OPTION_BYTES_BASE_L1 ((uint32_t) 0x1ff80000) #define STM32_OPTION_BYTES_BASE_F7 ((uint32_t) 0x1fff0000) #define STM32_OPTION_BYTES_BASE_G0 ((uint32_t) 0x1fff7800) #define STM32_OPTION_BYTES_BASE_L4 ((uint32_t) 0x1fff7800) #define STM32_OPTION_BYTES_BASE_F2 ((uint32_t) 0x1fffc000) #define STM32_OPTION_BYTES_BASE_F0 ((uint32_t) 0x1ffff800) #define STM32_OPTION_BYTES_BASE_F1 ((uint32_t) 0x1ffff800) #define STM32_OPTION_BYTES_BASE_F3 ((uint32_t) 0x1ffff800) #define STM32_OPTION_BYTES_BASE_G4 ((uint32_t) 0x1ffff800) /* ============ */ /* Old defines from common_legacy.c are below */ /* ============ */ /* Constant STM32 memory address */ #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 STM32F0_DBGMCU_CR ((uint32_t) 0xe0042004) #define STM32F0_DBGMCU_CR_IWDG_STOP 8 #define STM32F0_DBGMCU_CR_WWDG_STOP 9 #define STM32F4_DBGMCU_APB1FZR1 ((uint32_t) 0xe0042008) #define STM32F4_DBGMCU_APB1FZR1_WWDG_STOP 11 #define STM32F4_DBGMCU_APB1FZR1_IWDG_STOP 12 #define STM32L0_DBGMCU_APB1_FZ ((uint32_t) 0x40015808) #define STM32L0_DBGMCU_APB1_FZ_WWDG_STOP 11 #define STM32L0_DBGMCU_APB1_FZ_IWDG_STOP 12 #define STM32L1_DBGMCU_APB1_FZ ((uint32_t) 0xe0042008) #define STM32L1_DBGMCU_APB1_FZ_WWDG_STOP 11 #define STM32L1_DBGMCU_APB1_FZ_IWDG_STOP 12 #define STM32H7_DBGMCU_APB1HFZ ((uint32_t) 0x5c001054) #define STM32H7_DBGMCU_APB1HFZ_IWDG_STOP 18 #define STM32WB_DBGMCU_APB1FZR1 ((uint32_t) 0xe004203c) #define STM32WB_DBGMCU_APB1FZR1_WWDG_STOP 11 #define STM32WB_DBGMCU_APB1FZR1_IWDG_STOP 12 #define STM32C0_RCC_AHBENR ((uint32_t) 0x40021038) // RM0490 (Rev. 5), section 6.4.24 "RCC register map" #define STM32C0_RCC_DMAEN ((uint32_t) 0x00000001) // DMAEN // RM0490 (Rev. 5), section 6.4.24 "RCC register map" #define STM32F1_RCC_AHBENR ((uint32_t) 0x40021014) #define STM32F1_RCC_DMAEN ((uint32_t) 0x00000003) // DMA2EN | DMA1EN #define STM32F4_RCC_AHB1ENR ((uint32_t) 0x40023830) #define STM32F4_RCC_DMAEN ((uint32_t) 0x00600000) // DMA2EN | DMA1EN #define STM32G0_RCC_AHBENR ((uint32_t) 0x40021038) #define STM32G0_RCC_DMAEN ((uint32_t) 0x00000003) // DMA2EN | DMA1EN #define STM32G4_RCC_AHB1ENR ((uint32_t) 0x40021048) #define STM32G4_RCC_DMAEN ((uint32_t) 0x00000003) // DMA2EN | DMA1EN #define STM32L0_RCC_AHBENR ((uint32_t) 0x40021030) #define STM32L0_RCC_DMAEN ((uint32_t) 0x00000001) // DMAEN #define STM32L1_RCC_AHBENR ((uint32_t) 0x4002381c) #define STM32L1_RCC_DMAEN ((uint32_t) 0x30000000) // DMA2EN | DMA1EN #define STM32L5_RCC_AHB1ENR ((uint32_t) 0x40021048) // RM0438, p.91,377 #define STM32L5_RCC_DMAEN ((uint32_t) 0x00000003) // DMA2EN | DMA1EN // RM0438, p.378 #define STM32H7_RCC_AHB1ENR ((uint32_t) 0x58024538) #define STM32H7_RCC_DMAEN ((uint32_t) 0x00000003) // DMA2EN | DMA1EN #define STM32WB_RCC_AHB1ENR ((uint32_t) 0x58000048) #define STM32WB_RCC_DMAEN ((uint32_t) 0x00000003) // DMA2EN | DMA1EN #define STM32WB0_FLASH_BASE ((uint32_t) 0x10040000) #define STM32WB0_JTAG_ID ((uint32_t) 0x40000004) #define STM32WB0_JTAG_PART_NR 12 #define STM32WB0_RCC_AHBENR ((uint32_t) 0x48400050) #define STM32WB0_RCC_AHB_DMAEN ((uint32_t) 0x00000001) #define STM32WB0_RCC_APB0ENR ((uint32_t) 0x48400054) #define STM32WB0_RCC_APB0_WDGEN ((uint32_t) 0x00004000) // == STM32C5 == (RM0522) // C5 RCC register map: RCC_BASE = AHB3PERIPH_BASE(0x44020000) + 0x0C00, // AHB1ENR is at RCC_BASE + 0x088. // DMA clocks: LPDMA1EN@0 | LPDMA2EN@1. #define STM32C5_RCC_AHB1ENR 0x44020C88 // RM0522, RCC AHB1 peripheral clock enable register #define STM32C5_RCC_DMAEN 0x00000003 // LPDMA2EN | LPDMA1EN #define STM32L5_PWR_CR1 ((uint32_t) 0x40007000) // RM0438, p.93,324 #define STM32L5_PWR_CR1_VOS 9 #endif // STM32_H stlink-1.9.0/inc/stm32_flash.h000066400000000000000000000631201526027543100161030ustar00rootroot00000000000000/** ****************************************************************************** * @file : stm32_flash.h * @brief : STM32 specific flash registers, addresses and parametres * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #ifndef STM32_FLASH_H #define STM32_FLASH_H #include /* STM32Fx FPEC flash controller interface, PM0063 manual */ // STM32F05x is identical, based on RM0091 (DM00031936, Doc ID 018940 Rev.2, Aug 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) #define FLASH_RDPTR_KEY 0x00a5 #define FLASH_KEY1 0x45670123 #define FLASH_KEY2 0xcdef89ab #define FLASH_OPTKEY1 0x08192a3b #define FLASH_OPTKEY2 0x4c5d6e7f #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 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) // == STM32C0 == (RM0490) // C0 Flash registers #define STM32_FLASH_C0_REGS_ADDR ((uint32_t) 0x40022000) #define STM32_FLASH_C0_KEYR (STM32_FLASH_C0_REGS_ADDR + 0x08) #define STM32_FLASH_C0_OPT_KEYR (STM32_FLASH_C0_REGS_ADDR + 0x0C) #define STM32_FLASH_C0_SR (STM32_FLASH_C0_REGS_ADDR + 0x10) #define STM32_FLASH_C0_CR (STM32_FLASH_C0_REGS_ADDR + 0x14) #define STM32_FLASH_C0_OPTR (STM32_FLASH_C0_REGS_ADDR + 0x20) // C0 Flash control register #define STM32_FLASH_C0_CR_PNB 3 #define STM32_FLASH_C0_CR_STRT 16 #define STM32_FLASH_C0_CR_OPTSTRT 17 #define STM32_FLASH_C0_CR_OBL_LAUNCH 27 #define STM32_FLASH_C0_CR_OPTLOCK 30 #define STM32_FLASH_C0_CR_LOCK 31 // C0 Flash status register #define STM32_FLASH_C0_SR_ERROR_MASK 0xC3F8 // [15:14], [9:3] #define STM32_FLASH_C0_SR_PROGERR 3 #define STM32_FLASH_C0_SR_WRPERR 4 #define STM32_FLASH_C0_SR_PGAERR 5 #define STM32_FLASH_C0_SR_BSY 16 // == STM32F0 == #define STM32_FLASH_F0_OPTKEY1 0x45670123 #define STM32_FLASH_F0_OPTKEY2 0xcdef89ab // == STM32F2 == #define STM32_FLASH_F2_REGS_ADDR ((uint32_t) 0x40023c00) #define STM32_FLASH_F2_KEYR (STM32_FLASH_F2_REGS_ADDR + 0x04) #define STM32_FLASH_F2_OPT_KEYR (STM32_FLASH_F2_REGS_ADDR + 0x08) #define STM32_FLASH_F2_SR (STM32_FLASH_F2_REGS_ADDR + 0x0c) #define STM32_FLASH_F2_CR (STM32_FLASH_F2_REGS_ADDR + 0x10) #define STM32_FLASH_F2_OPT_CR (STM32_FLASH_F2_REGS_ADDR + 0x14) #define STM32_FLASH_F2_OPT_LOCK_BIT (1u << 0) // F2 Flash control register #define STM32_FLASH_F2_CR_STRT 16 #define STM32_FLASH_F2_CR_LOCK 31 #define STM32_FLASH_F2_CR_SER 1 #define STM32_FLASH_F2_CR_SNB 3 #define STM32_FLASH_F2_CR_SNB_MASK 0x78 // F2 Flash status register #define STM32_FLASH_F2_SR_BSY 16 // == STM32F4 == // F4 Flash registers #define STM32_FLASH_F4_REGS_ADDR ((uint32_t) 0x40023c00) #define STM32_FLASH_F4_KEYR (STM32_FLASH_F4_REGS_ADDR + 0x04) #define STM32_FLASH_F4_OPT_KEYR (STM32_FLASH_F4_REGS_ADDR + 0x08) #define STM32_FLASH_F4_SR (STM32_FLASH_F4_REGS_ADDR + 0x0c) #define STM32_FLASH_F4_CR (STM32_FLASH_F4_REGS_ADDR + 0x10) #define STM32_FLASH_F4_OPTCR (STM32_FLASH_F4_REGS_ADDR + 0x14) #define STM32_FLASH_F4_OPTCR_LOCK 0 #define STM32_FLASH_F4_OPTCR_START 1 // F4 Flash control register #define STM32_FLASH_F4_CR_STRT 16 #define STM32_FLASH_F4_CR_LOCK 31 #define STM32_FLASH_F4_CR_SER 1 #define STM32_FLASH_F4_CR_SNB 3 #define STM32_FLASH_F4_CR_SNB_MASK 0xf8 // F4 Flash status register #define STM32_FLASH_F4_SR_ERROR_MASK 0x000000F0 #define STM32_FLASH_F4_SR_PGAERR 5 #define STM32_FLASH_F4_SR_WRPERR 4 #define STM32_FLASH_F4_SR_BSY 16 // == STM32F7 == // F7 Flash registers #define STM32_FLASH_F7_REGS_ADDR ((uint32_t) 0x40023c00) #define STM32_FLASH_F7_KEYR (STM32_FLASH_F7_REGS_ADDR + 0x04) #define STM32_FLASH_F7_OPT_KEYR (STM32_FLASH_F7_REGS_ADDR + 0x08) #define STM32_FLASH_F7_SR (STM32_FLASH_F7_REGS_ADDR + 0x0c) #define STM32_FLASH_F7_CR (STM32_FLASH_F7_REGS_ADDR + 0x10) #define STM32_FLASH_F7_OPTCR (STM32_FLASH_F7_REGS_ADDR + 0x14) #define STM32_FLASH_F7_OPTCR1 (STM32_FLASH_F7_REGS_ADDR + 0x18) #define STM32_FLASH_F7_OPTCR_LOCK 0 #define STM32_FLASH_F7_OPTCR_START 1 #define STM32_FLASH_F7_OPTCR1_BOOT_ADD0 0 #define STM32_FLASH_F7_OPTCR1_BOOT_ADD1 16 // F7 Flash control register #define STM32_FLASH_F7_CR_STRT 16 #define STM32_FLASH_F7_CR_LOCK 31 #define STM32_FLASH_F7_CR_SER 1 #define STM32_FLASH_F7_CR_SNB 3 #define STM32_FLASH_F7_CR_SNB_MASK 0xf8 // F7 Flash status register #define STM32_FLASH_F7_SR_BSY 16 #define STM32_FLASH_F7_SR_ERS_ERR 7 /* Erase Sequence Error */ #define STM32_FLASH_F7_SR_PGP_ERR 6 /* Programming parallelism error */ #define STM32_FLASH_F7_SR_PGA_ERR 5 /* Programming alignment error */ #define STM32_FLASH_F7_SR_WRP_ERR 4 /* Write protection error */ #define STM32_FLASH_F7_SR_OP_ERR 1 /* Operation error */ #define STM32_FLASH_F7_SR_EOP 0 /* End of operation */ #define STM32_FLASH_F7_SR_ERROR_MASK \ ((1 << STM32_FLASH_F7_SR_ERS_ERR) | (1 << STM32_FLASH_F7_SR_PGP_ERR) | \ (1 << STM32_FLASH_F7_SR_PGA_ERR) | (1 << STM32_FLASH_F7_SR_WRP_ERR) | \ (1 << STM32_FLASH_F7_SR_OP_ERR)) // == STM32G0/G4 == // G0/G4 Flash registers (RM0440, p.146) #define STM32_FLASH_Gx_REGS_ADDR ((uint32_t) 0x40022000) #define STM32_FLASH_Gx_ACR (STM32_FLASH_Gx_REGS_ADDR + 0x00) #define STM32_FLASH_Gx_KEYR (STM32_FLASH_Gx_REGS_ADDR + 0x08) #define STM32_FLASH_Gx_OPTKEYR (STM32_FLASH_Gx_REGS_ADDR + 0x0c) #define STM32_FLASH_Gx_SR (STM32_FLASH_Gx_REGS_ADDR + 0x10) #define STM32_FLASH_Gx_CR (STM32_FLASH_Gx_REGS_ADDR + 0x14) #define STM32_FLASH_Gx_ECCR (STM32_FLASH_Gx_REGS_ADDR + 0x18) #define STM32_FLASH_Gx_OPTR (STM32_FLASH_Gx_REGS_ADDR + 0x20) // G0/G4 Flash control register #define STM32_FLASH_Gx_CR_PG (0) /* Program */ #define STM32_FLASH_Gx_CR_PER (1) /* Page erase */ #define STM32_FLASH_Gx_CR_MER1 (2) /* Mass erase */ #define STM32_FLASH_Gx_CR_PNB (3) /* Page number */ #define STM32_FLASH_G0_CR_PNB_LEN (10) /* STM32G0: PNB[9:0] (RM0444) */ #define STM32_FLASH_G4_CR_PNB_LEN (7) /* STM32G4 Cat.2/Cat.3: PNB[6:0] (RM0440) */ #define STM32_FLASH_G4_CAT4_CR_PNB_LEN (8) /* STM32G4 Cat.4: PNB[7:0] (RM0440) */ #define STM32_FLASH_G0_CR_BKER (13) /* Bank selection for erase operation on G0*/ #define STM32_FLASH_G4_CR_BKER (11) /* Bank selection for erase operation on G4*/ #define STM32_FLASH_Gx_CR_MER2 (15) /* Mass erase (2nd bank)*/ #define STM32_FLASH_Gx_CR_STRT (16) /* Start */ #define STM32_FLASH_Gx_CR_OPTSTRT (17) /* Start of modification of option bytes */ #define STM32_FLASH_Gx_CR_FSTPG (18) /* Fast programming */ #define STM32_FLASH_Gx_CR_EOPIE (24) /* End of operation interrupt enable */ #define STM32_FLASH_Gx_CR_ERRIE (25) /* Error interrupt enable */ #define STM32_FLASH_Gx_CR_OBL_LAUNCH (27) /* Forces the option byte loading */ #define STM32_FLASH_Gx_CR_OPTLOCK (30) /* Options Lock */ #define STM32_FLASH_Gx_CR_LOCK (31) /* FLASH_CR Lock */ // G0/G4 Flash status register #define STM32_FLASH_Gx_SR_ERROR_MASK (0x3fa) #define STM32_FLASH_Gx_SR_PROGERR (3) #define STM32_FLASH_Gx_SR_WRPERR (4) #define STM32_FLASH_Gx_SR_PGAERR (5) #define STM32_FLASH_Gx_SR_BSY (16) /* FLASH_SR Busy (BSY1 on G0) */ #define STM32_FLASH_G0_SR_BSY2 (17) /* STM32G0: Bank 2 busy (dual-bank devices only) */ #define STM32_FLASH_G0_SR_CFGBSY (18) /* STM32G0: Program/erase configuration busy */ #define STM32_FLASH_Gx_SR_EOP (0) /* FLASH_EOP End of Operation */ // == STM32G0 == (RM0444 Table 1, sec. 3.7) // Mostly the same as G4 chips, but the notation // varies a bit after the 'OPTR' register. #define STM32_FLASH_G0_REGS_ADDR (STM32_FLASH_Gx_REGS_ADDR) #define STM32_FLASH_G0_PCROP1ASR (STM32_FLASH_G0_REGS_ADDR + 0x24) #define STM32_FLASH_G0_PCROP1AER (STM32_FLASH_G0_REGS_ADDR + 0x28) #define STM32_FLASH_G0_WRP1AR (STM32_FLASH_G0_REGS_ADDR + 0x2c) #define STM32_FLASH_G0_WRP1BR (STM32_FLASH_G0_REGS_ADDR + 0x30) #define STM32_FLASH_G0_PCROP1BSR (STM32_FLASH_G0_REGS_ADDR + 0x34) #define STM32_FLASH_G0_PCROP1BER (STM32_FLASH_G0_REGS_ADDR + 0x38) #define STM32_FLASH_G0_SECR (STM32_FLASH_G0_REGS_ADDR + 0x80) #define STM32_FLASH_G0_OPTR_NSWAP_BANK (20) /* FLASH_OPTR Bank swap, active low: 0 = banks swapped (G0B1/G0C1 only) */ #define STM32_FLASH_G0_OPTR_DUAL_BANK (21) /* FLASH_OPTR Dual-Bank Mode (256 KB G0B1/G0C1 only) */ // == STM32G4 == (RM0440 Table 17, sec. 3.7.19) #define STM32_FLASH_G4_OPTR_DBANK (22) /* FLASH option register FLASH_OPTR Dual-Bank Mode */ // There are a few extra registers because 'cat 3' devices can have // two Flash banks. #define STM32_FLASH_G4_REGS_ADDR (STM32_FLASH_Gx_REGS_ADDR) #define STM32_FLASH_G4_PDKEYR (STM32_FLASH_G4_REGS_ADDR + 0x04) #define STM32_FLASH_G4_PCROP1SR (STM32_FLASH_G4_REGS_ADDR + 0x24) #define STM32_FLASH_G4_PCROP1ER (STM32_FLASH_G4_REGS_ADDR + 0x28) #define STM32_FLASH_G4_WRP1AR (STM32_FLASH_G4_REGS_ADDR + 0x2c) #define STM32_FLASH_G4_WRP1BR (STM32_FLASH_G4_REGS_ADDR + 0x30) #define STM32_FLASH_G4_PCROP2SR (STM32_FLASH_G4_REGS_ADDR + 0x44) #define STM32_FLASH_G4_PCROP2ER (STM32_FLASH_G4_REGS_ADDR + 0x48) #define STM32_FLASH_G4_WRP2AR (STM32_FLASH_G4_REGS_ADDR + 0x4c) #define STM32_FLASH_G4_WRP2BR (STM32_FLASH_G4_REGS_ADDR + 0x50) #define STM32_FLASH_G4_SEC1R (STM32_FLASH_G4_REGS_ADDR + 0x70) #define STM32_FLASH_G4_SEC2R (STM32_FLASH_G4_REGS_ADDR + 0x74) // == STM32H7 == // H7 Flash registers #define STM32_FLASH_H7_REGS_ADDR ((uint32_t) 0x52002000) #define STM32_FLASH_H7_KEYR1 (STM32_FLASH_H7_REGS_ADDR + 0x04) #define STM32_FLASH_H7_KEYR2 (STM32_FLASH_H7_REGS_ADDR + 0x104) #define STM32_FLASH_H7_OPT_KEYR (STM32_FLASH_H7_REGS_ADDR + 0x08) #define STM32_FLASH_H7_CR1 (STM32_FLASH_H7_REGS_ADDR + 0x0c) #define STM32_FLASH_H7_CR2 (STM32_FLASH_H7_REGS_ADDR + 0x10c) #define STM32_FLASH_H7_SR1 (STM32_FLASH_H7_REGS_ADDR + 0x10) #define STM32_FLASH_H7_SR2 (STM32_FLASH_H7_REGS_ADDR + 0x110) #define STM32_FLASH_H7_CCR1 (STM32_FLASH_H7_REGS_ADDR + 0x14) #define STM32_FLASH_H7_CCR2 (STM32_FLASH_H7_REGS_ADDR + 0x114) #define STM32_FLASH_H7_OPTCR (STM32_FLASH_H7_REGS_ADDR + 0x18) #define STM32_FLASH_H7_OPTCR2 (STM32_FLASH_H7_REGS_ADDR + 0x118) #define STM32_FLASH_H7_OPTSR_CUR (STM32_FLASH_H7_REGS_ADDR + 0x1c) #define STM32_FLASH_H7_OPTCCR (STM32_FLASH_H7_REGS_ADDR + 0x24) #define STM32_FLASH_H7_OPTCR_OPTLOCK 0 #define STM32_FLASH_H7_OPTCR_OPTSTART 1 #define STM32_FLASH_H7_OPTCR_MER 4 #define STM32_FLASH_H7_OPTSR_OPT_BUSY 0 #define STM32_FLASH_H7_OPTSR_OPTCHANGEERR 30 #define STM32_FLASH_H7_OPTCCR_CLR_OPTCHANGEERR 30 // H7 Flash control register #define STM32_FLASH_H7_CR_LOCK 0 #define STM32_FLASH_H7_CR_PG 1 #define STM32_FLASH_H7_CR_SER 2 #define STM32_FLASH_H7_CR_BER 3 #define STM32_FLASH_H7_CR_PSIZE 4 #define STM32_FLASH_H7_CR_START(chipid) (chipid == STM32_CHIPID_H7Ax ? 5 : 7) #define STM32_FLASH_H7_CR_SNB 8 #define STM32_FLASH_H7_CR_SNB_MASK 0x700 // H7 Flash status register #define STM32_FLASH_H7_SR_QW 2 #define STM32_FLASH_H7_SR_WRPERR 17 #define STM32_FLASH_H7_SR_PGSERR 18 #define STM32_FLASH_H7_SR_STRBERR 19 #define STM32_FLASH_H7_SR_ERROR_MASK \ ((1 << STM32_FLASH_H7_SR_PGSERR) | (1 << STM32_FLASH_H7_SR_STRBERR) | \ (1 << STM32_FLASH_H7_SR_WRPERR)) // == STM32L0/L1/L4/L5 == // Lx Flash registers #define STM32_FLASH_Lx_REGS_ADDR ((uint32_t) 0x40023c00) #define STM32_FLASH_Lx_ACR (STM32_FLASH_Lx_REGS_ADDR + 0x00) #define STM32_FLASH_Lx_PECR (STM32_FLASH_Lx_REGS_ADDR + 0x04) #define STM32_FLASH_Lx_PDKEYR (STM32_FLASH_Lx_REGS_ADDR + 0x08) #define STM32_FLASH_Lx_PEKEYR (STM32_FLASH_Lx_REGS_ADDR + 0x0c) #define STM32_FLASH_Lx_PRGKEYR (STM32_FLASH_Lx_REGS_ADDR + 0x10) #define STM32_FLASH_Lx_OPTKEYR (STM32_FLASH_Lx_REGS_ADDR + 0x14) #define STM32_FLASH_Lx_SR (STM32_FLASH_Lx_REGS_ADDR + 0x18) #define STM32_FLASH_Lx_OBR (STM32_FLASH_Lx_REGS_ADDR + 0x1c) #define STM32_FLASH_Lx_WRPR (STM32_FLASH_Lx_REGS_ADDR + 0x20) // == STM32L0 == // L0 Flash registers #define STM32_FLASH_L0_REGS_ADDR ((uint32_t) 0x40022000) #define STM32_FLASH_L0_PEKEY1 0x89abcdef #define STM32_FLASH_L0_PEKEY2 0x02030405 #define STM32_FLASH_L0_PRGKEY1 0x8c9daebf #define STM32_FLASH_L0_PRGKEY2 0x13141516 #define STM32_FLASH_L0_OPTKEY1 0xFBEAD9C8 #define STM32_FLASH_L0_OPTKEY2 0x24252627 #define STM32_FLASH_L0_PELOCK (0) #define STM32_FLASH_L0_OPTLOCK (2) #define STM32_FLASH_L0_OBL_LAUNCH (18) // L0 Flash status register #define STM32_FLASH_L0_SR_ERROR_MASK 0x00013f00 #define STM32_FLASH_L0_SR_WRPERR 8 #define STM32_FLASH_L0_SR_PGAERR 9 #define STM32_FLASH_L0_SR_NOTZEROERR 16 // == STM32L1 == // L1 Flash registers #define STM32_FLASH_L1_FPRG 10 #define STM32_FLASH_L1_PROG 3 // L1 Flash status register #define STM32_FLASH_L1_SR_ERROR_MASK 0x00003f00 #define STM32_FLASH_L1_SR_WRPERR 8 #define STM32_FLASH_L1_SR_PGAERR 9 // == STM32L4 == // L4 Flash registers // L4 register base is at STM32_FLASH_L0_REGS_ADDR (0x40022000) #define STM32_FLASH_L4_KEYR (STM32_FLASH_L0_REGS_ADDR + 0x08) #define STM32_FLASH_L4_OPTKEYR (STM32_FLASH_L0_REGS_ADDR + 0x0c) #define STM32_FLASH_L4_SR (STM32_FLASH_L0_REGS_ADDR + 0x10) #define STM32_FLASH_L4_CR (STM32_FLASH_L0_REGS_ADDR + 0x14) #define STM32_FLASH_L4_OPTR (STM32_FLASH_L0_REGS_ADDR + 0x20) // L4 Flash status register #define STM32_FLASH_L4_SR_ERROR_MASK 0x3f8 // SR [9:3] #define STM32_FLASH_L4_SR_PROGERR 3 #define STM32_FLASH_L4_SR_WRPERR 4 #define STM32_FLASH_L4_SR_PGAERR 5 #define STM32_FLASH_L4_SR_BSY 16 #define STM32_FLASH_L4_SR_PEMPTY 17 /* Program empty (L41x-L46x, L4P/Q, L4R/S only) */ // EOP, OPERR, PROGERR..FASTERR, RDERR, OPTVERR: all "write 1 to clear" flags. // Must never include PEMPTY: writing 1 to it toggles the bit (RM0394/RM0432). #define STM32_FLASH_L4_SR_CLEAR_MASK 0xc3fb // L4 Flash control register #define STM32_FLASH_L4_CR_LOCK 31 /* Lock control register */ #define STM32_FLASH_L4_CR_OPTLOCK 30 /* Lock option bytes */ #define STM32_FLASH_L4_CR_PG 0 /* Program */ #define STM32_FLASH_L4_CR_PER 1 /* Page erase */ #define STM32_FLASH_L4_CR_MER1 2 /* Bank 1 erase */ #define STM32_FLASH_L4_CR_MER2 15 /* Bank 2 erase */ #define STM32_FLASH_L4_CR_STRT 16 /* Start command */ #define STM32_FLASH_L4_CR_OPTSTRT 17 /* Start writing option bytes */ #define STM32_FLASH_L4_CR_BKER 11 /* Bank select for page erase */ #define STM32_FLASH_L4_CR_PNB 3 /* Page number (8 bits) */ #define STM32_FLASH_L4_CR_OBL_LAUNCH 27 /* Option bytes reload */ // Bits requesting flash operations (useful when we want to clear them) #define STM32_FLASH_L4_CR_OPBITS \ (uint32_t) ((1lu << STM32_FLASH_L4_CR_PG) | (1lu << STM32_FLASH_L4_CR_PER) | \ (1lu << STM32_FLASH_L4_CR_MER1) | (1lu << STM32_FLASH_L4_CR_MER1)) // Page is fully specified by BKER and PNB #define STM32_FLASH_L4_CR_PAGEMASK (uint32_t) (0x1fflu << STM32_FLASH_L4_CR_PNB) #define STM32_FLASH_L4_OPTR_DUALBANK 21 // == STM32L5 == (RM0438, p.241) // L5 Flash registers #define STM32_FLASH_L5_REGS_ADDR ((uint32_t) 0x40022000) #define STM32_FLASH_L5_ACR (STM32_FLASH_L5_REGS_ADDR + 0x00) #define STM32_FLASH_L5_NSKEYR (STM32_FLASH_L5_REGS_ADDR + 0x08) #define STM32_FLASH_L5_OPTKEYR (STM32_FLASH_L5_REGS_ADDR + 0x10) #define STM32_FLASH_L5_NSSR (STM32_FLASH_L5_REGS_ADDR + 0x20) #define STM32_FLASH_L5_NSCR (STM32_FLASH_L5_REGS_ADDR + 0x28) #define STM32_FLASH_L5_ECCR (STM32_FLASH_L5_REGS_ADDR + 0x30) #define STM32_FLASH_L5_OPTR (STM32_FLASH_L5_REGS_ADDR + 0x40) // FLASH_NSCR control registers (RM0438, p. 242) #define STM32_FLASH_L5_NSCR_NSPG 0 /* Program */ #define STM32_FLASH_L5_NSCR_NSPER 1 /* Page erase */ #define STM32_FLASH_L5_NSCR_NSMER1 2 /* Bank 1 erase */ #define STM32_FLASH_L5_NSCR_NSPNB 3 /* Page number (7 bits) */ #define STM32_FLASH_L5_NSCR_NSBKER 11 /* Bank select for page erase */ #define STM32_FLASH_L5_NSCR_NSMER2 15 /* Bank 2 erase */ #define STM32_FLASH_L5_NSCR_NSSTRT 16 /* Start command */ #define STM32_FLASH_L5_NSCR_NSOPTSTRT 17 /* Start writing option bytes */ #define STM32_FLASH_L5_NSCR_NSEOPIE 24 #define STM32_FLASH_L5_NSCR_NSERRIE 25 #define STM32_FLASH_L5_NSCR_OBL_LAUNCH 27 /* Option bytes reload */ #define STM32_FLASH_L5_NSCR_OPTLOCK 30 /* Lock option bytes */ #define STM32_FLASH_L5_NSCR_NSLOCK 31 /* Lock control register */ // FLASH_NSSR status register (RM0438, p. 241) #define STM32_FLASH_L5_NSSR_NSEOP 0 /* End of Operation */ #define STM32_FLASH_L5_NSSR_NSOPERR 1 #define STM32_FLASH_L5_NSSR_NSPROGERR 3 #define STM32_FLASH_L5_NSSR_NSWRPERR 4 #define STM32_FLASH_L5_NSSR_NSPGAERR 5 #define STM32_FLASH_L5_NSSR_NSSIZERR 6 #define STM32_FLASH_L5_NSSR_NSPGSERR 7 #define STM32_FLASH_L5_NSSR_OPTWERR 12 #define STM32_FLASH_L5_NSSR_BSY 16 /* Busy */ #define STM32_FLASH_L5_NSSR_ERROR_MASK (0x20fa) // == STM32H5 == (RM0481) // H5 non-secure flash registers. Bit positions and the dedicated clear-control // register (NSCCR) differ from L5/U5, so H5 has its own flash type. #define STM32_FLASH_H5_REGS_ADDR ((uint32_t) 0x40022000) #define STM32_FLASH_H5_ACR (STM32_FLASH_H5_REGS_ADDR + 0x00) #define STM32_FLASH_H5_NSKEYR (STM32_FLASH_H5_REGS_ADDR + 0x04) #define STM32_FLASH_H5_OPTKEYR (STM32_FLASH_H5_REGS_ADDR + 0x10) #define STM32_FLASH_H5_NSSR (STM32_FLASH_H5_REGS_ADDR + 0x20) #define STM32_FLASH_H5_NSCR (STM32_FLASH_H5_REGS_ADDR + 0x28) #define STM32_FLASH_H5_NSCCR (STM32_FLASH_H5_REGS_ADDR + 0x30) #define STM32_FLASH_H5_OPTSR_CUR (STM32_FLASH_H5_REGS_ADDR + 0x50) // FLASH_OPTSR_CUR: SWAP_BANK reports whether the two physical banks are mapped // swapped in the address space (RM0481). #define STM32_FLASH_H5_OPTSR_SWAP_BANK 31 // FLASH_NSCR control bits (RM0481) #define STM32_FLASH_H5_NSCR_LOCK 0 #define STM32_FLASH_H5_NSCR_PG 1 /* Program */ #define STM32_FLASH_H5_NSCR_SER 2 /* Sector erase */ #define STM32_FLASH_H5_NSCR_BER 3 /* Bank erase */ #define STM32_FLASH_H5_NSCR_STRT 5 /* Start */ #define STM32_FLASH_H5_NSCR_SNB 6 /* Sector number [12:6] (7 bits) */ #define STM32_FLASH_H5_NSCR_SNB_MASK (0x7Fu << STM32_FLASH_H5_NSCR_SNB) #define STM32_FLASH_H5_NSCR_MER 15 /* Mass erase */ #define STM32_FLASH_H5_NSCR_BKSEL 31 /* Bank selector */ // FLASH_NSSR status bits (RM0481) #define STM32_FLASH_H5_NSSR_BSY 0 /* Busy */ #define STM32_FLASH_H5_NSSR_EOP 16 /* End of operation */ #define STM32_FLASH_H5_NSSR_WRPERR 17 #define STM32_FLASH_H5_NSSR_PGSERR 18 #define STM32_FLASH_H5_NSSR_STRBERR 19 #define STM32_FLASH_H5_NSSR_INCERR 20 #define STM32_FLASH_H5_NSSR_OPTCHANGEERR 23 #define STM32_FLASH_H5_NSSR_ERROR_MASK (0x009E0000) /* WRPERR|PGSERR|STRBERR|INCERR|OPTCHANGEERR */ // FLASH_NSCCR: write 1 to clear the matching NSSR flag (bits 16..23) #define STM32_FLASH_H5_NSCCR_CLEAR_ALL (0x00FF0000) // == STM32WB0 == (RM0530) // WB0 FLASH registers #define STM32_FLASH_WB0_REGS_ADDR ((uint32_t) 0x40001000) #define STM32_FLASH_WB0_COMMAND (STM32_FLASH_WB0_REGS_ADDR + 0x00) #define STM32_FLASH_WB0_CONFIG (STM32_FLASH_WB0_REGS_ADDR + 0x04) #define STM32_FLASH_WB0_IRQSTAT (STM32_FLASH_WB0_REGS_ADDR + 0x08) #define STM32_FLASH_WB0_IRQMASK (STM32_FLASH_WB0_REGS_ADDR + 0x0c) #define STM32_FLASH_WB0_IRQRAW (STM32_FLASH_WB0_REGS_ADDR + 0x10) #define STM32_FLASH_WB0_FLASH_SIZE (STM32_FLASH_WB0_REGS_ADDR + 0x14) #define STM32_FLASH_WB0_ADDRESS (STM32_FLASH_WB0_REGS_ADDR + 0x18) #define STM32_FLASH_WB0_LFSRVAL (STM32_FLASH_WB0_REGS_ADDR + 0x24) #define STM32_FLASH_WB0_PAGEPROT0 (STM32_FLASH_WB0_REGS_ADDR + 0x34) #define STM32_FLASH_WB0_PAGEPROT1 (STM32_FLASH_WB0_REGS_ADDR + 0x38) #define STM32_FLASH_WB0_DATA0 (STM32_FLASH_WB0_REGS_ADDR + 0x40) #define STM32_FLASH_WB0_DATA1 (STM32_FLASH_WB0_REGS_ADDR + 0x44) #define STM32_FLASH_WB0_DATA2 (STM32_FLASH_WB0_REGS_ADDR + 0x48) #define STM32_FLASH_WB0_DATA3 (STM32_FLASH_WB0_REGS_ADDR + 0x4c) // WB0 FLASH commands #define STM32_FLASH_WB0_CMD_ERASE_PAGE (0x11) #define STM32_FLASH_WB0_CMD_MASS_ERASE (0x22) //WB06,WB07,WB09 only #define STM32_FLASH_WB0_CMD_WRITE (0x33) #define STM32_FLASH_WB0_CMD_MASSREAD (0x55) #define STM32_FLASH_WB0_CMD_BURSTWRITE (0xCC) #define STM32_FLASH_WB0_CMD_OTPWRITE (0xEE) #define STM32_FLASH_WB0_CMD_KEYWRITE (0xFF) // FLASH_SIZE register bits #define STM32_FLASH_WB0_RAM_SIZE (17) #define STM32_FLASH_WB0_FLASH_SECURE (19) #define STM32_FLASH_WB0_SWD_DISABLE (20) // FLASH IRQ (status) bits #define STM32_FLASH_WB0_IRQ_ILLCMD (1 << 3) #define STM32_FLASH_WB0_IRQ_CMDERR (1 << 2) #define STM32_FLASH_WB0_IRQ_CMDSTART (1 << 1) #define STM32_FLASH_WB0_IRQ_CMDDONE (1 << 0) #define STM32_FLASH_WB0_IRQ_ERR_MASK (STM32_FLASH_WB0_IRQ_CMDERR | STM32_FLASH_WB0_IRQ_ILLCMD) #define STM32_FLASH_WB0_IRQ_ALL (STM32_FLASH_WB0_IRQ_CMDDONE | STM32_FLASH_WB0_IRQ_CMDSTART | STM32_FLASH_WB0_IRQ_ERR_MASK) // key values, to be written into DATA0-3 #define STM32_FLASH_WB0_KEY01_UNLOCK (0xFFFFFFFF) #define STM32_FLASH_WB0_KEY01_READOUT_PROT (0xAAAAAAAA) #define STM32_FLASH_WB0_KEY01_SWD_DISABLED (0xABACABAD) /* irreversible protection level */ #define STM32_FLASH_WB0_KEY2 (0xC7EF584D) #define STM32_FLASH_WB0_KEY3 (0xB3A21096) // == STM32C5 == (RM0522) // C5 Flash registers // Base address: AHB1PERIPH_BASE(0x40020000) + 0x2000 = 0x40022000 #define STM32_FLASH_C5_REGS_ADDR ((uint32_t) 0x40022000) #define STM32_FLASH_C5_KEYR (STM32_FLASH_C5_REGS_ADDR + 0x04) #define STM32_FLASH_C5_OPTKEYR (STM32_FLASH_C5_REGS_ADDR + 0x0c) #define STM32_FLASH_C5_SR (STM32_FLASH_C5_REGS_ADDR + 0x20) #define STM32_FLASH_C5_CR (STM32_FLASH_C5_REGS_ADDR + 0x28) #define STM32_FLASH_C5_CCR (STM32_FLASH_C5_REGS_ADDR + 0x30) #define STM32_FLASH_C5_OPTSR_CUR (STM32_FLASH_C5_REGS_ADDR + 0x50) // C5 Flash control register (FLASH_CR) #define STM32_FLASH_C5_CR_LOCK 0 #define STM32_FLASH_C5_CR_PG 1 #define STM32_FLASH_C5_CR_PER 2 #define STM32_FLASH_C5_CR_BER 3 #define STM32_FLASH_C5_CR_STRT 5 #define STM32_FLASH_C5_CR_PNB 6 #define STM32_FLASH_C5_CR_MER 15 #define STM32_FLASH_C5_CR_BKSEL 31 // C5 Flash option status register #define STM32_FLASH_C5_OPTSR_CUR_SINGLE_BANK 30 #define STM32_FLASH_C5_OPTSR_CUR_SWAP_BANK 31 // C5 Flash status register (FLASH_SR) // SR is read-only; error flags are cleared by writing their clear bits to CCR. #define STM32_FLASH_C5_SR_BSY 0 #define STM32_FLASH_C5_SR_WBNE 1 #define STM32_FLASH_C5_SR_DBNE 3 #define STM32_FLASH_C5_SR_EOP 16 #define STM32_FLASH_C5_SR_WRPERR 17 #define STM32_FLASH_C5_SR_PGSERR 18 #define STM32_FLASH_C5_SR_STRBERR 19 #define STM32_FLASH_C5_SR_INCERR 20 #define STM32_FLASH_C5_SR_ERROR_MASK \ ((1u << STM32_FLASH_C5_SR_WRPERR) | (1u << STM32_FLASH_C5_SR_PGSERR) | \ (1u << STM32_FLASH_C5_SR_STRBERR) | (1u << STM32_FLASH_C5_SR_INCERR)) // == STM32WB == (RM0434) // WB Flash registers #define STM32_FLASH_WB_REGS_ADDR ((uint32_t) 0x58004000) #define STM32_FLASH_WB_ACR (STM32_FLASH_WB_REGS_ADDR + 0x00) #define STM32_FLASH_WB_KEYR (STM32_FLASH_WB_REGS_ADDR + 0x08) #define STM32_FLASH_WB_OPT_KEYR (STM32_FLASH_WB_REGS_ADDR + 0x0c) #define STM32_FLASH_WB_SR (STM32_FLASH_WB_REGS_ADDR + 0x10) #define STM32_FLASH_WB_CR (STM32_FLASH_WB_REGS_ADDR + 0x14) #define STM32_FLASH_WB_ECCR (STM32_FLASH_WB_REGS_ADDR + 0x18) #define STM32_FLASH_WB_OPTR (STM32_FLASH_WB_REGS_ADDR + 0x20) #define STM32_FLASH_WB_PCROP1ASR (STM32_FLASH_WB_REGS_ADDR + 0x24) #define STM32_FLASH_WB_PCROP1AER (STM32_FLASH_WB_REGS_ADDR + 0x28) #define STM32_FLASH_WB_WRP1AR (STM32_FLASH_WB_REGS_ADDR + 0x2c) #define STM32_FLASH_WB_WRP1BR (STM32_FLASH_WB_REGS_ADDR + 0x30) #define STM32_FLASH_WB_PCROP1BSR (STM32_FLASH_WB_REGS_ADDR + 0x34) #define STM32_FLASH_WB_PCROP1BER (STM32_FLASH_WB_REGS_ADDR + 0x38) #define STM32_FLASH_WB_IPCCBR (STM32_FLASH_WB_REGS_ADDR + 0x3c) #define STM32_FLASH_WB_C2ACR (STM32_FLASH_WB_REGS_ADDR + 0x5c) #define STM32_FLASH_WB_C2SR (STM32_FLASH_WB_REGS_ADDR + 0x60) #define STM32_FLASH_WB_C2CR (STM32_FLASH_WB_REGS_ADDR + 0x64) #define STM32_FLASH_WB_SFR (STM32_FLASH_WB_REGS_ADDR + 0x80) #define STM32_FLASH_WB_SRRVR (STM32_FLASH_WB_REGS_ADDR + 0x84) // WB Flash control register #define STM32_FLASH_WB_CR_STRT (16) /* Start */ #define STM32_FLASH_WB_CR_OPTSTRT (17) /* Start writing option bytes */ #define STM32_FLASH_WB_CR_OBL_LAUNCH (27) /* Forces the option byte loading */ #define STM32_FLASH_WB_CR_OPTLOCK (30) /* Option Lock */ #define STM32_FLASH_WB_CR_LOCK (31) /* Lock */ // WB Flash status register #define STM32_FLASH_WB_SR_ERROR_MASK (0x3f8) // SR [9:3] #define STM32_FLASH_WB_SR_PROGERR (3) /* Programming alignment error */ #define STM32_FLASH_WB_SR_WRPERR (4) /* Write protection error */ #define STM32_FLASH_WB_SR_PGAERR (5) /* Programming error */ #define STM32_FLASH_WB_SR_BSY (16) /* Busy */ #endif // STM32_FLASH_H stlink-1.9.0/inc/stm32_register.h000066400000000000000000000211521526027543100166310ustar00rootroot00000000000000/** ****************************************************************************** * @file : stm32_register.h * @brief : STM32 specific registers * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #ifndef STM32_REGISTER_H #define STM32_REGISTER_H #define STM32_REG_CM3_CPUID ((uint32_t) 0xe000ed00) #define STM32_REG_CMx_CPUID_PARTNO_CM0 0xc20 #define STM32_REG_CMx_CPUID_PARTNO_CM0P 0xc60 #define STM32_REG_CMx_CPUID_PARTNO_CM3 0xc23 #define STM32_REG_CMx_CPUID_PARTNO_CM4 0xc24 #define STM32_REG_CMx_CPUID_PARTNO_CM7 0xc27 #define STM32_REG_CMx_CPUID_PARTNO_CM33 0xd21 #define STM32_REG_CMx_CPUID_IMPL_ARM 0x41 #define STM32_REG_CM3_FP_CTRL ((uint32_t) 0xe0002000) // Flash Patch Control Register #define STM32_REG_CM3_FP_COMPn(n) ((uint32_t) (0xe0002008 + n * 4)) #define STM32_REG_CM3_FP_CTRL_KEY (1U << 1) #define STM32_REG_CM7_FP_LAR ((uint32_t) 0xe0000fb0) #define STM32_REG_CM7_FP_LAR_KEY ((uint32_t) 0xc5acce55) #define STM32_REG_CM3_DEMCR ((uint32_t) 0xe000edfc) #define STM32_REG_CM3_DEMCR_TRCENA (1U << 24) #define STM32_REG_CM3_DEMCR_VC_HARDERR (1U << 10) #define STM32_REG_CM3_DEMCR_VC_BUSERR (1U << 8) #define STM32_REG_CM3_DEMCR_VC_CORERESET (1U << 0) #define STM32_REG_CM3_DWT_COMPn(n) ((uint32_t) (0xe0001020 + n * 16)) #define STM32_REG_CM3_DWT_MASKn(n) ((uint32_t) (0xe0001024 + n * 16)) #define STM32_REG_CM3_DWT_FUNn(n) ((uint32_t) (0xe0001028 + n * 16)) /* Cortexâ„¢-M3 Technical Reference Manual */ /* Configurable Fault Status Register */ #define STM32_REG_CFSR ((uint32_t) 0xe000ed28) /* Hard Fault Status Register */ #define STM32_REG_HFSR ((uint32_t) 0xe000ed2c) /* Debug Halting Control and Status Register */ #define STM32_REG_DFSR ((uint32_t) 0xe000ed30) #define STM32_REG_DFSR_HALT (1U << 0) #define STM32_REG_DFSR_BKPT (1U << 1) #define STM32_REG_DFSR_VCATCH (1U << 3) #define STM32_REG_DFSR_EXTERNAL (1U << 4) #define STM32_REG_DFSR_CLEAR ((uint32_t) 0x0000001f) #define STM32_REG_DHCSR ((uint32_t) 0xe000edf0) #define STM32_REG_DHCSR_DBGKEY ((uint32_t) (0xa05f << 16)) #define STM32_REG_DHCSR_C_DEBUGEN (1U << 0) #define STM32_REG_DHCSR_C_HALT (1U << 1) #define STM32_REG_DHCSR_C_STEP (1U << 2) #define STM32_REG_DHCSR_C_MASKINTS (1U << 3) #define STM32_REG_DHCSR_S_REGRDY (1U << 16) #define STM32_REG_DHCSR_S_HALT (1U << 17) #define STM32_REG_DHCSR_S_SLEEP (1U << 18) #define STM32_REG_DHCSR_S_LOCKUP (1U << 19) #define STM32_REG_DHCSR_S_RETIRE_ST (1U << 24) #define STM32_REG_DHCSR_S_RESET_ST (1U << 25) #define STM32_REG_DCRSR ((uint32_t) 0xe000edf4) #define STM32_REG_DCRDR ((uint32_t) 0xe000edf8) #define STM32_REG_DEMCR ((uint32_t) 0xe000edfc) #define STM32_REG_DEMCR_TRCENA (1U << 24) /* MCU Debug Component Registers */ /* * DBGMCU's address and trace-enable bit layout are family-specific. * Below: classic parts (F0/F1/F3/F4/G0/G4/L4...) * --> One bit does both pin routing and TPIU clocking. */ #define STM32_REG_DBGMCU_CR ((uint32_t) 0xe0042004) // Debug MCU Configuration Register #define STM32_REG_DBGMCU_CR_DBG_SLEEP (1U << 0) #define STM32_REG_DBGMCU_CR_DBG_STOP (1U << 1) #define STM32_REG_DBGMCU_CR_DBG_STANDBY (1U << 2) #define STM32_REG_DBGMCU_CR_TRACE_IOEN (1U << 5) #define STM32_REG_DBGMCU_CR_TRACE_MODE_ASYNC (0U << 6) /* STM32H5 (RM0481): * Pin routing (TRACE_IOEN) and TPIU clocking (TRACE_CLKEN) are separate bits; * both are required for SWO to output anything. */ #define STM32_REG_DBGMCU_CR_H5 ((uint32_t) 0x44024004) // Debug MCU Configuration Register #define STM32_REG_DBGMCU_CR_TRACE_IOEN_H5 (1U << 4) #define STM32_REG_DBGMCU_CR_TRACE_CLKEN_H5 (1U << 5) /* STM32L5/U5: * Same two-bit layout as H5, different DBGMCU address. */ #define STM32_REG_DBGMCU_CR_L5_U5 ((uint32_t) 0xe0044004) // Debug MCU Configuration Register #define STM32_REG_DBGMCU_CR_TRACE_IOEN_L5_U5 (1U << 4) #define STM32_REG_DBGMCU_CR_TRACE_CLKEN_L5_U5 (1U << 5) /* Data Watchpoint and Trace (DWT) Registers */ #define STM32_REG_DWT_CTRL ((uint32_t) 0xe0001000) // DWT Control Register #define STM32_REG_DWT_CTRL_NUM_COMP (1U << 28) #define STM32_REG_DWT_CTRL_CYC_TAP (1U << 9) #define STM32_REG_DWT_CTRL_POST_INIT (1U << 5) #define STM32_REG_DWT_CTRL_POST_PRESET (1U << 1) #define STM32_REG_DWT_CTRL_CYCCNT_ENA (1U << 0) #define STM32_REG_DWT_FUNCTION0 ((uint32_t) 0xe0001028) // DWT Function Register 0 #define STM32_REG_DWT_FUNCTION1 ((uint32_t) 0xe0001038) // DWT Function Register 1 #define STM32_REG_DWT_FUNCTION2 ((uint32_t) 0xe0001048) // DWT Function Register 2 #define STM32_REG_DWT_FUNCTION3 ((uint32_t) 0xe0001058) // DWT Function Register 3 /* Instrumentation Trace Macrocell (ITM) Registers */ #define STM32_REG_ITM_TER ((uint32_t) 0xe0000e00) // ITM Trace Enable Register #define STM32_REG_ITM_TER_PORTS_ALL ((uint32_t) 0xffffffff) #define STM32_REG_ITM_TPR ((uint32_t) 0xe0000e40) // ITM Trace Privilege Register #define STM32_REG_ITM_TPR_PORTS_ALL ((uint32_t) 0x0000000f) #define STM32_REG_ITM_TCR ((uint32_t) 0xe0000e80) // ITM Trace Control Register #define STM32_REG_ITM_TCR_TRACE_BUS_ID_1 (1U << 16) #define STM32_REG_ITM_TCR_SWO_ENA (1U << 4) #define STM32_REG_ITM_TCR_DWT_ENA (1U << 3) #define STM32_REG_ITM_TCR_SYNC_ENA (1U << 2) #define STM32_REG_ITM_TCR_TS_ENA (1U << 1) #define STM32_REG_ITM_TCR_ITM_ENA (1U << 0) #define STM32_REG_ITM_TCC ((uint32_t) 0xe0000e90) // ITM Trace Cycle Count #define STM32_REG_ITM_LAR ((uint32_t) 0xe0000fb0) // ITM Lock Access Register #define STM32_REG_ITM_LAR_KEY ((uint32_t) 0xc5acce55) /* Trace Port Interface (TPI) Registers */ #define STM32_REG_TPI_LAR ((uint32_t) 0xe0040fb0) // TPI Lock Access Register #define STM32_REG_TPI_LAR_KEY ((uint32_t) 0xc5acce55) #define STM32_REG_TPI_CSPSR ((uint32_t) 0xe0040004) // TPI Current Parallel Port Size Reg #define STM32_REG_TPI_CSPSR_PORT_SIZE_1 (1U << 0) #define STM32_REG_TPI_ACPR ((uint32_t) 0xe0040010) // TPI Async Clock Prescaler Register #define STM32_REG_TPI_ACPR_MAX ((uint32_t) 0x00001fff) #define STM32_REG_TPI_SPPR ((uint32_t) 0xe00400f0) // TPI Selected Pin Protocol Register #define STM32_REG_TPI_SPPR_SWO_MANCHESTER (1U << 0) #define STM32_REG_TPI_SPPR_SWO_NRZ (2U << 0) #define STM32_REG_TPI_FFCR ((uint32_t) 0xe0040304) // TPI Formatter and Flush Control Register #define STM32_REG_TPI_FFCR_TRIG_IN (1U << 8) /* Application Interrupt and Reset Control Register */ #define STM32_REG_AIRCR ((uint32_t) 0xe000ed0c) #define STM32_REG_AIRCR_VECTKEY ((uint32_t) 0x05fa0000) #define STM32_REG_AIRCR_SYSRESETREQ ((uint32_t) 0x00000004) #define STM32_REG_AIRCR_VECTRESET ((uint32_t) 0x00000001) /* ARM Cortex-M7 Processor Technical Reference Manual */ /* Cache Control and Status Register */ #define STM32_REG_CM7_CTR ((uint32_t) 0xe000ed7c) #define STM32_REG_CM7_CLIDR ((uint32_t) 0xe000ed78) #define STM32_REG_CM7_CCR ((uint32_t) 0xe000ed14) #define STM32_REG_CM7_CCR_DC (1U << 16) #define STM32_REG_CM7_CCR_IC (1U << 17) #define STM32_REG_CM7_CSSELR ((uint32_t) 0xe000ed84) #define STM32_REG_CM7_DCCSW ((uint32_t) 0xe000ef6c) #define STM32_REG_CM7_ICIALLU ((uint32_t) 0xe000ef50) #define STM32_REG_CM7_CCSIDR ((uint32_t) 0xe000ed80) #endif // STM32_REGISTER_H stlink-1.9.0/inc/version.h.in000066400000000000000000000014411526027543100160460ustar00rootroot00000000000000/** ****************************************************************************** * @file : version.h * @brief : stlink project version * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #ifndef VERSION_H #define VERSION_H #define STLINK_VERSION "@PROJECT_VERSION@" #define STLINK_VERSION_MAJOR @PROJECT_VERSION_MAJOR@ #define STLINK_VERSION_MINOR @PROJECT_VERSION_MINOR@ #define STLINK_VERSION_PATCH @PROJECT_VERSION_PATCH@ #endif // VERSION_H stlink-1.9.0/src/000077500000000000000000000000001526027543100136215ustar00rootroot00000000000000stlink-1.9.0/src/st-flash/000077500000000000000000000000001526027543100153425ustar00rootroot00000000000000stlink-1.9.0/src/st-flash/flash.c000066400000000000000000000305251526027543100166100ustar00rootroot00000000000000/** ****************************************************************************** * @file : flash.c * @brief : Tool: st-flash * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #include "flash.h" #include "flash_opts.h" static stlink_t *connected_stlink = NULL; static void cleanup(int32_t signum) { (void)signum; if(connected_stlink) { // switch back to mass storage mode before closing stlink_run(connected_stlink, RUN_NORMAL); stlink_exit_debug_mode(connected_stlink); stlink_close(connected_stlink); } exit(1); } static void usage(void) { puts("usage: st-flash [options] read [file] [addr] [size]"); puts(" st-flash [options] write [addr] [size]"); puts(" st-flash [options] write "); puts(" st-flash [options] erase "); puts(" st-flash [options] reset"); puts(""); puts("options:"); puts(" --freq Frequency of JTAG/SWD, default 1800kHz."); puts(" --serial STLink device to use."); puts(" --connect-under-reset Pull reset low while connecting."); puts(" --hot-plug Connect without reset."); puts(" --reset Reset after writing."); puts(" --mass-erase Mass erase before writing"); puts(" --format {binary|ihex} Format of file to read or write. When writing"); puts(" with ihex specifying addr is not needed."); puts(" --flash Specify size of flash, e.g. 128k, 1M."); puts(" --area Area to access, one of: main(default), system,"); puts(" otp, option, option_boot_add, optcr, optcr1."); puts(" --opt Skip writing empty bytes at the tail end."); puts(" --debug Output extra debug information."); puts(" --version Print version information."); puts(" --help Show this help."); puts(""); puts("examples:"); puts(" st-flash --area=option read [file] [size]"); puts(" st-flash --area=option write 0xXXXXXXXX"); puts(" st-flash --area=option_boot_add read"); puts(" st-flash --area=option_boot_add write 0xXXXXXXXX"); puts(" st-flash --area=optcr read"); puts(" st-flash --area=optcr write 0xXXXXXXXX"); puts(" st-flash --area=optcr1 read"); puts(" st-flash --area=optcr1 write 0xXXXXXXXX"); puts(" st-flash --area=otp read "); puts(" st-flash --area=otp write 0xXXXXXXXX"); } int32_t main(int32_t ac, char** av) { stlink_t* sl = NULL; struct flash_opts o; int32_t err = -1; uint8_t * mem = NULL; int32_t getopt_ret; o.size = 0; o.connect = CONNECT_NORMAL; getopt_ret = flash_get_opts(&o, ac - 1, av + 1); if(getopt_ret == -1) { printf("invalid command line\n"); usage(); return (-1); } else if(getopt_ret == 1) { usage(); return 0; } printf("st-flash %s\n", STLINK_VERSION); init_chipids(NULL); if(o.remote) { sl = stlink_open_remote_str(o.log_level, o.remote, o.connect, o.freq); } else { sl = stlink_open_usb(o.log_level, o.connect, (char *)o.serial, o.freq); } if(sl == NULL) { return (-1); } if(sl->flash_type == STM32_FLASH_TYPE_UNKNOWN) { printf("Failed to connect to target\n"); fprintf(stderr, "Failed to parse flash type or unrecognized flash type\n"); goto on_error; } if( o.flash_size != 0u && o.flash_size != sl->flash_size ) { sl->flash_size = o.flash_size; printf("Forcing flash size: --flash=0x%08X\n", sl->flash_size); } sl->verbose = o.log_level; sl->opt = o.opt; const enum erase_type_t erase_type = o.mass_erase ? MASS_ERASE : SECTION_ERASE; connected_stlink = sl; signal(SIGINT, &cleanup); signal(SIGTERM, &cleanup); signal(SIGSEGV, &cleanup); // core must be halted to use RAM based flashloaders if(stlink_force_debug(sl)) { printf("Failed to halt the core\n"); goto on_error; } if(stlink_status(sl)) { printf("Failed to get Core's status\n"); goto on_error; } if(o.cmd == FLASH_CMD_WRITE) { uint32_t size = 0; if(erase_type == MASS_ERASE) { err = stlink_erase_flash_mass(sl); if(err == -1) { printf("stlink_erase_flash_mass() == -1\n"); goto on_error; } } // write if(o.format == FLASH_FORMAT_IHEX) { err = stlink_parse_ihex(o.filename, stlink_get_erased_pattern(sl), &mem, &size, &o.addr); if(err == -1) { printf("Cannot parse %s as Intel-HEX file\n", o.filename); goto on_error; } } if((o.addr >= sl->flash_base) && (o.addr < sl->flash_base + sl->flash_size)) { if(o.format == FLASH_FORMAT_IHEX) { err = stlink_mwrite_flash(sl, mem, size, o.addr, erase_type); } else { err = stlink_fwrite_flash(sl, o.filename, o.addr, erase_type); } if(err == -1) { printf("stlink_fwrite_flash() == -1\n"); goto on_error; } } else if((o.addr >= sl->sram_base) && (o.addr < sl->sram_base + sl->sram_size)) { if(o.format == FLASH_FORMAT_IHEX) { err = stlink_mwrite_sram(sl, mem, size, o.addr); } else { err = stlink_fwrite_sram(sl, o.filename, o.addr); } if(err == -1) { printf("stlink_fwrite_sram() == -1\n"); goto on_error; } } else if((o.addr >= sl->option_base) && (o.addr < sl->option_base + sl->option_size)) { err = stlink_fwrite_option_bytes(sl, o.filename, o.addr); if(err == -1) { printf("stlink_fwrite_option_bytes() == -1\n"); goto on_error; } } else if(o.area == FLASH_OPTION_BYTES) { if(o.val == 0) { printf("attempting to set option byte to 0, abort.\n"); goto on_error; } err = stlink_write_option_bytes32(sl, o.val); if(err == -1) { printf("stlink_write_option_bytes32() == -1\n"); goto on_error; } } else if(o.area == FLASH_OPTCR) { DLOG("@@@@ Write %d (%0#10x) to option control register\n", o.val, o.val); err = stlink_write_option_control_register32(sl, o.val); } else if(o.area == FLASH_OPTCR1) { DLOG("@@@@ Write %d (%0#10x) to option control register 1\n", o.val, o.val); err = stlink_write_option_control_register1_32(sl, o.val); } else if(o.area == FLASH_OPTION_BYTES_BOOT_ADD) { DLOG("@@@@ Write %d (%0#10x) to option bytes boot address\n", o.val, o.val); err = stlink_write_option_bytes_boot_add32(sl, o.val); } else if(o.area == FLASH_OTP) { if(sl->otp_base == 0) { err = -1; printf("OTP Write NOT implemented\n"); goto on_error; } err = stlink_fwrite_flash(sl, o.filename, o.addr, NO_ERASE); if(err == -1) { printf("stlink_fwrite_flash() == -1\n"); goto on_error; } } else { err = -1; printf("Unknown memory region\n"); goto on_error; } } else if(o.cmd == FLASH_CMD_ERASE) { // erase if((erase_type == MASS_ERASE) || (o.size == 0 || o.addr == 0)) { err = stlink_erase_flash_mass(sl); if(err == -1) { printf("stlink_erase_flash_mass() == -1\n"); goto on_error; } printf("Mass erase completed successfully.\n"); } else { err = stlink_erase_flash_section(sl, o.addr, o.size, false); if(err == -1) { printf("stlink_erase_flash_section() == -1\n"); goto on_error; } printf("Section erase completed successfully.\n"); } // reset after erase if(stlink_reset(sl, RESET_AUTO)) { printf("Failed to reset device\n"); goto on_error; } } else if(o.cmd == CMD_RESET) { // reset if(stlink_reset(sl, RESET_AUTO)) { printf("Failed to reset device\n"); goto on_error; } else { stlink_run(sl, RUN_NORMAL); } } else { // read if((o.area == FLASH_MAIN_MEMORY) || (o.area == FLASH_SYSTEM_MEMORY)) { if((o.size == 0) && (o.addr >= sl->flash_base) && (o.addr < sl->flash_base + sl->flash_size)) { o.size = sl->flash_size; } else if((o.size == 0) && (o.addr >= sl->sram_base) && (o.addr < sl->sram_base + sl->sram_size)) { o.size = sl->sram_size; } err = stlink_fread(sl, o.filename, o.format == FLASH_FORMAT_IHEX, o.addr, o.size); if(err == -1) { printf("could not read main memory (%d)\n", err); goto on_error; } } else if(o.area == FLASH_OPTION_BYTES) { uint32_t remaining_option_length = sl->option_size / 4; DLOG("@@@@ Read %u (%#x) option bytes from %#10x\n", remaining_option_length, remaining_option_length, sl->option_base); uint32_t option_byte = 0; err = stlink_read_option_bytes32(sl, &option_byte); if(err == -1) { printf("could not read option bytes (%d)\n", err); goto on_error; } else if(NULL != o.filename) { int32_t fd = open(o.filename, O_RDWR | O_TRUNC | O_CREAT | O_BINARY, 00700); if(fd == -1) { fprintf(stderr, "open(%s) == -1\n", o.filename); goto on_error; } err = (uint32_t) write(fd, &option_byte, 4); if(err == -1) { printf("could not write buffer to file (%d)\n", err); goto on_error; } close(fd); } else { printf("%08x\n", option_byte); } } else if(o.area == FLASH_OPTION_BYTES_BOOT_ADD) { uint32_t option_byte = 0; err = stlink_read_option_bytes_boot_add32(sl, &option_byte); if(err == -1) { printf("could not read option bytes boot address (%d)\n", err); goto on_error; } else { printf("%08x\n",option_byte); } } else if(o.area == FLASH_OPTCR) { uint32_t option_byte = 0; err = stlink_read_option_control_register32(sl, &option_byte); if(err == -1) { printf("could not read option control register (%d)\n", err); goto on_error; } else { printf("%08x\n",option_byte); } } else if(o.area == FLASH_OPTCR1) { uint32_t option_byte = 0; err = stlink_read_option_control_register1_32(sl, &option_byte); if(err == -1) { printf("could not read option control register (%d)\n", err); goto on_error; } else { printf("%08x\n",option_byte); } } else if(o.area == FLASH_OTP) { if(sl->otp_base == 0) { err = -1; printf("OTP Read NOT implemented\n"); goto on_error; } err = stlink_fread(sl, o.filename, 0, sl->otp_base, sl->otp_size); if(err == -1) { printf("could not read OTP area (%d)\n", err); goto on_error; } } } if(o.reset) stlink_reset(sl, RESET_AUTO); stlink_run(sl, RUN_NORMAL); err = 0; // success on_error: stlink_exit_debug_mode(sl); stlink_close(sl); free(mem); return (err); } stlink-1.9.0/src/st-flash/flash.h000066400000000000000000000021501526027543100166060ustar00rootroot00000000000000/** ****************************************************************************** * @file : flash.h * @brief : Tool: st-flash * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #ifndef FLASH_H #define FLASH_H #include #include #include #include #include #include #if defined(_WIN32) #else #include #endif // _WIN32 #include #include #include #include #include #include #include #include #define DEBUG_LOG_LEVEL 100 #define STND_LOG_LEVEL 50 #define ENABLE_OPT 1 // static stlink_t *connected_stlink = NULL; // static void cleanup(int32_t signum); // static void usage(void); #endif // FLASH_H stlink-1.9.0/src/st-flash/flash_opts.c000066400000000000000000000320371526027543100176550ustar00rootroot00000000000000/** ****************************************************************************** * @file : flash_opts.c * @brief : Tool: st-flash - Flash Options * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #include "flash.h" #include "flash_opts.h" static bool starts_with(const char * str, const char * prefix) { uint64_t n = strlen(prefix); if(strlen(str) < n) { return (false); } return (0 == strncmp(str, prefix, n)); } // support positive integer from 0 to UINT64_MAX // support decimal, hexadecimal, octal, binary format like 0xff 12 1k 1M, 0b1001 // negative numbers are not supported // return 0 if success else return -1 static int32_t get_long_integer_from_char_array (const char *const str, uint64_t *read_value) { uint64_t value; char *tail; if(starts_with (str, "0x") || starts_with (str, "0X")) { // hexadecimal value = strtoul (str + 2, &tail, 16); } else if(starts_with (str, "0b") || starts_with (str, "0B")) { // binary value = strtoul (str + 2, &tail, 2); } else if(starts_with (str, "0")) { // octal value = strtoul (str + 1, &tail, 8); } else { // decimal value = strtoul (str, &tail, 10); } if(((tail[0] == 'k') || (tail[0] == 'K')) && (tail[1] == '\0')) { value = value * 1024; } else if(((tail[0] == 'm') || (tail[0] == 'M')) && (tail[1] == '\0')) { value = value * 1024 * 1024; } else if(tail[0] == '\0') { /* value not changed */ } else { return (-1); } *read_value = value; return (0); } // support positive integer from 0 to UINT32_MAX // support decimal, hexadecimal, octal, binary format like 0xff 12 1k 1M, 0b1001 // negative numbers are not supported // return 0 if success else return -1 static int32_t get_integer_from_char_array (const char *const str, uint32_t *read_value) { uint64_t value; int32_t result = get_long_integer_from_char_array (str, &value); if(result != 0) { return (result); } else if(value > UINT32_MAX) { fprintf (stderr, "*** Error: Integer greater than UINT32_MAX, cannot convert to int32_t\n"); return (-1); } else { *read_value = (uint32_t) value; return (0); } } static int32_t invalid_args(const char *expected) { fprintf(stderr, "*** Error: Expected args for this command: %s\n", expected); return (-1); } static int32_t bad_arg(const char *arg) { fprintf(stderr, "*** Error: Invalid value for %s\n", arg); return (-1); } int32_t flash_get_opts(struct flash_opts* o, int32_t ac, char** av) { // defaults memset(o, 0, sizeof(*o)); o->log_level = STND_LOG_LEVEL; // options int32_t result; while (ac >= 1) { if(strcmp(av[0], "--version") == 0) { printf("v%s\n", STLINK_VERSION); exit(EXIT_SUCCESS); } else if(strcmp(av[0], "--help") == 0 || strcmp(av[0], "-h") == 0) { return 1; } else if(strcmp(av[0], "--debug") == 0) { o->log_level = DEBUG_LOG_LEVEL; } else if(strcmp(av[0], "--opt") == 0) { o->opt = ENABLE_OPT; } else if(strcmp(av[0], "--mass-erase") == 0) { o->mass_erase = ENABLE_OPT; } else if(strcmp(av[0], "--reset") == 0) { o->reset = 1; } else if(strcmp(av[0], "--serial") == 0 || starts_with(av[0], "--serial=")) { const char * serial; if(strcmp(av[0], "--serial") == 0) { ac--; av++; if(ac < 1) { return (-1); } serial = av[0]; } else { serial = av[0] + strlen("--serial="); } memcpy(o->serial, serial, STLINK_SERIAL_BUFFER_SIZE); } else if(strcmp(av[0], "--area") == 0 || starts_with(av[0], "--area=")) { const char * area; if(strcmp(av[0], "--area") == 0) { ac--; av++; if(ac < 1) { return (-1); } area = av[0]; } else { area = av[0] + strlen("--area="); } if(strcmp(area, "main") == 0) { o->area = FLASH_MAIN_MEMORY; } else if(strcmp(area, "system") == 0) { o->area = FLASH_SYSTEM_MEMORY; } else if(strcmp(area, "otp") == 0) { o->area = FLASH_OTP; } else if(strcmp(area, "option") == 0) { o->area = FLASH_OPTION_BYTES; } else if(strcmp(area, "option_boot_add") == 0) { o->area = FLASH_OPTION_BYTES_BOOT_ADD; } else if(strcmp(area, "optcr") == 0) { o->area = FLASH_OPTCR; } else if(strcmp(area, "optcr1") == 0) { o->area = FLASH_OPTCR1; } else { return (-1); } } else if(strcmp(av[0], "--freq") == 0) { ac--; av++; if(ac < 1) { return (-1); } o->freq = arg_parse_freq(av[0]); if(o->freq < 0) { return (-1); } } else if(starts_with(av[0], "--freq=")) { o->freq = arg_parse_freq(av[0] + strlen("--freq=")); if(o->freq < 0) { return (-1); } } else if(strcmp(av[0], "--format") == 0 || starts_with(av[0], "--format=")) { const char * format; if(strcmp(av[0], "--format") == 0) { ac--; av++; if(ac < 1) { return (-1); } format = av[0]; } else { format = av[0] + strlen("--format="); } if(strcmp(format, "binary") == 0) { o->format = FLASH_FORMAT_BINARY; } else if(strcmp(format, "ihex") == 0) { o->format = FLASH_FORMAT_IHEX; } else { return (bad_arg("format")); } } else if( starts_with(av[0], "--flash=")) { const char *arg = av[0] + strlen("--flash="); uint32_t flash_size; result = get_integer_from_char_array(arg, &flash_size); if(result != 0) { return (bad_arg ("--flash")); } else { o->flash_size = flash_size; } } else if(strcmp(av[0], "--remote") == 0 || starts_with(av[0], "--remote=")) { if(strcmp(av[0], "--remote") == 0) { ac--; av++; if(ac < 1) { return (-1); } o->remote = av[0]; } else { o->remote = av[0] + strlen("--remote="); } } else if(strcmp(av[0], "--connect-under-reset") == 0) { o->connect = CONNECT_UNDER_RESET; } else if(strcmp(av[0], "--hot-plug") == 0) { o->connect = CONNECT_HOT_PLUG; } else { break; // non-option found } ac--; av++; } // command and (optional) device name while (ac >= 1) { if(strcmp(av[0], "erase") == 0) { if(o->cmd != FLASH_CMD_NONE) { return (-1); } o->cmd = FLASH_CMD_ERASE; } else if(strcmp(av[0], "read") == 0) { if(o->cmd != FLASH_CMD_NONE) { return (-1); } o->cmd = FLASH_CMD_READ; } else if(strcmp(av[0], "write") == 0) { if(o->cmd != FLASH_CMD_NONE) { return (-1); } o->cmd = FLASH_CMD_WRITE; } else if(strcmp(av[0], "reset") == 0) { if(o->cmd != FLASH_CMD_NONE) { return (-1); } o->cmd = CMD_RESET; } else { break; } ac--; av++; } switch (o->cmd) { case FLASH_CMD_NONE: // no command found return (-1); case FLASH_CMD_ERASE: // no more arguments expected if(ac != 0 && ac != 2) { return (-1); } if(ac == 2) { uint32_t address; result = get_integer_from_char_array(av[0], &address); if(result != 0) { return bad_arg ("addr"); } else { o->addr = (stm32_addr_t) address; } uint32_t size; result = get_integer_from_char_array(av[1], &size); if(result != 0) { return bad_arg ("size"); } else { o->size = size; } } break; case FLASH_CMD_READ: // expect filename, addr and size if((o->area == FLASH_MAIN_MEMORY) || (o->area == FLASH_SYSTEM_MEMORY)) { if(ac != 3) { return invalid_args("read "); } o->filename = av[0]; uint32_t address; result = get_integer_from_char_array(av[1], &address); if(result != 0) { return bad_arg ("addr"); } else { o->addr = (stm32_addr_t) address; } uint32_t size; result = get_integer_from_char_array(av[2], &size); if(result != 0) { return bad_arg ("size"); } else { o->size = size; } break; } else if(o->area == FLASH_OTP) { if(ac > 1 || ac ==0 ) { return invalid_args("otp read: [path]"); } if(ac > 0) { o->filename = av[0]; } break; } else if(o->area == FLASH_OPTION_BYTES) { if(ac > 2) { return invalid_args("option bytes read: [path] [size]"); } if(ac > 0) { o->filename = av[0]; } if(ac > 1) { uint32_t size; result = get_integer_from_char_array(av[1], &size); if(result != 0) { return bad_arg("option bytes read: invalid size"); } else { o->size = size; } } break; } else if(o->area == FLASH_OPTION_BYTES_BOOT_ADD) { if(ac > 0) { return invalid_args("option bytes boot_add read"); } break; } else if(o->area == FLASH_OPTCR) { if(ac > 0) { return invalid_args("option control register read"); } break; } else if(o->area == FLASH_OPTCR1) { if(ac > 0) { return invalid_args("option control register 1 read"); } break; } break; case FLASH_CMD_WRITE: // TODO: should be boot add 0 and boot add 1 uint32 if(o->area == FLASH_OPTION_BYTES) { // expect option byte value if(ac != 1) { return invalid_args("option byte write "); } uint32_t val; result = get_integer_from_char_array(av[0], &val); if(result != 0) { return bad_arg ("val"); } else { o->val = val; } } else if(o->area == FLASH_OPTION_BYTES_BOOT_ADD) { // expect option bytes boot address if(ac != 1) { return invalid_args("option bytes boot_add write "); } uint32_t val; result = get_integer_from_char_array(av[0], &val); if(result != 0) { return (bad_arg ("val")); } else { o->val = val; } } else if(o->area == FLASH_OPTCR) { // expect option control register value if(ac != 1) { return invalid_args("option control register write "); } uint32_t val; result = get_integer_from_char_array(av[0], &val); if(result != 0) { return bad_arg ("val"); } else { o->val = val; } } else if(o->area == FLASH_OPTCR1) { // expect option control register 1 value if(ac != 1) { return invalid_args("option control register 1 write "); } uint32_t val; result = get_integer_from_char_array(av[0], &val); if(result != 0) { return bad_arg ("val"); } else { o->val = val; } } else if(o->format == FLASH_FORMAT_BINARY) { // expect filename and addr if(ac != 2) { return invalid_args("write "); } o->filename = av[0]; uint32_t addr; result = get_integer_from_char_array(av[1], &addr); if(result != 0) { return (bad_arg ("addr")); } else { o->addr = (stm32_addr_t) addr; } } else if(o->format == FLASH_FORMAT_IHEX) { // expect filename if(ac != 1) { return (invalid_args("write ")); } o->filename = av[0]; } else { return (-1); // should have been caught during format parsing } break; default: break; } return (0); } stlink-1.9.0/src/st-flash/flash_opts.h000066400000000000000000000047441526027543100176660ustar00rootroot00000000000000/** ****************************************************************************** * @file : flash_opts.h * @brief : Tool: st-flash - Flash Options * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #ifndef FLASH_OPTS_H #define FLASH_OPTS_H #include #include #include #include #include #include #include #define FLASH_OPTS_INITIALIZER {0, { 0 }, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL} enum flash_cmd {FLASH_CMD_NONE = 0, FLASH_CMD_WRITE = 1, FLASH_CMD_READ = 2, FLASH_CMD_ERASE = 3, CMD_RESET = 4 }; enum flash_format {FLASH_FORMAT_BINARY = 0, FLASH_FORMAT_IHEX = 1 }; enum flash_area {FLASH_MAIN_MEMORY = 0, FLASH_SYSTEM_MEMORY = 1, FLASH_OTP = 2, FLASH_OPTION_BYTES = 3, FLASH_OPTION_BYTES_BOOT_ADD = 4, FLASH_OPTCR = 5, FLASH_OPTCR1 = 6 }; struct flash_opts { enum flash_cmd cmd; uint8_t serial[STLINK_SERIAL_BUFFER_SIZE]; const char* filename; stm32_addr_t addr; uint32_t size; int32_t reset; int32_t log_level; enum flash_format format; enum flash_area area; uint32_t val; uint32_t flash_size; // --flash=n[k, M] int32_t opt; // enable empty tail data drop optimization int32_t mass_erase; // Use mass-erase when programming flash instead of sector-erase int32_t freq; // --freq=n[k, M] frequency of JTAG/SWD enum connect_type connect; const char *remote; // --remote=host[:port] drive an ST-LINK on another machine }; // static bool starts_with(const char * str, const char * prefix); // static int32_t get_long_integer_from_char_array (const char *const str, uint64_t *read_value); // static int32_t get_integer_from_char_array (const char *const str, uint32_t *read_value); // static int32_t invalid_args(const char *expected); // static int32_t bad_arg(const char *arg); int32_t flash_get_opts(struct flash_opts* o, int32_t ac, char** av); #endif // FLASH_OPTS_H stlink-1.9.0/src/st-info/000077500000000000000000000000001526027543100152005ustar00rootroot00000000000000stlink-1.9.0/src/st-info/info.c000066400000000000000000000151261526027543100163040ustar00rootroot00000000000000/** ****************************************************************************** * @file : info.c * @brief : Tool: st-info * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #include "info.h" static void usage(void) { puts("st-info --version"); puts("st-info --probe [--connect-under-reset] [--hot-plug] [--freq=]"); puts("st-info --serial"); puts("st-info --flash [--connect-under-reset] [--hot-plug] [--freq=]"); puts("st-info --pagesize [--connect-under-reset] [--hot-plug] [--freq=]"); puts("st-info --sram [--connect-under-reset] [--hot-plug] [--freq=]"); puts("st-info --chipid [--connect-under-reset] [--hot-plug] [--freq=]"); puts("st-info --descr [--connect-under-reset] [--hot-plug] [--freq=]"); puts("st-info --voltage [--connect-under-reset] [--hot-plug] [--freq=]"); } static void stlink_print_version(stlink_t *sl) { // Implementation of version printing is minimalistic // but contains all available information from sl->version printf("V%u", sl->version.stlink_v); if(sl->version.jtag_v > 0) printf("J%u", sl->version.jtag_v); if(sl->version.swim_v > 0) printf("S%u", sl->version.swim_v); printf("\n"); } static void stlink_print_info(stlink_t *sl) { const struct stlink_chipid_params *params = NULL; if(!sl) { return; } printf(" version: "); stlink_print_version(sl); printf(" serial: %s\n", sl->serial); printf(" flash: %u (pagesize: %u)\n", sl->flash_size, sl->flash_pgsz); printf(" sram: %u\n", sl->sram_size); printf(" chipid: 0x%.3x\n", sl->chip_id); params = stlink_chipid_get_params(sl->chip_id); if(params) { printf(" dev-type: %s\n", params->dev_type); } // Print target voltage if supported int32_t voltage_mv = -1; if(sl->version.stlink_v != 1) { voltage_mv = stlink_target_voltage(sl); } if(voltage_mv >= 0) { printf(" voltage: %d mV\n", voltage_mv); } else { printf(" voltage: n/a\n"); } } static void stlink_probe(enum connect_type connect, int32_t freq) { stlink_t **stdevs; uint32_t size; size = (uint32_t) stlink_probe_usb(&stdevs, connect, freq); printf("Found %u stlink programmers\n", size); for(uint32_t n = 0; n < size; n++) { if(size > 1) printf("%u.\n", n+1); stlink_print_info(stdevs[n]); } stlink_probe_usb_free(&stdevs, size); } static int32_t is_info_command(const char *a) { return (strcmp(a, "--version") == 0 || strcmp(a, "--probe") == 0 || strcmp(a, "--serial") == 0 || strcmp(a, "--flash") == 0 || strcmp(a, "--pagesize") == 0 || strcmp(a, "--sram") == 0 || strcmp(a, "--chipid") == 0 || strcmp(a, "--descr") == 0 || strcmp(a, "--voltage") == 0); } static int32_t print_data(int32_t ac, char **av) { stlink_t* sl = NULL; enum connect_type connect = CONNECT_NORMAL; int32_t freq = 0; const char *remote = NULL; const char *cmd = NULL; // The command (--probe, --flash, ...) and options may appear in any order. for(int32_t i = 1; i < ac; i++) { if(strcmp(av[i], "--connect-under-reset") == 0) { connect = CONNECT_UNDER_RESET; } else if(strcmp(av[i], "--hot-plug") == 0) { connect = CONNECT_HOT_PLUG; } else if(strcmp(av[i], "--freq") == 0) { if(++i >= ac || (freq = arg_parse_freq(av[i])) < 0) { printf("Incorrect argument: --freq\n\n"); usage(); return (-1); } } else if(strncmp(av[i], "--freq=", 7) == 0) { if((freq = arg_parse_freq(av[i] + 7)) < 0) { printf("Incorrect argument: %s\n\n", av[i]); usage(); return (-1); } } else if(strcmp(av[i], "--remote") == 0) { if(++i >= ac) { printf("Incorrect argument: --remote\n\n"); usage(); return (-1); } remote = av[i]; } else if(strncmp(av[i], "--remote=", 9) == 0) { remote = av[i] + 9; } else if(is_info_command(av[i]) && cmd == NULL) { cmd = av[i]; } else { printf("Incorrect argument: %s\n\n", av[i]); usage(); return (-1); } } if(cmd == NULL) { usage(); return (-1); } if(strcmp(cmd, "--version") == 0) { printf("v%s\n", STLINK_VERSION); return (0); } init_chipids(NULL); // probe needs all devices unclaimed (local only; a remote serves one device) if(strcmp(cmd, "--probe") == 0 && remote == NULL) { stlink_probe(connect, freq); return (0); } // open first st-link device (or the remote one) if(remote) { sl = stlink_open_remote_str(0, remote, connect, freq); } else { sl = stlink_open_usb(0, connect, NULL, freq); } if(sl == NULL) { return (-1); } if(strcmp(cmd, "--probe") == 0) { stlink_print_info(sl); } else if(strcmp(cmd, "--serial") == 0) { printf("%s\n", sl->serial); } else if(strcmp(cmd, "--flash") == 0) { printf("0x%x\n", sl->flash_size); } else if(strcmp(cmd, "--pagesize") == 0) { printf("0x%x\n", sl->flash_pgsz); } else if(strcmp(cmd, "--sram") == 0) { printf("0x%x\n", sl->sram_size); } else if(strcmp(cmd, "--chipid") == 0) { printf("0x%.4x\n", sl->chip_id); } else if(strcmp(cmd, "--descr") == 0) { const struct stlink_chipid_params *params = stlink_chipid_get_params(sl->chip_id); if(params == NULL) { return (-1); } printf("%s\n", params->dev_type); } else if(strcmp(cmd, "--voltage") == 0) { int32_t voltage_mv = -1; if(sl->version.stlink_v != 1) { voltage_mv = stlink_target_voltage(sl); } if(voltage_mv >= 0) { printf("%d\n", voltage_mv); } else { fprintf(stderr, "Failed to read target voltage\n"); if(sl) { stlink_exit_debug_mode(sl); stlink_close(sl); } return (-1); } } if(sl) { stlink_exit_debug_mode(sl); stlink_close(sl); } return (0); } int32_t main(int32_t ac, char** av) { int32_t err = -1; if(ac < 2) { usage(); return (-1); } err = print_data(ac, av); return (err); } stlink-1.9.0/src/st-info/info.h000066400000000000000000000017741526027543100163150ustar00rootroot00000000000000/** ****************************************************************************** * @file : info.h * @brief : Tool: st-info * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #ifndef INFO_H #define INFO_H #include #include #include #include #include #include #include #include // static void usage(void); // static void stlink_print_version(stlink_t *sl); // static void stlink_print_info(stlink_t *sl); // static void stlink_probe(enum connect_type connect, int32_t freq) { }; static int32_t print_data(int32_t ac, char **av); int32_t main(int32_t ac, char** av); #endif // INFO_Hstlink-1.9.0/src/st-server/000077500000000000000000000000001526027543100155535ustar00rootroot00000000000000stlink-1.9.0/src/st-server/server.c000066400000000000000000000153731526027543100172360ustar00rootroot00000000000000/** ****************************************************************************** * @file : server.c * @brief : Tool: st-server * Serves a locally-attached ST-LINK over TCP so that * st-flash / st-info on another machine can drive it via * --remote. The server forwards backend operations; * target-specific logic runs on the client. * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @author : James Walmsley (jameswalmsley) * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #include #include #include #include #include #include #include #if defined(_WIN32) #include #include #else #include #include #include #include #endif // _WIN32 #include #include #include #include static volatile sig_atomic_t stop_requested = 0; static void request_stop(int32_t signum) { (void)signum; stop_requested = 1; } static void setup_signal_handlers(void) { #if defined(_WIN32) signal(SIGINT, request_stop); signal(SIGTERM, request_stop); #else signal(SIGPIPE, SIG_IGN); // a client disconnecting mid-write must not kill us struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = request_stop; sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); #endif } static void usage(void) { puts("st-server - serve a local ST-LINK over TCP for st-flash/st-info --remote"); puts("Usage: st-server [--bind=
[:port]] [--port=] [--serial=] [--freq=] [--verbose[=n]]"); printf(" default bind: 127.0.0.1:%d\n", STLINK_REMOTE_DEFAULT_PORT); puts(" use --bind=0.0.0.0 or --bind=:4500 to listen on all IPv4 interfaces"); } static int32_t parse_bind(const char *arg, char *bind_addr, size_t bind_addr_size, int32_t *port) { const char *colon = strrchr(arg, ':'); if (colon) { size_t addr_len = (size_t)(colon - arg); if (addr_len >= bind_addr_size) { return (-1); } if (addr_len == 0) { strcpy(bind_addr, "0.0.0.0"); } else { memcpy(bind_addr, arg, addr_len); bind_addr[addr_len] = '\0'; } if (colon[1] != '\0') { char *end = NULL; long parsed_port = strtol(colon + 1, &end, 0); if (*end != '\0' || parsed_port <= 0 || parsed_port > UINT16_MAX) { return (-1); } *port = (int32_t)parsed_port; } } else { if (strlen(arg) >= bind_addr_size) { return (-1); } strcpy(bind_addr, arg); } return (0); } int32_t main(int32_t argc, char **argv) { int32_t port = STLINK_REMOTE_DEFAULT_PORT; int32_t freq = 0; int32_t verbose = UINFO; char *serial = NULL; char bind_addr[64] = "127.0.0.1"; static struct option long_options[] = { {"bind", required_argument, NULL, 'b'}, {"port", required_argument, NULL, 'p'}, {"serial", required_argument, NULL, 's'}, {"freq", required_argument, NULL, 'f'}, {"verbose", optional_argument, NULL, 'v'}, {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0} }; int32_t c, option_index = 0; while ((c = getopt_long(argc, argv, "b:p:s:f:v::h", long_options, &option_index)) != -1) { switch (c) { case 'b': if (parse_bind(optarg, bind_addr, sizeof(bind_addr), &port)) { ELOG("Invalid bind address: %s\n", optarg); usage(); return (1); } break; case 'p': { char *end = NULL; long parsed = strtol(optarg, &end, 0); if (*end != '\0' || parsed <= 0 || parsed > UINT16_MAX) { ELOG("Invalid port: %s\n", optarg); usage(); return (1); } port = (int32_t)parsed; break; } case 's': serial = optarg; break; case 'f': freq = (int32_t)strtol(optarg, NULL, 0) * 1000; break; case 'v': verbose = optarg ? atoi(optarg) : UDEBUG; break; case 'h': usage(); return (0); default: usage(); return (1); } } ugly_init(verbose); setup_signal_handlers(); // Open the one probe up front, so a running server means it was claimed. // open_usb also runs chip discovery, which logs a "Can not connect" error // for parts that need the client's connect mode (e.g. STM32H5 on AP1); the // server never uses the chip id, so quiet the open unless -v was given. int32_t open_verbose = (verbose > UINFO) ? verbose : (UERROR - 1); stlink_t *sl = stlink_open_usb(open_verbose, CONNECT_HOT_PLUG, serial, freq); ugly_init(verbose); // restore the requested level for the serve loop if (sl == NULL) { ELOG("Failed to open an ST-LINK device\n"); return (1); } ILOG("Serving ST-LINK (chip discovery is done by the client)\n"); int32_t srv = (int32_t)socket(AF_INET, SOCK_STREAM, 0); if (srv < 0) { ELOG("socket() failed\n"); stlink_close(sl); return (1); } int32_t one = 1; setsockopt(srv, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one)); struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; if (inet_pton(AF_INET, bind_addr, &addr.sin_addr) != 1) { ELOG("Invalid bind address: %s\n", bind_addr); close(srv); stlink_close(sl); return (1); } addr.sin_port = htons((uint16_t)port); if (bind(srv, (struct sockaddr *)&addr, sizeof(addr)) < 0 || listen(srv, 1) < 0) { ELOG("Failed to bind/listen on %s:%d\n", bind_addr, port); close(srv); stlink_close(sl); return (1); } ILOG("Listening on %s:%d\n", bind_addr, port); while (!stop_requested) { struct sockaddr_in cli; socklen_t clilen = sizeof(cli); int32_t fd = (int32_t)accept(srv, (struct sockaddr *)&cli, &clilen); if (fd < 0) { if (errno == EINTR && stop_requested) { break; } continue; } ILOG("Client connected from %s\n", inet_ntoa(cli.sin_addr)); stlink_remote_serve(sl, fd); close(fd); ILOG("Client disconnected\n"); } ILOG("Shutting down\n"); close(srv); stlink_close(sl); return (0); } stlink-1.9.0/src/st-trace/000077500000000000000000000000001526027543100153435ustar00rootroot00000000000000stlink-1.9.0/src/st-trace/trace.c000066400000000000000000000443361526027543100166170ustar00rootroot00000000000000/** ****************************************************************************** * @file : trace.c * @brief : Tool: st-trace * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @author : John Hall (simplerobot) * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #include "trace.h" // We use a global flag to allow communicating to the main thread from the // signal handler. static bool g_abort_trace = false; static void abort_trace() { g_abort_trace = true; } #if defined(_WIN32) BOOL WINAPI CtrlHandler(DWORD fdwCtrlType) { (void)fdwCtrlType; abort_trace(); return TRUE; } #endif int32_t stlink_trace_enable(stlink_t *sl, uint32_t frequency) { DLOG("*** stlink_trace_enable ***\n"); return (sl->backend->trace_enable(sl, frequency)); } int32_t stlink_trace_disable(stlink_t *sl) { DLOG("*** stlink_trace_disable ***\n"); return (sl->backend->trace_disable(sl)); } int32_t stlink_trace_read(stlink_t *sl, uint8_t *buf, uint32_t size) { return (sl->backend->trace_read(sl, buf, size)); } static void usage(void) { puts("st-trace - usage:"); puts(" -h, --help Print this help"); puts(" -V, --version Print this version"); puts(" -vXX, --verbose=XX Specify a specific verbosity level (0..99)"); puts(" -v, --verbose Specify a generally verbose logging"); puts(" -cXX, --clock=XX Specify the core frequency, optionally followed by"); puts(" k=kHz, m=MHz, or g=GHz (eg. --clock=180m)"); puts(" -tXX, --trace=XX Specify the trace frequency, optionally followed by"); puts(" k=kHz, m=MHz, or g=GHz (eg. --trace=2m)"); puts(" -n, --no-reset Do not reset board on connection"); puts(" -sXX, --serial=XX Use a specific serial number"); puts(" --remote=HOST[:PORT] Drive an ST-LINK served by st-server (best-effort on low-latency links)"); puts(" -f, --force Ignore most initialization errors"); } static bool parse_frequency(char* text, uint32_t* result) { if(text == NULL) { ELOG("Invalid frequency.\n"); return false; } char* suffix = text; double value = strtod(text, &suffix); if(value == 0.0) { ELOG("Invalid frequency.\n"); return false; } double scale = 1.0; if(*suffix == 'k') scale = 1000; else if(*suffix == 'm') scale = 1000000; else if(*suffix == 'g') scale = 1000000000; else if(*suffix != '\0') { ELOG("Unknown frequency suffix '%s'.\n", suffix); return false; } value *= scale; if(value <= 0 || value > 0xFFFFFFFFul) { ELOG("Frequency is out of valid range.\n"); return false; } *result = (uint32_t) value; return true; } bool parse_options(int32_t argc, char **argv, st_settings_t *settings) { static struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"version", no_argument, NULL, 'V'}, {"verbose", optional_argument, NULL, 'v'}, {"clock", required_argument, NULL, 'c'}, {"trace", required_argument, NULL, 't'}, {"no-reset", no_argument, NULL, 'n'}, {"serial", required_argument, NULL, 's'}, {"force", no_argument, NULL, 'f'}, {"remote", required_argument, NULL, REMOTE_OPTION}, {NULL, 0, NULL, 0} }; int32_t option_index = 0; int32_t c; bool error = false; settings->show_help = false; settings->show_version = false; settings->logging_level = DEFAULT_LOGGING_LEVEL; settings->core_frequency = 0; settings->trace_frequency = 0; settings->reset_board = true; settings->force = false; settings->serial_number = NULL; settings->remote = NULL; ugly_init(settings->logging_level); while ((c = getopt_long(argc, argv, "hVv::c:ns:f", long_options, &option_index)) != -1) { switch (c) { case 'h': settings->show_help = true; break; case 'V': settings->show_version = true; break; case 'v': if(optarg) { settings->logging_level = atoi(optarg); } else { settings->logging_level = DEBUG_LOGGING_LEVEL; } ugly_init(settings->logging_level); break; case 'c': if(!parse_frequency(optarg, &settings->core_frequency)) error = true; break; case 't': if(!parse_frequency(optarg, &settings->trace_frequency)) error = true; break; case 'n': settings->reset_board = false; break; case 'f': settings->force = true; break; case 's': settings->serial_number = optarg; break; case REMOTE_OPTION: settings->remote = optarg; break; case '?': error = true; break; default: ELOG("Unknown command line option: '%c' (0x%02x)\n", c, c); error = true; break; } } if(optind < argc) { while (optind < argc) { ELOG("Unknown command line argument: '%s'\n", argv[optind++]); } error = true; } if(error && !settings->force) return false; return true; } static stlink_t *stlink_connect(const st_settings_t *settings) { if(settings->remote) { return stlink_open_remote_str(settings->logging_level, settings->remote, CONNECT_HOT_PLUG, 0); } return stlink_open_usb(settings->logging_level, false, settings->serial_number, 0); } static bool enable_trace(stlink_t *stlink, const st_settings_t *settings, uint32_t trace_frequency) { if(stlink_force_debug(stlink)) { ELOG("Unable to debug device\n"); if(!settings->force) return false; } if(settings->reset_board && stlink_reset(stlink, RESET_SOFT_AND_HALT)) { ELOG("Unable to reset device\n"); if(!settings->force) return false; } stlink_write_debug32(stlink, STM32_REG_DHCSR, STM32_REG_DHCSR_DBGKEY | STM32_REG_DHCSR_C_DEBUGEN | STM32_REG_DHCSR_C_HALT); stlink_write_debug32(stlink, STM32_REG_DEMCR, STM32_REG_DEMCR_TRCENA); stlink_write_debug32(stlink, STM32_REG_CM3_FP_CTRL, STM32_REG_CM3_FP_CTRL_KEY); stlink_write_debug32(stlink, STM32_REG_DWT_FUNCTION0, 0); stlink_write_debug32(stlink, STM32_REG_DWT_FUNCTION1, 0); stlink_write_debug32(stlink, STM32_REG_DWT_FUNCTION2, 0); stlink_write_debug32(stlink, STM32_REG_DWT_FUNCTION3, 0); stlink_write_debug32(stlink, STM32_REG_DWT_CTRL, 0); stlink_write_debug32(stlink, STM32_REG_DBGMCU_CR, STM32_REG_DBGMCU_CR_DBG_SLEEP | STM32_REG_DBGMCU_CR_DBG_STOP | STM32_REG_DBGMCU_CR_DBG_STANDBY | STM32_REG_DBGMCU_CR_TRACE_IOEN | STM32_REG_DBGMCU_CR_TRACE_MODE_ASYNC); if(stlink_trace_enable(stlink, trace_frequency)) { ELOG("Unable to turn on tracing in stlink\n"); if(!settings->force) return false; } stlink_write_debug32(stlink, STM32_REG_TPI_CSPSR, STM32_REG_TPI_CSPSR_PORT_SIZE_1); if(settings->core_frequency) { uint32_t prescaler = settings->core_frequency / trace_frequency - 1; if(prescaler > STM32_REG_TPI_ACPR_MAX) { ELOG("Trace frequency prescaler %d out of range. Try setting a faster " "trace frequency.\n", prescaler); if(!settings->force) return false; } stlink_write_debug32(stlink, STM32_REG_TPI_ACPR, prescaler); // Set TPIU_ACPR clock divisor } stlink_write_debug32(stlink, STM32_REG_TPI_FFCR, STM32_REG_TPI_FFCR_TRIG_IN); stlink_write_debug32(stlink, STM32_REG_TPI_SPPR, STM32_REG_TPI_SPPR_SWO_NRZ); stlink_write_debug32(stlink, STM32_REG_ITM_LAR, STM32_REG_ITM_LAR_KEY); stlink_write_debug32(stlink, STM32_REG_ITM_TCC, 0x00000400); // Set sync counter stlink_write_debug32(stlink, STM32_REG_ITM_TCR, STM32_REG_ITM_TCR_TRACE_BUS_ID_1 | STM32_REG_ITM_TCR_TS_ENA | STM32_REG_ITM_TCR_ITM_ENA); stlink_write_debug32(stlink, STM32_REG_ITM_TER, STM32_REG_ITM_TER_PORTS_ALL); stlink_write_debug32(stlink, STM32_REG_ITM_TPR, STM32_REG_ITM_TPR_PORTS_ALL); stlink_write_debug32(stlink, STM32_REG_DWT_CTRL, 4 * STM32_REG_DWT_CTRL_NUM_COMP | STM32_REG_DWT_CTRL_CYC_TAP | 0xF * STM32_REG_DWT_CTRL_POST_INIT | 0xF * STM32_REG_DWT_CTRL_POST_PRESET | STM32_REG_DWT_CTRL_CYCCNT_ENA); stlink_write_debug32(stlink, STM32_REG_DEMCR, STM32_REG_DEMCR_TRCENA); uint32_t prescaler = 0; stlink_read_debug32(stlink, STM32_REG_TPI_ACPR, &prescaler); if(prescaler) { uint32_t system_clock_speed = (prescaler + 1) * trace_frequency; ILOG("Trace Port Interface configured to expect a %d Hz system clock.\n", system_clock_speed); } else { WLOG("Trace Port Interface not configured. Specify the system clock with " "a --clock=XX command\n"); WLOG("line option or set it in your device's clock initialization routine, " "such as with:\n"); WLOG(" TPI->ACPR = HAL_RCC_GetHCLKFreq() / %d - 1;\n", trace_frequency); } ILOG("Trace frequency set to %d Hz.\n", trace_frequency); return true; } static trace_state update_trace_idle(st_trace_t *trace, uint8_t c) { // Handle a trace byte when we are in the idle state. if(TRACE_OP_IS_TARGET_SOURCE(c)) return TRACE_STATE_TARGET_SOURCE; if(TRACE_OP_IS_SOURCE(c)) { uint8_t size = TRACE_OP_GET_SOURCE_SIZE(c); if(TRACE_OP_IS_SW_SOURCE(c)) { uint8_t addr = TRACE_OP_GET_SW_SOURCE_ADDR(c); if(!(trace->unknown_sources & (1 << addr))) WLOG("Unsupported source 0x%x size %d\n", addr, size); trace->unknown_sources |= (1 << addr); } if(size == 1) return TRACE_STATE_SKIP_1; if(size == 2) return TRACE_STATE_SKIP_2; if(size == 3) return TRACE_STATE_SKIP_4; } if(TRACE_OP_IS_LOCAL_TIME(c) || TRACE_OP_IS_GLOBAL_TIME(c)) { trace->count_time_packets++; return TRACE_OP_GET_CONTINUATION(c) ? TRACE_STATE_SKIP_FRAME : TRACE_STATE_IDLE; } if(TRACE_OP_IS_EXTENSION(c)) { return TRACE_OP_GET_CONTINUATION(c) ? TRACE_STATE_SKIP_FRAME : TRACE_STATE_IDLE; } if(TRACE_OP_IS_OVERFLOW(c)) trace->count_hw_overflow++; if(!(trace->unknown_opcodes[c / 8] & (1 << c % 8))) WLOG("Unknown opcode 0x%02x\n", c); trace->unknown_opcodes[c / 8] |= (1 << c % 8); trace->count_error++; return TRACE_OP_GET_CONTINUATION(c) ? TRACE_STATE_SKIP_FRAME : TRACE_STATE_IDLE; } static trace_state update_trace(st_trace_t *trace, uint8_t c) { trace->count_raw_bytes++; // Parse the input using a state machine. if(trace->state == TRACE_STATE_UNKNOWN) { if(TRACE_OP_IS_TARGET_SOURCE(c) || TRACE_OP_IS_LOCAL_TIME(c) || TRACE_OP_IS_GLOBAL_TIME(c)) trace->state = TRACE_STATE_IDLE; } switch (trace->state) { case TRACE_STATE_IDLE: return update_trace_idle(trace, c); case TRACE_STATE_TARGET_SOURCE: putchar(c); if(c == '\n') fflush(stdout); trace->count_target_data++; return TRACE_STATE_IDLE; case TRACE_STATE_SKIP_FRAME: return TRACE_OP_GET_CONTINUATION(c) ? TRACE_STATE_SKIP_FRAME : TRACE_STATE_IDLE; case TRACE_STATE_SKIP_4: return TRACE_STATE_SKIP_3; case TRACE_STATE_SKIP_3: return TRACE_STATE_SKIP_2; case TRACE_STATE_SKIP_2: return TRACE_STATE_SKIP_1; case TRACE_STATE_SKIP_1: return TRACE_STATE_IDLE; case TRACE_STATE_UNKNOWN: return TRACE_STATE_UNKNOWN; default: ELOG("Invalid state %d. This should never happen\n", trace->state); return TRACE_STATE_IDLE; } } static bool read_trace(stlink_t *stlink, st_trace_t *trace) { uint8_t buffer[STLINK_V3_TRACE_BUF_LEN]; int32_t length = stlink_trace_read(stlink, buffer, sizeof(buffer)); if(length < 0) { ELOG("Error reading trace (%d)\n", length); return false; } if(length == 0) { usleep(100); return true; } if(length == sizeof(buffer)) { if(trace->count_sw_overflow++) DLOG("Buffer overflow.\n"); else WLOG("Buffer overflow. Try using a slower trace frequency.\n"); trace->state = TRACE_STATE_UNKNOWN; } for(int32_t i = 0; i < length; i++) { trace->state = update_trace(trace, buffer[i]); } return true; } static void check_for_configuration_error(stlink_t *stlink, st_trace_t *trace, uint32_t trace_frequency) { // Only check configuration one time after the first 10 seconds of running. time_t elapsed_time_s = time(NULL) - trace->start_time; if(trace->configuration_checked || elapsed_time_s < 10) { return; } trace->configuration_checked = true; // Simple huristic to determine if we are configured poorly. bool error_no_data = (trace->count_raw_bytes < 100); bool error_low_data = (trace->count_time_packets < 10 && trace->count_target_data < 1000); bool error_bad_data = (trace->count_error > 1 || trace->unknown_sources > 0); bool error_dropped_data = (trace->count_sw_overflow > 0); if(!error_no_data && !error_low_data && !error_bad_data && !error_dropped_data) return; WLOG("****\n"); WLOG("We do not appear to be retrieving data from the stlink correctly.\n"); if(error_dropped_data) { WLOG("Try setting a slower trace frequency with the --trace=%d command " "line option.\n", trace_frequency / 2); } if(error_no_data || error_low_data || error_bad_data) { uint32_t prescaler = 0; stlink_read_debug32(stlink, STM32_REG_TPI_ACPR, &prescaler); if(prescaler) { uint32_t system_clock_speed = (prescaler + 1) * trace_frequency; WLOG("Verify the system clock is running at %d Hz.\n", system_clock_speed); } WLOG("Try specifying the system clock with the --clock=XX command line " "option.\n"); WLOG("Try setting the trace speed in your device's clock initialization " "routine:\n"); WLOG(" TPI->ACPR = HAL_RCC_GetHCLKFreq() / %d - 1;\n", trace_frequency); } WLOG("Diagnostic Information:\n"); WLOG("Raw Bytes: %d\n", trace->count_raw_bytes); WLOG("Target Data: %d\n", trace->count_target_data); WLOG("Time Packets: %d\n", trace->count_time_packets); WLOG("Hardware Overflow Count: %d\n", trace->count_hw_overflow); WLOG("Software Overflow Count: %d\n", trace->count_sw_overflow); WLOG("Errors: %d\n", trace->count_error); char buffer[1024]; memset(buffer, 0, sizeof(buffer)); uint32_t offset = 0; for(uint32_t i = 0; i <= 0xFF; i++) if(trace->unknown_opcodes[i / 8] & (1 << i % 8)) { uint32_t n = snprintf(buffer + offset, sizeof(buffer) - offset, "%02x, ", i); if(n >= sizeof(buffer) - offset) break; offset += n; } WLOG("Unknown Opcodes: %s\n", buffer); memset(buffer, 0, sizeof(buffer)); offset = 0; for(uint32_t i = 0; i < 32; i++) if(trace->unknown_sources & (1 << i)) { uint32_t n = snprintf(buffer + offset, sizeof(buffer) - offset, "%d, ", i); if(n >= sizeof(buffer) - offset) break; offset += n; } WLOG("Unknown Sources: %s\n", buffer); WLOG("Chip ID: 0x%04x\n", stlink->chip_id); WLOG("****\n"); } int32_t main(int32_t argc, char **argv) { #if defined(_WIN32) SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE); #else signal(SIGINT, &abort_trace); signal(SIGTERM, &abort_trace); signal(SIGSEGV, &abort_trace); signal(SIGPIPE, &abort_trace); #endif st_settings_t settings; if(!parse_options(argc, argv, &settings)) { usage(); return APP_RESULT_INVALID_PARAMS; } init_chipids(NULL); DLOG("show_help = %s\n", settings.show_help ? "true" : "false"); DLOG("show_version = %s\n", settings.show_version ? "true" : "false"); DLOG("logging_level = %d\n", settings.logging_level); DLOG("core_frequency = %d Hz\n", settings.core_frequency); DLOG("trace_frequency = %d Hz\n", settings.trace_frequency); DLOG("reset_board = %s\n", settings.reset_board ? "true" : "false"); DLOG("force = %s\n", settings.force ? "true" : "false"); DLOG("serial_number = %s\n", settings.serial_number ? settings.serial_number : "any"); if(settings.show_help) { usage(); return APP_RESULT_SUCCESS; } if(settings.show_version) { printf("v%s\n", STLINK_VERSION); return APP_RESULT_SUCCESS; } stlink_t *stlink = stlink_connect(&settings); if(!stlink) { ELOG("Unable to locate an stlink\n"); return APP_RESULT_STLINK_NOT_FOUND; } stlink->verbose = settings.logging_level; if(stlink->chip_id == STM32_CHIPID_UNKNOWN) { ELOG("Your stlink is not connected to a device\n"); if(!settings.force) return APP_RESULT_STLINK_MISSING_DEVICE; } if(!(stlink->version.flags & STLINK_F_HAS_TRACE)) { ELOG("Your stlink does not support tracing\n"); if(!settings.force) return APP_RESULT_STLINK_UNSUPPORTED_LINK; } if(!(stlink->chip_flags & CHIP_F_HAS_SWO_TRACING)) { const struct stlink_chipid_params *params = stlink_chipid_get_params(stlink->chip_id); ELOG("We do not support SWO output for device '%s'\n", params ? params->dev_type : ""); if(!settings.force) return APP_RESULT_STLINK_UNSUPPORTED_DEVICE; } uint32_t trace_frequency = settings.trace_frequency; if(!trace_frequency) trace_frequency = STLINK_DEFAULT_TRACE_FREQUENCY; uint32_t max_trace_freq = stlink->max_trace_freq; uint32_t min_trace_freq = 0; if(settings.core_frequency != 0) { if(max_trace_freq > settings.core_frequency / 5) max_trace_freq = settings.core_frequency / 5; min_trace_freq = settings.core_frequency / (STM32_REG_TPI_ACPR_MAX + 1); } if(trace_frequency > max_trace_freq || trace_frequency < min_trace_freq) { ELOG("Invalid trace frequency %d (min %d max %d)\n", trace_frequency, min_trace_freq, max_trace_freq); if(!settings.force) return APP_RESULT_UNSUPPORTED_TRACE_FREQUENCY; } if(!enable_trace(stlink, &settings, trace_frequency)) { ELOG("Unable to enable trace mode\n"); if(!settings.force) return APP_RESULT_STLINK_STATE_ERROR; } ILOG("Reading Trace\n"); st_trace_t trace; memset(&trace, 0, sizeof(trace)); trace.start_time = time(NULL); if(stlink_run(stlink, RUN_NORMAL)) { ELOG("Unable to run device\n"); if(!settings.force) return APP_RESULT_STLINK_STATE_ERROR; } while (!g_abort_trace && read_trace(stlink, &trace)) { check_for_configuration_error(stlink, &trace, trace_frequency); } stlink_trace_disable(stlink); stlink_close(stlink); return APP_RESULT_SUCCESS; } stlink-1.9.0/src/st-trace/trace.h000066400000000000000000000073651526027543100166250ustar00rootroot00000000000000/** ****************************************************************************** * @file : trace.h * @brief : Tool: st-trace * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @author : John Hall (simplerobot) * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #ifndef TRACE_H #define TRACE_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DEFAULT_LOGGING_LEVEL 50 #define DEBUG_LOGGING_LEVEL 100 #define REMOTE_OPTION 0x100 /* long-only option id for --remote */ #define APP_RESULT_SUCCESS 0 #define APP_RESULT_INVALID_PARAMS 1 #define APP_RESULT_STLINK_NOT_FOUND 2 #define APP_RESULT_STLINK_MISSING_DEVICE 3 #define APP_RESULT_STLINK_UNSUPPORTED_DEVICE 4 #define APP_RESULT_STLINK_UNSUPPORTED_LINK 5 #define APP_RESULT_UNSUPPORTED_TRACE_FREQUENCY 6 #define APP_RESULT_STLINK_STATE_ERROR 7 // See D4.2 of https://developer.arm.com/documentation/ddi0403/ed/ #define TRACE_OP_IS_OVERFLOW(c) ((c) == 0x70) #define TRACE_OP_IS_LOCAL_TIME(c) (((c)&0x0f) == 0x00 && ((c)&0x70) != 0x00) #define TRACE_OP_IS_EXTENSION(c) (((c)&0x0b) == 0x08) #define TRACE_OP_IS_GLOBAL_TIME(c) (((c)&0xdf) == 0x94) #define TRACE_OP_IS_SOURCE(c) (((c)&0x03) != 0x00) #define TRACE_OP_IS_SW_SOURCE(c) (((c)&0x03) != 0x00 && ((c)&0x04) == 0x00) #define TRACE_OP_IS_HW_SOURCE(c) (((c)&0x03) != 0x00 && ((c)&0x04) == 0x04) #define TRACE_OP_IS_TARGET_SOURCE(c) ((c) == 0x01) #define TRACE_OP_GET_CONTINUATION(c) ((c)&0x80) #define TRACE_OP_GET_SOURCE_SIZE(c) ((c)&0x03) #define TRACE_OP_GET_SW_SOURCE_ADDR(c) ((c) >> 3) typedef struct { bool show_help; bool show_version; int32_t logging_level; uint32_t core_frequency; uint32_t trace_frequency; bool reset_board; bool force; char *serial_number; char *remote; } st_settings_t; // We use a simple state machine to parse the trace data. typedef enum { TRACE_STATE_UNKNOWN, TRACE_STATE_IDLE, TRACE_STATE_TARGET_SOURCE, TRACE_STATE_SKIP_FRAME, TRACE_STATE_SKIP_4, TRACE_STATE_SKIP_3, TRACE_STATE_SKIP_2, TRACE_STATE_SKIP_1, } trace_state; typedef struct { time_t start_time; bool configuration_checked; trace_state state; uint32_t count_raw_bytes; uint32_t count_target_data; uint32_t count_time_packets; uint32_t count_hw_overflow; uint32_t count_sw_overflow; uint32_t count_error; uint8_t unknown_opcodes[256 / 8]; uint32_t unknown_sources; } st_trace_t; int32_t stlink_trace_enable(stlink_t* sl, uint32_t frequency); int32_t stlink_trace_disable(stlink_t* sl); int32_t stlink_trace_read(stlink_t* sl, uint8_t* buf, uint32_t size); static void usage(void); static bool parse_frequency(char* text, uint32_t* result); bool parse_options(int32_t argc, char **argv, st_settings_t *settings); static stlink_t *stlink_connect(const st_settings_t *settings); static bool enable_trace(stlink_t *stlink, const st_settings_t *settings, uint32_t trace_frequency); static trace_state update_trace_idle(st_trace_t *trace, uint8_t c); static trace_state update_trace(st_trace_t *trace, uint8_t c); static bool read_trace(stlink_t *stlink, st_trace_t *trace); static void check_for_configuration_error(stlink_t *stlink, st_trace_t *trace, uint32_t trace_frequency); #endif // TRACE_Hstlink-1.9.0/src/st-util/000077500000000000000000000000001526027543100152225ustar00rootroot00000000000000stlink-1.9.0/src/st-util/gdb-remote.c000066400000000000000000000100101526027543100174030ustar00rootroot00000000000000/** ****************************************************************************** * @file : gdb-remote.c * @brief : Tool: st-util * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @author : Peter Zotov (whitequark) * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #include "gdb-remote.h" static const char hex[] = "0123456789abcdef"; int32_t gdb_send_packet(int32_t fd, char* data) { uint32_t data_length = (uint32_t) strlen(data); int32_t length = data_length + 4; char* packet = malloc(length); // '$' data (hex) '#' cksum (hex) memset(packet, 0, length); packet[0] = '$'; uint8_t cksum = 0; for(uint32_t i = 0; i < data_length; i++) { packet[i + 1] = data[i]; cksum += data[i]; } packet[length - 3] = '#'; packet[length - 2] = hex[cksum >> 4]; packet[length - 1] = hex[cksum & 0xf]; while (1) { if(write(fd, packet, length) != length) { free(packet); return (-2); } char ack; if(read(fd, &ack, 1) != 1) { free(packet); return (-2); } if(ack == '+') { free(packet); return (0); } } } #define ALLOC_STEP 1024 int32_t gdb_recv_packet(int32_t fd, char** buffer) { uint32_t packet_size = ALLOC_STEP + 1, packet_idx = 0; uint8_t cksum = 0; char recv_cksum[3] = {0}; char* packet_buffer = malloc(packet_size); uint32_t state; if(packet_buffer == NULL) { return (-2); } start: state = 0; packet_idx = 0; /* * 0: waiting $ * 1: data, waiting # * 2: cksum 1 * 3: cksum 2 * 4: fin */ char c; while (state != 4) { if(read(fd, &c, 1) != 1) { free(packet_buffer); return (-2); } switch (state) { case 0: if(c != '$') { /* ignore */ } else { state = 1; } break; case 1: if(c == '#') { state = 2; } else { packet_buffer[packet_idx++] = c; cksum += c; if(packet_idx == packet_size) { packet_size += ALLOC_STEP; void* p = realloc(packet_buffer, packet_size); if(p != NULL) { packet_buffer = p; } else { free(packet_buffer); return (-2); } } } break; case 2: recv_cksum[0] = c; state = 3; break; case 3: recv_cksum[1] = c; state = 4; break; } } uint8_t recv_cksum_int = strtoul(recv_cksum, NULL, 16); if(recv_cksum_int != cksum) { char nack = '-'; if(write(fd, &nack, 1) != 1) { free(packet_buffer); return (-2); } goto start; } else { char ack = '+'; if(write(fd, &ack, 1) != 1) { free(packet_buffer); return (-2); } } packet_buffer[packet_idx] = 0; *buffer = packet_buffer; return (packet_idx); } /* * Here we skip any characters which are not \x03, GDB interrupt. * As we use the mode with ACK, in a (very unlikely) situation of a packet lost * because of this skipping, it will be resent anyway. */ int32_t gdb_check_for_interrupt(int32_t fd) { struct pollfd pfd; pfd.fd = fd; pfd.events = POLLIN; if(poll(&pfd, 1, 0) != 0) { char c; if(read(fd, &c, 1) != 1) { return (-2); } if(c == '\x03') { return (1); // ^C } } return (0); } stlink-1.9.0/src/st-util/gdb-remote.h000066400000000000000000000017251526027543100174250ustar00rootroot00000000000000/** ****************************************************************************** * @file : gdb-remote.ch * @brief : Tool: st-util * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @author : Peter Zotov (whitequark) * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #ifndef GDB_REMOTE_H #define GDB_REMOTE_H #include #include #include #if defined(_WIN32) #include #include #else #include #include #endif // _WIN32 int32_t gdb_send_packet(int32_t fd, char* data); int32_t gdb_recv_packet(int32_t fd, char** buffer); int32_t gdb_check_for_interrupt(int32_t fd); #endif // GDB_REMOTE_H stlink-1.9.0/src/st-util/gdb-server.c000066400000000000000000001554071526027543100174420ustar00rootroot00000000000000/** ****************************************************************************** * @file : gdb-server.c * @brief : Tool: st-util * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @author : Peter Zotov (whitequark) * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #include "gdb-server.h" #include "gdb-remote.h" #include "memory-map.h" #include "semihosting.h" #define FLASH_BASE 0x08000000 // Semihosting doesn't have a short option, we define a value to identify it #define SEMIHOSTING_OPTION 128 #define SERIAL_OPTION 127 #define REMOTE_OPTION 126 // always update the FLASH_PAGE before each use, by calling stlink_calculate_pagesize #define FLASH_PAGE (sl->flash_pgsz) static stlink_t *connected_stlink = NULL; #if defined(_WIN32) #define close_socket win32_close_socket #define IS_SOCK_VALID(__sock) ((__sock) != INVALID_SOCKET) #else #define close_socket close #define SOCKET int #define IS_SOCK_VALID(__sock) ((__sock) > 0) #endif static const char hex[] = "0123456789abcdef"; typedef struct _st_state_t { // things from command line, bleh int32_t logging_level; int32_t listen_port; int32_t persistent; enum connect_type connect_mode; int32_t freq; char serialnumber[STLINK_SERIAL_BUFFER_SIZE]; bool semihosting; const char* current_memory_map; const char* remote; // --remote=host[:port]: drive an ST-LINK on another machine } st_state_t; int32_t serve(stlink_t *sl, st_state_t *st); char* make_memory_map(stlink_t *sl); static void init_cache(stlink_t *sl); static void _cleanup() { if(connected_stlink) { // Switch back to mass storage mode before closing stlink_run(connected_stlink, RUN_NORMAL); stlink_exit_debug_mode(connected_stlink); stlink_close(connected_stlink); } } static void cleanup(int32_t signum) { printf("Receive signal %i. Exiting...\n", signum); _cleanup(); // if asked to gracefully terminate if(signum == SIGTERM){ // return 0 exit(0); }else{ exit(1); } } #if defined(_WIN32) BOOL WINAPI CtrlHandler(DWORD fdwCtrlType) { printf("Receive signal %i. Exiting...\r\n", (int32_t) fdwCtrlType); _cleanup(); return FALSE; } #endif int32_t parse_options(int32_t argc, char** argv, st_state_t *st) { static struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"verbose", optional_argument, NULL, 'v'}, {"listen_port", required_argument, NULL, 'p'}, {"multi", optional_argument, NULL, 'm'}, {"no-reset", optional_argument, NULL, 'n'}, {"hot-plug", optional_argument, NULL, 'n'}, {"connect-under-reset", optional_argument, NULL, 'u'}, {"freq", required_argument, NULL, 'F'}, {"version", no_argument, NULL, 'V'}, {"semihosting", no_argument, NULL, SEMIHOSTING_OPTION}, {"serial", required_argument, NULL, SERIAL_OPTION}, {"remote", required_argument, NULL, REMOTE_OPTION}, {NULL, 0, NULL, 0} }; const char * help_str = "%s - usage:\n\n" " -h, --help\t\tPrint this help\n" " -V, --version\t\tPrint the version\n" " -vXX, --verbose=XX\tSpecify a specific verbosity level (0...99)\n" " -v, --verbose\t\tSpecify generally verbose logging\n" " -p 4242, --listen_port=1234\n" "\t\t\tSet the gdb server listen port. " "(default port: " STRINGIFY(DEFAULT_GDB_LISTEN_PORT) ")\n" " -m, --multi\n" "\t\t\tSet gdb server to extended mode.\n" "\t\t\tst-util will continue listening for connections after disconnect.\n" " -n, --no-reset, --hot-plug\n" "\t\t\tDo not reset board on connection.\n" " -u, --connect-under-reset\n" "\t\t\tConnect to the board before executing any instructions.\n" " -F 1800k, --freq=1M\n" "\t\t\tSet the frequency of the SWD/JTAG interface.\n" " --semihosting\n" "\t\t\tEnable semihosting support.\n" " --serial \n" "\t\t\tUse a specific serial number.\n" " --remote \n" "\t\t\tDrive an ST-LINK served by st-server on another machine.\n" "\n" "The STLINK device to use can be specified in the environment\n" "variable STLINK_DEVICE on the format :.\n" "\n" ; int option_index = 0; int32_t c; int32_t q; while ((c = getopt_long(argc, argv, "hv::p:mnuF:V", long_options, &option_index)) != -1) switch (c) { case 0: break; case 'h': printf(help_str, argv[0]); exit(EXIT_SUCCESS); break; case 'v': if(optarg) { st->logging_level = atoi(optarg); } else { st->logging_level = DEBUG_LOGGING_LEVEL; } break; case 'p': if(sscanf(optarg, "%i", &q) != 1) { fprintf(stderr, "Invalid port %s\n", optarg); exit(EXIT_FAILURE); } else if(q < 0) { fprintf(stderr, "Can't use a negative port to listen on: %d\n", q); exit(EXIT_FAILURE); } st->listen_port = q; break; case 'm': st->persistent = true; break; case 'n': st->connect_mode = CONNECT_HOT_PLUG; break; case 'u': st->connect_mode = CONNECT_UNDER_RESET; break; case 'F': st->freq = arg_parse_freq(optarg); if(st->freq < 0) { fprintf(stderr, "Can't parse a frequency: %s\n", optarg); exit(EXIT_FAILURE); } break; case 'V': printf("v%s\n", STLINK_VERSION); exit(EXIT_SUCCESS); case SEMIHOSTING_OPTION: st->semihosting = true; break; case SERIAL_OPTION: printf("use serial %s\n", optarg); snprintf(st->serialnumber, STLINK_SERIAL_BUFFER_SIZE, "%s", optarg); break; case REMOTE_OPTION: st->remote = optarg; break; } if(optind < argc) { printf("non-option ARGV-elements: "); while (optind < argc) { printf("%s ", argv[optind++]); } printf("\n"); } return (0); } int32_t main(int32_t argc, char** argv) { stlink_t *sl = NULL; st_state_t state; memset(&state, 0, sizeof(state)); // set defaults ... state.logging_level = DEFAULT_LOGGING_LEVEL; state.listen_port = DEFAULT_GDB_LISTEN_PORT; state.connect_mode = CONNECT_NORMAL; // by default, reset board parse_options(argc, argv, &state); printf("st-util %s\n", STLINK_VERSION); init_chipids(NULL); if(state.remote) { sl = stlink_open_remote_str(state.logging_level, state.remote, state.connect_mode, state.freq); } else { sl = stlink_open_usb(state.logging_level, state.connect_mode, state.serialnumber, state.freq); } if(sl == NULL) { return (1); } if(sl->chip_id == STM32_CHIPID_UNKNOWN) { ELOG("Unsupported Target (Chip ID is %#010x, Core ID is %#010x).\n", sl->chip_id, sl->core_id); return (1); } sl->verbose = 0; connected_stlink = sl; #if defined(_WIN32) SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE); #else signal(SIGINT, &cleanup); signal(SIGTERM, &cleanup); signal(SIGSEGV, &cleanup); #endif DLOG("Chip ID is %#010x, Core ID is %#08x.\n", sl->chip_id, sl->core_id); #if defined(_WIN32) WSADATA wsadata; if(WSAStartup(MAKEWORD(2, 2), &wsadata) != 0) { goto winsock_error; } #endif do { // don't go beserk if serve() returns with error if(serve(sl, &state)) { usleep (1 * 1000); } sl = connected_stlink; // in case serve() changed the connection stlink_run(sl, RUN_NORMAL); // continue } while (state.persistent); #if defined(_WIN32) winsock_error: WSACleanup(); #endif // switch back to mass storage mode before closing stlink_exit_debug_mode(sl); stlink_close(sl); return (0); } static const char* const target_description = "" "" "" " arm" " none" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " ""; char* make_memory_map(stlink_t *sl) { // this will be freed in serve() const uint32_t sz = 4096; char* map = malloc(sz); map[0] = '\0'; if(sl->chip_id == STM32_CHIPID_F4 || sl->chip_id == STM32_CHIPID_F446 || sl->chip_id == STM32_CHIPID_F411xx) { snprintf(map, sz, memory_map_template_F4, sl->sram_size); } else if(sl->chip_id == STM32_CHIPID_F4_DE) { snprintf(map, sz, "%s", memory_map_template_F4_DE); } else if(sl->core_id == STM32_CORE_ID_M7F_SWD) { snprintf(map, sz, memory_map_template_F7, sl->sram_size); } else if(sl->chip_id == STM32_CHIPID_H74xxx) { snprintf(map, sz, memory_map_template_H7, sl->flash_size, sl->flash_pgsz); } else if(sl->chip_id == STM32_CHIPID_F4_HD) { snprintf(map, sz, "%s", memory_map_template_F4_HD); } else if(sl->chip_id == STM32_CHIPID_F2) { snprintf(map, sz, memory_map_template_F2, sl->flash_size, sl->sram_size, sl->flash_size - 0x20000, sl->sys_base, sl->sys_size); } else if((sl->chip_id == STM32_CHIPID_L4) || (sl->chip_id == STM32_CHIPID_L43x_L44x) || (sl->chip_id == STM32_CHIPID_L45x_L46x)) { snprintf(map, sz, memory_map_template_L4, sl->flash_size, sl->flash_size); } else if(sl->chip_id == STM32_CHIPID_L496x_L4A6x) { snprintf(map, sz, memory_map_template_L496, sl->flash_size, sl->flash_size); } else if(sl->chip_id == STM32_CHIPID_H72x) { snprintf(map, sz, memory_map_template_H72x3x, sl->flash_size, sl->flash_pgsz); } else { snprintf(map, sz, memory_map_template, sl->flash_size, sl->sram_size, sl->flash_size, sl->flash_pgsz, sl->sys_base, sl->sys_size); } return (map); } #define DATA_WATCH_NUM 4 enum watchfun { WATCHDISABLED = 0, WATCHREAD = 5, WATCHWRITE = 6, WATCHACCESS = 7 }; struct code_hw_watchpoint { stm32_addr_t addr; uint8_t mask; enum watchfun fun; }; static struct code_hw_watchpoint data_watches[DATA_WATCH_NUM]; static void init_data_watchpoints(stlink_t *sl) { uint32_t data; DLOG("init watchpoints\n"); // set TRCENA in debug command to turn on DWT unit stlink_read_debug32(sl, STM32_REG_CM3_DEMCR, &data); data |= STM32_REG_CM3_DEMCR_TRCENA; stlink_write_debug32(sl, STM32_REG_CM3_DEMCR, data); // make sure all watchpoints are cleared for(int32_t i = 0; i < DATA_WATCH_NUM; i++) { data_watches[i].fun = WATCHDISABLED; stlink_write_debug32(sl, STM32_REG_CM3_DWT_FUNn(i), 0); } } static int32_t add_data_watchpoint(stlink_t *sl, enum watchfun wf, stm32_addr_t addr, uint32_t len) { int32_t i = 0; uint32_t mask, dummy; // computer mask // find a free watchpoint // configure mask = -1; i = len; while (i) { i >>= 1; mask++; } if((mask != (uint32_t)-1) && (mask < 16)) { for(i = 0; i < DATA_WATCH_NUM; i++) // is this an empty slot ? if(data_watches[i].fun == WATCHDISABLED) { DLOG("insert watchpoint %d addr %x wf %u mask %u len %d\n", i, addr, wf, mask, len); data_watches[i].fun = wf; data_watches[i].addr = addr; data_watches[i].mask = mask; // insert comparator address stlink_write_debug32(sl, STM32_REG_CM3_DWT_COMPn(i), addr); // insert mask stlink_write_debug32(sl, STM32_REG_CM3_DWT_MASKn(i), mask); // insert function stlink_write_debug32(sl, STM32_REG_CM3_DWT_FUNn(i), wf); // just to make sure the matched bit is clear ! stlink_read_debug32(sl, STM32_REG_CM3_DWT_FUNn(i), &dummy); return (0); } } DLOG("failure: add watchpoints addr %x wf %u len %u\n", addr, wf, len); return (-1); } static int32_t delete_data_watchpoint(stlink_t *sl, stm32_addr_t addr) { int32_t i; for(i = 0; i < DATA_WATCH_NUM; i++) { if((data_watches[i].addr == addr) && (data_watches[i].fun != WATCHDISABLED)) { DLOG("delete watchpoint %d addr %x\n", i, addr); data_watches[i].fun = WATCHDISABLED; stlink_write_debug32(sl, STM32_REG_CM3_DWT_FUNn(i), 0); return (0); } } DLOG("failure: delete watchpoint addr %x\n", addr); return (-1); } static int32_t code_break_num; static int32_t code_lit_num; static int32_t code_break_rev; #define CODE_BREAK_NUM_MAX 15 #define CODE_BREAK_LOW 0x01 #define CODE_BREAK_HIGH 0x02 #define CODE_BREAK_REMAP 0x04 #define CODE_BREAK_REV_V1 0x00 #define CODE_BREAK_REV_V2 0x01 struct code_hw_breakpoint { stm32_addr_t addr; int32_t type; }; static struct code_hw_breakpoint code_breaks[CODE_BREAK_NUM_MAX]; static void init_code_breakpoints(stlink_t *sl) { uint32_t val; memset(sl->q_buf, 0, 4); stlink_write_debug32(sl, STM32_REG_CM3_FP_CTRL, 0x03 /* KEY | ENABLE */); stlink_read_debug32(sl, STM32_REG_CM3_FP_CTRL, &val); code_break_num = ((val >> 4) & 0xf); code_lit_num = ((val >> 8) & 0xf); code_break_rev = ((val >> 28) & 0xf); ILOG("Found %i hw breakpoint registers\n", code_break_num); stlink_read_debug32(sl, STM32_REG_CM3_CPUID, &val); if(((val>>4) & 0xFFF) == 0xC27) { // Cortex-M7 can have locked to write FP_* registers // IHI0029D, p. 48, Lock Access Register stlink_write_debug32(sl, STM32_REG_CM7_FP_LAR, STM32_REG_CM7_FP_LAR_KEY); } for(int32_t i = 0; i < code_break_num; i++) { code_breaks[i].type = 0; stlink_write_debug32(sl, STM32_REG_CM3_FP_COMPn(i), 0); } } static int32_t has_breakpoint(stm32_addr_t addr) { for(int32_t i = 0; i < code_break_num; i++) if(code_breaks[i].addr == addr) { return (1); } return (0); } static int32_t update_code_breakpoint(stlink_t *sl, stm32_addr_t addr, int32_t set) { uint32_t mask; int32_t type; stm32_addr_t fpb_addr; if(addr & 1) { ELOG("update_code_breakpoint: unaligned address %08x\n", addr); return (-1); } if(code_break_rev == CODE_BREAK_REV_V1) { type = (addr & 0x2) ? CODE_BREAK_HIGH : CODE_BREAK_LOW; fpb_addr = addr & 0x1FFFFFFC; } else { type = CODE_BREAK_REMAP; fpb_addr = addr; } int32_t id = -1; for(int32_t i = 0; i < code_break_num; i++) if(fpb_addr == code_breaks[i].addr || (set && code_breaks[i].type == 0)) { id = i; break; } if(id == -1) { if(set) return (-1); // free slot not found else return (0); // breakpoint is already removed } struct code_hw_breakpoint* bp = &code_breaks[id]; bp->addr = fpb_addr; if(set) bp->type |= type; else bp->type &= ~type; // DDI0403E, p. 759, FP_COMPn register description mask = ((bp->type&0x03) << 30) | bp->addr | 1; if(bp->type == 0) { DLOG("clearing hw break %d\n", id); stlink_write_debug32(sl, STM32_REG_CM3_FP_COMPn(id), 0); } else { DLOG("setting hw break %d at %08x (%d)\n", id, bp->addr, bp->type); DLOG("reg %08x \n", mask); stlink_write_debug32(sl, STM32_REG_CM3_FP_COMPn(id), mask); } return (0); } struct flash_block { stm32_addr_t addr; uint32_t length; uint8_t* data; struct flash_block* next; }; static struct flash_block* flash_root; static int32_t flash_add_block(stm32_addr_t addr, uint32_t length, stlink_t *sl) { if(addr < FLASH_BASE || addr + length > FLASH_BASE + sl->flash_size) { ELOG("flash_add_block: incorrect bounds\n"); return (-1); } stlink_calculate_pagesize(sl, addr); if(addr % FLASH_PAGE != 0 || length % FLASH_PAGE != 0) { ELOG("flash_add_block: unaligned block\n"); return (-1); } struct flash_block* new = malloc(sizeof(struct flash_block)); new->next = flash_root; new->addr = addr; new->length = length; new->data = malloc(length); memset(new->data, stlink_get_erased_pattern(sl), length); flash_root = new; return (0); } static int32_t flash_populate(stm32_addr_t addr, uint8_t* data, uint32_t length) { uint32_t fit_blocks = 0, fit_length = 0; for(struct flash_block* fb = flash_root; fb; fb = fb->next) { /* * Block: ------X------Y-------- * Data: a-----b * a--b * a-----------b * Block intersects with data, if: * a < Y && b > x */ uint32_t X = fb->addr, Y = fb->addr + fb->length; uint32_t a = addr, b = addr + length; if(a < Y && b > X) { // from start of the block uint32_t start = (a > X ? a : X) - X; uint32_t end = (b > Y ? Y : b) - X; memcpy(fb->data + start, data, end - start); fit_blocks++; fit_length += end - start; } } if(fit_blocks == 0) { ELOG("Unfit data block %08x -> %04x\n", addr, length); return (-1); } if(fit_length != length) { WLOG("data block %08x -> %04x truncated to %04x\n", addr, length, fit_length); WLOG("(this is not an error, just a GDB glitch)\n"); } return (0); } static int32_t flash_go(stlink_t *sl, st_state_t *st) { int32_t error = -1; int32_t ret; flash_loader_t fl; stlink_target_connect(sl, st->connect_mode); stlink_force_debug(sl); for(struct flash_block* fb = flash_root; fb; fb = fb->next) { ILOG("flash_erase: block %08x -> %04x\n", fb->addr, fb->length); for(stm32_addr_t page = fb->addr; page < fb->addr + fb->length; page += (uint32_t) FLASH_PAGE) { // update FLASH_PAGE stlink_calculate_pagesize(sl, page); ILOG("flash_erase: page %08x\n", page); ret = stlink_erase_flash_page(sl, page); if(ret) { goto error; } } } ret = stlink_flashloader_start(sl, &fl); if(ret) { goto error; } for(struct flash_block* fb = flash_root; fb; fb = fb->next) { ILOG("flash_do: block %08x -> %04x\n", fb->addr, fb->length); for(stm32_addr_t page = fb->addr; page < fb->addr + fb->length; page += (uint32_t) FLASH_PAGE) { uint32_t length = fb->length - (page - fb->addr); // update FLASH_PAGE stlink_calculate_pagesize(sl, page); ILOG("flash_do: page %08x\n", page); uint32_t len = (length > FLASH_PAGE) ? (uint32_t) FLASH_PAGE : length; ret = stlink_flashloader_write(sl, &fl, page, fb->data + (page - fb->addr), len); if(ret) { goto error; } } } stlink_flashloader_stop(sl, &fl); stlink_reset(sl, RESET_SOFT_AND_HALT); error = 0; error: for(struct flash_block* fb = flash_root, *next; fb; fb = next) { next = fb->next; free(fb->data); free(fb); } flash_root = NULL; return (error); } struct cache_level_desc { uint32_t nsets; uint32_t nways; uint32_t log2_nways; uint32_t width; }; struct cache_desc_t { uint32_t used; // minimal line size in bytes uint32_t dminline; uint32_t iminline; // last level of unification (uniprocessor) uint32_t louu; struct cache_level_desc icache[7]; struct cache_level_desc dcache[7]; }; static struct cache_desc_t cache_desc; // return the smallest R so that V <= (1 << R); not performance critical static uint32_t ceil_log2(uint32_t v) { uint32_t res; for(res = 0; (1U << res) < v; res++); return (res); } static void read_cache_level_desc(stlink_t *sl, struct cache_level_desc *desc) { uint32_t ccsidr; uint32_t log2_nsets; stlink_read_debug32(sl, STM32_REG_CM7_CCSIDR, &ccsidr); desc->nsets = ((ccsidr >> 13) & 0x3fff) + 1; desc->nways = ((ccsidr >> 3) & 0x1ff) + 1; desc->log2_nways = ceil_log2 (desc->nways); log2_nsets = ceil_log2 (desc->nsets); desc->width = 4 + (ccsidr & 7) + log2_nsets; ILOG("%08x LineSize: %u, ways: %u, sets: %u (width: %u)\n", ccsidr, 4 << (ccsidr & 7), desc->nways, desc->nsets, desc->width); } static void init_cache (stlink_t *sl) { uint32_t clidr; uint32_t ccr; uint32_t ctr; int32_t i; // Check have cache stlink_read_debug32(sl, STM32_REG_CM7_CTR, &ctr); if((ctr >> 29) != 0x04) { cache_desc.used = 0; return; } else cache_desc.used = 1; cache_desc.dminline = 4 << ((ctr >> 16) & 0x0f); cache_desc.iminline = 4 << (ctr & 0x0f); stlink_read_debug32(sl, STM32_REG_CM7_CLIDR, &clidr); cache_desc.louu = (clidr >> 27) & 7; stlink_read_debug32(sl, STM32_REG_CM7_CCR, &ccr); ILOG("Chip clidr: %08x, I-Cache: %s, D-Cache: %s\n", clidr, ccr & STM32_REG_CM7_CCR_IC ? "on" : "off", ccr & STM32_REG_CM7_CCR_DC ? "on" : "off"); ILOG(" cache: LoUU: %u, LoC: %u, LoUIS: %u\n", (clidr >> 27) & 7, (clidr >> 24) & 7, (clidr >> 21) & 7); ILOG(" cache: ctr: %08x, DminLine: %u bytes, IminLine: %u bytes\n", ctr, cache_desc.dminline, cache_desc.iminline); for(i = 0; i < 7; i++) { uint32_t ct = (clidr >> (3 * i)) & 0x07; cache_desc.dcache[i].width = 0; cache_desc.icache[i].width = 0; if(ct == 2 || ct == 3 || ct == 4) { // data stlink_write_debug32(sl, STM32_REG_CM7_CSSELR, i << 1); ILOG("D-Cache L%d: ", i); read_cache_level_desc(sl, &cache_desc.dcache[i]); } if(ct == 1 || ct == 3) { // instruction stlink_write_debug32(sl, STM32_REG_CM7_CSSELR, (i << 1) | 1); ILOG("I-Cache L%d: ", i); read_cache_level_desc(sl, &cache_desc.icache[i]); } } } static void cache_flush(stlink_t *sl, uint32_t ccr) { int32_t level; if(ccr & STM32_REG_CM7_CCR_DC) { for(level = cache_desc.louu - 1; level >= 0; level--) { struct cache_level_desc *desc = &cache_desc.dcache[level]; uint32_t addr; uint32_t max_addr = 1 << desc->width; uint32_t way_sh = 32 - desc->log2_nways; // D-cache clean by set-ways. for(addr = (level << 1); addr < max_addr; addr += cache_desc.dminline) { uint32_t way; for(way = 0; way < desc->nways; way++) { stlink_write_debug32(sl, STM32_REG_CM7_DCCSW, addr | (way << way_sh)); } } } } // invalidate all I-cache to oPU if(ccr & STM32_REG_CM7_CCR_IC) { stlink_write_debug32(sl, STM32_REG_CM7_ICIALLU, 0); } } static int32_t cache_modified; static void cache_change(stm32_addr_t start, uint32_t count) { if(count == 0) { return; } (void)start; cache_modified = 1; } static void cache_sync(stlink_t *sl) { uint32_t ccr; if(!cache_desc.used) { return; } if(!cache_modified) { return; } cache_modified = 0; stlink_read_debug32(sl, STM32_REG_CM7_CCR, &ccr); if(ccr & (STM32_REG_CM7_CCR_IC | STM32_REG_CM7_CCR_DC)) { cache_flush(sl, ccr); } } static uint32_t unhexify(const char *in, char *out, uint32_t out_count) { uint32_t i; uint32_t c; for(i = 0; i < out_count; i++) { if(sscanf(in + (2 * i), "%02x", &c) != 1) { return (i); } out[i] = (char)c; } return (i); } int32_t serve(stlink_t *sl, st_state_t *st) { SOCKET sock = socket(AF_INET, SOCK_STREAM, 0); if(!IS_SOCK_VALID(sock)) { perror("socket"); return (1); } uint32_t val = 1; setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val)); struct sockaddr_in serv_addr; memset(&serv_addr, 0, sizeof(struct sockaddr_in)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons(st->listen_port); if(bind(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) { perror("bind"); close_socket(sock); return (1); } if(listen(sock, 5) < 0) { perror("listen"); close_socket(sock); return (1); } ILOG("Listening at *:%d...\n", st->listen_port); SOCKET client = accept(sock, NULL, NULL); // signal (SIGINT, SIG_DFL); if(!IS_SOCK_VALID(client)) { perror("accept"); close_socket(sock); return (1); } close_socket(sock); uint32_t chip_id = sl->chip_id; stlink_target_connect(sl, st->connect_mode); stlink_force_debug(sl); if(sl->chip_id != chip_id) { WLOG("Target has changed!\n"); } init_code_breakpoints(sl); init_data_watchpoints(sl); init_cache(sl); st->current_memory_map = make_memory_map(sl); ILOG("GDB connected.\n"); /* * To allow resetting the chip from GDB it is required to emulate attaching * and detaching to target. */ uint32_t attached = 1; // if a critical error is detected, break from the loop int32_t critical_error = 0; int32_t ret; while (1) { ret = 0; char* packet; int32_t status = gdb_recv_packet(client, &packet); if(status < 0) { ELOG("cannot recv: %d\n", status); close_socket(client); return (1); } DLOG("recv: %s\n", packet); char* reply = NULL; struct stlink_reg regp; switch (packet[0]) { case 'q': { if(packet[1] == 'P' || packet[1] == 'C' || packet[1] == 'L') { reply = strdup(""); break; } char *separator = strstr(packet, ":"), *params = ""; if(separator == NULL) { separator = packet + strlen(packet); } else { params = separator + 1; } uint32_t queryNameLength = (uint32_t) (separator - &packet[1]); char* queryName = calloc(1, queryNameLength + 1); memcpy(queryName, &packet[1], queryNameLength); DLOG("query: %s;%s\n", queryName, params); if(!strcmp(queryName, "Supported")) { reply = strdup("PacketSize=3fff;qXfer:memory-map:read+;qXfer:features:read+"); } else if(!strcmp(queryName, "Xfer")) { char *type, *op, *__s_addr, *s_length; char *tok = params; char *annex __attribute__((unused)); type = strsep(&tok, ":"); op = strsep(&tok, ":"); annex = strsep(&tok, ":"); __s_addr = strsep(&tok, ","); s_length = tok; uint32_t addr = (uint32_t) strtoul(__s_addr, NULL, 16), length = (uint32_t) strtoul(s_length, NULL, 16); DLOG("Xfer: type:%s;op:%s;annex:%s;addr:%d;length:%d\n", type, op, annex, addr, length); const char* data; if(strcmp(op, "read")) { data = NULL; } else if(!strcmp(type, "memory-map")) { data = st->current_memory_map; } else if(!strcmp(type, "features")) { data = target_description; } else { data = NULL; } if(data) { uint32_t data_length = (uint32_t) strlen(data); if(addr + length > data_length) { length = data_length - addr; } if(length == 0) { reply = strdup("l"); } else { reply = calloc(1, length + 2); reply[0] = 'm'; memcpy(&reply[1], data, length); } } } else if(!strncmp(queryName, "Rcmd,", 4)) { // Rcmd uses the wrong separator separator = strstr(packet, ","); params = ""; if(separator == NULL) { separator = packet + strlen(packet); } else { params = separator + 1; } uint32_t hex_len = (uint32_t) strlen(params); uint32_t alloc_size = (hex_len / 2) + 1; uint32_t cmd_len; char *cmd = malloc(alloc_size); if(cmd == NULL) { DLOG("Rcmd unhexify allocation error\n"); break; } cmd_len = unhexify(params, cmd, alloc_size - 1); cmd[cmd_len] = 0; DLOG("unhexified Rcmd: '%s'\n", cmd); if(!strncmp(cmd, "resume", 6)) { // resume DLOG("Rcmd: resume\n"); cache_sync(sl); ret = stlink_run(sl, RUN_NORMAL); if(ret) { DLOG("Rcmd: resume failed\n"); reply = strdup("E00"); } else { reply = strdup("OK"); } } else if(!strncmp(cmd, "halt", 4)) { // halt ret = stlink_force_debug(sl); if(ret) { DLOG("Rcmd: halt failed\n"); reply = strdup("E00"); } else { reply = strdup("OK"); DLOG("Rcmd: halt\n"); } } else if(!strncmp(cmd, "jtag_reset", 10)) { // jtag_reset reply = strdup("OK"); ret = stlink_reset(sl, RESET_HARD); if(ret) { DLOG("Rcmd: jtag_reset failed with jtag_reset\n"); reply = strdup("E00"); } ret = stlink_force_debug(sl); if(ret) { DLOG("Rcmd: jtag_reset failed with force_debug\n"); reply = strdup("E00"); } if(strcmp(reply, "E00")) { // no errors have been found DLOG("Rcmd: jtag_reset\n"); } } else if(!strncmp(cmd, "reset", 5)) { // reset ret = stlink_force_debug(sl); if(ret) { DLOG("Rcmd: reset failed with force_debug\n"); reply = strdup("E00"); } ret = stlink_reset(sl, RESET_SOFT_AND_HALT); if(ret) { DLOG("Rcmd: reset failed with reset\n"); reply = strdup("E00"); } init_code_breakpoints(sl); init_data_watchpoints(sl); if(reply == NULL) { reply = strdup("OK"); DLOG("Rcmd: reset\n"); } } else if(!strncmp(cmd, "semihosting ", 12)) { DLOG("Rcmd: got semihosting cmd '%s'", cmd); char *arg = cmd + 12; while (isspace(*arg)) { arg++; } // skip whitespaces if(!strncmp(arg, "enable", 6) || !strncmp(arg, "1", 1)) { st->semihosting = true; reply = strdup("OK"); } else if(!strncmp(arg, "disable", 7) || !strncmp(arg, "0", 1)) { st->semihosting = false; reply = strdup("OK"); } else { DLOG("Rcmd: unknown semihosting arg: '%s'\n", arg); } } else { DLOG("Rcmd: %s\n", cmd); } free(cmd); } if(reply == NULL) { reply = strdup(""); } free(queryName); break; } case 'v': { char *params = NULL; char *cmdName = strtok_r(packet, ":;", ¶ms); cmdName++; // vCommand -> Command if(!strcmp(cmdName, "FlashErase")) { char *__s_addr, *s_length; char *tok = params; __s_addr = strsep(&tok, ","); s_length = tok; uint32_t addr = (uint32_t) strtoul(__s_addr, NULL, 16), length = (uint32_t) strtoul(s_length, NULL, 16); DLOG("FlashErase: addr:%08x,len:%04x\n", addr, length); if(flash_add_block(addr, length, sl) < 0) { reply = strdup("E00"); } else { reply = strdup("OK"); } } else if(!strcmp(cmdName, "FlashWrite")) { char *__s_addr, *data; char *tok = params; __s_addr = strsep(&tok, ":"); data = tok; uint32_t addr = (uint32_t) strtoul(__s_addr, NULL, 16); uint32_t data_length = status - (uint32_t) (data - packet); // Length of decoded data cannot be more than encoded, as escapes are removed. // Additional byte is reserved for alignment fix. uint8_t *decoded = calloc(1, data_length + 1); uint32_t dec_index = 0; for(uint32_t i = 0; i < data_length; i++) { if(data[i] == 0x7d) { i++; decoded[dec_index++] = data[i] ^ 0x20; } else { decoded[dec_index++] = data[i]; } } // fix alignment if(dec_index % 2 != 0) { dec_index++; } DLOG("binary packet %d -> %d\n", data_length, dec_index); if(flash_populate(addr, decoded, dec_index) < 0) { reply = strdup("E00"); } else { reply = strdup("OK"); } free(decoded); } else if(!strcmp(cmdName, "FlashDone")) { if(flash_go(sl, st)) { reply = strdup("E08"); } else { reply = strdup("OK"); } } else if(!strcmp(cmdName, "Kill")) { attached = 0; reply = strdup("OK"); } if(reply == NULL) { reply = strdup(""); } break; } case 'c': cache_sync(sl); ret = stlink_run(sl, RUN_NORMAL); if(ret) { DLOG("Semihost: run failed\n"); } while (1) { status = gdb_check_for_interrupt(client); if(status < 0) { ELOG("cannot check for int: %d\n", status); close_socket(client); return (1); } if(status == 1) { stlink_force_debug(sl); break; } ret = stlink_status(sl); if(ret) { DLOG("Semihost: status failed\n"); } if(sl->core_stat == TARGET_HALTED) { struct stlink_reg reg; stm32_addr_t pc; stm32_addr_t addr; int32_t offset = 0; uint16_t insn; if(!st->semihosting) { break; } ret = stlink_read_all_regs (sl, ®); if(ret) { DLOG("Semihost: read_all_regs failed\n"); } // read PC pc = reg.r[15]; // compute aligned value offset = pc % 4; addr = pc - offset; // read instructions (address and length must be aligned). ret = stlink_read_mem32(sl, addr, (offset > 2 ? 8 : 4)); if(ret != 0) { DLOG("Semihost: cannot read instructions at: 0x%08x\n", addr); break; } memcpy(&insn, &sl->q_buf[offset], sizeof(insn)); if(insn == 0xBEAB && !has_breakpoint(addr)) { ret = do_semihosting (sl, reg.r[0], reg.r[1], ®.r[0]); if(ret) { DLOG("Semihost: do_semihosting failed\n"); } // write return value ret = stlink_write_reg(sl, reg.r[0], 0); if(ret) { DLOG("Semihost: write_reg failed for return value\n"); } // jump over the break instruction ret = stlink_write_reg(sl, reg.r[15] + 2, 15); if(ret) { DLOG("Semihost: write_reg failed for jumping over break\n"); } // continue execution cache_sync(sl); ret = stlink_run(sl, RUN_NORMAL); if(ret) { DLOG("Semihost: continue execution failed with stlink_run\n"); } } else { break; } } usleep(100000); } reply = strdup("S05"); // TRAP break; case 's': cache_sync(sl); ret = stlink_step(sl); if(ret) { // ... having a problem sending step packet ELOG("Step: cannot send step request\n"); reply = strdup("E00"); critical_error = 1; // absolutely critical } else { reply = strdup("S05"); // TRAP } break; case '?': if(attached) { reply = strdup("S05"); // TRAP } else { reply = strdup("OK"); // stub shall reply OK if not attached } break; case 'g': ret = stlink_read_all_regs(sl, ®p); if(ret) { DLOG("g packet: read_all_regs failed\n"); } reply = calloc(1, 8 * 16 + 1); for(int32_t i = 0; i < 16; i++) { snprintf(&reply[i * 8], 9, "%08x", (uint32_t) htonl(regp.r[i])); } break; case 'p': { uint32_t id = (uint32_t) strtoul(&packet[1], NULL, 16); uint32_t myreg = 0xDEADDEAD; if(id < 16) { ret = stlink_read_reg(sl, id, ®p); myreg = htonl(regp.r[id]); } else if(id == 0x19) { ret = stlink_read_reg(sl, 16, ®p); myreg = htonl(regp.xpsr); } else if(id == 0x1A) { ret = stlink_read_reg(sl, 17, ®p); myreg = htonl(regp.main_sp); } else if(id == 0x1B) { ret = stlink_read_reg(sl, 18, ®p); myreg = htonl(regp.process_sp); } else if(id == 0x1C) { ret = stlink_read_unsupported_reg(sl, id, ®p); myreg = htonl(regp.control); } else if(id == 0x1D) { ret = stlink_read_unsupported_reg(sl, id, ®p); myreg = htonl(regp.faultmask); } else if(id == 0x1E) { ret = stlink_read_unsupported_reg(sl, id, ®p); myreg = htonl(regp.basepri); } else if(id == 0x1F) { ret = stlink_read_unsupported_reg(sl, id, ®p); myreg = htonl(regp.primask); } else if(id >= 0x20 && id < 0x40) { ret = stlink_read_unsupported_reg(sl, id, ®p); myreg = htonl(regp.s[id - 0x20]); } else if(id == 0x40) { ret = stlink_read_unsupported_reg(sl, id, ®p); myreg = htonl(regp.fpscr); } else { ret = 1; reply = strdup("E00"); } if(ret) { DLOG("p packet: could not read register with id %u\n", id); } if(reply == NULL) { // if reply is set to "E00", skip reply = calloc(1, 8 + 1); snprintf(reply, 9, "%08x", myreg); } break; } case 'P': { char* s_reg = &packet[1]; char* s_value = strstr(&packet[1], "=") + 1; uint32_t reg = (uint32_t) strtoul(s_reg, NULL, 16); uint32_t value = (uint32_t) strtoul(s_value, NULL, 16); if(reg < 16) { ret = stlink_write_reg(sl, ntohl(value), reg); } else if(reg == 0x19) { ret = stlink_write_reg(sl, ntohl(value), 16); } else if(reg == 0x1A) { ret = stlink_write_reg(sl, ntohl(value), 17); } else if(reg == 0x1B) { ret = stlink_write_reg(sl, ntohl(value), 18); } else if(reg == 0x1C) { ret = stlink_write_unsupported_reg(sl, ntohl(value), reg, ®p); } else if(reg == 0x1D) { ret = stlink_write_unsupported_reg(sl, ntohl(value), reg, ®p); } else if(reg == 0x1E) { ret = stlink_write_unsupported_reg(sl, ntohl(value), reg, ®p); } else if(reg == 0x1F) { ret = stlink_write_unsupported_reg(sl, ntohl(value), reg, ®p); } else if(reg >= 0x20 && reg < 0x40) { ret = stlink_write_unsupported_reg(sl, ntohl(value), reg, ®p); } else if(reg == 0x40) { ret = stlink_write_unsupported_reg(sl, ntohl(value), reg, ®p); } else { ret = 1; reply = strdup("E00"); } if(ret) { DLOG("P packet: stlink_write_unsupported_reg failed with reg %u\n", reg); } if(reply == NULL) { reply = strdup("OK"); /* Note: NULL may not be zero */ } break; } case 'G': for(int32_t i = 0; i < 16; i++) { char str[9] = {0}; memcpy(str, &packet[1 + i * 8], 8); uint32_t reg = (uint32_t) strtoul(str, NULL, 16); ret = stlink_write_reg(sl, ntohl(reg), i); if(ret) { DLOG("G packet: stlink_write_reg failed"); } } reply = strdup("OK"); break; case 'm': { char* s_start = &packet[1]; char* s_count = strstr(&packet[1], ",") + 1; stm32_addr_t start = (stm32_addr_t) strtoul(s_start, NULL, 16); uint32_t count = (uint32_t) strtoul(s_count, NULL, 16); uint32_t adj_start = start % 4; uint32_t count_rnd = (count + adj_start + 4 - 1) / 4 * 4; if(count_rnd > sl->flash_pgsz) { count_rnd = sl->flash_pgsz; } if(count_rnd > 0x1800) { count_rnd = 0x1800; } if(count_rnd < count) { count = count_rnd; } if(stlink_read_mem32(sl, start - adj_start, count_rnd) != 0) { count = 0; } // read failed somehow, don't return stale buffer reply = calloc(1, count * 2 + 1); for(uint32_t i = 0; i < count; i++) { reply[i * 2 + 0] = hex[sl->q_buf[i + adj_start] >> 4]; reply[i * 2 + 1] = hex[sl->q_buf[i + adj_start] & 0xf]; } break; } case 'M': { char* s_start = &packet[1]; char* s_count = strstr(&packet[1], ",") + 1; char* hexdata = strstr(packet, ":") + 1; stm32_addr_t start = (stm32_addr_t) strtoul(s_start, NULL, 16); uint32_t count = (uint32_t) strtoul(s_count, NULL, 16); int32_t err = 0; if(start % 4) { uint32_t align_count = 4 - start % 4; if(align_count > count) { align_count = count; } for(uint32_t i = 0; i < align_count; i++) { char hextmp[3] = { hexdata[i * 2], hexdata[i * 2 + 1], 0 }; uint8_t byte = (uint8_t) strtoul(hextmp, NULL, 16); sl->q_buf[i] = byte; } err |= stlink_write_mem8(sl, start, align_count); cache_change(start, align_count); start += align_count; count -= align_count; hexdata += 2 * align_count; } if(count - count % 4) { uint32_t aligned_count = count - count % 4; for(uint32_t i = 0; i < aligned_count; i++) { char hextmp[3] = { hexdata[i * 2], hexdata[i * 2 + 1], 0 }; uint8_t byte = (uint8_t) strtoul(hextmp, NULL, 16); sl->q_buf[i] = byte; } err |= stlink_write_mem32(sl, start, aligned_count); cache_change(start, aligned_count); count -= aligned_count; start += aligned_count; hexdata += 2 * aligned_count; } if(count) { for(uint32_t i = 0; i < count; i++) { char hextmp[3] = { hexdata[i * 2], hexdata[i * 2 + 1], 0 }; uint8_t byte = (uint8_t) strtoul(hextmp, NULL, 16); sl->q_buf[i] = byte; } err |= stlink_write_mem8(sl, start, count); cache_change(start, count); } reply = strdup(err ? "E00" : "OK"); break; } case 'Z': { char *endptr; stm32_addr_t addr = (stm32_addr_t) strtoul(&packet[3], &endptr, 16); stm32_addr_t len = (stm32_addr_t) strtoul(&endptr[1], NULL, 16); switch (packet[1]) { case '1': if(update_code_breakpoint(sl, addr, 1) < 0) { reply = strdup("E00"); } else { reply = strdup("OK"); } break; case '2': // insert write watchpoint case '3': // insert read watchpoint case '4': { // insert access watchpoint enum watchfun wf; if(packet[1] == '2') { wf = WATCHWRITE; } else if(packet[1] == '3') { wf = WATCHREAD; } else { wf = WATCHACCESS; } if(add_data_watchpoint(sl, wf, addr, len) < 0) { reply = strdup("E00"); } else { reply = strdup("OK"); break; } } break; default: reply = strdup(""); } break; } case 'z': { char *endptr; stm32_addr_t addr = (stm32_addr_t) strtoul(&packet[3], &endptr, 16); // stm32_addr_t len = strtoul(&endptr[1], NULL, 16); switch (packet[1]) { case '1': // remove breakpoint update_code_breakpoint(sl, addr, 0); reply = strdup("OK"); break; case '2': // remove write watchpoint case '3': // remove read watchpoint case '4': // remove access watchpoint if(delete_data_watchpoint(sl, addr) < 0) { reply = strdup("E00"); break; } else { reply = strdup("OK"); break; } default: reply = strdup(""); } break; } case '!': { // enter extended mode which allows restarting. We do support that always. // also, set to persistent mode to allow GDB disconnect. st->persistent = 1; reply = strdup("OK"); break; } case 'R': { // reset the core. ret = stlink_reset(sl, RESET_SOFT_AND_HALT); if(ret) { DLOG("R packet : stlink_reset failed\n"); } init_code_breakpoints(sl); init_data_watchpoints(sl); attached = 1; reply = strdup("OK"); break; } case 'k': // kill request - reset the connection itself ret = stlink_run(sl, RUN_NORMAL); if(ret) { DLOG("Kill: stlink_run failed\n"); } ret = stlink_exit_debug_mode(sl); if(ret) { DLOG("Kill: stlink_exit_debug_mode failed\n"); } stlink_close(sl); if(st->remote) { sl = stlink_open_remote_str(st->logging_level, st->remote, st->connect_mode, st->freq); } else { sl = stlink_open_usb(st->logging_level, st->connect_mode, st->serialnumber, st->freq); } if(sl == NULL || sl->chip_id == STM32_CHIPID_UNKNOWN) { cleanup(0); } connected_stlink = sl; ret = stlink_force_debug(sl); if(ret) { DLOG("Kill: stlink_force_debug failed\n"); } init_cache(sl); init_code_breakpoints(sl); init_data_watchpoints(sl); reply = NULL; // no response break; default: reply = strdup(""); } if(reply) { DLOG("send: %s\n", reply); int32_t result = gdb_send_packet(client, reply); if(result != 0) { ELOG("cannot send: %d\n", result); free(reply); free(packet); close_socket(client); return (1); } free(reply); } if(critical_error) { close_socket(client); return (1); } free(packet); } close_socket(client); return (0); } stlink-1.9.0/src/st-util/gdb-server.h000066400000000000000000000026471526027543100174440ustar00rootroot00000000000000/** ****************************************************************************** * @file : gdb-server.h * @brief : Tool: st-util * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @author : Peter Zotov (whitequark) * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #ifndef GDB_SERVER_H #define GDB_SERVER_H #include #include #include #include #include #include #include #include #if defined(_MSC_VER) #include #define __attribute__(x) #endif #if defined(_WIN32) #include #else #include #include #include #include #endif // _WIN32 #include #include #include #include #include #include #include #include #include #include #define STRINGIFY_inner(name) #name #define STRINGIFY(name) STRINGIFY_inner(name) #define DEFAULT_LOGGING_LEVEL 50 #define DEBUG_LOGGING_LEVEL 100 #define DEFAULT_GDB_LISTEN_PORT 4242 #endif // GDB_SERVER_H stlink-1.9.0/src/st-util/memory-map.h000066400000000000000000000347541526027543100174730ustar00rootroot00000000000000/** ****************************************************************************** * @file : memory-map.h * @brief : Tool: st-util * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #ifndef MEMORY_MAP_H #define MEMORY_MAP_H static const char* const memory_map_template_F4 = "" "" "" " " // code = sram, bootrom or flash; flash is bigger " " // ccm ram " " // sram " " // Sectors 0...3 " 0x4000" // 16 kB " " " " // Sector 4 " 0x10000" // 64 kB " " " " // Sectors 5...11 " 0x20000" // 128 kB " " " " // peripheral regs " " // AHB3 Peripherals " " // cortex regs " " // bootrom " " // option byte area ""; static const char* const memory_map_template_F4_HD = "" "" "" " " // code = sram, bootrom or flash; flash is bigger " " // ccm ram " " // sram " " // fmc bank 1 (nor/psram/sram) " " // fmc bank 2 & 3 (nand flash) " " // fmc bank 4 (pc card) " " // fmc sdram bank 1 & 2 " " // Sectors 0...3 " 0x4000" // 16 kB " " " " // Sector 4 " 0x10000" // 64 kB " " " " // Sectors 5...11 " 0x20000" // 128 kB " " " " // peripheral regs " " // cortex regs " " // bootrom " " // option byte area ""; static const char* const memory_map_template_F2 = "" "" "" " " // code = sram, bootrom or flash; flash is bigger " " // SRAM " " // Sectors 0...3 " 0x4000" // 16 kB " " " " // Sector 4 " 0x10000" // 64 kB " " " " // Sectors 5... " 0x20000" // 128 kB " " " " // peripheral regs " " // cortex regs " " // bootrom " " // option byte area ""; static const char* const memory_map_template_L4 = "" "" "" " " // code = sram, bootrom or flash; flash is bigger " " // SRAM2 (32 kB) " " // SRAM1 (96 kB) " " " 0x800" " " " " // peripheral regs " " // AHB3 Peripherals " " // cortex regs " " // bootrom " " // option byte area " " // option byte area ""; static const char* const memory_map_template_L496 = "" "" "" " " // code = sram, bootrom or flash; flash is bigger " " // SRAM2 (64 kB) " " // SRAM1 + aliased SRAM2 (256 + 64 = 320 kB) " " " 0x800" " " " " // peripheral regs " " // AHB3 Peripherals " " // cortex regs " " // bootrom " " // option byte area " " // option byte area ""; static const char* const memory_map_template = "" "" "" " " // code = sram, bootrom or flash; flash is bigger " " // SRAM (8 kB) " " " 0x%x" " " " " // peripheral regs " " // cortex regs " " // bootrom " " // option byte area ""; static const char* const memory_map_template_F7 = "" "" "" " " // ITCM ram 16 kB " " // ITCM flash " " // SRAM " " // Sectors 0...3 " 0x8000" // 32 kB " " " " // Sector 4 " 0x20000" // 128 kB " " " " // Sectors 5...7 " 0x40000" // 128 kB " " " " // peripheral regs " " // AHB3 Peripherals " " // cortex regs " " // bootrom " " // option byte area ""; static const char* const memory_map_template_H7 = "" "" "" " " // ITCMRAM 64 kB " " // DTCMRAM 128 kB " " // RAM D1 512 kB " " // RAM D2 288 kB " " // RAM D3 64 kB " " " 0x%x" " " " " // peripheral regs " " // cortex regs " " // bootrom ""; static const char* const memory_map_template_H72x3x = "" "" "" " " // ITCMRAM 64 kB + Optional remap " " // DTCMRAM 128 kB " " // RAM D1 320 kB " " // RAM D2 23 kB " " // RAM D3 16 kB " " // Backup RAM 4 kB " " " 0x%x" " " " " // peripheral regs " " // External Memory " " // External device " " // cortex regs " " // bootrom ""; static const char* const memory_map_template_F4_DE = "" "" "" " " // code = sram, bootrom or flash; flash is bigger " " // SRAM " " // Sectors 0..3 " 0x4000" // 16 kB " " " " // Sector 4 " 0x10000" // 64 kB " " " " // Sectors 5..7 " 0x20000" // 128 kB " " " " // peripheral regs " " // cortex regs " " // bootrom " " // otp " " // option byte area ""; #endif // MEMORY_MAP_Hstlink-1.9.0/src/st-util/semihosting.c000066400000000000000000000330321526027543100177200ustar00rootroot00000000000000/** ****************************************************************************** * @file : semihosting.c * @brief : Tool: st-util * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @author : Fabien-Chouteau (Fabien-Chouteau) * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #include #include "semihosting.h" static int32_t mem_read_u8(stlink_t *sl, uint32_t addr, uint8_t *data) { int32_t offset = addr % 4; int32_t len = 4; if(sl == NULL || data == NULL) { return (-1); } // read address and length must be aligned if(stlink_read_mem32(sl, addr - offset, len) != 0) { return (-1); } *data = sl->q_buf[offset]; return (0); } #ifdef UNUSED static int32_t mem_read_u16(stlink_t *sl, uint32_t addr, uint16_t *data) { int32_t offset = addr % 4; int32_t len = (offset > 2 ? 8 : 4); if(sl == NULL || data == NULL) { return (-1); } // read address and length must be aligned if(stlink_read_mem32(sl, addr - offset, len) != 0) { return (-1); } memcpy(data, &sl->q_buf[offset], sizeof(*data)); return (0); } static int32_t mem_read_u32(stlink_t *sl, uint32_t addr, uint32_t *data) { int32_t offset = addr % 4; int32_t len = (offset > 0 ? 8 : 4); if(sl == NULL || data == NULL) { return (-1); } // read address and length must be aligned if(stlink_read_mem32(sl, addr - offset, len) != 0) { return (-1); } memcpy(data, &sl->q_buf[offset], sizeof(*data)); return (0); } #endif static int32_t mem_read(stlink_t *sl, uint32_t addr, void *data, uint16_t len) { int32_t offset = addr % 4; int32_t read_len = len + offset; if(sl == NULL || data == NULL) { return (-1); } // align read size if((read_len % 4) != 0) { read_len += 4 - (read_len % 4); } // address and length must be aligned if(stlink_read_mem32(sl, addr - offset, read_len) != 0) { return (-1); } memcpy(data, &sl->q_buf[offset], len); return (0); } static int32_t mem_write(stlink_t *sl, uint32_t addr, void *data, uint16_t len) { /* Note: this function can write more than it is asked to! * If addr is not an even 32 bit boundary, or len is not a multiple of 4. * If only 32 bit values can be written to the target, then this function should read * the target memory at the start and end of the buffer where it will write more that * the requested bytes. (perhaps reading the whole area is faster??). * If 16 and 8 bit writes are available, then they could be used instead. * Just return when the length is zero avoiding unneeded work. */ if(len == 0) { return (0); } int32_t offset = addr % 4; int32_t write_len = len + offset; if(sl == NULL || data == NULL) { return (-1); } // align read size if((write_len % 4) != 0) { write_len += 4 - (write_len % 4); } memcpy(&sl->q_buf[offset], data, len); // address and length must be aligned if(stlink_write_mem32(sl, addr - offset, write_len) != 0) { return (-1); } return (0); } /* For the SYS_WRITE0 call, we don't know the size of the null-terminated buffer * in the target memory. Instead of reading one byte at a time, we read by * chunks of WRITE0_BUFFER_SIZE bytes. */ #define WRITE0_BUFFER_SIZE 64 /* Define a maximum size for buffers transmitted by semihosting. There is no * limit in the ARM specification but this is a safety net. * We remove 4 byte from Q_BUF_LEN to handle alignment correction. */ #define MAX_BUFFER_SIZE (Q_BUF_LEN - 4) /* Flags for Open syscall */ #ifndef O_BINARY #define O_BINARY 0 #endif static int32_t open_mode_flags[12] = { O_RDONLY, O_RDONLY | O_BINARY, O_RDWR, O_RDWR | O_BINARY, O_WRONLY | O_CREAT | O_TRUNC, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, O_RDWR | O_CREAT | O_TRUNC, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, O_WRONLY | O_CREAT | O_APPEND, O_WRONLY | O_CREAT | O_APPEND | O_BINARY, O_RDWR | O_CREAT | O_APPEND, O_RDWR | O_CREAT | O_APPEND | O_BINARY }; static int32_t saved_errno = 0; int32_t do_semihosting (stlink_t *sl, uint32_t r0, uint32_t r1, uint32_t *ret) { if(sl == NULL || ret == NULL) { return (-1); } DLOG("Do semihosting R0=0x%08x R1=0x%08x\n", r0, r1); switch (r0) { case SEMIHOST_SYS_OPEN: { uint32_t args[3]; uint32_t name_address; uint32_t mode; uint32_t name_len; char *name; if(mem_read(sl, r1, args, sizeof(args)) != 0) { DLOG("Semihosting SYS_OPEN error: cannot read args from target memory\n"); *ret = -1; return (-1); } name_address = args[0]; mode = args[1]; name_len = args[2]; if(mode > 12) { /* Invalid mode */ DLOG("Semihosting SYS_OPEN error: invalid mode %d\n", mode); *ret = -1; return (-1); } /* Add the trailing zero that is not counted in the length argument (see * ARM semihosting specification) */ name_len += 1; if(name_len > MAX_BUFFER_SIZE) { DLOG("Semihosting SYS_OPEN error: name buffer size is too big %d\n", name_len); *ret = -1; return (-1); } name = malloc(name_len); if(name == NULL) { DLOG("Semihosting SYS_OPEN error: cannot allocate name buffer\n"); *ret = -1; return (-1); } if(mem_read(sl, name_address, name, name_len) != 0) { free(name); *ret = -1; DLOG("Semihosting SYS_OPEN error: cannot read name from target memory\n"); return (-1); } DLOG("Semihosting: open('%s', (SH open mode)%d, 0644)\n", name, mode); if (name_len == 4 && strncmp(":tt", name, 3) == 0) { if (mode <= 3) { *ret = STDIN_FILENO; } else if (mode >= 4 && mode <= 7) { *ret = STDOUT_FILENO; } else if (mode >= 8 && mode <= 11) { *ret = STDERR_FILENO; } else { DLOG("Semihosting SYS_OPEN error: invalid mode %d for :tt\n", mode); *ret = -1; saved_errno = EINVAL; } DLOG("Semihosting: return %d\n", *ret); free(name); break; } *ret = (uint32_t) open(name, open_mode_flags[mode], 0644); saved_errno = errno; DLOG("Semihosting: return %d\n", *ret); free(name); break; } case SEMIHOST_SYS_CLOSE: { uint32_t args[1]; int32_t fd; if(mem_read(sl, r1, args, sizeof(args)) != 0) { DLOG("Semihosting SYS_CLOSE error: cannot read args from target memory\n"); *ret = -1; return (-1); } fd = (int32_t) args[0]; DLOG("Semihosting: close(%d)\n", fd); *ret = (uint32_t) close(fd); saved_errno = errno; DLOG("Semihosting: return %d\n", *ret); break; } case SEMIHOST_SYS_WRITE: { uint32_t args[3]; uint32_t buffer_address; int32_t fd; uint32_t buffer_len; void *buffer; if(mem_read(sl, r1, args, sizeof(args)) != 0) { DLOG("Semihosting SYS_WRITE error: cannot read args from target memory\n"); *ret = -1; return (-1); } fd = (int32_t) args[0]; buffer_address = args[1]; buffer_len = args[2]; if(buffer_len > MAX_BUFFER_SIZE) { DLOG("Semihosting SYS_WRITE error: buffer size is too big %d\n", buffer_len); *ret = buffer_len; return (-1); } buffer = malloc(buffer_len); if(buffer == NULL) { DLOG("Semihosting SYS_WRITE error: cannot allocate buffer\n"); *ret = buffer_len; return (-1); } if(mem_read(sl, buffer_address, buffer, buffer_len) != 0) { DLOG("Semihosting SYS_WRITE error: cannot read buffer from target memory\n"); free(buffer); *ret = buffer_len; return (-1); } DLOG("Semihosting: write(%d, target_addr:0x%08x, %u)\n", fd, buffer_address, buffer_len); *ret = (uint32_t) write(fd, buffer, buffer_len); saved_errno = errno; if(*ret == (uint32_t)-1) { *ret = buffer_len; } else { *ret -= buffer_len; } DLOG("Semihosting: return %d\n", *ret); free(buffer); break; } case SEMIHOST_SYS_READ: { uint32_t args[3]; uint32_t buffer_address; int32_t fd; uint32_t buffer_len; void *buffer; ssize_t read_result; if(mem_read(sl, r1, args, sizeof(args)) != 0) { DLOG("Semihosting SYS_READ error: cannot read args from target memory\n"); *ret = -1; return (-1); } fd = (int32_t) args[0]; buffer_address = args[1]; buffer_len = args[2]; if(buffer_len > MAX_BUFFER_SIZE) { DLOG("Semihosting SYS_READ error: buffer size is too big %d\n", buffer_len); *ret = buffer_len; return (-1); } buffer = malloc(buffer_len); if(buffer == NULL) { DLOG("Semihosting SYS_READ error: cannot allocatebuffer\n"); *ret = buffer_len; return (-1); } DLOG("Semihosting: read(%d, target_addr:0x%08x, %u)\n", fd, buffer_address, buffer_len); read_result = read(fd, buffer, buffer_len); saved_errno = errno; if(read_result == -1) { *ret = buffer_len; } else { if(mem_write(sl, buffer_address, buffer, read_result) != 0) { DLOG("Semihosting SYS_READ error: cannot write buffer to target memory\n"); free(buffer); *ret = buffer_len; return (-1); } else { *ret = buffer_len - (uint32_t) read_result; } } DLOG("Semihosting: return %d\n", *ret); free(buffer); break; } case SEMIHOST_SYS_ERRNO: { *ret = (uint32_t) saved_errno; DLOG("Semihosting: Errno return %d\n", *ret); break; } case SEMIHOST_SYS_REMOVE: { uint32_t args[2]; uint32_t name_address; uint32_t name_len; char *name; if(mem_read(sl, r1, args, sizeof(args)) != 0) { DLOG("Semihosting SYS_REMOVE error: cannot read args from target memory\n"); *ret = -1; return (-1); } name_address = args[0]; name_len = args[1]; /* Add the trailing zero that is not counted in the length argument (see * ARM semihosting specification) */ name_len += 1; if(name_len > MAX_BUFFER_SIZE) { DLOG("Semihosting SYS_REMOVE error: name buffer size is too big %d\n", name_len); *ret = -1; return (-1); } name = malloc(name_len); if(name == NULL) { DLOG("Semihosting SYS_REMOVE error: cannot allocate name buffer\n"); *ret = -1; return (-1); } if(mem_read(sl, name_address, name, name_len) != 0) { free(name); *ret = -1; DLOG("Semihosting SYS_REMOVE error: cannot read name from target memory\n"); return (-1); } DLOG("Semihosting: unlink('%s')\n", name); *ret = (uint32_t) unlink(name); saved_errno = errno; DLOG("Semihosting: return %d\n", *ret); free(name); break; } case SEMIHOST_SYS_SEEK: { uint32_t args[2]; int32_t fd; off_t offset; if(mem_read(sl, r1, args, sizeof(args)) != 0) { DLOG("Semihosting SYS_SEEK error: cannot read args from target memory\n"); *ret = -1; return (-1); } fd = (int32_t) args[0]; offset = (off_t) args[1]; DLOG("Semihosting: lseek(%d, %d, SEEK_SET)\n", fd, (int32_t) offset); *ret = (uint32_t) lseek(fd, offset, SEEK_SET); saved_errno = errno; if(*ret != (uint32_t)-1) { *ret = 0; /* Success */ } DLOG("Semihosting: return %d\n", *ret); break; } case SEMIHOST_SYS_WRITEC: { uint8_t c; if(mem_read_u8(sl, r1, &c) == 0) { fprintf(stderr, "%c", c); } else { DLOG("Semihosting WRITEC: cannot read target memory at 0x%08x\n", r1); } break; } case SEMIHOST_SYS_READC: { uint8_t c = getchar(); *ret = c; break; } case SEMIHOST_SYS_WRITE0: { uint8_t buf[WRITE0_BUFFER_SIZE]; while (true) { if(mem_read(sl, r1, buf, WRITE0_BUFFER_SIZE) != 0) { DLOG("Semihosting WRITE0: cannot read target memory at 0x%08x\n", r1); return (-1); } for(int32_t i = 0; i < WRITE0_BUFFER_SIZE; i++) { if(buf[i] == 0) { return (0); } fprintf(stderr, "%c", buf[i]); } r1 += WRITE0_BUFFER_SIZE; } break; } default: fprintf(stderr, "semihosting: unsupported call %#x\n", r0); return (-1); } return (0); } stlink-1.9.0/src/st-util/semihosting.h000066400000000000000000000032211526027543100177220ustar00rootroot00000000000000/** ****************************************************************************** * @file : semihosting.h * @brief : Tool: st-util * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @author : Fabien-Chouteau (Fabien-Chouteau) * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #ifndef SEMIHOSTING_H #define SEMIHOSTING_H #include #include #include #include #include #include #include #include #include #include #define SEMIHOST_SYS_OPEN 0x01 #define SEMIHOST_SYS_CLOSE 0x02 #define SEMIHOST_SYS_WRITEC 0x03 #define SEMIHOST_SYS_WRITE0 0x04 #define SEMIHOST_SYS_WRITE 0x05 #define SEMIHOST_SYS_READ 0x06 #define SEMIHOST_SYS_READC 0x07 #define SEMIHOST_SYS_ISERROR 0x08 #define SEMIHOST_SYS_ISTTY 0x09 #define SEMIHOST_SYS_SEEK 0x0A #define SEMIHOST_SYS_FLEN 0x0C #define SEMIHOST_SYS_TMPNAM 0x0D #define SEMIHOST_SYS_REMOVE 0x0E #define SEMIHOST_SYS_RENAME 0x0F #define SEMIHOST_SYS_CLOCK 0x10 #define SEMIHOST_SYS_TIME 0x11 #define SEMIHOST_SYS_ERRNO 0x13 #define SEMIHOST_SYS_GET_CMD 0x15 #define SEMIHOST_SYS_HEAPINFO 0x16 #define SEMIHOST_SYS_ELAPSED 0x30 #define SEMIHOST_SYS_TICKFREQ 0x31 int32_t do_semihosting(stlink_t *sl, uint32_t r0, uint32_t r1, uint32_t *ret); #endif // SEMIHOSTING_H stlink-1.9.0/src/stlink-env/000077500000000000000000000000001526027543100157135ustar00rootroot00000000000000stlink-1.9.0/src/stlink-env/CMakeLists.txt000066400000000000000000000121251526027543100204540ustar00rootroot00000000000000### # System-specific definitions, header files and libraries ### # Check for system-specific additional header files and libraries include(CheckIncludeFile) include(CheckLibraryExists) set(STLINK_DEFINITIONS) # collect all system-specific compiler definitions here set(STLINK_COMPILE_OPTIONS) # collect all system-specific compiler flags here # ==================================================================================================== ## Windows-specific build configuration if (WIN32) message(STATUS "Configuring for Windows (Windows 10+)") # Compiler definitions for Windows list(APPEND STLINK_DEFINITIONS -D_WIN32_WINNT=0x0A00 # Minimum system requirement: Windows 10 -D_WIN32=1 # Define _WIN32 for platform specific code -DWIN32_LEAN_AND_MEAN # Keep windows.h from pulling in winsock.h v1, which conflicts with # winsock2.h regardless of include order (libusb.h drags in windows.h # ahead of remote.h/win32_socket.h in some TUs) ) # Include directories containing windows-specific header files list(APPEND STLINK_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/win32) link_libraries(ws2_32) # Link Windows-Socket library # TODO: Additional win32_socket ??? list(APPEND STLINK_SOURCES src/stlink-env/win32/win32_socket.c) list(APPEND STLINK_HEADERS src/stlink-env/win32/win32_socket.h) endif() ## Additional fixes for MSVC if (MSVC) # Use string.h rather than strings.h and disable annoying warnings list(APPEND STLINK_DEFINITIONS -DHAVE_STRING_H -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_WARNINGS ) list(APPEND STLINK_COMPILE_OPTIONS /wd4710) endif() # ==================================================================================================== ### pthreads # One header, one implementation per platform, selected here rather than with # preprocessor branches inside a single file. list(APPEND STLINK_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/pthreads) list(APPEND STLINK_HEADERS src/stlink-env/pthreads/stlink_threads.h) if (WIN32) list(APPEND STLINK_SOURCES src/stlink-env/pthreads/stlink_threads_win32.c) else () list(APPEND STLINK_SOURCES src/stlink-env/pthreads/stlink_threads_posix.c) endif() ### filesystem lookups # Same arrangement as above: the executable's own location and walking a # directory have no portable spelling. list(APPEND STLINK_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/fs) list(APPEND STLINK_HEADERS src/stlink-env/fs/stlink_fs.h) if (WIN32) list(APPEND STLINK_SOURCES src/stlink-env/fs/stlink_fs_win32.c) else () list(APPEND STLINK_SOURCES src/stlink-env/fs/stlink_fs_posix.c) endif() ### libusb find_package(libusb REQUIRED) ### Stack Smashing Protection Library (SSP) CHECK_LIBRARY_EXISTS(ssp __stack_chk_fail "" _stack_chk_fail_exists) if (_stack_chk_fail_exists) if (WIN32) set(SSP_LIB -static ssp) # static linking else () set(SSP_LIB ssp) endif() else () set(SSP_LIB "") endif() ### Check for C standard library include files [POSIX] CHECK_INCLUDE_FILE(sys/mman.h STLINK_HAVE_SYS_MMAN_H) if (STLINK_HAVE_SYS_MMAN_H) list(APPEND STLINK_DEFINITIONS -DSTLINK_HAVE_SYS_MMAN_H) else () if (WIN32 OR MSVC OR MINGW) list(APPEND STLINK_SOURCES src/stlink-env/win32/sys_mmap.c) list(APPEND STLINK_HEADERS src/stlink-env/win32/sys_mmap.h) endif() endif() CHECK_INCLUDE_FILE(sys/time.h STLINK_HAVE_SYS_TIME_H) if (STLINK_HAVE_SYS_TIME_H) list(APPEND STLINK_DEFINITIONS -DSTLINK_HAVE_SYS_TIME_H) else () if (WIN32 OR MSVC OR MINGW) list(APPEND STLINK_SOURCES src/stlink-env/win32/sys_time.c) list(APPEND STLINK_HEADERS src/stlink-env/win32/sys_time.h) endif() endif() CHECK_INCLUDE_FILE(unistd.h STLINK_HAVE_UNISTD_H) if (STLINK_HAVE_UNISTD_H) list(APPEND STLINK_DEFINITIONS -DSTLINK_HAVE_UNISTD_H) else () if (WIN32 OR MSVC OR MINGW) list(APPEND STLINK_HEADERS src/stlink-env/win32/unistd.h) endif() endif() ### Check for non C standard library include files [POSIX] if (NOT WIN32) CHECK_INCLUDE_FILE(dirent.h STLINK_HAVE_DIRENT_H) if (STLINK_HAVE_DIRENT_H) list(APPEND STLINK_DEFINITIONS -DSTLINK_HAVE_DIRENT_H) else () message(FATAL_ERROR "dirent.h not found! init_chipids can not be compiled for Unix/Linux.") endif() else () # WIN32 CHECK_INCLUDE_FILE(windows.h STLINK_HAVE_WINDOWS_H) message(STATUS "Windows platform detected. Using Windows API for init_chipids.") list(APPEND STLINK_DEFINITIONS -DSTLINK_HAVE_WINDOWS_H) endif() # ==================================================================================================== ### Propagate system-specific additional definitions, sources, headers and libraries to parent scope set(STLINK_SOURCES ${STLINK_SOURCES} PARENT_SCOPE) set(STLINK_HEADERS ${STLINK_HEADERS} PARENT_SCOPE) set(STLINK_DEFINITIONS ${STLINK_DEFINITIONS} PARENT_SCOPE) set(STLINK_COMPILE_OPTIONS ${STLINK_COMPILE_OPTIONS} PARENT_SCOPE) set(STLINK_INCLUDE_DIRS ${STLINK_INCLUDE_DIRS} PARENT_SCOPE) set(SSP_LIB ${SSP_LIB} PARENT_SCOPE)stlink-1.9.0/src/stlink-env/fs/000077500000000000000000000000001526027543100163235ustar00rootroot00000000000000stlink-1.9.0/src/stlink-env/fs/stlink_fs.h000066400000000000000000000017671526027543100205030ustar00rootroot00000000000000/** ****************************************************************************** * @file : stlink_fs.h * @brief : Filesystem lookups that differ per platform * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-09-17 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #ifndef STLINK_FS_H #define STLINK_FS_H #include #include #define CHIP_FILE_EXT ".chip" /* Directory holding the running executable, without a trailing separator. * False where the platform will not say. */ bool stlink_exe_dir(char *buf, size_t len); /* Read every chip description file in dir. False if it held none, including * when dir cannot be read at all. */ bool search_for_chips(const char *dir); #endif // STLINK_FS_H stlink-1.9.0/src/stlink-env/fs/stlink_fs_posix.c000066400000000000000000000035431526027543100217120ustar00rootroot00000000000000/** ****************************************************************************** * @file : stlink_fs_posix.c * @brief : Filesystem lookups on Unix (POSIX) systems * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-09-17 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #include #include #include #include #if defined(__APPLE__) #include #endif #include #include "chipid.h" #include "logging.h" bool stlink_exe_dir(char *buf, size_t len) { char *cut; #if defined(__APPLE__) uint32_t n = (uint32_t)len; if(_NSGetExecutablePath(buf, &n) != 0) { return (false); } #else ssize_t n = readlink("/proc/self/exe", buf, len - 1); if((n <= 0) || ((size_t)n >= (len - 1))) { return (false); } buf[n] = '\0'; #endif cut = strrchr(buf, '/'); if(cut == NULL) { return (false); } *cut = '\0'; return (true); } bool search_for_chips(const char *dir) { DIR *d = opendir(dir); struct dirent *entry; size_t el = strlen(CHIP_FILE_EXT); bool found = false; DLOG("Looking for chip description files in %s\n", dir); if(d == NULL) { return (false); } while ((entry = readdir(d)) != NULL) { char path[1024]; size_t nl = strlen(entry->d_name); if((nl <= el) || (strcmp(entry->d_name + nl - el, CHIP_FILE_EXT) != 0)) { continue; } if(snprintf(path, sizeof(path), "%s/%s", dir, entry->d_name) >= (int)sizeof(path)) { ELOG("Path too long: %s/%s\n", dir, entry->d_name); continue; } process_chipfile(path); found = true; } closedir(d); return (found); } stlink-1.9.0/src/stlink-env/fs/stlink_fs_win32.c000066400000000000000000000040071526027543100215060ustar00rootroot00000000000000/** ****************************************************************************** * @file : stlink_fs_win32.c * @brief : Filesystem lookups on Windows * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-09-17 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #include #include #include #include #include "chipid.h" #include "logging.h" bool stlink_exe_dir(char *buf, size_t len) { DWORD n = GetModuleFileNameA(NULL, buf, (DWORD)len); char *cut; if((n == 0) || (n >= len)) { return (false); } /* Win32 takes either separator but not a mixture, and the caller appends * with '/'. Settle on that here rather than leave it to chance. */ for(char *p = buf; *p != '\0'; p++) { if(*p == '\\') { *p = '/'; } } cut = strrchr(buf, '/'); if(cut == NULL) { return (false); } *cut = '\0'; return (true); } bool search_for_chips(const char *dir) { WIN32_FIND_DATAA ffd; char path[MAX_PATH] = {0}; HANDLE hFind; bool found = false; DLOG("Looking for chip description files in %s\n", dir); if(FAILED(StringCchCopyA(path, sizeof(path), dir)) || FAILED(StringCchCatA(path, sizeof(path), "/*" CHIP_FILE_EXT))) { ELOG("Path too long: %s\n", dir); return (false); } hFind = FindFirstFileA(path, &ffd); if(INVALID_HANDLE_VALUE == hFind) { return (false); } do { if(FAILED(StringCchCopyA(path, sizeof(path), dir)) || FAILED(StringCchCatA(path, sizeof(path), "/")) || FAILED(StringCchCatA(path, sizeof(path), ffd.cFileName))) { ELOG("Path too long: %s/%s\n", dir, ffd.cFileName); continue; } process_chipfile(path); found = true; } while (FindNextFileA(hFind, &ffd) != 0); FindClose(hFind); return (found); } stlink-1.9.0/src/stlink-env/getopt/000077500000000000000000000000001526027543100172155ustar00rootroot00000000000000stlink-1.9.0/src/stlink-env/getopt/LICENSE.txt000066400000000000000000000027411526027543100210440ustar00rootroot00000000000000BSD 3-Clause License Copyright (c) 2012, Kim Gräsman All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Kim Gräsman nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KIM GRÄSMAN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. stlink-1.9.0/src/stlink-env/getopt/README.md000066400000000000000000000017051526027543100204770ustar00rootroot00000000000000getopt_port =========== [Kim Gräsman](http://grundlig.wordpress.com) [@kimgr](http://twitter.com/kimgr) An original implementation of `getopt` and `getopt_long` with limited GNU extensions. Provided under the BSD license, to allow non-GPL projects to use `getopt`-style command-line parsing. So far only built with Visual C++, but has no inherently non-portable constructs. Intended to be embedded into your code tree -- `getopt.h` and `getopt.c` are self-contained and should work in any context. Comes with a reasonable unit test suite. See also: * [Full Win32 getopt port](http://www.codeproject.com/Articles/157001/Full-getopt-Port-for-Unicode-and-Multibyte-Microso) -- LGPL licensed. * [XGetOpt](http://www.codeproject.com/Articles/1940/XGetopt-A-Unix-compatible-getopt-for-MFC-and-Win32) -- No `getopt_long` support. * [Free Getopt](https://sourceforge.net/projects/freegetopt/) -- No `getopt_long` support. For license terms, see LICENSE.txt. stlink-1.9.0/src/stlink-env/getopt/getopt.c000066400000000000000000000161761526027543100206760ustar00rootroot00000000000000/* * File: getopt.c * * */ #include "getopt.h" char* optarg; int32_t optopt; int32_t optind = 1; // The variable optind [...] shall be initialized to 1 by the system int32_t opterr; static char* optcursor = NULL; /* Implemented based on [1] and [2] for optional arguments. * optopt is handled FreeBSD-style, per [3]. * Other GNU and FreeBSD extensions are purely accidental. * * [1] http://pubs.opengroup.org/onlinepubs/000095399/functions/getopt.html * [2] http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html * [3] http://www.freebsd.org/cgi/man.cgi?query=getopt&sektion=3&manpath=FreeBSD+9.0-RELEASE */ int32_t getopt(int32_t argc, char* const argv[], const char* optstring) { int32_t optchar = -1; const char* optdecl = NULL; optarg = NULL; opterr = 0; optopt = 0; /* Unspecified, but we need it to avoid overrunning the argv bounds. */ if(optind >= argc) { goto no_more_optchars; } /* If, when getopt() is called argv[optind] is a null pointer, * getopt() shall return -1 without changing optind. */ if(argv[optind] == NULL) { goto no_more_optchars; } /* If, when getopt() is called *argv[optind] is not the character '-', * getopt() shall return -1 without changing optind. */ if(*argv[optind] != '-') { goto no_more_optchars; } /* If, when getopt() is called argv[optind] points to the string "-", * getopt() shall return -1 without changing optind. */ if(strcmp(argv[optind], "-") == 0) { goto no_more_optchars; } /* If, when getopt() is called argv[optind] points to the string "--", * getopt() shall return -1 after incrementing optind. */ if(strcmp(argv[optind], "--") == 0) { ++optind; goto no_more_optchars; } if(optcursor == NULL || *optcursor == '\0') { optcursor = argv[optind] + 1; } optchar = *optcursor; /* FreeBSD: The variable optopt saves the last known option character returned by getopt(). */ optopt = optchar; /* The getopt() function shall return the next option character (if one is found) * from argv that matches a character in optstring, if there is one that matches. */ optdecl = strchr(optstring, optchar); if(optdecl) { /* [I]f a character is followed by a colon, the option takes an argument. */ if(optdecl[1] == ':') { optarg = ++optcursor; if(*optarg == '\0') { /* GNU extension: Two colons mean an option takes an optional arg; * if there is text in the current argv-element (i.e., in the same word * as the option name itself, for example, "-oarg"), then it is returned * in optarg, otherwise optarg is set to zero. */ if(optdecl[2] != ':') { /* If the option was the last character in the string pointed to by * an element of argv, then optarg shall contain the next element * of argv, and optind shall be incremented by 2. If the resulting * value of optind is greater than argc, this indicates a missing * option-argument, and getopt() shall return an error indication. * Otherwise, optarg shall point to the string following the * option character in that element of argv, and optind shall be * incremented by 1. */ if(++optind < argc) { optarg = argv[optind]; } else { /* If it detects a missing option-argument, it shall return the * colon character ( ':' ) if the first character of optstring * was a colon, or a question-mark character ( '?' ) otherwise. */ optarg = NULL; optchar = (optstring[0] == ':') ? ':' : '?'; } } else { optarg = NULL; } } optcursor = NULL; } } else { /* If getopt() encounters an option character that is not contained in * optstring, it shall return the question-mark ( '?' ) character. */ optchar = '?'; } if(optcursor == NULL || *++optcursor == '\0') { ++optind; } return (optchar); no_more_optchars: optcursor = NULL; return (-1); } /* Implementation based on http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html */ int32_t getopt_long(int32_t argc, char* const argv[], const char* optstring, const struct option* longopts, int* longindex) { const struct option* o = longopts; const struct option* match = NULL; int32_t num_matches = 0; uint32_t argument_name_length = 0; const char* current_argument = NULL; int32_t retval = -1; optarg = NULL; optopt = 0; if(optind >= argc) { return (-1); } if(strlen(argv[optind]) < 3 || strncmp(argv[optind], "--", 2) != 0) { return (getopt(argc, argv, optstring)); } // it's an option; starts with -- and is longer than two chars current_argument = argv[optind] + 2; argument_name_length = strcspn(current_argument, "="); for( ; o->name; ++o) if(strncmp(o->name, current_argument, argument_name_length) == 0) { match = o; ++num_matches; } if(num_matches == 1) { /* If longindex is not NULL, it points to a variable which is set to the * index of the long option relative to longopts. */ if(longindex) { *longindex = (match - longopts); } /* If flag is NULL, then getopt_long() shall return val. * Otherwise, getopt_long() returns 0, and flag shall point to a variable * which shall be set to val if the option is found, but left unchanged if * the option is not found. */ if(match->flag) { *(match->flag) = match->val; } retval = match->flag ? 0 : match->val; if(match->has_arg != no_argument) { optarg = strchr(argv[optind], '='); if(optarg != NULL) { ++optarg; } if(match->has_arg == required_argument) { /* Only scan the next argv for required arguments. Behavior is not specified, but has been observed with Ubuntu. */ if(optarg == NULL && ++optind < argc) { optarg = argv[optind]; } if(optarg == NULL) { retval = ':'; } } } else if(strchr(argv[optind], '=')) { /* An argument was provided to a non-argument option. * I haven't seen this specified explicitly, but both GNU and BSD-based * implementations show this behavior. */ retval = '?'; } } else { // unknown option or ambiguous match retval = '?'; } ++optind; return (retval); } stlink-1.9.0/src/stlink-env/getopt/getopt.h000066400000000000000000000016161526027543100206740ustar00rootroot00000000000000/* * File: getopt.h * * */ #ifndef GETOPT_H #define GETOPT_H #include #include #include #if defined(__cplusplus) extern "C" { #endif /* Defines to initialize static/global struct option arrays */ // These must be compile-time constants rather than extern variables. #define no_argument 0 #define required_argument 1 #define optional_argument 2 extern char* optarg; extern int32_t optind, opterr, optopt; struct option { const char* name; int32_t has_arg; int* flag; int32_t val; }; int32_t getopt(int32_t argc, char* const argv[], const char* optstring); int32_t getopt_long(int32_t argc, char* const argv[], const char* optstring, const struct option* longopts, int* longindex); #if defined(__cplusplus) } #endif #endif // GETOPT_H stlink-1.9.0/src/stlink-env/libusb_settings.h000066400000000000000000000021451526027543100212660ustar00rootroot00000000000000/** ****************************************************************************** * @file : libusb_settings.h * @brief : Settings for libusb library * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #ifndef LIBUSB_SETTINGS_H #define LIBUSB_SETTINGS_H #include /* * libusb ver | LIBUSB_API_VERSION * -----------+-------------------- * v1.0.24 | 0x01000108 * v1.0.25 | 0x01000109 * v1.0.26 | 0x01000110 * v1.0.27 | 0x01000111 * v1.0.28 | 0x01000112 * v1.0.29 | 0x01000113 * v1.0.30 | 0x01000114 * v1.0.31 | 0x01000115 */ #define MINIMAL_API_VERSION 0x01000108 #if(LIBUSB_API_VERSION < MINIMAL_API_VERSION) #error unsupported libusb version #endif #endif // LIBUSB_SETTINGS_H stlink-1.9.0/src/stlink-env/pthreads/000077500000000000000000000000001526027543100175255ustar00rootroot00000000000000stlink-1.9.0/src/stlink-env/pthreads/stlink_threads.h000066400000000000000000000035611526027543100227210ustar00rootroot00000000000000/** ****************************************************************************** * @file : stlink_threads.h * @brief : pthreads wrapper * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @author : Andreas Michelis (a-michelis) * @date : 2026-09-15 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #ifndef STLINK_THREADS_H #define STLINK_THREADS_H #include /* * Minimal thread wrapper. * * The library only ever starts a handful of workers and waits for them, which * Win32 and pthreads both provide directly. Wrapping those two calls removes * the last reason for a Windows build to carry a pthreads implementation: * PThreads4W on MSVC, or winpthread on MinGW, the latter being a DLL that the * produced binaries would otherwise have to ship beside them. */ #if defined(_WIN32) /* A HANDLE, held as void* so that windows.h stays out of this header. */ typedef void *stlink_thread_t; #else #include typedef pthread_t stlink_thread_t; #endif /* * A thread entry point. It deliberately returns nothing: Win32 and pthreads * disagree on both the return type and the calling convention, and nothing * here reads a thread's result. */ typedef void (*stlink_thread_fn)(void *arg); /** * @brief Start a thread running fn(arg). * @return 0 on success, otherwise the platform error code */ int32_t stlink_thread_create(stlink_thread_t *thread, stlink_thread_fn fn, void *arg); /** * @brief Wait for a thread to finish, then release it. * @return 0 on success, otherwise the platform error code */ int32_t stlink_thread_join(stlink_thread_t thread); #endif // STLINK_THREADS_Hstlink-1.9.0/src/stlink-env/pthreads/stlink_threads_posix.c000066400000000000000000000031211526027543100241260ustar00rootroot00000000000000/** ****************************************************************************** * @file : stlink_threads_posix.c * @brief : pthreads wrapper for POSIX * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @author : Andreas Michelis (a-michelis) * @date : 2026-09-15 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #include #include #include "stlink_threads.h" /* * pthreads wants an entry point of void *(*)(void *), which is not the shape * the caller supplies, so the caller's function and argument travel in a * context. Kept deliberately identical in structure to the Win32 side. */ struct stlink_thread_ctx { stlink_thread_fn fn; void *arg; }; static void *stlink_thread_entry(void *raw) { struct stlink_thread_ctx ctx = *(struct stlink_thread_ctx *)raw; free(raw); ctx.fn(ctx.arg); return (NULL); } int32_t stlink_thread_create(stlink_thread_t *thread, stlink_thread_fn fn, void *arg) { struct stlink_thread_ctx *ctx = malloc(sizeof(*ctx)); if(ctx == NULL) { return (-1); } ctx->fn = fn; ctx->arg = arg; int32_t ret = (int32_t)pthread_create(thread, NULL, stlink_thread_entry, ctx); if(ret != 0) { free(ctx); } return (ret); } int32_t stlink_thread_join(stlink_thread_t thread) { return ((int32_t)pthread_join(thread, NULL)); }stlink-1.9.0/src/stlink-env/pthreads/stlink_threads_win32.c000066400000000000000000000042161526027543100237340ustar00rootroot00000000000000/** ****************************************************************************** * @file : stlink_threads_win32.c * @brief : pthreads wrapper for WIN32 * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @author : Andreas Michelis (a-michelis) * @date : 2026-09-15 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #include #include #include #include #include #include "stlink_threads.h" /* * Win32 wants an entry point of unsigned __stdcall (*)(void *), which is not * the shape the caller supplies. Casting is not an option, because on 32-bit * Windows __stdcall and __cdecl genuinely differ and this project ships i686 * binaries, so the caller's function and argument travel in a context instead. */ struct stlink_thread_ctx { stlink_thread_fn fn; void *arg; }; static unsigned __stdcall stlink_thread_entry(void *raw) { struct stlink_thread_ctx ctx = *(struct stlink_thread_ctx *)raw; free(raw); ctx.fn(ctx.arg); return (0); } int32_t stlink_thread_create(stlink_thread_t *thread, stlink_thread_fn fn, void *arg) { struct stlink_thread_ctx *ctx = malloc(sizeof(*ctx)); if(ctx == NULL) { return (-1); } ctx->fn = fn; ctx->arg = arg; /* _beginthreadex rather than CreateThread, because the worker calls into * the C runtime and that needs its per-thread state initialised. */ uintptr_t handle = _beginthreadex(NULL, 0, stlink_thread_entry, ctx, 0, NULL); if(handle == 0) { int32_t error = (int32_t)errno; free(ctx); return ((error == 0) ? -1 : error); } *thread = (stlink_thread_t)handle; return (0); } int32_t stlink_thread_join(stlink_thread_t thread) { if(WaitForSingleObject((HANDLE)thread, INFINITE) != WAIT_OBJECT_0) { return ((int32_t)GetLastError()); } CloseHandle((HANDLE)thread); return (0); }stlink-1.9.0/src/stlink-env/win32/000077500000000000000000000000001526027543100166555ustar00rootroot00000000000000stlink-1.9.0/src/stlink-env/win32/sys_mmap.c000066400000000000000000000012661526027543100206560ustar00rootroot00000000000000/* * File: sys_mmap.c * * */ #include "sys_mmap.h" void *mmap(void *addr, uint32_t len, int32_t prot, int32_t flags, int32_t fd, int64_t offset) { void *buf; ssize_t count; (void)flags; if (addr || fd == -1 || (prot & PROT_WRITE)) { return (MAP_FAILED); } buf = malloc(len); if (NULL == buf) { return (MAP_FAILED); } if (lseek(fd, offset, SEEK_SET) != offset) { free(buf); return (MAP_FAILED); } count = read(fd, buf, len); if (count != (ssize_t) len) { free(buf); return (MAP_FAILED); } return (buf); } int32_t munmap(void *addr, uint32_t len) { free (addr); (void)len; return (0); } stlink-1.9.0/src/stlink-env/win32/sys_mmap.h000066400000000000000000000011571526027543100206620ustar00rootroot00000000000000/* * File: sys_mmap.h * * */ #ifndef SYS_MMAP_H #define SYS_MMAP_H #include #include #include #include #include #ifdef STLINK_HAVE_SYS_MMAN_H #include #else #define PROT_READ (1 << 0) #define PROT_WRITE (1 << 1) #define MAP_SHARED (1 << 0) #define MAP_PRIVATE (1 << 1) #define MAP_ANONYMOUS (1 << 5) #define MAP_FAILED ((void *)-1) void *mmap(void *addr, uint32_t len, int32_t prot, int32_t flags, int32_t fd, int64_t offset); int32_t munmap(void *addr, uint32_t len); #endif // STLINK_HAVE_SYS_MMAN_H #endif // SYS_MMAP_H stlink-1.9.0/src/stlink-env/win32/sys_time.c000066400000000000000000000017131526027543100206570ustar00rootroot00000000000000/* * File: sys_time.c * * */ #include #include "sys_time.h" #ifndef STLINK_HAVE_SYS_TIME_H #include /* Simple gettimeofday implementation */ int32_t gettimeofday(struct timeval *tv, struct timezone *tz) { FILETIME ftime; ULARGE_INTEGER ulint; static int32_t tzflag = 0; if(NULL != tv) { GetSystemTimeAsFileTime(&ftime); ulint.LowPart = ftime.dwLowDateTime; ulint.HighPart = ftime.dwHighDateTime; ulint.QuadPart -= 116444736000000000LL; // shift base to unix epoch ulint.QuadPart /= 10LL; // 100ns ticks to microseconds tv->tv_sec = (int32_t) (ulint.QuadPart / 1000000LL); tv->tv_usec = (int32_t) (ulint.QuadPart % 1000000LL); } if(NULL != tz) { if(!tzflag) { _tzset(); tzflag++; } tz->tz_minuteswest = _timezone / 60; tz->tz_dsttime = _daylight; } return 0; } #endif // STLINK_HAVE_SYS_TIME_H stlink-1.9.0/src/stlink-env/win32/sys_time.h000066400000000000000000000006761526027543100206730ustar00rootroot00000000000000/* * File: sys_time.h * * */ #ifndef SYS_TIME_H #define SYS_TIME_H #include #ifdef STLINK_HAVE_SYS_TIME_H #include #else #include // struct timeval, including with WIN32_LEAN_AND_MEAN #include struct timezone { int32_t tz_minuteswest; int32_t tz_dsttime; }; int32_t gettimeofday(struct timeval *tv, struct timezone *tz); #endif // STLINK_HAVE_SYS_TIME_H #endif // SYS_TIME_H stlink-1.9.0/src/stlink-env/win32/unistd.h000066400000000000000000000041541526027543100203400ustar00rootroot00000000000000/* * File: unistd.h * * */ #ifndef UNISTD_H #define UNISTD_H /* * This file intended to serve as a drop-in replacement for unistd.h on Windows * Please add functionality as needed. */ #include #include #include #if defined(_MSC_VER) && !defined(_SSIZE_T_DEFINED) #include typedef SSIZE_T ssize_t; #define _SSIZE_T_DEFINED #endif #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) // #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 int32_t usleep(uint32_t waitTime); //#endif #endif // UNISTD_H stlink-1.9.0/src/stlink-env/win32/win32_socket.c000066400000000000000000000167571526027543100213530ustar00rootroot00000000000000/* * File: win32_socket.c * * */ #if defined(_WIN32) #include #include "win32_socket.h" #undef socket #undef connect #undef accept #undef shutdown #include #include #include int32_t win32_poll(struct pollfd *fds, uint32_t nfds, int32_t timo) { struct timeval timeout, *toptr; fd_set ifds, ofds, efds, *ip, *op; uint32_t i; int32_t rc; #ifdef _MSC_VER #pragma warning(disable: 4548) #endif /* Set up the file-descriptor sets in ifds, ofds and efds. */ FD_ZERO(&ifds); FD_ZERO(&ofds); FD_ZERO(&efds); for(i = 0, op = ip = 0; i < nfds; ++i) { fds[i].revents = 0; if(fds[i].events & (POLLIN | POLLPRI)) { ip = &ifds; FD_SET(fds[i].fd, ip); } if(fds[i].events & POLLOUT) { op = &ofds; FD_SET(fds[i].fd, op); } FD_SET(fds[i].fd, &efds); } #ifdef _MSC_VER #pragma warning(default: 4548) #endif /* Set up the timeval structure for the timeout parameter */ if(timo < 0) { toptr = 0; } else { toptr = &timeout; timeout.tv_sec = timo / 1000; timeout.tv_usec = (timo - timeout.tv_sec * 1000) * 1000; } #ifdef DEBUG_POLL printf("Entering select() sec=%ld usec=%ld ip=%lx op=%lx\n", (long)timeout.tv_sec, (long)timeout.tv_usec, (long)ip, (long)op); #endif rc = select(0, ip, op, &efds, toptr); #ifdef DEBUG_POLL printf("Exiting select rc=%d\n", rc); #endif if(rc <= 0) { return (rc); } if(rc > 0) { for( i = 0; i < nfds; ++i) { SOCKET fd = fds[i].fd; if(fds[i].events & (POLLIN | POLLPRI) && FD_ISSET(fd, &ifds)) { fds[i].revents |= POLLIN; } if(fds[i].events & POLLOUT && FD_ISSET(fd, &ofds)) { fds[i].revents |= POLLOUT; } if(FD_ISSET(fd, &efds)) { // Some error was detected ... should be some way to know fds[i].revents |= POLLHUP; } #ifdef DEBUG_POLL printf("%d %d %d revent = %x\n", FD_ISSET(fd, &ifds), FD_ISSET(fd, &ofds), FD_ISSET(fd, &efds), fds[i].revents); #endif } } return (rc); } static void set_connect_errno(int32_t winsock_err) { switch (winsock_err) { case WSAEINVAL: case WSAEALREADY: case WSAEWOULDBLOCK: errno = EINPROGRESS; break; default: errno = winsock_err; break; } } static void set_socket_errno(int32_t winsock_err) { switch (winsock_err) { case WSAEWOULDBLOCK: errno = EAGAIN; break; default: errno = winsock_err; break; } } /* * A wrapper around the socket() function. * The purpose of this wrapper is to ensure that the global errno symbol is set if an error occurs, * even if we are using winsock. */ SOCKET win32_socket(int32_t domain, int32_t type, int32_t protocol) { SOCKET fd = socket(domain, type, protocol); if(fd == INVALID_SOCKET) { set_socket_errno(WSAGetLastError()); } return (fd); } /* * A wrapper around the connect() function. * The purpose of this wrapper is to ensure that the global errno symbol is set if an error occurs, * even if we are using winsock. */ int32_t win32_connect(SOCKET fd, const struct sockaddr *addr, socklen_t addr_len) { int32_t rc = connect(fd, addr, addr_len); assert(rc == 0 || rc == SOCKET_ERROR); if(rc == SOCKET_ERROR) { set_connect_errno(WSAGetLastError()); } return (rc); } /* A wrapper around the accept() function. * The purpose of this wrapper is to ensure that the global errno symbol is set if an error occurs, * even if we are using winsock. */ SOCKET win32_accept(SOCKET fd, struct sockaddr *addr, socklen_t *addr_len) { SOCKET newfd = accept(fd, addr, addr_len); if(newfd == INVALID_SOCKET) { set_socket_errno(WSAGetLastError()); newfd = (SOCKET)-1; } return (newfd); } /* A wrapper around the shutdown() function. * The purpose of this wrapper is to ensure that the global errno symbol is set if an error occurs, * even if we are using winsock. */ int32_t win32_shutdown(SOCKET fd, int32_t mode) { int32_t rc = shutdown(fd, mode); assert(rc == 0 || rc == SOCKET_ERROR); if(rc == SOCKET_ERROR) { set_socket_errno(WSAGetLastError()); } return (rc); } int32_t win32_close_socket(SOCKET fd) { int32_t rc = closesocket(fd); if(rc == SOCKET_ERROR) { set_socket_errno(WSAGetLastError()); } return (rc); } ssize_t win32_write_socket(SOCKET fd, void *buf, int32_t n) { int32_t rc = send(fd, buf, n, 0); if(rc == SOCKET_ERROR) { set_socket_errno(WSAGetLastError()); } return (rc); } ssize_t win32_read_socket(SOCKET fd, void *buf, int32_t n) { int32_t rc = recv(fd, buf, n, 0); if(rc == SOCKET_ERROR) { set_socket_errno(WSAGetLastError()); } return (rc); } char * win32_strtok_r(char *s, const char *delim, char **lasts) { register char *spanp; register int32_t c, sc; char *tok; if(s == NULL && (s = *lasts) == NULL) { return (NULL); } // skip (span) leading delimiters (s += strspn(s, delim), sort of). cont: c = *s++; for(spanp = (char *)delim; (sc = *spanp++) != 0;) if(c == sc) { goto cont; } if(c == 0) { // no non-delimiter characters *lasts = NULL; return (NULL); } tok = s - 1; /* Scan token (scan for delimiters: s += strcspn(s, delim), sort of). * Note that delim must have one NUL; we stop if we see that, too. */ for( ; ;) { c = *s++; spanp = (char *)delim; do { if((sc = *spanp++) == c) { if(c == 0) { s = NULL; } else { s[-1] = 0; } *lasts = s; return (tok); } } while (sc != 0); } // NOT REACHED } char *win32_strsep (char **stringp, const char *delim) { register char *s; register const char *spanp; register int32_t c, sc; char *tok; if((s = *stringp) == NULL) { return (NULL); } for(tok = s; ;) { c = *s++; spanp = delim; do { if((sc = *spanp++) == c) { if(c == 0) { s = NULL; } else { s[-1] = 0; } *stringp = s; return (tok); } } while (sc != 0); } // NOT REACHED } #ifndef STLINK_HAVE_UNISTD_H int32_t usleep(uint32_t waitTime) { if(waitTime >= 1000) { /* Don't do long busy-waits. * However much it seems like the QPC code would be more accurate, * you can and probably will lose your time slice at any point during the wait, * so we might as well voluntarily give up the CPU with a WaitForSingleObject. */ HANDLE timer; LARGE_INTEGER dueTime; dueTime.QuadPart = -10 * (LONGLONG)waitTime; timer = CreateWaitableTimer(NULL, TRUE, NULL); SetWaitableTimer(timer, &dueTime, 0, NULL, NULL, 0); WaitForSingleObject(timer, INFINITE); CloseHandle(timer); return (0); } LARGE_INTEGER perf_cnt, start, now; QueryPerformanceFrequency(&perf_cnt); QueryPerformanceCounter(&start); do { QueryPerformanceCounter((LARGE_INTEGER*)&now); } while ((now.QuadPart - start.QuadPart) / (float)perf_cnt.QuadPart * 1000 * 1000 < waitTime); return (0); } #endif #endif // _WIN32 stlink-1.9.0/src/stlink-env/win32/win32_socket.h000066400000000000000000000052301526027543100213400ustar00rootroot00000000000000/* * File: win32_socket.h * * */ #if defined(_WIN32) #ifndef WIN32_SOCKET_H #define WIN32_SOCKET_H #include #define _USE_W32_SOCKETS 1 #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable: 4255 4668 4820) #endif #include #include #include #if defined(_MSC_VER) #pragma comment(lib, "ws2_32.lib") #endif #include #if defined(_MSC_VER) #pragma warning(pop) #endif /* * winsock doesn't feature poll(), so there is a version implemented in terms of select() in win32_socket.c. * The following definitions are copied from linux man pages. * A poll() macro is defined to call the version in win32_socket.c. */ #if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0600) #define POLLIN 0x0001 /* There is data to read */ #define POLLPRI 0x0002 /* There is urgent data to read */ #define POLLOUT 0x0004 /* Writing now will not block */ #define POLLERR 0x0008 /* Error condition */ #define POLLHUP 0x0010 /* Hung up */ #define POLLNVAL 0x0020 /* Invalid request: fd not open */ struct pollfd { SOCKET fd; /* file descriptor */ int16_t events; /* requested events */ int16_t revents; /* returned events */ }; #endif #define poll(x, y, z) win32_poll(x, y, z) /* * These wrappers do nothing special except set the global errno variable if an error occurs * (winsock doesn't do this by default). * They set errno to unix-like values (i.e. WSAEWOULDBLOCK is mapped to EAGAIN), * so code outside of this file "shouldn't" have to worry about winsock specific error handling. */ #define socket(x, y, z) win32_socket(x, y, z) #define connect(x, y, z) win32_connect(x, y, z) #define accept(x, y, z) win32_accept(x, y, z) #define shutdown(x, y) win32_shutdown(x, y) #define read(x, y, z) win32_read_socket(x, y, z) #define write(x, y, z) win32_write_socket(x, y, z) /* Winsock uses int32_t instead of the usual socklen_t */ typedef int32_t socklen_t; int32_t win32_poll(struct pollfd *, uint32_t, int32_t); SOCKET win32_socket(int32_t, int32_t, int32_t); int32_t win32_connect(SOCKET, const struct sockaddr*, socklen_t); SOCKET win32_accept(SOCKET, struct sockaddr*, socklen_t *); int32_t win32_shutdown(SOCKET, int32_t); int32_t win32_close_socket(SOCKET fd); #define strtok_r(x, y, z) win32_strtok_r(x, y, z) #define strsep(x,y) win32_strsep(x,y) char *win32_strtok_r(char *s, const char *delim, char **lasts); char *win32_strsep(char **stringp, const char *delim); ssize_t win32_read_socket(SOCKET fd, void *buf, int32_t n); ssize_t win32_write_socket(SOCKET fd, void *buf, int32_t n); #endif // WIN32_SOCKET_H #endif // defined(_WIN32) stlink-1.9.0/src/stlink-gui/000077500000000000000000000000001526027543100157075ustar00rootroot00000000000000stlink-1.9.0/src/stlink-gui/CMakeLists.txt000066400000000000000000000035161526027543100204540ustar00rootroot00000000000000### # Build GUI ### if (NOT WIN32) find_package(PkgConfig QUIET) if (PKG_CONFIG_FOUND) # Check for GTK3 pkg_check_modules(GTK3 QUIET gtk+-3.0) endif() ## GUI-Building requires the presence of a GTK3 toolset if (NOT GTK3_FOUND) message(STATUS "GTK3 not found! GUI build will be skipped.") return() # No GTK3 present => no GUI build else () message(STATUS "Found GTK3 version: ${GTK3_VERSION}") # Use target-based include directories if possible, or fall back to variable if (TARGET PkgConfig::GTK3) include_directories(SYSTEM PkgConfig::GTK3) else () include_directories(SYSTEM ${GTK3_INCLUDE_DIRS}) endif() # Install desktop application entry install(FILES stlink-gui.desktop DESTINATION ${CMAKE_INSTALL_FULL_DATADIR}/applications) # Install icons install(FILES icons/stlink-gui.svg DESTINATION ${CMAKE_INSTALL_FULL_DATADIR}/icons/hicolor/scalable/apps) set(GUI_SOURCES gui.c gui.h) ## stlink-gui add_executable(stlink-gui ${GUI_SOURCES}) install(FILES stlink-gui.ui DESTINATION ${CMAKE_INSTALL_FULL_DATADIR}/${PROJECT_NAME}) set_target_properties(stlink-gui PROPERTIES COMPILE_DEFINITIONS STLINK_UI_DIR="${CMAKE_INSTALL_FULL_DATADIR}/${PROJECT_NAME}") # Link using the modern PkgConfig GTK3 target, falling back to variables if necessary if (TARGET PkgConfig::GTK3) target_link_libraries(stlink-gui ${STLINK_LIB_SHARED} ${SSP_LIB} PkgConfig::GTK3) else () target_link_libraries(stlink-gui ${STLINK_LIB_SHARED} ${SSP_LIB} ${GTK3_LIBRARIES}) endif() install(TARGETS stlink-gui DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() endif() stlink-1.9.0/src/stlink-gui/gui.c000066400000000000000000001043741526027543100166500ustar00rootroot00000000000000/** ****************************************************************************** * @file : gui.c * @brief : stlink-gui * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #include #include #include #include #include #include #include #include #include #include #include "gui.h" #define MEM_READ_SIZE 1024 #ifndef G_VALUE_INIT #define G_VALUE_INIT {0, {{0}}} #endif G_DEFINE_TYPE(STlinkGUI, stlink_gui, G_TYPE_OBJECT); static void stlink_gui_dispose(GObject *gobject) { G_OBJECT_CLASS(stlink_gui_parent_class)->dispose(gobject); } static void stlink_gui_finalize(GObject *gobject) { G_OBJECT_CLASS(stlink_gui_parent_class)->finalize(gobject); } static void stlink_gui_class_init(STlinkGUIClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS(klass); gobject_class->dispose = stlink_gui_dispose; gobject_class->finalize = stlink_gui_finalize; } static void stlink_gui_init(STlinkGUI *self) { self->sl = NULL; self->filename = NULL; self->progress.activity_mode = FALSE; self->progress.fraction = 0; self->flash_mem.memory = NULL; self->flash_mem.size = 0; self->flash_mem.base = 0; self->file_mem.memory = NULL; self->file_mem.size = 0; self->file_mem.base = 0; } static void help(void) { puts("usage: stlink-gui [options] file\n"); puts("options:"); puts(" --version/-v Print version information."); puts(" --help/-h Show this help."); puts(""); puts("examples:"); puts(" stlink-gui path/to/file"); } static gboolean set_info_error_message_idle(STlinkGUI *gui) { if(gui->error_message != NULL) { gchar *markup; markup = g_markup_printf_escaped("%s", gui->error_message); gtk_label_set_markup(gui->infolabel, markup); gtk_info_bar_set_message_type(gui->infobar, GTK_MESSAGE_ERROR); gtk_widget_show(GTK_WIDGET(gui->infobar)); g_free(markup); g_free(gui->error_message); gui->error_message = NULL; } return (FALSE); } static void stlink_gui_set_info_error_message(STlinkGUI *gui, const gchar *message) { gui->error_message = g_strdup(message); g_idle_add((GSourceFunc)set_info_error_message_idle, gui); } static void stlink_gui_set_sensitivity(STlinkGUI *gui, gboolean sensitivity) { gtk_widget_set_sensitive(GTK_WIDGET(gui->open_button), sensitivity); if(sensitivity && gui->sl) { gtk_widget_set_sensitive(GTK_WIDGET(gui->disconnect_button), sensitivity); } if(sensitivity && !gui->sl) { gtk_widget_set_sensitive(GTK_WIDGET(gui->connect_button), sensitivity); } if(sensitivity && gui->sl && gui->filename) { gtk_widget_set_sensitive(GTK_WIDGET(gui->flash_button), sensitivity); } gtk_widget_set_sensitive(GTK_WIDGET(gui->reset_button), sensitivity && (gui->sl != NULL)); gtk_widget_set_sensitive(GTK_WIDGET(gui->export_button), sensitivity && (gui->sl != NULL)); gtk_widget_set_sensitive(GTK_WIDGET(gui->erase_button), sensitivity && (gui->sl != NULL)); } static void mem_view_init_headers(GtkTreeView *view) { GtkCellRenderer *renderer; gint i; g_return_if_fail(view != NULL); renderer = gtk_cell_renderer_text_new(); gtk_tree_view_insert_column_with_attributes(view, -1, "Address", renderer, "text", 0, /* column */ NULL); for(i = 0; i < 4; i++) { gchar *label; label = g_strdup_printf("%X", i * 4); renderer = gtk_cell_renderer_text_new(); gtk_tree_view_insert_column_with_attributes(view, -1, label, renderer, "text", (i + 1), /* column */ NULL); g_free(label); } for(i = 0; i < 5; i++) { GtkTreeViewColumn *column = gtk_tree_view_get_column(view, i); gtk_tree_view_column_set_expand(column, TRUE); } } static void mem_view_add_as_hex(GtkListStore *store, GtkTreeIter *iter, gint column, guint32 value) { gchar *hex_str; hex_str = g_strdup_printf("0x%08X", value); gtk_list_store_set(store, iter, column, hex_str, -1); g_free(hex_str); } static void mem_view_add_buffer(GtkListStore *store, GtkTreeIter *iter, guint32 address, guchar *buffer, gint len) { guint32 *word; gint i, step; gint column = 0; step = sizeof(*word); for(i = 0; i < len; i += step) { word = (guint *)&buffer[i]; if(column == 0) { gtk_list_store_append(store, iter); // new row mem_view_add_as_hex(store, iter, column, (address + i)); // add address } mem_view_add_as_hex(store, iter, (column + 1), *word); column = (column + 1) % step; } } static guint32 hexstr_to_guint32(const gchar *str, GError **err) { guint32 val; gchar *end_ptr; val = (guint32)strtoul(str, &end_ptr, 16); if((errno == ERANGE && val == UINT_MAX) || (errno != 0 && val == 0)) { g_set_error(err, g_quark_from_string("hextou32"), 1, "Invalid hexstring"); return (UINT32_MAX); } if(end_ptr == str) { g_set_error(err, g_quark_from_string("hextou32"), 2, "Invalid hexstring"); return (UINT32_MAX); } return (val); } static void stlink_gui_update_mem_view(STlinkGUI *gui, struct mem_t *mem, GtkTreeView *view) { GtkListStore *store; GtkTreeIter iter; store = GTK_LIST_STORE(gtk_tree_view_get_model(view)); mem_view_add_buffer(store, &iter, mem->base, mem->memory, (gint)mem->size); gtk_widget_hide(GTK_WIDGET(gui->progress.bar)); gtk_progress_bar_set_fraction(gui->progress.bar, 0); stlink_gui_set_sensitivity(gui, TRUE); } static gboolean stlink_gui_update_devmem_view(STlinkGUI *gui) { stlink_gui_update_mem_view(gui, &gui->flash_mem, gui->devmem_treeview); return (FALSE); } static gpointer stlink_gui_populate_devmem_view(gpointer data) { guint off; stm32_addr_t addr; g_return_val_if_fail(STLINK_IS_GUI(data), NULL); STlinkGUI *gui = (STlinkGUI *)data; g_return_val_if_fail((gui != NULL), NULL); g_return_val_if_fail((gui->sl != NULL), NULL); addr = gui->sl->flash_base; if(gui->flash_mem.memory) { g_free(gui->flash_mem.memory); } gui->flash_mem.memory = g_malloc(gui->sl->flash_size); gui->flash_mem.size = gui->sl->flash_size; gui->flash_mem.base = gui->sl->flash_base; for(off = 0; off < gui->sl->flash_size; off += MEM_READ_SIZE) { guint n_read = MEM_READ_SIZE; if(off + MEM_READ_SIZE > gui->sl->flash_size) { n_read = (guint)gui->sl->flash_size - off; if(n_read & 3) { n_read = (n_read + 4) & ~(3); } // align if needed } stlink_read_mem32(gui->sl, addr + off, n_read); // reads to sl->q_buf if(gui->sl->q_len < 0) { stlink_gui_set_info_error_message(gui, "Failed to read memory"); g_free(gui->flash_mem.memory); gui->flash_mem.memory = NULL; return (NULL); } memcpy(gui->flash_mem.memory + off, gui->sl->q_buf, n_read); gui->progress.fraction = (gdouble)(off + n_read) / gui->sl->flash_size; } g_idle_add((GSourceFunc)stlink_gui_update_devmem_view, gui); return (NULL); } static gboolean stlink_gui_update_filemem_view(STlinkGUI *gui) { gchar *basename; basename = g_path_get_basename(gui->filename); gtk_notebook_set_tab_label_text( gui->notebook, GTK_WIDGET(gtk_notebook_get_nth_page(gui->notebook, 1)), basename); g_free(basename); stlink_gui_update_mem_view(gui, &gui->file_mem, gui->filemem_treeview); return (FALSE); } static gpointer stlink_gui_populate_filemem_view(gpointer data) { guchar buffer[MEM_READ_SIZE]; GFile *file; GFileInfo *file_info; GInputStream *input_stream; gint off; GError *err = NULL; g_return_val_if_fail(STLINK_IS_GUI(data), NULL); STlinkGUI *gui = (STlinkGUI *)data; g_return_val_if_fail(gui != NULL, NULL); g_return_val_if_fail(gui->filename != NULL, NULL); if(g_str_has_suffix(gui->filename, ".hex")) { /* If the file has prefix .hex - try to interpret it as Intel-HEX. * It's difficult to merge the world of standard functions and GLib, so do it simple: * Load whole file into buffer and copy the data to the destination afterwards. * In the meanwhile we loose the displaying of the progress and need double memory. */ uint8_t* mem = NULL; uint32_t size = 0; uint32_t begin = 0; int32_t res = stlink_parse_ihex(gui->filename, 0, &mem, &size, &begin); if(res == 0) { if(gui->file_mem.memory) { g_free(gui->file_mem.memory); } gui->file_mem.size = size; gui->file_mem.memory = g_malloc(size); gui->file_mem.base = begin; memcpy(gui->file_mem.memory, mem, size); } else { stlink_gui_set_info_error_message(gui, "Cannot interpret the file as Intel-HEX"); } free(mem); } else { file = g_file_new_for_path(gui->filename); input_stream = G_INPUT_STREAM(g_file_read(file, NULL, &err)); if(err) { stlink_gui_set_info_error_message(gui, err->message); g_error_free(err); goto out; } file_info = g_file_input_stream_query_info( G_FILE_INPUT_STREAM(input_stream), G_FILE_ATTRIBUTE_STANDARD_SIZE, NULL, &err); if(err) { stlink_gui_set_info_error_message(gui, err->message); g_error_free(err); goto out_input; } if(gui->file_mem.memory) { g_free(gui->file_mem.memory); } goffset file_size = g_file_info_get_size(file_info); if((0 > file_size) && ((goffset)G_MAXSIZE <= file_size)) { stlink_gui_set_info_error_message(gui, "File too large."); goto out_input; } gui->file_mem.size = file_size; gui->file_mem.memory = g_malloc(gui->file_mem.size); for(off = 0; off < (gint)gui->file_mem.size; off += MEM_READ_SIZE) { guint n_read = MEM_READ_SIZE; if(off + MEM_READ_SIZE > (gint)gui->file_mem.size) { n_read = (guint)gui->file_mem.size - off; } if(g_input_stream_read( G_INPUT_STREAM(input_stream), &buffer, n_read, NULL, &err) == -1) { stlink_gui_set_info_error_message(gui, err->message); g_error_free(err); goto out_input; } memcpy(gui->file_mem.memory + off, buffer, n_read); gui->progress.fraction = (gdouble)(off + n_read) / gui->file_mem.size; } out_input: g_object_unref(input_stream); out: g_object_unref(file); } g_idle_add((GSourceFunc)stlink_gui_update_filemem_view, gui); return (NULL); } static void mem_jmp(GtkTreeView *view, GtkEntry *entry, guint32 base_addr, gsize size, GError **err) { GtkTreeModel *model; guint32 jmp_addr; GtkTreeIter iter; jmp_addr = hexstr_to_guint32(gtk_entry_get_text(entry), err); if(err && *err) { return; } if(jmp_addr < base_addr || jmp_addr > base_addr + size) { g_set_error(err, g_quark_from_string("mem_jmp"), 1, "Invalid address"); return; } model = gtk_tree_view_get_model(view); if(!model) { return; } if(gtk_tree_model_get_iter_first(model, &iter)) { do { guint32 addr; GValue value = G_VALUE_INIT; gtk_tree_model_get_value(model, &iter, 0, &value); if(G_VALUE_HOLDS_STRING(&value)) { addr = hexstr_to_guint32(g_value_get_string(&value), err); if(!*err) { if(addr == (jmp_addr & 0xFFFFFFF0)) { GtkTreeSelection *selection; GtkTreePath *path; selection = gtk_tree_view_get_selection(view); path = gtk_tree_model_get_path(model, &iter); gtk_tree_selection_select_iter(selection, &iter); gtk_tree_view_scroll_to_cell(view, path, NULL, TRUE, 0.0, 0.0); gtk_tree_path_free(path); } } } g_value_unset(&value); } while (gtk_tree_model_iter_next(model, &iter)); } } static void devmem_jmp_cb(GtkWidget *widget, gpointer data) { STlinkGUI *gui; GError *err = NULL; (void)widget; gui = STLINK_GUI(data); mem_jmp(gui->devmem_treeview, gui->devmem_jmp_entry, gui->sl->flash_base, gui->sl->flash_size, &err); if(err) { stlink_gui_set_info_error_message(gui, err->message); g_error_free(err); } } static void filemem_jmp_cb(GtkWidget *widget, gpointer data) { STlinkGUI *gui; GError *err = NULL; (void)widget; gui = STLINK_GUI(data); g_return_if_fail(gui->filename != NULL); mem_jmp(gui->filemem_treeview, gui->filemem_jmp_entry, 0, gui->file_mem.size, &err); if(err) { stlink_gui_set_info_error_message(gui, err->message); g_error_free(err); } } static gchar *dev_format_chip_id(guint32 chip_id) { const struct stlink_chipid_params *params; params = stlink_chipid_get_params(chip_id); if(!params) { return (g_strdup_printf("0x%x", chip_id)); } return (g_strdup(params->dev_type)); } static gchar *dev_format_mem_size(gsize flash_size) { return (g_strdup_printf("%u kB", (uint32_t) (flash_size / 1024))); } static void stlink_gui_set_connected(STlinkGUI *gui) { gchar *tmp_str; GtkListStore *store; GtkTreeIter iter; gtk_statusbar_push(gui->statusbar, gtk_statusbar_get_context_id(gui->statusbar, "conn"), "Connected"); gtk_widget_set_sensitive(GTK_WIDGET(gui->device_frame), TRUE); gtk_widget_set_sensitive(GTK_WIDGET(gui->devmem_box), TRUE); gtk_widget_set_sensitive(GTK_WIDGET(gui->connect_button), FALSE); if(gui->filename) { gtk_widget_set_sensitive(GTK_WIDGET(gui->flash_button), TRUE); } tmp_str = dev_format_chip_id(gui->sl->chip_id); gtk_label_set_text(gui->chip_id_label, tmp_str); g_free(tmp_str); tmp_str = g_strdup_printf("0x%x", gui->sl->core_id); gtk_label_set_text(gui->core_id_label, tmp_str); g_free(tmp_str); tmp_str = dev_format_mem_size(gui->sl->flash_size); gtk_label_set_text(gui->flash_size_label, tmp_str); g_free(tmp_str); tmp_str = dev_format_mem_size(gui->sl->sram_size); gtk_label_set_text(gui->ram_size_label, tmp_str); g_free(tmp_str); tmp_str = g_strdup_printf("0x%08X", gui->sl->flash_base); gtk_entry_set_text(gui->devmem_jmp_entry, tmp_str); gtk_editable_set_editable(GTK_EDITABLE(gui->devmem_jmp_entry), TRUE); g_free(tmp_str); store = GTK_LIST_STORE(gtk_tree_view_get_model(gui->devmem_treeview)); if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter)) { gtk_list_store_clear(store); } stlink_gui_set_sensitivity(gui, FALSE); gtk_notebook_set_current_page(gui->notebook, PAGE_DEVMEM); gtk_widget_show(GTK_WIDGET(gui->progress.bar)); gtk_progress_bar_set_text(gui->progress.bar, "Reading memory"); g_thread_new("devmem", (GThreadFunc)stlink_gui_populate_devmem_view, gui); } static void connect_button_cb(GtkWidget *widget, gpointer data) { STlinkGUI *gui; (void)widget; gui = STLINK_GUI(data); if(gui->sl != NULL) { return; } gui->sl = stlink_open_usb(0, 1, NULL, 0); if(gui->sl == NULL) { stlink_gui_set_info_error_message(gui, "Failed to connect to STLink."); return; } stlink_gui_set_connected(gui); } static void stlink_gui_set_disconnected(STlinkGUI *gui) { gtk_statusbar_push(gui->statusbar, gtk_statusbar_get_context_id(gui->statusbar, "conn"), "Disconnected"); gtk_widget_set_sensitive(GTK_WIDGET(gui->device_frame), FALSE); gtk_widget_set_sensitive(GTK_WIDGET(gui->connect_button), TRUE); gtk_widget_set_sensitive(GTK_WIDGET(gui->disconnect_button), FALSE); gtk_widget_set_sensitive(GTK_WIDGET(gui->flash_button), FALSE); gtk_widget_set_sensitive(GTK_WIDGET(gui->reset_button), FALSE); gtk_widget_set_sensitive(GTK_WIDGET(gui->export_button), FALSE); gtk_widget_set_sensitive(GTK_WIDGET(gui->erase_button), FALSE); } static void disconnect_button_cb(GtkWidget *widget, gpointer data) { STlinkGUI *gui; (void)widget; gui = STLINK_GUI(data); if(gui->sl != NULL) { stlink_exit_debug_mode(gui->sl); stlink_close(gui->sl); gui->sl = NULL; } stlink_gui_set_disconnected(gui); } static void stlink_gui_open_file(STlinkGUI *gui) { GtkWidget *dialog; GtkListStore *store; GtkTreeIter iter; dialog = gtk_file_chooser_dialog_new("Open file", gui->window, GTK_FILE_CHOOSER_ACTION_OPEN, "_Cancel", GTK_RESPONSE_CANCEL, "_Open", GTK_RESPONSE_ACCEPT, NULL); /* Start file chooser from last used directory */ if(gui->filename != NULL){ gchar *last_dir = g_path_get_dirname(gui->filename); if(last_dir){ gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER(dialog), last_dir); g_free(last_dir); } } if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { gui->filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); store = GTK_LIST_STORE(gtk_tree_view_get_model(gui->filemem_treeview)); if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter)) { gtk_list_store_clear(store); } stlink_gui_set_sensitivity(gui, FALSE); gtk_notebook_set_current_page(gui->notebook, PAGE_FILEMEM); gtk_widget_show(GTK_WIDGET(gui->progress.bar)); gtk_progress_bar_set_text(gui->progress.bar, "Reading file"); g_thread_new("file", (GThreadFunc)stlink_gui_populate_filemem_view, gui); } gtk_widget_destroy(dialog); } static gboolean open_file_from_args(STlinkGUI *gui) { if(gui->filename != NULL) { stlink_gui_set_sensitivity(gui, FALSE); gtk_notebook_set_current_page(gui->notebook, PAGE_FILEMEM); gtk_widget_show(GTK_WIDGET(gui->progress.bar)); gtk_progress_bar_set_text(gui->progress.bar, "Reading file"); g_thread_new("file", (GThreadFunc)stlink_gui_populate_filemem_view, gui); } return (FALSE); } static void open_button_cb(GtkWidget *widget, gpointer data) { STlinkGUI *gui; (void)widget; gui = STLINK_GUI(data); stlink_gui_open_file(gui); } static gboolean stlink_gui_restore_after_background_thread(STlinkGUI *gui) { stlink_gui_set_sensitivity(gui, TRUE); gui->progress.activity_mode = FALSE; gtk_widget_hide(GTK_WIDGET(gui->progress.bar)); return (FALSE); } static gpointer stlink_gui_write_flash(gpointer data) { g_return_val_if_fail(STLINK_IS_GUI(data), NULL); STlinkGUI *gui = (STlinkGUI *)data; g_return_val_if_fail((gui->sl != NULL), NULL); g_return_val_if_fail((gui->filename != NULL), NULL); if(stlink_mwrite_flash(gui->sl, gui->file_mem.memory, (uint32_t) gui->file_mem.size, gui->sl->flash_base, SECTION_ERASE) < 0) { stlink_gui_set_info_error_message(gui, "Failed to write to flash"); } g_idle_add((GSourceFunc)stlink_gui_restore_after_background_thread, gui); return (NULL); } static void flash_button_cb(GtkWidget *widget, gpointer data) { STlinkGUI *gui; gchar *tmp_str; guint32 address; gint result; GError *err = NULL; (void)widget; gui = STLINK_GUI(data); g_return_if_fail(gui->sl != NULL); if(!g_strcmp0(gtk_entry_get_text(gui->flash_dialog_entry), "")) { tmp_str = g_strdup_printf("0x%08X", gui->sl->flash_base); gtk_entry_set_text(gui->flash_dialog_entry, tmp_str); g_free(tmp_str); } result = gtk_dialog_run(gui->flash_dialog); if(result == GTK_RESPONSE_OK) { address = hexstr_to_guint32(gtk_entry_get_text(gui->flash_dialog_entry), &err); if(err) { stlink_gui_set_info_error_message(gui, err->message); } else { if(address > gui->sl->flash_base + gui->sl->flash_size || address < gui->sl->flash_base) { stlink_gui_set_info_error_message(gui, "Invalid address"); } else if(address + gui->file_mem.size > gui->sl->flash_base + gui->sl->flash_size) { stlink_gui_set_info_error_message(gui, "Binary overwrites flash"); } else { stlink_gui_set_sensitivity(gui, FALSE); gtk_progress_bar_set_text(gui->progress.bar, "Writing to flash"); gui->progress.activity_mode = TRUE; gtk_widget_show(GTK_WIDGET(gui->progress.bar)); g_thread_new("flash", (GThreadFunc)stlink_gui_write_flash, gui); } } } } static void reset_button_cb(GtkWidget *widget, gpointer data) { STlinkGUI *gui; (void)widget; gui = STLINK_GUI(data); g_return_if_fail(gui->sl != NULL); stlink_exit_debug_mode(gui->sl); stlink_reset(gui->sl, RESET_AUTO); stlink_enter_swd_mode(gui->sl); } int32_t export_to_file(const char*filename, const struct mem_t flash_mem) { printf("%s\n", filename); FILE * f = fopen(filename, "w"); if(f == NULL) { return (-1); } for(gsize i = 0; i < flash_mem.size; i++) if(fputc(flash_mem.memory[i], f) == EOF) { return (-1); } fclose(f); return (0); } static void export_button_cb(GtkWidget *widget, gpointer data) { (void)widget; STlinkGUI * gui = STLINK_GUI(data); GtkWidget *dialog; dialog = gtk_file_chooser_dialog_new("Save as", gui->window, GTK_FILE_CHOOSER_ACTION_SAVE, "_Cancel", GTK_RESPONSE_CANCEL, "_Open", GTK_RESPONSE_ACCEPT, NULL); GtkFileChooser *chooser = GTK_FILE_CHOOSER(dialog); gtk_file_chooser_set_do_overwrite_confirmation(chooser, TRUE); gint res = gtk_dialog_run(GTK_DIALOG(dialog)); if(res == GTK_RESPONSE_ACCEPT) { char *filename; filename = gtk_file_chooser_get_filename(chooser); if(export_to_file(filename, gui->flash_mem) != 0) { stlink_gui_set_info_error_message(gui, "Failed to export flash"); } else { stlink_gui_set_info_error_message(gui, "Export successful"); } g_free(filename); } gtk_widget_destroy(dialog); } static gpointer stlink_gui_erase_flash(gpointer data) { g_return_val_if_fail(STLINK_IS_GUI(data), NULL); STlinkGUI *gui = STLINK_GUI(data); g_return_val_if_fail((gui->sl != NULL), NULL); if(stlink_erase_flash_mass(gui->sl) < 0) { stlink_gui_set_info_error_message(gui, "Failed to mass erase flash"); } else { stlink_gui_set_info_error_message(gui, "Mass erased flash"); } g_idle_add((GSourceFunc)stlink_gui_restore_after_background_thread, gui); return (NULL); } static void erase_button_cb(GtkWidget *widget, gpointer data) { (void)widget; STlinkGUI *gui; gint result; gui = STLINK_GUI(data); g_return_if_fail(gui->sl != NULL); result = gtk_dialog_run(gui->erase_dialog); if(result == GTK_RESPONSE_OK) { stlink_gui_set_sensitivity(gui, FALSE); gtk_progress_bar_set_text(gui->progress.bar, "Mass erasing flash"); gui->progress.activity_mode = TRUE; gtk_widget_show(GTK_WIDGET(gui->progress.bar)); g_thread_new("erase_flash", (GThreadFunc)stlink_gui_erase_flash, gui); } } static gboolean progress_pulse_timeout(STlinkGUI *gui) { if(gui->progress.activity_mode) { gtk_progress_bar_pulse(gui->progress.bar); } else { gtk_progress_bar_set_fraction(gui->progress.bar, gui->progress.fraction); } return (TRUE); } static void notebook_switch_page_cb(GtkNotebook *notebook, GtkWidget *widget, guint page_num, gpointer data) { STlinkGUI *gui; (void)notebook; (void)widget; gui = STLINK_GUI(data); if(page_num == 1) { if(gui->filename == NULL) { stlink_gui_open_file(gui); } } } static void dnd_received_cb(GtkWidget *widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint target_type, guint timestamp, gpointer data) { GFile *file_uri; gchar **file_list; const guchar *file_data; STlinkGUI *gui = STLINK_GUI(data); GtkListStore *store; GtkTreeIter iter; (void)widget; (void)x; (void)y; if(selection_data != NULL && gtk_selection_data_get_length(selection_data) > 0) { switch (target_type) { case TARGET_FILENAME: if(gui->filename) { g_free(gui->filename); } file_data = gtk_selection_data_get_data(selection_data); file_list = g_strsplit((gchar *)file_data, "\r\n", 0); file_uri = g_file_new_for_uri(file_list[0]); gui->filename = g_file_get_path(file_uri); g_strfreev(file_list); g_object_unref(file_uri); store = GTK_LIST_STORE(gtk_tree_view_get_model(gui->devmem_treeview)); if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter)) { gtk_list_store_clear(store); } stlink_gui_set_sensitivity(gui, FALSE); gtk_notebook_set_current_page(gui->notebook, PAGE_FILEMEM); gtk_widget_show(GTK_WIDGET(gui->progress.bar)); gtk_progress_bar_set_text(gui->progress.bar, "Reading file"); g_thread_new("file", (GThreadFunc)stlink_gui_populate_filemem_view, gui); break; } } gtk_drag_finish( context, TRUE, gdk_drag_context_get_suggested_action(context) == GDK_ACTION_MOVE, timestamp); } void stlink_gui_init_dnd(STlinkGUI *gui) { GtkTargetEntry target_list[] = { { "text/uri-list", 0, TARGET_FILENAME }, }; gtk_drag_dest_set( GTK_WIDGET(gui->window), GTK_DEST_DEFAULT_ALL, target_list, G_N_ELEMENTS(target_list), GDK_ACTION_COPY); g_signal_connect(gui->window, "drag-data-received", G_CALLBACK(dnd_received_cb), gui); } static void stlink_gui_build_ui(STlinkGUI *gui) { GtkBuilder *builder; GtkListStore *devmem_store; GtkListStore *filemem_store; gchar *ui_file = STLINK_UI_DIR "/stlink-gui.ui"; if(!g_file_test(ui_file, G_FILE_TEST_EXISTS)) { ui_file = "stlink-gui.ui"; } builder = gtk_builder_new(); if(!gtk_builder_add_from_file(builder, ui_file, NULL)) { g_printerr("Failed to load UI file: %s\n", ui_file); exit(1); } gui->window = GTK_WINDOW(gtk_builder_get_object(builder, "window")); g_signal_connect(G_OBJECT(gui->window), "destroy", G_CALLBACK(gtk_main_quit), NULL); /* Setup for toolbutton clicked callbacks */ gui->open_button = GTK_TOOL_BUTTON(gtk_builder_get_object(builder, "open_button")); g_signal_connect(G_OBJECT(gui->open_button), "clicked", G_CALLBACK(open_button_cb), gui); gui->connect_button = GTK_TOOL_BUTTON(gtk_builder_get_object(builder, "connect_button")); g_signal_connect(G_OBJECT(gui->connect_button), "clicked", G_CALLBACK(connect_button_cb), gui); gui->disconnect_button = GTK_TOOL_BUTTON(gtk_builder_get_object(builder, "disconnect_button")); g_signal_connect(G_OBJECT(gui->disconnect_button), "clicked", G_CALLBACK(disconnect_button_cb), gui); gui->flash_button = GTK_TOOL_BUTTON(gtk_builder_get_object(builder, "flash_button")); g_signal_connect(G_OBJECT(gui->flash_button), "clicked", G_CALLBACK(flash_button_cb), gui); gui->reset_button = GTK_TOOL_BUTTON(gtk_builder_get_object(builder, "reset_button")); g_signal_connect(G_OBJECT(gui->reset_button), "clicked", G_CALLBACK(reset_button_cb), gui); gui->export_button = GTK_TOOL_BUTTON(gtk_builder_get_object(builder, "export_button")); g_signal_connect(G_OBJECT(gui->export_button), "clicked", G_CALLBACK(export_button_cb), gui); gui->erase_button = GTK_TOOL_BUTTON(gtk_builder_get_object(builder, "erase_button")); g_signal_connect(G_OBJECT(gui->erase_button), "clicked", G_CALLBACK(erase_button_cb), gui); gui->devmem_treeview = GTK_TREE_VIEW(gtk_builder_get_object(builder, "devmem_treeview")); mem_view_init_headers(gui->devmem_treeview); devmem_store = gtk_list_store_new(5, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); gtk_tree_view_set_model(gui->devmem_treeview, GTK_TREE_MODEL(devmem_store)); g_object_unref(devmem_store); gui->filemem_treeview = GTK_TREE_VIEW(gtk_builder_get_object(builder, "filemem_treeview")); mem_view_init_headers(gui->filemem_treeview); filemem_store = gtk_list_store_new(5, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); gtk_tree_view_set_model(gui->filemem_treeview, GTK_TREE_MODEL(filemem_store)); g_object_unref(filemem_store); gui->core_id_label = GTK_LABEL(gtk_builder_get_object(builder, "core_id_value")); gui->chip_id_label = GTK_LABEL(gtk_builder_get_object(builder, "chip_id_value")); gui->flash_size_label = GTK_LABEL(gtk_builder_get_object(builder, "flash_size_value")); gui->ram_size_label = GTK_LABEL(gtk_builder_get_object(builder, "ram_size_value")); gui->device_frame = GTK_FRAME(gtk_builder_get_object(builder, "device_frame")); gui->notebook = GTK_NOTEBOOK(gtk_builder_get_object(builder, "mem_notebook")); g_signal_connect(gui->notebook, "switch-page", G_CALLBACK(notebook_switch_page_cb), gui); gui->devmem_box = GTK_BOX(gtk_builder_get_object(builder, "devmem_box")); gui->filemem_box = GTK_BOX(gtk_builder_get_object(builder, "filemem_box")); gui->devmem_jmp_entry = GTK_ENTRY(gtk_builder_get_object(builder, "devmem_jmp_entry")); g_signal_connect(gui->devmem_jmp_entry, "activate", G_CALLBACK(devmem_jmp_cb), gui); gui->filemem_jmp_entry = GTK_ENTRY(gtk_builder_get_object(builder, "filemem_jmp_entry")); g_signal_connect(gui->filemem_jmp_entry, "activate", G_CALLBACK(filemem_jmp_cb), gui); gtk_editable_set_editable(GTK_EDITABLE(gui->filemem_jmp_entry), TRUE); gui->progress.bar = GTK_PROGRESS_BAR(gtk_builder_get_object(builder, "progressbar")); gtk_progress_bar_set_show_text(gui->progress.bar, TRUE); gui->progress.timer = g_timeout_add(100, (GSourceFunc)progress_pulse_timeout, gui); gui->statusbar = GTK_STATUSBAR(gtk_builder_get_object(builder, "statusbar")); gui->infobar = GTK_INFO_BAR(gtk_builder_get_object(builder, "infobar")); gtk_info_bar_add_button(gui->infobar, "_OK", GTK_RESPONSE_OK); gui->infolabel = GTK_LABEL(gtk_label_new("")); gtk_container_add(GTK_CONTAINER(gtk_info_bar_get_content_area(gui->infobar)), GTK_WIDGET(gui->infolabel)); g_signal_connect(gui->infobar, "response", G_CALLBACK(gtk_widget_hide), NULL); /* Flash dialog */ gui->flash_dialog = GTK_DIALOG(gtk_builder_get_object(builder, "flash_dialog")); g_signal_connect_swapped(gui->flash_dialog, "response", G_CALLBACK(gtk_widget_hide), gui->flash_dialog); gui->flash_dialog_ok = GTK_BUTTON(gtk_builder_get_object(builder, "flash_dialog_ok_button")); gui->flash_dialog_cancel = GTK_BUTTON(gtk_builder_get_object(builder, "flash_dialog_cancel_button")); gui->flash_dialog_entry = GTK_ENTRY(gtk_builder_get_object(builder, "flash_dialog_entry")); /* Erase dialog */ gui->erase_dialog = GTK_DIALOG(gtk_builder_get_object(builder, "erase_dialog")); g_signal_connect_swapped(gui->erase_dialog, "response", G_CALLBACK(gtk_widget_hide), gui->erase_dialog); gui->erase_dialog_ok = GTK_BUTTON(gtk_builder_get_object(builder, "erase_dialog_ok_button")); gui->erase_dialog_cancel = GTK_BUTTON(gtk_builder_get_object(builder, "erase_dialog_cancel_button")); // make it so gtk_widget_show_all(GTK_WIDGET(gui->window)); gtk_widget_hide(GTK_WIDGET(gui->infobar)); gtk_widget_hide(GTK_WIDGET(gui->progress.bar)); stlink_gui_set_disconnected(gui); } int32_t main(int32_t argc, char **argv) { STlinkGUI *gui; gtk_init(&argc, &argv); init_chipids(NULL); gui = g_object_new(STLINK_TYPE_GUI, NULL); stlink_gui_build_ui(gui); stlink_gui_init_dnd(gui); /* Parse remaining cli arguments */ argc--; argv++; while (argc > 0){ if(strcmp(argv[0], "--version") == 0 || strcmp(argv[0], "-v") == 0) { printf("v%s\n", STLINK_VERSION); exit(EXIT_SUCCESS); } else if(strcmp(argv[0], "--help") == 0 || strcmp(argv[0], "-h") == 0) { help(); return 1; } if(argc == 1 && g_file_test(*argv, G_FILE_TEST_IS_REGULAR)){ /* Open hex file at app startup */ gui->filename = g_strdup(*argv); g_idle_add((GSourceFunc)open_file_from_args, gui); } argc--; argv++; } gtk_main(); return (0); } stlink-1.9.0/src/stlink-gui/gui.h000066400000000000000000000062741526027543100166550ustar00rootroot00000000000000/** ****************************************************************************** * @file : gui.h * @brief : stlink-gui * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #ifndef GUI_H #define GUI_H #include #include #define STLINK_TYPE_GUI (stlink_gui_get_type()) #define STLINK_GUI(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), STLINK_TYPE_GUI, STlinkGUI)) #define STLINK_IS_GUI(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), STLINK_TYPE_GUI)) #define STLINK_GUI_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), STLINK_TYPE_GUI, STlinkGUIClass)) #define STLINK_IS_GUI_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), STLINK_TYPE_GUI)) #define STLINK_GUI_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), STLINK_TYPE_GUI, STlinkGUIlass)) #define STLINK_GUI_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), STLINK_TYPE_GUI, STlinkGUIPrivate)) typedef struct _STlinkGUI STlinkGUI; typedef struct _STlinkGUIClass STlinkGUIClass; typedef struct _STlinkGUIPrivate STlinkGUIPrivate; enum stlink_gui_pages_t { PAGE_DEVMEM, PAGE_FILEMEM }; enum stlink_gui_dnd_targets_t { TARGET_FILENAME, TARGET_ROOTWIN }; struct progress_t { GtkProgressBar *bar; guint timer; gboolean activity_mode; gdouble fraction; }; struct mem_t { guchar *memory; gsize size; guint32 base; }; struct _STlinkGUI { GObject parent_instance; /* < private > */ GtkWindow *window; GtkTreeView *devmem_treeview; GtkTreeView *filemem_treeview; GtkSpinner *spinner; GtkStatusbar *statusbar; GtkInfoBar *infobar; GtkLabel *infolabel; GtkNotebook *notebook; GtkFrame *device_frame; GtkLabel *chip_id_label; GtkLabel *core_id_label; GtkLabel *flash_size_label; GtkLabel *ram_size_label; GtkBox *devmem_box; GtkEntry *devmem_jmp_entry; GtkBox *filemem_box; GtkEntry *filemem_jmp_entry; GtkToolButton *open_button; GtkToolButton *connect_button; GtkToolButton *disconnect_button; GtkToolButton *flash_button; GtkToolButton *reset_button; GtkToolButton *export_button; GtkToolButton *erase_button; /* Flash dialog */ GtkDialog *flash_dialog; GtkButton *flash_dialog_ok; GtkButton *flash_dialog_cancel; GtkEntry *flash_dialog_entry; /* Erase dialog */ GtkDialog *erase_dialog; GtkButton *erase_dialog_ok; GtkButton *erase_dialog_cancel; struct progress_t progress; struct mem_t flash_mem; struct mem_t file_mem; gchar *error_message; gchar *filename; stlink_t *sl; }; struct _STlinkGUIClass { GObjectClass parent_class; /* class members */ }; GType stlink_gui_get_type(void); int32_t export_to_file(const char*filename, const struct mem_t flash_mem); #endif // GUI_H stlink-1.9.0/src/stlink-gui/icons/000077500000000000000000000000001526027543100170225ustar00rootroot00000000000000stlink-1.9.0/src/stlink-gui/icons/export-icons.sh000066400000000000000000000017571526027543100220220ustar00rootroot00000000000000#!/bin/sh # # create the XPM icon and all resolutions below hicolor as PNG APPNAME="stlink-gui" ORIGIN="stlink-gui_icon.svg" OUTDIR="hicolor" # possible size options are --export-dpi / --export-width / --export-height OPTS="-z --export-id-only" ID="scalable-icon" RESOLUTIONS="16 22 24 32 48 64 128 256" if ! [ -d $OUTDIR ]; then echo "output directory missing. Create it..." mkdir $OUTDIR for RES in $RESOLUTIONS; do mkdir -p $OUTDIR/${RES}x${RES}/apps done fi # create single app icon inkscape $OPTS --export-width=32 --export-id=$ID --export-png=$APPNAME.png $ORIGIN if [ $? != 0 ]; then exit 1; fi convert $APPNAME.png $APPNAME.xpm # create all the resolutions ALL="" for RES in $RESOLUTIONS; do inkscape $OPTS --export-width=$RES --export-id=$ID --export-png=$OUTDIR/${RES}x${RES}/apps/$APPNAME.png $ORIGIN ALL="$ALL $OUTDIR/${RES}x${RES}/apps/$APPNAME.png" done # this is for windows... #echo "build Windows icon from $ALL" #convert $ALL $APPNAME.ico exit 0 stlink-1.9.0/src/stlink-gui/icons/hicolor/000077500000000000000000000000001526027543100204615ustar00rootroot00000000000000stlink-1.9.0/src/stlink-gui/icons/hicolor/128x128/000077500000000000000000000000001526027543100214165ustar00rootroot00000000000000stlink-1.9.0/src/stlink-gui/icons/hicolor/128x128/apps/000077500000000000000000000000001526027543100223615ustar00rootroot00000000000000stlink-1.9.0/src/stlink-gui/icons/hicolor/128x128/apps/stlink-gui.png000066400000000000000000000157231526027543100251650ustar00rootroot00000000000000‰PNG  IHDR€€Ã>aËsBIT|dˆ pHYs'_'_†ºjtEXtSoftwarewww.inkscape.org›î<PIDATxœí�{XUUúÇ?<\D.¢H’†i *І˜x˼’•6c™Z3e¥eÍ#…¦9?-+3š²É.ÚÔXfMi–š…Š×PaòŠ÷+*ˆr¿~,àœ{ï³Ï ŽÊ÷yösöZï^ïûîó®ýÝk¯µöÚšÌÌÌjšqË©©hFÓ¢EíNII 'OžlJ_šaG8;;Œ———Q~]8sæ #GŽltÇšÑxÐjµÄÅÅ1nܸº¼æ[À-„’’bcc),,¬Ëk®·JJJHOO¯K7W€[:�®n¿…Âq i®¦5jÌôÀÜã­)×X¶ÕNÁÐUÊŠ•+€[ t[¡7jø+•§FF%�‡’t(½ UEPYUÅ +Ç9kÁ©´ð„î  €–m ¥ŸØwni_nÙ“ášžòëC¹È)6WV– 9;!7 ò�@U©I³ŠÐ¶¯ÛÁëðêÞw€WGÀI�Ÿg×CÆŽ†ÇÕ‡œÌ’2–ÈL¯õ�Q¯)ÇÁLW)ÅjkeÁaHÿ/\Mô÷«QrIlWöêó\Z�_(ø…�_whÝœœ¥ý+L‡+ÿ³�?M¯¶êâ û0@yœù²·©ruu%""‚þýï¥[·ntî‚��ÞÞÞx{{£Õj(**¢¼¼œ¼¼���<úèxžyfŠyçüòËU~+aüøñª�]³æ'JK­ì 7„�@`-äY ÆÝoRÕÅ‹™8q’>ø¾apû8ð뮞ÊöJs ÿ 䟆ÜÃ�ýGݘBVV‹ÈâÅßnvú¯……ô–´ ÷‹ÏL@€éaã¥K—qíÚ5‘¸ct™�ºÇ­¿ØÚEˆ´®®€¬=�ù;”^ ??_Þ÷ÚßÞϋ͜N®ú²³Ûaë&ÏY�î…ÞToÏ™ÌgÃýÒ,BBî0m ˆ�ß(v\[Ã�Á—³#ùÈiðëì mï�v÷@Øó�µNÿ Ù¨½-™­Ó™-Ñ„~ZÎè RP¹¿¿¿*5bÇ#XŒ÷××iiMwn· „¡àœ^ç6Z§ÓÊ+KléK£3@U9µWšÚV´»»»Ø©È“Ö©dO­¬U0ôš=¦€³³mt*É,…=|±ÀOó{k÷[¸�FüÁ†³L•зoÍý»ð<\ÚÑP§-¯—–àäÒÌ&`~O`ݾFL®^½jÚðâ‹ÓõEûÀ�·áÚa¨Ö5ÎUàH `{úi–3€pcû™ªÔDFFòÎ; E¢Z °û%Ø4RæÁùu�wJŒãKÙSò¥)dÖÂü4¯ P_±W�ãÔ©SdeehR]lì+„††;“´´4‘Y‘Y¿‹ ÀɼCÀ§‹˜ÚåÛUÌù«e�›!ørv¬õ³¾n0ï) ¾1Ÿ^pi ÕÕÕlÛ¶�ÇŸ JÝèÑ£5j$;wîä—_6��°…è»…uåpí¨ØjáÚ üºA›0•£™þ›˜|{Õ$ªùôÓÏTW�FàAƒ4hÙÙÙìÜù;ûöí#55•””T®_×O+£<_<ëgÕŒ xAðPè8¼:4Ý­ÁR8S™7P?Om"!{‰‰‰lÛ¶Ýâ@mÚ´á‘GÆñÈ#úOŸ>MJJ*{öìaçÎß9xð UUbÆ…�öµØÚö‚îOA›Pyßo�Ë“�u  :M‚l1÷é§§�’’Œ¯¯¯iË*BHHHÝœ¿¼¼<w±víZV¯þQß­|ù¸ü"EBø Ð*¨¡ŸJç`�Ì8˜÷ e´õÝ(‚Ξ=Ëc�M ¤¤D�u3áííMtôh–-[JVVkÖüÈС÷éÈH‚ø©pqw“_YªÑÄ~š× g44F<›7'0pà`}·¯�àææÆØ±“�°™­[·Ð¯_?!¨(‚ÿ€#ß5é•¥ 7hã÷½^ãù@JJ ½zõféÒeÆ/0Ø C† &1q'óæý_MGS5üño8¿³™LÀ6  <ÚýŸ‚o@´ê§N�FÏžá|óÍJ»ÝjáääÄüùóXµêœ���jØýä�¿µÛ&üTÏjŒºµ†ˆ8è< œÝ8rä“'?Aûö·ñ ÓÙ¶m;eeeªÌZ‚qãÆòÖ[oŠDe)ìÿÒ¼spôà›*/—'õ  Ö¨³ t} /‡ ûA#L\¿~�O>ù”ûîН¯?#FŒäÝwãHLL´9;ÌœKDDÍÀÓ…]�wμs0Wf),±×dmsÒ¶…ð9pÿJèú$¸ëߨ)..fÓ¦ÍÌšõ* ÂÛÛ‡ˆˆH^zéï|÷ݹråŠ:ïåÜÕhøÇ?æŠDµŽ­u<¨sÖF¾Xè§ú~9£¦dÚ¶pדÐu2\KƒìT±å­{�¬¢¢‚}ûö±oß>>úHL-gäÈŒ5’~ýúIÏúU@tôh‚‚‚ÄÓHÖÖ�ƒ\žµ°9 Ô—99‰¾ü»Ÿ„�ÿ‚1k!ê]øÓ_Åú—*·�Þû/Ës,°ûÿ©ÎOÛ?ØJ¦q†¶aÐwŒüDL >ýô3NŸ>mÒm??ƒ1‰Ò|û�ƒ¥pP®¦jWú¯�»ßþµ¹u„‹7Ž«ªªX¿þE·kѺuk}¢¢È± 7È)Î;{b`×ß!'Å6ÎÊÉÚõªséÔ©S&ÝŒ;œœ]lç‹­àð `%£¹‡`ÏLøý¸¼4ÕêÊ™#3xëØp¥K%½%Ô¢¥}þpkÑÄ  î)@­âkG!i¶˜ÇòE‰—=mq"WÕ™éÔ©“I·.\0X ѳ�yöÔȬElÅ@TT”>qý¤.„ �À¾·àÒ^㙾jtæ]†ÔOER£aìØ‡U¹|üøq}BiM=s|©/³�AÿvgëÖýÌ©S§X¸ðÖ®]'hºªÒ·ˆÍÍz�ð»ZwFJµ¹( În�c«¡LÐùSOý�Î�;›>3`ïÞš…$�]À·“ü9ÜÌ `ÂOuý*ßsÏ=¬Yó#ééé|ûíw¬\ù-‡ÕPwY¤o€Æ ÜÀ½ ´ô©YÀÊ ÅÐü‹Pl<&pÿýCU÷’˜¸K$Útº‰ät[ãK£3€ :tèÀ¬Y3™5k&dåÊoÙ°áWÒÒÒôS¿«uPtIl&àëëËË/Ç0kÖÌš±~Óøé§Ÿõ£Œû7ú½U  `S�B�bMŸE‹ÞáÊ•+ìÚµ›ýû÷sèÐ!Ξ=GFFÙÙÙFeÜÝÝéÚµ+Ý»wcÔ¨QDG�nð­%TWWóÞ{ÿ 'glúš@ÁAýŒû°d#®¤¤„ÒÒR|||,Sn€ÿû kqÇ`õ‹*ߌm°|±hC£6€V«µz±& P½òJ¬H8»BŸ'ì|kÏÝW¹•À²…"mI�6Ä™3gˆŽ£ïêó´î öoúo°l¡H öžn [¶l%*j çÎ��úCÏÇìó§Ú«XëKS2@÷îaôéÁÂ…ïpâÄ Ujm�‹/òÔSO3|ø²²ÄšEtèC_3ê>¾!ÀR_ìÖ0UóZ‹>öJ±\[jj*©©©Ì™ó!!!DEõ'**Ѝ¨þÜu×]êZþÁ€Î�ÀÑbOƱd[Me8}ú4§OŸæ«¯¾ÄËŸÝ»w£sçÎ[¾¾¾¸»»7hýWUU‘ŸŸÏõë×ÉÍÍåäÉS¤¥¥±wï^öìI¢  ÀØGïÛàÞàö¾�Þ°úë_ÿƳÏ>×P £ÊFöS Ö?8·«suº2Q2!û�Q'Ovv6[·ncëÖm²¦<<bkÛÍv:I†Ê`y?@³Lþבd&`y?€#�ä­,C…LÍ p£Ëš YfR¦…F F´ÌO|× [r tBC™Ѳ?ºÚtyÃtÀ]о—c^ujdI?Ö,¨-Q¦þ>@@0„ö·½/& üPž‡>W¯-ô1$?¡«€ÿ™¡ ûŸ!¨—^�#^YJ²í_A©ºE´è>PT€FfÛ~5Y©VÚC§£ËÌ…=|1UýÛ·oÅÓÓSR6{ö6oN0vFÁ¡‡zP¿xC=\¹’ÍèÑÑÆºLétTY "##Y²D~"kDD¤ñ‹.�̪*@Ïž=e¿úm´(¤‰àƒøºHïÞ½%uÍ)p„ Ú€Zµò’=ßh°í- V8$©Ç”ÎÆ”ÙàªSD#3€íÛ¶ ¾�Ž.3Í £Ç”NG”™ {VH¨/@ T0À±cÇY¶Lú‘ÐhyxGº’›’,õ¥¾NضÔ7*áЮ]»Øµk—yzLètH™¥°•/* ¹ p³2€J‡\Z¨÷¤erµÙ³Mã]­UePV Tƒ»·øÞà�Î*}iœ6€N™ R:7y�Ù'àʉ†:¤ôÔîß=ÜjÞ<ª®„»ád"d¤ÁõKâeÕZh[Aà�Ð9@åó““™ S:u:HM€ŠråÿÎp¿¤È a°rK l_¤~uå�ø¾yºÂþ �¡Ò:Ï&AÒróôÝ®np`ì^9òÇ–äÙT±%|½£aðàáÓÐÃßúûæÀ”N�¾]É›-TÞ0ø`�[€­ÚjiN-ò²àç×!ë¨Qv—.] ëA@@ÎÎÎäääpáB:ÉÉÉ”——ƒ®ö­…£¿Ã‹ÄdN9ŸìÅVDð£(Ñc FŽÁË/¿,Y<''‡ 7Ög"øŸ¾ŒŽ;Jê[ºt)«Wÿ(?¼ •bN¾V«eêÔç˜6m*wÞy§dÙÂÂB~þy-óæÍçÌ™3P˜ ÿ‰�'ã ¨KCŸl]ñëØS+ß�}b¼Å××—Ï>ûTö-êß~û�÷ßÿ@ŸÑÒ]qT²Ñ ((ˆûï*YTöýB…?52²/ݺu“,¯OÔðàAüç?_ÊVšZxzz2iÒDÆ�ÿ S¦<Êß@I¬~ ž_ ®-údëàW7 þæÍ —,¾jÕj–,ùXŸ1äaHÛ§Xì3lË«ÁVº€GOBÂf“Á7„««+_}µœ 9é°uyCŸlàŸQùj|£>ø_|ñ%&<.n[£'ÂÄ—Lš³}W°ƒ¶† ÌW_-W½ÄŒ‘+ ¼„öíÛ‹Œ½ë ¬Ð´Ÿfªù­ ~Š>ø ›dƒÿÁ‹yæ™gÅ75xäY÷´*“�Þ0[Ÿ tõèуŸ~Zƒ››yyy¬]»ŽcÇŽ‘››K»ví:ô>¢¢¢¿IàããClì+̘¥°?ú=,ï§¹0 þBHÙ€ŸŸ›7o¤W¯^’ÅæÍ›Ïo,¨ÑáÿƒÇ¨öÅqŸ”tš�àà`~ûmZ­–ùó_gÑ¢w)--5:æõ×ß 22’o¾ùš��Y]“'Oböì9¢üá¢Ø’Ì~uu53fÄðá‡5“Mœ[ÀS¯BÄ}fùrS·|}}‰�ÿÆŒy�×_£Aðk‘””Ä AC¸tI~Õ2???úöí+'ô�G¶`]¬xÛ(ø ›$ƒ_UUÅÓOOÑßÅžCßL_‡,ùS”‚¯R_lì+¸¸¸0mÚólÚTó íî &Ã�}Aë¹é°m9œI%##ƒ9s^ãË/¿�ÕÙ»w8;vì€òȹm;ûl†F8¼G<ò¡~Ïž=V^^Îĉ“ô�·-Ýaú›Ðµ§ER�ÃM¤ÓÅÅ…äädýð³—?Lù úŽß po·…ÂÄ·! #ßÿƒñ‚õ`ôÈ™{Iï“Õ `:øÅÅÅ<øàCúà{´‚˜8ãà›éKã<زgÌL¼ÿþúI—cb¡uÛ†:�]à.1'¿¸¸˜cÇŽÉê3ê€)-´é£ªŸŸ[¶l– ~^^#FŒbãÆM"ÃÛb?€NwKÛmf±ÞÀºuëE"° „Ü#¯³u`]¹K—.Ëê4š[f°–�•çìïïÏ–-› k ËÎÎfÈ�¡$&&Ö³>„ NÊÜ­Þ8pà€~¹Ø®ý•uººÖ•Sú�¥»»ÁZ†•å6a6IÿâÅ‹ 6BÏJ�·ÃŒ8ðñW¶«Ò‡Æéh"�‡Ö'»(ëláV'Vÿ%S…c¨„¿¿?›6ÅKÿÔ©S 6B¿ôÝí]àï‹ÀË[ùâp¸6@éÊÉ1òmå¯|µºXR°šÖ¯_+|€øø�úà Ôtð‘ØWÀMÝ0ZI¬¥»²Nu·YXxÎ ¼)ûÔ1}ú ,Xð†>cù"8ú?i{Ͷ~ P©¯²²RŸpr6Áú ×Y$룕ô×_còä'd¿ƒ4wîkÌ�ûšHT”Ã’¹p‴=3ƒ�ÁM|³uŒ¨ý(•$åZàß÷ßÿÀÓOOÑK¡,xƒW_�%奰x6œ”©fúbPéˆ*]Öß-v{é\¾ü+^}u¶¬|á·yé¥E¢¼>œ g�6´{Ó0€­u*Ê~Z€wß�cáÂwdå‹ÀóÏO‰’"xo&œ;ÞÐn34¢N³Êœ9¯±xñ‡Ò¦4–,ùˆçž{Vd”A\,œ7˜!m¦/ŽË¶n؃l|ŸÑP^~ù¾ýö;ÉÃ4 Ÿ|ò1“&MÅ…ðÏÙ�uÞØ/•¾43€£èìtüuhœÐét<ñÄ“¬Yó“ä¡NNN,_þý4µük°0FT‚æ6€‚Gf y?L˜ˆ1ÿI“&³}ûvÉÃ���Y±âkÆ�ÿ‹ÈÈ»‹fÂåL³|ifGÒ©AÌä}ðI@tH=øà䤤H^[ ÆŒy@däfÃÛ1��u0@c·,…=•= #Æ¢7sÔ¨hÒÒÒ$wuueõêUDG�W¯À›1�sÙÀA“úµެӰܸç` jNNÆ�àìÙ³’Å\]]Yµêî»oˆÈȹ oÇÂõ«&MÚ—êïÛBçÍÚ¨¯S£�'c b0™™™ fð]¤zÐjµ¬_¿ŽAƒ‰ŒKaAŒ˜k¨€�ìqK±G%µFOí¾“<;zDâ3<Ç�$77W²¸»»;6¬gÀ€"#3r•Y@å:�;ððð�”]¾l0{Fddd��°ER—Ñð­Ê?5)i¯ì žóçÏg(é4Ø?yò¤¬� ¦‹™ðóêÕ\Y]€¾ÿ_îÂiáÓçû±pê‡&:zŒñ(a=¼ôÒ‹>|˜k×®AEâ:—ßPU~x¬šÃôN×þJü)ññ‰�ßh¾®ú:kðÌ3ÏZ®KFçÒ¥ËXºt™u:k�ššÊ°aÃÍó±¾.·–ðòÛ¢…Ÿ~š¤¤$õ:ë ] n¼6€5:U2€ÍtZªOJ§‡ÌZín³ByÃp+0@µø0RÄS OJöÔH_Y.®0 ¾- M èù€úr¦t¶ï"6sÊ™Òé周Ng¿–•3%óo ÷©ô`ý÷�'Ýhµ_ ±Ç‰4Ël+Cb_¬ûxtcœH³L�LSï8•P¾ägÁ×�+" s�±Àùf;*Êä\Q,ª\t•�—i�G͸QPw pr²}§`3†±®ÛëСZ­V²@3nhµZ:tèP—®«žžžÄÅÅ5W‚›Z­–¸¸8£Ïÿh233�&£pá±àP3n8;;Œ———Q~ƒ ÐŒ[ Í-¿[ÿ+âý�„ß|IEND®B`‚stlink-1.9.0/src/stlink-gui/icons/hicolor/16x16/000077500000000000000000000000001526027543100212465ustar00rootroot00000000000000stlink-1.9.0/src/stlink-gui/icons/hicolor/16x16/apps/000077500000000000000000000000001526027543100222115ustar00rootroot00000000000000stlink-1.9.0/src/stlink-gui/icons/hicolor/16x16/apps/stlink-gui.png000066400000000000000000000014151526027543100250060ustar00rootroot00000000000000‰PNG  IHDRóÿasBIT|dˆ pHYsììŠnýrtEXtSoftwarewww.inkscape.org›î<ŠIDAT8�•’MHTa†Ÿ{çÏÉŸÔñÔ4ME12•Z¤E¢A"íÊvE«Dµ�‚„I-£v-wAXJjþf¤dæOM©i::3ÎŒwæÎmq¯ÓÎçããœ÷{Ïy_¡¥µ]yÿaö•ëÏT£ïþÌ'¥�¬˜o4T(¤'›ñøƒ Ú—˜vÆpñx4‚NT›´°±Ó“Òˆ¡¿]€çÌœ¬*`|ÖÍâªÃΊÁĶbÃåæÖ¥:Êg²-É`4ƒ^Ó«t¼äÚRYßò2»ìaΟ‚?ºb� ²q÷.I’NDAQåÓ®?|B[S•_Te�UŸUbŠO1)YH6Ð !ÍiTVÒg�øK\ÐÅtr'v~1nN"%è&ÕëÄ?Ú�pûn‡òæ]_Ø(ûÈõ5Õünà¦ÂÛÔIEND®B`‚stlink-1.9.0/src/stlink-gui/icons/hicolor/22x22/000077500000000000000000000000001526027543100212405ustar00rootroot00000000000000stlink-1.9.0/src/stlink-gui/icons/hicolor/22x22/apps/000077500000000000000000000000001526027543100222035ustar00rootroot00000000000000stlink-1.9.0/src/stlink-gui/icons/hicolor/22x22/apps/stlink-gui.png000066400000000000000000000021561526027543100250030ustar00rootroot00000000000000‰PNG  IHDRÄ´l;sBIT|dˆ pHYsÄĨ×ÄtEXtSoftwarewww.inkscape.org›î<ëIDAT8��•kL[eÇ=§wX¹S›¡T (¸1à qÂbF6Eû`¦‹f^&‰—³‹Æ9#cc&Æ 1’1Mç Í– 2˜�•)µÌ Еq\Jz ¥püÐRZ.F|“çä$ÏûüžÿûÞ“£¨¯o�/^jë¯Ë­È—•îFÙÚv…³�· Æ‚L¬8LRô j�ÉëgtV�G•ŒN”HVM+C�¢\TÊ (0dAr¹ÚóÔœ*§° ¿ß�ÝÞËã¯Õ! *ºêßC¥R­)¸³³‹ÝŸõ�V LÁh½6ªO?Ejj %ûŽ2áˆÖ)ÈL‰…ŒGˆá™£ï#‚ÏMÓ58�N^8~•.Ï” ôù )—ü‰ÓŒ±%ûn:¯þB§SËTbøUüèôB” F¾ŠHûûÜn7í>3³Æû ·,+žP˜ilnáÀþ½´Þ–HÝ—ßòÛ ‹Þ CñÅ�¢¥¤@dNW,€OŸÎÛu-tXí¼¸ÿÎTAEú”U|€-±lC`!4UQ榾˜Oû (:ÖJΞ78U}–ô´;Ùž� ÂâÁÁ§aº�{g?G/ýŠ´)»n¯ô°°(¯YüŸ¬Ð¨ éÜIn�ðC{7iŽ—ž}ŸÏÇ5Ç$ ÿÏã)m*OTT“aÒ“jJ 6Ö@Uu-W.¬†Ås?·�ûs·®Vú@Â!ëãqI~ˆŠƒé!Š¥VÆ'݉)Üc2Ð?ê¦Ë\€„–Kw#æMj:î`¡ 7(\± ŽQzùúã*’¢DXôrèé2N”?É–x‘­wqᣓ¤ ¶…Ž,#“c=ÏWÇ_aÊãaÌRˆ(Š72ò*)©wӠΧöR7ƒ�d�oËÊ áD*ߥ5¯Y§[ö8ÜŠp0û§s9ÞÈü¢è¿4L@’fQkԘ⠈>)T¿ÊŠP«0ÅK§‘r¤À68Ìž·Nóá›Gx¸¯an&°=/Û;Ök=ü1àäú|ÚÙ¿°wc»1‚+æfºš°÷ör+óA¢†zè±bs1‘�Âôåfì½×±=v�–Ú²� 8›1o6¡(ù�üÉåaH±,+q�÷õöün£�„h�ÞɃ$ Áq¿þ8àîwžnnõÙ>ûþöý~>Ÿ÷çù'ìÞ½[ihhàÿ ‹Å‚\__Ïš�ÕpS*ˆ€àB§tiðàòô8å�uàêg Éðð]¤ Î7âñx�3ClažãdÞz†å/.$11‡ÃAkkŸíØÃÇ�aDsŽío¿Œ,Ë×ôzå;%|›‡€!�ÒL'ØñÉFjödÑŠwD‘ÄØæd¦S~ôN·Âu¿"Iù¹�`2™øbç.δžÀf·CÂ�M€ó™Ó((ÞÆÑÐ<�°_bkÍ>þ M¦'*•7z½òO1óÎ?0™L”lÿžŸ é xOÁ@d]Ýv<šNEÕ—Øzµœ™D§ñ/˜HïéèI‹¬Õzó.áeÑ Ž„FR¹ÏŠÕÚÄ+/̧áÛŽó&ÍgÆ•2¤Á >ÃìO�o¢?€è½<©ŸÇ}Ï•roÎ"–¼¾–ŽŽNòŸ|Œý_oâG�Wn˜?ãB€«"Àîl‘³©!‡õ'&3cá6Ö•lE–e’�áA=у°ª®Ì—?ÄåG›'–^9šA1dÄÆ•Aèn Eª"¥hÞã9,}éiš››9ÙÔ¸¤™˜Í·Óræ,ÖN§¯ý‚Ep�øtalÙ³Ÿº#Ë­'1~,¿ün¥xC)¿µ+ü?G­,I¼·¥œò=uØÛÛ!åz€&”–ÐZ Ûí—@ú» 1ˆ‡ SÙ%Mõ~ÏÌð4� �$Ÿ&^© ©KÏ…ˆéLéúœP�–C†Y`ó¥%'ÜDÜÍQœPÂéJÍ Þ¦ã“â¨ÝQBDH?0Hº9‰¹fðô«‚ð”äXj?-Áà¸t�ùK£¡ì«*A€´ÅŒºxŒ˜îFú%®pF§�nq¶ �dµ®âÄX_‰Ö5ÀßçOã¾-Ò†HdÕkKؾy=¸û}¹kåûÌŽ“(J‹¢æƒ•Ô®~†äS»Tž*n“”ñÓê%L7†ã=I’TÍæ˜aò+VÆ=é¼U}šYùŒOIaB¤F5 ®c¨\[Äâ5ëØy‹™�°p_ TþäPuà0]æ‡èÑFàv»ÑI‚ê½¢t3UÕ5ü¨5â›lUàû3p) H ˆn·û*grŸz–ys&;¤­­% 0‚a�À¥8Áþ²“§ñà¢el(z•ìÎShûû€¡.úËÖNöóEôI£@£¡bï^ôzî¦ßAîÒU4µÚ ôQ<±¬˜¦6L„f{ÙK‹pD9lžAfÁ âÆÄuÖÊÀ8#Baa¡²¦¼âSÕ[Q8oôîd#…÷ÏBÎÊÊBÕ™úO(É‚Åbá_7hcçBf[IEND®B`‚stlink-1.9.0/src/stlink-gui/icons/hicolor/256x256/000077500000000000000000000000001526027543100214225ustar00rootroot00000000000000stlink-1.9.0/src/stlink-gui/icons/hicolor/256x256/apps/000077500000000000000000000000001526027543100223655ustar00rootroot00000000000000stlink-1.9.0/src/stlink-gui/icons/hicolor/256x256/apps/stlink-gui.png000066400000000000000000000343501526027543100251660ustar00rootroot00000000000000‰PNG  IHDR\r¨fsBIT|dˆ pHYsN½N½sjhtEXtSoftwarewww.inkscape.org›î< IDATxœí�y|EÚÇ¿3¹ÈAH Â%jÊAîûv�WuDÝ}w×]wÙ<^T.A@äRnÂÀH @€„„Ü×¼4�ÉLÏdŽžéš¤¿ŸÏ|’î_u÷ÓÕO=]U]]­KKK3 ¡¡Q-Ñ«m€†††zh@C££ �jŒ44ª1Þr+“““Ù»w¯»mÑÐÐP€€€"##iß¾=z½õ{¼l8t诼òŠKŒÓÐÐp‘‘‘,X°€Î�;[L£544ª(çÎ�cìØ±8pÀb-hhTaŠ‹‹™1ceee²º44ª8çÎ�ãøñ㲚44ª.\�]¯ �j@QQ‘ìz-hhTc´ ¡Q�Ñ€†F5Fv �í[ׂ€–¶§×9x[·sõþÕØNdÛÙNT»œÙNMÛÒÏB~–ƒ;r6¶�Vsï-fzr¢j%YP” E·ÀP¥¹wÖçeRbï ;ÛéÀ'¼À;¼ýÁ'ô¾âžŸ¦UmíÛÙ�¼Gq.£vFXÓŠ³ ç,ä^„ü‹�›ù—¥õeÅ8�w øÕßP¨5ê�D@@}ð¯zñòEÓªŽæ ÊkÆ(¡Ù›I%·!ó0d‡[Ç ÷à‰�Jr¥_nм®ó’‚@P#l A�!¸9Ôl^5Üã %9�ôµûäW;¥¹zÿîÖ\qŒàpè0T^sCá%€»£›%­$2öÀõ�q ÜÙ•ÂP y—¥Fã²uzlÁ‘P«5„¶…Ð(ÐùÈïǧ+ε4Ô!¢Ý½ T`²ç€ÚÕ�Ÿ —VÁµŸ ¬Ðšµâa(ƒœé—¶CZçå!ÑP»#Ôé¡m”­%hˆ‡Š×Ösûr’ å ¸y©³NY‚‚‚ðññ¡¬¬Œ¬,Ç{Yí¦´n“~¿zo©vP»½j·ßš÷Òk…ß³©r}®.üÅ™pá¸ú#öü€€¢££iÓ&š˜˜5jD½zõˆˆ¨O½zõð÷÷'$$Äâö¥¥¥dgg“™™Ivv6ÙÙÙܸq“´´4ÒÓÓ¹rå iiiœ?�óçÏSPP`—}²”•@æ)éwv…Ôl¨Ùâþ 5WLkk~jˆ�µ:åû\©]Ù–ÜyDW9áááÄÇ÷ G�<òH<111ètŽçž——¡¡¡„††Ú”^ çIJú�¤¤$’’’8}ú7’““)))qÌCdŸƒ¢,À(8˜×ÑÑÑ:f‹†Í¤¦¦’žžn9�;:.eP® ®« ”ä™pãçJMgÔ¨‘Œ;†îÝ»W:%’+iР 4 k×®Öçç瓘˜HBÂQŽ=JBÂQŽ9bñ…�JqânñÙgŸÐ¥KÇŽ«a3/½ô2|ðoyQë°¢å&é¿BAšÕÃ?øàƒLŸþ2£G�ÂÛ[Ù¸¦4þþþÄÆÆ{w]~~>¿þú+¿ü²‹={ö°wï>²³³+ß™ÖàÙh}V´ì“prŽô\ß>ø óæ½KÏž�Øh¬˜øûûÓ£‡Ô\©¿áĉüðÃ&^{íuù�Ík 1Q¡Àùú±­í{�5ó0$δXøëÕ«Ç'Ÿ|Ì�û<¾ðËáååÅ}÷ÝÇOL”O þª…J�uÝ×`)�œ–ó;œzÊä{Ñ{ö|„åË—ထUvi¸•:AÉ×�•j^‡“¯É~�NÇ?ÿù¶nýI+üåh}ž�Ö`ôYœzŠnšÂÛÛ›�?^j¹J\ÑšU �àl4KùrΘÂÛÛ›•+W0bÄp‡Í¬rh…¿j¡R€ë’ÛÛvÉ=—VÊ&ÿàƒi…ßZá÷l´>€2ø}¾4!‡ “'?ÇÔ©S1±J¢uz6*÷(œmÜØ#õü›Åûï¿ç¼}U­PµðøqŽ:dêr³Ýêõz>þx 5jÔpξªŠVø«J”#Pn>G�ÎÜ/{÷Ÿ8qݺusÊ<[ÉÏÏgÿþœ:uŠóçÏßù] ++‹ììlJKKÉÌ̼›¾üUáÀÀ@6lHxx="""hÔ¨QQQDEµ&** ???·Ø¯~G¥ÂJ*Çžvé•ïÍ’xyy1gÎ«ŠšdJrr2Ë–-gûöìß¿ŸÂBÛ'ÉÉÉ 33“K—.ɦÑëõDFFû qqqÄÅÅÒ©S'åk4Z€g£b ¨= ô6d4ÛÝØ±chÕª•"¦™²oß>Þ{ï}Ö­ûŽÒÒR— ¬¬Œ3gÎpæÌ¾úJšŠËÏÏ�®]¦wïÞôîý(÷ß?^^^ŽD�»Åöí;HM•bî¤qãF.y+qݺï(.Vz¸ß7¯åªÝj�¸þ‹ì¬¼“&MrÚ,SÒÓÓ™6íyV­Z­ø¾m¥°°�íÛw°}ûæÌy�°°0 ÈÈ‘#éׯ/þþþŽïÜÁª¢Å�ÜÌØ±cX±âÅ÷ûÔSOsëÖ-Å÷«8?À‘h–±×l7�5">¾‡bfœiÙl±% þ°Ýþí\¡mÿ8ÿ ªÑóeh7øÞ²;ÏÝUšƒ¸æÓ`¶-3Ç_ëÖÊ=úÛ±c'W®\1šŽ€ãÍmsçó „†Ý¥_Y1\? —wÂå_ì¢:¤§ÔBDÊòSùN@[Û¥ùWÍd«í];Ù±c‡ùJ/hù”¹-¦¸SÓû@ýXéwßópy7¤l†ôi pkˆrÎh"!R¾¸)?Õë(4ï˜S2¤¤È|¨3¬£ÔF)zÿïUšö–~¹W!y$ÿ u,š"ê9Ø£©�¨ùb�æ$Î=osæ„JóÌvW§N§Ì1Fvt[@õ/˜­ZP}èð Y q³!¸õ´Âï>ÍAÔé(+–­Þ(bÀÍ›æÓŠáln‹Üÿ"i^¾Ð¬/4ëWÁ™Õpå�xvÚ£©�¨ù¢B~ªÓ`a¶_%€ìÓ„b£)Æm±ÓMñ ­ƒˆXé—�"u$Šê�n¬Â*Š«}š�¨Ó 3þÀÏÏ×isʉˆ¨o¾2ó¤¹-¦Ë®pl¥µà&b9�›œUqD „*ÕÔyÀËGvvŽ�·‚ì›eYI�a20HÔ‹YÕ5µ5_ÜœŸÊO fº,§éå'ÊÈÏÏWÄ€Q£FÊ| ØGß„ÛçÍmébV7Í݈tî*Så? f‹Ñz_Й¿Ÿ••å´9å4kÖŒ>}z› …°g2üþ)g[·SÓ\¯©‰Úç.@MJÙiÁ­fªùÕ6K"ûìÞ þûß…ò3ð”ÁÙe°u,{n$Ü›oÏ9hšsšHˆ”/nÌOõæð«g¶ ¥@«V­xï½2M�;”Á¥Í°:l oBêfÈM5·[¤¨_4µ5_ÜœŸê½ à_²+H‰‰æo:Ë”)“ÑétL›ö|W®\aÏž½ìÙ³‡C‡sôèÑ»q d�“~¿¯”:v…F= üÐ{‹ëXU½ ö¹ �Ÿ®ë°ÅèºÝà̇fo.\ø_·S"""=z£G� ´´”¤¤$:ÌáÇ9|øG�%7×Ái¼Š²áü&éW#šõ…¡fcõ�GpgUµÏ]�š”ëæ´Eó¯uâàúþ «W¯^CBB�:uRÌ|„C‡Ý ve.È„ßVÀo+!ü>hó¨ÿ€¤9’Ÿž¤‰„Hùb�¦@þª7 üÿÆ#Í@YYÓ§Ï`Û¶­–ñ¨ˆ——íÚµ£]»v<ñÄD@š‚ú°òO†2Hú~œ,Õ ÊÉé<±ð›âŽöº«5Qo€éÿ1?ói¼RSSéÛ·?—.©ÿ k¥æÙg'qðà~ÜÏÈ‘#¬1ël~.lËéÜ쬊!R ¬ö}åøÖ‚v³@gnÒ©S§èÚµ;§N�rÜNA‰��eÍšÕœ“å:±Òg»dHII¡sç‡øòËeÎÙ((ÑÑѬ^½Š�;·Ó¡C © pô8ñ¥¸©~õ4pM€3'Ôü1h2\ö999Lœøüãã¶}îÛ‰��ç×_0{ö,¼¼Ìß•àØgðû�w&Ôv:­ð»N3ÅcúœÕÚLƒ¦–«Ã_}õ5mÚ´eÑ¢ÅËÏ0ìÉøúúòÎ;o³yó�„„„È':øoH7yB"R;_¤o ‘ò¥Z÷/ëõ3 ZÿI&¡Dff&S§N#::†Ï?ÿ‚ÒRÛ>·íI<úh/öìÙEãÆ�ÍECì~Šî¼§ Ò�K« ¨§Ù‰r¯›.+¡Eþ|Óü‹>F$''óä“OÙŠwß�Ç�7*³Ú£ˆ‰‰á§Ÿ6S·n]s1÷üú¿ê;�VøÅÐ@¼>S­ÞCÐm‰ôaO+\¼x‘Ù³_¥q㦌7žõë7PTTd‹åÂÅÆ�ëñõ•ùpJòOpÓLj„Hùâæü³ÀT«Qz:Ì”Z¡  €+V2lØp""òä“O±jÕjnݺeu;щ‹‹ã­·Þ4 eph±ô¿Hé)ýj·ó•М@Ì>YM�À#ŸCóQÒ·*!##ƒÏ?ÿ‚±c£nÝpzôx„×_ƒÜLvvv¥Û‹ÆË/¿D\\œ¹põÜÝ»››æô:èÞFú_TgÕ ¿k5¿À’æ_Úÿú¬€6“À?Üv[‘Þé?zô(‹-fâÄ'hÝ:šzõê3tè0Þ~ûvìØéäL@®¡[·nôíÛÇ\¸° ³ÅrH­ð»OsåçpwFøÕ‚Vã¡åc�þ+\ÞW÷@‰ýß¼~ý:6ldÆ�À½÷þ»v}˜îÝ»߃ˆˆ»÷«4Ó¦McË–Ÿ*®,-†Ë!òÎçÐÔvHQ ¿)"UßÕœ@ù9ÕÒtz¨ßYú•ÀÕýpmŸ ë,--娱c;vŒE‹¤Ž¶¨¨(âã{0xð`úôé-ÿé13hÐ@6lhþ–dÊž{ÀQ®Qeš»Qûܵ>i^5 Ñ#ÒÏP&}<ý0Ü8§ $OÞ~HJJ"))‰%K–R³fM Ș1c2d0>>òŸ=W½^Ï�!ƒùðÃ�* —Içküf¡Úw{QkjŸ» ùé¹}¶jz=„¶�¨Ç¡ë<òô\ §Aã^PG¹}û6ß|³‚Q£FÙŠyóæ»íqãàÁƒÍWçB¶Ñ÷Eº"~SDÊ7ç§òãÔΈÊ4�—ôŸ–#!îuð Z ÿ¢ÆA�R ÂNRSS™5k6M›6gÉ’¥ »÷a=ÔE~¾Äw‰�×–4‘)_TÈϪÓ`ªÙ“�þaàßt•´²iÿ›§àf"¤‡‚›V|�ììlþüççX¹r%_~ù…Ë: ÃÂÂhÑ¢çÎ�«(Ü< ­úV\状¦+4w#ªïÚ£9‰s@íÈgkT´WÓ{ßùÖ_´!­»�*õ!\;WJÕm+lÛ¶�Þ½û²sçvùqü о};ó�kòš´Rù"Ø�ËiÔöOAòÓ5ßP;#\¡7–~-�¡®†ÔŸ!åg驃 §N�¢_¿ìÝ»Û%O dß̽~ïµóL+üîÓ¤úõ(¡é} Aè< †Ÿ‘¾ò#CBBÿúײš³È€÷ì4Fí<³¤©�¨ùâ¦`ªì»jg„šo0ÄüÍdžÁï¼3—«W¯ÊjÎf>‰*Åybä‹-šÚ¸ûüÜ­Ù€²s#RF¸Có †‡_…–CÌ’Þ¾}›¯¿þÆÊÎ# À|eiaÅeµóÅVÍݸãü< & Þ8€‚ë�qBÜ»“Cšœ�æï%lܸÑl�³È~m¨¬TšA¸‚]˜/«­©‰Úç.P~ª×P˜û^„³àÖoêg Rš—DÄ”]»vSXXh¶Þ,�5Ћ—/¢"R¾¨�Ÿêõ”sýWØ=~}²Ï9·OQ´úæ_5...V|&ã¼<™!Íz0�MX”|‘[VQóÅ�ÁT�>\Ý ?? çÈÓe‘µ€:È¡tÈÍ•‹àíWqÙÕš»q÷ù šŸê�¨€®í‡ôƒÐ¨DM€À•o'šæ-ÿÌ?'Çúà!{‘­[©óðÎ¥("Ý<ÜœŸêÎ` C¤n†K[¡Awh9Fz¡ÇÙã¹K+ÈDŽ�ëóÚ‹l�Â7ÐÜ.Óeµ5‘)_TÈOeßPº-h(…Ë;¥_ív9F¯_ÞrQ;ã-i×ObŠN§£yóæfë�áâÅ‹æ+ƒêŠ›/rËj"j¾¸1˜º¦ `º¬„ÜL”~áФ?4ëWñU^a.ŠΚ?ò‹ŒŒ´ü•¹x1Å|eM“—�„É™e5qÅ9ˆ¤Ùˆ²‚”ãJ£ó®ÁoŸCÒ—P·4 ²ü ¯»3þôªŠóôßaذ¡V6rŒäädó•5�Æ ˆä�¢~g4‘‚«ƒ×0wî;|ñÅ—• ÜP&Íò“~X*üõã a<4è ÞöÛâ´f€“_ÃÑOÍLÕëõ<û¬üW�%55U~xqpC»0_ISQóÅMÍ1Þ0b̘Ñ$&gÓ¦èÓ§·ü¤¦”Àå_àà?aÃHØ=~_¿I�B);-i7“`û,HøøÞñŒ˜0áqZ·n]ùyØÁ¾}ûå…zÑê;¤VøÕÑ@¹ù4Z§ÓÑ¿?ú÷ïÇñãÇùàƒóÕW_Û6’®´®”~>�P§�ô~H$„FBPÄ=#=‡üëpù€ô:ð•ÃÍiذ!ï½· r»ídÿ~™P§bª”³*Ѝùâæü¾ C‡|úé'ÌŸ?�eË–óÉ'ŸrâĉÊ7,§8®�~åxHïöû×–Æíû×�€ºÒ(:ß@iBŸéͺÒ"(Í—æÜÏIƒìÔ{¿JfÆï¨]»¶}'m?ü°É|eý6—uwk"!R¾¸!?…ë°DíÚµyñÅxñÅ8xð Ÿ|ò)+W®rlÎ’<ÈHrÜˆŠŠbݺo‰ŽŽV|ßÇŽ#)IÆþ£!Èö8�µYGÔ;zuí°…¸¸8>úèC®]»Â¦M?ðÌ3¢Nùá·j0bÄpÜï’°jÕjó•:=4ïvçSÍÂÿjkj#j¾¸1˜ºæu`Óe9�¯¯/ýû÷céÒ%\½šÆ¶m[™9sqqqx{»¦uc�>}z³k×Ï|û킃ƒ]rŒ‚‚>ýô3s¡~;¬£¾Cj…_ÍA”o˜.»É ¼¼¼èÕ«'½zõ¤I8vïÞÃ/¿üÂáÇ9vì8éééŠ7**ŠÁƒ1vìù/÷*ÌçŸÁ•+WÌ…ñb9dU(üÖ¶Y³åo“‚tÕ¬Y“ú3`@ÿ»ë®^½Êñã'HLL$%%…K—.qéÒeRSS¹qãEE–¿2LDDÑÑQDEEѺukâã{вeKwœ ½R<¾ÌŸhe2™H)Rá·†HAÒMͱßP˜úõëS¿~}ù¯ëÞ!33“ââbrrr " €   7Zi™ Þ3Ÿ fÔ¨yoYm‡ìº[DÔ|qc€ç¼ à&BC¥Ù}ëÕ«§²%¹páo½õ¶¹àåFÝ[VÛ!=庋š/nÎOå§3]Ù <„¢¢"|¢ü m‡K� –Cºñ.f7"�»ÊÁTù�ªB[P0¦M{ž={ö˜ Aáû¤ô¿§vf‰„Hùâ¦üTN@ «¼ýö;,]ú±¼ØýEð‘™X¤»“È5@QóÅcúª‚Ìk¯½ÎÛo¿#/Fõƒ¦]¤ÿErHO¹î¢æ‹›ó³ÊŒ¨Jð /Z¾ó‡·…/Kÿ‹ê�žrÝEÊ�ìP¸*³iÓ�äää8m–§’˜˜HllgË…?¨ôû»Ôû/ªCzjSP¤¶¼Çô£€ÑÓ¦=OxxãÆ�gÍšo«M0ÈÉÉáoûbc;“˜˜(Ÿ(°. zÂÄr:79«âˆUª 9 //�+V²bÅJüüüxä‘x†ÊàÁƒhÒ¤‰ÆŠCQQ_|ñ%ýëß䇸–܆,€šõÅr:Omˆš/Z@E Ù¼y ›7oaêÔi´mÛ–^½zÒ³gOâã{È!׸|ù2}´„%K–VþÁ�ºQ0àM¨-–Ói…_ Í ” lºlM«Ù¢‡Ôí�›fóáNž<ÉÉ“'Y¸ð¿èõz:vìH·n]‰‹‹#..–V­ZÙ6�˜ ¤¥¥ñÝwëY»v-;v줤¤Äú:=tqOK“•ˆätU¡@ísw´€+˜‡Ê¾ dÏÉúAÛ§¥_æ)HÙ—vZü¨†eee$$$���pw]hh(±±Ò±cGÚ´iCÛ¶1´iÓ†š5kZÙ“kHIIaïÞ}ìß¿Ÿ={öräÈÊÊÌç ”%(™ �î—×EjË+à¬ßÿ‘‘­lKlÙÙÙ¶%)_Ü@]×`�#ý:N…ô#�º ÒöA‘�ψÌÌL¶lù‰-[~ª°¾I“&4mÚ”fÍšÒ¤I7nLãÆ�©];Œ°°0j×®mWsÂ`0pýúunܸÁ�7¸v-�ääd~ÿýw’’~'))‰7nØm?¾�pßxi|¿ñwþD½;)tWËÍÍ•ŸæÜUˆš/ÕªÀTÓë¡þƒÒ�2¸qB iûàvåsðY#%%…””víÚe1�N§»ûñŽ��t:z½///Š‹‹)))áöíÛdeeÙ~7·Ÿˆê÷ÿBM ³ðUÑÔDís¯¶}•jz¨ÛQúÝ÷œ®‘jéÇ¡0Ë9»e0 dfJM�ò¿.'¤±ôBOë¾ÒÝ_$ÇÒ ¿øš“(7ØtYi­fci&ßVä¹÷³ÎCúQ¸‘7ƒ\e?½íR‚Jó÷5ëõc¸{’"9VU/ü¦X³ÍS4£À^M§—æ÷�„¨;ïÂfJ�àæi¸• ·.@îUÙu¸�À:P/ÂÛI�za-¤õ"9�;µ˜>¥ž-�ÚˆU¬ ˆÕàŒV#>�º·¾´²S ë"ܾ yéRM!÷ºô·Ôò`Q£Ôj µICIÏðëÙvÕE‹ê tÖª 9�À} hÞ~ÖJúÉmW”#}ð£(ûÞÿÅy’V(uöa(•j^>€üïì»ø‡‚ˆTðkÔ8g…YIDATº“Æ�ç§išæd Po€šoø Ô·EÓ4ÍÒ²­š¸æ»"e`UÐLÑ´ê£9ê#6âš95MYMÔÀ¤ibhN Î|š¦išf¿æ$®›@¤LÒ4M«šh}šæ¹š)ÕYs­@ÓMÓ´ª¢9€Ö išæî»´+4Q¾@¤Œ÷ÍM«Zš»ýÇ |'n\=kz)c‰)ã·‚N&>Y;ñü°z¬kì1fü×Ò”]žâ UIû`<Ürñ«ßãÞ€ûzVn‹ˆš�(ÿqP¥qSFØ�Úº:k®Fíósc¾ˆ4Ñ4w_[SD:w䋸@sM³¦¹kÇIsq€%TÈ$‡Ž§iîÓ\�HÁÎ…�P±ùÞ~û-j×®m÷vGŽá£�–XN @M`æÌ´lÙÒnÛΟ?ÏܹïVnWe¶hš²š £F�¤oß¾ÖYà¹ç&c0,»2[DÒ@±ð‡?Œ§iÓ¦vo·fÍ·–€B1tèºuëf·m°lµEÓ”Õdèܹ3Ï>;©ò„2Lž<Å<Øj‹HšƒˆÛpsF8ŒHNP�4wà¨-îÖœ@ÜPŽæ šV™æ ì±Åƒ¡øÀÍA4M D:w…óEì ªƒ¨}¡«³ænD:w䋸@sMsaÕ×&D=÷jÕФzj¦¨]ËUsñ€1šƒTMÍZžH�ÐÅù"vµ ö…®Îš»éÜ]�/âÍA4Íž&‚+õÜÌe? æ p�—^šNHH-»�••m=�HNP�4w`íxž¢Ù€Ø@!9tè�BÙvþb9�¨š)®ÐÜ�»ÏÏÅù"v0Æ–Œð ‚®/«…=U++…¼L(Ê—~%R@õ­þ5!0Ôþ} xdzQƒ«Bù"n)s«¢vë œÝi§áƸqJ‹±ˆ·„F@ý–Ш-4»êM£ví¨}�lÕœ@ÜPŽ=Q” Ûÿáü1*K×û5µÿ‚­� X™}ÆQ»Œyt*Ôm.¿Ÿü,8ºNí€ëçíÛoI!\¿ ýNl•ÖÕkm{ƒƒ! DÞîê\ø‹ `Å�uÃúþí±Å”Ô³VTîkb{3¾´.q­MÜ9Ž#’š†2×ÙP˜cnË­+°ÿkHüI*ÈJ‘~^úíþ : €�CPhÅc›Úâ¬æ”hVÀGsàÌQ…Œ²†œQ¶ù™¸ *:ˆ»))€}_ÁÁ•PRäºãÀÁµpbôý3Ü×t&áŠ~ wàHÐrká—Ãö›Œ¸À˜ªæ î å(l|n_wß1ó³á»ùp挘-u BÕ¨ TÁžªšƒ¸CìývaSs£mÛ¶tïÞ�öíÛÓ†��‚ƒƒ©Q£äååqéÒeΟ?ϱcÇØ»w‰‰‰ÖgÒ=õ d¤Á„w¡fhE­ÊþWáÌ1×Ùeû›—b…dèÐ!Ô¯_ßîç§§³nÝw•ÛæDáôÑ^DFFÚm[^^Ë–-76-€ÌËV·mÖ¬S§NaÔ¨‘4oÞÜjZ€víÚUX¾xñ"+V¬dÑ¢Å\¼xQ~£«gá‹Wàé÷¥Çˆ \¸E\Pø»téB‡í2'55•M›~¬$•c}Kâï3gÎpø»²@Ag}æ™g7î1»mKKK“V dd$o½õ&£G�ÂËËËîc–Ó´iS^ye&/½ô>ÿü fÏ~•›7oš'¼v–¿O½ÞV\Mä&ž1–l)*€_…³ò…¿_¿¾¬[·–5jØ}È3gÎЧO?Ë jÖ‚Û™vï·ñ‡ƒç;Heš‹©Q£o½õ&‰‰Çyì±±N~c|||xæ™?qúôIz÷~T>QJ"lû¸âºªÔ paá?~ü8Ý»Ç[®eÝßšµ¶{¿Æˆ<ÝAä47ÒªU+öîÝÍœ9¯:ä„¶P·n]6mú�§Ÿ~J>ÁžU�œ ý_� ÿþý.üû÷ïç‘GzqíÚ5ù÷ƒ?ÿÍüi‹�ˆ<ÝAä472`@:H§N�\~,ooo–.]"ßœ1àû…PVro�È×Öڱ˗ ó+-ük×~ëPáß¶m;}úô#3ÓBÕþÑ‘ðä+àå|ñ7ˆì PøÇ�Çwß­#88ØmÇÔëõ|úé'´o/ÓÙ•~~Ý ý/r 5*þ9 ÿ€ý.üß}·žAƒ“““#Ÿ`ÈD7 ôÊd†¸À‘ ¿5é˜8qË–}‰���ûz¾új™ü±w¯„Ò’ŠëɳJ�ozç?§|á_¶l9£G�¡°Pf´¦Nc'ÃÐ'Íñ€§9ˆ-š ‰��géÒ%èõê]ÚvíÚ1uêsáÖ58ùó½eO«åÝ-üÇe78pk×~‹ŸŸŸÝ‡[´h1O<ñ$%%%æ¢^¦CŸ1ŠçƒØÀÓÄÍ…´jÕŠ5kVáëëk1Mff&ÇŽcß>i@OVV–Kl™3çUüýýÍ…Ã?H=íÚæÃâÙV ÿ·ß®q¨ð¿óÎ\¦N�FY™Ì³|o˜ô:tè’|7xšƒØ¢¹�ÐÐP6løŽÚµkWX_RRÂÚµë˜0a" 6&,¬÷Ýw??Ü�öí;FppýûàóÏ¿ ¨H™wêÖ­ËOL4΃œŒŠëÌÏ Ç+Ì“ ò Ùdƒ t¨ð f͚͜9¯É'ðñƒ)ÿ€±l›“ˆŒÝAä–ݤ|||X½zQQQwו••ñé§ŸÑ¢EKFŽŲeËIKK“ÝþöíÛlÞ¼…'Ÿ|ŠV­¢X½z�"v=õÔ“æ+ËÊàôž{Ë"7ñàNáÕjá_³fµÝ…¿¬¬Œ)S¦2oÞ|ùþ�ð—¹Ð¾³´ì"??ˆî å¨hç¢EÿK¯^=ï._¾|™GéÅŸþô ©©©ví+%%…1cÆòç??Gq±• Bl 66–-Z˜ Éw^”$€Ê¢£Ò;ÿàÁƒ*üÅÅÅL˜0‘?üH>AP-˜þ´îxÏc»Dì ºƒX:¶k%3fLç™gþtwùäÉ“<ø`»vírj¿K–,å©§ž–o—ÚˆN§£™a¬ç�‹mïþDÙ$ƒbõêUvþ‚‚F�ÍW_}-Ÿ ¤Ìü4m}Ïc»Lítq€ÈbíØn,üÆ åÝwçÞ]>wî={>ÊÕ«WÙÿòå_ñÁÿvj=zô0_yû&d¥ß[$˜Þ¥ Y.üC† vèÎûömĆ åÔm³þ šIËnðyq_2F4±t<7©��–/_v÷q_nn.Æ�àúu ïÿûÔ€˜xˆŒƒzÍ FåAöu8³Žü MìaÂ믿ÁOL4ë\´•.]:Ë ×R V=1¯íº¡ WV2d0«W[Ò"GFF âàÁƒò 4ƒ—æI5p[“RÜ@9":ˆnî 00ðîò¬Y³9yò¤|âö½áùå0t´ë)Íå\ê4…È¡ÿ4˜ú4ˆ2Û4??ŸÏ>û?‡ílÒ¤ AAAæBúqûw,þ¡C‡8Tø¯\¹B||OË…¿Y4ÌüÀráwá�Eì ªƒ˜_åÀtèÐ!-Z,/ö~†Ï‘¦õ¶fgH¸4�G­zf»øè£%Û¦Ó鈎Ž6n™4SDmâÝaèÐ!¬ZµÒîÂáºw�'1Q¾9ATG˜¾‚î Ùvs­RÜ r€@…à�7þ*?CÏCc¥Ÿœ-rvúÃÃæ/óœ={Ö©~…† ˜¯4~‡]°ü4eذ¡þÓ§OÓ½{<çÎ�“Oо3¼8jHË*ø¼¸ÀQD€ uþüy6oÞb.D´†^ÏTn‹©ÕEö8'NX¸ƒÙ€ìlLåƒ�D½¶w6l(+W®°»ð9r„øøž\ºtI>AlO˜úOi°�ZÀDu ?H=õ²wÿ¾S@ïm¿�!õÁ/Àlw'NÈ? ·…:u꘯ÌÏ»‰ >̡¿k×.zõêm¹C¶Ç`˜ôxõÁ«äçbÁä.*Ú);-XD4é`Ÿ-åšNµ™ÉÎ4dߌ+1d$R©ð¯Xñ�Ý…ÿÇ7Ó¿ÿ@ËïXô �¿:£¢çhá×ú,,»Aj%§OŸ&))É\hß»r[¬iæsXœœÂdŸ—§@�ü,gĈáÝùW¯^ðaÃÉËË“O0üiófñQ±ðƒÈÀÁÄâñܤŽI�Y«“>×åŒcÕ0lçL�� |^Á®íˆÃY±â»çRøôÓÏ7n¼üËT:Œ=n²ÞÂÿöhN"~ÌA,O…JB‚Lk5Ãl³Å’V>�·fëœF°k;rä‡ ÿÿþï"&Mz–ÒÒRsQ¯‡‰3 çðŠëm6VÛ>µ«ýÖP©àØ1™YiÂe^¾±ÅcÍ/ÐL¾}ÛÂU®@…k;rä¾ùæk» ÿßÿþ¦M{Þò»üþè:@™»½ Ê€¸C�í)TÕ´àÌ™³æ+Ã[Úf‹5ÍËÜ-dgªQ •ósÔ¨‘|ýõWv~ƒÁÀË/O·ü®„_ ˜üOˆy@ØÂ¢×ʤÀ™¡r3@¶§¹fmûl‘Ód¦sYðÀ°cÇNþýïÿXN0aº{ ¿“ù"~Ð ¿,ƒ�Û·o› ¾þÎ;–ÞüÃ!. \ÛüãïMžÚ«WOÞÿ=Ë Ö~ æô­À&pYèÌÍÍ•ït2Äc�-Æš»€-¶¸˜�Û=iJ9ùË‹Ì�û޼xó¼72ï ´ nP©cÍnT²Óâ¼ñ¾¦£¶Ç±ÜÙ¨Ìú‹/Ò·oË£ö*aÖ¬WøÇ?þ./^Oƒ÷f@¶Ñw*ü r0F« ˜aq¦žòfÎ8–ÎÜ-dkJ Àµýí·ßèÝ»¯ÃcÞxãu^{m޼x-æ¿ YÂ~ð„ €ƒÈ"@3À".èpIèÚ?~œaÃFXÅW o¾ùOf̘./^M…Í‚œì{ëõ­ÀÍÕTåÂ/§¹ €1»víbøðò_æ±�ùóç1sæ yñÒ9X0r³í;?­±œÕ­¯BYT¾Ö?ý´•ñãÿàp�çÝwç2eÊdy1õ,˜ ¹FOo´>;É‘«zMÀè×®]ÇäÉSä_³®�NÇÂ…ÿ±ü©ô”3ðŸ×¤/ p�Ä:ˆìñªB¡ò;ÝÀÒ¥ó—¿¼äжz½ž¥K—ðøã”Op&ÞŸ%Pµ©&vÕAªb¡R³ Òµ5â?ÿYÈÛo[xÎ_ z½žÿû¿Ï?~œ|‚3‰ðŸ7 È¤¿ÁÍ5\q€¨…ßO´ÓÍÝfçk¯½îð·¼¼¼øòË/;vŒ|‚SG`áP|çb­ÀDr‘l±v|‘k@_~yºÃS£—�!CË'H< ÿ ¥Î�äd¾ˆDu�ªX¨<ÅN7c0˜4éYÖ¬ùÖ¡í}}}Y½zƒ ”Opü ,~ÊŸ"ŸàÐ.X: V¾Å¨õØ ¹Qíô”ÂoŠͪ€óY‘ y0ª ¸°V)~ÑAäŽ'R3@ëpТ­4£�·ù\7oÞ¤oßþ$'';´ûÀÀ@6løŽØØXù¿l‚ÏþƒÖ ûe𻩠…ÊSìt'1À¤×e_�NKK£OŸ~¤¥¥9´ëZµj±eË�<ðÀò v|ËU\ç‚|7x‚ƒ˜_$;=¥@ô uwxb&æò¿Crr2ýú àæÍ›æÛÚ@HH›6}O»víäl^Ë߳ňÊÉYMµP™"r€1"Ùi|¼‡ûÁcSd“%&&2pà`ùéÙl nݺlÛö111ò 6­‚µŸ[¶ÍIÄƈê öhî@k8‡œ-½GÁÀ?È&?xð Æ §  À¡ÃÕ«W�íÛ·ÊF`Íç°n™¹mZ€ÍÕTÅBå)ùénŒ�?êè3J6ÙŽ;yì±qO�Ζ-?Ò¼ysù«>…�_ËÛåâQ�ÕQí¬Š…_„`úØèÖ_6ùúõxê©§-O×V �7fçÎí4kÖL>Á7ÖuíÛâ€r<ÍAlÑ\�§~SDjVY:žNO΀äŸã/[¶œçŸÁáÃ6iÒ„Ÿ~ÚLƒ ÌEƒ>_[×;¼SÄÆx‚ƒT¦¹‘íôÄÀ¤Cz,8iDw”M¾hÑbÞx㯮eË–ìØ±�ˆˆsÑ`€Ïþ Û6j}5WSk%j2‘®­)–lñõƒß‚æòwo¾ùóç/pø°­[·fóæMÔ©SÇ\4à“`×V‡÷_ޏ@ÔÂoЍvzJ3@ä U™-5àå¹Ð ™ìæ³fÍféÒ�>|ûöíÙºu aaa梡 Ï…Lç¾Ú,n(ǓĒæj´Âï<¶6�‚‚á•yP×¼ºn0˜ß@¨ÕðÞ²RÈÑŒ÷ò†ðÖ®³Åø8•Ù"§5hm}ÖWGl1ÅÏßù �Z;o‹5jÖrÌΆÍ!¨–²¶˜î#¨¦ó…¿üÿ¾# °þì˜-•qõ2äåV²3˃€;NÑϽwÓãÊýïJ- &~(†-rÿOZ$Ž-Ö´N½àþ^bØbº<õmËš«Žoíx¶hCÆÃÐñÊØbºˆšIš¦iUQS瀨™¤iš¦”fŠHšh}šæ¹ÀšH×Å(Û�[Ö4ÏÖD*ÕYsÎ�¸zÖM·¬;z®ÞNT»œÙNdÛÙNT»œÙÎ…úÂY§6w.dAêa§v¡¡¡¡âÖÐÐp9ZÐШÆh@C£#|}}Ým‡††† ±T¦e€ÅOihhx$–Ê´lèС‘‘‘®´GCCÃMDFFÒ¡CYM6èõz,X€���K ÓÐÐp->>>,X°½^¾»Ïb'`çÎ�Y¹r¥VÐÐðP"##Y¹r%�;w¶˜F—––fuá²²2Nœ8Á¹sçÈËËSÜH e  22’öíÛ[¼ó—SiÐÐШºhã44ª1ZÐШÆh@C££ �jÌÿ±†Fo/a…IEND®B`‚stlink-1.9.0/src/stlink-gui/icons/hicolor/32x32/000077500000000000000000000000001526027543100212425ustar00rootroot00000000000000stlink-1.9.0/src/stlink-gui/icons/hicolor/32x32/apps/000077500000000000000000000000001526027543100222055ustar00rootroot00000000000000stlink-1.9.0/src/stlink-gui/icons/hicolor/32x32/apps/stlink-gui.png000066400000000000000000000033341526027543100250040ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYs Ø ØÇ ¹­tEXtSoftwarewww.inkscape.org›î<YIDATX…½—PT×Ç?ïíoØe³€‚@""Ú®I\£LØÑAjø¡fR…ª£�É£M­I&¦:Ñ2mÇN´Ék4šV£¦Õˆ&£&BHŒ´j­É4C+m­RmQ)P²À²»ìã½þ±+°ì.bÇæÎÜyï�{Ï9ßû=÷œw¯põêU¥¶¶–¯» ‚@vv6êššJV®D£5GÆ¢=V/чüžŽ–•¡P©tømƒH Km$y?Á¤r£�~IÆíSpëÒqêFI˜†¹­“»vÈÑhO<¹›@ÕžH’ :×xk™®¯äÈobµZCQûý\¹r…¥«6R?n&o7ªËÑétc"Ä^PD‡¨†d#(LôŸäó/>Å`0ÐÔÔÄû'*èpº˜’‘†íQ+YYYhtúÀ|êëëÑjµƒf’’’ˆ��àÖ­[!|Þ¾!–CA¡·�¼Ül N§“œ…%4¡hÇÁÙÛÄËÄì}…^�&A§9‹y«ß¤Øëø7û_}žeË–ðxîB4Sæ …@“ÀzI™0‡ÃAf”øi Ñ�NÑŽSxZAwÊ\ÜâÜ!£º?„¬8&e2M¶’À˜Š¡yÈ!o±©Ôüí*S§Ne÷æg°{÷’Þø:‰-G¡ë2˜’C�E0ÚèóBè-\ºÞÁ¥š¿°bY1_ž?ÅÍšÓœÝÿ¯ØdÔmEÕ}=Ü Šð´ˆ¼ú¨DhIzŽE«¶²¼äy.^üI’E›ÍÆ?ÿ —/V0£·|Îp£‘òþž�‘Û×q¼%‡ÅO�ùøbfå~›½`4yëµRh»p÷ÆG€ Û„x`NS ]æ%t© A`Ó;GȘ˜Êü¬V+±ý­tÝBø:_·m|­æ'�ÆÛ@ŒA@P U—Ë…¬Öß—„`qñR¶o-åÝCÇøì|]N7j•ÀwW>ÅüÂŽ�¬ ÝüÈÿ£¡ù?�ȲÌúukY¿nmØ‚ª~{Ž_½ɾéÿÀ€1™sŽob+\�Eë%ÁGZêâLFšo·RWßH«æ!:fýD!ܨZÃ�_ßɶýGðš{ jð¥æÒ$æÒ$øÀÙ í^ˆ™Ó-Ñ ŠÀ7fSg�9ïï æög ‚_gÁ?ÁŽØý/ô½7A€~c ’1=º±ůn o¯ èZ’‘2½ô:6%Pñ³ì:"Œëþ3¿,±òáÆy$·�½ûІõøævN¦bMþQ5¶B4sæLòóóÕÚAiww7���ÃB4Æ.€ÝžM~~öJÄ=p§S§M�ÂË»Ëß)ÓJíס§-ðžø ¢ÏE‚ó}z3îÉvˆ‹�œ " yáZõà¸"Ë¡ ŒTHRZØõRǶ|Ÿ4ÿ-!­©Š#+&³§0�˜S?b}F7ç·¿Hù …<ú§}ÐÕ¹H^ROíàÀì4v>l&±ê=QÀ‚óY²ä;!²ââ"ž|r!¥ÖÑÐÜʉOªÈË{‚O�$åryØ_QòyHýèœØ±…yßÊåíãå8^|íî!ˆHcP6iÒ$>8s�Ú¬ïwá,ùs¾ ''“ì ÓuýóïüîÌiŒF#yO¯¦aùË`¶Œ`„³PÁÖÞÞN§.,I¸,ÑÒÒ €V%„éVžú�¶é¤?2ƒ¯^ÚqæYÉÙ( ôôô ëb‚ÕO…Çç‹ ~ó–­ˆ¢ÈÞ]o’Ty�#§á½0"#Ȇé^¾ÙÀ‚åO³há|v­}–äã{Ǻ`‹‚HÎFa%š®9c _N�CÑ3«ø¸ì’,³þ7oã@–¶ïÞGÙG§q»{%YQ(}uƸ8ü ˆÐ/+¬ÙPЧ¯¿¢ 8XvŒ —þŠ£5pZ–Pøé¶Xé�ñM{Œß{]Ì]TLff&¦Æ¸5EA8|ø°²ê¹5 ¬øuÀ F q‰àï�þž€Lo“<] /1F0ÆÁ€ÜÁó¡Z ‰ãÁÛ W % x øëv€Ü¨6<Ë�}{Q«Õjü>4'Šûp �6ÏïïG§Ó!444(ÕÕÕ(Š2F+÷§Ý¹žÿ¸hmšîtIEND®B`‚stlink-1.9.0/src/stlink-gui/icons/hicolor/48x48/000077500000000000000000000000001526027543100212605ustar00rootroot00000000000000stlink-1.9.0/src/stlink-gui/icons/hicolor/48x48/apps/000077500000000000000000000000001526027543100222235ustar00rootroot00000000000000stlink-1.9.0/src/stlink-gui/icons/hicolor/48x48/apps/stlink-gui.png000066400000000000000000000052231526027543100250210ustar00rootroot00000000000000‰PNG  IHDR00Wù‡sBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î< IDATh�Õ˜{T”uÇ?ï;7˜uÀ ®šQ‘”w¼m¬i©ÔVj™]´©]3Å xEM[S«õTkn¶§£v£6]s-MÝh%¸jn†)d^@æÎ̼û0Ì;Ì ƒzŽ»Ï9ïygæ¹~Ÿçù=ïóŽPZZ*ñLJ€�b6›ov,m¢””¶nÝÚÀd2QWg…„0-Ü ¹&»™üü| ±(´pÏn}ï¦S¨MùhëKð8ª‘Üõˆ=‚ºne;,ªx ‰`¸4:¯žòÌßPŠîfÇ‚ÏE�»?_— Ä5xZC,"°i¼7ìfþÀQ†þÒF¢"-ÌšñC§‹F£¡¦¦†ÊÊ*®^½Já±|“ÿwŠòN!Åÿû³Aáì§,Y–�J¥ #½�Éét²zí::M. ߬;+О]ÀŠeó˜7w¢(u2uêäæ~ÊŒ%[°7ÙæÍ›‹V«½f‹¥€oWø€hY�F!Ý•wÈ|)�ù™se"\¸p‡Ã�Á` oß¾¨Õj¹×&G7’|“ëC�[ÈU‹Çøo²³¾ð²ÊÊʘðÐcœ>ý#šÝD§ [M)}“x|âƒh##d-èAbؽ *ZVoNƳ<ýôSÞï;v|Àkoÿµ…œÇãA’¤–ç# €&”æ"îî?�ˆˆ/kfÆ~0õÅ5r%vQl–•œœ®þ‘5;Ã…¯cû{3å±–xä™�s_QRR"s]RRÂq£)ñþ–g±ç#ò  IÈUClLWëlñ/¸¢¦�(Ê�+ÔÐõn1wÃí3ÀôK³£Øä–M*NµÈ4âà7÷ÈåME¿œË¿ €JKm­IÆš;;]ÑZÅïCÍ)ðØå‡JTÐ)Qþ[ B�¹@WPMíúPPp—ËåeeÌšIþ¡=¼8®3‰µÛPïŸHûog¡.Ú•'Ap´•ú:x1 ²6·¶Þô¦L899™×6®ãôßc1Ws`÷vML ¡rÚ}O"žß^Á@„£V ‰`¾å%–­z••«Öàt:[øR*• 0€U+—Stª€Ã‡þÉ­æýDþðV›³ØD°+dü•u1Øúobý{ûèÓƒiÏe°ÿ×X­Ö€~“““)øö:Ö�„²ÂЄª@k•k€¯pdg,w­ÂÔÿu¶(™ô\†è.$Ü9€ù ³9~ü¸L]¯×³zÅbÚ]ÒJáœ�ÕB²»>OŸIÔÚHý¸Ïù¹ëtÞø²œ£ÓXº|•ÌĈѪÎÞØ ëûfÀz*òA�Z*«ÔÐùNÜw>ƒ%u36lÀápxM \vsèÚÚBm£õÕP¸ýwpqxlA³)ˆŠ†G}#�FTºa0�m�W “°á•¬ã-¾Ûÿ6š˜;¨ÓöÁÑ”D[9ÚÒƒ¼ðâlÙÊQPPˆÝëúZ¨ ºA·QA7îÆ�{£ÑÈáÃG((<Ư˰Ù+éÕ#ž‡ú�!C†ÈL¼þæfL±#¯ý9ÐÚÖ6êç ::š´´ ¤¥Mâ¹�V¬|™Ÿ.aBjØ´ð߯‡`àRk9w¶ˆA)÷2eÒï1býúõ øfåt:9pà /¯ÛÈÉs¥Xî[Ó°ðµ2Ëív;ÕÕÕ^;v»=|¾˜KKK¥„„êl˜°G¶&SqŒc!jã°V] ºK,;vB¯×aw8©6)¿ü+‘q Ôõ�tÛý P´ÀÑÑ~Ü2ƒ'!�šXÏ÷söxÚ©DΜ9¤…D@PCüPì݇bÉE…õ õuà²A”zè!µ;õJUè©ãÌÐ)8†MiÛÔ ÒÞA§P‹K¡„ñá; g+ 6÷¯e ‚„æÌ»^£n ꃈv`¾„úü—4½×K8bB\¿k Àç.žÜ‹ºæ²×¯Ë®ûg´}•ˆÔ¨w«�œ©Iä<‘„úüpY”,åt©ùžœÉIäLNb�î2\ýé†d·ýÙ<¦öŽ gl9c’pýëƒÖmªÀرcIOŸ À†7ÞÆâã(¶[w-Z@ùÕ*ò›®½uüd&OžÌ˜1÷�••}2òqzé|Iƒq ?/Ä~7æ<óf …ФdèFYÜXÖªn4rtë×zv]v¸z\NèÔ ]Ã[)Z«\Øš”L—¡Àï?›”tˆK”[Âe«ó²4q}‘ú¤ ßE�[zÓ¾�žŸ÷áŽî†yÂBˆê0›-g6¢Ý¼ë¥_äa)HJ�W4¬, þ[$É�$¹™›9_–…(P]]…$¹9zô;¥gQNqÑ)ŠNåhÞAŒå—Èž> ÝG‹Áí ÝF�Áë6/dAút$É�Ãa#í‘GÑÝ5I­F„VøƒÅ÷£ÔÔTÞ|}=»výƒÝ»¿@’$DQdqÖBúßÞáÔ¡Ð-T×ü¬éä,[‚ÍfcÌ„9p±Ë «e¢­æÈ·/}(>>žôôt�Íüm_3õ¥¥¼0'ÓËbâÃD^) ÙBºw°0ãYV,]ŒÉdbÄè±µ)°Î\ ~ûصW ¸˜˜2³—bŸ…uÌlêÍaû¶m^~Ïž=Q›ÊC®Ö 3žcù’l*++<ò^~ÔvÁöÌüæ=ˇ›B­�;*++£º¦z5N)½«©I’�èè(°™ƒÚ}啵de-¢ªªŠ�ÃFQÚ;ç£éAvý-äÇ»rå *C§f]Q@T©š×åà4š†éÅÐ!ƒP]:õŽ -@° „˜Ën·APÈ ‚ˆÇã Ëvfæ|ÞÝú¢(²í½w{{´[V‚§> |h¾Áû½µYŒÄ®$IÌÉZJnîg( >Þþ>©½âо³$× l¡A„ªP ~²þq-Óžÿ{÷~‰R©dç'‘Ú½+ÚÍk@r·@¨CÜ–u ”í@ß ëó9LzòiòòòP(|öáv†Di‰üËZ™¨l ;vŒÜÜ(6«,cåUrs?àç¢"âdYܹs:�Žââby€�üÏ?߉F£iæûØÎËË£¶¶V®w"–ÙŒx"›6¼ŠN§cÚ”Ç91/³aœÒð_”÷�ØbwÙw˜7+.�„cÔlР²˜Èc ŠÍ)³Ü– ) ‚ú‹õ¨<o`NC õcš_JÔŸü •Oÿ:£c¨Okà+¿Ú�¦¼yש—<83–{Á 'Ž ýþ ¬Zõ…GPP\|Îç¥Þá�Y{Z_eýß�îðÌxÚ)ý_ê�VØ’Ö\ÞpèfÉÙ­ ×�g`øðá9r$Líÿjßž”” ñ Üäp®‹þ ô Qÿ0Zš…IEND®B`‚stlink-1.9.0/src/stlink-gui/icons/hicolor/64x64/000077500000000000000000000000001526027543100212545ustar00rootroot00000000000000stlink-1.9.0/src/stlink-gui/icons/hicolor/64x64/apps/000077500000000000000000000000001526027543100222175ustar00rootroot00000000000000stlink-1.9.0/src/stlink-gui/icons/hicolor/64x64/apps/stlink-gui.png000066400000000000000000000066511526027543100250230ustar00rootroot00000000000000‰PNG  IHDR@@ªiqÞsBIT|dˆ pHYs¯¯cæŽÃtEXtSoftwarewww.inkscape.org›î< &IDATxœå›ytTU¶Æ·†¤H*Tè�`*Œ ‘) �ÁAy d´…ç�vPº­�øl£Mƒ‚  CHdlå@òH@BŠ!!S¥†[uß*¹U•ªÊ„ðÜk�UwøÎ>{wïsÎ=ç–�ŸŸ/ñÀŽ;øî»ï~m[„„0cÆ Âœթo[¦2@¢¬¬ À…UtþÚv-Š{Jlp÷4”þ„Âø3*{)‚­ÜP¨U:lÍ!H¡m Y<¨ƒÝõ™n‚ádÕ9.¿®×½Ý«éºR íÊ}X9 L%U.{dÊSÁ×SQlG¬¸M«˜8žêû$‘‘� ÓéEQ)(( 7ï9öQ�³APÚKH<Ò£!¢³C_iœþmˆ„º†BÍbµš%¶ÝÉ©&þ`+A�³Ê/2ûõ¦N�BLLŒO# §NeqêÔ)V¬\ÅCShÑYfÈõ_riÚ´i�œô&Ÿ|òw¦ÏzÝÔ‹o$ ªìyDh�8žEÛ¶mý6¢E‹ 2˜!C“¶'�;EÞ�i©7×SQ›¯røÔbccÕ˜F�é\%Þ À†êÆ6Þœ7ÇÍy£ÑȆ ÿ`ËçÛøùÒÏÜ-*D!„èšñÄñt}²#½{÷¦ÿ#$$Ä]¥ìܹ‹&MšÔhtt‰‰‰n×SS·#I5Ïá²²²|:’sˆæ&Nœ ƒ˜Íf’zöåÜùllá=‘š�½°sG,ãĵ\NedÅÊU(•JNÆ`(Í£nƼôÒ¤�3f´GÆ??›(z­+z}jE€1]hqqq2HZÚn~üñ,ö¤� Õ{dÚ"b1bÁ÷ìý×^Ä›yß­ Õ &ò>äZ\³w0p<ÑϽ^e‘êÖ»„5oî1 ¨4:,Áž�w–@<61f_S¡w¼{µ×[qÎcä¢ðªP¡DôfII=°‹àâËü3 Y,è»ùopC:ïE§w4á ò±X,2H§N�X»v5ZCÂ�çPŸç×B~&¯×ͰºPjE@hfS™™ßºÁ¦Lù~¹v…/>ßÌäOÑ6ð<ÊÓïÁþQgŒAqr1\;vsã‘Ðúä}€+8(UxWþémúõ{•J×étŒ7–qãÆ`2™8sæ ÇŽgÿ�ƒdú+ÂAˆ­Ç@ÛÑ  |ÈR@±õtΜý‘—&ý;f³Ù«=�†ÄÄDæÎ�Ã�ýéäç_cÁ)]Ú†úСâæC–ƒ­Ób¶mÿš„Ž]HKÛ�Ýn÷˶ˆˆÞ~{çþç ±á¨�,›é�Jß@xWÄÄÕ\.mΰaÃ‰ŠŽ!%å5vïÞCQQ‘O"bbbÈØ—†Úd€œ]W 8ÇÏ`=¶.‹á™MhŸfõæ} 6œ°°pbãÛ1eÊTRS·S\\ìÑÖ–-[2cÚT®ìu›°xlï�I·”xÚOÁÒk- ÙŽÔc —•]Ø”v’±ãžGÝŠ÷ß_æÑÖääd,…× âNç@IõAÄSÑ„‚>¢± €µã¥ÝÌ›¿€ððp&Ož$Só˜ã â6hÃ~�pÑë= € ÁZâŸâÀhÿ<öVýøâËmnª5�ãÀfi˜> .$¸ˆwlF¸ð)ÊCá?ómÿQPZVî¦úöíÛŽƒ&º†O�F! ²Â¼7R½•��>Õ‰9p%ÍñrƒÝ…° ¸˜†2÷ãÇŽrS�“sA¡mxÃD@àcAÄ!óçÏcÁ‚ùìÝ»�MŸ~Æ�ƒë©(/C¡ DŠØÉ\‚h,B©˜9s³fÍtS�žžŽ*²=Ö€&L øî+E£Ñ0räsŒù6›�óçÏsöìܺu‹;wî†^¯gР�„††º©ÍËËãÓ϶`í>­^×ËùúP]”J% $$$ø°Ð!åååŒ7B�vCÆyO¶6V°lÙdggû嬫deeñû½8óSÖþï€JU³q®c¹?Ò à nq#X²l%‹½�>º%}{?M�‰ÄÇÇKxx8ÁÁÁX­VŠŠŠÈÎÎæôé3|±5•ÿþþ_(£;!]¡Qµ68;;‡¥Kßw3Ü.U뀽M‚ê•AáÐùU¬Ì„Ÿȿy†­ßžcëö]ˆ¦2¹"u¢µjáD¤ÃÕ iðRÄG»€ Ôþi5ãÂÕŸYôÁJwÛEb ô£3õU~Ξ ˆ÷®YîBÙu°”�Í„h·@@0Ah4Vmóºåhõ2ðUÌuyÊ ÞJ“P õ�õ©¸Hí_†öâ"²lT'æÊ€ ¶ê�p\—D‡ÞB©”k³K`ëú2D´i4ã…-o¡ÂVÍàÊvû¾±ëO@€ZIÛ6ºwïæ¼öåÖ¯()ëP¥@’°çŸ¦ÿÀ´jÕ ‹ÅÂÆ�› al£>=!÷,={ö uëÖNûÖ­[Ýk1·p!Á­4h ï½÷®óüзÇ(ñ `úôé > €’’÷!|'OžÌ‹/¾ '€º9žú€šÄ‹Æß…‰:àÓ¶ú¤€ß à˜nÙ²pL€êdŒ¿äÔ°­uÿ¨ÞˆB€˜Þ¿ܸUu/¶77«›ó¢ 5u�€šHðDj­ ð¤@p¹ï [˜ ßoòŒò&ä�Fõc\;‡h*GP*Qëã±tè]ŸõüÎà¯�†\HÿÇæÒ¶Ù$SVû�$¸|˜¤¤$ôúHÀ‘;wî‚öƒ«p¦»pñ0Æ %00€‚G�E)±_Éb@r2#æ~ˆ^¯§¸¸˜£G�²aã:ìÙG',MPí (ÈE½jqÑ‘thWõ9ϱcǹqãB@R5bêÜÌ�;G6 ètÍܱÀúõ눈ˆ #c?ƒ%£+Î埙ßЫW/Y3&<ϬY3yºO?îf¬Â>bNíR Òù.íÛ²?}�óË”+V’šºOD:¼ ,&gµ†|`´Z-é{ÓxüñÇIOÏàìÙ³²ûíÚµcåò¿!e¥C±Áÿv rQ­šC×í8�±×éü’%áÕ?¦ �œ#_v«êuÍEQ«ÕlÝú%›7NËV1$'¦sç. ü¬l ~ôèQh›6…ìþµ[é|·íØŸ¾­V‹$IÌ�û^ô6LL�äñu4løÀõíÛ‡«W¯ò_«× }ÞLƒIãà7™|õUª§V«éÒåI¸qÉ¿v3>£{B{§ó6›�©¯LãÃ�–#½<ú ­QGí#À[ ïÞ’$ñî_—ar(tìš`x¬#Š–í8|ø° ­�DQQì=’z’±o7Z­«ÕÊ„‰/ð�MŸaŸ¶žzÆ«ŽûÚ\¿~�kyW�Ú÷‘aÅ@­Ûž¢F£Aáº�âAz÷îí|ò ñ;¾ÞƒmÖ{Ð)±æ~8æ/öêÕ«ŽƒÐ2œ¤¤Ühô¬ÏÇfé’%ï8—ä 9wî<4ZÆù5™j¼ð€+»·[äº/ RSaªáã íŽ5†œœ¢¢¢8òí74·›Q}ü˜Ê}’p_G�qõH«›7oÒ§ßgtÅÄÄp$ó ÍÊ‹P-ŸæŠûÔÓ@„*I0 ´nÝš#™ÑP¼¬¦zÐØàoÛ5ˆ4z¿-ôé7€ÂÂBÚ´iñ#™„ÜÊGµüO`5ÿú}@�¸z¤MC±¦,åÒÍ; L~Öùw˜6mÚpè@:Á¿\AùÑŸA´¸Uý„E`}})?\¸ÈÐá#œ_´uìØ‘Ìoötõ"Ê�¹UsïÞ½ËåË—�çÎÅ]•ˆ 'îã2ƒ+%//Ïy¿  ÀÝ©Êb4VÈÚ-))ñHÀ­[·d8æ‘h¬)ïrìýÙŒŸ0‘ÿ\æØQÒét¬^¹‚—&MF©TT_V•`³ÙX³f-kÖ¬•7‘äfÈ+¯LÃM<<ÙîÝïî»lj�m-ƒ)Úv•á$`öì9Ìž=§f}1ñˆ¯-áëÞb玺·-:*Üû¯�ŒQPÁØ�Ý þ]µ1[Xã9�êíýéãá•5U‘SÝÐê[Z  ÿ‹�4ÌÍ{�|=@šû±sOoD¤ÜŽ6±/Ýå¥UÑxïÞ;¯�±›ÍæN ´ˆ÷윳éãú  ‚¨xÏ÷\ËïZ@X ß:[Å×|ϵDD‚àB €Bép¼ò³_9¦RX7´êÜWÇãIä:F—M]p,R8Dsi5?\rÏg869$I¢´ô·á|HHÓ§O@ø­ÿ}þÿ-™S1c°EIEND®B`‚stlink-1.9.0/src/stlink-gui/icons/stlink-gui.png000066400000000000000000000033341526027543100216210ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYs Ø ØÇ ¹­tEXtSoftwarewww.inkscape.org›î<YIDATX…½—PT×Ç?ïíoØe³€‚@""Ú®I\£LØÑAjø¡fR…ª£�É£M­I&¦:Ñ2mÇN´Ék4šV£¦Õˆ&£&BHŒ´j­É4C+m­RmQ)P²À²»ìã½þ±+°ì.bÇæÎÜyï�{Ï9ßû=÷œw¯põêU¥¶¶–¯» ‚@vv6êššJV®D£5GÆ¢=V/чüžŽ–•¡P©tømƒH Km$y?Á¤r£�~IÆíSpëÒqêFI˜†¹­“»vÈÑhO<¹›@ÕžH’ :×xk™®¯äÈobµZCQûý\¹r…¥«6R?n&o7ªËÑétc"Ä^PD‡¨†d#(LôŸäó/>Å`0ÐÔÔÄû'*èpº˜’‘†íQ+YYYhtúÀ|êëëÑjµƒf’’’ˆ��àÖ­[!|Þ¾!–CA¡·�¼Ül N§“œ…%4¡hÇÁÙÛÄËÄì}…^�&A§9‹y«ß¤Øëø7û_}žeË–ðxîB4Sæ …@“ÀzI™0‡ÃAf”øi Ñ�NÑŽSxZAwÊ\ÜâÜ!£º?„¬8&e2M¶’À˜Š¡yÈ!o±©Ôüí*S§Ne÷æg°{÷’Þø:‰-G¡ë2˜’C�E0ÚèóBè-\ºÞÁ¥š¿°bY1_ž?ÅÍšÓœÝÿ¯ØdÔmEÕ}=Ü Šð´ˆ¼ú¨DhIzŽE«¶²¼äy.^üI’E›ÍÆ?ÿ —/V0£·|Îp£‘òþž�‘Û×q¼%‡ÅO�ùøbfå~›½`4yëµRh»p÷ÆG€ Û„x`NS ]æ%t© A`Ó;GȘ˜Êü¬V+±ý­tÝBø:_·m|­æ'�ÆÛ@ŒA@P U—Ë…¬Öß—„`qñR¶o-åÝCÇøì|]N7j•ÀwW>ÅüÂŽ�¬ ÝüÈÿ£¡ù?�ȲÌúukY¿nmØ‚ª~{Ž_½ɾéÿÀ€1™sŽob+\�Eë%ÁGZêâLFšo·RWßH«æ!:fýD!ܨZÃ�_ßɶýGðš{ jð¥æÒ$æÒ$øÀÙ í^ˆ™Ó-Ñ ŠÀ7fSg�9ïï æög ‚_gÁ?ÁŽØý/ô½7A€~c ’1=º±ůn o¯ èZ’‘2½ô:6%Pñ³ì:"Œëþ3¿,±òáÆy$·�½ûІõøævN¦bMþQ5¶B4sæLòóóÕÚAiww7���ÃB4Æ.€ÝžM~~öJÄ=p§S§M�ÂË»Ëß)ÓJíס§-ðžø ¢ÏE‚ó}z3îÉvˆ‹�œ " yáZõà¸"Ë¡ ŒTHRZØõRǶ|Ÿ4ÿ-!­©Š#+&³§0�˜S?b}F7ç·¿Hù …<ú§}ÐÕ¹H^ROíàÀì4v>l&±ê=QÀ‚óY²ä;!²ââ"ž|r!¥ÖÑÐÜʉOªÈË{‚O�$åryØ_QòyHýèœØ±…yßÊåíãå8^|íî!ˆHcP6iÒ$>8s�Ú¬ïwá,ùs¾ ''“ì ÓuýóïüîÌiŒF#yO¯¦aùË`¶Œ`„³PÁÖÞÞN§.,I¸,ÑÒÒ €V%„éVžú�¶é¤?2ƒ¯^ÚqæYÉÙ( ôôô ëb‚ÕO…Çç‹ ~ó–­ˆ¢ÈÞ]o’Ty�#§á½0"#Ȇé^¾ÙÀ‚åO³há|v­}–äã{Ǻ`‹‚HÎFa%š®9c _N�CÑ3«ø¸ì’,³þ7oã@–¶ïÞGÙG§q»{%YQ(}uƸ8ü ˆÐ/+¬ÙPЧ¯¿¢ 8XvŒ —þŠ£5pZ–Pøé¶Xé�ñM{Œß{]Ì]TLff&¦Æ¸5EA8|ø°²ê¹5 ¬øuÀ F q‰àï�þž€Lo“<] /1F0ÆÁ€ÜÁó¡Z ‰ãÁÛ W % x øëv€Ü¨6<Ë�}{Q«Õjü>4'Šûp �6ÏïïG§Ó!444(ÕÕÕ(Š2F+÷§Ý¹žÿ¸hmšîtIEND®B`‚stlink-1.9.0/src/stlink-gui/icons/stlink-gui.svg000066400000000000000000000113471526027543100216370ustar00rootroot00000000000000 image/svg+xml ST link stlink-1.9.0/src/stlink-gui/icons/stlink-gui.xpm000066400000000000000000000114211526027543100216350ustar00rootroot00000000000000/* XPM */ static char *stlink_gui[] = { /* columns rows colors chars-per-pixel */ "32 32 162 2 ", " c #010303", ". c #030608", "X c #050A0E", "o c #0C0D0F", "O c #0A1016", "+ c #141C24", "@ c #162226", "# c #172837", "$ c #1F383F", "% c #222B2E", "& c #25313A", "* c #002341", "= c #102841", "- c #1E2C43", "; c #1C2E4B", ": c #1B3A45", "> c #1C3349", ", c #153848", "< c #16394D", "1 c #1D3A4B", "2 c #172D55", "3 c #1C3C52", "4 c #193A55", "5 c #232E42", "6 c #213145", "7 c #2C3B46", "8 c #24364B", "9 c #24394B", "0 c #2E3A4C", "q c #333D4A", "w c #0E3562", "e c #003D6F", "r c #133666", "t c #163D65", "y c #183B61", "u c #12376C", "i c #0C3A76", "p c #17434D", "a c #1D4049", "s c #184455", "d c #184851", "f c #27404C", "g c #2D444D", "h c #34434F", "j c #3C4649", "k c #384250", "l c #0F4463", "z c #164265", "x c #184261", "c c #144964", "v c #184A62", "b c #144E69", "n c #135369", "m c #0A4177", "M c #00417F", "N c #0A5277", "B c #424D55", "V c #444E5A", "C c #4A5059", "Z c #4D5A5E", "A c #4E5562", "S c #515B63", "D c #565E69", "F c #58646B", "G c #5D686F", "H c #5D6670", "J c #5F6D72", "K c #656C77", "L c #676C78", "P c #6B737C", "I c #063C84", "U c #01378C", "Y c #033295", "T c #013E98", "R c #0034A0", "E c #0036A9", "W c #003CAF", "Q c #003CBF", "! c #004581", "~ c #074587", "^ c #004C81", "/ c #005286", "( c #005C85", ") c #004297", "_ c #044D91", "` c #034B99", "' c #025A90", "] c #005898", "[ c #006382", "{ c #076988", "} c #07758F", "| c #02689C", " . c #0042A3", ".. c #004CA8", "X. c #0051A0", "o. c #0055AB", "O. c #005BAF", "+. c #0045B4", "@. c #0049B9", "#. c #0052B6", "$. c #0054BD", "%. c #005ABC", "&. c #0060A6", "*. c #0069A6", "=. c #0065AC", "-. c #006FA9", ";. c #0072A6", ":. c #007DA6", ">. c #0073AF", ",. c #006EB3", "<. c #0065B9", "1. c #006ABF", "2. c #0076B0", "3. c #007EB2", "4. c #757B83", "5. c #0036C0", "6. c #003AC0", "7. c #0044C0", "8. c #004CC0", "9. c #0053C0", "0. c #005BC0", "q. c #0064C0", "w. c #006CC0", "e. c #0074C0", "r. c #007CC0", "t. c #0085A6", "y. c #0088A6", "u. c #0082AA", "i. c #0093A6", "p. c #0093AE", "a. c #0087B8", "s. c #008BB8", "d. c #0090B1", "f. c #009EBE", "g. c #00A3BE", "h. c #0083C0", "j. c #008BC0", "k. c #0093C0", "l. c #00A2C0", "z. c #84868A", "x. c #858B90", "c. c #8C8E92", "v. c #919192", "b. c #94989E", "n. c #9B9C9C", "m. c #9D9EA1", "M. c #9FA1A3", "N. c #A1A1A1", "B. c #A6ABAD", "V. c #A9A9A9", "C. c #ADB2B4", "Z. c #B7B7B8", "A. c #BBBBBC", "S. c #C2C2C3", "D. c #C6C7C8", "F. c #CBCCCC", "G. c #D2D2D2", "H. c #DBDBDB", "J. c #E1E1E1", "K. c #ECECEC", "L. c #F4F4F4", "P. c #FEFEFE", /* pixels */ "G.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.J.", "N. X . X X X X X X X X . X X X X X X X X X X X X X X X X X N.", "N.. Q 5.5.E 2 ; 0 0 0 > u T 8.i ; > ; ; > > > > - > 1 , r.1.. M.", "N.. Q 5.Y q G.P.P.P.P.L.F.5 9.; L.P.P.P.P.P.P.P.P.P.P.h e.1.. N.", "N.. 6.6.5 L.P.J.c.4.m.F.P.8 $.8 H.H.H.J.L.P.P.H.H.H.J.7 e.e.. N.", "N.. 6.R L P.K.5 Y T U r 5 # 9.~ y y y = V.P.P.+ z x x z r.r.. N.", "N.. 6.Y z.P.H.2 @.8.9.9.9...0.0.%.0.q.! V.P.P.1 e.e.e.e.r.r.. N.", "M.. 6.W A P.P.V.k 6 r ) $.9.0.0.q.q.q.! V.P.P.1 e.e.e.r.r.3.. N.", "M.. Q @.; F.P.P.P.P.F.4.6 ` %.0.q.q.w.! V.P.P.: e.e.r.r.r.h.. N.", "M.. 7.7.+.2 D S.P.P.P.P.L.q O.q.q.q.q.! V.P.P.> e.r.r.r.r.h.. N.", "N.. 7.8.8.8. .u > q m.P.P.S.m q.w.q.w.^ V.P.P.1 r.r.r.r.h.h.. N.", "N.. 7.+. .8.9.9.9.$.w Z.P.K.3 q.w.w.w.^ V.P.P.1 r.r.r.h.h.a.. N.", "N.. 8. .+ 5 U #.0.0.w Z.P.J.4 w.w.w.w.^ V.P.P.1 r.h.h.h.h.h.. N.", "M.. 8. .L K.c.V q k b.P.P.x._ w.w.w.e.^ V.P.P.1 r.h.h.h.j.j.. N.", "M.. @. .C K.P.P.P.P.P.P.A.> 1.w.w.e.e.^ V.P.P.1 h.h.h.h.j.j.. N.", "N.. 8.$.I 4 q B H P S 7 t <.1.w.e.e.e./ & h h < h.h.j.j.j.j.. N.", "N.. 9.9.9.0.%.%.o.X.O.q.q.w.w.e.e.e.e.r.r.r.h.h.h.h.j.j.j.k.. N.", "N.. i i ~ 0.` i m ` w.q.w.w.e.w.e.e.r.r.r.| N N { j.j.j.k.k.. N.", "N.o z.A.6 0.t N.Z.1 w.w.w.e.e.e.e.r.r.r.r.b n.A.1 j.j.j.k.k.. N.", "N.o A.P.8 q.t v.V.1 w.w.w.e.e.3.r.r.r.r.h.c G.P.1 j.k.k.k.k.. N.", "N.o A.P.9 q.M * * e w.] ^ ^ &.' z N >.h.h.b G.P.1 k.f.N [ N X M.", "N.o A.P.8 q.t v.V.> w.3 N.v.O 4.G.A.7 ;.h.b G.P.1 s.: m.v.@ . M.", "N.o A.P.8 q.z G.L.4 w.3 L.H.z.F x.P.J.s j.n G.P.$ : D.H.& i.. M.", "N.o A.P.9 q.z H.P.1 e.3 L.P.7 -.l S.P.f j.b G.P.O D.G.: p.g.. M.", "N.o A.P.9 w.z H.P.1 e.3 L.K.s r.( V.P.g s.n G.P.A.L.@ p.f.l.. N.", "N.o A.P.9 w.t H.L.4 e.3 L.H.v h.( N.P.g j.n G.P.j P.C.p f.l.. N.", "N.o A.P.9 w.x H.L.9 3.3 L.H.v h.( m.P.g k.n G.P.O B P.B.d g.. N.", "N.o A.P.9 e.z G.P.4 r.s L.H.v a.( N.P.g k.n G.P.a } Z P.B.d . N.", "N.o B H - e.c S G , r.< G S c j.[ k K # k.n Z J a g.} j J % o m.", "N.. &.&.=.1.,.*.-.>.h.2.;.;.3.s.a.:.u.t.f.d.y.y.p.g.g.i.i.i.. m.", "N. X X X X X X X X X X X X X X X X X X X X X X X X X X o o N.", "J.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.J." }; stlink-1.9.0/src/stlink-gui/icons/stlink-gui_48.png000066400000000000000000000052201526027543100221300ustar00rootroot00000000000000‰PNG  IHDR00Wù‡sBIT|dˆ pHYsÄÄ•+tEXtSoftwarewww.inkscape.org›î< IDATh�Õ˜{T”uÇ?ï;7˜t@S@\55¢")ïx©XÓR©­Ô2»h)Z»fŠPS̲uÕrÛjÍÍ:µµéškåm; •હ¦�yA`˜;3óîÀ0ïÜÔsÜ}ÎyÏ;3Ïõû<ÏïyŸw„òòr‰ÿcR 8³Ù|­ci¥§§³iÓ¦&&“‰†3(ô DháZÈµÈØÍÍ@¡…Ûw€Ø,è{7Gm*DÛX†ÇQ‹änDÔèÔq+c°¨zà1¤€áÐè¼zÊ“ï¡Ý­ŽŸ‹w¾.A‰kðÔ¦XDàõqÞ°[øGúóëˆ�¶0súã œEbb�†ºº:ª«k¸téŇ�òMáß))8Ž”ô[ì7Ï„SŸ²ä…\T*Ué NN§“•«VÃЩrpAøfÝY…öÔ–¿0�ysç ŠbH'S¦< @~þ§L_²{‹ `Þ¼¹hµÚË`±Xšøv…ˆÀ 4 é.¾MöóYÌÏž+©ªªâìÙ³8 }ûöE­V˽¶8ºšä›\ ÞB®z<Æ“›ó…—UQQÁøûæÄ‰Ñtì† ªð8MØêÊé›’Ê#îC%kAÃîºQX½9³žâ‰'÷~ߺõ^}ëor�I’ÏGP-(Í%ÜÖ QQQ^ÖŒYsøÁÔ×ÈØE±UVrr¢öG^ÞzÎîALèïÍ”{Ä*Žâ‘gNNEYY™ÌuYYGŒj¤”{ÏbÏå-@‹�«Ž„ø®2Ö©Ò_pÅNQ”W¨¡ëm8âoƒ›¦ƒé—VG i�MªŽd€Ž‰ð›ÛåòÁ¦¢_Îåß@¥¥¾Þ$cÍ��…®dŠÒ÷¡î8xìòC%ª(èœ"ÿ-Xá·¿\°+$€�˜>ÂåryY³fΠpÿNž{)õ›Qïž@‡og¢.ÙÕÇ@p´�‚ú:x1¨²6·¶ëÿü™pZZ¯®[͉¾Çb®eïŽ-,š�Lrõf´_?†xfWd„‰nD-$‚ùúçY¶r y+^ÂápøR*• 0€W,£äxöÿ“Ì»‰þáÍvg1D¨+lü•uñØú¿ÎÚ÷öÐ%¡SŸšÉîÝ{°Z­Aý¦¥¥Qôí7tj8ÅáW�¶*×&_áèë°ÜºSÿõl.V1ñé q]H¾eóæräÈ™º^¯gåòÅÄœ ÑJ‘œ�«ÕB²»>OŸ‰ÔZGãØÏù¹ë4ÖYɈQ™,]ö¢ÌĈÑjN]ÝŠèûfÀzª A�•Uj¸îÜ·<‰%ck×®•�ƒÁ€Ën@{[¨Ýc´±Š—£ÿnœû<¶�ÙDEÓ£¾™ŒF#*]LjšÀv �à«„)©XûÊrÖ¬“ïv¿…&þf´}ðDu¥ÑV‰¶|Ï>7[¶r#Äõº²j‡nÈmTÆŽ½—±cïÅh4ràÀAŠŠóë¹ löjzõHâ�û?dÈ�!2¯½±SÂÈË´uE´�ú9ˆ‹‹#3s<™™ãCxn¢å+^â§sFŸqþÛù ÞBj-§O•0(ý.&Oü#F £_¿~A߬œN'{÷îã¥Õë8vºËÝ/7-|mÌr»ÝNmm­×ŽÝn�„/æòòr)99™›Æï”­ÉT&ÊXŒÚø¬5g‰ë’@§N�ÑëuØNj�F*/üJtb2 =F!Ýx(mpèC4Å&cðD¤;¦×óýœ;Ž•ÈÉ“'C´�jHнûPì" ¹¨²^¤ª±\6ˆUB=dt§Q© ?uüƒ:ǰÉí›:!Ú;ä ¸J蘹ÃH¶ÒPsÿr¦� HhN¾ã5ê– 1ùaˆŠóyÔg¾¤å½^À‘0û]^>wñØ.Ôu¼~]pÝ3½ý«D´FÅØläMI%ïÑTÔgv‚ËÒ¤d©¤KÝ÷äMJ%oR*ƒtàÒOW%»N0¥wycRÉ�Šë_´m3XÆŒCVÖ Ö® ‹�£„nÝY´h!•—j(8`ºüÖñ“™4i£Gß @NNî<ÈüÉÇéù3eMÆ�‚û]�óÊo„-@‹’¡‰cX½¿¶ÙȭЭ_ÛÙuÙáÒip9¡s70t�l¥h«rhQ2]€"¿ÿlÒ³ 1DPn¼—­ÁËÒ$öE꓎xd;=®ïM‡=?]‚;®æñ !¶KÐl$ÎlD»aÖó¿ÈÃR(�”¯hDY8üN$É�$¹™›=_–…(P[[ƒ$¹9tè;å§UIiÉqJŽâPÁ>Œ•çÉ�6ÝG‹Áí ßFÍÁë6,dAÖ4$É�Ãa#óÁ‡ÐÝ:I­F„6øƒÇ÷£ŒŒ Þxm Û·ÿƒ;¾@’$DQdqÎBúßÔáøþð-ÔÐüÌiä½°›ÍÆèñ÷±÷\5–gWÊDÛÊ‘o_úPRRYYY 9Šù›÷0åù¥<;'ÛËtÂD_, ÛBº·°pÖS,_º“ÉĈQc8dS`�±üö±Ë¯@pñññdç.Å<.ëèÙ4<”Ç–Í›½üž={¢6U†]­ÎzšeKr©®®fðÈ»øQÛÛ“ó[÷,Šl µ5î|¨¢¢‚ÚºzèÕ<¥ô¬¦z$IBââbÁfi÷•WV‘“³ˆšš»ƒòÞi8Ê ™°+o!?ÞÅ‹Q:·êŠ¢JÕº.‡ Ñ4M—ØØX†„êüiht„lÙðBU Ì\v»Ý‚BPD<OD¶³³çóΦwE‘Íï¾Ã˜›ú Ý¸<�AåÃð 6ÔïmÍòPüv%IbNÎRòó?C¡Pðñ–÷É蕈öí• ¹®b … "\…øAÈú‡UL}æ÷ìÚõ%J¥’mŸ|DF÷®h7¼ ’»Ââö¬ál£¤^XŸÉcâcOPPP€B¡à³·0$VKô_WÉDeSèðáÃäçÇà°YeA«/‘Ÿÿ)?—”€�(Ëâ¶mÛÑét”––Êlæþù64M+ßÇvAAõõõrp½S°LÏeÜx}íŸÐétL�üGçe7�Sšþ‹ò¾[ì.¢ûófÅå‘pÜ1t¨.%úðˆbkÊ,7f@r:ˆ þb *�ØÓOãèÖ—õ'Dåӿθx3›øÊ¯¶¢©lÝu%ÎYË¼à…£Ñ~¿OV­Æâƒ((-=íóRïðÀÌ�m¯²‘Þ¯†�`wxr1Jÿ—z§6f¶–7ºVrv+èõ@ó>|8ŒPû€:t ==h>×8œ+¢ÿë¿Qÿº[·sIEND®B`‚stlink-1.9.0/src/stlink-gui/stlink-gui.desktop000066400000000000000000000003431526027543100213700ustar00rootroot00000000000000[Desktop Entry] Name=stlink GenericName=Stlink Tools Comment=Open source STM32 MCU programming toolset Exec=stlink-gui %f Icon=stlink-gui Terminal=false Type=Application Categories=Development;Electronics; MimeType=text/plain; stlink-1.9.0/src/stlink-gui/stlink-gui.ui000066400000000000000000001135321526027543100203410ustar00rootroot00000000000000 False 5 Flash device dialog False vertical 2 False end gtk-cancel True False True True False True 0 gtk-ok True True True True True False True 1 False True end 0 True False 5 5 5 5 5 True True False Address to write at: 0 0 1 1 True True • 12 1 0 1 1 False True 2 flash_dialog_cancel_button flash_dialog_ok_button False 5 Mass erase flash dialog False vertical 2 False end gtk-cancel True False True True False True 0 gtk-ok True True True True True False True 1 False True end 0 True False 5 5 5 5 5 True True False This will permanently delete all code and data on the chip. This action cannot be undone. 0 0 1 1 False True 2 erase_dialog_cancel_button erase_dialog_ok_button False STlink GUI 550 480 stlink-gui True False vertical True False True True False Open Open True gtk-open False True True False Connect Connect True gtk-connect False True True False Disconnect Disconnect True gtk-disconnect False True True False Flash Flash True gtk-media-record False True True False Reset Reset True gtk-refresh False True True False Export device memory __glade_unnamed_9 True gtk-save False True True False Erase device memory Erase device memory True gtk-delete False True True False True False start 5 5 False True 0 0 1 1 True False 5 5 5 True False 0.98999999999999999 4 4 1 0 True False 12 12 True False 2 6 True True False 1 1 0 0 Chip: 0 0 1 1 True False 0 0 Core: 0 1 1 1 True False 0 0 Flash size: 0 2 1 1 True False 0 0 True 1 1 1 1 True False 0 0 20 1 0 1 1 True False 0 0 1 2 1 1 True False 0 0 Ram size: 0 3 1 1 True False 0 0 1 3 1 1 True False 0.49000000953674316 2 <b>Device</b> True 0 0 1 1 0 2 1 1 True False 5 5 5 vertical 2 0 4 1 1 True False 5 5 5 5 True False vertical True False True False start 5 5 5 5 Goto address: 0 0 1 1 True True 5 5 5 5 15 • 12 1 0 1 1 False True 0 True False True in True False True both False True 1 Device memory True False Device memory False True False vertical True False True False 5 5 5 5 Goto address: 0 0 1 1 True True 5 5 5 5 15 • 12 1 0 1 1 False True 0 True False True in True False True both False True 1 1 True False No file 1 False 0 3 1 1 True True False error False 8 5 True True 0 False 5 vertical 6 end False True 1 0 1 1 1 stlink-1.9.0/src/stlink-lib/000077500000000000000000000000001526027543100156715ustar00rootroot00000000000000stlink-1.9.0/src/stlink-lib/calculate.c000066400000000000000000000050621526027543100177750ustar00rootroot00000000000000/** ****************************************************************************** * @file : calculate.c * @brief : Calculation of sector numbers and pages * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #include "calculate.h" #include "common_flash.h" #include "read_write.h" uint32_t calculate_F4_sectornum(uint32_t flashaddr) { uint32_t offset = 0; flashaddr &= ~STM32_FLASH_BASE; // page now holding the actual flash address if(flashaddr >= 0x100000) { offset = 12; flashaddr -= 0x100000; } if(flashaddr < 0x4000) { return (offset + 0); } else if(flashaddr < 0x8000) { return (offset + 1); } else if(flashaddr < 0xc000) { return (offset + 2); } else if(flashaddr < 0x10000) { return (offset + 3); } else if(flashaddr < 0x20000) { return (offset + 4); } else { return (offset + (flashaddr / 0x20000) + 4); } } uint32_t calculate_F7_sectornum(uint32_t flashaddr) { flashaddr &= ~STM32_FLASH_BASE; // Page now holding the actual flash address if(flashaddr < 0x20000) { return (flashaddr / 0x8000); } else if(flashaddr < 0x40000) { return (4); } else { return ((flashaddr / 0x40000) + 4); } } uint32_t calculate_H7_sectornum(stlink_t *sl, uint32_t flashaddr, uint32_t bank) { // sector holding the flash address flashaddr &= ~((bank == BANK_1) ? STM32_FLASH_BASE : STM32_H7_FLASH_BANK2_BASE); return (flashaddr / sl->flash_pgsz); } // returns BKER:PNB for the given page address uint32_t calculate_L4_page(stlink_t *sl, uint32_t flashaddr) { uint32_t bker = 0; uint32_t flashopt; stlink_read_debug32(sl, STM32_FLASH_L4_OPTR, &flashopt); flashaddr -= STM32_FLASH_BASE; if(sl->chip_id == STM32_CHIPID_L4 || sl->chip_id == STM32_CHIPID_L496x_L4A6x || sl->chip_id == STM32_CHIPID_L4Rx) { // these chips use dual bank flash if(flashopt & (uint32_t) (1lu << STM32_FLASH_L4_OPTR_DUALBANK)) { uint32_t banksize = sl->flash_size / 2; if(flashaddr >= banksize) { flashaddr -= banksize; bker = 0x100; } } } // For 1MB chips without the dual-bank option set, the page address will // overflow into the BKER bit, which gives us the correct bank:page value. return (bker | flashaddr / sl->flash_pgsz); } stlink-1.9.0/src/stlink-lib/calculate.h000066400000000000000000000015361526027543100200040ustar00rootroot00000000000000/** ****************************************************************************** * @file : calculate.h * @brief : Calculation of sector numbers and pages * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #ifndef CALCULATE_H #define CALCULATE_H #include #include uint32_t calculate_F4_sectornum(uint32_t); uint32_t calculate_F7_sectornum(uint32_t); uint32_t calculate_H7_sectornum(stlink_t *, uint32_t, uint32_t); uint32_t calculate_L4_page(stlink_t *, uint32_t); #endif // CALCULATE_H stlink-1.9.0/src/stlink-lib/chipid.c000066400000000000000000000216311526027543100173000ustar00rootroot00000000000000/** ****************************************************************************** * @file : chipid.c * @brief : Chip-ID parametres * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #include "chipid.h" #include #include "logging.h" static struct stlink_chipid_params *devicelist; void dump_a_chip(struct stlink_chipid_params *dev) { DLOG("# Device Type: %s\n", dev->dev_type); DLOG("# Reference Manual: RM%s\n", dev->ref_manual_id); DLOG("#\n"); DLOG("chip_id 0x%x\n", dev->chip_id); DLOG("flash_type %d\n", dev->flash_type); DLOG("flash_size_reg 0x%x\n", dev->flash_size_reg); DLOG("flash_pagesize 0x%x\n", dev->flash_pagesize); DLOG("sram_size 0x%x\n", dev->sram_size); DLOG("bootrom_base 0x%x\n", dev->bootrom_base); DLOG("bootrom_size 0x%x\n", dev->bootrom_size); DLOG("option_base 0x%x\n", dev->option_base); DLOG("option_size 0x%x\n", dev->option_size); DLOG("flags %d\n\n", dev->flags); DLOG("otp_base %d\n\n", dev->otp_base); DLOG("otp_size %d\n\n", dev->otp_size); } struct stlink_chipid_params *stlink_chipid_get_params(uint32_t chip_id) { struct stlink_chipid_params *params = NULL; for(params = devicelist; params != NULL; params = params->next) if(params->chip_id == chip_id) { DLOG("detected chip_id parameters\n\n"); dump_a_chip(params); break; } return (params); } void process_chipfile(char *fname) { FILE *fp; char *p, buf[256]; char word[64], value[64]; struct stlink_chipid_params *ts; int32_t nc; // fprintf (stderr, "processing chip-id file %s.\n", fname); fp = fopen(fname, "r"); if(!fp) { perror(fname); return; } ts = calloc(1, sizeof(struct stlink_chipid_params)); while (fgets(buf, sizeof(buf), fp) != NULL) { if(strncmp(buf, "#", strlen("#")) == 0) continue; // ignore comments if((strncmp(buf, "\n", strlen("\n")) == 0) || (strncmp(buf, " ", strlen(" ")) == 0)) continue; // ignore empty lines if(sscanf(buf, "%63s %63s", word, value) != 2) { fprintf(stderr, "Failed to read keyword or value\n"); continue; } if(strcmp(word, "dev_type") == 0) { buf[strlen(buf) - 1] = 0; // chomp newline sscanf(buf, "%*s %n", &nc); ts->dev_type = strdup(buf + nc); } else if(strcmp(word, "ref_manual_id") == 0) { buf[strlen(buf) - 1] = 0; // chomp newline sscanf(buf, "%*s %n", &nc); ts->ref_manual_id = strdup(buf + nc); } else if(strcmp(word, "chip_id") == 0) { buf[strlen(buf) - 1] = 0; // chomp newline sscanf(buf, "%*s %n", &nc); if(sscanf(value, "%i", &ts->chip_id) < 1) { fprintf(stderr, "Failed to parse chip-id\n"); } } else if(strcmp(word, "flash_type") == 0) { buf[strlen(buf) - 1] = 0; // chomp newline sscanf(buf, "%*s %n", &nc); // Match human readable flash_type with enum stm32_flash_type { }. if(strcmp(value, "C0") == 0) { ts->flash_type = STM32_FLASH_TYPE_C0; } else if(strcmp(value, "F0_F1_F3") == 0) { ts->flash_type = STM32_FLASH_TYPE_F0_F1_F3; } else if(strcmp(value, "F1_XL") == 0) { ts->flash_type = STM32_FLASH_TYPE_F1_XL; } else if(strcmp(value, "F2_F4") == 0) { ts->flash_type = STM32_FLASH_TYPE_F2_F4; } else if(strcmp(value, "F7") == 0) { ts->flash_type = STM32_FLASH_TYPE_F7; } else if(strcmp(value, "G0") == 0) { ts->flash_type = STM32_FLASH_TYPE_G0; } else if(strcmp(value, "G4") == 0) { ts->flash_type = STM32_FLASH_TYPE_G4; } else if(strcmp(value, "H7") == 0) { ts->flash_type = STM32_FLASH_TYPE_H7; } else if(strcmp(value, "L0_L1") == 0) { ts->flash_type = STM32_FLASH_TYPE_L0_L1; } else if(strcmp(value, "L4") == 0) { ts->flash_type = STM32_FLASH_TYPE_L4; } else if(strcmp(value, "L5_U5") == 0) { ts->flash_type = STM32_FLASH_TYPE_L5_U5; } else if(strcmp(value, "WB_WL") == 0) { ts->flash_type = STM32_FLASH_TYPE_WB_WL; } else if(strcmp(value, "WB0") == 0) { ts->flash_type = STM32_FLASH_TYPE_WB0; } else if(strcmp(value, "H5") == 0) { ts->flash_type = STM32_FLASH_TYPE_H5; } else if(strcmp(value, "C5") == 0) { ts->flash_type = STM32_FLASH_TYPE_C5; } else { ts->flash_type = STM32_FLASH_TYPE_UNKNOWN; } } else if(strcmp(word, "flash_size_reg") == 0) { buf[strlen(buf) - 1] = 0; // chomp newline sscanf(buf, "%*s %n", &nc); if(sscanf(value, "%i", &ts->flash_size_reg) < 1) { fprintf(stderr, "Failed to parse flash size reg\n"); } } else if(strcmp(word, "flash_pagesize") == 0) { buf[strlen(buf) - 1] = 0; // chomp newline sscanf(buf, "%*s %n", &nc); if(sscanf(value, "%i", &ts->flash_pagesize) < 1) { fprintf(stderr, "Failed to parse flash page size\n"); } } else if(strcmp(word, "sram_size") == 0) { buf[strlen(buf) - 1] = 0; // chomp newline sscanf(buf, "%*s %n", &nc); if(sscanf(value, "%i", &ts->sram_size) < 1) { fprintf(stderr, "Failed to parse SRAM size\n"); } } else if(strcmp(word, "bootrom_base") == 0) { buf[strlen(buf) - 1] = 0; // chomp newline sscanf(buf, "%*s %n", &nc); if(sscanf(value, "%i", &ts->bootrom_base) < 1) { fprintf(stderr, "Failed to parse BootROM base\n"); } } else if(strcmp(word, "bootrom_size") == 0) { buf[strlen(buf) - 1] = 0; // chomp newline sscanf(buf, "%*s %n", &nc); if(sscanf(value, "%i", &ts->bootrom_size) < 1) { fprintf(stderr, "Failed to parse BootROM size\n"); } } else if(strcmp(word, "option_base") == 0) { buf[strlen(buf) - 1] = 0; // chomp newline sscanf(buf, "%*s %n", &nc); if(sscanf(value, "%i", &ts->option_base) < 1) { fprintf(stderr, "Failed to parse option base\n"); } } else if(strcmp(word, "option_size") == 0) { buf[strlen(buf) - 1] = 0; // chomp newline sscanf(buf, "%*s %n", &nc); if(sscanf(value, "%i", &ts->option_size) < 1) { fprintf(stderr, "Failed to parse option size\n"); } } else if(strcmp(word, "flags") == 0) { buf[strlen(buf) - 1] = 0; // chomp newline sscanf(buf, "%*s %n", &nc); p = strtok(buf, " \t\n"); while ((p = strtok(NULL, " \t\n"))) { if(strcmp(p, "none") == 0) { // NOP } else if(strcmp(p, "dualbank") == 0) { ts->flags |= CHIP_F_HAS_DUAL_BANK; } else if(strcmp(p, "swo") == 0) { ts->flags |= CHIP_F_HAS_SWO_TRACING; } else { fprintf(stderr, "Unknown flags word in %s: '%s'\n", fname, p); } } sscanf(value, "%x", &ts->flags); } else if(strcmp(word, "otp_base") == 0) { buf[strlen(buf) - 1] = 0; // chomp newline sscanf(buf, "%*s %n", &nc); if(sscanf(value, "%i", &ts->otp_base) < 1) { fprintf(stderr, "Failed to parse option size\n"); } } else if(strcmp(word, "otp_size") == 0) { buf[strlen(buf) - 1] = 0; // chomp newline sscanf(buf, "%*s %n", &nc); if(sscanf(value, "%i", &ts->otp_size) < 1) { fprintf(stderr, "Failed to parse option size\n"); } } else { fprintf(stderr, "Unknown keyword in %s: %s\n", fname, word); } } fclose(fp); ts->next = devicelist; devicelist = ts; } /* Where to look beside the executable, in order. */ static const char *const chips_rel_dirs[] = { "../share/stlink/config/chips", "chips", }; void init_chipids(char *dir_to_scan) { char exe[1024]; const char *from_env; devicelist = NULL; /* The caller named a directory, very likely to test it. Falling back to the * usual places would hide their mistake, so nothing else is tried. */ if((dir_to_scan != NULL) && (*dir_to_scan != '\0')) { if(!search_for_chips(dir_to_scan)) { ELOG("No chip description file in %s\n", dir_to_scan); } return; } #ifdef STLINK_CHIPS_SRC_DIR /* A debug build is for working on the code, not for installing, so it reads * the checkout. The macro is only defined for that configuration. */ if(search_for_chips(STLINK_CHIPS_SRC_DIR)) { return; } #endif from_env = getenv("STLINK_CHIPS_DIR"); if((from_env != NULL) && (*from_env != '\0') && search_for_chips(from_env)) { return; } if(stlink_exe_dir(exe, sizeof(exe))) { for(size_t i = 0; i < STLINK_ARRAY_SIZE(chips_rel_dirs); i++) { char path[1024]; if(snprintf(path, sizeof(path), "%s/%s", exe, chips_rel_dirs[i]) >= (int)sizeof(path)) { continue; } if(search_for_chips(path)) { return; } } } ELOG("Can't find any chip description file. Set STLINK_CHIPS_DIR, or run " "with -v to see every path that was tried.\n"); } stlink-1.9.0/src/stlink-lib/chipid.h000066400000000000000000000025171526027543100173070ustar00rootroot00000000000000/** ****************************************************************************** * @file : chipid.h * @brief : Chip-ID parametres * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #ifndef CHIPID_H #define CHIPID_H #include #include #include #include #include #include /* Chipid parametres */ struct stlink_chipid_params { char *dev_type; char *ref_manual_id; uint32_t chip_id; enum stm32_flash_type flash_type; uint32_t flash_size_reg; uint32_t flash_pagesize; uint32_t sram_size; uint32_t bootrom_base; uint32_t bootrom_size; uint32_t option_base; uint32_t option_size; uint32_t flags; uint32_t otp_base; uint32_t otp_size; struct stlink_chipid_params *next; }; struct stlink_chipid_params *stlink_chipid_get_params(uint32_t chipid); void dump_a_chip(struct stlink_chipid_params *dev); void process_chipfile(char *fname); void init_chipids(char *dir_to_scan); #endif // CHIPID_H stlink-1.9.0/src/stlink-lib/common_flash.c000066400000000000000000002033171526027543100205100ustar00rootroot00000000000000/** ****************************************************************************** * @file : common_flash.c * @brief : Flash operations * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #include "common_flash.h" #include "calculate.h" #include "flash_loader.h" #include "helper.h" #include "logging.h" #include "map_file.h" #include "md5.h" #include "read_write.h" #define DEBUG_FLASH 0 // Upper bound for a single program/erase operation to finish. Mass erases are // polled separately (wait_flash_busy_progress), so this only needs to cover // the slowest page/sector erase with some margin. #define FLASH_BUSY_TIMEOUT_MS 30000 /* * STM32G0/G4: return true if the device is currently operated as dual-bank. * - G0B1/G0C1 (RM0444): 512 KB devices are always dual-bank, 256 KB devices * only when FLASH_OPTR.DUAL_BANK is set, 128 KB devices are single-bank. * - G4 Cat.3 (RM0440): dual-bank only when FLASH_OPTR.DBANK is set. * - G4 Cat.2 and Cat.4 are always single-bank (no BKER/MER2 bits). */ static bool stlink_gx_dual_bank(stlink_t *sl) { uint32_t optr = 0; if(sl->flash_type == STM32_FLASH_TYPE_G0) { if(!(sl->chip_flags & CHIP_F_HAS_DUAL_BANK) || sl->flash_size < 256 * 1024) { return false; } if(sl->flash_size > 256 * 1024) { return true; } stlink_read_debug32(sl, STM32_FLASH_Gx_OPTR, &optr); return (optr >> STM32_FLASH_G0_OPTR_DUAL_BANK) & 1u; } if(sl->flash_type == STM32_FLASH_TYPE_G4 && sl->chip_id == STM32_CHIPID_G4_CAT3) { stlink_read_debug32(sl, STM32_FLASH_Gx_OPTR, &optr); return (optr >> STM32_FLASH_G4_OPTR_DBANK) & 1u; } return false; } /* * STM32G0B1/G0C1 (RM0444): return true if the two flash banks are swapped in * the memory map, i.e. physical bank 2 is mapped at the start of the flash and * physical bank 1 behind it. FLASH_OPTR.nSWAP_BANK is active low, so the banks * are swapped when the bit reads 0 (the opposite polarity of SWAP_BANK on H5). * Only meaningful in dual-bank mode, callers must check stlink_gx_dual_bank(). */ static bool stlink_g0_bank_swapped(stlink_t *sl) { uint32_t optr; if(stlink_read_debug32(sl, STM32_FLASH_Gx_OPTR, &optr)) { return false; // keep the default (unswapped) mapping if OPTR is unreadable } return !((optr >> STM32_FLASH_G0_OPTR_NSWAP_BANK) & 1u); } uint32_t get_stm32l0_flash_base(stlink_t *sl) { switch (sl->chip_id) { case STM32_CHIPID_L0_CAT1: case STM32_CHIPID_L0_CAT2: case STM32_CHIPID_L0_CAT3: case STM32_CHIPID_L0_CAT5: return (STM32_FLASH_L0_REGS_ADDR); case STM32_CHIPID_L1_CAT2: case STM32_CHIPID_L1_MD: case STM32_CHIPID_L1_MD_PLUS: case STM32_CHIPID_L1_MD_PLUS_HD: case STM32_CHIPID_L152_RE: return (STM32_FLASH_Lx_REGS_ADDR); default: WLOG("Flash base use default L0 address\n"); return (STM32_FLASH_L0_REGS_ADDR); } } uint32_t read_flash_cr(stlink_t *sl, uint32_t bank) { uint32_t reg, res; if(sl->flash_type == STM32_FLASH_TYPE_C0) { reg = STM32_FLASH_C0_CR; } else if(sl->flash_type == STM32_FLASH_TYPE_F2_F4) { reg = STM32_FLASH_F4_CR; } else if(sl->flash_type == STM32_FLASH_TYPE_F7) { reg = STM32_FLASH_F7_CR; } else if(sl->flash_type == STM32_FLASH_TYPE_G0 || sl->flash_type == STM32_FLASH_TYPE_G4) { reg = STM32_FLASH_Gx_CR; } else if(sl->flash_type == STM32_FLASH_TYPE_H7) { reg = (bank == BANK_1) ? STM32_FLASH_H7_CR1 : STM32_FLASH_H7_CR2; } else if(sl->flash_type == STM32_FLASH_TYPE_L4) { reg = STM32_FLASH_L4_CR; } else if(sl->flash_type == STM32_FLASH_TYPE_L5_U5) { reg = STM32_FLASH_L5_NSCR; } else if(sl->flash_type == STM32_FLASH_TYPE_H5) { reg = STM32_FLASH_H5_NSCR; } else if(sl->flash_type == STM32_FLASH_TYPE_WB_WL) { reg = STM32_FLASH_WB_CR; } else if(sl->flash_type == STM32_FLASH_TYPE_C5) { reg = STM32_FLASH_C5_CR; } else { reg = (bank == BANK_1) ? FLASH_CR : FLASH_CR2; } stlink_read_debug32(sl, reg, &res); #if DEBUG_FLASH fprintf(stdout, "CR:0x%x\n", res); #endif return (res); } void lock_flash(stlink_t *sl) { uint32_t cr_lock_shift = 0, cr_reg = 0, n = 0, cr2_reg = 0; uint32_t cr_mask = 0xffffffffu; if(sl->flash_type == STM32_FLASH_TYPE_C0) { cr_reg = STM32_FLASH_C0_CR; cr_lock_shift = STM32_FLASH_C0_CR_LOCK; } else if(sl->flash_type == STM32_FLASH_TYPE_F0_F1_F3) { cr_reg = FLASH_CR; cr_lock_shift = FLASH_CR_LOCK; } else if(sl->flash_type == STM32_FLASH_TYPE_F1_XL) { cr_reg = FLASH_CR; cr2_reg = FLASH_CR2; cr_lock_shift = FLASH_CR_LOCK; } else if(sl->flash_type == STM32_FLASH_TYPE_F2_F4) { cr_reg = STM32_FLASH_F4_CR; cr_lock_shift = STM32_FLASH_F4_CR_LOCK; } else if(sl->flash_type == STM32_FLASH_TYPE_F7) { cr_reg = STM32_FLASH_F7_CR; cr_lock_shift = STM32_FLASH_F7_CR_LOCK; } else if(sl->flash_type == STM32_FLASH_TYPE_G0 || sl->flash_type == STM32_FLASH_TYPE_G4) { cr_reg = STM32_FLASH_Gx_CR; cr_lock_shift = STM32_FLASH_Gx_CR_LOCK; } else if(sl->flash_type == STM32_FLASH_TYPE_H7) { cr_reg = STM32_FLASH_H7_CR1; if(sl->chip_flags & CHIP_F_HAS_DUAL_BANK) { cr2_reg = STM32_FLASH_H7_CR2; } cr_lock_shift = STM32_FLASH_H7_CR_LOCK; cr_mask = ~(1u << STM32_FLASH_H7_CR_SER); } else if(sl->flash_type == STM32_FLASH_TYPE_L0_L1) { cr_reg = get_stm32l0_flash_base(sl) + FLASH_PECR_OFF; cr_lock_shift = STM32_FLASH_L0_PELOCK; } else if(sl->flash_type == STM32_FLASH_TYPE_L4) { cr_reg = STM32_FLASH_L4_CR; cr_lock_shift = STM32_FLASH_L4_CR_LOCK; } else if(sl->flash_type == STM32_FLASH_TYPE_L5_U5) { cr_reg = STM32_FLASH_L5_NSCR; cr_lock_shift = STM32_FLASH_L5_NSCR_NSLOCK; } else if(sl->flash_type == STM32_FLASH_TYPE_H5) { cr_reg = STM32_FLASH_H5_NSCR; cr_lock_shift = STM32_FLASH_H5_NSCR_LOCK; } else if(sl->flash_type == STM32_FLASH_TYPE_WB_WL) { cr_reg = STM32_FLASH_WB_CR; cr_lock_shift = STM32_FLASH_WB_CR_LOCK; } else if(sl->flash_type == STM32_FLASH_TYPE_C5) { cr_reg = STM32_FLASH_C5_CR; cr_lock_shift = STM32_FLASH_C5_CR_LOCK; } else { ELOG("unsupported flash method, abort\n"); return; } stlink_read_debug32(sl, cr_reg, &n); n &= cr_mask; n |= (1u << cr_lock_shift); stlink_write_debug32(sl, cr_reg, n); if(cr2_reg) { n = read_flash_cr(sl, BANK_2) | (1u << cr_lock_shift); stlink_write_debug32(sl, cr2_reg, n); } } /* * Write 'val' to the register through which the status flags of the given * bank are cleared. On most families this is the status register itself * (flags are rc_w1), but some families have read-only status registers and a * dedicated clear register with CLR_* bits at the same positions as the * status flags (H5: NSCCR, H7: CCR1/CCR2, C5: CCR). Writing the status * register on those parts is a no-op and leaves latched errors in place. */ static inline int32_t write_flash_sr(stlink_t *sl, uint32_t bank, uint32_t val) { uint32_t sr_reg; if(sl->flash_type == STM32_FLASH_TYPE_C0) { sr_reg = STM32_FLASH_C0_SR; } else if(sl->flash_type == STM32_FLASH_TYPE_F0_F1_F3 || sl->flash_type == STM32_FLASH_TYPE_F1_XL) { sr_reg = (bank == BANK_1) ? FLASH_SR : FLASH_SR2; } else if(sl->flash_type == STM32_FLASH_TYPE_F2_F4) { sr_reg = STM32_FLASH_F4_SR; } else if(sl->flash_type == STM32_FLASH_TYPE_F7) { sr_reg = STM32_FLASH_F7_SR; } else if(sl->flash_type == STM32_FLASH_TYPE_G0 || sl->flash_type == STM32_FLASH_TYPE_G4) { sr_reg = STM32_FLASH_Gx_SR; } else if(sl->flash_type == STM32_FLASH_TYPE_H7) { // FLASH_SR1/SR2 are read-only, flags are cleared through FLASH_CCR1/CCR2 sr_reg = (bank == BANK_1) ? STM32_FLASH_H7_CCR1 : STM32_FLASH_H7_CCR2; } else if(sl->flash_type == STM32_FLASH_TYPE_L0_L1) { sr_reg = get_stm32l0_flash_base(sl) + FLASH_SR_OFF; } else if(sl->flash_type == STM32_FLASH_TYPE_L4) { sr_reg = STM32_FLASH_L4_SR; } else if(sl->flash_type == STM32_FLASH_TYPE_L5_U5) { sr_reg = STM32_FLASH_L5_NSSR; } else if(sl->flash_type == STM32_FLASH_TYPE_H5) { // FLASH_NSSR is read-only, flags are cleared through FLASH_NSCCR sr_reg = STM32_FLASH_H5_NSCCR; } else if(sl->flash_type == STM32_FLASH_TYPE_WB_WL) { sr_reg = STM32_FLASH_WB_SR; } else if(sl->flash_type == STM32_FLASH_TYPE_WB0) { sr_reg = STM32_FLASH_WB0_IRQRAW; } else if(sl->flash_type == STM32_FLASH_TYPE_C5) { // FLASH_SR is read-only, flags are cleared through FLASH_CCR sr_reg = STM32_FLASH_C5_CCR; } else { ELOG("method 'write_flash_sr' is unsupported\n"); return (-1); } return stlink_write_debug32(sl, sr_reg, val); } void clear_flash_error(stlink_t *sl) { switch (sl->flash_type) { case STM32_FLASH_TYPE_C0: write_flash_sr(sl, BANK_1, STM32_FLASH_C0_SR_ERROR_MASK); break; case STM32_FLASH_TYPE_F0_F1_F3: write_flash_sr(sl, BANK_1, FLASH_SR_ERROR_MASK); break; case STM32_FLASH_TYPE_F1_XL: write_flash_sr(sl, BANK_1, FLASH_SR_ERROR_MASK); write_flash_sr(sl, BANK_2, FLASH_SR_ERROR_MASK); break; case STM32_FLASH_TYPE_F2_F4: write_flash_sr(sl, BANK_1, STM32_FLASH_F4_SR_ERROR_MASK); break; case STM32_FLASH_TYPE_F7: write_flash_sr(sl, BANK_1, STM32_FLASH_F7_SR_ERROR_MASK); break; case STM32_FLASH_TYPE_G0: case STM32_FLASH_TYPE_G4: write_flash_sr(sl, BANK_1, STM32_FLASH_Gx_SR_ERROR_MASK); break; case STM32_FLASH_TYPE_H7: // write_flash_sr() resolves to FLASH_CCR1/CCR2 here (SR1/SR2 are read-only) write_flash_sr(sl, BANK_1, STM32_FLASH_H7_SR_ERROR_MASK); if(sl->chip_flags & CHIP_F_HAS_DUAL_BANK) { write_flash_sr(sl, BANK_2, STM32_FLASH_H7_SR_ERROR_MASK); } break; case STM32_FLASH_TYPE_L0_L1: if(get_stm32l0_flash_base(sl) == STM32_FLASH_Lx_REGS_ADDR) { write_flash_sr(sl, BANK_1, STM32_FLASH_L1_SR_ERROR_MASK); } else { write_flash_sr(sl, BANK_1, STM32_FLASH_L0_SR_ERROR_MASK); } break; case STM32_FLASH_TYPE_L4: write_flash_sr(sl, BANK_1, STM32_FLASH_L4_SR_ERROR_MASK); break; case STM32_FLASH_TYPE_L5_U5: write_flash_sr(sl, BANK_1, STM32_FLASH_L5_NSSR_ERROR_MASK); break; case STM32_FLASH_TYPE_H5: // H5 has a dedicated clear-control register; writing 1 clears the flag. stlink_write_debug32(sl, STM32_FLASH_H5_NSCCR, STM32_FLASH_H5_NSCCR_CLEAR_ALL); break; case STM32_FLASH_TYPE_WB_WL: write_flash_sr(sl, BANK_1, STM32_FLASH_WB_SR_ERROR_MASK); break; case STM32_FLASH_TYPE_WB0: write_flash_sr(sl, BANK_1, STM32_FLASH_WB0_IRQ_ERR_MASK); break; case STM32_FLASH_TYPE_C5: write_flash_sr(sl, BANK_1, STM32_FLASH_C5_SR_ERROR_MASK); break; default: break; } } uint32_t read_flash_sr(stlink_t *sl, uint32_t bank) { uint32_t res, sr_reg; if(sl->flash_type == STM32_FLASH_TYPE_C0) { sr_reg = STM32_FLASH_C0_SR; } else if((sl->flash_type == STM32_FLASH_TYPE_F0_F1_F3) || (sl->flash_type == STM32_FLASH_TYPE_F1_XL)) { sr_reg = (bank == BANK_1) ? FLASH_SR : FLASH_SR2; } else if(sl->flash_type == STM32_FLASH_TYPE_F2_F4) { sr_reg = STM32_FLASH_F4_SR; } else if(sl->flash_type == STM32_FLASH_TYPE_F7) { sr_reg = STM32_FLASH_F7_SR; } else if(sl->flash_type == STM32_FLASH_TYPE_G0 || sl->flash_type == STM32_FLASH_TYPE_G4) { sr_reg = STM32_FLASH_Gx_SR; } else if(sl->flash_type == STM32_FLASH_TYPE_H7) { sr_reg = (bank == BANK_1) ? STM32_FLASH_H7_SR1 : STM32_FLASH_H7_SR2; } else if(sl->flash_type == STM32_FLASH_TYPE_L0_L1) { sr_reg = get_stm32l0_flash_base(sl) + FLASH_SR_OFF; } else if(sl->flash_type == STM32_FLASH_TYPE_L4) { sr_reg = STM32_FLASH_L4_SR; } else if(sl->flash_type == STM32_FLASH_TYPE_L5_U5) { sr_reg = STM32_FLASH_L5_NSSR; } else if(sl->flash_type == STM32_FLASH_TYPE_H5) { sr_reg = STM32_FLASH_H5_NSSR; } else if(sl->flash_type == STM32_FLASH_TYPE_WB_WL) { sr_reg = STM32_FLASH_WB_SR; } else if(sl->flash_type == STM32_FLASH_TYPE_WB0) { sr_reg = STM32_FLASH_WB0_IRQRAW; } else if(sl->flash_type == STM32_FLASH_TYPE_C5) { sr_reg = STM32_FLASH_C5_SR; } else { ELOG("method 'read_flash_sr' is unsupported\n"); return (-1); } stlink_read_debug32(sl, sr_reg, &res); return (res); } uint32_t is_flash_busy(stlink_t *sl) { uint32_t sr_busy_shift; uint32_t res; if(sl->flash_type == STM32_FLASH_TYPE_C0) { sr_busy_shift = STM32_FLASH_C0_SR_BSY; } else if(sl->flash_type == STM32_FLASH_TYPE_F0_F1_F3 || sl->flash_type == STM32_FLASH_TYPE_F1_XL || sl->flash_type == STM32_FLASH_TYPE_L0_L1) { sr_busy_shift = FLASH_SR_BSY; } else if(sl->flash_type == STM32_FLASH_TYPE_F2_F4) { sr_busy_shift = STM32_FLASH_F4_SR_BSY; } else if(sl->flash_type == STM32_FLASH_TYPE_F7) { sr_busy_shift = STM32_FLASH_F7_SR_BSY; } else if(sl->flash_type == STM32_FLASH_TYPE_G0) { // RM0444 sec. 3.3.7/3.3.8: an operation is only finished once BSY1, BSY2 // (bank 2 on dual-bank devices, reads as 0 otherwise) and CFGBSY are all // cleared. Starting the next operation while CFGBSY is still set results // in PGSERR (see #1473). return read_flash_sr(sl, BANK_1) & ((1u << STM32_FLASH_Gx_SR_BSY) | (1u << STM32_FLASH_G0_SR_BSY2) | (1u << STM32_FLASH_G0_SR_CFGBSY)); } else if(sl->flash_type == STM32_FLASH_TYPE_G4) { sr_busy_shift = STM32_FLASH_Gx_SR_BSY; } else if(sl->flash_type == STM32_FLASH_TYPE_H7) { sr_busy_shift = STM32_FLASH_H7_SR_QW; } else if(sl->flash_type == STM32_FLASH_TYPE_L4) { sr_busy_shift = STM32_FLASH_L4_SR_BSY; } else if(sl->flash_type == STM32_FLASH_TYPE_L5_U5) { sr_busy_shift = STM32_FLASH_L5_NSSR_BSY; } else if(sl->flash_type == STM32_FLASH_TYPE_H5) { sr_busy_shift = STM32_FLASH_H5_NSSR_BSY; } else if(sl->flash_type == STM32_FLASH_TYPE_WB_WL) { sr_busy_shift = STM32_FLASH_WB_SR_BSY; } else if(sl->flash_type == STM32_FLASH_TYPE_C5) { // a new C5 program/erase operation may only start when the controller and // both internal buffers are idle (RM0522 single-write sequence). return read_flash_sr(sl, BANK_1) & ((1u << STM32_FLASH_C5_SR_BSY) | (1u << STM32_FLASH_C5_SR_WBNE) | (1u << STM32_FLASH_C5_SR_DBNE)); } else if(sl->flash_type == STM32_FLASH_TYPE_WB0) { res = read_flash_sr(sl, BANK_1); uint32_t has_errors = res & STM32_FLASH_WB0_IRQ_ERR_MASK; return !has_errors && ((~res) & STM32_FLASH_WB0_IRQ_CMDDONE); } 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) { uint32_t start = time_ms(); while (is_flash_busy(sl)) { if((uint32_t)(time_ms() - start) > FLASH_BUSY_TIMEOUT_MS) { ELOG("Timeout while waiting for the flash controller (SR: %#010x)\n", read_flash_sr(sl, BANK_1)); return; } } } int32_t check_flash_error(stlink_t *sl) { uint32_t res = 0; uint32_t WRPERR, PROGERR, PGAERR; WRPERR = PROGERR = PGAERR = 0; switch (sl->flash_type) { case STM32_FLASH_TYPE_C0: res = read_flash_sr(sl, BANK_1) & STM32_FLASH_C0_SR_ERROR_MASK; WRPERR = (1 << STM32_FLASH_C0_SR_WRPERR); PROGERR = (1 << STM32_FLASH_C0_SR_PROGERR); PGAERR = (1 << STM32_FLASH_C0_SR_PGAERR); break; case STM32_FLASH_TYPE_F0_F1_F3: case STM32_FLASH_TYPE_F1_XL: res = read_flash_sr(sl, BANK_1) & FLASH_SR_ERROR_MASK; if(sl->flash_type == STM32_FLASH_TYPE_F1_XL) { res |= read_flash_sr(sl, BANK_2) & FLASH_SR_ERROR_MASK; } WRPERR = (1 << FLASH_SR_WRPRT_ERR); PROGERR = (1 << FLASH_SR_PG_ERR); break; case STM32_FLASH_TYPE_F2_F4: res = read_flash_sr(sl, BANK_1) & STM32_FLASH_F4_SR_ERROR_MASK; WRPERR = (1 << STM32_FLASH_F4_SR_WRPERR); PGAERR = (1 << STM32_FLASH_F4_SR_PGAERR); break; case STM32_FLASH_TYPE_F7: res = read_flash_sr(sl, BANK_1) & STM32_FLASH_F7_SR_ERROR_MASK; WRPERR = (1 << STM32_FLASH_F7_SR_WRP_ERR); PROGERR = (1 << STM32_FLASH_F7_SR_PGP_ERR); break; case STM32_FLASH_TYPE_G0: case STM32_FLASH_TYPE_G4: res = read_flash_sr(sl, BANK_1) & STM32_FLASH_Gx_SR_ERROR_MASK; if(sl->chip_flags & CHIP_F_HAS_DUAL_BANK) { res |= read_flash_sr(sl, BANK_2) & STM32_FLASH_Gx_SR_ERROR_MASK; } WRPERR = (1 << STM32_FLASH_Gx_SR_WRPERR); PROGERR = (1 << STM32_FLASH_Gx_SR_PROGERR); PGAERR = (1 << STM32_FLASH_Gx_SR_PGAERR); break; case STM32_FLASH_TYPE_H7: res = read_flash_sr(sl, BANK_1) & STM32_FLASH_H7_SR_ERROR_MASK; if(sl->chip_flags & CHIP_F_HAS_DUAL_BANK) { res |= read_flash_sr(sl, BANK_2) & STM32_FLASH_H7_SR_ERROR_MASK; } WRPERR = (1 << STM32_FLASH_H7_SR_WRPERR); break; case STM32_FLASH_TYPE_L0_L1: res = read_flash_sr(sl, BANK_1); if(get_stm32l0_flash_base(sl) == STM32_FLASH_Lx_REGS_ADDR) { res &= STM32_FLASH_L1_SR_ERROR_MASK; } else { res &= STM32_FLASH_L0_SR_ERROR_MASK; PROGERR = (1 << STM32_FLASH_L0_SR_NOTZEROERR); } WRPERR = (1 << STM32_FLASH_L0_SR_WRPERR); PGAERR = (1 << STM32_FLASH_L0_SR_PGAERR); break; case STM32_FLASH_TYPE_L4: res = read_flash_sr(sl, BANK_1) & STM32_FLASH_L4_SR_ERROR_MASK; WRPERR = (1 << STM32_FLASH_L4_SR_WRPERR); PROGERR = (1 << STM32_FLASH_L4_SR_PROGERR); PGAERR = (1 << STM32_FLASH_L4_SR_PGAERR); break; case STM32_FLASH_TYPE_L5_U5: res = read_flash_sr(sl, BANK_1) & STM32_FLASH_L5_NSSR_ERROR_MASK; WRPERR = (1 << STM32_FLASH_L5_NSSR_NSWRPERR); PROGERR = (1 << STM32_FLASH_L5_NSSR_NSPROGERR); PGAERR = (1 << STM32_FLASH_L5_NSSR_NSPGAERR); break; case STM32_FLASH_TYPE_H5: res = read_flash_sr(sl, BANK_1) & STM32_FLASH_H5_NSSR_ERROR_MASK; WRPERR = (1 << STM32_FLASH_H5_NSSR_WRPERR); PROGERR = (1 << STM32_FLASH_H5_NSSR_PGSERR); PGAERR = (1 << STM32_FLASH_H5_NSSR_STRBERR); break; case STM32_FLASH_TYPE_WB_WL: res = read_flash_sr(sl, BANK_1) & STM32_FLASH_WB_SR_ERROR_MASK; WRPERR = (1 << STM32_FLASH_WB_SR_WRPERR); PROGERR = (1 << STM32_FLASH_WB_SR_PROGERR); PGAERR = (1 << STM32_FLASH_WB_SR_PGAERR); break; case STM32_FLASH_TYPE_C5: res = read_flash_sr(sl, BANK_1) & STM32_FLASH_C5_SR_ERROR_MASK; WRPERR = (1 << STM32_FLASH_C5_SR_WRPERR); break; case STM32_FLASH_TYPE_WB0: res = read_flash_sr(sl, BANK_1) & STM32_FLASH_WB0_IRQ_ERR_MASK; if (res) { if (res & STM32_FLASH_WB0_IRQ_CMDERR) { ELOG("Internal error: COMMAND written while busy!\n"); } if (res & STM32_FLASH_WB0_IRQ_ILLCMD) { ELOG("FLASH has refused operation (write protected?)\n"); } return -1; } break; default: break; } if(res) { if(WRPERR && (WRPERR & res) == WRPERR) { ELOG("Flash memory is write protected\n"); res &= ~WRPERR; } else if(PROGERR && (PROGERR & res) == PROGERR) { ELOG("Flash memory contains a non-erased value\n"); res &= ~PROGERR; } else if(PGAERR && (PGAERR & res) == PGAERR) { ELOG("Invalid flash address\n"); res &= ~PGAERR; } if(res) ELOG("Flash programming error: %#010x\n", res); return (-1); } return (0); } static inline uint32_t is_flash_locked(stlink_t *sl) { /* return non zero for true */ uint32_t cr_lock_shift; uint32_t cr_reg; uint32_t n; if(sl->flash_type == STM32_FLASH_TYPE_C0) { cr_reg = STM32_FLASH_C0_CR; cr_lock_shift = STM32_FLASH_C0_CR_LOCK; } else if(sl->flash_type == STM32_FLASH_TYPE_F0_F1_F3 || sl->flash_type == STM32_FLASH_TYPE_F1_XL) { cr_reg = FLASH_CR; cr_lock_shift = FLASH_CR_LOCK; } else if(sl->flash_type == STM32_FLASH_TYPE_F2_F4) { cr_reg = STM32_FLASH_F4_CR; cr_lock_shift = STM32_FLASH_F4_CR_LOCK; } else if(sl->flash_type == STM32_FLASH_TYPE_F7) { cr_reg = STM32_FLASH_F7_CR; cr_lock_shift = STM32_FLASH_F7_CR_LOCK; } else if(sl->flash_type == STM32_FLASH_TYPE_G0 || sl->flash_type == STM32_FLASH_TYPE_G4) { cr_reg = STM32_FLASH_Gx_CR; cr_lock_shift = STM32_FLASH_Gx_CR_LOCK; } else if(sl->flash_type == STM32_FLASH_TYPE_H7) { cr_reg = STM32_FLASH_H7_CR1; cr_lock_shift = STM32_FLASH_H7_CR_LOCK; } else if(sl->flash_type == STM32_FLASH_TYPE_L0_L1) { cr_reg = get_stm32l0_flash_base(sl) + FLASH_PECR_OFF; cr_lock_shift = STM32_FLASH_L0_PELOCK; } else if(sl->flash_type == STM32_FLASH_TYPE_L4) { cr_reg = STM32_FLASH_L4_CR; cr_lock_shift = STM32_FLASH_L4_CR_LOCK; } else if(sl->flash_type == STM32_FLASH_TYPE_L5_U5) { cr_reg = STM32_FLASH_L5_NSCR; cr_lock_shift = STM32_FLASH_L5_NSCR_NSLOCK; } else if(sl->flash_type == STM32_FLASH_TYPE_H5) { cr_reg = STM32_FLASH_H5_NSCR; cr_lock_shift = STM32_FLASH_H5_NSCR_LOCK; } else if(sl->flash_type == STM32_FLASH_TYPE_WB_WL) { cr_reg = STM32_FLASH_WB_CR; cr_lock_shift = STM32_FLASH_WB_CR_LOCK; } else if(sl->flash_type == STM32_FLASH_TYPE_C5) { cr_reg = STM32_FLASH_C5_CR; cr_lock_shift = STM32_FLASH_C5_CR_LOCK; } else if(sl->flash_type == STM32_FLASH_TYPE_WB0) { return 0; } else { ELOG("unsupported flash method, abort\n"); return (-1); } stlink_read_debug32(sl, cr_reg, &n); return (n & (1u << cr_lock_shift)); } static void unlock_flash(stlink_t *sl) { uint32_t key_reg, key2_reg = 0; uint32_t flash_key1 = FLASH_KEY1; uint32_t flash_key2 = FLASH_KEY2; /* The unlock sequence consists of 2 write cycles where 2 key values are * written to the FLASH_KEYR register. An invalid sequence results in a * definitive lock of the FPEC block until next reset. */ if(sl->flash_type == STM32_FLASH_TYPE_C0) { key_reg = STM32_FLASH_C0_KEYR; } else if(sl->flash_type == STM32_FLASH_TYPE_F0_F1_F3) { key_reg = FLASH_KEYR; } else if(sl->flash_type == STM32_FLASH_TYPE_F1_XL) { key_reg = FLASH_KEYR; key2_reg = FLASH_KEYR2; } else if(sl->flash_type == STM32_FLASH_TYPE_F2_F4) { key_reg = STM32_FLASH_F4_KEYR; } else if(sl->flash_type == STM32_FLASH_TYPE_F7) { key_reg = STM32_FLASH_F7_KEYR; } else if(sl->flash_type == STM32_FLASH_TYPE_G0 || sl->flash_type == STM32_FLASH_TYPE_G4) { key_reg = STM32_FLASH_Gx_KEYR; } else if(sl->flash_type == STM32_FLASH_TYPE_H7) { key_reg = STM32_FLASH_H7_KEYR1; if(sl->chip_flags & CHIP_F_HAS_DUAL_BANK) { key2_reg = STM32_FLASH_H7_KEYR2; } } else if(sl->flash_type == STM32_FLASH_TYPE_L0_L1) { key_reg = get_stm32l0_flash_base(sl) + FLASH_PEKEYR_OFF; flash_key1 = STM32_FLASH_L0_PEKEY1; flash_key2 = STM32_FLASH_L0_PEKEY2; } else if(sl->flash_type == STM32_FLASH_TYPE_L4) { key_reg = STM32_FLASH_L4_KEYR; } else if(sl->flash_type == STM32_FLASH_TYPE_L5_U5) { // Set voltage scaling to range 0 to perform flash operations (RM0438 p. 183) uint32_t mask = (0b11 << STM32L5_PWR_CR1_VOS); uint32_t val; if(!stlink_read_debug32(sl, STM32L5_PWR_CR1, &val) && (val & mask) > (1 << STM32L5_PWR_CR1_VOS)) { val &= ~mask; stlink_write_debug32(sl, STM32L5_PWR_CR1, val); } key_reg = STM32_FLASH_L5_NSKEYR; } else if(sl->flash_type == STM32_FLASH_TYPE_H5) { key_reg = STM32_FLASH_H5_NSKEYR; } else if(sl->flash_type == STM32_FLASH_TYPE_WB_WL) { key_reg = STM32_FLASH_WB_KEYR; } else if(sl->flash_type == STM32_FLASH_TYPE_C5) { key_reg = STM32_FLASH_C5_KEYR; } else { ELOG("unsupported flash method, abort\n"); return; } stlink_write_debug32(sl, key_reg, flash_key1); stlink_write_debug32(sl, key_reg, flash_key2); if(key2_reg) { stlink_write_debug32(sl, key2_reg, flash_key1); stlink_write_debug32(sl, key2_reg, flash_key2); } } /* unlock flash if already locked */ int32_t unlock_flash_if(stlink_t *sl) { if(is_flash_locked(sl)) { unlock_flash(sl); if(is_flash_locked(sl)) { WLOG("Failed to unlock flash!\n"); return (-1); } } DLOG("Successfully unlocked flash\n"); return (0); } int32_t lock_flash_option(stlink_t *sl) { uint32_t optlock_shift, optcr_reg, n, optcr2_reg = 0; int32_t active_bit_level = 1; switch (sl->flash_type) { case STM32_FLASH_TYPE_C0: optcr_reg = STM32_FLASH_C0_CR; optlock_shift = STM32_FLASH_C0_CR_OPTLOCK; break; case STM32_FLASH_TYPE_F0_F1_F3: case STM32_FLASH_TYPE_F1_XL: optcr_reg = FLASH_CR; optlock_shift = FLASH_CR_OPTWRE; active_bit_level = 0; break; case STM32_FLASH_TYPE_F2_F4: optcr_reg = STM32_FLASH_F4_OPTCR; optlock_shift = STM32_FLASH_F4_OPTCR_LOCK; break; case STM32_FLASH_TYPE_F7: optcr_reg = STM32_FLASH_F7_OPTCR; optlock_shift = STM32_FLASH_F7_OPTCR_LOCK; break; case STM32_FLASH_TYPE_G0: case STM32_FLASH_TYPE_G4: optcr_reg = STM32_FLASH_Gx_CR; optlock_shift = STM32_FLASH_Gx_CR_OPTLOCK; break; case STM32_FLASH_TYPE_H7: optcr_reg = STM32_FLASH_H7_OPTCR; optlock_shift = STM32_FLASH_H7_OPTCR_OPTLOCK; if(sl->chip_flags & CHIP_F_HAS_DUAL_BANK) optcr2_reg = STM32_FLASH_H7_OPTCR2; break; case STM32_FLASH_TYPE_L0_L1: optcr_reg = get_stm32l0_flash_base(sl) + FLASH_PECR_OFF; optlock_shift = STM32_FLASH_L0_OPTLOCK; break; case STM32_FLASH_TYPE_L4: optcr_reg = STM32_FLASH_L4_CR; optlock_shift = STM32_FLASH_L4_CR_OPTLOCK; break; case STM32_FLASH_TYPE_L5_U5: optcr_reg = STM32_FLASH_L5_NSCR; optlock_shift = STM32_FLASH_L5_NSCR_OPTLOCK; break; case STM32_FLASH_TYPE_WB_WL: optcr_reg = STM32_FLASH_WB_CR; optlock_shift = STM32_FLASH_WB_CR_OPTLOCK; break; default: ELOG("unsupported flash method, abort\n"); return -1; } stlink_read_debug32(sl, optcr_reg, &n); if(active_bit_level == 0) { n &= ~(1u << optlock_shift); } else { n |= (1u << optlock_shift); } stlink_write_debug32(sl, optcr_reg, n); if(optcr2_reg) { stlink_read_debug32(sl, optcr2_reg, &n); if(active_bit_level == 0) { n &= ~(1u << optlock_shift); } else { n |= (1u << optlock_shift); } stlink_write_debug32(sl, optcr2_reg, n); } return (0); } static bool is_flash_option_locked(stlink_t *sl) { uint32_t optlock_shift, optcr_reg; int32_t active_bit_level = 1; uint32_t n; switch (sl->flash_type) { case STM32_FLASH_TYPE_C0: optcr_reg = STM32_FLASH_C0_CR; optlock_shift = STM32_FLASH_C0_CR_OPTLOCK; break; case STM32_FLASH_TYPE_F0_F1_F3: case STM32_FLASH_TYPE_F1_XL: optcr_reg = FLASH_CR; optlock_shift = FLASH_CR_OPTWRE; active_bit_level = 0; /* bit is "option write enable", not lock */ break; case STM32_FLASH_TYPE_F2_F4: optcr_reg = STM32_FLASH_F4_OPTCR; optlock_shift = STM32_FLASH_F4_OPTCR_LOCK; break; case STM32_FLASH_TYPE_F7: optcr_reg = STM32_FLASH_F7_OPTCR; optlock_shift = STM32_FLASH_F7_OPTCR_LOCK; break; case STM32_FLASH_TYPE_G0: case STM32_FLASH_TYPE_G4: optcr_reg = STM32_FLASH_Gx_CR; optlock_shift = STM32_FLASH_Gx_CR_OPTLOCK; break; case STM32_FLASH_TYPE_H7: optcr_reg = STM32_FLASH_H7_OPTCR; optlock_shift = STM32_FLASH_H7_OPTCR_OPTLOCK; break; case STM32_FLASH_TYPE_L0_L1: optcr_reg = get_stm32l0_flash_base(sl) + FLASH_PECR_OFF; optlock_shift = STM32_FLASH_L0_OPTLOCK; break; case STM32_FLASH_TYPE_L4: optcr_reg = STM32_FLASH_L4_CR; optlock_shift = STM32_FLASH_L4_CR_OPTLOCK; break; case STM32_FLASH_TYPE_L5_U5: optcr_reg = STM32_FLASH_L5_NSCR; optlock_shift = STM32_FLASH_L5_NSCR_OPTLOCK; break; case STM32_FLASH_TYPE_WB_WL: optcr_reg = STM32_FLASH_WB_CR; optlock_shift = STM32_FLASH_WB_CR_OPTLOCK; break; default: ELOG("unsupported flash method, abort\n"); return -1; } stlink_read_debug32(sl, optcr_reg, &n); if(active_bit_level == 0) { return (!(n & (1u << optlock_shift))); } return (n & (1u << optlock_shift)); } static int32_t unlock_flash_option(stlink_t *sl) { uint32_t optkey_reg, optkey2_reg = 0; uint32_t optkey1 = FLASH_OPTKEY1; uint32_t optkey2 = FLASH_OPTKEY2; switch (sl->flash_type) { case STM32_FLASH_TYPE_C0: optkey_reg = STM32_FLASH_C0_OPT_KEYR; break; case STM32_FLASH_TYPE_F0_F1_F3: case STM32_FLASH_TYPE_F1_XL: optkey_reg = FLASH_OPTKEYR; optkey1 = STM32_FLASH_F0_OPTKEY1; optkey2 = STM32_FLASH_F0_OPTKEY2; break; case STM32_FLASH_TYPE_F2_F4: optkey_reg = STM32_FLASH_F4_OPT_KEYR; break; case STM32_FLASH_TYPE_F7: optkey_reg = STM32_FLASH_F7_OPT_KEYR; break; case STM32_FLASH_TYPE_G0: case STM32_FLASH_TYPE_G4: optkey_reg = STM32_FLASH_Gx_OPTKEYR; break; case STM32_FLASH_TYPE_H7: optkey_reg = STM32_FLASH_H7_OPT_KEYR; break; case STM32_FLASH_TYPE_L0_L1: optkey_reg = get_stm32l0_flash_base(sl) + FLASH_OPTKEYR_OFF; optkey1 = STM32_FLASH_L0_OPTKEY1; optkey2 = STM32_FLASH_L0_OPTKEY2; break; case STM32_FLASH_TYPE_L4: optkey_reg = STM32_FLASH_L4_OPTKEYR; break; case STM32_FLASH_TYPE_L5_U5: optkey_reg = STM32_FLASH_L5_OPTKEYR; break; case STM32_FLASH_TYPE_WB_WL: optkey_reg = STM32_FLASH_WB_OPT_KEYR; break; default: ELOG("unsupported flash method, abort\n"); return (-1); } stlink_write_debug32(sl, optkey_reg, optkey1); stlink_write_debug32(sl, optkey_reg, optkey2); if(optkey2_reg) { stlink_write_debug32(sl, optkey2_reg, optkey1); stlink_write_debug32(sl, optkey2_reg, optkey2); } return (0); } int32_t unlock_flash_option_if(stlink_t *sl) { if(is_flash_option_locked(sl)) { if(unlock_flash_option(sl)) { ELOG("Could not unlock flash option!\n"); return (-1); } if(is_flash_option_locked(sl)) { ELOG("Failed to unlock flash option!\n"); return (-1); } } DLOG("Successfully unlocked flash option\n"); return (0); } void write_flash_cr_psiz(stlink_t *sl, uint32_t n, uint32_t bank) { uint32_t cr_reg, psize_shift; uint32_t x = read_flash_cr(sl, bank); if(sl->flash_type == STM32_FLASH_TYPE_H7) { cr_reg = (bank == BANK_1) ? STM32_FLASH_H7_CR1 : STM32_FLASH_H7_CR2; psize_shift = STM32_FLASH_H7_CR_PSIZE; } else { cr_reg = STM32_FLASH_F4_CR; psize_shift = 8; } x &= ~(0x03 << psize_shift); x |= (n << psize_shift); #if DEBUG_FLASH fprintf(stdout, "PSIZ:0x%x 0x%x\n", x, n); #endif stlink_write_debug32(sl, cr_reg, x); } void clear_flash_cr_pg(stlink_t *sl, uint32_t bank) { uint32_t cr_reg, n; uint32_t bit = FLASH_CR_PG; if(sl->flash_type == STM32_FLASH_TYPE_C0) { cr_reg = STM32_FLASH_C0_CR; } else if(sl->flash_type == STM32_FLASH_TYPE_F2_F4) { cr_reg = STM32_FLASH_F4_CR; } else if(sl->flash_type == STM32_FLASH_TYPE_F7) { cr_reg = STM32_FLASH_F7_CR; } else if(sl->flash_type == STM32_FLASH_TYPE_G0 || sl->flash_type == STM32_FLASH_TYPE_G4) { cr_reg = STM32_FLASH_Gx_CR; } else if(sl->flash_type == STM32_FLASH_TYPE_H7) { cr_reg = (bank == BANK_1) ? STM32_FLASH_H7_CR1 : STM32_FLASH_H7_CR2; bit = STM32_FLASH_H7_CR_PG; } else if(sl->flash_type == STM32_FLASH_TYPE_L4) { cr_reg = STM32_FLASH_L4_CR; } else if(sl->flash_type == STM32_FLASH_TYPE_L5_U5) { cr_reg = STM32_FLASH_L5_NSCR; } else if(sl->flash_type == STM32_FLASH_TYPE_H5) { cr_reg = STM32_FLASH_H5_NSCR; bit = STM32_FLASH_H5_NSCR_PG; } else if(sl->flash_type == STM32_FLASH_TYPE_WB_WL) { cr_reg = STM32_FLASH_WB_CR; } else if(sl->flash_type == STM32_FLASH_TYPE_C5) { cr_reg = STM32_FLASH_C5_CR; bit = STM32_FLASH_C5_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) { int32_t i = 0; fprintf(stdout, "Mass erasing..."); fflush(stdout); while (is_flash_busy(sl)) { usleep(10000); i++; if(i % 100 == 0) { fprintf(stdout, "."); fflush(stdout); } } fprintf(stdout, "\n"); } static inline void write_flash_ar(stlink_t *sl, uint32_t n, uint32_t bank) { stlink_write_debug32(sl, (bank == BANK_1) ? FLASH_AR : FLASH_AR2, n); } static inline void write_flash_cr_snb(stlink_t *sl, uint32_t n, uint32_t bank) { uint32_t cr_reg, snb_mask, snb_shift, ser_shift; uint32_t x = read_flash_cr(sl, bank); if(sl->flash_type == STM32_FLASH_TYPE_H7) { cr_reg = (bank == BANK_1) ? STM32_FLASH_H7_CR1 : STM32_FLASH_H7_CR2; snb_mask = STM32_FLASH_H7_CR_SNB_MASK; snb_shift = STM32_FLASH_H7_CR_SNB; ser_shift = STM32_FLASH_H7_CR_SER; } else { cr_reg = STM32_FLASH_F4_CR; snb_mask = STM32_FLASH_F4_CR_SNB_MASK; snb_shift = STM32_FLASH_F4_CR_SNB; ser_shift = STM32_FLASH_F4_CR_SER; } x &= ~snb_mask; x |= (n << snb_shift); x |= (1 << ser_shift); #if DEBUG_FLASH fprintf(stdout, "SNB:0x%x 0x%x\n", x, n); #endif stlink_write_debug32(sl, cr_reg, x); } static void set_flash_cr_per(stlink_t *sl, uint32_t bank) { uint32_t cr_reg, val; uint32_t per_shift = FLASH_CR_PER; if(sl->flash_type == STM32_FLASH_TYPE_C0) { cr_reg = STM32_FLASH_C0_CR; } else if(sl->flash_type == STM32_FLASH_TYPE_G0 || sl->flash_type == STM32_FLASH_TYPE_G4) { cr_reg = STM32_FLASH_Gx_CR; } else if(sl->flash_type == STM32_FLASH_TYPE_L5_U5) { cr_reg = STM32_FLASH_L5_NSCR; } else if(sl->flash_type == STM32_FLASH_TYPE_WB_WL) { cr_reg = STM32_FLASH_WB_CR; } else if(sl->flash_type == STM32_FLASH_TYPE_C5) { cr_reg = STM32_FLASH_C5_CR; per_shift = STM32_FLASH_C5_CR_PER; } else { cr_reg = (bank == BANK_1) ? FLASH_CR : FLASH_CR2; } stlink_read_debug32(sl, cr_reg, &val); val |= (1 << per_shift); stlink_write_debug32(sl, cr_reg, val); } static void clear_flash_cr_per(stlink_t *sl, uint32_t bank) { uint32_t cr_reg; uint32_t per_shift = FLASH_CR_PER; if(sl->flash_type == STM32_FLASH_TYPE_C0) { cr_reg = STM32_FLASH_C0_CR; } else if(sl->flash_type == STM32_FLASH_TYPE_G0 || sl->flash_type == STM32_FLASH_TYPE_G4) { cr_reg = STM32_FLASH_Gx_CR; } else if(sl->flash_type == STM32_FLASH_TYPE_L5_U5) { cr_reg = STM32_FLASH_L5_NSCR; } else if(sl->flash_type == STM32_FLASH_TYPE_WB_WL) { cr_reg = STM32_FLASH_WB_CR; } else if(sl->flash_type == STM32_FLASH_TYPE_C5) { cr_reg = STM32_FLASH_C5_CR; per_shift = STM32_FLASH_C5_CR_PER; } else { cr_reg = (bank == BANK_1) ? FLASH_CR : FLASH_CR2; } const uint32_t n = read_flash_cr(sl, bank) & ~(1 << per_shift); stlink_write_debug32(sl, cr_reg, n); } static inline void write_flash_cr_bker_pnb(stlink_t *sl, uint32_t n) { // Clear EOP and all error flags. stlink_write_debug32(sl, STM32_FLASH_L4_SR, STM32_FLASH_L4_SR_CLEAR_MASK); uint32_t x = read_flash_cr(sl, BANK_1); x &= ~STM32_FLASH_L4_CR_OPBITS; x &= ~STM32_FLASH_L4_CR_PAGEMASK; x &= ~(1 << STM32_FLASH_L4_CR_MER1); x &= ~(1 << STM32_FLASH_L4_CR_MER2); x |= (n << STM32_FLASH_L4_CR_PNB); x |= (uint32_t) (1lu << STM32_FLASH_L4_CR_PER); #if DEBUG_FLASH fprintf(stdout, "BKER:PNB:0x%x 0x%x\n", x, n); #endif stlink_write_debug32(sl, STM32_FLASH_L4_CR, x); } static void set_flash_cr_strt(stlink_t *sl, uint32_t bank) { uint32_t val, cr_reg, cr_strt; if(sl->flash_type == STM32_FLASH_TYPE_C0) { cr_reg = STM32_FLASH_C0_CR; cr_strt = 1 << STM32_FLASH_C0_CR_STRT; } else if(sl->flash_type == STM32_FLASH_TYPE_F2_F4) { cr_reg = STM32_FLASH_F4_CR; cr_strt = 1 << STM32_FLASH_F4_CR_STRT; } else if(sl->flash_type == STM32_FLASH_TYPE_F7) { cr_reg = STM32_FLASH_F7_CR; cr_strt = 1 << STM32_FLASH_F7_CR_STRT; } else if(sl->flash_type == STM32_FLASH_TYPE_G0 || sl->flash_type == STM32_FLASH_TYPE_G4) { cr_reg = STM32_FLASH_Gx_CR; cr_strt = (1 << STM32_FLASH_Gx_CR_STRT); } else if(sl->flash_type == STM32_FLASH_TYPE_H7) { cr_reg = (bank == BANK_1) ? STM32_FLASH_H7_CR1 : STM32_FLASH_H7_CR2; cr_strt = 1 << STM32_FLASH_H7_CR_START(sl->chip_id); } else if(sl->flash_type == STM32_FLASH_TYPE_L4) { cr_reg = STM32_FLASH_L4_CR; cr_strt = (1 << STM32_FLASH_L4_CR_STRT); } else if(sl->flash_type == STM32_FLASH_TYPE_L5_U5) { cr_reg = STM32_FLASH_L5_NSCR; cr_strt = (1 << STM32_FLASH_L5_NSCR_NSSTRT); } else if(sl->flash_type == STM32_FLASH_TYPE_H5) { cr_reg = STM32_FLASH_H5_NSCR; cr_strt = (1 << STM32_FLASH_H5_NSCR_STRT); } else if(sl->flash_type == STM32_FLASH_TYPE_WB_WL) { cr_reg = STM32_FLASH_WB_CR; cr_strt = (1 << STM32_FLASH_WB_CR_STRT); } else if(sl->flash_type == STM32_FLASH_TYPE_C5) { cr_reg = STM32_FLASH_C5_CR; cr_strt = (1 << STM32_FLASH_C5_CR_STRT); } else { cr_reg = (bank == BANK_1) ? FLASH_CR : FLASH_CR2; cr_strt = (1 << FLASH_CR_STRT); } stlink_read_debug32(sl, cr_reg, &val); val |= cr_strt; stlink_write_debug32(sl, cr_reg, val); } static void set_flash_cr_mer(stlink_t *sl, bool v, uint32_t bank) { uint32_t val, cr_reg, cr_mer, cr_pg; if(sl->flash_type == STM32_FLASH_TYPE_C0) { cr_reg = STM32_FLASH_C0_CR; cr_mer = 1 << FLASH_CR_MER; cr_pg = 1 << FLASH_CR_PG; } else if(sl->flash_type == STM32_FLASH_TYPE_F2_F4) { cr_reg = STM32_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 = STM32_FLASH_F7_CR; cr_mer = 1 << FLASH_CR_MER; cr_pg = 1 << FLASH_CR_PG; } else if(sl->flash_type == STM32_FLASH_TYPE_G0 || sl->flash_type == STM32_FLASH_TYPE_G4) { cr_reg = STM32_FLASH_Gx_CR; cr_mer = (1 << STM32_FLASH_Gx_CR_MER1); if(stlink_gx_dual_bank(sl)) { cr_mer |= (1 << STM32_FLASH_Gx_CR_MER2); } cr_pg = (1 << FLASH_CR_PG); } else if(sl->flash_type == STM32_FLASH_TYPE_H7) { cr_reg = (bank == BANK_1) ? STM32_FLASH_H7_CR1 : STM32_FLASH_H7_CR2; cr_mer = (1 << STM32_FLASH_H7_CR_BER); cr_pg = (1 << STM32_FLASH_H7_CR_PG); } else if(sl->flash_type == STM32_FLASH_TYPE_L4) { cr_reg = STM32_FLASH_L4_CR; cr_mer = (1 << STM32_FLASH_L4_CR_MER1) | (1 << STM32_FLASH_L4_CR_MER2); cr_pg = (1 << STM32_FLASH_L4_CR_PG); } else if(sl->flash_type == STM32_FLASH_TYPE_L5_U5) { cr_reg = STM32_FLASH_L5_NSCR; cr_mer = (1 << STM32_FLASH_L5_NSCR_NSMER1) | (1 << STM32_FLASH_L5_NSCR_NSMER2); cr_pg = (1 << STM32_FLASH_L5_NSCR_NSPG); } else if(sl->flash_type == STM32_FLASH_TYPE_H5) { cr_reg = STM32_FLASH_H5_NSCR; cr_mer = (1 << STM32_FLASH_H5_NSCR_MER); cr_pg = (1 << STM32_FLASH_H5_NSCR_PG); } else if(sl->flash_type == STM32_FLASH_TYPE_WB_WL) { cr_reg = STM32_FLASH_WB_CR; cr_mer = (1 << FLASH_CR_MER); cr_pg = (1 << FLASH_CR_PG); } else if(sl->flash_type == STM32_FLASH_TYPE_C5) { cr_reg = STM32_FLASH_C5_CR; cr_mer = (1 << STM32_FLASH_C5_CR_MER); cr_pg = (1 << STM32_FLASH_C5_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); } /* * Read the STM32H5 SWAP_BANK option bit. When set, the two physical banks are * mapped swapped in the address space; the BKSEL erase selector targets the * physical bank and ignores SWAP_BANK (RM0481), so the sector erase below has * to invert BKSEL to match a logical address. */ static bool stlink_h5_bank_swapped(stlink_t *sl) { uint32_t optsr = 0; stlink_read_debug32(sl, STM32_FLASH_H5_OPTSR_CUR, &optsr); return (optsr >> STM32_FLASH_H5_OPTSR_SWAP_BANK) & 1u; } /** * Erase a page of flash, assumes sl is fully populated with things like * chip/core ids * @param sl stlink context * @param flashaddr an address in the flash page to erase * @return 0 on success -ve on failure */ int32_t stlink_erase_flash_page(stlink_t *sl, stm32_addr_t flashaddr) { // wait for ongoing op to finish wait_flash_busy(sl); // clear flash IO errors clear_flash_error(sl); if(sl->flash_type == STM32_FLASH_TYPE_F2_F4 || sl->flash_type == STM32_FLASH_TYPE_F7 || sl->flash_type == STM32_FLASH_TYPE_L4) { // unlock if locked unlock_flash_if(sl); // select the page to erase // STM32L4 if(sl->flash_type == STM32_FLASH_TYPE_L4) { // calculate the actual bank+page from the address uint32_t page = calculate_L4_page(sl, flashaddr); fprintf(stderr, "EraseFlash - Page:0x%x Size:0x%x ", page, stlink_calculate_pagesize(sl, flashaddr)); write_flash_cr_bker_pnb(sl, page); // STM32F7 } 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); // STM32F2 // STM32F4 } 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 // STM32L0 // STM32L1 } 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, STM32_FLASH_L0_PEKEY1); stlink_write_debug32(sl, flash_regs_base + FLASH_PEKEYR_OFF, STM32_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, STM32_FLASH_L0_PRGKEY1); stlink_write_debug32(sl, flash_regs_base + FLASH_PRGKEYR_OFF, STM32_FLASH_L0_PRGKEY2); // check pecr.prglock is cleared stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val); if(val & (1 << 1)) { WLOG("pecr.prglock not clear (%#x)\n", val); return (-1); } } // set pecr.{erase,prog} val |= (1 << 9) | (1 << 3); stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val); // write 0 to the first word of the page to be erased stlink_write_debug32(sl, flashaddr, 0); /* MP: It is better to wait for clearing the busy bit after issuing page * erase command, even though PM0062 recommends to wait before it. * Test shows that a few iterations is performed in the following loop * before busy bit is cleared. */ wait_flash_busy(sl); // reset lock bits stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val); val |= (1 << 0) | (1 << 1) | (1 << 2); stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val); } else if(sl->flash_type == STM32_FLASH_TYPE_G0 || sl->flash_type == STM32_FLASH_TYPE_G4 || sl->flash_type == STM32_FLASH_TYPE_L5_U5 || sl->flash_type == STM32_FLASH_TYPE_WB_WL || sl->flash_type == STM32_FLASH_TYPE_C0 || sl->flash_type == STM32_FLASH_TYPE_C5) { uint32_t val; unlock_flash_if(sl); // STM32G0/G4 set PER together with PNB/BKER in a single write below (as // the ST HAL does): on G0, setting PER already sets CFGBSY (RM0444). if(sl->flash_type != STM32_FLASH_TYPE_G0 && sl->flash_type != STM32_FLASH_TYPE_G4) { set_flash_cr_per(sl, BANK_1); // set the 'enable Flash erase' bit } // set the page to erase // STM32G0 // STM32G4 if(sl->flash_type == STM32_FLASH_TYPE_G0 || sl->flash_type == STM32_FLASH_TYPE_G4) { bool is_g0 = (sl->flash_type == STM32_FLASH_TYPE_G0); uint32_t pnb_len = is_g0 ? STM32_FLASH_G0_CR_PNB_LEN : (sl->chip_id == STM32_CHIPID_G4_CAT4) ? STM32_FLASH_G4_CAT4_CR_PNB_LEN : STM32_FLASH_G4_CR_PNB_LEN; uint32_t pnb_mask = (1u << pnb_len) - 1; uint32_t bker_bit = is_g0 ? STM32_FLASH_G0_CR_BKER : STM32_FLASH_G4_CR_BKER; uint32_t offset = flashaddr - STM32_FLASH_BASE; bool dual_bank = stlink_gx_dual_bank(sl); bool upper_half = dual_bank && (offset >= sl->flash_size / 2); // The page number follows the logical memory mapping, whereas BKER // selects the *physical* bank. On G0B1/G0C1 the banks are swapped in the // memory map when FLASH_OPTR.nSWAP_BANK is cleared, so the upper half of // the address range then belongs to physical bank 1 (and vice versa). // Same rule as for H5/C5 below; see also ST community thread // "STM32G0 erasing bank2" and apache/nuttx#20081. bool swap_bank = dual_bank && is_g0 && stlink_g0_bank_swapped(sl); bool bank2 = (upper_half != swap_bank); // In dual-bank mode PNB is the page number *inside* the bank // (RM0444/RM0440 sec. 3.7.5, see also HAL FLASH_PageErase()). if(upper_half) { offset -= sl->flash_size / 2; } uint32_t flash_page = offset / sl->flash_pgsz; DLOG("Page erase at %#x: physical bank %u, page %u%s\n", flashaddr, bank2 ? 2u : 1u, flash_page, swap_bank ? " (banks swapped)" : ""); stlink_read_debug32(sl, STM32_FLASH_Gx_CR, &val); // Sec. 3.3.8 - PGSERR: PG, FSTPG and MER1/MER2 are not cleared by // hardware when PER is set (RM0444/RM0440, applies to both G0 and G4). val &= ~(1u << STM32_FLASH_Gx_CR_MER1); val &= ~(1u << STM32_FLASH_Gx_CR_MER2); val &= ~(1u << STM32_FLASH_Gx_CR_FSTPG); val &= ~(1u << STM32_FLASH_Gx_CR_PG); // BKER only exists on dual-bank capable devices and must be kept // cleared in single-bank mode. if(bank2) { val |= (1u << bker_bit); } else if(is_g0 || sl->chip_id == STM32_CHIPID_G4_CAT3) { val &= ~(1u << bker_bit); } val &= ~(pnb_mask << STM32_FLASH_Gx_CR_PNB); val |= ((flash_page & pnb_mask) << STM32_FLASH_Gx_CR_PNB) | (1u << FLASH_CR_PER); stlink_write_debug32(sl, STM32_FLASH_Gx_CR, val); // STM32L5 // STM32U5 } else if(sl->flash_type == STM32_FLASH_TYPE_L5_U5) { // STM32L5x2xx has two banks with 2k pages or single with 4k pages // STM32U535, STM32U545, STM32U575 or STM32U585 have 2 banks with 8k pages uint32_t flash_page; stlink_read_debug32(sl, STM32_FLASH_L5_NSCR, &val); if((sl->flash_pgsz == 0x800 || sl->flash_pgsz == 0x2000) && (flashaddr - STM32_FLASH_BASE) >= sl->flash_size/2) { flash_page = (flashaddr - STM32_FLASH_BASE - sl->flash_size/2) / sl->flash_pgsz; // set bank 2 for erasure val |= (1 << STM32_FLASH_L5_NSCR_NSBKER); } else { flash_page = ((flashaddr - STM32_FLASH_BASE) / sl->flash_pgsz); // set bank 1 for erasure val &= ~(1 << STM32_FLASH_L5_NSCR_NSBKER); } // sec 7.9.9 for U5, 6.9.9 for L5 (for L7 we have 7 bits instead of 8 bits for U5 but // the bit position for 8th bit reserved. // Maybe the best solution is to handle each one separately. val &= ~(0xFF << 3); val |= ((flash_page & 0xFF) << 3) | (1 << FLASH_CR_PER); stlink_write_debug32(sl, STM32_FLASH_L5_NSCR, val); // STM32WB // STM32WL } else if(sl->flash_type == STM32_FLASH_TYPE_WB_WL) { uint32_t flash_page = ((flashaddr - STM32_FLASH_BASE) / sl->flash_pgsz); stlink_read_debug32(sl, STM32_FLASH_WB_CR, &val); // sec 3.10.5 - PNB[7:0] is offset by 3. val &= ~(0xFF << 3); // Clear previously set page number (if any) val |= ((flash_page & 0xFF) << 3); stlink_write_debug32(sl, STM32_FLASH_WB_CR, val); // STM32C0 } else if(sl->flash_type == STM32_FLASH_TYPE_C0) { uint32_t flash_page = ((flashaddr - STM32_FLASH_BASE) / sl->flash_pgsz); stlink_read_debug32(sl, STM32_FLASH_C0_CR, &val); val &= ~(0xF << STM32_FLASH_C0_CR_PNB); val |= ((flash_page & 0xF) << STM32_FLASH_C0_CR_PNB); stlink_write_debug32(sl, STM32_FLASH_C0_CR, val); // STM32C5 } else if(sl->flash_type == STM32_FLASH_TYPE_C5) { // RM0522: page erase via CR.PER@2 + CR.PNB@6, bank via CR.BKSEL@31. // In dual-bank mode, bank 2 base = flash_base + flash_size/2. Half-size // devices can instead use one bank, with PNB spanning the whole flash. uint32_t flash_page, optsr = 0; stlink_read_debug32(sl, STM32_FLASH_C5_CR, &val); stlink_read_debug32(sl, STM32_FLASH_C5_OPTSR_CUR, &optsr); bool upper_half = (flashaddr - STM32_FLASH_BASE) >= sl->flash_size / 2; bool single_bank = (optsr >> STM32_FLASH_C5_OPTSR_CUR_SINGLE_BANK) & 1u; bool swap_bank = (optsr >> STM32_FLASH_C5_OPTSR_CUR_SWAP_BANK) & 1u; if(single_bank) { flash_page = (flashaddr - STM32_FLASH_BASE) / sl->flash_pgsz; val &= ~(1u << STM32_FLASH_C5_CR_BKSEL); } else { flash_page = (flashaddr - STM32_FLASH_BASE - (upper_half ? sl->flash_size / 2 : 0)) / sl->flash_pgsz; if(upper_half != swap_bank) { val |= (1u << STM32_FLASH_C5_CR_BKSEL); } else { val &= ~(1u << STM32_FLASH_C5_CR_BKSEL); } } val &= ~(0x7F << STM32_FLASH_C5_CR_PNB); val &= ~(1u << STM32_FLASH_C5_CR_PG); val &= ~(1u << STM32_FLASH_C5_CR_BER); val &= ~(1u << STM32_FLASH_C5_CR_MER); val |= ((flash_page & 0x7F) << STM32_FLASH_C5_CR_PNB); val |= (1u << STM32_FLASH_C5_CR_PER); stlink_write_debug32(sl, STM32_FLASH_C5_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); // STM32H5 } else if(sl->flash_type == STM32_FLASH_TYPE_H5) { // STM32H5: sector erase via NSCR. SNB selects the 8 KiB sector within the // bank, BKSEL the bank (RM0481). 256 sectors total, 128 per bank. uint32_t val, flash_page; unlock_flash_if(sl); clear_flash_error(sl); // clear stale NSSR flags through NSCCR // BKSEL selects the physical bank and ignores the SWAP_BANK option, so // invert it against the logical address when the banks are swapped (RM0481). bool swap_bank = stlink_h5_bank_swapped(sl); bool upper_half = (flashaddr - STM32_FLASH_BASE) >= sl->flash_size / 2; if(upper_half) { flash_page = (flashaddr - STM32_FLASH_BASE - sl->flash_size / 2) / sl->flash_pgsz; } else { flash_page = (flashaddr - STM32_FLASH_BASE) / sl->flash_pgsz; } stlink_read_debug32(sl, STM32_FLASH_H5_NSCR, &val); val &= ~(STM32_FLASH_H5_NSCR_SNB_MASK | (1u << STM32_FLASH_H5_NSCR_BKSEL) | (1u << STM32_FLASH_H5_NSCR_MER) | (1u << STM32_FLASH_H5_NSCR_PG)); if(upper_half != swap_bank) { val |= (1u << STM32_FLASH_H5_NSCR_BKSEL); } val |= (1u << STM32_FLASH_H5_NSCR_SER) | ((flash_page & 0x7F) << STM32_FLASH_H5_NSCR_SNB); stlink_write_debug32(sl, STM32_FLASH_H5_NSCR, val); set_flash_cr_strt(sl, BANK_1); // start the sector erase wait_flash_busy(sl); stlink_read_debug32(sl, STM32_FLASH_H5_NSCR, &val); val &= ~(1u << STM32_FLASH_H5_NSCR_SER); stlink_write_debug32(sl, STM32_FLASH_H5_NSCR, val); lock_flash(sl); // STM32WB0 } else if(sl->flash_type == STM32_FLASH_TYPE_WB0) { uint32_t flash_page = ((flashaddr - sl->flash_base) / sl->flash_pgsz); stlink_write_debug32(sl, STM32_FLASH_WB0_IRQRAW, STM32_FLASH_WB0_IRQ_ALL); stlink_write_debug32(sl, STM32_FLASH_WB0_ADDRESS, (flash_page * sl->flash_pgsz) >> 2); stlink_write_debug32(sl, STM32_FLASH_WB0_COMMAND, STM32_FLASH_WB0_CMD_ERASE_PAGE); wait_flash_busy(sl); // STM32Fx } else if(sl->flash_type == STM32_FLASH_TYPE_F0_F1_F3 || sl->flash_type == STM32_FLASH_TYPE_F1_XL) { uint32_t bank = (flashaddr < STM32_F1_FLASH_BANK2_BASE) ? BANK_1 : BANK_2; unlock_flash_if(sl); clear_flash_cr_pg(sl, bank); // clear the pg bit set_flash_cr_per(sl, bank); // set the page erase bit write_flash_ar(sl, flashaddr, bank); // select the page to erase set_flash_cr_strt(sl, bank); // start erase operation, reset by hw with busy bit wait_flash_busy(sl); clear_flash_cr_per(sl, bank); // clear the page erase bit lock_flash(sl); // STM32H7 } else if(sl->flash_type == STM32_FLASH_TYPE_H7) { uint32_t bank = (flashaddr < STM32_H7_FLASH_BANK2_BASE) ? BANK_1 : BANK_2; unlock_flash_if(sl); // unlock if locked uint32_t sector = calculate_H7_sectornum(sl, flashaddr, bank); // calculate the actual page from the address write_flash_cr_snb(sl, sector, bank); // select the page to erase set_flash_cr_strt(sl, bank); // start erase operation wait_flash_busy(sl); // wait for completion lock_flash(sl); // Unknown Core-ID } else { WLOG("unknown coreid %x, page erase failed\n", sl->core_id); return (-1); } return check_flash_error(sl); } int32_t stlink_erase_flash_section(stlink_t *sl, stm32_addr_t base_addr, uint32_t size, bool align_size) { // Check the address and size validity if(stlink_check_address_range_validity(sl, base_addr, size) < 0) { return -1; } // Make sure the requested address is aligned with the beginning of a page if(stlink_check_address_alignment(sl, base_addr) < 0) { ELOG("The address to erase is not aligned with the beginning of a page\n"); return -1; } stm32_addr_t addr = base_addr; do { uint32_t page_size = stlink_calculate_pagesize(sl, addr); // Check if size is aligned with a page, unless we want to completely erase the last page if((addr + page_size) > (base_addr + size) && !align_size) { ELOG("Invalid size (not aligned with a page). Page size at address %#x is %#x\n", addr, page_size); return (-1); } if(stlink_erase_flash_page(sl, addr)) { WLOG("Failed to erase_flash_page(%#x) == -1\n", addr); return (-1); } fprintf(stdout, "-> Flash page at %#x erased (size: %#x)\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; } int32_t stlink_erase_flash_mass(stlink_t *sl) { int32_t err = 0; // TODO: Use MER bit to mass-erase WB series. if(sl->flash_type == STM32_FLASH_TYPE_L0_L1 || sl->flash_type == STM32_FLASH_TYPE_WB_WL) { err = stlink_erase_flash_section(sl, sl->flash_base, sl->flash_size, false); } else if(sl->flash_type == STM32_FLASH_TYPE_WB0) { if(sl->chip_id == STM32_CHIPID_WB06_WB07 || sl->chip_id == STM32_CHIPID_WB09) { stlink_write_debug32(sl, STM32_FLASH_WB0_IRQRAW, STM32_FLASH_WB0_IRQ_ALL); stlink_write_debug32(sl, STM32_FLASH_WB0_COMMAND, STM32_FLASH_WB0_CMD_MASS_ERASE); wait_flash_busy_progress(sl); } else { // WB05 & WL3x do not support mass erase 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 /* 64 bit */, BANK_1); if(sl->chip_flags & CHIP_F_HAS_DUAL_BANK) { write_flash_cr_psiz(sl, 3 /* 64 bit */, 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); // reset the mass erase bit (must happen before locking, as FLASH_CR is // write protected once locked and a stale MERx bit causes PGSERR on the // next program operation, e.g. on STM32G0/G4) 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); } lock_flash(sl); err = check_flash_error(sl); } return (err); } int32_t stlink_mwrite_flash(stlink_t *sl, uint8_t *data, uint32_t length, stm32_addr_t addr, const enum erase_type_t erase_type) { /* Write the block in flash at addr */ int32_t err; uint32_t num_empty, idx; uint8_t erased_pattern = stlink_get_erased_pattern(sl); /* * This optimisation may cause unexpected garbage data remaining. * Therfore it is turned off by default. */ if(sl->opt) { idx = length; for(num_empty = 0; num_empty != length; ++num_empty) if(data[--idx] != erased_pattern) { break; } num_empty -= (num_empty & 3); // Round down to words if(num_empty != 0) { ILOG("Ignoring %d bytes of 0x%02x at end of file\n", num_empty, erased_pattern); } } else { num_empty = 0; } /* * TODO: investigate a kind of weird behaviour here: * If the file is identified to be all-empty and four-bytes aligned, * still flash the whole file even if ignoring message is printed. */ err = stlink_write_flash(sl, addr, data, (num_empty == length) ? length : length - num_empty, num_empty == length, erase_type); stlink_fwrite_finalize(sl, addr); return (err); } /** * Write the given binary file into flash at address "addr" * @param sl * @param path readable file path, should be binary image * @param addr where to start writing * @return 0 on success, -ve on failure. */ int32_t stlink_fwrite_flash(stlink_t *sl, const char *path, stm32_addr_t addr, const enum erase_type_t erase_type) { /* Write the file in flash at addr */ int32_t err; uint32_t num_empty, idx; uint8_t erased_pattern = stlink_get_erased_pattern(sl); mapped_file_t mf = MAPPED_FILE_INITIALIZER; if(map_file(&mf, path) == -1) { ELOG("map_file() == -1\n"); return (-1); } printf("file %s ", path); md5_calculate(&mf); stlink_checksum(&mf); if(sl->opt) { idx = (uint32_t) mf.len; for(num_empty = 0; num_empty != mf.len; ++num_empty) { if(mf.base[--idx] != erased_pattern) { break; } } num_empty -= (num_empty & 3); // round down to words if(num_empty != 0) { ILOG("Ignoring %d bytes of 0x%02x at end of file\n", num_empty, erased_pattern); } } else { num_empty = 0; } /* * TODO: investigate a kind of weird behaviour here: * If the file is identified to be all-empty and four-bytes aligned, * still flash the whole file even if ignoring message is printed. */ /* In case the address is within the OTP area we use a different flash method */ if(addr >= sl->otp_base && addr < sl->otp_base + sl->otp_size) { err = stlink_write_otp(sl, addr, mf.base, (num_empty == mf.len) ? (uint32_t) mf.len : (uint32_t) mf.len - num_empty); } else { err = stlink_write_flash(sl, addr, mf.base, (num_empty == mf.len) ? (uint32_t) mf.len : (uint32_t)mf.len - num_empty, num_empty == mf.len, erase_type); } stlink_fwrite_finalize(sl, addr); unmap_file(&mf); return (err); } int32_t stlink_fcheck_flash(stlink_t *sl, const char *path, stm32_addr_t addr) { // check the contents of path are at addr int32_t res; mapped_file_t mf = MAPPED_FILE_INITIALIZER; if(map_file(&mf, path) == -1) { return (-1); } res = check_file(sl, &mf, addr); unmap_file(&mf); return (res); } /** * Verify addr..addr+len is binary identical to base...base+len * @param sl stlink context * @param address stm device address * @param data host side buffer to check against * @param length how much * @return 0 for success, -ve for failure */ int32_t stlink_verify_write_flash(stlink_t *sl, stm32_addr_t address, uint8_t *data, uint32_t length) { uint32_t off; uint32_t chunk_size = (sl->flash_pgsz > 0x1800) ? 0x1800 : sl->flash_pgsz; ILOG("Starting verification of write complete\n"); for(off = 0; off < length; ) { uint32_t aligned_size; uint32_t read_address = address + off; uint32_t aligned_read_address = read_address & ~(4 - 1); uint32_t alignment_offset = read_address - aligned_read_address; uint32_t cmp_size = chunk_size - alignment_offset; if((off + cmp_size) > length) { cmp_size = length - off; } aligned_size = alignment_offset + cmp_size; if(aligned_size & (4 - 1)) { aligned_size = (aligned_size + 4) & ~(4 - 1); } stlink_read_mem32(sl, aligned_read_address, (uint16_t) aligned_size); if(memcmp(sl->q_buf + alignment_offset, data + off, cmp_size)) { ELOG("Verification of flash failed at offset: %u\n", off); return (-1); } off += cmp_size; } ILOG("Flash written and verified! jolly good!\n"); return (0); } // Check if an address and size are within the flash int32_t stlink_check_address_range_validity(stlink_t *sl, stm32_addr_t addr, uint32_t size) { uint32_t logvar; if(addr < sl->flash_base || addr >= (sl->flash_base + sl->flash_size)) { logvar = sl->flash_base + sl->flash_size - 1; ELOG("Invalid address, it should be within 0x%08x - 0x%08x\n", sl->flash_base, logvar); return (-1); } if((addr + size) > (sl->flash_base + sl->flash_size)) { logvar = sl->flash_base + sl->flash_size - addr; ELOG("The size exceeds the size of the flash (0x%08x bytes available)\n", logvar); return (-1); } return 0; } // Check if an address and size are within the flash (otp area) int32_t stlink_check_address_range_validity_otp(stlink_t *sl, stm32_addr_t addr, uint32_t size) { uint32_t logvar; if(addr < sl->otp_base || addr >= (sl->otp_base + sl->otp_size)) { logvar = sl->otp_base + sl->otp_size - 1; ELOG("Invalid address, it should be within 0x%08x - 0x%08x\n", sl->otp_base, logvar); return (-1); } if((addr + size) >= (sl->otp_base + sl->otp_size)) { logvar = sl->otp_base + sl->otp_size - addr; ELOG("The size exceeds the size of the OTP Area (0x%08x bytes available)\n", logvar); return (-1); } return 0; } // Check if an address is aligned with the beginning of a page int32_t stlink_check_address_alignment(stlink_t *sl, stm32_addr_t addr) { stm32_addr_t page = sl->flash_base; while (page < addr) { page += stlink_calculate_pagesize(sl, page); } if(page != addr) { return -1; } return 0; } int32_t stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len, uint8_t eraseonly, const enum erase_type_t erase_type) { int32_t ret; flash_loader_t fl; ILOG("Attempting to write %d (%#x) bytes to stm32 address: %u (%#x)\n", len, len, addr, addr); // check addr range is inside the flash stlink_calculate_pagesize(sl, addr); // Check the address and size validity if(stlink_check_address_range_validity(sl, addr, len) < 0) { return (-1); } else if((len & 1) && sl->flash_type != STM32_FLASH_TYPE_C5) { WLOG("unaligned len 0x%x -- padding with zero\n", len); len += 1; } else if(stlink_check_address_alignment(sl, addr) < 0) { ELOG("addr not a multiple of current pagesize (%u bytes), not supported, " "check page start address and compare with flash module organisation " "in related ST reference manual of your device.\n", sl->flash_pgsz); return (-1); } // make sure we've loaded the context with the chip details stlink_core_id(sl); // Erase this section of the flash if((erase_type == SECTION_ERASE) && 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) { // leave the flash controller in a clean state (PG cleared, locked), otherwise // a stale PG bit breaks the page erase of the next attempt (PGSERR) stlink_flashloader_stop(sl, &fl); return ret; } ret = stlink_flashloader_stop(sl, &fl); if(ret) return ret; return (stlink_verify_write_flash(sl, addr, base, len)); } int32_t stlink_write_otp(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) { int32_t ret; flash_loader_t fl; ILOG("Attempting to write %d (%#x) bytes to stm32 address: %u (%#x)\n", len, len, addr, addr); // Check the address and size validity if(stlink_check_address_range_validity_otp(sl, addr, len) < 0) { return (-1); } // make sure we've loaded the context with the chip details stlink_core_id(sl); ret = stlink_flashloader_start(sl, &fl); if(ret) return ret; ret = stlink_flashloader_write(sl, &fl, addr, base, len); if(ret) return ret; ret = stlink_flashloader_stop(sl, &fl); if(ret) return ret; return (stlink_verify_write_flash(sl, addr, base, len)); } void stlink_fwrite_finalize(stlink_t *sl, stm32_addr_t addr) { uint32_t val; // set PC to the reset routine stlink_read_debug32(sl, addr + 4, &val); stlink_write_reg(sl, val, 15); stlink_run(sl, RUN_NORMAL); } stlink-1.9.0/src/stlink-lib/common_flash.h000066400000000000000000000067221526027543100205160ustar00rootroot00000000000000/** ****************************************************************************** * @file : common_flash.h * @brief : Flash operations * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #ifndef COMMON_FLASH_H #define COMMON_FLASH_H #include #include #include #include #include #define BANK_1 0 #define BANK_2 1 enum erase_type_t { NO_ERASE = 0, SECTION_ERASE = 1, MASS_ERASE = 2, }; uint32_t get_stm32l0_flash_base(stlink_t *); uint32_t read_flash_cr(stlink_t *, uint32_t); void lock_flash(stlink_t *); // static inline int32_t write_flash_sr(stlink_t *sl, uint32_t bank, uint32_t val); void clear_flash_error(stlink_t *); uint32_t read_flash_sr(stlink_t *sl, uint32_t bank); uint32_t is_flash_busy(stlink_t *sl); void wait_flash_busy(stlink_t *); int32_t check_flash_error(stlink_t *); // static inline uint32_t is_flash_locked(stlink_t *sl); // static void unlock_flash(stlink_t *sl); int32_t unlock_flash_if(stlink_t *); int32_t lock_flash_option(stlink_t *); // static bool is_flash_option_locked(stlink_t *sl); // static int32_t unlock_flash_option(stlink_t *sl); int32_t unlock_flash_option_if(stlink_t *); void write_flash_cr_psiz(stlink_t *, uint32_t, uint32_t); void clear_flash_cr_pg(stlink_t *, uint32_t); // static void wait_flash_busy_progress(stlink_t *sl); // static inline void write_flash_ar(stlink_t *sl, uint32_t n, uint32_t bank); // static inline void write_flash_cr_snb(stlink_t *sl, uint32_t n, uint32_t bank); // static void set_flash_cr_per(stlink_t *sl, uint32_t bank); // static void clear_flash_cr_per(stlink_t *sl, uint32_t bank); // static inline void write_flash_cr_bker_pnb(stlink_t *sl, uint32_t n); // static void set_flash_cr_strt(stlink_t *sl, uint32_t bank); // static void set_flash_cr_mer(stlink_t *sl, bool v, uint32_t bank); int32_t stlink_erase_flash_page(stlink_t *sl, stm32_addr_t flashaddr); int32_t stlink_erase_flash_section(stlink_t *sl, stm32_addr_t base_addr, uint32_t size, bool align_size); int32_t stlink_erase_flash_mass(stlink_t *sl); int32_t stlink_mwrite_flash(stlink_t *sl, uint8_t *data, uint32_t length, stm32_addr_t addr, const enum erase_type_t erase); int32_t stlink_fwrite_flash(stlink_t *sl, const char *path, stm32_addr_t addr, const enum erase_type_t erase); int32_t stlink_fcheck_flash(stlink_t *sl, const char *path, stm32_addr_t addr); int32_t stlink_verify_write_flash(stlink_t *sl, stm32_addr_t address, uint8_t *data, uint32_t length); int32_t stlink_check_address_range_validity(stlink_t *sl, stm32_addr_t addr, uint32_t size); int32_t stlink_check_address_range_validity_otp(stlink_t *sl, stm32_addr_t addr, uint32_t size); int32_t stlink_check_address_alignment(stlink_t *sl, stm32_addr_t addr); int32_t stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len, uint8_t erase_only, const enum erase_type_t erase); int32_t stlink_write_otp(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len); void stlink_fwrite_finalize(stlink_t *, stm32_addr_t); #endif // COMMON_FLASH_H stlink-1.9.0/src/stlink-lib/common_legacy.c000066400000000000000000001254551526027543100206650ustar00rootroot00000000000000/* * File: common_legacy.c * * */ // TODO: CONTENT AND USE OF THIS SOURCE FILE IS TO BE VERIFIED // This file should be split up into new or existing modules. #include #include #include #include #include #include #include #include #include #include "calculate.h" #include "chipid.h" #include "common_flash.h" #include "helper.h" #include "logging.h" #include "map_file.h" #include "md5.h" #include "read_write.h" #include "usb.h" #ifndef O_BINARY #define O_BINARY 0 #endif #ifdef _MSC_VER #define __attribute__(x) #endif /* === Declaration of private structs and functions === */ struct stlink_fread_worker_arg { int32_t fd; }; struct stlink_fread_ihex_worker_arg { FILE *file; uint32_t addr; uint32_t lba; uint8_t buf[16]; uint8_t buf_pos; }; typedef bool (*save_block_fn)(void *arg, uint8_t *block, ssize_t len); static void stop_wdg_in_debug(stlink_t *); int32_t stlink_jtag_reset(stlink_t *, int32_t); int32_t stlink_soft_reset(stlink_t *, int32_t); void _parse_version(stlink_t *, stlink_version_t *); static uint8_t stlink_parse_hex(const char *); static int32_t stlink_read(stlink_t *, stm32_addr_t, uint32_t, save_block_fn, void *); static bool stlink_fread_ihex_init(struct stlink_fread_ihex_worker_arg *, int32_t, stm32_addr_t); // static bool stlink_fread_ihex_newsegment(struct stlink_fread_ihex_worker_arg *the_arg); // static bool stlink_fread_ihex_writeline(struct stlink_fread_ihex_worker_arg *the_arg); 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); /* === Definition of private structs and functions from stlink.h === */ static void stop_wdg_in_debug(stlink_t *sl) { uint32_t dbgmcu_cr; uint32_t set; uint32_t value; switch (sl->flash_type) { case STM32_FLASH_TYPE_F0_F1_F3: case STM32_FLASH_TYPE_F1_XL: case STM32_FLASH_TYPE_G4: dbgmcu_cr = STM32F0_DBGMCU_CR; set = (1 << STM32F0_DBGMCU_CR_IWDG_STOP) | (1 << STM32F0_DBGMCU_CR_WWDG_STOP); break; case STM32_FLASH_TYPE_F2_F4: case STM32_FLASH_TYPE_F7: case STM32_FLASH_TYPE_L4: dbgmcu_cr = STM32F4_DBGMCU_APB1FZR1; set = (1 << STM32F4_DBGMCU_APB1FZR1_IWDG_STOP) | (1 << STM32F4_DBGMCU_APB1FZR1_WWDG_STOP); break; case STM32_FLASH_TYPE_L0_L1: case STM32_FLASH_TYPE_G0: if(get_stm32l0_flash_base(sl) == STM32_FLASH_Lx_REGS_ADDR) { dbgmcu_cr = STM32L1_DBGMCU_APB1_FZ; set = (1 << STM32L1_DBGMCU_APB1_FZ_IWDG_STOP) | (1 << STM32L1_DBGMCU_APB1_FZ_WWDG_STOP); } else { dbgmcu_cr = STM32L0_DBGMCU_APB1_FZ; set = (1 << STM32L0_DBGMCU_APB1_FZ_IWDG_STOP) | (1 << STM32L0_DBGMCU_APB1_FZ_WWDG_STOP); } break; case STM32_FLASH_TYPE_H7: dbgmcu_cr = STM32H7_DBGMCU_APB1HFZ; set = (1 << STM32H7_DBGMCU_APB1HFZ_IWDG_STOP); break; case STM32_FLASH_TYPE_WB_WL: dbgmcu_cr = STM32WB_DBGMCU_APB1FZR1; set = (1 << STM32WB_DBGMCU_APB1FZR1_IWDG_STOP) | (1 << STM32WB_DBGMCU_APB1FZR1_WWDG_STOP); break; case STM32_FLASH_TYPE_WB0: // WB0 has no DBGMCU, watchdog can only be turned off if(!stlink_read_debug32(sl, STM32WB0_RCC_APB0ENR, &value)) { stlink_write_debug32(sl, STM32WB0_RCC_APB0ENR, value & (~STM32WB0_RCC_APB0_WDGEN)); } return; default: return; } if(!stlink_read_debug32(sl, dbgmcu_cr, &value)) { stlink_write_debug32(sl, dbgmcu_cr, value | set); } } int32_t stlink_jtag_reset(stlink_t *sl, int32_t value) { DLOG("*** stlink_jtag_reset %d ***\n", value); return (sl->backend->jtag_reset(sl, value)); } int32_t stlink_soft_reset(stlink_t *sl, int32_t halt_on_reset) { int32_t ret; uint32_t timeout; uint32_t dhcsr, dfsr; DLOG("*** stlink_soft_reset %s***\n", halt_on_reset ? "(halt) " : ""); // halt core and enable debugging (if not already done) // C_DEBUGEN is required to Halt on reset (DDI0337E, p. 10-6) stlink_write_debug32(sl, STM32_REG_DHCSR, STM32_REG_DHCSR_DBGKEY | STM32_REG_DHCSR_C_HALT | STM32_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, STM32_REG_CM3_DEMCR, STM32_REG_CM3_DEMCR_TRCENA | STM32_REG_CM3_DEMCR_VC_HARDERR | STM32_REG_CM3_DEMCR_VC_BUSERR | STM32_REG_CM3_DEMCR_VC_CORERESET); // clear VCATCH in the DFSR register stlink_write_debug32(sl, STM32_REG_DFSR, STM32_REG_DFSR_VCATCH); } else { stlink_write_debug32(sl, STM32_REG_CM3_DEMCR, STM32_REG_CM3_DEMCR_TRCENA | STM32_REG_CM3_DEMCR_VC_HARDERR | STM32_REG_CM3_DEMCR_VC_BUSERR); } // clear S_RESET_ST in the DHCSR register stlink_read_debug32(sl, STM32_REG_DHCSR, &dhcsr); // soft reset (core reset) by SYSRESETREQ (DDI0337E, p. 8-23) ret = stlink_write_debug32(sl, STM32_REG_AIRCR, STM32_REG_AIRCR_VECTKEY | STM32_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 = STM32_REG_DHCSR_S_RESET_ST; stlink_read_debug32(sl, STM32_REG_DHCSR, &dhcsr); if((dhcsr & STM32_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, STM32_REG_DFSR, &dfsr); if((dfsr & STM32_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, STM32_REG_DFSR, STM32_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; } // TODO: length not checked static uint8_t stlink_parse_hex(const char *hex) { uint8_t d[2]; for(int32_t i = 0; i < 2; ++i) { char c = *(hex + i); if(c >= '0' && c <= '9') { d[i] = c - '0'; } else if(c >= 'A' && c <= 'F') { d[i] = c - 'A' + 10; } else if(c >= 'a' && c <= 'f') { d[i] = c - 'a' + 10; } else { return (0); // error } } return ((d[0] << 4) | (d[1])); } static int32_t stlink_read(stlink_t *sl, stm32_addr_t addr, uint32_t size, save_block_fn fn, void *fn_arg) { int32_t error = -1; if(size < 1) { size = sl->flash_size; } if(size > sl->flash_size) { size = sl->flash_size; } uint32_t cmp_size = (sl->flash_pgsz > 0x1800) ? 0x1800 : sl->flash_pgsz; for(uint32_t off = 0; off < size; off += cmp_size) { uint32_t aligned_size; // adjust last page size if((off + cmp_size) > size) { cmp_size = size - off; } aligned_size = cmp_size; if(aligned_size & (4 - 1)) { aligned_size = (cmp_size + 4) & ~(4 - 1); } stlink_read_mem32(sl, addr + off, (uint16_t) aligned_size); if(!fn(fn_arg, sl->q_buf, aligned_size)) { goto on_error; } } error = 0; // success on_error: return (error); } static bool stlink_fread_ihex_init(struct stlink_fread_ihex_worker_arg *the_arg, int32_t fd, stm32_addr_t addr) { the_arg->file = fdopen(fd, "w"); the_arg->addr = addr; the_arg->lba = 0; the_arg->buf_pos = 0; return (the_arg->file != NULL); } // this function is called by stlink_fread_ihex_writeline() 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); } // this function is called by stlink_fread_ihex_worker() and stlink_fread_ihex_finalize() 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_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)); } 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); } } /* === Definition of functions from stlink.h === */ int32_t stlink_enter_swd_mode(stlink_t *sl) { DLOG("*** stlink_enter_swd_mode ***\n"); return (sl->backend->enter_swd_mode(sl)); } int32_t stlink_exit_debug_mode(stlink_t *sl) { DLOG("*** stlink_exit_debug_mode ***\n"); if(stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE) { // STLINK-V3 locks up completely when calling DEBUG_EXIT in MASS mode return 0; } if(sl->flash_type != STM32_FLASH_TYPE_UNKNOWN) { // stop debugging if the target has been identified. This must also run // when the last command was a reset (core_stat == TARGET_RESET, e.g. // `st-flash reset` or `write --reset`, since stlink_run() does not update // core_stat): C_DEBUGEN survives system resets, and left set it keeps any // armed vector catch live, halting the target with no debugger attached. stlink_write_debug32(sl, STM32_REG_DHCSR, STM32_REG_DHCSR_DBGKEY); // Disarm the vector catches armed at connect before detaching. // stlink_soft_reset() arms DEMCR.VC_CORERESET (halt-on-reset) and // VC_HARDERR/VC_BUSERR (halt-on-fault); they live in the debug power // domain and survive NRST, so if left armed the core halts on every reset // -- including NVIC_SystemReset() from firmware -- or silently at its next // hard/bus fault instead of running the fault handler, and the board looks // bricked until a power cycle. Only the read failing (dead debug link) // stops us, and we preserve the other DEMCR bits (TRCENA, MON_EN). const uint32_t vector_catches = STM32_REG_CM3_DEMCR_VC_CORERESET | STM32_REG_CM3_DEMCR_VC_HARDERR | STM32_REG_CM3_DEMCR_VC_BUSERR; uint32_t demcr = 0; if(!stlink_read_debug32(sl, STM32_REG_CM3_DEMCR, &demcr) && (demcr & vector_catches)) { if(stlink_write_debug32(sl, STM32_REG_CM3_DEMCR, demcr & ~vector_catches)) { WLOG("Could not clear DEMCR vector catches; target may halt on reset or fault\n"); } // clear the stale vector-catch status in DFSR stlink_write_debug32(sl, STM32_REG_DFSR, STM32_REG_DFSR_VCATCH); } } return (sl->backend->exit_debug_mode(sl)); } int32_t stlink_exit_dfu_mode(stlink_t *sl) { DLOG("*** stlink_exit_dfu_mode ***\n"); return (sl->backend->exit_dfu_mode(sl)); } void stlink_close(stlink_t *sl) { DLOG("*** stlink_close ***\n"); if(!sl) { return; } sl->backend->close(sl); free(sl); } int32_t stlink_core_id(stlink_t *sl) { int32_t ret; DLOG("*** stlink_core_id ***\n"); ret = sl->backend->core_id(sl); if(ret == -1) { ELOG("Failed to read core_id\n"); return (ret); } if(sl->verbose > 2) { stlink_print_data(sl); } DLOG("core_id = 0x%08x\n", sl->core_id); return (ret); } int32_t stlink_reset(stlink_t *sl, enum reset_type type) { uint32_t dhcsr; uint32_t timeout; DLOG("*** stlink_reset ***\n"); sl->core_stat = TARGET_RESET; if(type == RESET_AUTO) { // clear S_RESET_ST in DHCSR register for reset state detection stlink_read_debug32(sl, STM32_REG_DHCSR, &dhcsr); } if(type == RESET_HARD || type == RESET_AUTO) { // hardware target reset if(sl->version.stlink_v > 1) { stlink_jtag_reset(sl, STLINK_DEBUG_APIV2_DRIVE_NRST_LOW); // minimum reset pulse duration of 20 us (RM0008, 8.1.2 Power reset) usleep(100); stlink_jtag_reset(sl, STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH); } sl->backend->reset(sl); usleep(10000); } if(type == RESET_AUTO) { /* Check if the S_RESET_ST bit is set in DHCSR * This means that a reset has occurred * DDI0337E, p. 10-4, Debug Halting Control and Status Register */ dhcsr = 0; int32_t res = stlink_read_debug32(sl, STM32_REG_DHCSR, &dhcsr); if((dhcsr & STM32_REG_DHCSR_S_RESET_ST) == 0 && !res) { // reset not done yet --> try reset through AIRCR so that NRST does not need to be connected ILOG("NRST is not connected --> using software reset via AIRCR\n"); DLOG("NRST not connected --> Reset through SYSRESETREQ\n"); return stlink_soft_reset(sl, 0); } // waiting for reset the S_RESET_ST bit within 500ms timeout = time_ms() + 500; while (time_ms() < timeout) { dhcsr = STM32_REG_DHCSR_S_RESET_ST; stlink_read_debug32(sl, STM32_REG_DHCSR, &dhcsr); if((dhcsr & STM32_REG_DHCSR_S_RESET_ST) == 0) { return (0); } } return (-1); } if(type == RESET_SOFT || type == RESET_SOFT_AND_HALT) { return stlink_soft_reset(sl, (type == RESET_SOFT_AND_HALT)); } return (0); } int32_t stlink_run(stlink_t *sl, enum run_type type) { struct stlink_reg rr; DLOG("*** stlink_run ***\n"); /* Make sure we are in Thumb mode * Cortex-M chips don't support ARM mode instructions * xPSR may be incorrect if the vector table has invalid data */ stlink_read_reg(sl, 16, &rr); if((rr.xpsr & (1 << 24)) == 0) { ILOG("Go to Thumb mode\n"); stlink_write_reg(sl, rr.xpsr | (1 << 24), 16); } return (sl->backend->run(sl, type)); } // this function is called by stlink_status() // do not call this procedure 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"); } } int32_t stlink_status(stlink_t *sl) { int32_t ret; DLOG("*** stlink_status ***\n"); ret = sl->backend->status(sl); stlink_core_stat(sl); return (ret); } int32_t stlink_version(stlink_t *sl) { DLOG("*** looking up stlink version ***\n"); if(sl->backend->version(sl)) { return (-1); } _parse_version(sl, &sl->version); DLOG("st vid = 0x%04x (expect 0x%04x)\n", sl->version.st_vid, STLINK_USB_VID_ST); DLOG("stlink pid = 0x%04x\n", sl->version.stlink_pid); DLOG("stlink version = 0x%x\n", sl->version.stlink_v); DLOG("jtag version = 0x%x\n", sl->version.jtag_v); DLOG("swim version = 0x%x\n", sl->version.swim_v); if(sl->version.jtag_v == 0) { WLOG(" warning: stlink doesn't support JTAG/SWD interface\n"); } return (0); } int32_t stlink_step(stlink_t *sl) { DLOG("*** stlink_step ***\n"); return (sl->backend->step(sl)); } int32_t stlink_current_mode(stlink_t *sl) { int32_t mode = sl->backend->current_mode(sl); switch (mode) { case STLINK_DEV_DFU_MODE: DLOG("stlink current mode: dfu\n"); return (mode); case STLINK_DEV_DEBUG_MODE: DLOG("stlink current mode: debug (jtag or swd)\n"); return (mode); case STLINK_DEV_MASS_MODE: DLOG("stlink current mode: mass\n"); return (mode); } DLOG("stlink mode: unknown!\n"); return (STLINK_DEV_UNKNOWN_MODE); } // Force the core into the debug mode -> halted state. int32_t stlink_force_debug(stlink_t *sl) { DLOG("*** stlink_force_debug_mode ***\n"); int32_t res = sl->backend->force_debug(sl); if(res) { return (res); } // Stop the watchdogs in the halted state for suppress target reboot stop_wdg_in_debug(sl); return (0); } int32_t stlink_target_voltage(stlink_t *sl) { int32_t voltage = -1; DLOG("*** reading target voltage\n"); if(sl->backend->target_voltage != NULL) { voltage = sl->backend->target_voltage(sl); if(voltage != -1) { DLOG("target voltage = %imV\n", voltage); } else { DLOG("error reading target voltage\n"); } } else { DLOG("reading voltage not supported by backend\n"); } return (voltage); } int32_t stlink_set_swdclk(stlink_t *sl, int32_t freq_khz) { DLOG("*** set_swdclk ***\n"); return (sl->backend->set_swdclk(sl, freq_khz)); } int32_t stlink_parse_ihex(const char *path, uint8_t erased_pattern, uint8_t **mem, uint32_t *size, uint32_t *begin) { int32_t res = 0; *begin = UINT32_MAX; uint8_t *data = NULL; uint32_t end = 0; bool eof_found = false; for(int32_t scan = 0; (res == 0) && (scan < 2); ++scan) { // parse file two times - first to find memory range, second - to fill it if(scan == 1) { if(!eof_found) { ELOG("No EoF record\n"); res = -1; break; } if(*begin >= end) { ELOG("No data found in file\n"); res = -1; break; } *size = (end - *begin) + 1; data = calloc(1, *size); // use calloc to get NULL if out of memory if(!data) { ELOG("Cannot allocate %u bytes\n", (*size)); res = -1; break; } memset(data, erased_pattern, *size); } FILE *file = fopen(path, "r"); if(!file) { ELOG("Cannot open file\n"); res = -1; break; } uint32_t lba = 0; char line[1 + 5 * 2 + 255 * 2 + 2]; while (fgets(line, sizeof(line), file)) { if(line[0] == '\n' || line[0] == '\r') { continue; } // skip empty lines if(line[0] != ':') { // no marker - wrong file format ELOG("Wrong file format - no marker\n"); res = -1; break; } uint64_t l = strlen(line); while (l > 0 && (line[l - 1] == '\n' || line[l - 1] == '\r')) { --l; } // trim EoL if((l < 11) || (l == (sizeof(line) - 1))) { // line too short or long - wrong file format ELOG("Wrong file format - wrong line length\n"); res = -1; break; } uint8_t chksum = 0; // check sum for(uint32_t i = 1; i < l; i += 2) { chksum += stlink_parse_hex(line + i); } if(chksum != 0) { ELOG("Wrong file format - checksum mismatch\n"); res = -1; break; } uint8_t reclen = stlink_parse_hex(line + 1); if(((uint32_t) reclen + 5) * 2 + 1 != l) { ELOG("Wrong file format - record length mismatch\n"); res = -1; break; } uint16_t offset = ((uint16_t) stlink_parse_hex(line + 3) << 8) | ((uint16_t) stlink_parse_hex(line + 5)); uint8_t rectype = stlink_parse_hex(line + 7); switch (rectype) { case 0: /* Data */ if(scan == 0) { uint32_t b = lba + offset; uint32_t e = b + reclen - 1; if(b < *begin) { *begin = b; } if(e > end) { end = e; } } else { for(uint8_t i = 0; i < reclen; ++i) { uint8_t b = stlink_parse_hex(line + 9 + i * 2); uint32_t addr = lba + offset + i; if(addr >= *begin && addr <= end) { data[addr - *begin] = b; } } } break; case 1: /* EoF */ eof_found = true; break; case 2: /* Extended Segment Address, unexpected */ res = -1; break; case 3: /* Start Segment Address, unexpected */ res = -1; break; case 4: /* Extended Linear Address */ if(reclen == 2) { lba = ((uint32_t) stlink_parse_hex(line + 9) << 24) | ((uint32_t) stlink_parse_hex(line + 11) << 16); } else { ELOG("Wrong file format - wrong LBA length\n"); res = -1; } break; case 5: /* Start Linear Address - expected, but ignore */ break; default: ELOG("Wrong file format - unexpected record type %d\n", rectype); res = -1; } if(res != 0) { break; } } fclose(file); } if(res == 0) { *mem = data; } else { free(data); } return (res); } uint8_t stlink_get_erased_pattern(stlink_t *sl) { if(sl->flash_type == STM32_FLASH_TYPE_L0_L1) { return (0x00); } else { return (0xff); } } int32_t stlink_mwrite_sram(stlink_t *sl, uint8_t *data, uint32_t length, stm32_addr_t addr) { // write the file in sram at addr int32_t error = -1; uint32_t off; uint32_t len; // check addr range is inside the sram if(addr < sl->sram_base) { fprintf(stderr, "addr too low\n"); goto on_error; } else if((addr + length) < addr) { fprintf(stderr, "addr overruns\n"); goto on_error; } else if((addr + length) > (sl->sram_base + sl->sram_size)) { fprintf(stderr, "addr too high\n"); goto on_error; } else if(addr & 3) { fprintf(stderr, "unaligned addr\n"); goto on_error; } len = length; if(len & 3) { len -= len & 3; } // do the copy by 1kB blocks for(off = 0; off < len; off += 1024) { uint32_t size = 1024; if((off + size) > len) { size = len - off; } memcpy(sl->q_buf, data + off, size); if(size & 3) { size += 2; } // round size if needed stlink_write_mem32(sl, addr + off, (uint16_t) size); } if(length > len) { memcpy(sl->q_buf, data + len, length - len); stlink_write_mem8(sl, addr + len, (uint16_t) (length - len)); } error = 0; // success stlink_fwrite_finalize(sl, addr); on_error: return (error); } int32_t stlink_fwrite_sram(stlink_t *sl, const char *path, stm32_addr_t addr) { // write the file in sram at addr int32_t error = -1; uint32_t off; uint32_t len; mapped_file_t mf = MAPPED_FILE_INITIALIZER; if(map_file(&mf, path) == -1) { fprintf(stderr, "map_file() == -1\n"); return (-1); } printf("file %s ", path); md5_calculate(&mf); stlink_checksum(&mf); // check if addr range is inside the SRAM if(addr < sl->sram_base) { fprintf(stderr, "addr too low\n"); goto on_error; } else if((addr + mf.len) < addr) { fprintf(stderr, "addr overruns\n"); goto on_error; } else if((addr + mf.len) > (sl->sram_base + sl->sram_size)) { fprintf(stderr, "addr too high\n"); goto on_error; } else if(addr & 3) { fprintf(stderr, "unaligned addr\n"); goto on_error; } len = mf.len; if(len & 3) { len -= len & 3; } // do the copy by 1kB blocks for(off = 0; off < len; off += 1024) { uint32_t size = 1024; if((off + size) > len) { size = len - off; } memcpy(sl->q_buf, mf.base + off, size); if(size & 3) { size += 2; } // round size if needed stlink_write_mem32(sl, addr + off, (uint16_t) size); } if(mf.len > len) { memcpy(sl->q_buf, mf.base + len, mf.len - len); stlink_write_mem8(sl, addr + len, (uint16_t) (mf.len - len)); } // check the file has been written if(check_file(sl, &mf, addr) == -1) { fprintf(stderr, "check_file() == -1\n"); goto on_error; } error = 0; // success stlink_fwrite_finalize(sl, addr); on_error: unmap_file(&mf); return (error); } /** * Cortex M tech ref manual, CPUID register description * @param sl stlink context * @param cpuid pointer to the result object */ int32_t stlink_cpu_id(stlink_t *sl, cortex_m3_cpuid_t *cpuid) { uint32_t raw; if(stlink_read_debug32(sl, STM32_REG_CM3_CPUID, &raw)) { cpuid->implementer_id = 0; cpuid->variant = 0; cpuid->part = 0; cpuid->revision = 0; return (-1); } cpuid->implementer_id = (raw >> 24) & 0x7f; cpuid->variant = (raw >> 20) & 0xf; cpuid->part = (raw >> 4) & 0xfff; cpuid->revision = raw & 0xf; return (0); } uint32_t stlink_calculate_pagesize(stlink_t *sl, uint32_t flashaddr) { if((sl->chip_id == STM32_CHIPID_F2) || (sl->chip_id == STM32_CHIPID_F4) || (sl->chip_id == STM32_CHIPID_F4_DE) || (sl->chip_id == STM32_CHIPID_F4_LP) || (sl->chip_id == STM32_CHIPID_F4_HD) || (sl->chip_id == STM32_CHIPID_F411xx) || (sl->chip_id == STM32_CHIPID_F446) || (sl->chip_id == STM32_CHIPID_F4_DSI) || (sl->chip_id == STM32_CHIPID_F72xxx) || (sl->chip_id == STM32_CHIPID_F412) || (sl->chip_id == STM32_CHIPID_F410) || (sl->chip_id == STM32_CHIPID_F413)) { uint32_t sector = calculate_F4_sectornum(flashaddr); if(sector >= 12) { sector -= 12; } if(sector < 4) { sl->flash_pgsz = 0x4000; } else if(sector < 5) { sl->flash_pgsz = 0x10000; } else { sl->flash_pgsz = 0x20000; } } else if(sl->chip_id == STM32_CHIPID_F7 || sl->chip_id == STM32_CHIPID_F76xxx) { uint32_t sector = calculate_F7_sectornum(flashaddr); if(sector < 4) { sl->flash_pgsz = 0x8000; } else if(sector < 5) { sl->flash_pgsz = 0x20000; } else { sl->flash_pgsz = 0x40000; } } return (sl->flash_pgsz); } void stlink_print_data(stlink_t *sl) { if(sl->q_len <= 0 || sl->verbose < UDEBUG) { return; } if(sl->verbose > 2) { DLOG("data_len = %d 0x%x\n", sl->q_len, sl->q_len); } for(int32_t i = 0; i < sl->q_len; i++) { if(i % 16 == 0) { /* if(sl->q_data_dir == Q_DATA_OUT) { fprintf(stdout, "\n<- 0x%08x ", sl->q_addr + i); } else { fprintf(stdout, "\n-> 0x%08x ", sl->q_addr + i); } */ } // DLOG(" %02x", (uint32_t) sl->q_buf[i]); fprintf(stderr, " %02x", (uint32_t) sl->q_buf[i]); } // DLOG("\n\n"); fprintf(stderr, "\n"); } bool stlink_is_core_halted(stlink_t *sl) { stlink_status(sl); return (sl->core_stat == TARGET_HALTED); } int32_t stlink_write_buffer_to_sram(stlink_t *sl, flash_loader_t *fl, const uint8_t *buf, uint16_t size, uint16_t padded_size) { // write the buffer right after the loader, and pad the end with 0xFF if padded_size is larger than size int32_t ret = 0; uint16_t data_remaining = size; if (padded_size < size) { padded_size = size; } uint16_t word_chunk = padded_size & ~0x3; uint16_t byte_chunk = padded_size & 0x3; if(word_chunk) { uint16_t data_cnt = word_chunk > data_remaining ? data_remaining : word_chunk; memcpy(sl->q_buf, buf, data_cnt); memset(sl->q_buf + data_cnt, 0xFF, word_chunk - data_cnt); ret = stlink_write_mem32(sl, fl->buf_addr, word_chunk); data_remaining -= data_cnt; } if(byte_chunk && !ret) { uint16_t data_cnt = byte_chunk > data_remaining ? data_remaining : byte_chunk; memcpy(sl->q_buf, buf + word_chunk, data_cnt); memset(sl->q_buf + data_cnt, 0xFF, byte_chunk - data_cnt); ret = stlink_write_mem8(sl, (fl->buf_addr) + word_chunk, byte_chunk); } return (ret); } int32_t stlink_fread(stlink_t *sl, const char *path, bool is_ihex, stm32_addr_t addr, uint32_t size) { // read size bytes from addr to file ILOG("read from address %#010x size %u\n", addr, size); int32_t error; int32_t fd = open(path, O_RDWR | O_TRUNC | O_CREAT | O_BINARY, 00700); if(fd == -1) { fprintf(stderr, "open(%s) == -1\n", path); return (-1); } if(is_ihex) { struct stlink_fread_ihex_worker_arg arg; if(stlink_fread_ihex_init(&arg, fd, addr)) { error = stlink_read(sl, addr, size, &stlink_fread_ihex_worker, &arg); if(!stlink_fread_ihex_finalize(&arg)) { error = -1; } } else { error = -1; } } else { struct stlink_fread_worker_arg arg = {fd}; error = stlink_read(sl, addr, size, &stlink_fread_worker, &arg); close(fd); } return (error); } // this function is called by stlink_load_device_params() // do not call this procedure directly. int32_t stlink_chip_id(stlink_t *sl, uint32_t *chip_id) { int32_t ret; cortex_m3_cpuid_t cpu_id; // Read the CPU ID to determine where to read the core id if(stlink_cpu_id(sl, &cpu_id) || cpu_id.implementer_id != STM32_REG_CMx_CPUID_IMPL_ARM) { ELOG("Can not connect to target. Please use \'connect under reset\' and try again\n"); return -1; } /* * the chip_id register in the reference manual have * DBGMCU_IDCODE / DBG_IDCODE name */ if((sl->core_id == STM32_CORE_ID_M7F_M33_SWD || sl->core_id == STM32_CORE_ID_M7F_M33_JTAG) && cpu_id.part == STM32_REG_CMx_CPUID_PARTNO_CM7) { // STM32H7 chipid in 0x5c001000 (RM0433 pg3189) ret = stlink_read_debug32(sl, 0x5c001000, chip_id); } else if(cpu_id.part == STM32_REG_CMx_CPUID_PARTNO_CM0 || cpu_id.part == STM32_REG_CMx_CPUID_PARTNO_CM0P) { // STM32F0 (RM0091, pg914; RM0360, pg713) // STM32L0 (RM0377, pg813; RM0367, pg915; RM0376, pg917) // STM32G0 (RM0444, pg1367) ret = stlink_read_debug32(sl, 0x40015800, chip_id); if (*chip_id == 0) { // these devices don't have a DBG_IDCODE register // we follow STM32CubeProg and use PART_NUMBER from JTAG_ID instead // STM32WB05 (RM0491, pg115) // STM32WB06/WB07 (RM0530, pg105) // STM32WB09 (RM0505, pg167) // STM32WL3x (RM0511, pg176) ret = stlink_read_debug32(sl, STM32WB0_JTAG_ID, chip_id); *chip_id = (*chip_id) >> STM32WB0_JTAG_PART_NR; } } else if(cpu_id.part == STM32_REG_CMx_CPUID_PARTNO_CM33) { // STM32L5 (RM0438, pg2157) ret = stlink_read_debug32(sl, 0xE0044000, chip_id); if (!ret && !(*chip_id)) { // STM32H5 reports 0 at the L5 DBGMCU address; its DBGMCU_IDCODE is at // 0x44024000 (RM0481, DEV_ID 0x484). ret = stlink_read_debug32(sl, 0x44024000, chip_id); } } else /* СM3, СM4, CM7 */ { // default chipid address // STM32F1 (RM0008, pg1087; RM0041, pg681) // STM32F2 (RM0033, pg1326) // STM32F3 (RM0316, pg1095; RM0313, pg874) // STM32F7 (RM0385, pg1676; RM0410, pg1912) // STM32L1 (RM0038, pg861) // STM32L4 (RM0351, pg1840; RM0394, pg1560) // STM32G4 (RM0440, pg2086) // STM32WB (RM0434, pg1406) ret = stlink_read_debug32(sl, 0xE0042000, chip_id); } if(ret || !(*chip_id)) { *chip_id = 0; ret = ret?ret:-1; ELOG("Could not find chip id!\n"); } else { *chip_id = (*chip_id) & 0xfff; // Fix chip_id for F4 rev A errata, read CPU ID, as CoreID is the same for // F2/F4 if(*chip_id == 0x411 && cpu_id.part == STM32_REG_CMx_CPUID_PARTNO_CM4) { *chip_id = 0x413; } } return (ret); } /* * Determine which access port (AP) exposes the CPU. * * Most STM32 targets use the default AP0 and need no INIT_AP, so the legacy * path is preserved exactly: if a valid ARM CPUID is seen we leave sl->ap = 0 * and never emit INIT_AP. Some parts (e.g. STM32H5) route debug and memory * access through AP1; for those the default AP shows no recognisable core, so * we initialise AP1 and re-check. INIT_AP also sets the AP context used by the * debug-register access path, so this must happen before any CPUID/chip-id read. */ // Returns true if a Cortex CPU is reachable through the currently selected AP. // // This is a liveness probe, NOT chip identification: we are not decoding the // CPUID value to recognise a particular part. We read CPUID (0xE000ED00) // *through the selected MEM-AP* and check only that it looks like a valid ARM // core. Reading the wrong AP does not fail cleanly -- the MEM-AP read returns // garbage (e.g. 0x00000018 on STM32H5/AP0) rather than an error -- so checking // the return code alone is not enough; the ARM implementer field is what tells // a real core apart from a bus fault. static bool stlink_ap_has_cpu(stlink_t *sl) { cortex_m3_cpuid_t cpu_id; return (stlink_cpu_id(sl, &cpu_id) == 0 && cpu_id.implementer_id == STM32_REG_CMx_CPUID_IMPL_ARM); } static void stlink_probe_ap(stlink_t *sl) { if (stlink_ap_has_cpu(sl)) { return; // CPU visible on the default AP0 } if (sl->backend->init_ap == NULL) { return; // backend cannot select an AP (legacy SCSI) } // Some parts (e.g. STM32H5) expose the CPU only on AP1. if (sl->backend->init_ap(sl, 1) == 0) { sl->ap = 1; if (stlink_ap_has_cpu(sl)) { ILOG("CPU found on access port 1 (AP1)\n"); return; } sl->ap = 0; // no CPU on AP1 either; restore default for the error path } } /** * Reads and decodes the flash parameters, as dynamically as possible * @param sl * @return 0 for success, or -1 for unsupported core type. */ int32_t stlink_load_device_params(stlink_t *sl) { // This seems to normally work so is unnecessary info for a normal user. // Demoted to debug. -- REW DLOG("Loading device parameters....\n"); const struct stlink_chipid_params *params = NULL; stlink_core_id(sl); uint32_t flash_size; stlink_probe_ap(sl); if(stlink_chip_id(sl, &sl->chip_id)) { return (-1); } params = stlink_chipid_get_params(sl->chip_id); if(params == NULL) { WLOG("unknown chip id! %#x\n", sl->chip_id); return (-1); } if(params->flash_type == STM32_FLASH_TYPE_UNKNOWN) { WLOG("Invalid flash type, please check device declaration\n"); sl->flash_size = 0; return (0); } // These are fixed... sl->flash_base = STM32_FLASH_BASE; sl->sram_base = STM32_SRAM_BASE; stlink_read_debug32(sl, (params->flash_size_reg) & ~3, &flash_size); // On AP1 targets (e.g. STM32H5) the flash-size register lives in the // system-flash info region. Running firmware can leave that region // unreadable, in which case the read returns a bogus value. Only then do we // fall back to halting the core at its reset vector -- which restores access // -- and read again; a cooperative or absent firmware is left running // undisturbed (so --hot-plug stays non-intrusive). The halt arms // DEMCR.VC_CORERESET, which lives in the debug power domain and survives // NRST, so disarm it afterwards to keep the board's reset button working. if(sl->ap != 0) { uint32_t size_kb = (params->flash_size_reg & 2) ? (flash_size >> 16) : flash_size; size_kb &= 0xffff; if(size_kb == 0 || size_kb > 0x2000 /* > 8 MiB */) { WLOG("Bogus flash size (0x%08x) on AP%d, retrying after reset-halt\n", flash_size, sl->ap); if(!stlink_soft_reset(sl, 1 /* halt on reset */)) { stlink_read_debug32(sl, (params->flash_size_reg) & ~3, &flash_size); stlink_write_debug32(sl, STM32_REG_CM3_DEMCR, STM32_REG_CM3_DEMCR_TRCENA); } } } if(params->flash_size_reg & 2) { flash_size = flash_size >> 16; } if(params->flash_type != STM32_FLASH_TYPE_WB0) { 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 if(params->flash_type == STM32_FLASH_TYPE_WB0) { sl->flash_base = STM32WB0_FLASH_BASE; sl->flash_size = ((flash_size & 0x1ffff) + 1) * 4; if(sl->chip_id == STM32_CHIPID_WL3x) { // RM0511, p211 switch((flash_size >> STM32_FLASH_WB0_RAM_SIZE) & 0x01) { case 0: sl->sram_size = 16*1024; break; case 1: sl->sram_size = 32*1024; break; } } else if(sl->chip_id != STM32_CHIPID_WB05) { // WB06/WB07 RM0530, p149 // WB09 RM0505, p183 switch((flash_size >> STM32_FLASH_WB0_RAM_SIZE) & 0x03) { case 0: // also 32kB case 1: sl->sram_size = 32*1024; break; case 2: sl->sram_size = 48*1024; break; case 3: sl->sram_size = 64*1024; break; } } } else { sl->flash_size = flash_size * 1024; } sl->flash_type = params->flash_type; sl->flash_pgsz = params->flash_pagesize; if(params->flash_type != STM32_FLASH_TYPE_WB0) { sl->sram_size = params->sram_size; } sl->sys_base = params->bootrom_base; sl->sys_size = params->bootrom_size; sl->option_base = params->option_base; sl->option_size = params->option_size; sl->chip_flags = params->flags; sl->otp_base = params->otp_base; sl->otp_size = params->otp_size; // medium and low devices have the same chipid. ram size depends on flash // size. STM32F100xx datasheet Doc ID 16455 Table 2 if(sl->chip_id == STM32_CHIPID_F1_VL_MD_LD && sl->flash_size < 64 * 1024) { sl->sram_size = 0x1000; } if(sl->chip_id == STM32_CHIPID_G4_CAT3) { uint32_t flash_optr; stlink_read_debug32(sl, STM32_FLASH_Gx_OPTR, &flash_optr); if(!(flash_optr & (1 << STM32_FLASH_G4_OPTR_DBANK))) { sl->flash_pgsz <<= 1; } } if(sl->chip_id == STM32_CHIPID_L5x2xx) { uint32_t flash_optr; stlink_read_debug32(sl, STM32_FLASH_L5_OPTR, &flash_optr); if(sl->flash_size == 512*1024 && (flash_optr & (1 << 22)) != 0) { sl->flash_pgsz = 0x800; } } // H7 devices with small flash has one bank if(sl->chip_flags & CHIP_F_HAS_DUAL_BANK && sl->flash_type == STM32_FLASH_TYPE_H7) { if((sl->flash_size / sl->flash_pgsz) <= 1) sl->chip_flags &= ~CHIP_F_HAS_DUAL_BANK; } ILOG("%s: %u KiB SRAM, %u KiB flash in at least %u %s pages.\n", params->dev_type, (sl->sram_size / 1024), (sl->flash_size / 1024), (sl->flash_pgsz < 1024) ? sl->flash_pgsz : (sl->flash_pgsz / 1024), (sl->flash_pgsz < 1024) ? "byte" : "KiB"); return (0); } int32_t stlink_target_connect(stlink_t *sl, enum connect_type connect) { if(connect == CONNECT_UNDER_RESET) { stlink_enter_swd_mode(sl); // Select the access port before the halt/reset sequence below. On targets // whose CPU is on a non-default AP (e.g. STM32H5 on AP1) every debug access // here would otherwise run on AP0 and silently fail -- the core would not // actually halt, the S_RESET_ST check would misreport "NRST not connected", // and the soft reset would error on AIRCR. stlink_probe_ap(sl); stlink_jtag_reset(sl, STLINK_DEBUG_APIV2_DRIVE_NRST_LOW); // try to halt the core before reset // this is useful if the NRST pin is not connected sl->backend->force_debug(sl); // minimum reset pulse duration of 20 us (RM0008, 8.1.2 Power reset) usleep(20); stlink_jtag_reset(sl, STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH); // try to halt the core after reset uint32_t timeout = time_ms() + 10; while (time_ms() < timeout) { sl->backend->force_debug(sl); usleep(100); } // check NRST connection uint32_t dhcsr = 0; stlink_read_debug32(sl, STM32_REG_DHCSR, &dhcsr); if((dhcsr & STM32_REG_DHCSR_S_RESET_ST) == 0) { WLOG("NRST is not connected\n"); } // addition soft reset for halt before the first instruction stlink_soft_reset(sl, 1 /* halt on reset */); } if(stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE && stlink_enter_swd_mode(sl)) { printf("Failed to enter SWD mode\n"); return -1; } if(connect == CONNECT_NORMAL) { stlink_reset(sl, RESET_AUTO); } return stlink_load_device_params(sl); } // ================================================== // this function is called in sg_legacy.c 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); } } stlink-1.9.0/src/stlink-lib/flash_loader.c000066400000000000000000001143631526027543100204700ustar00rootroot00000000000000/** ****************************************************************************** * @file : flash_loader.c * @brief : Flash loaders * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #include "flash_loader.h" #include "common_flash.h" #include "helper.h" #include "logging.h" #include "read_write.h" #define FLASH_REGS_BANK2_OFS 0x40 #define FLASH_BANK2_START_ADDR 0x08080000 #define STM32F0_WDG_KR 0x40003000 #define STM32H7_WDG_KR 0x58004800 #define STM32F0_WDG_KR_KEY_RELOAD 0xAAAA /* * !!! DO NOT MODIFY FLASH LOADERS DIRECTLY !!! * * Edit assembly files in the '/flashloaders' instead. The sizes of binary * flash loaders must be aligned by 4 (it's written by stlink_write_mem32) */ // flashloaders/stm32f0.s -- compiled with thumb2 static const uint8_t loader_code_stm32vl[] = { 0x00, 0xbf, 0x00, 0xbf, 0x09, 0x4f, 0x1f, 0x44, 0x09, 0x4d, 0x3d, 0x44, 0x04, 0x88, 0x0c, 0x80, 0x02, 0x30, 0x02, 0x31, 0x4f, 0xf0, 0x01, 0x07, 0x2c, 0x68, 0x3c, 0x42, 0xfc, 0xd1, 0x4f, 0xf0, 0x14, 0x07, 0x3c, 0x42, 0x01, 0xd1, 0x02, 0x3a, 0xf0, 0xdc, 0x00, 0xbe, 0x00, 0x20, 0x02, 0x40, 0x0c, 0x00, 0x00, 0x00 }; // flashloaders/stm32f0.s -- thumb1 only, same sequence as for STM32VL, bank ignored static const uint8_t loader_code_stm32f0[] = { 0xc0, 0x46, 0xc0, 0x46, 0x08, 0x4f, 0x1f, 0x44, 0x08, 0x4d, 0x3d, 0x44, 0x04, 0x88, 0x0c, 0x80, 0x02, 0x30, 0x02, 0x31, 0x06, 0x4f, 0x2c, 0x68, 0x3c, 0x42, 0xfc, 0xd1, 0x05, 0x4f, 0x3c, 0x42, 0x01, 0xd1, 0x02, 0x3a, 0xf2, 0xdc, 0x00, 0xbe, 0x00, 0x20, 0x02, 0x40, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00 }; // flashloaders/stm32wb0.s static const uint8_t loader_code_stm32wb0[] = { 0x0b, 0x4b, 0xc9, 0x1a, 0x89, 0x08, 0x09, 0x4f, 0xb9, 0x61, 0x40, 0x37, 0x78, 0xc8, 0x78, 0xc7, 0x50, 0x3f, 0x0d, 0x25, 0x3d, 0x61, 0xcc, 0x24, 0x3c, 0x60, 0x3c, 0x69, 0x2c, 0x40, 0xfc, 0xd0, 0x64, 0x08, 0x02, 0xd1, 0x04, 0x31, 0x10, 0x3a, 0xee, 0xdc, 0x00, 0xbe, 0x00, 0x10, 0x00, 0x40, 0x00, 0x00, 0x04, 0x10 }; // flashloaders/stm32lx.s -- compiled for armv6-m for compatibility with both // armv6-m cores (STM32L0) and armv7-m cores (STM32L1) static const uint8_t loader_code_stm32lx[] = { 0x04, 0x68, 0x0c, 0x60, 0x04, 0x30, 0x04, 0x31, 0x04, 0x3a, 0xf9, 0xdc, 0x00, 0xbe, 0x00, 0x00 }; // flashloaders/stm32f4.s static const uint8_t loader_code_stm32f4[] = { 0xdf, 0xf8, 0x24, 0xc0, 0xdf, 0xf8, 0x24, 0xa0, 0xe2, 0x44, 0x04, 0x68, 0x0c, 0x60, 0x00, 0xf1, 0x04, 0x00, 0x01, 0xf1, 0x04, 0x01, 0xba, 0xf8, 0x00, 0x40, 0x14, 0xf0, 0x01, 0x0f, 0xfa, 0xd1, 0x04, 0x3a, 0xf2, 0xdc, 0x00, 0xbe, 0x00, 0xbf, 0x00, 0x3c, 0x02, 0x40, 0x0e, 0x00, 0x00, 0x00 }; // flashloaders/stm32f4lv.s static const uint8_t loader_code_stm32f4_lv[] = { 0xdf, 0xf8, 0x24, 0xc0, 0xdf, 0xf8, 0x24, 0xa0, 0xe2, 0x44, 0x04, 0x78, 0x0c, 0x70, 0x00, 0xf1, 0x01, 0x00, 0x01, 0xf1, 0x01, 0x01, 0xba, 0xf8, 0x00, 0x40, 0x14, 0xf0, 0x01, 0x0f, 0xfa, 0xd1, 0x01, 0x3a, 0xf2, 0xdc, 0x00, 0xbe, 0x00, 0xbf, 0x00, 0x3c, 0x02, 0x40, 0x0e, 0x00, 0x00, 0x00 }; // flashloaders/stm32h5.s -- 128-bit quad-word programming, waits on NSSR BSY static const uint8_t loader_code_stm32h5[] = { 0xdf, 0xf8, 0x34, 0xc0, 0xdf, 0xf8, 0x34, 0xa0, 0xe2, 0x44, 0x04, 0x68, 0x45, 0x68, 0x86, 0x68, 0xc7, 0x68, 0x0c, 0x60, 0x4d, 0x60, 0x8e, 0x60, 0xcf, 0x60, 0x00, 0xf1, 0x10, 0x00, 0x01, 0xf1, 0x10, 0x01, 0xbf, 0xf3, 0x4f, 0x8f, 0xda, 0xf8, 0x00, 0x40, 0x14, 0xf0, 0x01, 0x0f, 0xfa, 0xd1, 0x10, 0x3a, 0xea, 0xdc, 0x00, 0xbe, 0x00, 0xbf, 0x00, 0x20, 0x02, 0x40, 0x20, 0x00, 0x00, 0x00 }; // flashloaders/stm32l4.s static const uint8_t loader_code_stm32l4[] = { 0xdf, 0xf8, 0x28, 0xc0, 0xdf, 0xf8, 0x28, 0xa0, 0xe2, 0x44, 0x05, 0x68, 0x44, 0x68, 0x0d, 0x60, 0x4c, 0x60, 0x00, 0xf1, 0x08, 0x00, 0x01, 0xf1, 0x08, 0x01, 0xda, 0xf8, 0x00, 0x40, 0x14, 0xf4, 0x80, 0x3f, 0xfa, 0xd1, 0x08, 0x3a, 0xf0, 0xdc, 0x00, 0xbe, 0x00, 0xbf, 0x00, 0x20, 0x02, 0x40, 0x10, 0x00, 0x00, 0x00 }; // flashloaders/stm32f7.s static const uint8_t loader_code_stm32f7[] = { 0xdf, 0xf8, 0x28, 0xc0, 0xdf, 0xf8, 0x28, 0xa0, 0xe2, 0x44, 0x04, 0x68, 0x0c, 0x60, 0x00, 0xf1, 0x04, 0x00, 0x01, 0xf1, 0x04, 0x01, 0xbf, 0xf3, 0x4f, 0x8f, 0xba, 0xf8, 0x00, 0x40, 0x14, 0xf0, 0x01, 0x0f, 0xfa, 0xd1, 0x04, 0x3a, 0xf0, 0xdc, 0x00, 0xbe, 0x00, 0xbf, 0x00, 0x3c, 0x02, 0x40, 0x0e, 0x00, 0x00, 0x00 }; // flashloaders/stm32f7lv.s static const uint8_t loader_code_stm32f7_lv[] = { 0xdf, 0xf8, 0x28, 0xc0, 0xdf, 0xf8, 0x28, 0xa0, 0xe2, 0x44, 0x04, 0x78, 0x0c, 0x70, 0x00, 0xf1, 0x01, 0x00, 0x01, 0xf1, 0x01, 0x01, 0xbf, 0xf3, 0x4f, 0x8f, 0xba, 0xf8, 0x00, 0x40, 0x14, 0xf0, 0x01, 0x0f, 0xfa, 0xd1, 0x01, 0x3a, 0xf0, 0xdc, 0x00, 0xbe, 0x00, 0xbf, 0x00, 0x3c, 0x02, 0x40, 0x0e, 0x00, 0x00, 0x00 }; int32_t stlink_flash_loader_init(stlink_t *sl, flash_loader_t *fl) { uint32_t size = 0; uint32_t dfsr, cfsr, hfsr; /* Interrupt masking according to DDI0419C, Table C1-7 firstly force halt */ stlink_write_debug32(sl, STM32_REG_DHCSR, STM32_REG_DHCSR_DBGKEY | STM32_REG_DHCSR_C_DEBUGEN | STM32_REG_DHCSR_C_HALT); /* and only then disable interrupts */ stlink_write_debug32(sl, STM32_REG_DHCSR, STM32_REG_DHCSR_DBGKEY | STM32_REG_DHCSR_C_DEBUGEN | STM32_REG_DHCSR_C_HALT | STM32_REG_DHCSR_C_MASKINTS); // allocate the loader in SRAM if(stlink_flash_loader_write_to_sram(sl, &fl->loader_addr, &size) == -1) { WLOG("Failed to write flash loader to sram!\n"); return (-1); } // allocate a one page buffer in SRAM right after loader fl->buf_addr = fl->loader_addr + size; ILOG("Successfully loaded flash loader in sram\n"); // set address of IWDG key register for reset it if(sl->flash_type == STM32_FLASH_TYPE_H7) { fl->iwdg_kr = STM32H7_WDG_KR; } else { fl->iwdg_kr = STM32F0_WDG_KR; } /* Clear Fault Status Register for handling flash loader error */ if(!stlink_read_debug32(sl, STM32_REG_DFSR, &dfsr) && dfsr) { ILOG("Clear DFSR\n"); stlink_write_debug32(sl, STM32_REG_DFSR, dfsr); } if(!stlink_read_debug32(sl, STM32_REG_CFSR, &cfsr) && cfsr) { ILOG("Clear CFSR\n"); stlink_write_debug32(sl, STM32_REG_CFSR, cfsr); } if(!stlink_read_debug32(sl, STM32_REG_HFSR, &hfsr) && hfsr) { ILOG("Clear HFSR\n"); stlink_write_debug32(sl, STM32_REG_HFSR, hfsr); } return (0); } static int32_t loader_v_dependent_assignment(stlink_t *sl, const uint8_t **loader_code, uint32_t *loader_size, const uint8_t *high_v_loader, uint32_t high_v_loader_size, const uint8_t *low_v_loader, uint32_t low_v_loader_size) { int32_t retval = 0; if( sl->version.stlink_v == 1) { printf("STLINK V1 cannot read voltage, defaulting to 32-bit writes\n"); *loader_code = high_v_loader; *loader_size = high_v_loader_size; } else { int32_t voltage = stlink_target_voltage(sl); if(voltage == -1) { retval = -1; printf("Failed to read Target voltage\n"); } else { if(voltage > 2700) { *loader_code = high_v_loader; *loader_size = high_v_loader_size; } else { *loader_code = low_v_loader; *loader_size = low_v_loader_size; } } } return (retval); } int32_t stlink_flash_loader_write_to_sram(stlink_t *sl, stm32_addr_t* addr, uint32_t* size) { const uint8_t* loader_code; uint32_t loader_size; if(sl->chip_id == STM32_CHIPID_L1_MD || sl->chip_id == STM32_CHIPID_L1_CAT2 || sl->chip_id == STM32_CHIPID_L1_MD_PLUS || sl->chip_id == STM32_CHIPID_L1_MD_PLUS_HD || sl->chip_id == STM32_CHIPID_L152_RE || sl->chip_id == STM32_CHIPID_L0_CAT1 || sl->chip_id == STM32_CHIPID_L0_CAT2 || sl->chip_id == STM32_CHIPID_L0_CAT3 || sl->chip_id == STM32_CHIPID_L0_CAT5) { loader_code = loader_code_stm32lx; loader_size = sizeof(loader_code_stm32lx); } else if(sl->core_id == STM32_CORE_ID_M3_r1p1_SWD || sl->chip_id == STM32_CHIPID_F1_MD || sl->chip_id == STM32_CHIPID_F1_HD || sl->chip_id == STM32_CHIPID_F1_LD || sl->chip_id == STM32_CHIPID_F1_VL_MD_LD || sl->chip_id == STM32_CHIPID_F1_VL_HD || sl->chip_id == STM32_CHIPID_F1_XLD || sl->chip_id == STM32_CHIPID_F1_CONN || sl->chip_id == STM32_CHIPID_F3 || sl->chip_id == STM32_CHIPID_F3xx_SMALL || sl->chip_id == STM32_CHIPID_F303_HD || sl->chip_id == STM32_CHIPID_F37x || sl->chip_id == STM32_CHIPID_F334) { loader_code = loader_code_stm32vl; loader_size = sizeof(loader_code_stm32vl); } else if(sl->chip_id == STM32_CHIPID_F2 || sl->chip_id == STM32_CHIPID_F4 || sl->chip_id == STM32_CHIPID_F4_DE || sl->chip_id == STM32_CHIPID_F4_LP || sl->chip_id == STM32_CHIPID_F4_HD || sl->chip_id == STM32_CHIPID_F4_DSI || sl->chip_id == STM32_CHIPID_F410 || sl->chip_id == STM32_CHIPID_F411xx || sl->chip_id == STM32_CHIPID_F412 || sl->chip_id == STM32_CHIPID_F413 || sl->chip_id == STM32_CHIPID_F446) { int32_t retval; retval = loader_v_dependent_assignment(sl, &loader_code, &loader_size, loader_code_stm32f4, sizeof(loader_code_stm32f4), loader_code_stm32f4_lv, sizeof(loader_code_stm32f4_lv)); if(retval == -1) { return (retval); } } else if(sl->core_id == STM32_CORE_ID_M7F_SWD || sl->chip_id == STM32_CHIPID_F7 || sl->chip_id == STM32_CHIPID_F76xxx || sl->chip_id == STM32_CHIPID_F72xxx) { int32_t retval; retval = loader_v_dependent_assignment(sl, &loader_code, &loader_size, loader_code_stm32f7, sizeof(loader_code_stm32f7), loader_code_stm32f7_lv, sizeof(loader_code_stm32f7_lv)); if(retval == -1) { return (retval); } } else if(sl->chip_id == STM32_CHIPID_F0 || sl->chip_id == STM32_CHIPID_F04 || sl->chip_id == STM32_CHIPID_F0_CAN || sl->chip_id == STM32_CHIPID_F0xx_SMALL || sl->chip_id == STM32_CHIPID_F09x) { loader_code = loader_code_stm32f0; loader_size = sizeof(loader_code_stm32f0); } else if(sl->flash_type == STM32_FLASH_TYPE_WB0) { loader_code = loader_code_stm32wb0; loader_size = sizeof(loader_code_stm32wb0); } else if(sl->flash_type == STM32_FLASH_TYPE_H5) { loader_code = loader_code_stm32h5; loader_size = sizeof(loader_code_stm32h5); } else if((sl->chip_id == STM32_CHIPID_L4) || (sl->chip_id == STM32_CHIPID_L41x_L42x) || (sl->chip_id == STM32_CHIPID_L43x_L44x) || (sl->chip_id == STM32_CHIPID_L45x_L46x) || (sl->chip_id == STM32_CHIPID_L4PX) || (sl->chip_id == STM32_CHIPID_L4Rx) || (sl->chip_id == STM32_CHIPID_L496x_L4A6x)) { loader_code = loader_code_stm32l4; loader_size = sizeof(loader_code_stm32l4); } else { ELOG("unknown coreid, not sure what flash loader to use, aborting! coreid: %x, chipid: %x\n", sl->core_id, sl->chip_id); return (-1); } memcpy(sl->q_buf, loader_code, loader_size); int32_t ret = stlink_write_mem32(sl, sl->sram_base, (uint16_t) loader_size); if(ret) { return (ret); } *addr = sl->sram_base; *size = loader_size; return (0); // success } int32_t stlink_flash_loader_run(stlink_t *sl, flash_loader_t* fl, stm32_addr_t target, const uint8_t* buf, uint32_t size) { struct stlink_reg rr; uint32_t timeout; uint32_t flash_base = 0; uint32_t dhcsr, dfsr, cfsr, hfsr; uint16_t padded_size = size, pad_modulo = 1; if(sl->flash_type == STM32_FLASH_TYPE_WB0 || sl->flash_type == STM32_FLASH_TYPE_H5) { pad_modulo = 16; // H5 programs a 128-bit quad-word at a time } uint16_t unaligned_cnt = size % pad_modulo; if (unaligned_cnt) { padded_size = size + (pad_modulo - unaligned_cnt); } DLOG("Running flash loader, write address:%#x, size: %u, padded_size: %u\n", target, size, padded_size); if(stlink_write_buffer_to_sram(sl, fl, buf, size, padded_size) == -1) { ELOG("stlink_write_buffer_to_sram() == -1\n"); return (-1); } if((sl->flash_type == STM32_FLASH_TYPE_F1_XL) && (target >= FLASH_BANK2_START_ADDR)) { flash_base = FLASH_REGS_BANK2_OFS; } /* Setup core */ stlink_write_reg(sl, fl->buf_addr, 0); // source stlink_write_reg(sl, target, 1); // target stlink_write_reg(sl, padded_size, 2); // count stlink_write_reg(sl, flash_base, 3); // flash register base // only used on VL/F1_XL, but harmless for others stlink_write_reg(sl, fl->loader_addr, 15); // pc register /* Reset IWDG */ if(fl->iwdg_kr) { stlink_write_debug32(sl, fl->iwdg_kr, STM32F0_WDG_KR_KEY_RELOAD); } /* Run loader */ stlink_run(sl, RUN_FLASH_LOADER); /* * This piece of code used to try to spin for .1 second by waiting doing 10000 rounds of 10 µs. * But because this usually runs on Unix-like OSes, the 10 µs get rounded up to the "tick" * (actually almost two ticks) of the system. 1 ms. Thus, the ten thousand attempts, when * "something goes wrong" that requires the error message "flash loader run error" would wait * for something like 20 seconds before coming up with the error. * By increasing the sleep-per-round to the same order-of-magnitude as the tick-rounding that * the OS uses, the wait until the error message is reduced to the same order of magnitude * as what was intended. -- REW. */ // wait until done (reaches breakpoint) timeout = time_ms() + 500; while (time_ms() < timeout) { usleep(10000); if(stlink_is_core_halted(sl)) { timeout = 0; break; } } if(timeout) { ELOG("Flash loader run error\n"); goto error; } // check written byte count stlink_read_reg(sl, 2, &rr); /* * The chunk size for loading is not rounded. The flash loader * subtracts the size of the written block (1-8 bytes) from * the remaining size each time. A negative value may mean that * several bytes garbage have been written due to the unaligned * firmware size. */ if((int32_t) rr.r[2] > 0 || (int32_t) rr.r[2] < -7) { ELOG("Flash loader write error at 0x%08X\n", target + padded_size - rr.r[2]); goto error; } return (0); error: dhcsr = dfsr = cfsr = hfsr = 0; stlink_force_debug(sl); // ensure we can read regs, even after timeout stlink_read_debug32(sl, STM32_REG_DHCSR, &dhcsr); stlink_read_debug32(sl, STM32_REG_DFSR, &dfsr); stlink_read_debug32(sl, STM32_REG_CFSR, &cfsr); stlink_read_debug32(sl, STM32_REG_HFSR, &hfsr); stlink_read_all_regs(sl, &rr); WLOG("Loader state: PC 0x%08X\n", rr.r[15]); WLOG(" R0 0x%08X R1 0x%08X\n", rr.r[0], rr.r[1]); WLOG(" R2 0x%08X R3 0x%08X\n", rr.r[2], rr.r[3]); WLOG(" R4 0x%08X R5 0x%08X\n", rr.r[4], rr.r[5]); WLOG(" R6 0x%08X R7 0x%08X\n", rr.r[6], rr.r[7]); if(dhcsr != 0x3000B || dfsr || cfsr || hfsr) { WLOG("MCU state: DHCSR 0x%X DFSR 0x%X CFSR 0x%X HFSR 0x%X\n", dhcsr, dfsr, cfsr, hfsr); } return (-1); } /* === Content from old source file flashloader.c === */ #define L1_WRITE_BLOCK_SIZE 0x80 #define L0_WRITE_BLOCK_SIZE 0x40 int32_t stm32l1_write_half_pages(stlink_t *sl, flash_loader_t *fl, stm32_addr_t addr, uint8_t *base, uint32_t len, uint32_t pagesize) { uint32_t count, off; uint32_t num_half_pages = len / pagesize; uint32_t val; uint32_t flash_regs_base = get_stm32l0_flash_base(sl); bool use_loader = true; int32_t ret = 0; // enable half page write stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val); val |= (1 << STM32_FLASH_L1_FPRG); stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val); val |= (1 << STM32_FLASH_L1_PROG); stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val); wait_flash_busy(sl); for(count = 0; count < num_half_pages; count++) { if(use_loader) { ret = stlink_flash_loader_run(sl, fl, addr + count * pagesize, base + count * pagesize, pagesize); if(ret && count == 0) { /* It seems that stm32lx devices have a problem when it is blank */ WLOG("Failed to use flash loader, fallback to soft write\n"); use_loader = false; } } if(!use_loader) { ret = 0; for(off = 0; off < pagesize && !ret; off += 64) { uint32_t chunk = (pagesize - off > 64) ? 64 : pagesize - off; memcpy(sl->q_buf, base + count * pagesize + off, chunk); ret = stlink_write_mem32(sl, addr + count * pagesize + off, (uint16_t) chunk); } } if(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, "%3u/%3u halfpages written\n", 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 << STM32_FLASH_L1_FPRG) | (1 << STM32_FLASH_L1_PROG)); stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val); return (ret); } static void set_flash_cr_pg(stlink_t *sl, uint32_t bank) { uint32_t cr_reg, x; x = read_flash_cr(sl, bank); if(sl->flash_type == STM32_FLASH_TYPE_C0) { cr_reg = STM32_FLASH_C0_CR; x |= (1 << FLASH_CR_PG); } else if(sl->flash_type == STM32_FLASH_TYPE_F2_F4) { cr_reg = STM32_FLASH_F4_CR; x |= (1 << FLASH_CR_PG); } else if(sl->flash_type == STM32_FLASH_TYPE_F7) { cr_reg = STM32_FLASH_F7_CR; x |= (1 << FLASH_CR_PG); } else if(sl->flash_type == STM32_FLASH_TYPE_L4) { cr_reg = STM32_FLASH_L4_CR; x &= ~STM32_FLASH_L4_CR_OPBITS; x |= (1 << STM32_FLASH_L4_CR_PG); } else if(sl->flash_type == STM32_FLASH_TYPE_L5_U5) { cr_reg = STM32_FLASH_L5_NSCR; x |= (1 << FLASH_CR_PG); } else if(sl->flash_type == STM32_FLASH_TYPE_H5) { cr_reg = STM32_FLASH_H5_NSCR; x |= (1 << STM32_FLASH_H5_NSCR_PG); } else if(sl->flash_type == STM32_FLASH_TYPE_G0 || sl->flash_type == STM32_FLASH_TYPE_G4) { cr_reg = STM32_FLASH_Gx_CR; // RM0444/RM0440 sec. 3.3.8: PGSERR is raised if PER, MER1/MER2 or FSTPG // are still set while programming (e.g. left over from a previous erase). x &= ~((1u << STM32_FLASH_Gx_CR_PER) | (1u << STM32_FLASH_Gx_CR_MER1) | (1u << STM32_FLASH_Gx_CR_MER2) | (1u << STM32_FLASH_Gx_CR_FSTPG)); x |= (1 << FLASH_CR_PG); } else if(sl->flash_type == STM32_FLASH_TYPE_WB_WL) { cr_reg = STM32_FLASH_WB_CR; x |= (1 << FLASH_CR_PG); } else if(sl->flash_type == STM32_FLASH_TYPE_C5) { cr_reg = STM32_FLASH_C5_CR; x |= (1 << STM32_FLASH_C5_CR_PG); } else if(sl->flash_type == STM32_FLASH_TYPE_H7) { cr_reg = (bank == BANK_1) ? STM32_FLASH_H7_CR1 : STM32_FLASH_H7_CR2; x |= (1 << STM32_FLASH_H7_CR_PG); } else { cr_reg = (bank == BANK_1) ? FLASH_CR : FLASH_CR2; x = (1 << FLASH_CR_PG); } stlink_write_debug32(sl, cr_reg, x); } static void set_dma_state(stlink_t *sl, flash_loader_t *fl, int32_t bckpRstr) { uint32_t rcc, rcc_dma_mask, value; rcc = rcc_dma_mask = value = 0; switch (sl->flash_type) { case STM32_FLASH_TYPE_C0: rcc = STM32C0_RCC_AHBENR; rcc_dma_mask = STM32C0_RCC_DMAEN; break; case STM32_FLASH_TYPE_F0_F1_F3: case STM32_FLASH_TYPE_F1_XL: rcc = STM32F1_RCC_AHBENR; rcc_dma_mask = STM32F1_RCC_DMAEN; break; case STM32_FLASH_TYPE_F2_F4: case STM32_FLASH_TYPE_F7: rcc = STM32F4_RCC_AHB1ENR; rcc_dma_mask = STM32F4_RCC_DMAEN; break; case STM32_FLASH_TYPE_G0: rcc = STM32G0_RCC_AHBENR; rcc_dma_mask = STM32G0_RCC_DMAEN; break; case STM32_FLASH_TYPE_G4: case STM32_FLASH_TYPE_L4: rcc = STM32G4_RCC_AHB1ENR; rcc_dma_mask = STM32G4_RCC_DMAEN; break; case STM32_FLASH_TYPE_L0_L1: if(get_stm32l0_flash_base(sl) == STM32_FLASH_Lx_REGS_ADDR) { rcc = STM32L1_RCC_AHBENR; rcc_dma_mask = STM32L1_RCC_DMAEN; } else { rcc = STM32L0_RCC_AHBENR; rcc_dma_mask = STM32L0_RCC_DMAEN; } break; case STM32_FLASH_TYPE_L5_U5: rcc = STM32L5_RCC_AHB1ENR; rcc_dma_mask = STM32L5_RCC_DMAEN; break; case STM32_FLASH_TYPE_H7: rcc = STM32H7_RCC_AHB1ENR; rcc_dma_mask = STM32H7_RCC_DMAEN; break; case STM32_FLASH_TYPE_WB_WL: rcc = STM32WB_RCC_AHB1ENR; rcc_dma_mask = STM32WB_RCC_DMAEN; break; case STM32_FLASH_TYPE_WB0: rcc = STM32WB0_RCC_AHBENR; rcc_dma_mask = STM32WB0_RCC_AHB_DMAEN; break; case STM32_FLASH_TYPE_C5: rcc = STM32C5_RCC_AHB1ENR; rcc_dma_mask = STM32C5_RCC_DMAEN; break; default: return; } if(!stlink_read_debug32(sl, rcc, &value)) { if(bckpRstr) { value = (value & (~rcc_dma_mask)) | fl->rcc_dma_bkp; } else { fl->rcc_dma_bkp = value & rcc_dma_mask; value &= ~rcc_dma_mask; } stlink_write_debug32(sl, rcc, value); } } int32_t stlink_flashloader_start(stlink_t *sl, flash_loader_t *fl) { // disable DMA set_dma_state(sl, fl, 0); // wait for ongoing op to finish wait_flash_busy(sl); // Clear errors clear_flash_error(sl); if((sl->flash_type == STM32_FLASH_TYPE_F2_F4) || (sl->flash_type == STM32_FLASH_TYPE_F7) || (sl->flash_type == STM32_FLASH_TYPE_L4)) { ILOG("Starting Flash write for F2/F4/F7/L4\n"); // Flash loader initialisation if(stlink_flash_loader_init(sl, fl) == -1) { ELOG("stlink_flash_loader_init() == -1\n"); return (-1); } unlock_flash_if(sl); // first unlock the cr int32_t voltage; if(sl->version.stlink_v == 1) { WLOG("STLINK V1 cannot read voltage, use default voltage 3.2 V\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) { // 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_H5) { ILOG("Starting Flash write for H5\n"); // H5 programs via an SRAM loader, so it must be staged into SRAM first // (this sets fl->loader_addr / fl->buf_addr used by the loader run). if(stlink_flash_loader_init(sl, fl) == -1) { ELOG("stlink_flash_loader_init() == -1\n"); return (-1); } unlock_flash_if(sl); // unlock the flash control register set_flash_cr_pg(sl, BANK_1); // set PG 'allow programming' bit } else if(sl->flash_type == STM32_FLASH_TYPE_WB_WL || sl->flash_type == STM32_FLASH_TYPE_G0 || sl->flash_type == STM32_FLASH_TYPE_G4 || sl->flash_type == STM32_FLASH_TYPE_L5_U5 || sl->flash_type == STM32_FLASH_TYPE_C5 || sl->flash_type == STM32_FLASH_TYPE_C0) { ILOG("Starting Flash write for WB/WL/G0/G4/L5/U5/C0/C5\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, STM32_FLASH_L0_PEKEY1); stlink_write_debug32(sl, flash_regs_base + FLASH_PEKEYR_OFF, STM32_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, STM32_FLASH_L0_PRGKEY1); stlink_write_debug32(sl, flash_regs_base + FLASH_PRGKEYR_OFF, STM32_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_WB0) { ILOG("Starting Flash write for WB0\n"); if(stlink_flash_loader_init(sl, fl) == -1) { ELOG("stlink_flash_loader_init() == -1\n"); return (-1); } } 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 /* 64 bit */, BANK_1); if(sl->chip_flags & CHIP_F_HAS_DUAL_BANK) { write_flash_cr_psiz(sl, 3 /* 64 bit */, BANK_2); } } } else { ELOG("unknown coreid, not sure how to write: %x\n", sl->core_id); return (-1); } return (0); } int32_t stlink_flashloader_write(stlink_t *sl, flash_loader_t *fl, stm32_addr_t addr, uint8_t *base, uint32_t len) { uint32_t off; bool is_exclusively_otp = addr >= sl->otp_base && addr < sl->otp_base + sl->otp_size; bool is_exclusively_flash = addr >= sl->flash_base && addr < sl->flash_base + sl->flash_size; if((sl->flash_type == STM32_FLASH_TYPE_F2_F4) || (sl->flash_type == STM32_FLASH_TYPE_F7) || (sl->flash_type == STM32_FLASH_TYPE_L4) || (sl->flash_type == STM32_FLASH_TYPE_H5) || (sl->flash_type == STM32_FLASH_TYPE_WB0 && is_exclusively_flash)) { uint32_t buf_size = sl->sram_size - 0x1000; buf_size = buf_size > 0x8000 ? 0x8000 : buf_size; for(off = 0; off < len;) { uint32_t size = len - off > buf_size ? buf_size : len - off; if(stlink_flash_loader_run(sl, fl, addr + off, base + off, size) == -1) { ELOG("stlink_flash_loader_run(%#x) failed! == -1\n", (addr + off)); check_flash_error(sl); return (-1); } off += size; } } else if(sl->flash_type == STM32_FLASH_TYPE_C5) { // C5 programs flash in 16-byte (128-bit) rows: four 32-bit words are // latched, then the controller commits one row per BSY cycle (RM0522; // matches the DFP mem_loader_program). Writing a single word leaves the // row incomplete and the controller stalls, so write whole rows via one // MEM-AP transfer and wait for BSY only once per row. const uint32_t row = 16; const uint32_t padded_len = (len + row - 1) & ~(row - 1); if(len != padded_len) WLOG("Aligning data size to 16 bytes\n"); DLOG("Starting %3u row write\n", padded_len / row); for(off = 0; off < padded_len; off += row) { uint32_t bytes_to_copy = len - off < row ? len - off : row; memcpy(sl->q_buf, base + off, bytes_to_copy); memset(sl->q_buf + bytes_to_copy, 0xFF, row - bytes_to_copy); if((off % sl->flash_pgsz) > (sl->flash_pgsz - row - 1)) { fprintf(stdout, "%3u/%-3u pages written\n", (off / sl->flash_pgsz + 1), (padded_len / sl->flash_pgsz)); fflush(stdout); } if(stlink_write_mem32(sl, addr + off, (uint16_t)row)) { ELOG("stlink_write_mem32(%#x) failed! == -1\n", (addr + off)); check_flash_error(sl); return (-1); } wait_flash_busy(sl); if(check_flash_error(sl)) { return (-1); } } fprintf(stdout, "\n"); } else if(sl->flash_type == STM32_FLASH_TYPE_WB_WL || sl->flash_type == STM32_FLASH_TYPE_G0 || sl->flash_type == STM32_FLASH_TYPE_G4 || sl->flash_type == STM32_FLASH_TYPE_L5_U5 || sl->flash_type == STM32_FLASH_TYPE_C0) { // L5/U5 program in 16-byte units. if(sl->flash_type == STM32_FLASH_TYPE_L5_U5 && (len % 16)) { WLOG("Aligning data size to 16 bytes\n"); len += 16 - len % 16; } DLOG("Starting %3u page write\n", len / sl->flash_pgsz); for(off = 0; off < len; off += sizeof(uint32_t)) { uint32_t data; if((off % sl->flash_pgsz) > (sl->flash_pgsz - 5)) { fprintf(stdout, "%3u/%-3u pages written\n", (off / sl->flash_pgsz + 1), (len / sl->flash_pgsz)); fflush(stdout); } // write_uint32((unsigned char *)&data, *(uint32_t *)(base + off)); data = 0; memcpy(&data, base + off, (len - off) < 4 ? (len - off) : 4); stlink_write_debug32(sl, addr + off, data); // STM32G0: programming starts only once both words of a double-word are // written; CFGBSY stays set in between, so only wait after the 2nd word. if(sl->flash_type != STM32_FLASH_TYPE_G0 || ((addr + off) & 0x04)) { 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: complete a pending double-word if((addr + off) & 0x04) { stlink_write_debug32(sl, addr + off, 0); // write a single word of zeros wait_flash_busy(sl); // wait for 'busy' bit in FLASH_SR to clear } } else if(sl->flash_type == STM32_FLASH_TYPE_L0_L1) { uint32_t val; uint32_t flash_regs_base = get_stm32l0_flash_base(sl); uint32_t pagesize = (flash_regs_base == STM32_FLASH_L0_REGS_ADDR)? L0_WRITE_BLOCK_SIZE : L1_WRITE_BLOCK_SIZE; DLOG("Starting %3u page write\n", len / sl->flash_pgsz); off = 0; if(len > pagesize) { if(stm32l1_write_half_pages(sl, fl, addr, base, len, pagesize)) { return (-1); } else { off = (uint32_t) ((uint64_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, "%3u/%-3u pages written\n", (off / sl->flash_pgsz + 1), (len / sl->flash_pgsz)); fflush(stdout); } write_uint32((unsigned char *)&data, *(uint32_t *)(base + off)); stlink_write_debug32(sl, addr + off, data); // wait for sr.busy to be cleared do { stlink_read_debug32(sl, flash_regs_base + FLASH_SR_OFF, &val); } while ((val & (1 << 0)) != 0); // TODO: check redo write operation } fprintf(stdout, "\n"); } else if((sl->flash_type == STM32_FLASH_TYPE_F0_F1_F3) || (sl->flash_type == STM32_FLASH_TYPE_F1_XL)) { int32_t write_block_count = 0; for(off = 0; off < len; off += sl->flash_pgsz) { // adjust last write size uint32_t size = len - off > sl->flash_pgsz ? sl->flash_pgsz : len - off; // unlock and set programming mode unlock_flash_if(sl); DLOG("Finished unlocking flash, running loader!\n"); if(stlink_flash_loader_run(sl, fl, addr + off, base + off, size) == -1) { ELOG("stlink_flash_loader_run(%#x) failed! == -1\n", (addr + off)); check_flash_error(sl); return (-1); } lock_flash(sl); if(sl->verbose >= 1) { // show progress; writing procedure is slow and previous errors are // misleading fprintf(stdout, "%3u/%-3u pages written\n", ++write_block_count, (len + sl->flash_pgsz - 1) / sl->flash_pgsz); fflush(stdout); } } if(sl->verbose >= 1) { fprintf(stdout, "\n"); } } else if(sl->flash_type == STM32_FLASH_TYPE_H7) { for(off = 0; off < len;) { // Program STM32H7x with 64-byte Flash words uint32_t chunk = (len - off > 64) ? 64 : len - off; memcpy(sl->q_buf, base + off, chunk); stlink_write_mem32(sl, addr + off, 64); wait_flash_busy(sl); off += chunk; if(sl->verbose >= 1) { // show progress fprintf(stdout, "%u/%u bytes written\n", off, len); fflush(stdout); } } if(sl->verbose >= 1) { fprintf(stdout, "\n"); } } else if((sl->flash_type == STM32_FLASH_TYPE_WB0) && is_exclusively_otp) { // WB0 OTP area can not be written with BURSTWRITE as implemented in flashloader // Writes are done as 32bit words, out of bounds bytes are written as 0xFF (no change to flash) for(off = 0; off < len; ) { uint32_t current_addr = addr + off; uint32_t remaining = len - off; uint32_t word_base = current_addr & (~0x03); uint32_t unused_front = current_addr - word_base; uint32_t max_bytes = 4 - unused_front; uint32_t bytes_to_copy = remaining < max_bytes ? remaining : max_bytes; uint32_t data_word = 0xFFFFFFFF; memcpy(((uint8_t*)&data_word) + unused_front, base + off, bytes_to_copy); stlink_write_debug32(sl, STM32_FLASH_WB0_IRQRAW, STM32_FLASH_WB0_IRQ_ALL); stlink_write_debug32(sl, STM32_FLASH_WB0_DATA0, data_word); stlink_write_debug32(sl, STM32_FLASH_WB0_ADDRESS, (current_addr) >> 2); stlink_write_debug32(sl, STM32_FLASH_WB0_COMMAND, STM32_FLASH_WB0_CMD_OTPWRITE); wait_flash_busy(sl); if (check_flash_error(sl)) { ELOG("Failed to writing OTP word at 0x%08X!\n", current_addr); return (-1); } off += bytes_to_copy; } } else { return (-1); } return check_flash_error(sl); } /* * STM32L4 devices with FLASH_SR.PEMPTY boot from system memory instead of main * flash while PEMPTY is set. The flag is only re-evaluated on power-on reset or * option byte loading, so after programming a previously empty device it stays * set and a plain system reset starts the bootloader. Clear it (by toggling, * RM0394/RM0432) once the first flash word is programmed. This also recovers * devices left in that state by older stlink versions. */ static void stlink_l4_sync_pempty(stlink_t *sl) { uint32_t sr, first_word; switch(sl->chip_id) { case STM32_CHIPID_L41x_L42x: case STM32_CHIPID_L43x_L44x: case STM32_CHIPID_L45x_L46x: case STM32_CHIPID_L4PX: case STM32_CHIPID_L4Rx: break; default: return; // L47x/L48x, L49x/L4Ax: no PEMPTY flag (bit 17 reserved) } if(stlink_read_debug32(sl, STM32_FLASH_L4_SR, &sr) || stlink_read_debug32(sl, STM32_FLASH_BASE, &first_word)) { return; } if((sr & (1u << STM32_FLASH_L4_SR_PEMPTY)) && first_word != 0xffffffff) { DLOG("Clearing FLASH_SR.PEMPTY so the device boots from main flash\n"); stlink_write_debug32(sl, STM32_FLASH_L4_SR, (1u << STM32_FLASH_L4_SR_PEMPTY)); } } int32_t stlink_flashloader_stop(stlink_t *sl, flash_loader_t *fl) { uint32_t dhcsr; if(sl->flash_type == STM32_FLASH_TYPE_L4) { stlink_l4_sync_pempty(sl); } if((sl->flash_type == STM32_FLASH_TYPE_C0) || (sl->flash_type == STM32_FLASH_TYPE_F0_F1_F3) || (sl->flash_type == STM32_FLASH_TYPE_F1_XL) || (sl->flash_type == STM32_FLASH_TYPE_F2_F4) || (sl->flash_type == STM32_FLASH_TYPE_F7) || (sl->flash_type == STM32_FLASH_TYPE_G0) || (sl->flash_type == STM32_FLASH_TYPE_G4) || (sl->flash_type == STM32_FLASH_TYPE_H7) || (sl->flash_type == STM32_FLASH_TYPE_L4) || (sl->flash_type == STM32_FLASH_TYPE_L5_U5) || (sl->flash_type == STM32_FLASH_TYPE_H5) || (sl->flash_type == STM32_FLASH_TYPE_WB_WL) || (sl->flash_type == STM32_FLASH_TYPE_C5)) { 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, STM32_REG_DHCSR, &dhcsr)) { stlink_write_debug32(sl, STM32_REG_DHCSR, STM32_REG_DHCSR_DBGKEY | STM32_REG_DHCSR_C_DEBUGEN | (dhcsr & (~STM32_REG_DHCSR_C_MASKINTS))); } // restore DMA state set_dma_state(sl, fl, 1); return (0); } stlink-1.9.0/src/stlink-lib/flash_loader.h000066400000000000000000000037211526027543100204700ustar00rootroot00000000000000/** ****************************************************************************** * @file : flash_loader.h * @brief : Flash loaders * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #ifndef FLASH_LOADER_H #define FLASH_LOADER_H #include #include #include #include #include #include #include int32_t stlink_flash_loader_init(stlink_t *sl, flash_loader_t* fl); // static int32_t loader_v_dependent_assignment(stlink_t *sl, // const uint8_t **loader_code, uint32_t *loader_size, // const uint8_t *high_v_loader, uint32_t high_v_loader_size, // const uint8_t *low_v_loader, uint32_t low_v_loader_size); int32_t stlink_flash_loader_write_to_sram(stlink_t *sl, stm32_addr_t* addr, uint32_t* size); int32_t stlink_flash_loader_run(stlink_t *sl, flash_loader_t* fl, stm32_addr_t target, const uint8_t* buf, uint32_t size); /* === Functions from old header file flashloader.h === */ int32_t stm32l1_write_half_pages(stlink_t *sl, flash_loader_t *fl, stm32_addr_t addr, uint8_t *base, uint32_t len, uint32_t pagesize); // static void set_flash_cr_pg(stlink_t *sl, uint32_t bank); // static void set_dma_state(stlink_t *sl, flash_loader_t *fl, int32_t bckpRstr); int32_t stlink_flashloader_start(stlink_t *sl, flash_loader_t *fl); int32_t stlink_flashloader_write(stlink_t *sl, flash_loader_t *fl, stm32_addr_t addr, uint8_t *base, uint32_t len); int32_t stlink_flashloader_stop(stlink_t *sl, flash_loader_t *fl); #endif // FLASH_LOADER_H stlink-1.9.0/src/stlink-lib/helper.c000066400000000000000000000032401526027543100173130ustar00rootroot00000000000000/** ****************************************************************************** * @file : helper.c * @brief : General helper functions * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #include "helper.h" uint32_t time_ms() { struct timeval tv; gettimeofday(&tv, NULL); return (uint32_t) (tv.tv_sec * 1000 + tv.tv_usec / 1000); } int32_t arg_parse_freq(const char *str) { if(str == NULL) { return -1; // faulty input } char* tail = NULL; int32_t value = (uint32_t) strtol(str, &tail, 10); /* == Input value interpretation == * * These decimal values represent kHz. * The prefix "k" may be added for better understanding, but has no effect. * In addition, values can be interpreted as thousands of kHz thus representing MHz. * This is achieved by using the prefix "M". */ if(tail == NULL) { return -1; // faulty integer conversion } else if(tail[0] == '\0') { return value; // no prefix: kHz } else if((tail[0] == 'k' || tail[0] == 'K') && tail[1] == '\0') { return value; // k prefix: kHz } else if(tail[0] == 'M' && tail[1] == '\0') { return (value * 1000); // M prefix: MHz } return -1; // invalid prefix } stlink-1.9.0/src/stlink-lib/helper.h000066400000000000000000000014741526027543100173270ustar00rootroot00000000000000/** ****************************************************************************** * @file : helper.h * @brief : General helper functions * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #ifndef HELPER_H #define HELPER_H #ifdef STLINK_HAVE_SYS_TIME_H #include #else #include #endif // STLINK_HAVE_SYS_TIME_H #include #include #include uint32_t time_ms(); int32_t arg_parse_freq(const char *str); #endif // HELPER_H stlink-1.9.0/src/stlink-lib/lib_md5.c000066400000000000000000000230371526027543100173550ustar00rootroot00000000000000/* * WjCryptLib_Md5 (https://github.com/WaterJuice/WjCryptLib) * Implementation of MD5 hash function. Originally written by Alexander Peslyak. * Modified by WaterJuice retaining Public Domain license. * This is free and unencumbered software released into the public domain - June 2013 - waterjuice.org */ #include "lib_md5.h" /* INTERNAL FUNCTIONS */ /* F, G, H, I * * The basic MD5 functions. * F and G are optimised compared to their RFC 1321 definitions for architectures * that lack an AND-NOT instruction, just like in Colin Plumb's implementation. */ #define F( x, y, z ) ((z) ^ ((x) & ((y) ^ (z)))) #define G( x, y, z ) ((y) ^ ((z) & ((x) ^ (y)))) #define H( x, y, z ) ((x) ^ (y) ^ (z)) #define I( x, y, z ) ((y) ^ ((x) | ~(z))) /* STEP: The MD5 transformation for all four rounds. */ #define STEP( f, a, b, c, d, x, t, s ) \ (a) += f((b), (c), (d)) + (x) + (t); \ (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \ (a) += (b); /* TransformFunction * This processes one or more 64-byte data blocks, but does NOT update the bit counters. * There are no alignment requirements. */ static void* TransformFunction(Md5Context* ctx, void const* data, uintmax_t size) { uint8_t* ptr; uint32_t a; uint32_t b; uint32_t c; uint32_t d; uint32_t saved_a; uint32_t saved_b; uint32_t saved_c; uint32_t saved_d; #define GET(n) (ctx->block[(n)]) #define SET(n) (ctx->block[(n)] = ((uint32_t) ptr[(n) * 4 + 0] << 0) | \ ((uint32_t) ptr[(n) * 4 + 1] << 8) | \ ((uint32_t) ptr[(n) * 4 + 2] << 16) | \ ((uint32_t) ptr[(n) * 4 + 3] << 24)) ptr = (uint8_t*)data; a = ctx->a; b = ctx->b; c = ctx->c; d = ctx->d; do { saved_a = a; saved_b = b; saved_c = c; saved_d = d; // Round 1 STEP( F, a, b, c, d, SET(0), 0xd76aa478, 7 ) STEP( F, d, a, b, c, SET(1), 0xe8c7b756, 12 ) STEP( F, c, d, a, b, SET(2), 0x242070db, 17 ) STEP( F, b, c, d, a, SET(3), 0xc1bdceee, 22 ) STEP( F, a, b, c, d, SET(4), 0xf57c0faf, 7 ) STEP( F, d, a, b, c, SET(5), 0x4787c62a, 12 ) STEP( F, c, d, a, b, SET(6), 0xa8304613, 17 ) STEP( F, b, c, d, a, SET(7), 0xfd469501, 22 ) STEP( F, a, b, c, d, SET(8 ), 0x698098d8, 7 ) STEP( F, d, a, b, c, SET(9 ), 0x8b44f7af, 12 ) STEP( F, c, d, a, b, SET(10 ), 0xffff5bb1, 17 ) STEP( F, b, c, d, a, SET(11 ), 0x895cd7be, 22 ) STEP( F, a, b, c, d, SET(12 ), 0x6b901122, 7 ) STEP( F, d, a, b, c, SET(13 ), 0xfd987193, 12 ) STEP( F, c, d, a, b, SET(14 ), 0xa679438e, 17 ) STEP( F, b, c, d, a, SET(15 ), 0x49b40821, 22 ) // Round 2 STEP( G, a, b, c, d, GET(1), 0xf61e2562, 5 ) STEP( G, d, a, b, c, GET(6), 0xc040b340, 9 ) STEP( G, c, d, a, b, GET(11), 0x265e5a51, 14 ) STEP( G, b, c, d, a, GET(0), 0xe9b6c7aa, 20 ) STEP( G, a, b, c, d, GET(5), 0xd62f105d, 5 ) STEP( G, d, a, b, c, GET(10), 0x02441453, 9 ) STEP( G, c, d, a, b, GET(15), 0xd8a1e681, 14 ) STEP( G, b, c, d, a, GET(4), 0xe7d3fbc8, 20 ) STEP( G, a, b, c, d, GET(9), 0x21e1cde6, 5 ) STEP( G, d, a, b, c, GET(14), 0xc33707d6, 9 ) STEP( G, c, d, a, b, GET(3), 0xf4d50d87, 14 ) STEP( G, b, c, d, a, GET(8), 0x455a14ed, 20 ) STEP( G, a, b, c, d, GET(13), 0xa9e3e905, 5 ) STEP( G, d, a, b, c, GET(2), 0xfcefa3f8, 9 ) STEP( G, c, d, a, b, GET(7), 0x676f02d9, 14 ) STEP( G, b, c, d, a, GET(12), 0x8d2a4c8a, 20 ) // Round 3 STEP( H, a, b, c, d, GET(5), 0xfffa3942, 4 ) STEP( H, d, a, b, c, GET(8), 0x8771f681, 11 ) STEP( H, c, d, a, b, GET(11), 0x6d9d6122, 16 ) STEP( H, b, c, d, a, GET(14), 0xfde5380c, 23 ) STEP( H, a, b, c, d, GET(1), 0xa4beea44, 4 ) STEP( H, d, a, b, c, GET(4), 0x4bdecfa9, 11 ) STEP( H, c, d, a, b, GET(7), 0xf6bb4b60, 16 ) STEP( H, b, c, d, a, GET(10), 0xbebfbc70, 23 ) STEP( H, a, b, c, d, GET(13), 0x289b7ec6, 4 ) STEP( H, d, a, b, c, GET(0), 0xeaa127fa, 11 ) STEP( H, c, d, a, b, GET(3), 0xd4ef3085, 16 ) STEP( H, b, c, d, a, GET(6), 0x04881d05, 23 ) STEP( H, a, b, c, d, GET(9), 0xd9d4d039, 4 ) STEP( H, d, a, b, c, GET(12), 0xe6db99e5, 11 ) STEP( H, c, d, a, b, GET(15), 0x1fa27cf8, 16 ) STEP( H, b, c, d, a, GET(2), 0xc4ac5665, 23 ) // Round 4 STEP( I, a, b, c, d, GET(0), 0xf4292244, 6 ) STEP( I, d, a, b, c, GET(7), 0x432aff97, 10 ) STEP( I, c, d, a, b, GET(14), 0xab9423a7, 15 ) STEP( I, b, c, d, a, GET(5), 0xfc93a039, 21 ) STEP( I, a, b, c, d, GET(12), 0x655b59c3, 6 ) STEP( I, d, a, b, c, GET(3), 0x8f0ccc92, 10 ) STEP( I, c, d, a, b, GET(10), 0xffeff47d, 15 ) STEP( I, b, c, d, a, GET(1), 0x85845dd1, 21 ) STEP( I, a, b, c, d, GET(8), 0x6fa87e4f, 6 ) STEP( I, d, a, b, c, GET(15), 0xfe2ce6e0, 10 ) STEP( I, c, d, a, b, GET(6), 0xa3014314, 15 ) STEP( I, b, c, d, a, GET(13), 0x4e0811a1, 21 ) STEP( I, a, b, c, d, GET(4), 0xf7537e82, 6 ) STEP( I, d, a, b, c, GET(11), 0xbd3af235, 10 ) STEP( I, c, d, a, b, GET(2), 0x2ad7d2bb, 15 ) STEP( I, b, c, d, a, GET(9), 0xeb86d391, 21 ) a += saved_a; b += saved_b; c += saved_c; d += saved_d; ptr += 64; } while ( size -= 64 ); ctx->a = a; ctx->b = b; ctx->c = c; ctx->d = d; #undef GET #undef SET return (ptr); } /* EXPORTED FUNCTIONS */ /* Md5Initialise * Initialises an MD5 Context. * Use this to initialise/reset a context. */ void Md5Initialise(Md5Context* Context /* [out] */) { Context->a = 0x67452301; Context->b = 0xefcdab89; Context->c = 0x98badcfe; Context->d = 0x10325476; Context->lo = 0; Context->hi = 0; } /* Md5Update * Adds data to the MD5 context. * This will process the data and update the internal state of the context. * Keep on calling this function until all the data has been added. * Then call Md5Finalise to calculate the hash. */ void Md5Update(Md5Context* Context /* [in out] */, void const* Buffer /* [in] */, uint32_t BufferSize /* [in] */) { uint32_t saved_lo; uint32_t used; uint32_t free; saved_lo = Context->lo; if((Context->lo = (saved_lo + BufferSize) & 0x1fffffff) < saved_lo) { Context->hi++; } Context->hi += (uint32_t) (BufferSize >> 29); used = saved_lo & 0x3f; if( used ) { free = 64 - used; if( BufferSize < free ) { memcpy( &Context->buffer[used], Buffer, BufferSize ); return; } memcpy( &Context->buffer[used], Buffer, free ); Buffer = (uint8_t*)Buffer + free; BufferSize -= free; TransformFunction(Context, Context->buffer, 64); } if( BufferSize >= 64 ) { Buffer = TransformFunction( Context, Buffer, BufferSize & ~(uint32_t) 0x3f ); BufferSize &= 0x3f; } memcpy( Context->buffer, Buffer, BufferSize ); } /* Md5Finalise * Performs the final calculation of the hash and returns the digest * (16 byte buffer containing 128bit hash). * After calling this, Md5Initialised must be used to reuse the context. */ void Md5Finalise(Md5Context* Context /* [in out] */, MD5_HASH* Digest /* [in] */) { uint32_t used; uint32_t free; used = Context->lo & 0x3f; Context->buffer[used++] = 0x80; free = 64 - used; if(free < 8) { memset( &Context->buffer[used], 0, free ); TransformFunction( Context, Context->buffer, 64 ); used = 0; free = 64; } memset( &Context->buffer[used], 0, free - 8 ); Context->lo <<= 3; Context->buffer[56] = (uint8_t) (Context->lo); Context->buffer[57] = (uint8_t) (Context->lo >> 8); Context->buffer[58] = (uint8_t) (Context->lo >> 16); Context->buffer[59] = (uint8_t) (Context->lo >> 24); Context->buffer[60] = (uint8_t) (Context->hi); Context->buffer[61] = (uint8_t) (Context->hi >> 8); Context->buffer[62] = (uint8_t) (Context->hi >> 16); Context->buffer[63] = (uint8_t) (Context->hi >> 24); TransformFunction( Context, Context->buffer, 64 ); Digest->bytes[0] = (uint8_t) (Context->a); Digest->bytes[1] = (uint8_t) (Context->a >> 8); Digest->bytes[2] = (uint8_t) (Context->a >> 16); Digest->bytes[3] = (uint8_t) (Context->a >> 24); Digest->bytes[4] = (uint8_t) (Context->b); Digest->bytes[5] = (uint8_t) (Context->b >> 8); Digest->bytes[6] = (uint8_t) (Context->b >> 16); Digest->bytes[7] = (uint8_t) (Context->b >> 24); Digest->bytes[8] = (uint8_t) (Context->c); Digest->bytes[9] = (uint8_t) (Context->c >> 8); Digest->bytes[10] = (uint8_t) (Context->c >> 16); Digest->bytes[11] = (uint8_t) (Context->c >> 24); Digest->bytes[12] = (uint8_t) (Context->d); Digest->bytes[13] = (uint8_t) (Context->d >> 8); Digest->bytes[14] = (uint8_t) (Context->d >> 16); Digest->bytes[15] = (uint8_t) (Context->d >> 24); } /* Md5Calculate * Combines Md5Initialise, Md5Update, and Md5Finalise into one function. * Calculates the MD5 hash of the buffer. */ void Md5Calculate(void const* Buffer /* [in] */, uint32_t BufferSize /* [in] */, MD5_HASH* Digest /* [in] */) { Md5Context context; Md5Initialise( &context ); Md5Update( &context, Buffer, BufferSize ); Md5Finalise( &context, Digest ); } stlink-1.9.0/src/stlink-lib/lib_md5.h000066400000000000000000000036051526027543100173610ustar00rootroot00000000000000/* * WjCryptLib_Md5 (https://github.com/WaterJuice/WjCryptLib) * Implementation of MD5 hash function. Originally written by Alexander Peslyak. * Modified by WaterJuice retaining Public Domain license. * This is free and unencumbered software released into the public domain - June 2013 - waterjuice.org */ #ifndef LIB_MD5_H #define LIB_MD5_H #include #include #include #pragma once /* TYPES */ /* Md5Context * This must be initialised using Md5Initialised. * Do not modify the contents of this structure directly. */ typedef struct { uint32_t lo; uint32_t hi; uint32_t a; uint32_t b; uint32_t c; uint32_t d; uint8_t buffer[64]; uint32_t block[16]; } Md5Context; #define MD5_HASH_SIZE (128 / 8) typedef struct { uint8_t bytes [MD5_HASH_SIZE]; } MD5_HASH; /* PUBLIC FUNCTIONS */ /* Md5Initialise * Initialises an MD5 Context. * Use this to initialise/reset a context. */ void Md5Initialise(Md5Context* Context /* [out] */); /* Md5Update * Adds data to the MD5 context. * This will process the data and update the internal state of the context. * Keep on calling this function until all the data has been added. * Then call Md5Finalise to calculate the hash. */ void Md5Update(Md5Context* Context /* [in out] */, void const* Buffer /* [in] */, uint32_t BufferSize /* [in] */); /* Md5Finalise * Performs the final calculation of the hash and returns the digest * (16 byte buffer containing 128bit hash). * After calling this, Md5Initialised must be used to reuse the context. */ void Md5Finalise(Md5Context* Context /* [in out] */, MD5_HASH* Digest /* [in] */); /* Md5Calculate * Combines Md5Initialise, Md5Update, and Md5Finalise into one function. * Calculates the MD5 hash of the buffer. */ void Md5Calculate(void const* Buffer /* [in] */, uint32_t BufferSize /* [in] */, MD5_HASH* Digest /* [in] */); #endif // LIB_MD5_Hstlink-1.9.0/src/stlink-lib/logging.c000066400000000000000000000057421526027543100174730ustar00rootroot00000000000000/** ****************************************************************************** * @file : logging.c * @brief : UglyLogging logging "framework" * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #define __STDC_WANT_LIB_EXT1__ 1 #include "logging.h" static int32_t max_level = UDEBUG; int32_t ugly_init(int32_t maximum_threshold) { max_level = maximum_threshold; return (0); } int32_t ugly_log(int32_t level, const char *tag, const char *format, ...) { if(level > max_level) { return (0); } fflush(stdout); // flush to maintain order of streams va_list args; va_start(args, format); time_t mytt = time(NULL); struct tm *ptt; #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) // C11 struct tm tt; ptt = &tt; # if defined (_WIN32) || defined(__STDC_LIB_EXT1__) localtime_s(&tt, &mytt); # else localtime_r(&mytt, &tt); # endif #else ptt = localtime(&mytt); #endif fprintf(stderr, "%d-%02d-%02dT%02d:%02d:%02d ", ptt->tm_year + 1900, ptt->tm_mon + 1, ptt->tm_mday, ptt->tm_hour, ptt->tm_min, ptt->tm_sec); switch (level) { case UDEBUG: fprintf(stderr, "DEBUG %s: ", tag); break; case UINFO: fprintf(stderr, "INFO %s: ", tag); break; case UWARN: fprintf(stderr, "WARN %s: ", tag); break; case UERROR: fprintf(stderr, "ERROR %s: ", tag); break; default: fprintf(stderr, "%d %s: ", level, tag); break; } vfprintf(stderr, format, args); fflush(stderr); va_end(args); return (1); } /* * Log message levels. * - LIBUSB_LOG_LEVEL_NONE (0) : no messages ever printed by the library * (default) * - LIBUSB_LOG_LEVEL_ERROR (1) : error messages are printed to stderr * - LIBUSB_LOG_LEVEL_WARNING (2) : warning and error messages are printed to * stderr * - LIBUSB_LOG_LEVEL_INFO (3) : informational messages are printed to * stderr * - LIBUSB_LOG_LEVEL_DEBUG (4) : debug and informational messages are * printed to stderr */ int32_t ugly_libusb_log_level(enum ugly_loglevel v) { #ifdef __FreeBSD__ // FreeBSD includes its own reimplementation of libusb. // Its libusb_set_debug() function expects a lib_debug_level // instead of a lib_log_level and is verbose enough to drown out // all other output. switch (v) { case UDEBUG: return (3); // LIBUSB_DEBUG_FUNCTION + LIBUSB_DEBUG_TRANSFER case UINFO: return (1); // LIBUSB_DEBUG_FUNCTION only case UWARN: return (0); // LIBUSB_DEBUG_NO case UERROR: return (0); // LIBUSB_DEBUG_NO } return (0); #else switch (v) { case UDEBUG: return (4); case UINFO: return (3); case UWARN: return (2); case UERROR: return (1); } return (2); #endif } stlink-1.9.0/src/stlink-lib/logging.h000066400000000000000000000050731526027543100174750ustar00rootroot00000000000000/** ****************************************************************************** * @file : logging.h * @brief : UglyLogging logging "framework" * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #ifndef LOGGING_H #define LOGGING_H #include #include #include #include #include #include "logging_spdlog_wr.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus /* Optional: Enable interface for spdlog to replace UglyLogging */ // #define SPDLOG_LOGGING enum ugly_loglevel { UDEBUG = 90, UINFO = 50, UWARN = 30, UERROR = 20 }; #if defined(__GNUC__) #define PRINTF_ARRT __attribute__ ((format (printf, 3, 4))) #else #define PRINTF_ARRT #endif // __GNUC__ int32_t ugly_init(int32_t maximum_threshold); int32_t ugly_log(int32_t level, const char *tag, const char *format, ...) PRINTF_ARRT; int32_t ugly_libusb_log_level(enum ugly_loglevel v); #define UGLY_LOG_FILE (strstr(__FILE__, "/") != NULL ? \ strrchr(__FILE__, '/') + 1 : strstr(__FILE__, "\\") != NULL ? \ strrchr(__FILE__, '\\') + 1 : __FILE__) // TODO: we need to write this in a more generic way, for now this should compile // on visual studio (See http://stackoverflow.com/a/8673872/1836746) #define DLOG_HELPER(format, ...) ugly_log(UDEBUG, UGLY_LOG_FILE, format, __VA_ARGS__) #define DLOG(...) ugly_log(UDEBUG, UGLY_LOG_FILE, __VA_ARGS__) #define ILOG_HELPER(format, ...) ugly_log(UINFO, UGLY_LOG_FILE, format, __VA_ARGS__) #define ILOG(...) ugly_log(UINFO, UGLY_LOG_FILE, __VA_ARGS__) #define WLOG_HELPER(format, ...) ugly_log(UWARN, UGLY_LOG_FILE, format, __VA_ARGS__) #define WLOG(...) ugly_log(UWARN, UGLY_LOG_FILE, __VA_ARGS__) #define ELOG_HELPER(format, ...) ugly_log(UERROR, UGLY_LOG_FILE, format, __VA_ARGS__) #define ELOG(...) ugly_log(UERROR, UGLY_LOG_FILE, __VA_ARGS__) #if defined(SPDLOG_LOGGING) #undef DLOG_HELPER #undef ILOG_HELPER #undef WLOG_HELPER #undef ELOG_HELPER #define DLOG(...) spdlogLog(UDEBUG, __VA_ARGS__) #define ILOG(...) spdlogLog(UINFO, __VA_ARGS__) #define WLOG(...) spdlogLog(UWARN, __VA_ARGS__) #define ELOG(...) spdlogLog(UERROR, __VA_ARGS__) #endif // SPDLOG_LOGGING #ifdef __cplusplus } #endif // __cplusplus #endif // LOGGING_H stlink-1.9.0/src/stlink-lib/logging_spdlog_wr.h000066400000000000000000000005351526027543100215530ustar00rootroot00000000000000/* * File: logging_spdlog_wr.h * * spdlog: Very fast, header-only/compiled, C++ logging library. * This is a wrapper file for spdlog. */ #ifndef _SPDLOG_WRAPPER_ #define _SPDLOG_WRAPPER_ #ifdef __cplusplus #define EXTERNC extern "C" #else #define EXTERNC #endif EXTERNC int spdlogLog(int level, const char *str, ...); #undef EXTERNC #endifstlink-1.9.0/src/stlink-lib/map_file.c000066400000000000000000000050221526027543100176100ustar00rootroot00000000000000/** ****************************************************************************** * @file : map_file.c * @brief : File mapping * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #include "map_file.h" #include "read_write.h" #ifndef O_BINARY #define O_BINARY 0 #endif // 1 GB max file size #ifndef MAX_FILE_SIZE #define MAX_FILE_SIZE (1U<<30) #endif /* Limit the block size to compare to 0x1800 as anything larger will stall the * STLINK2 Maybe STLINK V1 needs smaller value! */ int32_t check_file(stlink_t *sl, mapped_file_t *mf, stm32_addr_t addr) { uint32_t off; uint32_t n_cmp = sl->flash_pgsz; if(n_cmp > 0x1800) { n_cmp = 0x1800; } for(off = 0; off < mf->len; off += n_cmp) { uint32_t aligned_size; uint32_t cmp_size = n_cmp; // adjust last page size if((off + n_cmp) > mf->len) { cmp_size = mf->len - off; } aligned_size = cmp_size; if(aligned_size & (4 - 1)) { aligned_size = (cmp_size + 4) & ~(4 - 1); } stlink_read_mem32(sl, addr + off, (uint16_t) aligned_size); if(memcmp(sl->q_buf, mf->base + off, cmp_size)) { return (-1); } } return (0); } int32_t map_file(mapped_file_t *mf, const char *path) { int32_t error = -1; struct stat st; const int32_t fd = open(path, O_RDONLY | O_BINARY); if(fd == -1) { fprintf(stderr, "open(%s) == -1\n", path); return (-1); } if(fstat(fd, &st) == -1) { fprintf(stderr, "fstat(%s) == -1\n", path); goto on_error; } if(sizeof(st.st_size) != sizeof(size_t)) { // on 32 bit systems, check if there is an overflow if(st.st_size > (off_t) MAX_FILE_SIZE /*1 GB*/ ) { // limit file size to 1 GB fprintf(stderr, "mmap() uint32_t overflow for file %s\n", path); goto on_error; } } mf->base = (uint8_t *)mmap(NULL, (size_t) (st.st_size), PROT_READ, MAP_SHARED, fd, 0); if(mf->base == MAP_FAILED) { fprintf(stderr, "mmap() == MAP_FAILED for file %s\n", path); goto on_error; } mf->len = (uint32_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; } stlink-1.9.0/src/stlink-lib/map_file.h000066400000000000000000000024061526027543100176200ustar00rootroot00000000000000/** ****************************************************************************** * @file : map_file.h * @brief : File mapping * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #ifndef MAP_FILE_H #define MAP_FILE_H #ifndef O_BINARY #define O_BINARY 0 #endif // O_BINARY #include #include #include #ifdef STLINK_HAVE_SYS_MMAN_H #include // use system-header #else #include // implemented fallback #endif #include #include #include #include /* Memory mapped file */ typedef struct mapped_file { uint8_t *base; uint32_t len; } mapped_file_t; #define MAPPED_FILE_INITIALIZER \ { NULL, 0 } int32_t check_file(stlink_t *, mapped_file_t *, stm32_addr_t); int32_t map_file(mapped_file_t *, const char *); void unmap_file(mapped_file_t *); #endif // MAP_FILE_H stlink-1.9.0/src/stlink-lib/md5.c000066400000000000000000000024001526027543100165160ustar00rootroot00000000000000/** ****************************************************************************** * @file : md5.c * @brief : MD5 hash function * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #include "md5.h" #include "map_file.h" #include "lib_md5.h" 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(int32_t i = 0; i < (int32_t) 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(uint32_t i = 0; i < mp->len; ++i) { sum += mp_byte[i]; } printf("stlink checksum: 0x%08x\n", sum); }stlink-1.9.0/src/stlink-lib/md5.h000066400000000000000000000013341526027543100165300ustar00rootroot00000000000000/** ****************************************************************************** * @file : md5.h * @brief : MD5 hash function * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #ifndef MD5_H #define MD5_H #include #include #include #include "map_file.h" void md5_calculate(mapped_file_t *); void stlink_checksum(mapped_file_t *); #endif // MD5_Hstlink-1.9.0/src/stlink-lib/option_bytes.c000066400000000000000000001025221526027543100205550ustar00rootroot00000000000000/** ****************************************************************************** * @file : option_bytes.c * @brief : Read and write option bytes and option control registers * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #include "option_bytes.h" #include "common_flash.h" #include "flash_loader.h" #include "logging.h" #include "map_file.h" #include "md5.h" #include "read_write.h" /** * Read option control register C0 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ static int32_t stlink_read_option_control_register_c0(stlink_t *sl, uint32_t *option_byte) { return stlink_read_debug32(sl, STM32_FLASH_C0_OPTR, option_byte); } /** * Read option bytes C0 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ static int32_t stlink_read_option_bytes_c0(stlink_t *sl, uint32_t *option_byte) { return stlink_read_option_control_register_c0(sl, option_byte); } /** * Write option control register C0 * @param sl * @param option_cr * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_control_register_c0(stlink_t *sl, uint32_t option_cr) { int32_t ret = 0; clear_flash_error(sl); if((ret = stlink_write_debug32(sl, STM32_FLASH_C0_OPTR, option_cr))) return ret; wait_flash_busy(sl); uint32_t cr_reg = (1 << STM32_FLASH_C0_CR_OPTSTRT); if((ret = stlink_write_debug32(sl, STM32_FLASH_C0_CR, cr_reg))) return ret; wait_flash_busy(sl); if((ret = check_flash_error(sl))) return ret; // trigger the load of option bytes into option registers cr_reg = (1 << STM32_FLASH_C0_CR_OBL_LAUNCH); stlink_write_debug32(sl, STM32_FLASH_C0_CR, cr_reg); return ret; } /** * Write option bytes C0 * @param sl * @param addr of the memory mapped option bytes * @param base option bytes * @param len of option bytes * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_bytes_c0(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) { (void)addr; (void)len; return stlink_write_option_control_register_c0(sl, *(uint32_t*)base); } /** * Read option control register F0 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_control_register_f0(stlink_t *sl, uint32_t *option_byte) { DLOG("@@@@ Read option control register byte from %#10x\n", FLASH_OBR); return stlink_read_debug32(sl, FLASH_OBR, option_byte); } /** * Write option bytes F0 * @param sl * @param addr of the memory mapped option bytes * @param base option bytes * @param len of option bytes * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_bytes_f0(stlink_t *sl, stm32_addr_t addr, uint8_t* base, uint32_t len) { int32_t ret = 0; if(len < 12 || addr != STM32_OPTION_BYTES_BASE_F0) { WLOG("Only full write of option bytes area is supported\n"); return -1; } clear_flash_error(sl); WLOG("Erasing option bytes\n"); /* erase option bytes */ stlink_write_debug32(sl, FLASH_CR, (1 << FLASH_CR_OPTER) | (1 << FLASH_CR_OPTWRE)); ret = stlink_write_debug32(sl, FLASH_CR, (1 << FLASH_CR_OPTER) | (1 << FLASH_CR_STRT) | (1 << FLASH_CR_OPTWRE)); if(ret) { return ret; } wait_flash_busy(sl); ret = check_flash_error(sl); if(ret) { return ret; } WLOG("Writing option bytes to %#10x\n", addr); /* Set the Option PG bit to enable programming */ stlink_write_debug32(sl, FLASH_CR, (1 << FLASH_CR_OPTPG) | (1 << FLASH_CR_OPTWRE)); /* Use flash loader for write OP * because flash memory writable by half word */ flash_loader_t fl; ret = stlink_flash_loader_init(sl, &fl); if(ret) { return ret; } ret = stlink_flash_loader_run(sl, &fl, addr, base, len); if(ret) { return ret; } /* Reload option bytes */ stlink_write_debug32(sl, FLASH_CR, (1 << FLASH_CR_OBL_LAUNCH)); return check_flash_error(sl); } /** * Write option control register F0 * @param sl * @param option_cr * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_control_register_f0(stlink_t *sl, uint32_t option_cr) { int32_t ret = 0; uint16_t opt_val[8]; uint32_t protection, optiondata; uint16_t user_options, user_data, rdp; uint32_t option_offset, user_data_offset; ILOG("Asked to write option control register %#10x to %#010x.\n", option_cr, FLASH_OBR); /* Clear errors */ clear_flash_error(sl); /* Retrieve current values */ ret = stlink_read_debug32(sl, FLASH_OBR, &optiondata); if(ret) { return ret; } ret = stlink_read_debug32(sl, FLASH_WRPR, &protection); if(ret) { return ret; } /* Translate OBR value to flash store structure * F0: RM0091, Option byte description, pp. 75-78 * F1: PM0075, Option byte description, pp. 19-22 * F3: RM0316, Option byte description, pp. 85-87 */ switch(sl->chip_id) { case 0x422: /* STM32F30x */ case 0x432: /* STM32F37x */ case 0x438: /* STM32F303x6/8 and STM32F328 */ case 0x446: /* STM32F303xD/E and STM32F398xE */ case 0x439: /* STM32F302x6/8 */ case 0x440: /* STM32F05x */ case 0x444: /* STM32F03x */ case 0x445: /* STM32F04x */ case 0x448: /* STM32F07x */ case 0x442: /* STM32F09x */ option_offset = 6; user_data_offset = 16; rdp = 0x55AA; break; default: option_offset = 0; user_data_offset = 10; rdp = 0x5AA5; break; } user_options = (option_cr >> option_offset >> 2) & 0xFFFF; user_data = (option_cr >> user_data_offset) & 0xFFFF; #define VAL_WITH_COMPLEMENT(v) (uint16_t) (((v)&0xFF) | (((~(v))<<8)&0xFF00)) opt_val[0] = (option_cr & (1 << 1/*OPT_READOUT*/)) ? 0xFFFF : rdp; opt_val[1] = VAL_WITH_COMPLEMENT(user_options); opt_val[2] = VAL_WITH_COMPLEMENT(user_data); opt_val[3] = VAL_WITH_COMPLEMENT(user_data >> 8); opt_val[4] = VAL_WITH_COMPLEMENT(protection); opt_val[5] = VAL_WITH_COMPLEMENT(protection >> 8); opt_val[6] = VAL_WITH_COMPLEMENT(protection >> 16); opt_val[7] = VAL_WITH_COMPLEMENT(protection >> 24); #undef VAL_WITH_COMPLEMENT /* Write bytes and check errors */ ret = stlink_write_option_bytes_f0(sl, STM32_OPTION_BYTES_BASE_F0, (uint8_t*)opt_val, sizeof(opt_val)); if(ret) return ret; ret = check_flash_error(sl); if(!ret) { ILOG("Wrote option bytes %#010x to %#010x!\n", option_cr, FLASH_OBR); } return ret; } /** * Read option control register F2 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_control_register_f2(stlink_t *sl, uint32_t *option_byte) { return stlink_read_debug32(sl, STM32_FLASH_F2_OPT_CR, option_byte); } /** * Read option bytes F2 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_bytes_f2(stlink_t *sl, uint32_t *option_byte) { return stlink_read_option_control_register_f2(sl, option_byte); } /** * Read option control register F4 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_control_register_f4(stlink_t *sl, uint32_t *option_byte) { return stlink_read_debug32(sl, STM32_FLASH_F4_OPTCR, option_byte); } /** * Read option bytes F4 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_bytes_f4(stlink_t *sl, uint32_t *option_byte) { return stlink_read_option_control_register_f4(sl, option_byte); } /** * Write option bytes F4 * @param sl * @param addr of the memory mapped option bytes * @param base option bytes * @param len of option bytes * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_bytes_f4(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) { uint32_t option_byte; int32_t ret = 0; (void)addr; (void)len; // Clear errors clear_flash_error(sl); write_uint32((unsigned char *)&option_byte, *(uint32_t *)(base)); // write option byte, ensuring we dont lock opt, and set strt bit stlink_write_debug32(sl, STM32_FLASH_F4_OPTCR, (option_byte & ~(1 << STM32_FLASH_F4_OPTCR_LOCK)) | (1 << STM32_FLASH_F4_OPTCR_START)); wait_flash_busy(sl); ret = check_flash_error(sl); // option bytes are reloaded at reset only, no obl. */ return (ret); } /** * Read option bytes F7 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ // Since multiple bytes can be read, we read and print32_t all, but one here // and then return the last one just like other devices. int32_t stlink_read_option_bytes_f7(stlink_t *sl, uint32_t *option_byte) { int32_t err = -1; for(uint32_t counter = 0; counter < (sl->option_size / 4 - 1); counter++) { err = stlink_read_debug32(sl, sl->option_base + counter * sizeof(uint32_t), option_byte); if(err == -1) { return err; } else { printf("%08x\n", *option_byte); } } return stlink_read_debug32( sl, sl->option_base + (uint32_t) (sl->option_size / 4 - 1) * sizeof(uint32_t), option_byte); } /** * Write option bytes F7 * @param sl * @param addr of the memory mapped option bytes * @param base option bytes * @param len of option bytes * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_bytes_f7(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) { uint32_t option_byte; int32_t ret = 0; // Clear errors clear_flash_error(sl); ILOG("Asked to write option byte %#10x to %#010x.\n", *(uint32_t *)(base), addr); write_uint32((unsigned char *)&option_byte, *(uint32_t *)(base)); ILOG("Write %d option bytes %#010x to %#010x!\n", len, option_byte, addr); if(addr == 0) { addr = STM32_FLASH_F7_OPTCR; ILOG("No address provided, using %#10x\n", addr); } if(addr == STM32_FLASH_F7_OPTCR) { /* write option byte, ensuring we dont lock opt, and set strt bit */ stlink_write_debug32(sl, STM32_FLASH_F7_OPTCR, (option_byte & ~(1 << STM32_FLASH_F7_OPTCR_LOCK)) | (1 << STM32_FLASH_F7_OPTCR_START)); } else if(addr == STM32_FLASH_F7_OPTCR1) { // Read STM32_FLASH_F7_OPTCR uint32_t oldvalue; stlink_read_debug32(sl, STM32_FLASH_F7_OPTCR, &oldvalue); /* write option byte */ stlink_write_debug32(sl, STM32_FLASH_F7_OPTCR1, option_byte); // Write STM32_FLASH_F7_OPTCR lock and start address stlink_write_debug32(sl, STM32_FLASH_F7_OPTCR, (oldvalue & ~(1 << STM32_FLASH_F7_OPTCR_LOCK)) | (1 << STM32_FLASH_F7_OPTCR_START)); } else { WLOG("WIP: write %#010x to address %#010x\n", option_byte, addr); stlink_write_debug32(sl, addr, option_byte); } wait_flash_busy(sl); ret = check_flash_error(sl); if(!ret) ILOG("Wrote %d option bytes %#010x to %#010x!\n", len, *(uint32_t *)base, addr); /* option bytes are reloaded at reset only, no obl. */ return ret; } /** * Read option control register F7 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_control_register_f7(stlink_t *sl, uint32_t *option_byte) { DLOG("@@@@ Read option control register byte from %#10x\n", STM32_FLASH_F7_OPTCR); return stlink_read_debug32(sl, STM32_FLASH_F7_OPTCR, option_byte); } /** * Write option control register F7 * @param sl * @param option_cr * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_control_register_f7(stlink_t *sl, uint32_t option_cr) { int32_t ret = 0; // Clear errors clear_flash_error(sl); ILOG("Asked to write option control register 1 %#10x to %#010x.\n", option_cr, STM32_FLASH_F7_OPTCR); /* write option byte, ensuring we dont lock opt, and set strt bit */ stlink_write_debug32(sl, STM32_FLASH_F7_OPTCR, (option_cr & ~(1 << STM32_FLASH_F7_OPTCR_LOCK)) | (1 << STM32_FLASH_F7_OPTCR_START)); wait_flash_busy(sl); ret = check_flash_error(sl); if(!ret) ILOG("Wrote option bytes %#010x to %#010x!\n", option_cr, STM32_FLASH_F7_OPTCR); return ret; } /** * Read option control register1 F7 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_control_register1_f7(stlink_t *sl, uint32_t *option_byte) { DLOG("@@@@ Read option control register 1 byte from %#10x\n", STM32_FLASH_F7_OPTCR1); return stlink_read_debug32(sl, STM32_FLASH_F7_OPTCR1, option_byte); } /** * Write option control register1 F7 * @param sl * @param option_cr1 * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_control_register1_f7(stlink_t *sl, uint32_t option_cr1) { int32_t ret = 0; // Clear errors clear_flash_error(sl); ILOG("Asked to write option control register 1 %#010x to %#010x.\n", option_cr1, STM32_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, STM32_FLASH_F7_OPTCR, ¤t_control_register_value); /* write option byte */ stlink_write_debug32(sl, STM32_FLASH_F7_OPTCR1, option_cr1); stlink_write_debug32( sl, STM32_FLASH_F7_OPTCR, (current_control_register_value & ~(1 << STM32_FLASH_F7_OPTCR_LOCK)) | (1 << STM32_FLASH_F7_OPTCR_START)); wait_flash_busy(sl); ret = check_flash_error(sl); if(!ret) ILOG("Wrote option bytes %#010x to %#010x!\n", option_cr1, STM32_FLASH_F7_OPTCR1); return ret; } /** * Read option bytes boot address F7 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_bytes_boot_add_f7(stlink_t *sl, uint32_t *option_byte) { DLOG("@@@@ Read option byte boot address\n"); return stlink_read_option_control_register1_f7(sl, option_byte); } /** * Write option bytes boot address F7 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_bytes_boot_add_f7(stlink_t *sl, uint32_t option_byte_boot_add) { ILOG("Asked to write option byte boot add %#010x.\n", option_byte_boot_add); return stlink_write_option_control_register1_f7(sl, option_byte_boot_add); } /** * Read option control register Gx * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_control_register_gx(stlink_t *sl, uint32_t *option_byte) { return stlink_read_debug32(sl, STM32_FLASH_Gx_OPTR, option_byte); } /** * Read option bytes Gx * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_bytes_gx(stlink_t *sl, uint32_t *option_byte) { return stlink_read_option_control_register_gx(sl, option_byte); } /** * Write option bytes Gx * @param sl * @param addr of the memory mapped option bytes * @param base option bytes * @param len of option bytes * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_bytes_gx(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) { /* Write options bytes */ uint32_t val; int32_t ret = 0; (void)len; uint32_t data; clear_flash_error(sl); write_uint32((unsigned char *)&data, *(uint32_t *)(base)); WLOG("Writing option bytes %#10x to %#10x\n", data, addr); stlink_write_debug32(sl, STM32_FLASH_Gx_OPTR, data); // Set Options Start bit stlink_read_debug32(sl, STM32_FLASH_Gx_CR, &val); val |= (1 << STM32_FLASH_Gx_CR_OPTSTRT); stlink_write_debug32(sl, STM32_FLASH_Gx_CR, val); wait_flash_busy(sl); ret = check_flash_error(sl); // Reload options stlink_read_debug32(sl, STM32_FLASH_Gx_CR, &val); val |= (1 << STM32_FLASH_Gx_CR_OBL_LAUNCH); stlink_write_debug32(sl, STM32_FLASH_Gx_CR, val); return (ret); } /** * Write option bytes H7 * @param sl * @param addr of the memory mapped option bytes * @param base option bytes * @param len of option bytes * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_bytes_h7(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) { uint32_t val; uint32_t data; // Wait until previous flash option has completed wait_flash_busy(sl); // Clear previous error stlink_write_debug32(sl, STM32_FLASH_H7_OPTCCR, 1 << STM32_FLASH_H7_OPTCCR_CLR_OPTCHANGEERR); while (len != 0) { switch (addr) { case STM32_FLASH_H7_REGS_ADDR + 0x20: // FLASH_OPTSR_PRG case STM32_FLASH_H7_REGS_ADDR + 0x2c: // FLASH_PRAR_PRG1 case STM32_FLASH_H7_REGS_ADDR + 0x34: // FLASH_SCAR_PRG1 case STM32_FLASH_H7_REGS_ADDR + 0x3c: // FLASH_WPSN_PRG1 case STM32_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, STM32_FLASH_H7_OPTCR, &val); val |= (1 << STM32_FLASH_H7_OPTCR_OPTSTART); stlink_write_debug32(sl, STM32_FLASH_H7_OPTCR, val); /* Wait for the option bytes modification to complete */ do { stlink_read_debug32(sl, STM32_FLASH_H7_OPTSR_CUR, &val); } while ((val & (1 << STM32_FLASH_H7_OPTSR_OPT_BUSY)) != 0); /* Check for errors */ if((val & (1 << STM32_FLASH_H7_OPTSR_OPTCHANGEERR)) != 0) { stlink_write_debug32(sl, STM32_FLASH_H7_OPTCCR, 1 << STM32_FLASH_H7_OPTCCR_CLR_OPTCHANGEERR); return -1; } break; default: /* Skip non-programmable registers */ break; } len -= 4; addr += 4; base += 4; } return 0; } /** * Write option bytes L0 * @param sl * @param addr of the memory mapped option bytes * @param base option bytes * @param len of option bytes * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_bytes_l0(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) { uint32_t flash_base = get_stm32l0_flash_base(sl); uint32_t val; uint32_t data; int32_t ret = 0; // Clear errors clear_flash_error(sl); while (len != 0) { write_uint32((unsigned char *)&data, *(uint32_t *)(base)); // write options bytes WLOG("Writing option bytes %#10x to %#10x\n", data, addr); stlink_write_debug32(sl, addr, data); wait_flash_busy(sl); if((ret = check_flash_error(sl))) { break; } len -= 4; addr += 4; base += 4; } // Reload options stlink_read_debug32(sl, flash_base + FLASH_PECR_OFF, &val); val |= (1 << STM32_FLASH_L0_OBL_LAUNCH); stlink_write_debug32(sl, flash_base + FLASH_PECR_OFF, val); return (ret); } /** * Write option bytes L4 * @param sl * @param addr of the memory mapped option bytes * @param base option bytes * @param len of option bytes * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_bytes_l4(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) { uint32_t val; int32_t ret = 0; (void)addr; (void)len; // Clear errors clear_flash_error(sl); // write options bytes uint32_t data; write_uint32((unsigned char *)&data, *(uint32_t *)(base)); WLOG("Writing option bytes 0x%04x\n", data); stlink_write_debug32(sl, STM32_FLASH_L4_OPTR, data); // set options start bit stlink_read_debug32(sl, STM32_FLASH_L4_CR, &val); val |= (1 << STM32_FLASH_L4_CR_OPTSTRT); stlink_write_debug32(sl, STM32_FLASH_L4_CR, val); wait_flash_busy(sl); ret = check_flash_error(sl); // apply options bytes immediate stlink_read_debug32(sl, STM32_FLASH_L4_CR, &val); val |= (1 << STM32_FLASH_L4_CR_OBL_LAUNCH); stlink_write_debug32(sl, STM32_FLASH_L4_CR, val); return (ret); } /** * Write option bytes WB * @param sl * @param addr of the memory mapped option bytes * @param base option bytes * @param len of option bytes * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_bytes_wb(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) { /* Write options bytes */ uint32_t val; int32_t ret = 0; (void)len; uint32_t data; clear_flash_error(sl); while (len != 0) { write_uint32((unsigned char *)&data, *(uint32_t *)(base)); // write options bytes WLOG("Writing option bytes %#10x to %#10x\n", data, addr); stlink_write_debug32(sl, addr, data); wait_flash_busy(sl); if((ret = check_flash_error(sl))) { break; } len -= 4; addr += 4; base += 4; } // Set Options Start bit stlink_read_debug32(sl, STM32_FLASH_WB_CR, &val); val |= (1 << STM32_FLASH_WB_CR_OPTSTRT); stlink_write_debug32(sl, STM32_FLASH_WB_CR, val); wait_flash_busy(sl); ret = check_flash_error(sl); // Reload options stlink_read_debug32(sl, STM32_FLASH_WB_CR, &val); val |= (1 << STM32_FLASH_WB_CR_OBL_LAUNCH); stlink_write_debug32(sl, STM32_FLASH_WB_CR, val); return (ret); } /** * Write option bytes L5 * @param sl * @param addr of the memory mapped option bytes * @param base option bytes * @param len of option bytes * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_bytes_l5(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) { /* Write options bytes */ uint32_t val; int32_t ret = 0; (void)len; uint32_t data; clear_flash_error(sl); while (len != 0) { write_uint32((unsigned char *)&data, *(uint32_t *)(base)); // write options bytes WLOG("Writing option bytes %#10x to %#10x\n", data, addr); stlink_write_debug32(sl, addr, data); wait_flash_busy(sl); if ((ret = check_flash_error(sl))) { break; } len -= 4; addr += 4; base += 4; } // Set Options Start bit stlink_read_debug32(sl, STM32_FLASH_L5_NSCR, &val); val |= (1 << STM32_FLASH_L5_NSCR_NSOPTSTRT); stlink_write_debug32(sl, STM32_FLASH_L5_NSCR, val); wait_flash_busy(sl); ret = check_flash_error(sl); // Reload options stlink_read_debug32(sl, STM32_FLASH_L5_NSCR, &val); val |= (1 << STM32_FLASH_L5_NSCR_OBL_LAUNCH); stlink_write_debug32(sl, STM32_FLASH_L5_NSCR, val); return (ret); } /** * Read option control register WB * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_control_register_wb(stlink_t *sl, uint32_t *option_byte) { DLOG("@@@@ Read option control register byte from %#10x\n", STM32_FLASH_WB_OPTR); return stlink_read_debug32(sl, STM32_FLASH_WB_OPTR, option_byte); } /** * Write option control register WB * @param sl * @param option_cr * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_control_register_wb(stlink_t *sl, uint32_t option_cr) { int32_t ret = 0; // Clear errors clear_flash_error(sl); ILOG("Asked to write option control register 1 %#10x to %#010x.\n", option_cr, STM32_FLASH_WB_OPTR); /* write option byte, ensuring we dont lock opt, and set strt bit */ stlink_write_debug32(sl, STM32_FLASH_WB_OPTR, option_cr); wait_flash_busy(sl); // Set Options Start bit uint32_t val = (1 << STM32_FLASH_WB_CR_OPTSTRT); stlink_write_debug32(sl, STM32_FLASH_WB_CR, val); wait_flash_busy(sl); ret = check_flash_error(sl); if(!ret) ILOG("Wrote option bytes %#010x to %#010x!\n", option_cr, STM32_FLASH_WB_OPTR); return ret; } /** * Read option bytes generic * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_bytes_generic(stlink_t *sl, uint32_t *option_byte) { DLOG("@@@@ Read option bytes boot address from %#10x\n", sl->option_base); return stlink_read_debug32(sl, sl->option_base, option_byte); } /** * Write option bytes * @param sl * @param addr of the memory mapped option bytes * @param base option bytes * @param len of option bytes * @return 0 on success, -ve on failure. */ int32_t stlink_write_option_bytes(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) { int32_t ret = -1; if(sl->option_base == 0) { ELOG("Option bytes writing is currently not supported for connected chip\n"); return (-1); } if((addr < sl->option_base) || addr > sl->option_base + sl->option_size) { ELOG("Option bytes start address out of Option bytes range\n"); return (-1); } if(addr + len > sl->option_base + sl->option_size) { ELOG("Option bytes data too long\n"); return (-1); } wait_flash_busy(sl); if(unlock_flash_if(sl)) { ELOG("Flash unlock failed! System reset required to be able to unlock it again!\n"); return (-1); } if(unlock_flash_option_if(sl)) { ELOG("Flash option unlock failed!\n"); return (-1); } switch (sl->flash_type) { case STM32_FLASH_TYPE_C0: ret = stlink_write_option_bytes_c0(sl, addr, base, len); break; case STM32_FLASH_TYPE_F0_F1_F3: case STM32_FLASH_TYPE_F1_XL: ret = stlink_write_option_bytes_f0(sl, addr, base, len); break; case STM32_FLASH_TYPE_F2_F4: ret = stlink_write_option_bytes_f4(sl, addr, base, len); break; case STM32_FLASH_TYPE_F7: ret = stlink_write_option_bytes_f7(sl, addr, base, len); break; case STM32_FLASH_TYPE_L0_L1: ret = stlink_write_option_bytes_l0(sl, addr, base, len); break; case STM32_FLASH_TYPE_L4: ret = stlink_write_option_bytes_l4(sl, addr, base, len); break; case STM32_FLASH_TYPE_G0: case STM32_FLASH_TYPE_G4: ret = stlink_write_option_bytes_gx(sl, addr, base, len); break; case STM32_FLASH_TYPE_H7: ret = stlink_write_option_bytes_h7(sl, addr, base, len); break; case STM32_FLASH_TYPE_WB_WL: ret = stlink_write_option_bytes_wb(sl, addr, base, len); break; case STM32_FLASH_TYPE_L5_U5: ret = stlink_write_option_bytes_l5(sl, addr, base, len); break; default: ELOG("Option bytes writing is currently not implemented for connected chip\n"); break; } if(ret) { ELOG("Flash option write failed!\n"); } else { ILOG("Wrote %d option bytes to %#010x!\n", len, addr); } /* Re-lock flash. */ lock_flash_option(sl); lock_flash(sl); return ret; } /** * Write the given binary file with option bytes * @param sl * @param path readable file path, should be binary image * @param addr of the memory mapped option bytes * @return 0 on success, -ve on failure. */ int32_t stlink_fwrite_option_bytes(stlink_t *sl, const char *path, stm32_addr_t addr) { /* Write the file in flash at addr */ int32_t err; mapped_file_t mf = MAPPED_FILE_INITIALIZER; if(map_file(&mf, path) == -1) { ELOG("map_file() == -1\n"); return (-1); } printf("file %s ", path); md5_calculate(&mf); stlink_checksum(&mf); err = stlink_write_option_bytes(sl, addr, mf.base, (uint32_t) mf.len); stlink_fwrite_finalize(sl, addr); unmap_file(&mf); return (err); } /** * Read option control register 32 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_control_register32(stlink_t *sl, uint32_t *option_byte) { if(sl->option_base == 0) { ELOG("Option bytes read is currently not supported for connected chip\n"); return -1; } switch (sl->flash_type) { case STM32_FLASH_TYPE_C0: return stlink_read_option_control_register_c0(sl, option_byte); case STM32_FLASH_TYPE_F0_F1_F3: case STM32_FLASH_TYPE_F1_XL: return stlink_read_option_control_register_f0(sl, option_byte); case STM32_FLASH_TYPE_F7: return stlink_read_option_control_register_f7(sl, option_byte); case STM32_FLASH_TYPE_WB_WL: return stlink_read_option_control_register_wb(sl, option_byte); default: return -1; } } /** * Write option control register 32 * @param sl * @param option_cr * @return 0 on success, -ve on failure. */ int32_t stlink_write_option_control_register32(stlink_t *sl, uint32_t option_cr) { int32_t ret = -1; wait_flash_busy(sl); if(unlock_flash_if(sl)) { ELOG("Flash unlock failed! System reset required to be able to unlock it again!\n"); return -1; } if(unlock_flash_option_if(sl)) { ELOG("Flash option unlock failed!\n"); return -1; } switch (sl->flash_type) { case STM32_FLASH_TYPE_C0: ret = stlink_write_option_control_register_c0(sl, option_cr); break; case STM32_FLASH_TYPE_F0_F1_F3: case STM32_FLASH_TYPE_F1_XL: ret = stlink_write_option_control_register_f0(sl, option_cr); break; case STM32_FLASH_TYPE_F7: ret = stlink_write_option_control_register_f7(sl, option_cr); break; case STM32_FLASH_TYPE_WB_WL: ret = stlink_write_option_control_register_wb(sl, option_cr); break; default: ELOG("Option control register writing is currently not implemented for connected chip\n"); break; } if(ret) ELOG("Flash option write failed!\n"); else ILOG("Wrote option control register %#010x!\n", option_cr); /* Re-lock flash. */ lock_flash_option(sl); lock_flash(sl); return ret; } /** * Read option control register1 32 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_control_register1_32(stlink_t *sl, uint32_t *option_byte) { if(sl->option_base == 0) { ELOG("Option bytes read is currently not supported for connected chip\n"); return -1; } switch (sl->flash_type) { case STM32_FLASH_TYPE_F7: return stlink_read_option_control_register1_f7(sl, option_byte); default: return -1; // return stlink_read_option_control_register1_generic(sl, option_byte); } } /** * Write option control register1 32 * @param sl * @param option_cr * @return 0 on success, -ve on failure. */ int32_t stlink_write_option_control_register1_32(stlink_t *sl, uint32_t option_cr1) { int32_t ret = -1; wait_flash_busy(sl); if(unlock_flash_if(sl)) { ELOG("Flash unlock failed! System reset required to be able to unlock it again!\n"); return -1; } if(unlock_flash_option_if(sl)) { ELOG("Flash option unlock failed!\n"); return -1; } switch (sl->flash_type) { case STM32_FLASH_TYPE_F7: ret = stlink_write_option_control_register1_f7(sl, option_cr1); break; default: ELOG("Option control register 1 writing is currently not implemented for " "connected chip\n"); break; } if(ret) ELOG("Flash option write failed!\n"); else ILOG("Wrote option control register 1 %#010x!\n", option_cr1); lock_flash_option(sl); lock_flash(sl); return (ret); } /** * Read option bytes 32 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_bytes32(stlink_t *sl, uint32_t *option_byte) { if(sl->option_base == 0) { ELOG("Option bytes read is currently not supported for connected chip\n"); return (-1); } switch (sl->chip_id) { case STM32_CHIPID_C011xx: case STM32_CHIPID_C031xx: case STM32_CHIPID_C051xx: case STM32_CHIPID_C071xx: case STM32_CHIPID_C091xx_C92xx: return stlink_read_option_bytes_c0(sl, option_byte); case STM32_CHIPID_F2: return stlink_read_option_bytes_f2(sl, option_byte); case STM32_CHIPID_F4: case STM32_CHIPID_F446: return stlink_read_option_bytes_f4(sl, option_byte); case STM32_CHIPID_F76xxx: return stlink_read_option_bytes_f7(sl, option_byte); case STM32_CHIPID_G0_CAT1: case STM32_CHIPID_G0_CAT2: case STM32_CHIPID_G4_CAT2: case STM32_CHIPID_G4_CAT3: case STM32_CHIPID_G4_CAT4: return stlink_read_option_bytes_gx(sl, option_byte); default: return stlink_read_option_bytes_generic(sl, option_byte); } } /** * Write option bytes 32 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_write_option_bytes32(stlink_t *sl, uint32_t option_byte) { WLOG("About to write option byte %#10x to %#10x.\n", option_byte, sl->option_base); return stlink_write_option_bytes(sl, sl->option_base, (uint8_t *)&option_byte, 4); } /** * Read option bytes boot address 32 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_bytes_boot_add32(stlink_t *sl, uint32_t *option_byte) { if(sl->option_base == 0) { ELOG("Option bytes boot address read is currently not supported for connected chip\n"); return -1; } switch (sl->flash_type) { case STM32_FLASH_TYPE_F7: return stlink_read_option_bytes_boot_add_f7(sl, option_byte); default: return -1; // return stlink_read_option_bytes_boot_add_generic(sl, option_byte); } } /** * Write option bytes boot address 32 * @param sl * @param option_bytes_boot_add * @return 0 on success, -ve on failure. */ int32_t stlink_write_option_bytes_boot_add32(stlink_t *sl, uint32_t option_bytes_boot_add) { int32_t ret = -1; wait_flash_busy(sl); if(unlock_flash_if(sl)) { ELOG("Flash unlock failed! System reset required to be able to unlock it again!\n"); return -1; } if(unlock_flash_option_if(sl)) { ELOG("Flash option unlock failed!\n"); return -1; } switch (sl->flash_type) { case STM32_FLASH_TYPE_F7: ret = stlink_write_option_bytes_boot_add_f7(sl, option_bytes_boot_add); break; default: ELOG("Option bytes boot address writing is currently not implemented for connected chip\n"); break; } if(ret) ELOG("Flash option write failed!\n"); else ILOG("Wrote option bytes boot address %#010x!\n", option_bytes_boot_add); /* Re-lock flash. */ lock_flash_option(sl); lock_flash(sl); return ret; } stlink-1.9.0/src/stlink-lib/option_bytes.h000066400000000000000000000076141526027543100205700ustar00rootroot00000000000000/** ****************************************************************************** * @file : option_bytes.h * @brief : Read and write option bytes and option control registers * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #ifndef OPTION_BYTES_H #define OPTION_BYTES_H #include #include #include #include int32_t stlink_read_option_control_register_f0(stlink_t *sl, uint32_t *option_byte); // static int32_t stlink_write_option_bytes_f0(stlink_t *sl, stm32_addr_t addr, uint8_t* base, uint32_t len); // static int32_t stlink_write_option_control_register_f0(stlink_t *sl, uint32_t option_cr); int32_t stlink_read_option_control_register_f2(stlink_t *sl, uint32_t *option_byte); int32_t stlink_read_option_bytes_f2(stlink_t *sl, uint32_t *option_byte); int32_t stlink_read_option_control_register_f4(stlink_t *sl, uint32_t *option_byte); int32_t stlink_read_option_bytes_f4(stlink_t *sl, uint32_t *option_byte); // static int32_t stlink_write_option_bytes_f4(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len); int32_t stlink_read_option_bytes_f7(stlink_t *sl, uint32_t *option_byte); // static int32_t stlink_write_option_bytes_f7(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len); int32_t stlink_read_option_control_register_f7(stlink_t *sl, uint32_t *option_byte); // static int32_t stlink_write_option_control_register_f7(stlink_t *sl, uint32_t option_cr); int32_t stlink_read_option_control_register1_f7(stlink_t *sl, uint32_t *option_byte); // static int32_t stlink_write_option_control_register1_f7(stlink_t *sl, uint32_t option_cr1); int32_t stlink_read_option_bytes_boot_add_f7(stlink_t *sl, uint32_t *option_byte); // static int32_t stlink_write_option_bytes_boot_add_f7(stlink_t *sl, uint32_t option_byte_boot_add); int32_t stlink_read_option_control_register_gx(stlink_t *sl, uint32_t *option_byte); int32_t stlink_read_option_bytes_gx(stlink_t *sl, uint32_t *option_byte); // static int32_t stlink_write_option_bytes_gx(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len); // static int32_t stlink_write_option_bytes_h7(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len); // static int32_t stlink_write_option_bytes_l0(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len); // static int32_t stlink_write_option_bytes_l4(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len); // static int32_t stlink_write_option_bytes_wb(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len); int32_t stlink_read_option_control_register_wb(stlink_t *sl, uint32_t *option_byte); // static int32_t stlink_write_option_control_register_wb(stlink_t *sl, uint32_t option_cr); int32_t stlink_read_option_bytes_generic(stlink_t *sl, uint32_t *option_byte); int32_t stlink_write_option_bytes(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len); int32_t stlink_fwrite_option_bytes(stlink_t *sl, const char *path, stm32_addr_t addr); int32_t stlink_read_option_control_register32(stlink_t *sl, uint32_t *option_byte); int32_t stlink_write_option_control_register32(stlink_t *sl, uint32_t option_cr); int32_t stlink_read_option_control_register1_32(stlink_t *sl, uint32_t *option_byte); int32_t stlink_write_option_control_register1_32(stlink_t *sl, uint32_t option_cr1); int32_t stlink_read_option_bytes32(stlink_t *sl, uint32_t* option_byte); int32_t stlink_write_option_bytes32(stlink_t *sl, uint32_t option_byte); int32_t stlink_read_option_bytes_boot_add32(stlink_t *sl, uint32_t* option_byte); int32_t stlink_write_option_bytes_boot_add32(stlink_t *sl, uint32_t option_bytes_boot_add); #endif // OPTION_BYTES_H stlink-1.9.0/src/stlink-lib/read_write.c000066400000000000000000000114351526027543100201660ustar00rootroot00000000000000/** ****************************************************************************** * @file : read_write.c * @brief : Read and write operations * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #include "read_write.h" #include "logging.h" // Endianness // https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html // These functions encode and decode little endian uint16 and uint32 values. uint16_t read_uint16(const unsigned char *c, const int32_t pt) { return ((uint16_t) c[pt]) | ((uint16_t) c[pt + 1] << 8); } void write_uint16(unsigned char *buf, uint16_t ui) { buf[0] = (uint8_t) ui; buf[1] = (uint8_t) (ui >> 8); } uint32_t read_uint32(const unsigned char *c, const int32_t pt) { return ((uint32_t) c[pt]) | ((uint32_t) c[pt + 1] << 8) | ((uint32_t) c[pt + 2] << 16) | ((uint32_t) c[pt + 3] << 24); } void write_uint32(unsigned char *buf, uint32_t ui) { buf[0] = ui; buf[1] = ui >> 8; buf[2] = ui >> 16; buf[3] = ui >> 24; } int32_t stlink_read_debug32(stlink_t *sl, uint32_t addr, uint32_t *data) { int32_t ret; ret = sl->backend->read_debug32(sl, addr, data); if(!ret) DLOG("*** stlink_read_debug32 %#010x at %#010x\n", *data, addr); return (ret); } int32_t stlink_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data) { DLOG("*** stlink_write_debug32 %#010x to %#010x\n", data, addr); return sl->backend->write_debug32(sl, addr, data); } int32_t stlink_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len) { DLOG("*** stlink_read_mem32 ***\n"); if(len % 4 != 0) { // !!! never ever: fw gives just wrong values ELOG("Data length doesn't have a 32 bit alignment: +%d byte.\n", len % 4); return (-1); } return (sl->backend->read_mem32(sl, addr, len)); } int32_t stlink_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len) { DLOG("*** stlink_write_mem32 %u bytes to %#x\n", len, addr); if(len % 4 != 0) { ELOG("Data length doesn't have a 32 bit alignment: +%d byte.\n", len % 4); return (-1); } return (sl->backend->write_mem32(sl, addr, len)); } int32_t stlink_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len) { DLOG("*** stlink_write_mem8 ***\n"); return (sl->backend->write_mem8(sl, addr, len)); } int32_t stlink_read_reg(stlink_t *sl, int32_t r_idx, struct stlink_reg *regp) { DLOG("*** stlink_read_reg\n"); DLOG(" (%d) ***\n", r_idx); if(r_idx > 20 || r_idx < 0) { fprintf(stderr, "Error: register index must be in [0..20]\n"); return (-1); } return (sl->backend->read_reg(sl, r_idx, regp)); } int32_t stlink_write_reg(stlink_t *sl, uint32_t reg, int32_t idx) { DLOG("*** stlink_write_reg\n"); return (sl->backend->write_reg(sl, reg, idx)); } int32_t stlink_read_unsupported_reg(stlink_t *sl, int32_t r_idx, struct stlink_reg *regp) { int32_t r_convert; DLOG("*** stlink_read_unsupported_reg\n"); DLOG(" (%d) ***\n", r_idx); /* Convert to values used by STM32_REG_DCRSR */ if(r_idx >= 0x1C && r_idx <= 0x1F) { // primask, basepri, faultmask, or control r_convert = 0x14; } else if(r_idx == 0x40) { // FPSCR r_convert = 0x21; } else if(r_idx >= 0x20 && r_idx < 0x40) { r_convert = 0x40 + (r_idx - 0x20); } else { fprintf(stderr, "Error: register address must be in [0x1C..0x40]\n"); return (-1); } return (sl->backend->read_unsupported_reg(sl, r_convert, regp)); } int32_t stlink_write_unsupported_reg(stlink_t *sl, uint32_t val, int32_t r_idx, struct stlink_reg *regp) { int32_t r_convert; DLOG("*** stlink_write_unsupported_reg\n"); DLOG(" (%d) ***\n", r_idx); /* Convert to values used by STM32_REG_DCRSR */ if(r_idx >= 0x1C && r_idx <= 0x1F) { /* primask, basepri, faultmask, or control */ r_convert = r_idx; // the backend function handles this } else if(r_idx == 0x40) { // FPSCR r_convert = 0x21; } else if(r_idx >= 0x20 && r_idx < 0x40) { r_convert = 0x40 + (r_idx - 0x20); } else { fprintf(stderr, "Error: register address must be in [0x1C..0x40]\n"); return (-1); } return (sl->backend->write_unsupported_reg(sl, val, r_convert, regp)); } int32_t stlink_read_all_regs(stlink_t *sl, struct stlink_reg *regp) { DLOG("*** stlink_read_all_regs ***\n"); return (sl->backend->read_all_regs(sl, regp)); } int32_t stlink_read_all_unsupported_regs(stlink_t *sl, struct stlink_reg *regp) { DLOG("*** stlink_read_all_unsupported_regs ***\n"); return (sl->backend->read_all_unsupported_regs(sl, regp)); } stlink-1.9.0/src/stlink-lib/read_write.h000066400000000000000000000034151526027543100201720ustar00rootroot00000000000000/** ****************************************************************************** * @file : read_write.h * @brief : Read and write operations * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #ifndef READ_WRITE_H #define READ_WRITE_H #include #include #include #include #include uint16_t read_uint16(const unsigned char *c, const int32_t pt); void write_uint16(unsigned char *buf, uint16_t ui); uint32_t read_uint32(const unsigned char *c, const int32_t pt); void write_uint32(unsigned char *buf, uint32_t ui); int32_t stlink_read_debug32(stlink_t *sl, uint32_t addr, uint32_t *data); int32_t stlink_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data); int32_t stlink_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len); int32_t stlink_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len); int32_t stlink_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len); int32_t stlink_read_reg(stlink_t *sl, int32_t r_idx, struct stlink_reg *regp); int32_t stlink_write_reg(stlink_t *sl, uint32_t reg, int32_t idx); int32_t stlink_read_unsupported_reg(stlink_t *sl, int32_t r_idx, struct stlink_reg *regp); int32_t stlink_write_unsupported_reg(stlink_t *sl, uint32_t value, int32_t r_idx, struct stlink_reg *regp); int32_t stlink_read_all_regs(stlink_t *sl, struct stlink_reg *regp); int32_t stlink_read_all_unsupported_regs(stlink_t *sl, struct stlink_reg *regp); #endif // READ_WRITE_H stlink-1.9.0/src/stlink-lib/remote.c000066400000000000000000000647051526027543100173440ustar00rootroot00000000000000/** ****************************************************************************** * @file : remote.c * @brief : Remote backend and server dispatch * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @author : James Walmsley (jameswalmsley) * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ /* * Wire format (all integers little-endian via read_uint32/write_uint32): * * request: [op u32][ap u32][arg0 u32][arg1 u32][payload_len u32][payload...] * reply: [status u32][ret i32][payload_len u32][payload...] * handshake (server -> client on connect): * [magic][protocol_version][capabilities][stlink_v][jtag_v][swim_v] * [st_vid][stlink_pid][jtag_api][flags][max_trace_freq] * * Capabilities is reserved for future optional protocol features. Version 1 * servers send 0 and clients must ignore unknown future capability bits. * * The client carries sl->ap in every request because the USB command bytes * are built on the server, but the access port is selected by the client's * probe; the server applies the supplied ap before each operation. */ #if defined(_WIN32) #include #endif #include "remote.h" #define REQ_HDR_LEN 20 #define REP_HDR_LEN 12 #define REMOTE_CONNECT_TIMEOUT_SEC 5 #define HANDSHAKE_LEN (44 + STLINK_REMOTE_SERIAL_WIRE_LEN) #define REG_CORE_COUNT 16 #define REG_FLOAT_COUNT 32 #define REG_SCALAR_COUNT 10 #define REG_WIRE_LEN ((REG_CORE_COUNT + REG_FLOAT_COUNT + REG_SCALAR_COUNT) * 4) struct stlink_remote { int32_t fd; bool dead; // set when a TCP send/recv breaks the connection }; static void reg_to_wire(uint8_t *buf, const struct stlink_reg *regp) { uint32_t off = 0; for (uint32_t i = 0; i < REG_CORE_COUNT; i++, off += 4) { write_uint32(&buf[off], regp->r[i]); } for (uint32_t i = 0; i < REG_FLOAT_COUNT; i++, off += 4) { write_uint32(&buf[off], regp->s[i]); } write_uint32(&buf[off], regp->xpsr); off += 4; write_uint32(&buf[off], regp->main_sp); off += 4; write_uint32(&buf[off], regp->process_sp); off += 4; write_uint32(&buf[off], regp->rw); off += 4; write_uint32(&buf[off], regp->rw2); off += 4; write_uint32(&buf[off], regp->control); off += 4; write_uint32(&buf[off], regp->faultmask); off += 4; write_uint32(&buf[off], regp->basepri); off += 4; write_uint32(&buf[off], regp->primask); off += 4; write_uint32(&buf[off], regp->fpscr); } static void reg_from_wire(struct stlink_reg *regp, const uint8_t *buf) { uint32_t off = 0; for (uint32_t i = 0; i < REG_CORE_COUNT; i++, off += 4) { regp->r[i] = read_uint32(buf, off); } for (uint32_t i = 0; i < REG_FLOAT_COUNT; i++, off += 4) { regp->s[i] = read_uint32(buf, off); } regp->xpsr = read_uint32(buf, off); off += 4; regp->main_sp = read_uint32(buf, off); off += 4; regp->process_sp = read_uint32(buf, off); off += 4; regp->rw = read_uint32(buf, off); off += 4; regp->rw2 = read_uint32(buf, off); off += 4; regp->control = (uint8_t)read_uint32(buf, off); off += 4; regp->faultmask = (uint8_t)read_uint32(buf, off); off += 4; regp->basepri = (uint8_t)read_uint32(buf, off); off += 4; regp->primask = (uint8_t)read_uint32(buf, off); off += 4; regp->fpscr = read_uint32(buf, off); } /* === transport helpers === */ static int32_t send_all(int32_t fd, const void *buf, uint32_t len) { const uint8_t *p = (const uint8_t *)buf; while (len) { ssize_t n = send(fd, (const void *)p, len, 0); if (n < 0) { ELOG("remote: TCP send failed: %s\n", strerror(errno)); return (-1); } if (n == 0) { ELOG("remote: TCP send returned 0\n"); return (-1); } p += n; len -= (uint32_t)n; } return (0); } static int32_t recv_all(int32_t fd, void *buf, uint32_t len) { uint8_t *p = (uint8_t *)buf; while (len) { ssize_t n = recv(fd, (void *)p, len, 0); if (n < 0) { ELOG("remote: TCP receive failed: %s\n", strerror(errno)); return (-1); } if (n == 0) { DLOG("remote: peer disconnected\n"); return (-1); } p += n; len -= (uint32_t)n; } return (0); } // Disable Nagle; the request/reply pattern stalls on delayed-ACK otherwise. static void set_tcp_nodelay(int32_t fd) { int32_t one = 1; setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const void *)&one, sizeof(one)); } // connect() with a timeout so an unreachable host fails fast instead of // blocking on the OS default. POSIX only; Windows uses a blocking connect. static int32_t remote_connect_timeout(int32_t fd, const struct sockaddr *addr, socklen_t addrlen, int32_t timeout_sec) { #if defined(_WIN32) (void)timeout_sec; return (connect(fd, addr, addrlen) < 0) ? (-1) : (0); #else int32_t flags = fcntl(fd, F_GETFL, 0); if (flags < 0 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) { return (-1); } int32_t rc = connect(fd, addr, addrlen); if (rc < 0 && errno == EINPROGRESS) { fd_set wset; FD_ZERO(&wset); FD_SET(fd, &wset); struct timeval tv = { timeout_sec, 0 }; rc = select(fd + 1, NULL, &wset, NULL, &tv); if (rc == 0) { errno = ETIMEDOUT; rc = -1; } else if (rc > 0) { int32_t soerr = 0; socklen_t len = sizeof(soerr); if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &soerr, &len) < 0 || soerr != 0) { if (soerr) { errno = soerr; } rc = -1; } else { rc = 0; } } } fcntl(fd, F_SETFL, flags); // restore blocking mode for the rest of the session return (rc < 0) ? (-1) : (0); #endif } static int32_t send_reply(int32_t fd, uint32_t status, int32_t ret, const uint8_t *payload, uint32_t payload_len) { uint8_t rhdr[REP_HDR_LEN]; write_uint32(&rhdr[0], status); write_uint32(&rhdr[4], (uint32_t)ret); write_uint32(&rhdr[8], payload_len); if (send_all(fd, rhdr, REP_HDR_LEN)) { return (-1); } if (payload_len && send_all(fd, payload, payload_len)) { return (-1); } return (0); } static int32_t send_protocol_error(int32_t fd) { return send_reply(fd, REMOTE_REPLY_PROTOCOL_ERROR, -1, NULL, 0); } /* * Client-side remote procedure call: send one request, read the reply. * Returns the backend return code (the reply's ret field), or -1 on a * transport error. Read payloads land in rpayload (capped at rmax). */ static int32_t remote_rpc(stlink_t *sl, uint8_t op, uint32_t a0, uint32_t a1, const uint8_t *spayload, uint32_t splen, uint8_t *rpayload, uint32_t rmax, uint32_t *rplen) { struct stlink_remote *rl = (struct stlink_remote *)sl->backend_data; uint8_t hdr[REQ_HDR_LEN]; write_uint32(&hdr[0], op); write_uint32(&hdr[4], sl->ap); write_uint32(&hdr[8], a0); write_uint32(&hdr[12], a1); write_uint32(&hdr[16], splen); if (send_all(rl->fd, hdr, REQ_HDR_LEN)) { rl->dead = true; return (-1); } if (splen && send_all(rl->fd, spayload, splen)) { rl->dead = true; return (-1); } uint8_t rhdr[REP_HDR_LEN]; if (recv_all(rl->fd, rhdr, REP_HDR_LEN)) { rl->dead = true; return (-1); } uint32_t status = read_uint32(rhdr, 0); int32_t ret = (int32_t)read_uint32(rhdr, 4); uint32_t plen = read_uint32(rhdr, 8); if (plen > rmax) { ELOG("remote: reply payload too large (%u > %u)\n", plen, rmax); rl->dead = true; // oversized reply leaves the stream desynced return (-1); } if (plen && recv_all(rl->fd, rpayload, plen)) { rl->dead = true; return (-1); } if (rplen) { *rplen = plen; } if (status != REMOTE_REPLY_OK) { ELOG("remote: server reported protocol error\n"); return (-1); } return (ret); } /* === client backend === */ static void rb_close(stlink_t *sl) { if (sl && sl->backend_data) { struct stlink_remote *rl = (struct stlink_remote *)sl->backend_data; remote_rpc(sl, RPC_CLOSE, 0, 0, NULL, 0, NULL, 0, NULL); if (rl->fd >= 0) { close(rl->fd); } free(rl); sl->backend_data = NULL; } } static int32_t rb_exit_debug_mode(stlink_t *sl) { return remote_rpc(sl, RPC_EXIT_DEBUG, 0, 0, NULL, 0, NULL, 0, NULL); } static int32_t rb_enter_swd_mode(stlink_t *sl) { return remote_rpc(sl, RPC_ENTER_SWD, 0, 0, NULL, 0, NULL, 0, NULL); } static int32_t rb_enter_jtag_mode(stlink_t *sl) { return remote_rpc(sl, RPC_ENTER_JTAG, 0, 0, NULL, 0, NULL, 0, NULL); } static int32_t rb_exit_dfu_mode(stlink_t *sl) { return remote_rpc(sl, RPC_EXIT_DFU, 0, 0, NULL, 0, NULL, 0, NULL); } static int32_t rb_reset(stlink_t *sl) { return remote_rpc(sl, RPC_RESET, 0, 0, NULL, 0, NULL, 0, NULL); } static int32_t rb_jtag_reset(stlink_t *sl, int32_t value) { return remote_rpc(sl, RPC_JTAG_RESET, (uint32_t)value, 0, NULL, 0, NULL, 0, NULL); } static int32_t rb_run(stlink_t *sl, enum run_type type) { return remote_rpc(sl, RPC_RUN, (uint32_t)type, 0, NULL, 0, NULL, 0, NULL); } static int32_t rb_step(stlink_t *sl) { return remote_rpc(sl, RPC_STEP, 0, 0, NULL, 0, NULL, 0, NULL); } static int32_t rb_current_mode(stlink_t *sl) { return remote_rpc(sl, RPC_CURRENT_MODE, 0, 0, NULL, 0, NULL, 0, NULL); } static int32_t rb_force_debug(stlink_t *sl) { return remote_rpc(sl, RPC_FORCE_DEBUG, 0, 0, NULL, 0, NULL, 0, NULL); } static int32_t rb_target_voltage(stlink_t *sl) { return remote_rpc(sl, RPC_TARGET_VOLTAGE, 0, 0, NULL, 0, NULL, 0, NULL); } static int32_t rb_set_swdclk(stlink_t *sl, int32_t freq) { return remote_rpc(sl, RPC_SET_SWDCLK, (uint32_t)freq, 0, NULL, 0, NULL, 0, NULL); } static int32_t rb_init_ap(stlink_t *sl, uint8_t ap) { return remote_rpc(sl, RPC_INIT_AP, ap, 0, NULL, 0, NULL, 0, NULL); } static int32_t rb_core_id(stlink_t *sl) { uint8_t p[4]; uint32_t pl; int32_t ret = remote_rpc(sl, RPC_CORE_ID, 0, 0, NULL, 0, p, sizeof(p), &pl); if (ret == 0 && pl == 4) { sl->core_id = read_uint32(p, 0); } return (ret); } static int32_t rb_status(stlink_t *sl) { uint8_t p[4]; uint32_t pl; int32_t ret = remote_rpc(sl, RPC_STATUS_REMOTE, 0, 0, NULL, 0, p, sizeof(p), &pl); if (ret == 0 && pl == 4) { sl->core_stat = (enum target_state)read_uint32(p, 0); } return (ret); } static int32_t rb_version(stlink_t *sl) { (void)sl; // version is delivered by the connect handshake return (0); } static int32_t rb_read_debug32(stlink_t *sl, uint32_t addr, uint32_t *data) { uint8_t p[4]; uint32_t pl; int32_t ret = remote_rpc(sl, RPC_READ_DEBUG32, addr, 0, NULL, 0, p, sizeof(p), &pl); if (ret == 0 && pl == 4 && data) { *data = read_uint32(p, 0); } return (ret); } static int32_t rb_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data) { return remote_rpc(sl, RPC_WRITE_DEBUG32, addr, data, NULL, 0, NULL, 0, NULL); } static int32_t rb_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len) { uint32_t pl; int32_t ret = remote_rpc(sl, RPC_READ_MEM32, addr, len, NULL, 0, (uint8_t *)sl->q_buf, Q_BUF_LEN, &pl); if (ret == 0) { if (pl != len) { ELOG("remote: READ_MEM32 returned %u bytes, expected %u\n", pl, len); return (-1); } sl->q_len = (int32_t)pl; } return (ret); } static int32_t rb_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len) { return remote_rpc(sl, RPC_WRITE_MEM32, addr, len, (uint8_t *)sl->q_buf, len, NULL, 0, NULL); } static int32_t rb_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len) { return remote_rpc(sl, RPC_WRITE_MEM8, addr, len, (uint8_t *)sl->q_buf, len, NULL, 0, NULL); } static int32_t rb_read_reg_payload(stlink_t *sl, uint8_t op, uint32_t arg, struct stlink_reg *regp) { uint8_t p[REG_WIRE_LEN]; uint32_t pl; int32_t ret = remote_rpc(sl, op, arg, 0, NULL, 0, p, sizeof(p), &pl); if (ret == 0 && pl == REG_WIRE_LEN) { reg_from_wire(regp, p); } else if (ret == 0) { ret = -1; } return (ret); } static int32_t rb_read_all_regs(stlink_t *sl, struct stlink_reg *regp) { return rb_read_reg_payload(sl, RPC_READ_ALL_REGS, 0, regp); } static int32_t rb_read_reg(stlink_t *sl, int32_t r_idx, struct stlink_reg *regp) { return rb_read_reg_payload(sl, RPC_READ_REG, (uint32_t)r_idx, regp); } static int32_t rb_read_all_unsupported_regs(stlink_t *sl, struct stlink_reg *regp) { return rb_read_reg_payload(sl, RPC_READ_ALL_UNSUPPORTED_REGS, 0, regp); } static int32_t rb_read_unsupported_reg(stlink_t *sl, int32_t r_idx, struct stlink_reg *regp) { return rb_read_reg_payload(sl, RPC_READ_UNSUPPORTED_REG, (uint32_t)r_idx, regp); } static int32_t rb_write_unsupported_reg(stlink_t *sl, uint32_t value, int32_t r_idx, struct stlink_reg *regp) { uint8_t p[REG_WIRE_LEN]; uint8_t rp[REG_WIRE_LEN]; uint32_t pl; reg_to_wire(p, regp); int32_t ret = remote_rpc(sl, RPC_WRITE_UNSUPPORTED_REG, value, (uint32_t)r_idx, p, sizeof(p), rp, sizeof(rp), &pl); if (ret == 0 && pl == REG_WIRE_LEN) { reg_from_wire(regp, rp); } else if (ret == 0) { ret = -1; } return (ret); } static int32_t rb_write_reg(stlink_t *sl, uint32_t reg, int32_t idx) { return remote_rpc(sl, RPC_WRITE_REG, reg, (uint32_t)idx, NULL, 0, NULL, 0, NULL); } static int32_t rb_trace_enable(stlink_t *sl, uint32_t frequency) { return remote_rpc(sl, RPC_TRACE_ENABLE, frequency, 0, NULL, 0, NULL, 0, NULL); } static int32_t rb_trace_disable(stlink_t *sl) { return remote_rpc(sl, RPC_TRACE_DISABLE, 0, 0, NULL, 0, NULL, 0, NULL); } static int32_t rb_trace_read(stlink_t *sl, uint8_t *buf, uint32_t size) { // trace_read returns a byte count: it comes back in ret, the bytes in the payload. return remote_rpc(sl, RPC_TRACE_READ, size, 0, NULL, 0, buf, size, NULL); } static stlink_backend_t _stlink_remote_backend = { rb_close, rb_exit_debug_mode, rb_enter_swd_mode, rb_enter_jtag_mode, rb_exit_dfu_mode, rb_core_id, rb_reset, rb_jtag_reset, rb_run, rb_status, rb_version, rb_read_debug32, rb_read_mem32, rb_write_debug32, rb_write_mem32, rb_write_mem8, rb_read_all_regs, rb_read_reg, rb_read_all_unsupported_regs, rb_read_unsupported_reg, rb_write_unsupported_reg, rb_write_reg, rb_step, rb_current_mode, rb_force_debug, rb_target_voltage, rb_set_swdclk, rb_trace_enable, rb_trace_disable, rb_trace_read, rb_init_ap, }; /* === client open === */ stlink_t *stlink_open_remote(int32_t verbose, const char *host, int32_t port, enum connect_type conn, int32_t freq) { ugly_init(verbose); char portstr[16]; snprintf(portstr, sizeof(portstr), "%d", port ? port : STLINK_REMOTE_DEFAULT_PORT); struct addrinfo hints, *res = NULL; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; // Report connection failures to stderr, not ELOG: they must show even at a // log level that suppresses errors (st-info opens with verbose 0). if (getaddrinfo(host, portstr, &hints, &res) != 0 || res == NULL) { fprintf(stderr, "remote: cannot resolve host '%s'\n", host); return (NULL); } int32_t fd = (int32_t)socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (fd < 0 || remote_connect_timeout(fd, res->ai_addr, (socklen_t)res->ai_addrlen, REMOTE_CONNECT_TIMEOUT_SEC) < 0) { fprintf(stderr, "remote: cannot connect to st-server at %s:%s (%s)\n", host, portstr, strerror(errno)); if (fd >= 0) { close(fd); } freeaddrinfo(res); return (NULL); } freeaddrinfo(res); set_tcp_nodelay(fd); uint8_t hs[HANDSHAKE_LEN]; if (recv_all(fd, hs, HANDSHAKE_LEN) || read_uint32(hs, 0) != STLINK_REMOTE_MAGIC) { fprintf(stderr, "remote: no valid handshake from %s:%s (is st-server running there?)\n", host, portstr); close(fd); return (NULL); } if (read_uint32(hs, 4) != STLINK_REMOTE_PROTOCOL_VERSION) { fprintf(stderr, "remote: server at %s:%s uses protocol version %u, client expects %u\n", host, portstr, read_uint32(hs, 4), STLINK_REMOTE_PROTOCOL_VERSION); close(fd); return (NULL); } stlink_t *sl = calloc(1, sizeof(stlink_t)); struct stlink_remote *rl = calloc(1, sizeof(struct stlink_remote)); if (!sl || !rl) { free(sl); free(rl); close(fd); return (NULL); } rl->fd = fd; sl->backend = &_stlink_remote_backend; sl->backend_data = rl; sl->version.stlink_v = read_uint32(hs, 12); sl->version.jtag_v = read_uint32(hs, 16); sl->version.swim_v = read_uint32(hs, 20); sl->version.st_vid = read_uint32(hs, 24); sl->version.stlink_pid = read_uint32(hs, 28); sl->version.jtag_api = (enum stlink_jtag_api_version)read_uint32(hs, 32); sl->version.flags = read_uint32(hs, 36); sl->max_trace_freq = read_uint32(hs, 40); memcpy(sl->serial, &hs[44], STLINK_SERIAL_BUFFER_SIZE); // wire field is zero-padded sl->serial[STLINK_SERIAL_BUFFER_SIZE - 1] = '\0'; // Same connect sequence as stlink_open_usb(), driven over the backend ops. int32_t mode = stlink_current_mode(sl); if (mode == STLINK_DEV_DFU_MODE) { sl->backend->exit_dfu_mode(sl); } if (conn == CONNECT_UNDER_RESET) { if (mode == STLINK_DEV_DEBUG_MODE) { sl->backend->exit_debug_mode(sl); } sl->backend->jtag_reset(sl, STLINK_DEBUG_APIV2_DRIVE_NRST_LOW); } sl->freq = freq; sl->backend->set_swdclk(sl, freq); stlink_target_connect(sl, conn); // Bail if a TCP error broke the link during the sequence above; a failed // target_connect (link still up) is handled downstream instead. if (rl->dead) { fprintf(stderr, "remote: lost connection to st-server during connect\n"); close(rl->fd); free(rl); free(sl); return (NULL); } return (sl); } stlink_t *stlink_open_remote_str(int32_t verbose, const char *hostport, enum connect_type connect, int32_t freq) { char host[256]; int32_t port = STLINK_REMOTE_DEFAULT_PORT; const char *colon = strrchr(hostport, ':'); if (colon) { size_t hlen = (size_t)(colon - hostport); if (hlen >= sizeof(host)) { hlen = sizeof(host) - 1; } memcpy(host, hostport, hlen); host[hlen] = '\0'; char *end = NULL; long parsed = strtol(colon + 1, &end, 0); if (*end != '\0' || parsed <= 0 || parsed > UINT16_MAX) { fprintf(stderr, "remote: invalid port in '%s'\n", hostport); return (NULL); } port = (int32_t)parsed; } else { snprintf(host, sizeof(host), "%s", hostport); } return stlink_open_remote(verbose, host, port, connect, freq); } /* === server dispatch === */ int32_t stlink_remote_serve(stlink_t *sl, int32_t fd) { set_tcp_nodelay(fd); uint8_t hs[HANDSHAKE_LEN]; write_uint32(&hs[0], STLINK_REMOTE_MAGIC); write_uint32(&hs[4], STLINK_REMOTE_PROTOCOL_VERSION); write_uint32(&hs[8], 0); // capabilities: reserved for future protocol options write_uint32(&hs[12], sl->version.stlink_v); write_uint32(&hs[16], sl->version.jtag_v); write_uint32(&hs[20], sl->version.swim_v); write_uint32(&hs[24], sl->version.st_vid); write_uint32(&hs[28], sl->version.stlink_pid); write_uint32(&hs[32], (uint32_t)sl->version.jtag_api); write_uint32(&hs[36], sl->version.flags); write_uint32(&hs[40], sl->max_trace_freq); memset(&hs[44], 0, STLINK_REMOTE_SERIAL_WIRE_LEN); // zero-pad the fixed serial field memcpy(&hs[44], sl->serial, STLINK_SERIAL_BUFFER_SIZE); if (send_all(fd, hs, HANDSHAKE_LEN)) { return (-1); } for (;;) { uint8_t hdr[REQ_HDR_LEN]; if (recv_all(fd, hdr, REQ_HDR_LEN)) { return (0); } // client disconnected uint8_t op = (uint8_t)read_uint32(hdr, 0); sl->ap = (uint8_t)read_uint32(hdr, 4); uint32_t a0 = read_uint32(hdr, 8); uint32_t a1 = read_uint32(hdr, 12); uint32_t splen = read_uint32(hdr, 16); if (splen) { if (splen > Q_BUF_LEN) { ELOG("remote: request payload too large (%u > %u)\n", splen, Q_BUF_LEN); send_protocol_error(fd); return (-1); } if (recv_all(fd, sl->q_buf, splen)) { return (-1); } } int32_t ret = -1; uint32_t status = REMOTE_REPLY_OK; uint8_t scratch[4]; struct stlink_reg regbuf; uint8_t regwire[REG_WIRE_LEN]; uint8_t *rpay = NULL; uint32_t rplen = 0; switch (op) { case RPC_EXIT_DEBUG: ret = sl->backend->exit_debug_mode(sl); break; case RPC_ENTER_SWD: ret = sl->backend->enter_swd_mode(sl); break; case RPC_ENTER_JTAG: ret = sl->backend->enter_jtag_mode(sl); break; case RPC_EXIT_DFU: ret = sl->backend->exit_dfu_mode(sl); break; case RPC_RESET: ret = sl->backend->reset(sl); break; case RPC_JTAG_RESET: ret = sl->backend->jtag_reset(sl, (int32_t)a0); break; case RPC_RUN: ret = sl->backend->run(sl, (enum run_type)a0); break; case RPC_STEP: ret = sl->backend->step(sl); break; case RPC_FORCE_DEBUG: ret = sl->backend->force_debug(sl); break; case RPC_CURRENT_MODE:ret = sl->backend->current_mode(sl); break; case RPC_TARGET_VOLTAGE: ret = sl->backend->target_voltage(sl); break; case RPC_SET_SWDCLK: ret = sl->backend->set_swdclk(sl, (int32_t)a0); break; case RPC_INIT_AP: ret = sl->backend->init_ap ? sl->backend->init_ap(sl, (uint8_t)a0) : -1; break; case RPC_TRACE_ENABLE: ret = sl->backend->trace_enable ? sl->backend->trace_enable(sl, a0) : -1; break; case RPC_TRACE_DISABLE: ret = sl->backend->trace_disable ? sl->backend->trace_disable(sl) : -1; break; case RPC_TRACE_READ: // ret = byte count read into q_buf; ship those bytes back. if (a0 > Q_BUF_LEN) { ELOG("remote: TRACE_READ size too large (%u > %u)\n", a0, Q_BUF_LEN); status = REMOTE_REPLY_PROTOCOL_ERROR; } else if (sl->backend->trace_read) { ret = sl->backend->trace_read(sl, sl->q_buf, a0); if (ret > 0) { rpay = (uint8_t *)sl->q_buf; rplen = (uint32_t)ret; } } break; case RPC_CORE_ID: ret = sl->backend->core_id(sl); write_uint32(scratch, sl->core_id); rpay = scratch; rplen = 4; break; case RPC_STATUS_REMOTE: ret = sl->backend->status(sl); write_uint32(scratch, (uint32_t)sl->core_stat); rpay = scratch; rplen = 4; break; case RPC_VERSION_REMOTE: ret = sl->backend->version(sl); break; case RPC_READ_DEBUG32: { uint32_t d = 0; ret = sl->backend->read_debug32(sl, a0, &d); write_uint32(scratch, d); rpay = scratch; rplen = 4; break; } case RPC_READ_MEM32: ret = sl->backend->read_mem32(sl, a0, (uint16_t)a1); // send the bytes read (uint16), not the raw arg: a bogus large a1 // would otherwise make send_all() run past q_buf. if (ret == 0) { rpay = (uint8_t *)sl->q_buf; rplen = (uint16_t)a1; } break; case RPC_WRITE_DEBUG32: ret = sl->backend->write_debug32(sl, a0, a1); break; case RPC_WRITE_MEM32: case RPC_WRITE_MEM8: // payload length must match what the backend will write, else it // programs stale q_buf bytes. if (splen != (uint16_t)a1) { ELOG("remote: write payload %u != declared length %u\n", splen, (uint16_t)a1); status = REMOTE_REPLY_PROTOCOL_ERROR; } else if (op == RPC_WRITE_MEM32) { ret = sl->backend->write_mem32(sl, a0, (uint16_t)a1); } else { ret = sl->backend->write_mem8(sl, a0, (uint16_t)a1); } break; case RPC_READ_ALL_REGS: memset(®buf, 0, sizeof(regbuf)); ret = sl->backend->read_all_regs(sl, ®buf); if (ret == 0) { reg_to_wire(regwire, ®buf); rpay = regwire; rplen = REG_WIRE_LEN; } break; case RPC_READ_REG: memset(®buf, 0, sizeof(regbuf)); ret = sl->backend->read_reg(sl, (int32_t)a0, ®buf); if (ret == 0) { reg_to_wire(regwire, ®buf); rpay = regwire; rplen = REG_WIRE_LEN; } break; case RPC_READ_ALL_UNSUPPORTED_REGS: memset(®buf, 0, sizeof(regbuf)); ret = sl->backend->read_all_unsupported_regs(sl, ®buf); if (ret == 0) { reg_to_wire(regwire, ®buf); rpay = regwire; rplen = REG_WIRE_LEN; } break; case RPC_READ_UNSUPPORTED_REG: memset(®buf, 0, sizeof(regbuf)); ret = sl->backend->read_unsupported_reg(sl, (int32_t)a0, ®buf); if (ret == 0) { reg_to_wire(regwire, ®buf); rpay = regwire; rplen = REG_WIRE_LEN; } break; case RPC_WRITE_UNSUPPORTED_REG: if (splen == REG_WIRE_LEN) { reg_from_wire(®buf, sl->q_buf); ret = sl->backend->write_unsupported_reg(sl, a0, (int32_t)a1, ®buf); if (ret == 0) { reg_to_wire(regwire, ®buf); rpay = regwire; rplen = REG_WIRE_LEN; } } else { ELOG("remote: invalid WRITE_UNSUPPORTED_REG payload length %u\n", splen); status = REMOTE_REPLY_PROTOCOL_ERROR; } break; case RPC_WRITE_REG: ret = sl->backend->write_reg(sl, a0, (int32_t)a1); break; case RPC_CLOSE: ret = 0; break; default: ELOG("remote: unknown opcode %u\n", op); status = REMOTE_REPLY_PROTOCOL_ERROR; ret = -1; break; } if (send_reply(fd, status, ret, rpay, rplen)) { return (-1); } if (op == RPC_CLOSE) { return (0); } } } stlink-1.9.0/src/stlink-lib/remote.h000066400000000000000000000074501526027543100173430ustar00rootroot00000000000000/** ****************************************************************************** * @file : remote.h * @brief : Remote backend and server dispatch * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @author : James Walmsley (jameswalmsley) * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ /* * Remote backend: tunnels the stlink backend operations over TCP so that * st-flash / st-info can drive an ST-LINK attached to another machine * (the server, st-server). The client runs all the high-level logic * (chip-id lookup, flash loaders, erase/program sequencing) and only the * low-level backend primitives cross the wire. */ #ifndef REMOTE_H #define REMOTE_H #include #include #include #include #include #if defined(_WIN32) #include #else #include #include #include #include #include #include #include #include #endif // _WIN32 #include #include #include "read_write.h" #include "logging.h" #define STLINK_REMOTE_DEFAULT_PORT 4500 #define STLINK_REMOTE_MAGIC 0x4b4c5453 /* "STLK" */ #define STLINK_REMOTE_PROTOCOL_VERSION 1 /* * Fixed on-wire size of the handshake serial field. Deliberately decoupled * from STLINK_SERIAL_BUFFER_SIZE so that changing the internal serial buffer * cannot silently alter the protocol layout. The buffer must fit within it; if * a future ST-LINK serial needs more room, enlarge this AND bump * STLINK_REMOTE_PROTOCOL_VERSION. */ #define STLINK_REMOTE_SERIAL_WIRE_LEN 32 #if STLINK_SERIAL_BUFFER_SIZE > STLINK_REMOTE_SERIAL_WIRE_LEN #error "STLINK_SERIAL_BUFFER_SIZE exceeds the remote serial wire field; \ enlarge STLINK_REMOTE_SERIAL_WIRE_LEN and bump STLINK_REMOTE_PROTOCOL_VERSION" #endif enum stlink_remote_reply_status { REMOTE_REPLY_OK = 0, REMOTE_REPLY_PROTOCOL_ERROR = 1, }; /* Backend operations, one opcode per stlink_backend_t function pointer. */ enum stlink_remote_op { RPC_EXIT_DEBUG = 1, RPC_ENTER_SWD, RPC_ENTER_JTAG, RPC_EXIT_DFU, RPC_CORE_ID, RPC_RESET, RPC_JTAG_RESET, RPC_RUN, RPC_STATUS_REMOTE, RPC_VERSION_REMOTE, RPC_READ_DEBUG32, RPC_READ_MEM32, RPC_WRITE_DEBUG32, RPC_WRITE_MEM32, RPC_WRITE_MEM8, RPC_READ_ALL_REGS, RPC_READ_REG, RPC_READ_ALL_UNSUPPORTED_REGS, RPC_READ_UNSUPPORTED_REG, RPC_WRITE_UNSUPPORTED_REG, RPC_WRITE_REG, RPC_STEP, RPC_CURRENT_MODE, RPC_FORCE_DEBUG, RPC_TARGET_VOLTAGE, RPC_SET_SWDCLK, RPC_INIT_AP, RPC_TRACE_ENABLE, RPC_TRACE_DISABLE, RPC_TRACE_READ, RPC_CLOSE, }; /* * Client: open a remote ST-LINK over TCP and run the same open/connect * sequence as stlink_open_usb (version is taken from the server handshake). * Returns NULL on failure. */ stlink_t *stlink_open_remote(int32_t verbose, const char *host, int32_t port, enum connect_type connect, int32_t freq); /* As stlink_open_remote, but parses a "host" or "host:port" string. */ stlink_t *stlink_open_remote_str(int32_t verbose, const char *hostport, enum connect_type connect, int32_t freq); /* * Server: send the handshake then serve backend requests for one connected * client against an already-open local stlink, until the client disconnects. * Returns 0 on a clean disconnect, -1 on a transport error. */ int32_t stlink_remote_serve(stlink_t *sl, int32_t client_fd); #endif // REMOTE_H stlink-1.9.0/src/stlink-lib/sg_legacy.c000066400000000000000000001061071526027543100177770ustar00rootroot00000000000000/* * File: sg_legacy.c * * */ // TODO: CONTENT AND USE OF THIS SOURCE FILE IS TO BE VERIFIED // This file should be split up into new or existing modules /* * Copyright (c) 2010 "Capt'ns Missing Link" Authors. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. * * A linux stlink access demo. The purpose of this file is to mitigate the usual * "reinventing the wheel" force by incompatible licenses and give you an idea, * how to access the stlink device. That doesn't mean you should be a free-loader * and not contribute your improvements to this code. * * Author: Martin Capitanio * The stlink related constants kindly provided by Oliver Spencer (OpenOCD) * for use in a GPL compatible license. * * Tested compatibility: linux, gcc >= 4.3.3 * * The communication is based on standard USB mass storage device * BOT (Bulk Only Transfer) * - Endpoint 1: BULK_IN, 64 bytes max * - Endpoint 2: BULK_OUT, 64 bytes max * * All CBW transfers are ordered with the LSB (byte 0) first (little endian). * Any command must be answered before sending the next command. * Each USB transfer must complete in less than 1s. * * SB Device Class Definition for Mass Storage Devices: * www.usb.org/developers/devclass_docs/usbmassbulk_10.pdf * * dt - Data Transfer (IN/OUT) * CBW - Command Block Wrapper * CSW - Command Status Wrapper * RFU - Reserved for Future Use * * Originally, this driver used scsi pass through commands, which required the * usb-storage module to be loaded, providing the /dev/sgX links. The USB mass * storage implementation on the STLinkv1 is however terribly broken, and it can * take many minutes for the kernel to give up. * * However, in Nov 2011, the scsi pass through was replaced by raw libusb, so * instead of having to let usb-storage struggle with the device, and also greatly * limiting the portability of the driver, you can now tell usb-storage to simply * ignore this device completely. * * usb-storage.quirks * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob_plain;f=Documentation/kernel-parameters.txt * Each entry has the form VID:PID:Flags where VID and PID are Vendor and Product * ID values (4-digit hex numbers) and Flags is a set of characters, each corresponding * to a common usb-storage quirk flag as follows: * * a = SANE_SENSE (collect more than 18 bytes of sense data); * b = BAD_SENSE (don't collect more than 18 bytes of sense data); * c = FIX_CAPACITY (decrease the reported device capacity by one sector); * h = CAPACITY_HEURISTICS (decrease the reported device capacity by one sector if the number is odd); * i = IGNORE_DEVICE (don't bind to this device); * l = NOT_LOCKABLE (don't try to lock and unlock ejectable media); * m = MAX_SECTORS_64 (don't transfer more than 64 sectors = 32 KB at a time); * o = CAPACITY_OK (accept the capacity reported by the device); * r = IGNORE_RESIDUE (the device reports bogus residue values); * s = SINGLE_LUN (the device has only one Logical Unit); * w = NO_WP_DETECT (don't test whether the medium is write-protected). * * Example: quirks=0419:aaf5:rl,0421:0433:rc * http://permalink.gmane.org/gmane.linux.usb.general/35053 * * For the stlinkv1, you just want the following * * modprobe -r usb-storage && modprobe usb-storage quirks=483:3744:i * * Equivalently, you can add a line saying * * options usb-storage quirks=483:3744:i * * to your /etc/modprobe.conf or /etc/modprobe.d/local.conf (or add the "quirks=..." * part to an existing options line for usb-storage). */ #define __USE_GNU #include "sg_legacy.h" #include "logging.h" #include "read_write.h" #include "usb.h" #define STLINK_OK 0x80 #define STLINK_FALSE 0x81 static void clear_cdb(struct stlink_libsg *sl) { for(uint32_t i = 0; i < sizeof(sl->cdb_cmd_blk); i++) { sl->cdb_cmd_blk[i] = 0; } // set default sl->cdb_cmd_blk[0] = STLINK_DEBUG_COMMAND; sl->q_data_dir = Q_DATA_IN; } /** * Close and free any _backend_ related information... * @param sl */ void _stlink_sg_close(stlink_t *sl) { if(sl) { struct stlink_libsg *slsg = sl->backend_data; libusb_close(slsg->usb_handle); libusb_exit(slsg->libusb_ctx); free(slsg); } } static int32_t get_usb_mass_storage_status(libusb_device_handle *handle, uint8_t endpoint, uint32_t *tag) { unsigned char csw[13]; memset(csw, 0, sizeof(csw)); int32_t transferred; int32_t ret; int32_t try = 0; do { ret = libusb_bulk_transfer(handle, endpoint, (unsigned char *)&csw, sizeof(csw), &transferred, SG_TIMEOUT_MSEC); if(ret == LIBUSB_ERROR_PIPE) { libusb_clear_halt(handle, endpoint); } try++; } while ((ret == LIBUSB_ERROR_PIPE) && (try < 3)); if(ret != LIBUSB_SUCCESS) { WLOG("%s: receiving failed: %d\n", __func__, ret); return (-1); } if(transferred != sizeof(csw)) { WLOG("%s: received unexpected amount: %d\n", __func__, transferred); return (-1); } uint32_t rsig = read_uint32(csw, 0); uint32_t rtag = read_uint32(csw, 4); /* uint32_t residue = read_uint32(csw, 8); */ #define USB_CSW_SIGNATURE 0x53425355 // 'U' 'S' 'B' 'S' (reversed) if(rsig != USB_CSW_SIGNATURE) { WLOG("status signature was invalid: %#x\n", rsig); return (-1); } *tag = rtag; uint8_t rstatus = csw[12]; return (rstatus); } static int32_t dump_CDB_command(uint8_t *cdb, uint8_t cdb_len) { char dbugblah[100]; char *dbugp = dbugblah; dbugp += sprintf(dbugp, "Sending CDB ["); for(uint8_t i = 0; i < cdb_len; i++) { dbugp += sprintf(dbugp, " 0x%02x", (uint32_t) cdb[i]); } sprintf(dbugp, "]\n"); DLOG("%s",dbugblah); return (0); } /** * Wraps a CDB mass storage command in the appropriate gunk to get it down * @param handle * @param endpoint * @param cdb * @param cdb_length * @param lun * @param flags * @param expected_rx_size * @return */ int32_t send_usb_mass_storage_command(libusb_device_handle *handle, uint8_t endpoint_out, uint8_t *cdb, uint8_t cdb_length, uint8_t lun, uint8_t flags, uint32_t expected_rx_size) { DLOG("Sending usb m-s cmd: cdblen:%d, rxsize=%d\n", cdb_length, expected_rx_size); dump_CDB_command(cdb, cdb_length); static uint32_t tag; if(tag == 0) { tag = 1; } int32_t try = 0; int32_t ret = 0; int32_t real_transferred; int32_t i = 0; uint8_t c_buf[STLINK_SG_SIZE]; // tag is allegedly ignored... TODO - verify c_buf[i++] = 'U'; c_buf[i++] = 'S'; c_buf[i++] = 'B'; c_buf[i++] = 'C'; write_uint32(&c_buf[i], tag); uint32_t this_tag = tag++; write_uint32(&c_buf[i + 4], expected_rx_size); i += 8; c_buf[i++] = flags; c_buf[i++] = lun; c_buf[i++] = cdb_length; // now the actual CDB request assert(cdb_length <= CDB_SL); memcpy(&(c_buf[i]), cdb, cdb_length); int32_t sending_length = STLINK_SG_SIZE; // send.... do { ret = libusb_bulk_transfer(handle, endpoint_out, c_buf, sending_length, &real_transferred, SG_TIMEOUT_MSEC); if(ret == LIBUSB_ERROR_PIPE) { libusb_clear_halt(handle, endpoint_out); } try++; } while ((ret == LIBUSB_ERROR_PIPE) && (try < 3)); if(ret != LIBUSB_SUCCESS) { WLOG("sending failed: %d\n", ret); return (-1); } return (this_tag); } /** * Straight from stm8 stlink code... * @param handle * @param endpoint_in * @param endpoint_out */ static void get_sense(libusb_device_handle *handle, uint8_t endpoint_in, uint8_t endpoint_out) { DLOG("Fetching sense...\n"); uint8_t cdb[16]; memset(cdb, 0, sizeof(cdb)); #define REQUEST_SENSE 0x03 #define REQUEST_SENSE_LENGTH 18 cdb[0] = REQUEST_SENSE; cdb[4] = REQUEST_SENSE_LENGTH; uint32_t tag = send_usb_mass_storage_command(handle, endpoint_out, cdb, sizeof(cdb), 0, LIBUSB_ENDPOINT_IN, REQUEST_SENSE_LENGTH); if(tag == 0) { WLOG("refusing to send request sense with tag 0\n"); return; } unsigned char sense[REQUEST_SENSE_LENGTH]; int32_t transferred; int32_t ret; int32_t try = 0; do { ret = libusb_bulk_transfer(handle, endpoint_in, sense, sizeof(sense), &transferred, SG_TIMEOUT_MSEC); if(ret == LIBUSB_ERROR_PIPE) { libusb_clear_halt(handle, endpoint_in); } try++; } while ((ret == LIBUSB_ERROR_PIPE) && (try < 3)); if(ret != LIBUSB_SUCCESS) { WLOG("receiving sense failed: %d\n", ret); return; } if(transferred != sizeof(sense)) { WLOG("received unexpected amount of sense: %d != %u\n", transferred, (uint32_t) sizeof(sense)); } uint32_t received_tag; int32_t status = get_usb_mass_storage_status(handle, endpoint_in, &received_tag); if(status != 0) { WLOG("receiving sense failed with status: %02x\n", status); return; } if(sense[0] != 0x70 && sense[0] != 0x71) { WLOG("No sense data\n"); } else { WLOG("Sense KCQ: %02X %02X %02X\n", sense[2] & 0x0f, sense[12], sense[13]); } } /** * Just send a buffer on an endpoint, no questions asked. * Handles repeats, and time outs. Also handles reading status reports and sense * @param handle libusb device * * @param endpoint_out sends * @param endpoint_in used to read status reports back in * @param cbuf what to send * @param length how much to send * @return number of bytes actually sent, or -1 for failures. */ int32_t send_usb_data_only(libusb_device_handle *handle, unsigned char endpoint_out, unsigned char endpoint_in, unsigned char *cbuf, uint32_t length) { int32_t ret; int32_t real_transferred; int32_t try = 0; do { ret = libusb_bulk_transfer(handle, endpoint_out, cbuf, length, &real_transferred, SG_TIMEOUT_MSEC); if(ret == LIBUSB_ERROR_PIPE) { libusb_clear_halt(handle, endpoint_out); } try++; } while ((ret == LIBUSB_ERROR_PIPE) && (try < 3)); if(ret != LIBUSB_SUCCESS) { WLOG("sending failed: %d\n", ret); return (-1); } // now, swallow up the status, so that things behave nicely... uint32_t received_tag; // -ve is for my errors, 0 is good, +ve is libusb sense status bytes int32_t status = get_usb_mass_storage_status(handle, endpoint_in, &received_tag); if(status < 0) { WLOG("receiving status failed: %d\n", status); return (-1); } if(status != 0) { WLOG("receiving status not passed :(: %02x\n", status); } if(status == 1) { get_sense(handle, endpoint_in, endpoint_out); return (-1); } return (real_transferred); } int32_t stlink_q(stlink_t *sl) { struct stlink_libsg* sg = sl->backend_data; // uint8_t cdb_len = 6; // FIXME varies!!! uint8_t cdb_len = 10; // FIXME varies!!! uint8_t lun = 0; // always zero... uint32_t tag = send_usb_mass_storage_command(sg->usb_handle, sg->ep_req, sg->cdb_cmd_blk, cdb_len, lun, LIBUSB_ENDPOINT_IN, sl->q_len); // now wait for our response... // length copied from stlink-usb... int32_t rx_length = sl->q_len; int32_t try = 0; int32_t real_transferred; int32_t ret; if(rx_length > 0) { do { ret = libusb_bulk_transfer(sg->usb_handle, sg->ep_rep, sl->q_buf, rx_length, &real_transferred, SG_TIMEOUT_MSEC); if(ret == LIBUSB_ERROR_PIPE) { libusb_clear_halt(sg->usb_handle, sg->ep_req); } try++; } while ((ret == LIBUSB_ERROR_PIPE) && (try < 3)); if(ret != LIBUSB_SUCCESS) { WLOG("Receiving failed: %d\n", ret); return (-1); } if(real_transferred != rx_length) { WLOG("received unexpected amount: %d != %d\n", real_transferred, rx_length); } } uint32_t received_tag; // -ve is for my errors, 0 is good, +ve is libusb sense status bytes int32_t status = get_usb_mass_storage_status(sg->usb_handle, sg->ep_rep, &received_tag); if(status < 0) { WLOG("receiving status failed: %d\n", status); return (-1); } if(status != 0) { WLOG("receiving status not passed :(: %02x\n", status); } if(status == 1) { get_sense(sg->usb_handle, sg->ep_rep, sg->ep_req); return (-1); } if(received_tag != tag) { WLOG("received tag %d but expected %d\n", received_tag, tag); // return -1; } if(rx_length > 0 && real_transferred != rx_length) { return (-1); } return (0); } // TODO: thinking, cleanup void stlink_stat(stlink_t *stl, char *txt) { if(stl->q_len <= 0) { return; } stlink_print_data(stl); switch (stl->q_buf[0]) { case STLINK_OK: DLOG(" %s: ok\n", txt); return; case STLINK_FALSE: DLOG(" %s: false\n", txt); return; default: DLOG(" %s: unknown\n", txt); } } int32_t _stlink_sg_version(stlink_t *stl) { struct stlink_libsg *sl = stl->backend_data; clear_cdb(sl); sl->cdb_cmd_blk[0] = STLINK_GET_VERSION; stl->q_len = 6; sl->q_addr = 0; return (stlink_q(stl)); } // Get stlink mode: // STLINK_DEV_DFU_MODE || STLINK_DEV_MASS_MODE || STLINK_DEV_DEBUG_MODE // usb dfu || usb mass || jtag or swd int32_t _stlink_sg_current_mode(stlink_t *stl) { struct stlink_libsg *sl = stl->backend_data; clear_cdb(sl); sl->cdb_cmd_blk[0] = STLINK_GET_CURRENT_MODE; stl->q_len = 2; sl->q_addr = 0; if(stlink_q(stl)) { return (-1); } return (stl->q_buf[0]); } // exit the mass mode and enter the swd debug mode. int32_t _stlink_sg_enter_swd_mode(stlink_t *sl) { struct stlink_libsg *sg = sl->backend_data; clear_cdb(sg); sg->cdb_cmd_blk[1] = STLINK_DEBUG_APIV1_ENTER; sg->cdb_cmd_blk[2] = STLINK_DEBUG_ENTER_SWD; sl->q_len = 0; // >0 -> aboard return (stlink_q(sl)); } // exit the mass mode and enter the jtag debug mode. // (jtag is disabled in the discovery's stlink firmware) int32_t _stlink_sg_enter_jtag_mode(stlink_t *sl) { struct stlink_libsg *sg = sl->backend_data; DLOG("\n*** stlink_enter_jtag_mode ***\n"); clear_cdb(sg); sg->cdb_cmd_blk[1] = STLINK_DEBUG_APIV1_ENTER; sg->cdb_cmd_blk[2] = STLINK_DEBUG_ENTER_JTAG_RESET; sl->q_len = 0; return (stlink_q(sl)); } // XXX kernel driver performs reset, the device temporally disappears // Suspect this is no longer the case when we have ignore on? RECHECK int32_t _stlink_sg_exit_dfu_mode(stlink_t *sl) { struct stlink_libsg *sg = sl->backend_data; DLOG("\n*** stlink_exit_dfu_mode ***\n"); clear_cdb(sg); sg->cdb_cmd_blk[0] = STLINK_DFU_COMMAND; sg->cdb_cmd_blk[1] = STLINK_DFU_EXIT; sl->q_len = 0; // ?? return (stlink_q(sl)); /* [135121.844564] sd 19:0:0:0: [sdb] Unhandled error code [135121.844569] sd 19:0:0:0: [sdb] Result: hostbyte=DID_ERROR driverbyte=DRIVER_OK [135121.844574] sd 19:0:0:0: [sdb] CDB: Read(10): 28 00 00 00 10 00 00 00 08 00 [135121.844584] end_request: I/O error, dev sdb, sector 4096 [135121.844590] Buffer I/O error on device sdb, logical block 512 [135130.122567] usb 6-1: reset full speed USB device using uhci_hcd and address 7 [135130.274551] usb 6-1: device firmware changed [135130.274618] usb 6-1: USB disconnect, address 7 [135130.275186] VFS: busy inodes on changed media or resized disk sdb [135130.275424] VFS: busy inodes on changed media or resized disk sdb [135130.286758] VFS: busy inodes on changed media or resized disk sdb [135130.292796] VFS: busy inodes on changed media or resized disk sdb [135130.301481] VFS: busy inodes on changed media or resized disk sdb [135130.304316] VFS: busy inodes on changed media or resized disk sdb [135130.431113] usb 6-1: new full speed USB device using uhci_hcd and address 8 [135130.629444] usb-storage 6-1:1.0: Quirks match for vid 0483 pid 3744: 102a1 [135130.629492] scsi20 : usb-storage 6-1:1.0 [135131.625600] scsi 20:0:0:0: Direct-Access STM32 PQ: 0 ANSI: 0 [135131.627010] sd 20:0:0:0: Attached scsi generic sg2 type 0 [135131.633603] sd 20:0:0:0: [sdb] 64000 512-byte logical blocks: (32.7 MB/31.2 MiB) [135131.633613] sd 20:0:0:0: [sdb] Assuming Write Enabled [135131.633620] sd 20:0:0:0: [sdb] Assuming drive cache: write through [135131.640584] sd 20:0:0:0: [sdb] Assuming Write Enabled [135131.640592] sd 20:0:0:0: [sdb] Assuming drive cache: write through [135131.640609] sdb: [135131.652634] sd 20:0:0:0: [sdb] Assuming Write Enabled [135131.652639] sd 20:0:0:0: [sdb] Assuming drive cache: write through [135131.652645] sd 20:0:0:0: [sdb] Attached SCSI removable disk [135131.671536] sd 20:0:0:0: [sdb] Result: hostbyte=DID_OK driverbyte=DRIVER_SENSE [135131.671548] sd 20:0:0:0: [sdb] Sense Key : Illegal Request [current] [135131.671553] sd 20:0:0:0: [sdb] Add. Sense: Logical block address out of range [135131.671560] sd 20:0:0:0: [sdb] CDB: Read(10): 28 00 00 00 f9 80 00 00 08 00 [135131.671570] end_request: I/O error, dev sdb, sector 63872 [135131.671575] Buffer I/O error on device sdb, logical block 7984 [135131.678527] sd 20:0:0:0: [sdb] Result: hostbyte=DID_OK driverbyte=DRIVER_SENSE [135131.678532] sd 20:0:0:0: [sdb] Sense Key : Illegal Request [current] [135131.678537] sd 20:0:0:0: [sdb] Add. Sense: Logical block address out of range [135131.678542] sd 20:0:0:0: [sdb] CDB: Read(10): 28 00 00 00 f9 80 00 00 08 00 [135131.678551] end_request: I/O error, dev sdb, sector 63872 ... [135131.853565] end_request: I/O error, dev sdb, sector 4096 */ } int32_t _stlink_sg_core_id(stlink_t *sl) { struct stlink_libsg *sg = sl->backend_data; int32_t ret; clear_cdb(sg); sg->cdb_cmd_blk[1] = STLINK_DEBUG_READCOREID; sl->q_len = 4; sg->q_addr = 0; ret = stlink_q(sl); if(ret) { return (ret); } sl->core_id = read_uint32(sl->q_buf, 0); return (0); } // arm-core reset -> halted state. int32_t _stlink_sg_reset(stlink_t *sl) { struct stlink_libsg *sg = sl->backend_data; clear_cdb(sg); sg->cdb_cmd_blk[1] = STLINK_DEBUG_APIV1_RESETSYS; sl->q_len = 2; sg->q_addr = 0; if(stlink_q(sl)) { return (-1); } // Reset through AIRCR so NRST does not need to be connected if(stlink_write_debug32(sl, STM32_REG_AIRCR, STM32_REG_AIRCR_VECTKEY | \ STM32_REG_AIRCR_SYSRESETREQ)) { return (-1); } stlink_stat(sl, "core reset"); return (0); } // arm-core reset -> halted state. int32_t _stlink_sg_jtag_reset(stlink_t *sl, int32_t value) { struct stlink_libsg *sg = sl->backend_data; clear_cdb(sg); sg->cdb_cmd_blk[1] = STLINK_DEBUG_APIV2_DRIVE_NRST; sg->cdb_cmd_blk[2] = (value) ? 0 : 1; sl->q_len = 3; sg->q_addr = 2; if(stlink_q(sl)) { return (-1); } stlink_stat(sl, "core reset"); return (0); } // arm-core status: halted or running. int32_t _stlink_sg_status(stlink_t *sl) { struct stlink_libsg *sg = sl->backend_data; clear_cdb(sg); sg->cdb_cmd_blk[1] = STLINK_DEBUG_GETSTATUS; sl->q_len = 2; sg->q_addr = 0; return (stlink_q(sl)); } // force the core into the debug mode -> halted state. int32_t _stlink_sg_force_debug(stlink_t *sl) { struct stlink_libsg *sg = sl->backend_data; clear_cdb(sg); sg->cdb_cmd_blk[1] = STLINK_DEBUG_FORCEDEBUG; sl->q_len = 2; sg->q_addr = 0; if(stlink_q(sl)) { return (-1); } stlink_stat(sl, "force debug"); return (0); } // read all arm-core registers. int32_t _stlink_sg_read_all_regs(stlink_t *sl, struct stlink_reg *regp) { struct stlink_libsg *sg = sl->backend_data; clear_cdb(sg); sg->cdb_cmd_blk[1] = STLINK_DEBUG_APIV1_READALLREGS; sl->q_len = 84; sg->q_addr = 0; if(stlink_q(sl)) { return (-1); } stlink_print_data(sl); // TODO: most of this should be re-extracted up.... // 0-3 | 4-7 | ... | 60-63 | 64-67 | 68-71 | 72-75 | 76-79 | 80-83 // r0 | r1 | ... | r15 | xpsr | main_sp | process_sp | rw | rw2 for(int32_t i = 0; i < 16; i++) { regp->r[i] = read_uint32(sl->q_buf, 4 * i); if(sl->verbose > 1) { DLOG("r%2d = 0x%08x\n", i, regp->r[i]); } } regp->xpsr = read_uint32(sl->q_buf, 64); regp->main_sp = read_uint32(sl->q_buf, 68); regp->process_sp = read_uint32(sl->q_buf, 72); regp->rw = read_uint32(sl->q_buf, 76); regp->rw2 = read_uint32(sl->q_buf, 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); } // read an arm-core register, the index must be in the range 0..20. // 0 | 1 | ... | 15 | 16 | 17 | 18 | 19 | 20 // r0 | r1 | ... | r15 | xpsr | main_sp | process_sp | rw | rw2 int32_t _stlink_sg_read_reg(stlink_t *sl, int32_t r_idx, struct stlink_reg *regp) { struct stlink_libsg *sg = sl->backend_data; clear_cdb(sg); sg->cdb_cmd_blk[1] = STLINK_DEBUG_APIV1_READREG; sg->cdb_cmd_blk[2] = r_idx; sl->q_len = 4; sg->q_addr = 0; if(stlink_q(sl)) { return (-1); } // 0 | 1 | ... | 15 | 16 | 17 | 18 | 19 | 20 // 0-3 | 4-7 | ... | 60-63 | 64-67 | 68-71 | 72-75 | 76-79 | 80-83 // r0 | r1 | ... | r15 | xpsr | main_sp | process_sp | rw | rw2 stlink_print_data(sl); uint32_t r = read_uint32(sl->q_buf, 0); 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); } // write an arm-core register. Index: // 0 | 1 | ... | 15 | 16 | 17 | 18 | 19 | 20 // r0 | r1 | ... | r15 | xpsr | main_sp | process_sp | rw | rw2 int32_t _stlink_sg_write_reg(stlink_t *sl, uint32_t reg, int32_t idx) { struct stlink_libsg *sg = sl->backend_data; clear_cdb(sg); sg->cdb_cmd_blk[1] = STLINK_DEBUG_APIV1_WRITEREG; // 2: reg index // 3-6: reg content sg->cdb_cmd_blk[2] = idx; write_uint32(sg->cdb_cmd_blk + 3, reg); sl->q_len = 2; sg->q_addr = 0; if(stlink_q(sl)) { return (-1); } stlink_stat(sl, "write reg"); return (0); } // write a register of the debug module of the core. // XXX ?(atomic writes) // TODO: test void stlink_write_dreg(stlink_t *sl, uint32_t reg, uint32_t addr) { struct stlink_libsg *sg = sl->backend_data; DLOG("\n*** stlink_write_dreg ***\n"); clear_cdb(sg); sg->cdb_cmd_blk[1] = STLINK_DEBUG_APIV1_WRITEDEBUGREG; // 2-5: address of reg of the debug module // 6-9: reg content write_uint32(sg->cdb_cmd_blk + 2, addr); write_uint32(sg->cdb_cmd_blk + 6, reg); sl->q_len = 2; sg->q_addr = addr; stlink_q(sl); stlink_stat(sl, "write debug reg"); } // force the core exit the debug mode. int32_t _stlink_sg_run(stlink_t *sl, enum run_type type) { struct stlink_libsg *sg = sl->backend_data; (void)(type); //unused clear_cdb(sg); sg->cdb_cmd_blk[1] = STLINK_DEBUG_RUNCORE; sl->q_len = 2; sg->q_addr = 0; if(stlink_q(sl)) { return (-1); } stlink_stat(sl, "run core"); return (0); } // step the arm-core. int32_t _stlink_sg_step(stlink_t *sl) { struct stlink_libsg *sg = sl->backend_data; clear_cdb(sg); sg->cdb_cmd_blk[1] = STLINK_DEBUG_STEPCORE; sl->q_len = 2; sg->q_addr = 0; if(stlink_q(sl)) { return (-1); } stlink_stat(sl, "step core"); return (0); } // TODO: test and make delegate! // see Cortex-M3 Technical Reference Manual void stlink_set_hw_bp(stlink_t *sl, int32_t fp_nr, uint32_t addr, int32_t fp) { DLOG("\n*** stlink_set_hw_bp ***\n"); struct stlink_libsg *sg = sl->backend_data; clear_cdb(sg); sg->cdb_cmd_blk[1] = STLINK_DEBUG_APIV1_SETFP; // 2:The number of the flash patch used to set the breakpoint // 3-6: Address of the breakpoint (LSB) // 7: FP_ALL (0x02) / FP_UPPER (0x01) / FP_LOWER (0x00) sl->q_buf[2] = fp_nr; write_uint32(sl->q_buf, addr); sl->q_buf[7] = fp; sl->q_len = 2; stlink_q(sl); stlink_stat(sl, "set flash breakpoint"); } // TODO: test and make delegate! void stlink_clr_hw_bp(stlink_t *sl, int32_t fp_nr) { struct stlink_libsg *sg = sl->backend_data; DLOG("\n*** stlink_clr_hw_bp ***\n"); clear_cdb(sg); sg->cdb_cmd_blk[1] = STLINK_DEBUG_APIV1_CLEARFP; sg->cdb_cmd_blk[2] = fp_nr; sl->q_len = 2; stlink_q(sl); stlink_stat(sl, "clear flash breakpoint"); } // read a "len" bytes to the sl->q_buf from the memory, max 6kB (6144 bytes) int32_t _stlink_sg_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len) { struct stlink_libsg *sg = sl->backend_data; clear_cdb(sg); sg->cdb_cmd_blk[1] = STLINK_DEBUG_READMEM_32BIT; // 2-5: addr // 6-7: len write_uint32(sg->cdb_cmd_blk + 2, addr); write_uint16(sg->cdb_cmd_blk + 6, len); // data_in 0-0x40-len // !!! len _and_ q_len must be max 6k, // i.e. >1024 * 6 = 6144 -> aboard) // !!! if len < q_len: 64*k, 1024*n, n=1..5 -> aboard // (broken residue issue) sl->q_len = len; sg->q_addr = addr; if(stlink_q(sl)) { return (-1); } stlink_print_data(sl); return (0); } // write a "len" bytes from the sl->q_buf to the memory, max 64 Bytes. int32_t _stlink_sg_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len) { struct stlink_libsg *sg = sl->backend_data; int32_t ret; clear_cdb(sg); sg->cdb_cmd_blk[1] = STLINK_DEBUG_WRITEMEM_8BIT; // 2-5: addr // 6-7: len (>0x40 (64) -> aboard) write_uint32(sg->cdb_cmd_blk + 2, addr); write_uint16(sg->cdb_cmd_blk + 6, len); // this sends the command... ret = send_usb_mass_storage_command(sg->usb_handle, sg->ep_req, sg->cdb_cmd_blk, CDB_SL, 0, 0, 0); if(ret == -1) { return (ret); } // This sends the data... ret = send_usb_data_only(sg->usb_handle, sg->ep_req, sg->ep_rep, sl->q_buf, len); if(ret == -1) { return (ret); } stlink_print_data(sl); return (0); } // write a "len" bytes from the sl->q_buf to the memory, max Q_BUF_LEN bytes. int32_t _stlink_sg_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len) { struct stlink_libsg *sg = sl->backend_data; int32_t ret; clear_cdb(sg); sg->cdb_cmd_blk[1] = STLINK_DEBUG_WRITEMEM_32BIT; // 2-5: addr // 6-7: len "unlimited" write_uint32(sg->cdb_cmd_blk + 2, addr); write_uint16(sg->cdb_cmd_blk + 6, len); // this sends the command... ret = send_usb_mass_storage_command(sg->usb_handle, sg->ep_req, sg->cdb_cmd_blk, CDB_SL, 0, 0, 0); if(ret == -1) { return (ret); } // This sends the data... ret = send_usb_data_only(sg->usb_handle, sg->ep_req, sg->ep_rep, sl->q_buf, len); if(ret == -1) { return (ret); } stlink_print_data(sl); return (0); } // write one DWORD data to memory int32_t _stlink_sg_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data) { struct stlink_libsg *sg = sl->backend_data; clear_cdb(sg); sg->cdb_cmd_blk[1] = STLINK_DEBUG_APIV2_WRITEDEBUGREG; // 2-5: addr write_uint32(sg->cdb_cmd_blk + 2, addr); write_uint32(sg->cdb_cmd_blk + 6, data); sl->q_len = 2; return (stlink_q(sl)); } // read one DWORD data from memory int32_t _stlink_sg_read_debug32(stlink_t *sl, uint32_t addr, uint32_t *data) { struct stlink_libsg *sg = sl->backend_data; clear_cdb(sg); sg->cdb_cmd_blk[1] = STLINK_DEBUG_APIV2_READDEBUGREG; // 2-5: addr write_uint32(sg->cdb_cmd_blk + 2, addr); sl->q_len = 8; if(stlink_q(sl)) { return (-1); } *data = read_uint32(sl->q_buf, 4); return (0); } // exit the jtag or swd mode and enter the mass mode. int32_t _stlink_sg_exit_debug_mode(stlink_t *stl) { if(stl) { struct stlink_libsg* sl = stl->backend_data; clear_cdb(sl); sl->cdb_cmd_blk[1] = STLINK_DEBUG_EXIT; stl->q_len = 0; // >0 -> aboard return (stlink_q(stl)); } return (0); } // 1) open a sg device, switch the stlink from dfu to mass mode // 2) wait 5s until the kernel driver stops reseting the broken device // 3) reopen the device // 4) the device driver is now ready for a switch to jtag/swd mode // TODO thinking, better error handling, wait until the kernel driver stops reseting the plugged-in device static stlink_backend_t _stlink_sg_backend = { _stlink_sg_close, _stlink_sg_exit_debug_mode, _stlink_sg_enter_swd_mode, _stlink_sg_enter_jtag_mode, _stlink_sg_exit_dfu_mode, _stlink_sg_core_id, _stlink_sg_reset, _stlink_sg_jtag_reset, _stlink_sg_run, _stlink_sg_status, _stlink_sg_version, _stlink_sg_read_debug32, _stlink_sg_read_mem32, _stlink_sg_write_debug32, _stlink_sg_write_mem32, _stlink_sg_write_mem8, _stlink_sg_read_all_regs, _stlink_sg_read_reg, NULL, // read_all_unsupported_regs NULL, // read_unsupported_regs NULL, // write_unsupported_regs _stlink_sg_write_reg, _stlink_sg_step, _stlink_sg_current_mode, _stlink_sg_force_debug, NULL, // target_voltage NULL, // set_swdclk NULL, // trace_enable NULL, // trace_disable NULL, // trace_read NULL, // init_ap (unsupported on legacy SCSI backend) }; static stlink_t* stlink_open(const int32_t verbose) { stlink_t *sl = malloc(sizeof(stlink_t)); struct stlink_libsg *slsg = malloc(sizeof(struct stlink_libsg)); if(sl == NULL || slsg == NULL) { WLOG("Couldn't malloc stlink and stlink_sg structures out of memory!\n"); if(sl != NULL) { free(sl); } if(slsg != NULL) { free(slsg); } return (NULL); } memset(sl, 0, sizeof(stlink_t)); if(libusb_init(&(slsg->libusb_ctx))) { WLOG("failed to init libusb context, wrong version of libraries?\n"); free(sl); free(slsg); return (NULL); } #if LIBUSB_API_VERSION < 0x01000106 libusb_set_debug(slsg->libusb_ctx, ugly_libusb_log_level(verbose)); #else libusb_set_option(slsg->libusb_ctx, LIBUSB_OPTION_LOG_LEVEL, ugly_libusb_log_level(verbose)); #endif slsg->usb_handle = libusb_open_device_with_vid_pid(slsg->libusb_ctx, STLINK_USB_VID_ST, STLINK_USB_PID_STLINK); if(slsg->usb_handle == NULL) { WLOG("Failed to find an stlink v1 by VID:PID\n"); libusb_close(slsg->usb_handle); libusb_exit(slsg->libusb_ctx); free(sl); free(slsg); return (NULL); } // TODO: Could read the interface config descriptor, and assert lots of the assumptions // assumption: numInterfaces is always 1... if(libusb_kernel_driver_active(slsg->usb_handle, 0) == 1) { int32_t r = libusb_detach_kernel_driver(slsg->usb_handle, 0); if(r < 0) { WLOG("libusb_detach_kernel_driver(() error %s\n", strerror(-r)); libusb_close(slsg->usb_handle); libusb_exit(slsg->libusb_ctx); free(sl); free(slsg); return (NULL); } DLOG("Kernel driver was successfully detached\n"); } int32_t config; if(libusb_get_configuration(slsg->usb_handle, &config)) { /* this may fail for a previous configured device */ WLOG("libusb_get_configuration()\n"); libusb_close(slsg->usb_handle); libusb_exit(slsg->libusb_ctx); free(sl); free(slsg); return (NULL); } // assumption: bConfigurationValue is always 1 if(config != 1) { WLOG("Your stlink got into a real weird configuration, trying to fix it!\n"); DLOG("setting new configuration (%d -> 1)\n", config); if(libusb_set_configuration(slsg->usb_handle, 1)) { /* this may fail for a previous configured device */ WLOG("libusb_set_configuration() failed\n"); libusb_close(slsg->usb_handle); libusb_exit(slsg->libusb_ctx); free(sl); free(slsg); return (NULL); } } if(libusb_claim_interface(slsg->usb_handle, 0)) { WLOG("libusb_claim_interface() failed\n"); libusb_close(slsg->usb_handle); libusb_exit(slsg->libusb_ctx); free(sl); free(slsg); return (NULL); } // assumption: endpoint config is fixed mang. really. slsg->ep_rep = 1 /* ep rep */ | LIBUSB_ENDPOINT_IN; slsg->ep_req = 2 /* ep req */ | LIBUSB_ENDPOINT_OUT; DLOG("Successfully opened stlinkv1 by libusb :)\n"); sl->verbose = verbose; sl->backend_data = slsg; sl->backend = &_stlink_sg_backend; sl->core_stat = TARGET_UNKNOWN; slsg->q_addr = 0; return (sl); } stlink_t* stlink_v1_open_inner(const int32_t verbose) { ugly_init(verbose); stlink_t *sl = stlink_open(verbose); if(sl == NULL) { ELOG("Could not open stlink device\n"); return (NULL); } stlink_version(sl); if((sl->version.st_vid != STLINK_USB_VID_ST) || (sl->version.stlink_pid != STLINK_USB_PID_STLINK)) { ELOG("WTF? successfully opened, but unable to read version details. BROKEN!\n"); return (NULL); } DLOG("Reading current mode...\n"); switch (stlink_current_mode(sl)) { case STLINK_DEV_MASS_MODE: return (sl); case STLINK_DEV_DEBUG_MODE: // TODO go to mass? return (sl); default: ILOG("Current mode unusable, trying to get back to a useful state...\n"); break; } DLOG("Attempting to exit DFU mode\n"); _stlink_sg_exit_dfu_mode(sl); // re-query device info (and retest) stlink_version(sl); if((sl->version.st_vid != STLINK_USB_VID_ST) || (sl->version.stlink_pid != STLINK_USB_PID_STLINK)) { ELOG("WTF? successfully opened, but unable to read version details. BROKEN!\n"); return (NULL); } return (sl); } stlink_t* stlink_v1_open(const int32_t verbose, int32_t reset) { stlink_t *sl = stlink_v1_open_inner(verbose); if(sl == NULL) { return (NULL); } // by now, it _must_ be fully open and in a useful mode.... stlink_enter_swd_mode(sl); // now we are ready to read the parameters if(reset) { stlink_reset(sl, RESET_AUTO); } stlink_load_device_params(sl); ILOG("Successfully opened a stlink v1 debugger\n"); return (sl); } stlink-1.9.0/src/stlink-lib/sg_legacy.h000066400000000000000000000101161526027543100177760ustar00rootroot00000000000000/* * File: sg_legacy.h * * */ // TODO: CONTENT AND USE OF THIS SOURCE FILE IS TO BE VERIFIED // This file should be split up into new or existing modules #ifndef SG_LEGACY_H #define SG_LEGACY_H #include #include #include #include #include #include #include #include #include #include "libusb_settings.h" /* Device access */ #define RDWR 0 #define RO 1 #define SG_TIMEOUT_SEC 1 // actually 1 is about 2 sec #define SG_TIMEOUT_MSEC 3 * 1000 // Each CDB can be a total of 6, 10, 12, or 16 bytes, later version of the SCSI standard // also allow for variable-length CDBs (min. CDB is 6). The stlink needs max. 10 bytes. #define CDB_6 6 #define CDB_10 10 #define CDB_12 12 #define CDB_16 16 #define CDB_SL 10 /* Query data flow direction */ #define Q_DATA_OUT 0 #define Q_DATA_IN 1 // The SCSI Request Sense command is used to obtain sense data (error information) from // a target device. (http://en.wikipedia.org/wiki/SCSI_Request_Sense_Command) #define SENSE_BUF_LEN 32 struct stlink_libsg { libusb_context* libusb_ctx; libusb_device_handle *usb_handle; uint32_t ep_rep; uint32_t ep_req; int32_t sg_fd; int32_t do_scsi_pt_err; unsigned char cdb_cmd_blk[CDB_SL]; int32_t q_data_dir; // Q_DATA_IN, Q_DATA_OUT // the start of the query data in the device memory space uint32_t q_addr; // Sense (error information) data // obsolete, this was fed to the scsi tools unsigned char sense_buf[SENSE_BUF_LEN]; struct stlink_reg reg; }; // static void clear_cdb(struct stlink_libsg *sl); void _stlink_sg_close(stlink_t *sl); // static int32_t get_usb_mass_storage_status(libusb_device_handle *handle, uint8_t endpoint, uint32_t *tag); // static int32_t dump_CDB_command(uint8_t *cdb, uint8_t cdb_len); int32_t send_usb_mass_storage_command(libusb_device_handle *handle, uint8_t endpoint_out, uint8_t *cdb, uint8_t cdb_length, uint8_t lun, uint8_t flags, uint32_t expected_rx_size); // static void get_sense(libusb_device_handle *handle, uint8_t endpoint_in, uint8_t endpoint_out); int32_t send_usb_data_only(libusb_device_handle *handle, unsigned char endpoint_out, unsigned char endpoint_in, unsigned char *cbuf, uint32_t length); int32_t stlink_q(stlink_t *sl); void stlink_stat(stlink_t *stl, char *txt); int32_t _stlink_sg_version(stlink_t *stl); int32_t _stlink_sg_current_mode(stlink_t *stl); int32_t _stlink_sg_enter_swd_mode(stlink_t *sl); int32_t _stlink_sg_enter_jtag_mode(stlink_t *sl); int32_t _stlink_sg_exit_dfu_mode(stlink_t *sl); int32_t _stlink_sg_core_id(stlink_t *sl); int32_t _stlink_sg_reset(stlink_t *sl); int32_t _stlink_sg_jtag_reset(stlink_t *sl, int32_t value); int32_t _stlink_sg_status(stlink_t *sl); int32_t _stlink_sg_force_debug(stlink_t *sl); int32_t _stlink_sg_read_all_regs(stlink_t *sl, struct stlink_reg *regp); int32_t _stlink_sg_read_reg(stlink_t *sl, int32_t r_idx, struct stlink_reg *regp); int32_t _stlink_sg_write_reg(stlink_t *sl, uint32_t reg, int32_t idx); void stlink_write_dreg(stlink_t *sl, uint32_t reg, uint32_t addr); int32_t _stlink_sg_run(stlink_t *sl, enum run_type type); int32_t _stlink_sg_step(stlink_t *sl); void stlink_set_hw_bp(stlink_t *sl, int32_t fp_nr, uint32_t addr, int32_t fp); void stlink_clr_hw_bp(stlink_t *sl, int32_t fp_nr); int32_t _stlink_sg_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len); int32_t _stlink_sg_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len); int32_t _stlink_sg_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len); int32_t _stlink_sg_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data); int32_t _stlink_sg_read_debug32(stlink_t *sl, uint32_t addr, uint32_t *data); int32_t _stlink_sg_exit_debug_mode(stlink_t *stl); // static stlink_backend_t _stlink_sg_backend = { }; // static stlink_t* stlink_open(const int32_t verbose); stlink_t* stlink_v1_open_inner(const int32_t verbose); stlink_t* stlink_v1_open(const int32_t verbose, int32_t reset); #endif // SG_LEGACY_H stlink-1.9.0/src/stlink-lib/usb.c000066400000000000000000001452061526027543100166360ustar00rootroot00000000000000/** ****************************************************************************** * @file : usb.c * @brief : USB commands & interaction with ST-LINK devices * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #include "usb.h" #include #include "logging.h" #include "read_write.h" static inline uint32_t le_to_h_u32(const uint8_t* buf) { return ((uint32_t) ((uint32_t) buf[0] | (uint32_t) buf[1] << 8 | (uint32_t) buf[2] << 16 | (uint32_t) buf[3] << 24)); } static int32_t _stlink_match_speed_map(const uint32_t *map, uint32_t map_size, uint32_t khz) { uint32_t i; int32_t speed_index = -1; int32_t speed_diff = INT_MAX; int32_t last_valid_speed = -1; bool match = true; for(i = 0; i < map_size; i++) { if(!map[i]) { continue; } last_valid_speed = i; if(khz == map[i]) { speed_index = i; break; } else { int32_t 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, int32_t terminate, unsigned char* txbuf, uint32_t txsize, unsigned char* rxbuf, uint32_t rxsize, int32_t check_error, const char *cmd) { // Note: txbuf and rxbuf can point to the same area int32_t res, t, retry = 0; while (1) { res = 0; t = libusb_bulk_transfer(handle->usb_handle, handle->ep_req, txbuf, (int32_t) 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, (uint32_t) res, (uint32_t) txsize); } if(rxsize != 0) { t = libusb_bulk_transfer(handle->usb_handle, handle->ep_rep, rxbuf, (int32_t) 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->protocol != 1 && check_error >= CMD_CHECK_STATUS && rxbuf[0] != STLINK_DEBUG_ERR_OK) { switch(rxbuf[0]) { case STLINK_DEBUG_ERR_AP_WAIT: case STLINK_DEBUG_ERR_DP_WAIT: if(check_error == CMD_CHECK_RETRY && retry < 3) { uint32_t delay_us = (1 << retry) * 1000; DLOG("%s wait error (0x%02X), delaying %u us and retry\n", cmd, rxbuf[0], delay_us); usleep(delay_us); retry++; continue; } DLOG("%s wait error (0x%02X)\n", cmd, rxbuf[0]); break; case STLINK_DEBUG_ERR_FAULT: DLOG("%s response fault\n", cmd); break; case STLINK_DEBUG_ERR_AP_FAULT: DLOG("%s access port fault\n", cmd); break; case STLINK_DEBUG_ERR_DP_FAULT: DLOG("%s debug port fault\n", cmd); break; case STLINK_DEBUG_ERR_AP_ERROR: DLOG("%s access port error\n", cmd); break; case STLINK_DEBUG_ERR_DP_ERROR: DLOG("%s debug port error\n", cmd); break; case STLINK_DEBUG_ERR_WRITE_VERIFY: DLOG("%s verification error\n", cmd); break; case STLINK_DEBUG_ERR_WRITE: DLOG("%s write error\n", cmd); break; default: DLOG("%s error (0x%02X)\n", cmd, rxbuf[0]); break; } return (-1); } if(check_error == CMD_CHECK_REP_LEN && res != (int32_t) rxsize) { ELOG("%s wrong reply length\n", cmd); res = -1; } } if((handle->protocol == 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 int32_t send_only(struct stlink_libusb* handle, int32_t terminate, unsigned char* txbuf, uint32_t txsize, const char *cmd) { return ((int32_t) send_recv(handle, terminate, txbuf, txsize, NULL, 0, CMD_CHECK_NO, cmd)); } static int32_t fill_command(stlink_t * sl, enum SCSI_Generic_Direction dir, uint32_t len) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const cmd = sl->c_buf; int32_t i = 0; memset(cmd, 0, sizeof(sl->c_buf)); if(slu->protocol == 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); } int32_t _stlink_usb_version(stlink_t *sl) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const data = sl->q_buf; unsigned char* const cmd = sl->c_buf; ssize_t size; uint32_t rep_len; int32_t 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; int32_t i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len); uint32_t factor, reading; int32_t 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); DLOG("target voltage factor=%08x reading=%08x\n", factor, reading); if(factor != 0 && reading != 0) { voltage = 2400 * reading / factor; } else { DLOG("voltage reading failed at device side, bad STLink chip?\n"); voltage = 0; } return (voltage); } int32_t _stlink_usb_read_debug32(stlink_t *sl, uint32_t addr, uint32_t *data) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const rdata = sl->q_buf; unsigned char* const cmd = sl->c_buf; ssize_t size; const int32_t rep_len = 8; // On targets that live on a non-default AP (e.g. STM32H5 on AP1) the native // READDEBUGREG path does not honour the selected AP. The debug registers are // memory-mapped in the PPB, so route the access through the MEM-AP instead. if (sl->ap) { if (_stlink_usb_read_mem32(sl, addr, 4) != 0) { return (-1); } *data = read_uint32(sl->q_buf, 0); return (0); } int32_t 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); } int32_t _stlink_usb_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const rdata = sl->q_buf; unsigned char* const cmd = sl->c_buf; ssize_t size; const int32_t rep_len = 2; // See _stlink_usb_read_debug32: route via the MEM-AP when not on AP0. if (sl->ap) { write_uint32(sl->q_buf, data); return (_stlink_usb_write_mem32(sl, addr, 4)); } int32_t 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); } int32_t _stlink_usb_get_rw_status(stlink_t *sl) { if(sl->version.jtag_api == STLINK_JTAG_API_V1) { return (0); } unsigned char* const rdata = sl->q_buf; struct stlink_libusb * const slu = sl->backend_data; unsigned char* const cmd = sl->c_buf; int32_t 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); } int32_t _stlink_usb_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const data = sl->q_buf; unsigned char* const cmd = sl->c_buf; int32_t i, ret; i = fill_command(sl, SG_DXFER_TO_DEV, len); cmd[i++] = STLINK_DEBUG_COMMAND; cmd[i++] = STLINK_DEBUG_WRITEMEM_32BIT; write_uint32(&cmd[i], addr); write_uint16(&cmd[i + 4], len); cmd[i + 6] = sl->ap; // access port selector (0 = AP0) 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)); } int32_t _stlink_usb_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const data = sl->q_buf; unsigned char* const cmd = sl->c_buf; int32_t i, ret; if((sl->version.jtag_api < STLINK_JTAG_API_V3 && len > 64) || (sl->version.jtag_api >= STLINK_JTAG_API_V3 && len > 512)) { ELOG("WRITEMEM_8BIT: bulk packet limits exceeded (data len %d byte)\n", len); return (-1); } i = fill_command(sl, SG_DXFER_TO_DEV, 0); cmd[i++] = STLINK_DEBUG_COMMAND; cmd[i++] = STLINK_DEBUG_WRITEMEM_8BIT; write_uint32(&cmd[i], addr); write_uint16(&cmd[i + 4], len); cmd[i + 6] = sl->ap; // access port selector (0 = AP0) 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); } int32_t _stlink_usb_current_mode(stlink_t * sl) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const cmd = sl->c_buf; unsigned char* const data = sl->q_buf; ssize_t size; int32_t rep_len = 2; int32_t i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len); cmd[i++] = STLINK_GET_CURRENT_MODE; size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_NO, "GET_CURRENT_MODE"); if(size < 0) { return (-1); } return (sl->q_buf[0]); } int32_t _stlink_usb_core_id(stlink_t * sl) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const cmd = sl->c_buf; unsigned char* const data = sl->q_buf; ssize_t size; int32_t offset, rep_len = sl->version.jtag_api == STLINK_JTAG_API_V1 ? 4 : 12; int32_t i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len); cmd[i++] = STLINK_DEBUG_COMMAND; 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); } int32_t _stlink_usb_status_v2(stlink_t *sl) { int32_t result; uint32_t status = 0; result = _stlink_usb_read_debug32(sl, STM32_REG_DHCSR, &status); DLOG("core status: %08X\n", status); if(result != 0) { sl->core_stat = TARGET_UNKNOWN; } else { if(status & STM32_REG_DHCSR_C_HALT) { sl->core_stat = TARGET_HALTED; } else if(status & STM32_REG_DHCSR_S_RESET_ST) { sl->core_stat = TARGET_RESET; } else { sl->core_stat = TARGET_RUNNING; } } return (result); } int32_t _stlink_usb_status(stlink_t * sl) { // Use _stlink_usb_status_v2() for STLINK_JTAG_API_V2 (and STLINK_JTAG_API_V3) 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; int32_t rep_len = 2; int32_t i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len); cmd[i++] = STLINK_DEBUG_COMMAND; cmd[i++] = STLINK_DEBUG_GETSTATUS; size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, 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); } int32_t _stlink_usb_force_debug(stlink_t *sl) { struct stlink_libusb *slu = sl->backend_data; int32_t res; if(sl->version.jtag_api != STLINK_JTAG_API_V1) { res = _stlink_usb_write_debug32(sl, STM32_REG_DHCSR, STM32_REG_DHCSR_DBGKEY | STM32_REG_DHCSR_C_HALT | STM32_REG_DHCSR_C_DEBUGEN); return (res); } unsigned char* const data = sl->q_buf; unsigned char* const cmd = sl->c_buf; ssize_t size; int32_t rep_len = 2; int32_t i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len); cmd[i++] = STLINK_DEBUG_COMMAND; cmd[i++] = STLINK_DEBUG_FORCEDEBUG; size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_RETRY, "FORCEDEBUG"); return (size < 0 ? -1 : 0); } int32_t _stlink_usb_enter_swd_mode(stlink_t * sl) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const cmd = sl->c_buf; ssize_t size; unsigned char* const data = sl->q_buf; const uint32_t rep_len = sl->version.jtag_api == STLINK_JTAG_API_V1 ? 0 : 2; int32_t i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len); cmd[i++] = STLINK_DEBUG_COMMAND; // select correct API-Version for entering SWD mode: V1 API (0x20), V2 API (0x30) or V3 API (0x??) if(sl->version.jtag_api == STLINK_JTAG_API_V1) { cmd[i++] = STLINK_DEBUG_APIV1_ENTER; } else if(sl->version.jtag_api == STLINK_JTAG_API_V2) { cmd[i++] = STLINK_DEBUG_APIV2_ENTER; } else { // STLINK_JTAG_API_V3 cmd[i++] = 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); } // Select and initialise an access port (MEM-AP). Required for targets whose // debug/memory access is not on the default AP0 (e.g. STM32H5 uses AP1). int32_t _stlink_usb_init_ap(stlink_t * sl, uint8_t ap) { 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; const uint32_t rep_len = 2; int32_t i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len); cmd[i++] = STLINK_DEBUG_COMMAND; cmd[i++] = STLINK_DEBUG_APIV2_INIT_AP; cmd[i++] = ap; size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_RETRY, "INIT_AP"); return (size < 0 ? -1 : 0); } int32_t _stlink_usb_exit_dfu_mode(stlink_t* sl) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const cmd = sl->c_buf; ssize_t size; int32_t i = fill_command(sl, SG_DXFER_FROM_DEV, 0); cmd[i++] = STLINK_DFU_COMMAND; cmd[i++] = STLINK_DFU_EXIT; size = send_only(slu, 1, cmd, slu->cmd_len, "DFU_EXIT"); return (size < 0 ? -1 : 0); } int32_t _stlink_usb_reset(stlink_t * sl) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const data = sl->q_buf; unsigned char* const cmd = sl->c_buf; ssize_t size; int32_t 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 if(sl->version.jtag_api == STLINK_JTAG_API_V2){ cmd[i++] = STLINK_DEBUG_APIV2_RESETSYS; } else { // STLINK_JTAG_API_V3; 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); } int32_t _stlink_usb_jtag_reset(stlink_t * sl, int32_t value) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const data = sl->q_buf; unsigned char* const cmd = sl->c_buf; ssize_t size; int32_t rep_len = 2; int32_t i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len); cmd[i++] = STLINK_DEBUG_COMMAND; cmd[i++] = STLINK_DEBUG_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); } int32_t _stlink_usb_step(stlink_t* sl) { struct stlink_libusb * const slu = sl->backend_data; if(sl->version.jtag_api != STLINK_JTAG_API_V1) { // emulates the JTAG v1 API by using DHCSR _stlink_usb_write_debug32(sl, STM32_REG_DHCSR, STM32_REG_DHCSR_DBGKEY | STM32_REG_DHCSR_C_HALT | STM32_REG_DHCSR_C_MASKINTS | STM32_REG_DHCSR_C_DEBUGEN); _stlink_usb_write_debug32(sl, STM32_REG_DHCSR, STM32_REG_DHCSR_DBGKEY | STM32_REG_DHCSR_C_STEP | STM32_REG_DHCSR_C_MASKINTS | STM32_REG_DHCSR_C_DEBUGEN); return _stlink_usb_write_debug32(sl, STM32_REG_DHCSR, STM32_REG_DHCSR_DBGKEY | STM32_REG_DHCSR_C_HALT | STM32_REG_DHCSR_C_DEBUGEN); } unsigned char* const data = sl->q_buf; unsigned char* const cmd = sl->c_buf; ssize_t size; int32_t rep_len = 2; int32_t i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len); cmd[i++] = STLINK_DEBUG_COMMAND; cmd[i++] = STLINK_DEBUG_STEPCORE; size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, 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 */ int32_t _stlink_usb_run(stlink_t* sl, enum run_type type) { struct stlink_libusb * const slu = sl->backend_data; int32_t res; if(sl->version.jtag_api != STLINK_JTAG_API_V1) { res = _stlink_usb_write_debug32(sl, STM32_REG_DHCSR, STM32_REG_DHCSR_DBGKEY | STM32_REG_DHCSR_C_DEBUGEN | ((type==RUN_FLASH_LOADER)?STM32_REG_DHCSR_C_MASKINTS:0)); return (res); } unsigned char* const data = sl->q_buf; unsigned char* const cmd = sl->c_buf; ssize_t size; int32_t rep_len = 2; int32_t i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len); cmd[i++] = STLINK_DEBUG_COMMAND; cmd[i++] = STLINK_DEBUG_RUNCORE; size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_RETRY, "RUNCORE"); return (size < 0 ? -1 : 0); } int32_t _stlink_usb_set_swdclk(stlink_t* sl, int32_t clk_freq) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const data = sl->q_buf; unsigned char* const cmd = sl->c_buf; ssize_t size; int32_t rep_len = 2; int32_t i; // clock speed only supported by stlink/v2 and for firmware >= 22 if(sl->version.stlink_v == 2 && sl->version.jtag_v >= 22) { uint16_t clk_divisor; if(clk_freq) { const uint32_t map[] = {5, 15, 25, 50, 100, 125, 240, 480, 950, 1200, 1800, 4000}; int32_t speed_index = _stlink_match_speed_map(map, STLINK_ARRAY_SIZE(map), clk_freq); switch (map[speed_index]) { case 5: clk_divisor = STLINK_SWDCLK_5KHZ_DIVISOR; break; case 15: clk_divisor = STLINK_SWDCLK_15KHZ_DIVISOR; break; 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) { int32_t speed_index; uint32_t map[STLINK_V3_MAX_FREQ_NB]; i = fill_command(sl, SG_DXFER_FROM_DEV, 16); cmd[i++] = STLINK_DEBUG_COMMAND; cmd[i++] = STLINK_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); } int32_t 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); } int32_t _stlink_usb_exit_debug_mode(stlink_t *sl) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const cmd = sl->c_buf; ssize_t size; int32_t i = fill_command(sl, SG_DXFER_FROM_DEV, 0); cmd[i++] = STLINK_DEBUG_COMMAND; cmd[i++] = STLINK_DEBUG_EXIT; size = send_only(slu, 1, cmd, slu->cmd_len, "DEBUG_EXIT"); return (size < 0 ? -1 : 0); } int32_t _stlink_usb_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const data = sl->q_buf; unsigned char* const cmd = sl->c_buf; ssize_t size; int32_t i = fill_command(sl, SG_DXFER_FROM_DEV, len); cmd[i++] = STLINK_DEBUG_COMMAND; cmd[i++] = STLINK_DEBUG_READMEM_32BIT; write_uint32(&cmd[i], addr); write_uint16(&cmd[i + 4], len); cmd[i + 6] = sl->ap; // access port selector (0 = AP0) size = send_recv(slu, 1, cmd, slu->cmd_len, data, len, CMD_CHECK_NO, "READMEM_32BIT"); if(size < 0) { return (-1); } sl->q_len = (int32_t) size; stlink_print_data(sl); return (0); } int32_t _stlink_usb_read_all_regs(stlink_t *sl, struct stlink_reg *regp) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const cmd = sl->c_buf; unsigned char* const data = sl->q_buf; ssize_t size; uint32_t rep_len = sl->version.jtag_api == STLINK_JTAG_API_V1 ? 84 : 88; int32_t 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 if(sl->version.jtag_api == STLINK_JTAG_API_V2) { cmd[i++] = STLINK_DEBUG_APIV2_READALLREGS; } else { // STLINK_JTAG_API_V3 cmd[i++] = STLINK_DEBUG_APIV2_READALLREGS; } cmd[i] = sl->ap; // access port selector (0 = AP0) 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 */ int32_t reg_offset = sl->version.jtag_api == STLINK_JTAG_API_V1 ? 0 : 4; sl->q_len = (int32_t) size; stlink_print_data(sl); for(i = 0; i < 16; i++) regp->r[i] = read_uint32(sl->q_buf, reg_offset + i * 4); 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); } int32_t _stlink_usb_read_reg(stlink_t *sl, int32_t r_idx, struct stlink_reg *regp) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const data = sl->q_buf; unsigned char* const cmd = sl->c_buf; ssize_t size; uint32_t r; uint32_t rep_len = sl->version.jtag_api == STLINK_JTAG_API_V1 ? 4 : 8; int32_t reg_offset = sl->version.jtag_api == STLINK_JTAG_API_V1 ? 0 : 4; int32_t i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len); cmd[i++] = STLINK_DEBUG_COMMAND; if(sl->version.jtag_api == STLINK_JTAG_API_V1) { cmd[i++] = STLINK_DEBUG_APIV1_READREG; } else if(sl->version.jtag_api == STLINK_JTAG_API_V2) { cmd[i++] = STLINK_DEBUG_APIV2_READREG; } else { // STLINK_JTAG_API_V3 cmd[i++] = STLINK_DEBUG_APIV2_READREG; } cmd[i++] = (uint8_t) r_idx; cmd[i] = sl->ap; // access port selector, after the register index (0 = AP0) size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_RETRY, "READREG"); if(size < 0) { return (-1); } sl->q_len = (int32_t) size; stlink_print_data(sl); r = read_uint32(sl->q_buf, reg_offset); DLOG("r_idx (%2d) = 0x%08x\n", r_idx, r); 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 */ int32_t _stlink_usb_read_unsupported_reg(stlink_t *sl, int32_t r_idx, struct stlink_reg *regp) { uint32_t r; int32_t ret; sl->q_buf[0] = (unsigned char)r_idx; for(int32_t i = 1; i < 4; i++) sl->q_buf[i] = 0; ret = _stlink_usb_write_mem32(sl, STM32_REG_DCRSR, 4); if(ret == -1) { return (ret); } ret = _stlink_usb_read_mem32(sl, STM32_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); } int32_t _stlink_usb_read_all_unsupported_regs(stlink_t *sl, struct stlink_reg *regp) { int32_t ret; ret = _stlink_usb_read_unsupported_reg(sl, 0x14, regp); if(ret == -1) { return (ret); } ret = _stlink_usb_read_unsupported_reg(sl, 0x21, regp); if(ret == -1) { return (ret); } for(int32_t 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 */ int32_t _stlink_usb_write_unsupported_reg(stlink_t *sl, uint32_t val, int32_t r_idx, struct stlink_reg *regp) { int32_t ret; if(r_idx >= 0x1C && r_idx <= 0x1F) { // primask, basepri, faultmask, or control /* These are held in the same register */ ret = _stlink_usb_read_unsupported_reg(sl, 0x14, regp); if(ret == -1) { return (ret); } 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, STM32_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, STM32_REG_DCRSR, 4)); } int32_t _stlink_usb_write_reg(stlink_t *sl, uint32_t reg, int32_t idx) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const data = sl->q_buf; unsigned char* const cmd = sl->c_buf; ssize_t size; uint32_t rep_len = 2; int32_t 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 if(sl->version.jtag_api == STLINK_JTAG_API_V2) { cmd[i++] = STLINK_DEBUG_APIV2_WRITEREG; } else { // STLINK_JTAG_API_V3 cmd[i++] = STLINK_DEBUG_APIV2_WRITEREG; } cmd[i++] = idx; write_uint32(&cmd[i], reg); cmd[i + 4] = sl->ap; // access port selector, after the register data (0 = AP0) size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_RETRY, "WRITEREG"); return (size < 0 ? -1 : 0); } int32_t _stlink_usb_enable_trace(stlink_t* sl, uint32_t frequency) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const data = sl->q_buf; unsigned char* const cmd = sl->c_buf; ssize_t size; uint32_t rep_len = 2; uint32_t max_trace_buf_len = 0; if(sl->version.stlink_v == 2) { max_trace_buf_len = STLINK_V2_TRACE_BUF_LEN; } else if(sl->version.stlink_v == 3) { max_trace_buf_len = STLINK_V3_TRACE_BUF_LEN; }; int32_t i = fill_command(sl, SG_DXFER_TO_DEV, rep_len); cmd[i++] = STLINK_DEBUG_COMMAND; cmd[i++] = STLINK_DEBUG_APIV2_START_TRACE_RX; write_uint16(&cmd[i + 0], 2 * max_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); } int32_t _stlink_usb_disable_trace(stlink_t* sl) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const data = sl->q_buf; unsigned char* const cmd = sl->c_buf; ssize_t size; uint32_t rep_len = 2; int32_t i = fill_command(sl, SG_DXFER_TO_DEV, rep_len); cmd[i++] = STLINK_DEBUG_COMMAND; cmd[i++] = STLINK_DEBUG_APIV2_STOP_TRACE_RX; size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_STATUS, "STOP_TRACE_RX"); return (size < 0 ? -1 : 0); } int32_t _stlink_usb_read_trace(stlink_t* sl, uint8_t* buf, uint32_t size) { struct stlink_libusb * const slu = sl->backend_data; unsigned char* const data = sl->q_buf; unsigned char* const cmd = sl->c_buf; uint32_t rep_len = 2; int32_t i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len); cmd[i++] = STLINK_DEBUG_COMMAND; cmd[i++] = STLINK_DEBUG_APIV2_GET_TRACE_NB; ssize_t send_size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, 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", (int32_t) 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) { int32_t res = 0; int32_t t = libusb_bulk_transfer(slu->usb_handle, slu->ep_trace, buf, trace_count, &res, 3000); if(t || res != (int32_t) 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, _stlink_usb_init_ap }; static stlink_t *stlink_open_usb_at(enum ugly_loglevel verbose, enum connect_type connect, char serial[STLINK_SERIAL_BUFFER_SIZE], int32_t bus, int32_t addr, int32_t freq); /* Argument structure for threaded probing */ struct stlink_probe_arg { int32_t bus; int32_t addr; enum connect_type connect; int32_t freq; stlink_t *res; }; /* Worker invoked by each thread to open one of the devices the probe found */ static void stlink_probe_worker(void *varg) { struct stlink_probe_arg *arg = (struct stlink_probe_arg *)varg; arg->res = stlink_open_usb_at(0, arg->connect, NULL, arg->bus, arg->addr, arg->freq); } /* return the length of serial or (0) in case of errors */ uint32_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 */ int32_t ret = libusb_get_string_descriptor(handle, 0, 0, desc_serial, sizeof(desc_serial)); if(ret < 4) return 0; uint32_t langid = desc_serial[2] | (desc_serial[3] << 8); /* 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(uint32_t 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 (uint32_t)strlen(serial); } /** * Open a stlink, by serial or by its place on the bus * @param verbose Verbosity loglevel * @param connect Type of connect to target * @param serial Serial number to search for, when NULL the first stlink found is opened (binary format) * @param bus Bus of the device to open, or (-1) to search by serial * @param addr Address of the device on that bus, unused when bus is negative * @retval NULL Error while opening the stlink * @retval !NULL Stlink found and ready to use */ static stlink_t *stlink_open_usb_at(enum ugly_loglevel verbose, enum connect_type connect, char serial[STLINK_SERIAL_BUFFER_SIZE], int32_t bus, int32_t addr, int32_t freq) { stlink_t* sl = NULL; struct stlink_libusb* slu = NULL; int32_t ret = -1; int32_t 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; } 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; ssize_t cnt = libusb_get_device_list(slu->libusb_ctx, &list); struct libusb_device_descriptor desc; while (cnt-- > 0) { struct libusb_device_handle *handle; bool match; libusb_get_device_descriptor(list[cnt], &desc); if(desc.idVendor != STLINK_USB_VID_ST) { continue; } if(bus >= 0) { // Bus and address are known without reading from the device, so the // caller's device is reached without opening any of the others. match = (libusb_get_bus_number(list[cnt]) == bus) && (libusb_get_device_address(list[cnt]) == addr); } else { ret = libusb_open(list[cnt], &handle); if(ret) { continue; } // could not open device uint64_t serial_len = stlink_serial(handle, &desc, sl->serial); libusb_close(handle); if(serial_len != STLINK_SERIAL_LENGTH) { continue; } // could not read the serial // no serial provided, or the serial matches this device match = ((serial == NULL) || (*serial == 0)) || (memcmp(serial, &sl->serial, STLINK_SERIAL_LENGTH) == 0); } // fixup version and protocol if(match) { if(STLINK_V1_USB_PID(desc.idProduct)) { slu->protocol = 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); // Nothing has read the serial of a device that was found by address. Same as // in the search above, one that cannot be read means the device is not usable. if((bus >= 0) && (stlink_serial(slu->usb_handle, &desc, sl->serial) != STLINK_SERIAL_LENGTH)) { WLOG("Could not read the serial of device %03d:%03d\n", bus, addr); goto on_libusb_error; } // 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 // NOT _WIN32 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 || desc.idProduct == STLINK_USB_PID_STLINK_V3P) { 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->protocol == 1) ? STLINK_SG_SIZE : STLINK_CMD_SIZE; // initialize stlink version (sl->version) stlink_version(sl); int32_t 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 1800 kHz) 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); } /** * Open a stlink * @param verbose Verbosity loglevel * @param connect Type of connect to target * @param serial Serial number to search for, when NULL the first stlink found is opened (binary format) * @retval NULL Error while opening the stlink * @retval !NULL Stlink found and ready to use */ stlink_t *stlink_open_usb(enum ugly_loglevel verbose, enum connect_type connect, char serial[STLINK_SERIAL_BUFFER_SIZE], int32_t freq) { // The loglevel is process wide, so only a caller that asked for one sets it. ugly_init(verbose); return (stlink_open_usb_at(verbose, connect, serial, -1, -1, freq)); } static uint32_t stlink_probe_usb_devs(libusb_device **devs, stlink_t **sldevs[], enum connect_type connect, int32_t freq) { stlink_t **_sldevs; libusb_device *dev; int32_t i = 0; uint32_t slcnt = 0; uint32_t slcur = 0; /* Count STLINKs */ while ((dev = devs[i++]) != NULL) { struct libusb_device_descriptor desc; int32_t ret = libusb_get_device_descriptor(dev, &desc); if(ret < 0) { WLOG("failed to get libusb device descriptor (libusb error: %d)\n", ret); 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); } /* Collect serials for all devices to probe */ struct stlink_probe_arg *args = calloc(slcnt, sizeof(*args)); stlink_thread_t *threads = calloc(slcnt, sizeof(*threads)); if(!args || !threads) { free(_sldevs); free(args); free(threads); *sldevs = NULL; return 0; } i = 0; uint32_t job_idx = 0; while ((dev = devs[i++]) != NULL) { struct libusb_device_descriptor desc; int32_t ret = libusb_get_device_descriptor(dev, &desc); if(ret < 0) { WLOG("failed to get libusb device descriptor (libusb error: %d)\n", ret); break; } if(desc.idVendor != STLINK_USB_VID_ST) { continue; } if(!STLINK_SUPPORTED_USB_PID(desc.idProduct)) { continue; } /* prepare thread args */ args[job_idx].bus = libusb_get_bus_number(dev); args[job_idx].addr = libusb_get_device_address(dev); args[job_idx].connect = connect; args[job_idx].freq = freq; args[job_idx].res = NULL; /* spawn worker thread */ int32_t rc = stlink_thread_create(&threads[job_idx], stlink_probe_worker, &args[job_idx]); if(rc != 0) { ELOG("Failed to create probe thread (error %d)\n", rc); args[job_idx].res = NULL; /* do not increment job_idx in this case, but continue scanning */ continue; } job_idx++; } /* Join threads and collect successful opens */ for(uint32_t n = 0; n < job_idx; n++) { stlink_thread_join(threads[n]); if(args[n].res) { _sldevs[slcur++] = args[n].res; } else { ELOG("Failed to open device %03d:%03d\n", args[n].bus, args[n].addr); } } free(args); free(threads); *sldevs = _sldevs; return (slcur); } uint32_t stlink_probe_usb(stlink_t **stdevs[], enum connect_type connect, int32_t freq) { libusb_device **devs; stlink_t **sldevs; uint32_t slcnt = 0; int32_t 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, uint32_t size) { if(stdevs == NULL || *stdevs == NULL || size == 0) { return; } for(uint32_t n = 0; n < size; n++) { stlink_close((*stdevs)[n]); } free(*stdevs); *stdevs = NULL; } stlink-1.9.0/src/stlink-lib/usb.h000066400000000000000000000142441526027543100166400ustar00rootroot00000000000000/** ****************************************************************************** * @file : usb.h * @brief : USB commands & interaction with ST-LINK devices * @copyright : Copyright (c) 2026 stlink-org. All rights reserved. * @date : 2026-07-27 * SPDX-License-Identifier: BSD-3-Clause * * This file is licensed under the BSD 3-Clause License. * See the LICENSE file in the project root for full license information. ****************************************************************************** */ #ifndef USB_H #define USB_H #if !defined(_MSC_VER) #include #endif // _MSC_VER #if defined(_WIN32) #include #endif // _WIN32 #include #include #include #include #include #include #include #include #include #include #include #include #include "libusb_settings.h" #include "logging.h" #define STLINK_USB_VID_ST 0x0483 #define STLINK_USB_PID_STLINK 0x3744 #define STLINK_USB_PID_STLINK_32L 0x3748 #define STLINK_USB_PID_STLINK_32L_AUDIO 0x374a #define STLINK_USB_PID_STLINK_NUCLEO 0x374b #define STLINK_USB_PID_STLINK_V2_1 0x3752 #define STLINK_USB_PID_STLINK_V3_USBLOADER 0x374d #define STLINK_USB_PID_STLINK_V3E_PID 0x374e #define STLINK_USB_PID_STLINK_V3S_PID 0x374f #define STLINK_USB_PID_STLINK_V3_2VCP_PID 0x3753 #define STLINK_USB_PID_STLINK_V3_NO_MSD_PID 0x3754 #define STLINK_USB_PID_STLINK_V3P 0x3757 #define STLINK_V1_USB_PID(pid) ((pid) == STLINK_USB_PID_STLINK) #define STLINK_V2_USB_PID(pid) ((pid) == STLINK_USB_PID_STLINK_32L || \ (pid) == STLINK_USB_PID_STLINK_32L_AUDIO || \ (pid) == STLINK_USB_PID_STLINK_NUCLEO) #define STLINK_V2_1_USB_PID(pid) ((pid) == STLINK_USB_PID_STLINK_V2_1) #define STLINK_V3_USB_PID(pid) ((pid) == STLINK_USB_PID_STLINK_V3_USBLOADER || \ (pid) == STLINK_USB_PID_STLINK_V3E_PID || \ (pid) == STLINK_USB_PID_STLINK_V3S_PID || \ (pid) == STLINK_USB_PID_STLINK_V3_2VCP_PID || \ (pid) == STLINK_USB_PID_STLINK_V3_NO_MSD_PID || \ (pid) == STLINK_USB_PID_STLINK_V3P) #define STLINK_SUPPORTED_USB_PID(pid) (STLINK_V1_USB_PID(pid) || \ STLINK_V2_USB_PID(pid) || \ STLINK_V2_1_USB_PID(pid) || \ STLINK_V3_USB_PID(pid)) #define STLINK_SG_SIZE 31 #define STLINK_CMD_SIZE 16 enum SCSI_Generic_Direction {SG_DXFER_TO_DEV = 0, SG_DXFER_FROM_DEV = 0x80}; struct stlink_libusb { libusb_context* libusb_ctx; libusb_device_handle* usb_handle; uint32_t ep_req; uint32_t ep_rep; uint32_t ep_trace; int32_t protocol; uint32_t sg_transfer_idx; uint32_t cmd_len; }; // static inline uint32_t le_to_h_u32(const uint8_t* buf); // static int32_t _stlink_match_speed_map(const uint32_t *map, uint32_t map_size, uint32_t khz); void _stlink_usb_close(stlink_t* sl); ssize_t send_recv(struct stlink_libusb* handle, int32_t terminate, unsigned char* txbuf, uint32_t txsize, unsigned char* rxbuf, uint32_t rxsize, int32_t check_error, const char *cmd); // static inline int32_t send_only(struct stlink_libusb* handle, int32_t terminate, unsigned char* txbuf, // uint32_t txsize, const char *cmd); // static int32_t fill_command(stlink_t * sl, enum SCSI_Generic_Direction dir, uint32_t len); int32_t _stlink_usb_version(stlink_t *sl); int32_t _stlink_usb_target_voltage(stlink_t *sl); int32_t _stlink_usb_read_debug32(stlink_t *sl, uint32_t addr, uint32_t *data); int32_t _stlink_usb_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data); int32_t _stlink_usb_get_rw_status(stlink_t *sl); int32_t _stlink_usb_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len); int32_t _stlink_usb_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len); int32_t _stlink_usb_current_mode(stlink_t * sl); int32_t _stlink_usb_core_id(stlink_t * sl); int32_t _stlink_usb_status_v2(stlink_t *sl); int32_t _stlink_usb_status(stlink_t * sl); int32_t _stlink_usb_force_debug(stlink_t *sl); int32_t _stlink_usb_enter_swd_mode(stlink_t * sl); int32_t _stlink_usb_init_ap(stlink_t * sl, uint8_t ap); int32_t _stlink_usb_exit_dfu_mode(stlink_t* sl); int32_t _stlink_usb_reset(stlink_t * sl); int32_t _stlink_usb_jtag_reset(stlink_t * sl, int32_t value); int32_t _stlink_usb_step(stlink_t* sl); int32_t _stlink_usb_run(stlink_t* sl, enum run_type type); int32_t _stlink_usb_set_swdclk(stlink_t* sl, int32_t clk_freq); int32_t _stlink_usb_exit_debug_mode(stlink_t *sl); int32_t _stlink_usb_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len); int32_t _stlink_usb_read_all_regs(stlink_t *sl, struct stlink_reg *regp); int32_t _stlink_usb_read_reg(stlink_t *sl, int32_t r_idx, struct stlink_reg *regp); int32_t _stlink_usb_read_unsupported_reg(stlink_t *sl, int32_t r_idx, struct stlink_reg *regp); int32_t _stlink_usb_read_all_unsupported_regs(stlink_t *sl, struct stlink_reg *regp); int32_t _stlink_usb_write_unsupported_reg(stlink_t *sl, uint32_t val, int32_t r_idx, struct stlink_reg *regp); int32_t _stlink_usb_write_reg(stlink_t *sl, uint32_t reg, int32_t idx); int32_t _stlink_usb_enable_trace(stlink_t* sl, uint32_t frequency); int32_t _stlink_usb_disable_trace(stlink_t* sl); int32_t _stlink_usb_read_trace(stlink_t* sl, uint8_t* buf, uint32_t size); // static stlink_backend_t _stlink_usb_backend = { }; uint32_t stlink_serial(struct libusb_device_handle *handle, struct libusb_device_descriptor *desc, char *serial); stlink_t *stlink_open_usb(enum ugly_loglevel verbose, enum connect_type connect, char serial[STLINK_SERIAL_BUFFER_SIZE], int32_t freq); // static uint32_t stlink_probe_usb_devs(libusb_device **devs, stlink_t **sldevs[], enum connect_type connect, int32_t freq); uint32_t stlink_probe_usb(stlink_t **stdevs[], enum connect_type connect, int32_t freq); void stlink_probe_usb_free(stlink_t **stdevs[], uint32_t size); #endif // USB_H stlink-1.9.0/tests/000077500000000000000000000000001526027543100141745ustar00rootroot00000000000000stlink-1.9.0/tests/CMakeLists.txt000066400000000000000000000014231526027543100167340ustar00rootroot00000000000000### # Build test executables ### set(TESTEXEC usb sg_legacy) if (WIN32) set(TEST_DEPENDENCY ${STLINK_LIB_STATIC}) else () set(TEST_DEPENDENCY ${STLINK_LIB_SHARED}) endif() foreach (test ${TESTEXEC}) add_executable(test-${test} ${test}.c) add_dependencies(test-${test} ${TEST_DEPENDENCY}) target_link_libraries(test-${test} ${TEST_DEPENDENCY} ${SSP_LIB}) add_test(test-${test} ${CMAKE_BINARY_DIR}/bin/test-${test}) endforeach () add_executable(test-flash flash.c "${CMAKE_SOURCE_DIR}/src/st-flash/flash_opts.c") target_include_directories(test-flash PRIVATE ${CMAKE_SOURCE_DIR}/src/st-flash) add_dependencies(test-flash ${TEST_DEPENDENCY}) target_link_libraries(test-flash ${TEST_DEPENDENCY} ${SSP_LIB}) add_test(test-flash ${CMAKE_BINARY_DIR}/bin/test-flash) stlink-1.9.0/tests/flash.c000066400000000000000000000157421526027543100154460ustar00rootroot00000000000000/* * File: tests/flash.c * * */ // TODO: CONTENT AND USE OF THIS SOURCE FILE IS TO BE VERIFIED #include #include #include #include #include #include #include #if defined(_MSC_VER) #include #endif struct Test { const char * cmd_line; int32_t res; struct flash_opts opts; }; static bool cmp_strings(const char * s1, const char * s2) { if(s1 == NULL || s2 == NULL) { return (s1 == s2); } else { return (0 == strcmp(s1, s2)); } } static bool cmp_mem(const uint8_t * s1, const uint8_t * s2, uint32_t size) { if(s1 == NULL || s2 == NULL) { return (s1 == s2); } else { return (0 == memcmp(s1, s2, size)); } } static bool execute_test(const struct Test * test) { int32_t ac = 0; char* av[32]; /* parse (tokenize) the test command line */ #if defined(_MSC_VER) char *cmd_line = alloca(strlen(test->cmd_line) + 1); #else char cmd_line[strlen(test->cmd_line) + 1]; #endif strcpy(cmd_line, test->cmd_line); for(char * tok = strtok(cmd_line, " "); tok; tok = strtok(NULL, " ")) { if((size_t) ac >= sizeof(av) / sizeof(av[0])) return (false); av[ac] = tok; ++ac; } /* Call */ struct flash_opts opts; int32_t res = flash_get_opts(&opts, ac, av); /* Compare results */ bool ret = (res == test->res); if(ret && (res == 0)) { ret &= (opts.cmd == test->opts.cmd); ret &= cmp_mem(opts.serial, test->opts.serial, sizeof(opts.serial)); ret &= cmp_strings(opts.filename, test->opts.filename); ret &= (opts.addr == test->opts.addr); ret &= (opts.size == test->opts.size); ret &= (opts.reset == test->opts.reset); ret &= (opts.log_level == test->opts.log_level); ret &= (opts.freq == test->opts.freq); ret &= (opts.format == test->opts.format); } printf("[%s] (%d) %s\n", ret ? "OK" : "ERROR", res, test->cmd_line); return (ret); } static struct Test tests[] = { { "", -1, FLASH_OPTS_INITIALIZER }, { "--debug --reset read test.bin 0x80000000 0x1000", 0, { .cmd = FLASH_CMD_READ, .serial = { 0 }, .filename = "test.bin", .addr = 0x80000000, .size = 0x1000, .reset = 1, .log_level = DEBUG_LOG_LEVEL, .freq = 0, .format = FLASH_FORMAT_BINARY } }, { "--debug --mass-erase --reset write test.bin 0x80000000", 0, { .cmd = FLASH_CMD_WRITE, .serial = { 0 }, .filename = "test.bin", .addr = 0x80000000, .size = 0, .reset = 1, .log_level = DEBUG_LOG_LEVEL, .mass_erase = 1, .freq = 0, .format = FLASH_FORMAT_BINARY } }, { "--debug --freq 5k --reset write test.bin 0x80000000", 0, { .cmd = FLASH_CMD_WRITE, .serial = { 0 }, .filename = "test.bin", .addr = 0x80000000, .size = 0, .reset = 1, .log_level = DEBUG_LOG_LEVEL, .freq = 5, .format = FLASH_FORMAT_BINARY } }, { "--debug --freq 15k --reset write test.bin 0x80000000", 0, { .cmd = FLASH_CMD_WRITE, .serial = { 0 }, .filename = "test.bin", .addr = 0x80000000, .size = 0, .reset = 1, .log_level = DEBUG_LOG_LEVEL, .freq = 15, .format = FLASH_FORMAT_BINARY } }, { "--debug --freq=5k --reset write test.bin 0x80000000", 0, { .cmd = FLASH_CMD_WRITE, .serial = { 0 }, .filename = "test.bin", .addr = 0x80000000, .size = 0, .reset = 1, .log_level = DEBUG_LOG_LEVEL, .freq = 5, .format = FLASH_FORMAT_BINARY } }, { "--debug --reset read test.bin 0x80000000 1000", 0, { .cmd = FLASH_CMD_READ, .serial = { 0 }, .filename = "test.bin", .addr = 0x80000000, .size = 1000, .reset = 1, .log_level = DEBUG_LOG_LEVEL, .freq = 0, .format = FLASH_FORMAT_BINARY } }, { "--debug --reset read test.bin 0x80000000 1k", 0, { .cmd = FLASH_CMD_READ, .serial = { 0 }, .filename = "test.bin", .addr = 0x80000000, .size = 1024, .reset = 1, .log_level = DEBUG_LOG_LEVEL, .freq = 0, .format = FLASH_FORMAT_BINARY } }, { "--debug --reset read test.bin 0x80000000 1M", 0, { .cmd = FLASH_CMD_READ, .serial = { 0 }, .filename = "test.bin", .addr = 0x80000000, .size = 1048576, .reset = 1, .log_level = DEBUG_LOG_LEVEL, .freq = 0, .format = FLASH_FORMAT_BINARY } }, { "--debug --reset write test.bin 0x80000000", 0, { .cmd = FLASH_CMD_WRITE, .serial = { 0 }, .filename = "test.bin", .addr = 0x80000000, .size = 0, .reset = 1, .log_level = DEBUG_LOG_LEVEL, .freq = 0, .format = FLASH_FORMAT_BINARY } }, { "erase", 0, { .cmd = FLASH_CMD_ERASE, .serial = { 0 }, .filename = NULL, .addr = 0, .size = 0, .reset = 0, .log_level = STND_LOG_LEVEL, .mass_erase = 1, .freq = 0, .format = FLASH_FORMAT_BINARY } }, { "--mass-erase erase", 0, { .cmd = FLASH_CMD_ERASE, .serial = { 0 }, .filename = NULL, .addr = 0, .size = 0, .reset = 0, .log_level = STND_LOG_LEVEL, .mass_erase = 1, .freq = 0, .format = FLASH_FORMAT_BINARY } }, { "--debug --reset --format=ihex write test.hex", 0, { .cmd = FLASH_CMD_WRITE, .serial = { 0 }, .filename = "test.hex", .addr = 0, .size = 0, .reset = 1, .log_level = DEBUG_LOG_LEVEL, .freq = 0, .format = FLASH_FORMAT_IHEX } }, { "--debug --reset --format=binary write test.hex", -1, FLASH_OPTS_INITIALIZER }, { "--debug --reset --format=ihex write test.hex 0x80000000", -1, FLASH_OPTS_INITIALIZER }, { "--debug --reset write test.hex sometext", -1, FLASH_OPTS_INITIALIZER }, { "--serial ABCEFF544851717867216044 erase sometext", -1, FLASH_OPTS_INITIALIZER }, { "--serial ABCEFF544851717867216044 erase", 0, { .cmd = FLASH_CMD_ERASE, .serial = "ABCEFF544851717867216044", .filename = NULL, .addr = 0, .size = 0, .reset = 0, .log_level = STND_LOG_LEVEL, .freq = 0, .format = FLASH_FORMAT_BINARY } }, { "--serial=ABCEFF544851717867216044 erase", 0, { .cmd = FLASH_CMD_ERASE, .serial = "ABCEFF544851717867216044", .filename = NULL, .addr = 0, .size = 0, .reset = 0, .log_level = STND_LOG_LEVEL, .freq = 0, .format = FLASH_FORMAT_BINARY } }, }; int32_t main() { bool allOk = true; for(uint32_t i = 0; i < sizeof(tests) / sizeof(tests[0]); ++i) if(!execute_test(&tests[i])) allOk = false; return (allOk ? 0 : 1); } stlink-1.9.0/tests/sg_legacy.c000066400000000000000000000152531526027543100163030ustar00rootroot00000000000000/* * File: tests/sg_legacy.c * * */ // TODO: CONTENT AND USE OF THIS SOURCE FILE IS TO BE VERIFIED #include #include #include #include #include #include #include #include #if defined(_MSC_VER) #define __attribute__(x) #endif static void __attribute__((unused)) mark_buf(stlink_t *sl) { memset(sl->q_buf, 0, sizeof(sl->q_buf)); sl->q_buf[0] = 0xaa; sl->q_buf[1] = 0xbb; sl->q_buf[2] = 0xcc; sl->q_buf[3] = 0xdd; sl->q_buf[4] = 0x11; sl->q_buf[15] = 0x22; sl->q_buf[16] = 0x33; sl->q_buf[63] = 0x44; sl->q_buf[64] = 0x69; sl->q_buf[1024 * 6 - 1] = 0x42; // 6kB sl->q_buf[1024 * 8 - 1] = 0x42; // 8kB } int32_t main(void) { // main() ripped out of old stlink-hw.c /* Avoid unused parameter warning */ // set scpi lib debug level: 0 for no debug info, 10 for lots fputs( "\nUsage: stlink-access-test [anything at all] ...\n" "\n*** Notice: The stlink firmware violates the USB standard.\n" "*** Because we just use libusb, we can just tell the kernel's\n" "*** driver to simply ignore the device...\n" "*** Unplug the stlink and execute once as root:\n" "modprobe -r usb-storage && modprobe usb-storage quirks=483:3744:i\n\n", stderr); stlink_t *sl = stlink_v1_open(99, 1); if(sl == NULL) return (0); // we are in mass mode, go to swd stlink_enter_swd_mode(sl); stlink_current_mode(sl); stlink_core_id(sl); stlink_status(sl); // stlink_force_debug(sl); stlink_reset(sl, RESET_AUTO); stlink_status(sl); // core system control block stlink_read_mem32(sl, 0xe000ed00, 4); DLOG("cpu id base register: SCB_CPUID = got 0x%08x expect 0x411fc231\n", read_uint32(sl->q_buf, 0)); // no MPU stlink_read_mem32(sl, 0xe000ed90, 4); DLOG("mpu type register: MPU_TYPER = got 0x%08x expect 0x0\n", read_uint32(sl->q_buf, 0)); #if 0 stlink_read_mem32(sl, 0xe000edf0, 4); DD(sl, "DHCSR = 0x%08x", read_uint32(sl->q_buf, 0)); stlink_read_mem32(sl, 0x4001100c, 4); DD(sl, "GPIOC_ODR = 0x%08x", read_uint32(sl->q_buf, 0)); #endif #if 0 // let blink all the leds // see "RM0041 Reference manual - STM32F100xx advanced ARM-based 32-bit MCUs" #define GPIOC 0x40011000 // port C #define GPIOC_CRH (GPIOC + 0x04) // port configuration register high #define GPIOC_ODR (GPIOC + 0x0c) // port output data register #define LED_BLUE (1 << 8) // pin 8 #define LED_GREEN (1 << 9) // pin 9 stlink_read_mem32(sl, GPIOC_CRH, 4); uint32_t io_conf = read_uint32(sl->q_buf, 0); DLOG("GPIOC_CRH = 0x%08x\n", io_conf); // set: general purpose output push-pull, output mode, max speed 10 MHz. write_uint32(sl->q_buf, 0x44444411); stlink_write_mem32(sl, GPIOC_CRH, 4); memset(sl->q_buf, 0, sizeof(sl->q_buf)); for(int32_t i = 0; i < 100; i++) { write_uint32(sl->q_buf, LED_BLUE | LED_GREEN); stlink_write_mem32(sl, GPIOC_ODR, 4); // stlink_read_mem32(sl, 0x4001100c, 4); // DD(sl, "GPIOC_ODR = 0x%08x", read_uint32(sl->q_buf, 0)); usleep(100 * 1000); memset(sl->q_buf, 0, sizeof(sl->q_buf)); stlink_write_mem32(sl, GPIOC_ODR, 4); // PC lo usleep(100 * 1000); } write_uint32(sl->q_buf, io_conf); // set old state #endif #if 0 // TODO rtfm: stlink doesn't have flash write routines // writing to the flash area confuses the fw for the next read access // stlink_read_mem32(sl, 0, 1024*6); // flash 0x08000000 128kB fputs("++++++++++ read a flash at 0x0800 0000\n", stderr); stlink_read_mem32(sl, 0x08000000, 1024 * 6); // max 6kB clear_buf(sl); stlink_read_mem32(sl, 0x08000c00, 5); stlink_read_mem32(sl, 0x08000c00, 4); mark_buf(sl); stlink_write_mem32(sl, 0x08000c00, 4); stlink_read_mem32(sl, 0x08000c00, 256); stlink_read_mem32(sl, 0x08000c00, 256); #endif #if 0 // sram 0x20000000 8kB fputs("\n++++++++++ read/write 8bit, sram at 0x2000 0000 ++++++++++++++++\n\n", stderr); memset(sl->q_buf, 0, sizeof(sl->q_buf)); mark_buf(sl); // stlink_write_mem8(sl, 0x20000000, 16); // stlink_write_mem8(sl, 0x20000000, 1); // stlink_write_mem8(sl, 0x20000001, 1); stlink_write_mem8(sl, 0x2000000b, 3); stlink_read_mem32(sl, 0x20000000, 16); #endif #if 0 // a not aligned mem32 access doesn't work indeed fputs("\n++++++++++ read/write 32bit, sram at 0x2000 0000 ++++++++++++++++\n\n", stderr); memset(sl->q_buf, 0, sizeof(sl->q_buf)); mark_buf(sl); stlink_write_mem32(sl, 0x20000000, 1); stlink_read_mem32(sl, 0x20000000, 16); mark_buf(sl); stlink_write_mem32(sl, 0x20000001, 1); stlink_read_mem32(sl, 0x20000000, 16); mark_buf(sl); stlink_write_mem32(sl, 0x2000000b, 3); stlink_read_mem32(sl, 0x20000000, 16); mark_buf(sl); stlink_write_mem32(sl, 0x20000000, 17); stlink_read_mem32(sl, 0x20000000, 32); #endif #if 0 // sram 0x20000000 8kB fputs("++++++++++ read/write 32bit, sram at 0x2000 0000 ++++++++++++\n", stderr); memset(sl->q_buf, 0, sizeof(sl->q_buf)); mark_buf(sl); stlink_write_mem8(sl, 0x20000000, 64); stlink_read_mem32(sl, 0x20000000, 64); mark_buf(sl); stlink_write_mem32(sl, 0x20000000, 1024 * 8); // 8kB stlink_read_mem32(sl, 0x20000000, 1024 * 6); stlink_read_mem32(sl, 0x20000000 + 1024 * 6, 1024 * 2); #endif #if 0 stlink_run(sl, RUN_NORMAL); stlink_status(sl); stlink_force_debug(sl); stlink_status(sl); #endif #if 0 /* read the system bootloader */ fputs("\n++++++++++ reading bootloader ++++++++++++++++\n\n", stderr); stlink_fread(sl, "/tmp/barfoo", sl->sys_base, sl->sys_size); #endif #if 0 /* read the flash memory */ fputs("\n+++++++ read flash memory\n\n", stderr); /* mark_buf(sl); */ stlink_read_mem32(sl, 0x08000000, 4); #endif #if 0 /* flash programming */ fputs("\n+++++++ program flash memory\n\n", stderr); stlink_fwrite_flash(sl, "/tmp/foobar", 0x08000000); #endif #if 0 /* check file contents */ fputs("\n+++++++ check flash memory\n\n", stderr); { const int32_t res = stlink_fcheck_flash(sl, "/tmp/foobar", 0x08000000); printf("_____ stlink_fcheck_flash() == %d\n", res); } #endif #if 0 fputs("\n+++++++ sram write and execute\n\n", stderr); stlink_fwrite_sram(sl, "/tmp/foobar", sl->sram_base); stlink_run_at(sl, sl->sram_base); #endif #if 0 stlink_run(sl, RUN_NORMAL); stlink_status(sl); // back to mass mode, just in case ... stlink_exit_debug_mode(sl); stlink_current_mode(sl); stlink_close(sl); #endif // fflush(stderr); // fflush(stdout); return (EXIT_SUCCESS); } stlink-1.9.0/tests/test_invariant_gdb-server.c000066400000000000000000000051351526027543100215160ustar00rootroot00000000000000/* * File: tests/test_invariant_gdb-server.c * * */ // TODO: CONTENT AND USE OF THIS SOURCE FILE IS TO BE VERIFIED #include #include #include #include // Simulate the vulnerable function's context #define STLINK_SERIAL_BUFFER_SIZE 16 // This test simulates the security property: buffer boundaries must never be exceeded START_TEST(test_serial_buffer_boundary) { // Invariant: memcpy must never write beyond st->serialnumber buffer boundaries const char *payloads[] = { "EXACT_EXPLOIT_PAYLOAD_OVERFLOW", // Exact exploit case: longer than buffer "BOUNDARY_16_CHARS", // Boundary: exactly STLINK_SERIAL_BUFFER_SIZE "VALID", // Valid: shorter than buffer "", // Edge: empty string "A\0B" // Edge: embedded null }; int num_payloads = sizeof(payloads) / sizeof(payloads[0]); for (int i = 0; i < num_payloads; i++) { char serialnumber[STLINK_SERIAL_BUFFER_SIZE]; memset(serialnumber, 0xAA, sizeof(serialnumber)); // Fill with sentinel // Track bytes written size_t copy_len = strlen(payloads[i]) + 1; if (copy_len > STLINK_SERIAL_BUFFER_SIZE) { copy_len = STLINK_SERIAL_BUFFER_SIZE; } // Simulate the vulnerable memcpy call memcpy(serialnumber, payloads[i], STLINK_SERIAL_BUFFER_SIZE); // Property: No byte beyond buffer boundary should be modified // Check sentinel after buffer char after_buffer[8]; memset(after_buffer, 0xAA, sizeof(after_buffer)); // In real test, we'd check adjacent memory wasn't corrupted // For this demonstration, we verify buffer null-terminator when string fits if (strlen(payloads[i]) < STLINK_SERIAL_BUFFER_SIZE) { ck_assert_msg(serialnumber[STLINK_SERIAL_BUFFER_SIZE - 1] == 0xAA, "Buffer overflow detected for payload: %s", payloads[i]); } } } END_TEST Suite *security_suite(void) { Suite *s; TCase *tc_core; s = suite_create("Security"); tc_core = tcase_create("Core"); tcase_add_test(tc_core, test_serial_buffer_boundary); suite_add_tcase(s, tc_core); return s; } int main(void) { int number_failed; Suite *s; SRunner *sr; s = security_suite(); sr = srunner_create(s); srunner_run_all(sr, CK_NORMAL); number_failed = srunner_ntests_failed(sr); srunner_free(sr); return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; }stlink-1.9.0/tests/usb.c000066400000000000000000000067701526027543100151430ustar00rootroot00000000000000/* * File: tests/usb.c * * */ // TODO: CONTENT AND USE OF THIS SOURCE FILE IS TO BE VERIFIED #include #include #include #include #include #include #include static void usage(void) { puts("test-usb --reset"); puts("test-usb --no-reset"); } int32_t main(int32_t ac, char** av) { stlink_t* sl; struct stlink_reg regs; int32_t reset = 0; if(ac == 2) { if(strcmp(av[1], "--reset") == 0) reset = 2; if(strcmp(av[1], "--no-reset") == 0) reset = 1; } if(reset == 0) { usage(); return (0); } sl = stlink_open_usb(10, reset, NULL, 0); if(sl != NULL) { printf("-- version\n"); stlink_version(sl); printf("mode before doing anything: %d\n", stlink_current_mode(sl)); if(stlink_current_mode(sl) == STLINK_DEV_DFU_MODE) { printf("-- exit_dfu_mode\n"); stlink_exit_dfu_mode(sl); } printf("-- enter_swd_mode\n"); stlink_enter_swd_mode(sl); printf("-- mode after entering swd mode: %d\n", stlink_current_mode(sl)); printf("-- chip id: %#x\n", sl->chip_id); printf("-- core_id: %#x\n", sl->core_id); cortex_m3_cpuid_t cpuid; if(stlink_cpu_id(sl, &cpuid)) { printf("Failed reading stlink_cpu_id\n"); } else { printf("cpuid:impl_id = %0#x, variant = %#x\n", cpuid.implementer_id, cpuid.variant); printf("cpuid:part = %#x, rev = %#x\n", cpuid.part, cpuid.revision); } printf("-- read_sram\n"); static const uint32_t sram_base = STM32_SRAM_BASE; uint32_t off; for(off = 0; off < 16; off += 4) stlink_read_mem32(sl, sram_base + off, 4); printf("FP_CTRL\n"); stlink_read_mem32(sl, STM32_REG_CM3_FP_CTRL, 4); // no idea what reg this is... // stlink_read_mem32(sl, 0xe000ed90, 4); // no idea what register this is... // stlink_read_mem32(sl, 0xe000edf0, 4); // offset 0xC into TIM11 register? TIMx_DIER? // stlink_read_mem32(sl, 0x4001100c, 4); /* Test 32 bit write */ write_uint32(sl->q_buf, 0x01234567); stlink_write_mem32(sl, 0x200000a8, 4); write_uint32(sl->q_buf, 0x89abcdef); stlink_write_mem32(sl, 0x200000ac, 4); stlink_read_mem32(sl, 0x200000a8, 4); stlink_read_mem32(sl, 0x200000ac, 4); /* Test 8 bit write */ write_uint32(sl->q_buf, 0x01234567); stlink_write_mem8(sl, 0x200001a8, 3); write_uint32(sl->q_buf, 0x89abcdef); stlink_write_mem8(sl, 0x200001ac, 3); stlink_read_mem32(sl, 0x200001a8, 4); stlink_read_mem32(sl, 0x200001ac, 4); printf("-- status\n"); stlink_status(sl); printf("-- reset\n"); stlink_reset(sl, RESET_AUTO); stlink_force_debug(sl); /* Test reg write */ stlink_write_reg(sl, 0x01234567, 3); stlink_write_reg(sl, 0x89abcdef, 4); stlink_write_reg(sl, 0x12345678, 15); for(off = 0; off < 21; off += 1) stlink_read_reg(sl, off, ®s); stlink_read_all_regs(sl, ®s); printf("-- status\n"); stlink_status(sl); printf("-- step\n"); stlink_step(sl); printf("-- run\n"); stlink_run(sl, RUN_NORMAL); printf("-- exit_debug_mode\n"); stlink_exit_debug_mode(sl); stlink_close(sl); } return (0); } stlink-1.9.0/vcpkg.json000066400000000000000000000001011526027543100150270ustar00rootroot00000000000000{ "name": "stlink", "dependencies": [ "libusb" ] }