pax_global_header00006660000000000000000000000064145565505460014531gustar00rootroot0000000000000052 comment=40948aa3de78778f51af02d795327ac20fa385d3 stlink-1.8.0/000077500000000000000000000000001455655054600130435ustar00rootroot00000000000000stlink-1.8.0/.github/000077500000000000000000000000001455655054600144035ustar00rootroot00000000000000stlink-1.8.0/.github/ISSUE_TEMPLATE/000077500000000000000000000000001455655054600165665ustar00rootroot00000000000000stlink-1.8.0/.github/ISSUE_TEMPLATE/bug-report.md000066400000000000000000000027711455655054600212050ustar00rootroot00000000000000--- 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.8.0/.github/ISSUE_TEMPLATE/feature-request.md000066400000000000000000000030311455655054600222260ustar00rootroot00000000000000--- 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.8.0/.github/workflows/000077500000000000000000000000001455655054600164405ustar00rootroot00000000000000stlink-1.8.0/.github/workflows/c-cpp.yml000066400000000000000000000155421455655054600201740ustar00rootroot00000000000000name: C/C++ CI on: push: branches: [master, develop, testing] pull_request: branches: [master, develop, testing] jobs: # Linux job_linux_20_04_64_gcc: name: ubuntu-20.04 gcc runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 - name: Install dependencies run: sudo apt update && sudo apt-get install gcc-10 libusb-1.0.0-dev libgtk-3-dev rpm - name: make debug run: sudo make clean && make debug - name: make test run: sudo make clean && make test - name: make release run: sudo make clean && make release - name: sudo make install run: sudo make clean && sudo make install - name: sudo make package run: sudo make package - name: sudo make uninstall run: sudo make uninstall && sudo make clean job_linux_20_04_32_gcc: name: ubuntu-20.04 gcc 32-bit runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 - name: Install dependencies run: sudo apt update && sudo apt-get install gcc-10 libusb-1.0.0-dev libgtk-3-dev rpm - name: Set compiler flags run: | CFLAGS="$CFLAGS -m32" CXXFLAGS="$CXXFLAGS -m32" LDFLAGS="$LDFLAGS -m32" - name: make debug run: sudo make clean && make debug - name: make test run: sudo make clean && make test - name: make release run: sudo make clean && make release - name: sudo make install run: sudo make clean && sudo make install - name: sudo make package run: sudo make package - name: sudo make uninstall run: sudo make uninstall && sudo make clean job_linux_20_04_64_clang: name: ubuntu-20.04 clang runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 - name: Install dependencies run: sudo apt update && sudo apt-get install clang-12 libusb-1.0.0-dev libgtk-3-dev rpm - name: make debug run: sudo make clean && make debug - name: make test run: sudo make clean && make test - name: make release run: sudo make clean && make release - name: sudo make install run: sudo make clean && sudo make install - name: sudo make package run: sudo make package - name: sudo make uninstall run: sudo make uninstall && sudo make clean job_linux_20_04_32_clang: name: ubuntu-20.04 clang 32-bit runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 - name: Install dependencies run: sudo apt update && sudo apt-get install clang-12 libusb-1.0.0-dev libgtk-3-dev rpm - name: Set compiler flags run: | CFLAGS="$CFLAGS -m32" CXXFLAGS="$CXXFLAGS -m32" LDFLAGS="$LDFLAGS -m32" - name: make debug run: sudo make clean && make debug - name: make test run: sudo make clean && make test - name: make release run: sudo make clean && make release - name: sudo make install run: sudo make clean && sudo make install - name: sudo make package run: sudo make package - name: sudo make uninstall run: sudo make uninstall && sudo make clean job_linux_22_04_64_gcc: name: ubuntu-22.04 gcc runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v2 - name: Install dependencies run: sudo apt update && sudo apt-get install gcc-12 libusb-1.0.0-dev libgtk-4-dev rpm - name: make debug run: sudo make clean && make debug - name: make test run: sudo make clean && make test - name: make release run: sudo make clean && make release - name: sudo make install run: sudo make clean && sudo make install - name: sudo make package run: sudo make package - name: sudo make uninstall run: sudo make uninstall && sudo make clean job_linux_22_04_32_gcc: name: ubuntu-22.04 gcc 32-bit runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v2 - name: Install dependencies run: sudo apt update && sudo apt-get install gcc-12 libusb-1.0.0-dev libgtk-4-dev rpm - name: Set compiler flags run: | CFLAGS="$CFLAGS -m32" CXXFLAGS="$CXXFLAGS -m32" LDFLAGS="$LDFLAGS -m32" - name: make debug run: sudo make clean && make debug - name: make test run: sudo make clean && make test - name: make release run: sudo make clean && make release - name: sudo make install run: sudo make clean && sudo make install - name: sudo make package run: sudo make package - name: sudo make uninstall run: sudo make uninstall && sudo make clean job_linux_22_04_64_clang: name: ubuntu-22.04 clang runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v2 - name: Install dependencies run: sudo apt update && sudo apt-get install clang-14 libusb-1.0.0-dev libgtk-4-dev rpm - name: make debug run: sudo make clean && make debug - name: make test run: sudo make clean && make test - name: make release run: sudo make clean && make release - name: sudo make install run: sudo make clean && sudo make install - name: sudo make package run: sudo make package - name: sudo make uninstall run: sudo make uninstall && sudo make clean job_linux_22_04_32_clang: name: ubuntu-22.04 clang 32-bit runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v2 - name: Install dependencies run: sudo apt update && sudo apt-get install clang-14 libusb-1.0.0-dev libgtk-4-dev rpm - name: Set compiler flags run: | CFLAGS="$CFLAGS -m32" CXXFLAGS="$CXXFLAGS -m32" LDFLAGS="$LDFLAGS -m32" - name: make debug run: sudo make clean && make debug - name: make test run: sudo make clean && make test - name: make release run: sudo make clean && make release - name: sudo make install run: sudo make clean && sudo make install - name: sudo make package run: sudo make package - name: sudo make uninstall run: sudo make uninstall && sudo make clean # Linux MinGW cross compliation # job_linux_22_04_cross: # name: ubuntu-22.04 mingw64 # runs-on: ubuntu-22.04 # steps: # - uses: actions/checkout@v2 # - name: Install dependencies # run: sudo apt-get install gcc-12 libusb-1.0.0-dev libgtk-4-dev rpm mingw-w64 # - name: Building Release for Windows (x86-64) ... # run: sudo mkdir -p build-mingw && cd build-mingw && sudo cmake \ # -DCMAKE_SYSTEM_NAME=Windows \ # -DTOOLCHAIN_PREFIX=x86_64-w64-mingw32 \ # -DCMAKE_TOOLCHAIN_FILE=$PWD/../cmake/modules/set_toolchain.cmake \ # -DCMAKE_INSTALL_PREFIX=$PWD/install $PWD && \ # sudo make && sudo rm -rf build-mingw && cd - stlink-1.8.0/.github/workflows/codeql-analysis.yml000066400000000000000000000047771455655054600222720ustar00rootroot00000000000000# 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-10 libusb-1.0.0-dev libgtk-3-dev rpm - name: Checkout repository uses: actions/checkout@v2 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v2 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@v2 # ℹ️ 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@v2 stlink-1.8.0/.gitignore000066400000000000000000000001231455655054600150270ustar00rootroot00000000000000build build-mingw-32 build-mingw-64 .project .cmake/ .vscode/ obj-* *.user* *.swpstlink-1.8.0/.version000066400000000000000000000000061455655054600145250ustar00rootroot000000000000001.8.0 stlink-1.8.0/CHANGELOG.md000066400000000000000000001752451455655054600146720ustar00rootroot00000000000000# stlink Changelog # v1.8.0 Release date: 2024-02-01 This release drops support for macOS and some older operating systems. Check project README for details. Removed Travis CI integration as it is no longer functional. Updated system requirements: - `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)) # 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.8.0/CMakeLists.txt000066400000000000000000000343131455655054600156070ustar00rootroot00000000000000### # General cmake settings ### cmake_minimum_required(VERSION 3.10.2) cmake_policy(SET CMP0042 NEW) set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_EXTENSIONS ON) ### # # Default cmake directories: # # | Target Type | GNUInstallDirs Variable | Built-In Default | # | --- | --- | --- | # | RUNTIME | ${CMAKE_INSTALL_BINDIR} | bin | # | LIBRARY | ${CMAKE_INSTALL_LIBDIR} | lib | # | ARCHIVE | ${CMAKE_INSTALL_LIBDIR} | lib | # | PRIVATE_HEADER | ${CMAKE_INSTALL_INCLUDEDIR} | include | # | PUBLIC_HEADER | ${CMAKE_INSTALL_INCLUDEDIR} | include | # | FILE_SET (type HEADERS) | ${CMAKE_INSTALL_INCLUDEDIR} | include | # # | TYPE Argument | GNUInstallDirs Variable | Built-In Default | # | --- | --- | --- | # | BIN | ${CMAKE_INSTALL_BINDIR} | bin | # | SBIN | ${CMAKE_INSTALL_SBINDIR} | sbin | # | LIB | ${CMAKE_INSTALL_LIBDIR} | lib | # | INCLUDE | ${CMAKE_INSTALL_INCLUDEDIR} | include | # | SYSCONF | ${CMAKE_INSTALL_SYSCONFDIR} | etc | # | SHAREDSTATE | ${CMAKE_INSTALL_SHARESTATEDIR} | com | # | LOCALSTATE | ${CMAKE_INSTALL_LOCALSTATEDIR} | var | # | RUNSTATE | ${CMAKE_INSTALL_RUNSTATEDIR} | /run | # | DATA | ${CMAKE_INSTALL_DATADIR} | | # | INFO | ${CMAKE_INSTALL_INFODIR} | /info | # | LOCALE | ${CMAKE_INSTALL_LOCALEDIR} | /locale | # | MAN | ${CMAKE_INSTALL_MANDIR} | /man | # | DOC | ${CMAKE_INSTALL_DOCDIR} | /doc | # # ${CMAKE_BINARY_DIR} # This is the full path to the top level of the current CMake build tree. # For an in-source build, this would be the same as CMAKE_SOURCE_DIR. # # ${CMAKE_SOURCE_DIR} # This is the full path to the top level of the current CMake source tree. # For an in-source build, this would be the same as CMAKE_BINARY_DIR. # # ${CMAKE_CURRENT_BINARY_DIR} # The path to the binary directory currently being processed. # This is the full path to the build directory that is currently being processed by cmake. # Each directory added by add_subdirectory() will create a binary directory in the build tree, # and as it is being processed this variable will be set. # For in-source builds this is the current source directory being processed. # # ${CMAKE_CURRENT_SOURCE_DIR} # The path to the source directory currently being processed. # This is the full path to the source directory that is currently being processed by cmake. # ### ### # 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 # Define install directory for st-link shared files cmake_host_system_information(RESULT OS_NAME QUERY OS_NAME) message(STATUS "Checking for OS_NAME: ${OS_NAME}") ## Set C build flags if (NOT MSVC) include(${CMAKE_MODULE_PATH}/c_flags.cmake) else () message(STATUS "MSVC C Flags override to /MT") set(CMAKE_C_FLAGS_DEBUG_INIT "/D_DEBUG /MTd /Zi /Ob0 /Od /RTC1") set(CMAKE_C_FLAGS_MINSIZEREL_INIT "/MT /O1 /Ob1 /D NDEBUG") set(CMAKE_C_FLAGS_RELEASE_INIT "/MT /O2 /Ob2 /D NDEBUG") set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "/MT /Zi /O2 /Ob1 /D NDEBUG") endif() ### # Dependencies ### find_package(libusb REQUIRED) ## Check for system-specific additional header files and libraries include(CheckIncludeFile) include(CheckLibraryExists) CHECK_LIBRARY_EXISTS(ssp __stack_chk_fail "" _stack_chk_fail_exists) if (_stack_chk_fail_exists) if (WIN32) set(SSP_LIB -static ssp) else () set(SSP_LIB ssp) endif() else () set(SSP_LIB "") endif() CHECK_INCLUDE_FILE(sys/mman.h STLINK_HAVE_SYS_MMAN_H) if (STLINK_HAVE_SYS_MMAN_H) add_definitions(-DSTLINK_HAVE_SYS_MMAN_H) endif() CHECK_INCLUDE_FILE(sys/time.h STLINK_HAVE_SYS_TIME_H) if (STLINK_HAVE_SYS_TIME_H) add_definitions(-DSTLINK_HAVE_SYS_TIME_H) endif() CHECK_INCLUDE_FILE(unistd.h STLINK_HAVE_UNISTD_H) if (STLINK_HAVE_UNISTD_H) add_definitions(-DSTLINK_HAVE_UNISTD_H) endif() CHECK_INCLUDE_FILE(dirent.h STLINK_HAVE_DIRENT_H) if (STLINK_HAVE_DIRENT_H) add_definitions(-DSTLINK_HAVE_DIRENT_H) endif() if (MSVC) # Use string.h rather than strings.h and disable annoying warnings add_definitions(-DHAVE_STRING_H -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_WARNINGS /wd4710) endif() ### # Main build process ### ## Define include directories to avoid absolute paths for header defines include_directories(${LIBUSB_INCLUDE_DIR}) include_directories(${PROJECT_SOURCE_DIR}/inc) # contains top-level header files include_directories(${PROJECT_BINARY_DIR}/inc) # contains version.h include_directories(src) include_directories(src/st-flash) include_directories(src/st-info) include_directories(src/st-trace) include_directories(src/st-util) include_directories(src/stlink-lib) ## Set 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() ## Subordinate CMakeLists for version config & header installation add_subdirectory(inc) ## Define source- and headerfiles for stlink library set(STLINK_HEADERS inc/backend.h inc/stlink.h inc/stm32.h inc/stm32flash.h src/stlink-lib/calculate.h src/stlink-lib/chipid.h src/stlink-lib/commands.h src/stlink-lib/common_flash.h src/stlink-lib/flash_loader.h src/stlink-lib/helper.h src/stlink-lib/libusb_settings.h src/stlink-lib/lib_md5.h src/stlink-lib/logging.h src/stlink-lib/map_file.h src/stlink-lib/md5.h src/stlink-lib/option_bytes.h src/stlink-lib/register.h src/stlink-lib/sg.h src/stlink-lib/usb.h ) set(STLINK_SOURCE src/stlink-lib/calculate.c src/stlink-lib/chipid.c src/stlink-lib/common_flash.c src/stlink-lib/common.c src/stlink-lib/flash_loader.c src/stlink-lib/helper.c src/stlink-lib/logging.c src/stlink-lib/map_file.c src/stlink-lib/lib_md5.c src/stlink-lib/md5.c src/stlink-lib/option_bytes.c src/stlink-lib/read_write.c src/stlink-lib/sg.c src/stlink-lib/usb.c ) if (WIN32) include_directories(src/win32) set(STLINK_SOURCE "${STLINK_SOURCE};src/win32/win32_socket.c") set(STLINK_HEADERS "${STLINK_HEADERS};src/win32/win32_socket.h") if (MSVC) # Add drop-in replacement for unistd.h to sources include_directories(src/win32/unistd) set(STLINK_HEADERS "${STLINK_HEADERS};src/win32/unistd/unistd.h") endif() if (NOT STLINK_HAVE_SYS_MMAN_H) include_directories(src/win32/mmap) set(STLINK_SOURCE "${STLINK_SOURCE};src/win32/mmap.c") set(STLINK_HEADERS "${STLINK_HEADERS};src/win32/mmap.h") endif() if (NOT STLINK_HAVE_SYS_TIME_H) set(STLINK_SOURCE "${STLINK_SOURCE};src/win32/sys_time.c") set(STLINK_HEADERS "${STLINK_HEADERS};src/win32/sys_time.h") endif() endif() ## Include test execution for test-targets for target Debug if (${CMAKE_BUILD_TYPE} MATCHES "Debug") include(CTest) endif() ### # Libraries ### # Set the environment variable LD_LIBRARY_PATH to point to /usr/local/lib (per default). execute_process(COMMAND bash -c "export LD_LIBRARY_PATH=${CMAKE_INSTALL_LIBDIR}") ### # Shared library ### # Set library name set(STLINK_LIB_SHARED ${PROJECT_NAME}-shared) add_library(${STLINK_LIB_SHARED} SHARED ${STLINK_HEADERS} ${STLINK_SOURCE}) set(STLINK_SHARED_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}) message(STATUS "STLINK_LIB_SHARED: ${STLINK_LIB_SHARED}") message(STATUS "PROJECT_VERSION_MAJOR: ${PROJECT_VERSION_MAJOR}") 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} ) # Link shared library if (WIN32) # ... with Windows libraries target_link_libraries(${STLINK_LIB_SHARED} ${LIBUSB_LIBRARY} ${SSP_LIB} wsock32 ws2_32) else () target_link_libraries(${STLINK_LIB_SHARED} ${LIBUSB_LIBRARY} ${SSP_LIB}) endif() install(TARGETS ${STLINK_LIB_SHARED} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) # Copy libusb DLL-library to binary output folder if (WIN32) file(COPY ${LIBUSB_WIN_OUTPUT_FOLDER}/MinGW64/dll/libusb-1.0.dll DESTINATION ${CMAKE_INSTALL_BINDIR}) file(COPY ${LIBUSB_WIN_OUTPUT_FOLDER}/MinGW64/dll/libusb-1.0.dll DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}) 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_SOURCE}) set(STLINK_STATIC_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}) message(STATUS "STLINK_LIB_STATIC: ${STLINK_LIB_STATIC}") message(STATUS "PROJECT_VERSION_MAJOR: ${PROJECT_VERSION_MAJOR}") 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 if (WIN32) # ... with Windows libraries target_link_libraries(${STLINK_LIB_STATIC} ${LIBUSB_LIBRARY} ${SSP_LIB} wsock32 ws2_32) else () target_link_libraries(${STLINK_LIB_STATIC} ${LIBUSB_LIBRARY} ${SSP_LIB}) endif() install(TARGETS ${STLINK_LIB_STATIC} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) ### # Build toolset executables ### set(ST-FLASH_SOURCES src/st-flash/flash.c src/st-flash/flash_opts.c) set(ST-INFO_SOURCES src/st-info/info.c) set(ST-UTIL_SOURCES src/st-util/gdb-remote.c src/st-util/gdb-server.c src/st-util/semihosting.c) set(ST-TRACE_SOURCES src/st-trace/trace.c) if (MSVC) # Add getopt to sources include_directories(src/win32/getopt) set(ST-UTIL_SOURCES "${ST-UTIL_SOURCES};src/win32/getopt/getopt.c") set(ST-TRACE_SOURCES "${ST-TRACE_SOURCES};src/win32/getopt/getopt.c") endif() add_executable(st-flash ${ST-FLASH_SOURCES}) add_executable(st-info ${ST-INFO_SOURCES}) add_executable(st-util ${ST-UTIL_SOURCES}) add_executable(st-trace ${ST-TRACE_SOURCES}) if (WIN32) target_link_libraries(st-flash ${STLINK_LIB_STATIC} ${SSP_LIB}) target_link_libraries(st-info ${STLINK_LIB_STATIC} ${SSP_LIB}) target_link_libraries(st-util ${STLINK_LIB_STATIC} ${SSP_LIB}) target_link_libraries(st-trace ${STLINK_LIB_STATIC} ${SSP_LIB}) else () target_link_libraries(st-flash ${STLINK_LIB_SHARED} ${SSP_LIB}) target_link_libraries(st-info ${STLINK_LIB_SHARED} ${SSP_LIB}) target_link_libraries(st-util ${STLINK_LIB_SHARED} ${SSP_LIB}) target_link_libraries(st-trace ${STLINK_LIB_SHARED} ${SSP_LIB}) endif() install(TARGETS st-flash DESTINATION ${CMAKE_INSTALL_BINDIR}) install(TARGETS st-info DESTINATION ${CMAKE_INSTALL_BINDIR}) install(TARGETS st-util DESTINATION ${CMAKE_INSTALL_BINDIR}) install(TARGETS st-trace DESTINATION ${CMAKE_INSTALL_BINDIR}) ### # 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 configuration files if (WIN32) set(CMAKE_CHIPS_DIR ${CMAKE_INSTALL_PREFIX}/config/chips) else () set(CMAKE_CHIPS_DIR ${CMAKE_INSTALL_FULL_DATADIR}/${PROJECT_NAME}/chips) endif () add_definitions( -DSTLINK_CHIPS_DIR="${CMAKE_CHIPS_DIR}" ) file(GLOB CHIP_FILES ${CMAKE_SOURCE_DIR}/config/chips/*.chip) install(FILES ${CHIP_FILES} DESTINATION ${CMAKE_CHIPS_DIR}) # Documentation / manpages option(STLINK_GENERATE_MANPAGES "Generate manpages with pandoc" OFF) add_subdirectory(doc/man) # contains subordinate CMakeLists to generate manpages add_subdirectory(src/stlink-gui) # contains subordinate CMakeLists to build GUI add_subdirectory(tests) # contains subordinate CMakeLists to build test executables add_subdirectory(cmake/packaging) # contains subordinate CMakeLists to build packages ### # 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.8.0/CODE_OF_CONDUCT.md000066400000000000000000000064241455655054600156500ustar00rootroot00000000000000# 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 at texane@gmail.com. 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.8.0/CONTRIBUTING.md000066400000000000000000000115551455655054600153030ustar00rootroot00000000000000# 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 `develop` 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.8.0/LICENSE.md000066400000000000000000000027561455655054600144610ustar00rootroot00000000000000BSD 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.8.0/Makefile000066400000000000000000000027371455655054600145140ustar00rootroot00000000000000## # 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.8.0/README.md000066400000000000000000000147601455655054600143320ustar00rootroot00000000000000# 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.8.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 STM32L Discovery and STM32 Nucleo boards - **STLINK/V2-1** - transport layer: raw USB commands - on-board on some STM32 Nucleo boards - **STLINK-V3** - transport layer: raw USB commands - stand-alone programmer (STLINK-V3SET, STLINK-V3MINI, STLINK-V3MODS) - on-board on some 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-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) on the release page of the project. 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 systems and to `C:\Program Files (x86)\` on 64-bit systems (the toolset is 32-bit). Alternatively one may compile and install from source as described in our [compiling manual](doc/compiling.md#Windows). **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**: **Support for macOS has been dropped with v1.8.0.** Please use v1.7.0 instead, **but note that this version is no longer maintained and supported!** ## 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.8.0/SECURITY.md000066400000000000000000000013601455655054600146340ustar00rootroot00000000000000# 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.8.0 | :white_check_mark: | | 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.8.0/cmake/000077500000000000000000000000001455655054600141235ustar00rootroot00000000000000stlink-1.8.0/cmake/modules/000077500000000000000000000000001455655054600155735ustar00rootroot00000000000000stlink-1.8.0/cmake/modules/Findlibusb.cmake000066400000000000000000000130251455655054600206570ustar00rootroot00000000000000# Findlibusb.cmake # Find and install external libusb library # Once done this will define # # LIBUSB_FOUND libusb present on system # LIBUSB_INCLUDE_DIR the libusb include directory # LIBUSB_LIBRARY the libraries needed to use libusb # LIBUSB_DEFINITIONS compiler switches required for using libusb include(FindPackageHandleStandardArgs) if (CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") # FreeBSD; libusb is integrated into the system FIND_PATH( LIBUSB_INCLUDE_DIR NAMES libusb.h HINTS /usr/include ) set(LIBUSB_NAME usb) find_library( LIBUSB_LIBRARY NAMES ${LIBUSB_NAME} HINTS /usr /usr/local /opt ) FIND_PACKAGE_HANDLE_STANDARD_ARGS(libusb DEFAULT_MSG LIBUSB_LIBRARY LIBUSB_INCLUDE_DIR) mark_as_advanced(LIBUSB_INCLUDE_DIR LIBUSB_LIBRARY) if (NOT LIBUSB_FOUND) message(FATAL_ERROR "Expected libusb library not found on your system! Verify your system integrity.") endif() elseif (CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") # OpenBSD; libusb-1.0 is available from ports FIND_PATH( LIBUSB_INCLUDE_DIR NAMES libusb.h HINTS /usr/local/include PATH_SUFFIXES libusb-1.0 ) set(LIBUSB_NAME usb-1.0) find_library( LIBUSB_LIBRARY NAMES ${LIBUSB_NAME} HINTS /usr/local ) FIND_PACKAGE_HANDLE_STANDARD_ARGS(libusb DEFAULT_MSG LIBUSB_LIBRARY LIBUSB_INCLUDE_DIR) mark_as_advanced(LIBUSB_INCLUDE_DIR LIBUSB_LIBRARY) if (NOT LIBUSB_FOUND) message(FATAL_ERROR "No libusb-1.0 library found on your system! Install libusb-1.0 from ports or packages.") endif() elseif (WIN32 OR (EXISTS "/etc/debian_version" AND MINGW)) # Windows or MinGW-toolchain on Debian # MinGW/MSYS/MSVC: 64-bit or 32-bit? if (CMAKE_SIZEOF_VOID_P EQUAL 8) message(STATUS "=== Building for Windows (x86-64) ===") set(ARCH 64) else () message(STATUS "=== Building for Windows (i686) ===") set(ARCH 32) endif() if (WIN32 AND NOT EXISTS "/etc/debian_version") # Skip this for Debian... # Preparations for installing libusb library set(LIBUSB_WIN_VERSION 1.0.25) # set libusb version set(LIBUSB_WIN_ARCHIVE libusb-${LIBUSB_WIN_VERSION}.7z) if (WIN32 AND NOT EXISTS "/etc/debian_version") # ... on native Windows systems set(LIBUSB_WIN_ARCHIVE_PATH ${CMAKE_BINARY_DIR}/${LIBUSB_WIN_ARCHIVE}) set(LIBUSB_WIN_OUTPUT_FOLDER ${CMAKE_BINARY_DIR}/3rdparty/libusb-${LIBUSB_WIN_VERSION}) elseif (EXISTS "/etc/debian_version" AND MINGW) # ... only for cross-building on Debian set(LIBUSB_WIN_ARCHIVE_PATH ${CMAKE_SOURCE_DIR}/build-mingw-${ARCH}/${LIBUSB_WIN_ARCHIVE}) set(LIBUSB_WIN_OUTPUT_FOLDER ${CMAKE_SOURCE_DIR}/build-mingw-${ARCH}/3rdparty/libusb-${LIBUSB_WIN_VERSION}) endif() # Get libusb package if (EXISTS ${LIBUSB_WIN_ARCHIVE_PATH}) # ... should the package be already there (for whatever reason) message(STATUS "libusb archive already in build folder") else () # ... download the package message(STATUS "downloading libusb ${LIBUSB_WIN_VERSION}") file(DOWNLOAD https://sourceforge.net/projects/libusb/files/libusb-1.0/libusb-${LIBUSB_WIN_VERSION}/libusb-${LIBUSB_WIN_VERSION}.7z/download ${LIBUSB_WIN_ARCHIVE_PATH} EXPECTED_MD5 aabe177bde869bfad34278335eaf8955 ) endif() file(MAKE_DIRECTORY ${LIBUSB_WIN_OUTPUT_FOLDER}) # Extract libusb package with cmake execute_process( COMMAND ${CMAKE_COMMAND} -E tar xv ${LIBUSB_WIN_ARCHIVE_PATH} WORKING_DIRECTORY ${LIBUSB_WIN_OUTPUT_FOLDER} ) # Find path to libusb library FIND_PATH( LIBUSB_INCLUDE_DIR NAMES libusb.h HINTS ${LIBUSB_WIN_OUTPUT_FOLDER}/include PATH_SUFFIXES libusb-1.0 NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH ) if (MINGW OR MSYS) set(LIBUSB_NAME usb-1.0) find_library( LIBUSB_LIBRARY NAMES ${LIBUSB_NAME} HINTS ${LIBUSB_WIN_OUTPUT_FOLDER}/MinGW${ARCH}/static NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH ) elseif (MSVC) set(LIBUSB_NAME libusb-1.0.lib) find_library( LIBUSB_LIBRARY NAMES ${LIBUSB_NAME} HINTS ${LIBUSB_WIN_OUTPUT_FOLDER}/MS${ARCH}/dll NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH ) endif() message(STATUS "Missing libusb library has been installed") endif() FIND_PACKAGE_HANDLE_STANDARD_ARGS(libusb DEFAULT_MSG LIBUSB_LIBRARY LIBUSB_INCLUDE_DIR) mark_as_advanced(LIBUSB_INCLUDE_DIR LIBUSB_LIBRARY) else () # all other OS (unix-based) FIND_PATH( LIBUSB_INCLUDE_DIR NAMES libusb.h HINTS /usr /usr/local /opt PATH_SUFFIXES libusb-1.0 ) set(LIBUSB_NAME usb-1.0) find_library( LIBUSB_LIBRARY NAMES ${LIBUSB_NAME} HINTS /usr /usr/local /opt ) FIND_PACKAGE_HANDLE_STANDARD_ARGS(libusb DEFAULT_MSG LIBUSB_LIBRARY LIBUSB_INCLUDE_DIR) mark_as_advanced(LIBUSB_INCLUDE_DIR LIBUSB_LIBRARY) if (NOT LIBUSB_FOUND) message(FATAL_ERROR "libusb library not found on your system! Install libusb 1.0.x from your package repository.") endif() endif() stlink-1.8.0/cmake/modules/c_flags.cmake000066400000000000000000000032161455655054600201750ustar00rootroot00000000000000# 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("-O") add_cflag_if_supported("-D_FORTIFY_SOURCE=2") add_cflag_if_supported("-fstrict-aliasing") 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("-Wshorten-64-to-32") add_cflag_if_supported("-Wimplicit-function-declaration") ## # On 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() if (NOT (WIN32 OR (EXISTS "/etc/debian_version" AND MINGW))) add_cflag_if_supported("-fPIC") endif() if (${CMAKE_BUILD_TYPE} MATCHES "Debug") add_cflag_if_supported("-ggdb") else () add_cflag_if_supported("-Werror") endif() stlink-1.8.0/cmake/modules/get_version.cmake000066400000000000000000000110601455655054600211170ustar00rootroot00000000000000# 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.8.0/cmake/modules/pandocology.cmake000066400000000000000000000433241455655054600211210ustar00rootroot00000000000000################################################################################ ## ## 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.8.0/cmake/modules/set_toolchain.cmake000066400000000000000000000014241455655054600214310ustar00rootroot00000000000000# set_toolchain.cmake # Toolchain file for 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) stlink-1.8.0/cmake/packaging/000077500000000000000000000000001455655054600160475ustar00rootroot00000000000000stlink-1.8.0/cmake/packaging/CMakeLists.txt000066400000000000000000000001431455655054600206050ustar00rootroot00000000000000add_subdirectory(deb) add_subdirectory(rpm) add_subdirectory(windows) include(cpack_config.cmake) stlink-1.8.0/cmake/packaging/cpack_config.cmake000066400000000000000000000105631455655054600214640ustar00rootroot00000000000000# 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 is available on Debian/Ubuntu only 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.13.0), libusb-1.0-0-dev (>= 1.0.22)") 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.8.0/cmake/packaging/deb/000077500000000000000000000000001455655054600166015ustar00rootroot00000000000000stlink-1.8.0/cmake/packaging/deb/CMakeLists.txt000066400000000000000000000000001455655054600213270ustar00rootroot00000000000000stlink-1.8.0/cmake/packaging/deb/changelog000066400000000000000000000006431455655054600204560ustar00rootroot00000000000000stlink (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.8.0/cmake/packaging/deb/control000066400000000000000000000006311455655054600202040ustar00rootroot00000000000000Source: stlink Priority: optional Maintainer: Nightwalker-87 Build-Depends: cmake (>= 3.13.0), dh-cmake, debhelper (>= 9), libusb-1.0-0-dev (>= 1.0.22), libgtk-3-dev (>= 3.22.30) 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.8.0/cmake/packaging/deb/copyright000066400000000000000000000037031455655054600205370ustar00rootroot00000000000000Format: 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.8.0/cmake/packaging/deb/postinst000066400000000000000000000001201455655054600204000ustar00rootroot00000000000000#!/bin/bash # This `DEBIAN/postinst` script is run post-installation depmod -a stlink-1.8.0/cmake/packaging/deb/rules000077500000000000000000000007671455655054600176730ustar00rootroot00000000000000#!/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.8.0/cmake/packaging/rpm/000077500000000000000000000000001455655054600166455ustar00rootroot00000000000000stlink-1.8.0/cmake/packaging/rpm/CMakeLists.txt000066400000000000000000000000001455655054600213730ustar00rootroot00000000000000stlink-1.8.0/cmake/packaging/rpm/changelog000066400000000000000000000003601455655054600205160ustar00rootroot00000000000000* 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.8.0/cmake/packaging/windows/000077500000000000000000000000001455655054600175415ustar00rootroot00000000000000stlink-1.8.0/cmake/packaging/windows/CMakeLists.txt000066400000000000000000000000001455655054600222670ustar00rootroot00000000000000stlink-1.8.0/cmake/packaging/windows/generate_binaries.sh000066400000000000000000000013061455655054600235430ustar00rootroot00000000000000### # Build package with binaries for Windows ### # Install this cross-compiler toolchain: #sudo apt-get install mingw-w64 # x86_64 mkdir build-mingw-64 cd build-mingw-64 cmake -DCMAKE_SYSTEM_NAME=Windows \ -DTOOLCHAIN_PREFIX=x86_64-w64-mingw32 \ -DCMAKE_TOOLCHAIN_FILE=./../cmake/modules/set_toolchain.cmake .. make package sudo cp dist/*.zip ../build/Release/dist make clean cd .. rm -rf build-mingw-64 # i686 mkdir build-mingw-32 cd build-mingw-32 cmake -DCMAKE_SYSTEM_NAME=Windows \ -DTOOLCHAIN_PREFIX=i686-w64-mingw32 \ -DCMAKE_TOOLCHAIN_FILE=./../cmake/modules/set_toolchain.cmake .. make package sudo cp dist/*.zip ../build/Release/dist make clean cd .. rm -rf build-mingw-32 stlink-1.8.0/cmake_uninstall.cmake.in000066400000000000000000000016201455655054600176220ustar00rootroot00000000000000if (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}") exec_program("@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" OUTPUT_VARIABLE rm_out RETURN_VALUE rm_retval ) if (NOT "${rm_retval}" STREQUAL 0) message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") endif () else (IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") message(STATUS "File $ENV{DESTDIR}${file} does not exist.") endif () endforeach () stlink-1.8.0/config/000077500000000000000000000000001455655054600143105ustar00rootroot00000000000000stlink-1.8.0/config/chips/000077500000000000000000000000001455655054600154165ustar00rootroot00000000000000stlink-1.8.0/config/chips/C011xx.chip000066400000000000000000000006371455655054600172550ustar00rootroot00000000000000# 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_C0_OPTION_BYTES_BASE option_size 0x80 // 128 B flags none stlink-1.8.0/config/chips/C031xx.chip000066400000000000000000000006401455655054600172510ustar00rootroot00000000000000# 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_C0_OPTION_BYTES_BASE option_size 0x80 // 128 B flags none stlink-1.8.0/config/chips/F03x.chip000066400000000000000000000006441455655054600170070ustar00rootroot00000000000000# 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_F0_OPTION_BYTES_BASE option_size 0x10 // 16 B flags none stlink-1.8.0/config/chips/F04x.chip000066400000000000000000000006351455655054600170100ustar00rootroot00000000000000# 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_F0_OPTION_BYTES_BASE option_size 0x10 // 16 B flags none stlink-1.8.0/config/chips/F05x.chip000066400000000000000000000006341455655054600170100ustar00rootroot00000000000000# 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_F0_OPTION_BYTES_BASE option_size 0x10 // 16 B flags none stlink-1.8.0/config/chips/F07x.chip000066400000000000000000000006421455655054600170110ustar00rootroot00000000000000# 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_F0_OPTION_BYTES_BASE option_size 0x10 // 16 B flags none stlink-1.8.0/config/chips/F09x.chip000066400000000000000000000006401455655054600170110ustar00rootroot00000000000000# 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_F0_OPTION_BYTES_BASE option_size 0x10 // 16 B flags none stlink-1.8.0/config/chips/F1xx_CL.chip000066400000000000000000000007061455655054600174720ustar00rootroot00000000000000# 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_F0_OPTION_BYTES_BASE option_size 0x10 // 16 B flags swo stlink-1.8.0/config/chips/F1xx_HD.chip000066400000000000000000000006521455655054600174670ustar00rootroot00000000000000# 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_F0_OPTION_BYTES_BASE option_size 0x10 // 16 B flags swo stlink-1.8.0/config/chips/F1xx_LD.chip000066400000000000000000000006541455655054600174750ustar00rootroot00000000000000# 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_F0_OPTION_BYTES_BASE option_size 0x10 // 16 B flags swo stlink-1.8.0/config/chips/F1xx_MD.chip000066400000000000000000000006611455655054600174740ustar00rootroot00000000000000# 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_F0_OPTION_BYTES_BASE option_size 0x10 // 16 B flags swo stlink-1.8.0/config/chips/F1xx_VL_HD.chip000066400000000000000000000007001455655054600200620ustar00rootroot00000000000000# 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_F0_OPTION_BYTES_BASE option_size 0x10 // 16 B flags swo stlink-1.8.0/config/chips/F1xx_VL_MD_LD.chip000066400000000000000000000007601455655054600204540ustar00rootroot00000000000000# 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_F0_OPTION_BYTES_BASE option_size 0x10 // 16 B flags swo stlink-1.8.0/config/chips/F1xx_XLD.chip000066400000000000000000000006541455655054600176250ustar00rootroot00000000000000# 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_F0_OPTION_BYTES_BASE option_size 0x10 // 16 B flags swo stlink-1.8.0/config/chips/F2xx.chip000066400000000000000000000006341455655054600171150ustar00rootroot00000000000000# 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_F2_OPTION_BYTES_BASE option_size 0x4 // 4 B flags swo stlink-1.8.0/config/chips/F301_F302_F318.chip000066400000000000000000000007441455655054600200740ustar00rootroot00000000000000# 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_F0_OPTION_BYTES_BASE option_size 0x10 // 16 B flags swo stlink-1.8.0/config/chips/F302_F303_F358.chip000066400000000000000000000007311455655054600200760ustar00rootroot00000000000000# 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_F0_OPTION_BYTES_BASE option_size 0x10 // 16 B flags swo stlink-1.8.0/config/chips/F302_F303_F398_HD.chip000066400000000000000000000007711455655054600204610ustar00rootroot00000000000000# 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_F0_OPTION_BYTES_BASE option_size 0x10 // 16 B flags swo stlink-1.8.0/config/chips/F303_F328_F334.chip000066400000000000000000000007301455655054600200770ustar00rootroot00000000000000# 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_F0_OPTION_BYTES_BASE option_size 0x10 // 16 B flags swo stlink-1.8.0/config/chips/F37x.chip000066400000000000000000000006361455655054600170170ustar00rootroot00000000000000# 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_F0_OPTION_BYTES_BASE option_size 0x10 // 16 B flags swo stlink-1.8.0/config/chips/F401xB_xC.chip000066400000000000000000000005501455655054600176210ustar00rootroot00000000000000# 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.8.0/config/chips/F401xD_xE.chip000066400000000000000000000006471455655054600176340ustar00rootroot00000000000000# 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_F4_OPTION_BYTES_BASE option_size 0x4 // 4 B flags swo stlink-1.8.0/config/chips/F410.chip000066400000000000000000000005351455655054600167000ustar00rootroot00000000000000# 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.8.0/config/chips/F411xC_xE.chip000066400000000000000000000005521455655054600176270ustar00rootroot00000000000000# 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 0x0 option_size 0x0 flags swo stlink-1.8.0/config/chips/F412.chip000066400000000000000000000005361455655054600167030ustar00rootroot00000000000000# 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.8.0/config/chips/F413_F423.chip000066400000000000000000000006131455655054600173760ustar00rootroot00000000000000# 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.8.0/config/chips/F42x_F43x.chip000066400000000000000000000006151455655054600176140ustar00rootroot00000000000000# 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.8.0/config/chips/F446.chip000066400000000000000000000006371455655054600167140ustar00rootroot00000000000000# 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_F4_OPTION_BYTES_BASE option_size 0x10 // 16 B flags swo stlink-1.8.0/config/chips/F46x_F47x.chip000066400000000000000000000006161455655054600176250ustar00rootroot00000000000000# 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.8.0/config/chips/F4x5_F4x7.chip000066400000000000000000000007111455655054600176200ustar00rootroot00000000000000# 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_F4_OPTION_BYTES_BASE option_size 0x4 // 4 B flags swo stlink-1.8.0/config/chips/F72x_F73x.chip000066400000000000000000000006601455655054600176220ustar00rootroot00000000000000# 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_F7_OPTION_BYTES_BASE option_size 0x20 // 32 B flags swo stlink-1.8.0/config/chips/F74x_F75x.chip000066400000000000000000000006541455655054600176310ustar00rootroot00000000000000# 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_F7_OPTION_BYTES_BASE option_size 0x20 // 32 B flags swo stlink-1.8.0/config/chips/F76x_F77x.chip000066400000000000000000000010231455655054600176240ustar00rootroot00000000000000# 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_F7_OPTION_BYTES_BASE /* Used for reading back option bytes, writing uses FLASH_F7_OPTCR and FLASH_F7_OPTCR1 */ option_size 0x20 // 32 B flags swo dualbank stlink-1.8.0/config/chips/G03x_G04x.chip000066400000000000000000000007211455655054600176060ustar00rootroot00000000000000# 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_G0_OPTION_BYTES_BASE option_size 0x80 // 128 B flags none stlink-1.8.0/config/chips/G05x_G06x.chip000066400000000000000000000007071455655054600176160ustar00rootroot00000000000000# 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_G0_OPTION_BYTES_BASE option_size 0x80 // 128 B flags none stlink-1.8.0/config/chips/G07x_G08x.chip000066400000000000000000000007071455655054600176220ustar00rootroot00000000000000# 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_G0_OPTION_BYTES_BASE option_size 0x80 // 128 B flags none stlink-1.8.0/config/chips/G0Bx_G0Cx.chip000066400000000000000000000007141455655054600176460ustar00rootroot00000000000000# 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_G0_OPTION_BYTES_BASE option_size 0x80 // 128 B flags dualbank stlink-1.8.0/config/chips/G43x_G44x.chip000066400000000000000000000006541455655054600176230ustar00rootroot00000000000000# 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_G4_OPTION_BYTES_BASE option_size 0x4 // 4 B flags swo stlink-1.8.0/config/chips/G47x_G48x.chip000066400000000000000000000006661455655054600176360ustar00rootroot00000000000000# 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_G4_OPTION_BYTES_BASE option_size 0x4 // 4 B flags swo dualbank stlink-1.8.0/config/chips/G49x_G4Ax.chip000066400000000000000000000006661455655054600176510ustar00rootroot00000000000000# 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_G4_OPTION_BYTES_BASE option_size 0x4 // 4 B flags swo dualbank stlink-1.8.0/config/chips/H5xx.chip000066400000000000000000000005451455655054600171230ustar00rootroot00000000000000# Chip-ID file for STM32H5xx device # dev_type STM32H5xx ref_manual_id 0481 chip_id 0x484 // STM32_CHIPID_H5xx flash_type L5_U5_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.8.0/config/chips/H72x_H73x.chip000066400000000000000000000006651455655054600176330ustar00rootroot00000000000000# 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 0x5200201c // STM32_H7_OPTION_BYTES_BASE option_size 0x2c // 44 B flags swo stlink-1.8.0/config/chips/H74x_H75x.chip000066400000000000000000000007511455655054600176330ustar00rootroot00000000000000# 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 0x5200201c // STM32_H7_OPTION_BYTES_BASE option_size 0x2c // 44 B /* FLASH_OPTSR_CUR to FLASH_BOOT_PRGR */ flags swo dualbank stlink-1.8.0/config/chips/H7Ax_H7Bx.chip000066400000000000000000000006741455655054600176710ustar00rootroot00000000000000# 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 0x2000 // 8 KB sram_size 0x20000 // 128 KB "DTCM" bootrom_base 0x1ff00000 bootrom_size 0x20000 // 128 KB option_base 0x5200201c // STM32_H7_OPTION_BYTES_BASE option_size 0x2c // 44 B flags swo dualbank stlink-1.8.0/config/chips/L0xxx_Cat_1.chip000066400000000000000000000007521455655054600203210ustar00rootroot00000000000000# 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_L0_OPTION_BYTES_BASE option_size 0x20 // 32 B flags none stlink-1.8.0/config/chips/L0xxx_Cat_2.chip000066400000000000000000000007411455655054600203200ustar00rootroot00000000000000# 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_L0_OPTION_BYTES_BASE option_size 0x20 // 32 B flags none stlink-1.8.0/config/chips/L0xxx_Cat_3.chip000066400000000000000000000007621455655054600203240ustar00rootroot00000000000000# 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_L0_OPTION_BYTES_BASE option_size 0x20 // 32 B flags none stlink-1.8.0/config/chips/L0xxx_Cat_5.chip000066400000000000000000000007771455655054600203340ustar00rootroot00000000000000# 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_L0_OPTION_BYTES_BASE option_size 0x20 // 32 B flags dualbank stlink-1.8.0/config/chips/L1xx_Cat_1.chip000066400000000000000000000006061455655054600201300ustar00rootroot00000000000000# 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.8.0/config/chips/L1xx_Cat_2.chip000066400000000000000000000006161455655054600201320ustar00rootroot00000000000000# 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.8.0/config/chips/L1xx_Cat_3.chip000066400000000000000000000006021455655054600201260ustar00rootroot00000000000000# 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.8.0/config/chips/L1xx_Cat_4.chip000066400000000000000000000007041455655054600201320ustar00rootroot00000000000000# 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_L1_OPTION_BYTES_BASE option_size 0x8 // 8 B flags swo stlink-1.8.0/config/chips/L1xx_Cat_5.chip000066400000000000000000000005771455655054600201430ustar00rootroot00000000000000# 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.8.0/config/chips/L41x_L42x.chip000066400000000000000000000005571455655054600176330ustar00rootroot00000000000000# 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 0x0 option_size 0x0 flags swo stlink-1.8.0/config/chips/L43x_L44x.chip000066400000000000000000000006561455655054600176370ustar00rootroot00000000000000# 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_L4_OPTION_BYTES_BASE option_size 0x4 // 4 B flags swo stlink-1.8.0/config/chips/L45x_L46x.chip000066400000000000000000000006431455655054600176370ustar00rootroot00000000000000# 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.8.0/config/chips/L47x_L48x.chip000066400000000000000000000006471455655054600176470ustar00rootroot00000000000000# 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_L4_OPTION_BYTES_BASE option_size 0x4 // 4 B flags swo stlink-1.8.0/config/chips/L496x_L4A6x.chip000066400000000000000000000007501455655054600200310ustar00rootroot00000000000000# 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_L4_OPTION_BYTES_BASE option_size 0x4 // 4 B flags swo otp_base 0x1fff7000 otp_size 0x400 // 1 KB stlink-1.8.0/config/chips/L4Px_L4Qx.chip000066400000000000000000000006061455655054600177240ustar00rootroot00000000000000# 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 0xa0000 // 640 KB bootrom_base 0x1fff0000 bootrom_size 0x7000 // 28 KB option_base 0x1ff00000 option_size 0x4 // 4 B flags swo stlink-1.8.0/config/chips/L4Rx.chip000066400000000000000000000005651455655054600170620ustar00rootroot00000000000000# 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.8.0/config/chips/L5x5xx.chip000066400000000000000000000005531455655054600174030ustar00rootroot00000000000000# Chip-ID file for STM32L5x2xx device # dev_type STM32L5x2xx ref_manual_id 0438 chip_id 0x472 // STM32_CHIPID_L5x2xx flash_type L5_U5_H5 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.8.0/config/chips/U535_U545.chip000066400000000000000000000005661455655054600174550ustar00rootroot00000000000000# Chip-ID file for STM32U535 / STM32U545 device # dev_type STM32U535_U545 ref_manual_id 0456 chip_id 0x455 // STM32U535/545 flash_type L5_U5_H5 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.8.0/config/chips/U55Fx_U5Gx.chip000066400000000000000000000005701455655054600200110ustar00rootroot00000000000000# Chip-ID file for STM32U5Fx / STM32U5Gx device # dev_type STM32U5Fx_U5Gx ref_manual_id 0456 chip_id 0x476 // STM32U5Fx5/5Gx flash_type L5_U5_H5 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.8.0/config/chips/U575_U585.chip000066400000000000000000000005661455655054600174650ustar00rootroot00000000000000# Chip-ID file for STM32U575 / STM32U585 device # dev_type STM32U575_U585 ref_manual_id 0456 chip_id 0x482 // STM32U575/585 flash_type L5_U5_H5 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 stlink-1.8.0/config/chips/U59x_U5Ax.chip000066400000000000000000000005671455655054600177070ustar00rootroot00000000000000# Chip-ID file for STM32U59x / STM32U5Ax device # dev_type STM32U59x_U5Ax ref_manual_id 0456 chip_id 0x481 // STM32U59x/5Ax flash_type L5_U5_H5 flash_size_reg 0x0bfa07a0 flash_pagesize 0x2000 // 8 KB sram_size 0x274800 // 2514 KB bootrom_base 0x0bf90000 bootrom_size 0x8000 // 32 KB option_base 0x0 option_size 0x0 flags swo dualbank stlink-1.8.0/config/chips/WBx0_WBx5.chip000066400000000000000000000006441455655054600177140ustar00rootroot00000000000000# 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.8.0/config/chips/WLEx.chip000066400000000000000000000006001455655054600170760ustar00rootroot00000000000000# 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.8.0/config/chips/unknown_device.chip000066400000000000000000000004211455655054600212760ustar00rootroot00000000000000# 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.8.0/config/code_style.cfg000066400000000000000000003610131455655054600171270ustar00rootroot00000000000000# 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.8.0/config/modprobe.d/000077500000000000000000000000001455655054600163415ustar00rootroot00000000000000stlink-1.8.0/config/modprobe.d/stlink_v1.conf000066400000000000000000000000461455655054600211220ustar00rootroot00000000000000options usb-storage quirks=483:3744:i stlink-1.8.0/config/udev/000077500000000000000000000000001455655054600152535ustar00rootroot00000000000000stlink-1.8.0/config/udev/rules.d/000077500000000000000000000000001455655054600166275ustar00rootroot00000000000000stlink-1.8.0/config/udev/rules.d/49-stlinkv1.rules000066400000000000000000000007271455655054600217160ustar00rootroot00000000000000# 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.8.0/config/udev/rules.d/49-stlinkv2-1.rules000066400000000000000000000014101455655054600220430ustar00rootroot00000000000000# 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.8.0/config/udev/rules.d/49-stlinkv2.rules000066400000000000000000000010221455655054600217040ustar00rootroot00000000000000# 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.8.0/config/udev/rules.d/49-stlinkv3.rules000066400000000000000000000022121455655054600217070ustar00rootroot00000000000000# 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" # 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.8.0/contributors.txt000066400000000000000000000050641455655054600163460ustar00rootroot00000000000000List of contributors to the stlink project: Alexey Cherevatenko Alexey Panarin Anatoli Klassen [dev26th] Andrea Mucignat Andrew Andrianov [nekromant] Andrey Yurovsky Andy Isaacson Andreas Sandberg [andysan] Antoine Faure [antoinefaure] Anton [Ant-ON] Áron Radics A. Sheaff Björn Hauffe Ihor Bobalo Breton M. Saunders Bruno Dal Bo Brian Team [dot4qu] Burns Fisher Cheng Guokai (Xim) [chenguokai] Chris Dew Chris Hiszpanski Chris Li Chris Samuelson Christian Deussen [nullsub] Christophe Levantis Craig Lilley Crest [Crest] Dan Dev Dan Hepler Daniel Campoverde [alx741] Daniel O'Connor Dave Flogeras Dave Murphy [WinterMute] Dave Vandervies [dj3vande] Denis Fokin Denis Osterland Dmitry Bravikov [bravikov] Efe Can İçöz Ethan Zonca Fabien Chouteau [Fabien-Chouteau] Florian Hars Friedrich Beckmann Gabriel Górski [Glaeqen] Geoffrey Brown [geoffreymbrown] George Talusan [gtalusan] Georg von Zengen Giuseppe Barba Greg Alexander [galexander1] Greg Meiste [meisteg] Grzegorz Szymaszek [gszy] Guillaume Revaillot [grevaillot] Gwenhael Goavec-Merou [trabucayre] [Hakkavélin] Halt Hammerzeit Hsu Pu [hsupu] [hydroconstructor] Ian Griffiths Jack Peel Jakub Tyszkowski Jan Sarenik Jean-Luc Béchennec Jean-Marie Lemetayer Jeff Kent Jeffrey Nelson Jens Hoffmann Jerome Lambourg Jim Paris Jiří Netolický Jerry Jacobs [xor-gate] Jerry Nosky [jnosky] Jochen Wilhelmy [Jochen0x90h] John Hall [simplerobot] Joel Bodenmann [Tectu] Johannes Taelman Jonas Danielsson Jonas Norling Josh Bialkowski Karl Palsson [karlp] Kevlar Harness Kyle Manna Lari Lehtomäki Luuk van Dijk [lvdlvd] Martin Nowak Matteo Collina Max Chen Maxime Coquelin [mcoquelin-stm32] Maxime Vincent Michael Pratt [prattmic] Michael Sparmann Mike Szczys Magnus Lundin [mlu] Ned Konz Nic McDonald Nicolas Schodet Oleksiy Slyshyk [slyshykO] Olivier Croquette Olivier Gay Onno Kortmann [orangeudav] Pavel Kirienko Pekka Nikander Pete Nelson Peter Torelli [petertorelli] Peter Zotov Petteri Aimonen Piotr Haber [RafaelLeeImg] [rcubee] Rene Hopf [rene-dev] Robin Kreis Roger Wolff [rewolff] Rob Spanton Rytis Karpuska Rutger Hendriks [rutgerhendriks] Sean Simmons Sergey Alirzaev Simon Derr [sderr] Simon Wright Stany Marcel Stefan Misik Sven Wegener Tarek Bochkati [tarek-bochkati] [texane] Timothy Lee [timothytylee] Tuomo Kaikkonen Theodore A. Roth Thomas Gärtner Tobias Badertscher Tom de Boer Tristan Gingold Uli Köhler Uwe Bonnes [UweBonnes] Vadim Kaushan Vasiliy Glazov [Vascom] Vegard Storheil Eriksen Viacheslav Dobromyslov Victor Mayoral Vilches [whitequark] William Ransohoff [WRansohoff] Wojciech A. Koszek Woodrow Douglass ... and others stlink-1.8.0/debian/000077500000000000000000000000001455655054600142655ustar00rootroot00000000000000stlink-1.8.0/debian/.gitignore000066400000000000000000000001551455655054600162560ustar00rootroot00000000000000.debhelper *.log *.substvars debhelper-build-stamp files libstlink-dev libstlink stlink-gui stlink-tools tmp stlink-1.8.0/debian/changelog000066400000000000000000000161621455655054600161450ustar00rootroot00000000000000stlink (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.8.0/debian/control000066400000000000000000000031361455655054600156730ustar00rootroot00000000000000Source: stlink Priority: optional Maintainer: Luca Boccassi Build-Depends: debhelper-compat (= 13), cmake (>= 3.4.2), libusb-1.0-0-dev, libgtk-3-dev Standards-Version: 4.5.1 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: stlink-lib-dev Section: libdevel Architecture: linux-any Multi-Arch: same Depends: stlink-lib (= ${binary:Version}), ${misc:Depends} Replaces: libstlink-dev (<< 1.7.0+ds-1) Breaks: libstlink-dev (<< 1.7.0+ds-1) Description: Open source version of the STMicroelectronics STLINK Tools . This package contains development files for stlink. Package: stlink-lib Section: libs Architecture: linux-any Multi-Arch: same Depends: ${shlibs:Depends}, ${misc:Depends} Replaces: libstlink1 (<< 1.7.0+ds-1) Breaks: libstlink1 (<< 1.7.0+ds-1) Description: Open source version of the STMicroelectronics STLINK Tools . This package contains the shared library for stlink. Package: stlink-tools Architecture: linux-any Depends: stlink-lib (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} Description: Open source version of the STMicroelectronics STLINK Tools . This package contains commandline utilities for stlink, as well as modprobe and udev rules. Package: stlink-gui Architecture: linux-any Depends: stlink-lib (= ${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.8.0/debian/copyright000066400000000000000000000042571455655054600162300ustar00rootroot00000000000000Format: 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 Comment: Upstream tarball has been repackaged to remove binary OSX kernel drivers that are of unknown license and of no use to Debian. Files-Excluded: stlinkv1_macos_driver Files: * Copyright: 2011-2021 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.8.0/debian/gbp.conf000066400000000000000000000002461455655054600157060ustar00rootroot00000000000000[buildpackage] upstream-tag = %(version)s debian-branch = debian [dch] git-log = --first-parent customizations = /usr/share/doc/git-buildpackage/examples/wrap_cl.py stlink-1.8.0/debian/rules000077500000000000000000000014461455655054600153520ustar00rootroot00000000000000#!/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 override_dh_auto_configure: dh_auto_configure -- \ -DSTLINK_UDEV_RULES_DIR='/lib/udev/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.8.0/debian/source/000077500000000000000000000000001455655054600155655ustar00rootroot00000000000000stlink-1.8.0/debian/source/format000066400000000000000000000000141455655054600167730ustar00rootroot000000000000003.0 (quilt) stlink-1.8.0/debian/source/options000066400000000000000000000000511455655054600171770ustar00rootroot00000000000000extend-diff-ignore=stlinkv1_macos_driver stlink-1.8.0/debian/stlink-gui.install000066400000000000000000000002251455655054600177420ustar00rootroot00000000000000/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.8.0/debian/stlink-lib-dev.install000066400000000000000000000001101455655054600204710ustar00rootroot00000000000000usr/include/* usr/lib/*/lib*.a usr/lib/*/pkgconfig/* usr/lib/*/lib*.so stlink-1.8.0/debian/stlink-lib.install000066400000000000000000000000241455655054600177210ustar00rootroot00000000000000usr/lib/*/lib*.so.* stlink-1.8.0/debian/stlink-lib.symbols000066400000000000000000000132451455655054600177540ustar00rootroot00000000000000stlink-lib.so.1 stlink-lib #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 #MISSING: 1.7.0# is_bigendian@Base 1.5.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_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_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_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 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_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 stlink_read_option_control_register_Gx@Base 1.7.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_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 stlink_trace_disable@Base 1.7.0 stlink_trace_enable@Base 1.7.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_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 write_buffer_to_sram@Base 1.5.0 write_uint16@Base 1.5.0 write_uint32@Base 1.5.0 stlink-1.8.0/debian/stlink-tools.install000066400000000000000000000000751455655054600203210ustar00rootroot00000000000000/usr/bin/st-* lib/udev/rules.d/*.rules etc/modprobe.d/*.conf stlink-1.8.0/debian/stlink-tools.manpages000066400000000000000000000001301455655054600204360ustar00rootroot00000000000000usr/share/man/man1/st-flash.1 usr/share/man/man1/st-info.1 usr/share/man/man1/st-util.1 stlink-1.8.0/debian/stlink.pc.in000066400000000000000000000004131455655054600165200ustar00rootroot00000000000000prefix=/usr includedir=${prefix}/include/stlink libdir=${prefix}/lib/@DEB_HOST_MULTIARCH@ Name: stlink Description: Open source version of the STMicroelectronics STLINK Tools Version: @VERSION@ Requires: libusb-1.0 Libs: -L${libdir} -lstlink Cflags: -I${includedir} stlink-1.8.0/debian/watch000066400000000000000000000002711455655054600153160ustar00rootroot00000000000000version=3 opts=dversionmangle=s/\+ds$//,repacksuffix=+ds,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.8.0/doc/000077500000000000000000000000001455655054600136105ustar00rootroot00000000000000stlink-1.8.0/doc/compiling.md000066400000000000000000000160071455655054600161170ustar00rootroot00000000000000# Compiling from sources ## Microsoft Windows (10, 11) ### Common Requirements On Windows users should ensure that the following software is installed: - `git` (_optional, but recommended_) - `cmake` - `7-zip` - `MinGW-w64` ### Installation 1. Install `git` from 2. Install `cmake` from
Ensure that you add cmake to the $PATH system variable when following the instructions by the setup assistant. 3. Install MinGW-w64
Download **MinGW-w64** from . Extract content to `C:\mingw-w64\` and add `C:\mingw-w64\bin\` to PATH-Variable.
4. Create a new destination folder at a place of your choice 5. Open the command-line (cmd.exe) and execute `cd C:\$Path-to-your-destination-folder$\` 6. Fetch the project sourcefiles by running `git clone https://github.com/stlink-org/stlink.git`from the command-line (cmd.exe)
or download and extract the stlink zip-sourcefolder from the Release page on GitHub. ### Building #### MinGW-w64 1. Open command-line with administrator privileges 2. Move to the `stlink` directory 3. Execute `mingw64-build.bat` NOTE:
Per default the build script (currently) uses `C:\mingw-w64\x86_64-8.1.0-release-win32-sjlj-rt_v6-rev0\mingw64\bin`.
When installing different toolchains make sure to update the path in the `mingw64-build.bat`.
This can be achieved by opening the .bat file with a common text editor. Options: - `/m` - compilation runs in parallel utilizing multiple cores - `/p:Configuration=Release` - generates _Release_, optimized build. Directory `\build\Release` contains final executables. (`st-util.exe` is located in `\build\src\gdbserver\Release`). **NOTE 1:** Executables link against libusb.dll library. It has to be placed in the same directory as binaries or in PATH. It can be copied from: `\build\3rdparty\libusb-{version}\MS{arch}\dll\libusb-1.0.dll`. **NOTE 2:** [ST-LINK drivers](https://www.st.com/en/development-tools/stsw-link009.html) are required for `stlink` to work. ## Linux ### Common requirements Install the following packages from your package repository: - `git` - `gcc` or `clang` or `mingw32-gcc` or `mingw64-gcc` (C-compiler; very likely gcc is already present) - `build-essential` (on Debian based distros (Debian, Ubuntu)) - `cmake` - `rpm` (on Debian based distros (Debian, Ubuntu), needed for package build with `make package`) - `libusb-1.0` - `libusb-1.0-0-dev` (development headers for building) - `libgtk-3-dev` (_optional_, needed for `stlink-gui`) - `pandoc` (_optional_, needed for generating manpages from markdown) or execute (Debian-based systems only): `apt-get install gcc build-essential cmake libusb-1.0 libusb-1.0-0-dev libgtk-3-dev pandoc` (Replace gcc with the intended C-compiler if necessary or leave out any optional package not needed.) ### 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`. As an option you may also install to an individual user-defined folder e.g `$HOME` with `make install DESTDIR=$HOME`. ### How to avoid the error message: "Can not open shared object file" When installing system-wide (`sudo make install`) the dynamic library cache needs to be updated with the command `ldconfig`. #### 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` - `mingw-w64-common` - `mingw-w64-i686-dev` - `mingw-w64-x86-64-dev` After following the steps for installation above, proceed with from the build dircetory itself: ```sh $ sudo sh ./cmake/packaging/windows/generate_binaries.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.8.0/doc/flashloaders.md000066400000000000000000000073271455655054600166120ustar00rootroot00000000000000# 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.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.8.0/doc/man/000077500000000000000000000000001455655054600143635ustar00rootroot00000000000000stlink-1.8.0/doc/man/.gitignore000066400000000000000000000000041455655054600163450ustar00rootroot00000000000000*.1 stlink-1.8.0/doc/man/CMakeLists.txt000066400000000000000000000020131455655054600171170ustar00rootroot00000000000000### # Generate manpages ### set(MANPAGES st-util st-flash st-info) # 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_CURRENT_BINARY_DIR} ) endforeach () else () message(STATUS "Manpage generation disabled") endif() # Install from output folder or this folder foreach (manpage ${MANPAGES}) if (EXISTS ${CMAKE_CURRENT_BINARY_DIR}/${manpage}.1) set(f "${CMAKE_CURRENT_BINARY_DIR}/${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_DATADIR}/man/man1) unset(f) endif() endforeach () stlink-1.8.0/doc/man/st-flash.1000066400000000000000000000035601455655054600161720ustar00rootroot00000000000000.\" 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.8.0/doc/man/st-flash.md000066400000000000000000000032751455655054600164350ustar00rootroot00000000000000% st-flash(1) Open Source STMicroelectronics Stlink Tools | stlink % % Feb 2018 # 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.8.0/doc/man/st-info.1000066400000000000000000000023351455655054600160270ustar00rootroot00000000000000.\" 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.8.0/doc/man/st-info.md000066400000000000000000000023731455655054600162710ustar00rootroot00000000000000% st-flash(1) Open Source STMicroelectronics Stlink Tools | stlink % % Oct 2020 # 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.8.0/doc/man/st-util.1000066400000000000000000000031771455655054600160560ustar00rootroot00000000000000.\" 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.8.0/doc/man/st-util.md000066400000000000000000000024451455655054600163130ustar00rootroot00000000000000% st-util(1) Open Source STMicroelectronics Stlink Tools | stlink % % Feb 2018 # 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.8.0/doc/release.md000066400000000000000000000013151455655054600155520ustar00rootroot00000000000000Release ======= 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 ./cmake/packaging/windows/generate_binaries.sh` 8. Upload packages to the [release page](https://github.com/stlink-org/stlink/releases) of this project 9. Merge `master` into `develop` stlink-1.8.0/doc/supported_devices.md000066400000000000000000000111471455655054600176650ustar00rootroot00000000000000# 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+ | | | 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 | | | STM32H5 | M33 | | | STM32U5 | M33 | | # 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.8.0/doc/tutorial.md000066400000000000000000000625311455655054600160040ustar00rootroot00000000000000# 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 with the unit `Hz` being left out. 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.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.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 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, --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.8.0/doc/version_support.md000066400000000000000000000170131455655054600174150ustar00rootroot00000000000000_Source:_ [pkgs.org](https://pkgs.org) - libusb, cmake, gtk, libgtk (as of Apr 2023) ## Supported Operating Systems ### Microsoft Windows On Windows users should ensure that cmake **3.13.0** or any later version is installed.
Up on compiling c-make will **automatically** download and install the latest compatible version of `libusb`. - Windows 10 - Windows 11 ### Linux-/Unix-based: Maintained versions of: - Debian - Ubuntu - Fedora - openSUSE - OpenMandriva - Arch Linux - FreeBSD - NetBSD - OpenBSD Other Linux-/Unix-based Operating Systems: | Operating System | libusb | cmake | libgtk-dev | End of
OS-Support | | ------------------------ | ------------------------------ | ---------- | ----------- | ---------------------- | | Debian Sid | 1.0.24 | 3.22.1 | 3.24.31 | | | Debian 11 (Bullseye) | 1.0.24 | 3.**18.4** | 3.24.24 | | | Debian 10 (Buster) | 1.0.**22** | 3.**13.4** | 3.24.**5** | Jun 2024 | | | | | | | | Ubuntu 20.04 LTS (Focal) | 1.0.23 | 3.**16.3** | 3.24.**18** | May 2025 | | | | | | | | FreeBSD 13.x | 1.0.**16-18** (API 0x01000102) | 3.22.1 | 3.24.31 | | | | | | | | | NetBSD 9.x | 1.0.24 | 3.21.2 | 3.24.30 | | | NetBSD 8.x | 1.0.24 | 3.**19.7** | 3.24.27 | | | | | | | | | CentOS 9 Stream [x64] | 1.0.24 (`libusbx`) | 3.20.3 | 3.24.30 | | | CentOS 8 Stream [x64] | 1.0.23 (`libusbx`) | 3.20.2 | 3.**22.30** | May 2024 | | | | | | | | ALT Linux Sisyphus | 1.0.24 | 3.22.1 | 3.24.31 | | | ALT Linux P10 | 1.0.24 | 3.20.5 | 3.24.31 | | | ALT Linux P9 | 1.0.**22** | 3.**16.3** | 3.24.29 | | | | | | | | | KaOS [x64] | 1.0.24 | 3.22.1 | 3.24.31 | | | Mageia Cauldron | 1.0.24 | 3.22.1 | 3.24.31 | | | PCLinuxOS [x64] | (?) | 3.22.1 | 3.24.31 | | | Solus [x64] | 1.0.24 | 3.22.1 | 3.24.30 | | | Void Linux | 1.0.24 | 3.22.1 | 3.24.31 | | | Slackware Current | 1.0.24 | 3.21.4 | 3.24.31 | | | Adélie 1.0 | 1.0.23 | 3.**16.4** | 3.24.23 | | ## Unsupported Operating Systems (as of Release v1.8.0) Systems with highlighted versions remain compatible with this toolset. | Operating System | libusb | cmake | End of
OS-Support | | ---------------------------------------- | ------------------------------ | ---------- | ---------------------- | | FreeBSD 12.x | 1.0.**16-18** (API 0x01000102) | 3.**22.1** | Dec 2023 | | Alpine 3.15 | 1.0.**24** | 3.**21.3** | Nov 2023 | | Fedora 35 [x64] | 1.0.**24** | 3.**21.3** | Dec 2022 | | Alpine 3.14 | 1.0.**24** | 3.**20.3** | May 2023 | | CentOS / Rocky Linux / AlmaLinux 8 [x64] | 1.0.**23** (`libusbx`) | 3.**20.3** | Dec 2021 | | Fedora 34 [x64] | 1.0.**24** (`libusbx`) | 3.**19.7** | Jun 2022 | | OpenMandriva Lx 4.2 | 1.0.**24** | 3.**19.3** | Mar 2023 | | Mageia 8 | 1.0.**24** | 3.**19.2** | Aug 2022 | | Alpine 3.13 | 1.0.**24** | 3.**18.4** | Nov 2022 | | Ubuntu 21.04 (Hirsute) | 1.0.**24** | 3.**18.4** | Jan 2022 | | Fedora 33 [x64] | 1.0.**23** (`libusbx`) | 3.**18.3** | Nov 2021 | | Alpine 3.12 | 1.0.**23** | 3.**17.2** | May 2022 | | openSUSE Leap 15.3 [x64] | 1.0.21 | 3.**17.0** | Dec 2022 | | Fedora 32 [x64] | 1.0.**23** (`libusbx`) | 3.**17.0** | May 2021 | | openSUSE Leap 15.2 [x64] | 1.0.21 | 3.**17.0** | Dec 2021 | | Ubuntu 20.10 (Groovy) | 1.0.**23** | 3.**16.3** | Jul 2021 | | NetBSD 7.x | 1.0.**22** | 3.**16.1** | Jun 2020 | | Alpine 3.11 | 1.0.**23** | 3.**15.5** | Nov 2021 | | FreeBSD 11.x | 1.0.**16-18** (API 0x01000102) | 3.**15.5** | Sep 2021 | | Alpine 3.10 | 1.0.**22** | 3.**14.5** | May 2021 | | Fedora 31 [x64] | 1.0.**22**(`libusbx`) | 3.**14.5** | Nov 2020 | | Mageia 7.1 | 1.0.**22** | 3.**14.3** | Jun 2021 | | Fedora 30 | 1.0.**22**(`libusbx`) | 3.**14.2** | May 2020 | | Ubuntu 19.10 (Eoan) | 1.0.**23** | 3.**13.4** | Jul 2020 | | Alpine 3.9 | 1.0.**22** | 3.**13.0** | Jan 2021 | | Ubuntu 18.04 LTS (Bionic) | 1.0.21 | 3.10.2 | Apr 2023 | | openSUSE Leap 15.1 [x64] | 1.0.21 | 3.10.2 | Jan 2021 | | Debian 9 (Stretch) | 1.0.21 | 3.7.2 | Jun 2022 | | Slackware 14.2 | 1.0.20 | 3.5.2 | | | OpenMandriva Lx 3.0x | 1.0.20 | 3.4.2 | | | CentOS / Rocky Linux / AlmaLinux 7 [x64] | 1.0.21 (`libusbx`) | 2.8.12.2 | Jun 2024 | _All other operating systems which are not listed are unsupported._ Author: nightwalker-87 stlink-1.8.0/flashloaders/000077500000000000000000000000001455655054600155125ustar00rootroot00000000000000stlink-1.8.0/flashloaders/Makefile000066400000000000000000000020161455655054600171510ustar00rootroot00000000000000# 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 stm32lx.h stm32f4.h stm32f4lv.h stm32l4.h stm32f7.h stm32f7lv.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 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.8.0/flashloaders/cleanroom.md000066400000000000000000000132311455655054600200130ustar00rootroot00000000000000# 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. ## 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.8.0/flashloaders/linker.ld000066400000000000000000000001751455655054600173220ustar00rootroot00000000000000/* Entry Point */ ENTRY(copy) /* Specify the memory areas */ MEMORY { RAM (xrw) : ORIGIN = 0x20000000 , LENGTH = 64K } stlink-1.8.0/flashloaders/stm32f0.s000066400000000000000000000031571455655054600171020ustar00rootroot00000000000000 .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.8.0/flashloaders/stm32f4.s000066400000000000000000000012421455655054600170770ustar00rootroot00000000000000 .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.8.0/flashloaders/stm32f4lv.s000066400000000000000000000012431455655054600174420ustar00rootroot00000000000000 .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.8.0/flashloaders/stm32f7.s000066400000000000000000000013071455655054600171040ustar00rootroot00000000000000 .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.8.0/flashloaders/stm32f7lv.s000066400000000000000000000013041455655054600174430ustar00rootroot00000000000000 .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.8.0/flashloaders/stm32l4.s000066400000000000000000000013171455655054600171100ustar00rootroot00000000000000 .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.8.0/flashloaders/stm32lx.s000066400000000000000000000006371455655054600172200ustar00rootroot00000000000000 .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.8.0/inc/000077500000000000000000000000001455655054600136145ustar00rootroot00000000000000stlink-1.8.0/inc/CMakeLists.txt000066400000000000000000000005011455655054600163500ustar00rootroot00000000000000configure_file( "${PROJECT_SOURCE_DIR}/inc/version.h.in" "${CMAKE_BINARY_DIR}/inc/version.h" ) file(GLOB STLINK_HEADERS "${CMAKE_SOURCE_DIR}/inc/*.h" "${CMAKE_SOURCE_DIR}/src/stlink-lib/*.h" "${CMAKE_BINARY_DIR}/inc/version.h") install(FILES ${STLINK_HEADERS} DESTINATION ${STLINK_INCLUDE_PATH}) stlink-1.8.0/inc/backend.h000066400000000000000000000037741455655054600153670ustar00rootroot00000000000000#ifndef BACKEND_H #define 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); } stlink_backend_t; #endif // BACKEND_H stlink-1.8.0/inc/stlink.h000066400000000000000000000216131455655054600152740ustar00rootroot00000000000000/* * File: stlink.h * * All common top level stlink interfaces, regardless of how the backend does the work.... */ #ifndef STLINK_H #define STLINK_H #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif #define STLINK_ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) /* Max data transfer size */ // 6kB = max mem32_read block, 8kB 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 0x00 #define STLINK_DEV_MASS_MODE 0x01 #define STLINK_DEV_DEBUG_MODE 0x02 #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 (1 << 0) #define STLINK_F_HAS_SWD_SET_FREQ (1 << 1) #define STLINK_F_HAS_JTAG_SET_FREQ (1 << 2) #define STLINK_F_HAS_MEM_16BIT (1 << 3) #define STLINK_F_HAS_GETLASTRWSTATUS2 (1 << 4) #define STLINK_F_HAS_DAP_REG (1 << 5) #define STLINK_F_QUIRK_JTAG_DP_READ (1 << 6) #define STLINK_F_HAS_AP_INIT (1 << 7) #define STLINK_F_HAS_DPBANKSEL (1 << 8) #define STLINK_F_HAS_RW8_512BYTES (1 << 9) /* Additional MCU features */ #define CHIP_F_HAS_DUAL_BANK (1 << 0) #define CHIP_F_HAS_SWO_TRACING (1 << 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 #include 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 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.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; }; /* Functions defined in common.c */ int32_t stlink_enter_swd_mode(stlink_t *sl); // int32_t stlink_enter_jtag_mode(stlink_t *sl); int32_t stlink_exit_debug_mode(stlink_t *sl); int32_t stlink_exit_dfu_mode(stlink_t *sl); void stlink_close(stlink_t *sl); int32_t stlink_core_id(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); int32_t stlink_status(stlink_t *sl); int32_t stlink_version(stlink_t *sl); int32_t stlink_step(stlink_t *sl); int32_t stlink_current_mode(stlink_t *sl); int32_t stlink_force_debug(stlink_t *sl); int32_t stlink_target_voltage(stlink_t *sl); int32_t stlink_set_swdclk(stlink_t *sl, int32_t freq_khz); int32_t stlink_parse_ihex(const char* path, uint8_t erased_pattern, uint8_t* *mem, uint32_t* size, uint32_t* begin); uint8_t stlink_get_erased_pattern(stlink_t *sl); int32_t stlink_mwrite_sram(stlink_t *sl, uint8_t* data, uint32_t length, stm32_addr_t addr); int32_t stlink_fwrite_sram(stlink_t *sl, const char* path, stm32_addr_t addr); int32_t stlink_cpu_id(stlink_t *sl, cortex_m3_cpuid_t *cpuid); uint32_t stlink_calculate_pagesize(stlink_t *sl, uint32_t flashaddr); //void stlink_core_stat(stlink_t *sl); void stlink_print_data(stlink_t *sl); uint32_t is_bigendian(void); bool stlink_is_core_halted(stlink_t *sl); int32_t write_buffer_to_sram(stlink_t *sl, flash_loader_t* fl, const uint8_t* buf, uint16_t size); // int32_t write_loader_to_sram(stlink_t *sl, stm32_addr_t* addr, uint16_t* size); int32_t stlink_fread(stlink_t* sl, const char* path, bool is_ihex, stm32_addr_t addr, uint32_t size); int32_t stlink_load_device_params(stlink_t *sl); int32_t stlink_target_connect(stlink_t *sl, enum connect_type connect); #include #include #include #include #include #include #include #ifdef __cplusplus } #endif #endif // STLINK_H stlink-1.8.0/inc/stm32.h000066400000000000000000000250771455655054600147500ustar00rootroot00000000000000/* * File: stm32.h * * STM32-specific defines & identification parametres */ #ifndef STM32_H #define STM32_H #include /* STM32 Cortex-M core ids (CPUTAPID) */ enum stm32_core_id { STM32_CORE_ID_M0_SWD = 0x0bb11477, // (RM0091 Section 32.5.3) F0 SW-DP STM32_CORE_ID_M0P_SWD = 0x0bc11477, // (RM0444 Section 40.5.3) G0 SW-DP // (RM0377 Section 27.5.3) L0 SW-DP STM32_CORE_ID_M3_r1p1_SWD = 0x1ba01477, // (RM0008 Section 31.8.3) F1 SW-DP STM32_CORE_ID_M3_r1p1_JTAG = 0x3ba00477, // (RM0008 Section 31.6.3) F1 JTAG STM32_CORE_ID_M3_r2p0_SWD = 0x2ba01477, // (RM0033 Section 32.8.3) F2 SW-DP // (RM0038 Section 30.8.3) L1 SW-DP STM32_CORE_ID_M3_r2p0_JTAG = 0x0ba00477, // (RM0033 Section 32.6.3) F2 JTAG // (RM0038 Section 30.6.2) L1 JTAG STM32_CORE_ID_M4_r0p1_SWD = 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 = 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 = 0x2ba01477, // (RM0090 Section 38.8.3) F4 SW-DP // (RM0090 Section 47.8.3) G4 SW-DP STM32_CORE_ID_M4F_r0p1_JTAG = 0x4ba00477, // (RM0090 Section 38.6.3) F4 JTAG // (RM0090 Section 47.6.3) G4 JTAG STM32_CORE_ID_M7F_SWD = 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 = 0x5ba00477, // (RM0385 Section 40.6.3) F7 JTAG STM32_CORE_ID_M7F_M33_SWD = 0x6ba02477, // (RM0481 Section 58.3.3) H5 SW-DP // (RM0433 Section 60.4.1) H7 SW-DP STM32_CORE_ID_M7F_M33_JTAG = 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 = 0x0be02477, // (RM0438 Section 52.2.10) L5 SW-DP // (RM0456 Section 65.3.3) U5 SW-DP STM32_CORE_ID_M33_JTAGD = 0x0be01477, // (RM0438 Section 52.2.10) L5 JTAG-DP // (RM0456 Section 65.3.3) U5 JTAG-DP STM32_CORE_ID_M33_JTAG = 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_H5 = 11, STM32_FLASH_TYPE_WB_WL = 12, }; /* 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_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 (revision 3), section 26.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_H74xxx = 0x450, /* RM0433, p.3189 */ STM32_CHIPID_F76xxx = 0x451, STM32_CHIPID_F72xxx = 0x452, /* Nucleo F722ZE board */ STM32_CHIPID_C031xx = 0x453, /* RM0490 (revision 3), section 26.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_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_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_WB55 = 0x495, STM32_CHIPID_WLE = 0x497, }; /* Constant STM32 option bytes base memory address */ #define STM32_C0_OPTION_BYTES_BASE ((uint32_t)0x1fff7800) #define STM32_F4_OPTION_BYTES_BASE ((uint32_t)0x40023c14) #define STM32_H7_OPTION_BYTES_BASE ((uint32_t)0x5200201c) #define STM32_L0_OPTION_BYTES_BASE ((uint32_t)0x1ff80000) #define STM32_L1_OPTION_BYTES_BASE ((uint32_t)0x1ff80000) #define STM32_F7_OPTION_BYTES_BASE ((uint32_t)0x1fff0000) #define STM32_G0_OPTION_BYTES_BASE ((uint32_t)0x1fff7800) #define STM32_L4_OPTION_BYTES_BASE ((uint32_t)0x1fff7800) #define STM32_F2_OPTION_BYTES_BASE ((uint32_t)0x1fffc000) #define STM32_F0_OPTION_BYTES_BASE ((uint32_t)0x1ffff800) #define STM32_F1_OPTION_BYTES_BASE ((uint32_t)0x1ffff800) #define STM32_F3_OPTION_BYTES_BASE ((uint32_t)0x1ffff800) #define STM32_G4_OPTION_BYTES_BASE ((uint32_t)0x1ffff800) /* ============ */ /* Old defines from common.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 0xE0042004 #define STM32F0_DBGMCU_CR_IWDG_STOP 8 #define STM32F0_DBGMCU_CR_WWDG_STOP 9 #define STM32F4_DBGMCU_APB1FZR1 0xE0042008 #define STM32F4_DBGMCU_APB1FZR1_WWDG_STOP 11 #define STM32F4_DBGMCU_APB1FZR1_IWDG_STOP 12 #define STM32L0_DBGMCU_APB1_FZ 0x40015808 #define STM32L0_DBGMCU_APB1_FZ_WWDG_STOP 11 #define STM32L0_DBGMCU_APB1_FZ_IWDG_STOP 12 #define STM32L1_DBGMCU_APB1_FZ 0xE0042008 #define STM32L1_DBGMCU_APB1_FZ_WWDG_STOP 11 #define STM32L1_DBGMCU_APB1_FZ_IWDG_STOP 12 #define STM32H7_DBGMCU_APB1HFZ 0x5C001054 #define STM32H7_DBGMCU_APB1HFZ_IWDG_STOP 18 #define STM32WB_DBGMCU_APB1FZR1 0xE004203C #define STM32WB_DBGMCU_APB1FZR1_WWDG_STOP 11 #define STM32WB_DBGMCU_APB1FZR1_IWDG_STOP 12 #define STM32C0_RCC_AHBENR 0x40021038 // RM0490 (revision 3), section 5.4.25 "RCC register map" #define STM32C0_RCC_DMAEN 0x00000001 // DMAEN // RM0490 (revision 3), section 5.4.25 "RCC register map" #define STM32F1_RCC_AHBENR 0x40021014 #define STM32F1_RCC_DMAEN 0x00000003 // DMA2EN | DMA1EN #define STM32F4_RCC_AHB1ENR 0x40023830 #define STM32F4_RCC_DMAEN 0x00600000 // DMA2EN | DMA1EN #define STM32G0_RCC_AHBENR 0x40021038 #define STM32G0_RCC_DMAEN 0x00000003 // DMA2EN | DMA1EN #define STM32G4_RCC_AHB1ENR 0x40021048 #define STM32G4_RCC_DMAEN 0x00000003 // DMA2EN | DMA1EN #define STM32L0_RCC_AHBENR 0x40021030 #define STM32L0_RCC_DMAEN 0x00000001 // DMAEN #define STM32L1_RCC_AHBENR 0x4002381C #define STM32L1_RCC_DMAEN 0x30000000 // DMA2EN | DMA1EN #define STM32L5_RCC_AHB1ENR 0x40021048 // RM0438, p. 91,377 #define STM32L5_RCC_DMAEN 0x00000003 // DMA2EN | DMA1EN // RM0438, p. 378 #define STM32H7_RCC_AHB1ENR 0x58024538 #define STM32H7_RCC_DMAEN 0x00000003 // DMA2EN | DMA1EN #define STM32WB_RCC_AHB1ENR 0x58000048 #define STM32WB_RCC_DMAEN 0x00000003 // DMA2EN | DMA1EN #define STM32L5_PWR_CR1 0x40007000 // RM0438, p. 93,324 #define STM32L5_PWR_CR1_VOS 9 #endif // STM32_H stlink-1.8.0/inc/stm32flash.h000066400000000000000000000401201455655054600157500ustar00rootroot00000000000000#ifndef STM32FLASH_H #define STM32FLASH_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 FLASH_C0_REGS_ADDR ((uint32_t)0x40022000) #define FLASH_C0_KEYR (FLASH_C0_REGS_ADDR + 0x08) #define FLASH_C0_OPT_KEYR (FLASH_C0_REGS_ADDR + 0x0C) #define FLASH_C0_SR (FLASH_C0_REGS_ADDR + 0x10) #define FLASH_C0_CR (FLASH_C0_REGS_ADDR + 0x14) #define FLASH_C0_OPTR (FLASH_C0_REGS_ADDR + 0x20) // C0 Flash control register #define FLASH_C0_CR_PNB 3 #define FLASH_C0_CR_STRT 16 #define FLASH_C0_CR_OPTSTRT 17 #define FLASH_C0_CR_OBL_LAUNCH 27 #define FLASH_C0_CR_OPTLOCK 30 #define FLASH_C0_CR_LOCK 31 // C0 Flash status register #define FLASH_C0_SR_ERROR_MASK 0xC3F8 // [15:14], [9:3] #define FLASH_C0_SR_PROGERR 3 #define FLASH_C0_SR_WRPERR 4 #define FLASH_C0_SR_PGAERR 5 #define FLASH_C0_SR_BSY 16 // == STM32F0 == #define FLASH_F0_OPTKEY1 0x45670123 #define FLASH_F0_OPTKEY2 0xcdef89ab // == STM32F2 == #define FLASH_F2_REGS_ADDR ((uint32_t)0x40023c00) #define FLASH_F2_KEYR (FLASH_F2_REGS_ADDR + 0x04) #define FLASH_F2_OPT_KEYR (FLASH_F2_REGS_ADDR + 0x08) #define FLASH_F2_SR (FLASH_F2_REGS_ADDR + 0x0c) #define FLASH_F2_CR (FLASH_F2_REGS_ADDR + 0x10) #define FLASH_F2_OPT_CR (FLASH_F2_REGS_ADDR + 0x14) #define FLASH_F2_OPT_LOCK_BIT (1u << 0) // F2 Flash control register #define FLASH_F2_CR_STRT 16 #define FLASH_F2_CR_LOCK 31 #define FLASH_F2_CR_SER 1 #define FLASH_F2_CR_SNB 3 #define FLASH_F2_CR_SNB_MASK 0x78 // F2 Flash status register #define FLASH_F2_SR_BSY 16 // == STM32F4 == // F4 Flash registers #define FLASH_F4_REGS_ADDR ((uint32_t)0x40023c00) #define FLASH_F4_KEYR (FLASH_F4_REGS_ADDR + 0x04) #define FLASH_F4_OPT_KEYR (FLASH_F4_REGS_ADDR + 0x08) #define FLASH_F4_SR (FLASH_F4_REGS_ADDR + 0x0c) #define FLASH_F4_CR (FLASH_F4_REGS_ADDR + 0x10) #define FLASH_F4_OPTCR (FLASH_F4_REGS_ADDR + 0x14) #define FLASH_F4_OPTCR_LOCK 0 #define FLASH_F4_OPTCR_START 1 // F4 Flash control register #define FLASH_F4_CR_STRT 16 #define FLASH_F4_CR_LOCK 31 #define FLASH_F4_CR_SER 1 #define FLASH_F4_CR_SNB 3 #define FLASH_F4_CR_SNB_MASK 0xf8 // F4 Flash status register #define FLASH_F4_SR_ERROR_MASK 0x000000F0 #define FLASH_F4_SR_PGAERR 5 #define FLASH_F4_SR_WRPERR 4 #define FLASH_F4_SR_BSY 16 // == STM32F7 == // F7 Flash registers #define FLASH_F7_REGS_ADDR ((uint32_t)0x40023c00) #define FLASH_F7_KEYR (FLASH_F7_REGS_ADDR + 0x04) #define FLASH_F7_OPT_KEYR (FLASH_F7_REGS_ADDR + 0x08) #define FLASH_F7_SR (FLASH_F7_REGS_ADDR + 0x0c) #define FLASH_F7_CR (FLASH_F7_REGS_ADDR + 0x10) #define FLASH_F7_OPTCR (FLASH_F7_REGS_ADDR + 0x14) #define FLASH_F7_OPTCR1 (FLASH_F7_REGS_ADDR + 0x18) #define FLASH_F7_OPTCR_LOCK 0 #define FLASH_F7_OPTCR_START 1 #define FLASH_F7_OPTCR1_BOOT_ADD0 0 #define FLASH_F7_OPTCR1_BOOT_ADD1 16 // F7 Flash control register #define FLASH_F7_CR_STRT 16 #define FLASH_F7_CR_LOCK 31 #define FLASH_F7_CR_SER 1 #define FLASH_F7_CR_SNB 3 #define FLASH_F7_CR_SNB_MASK 0xf8 // F7 Flash status register #define FLASH_F7_SR_BSY 16 #define FLASH_F7_SR_ERS_ERR 7 /* Erase Sequence Error */ #define FLASH_F7_SR_PGP_ERR 6 /* Programming parallelism error */ #define FLASH_F7_SR_PGA_ERR 5 /* Programming alignment error */ #define FLASH_F7_SR_WRP_ERR 4 /* Write protection error */ #define FLASH_F7_SR_OP_ERR 1 /* Operation error */ #define FLASH_F7_SR_EOP 0 /* End of operation */ #define FLASH_F7_SR_ERROR_MASK \ ((1 << FLASH_F7_SR_ERS_ERR) | (1 << FLASH_F7_SR_PGP_ERR) | \ (1 << FLASH_F7_SR_PGA_ERR) | (1 << FLASH_F7_SR_WRP_ERR) | \ (1 << FLASH_F7_SR_OP_ERR)) // == STM32G0/G4 == // G0/G4 Flash registers (RM0440, p.146) #define FLASH_Gx_REGS_ADDR ((uint32_t)0x40022000) #define FLASH_Gx_ACR (FLASH_Gx_REGS_ADDR + 0x00) #define FLASH_Gx_KEYR (FLASH_Gx_REGS_ADDR + 0x08) #define FLASH_Gx_OPTKEYR (FLASH_Gx_REGS_ADDR + 0x0c) #define FLASH_Gx_SR (FLASH_Gx_REGS_ADDR + 0x10) #define FLASH_Gx_CR (FLASH_Gx_REGS_ADDR + 0x14) #define FLASH_Gx_ECCR (FLASH_Gx_REGS_ADDR + 0x18) #define FLASH_Gx_OPTR (FLASH_Gx_REGS_ADDR + 0x20) // G0/G4 Flash control register #define FLASH_Gx_CR_PG (0) /* Program */ #define FLASH_Gx_CR_PER (1) /* Page erase */ #define FLASH_Gx_CR_MER1 (2) /* Mass erase */ #define FLASH_Gx_CR_PNB (3) /* Page number */ #define FLASH_G0_CR_PNG_LEN (5) /* STM32G0: 5 page number bits */ #define FLASH_G4_CR_PNG_LEN (7) /* STM32G4: 7 page number bits */ #define FLASH_Gx_CR_MER2 (15) /* Mass erase (2nd bank)*/ #define FLASH_Gx_CR_STRT (16) /* Start */ #define FLASH_Gx_CR_OPTSTRT (17) /* Start of modification of option bytes */ #define FLASH_Gx_CR_FSTPG (18) /* Fast programming */ #define FLASH_Gx_CR_EOPIE (24) /* End of operation interrupt enable */ #define FLASH_Gx_CR_ERRIE (25) /* Error interrupt enable */ #define FLASH_Gx_CR_OBL_LAUNCH (27) /* Forces the option byte loading */ #define FLASH_Gx_CR_OPTLOCK (30) /* Options Lock */ #define FLASH_Gx_CR_LOCK (31) /* FLASH_CR Lock */ // G0/G4 Flash status register #define FLASH_Gx_SR_ERROR_MASK (0x3fa) #define FLASH_Gx_SR_PROGERR (3) #define FLASH_Gx_SR_WRPERR (4) #define FLASH_Gx_SR_PGAERR (5) #define FLASH_Gx_SR_BSY (16) /* FLASH_SR Busy */ #define 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 FLASH_G0_REGS_ADDR (FLASH_Gx_REGS_ADDR) #define FLASH_G0_PCROP1ASR (FLASH_G0_REGS_ADDR + 0x24) #define FLASH_G0_PCROP1AER (FLASH_G0_REGS_ADDR + 0x28) #define FLASH_G0_WRP1AR (FLASH_G0_REGS_ADDR + 0x2c) #define FLASH_G0_WRP1BR (FLASH_G0_REGS_ADDR + 0x30) #define FLASH_G0_PCROP1BSR (FLASH_G0_REGS_ADDR + 0x34) #define FLASH_G0_PCROP1BER (FLASH_G0_REGS_ADDR + 0x38) #define FLASH_G0_SECR (FLASH_G0_REGS_ADDR + 0x80) // == STM32G4 == (RM0440 Table 17, sec. 3.7.19) #define 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 FLASH_G4_REGS_ADDR (FLASH_Gx_REGS_ADDR) #define FLASH_G4_PDKEYR (FLASH_G4_REGS_ADDR + 0x04) #define FLASH_G4_PCROP1SR (FLASH_G4_REGS_ADDR + 0x24) #define FLASH_G4_PCROP1ER (FLASH_G4_REGS_ADDR + 0x28) #define FLASH_G4_WRP1AR (FLASH_G4_REGS_ADDR + 0x2c) #define FLASH_G4_WRP1BR (FLASH_G4_REGS_ADDR + 0x30) #define FLASH_G4_PCROP2SR (FLASH_G4_REGS_ADDR + 0x44) #define FLASH_G4_PCROP2ER (FLASH_G4_REGS_ADDR + 0x48) #define FLASH_G4_WRP2AR (FLASH_G4_REGS_ADDR + 0x4c) #define FLASH_G4_WRP2BR (FLASH_G4_REGS_ADDR + 0x50) #define FLASH_G4_SEC1R (FLASH_G4_REGS_ADDR + 0x70) #define FLASH_G4_SEC2R (FLASH_G4_REGS_ADDR + 0x74) // == STM32H7 == // H7 Flash registers #define FLASH_H7_REGS_ADDR ((uint32_t)0x52002000) #define FLASH_H7_KEYR1 (FLASH_H7_REGS_ADDR + 0x04) #define FLASH_H7_KEYR2 (FLASH_H7_REGS_ADDR + 0x104) #define FLASH_H7_OPT_KEYR (FLASH_H7_REGS_ADDR + 0x08) #define FLASH_H7_OPT_KEYR2 (FLASH_H7_REGS_ADDR + 0x108) #define FLASH_H7_CR1 (FLASH_H7_REGS_ADDR + 0x0c) #define FLASH_H7_CR2 (FLASH_H7_REGS_ADDR + 0x10c) #define FLASH_H7_SR1 (FLASH_H7_REGS_ADDR + 0x10) #define FLASH_H7_SR2 (FLASH_H7_REGS_ADDR + 0x110) #define FLASH_H7_CCR1 (FLASH_H7_REGS_ADDR + 0x14) #define FLASH_H7_CCR2 (FLASH_H7_REGS_ADDR + 0x114) #define FLASH_H7_OPTCR (FLASH_H7_REGS_ADDR + 0x18) #define FLASH_H7_OPTCR2 (FLASH_H7_REGS_ADDR + 0x118) #define FLASH_H7_OPTSR_CUR (FLASH_H7_REGS_ADDR + 0x1c) #define FLASH_H7_OPTCCR (FLASH_H7_REGS_ADDR + 0x24) #define FLASH_H7_OPTCR_OPTLOCK 0 #define FLASH_H7_OPTCR_OPTSTART 1 #define FLASH_H7_OPTCR_MER 4 #define FLASH_H7_OPTSR_OPT_BUSY 0 #define FLASH_H7_OPTSR_OPTCHANGEERR 30 #define FLASH_H7_OPTCCR_CLR_OPTCHANGEERR 30 // H7 Flash control register #define FLASH_H7_CR_LOCK 0 #define FLASH_H7_CR_PG 1 #define FLASH_H7_CR_SER 2 #define FLASH_H7_CR_BER 3 #define FLASH_H7_CR_PSIZE 4 #define FLASH_H7_CR_START(chipid) (chipid == STM32_CHIPID_H7Ax ? 5 : 7) #define FLASH_H7_CR_SNB 8 #define FLASH_H7_CR_SNB_MASK 0x700 // H7 Flash status register #define FLASH_H7_SR_QW 2 #define FLASH_H7_SR_WRPERR 17 #define FLASH_H7_SR_PGSERR 18 #define FLASH_H7_SR_STRBERR 19 #define FLASH_H7_SR_ERROR_MASK \ ((1 << FLASH_H7_SR_PGSERR) | (1 << FLASH_H7_SR_STRBERR) | \ (1 << FLASH_H7_SR_WRPERR)) // == STM32L0/L1/L4/L5 == // Lx Flash registers #define FLASH_Lx_REGS_ADDR ((uint32_t)0x40023c00) #define FLASH_Lx_ACR (FLASH_Lx_REGS_ADDR + 0x00) #define FLASH_Lx_PECR (FLASH_Lx_REGS_ADDR + 0x04) #define FLASH_Lx_PDKEYR (FLASH_Lx_REGS_ADDR + 0x08) #define FLASH_Lx_PEKEYR (FLASH_Lx_REGS_ADDR + 0x0c) #define FLASH_Lx_PRGKEYR (FLASH_Lx_REGS_ADDR + 0x10) #define FLASH_Lx_OPTKEYR (FLASH_Lx_REGS_ADDR + 0x14) #define FLASH_Lx_SR (FLASH_Lx_REGS_ADDR + 0x18) #define FLASH_Lx_OBR (FLASH_Lx_REGS_ADDR + 0x1c) #define FLASH_Lx_WRPR (FLASH_Lx_REGS_ADDR + 0x20) // == STM32L0 == // L0 Flash registers #define FLASH_L0_PEKEY1 0x89abcdef #define FLASH_L0_PEKEY2 0x02030405 #define FLASH_L0_PRGKEY1 0x8c9daebf #define FLASH_L0_PRGKEY2 0x13141516 #define FLASH_L0_OPTKEY1 0xFBEAD9C8 #define FLASH_L0_OPTKEY2 0x24252627 #define FLASH_L0_REGS_ADDR ((uint32_t)0x40022000) #define FLASH_L0_PELOCK (0) #define FLASH_L0_OPTLOCK (2) #define FLASH_L0_OBL_LAUNCH (18) // L0 Flash status register #define FLASH_L0_SR_ERROR_MASK 0x00013f00 #define FLASH_L0_SR_WRPERR 8 #define FLASH_L0_SR_PGAERR 9 #define FLASH_L0_SR_NOTZEROERR 16 // == STM32L1 == // L1 Flash registers #define FLASH_L1_FPRG 10 #define FLASH_L1_PROG 3 // L1 Flash status register #define FLASH_L1_SR_ERROR_MASK 0x00003f00 #define FLASH_L1_SR_WRPERR 8 #define FLASH_L1_SR_PGAERR 9 // == STM32L4 == // L4 Flash registers // L4 register base is at FLASH_REGS_ADDR (0x40022000) #define FLASH_L4_KEYR (FLASH_REGS_ADDR + 0x08) #define FLASH_L4_OPTKEYR (FLASH_REGS_ADDR + 0x0c) #define FLASH_L4_SR (FLASH_REGS_ADDR + 0x10) #define FLASH_L4_CR (FLASH_REGS_ADDR + 0x14) #define FLASH_L4_OPTR (FLASH_REGS_ADDR + 0x20) // L4 Flash status register #define FLASH_L4_SR_ERROR_MASK 0x3f8 // SR [9:3] #define FLASH_L4_SR_PROGERR 3 #define FLASH_L4_SR_WRPERR 4 #define FLASH_L4_SR_PGAERR 5 #define FLASH_L4_SR_BSY 16 // L4 Flash control register #define FLASH_L4_CR_LOCK 31 /* Lock control register */ #define FLASH_L4_CR_OPTLOCK 30 /* Lock option bytes */ #define FLASH_L4_CR_PG 0 /* Program */ #define FLASH_L4_CR_PER 1 /* Page erase */ #define FLASH_L4_CR_MER1 2 /* Bank 1 erase */ #define FLASH_L4_CR_MER2 15 /* Bank 2 erase */ #define FLASH_L4_CR_STRT 16 /* Start command */ #define FLASH_L4_CR_OPTSTRT 17 /* Start writing option bytes */ #define FLASH_L4_CR_BKER 11 /* Bank select for page erase */ #define FLASH_L4_CR_PNB 3 /* Page number (8 bits) */ #define FLASH_L4_CR_OBL_LAUNCH 27 /* Option bytes reload */ // Bits requesting flash operations (useful when we want to clear them) #define FLASH_L4_CR_OPBITS \ (uint32_t)((1lu << FLASH_L4_CR_PG) | (1lu << FLASH_L4_CR_PER) | \ (1lu << FLASH_L4_CR_MER1) | (1lu << FLASH_L4_CR_MER1)) // Page is fully specified by BKER and PNB #define FLASH_L4_CR_PAGEMASK (uint32_t)(0x1fflu << FLASH_L4_CR_PNB) #define FLASH_L4_OPTR_DUALBANK 21 // == STM32L5 == (RM0438, p.241) // L5 Flash registers #define FLASH_L5_REGS_ADDR ((uint32_t)0x40022000) #define FLASH_L5_ACR (FLASH_L5_REGS_ADDR + 0x00) #define FLASH_L5_NSKEYR (FLASH_L5_REGS_ADDR + 0x08) #define FLASH_L5_OPTKEYR (FLASH_L5_REGS_ADDR + 0x10) #define FLASH_L5_NSSR (FLASH_L5_REGS_ADDR + 0x20) #define FLASH_L5_NSCR (FLASH_L5_REGS_ADDR + 0x28) #define FLASH_L5_ECCR (FLASH_L5_REGS_ADDR + 0x30) #define FLASH_L5_OPTR (FLASH_L5_REGS_ADDR + 0x40) // FLASH_NSCR control registers (RM0438, p. 242) #define FLASH_L5_NSCR_NSPG 0 /* Program */ #define FLASH_L5_NSCR_NSPER 1 /* Page erase */ #define FLASH_L5_NSCR_NSMER1 2 /* Bank 1 erase */ #define FLASH_L5_NSCR_NSPNB 3 /* Page number (7 bits) */ #define FLASH_L5_NSCR_NSBKER 11 /* Bank select for page erase */ #define FLASH_L5_NSCR_NSMER2 15 /* Bank 2 erase */ #define FLASH_L5_NSCR_NSSTRT 16 /* Start command */ #define FLASH_L5_NSCR_NSOPTSTRT 17 /* Start writing option bytes */ #define FLASH_L5_NSCR_NSEOPIE 24 #define FLASH_L5_NSCR_NSERRIE 25 #define FLASH_L5_NSCR_OBL_LAUNCH 27 /* Option bytes reload */ #define FLASH_L5_NSCR_OPTLOCK 30 /* Lock option bytes */ #define FLASH_L5_NSCR_NSLOCK 31 /* Lock control register */ // FLASH_NSSR status register (RM0438, p. 241) #define FLASH_L5_NSSR_NSEOP 0 /* End of Operation */ #define FLASH_L5_NSSR_NSOPERR 1 #define FLASH_L5_NSSR_NSPROGERR 3 #define FLASH_L5_NSSR_NSWRPERR 4 #define FLASH_L5_NSSR_NSPGAERR 5 #define FLASH_L5_NSSR_NSSIZERR 6 #define FLASH_L5_NSSR_NSPGSERR 7 #define FLASH_L5_NSSR_OPTWERR 12 #define FLASH_L5_NSSR_BSY 16 /* Busy */ #define FLASH_L5_NSSR_ERROR_MASK (0x20fa) // == STM32WB == (RM0434) // WB Flash registers #define FLASH_WB_REGS_ADDR ((uint32_t)0x58004000) #define FLASH_WB_ACR (FLASH_WB_REGS_ADDR + 0x00) #define FLASH_WB_KEYR (FLASH_WB_REGS_ADDR + 0x08) #define FLASH_WB_OPT_KEYR (FLASH_WB_REGS_ADDR + 0x0c) #define FLASH_WB_SR (FLASH_WB_REGS_ADDR + 0x10) #define FLASH_WB_CR (FLASH_WB_REGS_ADDR + 0x14) #define FLASH_WB_ECCR (FLASH_WB_REGS_ADDR + 0x18) #define FLASH_WB_OPTR (FLASH_WB_REGS_ADDR + 0x20) #define FLASH_WB_PCROP1ASR (FLASH_WB_REGS_ADDR + 0x24) #define FLASH_WB_PCROP1AER (FLASH_WB_REGS_ADDR + 0x28) #define FLASH_WB_WRP1AR (FLASH_WB_REGS_ADDR + 0x2c) #define FLASH_WB_WRP1BR (FLASH_WB_REGS_ADDR + 0x30) #define FLASH_WB_PCROP1BSR (FLASH_WB_REGS_ADDR + 0x34) #define FLASH_WB_PCROP1BER (FLASH_WB_REGS_ADDR + 0x38) #define FLASH_WB_IPCCBR (FLASH_WB_REGS_ADDR + 0x3c) #define FLASH_WB_C2ACR (FLASH_WB_REGS_ADDR + 0x5c) #define FLASH_WB_C2SR (FLASH_WB_REGS_ADDR + 0x60) #define FLASH_WB_C2CR (FLASH_WB_REGS_ADDR + 0x64) #define FLASH_WB_SFR (FLASH_WB_REGS_ADDR + 0x80) #define FLASH_WB_SRRVR (FLASH_WB_REGS_ADDR + 0x84) // WB Flash control register #define FLASH_WB_CR_STRT (16) /* Start */ #define FLASH_WB_CR_OPTSTRT (17) /* Start writing option bytes */ #define FLASH_WB_CR_OBL_LAUNCH (27) /* Forces the option byte loading */ #define FLASH_WB_CR_OPTLOCK (30) /* Option Lock */ #define FLASH_WB_CR_LOCK (31) /* Lock */ // WB Flash status register #define FLASH_WB_SR_ERROR_MASK (0x3f8) // SR [9:3] #define FLASH_WB_SR_PROGERR (3) /* Programming alignment error */ #define FLASH_WB_SR_WRPERR (4) /* Write protection error */ #define FLASH_WB_SR_PGAERR (5) /* Programming error */ #define FLASH_WB_SR_BSY (16) /* Busy */ #endif // STM32FLASH_H stlink-1.8.0/inc/version.h.in000066400000000000000000000004121455655054600160540ustar00rootroot00000000000000#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.8.0/mingw64-build.bat000066400000000000000000000004071455655054600161240ustar00rootroot00000000000000@echo on mkdir build-mingw cd build-mingw set PATH=C:\Program Files\CMake\bin;C:\mingw-w64\x86_64-13.2.0-release-win32-seh-msvcrt-rt_v11-rev1\mingw64\bin;%PATH% cmake -G "MinGW Makefiles" .. mingw32-make mingw32-make install mingw32-make package cd .. stlink-1.8.0/src/000077500000000000000000000000001455655054600136325ustar00rootroot00000000000000stlink-1.8.0/src/st-flash/000077500000000000000000000000001455655054600153535ustar00rootroot00000000000000stlink-1.8.0/src/st-flash/flash.c000066400000000000000000000265551455655054600166310ustar00rootroot00000000000000/* * File: flash.c * * Tool st-flash - Simple wrapper around the stlink_flash_write function */ #include #include #include #include #include #include #if defined(_WIN32) #include #else #include #endif // _WIN32 #include #include #include "flash.h" #include "flash_opts.h" #include #include #include #include #include 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("command line: ./st-flash [--debug] [--reset] [--connect-under-reset] [--hot-plug] [--opt] [--serial ] [--format ] [--flash=] [--freq=] [--area=] {read|write} [path] [addr] [size]"); puts("command line: ./st-flash [--debug] [--connect-under-reset] [--hot-plug] [--freq=] [--serial ] erase [addr] [size]"); puts("command line: ./st-flash [--debug] [--freq=] [--serial ] reset"); puts(" , and : Use hex format."); puts(" : Use decimal, octal or hex (prefix 0xXXX) format, optionally followed by k=KB, or m=MB (eg. --flash=128k)"); puts(" : Can be 'binary' (default) or 'ihex', although must be specified for binary format only."); puts(" : Can be 'main' (default), 'system', 'otp', 'optcr', 'optcr1', 'option' or 'option_boot_add'"); puts("print tool version info: ./st-flash [--version]"); puts("example read option byte: ./st-flash --area=option read [path] [size]"); puts("example write option byte: ./st-flash --area=option write 0xXXXXXXXX"); puts("On selected targets:"); puts("example read boot_add option byte: ./st-flash --area=option_boot_add read"); puts("example write boot_add option byte: ./st-flash --area=option_boot_add write 0xXXXXXXXX"); puts("example read option control register byte: ./st-flash --area=optcr read"); puts("example write option control register1 byte: ./st-flash --area=optcr write 0xXXXXXXXX"); puts("example read option control register1 byte: ./st-flash --area=optcr1 read"); puts("example write option control register1 byte: ./st-flash --area=optcr1 write 0xXXXXXXXX"); puts("example read OTP area: ./st-flash --area=otp read [path]"); puts("example write OTP area: ./st-flash --area=otp write [path] 0xXXXXXXXX"); } int32_t main(int32_t ac, char** av) { stlink_t* sl = NULL; struct flash_opts o; int32_t err = -1; uint8_t * mem = NULL; o.size = 0; o.connect = CONNECT_NORMAL; if (flash_get_opts(&o, ac - 1, av + 1) == -1) { printf("invalid command line\n"); usage(); return (-1); } printf("st-flash %s\n", STLINK_VERSION); init_chipids (STLINK_CHIPS_DIR); sl = stlink_open_usb(o.log_level, o.connect, (char *)o.serial, o.freq); if (sl == NULL) { return (-1); } if (sl->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; 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; // 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); } else { err = stlink_fwrite_flash(sl, o.filename, o.addr); } 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); 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 (o.size > 0 && o.addr > 0) { err = stlink_erase_flash_section(sl, o.addr, o.size, false); } else { err = stlink_erase_flash_mass(sl); } if (err == -1) { printf("stlink_erase_flash_mass() == -1\n"); goto on_error; } printf("Mass erase completed successfully.\n"); // reset after erase if (stlink_reset(sl, RESET_AUTO)) { printf("Failed to reset device\n"); goto on_error; } } else if (o.cmd == CMD_RESET) { // reset if (stlink_reset(sl, RESET_AUTO)) { printf("Failed to reset device\n"); goto on_error; } } else { // read 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.8.0/src/st-flash/flash.h000066400000000000000000000004451455655054600166240ustar00rootroot00000000000000/* * File: flash.h * * Tool st-flash */ #ifndef FLASH_H #define FLASH_H #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.8.0/src/st-flash/flash_opts.c000066400000000000000000000304031455655054600176610ustar00rootroot00000000000000/* * File: flash_opts.c * * Flash Options */ #include #include #include #include #include #include #include "flash_opts.h" #include "flash.h" #include static bool starts_with(const char * str, const char * prefix) { uint32_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 = 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], "--debug") == 0) { o->log_level = DEBUG_LOG_LEVEL; } else if (strcmp(av[0], "--opt") == 0) { o->opt = 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 = (size_t)flash_size; } } 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_t) 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_t) 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_t) 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.8.0/src/st-flash/flash_opts.h000066400000000000000000000026771455655054600177020ustar00rootroot00000000000000/* * File: flash_opts.h * * Flash Options */ #ifndef FLASH_OPTS_H #define FLASH_OPTS_H #define FLASH_OPTS_INITIALIZER {0, { 0 }, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} enum flash_cmd {FLASH_CMD_NONE = 0, FLASH_CMD_WRITE = 1, FLASH_CMD_READ = 2, FLASH_CMD_ERASE = 3, CMD_RESET = 4}; enum flash_format {FLASH_FORMAT_BINARY = 0, FLASH_FORMAT_IHEX = 1}; enum flash_area {FLASH_MAIN_MEMORY = 0, FLASH_SYSTEM_MEMORY = 1, FLASH_OTP = 2, FLASH_OPTION_BYTES = 3, FLASH_OPTION_BYTES_BOOT_ADD = 4, FLASH_OPTCR = 5, FLASH_OPTCR1 = 6}; struct flash_opts { enum flash_cmd cmd; uint8_t serial[STLINK_SERIAL_BUFFER_SIZE]; const char* filename; stm32_addr_t addr; uint32_t size; int32_t reset; int32_t log_level; enum flash_format format; enum flash_area area; uint32_t val; uint32_t flash_size; // --flash=n[k, M] int32_t opt; // enable empty tail data drop optimization int32_t freq; // --freq=n[k, M] frequency of JTAG/SWD enum connect_type connect; }; // static bool starts_with(const char * str, const char * prefix); // static int32_t get_long_integer_from_char_array (const char *const str, uint64_t *read_value); // static int32_t get_integer_from_char_array (const char *const str, uint32_t *read_value); // static int32_t invalid_args(const char *expected); // static int32_t bad_arg(const char *arg); int32_t flash_get_opts(struct flash_opts* o, int32_t ac, char** av); #endif // FLASH_OPTS_H stlink-1.8.0/src/st-info/000077500000000000000000000000001455655054600152115ustar00rootroot00000000000000stlink-1.8.0/src/st-info/info.c000066400000000000000000000103501455655054600163070ustar00rootroot00000000000000/* * File: stinfo.c * * Tool st-info */ #include #include #include #include #include "info.h" #include #include #include 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=]"); } 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); } } static void stlink_probe(enum connect_type connect, int32_t freq) { stlink_t **stdevs; uint32_t size; size = 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 print_data(int32_t ac, char **av) { stlink_t* sl = NULL; enum connect_type connect = CONNECT_NORMAL; int32_t freq = 0; if (strcmp(av[1], "--version") == 0) { printf("v%s\n", STLINK_VERSION); return (0); } init_chipids(STLINK_CHIPS_DIR); for (int32_t i=2; i= 0) { continue; } } } else if (strncmp(av[i], "--freq=", 7) == 0) { freq = arg_parse_freq(av[i] + 7); if (freq >= 0) { continue; } } printf("Incorrect argument: %s\n\n", av[i]); usage(); return (-1); } // probe needs all devices unclaimed if (strcmp(av[1], "--probe") == 0) { stlink_probe(connect, freq); return (0); } // open first st-link device sl = stlink_open_usb(0, connect, NULL, freq); if (sl == NULL) { return (-1); } if (strcmp(av[1], "--serial") == 0) { printf("%s\n", sl->serial); } else if (strcmp(av[1], "--flash") == 0) { printf("0x%x\n", sl->flash_size); } else if (strcmp(av[1], "--pagesize") == 0) { printf("0x%x\n", sl->flash_pgsz); } else if (strcmp(av[1], "--sram") == 0) { printf("0x%x\n", sl->sram_size); } else if (strcmp(av[1], "--chipid") == 0) { printf("0x%.4x\n", sl->chip_id); } else if (strcmp(av[1], "--descr") == 0) { const struct stlink_chipid_params *params = stlink_chipid_get_params(sl->chip_id); if (params == NULL) { return (-1); } printf("%s\n", params->dev_type); } 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.8.0/src/st-info/info.h000066400000000000000000000005751455655054600163240ustar00rootroot00000000000000/* * File: info.h * * Tool st-info */ #ifndef INFO_H #define INFO_H // static void usage(void); // static void stlink_print_version(stlink_t *sl); // static void stlink_print_info(stlink_t *sl); // static void stlink_probe(enum connect_type connect, int32_t freq) { }; static int32_t print_data(int32_t ac, char **av); int32_t main(int32_t ac, char** av); #endif // INFO_Hstlink-1.8.0/src/st-trace/000077500000000000000000000000001455655054600153545ustar00rootroot00000000000000stlink-1.8.0/src/st-trace/trace.c000066400000000000000000000470471455655054600166320ustar00rootroot00000000000000#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 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; } 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; // 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(" -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'}, {0, 0, 0, 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; 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 '?': 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) { 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, STLINK_REG_DHCSR, STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_DEBUGEN | STLINK_REG_DHCSR_C_HALT); stlink_write_debug32(stlink, STLINK_REG_DEMCR, STLINK_REG_DEMCR_TRCENA); stlink_write_debug32(stlink, STLINK_REG_CM3_FP_CTRL, STLINK_REG_CM3_FP_CTRL_KEY); stlink_write_debug32(stlink, STLINK_REG_DWT_FUNCTION0, 0); stlink_write_debug32(stlink, STLINK_REG_DWT_FUNCTION1, 0); stlink_write_debug32(stlink, STLINK_REG_DWT_FUNCTION2, 0); stlink_write_debug32(stlink, STLINK_REG_DWT_FUNCTION3, 0); stlink_write_debug32(stlink, STLINK_REG_DWT_CTRL, 0); stlink_write_debug32(stlink, STLINK_REG_DBGMCU_CR, STLINK_REG_DBGMCU_CR_DBG_SLEEP | STLINK_REG_DBGMCU_CR_DBG_STOP | STLINK_REG_DBGMCU_CR_DBG_STANDBY | STLINK_REG_DBGMCU_CR_TRACE_IOEN | STLINK_REG_DBGMCU_CR_TRACE_MODE_ASYNC); if (stlink_trace_enable(stlink, trace_frequency)) { ELOG("Unable to turn on tracing in stlink\n"); if (!settings->force) return false; } stlink_write_debug32(stlink, STLINK_REG_TPI_CSPSR, STLINK_REG_TPI_CSPSR_PORT_SIZE_1); if (settings->core_frequency) { uint32_t prescaler = settings->core_frequency / trace_frequency - 1; if (prescaler > STLINK_REG_TPI_ACPR_MAX) { ELOG("Trace frequency prescaler %d out of range. Try setting a faster " "trace frequency.\n", prescaler); if (!settings->force) return false; } stlink_write_debug32(stlink, STLINK_REG_TPI_ACPR, prescaler); // Set TPIU_ACPR clock divisor } stlink_write_debug32(stlink, STLINK_REG_TPI_FFCR, STLINK_REG_TPI_FFCR_TRIG_IN); stlink_write_debug32(stlink, STLINK_REG_TPI_SPPR, STLINK_REG_TPI_SPPR_SWO_NRZ); stlink_write_debug32(stlink, STLINK_REG_ITM_LAR, STLINK_REG_ITM_LAR_KEY); stlink_write_debug32(stlink, STLINK_REG_ITM_TCC, 0x00000400); // Set sync counter stlink_write_debug32(stlink, STLINK_REG_ITM_TCR, STLINK_REG_ITM_TCR_TRACE_BUS_ID_1 | STLINK_REG_ITM_TCR_TS_ENA | STLINK_REG_ITM_TCR_ITM_ENA); stlink_write_debug32(stlink, STLINK_REG_ITM_TER, STLINK_REG_ITM_TER_PORTS_ALL); stlink_write_debug32(stlink, STLINK_REG_ITM_TPR, STLINK_REG_ITM_TPR_PORTS_ALL); stlink_write_debug32(stlink, STLINK_REG_DWT_CTRL, 4 * STLINK_REG_DWT_CTRL_NUM_COMP | STLINK_REG_DWT_CTRL_CYC_TAP | 0xF * STLINK_REG_DWT_CTRL_POST_INIT | 0xF * STLINK_REG_DWT_CTRL_POST_PRESET | STLINK_REG_DWT_CTRL_CYCCNT_ENA); stlink_write_debug32(stlink, STLINK_REG_DEMCR, STLINK_REG_DEMCR_TRCENA); uint32_t prescaler = 0; stlink_read_debug32(stlink, STLINK_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 = 0; 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, STLINK_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 (STLINK_CHIPS_DIR); 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 / (STLINK_REG_TPI_ACPR_MAX + 1); } if (trace_frequency > max_trace_freq || trace_frequency < min_trace_freq) { ELOG("Invalid trace frequency %d (min %d max %d)\n", trace_frequency, min_trace_freq, max_trace_freq); if (!settings.force) return APP_RESULT_UNSUPPORTED_TRACE_FREQUENCY; } if (!enable_trace(stlink, &settings, trace_frequency)) { ELOG("Unable to enable trace mode\n"); if (!settings.force) return APP_RESULT_STLINK_STATE_ERROR; } 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.8.0/src/st-trace/trace.h000066400000000000000000000015761455655054600166340ustar00rootroot00000000000000/* * File: trace.h * * Tool st-trace */ #ifndef TRACE_H #define TRACE_H int32_t stlink_trace_enable(stlink_t* sl, uint32_t frequency); int32_t stlink_trace_disable(stlink_t* sl); int32_t stlink_trace_read(stlink_t* sl, uint8_t* buf, uint32_t size); static void usage(void); static bool parse_frequency(char* text, uint32_t* result); bool parse_options(int32_t argc, char **argv, st_settings_t *settings); static stlink_t *stlink_connect(const st_settings_t *settings); static bool enable_trace(stlink_t *stlink, const st_settings_t *settings, uint32_t trace_frequency); static trace_state update_trace_idle(st_trace_t *trace, uint8_t c); static trace_state update_trace(st_trace_t *trace, uint8_t c); static bool read_trace(stlink_t *stlink, st_trace_t *trace); static void check_for_configuration_error(stlink_t *stlink, st_trace_t *trace, uint32_t trace_frequency); #endif // TRACE_Hstlink-1.8.0/src/st-util/000077500000000000000000000000001455655054600152335ustar00rootroot00000000000000stlink-1.8.0/src/st-util/gdb-remote.c000066400000000000000000000074671455655054600174420ustar00rootroot00000000000000/* * Copyright (c) 2011 Peter Zotov * Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #include #include #include #include #if defined(_WIN32) #include #else #include #include #endif #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.8.0/src/st-util/gdb-remote.h000066400000000000000000000003521455655054600174310ustar00rootroot00000000000000#ifndef GDB_REMOTE_H #define GDB_REMOTE_H #include 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.8.0/src/st-util/gdb-server.c000066400000000000000000001540651455655054600174520ustar00rootroot00000000000000/* * Copyright (c) 2011 Peter Zotov * Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ #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 #include #include "gdb-server.h" #include "gdb-remote.h" #include "memory-map.h" #include "semihosting.h" #include #include #include #include #include #include #include #include #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 // 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; } 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(); exit(1); (void)signum; } #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", optional_argument, NULL, 'F'}, {"version", no_argument, NULL, 'V'}, {"semihosting", no_argument, NULL, SEMIHOSTING_OPTION}, {"serial", required_argument, NULL, SERIAL_OPTION}, {0, 0, 0, 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" "\n" "The STLINK device to use can be specified in the environment\n" "variable STLINK_DEVICE on the format :.\n" "\n" ; int32_t option_index = 0; int32_t c; int32_t q; while ((c = getopt_long(argc, argv, "hv::p:mnu", 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); memcpy(st->serialnumber, optarg, STLINK_SERIAL_BUFFER_SIZE); 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 (STLINK_CHIPS_DIR); 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" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " ""; 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) { strcpy(map, memory_map_template_F4); } else if (sl->chip_id == STM32_CHIPID_F4_DE) { strcpy(map, 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) { strcpy(map, 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, STLINK_REG_CM3_DEMCR, &data); data |= STLINK_REG_CM3_DEMCR_TRCENA; stlink_write_debug32(sl, STLINK_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, STLINK_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, STLINK_REG_CM3_DWT_COMPn(i), addr); // insert mask stlink_write_debug32(sl, STLINK_REG_CM3_DWT_MASKn(i), mask); // insert function stlink_write_debug32(sl, STLINK_REG_CM3_DWT_FUNn(i), wf); // just to make sure the matched bit is clear ! stlink_read_debug32(sl, STLINK_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, STLINK_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, STLINK_REG_CM3_FP_CTRL, 0x03 /* KEY | ENABLE */); stlink_read_debug32(sl, STLINK_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, STLINK_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, STLINK_REG_CM7_FP_LAR, STLINK_REG_CM7_FP_LAR_KEY); } for (int32_t i = 0; i < code_break_num; i++) { code_breaks[i].type = 0; stlink_write_debug32(sl, STLINK_REG_CM3_FP_COMPn(i), 0); } } static 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, STLINK_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, STLINK_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, STLINK_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, STLINK_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, STLINK_REG_CM7_CLIDR, &clidr); cache_desc.louu = (clidr >> 27) & 7; stlink_read_debug32(sl, STLINK_REG_CM7_CCR, &ccr); ILOG("Chip clidr: %08x, I-Cache: %s, D-Cache: %s\n", clidr, ccr & STLINK_REG_CM7_CCR_IC ? "on" : "off", ccr & STLINK_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, STLINK_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, STLINK_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 & STLINK_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, STLINK_REG_CM7_DCCSW, addr | (way << way_sh)); } } } } // invalidate all I-cache to oPU if (ccr & STLINK_REG_CM7_CCR_IC) { stlink_write_debug32(sl, STLINK_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, STLINK_REG_CM7_CCR, &ccr); if (ccr & (STLINK_REG_CM7_CCR_IC | STLINK_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(queryNameLength + 1, 1); strncpy(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(length + 2, 1); reply[0] = 'm'; strncpy(&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 = 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(data_length + 1, 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(8 * 16 + 1, 1); for (int32_t i = 0; i < 16; i++) { sprintf(&reply[i * 8], "%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(8 + 1, 1); sprintf(reply, "%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}; strncpy(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(count * 2 + 1, 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); 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.8.0/src/st-util/gdb-server.h000066400000000000000000000003741455655054600174500ustar00rootroot00000000000000#ifndef GDB_SERVER_H #define GDB_SERVER_H #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.8.0/src/st-util/memory-map.h000066400000000000000000000337331455655054600175000ustar00rootroot00000000000000#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.8.0/src/st-util/semihosting.c000066400000000000000000000311161455655054600177320ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include "semihosting.h" #include #include 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); *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.8.0/src/st-util/semihosting.h000066400000000000000000000016431455655054600177410ustar00rootroot00000000000000#ifndef SEMIHOSTING_H #define SEMIHOSTING_H #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 0x0E #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.8.0/src/stlink-gui/000077500000000000000000000000001455655054600157205ustar00rootroot00000000000000stlink-1.8.0/src/stlink-gui/CMakeLists.txt000066400000000000000000000024021455655054600204560ustar00rootroot00000000000000### # Build GUI ### if (NOT WIN32) find_package(PkgConfig) pkg_check_modules(GTK3 gtk+-3.0) ## GUI-Building requires the presence of a GTK3 toolset if (NOT GTK3_FOUND) message(STATUS "GTK3 not found!") return() # no GTK3 present => no GUI build else (GTK3_FOUND) message(STATUS "Found GTK3: -I${GTK3_INCLUDE_DIRS}, ${GTK3_LIBRARIES}") include_directories(SYSTEM ${GTK3_INCLUDE_DIRS}) # 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}") target_link_libraries(stlink-gui ${STLINK_LIB_SHARED} ${SSP_LIB} ${GTK3_LDFLAGS}) install(TARGETS stlink-gui DESTINATION ${CMAKE_BINDIR}) endif() endif() stlink-1.8.0/src/stlink-gui/gui.c000066400000000000000000000731331455655054600166570ustar00rootroot00000000000000#include #include #include #include #include #include #include "gui.h" #include #include #include #include #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 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->export_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->flash_button), FALSE); gtk_widget_set_sensitive(GTK_WIDGET(gui->export_button), FALSE); gtk_widget_set_sensitive(GTK_WIDGET(gui->disconnect_button), FALSE); gtk_widget_set_sensitive(GTK_WIDGET(gui->connect_button), TRUE); } 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); 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 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_write_flash_update(STlinkGUI *gui) { stlink_gui_set_sensitivity(gui, TRUE); gui->progress.activity_mode = FALSE; gtk_widget_hide(GTK_WIDGET(gui->progress.bar)); return (FALSE); } 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) < 0) { stlink_gui_set_info_error_message(gui, "Failed to write to flash"); } g_idle_add((GSourceFunc)stlink_gui_write_flash_update, 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); } } } } 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 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->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->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")); // 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 (STLINK_CHIPS_DIR); gui = g_object_new(STLINK_TYPE_GUI, NULL); stlink_gui_build_ui(gui); stlink_gui_init_dnd(gui); gtk_main(); return (0); } stlink-1.8.0/src/stlink-gui/gui.h000066400000000000000000000047651455655054600166710ustar00rootroot00000000000000#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 *connect_button; GtkToolButton *disconnect_button; GtkToolButton *flash_button; GtkToolButton *export_button; GtkToolButton *open_button; /* flash dialog */ GtkDialog *flash_dialog; GtkButton *flash_dialog_ok; GtkButton *flash_dialog_cancel; GtkEntry *flash_dialog_entry; 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.8.0/src/stlink-gui/icons/000077500000000000000000000000001455655054600170335ustar00rootroot00000000000000stlink-1.8.0/src/stlink-gui/icons/export-icons.sh000066400000000000000000000017571455655054600220330ustar00rootroot00000000000000#!/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.8.0/src/stlink-gui/icons/hicolor/000077500000000000000000000000001455655054600204725ustar00rootroot00000000000000stlink-1.8.0/src/stlink-gui/icons/hicolor/128x128/000077500000000000000000000000001455655054600214275ustar00rootroot00000000000000stlink-1.8.0/src/stlink-gui/icons/hicolor/128x128/apps/000077500000000000000000000000001455655054600223725ustar00rootroot00000000000000stlink-1.8.0/src/stlink-gui/icons/hicolor/128x128/apps/stlink-gui.png000066400000000000000000000157231455655054600251760ustar00rootroot00000000000000PNG  IHDR>asBIT|d pHYs'_'_jtEXtSoftwarewww.inkscape.org<PIDATx{XUU?<\D.Hi *x˼6cZ3ee#9?-+3.XfMiPa+*r~,{ ysZ^kښjq©hFӢENII 'OlJ_aG8;;Q~]8s #Gltǚxj1nܸ[-bcc),,kJJJHOOK7W[:nqi5j)XNUʊ+[ t[7j+FF%t( UEPYUŠ+9k mwni_n᚞C)6WV 9;!7 @UIжwWGIgCƎՇ̒2LQ)LW)jkeaH/\MQrIlW\Z_(_wh+L+?M0@yruu%""[ntx{{j(**ap8Js 䟆ÐGݘBVVnv L@aKq5ctE=;^ ??_ϋ͜Na&YTog,BB0m (v\[Ý#i mv@N --ф~ZRP*5b#XiiMwn ^6Z+KlK3@U9WVةȓ֩dOU0=mt*,=|O{k[FLзo<\P-&`~O`ݾFL^jEa5UH `{i3pcDFF; EZ %4RuwJKS)d4 P_WԩSdeehR]l+;4YY CUe!rvn0)1^pi l۶Jѣ5j$;w_6軅upj A0|{$TWFàA4h;#55T_O+<_MJJ*{a9x UUbOAPyo˓u :Ml1駧i*BHHHݜ<wvZVQ߭|"EB *J`8 e(Ξ=cMDu3Mth-[JVVkСHpqw_Y~ g44F<7'0p`}ر[Я_?!(#5镥 7h^@JJ zfe/0 C &1q'_MGS5o8L6 <ýo@NFϞ|JjXj䝿&Tj8< 8r'?A ٶm;eeeZq[oDe)Ҽsp*/' ֨ t} /A#L\~O>?#FwHLL9;̜KDDӅ]wμs0Wf),dmsҶ9pJ$)..fӦ̚* ۇH^z|r:h?Du<sFX~9dڶpדu2\KT{}o>>HL-g5~IU@thH֝\9 ԗ991k!]_*/s,O?JqawDL >3N>mm??1|pPjWu7XEkѺuk}ȱ7);{b`!'6sԩS&;]l狭 `%`L4ʙ#3xpK%%Ԣ}pk )@kG!iE=mq"WՙԩI.\0X ѳyȬEl@TT>q. ^㙾jt]OERa؇U|q}BiM=s|/Avg̩SX֮]'hҷzZwFJ( ncLSOΝ;>3`ޚ$]9 `Ou*s=Y#|w\-PwYo  Y Pl<&pCUK$tt[K3 :tY35k&doٰWSuPtIl&/0k̚~駟7U `SBbMEʕ+ڵs!Ξ=GFFFeڵ+ݻwcԨQDGn%TWW{ 'gl@Ad#R|||,Sn kq`*ߌm|hC6Vz& PJH8B'|kW"mI6ę3g oolH n [l%*j ΝCګXKS2@a…p Ujm/SO3|ĚEtC_3>!R_0UZ>J\[jj*̙!!!DE'**u]ZΏbOd[Me8}4O櫯˟ݻws[7hWUUSw^IGް_Ƴ>P FS ?8su2Q2!Q'Ovv6[ncm<<bkv:I`y?@Lבd&`y?#,CL p˚YfRFFO| [r tBCѲ?tyt]оc^ujdI?,-Q>@@0/&P>W-1$?!^#^YJ_AE>PTFf~5YVC̅=|1U۷oSR6{6oN0vFzPxC=\ƺLtTY "##YD~"kDD.*@Ϟ=em(H޽%u)p ڀZ=h-V8$ǔƔSD#3 .3 ǔNG {VH/@ T0cYLhyxG,Nض7*Ю]صkyzLtH/* p2J\Z¨erٳM]UePV T*}i6N R:7y'ʉ:=j<d"dKeZh[A9@󓓙 S:u:HMrp arK l_~uy :&Arnp`^9ǖÙT%|aN]ɛ-T0`[jiN-!Qv.] A@@pB:ɔdN9VD(c F/,Y<'' 7g";J[t)W(? bNVe6m*wydB~y-̙3P ' KCl]S+߁}bח>T-~@]qT ((*YTB?52/ݺu,OA?_VZxzz2iDƏ S<Ê@I~ _ -dW7  ,jj,X1aHۧX3l˫VGOBf7+_} 9uyClQj|>_|%&<.n['ėL}W W_-WČ+ ۋ렬дf ~> dyg75xY*0[ tу~Zyyy]cǎKv:>ICl+̘?=,粒0 BH7oW^͛o,Ǩqt`~mZ_gѢw)--5: 22oY]'Ob9ؒ~uu53f5M[SB}frS|}}ƌy_AkĠACtI~2???+'G`]x( $_UUOOCL_,SR_l+0mlT &Ý}Am9I%##9s^/ٻw8;vȹm;lF8G<~Ϟ=V^^ĉ-aеERMŅd?L  poķ!#`ș{I `:Nܭ8p~خu֕SZ6a6Iŋ 6BJÌ8W҇h"'(lV'V%Sc?6KԩS 6B][p6@1m|XR֯_+| tWM0ZINuYXx )1} ,X>c"8?i{~ PRpr6 Y$_c'd4wk̝HTÒp‴=3M|u($ZOOK,xW_%奰x6fbP*]-v{\+^}u|·yE> g6{0u*~ZwߍcwdO"xo&;n34Nʜ9xҦ4,{VdA\,7!m/n؃l|P^~;4 |1&MŅِu/43tuht<ēYNNN,_4k0FT6Gf y?L1I&}vÝYkƏȻfL|ifGҩA}I@tH=äH^[ ƌy@df1u0@c,== #7sԨh$wuueUDGW1sAӰ`jNNÆٳ\]]Yoȹ o&MڗBS'c b0 f]zj_AKaAkqKG%FO<;zD3<Ç$77W;6g"#3rY@:;]l0{FdddER?5)i g(4?y򤬏 \Y]_iûp&:z(a=ҋ>|k׮AE:PU~xNJ)h:k3ZKFҥXtu:kʰa.ۢ~$: ] n65:U2tZOJZnByp+0@0RS OJH_Y.0- M rt"6sʙNg3%o `'h_ lj4l+Cb_xtcHLLS8Pg׏+" sf;*\Q,\tiG͸QPw pr}`3СZV@3nhZ:tP5WZ8h233&pP3n8;;Q~ Ќ[ -[+|IENDB`stlink-1.8.0/src/stlink-gui/icons/hicolor/16x16/000077500000000000000000000000001455655054600212575ustar00rootroot00000000000000stlink-1.8.0/src/stlink-gui/icons/hicolor/16x16/apps/000077500000000000000000000000001455655054600222225ustar00rootroot00000000000000stlink-1.8.0/src/stlink-gui/icons/hicolor/16x16/apps/stlink-gui.png000066400000000000000000000014151455655054600250170ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYsnrtEXtSoftwarewww.inkscape.org<IDAT8MHTa{ɟ4ME12ZEA"vEDI-v-wAXJjf¤dOMi::3Όwmq{y_]yaT'o4T(' ڗvpx4NTӓ҈]̜*`|Ķb֥:g-`4^ӫtRY2aΟ?b q.INDAQ?|B[S_TeUUbO1)YH6 !iTVgK\tr'v~1nN"%&?ڏpn]_(5nIENDB`stlink-1.8.0/src/stlink-gui/icons/hicolor/22x22/000077500000000000000000000000001455655054600212515ustar00rootroot00000000000000stlink-1.8.0/src/stlink-gui/icons/hicolor/22x22/apps/000077500000000000000000000000001455655054600222145ustar00rootroot00000000000000stlink-1.8.0/src/stlink-gui/icons/hicolor/22x22/apps/stlink-gui.png000066400000000000000000000021561455655054600250140ustar00rootroot00000000000000PNG  IHDRĴl;sBIT|d pHYstEXtSoftwarewww.inkscape.org<IDAT8kL[e=wXST (1 qbF6E`f^&9#cc&Ơ11M ͖ 2) Еq\JzpRZ.F|$ޓo/^j˭ȗFv L8LR jgtVGNHVM+C\T (0dArԜ* ߏ! *CR)ݟV Lh6O?Ejj %2)LGᙣ#M58N^8~.ϔ )ӌ%n:BSTbUB FHn7>3 ,+PilnޖHݗ۠ CŁ@dNW,Ou-tXTAEU|-lC`!4UQ榾O (:JΞ78U};ٞ a{g?G/)n(YШInC{7i}5$ )m*OTTaғjJ 6@Uu-W.s?sV@!qI~!V')c2?\Kw#Mj:` 7(\ Qz*DXr2N?ɖx­wqᣓ ,#c=W_aaR(72*)wӠΧR7doʠD*ߥ5Y[8܊p0s94L@fQkԘ >)TʊP0Kr68̞NGxan&=/;k=1|ٿwc1+fr+Azbs1fױ=v 81o6(aH,+qnhɃ$q8wnn>~>'޽[ihh ł\__ϚpS*Bti8ug ] 7x3Cladz/.$11AkkǍaDso,z;%|!L'FjdъwDdS~Nu"I`2b.δfCM((<_bk> M'*7zO1?0Ll xO@d]vOo?<}ϕro"N|_oGWn?B"l!'&3c6֕lEeA=̗?G'^9A1dƕAn E"h9,}i9¸ͷr,NEptalٳ#'1~,nxC)+?G,I=u!z&Z@ 1 S%M~4 $&^KυLPCY`%'DQPJ ަQBDH?0H9fXj?-tK*AŌxF%pFnq dX_5O-HdkKؾy=}k̎(J惕Ԯ~ST*n%L7=ITa+V=U}YOIaBF5 c\[5yp_ TPu0]FvI꽢t3U55lU3p) Hn*grzys&;% 0a8el(zSh.NEI@b^zAU4 Q<6Lf{KpD9lAf u8#BaaS[Q8od#BBՙO(ɂb_7hcBf[IENDB`stlink-1.8.0/src/stlink-gui/icons/hicolor/256x256/000077500000000000000000000000001455655054600214335ustar00rootroot00000000000000stlink-1.8.0/src/stlink-gui/icons/hicolor/256x256/apps/000077500000000000000000000000001455655054600223765ustar00rootroot00000000000000stlink-1.8.0/src/stlink-gui/icons/hicolor/256x256/apps/stlink-gui.png000066400000000000000000000343501455655054600251770ustar00rootroot00000000000000PNG  IHDR\rfsBIT|d pHYsNNsjhtEXtSoftwarewww.inkscape.org< IDATxy|Eǿ3AH %jAvWuD}w]w<^T.A@RnH @׼4Ld隤|_uO=]U]]KKK3Q-ѫmzh@C j441r+ٻwmP"##i߾=z{l8tKp,XΝ;[L544(Νcر8pb-hhTa1ceee448Ν㲚44.\] j@QQz-hhTcQF5Fv [ׂ9x[sNdNTNMB~;r6Vs-fzrj%YP EPweRb;';'➟UmِGq.vFXӊ ,^e8w P5D@@}zEӪ k(ٛI%!0d[ ‰Jr_n@P#l A!9l^5 %9W;z\qp0T^sC%%$2q ٕP yFuzlP5(+ε4!ݽT` VКa(闶CZ!P#m%hsr yNY񡬬,{Yn~zovPjߚk߳r}.řp#i&5jDzOz'$$dggIvv6ܸq4ӹr iii?SPP`}@)wvl 5WLkk~j:\]yDW9G+={w>+ߙh}Vpr\> KϞhӣ\ĉ&^{uk 1Q{50$δXի'|́<}OLOJu`);z{{|˗ထUvi:Aׁj^~N?nI+h}`Yznۛ?^jJ\њU l4KrΘۛ+W0bpͬrhjRv=V&iZl>2}4! '?ԩS1Juz6*(m#}UPq:drz>x 5jpξVJ#Pn>G/{8qݺus<[g:u] ++lJKK̼U@6lHxx="""hԨQQQDE&** ???د~GJ*Ǟv͒xyy1gΫdJrr2˖-g߿B' 33K.ɦDFF qqqҩS'k4Zgb =6d4رchժ"o>{}֭R3gpJϏ]w(?^^^D;HMbqF.y+qݺ(.Vz7j쬼&Mr,Sә6yVZmw}y0 ȑ#ׯ/رcXSOs-8?hl75">bfil% \m8 eh7޲;U`-3_=۱c'W\1ms ݥ_Y1\? w_:BDSN@[ۥWd];ٱcJ/h-S@Xwpy7li pkrh"!R)?(4S2|3F)zU~W!y$ u,"9أb$=osJvWN1Fvt[@/ZP} Y q!>A(+(b͛ӊln"i^Ь/4WpxvڣB~`a_%ӄb)mM X闝"u$n*} 3isʉo2-ˮpl&b9UqD *yGvveYIa20HԋY55_ܜO f,'WQF| G߄mbV7݈t*S? fz_Й94k֌>}z g2)g[S\.@MJif6K" ߅3eu,{n$o9hsH/nOg @Vx2M;Ͱ:l oBfM5[_45_ܜ _+Ho:˔)tL|W\aϞٳCsѻq d~:vF= {XU ̇fo.\_S"""=zG$:Ç9|G%7i&W#fcGpgU]Eu W^CBB:uR|C ve.ȄVo+!>h9Hb@7#@YYӧ`۶񨈗ڵ]vO2H~, <5Qo1?iRSS۷?. kg'q~ȑ#1l~.l쬊!R }ւv@gnҩSڵ;NrNAe͚՜:gdHIIse((Ѭ^;ӡC p8~4pM3'1h2\999L}_0{,ߕgw&v:N3cL_}5mڴeѢ0;oy󏄄':oH7yB"R;_o Z/3 ZI&Dff&SN#::?R>IF$''OيwߝǍ7*ڣ᧟6Sn]s1;V@>SCmaO+\xٳ_q㦌77PTTdƍpJOpHTQz:̔Z+V2lp""Ojjnݺeu;щ㭷4 ephH)jМ@>YM#CQҷ*!##?cnpzx_Lvvvۋ/D\\pݻ:F_Tg k5_6?v[?z(-f'h:z3t0~vL@[n\ rHOspwFՂVc+\W@~:6ldÆv}ݻ߃4ӦMc˖*,-!vHQ )"U՜@9tzYpm ,--رc;vE({0x`-13h@6lhdʞ{QQeQܵ>i^5#P&}<08$O~HJJ"))%KRfM Ș1c2d0>>=W^ϐ!Ï* Ikfw{Qkj }jz=ǡ<\ A^PG}6|QFيyqWBE"~SD7Έ4#!u Z AR NRSS5k6M6gɒ a=E~wז4)_TϪ`ٓatif"V|lXr%_~: hѢΝ(< V\状+4w#ڣ9s@gkTW{_!*!\;WJm+l۶޽svq о};kR"؝iOA5P;#\7~-ԟ!g驃 N_ݻ%O d̽~L+(}A< #CBB4F<`jgo0d3Wjf>*yb-ڸܭـs#RFC _C̒޾}# |eiaeVݸ<&8qBܻC%lܸl~mTA]/.P~P^ogRDĔ]vSXXh,5Ћ/"RsW=~}9OQ_5...V|&\ ?? e:ȡt͕Wqq ШDMo'-?'!{[Υ("<ܜ` CnK[Awh9FzK+Dڋl7.e5)_TOeP-h(;_v9F_rQ;-iObNyfŋ+ꊛ/rj"j1 `L~Ф?4WU^a.Κ?򋌌x1|eMe5q9وJoCҗP4  3aذV6rd5 䐢~g40w;|ŗ P&~X*a<4 f_OLP~H$FBP=#=p:iذ!キrd~Pb*C|'̟?e˖'rĉ7,8~xHזׁ(:@iBͺ"(͗I{JfÆ]}'m?|e6uwk"!R!?Dڵyx8x |)+WrlΒC]¦M?3Nj0bpjj:=4vSjkj#j1u`e9/c%\ƶm[9sqqqx{uc>}zk|]r>3s~;Cj_Ao. ի'zI8v/Ç9v87**1v/*+W̅b9dU(ֶYotլY3`@^'HLL$%%K.qeRSSqEE2LDDQDEEѺuk{вeKw R<he2H)R᷆HAMPS~}!33brrr " 7Zi 3 fԨyoYm[D|qc &BC}ի%poF[V!=庋/nO3] <"| mK C.f7"TB[P0M{={ AvfHTN@ ;,]EX5@Qcko#/F]ErHO招ʌJ /Z󇷅/KꐞrEP*iӏ8mHllg˅?/CzjSPӦ=Oxxƍg͚oM0obc;((. zr:79U 9 //+VbJxxhҤƊCQQ_|%,r:Om/Z@E ټy 7oaimۖ^zҳgO{!|2}%KVQ0M-i_  llM퐛fN<ɓ'Yz:vHn]#..VZ6 wYv-;v줤:=tqOKtU@sw+ʾ dAۧ_)HvZeee$$$pw]hh(ұcGڴiC۶1iӆ5kZٓkHIIa}߿={r %( Ej+lKlٶ%)_@]`#:N# AψLl-[~I&4mڔf͚ҤI7nLƍ];0j׮mWs`0punܸ7v-d~w~'))7nm?pxi|wD;)tW͕U/ժTҏ2qB ivsY#%%ve1N񎐐t:z///)))dee~7BM UDs}jzQjǡ09e0 dfJM.'BO_$ (7tYifci&VäCQ7\e?RJ5c{"9VU/XS4^M;fJi .@Uu:P/Iza-"9;>-ڈU V#>S "ܾ yRM!`Qj ICIvE tÖ9} h~JmW#}(yV(ua(j^>Tk8gYIDATƍid Poo ԷE4Ҳ"e`ULѴ9#695MYMibhN |if$@L4Mh}湚)Ys@MӴ9i+4Q@MZ |'n\=kz)c)㷂N&>Y;zk1fҔ] UI`;2L<<jHpsF8HNP4w-֜@P V ŃA4M D:wE }nD:w䋸@sMsa&D=jzj]Us1TMZH"vΚ]/A4͞&+e? p^NHH-m=HNP4w`xـ@!9tBvb9)܍"v0Ɩ /=U++L(ʗ~%R@5!0} xdzQB"n)sv iqJF@Ш-4Mv}l՜@P=Q 1*K5 X}Qyt*m.,8NoI!\ Nlkm{ƒ! D\ `uŔԳVTkb{3.qM9#2Pcn˭+kHI*J~^ : CPhchVGsQQ*:))}_PRpb3t&~ wHrk (l|n_w1p-u Bը TCvaSsm۶tލӆQqeΟ?ϱcػwg= dwfhEW1ebd!ԯ_çnwD^DFFm[^^˖-76-Vm֬SNaԨ4ojZvUXx"+VdѢ\xQ~gWLj \E\PtB2'55M~$c}K3gp@Ag}g71mKKKV dd$o&GcӴiS^ye&/> f~7o'vOV\M&1l)*__[5j}3gЧO? jւۙv;HeQo&y챱N~c|||x?qIz~T>QJ"l⺪ pa?~8ݻ[e{ƈU _ .Gzq5?ii@OVVKl3Uͅ?H=V ߮q\NFY̳|o:t|7xآP6lڵkWX_RRڵ0a" 6&,w??܍;FppϿHw֭OL4 +̓  d t f͚͜9')lA|||XzQQQwו駟ѢEKFŲeIKKl޼'|VXz"v=ԓ+{"7Nj_f݅)S2o|о"?? hEK^=._|Gş v+%%1c??Gq Bl 66-Z w^$ʢ;*L0?H>AP-xcD X:k%3fLgtwɓ<`vrjK,婧oڈNa珋mD$bUvFW_}- 4m}cLtqbn,Æ w]>w={>իW_vj=z0_y&d[$ޥ Y.C vmĆ m Inyq_2F4t<7/_vq_nn.Æu Ԁxz͠FAu8 Ma믿OL4\.]: RV=1 WV2d0W["GFF 4I5p[R@9":n 00Y9y|0t)\44424??>?lҤ AAABqw,C8T\B||O˅Y4rwE _t!-Z,/~ϑfgH4Gzf%ۦ鈎6n4SDma!Zw'1Q9ATG vsR r@7*?CCc-rv/={֩~ 4~]4eذӧOӽ{<ΝOо38jH*QD uy6ob.D^TnE8'NXـlL僁Dw6l(+W9r\tI>AlOOiZDu ?H=wS@m!/lw'N? :u꘯ >̡¿k.zmC`xb.*);-XD4`-N4dߌ+1d$RX݅7ӿ@X :h,,Aj%O&))\h߻r[isXd@,gĈW^ða˓O0ifQIY>c0lL|^YR7nT:=nhN"~A,OJBLk5lŒV>fFk;r "&MzRsQ3m6V>P1Yie^c/L}U@k;rk M{:@ ʀC)Tմ̙+[f5-dgQ sԨ|Wv~/O_ Oy@r3@fmldsYcNXN0a{ "~ ,۷o ;!. \MګWO= ~ &pY͕t2c-ƚ-=iJ9ˋ̝x72  nPcnTDZ/ҷoˣ*a֬W?./^Of@w* r0F aqf8-dkJ ݻcxu^{mx- Y~ "@3".pI?~aFXW oOf̘./^M͂{T/ 1vb_汁1s y9X0r;?BYT?pw2edy1, FOo>;ɑzM׮]S_N…3פ/ p:B;ҥ󗿼жzKOp&ޟ%P&vAbR ҵ5?Yo[x_ z?~|37Ȥ5\qOfk/;v|SG`P|bDrlv|k@_~yS!C'H< ΐdDuX".X: VŨؠQoͪY y0 V)~A'R3@pТ4\7oޤo$'';@6lXl e St'1e_NKKO~9Zjeˏ< v|U\|7x_$;=@ uwxb&Crr2 ͛@HH6}Ovl^߳YMP"r1"i|cSd%&&2p`lnݺl111 6[Iƈ h@k8-G?&?x Æ իW۷F`nmZTB)n?3J6َ;yqOΖ-?Ҽys>_QQ_`_6xꩧ-OV 7f4kL>7Öur_[;SxTCz,8iDwMhbxe˖رs` 6j}5WSk%j2)l߂wo/p[fMԩS\4`V_@ovzJ3@ U-5Рffҏ>|ٺu aaa梡 υL,n(ǓĒj<6yP׼n0@޲Rь֮8"5hm}WGl1 Z;o5jrΆ!##-q2V3;NϽwJ- &~(-rOZ$-ִN^bbIiUQSifHh}H([4D*Ys΍zM;zNTNdNTY6w.dAavp9ZШh@C#|}}m TeOihhx$ʴlСGCCMDFFҡCYM6z,XK p->>>,X^b'`ΝYrVP"##Yr%;wFfuᲲ2N8sSH e  22[SiШh441ZШh@C jFo/aIENDB`stlink-1.8.0/src/stlink-gui/icons/hicolor/32x32/000077500000000000000000000000001455655054600212535ustar00rootroot00000000000000stlink-1.8.0/src/stlink-gui/icons/hicolor/32x32/apps/000077500000000000000000000000001455655054600222165ustar00rootroot00000000000000stlink-1.8.0/src/stlink-gui/icons/hicolor/32x32/apps/stlink-gui.png000066400000000000000000000033341455655054600250150ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs ǠtEXtSoftwarewww.inkscape.org<YIDATXPT?oe@""ڮI\LAjfRMI&:2mNk4VՈ&&BHj4C+mRmQ)P²²+.by{9=wpU @vv6ꚚJVD5GƢ=V/чPtmHKm$y?r~ISpqFIvhO<@՞H :xkobZCQ\r6R?n&o7tc"^PDd#(L/>`0'*pQ+YYYht|jf֭[!|޾!CAl N%4h}^&A9y7_}e˖xB4S @zI0AfiсNюSxZAw\!?8&e2My!o*SNeg{:-G2CE0B-\bY1_?͚ӜdmE}=ܠDhIzEy.^IE? /V0|pq%Obf~`4yRhpG ۄx`NS ]%tA`;GȘV+tB:_m|'@A@P U˅ߗ`qRo-C|]N7jwW>?ȲukYnm؂~{_ɾ1sob+\E%GZLFoRWH!:fD!ܨZÏ_ɶG{ j$$ ^- 7fSg9 g _g?/7A~c 1=ůno Z2:6%P:"3,y$vNbMQ5B4sLAiww7B4.ݞM~~J=pSM˻)Jס- E}z3v " yZ"ˡ THRZRǶ|4-!#+&0S?b}F7緿H <}H^RO4v>l&=QY;!"|r!ʉO{O$ry_QyHرy8^|!HcP6i$>8sڬw,s '' uiF#yOa``PN.,I, V%V?2^qY( bO ~󖭈]oTy#0"#Ȇ^Oh|v}{Ǻ`HFa%9c _NC3,7o@GGq{%YQ(}uƸ8 /+P 8Xv 5pZPXM{{]]TLff&5EA8|5 uF qLo<] /1F0Z W % x v6<ˁ}{Qj>4'p 6G!444((2F+ݹhmtIENDB`stlink-1.8.0/src/stlink-gui/icons/hicolor/48x48/000077500000000000000000000000001455655054600212715ustar00rootroot00000000000000stlink-1.8.0/src/stlink-gui/icons/hicolor/48x48/apps/000077500000000000000000000000001455655054600222345ustar00rootroot00000000000000stlink-1.8.0/src/stlink-gui/icons/hicolor/48x48/apps/stlink-gui.png000066400000000000000000000052231455655054600250320ustar00rootroot00000000000000PNG  IHDR00WsBIT|d pHYs+tEXtSoftwarewww.inkscape.org< IDATh՘{Tu?;7u QwmiVj]]3 xEM[STknv6]s-Mh%jn)d^@̼0; z9yg~=PZZ*LJb6ov,mnd2QWg0- &|(pn}SMhK8=ne;,x `4:PfǂE?_5xZC,"i7fQF"-̚CF*^J|wN!A,YJ #tz::M. ߬;+О]e7w(u2u~ʌ%[7͛VfoWhYF!ݕw|)se"\pÁ`o߾j&G7|C[Uoʘc>#D [M)}x|h##d-Abؽ *ZVoNƳOIHtX|ĈÑ fz*AZ*Nw>%u36lpxM \vsBmPwpqxlA)G}#FTa0mW -6;D[9҃lQPPZ AQA7ƍ{G((<Ư˰+#!CLfL#96 :: M⹁V|.aBjƇ`Rk9wA)2e1b ft:9p /sX[Ӱ2v;^;v=|KKKlG&Sqc!jV] K,;vBaw86)+q tP~2'!XsxکDΜ9D@PCP݇bE uAz!;JU)8Mi APK; g+ 6e ̻^n v`4K8bB\k .܋ׯg}ԨwI<pY,tILNb2\d< gl9cpmرcIO 7([w-Z@*ud&O̘1}2qz|Iq ?/~7<f ФdFYXn4rtzv]vz\N ][)Z\L?tK[e4q} E[zӾyB0-g6ݼ_a)HJW4, [$ɍ$9_(P]]$9z;gQNq)NhAȞ> G F6/dAt$ɍa#G5IFVT|}=vݻ@$DQdqBԡ-T,[fc̄9p eȷ/}(>>tm_30'bD^) Bw0YV,]db)\ ~صW 2bulam^~Ϟ=QC 3cl*++<^~v=ˇ›B;*++z5N)I(}啵de-FQ;Av-ǻr *Cf]Q@T4!P]:-@ nAP vf|(w{{[V>|hYĮ$IZJng( >>о$ lAP ~q-Ӟ{~Rd'ڽ+k@r@Cܖu @ 9LziP(|vDiZl ;v(6,cUrs?"dYܹs:by?߉FiˣVw"ٌx"6Ncڔ91/a_bww7+.clc )ܖ ) <o`NC c_Jԟ O:cOk+ځyש<83{ 'ZGPP\|Y{Z_eýx)_Vؒ\pf٭g`9r$Ljߞ p Q0ZIENDB`stlink-1.8.0/src/stlink-gui/icons/hicolor/64x64/000077500000000000000000000000001455655054600212655ustar00rootroot00000000000000stlink-1.8.0/src/stlink-gui/icons/hicolor/64x64/apps/000077500000000000000000000000001455655054600222305ustar00rootroot00000000000000stlink-1.8.0/src/stlink-gui/icons/hicolor/64x64/apps/stlink-gui.png000066400000000000000000000066511455655054600250340ustar00rootroot00000000000000PNG  IHDR@@iqsBIT|d pHYsctEXtSoftwarewww.inkscape.org< &IDATxytTUH*T`* ) Ay dvPlM  CHdl@H@B!!S[u*UʄkUw>{ws=疐/;~m[0c թo[2@ Utv-{Jlp43*{)PU:l!HmYZ\w0p<Ͻ^eֻ5o1 4:,w@<61f_Sw{[qcPDfII=3Y,opC:Ew4 X,2HNXv5ZCPB~&ͰPjE@hfSߺL~v/>O6<QgAqr1\;vs}+8(UxWm{Jt7q`28s ǎgd+A@Ѡ |R@tΜ&;f٫=DΝÁ_c)]چCbm]HKۍn˶~{ ,J@xW\.mΰaÉ!%5vCQQO"bbbؗd]W 8`=.Mhf} 6pb1eTRSS\\֖-[2cTuxlIxOk- َc ]ؔvG݊_d,נNç@IASф> ̛p&O$S6h~p=  Zh.$wlF)C?mQPZVێ&OF!¼7R>Չ9p%r݅ 2ǎrSsAmxD@cA!cݻM~Ɓ(/C D\h,B9sftS*=ր&L +E0rs6sܺu;w^gР϶`>^P]J% $$$!7BvCyO6Vldgg嬫dee8SJUqc?Ҡ nq#Xl%>%}{?MKxx8XV3|5_(;!]Q68;;Kw3.U뀽MAŪŸȿyߞc]2"ujD iRG i5՟YJwÛEb 3U~ YBǘh@@0Ah4Vmh2Uuy JP H_"lT'ʀ p\DBkK`2Di4-oVvO@ZI6w֯()P@矦j ƍ al>=!,={uN֭[k1p!4h з(` > !|'Ő/ '9ċ߅:Ӷ nٲpLd԰uވBܸUu/77 5uHDj @p [ o&Fc\;h*GP*Qt]்\HҶ$SV$|$H;wpp0Æ %00GE)_b@r2#~^Ga:G',MP (EjqёthW9ϱcǹqB@R5b̝;G6 tܱ눈 #c?%+埙ЫW/Y3&<ϬY3yO?f>bNR.۲?}˔+VOD: ,&g|`Z-{xIOٳڵc!eCv rQC8%? #_vuEQl%7NV1$'s. l ~Qh6[|؟V$I̝^6LLu4lۇW_ }LI7|UVIqɿv3>{B{6LÏ#< QG#[ ޒ$_ar(t`x#8| DQQ=zo7Zʄ/Mazƫ\~kyWa@۞FAẁAz| ;ރm{)~8/ի2hf%8 9w<4Z5j+[/RSa 5874Q}}p_GqH7oҧgtp$ ʋP-@*I0 nݚ#Pzo54z-7Bڴiñ#GO`5}@zMC,; L~w6mp@:\AџAUE`}})?\#_uؑot"ʏUs޽˗] '2+%//yݩb4V-))H[d8h)rٌ0\Qt^&MFTT_V`Xf-k֬7f+LM<<ljm-)v$`9̞=f}1-b-:*QP؏ ]1[X9ê5US[Z 4{|=@sOoD܎6/Ux;N 윳 x\Z@X :[|ϵDDB Bp_9RX7WI:FM]p,R8Dsi5?\rg869$I|HHӧO@}-S1cEIENDB`stlink-1.8.0/src/stlink-gui/icons/stlink-gui.png000066400000000000000000000033341455655054600216320ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs ǠtEXtSoftwarewww.inkscape.org<YIDATXPT?oe@""ڮI\LAjfRMI&:2mNk4VՈ&&BHj4C+mRmQ)P²²+.by{9=wpU @vv6ꚚJVD5GƢ=V/чPtmHKm$y?r~ISpqFIvhO<@՞H :xkobZCQ\r6R?n&o7tc"^PDd#(L/>`0'*pQ+YYYht|jf֭[!|޾!CAl N%4h}^&A9y7_}e˖xB4S @zI0AfiсNюSxZAw\!?8&e2My!o*SNeg{:-G2CE0B-\bY1_?͚ӜdmE}=ܠDhIzEy.^IE? /V0|pq%Obf~`4yRhpG ۄx`NS ]%tA`;GȘV+tB:_m|'@A@P U˅ߗ`qRo-C|]N7jwW>?ȲukYnm؂~{_ɾ1sob+\E%GZLFoRWH!:fD!ܨZÏ_ɶG{ j$$ ^- 7fSg9 g _g?/7A~c 1=ůno Z2:6%P:"3,y$vNbMQ5B4sLAiww7B4.ݞM~~J=pSM˻)Jס- E}z3v " yZ"ˡ THRZRǶ|4-!#+&0S?b}F7緿H <}H^RO4v>l&=QY;!"|r!ʉO{O$ry_QyHرy8^|!HcP6i$>8sڬw,s '' uiF#yOa``PN.,I, V%V?2^qY( bO ~󖭈]oTy#0"#Ȇ^Oh|v}{Ǻ`HFa%9c _NC3,7o@GGq{%YQ(}uƸ8 /+P 8Xv 5pZPXM{{]]TLff&5EA8|5 uF qLo<] /1F0Z W % x v6<ˁ}{Qj>4'p 6G!444((2F+ݹhmtIENDB`stlink-1.8.0/src/stlink-gui/icons/stlink-gui.svg000066400000000000000000000113471455655054600216500ustar00rootroot00000000000000 image/svg+xml ST link stlink-1.8.0/src/stlink-gui/icons/stlink-gui.xpm000066400000000000000000000114211455655054600216460ustar00rootroot00000000000000/* 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.8.0/src/stlink-gui/icons/stlink-gui_48.png000066400000000000000000000052201455655054600221410ustar00rootroot00000000000000PNG  IHDR00WsBIT|d pHYs+tEXtSoftwarewww.inkscape.org< IDATh՘{Tu?;7t@S@\55")xXR2h)ZfPS̲urj:km;હyA`;30s}y;3ryYfΠpN{)Q@og.@p:x16pZZ[͉be-,Lrf_?xfWdnD-$Yr y+^pR* 0W,x̻vg1D+lu%S{ZAQ7tj8W*&_ܺSl.V1 q]Her^gĜ JB>OZG4YɈQ,]ĈÑjN]fz AUjܷ<%ck׮n@{[cn<DEӣF#*]Ljv ૄ)Xr֬v&f}DuV|>7[r#jnmTƎch4rA ljzH?dȐ!2SuE9#3sw.u~]p3DFlMI%TgvҤdKMJ%oR*tOW%N0wycR_m3XƌCV ֮ nYh!j(8`4iG @NN<3eMƁ‚]o-@cXȭЭ_uip9s70tlhrhQ2]"lҳ 1DPn$E꓎xd;=M=?]; !Kl$lDaR(hDY8N$ɍ$=_(P[[$9t;UIiqJP>ɝ6G F6,dA4$ɍa#:IF6 xm ۷;@$DQdqB-i佰\5gWDʑo_PRRYYY 90<;'tD_, BpS,_ĈQc8dS`˯@pd.<.4<ǖ͛={6U]zeKrfȻQۓ[,l 5|ںz<z$IBbfiWVi8 +o!?ŋQ:Jպ.4MXihtlBU \vBPD<ODΦwEØݸ|8P:t ==h>8+Q[sIENDB`stlink-1.8.0/src/stlink-gui/stlink-gui.desktop000066400000000000000000000003131455655054600213760ustar00rootroot00000000000000[Desktop Entry] Name=stlink GenericName=Stlink Tools Comment=Open source STM32 MCU programming toolset Exec=stlink-gui Icon=stlink-gui Terminal=false Type=Application Categories=Development;Electronics; stlink-1.8.0/src/stlink-gui/stlink-gui.ui000066400000000000000000001007041455655054600203470ustar00rootroot00000000000000 False 5 Flash device dialog False vertical 2 False end gtk-cancel True False True True False True 0 gtk-ok True False 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 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 Export device memory __glade_unnamed_9 True gtk-save 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.8.0/src/stlink-lib/000077500000000000000000000000001455655054600157025ustar00rootroot00000000000000stlink-1.8.0/src/stlink-lib/calculate.c000066400000000000000000000041711455655054600200060ustar00rootroot00000000000000/* * File: calculate.c * * Calculation of sector numbers and pages */ #include #include #include "calculate.h" #include "common_flash.h" #include "read_write.h" uint32_t calculate_F4_sectornum(uint32_t flashaddr) { uint32_t offset = 0; flashaddr &= ~STM32_FLASH_BASE; // page now holding the actual flash address if (flashaddr >= 0x100000) { offset = 12; flashaddr -= 0x100000; } if (flashaddr < 0x4000) { return (offset + 0); } else if (flashaddr < 0x8000) { return (offset + 1); } else if (flashaddr < 0xc000) { return (offset + 2); } else if (flashaddr < 0x10000) { return (offset + 3); } else if (flashaddr < 0x20000) { return (offset + 4); } else { return (offset + (flashaddr / 0x20000) + 4); } } uint32_t calculate_F7_sectornum(uint32_t flashaddr) { flashaddr &= ~STM32_FLASH_BASE; // Page now holding the actual flash address if (flashaddr < 0x20000) { return (flashaddr / 0x8000); } else if (flashaddr < 0x40000) { return (4); } else { return ((flashaddr / 0x40000) + 4); } } uint32_t calculate_H7_sectornum(stlink_t *sl, uint32_t flashaddr, uint32_t bank) { // sector holding the flash address flashaddr &= ~((bank == BANK_1) ? STM32_FLASH_BASE : STM32_H7_FLASH_BANK2_BASE); return (flashaddr / sl->flash_pgsz); } // returns BKER:PNB for the given page address uint32_t calculate_L4_page(stlink_t *sl, uint32_t flashaddr) { uint32_t bker = 0; uint32_t flashopt; stlink_read_debug32(sl, FLASH_L4_OPTR, &flashopt); flashaddr -= STM32_FLASH_BASE; if (sl->chip_id == STM32_CHIPID_L4 || sl->chip_id == STM32_CHIPID_L496x_L4A6x || sl->chip_id == STM32_CHIPID_L4Rx) { // these chips use dual bank flash if (flashopt & (uint32_t)(1lu << FLASH_L4_OPTR_DUALBANK)) { uint32_t banksize = sl->flash_size / 2; if (flashaddr >= banksize) { flashaddr -= banksize; bker = 0x100; } } } // For 1MB chips without the dual-bank option set, the page address will // overflow into the BKER bit, which gives us the correct bank:page value. return (bker | flashaddr / sl->flash_pgsz); } stlink-1.8.0/src/stlink-lib/calculate.h000066400000000000000000000005241455655054600200110ustar00rootroot00000000000000/* * File: calculate.h * * Calculation of sector numbers and pages */ #ifndef CALCULATE_H #define CALCULATE_H uint32_t calculate_F4_sectornum(uint32_t); uint32_t calculate_F7_sectornum(uint32_t); uint32_t calculate_H7_sectornum(stlink_t *, uint32_t, uint32_t); uint32_t calculate_L4_page(stlink_t *, uint32_t); #endif // CALCULATE_H stlink-1.8.0/src/stlink-lib/chipid.c000066400000000000000000000212671455655054600173160ustar00rootroot00000000000000/* * File: chipid.c * * Chip-ID parametres */ #include #include #include #include #include #include #include "chipid.h" #include "logging.h" // #include // TODO: Check use // #include // TODO: Check use static struct stlink_chipid_params *devicelist; void dump_a_chip(struct stlink_chipid_params *dev) { DLOG("# Device Type: %s\n", dev->dev_type); DLOG("# Reference Manual: RM%s\n", dev->ref_manual_id); DLOG("#\n"); DLOG("chip_id 0x%x\n", dev->chip_id); DLOG("flash_type %d\n", dev->flash_type); DLOG("flash_size_reg 0x%x\n", dev->flash_size_reg); DLOG("flash_pagesize 0x%x\n", dev->flash_pagesize); DLOG("sram_size 0x%x\n", dev->sram_size); DLOG("bootrom_base 0x%x\n", dev->bootrom_base); DLOG("bootrom_size 0x%x\n", dev->bootrom_size); DLOG("option_base 0x%x\n", dev->option_base); DLOG("option_size 0x%x\n", dev->option_size); DLOG("flags %d\n\n", dev->flags); DLOG("otp_base %d\n\n", dev->otp_base); DLOG("otp_size %d\n\n", dev->otp_size); } struct stlink_chipid_params *stlink_chipid_get_params(uint32_t chip_id) { struct stlink_chipid_params *params = NULL; for (params = devicelist; params != NULL; params = params->next) if (params->chip_id == chip_id) { DLOG("detected chip_id parameters\n\n"); dump_a_chip(params); break; } return (params); } void process_chipfile(char *fname) { FILE *fp; char *p, buf[256]; char word[64], value[64]; struct stlink_chipid_params *ts; int32_t nc; // fprintf (stderr, "processing chip-id file %s.\n", fname); fp = fopen(fname, "r"); if (!fp) { perror(fname); return; } ts = calloc(sizeof(struct stlink_chipid_params), 1); while (fgets(buf, sizeof(buf), fp) != NULL) { if (strncmp(buf, "#", strlen("#")) == 0) continue; // ignore comments if ((strncmp(buf, "\n", strlen("\n")) == 0) || (strncmp(buf, " ", strlen(" ")) == 0)) continue; // ignore empty lines if (sscanf(buf, "%63s %63s", word, value) != 2) { fprintf(stderr, "Failed to read keyword or value\n"); continue; } if (strcmp(word, "dev_type") == 0) { buf[strlen(buf) - 1] = 0; // chomp newline sscanf(buf, "%*s %n", &nc); ts->dev_type = strdup(buf + nc); } else if (strcmp(word, "ref_manual_id") == 0) { buf[strlen(buf) - 1] = 0; // chomp newline sscanf(buf, "%*s %n", &nc); ts->ref_manual_id = strdup(buf + nc); } else if (strcmp(word, "chip_id") == 0) { buf[strlen(buf) - 1] = 0; // chomp newline sscanf(buf, "%*s %n", &nc); if (sscanf(value, "%i", &ts->chip_id) < 1) { fprintf(stderr, "Failed to parse chip-id\n"); } } else if (strcmp(word, "flash_type") == 0) { buf[strlen(buf) - 1] = 0; // chomp newline sscanf(buf, "%*s %n", &nc); // Match human readable flash_type with enum stm32_flash_type { }. if(strcmp(value, "C0") == 0) { ts->flash_type = STM32_FLASH_TYPE_C0; } else if (strcmp(value, "F0_F1_F3") == 0) { ts->flash_type = STM32_FLASH_TYPE_F0_F1_F3; } else if (strcmp(value, "F1_XL") == 0) { ts->flash_type = STM32_FLASH_TYPE_F1_XL; } else if (strcmp(value, "F2_F4") == 0) { ts->flash_type = STM32_FLASH_TYPE_F2_F4; } else if (strcmp(value, "F7") == 0) { ts->flash_type = STM32_FLASH_TYPE_F7; } else if (strcmp(value, "G0") == 0) { ts->flash_type = STM32_FLASH_TYPE_G0; } else if (strcmp(value, "G4") == 0) { ts->flash_type = STM32_FLASH_TYPE_G4; } else if (strcmp(value, "H7") == 0) { ts->flash_type = STM32_FLASH_TYPE_H7; } else if (strcmp(value, "L0_L1") == 0) { ts->flash_type = STM32_FLASH_TYPE_L0_L1; } else if (strcmp(value, "L4") == 0) { ts->flash_type = STM32_FLASH_TYPE_L4; } else if (strcmp(value, "L5_U5_H5") == 0) { ts->flash_type = STM32_FLASH_TYPE_L5_U5_H5; } else if (strcmp(value, "WB_WL") == 0) { ts->flash_type = STM32_FLASH_TYPE_WB_WL; } else { ts->flash_type = STM32_FLASH_TYPE_UNKNOWN; } } else if (strcmp(word, "flash_size_reg") == 0) { buf[strlen(buf) - 1] = 0; // chomp newline sscanf(buf, "%*s %n", &nc); if (sscanf(value, "%i", &ts->flash_size_reg) < 1) { fprintf(stderr, "Failed to parse flash size reg\n"); } } else if (strcmp(word, "flash_pagesize") == 0) { buf[strlen(buf) - 1] = 0; // chomp newline sscanf(buf, "%*s %n", &nc); if (sscanf(value, "%i", &ts->flash_pagesize) < 1) { fprintf(stderr, "Failed to parse flash page size\n"); } } else if (strcmp(word, "sram_size") == 0) { buf[strlen(buf) - 1] = 0; // chomp newline sscanf(buf, "%*s %n", &nc); if (sscanf(value, "%i", &ts->sram_size) < 1) { fprintf(stderr, "Failed to parse SRAM size\n"); } } else if (strcmp(word, "bootrom_base") == 0) { buf[strlen(buf) - 1] = 0; // chomp newline sscanf(buf, "%*s %n", &nc); if (sscanf(value, "%i", &ts->bootrom_base) < 1) { fprintf(stderr, "Failed to parse BootROM base\n"); } } else if (strcmp(word, "bootrom_size") == 0) { buf[strlen(buf) - 1] = 0; // chomp newline sscanf(buf, "%*s %n", &nc); if (sscanf(value, "%i", &ts->bootrom_size) < 1) { fprintf(stderr, "Failed to parse BootROM size\n"); } } else if (strcmp(word, "option_base") == 0) { buf[strlen(buf) - 1] = 0; // chomp newline sscanf(buf, "%*s %n", &nc); if (sscanf(value, "%i", &ts->option_base) < 1) { fprintf(stderr, "Failed to parse option base\n"); } } else if (strcmp(word, "option_size") == 0) { buf[strlen(buf) - 1] = 0; // chomp newline sscanf(buf, "%*s %n", &nc); if (sscanf(value, "%i", &ts->option_size) < 1) { fprintf(stderr, "Failed to parse option size\n"); } } else if (strcmp(word, "flags") == 0) { buf[strlen(buf) - 1] = 0; // chomp newline sscanf(buf, "%*s %n", &nc); p = strtok(buf, " \t\n"); while ((p = strtok(NULL, " \t\n"))) { if (strcmp(p, "none") == 0) { // NOP } else if (strcmp(p, "dualbank") == 0) { ts->flags |= CHIP_F_HAS_DUAL_BANK; } else if (strcmp(p, "swo") == 0) { ts->flags |= CHIP_F_HAS_SWO_TRACING; } else { fprintf(stderr, "Unknown flags word in %s: '%s'\n", fname, p); } } sscanf(value, "%x", &ts->flags); } else if (strcmp(word, "otp_base") == 0) { buf[strlen(buf) - 1] = 0; // chomp newline sscanf(buf, "%*s %n", &nc); if (sscanf(value, "%i", &ts->otp_base) < 1) { fprintf(stderr, "Failed to parse option size\n"); } } else if (strcmp(word, "otp_size") == 0) { buf[strlen(buf) - 1] = 0; // chomp newline sscanf(buf, "%*s %n", &nc); if (sscanf(value, "%i", &ts->otp_size) < 1) { fprintf(stderr, "Failed to parse option size\n"); } } else { fprintf(stderr, "Unknown keyword in %s: %s\n", fname, word); } } fclose(fp); ts->next = devicelist; devicelist = ts; } #if defined(STLINK_HAVE_DIRENT_H) #include void init_chipids(char *dir_to_scan) { DIR *d; uint32_t nl; // namelen struct dirent *dir; if (!dir_to_scan) { dir_to_scan = "./"; } devicelist = NULL; d = opendir(dir_to_scan); if (d) { while ((dir = readdir(d)) != NULL) { nl = strlen(dir->d_name); if (strcmp(dir->d_name + nl - 5, ".chip") == 0) { char buf[1024]; sprintf(buf, "%s/%s", dir_to_scan, dir->d_name); process_chipfile(buf); } } closedir(d); } else { perror(dir_to_scan); return; } } #endif // STLINK_HAVE_DIRENT_H #if defined(_WIN32) && !defined(STLINK_HAVE_DIRENT_H) #include #include void init_chipids(char *dir_to_scan) { HANDLE hFind = INVALID_HANDLE_VALUE; WIN32_FIND_DATAA ffd; char filepath[MAX_PATH] = {0}; StringCchCopyA(filepath, STLINK_ARRAY_SIZE(filepath), dir_to_scan); if (FAILED( StringCchCatA(filepath, STLINK_ARRAY_SIZE(filepath), "\\*.chip"))) { ELOG("Path to chips's dir too long.\n"); return; } hFind = FindFirstFileA(filepath, &ffd); if (INVALID_HANDLE_VALUE == hFind) { ELOG("Can't find any chip description file in %s.\n", filepath); return; } do { memset(filepath, 0, STLINK_ARRAY_SIZE(filepath)); StringCchCopyA(filepath, STLINK_ARRAY_SIZE(filepath), dir_to_scan); StringCchCatA(filepath, STLINK_ARRAY_SIZE(filepath), "\\"); StringCchCatA(filepath, STLINK_ARRAY_SIZE(filepath), ffd.cFileName); process_chipfile(filepath); } while (FindNextFileA(hFind, &ffd) != 0); FindClose(hFind); } #endif // defined(_WIN32) && !defined(STLINK_HAVE_DIRENT_H) stlink-1.8.0/src/stlink-lib/chipid.h000066400000000000000000000013671455655054600173220ustar00rootroot00000000000000/* * File: chipid.h * * Chip-ID parametres */ #ifndef CHIPID_H #define CHIPID_H /* 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.8.0/src/stlink-lib/commands.h000066400000000000000000000044631455655054600176630ustar00rootroot00000000000000/* * File: commands.h * * stlink commands */ #ifndef COMMANDS_H #define COMMANDS_H enum stlink_commands { STLINK_GET_VERSION = 0xF1, STLINK_DEBUG_COMMAND = 0xF2, STLINK_DFU_COMMAND = 0xF3, STLINK_GET_CURRENT_MODE = 0xF5, STLINK_GET_TARGET_VOLTAGE = 0xF7, STLINK_GET_VERSION_APIV3 = 0xFB }; enum stlink_debug_commands { STLINK_DEBUG_ENTER_JTAG_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_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 // COMMANDS_H stlink-1.8.0/src/stlink-lib/common.c000066400000000000000000001070731455655054600173460ustar00rootroot00000000000000/* == nightwalker-87: TODO: CONTENT AND USE OF THIS SOURCE FILE IS TO BE VERIFIED (07.06.2023) == */ /* TODO: This file should be split up into new or existing modules. */ /* * File: common.c * * */ #include #include #include #include #include #include // #include // TODO: Check use // #include // TODO: Check use #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 "register.h" #include "usb.h" #ifndef O_BINARY #define O_BINARY 0 #endif #ifdef _MSC_VER #define __attribute__(x) #endif // Private structs and functions defines struct stlink_fread_worker_arg { int32_t fd; }; struct stlink_fread_ihex_worker_arg { FILE *file; uint32_t addr; uint32_t lba; uint8_t buf[16]; uint8_t buf_pos; }; typedef bool (*save_block_fn)(void *arg, uint8_t *block, ssize_t len); static void stop_wdg_in_debug(stlink_t *); int32_t stlink_jtag_reset(stlink_t *, int32_t); int32_t stlink_soft_reset(stlink_t *, int32_t); void _parse_version(stlink_t *, stlink_version_t *); static uint8_t stlink_parse_hex(const char *); static int32_t stlink_read(stlink_t *, stm32_addr_t, uint32_t, save_block_fn, void *); static bool stlink_fread_ihex_init(struct stlink_fread_ihex_worker_arg *, int32_t, stm32_addr_t); static bool stlink_fread_ihex_worker(void *, uint8_t *, ssize_t); static bool stlink_fread_ihex_finalize(struct stlink_fread_ihex_worker_arg *); static bool stlink_fread_worker(void *, uint8_t *, ssize_t); // End of private structs and functions defines // Functions below are defined in stlink.h (see line num before function) // 252 void stlink_close(stlink_t *sl) { DLOG("*** stlink_close ***\n"); if (!sl) { return; } sl->backend->close(sl); free(sl); } // 250 int32_t stlink_exit_debug_mode(stlink_t *sl) { DLOG("*** stlink_exit_debug_mode ***\n"); if (sl->flash_type != STM32_FLASH_TYPE_UNKNOWN && sl->core_stat != TARGET_RESET) { // stop debugging if the target has been identified stlink_write_debug32(sl, STLINK_REG_DHCSR, STLINK_REG_DHCSR_DBGKEY); } return (sl->backend->exit_debug_mode(sl)); } //248 int32_t stlink_enter_swd_mode(stlink_t *sl) { DLOG("*** stlink_enter_swd_mode ***\n"); return (sl->backend->enter_swd_mode(sl)); } // 271 // Force the core into the debug mode -> halted state. int32_t stlink_force_debug(stlink_t *sl) { DLOG("*** stlink_force_debug_mode ***\n"); int32_t res = sl->backend->force_debug(sl); if (res) { return (res); } // Stop the watchdogs in the halted state for suppress target reboot stop_wdg_in_debug(sl); return (0); } // 251 int32_t stlink_exit_dfu_mode(stlink_t *sl) { DLOG("*** stlink_exit_dfu_mode ***\n"); return (sl->backend->exit_dfu_mode(sl)); } // 253 int32_t stlink_core_id(stlink_t *sl) { int32_t ret; DLOG("*** stlink_core_id ***\n"); ret = sl->backend->core_id(sl); if (ret == -1) { ELOG("Failed to read core_id\n"); return (ret); } if (sl->verbose > 2) { stlink_print_data(sl); } DLOG("core_id = 0x%08x\n", sl->core_id); return (ret); } // 287 // stlink_chip_id() is called by stlink_load_device_params() // do not call this procedure directly. int32_t stlink_chip_id(stlink_t *sl, uint32_t *chip_id) { int32_t ret; cortex_m3_cpuid_t cpu_id; // Read the CPU ID to determine where to read the core id if (stlink_cpu_id(sl, &cpu_id) || cpu_id.implementer_id != STLINK_REG_CMx_CPUID_IMPL_ARM) { ELOG("Can not connect to target. Please use \'connect under reset\' and try again\n"); return -1; } /* * the chip_id register in the reference manual have * DBGMCU_IDCODE / DBG_IDCODE name */ if ((sl->core_id == STM32_CORE_ID_M7F_M33_SWD || sl->core_id == STM32_CORE_ID_M7F_M33_JTAG) && cpu_id.part == STLINK_REG_CMx_CPUID_PARTNO_CM7) { // STM32H7 chipid in 0x5c001000 (RM0433 pg3189) ret = stlink_read_debug32(sl, 0x5c001000, chip_id); } else if (cpu_id.part == STLINK_REG_CMx_CPUID_PARTNO_CM0 || cpu_id.part == STLINK_REG_CMx_CPUID_PARTNO_CM0P) { // STM32F0 (RM0091, pg914; RM0360, pg713) // STM32L0 (RM0377, pg813; RM0367, pg915; RM0376, pg917) // STM32G0 (RM0444, pg1367) ret = stlink_read_debug32(sl, 0x40015800, chip_id); } else if (cpu_id.part == STLINK_REG_CMx_CPUID_PARTNO_CM33) { // STM32L5 (RM0438, pg2157) ret = stlink_read_debug32(sl, 0xE0044000, chip_id); } else /* СM3, СM4, CM7 */ { // default chipid address // STM32F1 (RM0008, pg1087; RM0041, pg681) // STM32F2 (RM0033, pg1326) // STM32F3 (RM0316, pg1095; RM0313, pg874) // STM32F7 (RM0385, pg1676; RM0410, pg1912) // STM32L1 (RM0038, pg861) // STM32L4 (RM0351, pg1840; RM0394, pg1560) // STM32G4 (RM0440, pg2086) // STM32WB (RM0434, pg1406) ret = stlink_read_debug32(sl, 0xE0042000, chip_id); } if (ret || !(*chip_id)) { *chip_id = 0; ret = ret?ret:-1; ELOG("Could not find chip id!\n"); } else { *chip_id = (*chip_id) & 0xfff; // Fix chip_id for F4 rev A errata, read CPU ID, as CoreID is the same for // F2/F4 if (*chip_id == 0x411 && cpu_id.part == STLINK_REG_CMx_CPUID_PARTNO_CM4) { *chip_id = 0x413; } } return (ret); } // 288 /** * Cortex M tech ref manual, CPUID register description * @param sl stlink context * @param cpuid pointer to the result object */ int32_t stlink_cpu_id(stlink_t *sl, cortex_m3_cpuid_t *cpuid) { uint32_t raw; if (stlink_read_debug32(sl, STLINK_REG_CM3_CPUID, &raw)) { cpuid->implementer_id = 0; cpuid->variant = 0; cpuid->part = 0; cpuid->revision = 0; return (-1); } cpuid->implementer_id = (raw >> 24) & 0x7f; cpuid->variant = (raw >> 20) & 0xf; cpuid->part = (raw >> 4) & 0xfff; cpuid->revision = raw & 0xf; return (0); } // 303 /** * Reads and decodes the flash parameters, as dynamically as possible * @param sl * @return 0 for success, or -1 for unsupported core type. */ int32_t stlink_load_device_params(stlink_t *sl) { // This seems to normally work so is unnecessary info for a normal user. // Demoted to debug. -- REW DLOG("Loading device parameters....\n"); const struct stlink_chipid_params *params = NULL; stlink_core_id(sl); uint32_t flash_size; if (stlink_chip_id(sl, &sl->chip_id)) { return (-1); } params = stlink_chipid_get_params(sl->chip_id); if (params == NULL) { WLOG("unknown chip id! %#x\n", sl->chip_id); return (-1); } if (params->flash_type == STM32_FLASH_TYPE_UNKNOWN) { WLOG("Invalid flash type, please check device declaration\n"); sl->flash_size = 0; return (0); } // These are fixed... sl->flash_base = STM32_FLASH_BASE; sl->sram_base = STM32_SRAM_BASE; stlink_read_debug32(sl, (params->flash_size_reg) & ~3, &flash_size); if (params->flash_size_reg & 2) { flash_size = flash_size >> 16; } flash_size = flash_size & 0xffff; if ((sl->chip_id == STM32_CHIPID_L1_MD || sl->chip_id == STM32_CHIPID_F1_VL_MD_LD || sl->chip_id == STM32_CHIPID_L1_MD_PLUS) && (flash_size == 0)) { sl->flash_size = 128 * 1024; } else if (sl->chip_id == STM32_CHIPID_L1_CAT2) { sl->flash_size = (flash_size & 0xff) * 1024; } else if ((sl->chip_id & 0xFFF) == STM32_CHIPID_L1_MD_PLUS_HD) { // 0 is 384k and 1 is 256k if (flash_size == 0) { sl->flash_size = 384 * 1024; } else { sl->flash_size = 256 * 1024; } } else { sl->flash_size = flash_size * 1024; } sl->flash_type = params->flash_type; sl->flash_pgsz = params->flash_pagesize; sl->sram_size = params->sram_size; sl->sys_base = params->bootrom_base; sl->sys_size = params->bootrom_size; sl->option_base = params->option_base; sl->option_size = params->option_size; sl->chip_flags = params->flags; sl->otp_base = params->otp_base; sl->otp_size = params->otp_size; // medium and low devices have the same chipid. ram size depends on flash // size. STM32F100xx datasheet Doc ID 16455 Table 2 if (sl->chip_id == STM32_CHIPID_F1_VL_MD_LD && sl->flash_size < 64 * 1024) { sl->sram_size = 0x1000; } if (sl->chip_id == STM32_CHIPID_G4_CAT3 || sl->chip_id == STM32_CHIPID_G4_CAT4) { uint32_t flash_optr; stlink_read_debug32(sl, FLASH_Gx_OPTR, &flash_optr); if (!(flash_optr & (1 << FLASH_G4_OPTR_DBANK))) { sl->flash_pgsz <<= 1; } } if (sl->chip_id == STM32_CHIPID_L5x2xx) { uint32_t flash_optr; stlink_read_debug32(sl, FLASH_L5_OPTR, &flash_optr); if (sl->flash_size == 512*1024 && (flash_optr & (1 << 22)) != 0) { sl->flash_pgsz = 0x800; } } // H7 devices with small flash has one bank if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK && sl->flash_type == STM32_FLASH_TYPE_H7) { if ((sl->flash_size / sl->flash_pgsz) <= 1) sl->chip_flags &= ~CHIP_F_HAS_DUAL_BANK; } ILOG("%s: %u KiB SRAM, %u KiB flash in at least %u %s pages.\n", params->dev_type, (sl->sram_size / 1024), (sl->flash_size / 1024), (sl->flash_pgsz < 1024) ? sl->flash_pgsz : (sl->flash_pgsz / 1024), (sl->flash_pgsz < 1024) ? "byte" : "KiB"); return (0); } // 254 int32_t stlink_reset(stlink_t *sl, enum reset_type type) { uint32_t dhcsr; uint32_t timeout; DLOG("*** stlink_reset ***\n"); sl->core_stat = TARGET_RESET; if (type == RESET_AUTO) { // clear S_RESET_ST in DHCSR register for reset state detection stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr); } if (type == RESET_HARD || type == RESET_AUTO) { // hardware target reset if (sl->version.stlink_v > 1) { stlink_jtag_reset(sl, STLINK_DEBUG_APIV2_DRIVE_NRST_LOW); // minimum reset pulse duration of 20 us (RM0008, 8.1.2 Power reset) usleep(100); stlink_jtag_reset(sl, STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH); } sl->backend->reset(sl); usleep(10000); } if (type == RESET_AUTO) { /* Check if the S_RESET_ST bit is set in DHCSR * This means that a reset has occurred * DDI0337E, p. 10-4, Debug Halting Control and Status Register */ dhcsr = 0; int32_t res = stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr); if ((dhcsr & STLINK_REG_DHCSR_S_RESET_ST) == 0 && !res) { // reset not done yet --> try reset through AIRCR so that NRST does not need to be connected ILOG("NRST is not connected --> using software reset via AIRCR\n"); DLOG("NRST not connected --> Reset through SYSRESETREQ\n"); return stlink_soft_reset(sl, 0); } // waiting for reset the S_RESET_ST bit within 500ms timeout = time_ms() + 500; while (time_ms() < timeout) { dhcsr = STLINK_REG_DHCSR_S_RESET_ST; stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr); if ((dhcsr & STLINK_REG_DHCSR_S_RESET_ST) == 0) { return (0); } } return (-1); } if (type == RESET_SOFT || type == RESET_SOFT_AND_HALT) { return stlink_soft_reset(sl, (type == RESET_SOFT_AND_HALT)); } return (0); } int32_t stlink_soft_reset(stlink_t *sl, int32_t halt_on_reset) { int32_t ret; uint32_t timeout; uint32_t dhcsr, dfsr; DLOG("*** stlink_soft_reset %s***\n", halt_on_reset ? "(halt) " : ""); // halt core and enable debugging (if not already done) // C_DEBUGEN is required to Halt on reset (DDI0337E, p. 10-6) stlink_write_debug32(sl, STLINK_REG_DHCSR, STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_HALT | STLINK_REG_DHCSR_C_DEBUGEN); // enable Halt on reset by set VC_CORERESET and TRCENA (DDI0337E, p. 10-10) if (halt_on_reset) { stlink_write_debug32( sl, STLINK_REG_CM3_DEMCR, STLINK_REG_CM3_DEMCR_TRCENA | STLINK_REG_CM3_DEMCR_VC_HARDERR | STLINK_REG_CM3_DEMCR_VC_BUSERR | STLINK_REG_CM3_DEMCR_VC_CORERESET); // clear VCATCH in the DFSR register stlink_write_debug32(sl, STLINK_REG_DFSR, STLINK_REG_DFSR_VCATCH); } else { stlink_write_debug32(sl, STLINK_REG_CM3_DEMCR, STLINK_REG_CM3_DEMCR_TRCENA | STLINK_REG_CM3_DEMCR_VC_HARDERR | STLINK_REG_CM3_DEMCR_VC_BUSERR); } // clear S_RESET_ST in the DHCSR register stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr); // soft reset (core reset) by SYSRESETREQ (DDI0337E, p. 8-23) ret = stlink_write_debug32(sl, STLINK_REG_AIRCR, STLINK_REG_AIRCR_VECTKEY | STLINK_REG_AIRCR_SYSRESETREQ); if (ret) { ELOG("Soft reset failed: error write to AIRCR\n"); return (ret); } // waiting for a reset within 500ms // DDI0337E, p. 10-4, Debug Halting Control and Status Register timeout = time_ms() + 500; while (time_ms() < timeout) { // DDI0337E, p. 10-4, Debug Halting Control and Status Register dhcsr = STLINK_REG_DHCSR_S_RESET_ST; stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr); if ((dhcsr & STLINK_REG_DHCSR_S_RESET_ST) == 0) { if (halt_on_reset) { // waiting halt by the SYSRESETREQ exception // DDI0403E, p. C1-699, Debug Fault Status Register dfsr = 0; stlink_read_debug32(sl, STLINK_REG_DFSR, &dfsr); if ((dfsr & STLINK_REG_DFSR_VCATCH) == 0) { continue; } } timeout = 0; break; } } // reset DFSR register. DFSR is power-on reset only (DDI0337H, p. 7-5) stlink_write_debug32(sl, STLINK_REG_DFSR, STLINK_REG_DFSR_CLEAR); if (timeout) { ELOG("Soft reset failed: timeout\n"); return (-1); } return (0); } // 255 int32_t stlink_run(stlink_t *sl, enum run_type type) { struct stlink_reg rr; DLOG("*** stlink_run ***\n"); /* Make sure we are in Thumb mode * Cortex-M chips don't support ARM mode instructions * xPSR may be incorrect if the vector table has invalid data */ stlink_read_reg(sl, 16, &rr); if ((rr.xpsr & (1 << 24)) == 0) { ILOG("Go to Thumb mode\n"); stlink_write_reg(sl, rr.xpsr | (1 << 24), 16); } return (sl->backend->run(sl, type)); } // 273 int32_t stlink_set_swdclk(stlink_t *sl, int32_t freq_khz) { DLOG("*** set_swdclk ***\n"); return (sl->backend->set_swdclk(sl, freq_khz)); } // 293 // this function is called by stlink_status() // do not call stlink_core_stat() directly, always use stlink_status() void stlink_core_stat(stlink_t *sl) { switch (sl->core_stat) { case TARGET_RUNNING: DLOG(" core status: running\n"); return; case TARGET_HALTED: DLOG(" core status: halted\n"); return; case TARGET_RESET: DLOG(" core status: reset\n"); return; case TARGET_DEBUG_RUNNING: DLOG(" core status: debug running\n"); return; default: DLOG(" core status: unknown\n"); } } // 256 int32_t stlink_status(stlink_t *sl) { int32_t ret; DLOG("*** stlink_status ***\n"); ret = sl->backend->status(sl); stlink_core_stat(sl); return (ret); } // 257 int32_t stlink_version(stlink_t *sl) { DLOG("*** looking up stlink version ***\n"); if (sl->backend->version(sl)) { return (-1); } _parse_version(sl, &sl->version); DLOG("st vid = 0x%04x (expect 0x%04x)\n", sl->version.st_vid, STLINK_USB_VID_ST); DLOG("stlink pid = 0x%04x\n", sl->version.stlink_pid); DLOG("stlink version = 0x%x\n", sl->version.stlink_v); DLOG("jtag version = 0x%x\n", sl->version.jtag_v); DLOG("swim version = 0x%x\n", sl->version.swim_v); if (sl->version.jtag_v == 0) { WLOG(" warning: stlink doesn't support JTAG/SWD interface\n"); } return (0); } // 272 int32_t stlink_target_voltage(stlink_t *sl) { int32_t voltage = -1; DLOG("*** reading target voltage\n"); if (sl->backend->target_voltage != NULL) { voltage = sl->backend->target_voltage(sl); if (voltage != -1) { DLOG("target voltage = %imV\n", voltage); } else { DLOG("error reading target voltage\n"); } } else { DLOG("reading voltage not supported by backend\n"); } return (voltage); } // 299 bool stlink_is_core_halted(stlink_t *sl) { stlink_status(sl); return (sl->core_stat == TARGET_HALTED); } // 269 int32_t stlink_step(stlink_t *sl) { DLOG("*** stlink_step ***\n"); return (sl->backend->step(sl)); } // 270 int32_t stlink_current_mode(stlink_t *sl) { int32_t mode = sl->backend->current_mode(sl); switch (mode) { case STLINK_DEV_DFU_MODE: DLOG("stlink current mode: dfu\n"); return (mode); case STLINK_DEV_DEBUG_MODE: DLOG("stlink current mode: debug (jtag or swd)\n"); return (mode); case STLINK_DEV_MASS_MODE: DLOG("stlink current mode: mass\n"); return (mode); } DLOG("stlink mode: unknown!\n"); return (STLINK_DEV_UNKNOWN_MODE); } // 294 void stlink_print_data(stlink_t *sl) { if (sl->q_len <= 0 || sl->verbose < UDEBUG) { return; } if (sl->verbose > 2) { DLOG("data_len = %d 0x%x\n", sl->q_len, sl->q_len); } for (int32_t i = 0; i < sl->q_len; i++) { if (i % 16 == 0) { /* if (sl->q_data_dir == Q_DATA_OUT) { fprintf(stdout, "\n<- 0x%08x ", sl->q_addr + i); } else { fprintf(stdout, "\n-> 0x%08x ", sl->q_addr + i); } */ } // DLOG(" %02x", (uint32_t) sl->q_buf[i]); fprintf(stderr, " %02x", (uint32_t)sl->q_buf[i]); } // DLOG("\n\n"); fprintf(stderr, "\n"); } // 283 int32_t stlink_mwrite_sram(stlink_t *sl, uint8_t *data, uint32_t length, stm32_addr_t addr) { // write the file in sram at addr int32_t error = -1; uint32_t off; uint32_t len; // check addr range is inside the sram if (addr < sl->sram_base) { fprintf(stderr, "addr too low\n"); goto on_error; } else if ((addr + length) < addr) { fprintf(stderr, "addr overruns\n"); goto on_error; } else if ((addr + length) > (sl->sram_base + sl->sram_size)) { fprintf(stderr, "addr too high\n"); goto on_error; } else if (addr & 3) { fprintf(stderr, "unaligned addr\n"); goto on_error; } len = length; if (len & 3) { len -= len & 3; } // do the copy by 1kB blocks for (off = 0; off < len; off += 1024) { uint32_t size = 1024; if ((off + size) > len) { size = len - off; } memcpy(sl->q_buf, data + off, size); if (size & 3) { size += 2; } // round size if needed stlink_write_mem32(sl, addr + off, (uint16_t)size); } if (length > len) { memcpy(sl->q_buf, data + len, length - len); stlink_write_mem8(sl, addr + len, (uint16_t)(length - len)); } error = 0; // success stlink_fwrite_finalize(sl, addr); on_error: return (error); } //284 int32_t stlink_fwrite_sram(stlink_t *sl, const char *path, stm32_addr_t addr) { // write the file in sram at addr int32_t error = -1; uint32_t off; uint32_t len; mapped_file_t mf = MAPPED_FILE_INITIALIZER; if (map_file(&mf, path) == -1) { fprintf(stderr, "map_file() == -1\n"); return (-1); } printf("file %s ", path); md5_calculate(&mf); stlink_checksum(&mf); // check if addr range is inside the SRAM if (addr < sl->sram_base) { fprintf(stderr, "addr too low\n"); goto on_error; } else if ((addr + mf.len) < addr) { fprintf(stderr, "addr overruns\n"); goto on_error; } else if ((addr + mf.len) > (sl->sram_base + sl->sram_size)) { fprintf(stderr, "addr too high\n"); goto on_error; } else if (addr & 3) { fprintf(stderr, "unaligned addr\n"); goto on_error; } len = mf.len; if (len & 3) { len -= len & 3; } // do the copy by 1kB blocks for (off = 0; off < len; off += 1024) { uint32_t size = 1024; if ((off + size) > len) { size = len - off; } memcpy(sl->q_buf, mf.base + off, size); if (size & 3) { size += 2; } // round size if needed stlink_write_mem32(sl, addr + off, (uint16_t)size); } if (mf.len > len) { memcpy(sl->q_buf, mf.base + len, mf.len - len); stlink_write_mem8(sl, addr + len, (uint16_t)(mf.len - len)); } // check the file has been written if (check_file(sl, &mf, addr) == -1) { fprintf(stderr, "check_file() == -1\n"); goto on_error; } error = 0; // success stlink_fwrite_finalize(sl, addr); on_error: unmap_file(&mf); return (error); } // 302 int32_t stlink_fread(stlink_t *sl, const char *path, bool is_ihex, stm32_addr_t addr, uint32_t size) { // read size bytes from addr to file ILOG("read from address %#010x size %u\n", addr, size); int32_t error; int32_t fd = open(path, O_RDWR | O_TRUNC | O_CREAT | O_BINARY, 00700); if (fd == -1) { fprintf(stderr, "open(%s) == -1\n", path); return (-1); } if (is_ihex) { struct stlink_fread_ihex_worker_arg arg; if (stlink_fread_ihex_init(&arg, fd, addr)) { error = stlink_read(sl, addr, size, &stlink_fread_ihex_worker, &arg); if (!stlink_fread_ihex_finalize(&arg)) { error = -1; } } else { error = -1; } } else { struct stlink_fread_worker_arg arg = {fd}; error = stlink_read(sl, addr, size, &stlink_fread_worker, &arg); } close(fd); return (error); } // 300 int32_t write_buffer_to_sram(stlink_t *sl, flash_loader_t *fl, const uint8_t *buf, uint16_t size) { // write the buffer right after the loader int32_t ret = 0; uint16_t chunk = size & ~0x3; uint16_t rem = size & 0x3; if (chunk) { memcpy(sl->q_buf, buf, chunk); ret = stlink_write_mem32(sl, fl->buf_addr, chunk); } if (rem && !ret) { memcpy(sl->q_buf, buf + chunk, rem); ret = stlink_write_mem8(sl, (fl->buf_addr) + chunk, rem); } return (ret); } // 291 uint32_t stlink_calculate_pagesize(stlink_t *sl, uint32_t flashaddr) { if ((sl->chip_id == STM32_CHIPID_F2) || (sl->chip_id == STM32_CHIPID_F4) || (sl->chip_id == STM32_CHIPID_F4_DE) || (sl->chip_id == STM32_CHIPID_F4_LP) || (sl->chip_id == STM32_CHIPID_F4_HD) || (sl->chip_id == STM32_CHIPID_F411xx) || (sl->chip_id == STM32_CHIPID_F446) || (sl->chip_id == STM32_CHIPID_F4_DSI) || (sl->chip_id == STM32_CHIPID_F72xxx) || (sl->chip_id == STM32_CHIPID_F412)) { uint32_t sector = calculate_F4_sectornum(flashaddr); if (sector >= 12) { sector -= 12; } if (sector < 4) { sl->flash_pgsz = 0x4000; } else if (sector < 5) { sl->flash_pgsz = 0x10000; } else { sl->flash_pgsz = 0x20000; } } else if (sl->chip_id == STM32_CHIPID_F7 || sl->chip_id == STM32_CHIPID_F76xxx) { uint32_t sector = calculate_F7_sectornum(flashaddr); if (sector < 4) { sl->flash_pgsz = 0x8000; } else if (sector < 5) { sl->flash_pgsz = 0x20000; } else { sl->flash_pgsz = 0x40000; } } return (sl->flash_pgsz); } // 279 int32_t stlink_parse_ihex(const char *path, uint8_t erased_pattern, uint8_t **mem, uint32_t *size, uint32_t *begin) { int32_t res = 0; *begin = UINT32_MAX; uint8_t *data = NULL; uint32_t end = 0; bool eof_found = false; for (int32_t scan = 0; (res == 0) && (scan < 2); ++scan) { // parse file two times - first to find memory range, second - to fill it if (scan == 1) { if (!eof_found) { ELOG("No EoF recond\n"); res = -1; break; } if (*begin >= end) { ELOG("No data found in file\n"); res = -1; break; } *size = (end - *begin) + 1; data = calloc(*size, 1); // use calloc to get NULL if out of memory if (!data) { ELOG("Cannot allocate %u bytes\n", (*size)); res = -1; break; } memset(data, erased_pattern, *size); } FILE *file = fopen(path, "r"); if (!file) { ELOG("Cannot open file\n"); res = -1; break; } uint32_t lba = 0; char line[1 + 5 * 2 + 255 * 2 + 2]; while (fgets(line, sizeof(line), file)) { if (line[0] == '\n' || line[0] == '\r') { continue; } // skip empty lines if (line[0] != ':') { // no marker - wrong file format ELOG("Wrong file format - no marker\n"); res = -1; break; } uint32_t l = strlen(line); while (l > 0 && (line[l - 1] == '\n' || line[l - 1] == '\r')) { --l; } // trim EoL if ((l < 11) || (l == (sizeof(line) - 1))) { // line too short or long - wrong file format ELOG("Wrong file format - wrong line length\n"); res = -1; break; } uint8_t chksum = 0; // check sum for (uint32_t i = 1; i < l; i += 2) { chksum += stlink_parse_hex(line + i); } if (chksum != 0) { ELOG("Wrong file format - checksum mismatch\n"); res = -1; break; } uint8_t reclen = stlink_parse_hex(line + 1); if (((uint32_t)reclen + 5) * 2 + 1 != l) { ELOG("Wrong file format - record length mismatch\n"); res = -1; break; } uint16_t offset = ((uint16_t)stlink_parse_hex(line + 3) << 8) | ((uint16_t)stlink_parse_hex(line + 5)); uint8_t rectype = stlink_parse_hex(line + 7); switch (rectype) { case 0: /* Data */ if (scan == 0) { uint32_t b = lba + offset; uint32_t e = b + reclen - 1; if (b < *begin) { *begin = b; } if (e > end) { end = e; } } else { for (uint8_t i = 0; i < reclen; ++i) { uint8_t b = stlink_parse_hex(line + 9 + i * 2); uint32_t addr = lba + offset + i; if (addr >= *begin && addr <= end) { data[addr - *begin] = b; } } } break; case 1: /* EoF */ eof_found = true; break; case 2: /* Extended Segment Address, unexpected */ res = -1; break; case 3: /* Start Segment Address, unexpected */ res = -1; break; case 4: /* Extended Linear Address */ if (reclen == 2) { lba = ((uint32_t)stlink_parse_hex(line + 9) << 24) | ((uint32_t)stlink_parse_hex(line + 11) << 16); } else { ELOG("Wrong file format - wrong LBA length\n"); res = -1; } break; case 5: /* Start Linear Address - expected, but ignore */ break; default: ELOG("Wrong file format - unexpected record type %d\n", rectype); res = -1; } if (res != 0) { break; } } fclose(file); } if (res == 0) { *mem = data; } else { free(data); } return (res); } // 280 uint8_t stlink_get_erased_pattern(stlink_t *sl) { if (sl->flash_type == STM32_FLASH_TYPE_L0_L1) { return (0x00); } else { return (0xff); } } // 322 int32_t stlink_target_connect(stlink_t *sl, enum connect_type connect) { if (connect == CONNECT_UNDER_RESET) { stlink_enter_swd_mode(sl); stlink_jtag_reset(sl, STLINK_DEBUG_APIV2_DRIVE_NRST_LOW); // try to halt the core before reset // this is useful if the NRST pin is not connected sl->backend->force_debug(sl); // minimum reset pulse duration of 20 us (RM0008, 8.1.2 Power reset) usleep(20); stlink_jtag_reset(sl, STLINK_DEBUG_APIV2_DRIVE_NRST_HIGH); // try to halt the core after reset uint32_t timeout = time_ms() + 10; while (time_ms() < timeout) { sl->backend->force_debug(sl); usleep(100); } // check NRST connection uint32_t dhcsr = 0; stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr); if ((dhcsr & STLINK_REG_DHCSR_S_RESET_ST) == 0) { WLOG("NRST is not connected\n"); } // addition soft reset for halt before the first instruction stlink_soft_reset(sl, 1 /* halt on reset */); } if (stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE && stlink_enter_swd_mode(sl)) { printf("Failed to enter SWD mode\n"); return -1; } if (connect == CONNECT_NORMAL) { stlink_reset(sl, RESET_AUTO); } return stlink_load_device_params(sl); } // End of delegates.... functions below are private to this module // same as above with entrypoint. static void stop_wdg_in_debug(stlink_t *sl) { uint32_t dbgmcu_cr; uint32_t set; uint32_t value; switch (sl->flash_type) { case STM32_FLASH_TYPE_F0_F1_F3: case STM32_FLASH_TYPE_F1_XL: case STM32_FLASH_TYPE_G4: dbgmcu_cr = STM32F0_DBGMCU_CR; set = (1 << STM32F0_DBGMCU_CR_IWDG_STOP) | (1 << STM32F0_DBGMCU_CR_WWDG_STOP); break; case STM32_FLASH_TYPE_F2_F4: case STM32_FLASH_TYPE_F7: case STM32_FLASH_TYPE_L4: dbgmcu_cr = STM32F4_DBGMCU_APB1FZR1; set = (1 << STM32F4_DBGMCU_APB1FZR1_IWDG_STOP) | (1 << STM32F4_DBGMCU_APB1FZR1_WWDG_STOP); break; case STM32_FLASH_TYPE_L0_L1: case STM32_FLASH_TYPE_G0: if (get_stm32l0_flash_base(sl) == FLASH_Lx_REGS_ADDR) { dbgmcu_cr = STM32L1_DBGMCU_APB1_FZ; set = (1 << STM32L1_DBGMCU_APB1_FZ_IWDG_STOP) | (1 << STM32L1_DBGMCU_APB1_FZ_WWDG_STOP); } else { dbgmcu_cr = STM32L0_DBGMCU_APB1_FZ; set = (1 << STM32L0_DBGMCU_APB1_FZ_IWDG_STOP) | (1 << STM32L0_DBGMCU_APB1_FZ_WWDG_STOP); } break; case STM32_FLASH_TYPE_H7: dbgmcu_cr = STM32H7_DBGMCU_APB1HFZ; set = (1 << STM32H7_DBGMCU_APB1HFZ_IWDG_STOP); break; case STM32_FLASH_TYPE_WB_WL: dbgmcu_cr = STM32WB_DBGMCU_APB1FZR1; set = (1 << STM32WB_DBGMCU_APB1FZR1_IWDG_STOP) | (1 << STM32WB_DBGMCU_APB1FZR1_WWDG_STOP); break; default: return; } if (!stlink_read_debug32(sl, dbgmcu_cr, &value)) { stlink_write_debug32(sl, dbgmcu_cr, value | set); } } int32_t stlink_jtag_reset(stlink_t *sl, int32_t value) { DLOG("*** stlink_jtag_reset %d ***\n", value); return (sl->backend->jtag_reset(sl, value)); } /** * Decode the version bits, originally from -sg, verified with usb * @param sl stlink context, assumed to contain valid data in the buffer * @param slv output parsed version object */ void _parse_version(stlink_t *sl, stlink_version_t *slv) { sl->version.flags = 0; if (sl->version.stlink_v < 3) { uint32_t b0 = sl->q_buf[0]; // lsb uint32_t b1 = sl->q_buf[1]; uint32_t b2 = sl->q_buf[2]; uint32_t b3 = sl->q_buf[3]; uint32_t b4 = sl->q_buf[4]; uint32_t b5 = sl->q_buf[5]; // msb // b0 b1 || b2 b3 | b4 b5 // 4b | 6b | 6b || 2B | 2B // stlink_v | jtag_v | swim_v || st_vid | stlink_pid slv->stlink_v = (b0 & 0xf0) >> 4; slv->jtag_v = ((b0 & 0x0f) << 2) | ((b1 & 0xc0) >> 6); slv->swim_v = b1 & 0x3f; slv->st_vid = (b3 << 8) | b2; slv->stlink_pid = (b5 << 8) | b4; // ST-LINK/V1 from J11 switch to api-v2 (and support SWD) if (slv->stlink_v == 1) { slv->jtag_api = slv->jtag_v > 11 ? STLINK_JTAG_API_V2 : STLINK_JTAG_API_V1; } else { slv->jtag_api = STLINK_JTAG_API_V2; // preferred API to get last R/W status from J15 if (sl->version.jtag_v >= 15) { sl->version.flags |= STLINK_F_HAS_GETLASTRWSTATUS2; } if (sl->version.jtag_v >= 13) { sl->version.flags |= STLINK_F_HAS_TRACE; sl->max_trace_freq = STLINK_V2_MAX_TRACE_FREQUENCY; } } } else { // V3 uses different version format, for reference see OpenOCD source // (that was written from docs available from ST under NDA): // https://github.com/ntfreak/openocd/blob/a6dacdff58ef36fcdac00c53ec27f19de1fbce0d/src/jtag/drivers/stlink_usb.c#L965 slv->stlink_v = sl->q_buf[0]; slv->swim_v = sl->q_buf[1]; slv->jtag_v = sl->q_buf[2]; slv->st_vid = (uint32_t)((sl->q_buf[9] << 8) | sl->q_buf[8]); slv->stlink_pid = (uint32_t)((sl->q_buf[11] << 8) | sl->q_buf[10]); slv->jtag_api = STLINK_JTAG_API_V3; /* preferred API to get last R/W status */ sl->version.flags |= STLINK_F_HAS_GETLASTRWSTATUS2; sl->version.flags |= STLINK_F_HAS_TRACE; sl->max_trace_freq = STLINK_V3_MAX_TRACE_FREQUENCY; } return; } void stlink_run_at(stlink_t *sl, stm32_addr_t addr) { stlink_write_reg(sl, addr, 15); /* pc register */ stlink_run(sl, RUN_NORMAL); while (stlink_is_core_halted(sl)) { usleep(3000000); } } static int32_t stlink_read(stlink_t *sl, stm32_addr_t addr, uint32_t size, save_block_fn fn, void *fn_arg) { int32_t error = -1; if (size < 1) { size = sl->flash_size; } if (size > sl->flash_size) { size = sl->flash_size; } uint32_t cmp_size = (sl->flash_pgsz > 0x1800) ? 0x1800 : sl->flash_pgsz; for (uint32_t off = 0; off < size; off += cmp_size) { uint32_t aligned_size; // adjust last page size if ((off + cmp_size) > size) { cmp_size = size - off; } aligned_size = cmp_size; if (aligned_size & (4 - 1)) { aligned_size = (cmp_size + 4) & ~(4 - 1); } stlink_read_mem32(sl, addr + off, (uint16_t)aligned_size); if (!fn(fn_arg, sl->q_buf, aligned_size)) { goto on_error; } } error = 0; // success on_error: return (error); } static bool stlink_fread_worker(void *arg, uint8_t *block, ssize_t len) { struct stlink_fread_worker_arg *the_arg = (struct stlink_fread_worker_arg *)arg; if (write(the_arg->fd, block, len) != len) { fprintf(stderr, "write() != aligned_size\n"); return (false); } else { return (true); } } // TODO: length not checked static uint8_t stlink_parse_hex(const char *hex) { uint8_t d[2]; for (int32_t i = 0; i < 2; ++i) { char c = *(hex + i); if (c >= '0' && c <= '9') { d[i] = c - '0'; } else if (c >= 'A' && c <= 'F') { d[i] = c - 'A' + 10; } else if (c >= 'a' && c <= 'f') { d[i] = c - 'a' + 10; } else { return (0); // error } } return ((d[0] << 4) | (d[1])); } static bool stlink_fread_ihex_newsegment(struct stlink_fread_ihex_worker_arg *the_arg) { uint32_t addr = the_arg->addr; uint8_t sum = 2 + 4 + (uint8_t)((addr & 0xFF000000) >> 24) + (uint8_t)((addr & 0x00FF0000) >> 16); if (17 != fprintf(the_arg->file, ":02000004%04X%02X\r\n", (addr & 0xFFFF0000) >> 16, (uint8_t)(0x100 - sum))) { return (false); } the_arg->lba = (addr & 0xFFFF0000); return (true); } static bool stlink_fread_ihex_writeline(struct stlink_fread_ihex_worker_arg *the_arg) { uint8_t count = the_arg->buf_pos; if (count == 0) { return (true); } uint32_t addr = the_arg->addr; if (the_arg->lba != (addr & 0xFFFF0000)) { // segment changed if (!stlink_fread_ihex_newsegment(the_arg)) { return (false); } } uint8_t sum = count + (uint8_t)((addr & 0x0000FF00) >> 8) + (uint8_t)(addr & 0x000000FF); if (9 != fprintf(the_arg->file, ":%02X%04X00", count, (addr & 0x0000FFFF))) { return (false); } for (uint8_t i = 0; i < count; ++i) { uint8_t b = the_arg->buf[i]; sum += b; if (2 != fprintf(the_arg->file, "%02X", b)) { return (false); } } if (4 != fprintf(the_arg->file, "%02X\r\n", (uint8_t)(0x100 - sum))) { return (false); } the_arg->addr += count; the_arg->buf_pos = 0; return (true); } static bool stlink_fread_ihex_init(struct stlink_fread_ihex_worker_arg *the_arg, int32_t fd, stm32_addr_t addr) { the_arg->file = fdopen(fd, "w"); the_arg->addr = addr; the_arg->lba = 0; the_arg->buf_pos = 0; return (the_arg->file != NULL); } static bool stlink_fread_ihex_worker(void *arg, uint8_t *block, ssize_t len) { struct stlink_fread_ihex_worker_arg *the_arg = (struct stlink_fread_ihex_worker_arg *)arg; for (ssize_t i = 0; i < len; ++i) { if (the_arg->buf_pos == sizeof(the_arg->buf)) { // line is full if (!stlink_fread_ihex_writeline(the_arg)) { return (false); } } the_arg->buf[the_arg->buf_pos++] = block[i]; } return (true); } static bool stlink_fread_ihex_finalize(struct stlink_fread_ihex_worker_arg *the_arg) { if (!stlink_fread_ihex_writeline(the_arg)) { return (false); } // FIXME: do we need the Start Linear Address? if (13 != fprintf(the_arg->file, ":00000001FF\r\n")) { // EoF return (false); } return (0 == fclose(the_arg->file)); } stlink-1.8.0/src/stlink-lib/common_flash.c000066400000000000000000001414271455655054600205240ustar00rootroot00000000000000/* * File: common_flash.c * * Flash operations */ #include #include #include #include #include #include "common_flash.h" #include "calculate.h" #include "flash_loader.h" #include "logging.h" #include "map_file.h" #include "md5.h" #include "read_write.h" #define DEBUG_FLASH 0 uint32_t get_stm32l0_flash_base(stlink_t *sl) { switch (sl->chip_id) { case STM32_CHIPID_L0_CAT1: case STM32_CHIPID_L0_CAT2: case STM32_CHIPID_L0_CAT3: case STM32_CHIPID_L0_CAT5: return (FLASH_L0_REGS_ADDR); case STM32_CHIPID_L1_CAT2: case STM32_CHIPID_L1_MD: case STM32_CHIPID_L1_MD_PLUS: case STM32_CHIPID_L1_MD_PLUS_HD: case STM32_CHIPID_L152_RE: return (FLASH_Lx_REGS_ADDR); default: WLOG("Flash base use default L0 address\n"); return (FLASH_L0_REGS_ADDR); } } uint32_t read_flash_cr(stlink_t *sl, uint32_t bank) { uint32_t reg, res; if (sl->flash_type == STM32_FLASH_TYPE_C0) { reg = FLASH_C0_CR; } else if (sl->flash_type == STM32_FLASH_TYPE_F2_F4) { reg = FLASH_F4_CR; } else if (sl->flash_type == STM32_FLASH_TYPE_F7) { reg = FLASH_F7_CR; } else if (sl->flash_type == STM32_FLASH_TYPE_G0 || sl->flash_type == STM32_FLASH_TYPE_G4) { reg = FLASH_Gx_CR; } else if (sl->flash_type == STM32_FLASH_TYPE_H7) { reg = (bank == BANK_1) ? FLASH_H7_CR1 : FLASH_H7_CR2; } else if (sl->flash_type == STM32_FLASH_TYPE_L4) { reg = FLASH_L4_CR; } else if (sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5) { reg = FLASH_L5_NSCR; } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { reg = FLASH_WB_CR; } else { reg = (bank == BANK_1) ? FLASH_CR : FLASH_CR2; } stlink_read_debug32(sl, reg, &res); #if DEBUG_FLASH fprintf(stdout, "CR:0x%x\n", res); #endif return (res); } void lock_flash(stlink_t *sl) { uint32_t cr_lock_shift = 0, cr_reg = 0, n = 0, cr2_reg = 0; uint32_t cr_mask = 0xffffffffu; if (sl->flash_type == STM32_FLASH_TYPE_C0) { cr_reg = FLASH_C0_CR; cr_lock_shift = FLASH_C0_CR_LOCK; } else if (sl->flash_type == STM32_FLASH_TYPE_F0_F1_F3) { cr_reg = FLASH_CR; cr_lock_shift = FLASH_CR_LOCK; } else if (sl->flash_type == STM32_FLASH_TYPE_F1_XL) { cr_reg = FLASH_CR; cr2_reg = FLASH_CR2; cr_lock_shift = FLASH_CR_LOCK; } else if (sl->flash_type == STM32_FLASH_TYPE_F2_F4) { cr_reg = FLASH_F4_CR; cr_lock_shift = FLASH_F4_CR_LOCK; } else if (sl->flash_type == STM32_FLASH_TYPE_F7) { cr_reg = FLASH_F7_CR; cr_lock_shift = FLASH_F7_CR_LOCK; } else if (sl->flash_type == STM32_FLASH_TYPE_G0 || sl->flash_type == STM32_FLASH_TYPE_G4) { cr_reg = FLASH_Gx_CR; cr_lock_shift = FLASH_Gx_CR_LOCK; } else if (sl->flash_type == STM32_FLASH_TYPE_H7) { cr_reg = FLASH_H7_CR1; if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) { cr2_reg = FLASH_H7_CR2; } cr_lock_shift = FLASH_H7_CR_LOCK; cr_mask = ~(1u << FLASH_H7_CR_SER); } else if (sl->flash_type == STM32_FLASH_TYPE_L0_L1) { cr_reg = get_stm32l0_flash_base(sl) + FLASH_PECR_OFF; cr_lock_shift = FLASH_L0_PELOCK; } else if (sl->flash_type == STM32_FLASH_TYPE_L4) { cr_reg = FLASH_L4_CR; cr_lock_shift = FLASH_L4_CR_LOCK; } else if (sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5) { cr_reg = FLASH_L5_NSCR; cr_lock_shift = FLASH_L5_NSCR_NSLOCK; } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { cr_reg = FLASH_WB_CR; cr_lock_shift = FLASH_WB_CR_LOCK; } else { ELOG("unsupported flash method, abort\n"); return; } stlink_read_debug32(sl, cr_reg, &n); n &= cr_mask; n |= (1u << cr_lock_shift); stlink_write_debug32(sl, cr_reg, n); if (cr2_reg) { n = read_flash_cr(sl, BANK_2) | (1u << cr_lock_shift); stlink_write_debug32(sl, cr2_reg, n); } } static inline int32_t write_flash_sr(stlink_t *sl, uint32_t bank, uint32_t val) { uint32_t sr_reg; if (sl->flash_type == STM32_FLASH_TYPE_C0) { sr_reg = FLASH_C0_SR; } else if (sl->flash_type == STM32_FLASH_TYPE_F0_F1_F3 || sl->flash_type == STM32_FLASH_TYPE_F1_XL) { sr_reg = (bank == BANK_1) ? FLASH_SR : FLASH_SR2; } else if (sl->flash_type == STM32_FLASH_TYPE_F2_F4) { sr_reg = FLASH_F4_SR; } else if (sl->flash_type == STM32_FLASH_TYPE_F7) { sr_reg = FLASH_F7_SR; } else if (sl->flash_type == STM32_FLASH_TYPE_G0 || sl->flash_type == STM32_FLASH_TYPE_G4) { sr_reg = FLASH_Gx_SR; } else if (sl->flash_type == STM32_FLASH_TYPE_H7) { sr_reg = (bank == BANK_1) ? FLASH_H7_SR1 : FLASH_H7_SR2; } else if (sl->flash_type == STM32_FLASH_TYPE_L0_L1) { sr_reg = get_stm32l0_flash_base(sl) + FLASH_SR_OFF; } else if (sl->flash_type == STM32_FLASH_TYPE_L4) { sr_reg = FLASH_L4_SR; } else if (sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5) { sr_reg = FLASH_L5_NSSR; } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { sr_reg = FLASH_WB_SR; } else { ELOG("method 'write_flash_sr' is unsupported\n"); return (-1); } return stlink_write_debug32(sl, sr_reg, val); } void clear_flash_error(stlink_t *sl) { switch (sl->flash_type) { case STM32_FLASH_TYPE_C0: write_flash_sr(sl, BANK_1, FLASH_C0_SR_ERROR_MASK); break; case STM32_FLASH_TYPE_F0_F1_F3: write_flash_sr(sl, BANK_1, FLASH_SR_ERROR_MASK); break; case STM32_FLASH_TYPE_F2_F4: write_flash_sr(sl, BANK_1, FLASH_F4_SR_ERROR_MASK); break; case STM32_FLASH_TYPE_F7: write_flash_sr(sl, BANK_1, FLASH_F7_SR_ERROR_MASK); break; case STM32_FLASH_TYPE_G0: case STM32_FLASH_TYPE_G4: write_flash_sr(sl, BANK_1, FLASH_Gx_SR_ERROR_MASK); break; case STM32_FLASH_TYPE_H7: write_flash_sr(sl, BANK_1, FLASH_H7_SR_ERROR_MASK); if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) { write_flash_sr(sl, BANK_2, FLASH_H7_SR_ERROR_MASK); } break; case STM32_FLASH_TYPE_L0_L1: if (get_stm32l0_flash_base(sl) == FLASH_Lx_REGS_ADDR) { write_flash_sr(sl, BANK_1, FLASH_L1_SR_ERROR_MASK); } else { write_flash_sr(sl, BANK_1, FLASH_L0_SR_ERROR_MASK); } break; case STM32_FLASH_TYPE_L4: write_flash_sr(sl, BANK_1, FLASH_L4_SR_ERROR_MASK); break; case STM32_FLASH_TYPE_L5_U5_H5: write_flash_sr(sl, BANK_1, FLASH_L5_NSSR_ERROR_MASK); break; case STM32_FLASH_TYPE_WB_WL: write_flash_sr(sl, BANK_1, FLASH_WB_SR_ERROR_MASK); break; default: break; } } uint32_t read_flash_sr(stlink_t *sl, uint32_t bank) { uint32_t res, sr_reg; if (sl->flash_type == STM32_FLASH_TYPE_C0) { sr_reg = FLASH_C0_SR; } else if ((sl->flash_type == STM32_FLASH_TYPE_F0_F1_F3) || (sl->flash_type == STM32_FLASH_TYPE_F1_XL)) { sr_reg = (bank == BANK_1) ? FLASH_SR : FLASH_SR2; } else if (sl->flash_type == STM32_FLASH_TYPE_F2_F4) { sr_reg = FLASH_F4_SR; } else if (sl->flash_type == STM32_FLASH_TYPE_F7) { sr_reg = FLASH_F7_SR; } else if (sl->flash_type == STM32_FLASH_TYPE_G0 || sl->flash_type == STM32_FLASH_TYPE_G4) { sr_reg = FLASH_Gx_SR; } else if (sl->flash_type == STM32_FLASH_TYPE_H7) { sr_reg = (bank == BANK_1) ? FLASH_H7_SR1 : FLASH_H7_SR2; } else if (sl->flash_type == STM32_FLASH_TYPE_L0_L1) { sr_reg = get_stm32l0_flash_base(sl) + FLASH_SR_OFF; } else if (sl->flash_type == STM32_FLASH_TYPE_L4) { sr_reg = FLASH_L4_SR; } else if (sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5) { sr_reg = FLASH_L5_NSSR; } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { sr_reg = FLASH_WB_SR; } else { ELOG("method 'read_flash_sr' is unsupported\n"); return (-1); } stlink_read_debug32(sl, sr_reg, &res); return (res); } uint32_t is_flash_busy(stlink_t *sl) { uint32_t sr_busy_shift; uint32_t res; if (sl->flash_type == STM32_FLASH_TYPE_C0) { sr_busy_shift = FLASH_C0_SR_BSY; } else if (sl->flash_type == STM32_FLASH_TYPE_F0_F1_F3 || sl->flash_type == STM32_FLASH_TYPE_F1_XL || sl->flash_type == STM32_FLASH_TYPE_L0_L1) { sr_busy_shift = FLASH_SR_BSY; } else if (sl->flash_type == STM32_FLASH_TYPE_F2_F4) { sr_busy_shift = FLASH_F4_SR_BSY; } else if (sl->flash_type == STM32_FLASH_TYPE_F7) { sr_busy_shift = FLASH_F7_SR_BSY; } else if (sl->flash_type == STM32_FLASH_TYPE_G0 || sl->flash_type == STM32_FLASH_TYPE_G4) { sr_busy_shift = FLASH_Gx_SR_BSY; } else if (sl->flash_type == STM32_FLASH_TYPE_H7) { sr_busy_shift = FLASH_H7_SR_QW; } else if (sl->flash_type == STM32_FLASH_TYPE_L4) { sr_busy_shift = FLASH_L4_SR_BSY; } else if (sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5) { sr_busy_shift = FLASH_L5_NSSR_BSY; } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { sr_busy_shift = FLASH_WB_SR_BSY; } else { ELOG("method 'is_flash_busy' is unsupported\n"); return (-1); } res = read_flash_sr(sl, BANK_1) & (1 << sr_busy_shift); if (sl->flash_type == STM32_FLASH_TYPE_F1_XL || (sl->flash_type == STM32_FLASH_TYPE_H7 && sl->chip_flags & CHIP_F_HAS_DUAL_BANK)) { res |= read_flash_sr(sl, BANK_2) & (1 << sr_busy_shift); } return (res); } void wait_flash_busy(stlink_t *sl) { // TODO: add some delays here while (is_flash_busy(sl)) ; } int32_t check_flash_error(stlink_t *sl) { uint32_t res = 0; uint32_t WRPERR, PROGERR, PGAERR; WRPERR = PROGERR = PGAERR = 0; switch (sl->flash_type) { case STM32_FLASH_TYPE_C0: res = read_flash_sr(sl, BANK_1) & FLASH_C0_SR_ERROR_MASK; WRPERR = (1 << FLASH_C0_SR_WRPERR); PROGERR = (1 << FLASH_C0_SR_PROGERR); PGAERR = (1 << FLASH_C0_SR_PGAERR); break; case STM32_FLASH_TYPE_F0_F1_F3: case STM32_FLASH_TYPE_F1_XL: res = read_flash_sr(sl, BANK_1) & FLASH_SR_ERROR_MASK; if (sl->flash_type == STM32_FLASH_TYPE_F1_XL) { res |= read_flash_sr(sl, BANK_2) & FLASH_SR_ERROR_MASK; } WRPERR = (1 << FLASH_SR_WRPRT_ERR); PROGERR = (1 << FLASH_SR_PG_ERR); break; case STM32_FLASH_TYPE_F2_F4: res = read_flash_sr(sl, BANK_1) & FLASH_F4_SR_ERROR_MASK; WRPERR = (1 << FLASH_F4_SR_WRPERR); PGAERR = (1 << FLASH_F4_SR_PGAERR); break; case STM32_FLASH_TYPE_F7: res = read_flash_sr(sl, BANK_1) & FLASH_F7_SR_ERROR_MASK; WRPERR = (1 << FLASH_F7_SR_WRP_ERR); PROGERR = (1 << FLASH_F7_SR_PGP_ERR); break; case STM32_FLASH_TYPE_G0: case STM32_FLASH_TYPE_G4: res = read_flash_sr(sl, BANK_1) & FLASH_Gx_SR_ERROR_MASK; if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) { res |= read_flash_sr(sl, BANK_2) & FLASH_Gx_SR_ERROR_MASK; } WRPERR = (1 << FLASH_Gx_SR_WRPERR); PROGERR = (1 << FLASH_Gx_SR_PROGERR); PGAERR = (1 << FLASH_Gx_SR_PGAERR); break; case STM32_FLASH_TYPE_H7: res = read_flash_sr(sl, BANK_1) & FLASH_H7_SR_ERROR_MASK; if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) { res |= read_flash_sr(sl, BANK_2) & FLASH_H7_SR_ERROR_MASK; } WRPERR = (1 << FLASH_H7_SR_WRPERR); break; case STM32_FLASH_TYPE_L0_L1: res = read_flash_sr(sl, BANK_1); if (get_stm32l0_flash_base(sl) == FLASH_Lx_REGS_ADDR) { res &= FLASH_L1_SR_ERROR_MASK; } else { res &= FLASH_L0_SR_ERROR_MASK; PROGERR = (1 << FLASH_L0_SR_NOTZEROERR); } WRPERR = (1 << FLASH_L0_SR_WRPERR); PGAERR = (1 << FLASH_L0_SR_PGAERR); break; case STM32_FLASH_TYPE_L4: res = read_flash_sr(sl, BANK_1) & FLASH_L4_SR_ERROR_MASK; WRPERR = (1 << FLASH_L4_SR_WRPERR); PROGERR = (1 << FLASH_L4_SR_PROGERR); PGAERR = (1 << FLASH_L4_SR_PGAERR); break; case STM32_FLASH_TYPE_L5_U5_H5: res = read_flash_sr(sl, BANK_1) & FLASH_L5_NSSR_ERROR_MASK; WRPERR = (1 << FLASH_L5_NSSR_NSWRPERR); PROGERR = (1 << FLASH_L5_NSSR_NSPROGERR); PGAERR = (1 << FLASH_L5_NSSR_NSPGAERR); break; case STM32_FLASH_TYPE_WB_WL: res = read_flash_sr(sl, BANK_1) & FLASH_WB_SR_ERROR_MASK; WRPERR = (1 << FLASH_WB_SR_WRPERR); PROGERR = (1 << FLASH_WB_SR_PROGERR); PGAERR = (1 << FLASH_WB_SR_PGAERR); break; default: break; } if (res) { if (WRPERR && (WRPERR & res) == WRPERR) { ELOG("Flash memory is write protected\n"); res &= ~WRPERR; } else if (PROGERR && (PROGERR & res) == PROGERR) { ELOG("Flash memory contains a non-erased value\n"); res &= ~PROGERR; } else if (PGAERR && (PGAERR & res) == PGAERR) { ELOG("Invalid flash address\n"); res &= ~PGAERR; } if (res) ELOG("Flash programming error: %#010x\n", res); return (-1); } return (0); } static inline uint32_t is_flash_locked(stlink_t *sl) { /* return non zero for true */ uint32_t cr_lock_shift; uint32_t cr_reg; uint32_t n; if (sl->flash_type == STM32_FLASH_TYPE_C0) { cr_reg = FLASH_C0_CR; cr_lock_shift = FLASH_C0_CR_LOCK; } else if (sl->flash_type == STM32_FLASH_TYPE_F0_F1_F3 || sl->flash_type == STM32_FLASH_TYPE_F1_XL) { cr_reg = FLASH_CR; cr_lock_shift = FLASH_CR_LOCK; } else if (sl->flash_type == STM32_FLASH_TYPE_F2_F4) { cr_reg = FLASH_F4_CR; cr_lock_shift = FLASH_F4_CR_LOCK; } else if (sl->flash_type == STM32_FLASH_TYPE_F7) { cr_reg = FLASH_F7_CR; cr_lock_shift = FLASH_F7_CR_LOCK; } else if (sl->flash_type == STM32_FLASH_TYPE_G0 || sl->flash_type == STM32_FLASH_TYPE_G4) { cr_reg = FLASH_Gx_CR; cr_lock_shift = FLASH_Gx_CR_LOCK; } else if (sl->flash_type == STM32_FLASH_TYPE_H7) { cr_reg = FLASH_H7_CR1; cr_lock_shift = FLASH_H7_CR_LOCK; } else if (sl->flash_type == STM32_FLASH_TYPE_L0_L1) { cr_reg = get_stm32l0_flash_base(sl) + FLASH_PECR_OFF; cr_lock_shift = FLASH_L0_PELOCK; } else if (sl->flash_type == STM32_FLASH_TYPE_L4) { cr_reg = FLASH_L4_CR; cr_lock_shift = FLASH_L4_CR_LOCK; } else if (sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5) { cr_reg = FLASH_L5_NSCR; cr_lock_shift = FLASH_L5_NSCR_NSLOCK; } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { cr_reg = FLASH_WB_CR; cr_lock_shift = FLASH_WB_CR_LOCK; } else { ELOG("unsupported flash method, abort\n"); return (-1); } stlink_read_debug32(sl, cr_reg, &n); return (n & (1u << cr_lock_shift)); } static void unlock_flash(stlink_t *sl) { uint32_t key_reg, key2_reg = 0; uint32_t flash_key1 = FLASH_KEY1; uint32_t flash_key2 = FLASH_KEY2; /* The unlock sequence consists of 2 write cycles where 2 key values are * written to the FLASH_KEYR register. An invalid sequence results in a * definitive lock of the FPEC block until next reset. */ if (sl->flash_type == STM32_FLASH_TYPE_C0) { key_reg = FLASH_C0_KEYR; } else if (sl->flash_type == STM32_FLASH_TYPE_F0_F1_F3) { key_reg = FLASH_KEYR; } else if (sl->flash_type == STM32_FLASH_TYPE_F1_XL) { key_reg = FLASH_KEYR; key2_reg = FLASH_KEYR2; } else if (sl->flash_type == STM32_FLASH_TYPE_F2_F4) { key_reg = FLASH_F4_KEYR; } else if (sl->flash_type == STM32_FLASH_TYPE_F7) { key_reg = FLASH_F7_KEYR; } else if (sl->flash_type == STM32_FLASH_TYPE_G0 || sl->flash_type == STM32_FLASH_TYPE_G4) { key_reg = FLASH_Gx_KEYR; } else if (sl->flash_type == STM32_FLASH_TYPE_H7) { key_reg = FLASH_H7_KEYR1; if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) { key2_reg = FLASH_H7_KEYR2; } } else if (sl->flash_type == STM32_FLASH_TYPE_L0_L1) { key_reg = get_stm32l0_flash_base(sl) + FLASH_PEKEYR_OFF; flash_key1 = FLASH_L0_PEKEY1; flash_key2 = FLASH_L0_PEKEY2; } else if (sl->flash_type == STM32_FLASH_TYPE_L4) { key_reg = FLASH_L4_KEYR; } else if (sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5) { // Set voltage scaling to range 0 to perform flash operations (RM0438 p. 183) uint32_t mask = (0b11 << STM32L5_PWR_CR1_VOS); uint32_t val; if (!stlink_read_debug32(sl, STM32L5_PWR_CR1, &val) && (val & mask) > (1 << STM32L5_PWR_CR1_VOS)) { val &= ~mask; stlink_write_debug32(sl, STM32L5_PWR_CR1, val); } key_reg = FLASH_L5_NSKEYR; } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { key_reg = FLASH_WB_KEYR; } else { ELOG("unsupported flash method, abort\n"); return; } stlink_write_debug32(sl, key_reg, flash_key1); stlink_write_debug32(sl, key_reg, flash_key2); if (key2_reg) { stlink_write_debug32(sl, key2_reg, flash_key1); stlink_write_debug32(sl, key2_reg, flash_key2); } } /* unlock flash if already locked */ int32_t unlock_flash_if(stlink_t *sl) { if (is_flash_locked(sl)) { unlock_flash(sl); if (is_flash_locked(sl)) { WLOG("Failed to unlock flash!\n"); return (-1); } } DLOG("Successfully unlocked flash\n"); return (0); } int32_t lock_flash_option(stlink_t *sl) { uint32_t optlock_shift, optcr_reg, n, optcr2_reg = 0; int32_t active_bit_level = 1; switch (sl->flash_type) { case STM32_FLASH_TYPE_C0: optcr_reg = FLASH_C0_CR; optlock_shift = FLASH_C0_CR_OPTLOCK; break; case STM32_FLASH_TYPE_F0_F1_F3: case STM32_FLASH_TYPE_F1_XL: optcr_reg = FLASH_CR; optlock_shift = FLASH_CR_OPTWRE; active_bit_level = 0; break; case STM32_FLASH_TYPE_F2_F4: optcr_reg = FLASH_F4_OPTCR; optlock_shift = FLASH_F4_OPTCR_LOCK; break; case STM32_FLASH_TYPE_F7: optcr_reg = FLASH_F7_OPTCR; optlock_shift = FLASH_F7_OPTCR_LOCK; break; case STM32_FLASH_TYPE_G0: case STM32_FLASH_TYPE_G4: optcr_reg = FLASH_Gx_CR; optlock_shift = FLASH_Gx_CR_OPTLOCK; break; case STM32_FLASH_TYPE_H7: optcr_reg = FLASH_H7_OPTCR; optlock_shift = FLASH_H7_OPTCR_OPTLOCK; if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) optcr2_reg = FLASH_H7_OPTCR2; break; case STM32_FLASH_TYPE_L0_L1: optcr_reg = get_stm32l0_flash_base(sl) + FLASH_PECR_OFF; optlock_shift = FLASH_L0_OPTLOCK; break; case STM32_FLASH_TYPE_L4: optcr_reg = FLASH_L4_CR; optlock_shift = FLASH_L4_CR_OPTLOCK; break; case STM32_FLASH_TYPE_L5_U5_H5: optcr_reg = FLASH_L5_NSCR; optlock_shift = FLASH_L5_NSCR_OPTLOCK; break; case STM32_FLASH_TYPE_WB_WL: optcr_reg = FLASH_WB_CR; optlock_shift = FLASH_WB_CR_OPTLOCK; break; default: ELOG("unsupported flash method, abort\n"); return -1; } stlink_read_debug32(sl, optcr_reg, &n); if (active_bit_level == 0) { n &= ~(1u << optlock_shift); } else { n |= (1u << optlock_shift); } stlink_write_debug32(sl, optcr_reg, n); if (optcr2_reg) { stlink_read_debug32(sl, optcr2_reg, &n); if (active_bit_level == 0) { n &= ~(1u << optlock_shift); } else { n |= (1u << optlock_shift); } stlink_write_debug32(sl, optcr2_reg, n); } return (0); } static bool is_flash_option_locked(stlink_t *sl) { uint32_t optlock_shift, optcr_reg; int32_t active_bit_level = 1; uint32_t n; switch (sl->flash_type) { case STM32_FLASH_TYPE_C0: optcr_reg = FLASH_C0_CR; optlock_shift = FLASH_C0_CR_OPTLOCK; break; case STM32_FLASH_TYPE_F0_F1_F3: case STM32_FLASH_TYPE_F1_XL: optcr_reg = FLASH_CR; optlock_shift = FLASH_CR_OPTWRE; active_bit_level = 0; /* bit is "option write enable", not lock */ break; case STM32_FLASH_TYPE_F2_F4: optcr_reg = FLASH_F4_OPTCR; optlock_shift = FLASH_F4_OPTCR_LOCK; break; case STM32_FLASH_TYPE_F7: optcr_reg = FLASH_F7_OPTCR; optlock_shift = FLASH_F7_OPTCR_LOCK; break; case STM32_FLASH_TYPE_G0: case STM32_FLASH_TYPE_G4: optcr_reg = FLASH_Gx_CR; optlock_shift = FLASH_Gx_CR_OPTLOCK; break; case STM32_FLASH_TYPE_H7: optcr_reg = FLASH_H7_OPTCR; optlock_shift = FLASH_H7_OPTCR_OPTLOCK; break; case STM32_FLASH_TYPE_L0_L1: optcr_reg = get_stm32l0_flash_base(sl) + FLASH_PECR_OFF; optlock_shift = FLASH_L0_OPTLOCK; break; case STM32_FLASH_TYPE_L4: optcr_reg = FLASH_L4_CR; optlock_shift = FLASH_L4_CR_OPTLOCK; break; case STM32_FLASH_TYPE_L5_U5_H5: optcr_reg = FLASH_L5_NSCR; optlock_shift = FLASH_L5_NSCR_OPTLOCK; break; case STM32_FLASH_TYPE_WB_WL: optcr_reg = FLASH_WB_CR; optlock_shift = FLASH_WB_CR_OPTLOCK; break; default: ELOG("unsupported flash method, abort\n"); return -1; } stlink_read_debug32(sl, optcr_reg, &n); if (active_bit_level == 0) { return (!(n & (1u << optlock_shift))); } return (n & (1u << optlock_shift)); } static int32_t unlock_flash_option(stlink_t *sl) { uint32_t optkey_reg, optkey2_reg = 0; uint32_t optkey1 = FLASH_OPTKEY1; uint32_t optkey2 = FLASH_OPTKEY2; switch (sl->flash_type) { case STM32_FLASH_TYPE_C0: optkey_reg = FLASH_C0_OPT_KEYR; break; case STM32_FLASH_TYPE_F0_F1_F3: case STM32_FLASH_TYPE_F1_XL: optkey_reg = FLASH_OPTKEYR; optkey1 = FLASH_F0_OPTKEY1; optkey2 = FLASH_F0_OPTKEY2; break; case STM32_FLASH_TYPE_F2_F4: optkey_reg = FLASH_F4_OPT_KEYR; break; case STM32_FLASH_TYPE_F7: optkey_reg = FLASH_F7_OPT_KEYR; break; case STM32_FLASH_TYPE_G0: case STM32_FLASH_TYPE_G4: optkey_reg = FLASH_Gx_OPTKEYR; break; case STM32_FLASH_TYPE_H7: optkey_reg = FLASH_H7_OPT_KEYR; if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) optkey2_reg = FLASH_H7_OPT_KEYR2; break; case STM32_FLASH_TYPE_L0_L1: optkey_reg = get_stm32l0_flash_base(sl) + FLASH_OPTKEYR_OFF; optkey1 = FLASH_L0_OPTKEY1; optkey2 = FLASH_L0_OPTKEY2; break; case STM32_FLASH_TYPE_L4: optkey_reg = FLASH_L4_OPTKEYR; break; case STM32_FLASH_TYPE_L5_U5_H5: optkey_reg = FLASH_L5_OPTKEYR; break; case STM32_FLASH_TYPE_WB_WL: optkey_reg = FLASH_WB_OPT_KEYR; break; default: ELOG("unsupported flash method, abort\n"); return (-1); } stlink_write_debug32(sl, optkey_reg, optkey1); stlink_write_debug32(sl, optkey_reg, optkey2); if (optkey2_reg) { stlink_write_debug32(sl, optkey2_reg, optkey1); stlink_write_debug32(sl, optkey2_reg, optkey2); } return (0); } int32_t unlock_flash_option_if(stlink_t *sl) { if (is_flash_option_locked(sl)) { if (unlock_flash_option(sl)) { ELOG("Could not unlock flash option!\n"); return (-1); } if (is_flash_option_locked(sl)) { ELOG("Failed to unlock flash option!\n"); return (-1); } } DLOG("Successfully unlocked flash option\n"); return (0); } void write_flash_cr_psiz(stlink_t *sl, uint32_t n, uint32_t bank) { uint32_t cr_reg, psize_shift; uint32_t x = read_flash_cr(sl, bank); if (sl->flash_type == STM32_FLASH_TYPE_H7) { cr_reg = (bank == BANK_1) ? FLASH_H7_CR1 : FLASH_H7_CR2; psize_shift = FLASH_H7_CR_PSIZE; } else { cr_reg = FLASH_F4_CR; psize_shift = 8; } x &= ~(0x03 << psize_shift); x |= (n << psize_shift); #if DEBUG_FLASH fprintf(stdout, "PSIZ:0x%x 0x%x\n", x, n); #endif stlink_write_debug32(sl, cr_reg, x); } void clear_flash_cr_pg(stlink_t *sl, uint32_t bank) { uint32_t cr_reg, n; uint32_t bit = FLASH_CR_PG; if (sl->flash_type == STM32_FLASH_TYPE_C0) { cr_reg = FLASH_C0_CR; } else if (sl->flash_type == STM32_FLASH_TYPE_F2_F4) { cr_reg = FLASH_F4_CR; } else if (sl->flash_type == STM32_FLASH_TYPE_F7) { cr_reg = FLASH_F7_CR; } else if (sl->flash_type == STM32_FLASH_TYPE_G0 || sl->flash_type == STM32_FLASH_TYPE_G4) { cr_reg = FLASH_Gx_CR; } else if (sl->flash_type == STM32_FLASH_TYPE_H7) { cr_reg = (bank == BANK_1) ? FLASH_H7_CR1 : FLASH_H7_CR2; bit = FLASH_H7_CR_PG; } else if (sl->flash_type == STM32_FLASH_TYPE_L4) { cr_reg = FLASH_L4_CR; } else if (sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5) { cr_reg = FLASH_L5_NSCR; } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { cr_reg = FLASH_WB_CR; } else { cr_reg = FLASH_CR; } n = read_flash_cr(sl, bank) & ~(1 << bit); stlink_write_debug32(sl, cr_reg, n); } /* ------------------------------------------------------------------------ */ static void wait_flash_busy_progress(stlink_t *sl) { int32_t i = 0; fprintf(stdout, "Mass erasing..."); fflush(stdout); while (is_flash_busy(sl)) { usleep(10000); i++; if (i % 100 == 0) { fprintf(stdout, "."); fflush(stdout); } } fprintf(stdout, "\n"); } static inline void write_flash_ar(stlink_t *sl, uint32_t n, uint32_t bank) { stlink_write_debug32(sl, (bank == BANK_1) ? FLASH_AR : FLASH_AR2, n); } static inline void write_flash_cr_snb(stlink_t *sl, uint32_t n, uint32_t bank) { uint32_t cr_reg, snb_mask, snb_shift, ser_shift; uint32_t x = read_flash_cr(sl, bank); if (sl->flash_type == STM32_FLASH_TYPE_H7) { cr_reg = (bank == BANK_1) ? FLASH_H7_CR1 : FLASH_H7_CR2; snb_mask = FLASH_H7_CR_SNB_MASK; snb_shift = FLASH_H7_CR_SNB; ser_shift = FLASH_H7_CR_SER; } else { cr_reg = FLASH_F4_CR; snb_mask = FLASH_F4_CR_SNB_MASK; snb_shift = FLASH_F4_CR_SNB; ser_shift = FLASH_F4_CR_SER; } x &= ~snb_mask; x |= (n << snb_shift); x |= (1 << ser_shift); #if DEBUG_FLASH fprintf(stdout, "SNB:0x%x 0x%x\n", x, n); #endif stlink_write_debug32(sl, cr_reg, x); } static void set_flash_cr_per(stlink_t *sl, uint32_t bank) { uint32_t cr_reg, val; if (sl->flash_type == STM32_FLASH_TYPE_C0) { cr_reg = FLASH_C0_CR; } else if (sl->flash_type == STM32_FLASH_TYPE_G0 || sl->flash_type == STM32_FLASH_TYPE_G4) { cr_reg = FLASH_Gx_CR; } else if (sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5) { cr_reg = FLASH_L5_NSCR; } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { cr_reg = FLASH_WB_CR; } else { cr_reg = (bank == BANK_1) ? FLASH_CR : FLASH_CR2; } stlink_read_debug32(sl, cr_reg, &val); val |= (1 << FLASH_CR_PER); stlink_write_debug32(sl, cr_reg, val); } static void clear_flash_cr_per(stlink_t *sl, uint32_t bank) { uint32_t cr_reg; if (sl->flash_type == STM32_FLASH_TYPE_C0) { cr_reg = FLASH_C0_CR; } else if (sl->flash_type == STM32_FLASH_TYPE_G0 || sl->flash_type == STM32_FLASH_TYPE_G4) { cr_reg = FLASH_Gx_CR; } else if (sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5) { cr_reg = FLASH_L5_NSCR; } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { cr_reg = FLASH_WB_CR; } else { cr_reg = (bank == BANK_1) ? FLASH_CR : FLASH_CR2; } const uint32_t n = read_flash_cr(sl, bank) & ~(1 << FLASH_CR_PER); stlink_write_debug32(sl, cr_reg, n); } static inline void write_flash_cr_bker_pnb(stlink_t *sl, uint32_t n) { stlink_write_debug32(sl, FLASH_L4_SR, 0xFFFFFFFF & ~(1 << FLASH_L4_SR_BSY)); uint32_t x = read_flash_cr(sl, BANK_1); x &= ~FLASH_L4_CR_OPBITS; x &= ~FLASH_L4_CR_PAGEMASK; x &= ~(1 << FLASH_L4_CR_MER1); x &= ~(1 << FLASH_L4_CR_MER2); x |= (n << FLASH_L4_CR_PNB); x |= (uint32_t)(1lu << FLASH_L4_CR_PER); #if DEBUG_FLASH fprintf(stdout, "BKER:PNB:0x%x 0x%x\n", x, n); #endif stlink_write_debug32(sl, FLASH_L4_CR, x); } static void set_flash_cr_strt(stlink_t *sl, uint32_t bank) { uint32_t val, cr_reg, cr_strt; if (sl->flash_type == STM32_FLASH_TYPE_C0) { cr_reg = FLASH_C0_CR; cr_strt = 1 << FLASH_C0_CR_STRT; } else if (sl->flash_type == STM32_FLASH_TYPE_F2_F4) { cr_reg = FLASH_F4_CR; cr_strt = 1 << FLASH_F4_CR_STRT; } else if (sl->flash_type == STM32_FLASH_TYPE_F7) { cr_reg = FLASH_F7_CR; cr_strt = 1 << FLASH_F7_CR_STRT; } else if (sl->flash_type == STM32_FLASH_TYPE_G0 || sl->flash_type == STM32_FLASH_TYPE_G4) { cr_reg = FLASH_Gx_CR; cr_strt = (1 << FLASH_Gx_CR_STRT); } else if (sl->flash_type == STM32_FLASH_TYPE_H7) { cr_reg = (bank == BANK_1) ? FLASH_H7_CR1 : FLASH_H7_CR2; cr_strt = 1 << FLASH_H7_CR_START(sl->chip_id); } else if (sl->flash_type == STM32_FLASH_TYPE_L4) { cr_reg = FLASH_L4_CR; cr_strt = (1 << FLASH_L4_CR_STRT); } else if (sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5) { cr_reg = FLASH_L5_NSCR; cr_strt = (1 << FLASH_L5_NSCR_NSSTRT); } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { cr_reg = FLASH_WB_CR; cr_strt = (1 << FLASH_WB_CR_STRT); } else { cr_reg = (bank == BANK_1) ? FLASH_CR : FLASH_CR2; cr_strt = (1 << FLASH_CR_STRT); } stlink_read_debug32(sl, cr_reg, &val); val |= cr_strt; stlink_write_debug32(sl, cr_reg, val); } static void set_flash_cr_mer(stlink_t *sl, bool v, uint32_t bank) { uint32_t val, cr_reg, cr_mer, cr_pg; if (sl->flash_type == STM32_FLASH_TYPE_C0) { cr_reg = FLASH_C0_CR; cr_mer = 1 << FLASH_CR_MER; cr_pg = 1 << FLASH_CR_PG; } else if (sl->flash_type == STM32_FLASH_TYPE_F2_F4) { cr_reg = FLASH_F4_CR; cr_mer = 1 << FLASH_CR_MER; cr_pg = 1 << FLASH_CR_PG; } else if (sl->flash_type == STM32_FLASH_TYPE_F7) { cr_reg = FLASH_F7_CR; cr_mer = 1 << FLASH_CR_MER; cr_pg = 1 << FLASH_CR_PG; } else if (sl->flash_type == STM32_FLASH_TYPE_G0 || sl->flash_type == STM32_FLASH_TYPE_G4) { cr_reg = FLASH_Gx_CR; cr_mer = (1 << FLASH_Gx_CR_MER1); if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) { cr_mer |= (1 << FLASH_Gx_CR_MER2); } cr_pg = (1 << FLASH_CR_PG); } else if (sl->flash_type == STM32_FLASH_TYPE_H7) { cr_reg = (bank == BANK_1) ? FLASH_H7_CR1 : FLASH_H7_CR2; cr_mer = (1 << FLASH_H7_CR_BER); cr_pg = (1 << FLASH_H7_CR_PG); } else if (sl->flash_type == STM32_FLASH_TYPE_L4) { cr_reg = FLASH_L4_CR; cr_mer = (1 << FLASH_L4_CR_MER1) | (1 << FLASH_L4_CR_MER2); cr_pg = (1 << FLASH_L4_CR_PG); } else if (sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5) { cr_reg = FLASH_L5_NSCR; cr_mer = (1 << FLASH_L5_NSCR_NSMER1) | (1 << FLASH_L5_NSCR_NSMER2); cr_pg = (1 << FLASH_L5_NSCR_NSPG); } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { cr_reg = FLASH_WB_CR; cr_mer = (1 << FLASH_CR_MER); cr_pg = (1 << FLASH_CR_PG); } else { cr_reg = (bank == BANK_1) ? FLASH_CR : FLASH_CR2; cr_mer = (1 << FLASH_CR_MER); cr_pg = (1 << FLASH_CR_PG); } stlink_read_debug32(sl, cr_reg, &val); if (val & cr_pg) { // STM32F030 will drop MER bit if PG was set val &= ~cr_pg; stlink_write_debug32(sl, cr_reg, val); } if (v) { val |= cr_mer; } else { val &= ~cr_mer; } stlink_write_debug32(sl, cr_reg, val); } /** * Erase a page of flash, assumes sl is fully populated with things like * chip/core ids * @param sl stlink context * @param flashaddr an address in the flash page to erase * @return 0 on success -ve on failure */ int32_t stlink_erase_flash_page(stlink_t *sl, stm32_addr_t flashaddr) { // wait for ongoing op to finish wait_flash_busy(sl); // clear flash IO errors clear_flash_error(sl); if (sl->flash_type == STM32_FLASH_TYPE_F2_F4 || sl->flash_type == STM32_FLASH_TYPE_F7 || sl->flash_type == STM32_FLASH_TYPE_L4) { // unlock if locked unlock_flash_if(sl); // select the page to erase if (sl->flash_type == STM32_FLASH_TYPE_L4) { // calculate the actual bank+page from the address uint32_t page = calculate_L4_page(sl, flashaddr); fprintf(stderr, "EraseFlash - Page:0x%x Size:0x%x ", page, stlink_calculate_pagesize(sl, flashaddr)); write_flash_cr_bker_pnb(sl, page); } else if (sl->chip_id == STM32_CHIPID_F7 || sl->chip_id == STM32_CHIPID_F76xxx) { // calculate the actual page from the address uint32_t sector = calculate_F7_sectornum(flashaddr); fprintf(stderr, "EraseFlash - Sector:0x%x Size:0x%x ", sector, stlink_calculate_pagesize(sl, flashaddr)); write_flash_cr_snb(sl, sector, BANK_1); } else { // calculate the actual page from the address uint32_t sector = calculate_F4_sectornum(flashaddr); fprintf(stderr, "EraseFlash - Sector:0x%x Size:0x%x ", sector, stlink_calculate_pagesize(sl, flashaddr)); // the SNB values for flash sectors in the second bank do not directly // follow the values for the first bank on 2mb devices... if (sector >= 12) { sector += 4; } write_flash_cr_snb(sl, sector, BANK_1); } set_flash_cr_strt(sl, BANK_1); // start erase operation wait_flash_busy(sl); // wait for completion lock_flash(sl); // TODO: fails to program if this is in #if DEBUG_FLASH fprintf(stdout, "Erase Final CR:0x%x\n", read_flash_cr(sl, BANK_1)); #endif } else if (sl->flash_type == STM32_FLASH_TYPE_L0_L1) { uint32_t val; uint32_t flash_regs_base = get_stm32l0_flash_base(sl); // check if the locks are set stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val); if ((val & (1 << 0)) || (val & (1 << 1))) { // disable pecr protection stlink_write_debug32(sl, flash_regs_base + FLASH_PEKEYR_OFF, FLASH_L0_PEKEY1); stlink_write_debug32(sl, flash_regs_base + FLASH_PEKEYR_OFF, FLASH_L0_PEKEY2); // check pecr.pelock is cleared stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val); if (val & (1 << 0)) { WLOG("pecr.pelock not clear (%#x)\n", val); return (-1); } // unlock program memory stlink_write_debug32(sl, flash_regs_base + FLASH_PRGKEYR_OFF, FLASH_L0_PRGKEY1); stlink_write_debug32(sl, flash_regs_base + FLASH_PRGKEYR_OFF, FLASH_L0_PRGKEY2); // check pecr.prglock is cleared stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val); if (val & (1 << 1)) { WLOG("pecr.prglock not clear (%#x)\n", val); return (-1); } } // set pecr.{erase,prog} val |= (1 << 9) | (1 << 3); stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val); // write 0 to the first word of the page to be erased stlink_write_debug32(sl, flashaddr, 0); /* MP: It is better to wait for clearing the busy bit after issuing page * erase command, even though PM0062 recommends to wait before it. * Test shows that a few iterations is performed in the following loop * before busy bit is cleared. */ wait_flash_busy(sl); // reset lock bits stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val); val |= (1 << 0) | (1 << 1) | (1 << 2); stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val); } else if (sl->flash_type == STM32_FLASH_TYPE_G0 || sl->flash_type == STM32_FLASH_TYPE_G4 || sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5 || sl->flash_type == STM32_FLASH_TYPE_WB_WL || sl->flash_type == STM32_FLASH_TYPE_C0) { uint32_t val; unlock_flash_if(sl); set_flash_cr_per(sl, BANK_1); // set the 'enable Flash erase' bit // set the page to erase if (sl->flash_type == STM32_FLASH_TYPE_G0) { uint32_t flash_page = ((flashaddr - STM32_FLASH_BASE) / sl->flash_pgsz); stlink_read_debug32(sl, FLASH_Gx_CR, &val); // sec 3.7.5 - PNB[9:0] is offset by 3. PER is 0x2. val &= ~(0x3FF << 3); val |= ((flash_page & 0x3FF) << 3) | (1 << FLASH_CR_PER); stlink_write_debug32(sl, FLASH_Gx_CR, val); } else if (sl->flash_type == STM32_FLASH_TYPE_G4) { uint32_t flash_page = ((flashaddr - STM32_FLASH_BASE) / sl->flash_pgsz); stlink_read_debug32(sl, FLASH_Gx_CR, &val); // sec 3.7.5 - PNB[9:0] is offset by 3. PER is 0x2. val &= ~(0x7FF << 3); val |= ((flash_page & 0x7FF) << 3) | (1 << FLASH_CR_PER); stlink_write_debug32(sl, FLASH_Gx_CR, val); // STM32L5x2xx has two banks with 2k pages or single with 4k pages // STM32H5xx, STM32U535, STM32U545, STM32U575 or STM32U585 have 2 banks with 8k pages } else if (sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5) { uint32_t flash_page; stlink_read_debug32(sl, FLASH_L5_NSCR, &val); if ((sl->flash_pgsz == 0x800 || sl->flash_pgsz == 0x2000) && (flashaddr - STM32_FLASH_BASE) >= sl->flash_size/2) { flash_page = (flashaddr - STM32_FLASH_BASE - sl->flash_size/2) / sl->flash_pgsz; // set bank 2 for erasure val |= (1 << FLASH_L5_NSCR_NSBKER); } else { flash_page = ((flashaddr - STM32_FLASH_BASE) / sl->flash_pgsz); // set bank 1 for erasure val &= ~(1 << FLASH_L5_NSCR_NSBKER); } // sec 7.9.9 for U5, 6.9.9 for L5 (for L7 we have 7 bits instead of 8 bits for U5 but // the bit position for 8th bit reserved. // Maybe the best solution is to handle each one separately. val &= ~(0xFF << 3); val |= ((flash_page & 0xFF) << 3) | (1 << FLASH_CR_PER); stlink_write_debug32(sl, FLASH_L5_NSCR, val); } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { uint32_t flash_page = ((flashaddr - STM32_FLASH_BASE) / sl->flash_pgsz); stlink_read_debug32(sl, FLASH_WB_CR, &val); // sec 3.10.5 - PNB[7:0] is offset by 3. val &= ~(0xFF << 3); // Clear previously set page number (if any) val |= ((flash_page & 0xFF) << 3); stlink_write_debug32(sl, FLASH_WB_CR, val); } else if (sl->flash_type == STM32_FLASH_TYPE_C0) { uint32_t flash_page = ((flashaddr - STM32_FLASH_BASE) / sl->flash_pgsz); stlink_read_debug32(sl, FLASH_C0_CR, &val); val &= ~(0xF << FLASH_C0_CR_PNB); val |= ((flash_page & 0xF) << FLASH_C0_CR_PNB); stlink_write_debug32(sl, FLASH_C0_CR, val); } set_flash_cr_strt(sl, BANK_1); // set the 'start operation' bit wait_flash_busy(sl); // wait for the 'busy' bit to clear clear_flash_cr_per(sl, BANK_1); // clear the 'enable page erase' bit lock_flash(sl); } else if (sl->flash_type == STM32_FLASH_TYPE_F0_F1_F3 || sl->flash_type == STM32_FLASH_TYPE_F1_XL) { uint32_t bank = (flashaddr < STM32_F1_FLASH_BANK2_BASE) ? BANK_1 : BANK_2; unlock_flash_if(sl); clear_flash_cr_pg(sl, bank); // clear the pg bit set_flash_cr_per(sl, bank); // set the page erase bit write_flash_ar(sl, flashaddr, bank); // select the page to erase set_flash_cr_strt(sl, bank); // start erase operation, reset by hw with busy bit wait_flash_busy(sl); clear_flash_cr_per(sl, bank); // clear the page erase bit lock_flash(sl); } else if (sl->flash_type == STM32_FLASH_TYPE_H7) { uint32_t bank = (flashaddr < STM32_H7_FLASH_BANK2_BASE) ? BANK_1 : BANK_2; unlock_flash_if(sl); // unlock if locked uint32_t sector = calculate_H7_sectornum(sl, flashaddr, bank); // calculate the actual page from the address write_flash_cr_snb(sl, sector, bank); // select the page to erase set_flash_cr_strt(sl, bank); // start erase operation wait_flash_busy(sl); // wait for completion lock_flash(sl); } else { WLOG("unknown coreid %x, page erase failed\n", sl->core_id); return (-1); } return check_flash_error(sl); } int32_t stlink_erase_flash_section(stlink_t *sl, stm32_addr_t base_addr, uint32_t size, bool align_size) { // Check the address and size validity if (stlink_check_address_range_validity(sl, base_addr, size) < 0) { return -1; } // Make sure the requested address is aligned with the beginning of a page if (stlink_check_address_alignment(sl, base_addr) < 0) { ELOG("The address to erase is not aligned with the beginning of a page\n"); return -1; } stm32_addr_t addr = base_addr; do { uint32_t page_size = stlink_calculate_pagesize(sl, addr); // Check if size is aligned with a page, unless we want to completely erase the last page if ((addr + page_size) > (base_addr + size) && !align_size) { ELOG("Invalid size (not aligned with a page). Page size at address %#x is %#x\n", addr, page_size); return (-1); } if (stlink_erase_flash_page(sl, addr)) { WLOG("Failed to erase_flash_page(%#x) == -1\n", addr); return (-1); } fprintf(stdout, "-> Flash page at %#x erased (size: %#x)\r", addr, page_size); fflush(stdout); // check the next page is within the range to erase addr += page_size; } while (addr < (base_addr + size)); fprintf(stdout, "\n"); return 0; } int32_t stlink_erase_flash_mass(stlink_t *sl) { int32_t err = 0; // TODO: Use MER bit to mass-erase WB series. if (sl->flash_type == STM32_FLASH_TYPE_L0_L1 || sl->flash_type == STM32_FLASH_TYPE_WB_WL) { err = stlink_erase_flash_section(sl, sl->flash_base, sl->flash_size, false); } else { wait_flash_busy(sl); clear_flash_error(sl); unlock_flash_if(sl); if (sl->flash_type == STM32_FLASH_TYPE_H7 && sl->chip_id != STM32_CHIPID_H7Ax) { // set parallelism write_flash_cr_psiz(sl, 3 /*64bit*/, BANK_1); if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) { write_flash_cr_psiz(sl, 3 /*64bit*/, BANK_2); } } set_flash_cr_mer(sl, 1, BANK_1); // set the mass erase bit set_flash_cr_strt(sl, BANK_1); // start erase operation, reset by hw with busy bit if (sl->flash_type == STM32_FLASH_TYPE_F1_XL || (sl->flash_type == STM32_FLASH_TYPE_H7 && sl->chip_flags & CHIP_F_HAS_DUAL_BANK)) { set_flash_cr_mer(sl, 1, BANK_2); // set the mass erase bit in bank 2 set_flash_cr_strt(sl, BANK_2); // start erase operation in bank 2 } wait_flash_busy_progress(sl); lock_flash(sl); // reset the mass erase bit set_flash_cr_mer(sl, 0, BANK_1); if (sl->flash_type == STM32_FLASH_TYPE_F1_XL || (sl->flash_type == STM32_FLASH_TYPE_H7 && sl->chip_flags & CHIP_F_HAS_DUAL_BANK)) { set_flash_cr_mer(sl, 0, BANK_2); } err = check_flash_error(sl); } return (err); } int32_t stlink_mwrite_flash(stlink_t *sl, uint8_t *data, uint32_t length, stm32_addr_t addr) { /* Write the block in flash at addr */ int32_t err; uint32_t num_empty, idx; uint8_t erased_pattern = stlink_get_erased_pattern(sl); /* * This optimisation may cause unexpected garbage data remaining. * Therfore it is turned off by default. */ if (sl->opt) { idx = length; for (num_empty = 0; num_empty != length; ++num_empty) if (data[--idx] != erased_pattern) { break; } num_empty -= (num_empty & 3); // Round down to words if (num_empty != 0) { ILOG("Ignoring %d bytes of 0x%02x at end of file\n", num_empty, erased_pattern); } } else { num_empty = 0; } /* * TODO: investigate a kind of weird behaviour here: * If the file is identified to be all-empty and four-bytes aligned, * still flash the whole file even if ignoring message is printed. */ err = stlink_write_flash(sl, addr, data, (num_empty == length) ? length : length - num_empty, num_empty == length); stlink_fwrite_finalize(sl, addr); return (err); } /** * Write the given binary file into flash at address "addr" * @param sl * @param path readable file path, should be binary image * @param addr where to start writing * @return 0 on success, -ve on failure. */ int32_t stlink_fwrite_flash(stlink_t *sl, const char *path, stm32_addr_t addr) { /* Write the file in flash at addr */ int32_t err; uint32_t num_empty, idx; uint8_t erased_pattern = stlink_get_erased_pattern(sl); mapped_file_t mf = MAPPED_FILE_INITIALIZER; if (map_file(&mf, path) == -1) { ELOG("map_file() == -1\n"); return (-1); } printf("file %s ", path); md5_calculate(&mf); stlink_checksum(&mf); if (sl->opt) { idx = (uint32_t)mf.len; for (num_empty = 0; num_empty != mf.len; ++num_empty) { if (mf.base[--idx] != erased_pattern) { break; } } num_empty -= (num_empty & 3); // round down to words if (num_empty != 0) { ILOG("Ignoring %d bytes of 0x%02x at end of file\n", num_empty, erased_pattern); } } else { num_empty = 0; } /* * TODO: investigate a kind of weird behaviour here: * If the file is identified to be all-empty and four-bytes aligned, * still flash the whole file even if ignoring message is printed. */ /* In case the address is within the OTP area we use a different flash method */ if(addr >= sl->otp_base && addr < sl->otp_base + sl->otp_size) { err = stlink_write_otp(sl, addr, mf.base, (num_empty == mf.len) ? (uint32_t)mf.len : (uint32_t)mf.len - num_empty); } else { err = stlink_write_flash(sl, addr, mf.base, (num_empty == mf.len) ? (uint32_t)mf.len : (uint32_t)mf.len - num_empty, num_empty == mf.len); } stlink_fwrite_finalize(sl, addr); unmap_file(&mf); return (err); } int32_t stlink_fcheck_flash(stlink_t *sl, const char *path, stm32_addr_t addr) { // check the contents of path are at addr int32_t res; mapped_file_t mf = MAPPED_FILE_INITIALIZER; if (map_file(&mf, path) == -1) { return (-1); } res = check_file(sl, &mf, addr); unmap_file(&mf); return (res); } /** * Verify addr..addr+len is binary identical to base...base+len * @param sl stlink context * @param address stm device address * @param data host side buffer to check against * @param length how much * @return 0 for success, -ve for failure */ int32_t stlink_verify_write_flash(stlink_t *sl, stm32_addr_t address, uint8_t *data, uint32_t length) { uint32_t off; uint32_t cmp_size = (sl->flash_pgsz > 0x1800) ? 0x1800 : sl->flash_pgsz; ILOG("Starting verification of write complete\n"); for (off = 0; off < length; off += cmp_size) { uint32_t aligned_size; // adjust last page size if ((off + cmp_size) > length) { cmp_size = length - off; } aligned_size = cmp_size; if (aligned_size & (4 - 1)) { aligned_size = (cmp_size + 4) & ~(4 - 1); } stlink_read_mem32(sl, address + off, (uint16_t)aligned_size); if (memcmp(sl->q_buf, data + off, cmp_size)) { ELOG("Verification of flash failed at offset: %u\n", off); return (-1); } } ILOG("Flash written and verified! jolly good!\n"); return (0); } // Check if an address and size are within the flash int32_t stlink_check_address_range_validity(stlink_t *sl, stm32_addr_t addr, uint32_t size) { uint32_t logvar; if (addr < sl->flash_base || addr >= (sl->flash_base + sl->flash_size)) { logvar = sl->flash_base + sl->flash_size - 1; ELOG("Invalid address, it should be within 0x%08x - 0x%08x\n", sl->flash_base, logvar); return (-1); } if ((addr + size) > (sl->flash_base + sl->flash_size)) { logvar = sl->flash_base + sl->flash_size - addr; ELOG("The size exceeds the size of the flash (0x%08x bytes available)\n", logvar); return (-1); } return 0; } // Check if an address and size are within the flash (otp area) int32_t stlink_check_address_range_validity_otp(stlink_t *sl, stm32_addr_t addr, uint32_t size) { uint32_t logvar; if (addr < sl->otp_base || addr >= (sl->otp_base + sl->otp_size)) { logvar = sl->otp_base + sl->otp_size - 1; ELOG("Invalid address, it should be within 0x%08x - 0x%08x\n", sl->otp_base, logvar); return (-1); } if ((addr + size) >= (sl->otp_base + sl->otp_size)) { logvar = sl->otp_base + sl->otp_size - addr; ELOG("The size exceeds the size of the OTP Area (0x%08x bytes available)\n", logvar); return (-1); } return 0; } // Check if an address is aligned with the beginning of a page int32_t stlink_check_address_alignment(stlink_t *sl, stm32_addr_t addr) { stm32_addr_t page = sl->flash_base; while (page < addr) { page += stlink_calculate_pagesize(sl, page); } if (page != addr) { return -1; } return 0; } int32_t stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len, uint8_t eraseonly) { int32_t ret; flash_loader_t fl; ILOG("Attempting to write %d (%#x) bytes to stm32 address: %u (%#x)\n", len, len, addr, addr); // check addr range is inside the flash stlink_calculate_pagesize(sl, addr); // Check the address and size validity if (stlink_check_address_range_validity(sl, addr, len) < 0) { return (-1); } else if (len & 1) { WLOG("unaligned len 0x%x -- padding with zero\n", len); len += 1; } else if (stlink_check_address_alignment(sl, addr) < 0) { ELOG("addr not a multiple of current pagesize (%u bytes), not supported, " "check page start address and compare with flash module organisation " "in related ST reference manual of your device.\n", sl->flash_pgsz); return (-1); } // make sure we've loaded the context with the chip details stlink_core_id(sl); // Erase this section of the flash if (stlink_erase_flash_section(sl, addr, len, true) < 0) { ELOG("Failed to erase the flash prior to writing\n"); return (-1); } if (eraseonly) { return (0); } ret = stlink_flashloader_start(sl, &fl); if (ret) return ret; ret = stlink_flashloader_write(sl, &fl, addr, base, len); if (ret) return ret; ret = stlink_flashloader_stop(sl, &fl); if (ret) return ret; return (stlink_verify_write_flash(sl, addr, base, len)); } int32_t stlink_write_otp(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) { int32_t ret; flash_loader_t fl; ILOG("Attempting to write %d (%#x) bytes to stm32 address: %u (%#x)\n", len, len, addr, addr); // Check the address and size validity if (stlink_check_address_range_validity_otp(sl, addr, len) < 0) { return (-1); } // make sure we've loaded the context with the chip details stlink_core_id(sl); ret = stlink_flashloader_start(sl, &fl); if (ret) return ret; ret = stlink_flashloader_write(sl, &fl, addr, base, len); if (ret) return ret; ret = stlink_flashloader_stop(sl, &fl); if (ret) return ret; return (stlink_verify_write_flash(sl, addr, base, len)); } void stlink_fwrite_finalize(stlink_t *sl, stm32_addr_t addr) { uint32_t val; // set PC to the reset routine stlink_read_debug32(sl, addr + 4, &val); stlink_write_reg(sl, val, 15); stlink_run(sl, RUN_NORMAL); } stlink-1.8.0/src/stlink-lib/common_flash.h000066400000000000000000000051221455655054600205200ustar00rootroot00000000000000/* * File: common_flash.h * * Flash operations */ #ifndef COMMON_FLASH_H #define COMMON_FLASH_H #define BANK_1 0 #define BANK_2 1 uint32_t get_stm32l0_flash_base(stlink_t *); uint32_t read_flash_cr(stlink_t *, uint32_t); void lock_flash(stlink_t *); // static inline int32_t write_flash_sr(stlink_t *sl, uint32_t bank, uint32_t val); void clear_flash_error(stlink_t *); uint32_t read_flash_sr(stlink_t *sl, uint32_t bank); uint32_t is_flash_busy(stlink_t *sl); void wait_flash_busy(stlink_t *); int32_t check_flash_error(stlink_t *); // static inline uint32_t is_flash_locked(stlink_t *sl); // static void unlock_flash(stlink_t *sl); int32_t unlock_flash_if(stlink_t *); int32_t lock_flash_option(stlink_t *); // static bool is_flash_option_locked(stlink_t *sl); // static int32_t unlock_flash_option(stlink_t *sl); int32_t unlock_flash_option_if(stlink_t *); void write_flash_cr_psiz(stlink_t *, uint32_t, uint32_t); void clear_flash_cr_pg(stlink_t *, uint32_t); // static void wait_flash_busy_progress(stlink_t *sl); // static inline void write_flash_ar(stlink_t *sl, uint32_t n, uint32_t bank); // static inline void write_flash_cr_snb(stlink_t *sl, uint32_t n, uint32_t bank); // static void set_flash_cr_per(stlink_t *sl, uint32_t bank); // static void clear_flash_cr_per(stlink_t *sl, uint32_t bank); // static inline void write_flash_cr_bker_pnb(stlink_t *sl, uint32_t n); // static void set_flash_cr_strt(stlink_t *sl, uint32_t bank); // static void set_flash_cr_mer(stlink_t *sl, bool v, uint32_t bank); int32_t stlink_erase_flash_page(stlink_t *sl, stm32_addr_t flashaddr); int32_t stlink_erase_flash_section(stlink_t *sl, stm32_addr_t base_addr, uint32_t size, bool align_size); int32_t stlink_erase_flash_mass(stlink_t *sl); int32_t stlink_mwrite_flash(stlink_t *sl, uint8_t *data, uint32_t length, stm32_addr_t addr); int32_t stlink_fwrite_flash(stlink_t *sl, const char *path, stm32_addr_t addr); int32_t stlink_fcheck_flash(stlink_t *sl, const char *path, stm32_addr_t addr); int32_t stlink_verify_write_flash(stlink_t *sl, stm32_addr_t address, uint8_t *data, uint32_t length); int32_t stlink_check_address_range_validity(stlink_t *sl, stm32_addr_t addr, uint32_t size); int32_t stlink_check_address_range_validity_otp(stlink_t *sl, stm32_addr_t addr, uint32_t size); int32_t stlink_check_address_alignment(stlink_t *sl, stm32_addr_t addr); int32_t stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len, uint8_t eraseonly); int32_t stlink_write_otp(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len); void stlink_fwrite_finalize(stlink_t *, stm32_addr_t); #endif // COMMON_FLASH_H stlink-1.8.0/src/stlink-lib/flash_loader.c000066400000000000000000000732731455655054600205050ustar00rootroot00000000000000/* * File: flash_loader.c * * Flash loaders */ #include #include #include #include #include #include #include "flash_loader.h" #include "common_flash.h" #include "helper.h" #include "logging.h" #include "read_write.h" #include "register.h" #define FLASH_REGS_BANK2_OFS 0x40 #define FLASH_BANK2_START_ADDR 0x08080000 #define STM32F0_WDG_KR 0x40003000 #define STM32H7_WDG_KR 0x58004800 #define STM32F0_WDG_KR_KEY_RELOAD 0xAAAA /* * !!! DO NOT MODIFY 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/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/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, STLINK_REG_DHCSR, STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_DEBUGEN | STLINK_REG_DHCSR_C_HALT); /* and only then disable interrupts */ stlink_write_debug32(sl, STLINK_REG_DHCSR, STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_DEBUGEN | STLINK_REG_DHCSR_C_HALT | STLINK_REG_DHCSR_C_MASKINTS); // allocate the loader in SRAM if (stlink_flash_loader_write_to_sram(sl, &fl->loader_addr, &size) == -1) { WLOG("Failed to write flash loader to sram!\n"); return (-1); } // 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, STLINK_REG_DFSR, &dfsr) && dfsr) { ILOG("Clear DFSR\n"); stlink_write_debug32(sl, STLINK_REG_DFSR, dfsr); } if (!stlink_read_debug32(sl, STLINK_REG_CFSR, &cfsr) && cfsr) { ILOG("Clear CFSR\n"); stlink_write_debug32(sl, STLINK_REG_CFSR, cfsr); } if (!stlink_read_debug32(sl, STLINK_REG_HFSR, &hfsr) && hfsr) { ILOG("Clear HFSR\n"); stlink_write_debug32(sl, STLINK_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->chip_id == STM32_CHIPID_L4) || (sl->chip_id == STM32_CHIPID_L41x_L42x) || (sl->chip_id == STM32_CHIPID_L43x_L44x) || (sl->chip_id == STM32_CHIPID_L45x_L46x) || (sl->chip_id == STM32_CHIPID_L4Rx) || (sl->chip_id == STM32_CHIPID_L496x_L4A6x)) { loader_code = loader_code_stm32l4; loader_size = sizeof(loader_code_stm32l4); } else { ELOG("unknown coreid, not sure what flash loader to use, aborting! coreid: %x, chipid: %x\n", sl->core_id, sl->chip_id); return (-1); } 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; DLOG("Running flash loader, write address:%#x, size: %u\n", target, size); if (write_buffer_to_sram(sl, fl, buf, size) == -1) { ELOG("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, 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\n"); goto error; } return (0); error: dhcsr = dfsr = cfsr = hfsr = 0; stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr); stlink_read_debug32(sl, STLINK_REG_DFSR, &dfsr); stlink_read_debug32(sl, STLINK_REG_CFSR, &cfsr); stlink_read_debug32(sl, STLINK_REG_HFSR, &hfsr); stlink_read_all_regs(sl, &rr); WLOG("Loader state: R2 0x%X R15 0x%X\n", rr.r[2], rr.r[15]); if (dhcsr != 0x3000B || dfsr || cfsr || hfsr) { WLOG("MCU state: DHCSR 0x%X DFSR 0x%X CFSR 0x%X HFSR 0x%X\n", dhcsr, dfsr, cfsr, hfsr); } return (-1); } /* === Content from old source file flashloader.c === */ #define L1_WRITE_BLOCK_SIZE 0x80 #define L0_WRITE_BLOCK_SIZE 0x40 int32_t stm32l1_write_half_pages(stlink_t *sl, flash_loader_t *fl, stm32_addr_t addr, uint8_t *base, uint32_t len, uint32_t pagesize) { uint32_t count, off; uint32_t num_half_pages = len / pagesize; uint32_t val; uint32_t flash_regs_base = get_stm32l0_flash_base(sl); bool use_loader = true; int32_t ret = 0; // enable half page write stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val); val |= (1 << FLASH_L1_FPRG); stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val); val |= (1 << FLASH_L1_PROG); stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val); wait_flash_busy(sl); for (count = 0; count < num_half_pages; count++) { if (use_loader) { ret = stlink_flash_loader_run(sl, fl, addr + count * pagesize, base + count * pagesize, pagesize); if (ret && count == 0) { /* It seems that stm32lx devices have a problem when it is blank */ WLOG("Failed to use flash loader, fallback to soft write\n"); use_loader = false; } } if (!use_loader) { ret = 0; for (off = 0; off < pagesize && !ret; off += 64) { uint32_t chunk = (pagesize - off > 64) ? 64 : pagesize - off; memcpy(sl->q_buf, base + count * pagesize + off, chunk); ret = stlink_write_mem32(sl, addr + count * pagesize + off, (uint16_t)chunk); } } if (ret) { WLOG("l1_stlink_flash_loader_run(%#x) failed! == -1\n", addr + count * pagesize); break; } if (sl->verbose >= 1) { // show progress; writing procedure is slow and previous errors are misleading fprintf(stdout, "\r%3u/%3u halfpages written", count + 1, num_half_pages); fflush(stdout); } // wait for sr.busy to be cleared wait_flash_busy(sl); } // disable half page write stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val); val &= ~((1 << FLASH_L1_FPRG) | (1 << FLASH_L1_PROG)); stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val); return (ret); } static void set_flash_cr_pg(stlink_t *sl, uint32_t bank) { uint32_t cr_reg, x; x = read_flash_cr(sl, bank); if (sl->flash_type == STM32_FLASH_TYPE_C0) { cr_reg = FLASH_C0_CR; x |= (1 << FLASH_CR_PG); } else if (sl->flash_type == STM32_FLASH_TYPE_F2_F4) { cr_reg = FLASH_F4_CR; x |= (1 << FLASH_CR_PG); } else if (sl->flash_type == STM32_FLASH_TYPE_F7) { cr_reg = FLASH_F7_CR; x |= (1 << FLASH_CR_PG); } else if (sl->flash_type == STM32_FLASH_TYPE_L4) { cr_reg = FLASH_L4_CR; x &= ~FLASH_L4_CR_OPBITS; x |= (1 << FLASH_L4_CR_PG); } else if (sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5) { cr_reg = FLASH_L5_NSCR; x |= (1 << FLASH_CR_PG); } else if (sl->flash_type == STM32_FLASH_TYPE_G0 || sl->flash_type == STM32_FLASH_TYPE_G4) { cr_reg = FLASH_Gx_CR; x |= (1 << FLASH_CR_PG); } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL) { cr_reg = FLASH_WB_CR; x |= (1 << FLASH_CR_PG); } else if (sl->flash_type == STM32_FLASH_TYPE_H7) { cr_reg = (bank == BANK_1) ? FLASH_H7_CR1 : FLASH_H7_CR2; x |= (1 << FLASH_H7_CR_PG); } else { cr_reg = (bank == BANK_1) ? FLASH_CR : FLASH_CR2; x = (1 << FLASH_CR_PG); } stlink_write_debug32(sl, cr_reg, x); } static void set_dma_state(stlink_t *sl, flash_loader_t *fl, int32_t bckpRstr) { uint32_t rcc, rcc_dma_mask, value; rcc = rcc_dma_mask = value = 0; switch (sl->flash_type) { case STM32_FLASH_TYPE_C0: rcc = STM32C0_RCC_AHBENR; rcc_dma_mask = STM32C0_RCC_DMAEN; break; case STM32_FLASH_TYPE_F0_F1_F3: case STM32_FLASH_TYPE_F1_XL: rcc = STM32F1_RCC_AHBENR; rcc_dma_mask = STM32F1_RCC_DMAEN; break; case STM32_FLASH_TYPE_F2_F4: case STM32_FLASH_TYPE_F7: rcc = STM32F4_RCC_AHB1ENR; rcc_dma_mask = STM32F4_RCC_DMAEN; break; case STM32_FLASH_TYPE_G0: rcc = STM32G0_RCC_AHBENR; rcc_dma_mask = STM32G0_RCC_DMAEN; break; case STM32_FLASH_TYPE_G4: case STM32_FLASH_TYPE_L4: rcc = STM32G4_RCC_AHB1ENR; rcc_dma_mask = STM32G4_RCC_DMAEN; break; case STM32_FLASH_TYPE_L0_L1: if (get_stm32l0_flash_base(sl) == FLASH_Lx_REGS_ADDR) { rcc = STM32L1_RCC_AHBENR; rcc_dma_mask = STM32L1_RCC_DMAEN; } else { rcc = STM32L0_RCC_AHBENR; rcc_dma_mask = STM32L0_RCC_DMAEN; } break; case STM32_FLASH_TYPE_L5_U5_H5: rcc = STM32L5_RCC_AHB1ENR; rcc_dma_mask = STM32L5_RCC_DMAEN; break; case STM32_FLASH_TYPE_H7: rcc = STM32H7_RCC_AHB1ENR; rcc_dma_mask = STM32H7_RCC_DMAEN; break; case STM32_FLASH_TYPE_WB_WL: rcc = STM32WB_RCC_AHB1ENR; rcc_dma_mask = STM32WB_RCC_DMAEN; break; default: return; } if (!stlink_read_debug32(sl, rcc, &value)) { if (bckpRstr) { value = (value & (~rcc_dma_mask)) | fl->rcc_dma_bkp; } else { fl->rcc_dma_bkp = value & rcc_dma_mask; value &= ~rcc_dma_mask; } stlink_write_debug32(sl, rcc, value); } } int32_t stlink_flashloader_start(stlink_t *sl, flash_loader_t *fl) { // disable DMA set_dma_state(sl, fl, 0); // wait for ongoing op to finish wait_flash_busy(sl); // Clear errors clear_flash_error(sl); if ((sl->flash_type == STM32_FLASH_TYPE_F2_F4) || (sl->flash_type == STM32_FLASH_TYPE_F7) || (sl->flash_type == STM32_FLASH_TYPE_L4)) { ILOG("Starting Flash write for F2/F4/F7/L4\n"); // Flash loader initialisation if (stlink_flash_loader_init(sl, fl) == -1) { ELOG("stlink_flash_loader_init() == -1\n"); return (-1); } 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.2V\n"); voltage = 3200; } else { voltage = stlink_target_voltage(sl); } if (voltage == -1) { ELOG("Failed to read Target voltage\n"); return (-1); } if (sl->flash_type == STM32_FLASH_TYPE_L4) { // L4 does not have a byte-write mode if (voltage < 1710) { ELOG("Target voltage (%d mV) too low for flash writes!\n", voltage); return (-1); } } else { if (voltage > 2700) { ILOG("enabling 32-bit flash writes\n"); write_flash_cr_psiz(sl, 2, BANK_1); } else { ILOG("Target voltage (%d mV) too low for 32-bit flash, using 8-bit flash writes\n", voltage); write_flash_cr_psiz(sl, 0, BANK_1); } } // set programming mode set_flash_cr_pg(sl, BANK_1); } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL || sl->flash_type == STM32_FLASH_TYPE_G0 || sl->flash_type == STM32_FLASH_TYPE_G4 || sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5 || sl->flash_type == STM32_FLASH_TYPE_C0) { ILOG("Starting Flash write for WB/G0/G4/L5/U5/H5/C0\n"); unlock_flash_if(sl); // unlock flash if necessary set_flash_cr_pg(sl, BANK_1); // set PG 'allow programming' bit } else if (sl->flash_type == STM32_FLASH_TYPE_L0_L1) { ILOG("Starting Flash write for L0\n"); uint32_t val; uint32_t flash_regs_base = get_stm32l0_flash_base(sl); // disable pecr protection stlink_write_debug32(sl, flash_regs_base + FLASH_PEKEYR_OFF, FLASH_L0_PEKEY1); stlink_write_debug32(sl, flash_regs_base + FLASH_PEKEYR_OFF, FLASH_L0_PEKEY2); // check pecr.pelock is cleared stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val); if (val & (1 << 0)) { ELOG("pecr.pelock not clear\n"); return (-1); } // unlock program memory stlink_write_debug32(sl, flash_regs_base + FLASH_PRGKEYR_OFF, FLASH_L0_PRGKEY1); stlink_write_debug32(sl, flash_regs_base + FLASH_PRGKEYR_OFF, FLASH_L0_PRGKEY2); // check pecr.prglock is cleared stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val); if (val & (1 << 1)) { ELOG("pecr.prglock not clear\n"); return (-1); } /* Flash loader initialisation */ if (stlink_flash_loader_init(sl, fl) == -1) { // L0/L1 have fallback to soft write WLOG("stlink_flash_loader_init() == -1\n"); } } else if ((sl->flash_type == STM32_FLASH_TYPE_F0_F1_F3) || (sl->flash_type == STM32_FLASH_TYPE_F1_XL)) { ILOG("Starting Flash write for VL/F0/F3/F1_XL\n"); // flash loader initialisation if (stlink_flash_loader_init(sl, fl) == -1) { ELOG("stlink_flash_loader_init() == -1\n"); return (-1); } // unlock flash unlock_flash_if(sl); // set programming mode set_flash_cr_pg(sl, BANK_1); if (sl->flash_type == STM32_FLASH_TYPE_F1_XL) { set_flash_cr_pg(sl, BANK_2); } } else if (sl->flash_type == STM32_FLASH_TYPE_H7) { ILOG("Starting Flash write for H7\n"); unlock_flash_if(sl); // unlock the cr set_flash_cr_pg(sl, BANK_1); // set programming mode if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) { set_flash_cr_pg(sl, BANK_2); } if (sl->chip_id != STM32_CHIPID_H7Ax) { // set parallelism write_flash_cr_psiz(sl, 3 /* 64bit */, BANK_1); if (sl->chip_flags & CHIP_F_HAS_DUAL_BANK) { write_flash_cr_psiz(sl, 3 /* 64bit */, BANK_2); } } } else { ELOG("unknown coreid, not sure how to write: %x\n", sl->core_id); return (-1); } return (0); } int32_t stlink_flashloader_write(stlink_t *sl, flash_loader_t *fl, stm32_addr_t addr, uint8_t *base, uint32_t len) { uint32_t off; if ((sl->flash_type == STM32_FLASH_TYPE_F2_F4) || (sl->flash_type == STM32_FLASH_TYPE_F7) || (sl->flash_type == STM32_FLASH_TYPE_L4)) { uint32_t buf_size = (sl->sram_size > 0x8000) ? 0x8000 : 0x4000; for (off = 0; off < len;) { uint32_t size = len - off > buf_size ? buf_size : len - off; if (stlink_flash_loader_run(sl, fl, addr + off, base + off, size) == -1) { ELOG("stlink_flash_loader_run(%#x) failed! == -1\n", (addr + off)); check_flash_error(sl); return (-1); } off += size; } } else if (sl->flash_type == STM32_FLASH_TYPE_WB_WL || sl->flash_type == STM32_FLASH_TYPE_G0 || sl->flash_type == STM32_FLASH_TYPE_G4 || sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5 || sl->flash_type == STM32_FLASH_TYPE_C0) { if (sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5 && (len % 16)) { WLOG("Data size is aligned to 16 byte"); len += 16 - len%16; } DLOG("Starting %3u page write\n", len / sl->flash_pgsz); for (off = 0; off < len; off += sizeof(uint32_t)) { uint32_t data; if ((off % sl->flash_pgsz) > (sl->flash_pgsz - 5)) { fprintf(stdout, "\r%3u/%-3u pages written", (off / sl->flash_pgsz + 1), (len / sl->flash_pgsz)); fflush(stdout); } // write_uint32((unsigned char *)&data, *(uint32_t *)(base + off)); data = 0; memcpy(&data, base + off, (len - off) < 4 ? (len - off) : 4); stlink_write_debug32(sl, addr + off, data); wait_flash_busy(sl); // wait for 'busy' bit in FLASH_SR to clear } fprintf(stdout, "\n"); // flash writes happen as 2 words at a time if ((off / sizeof(uint32_t)) % 2 != 0) { stlink_write_debug32(sl, addr + off, 0); // write a single word of zeros wait_flash_busy(sl); // wait for 'busy' bit in FLASH_SR to clear } } else if (sl->flash_type == STM32_FLASH_TYPE_L0_L1) { uint32_t val; uint32_t flash_regs_base = get_stm32l0_flash_base(sl); uint32_t pagesize = (flash_regs_base == FLASH_L0_REGS_ADDR)? L0_WRITE_BLOCK_SIZE : L1_WRITE_BLOCK_SIZE; DLOG("Starting %3u page write\r\n", len / sl->flash_pgsz); off = 0; if (len > pagesize) { if (stm32l1_write_half_pages(sl, fl, addr, base, len, pagesize)) { return (-1); } else { off = (size_t)(len / pagesize) * pagesize; } } // write remaining word in program memory for (; off < len; off += sizeof(uint32_t)) { uint32_t data; if ((off % sl->flash_pgsz) > (sl->flash_pgsz - 5)) { fprintf(stdout, "\r%3u/%-3u pages written", (off / sl->flash_pgsz + 1), (len / sl->flash_pgsz)); fflush(stdout); } write_uint32((unsigned char *)&data, *(uint32_t *)(base + off)); stlink_write_debug32(sl, addr + off, data); // wait for sr.busy to be cleared do { stlink_read_debug32(sl, flash_regs_base + FLASH_SR_OFF, &val); } while ((val & (1 << 0)) != 0); // TODO: check redo write operation } fprintf(stdout, "\n"); } else if ((sl->flash_type == STM32_FLASH_TYPE_F0_F1_F3) || (sl->flash_type == STM32_FLASH_TYPE_F1_XL)) { int32_t write_block_count = 0; for (off = 0; off < len; off += sl->flash_pgsz) { // adjust last write size uint32_t size = len - off > sl->flash_pgsz ? sl->flash_pgsz : len - off; // unlock and set programming mode unlock_flash_if(sl); DLOG("Finished unlocking flash, running loader!\n"); if (stlink_flash_loader_run(sl, fl, addr + off, base + off, size) == -1) { ELOG("stlink_flash_loader_run(%#x) failed! == -1\n", (addr + off)); check_flash_error(sl); return (-1); } lock_flash(sl); if (sl->verbose >= 1) { // show progress; writing procedure is slow and previous errors are // misleading fprintf(stdout, "\r%3u/%-3u pages written", ++write_block_count, (len + sl->flash_pgsz - 1) / sl->flash_pgsz); fflush(stdout); } } if (sl->verbose >= 1) { fprintf(stdout, "\n"); } } else if (sl->flash_type == STM32_FLASH_TYPE_H7) { for (off = 0; off < len;) { // Program STM32H7x with 64-byte Flash words uint32_t chunk = (len - off > 64) ? 64 : len - off; memcpy(sl->q_buf, base + off, chunk); stlink_write_mem32(sl, addr + off, 64); wait_flash_busy(sl); off += chunk; if (sl->verbose >= 1) { // show progress fprintf(stdout, "\r%u/%u bytes written", off, len); fflush(stdout); } } if (sl->verbose >= 1) { fprintf(stdout, "\n"); } } else { return (-1); } return check_flash_error(sl); } int32_t stlink_flashloader_stop(stlink_t *sl, flash_loader_t *fl) { uint32_t dhcsr; if ((sl->flash_type == STM32_FLASH_TYPE_C0) || (sl->flash_type == STM32_FLASH_TYPE_F0_F1_F3) || (sl->flash_type == STM32_FLASH_TYPE_F1_XL) || (sl->flash_type == STM32_FLASH_TYPE_F2_F4) || (sl->flash_type == STM32_FLASH_TYPE_F7) || (sl->flash_type == STM32_FLASH_TYPE_G0) || (sl->flash_type == STM32_FLASH_TYPE_G4) || (sl->flash_type == STM32_FLASH_TYPE_H7) || (sl->flash_type == STM32_FLASH_TYPE_L4) || (sl->flash_type == STM32_FLASH_TYPE_L5_U5_H5) || (sl->flash_type == STM32_FLASH_TYPE_WB_WL)) { clear_flash_cr_pg(sl, BANK_1); if ((sl->flash_type == STM32_FLASH_TYPE_H7 && sl->chip_flags & CHIP_F_HAS_DUAL_BANK) || sl->flash_type == STM32_FLASH_TYPE_F1_XL) { clear_flash_cr_pg(sl, BANK_2); } lock_flash(sl); } else if (sl->flash_type == STM32_FLASH_TYPE_L0_L1) { uint32_t val; uint32_t flash_regs_base = get_stm32l0_flash_base(sl); // reset lock bits stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val); val |= (1 << 0) | (1 << 1) | (1 << 2); stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val); } // enable interrupt if (!stlink_read_debug32(sl, STLINK_REG_DHCSR, &dhcsr)) { stlink_write_debug32(sl, STLINK_REG_DHCSR, STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_DEBUGEN | (dhcsr & (~STLINK_REG_DHCSR_C_MASKINTS))); } // restore DMA state set_dma_state(sl, fl, 1); return (0); } stlink-1.8.0/src/stlink-lib/flash_loader.h000066400000000000000000000025351455655054600205030ustar00rootroot00000000000000/* * File: flash_loader.h * * Flash loaders */ #ifndef FLASH_LOADER_H #define FLASH_LOADER_H int32_t stlink_flash_loader_init(stlink_t *sl, flash_loader_t* fl); // static int32_t loader_v_dependent_assignment(stlink_t *sl, // const uint8_t **loader_code, uint32_t *loader_size, // const uint8_t *high_v_loader, uint32_t high_v_loader_size, // const uint8_t *low_v_loader, uint32_t low_v_loader_size); int32_t stlink_flash_loader_write_to_sram(stlink_t *sl, stm32_addr_t* addr, uint32_t* size); int32_t stlink_flash_loader_run(stlink_t *sl, flash_loader_t* fl, stm32_addr_t target, const uint8_t* buf, uint32_t size); /* === 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.8.0/src/stlink-lib/helper.c000066400000000000000000000012661455655054600173320ustar00rootroot00000000000000/* * File: helper.c * * General helper functions */ #ifdef STLINK_HAVE_SYS_TIME_H #include #else #include #endif // STLINK_HAVE_SYS_TIME_H #include #include #include #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) { char *tail; int32_t value = (int32_t)strtol(str, &tail, 10); if (tail[0] == 'M' && tail[1] == '\0') { value = value*1000; } else if ((tail[0] != 'k' || tail[1] != '\0') && tail[0] != '\0') { return -1; } return value; } stlink-1.8.0/src/stlink-lib/helper.h000066400000000000000000000002551455655054600173340ustar00rootroot00000000000000/* * File: helper.h * * General helper functions */ #ifndef HELPER_H #define HELPER_H uint32_t time_ms(); int32_t arg_parse_freq(const char *str); #endif // HELPER_H stlink-1.8.0/src/stlink-lib/lib_md5.c000066400000000000000000000231011455655054600173560ustar00rootroot00000000000000/* * 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 #include #include #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.8.0/src/stlink-lib/lib_md5.h000066400000000000000000000035101455655054600173650ustar00rootroot00000000000000/* * WjCryptLib_Md5 (https://github.com/WaterJuice/WjCryptLib) * Implementation of MD5 hash function. Originally written by Alexander Peslyak. * Modified by WaterJuice retaining Public Domain license. * This is free and unencumbered software released into the public domain - June 2013 - waterjuice.org */ #ifndef LIB_MD5_H #define LIB_MD5_H #pragma once /* TYPES */ /* Md5Context * This must be initialised using Md5Initialised. * Do not modify the contents of this structure directly. */ typedef struct { uint32_t lo; uint32_t hi; uint32_t a; uint32_t b; uint32_t c; uint32_t d; uint8_t buffer[64]; uint32_t block[16]; } Md5Context; #define MD5_HASH_SIZE (128 / 8) typedef struct { uint8_t bytes [MD5_HASH_SIZE]; } MD5_HASH; /* PUBLIC FUNCTIONS */ /* Md5Initialise * Initialises an MD5 Context. * Use this to initialise/reset a context. */ void Md5Initialise(Md5Context* Context /* [out] */); /* Md5Update * Adds data to the MD5 context. * This will process the data and update the internal state of the context. * Keep on calling this function until all the data has been added. * Then call Md5Finalise to calculate the hash. */ void Md5Update(Md5Context* Context /* [in out] */, void const* Buffer /* [in] */, uint32_t BufferSize /* [in] */); /* Md5Finalise * Performs the final calculation of the hash and returns the digest * (16 byte buffer containing 128bit hash). * After calling this, Md5Initialised must be used to reuse the context. */ void Md5Finalise(Md5Context* Context /* [in out] */, MD5_HASH* Digest /* [in] */); /* Md5Calculate * Combines Md5Initialise, Md5Update, and Md5Finalise into one function. * Calculates the MD5 hash of the buffer. */ void Md5Calculate(void const* Buffer /* [in] */, uint32_t BufferSize /* [in] */, MD5_HASH* Digest /* [in] */); #endif // LIB_MD5_Hstlink-1.8.0/src/stlink-lib/libusb_settings.h000066400000000000000000000024721455655054600212600ustar00rootroot00000000000000/* * File: libusb_settings.h * * Settings for libusb library */ #ifndef LIBUSB_SETTINGS_H #define LIBUSB_SETTINGS_H #include /* * libusb ver | LIBUSB_API_VERSION * -----------+-------------------- * v1.0.13 | 0x01000100 * v1.0.14 | 0x010000FF * v1.0.15 | 0x01000101 * v1.0.16 | 0x01000102 * v1.0.17 | 0x01000102 * v1.0.18 | 0x01000102 * v1.0.19 | 0x01000103 * v1.0.20 | 0x01000104 * v1.0.21 | 0x01000105 * v1.0.22 | 0x01000106 * v1.0.23 | 0x01000107 * v1.0.24 | 0x01000108 * v1.0.25 | 0x01000109 * v1.0.26 | 0x01000110 */ #if defined (__FreeBSD__) #if !defined (LIBUSBX_API_VERSION) #define LIBUSBX_API_VERSION LIBUSB_API_VERSION #elif !defined (LIBUSB_API_VERSION) #error unsupported libusb version #endif #endif #if defined (__FreeBSD__) #define MINIMAL_API_VERSION 0x01000102 // v1.0.16 #elif defined (__OpenBSD__) #define MINIMAL_API_VERSION 0x01000106 // v1.0.22 #elif defined (__linux__) #define MINIMAL_API_VERSION 0x01000106 // v1.0.22 #elif defined (_WIN32) #define MINIMAL_API_VERSION 0x01000109 // v1.0.25 #endif #if (LIBUSB_API_VERSION < MINIMAL_API_VERSION) #error unsupported libusb version #endif #endif // LIBUSB_SETTINGS_H stlink-1.8.0/src/stlink-lib/logging.c000066400000000000000000000052321455655054600174760ustar00rootroot00000000000000/* * File: logging.c * * UglyLogging: Slow, yet another wheel reinvented, but enough to make the rest of our code pretty enough. */ #define __STDC_WANT_LIB_EXT1__ 1 #include #include #include #include #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.8.0/src/stlink-lib/logging.h000066400000000000000000000042241455655054600175030ustar00rootroot00000000000000/* * File: logging.h * * UglyLogging: Slow, yet another wheel reinvented, but enough to make the rest of our code pretty enough. * Ugly, low performance, configurable level, logging "framework" */ #ifndef LOGGING_H #define LOGGING_H #include #include "spdlog_wrapper.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.8.0/src/stlink-lib/map_file.c000066400000000000000000000043041455655054600176230ustar00rootroot00000000000000/* * File: map_file.c * * File mapping */ #include #include #include #include #include #include #include #include "map_file.h" #include "read_write.h" #ifndef O_BINARY #define O_BINARY 0 #endif // 1 GB max file size #ifndef MAX_FILE_SIZE #define MAX_FILE_SIZE (1<<20) #endif /* Limit the block size to compare to 0x1800 as anything larger will stall the * STLINK2 Maybe STLINK V1 needs smaller value! */ int32_t check_file(stlink_t *sl, mapped_file_t *mf, stm32_addr_t addr) { uint32_t off; uint32_t n_cmp = sl->flash_pgsz; if (n_cmp > 0x1800) { n_cmp = 0x1800; } for (off = 0; off < mf->len; off += n_cmp) { uint32_t aligned_size; uint32_t cmp_size = n_cmp; // adjust last page size if ((off + n_cmp) > mf->len) { cmp_size = mf->len - off; } aligned_size = cmp_size; if (aligned_size & (4 - 1)) { aligned_size = (cmp_size + 4) & ~(4 - 1); } stlink_read_mem32(sl, addr + off, (uint16_t)aligned_size); if (memcmp(sl->q_buf, mf->base + off, cmp_size)) { return (-1); } } return (0); } int32_t map_file(mapped_file_t *mf, const char *path) { int32_t error = -1; struct stat st; const int32_t fd = open(path, O_RDONLY | O_BINARY); if (fd == -1) { fprintf(stderr, "open(%s) == -1\n", path); return (-1); } if (fstat(fd, &st) == -1) { fprintf(stderr, "fstat(%s) == -1\n", path); goto on_error; } if (sizeof(st.st_size) != sizeof(size_t)) { // on 32 bit systems, check if there is an overflow if (st.st_size > (off_t)MAX_FILE_SIZE /*1 GB*/ ) { // limit file size to 1 GB fprintf(stderr, "mmap() uint32_t overflow for file %s\n", path); goto on_error; } } mf->base = (uint8_t *)mmap(NULL, (size_t)(st.st_size), PROT_READ, MAP_SHARED, fd, 0); if (mf->base == MAP_FAILED) { fprintf(stderr, "mmap() == MAP_FAILED for file %s\n", path); goto on_error; } mf->len = (size_t)st.st_size; error = 0; // success on_error: close(fd); return (error); } void unmap_file(mapped_file_t *mf) { munmap((void *)mf->base, mf->len); mf->base = (unsigned char *)MAP_FAILED; mf->len = 0; } stlink-1.8.0/src/stlink-lib/map_file.h000066400000000000000000000011551455655054600176310ustar00rootroot00000000000000/* * File: map_file.h * * File mapping */ #ifndef MAP_FILE_H #define MAP_FILE_H #ifndef O_BINARY #define O_BINARY 0 #endif // O_BINARY #ifdef STLINK_HAVE_SYS_MMAN_H #include #else #include #endif // STLINK_HAVE_SYS_MMAN_H /* Memory mapped file */ typedef struct mapped_file { uint8_t *base; uint32_t len; } mapped_file_t; #define MAPPED_FILE_INITIALIZER \ { NULL, 0 } int32_t check_file(stlink_t *, mapped_file_t *, stm32_addr_t); int32_t map_file(mapped_file_t *, const char *); void unmap_file(mapped_file_t *); #endif // MAP_FILE_H stlink-1.8.0/src/stlink-lib/md5.c000066400000000000000000000015341455655054600165360ustar00rootroot00000000000000/* * File: md5.c * * MD5 hash function */ #include #include #include #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.8.0/src/stlink-lib/md5.h000066400000000000000000000002771455655054600165460ustar00rootroot00000000000000/* * File: md5.h * * MD5 hash function */ #ifndef MD5_H #define MD5_H #include "map_file.h" void md5_calculate(mapped_file_t *); void stlink_checksum(mapped_file_t *); #endif // MD5_Hstlink-1.8.0/src/stlink-lib/option_bytes.c000066400000000000000000000760751455655054600206030ustar00rootroot00000000000000/* * File: option_bytes.c * * Read and write option bytes and option control registers */ #include #include #include #include #include "option_bytes.h" #include "common_flash.h" #include "flash_loader.h" #include "logging.h" #include "map_file.h" #include "md5.h" #include "read_write.h" /** * Read option control register C0 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ static int32_t stlink_read_option_control_register_c0(stlink_t *sl, uint32_t *option_byte) { return stlink_read_debug32(sl, FLASH_C0_OPTR, option_byte); } /** * Read option bytes C0 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ static int32_t stlink_read_option_bytes_c0(stlink_t *sl, uint32_t *option_byte) { return stlink_read_option_control_register_c0(sl, option_byte); } /** * Write option control register C0 * @param sl * @param option_cr * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_control_register_c0(stlink_t *sl, uint32_t option_cr) { int32_t ret = 0; clear_flash_error(sl); if ((ret = stlink_write_debug32(sl, FLASH_C0_OPTR, option_cr))) return ret; wait_flash_busy(sl); uint32_t cr_reg = (1 << FLASH_C0_CR_OPTSTRT); if ((ret = stlink_write_debug32(sl, FLASH_C0_CR, cr_reg))) return ret; wait_flash_busy(sl); if ((ret = check_flash_error(sl))) return ret; // trigger the load of option bytes into option registers cr_reg = (1 << FLASH_C0_CR_OBL_LAUNCH); stlink_write_debug32(sl, FLASH_C0_CR, cr_reg); return ret; } /** * Write option bytes C0 * @param sl * @param addr of the memory mapped option bytes * @param base option bytes * @param len of option bytes * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_bytes_c0(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) { (void)addr; (void)len; return stlink_write_option_control_register_c0(sl, *(uint32_t*)base); } /** * Read option control register F0 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_control_register_f0(stlink_t *sl, uint32_t *option_byte) { DLOG("@@@@ Read option control register byte from %#10x\n", FLASH_OBR); return stlink_read_debug32(sl, FLASH_OBR, option_byte); } /** * Write option bytes F0 * @param sl * @param addr of the memory mapped option bytes * @param base option bytes * @param len of option bytes * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_bytes_f0(stlink_t *sl, stm32_addr_t addr, uint8_t* base, uint32_t len) { int32_t ret = 0; if (len < 12 || addr != STM32_F0_OPTION_BYTES_BASE) { WLOG("Only full write of option bytes area is supported\n"); return -1; } clear_flash_error(sl); WLOG("Erasing option bytes\n"); /* erase option bytes */ stlink_write_debug32(sl, FLASH_CR, (1 << FLASH_CR_OPTER) | (1 << FLASH_CR_OPTWRE)); ret = stlink_write_debug32(sl, FLASH_CR, (1 << FLASH_CR_OPTER) | (1 << FLASH_CR_STRT) | (1 << FLASH_CR_OPTWRE)); if (ret) { return ret; } wait_flash_busy(sl); ret = check_flash_error(sl); if (ret) { return ret; } WLOG("Writing option bytes to %#10x\n", addr); /* Set the Option PG bit to enable programming */ stlink_write_debug32(sl, FLASH_CR, (1 << FLASH_CR_OPTPG) | (1 << FLASH_CR_OPTWRE)); /* Use flash loader for write OP * because flash memory writable by half word */ flash_loader_t fl; ret = stlink_flash_loader_init(sl, &fl); if (ret) { return ret; } ret = stlink_flash_loader_run(sl, &fl, addr, base, len); if (ret) { return ret; } /* Reload option bytes */ stlink_write_debug32(sl, FLASH_CR, (1 << FLASH_CR_OBL_LAUNCH)); return check_flash_error(sl); } /** * Write option control register F0 * @param sl * @param option_cr * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_control_register_f0(stlink_t *sl, uint32_t option_cr) { int32_t ret = 0; uint16_t opt_val[8]; uint32_t protection, optiondata; uint16_t user_options, user_data, rdp; uint32_t option_offset, user_data_offset; ILOG("Asked to write option control register %#10x to %#010x.\n", option_cr, FLASH_OBR); /* Clear errors */ clear_flash_error(sl); /* Retrieve current values */ ret = stlink_read_debug32(sl, FLASH_OBR, &optiondata); if (ret) { return ret; } ret = stlink_read_debug32(sl, FLASH_WRPR, &protection); if (ret) { return ret; } /* Translate OBR value to flash store structure * F0: RM0091, Option byte description, pp. 75-78 * F1: PM0075, Option byte description, pp. 19-22 * F3: RM0316, Option byte description, pp. 85-87 */ switch(sl->chip_id) { case 0x422: /* STM32F30x */ case 0x432: /* STM32F37x */ case 0x438: /* STM32F303x6/8 and STM32F328 */ case 0x446: /* STM32F303xD/E and STM32F398xE */ case 0x439: /* STM32F302x6/8 */ case 0x440: /* STM32F05x */ case 0x444: /* STM32F03x */ case 0x445: /* STM32F04x */ case 0x448: /* STM32F07x */ case 0x442: /* STM32F09x */ option_offset = 6; user_data_offset = 16; rdp = 0x55AA; break; default: option_offset = 0; user_data_offset = 10; rdp = 0x5AA5; break; } user_options = (option_cr >> option_offset >> 2) & 0xFFFF; user_data = (option_cr >> user_data_offset) & 0xFFFF; #define VAL_WITH_COMPLEMENT(v) (uint16_t)(((v)&0xFF) | (((~(v))<<8)&0xFF00)) opt_val[0] = (option_cr & (1 << 1/*OPT_READOUT*/)) ? 0xFFFF : rdp; opt_val[1] = VAL_WITH_COMPLEMENT(user_options); opt_val[2] = VAL_WITH_COMPLEMENT(user_data); opt_val[3] = VAL_WITH_COMPLEMENT(user_data >> 8); opt_val[4] = VAL_WITH_COMPLEMENT(protection); opt_val[5] = VAL_WITH_COMPLEMENT(protection >> 8); opt_val[6] = VAL_WITH_COMPLEMENT(protection >> 16); opt_val[7] = VAL_WITH_COMPLEMENT(protection >> 24); #undef VAL_WITH_COMPLEMENT /* Write bytes and check errors */ ret = stlink_write_option_bytes_f0(sl, STM32_F0_OPTION_BYTES_BASE, (uint8_t*)opt_val, sizeof(opt_val)); if (ret) return ret; ret = check_flash_error(sl); if (!ret) { ILOG("Wrote option bytes %#010x to %#010x!\n", option_cr, FLASH_OBR); } return ret; } /** * Read option control register F2 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_control_register_f2(stlink_t *sl, uint32_t *option_byte) { return stlink_read_debug32(sl, FLASH_F2_OPT_CR, option_byte); } /** * Read option bytes F2 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_bytes_f2(stlink_t *sl, uint32_t *option_byte) { return stlink_read_option_control_register_f2(sl, option_byte); } /** * Read option control register F4 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_control_register_f4(stlink_t *sl, uint32_t *option_byte) { return stlink_read_debug32(sl, FLASH_F4_OPTCR, option_byte); } /** * Read option bytes F4 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_bytes_f4(stlink_t *sl, uint32_t *option_byte) { return stlink_read_option_control_register_f4(sl, option_byte); } /** * Write option bytes F4 * @param sl * @param addr of the memory mapped option bytes * @param base option bytes * @param len of option bytes * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_bytes_f4(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) { uint32_t option_byte; int32_t ret = 0; (void)addr; (void)len; // Clear errors clear_flash_error(sl); write_uint32((unsigned char *)&option_byte, *(uint32_t *)(base)); // write option byte, ensuring we dont lock opt, and set strt bit stlink_write_debug32(sl, FLASH_F4_OPTCR, (option_byte & ~(1 << FLASH_F4_OPTCR_LOCK)) | (1 << FLASH_F4_OPTCR_START)); wait_flash_busy(sl); ret = check_flash_error(sl); // option bytes are reloaded at reset only, no obl. */ return (ret); } /** * Read option bytes F7 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ // Since multiple bytes can be read, we read and print32_t all, but one here // and then return the last one just like other devices. int32_t stlink_read_option_bytes_f7(stlink_t *sl, uint32_t *option_byte) { int32_t err = -1; for (uint32_t counter = 0; counter < (sl->option_size / 4 - 1); counter++) { err = stlink_read_debug32(sl, sl->option_base + counter * sizeof(uint32_t), option_byte); if (err == -1) { return err; } else { printf("%08x\n", *option_byte); } } return stlink_read_debug32( sl, sl->option_base + (uint32_t)(sl->option_size / 4 - 1) * sizeof(uint32_t), option_byte); } /** * Write option bytes F7 * @param sl * @param addr of the memory mapped option bytes * @param base option bytes * @param len of option bytes * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_bytes_f7(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) { uint32_t option_byte; int32_t ret = 0; // Clear errors clear_flash_error(sl); ILOG("Asked to write option byte %#10x to %#010x.\n", *(uint32_t *)(base), addr); write_uint32((unsigned char *)&option_byte, *(uint32_t *)(base)); ILOG("Write %d option bytes %#010x to %#010x!\n", len, option_byte, addr); if (addr == 0) { addr = FLASH_F7_OPTCR; ILOG("No address provided, using %#10x\n", addr); } if (addr == FLASH_F7_OPTCR) { /* write option byte, ensuring we dont lock opt, and set strt bit */ stlink_write_debug32(sl, FLASH_F7_OPTCR, (option_byte & ~(1 << FLASH_F7_OPTCR_LOCK)) | (1 << FLASH_F7_OPTCR_START)); } else if (addr == FLASH_F7_OPTCR1) { // Read FLASH_F7_OPTCR uint32_t oldvalue; stlink_read_debug32(sl, FLASH_F7_OPTCR, &oldvalue); /* write option byte */ stlink_write_debug32(sl, FLASH_F7_OPTCR1, option_byte); // Write FLASH_F7_OPTCR lock and start address stlink_write_debug32(sl, FLASH_F7_OPTCR, (oldvalue & ~(1 << FLASH_F7_OPTCR_LOCK)) | (1 << FLASH_F7_OPTCR_START)); } else { WLOG("WIP: write %#010x to address %#010x\n", option_byte, addr); stlink_write_debug32(sl, addr, option_byte); } wait_flash_busy(sl); ret = check_flash_error(sl); if (!ret) ILOG("Wrote %d option bytes %#010x to %#010x!\n", len, *(uint32_t *)base, addr); /* option bytes are reloaded at reset only, no obl. */ return ret; } /** * Read option control register F7 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_control_register_f7(stlink_t *sl, uint32_t *option_byte) { DLOG("@@@@ Read option control register byte from %#10x\n", FLASH_F7_OPTCR); return stlink_read_debug32(sl, FLASH_F7_OPTCR, option_byte); } /** * Write option control register F7 * @param sl * @param option_cr * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_control_register_f7(stlink_t *sl, uint32_t option_cr) { int32_t ret = 0; // Clear errors clear_flash_error(sl); ILOG("Asked to write option control register 1 %#10x to %#010x.\n", option_cr, FLASH_F7_OPTCR); /* write option byte, ensuring we dont lock opt, and set strt bit */ stlink_write_debug32(sl, FLASH_F7_OPTCR, (option_cr & ~(1 << FLASH_F7_OPTCR_LOCK)) | (1 << FLASH_F7_OPTCR_START)); wait_flash_busy(sl); ret = check_flash_error(sl); if (!ret) ILOG("Wrote option bytes %#010x to %#010x!\n", option_cr, FLASH_F7_OPTCR); return ret; } /** * Read option control register1 F7 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_control_register1_f7(stlink_t *sl, uint32_t *option_byte) { DLOG("@@@@ Read option control register 1 byte from %#10x\n", FLASH_F7_OPTCR1); return stlink_read_debug32(sl, FLASH_F7_OPTCR1, option_byte); } /** * Write option control register1 F7 * @param sl * @param option_cr1 * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_control_register1_f7(stlink_t *sl, uint32_t option_cr1) { int32_t ret = 0; // Clear errors clear_flash_error(sl); ILOG("Asked to write option control register 1 %#010x to %#010x.\n", option_cr1, FLASH_F7_OPTCR1); /* write option byte, ensuring we dont lock opt, and set strt bit */ uint32_t current_control_register_value; stlink_read_debug32(sl, FLASH_F7_OPTCR, ¤t_control_register_value); /* write option byte */ stlink_write_debug32(sl, FLASH_F7_OPTCR1, option_cr1); stlink_write_debug32( sl, FLASH_F7_OPTCR, (current_control_register_value & ~(1 << FLASH_F7_OPTCR_LOCK)) | (1 << FLASH_F7_OPTCR_START)); wait_flash_busy(sl); ret = check_flash_error(sl); if (!ret) ILOG("Wrote option bytes %#010x to %#010x!\n", option_cr1, FLASH_F7_OPTCR1); return ret; } /** * Read option bytes boot address F7 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_bytes_boot_add_f7(stlink_t *sl, uint32_t *option_byte) { DLOG("@@@@ Read option byte boot address\n"); return stlink_read_option_control_register1_f7(sl, option_byte); } /** * Write option bytes boot address F7 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_bytes_boot_add_f7(stlink_t *sl, uint32_t option_byte_boot_add) { ILOG("Asked to write option byte boot add %#010x.\n", option_byte_boot_add); return stlink_write_option_control_register1_f7(sl, option_byte_boot_add); } /** * Read option control register Gx * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_control_register_gx(stlink_t *sl, uint32_t *option_byte) { return stlink_read_debug32(sl, FLASH_Gx_OPTR, option_byte); } /** * Read option bytes Gx * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_bytes_gx(stlink_t *sl, uint32_t *option_byte) { return stlink_read_option_control_register_gx(sl, option_byte); } /** * Write option bytes Gx * @param sl * @param addr of the memory mapped option bytes * @param base option bytes * @param len of option bytes * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_bytes_gx(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) { /* Write options bytes */ uint32_t val; int32_t ret = 0; (void)len; uint32_t data; clear_flash_error(sl); write_uint32((unsigned char *)&data, *(uint32_t *)(base)); WLOG("Writing option bytes %#10x to %#10x\n", data, addr); stlink_write_debug32(sl, FLASH_Gx_OPTR, data); // Set Options Start bit stlink_read_debug32(sl, FLASH_Gx_CR, &val); val |= (1 << FLASH_Gx_CR_OPTSTRT); stlink_write_debug32(sl, FLASH_Gx_CR, val); wait_flash_busy(sl); ret = check_flash_error(sl); // Reload options stlink_read_debug32(sl, FLASH_Gx_CR, &val); val |= (1 << FLASH_Gx_CR_OBL_LAUNCH); stlink_write_debug32(sl, FLASH_Gx_CR, val); return (ret); } /** * Write option bytes H7 * @param sl * @param addr of the memory mapped option bytes * @param base option bytes * @param len of option bytes * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_bytes_h7(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) { uint32_t val; uint32_t data; // Wait until previous flash option has completed wait_flash_busy(sl); // Clear previous error stlink_write_debug32(sl, FLASH_H7_OPTCCR, 1 << FLASH_H7_OPTCCR_CLR_OPTCHANGEERR); while (len != 0) { switch (addr) { case FLASH_H7_REGS_ADDR + 0x20: // FLASH_OPTSR_PRG case FLASH_H7_REGS_ADDR + 0x2c: // FLASH_PRAR_PRG1 case FLASH_H7_REGS_ADDR + 0x34: // FLASH_SCAR_PRG1 case FLASH_H7_REGS_ADDR + 0x3c: // FLASH_WPSN_PRG1 case FLASH_H7_REGS_ADDR + 0x44: // FLASH_BOOT_PRG /* Write to FLASH_xxx_PRG registers */ write_uint32((unsigned char *)&data, *(uint32_t *)(base)); // write options bytes WLOG("Writing option bytes %#10x to %#10x\n", data, addr); /* Skip if the value in the CUR register is identical */ stlink_read_debug32(sl, addr - 4, &val); if (val == data) { break; } /* Write new option byte values and start modification */ stlink_write_debug32(sl, addr, data); stlink_read_debug32(sl, FLASH_H7_OPTCR, &val); val |= (1 << FLASH_H7_OPTCR_OPTSTART); stlink_write_debug32(sl, FLASH_H7_OPTCR, val); /* Wait for the option bytes modification to complete */ do { stlink_read_debug32(sl, FLASH_H7_OPTSR_CUR, &val); } while ((val & (1 << FLASH_H7_OPTSR_OPT_BUSY)) != 0); /* Check for errors */ if ((val & (1 << FLASH_H7_OPTSR_OPTCHANGEERR)) != 0) { stlink_write_debug32(sl, FLASH_H7_OPTCCR, 1 << FLASH_H7_OPTCCR_CLR_OPTCHANGEERR); return -1; } break; default: /* Skip non-programmable registers */ break; } len -= 4; addr += 4; base += 4; } return 0; } /** * Write option bytes L0 * @param sl * @param addr of the memory mapped option bytes * @param base option bytes * @param len of option bytes * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_bytes_l0(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) { uint32_t flash_base = get_stm32l0_flash_base(sl); uint32_t val; uint32_t data; int32_t ret = 0; // Clear errors clear_flash_error(sl); while (len != 0) { write_uint32((unsigned char *)&data, *(uint32_t *)(base)); // write options bytes WLOG("Writing option bytes %#10x to %#10x\n", data, addr); stlink_write_debug32(sl, addr, data); wait_flash_busy(sl); if ((ret = check_flash_error(sl))) { break; } len -= 4; addr += 4; base += 4; } // Reload options stlink_read_debug32(sl, flash_base + FLASH_PECR_OFF, &val); val |= (1 << FLASH_L0_OBL_LAUNCH); stlink_write_debug32(sl, flash_base + FLASH_PECR_OFF, val); return (ret); } /** * Write option bytes L4 * @param sl * @param addr of the memory mapped option bytes * @param base option bytes * @param len of option bytes * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_bytes_l4(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) { uint32_t val; int32_t ret = 0; (void)addr; (void)len; // Clear errors clear_flash_error(sl); // write options bytes uint32_t data; write_uint32((unsigned char *)&data, *(uint32_t *)(base)); WLOG("Writing option bytes 0x%04x\n", data); stlink_write_debug32(sl, FLASH_L4_OPTR, data); // set options start bit stlink_read_debug32(sl, FLASH_L4_CR, &val); val |= (1 << FLASH_L4_CR_OPTSTRT); stlink_write_debug32(sl, FLASH_L4_CR, val); wait_flash_busy(sl); ret = check_flash_error(sl); // apply options bytes immediate stlink_read_debug32(sl, FLASH_L4_CR, &val); val |= (1 << FLASH_L4_CR_OBL_LAUNCH); stlink_write_debug32(sl, FLASH_L4_CR, val); return (ret); } /** * Write option bytes WB * @param sl * @param addr of the memory mapped option bytes * @param base option bytes * @param len of option bytes * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_bytes_wb(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) { /* Write options bytes */ uint32_t val; int32_t ret = 0; (void)len; uint32_t data; clear_flash_error(sl); while (len != 0) { write_uint32((unsigned char *)&data, *(uint32_t *)(base)); // write options bytes WLOG("Writing option bytes %#10x to %#10x\n", data, addr); stlink_write_debug32(sl, addr, data); wait_flash_busy(sl); if ((ret = check_flash_error(sl))) { break; } len -= 4; addr += 4; base += 4; } // Set Options Start bit stlink_read_debug32(sl, FLASH_WB_CR, &val); val |= (1 << FLASH_WB_CR_OPTSTRT); stlink_write_debug32(sl, FLASH_WB_CR, val); wait_flash_busy(sl); ret = check_flash_error(sl); // Reload options stlink_read_debug32(sl, FLASH_WB_CR, &val); val |= (1 << FLASH_WB_CR_OBL_LAUNCH); stlink_write_debug32(sl, FLASH_WB_CR, val); return (ret); } /** * Read option control register WB * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_control_register_wb(stlink_t *sl, uint32_t *option_byte) { DLOG("@@@@ Read option control register byte from %#10x\n", FLASH_WB_OPTR); return stlink_read_debug32(sl, FLASH_WB_OPTR, option_byte); } /** * Write option control register WB * @param sl * @param option_cr * @return 0 on success, -ve on failure. */ static int32_t stlink_write_option_control_register_wb(stlink_t *sl, uint32_t option_cr) { int32_t ret = 0; // Clear errors clear_flash_error(sl); ILOG("Asked to write option control register 1 %#10x to %#010x.\n", option_cr, FLASH_WB_OPTR); /* write option byte, ensuring we dont lock opt, and set strt bit */ stlink_write_debug32(sl, FLASH_WB_OPTR, option_cr); wait_flash_busy(sl); // Set Options Start bit uint32_t val = (1 << FLASH_WB_CR_OPTSTRT); stlink_write_debug32(sl, FLASH_WB_CR, val); wait_flash_busy(sl); ret = check_flash_error(sl); if (!ret) ILOG("Wrote option bytes %#010x to %#010x!\n", option_cr, FLASH_WB_OPTR); return ret; } /** * Read option bytes generic * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_bytes_generic(stlink_t *sl, uint32_t *option_byte) { DLOG("@@@@ Read option bytes boot address from %#10x\n", sl->option_base); return stlink_read_debug32(sl, sl->option_base, option_byte); } /** * Write option bytes * @param sl * @param addr of the memory mapped option bytes * @param base option bytes * @param len of option bytes * @return 0 on success, -ve on failure. */ int32_t stlink_write_option_bytes(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len) { int32_t ret = -1; if (sl->option_base == 0) { ELOG("Option bytes writing is currently not supported for connected chip\n"); return (-1); } if ((addr < sl->option_base) || addr > sl->option_base + sl->option_size) { ELOG("Option bytes start address out of Option bytes range\n"); return (-1); } if (addr + len > sl->option_base + sl->option_size) { ELOG("Option bytes data too long\n"); return (-1); } wait_flash_busy(sl); if (unlock_flash_if(sl)) { ELOG("Flash unlock failed! System reset required to be able to unlock it again!\n"); return (-1); } if (unlock_flash_option_if(sl)) { ELOG("Flash option unlock failed!\n"); return (-1); } switch (sl->flash_type) { case STM32_FLASH_TYPE_C0: ret = stlink_write_option_bytes_c0(sl, addr, base, len); break; case STM32_FLASH_TYPE_F0_F1_F3: case STM32_FLASH_TYPE_F1_XL: ret = stlink_write_option_bytes_f0(sl, addr, base, len); break; case STM32_FLASH_TYPE_F2_F4: ret = stlink_write_option_bytes_f4(sl, addr, base, len); break; case STM32_FLASH_TYPE_F7: ret = stlink_write_option_bytes_f7(sl, addr, base, len); break; case STM32_FLASH_TYPE_L0_L1: ret = stlink_write_option_bytes_l0(sl, addr, base, len); break; case STM32_FLASH_TYPE_L4: ret = stlink_write_option_bytes_l4(sl, addr, base, len); break; case STM32_FLASH_TYPE_G0: case STM32_FLASH_TYPE_G4: ret = stlink_write_option_bytes_gx(sl, addr, base, len); break; case STM32_FLASH_TYPE_H7: ret = stlink_write_option_bytes_h7(sl, addr, base, len); break; case STM32_FLASH_TYPE_WB_WL: ret = stlink_write_option_bytes_wb(sl, addr, base, len); break; default: ELOG("Option bytes writing is currently not implemented for connected chip\n"); break; } if (ret) { ELOG("Flash option write failed!\n"); } else { ILOG("Wrote %d option bytes to %#010x!\n", len, addr); } /* Re-lock flash. */ lock_flash_option(sl); lock_flash(sl); return ret; } /** * Write the given binary file with option bytes * @param sl * @param path readable file path, should be binary image * @param addr of the memory mapped option bytes * @return 0 on success, -ve on failure. */ int32_t stlink_fwrite_option_bytes(stlink_t *sl, const char *path, stm32_addr_t addr) { /* Write the file in flash at addr */ int32_t err; mapped_file_t mf = MAPPED_FILE_INITIALIZER; if (map_file(&mf, path) == -1) { ELOG("map_file() == -1\n"); return (-1); } printf("file %s ", path); md5_calculate(&mf); stlink_checksum(&mf); err = stlink_write_option_bytes(sl, addr, mf.base, (uint32_t)mf.len); stlink_fwrite_finalize(sl, addr); unmap_file(&mf); return (err); } /** * Read option control register 32 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_control_register32(stlink_t *sl, uint32_t *option_byte) { if (sl->option_base == 0) { ELOG("Option bytes read is currently not supported for connected chip\n"); return -1; } switch (sl->flash_type) { case STM32_FLASH_TYPE_C0: return stlink_read_option_control_register_c0(sl, option_byte); case STM32_FLASH_TYPE_F0_F1_F3: case STM32_FLASH_TYPE_F1_XL: return stlink_read_option_control_register_f0(sl, option_byte); case STM32_FLASH_TYPE_F7: return stlink_read_option_control_register_f7(sl, option_byte); case STM32_FLASH_TYPE_WB_WL: return stlink_read_option_control_register_wb(sl, option_byte); default: return -1; } } /** * Write option control register 32 * @param sl * @param option_cr * @return 0 on success, -ve on failure. */ int32_t stlink_write_option_control_register32(stlink_t *sl, uint32_t option_cr) { int32_t ret = -1; wait_flash_busy(sl); if (unlock_flash_if(sl)) { ELOG("Flash unlock failed! System reset required to be able to unlock it again!\n"); return -1; } if (unlock_flash_option_if(sl)) { ELOG("Flash option unlock failed!\n"); return -1; } switch (sl->flash_type) { case STM32_FLASH_TYPE_C0: ret = stlink_write_option_control_register_c0(sl, option_cr); break; case STM32_FLASH_TYPE_F0_F1_F3: case STM32_FLASH_TYPE_F1_XL: ret = stlink_write_option_control_register_f0(sl, option_cr); break; case STM32_FLASH_TYPE_F7: ret = stlink_write_option_control_register_f7(sl, option_cr); break; case STM32_FLASH_TYPE_WB_WL: ret = stlink_write_option_control_register_wb(sl, option_cr); break; default: ELOG("Option control register writing is currently not implemented for connected chip\n"); break; } if (ret) ELOG("Flash option write failed!\n"); else ILOG("Wrote option control register %#010x!\n", option_cr); /* Re-lock flash. */ lock_flash_option(sl); lock_flash(sl); return ret; } /** * Read option control register1 32 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_control_register1_32(stlink_t *sl, uint32_t *option_byte) { if (sl->option_base == 0) { ELOG("Option bytes read is currently not supported for connected chip\n"); return -1; } switch (sl->flash_type) { case STM32_FLASH_TYPE_F7: return stlink_read_option_control_register1_f7(sl, option_byte); default: return -1; // return stlink_read_option_control_register1_generic(sl, option_byte); } } /** * Write option control register1 32 * @param sl * @param option_cr * @return 0 on success, -ve on failure. */ int32_t stlink_write_option_control_register1_32(stlink_t *sl, uint32_t option_cr1) { int32_t ret = -1; wait_flash_busy(sl); if (unlock_flash_if(sl)) { ELOG("Flash unlock failed! System reset required to be able to unlock it again!\n"); return -1; } if (unlock_flash_option_if(sl)) { ELOG("Flash option unlock failed!\n"); return -1; } switch (sl->flash_type) { case STM32_FLASH_TYPE_F7: ret = stlink_write_option_control_register1_f7(sl, option_cr1); break; default: ELOG("Option control register 1 writing is currently not implemented for " "connected chip\n"); break; } if (ret) ELOG("Flash option write failed!\n"); else ILOG("Wrote option control register 1 %#010x!\n", option_cr1); lock_flash_option(sl); lock_flash(sl); return (ret); } /** * Read option bytes 32 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_bytes32(stlink_t *sl, uint32_t *option_byte) { if (sl->option_base == 0) { ELOG("Option bytes read is currently not supported for connected chip\n"); return (-1); } switch (sl->chip_id) { case STM32_CHIPID_C011xx: case STM32_CHIPID_C031xx: return stlink_read_option_bytes_c0(sl, option_byte); case STM32_CHIPID_F2: return stlink_read_option_bytes_f2(sl, option_byte); case STM32_CHIPID_F4: case STM32_CHIPID_F446: return stlink_read_option_bytes_f4(sl, option_byte); case STM32_CHIPID_F76xxx: return stlink_read_option_bytes_f7(sl, option_byte); case STM32_CHIPID_G0_CAT1: case STM32_CHIPID_G0_CAT2: case STM32_CHIPID_G4_CAT2: case STM32_CHIPID_G4_CAT3: case STM32_CHIPID_G4_CAT4: return stlink_read_option_bytes_gx(sl, option_byte); default: return stlink_read_option_bytes_generic(sl, option_byte); } } /** * Write option bytes 32 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_write_option_bytes32(stlink_t *sl, uint32_t option_byte) { WLOG("About to write option byte %#10x to %#10x.\n", option_byte, sl->option_base); return stlink_write_option_bytes(sl, sl->option_base, (uint8_t *)&option_byte, 4); } /** * Read option bytes boot address 32 * @param sl * @param option_byte * @return 0 on success, -ve on failure. */ int32_t stlink_read_option_bytes_boot_add32(stlink_t *sl, uint32_t *option_byte) { if (sl->option_base == 0) { ELOG("Option bytes boot address read is currently not supported for connected chip\n"); return -1; } switch (sl->flash_type) { case STM32_FLASH_TYPE_F7: return stlink_read_option_bytes_boot_add_f7(sl, option_byte); default: return -1; // return stlink_read_option_bytes_boot_add_generic(sl, option_byte); } } /** * Write option bytes boot address 32 * @param sl * @param option_bytes_boot_add * @return 0 on success, -ve on failure. */ int32_t stlink_write_option_bytes_boot_add32(stlink_t *sl, uint32_t option_bytes_boot_add) { int32_t ret = -1; wait_flash_busy(sl); if (unlock_flash_if(sl)) { ELOG("Flash unlock failed! System reset required to be able to unlock it again!\n"); return -1; } if (unlock_flash_option_if(sl)) { ELOG("Flash option unlock failed!\n"); return -1; } switch (sl->flash_type) { case STM32_FLASH_TYPE_F7: ret = stlink_write_option_bytes_boot_add_f7(sl, option_bytes_boot_add); break; default: ELOG("Option bytes boot address writing is currently not implemented for connected chip\n"); break; } if (ret) ELOG("Flash option write failed!\n"); else ILOG("Wrote option bytes boot address %#010x!\n", option_bytes_boot_add); /* Re-lock flash. */ lock_flash_option(sl); lock_flash(sl); return ret; } stlink-1.8.0/src/stlink-lib/option_bytes.h000066400000000000000000000065331455655054600206000ustar00rootroot00000000000000/* * File: option_bytes.h * * Read and write option bytes and option control registers */ #ifndef OPTION_BYTES_H #define OPTION_BYTES_H int32_t stlink_read_option_control_register_f0(stlink_t *sl, uint32_t *option_byte); // static int32_t stlink_write_option_bytes_f0(stlink_t *sl, stm32_addr_t addr, uint8_t* base, uint32_t len); // static int32_t stlink_write_option_control_register_f0(stlink_t *sl, uint32_t option_cr); int32_t stlink_read_option_control_register_f2(stlink_t *sl, uint32_t *option_byte); int32_t stlink_read_option_bytes_f2(stlink_t *sl, uint32_t *option_byte); int32_t stlink_read_option_control_register_f4(stlink_t *sl, uint32_t *option_byte); int32_t stlink_read_option_bytes_f4(stlink_t *sl, uint32_t *option_byte); // static int32_t stlink_write_option_bytes_f4(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len); int32_t stlink_read_option_bytes_f7(stlink_t *sl, uint32_t *option_byte); // static int32_t stlink_write_option_bytes_f7(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len); int32_t stlink_read_option_control_register_f7(stlink_t *sl, uint32_t *option_byte); // static int32_t stlink_write_option_control_register_f7(stlink_t *sl, uint32_t option_cr); int32_t stlink_read_option_control_register1_f7(stlink_t *sl, uint32_t *option_byte); // static int32_t stlink_write_option_control_register1_f7(stlink_t *sl, uint32_t option_cr1); int32_t stlink_read_option_bytes_boot_add_f7(stlink_t *sl, uint32_t *option_byte); // static int32_t stlink_write_option_bytes_boot_add_f7(stlink_t *sl, uint32_t option_byte_boot_add); int32_t stlink_read_option_control_register_gx(stlink_t *sl, uint32_t *option_byte); int32_t stlink_read_option_bytes_gx(stlink_t *sl, uint32_t *option_byte); // static int32_t stlink_write_option_bytes_gx(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len); // static int32_t stlink_write_option_bytes_h7(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len); // static int32_t stlink_write_option_bytes_l0(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len); // static int32_t stlink_write_option_bytes_l4(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len); // static int32_t stlink_write_option_bytes_wb(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len); int32_t stlink_read_option_control_register_wb(stlink_t *sl, uint32_t *option_byte); // static int32_t stlink_write_option_control_register_wb(stlink_t *sl, uint32_t option_cr); int32_t stlink_read_option_bytes_generic(stlink_t *sl, uint32_t *option_byte); int32_t stlink_write_option_bytes(stlink_t *sl, stm32_addr_t addr, uint8_t *base, uint32_t len); int32_t stlink_fwrite_option_bytes(stlink_t *sl, const char *path, stm32_addr_t addr); int32_t stlink_read_option_control_register32(stlink_t *sl, uint32_t *option_byte); int32_t stlink_write_option_control_register32(stlink_t *sl, uint32_t option_cr); int32_t stlink_read_option_control_register1_32(stlink_t *sl, uint32_t *option_byte); int32_t stlink_write_option_control_register1_32(stlink_t *sl, uint32_t option_cr1); int32_t stlink_read_option_bytes32(stlink_t *sl, uint32_t* option_byte); int32_t stlink_write_option_bytes32(stlink_t *sl, uint32_t option_byte); int32_t stlink_read_option_bytes_boot_add32(stlink_t *sl, uint32_t* option_byte); int32_t stlink_write_option_bytes_boot_add32(stlink_t *sl, uint32_t option_bytes_boot_add); #endif // OPTION_BYTES_H stlink-1.8.0/src/stlink-lib/read_write.c000066400000000000000000000106211455655054600201730ustar00rootroot00000000000000/* * File: read_write.c * * Read and write operations */ #include #include #include #include #include "read_write.h" #include "logging.h" // Endianness // https://commandcenter.blogspot.com/2012/04/byte-order-fallacy.html // These functions encode and decode little endian uint16 and uint32 values. uint16_t read_uint16(const unsigned char *c, const int32_t pt) { return ((uint16_t)c[pt]) | ((uint16_t)c[pt + 1] << 8); } void write_uint16(unsigned char *buf, uint16_t ui) { buf[0] = (uint8_t)ui; buf[1] = (uint8_t)(ui >> 8); } uint32_t read_uint32(const unsigned char *c, const int32_t pt) { return ((uint32_t)c[pt]) | ((uint32_t)c[pt + 1] << 8) | ((uint32_t)c[pt + 2] << 16) | ((uint32_t)c[pt + 3] << 24); } void write_uint32(unsigned char *buf, uint32_t ui) { buf[0] = ui; buf[1] = ui >> 8; buf[2] = ui >> 16; buf[3] = ui >> 24; } int32_t stlink_read_debug32(stlink_t *sl, uint32_t addr, uint32_t *data) { int32_t ret; ret = sl->backend->read_debug32(sl, addr, data); if (!ret) DLOG("*** stlink_read_debug32 %#010x at %#010x\n", *data, addr); return (ret); } int32_t stlink_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data) { DLOG("*** stlink_write_debug32 %#010x to %#010x\n", data, addr); return sl->backend->write_debug32(sl, addr, data); } int32_t stlink_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len) { DLOG("*** stlink_read_mem32 ***\n"); if (len % 4 != 0) { // !!! never ever: fw gives just wrong values ELOG("Data length doesn't have a 32 bit alignment: +%d byte.\n", len % 4); return (-1); } return (sl->backend->read_mem32(sl, addr, len)); } int32_t stlink_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len) { DLOG("*** stlink_write_mem32 %u bytes to %#x\n", len, addr); if (len % 4 != 0) { ELOG("Data length doesn't have a 32 bit alignment: +%d byte.\n", len % 4); return (-1); } return (sl->backend->write_mem32(sl, addr, len)); } int32_t stlink_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len) { DLOG("*** stlink_write_mem8 ***\n"); return (sl->backend->write_mem8(sl, addr, len)); } int32_t stlink_read_reg(stlink_t *sl, int32_t r_idx, struct stlink_reg *regp) { DLOG("*** stlink_read_reg\n"); DLOG(" (%d) ***\n", r_idx); if (r_idx > 20 || r_idx < 0) { fprintf(stderr, "Error: register index must be in [0..20]\n"); return (-1); } return (sl->backend->read_reg(sl, r_idx, regp)); } int32_t stlink_write_reg(stlink_t *sl, uint32_t reg, int32_t idx) { DLOG("*** stlink_write_reg\n"); return (sl->backend->write_reg(sl, reg, idx)); } int32_t stlink_read_unsupported_reg(stlink_t *sl, int32_t r_idx, struct stlink_reg *regp) { int32_t r_convert; DLOG("*** stlink_read_unsupported_reg\n"); DLOG(" (%d) ***\n", r_idx); /* Convert to values used by STLINK_REG_DCRSR */ if (r_idx >= 0x1C && r_idx <= 0x1F) { // primask, basepri, faultmask, or control r_convert = 0x14; } else if (r_idx == 0x40) { // FPSCR r_convert = 0x21; } else if (r_idx >= 0x20 && r_idx < 0x40) { r_convert = 0x40 + (r_idx - 0x20); } else { fprintf(stderr, "Error: register address must be in [0x1C..0x40]\n"); return (-1); } return (sl->backend->read_unsupported_reg(sl, r_convert, regp)); } int32_t stlink_write_unsupported_reg(stlink_t *sl, uint32_t val, int32_t r_idx, struct stlink_reg *regp) { int32_t r_convert; DLOG("*** stlink_write_unsupported_reg\n"); DLOG(" (%d) ***\n", r_idx); /* Convert to values used by STLINK_REG_DCRSR */ if (r_idx >= 0x1C && r_idx <= 0x1F) { /* primask, basepri, faultmask, or control */ r_convert = r_idx; // the backend function handles this } else if (r_idx == 0x40) { // FPSCR r_convert = 0x21; } else if (r_idx >= 0x20 && r_idx < 0x40) { r_convert = 0x40 + (r_idx - 0x20); } else { fprintf(stderr, "Error: register address must be in [0x1C..0x40]\n"); return (-1); } return (sl->backend->write_unsupported_reg(sl, val, r_convert, regp)); } int32_t stlink_read_all_regs(stlink_t *sl, struct stlink_reg *regp) { DLOG("*** stlink_read_all_regs ***\n"); return (sl->backend->read_all_regs(sl, regp)); } int32_t stlink_read_all_unsupported_regs(stlink_t *sl, struct stlink_reg *regp) { DLOG("*** stlink_read_all_unsupported_regs ***\n"); return (sl->backend->read_all_unsupported_regs(sl, regp)); } stlink-1.8.0/src/stlink-lib/read_write.h000066400000000000000000000023001455655054600201730ustar00rootroot00000000000000/* * File: read_write.h * * Read and write operations */ #ifndef READ_WRITE_H #define READ_WRITE_H uint16_t read_uint16(const unsigned char *c, const int32_t pt); void write_uint16(unsigned char *buf, uint16_t ui); uint32_t read_uint32(const unsigned char *c, const int32_t pt); void write_uint32(unsigned char *buf, uint32_t ui); int32_t stlink_read_debug32(stlink_t *sl, uint32_t addr, uint32_t *data); int32_t stlink_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data); int32_t stlink_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len); int32_t stlink_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len); int32_t stlink_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len); int32_t stlink_read_reg(stlink_t *sl, int32_t r_idx, struct stlink_reg *regp); int32_t stlink_write_reg(stlink_t *sl, uint32_t reg, int32_t idx); int32_t stlink_read_unsupported_reg(stlink_t *sl, int32_t r_idx, struct stlink_reg *regp); int32_t stlink_write_unsupported_reg(stlink_t *sl, uint32_t value, int32_t r_idx, struct stlink_reg *regp); int32_t stlink_read_all_regs(stlink_t *sl, struct stlink_reg *regp); int32_t stlink_read_all_unsupported_regs(stlink_t *sl, struct stlink_reg *regp); #endif // READ_WRITE_H stlink-1.8.0/src/stlink-lib/register.h000066400000000000000000000143741455655054600177100ustar00rootroot00000000000000/* * File: register.h * * Common STM32 registers */ #ifndef REGISTER_H #define REGISTER_H #define STLINK_REG_CM3_CPUID 0xE000ED00 #define STLINK_REG_CMx_CPUID_PARTNO_CM0 0xC20 #define STLINK_REG_CMx_CPUID_PARTNO_CM0P 0xC60 #define STLINK_REG_CMx_CPUID_PARTNO_CM3 0xC23 #define STLINK_REG_CMx_CPUID_PARTNO_CM4 0xC24 #define STLINK_REG_CMx_CPUID_PARTNO_CM7 0xC27 #define STLINK_REG_CMx_CPUID_PARTNO_CM33 0xD21 #define STLINK_REG_CMx_CPUID_IMPL_ARM 0x41 #define STLINK_REG_CM3_FP_CTRL 0xE0002000 // Flash Patch Control Register #define STLINK_REG_CM3_FP_COMPn(n) (0xE0002008 + n*4) #define STLINK_REG_CM3_FP_CTRL_KEY (1 << 1) #define STLINK_REG_CM7_FP_LAR 0xE0000FB0 #define STLINK_REG_CM7_FP_LAR_KEY 0xC5ACCE55 #define STLINK_REG_CM3_DEMCR 0xE000EDFC #define STLINK_REG_CM3_DEMCR_TRCENA (1 << 24) #define STLINK_REG_CM3_DEMCR_VC_HARDERR (1 << 10) #define STLINK_REG_CM3_DEMCR_VC_BUSERR (1 << 8) #define STLINK_REG_CM3_DEMCR_VC_CORERESET (1 << 0) #define STLINK_REG_CM3_DWT_COMPn(n) (0xE0001020 + n*16) #define STLINK_REG_CM3_DWT_MASKn(n) (0xE0001024 + n*16) #define STLINK_REG_CM3_DWT_FUNn(n) (0xE0001028 + n*16) /* Cortex™-M3 Technical Reference Manual */ /* Configurable Fault Status Register */ #define STLINK_REG_CFSR 0xE000ED28 /* Hard Fault Status Register */ #define STLINK_REG_HFSR 0xE000ED2C /* Debug Halting Control and Status Register */ #define STLINK_REG_DFSR 0xE000ED30 #define STLINK_REG_DFSR_HALT (1 << 0) #define STLINK_REG_DFSR_BKPT (1 << 1) #define STLINK_REG_DFSR_VCATCH (1 << 3) #define STLINK_REG_DFSR_EXTERNAL (1 << 4) #define STLINK_REG_DFSR_CLEAR 0x0000001F #define STLINK_REG_DHCSR 0xe000edf0 #define STLINK_REG_DHCSR_DBGKEY (0xA05F << 16) #define STLINK_REG_DHCSR_C_DEBUGEN (1 << 0) #define STLINK_REG_DHCSR_C_HALT (1 << 1) #define STLINK_REG_DHCSR_C_STEP (1 << 2) #define STLINK_REG_DHCSR_C_MASKINTS (1 << 3) #define STLINK_REG_DHCSR_S_REGRDY (1 << 16) #define STLINK_REG_DHCSR_S_HALT (1 << 17) #define STLINK_REG_DHCSR_S_SLEEP (1 << 18) #define STLINK_REG_DHCSR_S_LOCKUP (1 << 19) #define STLINK_REG_DHCSR_S_RETIRE_ST (1 << 24) #define STLINK_REG_DHCSR_S_RESET_ST (1 << 25) #define STLINK_REG_DCRSR 0xe000edf4 #define STLINK_REG_DCRDR 0xe000edf8 #define STLINK_REG_DEMCR 0xe000edfc #define STLINK_REG_DEMCR_TRCENA (1 << 24) /* MCU Debug Component Registers */ #define STLINK_REG_DBGMCU_CR 0xE0042004 // Debug MCU Configuration Register #define STLINK_REG_DBGMCU_CR_DBG_SLEEP (1 << 0) #define STLINK_REG_DBGMCU_CR_DBG_STOP (1 << 1) #define STLINK_REG_DBGMCU_CR_DBG_STANDBY (1 << 2) #define STLINK_REG_DBGMCU_CR_TRACE_IOEN (1 << 5) #define STLINK_REG_DBGMCU_CR_TRACE_MODE_ASYNC (0x00 << 6) /* Data Watchpoint and Trace (DWT) Registers */ #define STLINK_REG_DWT_CTRL 0xE0001000 // DWT Control Register #define STLINK_REG_DWT_CTRL_NUM_COMP (1 << 28) #define STLINK_REG_DWT_CTRL_CYC_TAP (1 << 9) #define STLINK_REG_DWT_CTRL_POST_INIT (1 << 5) #define STLINK_REG_DWT_CTRL_POST_PRESET (1 << 1) #define STLINK_REG_DWT_CTRL_CYCCNT_ENA (1 << 0) #define STLINK_REG_DWT_FUNCTION0 0xE0001028 // DWT Function Register 0 #define STLINK_REG_DWT_FUNCTION1 0xE0001038 // DWT Function Register 1 #define STLINK_REG_DWT_FUNCTION2 0xE0001048 // DWT Function Register 2 #define STLINK_REG_DWT_FUNCTION3 0xE0001058 // DWT Function Register 3 /* Instrumentation Trace Macrocell (ITM) Registers */ #define STLINK_REG_ITM_TER 0xE0000E00 // ITM Trace Enable Register #define STLINK_REG_ITM_TER_PORTS_ALL (0xFFFFFFFF) #define STLINK_REG_ITM_TPR 0xE0000E40 // ITM Trace Privilege Register #define STLINK_REG_ITM_TPR_PORTS_ALL (0x0F) #define STLINK_REG_ITM_TCR 0xE0000E80 // ITM Trace Control Register #define STLINK_REG_ITM_TCR_TRACE_BUS_ID_1 (0x01 << 16) #define STLINK_REG_ITM_TCR_SWO_ENA (1 << 4) #define STLINK_REG_ITM_TCR_DWT_ENA (1 << 3) #define STLINK_REG_ITM_TCR_SYNC_ENA (1 << 2) #define STLINK_REG_ITM_TCR_TS_ENA (1 << 1) #define STLINK_REG_ITM_TCR_ITM_ENA (1 << 0) #define STLINK_REG_ITM_TCC 0xE0000E90 // ITM Trace Cycle Count #define STLINK_REG_ITM_LAR 0xE0000FB0 // ITM Lock Access Register #define STLINK_REG_ITM_LAR_KEY 0xC5ACCE55 /* Trace Port Interface (TPI) Registers */ #define STLINK_REG_TPI_CSPSR 0xE0040004 // TPI Current Parallel Port Size Reg #define STLINK_REG_TPI_CSPSR_PORT_SIZE_1 (0x01 << 0) #define STLINK_REG_TPI_ACPR 0xE0040010 // TPI Async Clock Prescaler Register #define STLINK_REG_TPI_ACPR_MAX (0x1FFF) #define STLINK_REG_TPI_SPPR 0xE00400F0 // TPI Selected Pin Protocol Register #define STLINK_REG_TPI_SPPR_SWO_MANCHESTER (0x01 << 0) #define STLINK_REG_TPI_SPPR_SWO_NRZ (0x02 << 0) #define STLINK_REG_TPI_FFCR 0xE0040304 // TPI Formatter and Flush Control Register #define STLINK_REG_TPI_FFCR_TRIG_IN (0x01 << 8) /* Application Interrupt and Reset Control Register */ #define STLINK_REG_AIRCR 0xe000ed0c #define STLINK_REG_AIRCR_VECTKEY 0x05fa0000 #define STLINK_REG_AIRCR_SYSRESETREQ 0x00000004 #define STLINK_REG_AIRCR_VECTRESET 0x00000001 /* ARM Cortex-M7 Processor Technical Reference Manual */ /* Cache Control and Status Register */ #define STLINK_REG_CM7_CTR 0xE000ED7C #define STLINK_REG_CM7_CLIDR 0xE000ED78 #define STLINK_REG_CM7_CCR 0xE000ED14 #define STLINK_REG_CM7_CCR_DC (1 << 16) #define STLINK_REG_CM7_CCR_IC (1 << 17) #define STLINK_REG_CM7_CSSELR 0xE000ED84 #define STLINK_REG_CM7_DCCSW 0xE000EF6C #define STLINK_REG_CM7_ICIALLU 0xE000EF50 #define STLINK_REG_CM7_CCSIDR 0xE000ED80 #endif // REGISTER_H stlink-1.8.0/src/stlink-lib/sg.c000066400000000000000000001063571455655054600164730ustar00rootroot00000000000000/* == nightwalker-87: TODO: CONTENT AND USE OF THIS SOURCE FILE IS TO BE VERIFIED (07.06.2023) == */ /* * Copyright (c) 2010 "Capt'ns Missing Link" Authors. All rights reserved. * Use of this source code is governed by a BSD-style * 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). */ /* * File: sg.c * * */ #define __USE_GNU #include #include #include #include #include // #include // TODO: Check use #include "sg.h" #include "commands.h" #include "logging.h" #include "read_write.h" #include "register.h" #include "usb.h" // #include // TODO: Check use #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, STLINK_REG_AIRCR, STLINK_REG_AIRCR_VECTKEY | \ STLINK_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 }; 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.8.0/src/stlink-lib/sg.h000066400000000000000000000075731455655054600165000ustar00rootroot00000000000000/* == nightwalker-87: TODO: CONTENT AND USE OF THIS SOURCE FILE IS TO BE VERIFIED (07.06.2023) == */ /* * File: sg.h * * */ #ifndef SG_H #define SG_H #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_H stlink-1.8.0/src/stlink-lib/spdlog_wrapper.h000066400000000000000000000003161455655054600211030ustar00rootroot00000000000000#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.8.0/src/stlink-lib/usb.c000066400000000000000000001322041455655054600166410ustar00rootroot00000000000000/* * File: usb.c * * USB commands & interaction with ST-LINK devices */ #if !defined(_MSC_VER) #include #endif // _MSC_VER #if defined(_WIN32) #include #endif // _WIN32 #include #include #include #include #include #include #include #include #include #include "usb.h" #include "commands.h" #include "logging.h" #include "read_write.h" #include "register.h" static inline uint32_t le_to_h_u32(const uint8_t* buf) { return ((uint32_t)((uint32_t)buf[0] | (uint32_t)buf[1] << 8 | (uint32_t)buf[2] << 16 | (uint32_t)buf[3] << 24)); } 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->protocoll != 1 && check_error >= CMD_CHECK_STATUS && rxbuf[0] != STLINK_DEBUG_ERR_OK) { switch(rxbuf[0]) { case STLINK_DEBUG_ERR_AP_WAIT: case STLINK_DEBUG_ERR_DP_WAIT: if (check_error == CMD_CHECK_RETRY && retry < 3) { uint32_t delay_us = (1<protocoll == 1) && terminate) { // read the SG reply unsigned char sg_buf[13]; t = libusb_bulk_transfer(handle->usb_handle, handle->ep_rep, sg_buf, 13, &res, 3000); if (t) { ELOG("%s read storage failed: %s\n", cmd, libusb_error_name(t)); return (-1); } // The STLink doesn't seem to evaluate the sequence number. handle->sg_transfer_idx++; } return (res); } } static inline 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->protocoll == 1) { cmd[i++] = 'U'; cmd[i++] = 'S'; cmd[i++] = 'B'; cmd[i++] = 'C'; write_uint32(&cmd[i], slu->sg_transfer_idx); write_uint32(&cmd[i + 4], len); i += 8; cmd[i++] = (dir == SG_DXFER_FROM_DEV) ? 0x80 : 0; cmd[i++] = 0; // logical unit cmd[i++] = 0xa; // command length } return (i); } 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; 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; 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); 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); 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, STLINK_REG_DHCSR, &status); DLOG("core status: %08X\n", status); if (result != 0) { sl->core_stat = TARGET_UNKNOWN; } else { if (status & STLINK_REG_DHCSR_C_HALT) { sl->core_stat = TARGET_HALTED; } else if (status & STLINK_REG_DHCSR_S_RESET_ST) { sl->core_stat = TARGET_RESET; } else { sl->core_stat = TARGET_RUNNING; } } return (result); } int32_t _stlink_usb_status(stlink_t * sl) { if (sl->version.jtag_api != STLINK_JTAG_API_V1) { return (_stlink_usb_status_v2(sl)); } struct stlink_libusb * const slu = sl->backend_data; unsigned char* const data = sl->q_buf; unsigned char* const cmd = sl->c_buf; ssize_t size; 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, STLINK_REG_DHCSR, STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_HALT | STLINK_REG_DHCSR_C_DEBUGEN); return (res); } unsigned char* const data = sl->q_buf; unsigned char* const cmd = sl->c_buf; ssize_t size; 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) or V2 API (0x30). cmd[i++] = sl->version.jtag_api == STLINK_JTAG_API_V1 ? STLINK_DEBUG_APIV1_ENTER : STLINK_DEBUG_APIV2_ENTER; cmd[i++] = STLINK_DEBUG_ENTER_SWD; size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_RETRY, "ENTER_SWD"); return (size < 0 ? -1 : 0); } 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 { 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, STLINK_REG_DHCSR, STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_HALT | STLINK_REG_DHCSR_C_MASKINTS | STLINK_REG_DHCSR_C_DEBUGEN); _stlink_usb_write_debug32(sl, STLINK_REG_DHCSR, STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_STEP | STLINK_REG_DHCSR_C_MASKINTS | STLINK_REG_DHCSR_C_DEBUGEN); return _stlink_usb_write_debug32(sl, STLINK_REG_DHCSR, STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_HALT | STLINK_REG_DHCSR_C_DEBUGEN); } unsigned char* const data = sl->q_buf; unsigned char* const cmd = sl->c_buf; ssize_t size; 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, STLINK_REG_DHCSR, STLINK_REG_DHCSR_DBGKEY | STLINK_REG_DHCSR_C_DEBUGEN | ((type==RUN_FLASH_LOADER)?STLINK_REG_DHCSR_C_MASKINTS:0)); return (res); } unsigned char* const data = sl->q_buf; unsigned char* const cmd = sl->c_buf; ssize_t size; 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); 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 { cmd[i++] = STLINK_DEBUG_APIV2_READALLREGS; } size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_STATUS, "READALLREGS"); if (size < 0) { return (-1); } /* V1: regs data from offset 0 */ /* V2: status at offset 0, regs data from offset 4 */ 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 { cmd[i++] = STLINK_DEBUG_APIV2_READREG; } cmd[i++] = (uint8_t)r_idx; size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_RETRY, "READREG"); if (size < 0) { return (-1); } sl->q_len = (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, STLINK_REG_DCRSR, 4); if (ret == -1) { return (ret); } ret = _stlink_usb_read_mem32(sl, STLINK_REG_DCRDR, 4); if (ret == -1) { return (ret); } r = read_uint32(sl->q_buf, 0); DLOG("r_idx (%2d) = 0x%08x\n", r_idx, r); switch (r_idx) { case 0x14: regp->primask = (uint8_t)(r & 0xFF); regp->basepri = (uint8_t)((r >> 8) & 0xFF); regp->faultmask = (uint8_t)((r >> 16) & 0xFF); regp->control = (uint8_t)((r >> 24) & 0xFF); break; case 0x21: regp->fpscr = r; break; default: regp->s[r_idx - 0x40] = r; break; } return (0); } 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, STLINK_REG_DCRDR, 4); if (ret == -1) { return (ret); } sl->q_buf[0] = (unsigned char)r_idx; sl->q_buf[1] = 0; sl->q_buf[2] = 0x01; sl->q_buf[3] = 0; return (_stlink_usb_write_mem32(sl, STLINK_REG_DCRSR, 4)); } 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 { cmd[i++] = STLINK_DEBUG_APIV2_WRITEREG; } cmd[i++] = idx; write_uint32(&cmd[i], reg); size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len, CMD_CHECK_RETRY, "WRITEREG"); return (size < 0 ? -1 : 0); } 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 }; /* return the length of serial or (0) in case of errors */ size_t stlink_serial(struct libusb_device_handle *handle, struct libusb_device_descriptor *desc, char *serial) { unsigned char desc_serial[(STLINK_SERIAL_LENGTH) * 2]; /* truncate the string in the serial buffer */ serial[0] = '\0'; /* get the LANGID from String Descriptor Zero */ 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 strlen(serial); } /** * Open a stlink * @param verbose Verbosity loglevel * @param connect Type of connect to target * @param serial Serial number to search for, when NULL the first stlink found is opened (binary format) * @retval NULL Error while opening the stlink * @retval !NULL Stlink found and ready to use */ stlink_t *stlink_open_usb(enum ugly_loglevel verbose, enum connect_type connect, char serial[STLINK_SERIAL_BUFFER_SIZE], int32_t freq) { stlink_t* sl = NULL; struct stlink_libusb* slu = NULL; 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; } ugly_init(verbose); sl->backend = &_stlink_usb_backend; sl->backend_data = slu; sl->core_stat = TARGET_UNKNOWN; if (libusb_init(&(slu->libusb_ctx))) { WLOG("failed to init libusb context, wrong version of libraries?\n"); goto on_error; } #if LIBUSB_API_VERSION < 0x01000106 libusb_set_debug(slu->libusb_ctx, ugly_libusb_log_level(verbose)); #else libusb_set_option(slu->libusb_ctx, LIBUSB_OPTION_LOG_LEVEL, ugly_libusb_log_level(verbose)); #endif libusb_device **list = NULL; ssize_t cnt = libusb_get_device_list(slu->libusb_ctx, &list); struct libusb_device_descriptor desc; while (cnt-- > 0) { struct libusb_device_handle *handle; libusb_get_device_descriptor(list[cnt], &desc); if (desc.idVendor != STLINK_USB_VID_ST) { continue; } ret = libusb_open(list[cnt], &handle); if (ret) { continue; } // could not open device uint32_t serial_len = stlink_serial(handle, &desc, sl->serial); libusb_close(handle); if (serial_len != STLINK_SERIAL_LENGTH) { continue; } // could not read the serial // if no serial provided, or if serial match device, fixup version and protocol if (((serial == NULL) || (*serial == 0)) || (memcmp(serial, &sl->serial, STLINK_SERIAL_LENGTH) == 0)) { if (STLINK_V1_USB_PID(desc.idProduct)) { slu->protocoll = 1; sl->version.stlink_v = 1; } else if (STLINK_V2_USB_PID(desc.idProduct) || STLINK_V2_1_USB_PID(desc.idProduct)) { sl->version.stlink_v = 2; } else if (STLINK_V3_USB_PID(desc.idProduct)) { sl->version.stlink_v = 3; } break; } } if (cnt < 0) { WLOG ("Couldn't find any ST-Link devices\n"); libusb_free_device_list(list, 1); goto on_error; } else { ret = libusb_open(list[cnt], &slu->usb_handle); if (ret != 0) { WLOG("Error %d (%s) opening ST-Link v%d device %03d:%03d\n", ret, strerror(errno), sl->version.stlink_v, libusb_get_bus_number(list[cnt]), libusb_get_device_address(list[cnt])); libusb_free_device_list(list, 1); goto on_error; } } libusb_free_device_list(list, 1); // libusb_kernel_driver_active is not available on Windows. #if !defined(_WIN32) if (libusb_kernel_driver_active(slu->usb_handle, 0) == 1) { ret = libusb_detach_kernel_driver(slu->usb_handle, 0); if (ret < 0) { WLOG("libusb_detach_kernel_driver(() error %s\n", strerror(-ret)); goto on_libusb_error; } } #endif // 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) { slu->ep_req = 1 /* ep req */ | LIBUSB_ENDPOINT_OUT; slu->ep_trace = 2 | LIBUSB_ENDPOINT_IN; } else { slu->ep_req = 2 /* ep req */ | LIBUSB_ENDPOINT_OUT; slu->ep_trace = 3 | LIBUSB_ENDPOINT_IN; } slu->sg_transfer_idx = 0; slu->cmd_len = (slu->protocoll == 1) ? STLINK_SG_SIZE : STLINK_CMD_SIZE; // initialize stlink version (sl->version) stlink_version(sl); 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 1800kHz) DLOG("JTAG/SWD freq set to %d\n", freq); _stlink_usb_set_swdclk(sl, freq); stlink_target_connect(sl, connect); return (sl); on_libusb_error: stlink_close(sl); return (NULL); on_error: if (slu->libusb_ctx) { libusb_exit(slu->libusb_ctx); } on_malloc_error: if (sl != NULL) { free(sl); } if (slu != NULL) { free(slu); } return (NULL); } static 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); } /* Open STLINKS and attach them to list */ i = 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 (!STLINK_SUPPORTED_USB_PID(desc.idProduct)) { continue; } struct libusb_device_handle* handle; char serial[STLINK_SERIAL_BUFFER_SIZE] = {0, }; ret = libusb_open(dev, &handle); if (ret < 0) { if (ret == LIBUSB_ERROR_ACCESS) { ELOG("Could not open USB device %#06x:%#06x, access error.\n", desc.idVendor, desc.idProduct); } else { ELOG("Failed to open USB device %#06x:%#06x, libusb error: %d)\n", desc.idVendor, desc.idProduct, ret); } break; } uint32_t serial_len = stlink_serial(handle, &desc, serial); libusb_close(handle); if (serial_len != STLINK_SERIAL_LENGTH) { continue; } stlink_t *sl = stlink_open_usb(0, connect, serial, freq); if (!sl) { ELOG("Failed to open USB device %#06x:%#06x\n", desc.idVendor, desc.idProduct); continue; } _sldevs[slcur++] = sl; } *sldevs = _sldevs; return (slcur); } size_t stlink_probe_usb(stlink_t **stdevs[], enum connect_type connect, 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.8.0/src/stlink-lib/usb.h000066400000000000000000000122411455655054600166440ustar00rootroot00000000000000/* * File: usb.h * * USB commands & interaction with ST-LINK devices */ #ifndef USB_H #define USB_H #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_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) #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 protocoll; 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_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 = { }; size_t stlink_serial(struct libusb_device_handle *handle, struct libusb_device_descriptor *desc, char *serial); stlink_t *stlink_open_usb(enum ugly_loglevel verbose, enum connect_type connect, char serial[STLINK_SERIAL_BUFFER_SIZE], int32_t freq); // static uint32_t stlink_probe_usb_devs(libusb_device **devs, stlink_t **sldevs[], enum connect_type connect, int32_t freq); size_t stlink_probe_usb(stlink_t **stdevs[], enum connect_type connect, int32_t freq); void stlink_probe_usb_free(stlink_t **stdevs[], uint32_t size); #endif // USB_H stlink-1.8.0/src/win32/000077500000000000000000000000001455655054600145745ustar00rootroot00000000000000stlink-1.8.0/src/win32/getopt/000077500000000000000000000000001455655054600160765ustar00rootroot00000000000000stlink-1.8.0/src/win32/getopt/LICENSE.txt000066400000000000000000000027411455655054600177250ustar00rootroot00000000000000BSD 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.8.0/src/win32/getopt/README.md000066400000000000000000000017051455655054600173600ustar00rootroot00000000000000getopt_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.8.0/src/win32/getopt/getopt.c000066400000000000000000000164761455655054600175620ustar00rootroot00000000000000#include #include #include #include "getopt.h" #if !defined(_MSC_VER) const int32_t no_argument = 0; const int32_t required_argument = 1; const int32_t optional_argument = 2; #endif 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.8.0/src/win32/getopt/getopt.h000066400000000000000000000016261455655054600175560ustar00rootroot00000000000000#ifndef GETOPT_H #define GETOPT_H #include #if defined(__cplusplus) extern "C" { #endif #if defined(_MSC_VER) // These may be used to initialize structures and it fails with MSVC #define no_argument 0 #define required_argument 1 #define optional_argument 2 #else extern const int32_t no_argument; extern const int32_t required_argument; extern const int32_t optional_argument; #endif 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.8.0/src/win32/mmap.c000066400000000000000000000013721455655054600156750ustar00rootroot00000000000000#include #include #include #include #include #include "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; 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); (void)flags; } int32_t munmap (void *addr, uint32_t len) { free (addr); return (0); (void)len; } stlink-1.8.0/src/win32/mmap.h000066400000000000000000000007541455655054600157050ustar00rootroot00000000000000#ifndef MMAP_H #define MMAP_H #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 // MMAP_H stlink-1.8.0/src/win32/sys_time.c000066400000000000000000000015141455655054600165750ustar00rootroot00000000000000#include #include "sys_time.h" #ifndef STLINK_HAVE_SYS_TIME_H #include /* Simple gettimeofday implementation without converting Windows time to Linux time */ 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; tv->tv_sec = (int32_t)(ulint.QuadPart / 10000000L); tv->tv_usec = (int32_t)(ulint.QuadPart % 10000000L); } 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.8.0/src/win32/sys_time.h000066400000000000000000000005201455655054600165760ustar00rootroot00000000000000#ifndef SYS_TIME_H #define SYS_TIME_H #include #ifdef STLINK_HAVE_SYS_TIME_H #include #else #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.8.0/src/win32/unistd/000077500000000000000000000000001455655054600161025ustar00rootroot00000000000000stlink-1.8.0/src/win32/unistd/unistd.h000066400000000000000000000036411455655054600175650ustar00rootroot00000000000000#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) #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.8.0/src/win32/win32_socket.c000066400000000000000000000167511455655054600172640ustar00rootroot00000000000000#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, 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 // defined(_WIN32) stlink-1.8.0/src/win32/win32_socket.h000066400000000000000000000050151455655054600172600ustar00rootroot00000000000000#if defined(_WIN32) #include #define _USE_W32_SOCKETS 1 #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable: 4255 4668 4820) #endif #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, 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 // defined(_WIN32) stlink-1.8.0/tests/000077500000000000000000000000001455655054600142055ustar00rootroot00000000000000stlink-1.8.0/tests/CMakeLists.txt000066400000000000000000000012601455655054600167440ustar00rootroot00000000000000### # Build test executables ### set(TESTEXEC usb sg) set(TEST_DEPENDENCY ${STLINK_LIB_SHARED}) if (WIN32) set(TEST_DEPENDENCY ${STLINK_LIB_STATIC}) 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") 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.8.0/tests/flash.c000066400000000000000000000151761455655054600154600ustar00rootroot00000000000000/* == nightwalker-87: TODO: CONTENT AND USE OF THIS SOURCE FILE IS TO BE VERIFIED (07.06.2023) == */ #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 --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 } }, { "--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, .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.8.0/tests/sg.c000066400000000000000000000152431455655054600147670ustar00rootroot00000000000000/* == nightwalker-87: TODO: CONTENT AND USE OF THIS SOURCE FILE IS TO BE VERIFIED (07.06.2023) == */ #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.8.0/tests/usb.c000066400000000000000000000067771455655054600151630ustar00rootroot00000000000000/* == nightwalker-87: TODO: CONTENT AND USE OF THIS SOURCE FILE IS TO BE VERIFIED (07.06.2023) == */ #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, STLINK_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); }