Reorganize files:
authorJerry Jacobs <jerry.jacobs@xor-gate.org>
Thu, 5 May 2016 12:46:42 +0000 (14:46 +0200)
committerJerry Jacobs <jerry.jacobs@xor-gate.org>
Thu, 5 May 2016 17:30:32 +0000 (19:30 +0200)
* Header files moved into include/stlink
* doc/tutorial.{pdf/tex} converted to markdown for rendering by github and easy editing
* Remove `stlink-` suffix from some C source files and move into `src/tools`

61 files changed:
49-stlinkv1.rules [deleted file]
49-stlinkv2-1.rules [deleted file]
49-stlinkv2.rules [deleted file]
CMakeLists.txt
Makefile.am
README.md [deleted symlink]
TODO [deleted file]
TODO.md [new file with mode: 0644]
configure.ac
doc/tutorial.md [new file with mode: 0644]
doc/tutorial/tutorial.pdf [deleted file]
doc/tutorial/tutorial.tex [deleted file]
etc/modprobe.d/stlink_v1.conf [new file with mode: 0644]
etc/udev/rules.d/49-stlinkv1.rules [new file with mode: 0644]
etc/udev/rules.d/49-stlinkv2-1.rules [new file with mode: 0644]
etc/udev/rules.d/49-stlinkv2.rules [new file with mode: 0644]
flash/Makefile [deleted file]
flash/main.c [deleted file]
gdbserver/Makefile [deleted file]
gdbserver/gdb-remote.c [deleted file]
gdbserver/gdb-remote.h [deleted file]
gdbserver/gdb-server.c [deleted file]
gdbserver/gdb-server.h [deleted file]
include/stlink.h [new file with mode: 0644]
include/stlink/logging.h [new file with mode: 0644]
include/stlink/mmap.h [new file with mode: 0644]
include/stlink/sg.h [new file with mode: 0644]
include/stlink/usb.h [new file with mode: 0644]
mingw/mingw.c [deleted file]
mingw/mingw.h [deleted file]
src/common.c [new file with mode: 0644]
src/gdbserver/Makefile [new file with mode: 0644]
src/gdbserver/gdb-remote.c [new file with mode: 0644]
src/gdbserver/gdb-remote.h [new file with mode: 0644]
src/gdbserver/gdb-server.c [new file with mode: 0644]
src/gdbserver/gdb-server.h [new file with mode: 0644]
src/logging.c [new file with mode: 0644]
src/mingw/mingw.c [new file with mode: 0644]
src/mingw/mingw.h [new file with mode: 0644]
src/mmap.c
src/mmap.h [deleted file]
src/sg.c [new file with mode: 0644]
src/st-info.c [deleted file]
src/st-term.c [deleted file]
src/stlink-common.c [deleted file]
src/stlink-common.h [deleted file]
src/stlink-sg.c [deleted file]
src/stlink-sg.h [deleted file]
src/stlink-usb.c [deleted file]
src/stlink-usb.h [deleted file]
src/test_sg.c [deleted file]
src/test_usb.c [deleted file]
src/tools/flash.c [new file with mode: 0644]
src/tools/info.c [new file with mode: 0644]
src/tools/term.c [new file with mode: 0644]
src/uglylogging.c [deleted file]
src/uglylogging.h [deleted file]
src/usb.c [new file with mode: 0644]
stlink_v1.modprobe.conf [deleted file]
tests/stlink_sg.c [new file with mode: 0644]
tests/stlink_usb.c [new file with mode: 0644]

diff --git a/49-stlinkv1.rules b/49-stlinkv1.rules
deleted file mode 100644 (file)
index d474d6a..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-# 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.
diff --git a/49-stlinkv2-1.rules b/49-stlinkv2-1.rules
deleted file mode 100644 (file)
index a5a79b9..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-# 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.
diff --git a/49-stlinkv2.rules b/49-stlinkv2.rules
deleted file mode 100644 (file)
index a11215c..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-# 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.
index d26f03c8ffe7f490164d74c4e40937ea02069637..f75ce611db9ac5aede84b3f3ddf200c9775f59a3 100644 (file)
@@ -47,37 +47,38 @@ elseif()
     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
