+++ /dev/null
-# 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.
+++ /dev/null
-# 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}=="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.
+++ /dev/null
-# 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.
add_cflag_if_supported("-O2")
endif()
-set(HFILES src/stlink-common.h
- src/stlink-usb.h
- src/stlink-sg.h
- src/uglylogging.h
- src/mmap.h)
-
-set(CFILES src/stlink-common.c
- src/stlink-usb.c
- src/stlink-sg.c
- src/uglylogging.c
- )
+set(STLINK_HEADERS include/stlink.h
+ include/stlink/usb.h
+ include/stlink/sg.h
+ include/stlink/logging.h
+ include/stlink/mmap.h
+)
+
+set(STLINK_SOURCE src/common.c
+ src/usb.c
+ src/sg.c
+ src/logging.c
+)
include_directories(${LIBUSB_INCLUDE_DIR})
-include_directories(src)
-include_directories(mingw)
+include_directories(include)
+include_directories(src/mingw)
add_library(${PROJECT_NAME} STATIC
- ${HFILES} # header files for ide projects generated by cmake
- ${CFILES})
+ ${STLINK_HEADERS} # header files for ide projects generated by cmake
+ ${STLINK_SOURCE})
target_link_libraries(${PROJECT_NAME} ${LIBUSB_LIBRARIES})
-add_executable(st-flash flash/main.c)
+add_executable(st-flash src/tools/flash.c)
target_link_libraries(st-flash ${PROJECT_NAME})
-add_executable(st-info src/st-info.c)
+add_executable(st-info src/tools/info.c)
target_link_libraries(st-info ${PROJECT_NAME})
-add_executable(st-util gdbserver/gdb-remote.c
- gdbserver/gdb-remote.h
- gdbserver/gdb-server.c
- gdbserver/gdb-server.h)
+add_executable(st-util src/gdbserver/gdb-remote.c
+ src/gdbserver/gdb-remote.h
+ src/gdbserver/gdb-server.c
+ src/gdbserver/gdb-server.h)
target_link_libraries(st-util ${PROJECT_NAME})
install(TARGETS ${PROJECT_NAME} st-flash st-util st-info
)
if(NOT MINGW)
- list(APPEND CFILES src/st-term.c)
- add_executable(st-term src/st-term.c)
+ list(APPEND STLINK_SOURCE src/tools/term.c)
+ add_executable(st-term src/tools/term.c)
target_link_libraries(st-term ${PROJECT_NAME})
install(TARGETS st-term
noinst_LIBRARIES = libstlink.a
-st_flash_SOURCES = flash/main.c
-st_term_SOURCES = src/st-term.c
-st_info_SOURCES = src/st-info.c
-st_util_SOURCES = gdbserver/gdb-remote.c gdbserver/gdb-remote.h gdbserver/gdb-server.c mingw/mingw.c mingw/mingw.h
+st_flash_SOURCES = src/tools/flash.c
+st_term_SOURCES = src/tools/term.c
+st_info_SOURCES = src/tools/info.c
+st_util_SOURCES = src/gdbserver/gdb-remote.c src/gdbserver/gdb-remote.h src/gdbserver/gdb-server.c src/mingw/mingw.c src/mingw/mingw.h
CFILES = \
- src/stlink-common.c \
- src/stlink-usb.c \
- src/stlink-sg.c \
- src/uglylogging.c
+ src/common.c \
+ src/usb.c \
+ src/sg.c \
+ src/logging.c
if !MINGW
-CFILES += src/st-term.c
+CFILES += src/tools/term.c
endif
HFILES = \
- src/stlink-common.h \
- src/stlink-usb.h \
- src/stlink-sg.h \
- src/uglylogging.h \
- src/mmap.h
+ include/stlink.h \
+ include/stlink/usb.h \
+ include/stlink/sg.h \
+ include/stlink/logging.h \
+ include/stlink/mmap.h
libstlink_a_SOURCES = $(CFILES) $(HFILES)
-libstlink_a_CPPFLAGS = -std=gnu99 -Wall -Wextra -O2
libstlink_a_LIBADD = $(LIBOBJS)
+libstlink_a_CPPFLAGS = -std=gnu99 -Wall -Wextra -O2 -I$(top_srcdir)/include
st_flash_LDADD = libstlink.a
-st_flash_CPPFLAGS = -std=gnu99 -Wall -Wextra -O2 -I$(top_srcdir)/src -I$(top_srcdir)/mingw
+st_flash_CPPFLAGS = -std=gnu99 -Wall -Wextra -O2 -I$(top_srcdir)/include -I$(top_srcdir)/src/mingw
st_util_LDADD = libstlink.a
-st_util_CPPFLAGS = -std=gnu99 -Wall -Wextra -O2 -I$(top_srcdir)/src -I$(top_srcdir)/mingw
+st_util_CPPFLAGS = -std=gnu99 -Wall -Wextra -O2 -I$(top_srcdir)/include -I$(top_srcdir)/src/mingw
st_term_LDADD = libstlink.a
-st_term_CPPFLAGS = -std=gnu99 -Wall -Wextra -O2 -I$(top_srcdir)/src -I$(top_srcdir)/mingw
+st_term_CPPFLAGS = -std=gnu99 -Wall -Wextra -O2 -I$(top_srcdir)/include -I$(top_srcdir)/src/mingw
st_info_LDADD = libstlink.a
-st_info_CPPFLAGS = -std=gnu99 -Wall -Wextra -O2 -I$(top_srcdir)/src -I$(top_srcdir)/mingw
+st_info_CPPFLAGS = -std=gnu99 -Wall -Wextra -O2 -I$(top_srcdir)/include -I$(top_srcdir)/src/mingw
EXTRA_DIST = autogen.sh
+++ /dev/null
-README
\ No newline at end of file
+++ /dev/null
-. flash tool
- . improve flash writing, still use word fast write... too slow
-
-. documentation
- . make README points to doc/tutorial
-
-. compile and test a realtime kernel, for instance:
-http://www.chibios.org/dokuwiki/doku.php?id=chibios:articles:stm32l_discovery
-svn checkout https://chibios.svn.sourceforge.net/svnroot/chibios/trunk ;
-cd chibios/trunk/demos/ARMCM3-STM32L152-DISCOVERY ;
-make ;
--- /dev/null
+# flash tool
+
+- improve flash writing, still use word fast write... too slow
+
+# documentation
+
+- make README points to doc/tutorial
+
+# testing
+
+- compile and test a realtime kernel (e.g ChibiOS)
AC_PREREQ(2.61)
AC_INIT([stlink],[0.5.6],[davem@devkitpro.org])
-AC_CONFIG_SRCDIR([src/stlink-common.c])
+AC_CONFIG_SRCDIR([src/common.c])
AC_CONFIG_LIBOBJ_DIR([src])
AM_INIT_AUTOMAKE([1.10])
--- /dev/null
+Using STM32 discovery kits with open source tools
+========
+
+This guide details the use of STMicroelectronics STM32 discovery kits in an open source environment.
+
+Installing a GNU toolchain
+==========================
+
+Any toolchain supporting the cortex m3 should do. You can find the
+necessary to install such a toolchain here:
+
+```
+https://github.com/esden/summon-arm-toolchain
+```
+
+Details for the installation are provided in the topmost `README` file.
+This documentation assumes the toolchains is installed in a
+`$TOOLCHAIN_PATH`.
+
+Installing STLINK
+=================
+
+STLINK is open source software to program and debug ST’s STM32 Discovery
+kits. Those kits have an onboard chip that translates USB commands sent
+by the host PC into JTAG/SWD commands. This chip is called STLINK, (yes,
+isn’t that confusing? suggest a better name!) and comes in 2 versions
+(STLINK v1 and v2). From a software point of view, those versions differ
+only in the transport layer used to communicate (v1 uses SCSI passthru
+commands, while v2 uses raw USB). From a user point of view, they are
+identical.
+
+
+Before continuing, the following dependencies must be met:
+
+- libusb-1.0
+- pkg-config
+- autotools
+
+STLINK should run on any system meeting the above constraints.
+
+The STLINK software source code is retrieved using:
+
+```
+$> git clone https://github.com/texane/stlink stlink.git
+```
+
+Everything can be built from the top directory:
+
+```
+$> cd stlink.git
+$> ./autogen.sh
+$> ./configure
+$> make
+```
+
+It includes:
+
+- a communication library (stlink.git/libstlink.a),
+- a GDB server (stlink.git/st-util),
+- a flash manipulation tool (stlink.git/st-flash).
+
+Using the GDB server
+====================
+
+
+This assumes you have got the libopencm3 project downloaded in `ocm3`.
+The libopencm3 project 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. Depending on
+the discovery kit you are using, you must run one of the 2 commands:
+
+```
+# STM32VL discovery kit (onboard ST-link)
+$> ./st-util --stlinkv1
+
+# STM32L or STM32F4 discovery kit (onboard ST-link/V2)
+$> ./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.
+
+Building and flashing a program
+===============================
+
+If you want to simply flash binary files to arbitrary sections of
+memory, or read arbitary addresses of memory out to a binary file, use
+the st-flash tool, as shown below:
+
+```
+
+# stlinkv1 command to read 4096 from flash into out.bin
+$> ./st-flash read v1 out.bin 0x8000000 4096
+
+# stlinkv2 command
+$> ./st-flash read out.bin 0x8000000 4096
+
+# stlinkv1 command to write the file in.bin into flash
+$> ./st-flash write v1 in.bin 0x8000000
+
+# stlinkv2 command
+$> ./st-flash write in.bin 0x8000000
+```
+
+####
+
+Of course, you can use this instead of the gdb server, if you prefer.
+Just remember to use the “.bin” image, rather than the .elf file.
+
+```
+
+# write blink.bin into FLASH
+$> [sudo] ./st-flash write fancy_blink.bin 0x08000000
+```
+
+Upon reset, the board LEDs should be blinking.
+
+Notes
+=====
+
+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
+```
+
+References
+==========
+
+- <http://www.st.com/internet/mcu/product/248823.jsp>
+ documentation related to the STM32L mcu
+
+- <http://www.st.com/internet/evalboard/product/250990.jsp>
+ documentation related to the STM32L discovery kit
+
+- <http://www.libopencm3.org>
+ libopencm3, a project providing a firmware library, with solid
+ examples for Cortex M3, M4 and M0 processors from any vendor.
+++ /dev/null
-\documentclass[a4paper, 11pt]{article}
-
-\usepackage{graphicx}
-\usepackage{graphics}
-\usepackage{verbatim}
-\usepackage{listings}
-\usepackage{color}
-
-\begin{document}
-
-\title{Using STM32 discovery kits with open source tools}
-\author{STLINK development team}
-\date{}
-
-\maketitle
-
-\newpage
-\tableofcontents
-\addtocontents{toc}{\protect\setcounter{tocdepth}{1}}
-
-
-\newpage
-
-\section{Overview}
-\paragraph{}
-This guide details the use of STMicroelectronics STM32 discovery kits in
-an open source environment.
-
-
-\newpage
-
-\section{Installing a GNU toolchain}
-\paragraph{}
-Any toolchain supporting the cortex m3 should do. You can find the necessary
-to install such a toolchain here:\\
-\begin{small}
-\begin{lstlisting}[frame=tb]
-https://github.com/esden/summon-arm-toolchain
-\end{lstlisting}
-\end{small}
-
-\paragraph{}
-Details for the installation are provided in the topmost README file.
-This documentation assumes the toolchains is installed in a \$TOOLCHAIN\_PATH.
-
-
-\newpage
-
-\section{Installing STLINK}
-\paragraph{}
-STLINK is open source software to program and debug ST's STM32 Discovery kits. Those
-kits have an onboard chip that translates USB commands sent by the host PC into
-JTAG/SWD commands. This chip is called STLINK, (yes, isn't that confusing? suggest a better
-name!) and comes in 2 versions (STLINK v1 and v2). From a software
-point of view, those versions differ only in the transport layer used to communicate
-(v1 uses SCSI passthru commands, while v2 uses raw USB). From a user point of view, they
-are identical.
-
-\paragraph{}
-Before continuing, the following dependencies must be met:
-\begin{itemize}
-\item libusb-1.0
-\item pkg-config
-\item autotools
-\end{itemize}
-
-\paragraph{}
-STLINK should run on any system meeting the above constraints.
-
-\paragraph{}
-The STLINK software source code is retrieved using:\\
-\begin{small}
-\begin{lstlisting}[frame=tb]
-$> git clone https://github.com/texane/stlink stlink.git
-\end{lstlisting}
-\end{small}
-
-\paragraph{}
-Everything can be built from the top directory:\\
-\begin{small}
-\begin{lstlisting}[frame=tb]
-$> cd stlink.git
-$> ./autogen.sh
-$> ./configure
-$> make
-\end{lstlisting}
-\end{small}
-It includes:
-\begin{itemize}
-\item a communication library (stlink.git/libstlink.a),
-\item a GDB server (stlink.git/st-util),
-\item a flash manipulation tool (stlink.git/st-flash).
-\end{itemize}
-
-
-\newpage
-\section{Using the GDB server}
-\paragraph{}
-This assumes you have got the libopencm3 project downloaded in [ocm3]. The
-libopencm3 project 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:
-
-\begin{itemize}
-\item Your installed toolchain is capable of compiling for cortex M3/M4 targets
-\item stlink is functional
-\item Your arm-none-eabi-gdb is functional
-\item Your board is functional
-\end{itemize}
-
-\paragraph{}
-A GDB server must be started to interact with the STM32. Depending on the discovery kit you
-are using, you must run one of the 2 commands:\\
-\begin{small}
-\begin{lstlisting}[frame=tb]
-# STM32VL discovery kit (onboard ST-link)
-$> ./st-util --stlinkv1
-
-# STM32L or STM32F4 discovery kit (onboard ST-link/V2)
-$> ./st-util
-
-# Full help for other options (listen port, version)
-$> ./st-util --help
-\end{lstlisting}
-\end{small}
-
-\paragraph{}
-Then, GDB can be used to interact with the kit:\\
-\begin{small}
-\begin{lstlisting}[frame=tb]
-$> $TOOLCHAIN_PATH/bin/arm-none-eabi-gdb example_file.elf
-\end{lstlisting}
-\end{small}
-
-\paragraph{}
-From GDB, connect to the server using:\\
-\begin{small}
-\begin{lstlisting}[frame=tb]
-(gdb) target extended localhost:4242
-\end{lstlisting}
-\end{small}
-
-\paragraph{}
-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:\\
-\begin{small}
-\begin{lstlisting}[frame=tb]
-(gdb) load
-\end{lstlisting}
-\end{small}
-
-\paragraph{}
-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"\\
-\begin{small}
-\begin{lstlisting}[frame=tb]
-(gdb) continue
-\end{lstlisting}
-\end{small}
-
-\paragraph{}
-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.
-
-\newpage
-\section{Building and flashing a program}
-\paragraph{}
-If you want to simply flash binary files to arbitrary sections of memory, or
-read arbitary addresses of memory out to a binary file, use the st-flash tool,
-as shown below:\\
-\begin{small}
-\begin{lstlisting}[frame=tb]
-
-# stlinkv1 command to read 4096 from flash into out.bin
-$> ./st-flash read v1 out.bin 0x8000000 4096
-
-# stlinkv2 command
-$> ./st-flash read out.bin 0x8000000 4096
-
-# stlinkv1 command to write the file in.bin into flash
-$> ./st-flash write v1 in.bin 0x8000000
-
-# stlinkv2 command
-$> ./st-flash write in.bin 0x8000000
-\end{lstlisting}
-\end{small}
-
-\paragraph{}
-Of course, you can use this instead of the gdb server, if you prefer. Just remember
-to use the ".bin" image, rather than the .elf file.\\
-\begin{small}
-\begin{lstlisting}[frame=tb]
-
-# write blink.bin into FLASH
-$> [sudo] ./st-flash write fancy_blink.bin 0x08000000
-\end{lstlisting}
-\end{small}
-
-\paragraph{}
-Upon reset, the board LEDs should be blinking.
-
-\newpage
-\section{Notes}
-
-\subsection{Disassembling THUMB code in GDB}
-\paragraph{}
-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:\\
-\begin{small}
-\begin{lstlisting}[frame=tb]
-(gdb) disassemble 0x20000001
-\end{lstlisting}
-\end{small}
-
-
-\newpage
-\section{References}
-\begin{itemize}
-\item http://www.st.com/internet/mcu/product/248823.jsp\\
- documentation related to the STM32L mcu
-\item http://www.st.com/internet/evalboard/product/250990.jsp\\
- documentation related to the STM32L discovery kit
-\item http://www.libopencm3.org\\
- libopencm3, a project providing a firmware library, with solid examples for Cortex
- M3, M4 and M0 processors from any vendor.
-\end{itemize}
-
-\end{document}
--- /dev/null
+options usb-storage quirks=483:3744:i
--- /dev/null
+# 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.
--- /dev/null
+# 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}=="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.
--- /dev/null
+# 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.
+++ /dev/null
-CFLAGS+=-g
-CFLAGS+=-DDEBUG
-CFLAGS+=-std=gnu99
-CFLAGS+=-Wall -Wextra
-CFLAGS+=-I../src
-
-LDFLAGS=-L.. -lstlink
-
-# libusb location
-LDFLAGS+=`pkg-config --libs libusb-1.0`
-CFLAGS+=`pkg-config --cflags libusb-1.0`
-
-SRCS=main.c
-OBJS=$(SRCS:.c=.o)
-
-NAME=st-flash
-
-all: $(NAME)
-
-$(NAME): $(OBJS) ../libstlink.a
- $(CC) $(CFLAGS) -o $(NAME) $(OBJS) $(LDFLAGS)
-
-%.o: %.c
- $(CC) $(CFLAGS) -c $^ -o $@
-
-clean:
- rm -f $(OBJS)
- rm -f $(NAME)
-
-.PHONY: clean all
+++ /dev/null
-/* simple wrapper around the stlink_flash_write function */
-
-// TODO - this should be done as just a simple flag to the st-util command line...
-
-
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include "stlink-common.h"
-
-#define DEBUG_LOG_LEVEL 100
-#define STND_LOG_LEVEL 50
-
-stlink_t *connected_stlink = NULL;
-
-static void cleanup(int signal __attribute__((unused))) {
- if (connected_stlink) {
- /* Switch back to mass storage mode before closing. */
- stlink_run(connected_stlink);
- stlink_exit_debug_mode(connected_stlink);
- stlink_close(connected_stlink);
- }
-
- exit(1);
-}
-
-enum st_cmds {DO_WRITE = 0, DO_READ = 1, DO_ERASE = 2};
-struct opts
-{
- enum st_cmds cmd;
- const char* devname;
- char *serial;
- const char* filename;
- stm32_addr_t addr;
- size_t size;
- int reset;
- int log_level;
-};
-
-static void usage(void)
-{
- puts("stlinkv1 command line: ./st-flash [--debug] [--reset] [--serial <iSerial>] {read|write} /dev/sgX path addr <size>");
- puts("stlinkv1 command line: ./st-flash [--debug] /dev/sgX erase");
- puts("stlinkv2 command line: ./st-flash [--debug] [--reset] [--serial <iSerial>] {read|write} path addr <size>");
- puts("stlinkv2 command line: ./st-flash [--debug] [--serial <iSerial>] erase");
- puts(" use hex format for addr, <iSerial> and <size>");
-}
-
-static int get_opts(struct opts* o, int ac, char** av)
-{
- /* stlinkv1 command line: ./st-flash {read|write} /dev/sgX path addr <size> */
- /* stlinkv2 command line: ./st-flash {read|write} path addr <size> */
-
- unsigned int i = 0;
-
- if (ac < 1) return -1;
-
- if (strcmp(av[0], "--debug") == 0)
- {
- o->log_level = DEBUG_LOG_LEVEL;
- ac--;
- av++;
- }
- else
- {
- o->log_level = STND_LOG_LEVEL;
- }
-
- if (strcmp(av[0], "--reset") == 0)
- {
- o->reset = 1;
- ac--;
- av++;
- }
- else
- {
- o->reset = 0;
- }
-
- if (strcmp(av[0], "--serial") == 0)
- {
- ac--;
- av++;
- int i=strlen(av[0]);
- if(i%2 != 0){
- puts("no valid hex value, length must be multiple of 2\n");
- return -1;
- }
- int j=0;
- while(i>=0 && j<=13){
- char buffer[3]={0};
- memcpy(buffer,&av[0][i],2);
- o->serial[12-j] = (char)strtol((const char*)buffer,NULL, 16);
- j++;
- i-=2;
- }
- ac--;
- av++;
- }
- else
- {
- o->serial = NULL;
- }
-
- if (ac < 1) return -1;
-
- /* stlinkv2 */
- o->devname = NULL;
-
- if (strcmp(av[0], "erase") == 0)
- {
- o->cmd = DO_ERASE;
-
- /* stlinkv1 mode */
- if (ac == 2)
- {
- o->devname = av[1];
- i = 1;
- }
- }
- else {
- if (ac < 3) return -1;
- if (strcmp(av[0], "read") == 0)
- {
- o->cmd = DO_READ;
-
- /* stlinkv1 mode */
- if (ac == 5)
- {
- o->devname = av[1];
- i = 1;
- }
- if (ac > 3)
- o->size = strtoul(av[i + 3], NULL, 16);
- }
- else if (strcmp(av[0], "write") == 0)
- {
- o->cmd = DO_WRITE;
-
- /* stlinkv1 mode */
- if (ac == 4)
- {
- o->devname = av[1];
- i = 1;
- }
- }
- else
- {
- return -1;
- }
- }
-
- o->filename = av[i + 1];
- o->addr = strtoul(av[i + 2], NULL, 16);
-
- return 0;
-}
-
-
-int main(int ac, char** av)
-{
- stlink_t* sl = NULL;
- struct opts o;
- char serial_buffer[13] = {0};
- o.serial = serial_buffer;
- int err = -1;
-
- o.size = 0;
- if (get_opts(&o, ac - 1, av + 1) == -1)
- {
- printf("invalid command line\n");
- usage();
- return -1;
- }
-
- if (o.devname != NULL) /* stlinkv1 */
- sl = stlink_v1_open(o.log_level, 1);
- else /* stlinkv2 */
- sl = stlink_open_usb(o.log_level, 1, o.serial);
-
- if (sl == NULL)
- return -1;
-
- sl->verbose = o.log_level;
-
- connected_stlink = sl;
- signal(SIGINT, &cleanup);
- signal(SIGTERM, &cleanup);
- signal(SIGSEGV, &cleanup);
-
- if (stlink_current_mode(sl) == STLINK_DEV_DFU_MODE) {
- if (stlink_exit_dfu_mode(sl)) {
- printf("Failed to exit DFU mode\n");
- goto on_error;
- }
- }
-
- if (stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE) {
- if (stlink_enter_swd_mode(sl)) {
- printf("Failed to enter SWD mode\n");
- goto on_error;
- }
- }
-
- if (o.reset){
- if (stlink_jtag_reset(sl, 2)) {
- printf("Failed to reset JTAG\n");
- goto on_error;
- }
-
- if (stlink_reset(sl)) {
- printf("Failed to reset device\n");
- goto on_error;
- }
- }
-
- // Disable DMA - Set All DMA CCR Registers to zero. - AKS 1/7/2013
- if (sl->chip_id == STM32_CHIPID_F4)
- {
- memset(sl->q_buf,0,4);
- for (int i=0;i<8;i++) {
- stlink_write_mem32(sl,0x40026000+0x10+0x18*i,4);
- stlink_write_mem32(sl,0x40026400+0x10+0x18*i,4);
- stlink_write_mem32(sl,0x40026000+0x24+0x18*i,4);
- stlink_write_mem32(sl,0x40026400+0x24+0x18*i,4);
- }
- }
-
- // 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 == DO_WRITE) /* write */
- {
- if ((o.addr >= sl->flash_base) &&
- (o.addr < sl->flash_base + sl->flash_size)) {
- 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)) {
- err = stlink_fwrite_sram(sl, o.filename, o.addr);
- if (err == -1)
- {
- printf("stlink_fwrite_sram() == -1\n");
- goto on_error;
- }
- }
- } else if (o.cmd == DO_ERASE)
- {
- err = stlink_erase_flash_mass(sl);
- if (err == -1)
- {
- printf("stlink_erase_flash_mass() == -1\n");
- goto on_error;
- }
- }
- else /* read */
- {
- if ((o.addr >= sl->flash_base) && (o.size == 0) &&
- (o.addr < sl->flash_base + sl->flash_size))
- o.size = sl->flash_size;
- else if ((o.addr >= sl->sram_base) && (o.size == 0) &&
- (o.addr < sl->sram_base + sl->sram_size))
- o.size = sl->sram_size;
- err = stlink_fread(sl, o.filename, o.addr, o.size);
- if (err == -1)
- {
- printf("stlink_fread() == -1\n");
- goto on_error;
- }
- }
-
- if (o.reset){
- stlink_jtag_reset(sl,2);
- stlink_reset(sl);
- }
-
- /* success */
- err = 0;
-
-on_error:
- stlink_exit_debug_mode(sl);
- stlink_close(sl);
-
- return err;
-}
+++ /dev/null
-PRG := st-util
-OBJS = gdb-remote.o gdb-server.o
-
-CFLAGS+=-g -Wall -Werror -std=gnu99 -I../src
-LDFLAGS=-L.. -lstlink
-
-# libusb location
-LDFLAGS+=`pkg-config --libs libusb-1.0`
-CFLAGS+=`pkg-config --cflags libusb-1.0`
-
-all: $(PRG)
-
-$(PRG): $(OBJS) ../libstlink.a
- $(CC) -o $@ $^ $(LDFLAGS)
-
-clean:
- rm -rf $(OBJS)
- rm -rf $(PRG)
-
-.PHONY: clean all
+++ /dev/null
-/*
- * Copyright (C) 2011 Peter Zotov <whitequark@whitequark.org>
- * Use of this source code is governed by a BSD-style
- * license that can be found in the LICENSE file.
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdint.h>
-#ifdef __MINGW32__
-#include "mingw.h"
-#else
-#include <sys/poll.h>
-#endif
-
-static const char hex[] = "0123456789abcdef";
-
-int gdb_send_packet(int fd, char* data) {
- unsigned int data_length = strlen(data);
- int length = data_length + 4;
- char* packet = malloc(length); /* '$' data (hex) '#' cksum (hex) */
-
- memset(packet, 0, length);
-
- packet[0] = '$';
-
- uint8_t cksum = 0;
- for(unsigned int 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
-
-int gdb_recv_packet(int fd, char** buffer) {
- unsigned packet_size = ALLOC_STEP + 1, packet_idx = 0;
- uint8_t cksum = 0;
- char recv_cksum[3] = {0};
- char* packet_buffer = malloc(packet_size);
- unsigned state;
-
-start:
- state = 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) {
- 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;
- packet_buffer = realloc(packet_buffer, packet_size);
- }
- }
- 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) {
- return -2;
- }
-
- goto start;
- } else {
- char ack = '+';
- if(write(fd, &ack, 1) != 1) {
- 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.
-int gdb_check_for_interrupt(int 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') // ^C
- return 1;
- }
-
- return 0;
-}
-
+++ /dev/null
-#ifndef _GDB_REMOTE_H_
-#define _GDB_REMOTE_H_
-
-int gdb_send_packet(int fd, char* data);
-int gdb_recv_packet(int fd, char** buffer);
-int gdb_check_for_interrupt(int fd);
-
-#endif
+++ /dev/null
-/*
- * Copyright (C) 2011 Peter Zotov <whitequark@whitequark.org>
- * Use of this source code is governed by a BSD-style
- * license that can be found in the LICENSE file.
- */
-
-#include <getopt.h>
-#include <signal.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-#ifdef __MINGW32__
-#include "mingw.h"
-#else
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#endif
-
-#include <stlink-common.h>
-#include <uglylogging.h>
-
-#include "gdb-remote.h"
-#include "gdb-server.h"
-
-#define FLASH_BASE 0x08000000
-
-//Allways update the FLASH_PAGE before each use, by calling stlink_calculate_pagesize
-#define FLASH_PAGE (sl->flash_pgsz)
-
-stlink_t *connected_stlink = NULL;
-
-static const char hex[] = "0123456789abcdef";
-
-static const char* current_memory_map = NULL;
-
-typedef struct _st_state_t {
- // things from command line, bleh
- int stlink_version;
- int logging_level;
- int listen_port;
- int persistent;
- int reset;
-} st_state_t;
-
-
-int 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(int signal __attribute__((unused))) {
- if (connected_stlink) {
- /* Switch back to mass storage mode before closing. */
- stlink_run(connected_stlink);
- stlink_exit_debug_mode(connected_stlink);
- stlink_close(connected_stlink);
- }
-
- exit(1);
-}
-
-
-
-int parse_options(int argc, char** argv, st_state_t *st) {
- static struct option long_options[] = {
- {"help", no_argument, NULL, 'h'},
- {"verbose", optional_argument, NULL, 'v'},
- {"stlink_version", required_argument, NULL, 's'},
- {"stlinkv1", no_argument, NULL, '1'},
- {"listen_port", required_argument, NULL, 'p'},
- {"multi", optional_argument, NULL, 'm'},
- {"no-reset", optional_argument, NULL, 'n'},
- {0, 0, 0, 0},
- };
- const char * help_str = "%s - usage:\n\n"
- " -h, --help\t\tPrint this help\n"
- " -vXX, --verbose=XX\tSpecify a specific verbosity level (0..99)\n"
- " -v, --verbose\t\tSpecify generally verbose logging\n"
- " -s X, --stlink_version=X\n"
- "\t\t\tChoose what version of stlink to use, (defaults to 2)\n"
- " -1, --stlinkv1\tForce stlink version 1\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\n"
- "\t\t\tDo not reset board on connection.\n"
- "\n"
- "The STLINKv2 device to use can be specified in the environment\n"
- "variable STLINK_DEVICE on the format <USB_BUS>:<USB_ADDR>.\n"
- "\n"
- ;
-
-
- int option_index = 0;
- int c;
- int q;
- while ((c = getopt_long(argc, argv, "hv::s:1p:mn", long_options, &option_index)) != -1) {
- switch (c) {
- case 0:
- printf("XXXXX Shouldn't really normally come here, only if there's no corresponding option\n");
- printf("option %s", long_options[option_index].name);
- if (optarg) {
- printf(" with arg %s", optarg);
- }
- printf("\n");
- 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 = DEFAULT_LOGGING_LEVEL;
- }
- break;
- case '1':
- st->stlink_version = 1;
- break;
- case 's':
- sscanf(optarg, "%i", &q);
- if (q < 0 || q > 2) {
- fprintf(stderr, "stlink version %d unknown!\n", q);
- exit(EXIT_FAILURE);
- }
- st->stlink_version = q;
- break;
- case 'p':
- sscanf(optarg, "%i", &q);
- 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 = 1;
- break;
- case 'n':
- st->reset = 0;
- break;
- }
- }
-
- if (optind < argc) {
- printf("non-option ARGV-elements: ");
- while (optind < argc)
- printf("%s ", argv[optind++]);
- printf("\n");
- }
- return 0;
-}
-
-
-int main(int argc, char** argv) {
- int32_t voltage;
-
- stlink_t *sl = NULL;
-
- st_state_t state;
- memset(&state, 0, sizeof(state));
- // set defaults...
- state.stlink_version = 2;
- state.logging_level = DEFAULT_LOGGING_LEVEL;
- state.listen_port = DEFAULT_GDB_LISTEN_PORT;
- state.reset = 1; /* By default, reset board */
- parse_options(argc, argv, &state);
- switch (state.stlink_version) {
- case 2:
- sl = stlink_open_usb(state.logging_level, state.reset, NULL);
- if(sl == NULL) return 1;
- break;
- case 1:
- sl = stlink_v1_open(state.logging_level, state.reset);
- if(sl == NULL) return 1;
- break;
- }
-
- connected_stlink = sl;
- signal(SIGINT, &cleanup);
- signal(SIGTERM, &cleanup);
- signal(SIGSEGV, &cleanup);
-
- if (state.reset) {
- stlink_reset(sl);
- }
-
- ILOG("Chip ID is %08x, Core ID is %08x.\n", sl->chip_id, sl->core_id);
-
- voltage = stlink_target_voltage(sl);
- if (voltage != -1) {
- ILOG("Target voltage is %d mV.\n", voltage);
- }
-
- sl->verbose=0;
-
- current_memory_map = make_memory_map(sl);
-
-#ifdef __MINGW32__
- WSADATA wsadata;
- if (WSAStartup(MAKEWORD(2,2),&wsadata) !=0 ) {
- goto winsock_error;
- }
-#endif
-
- init_cache(sl);
-
- do {
- if (serve(sl, &state)) {
- sleep (1); // don't go bezurk if serve returns with error
- }
-
- /* Continue */
- stlink_run(sl);
- } while (state.persistent);
-
-#ifdef __MINGW32__
-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_F4 =
- "<?xml version=\"1.0\"?>"
- "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"
- "<target version=\"1.0\">"
- " <architecture>arm</architecture>"
- " <feature name=\"org.gnu.gdb.arm.m-profile\">"
- " <reg name=\"r0\" bitsize=\"32\"/>"
- " <reg name=\"r1\" bitsize=\"32\"/>"
- " <reg name=\"r2\" bitsize=\"32\"/>"
- " <reg name=\"r3\" bitsize=\"32\"/>"
- " <reg name=\"r4\" bitsize=\"32\"/>"
- " <reg name=\"r5\" bitsize=\"32\"/>"
- " <reg name=\"r6\" bitsize=\"32\"/>"
- " <reg name=\"r7\" bitsize=\"32\"/>"
- " <reg name=\"r8\" bitsize=\"32\"/>"
- " <reg name=\"r9\" bitsize=\"32\"/>"
- " <reg name=\"r10\" bitsize=\"32\"/>"
- " <reg name=\"r11\" bitsize=\"32\"/>"
- " <reg name=\"r12\" bitsize=\"32\"/>"
- " <reg name=\"sp\" bitsize=\"32\" type=\"data_ptr\"/>"
- " <reg name=\"lr\" bitsize=\"32\"/>"
- " <reg name=\"pc\" bitsize=\"32\" type=\"code_ptr\"/>"
- " <reg name=\"xpsr\" bitsize=\"32\" regnum=\"25\"/>"
- " <reg name=\"msp\" bitsize=\"32\" regnum=\"26\" type=\"data_ptr\" group=\"general\" />"
- " <reg name=\"psp\" bitsize=\"32\" regnum=\"27\" type=\"data_ptr\" group=\"general\" />"
- " <reg name=\"control\" bitsize=\"8\" regnum=\"28\" type=\"int\" group=\"general\" />"
- " <reg name=\"faultmask\" bitsize=\"8\" regnum=\"29\" type=\"int\" group=\"general\" />"
- " <reg name=\"basepri\" bitsize=\"8\" regnum=\"30\" type=\"int\" group=\"general\" />"
- " <reg name=\"primask\" bitsize=\"8\" regnum=\"31\" type=\"int\" group=\"general\" />"
- " <reg name=\"s0\" bitsize=\"32\" regnum=\"32\" type=\"float\" group=\"float\" />"
- " <reg name=\"s1\" bitsize=\"32\" type=\"float\" group=\"float\" />"
- " <reg name=\"s2\" bitsize=\"32\" type=\"float\" group=\"float\" />"
- " <reg name=\"s3\" bitsize=\"32\" type=\"float\" group=\"float\" />"
- " <reg name=\"s4\" bitsize=\"32\" type=\"float\" group=\"float\" />"
- " <reg name=\"s5\" bitsize=\"32\" type=\"float\" group=\"float\" />"
- " <reg name=\"s6\" bitsize=\"32\" type=\"float\" group=\"float\" />"
- " <reg name=\"s7\" bitsize=\"32\" type=\"float\" group=\"float\" />"
- " <reg name=\"s8\" bitsize=\"32\" type=\"float\" group=\"float\" />"
- " <reg name=\"s9\" bitsize=\"32\" type=\"float\" group=\"float\" />"
- " <reg name=\"s10\" bitsize=\"32\" type=\"float\" group=\"float\" />"
- " <reg name=\"s11\" bitsize=\"32\" type=\"float\" group=\"float\" />"
- " <reg name=\"s12\" bitsize=\"32\" type=\"float\" group=\"float\" />"
- " <reg name=\"s13\" bitsize=\"32\" type=\"float\" group=\"float\" />"
- " <reg name=\"s14\" bitsize=\"32\" type=\"float\" group=\"float\" />"
- " <reg name=\"s15\" bitsize=\"32\" type=\"float\" group=\"float\" />"
- " <reg name=\"s16\" bitsize=\"32\" type=\"float\" group=\"float\" />"
- " <reg name=\"s17\" bitsize=\"32\" type=\"float\" group=\"float\" />"
- " <reg name=\"s18\" bitsize=\"32\" type=\"float\" group=\"float\" />"
- " <reg name=\"s19\" bitsize=\"32\" type=\"float\" group=\"float\" />"
- " <reg name=\"s20\" bitsize=\"32\" type=\"float\" group=\"float\" />"
- " <reg name=\"s21\" bitsize=\"32\" type=\"float\" group=\"float\" />"
- " <reg name=\"s22\" bitsize=\"32\" type=\"float\" group=\"float\" />"
- " <reg name=\"s23\" bitsize=\"32\" type=\"float\" group=\"float\" />"
- " <reg name=\"s24\" bitsize=\"32\" type=\"float\" group=\"float\" />"
- " <reg name=\"s25\" bitsize=\"32\" type=\"float\" group=\"float\" />"
- " <reg name=\"s26\" bitsize=\"32\" type=\"float\" group=\"float\" />"
- " <reg name=\"s27\" bitsize=\"32\" type=\"float\" group=\"float\" />"
- " <reg name=\"s28\" bitsize=\"32\" type=\"float\" group=\"float\" />"
- " <reg name=\"s29\" bitsize=\"32\" type=\"float\" group=\"float\" />"
- " <reg name=\"s30\" bitsize=\"32\" type=\"float\" group=\"float\" />"
- " <reg name=\"s31\" bitsize=\"32\" type=\"float\" group=\"float\" />"
- " <reg name=\"fpscr\" bitsize=\"32\" type=\"int\" group=\"float\" />"
- " </feature>"
- "</target>";
-
-static const char* const memory_map_template_F4 =
- "<?xml version=\"1.0\"?>"
- "<!DOCTYPE memory-map PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\""
- " \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"
- "<memory-map>"
- " <memory type=\"rom\" start=\"0x00000000\" length=\"0x100000\"/>" // code = sram, bootrom or flash; flash is bigger
- " <memory type=\"ram\" start=\"0x10000000\" length=\"0x10000\"/>" // ccm ram
- " <memory type=\"ram\" start=\"0x20000000\" length=\"0x20000\"/>" // sram
- " <memory type=\"flash\" start=\"0x08000000\" length=\"0x10000\">" //Sectors 0..3
- " <property name=\"blocksize\">0x4000</property>" //16kB
- " </memory>"
- " <memory type=\"flash\" start=\"0x08010000\" length=\"0x10000\">" //Sector 4
- " <property name=\"blocksize\">0x10000</property>" //64kB
- " </memory>"
- " <memory type=\"flash\" start=\"0x08020000\" length=\"0xE0000\">" //Sectors 5..11
- " <property name=\"blocksize\">0x20000</property>" //128kB
- " </memory>"
- " <memory type=\"ram\" start=\"0x40000000\" length=\"0x1fffffff\"/>" // peripheral regs
- " <memory type=\"ram\" start=\"0x60000000\" length=\"0x7fffffff\"/>" // AHB3 Peripherals
- " <memory type=\"ram\" start=\"0xe0000000\" length=\"0x1fffffff\"/>" // cortex regs
- " <memory type=\"rom\" start=\"0x1fff0000\" length=\"0x7800\"/>" // bootrom
- " <memory type=\"rom\" start=\"0x1fffc000\" length=\"0x10\"/>" // option byte area
- "</memory-map>";
-
-static const char* const memory_map_template_F4_HD =
- "<?xml version=\"1.0\"?>"
- "<!DOCTYPE memory-map PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\""
- " \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"
- "<memory-map>"
- " <memory type=\"rom\" start=\"0x00000000\" length=\"0x100000\"/>" // code = sram, bootrom or flash; flash is bigger
- " <memory type=\"ram\" start=\"0x10000000\" length=\"0x10000\"/>" // ccm ram
- " <memory type=\"ram\" start=\"0x20000000\" length=\"0x40000\"/>" // sram
- " <memory type=\"ram\" start=\"0x60000000\" length=\"0x10000000\"/>" // fmc bank 1 (nor/psram/sram)
- " <memory type=\"ram\" start=\"0x70000000\" length=\"0x20000000\"/>" // fmc bank 2 & 3 (nand flash)
- " <memory type=\"ram\" start=\"0x90000000\" length=\"0x10000000\"/>" // fmc bank 4 (pc card)
- " <memory type=\"ram\" start=\"0xC0000000\" length=\"0x20000000\"/>" // fmc sdram bank 1 & 2
- " <memory type=\"flash\" start=\"0x08000000\" length=\"0x10000\">" //Sectors 0..3
- " <property name=\"blocksize\">0x4000</property>" //16kB
- " </memory>"
- " <memory type=\"flash\" start=\"0x08010000\" length=\"0x10000\">" //Sector 4
- " <property name=\"blocksize\">0x10000</property>" //64kB
- " </memory>"
- " <memory type=\"flash\" start=\"0x08020000\" length=\"0xE0000\">" //Sectors 5..11
- " <property name=\"blocksize\">0x20000</property>" //128kB
- " </memory>"
- " <memory type=\"ram\" start=\"0x40000000\" length=\"0x1fffffff\"/>" // peripheral regs
- " <memory type=\"ram\" start=\"0xe0000000\" length=\"0x1fffffff\"/>" // cortex regs
- " <memory type=\"rom\" start=\"0x1fff0000\" length=\"0x7800\"/>" // bootrom
- " <memory type=\"rom\" start=\"0x1fffc000\" length=\"0x10\"/>" // option byte area
- "</memory-map>";
-
-static const char* const memory_map_template_F2 =
- "<?xml version=\"1.0\"?>"
- "<!DOCTYPE memory-map PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\""
- " \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"
- "<memory-map>"
- " <memory type=\"rom\" start=\"0x00000000\" length=\"0x%zx\"/>" // code = sram, bootrom or flash; flash is bigger
- " <memory type=\"ram\" start=\"0x20000000\" length=\"0x%zx\"/>" // sram
- " <memory type=\"flash\" start=\"0x08000000\" length=\"0x10000\">" //Sectors 0..3
- " <property name=\"blocksize\">0x4000</property>" //16kB
- " </memory>"
- " <memory type=\"flash\" start=\"0x08010000\" length=\"0x10000\">" //Sector 4
- " <property name=\"blocksize\">0x10000</property>" //64kB
- " </memory>"
- " <memory type=\"flash\" start=\"0x08020000\" length=\"0x%zx\">" //Sectors 5..
- " <property name=\"blocksize\">0x20000</property>" //128kB
- " </memory>"
- " <memory type=\"ram\" start=\"0x40000000\" length=\"0x1fffffff\"/>" // peripheral regs
- " <memory type=\"ram\" start=\"0xe0000000\" length=\"0x1fffffff\"/>" // cortex regs
- " <memory type=\"rom\" start=\"0x%08x\" length=\"0x%zx\"/>" // bootrom
- " <memory type=\"rom\" start=\"0x1fffc000\" length=\"0x10\"/>" // option byte area
- "</memory-map>";
-
-static const char* const memory_map_template_L4 =
- "<?xml version=\"1.0\"?>"
- "<!DOCTYPE memory-map PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\""
- " \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"
- "<memory-map>"
- " <memory type=\"rom\" start=\"0x00000000\" length=\"0x%zx\"/>" // code = sram, bootrom or flash; flash is bigger
- " <memory type=\"ram\" start=\"0x10000000\" length=\"0x8000\"/>" // SRAM2 (32 KB)
- " <memory type=\"ram\" start=\"0x20000000\" length=\"0x18000\"/>" // SRAM1 (96 KB)
- " <memory type=\"flash\" start=\"0x08000000\" length=\"0x%zx\">"
- " <property name=\"blocksize\">0x800</property>"
- " </memory>"
- " <memory type=\"ram\" start=\"0x40000000\" length=\"0x1fffffff\"/>" // peripheral regs
- " <memory type=\"ram\" start=\"0x60000000\" length=\"0x7fffffff\"/>" // AHB3 Peripherals
- " <memory type=\"ram\" start=\"0xe0000000\" length=\"0x1fffffff\"/>" // cortex regs
- " <memory type=\"rom\" start=\"0x1fff0000\" length=\"0x7000\"/>" // bootrom
- " <memory type=\"rom\" start=\"0x1fff7800\" length=\"0x10\"/>" // option byte area
- " <memory type=\"rom\" start=\"0x1ffff800\" length=\"0x10\"/>" // option byte area
- "</memory-map>";
-
-static const char* const memory_map_template =
- "<?xml version=\"1.0\"?>"
- "<!DOCTYPE memory-map PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\""
- " \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"
- "<memory-map>"
- " <memory type=\"rom\" start=\"0x00000000\" length=\"0x%zx\"/>" // code = sram, bootrom or flash; flash is bigger
- " <memory type=\"ram\" start=\"0x20000000\" length=\"0x%zx\"/>" // sram 8k
- " <memory type=\"flash\" start=\"0x08000000\" length=\"0x%zx\">"
- " <property name=\"blocksize\">0x%zx</property>"
- " </memory>"
- " <memory type=\"ram\" start=\"0x40000000\" length=\"0x1fffffff\"/>" // peripheral regs
- " <memory type=\"ram\" start=\"0xe0000000\" length=\"0x1fffffff\"/>" // cortex regs
- " <memory type=\"rom\" start=\"0x%08x\" length=\"0x%zx\"/>" // bootrom
- " <memory type=\"rom\" start=\"0x1ffff800\" length=\"0x10\"/>" // option byte area
- "</memory-map>";
-
-static const char* const memory_map_template_F7 =
- "<?xml version=\"1.0\"?>"
- "<!DOCTYPE memory-map PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\""
- " \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"
- "<memory-map>"
- " <memory type=\"ram\" start=\"0x00000000\" length=\"0x4000\"/>" // ITCM ram 16kB
- " <memory type=\"rom\" start=\"0x00200000\" length=\"0x100000\"/>" // ITCM flash
- " <memory type=\"ram\" start=\"0x20000000\" length=\"0x50000\"/>" // sram
- " <memory type=\"flash\" start=\"0x08000000\" length=\"0x20000\">" // Sectors 0..3
- " <property name=\"blocksize\">0x8000</property>" // 32kB
- " </memory>"
- " <memory type=\"flash\" start=\"0x08020000\" length=\"0x20000\">" // Sector 4
- " <property name=\"blocksize\">0x20000</property>" // 128kB
- " </memory>"
- " <memory type=\"flash\" start=\"0x08040000\" length=\"0xC0000\">" // Sectors 5..7
- " <property name=\"blocksize\">0x40000</property>" // 128kB
- " </memory>"
- " <memory type=\"ram\" start=\"0x40000000\" length=\"0x1fffffff\"/>" // peripheral regs
- " <memory type=\"ram\" start=\"0x60000000\" length=\"0x7fffffff\"/>" // AHB3 Peripherals
- " <memory type=\"ram\" start=\"0xe0000000\" length=\"0x1fffffff\"/>" // cortex regs
- " <memory type=\"rom\" start=\"0x00100000\" length=\"0xEDC0\"/>" // bootrom
- " <memory type=\"rom\" start=\"0x1fff0000\" length=\"0x20\"/>" // option byte area
- "</memory-map>";
-
-char* make_memory_map(stlink_t *sl) {
- /* This will be freed in serve() */
- char* map = malloc(4096);
- map[0] = '\0';
-
- if(sl->chip_id==STM32_CHIPID_F4 || sl->chip_id==STM32_CHIPID_F446) {
- strcpy(map, memory_map_template_F4);
- } else if(sl->chip_id==STM32_CHIPID_F4 || sl->chip_id==STM32_CHIPID_F7) {
- strcpy(map, memory_map_template_F7);
- } 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, 4096, 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) {
- snprintf(map, 4096, memory_map_template_L4,
- sl->flash_size, sl->flash_size);
- } else {
- snprintf(map, 4096, memory_map_template,
- sl->flash_size,
- sl->sram_size,
- sl->flash_size, sl->flash_pgsz,
- sl->sys_base, sl->sys_size);
- }
- return map;
-}
-
-
-/*
- * DWT_COMP0 0xE0001020
- * DWT_MASK0 0xE0001024
- * DWT_FUNCTION0 0xE0001028
- * DWT_COMP1 0xE0001030
- * DWT_MASK1 0xE0001034
- * DWT_FUNCTION1 0xE0001038
- * DWT_COMP2 0xE0001040
- * DWT_MASK2 0xE0001044
- * DWT_FUNCTION2 0xE0001048
- * DWT_COMP3 0xE0001050
- * DWT_MASK3 0xE0001054
- * DWT_FUNCTION3 0xE0001058
- */
-
-#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;
-};
-
-struct code_hw_watchpoint data_watches[DATA_WATCH_NUM];
-
-static void init_data_watchpoints(stlink_t *sl) {
- uint32_t data;
- DLOG("init watchpoints\n");
-
- stlink_read_debug32(sl, 0xE000EDFC, &data);
- data |= 1<<24;
- // set trcena in debug command to turn on dwt unit
- stlink_write_debug32(sl, 0xE000EDFC, data);
-
- // make sure all watchpoints are cleared
- for(int i = 0; i < DATA_WATCH_NUM; i++) {
- data_watches[i].fun = WATCHDISABLED;
- stlink_write_debug32(sl, 0xe0001028 + i * 16, 0);
- }
-}
-
-static int add_data_watchpoint(stlink_t *sl, enum watchfun wf,
- stm32_addr_t addr, unsigned int len) {
- int 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, 0xE0001020 + i * 16, addr);
-
- // insert mask
- stlink_write_debug32(sl, 0xE0001024 + i * 16, mask);
-
- // insert function
- stlink_write_debug32(sl, 0xE0001028 + i * 16, wf);
-
- // just to make sure the matched bit is clear !
- stlink_read_debug32(sl, 0xE0001028 + i * 16, &dummy);
- return 0;
- }
- }
- }
-
- DLOG("failure: add watchpoints addr %x wf %u len %u\n", addr, wf, len);
- return -1;
-}
-
-static int delete_data_watchpoint(stlink_t *sl, stm32_addr_t addr)
-{
- int 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, 0xe0001028 + i * 16, 0);
-
- return 0;
- }
- }
-
- DLOG("failure: delete watchpoint addr %x\n", addr);
-
- return -1;
-}
-
-int code_break_num;
-int code_lit_num;
-#define CODE_BREAK_NUM_MAX 15
-#define CODE_BREAK_LOW 0x01
-#define CODE_BREAK_HIGH 0x02
-
-struct code_hw_breakpoint {
- stm32_addr_t addr;
- int type;
-};
-
-struct code_hw_breakpoint code_breaks[CODE_BREAK_NUM_MAX];
-
-static void init_code_breakpoints(stlink_t *sl) {
- unsigned int val;
- memset(sl->q_buf, 0, 4);
- stlink_write_debug32(sl, CM3_REG_FP_CTRL, 0x03 /*KEY | ENABLE4*/);
- stlink_read_debug32(sl, CM3_REG_FP_CTRL, &val);
- code_break_num = ((val >> 4) & 0xf);
- code_lit_num = ((val >> 8) & 0xf);
-
- ILOG("Found %i hw breakpoint registers\n", code_break_num);
-
- for(int i = 0; i < code_break_num; i++) {
- code_breaks[i].type = 0;
- stlink_write_debug32(sl, CM3_REG_FP_COMP0 + i * 4, 0);
- }
-}
-
-static int update_code_breakpoint(stlink_t *sl, stm32_addr_t addr, int set) {
- stm32_addr_t fpb_addr;
- uint32_t mask;
- int type = (addr & 0x2) ? CODE_BREAK_HIGH : CODE_BREAK_LOW;
-
- if(addr & 1) {
- ELOG("update_code_breakpoint: unaligned address %08x\n", addr);
- return -1;
- }
-
- if (sl->chip_id==STM32_CHIPID_F7) {
- fpb_addr = addr;
- } else {
- fpb_addr = addr & ~0x3;
- }
-
- int id = -1;
- for(int 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* brk = &code_breaks[id];
-
- brk->addr = fpb_addr;
-
- if (sl->chip_id==STM32_CHIPID_F7) {
- if(set) brk->type = type;
- else brk->type = 0;
-
- mask = (brk->addr) | 1;
- } else {
- if(set) brk->type |= type;
- else brk->type &= ~type;
-
- mask = (brk->addr) | 1 | (brk->type << 30);
- }
-
- if(brk->type == 0) {
- DLOG("clearing hw break %d\n", id);
-
- stlink_write_debug32(sl, 0xe0002008 + id * 4, 0);
- } else {
- DLOG("setting hw break %d at %08x (%d)\n",
- id, brk->addr, brk->type);
- DLOG("reg %08x \n",
- mask);
-
- stlink_write_debug32(sl, 0xe0002008 + id * 4, mask);
- }
-
- return 0;
-}
-
-
-struct flash_block {
- stm32_addr_t addr;
- unsigned length;
- uint8_t* data;
-
- struct flash_block* next;
-};
-
-static struct flash_block* flash_root;
-
-static int flash_add_block(stm32_addr_t addr, unsigned 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 = calloc(length, 1);
-
- flash_root = new;
-
- return 0;
-}
-
-static int flash_populate(stm32_addr_t addr, uint8_t* data, unsigned length) {
- unsigned int 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
- */
-
- unsigned X = fb->addr, Y = fb->addr + fb->length;
- unsigned a = addr, b = addr + length;
- if(a < Y && b > X) {
- // from start of the block
- unsigned start = (a > X ? a : X) - X;
- unsigned end = (b > Y ? Y : b) - X;
-
- 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 int flash_go(stlink_t *sl) {
- int error = -1;
-
- // Some kinds of clock settings do not allow writing to flash.
- stlink_reset(sl);
- stlink_force_debug(sl);
-
- for(struct flash_block* fb = flash_root; fb; fb = fb->next) {
- DLOG("flash_do: block %08x -> %04x\n", fb->addr, fb->length);
-
- for(stm32_addr_t page = fb->addr; page < fb->addr + fb->length; page += FLASH_PAGE) {
- unsigned length = fb->length - (page - fb->addr);
-
- //Update FLASH_PAGE
- stlink_calculate_pagesize(sl, page);
-
- DLOG("flash_do: page %08x\n", page);
- unsigned send = length > FLASH_PAGE ? FLASH_PAGE : length;
- if(stlink_write_flash(sl, page, fb->data + (page - fb->addr),
- send, 0) < 0)
- goto error;
- length -= send;
-
- }
- }
-
- stlink_reset(sl);
-
- 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;
-}
-
-#define CLIDR 0xE000ED78
-#define CTR 0xE000ED7C
-#define CCSIDR 0xE000ED80
-#define CSSELR 0xE000ED84
-#define CCR 0xE000ED14
-#define CCR_DC (1 << 16)
-#define CCR_IC (1 << 17)
-#define DCCSW 0xE000EF6C
-#define ICIALLU 0xE000EF50
-
-struct cache_level_desc
-{
- unsigned int nsets;
- unsigned int nways;
- unsigned int log2_nways;
- unsigned int width;
-};
-
-struct cache_desc_t
-{
- /* Minimal line size in bytes. */
- unsigned int dminline;
- unsigned int iminline;
-
- /* Last level of unification (uniprocessor). */
- unsigned int 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 unsigned ceil_log2(unsigned v)
-{
- unsigned res;
- for (res = 0; (1U << res) < v; res++)
- ;
- return res;
-}
-
-static void read_cache_level_desc(stlink_t *sl, struct cache_level_desc *desc)
-{
- unsigned int ccsidr;
- unsigned int log2_nsets;
-
- stlink_read_debug32(sl, 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) {
- unsigned int clidr;
- unsigned int ccr;
- unsigned int ctr;
- int i;
-
- /* Assume only F7 has a cache. */
- if(sl->chip_id!=STM32_CHIPID_F7)
- return;
-
- stlink_read_debug32(sl, CLIDR, &clidr);
- stlink_read_debug32(sl, CCR, &ccr);
- stlink_read_debug32(sl, CTR, &ctr);
- cache_desc.dminline = 4 << ((ctr >> 16) & 0x0f);
- cache_desc.iminline = 4 << (ctr & 0x0f);
- cache_desc.louu = (clidr >> 27) & 7;
-
- ILOG("Chip clidr: %08x, I-Cache: %s, D-Cache: %s\n",
- clidr, ccr & CCR_IC ? "on" : "off", ccr & 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++)
- {
- unsigned int 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, 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, 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, unsigned ccr) {
- int level;
-
- if (ccr & CCR_DC)
- for (level = cache_desc.louu - 1; level >= 0; level--)
- {
- struct cache_level_desc *desc = &cache_desc.dcache[level];
- unsigned addr;
- unsigned max_addr = 1 << desc->width;
- unsigned way_sh = 32 - desc->log2_nways;
-
- /* D-cache clean by set-ways. */
- for (addr = (level << 1); addr < max_addr; addr += cache_desc.dminline)
- {
- unsigned int way;
-
- for (way = 0; way < desc->nways; way++)
- stlink_write_debug32(sl, DCCSW, addr | (way << way_sh));
- }
- }
-
- /* Invalidate all I-cache to oPU. */
- if (ccr & CCR_IC)
- stlink_write_debug32(sl, ICIALLU, 0);
-}
-
-static int cache_modified;
-
-static void cache_change(stm32_addr_t start, unsigned count)
-{
- if (count == 0)
- return;
- (void)start;
- cache_modified = 1;
-}
-
-static void cache_sync(stlink_t *sl)
-{
- unsigned ccr;
-
- if(sl->chip_id!=STM32_CHIPID_F7)
- return;
- if (!cache_modified)
- return;
- cache_modified = 0;
-
- stlink_read_debug32(sl, CCR, &ccr);
- if (ccr & (CCR_IC | CCR_DC))
- cache_flush(sl, ccr);
-}
-
-int serve(stlink_t *sl, st_state_t *st) {
- int sock = socket(AF_INET, SOCK_STREAM, 0);
- if(sock < 0) {
- perror("socket");
- return 1;
- }
-
- unsigned int 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");
- return 1;
- }
-
- if(listen(sock, 5) < 0) {
- perror("listen");
- return 1;
- }
-
- ILOG("Listening at *:%d...\n", st->listen_port);
-
- int client = accept(sock, NULL, NULL);
- //signal (SIGINT, SIG_DFL);
- if(client < 0) {
- perror("accept");
- return 1;
- }
-
- close(sock);
-
- stlink_force_debug(sl);
- if (st->reset) {
- stlink_reset(sl);
- }
- init_code_breakpoints(sl);
- init_data_watchpoints(sl);
-
- ILOG("GDB connected.\n");
-
- /*
- * To allow resetting the chip from GDB it is required to
- * emulate attaching and detaching to target.
- */
- unsigned int attached = 1;
-
- while(1) {
- char* packet;
-
- int status = gdb_recv_packet(client, &packet);
- if(status < 0) {
- ELOG("cannot recv: %d\n", status);
-#ifdef __MINGW32__
- win32_close_socket(sock);
-#endif
- return 1;
- }
-
- DLOG("recv: %s\n", packet);
-
- char* reply = NULL;
- 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;
- }
-
- unsigned queryNameLength = (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")) {
- if(sl->chip_id==STM32_CHIPID_F4
- || sl->chip_id==STM32_CHIPID_F4_HD
- || sl->chip_id==STM32_CHIPID_F7) {
- reply = strdup("PacketSize=3fff;qXfer:memory-map:read+;qXfer:features:read+");
- }
- else {
- reply = strdup("PacketSize=3fff;qXfer:memory-map: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;
-
- unsigned addr = strtoul(__s_addr, NULL, 16),
- length = 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 = NULL;
-
- if(!strcmp(type, "memory-map") && !strcmp(op, "read"))
- data = current_memory_map;
-
- if(!strcmp(type, "features") && !strcmp(op, "read"))
- data = target_description_F4;
-
- if(data) {
- unsigned data_length = 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
- char *separator = strstr(packet, ","), *params = "";
- if(separator == NULL) {
- separator = packet + strlen(packet);
- } else {
- params = separator + 1;
- }
-
-
- if (!strncmp(params,"726573756d65",12)) {// resume
- DLOG("Rcmd: resume\n");
- cache_sync(sl);
- stlink_run(sl);
-
- reply = strdup("OK");
- } else if (!strncmp(params,"68616c74",8)) { //halt
- reply = strdup("OK");
-
- stlink_force_debug(sl);
-
- DLOG("Rcmd: halt\n");
- } else if (!strncmp(params,"6a7461675f7265736574",20)) { //jtag_reset
- reply = strdup("OK");
-
- stlink_jtag_reset(sl, 0);
- stlink_jtag_reset(sl, 1);
- stlink_force_debug(sl);
-
- DLOG("Rcmd: jtag_reset\n");
- } else if (!strncmp(params,"7265736574",10)) { //reset
- reply = strdup("OK");
-
- stlink_force_debug(sl);
- stlink_reset(sl);
- init_code_breakpoints(sl);
- init_data_watchpoints(sl);
-
- DLOG("Rcmd: reset\n");
- } else {
- DLOG("Rcmd: %s\n", params);
- }
-
- }
-
- 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;
-
- unsigned addr = strtoul(__s_addr, NULL, 16),
- length = 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;
-
- unsigned addr = strtoul(__s_addr, NULL, 16);
- unsigned data_length = status - (data - packet);
-
- // Length of decoded data cannot be more than
- // encoded, as escapes are removed.
- // Additional byte is reserved for alignment fix.
- uint8_t *decoded = calloc(data_length + 1, 1);
- unsigned dec_index = 0;
- for(unsigned int 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");
- }
- } else if(!strcmp(cmdName, "FlashDone")) {
- if(flash_go(sl) < 0) {
- reply = strdup("E00");
- } 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);
- stlink_run(sl);
-
- while(1) {
- int status = gdb_check_for_interrupt(client);
- if(status < 0) {
- ELOG("cannot check for int: %d\n", status);
-#ifdef __MINGW32__
- win32_close_socket(sock);
-#endif
- return 1;
- }
-
- if(status == 1) {
- stlink_force_debug(sl);
- break;
- }
-
- stlink_status(sl);
- if(sl->core_stat == STLINK_CORE_HALTED) {
- break;
- }
-
- usleep(100000);
- }
-
- reply = strdup("S05"); // TRAP
- break;
-
- case 's':
- cache_sync(sl);
- stlink_step(sl);
-
- reply = strdup("S05"); // TRAP
- break;
-
- case '?':
- if(attached) {
- reply = strdup("S05"); // TRAP
- } else {
- /* Stub shall reply OK if not attached. */
- reply = strdup("OK");
- }
- break;
-
- case 'g':
- stlink_read_all_regs(sl, ®p);
-
- reply = calloc(8 * 16 + 1, 1);
- for(int i = 0; i < 16; i++)
- sprintf(&reply[i * 8], "%08x", htonl(regp.r[i]));
-
- break;
-
- case 'p': {
- unsigned id = strtoul(&packet[1], NULL, 16);
- unsigned myreg = 0xDEADDEAD;
-
- if(id < 16) {
- stlink_read_reg(sl, id, ®p);
- myreg = htonl(regp.r[id]);
- } else if(id == 0x19) {
- stlink_read_reg(sl, 16, ®p);
- myreg = htonl(regp.xpsr);
- } else if(id == 0x1A) {
- stlink_read_reg(sl, 17, ®p);
- myreg = htonl(regp.main_sp);
- } else if(id == 0x1B) {
- stlink_read_reg(sl, 18, ®p);
- myreg = htonl(regp.process_sp);
- } else if(id == 0x1C) {
- stlink_read_unsupported_reg(sl, id, ®p);
- myreg = htonl(regp.control);
- } else if(id == 0x1D) {
- stlink_read_unsupported_reg(sl, id, ®p);
- myreg = htonl(regp.faultmask);
- } else if(id == 0x1E) {
- stlink_read_unsupported_reg(sl, id, ®p);
- myreg = htonl(regp.basepri);
- } else if(id == 0x1F) {
- stlink_read_unsupported_reg(sl, id, ®p);
- myreg = htonl(regp.primask);
- } else if(id >= 0x20 && id < 0x40) {
- stlink_read_unsupported_reg(sl, id, ®p);
- myreg = htonl(regp.s[id-0x20]);
- } else if(id == 0x40) {
- stlink_read_unsupported_reg(sl, id, ®p);
- myreg = htonl(regp.fpscr);
- } else {
- reply = strdup("E00");
- }
-
- reply = calloc(8 + 1, 1);
- sprintf(reply, "%08x", myreg);
-
- break;
- }
-
- case 'P': {
- char* s_reg = &packet[1];
- char* s_value = strstr(&packet[1], "=") + 1;
-
- unsigned reg = strtoul(s_reg, NULL, 16);
- unsigned value = strtoul(s_value, NULL, 16);
-
- if(reg < 16) {
- stlink_write_reg(sl, ntohl(value), reg);
- } else if(reg == 0x19) {
- stlink_write_reg(sl, ntohl(value), 16);
- } else if(reg == 0x1A) {
- stlink_write_reg(sl, ntohl(value), 17);
- } else if(reg == 0x1B) {
- stlink_write_reg(sl, ntohl(value), 18);
- } else if(reg == 0x1C) {
- stlink_write_unsupported_reg(sl, ntohl(value), reg, ®p);
- } else if(reg == 0x1D) {
- stlink_write_unsupported_reg(sl, ntohl(value), reg, ®p);
- } else if(reg == 0x1E) {
- stlink_write_unsupported_reg(sl, ntohl(value), reg, ®p);
- } else if(reg == 0x1F) {
- stlink_write_unsupported_reg(sl, ntohl(value), reg, ®p);
- } else if(reg >= 0x20 && reg < 0x40) {
- stlink_write_unsupported_reg(sl, ntohl(value), reg, ®p);
- } else if(reg == 0x40) {
- stlink_write_unsupported_reg(sl, ntohl(value), reg, ®p);
- } else {
- reply = strdup("E00");
- }
-
- if(!reply) {
- reply = strdup("OK");
- }
-
- break;
- }
-
- case 'G':
- for(int i = 0; i < 16; i++) {
- char str[9] = {0};
- strncpy(str, &packet[1 + i * 8], 8);
- uint32_t reg = strtoul(str, NULL, 16);
- stlink_write_reg(sl, ntohl(reg), i);
- }
-
- reply = strdup("OK");
- break;
-
- case 'm': {
- char* s_start = &packet[1];
- char* s_count = strstr(&packet[1], ",") + 1;
-
- stm32_addr_t start = strtoul(s_start, NULL, 16);
- unsigned count = strtoul(s_count, NULL, 16);
-
- unsigned adj_start = start % 4;
- unsigned 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;
-
- stlink_read_mem32(sl, start - adj_start, count_rnd);
-
- reply = calloc(count * 2 + 1, 1);
- for(unsigned int 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 = strtoul(s_start, NULL, 16);
- unsigned count = strtoul(s_count, NULL, 16);
-
- if(start % 4) {
- unsigned align_count = 4 - start % 4;
- if (align_count > count) align_count = count;
- for(unsigned int i = 0; i < align_count; i ++) {
- char hex[3] = { hexdata[i*2], hexdata[i*2+1], 0 };
- uint8_t byte = strtoul(hex, NULL, 16);
- sl->q_buf[i] = byte;
- }
- 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) {
- unsigned aligned_count = count - count % 4;
-
- for(unsigned int i = 0; i < aligned_count; i ++) {
- char hex[3] = { hexdata[i*2], hexdata[i*2+1], 0 };
- uint8_t byte = strtoul(hex, NULL, 16);
- sl->q_buf[i] = byte;
- }
- 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(unsigned int i = 0; i < count; i ++) {
- char hex[3] = { hexdata[i*2], hexdata[i*2+1], 0 };
- uint8_t byte = strtoul(hex, NULL, 16);
- sl->q_buf[i] = byte;
- }
- stlink_write_mem8(sl, start, count);
- cache_change(start, count);
- }
- reply = strdup("OK");
- break;
- }
-
- case 'Z': {
- char *endptr;
- stm32_addr_t addr = strtoul(&packet[3], &endptr, 16);
- stm32_addr_t len = 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;
- }
- }
-
- default:
- reply = strdup("");
- }
- break;
- }
- case 'z': {
- char *endptr;
- stm32_addr_t addr = 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");
- } 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. */
-
- stlink_reset(sl);
- init_code_breakpoints(sl);
- init_data_watchpoints(sl);
-
- attached = 1;
-
- reply = strdup("OK");
-
- break;
- }
-
- default:
- reply = strdup("");
- }
-
- if(reply) {
- DLOG("send: %s\n", reply);
-
- int result = gdb_send_packet(client, reply);
- if(result != 0) {
- ELOG("cannot send: %d\n", result);
- free(reply);
- free(packet);
-#ifdef __MINGW32__
- win32_close_socket(sock);
-#endif
- return 1;
- }
-
- free(reply);
- }
-
- free(packet);
- }
-
-#ifdef __MINGW32__
- win32_close_socket(sock);
-#endif
-
- return 0;
-}
+++ /dev/null
-#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
--- /dev/null
+/*
+ * File: stlink.h
+ *
+ * This should contain all the common top level stlink interfaces, regardless
+ * of how the backend does the work....
+ */
+#ifndef STLINK_H
+#define STLINK_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ // Max data transfer size.
+ // 6kB = max mem32_read block, 8kB sram
+ //#define Q_BUF_LEN 96
+#define Q_BUF_LEN (1024 * 100)
+
+ // st-link vendor cmd's
+#define USB_ST_VID 0x0483
+#define USB_STLINK_PID 0x3744
+#define USB_STLINK_32L_PID 0x3748
+#define USB_STLINK_NUCLEO_PID 0x374b
+
+ // STLINK_DEBUG_RESETSYS, etc:
+#define STLINK_OK 0x80
+#define STLINK_FALSE 0x81
+#define STLINK_CORE_RUNNING 0x80
+#define STLINK_CORE_HALTED 0x81
+#define STLINK_CORE_STAT_UNKNOWN -1
+
+#define STLINK_GET_VERSION 0xf1
+#define STLINK_GET_CURRENT_MODE 0xf5
+#define STLINK_GET_TARGET_VOLTAGE 0xF7
+
+#define STLINK_DEBUG_COMMAND 0xF2
+#define STLINK_DFU_COMMAND 0xF3
+#define STLINK_DFU_EXIT 0x07
+ // enter dfu could be 0x08?
+
+ // STLINK_GET_CURRENT_MODE
+#define STLINK_DEV_DFU_MODE 0x00
+#define STLINK_DEV_MASS_MODE 0x01
+#define STLINK_DEV_DEBUG_MODE 0x02
+#define STLINK_DEV_UNKNOWN_MODE -1
+
+ // jtag mode cmds
+#define STLINK_DEBUG_ENTER 0x20
+#define STLINK_DEBUG_EXIT 0x21
+#define STLINK_DEBUG_READCOREID 0x22
+#define STLINK_DEBUG_GETSTATUS 0x01
+#define STLINK_DEBUG_FORCEDEBUG 0x02
+#define STLINK_DEBUG_RESETSYS 0x03
+#define STLINK_DEBUG_READALLREGS 0x04
+#define STLINK_DEBUG_READREG 0x05
+#define STLINK_DEBUG_WRITEREG 0x06
+#define STLINK_DEBUG_READMEM_32BIT 0x07
+#define STLINK_DEBUG_WRITEMEM_32BIT 0x08
+#define STLINK_DEBUG_RUNCORE 0x09
+#define STLINK_DEBUG_STEPCORE 0x0a
+#define STLINK_DEBUG_SETFP 0x0b
+#define STLINK_DEBUG_WRITEMEM_8BIT 0x0d
+#define STLINK_DEBUG_CLEARFP 0x0e
+#define STLINK_DEBUG_WRITEDEBUGREG 0x0f
+#define STLINK_DEBUG_ENTER_SWD 0xa3
+#define STLINK_DEBUG_ENTER_JTAG 0x00
+
+ // TODO - possible poor names...
+#define STLINK_SWD_ENTER 0x30
+#define STLINK_SWD_READCOREID 0x32 // TBD
+#define STLINK_JTAG_WRITEDEBUG_32BIT 0x35
+#define STLINK_JTAG_READDEBUG_32BIT 0x36
+#define STLINK_JTAG_DRIVE_NRST 0x3c
+#define STLINK_JTAG_DRIVE_NRST 0x3c
+
+ // cortex m3 technical reference manual
+#define CM3_REG_CPUID 0xE000ED00
+#define CM3_REG_FP_CTRL 0xE0002000
+#define CM3_REG_FP_COMP0 0xE0002008
+
+ /* cortex core ids */
+ // TODO clean this up...
+#define STM32VL_CORE_ID 0x1ba01477
+#define STM32L_CORE_ID 0x2ba01477
+#define STM32F3_CORE_ID 0x2ba01477
+#define STM32F4_CORE_ID 0x2ba01477
+#define STM32F0_CORE_ID 0xbb11477
+#define CORE_M3_R1 0x1BA00477
+#define CORE_M3_R2 0x4BA00477
+#define CORE_M4_R0 0x2BA01477
+
+ /*
+ * Chip IDs are explained in the appropriate programming manual for the
+ * DBGMCU_IDCODE register (0xE0042000)
+ */
+ // stm32 chipids, only lower 12 bits..
+#define STM32_CHIPID_F1_MEDIUM 0x410
+#define STM32_CHIPID_F2 0x411
+#define STM32_CHIPID_F1_LOW 0x412
+#define STM32_CHIPID_F4 0x413
+#define STM32_CHIPID_F1_HIGH 0x414
+#define STM32_CHIPID_L4 0x415 /* Seen on L4x6 (RM0351) */
+#define STM32_CHIPID_L1_MEDIUM 0x416
+#define STM32_CHIPID_L0 0x417
+#define STM32_CHIPID_F1_CONN 0x418
+#define STM32_CHIPID_F4_HD 0x419
+#define STM32_CHIPID_F1_VL_MEDIUM_LOW 0x420
+
+#define STM32_CHIPID_F446 0x421
+#define STM32_CHIPID_F3 0x422
+#define STM32_CHIPID_F4_LP 0x423
+
+#define STM32_CHIPID_F411RE 0x431
+
+#define STM32_CHIPID_L1_MEDIUM_PLUS 0x427
+#define STM32_CHIPID_F1_VL_HIGH 0x428
+#define STM32_CHIPID_L1_CAT2 0x429
+
+#define STM32_CHIPID_F1_XL 0x430
+
+#define STM32_CHIPID_F37x 0x432
+#define STM32_CHIPID_F4_DE 0x433
+#define STM32_CHIPID_F4_DE 0x433
+
+#define STM32_CHIPID_F4_DSI 0x434
+
+#define STM32_CHIPID_L1_HIGH 0x436
+#define STM32_CHIPID_L152_RE 0x437
+#define STM32_CHIPID_F334 0x438
+
+#define STM32_CHIPID_F3_SMALL 0x439
+#define STM32_CHIPID_F0 0x440
+#define STM32_CHIPID_F09X 0x442
+#define STM32_CHIPID_F0_SMALL 0x444
+
+#define STM32_CHIPID_F04 0x445
+
+#define STM32_CHIPID_F303_HIGH 0x446
+
+#define STM32_CHIPID_F0_CAN 0x448
+
+#define STM32_CHIPID_F7 0x449
+
+ /*
+ * 0x436 is actually assigned to some L1 chips that are called "Medium-Plus"
+ * and some that are called "High". 0x427 is assigned to the other "Medium-
+ * plus" chips. To make it a bit simpler we just call 427 MEDIUM_PLUS and
+ * 0x436 HIGH.
+ */
+
+ // Constant STM32 memory map figures
+#define STM32_FLASH_BASE 0x08000000
+#define STM32_SRAM_BASE 0x20000000
+
+ /* Cortex™-M3 Technical Reference Manual */
+ /* Debug Halting Control and Status Register */
+#define DHCSR 0xe000edf0
+#define DCRSR 0xe000edf4
+#define DCRDR 0xe000edf8
+#define DBGKEY 0xa05f0000
+
+ /* Enough space to hold both a V2 command or a V1 command packaged as generic scsi*/
+#define C_BUF_LEN 32
+
+ enum flash_type {
+ FLASH_TYPE_UNKNOWN = 0,
+ FLASH_TYPE_F0,
+ FLASH_TYPE_L0,
+ FLASH_TYPE_F4,
+ FLASH_TYPE_L4,
+ };
+
+ typedef struct chip_params_ {
+ uint32_t chip_id;
+ char* description;
+ enum flash_type flash_type;
+ uint32_t flash_size_reg;
+ uint32_t flash_pagesize;
+ uint32_t sram_size;
+ uint32_t bootrom_base, bootrom_size;
+ } chip_params_t;
+
+
+ // These maps are from a combination of the Programming Manuals, and
+ // also the Reference manuals. (flash size reg is normally in ref man)
+ static const chip_params_t devices[] = {
+ {
+ //RM0385 and DS10916 document was used to find these paramaters
+ .chip_id = STM32_CHIPID_F7,
+ .description = "F7 device",
+ .flash_type = FLASH_TYPE_F4,
+ .flash_size_reg = 0x1ff0f442, // section 41.2
+ .flash_pagesize = 0x800, // No flash pages
+ .sram_size = 0x50000, // "SRAM" byte size in hex from DS Fig 18
+ .bootrom_base = 0x00100000, // "System memory" starting address from DS Fig 18
+ .bootrom_size = 0xEDC0 // "System memory" byte size in hex from DS Fig 18
+ },
+ { // table 2, PM0063
+ .chip_id = STM32_CHIPID_F1_MEDIUM,
+ .description = "F1 Medium-density device",
+ .flash_type = FLASH_TYPE_F0,
+ .flash_size_reg = 0x1ffff7e0,
+ .flash_pagesize = 0x400,
+ .sram_size = 0x5000,
+ .bootrom_base = 0x1ffff000,
+ .bootrom_size = 0x800
+ },
+ { // table 1, PM0059
+ .chip_id = STM32_CHIPID_F2,
+ .description = "F2 device",
+ .flash_type = FLASH_TYPE_F4,
+ .flash_size_reg = 0x1fff7a22, /* As in RM0033 Rev 5*/
+ .flash_pagesize = 0x20000,
+ .sram_size = 0x20000,
+ .bootrom_base = 0x1fff0000,
+ .bootrom_size = 0x7800
+ },
+ { // PM0063
+ .chip_id = STM32_CHIPID_F1_LOW,
+ .description = "F1 Low-density device",
+ .flash_type = FLASH_TYPE_F0,
+ .flash_size_reg = 0x1ffff7e0,
+ .flash_pagesize = 0x400,
+ .sram_size = 0x2800,
+ .bootrom_base = 0x1ffff000,
+ .bootrom_size = 0x800
+ },
+ {
+ .chip_id = STM32_CHIPID_F4,
+ .description = "F4 device",
+ .flash_type = FLASH_TYPE_F4,
+ .flash_size_reg = 0x1FFF7A22, /* As in rm0090 since Rev 2*/
+ .flash_pagesize = 0x4000,
+ .sram_size = 0x30000,
+ .bootrom_base = 0x1fff0000,
+ .bootrom_size = 0x7800
+ },
+ {
+ .chip_id = STM32_CHIPID_F4_DSI,
+ .description = "F46x and F47x device",
+ .flash_type = FLASH_TYPE_F4,
+ .flash_size_reg = 0x1FFF7A22, /* As in rm0090 since Rev 2*/
+ .flash_pagesize = 0x4000,
+ .sram_size = 0x40000,
+ .bootrom_base = 0x1fff0000,
+ .bootrom_size = 0x7800
+ },
+ {
+ .chip_id = STM32_CHIPID_F4_HD,
+ .description = "F42x and F43x device",
+ .flash_type = FLASH_TYPE_F4,
+ .flash_size_reg = 0x1FFF7A22, /* As in rm0090 since Rev 2*/
+ .flash_pagesize = 0x4000,
+ .sram_size = 0x40000,
+ .bootrom_base = 0x1fff0000,
+ .bootrom_size = 0x7800
+ },
+ {
+ .chip_id = STM32_CHIPID_F4_LP,
+ .description = "F4 device (low power)",
+ .flash_type = FLASH_TYPE_F4,
+ .flash_size_reg = 0x1FFF7A22,
+ .flash_pagesize = 0x4000,
+ .sram_size = 0x10000,
+ .bootrom_base = 0x1fff0000,
+ .bootrom_size = 0x7800
+ },
+ {
+ .chip_id = STM32_CHIPID_F411RE,
+ .description = "F4 device (low power) - stm32f411re",
+ .flash_type = FLASH_TYPE_F4,
+ .flash_size_reg = 0x1FFF7A22,
+ .flash_pagesize = 0x4000,
+ .sram_size = 0x20000,
+ .bootrom_base = 0x1fff0000,
+ .bootrom_size = 0x7800
+ },
+ {
+ .chip_id = STM32_CHIPID_F4_DE,
+ .description = "F4 device (Dynamic Efficency)",
+ .flash_type = FLASH_TYPE_F4,
+ .flash_size_reg = 0x1FFF7A22,
+ .flash_pagesize = 0x4000,
+ .sram_size = 0x18000,
+ .bootrom_base = 0x1fff0000,
+ .bootrom_size = 0x7800
+ },
+ {
+ .chip_id = STM32_CHIPID_F1_HIGH,
+ .description = "F1 High-density device",
+ .flash_type = FLASH_TYPE_F0,
+ .flash_size_reg = 0x1ffff7e0,
+ .flash_pagesize = 0x800,
+ .sram_size = 0x10000,
+ .bootrom_base = 0x1ffff000,
+ .bootrom_size = 0x800
+ },
+ {
+ // This ignores the EEPROM! (and uses the page erase size,
+ // not the sector write protection...)
+ .chip_id = STM32_CHIPID_L1_MEDIUM,
+ .description = "L1 Med-density device",
+ .flash_type = FLASH_TYPE_L0,
+ .flash_size_reg = 0x1ff8004c,
+ .flash_pagesize = 0x100,
+ .sram_size = 0x4000,
+ .bootrom_base = 0x1ff00000,
+ .bootrom_size = 0x1000
+ },
+ {
+ .chip_id = STM32_CHIPID_L1_CAT2,
+ .description = "L1 Cat.2 device",
+ .flash_type = FLASH_TYPE_L0,
+ .flash_size_reg = 0x1ff8004c,
+ .flash_pagesize = 0x100,
+ .sram_size = 0x8000,
+ .bootrom_base = 0x1ff00000,
+ .bootrom_size = 0x1000
+ },
+ {
+ .chip_id = STM32_CHIPID_L1_MEDIUM_PLUS,
+ .description = "L1 Medium-Plus-density device",
+ .flash_type = FLASH_TYPE_L0,
+ .flash_size_reg = 0x1ff800cc,
+ .flash_pagesize = 0x100,
+ .sram_size = 0x8000,/*Not completely clear if there are some with 48K*/
+ .bootrom_base = 0x1ff00000,
+ .bootrom_size = 0x1000
+ },
+ {
+ .chip_id = STM32_CHIPID_L1_HIGH,
+ .description = "L1 High-density device",
+ .flash_type = FLASH_TYPE_L0,
+ .flash_size_reg = 0x1ff800cc,
+ .flash_pagesize = 0x100,
+ .sram_size = 0xC000, /*Not completely clear if there are some with 32K*/
+ .bootrom_base = 0x1ff00000,
+ .bootrom_size = 0x1000
+ },
+ {
+ .chip_id = STM32_CHIPID_L152_RE,
+ .description = "L152RE",
+ .flash_type = FLASH_TYPE_L0,
+ .flash_size_reg = 0x1ff800cc,
+ .flash_pagesize = 0x100,
+ .sram_size = 0x14000, /*Not completely clear if there are some with 32K*/
+ .bootrom_base = 0x1ff00000,
+ .bootrom_size = 0x1000
+ },
+ {
+ .chip_id = STM32_CHIPID_F1_CONN,
+ .description = "F1 Connectivity line device",
+ .flash_type = FLASH_TYPE_F0,
+ .flash_size_reg = 0x1ffff7e0,
+ .flash_pagesize = 0x800,
+ .sram_size = 0x10000,
+ .bootrom_base = 0x1fffb000,
+ .bootrom_size = 0x4800
+ },
+ {//Low and Medium density VL have same chipid. RM0041 25.6.1
+ .chip_id = STM32_CHIPID_F1_VL_MEDIUM_LOW,
+ .description = "F1 Medium/Low-density Value Line device",
+ .flash_type = FLASH_TYPE_F0,
+ .flash_size_reg = 0x1ffff7e0,
+ .flash_pagesize = 0x400,
+ .sram_size = 0x2000,//0x1000 for low density devices
+ .bootrom_base = 0x1ffff000,
+ .bootrom_size = 0x800
+ },
+ {
+ // STM32F446x family. Support based on DM00135183.pdf (RM0390) document.
+ .chip_id = STM32_CHIPID_F446,
+ .description = "F446 device",
+ .flash_type = FLASH_TYPE_F4,
+ .flash_size_reg = 0x1fff7a22,
+ .flash_pagesize = 0x20000,
+ .sram_size = 0x20000,
+ .bootrom_base = 0x1fff0000,
+ .bootrom_size = 0x7800
+ },
+ {
+ // This is STK32F303VCT6 device from STM32 F3 Discovery board.
+ // Support based on DM00043574.pdf (RM0316) document.
+ .chip_id = STM32_CHIPID_F3,
+ .description = "F3 device",
+ .flash_type = FLASH_TYPE_F0,
+ .flash_size_reg = 0x1ffff7cc,
+ .flash_pagesize = 0x800,
+ .sram_size = 0xa000,
+ .bootrom_base = 0x1ffff000,
+ .bootrom_size = 0x800
+ },
+ {
+ // This is STK32F373VCT6 device from STM32 F373 eval board
+ // Support based on 303 above (37x and 30x have same memory map)
+ .chip_id = STM32_CHIPID_F37x,
+ .description = "F3 device",
+ .flash_type = FLASH_TYPE_F0,
+ .flash_size_reg = 0x1ffff7cc,
+ .flash_pagesize = 0x800,
+ .sram_size = 0xa000,
+ .bootrom_base = 0x1ffff000,
+ .bootrom_size = 0x800
+ },
+ {
+ .chip_id = STM32_CHIPID_F1_VL_HIGH,
+ .description = "F1 High-density value line device",
+ .flash_type = FLASH_TYPE_F0,
+ .flash_size_reg = 0x1ffff7e0,
+ .flash_pagesize = 0x800,
+ .sram_size = 0x8000,
+ .bootrom_base = 0x1ffff000,
+ .bootrom_size = 0x800
+ },
+ {
+ .chip_id = STM32_CHIPID_F1_XL,
+ .description = "F1 XL-density device",
+ .flash_type = FLASH_TYPE_F0,
+ .flash_size_reg = 0x1ffff7e0,
+ .flash_pagesize = 0x800,
+ .sram_size = 0x18000,
+ .bootrom_base = 0x1fffe000,
+ .bootrom_size = 0x1800
+ },
+ {
+ //Use this as an example for mapping future chips:
+ //RM0091 document was used to find these paramaters
+ .chip_id = STM32_CHIPID_F0_CAN,
+ .description = "F07x device",
+ .flash_type = FLASH_TYPE_F0,
+ .flash_size_reg = 0x1ffff7cc, // "Flash size data register" (pg735)
+ .flash_pagesize = 0x800, // Page sizes listed in Table 4
+ .sram_size = 0x4000, // "SRAM" byte size in hex from Table 2
+ .bootrom_base = 0x1fffC800, // "System memory" starting address from Table 2
+ .bootrom_size = 0x3000 // "System memory" byte size in hex from Table 2
+ },
+ {
+ //Use this as an example for mapping future chips:
+ //RM0091 document was used to find these paramaters
+ .chip_id = STM32_CHIPID_F0,
+ .description = "F0 device",
+ .flash_type = FLASH_TYPE_F0,
+ .flash_size_reg = 0x1ffff7cc, // "Flash size data register" (pg735)
+ .flash_pagesize = 0x400, // Page sizes listed in Table 4
+ .sram_size = 0x2000, // "SRAM" byte size in hex from Table 2
+ .bootrom_base = 0x1fffec00, // "System memory" starting address from Table 2
+ .bootrom_size = 0xC00 // "System memory" byte size in hex from Table 2
+ },
+ {
+ .chip_id = STM32_CHIPID_F09X,
+ .description = "F09X device",
+ .flash_type = FLASH_TYPE_F0,
+ .flash_size_reg = 0x1ffff7cc, // "Flash size data register" (pg735)
+ .flash_pagesize = 0x800, // Page sizes listed in Table 4 (pg 56)
+ .sram_size = 0x8000, // "SRAM" byte size in hex from Table 2 (pg 50)
+ .bootrom_base = 0x1fffd800, // "System memory" starting address from Table 2
+ .bootrom_size = 0x2000 // "System memory" byte size in hex from Table 2
+ },
+ {
+ //Use this as an example for mapping future chips:
+ //RM0091 document was used to find these paramaters
+ .chip_id = STM32_CHIPID_F04,
+ .description = "F04x device",
+ .flash_type = FLASH_TYPE_F0,
+ .flash_size_reg = 0x1ffff7cc, // "Flash size data register" (pg735)
+ .flash_pagesize = 0x400, // Page sizes listed in Table 4
+ .sram_size = 0x1800, // "SRAM" byte size in hex from Table 2
+ .bootrom_base = 0x1fffec00, // "System memory" starting address from Table 2
+ .bootrom_size = 0xC00 // "System memory" byte size in hex from Table 2
+ },
+ {
+ //Use this as an example for mapping future chips:
+ //RM0091 document was used to find these paramaters
+ .chip_id = STM32_CHIPID_F0_SMALL,
+ .description = "F0 small device",
+ .flash_type = FLASH_TYPE_F0,
+ .flash_size_reg = 0x1ffff7cc, // "Flash size data register" (pg735)
+ .flash_pagesize = 0x400, // Page sizes listed in Table 4
+ .sram_size = 0x1000, // "SRAM" byte size in hex from Table 2
+ .bootrom_base = 0x1fffec00, // "System memory" starting address from Table 2
+ .bootrom_size = 0xC00 // "System memory" byte size in hex from Table 2
+ },
+ {
+ // STM32F30x
+ .chip_id = STM32_CHIPID_F3_SMALL,
+ .description = "F3 small device",
+ .flash_type = FLASH_TYPE_F0,
+ .flash_size_reg = 0x1ffff7cc,
+ .flash_pagesize = 0x800,
+ .sram_size = 0xa000,
+ .bootrom_base = 0x1fffd800,
+ .bootrom_size = 0x2000
+ },
+ {
+ // STM32L0x
+ // RM0367,RM0377 documents was used to find these parameters
+ .chip_id = STM32_CHIPID_L0,
+ .description = "L0x3 device",
+ .flash_type = FLASH_TYPE_L0,
+ .flash_size_reg = 0x1ff8007c,
+ .flash_pagesize = 0x80,
+ .sram_size = 0x2000,
+ .bootrom_base = 0x1ff0000,
+ .bootrom_size = 0x1000
+ },
+ {
+ // STM32F334
+ // RM0364 document was used to find these parameters
+ .chip_id = STM32_CHIPID_F334,
+ .description = "F334 device",
+ .flash_type = FLASH_TYPE_F0,
+ .flash_size_reg = 0x1ffff7cc,
+ .flash_pagesize = 0x800,
+ .sram_size = 0x3000,
+ .bootrom_base = 0x1fffd800,
+ .bootrom_size = 0x2000
+ },
+ {
+ // This is STK32F303RET6 device from STM32 F3 Nucelo board.
+ // Support based on DM00043574.pdf (RM0316) document rev 5.
+ .chip_id = STM32_CHIPID_F303_HIGH,
+ .description = "F303 high density device",
+ .flash_type = FLASH_TYPE_F0,
+ .flash_size_reg = 0x1ffff7cc, // 34.2.1 Flash size data register
+ .flash_pagesize = 0x800, // 4.2.1 Flash memory organization
+ .sram_size = 0x10000, // 3.3 Embedded SRAM
+ .bootrom_base = 0x1fffd800, // 3.3.2 / Table 4 System Memory
+ .bootrom_size = 0x2000
+ },
+ {
+ // STM32L4x6
+ // From RM0351.
+ .chip_id = STM32_CHIPID_L4,
+ .description = "L4 device",
+ .flash_type = FLASH_TYPE_L4,
+ .flash_size_reg = 0x1fff75e0, // "Flash size data register" (sec 45.2, page 1671)
+ .flash_pagesize = 0x800, // 2K (sec 3.2, page 78; also appears in sec 3.3.1 and tables 4-6 on pages 79-81)
+ // SRAM1 is "up to" 96k in the standard Cortex-M memory map;
+ // SRAM2 is 32k mapped at at 0x10000000 (sec 2.3, page 73 for
+ // sizes; table 2, page 74 for SRAM2 location)
+ .sram_size = 0x18000,
+ .bootrom_base = 0x1fff0000, // Tables 4-6, pages 80-81 (Bank 1 system memory)
+ .bootrom_size = 0x7000 // 28k (per bank), same source as base
+ },
+
+ };
+
+
+ typedef struct {
+ 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;
+ } reg;
+
+ typedef uint32_t stm32_addr_t;
+
+ typedef struct _cortex_m3_cpuid_ {
+ uint16_t implementer_id;
+ uint16_t variant;
+ uint16_t part;
+ uint8_t revision;
+ } cortex_m3_cpuid_t;
+
+ typedef struct stlink_version_ {
+ uint32_t stlink_v;
+ uint32_t jtag_v;
+ uint32_t swim_v;
+ uint32_t st_vid;
+ uint32_t stlink_pid;
+ } stlink_version_t;
+
+ typedef struct flash_loader {
+ stm32_addr_t loader_addr; /* loader sram adddr */
+ stm32_addr_t buf_addr; /* buffer sram address */
+ } flash_loader_t;
+
+ enum transport_type {
+ TRANSPORT_TYPE_ZERO = 0,
+ TRANSPORT_TYPE_LIBSG,
+ TRANSPORT_TYPE_LIBUSB,
+ TRANSPORT_TYPE_INVALID
+ };
+
+ typedef struct _stlink stlink_t;
+
+ typedef struct _stlink_backend {
+ void (*close) (stlink_t * sl);
+ int (*exit_debug_mode) (stlink_t * sl);
+ int (*enter_swd_mode) (stlink_t * sl);
+ int (*enter_jtag_mode) (stlink_t * stl);
+ int (*exit_dfu_mode) (stlink_t * stl);
+ int (*core_id) (stlink_t * stl);
+ int (*reset) (stlink_t * stl);
+ int (*jtag_reset) (stlink_t * stl, int value);
+ int (*run) (stlink_t * stl);
+ int (*status) (stlink_t * stl);
+ int (*version) (stlink_t *sl);
+ int (*read_debug32) (stlink_t *sl, uint32_t addr, uint32_t *data);
+ int (*read_mem32) (stlink_t *sl, uint32_t addr, uint16_t len);
+ int (*write_debug32) (stlink_t *sl, uint32_t addr, uint32_t data);
+ int (*write_mem32) (stlink_t *sl, uint32_t addr, uint16_t len);
+ int (*write_mem8) (stlink_t *sl, uint32_t addr, uint16_t len);
+ int (*read_all_regs) (stlink_t *sl, reg * regp);
+ int (*read_reg) (stlink_t *sl, int r_idx, reg * regp);
+ int (*read_all_unsupported_regs) (stlink_t *sl, reg *regp);
+ int (*read_unsupported_reg) (stlink_t *sl, int r_idx, reg *regp);
+ int (*write_unsupported_reg) (stlink_t *sl, uint32_t value, int idx, reg *regp);
+ int (*write_reg) (stlink_t *sl, uint32_t reg, int idx);
+ int (*step) (stlink_t * stl);
+ int (*current_mode) (stlink_t * stl);
+ int (*force_debug) (stlink_t *sl);
+ int32_t (*target_voltage) (stlink_t *sl);
+ } stlink_backend_t;
+
+ 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];
+ int q_len;
+
+ // transport layer verboseness: 0 for no debug info, 10 for lots
+ int verbose;
+ uint32_t core_id;
+ uint32_t chip_id;
+ int core_stat;
+
+ char serial[16];
+ int serial_size;
+
+#define STM32_FLASH_PGSZ 1024
+#define STM32L_FLASH_PGSZ 256
+
+#define STM32F4_FLASH_PGSZ 16384
+#define STM32F4_FLASH_SIZE (128 * 1024 * 8)
+
+ enum flash_type flash_type;
+ stm32_addr_t flash_base;
+ size_t flash_size;
+ size_t flash_pgsz;
+
+ /* sram settings */
+#define STM32_SRAM_SIZE (8 * 1024)
+#define STM32L_SRAM_SIZE (16 * 1024)
+ stm32_addr_t sram_base;
+ size_t sram_size;
+
+ // bootloader
+ stm32_addr_t sys_base;
+ size_t sys_size;
+
+ struct stlink_version_ version;
+ };
+
+ //stlink_t* stlink_quirk_open(const char *dev_name, const int verbose);
+
+ // delegated functions...
+ int stlink_enter_swd_mode(stlink_t *sl);
+ int stlink_enter_jtag_mode(stlink_t *sl);
+ int stlink_exit_debug_mode(stlink_t *sl);
+ int stlink_exit_dfu_mode(stlink_t *sl);
+ void stlink_close(stlink_t *sl);
+ int stlink_core_id(stlink_t *sl);
+ int stlink_reset(stlink_t *sl);
+ int stlink_jtag_reset(stlink_t *sl, int value);
+ int stlink_run(stlink_t *sl);
+ int stlink_status(stlink_t *sl);
+ int stlink_version(stlink_t *sl);
+ int stlink_read_debug32(stlink_t *sl, uint32_t addr, uint32_t *data);
+ int stlink_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len);
+ int stlink_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data);
+ int stlink_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len);
+ int stlink_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len);
+ int stlink_read_all_regs(stlink_t *sl, reg *regp);
+ int stlink_read_all_unsupported_regs(stlink_t *sl, reg *regp);
+ int stlink_read_reg(stlink_t *sl, int r_idx, reg *regp);
+ int stlink_read_unsupported_reg(stlink_t *sl, int r_idx, reg *regp);
+ int stlink_write_unsupported_reg(stlink_t *sl, uint32_t value, int r_idx, reg *regp);
+ int stlink_write_reg(stlink_t *sl, uint32_t reg, int idx);
+ int stlink_step(stlink_t *sl);
+ int stlink_current_mode(stlink_t *sl);
+ int stlink_force_debug(stlink_t *sl);
+ int stlink_target_voltage(stlink_t *sl);
+
+
+ // unprocessed
+ int stlink_erase_flash_mass(stlink_t* sl);
+ int stlink_write_flash(stlink_t* sl, stm32_addr_t address, uint8_t* data, uint32_t length, uint8_t eraseonly);
+ int stlink_fwrite_flash(stlink_t *sl, const char* path, stm32_addr_t addr);
+ int stlink_fwrite_sram(stlink_t *sl, const char* path, stm32_addr_t addr);
+ int stlink_verify_write_flash(stlink_t *sl, stm32_addr_t address, uint8_t *data, uint32_t length);
+
+ // PUBLIC
+ int stlink_chip_id(stlink_t *sl, uint32_t *chip_id);
+ int stlink_cpu_id(stlink_t *sl, cortex_m3_cpuid_t *cpuid);
+
+ // privates, publics, the rest....
+ // TODO sort what is private, and what is not
+ int stlink_erase_flash_page(stlink_t* sl, stm32_addr_t flashaddr);
+ uint32_t stlink_calculate_pagesize(stlink_t *sl, uint32_t flashaddr);
+ uint16_t read_uint16(const unsigned char *c, const int pt);
+ void stlink_core_stat(stlink_t *sl);
+ void stlink_print_data(stlink_t *sl);
+ unsigned int is_bigendian(void);
+ uint32_t read_uint32(const unsigned char *c, const int pt);
+ void write_uint32(unsigned char* buf, uint32_t ui);
+ void write_uint16(unsigned char* buf, uint16_t ui);
+ unsigned int is_core_halted(stlink_t *sl);
+ int write_buffer_to_sram(stlink_t *sl, flash_loader_t* fl, const uint8_t* buf, size_t size);
+ int write_loader_to_sram(stlink_t *sl, stm32_addr_t* addr, size_t* size);
+ int stlink_fread(stlink_t* sl, const char* path, stm32_addr_t addr, size_t size);
+ int run_flash_loader(stlink_t *sl, flash_loader_t* fl, stm32_addr_t target, const uint8_t* buf, size_t size);
+ int stlink_load_device_params(stlink_t *sl);
+
+#include "stlink/sg.h"
+#include "stlink/usb.h"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* STLINK_H */
--- /dev/null
+/*
+ * Ugly, low performance, configurable level, logging "framework"
+ */
+
+#ifndef UGLYLOGGING_H
+#define UGLYLOGGING_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum ugly_loglevel {
+ UDEBUG = 90,
+ UINFO = 50,
+ UWARN = 30,
+ UERROR = 20,
+ UFATAL = 10
+};
+
+int ugly_init(int maximum_threshold);
+int ugly_log(int level, const char *tag, const char *format, ...);
+
+#define DLOG(format, args...) ugly_log(UDEBUG, __FILE__, format, ## args)
+#define ILOG(format, args...) ugly_log(UINFO, __FILE__, format, ## args)
+#define WLOG(format, args...) ugly_log(UWARN, __FILE__, format, ## args)
+#define ELOG(format, args...) ugly_log(UERROR, __FILE__, format, ## args)
+#define fatal(format, args...) ugly_log(UFATAL, __FILE__, format, ## args)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UGLYLOGGING_H */
+
--- /dev/null
+#ifndef STLINK_MMAP_H
+#define STLINK_MMAP_H
+
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#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)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ void *mmap(void *addr, size_t len, int prot, int flags, int fd, long long offset);
+ int munmap(void *addr, size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAVE_SYS_MMAN_H */
+
+#endif /* STLINK_MMAP_H */
--- /dev/null
+/*
+ * File: stlink/sg.h
+ * Author: karl
+ *
+ * Created on October 1, 2011, 11:29 PM
+ */
+
+#ifndef STLINK_SG_H
+#define STLINK_SG_H
+
+#include <libusb.h>
+#include "stlink.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ // 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;
+ unsigned ep_rep;
+ unsigned ep_req;
+
+ int sg_fd;
+ int do_scsi_pt_err;
+
+ unsigned char cdb_cmd_blk[CDB_SL];
+
+ int 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];
+
+ reg reg;
+ };
+
+ stlink_t* stlink_v1_open(const int verbose, int reset);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* STLINK_SG_H */
+
--- /dev/null
+/*
+ * File: stlink/usb.h
+ * Author: karl
+ *
+ * Created on October 1, 2011, 11:29 PM
+ */
+
+#ifndef STLINK_USB_H
+#define STLINK_USB_H
+
+#include <stdbool.h>
+#include <libusb.h>
+
+#include "stlink.h"
+#include "stlink/logging.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define STLINK_SG_SIZE 31
+#define STLINK_CMD_SIZE 16
+
+ struct stlink_libusb {
+ libusb_context* libusb_ctx;
+ libusb_device_handle* usb_handle;
+ unsigned int ep_req;
+ unsigned int ep_rep;
+ int protocoll;
+ unsigned int sg_transfer_idx;
+ unsigned int cmd_len;
+ };
+
+ /**
+ * Open a stlink
+ * @param verbose Verbosity loglevel
+ * @param reset Reset stlink programmer
+ * @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, bool reset, char serial[16]);
+ size_t stlink_probe_usb(stlink_t **stdevs[]);
+ void stlink_probe_usb_free(stlink_t **stdevs[], size_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* STLINK_USB_H */
+
+++ /dev/null
-#ifdef __MINGW32__
-
-#include "mingw.h"
-
-#undef socket
-#undef connect
-#undef accept
-#undef shutdown
-
-#include <string.h>
-#include <errno.h>
-#include <assert.h>
-
-int win32_poll(struct pollfd *fds, unsigned int nfds, int timo)
-{
- struct timeval timeout, *toptr;
- fd_set ifds, ofds, efds, *ip, *op;
- unsigned int i, rc;
-
- /* 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);
- }
-
- /* 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) {
- int 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(int winsock_err)
-{
- switch(winsock_err) {
- case WSAEINVAL:
- case WSAEALREADY:
- case WSAEWOULDBLOCK:
- errno = EINPROGRESS;
- break;
- default:
- errno = winsock_err;
- break;
- }
-}
-
-static void
-set_socket_errno(int 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(int domain, int type, int 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.
- */
-int
-win32_connect(SOCKET fd, struct sockaddr *addr, socklen_t addr_len)
-{
- int 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 = -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.
- */
-int
-win32_shutdown(SOCKET fd, int mode)
-{
- int rc = shutdown(fd, mode);
- assert(rc == 0 || rc == SOCKET_ERROR);
- if(rc == SOCKET_ERROR) {
- set_socket_errno(WSAGetLastError());
- }
- return rc;
-}
-
-int win32_close_socket(SOCKET fd)
-{
- int rc = closesocket(fd);
- if(rc == SOCKET_ERROR) {
- set_socket_errno(WSAGetLastError());
- }
- return rc;
-}
-
-ssize_t win32_write_socket(SOCKET fd, void *buf, int n)
-{
- int 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, int n)
-{
- int 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 int 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);
- }
- /* NOTREACHED */
-}
-
-char *win32_strsep (char **stringp, const char *delim)
-{
- register char *s;
- register const char *spanp;
- register int 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);
- }
- /* NOTREACHED */
-}
-
-#endif
-
-
+++ /dev/null
-#ifdef __MINGW32__
-
-#include <io.h>
-
-#define _USE_W32_SOCKETS 1
-#include <windows.h>
-
-#define ENOTCONN WSAENOTCONN
-#define EWOULDBLOCK WSAEWOULDBLOCK
-#define ENOBUFS WSAENOBUFS
-#define ECONNRESET WSAECONNRESET
-#define ESHUTDOWN WSAESHUTDOWN
-#define EAFNOSUPPORT WSAEAFNOSUPPORT
-#define EPROTONOSUPPORT WSAEPROTONOSUPPORT
-#define EINPROGRESS WSAEINPROGRESS
-#define EISCONN WSAEISCONN
-
-/* winsock doesn't feature poll(), so there is a version implemented
- * in terms of select() in mingw.c. The following definitions
- * are copied from linux man pages. A poll() macro is defined to
- * call the version in mingw.c.
- */
-#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 */
- short events; /* requested events */
- short revents; /* returned events */
-};
-#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 int instead of the usual socklen_t */
-typedef int socklen_t;
-
-int win32_poll(struct pollfd *, unsigned int, int);
-SOCKET win32_socket(int, int, int);
-int win32_connect(SOCKET, struct sockaddr*, socklen_t);
-SOCKET win32_accept(SOCKET, struct sockaddr*, socklen_t *);
-int win32_shutdown(SOCKET, int);
-int win32_close_socket(SOCKET fd);
-
-#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, int n);
-ssize_t win32_write_socket(SOCKET fd, void *buf, int n);
-
-static inline void sleep(unsigned ms) { Sleep(ms); }
-
-#endif
--- /dev/null
+#define DEBUG_FLASH 0
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "stlink.h"
+#include "stlink/mmap.h"
+#include "stlink/logging.h"
+
+#ifndef _WIN32
+#define O_BINARY 0
+#endif
+
+/* todo: stm32l15xxx flash memory, pm0062 manual */
+
+/* stm32f FPEC flash controller interface, pm0063 manual */
+// TODO - all of this needs to be abstracted out....
+// STM32F05x is identical, based on RM0091 (DM00031936, Doc ID 018940 Rev 2, August 2012)
+#define FLASH_REGS_ADDR 0x40022000
+#define FLASH_REGS_SIZE 0x28
+
+#define FLASH_ACR (FLASH_REGS_ADDR + 0x00)
+#define FLASH_KEYR (FLASH_REGS_ADDR + 0x04)
+#define FLASH_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)
+
+// For STM32F05x, the RDPTR_KEY may be wrong, but as it is not used anywhere...
+#define FLASH_RDPTR_KEY 0x00a5
+#define FLASH_KEY1 0x45670123
+#define FLASH_KEY2 0xcdef89ab
+
+#define FLASH_SR_BSY 0
+#define FLASH_SR_EOP 5
+
+#define FLASH_CR_PG 0
+#define FLASH_CR_PER 1
+#define FLASH_CR_MER 2
+#define FLASH_CR_STRT 6
+#define FLASH_CR_LOCK 7
+
+
+//32L = 32F1 same CoreID as 32F4!
+#define STM32L_FLASH_REGS_ADDR ((uint32_t)0x40023c00)
+#define STM32L_FLASH_ACR (STM32L_FLASH_REGS_ADDR + 0x00)
+#define STM32L_FLASH_PECR (STM32L_FLASH_REGS_ADDR + 0x04)
+#define STM32L_FLASH_PDKEYR (STM32L_FLASH_REGS_ADDR + 0x08)
+#define STM32L_FLASH_PEKEYR (STM32L_FLASH_REGS_ADDR + 0x0c)
+#define STM32L_FLASH_PRGKEYR (STM32L_FLASH_REGS_ADDR + 0x10)
+#define STM32L_FLASH_OPTKEYR (STM32L_FLASH_REGS_ADDR + 0x14)
+#define STM32L_FLASH_SR (STM32L_FLASH_REGS_ADDR + 0x18)
+#define STM32L_FLASH_OBR (STM32L_FLASH_REGS_ADDR + 0x1c)
+#define STM32L_FLASH_WRPR (STM32L_FLASH_REGS_ADDR + 0x20)
+#define FLASH_L1_FPRG 10
+#define FLASH_L1_PROG 3
+
+//32L4 register base is at FLASH_REGS_ADDR (0x40022000)
+#define STM32L4_FLASH_KEYR (FLASH_REGS_ADDR + 0x08)
+#define STM32L4_FLASH_SR (FLASH_REGS_ADDR + 0x10)
+#define STM32L4_FLASH_CR (FLASH_REGS_ADDR + 0x14)
+#define STM32L4_FLASH_OPTR (FLASH_REGS_ADDR + 0x20)
+
+#define STM32L4_FLASH_SR_BSY 16
+#define STM32L4_FLASH_SR_ERRMASK 0x3f8 /* SR [9:3] */
+
+#define STM32L4_FLASH_CR_LOCK 31 /* Lock control register */
+#define STM32L4_FLASH_CR_PG 0 /* Program */
+#define STM32L4_FLASH_CR_PER 1 /* Page erase */
+#define STM32L4_FLASH_CR_MER1 2 /* Bank 1 erase */
+#define STM32L4_FLASH_CR_MER2 15 /* Bank 2 erase */
+#define STM32L4_FLASH_CR_STRT 16 /* Start command */
+#define STM32L4_FLASH_CR_BKER 11 /* Bank select for page erase */
+#define STM32L4_FLASH_CR_PNB 3 /* Page number (8 bits) */
+// Bits requesting flash operations (useful when we want to clear them)
+#define STM32L4_FLASH_CR_OPBITS \
+ ((1lu<<STM32L4_FLASH_CR_PG) | (1lu<<STM32L4_FLASH_CR_PER) \
+ | (1lu<<STM32L4_FLASH_CR_MER1) | (1lu<<STM32L4_FLASH_CR_MER1))
+// Page is fully specified by BKER and PNB
+#define STM32L4_FLASH_CR_PAGEMASK (0x1fflu << STM32L4_FLASH_CR_PNB)
+
+#define STM32L4_FLASH_OPTR_DUALBANK 21
+
+//STM32L0x flash register base and offsets
+//same as 32L1 above
+// RM0090 - DM00031020.pdf
+#define STM32L0_FLASH_REGS_ADDR ((uint32_t)0x40022000)
+#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)
+
+
+
+//STM32F4
+#define FLASH_F4_REGS_ADDR ((uint32_t)0x40023c00)
+#define FLASH_F4_KEYR (FLASH_F4_REGS_ADDR + 0x04)
+#define FLASH_F4_OPT_KEYR (FLASH_F4_REGS_ADDR + 0x08)
+#define FLASH_F4_SR (FLASH_F4_REGS_ADDR + 0x0c)
+#define FLASH_F4_CR (FLASH_F4_REGS_ADDR + 0x10)
+#define FLASH_F4_OPT_CR (FLASH_F4_REGS_ADDR + 0x14)
+#define FLASH_F4_CR_STRT 16
+#define FLASH_F4_CR_LOCK 31
+#define FLASH_F4_CR_SER 1
+#define FLASH_F4_CR_SNB 3
+#define FLASH_F4_CR_SNB_MASK 0xf8
+#define FLASH_F4_SR_BSY 16
+
+#define L1_WRITE_BLOCK_SIZE 0x80
+#define L0_WRITE_BLOCK_SIZE 0x40
+
+void write_uint32(unsigned char* buf, uint32_t ui) {
+ if (!is_bigendian()) { // le -> le (don't swap)
+ buf[0] = ((unsigned char*) &ui)[0];
+ buf[1] = ((unsigned char*) &ui)[1];
+ buf[2] = ((unsigned char*) &ui)[2];
+ buf[3] = ((unsigned char*) &ui)[3];
+ } else {
+ buf[0] = ((unsigned char*) &ui)[3];
+ buf[1] = ((unsigned char*) &ui)[2];
+ buf[2] = ((unsigned char*) &ui)[1];
+ buf[3] = ((unsigned char*) &ui)[0];
+ }
+}
+
+void write_uint16(unsigned char* buf, uint16_t ui) {
+ if (!is_bigendian()) { // le -> le (don't swap)
+ buf[0] = ((unsigned char*) &ui)[0];
+ buf[1] = ((unsigned char*) &ui)[1];
+ } else {
+ buf[0] = ((unsigned char*) &ui)[1];
+ buf[1] = ((unsigned char*) &ui)[0];
+ }
+}
+
+uint32_t read_uint32(const unsigned char *c, const int pt) {
+ uint32_t ui;
+ char *p = (char *) &ui;
+
+ if (!is_bigendian()) { // le -> le (don't swap)
+ p[0] = c[pt + 0];
+ p[1] = c[pt + 1];
+ p[2] = c[pt + 2];
+ p[3] = c[pt + 3];
+ } else {
+ p[0] = c[pt + 3];
+ p[1] = c[pt + 2];
+ p[2] = c[pt + 1];
+ p[3] = c[pt + 0];
+ }
+ return ui;
+}
+
+static uint32_t __attribute__((unused)) read_flash_rdp(stlink_t *sl) {
+ uint32_t rdp;
+ stlink_read_debug32(sl, FLASH_WRPR, &rdp);
+ return rdp & 0xff;
+}
+
+static inline uint32_t read_flash_wrpr(stlink_t *sl) {
+ uint32_t wrpr;
+ stlink_read_debug32(sl, FLASH_WRPR, &wrpr);
+ return wrpr;
+}
+
+static inline uint32_t read_flash_obr(stlink_t *sl) {
+ uint32_t obr;
+ stlink_read_debug32(sl, FLASH_OBR, &obr);
+ return obr;
+}
+
+static inline uint32_t read_flash_cr(stlink_t *sl) {
+ uint32_t reg, res;
+
+ if (sl->flash_type == FLASH_TYPE_F4)
+ reg = FLASH_F4_CR;
+ else if (sl->flash_type == FLASH_TYPE_L4)
+ reg = STM32L4_FLASH_CR;
+ else
+ reg = FLASH_CR;
+
+ stlink_read_debug32(sl, reg, &res);
+
+#if DEBUG_FLASH
+ fprintf(stdout, "CR:0x%x\n", res);
+#endif
+ return res;
+}
+
+static inline unsigned int is_flash_locked(stlink_t *sl) {
+ /* return non zero for true */
+ uint32_t cr_lock_shift, cr = read_flash_cr(sl);
+
+ if (sl->flash_type == FLASH_TYPE_F4)
+ cr_lock_shift = FLASH_F4_CR_LOCK;
+ else if (sl->flash_type == FLASH_TYPE_L4)
+ cr_lock_shift = STM32L4_FLASH_CR_LOCK;
+ else
+ cr_lock_shift = FLASH_CR_LOCK;
+
+ return cr & (1 << cr_lock_shift);
+}
+
+static void unlock_flash(stlink_t *sl) {
+ uint32_t key_reg;
+ /* 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 == FLASH_TYPE_F4)
+ key_reg = FLASH_F4_KEYR;
+ else if (sl->flash_type == FLASH_TYPE_L4)
+ key_reg = STM32L4_FLASH_KEYR;
+ else
+ key_reg = FLASH_KEYR;
+
+ stlink_write_debug32(sl, key_reg, FLASH_KEY1);
+ stlink_write_debug32(sl, key_reg, FLASH_KEY2);
+}
+
+static int unlock_flash_if(stlink_t *sl) {
+ /* unlock flash if already locked */
+
+ if (is_flash_locked(sl)) {
+ unlock_flash(sl);
+ if (is_flash_locked(sl)) {
+ WLOG("Failed to unlock flash!\n");
+ return -1;
+ }
+ }
+ DLOG("Successfully unlocked flash\n");
+ return 0;
+}
+
+static void lock_flash(stlink_t *sl) {
+ uint32_t cr_lock_shift, cr_reg, n;
+
+ if (sl->flash_type == FLASH_TYPE_F4) {
+ cr_reg = FLASH_F4_CR;
+ cr_lock_shift = FLASH_F4_CR_LOCK;
+ } else if (sl->flash_type == FLASH_TYPE_L4) {
+ cr_reg = STM32L4_FLASH_CR;
+ cr_lock_shift = STM32L4_FLASH_CR_LOCK;
+ } else {
+ cr_reg = FLASH_CR;
+ cr_lock_shift = FLASH_CR_LOCK;
+ }
+
+ n = read_flash_cr(sl) | (1 << cr_lock_shift);
+ stlink_write_debug32(sl, cr_reg, n);
+}
+
+
+static void set_flash_cr_pg(stlink_t *sl) {
+ uint32_t cr_reg, x;
+
+ x = read_flash_cr(sl);
+
+ if (sl->flash_type == FLASH_TYPE_F4) {
+ cr_reg = FLASH_F4_CR;
+ x |= 1 << FLASH_CR_PG;
+ } else if (sl->flash_type == FLASH_TYPE_L4) {
+ cr_reg = STM32L4_FLASH_CR;
+ x &= ~STM32L4_FLASH_CR_OPBITS;
+ x |= 1 << STM32L4_FLASH_CR_PG;
+ } else {
+ cr_reg = FLASH_CR;
+ x = 1 << FLASH_CR_PG;
+ }
+
+ stlink_write_debug32(sl, cr_reg, x);
+}
+
+static void __attribute__((unused)) clear_flash_cr_pg(stlink_t *sl) {
+ uint32_t cr_reg, n;
+
+ if (sl->flash_type == FLASH_TYPE_F4)
+ cr_reg = FLASH_F4_CR;
+ else if (sl->flash_type == FLASH_TYPE_L4)
+ cr_reg = STM32L4_FLASH_CR;
+ else
+ cr_reg = FLASH_CR;
+
+ n = read_flash_cr(sl) & ~(1 << FLASH_CR_PG);
+ stlink_write_debug32(sl, cr_reg, n);
+}
+
+static void set_flash_cr_per(stlink_t *sl) {
+ const uint32_t n = 1 << FLASH_CR_PER;
+ stlink_write_debug32(sl, FLASH_CR, n);
+}
+
+static void __attribute__((unused)) clear_flash_cr_per(stlink_t *sl) {
+ const uint32_t n = read_flash_cr(sl) & ~(1 << FLASH_CR_PER);
+ stlink_write_debug32(sl, FLASH_CR, n);
+}
+
+static void set_flash_cr_mer(stlink_t *sl) {
+ uint32_t val, cr_reg, cr_mer;
+
+ if (sl->flash_type == FLASH_TYPE_F4) {
+ cr_reg = FLASH_F4_CR;
+ cr_mer = 1 << FLASH_CR_MER;
+ } else if (sl->flash_type == FLASH_TYPE_L4) {
+ cr_reg = STM32L4_FLASH_CR;
+ cr_mer = (1 << STM32L4_FLASH_CR_MER1) | (1 << STM32L4_FLASH_CR_MER2);
+ } else {
+ cr_reg = FLASH_CR;
+ cr_mer = 1 << FLASH_CR_MER;
+ }
+
+ stlink_read_debug32(sl, cr_reg, &val);
+ val |= cr_mer;
+ stlink_write_debug32(sl, cr_reg, val);
+}
+
+static void __attribute__((unused)) clear_flash_cr_mer(stlink_t *sl) {
+ uint32_t val, cr_reg, cr_mer;
+
+ if (sl->flash_type == FLASH_TYPE_F4) {
+ cr_reg = FLASH_F4_CR;
+ cr_mer = 1 << FLASH_CR_MER;
+ } else if (sl->flash_type == FLASH_TYPE_L4) {
+ cr_reg = STM32L4_FLASH_CR;
+ cr_mer = (1 << STM32L4_FLASH_CR_MER1) | (1 << STM32L4_FLASH_CR_MER2);
+ } else {
+ cr_reg = FLASH_CR;
+ cr_mer = 1 << FLASH_CR_MER;
+ }
+
+ stlink_read_debug32(sl, cr_reg, &val);
+ val &= ~cr_mer;
+ stlink_write_debug32(sl, cr_reg, val);
+}
+
+static void set_flash_cr_strt(stlink_t *sl) {
+ uint32_t val, cr_reg, cr_strt;
+
+ if (sl->flash_type == FLASH_TYPE_F4) {
+ cr_reg = FLASH_F4_CR;
+ cr_strt = 1 << FLASH_F4_CR_STRT;
+ } else if (sl->flash_type == FLASH_TYPE_L4) {
+ cr_reg = STM32L4_FLASH_CR;
+ cr_strt = 1 << STM32L4_FLASH_CR_STRT;
+ } else {
+ cr_reg = FLASH_CR;
+ cr_strt = 1 << FLASH_CR_STRT;
+ }
+
+ stlink_read_debug32(sl, cr_reg, &val);
+ val |= cr_strt;
+ stlink_write_debug32(sl, cr_reg, val);
+}
+
+static inline uint32_t read_flash_acr(stlink_t *sl) {
+ uint32_t acr;
+ stlink_read_debug32(sl, FLASH_ACR, &acr);
+ return acr;
+}
+
+static inline uint32_t read_flash_sr(stlink_t *sl) {
+ uint32_t res, sr_reg;
+
+ if (sl->flash_type == FLASH_TYPE_F4)
+ sr_reg = FLASH_F4_SR;
+ else if (sl->flash_type == FLASH_TYPE_L4)
+ sr_reg = STM32L4_FLASH_SR;
+ else
+ sr_reg = FLASH_SR;
+
+ stlink_read_debug32(sl, sr_reg, &res);
+
+ return res;
+}
+
+static inline unsigned int is_flash_busy(stlink_t *sl) {
+ uint32_t sr_busy_shift;
+
+ if (sl->flash_type == FLASH_TYPE_F4)
+ sr_busy_shift = FLASH_F4_SR_BSY;
+ else if (sl->flash_type == FLASH_TYPE_L4)
+ sr_busy_shift = STM32L4_FLASH_SR_BSY;
+ else
+ sr_busy_shift = FLASH_SR_BSY;
+
+ return read_flash_sr(sl) & (1 << sr_busy_shift);
+}
+
+static void wait_flash_busy(stlink_t *sl) {
+ /* todo: add some delays here */
+ while (is_flash_busy(sl))
+ ;
+}
+
+static void wait_flash_busy_progress(stlink_t *sl) {
+ int i = 0;
+ fprintf(stdout, "Mass erasing");
+ fflush(stdout);
+ while (is_flash_busy(sl)) {
+ usleep(10000);
+ i++;
+ if (i % 100 == 0) {
+ fprintf(stdout, ".");
+ fflush(stdout);
+ }
+ }
+ fprintf(stdout, "\n");
+}
+
+static inline unsigned int is_flash_eop(stlink_t *sl) {
+ return read_flash_sr(sl) & (1 << FLASH_SR_EOP);
+}
+
+static void __attribute__((unused)) clear_flash_sr_eop(stlink_t *sl) {
+ const uint32_t n = read_flash_sr(sl) & ~(1 << FLASH_SR_EOP);
+ stlink_write_debug32(sl, FLASH_SR, n);
+}
+
+static void __attribute__((unused)) wait_flash_eop(stlink_t *sl) {
+ /* todo: add some delays here */
+ while (is_flash_eop(sl) == 0)
+ ;
+}
+
+static inline void write_flash_ar(stlink_t *sl, uint32_t n) {
+ stlink_write_debug32(sl, FLASH_AR, n);
+}
+
+static inline void write_flash_cr_psiz(stlink_t *sl, uint32_t n) {
+ uint32_t x = read_flash_cr(sl);
+ x &= ~(0x03 << 8);
+ x |= (n << 8);
+#if DEBUG_FLASH
+ fprintf(stdout, "PSIZ:0x%x 0x%x\n", x, n);
+#endif
+ stlink_write_debug32(sl, FLASH_F4_CR, x);
+}
+
+
+static inline void write_flash_cr_snb(stlink_t *sl, uint32_t n) {
+ uint32_t x = read_flash_cr(sl);
+ x &= ~FLASH_F4_CR_SNB_MASK;
+ x |= (n << FLASH_F4_CR_SNB);
+ x |= (1 << FLASH_F4_CR_SER);
+#if DEBUG_FLASH
+ fprintf(stdout, "SNB:0x%x 0x%x\n", x, n);
+#endif
+ stlink_write_debug32(sl, FLASH_F4_CR, x);
+}
+
+static inline void write_flash_cr_bker_pnb(stlink_t *sl, uint32_t n) {
+ stlink_write_debug32(sl, STM32L4_FLASH_SR, 0xFFFFFFFF & ~(1<<STM32L4_FLASH_SR_BSY));
+ uint32_t x = read_flash_cr(sl);
+ x &=~ STM32L4_FLASH_CR_OPBITS;
+ x &=~ STM32L4_FLASH_CR_PAGEMASK;
+ x &= ~(1<<STM32L4_FLASH_CR_MER1);
+ x &= ~(1<<STM32L4_FLASH_CR_MER2);
+ x |= (n << STM32L4_FLASH_CR_PNB);
+ x |= (1lu << STM32L4_FLASH_CR_PER);
+#if DEBUG_FLASH
+ fprintf(stdout, "BKER:PNB:0x%x 0x%x\n", x, n);
+#endif
+ stlink_write_debug32(sl, STM32L4_FLASH_CR, x);
+}
+
+// Delegates to the backends...
+
+void stlink_close(stlink_t *sl) {
+ DLOG("*** stlink_close ***\n");
+ if (!sl)
+ return;
+ sl->backend->close(sl);
+ free(sl);
+}
+
+int stlink_exit_debug_mode(stlink_t *sl) {
+ int ret;
+
+ DLOG("*** stlink_exit_debug_mode ***\n");
+ ret = stlink_write_debug32(sl, DHCSR, DBGKEY);
+ if (ret == -1)
+ return ret;
+
+ return sl->backend->exit_debug_mode(sl);
+}
+
+int stlink_enter_swd_mode(stlink_t *sl) {
+ DLOG("*** stlink_enter_swd_mode ***\n");
+ return sl->backend->enter_swd_mode(sl);
+}
+
+// Force the core into the debug mode -> halted state.
+int stlink_force_debug(stlink_t *sl) {
+ DLOG("*** stlink_force_debug_mode ***\n");
+ return sl->backend->force_debug(sl);
+}
+
+int stlink_exit_dfu_mode(stlink_t *sl) {
+ DLOG("*** stlink_exit_dfu_mode ***\n");
+ return sl->backend->exit_dfu_mode(sl);
+}
+
+int stlink_core_id(stlink_t *sl) {
+ int ret;
+
+ DLOG("*** stlink_core_id ***\n");
+ ret = sl->backend->core_id(sl);
+ if (ret == -1) {
+ ELOG("Failed to read core_id\n");
+ return ret;
+ }
+ if (sl->verbose > 2)
+ stlink_print_data(sl);
+ DLOG("core_id = 0x%08x\n", sl->core_id);
+ return ret;
+}
+
+int stlink_chip_id(stlink_t *sl, uint32_t *chip_id) {
+ int ret;
+
+ ret = stlink_read_debug32(sl, 0xE0042000, chip_id);
+ if (ret == -1)
+ return ret;
+
+ if (*chip_id == 0)
+ ret = stlink_read_debug32(sl, 0x40015800, chip_id); //Try Corex M0 DBGMCU_IDCODE register address
+
+ return ret;
+}
+
+/**
+ * Cortex m3 tech ref manual, CPUID register description
+ * @param sl stlink context
+ * @param cpuid pointer to the result object
+ */
+int stlink_cpu_id(stlink_t *sl, cortex_m3_cpuid_t *cpuid) {
+ uint32_t raw;
+
+ if (stlink_read_debug32(sl, CM3_REG_CPUID, &raw))
+ return -1;
+
+ cpuid->implementer_id = (raw >> 24) & 0x7f;
+ cpuid->variant = (raw >> 20) & 0xf;
+ cpuid->part = (raw >> 4) & 0xfff;
+ cpuid->revision = raw & 0xf;
+ return 0;
+}
+
+/**
+ * reads and decodes the flash parameters, as dynamically as possible
+ * @param sl
+ * @return 0 for success, or -1 for unsupported core type.
+ */
+int stlink_load_device_params(stlink_t *sl) {
+ ILOG("Loading device parameters....\n");
+ const chip_params_t *params = NULL;
+ stlink_core_id(sl);
+ uint32_t chip_id;
+ uint32_t flash_size;
+
+ stlink_chip_id(sl, &chip_id);
+ sl->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 (sl->chip_id == 0x411) {
+ uint32_t cpuid;
+ stlink_read_debug32(sl, 0xE000ED00, &cpuid);
+ if ((cpuid & 0xfff0) == 0xc240)
+ sl->chip_id = 0x413;
+ }
+
+ for (size_t i = 0; i < sizeof(devices) / sizeof(devices[0]); i++) {
+ if(devices[i].chip_id == sl->chip_id) {
+ params = &devices[i];
+ break;
+ }
+ }
+ if (params == NULL) {
+ WLOG("unknown chip id! %#x\n", chip_id);
+ return -1;
+ }
+
+ if (params->flash_type == FLASH_TYPE_UNKNOWN) {
+ WLOG("Invalid flash type, please check device declaration\n");
+ return -1;
+ }
+
+
+ // 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_MEDIUM || sl->chip_id == STM32_CHIPID_L1_MEDIUM_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_HIGH) {
+ // 0 is 384k and 1 is 256k
+ if ( flash_size == 0 ) {
+ sl->flash_size = 384 * 1024;
+ } else {
+ sl->flash_size = 256 * 1024;
+ }
+ } else {
+ sl->flash_size = flash_size * 1024;
+ }
+ sl->flash_type = params->flash_type;
+ sl->flash_pgsz = params->flash_pagesize;
+ sl->sram_size = params->sram_size;
+ sl->sys_base = params->bootrom_base;
+ sl->sys_size = params->bootrom_size;
+
+ //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_MEDIUM_LOW && sl->flash_size < 64 * 1024){
+ sl->sram_size = 0x1000;
+ }
+
+ ILOG("Device connected is: %s, id %#x\n", params->description, chip_id);
+ // TODO make note of variable page size here.....
+ ILOG("SRAM size: %#x bytes (%d KiB), Flash: %#x bytes (%d KiB) in pages of %zd bytes\n",
+ sl->sram_size, sl->sram_size / 1024, sl->flash_size, sl->flash_size / 1024,
+ sl->flash_pgsz);
+ return 0;
+}
+
+int stlink_reset(stlink_t *sl) {
+ DLOG("*** stlink_reset ***\n");
+ return sl->backend->reset(sl);
+}
+
+int stlink_jtag_reset(stlink_t *sl, int value) {
+ DLOG("*** stlink_jtag_reset ***\n");
+ return sl->backend->jtag_reset(sl, value);
+}
+
+int stlink_run(stlink_t *sl) {
+ DLOG("*** stlink_run ***\n");
+ return sl->backend->run(sl);
+}
+
+int stlink_status(stlink_t *sl) {
+ int ret;
+
+ DLOG("*** stlink_status ***\n");
+ ret = sl->backend->status(sl);
+ stlink_core_stat(sl);
+
+ return ret;
+}
+
+/**
+ * Decode the version bits, originally from -sg, verified with usb
+ * @param sl stlink context, assumed to contain valid data in the buffer
+ * @param slv output parsed version object
+ */
+void _parse_version(stlink_t *sl, stlink_version_t *slv) {
+ 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;
+ return;
+}
+
+int stlink_version(stlink_t *sl) {
+ DLOG("*** looking up stlink version\n");
+ if (sl->backend->version(sl))
+ return -1;
+
+ _parse_version(sl, &sl->version);
+
+ DLOG("st vid = 0x%04x (expect 0x%04x)\n", sl->version.st_vid, USB_ST_VID);
+ DLOG("stlink pid = 0x%04x\n", sl->version.stlink_pid);
+ DLOG("stlink version = 0x%x\n", sl->version.stlink_v);
+ DLOG("jtag version = 0x%x\n", sl->version.jtag_v);
+ DLOG("swim version = 0x%x\n", sl->version.swim_v);
+ if (sl->version.jtag_v == 0) {
+ DLOG(" notice: the firmware doesn't support a jtag/swd interface\n");
+ }
+ if (sl->version.swim_v == 0) {
+ DLOG(" notice: the firmware doesn't support a swim interface\n");
+ }
+
+ return 0;
+}
+
+int stlink_target_voltage(stlink_t *sl) {
+ int voltage = -1;
+ DLOG("*** reading target voltage\n");
+ if (sl->backend->target_voltage != NULL) {
+ voltage = sl->backend->target_voltage(sl);
+ if (voltage != -1) {
+ DLOG("target voltage = %ldmV\n", voltage);
+ } else {
+ DLOG("error reading target voltage\n");
+ }
+ } else {
+ DLOG("reading voltage not supported by backend\n");
+ }
+ return voltage;
+}
+
+int stlink_read_debug32(stlink_t *sl, uint32_t addr, uint32_t *data) {
+ int ret;
+
+ ret = sl->backend->read_debug32(sl, addr, data);
+ if (!ret)
+ DLOG("*** stlink_read_debug32 %x is %#x\n", *data, addr);
+
+ return ret;
+}
+
+int stlink_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data) {
+ DLOG("*** stlink_write_debug32 %x to %#x\n", data, addr);
+ return sl->backend->write_debug32(sl, addr, data);
+}
+
+int stlink_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
+ DLOG("*** stlink_write_mem32 %u bytes to %#x\n", len, addr);
+ if (len % 4 != 0) {
+ fprintf(stderr, "Error: Data length doesn't have a 32 bit alignment: +%d byte.\n", len % 4);
+ abort();
+ }
+ return sl->backend->write_mem32(sl, addr, len);
+}
+
+int stlink_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
+ DLOG("*** stlink_read_mem32 ***\n");
+ if (len % 4 != 0) { // !!! never ever: fw gives just wrong values
+ fprintf(stderr, "Error: Data length doesn't have a 32 bit alignment: +%d byte.\n",
+ len % 4);
+ abort();
+ }
+ return sl->backend->read_mem32(sl, addr, len);
+}
+
+int stlink_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len) {
+ DLOG("*** stlink_write_mem8 ***\n");
+ if (len > 0x40 ) { // !!! never ever: Writing more then 0x40 bytes gives unexpected behaviour
+ fprintf(stderr, "Error: Data length > 64: +%d byte.\n",
+ len);
+ abort();
+ }
+ return sl->backend->write_mem8(sl, addr, len);
+}
+
+int stlink_read_all_regs(stlink_t *sl, reg *regp) {
+ DLOG("*** stlink_read_all_regs ***\n");
+ return sl->backend->read_all_regs(sl, regp);
+}
+
+int stlink_read_all_unsupported_regs(stlink_t *sl, reg *regp) {
+ DLOG("*** stlink_read_all_unsupported_regs ***\n");
+ return sl->backend->read_all_unsupported_regs(sl, regp);
+}
+
+int stlink_write_reg(stlink_t *sl, uint32_t reg, int idx) {
+ DLOG("*** stlink_write_reg\n");
+ return sl->backend->write_reg(sl, reg, idx);
+}
+
+int stlink_read_reg(stlink_t *sl, int r_idx, reg *regp) {
+ DLOG("*** stlink_read_reg\n");
+ DLOG(" (%d) ***\n", r_idx);
+
+ if (r_idx > 20 || r_idx < 0) {
+ fprintf(stderr, "Error: register index must be in [0..20]\n");
+ return -1;
+ }
+
+ return sl->backend->read_reg(sl, r_idx, regp);
+}
+
+int stlink_read_unsupported_reg(stlink_t *sl, int r_idx, reg *regp) {
+ int r_convert;
+
+ DLOG("*** stlink_read_unsupported_reg\n");
+ DLOG(" (%d) ***\n", r_idx);
+
+ /* Convert to values used by DCRSR */
+ if (r_idx >= 0x1C && r_idx <= 0x1F) { /* primask, basepri, faultmask, or control */
+ r_convert = 0x14;
+ } else if (r_idx == 0x40) { /* FPSCR */
+ r_convert = 0x21;
+ } else if (r_idx >= 0x20 && r_idx < 0x40) {
+ r_convert = 0x40 + (r_idx - 0x20);
+ } else {
+ fprintf(stderr, "Error: register address must be in [0x1C..0x40]\n");
+ return -1;
+ }
+
+ return sl->backend->read_unsupported_reg(sl, r_convert, regp);
+}
+
+int stlink_write_unsupported_reg(stlink_t *sl, uint32_t val, int r_idx, reg *regp) {
+ int r_convert;
+
+ DLOG("*** stlink_write_unsupported_reg\n");
+ DLOG(" (%d) ***\n", r_idx);
+
+ /* Convert to values used by 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);
+}
+
+unsigned int is_core_halted(stlink_t *sl) {
+ /* return non zero if core is halted */
+ stlink_status(sl);
+ return sl->q_buf[0] == STLINK_CORE_HALTED;
+}
+
+int stlink_step(stlink_t *sl) {
+ DLOG("*** stlink_step ***\n");
+ return sl->backend->step(sl);
+}
+
+int stlink_current_mode(stlink_t *sl) {
+ int mode = sl->backend->current_mode(sl);
+ switch (mode) {
+ case STLINK_DEV_DFU_MODE:
+ DLOG("stlink current mode: dfu\n");
+ return mode;
+ case STLINK_DEV_DEBUG_MODE:
+ DLOG("stlink current mode: debug (jtag or swd)\n");
+ return mode;
+ case STLINK_DEV_MASS_MODE:
+ DLOG("stlink current mode: mass\n");
+ return mode;
+ }
+ DLOG("stlink mode: unknown!\n");
+ return STLINK_DEV_UNKNOWN_MODE;
+}
+
+
+
+
+// End of delegates.... Common code below here...
+
+// Endianness
+// http://www.ibm.com/developerworks/aix/library/au-endianc/index.html
+// const int i = 1;
+// #define is_bigendian() ( (*(char*)&i) == 0 )
+
+inline unsigned int is_bigendian(void) {
+ static volatile const unsigned int i = 1;
+ return *(volatile const char*) &i == 0;
+}
+
+uint16_t read_uint16(const unsigned char *c, const int pt) {
+ uint32_t ui;
+ char *p = (char *) &ui;
+
+ if (!is_bigendian()) { // le -> le (don't swap)
+ p[0] = c[pt + 0];
+ p[1] = c[pt + 1];
+ } else {
+ p[0] = c[pt + 1];
+ p[1] = c[pt + 0];
+ }
+ return ui;
+}
+
+// same as above with entrypoint.
+
+void stlink_run_at(stlink_t *sl, stm32_addr_t addr) {
+ stlink_write_reg(sl, addr, 15); /* pc register */
+
+ stlink_run(sl);
+
+ while (is_core_halted(sl) == 0)
+ usleep(3000000);
+}
+
+void stlink_core_stat(stlink_t *sl) {
+ if (sl->q_len <= 0)
+ return;
+
+ switch (sl->q_buf[0]) {
+ case STLINK_CORE_RUNNING:
+ sl->core_stat = STLINK_CORE_RUNNING;
+ DLOG(" core status: running\n");
+ return;
+ case STLINK_CORE_HALTED:
+ sl->core_stat = STLINK_CORE_HALTED;
+ DLOG(" core status: halted\n");
+ return;
+ default:
+ sl->core_stat = STLINK_CORE_STAT_UNKNOWN;
+ fprintf(stderr, " core status: unknown\n");
+ }
+}
+
+void stlink_print_data(stlink_t * sl) {
+ if (sl->q_len <= 0 || sl->verbose < UDEBUG)
+ return;
+ if (sl->verbose > 2)
+ fprintf(stdout, "data_len = %d 0x%x\n", sl->q_len, sl->q_len);
+
+ for (int i = 0; i < sl->q_len; i++) {
+ if (i % 16 == 0) {
+ /*
+ if (sl->q_data_dir == Q_DATA_OUT)
+ fprintf(stdout, "\n<- 0x%08x ", sl->q_addr + i);
+ else
+ fprintf(stdout, "\n-> 0x%08x ", sl->q_addr + i);
+ */
+ }
+ fprintf(stdout, " %02x", (unsigned int) sl->q_buf[i]);
+ }
+ fputs("\n\n", stdout);
+}
+
+/* memory mapped file */
+
+typedef struct mapped_file {
+ uint8_t* base;
+ size_t len;
+} mapped_file_t;
+
+#define MAPPED_FILE_INITIALIZER { NULL, 0 }
+
+static int map_file(mapped_file_t* mf, const char* path) {
+ int error = -1;
+ struct stat st;
+
+ const int fd = open(path, O_RDONLY | O_BINARY);
+ if (fd == -1) {
+ fprintf(stderr, "open(%s) == -1\n", path);
+ return -1;
+ }
+
+ if (fstat(fd, &st) == -1) {
+ fprintf(stderr, "fstat() == -1\n");
+ goto on_error;
+ }
+
+ mf->base = (uint8_t*) mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ if (mf->base == MAP_FAILED) {
+ fprintf(stderr, "mmap() == MAP_FAILED\n");
+ goto on_error;
+ }
+
+ mf->len = st.st_size;
+
+ /* success */
+ error = 0;
+
+on_error:
+ close(fd);
+
+ return error;
+}
+
+static void unmap_file(mapped_file_t * mf) {
+ munmap((void*) mf->base, mf->len);
+ mf->base = (unsigned char*) MAP_FAILED;
+ mf->len = 0;
+}
+
+/* Limit the block size to compare to 0x1800
+ Anything larger will stall the STLINK2
+ Maybe STLINK V1 needs smaller value!*/
+static int check_file(stlink_t* sl, mapped_file_t* mf, stm32_addr_t addr) {
+ size_t off;
+ size_t n_cmp = sl->flash_pgsz;
+ if ( n_cmp > 0x1800)
+ n_cmp = 0x1800;
+
+ for (off = 0; off < mf->len; off += n_cmp) {
+ size_t aligned_size;
+
+ /* adjust last page size */
+ size_t cmp_size = n_cmp;
+ 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, aligned_size);
+
+ if (memcmp(sl->q_buf, mf->base + off, cmp_size))
+ return -1;
+ }
+
+ return 0;
+}
+
+int stlink_fwrite_sram
+(stlink_t * sl, const char* path, stm32_addr_t addr) {
+ /* write the file in sram at addr */
+
+ int error = -1;
+ size_t off;
+ size_t len;
+ mapped_file_t mf = MAPPED_FILE_INITIALIZER;
+ uint32_t val;
+
+
+ if (map_file(&mf, path) == -1) {
+ fprintf(stderr, "map_file() == -1\n");
+ return -1;
+ }
+
+ /* check 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) {
+ /* todo */
+ fprintf(stderr, "unaligned addr\n");
+ goto on_error;
+ }
+
+ len = mf.len;
+
+ if(len & 3) {
+ len -= len & 3;
+ }
+
+ /* do the copy by 1k blocks */
+ for (off = 0; off < len; off += 1024) {
+ size_t size = 1024;
+ if ((off + size) > len)
+ size = len - off;
+
+ memcpy(sl->q_buf, mf.base + off, size);
+
+ /* round size if needed */
+ if (size & 3)
+ size += 2;
+
+ stlink_write_mem32(sl, addr + off, size);
+ }
+
+ if(mf.len > len) {
+ memcpy(sl->q_buf, mf.base + len, mf.len - len);
+ stlink_write_mem8(sl, addr + len, mf.len - len);
+ }
+
+ /* check the file ha been written */
+ if (check_file(sl, &mf, addr) == -1) {
+ fprintf(stderr, "check_file() == -1\n");
+ goto on_error;
+ }
+
+ /* success */
+ error = 0;
+ /* set stack*/
+ stlink_read_debug32(sl, addr, &val);
+ stlink_write_reg(sl, val, 13);
+ /* Set PC to the reset routine*/
+ stlink_read_debug32(sl, addr + 4, &val);
+ stlink_write_reg(sl, val, 15);
+ stlink_run(sl);
+
+on_error:
+ unmap_file(&mf);
+ return error;
+}
+
+int stlink_fread(stlink_t* sl, const char* path, stm32_addr_t addr, size_t size) {
+ /* read size bytes from addr to file */
+
+ int error = -1;
+ size_t off;
+
+ const int fd = open(path, O_RDWR | O_TRUNC | O_CREAT, 00700);
+ if (fd == -1) {
+ fprintf(stderr, "open(%s) == -1\n", path);
+ return -1;
+ }
+
+ if (size <1)
+ size = sl->flash_size;
+
+ if (size > sl->flash_size)
+ size = sl->flash_size;
+
+ size_t cmp_size = (sl->flash_pgsz > 0x1800)? 0x1800:sl->flash_pgsz;
+ for (off = 0; off < size; off += cmp_size) {
+ size_t aligned_size;
+
+ /* adjust last page size */
+ if ((off + cmp_size) > size)
+ cmp_size = size - off;
+
+ aligned_size = cmp_size;
+ if (aligned_size & (4 - 1))
+ aligned_size = (cmp_size + 4) & ~(4 - 1);
+
+ stlink_read_mem32(sl, addr + off, aligned_size);
+
+ if (write(fd, sl->q_buf, sl->q_len) != (ssize_t) aligned_size) {
+ fprintf(stderr, "write() != aligned_size\n");
+ goto on_error;
+ }
+ }
+
+ /* success */
+ error = 0;
+
+on_error:
+ close(fd);
+
+ return error;
+}
+
+int write_buffer_to_sram(stlink_t *sl, flash_loader_t* fl, const uint8_t* buf, size_t size) {
+ /* write the buffer right after the loader */
+ size_t chunk = size & ~0x3;
+ size_t rem = size & 0x3;
+ if (chunk) {
+ memcpy(sl->q_buf, buf, chunk);
+ stlink_write_mem32(sl, fl->buf_addr, chunk);
+ }
+ if (rem) {
+ memcpy(sl->q_buf, buf+chunk, rem);
+ stlink_write_mem8(sl, (fl->buf_addr)+chunk, rem);
+ }
+ return 0;
+}
+
+uint32_t calculate_F4_sectornum(uint32_t flashaddr){
+ uint32_t offset = 0;
+ flashaddr &= ~STM32_FLASH_BASE; //Page now holding the actual flash address
+ if (flashaddr >= 0x100000) {
+ offset = 12;
+ flashaddr -= 0x100000;
+ }
+ if (flashaddr<0x4000) return (offset + 0);
+ else if(flashaddr<0x8000) return(offset + 1);
+ else if(flashaddr<0xc000) return(offset + 2);
+ else if(flashaddr<0x10000) return(offset + 3);
+ else if(flashaddr<0x20000) return(offset + 4);
+ else return offset + (flashaddr/0x20000) +4;
+
+}
+
+uint32_t calculate_F7_sectornum(uint32_t flashaddr){
+ flashaddr &= ~STM32_FLASH_BASE; //Page now holding the actual flash address
+ if(flashaddr<0x20000) return(flashaddr/0x8000);
+ else if(flashaddr<0x40000) return(4);
+ else return(flashaddr/0x40000) +4;
+
+}
+
+// Returns BKER:PNB for the given page address
+uint32_t calculate_L4_page(stlink_t *sl, uint32_t flashaddr) {
+ uint32_t bker = 0;
+ uint32_t flashopt;
+ stlink_read_debug32(sl, STM32L4_FLASH_OPTR, &flashopt);
+ flashaddr -= STM32_FLASH_BASE;
+ if (flashopt & (1lu << STM32L4_FLASH_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;
+}
+
+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_F411RE) ||
+ (sl->chip_id == STM32_CHIPID_F446) || (sl->chip_id == STM32_CHIPID_F4_DSI)) {
+ 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) {
+ 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);
+}
+
+/**
+ * Erase a page of flash, assumes sl is fully populated with things like chip/core ids
+ * @param sl stlink context
+ * @param flashaddr an address in the flash page to erase
+ * @return 0 on success -ve on failure
+ */
+int stlink_erase_flash_page(stlink_t *sl, stm32_addr_t flashaddr)
+{
+ if (sl->flash_type == FLASH_TYPE_F4 || sl->flash_type == FLASH_TYPE_L4) {
+ /* wait for ongoing op to finish */
+ wait_flash_busy(sl);
+
+ /* unlock if locked */
+ unlock_flash_if(sl);
+
+ /* select the page to erase */
+ if (sl->chip_id == STM32_CHIPID_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) {
+ // 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);
+ } 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);
+ }
+
+ /* start erase operation */
+ set_flash_cr_strt(sl);
+
+ /* wait for completion */
+ wait_flash_busy(sl);
+
+ /* relock the flash */
+ //todo: fails to program if this is in
+ lock_flash(sl);
+#if DEBUG_FLASH
+ fprintf(stdout, "Erase Final CR:0x%x\n", read_flash_cr(sl));
+#endif
+ } else if (sl->flash_type == FLASH_TYPE_L0) {
+
+ uint32_t val;
+ uint32_t flash_regs_base;
+ if (sl->chip_id == STM32_CHIPID_L0) {
+ flash_regs_base = STM32L0_FLASH_REGS_ADDR;
+ } else {
+ flash_regs_base = STM32L_FLASH_REGS_ADDR;
+ }
+
+ /* 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, 0x89abcdef);
+ stlink_write_debug32(sl, flash_regs_base + FLASH_PEKEYR_OFF, 0x02030405);
+
+ /* 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, 0x8c9daebf);
+ stlink_write_debug32(sl, flash_regs_base + FLASH_PRGKEYR_OFF, 0x13141516);
+
+ /* 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);
+#if 0 /* fix_to_be_confirmed */
+
+ /* wait for sr.busy to be cleared
+ * MP: Test shows that busy bit is not set here. Perhaps, PM0062 is
+ * wrong and we do not need to wait here for clearing the busy bit.
+ * TEXANE: ok, if experience says so and it works for you, we comment
+ * it. If someone has a problem, please drop an email.
+ */
+ do {
+ stlink_read_debug32(sl, STM32L_FLASH_SR, &val)
+ } while((val & (1 << 0)) != 0);
+
+#endif /* fix_to_be_confirmed */
+
+ /* 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.*/
+ do {
+ stlink_read_debug32(sl, flash_regs_base + FLASH_SR_OFF, &val);
+ } while ((val & (1 << 0)) != 0);
+
+ /* 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 == FLASH_TYPE_F0) {
+ /* wait for ongoing op to finish */
+ wait_flash_busy(sl);
+
+ /* unlock if locked */
+ unlock_flash_if(sl);
+
+ /* set the page erase bit */
+ set_flash_cr_per(sl);
+
+ /* select the page to erase */
+ write_flash_ar(sl, flashaddr);
+
+ /* start erase operation, reset by hw with bsy bit */
+ set_flash_cr_strt(sl);
+
+ /* wait for completion */
+ wait_flash_busy(sl);
+
+ /* relock the flash */
+ lock_flash(sl);
+ } else {
+ WLOG("unknown coreid %x, page erase failed\n", sl->core_id);
+ return -1;
+ }
+
+ /* todo: verify the erased page */
+
+ return 0;
+}
+
+int stlink_erase_flash_mass(stlink_t *sl) {
+ if (sl->flash_type == FLASH_TYPE_L0) {
+ /* erase each page */
+ int i = 0, num_pages = sl->flash_size/sl->flash_pgsz;
+ for (i = 0; i < num_pages; i++) {
+ /* addr must be an addr inside the page */
+ stm32_addr_t addr = sl->flash_base + i * sl->flash_pgsz;
+ if (stlink_erase_flash_page(sl, addr) == -1) {
+ WLOG("Failed to erase_flash_page(%#zx) == -1\n", addr);
+ return -1;
+ }
+ fprintf(stdout,"-> Flash page at %5d/%5d erased\n", i, num_pages);
+ fflush(stdout);
+ }
+ fprintf(stdout, "\n");
+ } else {
+ /* wait for ongoing op to finish */
+ wait_flash_busy(sl);
+
+ /* unlock if locked */
+ unlock_flash_if(sl);
+
+ /* set the mass erase bit */
+ set_flash_cr_mer(sl);
+
+ /* start erase operation, reset by hw with bsy bit */
+ set_flash_cr_strt(sl);
+
+ /* wait for completion */
+ wait_flash_busy_progress(sl);
+
+ /* relock the flash */
+ lock_flash(sl);
+
+ /* todo: verify the erased memory */
+ }
+ return 0;
+}
+
+int init_flash_loader(stlink_t *sl, flash_loader_t* fl) {
+ size_t size;
+
+ /* allocate the loader in sram */
+ if (write_loader_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");
+ return 0;
+}
+
+int write_loader_to_sram(stlink_t *sl, stm32_addr_t* addr, size_t* size) {
+ /* from openocd, contrib/loaders/flash/stm32.s */
+ static const uint8_t loader_code_stm32vl[] = {
+ 0x08, 0x4c, /* ldr r4, STM32_FLASH_BASE */
+ 0x1c, 0x44, /* add r4, r3 */
+ /* write_half_word: */
+ 0x01, 0x23, /* movs r3, #0x01 */
+ 0x23, 0x61, /* str r3, [r4, #STM32_FLASH_CR_OFFSET] */
+ 0x30, 0xf8, 0x02, 0x3b, /* ldrh r3, [r0], #0x02 */
+ 0x21, 0xf8, 0x02, 0x3b, /* strh r3, [r1], #0x02 */
+ /* busy: */
+ 0xe3, 0x68, /* ldr r3, [r4, #STM32_FLASH_SR_OFFSET] */
+ 0x13, 0xf0, 0x01, 0x0f, /* tst r3, #0x01 */
+ 0xfb, 0xd0, /* beq busy */
+ 0x13, 0xf0, 0x14, 0x0f, /* tst r3, #0x14 */
+ 0x01, 0xd1, /* bne exit */
+ 0x01, 0x3a, /* subs r2, r2, #0x01 */
+ 0xf0, 0xd1, /* bne write_half_word */
+ /* exit: */
+ 0x00, 0xbe, /* bkpt #0x00 */
+ 0x00, 0x20, 0x02, 0x40, /* STM32_FLASH_BASE: .word 0x40022000 */
+ };
+
+ /* flashloaders/stm32f0.s -- thumb1 only, same sequence as for STM32VL, bank ignored */
+ static const uint8_t loader_code_stm32f0[] = {
+#if 1
+ /*
+ * 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.
+ */
+ 0x00, 0x30, // nop /* add r0,#0 */
+ 0x00, 0x30, // nop /* add r0,#0 */
+#endif
+ 0x0A, 0x4C, // ldr r4, STM32_FLASH_BASE
+ 0x01, 0x25, // mov r5, #1 /* FLASH_CR_PG, FLASH_SR_BUSY */
+ 0x04, 0x26, // mov r6, #4 /* PGERR */
+ // write_half_word:
+ 0x23, 0x69, // ldr r3, [r4, #16] /* FLASH->CR */
+ 0x2B, 0x43, // orr r3, r5
+ 0x23, 0x61, // str r3, [r4, #16] /* FLASH->CR |= FLASH_CR_PG */
+ 0x03, 0x88, // ldrh r3, [r0] /* r3 = *sram */
+ 0x0B, 0x80, // strh r3, [r1] /* *flash = r3 */
+ // busy:
+ 0xE3, 0x68, // ldr r3, [r4, #12] /* FLASH->SR */
+ 0x2B, 0x42, // tst r3, r5 /* FLASH_SR_BUSY */
+ 0xFC, 0xD0, // beq busy
+
+ 0x33, 0x42, // tst r3, r6 /* PGERR */
+ 0x04, 0xD1, // bne exit
+
+ 0x02, 0x30, // add r0, r0, #2 /* sram += 2 */
+ 0x02, 0x31, // add r1, r1, #2 /* flash += 2 */
+ 0x01, 0x3A, // sub r2, r2, #0x01 /* count-- */
+ 0x00, 0x2A, // cmp r2, #0
+ 0xF0, 0xD1, // bne write_half_word
+ // exit:
+ 0x23, 0x69, // ldr r3, [r4, #16] /* FLASH->CR */
+ 0xAB, 0x43, // bic r3, r5
+ 0x23, 0x61, // str r3, [r4, #16] /* FLASH->CR &= ~FLASH_CR_PG */
+ 0x00, 0xBE, // bkpt #0x00
+ 0x00, 0x20, 0x02, 0x40, /* STM32_FLASH_BASE: .word 0x40022000 */
+ };
+
+ static const uint8_t loader_code_stm32l[] = {
+
+ /* openocd.git/contrib/loaders/flash/stm32lx.S
+ r0, input, source addr
+ r1, input, dest addr
+ r2, input, word count
+ r2, output, remaining word count
+ */
+
+ 0x04, 0xe0,
+
+ 0x50, 0xf8, 0x04, 0xcb,
+ 0x41, 0xf8, 0x04, 0xcb,
+ 0x01, 0x3a,
+
+ 0x00, 0x2a,
+ 0xf8, 0xd3,
+ 0x00, 0xbe
+ };
+
+ static const uint8_t loader_code_stm32l0[] = {
+
+ /*
+ r0, input, source addr
+ r1, input, dest addr
+ r2, input, word count
+ r2, output, remaining word count
+ */
+
+ 0x04, 0xe0,
+
+ 0x04, 0x68,
+ 0x0c, 0x60,
+ 0x01, 0x3a,
+ 0x04, 0x31,
+ 0x04, 0x30,
+
+ 0x00, 0x2a,
+ 0xf8, 0xd3,
+ 0x00, 0xbe
+ };
+
+ static const uint8_t loader_code_stm32f4[] = {
+ // flashloaders/stm32f4.s
+
+ 0x07, 0x4b,
+
+ 0x62, 0xb1,
+ 0x04, 0x68,
+ 0x0c, 0x60,
+
+ 0xdc, 0x89,
+ 0x14, 0xf0, 0x01, 0x0f,
+ 0xfb, 0xd1,
+ 0x00, 0xf1, 0x04, 0x00,
+ 0x01, 0xf1, 0x04, 0x01,
+ 0xa2, 0xf1, 0x01, 0x02,
+ 0xf1, 0xe7,
+
+ 0x00, 0xbe,
+
+ 0x00, 0x3c, 0x02, 0x40,
+ };
+
+ static const uint8_t loader_code_stm32f4_lv[] = {
+ // flashloaders/stm32f4lv.s
+ 0x92, 0x00,
+
+ 0x08, 0x4b,
+ 0x62, 0xb1,
+ 0x04, 0x78,
+ 0x0c, 0x70,
+
+ 0xdc, 0x89,
+ 0x14, 0xf0, 0x01, 0x0f,
+ 0xfb, 0xd1,
+ 0x00, 0xf1, 0x01, 0x00,
+ 0x01, 0xf1, 0x01, 0x01,
+ 0xa2, 0xf1, 0x01, 0x02,
+ 0xf1, 0xe7,
+
+ 0x00, 0xbe,
+ 0x00, 0xbf,
+
+ 0x00, 0x3c, 0x02, 0x40,
+ };
+
+ static const uint8_t loader_code_stm32l4[] = {
+ // flashloaders/stm32l4.s
+ 0x08, 0x4b, // start: ldr r3, [pc, #32] ; <flash_base>
+ 0x72, 0xb1, // next: cbz r2, <done>
+ 0x04, 0x68, // ldr r4, [r0, #0]
+ 0x45, 0x68, // ldr r5, [r0, #4]
+ 0x0c, 0x60, // str r4, [r1, #0]
+ 0x4d, 0x60, // str r5, [r1, #4]
+ 0x5c, 0x8a, // wait: ldrh r4, [r3, #18]
+ 0x14, 0xf0, 0x01, 0x0f, // tst.w r4, #1
+ 0xfb, 0xd1, // bne.n <wait>
+ 0x00, 0xf1, 0x08, 0x00, // add.w r0, r0, #8
+ 0x01, 0xf1, 0x08, 0x01, // add.w r1, r1, #8
+ 0xa2, 0xf1, 0x01, 0x02, // sub.w r2, r2, #1
+ 0xef, 0xe7, // b.n <next>
+ 0x00, 0xbe, // done: bkpt 0x0000
+ 0x00, 0x20, 0x02, 0x40 // flash_base: .word 0x40022000
+ };
+
+ static const uint8_t loader_code_stm32f7[] = {
+ 0x08, 0x4b,
+ 0x72, 0xb1,
+ 0x04, 0x68,
+ 0x0c, 0x60,
+ 0xbf, 0xf3, 0x4f, 0x8f, // DSB Memory barrier for in order flash write
+ 0xdc, 0x89,
+ 0x14, 0xf0, 0x01, 0x0f,
+ 0xfb, 0xd1,
+ 0x00, 0xf1, 0x04, 0x00,
+ 0x01, 0xf1, 0x04, 0x01,
+ 0xa2, 0xf1, 0x01, 0x02,
+ 0xef, 0xe7,
+ 0x00, 0xbe, // bkpt #0x00
+ 0x00, 0x3c, 0x02, 0x40,
+ };
+
+ const uint8_t* loader_code;
+ size_t loader_size;
+
+ if (sl->chip_id == STM32_CHIPID_L1_MEDIUM || sl->chip_id == STM32_CHIPID_L1_CAT2
+ || sl->chip_id == STM32_CHIPID_L1_MEDIUM_PLUS || sl->chip_id == STM32_CHIPID_L1_HIGH
+ || sl->chip_id == STM32_CHIPID_L152_RE) { /* stm32l */
+ loader_code = loader_code_stm32l;
+ loader_size = sizeof(loader_code_stm32l);
+ } else if (sl->core_id == STM32VL_CORE_ID
+ || sl->chip_id == STM32_CHIPID_F3
+ || sl->chip_id == STM32_CHIPID_F3_SMALL
+ || sl->chip_id == STM32_CHIPID_F303_HIGH
+ || 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_F411RE) ||
+ (sl->chip_id == STM32_CHIPID_F446) || (sl->chip_id == STM32_CHIPID_F4_DSI)){
+ int voltage = stlink_target_voltage(sl);
+ if (voltage == -1) {
+ printf("Failed to read Target voltage\n");
+ return voltage;
+ } else if (voltage > 2700) {
+ loader_code = loader_code_stm32f4;
+ loader_size = sizeof(loader_code_stm32f4);
+ } else {
+ loader_code = loader_code_stm32f4_lv;
+ loader_size = sizeof(loader_code_stm32f4_lv);
+ }
+ } else if (sl->chip_id == STM32_CHIPID_F7){
+ loader_code = loader_code_stm32f7;
+ loader_size = sizeof(loader_code_stm32f7);
+ } 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_F0_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_L0) {
+ loader_code = loader_code_stm32l0;
+ loader_size = sizeof(loader_code_stm32l0);
+ } else if (sl->chip_id == STM32_CHIPID_L4) {
+ loader_code = loader_code_stm32l4;
+ loader_size = sizeof(loader_code_stm32l4);
+ } else {
+ ELOG("unknown coreid, not sure what flash loader to use, aborting!: %x\n", sl->core_id);
+ return -1;
+ }
+
+ memcpy(sl->q_buf, loader_code, loader_size);
+ stlink_write_mem32(sl, sl->sram_base, loader_size);
+
+ *addr = sl->sram_base;
+ *size = loader_size;
+
+ /* success */
+ return 0;
+}
+
+int stlink_fcheck_flash(stlink_t *sl, const char* path, stm32_addr_t addr) {
+ /* check the contents of path are at addr */
+
+ int res;
+ mapped_file_t mf = MAPPED_FILE_INITIALIZER;
+
+ if (map_file(&mf, path) == -1)
+ return -1;
+
+ res = check_file(sl, &mf, addr);
+
+ unmap_file(&mf);
+
+ return res;
+}
+
+/**
+ * Verify addr..addr+len is binary identical to base...base+len
+ * @param sl stlink context
+ * @param address stm device address
+ * @param data host side buffer to check against
+ * @param length how much
+ * @return 0 for success, -ve for failure
+ */
+int stlink_verify_write_flash(stlink_t *sl, stm32_addr_t address, uint8_t *data, unsigned length) {
+ size_t off;
+ size_t cmp_size = (sl->flash_pgsz > 0x1800)? 0x1800:sl->flash_pgsz;
+ ILOG("Starting verification of write complete\n");
+ for (off = 0; off < length; off += cmp_size) {
+ size_t aligned_size;
+
+ /* adjust last page size */
+ if ((off + cmp_size) > length)
+ cmp_size = length - off;
+
+ aligned_size = cmp_size;
+ if (aligned_size & (4 - 1))
+ aligned_size = (cmp_size + 4) & ~(4 - 1);
+
+ stlink_read_mem32(sl, address + off, aligned_size);
+
+ if (memcmp(sl->q_buf, data + off, cmp_size)) {
+ ELOG("Verification of flash failed at offset: %zd\n", off);
+ return -1;
+ }
+ }
+ ILOG("Flash written and verified! jolly good!\n");
+ return 0;
+
+}
+
+int stm32l1_write_half_pages(stlink_t *sl, stm32_addr_t addr, uint8_t* base, uint32_t len, uint32_t pagesize)
+{
+ unsigned int count;
+ unsigned int num_half_pages = len / pagesize;
+ uint32_t val;
+ uint32_t flash_regs_base;
+ flash_loader_t fl;
+
+ if (sl->chip_id == STM32_CHIPID_L0) {
+ flash_regs_base = STM32L0_FLASH_REGS_ADDR;
+ } else {
+ flash_regs_base = STM32L_FLASH_REGS_ADDR;
+ }
+
+ ILOG("Starting Half page flash write for STM32L core id\n");
+ /* flash loader initialization */
+ if (init_flash_loader(sl, &fl) == -1) {
+ WLOG("init_flash_loader() == -1\n");
+ return -1;
+ }
+ /* Unlock already done */
+ stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
+ val |= (1 << FLASH_L1_FPRG);
+ stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val);
+
+ val |= (1 << FLASH_L1_PROG);
+ stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val);
+ do {
+ stlink_read_debug32(sl, flash_regs_base + FLASH_SR_OFF, &val);
+ } while ((val & (1 << 0)) != 0);
+
+ for (count = 0; count < num_half_pages; count ++) {
+ if (run_flash_loader(sl, &fl, addr + count * pagesize, base + count * pagesize, pagesize) == -1) {
+ WLOG("l1_run_flash_loader(%#zx) failed! == -1\n", addr + count * pagesize);
+ stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
+ val &= ~((1 << FLASH_L1_FPRG) |(1 << FLASH_L1_PROG));
+ stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val);
+ return -1;
+ }
+ /* wait for sr.busy to be cleared */
+ if (sl->verbose >= 1) {
+ /* show progress. writing procedure is slow
+ and previous errors are misleading */
+ fprintf(stdout, "\r%3u/%u halfpages written", count + 1, num_half_pages);
+ fflush(stdout);
+ }
+ do {
+ stlink_read_debug32(sl, flash_regs_base + FLASH_SR_OFF, &val);
+ } while ((val & (1 << 0)) != 0);
+ }
+ stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
+ val &= ~(1 << FLASH_L1_PROG);
+ stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val);
+ stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
+ val &= ~(1 << FLASH_L1_FPRG);
+ stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val);
+
+ return 0;
+}
+
+int stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t* base, uint32_t len, uint8_t eraseonly) {
+ size_t off;
+ flash_loader_t fl;
+ ILOG("Attempting to write %d (%#x) bytes to stm32 address: %u (%#x)\n",
+ len, len, addr, addr);
+ /* check addr range is inside the flash */
+ stlink_calculate_pagesize(sl, addr);
+ if (addr < sl->flash_base) {
+ ELOG("addr too low %#x < %#x\n", addr, sl->flash_base);
+ return -1;
+ } else if ((addr + len) < addr) {
+ ELOG("addr overruns\n");
+ return -1;
+ } else if ((addr + len) > (sl->flash_base + sl->flash_size)) {
+ ELOG("addr too high\n");
+ return -1;
+ } else if (addr & 1) {
+ ELOG("unaligned addr 0x%x\n", addr);
+ return -1;
+ } else if (len & 1) {
+ WLOG("unaligned len 0x%x -- padding with zero\n", len);
+ len += 1;
+ } else if (addr & (sl->flash_pgsz - 1)) {
+ ELOG("addr not a multiple of pagesize, not supported\n");
+ return -1;
+ }
+
+ // Make sure we've loaded the context with the chip details
+ stlink_core_id(sl);
+ /* erase each page */
+ int page_count = 0;
+ for (off = 0; off < len; off += stlink_calculate_pagesize(sl, addr + off)) {
+ /* addr must be an addr inside the page */
+ if (stlink_erase_flash_page(sl, addr + off) == -1) {
+ ELOG("Failed to erase_flash_page(%#zx) == -1\n", addr + off);
+ return -1;
+ }
+ fprintf(stdout,"\rFlash page at addr: 0x%08lx erased",
+ (unsigned long)addr + off);
+ fflush(stdout);
+ page_count++;
+ }
+ fprintf(stdout,"\n");
+ ILOG("Finished erasing %d pages of %d (%#x) bytes\n",
+ page_count, sl->flash_pgsz, sl->flash_pgsz);
+
+ if (eraseonly)
+ return 0;
+
+ if ((sl->flash_type == FLASH_TYPE_F4) || (sl->flash_type == FLASH_TYPE_L4)) {
+ /* todo: check write operation */
+
+ ILOG("Starting Flash write for F2/F4/L4\n");
+ /* flash loader initialization */
+ if (init_flash_loader(sl, &fl) == -1) {
+ ELOG("init_flash_loader() == -1\n");
+ return -1;
+ }
+
+ /* First unlock the cr */
+ unlock_flash_if(sl);
+
+ /* TODO: Check that Voltage range is 2.7 - 3.6 V */
+ if (sl->chip_id != STM32_CHIPID_L4) {
+ /* set parallelisim to 32 bit*/
+ int voltage = stlink_target_voltage(sl);
+ if (voltage == -1) {
+ printf("Failed to read Target voltage\n");
+ return voltage;
+ } else if (voltage > 2700) {
+ printf("enabling 32-bit flash writes\n");
+ write_flash_cr_psiz(sl, 2);
+ } else {
+ printf("Target voltage (%d mV) too low for 32-bit flash, using 8-bit flash writes\n", voltage);
+ write_flash_cr_psiz(sl, 0);
+ }
+ } else {
+ /* L4 does not have a byte-write mode */
+ int voltage = stlink_target_voltage(sl);
+ if (voltage == -1) {
+ printf("Failed to read Target voltage\n");
+ return voltage;
+ } else if (voltage < 1710) {
+ printf("Target voltage (%d mV) too low for flash writes!\n", voltage);
+ return -1;
+ }
+ }
+
+ /* set programming mode */
+ set_flash_cr_pg(sl);
+
+ for(off = 0; off < len;) {
+ size_t size = len - off > 0x8000 ? 0x8000 : len - off;
+
+ printf("size: %zu\n", size);
+
+ if (run_flash_loader(sl, &fl, addr + off, base + off, size) == -1) {
+ ELOG("run_flash_loader(%#zx) failed! == -1\n", addr + off);
+ return -1;
+ }
+
+ off += size;
+ }
+
+ /* Relock flash */
+ lock_flash(sl);
+
+ } //STM32F4END
+
+ else if (sl->flash_type == FLASH_TYPE_L0) {
+ /* use fast word write. todo: half page. */
+ uint32_t val;
+ uint32_t flash_regs_base;
+ uint32_t pagesize;
+
+ if (sl->chip_id == STM32_CHIPID_L0) {
+ flash_regs_base = STM32L0_FLASH_REGS_ADDR;
+ pagesize = L0_WRITE_BLOCK_SIZE;
+ } else {
+ flash_regs_base = STM32L_FLASH_REGS_ADDR;
+ pagesize = L1_WRITE_BLOCK_SIZE;
+ }
+
+ /* todo: check write operation */
+
+ /* disable pecr protection */
+ stlink_write_debug32(sl, flash_regs_base + FLASH_PEKEYR_OFF, 0x89abcdef);
+ stlink_write_debug32(sl, flash_regs_base + FLASH_PEKEYR_OFF, 0x02030405);
+
+ /* check pecr.pelock is cleared */
+ stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
+ if (val & (1 << 0)) {
+ fprintf(stderr, "pecr.pelock not clear\n");
+ return -1;
+ }
+
+ /* unlock program memory */
+ stlink_write_debug32(sl, flash_regs_base + FLASH_PRGKEYR_OFF, 0x8c9daebf);
+ stlink_write_debug32(sl, flash_regs_base + FLASH_PRGKEYR_OFF, 0x13141516);
+
+ /* check pecr.prglock is cleared */
+ stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
+ if (val & (1 << 1)) {
+ fprintf(stderr, "pecr.prglock not clear\n");
+ return -1;
+ }
+ off = 0;
+ if (len > pagesize) {
+ if (stm32l1_write_half_pages(sl, addr, base, len, pagesize) == -1) {
+ /* This may happen on a blank device! */
+ WLOG("\nwrite_half_pages failed == -1\n");
+ } else {
+ off = (len / pagesize)*pagesize;
+ }
+ }
+
+ /* write remainingword in program memory */
+ for ( ; off < len; off += sizeof(uint32_t)) {
+ uint32_t data;
+ if (off > 254)
+ fprintf(stdout, "\r");
+
+ if ((off % sl->flash_pgsz) > (sl->flash_pgsz -5)) {
+ fprintf(stdout, "\r%3zd/%3zd pages written",
+ off/sl->flash_pgsz, 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");
+ /* 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 == FLASH_TYPE_F0) {
+ ILOG("Starting Flash write for VL/F0/F3 core id\n");
+ /* flash loader initialization */
+ if (init_flash_loader(sl, &fl) == -1) {
+ ELOG("init_flash_loader() == -1\n");
+ return -1;
+ }
+
+ int write_block_count = 0;
+ for (off = 0; off < len; off += sl->flash_pgsz) {
+ /* adjust last write size */
+ size_t size = sl->flash_pgsz;
+ if ((off + sl->flash_pgsz) > len) size = len - off;
+
+ /* unlock and set programming mode */
+ unlock_flash_if(sl);
+ set_flash_cr_pg(sl);
+ //DLOG("Finished setting flash cr pg, running loader!\n");
+ if (run_flash_loader(sl, &fl, addr + off, base + off, size) == -1) {
+ ELOG("run_flash_loader(%#zx) failed! == -1\n", addr + off);
+ return -1;
+ }
+ lock_flash(sl);
+ if (sl->verbose >= 1) {
+ /* show progress. writing procedure is slow
+ and previous errors are misleading */
+ fprintf(stdout, "\r%3u/%lu pages written", write_block_count++, (unsigned long)len/sl->flash_pgsz);
+ fflush(stdout);
+ }
+ }
+ fprintf(stdout, "\n");
+ } else {
+ ELOG("unknown coreid, not sure how to write: %x\n", sl->core_id);
+ return -1;
+ }
+
+ return stlink_verify_write_flash(sl, addr, base, len);
+}
+
+/**
+ * Write the given binary file into flash at address "addr"
+ * @param sl
+ * @param path readable file path, should be binary image
+ * @param addr where to start writing
+ * @return 0 on success, -ve on failure.
+ */
+int stlink_fwrite_flash(stlink_t *sl, const char* path, stm32_addr_t addr) {
+ /* write the file in flash at addr */
+ int err;
+ unsigned int num_empty, index, val;
+ unsigned char erased_pattern;
+ mapped_file_t mf = MAPPED_FILE_INITIALIZER;
+
+ if (map_file(&mf, path) == -1) {
+ ELOG("map_file() == -1\n");
+ return -1;
+ }
+
+ if (sl->flash_type == FLASH_TYPE_L0)
+ erased_pattern = 0x00;
+ else
+ erased_pattern = 0xff;
+
+ index = mf.len;
+ for(num_empty = 0; num_empty != mf.len; ++num_empty) {
+ if (mf.base[--index] != erased_pattern) {
+ break;
+ }
+ }
+ /* Round down to words */
+ num_empty -= (num_empty & 3);
+ if(num_empty != 0) {
+ ILOG("Ignoring %d bytes of 0x%02x at end of file\n", num_empty, erased_pattern);
+ }
+ err = stlink_write_flash(sl, addr, mf.base, num_empty == mf.len? mf.len : mf.len - num_empty, num_empty == mf.len);
+ /* set stack*/
+ stlink_read_debug32(sl, addr, &val);
+ stlink_write_reg(sl, val, 13);
+ /* Set PC to the reset routine*/
+ stlink_read_debug32(sl, addr + 4, &val);
+ stlink_write_reg(sl, val, 15);
+ stlink_run(sl);
+ unmap_file(&mf);
+ return err;
+}
+
+int run_flash_loader(stlink_t *sl, flash_loader_t* fl, stm32_addr_t target, const uint8_t* buf, size_t size) {
+
+ reg rr;
+ int i = 0;
+ size_t count = 0;
+
+ DLOG("Running flash loader, write address:%#x, size: %zd\n", target, size);
+ // FIXME This can never return -1
+ if (write_buffer_to_sram(sl, fl, buf, size) == -1) {
+ // IMPOSSIBLE!
+ ELOG("write_buffer_to_sram() == -1\n");
+ return -1;
+ }
+
+ if (sl->flash_type == FLASH_TYPE_F0) {
+ count = size / sizeof(uint16_t);
+ if (size % sizeof(uint16_t))
+ ++count;
+ } else if (sl->flash_type == FLASH_TYPE_F4 || sl->flash_type == FLASH_TYPE_L0) {
+ count = size / sizeof(uint32_t);
+ if (size % sizeof(uint32_t))
+ ++count;
+ } else if (sl->flash_type == FLASH_TYPE_L4) {
+ count = size / sizeof(uint64_t);
+ if (size % sizeof(uint64_t))
+ ++count;
+ }
+
+ /* setup core */
+ stlink_write_reg(sl, fl->buf_addr, 0); /* source */
+ stlink_write_reg(sl, target, 1); /* target */
+ stlink_write_reg(sl, count, 2); /* count */
+ stlink_write_reg(sl, 0, 3); /* flash bank 0 (input), only used on F0, but armless fopr others */
+ stlink_write_reg(sl, fl->loader_addr, 15); /* pc register */
+
+ /* run loader */
+ stlink_run(sl);
+
+#define WAIT_ROUNDS 10000
+ /* wait until done (reaches breakpoint) */
+ for (i = 0; i < WAIT_ROUNDS; i++) {
+ usleep(10);
+ if (is_core_halted(sl))
+ break;
+ }
+
+ if (i >= WAIT_ROUNDS) {
+ ELOG("flash loader run error\n");
+ return -1;
+ }
+
+ /* check written byte count */
+ stlink_read_reg(sl, 2, &rr);
+ if (rr.r[2] != 0) {
+ fprintf(stderr, "write error, count == %u\n", rr.r[2]);
+ return -1;
+ }
+
+ return 0;
+}
--- /dev/null
+PRG := st-util
+OBJS = gdb-remote.o gdb-server.o
+
+CFLAGS+=-g -Wall -Werror -std=gnu99 -I../src
+LDFLAGS=-L.. -lstlink
+
+# libusb location
+LDFLAGS+=`pkg-config --libs libusb-1.0`
+CFLAGS+=`pkg-config --cflags libusb-1.0`
+
+all: $(PRG)
+
+$(PRG): $(OBJS) ../libstlink.a
+ $(CC) -o $@ $^ $(LDFLAGS)
+
+clean:
+ rm -rf $(OBJS)
+ rm -rf $(PRG)
+
+.PHONY: clean all
--- /dev/null
+/*
+ * Copyright (C) 2011 Peter Zotov <whitequark@whitequark.org>
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdint.h>
+#ifdef __MINGW32__
+#include "mingw.h"
+#else
+#include <sys/poll.h>
+#endif
+
+static const char hex[] = "0123456789abcdef";
+
+int gdb_send_packet(int fd, char* data) {
+ unsigned int data_length = strlen(data);
+ int length = data_length + 4;
+ char* packet = malloc(length); /* '$' data (hex) '#' cksum (hex) */
+
+ memset(packet, 0, length);
+
+ packet[0] = '$';
+
+ uint8_t cksum = 0;
+ for(unsigned int 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
+
+int gdb_recv_packet(int fd, char** buffer) {
+ unsigned packet_size = ALLOC_STEP + 1, packet_idx = 0;
+ uint8_t cksum = 0;
+ char recv_cksum[3] = {0};
+ char* packet_buffer = malloc(packet_size);
+ unsigned state;
+
+start:
+ state = 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) {
+ 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;
+ packet_buffer = realloc(packet_buffer, packet_size);
+ }
+ }
+ 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) {
+ return -2;
+ }
+
+ goto start;
+ } else {
+ char ack = '+';
+ if(write(fd, &ack, 1) != 1) {
+ 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.
+int gdb_check_for_interrupt(int 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') // ^C
+ return 1;
+ }
+
+ return 0;
+}
+
--- /dev/null
+#ifndef _GDB_REMOTE_H_
+#define _GDB_REMOTE_H_
+
+int gdb_send_packet(int fd, char* data);
+int gdb_recv_packet(int fd, char** buffer);
+int gdb_check_for_interrupt(int fd);
+
+#endif
--- /dev/null
+/*
+ * Copyright (C) 2011 Peter Zotov <whitequark@whitequark.org>
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file.
+ */
+
+#include <getopt.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#ifdef __MINGW32__
+#include "mingw.h"
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+
+#include <stlink.h>
+#include <stlink/logging.h>
+
+#include "gdb-remote.h"
+#include "gdb-server.h"
+
+#define FLASH_BASE 0x08000000
+
+//Allways update the FLASH_PAGE before each use, by calling stlink_calculate_pagesize
+#define FLASH_PAGE (sl->flash_pgsz)
+
+stlink_t *connected_stlink = NULL;
+
+static const char hex[] = "0123456789abcdef";
+
+static const char* current_memory_map = NULL;
+
+typedef struct _st_state_t {
+ // things from command line, bleh
+ int stlink_version;
+ int logging_level;
+ int listen_port;
+ int persistent;
+ int reset;
+} st_state_t;
+
+
+int 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(int signal __attribute__((unused))) {
+ if (connected_stlink) {
+ /* Switch back to mass storage mode before closing. */
+ stlink_run(connected_stlink);
+ stlink_exit_debug_mode(connected_stlink);
+ stlink_close(connected_stlink);
+ }
+
+ exit(1);
+}
+
+
+
+int parse_options(int argc, char** argv, st_state_t *st) {
+ static struct option long_options[] = {
+ {"help", no_argument, NULL, 'h'},
+ {"verbose", optional_argument, NULL, 'v'},
+ {"stlink_version", required_argument, NULL, 's'},
+ {"stlinkv1", no_argument, NULL, '1'},
+ {"listen_port", required_argument, NULL, 'p'},
+ {"multi", optional_argument, NULL, 'm'},
+ {"no-reset", optional_argument, NULL, 'n'},
+ {0, 0, 0, 0},
+ };
+ const char * help_str = "%s - usage:\n\n"
+ " -h, --help\t\tPrint this help\n"
+ " -vXX, --verbose=XX\tSpecify a specific verbosity level (0..99)\n"
+ " -v, --verbose\t\tSpecify generally verbose logging\n"
+ " -s X, --stlink_version=X\n"
+ "\t\t\tChoose what version of stlink to use, (defaults to 2)\n"
+ " -1, --stlinkv1\tForce stlink version 1\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\n"
+ "\t\t\tDo not reset board on connection.\n"
+ "\n"
+ "The STLINKv2 device to use can be specified in the environment\n"
+ "variable STLINK_DEVICE on the format <USB_BUS>:<USB_ADDR>.\n"
+ "\n"
+ ;
+
+
+ int option_index = 0;
+ int c;
+ int q;
+ while ((c = getopt_long(argc, argv, "hv::s:1p:mn", long_options, &option_index)) != -1) {
+ switch (c) {
+ case 0:
+ printf("XXXXX Shouldn't really normally come here, only if there's no corresponding option\n");
+ printf("option %s", long_options[option_index].name);
+ if (optarg) {
+ printf(" with arg %s", optarg);
+ }
+ printf("\n");
+ 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 = DEFAULT_LOGGING_LEVEL;
+ }
+ break;
+ case '1':
+ st->stlink_version = 1;
+ break;
+ case 's':
+ sscanf(optarg, "%i", &q);
+ if (q < 0 || q > 2) {
+ fprintf(stderr, "stlink version %d unknown!\n", q);
+ exit(EXIT_FAILURE);
+ }
+ st->stlink_version = q;
+ break;
+ case 'p':
+ sscanf(optarg, "%i", &q);
+ 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 = 1;
+ break;
+ case 'n':
+ st->reset = 0;
+ break;
+ }
+ }
+
+ if (optind < argc) {
+ printf("non-option ARGV-elements: ");
+ while (optind < argc)
+ printf("%s ", argv[optind++]);
+ printf("\n");
+ }
+ return 0;
+}
+
+
+int main(int argc, char** argv) {
+ int32_t voltage;
+
+ stlink_t *sl = NULL;
+
+ st_state_t state;
+ memset(&state, 0, sizeof(state));
+ // set defaults...
+ state.stlink_version = 2;
+ state.logging_level = DEFAULT_LOGGING_LEVEL;
+ state.listen_port = DEFAULT_GDB_LISTEN_PORT;
+ state.reset = 1; /* By default, reset board */
+ parse_options(argc, argv, &state);
+ switch (state.stlink_version) {
+ case 2:
+ sl = stlink_open_usb(state.logging_level, state.reset, NULL);
+ if(sl == NULL) return 1;
+ break;
+ case 1:
+ sl = stlink_v1_open(state.logging_level, state.reset);
+ if(sl == NULL) return 1;
+ break;
+ }
+
+ connected_stlink = sl;
+ signal(SIGINT, &cleanup);
+ signal(SIGTERM, &cleanup);
+ signal(SIGSEGV, &cleanup);
+
+ if (state.reset) {
+ stlink_reset(sl);
+ }
+
+ ILOG("Chip ID is %08x, Core ID is %08x.\n", sl->chip_id, sl->core_id);
+
+ voltage = stlink_target_voltage(sl);
+ if (voltage != -1) {
+ ILOG("Target voltage is %d mV.\n", voltage);
+ }
+
+ sl->verbose=0;
+
+ current_memory_map = make_memory_map(sl);
+
+#ifdef __MINGW32__
+ WSADATA wsadata;
+ if (WSAStartup(MAKEWORD(2,2),&wsadata) !=0 ) {
+ goto winsock_error;
+ }
+#endif
+
+ init_cache(sl);
+
+ do {
+ if (serve(sl, &state)) {
+ sleep (1); // don't go bezurk if serve returns with error
+ }
+
+ /* Continue */
+ stlink_run(sl);
+ } while (state.persistent);
+
+#ifdef __MINGW32__
+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_F4 =
+ "<?xml version=\"1.0\"?>"
+ "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"
+ "<target version=\"1.0\">"
+ " <architecture>arm</architecture>"
+ " <feature name=\"org.gnu.gdb.arm.m-profile\">"
+ " <reg name=\"r0\" bitsize=\"32\"/>"
+ " <reg name=\"r1\" bitsize=\"32\"/>"
+ " <reg name=\"r2\" bitsize=\"32\"/>"
+ " <reg name=\"r3\" bitsize=\"32\"/>"
+ " <reg name=\"r4\" bitsize=\"32\"/>"
+ " <reg name=\"r5\" bitsize=\"32\"/>"
+ " <reg name=\"r6\" bitsize=\"32\"/>"
+ " <reg name=\"r7\" bitsize=\"32\"/>"
+ " <reg name=\"r8\" bitsize=\"32\"/>"
+ " <reg name=\"r9\" bitsize=\"32\"/>"
+ " <reg name=\"r10\" bitsize=\"32\"/>"
+ " <reg name=\"r11\" bitsize=\"32\"/>"
+ " <reg name=\"r12\" bitsize=\"32\"/>"
+ " <reg name=\"sp\" bitsize=\"32\" type=\"data_ptr\"/>"
+ " <reg name=\"lr\" bitsize=\"32\"/>"
+ " <reg name=\"pc\" bitsize=\"32\" type=\"code_ptr\"/>"
+ " <reg name=\"xpsr\" bitsize=\"32\" regnum=\"25\"/>"
+ " <reg name=\"msp\" bitsize=\"32\" regnum=\"26\" type=\"data_ptr\" group=\"general\" />"
+ " <reg name=\"psp\" bitsize=\"32\" regnum=\"27\" type=\"data_ptr\" group=\"general\" />"
+ " <reg name=\"control\" bitsize=\"8\" regnum=\"28\" type=\"int\" group=\"general\" />"
+ " <reg name=\"faultmask\" bitsize=\"8\" regnum=\"29\" type=\"int\" group=\"general\" />"
+ " <reg name=\"basepri\" bitsize=\"8\" regnum=\"30\" type=\"int\" group=\"general\" />"
+ " <reg name=\"primask\" bitsize=\"8\" regnum=\"31\" type=\"int\" group=\"general\" />"
+ " <reg name=\"s0\" bitsize=\"32\" regnum=\"32\" type=\"float\" group=\"float\" />"
+ " <reg name=\"s1\" bitsize=\"32\" type=\"float\" group=\"float\" />"
+ " <reg name=\"s2\" bitsize=\"32\" type=\"float\" group=\"float\" />"
+ " <reg name=\"s3\" bitsize=\"32\" type=\"float\" group=\"float\" />"
+ " <reg name=\"s4\" bitsize=\"32\" type=\"float\" group=\"float\" />"
+ " <reg name=\"s5\" bitsize=\"32\" type=\"float\" group=\"float\" />"
+ " <reg name=\"s6\" bitsize=\"32\" type=\"float\" group=\"float\" />"
+ " <reg name=\"s7\" bitsize=\"32\" type=\"float\" group=\"float\" />"
+ " <reg name=\"s8\" bitsize=\"32\" type=\"float\" group=\"float\" />"
+ " <reg name=\"s9\" bitsize=\"32\" type=\"float\" group=\"float\" />"
+ " <reg name=\"s10\" bitsize=\"32\" type=\"float\" group=\"float\" />"
+ " <reg name=\"s11\" bitsize=\"32\" type=\"float\" group=\"float\" />"
+ " <reg name=\"s12\" bitsize=\"32\" type=\"float\" group=\"float\" />"
+ " <reg name=\"s13\" bitsize=\"32\" type=\"float\" group=\"float\" />"
+ " <reg name=\"s14\" bitsize=\"32\" type=\"float\" group=\"float\" />"
+ " <reg name=\"s15\" bitsize=\"32\" type=\"float\" group=\"float\" />"
+ " <reg name=\"s16\" bitsize=\"32\" type=\"float\" group=\"float\" />"
+ " <reg name=\"s17\" bitsize=\"32\" type=\"float\" group=\"float\" />"
+ " <reg name=\"s18\" bitsize=\"32\" type=\"float\" group=\"float\" />"
+ " <reg name=\"s19\" bitsize=\"32\" type=\"float\" group=\"float\" />"
+ " <reg name=\"s20\" bitsize=\"32\" type=\"float\" group=\"float\" />"
+ " <reg name=\"s21\" bitsize=\"32\" type=\"float\" group=\"float\" />"
+ " <reg name=\"s22\" bitsize=\"32\" type=\"float\" group=\"float\" />"
+ " <reg name=\"s23\" bitsize=\"32\" type=\"float\" group=\"float\" />"
+ " <reg name=\"s24\" bitsize=\"32\" type=\"float\" group=\"float\" />"
+ " <reg name=\"s25\" bitsize=\"32\" type=\"float\" group=\"float\" />"
+ " <reg name=\"s26\" bitsize=\"32\" type=\"float\" group=\"float\" />"
+ " <reg name=\"s27\" bitsize=\"32\" type=\"float\" group=\"float\" />"
+ " <reg name=\"s28\" bitsize=\"32\" type=\"float\" group=\"float\" />"
+ " <reg name=\"s29\" bitsize=\"32\" type=\"float\" group=\"float\" />"
+ " <reg name=\"s30\" bitsize=\"32\" type=\"float\" group=\"float\" />"
+ " <reg name=\"s31\" bitsize=\"32\" type=\"float\" group=\"float\" />"
+ " <reg name=\"fpscr\" bitsize=\"32\" type=\"int\" group=\"float\" />"
+ " </feature>"
+ "</target>";
+
+static const char* const memory_map_template_F4 =
+ "<?xml version=\"1.0\"?>"
+ "<!DOCTYPE memory-map PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\""
+ " \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"
+ "<memory-map>"
+ " <memory type=\"rom\" start=\"0x00000000\" length=\"0x100000\"/>" // code = sram, bootrom or flash; flash is bigger
+ " <memory type=\"ram\" start=\"0x10000000\" length=\"0x10000\"/>" // ccm ram
+ " <memory type=\"ram\" start=\"0x20000000\" length=\"0x20000\"/>" // sram
+ " <memory type=\"flash\" start=\"0x08000000\" length=\"0x10000\">" //Sectors 0..3
+ " <property name=\"blocksize\">0x4000</property>" //16kB
+ " </memory>"
+ " <memory type=\"flash\" start=\"0x08010000\" length=\"0x10000\">" //Sector 4
+ " <property name=\"blocksize\">0x10000</property>" //64kB
+ " </memory>"
+ " <memory type=\"flash\" start=\"0x08020000\" length=\"0xE0000\">" //Sectors 5..11
+ " <property name=\"blocksize\">0x20000</property>" //128kB
+ " </memory>"
+ " <memory type=\"ram\" start=\"0x40000000\" length=\"0x1fffffff\"/>" // peripheral regs
+ " <memory type=\"ram\" start=\"0x60000000\" length=\"0x7fffffff\"/>" // AHB3 Peripherals
+ " <memory type=\"ram\" start=\"0xe0000000\" length=\"0x1fffffff\"/>" // cortex regs
+ " <memory type=\"rom\" start=\"0x1fff0000\" length=\"0x7800\"/>" // bootrom
+ " <memory type=\"rom\" start=\"0x1fffc000\" length=\"0x10\"/>" // option byte area
+ "</memory-map>";
+
+static const char* const memory_map_template_F4_HD =
+ "<?xml version=\"1.0\"?>"
+ "<!DOCTYPE memory-map PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\""
+ " \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"
+ "<memory-map>"
+ " <memory type=\"rom\" start=\"0x00000000\" length=\"0x100000\"/>" // code = sram, bootrom or flash; flash is bigger
+ " <memory type=\"ram\" start=\"0x10000000\" length=\"0x10000\"/>" // ccm ram
+ " <memory type=\"ram\" start=\"0x20000000\" length=\"0x40000\"/>" // sram
+ " <memory type=\"ram\" start=\"0x60000000\" length=\"0x10000000\"/>" // fmc bank 1 (nor/psram/sram)
+ " <memory type=\"ram\" start=\"0x70000000\" length=\"0x20000000\"/>" // fmc bank 2 & 3 (nand flash)
+ " <memory type=\"ram\" start=\"0x90000000\" length=\"0x10000000\"/>" // fmc bank 4 (pc card)
+ " <memory type=\"ram\" start=\"0xC0000000\" length=\"0x20000000\"/>" // fmc sdram bank 1 & 2
+ " <memory type=\"flash\" start=\"0x08000000\" length=\"0x10000\">" //Sectors 0..3
+ " <property name=\"blocksize\">0x4000</property>" //16kB
+ " </memory>"
+ " <memory type=\"flash\" start=\"0x08010000\" length=\"0x10000\">" //Sector 4
+ " <property name=\"blocksize\">0x10000</property>" //64kB
+ " </memory>"
+ " <memory type=\"flash\" start=\"0x08020000\" length=\"0xE0000\">" //Sectors 5..11
+ " <property name=\"blocksize\">0x20000</property>" //128kB
+ " </memory>"
+ " <memory type=\"ram\" start=\"0x40000000\" length=\"0x1fffffff\"/>" // peripheral regs
+ " <memory type=\"ram\" start=\"0xe0000000\" length=\"0x1fffffff\"/>" // cortex regs
+ " <memory type=\"rom\" start=\"0x1fff0000\" length=\"0x7800\"/>" // bootrom
+ " <memory type=\"rom\" start=\"0x1fffc000\" length=\"0x10\"/>" // option byte area
+ "</memory-map>";
+
+static const char* const memory_map_template_F2 =
+ "<?xml version=\"1.0\"?>"
+ "<!DOCTYPE memory-map PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\""
+ " \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"
+ "<memory-map>"
+ " <memory type=\"rom\" start=\"0x00000000\" length=\"0x%zx\"/>" // code = sram, bootrom or flash; flash is bigger
+ " <memory type=\"ram\" start=\"0x20000000\" length=\"0x%zx\"/>" // sram
+ " <memory type=\"flash\" start=\"0x08000000\" length=\"0x10000\">" //Sectors 0..3
+ " <property name=\"blocksize\">0x4000</property>" //16kB
+ " </memory>"
+ " <memory type=\"flash\" start=\"0x08010000\" length=\"0x10000\">" //Sector 4
+ " <property name=\"blocksize\">0x10000</property>" //64kB
+ " </memory>"
+ " <memory type=\"flash\" start=\"0x08020000\" length=\"0x%zx\">" //Sectors 5..
+ " <property name=\"blocksize\">0x20000</property>" //128kB
+ " </memory>"
+ " <memory type=\"ram\" start=\"0x40000000\" length=\"0x1fffffff\"/>" // peripheral regs
+ " <memory type=\"ram\" start=\"0xe0000000\" length=\"0x1fffffff\"/>" // cortex regs
+ " <memory type=\"rom\" start=\"0x%08x\" length=\"0x%zx\"/>" // bootrom
+ " <memory type=\"rom\" start=\"0x1fffc000\" length=\"0x10\"/>" // option byte area
+ "</memory-map>";
+
+static const char* const memory_map_template_L4 =
+ "<?xml version=\"1.0\"?>"
+ "<!DOCTYPE memory-map PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\""
+ " \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"
+ "<memory-map>"
+ " <memory type=\"rom\" start=\"0x00000000\" length=\"0x%zx\"/>" // code = sram, bootrom or flash; flash is bigger
+ " <memory type=\"ram\" start=\"0x10000000\" length=\"0x8000\"/>" // SRAM2 (32 KB)
+ " <memory type=\"ram\" start=\"0x20000000\" length=\"0x18000\"/>" // SRAM1 (96 KB)
+ " <memory type=\"flash\" start=\"0x08000000\" length=\"0x%zx\">"
+ " <property name=\"blocksize\">0x800</property>"
+ " </memory>"
+ " <memory type=\"ram\" start=\"0x40000000\" length=\"0x1fffffff\"/>" // peripheral regs
+ " <memory type=\"ram\" start=\"0x60000000\" length=\"0x7fffffff\"/>" // AHB3 Peripherals
+ " <memory type=\"ram\" start=\"0xe0000000\" length=\"0x1fffffff\"/>" // cortex regs
+ " <memory type=\"rom\" start=\"0x1fff0000\" length=\"0x7000\"/>" // bootrom
+ " <memory type=\"rom\" start=\"0x1fff7800\" length=\"0x10\"/>" // option byte area
+ " <memory type=\"rom\" start=\"0x1ffff800\" length=\"0x10\"/>" // option byte area
+ "</memory-map>";
+
+static const char* const memory_map_template =
+ "<?xml version=\"1.0\"?>"
+ "<!DOCTYPE memory-map PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\""
+ " \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"
+ "<memory-map>"
+ " <memory type=\"rom\" start=\"0x00000000\" length=\"0x%zx\"/>" // code = sram, bootrom or flash; flash is bigger
+ " <memory type=\"ram\" start=\"0x20000000\" length=\"0x%zx\"/>" // sram 8k
+ " <memory type=\"flash\" start=\"0x08000000\" length=\"0x%zx\">"
+ " <property name=\"blocksize\">0x%zx</property>"
+ " </memory>"
+ " <memory type=\"ram\" start=\"0x40000000\" length=\"0x1fffffff\"/>" // peripheral regs
+ " <memory type=\"ram\" start=\"0xe0000000\" length=\"0x1fffffff\"/>" // cortex regs
+ " <memory type=\"rom\" start=\"0x%08x\" length=\"0x%zx\"/>" // bootrom
+ " <memory type=\"rom\" start=\"0x1ffff800\" length=\"0x10\"/>" // option byte area
+ "</memory-map>";
+
+static const char* const memory_map_template_F7 =
+ "<?xml version=\"1.0\"?>"
+ "<!DOCTYPE memory-map PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\""
+ " \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"
+ "<memory-map>"
+ " <memory type=\"ram\" start=\"0x00000000\" length=\"0x4000\"/>" // ITCM ram 16kB
+ " <memory type=\"rom\" start=\"0x00200000\" length=\"0x100000\"/>" // ITCM flash
+ " <memory type=\"ram\" start=\"0x20000000\" length=\"0x50000\"/>" // sram
+ " <memory type=\"flash\" start=\"0x08000000\" length=\"0x20000\">" // Sectors 0..3
+ " <property name=\"blocksize\">0x8000</property>" // 32kB
+ " </memory>"
+ " <memory type=\"flash\" start=\"0x08020000\" length=\"0x20000\">" // Sector 4
+ " <property name=\"blocksize\">0x20000</property>" // 128kB
+ " </memory>"
+ " <memory type=\"flash\" start=\"0x08040000\" length=\"0xC0000\">" // Sectors 5..7
+ " <property name=\"blocksize\">0x40000</property>" // 128kB
+ " </memory>"
+ " <memory type=\"ram\" start=\"0x40000000\" length=\"0x1fffffff\"/>" // peripheral regs
+ " <memory type=\"ram\" start=\"0x60000000\" length=\"0x7fffffff\"/>" // AHB3 Peripherals
+ " <memory type=\"ram\" start=\"0xe0000000\" length=\"0x1fffffff\"/>" // cortex regs
+ " <memory type=\"rom\" start=\"0x00100000\" length=\"0xEDC0\"/>" // bootrom
+ " <memory type=\"rom\" start=\"0x1fff0000\" length=\"0x20\"/>" // option byte area
+ "</memory-map>";
+
+char* make_memory_map(stlink_t *sl) {
+ /* This will be freed in serve() */
+ char* map = malloc(4096);
+ map[0] = '\0';
+
+ if(sl->chip_id==STM32_CHIPID_F4 || sl->chip_id==STM32_CHIPID_F446) {
+ strcpy(map, memory_map_template_F4);
+ } else if(sl->chip_id==STM32_CHIPID_F4 || sl->chip_id==STM32_CHIPID_F7) {
+ strcpy(map, memory_map_template_F7);
+ } 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, 4096, 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) {
+ snprintf(map, 4096, memory_map_template_L4,
+ sl->flash_size, sl->flash_size);
+ } else {
+ snprintf(map, 4096, memory_map_template,
+ sl->flash_size,
+ sl->sram_size,
+ sl->flash_size, sl->flash_pgsz,
+ sl->sys_base, sl->sys_size);
+ }
+ return map;
+}
+
+
+/*
+ * DWT_COMP0 0xE0001020
+ * DWT_MASK0 0xE0001024
+ * DWT_FUNCTION0 0xE0001028
+ * DWT_COMP1 0xE0001030
+ * DWT_MASK1 0xE0001034
+ * DWT_FUNCTION1 0xE0001038
+ * DWT_COMP2 0xE0001040
+ * DWT_MASK2 0xE0001044
+ * DWT_FUNCTION2 0xE0001048
+ * DWT_COMP3 0xE0001050
+ * DWT_MASK3 0xE0001054
+ * DWT_FUNCTION3 0xE0001058
+ */
+
+#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;
+};
+
+struct code_hw_watchpoint data_watches[DATA_WATCH_NUM];
+
+static void init_data_watchpoints(stlink_t *sl) {
+ uint32_t data;
+ DLOG("init watchpoints\n");
+
+ stlink_read_debug32(sl, 0xE000EDFC, &data);
+ data |= 1<<24;
+ // set trcena in debug command to turn on dwt unit
+ stlink_write_debug32(sl, 0xE000EDFC, data);
+
+ // make sure all watchpoints are cleared
+ for(int i = 0; i < DATA_WATCH_NUM; i++) {
+ data_watches[i].fun = WATCHDISABLED;
+ stlink_write_debug32(sl, 0xe0001028 + i * 16, 0);
+ }
+}
+
+static int add_data_watchpoint(stlink_t *sl, enum watchfun wf,
+ stm32_addr_t addr, unsigned int len) {
+ int 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, 0xE0001020 + i * 16, addr);
+
+ // insert mask
+ stlink_write_debug32(sl, 0xE0001024 + i * 16, mask);
+
+ // insert function
+ stlink_write_debug32(sl, 0xE0001028 + i * 16, wf);
+
+ // just to make sure the matched bit is clear !
+ stlink_read_debug32(sl, 0xE0001028 + i * 16, &dummy);
+ return 0;
+ }
+ }
+ }
+
+ DLOG("failure: add watchpoints addr %x wf %u len %u\n", addr, wf, len);
+ return -1;
+}
+
+static int delete_data_watchpoint(stlink_t *sl, stm32_addr_t addr)
+{
+ int 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, 0xe0001028 + i * 16, 0);
+
+ return 0;
+ }
+ }
+
+ DLOG("failure: delete watchpoint addr %x\n", addr);
+
+ return -1;
+}
+
+int code_break_num;
+int code_lit_num;
+#define CODE_BREAK_NUM_MAX 15
+#define CODE_BREAK_LOW 0x01
+#define CODE_BREAK_HIGH 0x02
+
+struct code_hw_breakpoint {
+ stm32_addr_t addr;
+ int type;
+};
+
+struct code_hw_breakpoint code_breaks[CODE_BREAK_NUM_MAX];
+
+static void init_code_breakpoints(stlink_t *sl) {
+ unsigned int val;
+ memset(sl->q_buf, 0, 4);
+ stlink_write_debug32(sl, CM3_REG_FP_CTRL, 0x03 /*KEY | ENABLE4*/);
+ stlink_read_debug32(sl, CM3_REG_FP_CTRL, &val);
+ code_break_num = ((val >> 4) & 0xf);
+ code_lit_num = ((val >> 8) & 0xf);
+
+ ILOG("Found %i hw breakpoint registers\n", code_break_num);
+
+ for(int i = 0; i < code_break_num; i++) {
+ code_breaks[i].type = 0;
+ stlink_write_debug32(sl, CM3_REG_FP_COMP0 + i * 4, 0);
+ }
+}
+
+static int update_code_breakpoint(stlink_t *sl, stm32_addr_t addr, int set) {
+ stm32_addr_t fpb_addr;
+ uint32_t mask;
+ int type = (addr & 0x2) ? CODE_BREAK_HIGH : CODE_BREAK_LOW;
+
+ if(addr & 1) {
+ ELOG("update_code_breakpoint: unaligned address %08x\n", addr);
+ return -1;
+ }
+
+ if (sl->chip_id==STM32_CHIPID_F7) {
+ fpb_addr = addr;
+ } else {
+ fpb_addr = addr & ~0x3;
+ }
+
+ int id = -1;
+ for(int 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* brk = &code_breaks[id];
+
+ brk->addr = fpb_addr;
+
+ if (sl->chip_id==STM32_CHIPID_F7) {
+ if(set) brk->type = type;
+ else brk->type = 0;
+
+ mask = (brk->addr) | 1;
+ } else {
+ if(set) brk->type |= type;
+ else brk->type &= ~type;
+
+ mask = (brk->addr) | 1 | (brk->type << 30);
+ }
+
+ if(brk->type == 0) {
+ DLOG("clearing hw break %d\n", id);
+
+ stlink_write_debug32(sl, 0xe0002008 + id * 4, 0);
+ } else {
+ DLOG("setting hw break %d at %08x (%d)\n",
+ id, brk->addr, brk->type);
+ DLOG("reg %08x \n",
+ mask);
+
+ stlink_write_debug32(sl, 0xe0002008 + id * 4, mask);
+ }
+
+ return 0;
+}
+
+
+struct flash_block {
+ stm32_addr_t addr;
+ unsigned length;
+ uint8_t* data;
+
+ struct flash_block* next;
+};
+
+static struct flash_block* flash_root;
+
+static int flash_add_block(stm32_addr_t addr, unsigned 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 = calloc(length, 1);
+
+ flash_root = new;
+
+ return 0;
+}
+
+static int flash_populate(stm32_addr_t addr, uint8_t* data, unsigned length) {
+ unsigned int 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
+ */
+
+ unsigned X = fb->addr, Y = fb->addr + fb->length;
+ unsigned a = addr, b = addr + length;
+ if(a < Y && b > X) {
+ // from start of the block
+ unsigned start = (a > X ? a : X) - X;
+ unsigned end = (b > Y ? Y : b) - X;
+
+ 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 int flash_go(stlink_t *sl) {
+ int error = -1;
+
+ // Some kinds of clock settings do not allow writing to flash.
+ stlink_reset(sl);
+ stlink_force_debug(sl);
+
+ for(struct flash_block* fb = flash_root; fb; fb = fb->next) {
+ DLOG("flash_do: block %08x -> %04x\n", fb->addr, fb->length);
+
+ for(stm32_addr_t page = fb->addr; page < fb->addr + fb->length; page += FLASH_PAGE) {
+ unsigned length = fb->length - (page - fb->addr);
+
+ //Update FLASH_PAGE
+ stlink_calculate_pagesize(sl, page);
+
+ DLOG("flash_do: page %08x\n", page);
+ unsigned send = length > FLASH_PAGE ? FLASH_PAGE : length;
+ if(stlink_write_flash(sl, page, fb->data + (page - fb->addr),
+ send, 0) < 0)
+ goto error;
+ length -= send;
+
+ }
+ }
+
+ stlink_reset(sl);
+
+ 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;
+}
+
+#define CLIDR 0xE000ED78
+#define CTR 0xE000ED7C
+#define CCSIDR 0xE000ED80
+#define CSSELR 0xE000ED84
+#define CCR 0xE000ED14
+#define CCR_DC (1 << 16)
+#define CCR_IC (1 << 17)
+#define DCCSW 0xE000EF6C
+#define ICIALLU 0xE000EF50
+
+struct cache_level_desc
+{
+ unsigned int nsets;
+ unsigned int nways;
+ unsigned int log2_nways;
+ unsigned int width;
+};
+
+struct cache_desc_t
+{
+ /* Minimal line size in bytes. */
+ unsigned int dminline;
+ unsigned int iminline;
+
+ /* Last level of unification (uniprocessor). */
+ unsigned int 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 unsigned ceil_log2(unsigned v)
+{
+ unsigned res;
+ for (res = 0; (1U << res) < v; res++)
+ ;
+ return res;
+}
+
+static void read_cache_level_desc(stlink_t *sl, struct cache_level_desc *desc)
+{
+ unsigned int ccsidr;
+ unsigned int log2_nsets;
+
+ stlink_read_debug32(sl, 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) {
+ unsigned int clidr;
+ unsigned int ccr;
+ unsigned int ctr;
+ int i;
+
+ /* Assume only F7 has a cache. */
+ if(sl->chip_id!=STM32_CHIPID_F7)
+ return;
+
+ stlink_read_debug32(sl, CLIDR, &clidr);
+ stlink_read_debug32(sl, CCR, &ccr);
+ stlink_read_debug32(sl, CTR, &ctr);
+ cache_desc.dminline = 4 << ((ctr >> 16) & 0x0f);
+ cache_desc.iminline = 4 << (ctr & 0x0f);
+ cache_desc.louu = (clidr >> 27) & 7;
+
+ ILOG("Chip clidr: %08x, I-Cache: %s, D-Cache: %s\n",
+ clidr, ccr & CCR_IC ? "on" : "off", ccr & 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++)
+ {
+ unsigned int 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, 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, 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, unsigned ccr) {
+ int level;
+
+ if (ccr & CCR_DC)
+ for (level = cache_desc.louu - 1; level >= 0; level--)
+ {
+ struct cache_level_desc *desc = &cache_desc.dcache[level];
+ unsigned addr;
+ unsigned max_addr = 1 << desc->width;
+ unsigned way_sh = 32 - desc->log2_nways;
+
+ /* D-cache clean by set-ways. */
+ for (addr = (level << 1); addr < max_addr; addr += cache_desc.dminline)
+ {
+ unsigned int way;
+
+ for (way = 0; way < desc->nways; way++)
+ stlink_write_debug32(sl, DCCSW, addr | (way << way_sh));
+ }
+ }
+
+ /* Invalidate all I-cache to oPU. */
+ if (ccr & CCR_IC)
+ stlink_write_debug32(sl, ICIALLU, 0);
+}
+
+static int cache_modified;
+
+static void cache_change(stm32_addr_t start, unsigned count)
+{
+ if (count == 0)
+ return;
+ (void)start;
+ cache_modified = 1;
+}
+
+static void cache_sync(stlink_t *sl)
+{
+ unsigned ccr;
+
+ if(sl->chip_id!=STM32_CHIPID_F7)
+ return;
+ if (!cache_modified)
+ return;
+ cache_modified = 0;
+
+ stlink_read_debug32(sl, CCR, &ccr);
+ if (ccr & (CCR_IC | CCR_DC))
+ cache_flush(sl, ccr);
+}
+
+int serve(stlink_t *sl, st_state_t *st) {
+ int sock = socket(AF_INET, SOCK_STREAM, 0);
+ if(sock < 0) {
+ perror("socket");
+ return 1;
+ }
+
+ unsigned int 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");
+ return 1;
+ }
+
+ if(listen(sock, 5) < 0) {
+ perror("listen");
+ return 1;
+ }
+
+ ILOG("Listening at *:%d...\n", st->listen_port);
+
+ int client = accept(sock, NULL, NULL);
+ //signal (SIGINT, SIG_DFL);
+ if(client < 0) {
+ perror("accept");
+ return 1;
+ }
+
+ close(sock);
+
+ stlink_force_debug(sl);
+ if (st->reset) {
+ stlink_reset(sl);
+ }
+ init_code_breakpoints(sl);
+ init_data_watchpoints(sl);
+
+ ILOG("GDB connected.\n");
+
+ /*
+ * To allow resetting the chip from GDB it is required to
+ * emulate attaching and detaching to target.
+ */
+ unsigned int attached = 1;
+
+ while(1) {
+ char* packet;
+
+ int status = gdb_recv_packet(client, &packet);
+ if(status < 0) {
+ ELOG("cannot recv: %d\n", status);
+#ifdef __MINGW32__
+ win32_close_socket(sock);
+#endif
+ return 1;
+ }
+
+ DLOG("recv: %s\n", packet);
+
+ char* reply = NULL;
+ 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;
+ }
+
+ unsigned queryNameLength = (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")) {
+ if(sl->chip_id==STM32_CHIPID_F4
+ || sl->chip_id==STM32_CHIPID_F4_HD
+ || sl->chip_id==STM32_CHIPID_F7) {
+ reply = strdup("PacketSize=3fff;qXfer:memory-map:read+;qXfer:features:read+");
+ }
+ else {
+ reply = strdup("PacketSize=3fff;qXfer:memory-map: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;
+
+ unsigned addr = strtoul(__s_addr, NULL, 16),
+ length = 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 = NULL;
+
+ if(!strcmp(type, "memory-map") && !strcmp(op, "read"))
+ data = current_memory_map;
+
+ if(!strcmp(type, "features") && !strcmp(op, "read"))
+ data = target_description_F4;
+
+ if(data) {
+ unsigned data_length = 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
+ char *separator = strstr(packet, ","), *params = "";
+ if(separator == NULL) {
+ separator = packet + strlen(packet);
+ } else {
+ params = separator + 1;
+ }
+
+
+ if (!strncmp(params,"726573756d65",12)) {// resume
+ DLOG("Rcmd: resume\n");
+ cache_sync(sl);
+ stlink_run(sl);
+
+ reply = strdup("OK");
+ } else if (!strncmp(params,"68616c74",8)) { //halt
+ reply = strdup("OK");
+
+ stlink_force_debug(sl);
+
+ DLOG("Rcmd: halt\n");
+ } else if (!strncmp(params,"6a7461675f7265736574",20)) { //jtag_reset
+ reply = strdup("OK");
+
+ stlink_jtag_reset(sl, 0);
+ stlink_jtag_reset(sl, 1);
+ stlink_force_debug(sl);
+
+ DLOG("Rcmd: jtag_reset\n");
+ } else if (!strncmp(params,"7265736574",10)) { //reset
+ reply = strdup("OK");
+
+ stlink_force_debug(sl);
+ stlink_reset(sl);
+ init_code_breakpoints(sl);
+ init_data_watchpoints(sl);
+
+ DLOG("Rcmd: reset\n");
+ } else {
+ DLOG("Rcmd: %s\n", params);
+ }
+
+ }
+
+ 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;
+
+ unsigned addr = strtoul(__s_addr, NULL, 16),
+ length = 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;
+
+ unsigned addr = strtoul(__s_addr, NULL, 16);
+ unsigned data_length = status - (data - packet);
+
+ // Length of decoded data cannot be more than
+ // encoded, as escapes are removed.
+ // Additional byte is reserved for alignment fix.
+ uint8_t *decoded = calloc(data_length + 1, 1);
+ unsigned dec_index = 0;
+ for(unsigned int 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");
+ }
+ } else if(!strcmp(cmdName, "FlashDone")) {
+ if(flash_go(sl) < 0) {
+ reply = strdup("E00");
+ } 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);
+ stlink_run(sl);
+
+ while(1) {
+ int status = gdb_check_for_interrupt(client);
+ if(status < 0) {
+ ELOG("cannot check for int: %d\n", status);
+#ifdef __MINGW32__
+ win32_close_socket(sock);
+#endif
+ return 1;
+ }
+
+ if(status == 1) {
+ stlink_force_debug(sl);
+ break;
+ }
+
+ stlink_status(sl);
+ if(sl->core_stat == STLINK_CORE_HALTED) {
+ break;
+ }
+
+ usleep(100000);
+ }
+
+ reply = strdup("S05"); // TRAP
+ break;
+
+ case 's':
+ cache_sync(sl);
+ stlink_step(sl);
+
+ reply = strdup("S05"); // TRAP
+ break;
+
+ case '?':
+ if(attached) {
+ reply = strdup("S05"); // TRAP
+ } else {
+ /* Stub shall reply OK if not attached. */
+ reply = strdup("OK");
+ }
+ break;
+
+ case 'g':
+ stlink_read_all_regs(sl, ®p);
+
+ reply = calloc(8 * 16 + 1, 1);
+ for(int i = 0; i < 16; i++)
+ sprintf(&reply[i * 8], "%08x", htonl(regp.r[i]));
+
+ break;
+
+ case 'p': {
+ unsigned id = strtoul(&packet[1], NULL, 16);
+ unsigned myreg = 0xDEADDEAD;
+
+ if(id < 16) {
+ stlink_read_reg(sl, id, ®p);
+ myreg = htonl(regp.r[id]);
+ } else if(id == 0x19) {
+ stlink_read_reg(sl, 16, ®p);
+ myreg = htonl(regp.xpsr);
+ } else if(id == 0x1A) {
+ stlink_read_reg(sl, 17, ®p);
+ myreg = htonl(regp.main_sp);
+ } else if(id == 0x1B) {
+ stlink_read_reg(sl, 18, ®p);
+ myreg = htonl(regp.process_sp);
+ } else if(id == 0x1C) {
+ stlink_read_unsupported_reg(sl, id, ®p);
+ myreg = htonl(regp.control);
+ } else if(id == 0x1D) {
+ stlink_read_unsupported_reg(sl, id, ®p);
+ myreg = htonl(regp.faultmask);
+ } else if(id == 0x1E) {
+ stlink_read_unsupported_reg(sl, id, ®p);
+ myreg = htonl(regp.basepri);
+ } else if(id == 0x1F) {
+ stlink_read_unsupported_reg(sl, id, ®p);
+ myreg = htonl(regp.primask);
+ } else if(id >= 0x20 && id < 0x40) {
+ stlink_read_unsupported_reg(sl, id, ®p);
+ myreg = htonl(regp.s[id-0x20]);
+ } else if(id == 0x40) {
+ stlink_read_unsupported_reg(sl, id, ®p);
+ myreg = htonl(regp.fpscr);
+ } else {
+ reply = strdup("E00");
+ }
+
+ reply = calloc(8 + 1, 1);
+ sprintf(reply, "%08x", myreg);
+
+ break;
+ }
+
+ case 'P': {
+ char* s_reg = &packet[1];
+ char* s_value = strstr(&packet[1], "=") + 1;
+
+ unsigned reg = strtoul(s_reg, NULL, 16);
+ unsigned value = strtoul(s_value, NULL, 16);
+
+ if(reg < 16) {
+ stlink_write_reg(sl, ntohl(value), reg);
+ } else if(reg == 0x19) {
+ stlink_write_reg(sl, ntohl(value), 16);
+ } else if(reg == 0x1A) {
+ stlink_write_reg(sl, ntohl(value), 17);
+ } else if(reg == 0x1B) {
+ stlink_write_reg(sl, ntohl(value), 18);
+ } else if(reg == 0x1C) {
+ stlink_write_unsupported_reg(sl, ntohl(value), reg, ®p);
+ } else if(reg == 0x1D) {
+ stlink_write_unsupported_reg(sl, ntohl(value), reg, ®p);
+ } else if(reg == 0x1E) {
+ stlink_write_unsupported_reg(sl, ntohl(value), reg, ®p);
+ } else if(reg == 0x1F) {
+ stlink_write_unsupported_reg(sl, ntohl(value), reg, ®p);
+ } else if(reg >= 0x20 && reg < 0x40) {
+ stlink_write_unsupported_reg(sl, ntohl(value), reg, ®p);
+ } else if(reg == 0x40) {
+ stlink_write_unsupported_reg(sl, ntohl(value), reg, ®p);
+ } else {
+ reply = strdup("E00");
+ }
+
+ if(!reply) {
+ reply = strdup("OK");
+ }
+
+ break;
+ }
+
+ case 'G':
+ for(int i = 0; i < 16; i++) {
+ char str[9] = {0};
+ strncpy(str, &packet[1 + i * 8], 8);
+ uint32_t reg = strtoul(str, NULL, 16);
+ stlink_write_reg(sl, ntohl(reg), i);
+ }
+
+ reply = strdup("OK");
+ break;
+
+ case 'm': {
+ char* s_start = &packet[1];
+ char* s_count = strstr(&packet[1], ",") + 1;
+
+ stm32_addr_t start = strtoul(s_start, NULL, 16);
+ unsigned count = strtoul(s_count, NULL, 16);
+
+ unsigned adj_start = start % 4;
+ unsigned 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;
+
+ stlink_read_mem32(sl, start - adj_start, count_rnd);
+
+ reply = calloc(count * 2 + 1, 1);
+ for(unsigned int 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 = strtoul(s_start, NULL, 16);
+ unsigned count = strtoul(s_count, NULL, 16);
+
+ if(start % 4) {
+ unsigned align_count = 4 - start % 4;
+ if (align_count > count) align_count = count;
+ for(unsigned int i = 0; i < align_count; i ++) {
+ char hex[3] = { hexdata[i*2], hexdata[i*2+1], 0 };
+ uint8_t byte = strtoul(hex, NULL, 16);
+ sl->q_buf[i] = byte;
+ }
+ 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) {
+ unsigned aligned_count = count - count % 4;
+
+ for(unsigned int i = 0; i < aligned_count; i ++) {
+ char hex[3] = { hexdata[i*2], hexdata[i*2+1], 0 };
+ uint8_t byte = strtoul(hex, NULL, 16);
+ sl->q_buf[i] = byte;
+ }
+ 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(unsigned int i = 0; i < count; i ++) {
+ char hex[3] = { hexdata[i*2], hexdata[i*2+1], 0 };
+ uint8_t byte = strtoul(hex, NULL, 16);
+ sl->q_buf[i] = byte;
+ }
+ stlink_write_mem8(sl, start, count);
+ cache_change(start, count);
+ }
+ reply = strdup("OK");
+ break;
+ }
+
+ case 'Z': {
+ char *endptr;
+ stm32_addr_t addr = strtoul(&packet[3], &endptr, 16);
+ stm32_addr_t len = 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;
+ }
+ }
+
+ default:
+ reply = strdup("");
+ }
+ break;
+ }
+ case 'z': {
+ char *endptr;
+ stm32_addr_t addr = 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");
+ } 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. */
+
+ stlink_reset(sl);
+ init_code_breakpoints(sl);
+ init_data_watchpoints(sl);
+
+ attached = 1;
+
+ reply = strdup("OK");
+
+ break;
+ }
+
+ default:
+ reply = strdup("");
+ }
+
+ if(reply) {
+ DLOG("send: %s\n", reply);
+
+ int result = gdb_send_packet(client, reply);
+ if(result != 0) {
+ ELOG("cannot send: %d\n", result);
+ free(reply);
+ free(packet);
+#ifdef __MINGW32__
+ win32_close_socket(sock);
+#endif
+ return 1;
+ }
+
+ free(reply);
+ }
+
+ free(packet);
+ }
+
+#ifdef __MINGW32__
+ win32_close_socket(sock);
+#endif
+
+ return 0;
+}
--- /dev/null
+#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
--- /dev/null
+/*
+ * UglyLogging. Slow, yet another wheel reinvented, but enough to make the
+ * rest of our code pretty enough.
+ *
+ */
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <time.h>
+
+#include "stlink/logging.h"
+
+static int max_level;
+
+int ugly_init(int maximum_threshold) {
+ max_level = maximum_threshold;
+ return 0;
+}
+
+int ugly_log(int level, const char *tag, const char *format, ...) {
+ if (level > max_level) {
+ return 0;
+ }
+ va_list args;
+ va_start(args, format);
+ time_t mytt = time(NULL);
+ struct tm *tt;
+ tt = localtime(&mytt);
+ fprintf(stderr, "%d-%02d-%02dT%02d:%02d:%02d ", tt->tm_year + 1900, tt->tm_mon + 1, tt->tm_mday, tt->tm_hour, tt->tm_min, tt->tm_sec);
+ 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;
+ case UFATAL:
+ fprintf(stderr, "FATAL %s: ", tag);
+ vfprintf(stderr, format, args);
+ exit(EXIT_FAILURE);
+ // NEVER GETS HERE!!!
+ break;
+ default:
+ fprintf(stderr, "%d %s: ", level, tag);
+ break;
+ }
+ vfprintf(stderr, format, args);
+ va_end(args);
+ return 1;
+}
--- /dev/null
+#ifdef __MINGW32__
+
+#include "mingw.h"
+
+#undef socket
+#undef connect
+#undef accept
+#undef shutdown
+
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+int win32_poll(struct pollfd *fds, unsigned int nfds, int timo)
+{
+ struct timeval timeout, *toptr;
+ fd_set ifds, ofds, efds, *ip, *op;
+ unsigned int i, rc;
+
+ /* 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);
+ }
+
+ /* 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) {
+ int 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(int winsock_err)
+{
+ switch(winsock_err) {
+ case WSAEINVAL:
+ case WSAEALREADY:
+ case WSAEWOULDBLOCK:
+ errno = EINPROGRESS;
+ break;
+ default:
+ errno = winsock_err;
+ break;
+ }
+}
+
+static void
+set_socket_errno(int 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(int domain, int type, int 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.
+ */
+int
+win32_connect(SOCKET fd, struct sockaddr *addr, socklen_t addr_len)
+{
+ int 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 = -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.
+ */
+int
+win32_shutdown(SOCKET fd, int mode)
+{
+ int rc = shutdown(fd, mode);
+ assert(rc == 0 || rc == SOCKET_ERROR);
+ if(rc == SOCKET_ERROR) {
+ set_socket_errno(WSAGetLastError());
+ }
+ return rc;
+}
+
+int win32_close_socket(SOCKET fd)
+{
+ int rc = closesocket(fd);
+ if(rc == SOCKET_ERROR) {
+ set_socket_errno(WSAGetLastError());
+ }
+ return rc;
+}
+
+ssize_t win32_write_socket(SOCKET fd, void *buf, int n)
+{
+ int 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, int n)
+{
+ int 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 int 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);
+ }
+ /* NOTREACHED */
+}
+
+char *win32_strsep (char **stringp, const char *delim)
+{
+ register char *s;
+ register const char *spanp;
+ register int 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);
+ }
+ /* NOTREACHED */
+}
+
+#endif
+
+
--- /dev/null
+#ifdef __MINGW32__
+
+#include <io.h>
+
+#define _USE_W32_SOCKETS 1
+#include <windows.h>
+
+#define ENOTCONN WSAENOTCONN
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#define ENOBUFS WSAENOBUFS
+#define ECONNRESET WSAECONNRESET
+#define ESHUTDOWN WSAESHUTDOWN
+#define EAFNOSUPPORT WSAEAFNOSUPPORT
+#define EPROTONOSUPPORT WSAEPROTONOSUPPORT
+#define EINPROGRESS WSAEINPROGRESS
+#define EISCONN WSAEISCONN
+
+/* winsock doesn't feature poll(), so there is a version implemented
+ * in terms of select() in mingw.c. The following definitions
+ * are copied from linux man pages. A poll() macro is defined to
+ * call the version in mingw.c.
+ */
+#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 */
+ short events; /* requested events */
+ short revents; /* returned events */
+};
+#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 int instead of the usual socklen_t */
+typedef int socklen_t;
+
+int win32_poll(struct pollfd *, unsigned int, int);
+SOCKET win32_socket(int, int, int);
+int win32_connect(SOCKET, struct sockaddr*, socklen_t);
+SOCKET win32_accept(SOCKET, struct sockaddr*, socklen_t *);
+int win32_shutdown(SOCKET, int);
+int win32_close_socket(SOCKET fd);
+
+#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, int n);
+ssize_t win32_write_socket(SOCKET fd, void *buf, int n);
+
+static inline void sleep(unsigned ms) { Sleep(ms); }
+
+#endif
#include <stdlib.h>
#include <unistd.h>
-#include "mmap.h"
+#include "stlink/mmap.h"
void *mmap (void *addr, size_t len, int prot, int flags, int fd, long long offset) {
+++ /dev/null
-#ifndef STLINK_MMAP_H
-#define STLINK_MMAP_H
-
-#ifdef HAVE_SYS_MMAN_H
-#include <sys/mman.h>
-#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)
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
- void *mmap(void *addr, size_t len, int prot, int flags, int fd, long long offset);
- int munmap(void *addr, size_t len);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* HAVE_SYS_MMAN_H */
-
-#endif /* STLINK_MMAP_H */
--- /dev/null
+/*
+ * 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 <m@capitanio.org>
+ * The stlink related constants kindly provided by Oliver Spencer (OpenOCD)
+ * for use in a GPL compatible license.
+ *
+ * Tested compatibility: linux, gcc >= 4.3.3
+ *
+ * The communication is based on standard USB mass storage device
+ * BOT (Bulk Only Transfer)
+ * - Endpoint 1: BULK_IN, 64 bytes max
+ * - Endpoint 2: BULK_OUT, 64 bytes max
+ *
+ * All CBW transfers are ordered with the LSB (byte 0) first (little endian).
+ * Any command must be answered before sending the next command.
+ * Each USB transfer must complete in less than 1s.
+ *
+ * SB Device Class Definition for Mass Storage Devices:
+ * www.usb.org/developers/devclass_docs/usbmassbulk_10.pdf
+ *
+ * dt - Data Transfer (IN/OUT)
+ * CBW - Command Block Wrapper
+ * CSW - Command Status Wrapper
+ * RFU - Reserved for Future Use
+ *
+ * Originally, this driver used scsi pass through commands, which required the
+ * usb-storage module to be loaded, providing the /dev/sgX links. The USB mass
+ * storage implementation on the STLinkv1 is however terribly broken, and it can
+ * take many minutes for the kernel to give up.
+ *
+ * However, in Nov 2011, the scsi pass through was replaced by raw libusb, so
+ * instead of having to let usb-storage struggle with the device, and also greatly
+ * limiting the portability of the driver, you can now tell usb-storage to simply
+ * ignore this device completely.
+ *
+ * usb-storage.quirks
+ * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob_plain;f=Documentation/kernel-parameters.txt
+ * Each entry has the form VID:PID:Flags where VID and PID are Vendor and Product
+ * ID values (4-digit hex numbers) and Flags is a set of characters, each corresponding
+ * to a common usb-storage quirk flag as follows:
+ *
+ * a = SANE_SENSE (collect more than 18 bytes of sense data);
+ * b = BAD_SENSE (don't collect more than 18 bytes of sense data);
+ * c = FIX_CAPACITY (decrease the reported device capacity by one sector);
+ * h = CAPACITY_HEURISTICS (decrease the reported device capacity by one sector if the number is odd);
+ * i = IGNORE_DEVICE (don't bind to this device);
+ * l = NOT_LOCKABLE (don't try to lock and unlock ejectable media);
+ * m = MAX_SECTORS_64 (don't transfer more than 64 sectors = 32 KB at a time);
+ * o = CAPACITY_OK (accept the capacity reported by the device);
+ * r = IGNORE_RESIDUE (the device reports bogus residue values);
+ * s = SINGLE_LUN (the device has only one Logical Unit);
+ * w = NO_WP_DETECT (don't test whether the medium is write-protected).
+ *
+ * Example: quirks=0419:aaf5:rl,0421:0433:rc
+ * http://permalink.gmane.org/gmane.linux.usb.general/35053
+ *
+ * For the stlinkv1, you just want the following
+ *
+ * modprobe -r usb-storage && modprobe usb-storage quirks=483:3744:i
+ *
+ * Equivalently, you can add a line saying
+ *
+ * options usb-storage quirks=483:3744:i
+ *
+ * to your /etc/modprobe.conf or /etc/modprobe.d/local.conf (or add the "quirks=..."
+ * part to an existing options line for usb-storage).
+ */
+
+
+#define __USE_GNU
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include "stlink.h"
+#include "stlink/logging.h"
+
+static void clear_cdb(struct stlink_libsg *sl) {
+ for (size_t i = 0; i < sizeof (sl->cdb_cmd_blk); i++)
+ sl->cdb_cmd_blk[i] = 0;
+ // 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 int get_usb_mass_storage_status(libusb_device_handle *handle, uint8_t endpoint, uint32_t *tag)
+{
+ unsigned char csw[13];
+ memset(csw, 0, sizeof(csw));
+ int transferred;
+ int ret;
+ int try = 0;
+ 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 int dump_CDB_command(uint8_t *cdb, uint8_t cdb_len) {
+ char dbugblah[100];
+ char *dbugp = dbugblah;
+ dbugp += sprintf(dbugp, "Sending CDB [");
+ for (uint8_t i = 0; i < cdb_len; i++) {
+ dbugp += sprintf(dbugp, " %#02x", (unsigned int) cdb[i]);
+ }
+ sprintf(dbugp, "]\n");
+ DLOG(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
+ */
+int send_usb_mass_storage_command(libusb_device_handle *handle, uint8_t endpoint_out,
+ uint8_t *cdb, uint8_t cdb_length,
+ uint8_t lun, uint8_t flags, uint32_t expected_rx_size) {
+ 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;
+ }
+
+ int try = 0;
+ int ret = 0;
+ int real_transferred;
+ int 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);
+
+ int 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];
+ int transferred;
+ int ret;
+ int 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 != %d\n", transferred, sizeof(sense));
+ }
+ uint32_t received_tag;
+ int 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.
+ */
+int send_usb_data_only(libusb_device_handle *handle, unsigned char endpoint_out,
+ unsigned char endpoint_in, unsigned char *cbuf, unsigned int length) {
+ int ret;
+ int real_transferred;
+ int try = 0;
+ 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
+ int 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;
+}
+
+
+int 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...
+ int rx_length = sl->q_len;
+ int try = 0;
+ int real_transferred;
+ int 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
+ int 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);
+ }
+}
+
+
+int _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
+
+int _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.
+
+int _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_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)
+
+int _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_ENTER;
+ sg->cdb_cmd_blk[2] = STLINK_DEBUG_ENTER_JTAG;
+ 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
+int _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
+ */
+}
+
+int _stlink_sg_core_id(stlink_t *sl) {
+ struct stlink_libsg *sg = sl->backend_data;
+ int 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.
+
+int _stlink_sg_reset(stlink_t *sl) {
+ struct stlink_libsg *sg = sl->backend_data;
+ clear_cdb(sg);
+ sg->cdb_cmd_blk[1] = STLINK_DEBUG_RESETSYS;
+ sl->q_len = 2;
+ sg->q_addr = 0;
+ if (stlink_q(sl))
+ return -1;
+
+ stlink_stat(sl, "core reset");
+ return 0;
+}
+
+// Arm-core reset -> halted state.
+
+int _stlink_sg_jtag_reset(stlink_t *sl, int value) {
+ struct stlink_libsg *sg = sl->backend_data;
+ clear_cdb(sg);
+ sg->cdb_cmd_blk[1] = STLINK_JTAG_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.
+
+int _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.
+
+int _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.
+
+int _stlink_sg_read_all_regs(stlink_t *sl, reg *regp) {
+ struct stlink_libsg *sg = sl->backend_data;
+
+ clear_cdb(sg);
+ sg->cdb_cmd_blk[1] = STLINK_DEBUG_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 (int 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
+
+int _stlink_sg_read_reg(stlink_t *sl, int r_idx, reg *regp) {
+ struct stlink_libsg *sg = sl->backend_data;
+ clear_cdb(sg);
+ sg->cdb_cmd_blk[1] = STLINK_DEBUG_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
+
+int _stlink_sg_write_reg(stlink_t *sl, uint32_t reg, int idx) {
+ struct stlink_libsg *sg = sl->backend_data;
+ clear_cdb(sg);
+ sg->cdb_cmd_blk[1] = STLINK_DEBUG_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_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.
+
+int _stlink_sg_run(stlink_t *sl) {
+ struct stlink_libsg *sg = sl->backend_data;
+ 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.
+
+int _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
+// see Cortex-M3 Technical Reference Manual
+// TODO make delegate!
+void stlink_set_hw_bp(stlink_t *sl, int fp_nr, uint32_t addr, int 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_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
+
+// TODO make delegate!
+void stlink_clr_hw_bp(stlink_t *sl, int 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_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)
+
+int _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.
+
+int _stlink_sg_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len) {
+ struct stlink_libsg *sg = sl->backend_data;
+ int 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.
+
+int _stlink_sg_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
+ struct stlink_libsg *sg = sl->backend_data;
+ int 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
+
+int _stlink_sg_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data) {
+ struct stlink_libsg *sg = sl->backend_data;
+ clear_cdb(sg);
+ sg->cdb_cmd_blk[1] = STLINK_JTAG_WRITEDEBUG_32BIT;
+ // 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
+
+int _stlink_sg_read_debug32(stlink_t *sl, uint32_t addr, uint32_t *data) {
+ struct stlink_libsg *sg = sl->backend_data;
+ clear_cdb(sg);
+ sg->cdb_cmd_blk[1] = STLINK_JTAG_READDEBUG_32BIT;
+ // 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.
+
+int _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
+
+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
+};
+
+static stlink_t* stlink_open(const int verbose) {
+
+ stlink_t *sl = malloc(sizeof (stlink_t));
+ memset(sl, 0, 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");
+ return NULL;
+ }
+
+ if (libusb_init(&(slsg->libusb_ctx))) {
+ WLOG("failed to init libusb context, wrong version of libraries?\n");
+ free(sl);
+ free(slsg);
+ return NULL;
+ }
+
+ libusb_set_debug(slsg->libusb_ctx, 3);
+
+ slsg->usb_handle = libusb_open_device_with_vid_pid(slsg->libusb_ctx, USB_ST_VID, USB_STLINK_PID);
+ 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) {
+ int 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");
+ }
+
+ int 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 = STLINK_CORE_STAT_UNKNOWN;
+ slsg->q_addr = 0;
+
+ return sl;
+}
+
+
+stlink_t* stlink_v1_open_inner(const int 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 != USB_ST_VID) || (sl->version.stlink_pid != USB_STLINK_PID)) {
+ 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 != USB_ST_VID) || (sl->version.stlink_pid != USB_STLINK_PID)) {
+ ELOG("WTF? successfully opened, but unable to read version details. BROKEN!\n");
+ return NULL;
+ }
+
+ return sl;
+}
+
+stlink_t* stlink_v1_open(const int verbose, int 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);
+ }
+ stlink_load_device_params(sl);
+ ILOG("Successfully opened a stlink v1 debugger\n");
+ return sl;
+}
+++ /dev/null
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-
-#include <stlink-common.h>
-
-static void usage(void)
-{
- puts("st-info --flash");
- puts("st-info --sram");
- puts("st-info --descr");
- puts("st-info --pagesize");
- puts("st-info --chipid");
- puts("st-info --serial");
- puts("st-info --hla-serial");
- puts("st-info --probe");
-}
-
-/* Print normal or OpenOCD hla_serial with newline */
-static void stlink_print_serial(stlink_t *sl, bool openocd)
-{
- const char *fmt;
-
- if (openocd) {
- printf("\"");
- fmt = "\\x%02x";
- } else {
- fmt = "%02x";
- }
-
- for (int n = 0; n < sl->serial_size; n++)
- printf(fmt, sl->serial[n]);
-
- if (openocd)
- printf("\"");
- printf("\n");
-}
-
-static void stlink_print_info(stlink_t *sl)
-{
- const chip_params_t *params = NULL;
-
- if (!sl)
- return;
-
- printf(" serial: ");
- stlink_print_serial(sl, false);
- printf("openocd: ");
- stlink_print_serial(sl, true);
-
- printf(" flash: %zu (pagesize: %zu)\n", sl->flash_size, sl->flash_pgsz);
- printf(" sram: %zu\n", sl->sram_size);
- printf(" chipid: 0x%.4x\n", sl->chip_id);
-
- for (size_t i = 0; i < sizeof(devices) / sizeof(devices[0]); i++) {
- if (devices[i].chip_id == sl->chip_id) {
- params = &devices[i];
- break;
- }
- }
-
- if (params)
- printf(" descr: %s\n", params->description);
-}
-
-static void stlink_probe(void)
-{
- stlink_t **stdevs;
- size_t size;
-
- size = stlink_probe_usb(&stdevs);
-
- printf("Found %zu stlink programmers\n", size);
-
- for (size_t n = 0; n < size; n++)
- stlink_print_info(stdevs[n]);
-
- stlink_probe_usb_free(&stdevs, size);
-}
-
-static stlink_t *stlink_open_first(void)
-{
- stlink_t* sl = NULL;
- sl = stlink_v1_open(0, 1);
- if (sl == NULL)
- sl = stlink_open_usb(0, 1, NULL);
-
- return sl;
-}
-
-static int print_data(char **av)
-{
- stlink_t* sl = NULL;
-
- // Probe needs all devices unclaimed
- if (strcmp(av[1], "--probe") == 0) {
- stlink_probe();
- return 0;
- }
-
- sl = stlink_open_first();
-
- if (sl == NULL) {
- return -1;
- }
-
- sl->verbose = 0;
-
- if (stlink_current_mode(sl) == STLINK_DEV_DFU_MODE)
- stlink_exit_dfu_mode(sl);
-
- if (stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE)
- stlink_enter_swd_mode(sl);
-
- if (strcmp(av[1], "--flash") == 0)
- printf("0x%zx\n", sl->flash_size);
- else if (strcmp(av[1], "--sram") == 0)
- printf("0x%zx\n", sl->sram_size);
- else if (strcmp(av[1], "--pagesize") == 0)
- printf("0x%zx\n", sl->flash_pgsz);
- else if (strcmp(av[1], "--chipid") == 0)
- printf("0x%.4x\n", sl->chip_id);
- else if (strcmp(av[1], "--serial") == 0)
- stlink_print_serial(sl, false);
- else if (strcmp(av[1], "--hla-serial") == 0)
- stlink_print_serial(sl, true);
- else if (strcmp(av[1], "--descr") == 0) {
- const chip_params_t *params = NULL;
- for (size_t i = 0; i < sizeof(devices) / sizeof(devices[0]); i++) {
- if(devices[i].chip_id == sl->chip_id) {
- params = &devices[i];
- break;
- }
- }
- if (params == NULL) {
- return -1;
- }
- printf("%s\n", params->description);
- }
-
- if (sl)
- {
- stlink_exit_debug_mode(sl);
- stlink_close(sl);
- }
-
- return 0;
-}
-
-int main(int ac, char** av)
-{
- int err = -1;
- if (ac < 2) {
- usage();
- return -1;
- }
-
- err = print_data(av);
-
- return err;
-}
+++ /dev/null
-#include <stdio.h>
-#include <stdlib.h>
-/* According to POSIX.1-2001 */
-#include <sys/select.h>
-#include <string.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <termios.h>
-#include <fcntl.h>
-#include <signal.h>
-#include "stlink-common.h"
-
-/* STLinky structure on STM chip
-
-struct stlinky {
- uint32_t magic;
- uint32_t bufsize;
- uint32_t up_tail;
- uint32_t up_head;
- uint32_t dw_tail;
- uint32_t dw_head;
- char upbuf[CONFIG_LIB_STLINKY_BSIZE];
- char dwbuf[CONFIG_LIB_STLINKY_BSIZE];
-} __attribute__ ((packed));
-*/
-
-
-#define STLINKY_MAGIC 0xDEADF00D
-
-#define ST_TERM_MAX_BUFF_SIZE (1024*1024) //1Mb
-
-#define RX_Q_OFFSET 8
-#define RX_BUFF_OFFSET 24
-#define TX_Q_OFFSET 16
-#define TX_BUFF_OFFSET(bufsize) (24 + bufsize)
-
-#define READ_UINT32_LE(buf) ((uint32_t) ( buf[0] \
- | buf[1] << 8 \
- | buf[2] << 16 \
- | buf[3] << 24))
-
-static stlink_t* sl;
-sigset_t sig_mask;
-
-struct stlinky {
- stlink_t *sl;
- uint32_t off;
- size_t bufsize;
-};
-
-void nonblock(int state);
-
-static void cleanup(int signal __attribute__((unused))) {
- if (sl) {
- /* Switch back to mass storage mode before closing. */
- stlink_run(sl);
- stlink_exit_debug_mode(sl);
- stlink_close(sl);
- }
-
- printf("\n");
- nonblock(0);
- exit(1);
-}
-
-void sig_init() {
- sigemptyset(&sig_mask);
- sigaddset(&sig_mask, SIGINT);
- sigaddset(&sig_mask, SIGTERM);
- signal(SIGINT, &cleanup);
- signal(SIGTERM, &cleanup);
- sigprocmask(SIG_BLOCK, &sig_mask, NULL);
-}
-
-void sig_process() {
- sigset_t pending;
- sigpending(&pending);
- if (sigismember(&pending, SIGINT) || sigismember(&pending, SIGTERM)) {
- sigprocmask(SIG_UNBLOCK, &sig_mask, NULL);
- sigsuspend(&pending);
- sigprocmask(SIG_BLOCK, &sig_mask, NULL);
- }
-}
-
-/* Detects stlinky in RAM, returns handler */
-struct stlinky* stlinky_detect(stlink_t* sl)
-{
- static const uint32_t sram_base = 0x20000000;
- struct stlinky* st = malloc(sizeof(struct stlinky));
- int multiple=0;
- st->sl = sl;
- printf("sram: 0x%x bytes @ 0x%zx\n", sl->sram_base, sl->sram_size);
- uint32_t off;
- for (off = 0; off < sl->sram_size; off += 4) {
- if (off % 1024 == 0) sig_process();
- stlink_read_mem32(sl, sram_base + off, 4);
- if (STLINKY_MAGIC == READ_UINT32_LE(sl->q_buf))
- {
- if (multiple > 0) printf("WARNING: another ");
- printf("stlinky detected at 0x%x\n", sram_base + off);
- st->off = sram_base + off;
- stlink_read_mem32(sl, st->off + 4, 4);
- st->bufsize = READ_UINT32_LE(sl->q_buf);
- printf("stlinky buffer size 0x%zu \n", st->bufsize);
- multiple++;
- }
- }
- if (multiple > 0) {
- if (multiple > 1) {
- printf("Using last stlinky structure detected\n");
- }
- return st;
- }
- return NULL;
-}
-
-static void stlinky_read_buff(struct stlinky *st, uint32_t off, uint32_t size, char *buffer)
-{
- int aligned_size;
-
- if (size == 0)
- return;
-
- //Read from device with 4-byte alignment
- aligned_size = (size & 0xFFFFFFFC) + 8;
- stlink_read_mem32(st->sl, off & 0xFFFFFFFC, aligned_size);
-
- //copy to local buffer
- memcpy(buffer, st->sl->q_buf + (off & 0x3), size);
-
- return;
-}
-
-static void stlinky_write_buf(struct stlinky *st, uint32_t off, uint32_t size, char *buffer)
-{
- memcpy(st->sl->q_buf, buffer, size);
- stlink_write_mem8(st->sl, off, size);
- return;
-}
-
-size_t stlinky_rx(struct stlinky *st, char* buffer)
-{
- //read head and tail values
- uint32_t tail, head;
- stlink_read_mem32(st->sl, st->off + RX_Q_OFFSET, sizeof(tail) + sizeof(head));
- memcpy(&tail, &st->sl->q_buf[0], sizeof(tail));
- memcpy(&head, &st->sl->q_buf[sizeof(tail)], sizeof(head));
-
- //return if empty
- if(head == tail)
- return 0;
-
- //read data
- int size_read = 0;
- if(head > tail){
- stlinky_read_buff(st, st->off + RX_BUFF_OFFSET + tail, head - tail, buffer);
- size_read += head - tail;
- } else if(head < tail){
- stlinky_read_buff(st, st->off + RX_BUFF_OFFSET + tail, st->bufsize - tail, buffer);
- size_read += st->bufsize - tail;
-
- stlinky_read_buff(st, st->off + RX_BUFF_OFFSET, head, buffer + size_read);
- size_read += head;
- }
-
- //move tail
- tail = (tail + size_read) % st->bufsize;
-
- //write tail
- memcpy(st->sl->q_buf, &tail, sizeof(tail));
- stlink_write_mem32(st->sl, st->off + RX_Q_OFFSET, sizeof(tail));
-
- return size_read;
-}
-
-size_t stlinky_tx(struct stlinky *st, char* buffer, size_t siz)
-{
- //read head and tail values
- uint32_t tail, head;
- stlink_read_mem32(st->sl, st->off + TX_Q_OFFSET, sizeof(tail) + sizeof(head));
- memcpy(&tail, &st->sl->q_buf[0], sizeof(tail));
- memcpy(&head, &st->sl->q_buf[sizeof(tail)], sizeof(head));
-
- //Figure out buffer usage
- int usage = head - tail;
- if (usage < 0)
- usage += st->bufsize;
-
- //check if new data will fit
- if (usage + siz >= st->bufsize)
- return 0;
-
- //copy in data (take care of possible split)
- int first_chunk = head + siz >= st->bufsize ? st->bufsize - head : siz;
- int second_chunk = siz - first_chunk;
-
- //copy data
- stlinky_write_buf(st, st->off + TX_BUFF_OFFSET(st->bufsize) + head, first_chunk, buffer);
- if (second_chunk > 0)
- stlinky_write_buf(st, st->off + TX_BUFF_OFFSET(st->bufsize),
- second_chunk, buffer + first_chunk);
-
- //increment head pointer
- head = (head + siz) % st->bufsize;
- memcpy(st->sl->q_buf, &head, sizeof(head));
- stlink_write_mem32(st->sl, st->off + TX_Q_OFFSET + sizeof(tail), sizeof(head));
-
- return siz;
-}
-
-int kbhit()
-{
- struct timeval tv;
- fd_set fds;
- tv.tv_sec = 0;
- tv.tv_usec = 0;
- FD_ZERO(&fds);
- FD_SET(STDIN_FILENO, &fds); //STDIN_FILENO is 0
- select(STDIN_FILENO+1, &fds, NULL, NULL, &tv);
- return FD_ISSET(STDIN_FILENO, &fds);
-}
-
-void nonblock(int state)
-{
- struct termios ttystate;
-
- //get the terminal state
- tcgetattr(STDIN_FILENO, &ttystate);
-
- if (state==1)
- {
- //turn off canonical mode
- ttystate.c_lflag &= ~ICANON;
- ttystate.c_lflag &= ~ECHO;
- //minimum of number input read.
- ttystate.c_cc[VMIN] = 1;
- }
- else if (state==0)
- {
- //turn on canonical mode
- ttystate.c_lflag |= ICANON | ECHO;
- }
- //set the terminal attributes.
- tcsetattr(STDIN_FILENO, TCSANOW, &ttystate);
-
-}
-
-int main(int ac, char** av) {
- struct stlinky *st=NULL;
-
- sig_init();
-
- sl = stlink_open_usb(10, 1, NULL);
- if (sl != NULL) {
- printf("ST-Linky proof-of-concept terminal :: Created by Necromant for lulz\n");
- stlink_version(sl);
- stlink_enter_swd_mode(sl);
- printf("chip id: %#x\n", sl->chip_id);
- printf("core_id: %#x\n", sl->core_id);
-
- cortex_m3_cpuid_t cpuid;
- stlink_cpu_id(sl, &cpuid);
- 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);
-
- stlink_reset(sl);
- stlink_force_debug(sl);
- stlink_run(sl);
- stlink_status(sl);
-
- /* wait for device to boot */
- /* TODO: Make timeout adjustable via command line */
- sleep(1);
-
- if(ac == 1){
- st = stlinky_detect(sl);
- }else if(ac == 2){
- st = malloc(sizeof(struct stlinky));
- st->sl = sl;
- st->off = (int)strtol(av[1], NULL, 16);
- printf("using stlinky at 0x%x\n", st->off);
- stlink_read_mem32(sl, st->off + 4, 4);
- st->bufsize = READ_UINT32_LE(sl->q_buf);
- printf("stlinky buffer size 0x%zu \n", st->bufsize);
- }else{
- cleanup(0);
- }
- if (st == NULL)
- {
- printf("stlinky magic not found in sram :(\n");
- cleanup(0);
- }
- if (st->bufsize > ST_TERM_MAX_BUFF_SIZE){
- printf("stlinky buffer size too big\n");
- cleanup(0);
- }
- char* rxbuf = malloc(st->bufsize);
- char* txbuf = malloc(st->bufsize);
- size_t tmp;
- nonblock(1);
- int fd = fileno(stdin);
- int saved_flags = fcntl(fd, F_GETFL);
- fcntl(fd, F_SETFL, saved_flags & ~O_NONBLOCK);
- printf("Entering interactive terminal. CTRL+C to exit\n\n\n");
- while(1) {
- sig_process();
- tmp = stlinky_rx(st, rxbuf);
- if(tmp > 0)
- {
- fwrite(rxbuf,tmp,1,stdout);
- fflush(stdout);
- }
- if (kbhit()) {
- tmp = read(fd, txbuf, st->bufsize);
- stlinky_tx(st,txbuf,tmp);
- }
- }
- }
- return 0;
-}
+++ /dev/null
-#define DEBUG_FLASH 0
-
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include "mmap.h"
-
-#include "stlink-common.h"
-#include "uglylogging.h"
-
-#ifndef _WIN32
-#define O_BINARY 0
-#endif
-
-/* todo: stm32l15xxx flash memory, pm0062 manual */
-
-/* stm32f FPEC flash controller interface, pm0063 manual */
-// TODO - all of this needs to be abstracted out....
-// STM32F05x is identical, based on RM0091 (DM00031936, Doc ID 018940 Rev 2, August 2012)
-#define FLASH_REGS_ADDR 0x40022000
-#define FLASH_REGS_SIZE 0x28
-
-#define FLASH_ACR (FLASH_REGS_ADDR + 0x00)
-#define FLASH_KEYR (FLASH_REGS_ADDR + 0x04)
-#define FLASH_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)
-
-// For STM32F05x, the RDPTR_KEY may be wrong, but as it is not used anywhere...
-#define FLASH_RDPTR_KEY 0x00a5
-#define FLASH_KEY1 0x45670123
-#define FLASH_KEY2 0xcdef89ab
-
-#define FLASH_SR_BSY 0
-#define FLASH_SR_EOP 5
-
-#define FLASH_CR_PG 0
-#define FLASH_CR_PER 1
-#define FLASH_CR_MER 2
-#define FLASH_CR_STRT 6
-#define FLASH_CR_LOCK 7
-
-
-//32L = 32F1 same CoreID as 32F4!
-#define STM32L_FLASH_REGS_ADDR ((uint32_t)0x40023c00)
-#define STM32L_FLASH_ACR (STM32L_FLASH_REGS_ADDR + 0x00)
-#define STM32L_FLASH_PECR (STM32L_FLASH_REGS_ADDR + 0x04)
-#define STM32L_FLASH_PDKEYR (STM32L_FLASH_REGS_ADDR + 0x08)
-#define STM32L_FLASH_PEKEYR (STM32L_FLASH_REGS_ADDR + 0x0c)
-#define STM32L_FLASH_PRGKEYR (STM32L_FLASH_REGS_ADDR + 0x10)
-#define STM32L_FLASH_OPTKEYR (STM32L_FLASH_REGS_ADDR + 0x14)
-#define STM32L_FLASH_SR (STM32L_FLASH_REGS_ADDR + 0x18)
-#define STM32L_FLASH_OBR (STM32L_FLASH_REGS_ADDR + 0x1c)
-#define STM32L_FLASH_WRPR (STM32L_FLASH_REGS_ADDR + 0x20)
-#define FLASH_L1_FPRG 10
-#define FLASH_L1_PROG 3
-
-//32L4 register base is at FLASH_REGS_ADDR (0x40022000)
-#define STM32L4_FLASH_KEYR (FLASH_REGS_ADDR + 0x08)
-#define STM32L4_FLASH_SR (FLASH_REGS_ADDR + 0x10)
-#define STM32L4_FLASH_CR (FLASH_REGS_ADDR + 0x14)
-#define STM32L4_FLASH_OPTR (FLASH_REGS_ADDR + 0x20)
-
-#define STM32L4_FLASH_SR_BSY 16
-#define STM32L4_FLASH_SR_ERRMASK 0x3f8 /* SR [9:3] */
-
-#define STM32L4_FLASH_CR_LOCK 31 /* Lock control register */
-#define STM32L4_FLASH_CR_PG 0 /* Program */
-#define STM32L4_FLASH_CR_PER 1 /* Page erase */
-#define STM32L4_FLASH_CR_MER1 2 /* Bank 1 erase */
-#define STM32L4_FLASH_CR_MER2 15 /* Bank 2 erase */
-#define STM32L4_FLASH_CR_STRT 16 /* Start command */
-#define STM32L4_FLASH_CR_BKER 11 /* Bank select for page erase */
-#define STM32L4_FLASH_CR_PNB 3 /* Page number (8 bits) */
-// Bits requesting flash operations (useful when we want to clear them)
-#define STM32L4_FLASH_CR_OPBITS \
- ((1lu<<STM32L4_FLASH_CR_PG) | (1lu<<STM32L4_FLASH_CR_PER) \
- | (1lu<<STM32L4_FLASH_CR_MER1) | (1lu<<STM32L4_FLASH_CR_MER1))
-// Page is fully specified by BKER and PNB
-#define STM32L4_FLASH_CR_PAGEMASK (0x1fflu << STM32L4_FLASH_CR_PNB)
-
-#define STM32L4_FLASH_OPTR_DUALBANK 21
-
-//STM32L0x flash register base and offsets
-//same as 32L1 above
-// RM0090 - DM00031020.pdf
-#define STM32L0_FLASH_REGS_ADDR ((uint32_t)0x40022000)
-#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)
-
-
-
-//STM32F4
-#define FLASH_F4_REGS_ADDR ((uint32_t)0x40023c00)
-#define FLASH_F4_KEYR (FLASH_F4_REGS_ADDR + 0x04)
-#define FLASH_F4_OPT_KEYR (FLASH_F4_REGS_ADDR + 0x08)
-#define FLASH_F4_SR (FLASH_F4_REGS_ADDR + 0x0c)
-#define FLASH_F4_CR (FLASH_F4_REGS_ADDR + 0x10)
-#define FLASH_F4_OPT_CR (FLASH_F4_REGS_ADDR + 0x14)
-#define FLASH_F4_CR_STRT 16
-#define FLASH_F4_CR_LOCK 31
-#define FLASH_F4_CR_SER 1
-#define FLASH_F4_CR_SNB 3
-#define FLASH_F4_CR_SNB_MASK 0xf8
-#define FLASH_F4_SR_BSY 16
-
-#define L1_WRITE_BLOCK_SIZE 0x80
-#define L0_WRITE_BLOCK_SIZE 0x40
-
-void write_uint32(unsigned char* buf, uint32_t ui) {
- if (!is_bigendian()) { // le -> le (don't swap)
- buf[0] = ((unsigned char*) &ui)[0];
- buf[1] = ((unsigned char*) &ui)[1];
- buf[2] = ((unsigned char*) &ui)[2];
- buf[3] = ((unsigned char*) &ui)[3];
- } else {
- buf[0] = ((unsigned char*) &ui)[3];
- buf[1] = ((unsigned char*) &ui)[2];
- buf[2] = ((unsigned char*) &ui)[1];
- buf[3] = ((unsigned char*) &ui)[0];
- }
-}
-
-void write_uint16(unsigned char* buf, uint16_t ui) {
- if (!is_bigendian()) { // le -> le (don't swap)
- buf[0] = ((unsigned char*) &ui)[0];
- buf[1] = ((unsigned char*) &ui)[1];
- } else {
- buf[0] = ((unsigned char*) &ui)[1];
- buf[1] = ((unsigned char*) &ui)[0];
- }
-}
-
-uint32_t read_uint32(const unsigned char *c, const int pt) {
- uint32_t ui;
- char *p = (char *) &ui;
-
- if (!is_bigendian()) { // le -> le (don't swap)
- p[0] = c[pt + 0];
- p[1] = c[pt + 1];
- p[2] = c[pt + 2];
- p[3] = c[pt + 3];
- } else {
- p[0] = c[pt + 3];
- p[1] = c[pt + 2];
- p[2] = c[pt + 1];
- p[3] = c[pt + 0];
- }
- return ui;
-}
-
-static uint32_t __attribute__((unused)) read_flash_rdp(stlink_t *sl) {
- uint32_t rdp;
- stlink_read_debug32(sl, FLASH_WRPR, &rdp);
- return rdp & 0xff;
-}
-
-static inline uint32_t read_flash_wrpr(stlink_t *sl) {
- uint32_t wrpr;
- stlink_read_debug32(sl, FLASH_WRPR, &wrpr);
- return wrpr;
-}
-
-static inline uint32_t read_flash_obr(stlink_t *sl) {
- uint32_t obr;
- stlink_read_debug32(sl, FLASH_OBR, &obr);
- return obr;
-}
-
-static inline uint32_t read_flash_cr(stlink_t *sl) {
- uint32_t reg, res;
-
- if (sl->flash_type == FLASH_TYPE_F4)
- reg = FLASH_F4_CR;
- else if (sl->flash_type == FLASH_TYPE_L4)
- reg = STM32L4_FLASH_CR;
- else
- reg = FLASH_CR;
-
- stlink_read_debug32(sl, reg, &res);
-
-#if DEBUG_FLASH
- fprintf(stdout, "CR:0x%x\n", res);
-#endif
- return res;
-}
-
-static inline unsigned int is_flash_locked(stlink_t *sl) {
- /* return non zero for true */
- uint32_t cr_lock_shift, cr = read_flash_cr(sl);
-
- if (sl->flash_type == FLASH_TYPE_F4)
- cr_lock_shift = FLASH_F4_CR_LOCK;
- else if (sl->flash_type == FLASH_TYPE_L4)
- cr_lock_shift = STM32L4_FLASH_CR_LOCK;
- else
- cr_lock_shift = FLASH_CR_LOCK;
-
- return cr & (1 << cr_lock_shift);
-}
-
-static void unlock_flash(stlink_t *sl) {
- uint32_t key_reg;
- /* 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 == FLASH_TYPE_F4)
- key_reg = FLASH_F4_KEYR;
- else if (sl->flash_type == FLASH_TYPE_L4)
- key_reg = STM32L4_FLASH_KEYR;
- else
- key_reg = FLASH_KEYR;
-
- stlink_write_debug32(sl, key_reg, FLASH_KEY1);
- stlink_write_debug32(sl, key_reg, FLASH_KEY2);
-}
-
-static int unlock_flash_if(stlink_t *sl) {
- /* unlock flash if already locked */
-
- if (is_flash_locked(sl)) {
- unlock_flash(sl);
- if (is_flash_locked(sl)) {
- WLOG("Failed to unlock flash!\n");
- return -1;
- }
- }
- DLOG("Successfully unlocked flash\n");
- return 0;
-}
-
-static void lock_flash(stlink_t *sl) {
- uint32_t cr_lock_shift, cr_reg, n;
-
- if (sl->flash_type == FLASH_TYPE_F4) {
- cr_reg = FLASH_F4_CR;
- cr_lock_shift = FLASH_F4_CR_LOCK;
- } else if (sl->flash_type == FLASH_TYPE_L4) {
- cr_reg = STM32L4_FLASH_CR;
- cr_lock_shift = STM32L4_FLASH_CR_LOCK;
- } else {
- cr_reg = FLASH_CR;
- cr_lock_shift = FLASH_CR_LOCK;
- }
-
- n = read_flash_cr(sl) | (1 << cr_lock_shift);
- stlink_write_debug32(sl, cr_reg, n);
-}
-
-
-static void set_flash_cr_pg(stlink_t *sl) {
- uint32_t cr_reg, x;
-
- x = read_flash_cr(sl);
-
- if (sl->flash_type == FLASH_TYPE_F4) {
- cr_reg = FLASH_F4_CR;
- x |= 1 << FLASH_CR_PG;
- } else if (sl->flash_type == FLASH_TYPE_L4) {
- cr_reg = STM32L4_FLASH_CR;
- x &= ~STM32L4_FLASH_CR_OPBITS;
- x |= 1 << STM32L4_FLASH_CR_PG;
- } else {
- cr_reg = FLASH_CR;
- x = 1 << FLASH_CR_PG;
- }
-
- stlink_write_debug32(sl, cr_reg, x);
-}
-
-static void __attribute__((unused)) clear_flash_cr_pg(stlink_t *sl) {
- uint32_t cr_reg, n;
-
- if (sl->flash_type == FLASH_TYPE_F4)
- cr_reg = FLASH_F4_CR;
- else if (sl->flash_type == FLASH_TYPE_L4)
- cr_reg = STM32L4_FLASH_CR;
- else
- cr_reg = FLASH_CR;
-
- n = read_flash_cr(sl) & ~(1 << FLASH_CR_PG);
- stlink_write_debug32(sl, cr_reg, n);
-}
-
-static void set_flash_cr_per(stlink_t *sl) {
- const uint32_t n = 1 << FLASH_CR_PER;
- stlink_write_debug32(sl, FLASH_CR, n);
-}
-
-static void __attribute__((unused)) clear_flash_cr_per(stlink_t *sl) {
- const uint32_t n = read_flash_cr(sl) & ~(1 << FLASH_CR_PER);
- stlink_write_debug32(sl, FLASH_CR, n);
-}
-
-static void set_flash_cr_mer(stlink_t *sl) {
- uint32_t val, cr_reg, cr_mer;
-
- if (sl->flash_type == FLASH_TYPE_F4) {
- cr_reg = FLASH_F4_CR;
- cr_mer = 1 << FLASH_CR_MER;
- } else if (sl->flash_type == FLASH_TYPE_L4) {
- cr_reg = STM32L4_FLASH_CR;
- cr_mer = (1 << STM32L4_FLASH_CR_MER1) | (1 << STM32L4_FLASH_CR_MER2);
- } else {
- cr_reg = FLASH_CR;
- cr_mer = 1 << FLASH_CR_MER;
- }
-
- stlink_read_debug32(sl, cr_reg, &val);
- val |= cr_mer;
- stlink_write_debug32(sl, cr_reg, val);
-}
-
-static void __attribute__((unused)) clear_flash_cr_mer(stlink_t *sl) {
- uint32_t val, cr_reg, cr_mer;
-
- if (sl->flash_type == FLASH_TYPE_F4) {
- cr_reg = FLASH_F4_CR;
- cr_mer = 1 << FLASH_CR_MER;
- } else if (sl->flash_type == FLASH_TYPE_L4) {
- cr_reg = STM32L4_FLASH_CR;
- cr_mer = (1 << STM32L4_FLASH_CR_MER1) | (1 << STM32L4_FLASH_CR_MER2);
- } else {
- cr_reg = FLASH_CR;
- cr_mer = 1 << FLASH_CR_MER;
- }
-
- stlink_read_debug32(sl, cr_reg, &val);
- val &= ~cr_mer;
- stlink_write_debug32(sl, cr_reg, val);
-}
-
-static void set_flash_cr_strt(stlink_t *sl) {
- uint32_t val, cr_reg, cr_strt;
-
- if (sl->flash_type == FLASH_TYPE_F4) {
- cr_reg = FLASH_F4_CR;
- cr_strt = 1 << FLASH_F4_CR_STRT;
- } else if (sl->flash_type == FLASH_TYPE_L4) {
- cr_reg = STM32L4_FLASH_CR;
- cr_strt = 1 << STM32L4_FLASH_CR_STRT;
- } else {
- cr_reg = FLASH_CR;
- cr_strt = 1 << FLASH_CR_STRT;
- }
-
- stlink_read_debug32(sl, cr_reg, &val);
- val |= cr_strt;
- stlink_write_debug32(sl, cr_reg, val);
-}
-
-static inline uint32_t read_flash_acr(stlink_t *sl) {
- uint32_t acr;
- stlink_read_debug32(sl, FLASH_ACR, &acr);
- return acr;
-}
-
-static inline uint32_t read_flash_sr(stlink_t *sl) {
- uint32_t res, sr_reg;
-
- if (sl->flash_type == FLASH_TYPE_F4)
- sr_reg = FLASH_F4_SR;
- else if (sl->flash_type == FLASH_TYPE_L4)
- sr_reg = STM32L4_FLASH_SR;
- else
- sr_reg = FLASH_SR;
-
- stlink_read_debug32(sl, sr_reg, &res);
-
- return res;
-}
-
-static inline unsigned int is_flash_busy(stlink_t *sl) {
- uint32_t sr_busy_shift;
-
- if (sl->flash_type == FLASH_TYPE_F4)
- sr_busy_shift = FLASH_F4_SR_BSY;
- else if (sl->flash_type == FLASH_TYPE_L4)
- sr_busy_shift = STM32L4_FLASH_SR_BSY;
- else
- sr_busy_shift = FLASH_SR_BSY;
-
- return read_flash_sr(sl) & (1 << sr_busy_shift);
-}
-
-static void wait_flash_busy(stlink_t *sl) {
- /* todo: add some delays here */
- while (is_flash_busy(sl))
- ;
-}
-
-static void wait_flash_busy_progress(stlink_t *sl) {
- int i = 0;
- fprintf(stdout, "Mass erasing");
- fflush(stdout);
- while (is_flash_busy(sl)) {
- usleep(10000);
- i++;
- if (i % 100 == 0) {
- fprintf(stdout, ".");
- fflush(stdout);
- }
- }
- fprintf(stdout, "\n");
-}
-
-static inline unsigned int is_flash_eop(stlink_t *sl) {
- return read_flash_sr(sl) & (1 << FLASH_SR_EOP);
-}
-
-static void __attribute__((unused)) clear_flash_sr_eop(stlink_t *sl) {
- const uint32_t n = read_flash_sr(sl) & ~(1 << FLASH_SR_EOP);
- stlink_write_debug32(sl, FLASH_SR, n);
-}
-
-static void __attribute__((unused)) wait_flash_eop(stlink_t *sl) {
- /* todo: add some delays here */
- while (is_flash_eop(sl) == 0)
- ;
-}
-
-static inline void write_flash_ar(stlink_t *sl, uint32_t n) {
- stlink_write_debug32(sl, FLASH_AR, n);
-}
-
-static inline void write_flash_cr_psiz(stlink_t *sl, uint32_t n) {
- uint32_t x = read_flash_cr(sl);
- x &= ~(0x03 << 8);
- x |= (n << 8);
-#if DEBUG_FLASH
- fprintf(stdout, "PSIZ:0x%x 0x%x\n", x, n);
-#endif
- stlink_write_debug32(sl, FLASH_F4_CR, x);
-}
-
-
-static inline void write_flash_cr_snb(stlink_t *sl, uint32_t n) {
- uint32_t x = read_flash_cr(sl);
- x &= ~FLASH_F4_CR_SNB_MASK;
- x |= (n << FLASH_F4_CR_SNB);
- x |= (1 << FLASH_F4_CR_SER);
-#if DEBUG_FLASH
- fprintf(stdout, "SNB:0x%x 0x%x\n", x, n);
-#endif
- stlink_write_debug32(sl, FLASH_F4_CR, x);
-}
-
-static inline void write_flash_cr_bker_pnb(stlink_t *sl, uint32_t n) {
- stlink_write_debug32(sl, STM32L4_FLASH_SR, 0xFFFFFFFF & ~(1<<STM32L4_FLASH_SR_BSY));
- uint32_t x = read_flash_cr(sl);
- x &=~ STM32L4_FLASH_CR_OPBITS;
- x &=~ STM32L4_FLASH_CR_PAGEMASK;
- x &= ~(1<<STM32L4_FLASH_CR_MER1);
- x &= ~(1<<STM32L4_FLASH_CR_MER2);
- x |= (n << STM32L4_FLASH_CR_PNB);
- x |= (1lu << STM32L4_FLASH_CR_PER);
-#if DEBUG_FLASH
- fprintf(stdout, "BKER:PNB:0x%x 0x%x\n", x, n);
-#endif
- stlink_write_debug32(sl, STM32L4_FLASH_CR, x);
-}
-
-// Delegates to the backends...
-
-void stlink_close(stlink_t *sl) {
- DLOG("*** stlink_close ***\n");
- if (!sl)
- return;
- sl->backend->close(sl);
- free(sl);
-}
-
-int stlink_exit_debug_mode(stlink_t *sl) {
- int ret;
-
- DLOG("*** stlink_exit_debug_mode ***\n");
- ret = stlink_write_debug32(sl, DHCSR, DBGKEY);
- if (ret == -1)
- return ret;
-
- return sl->backend->exit_debug_mode(sl);
-}
-
-int stlink_enter_swd_mode(stlink_t *sl) {
- DLOG("*** stlink_enter_swd_mode ***\n");
- return sl->backend->enter_swd_mode(sl);
-}
-
-// Force the core into the debug mode -> halted state.
-int stlink_force_debug(stlink_t *sl) {
- DLOG("*** stlink_force_debug_mode ***\n");
- return sl->backend->force_debug(sl);
-}
-
-int stlink_exit_dfu_mode(stlink_t *sl) {
- DLOG("*** stlink_exit_dfu_mode ***\n");
- return sl->backend->exit_dfu_mode(sl);
-}
-
-int stlink_core_id(stlink_t *sl) {
- int ret;
-
- DLOG("*** stlink_core_id ***\n");
- ret = sl->backend->core_id(sl);
- if (ret == -1) {
- ELOG("Failed to read core_id\n");
- return ret;
- }
- if (sl->verbose > 2)
- stlink_print_data(sl);
- DLOG("core_id = 0x%08x\n", sl->core_id);
- return ret;
-}
-
-int stlink_chip_id(stlink_t *sl, uint32_t *chip_id) {
- int ret;
-
- ret = stlink_read_debug32(sl, 0xE0042000, chip_id);
- if (ret == -1)
- return ret;
-
- if (*chip_id == 0)
- ret = stlink_read_debug32(sl, 0x40015800, chip_id); //Try Corex M0 DBGMCU_IDCODE register address
-
- return ret;
-}
-
-/**
- * Cortex m3 tech ref manual, CPUID register description
- * @param sl stlink context
- * @param cpuid pointer to the result object
- */
-int stlink_cpu_id(stlink_t *sl, cortex_m3_cpuid_t *cpuid) {
- uint32_t raw;
-
- if (stlink_read_debug32(sl, CM3_REG_CPUID, &raw))
- return -1;
-
- cpuid->implementer_id = (raw >> 24) & 0x7f;
- cpuid->variant = (raw >> 20) & 0xf;
- cpuid->part = (raw >> 4) & 0xfff;
- cpuid->revision = raw & 0xf;
- return 0;
-}
-
-/**
- * reads and decodes the flash parameters, as dynamically as possible
- * @param sl
- * @return 0 for success, or -1 for unsupported core type.
- */
-int stlink_load_device_params(stlink_t *sl) {
- ILOG("Loading device parameters....\n");
- const chip_params_t *params = NULL;
- stlink_core_id(sl);
- uint32_t chip_id;
- uint32_t flash_size;
-
- stlink_chip_id(sl, &chip_id);
- sl->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 (sl->chip_id == 0x411) {
- uint32_t cpuid;
- stlink_read_debug32(sl, 0xE000ED00, &cpuid);
- if ((cpuid & 0xfff0) == 0xc240)
- sl->chip_id = 0x413;
- }
-
- for (size_t i = 0; i < sizeof(devices) / sizeof(devices[0]); i++) {
- if(devices[i].chip_id == sl->chip_id) {
- params = &devices[i];
- break;
- }
- }
- if (params == NULL) {
- WLOG("unknown chip id! %#x\n", chip_id);
- return -1;
- }
-
- if (params->flash_type == FLASH_TYPE_UNKNOWN) {
- WLOG("Invalid flash type, please check device declaration\n");
- return -1;
- }
-
-
- // 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_MEDIUM || sl->chip_id == STM32_CHIPID_L1_MEDIUM_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_HIGH) {
- // 0 is 384k and 1 is 256k
- if ( flash_size == 0 ) {
- sl->flash_size = 384 * 1024;
- } else {
- sl->flash_size = 256 * 1024;
- }
- } else {
- sl->flash_size = flash_size * 1024;
- }
- sl->flash_type = params->flash_type;
- sl->flash_pgsz = params->flash_pagesize;
- sl->sram_size = params->sram_size;
- sl->sys_base = params->bootrom_base;
- sl->sys_size = params->bootrom_size;
-
- //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_MEDIUM_LOW && sl->flash_size < 64 * 1024){
- sl->sram_size = 0x1000;
- }
-
- ILOG("Device connected is: %s, id %#x\n", params->description, chip_id);
- // TODO make note of variable page size here.....
- ILOG("SRAM size: %#x bytes (%d KiB), Flash: %#x bytes (%d KiB) in pages of %zd bytes\n",
- sl->sram_size, sl->sram_size / 1024, sl->flash_size, sl->flash_size / 1024,
- sl->flash_pgsz);
- return 0;
-}
-
-int stlink_reset(stlink_t *sl) {
- DLOG("*** stlink_reset ***\n");
- return sl->backend->reset(sl);
-}
-
-int stlink_jtag_reset(stlink_t *sl, int value) {
- DLOG("*** stlink_jtag_reset ***\n");
- return sl->backend->jtag_reset(sl, value);
-}
-
-int stlink_run(stlink_t *sl) {
- DLOG("*** stlink_run ***\n");
- return sl->backend->run(sl);
-}
-
-int stlink_status(stlink_t *sl) {
- int ret;
-
- DLOG("*** stlink_status ***\n");
- ret = sl->backend->status(sl);
- stlink_core_stat(sl);
-
- return ret;
-}
-
-/**
- * Decode the version bits, originally from -sg, verified with usb
- * @param sl stlink context, assumed to contain valid data in the buffer
- * @param slv output parsed version object
- */
-void _parse_version(stlink_t *sl, stlink_version_t *slv) {
- 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;
- return;
-}
-
-int stlink_version(stlink_t *sl) {
- DLOG("*** looking up stlink version\n");
- if (sl->backend->version(sl))
- return -1;
-
- _parse_version(sl, &sl->version);
-
- DLOG("st vid = 0x%04x (expect 0x%04x)\n", sl->version.st_vid, USB_ST_VID);
- DLOG("stlink pid = 0x%04x\n", sl->version.stlink_pid);
- DLOG("stlink version = 0x%x\n", sl->version.stlink_v);
- DLOG("jtag version = 0x%x\n", sl->version.jtag_v);
- DLOG("swim version = 0x%x\n", sl->version.swim_v);
- if (sl->version.jtag_v == 0) {
- DLOG(" notice: the firmware doesn't support a jtag/swd interface\n");
- }
- if (sl->version.swim_v == 0) {
- DLOG(" notice: the firmware doesn't support a swim interface\n");
- }
-
- return 0;
-}
-
-int stlink_target_voltage(stlink_t *sl) {
- int voltage = -1;
- DLOG("*** reading target voltage\n");
- if (sl->backend->target_voltage != NULL) {
- voltage = sl->backend->target_voltage(sl);
- if (voltage != -1) {
- DLOG("target voltage = %ldmV\n", voltage);
- } else {
- DLOG("error reading target voltage\n");
- }
- } else {
- DLOG("reading voltage not supported by backend\n");
- }
- return voltage;
-}
-
-int stlink_read_debug32(stlink_t *sl, uint32_t addr, uint32_t *data) {
- int ret;
-
- ret = sl->backend->read_debug32(sl, addr, data);
- if (!ret)
- DLOG("*** stlink_read_debug32 %x is %#x\n", *data, addr);
-
- return ret;
-}
-
-int stlink_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data) {
- DLOG("*** stlink_write_debug32 %x to %#x\n", data, addr);
- return sl->backend->write_debug32(sl, addr, data);
-}
-
-int stlink_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
- DLOG("*** stlink_write_mem32 %u bytes to %#x\n", len, addr);
- if (len % 4 != 0) {
- fprintf(stderr, "Error: Data length doesn't have a 32 bit alignment: +%d byte.\n", len % 4);
- abort();
- }
- return sl->backend->write_mem32(sl, addr, len);
-}
-
-int stlink_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
- DLOG("*** stlink_read_mem32 ***\n");
- if (len % 4 != 0) { // !!! never ever: fw gives just wrong values
- fprintf(stderr, "Error: Data length doesn't have a 32 bit alignment: +%d byte.\n",
- len % 4);
- abort();
- }
- return sl->backend->read_mem32(sl, addr, len);
-}
-
-int stlink_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len) {
- DLOG("*** stlink_write_mem8 ***\n");
- if (len > 0x40 ) { // !!! never ever: Writing more then 0x40 bytes gives unexpected behaviour
- fprintf(stderr, "Error: Data length > 64: +%d byte.\n",
- len);
- abort();
- }
- return sl->backend->write_mem8(sl, addr, len);
-}
-
-int stlink_read_all_regs(stlink_t *sl, reg *regp) {
- DLOG("*** stlink_read_all_regs ***\n");
- return sl->backend->read_all_regs(sl, regp);
-}
-
-int stlink_read_all_unsupported_regs(stlink_t *sl, reg *regp) {
- DLOG("*** stlink_read_all_unsupported_regs ***\n");
- return sl->backend->read_all_unsupported_regs(sl, regp);
-}
-
-int stlink_write_reg(stlink_t *sl, uint32_t reg, int idx) {
- DLOG("*** stlink_write_reg\n");
- return sl->backend->write_reg(sl, reg, idx);
-}
-
-int stlink_read_reg(stlink_t *sl, int r_idx, reg *regp) {
- DLOG("*** stlink_read_reg\n");
- DLOG(" (%d) ***\n", r_idx);
-
- if (r_idx > 20 || r_idx < 0) {
- fprintf(stderr, "Error: register index must be in [0..20]\n");
- return -1;
- }
-
- return sl->backend->read_reg(sl, r_idx, regp);
-}
-
-int stlink_read_unsupported_reg(stlink_t *sl, int r_idx, reg *regp) {
- int r_convert;
-
- DLOG("*** stlink_read_unsupported_reg\n");
- DLOG(" (%d) ***\n", r_idx);
-
- /* Convert to values used by DCRSR */
- if (r_idx >= 0x1C && r_idx <= 0x1F) { /* primask, basepri, faultmask, or control */
- r_convert = 0x14;
- } else if (r_idx == 0x40) { /* FPSCR */
- r_convert = 0x21;
- } else if (r_idx >= 0x20 && r_idx < 0x40) {
- r_convert = 0x40 + (r_idx - 0x20);
- } else {
- fprintf(stderr, "Error: register address must be in [0x1C..0x40]\n");
- return -1;
- }
-
- return sl->backend->read_unsupported_reg(sl, r_convert, regp);
-}
-
-int stlink_write_unsupported_reg(stlink_t *sl, uint32_t val, int r_idx, reg *regp) {
- int r_convert;
-
- DLOG("*** stlink_write_unsupported_reg\n");
- DLOG(" (%d) ***\n", r_idx);
-
- /* Convert to values used by 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);
-}
-
-unsigned int is_core_halted(stlink_t *sl) {
- /* return non zero if core is halted */
- stlink_status(sl);
- return sl->q_buf[0] == STLINK_CORE_HALTED;
-}
-
-int stlink_step(stlink_t *sl) {
- DLOG("*** stlink_step ***\n");
- return sl->backend->step(sl);
-}
-
-int stlink_current_mode(stlink_t *sl) {
- int mode = sl->backend->current_mode(sl);
- switch (mode) {
- case STLINK_DEV_DFU_MODE:
- DLOG("stlink current mode: dfu\n");
- return mode;
- case STLINK_DEV_DEBUG_MODE:
- DLOG("stlink current mode: debug (jtag or swd)\n");
- return mode;
- case STLINK_DEV_MASS_MODE:
- DLOG("stlink current mode: mass\n");
- return mode;
- }
- DLOG("stlink mode: unknown!\n");
- return STLINK_DEV_UNKNOWN_MODE;
-}
-
-
-
-
-// End of delegates.... Common code below here...
-
-// Endianness
-// http://www.ibm.com/developerworks/aix/library/au-endianc/index.html
-// const int i = 1;
-// #define is_bigendian() ( (*(char*)&i) == 0 )
-
-inline unsigned int is_bigendian(void) {
- static volatile const unsigned int i = 1;
- return *(volatile const char*) &i == 0;
-}
-
-uint16_t read_uint16(const unsigned char *c, const int pt) {
- uint32_t ui;
- char *p = (char *) &ui;
-
- if (!is_bigendian()) { // le -> le (don't swap)
- p[0] = c[pt + 0];
- p[1] = c[pt + 1];
- } else {
- p[0] = c[pt + 1];
- p[1] = c[pt + 0];
- }
- return ui;
-}
-
-// same as above with entrypoint.
-
-void stlink_run_at(stlink_t *sl, stm32_addr_t addr) {
- stlink_write_reg(sl, addr, 15); /* pc register */
-
- stlink_run(sl);
-
- while (is_core_halted(sl) == 0)
- usleep(3000000);
-}
-
-void stlink_core_stat(stlink_t *sl) {
- if (sl->q_len <= 0)
- return;
-
- switch (sl->q_buf[0]) {
- case STLINK_CORE_RUNNING:
- sl->core_stat = STLINK_CORE_RUNNING;
- DLOG(" core status: running\n");
- return;
- case STLINK_CORE_HALTED:
- sl->core_stat = STLINK_CORE_HALTED;
- DLOG(" core status: halted\n");
- return;
- default:
- sl->core_stat = STLINK_CORE_STAT_UNKNOWN;
- fprintf(stderr, " core status: unknown\n");
- }
-}
-
-void stlink_print_data(stlink_t * sl) {
- if (sl->q_len <= 0 || sl->verbose < UDEBUG)
- return;
- if (sl->verbose > 2)
- fprintf(stdout, "data_len = %d 0x%x\n", sl->q_len, sl->q_len);
-
- for (int i = 0; i < sl->q_len; i++) {
- if (i % 16 == 0) {
- /*
- if (sl->q_data_dir == Q_DATA_OUT)
- fprintf(stdout, "\n<- 0x%08x ", sl->q_addr + i);
- else
- fprintf(stdout, "\n-> 0x%08x ", sl->q_addr + i);
- */
- }
- fprintf(stdout, " %02x", (unsigned int) sl->q_buf[i]);
- }
- fputs("\n\n", stdout);
-}
-
-/* memory mapped file */
-
-typedef struct mapped_file {
- uint8_t* base;
- size_t len;
-} mapped_file_t;
-
-#define MAPPED_FILE_INITIALIZER { NULL, 0 }
-
-static int map_file(mapped_file_t* mf, const char* path) {
- int error = -1;
- struct stat st;
-
- const int fd = open(path, O_RDONLY | O_BINARY);
- if (fd == -1) {
- fprintf(stderr, "open(%s) == -1\n", path);
- return -1;
- }
-
- if (fstat(fd, &st) == -1) {
- fprintf(stderr, "fstat() == -1\n");
- goto on_error;
- }
-
- mf->base = (uint8_t*) mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
- if (mf->base == MAP_FAILED) {
- fprintf(stderr, "mmap() == MAP_FAILED\n");
- goto on_error;
- }
-
- mf->len = st.st_size;
-
- /* success */
- error = 0;
-
-on_error:
- close(fd);
-
- return error;
-}
-
-static void unmap_file(mapped_file_t * mf) {
- munmap((void*) mf->base, mf->len);
- mf->base = (unsigned char*) MAP_FAILED;
- mf->len = 0;
-}
-
-/* Limit the block size to compare to 0x1800
- Anything larger will stall the STLINK2
- Maybe STLINK V1 needs smaller value!*/
-static int check_file(stlink_t* sl, mapped_file_t* mf, stm32_addr_t addr) {
- size_t off;
- size_t n_cmp = sl->flash_pgsz;
- if ( n_cmp > 0x1800)
- n_cmp = 0x1800;
-
- for (off = 0; off < mf->len; off += n_cmp) {
- size_t aligned_size;
-
- /* adjust last page size */
- size_t cmp_size = n_cmp;
- 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, aligned_size);
-
- if (memcmp(sl->q_buf, mf->base + off, cmp_size))
- return -1;
- }
-
- return 0;
-}
-
-int stlink_fwrite_sram
-(stlink_t * sl, const char* path, stm32_addr_t addr) {
- /* write the file in sram at addr */
-
- int error = -1;
- size_t off;
- size_t len;
- mapped_file_t mf = MAPPED_FILE_INITIALIZER;
- uint32_t val;
-
-
- if (map_file(&mf, path) == -1) {
- fprintf(stderr, "map_file() == -1\n");
- return -1;
- }
-
- /* check 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) {
- /* todo */
- fprintf(stderr, "unaligned addr\n");
- goto on_error;
- }
-
- len = mf.len;
-
- if(len & 3) {
- len -= len & 3;
- }
-
- /* do the copy by 1k blocks */
- for (off = 0; off < len; off += 1024) {
- size_t size = 1024;
- if ((off + size) > len)
- size = len - off;
-
- memcpy(sl->q_buf, mf.base + off, size);
-
- /* round size if needed */
- if (size & 3)
- size += 2;
-
- stlink_write_mem32(sl, addr + off, size);
- }
-
- if(mf.len > len) {
- memcpy(sl->q_buf, mf.base + len, mf.len - len);
- stlink_write_mem8(sl, addr + len, mf.len - len);
- }
-
- /* check the file ha been written */
- if (check_file(sl, &mf, addr) == -1) {
- fprintf(stderr, "check_file() == -1\n");
- goto on_error;
- }
-
- /* success */
- error = 0;
- /* set stack*/
- stlink_read_debug32(sl, addr, &val);
- stlink_write_reg(sl, val, 13);
- /* Set PC to the reset routine*/
- stlink_read_debug32(sl, addr + 4, &val);
- stlink_write_reg(sl, val, 15);
- stlink_run(sl);
-
-on_error:
- unmap_file(&mf);
- return error;
-}
-
-int stlink_fread(stlink_t* sl, const char* path, stm32_addr_t addr, size_t size) {
- /* read size bytes from addr to file */
-
- int error = -1;
- size_t off;
-
- const int fd = open(path, O_RDWR | O_TRUNC | O_CREAT, 00700);
- if (fd == -1) {
- fprintf(stderr, "open(%s) == -1\n", path);
- return -1;
- }
-
- if (size <1)
- size = sl->flash_size;
-
- if (size > sl->flash_size)
- size = sl->flash_size;
-
- size_t cmp_size = (sl->flash_pgsz > 0x1800)? 0x1800:sl->flash_pgsz;
- for (off = 0; off < size; off += cmp_size) {
- size_t aligned_size;
-
- /* adjust last page size */
- if ((off + cmp_size) > size)
- cmp_size = size - off;
-
- aligned_size = cmp_size;
- if (aligned_size & (4 - 1))
- aligned_size = (cmp_size + 4) & ~(4 - 1);
-
- stlink_read_mem32(sl, addr + off, aligned_size);
-
- if (write(fd, sl->q_buf, sl->q_len) != (ssize_t) aligned_size) {
- fprintf(stderr, "write() != aligned_size\n");
- goto on_error;
- }
- }
-
- /* success */
- error = 0;
-
-on_error:
- close(fd);
-
- return error;
-}
-
-int write_buffer_to_sram(stlink_t *sl, flash_loader_t* fl, const uint8_t* buf, size_t size) {
- /* write the buffer right after the loader */
- size_t chunk = size & ~0x3;
- size_t rem = size & 0x3;
- if (chunk) {
- memcpy(sl->q_buf, buf, chunk);
- stlink_write_mem32(sl, fl->buf_addr, chunk);
- }
- if (rem) {
- memcpy(sl->q_buf, buf+chunk, rem);
- stlink_write_mem8(sl, (fl->buf_addr)+chunk, rem);
- }
- return 0;
-}
-
-uint32_t calculate_F4_sectornum(uint32_t flashaddr){
- uint32_t offset = 0;
- flashaddr &= ~STM32_FLASH_BASE; //Page now holding the actual flash address
- if (flashaddr >= 0x100000) {
- offset = 12;
- flashaddr -= 0x100000;
- }
- if (flashaddr<0x4000) return (offset + 0);
- else if(flashaddr<0x8000) return(offset + 1);
- else if(flashaddr<0xc000) return(offset + 2);
- else if(flashaddr<0x10000) return(offset + 3);
- else if(flashaddr<0x20000) return(offset + 4);
- else return offset + (flashaddr/0x20000) +4;
-
-}
-
-uint32_t calculate_F7_sectornum(uint32_t flashaddr){
- flashaddr &= ~STM32_FLASH_BASE; //Page now holding the actual flash address
- if(flashaddr<0x20000) return(flashaddr/0x8000);
- else if(flashaddr<0x40000) return(4);
- else return(flashaddr/0x40000) +4;
-
-}
-
-// Returns BKER:PNB for the given page address
-uint32_t calculate_L4_page(stlink_t *sl, uint32_t flashaddr) {
- uint32_t bker = 0;
- uint32_t flashopt;
- stlink_read_debug32(sl, STM32L4_FLASH_OPTR, &flashopt);
- flashaddr -= STM32_FLASH_BASE;
- if (flashopt & (1lu << STM32L4_FLASH_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;
-}
-
-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_F411RE) ||
- (sl->chip_id == STM32_CHIPID_F446) || (sl->chip_id == STM32_CHIPID_F4_DSI)) {
- 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) {
- 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);
-}
-
-/**
- * Erase a page of flash, assumes sl is fully populated with things like chip/core ids
- * @param sl stlink context
- * @param flashaddr an address in the flash page to erase
- * @return 0 on success -ve on failure
- */
-int stlink_erase_flash_page(stlink_t *sl, stm32_addr_t flashaddr)
-{
- if (sl->flash_type == FLASH_TYPE_F4 || sl->flash_type == FLASH_TYPE_L4) {
- /* wait for ongoing op to finish */
- wait_flash_busy(sl);
-
- /* unlock if locked */
- unlock_flash_if(sl);
-
- /* select the page to erase */
- if (sl->chip_id == STM32_CHIPID_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) {
- // 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);
- } 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);
- }
-
- /* start erase operation */
- set_flash_cr_strt(sl);
-
- /* wait for completion */
- wait_flash_busy(sl);
-
- /* relock the flash */
- //todo: fails to program if this is in
- lock_flash(sl);
-#if DEBUG_FLASH
- fprintf(stdout, "Erase Final CR:0x%x\n", read_flash_cr(sl));
-#endif
- } else if (sl->flash_type == FLASH_TYPE_L0) {
-
- uint32_t val;
- uint32_t flash_regs_base;
- if (sl->chip_id == STM32_CHIPID_L0) {
- flash_regs_base = STM32L0_FLASH_REGS_ADDR;
- } else {
- flash_regs_base = STM32L_FLASH_REGS_ADDR;
- }
-
- /* 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, 0x89abcdef);
- stlink_write_debug32(sl, flash_regs_base + FLASH_PEKEYR_OFF, 0x02030405);
-
- /* 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, 0x8c9daebf);
- stlink_write_debug32(sl, flash_regs_base + FLASH_PRGKEYR_OFF, 0x13141516);
-
- /* 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);
-#if 0 /* fix_to_be_confirmed */
-
- /* wait for sr.busy to be cleared
- * MP: Test shows that busy bit is not set here. Perhaps, PM0062 is
- * wrong and we do not need to wait here for clearing the busy bit.
- * TEXANE: ok, if experience says so and it works for you, we comment
- * it. If someone has a problem, please drop an email.
- */
- do {
- stlink_read_debug32(sl, STM32L_FLASH_SR, &val)
- } while((val & (1 << 0)) != 0);
-
-#endif /* fix_to_be_confirmed */
-
- /* 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.*/
- do {
- stlink_read_debug32(sl, flash_regs_base + FLASH_SR_OFF, &val);
- } while ((val & (1 << 0)) != 0);
-
- /* 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 == FLASH_TYPE_F0) {
- /* wait for ongoing op to finish */
- wait_flash_busy(sl);
-
- /* unlock if locked */
- unlock_flash_if(sl);
-
- /* set the page erase bit */
- set_flash_cr_per(sl);
-
- /* select the page to erase */
- write_flash_ar(sl, flashaddr);
-
- /* start erase operation, reset by hw with bsy bit */
- set_flash_cr_strt(sl);
-
- /* wait for completion */
- wait_flash_busy(sl);
-
- /* relock the flash */
- lock_flash(sl);
- } else {
- WLOG("unknown coreid %x, page erase failed\n", sl->core_id);
- return -1;
- }
-
- /* todo: verify the erased page */
-
- return 0;
-}
-
-int stlink_erase_flash_mass(stlink_t *sl) {
- if (sl->flash_type == FLASH_TYPE_L0) {
- /* erase each page */
- int i = 0, num_pages = sl->flash_size/sl->flash_pgsz;
- for (i = 0; i < num_pages; i++) {
- /* addr must be an addr inside the page */
- stm32_addr_t addr = sl->flash_base + i * sl->flash_pgsz;
- if (stlink_erase_flash_page(sl, addr) == -1) {
- WLOG("Failed to erase_flash_page(%#zx) == -1\n", addr);
- return -1;
- }
- fprintf(stdout,"-> Flash page at %5d/%5d erased\n", i, num_pages);
- fflush(stdout);
- }
- fprintf(stdout, "\n");
- } else {
- /* wait for ongoing op to finish */
- wait_flash_busy(sl);
-
- /* unlock if locked */
- unlock_flash_if(sl);
-
- /* set the mass erase bit */
- set_flash_cr_mer(sl);
-
- /* start erase operation, reset by hw with bsy bit */
- set_flash_cr_strt(sl);
-
- /* wait for completion */
- wait_flash_busy_progress(sl);
-
- /* relock the flash */
- lock_flash(sl);
-
- /* todo: verify the erased memory */
- }
- return 0;
-}
-
-int init_flash_loader(stlink_t *sl, flash_loader_t* fl) {
- size_t size;
-
- /* allocate the loader in sram */
- if (write_loader_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");
- return 0;
-}
-
-int write_loader_to_sram(stlink_t *sl, stm32_addr_t* addr, size_t* size) {
- /* from openocd, contrib/loaders/flash/stm32.s */
- static const uint8_t loader_code_stm32vl[] = {
- 0x08, 0x4c, /* ldr r4, STM32_FLASH_BASE */
- 0x1c, 0x44, /* add r4, r3 */
- /* write_half_word: */
- 0x01, 0x23, /* movs r3, #0x01 */
- 0x23, 0x61, /* str r3, [r4, #STM32_FLASH_CR_OFFSET] */
- 0x30, 0xf8, 0x02, 0x3b, /* ldrh r3, [r0], #0x02 */
- 0x21, 0xf8, 0x02, 0x3b, /* strh r3, [r1], #0x02 */
- /* busy: */
- 0xe3, 0x68, /* ldr r3, [r4, #STM32_FLASH_SR_OFFSET] */
- 0x13, 0xf0, 0x01, 0x0f, /* tst r3, #0x01 */
- 0xfb, 0xd0, /* beq busy */
- 0x13, 0xf0, 0x14, 0x0f, /* tst r3, #0x14 */
- 0x01, 0xd1, /* bne exit */
- 0x01, 0x3a, /* subs r2, r2, #0x01 */
- 0xf0, 0xd1, /* bne write_half_word */
- /* exit: */
- 0x00, 0xbe, /* bkpt #0x00 */
- 0x00, 0x20, 0x02, 0x40, /* STM32_FLASH_BASE: .word 0x40022000 */
- };
-
- /* flashloaders/stm32f0.s -- thumb1 only, same sequence as for STM32VL, bank ignored */
- static const uint8_t loader_code_stm32f0[] = {
-#if 1
- /*
- * 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.
- */
- 0x00, 0x30, // nop /* add r0,#0 */
- 0x00, 0x30, // nop /* add r0,#0 */
-#endif
- 0x0A, 0x4C, // ldr r4, STM32_FLASH_BASE
- 0x01, 0x25, // mov r5, #1 /* FLASH_CR_PG, FLASH_SR_BUSY */
- 0x04, 0x26, // mov r6, #4 /* PGERR */
- // write_half_word:
- 0x23, 0x69, // ldr r3, [r4, #16] /* FLASH->CR */
- 0x2B, 0x43, // orr r3, r5
- 0x23, 0x61, // str r3, [r4, #16] /* FLASH->CR |= FLASH_CR_PG */
- 0x03, 0x88, // ldrh r3, [r0] /* r3 = *sram */
- 0x0B, 0x80, // strh r3, [r1] /* *flash = r3 */
- // busy:
- 0xE3, 0x68, // ldr r3, [r4, #12] /* FLASH->SR */
- 0x2B, 0x42, // tst r3, r5 /* FLASH_SR_BUSY */
- 0xFC, 0xD0, // beq busy
-
- 0x33, 0x42, // tst r3, r6 /* PGERR */
- 0x04, 0xD1, // bne exit
-
- 0x02, 0x30, // add r0, r0, #2 /* sram += 2 */
- 0x02, 0x31, // add r1, r1, #2 /* flash += 2 */
- 0x01, 0x3A, // sub r2, r2, #0x01 /* count-- */
- 0x00, 0x2A, // cmp r2, #0
- 0xF0, 0xD1, // bne write_half_word
- // exit:
- 0x23, 0x69, // ldr r3, [r4, #16] /* FLASH->CR */
- 0xAB, 0x43, // bic r3, r5
- 0x23, 0x61, // str r3, [r4, #16] /* FLASH->CR &= ~FLASH_CR_PG */
- 0x00, 0xBE, // bkpt #0x00
- 0x00, 0x20, 0x02, 0x40, /* STM32_FLASH_BASE: .word 0x40022000 */
- };
-
- static const uint8_t loader_code_stm32l[] = {
-
- /* openocd.git/contrib/loaders/flash/stm32lx.S
- r0, input, source addr
- r1, input, dest addr
- r2, input, word count
- r2, output, remaining word count
- */
-
- 0x04, 0xe0,
-
- 0x50, 0xf8, 0x04, 0xcb,
- 0x41, 0xf8, 0x04, 0xcb,
- 0x01, 0x3a,
-
- 0x00, 0x2a,
- 0xf8, 0xd3,
- 0x00, 0xbe
- };
-
- static const uint8_t loader_code_stm32l0[] = {
-
- /*
- r0, input, source addr
- r1, input, dest addr
- r2, input, word count
- r2, output, remaining word count
- */
-
- 0x04, 0xe0,
-
- 0x04, 0x68,
- 0x0c, 0x60,
- 0x01, 0x3a,
- 0x04, 0x31,
- 0x04, 0x30,
-
- 0x00, 0x2a,
- 0xf8, 0xd3,
- 0x00, 0xbe
- };
-
- static const uint8_t loader_code_stm32f4[] = {
- // flashloaders/stm32f4.s
-
- 0x07, 0x4b,
-
- 0x62, 0xb1,
- 0x04, 0x68,
- 0x0c, 0x60,
-
- 0xdc, 0x89,
- 0x14, 0xf0, 0x01, 0x0f,
- 0xfb, 0xd1,
- 0x00, 0xf1, 0x04, 0x00,
- 0x01, 0xf1, 0x04, 0x01,
- 0xa2, 0xf1, 0x01, 0x02,
- 0xf1, 0xe7,
-
- 0x00, 0xbe,
-
- 0x00, 0x3c, 0x02, 0x40,
- };
-
- static const uint8_t loader_code_stm32f4_lv[] = {
- // flashloaders/stm32f4lv.s
- 0x92, 0x00,
-
- 0x08, 0x4b,
- 0x62, 0xb1,
- 0x04, 0x78,
- 0x0c, 0x70,
-
- 0xdc, 0x89,
- 0x14, 0xf0, 0x01, 0x0f,
- 0xfb, 0xd1,
- 0x00, 0xf1, 0x01, 0x00,
- 0x01, 0xf1, 0x01, 0x01,
- 0xa2, 0xf1, 0x01, 0x02,
- 0xf1, 0xe7,
-
- 0x00, 0xbe,
- 0x00, 0xbf,
-
- 0x00, 0x3c, 0x02, 0x40,
- };
-
- static const uint8_t loader_code_stm32l4[] = {
- // flashloaders/stm32l4.s
- 0x08, 0x4b, // start: ldr r3, [pc, #32] ; <flash_base>
- 0x72, 0xb1, // next: cbz r2, <done>
- 0x04, 0x68, // ldr r4, [r0, #0]
- 0x45, 0x68, // ldr r5, [r0, #4]
- 0x0c, 0x60, // str r4, [r1, #0]
- 0x4d, 0x60, // str r5, [r1, #4]
- 0x5c, 0x8a, // wait: ldrh r4, [r3, #18]
- 0x14, 0xf0, 0x01, 0x0f, // tst.w r4, #1
- 0xfb, 0xd1, // bne.n <wait>
- 0x00, 0xf1, 0x08, 0x00, // add.w r0, r0, #8
- 0x01, 0xf1, 0x08, 0x01, // add.w r1, r1, #8
- 0xa2, 0xf1, 0x01, 0x02, // sub.w r2, r2, #1
- 0xef, 0xe7, // b.n <next>
- 0x00, 0xbe, // done: bkpt 0x0000
- 0x00, 0x20, 0x02, 0x40 // flash_base: .word 0x40022000
- };
-
- static const uint8_t loader_code_stm32f7[] = {
- 0x08, 0x4b,
- 0x72, 0xb1,
- 0x04, 0x68,
- 0x0c, 0x60,
- 0xbf, 0xf3, 0x4f, 0x8f, // DSB Memory barrier for in order flash write
- 0xdc, 0x89,
- 0x14, 0xf0, 0x01, 0x0f,
- 0xfb, 0xd1,
- 0x00, 0xf1, 0x04, 0x00,
- 0x01, 0xf1, 0x04, 0x01,
- 0xa2, 0xf1, 0x01, 0x02,
- 0xef, 0xe7,
- 0x00, 0xbe, // bkpt #0x00
- 0x00, 0x3c, 0x02, 0x40,
- };
-
- const uint8_t* loader_code;
- size_t loader_size;
-
- if (sl->chip_id == STM32_CHIPID_L1_MEDIUM || sl->chip_id == STM32_CHIPID_L1_CAT2
- || sl->chip_id == STM32_CHIPID_L1_MEDIUM_PLUS || sl->chip_id == STM32_CHIPID_L1_HIGH
- || sl->chip_id == STM32_CHIPID_L152_RE) { /* stm32l */
- loader_code = loader_code_stm32l;
- loader_size = sizeof(loader_code_stm32l);
- } else if (sl->core_id == STM32VL_CORE_ID
- || sl->chip_id == STM32_CHIPID_F3
- || sl->chip_id == STM32_CHIPID_F3_SMALL
- || sl->chip_id == STM32_CHIPID_F303_HIGH
- || 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_F411RE) ||
- (sl->chip_id == STM32_CHIPID_F446) || (sl->chip_id == STM32_CHIPID_F4_DSI)){
- int voltage = stlink_target_voltage(sl);
- if (voltage == -1) {
- printf("Failed to read Target voltage\n");
- return voltage;
- } else if (voltage > 2700) {
- loader_code = loader_code_stm32f4;
- loader_size = sizeof(loader_code_stm32f4);
- } else {
- loader_code = loader_code_stm32f4_lv;
- loader_size = sizeof(loader_code_stm32f4_lv);
- }
- } else if (sl->chip_id == STM32_CHIPID_F7){
- loader_code = loader_code_stm32f7;
- loader_size = sizeof(loader_code_stm32f7);
- } 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_F0_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_L0) {
- loader_code = loader_code_stm32l0;
- loader_size = sizeof(loader_code_stm32l0);
- } else if (sl->chip_id == STM32_CHIPID_L4) {
- loader_code = loader_code_stm32l4;
- loader_size = sizeof(loader_code_stm32l4);
- } else {
- ELOG("unknown coreid, not sure what flash loader to use, aborting!: %x\n", sl->core_id);
- return -1;
- }
-
- memcpy(sl->q_buf, loader_code, loader_size);
- stlink_write_mem32(sl, sl->sram_base, loader_size);
-
- *addr = sl->sram_base;
- *size = loader_size;
-
- /* success */
- return 0;
-}
-
-int stlink_fcheck_flash(stlink_t *sl, const char* path, stm32_addr_t addr) {
- /* check the contents of path are at addr */
-
- int res;
- mapped_file_t mf = MAPPED_FILE_INITIALIZER;
-
- if (map_file(&mf, path) == -1)
- return -1;
-
- res = check_file(sl, &mf, addr);
-
- unmap_file(&mf);
-
- return res;
-}
-
-/**
- * Verify addr..addr+len is binary identical to base...base+len
- * @param sl stlink context
- * @param address stm device address
- * @param data host side buffer to check against
- * @param length how much
- * @return 0 for success, -ve for failure
- */
-int stlink_verify_write_flash(stlink_t *sl, stm32_addr_t address, uint8_t *data, unsigned length) {
- size_t off;
- size_t cmp_size = (sl->flash_pgsz > 0x1800)? 0x1800:sl->flash_pgsz;
- ILOG("Starting verification of write complete\n");
- for (off = 0; off < length; off += cmp_size) {
- size_t aligned_size;
-
- /* adjust last page size */
- if ((off + cmp_size) > length)
- cmp_size = length - off;
-
- aligned_size = cmp_size;
- if (aligned_size & (4 - 1))
- aligned_size = (cmp_size + 4) & ~(4 - 1);
-
- stlink_read_mem32(sl, address + off, aligned_size);
-
- if (memcmp(sl->q_buf, data + off, cmp_size)) {
- ELOG("Verification of flash failed at offset: %zd\n", off);
- return -1;
- }
- }
- ILOG("Flash written and verified! jolly good!\n");
- return 0;
-
-}
-
-int stm32l1_write_half_pages(stlink_t *sl, stm32_addr_t addr, uint8_t* base, uint32_t len, uint32_t pagesize)
-{
- unsigned int count;
- unsigned int num_half_pages = len / pagesize;
- uint32_t val;
- uint32_t flash_regs_base;
- flash_loader_t fl;
-
- if (sl->chip_id == STM32_CHIPID_L0) {
- flash_regs_base = STM32L0_FLASH_REGS_ADDR;
- } else {
- flash_regs_base = STM32L_FLASH_REGS_ADDR;
- }
-
- ILOG("Starting Half page flash write for STM32L core id\n");
- /* flash loader initialization */
- if (init_flash_loader(sl, &fl) == -1) {
- WLOG("init_flash_loader() == -1\n");
- return -1;
- }
- /* Unlock already done */
- stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
- val |= (1 << FLASH_L1_FPRG);
- stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val);
-
- val |= (1 << FLASH_L1_PROG);
- stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val);
- do {
- stlink_read_debug32(sl, flash_regs_base + FLASH_SR_OFF, &val);
- } while ((val & (1 << 0)) != 0);
-
- for (count = 0; count < num_half_pages; count ++) {
- if (run_flash_loader(sl, &fl, addr + count * pagesize, base + count * pagesize, pagesize) == -1) {
- WLOG("l1_run_flash_loader(%#zx) failed! == -1\n", addr + count * pagesize);
- stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
- val &= ~((1 << FLASH_L1_FPRG) |(1 << FLASH_L1_PROG));
- stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val);
- return -1;
- }
- /* wait for sr.busy to be cleared */
- if (sl->verbose >= 1) {
- /* show progress. writing procedure is slow
- and previous errors are misleading */
- fprintf(stdout, "\r%3u/%u halfpages written", count + 1, num_half_pages);
- fflush(stdout);
- }
- do {
- stlink_read_debug32(sl, flash_regs_base + FLASH_SR_OFF, &val);
- } while ((val & (1 << 0)) != 0);
- }
- stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
- val &= ~(1 << FLASH_L1_PROG);
- stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val);
- stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
- val &= ~(1 << FLASH_L1_FPRG);
- stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val);
-
- return 0;
-}
-
-int stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t* base, uint32_t len, uint8_t eraseonly) {
- size_t off;
- flash_loader_t fl;
- ILOG("Attempting to write %d (%#x) bytes to stm32 address: %u (%#x)\n",
- len, len, addr, addr);
- /* check addr range is inside the flash */
- stlink_calculate_pagesize(sl, addr);
- if (addr < sl->flash_base) {
- ELOG("addr too low %#x < %#x\n", addr, sl->flash_base);
- return -1;
- } else if ((addr + len) < addr) {
- ELOG("addr overruns\n");
- return -1;
- } else if ((addr + len) > (sl->flash_base + sl->flash_size)) {
- ELOG("addr too high\n");
- return -1;
- } else if (addr & 1) {
- ELOG("unaligned addr 0x%x\n", addr);
- return -1;
- } else if (len & 1) {
- WLOG("unaligned len 0x%x -- padding with zero\n", len);
- len += 1;
- } else if (addr & (sl->flash_pgsz - 1)) {
- ELOG("addr not a multiple of pagesize, not supported\n");
- return -1;
- }
-
- // Make sure we've loaded the context with the chip details
- stlink_core_id(sl);
- /* erase each page */
- int page_count = 0;
- for (off = 0; off < len; off += stlink_calculate_pagesize(sl, addr + off)) {
- /* addr must be an addr inside the page */
- if (stlink_erase_flash_page(sl, addr + off) == -1) {
- ELOG("Failed to erase_flash_page(%#zx) == -1\n", addr + off);
- return -1;
- }
- fprintf(stdout,"\rFlash page at addr: 0x%08lx erased",
- (unsigned long)addr + off);
- fflush(stdout);
- page_count++;
- }
- fprintf(stdout,"\n");
- ILOG("Finished erasing %d pages of %d (%#x) bytes\n",
- page_count, sl->flash_pgsz, sl->flash_pgsz);
-
- if (eraseonly)
- return 0;
-
- if ((sl->flash_type == FLASH_TYPE_F4) || (sl->flash_type == FLASH_TYPE_L4)) {
- /* todo: check write operation */
-
- ILOG("Starting Flash write for F2/F4/L4\n");
- /* flash loader initialization */
- if (init_flash_loader(sl, &fl) == -1) {
- ELOG("init_flash_loader() == -1\n");
- return -1;
- }
-
- /* First unlock the cr */
- unlock_flash_if(sl);
-
- /* TODO: Check that Voltage range is 2.7 - 3.6 V */
- if (sl->chip_id != STM32_CHIPID_L4) {
- /* set parallelisim to 32 bit*/
- int voltage = stlink_target_voltage(sl);
- if (voltage == -1) {
- printf("Failed to read Target voltage\n");
- return voltage;
- } else if (voltage > 2700) {
- printf("enabling 32-bit flash writes\n");
- write_flash_cr_psiz(sl, 2);
- } else {
- printf("Target voltage (%d mV) too low for 32-bit flash, using 8-bit flash writes\n", voltage);
- write_flash_cr_psiz(sl, 0);
- }
- } else {
- /* L4 does not have a byte-write mode */
- int voltage = stlink_target_voltage(sl);
- if (voltage == -1) {
- printf("Failed to read Target voltage\n");
- return voltage;
- } else if (voltage < 1710) {
- printf("Target voltage (%d mV) too low for flash writes!\n", voltage);
- return -1;
- }
- }
-
- /* set programming mode */
- set_flash_cr_pg(sl);
-
- for(off = 0; off < len;) {
- size_t size = len - off > 0x8000 ? 0x8000 : len - off;
-
- printf("size: %zu\n", size);
-
- if (run_flash_loader(sl, &fl, addr + off, base + off, size) == -1) {
- ELOG("run_flash_loader(%#zx) failed! == -1\n", addr + off);
- return -1;
- }
-
- off += size;
- }
-
- /* Relock flash */
- lock_flash(sl);
-
- } //STM32F4END
-
- else if (sl->flash_type == FLASH_TYPE_L0) {
- /* use fast word write. todo: half page. */
- uint32_t val;
- uint32_t flash_regs_base;
- uint32_t pagesize;
-
- if (sl->chip_id == STM32_CHIPID_L0) {
- flash_regs_base = STM32L0_FLASH_REGS_ADDR;
- pagesize = L0_WRITE_BLOCK_SIZE;
- } else {
- flash_regs_base = STM32L_FLASH_REGS_ADDR;
- pagesize = L1_WRITE_BLOCK_SIZE;
- }
-
- /* todo: check write operation */
-
- /* disable pecr protection */
- stlink_write_debug32(sl, flash_regs_base + FLASH_PEKEYR_OFF, 0x89abcdef);
- stlink_write_debug32(sl, flash_regs_base + FLASH_PEKEYR_OFF, 0x02030405);
-
- /* check pecr.pelock is cleared */
- stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
- if (val & (1 << 0)) {
- fprintf(stderr, "pecr.pelock not clear\n");
- return -1;
- }
-
- /* unlock program memory */
- stlink_write_debug32(sl, flash_regs_base + FLASH_PRGKEYR_OFF, 0x8c9daebf);
- stlink_write_debug32(sl, flash_regs_base + FLASH_PRGKEYR_OFF, 0x13141516);
-
- /* check pecr.prglock is cleared */
- stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val);
- if (val & (1 << 1)) {
- fprintf(stderr, "pecr.prglock not clear\n");
- return -1;
- }
- off = 0;
- if (len > pagesize) {
- if (stm32l1_write_half_pages(sl, addr, base, len, pagesize) == -1) {
- /* This may happen on a blank device! */
- WLOG("\nwrite_half_pages failed == -1\n");
- } else {
- off = (len / pagesize)*pagesize;
- }
- }
-
- /* write remainingword in program memory */
- for ( ; off < len; off += sizeof(uint32_t)) {
- uint32_t data;
- if (off > 254)
- fprintf(stdout, "\r");
-
- if ((off % sl->flash_pgsz) > (sl->flash_pgsz -5)) {
- fprintf(stdout, "\r%3zd/%3zd pages written",
- off/sl->flash_pgsz, 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");
- /* 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 == FLASH_TYPE_F0) {
- ILOG("Starting Flash write for VL/F0/F3 core id\n");
- /* flash loader initialization */
- if (init_flash_loader(sl, &fl) == -1) {
- ELOG("init_flash_loader() == -1\n");
- return -1;
- }
-
- int write_block_count = 0;
- for (off = 0; off < len; off += sl->flash_pgsz) {
- /* adjust last write size */
- size_t size = sl->flash_pgsz;
- if ((off + sl->flash_pgsz) > len) size = len - off;
-
- /* unlock and set programming mode */
- unlock_flash_if(sl);
- set_flash_cr_pg(sl);
- //DLOG("Finished setting flash cr pg, running loader!\n");
- if (run_flash_loader(sl, &fl, addr + off, base + off, size) == -1) {
- ELOG("run_flash_loader(%#zx) failed! == -1\n", addr + off);
- return -1;
- }
- lock_flash(sl);
- if (sl->verbose >= 1) {
- /* show progress. writing procedure is slow
- and previous errors are misleading */
- fprintf(stdout, "\r%3u/%lu pages written", write_block_count++, (unsigned long)len/sl->flash_pgsz);
- fflush(stdout);
- }
- }
- fprintf(stdout, "\n");
- } else {
- ELOG("unknown coreid, not sure how to write: %x\n", sl->core_id);
- return -1;
- }
-
- return stlink_verify_write_flash(sl, addr, base, len);
-}
-
-/**
- * Write the given binary file into flash at address "addr"
- * @param sl
- * @param path readable file path, should be binary image
- * @param addr where to start writing
- * @return 0 on success, -ve on failure.
- */
-int stlink_fwrite_flash(stlink_t *sl, const char* path, stm32_addr_t addr) {
- /* write the file in flash at addr */
- int err;
- unsigned int num_empty, index, val;
- unsigned char erased_pattern;
- mapped_file_t mf = MAPPED_FILE_INITIALIZER;
-
- if (map_file(&mf, path) == -1) {
- ELOG("map_file() == -1\n");
- return -1;
- }
-
- if (sl->flash_type == FLASH_TYPE_L0)
- erased_pattern = 0x00;
- else
- erased_pattern = 0xff;
-
- index = mf.len;
- for(num_empty = 0; num_empty != mf.len; ++num_empty) {
- if (mf.base[--index] != erased_pattern) {
- break;
- }
- }
- /* Round down to words */
- num_empty -= (num_empty & 3);
- if(num_empty != 0) {
- ILOG("Ignoring %d bytes of 0x%02x at end of file\n", num_empty, erased_pattern);
- }
- err = stlink_write_flash(sl, addr, mf.base, num_empty == mf.len? mf.len : mf.len - num_empty, num_empty == mf.len);
- /* set stack*/
- stlink_read_debug32(sl, addr, &val);
- stlink_write_reg(sl, val, 13);
- /* Set PC to the reset routine*/
- stlink_read_debug32(sl, addr + 4, &val);
- stlink_write_reg(sl, val, 15);
- stlink_run(sl);
- unmap_file(&mf);
- return err;
-}
-
-int run_flash_loader(stlink_t *sl, flash_loader_t* fl, stm32_addr_t target, const uint8_t* buf, size_t size) {
-
- reg rr;
- int i = 0;
- size_t count = 0;
-
- DLOG("Running flash loader, write address:%#x, size: %zd\n", target, size);
- // FIXME This can never return -1
- if (write_buffer_to_sram(sl, fl, buf, size) == -1) {
- // IMPOSSIBLE!
- ELOG("write_buffer_to_sram() == -1\n");
- return -1;
- }
-
- if (sl->flash_type == FLASH_TYPE_F0) {
- count = size / sizeof(uint16_t);
- if (size % sizeof(uint16_t))
- ++count;
- } else if (sl->flash_type == FLASH_TYPE_F4 || sl->flash_type == FLASH_TYPE_L0) {
- count = size / sizeof(uint32_t);
- if (size % sizeof(uint32_t))
- ++count;
- } else if (sl->flash_type == FLASH_TYPE_L4) {
- count = size / sizeof(uint64_t);
- if (size % sizeof(uint64_t))
- ++count;
- }
-
- /* setup core */
- stlink_write_reg(sl, fl->buf_addr, 0); /* source */
- stlink_write_reg(sl, target, 1); /* target */
- stlink_write_reg(sl, count, 2); /* count */
- stlink_write_reg(sl, 0, 3); /* flash bank 0 (input), only used on F0, but armless fopr others */
- stlink_write_reg(sl, fl->loader_addr, 15); /* pc register */
-
- /* run loader */
- stlink_run(sl);
-
-#define WAIT_ROUNDS 10000
- /* wait until done (reaches breakpoint) */
- for (i = 0; i < WAIT_ROUNDS; i++) {
- usleep(10);
- if (is_core_halted(sl))
- break;
- }
-
- if (i >= WAIT_ROUNDS) {
- ELOG("flash loader run error\n");
- return -1;
- }
-
- /* check written byte count */
- stlink_read_reg(sl, 2, &rr);
- if (rr.r[2] != 0) {
- fprintf(stderr, "write error, count == %u\n", rr.r[2]);
- return -1;
- }
-
- return 0;
-}
+++ /dev/null
-/*
- * File: stlink-common.h
- * Bulk import from stlink-hw.h
- *
- * This should contain all the common top level stlink interfaces, regardless
- * of how the backend does the work....
- */
-
-#ifndef STLINK_COMMON_H
-#define STLINK_COMMON_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <stdint.h>
-
- // Max data transfer size.
- // 6kB = max mem32_read block, 8kB sram
- //#define Q_BUF_LEN 96
-#define Q_BUF_LEN (1024 * 100)
-
- // st-link vendor cmd's
-#define USB_ST_VID 0x0483
-#define USB_STLINK_PID 0x3744
-#define USB_STLINK_32L_PID 0x3748
-#define USB_STLINK_NUCLEO_PID 0x374b
-
- // STLINK_DEBUG_RESETSYS, etc:
-#define STLINK_OK 0x80
-#define STLINK_FALSE 0x81
-#define STLINK_CORE_RUNNING 0x80
-#define STLINK_CORE_HALTED 0x81
-#define STLINK_CORE_STAT_UNKNOWN -1
-
-#define STLINK_GET_VERSION 0xf1
-#define STLINK_GET_CURRENT_MODE 0xf5
-#define STLINK_GET_TARGET_VOLTAGE 0xF7
-
-#define STLINK_DEBUG_COMMAND 0xF2
-#define STLINK_DFU_COMMAND 0xF3
-#define STLINK_DFU_EXIT 0x07
- // enter dfu could be 0x08?
-
- // STLINK_GET_CURRENT_MODE
-#define STLINK_DEV_DFU_MODE 0x00
-#define STLINK_DEV_MASS_MODE 0x01
-#define STLINK_DEV_DEBUG_MODE 0x02
-#define STLINK_DEV_UNKNOWN_MODE -1
-
- // jtag mode cmds
-#define STLINK_DEBUG_ENTER 0x20
-#define STLINK_DEBUG_EXIT 0x21
-#define STLINK_DEBUG_READCOREID 0x22
-#define STLINK_DEBUG_GETSTATUS 0x01
-#define STLINK_DEBUG_FORCEDEBUG 0x02
-#define STLINK_DEBUG_RESETSYS 0x03
-#define STLINK_DEBUG_READALLREGS 0x04
-#define STLINK_DEBUG_READREG 0x05
-#define STLINK_DEBUG_WRITEREG 0x06
-#define STLINK_DEBUG_READMEM_32BIT 0x07
-#define STLINK_DEBUG_WRITEMEM_32BIT 0x08
-#define STLINK_DEBUG_RUNCORE 0x09
-#define STLINK_DEBUG_STEPCORE 0x0a
-#define STLINK_DEBUG_SETFP 0x0b
-#define STLINK_DEBUG_WRITEMEM_8BIT 0x0d
-#define STLINK_DEBUG_CLEARFP 0x0e
-#define STLINK_DEBUG_WRITEDEBUGREG 0x0f
-#define STLINK_DEBUG_ENTER_SWD 0xa3
-#define STLINK_DEBUG_ENTER_JTAG 0x00
-
- // TODO - possible poor names...
-#define STLINK_SWD_ENTER 0x30
-#define STLINK_SWD_READCOREID 0x32 // TBD
-#define STLINK_JTAG_WRITEDEBUG_32BIT 0x35
-#define STLINK_JTAG_READDEBUG_32BIT 0x36
-#define STLINK_JTAG_DRIVE_NRST 0x3c
-#define STLINK_JTAG_DRIVE_NRST 0x3c
-
- // cortex m3 technical reference manual
-#define CM3_REG_CPUID 0xE000ED00
-#define CM3_REG_FP_CTRL 0xE0002000
-#define CM3_REG_FP_COMP0 0xE0002008
-
- /* cortex core ids */
- // TODO clean this up...
-#define STM32VL_CORE_ID 0x1ba01477
-#define STM32L_CORE_ID 0x2ba01477
-#define STM32F3_CORE_ID 0x2ba01477
-#define STM32F4_CORE_ID 0x2ba01477
-#define STM32F0_CORE_ID 0xbb11477
-#define CORE_M3_R1 0x1BA00477
-#define CORE_M3_R2 0x4BA00477
-#define CORE_M4_R0 0x2BA01477
-
- /*
- * Chip IDs are explained in the appropriate programming manual for the
- * DBGMCU_IDCODE register (0xE0042000)
- */
- // stm32 chipids, only lower 12 bits..
-#define STM32_CHIPID_F1_MEDIUM 0x410
-#define STM32_CHIPID_F2 0x411
-#define STM32_CHIPID_F1_LOW 0x412
-#define STM32_CHIPID_F4 0x413
-#define STM32_CHIPID_F1_HIGH 0x414
-#define STM32_CHIPID_L4 0x415 /* Seen on L4x6 (RM0351) */
-#define STM32_CHIPID_L1_MEDIUM 0x416
-#define STM32_CHIPID_L0 0x417
-#define STM32_CHIPID_F1_CONN 0x418
-#define STM32_CHIPID_F4_HD 0x419
-#define STM32_CHIPID_F1_VL_MEDIUM_LOW 0x420
-
-#define STM32_CHIPID_F446 0x421
-#define STM32_CHIPID_F3 0x422
-#define STM32_CHIPID_F4_LP 0x423
-
-#define STM32_CHIPID_F411RE 0x431
-
-#define STM32_CHIPID_L1_MEDIUM_PLUS 0x427
-#define STM32_CHIPID_F1_VL_HIGH 0x428
-#define STM32_CHIPID_L1_CAT2 0x429
-
-#define STM32_CHIPID_F1_XL 0x430
-
-#define STM32_CHIPID_F37x 0x432
-#define STM32_CHIPID_F4_DE 0x433
-#define STM32_CHIPID_F4_DE 0x433
-
-#define STM32_CHIPID_F4_DSI 0x434
-
-#define STM32_CHIPID_L1_HIGH 0x436
-#define STM32_CHIPID_L152_RE 0x437
-#define STM32_CHIPID_F334 0x438
-
-#define STM32_CHIPID_F3_SMALL 0x439
-#define STM32_CHIPID_F0 0x440
-#define STM32_CHIPID_F09X 0x442
-#define STM32_CHIPID_F0_SMALL 0x444
-
-#define STM32_CHIPID_F04 0x445
-
-#define STM32_CHIPID_F303_HIGH 0x446
-
-#define STM32_CHIPID_F0_CAN 0x448
-
-#define STM32_CHIPID_F7 0x449
-
- /*
- * 0x436 is actually assigned to some L1 chips that are called "Medium-Plus"
- * and some that are called "High". 0x427 is assigned to the other "Medium-
- * plus" chips. To make it a bit simpler we just call 427 MEDIUM_PLUS and
- * 0x436 HIGH.
- */
-
- // Constant STM32 memory map figures
-#define STM32_FLASH_BASE 0x08000000
-#define STM32_SRAM_BASE 0x20000000
-
- /* Cortex™-M3 Technical Reference Manual */
- /* Debug Halting Control and Status Register */
-#define DHCSR 0xe000edf0
-#define DCRSR 0xe000edf4
-#define DCRDR 0xe000edf8
-#define DBGKEY 0xa05f0000
-
- /* Enough space to hold both a V2 command or a V1 command packaged as generic scsi*/
-#define C_BUF_LEN 32
-
- enum flash_type {
- FLASH_TYPE_UNKNOWN = 0,
- FLASH_TYPE_F0,
- FLASH_TYPE_L0,
- FLASH_TYPE_F4,
- FLASH_TYPE_L4,
- };
-
- typedef struct chip_params_ {
- uint32_t chip_id;
- char* description;
- enum flash_type flash_type;
- uint32_t flash_size_reg;
- uint32_t flash_pagesize;
- uint32_t sram_size;
- uint32_t bootrom_base, bootrom_size;
- } chip_params_t;
-
-
- // These maps are from a combination of the Programming Manuals, and
- // also the Reference manuals. (flash size reg is normally in ref man)
- static const chip_params_t devices[] = {
- {
- //RM0385 and DS10916 document was used to find these paramaters
- .chip_id = STM32_CHIPID_F7,
- .description = "F7 device",
- .flash_type = FLASH_TYPE_F4,
- .flash_size_reg = 0x1ff0f442, // section 41.2
- .flash_pagesize = 0x800, // No flash pages
- .sram_size = 0x50000, // "SRAM" byte size in hex from DS Fig 18
- .bootrom_base = 0x00100000, // "System memory" starting address from DS Fig 18
- .bootrom_size = 0xEDC0 // "System memory" byte size in hex from DS Fig 18
- },
- { // table 2, PM0063
- .chip_id = STM32_CHIPID_F1_MEDIUM,
- .description = "F1 Medium-density device",
- .flash_type = FLASH_TYPE_F0,
- .flash_size_reg = 0x1ffff7e0,
- .flash_pagesize = 0x400,
- .sram_size = 0x5000,
- .bootrom_base = 0x1ffff000,
- .bootrom_size = 0x800
- },
- { // table 1, PM0059
- .chip_id = STM32_CHIPID_F2,
- .description = "F2 device",
- .flash_type = FLASH_TYPE_F4,
- .flash_size_reg = 0x1fff7a22, /* As in RM0033 Rev 5*/
- .flash_pagesize = 0x20000,
- .sram_size = 0x20000,
- .bootrom_base = 0x1fff0000,
- .bootrom_size = 0x7800
- },
- { // PM0063
- .chip_id = STM32_CHIPID_F1_LOW,
- .description = "F1 Low-density device",
- .flash_type = FLASH_TYPE_F0,
- .flash_size_reg = 0x1ffff7e0,
- .flash_pagesize = 0x400,
- .sram_size = 0x2800,
- .bootrom_base = 0x1ffff000,
- .bootrom_size = 0x800
- },
- {
- .chip_id = STM32_CHIPID_F4,
- .description = "F4 device",
- .flash_type = FLASH_TYPE_F4,
- .flash_size_reg = 0x1FFF7A22, /* As in rm0090 since Rev 2*/
- .flash_pagesize = 0x4000,
- .sram_size = 0x30000,
- .bootrom_base = 0x1fff0000,
- .bootrom_size = 0x7800
- },
- {
- .chip_id = STM32_CHIPID_F4_DSI,
- .description = "F46x and F47x device",
- .flash_type = FLASH_TYPE_F4,
- .flash_size_reg = 0x1FFF7A22, /* As in rm0090 since Rev 2*/
- .flash_pagesize = 0x4000,
- .sram_size = 0x40000,
- .bootrom_base = 0x1fff0000,
- .bootrom_size = 0x7800
- },
- {
- .chip_id = STM32_CHIPID_F4_HD,
- .description = "F42x and F43x device",
- .flash_type = FLASH_TYPE_F4,
- .flash_size_reg = 0x1FFF7A22, /* As in rm0090 since Rev 2*/
- .flash_pagesize = 0x4000,
- .sram_size = 0x40000,
- .bootrom_base = 0x1fff0000,
- .bootrom_size = 0x7800
- },
- {
- .chip_id = STM32_CHIPID_F4_LP,
- .description = "F4 device (low power)",
- .flash_type = FLASH_TYPE_F4,
- .flash_size_reg = 0x1FFF7A22,
- .flash_pagesize = 0x4000,
- .sram_size = 0x10000,
- .bootrom_base = 0x1fff0000,
- .bootrom_size = 0x7800
- },
- {
- .chip_id = STM32_CHIPID_F411RE,
- .description = "F4 device (low power) - stm32f411re",
- .flash_type = FLASH_TYPE_F4,
- .flash_size_reg = 0x1FFF7A22,
- .flash_pagesize = 0x4000,
- .sram_size = 0x20000,
- .bootrom_base = 0x1fff0000,
- .bootrom_size = 0x7800
- },
- {
- .chip_id = STM32_CHIPID_F4_DE,
- .description = "F4 device (Dynamic Efficency)",
- .flash_type = FLASH_TYPE_F4,
- .flash_size_reg = 0x1FFF7A22,
- .flash_pagesize = 0x4000,
- .sram_size = 0x18000,
- .bootrom_base = 0x1fff0000,
- .bootrom_size = 0x7800
- },
- {
- .chip_id = STM32_CHIPID_F1_HIGH,
- .description = "F1 High-density device",
- .flash_type = FLASH_TYPE_F0,
- .flash_size_reg = 0x1ffff7e0,
- .flash_pagesize = 0x800,
- .sram_size = 0x10000,
- .bootrom_base = 0x1ffff000,
- .bootrom_size = 0x800
- },
- {
- // This ignores the EEPROM! (and uses the page erase size,
- // not the sector write protection...)
- .chip_id = STM32_CHIPID_L1_MEDIUM,
- .description = "L1 Med-density device",
- .flash_type = FLASH_TYPE_L0,
- .flash_size_reg = 0x1ff8004c,
- .flash_pagesize = 0x100,
- .sram_size = 0x4000,
- .bootrom_base = 0x1ff00000,
- .bootrom_size = 0x1000
- },
- {
- .chip_id = STM32_CHIPID_L1_CAT2,
- .description = "L1 Cat.2 device",
- .flash_type = FLASH_TYPE_L0,
- .flash_size_reg = 0x1ff8004c,
- .flash_pagesize = 0x100,
- .sram_size = 0x8000,
- .bootrom_base = 0x1ff00000,
- .bootrom_size = 0x1000
- },
- {
- .chip_id = STM32_CHIPID_L1_MEDIUM_PLUS,
- .description = "L1 Medium-Plus-density device",
- .flash_type = FLASH_TYPE_L0,
- .flash_size_reg = 0x1ff800cc,
- .flash_pagesize = 0x100,
- .sram_size = 0x8000,/*Not completely clear if there are some with 48K*/
- .bootrom_base = 0x1ff00000,
- .bootrom_size = 0x1000
- },
- {
- .chip_id = STM32_CHIPID_L1_HIGH,
- .description = "L1 High-density device",
- .flash_type = FLASH_TYPE_L0,
- .flash_size_reg = 0x1ff800cc,
- .flash_pagesize = 0x100,
- .sram_size = 0xC000, /*Not completely clear if there are some with 32K*/
- .bootrom_base = 0x1ff00000,
- .bootrom_size = 0x1000
- },
- {
- .chip_id = STM32_CHIPID_L152_RE,
- .description = "L152RE",
- .flash_type = FLASH_TYPE_L0,
- .flash_size_reg = 0x1ff800cc,
- .flash_pagesize = 0x100,
- .sram_size = 0x14000, /*Not completely clear if there are some with 32K*/
- .bootrom_base = 0x1ff00000,
- .bootrom_size = 0x1000
- },
- {
- .chip_id = STM32_CHIPID_F1_CONN,
- .description = "F1 Connectivity line device",
- .flash_type = FLASH_TYPE_F0,
- .flash_size_reg = 0x1ffff7e0,
- .flash_pagesize = 0x800,
- .sram_size = 0x10000,
- .bootrom_base = 0x1fffb000,
- .bootrom_size = 0x4800
- },
- {//Low and Medium density VL have same chipid. RM0041 25.6.1
- .chip_id = STM32_CHIPID_F1_VL_MEDIUM_LOW,
- .description = "F1 Medium/Low-density Value Line device",
- .flash_type = FLASH_TYPE_F0,
- .flash_size_reg = 0x1ffff7e0,
- .flash_pagesize = 0x400,
- .sram_size = 0x2000,//0x1000 for low density devices
- .bootrom_base = 0x1ffff000,
- .bootrom_size = 0x800
- },
- {
- // STM32F446x family. Support based on DM00135183.pdf (RM0390) document.
- .chip_id = STM32_CHIPID_F446,
- .description = "F446 device",
- .flash_type = FLASH_TYPE_F4,
- .flash_size_reg = 0x1fff7a22,
- .flash_pagesize = 0x20000,
- .sram_size = 0x20000,
- .bootrom_base = 0x1fff0000,
- .bootrom_size = 0x7800
- },
- {
- // This is STK32F303VCT6 device from STM32 F3 Discovery board.
- // Support based on DM00043574.pdf (RM0316) document.
- .chip_id = STM32_CHIPID_F3,
- .description = "F3 device",
- .flash_type = FLASH_TYPE_F0,
- .flash_size_reg = 0x1ffff7cc,
- .flash_pagesize = 0x800,
- .sram_size = 0xa000,
- .bootrom_base = 0x1ffff000,
- .bootrom_size = 0x800
- },
- {
- // This is STK32F373VCT6 device from STM32 F373 eval board
- // Support based on 303 above (37x and 30x have same memory map)
- .chip_id = STM32_CHIPID_F37x,
- .description = "F3 device",
- .flash_type = FLASH_TYPE_F0,
- .flash_size_reg = 0x1ffff7cc,
- .flash_pagesize = 0x800,
- .sram_size = 0xa000,
- .bootrom_base = 0x1ffff000,
- .bootrom_size = 0x800
- },
- {
- .chip_id = STM32_CHIPID_F1_VL_HIGH,
- .description = "F1 High-density value line device",
- .flash_type = FLASH_TYPE_F0,
- .flash_size_reg = 0x1ffff7e0,
- .flash_pagesize = 0x800,
- .sram_size = 0x8000,
- .bootrom_base = 0x1ffff000,
- .bootrom_size = 0x800
- },
- {
- .chip_id = STM32_CHIPID_F1_XL,
- .description = "F1 XL-density device",
- .flash_type = FLASH_TYPE_F0,
- .flash_size_reg = 0x1ffff7e0,
- .flash_pagesize = 0x800,
- .sram_size = 0x18000,
- .bootrom_base = 0x1fffe000,
- .bootrom_size = 0x1800
- },
- {
- //Use this as an example for mapping future chips:
- //RM0091 document was used to find these paramaters
- .chip_id = STM32_CHIPID_F0_CAN,
- .description = "F07x device",
- .flash_type = FLASH_TYPE_F0,
- .flash_size_reg = 0x1ffff7cc, // "Flash size data register" (pg735)
- .flash_pagesize = 0x800, // Page sizes listed in Table 4
- .sram_size = 0x4000, // "SRAM" byte size in hex from Table 2
- .bootrom_base = 0x1fffC800, // "System memory" starting address from Table 2
- .bootrom_size = 0x3000 // "System memory" byte size in hex from Table 2
- },
- {
- //Use this as an example for mapping future chips:
- //RM0091 document was used to find these paramaters
- .chip_id = STM32_CHIPID_F0,
- .description = "F0 device",
- .flash_type = FLASH_TYPE_F0,
- .flash_size_reg = 0x1ffff7cc, // "Flash size data register" (pg735)
- .flash_pagesize = 0x400, // Page sizes listed in Table 4
- .sram_size = 0x2000, // "SRAM" byte size in hex from Table 2
- .bootrom_base = 0x1fffec00, // "System memory" starting address from Table 2
- .bootrom_size = 0xC00 // "System memory" byte size in hex from Table 2
- },
- {
- .chip_id = STM32_CHIPID_F09X,
- .description = "F09X device",
- .flash_type = FLASH_TYPE_F0,
- .flash_size_reg = 0x1ffff7cc, // "Flash size data register" (pg735)
- .flash_pagesize = 0x800, // Page sizes listed in Table 4 (pg 56)
- .sram_size = 0x8000, // "SRAM" byte size in hex from Table 2 (pg 50)
- .bootrom_base = 0x1fffd800, // "System memory" starting address from Table 2
- .bootrom_size = 0x2000 // "System memory" byte size in hex from Table 2
- },
- {
- //Use this as an example for mapping future chips:
- //RM0091 document was used to find these paramaters
- .chip_id = STM32_CHIPID_F04,
- .description = "F04x device",
- .flash_type = FLASH_TYPE_F0,
- .flash_size_reg = 0x1ffff7cc, // "Flash size data register" (pg735)
- .flash_pagesize = 0x400, // Page sizes listed in Table 4
- .sram_size = 0x1800, // "SRAM" byte size in hex from Table 2
- .bootrom_base = 0x1fffec00, // "System memory" starting address from Table 2
- .bootrom_size = 0xC00 // "System memory" byte size in hex from Table 2
- },
- {
- //Use this as an example for mapping future chips:
- //RM0091 document was used to find these paramaters
- .chip_id = STM32_CHIPID_F0_SMALL,
- .description = "F0 small device",
- .flash_type = FLASH_TYPE_F0,
- .flash_size_reg = 0x1ffff7cc, // "Flash size data register" (pg735)
- .flash_pagesize = 0x400, // Page sizes listed in Table 4
- .sram_size = 0x1000, // "SRAM" byte size in hex from Table 2
- .bootrom_base = 0x1fffec00, // "System memory" starting address from Table 2
- .bootrom_size = 0xC00 // "System memory" byte size in hex from Table 2
- },
- {
- // STM32F30x
- .chip_id = STM32_CHIPID_F3_SMALL,
- .description = "F3 small device",
- .flash_type = FLASH_TYPE_F0,
- .flash_size_reg = 0x1ffff7cc,
- .flash_pagesize = 0x800,
- .sram_size = 0xa000,
- .bootrom_base = 0x1fffd800,
- .bootrom_size = 0x2000
- },
- {
- // STM32L0x
- // RM0367,RM0377 documents was used to find these parameters
- .chip_id = STM32_CHIPID_L0,
- .description = "L0x3 device",
- .flash_type = FLASH_TYPE_L0,
- .flash_size_reg = 0x1ff8007c,
- .flash_pagesize = 0x80,
- .sram_size = 0x2000,
- .bootrom_base = 0x1ff0000,
- .bootrom_size = 0x1000
- },
- {
- // STM32F334
- // RM0364 document was used to find these parameters
- .chip_id = STM32_CHIPID_F334,
- .description = "F334 device",
- .flash_type = FLASH_TYPE_F0,
- .flash_size_reg = 0x1ffff7cc,
- .flash_pagesize = 0x800,
- .sram_size = 0x3000,
- .bootrom_base = 0x1fffd800,
- .bootrom_size = 0x2000
- },
- {
- // This is STK32F303RET6 device from STM32 F3 Nucelo board.
- // Support based on DM00043574.pdf (RM0316) document rev 5.
- .chip_id = STM32_CHIPID_F303_HIGH,
- .description = "F303 high density device",
- .flash_type = FLASH_TYPE_F0,
- .flash_size_reg = 0x1ffff7cc, // 34.2.1 Flash size data register
- .flash_pagesize = 0x800, // 4.2.1 Flash memory organization
- .sram_size = 0x10000, // 3.3 Embedded SRAM
- .bootrom_base = 0x1fffd800, // 3.3.2 / Table 4 System Memory
- .bootrom_size = 0x2000
- },
- {
- // STM32L4x6
- // From RM0351.
- .chip_id = STM32_CHIPID_L4,
- .description = "L4 device",
- .flash_type = FLASH_TYPE_L4,
- .flash_size_reg = 0x1fff75e0, // "Flash size data register" (sec 45.2, page 1671)
- .flash_pagesize = 0x800, // 2K (sec 3.2, page 78; also appears in sec 3.3.1 and tables 4-6 on pages 79-81)
- // SRAM1 is "up to" 96k in the standard Cortex-M memory map;
- // SRAM2 is 32k mapped at at 0x10000000 (sec 2.3, page 73 for
- // sizes; table 2, page 74 for SRAM2 location)
- .sram_size = 0x18000,
- .bootrom_base = 0x1fff0000, // Tables 4-6, pages 80-81 (Bank 1 system memory)
- .bootrom_size = 0x7000 // 28k (per bank), same source as base
- },
-
- };
-
-
- typedef struct {
- 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;
- } reg;
-
- typedef uint32_t stm32_addr_t;
-
- typedef struct _cortex_m3_cpuid_ {
- uint16_t implementer_id;
- uint16_t variant;
- uint16_t part;
- uint8_t revision;
- } cortex_m3_cpuid_t;
-
- typedef struct stlink_version_ {
- uint32_t stlink_v;
- uint32_t jtag_v;
- uint32_t swim_v;
- uint32_t st_vid;
- uint32_t stlink_pid;
- } stlink_version_t;
-
- typedef struct flash_loader {
- stm32_addr_t loader_addr; /* loader sram adddr */
- stm32_addr_t buf_addr; /* buffer sram address */
- } flash_loader_t;
-
- enum transport_type {
- TRANSPORT_TYPE_ZERO = 0,
- TRANSPORT_TYPE_LIBSG,
- TRANSPORT_TYPE_LIBUSB,
- TRANSPORT_TYPE_INVALID
- };
-
- typedef struct _stlink stlink_t;
-
- typedef struct _stlink_backend {
- void (*close) (stlink_t * sl);
- int (*exit_debug_mode) (stlink_t * sl);
- int (*enter_swd_mode) (stlink_t * sl);
- int (*enter_jtag_mode) (stlink_t * stl);
- int (*exit_dfu_mode) (stlink_t * stl);
- int (*core_id) (stlink_t * stl);
- int (*reset) (stlink_t * stl);
- int (*jtag_reset) (stlink_t * stl, int value);
- int (*run) (stlink_t * stl);
- int (*status) (stlink_t * stl);
- int (*version) (stlink_t *sl);
- int (*read_debug32) (stlink_t *sl, uint32_t addr, uint32_t *data);
- int (*read_mem32) (stlink_t *sl, uint32_t addr, uint16_t len);
- int (*write_debug32) (stlink_t *sl, uint32_t addr, uint32_t data);
- int (*write_mem32) (stlink_t *sl, uint32_t addr, uint16_t len);
- int (*write_mem8) (stlink_t *sl, uint32_t addr, uint16_t len);
- int (*read_all_regs) (stlink_t *sl, reg * regp);
- int (*read_reg) (stlink_t *sl, int r_idx, reg * regp);
- int (*read_all_unsupported_regs) (stlink_t *sl, reg *regp);
- int (*read_unsupported_reg) (stlink_t *sl, int r_idx, reg *regp);
- int (*write_unsupported_reg) (stlink_t *sl, uint32_t value, int idx, reg *regp);
- int (*write_reg) (stlink_t *sl, uint32_t reg, int idx);
- int (*step) (stlink_t * stl);
- int (*current_mode) (stlink_t * stl);
- int (*force_debug) (stlink_t *sl);
- int32_t (*target_voltage) (stlink_t *sl);
- } stlink_backend_t;
-
- 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];
- int q_len;
-
- // transport layer verboseness: 0 for no debug info, 10 for lots
- int verbose;
- uint32_t core_id;
- uint32_t chip_id;
- int core_stat;
-
- char serial[16];
- int serial_size;
-
-#define STM32_FLASH_PGSZ 1024
-#define STM32L_FLASH_PGSZ 256
-
-#define STM32F4_FLASH_PGSZ 16384
-#define STM32F4_FLASH_SIZE (128 * 1024 * 8)
-
- enum flash_type flash_type;
- stm32_addr_t flash_base;
- size_t flash_size;
- size_t flash_pgsz;
-
- /* sram settings */
-#define STM32_SRAM_SIZE (8 * 1024)
-#define STM32L_SRAM_SIZE (16 * 1024)
- stm32_addr_t sram_base;
- size_t sram_size;
-
- // bootloader
- stm32_addr_t sys_base;
- size_t sys_size;
-
- struct stlink_version_ version;
- };
-
- //stlink_t* stlink_quirk_open(const char *dev_name, const int verbose);
-
- // delegated functions...
- int stlink_enter_swd_mode(stlink_t *sl);
- int stlink_enter_jtag_mode(stlink_t *sl);
- int stlink_exit_debug_mode(stlink_t *sl);
- int stlink_exit_dfu_mode(stlink_t *sl);
- void stlink_close(stlink_t *sl);
- int stlink_core_id(stlink_t *sl);
- int stlink_reset(stlink_t *sl);
- int stlink_jtag_reset(stlink_t *sl, int value);
- int stlink_run(stlink_t *sl);
- int stlink_status(stlink_t *sl);
- int stlink_version(stlink_t *sl);
- int stlink_read_debug32(stlink_t *sl, uint32_t addr, uint32_t *data);
- int stlink_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len);
- int stlink_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data);
- int stlink_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len);
- int stlink_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len);
- int stlink_read_all_regs(stlink_t *sl, reg *regp);
- int stlink_read_all_unsupported_regs(stlink_t *sl, reg *regp);
- int stlink_read_reg(stlink_t *sl, int r_idx, reg *regp);
- int stlink_read_unsupported_reg(stlink_t *sl, int r_idx, reg *regp);
- int stlink_write_unsupported_reg(stlink_t *sl, uint32_t value, int r_idx, reg *regp);
- int stlink_write_reg(stlink_t *sl, uint32_t reg, int idx);
- int stlink_step(stlink_t *sl);
- int stlink_current_mode(stlink_t *sl);
- int stlink_force_debug(stlink_t *sl);
- int stlink_target_voltage(stlink_t *sl);
-
-
- // unprocessed
- int stlink_erase_flash_mass(stlink_t* sl);
- int stlink_write_flash(stlink_t* sl, stm32_addr_t address, uint8_t* data, uint32_t length, uint8_t eraseonly);
- int stlink_fwrite_flash(stlink_t *sl, const char* path, stm32_addr_t addr);
- int stlink_fwrite_sram(stlink_t *sl, const char* path, stm32_addr_t addr);
- int stlink_verify_write_flash(stlink_t *sl, stm32_addr_t address, uint8_t *data, uint32_t length);
-
- // PUBLIC
- int stlink_chip_id(stlink_t *sl, uint32_t *chip_id);
- int stlink_cpu_id(stlink_t *sl, cortex_m3_cpuid_t *cpuid);
-
- // privates, publics, the rest....
- // TODO sort what is private, and what is not
- int stlink_erase_flash_page(stlink_t* sl, stm32_addr_t flashaddr);
- uint32_t stlink_calculate_pagesize(stlink_t *sl, uint32_t flashaddr);
- uint16_t read_uint16(const unsigned char *c, const int pt);
- void stlink_core_stat(stlink_t *sl);
- void stlink_print_data(stlink_t *sl);
- unsigned int is_bigendian(void);
- uint32_t read_uint32(const unsigned char *c, const int pt);
- void write_uint32(unsigned char* buf, uint32_t ui);
- void write_uint16(unsigned char* buf, uint16_t ui);
- unsigned int is_core_halted(stlink_t *sl);
- int write_buffer_to_sram(stlink_t *sl, flash_loader_t* fl, const uint8_t* buf, size_t size);
- int write_loader_to_sram(stlink_t *sl, stm32_addr_t* addr, size_t* size);
- int stlink_fread(stlink_t* sl, const char* path, stm32_addr_t addr, size_t size);
- int run_flash_loader(stlink_t *sl, flash_loader_t* fl, stm32_addr_t target, const uint8_t* buf, size_t size);
- int stlink_load_device_params(stlink_t *sl);
-
-
-
-#include "stlink-sg.h"
-#include "stlink-usb.h"
-
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* STLINK_COMMON_H */
+++ /dev/null
-/*
- * 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 <m@capitanio.org>
- * The stlink related constants kindly provided by Oliver Spencer (OpenOCD)
- * for use in a GPL compatible license.
- *
- * Tested compatibility: linux, gcc >= 4.3.3
- *
- * The communication is based on standard USB mass storage device
- * BOT (Bulk Only Transfer)
- * - Endpoint 1: BULK_IN, 64 bytes max
- * - Endpoint 2: BULK_OUT, 64 bytes max
- *
- * All CBW transfers are ordered with the LSB (byte 0) first (little endian).
- * Any command must be answered before sending the next command.
- * Each USB transfer must complete in less than 1s.
- *
- * SB Device Class Definition for Mass Storage Devices:
- * www.usb.org/developers/devclass_docs/usbmassbulk_10.pdf
- *
- * dt - Data Transfer (IN/OUT)
- * CBW - Command Block Wrapper
- * CSW - Command Status Wrapper
- * RFU - Reserved for Future Use
- *
- * Originally, this driver used scsi pass through commands, which required the
- * usb-storage module to be loaded, providing the /dev/sgX links. The USB mass
- * storage implementation on the STLinkv1 is however terribly broken, and it can
- * take many minutes for the kernel to give up.
- *
- * However, in Nov 2011, the scsi pass through was replaced by raw libusb, so
- * instead of having to let usb-storage struggle with the device, and also greatly
- * limiting the portability of the driver, you can now tell usb-storage to simply
- * ignore this device completely.
- *
- * usb-storage.quirks
- * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob_plain;f=Documentation/kernel-parameters.txt
- * Each entry has the form VID:PID:Flags where VID and PID are Vendor and Product
- * ID values (4-digit hex numbers) and Flags is a set of characters, each corresponding
- * to a common usb-storage quirk flag as follows:
- *
- * a = SANE_SENSE (collect more than 18 bytes of sense data);
- * b = BAD_SENSE (don't collect more than 18 bytes of sense data);
- * c = FIX_CAPACITY (decrease the reported device capacity by one sector);
- * h = CAPACITY_HEURISTICS (decrease the reported device capacity by one sector if the number is odd);
- * i = IGNORE_DEVICE (don't bind to this device);
- * l = NOT_LOCKABLE (don't try to lock and unlock ejectable media);
- * m = MAX_SECTORS_64 (don't transfer more than 64 sectors = 32 KB at a time);
- * o = CAPACITY_OK (accept the capacity reported by the device);
- * r = IGNORE_RESIDUE (the device reports bogus residue values);
- * s = SINGLE_LUN (the device has only one Logical Unit);
- * w = NO_WP_DETECT (don't test whether the medium is write-protected).
- *
- * Example: quirks=0419:aaf5:rl,0421:0433:rc
- * http://permalink.gmane.org/gmane.linux.usb.general/35053
- *
- * For the stlinkv1, you just want the following
- *
- * modprobe -r usb-storage && modprobe usb-storage quirks=483:3744:i
- *
- * Equivalently, you can add a line saying
- *
- * options usb-storage quirks=483:3744:i
- *
- * to your /etc/modprobe.conf or /etc/modprobe.d/local.conf (or add the "quirks=..."
- * part to an existing options line for usb-storage).
- */
-
-
-#define __USE_GNU
-#include <assert.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/types.h>
-
-#include "stlink-common.h"
-#include "stlink-sg.h"
-#include "uglylogging.h"
-
-static void clear_cdb(struct stlink_libsg *sl) {
- for (size_t i = 0; i < sizeof (sl->cdb_cmd_blk); i++)
- sl->cdb_cmd_blk[i] = 0;
- // 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 int get_usb_mass_storage_status(libusb_device_handle *handle, uint8_t endpoint, uint32_t *tag)
-{
- unsigned char csw[13];
- memset(csw, 0, sizeof(csw));
- int transferred;
- int ret;
- int try = 0;
- 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 int dump_CDB_command(uint8_t *cdb, uint8_t cdb_len) {
- char dbugblah[100];
- char *dbugp = dbugblah;
- dbugp += sprintf(dbugp, "Sending CDB [");
- for (uint8_t i = 0; i < cdb_len; i++) {
- dbugp += sprintf(dbugp, " %#02x", (unsigned int) cdb[i]);
- }
- sprintf(dbugp, "]\n");
- DLOG(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
- */
-int send_usb_mass_storage_command(libusb_device_handle *handle, uint8_t endpoint_out,
- uint8_t *cdb, uint8_t cdb_length,
- uint8_t lun, uint8_t flags, uint32_t expected_rx_size) {
- 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;
- }
-
- int try = 0;
- int ret = 0;
- int real_transferred;
- int 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);
-
- int 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];
- int transferred;
- int ret;
- int 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 != %d\n", transferred, sizeof(sense));
- }
- uint32_t received_tag;
- int 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.
- */
-int send_usb_data_only(libusb_device_handle *handle, unsigned char endpoint_out,
- unsigned char endpoint_in, unsigned char *cbuf, unsigned int length) {
- int ret;
- int real_transferred;
- int try = 0;
- 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
- int 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;
-}
-
-
-int 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...
- int rx_length = sl->q_len;
- int try = 0;
- int real_transferred;
- int 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
- int 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);
- }
-}
-
-
-int _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
-
-int _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.
-
-int _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_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)
-
-int _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_ENTER;
- sg->cdb_cmd_blk[2] = STLINK_DEBUG_ENTER_JTAG;
- 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
-int _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
- */
-}
-
-int _stlink_sg_core_id(stlink_t *sl) {
- struct stlink_libsg *sg = sl->backend_data;
- int 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.
-
-int _stlink_sg_reset(stlink_t *sl) {
- struct stlink_libsg *sg = sl->backend_data;
- clear_cdb(sg);
- sg->cdb_cmd_blk[1] = STLINK_DEBUG_RESETSYS;
- sl->q_len = 2;
- sg->q_addr = 0;
- if (stlink_q(sl))
- return -1;
-
- stlink_stat(sl, "core reset");
- return 0;
-}
-
-// Arm-core reset -> halted state.
-
-int _stlink_sg_jtag_reset(stlink_t *sl, int value) {
- struct stlink_libsg *sg = sl->backend_data;
- clear_cdb(sg);
- sg->cdb_cmd_blk[1] = STLINK_JTAG_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.
-
-int _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.
-
-int _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.
-
-int _stlink_sg_read_all_regs(stlink_t *sl, reg *regp) {
- struct stlink_libsg *sg = sl->backend_data;
-
- clear_cdb(sg);
- sg->cdb_cmd_blk[1] = STLINK_DEBUG_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 (int 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
-
-int _stlink_sg_read_reg(stlink_t *sl, int r_idx, reg *regp) {
- struct stlink_libsg *sg = sl->backend_data;
- clear_cdb(sg);
- sg->cdb_cmd_blk[1] = STLINK_DEBUG_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
-
-int _stlink_sg_write_reg(stlink_t *sl, uint32_t reg, int idx) {
- struct stlink_libsg *sg = sl->backend_data;
- clear_cdb(sg);
- sg->cdb_cmd_blk[1] = STLINK_DEBUG_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_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.
-
-int _stlink_sg_run(stlink_t *sl) {
- struct stlink_libsg *sg = sl->backend_data;
- 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.
-
-int _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
-// see Cortex-M3 Technical Reference Manual
-// TODO make delegate!
-void stlink_set_hw_bp(stlink_t *sl, int fp_nr, uint32_t addr, int 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_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
-
-// TODO make delegate!
-void stlink_clr_hw_bp(stlink_t *sl, int 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_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)
-
-int _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.
-
-int _stlink_sg_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len) {
- struct stlink_libsg *sg = sl->backend_data;
- int 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.
-
-int _stlink_sg_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
- struct stlink_libsg *sg = sl->backend_data;
- int 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
-
-int _stlink_sg_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data) {
- struct stlink_libsg *sg = sl->backend_data;
- clear_cdb(sg);
- sg->cdb_cmd_blk[1] = STLINK_JTAG_WRITEDEBUG_32BIT;
- // 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
-
-int _stlink_sg_read_debug32(stlink_t *sl, uint32_t addr, uint32_t *data) {
- struct stlink_libsg *sg = sl->backend_data;
- clear_cdb(sg);
- sg->cdb_cmd_blk[1] = STLINK_JTAG_READDEBUG_32BIT;
- // 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.
-
-int _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
-
-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
-};
-
-static stlink_t* stlink_open(const int verbose) {
-
- stlink_t *sl = malloc(sizeof (stlink_t));
- memset(sl, 0, 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");
- return NULL;
- }
-
- if (libusb_init(&(slsg->libusb_ctx))) {
- WLOG("failed to init libusb context, wrong version of libraries?\n");
- free(sl);
- free(slsg);
- return NULL;
- }
-
- libusb_set_debug(slsg->libusb_ctx, 3);
-
- slsg->usb_handle = libusb_open_device_with_vid_pid(slsg->libusb_ctx, USB_ST_VID, USB_STLINK_PID);
- 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) {
- int 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");
- }
-
- int 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 = STLINK_CORE_STAT_UNKNOWN;
- slsg->q_addr = 0;
-
- return sl;
-}
-
-
-stlink_t* stlink_v1_open_inner(const int 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 != USB_ST_VID) || (sl->version.stlink_pid != USB_STLINK_PID)) {
- 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 != USB_ST_VID) || (sl->version.stlink_pid != USB_STLINK_PID)) {
- ELOG("WTF? successfully opened, but unable to read version details. BROKEN!\n");
- return NULL;
- }
-
- return sl;
-}
-
-stlink_t* stlink_v1_open(const int verbose, int 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);
- }
- stlink_load_device_params(sl);
- ILOG("Successfully opened a stlink v1 debugger\n");
- return sl;
-}
+++ /dev/null
-/*
- * File: stlink-sg.h
- * Author: karl
- *
- * Created on October 1, 2011, 11:29 PM
- */
-
-#ifndef STLINK_SG_H
-#define STLINK_SG_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <libusb.h>
-#include "stlink-common.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;
- unsigned ep_rep;
- unsigned ep_req;
-
- int sg_fd;
- int do_scsi_pt_err;
-
- unsigned char cdb_cmd_blk[CDB_SL];
-
- int 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];
-
- reg reg;
- };
-
- stlink_t* stlink_v1_open(const int verbose, int reset);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* STLINK_SG_H */
-
+++ /dev/null
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <libusb.h>
-#include <errno.h>
-#include <unistd.h>
-
-#include "stlink-common.h"
-#include "stlink-usb.h"
-
-enum SCSI_Generic_Direction {SG_DXFER_TO_DEV=0, SG_DXFER_FROM_DEV=0x80};
-
-void _stlink_usb_close(stlink_t* sl) {
- if (!sl)
- return;
-
- struct stlink_libusb * const handle = sl->backend_data;
- // maybe we couldn't even get the usb device?
- if (handle != NULL) {
- if (handle->usb_handle != NULL) {
- libusb_close(handle->usb_handle);
- }
-
- libusb_exit(handle->libusb_ctx);
- free(handle);
- }
-}
-
-ssize_t send_recv(struct stlink_libusb* handle, int terminate,
- unsigned char* txbuf, size_t txsize,
- unsigned char* rxbuf, size_t rxsize) {
- /* note: txbuf and rxbuf can point to the same area */
- int res = 0;
-
- if (libusb_bulk_transfer(handle->usb_handle, handle->ep_req,
- txbuf,
- txsize,
- &res,
- 3000))
- return -1;
-
- if (rxsize != 0) {
- if (libusb_bulk_transfer(handle->usb_handle, handle->ep_rep,
- rxbuf,
- rxsize,
- &res,
- 3000))
- return -1;
- }
-
- if ((handle->protocoll == 1) && terminate) {
- /* Read the SG reply */
- unsigned char sg_buf[13];
- if (libusb_bulk_transfer(handle->usb_handle, handle->ep_rep,
- sg_buf,
- 13,
- &res,
- 3000))
- return -1;
- /* The STLink doesn't seem to evaluate the sequence number */
- handle->sg_transfer_idx++;
- }
-
- return res;
-}
-
-static inline int send_only
-(struct stlink_libusb* handle, int terminate,
- unsigned char* txbuf, size_t txsize) {
- return send_recv(handle, terminate, txbuf, txsize, NULL, 0);
-}
-
-
-static int fill_command
-(stlink_t * sl, enum SCSI_Generic_Direction dir, uint32_t len) {
- struct stlink_libusb * const slu = sl->backend_data;
- unsigned char* const cmd = sl->c_buf;
- int i = 0;
- memset(cmd, 0, sizeof (sl->c_buf));
- if(slu->protocoll == 1) {
- cmd[i++] = 'U';
- cmd[i++] = 'S';
- cmd[i++] = 'B';
- cmd[i++] = 'C';
- write_uint32(&cmd[i], slu->sg_transfer_idx);
- write_uint32(&cmd[i + 4], len);
- i += 8;
- cmd[i++] = (dir == SG_DXFER_FROM_DEV)?0x80:0;
- cmd[i++] = 0; /* Logical unit */
- cmd[i++] = 0xa; /* Command length */
- }
- return i;
-}
-
-int _stlink_usb_version(stlink_t *sl) {
- struct stlink_libusb * const slu = sl->backend_data;
- unsigned char* const data = sl->q_buf;
- unsigned char* const cmd = sl->c_buf;
- ssize_t size;
- uint32_t rep_len = 6;
- int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
-
- cmd[i++] = STLINK_GET_VERSION;
-
- size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
- if (size == -1) {
- printf("[!] send_recv\n");
- return size;
- }
-
- return 0;
-}
-
-int32_t _stlink_usb_target_voltage(stlink_t *sl) {
- struct stlink_libusb * const slu = sl->backend_data;
- unsigned char* const rdata = sl->q_buf;
- unsigned char* const cmd = sl->c_buf;
- ssize_t size;
- uint32_t rep_len = 8;
- int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
- uint32_t factor, reading;
- int voltage;
-
- cmd[i++] = STLINK_GET_TARGET_VOLTAGE;
-
- size = send_recv(slu, 1, cmd, slu->cmd_len, rdata, rep_len);
- if (size == -1) {
- printf("[!] send_recv\n");
- return -1;
- } else if (size != 8) {
- printf("[!] wrong length\n");
- return -1;
- }
-
- factor = (rdata[3] << 24) | (rdata[2] << 16) | (rdata[1] << 8) | (rdata[0] << 0);
- reading = (rdata[7] << 24) | (rdata[6] << 16) | (rdata[5] << 8) | (rdata[4] << 0);
- voltage = 2400 * reading / factor;
-
- return voltage;
-}
-
-int _stlink_usb_read_debug32(stlink_t *sl, uint32_t addr, uint32_t *data) {
- struct stlink_libusb * const slu = sl->backend_data;
- unsigned char* const rdata = sl->q_buf;
- unsigned char* const cmd = sl->c_buf;
- ssize_t size;
- const int rep_len = 8;
-
- int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
- cmd[i++] = STLINK_DEBUG_COMMAND;
- cmd[i++] = STLINK_JTAG_READDEBUG_32BIT;
- write_uint32(&cmd[i], addr);
- size = send_recv(slu, 1, cmd, slu->cmd_len, rdata, rep_len);
- if (size == -1) {
- printf("[!] send_recv\n");
- return size;
- }
- *data = read_uint32(rdata, 4);
- return 0;
-}
-
-int _stlink_usb_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data) {
- struct stlink_libusb * const slu = sl->backend_data;
- unsigned char* const rdata = sl->q_buf;
- unsigned char* const cmd = sl->c_buf;
- ssize_t size;
- const int rep_len = 2;
-
- int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
- cmd[i++] = STLINK_DEBUG_COMMAND;
- cmd[i++] = STLINK_JTAG_WRITEDEBUG_32BIT;
- write_uint32(&cmd[i], addr);
- write_uint32(&cmd[i + 4], data);
- size = send_recv(slu, 1, cmd, slu->cmd_len, rdata, rep_len);
- if (size == -1) {
- printf("[!] send_recv\n");
- return size;
- }
-
- return 0;
-}
-
-int _stlink_usb_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
- struct stlink_libusb * const slu = sl->backend_data;
- unsigned char* const data = sl->q_buf;
- unsigned char* const cmd = sl->c_buf;
- int i, ret;
-
- i = fill_command(sl, SG_DXFER_TO_DEV, len);
- cmd[i++] = STLINK_DEBUG_COMMAND;
- cmd[i++] = STLINK_DEBUG_WRITEMEM_32BIT;
- write_uint32(&cmd[i], addr);
- write_uint16(&cmd[i + 4], len);
- ret = send_only(slu, 0, cmd, slu->cmd_len);
- if (ret == -1)
- return ret;
-
- ret = send_only(slu, 1, data, len);
- if (ret == -1)
- return ret;
-
- return 0;
-}
-
-int _stlink_usb_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len) {
- struct stlink_libusb * const slu = sl->backend_data;
- unsigned char* const data = sl->q_buf;
- unsigned char* const cmd = sl->c_buf;
- int i, ret;
-
- 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);
- if (ret == -1)
- return ret;
-
- ret = send_only(slu, 1, data, len);
- if (ret == -1)
- return ret;
-
- return 0;
-}
-
-
-int _stlink_usb_current_mode(stlink_t * sl) {
- struct stlink_libusb * const slu = sl->backend_data;
- unsigned char* const cmd = sl->c_buf;
- unsigned char* const data = sl->q_buf;
- ssize_t size;
- int rep_len = 2;
- int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
-
- cmd[i++] = STLINK_GET_CURRENT_MODE;
- size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
- if (size == -1) {
- printf("[!] send_recv\n");
- return -1;
- }
- return sl->q_buf[0];
-}
-
-int _stlink_usb_core_id(stlink_t * sl) {
- struct stlink_libusb * const slu = sl->backend_data;
- unsigned char* const cmd = sl->c_buf;
- unsigned char* const data = sl->q_buf;
- ssize_t size;
- int rep_len = 4;
- int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
-
- cmd[i++] = STLINK_DEBUG_COMMAND;
- cmd[i++] = STLINK_DEBUG_READCOREID;
-
- size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
- if (size == -1) {
- printf("[!] send_recv\n");
- return -1;
- }
-
- sl->core_id = read_uint32(data, 0);
- return 0;
-}
-
-int _stlink_usb_status(stlink_t * sl) {
- struct stlink_libusb * const slu = sl->backend_data;
- unsigned char* const data = sl->q_buf;
- unsigned char* const cmd = sl->c_buf;
- ssize_t size;
- int rep_len = 2;
- int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
-
- cmd[i++] = STLINK_DEBUG_COMMAND;
- cmd[i++] = STLINK_DEBUG_GETSTATUS;
-
- size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
- if (size == -1) {
- printf("[!] send_recv\n");
- return size;
- }
- sl->q_len = (size_t) size;
-
- return 0;
-}
-
-int _stlink_usb_force_debug(stlink_t *sl) {
- struct stlink_libusb *slu = sl->backend_data;
- unsigned char* const data = sl->q_buf;
- unsigned char* const cmd = sl->c_buf;
- ssize_t size;
- int rep_len = 2;
- int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
-
- cmd[i++] = STLINK_DEBUG_COMMAND;
- cmd[i++] = STLINK_DEBUG_FORCEDEBUG;
- size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
- if (size == -1) {
- printf("[!] send_recv\n");
- return size;
- }
-
- return 0;
-}
-
-int _stlink_usb_enter_swd_mode(stlink_t * sl) {
- struct stlink_libusb * const slu = sl->backend_data;
- unsigned char* const cmd = sl->c_buf;
- ssize_t size;
- const int rep_len = 0;
- int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
-
- cmd[i++] = STLINK_DEBUG_COMMAND;
- cmd[i++] = STLINK_DEBUG_ENTER;
- cmd[i++] = STLINK_DEBUG_ENTER_SWD;
-
- size = send_only(slu, 1, cmd, slu->cmd_len);
- if (size == -1) {
- printf("[!] send_recv\n");
- return size;
- }
-
- return 0;
-}
-
-int _stlink_usb_exit_dfu_mode(stlink_t* sl) {
- struct stlink_libusb * const slu = sl->backend_data;
- unsigned char* const cmd = sl->c_buf;
- ssize_t size;
- int i = fill_command(sl, SG_DXFER_FROM_DEV, 0);
-
- cmd[i++] = STLINK_DFU_COMMAND;
- cmd[i++] = STLINK_DFU_EXIT;
-
- size = send_only(slu, 1, cmd, slu->cmd_len);
- if (size == -1) {
- printf("[!] send_recv\n");
- return size;
- }
-
- return 0;
-}
-
-/**
- * TODO - not convinced this does anything...
- * @param sl
- */
-int _stlink_usb_reset(stlink_t * sl) {
- struct stlink_libusb * const slu = sl->backend_data;
- unsigned char* const data = sl->q_buf;
- unsigned char* const cmd = sl->c_buf;
- ssize_t size;
- int rep_len = 2;
- int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
-
- cmd[i++] = STLINK_DEBUG_COMMAND;
- cmd[i++] = STLINK_DEBUG_RESETSYS;
-
- size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
- if (size == -1) {
- printf("[!] send_recv\n");
- return size;
- }
-
- return 0;
-}
-
-
-int _stlink_usb_jtag_reset(stlink_t * sl, int value) {
- struct stlink_libusb * const slu = sl->backend_data;
- unsigned char* const data = sl->q_buf;
- unsigned char* const cmd = sl->c_buf;
- ssize_t size;
- int rep_len = 2;
- int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
-
- cmd[i++] = STLINK_DEBUG_COMMAND;
- cmd[i++] = STLINK_JTAG_DRIVE_NRST;
- cmd[i++] = value;
-
- size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
- if (size == -1) {
- printf("[!] send_recv\n");
- return size;
- }
-
- return 0;
-}
-
-
-int _stlink_usb_step(stlink_t* sl) {
- struct stlink_libusb * const slu = sl->backend_data;
- unsigned char* const data = sl->q_buf;
- unsigned char* const cmd = sl->c_buf;
- ssize_t size;
- int rep_len = 2;
- int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
-
- cmd[i++] = STLINK_DEBUG_COMMAND;
- cmd[i++] = STLINK_DEBUG_STEPCORE;
-
- size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
- if (size == -1) {
- printf("[!] send_recv\n");
- return size;
- }
-
- return 0;
-}
-
-/**
- * This seems to do a good job of restarting things from the beginning?
- * @param sl
- */
-int _stlink_usb_run(stlink_t* sl) {
- struct stlink_libusb * const slu = sl->backend_data;
- unsigned char* const data = sl->q_buf;
- unsigned char* const cmd = sl->c_buf;
- ssize_t size;
- int rep_len = 2;
- int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
-
- cmd[i++] = STLINK_DEBUG_COMMAND;
- cmd[i++] = STLINK_DEBUG_RUNCORE;
-
- size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
- if (size == -1) {
- printf("[!] send_recv\n");
- return size;
- }
-
- return 0;
-}
-
-int _stlink_usb_exit_debug_mode(stlink_t *sl) {
- struct stlink_libusb * const slu = sl->backend_data;
- unsigned char* const cmd = sl->c_buf;
- ssize_t size;
- int i = fill_command(sl, SG_DXFER_FROM_DEV, 0);
-
- cmd[i++] = STLINK_DEBUG_COMMAND;
- cmd[i++] = STLINK_DEBUG_EXIT;
-
- size = send_only(slu, 1, cmd, slu->cmd_len);
- if (size == -1) {
- printf("[!] send_only\n");
- return size;
- }
-
- return 0;
-}
-
-int _stlink_usb_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
- struct stlink_libusb * const slu = sl->backend_data;
- unsigned char* const data = sl->q_buf;
- unsigned char* const cmd = sl->c_buf;
- ssize_t size;
- int i = fill_command(sl, SG_DXFER_FROM_DEV, len);
-
- cmd[i++] = STLINK_DEBUG_COMMAND;
- cmd[i++] = STLINK_DEBUG_READMEM_32BIT;
- write_uint32(&cmd[i], addr);
- write_uint16(&cmd[i + 4], len);
-
- size = send_recv(slu, 1, cmd, slu->cmd_len, data, len);
- if (size == -1) {
- printf("[!] send_recv\n");
- return size;
- }
-
- sl->q_len = (size_t) size;
-
- stlink_print_data(sl);
- return 0;
-}
-
-int _stlink_usb_read_all_regs(stlink_t *sl, 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 = 84;
- int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
-
- cmd[i++] = STLINK_DEBUG_COMMAND;
- cmd[i++] = STLINK_DEBUG_READALLREGS;
- size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
- if (size == -1) {
- printf("[!] send_recv\n");
- return size;
- }
- sl->q_len = (size_t) size;
- stlink_print_data(sl);
- for(i=0; i<16; i++)
- regp->r[i]= read_uint32(sl->q_buf, i*4);
- 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", read_uint32(sl->q_buf, 64));
- DLOG("main_sp = 0x%08x\n", read_uint32(sl->q_buf, 68));
- DLOG("process_sp = 0x%08x\n", read_uint32(sl->q_buf, 72));
- DLOG("rw = 0x%08x\n", read_uint32(sl->q_buf, 76));
- DLOG("rw2 = 0x%08x\n", read_uint32(sl->q_buf, 80));
-
- return 0;
-}
-
-int _stlink_usb_read_reg(stlink_t *sl, int r_idx, 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 = 4;
- int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
-
- cmd[i++] = STLINK_DEBUG_COMMAND;
- cmd[i++] = STLINK_DEBUG_READREG;
- cmd[i++] = (uint8_t) r_idx;
- size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
- if (size == -1) {
- printf("[!] send_recv\n");
- return size;
- }
- sl->q_len = (size_t) size;
- stlink_print_data(sl);
- 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;
-}
-
-/* See section C1.6 of the ARMv7-M Architecture Reference Manual */
-int _stlink_usb_read_unsupported_reg(stlink_t *sl, int r_idx, reg *regp) {
- uint32_t r;
- int ret;
-
- sl->q_buf[0] = (unsigned char) r_idx;
- for (int i = 1; i < 4; i++) {
- sl->q_buf[i] = 0;
- }
-
- ret = _stlink_usb_write_mem32(sl, DCRSR, 4);
- if (ret == -1)
- return ret;
-
- _stlink_usb_read_mem32(sl, DCRDR, 4);
- if (ret == -1)
- return ret;
-
- r = read_uint32(sl->q_buf, 0);
- DLOG("r_idx (%2d) = 0x%08x\n", r_idx, r);
-
- switch (r_idx) {
- case 0x14:
- regp->primask = (uint8_t) (r & 0xFF);
- regp->basepri = (uint8_t) ((r>>8) & 0xFF);
- regp->faultmask = (uint8_t) ((r>>16) & 0xFF);
- regp->control = (uint8_t) ((r>>24) & 0xFF);
- break;
- case 0x21:
- regp->fpscr = r;
- break;
- default:
- regp->s[r_idx - 0x40] = r;
- break;
- }
-
- return 0;
-}
-
-int _stlink_usb_read_all_unsupported_regs(stlink_t *sl, reg *regp) {
- int ret;
-
- ret = _stlink_usb_read_unsupported_reg(sl, 0x14, regp);
- if (ret == -1)
- return ret;
-
- ret = _stlink_usb_read_unsupported_reg(sl, 0x21, regp);
- if (ret == -1)
- return ret;
-
- for (int i = 0; i < 32; i++) {
- ret = _stlink_usb_read_unsupported_reg(sl, 0x40+i, regp);
- if (ret == -1)
- return ret;
- }
-
- return 0;
-}
-
-/* See section C1.6 of the ARMv7-M Architecture Reference Manual */
-int _stlink_usb_write_unsupported_reg(stlink_t *sl, uint32_t val, int r_idx, reg *regp) {
- int ret;
-
- if (r_idx >= 0x1C && r_idx <= 0x1F) { /* primask, basepri, faultmask, or control */
- /* These are held in the same register */
- ret = _stlink_usb_read_unsupported_reg(sl, 0x14, regp);
- if (ret == -1)
- return ret;
-
- val = (uint8_t) (val>>24);
-
- switch (r_idx) {
- case 0x1C: /* control */
- val = (((uint32_t) val) << 24) | (((uint32_t) regp->faultmask) << 16) | (((uint32_t) regp->basepri) << 8) | ((uint32_t) regp->primask);
- break;
- case 0x1D: /* faultmask */
- val = (((uint32_t) regp->control) << 24) | (((uint32_t) val) << 16) | (((uint32_t) regp->basepri) << 8) | ((uint32_t) regp->primask);
- break;
- case 0x1E: /* basepri */
- val = (((uint32_t) regp->control) << 24) | (((uint32_t) regp->faultmask) << 16) | (((uint32_t) val) << 8) | ((uint32_t) regp->primask);
- break;
- case 0x1F: /* primask */
- val = (((uint32_t) regp->control) << 24) | (((uint32_t) regp->faultmask) << 16) | (((uint32_t) regp->basepri) << 8) | ((uint32_t) val);
- break;
- }
-
- r_idx = 0x14;
- }
-
- write_uint32(sl->q_buf, val);
-
- ret = _stlink_usb_write_mem32(sl, 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, DCRSR, 4);
-}
-
-int _stlink_usb_write_reg(stlink_t *sl, uint32_t reg, int idx) {
- struct stlink_libusb * const slu = sl->backend_data;
- unsigned char* const data = sl->q_buf;
- unsigned char* const cmd = sl->c_buf;
- ssize_t size;
- uint32_t rep_len = 2;
- int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
-
- cmd[i++] = STLINK_DEBUG_COMMAND;
- cmd[i++] = STLINK_DEBUG_WRITEREG;
- cmd[i++] = idx;
- write_uint32(&cmd[i], reg);
- size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
- if (size == -1) {
- printf("[!] send_recv\n");
- return size;
- }
- sl->q_len = (size_t) size;
- stlink_print_data(sl);
-
- return 0;
-}
-
-stlink_backend_t _stlink_usb_backend = {
- _stlink_usb_close,
- _stlink_usb_exit_debug_mode,
- _stlink_usb_enter_swd_mode,
- NULL, // no 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_t *stlink_open_usb(enum ugly_loglevel verbose, bool reset, char serial[16])
-{
- stlink_t* sl = NULL;
- struct stlink_libusb* slu = NULL;
- int ret = -1;
- int config;
-
- sl = calloc(1, sizeof (stlink_t));
- slu = calloc(1, sizeof (struct stlink_libusb));
- if (sl == NULL)
- goto on_malloc_error;
- if (slu == NULL)
- goto on_malloc_error;
-
- ugly_init(verbose);
- sl->backend = &_stlink_usb_backend;
- sl->backend_data = slu;
-
- sl->core_stat = STLINK_CORE_STAT_UNKNOWN;
- if (libusb_init(&(slu->libusb_ctx))) {
- WLOG("failed to init libusb context, wrong version of libraries?\n");
- goto on_error;
- }
-
- libusb_device **list;
- int cnt = libusb_get_device_list(slu->libusb_ctx, &list);
- struct libusb_device_descriptor desc;
- int devBus =0;
- int devAddr=0;
-
- /* @TODO: Reading a environment variable in a usb open function is not very nice, this
- should be refactored and moved into the CLI tools, and instead of giving USB_BUS:USB_ADDR a real stlink
- serial string should be passed to this function. Probably people are using this but this is very odd because
- as programmer can change to multiple busses and it is better to detect them based on serial. */
- char *device = getenv("STLINK_DEVICE");
- if (device) {
- char *c = strchr(device,':');
- if (c==NULL) {
- WLOG("STLINK_DEVICE must be <USB_BUS>:<USB_ADDR> format\n");
- goto on_error;
- }
- devBus=atoi(device);
- *c++=0;
- devAddr=atoi(c);
- ILOG("bus %03d dev %03d\n",devBus, devAddr);
- }
-
- while (cnt--) {
- libusb_get_device_descriptor( list[cnt], &desc );
- if (desc.idVendor != USB_ST_VID)
- continue;
-
- if (devBus && devAddr) {
- if ((libusb_get_bus_number(list[cnt]) != devBus)
- || (libusb_get_device_address(list[cnt]) != devAddr)) {
- continue;
- }
- }
-
- if ((desc.idProduct == USB_STLINK_32L_PID) || (desc.idProduct == USB_STLINK_NUCLEO_PID)) {
- struct libusb_device_handle *handle;
-
- libusb_open(list[cnt], &handle);
- sl->serial_size = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber,
- (unsigned char *)sl->serial, sizeof(sl->serial));
- libusb_close(handle);
-
- if ((serial == NULL) || (*serial == 0))
- break;
-
- if (sl->serial_size < 0)
- continue;
-
- if (memcmp(serial, &sl->serial, sl->serial_size) == 0)
- break;
-
- continue;
- }
-
- if (desc.idProduct == USB_STLINK_PID) {
- slu->protocoll = 1;
- break;
- }
- }
-
- if (cnt < 0) {
- WLOG ("Couldn't find %s ST-Link/V2 devices\n",(devBus && devAddr)?"matched":"any");
- goto on_error;
- } else {
- ret = libusb_open(list[cnt], &slu->usb_handle);
- if (ret != 0) {
- WLOG("Error %d (%s) opening ST-Link/V2 device %03d:%03d\n",
- ret, strerror (errno), libusb_get_bus_number(list[cnt]), libusb_get_device_address(list[cnt]));
- goto on_error;
- }
- }
-
- libusb_free_device_list(list, 1);
-
- 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;
- }
- }
-
- 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 techniq from stm8 code here...
- slu->ep_rep = 1 /* ep rep */ | LIBUSB_ENDPOINT_IN;
- if (desc.idProduct == USB_STLINK_NUCLEO_PID) {
- slu->ep_req = 1 /* ep req */ | LIBUSB_ENDPOINT_OUT;
- } else {
- slu->ep_req = 2 /* ep req */ | LIBUSB_ENDPOINT_OUT;
- }
-
- slu->sg_transfer_idx = 0;
- // TODO - never used at the moment, always CMD_SIZE
- slu->cmd_len = (slu->protocoll == 1)? STLINK_SG_SIZE: STLINK_CMD_SIZE;
-
- if (stlink_current_mode(sl) == STLINK_DEV_DFU_MODE) {
- ILOG("-- exit_dfu_mode\n");
- stlink_exit_dfu_mode(sl);
- }
-
- if (stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE) {
- stlink_enter_swd_mode(sl);
- }
-
- if (reset) {
- stlink_reset(sl);
- usleep(10000);
- }
-
- stlink_version(sl);
- ret = stlink_load_device_params(sl);
-
-on_libusb_error:
- if (ret == -1) {
- stlink_close(sl);
- return NULL;
- }
-
- return sl;
-
-on_error:
- if (slu->libusb_ctx)
- libusb_exit(slu->libusb_ctx);
-
-on_malloc_error:
- if (sl != NULL)
- free(sl);
- if (slu != NULL)
- free(slu);
-
- return NULL;
-}
-
-static size_t stlink_probe_usb_devs(libusb_device **devs, stlink_t **sldevs[]) {
- stlink_t **_sldevs;
- libusb_device *dev;
- int i = 0;
- int ret = 0;
- size_t slcnt = 0;
- size_t slcur = 0;
-
- /* Count stlink */
- while ((dev = devs[i++]) != NULL) {
- struct libusb_device_descriptor desc;
- int r = libusb_get_device_descriptor(dev, &desc);
- if (r < 0) {
- WLOG("failed to get libusb device descriptor\n");
- break;
- }
-
- if (desc.idProduct != USB_STLINK_32L_PID &&
- desc.idProduct != USB_STLINK_NUCLEO_PID)
- continue;
-
- slcnt++;
- }
-
- /* Allocate list of pointers */
- _sldevs = calloc(slcnt, sizeof(stlink_t *));
- if (!_sldevs) {
- *sldevs = NULL;
- return 0;
- }
-
- /* Open stlinks and attach to list */
- i = 0;
- while ((dev = devs[i++]) != NULL) {
- struct libusb_device_descriptor desc;
- ret = libusb_get_device_descriptor(dev, &desc);
- if (ret < 0) {
- WLOG("failed to get libusb device descriptor\n");
- break;
- }
-
- if (desc.idProduct != USB_STLINK_32L_PID &&
- desc.idProduct != USB_STLINK_NUCLEO_PID)
- continue;
-
- struct libusb_device_handle* handle;
- char serial[13];
- memset(serial, 0, sizeof(serial));
-
- ret = libusb_open(dev, &handle);
- if (ret < 0) {
- WLOG("failed to get libusb device descriptor\n");
- break;
- }
-
- ret = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, (unsigned char *)&serial, sizeof(serial));
- if (ret < 0)
- *serial = NULL;
-
- libusb_close(handle);
-
- stlink_t *sl = NULL;
- sl = stlink_open_usb(0, 1, serial);
- if (!sl)
- continue;
-
- _sldevs[slcur] = sl;
- slcur++;
- }
-
- /* Something went wrong */
- if (ret < 0) {
- free(_sldevs);
- *sldevs = NULL;
- return 0;
- }
-
- *sldevs = _sldevs;
- return slcnt;
-}
-
-size_t stlink_probe_usb(stlink_t **stdevs[]) {
- libusb_device **devs;
- stlink_t **sldevs;
-
- size_t slcnt = 0;
- int r;
- ssize_t cnt;
-
- r = libusb_init(NULL);
- if (r < 0)
- return 0;
-
- cnt = libusb_get_device_list(NULL, &devs);
- if (cnt < 0)
- return 0;
-
- slcnt = stlink_probe_usb_devs(devs, &sldevs);
- libusb_free_device_list(devs, 1);
-
- libusb_exit(NULL);
-
- *stdevs = sldevs;
- return slcnt;
-}
-
-void stlink_probe_usb_free(stlink_t ***stdevs, size_t size) {
- if (stdevs == NULL || *stdevs == NULL || size == 0)
- return;
-
- for (size_t n = 0; n < size; n++)
- stlink_close((*stdevs)[n]);
- free(*stdevs);
- *stdevs = NULL;
-}
+++ /dev/null
-/*
- * File: stlink-usb.h
- * Author: karl
- *
- * Created on October 1, 2011, 11:29 PM
- */
-
-#ifndef STLINK_USB_H
-#define STLINK_USB_H
-
-#include <stdbool.h>
-#include <libusb.h>
-
-#include "stlink-common.h"
-#include "uglylogging.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define STLINK_SG_SIZE 31
-#define STLINK_CMD_SIZE 16
-
- struct stlink_libusb {
- libusb_context* libusb_ctx;
- libusb_device_handle* usb_handle;
- unsigned int ep_req;
- unsigned int ep_rep;
- int protocoll;
- unsigned int sg_transfer_idx;
- unsigned int cmd_len;
- };
-
- /**
- * Open a stlink
- * @param verbose Verbosity loglevel
- * @param reset Reset stlink programmer
- * @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, bool reset, char serial[16]);
- size_t stlink_probe_usb(stlink_t **stdevs[]);
- void stlink_probe_usb_free(stlink_t **stdevs[], size_t size);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* STLINK_USB_H */
-
+++ /dev/null
-/*
- * File: test_main.c
- *
- * main() ripped out of old stlink-hw.c
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "stlink-common.h"
-#include "uglylogging.h"
-
-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
-}
-
-
-int main(int argc, char *argv[]) {
- /* Avoid unused parameter warning */
- (void)argv;
- // set scpi lib debug level: 0 for no debug info, 10 for lots
-
- switch (argc) {
- case 1:
- 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);
- return EXIT_FAILURE;
- default:
- break;
- }
-
- stlink_t *sl = stlink_v1_open(99, 1);
- if (sl == NULL)
- return EXIT_FAILURE;
-
- // 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);
- 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
- // happy new year 2011: 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 (int 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 1
- reg regs;
- stlink_read_all_regs(sl, ®s);
- stlink_step(sl);
- fputs("++++++++++ write r0 = 0x12345678\n", stderr);
- stlink_write_reg(sl, 0x12345678, 0);
- stlink_read_reg(sl, 0, ®s);
- stlink_read_all_regs(sl, ®s);
-#endif
-#if 0
- stlink_run(sl);
- 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 int 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);
- 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;
-}
+++ /dev/null
-#include <stdio.h>
-#include "stlink-common.h"
-
-
-int main(int ac, char** av) {
- stlink_t* sl;
- reg regs;
-
- /* unused */
- ac = ac;
- av = av;
-
- sl = stlink_open_usb(10, 1, NULL);
- 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;
- stlink_cpu_id(sl, &cpuid);
- 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 = 0x8000000;
- 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, CM3_REG_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);
- 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);
-
- printf("-- exit_debug_mode\n");
- stlink_exit_debug_mode(sl);
-
- stlink_close(sl);
- }
-
- return 0;
-}
--- /dev/null
+/* simple wrapper around the stlink_flash_write function */
+
+// TODO - this should be done as just a simple flag to the st-util command line...
+
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <stlink.h>
+
+#define DEBUG_LOG_LEVEL 100
+#define STND_LOG_LEVEL 50
+
+stlink_t *connected_stlink = NULL;
+
+static void cleanup(int signal __attribute__((unused))) {
+ if (connected_stlink) {
+ /* Switch back to mass storage mode before closing. */
+ stlink_run(connected_stlink);
+ stlink_exit_debug_mode(connected_stlink);
+ stlink_close(connected_stlink);
+ }
+
+ exit(1);
+}
+
+enum st_cmds {DO_WRITE = 0, DO_READ = 1, DO_ERASE = 2};
+struct opts
+{
+ enum st_cmds cmd;
+ const char* devname;
+ char *serial;
+ const char* filename;
+ stm32_addr_t addr;
+ size_t size;
+ int reset;
+ int log_level;
+};
+
+static void usage(void)
+{
+ puts("stlinkv1 command line: ./st-flash [--debug] [--reset] [--serial <iSerial>] {read|write} /dev/sgX path addr <size>");
+ puts("stlinkv1 command line: ./st-flash [--debug] /dev/sgX erase");
+ puts("stlinkv2 command line: ./st-flash [--debug] [--reset] [--serial <iSerial>] {read|write} path addr <size>");
+ puts("stlinkv2 command line: ./st-flash [--debug] [--serial <iSerial>] erase");
+ puts(" use hex format for addr, <iSerial> and <size>");
+}
+
+static int get_opts(struct opts* o, int ac, char** av)
+{
+ /* stlinkv1 command line: ./st-flash {read|write} /dev/sgX path addr <size> */
+ /* stlinkv2 command line: ./st-flash {read|write} path addr <size> */
+
+ unsigned int i = 0;
+
+ if (ac < 1) return -1;
+
+ if (strcmp(av[0], "--debug") == 0)
+ {
+ o->log_level = DEBUG_LOG_LEVEL;
+ ac--;
+ av++;
+ }
+ else
+ {
+ o->log_level = STND_LOG_LEVEL;
+ }
+
+ if (strcmp(av[0], "--reset") == 0)
+ {
+ o->reset = 1;
+ ac--;
+ av++;
+ }
+ else
+ {
+ o->reset = 0;
+ }
+
+ if (strcmp(av[0], "--serial") == 0)
+ {
+ ac--;
+ av++;
+ int i=strlen(av[0]);
+ if(i%2 != 0){
+ puts("no valid hex value, length must be multiple of 2\n");
+ return -1;
+ }
+ int j=0;
+ while(i>=0 && j<=13){
+ char buffer[3]={0};
+ memcpy(buffer,&av[0][i],2);
+ o->serial[12-j] = (char)strtol((const char*)buffer,NULL, 16);
+ j++;
+ i-=2;
+ }
+ ac--;
+ av++;
+ }
+ else
+ {
+ o->serial = NULL;
+ }
+
+ if (ac < 1) return -1;
+
+ /* stlinkv2 */
+ o->devname = NULL;
+
+ if (strcmp(av[0], "erase") == 0)
+ {
+ o->cmd = DO_ERASE;
+
+ /* stlinkv1 mode */
+ if (ac == 2)
+ {
+ o->devname = av[1];
+ i = 1;
+ }
+ }
+ else {
+ if (ac < 3) return -1;
+ if (strcmp(av[0], "read") == 0)
+ {
+ o->cmd = DO_READ;
+
+ /* stlinkv1 mode */
+ if (ac == 5)
+ {
+ o->devname = av[1];
+ i = 1;
+ }
+ if (ac > 3)
+ o->size = strtoul(av[i + 3], NULL, 16);
+ }
+ else if (strcmp(av[0], "write") == 0)
+ {
+ o->cmd = DO_WRITE;
+
+ /* stlinkv1 mode */
+ if (ac == 4)
+ {
+ o->devname = av[1];
+ i = 1;
+ }
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ o->filename = av[i + 1];
+ o->addr = strtoul(av[i + 2], NULL, 16);
+
+ return 0;
+}
+
+
+int main(int ac, char** av)
+{
+ stlink_t* sl = NULL;
+ struct opts o;
+ char serial_buffer[13] = {0};
+ o.serial = serial_buffer;
+ int err = -1;
+
+ o.size = 0;
+ if (get_opts(&o, ac - 1, av + 1) == -1)
+ {
+ printf("invalid command line\n");
+ usage();
+ return -1;
+ }
+
+ if (o.devname != NULL) /* stlinkv1 */
+ sl = stlink_v1_open(o.log_level, 1);
+ else /* stlinkv2 */
+ sl = stlink_open_usb(o.log_level, 1, o.serial);
+
+ if (sl == NULL)
+ return -1;
+
+ sl->verbose = o.log_level;
+
+ connected_stlink = sl;
+ signal(SIGINT, &cleanup);
+ signal(SIGTERM, &cleanup);
+ signal(SIGSEGV, &cleanup);
+
+ if (stlink_current_mode(sl) == STLINK_DEV_DFU_MODE) {
+ if (stlink_exit_dfu_mode(sl)) {
+ printf("Failed to exit DFU mode\n");
+ goto on_error;
+ }
+ }
+
+ if (stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE) {
+ if (stlink_enter_swd_mode(sl)) {
+ printf("Failed to enter SWD mode\n");
+ goto on_error;
+ }
+ }
+
+ if (o.reset){
+ if (stlink_jtag_reset(sl, 2)) {
+ printf("Failed to reset JTAG\n");
+ goto on_error;
+ }
+
+ if (stlink_reset(sl)) {
+ printf("Failed to reset device\n");
+ goto on_error;
+ }
+ }
+
+ // Disable DMA - Set All DMA CCR Registers to zero. - AKS 1/7/2013
+ if (sl->chip_id == STM32_CHIPID_F4)
+ {
+ memset(sl->q_buf,0,4);
+ for (int i=0;i<8;i++) {
+ stlink_write_mem32(sl,0x40026000+0x10+0x18*i,4);
+ stlink_write_mem32(sl,0x40026400+0x10+0x18*i,4);
+ stlink_write_mem32(sl,0x40026000+0x24+0x18*i,4);
+ stlink_write_mem32(sl,0x40026400+0x24+0x18*i,4);
+ }
+ }
+
+ // 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 == DO_WRITE) /* write */
+ {
+ if ((o.addr >= sl->flash_base) &&
+ (o.addr < sl->flash_base + sl->flash_size)) {
+ 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)) {
+ err = stlink_fwrite_sram(sl, o.filename, o.addr);
+ if (err == -1)
+ {
+ printf("stlink_fwrite_sram() == -1\n");
+ goto on_error;
+ }
+ }
+ } else if (o.cmd == DO_ERASE)
+ {
+ err = stlink_erase_flash_mass(sl);
+ if (err == -1)
+ {
+ printf("stlink_erase_flash_mass() == -1\n");
+ goto on_error;
+ }
+ }
+ else /* read */
+ {
+ if ((o.addr >= sl->flash_base) && (o.size == 0) &&
+ (o.addr < sl->flash_base + sl->flash_size))
+ o.size = sl->flash_size;
+ else if ((o.addr >= sl->sram_base) && (o.size == 0) &&
+ (o.addr < sl->sram_base + sl->sram_size))
+ o.size = sl->sram_size;
+ err = stlink_fread(sl, o.filename, o.addr, o.size);
+ if (err == -1)
+ {
+ printf("stlink_fread() == -1\n");
+ goto on_error;
+ }
+ }
+
+ if (o.reset){
+ stlink_jtag_reset(sl,2);
+ stlink_reset(sl);
+ }
+
+ /* success */
+ err = 0;
+
+on_error:
+ stlink_exit_debug_mode(sl);
+ stlink_close(sl);
+
+ return err;
+}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <stlink.h>
+
+static void usage(void)
+{
+ puts("st-info --flash");
+ puts("st-info --sram");
+ puts("st-info --descr");
+ puts("st-info --pagesize");
+ puts("st-info --chipid");
+ puts("st-info --serial");
+ puts("st-info --hla-serial");
+ puts("st-info --probe");
+}
+
+/* Print normal or OpenOCD hla_serial with newline */
+static void stlink_print_serial(stlink_t *sl, bool openocd)
+{
+ const char *fmt;
+
+ if (openocd) {
+ printf("\"");
+ fmt = "\\x%02x";
+ } else {
+ fmt = "%02x";
+ }
+
+ for (int n = 0; n < sl->serial_size; n++)
+ printf(fmt, sl->serial[n]);
+
+ if (openocd)
+ printf("\"");
+ printf("\n");
+}
+
+static void stlink_print_info(stlink_t *sl)
+{
+ const chip_params_t *params = NULL;
+
+ if (!sl)
+ return;
+
+ printf(" serial: ");
+ stlink_print_serial(sl, false);
+ printf("openocd: ");
+ stlink_print_serial(sl, true);
+
+ printf(" flash: %zu (pagesize: %zu)\n", sl->flash_size, sl->flash_pgsz);
+ printf(" sram: %zu\n", sl->sram_size);
+ printf(" chipid: 0x%.4x\n", sl->chip_id);
+
+ for (size_t i = 0; i < sizeof(devices) / sizeof(devices[0]); i++) {
+ if (devices[i].chip_id == sl->chip_id) {
+ params = &devices[i];
+ break;
+ }
+ }
+
+ if (params)
+ printf(" descr: %s\n", params->description);
+}
+
+static void stlink_probe(void)
+{
+ stlink_t **stdevs;
+ size_t size;
+
+ size = stlink_probe_usb(&stdevs);
+
+ printf("Found %zu stlink programmers\n", size);
+
+ for (size_t n = 0; n < size; n++)
+ stlink_print_info(stdevs[n]);
+
+ stlink_probe_usb_free(&stdevs, size);
+}
+
+static stlink_t *stlink_open_first(void)
+{
+ stlink_t* sl = NULL;
+ sl = stlink_v1_open(0, 1);
+ if (sl == NULL)
+ sl = stlink_open_usb(0, 1, NULL);
+
+ return sl;
+}
+
+static int print_data(char **av)
+{
+ stlink_t* sl = NULL;
+
+ // Probe needs all devices unclaimed
+ if (strcmp(av[1], "--probe") == 0) {
+ stlink_probe();
+ return 0;
+ }
+
+ sl = stlink_open_first();
+
+ if (sl == NULL) {
+ return -1;
+ }
+
+ sl->verbose = 0;
+
+ if (stlink_current_mode(sl) == STLINK_DEV_DFU_MODE)
+ stlink_exit_dfu_mode(sl);
+
+ if (stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE)
+ stlink_enter_swd_mode(sl);
+
+ if (strcmp(av[1], "--flash") == 0)
+ printf("0x%zx\n", sl->flash_size);
+ else if (strcmp(av[1], "--sram") == 0)
+ printf("0x%zx\n", sl->sram_size);
+ else if (strcmp(av[1], "--pagesize") == 0)
+ printf("0x%zx\n", sl->flash_pgsz);
+ else if (strcmp(av[1], "--chipid") == 0)
+ printf("0x%.4x\n", sl->chip_id);
+ else if (strcmp(av[1], "--serial") == 0)
+ stlink_print_serial(sl, false);
+ else if (strcmp(av[1], "--hla-serial") == 0)
+ stlink_print_serial(sl, true);
+ else if (strcmp(av[1], "--descr") == 0) {
+ const chip_params_t *params = NULL;
+ for (size_t i = 0; i < sizeof(devices) / sizeof(devices[0]); i++) {
+ if(devices[i].chip_id == sl->chip_id) {
+ params = &devices[i];
+ break;
+ }
+ }
+ if (params == NULL) {
+ return -1;
+ }
+ printf("%s\n", params->description);
+ }
+
+ if (sl)
+ {
+ stlink_exit_debug_mode(sl);
+ stlink_close(sl);
+ }
+
+ return 0;
+}
+
+int main(int ac, char** av)
+{
+ int err = -1;
+ if (ac < 2) {
+ usage();
+ return -1;
+ }
+
+ err = print_data(av);
+
+ return err;
+}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+/* According to POSIX.1-2001 */
+#include <sys/select.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#include <stlink.h>
+
+/* STLinky structure on STM chip
+
+struct stlinky {
+ uint32_t magic;
+ uint32_t bufsize;
+ uint32_t up_tail;
+ uint32_t up_head;
+ uint32_t dw_tail;
+ uint32_t dw_head;
+ char upbuf[CONFIG_LIB_STLINKY_BSIZE];
+ char dwbuf[CONFIG_LIB_STLINKY_BSIZE];
+} __attribute__ ((packed));
+*/
+
+
+#define STLINKY_MAGIC 0xDEADF00D
+
+#define ST_TERM_MAX_BUFF_SIZE (1024*1024) //1Mb
+
+#define RX_Q_OFFSET 8
+#define RX_BUFF_OFFSET 24
+#define TX_Q_OFFSET 16
+#define TX_BUFF_OFFSET(bufsize) (24 + bufsize)
+
+#define READ_UINT32_LE(buf) ((uint32_t) ( buf[0] \
+ | buf[1] << 8 \
+ | buf[2] << 16 \
+ | buf[3] << 24))
+
+static stlink_t* sl;
+sigset_t sig_mask;
+
+struct stlinky {
+ stlink_t *sl;
+ uint32_t off;
+ size_t bufsize;
+};
+
+void nonblock(int state);
+
+static void cleanup(int signal __attribute__((unused))) {
+ if (sl) {
+ /* Switch back to mass storage mode before closing. */
+ stlink_run(sl);
+ stlink_exit_debug_mode(sl);
+ stlink_close(sl);
+ }
+
+ printf("\n");
+ nonblock(0);
+ exit(1);
+}
+
+void sig_init() {
+ sigemptyset(&sig_mask);
+ sigaddset(&sig_mask, SIGINT);
+ sigaddset(&sig_mask, SIGTERM);
+ signal(SIGINT, &cleanup);
+ signal(SIGTERM, &cleanup);
+ sigprocmask(SIG_BLOCK, &sig_mask, NULL);
+}
+
+void sig_process() {
+ sigset_t pending;
+ sigpending(&pending);
+ if (sigismember(&pending, SIGINT) || sigismember(&pending, SIGTERM)) {
+ sigprocmask(SIG_UNBLOCK, &sig_mask, NULL);
+ sigsuspend(&pending);
+ sigprocmask(SIG_BLOCK, &sig_mask, NULL);
+ }
+}
+
+/* Detects stlinky in RAM, returns handler */
+struct stlinky* stlinky_detect(stlink_t* sl)
+{
+ static const uint32_t sram_base = 0x20000000;
+ struct stlinky* st = malloc(sizeof(struct stlinky));
+ int multiple=0;
+ st->sl = sl;
+ printf("sram: 0x%x bytes @ 0x%zx\n", sl->sram_base, sl->sram_size);
+ uint32_t off;
+ for (off = 0; off < sl->sram_size; off += 4) {
+ if (off % 1024 == 0) sig_process();
+ stlink_read_mem32(sl, sram_base + off, 4);
+ if (STLINKY_MAGIC == READ_UINT32_LE(sl->q_buf))
+ {
+ if (multiple > 0) printf("WARNING: another ");
+ printf("stlinky detected at 0x%x\n", sram_base + off);
+ st->off = sram_base + off;
+ stlink_read_mem32(sl, st->off + 4, 4);
+ st->bufsize = READ_UINT32_LE(sl->q_buf);
+ printf("stlinky buffer size 0x%zu \n", st->bufsize);
+ multiple++;
+ }
+ }
+ if (multiple > 0) {
+ if (multiple > 1) {
+ printf("Using last stlinky structure detected\n");
+ }
+ return st;
+ }
+ return NULL;
+}
+
+static void stlinky_read_buff(struct stlinky *st, uint32_t off, uint32_t size, char *buffer)
+{
+ int aligned_size;
+
+ if (size == 0)
+ return;
+
+ //Read from device with 4-byte alignment
+ aligned_size = (size & 0xFFFFFFFC) + 8;
+ stlink_read_mem32(st->sl, off & 0xFFFFFFFC, aligned_size);
+
+ //copy to local buffer
+ memcpy(buffer, st->sl->q_buf + (off & 0x3), size);
+
+ return;
+}
+
+static void stlinky_write_buf(struct stlinky *st, uint32_t off, uint32_t size, char *buffer)
+{
+ memcpy(st->sl->q_buf, buffer, size);
+ stlink_write_mem8(st->sl, off, size);
+ return;
+}
+
+size_t stlinky_rx(struct stlinky *st, char* buffer)
+{
+ //read head and tail values
+ uint32_t tail, head;
+ stlink_read_mem32(st->sl, st->off + RX_Q_OFFSET, sizeof(tail) + sizeof(head));
+ memcpy(&tail, &st->sl->q_buf[0], sizeof(tail));
+ memcpy(&head, &st->sl->q_buf[sizeof(tail)], sizeof(head));
+
+ //return if empty
+ if(head == tail)
+ return 0;
+
+ //read data
+ int size_read = 0;
+ if(head > tail){
+ stlinky_read_buff(st, st->off + RX_BUFF_OFFSET + tail, head - tail, buffer);
+ size_read += head - tail;
+ } else if(head < tail){
+ stlinky_read_buff(st, st->off + RX_BUFF_OFFSET + tail, st->bufsize - tail, buffer);
+ size_read += st->bufsize - tail;
+
+ stlinky_read_buff(st, st->off + RX_BUFF_OFFSET, head, buffer + size_read);
+ size_read += head;
+ }
+
+ //move tail
+ tail = (tail + size_read) % st->bufsize;
+
+ //write tail
+ memcpy(st->sl->q_buf, &tail, sizeof(tail));
+ stlink_write_mem32(st->sl, st->off + RX_Q_OFFSET, sizeof(tail));
+
+ return size_read;
+}
+
+size_t stlinky_tx(struct stlinky *st, char* buffer, size_t siz)
+{
+ //read head and tail values
+ uint32_t tail, head;
+ stlink_read_mem32(st->sl, st->off + TX_Q_OFFSET, sizeof(tail) + sizeof(head));
+ memcpy(&tail, &st->sl->q_buf[0], sizeof(tail));
+ memcpy(&head, &st->sl->q_buf[sizeof(tail)], sizeof(head));
+
+ //Figure out buffer usage
+ int usage = head - tail;
+ if (usage < 0)
+ usage += st->bufsize;
+
+ //check if new data will fit
+ if (usage + siz >= st->bufsize)
+ return 0;
+
+ //copy in data (take care of possible split)
+ int first_chunk = head + siz >= st->bufsize ? st->bufsize - head : siz;
+ int second_chunk = siz - first_chunk;
+
+ //copy data
+ stlinky_write_buf(st, st->off + TX_BUFF_OFFSET(st->bufsize) + head, first_chunk, buffer);
+ if (second_chunk > 0)
+ stlinky_write_buf(st, st->off + TX_BUFF_OFFSET(st->bufsize),
+ second_chunk, buffer + first_chunk);
+
+ //increment head pointer
+ head = (head + siz) % st->bufsize;
+ memcpy(st->sl->q_buf, &head, sizeof(head));
+ stlink_write_mem32(st->sl, st->off + TX_Q_OFFSET + sizeof(tail), sizeof(head));
+
+ return siz;
+}
+
+int kbhit()
+{
+ struct timeval tv;
+ fd_set fds;
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ FD_ZERO(&fds);
+ FD_SET(STDIN_FILENO, &fds); //STDIN_FILENO is 0
+ select(STDIN_FILENO+1, &fds, NULL, NULL, &tv);
+ return FD_ISSET(STDIN_FILENO, &fds);
+}
+
+void nonblock(int state)
+{
+ struct termios ttystate;
+
+ //get the terminal state
+ tcgetattr(STDIN_FILENO, &ttystate);
+
+ if (state==1)
+ {
+ //turn off canonical mode
+ ttystate.c_lflag &= ~ICANON;
+ ttystate.c_lflag &= ~ECHO;
+ //minimum of number input read.
+ ttystate.c_cc[VMIN] = 1;
+ }
+ else if (state==0)
+ {
+ //turn on canonical mode
+ ttystate.c_lflag |= ICANON | ECHO;
+ }
+ //set the terminal attributes.
+ tcsetattr(STDIN_FILENO, TCSANOW, &ttystate);
+
+}
+
+int main(int ac, char** av) {
+ struct stlinky *st=NULL;
+
+ sig_init();
+
+ sl = stlink_open_usb(10, 1, NULL);
+ if (sl != NULL) {
+ printf("ST-Linky proof-of-concept terminal :: Created by Necromant for lulz\n");
+ stlink_version(sl);
+ stlink_enter_swd_mode(sl);
+ printf("chip id: %#x\n", sl->chip_id);
+ printf("core_id: %#x\n", sl->core_id);
+
+ cortex_m3_cpuid_t cpuid;
+ stlink_cpu_id(sl, &cpuid);
+ 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);
+
+ stlink_reset(sl);
+ stlink_force_debug(sl);
+ stlink_run(sl);
+ stlink_status(sl);
+
+ /* wait for device to boot */
+ /* TODO: Make timeout adjustable via command line */
+ sleep(1);
+
+ if(ac == 1){
+ st = stlinky_detect(sl);
+ }else if(ac == 2){
+ st = malloc(sizeof(struct stlinky));
+ st->sl = sl;
+ st->off = (int)strtol(av[1], NULL, 16);
+ printf("using stlinky at 0x%x\n", st->off);
+ stlink_read_mem32(sl, st->off + 4, 4);
+ st->bufsize = READ_UINT32_LE(sl->q_buf);
+ printf("stlinky buffer size 0x%zu \n", st->bufsize);
+ }else{
+ cleanup(0);
+ }
+ if (st == NULL)
+ {
+ printf("stlinky magic not found in sram :(\n");
+ cleanup(0);
+ }
+ if (st->bufsize > ST_TERM_MAX_BUFF_SIZE){
+ printf("stlinky buffer size too big\n");
+ cleanup(0);
+ }
+ char* rxbuf = malloc(st->bufsize);
+ char* txbuf = malloc(st->bufsize);
+ size_t tmp;
+ nonblock(1);
+ int fd = fileno(stdin);
+ int saved_flags = fcntl(fd, F_GETFL);
+ fcntl(fd, F_SETFL, saved_flags & ~O_NONBLOCK);
+ printf("Entering interactive terminal. CTRL+C to exit\n\n\n");
+ while(1) {
+ sig_process();
+ tmp = stlinky_rx(st, rxbuf);
+ if(tmp > 0)
+ {
+ fwrite(rxbuf,tmp,1,stdout);
+ fflush(stdout);
+ }
+ if (kbhit()) {
+ tmp = read(fd, txbuf, st->bufsize);
+ stlinky_tx(st,txbuf,tmp);
+ }
+ }
+ }
+ return 0;
+}
+++ /dev/null
-/*
- * UglyLogging. Slow, yet another wheel reinvented, but enough to make the
- * rest of our code pretty enough.
- *
- */
-
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <time.h>
-
-#include "uglylogging.h"
-
-static int max_level;
-
-int ugly_init(int maximum_threshold) {
- max_level = maximum_threshold;
- return 0;
-}
-
-int ugly_log(int level, const char *tag, const char *format, ...) {
- if (level > max_level) {
- return 0;
- }
- va_list args;
- va_start(args, format);
- time_t mytt = time(NULL);
- struct tm *tt;
- tt = localtime(&mytt);
- fprintf(stderr, "%d-%02d-%02dT%02d:%02d:%02d ", tt->tm_year + 1900, tt->tm_mon + 1, tt->tm_mday, tt->tm_hour, tt->tm_min, tt->tm_sec);
- 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;
- case UFATAL:
- fprintf(stderr, "FATAL %s: ", tag);
- vfprintf(stderr, format, args);
- exit(EXIT_FAILURE);
- // NEVER GETS HERE!!!
- break;
- default:
- fprintf(stderr, "%d %s: ", level, tag);
- break;
- }
- vfprintf(stderr, format, args);
- va_end(args);
- return 1;
-}
+++ /dev/null
-/*
- * Ugly, low performance, configurable level, logging "framework"
- */
-
-#ifndef UGLYLOGGING_H
-#define UGLYLOGGING_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-enum ugly_loglevel {
- UDEBUG = 90,
- UINFO = 50,
- UWARN = 30,
- UERROR = 20,
- UFATAL = 10
-};
-
-int ugly_init(int maximum_threshold);
-int ugly_log(int level, const char *tag, const char *format, ...);
-
-#define DLOG(format, args...) ugly_log(UDEBUG, __FILE__, format, ## args)
-#define ILOG(format, args...) ugly_log(UINFO, __FILE__, format, ## args)
-#define WLOG(format, args...) ugly_log(UWARN, __FILE__, format, ## args)
-#define ELOG(format, args...) ugly_log(UERROR, __FILE__, format, ## args)
-#define fatal(format, args...) ugly_log(UFATAL, __FILE__, format, ## args)
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* UGLYLOGGING_H */
-
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <libusb.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "stlink.h"
+
+enum SCSI_Generic_Direction {SG_DXFER_TO_DEV=0, SG_DXFER_FROM_DEV=0x80};
+
+void _stlink_usb_close(stlink_t* sl) {
+ if (!sl)
+ return;
+
+ struct stlink_libusb * const handle = sl->backend_data;
+ // maybe we couldn't even get the usb device?
+ if (handle != NULL) {
+ if (handle->usb_handle != NULL) {
+ libusb_close(handle->usb_handle);
+ }
+
+ libusb_exit(handle->libusb_ctx);
+ free(handle);
+ }
+}
+
+ssize_t send_recv(struct stlink_libusb* handle, int terminate,
+ unsigned char* txbuf, size_t txsize,
+ unsigned char* rxbuf, size_t rxsize) {
+ /* note: txbuf and rxbuf can point to the same area */
+ int res = 0;
+
+ if (libusb_bulk_transfer(handle->usb_handle, handle->ep_req,
+ txbuf,
+ txsize,
+ &res,
+ 3000))
+ return -1;
+
+ if (rxsize != 0) {
+ if (libusb_bulk_transfer(handle->usb_handle, handle->ep_rep,
+ rxbuf,
+ rxsize,
+ &res,
+ 3000))
+ return -1;
+ }
+
+ if ((handle->protocoll == 1) && terminate) {
+ /* Read the SG reply */
+ unsigned char sg_buf[13];
+ if (libusb_bulk_transfer(handle->usb_handle, handle->ep_rep,
+ sg_buf,
+ 13,
+ &res,
+ 3000))
+ return -1;
+ /* The STLink doesn't seem to evaluate the sequence number */
+ handle->sg_transfer_idx++;
+ }
+
+ return res;
+}
+
+static inline int send_only
+(struct stlink_libusb* handle, int terminate,
+ unsigned char* txbuf, size_t txsize) {
+ return send_recv(handle, terminate, txbuf, txsize, NULL, 0);
+}
+
+
+static int fill_command
+(stlink_t * sl, enum SCSI_Generic_Direction dir, uint32_t len) {
+ struct stlink_libusb * const slu = sl->backend_data;
+ unsigned char* const cmd = sl->c_buf;
+ int i = 0;
+ memset(cmd, 0, sizeof (sl->c_buf));
+ if(slu->protocoll == 1) {
+ cmd[i++] = 'U';
+ cmd[i++] = 'S';
+ cmd[i++] = 'B';
+ cmd[i++] = 'C';
+ write_uint32(&cmd[i], slu->sg_transfer_idx);
+ write_uint32(&cmd[i + 4], len);
+ i += 8;
+ cmd[i++] = (dir == SG_DXFER_FROM_DEV)?0x80:0;
+ cmd[i++] = 0; /* Logical unit */
+ cmd[i++] = 0xa; /* Command length */
+ }
+ return i;
+}
+
+int _stlink_usb_version(stlink_t *sl) {
+ struct stlink_libusb * const slu = sl->backend_data;
+ unsigned char* const data = sl->q_buf;
+ unsigned char* const cmd = sl->c_buf;
+ ssize_t size;
+ uint32_t rep_len = 6;
+ int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
+
+ cmd[i++] = STLINK_GET_VERSION;
+
+ size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
+ if (size == -1) {
+ printf("[!] send_recv\n");
+ return size;
+ }
+
+ return 0;
+}
+
+int32_t _stlink_usb_target_voltage(stlink_t *sl) {
+ struct stlink_libusb * const slu = sl->backend_data;
+ unsigned char* const rdata = sl->q_buf;
+ unsigned char* const cmd = sl->c_buf;
+ ssize_t size;
+ uint32_t rep_len = 8;
+ int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
+ uint32_t factor, reading;
+ int voltage;
+
+ cmd[i++] = STLINK_GET_TARGET_VOLTAGE;
+
+ size = send_recv(slu, 1, cmd, slu->cmd_len, rdata, rep_len);
+ if (size == -1) {
+ printf("[!] send_recv\n");
+ return -1;
+ } else if (size != 8) {
+ printf("[!] wrong length\n");
+ return -1;
+ }
+
+ factor = (rdata[3] << 24) | (rdata[2] << 16) | (rdata[1] << 8) | (rdata[0] << 0);
+ reading = (rdata[7] << 24) | (rdata[6] << 16) | (rdata[5] << 8) | (rdata[4] << 0);
+ voltage = 2400 * reading / factor;
+
+ return voltage;
+}
+
+int _stlink_usb_read_debug32(stlink_t *sl, uint32_t addr, uint32_t *data) {
+ struct stlink_libusb * const slu = sl->backend_data;
+ unsigned char* const rdata = sl->q_buf;
+ unsigned char* const cmd = sl->c_buf;
+ ssize_t size;
+ const int rep_len = 8;
+
+ int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
+ cmd[i++] = STLINK_DEBUG_COMMAND;
+ cmd[i++] = STLINK_JTAG_READDEBUG_32BIT;
+ write_uint32(&cmd[i], addr);
+ size = send_recv(slu, 1, cmd, slu->cmd_len, rdata, rep_len);
+ if (size == -1) {
+ printf("[!] send_recv\n");
+ return size;
+ }
+ *data = read_uint32(rdata, 4);
+ return 0;
+}
+
+int _stlink_usb_write_debug32(stlink_t *sl, uint32_t addr, uint32_t data) {
+ struct stlink_libusb * const slu = sl->backend_data;
+ unsigned char* const rdata = sl->q_buf;
+ unsigned char* const cmd = sl->c_buf;
+ ssize_t size;
+ const int rep_len = 2;
+
+ int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
+ cmd[i++] = STLINK_DEBUG_COMMAND;
+ cmd[i++] = STLINK_JTAG_WRITEDEBUG_32BIT;
+ write_uint32(&cmd[i], addr);
+ write_uint32(&cmd[i + 4], data);
+ size = send_recv(slu, 1, cmd, slu->cmd_len, rdata, rep_len);
+ if (size == -1) {
+ printf("[!] send_recv\n");
+ return size;
+ }
+
+ return 0;
+}
+
+int _stlink_usb_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
+ struct stlink_libusb * const slu = sl->backend_data;
+ unsigned char* const data = sl->q_buf;
+ unsigned char* const cmd = sl->c_buf;
+ int i, ret;
+
+ i = fill_command(sl, SG_DXFER_TO_DEV, len);
+ cmd[i++] = STLINK_DEBUG_COMMAND;
+ cmd[i++] = STLINK_DEBUG_WRITEMEM_32BIT;
+ write_uint32(&cmd[i], addr);
+ write_uint16(&cmd[i + 4], len);
+ ret = send_only(slu, 0, cmd, slu->cmd_len);
+ if (ret == -1)
+ return ret;
+
+ ret = send_only(slu, 1, data, len);
+ if (ret == -1)
+ return ret;
+
+ return 0;
+}
+
+int _stlink_usb_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len) {
+ struct stlink_libusb * const slu = sl->backend_data;
+ unsigned char* const data = sl->q_buf;
+ unsigned char* const cmd = sl->c_buf;
+ int i, ret;
+
+ 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);
+ if (ret == -1)
+ return ret;
+
+ ret = send_only(slu, 1, data, len);
+ if (ret == -1)
+ return ret;
+
+ return 0;
+}
+
+
+int _stlink_usb_current_mode(stlink_t * sl) {
+ struct stlink_libusb * const slu = sl->backend_data;
+ unsigned char* const cmd = sl->c_buf;
+ unsigned char* const data = sl->q_buf;
+ ssize_t size;
+ int rep_len = 2;
+ int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
+
+ cmd[i++] = STLINK_GET_CURRENT_MODE;
+ size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
+ if (size == -1) {
+ printf("[!] send_recv\n");
+ return -1;
+ }
+ return sl->q_buf[0];
+}
+
+int _stlink_usb_core_id(stlink_t * sl) {
+ struct stlink_libusb * const slu = sl->backend_data;
+ unsigned char* const cmd = sl->c_buf;
+ unsigned char* const data = sl->q_buf;
+ ssize_t size;
+ int rep_len = 4;
+ int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
+
+ cmd[i++] = STLINK_DEBUG_COMMAND;
+ cmd[i++] = STLINK_DEBUG_READCOREID;
+
+ size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
+ if (size == -1) {
+ printf("[!] send_recv\n");
+ return -1;
+ }
+
+ sl->core_id = read_uint32(data, 0);
+ return 0;
+}
+
+int _stlink_usb_status(stlink_t * sl) {
+ struct stlink_libusb * const slu = sl->backend_data;
+ unsigned char* const data = sl->q_buf;
+ unsigned char* const cmd = sl->c_buf;
+ ssize_t size;
+ int rep_len = 2;
+ int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
+
+ cmd[i++] = STLINK_DEBUG_COMMAND;
+ cmd[i++] = STLINK_DEBUG_GETSTATUS;
+
+ size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
+ if (size == -1) {
+ printf("[!] send_recv\n");
+ return size;
+ }
+ sl->q_len = (size_t) size;
+
+ return 0;
+}
+
+int _stlink_usb_force_debug(stlink_t *sl) {
+ struct stlink_libusb *slu = sl->backend_data;
+ unsigned char* const data = sl->q_buf;
+ unsigned char* const cmd = sl->c_buf;
+ ssize_t size;
+ int rep_len = 2;
+ int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
+
+ cmd[i++] = STLINK_DEBUG_COMMAND;
+ cmd[i++] = STLINK_DEBUG_FORCEDEBUG;
+ size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
+ if (size == -1) {
+ printf("[!] send_recv\n");
+ return size;
+ }
+
+ return 0;
+}
+
+int _stlink_usb_enter_swd_mode(stlink_t * sl) {
+ struct stlink_libusb * const slu = sl->backend_data;
+ unsigned char* const cmd = sl->c_buf;
+ ssize_t size;
+ const int rep_len = 0;
+ int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
+
+ cmd[i++] = STLINK_DEBUG_COMMAND;
+ cmd[i++] = STLINK_DEBUG_ENTER;
+ cmd[i++] = STLINK_DEBUG_ENTER_SWD;
+
+ size = send_only(slu, 1, cmd, slu->cmd_len);
+ if (size == -1) {
+ printf("[!] send_recv\n");
+ return size;
+ }
+
+ return 0;
+}
+
+int _stlink_usb_exit_dfu_mode(stlink_t* sl) {
+ struct stlink_libusb * const slu = sl->backend_data;
+ unsigned char* const cmd = sl->c_buf;
+ ssize_t size;
+ int i = fill_command(sl, SG_DXFER_FROM_DEV, 0);
+
+ cmd[i++] = STLINK_DFU_COMMAND;
+ cmd[i++] = STLINK_DFU_EXIT;
+
+ size = send_only(slu, 1, cmd, slu->cmd_len);
+ if (size == -1) {
+ printf("[!] send_recv\n");
+ return size;
+ }
+
+ return 0;
+}
+
+/**
+ * TODO - not convinced this does anything...
+ * @param sl
+ */
+int _stlink_usb_reset(stlink_t * sl) {
+ struct stlink_libusb * const slu = sl->backend_data;
+ unsigned char* const data = sl->q_buf;
+ unsigned char* const cmd = sl->c_buf;
+ ssize_t size;
+ int rep_len = 2;
+ int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
+
+ cmd[i++] = STLINK_DEBUG_COMMAND;
+ cmd[i++] = STLINK_DEBUG_RESETSYS;
+
+ size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
+ if (size == -1) {
+ printf("[!] send_recv\n");
+ return size;
+ }
+
+ return 0;
+}
+
+
+int _stlink_usb_jtag_reset(stlink_t * sl, int value) {
+ struct stlink_libusb * const slu = sl->backend_data;
+ unsigned char* const data = sl->q_buf;
+ unsigned char* const cmd = sl->c_buf;
+ ssize_t size;
+ int rep_len = 2;
+ int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
+
+ cmd[i++] = STLINK_DEBUG_COMMAND;
+ cmd[i++] = STLINK_JTAG_DRIVE_NRST;
+ cmd[i++] = value;
+
+ size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
+ if (size == -1) {
+ printf("[!] send_recv\n");
+ return size;
+ }
+
+ return 0;
+}
+
+
+int _stlink_usb_step(stlink_t* sl) {
+ struct stlink_libusb * const slu = sl->backend_data;
+ unsigned char* const data = sl->q_buf;
+ unsigned char* const cmd = sl->c_buf;
+ ssize_t size;
+ int rep_len = 2;
+ int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
+
+ cmd[i++] = STLINK_DEBUG_COMMAND;
+ cmd[i++] = STLINK_DEBUG_STEPCORE;
+
+ size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
+ if (size == -1) {
+ printf("[!] send_recv\n");
+ return size;
+ }
+
+ return 0;
+}
+
+/**
+ * This seems to do a good job of restarting things from the beginning?
+ * @param sl
+ */
+int _stlink_usb_run(stlink_t* sl) {
+ struct stlink_libusb * const slu = sl->backend_data;
+ unsigned char* const data = sl->q_buf;
+ unsigned char* const cmd = sl->c_buf;
+ ssize_t size;
+ int rep_len = 2;
+ int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
+
+ cmd[i++] = STLINK_DEBUG_COMMAND;
+ cmd[i++] = STLINK_DEBUG_RUNCORE;
+
+ size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
+ if (size == -1) {
+ printf("[!] send_recv\n");
+ return size;
+ }
+
+ return 0;
+}
+
+int _stlink_usb_exit_debug_mode(stlink_t *sl) {
+ struct stlink_libusb * const slu = sl->backend_data;
+ unsigned char* const cmd = sl->c_buf;
+ ssize_t size;
+ int i = fill_command(sl, SG_DXFER_FROM_DEV, 0);
+
+ cmd[i++] = STLINK_DEBUG_COMMAND;
+ cmd[i++] = STLINK_DEBUG_EXIT;
+
+ size = send_only(slu, 1, cmd, slu->cmd_len);
+ if (size == -1) {
+ printf("[!] send_only\n");
+ return size;
+ }
+
+ return 0;
+}
+
+int _stlink_usb_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
+ struct stlink_libusb * const slu = sl->backend_data;
+ unsigned char* const data = sl->q_buf;
+ unsigned char* const cmd = sl->c_buf;
+ ssize_t size;
+ int i = fill_command(sl, SG_DXFER_FROM_DEV, len);
+
+ cmd[i++] = STLINK_DEBUG_COMMAND;
+ cmd[i++] = STLINK_DEBUG_READMEM_32BIT;
+ write_uint32(&cmd[i], addr);
+ write_uint16(&cmd[i + 4], len);
+
+ size = send_recv(slu, 1, cmd, slu->cmd_len, data, len);
+ if (size == -1) {
+ printf("[!] send_recv\n");
+ return size;
+ }
+
+ sl->q_len = (size_t) size;
+
+ stlink_print_data(sl);
+ return 0;
+}
+
+int _stlink_usb_read_all_regs(stlink_t *sl, 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 = 84;
+ int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
+
+ cmd[i++] = STLINK_DEBUG_COMMAND;
+ cmd[i++] = STLINK_DEBUG_READALLREGS;
+ size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
+ if (size == -1) {
+ printf("[!] send_recv\n");
+ return size;
+ }
+ sl->q_len = (size_t) size;
+ stlink_print_data(sl);
+ for(i=0; i<16; i++)
+ regp->r[i]= read_uint32(sl->q_buf, i*4);
+ 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", read_uint32(sl->q_buf, 64));
+ DLOG("main_sp = 0x%08x\n", read_uint32(sl->q_buf, 68));
+ DLOG("process_sp = 0x%08x\n", read_uint32(sl->q_buf, 72));
+ DLOG("rw = 0x%08x\n", read_uint32(sl->q_buf, 76));
+ DLOG("rw2 = 0x%08x\n", read_uint32(sl->q_buf, 80));
+
+ return 0;
+}
+
+int _stlink_usb_read_reg(stlink_t *sl, int r_idx, 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 = 4;
+ int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
+
+ cmd[i++] = STLINK_DEBUG_COMMAND;
+ cmd[i++] = STLINK_DEBUG_READREG;
+ cmd[i++] = (uint8_t) r_idx;
+ size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
+ if (size == -1) {
+ printf("[!] send_recv\n");
+ return size;
+ }
+ sl->q_len = (size_t) size;
+ stlink_print_data(sl);
+ 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;
+}
+
+/* See section C1.6 of the ARMv7-M Architecture Reference Manual */
+int _stlink_usb_read_unsupported_reg(stlink_t *sl, int r_idx, reg *regp) {
+ uint32_t r;
+ int ret;
+
+ sl->q_buf[0] = (unsigned char) r_idx;
+ for (int i = 1; i < 4; i++) {
+ sl->q_buf[i] = 0;
+ }
+
+ ret = _stlink_usb_write_mem32(sl, DCRSR, 4);
+ if (ret == -1)
+ return ret;
+
+ _stlink_usb_read_mem32(sl, DCRDR, 4);
+ if (ret == -1)
+ return ret;
+
+ r = read_uint32(sl->q_buf, 0);
+ DLOG("r_idx (%2d) = 0x%08x\n", r_idx, r);
+
+ switch (r_idx) {
+ case 0x14:
+ regp->primask = (uint8_t) (r & 0xFF);
+ regp->basepri = (uint8_t) ((r>>8) & 0xFF);
+ regp->faultmask = (uint8_t) ((r>>16) & 0xFF);
+ regp->control = (uint8_t) ((r>>24) & 0xFF);
+ break;
+ case 0x21:
+ regp->fpscr = r;
+ break;
+ default:
+ regp->s[r_idx - 0x40] = r;
+ break;
+ }
+
+ return 0;
+}
+
+int _stlink_usb_read_all_unsupported_regs(stlink_t *sl, reg *regp) {
+ int ret;
+
+ ret = _stlink_usb_read_unsupported_reg(sl, 0x14, regp);
+ if (ret == -1)
+ return ret;
+
+ ret = _stlink_usb_read_unsupported_reg(sl, 0x21, regp);
+ if (ret == -1)
+ return ret;
+
+ for (int i = 0; i < 32; i++) {
+ ret = _stlink_usb_read_unsupported_reg(sl, 0x40+i, regp);
+ if (ret == -1)
+ return ret;
+ }
+
+ return 0;
+}
+
+/* See section C1.6 of the ARMv7-M Architecture Reference Manual */
+int _stlink_usb_write_unsupported_reg(stlink_t *sl, uint32_t val, int r_idx, reg *regp) {
+ int ret;
+
+ if (r_idx >= 0x1C && r_idx <= 0x1F) { /* primask, basepri, faultmask, or control */
+ /* These are held in the same register */
+ ret = _stlink_usb_read_unsupported_reg(sl, 0x14, regp);
+ if (ret == -1)
+ return ret;
+
+ val = (uint8_t) (val>>24);
+
+ switch (r_idx) {
+ case 0x1C: /* control */
+ val = (((uint32_t) val) << 24) | (((uint32_t) regp->faultmask) << 16) | (((uint32_t) regp->basepri) << 8) | ((uint32_t) regp->primask);
+ break;
+ case 0x1D: /* faultmask */
+ val = (((uint32_t) regp->control) << 24) | (((uint32_t) val) << 16) | (((uint32_t) regp->basepri) << 8) | ((uint32_t) regp->primask);
+ break;
+ case 0x1E: /* basepri */
+ val = (((uint32_t) regp->control) << 24) | (((uint32_t) regp->faultmask) << 16) | (((uint32_t) val) << 8) | ((uint32_t) regp->primask);
+ break;
+ case 0x1F: /* primask */
+ val = (((uint32_t) regp->control) << 24) | (((uint32_t) regp->faultmask) << 16) | (((uint32_t) regp->basepri) << 8) | ((uint32_t) val);
+ break;
+ }
+
+ r_idx = 0x14;
+ }
+
+ write_uint32(sl->q_buf, val);
+
+ ret = _stlink_usb_write_mem32(sl, 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, DCRSR, 4);
+}
+
+int _stlink_usb_write_reg(stlink_t *sl, uint32_t reg, int idx) {
+ struct stlink_libusb * const slu = sl->backend_data;
+ unsigned char* const data = sl->q_buf;
+ unsigned char* const cmd = sl->c_buf;
+ ssize_t size;
+ uint32_t rep_len = 2;
+ int i = fill_command(sl, SG_DXFER_FROM_DEV, rep_len);
+
+ cmd[i++] = STLINK_DEBUG_COMMAND;
+ cmd[i++] = STLINK_DEBUG_WRITEREG;
+ cmd[i++] = idx;
+ write_uint32(&cmd[i], reg);
+ size = send_recv(slu, 1, cmd, slu->cmd_len, data, rep_len);
+ if (size == -1) {
+ printf("[!] send_recv\n");
+ return size;
+ }
+ sl->q_len = (size_t) size;
+ stlink_print_data(sl);
+
+ return 0;
+}
+
+stlink_backend_t _stlink_usb_backend = {
+ _stlink_usb_close,
+ _stlink_usb_exit_debug_mode,
+ _stlink_usb_enter_swd_mode,
+ NULL, // no 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_t *stlink_open_usb(enum ugly_loglevel verbose, bool reset, char serial[16])
+{
+ stlink_t* sl = NULL;
+ struct stlink_libusb* slu = NULL;
+ int ret = -1;
+ int config;
+
+ sl = calloc(1, sizeof (stlink_t));
+ slu = calloc(1, sizeof (struct stlink_libusb));
+ if (sl == NULL)
+ goto on_malloc_error;
+ if (slu == NULL)
+ goto on_malloc_error;
+
+ ugly_init(verbose);
+ sl->backend = &_stlink_usb_backend;
+ sl->backend_data = slu;
+
+ sl->core_stat = STLINK_CORE_STAT_UNKNOWN;
+ if (libusb_init(&(slu->libusb_ctx))) {
+ WLOG("failed to init libusb context, wrong version of libraries?\n");
+ goto on_error;
+ }
+
+ libusb_device **list;
+ int cnt = libusb_get_device_list(slu->libusb_ctx, &list);
+ struct libusb_device_descriptor desc;
+ int devBus =0;
+ int devAddr=0;
+
+ /* @TODO: Reading a environment variable in a usb open function is not very nice, this
+ should be refactored and moved into the CLI tools, and instead of giving USB_BUS:USB_ADDR a real stlink
+ serial string should be passed to this function. Probably people are using this but this is very odd because
+ as programmer can change to multiple busses and it is better to detect them based on serial. */
+ char *device = getenv("STLINK_DEVICE");
+ if (device) {
+ char *c = strchr(device,':');
+ if (c==NULL) {
+ WLOG("STLINK_DEVICE must be <USB_BUS>:<USB_ADDR> format\n");
+ goto on_error;
+ }
+ devBus=atoi(device);
+ *c++=0;
+ devAddr=atoi(c);
+ ILOG("bus %03d dev %03d\n",devBus, devAddr);
+ }
+
+ while (cnt--) {
+ libusb_get_device_descriptor( list[cnt], &desc );
+ if (desc.idVendor != USB_ST_VID)
+ continue;
+
+ if (devBus && devAddr) {
+ if ((libusb_get_bus_number(list[cnt]) != devBus)
+ || (libusb_get_device_address(list[cnt]) != devAddr)) {
+ continue;
+ }
+ }
+
+ if ((desc.idProduct == USB_STLINK_32L_PID) || (desc.idProduct == USB_STLINK_NUCLEO_PID)) {
+ struct libusb_device_handle *handle;
+
+ libusb_open(list[cnt], &handle);
+ sl->serial_size = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber,
+ (unsigned char *)sl->serial, sizeof(sl->serial));
+ libusb_close(handle);
+
+ if ((serial == NULL) || (*serial == 0))
+ break;
+
+ if (sl->serial_size < 0)
+ continue;
+
+ if (memcmp(serial, &sl->serial, sl->serial_size) == 0)
+ break;
+
+ continue;
+ }
+
+ if (desc.idProduct == USB_STLINK_PID) {
+ slu->protocoll = 1;
+ break;
+ }
+ }
+
+ if (cnt < 0) {
+ WLOG ("Couldn't find %s ST-Link/V2 devices\n",(devBus && devAddr)?"matched":"any");
+ goto on_error;
+ } else {
+ ret = libusb_open(list[cnt], &slu->usb_handle);
+ if (ret != 0) {
+ WLOG("Error %d (%s) opening ST-Link/V2 device %03d:%03d\n",
+ ret, strerror (errno), libusb_get_bus_number(list[cnt]), libusb_get_device_address(list[cnt]));
+ goto on_error;
+ }
+ }
+
+ libusb_free_device_list(list, 1);
+
+ 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;
+ }
+ }
+
+ 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 techniq from stm8 code here...
+ slu->ep_rep = 1 /* ep rep */ | LIBUSB_ENDPOINT_IN;
+ if (desc.idProduct == USB_STLINK_NUCLEO_PID) {
+ slu->ep_req = 1 /* ep req */ | LIBUSB_ENDPOINT_OUT;
+ } else {
+ slu->ep_req = 2 /* ep req */ | LIBUSB_ENDPOINT_OUT;
+ }
+
+ slu->sg_transfer_idx = 0;
+ // TODO - never used at the moment, always CMD_SIZE
+ slu->cmd_len = (slu->protocoll == 1)? STLINK_SG_SIZE: STLINK_CMD_SIZE;
+
+ if (stlink_current_mode(sl) == STLINK_DEV_DFU_MODE) {
+ ILOG("-- exit_dfu_mode\n");
+ stlink_exit_dfu_mode(sl);
+ }
+
+ if (stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE) {
+ stlink_enter_swd_mode(sl);
+ }
+
+ if (reset) {
+ stlink_reset(sl);
+ usleep(10000);
+ }
+
+ stlink_version(sl);
+ ret = stlink_load_device_params(sl);
+
+on_libusb_error:
+ if (ret == -1) {
+ stlink_close(sl);
+ return NULL;
+ }
+
+ return sl;
+
+on_error:
+ if (slu->libusb_ctx)
+ libusb_exit(slu->libusb_ctx);
+
+on_malloc_error:
+ if (sl != NULL)
+ free(sl);
+ if (slu != NULL)
+ free(slu);
+
+ return NULL;
+}
+
+static size_t stlink_probe_usb_devs(libusb_device **devs, stlink_t **sldevs[]) {
+ stlink_t **_sldevs;
+ libusb_device *dev;
+ int i = 0;
+ int ret = 0;
+ size_t slcnt = 0;
+ size_t slcur = 0;
+
+ /* Count stlink */
+ while ((dev = devs[i++]) != NULL) {
+ struct libusb_device_descriptor desc;
+ int r = libusb_get_device_descriptor(dev, &desc);
+ if (r < 0) {
+ WLOG("failed to get libusb device descriptor\n");
+ break;
+ }
+
+ if (desc.idProduct != USB_STLINK_32L_PID &&
+ desc.idProduct != USB_STLINK_NUCLEO_PID)
+ continue;
+
+ slcnt++;
+ }
+
+ /* Allocate list of pointers */
+ _sldevs = calloc(slcnt, sizeof(stlink_t *));
+ if (!_sldevs) {
+ *sldevs = NULL;
+ return 0;
+ }
+
+ /* Open stlinks and attach to list */
+ i = 0;
+ while ((dev = devs[i++]) != NULL) {
+ struct libusb_device_descriptor desc;
+ ret = libusb_get_device_descriptor(dev, &desc);
+ if (ret < 0) {
+ WLOG("failed to get libusb device descriptor\n");
+ break;
+ }
+
+ if (desc.idProduct != USB_STLINK_32L_PID &&
+ desc.idProduct != USB_STLINK_NUCLEO_PID)
+ continue;
+
+ struct libusb_device_handle* handle;
+ char serial[13];
+ memset(serial, 0, sizeof(serial));
+
+ ret = libusb_open(dev, &handle);
+ if (ret < 0) {
+ WLOG("failed to get libusb device descriptor\n");
+ break;
+ }
+
+ ret = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, (unsigned char *)&serial, sizeof(serial));
+ if (ret < 0)
+ *serial = NULL;
+
+ libusb_close(handle);
+
+ stlink_t *sl = NULL;
+ sl = stlink_open_usb(0, 1, serial);
+ if (!sl)
+ continue;
+
+ _sldevs[slcur] = sl;
+ slcur++;
+ }
+
+ /* Something went wrong */
+ if (ret < 0) {
+ free(_sldevs);
+ *sldevs = NULL;
+ return 0;
+ }
+
+ *sldevs = _sldevs;
+ return slcnt;
+}
+
+size_t stlink_probe_usb(stlink_t **stdevs[]) {
+ libusb_device **devs;
+ stlink_t **sldevs;
+
+ size_t slcnt = 0;
+ int r;
+ ssize_t cnt;
+
+ r = libusb_init(NULL);
+ if (r < 0)
+ return 0;
+
+ cnt = libusb_get_device_list(NULL, &devs);
+ if (cnt < 0)
+ return 0;
+
+ slcnt = stlink_probe_usb_devs(devs, &sldevs);
+ libusb_free_device_list(devs, 1);
+
+ libusb_exit(NULL);
+
+ *stdevs = sldevs;
+ return slcnt;
+}
+
+void stlink_probe_usb_free(stlink_t ***stdevs, size_t size) {
+ if (stdevs == NULL || *stdevs == NULL || size == 0)
+ return;
+
+ for (size_t n = 0; n < size; n++)
+ stlink_close((*stdevs)[n]);
+ free(*stdevs);
+ *stdevs = NULL;
+}
+++ /dev/null
-options usb-storage quirks=483:3744:i
--- /dev/null
+/*
+ * File: test_main.c
+ *
+ * main() ripped out of old stlink-hw.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "stlink-common.h"
+#include "uglylogging.h"
+
+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
+}
+
+
+int main(int argc, char *argv[]) {
+ /* Avoid unused parameter warning */
+ (void)argv;
+ // set scpi lib debug level: 0 for no debug info, 10 for lots
+
+ switch (argc) {
+ case 1:
+ 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);
+ return EXIT_FAILURE;
+ default:
+ break;
+ }
+
+ stlink_t *sl = stlink_v1_open(99, 1);
+ if (sl == NULL)
+ return EXIT_FAILURE;
+
+ // 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);
+ 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
+ // happy new year 2011: 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 (int 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 1
+ reg regs;
+ stlink_read_all_regs(sl, ®s);
+ stlink_step(sl);
+ fputs("++++++++++ write r0 = 0x12345678\n", stderr);
+ stlink_write_reg(sl, 0x12345678, 0);
+ stlink_read_reg(sl, 0, ®s);
+ stlink_read_all_regs(sl, ®s);
+#endif
+#if 0
+ stlink_run(sl);
+ 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 int 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);
+ 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;
+}
--- /dev/null
+#include <stdio.h>
+#include "stlink-common.h"
+
+
+int main(int ac, char** av) {
+ stlink_t* sl;
+ reg regs;
+
+ /* unused */
+ ac = ac;
+ av = av;
+
+ sl = stlink_open_usb(10, 1, NULL);
+ 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;
+ stlink_cpu_id(sl, &cpuid);
+ 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 = 0x8000000;
+ 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, CM3_REG_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);
+ 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);
+
+ printf("-- exit_debug_mode\n");
+ stlink_exit_debug_mode(sl);
+
+ stlink_close(sl);
+ }
+
+ return 0;
+}