1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/dist/tools/openocd/openocd.sh
Gaëtan Harter 468e4084f2
tools/openocd.sh: probe the board for real flash address on binary flash
Some boards have a configuration of the flash bank with an address of 0
when it actually starts as 0x08000000 but openocd relies on probing
the hardware at runtime.

This now allows to first probe the board to get the actual value.
If probing fail for any reason, return the value from the configuration.
This can happen when the board is unreachable so at least give a valid
output instead of an error.

This will allow correct flash detection on for example the `stm32f3` and
`stm32l4` which have a configured address of 0.

4a6f93c961/tcl/target/stm32f3x.cfg (L64)
4a6f93c961/tcl/target/stm32l4x.cfg (L51)
2019-05-17 18:28:27 +02:00

394 lines
13 KiB
Bash
Executable File

#!/bin/bash
#
# Unified OpenOCD script for RIOT
#
# This script is supposed to be called from RIOTs make system,
# as it depends on certain environment variables. An OpenOCD
# configuration file must be present in a the boards dist folder.
#
# Any extra command line arguments after the command name are passed on the
# openocd command line after the configuration file name but before any other
# initialization commands.
#
# Global environment variables used:
# OPENOCD: OpenOCD command name, default: "openocd"
# OPENOCD_CONFIG: OpenOCD configuration file name,
# default: "${RIOTBOARD}/${BOARD}/dist/openocd.cfg"
#
# The script supports the following actions:
#
# flash: flash <image_file>
# flash given file to the target.
#
# options:
# <image_file>: Filename of the file that will be flashed
# PRE_FLASH_CHECK_SCRIPT: a command to run before flashing to
# verify the integrity of the image to be flashed. <image_file> is
# passed as a command line argument to this command.
#
# Flashing works with any file format recognized by OpenOCD
# (elf, ihex, s19, bin).
#
# debug: debug <elfile>
# starts OpenOCD as GDB server in the background and
# connects to the server with the GDB client specified by
# the board
#
# options:
# <elffile>: path to the file to debug, must be in a format
# recognized by GDB (preferably ELF, it will not
# work with .bin, .hex or .s19 because they lack
# symbol information)
# GDB_PORT: port opened for GDB connections
# TCL_PORT: port opened for TCL connections
# TELNET_PORT: port opened for telnet connections
# DBG: debugger client command, default: 'gdb -q'
# TUI: if TUI!=null, the -tui option will be used
#
# debug-server: starts OpenOCD as GDB server, but does not connect to
# to it with any frontend. This might be useful when using
# IDEs.
#
# options:
# GDB_PORT: port opened for GDB connections
# TCL_PORT: port opened for TCL connections
# TELNET_PORT: port opened for telnet connections
#
# reset: triggers a hardware reset of the target board
#
# @author Hauke Peteresen <hauke.petersen@fu-berlin.de>
# @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
# Default GDB port, set to 0 to disable, required != 0 for debug and debug-server targets
: ${GDB_PORT:=3333}
# Default telnet port, set to 0 to disable
: ${TELNET_PORT:=4444}
# Default TCL port, set to 0 to disable
: ${TCL_PORT:=6333}
# Default path to OpenOCD configuration file
: ${OPENOCD_CONFIG:=${RIOTBOARD}/${BOARD}/dist/openocd.cfg}
# Default OpenOCD command
: ${OPENOCD:=openocd}
# Extra board initialization commands to pass to OpenOCD
: ${OPENOCD_EXTRA_INIT:=}
# Debugger interface initialization commands to pass to OpenOCD
: ${OPENOCD_ADAPTER_INIT:=}
# The setsid command is needed so that Ctrl+C in GDB doesn't kill OpenOCD
: ${SETSID:=setsid}
# GDB command, usually a separate command for each platform (e.g. arm-none-eabi-gdb)
: ${GDB:=gdb}
# Debugger client command, can be used to wrap GDB in a front-end
: ${DBG:=${GDB}}
# Default debugger flags,
: ${DBG_DEFAULT_FLAGS:=-q -ex \"tar ext :${GDB_PORT}\"}
# Extra debugger flags, added by the user
: ${DBG_EXTRA_FLAGS:=}
# Debugger flags, will be passed to sh -c, remember to escape any quotation signs.
# Use ${DBG_DEFAULT_FLAGS} to insert the default flags anywhere in the string
: ${DBG_FLAGS:=${DBG_DEFAULT_FLAGS} ${DBG_EXTRA_FLAGS}}
# Initial target state when using debug, by default a 'halt' request is sent to
# the target when starting a debug session. 'reset halt' can also be used
# depending on the type of target.
: ${OPENOCD_DBG_START_CMD:=-c 'halt'}
# command used to reset the board
: ${OPENOCD_CMD_RESET_RUN:="-c 'reset run'"}
# This is an optional offset to the base address that can be used to flash an
# image in a different location than it is linked at. This feature can be useful
# when flashing images for firmware swapping/remapping boot loaders.
# Default offset is 0, meaning the image will be flashed at the address that it
# was linked at.
: ${IMAGE_OFFSET:=0}
# Type of image, leave empty to let OpenOCD automatically detect the type from
# the file (default).
# Valid values: elf, hex, s19, bin (see OpenOCD manual for more information)
: ${IMAGE_TYPE:=}
#
# Examples of alternative debugger configurations
#
# Using the GDB text UI:
# DBG_EXTRA_FLAGS=-tui make debug
# or to always use TUI, put in your .profile:
# export DBG_EXTRA_FLAGS=-tui
# Wrapping GDB inside DDD (https://www.gnu.org/software/ddd/)
# DBG=ddd DBG_FLAGS='--debugger "${GDB} ${DBG_DEFAULT_FLAGS}"' make debug
# Alternatively, to always use DDD, put the following in your .profile or similar:
# export DBG=ddd
# export DBG_FLAGS='--debugger "${GDB} ${DBG_DEFAULT_FLAGS}"'
# The single quotes are important on the line above, or it will not work.
#
# a couple of tests for certain configuration options
#
test_config() {
if [ ! -f "${OPENOCD_CONFIG}" ]; then
echo "Error: Unable to locate OpenOCD configuration file"
echo " (${OPENOCD_CONFIG})"
exit 1
fi
}
test_elffile() {
if [ ! -f "${ELFFILE}" ]; then
echo "Error: Unable to locate ELFFILE"
echo " (${ELFFILE})"
exit 1
fi
}
test_imagefile() {
if [ ! -f "${IMAGE_FILE}" ]; then
echo "Error: Unable to locate IMAGE_FILE"
echo " (${IMAGE_FILE})"
exit 1
fi
}
_has_bin_extension() {
# The regex need to be without quotes
local firmware=$1
[[ "${firmware}" =~ ^.*\.bin$ ]]
}
# Return 0 if given file should be considered a binary
_is_binfile() {
local firmware="$1"
local firmware_type="$2"
[[ "${firmware_type}" = "bin" ]] || { \
[[ -z "${firmware_type}" ]] && _has_bin_extension "${firmware}"; }
}
# Split bank info on different lines without the '{}'
_split_banks() {
# Input:
# ...
# {name nrf51 base 0 size 0 bus_width 1 chip_width 1} {name nrf51 base 268439552 size 0 bus_width 1 chip_width 1}
# ...
#
# Output:
# name nrf51 base 0 size 0 bus_width 1 chip_width 1
# name nrf51 base 268439552 size 0 bus_width 1 chip_width 1
# The following command needs specific osx handling (non gnu):
# * Same commands for a pattern should be on different lines
# * Cannot use '\n' in the replacement string
local sed_escaped_newline=\\$'\n'
sed -n '
/^{.*}$/ {
s/\} /\}'"${sed_escaped_newline}"'/g
s/[{}]//g
p
}'
}
_flash_list_raw() {
# Openocd output for 'flash list' is
# ....
# {name nrf51 base 0 size 0 bus_width 1 chip_width 1} {name nrf51 base 268439552 size 0 bus_width 1 chip_width 1}
# ....
#
# Before printing the flash list, try to init and probe the board
# to get the actual address.
# Some openocd configuration put an address of 0 and rely on probing to
# find the real flash address like 0x08000000
#
# If it does not work, fallback to only query the configured value
#
# Probing can fail when the board is in a non flashable state or
# maybe probing would need a different init procedure.
# At least, currently fallback to returning the configured value
# Probe the real value
sh -c "${OPENOCD} \
${OPENOCD_ADAPTER_INIT} \
-f '${OPENOCD_CONFIG}' \
-c 'init' \
-c 'flash probe 0' \
-c 'flash list' \
-c 'shutdown'" 2>&1 && return
# Fallback to return the value stored in openocd
echo "WARN: Failed to probe board flash." >&2
echo "WARN: Falling back to using the openocd configuration value." >&2
sh -c "${OPENOCD} \
${OPENOCD_ADAPTER_INIT} \
-f '${OPENOCD_CONFIG}' \
-c 'flash list' \
-c 'shutdown'" 2>&1
}
# Outputs bank info on different lines without the '{}'
_flash_list() {
# ....
# name nrf51 base 0 size 0 bus_width 1 chip_width 1
# name nrf51 base 268439552 size 0 bus_width 1 chip_width 1
# ....
_flash_list_raw | _split_banks
}
# Print flash address for 'bank_num' num defaults to 1
# _flash_address [bank_num:1]
_flash_address() {
bank_num=${1:-1}
# extract 'base' value and print as hexadecimal
# name nrf51 base 268439552 size 0 bus_width 1 chip_width 1
_flash_list | awk "NR==${bank_num}"'{printf "0x%08x\n", $4}'
}
#
# now comes the actual actions
#
do_flash() {
IMAGE_FILE=$1
test_config
test_imagefile
if [ -n "${PRE_FLASH_CHECK_SCRIPT}" ]; then
sh -c "${PRE_FLASH_CHECK_SCRIPT} '${IMAGE_FILE}'"
RETVAL=$?
if [ $RETVAL -ne 0 ]; then
echo "pre-flash checks failed, status=$RETVAL"
exit $RETVAL
fi
fi
# In case of binary file, IMAGE_OFFSET should include the flash base address
# This allows flashing normal binary files without env configuration
if _is_binfile "${IMAGE_FILE}" "${IMAGE_TYPE}"; then
# hardwritten to use the first bank
FLASH_ADDR=$(_flash_address 1)
echo "Binfile detected, adding ROM base address: ${FLASH_ADDR}"
IMAGE_TYPE=bin
IMAGE_OFFSET=$(printf "0x%08x\n" "$((${IMAGE_OFFSET} + ${FLASH_ADDR}))")
fi
if [ "${IMAGE_OFFSET}" != "0" ]; then
echo "Flashing with IMAGE_OFFSET: ${IMAGE_OFFSET}"
fi
# flash device
sh -c "${OPENOCD} \
${OPENOCD_ADAPTER_INIT} \
-f '${OPENOCD_CONFIG}' \
${OPENOCD_EXTRA_INIT} \
-c 'tcl_port 0' \
-c 'telnet_port 0' \
-c 'gdb_port 0' \
-c 'init' \
-c 'targets' \
-c 'reset halt' \
${OPENOCD_PRE_FLASH_CMDS} \
-c 'flash write_image erase \"${IMAGE_FILE}\" ${IMAGE_OFFSET} ${IMAGE_TYPE}' \
${OPENOCD_PRE_VERIFY_CMDS} \
-c 'verify_image \"${IMAGE_FILE}\" ${IMAGE_OFFSET}' \
-c 'reset run' \
-c 'shutdown'" &&
echo 'Done flashing'
}
do_debug() {
ELFFILE=$1
test_config
test_elffile
# temporary file that saves OpenOCD pid
OCD_PIDFILE=$(mktemp -t "openocd_pid.XXXXXXXXXX")
# will be called by trap
cleanup() {
OCD_PID="$(cat $OCD_PIDFILE)"
kill ${OCD_PID}
rm -f "$OCD_PIDFILE"
exit 0
}
# cleanup after script terminates
trap "cleanup ${OCD_PIDFILE}" EXIT
# don't trap on Ctrl+C, because GDB keeps running
trap '' INT
# start OpenOCD as GDB server
${SETSID} sh -c "${OPENOCD} \
${OPENOCD_ADAPTER_INIT} \
-f '${OPENOCD_CONFIG}' \
${OPENOCD_EXTRA_INIT} \
-c 'tcl_port ${TCL_PORT}' \
-c 'telnet_port ${TELNET_PORT}' \
-c 'gdb_port ${GDB_PORT}' \
-c 'init' \
-c 'targets' \
${OPENOCD_DBG_START_CMD} \
-l /dev/null & \
echo \$! > $OCD_PIDFILE" &
# Export to be able to access these from the sh -c command lines, may be
# useful when using a frontend for GDB
export ELFFILE
export GDB
export GDB_PORT
export DBG_FLAGS
export DBG_DEFAULT_FLAGS
export DBG_EXTRA_FLAGS
# Start the debugger and connect to the GDB server
sh -c "${DBG} ${DBG_FLAGS} ${ELFFILE}"
}
do_debugserver() {
test_config
# start OpenOCD as GDB server
sh -c "${OPENOCD} \
${OPENOCD_ADAPTER_INIT} \
-f '${OPENOCD_CONFIG}' \
${OPENOCD_EXTRA_INIT} \
-c 'tcl_port ${TCL_PORT}' \
-c 'telnet_port ${TELNET_PORT}' \
-c 'gdb_port ${GDB_PORT}' \
-c 'init' \
-c 'targets' \
-c 'halt'"
}
do_reset() {
test_config
# start OpenOCD and invoke board reset
sh -c "${OPENOCD} \
${OPENOCD_ADAPTER_INIT} \
-f '${OPENOCD_CONFIG}' \
${OPENOCD_EXTRA_INIT} \
-c 'tcl_port 0' \
-c 'telnet_port 0' \
-c 'gdb_port 0' \
-c 'init' \
${OPENOCD_CMD_RESET_RUN} \
-c 'shutdown'"
}
#
# parameter dispatching
#
ACTION="$1"
shift # pop $1 from $@
case "${ACTION}" in
flash)
echo "### Flashing Target ###"
do_flash "$@"
;;
debug)
echo "### Starting Debugging ###"
do_debug "$@"
;;
debug-server)
echo "### Starting GDB Server ###"
do_debugserver
;;
reset)
echo "### Resetting Target ###"
do_reset
;;
*)
echo "Usage: $0 {flash|debug|debug-server|reset}"
echo " flash <flashfile>"
echo " debug <elffile>"
exit 2
;;
esac