@@ -86,8 +87,8 @@ 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
index 9afbc0f0b0b06c4a18a8f391e22ba3b71138a33c..fc95184bc738b636bf0e9285ae6d6c603bf7f83a 100644 (file)
@@ -12,43 +12,43 @@ endif
 
 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
diff --git a/README.md b/README.md
deleted file mode 120000 (symlink)
index 100b938..0000000
--- a/README.md
+++ /dev/null
@@ -1 +0,0 @@
-README
\ No newline at end of file
diff --git a/TODO b/TODO
deleted file mode 100644 (file)
index 2b0baf6..0000000
--- a/TODO
+++ /dev/null
@@ -1,11 +0,0 @@
-. 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 ;
diff --git a/TODO.md b/TODO.md
new file mode 100644 (file)
index 0000000..9c5059a
--- /dev/null
+++ b/TODO.md
@@ -0,0 +1,11 @@
+# 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)
index 203cc6bd59e507698b85d97bcd811dcc63653eda..f374717401835065314c9445c2fde5ca6ac5b2cb 100644 (file)
@@ -3,7 +3,7 @@
 
 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])
 
diff --git a/doc/tutorial.md b/doc/tutorial.md
new file mode 100644 (file)
index 0000000..937e2da
--- /dev/null
@@ -0,0 +1,190 @@
+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.
diff --git a/doc/tutorial/tutorial.pdf b/doc/tutorial/tutorial.pdf
deleted file mode 100644 (file)
index b73396c..0000000
Binary files a/doc/tutorial/tutorial.pdf and /dev/null differ
diff --git a/doc/tutorial/tutorial.tex b/doc/tutorial/tutorial.tex
deleted file mode 100644 (file)
index 5860ca8..0000000
+++ /dev/null
@@ -1,234 +0,0 @@
-\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}
diff --git a/etc/modprobe.d/stlink_v1.conf b/etc/modprobe.d/stlink_v1.conf
new file mode 100644 (file)
index 0000000..94b3786
--- /dev/null
@@ -0,0 +1 @@
+options usb-storage quirks=483:3744:i
diff --git a/etc/udev/rules.d/49-stlinkv1.rules b/etc/udev/rules.d/49-stlinkv1.rules
new file mode 100644 (file)
index 0000000..d474d6a
--- /dev/null
@@ -0,0 +1,11 @@
+# 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.
diff --git a/etc/udev/rules.d/49-stlinkv2-1.rules b/etc/udev/rules.d/49-stlinkv2-1.rules
new file mode 100644 (file)
index 0000000..a5a79b9
--- /dev/null
@@ -0,0 +1,12 @@
+# 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.
diff --git a/etc/udev/rules.d/49-stlinkv2.rules b/etc/udev/rules.d/49-stlinkv2.rules
new file mode 100644 (file)
index 0000000..a11215c
--- /dev/null
@@ -0,0 +1,12 @@
+# 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.
diff --git a/flash/Makefile b/flash/Makefile
deleted file mode 100644 (file)
index 5345dcb..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-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
diff --git a/flash/main.c b/flash/main.c
deleted file mode 100644 (file)
index 0ba429c..0000000
+++ /dev/null
@@ -1,300 +0,0 @@
-/* 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;
-}
diff --git a/gdbserver/Makefile b/gdbserver/Makefile
deleted file mode 100644 (file)
index bd5c73d..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-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
diff --git a/gdbserver/gdb-remote.c b/gdbserver/gdb-remote.c
deleted file mode 100644 (file)
index 2f61b93..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * 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;
-}
-
diff --git a/gdbserver/gdb-remote.h b/gdbserver/gdb-remote.h
deleted file mode 100644 (file)
index bfa0104..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#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
diff --git a/gdbserver/gdb-server.c b/gdbserver/gdb-server.c
deleted file mode 100644 (file)
index eca6597..0000000
+++ /dev/null
@@ -1,1555 +0,0 @@
-/*
- * 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, ":;", &params);
-
-                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, &regp);
-
-                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, &regp);
-                    myreg = htonl(regp.r[id]);
-                } else if(id == 0x19) {
-                    stlink_read_reg(sl, 16, &regp);
-                    myreg = htonl(regp.xpsr);
-                } else if(id == 0x1A) {
-                    stlink_read_reg(sl, 17, &regp);
-                    myreg = htonl(regp.main_sp);
-                } else if(id == 0x1B) {
-                    stlink_read_reg(sl, 18, &regp);
-                    myreg = htonl(regp.process_sp);
-                } else if(id == 0x1C) {
-                    stlink_read_unsupported_reg(sl, id, &regp);
-                    myreg = htonl(regp.control);
-                } else if(id == 0x1D) {
-                    stlink_read_unsupported_reg(sl, id, &regp);
-                    myreg = htonl(regp.faultmask);
-                } else if(id == 0x1E) {
-                    stlink_read_unsupported_reg(sl, id, &regp);
-                    myreg = htonl(regp.basepri);
-                } else if(id == 0x1F) {
-                    stlink_read_unsupported_reg(sl, id, &regp);
-                    myreg = htonl(regp.primask);
-                } else if(id >= 0x20 && id < 0x40) {
-                    stlink_read_unsupported_reg(sl, id, &regp);
-                    myreg = htonl(regp.s[id-0x20]);
-                } else if(id == 0x40) {
-                    stlink_read_unsupported_reg(sl, id, &regp);
-                    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, &regp);
-                } else if(reg == 0x1D) {
-                    stlink_write_unsupported_reg(sl, ntohl(value), reg, &regp);
-                } else if(reg == 0x1E) {
-                    stlink_write_unsupported_reg(sl, ntohl(value), reg, &regp);
-                } else if(reg == 0x1F) {
-                    stlink_write_unsupported_reg(sl, ntohl(value), reg, &regp);
-                } else if(reg >= 0x20 && reg < 0x40) {
-                    stlink_write_unsupported_reg(sl, ntohl(value), reg, &regp);
-                } else if(reg == 0x40) {
-                    stlink_write_unsupported_reg(sl, ntohl(value), reg, &regp);
-                } 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;
-}
diff --git a/gdbserver/gdb-server.h b/gdbserver/gdb-server.h
deleted file mode 100644 (file)
index 8c8d471..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#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
diff --git a/include/stlink.h b/include/stlink.h
new file mode 100644 (file)
index 0000000..24b4dcf
--- /dev/null
@@ -0,0 +1,735 @@
+/*
+ * 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 */
diff --git a/include/stlink/logging.h b/include/stlink/logging.h
new file mode 100644 (file)
index 0000000..df816ca
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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 */
+
diff --git a/include/stlink/mmap.h b/include/stlink/mmap.h
new file mode 100644 (file)
index 0000000..71de819
--- /dev/null
@@ -0,0 +1,31 @@
+#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 */
diff --git a/include/stlink/sg.h b/include/stlink/sg.h
new file mode 100644 (file)
index 0000000..56780f4
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * 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 */
+
diff --git a/include/stlink/usb.h b/include/stlink/usb.h
new file mode 100644 (file)
index 0000000..76ac921
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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 */
+
diff --git a/mingw/mingw.c b/mingw/mingw.c
deleted file mode 100644 (file)
index 3c5d025..0000000
+++ /dev/null
@@ -1,270 +0,0 @@
-#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
-
-
diff --git a/mingw/mingw.h b/mingw/mingw.h
deleted file mode 100644 (file)
index cb33301..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-#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
diff --git a/src/common.c b/src/common.c
new file mode 100644 (file)
index 0000000..3e87824
--- /dev/null
@@ -0,0 +1,2131 @@
+#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;
+}
diff --git a/src/gdbserver/Makefile b/src/gdbserver/Makefile
new file mode 100644 (file)
index 0000000..bd5c73d
--- /dev/null
@@ -0,0 +1,20 @@
+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
diff --git a/src/gdbserver/gdb-remote.c b/src/gdbserver/gdb-remote.c
new file mode 100644 (file)
index 0000000..2f61b93
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * 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;
+}
+
diff --git a/src/gdbserver/gdb-remote.h b/src/gdbserver/gdb-remote.h
new file mode 100644 (file)
index 0000000..bfa0104
--- /dev/null
@@ -0,0 +1,8 @@
+#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
diff --git a/src/gdbserver/gdb-server.c b/src/gdbserver/gdb-server.c
new file mode 100644 (file)
index 0000000..666251c
--- /dev/null
@@ -0,0 +1,1555 @@
+/*
+ * 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, ":;", &params);
+
+                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, &regp);
+
+                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, &regp);
+                    myreg = htonl(regp.r[id]);
+                } else if(id == 0x19) {
+                    stlink_read_reg(sl, 16, &regp);
+                    myreg = htonl(regp.xpsr);
+                } else if(id == 0x1A) {
+                    stlink_read_reg(sl, 17, &regp);
+                    myreg = htonl(regp.main_sp);
+                } else if(id == 0x1B) {
+                    stlink_read_reg(sl, 18, &regp);
+                    myreg = htonl(regp.process_sp);
+                } else if(id == 0x1C) {
+                    stlink_read_unsupported_reg(sl, id, &regp);
+                    myreg = htonl(regp.control);
+                } else if(id == 0x1D) {
+                    stlink_read_unsupported_reg(sl, id, &regp);
+                    myreg = htonl(regp.faultmask);
+                } else if(id == 0x1E) {
+                    stlink_read_unsupported_reg(sl, id, &regp);
+                    myreg = htonl(regp.basepri);
+                } else if(id == 0x1F) {
+                    stlink_read_unsupported_reg(sl, id, &regp);
+                    myreg = htonl(regp.primask);
+                } else if(id >= 0x20 && id < 0x40) {
+                    stlink_read_unsupported_reg(sl, id, &regp);
+                    myreg = htonl(regp.s[id-0x20]);
+                } else if(id == 0x40) {
+                    stlink_read_unsupported_reg(sl, id, &regp);
+                    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, &regp);
+                } else if(reg == 0x1D) {
+                    stlink_write_unsupported_reg(sl, ntohl(value), reg, &regp);
+                } else if(reg == 0x1E) {
+                    stlink_write_unsupported_reg(sl, ntohl(value), reg, &regp);
+                } else if(reg == 0x1F) {
+                    stlink_write_unsupported_reg(sl, ntohl(value), reg, &regp);
+                } else if(reg >= 0x20 && reg < 0x40) {
+                    stlink_write_unsupported_reg(sl, ntohl(value), reg, &regp);
+                } else if(reg == 0x40) {
+                    stlink_write_unsupported_reg(sl, ntohl(value), reg, &regp);
+                } 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;
+}
diff --git a/src/gdbserver/gdb-server.h b/src/gdbserver/gdb-server.h
new file mode 100644 (file)
index 0000000..8c8d471
--- /dev/null
@@ -0,0 +1,11 @@
+#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
diff --git a/src/logging.c b/src/logging.c
new file mode 100644 (file)
index 0000000..4969c44
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * 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;
+}
diff --git a/src/mingw/mingw.c b/src/mingw/mingw.c
new file mode 100644 (file)
index 0000000..3c5d025
--- /dev/null
@@ -0,0 +1,270 @@
+#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
+
+
diff --git a/src/mingw/mingw.h b/src/mingw/mingw.h
new file mode 100644 (file)
index 0000000..cb33301
--- /dev/null
@@ -0,0 +1,70 @@
+#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
index c5794da9195748e6b2cccca1cbccbc097d52a94b..bee0dcecef8b79a1e8d50287d4a8612b2d4a78b1 100644 (file)
@@ -3,7 +3,7 @@
 #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) {
 
diff --git a/src/mmap.h b/src/mmap.h
deleted file mode 100644 (file)
index 71de819..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#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 */
diff --git a/src/sg.c b/src/sg.c
new file mode 100644 (file)
index 0000000..4057098
--- /dev/null
+++ b/src/sg.c
@@ -0,0 +1,1088 @@
+/*
+ * 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;
+}
diff --git a/src/st-info.c b/src/st-info.c
deleted file mode 100644 (file)
index 1671468..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-#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;
-}
diff --git a/src/st-term.c b/src/st-term.c
deleted file mode 100644 (file)
index 245ed59..0000000
+++ /dev/null
@@ -1,321 +0,0 @@
-#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;
-}
diff --git a/src/stlink-common.c b/src/stlink-common.c
deleted file mode 100644 (file)
index 18c76fb..0000000
+++ /dev/null
@@ -1,2131 +0,0 @@
-#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;
-}
diff --git a/src/stlink-common.h b/src/stlink-common.h
deleted file mode 100644 (file)
index e2f7b75..0000000
+++ /dev/null
@@ -1,742 +0,0 @@
-/*
- * 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 */
diff --git a/src/stlink-sg.c b/src/stlink-sg.c
deleted file mode 100644 (file)
index 03df7d8..0000000
+++ /dev/null
@@ -1,1089 +0,0 @@
-/*
- * 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;
-}
diff --git a/src/stlink-sg.h b/src/stlink-sg.h
deleted file mode 100644 (file)
index 7c02028..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * 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 */
-
diff --git a/src/stlink-usb.c b/src/stlink-usb.c
deleted file mode 100644 (file)
index 9865412..0000000
+++ /dev/null
@@ -1,1007 +0,0 @@
-#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;
-}
diff --git a/src/stlink-usb.h b/src/stlink-usb.h
deleted file mode 100644 (file)
index 747d54c..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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 */
-
diff --git a/src/test_sg.c b/src/test_sg.c
deleted file mode 100644 (file)
index db7eed3..0000000
+++ /dev/null
@@ -1,222 +0,0 @@
-/* 
- * 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, &regs);
-    stlink_step(sl);
-    fputs("++++++++++ write r0 = 0x12345678\n", stderr);
-    stlink_write_reg(sl, 0x12345678, 0);
-    stlink_read_reg(sl, 0, &regs);
-    stlink_read_all_regs(sl, &regs);
-#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;
-}
diff --git a/src/test_usb.c b/src/test_usb.c
deleted file mode 100644 (file)
index 787ac12..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-#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, &regs);
-
-
-        stlink_read_all_regs(sl, &regs);
-
-        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;
-}
diff --git a/src/tools/flash.c b/src/tools/flash.c
new file mode 100644 (file)
index 0000000..770289b
--- /dev/null
@@ -0,0 +1,301 @@
+/* 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;
+}
diff --git a/src/tools/info.c b/src/tools/info.c
new file mode 100644 (file)
index 0000000..e29184e
--- /dev/null
@@ -0,0 +1,162 @@
+#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;
+}
diff --git a/src/tools/term.c b/src/tools/term.c
new file mode 100644 (file)
index 0000000..9b46e2a
--- /dev/null
@@ -0,0 +1,322 @@
+#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;
+}
diff --git a/src/uglylogging.c b/src/uglylogging.c
deleted file mode 100644 (file)
index a04ab33..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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;
-}
diff --git a/src/uglylogging.h b/src/uglylogging.h
deleted file mode 100644 (file)
index df816ca..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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 */
-
diff --git a/src/usb.c b/src/usb.c
new file mode 100644 (file)
index 0000000..e8d8ec3
--- /dev/null
+++ b/src/usb.c
@@ -0,0 +1,1006 @@
+#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;
+}
diff --git a/stlink_v1.modprobe.conf b/stlink_v1.modprobe.conf
deleted file mode 100644 (file)
index 94b3786..0000000
+++ /dev/null
@@ -1 +0,0 @@
-options usb-storage quirks=483:3744:i
diff --git a/tests/stlink_sg.c b/tests/stlink_sg.c
new file mode 100644 (file)
index 0000000..db7eed3
--- /dev/null
@@ -0,0 +1,222 @@
+/* 
+ * 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, &regs);
+    stlink_step(sl);
+    fputs("++++++++++ write r0 = 0x12345678\n", stderr);
+    stlink_write_reg(sl, 0x12345678, 0);
+    stlink_read_reg(sl, 0, &regs);
+    stlink_read_all_regs(sl, &regs);
+#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;
+}
diff --git a/tests/stlink_usb.c b/tests/stlink_usb.c
new file mode 100644 (file)
index 0000000..787ac12
--- /dev/null
@@ -0,0 +1,102 @@
+#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, &regs);
+
+
+        stlink_read_all_regs(sl, &regs);
+
+        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;
+}