Merge commit 'ee31f1578a333a75737bc5b183cd4ae98cdaf798' into from_upstream

Conflicts:
	Makefile.am
	jimtcl
	src/helper/Makefile.am
	src/rtos/rtos.c
	src/rtos/rtos.h
	src/rtos/rtos_standard_stackings.c

Change-Id: I00c98d20089558744988184370a8cb7f95f03329
This commit is contained in:
Tim Newsome 2023-09-12 12:55:10 -07:00
commit 8c1f1b77d3
66 changed files with 2439 additions and 1133 deletions

View File

@ -26,10 +26,14 @@ noinst_LTLIBRARIES =
info_TEXINFOS =
dist_man_MANS =
EXTRA_DIST =
DISTCLEANFILES =
if INTERNAL_JIMTCL
SUBDIRS += jimtcl
DIST_SUBDIRS += jimtcl
EXTRA_DIST += jimtcl/configure.gnu
# jimtcl from 0.79 to 0.82 miss cleaning jsmn.o
DISTCLEANFILES += jimtcl/jsmn/jsmn.o
endif
# common flags used in openocd build
@ -131,18 +135,9 @@ uninstall-hook:
distclean-local:
rm -rf Doxyfile doxygen
rm -f $(srcdir)/jimtcl/configure.gnu
-rm -f $(srcdir)/jimtcl/configure.gnu
# We want every change to have Signed-off-by. This is tricky to enforce in
# Travis, because it automatically makes temporary commits when merging. So
# instead we have a hook that enforces this in each workspace. To make sure
# that users actually use those hooks, we point git at them here.
# If git fails for some reason, that's OK. It's probably because somebody is
# building the source completely outside a git repo.
all-local:
cd $(srcdir) && git config core.hooksPath ./git-hooks || true
DISTCLEANFILES = doxygen.log
DISTCLEANFILES += doxygen.log
METASOURCES = AUTO

3
README
View File

@ -240,8 +240,7 @@ Optional CMSIS-DAP adapter driver needs HIDAPI library.
Optional linuxgpiod adapter driver needs libgpiod library.
Optional JLink adapter driver needs libjaylink; build from git can
retrieve libjaylink as git submodule.
Optional J-Link adapter driver needs libjaylink library.
Optional ARM disassembly needs capstone library.

2
TODO
View File

@ -202,8 +202,6 @@ https://lists.berlios.de/pipermail/openocd-development/2009-October/011506.html
- MC1322x support (JW/DE?)
- integrate and test support from JW (and DE?)
- get working with a known good interface (i.e. not today's jlink)
- AT91SAM92xx:
- improvements for unknown-board-atmel-at91sam9260.cfg (RD)
- STR9x: (ZW)
- improvements to str912.cfg to be more general purpose
- AVR: (SQ)

View File

@ -572,9 +572,9 @@ AS_IF([test "x$enable_buspirate" != "xno"], [
AS_IF([test "x$use_internal_jimtcl" = "xyes"], [
AS_IF([test -f "$srcdir/jimtcl/configure"], [
AS_IF([test "x$use_internal_jimtcl_maintainer" = "xyes"], [
jimtcl_config_options="--disable-install-jim --with-ext=json --maintainer"
jimtcl_config_options="--disable-install-jim --with-ext=json --minimal --disable-ssl --maintainer"
], [
jimtcl_config_options="--disable-install-jim --with-ext=json"
jimtcl_config_options="--disable-install-jim --with-ext=json --minimal --disable-ssl"
])
AX_CONFIG_SUBDIR_OPTION([jimtcl], [$jimtcl_config_options])
], [

View File

@ -5031,7 +5031,7 @@ The value should normally correspond to a static mapping for the
@var{rtos_type} can be one of @option{auto}, @option{none}, @option{eCos},
@option{ThreadX}, @option{FreeRTOS}, @option{linux}, @option{ChibiOS},
@option{embKernel}, @option{mqx}, @option{uCOS-III}, @option{nuttx},
@option{RIOT}, @option{Zephyr}
@option{RIOT}, @option{Zephyr}, @option{rtkernel}
@xref{gdbrtossupport,,RTOS Support}.
@item @code{-defer-examine} -- skip target examination at initial JTAG chain
@ -11651,7 +11651,8 @@ In a debug session using JTAG for its transport protocol,
OpenOCD supports running such test files.
@deffn {Command} {svf} @file{filename} [@option{-tap @var{tapname}}] [@option{[-]quiet}] @
[@option{[-]nil}] [@option{[-]progress}] [@option{[-]ignore_error}]
[@option{[-]nil}] [@option{[-]progress}] [@option{[-]ignore_error}] @
[@option{-noreset}] [@option{-addcycles @var{cyclecount}}]
This issues a JTAG reset (Test-Logic-Reset) and then
runs the SVF script from @file{filename}.
@ -11670,6 +11671,10 @@ on the real interface;
@item @option{[-]progress} enable progress indication;
@item @option{[-]ignore_error} continue execution despite TDO check
errors.
@item @option{-noreset} omit JTAG reset (Test-Logic-Reset) before executing
content of the SVF file;
@item @option{-addcycles @var{cyclecount}} inject @var{cyclecount} number of
additional TCLK cycles after each SDR scan instruction;
@end itemize
@end deffn
@ -12085,6 +12090,7 @@ Currently supported rtos's include:
@item @option{RIOT}
@item @option{hwthread} (This is not an actual RTOS. @xref{usingopenocdsmpwithgdb,,Using OpenOCD SMP with GDB}.)
@item @option{Zephyr}
@item @option{rtkernel}
@end itemize
At any time, it's possible to drop the selected RTOS using:
@ -12104,7 +12110,7 @@ _tx_thread_current_ptr, _tx_thread_created_ptr, _tx_thread_created_count.
@raggedright
pxCurrentTCB, pxReadyTasksLists, xDelayedTaskList1, xDelayedTaskList2,
pxDelayedTaskList, pxOverflowDelayedTaskList, xPendingReadyList,
uxCurrentNumberOfTasks, uxTopUsedPriority.
uxCurrentNumberOfTasks, uxTopUsedPriority, xSchedulerRunning.
@end raggedright
@item linux symbols
init_task.
@ -12126,6 +12132,8 @@ _tcb_name_offset.
@end raggedright
@item Zephyr symbols
_kernel, _kernel_openocd_offsets, _kernel_openocd_size_t_size
@item rtkernel symbols
Multiple struct offsets.
@end table
For most RTOS supported the above symbols will be exported by default. However for

2
jimtcl

@ -1 +1 @@
Subproject commit 70b007b63669a709b0e8aef34a22658047815cc2
Subproject commit 1933e5457b9512d39ebbe11ed32578aada149f49

View File

@ -243,8 +243,12 @@ static const struct samd_part saml21_parts[] = {
{ 0x1F, "SAMR30E18A", 256, 32 },
/* SAMR34/R35 parts have integrated SAML21 with a lora radio */
{ 0x28, "SAMR34J18", 256, 32 },
{ 0x2B, "SAMR35J18", 256, 32 },
{ 0x28, "SAMR34J18", 256, 40 },
{ 0x29, "SAMR34J17", 128, 24 },
{ 0x2A, "SAMR34J16", 64, 12 },
{ 0x2B, "SAMR35J18", 256, 40 },
{ 0x2C, "SAMR35J17", 128, 24 },
{ 0x2D, "SAMR35J16", 64, 12 },
};
/* Known SAML22 parts. */

View File

@ -23,7 +23,14 @@
* from device datasheets and Linux SPI flash drivers. */
const struct flash_device flash_devices[] = {
/* name, read_cmd, qread_cmd, pprog_cmd, erase_cmd, chip_erase_cmd, device_id,
* pagesize, sectorsize, size_in_bytes */
* pagesize, sectorsize, size_in_bytes
* note: device id is usually 3 bytes long, however the unused highest byte counts
* continuation codes for manufacturer id as per JEP106xx */
FLASH_ID("st m25pe10", 0x03, 0x00, 0x02, 0xd8, 0x00, 0x00118020, 0x100, 0x10000, 0x20000),
FLASH_ID("st m25pe20", 0x03, 0x00, 0x02, 0xd8, 0x00, 0x00128020, 0x100, 0x10000, 0x40000),
FLASH_ID("st m25pe40", 0x03, 0x00, 0x02, 0xd8, 0x00, 0x00138020, 0x100, 0x10000, 0x80000),
FLASH_ID("st m25pe80", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00148020, 0x100, 0x10000, 0x100000),
FLASH_ID("st m25pe16", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00158020, 0x100, 0x10000, 0x200000),
FLASH_ID("st m25p05", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00102020, 0x80, 0x8000, 0x10000),
FLASH_ID("st m25p10", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00112020, 0x80, 0x8000, 0x20000),
FLASH_ID("st m25p20", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00122020, 0x100, 0x10000, 0x40000),
@ -51,12 +58,28 @@ const struct flash_device flash_devices[] = {
FLASH_ID("cyp s25fl064l", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00176001, 0x100, 0x10000, 0x800000),
FLASH_ID("cyp s25fl128l", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x00186001, 0x100, 0x10000, 0x1000000),
FLASH_ID("cyp s25fl256l", 0x13, 0x00, 0x12, 0xdc, 0xc7, 0x00196001, 0x100, 0x10000, 0x2000000),
FLASH_ID("cyp s28hl256t", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x00195a34, 0x100, 0x40000, 0x2000000), /* page! */
FLASH_ID("cyp s28hs256t", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x00195b34, 0x100, 0x40000, 0x2000000), /* page! */
FLASH_ID("cyp s28hl512t", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001a5a34, 0x100, 0x40000, 0x4000000), /* page! */
FLASH_ID("cyp s28hs512t", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001a5b34, 0x100, 0x40000, 0x4000000), /* page! */
FLASH_ID("cyp s28hl01gt", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001b5a34, 0x100, 0x40000, 0x8000000), /* page! */
FLASH_ID("cyp s28hs01gt", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001b5b34, 0x100, 0x40000, 0x8000000), /* page! */
FLASH_ID("atmel 25f512", 0x03, 0x00, 0x02, 0x52, 0xc7, 0x0065001f, 0x80, 0x8000, 0x10000),
FLASH_ID("atmel 25f1024", 0x03, 0x00, 0x02, 0x52, 0x62, 0x0060001f, 0x100, 0x8000, 0x20000),
FLASH_ID("atmel 25f2048", 0x03, 0x00, 0x02, 0x52, 0x62, 0x0063001f, 0x100, 0x10000, 0x40000),
FLASH_ID("atmel 25f4096", 0x03, 0x00, 0x02, 0x52, 0x62, 0x0064001f, 0x100, 0x10000, 0x80000),
FLASH_ID("atmel 25fs040", 0x03, 0x00, 0x02, 0xd7, 0xc7, 0x0004661f, 0x100, 0x10000, 0x80000),
FLASH_ID("adesto 25sf041b", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001841f, 0x100, 0x10000, 0x80000),
FLASH_ID("adesto 25df081a", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001451f, 0x100, 0x10000, 0x100000),
FLASH_ID("adesto 25sf081b", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001851f, 0x100, 0x10000, 0x100000),
FLASH_ID("adesto 25sf161b", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001861f, 0x100, 0x10000, 0x200000),
FLASH_ID("adesto 25df321b", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001471f, 0x100, 0x10000, 0x400000),
FLASH_ID("adesto 25sf321b", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001871f, 0x100, 0x10000, 0x400000),
FLASH_ID("adesto 25xf641b", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001881f, 0x100, 0x10000, 0x800000), /* sf/qf */
FLASH_ID("adesto 25xf128a", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0001891f, 0x100, 0x10000, 0x1000000), /* sf/qf */
FLASH_ID("adesto xp032", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0700a743, 0x100, 0x10000, 0x400000), /* 4-byte */
FLASH_ID("adesto xp064b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0001a81f, 0x100, 0x10000, 0x800000), /* 4-byte */
FLASH_ID("adesto xp128", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0000a91f, 0x100, 0x10000, 0x1000000), /* 4-byte */
FLASH_ID("mac 25l512", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001020c2, 0x010, 0x10000, 0x10000),
FLASH_ID("mac 25l1005", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001120c2, 0x010, 0x10000, 0x20000),
FLASH_ID("mac 25l2005", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001220c2, 0x010, 0x10000, 0x40000),
@ -78,6 +101,9 @@ const struct flash_device flash_devices[] = {
FLASH_ID("mac 25r3235f", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001628c2, 0x100, 0x10000, 0x400000),
FLASH_ID("mac 25r6435f", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001728c2, 0x100, 0x10000, 0x800000),
FLASH_ID("mac 25u1635e", 0x03, 0xeb, 0x02, 0x20, 0xc7, 0x003525c2, 0x100, 0x1000, 0x100000),
FLASH_ID("mac 66l1g45g", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001b20c2, 0x100, 0x10000, 0x8000000),
FLASH_ID("mac 66um1g45g", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x003b80c2, 0x100, 0x10000, 0x8000000),
FLASH_ID("mac 66lm1g45g", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x003b85c2, 0x100, 0x10000, 0x8000000),
FLASH_ID("micron n25q032", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x0016ba20, 0x100, 0x10000, 0x400000),
FLASH_ID("micron n25q064", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x0017ba20, 0x100, 0x10000, 0x800000),
FLASH_ID("micron n25q128", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x0018ba20, 0x100, 0x10000, 0x1000000),
@ -102,6 +128,10 @@ const struct flash_device flash_devices[] = {
FLASH_ID("win w25q256fv/jv", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001940ef, 0x100, 0x10000, 0x2000000),
FLASH_ID("win w25q256fv", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001960ef, 0x100, 0x10000, 0x2000000), /* QPI mode */
FLASH_ID("win w25q256jv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001970ef, 0x100, 0x10000, 0x2000000),
FLASH_ID("win w25q512jv", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x002040ef, 0x100, 0x10000, 0x4000000),
FLASH_ID("win w25q01jv", 0x13, 0x00, 0x12, 0xdc, 0xc7, 0x002140ef, 0x100, 0x10000, 0x8000000),
FLASH_ID("win w25q01jv-dtr", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x002170ef, 0x100, 0x10000, 0x8000000),
FLASH_ID("win w25q02jv-dtr", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x002270ef, 0x100, 0x10000, 0x10000000),
FLASH_ID("gd gd25q512", 0x03, 0x00, 0x02, 0x20, 0xc7, 0x001040c8, 0x100, 0x1000, 0x10000),
FLASH_ID("gd gd25q10", 0x03, 0x00, 0x02, 0x20, 0xc7, 0x001140c8, 0x100, 0x1000, 0x20000),
FLASH_ID("gd gd25q20", 0x03, 0x00, 0x02, 0x20, 0xc7, 0x001240c8, 0x100, 0x1000, 0x40000),
@ -109,9 +139,17 @@ const struct flash_device flash_devices[] = {
FLASH_ID("gd gd25q16c", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001540c8, 0x100, 0x10000, 0x200000),
FLASH_ID("gd gd25q32c", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001640c8, 0x100, 0x10000, 0x400000),
FLASH_ID("gd gd25q64c", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001740c8, 0x100, 0x10000, 0x800000),
FLASH_ID("gd gd25q128c", 0x03, 0xeb, 0x02, 0xd8, 0xc7, 0x001840c8, 0x100, 0x10000, 0x1000000),
FLASH_ID("gd gd25q128c", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x001840c8, 0x100, 0x10000, 0x1000000),
FLASH_ID("gd gd25q256c", 0x13, 0x00, 0x12, 0xdc, 0xc7, 0x001940c8, 0x100, 0x10000, 0x2000000),
FLASH_ID("gd gd25q512mc", 0x13, 0x00, 0x12, 0xdc, 0xc7, 0x002040c8, 0x100, 0x10000, 0x4000000),
FLASH_ID("gd gd25lx256e", 0x13, 0x0c, 0x12, 0xdc, 0xc7, 0x001968c8, 0x100, 0x10000, 0x2000000),
FLASH_ID("zbit zb25vq16", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0015605e, 0x100, 0x10000, 0x200000),
FLASH_ID("zbit zb25vq32", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0016405e, 0x100, 0x10000, 0x400000),
FLASH_ID("zbit zb25vq32", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0016605e, 0x100, 0x10000, 0x400000), /* QPI mode */
FLASH_ID("zbit zb25vq64", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0017405e, 0x100, 0x10000, 0x800000),
FLASH_ID("zbit zb25vq64", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0017605e, 0x100, 0x10000, 0x800000), /* QPI mode */
FLASH_ID("zbit zb25vq128", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0018405e, 0x100, 0x10000, 0x1000000),
FLASH_ID("zbit zb25vq128", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0018605e, 0x100, 0x10000, 0x1000000), /* QPI mode */
FLASH_ID("issi is25lq040b", 0x03, 0xeb, 0x02, 0x20, 0xc7, 0x0013409d, 0x100, 0x1000, 0x80000),
FLASH_ID("issi is25lp032", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0016609d, 0x100, 0x10000, 0x400000),
FLASH_ID("issi is25lp064", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0017609d, 0x100, 0x10000, 0x800000),
@ -121,6 +159,18 @@ const struct flash_device flash_devices[] = {
FLASH_ID("issi is25wp256d", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x0019709d, 0x100, 0x10000, 0x2000000),
FLASH_ID("issi is25lp512m", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001a609d, 0x100, 0x10000, 0x4000000),
FLASH_ID("issi is25wp512m", 0x13, 0xec, 0x12, 0xdc, 0xc7, 0x001a709d, 0x100, 0x10000, 0x4000000),
FLASH_ID("xtx xt25f02e", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0012400b, 0x100, 0x10000, 0x40000),
FLASH_ID("xtx xt25f04d", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0013400b, 0x100, 0x10000, 0x80000),
FLASH_ID("xtx xt25f08b", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0014400b, 0x100, 0x10000, 0x100000),
FLASH_ID("xtx xt25f16b", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x0015400b, 0x100, 0x10000, 0x200000),
FLASH_ID("xtx xt25f32b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0016400b, 0x100, 0x10000, 0x200000),
FLASH_ID("xtx xt25f64b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0017400b, 0x100, 0x10000, 0x400000),
FLASH_ID("xtx xt25f128b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0018400b, 0x100, 0x10000, 0x800000),
FLASH_ID("xtx xt25q08d", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0014600b, 0x100, 0x10000, 0x100000),
FLASH_ID("xtx xt25q16b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0015600b, 0x100, 0x10000, 0x200000),
FLASH_ID("xtx xt25q32b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0016600b, 0x100, 0x10000, 0x400000), /* exists ? */
FLASH_ID("xtx xt25q64b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0017600b, 0x100, 0x10000, 0x800000),
FLASH_ID("xtx xt25q128b", 0x03, 0x0b, 0x02, 0xd8, 0xc7, 0x0018600b, 0x100, 0x10000, 0x1000000),
/* FRAM, no erase commands, no write page or sectors */
FRAM_ID("fu mb85rs16n", 0x03, 0, 0x02, 0x00010104, 0x800),
@ -131,13 +181,30 @@ const struct flash_device flash_devices[] = {
FRAM_ID("fu mb85rs512t", 0x03, 0, 0x02, 0x00032604, 0x10000),
FRAM_ID("fu mb85rs1mt", 0x03, 0, 0x02, 0x00032704, 0x20000),
FRAM_ID("fu mb85rs2mta", 0x03, 0, 0x02, 0x00034804, 0x40000),
FRAM_ID("cyp fm25v01a", 0x03, 0, 0x02, 0x000821c2, 0x4000),
FRAM_ID("cyp fm25v02", 0x03, 0, 0x02, 0x000022c2, 0x8000),
FRAM_ID("cyp fm25v02a", 0x03, 0, 0x02, 0x000822c2, 0x8000),
FRAM_ID("cyp fm25v05", 0x03, 0, 0x02, 0x000023c2, 0x10000),
FRAM_ID("cyp fm25v10", 0x03, 0, 0x02, 0x000024c2, 0x20000),
FRAM_ID("cyp fm25v20a", 0x03, 0, 0x02, 0x000825c2, 0x40000),
FRAM_ID("cyp fm25v40", 0x03, 0, 0x02, 0x004026c2, 0x80000),
FRAM_ID("cyp fm25v01a", 0x03, 0, 0x02, 0x060821c2, 0x4000),
FRAM_ID("cyp fm25v02", 0x03, 0, 0x02, 0x060022c2, 0x8000),
FRAM_ID("cyp fm25v02a", 0x03, 0, 0x02, 0x060822c2, 0x8000),
FRAM_ID("cyp fm25v05", 0x03, 0, 0x02, 0x060023c2, 0x10000),
FRAM_ID("cyp fm25v10", 0x03, 0, 0x02, 0x060024c2, 0x20000),
FRAM_ID("cyp fm25v20a", 0x03, 0, 0x02, 0x060825c2, 0x40000),
FRAM_ID("cyp fm25v40", 0x03, 0, 0x02, 0x064026c2, 0x80000),
FRAM_ID("cyp cy15b102qn", 0x03, 0, 0x02, 0x06002ac2, 0x40000),
FRAM_ID("cyp cy15v102qn", 0x03, 0, 0x02, 0x06042ac2, 0x40000),
FRAM_ID("cyp cy15b104qi", 0x03, 0, 0x02, 0x06012dc2, 0x80000),
FRAM_ID("cyp cy15b104qi", 0x03, 0, 0x02, 0x06a12dc2, 0x80000),
FRAM_ID("cyp cy15v104qi", 0x03, 0, 0x02, 0x06052dc2, 0x80000),
FRAM_ID("cyp cy15v104qi", 0x03, 0, 0x02, 0x06a52dc2, 0x80000),
FRAM_ID("cyp cy15b104qn", 0x03, 0, 0x02, 0x06402cc2, 0x80000),
FRAM_ID("cyp cy15b108qi", 0x03, 0, 0x02, 0x06012fc2, 0x100000),
FRAM_ID("cyp cy15b108qi", 0x03, 0, 0x02, 0x06a12fc2, 0x100000),
FRAM_ID("cyp cy15v108qi", 0x03, 0, 0x02, 0x06052fc2, 0x100000),
FRAM_ID("cyp cy15v108qi", 0x03, 0, 0x02, 0x06a52fc2, 0x100000),
FRAM_ID("cyp cy15b108qn", 0x03, 0, 0x02, 0x06012ec2, 0x100000),
FRAM_ID("cyp cy15b108qn", 0x03, 0, 0x02, 0x06032ec2, 0x100000),
FRAM_ID("cyp cy15b108qn", 0x03, 0, 0x02, 0x06a12ec2, 0x100000),
FRAM_ID("cyp cy15v108qn", 0x03, 0, 0x02, 0x06052ec2, 0x100000),
FRAM_ID("cyp cy15v108qn", 0x03, 0, 0x02, 0x06072ec2, 0x100000),
FRAM_ID("cyp cy15v108qn", 0x03, 0, 0x02, 0x06a52ec2, 0x100000),
FLASH_ID(NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0)
};

View File

@ -318,7 +318,7 @@ static const struct stm32l4_rev stm32l4p_l4qxx_revs[] = {
};
static const struct stm32l4_rev stm32l55_l56xx_revs[] = {
{ 0x1000, "A" }, { 0x2000, "B" },
{ 0x1000, "A" }, { 0x2000, "B" }, { 0x2001, "Z" },
};
static const struct stm32l4_rev stm32g49_g4axx_revs[] = {

View File

@ -16,6 +16,7 @@ noinst_LTLIBRARIES += %D%/libhelper.la
%D%/util.c \
%D%/jep106.c \
%D%/jim-nvp.c \
%D%/nvp.c \
%D%/align.h \
%D%/binarybuffer.h \
%D%/bits.h \
@ -34,7 +35,9 @@ noinst_LTLIBRARIES += %D%/libhelper.la
%D%/jep106.inc \
%D%/jim-nvp.h \
%D%/base64.c \
%D%/base64.h
%D%/base64.h \
%D%/nvp.h \
%D%/compiler.h
STARTUP_TCL_SRCS += %D%/startup.tcl
EXTRA_DIST += \

View File

@ -18,9 +18,6 @@
#include "config.h"
#endif
/* see Embedded-HOWTO.txt in Jim Tcl project hosted on BerliOS*/
#define JIM_EMBEDDED
/* @todo the inclusion of target.h here is a layering violation */
#include <jtag/jtag.h>
#include <target/target.h>
@ -543,8 +540,16 @@ static int run_command(struct command_context *context,
if (retval != ERROR_OK)
LOG_DEBUG("Command '%s' failed with error code %d",
words[0], retval);
/* Use the command output as the Tcl result */
Jim_SetResult(context->interp, cmd.output);
/*
* Use the command output as the Tcl result.
* Drop last '\n' to allow command output concatenation
* while keep using command_print() everywhere.
*/
const char *output_txt = Jim_String(cmd.output);
int len = strlen(output_txt);
if (len && output_txt[len - 1] == '\n')
--len;
Jim_SetResultString(context->interp, output_txt, len);
}
Jim_DecrRefCount(context->interp, cmd.output);

View File

@ -370,10 +370,21 @@ struct command_context *copy_command_context(struct command_context *cmd_ctx);
*/
void command_done(struct command_context *context);
/*
* command_print() and command_print_sameline() are used to produce the TCL
* output of OpenOCD commands. command_print() automatically adds a '\n' at
* the end or the format string. Use command_print_sameline() to avoid the
* trailing '\n', e.g. to concatenate the command output in the same line.
* The very last '\n' of the command is stripped away (see run_command()).
* For commands that strictly require a '\n' as last output character, add
* it explicitly with either an empty command_print() or with a '\n' in the
* last command_print() and add a comment to document it.
*/
void command_print(struct command_invocation *cmd, const char *format, ...)
__attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 2, 3)));
void command_print_sameline(struct command_invocation *cmd, const char *format, ...)
__attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 2, 3)));
int command_run_line(struct command_context *context, char *line);
int command_run_linef(struct command_context *context, const char *format, ...)
__attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 2, 3)));

52
src/helper/compiler.h Normal file
View File

@ -0,0 +1,52 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* This file contains compiler specific workarounds to handle different
* compilers and different compiler versions.
* Inspired by Linux's include/linux/compiler_attributes.h
* and file sys/cdefs.h in libc and newlib.
*/
#ifndef OPENOCD_HELPER_COMPILER_H
#define OPENOCD_HELPER_COMPILER_H
/*
* __has_attribute is supported on gcc >= 5, clang >= 2.9 and icc >= 17.
*/
#ifndef __has_attribute
# define __has_attribute(x) 0
#endif
/*
* The __returns_nonnull function attribute marks the return type of the function
* as always being non-null.
*/
#ifndef __returns_nonnull
# if __has_attribute(__returns_nonnull__)
# define __returns_nonnull __attribute__((__returns_nonnull__))
# else
# define __returns_nonnull
# endif
#endif
/*
* The __nonnull function attribute marks pointer parameters that
* must not be NULL.
*
* clang for Apple defines
* #define __nonnull _Nonnull
* that is a per argument attribute, incompatible with the gcc per function attribute __nonnull__.
* Undefine it to keep compatibility among compilers.
*/
#if defined(__clang__) && defined(__APPLE__)
# undef __nonnull
#endif
#ifndef __nonnull
# if __has_attribute(__nonnull__)
# define __nonnull(params) __attribute__ ((__nonnull__ params))
# else
# define __nonnull(params)
# endif
#endif
#endif /* OPENOCD_HELPER_COMPILER_H */

67
src/helper/nvp.c Normal file
View File

@ -0,0 +1,67 @@
// SPDX-License-Identifier: BSD-2-Clause-Views
/*
* Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
* Copyright 2005 Clemens Hintze <c.hintze@gmx.net>
* Copyright 2005 patthoyts - Pat Thoyts <patthoyts@users.sf.net>
* Copyright 2008 oharboe - Øyvind Harboe - oyvind.harboe@zylin.com
* Copyright 2008 Andrew Lunn <andrew@lunn.ch>
* Copyright 2008 Duane Ellis <openocd@duaneellis.com>
* Copyright 2008 Uwe Klein <uklein@klein-messgeraete.de>
* Copyright 2008 Steve Bennett <steveb@workware.net.au>
* Copyright 2009 Nico Coesel <ncoesel@dealogic.nl>
* Copyright 2009 Zachary T Welch zw@superlucidity.net
* Copyright 2009 David Brownell
* Copyright (c) 2005-2011 Jim Tcl Project. All rights reserved.
*
* This file is extracted from jim_nvp.c, originally part of jim TCL code.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include <helper/command.h>
#include <helper/nvp.h>
const struct nvp *nvp_name2value(const struct nvp *p, const char *name)
{
while (p->name) {
if (strcmp(name, p->name) == 0)
break;
p++;
}
return p;
}
const struct nvp *nvp_value2name(const struct nvp *p, int value)
{
while (p->name) {
if (value == p->value)
break;
p++;
}
return p;
}
void nvp_unknown_command_print(struct command_invocation *cmd, const struct nvp *nvp,
const char *param_name, const char *param_value)
{
if (param_name)
command_print_sameline(cmd, "%s: Unknown: %s, try one of: ", param_name, param_value);
else
command_print_sameline(cmd, "Unknown param: %s, try one of: ", param_value);
while (nvp->name) {
if ((nvp + 1)->name)
command_print_sameline(cmd, "%s, ", nvp->name);
else
command_print(cmd, "or %s", nvp->name);
nvp++;
}
/* We assume nvp to be not empty and loop has been taken; no need to add a '\n' */
}

77
src/helper/nvp.h Normal file
View File

@ -0,0 +1,77 @@
/* SPDX-License-Identifier: BSD-2-Clause-Views */
/*
* Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
* Copyright 2005 Clemens Hintze <c.hintze@gmx.net>
* Copyright 2005 patthoyts - Pat Thoyts <patthoyts@users.sf.net>
* Copyright 2008 oharboe - Øyvind Harboe - oyvind.harboe@zylin.com
* Copyright 2008 Andrew Lunn <andrew@lunn.ch>
* Copyright 2008 Duane Ellis <openocd@duaneellis.com>
* Copyright 2008 Uwe Klein <uklein@klein-messgeraete.de>
* Copyright 2008 Steve Bennett <steveb@workware.net.au>
* Copyright 2009 Nico Coesel <ncoesel@dealogic.nl>
* Copyright 2009 Zachary T Welch zw@superlucidity.net
* Copyright 2009 David Brownell
* Copyright (c) 2005-2011 Jim Tcl Project. All rights reserved.
*
* This file is extracted from jim_nvp.h, originally part of jim TCL code.
*/
#ifndef OPENOCD_HELPER_NVP_H
#define OPENOCD_HELPER_NVP_H
#include <helper/compiler.h>
/** Name Value Pairs, aka: NVP
* - Given a string - return the associated int.
* - Given a number - return the associated string.
* .
*
* Very useful when the number is not a simple index into an array of
* known string, or there may be multiple strings (aliases) that mean then same
* thing.
*
* An NVP Table is terminated with ".name = NULL".
*
* During the 'name2value' operation, if no matching string is found
* the pointer to the terminal element (with p->name == NULL) is returned.
*
* Example:
* \code
* const struct nvp yn[] = {
* { "yes", 1 },
* { "no" , 0 },
* { "yep", 1 },
* { "nope", 0 },
* { NULL, -1 },
* };
*
* struct nvp *result;
* result = nvp_name2value(yn, "yes");
* returns &yn[0];
* result = nvp_name2value(yn, "no");
* returns &yn[1];
* result = jim_nvp_name2value(yn, "Blah");
* returns &yn[4];
* \endcode
*
* During the number2name operation, the first matching value is returned.
*/
struct nvp {
const char *name;
int value;
};
struct command_invocation;
/* Name Value Pairs Operations */
const struct nvp *nvp_name2value(const struct nvp *nvp_table, const char *name)
__returns_nonnull __nonnull((1));
const struct nvp *nvp_value2name(const struct nvp *nvp_table, int v)
__returns_nonnull __nonnull((1));
void nvp_unknown_command_print(struct command_invocation *cmd, const struct nvp *nvp,
const char *param_name, const char *param_value);
#endif /* OPENOCD_HELPER_NVP_H */

View File

@ -66,6 +66,12 @@ static inline void bcm2835_gpio_synchronize(void)
__sync_synchronize();
}
static inline void bcm2835_delay(void)
{
for (unsigned int i = 0; i < jtag_delay; i++)
asm volatile ("");
}
static bool is_gpio_config_valid(enum adapter_gpio_config_index idx)
{
/* Only chip 0 is supported, accept unset value (-1) too */
@ -178,8 +184,7 @@ static int bcm2835gpio_write(int tck, int tms, int tdi)
GPIO_CLR = clear;
bcm2835_gpio_synchronize();
for (unsigned int i = 0; i < jtag_delay; i++)
asm volatile ("");
bcm2835_delay();
return ERROR_OK;
}
@ -199,8 +204,7 @@ static int bcm2835gpio_swd_write_fast(int swclk, int swdio)
GPIO_CLR = clear;
bcm2835_gpio_synchronize();
for (unsigned int i = 0; i < jtag_delay; i++)
asm volatile ("");
bcm2835_delay();
return ERROR_OK;
}
@ -211,8 +215,7 @@ static int bcm2835gpio_swd_write_generic(int swclk, int swdio)
set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWDIO], swdio);
set_gpio_value(&adapter_gpio_config[ADAPTER_GPIO_IDX_SWCLK], swclk); /* Write clock last */
for (unsigned int i = 0; i < jtag_delay; ++i)
asm volatile ("");
bcm2835_delay();
return ERROR_OK;
}
@ -264,7 +267,8 @@ static int bcm2835gpio_khz(int khz, int *jtag_speed)
LOG_DEBUG("BCM2835 GPIO: RCLK not supported");
return ERROR_FAIL;
}
*jtag_speed = speed_coeff/khz - speed_offset;
*jtag_speed = DIV_ROUND_UP(speed_coeff, khz) - speed_offset;
LOG_DEBUG("jtag_delay %d", *jtag_speed);
if (*jtag_speed < 0)
*jtag_speed = 0;
return ERROR_OK;
@ -272,7 +276,9 @@ static int bcm2835gpio_khz(int khz, int *jtag_speed)
static int bcm2835gpio_speed_div(int speed, int *khz)
{
*khz = speed_coeff/(speed + speed_offset);
int divisor = speed + speed_offset;
/* divide with roundig to the closest */
*khz = (speed_coeff + divisor / 2) / divisor;
return ERROR_OK;
}

View File

@ -525,7 +525,19 @@ static void bitbang_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay
bitbang_swd_exchange(false, &cmd, 0, 8);
bitbang_interface->swdio_drive(false);
bitbang_swd_exchange(true, trn_ack_data_parity_trn, 0, 1 + 3 + 1);
bitbang_swd_exchange(true, trn_ack_data_parity_trn, 0, 1 + 3);
/* Avoid a glitch on SWDIO when changing the direction to output.
* To keep performance penalty minimal, pre-write the first data
* bit to SWDIO GPIO output buffer while clocking the turnaround bit.
* Following swdio_drive(true) outputs the pre-written value
* and the same value is rewritten by the next swd_write()
* instead of glitching SWDIO
* HiZ/pull-up --------------> 0 -------------> 1
* swdio_drive(true) swd_write(0,1)
* in case of data bit 0 = 1
*/
bitbang_swd_exchange(false, trn_ack_data_parity_trn, 1 + 3 + 1, 1);
bitbang_interface->swdio_drive(true);
bitbang_swd_exchange(false, trn_ack_data_parity_trn, 1 + 3 + 1, 32 + 1);

View File

@ -1001,12 +1001,14 @@ static void cmsis_dap_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data)
block_cmd);
unsigned int resp_size = cmsis_dap_tfer_resp_size(write_count, read_count,
block_cmd);
unsigned int max_transfer_count = block_cmd ? 65535 : 255;
/* Does the DAP Transfer command and the expected response fit into one packet?
* Run the queue also before a targetsel - it cannot be queued */
if (cmd_size > tfer_max_command_size
|| resp_size > tfer_max_response_size
|| targetsel_cmd) {
|| targetsel_cmd
|| write_count + read_count > max_transfer_count) {
if (cmsis_dap_handle->pending_fifo_block_count)
cmsis_dap_swd_read_process(cmsis_dap_handle, 0);

View File

@ -735,13 +735,8 @@ static int ftdi_initialize(void)
return ERROR_JTAG_INIT_FAILED;
}
for (int i = 0; ftdi_vid[i] || ftdi_pid[i]; i++) {
mpsse_ctx = mpsse_open(&ftdi_vid[i], &ftdi_pid[i], ftdi_device_desc,
mpsse_ctx = mpsse_open(ftdi_vid, ftdi_pid, ftdi_device_desc,
adapter_get_required_serial(), adapter_usb_get_location(), ftdi_channel);
if (mpsse_ctx)
break;
}
if (!mpsse_ctx)
return ERROR_JTAG_INIT_FAILED;

View File

@ -1976,6 +1976,8 @@ struct pending_scan_result {
void *buffer;
/** Offset in the destination buffer */
unsigned buffer_offset;
/** SWD command */
uint8_t swd_cmd;
};
#define MAX_PENDING_SCAN_RESULTS 256
@ -2179,12 +2181,13 @@ static int jlink_swd_run_queue(void)
}
for (i = 0; i < pending_scan_results_length; i++) {
/* Devices do not reply to DP_TARGETSEL write cmd, ignore received ack */
bool check_ack = swd_cmd_returns_ack(pending_scan_results_buffer[i].swd_cmd);
int ack = buf_get_u32(tdo_buffer, pending_scan_results_buffer[i].first, 3);
if (ack != SWD_ACK_OK) {
if (check_ack && ack != SWD_ACK_OK) {
LOG_DEBUG("SWD ack not OK: %d %s", ack,
ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK");
queued_retval = ack == SWD_ACK_WAIT ? ERROR_WAIT : ERROR_FAIL;
queued_retval = swd_ack_to_error_code(ack);
goto skip;
} else if (pending_scan_results_buffer[i].length) {
uint32_t data = buf_get_u32(tdo_buffer, 3 + pending_scan_results_buffer[i].first, 32);
@ -2221,6 +2224,7 @@ static void jlink_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data, uint3
if (queued_retval != ERROR_OK)
return;
pending_scan_results_buffer[pending_scan_results_length].swd_cmd = cmd;
cmd |= SWD_CMD_START | SWD_CMD_PARK;
jlink_queue_data_out(&cmd, 8);

View File

@ -50,7 +50,7 @@ static int jtag_libusb_error(int err)
}
}
static bool jtag_libusb_match_ids(struct libusb_device_descriptor *dev_desc,
bool jtag_libusb_match_ids(struct libusb_device_descriptor *dev_desc,
const uint16_t vids[], const uint16_t pids[])
{
for (unsigned i = 0; vids[i]; i++) {

View File

@ -30,6 +30,8 @@
typedef char * (*adapter_get_alternate_serial_fn)(struct libusb_device_handle *device,
struct libusb_device_descriptor *dev_desc);
bool jtag_libusb_match_ids(struct libusb_device_descriptor *dev_desc,
const uint16_t vids[], const uint16_t pids[]);
int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[],
struct libusb_device_handle **out,
adapter_get_alternate_serial_fn adapter_get_alternate_serial);

View File

@ -13,6 +13,7 @@
#include "helper/log.h"
#include "helper/replacements.h"
#include "helper/time_support.h"
#include "libusb_helper.h"
#include <libusb.h>
/* Compatibility define for older libusb-1.0 */
@ -148,7 +149,7 @@ static bool device_location_equal(struct libusb_device *device, const char *loca
* Set any field to 0 as a wildcard. If the device is found true is returned, with ctx containing
* the already opened handle. ctx->interface must be set to the desired interface (channel) number
* prior to calling this function. */
static bool open_matching_device(struct mpsse_ctx *ctx, const uint16_t *vid, const uint16_t *pid,
static bool open_matching_device(struct mpsse_ctx *ctx, const uint16_t vids[], const uint16_t pids[],
const char *product, const char *serial, const char *location)
{
struct libusb_device **list;
@ -169,9 +170,7 @@ static bool open_matching_device(struct mpsse_ctx *ctx, const uint16_t *vid, con
continue;
}
if (vid && *vid != desc.idVendor)
continue;
if (pid && *pid != desc.idProduct)
if (!jtag_libusb_match_ids(&desc, vids, pids))
continue;
err = libusb_open(device, &ctx->usb_dev);
@ -203,7 +202,7 @@ static bool open_matching_device(struct mpsse_ctx *ctx, const uint16_t *vid, con
libusb_free_device_list(list, 1);
if (!found) {
LOG_ERROR("no device found");
/* The caller reports detailed error desc */
return false;
}
@ -307,7 +306,7 @@ error:
return false;
}
struct mpsse_ctx *mpsse_open(const uint16_t *vid, const uint16_t *pid, const char *description,
struct mpsse_ctx *mpsse_open(const uint16_t vids[], const uint16_t pids[], const char *description,
const char *serial, const char *location, int channel)
{
struct mpsse_ctx *ctx = calloc(1, sizeof(*ctx));
@ -343,14 +342,9 @@ struct mpsse_ctx *mpsse_open(const uint16_t *vid, const uint16_t *pid, const cha
goto error;
}
if (!open_matching_device(ctx, vid, pid, description, serial, location)) {
/* Four hex digits plus terminating zero each */
char vidstr[5];
char pidstr[5];
LOG_ERROR("unable to open ftdi device with vid %s, pid %s, description '%s', "
if (!open_matching_device(ctx, vids, pids, description, serial, location)) {
LOG_ERROR("unable to open ftdi device with description '%s', "
"serial '%s' at bus location '%s'",
vid ? sprintf(vidstr, "%04x", *vid), vidstr : "*",
pid ? sprintf(pidstr, "%04x", *pid), pidstr : "*",
description ? description : "*",
serial ? serial : "*",
location ? location : "*");

View File

@ -742,16 +742,18 @@ static void openjtag_execute_runtest(struct jtag_command *cmd)
tap_set_state(TAP_IDLE);
}
if (cmd->cmd.runtest->num_cycles > 16)
LOG_WARNING("num_cycles > 16 on run test");
if (openjtag_variant != OPENJTAG_VARIANT_CY7C65215 ||
cmd->cmd.runtest->num_cycles) {
uint8_t command;
command = 7;
command |= ((cmd->cmd.runtest->num_cycles - 1) & 0x0F) << 4;
int cycles = cmd->cmd.runtest->num_cycles;
openjtag_add_byte(command);
do {
command = 7;
command |= (((cycles > 16 ? 16 : cycles) - 1) & 0x0F) << 4;
openjtag_add_byte(command);
cycles -= 16;
} while (cycles > 0);
}
tap_set_end_state(end_state);

View File

@ -236,7 +236,7 @@ static int freertos_get_thread_reg_value(struct rtos *rtos, threadid_t thread_id
static int freertos_set_reg(struct rtos *rtos, uint32_t reg_num, uint8_t *reg_value);
static int freertos_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]);
struct rtos_type freertos_rtos = {
const struct rtos_type freertos_rtos = {
.name = "FreeRTOS",
.detect_rtos = freertos_detect_rtos,

View File

@ -21,6 +21,7 @@ noinst_LTLIBRARIES += %D%/librtos.la
%D%/mqx.c \
%D%/uCOS-III.c \
%D%/nuttx.c \
%D%/rtkernel.c \
%D%/hwthread.c \
%D%/zephyr.c \
%D%/riot.c \
@ -33,5 +34,4 @@ noinst_LTLIBRARIES += %D%/librtos.la
%D%/rtos_mqx_stackings.h \
%D%/rtos_riot_stackings.h \
%D%/rtos_ucos_iii_stackings.h \
%D%/rtos_nuttx_stackings.h \
%D%/nuttx_header.h
%D%/rtos_nuttx_stackings.h

View File

@ -97,7 +97,7 @@ static int chibios_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
struct rtos_reg **reg_list, int *num_regs);
static int chibios_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]);
struct rtos_type chibios_rtos = {
const struct rtos_type chibios_rtos = {
.name = "chibios",
.detect_rtos = chibios_detect_rtos,

View File

@ -27,7 +27,7 @@ static int embkernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
struct rtos_reg **reg_list, int *num_regs);
static int embkernel_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]);
struct rtos_type embkernel_rtos = {
const struct rtos_type embkernel_rtos = {
.name = "embKernel",
.detect_rtos = embkernel_detect_rtos,
.create = embkernel_create,

View File

@ -498,7 +498,7 @@ static int mqx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]
return ERROR_OK;
}
struct rtos_type mqx_rtos = {
const struct rtos_type mqx_rtos = {
.name = "mqx",
.detect_rtos = mqx_detect_rtos,
.create = mqx_create,

View File

@ -18,53 +18,60 @@
#include "rtos.h"
#include "helper/log.h"
#include "helper/types.h"
#include "server/gdb_server.h"
#include "nuttx_header.h"
#include "target/register.h"
#include "rtos_nuttx_stackings.h"
int rtos_thread_packet(struct connection *connection, const char *packet, int packet_size);
#define NAME_SIZE 32
#define EXTRAINFO_SIZE 256
#ifdef CONFIG_DISABLE_SIGNALS
#define SIG_QUEUE_NUM 0
#else
#define SIG_QUEUE_NUM 1
#endif /* CONFIG_DISABLE_SIGNALS */
/* Only 32-bit CPUs are supported by the current implementation. Supporting
* other CPUs will require reading this information from the target and
* adapting the code accordingly.
*/
#define PTR_WIDTH 4
#ifdef CONFIG_DISABLE_MQUEUE
#define M_QUEUE_NUM 0
#else
#define M_QUEUE_NUM 2
#endif /* CONFIG_DISABLE_MQUEUE */
#ifdef CONFIG_PAGING
#define PAGING_QUEUE_NUM 1
#else
#define PAGING_QUEUE_NUM 0
#endif /* CONFIG_PAGING */
#define TASK_QUEUE_NUM (6 + SIG_QUEUE_NUM + M_QUEUE_NUM + PAGING_QUEUE_NUM)
/* see nuttx/sched/os_start.c */
static char *nuttx_symbol_list[] = {
"g_readytorun", /* 0: must be top of this array */
"g_tasklisttable",
NULL
struct nuttx_params {
const char *target_name;
const struct rtos_register_stacking *stacking;
const struct rtos_register_stacking *(*select_stackinfo)(struct target *target);
};
/* see nuttx/include/nuttx/sched.h */
struct tcb {
uint32_t flink;
uint32_t blink;
uint8_t dat[512];
/*
* struct tcbinfo_s is located in the sched.h
* https://github.com/apache/nuttx/blob/master/include/nuttx/sched.h
*/
#define TCBINFO_TARGET_SIZE 22
struct tcbinfo {
uint16_t pid_off; /* Offset of tcb.pid */
uint16_t state_off; /* Offset of tcb.task_state */
uint16_t pri_off; /* Offset of tcb.sched_priority */
uint16_t name_off; /* Offset of tcb.name */
uint16_t regs_off; /* Offset of tcb.regs */
uint16_t basic_num; /* Num of genernal regs */
uint16_t total_num; /* Num of regs in tcbinfo.reg_offs */
target_addr_t xcpreg_off; /* Offset pointer of xcp.regs */
};
static struct {
uint32_t addr;
uint32_t prio;
} g_tasklist[TASK_QUEUE_NUM];
struct symbols {
const char *name;
bool optional;
};
/* Used to index the list of retrieved symbols. See nuttx_symbol_list for the order. */
enum nuttx_symbol_vals {
NX_SYM_READYTORUN = 0,
NX_SYM_PIDHASH,
NX_SYM_NPIDHASH,
NX_SYM_TCB_INFO,
};
static const struct symbols nuttx_symbol_list[] = {
{ "g_readytorun", false },
{ "g_pidhash", false },
{ "g_npidhash", false },
{ "g_tcbinfo", false },
{ NULL, false }
};
static char *task_state_str[] = {
"INVALID",
@ -73,261 +80,363 @@ static char *task_state_str[] = {
"RUNNING",
"INACTIVE",
"WAIT_SEM",
#ifndef CONFIG_DISABLE_SIGNALS
"WAIT_SIG",
#endif /* CONFIG_DISABLE_SIGNALS */
#ifndef CONFIG_DISABLE_MQUEUE
"WAIT_MQNOTEMPTY",
"WAIT_MQNOTFULL",
#endif /* CONFIG_DISABLE_MQUEUE */
#ifdef CONFIG_PAGING
"WAIT_PAGEFILL",
#endif /* CONFIG_PAGING */
"STOPPED",
};
static int pid_offset = PID;
static int state_offset = STATE;
static int name_offset = NAME;
static int xcpreg_offset = XCPREG;
static int name_size = NAME_SIZE;
static const struct rtos_register_stacking *cortexm_select_stackinfo(struct target *target);
static int rcmd_offset(const char *cmd, const char *name)
static const struct nuttx_params nuttx_params_list[] = {
{
.target_name = "cortex_m",
.stacking = NULL,
.select_stackinfo = cortexm_select_stackinfo,
},
{
.target_name = "hla_target",
.stacking = NULL,
.select_stackinfo = cortexm_select_stackinfo,
},
{
.target_name = "esp32",
.stacking = &nuttx_esp32_stacking,
},
{
.target_name = "esp32s2",
.stacking = &nuttx_esp32s2_stacking,
},
{
.target_name = "esp32s3",
.stacking = &nuttx_esp32s3_stacking,
},
{
.target_name = "esp32c3",
.stacking = &nuttx_riscv_stacking,
},
};
static bool cortexm_hasfpu(struct target *target)
{
if (strncmp(cmd, name, strlen(name)))
return -1;
uint32_t cpacr;
struct armv7m_common *armv7m_target = target_to_armv7m(target);
if (strlen(cmd) <= strlen(name) + 1)
return -1;
if (!is_armv7m(armv7m_target) || armv7m_target->fp_feature == FP_NONE)
return false;
return atoi(cmd + strlen(name));
}
static int nuttx_thread_packet(struct connection *connection,
char const *packet, int packet_size)
{
char cmd[GDB_BUFFER_SIZE / 2 + 1] = ""; /* Extra byte for null-termination */
if (!strncmp(packet, "qRcmd", 5)) {
size_t len = unhexify((uint8_t *)cmd, packet + 6, sizeof(cmd));
int offset;
if (len <= 0)
goto pass;
offset = rcmd_offset(cmd, "nuttx.pid_offset");
if (offset >= 0) {
LOG_INFO("pid_offset: %d", offset);
pid_offset = offset;
goto retok;
}
offset = rcmd_offset(cmd, "nuttx.state_offset");
if (offset >= 0) {
LOG_INFO("state_offset: %d", offset);
state_offset = offset;
goto retok;
}
offset = rcmd_offset(cmd, "nuttx.name_offset");
if (offset >= 0) {
LOG_INFO("name_offset: %d", offset);
name_offset = offset;
goto retok;
}
offset = rcmd_offset(cmd, "nuttx.xcpreg_offset");
if (offset >= 0) {
LOG_INFO("xcpreg_offset: %d", offset);
xcpreg_offset = offset;
goto retok;
}
offset = rcmd_offset(cmd, "nuttx.name_size");
if (offset >= 0) {
LOG_INFO("name_size: %d", offset);
name_size = offset;
goto retok;
}
int retval = target_read_u32(target, FPU_CPACR, &cpacr);
if (retval != ERROR_OK) {
LOG_ERROR("Could not read CPACR register to check FPU state");
return false;
}
pass:
return rtos_thread_packet(connection, packet, packet_size);
retok:
gdb_put_packet(connection, "OK", 2);
return ERROR_OK;
return cpacr & 0x00F00000;
}
static const struct rtos_register_stacking *cortexm_select_stackinfo(struct target *target)
{
return cortexm_hasfpu(target) ? &nuttx_stacking_cortex_m_fpu : &nuttx_stacking_cortex_m;
}
static bool nuttx_detect_rtos(struct target *target)
{
if ((target->rtos->symbols) &&
(target->rtos->symbols[0].address != 0) &&
(target->rtos->symbols[1].address != 0)) {
if (target->rtos->symbols &&
target->rtos->symbols[NX_SYM_READYTORUN].address != 0 &&
target->rtos->symbols[NX_SYM_PIDHASH].address != 0)
return true;
}
return false;
}
static int nuttx_create(struct target *target)
{
const struct nuttx_params *param;
unsigned int i;
target->rtos->gdb_thread_packet = nuttx_thread_packet;
LOG_INFO("target type name = %s", target->type->name);
return 0;
for (i = 0; i < ARRAY_SIZE(nuttx_params_list); i++) {
param = &nuttx_params_list[i];
if (strcmp(target_type_name(target), param->target_name) == 0) {
LOG_INFO("Detected target \"%s\"", param->target_name);
break;
}
}
if (i >= ARRAY_SIZE(nuttx_params_list)) {
LOG_ERROR("Could not find \"%s\" target in NuttX compatibility list", target_type_name(target));
return JIM_ERR;
}
/* We found a target in our list, copy its reference. */
target->rtos->rtos_specific_params = (void *)param;
return JIM_OK;
}
static int nuttx_smp_init(struct target *target)
{
/* Return OK for now so that the initialisation sequence doesn't stop.
* SMP case will be implemented later. */
return ERROR_OK;
}
static target_addr_t target_buffer_get_addr(struct target *target, const uint8_t *buffer)
{
#if PTR_WIDTH == 8
return target_buffer_get_u64(target, buffer);
#else
return target_buffer_get_u32(target, buffer);
#endif
}
static int nuttx_update_threads(struct rtos *rtos)
{
uint32_t thread_count;
struct tcb tcb;
int ret;
uint32_t head;
uint32_t tcb_addr;
uint32_t i;
struct tcbinfo tcbinfo;
uint32_t pidhashaddr, npidhash, tcbaddr;
uint16_t pid;
uint8_t state;
if (!rtos->symbols) {
LOG_ERROR("No symbols for NuttX");
return -3;
}
/* free previous thread details */
rtos_free_threadlist(rtos);
ret = target_read_buffer(rtos->target, rtos->symbols[1].address,
sizeof(g_tasklist), (uint8_t *)&g_tasklist);
if (ret) {
LOG_ERROR("target_read_buffer : ret = %d\n", ret);
LOG_ERROR("No symbols for nuttx");
return ERROR_FAIL;
}
thread_count = 0;
/* Free previous thread details */
rtos_free_threadlist(rtos);
for (i = 0; i < TASK_QUEUE_NUM; i++) {
/* NuttX provides a hash table that keeps track of all the TCBs.
* We first read its size from g_npidhash and its address from g_pidhash.
* Its content is then read from these values.
*/
int ret = target_read_u32(rtos->target, rtos->symbols[NX_SYM_NPIDHASH].address, &npidhash);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to read g_npidhash: ret = %d", ret);
return ERROR_FAIL;
}
if (g_tasklist[i].addr == 0)
LOG_DEBUG("Hash table size (g_npidhash) = %" PRId32, npidhash);
ret = target_read_u32(rtos->target, rtos->symbols[NX_SYM_PIDHASH].address, &pidhashaddr);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to read g_pidhash address: ret = %d", ret);
return ERROR_FAIL;
}
LOG_DEBUG("Hash table address (g_pidhash) = %" PRIx32, pidhashaddr);
uint8_t *pidhash = malloc(npidhash * PTR_WIDTH);
if (!pidhash) {
LOG_ERROR("Failed to allocate pidhash");
return ERROR_FAIL;
}
ret = target_read_buffer(rtos->target, pidhashaddr, PTR_WIDTH * npidhash, pidhash);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to read tcbhash: ret = %d", ret);
goto errout;
}
/* NuttX provides a struct that contains TCB offsets for required members.
* Read its content from g_tcbinfo.
*/
uint8_t buff[TCBINFO_TARGET_SIZE];
ret = target_read_buffer(rtos->target, rtos->symbols[NX_SYM_TCB_INFO].address, sizeof(buff), buff);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to read tcbinfo: ret = %d", ret);
goto errout;
}
tcbinfo.pid_off = target_buffer_get_u16(rtos->target, buff);
tcbinfo.state_off = target_buffer_get_u16(rtos->target, buff + 2);
tcbinfo.pri_off = target_buffer_get_u16(rtos->target, buff + 4);
tcbinfo.name_off = target_buffer_get_u16(rtos->target, buff + 6);
tcbinfo.regs_off = target_buffer_get_u16(rtos->target, buff + 8);
tcbinfo.basic_num = target_buffer_get_u16(rtos->target, buff + 10);
tcbinfo.total_num = target_buffer_get_u16(rtos->target, buff + 12);
tcbinfo.xcpreg_off = target_buffer_get_addr(rtos->target, buff + 14);
/* The head of the g_readytorun list is the currently running task.
* Reading in a temporary variable first to avoid endianness issues,
* rtos->current_thread is int64_t. */
uint32_t current_thread;
ret = target_read_u32(rtos->target, rtos->symbols[NX_SYM_READYTORUN].address, &current_thread);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to read g_readytorun: ret = %d", ret);
goto errout;
}
rtos->current_thread = current_thread;
uint32_t thread_count = 0;
for (unsigned int i = 0; i < npidhash; i++) {
tcbaddr = target_buffer_get_u32(rtos->target, &pidhash[i * PTR_WIDTH]);
if (!tcbaddr)
continue;
ret = target_read_u32(rtos->target, g_tasklist[i].addr,
&head);
if (ret) {
LOG_ERROR("target_read_u32 : ret = %d\n", ret);
return ERROR_FAIL;
ret = target_read_u16(rtos->target, tcbaddr + tcbinfo.pid_off, &pid);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to read PID of TCB@0x%x from pidhash[%d]: ret = %d",
tcbaddr, i, ret);
goto errout;
}
/* readytorun head is current thread */
if (g_tasklist[i].addr == rtos->symbols[0].address)
rtos->current_thread = head;
ret = target_read_u8(rtos->target, tcbaddr + tcbinfo.state_off, &state);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to read state of TCB@0x%x from pidhash[%d]: ret = %d",
tcbaddr, i, ret);
goto errout;
}
struct thread_detail *new_thread_details = realloc(rtos->thread_details,
sizeof(struct thread_detail) * (thread_count + 1));
if (!new_thread_details) {
ret = ERROR_FAIL;
goto errout;
}
tcb_addr = head;
while (tcb_addr) {
struct thread_detail *thread;
ret = target_read_buffer(rtos->target, tcb_addr,
sizeof(tcb), (uint8_t *)&tcb);
if (ret) {
LOG_ERROR("target_read_buffer : ret = %d\n",
ret);
return ERROR_FAIL;
struct thread_detail *thread = &new_thread_details[thread_count];
thread->threadid = tcbaddr;
thread->exists = true;
thread->extra_info_str = NULL;
rtos->thread_details = new_thread_details;
thread_count++;
if (state < ARRAY_SIZE(task_state_str)) {
thread->extra_info_str = malloc(EXTRAINFO_SIZE);
if (!thread->extra_info_str) {
ret = ERROR_FAIL;
goto errout;
}
thread_count++;
snprintf(thread->extra_info_str, EXTRAINFO_SIZE, "pid:%d, %s",
pid,
task_state_str[state]);
}
rtos->thread_details = realloc(rtos->thread_details,
sizeof(struct thread_detail) * thread_count);
thread = &rtos->thread_details[thread_count - 1];
thread->threadid = tcb_addr;
thread->exists = true;
state = tcb.dat[state_offset - 8];
thread->extra_info_str = NULL;
if (state < ARRAY_SIZE(task_state_str)) {
thread->extra_info_str = malloc(256);
snprintf(thread->extra_info_str, 256, "pid:%d, %s",
tcb.dat[pid_offset - 8] |
tcb.dat[pid_offset - 8 + 1] << 8,
task_state_str[state]);
if (tcbinfo.name_off) {
thread->thread_name_str = calloc(NAME_SIZE + 1, sizeof(char));
if (!thread->thread_name_str) {
ret = ERROR_FAIL;
goto errout;
}
if (name_offset) {
thread->thread_name_str = malloc(name_size + 1);
snprintf(thread->thread_name_str, name_size,
"%s", (char *)&tcb.dat[name_offset - 8]);
} else {
thread->thread_name_str = malloc(sizeof("None"));
strcpy(thread->thread_name_str, "None");
ret = target_read_buffer(rtos->target, tcbaddr + tcbinfo.name_off,
sizeof(char) * NAME_SIZE, (uint8_t *)thread->thread_name_str);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to read thread's name: ret = %d", ret);
goto errout;
}
tcb_addr = tcb.flink;
} else {
thread->thread_name_str = strdup("None");
}
}
rtos->thread_count = thread_count;
return 0;
ret = ERROR_OK;
rtos->thread_count = thread_count;
errout:
free(pidhash);
return ret;
}
static int nuttx_getreg_current_thread(struct rtos *rtos,
struct rtos_reg **reg_list, int *num_regs)
{
struct reg **gdb_reg_list;
/* Registers for currently running thread are not on task's stack and
* should be retrieved from reg caches via target_get_gdb_reg_list */
int ret = target_get_gdb_reg_list(rtos->target, &gdb_reg_list, num_regs,
REG_CLASS_GENERAL);
if (ret != ERROR_OK) {
LOG_ERROR("target_get_gdb_reg_list failed %d", ret);
return ret;
}
*reg_list = calloc(*num_regs, sizeof(struct rtos_reg));
if (!(*reg_list)) {
LOG_ERROR("Failed to alloc memory for %d", *num_regs);
free(gdb_reg_list);
return ERROR_FAIL;
}
for (int i = 0; i < *num_regs; i++) {
(*reg_list)[i].number = gdb_reg_list[i]->number;
(*reg_list)[i].size = gdb_reg_list[i]->size;
memcpy((*reg_list)[i].value, gdb_reg_list[i]->value, ((*reg_list)[i].size + 7) / 8);
}
free(gdb_reg_list);
return ERROR_OK;
}
static int nuttx_getregs_fromstack(struct rtos *rtos, int64_t thread_id,
struct rtos_reg **reg_list, int *num_regs)
{
uint16_t xcpreg_off;
uint32_t regsaddr;
const struct nuttx_params *priv = rtos->rtos_specific_params;
const struct rtos_register_stacking *stacking = priv->stacking;
if (!stacking) {
if (priv->select_stackinfo) {
stacking = priv->select_stackinfo(rtos->target);
} else {
LOG_ERROR("Can't find a way to get stacking info");
return ERROR_FAIL;
}
}
int ret = target_read_u16(rtos->target,
rtos->symbols[NX_SYM_TCB_INFO].address + offsetof(struct tcbinfo, regs_off),
&xcpreg_off);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to read registers' offset: ret = %d", ret);
return ERROR_FAIL;
}
ret = target_read_u32(rtos->target, thread_id + xcpreg_off, &regsaddr);
if (ret != ERROR_OK) {
LOG_ERROR("Failed to read registers' address: ret = %d", ret);
return ERROR_FAIL;
}
return rtos_generic_stack_read(rtos->target, stacking, regsaddr, reg_list, num_regs);
}
/*
* thread_id = tcb address;
*/
static int nuttx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
struct rtos_reg **reg_list, int *num_regs)
{
int retval;
/* Check for armv7m with *enabled* FPU, i.e. a Cortex-M4F */
bool cm4_fpu_enabled = false;
struct armv7m_common *armv7m_target = target_to_armv7m(rtos->target);
if (is_armv7m(armv7m_target)) {
if (armv7m_target->fp_feature == FPV4_SP) {
/* Found ARM v7m target which includes a FPU */
uint32_t cpacr;
retval = target_read_u32(rtos->target, FPU_CPACR, &cpacr);
if (retval != ERROR_OK) {
LOG_ERROR("Could not read CPACR register to check FPU state");
return -1;
}
/* Check if CP10 and CP11 are set to full access. */
if (cpacr & 0x00F00000) {
/* Found target with enabled FPU */
cm4_fpu_enabled = 1;
}
}
if (!rtos) {
LOG_ERROR("NUTTX: out of memory");
return ERROR_FAIL;
}
const struct rtos_register_stacking *stacking;
if (cm4_fpu_enabled)
stacking = &nuttx_stacking_cortex_m_fpu;
else
stacking = &nuttx_stacking_cortex_m;
return rtos_generic_stack_read(rtos->target, stacking,
(uint32_t)thread_id + xcpreg_offset, reg_list, num_regs);
if (thread_id == rtos->current_thread)
return nuttx_getreg_current_thread(rtos, reg_list, num_regs);
return nuttx_getregs_fromstack(rtos, thread_id, reg_list, num_regs);
}
static int nuttx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
{
unsigned int i;
*symbol_list = calloc(ARRAY_SIZE(nuttx_symbol_list), sizeof(**symbol_list));
if (!*symbol_list) {
LOG_ERROR("NUTTX: out of memory");
return ERROR_FAIL;
}
*symbol_list = (struct symbol_table_elem *) calloc(1,
sizeof(struct symbol_table_elem) * ARRAY_SIZE(nuttx_symbol_list));
for (unsigned int i = 0; i < ARRAY_SIZE(nuttx_symbol_list); i++) {
(*symbol_list)[i].symbol_name = nuttx_symbol_list[i].name;
(*symbol_list)[i].optional = nuttx_symbol_list[i].optional;
}
for (i = 0; i < ARRAY_SIZE(nuttx_symbol_list); i++)
(*symbol_list)[i].symbol_name = nuttx_symbol_list[i];
return 0;
return ERROR_OK;
}
struct rtos_type nuttx_rtos = {
const struct rtos_type nuttx_rtos = {
.name = "nuttx",
.detect_rtos = nuttx_detect_rtos,
.create = nuttx_create,
.smp_init = nuttx_smp_init,
.update_threads = nuttx_update_threads,
.get_thread_reg_list = nuttx_get_thread_reg_list,
.get_symbol_list_to_lookup = nuttx_get_symbol_list_to_lookup,

View File

@ -1,60 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/***************************************************************************
* Copyright 2016,2017 Sony Video & Sound Products Inc. *
* Masatoshi Tateishi - Masatoshi.Tateishi@jp.sony.com *
* Masayuki Ishikawa - Masayuki.Ishikawa@jp.sony.com *
***************************************************************************/
#ifndef OPENOCD_RTOS_NUTTX_HEADER_H
#define OPENOCD_RTOS_NUTTX_HEADER_H
/* gdb script to update the header file
according to kernel version and build option
before executing function awareness
kernel symbol must be loaded : symbol nuttx
define awareness
set logging off
set logging file nuttx_header.h
set logging on
printf "#define PID %p\n",&((struct tcb_s *)(0))->pid
printf "#define XCPREG %p\n",&((struct tcb_s *)(0))->xcp.regs
printf "#define STATE %p\n",&((struct tcb_s *)(0))->task_state
printf "#define NAME %p\n",&((struct tcb_s *)(0))->name
printf "#define NAME_SIZE %d\n",sizeof(((struct tcb_s *)(0))->name)
end
OR ~/.gdbinit
define hookpost-file
if &g_readytorun != 0
eval "monitor nuttx.pid_offset %d", &((struct tcb_s *)(0))->pid
eval "monitor nuttx.xcpreg_offset %d", &((struct tcb_s *)(0))->xcp.regs
eval "monitor nuttx.state_offset %d", &((struct tcb_s *)(0))->task_state
eval "monitor nuttx.name_offset %d", &((struct tcb_s *)(0))->name
eval "monitor nuttx.name_size %d", sizeof(((struct tcb_s *)(0))->name)
end
end
*/
/* default offset */
#define PID 0xc
#define XCPREG 0x70
#define STATE 0x19
#define NAME 0xb8
#define NAME_SIZE 32
/* defconfig of nuttx */
/* #define CONFIG_DISABLE_SIGNALS */
#define CONFIG_DISABLE_MQUEUE
/* #define CONFIG_PAGING */
#endif /* OPENOCD_RTOS_NUTTX_HEADER_H */

384
src/rtos/rtkernel.c Normal file
View File

@ -0,0 +1,384 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/***************************************************************************
* Copyright (C) 2016-2023 by Andreas Fritiofson *
* andreas.fritiofson@gmail.com *
***************************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <helper/time_support.h>
#include <jtag/jtag.h>
#include "target/target.h"
#include "target/target_type.h"
#include "rtos.h"
#include "helper/log.h"
#include "helper/types.h"
#include "rtos_standard_stackings.h"
#include "target/armv7m.h"
#include "target/cortex_m.h"
#define ST_DEAD BIT(0) /* Task is waiting to be deleted */
#define ST_WAIT BIT(1) /* Task is blocked: */
#define ST_SEM BIT(2) /* on semaphore */
#define ST_MTX BIT(3) /* on mutex */
#define ST_SIG BIT(4) /* on signal */
#define ST_DLY BIT(5) /* on timer */
#define ST_FLAG BIT(6) /* on flag */
#define ST_FLAG_ALL BIT(7) /* on flag and flag mode is "ALL" */
#define ST_MBOX BIT(8) /* on mailbox */
#define ST_STP BIT(9) /* self stopped */
#define ST_SUSPEND BIT(10) /* Task is suspended */
#define ST_TT BIT(11) /* Time triggered task */
#define ST_TT_YIELD BIT(12) /* Time triggered task that yields */
#define ST_CREATE BIT(13) /* Task was created by task_create() */
struct rtkernel_params {
const char *target_name;
const struct rtos_register_stacking *stacking_info_cm3;
const struct rtos_register_stacking *stacking_info_cm4f;
const struct rtos_register_stacking *stacking_info_cm4f_fpu;
};
static const struct rtkernel_params rtkernel_params_list[] = {
{
"cortex_m", /* target_name */
&rtos_standard_cortex_m3_stacking, /* stacking_info */
&rtos_standard_cortex_m4f_stacking,
&rtos_standard_cortex_m4f_fpu_stacking,
},
{
"hla_target", /* target_name */
&rtos_standard_cortex_m3_stacking, /* stacking_info */
&rtos_standard_cortex_m4f_stacking,
&rtos_standard_cortex_m4f_fpu_stacking,
},
};
enum rtkernel_symbol_values {
sym_os_state = 0,
sym___off_os_state2chain = 1,
sym___off_os_state2current = 2,
sym___off_task2chain = 3,
sym___off_task2magic = 4,
sym___off_task2stack = 5,
sym___off_task2state = 6,
sym___off_task2name = 7,
sym___val_task_magic = 8,
};
struct symbols {
const char *name;
bool optional;
};
static const struct symbols rtkernel_symbol_list[] = {
{ "os_state", false },
{ "__off_os_state2chain", false },
{ "__off_os_state2current", false },
{ "__off_task2chain", false },
{ "__off_task2magic", false },
{ "__off_task2stack", false },
{ "__off_task2state", false },
{ "__off_task2name", false },
{ "__val_task_magic", false },
{ NULL, false }
};
static void *realloc_preserve(void *ptr, size_t old_size, size_t new_size)
{
void *new_ptr = malloc(new_size);
if (new_ptr) {
memcpy(new_ptr, ptr, MIN(old_size, new_size));
free(ptr);
}
return new_ptr;
}
static int rtkernel_add_task(struct rtos *rtos, uint32_t task, uint32_t current_task)
{
int retval;
int new_thread_count = rtos->thread_count + 1;
struct thread_detail *new_thread_details = realloc_preserve(rtos->thread_details,
rtos->thread_count * sizeof(struct thread_detail),
new_thread_count * sizeof(struct thread_detail));
if (!new_thread_details) {
LOG_ERROR("Error growing memory to %d threads", new_thread_count);
return ERROR_FAIL;
}
rtos->thread_details = new_thread_details;
struct thread_detail *thread = &new_thread_details[rtos->thread_count];
*thread = (struct thread_detail){ .threadid = task, .exists = true };
/* Read the task name */
uint32_t name;
retval = target_read_u32(rtos->target, task + rtos->symbols[sym___off_task2name].address, &name);
if (retval != ERROR_OK) {
LOG_ERROR("Could not read task name pointer from target");
return retval;
}
uint8_t tmp_str[33];
retval = target_read_buffer(rtos->target, name, sizeof(tmp_str) - 1, tmp_str);
if (retval != ERROR_OK) {
LOG_ERROR("Error reading task name from target");
return retval;
}
tmp_str[sizeof(tmp_str) - 1] = '\0';
LOG_DEBUG("task name at 0x%" PRIx32 ", value \"%s\"", name, tmp_str);
if (tmp_str[0] != '\0')
thread->thread_name_str = strdup((char *)tmp_str);
else
thread->thread_name_str = strdup("No Name");
/* Read the task state */
uint16_t state;
retval = target_read_u16(rtos->target, task + rtos->symbols[sym___off_task2state].address, &state);
if (retval != ERROR_OK) {
LOG_ERROR("Could not read task state from target");
return retval;
}
LOG_DEBUG("task state 0x%" PRIx16, state);
char state_str[64] = "";
if (state & ST_TT)
strcat(state_str, "TT|");
if (task == current_task) {
strcat(state_str, "RUN");
} else {
if (state & (ST_TT | ST_TT_YIELD))
strcat(state_str, "YIELD");
else if (state & ST_DEAD)
strcat(state_str, "DEAD");
else if (state & ST_WAIT)
strcat(state_str, "WAIT");
else if (state & ST_SUSPEND)
strcat(state_str, "SUSP");
else
strcat(state_str, "READY");
}
if (state & ST_SEM)
strcat(state_str, "|SEM");
if (state & ST_MTX)
strcat(state_str, "|MTX");
if (state & ST_SIG)
strcat(state_str, "|SIG");
if (state & ST_DLY)
strcat(state_str, "|DLY");
if ((state & ST_FLAG) || (state & ST_FLAG_ALL))
strcat(state_str, "|FLAG");
if (state & ST_FLAG_ALL)
strcat(state_str, "_ALL");
if (state & ST_MBOX)
strcat(state_str, "|MBOX");
if (state & ST_STP)
strcat(state_str, "|STP");
thread->extra_info_str = strdup(state_str);
rtos->thread_count = new_thread_count;
if (task == current_task)
rtos->current_thread = task;
return ERROR_OK;
}
static int rtkernel_verify_task(struct rtos *rtos, uint32_t task)
{
int retval;
uint32_t magic;
retval = target_read_u32(rtos->target, task + rtos->symbols[sym___off_task2magic].address, &magic);
if (retval != ERROR_OK) {
LOG_ERROR("Could not read task magic from target");
return retval;
}
if (magic != rtos->symbols[sym___val_task_magic].address) {
LOG_ERROR("Invalid task found (magic=0x%" PRIx32 ")", magic);
return ERROR_FAIL;
}
return retval;
}
static int rtkernel_update_threads(struct rtos *rtos)
{
/* wipe out previous thread details if any */
/* do this first because rtos layer does not check our retval */
rtos_free_threadlist(rtos);
rtos->current_thread = 0;
if (!rtos->symbols) {
LOG_ERROR("No symbols for rt-kernel");
return -3;
}
/* read the current task */
uint32_t current_task;
int retval = target_read_u32(rtos->target,
rtos->symbols[sym_os_state].address + rtos->symbols[sym___off_os_state2current].address,
&current_task);
if (retval != ERROR_OK) {
LOG_ERROR("Error reading current task");
return retval;
}
LOG_DEBUG("current task is 0x%" PRIx32, current_task);
retval = rtkernel_verify_task(rtos, current_task);
if (retval != ERROR_OK) {
LOG_ERROR("Current task is invalid");
return retval;
}
/* loop through kernel task list */
uint32_t chain = rtos->symbols[sym_os_state].address + rtos->symbols[sym___off_os_state2chain].address;
LOG_DEBUG("chain start at 0x%" PRIx32, chain);
uint32_t next = chain;
for (;;) {
retval = target_read_u32(rtos->target, next, &next);
if (retval != ERROR_OK) {
LOG_ERROR("Could not read rt-kernel data structure from target");
return retval;
}
LOG_DEBUG("next entry at 0x%" PRIx32, next);
if (next == chain) {
LOG_DEBUG("end of chain detected");
break;
}
uint32_t task = next - rtos->symbols[sym___off_task2chain].address;
LOG_DEBUG("found task at 0x%" PRIx32, task);
retval = rtkernel_verify_task(rtos, task);
if (retval != ERROR_OK) {
LOG_ERROR("Invalid task found");
return retval;
}
retval = rtkernel_add_task(rtos, task, current_task);
if (retval != ERROR_OK) {
LOG_ERROR("Could not add task to rtos system");
return retval;
}
}
return ERROR_OK;
}
static int rtkernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
struct rtos_reg **reg_list, int *num_regs)
{
uint32_t stack_ptr = 0;
if (!rtos)
return -1;
if (thread_id == 0)
return -2;
if (!rtos->rtos_specific_params)
return -1;
const struct rtkernel_params *param = rtos->rtos_specific_params;
/* Read the stack pointer */
int retval = target_read_u32(rtos->target, thread_id + rtos->symbols[sym___off_task2stack].address, &stack_ptr);
if (retval != ERROR_OK) {
LOG_ERROR("Error reading stack pointer from rtkernel thread");
return retval;
}
LOG_DEBUG("stack pointer at 0x%" PRIx64 ", value 0x%" PRIx32,
thread_id + rtos->symbols[sym___off_task2stack].address,
stack_ptr);
/* Adjust stack pointer to ignore non-standard BASEPRI register stacking */
stack_ptr += 4;
/* Check for armv7m with *enabled* FPU, i.e. a Cortex M4F */
bool cm4_fpu_enabled = false;
struct armv7m_common *armv7m_target = target_to_armv7m(rtos->target);
if (is_armv7m(armv7m_target)) {
if (armv7m_target->fp_feature != FP_NONE) {
/* Found ARM v7m target which includes a FPU */
uint32_t cpacr;
retval = target_read_u32(rtos->target, FPU_CPACR, &cpacr);
if (retval != ERROR_OK) {
LOG_ERROR("Could not read CPACR register to check FPU state");
return -1;
}
/* Check if CP10 and CP11 are set to full access. */
if (cpacr & 0x00F00000) {
/* Found target with enabled FPU */
cm4_fpu_enabled = true;
}
}
}
if (!cm4_fpu_enabled) {
LOG_DEBUG("cm3 stacking");
return rtos_generic_stack_read(rtos->target, param->stacking_info_cm3, stack_ptr, reg_list, num_regs);
}
/* Read the LR to decide between stacking with or without FPU */
uint32_t lr_svc;
retval = target_read_u32(rtos->target, stack_ptr + 0x20, &lr_svc);
if (retval != ERROR_OK) {
LOG_OUTPUT("Error reading stack frame from rtkernel thread\r\n");
return retval;
}
if ((lr_svc & 0x10) == 0) {
LOG_DEBUG("cm4f_fpu stacking");
return rtos_generic_stack_read(rtos->target, param->stacking_info_cm4f_fpu, stack_ptr, reg_list, num_regs);
}
LOG_DEBUG("cm4f stacking");
return rtos_generic_stack_read(rtos->target, param->stacking_info_cm4f, stack_ptr, reg_list, num_regs);
}
static int rtkernel_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
{
*symbol_list = calloc(ARRAY_SIZE(rtkernel_symbol_list), sizeof(struct symbol_table_elem));
if (!*symbol_list)
return ERROR_FAIL;
for (size_t i = 0; i < ARRAY_SIZE(rtkernel_symbol_list); i++) {
(*symbol_list)[i].symbol_name = rtkernel_symbol_list[i].name;
(*symbol_list)[i].optional = rtkernel_symbol_list[i].optional;
}
return ERROR_OK;
}
static bool rtkernel_detect_rtos(struct target *target)
{
return (target->rtos->symbols) &&
(target->rtos->symbols[sym___off_os_state2chain].address != 0);
}
static int rtkernel_create(struct target *target)
{
for (size_t i = 0; i < ARRAY_SIZE(rtkernel_params_list); i++) {
if (strcmp(rtkernel_params_list[i].target_name, target->type->name) == 0) {
target->rtos->rtos_specific_params = (void *)&rtkernel_params_list[i];
return 0;
}
}
LOG_ERROR("Could not find target in rt-kernel compatibility list");
return -1;
}
const struct rtos_type rtkernel_rtos = {
.name = "rtkernel",
.detect_rtos = rtkernel_detect_rtos,
.create = rtkernel_create,
.update_threads = rtkernel_update_threads,
.get_thread_reg_list = rtkernel_get_thread_reg_list,
.get_symbol_list_to_lookup = rtkernel_get_symbol_list_to_lookup,
};

View File

@ -17,21 +17,22 @@
#include "server/gdb_server.h"
/* RTOSs */
extern struct rtos_type freertos_rtos;
extern struct rtos_type threadx_rtos;
extern struct rtos_type ecos_rtos;
extern struct rtos_type linux_rtos;
extern struct rtos_type chibios_rtos;
extern struct rtos_type chromium_ec_rtos;
extern struct rtos_type embkernel_rtos;
extern struct rtos_type mqx_rtos;
extern struct rtos_type ucos_iii_rtos;
extern struct rtos_type nuttx_rtos;
extern struct rtos_type hwthread_rtos;
extern struct rtos_type riot_rtos;
extern struct rtos_type zephyr_rtos;
extern const struct rtos_type freertos_rtos;
extern const struct rtos_type threadx_rtos;
extern const struct rtos_type ecos_rtos;
extern const struct rtos_type linux_rtos;
extern const struct rtos_type chibios_rtos;
extern const struct rtos_type chromium_ec_rtos;
extern const struct rtos_type embkernel_rtos;
extern const struct rtos_type mqx_rtos;
extern const struct rtos_type ucos_iii_rtos;
extern const struct rtos_type nuttx_rtos;
extern const struct rtos_type hwthread_rtos;
extern const struct rtos_type riot_rtos;
extern const struct rtos_type zephyr_rtos;
extern const struct rtos_type rtkernel_rtos;
static struct rtos_type *rtos_types[] = {
static const struct rtos_type *rtos_types[] = {
&threadx_rtos,
&freertos_rtos,
&ecos_rtos,
@ -44,6 +45,7 @@ static struct rtos_type *rtos_types[] = {
&nuttx_rtos,
&riot_rtos,
&zephyr_rtos,
&rtkernel_rtos,
/* keep this as last, as it always matches with rtos auto */
&hwthread_rtos,
NULL
@ -71,7 +73,7 @@ static int rtos_target_for_threadid(struct connection *connection,
return ERROR_OK;
}
static int os_alloc(struct target *target, struct rtos_type *ostype,
static int os_alloc(struct target *target, const struct rtos_type *ostype,
struct command_context *cmd_ctx)
{
struct rtos *os = target->rtos = calloc(1, sizeof(struct rtos));
@ -103,7 +105,7 @@ static void os_free(struct target *target)
target->rtos = NULL;
}
static int os_alloc_create(struct target *target, struct rtos_type *ostype,
static int os_alloc_create(struct target *target, const struct rtos_type *ostype,
struct command_context *cmd_ctx)
{
int ret = os_alloc(target, ostype, cmd_ctx);
@ -657,7 +659,10 @@ int rtos_generic_stack_read(struct target *target,
if (stacking->stack_growth_direction == 1)
address -= stacking->stack_registers_size;
retval = target_read_buffer(target, address, stacking->stack_registers_size, stack_data);
if (stacking->read_stack)
retval = stacking->read_stack(target, address, stacking, stack_data);
else
retval = target_read_buffer(target, address, stacking->stack_registers_size, stack_data);
if (retval != ERROR_OK) {
free(stack_data);
LOG_ERROR("Error reading stack frame from thread");
@ -800,7 +805,7 @@ int rtos_generic_stack_write_reg(struct target *target,
static int rtos_try_next(struct target *target)
{
struct rtos *os = target->rtos;
struct rtos_type **type = rtos_types;
const struct rtos_type **type = rtos_types;
if (!os)
return 0;

View File

@ -126,7 +126,15 @@ struct rtos_register_stacking {
/* Total number of registers on the stack, including the general ones. This
* may be 0 if there are no additional registers on the stack beyond the
* general ones. */
unsigned total_register_count;
unsigned int total_register_count;
/* Optional field for targets which may have to implement their own stack read function.
* Because stack format can be weird or stack data needed to be edited before passing to the gdb.
*/
int (*read_stack)(struct target *target,
int64_t stack_ptr,
const struct rtos_register_stacking *stacking,
uint8_t *stack_data);
};
#define GDB_THREAD_PACKET_NOT_CONSUMED (-40)

View File

@ -14,6 +14,7 @@
#include "rtos.h"
#include "target/armv7m.h"
#include "rtos_chibios_stackings.h"
static const struct stack_register_offset rtos_chibios_arm_v7m_stack_offsets[ARMV7M_NUM_CORE_REGS] = {
{ ARMV7M_R0, -1, 32 }, /* r0 */

View File

@ -8,10 +8,6 @@
#ifndef OPENOCD_RTOS_RTOS_CHIBIOS_STACKINGS_H
#define OPENOCD_RTOS_RTOS_CHIBIOS_STACKINGS_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "rtos.h"
extern const struct rtos_register_stacking rtos_chibios_arm_v7m_stacking;

View File

@ -5,8 +5,9 @@
#endif
#include "rtos.h"
#include "rtos_standard_stackings.h"
#include "target/armv7m.h"
#include "rtos_standard_stackings.h"
#include "rtos_ecos_stackings.h"
/* For Cortex-M eCos applications the actual thread context register layout can
* be different between active threads of an application depending on whether

View File

@ -3,10 +3,6 @@
#ifndef OPENOCD_RTOS_RTOS_ECOS_STACKINGS_H
#define OPENOCD_RTOS_RTOS_ECOS_STACKINGS_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "rtos.h"
extern const struct rtos_register_stacking rtos_ecos_cortex_m3_stacking;

View File

@ -12,6 +12,7 @@
#include "rtos.h"
#include "target/armv7m.h"
#include "rtos_standard_stackings.h"
#include "rtos_embkernel_stackings.h"
static const struct stack_register_offset rtos_embkernel_cortex_m_stack_offsets[ARMV7M_NUM_CORE_REGS] = {
{ ARMV7M_R0, 0x24, 32 }, /* r0 */

View File

@ -8,10 +8,6 @@
#ifndef OPENOCD_RTOS_RTOS_EMBKERNEL_STACKINGS_H
#define OPENOCD_RTOS_RTOS_EMBKERNEL_STACKINGS_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "rtos.h"
extern const struct rtos_register_stacking rtos_embkernel_cortex_m_stacking;

View File

@ -11,7 +11,7 @@
#include "rtos.h"
#include "target/armv7m.h"
#include "rtos_mqx_stackings.h"
/*
* standard exception stack

View File

@ -8,10 +8,6 @@
#ifndef OPENOCD_RTOS_RTOS_MQX_STACKINGS_H
#define OPENOCD_RTOS_RTOS_MQX_STACKINGS_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "rtos.h"
extern const struct rtos_register_stacking rtos_mqx_arm_v7m_stacking;

View File

@ -108,3 +108,361 @@ const struct rtos_register_stacking nuttx_riscv_stacking = {
.calculate_process_stack = rtos_generic_stack_align8,
.register_offsets = nuttx_stack_offsets_riscv,
};
static int nuttx_esp_xtensa_stack_read(struct target *target,
int64_t stack_ptr, const struct rtos_register_stacking *stacking,
uint8_t *stack_data)
{
int retval = target_read_buffer(target, stack_ptr, stacking->stack_registers_size, stack_data);
if (retval != ERROR_OK)
return retval;
stack_data[4] &= ~0x10; /* Clear exception bit in PS */
return ERROR_OK;
}
static const struct stack_register_offset nuttx_stack_offsets_esp32[] = {
{ 0, 0x00, 32 }, /* PC */
{ 1, 0x08, 32 }, /* A0 */
{ 2, 0x0c, 32 }, /* A1 */
{ 3, 0x10, 32 }, /* A2 */
{ 4, 0x14, 32 }, /* A3 */
{ 5, 0x18, 32 }, /* A4 */
{ 6, 0x1c, 32 }, /* A5 */
{ 7, 0x20, 32 }, /* A6 */
{ 8, 0x24, 32 }, /* A7 */
{ 9, 0x28, 32 }, /* A8 */
{ 10, 0x2c, 32 }, /* A9 */
{ 11, 0x30, 32 }, /* A10 */
{ 12, 0x34, 32 }, /* A11 */
{ 13, 0x38, 32 }, /* A12 */
{ 14, 0x3c, 32 }, /* A13 */
{ 15, 0x40, 32 }, /* A14 */
{ 16, 0x44, 32 }, /* A15 */
/* A16-A63 aren't in the stack frame because they've been flushed to the stack earlier */
{ 17, -1, 32 }, /* A16 */
{ 18, -1, 32 }, /* A17 */
{ 19, -1, 32 }, /* A18 */
{ 20, -1, 32 }, /* A19 */
{ 21, -1, 32 }, /* A20 */
{ 22, -1, 32 }, /* A21 */
{ 23, -1, 32 }, /* A22 */
{ 24, -1, 32 }, /* A23 */
{ 25, -1, 32 }, /* A24 */
{ 26, -1, 32 }, /* A25 */
{ 27, -1, 32 }, /* A26 */
{ 28, -1, 32 }, /* A27 */
{ 29, -1, 32 }, /* A28 */
{ 30, -1, 32 }, /* A29 */
{ 31, -1, 32 }, /* A30 */
{ 32, -1, 32 }, /* A31 */
{ 33, -1, 32 }, /* A32 */
{ 34, -1, 32 }, /* A33 */
{ 35, -1, 32 }, /* A34 */
{ 36, -1, 32 }, /* A35 */
{ 37, -1, 32 }, /* A36 */
{ 38, -1, 32 }, /* A37 */
{ 39, -1, 32 }, /* A38 */
{ 40, -1, 32 }, /* A39 */
{ 41, -1, 32 }, /* A40 */
{ 42, -1, 32 }, /* A41 */
{ 43, -1, 32 }, /* A42 */
{ 44, -1, 32 }, /* A43 */
{ 45, -1, 32 }, /* A44 */
{ 46, -1, 32 }, /* A45 */
{ 47, -1, 32 }, /* A46 */
{ 48, -1, 32 }, /* A47 */
{ 49, -1, 32 }, /* A48 */
{ 50, -1, 32 }, /* A49 */
{ 51, -1, 32 }, /* A50 */
{ 52, -1, 32 }, /* A51 */
{ 53, -1, 32 }, /* A52 */
{ 54, -1, 32 }, /* A53 */
{ 55, -1, 32 }, /* A54 */
{ 56, -1, 32 }, /* A55 */
{ 57, -1, 32 }, /* A56 */
{ 58, -1, 32 }, /* A57 */
{ 59, -1, 32 }, /* A58 */
{ 60, -1, 32 }, /* A59 */
{ 61, -1, 32 }, /* A60 */
{ 62, -1, 32 }, /* A61 */
{ 63, -1, 32 }, /* A62 */
{ 64, -1, 32 }, /* A63 */
{ 65, 0x58, 32 }, /* lbeg */
{ 66, 0x5c, 32 }, /* lend */
{ 67, 0x60, 32 }, /* lcount */
{ 68, 0x48, 32 }, /* SAR */
{ 69, -1, 32 }, /* windowbase */
{ 70, -1, 32 }, /* windowstart */
{ 71, -1, 32 }, /* configid0 */
{ 72, -1, 32 }, /* configid1 */
{ 73, 0x04, 32 }, /* PS */
{ 74, -1, 32 }, /* threadptr */
{ 75, -1, 32 }, /* br */
{ 76, 0x54, 32 }, /* scompare1 */
{ 77, -1, 32 }, /* acclo */
{ 78, -1, 32 }, /* acchi */
{ 79, -1, 32 }, /* m0 */
{ 80, -1, 32 }, /* m1 */
{ 81, -1, 32 }, /* m2 */
{ 82, -1, 32 }, /* m3 */
{ 83, -1, 32 }, /* expstate */
{ 84, -1, 32 }, /* f64r_lo */
{ 85, -1, 32 }, /* f64r_hi */
{ 86, -1, 32 }, /* f64s */
{ 87, -1, 32 }, /* f0 */
{ 88, -1, 32 }, /* f1 */
{ 89, -1, 32 }, /* f2 */
{ 90, -1, 32 }, /* f3 */
{ 91, -1, 32 }, /* f4 */
{ 92, -1, 32 }, /* f5 */
{ 93, -1, 32 }, /* f6 */
{ 94, -1, 32 }, /* f7 */
{ 95, -1, 32 }, /* f8 */
{ 96, -1, 32 }, /* f9 */
{ 97, -1, 32 }, /* f10 */
{ 98, -1, 32 }, /* f11 */
{ 99, -1, 32 }, /* f12 */
{ 100, -1, 32 }, /* f13 */
{ 101, -1, 32 }, /* f14 */
{ 102, -1, 32 }, /* f15 */
{ 103, -1, 32 }, /* fcr */
{ 104, -1, 32 }, /* fsr */
};
const struct rtos_register_stacking nuttx_esp32_stacking = {
.stack_registers_size = 26 * 4,
.stack_growth_direction = -1,
.num_output_registers = ARRAY_SIZE(nuttx_stack_offsets_esp32),
.calculate_process_stack = rtos_generic_stack_align8,
.register_offsets = nuttx_stack_offsets_esp32,
.read_stack = nuttx_esp_xtensa_stack_read,
};
static const struct stack_register_offset nuttx_stack_offsets_esp32s2[] = {
{ 0, 0x00, 32 }, /* PC */
{ 1, 0x08, 32 }, /* A0 */
{ 2, 0x0c, 32 }, /* A1 */
{ 3, 0x10, 32 }, /* A2 */
{ 4, 0x14, 32 }, /* A3 */
{ 5, 0x18, 32 }, /* A4 */
{ 6, 0x1c, 32 }, /* A5 */
{ 7, 0x20, 32 }, /* A6 */
{ 8, 0x24, 32 }, /* A7 */
{ 9, 0x28, 32 }, /* A8 */
{ 10, 0x2c, 32 }, /* A9 */
{ 11, 0x30, 32 }, /* A10 */
{ 12, 0x34, 32 }, /* A11 */
{ 13, 0x38, 32 }, /* A12 */
{ 14, 0x3c, 32 }, /* A13 */
{ 15, 0x40, 32 }, /* A14 */
{ 16, 0x44, 32 }, /* A15 */
/* A16-A63 aren't in the stack frame because they've been flushed to the stack earlier */
{ 17, -1, 32 }, /* A16 */
{ 18, -1, 32 }, /* A17 */
{ 19, -1, 32 }, /* A18 */
{ 20, -1, 32 }, /* A19 */
{ 21, -1, 32 }, /* A20 */
{ 22, -1, 32 }, /* A21 */
{ 23, -1, 32 }, /* A22 */
{ 24, -1, 32 }, /* A23 */
{ 25, -1, 32 }, /* A24 */
{ 26, -1, 32 }, /* A25 */
{ 27, -1, 32 }, /* A26 */
{ 28, -1, 32 }, /* A27 */
{ 29, -1, 32 }, /* A28 */
{ 30, -1, 32 }, /* A29 */
{ 31, -1, 32 }, /* A30 */
{ 32, -1, 32 }, /* A31 */
{ 33, -1, 32 }, /* A32 */
{ 34, -1, 32 }, /* A33 */
{ 35, -1, 32 }, /* A34 */
{ 36, -1, 32 }, /* A35 */
{ 37, -1, 32 }, /* A36 */
{ 38, -1, 32 }, /* A37 */
{ 39, -1, 32 }, /* A38 */
{ 40, -1, 32 }, /* A39 */
{ 41, -1, 32 }, /* A40 */
{ 42, -1, 32 }, /* A41 */
{ 43, -1, 32 }, /* A42 */
{ 44, -1, 32 }, /* A43 */
{ 45, -1, 32 }, /* A44 */
{ 46, -1, 32 }, /* A45 */
{ 47, -1, 32 }, /* A46 */
{ 48, -1, 32 }, /* A47 */
{ 49, -1, 32 }, /* A48 */
{ 50, -1, 32 }, /* A49 */
{ 51, -1, 32 }, /* A50 */
{ 52, -1, 32 }, /* A51 */
{ 53, -1, 32 }, /* A52 */
{ 54, -1, 32 }, /* A53 */
{ 55, -1, 32 }, /* A54 */
{ 56, -1, 32 }, /* A55 */
{ 57, -1, 32 }, /* A56 */
{ 58, -1, 32 }, /* A57 */
{ 59, -1, 32 }, /* A58 */
{ 60, -1, 32 }, /* A59 */
{ 61, -1, 32 }, /* A60 */
{ 62, -1, 32 }, /* A61 */
{ 63, -1, 32 }, /* A62 */
{ 64, -1, 32 }, /* A63 */
{ 65, 0x48, 32 }, /* SAR */
{ 66, -1, 32 }, /* windowbase */
{ 67, -1, 32 }, /* windowstart */
{ 68, -1, 32 }, /* configid0 */
{ 69, -1, 32 }, /* configid1 */
{ 70, 0x04, 32 }, /* PS */
{ 71, -1, 32 }, /* threadptr */
{ 72, -1, 32 }, /* gpio_out */
};
const struct rtos_register_stacking nuttx_esp32s2_stacking = {
.stack_registers_size = 25 * 4,
.stack_growth_direction = -1,
.num_output_registers = ARRAY_SIZE(nuttx_stack_offsets_esp32s2),
.calculate_process_stack = rtos_generic_stack_align8,
.register_offsets = nuttx_stack_offsets_esp32s2,
.read_stack = nuttx_esp_xtensa_stack_read,
};
static const struct stack_register_offset nuttx_stack_offsets_esp32s3[] = {
{ 0, 0x00, 32 }, /* PC */
{ 1, 0x08, 32 }, /* A0 */
{ 2, 0x0c, 32 }, /* A1 */
{ 3, 0x10, 32 }, /* A2 */
{ 4, 0x14, 32 }, /* A3 */
{ 5, 0x18, 32 }, /* A4 */
{ 6, 0x1c, 32 }, /* A5 */
{ 7, 0x20, 32 }, /* A6 */
{ 8, 0x24, 32 }, /* A7 */
{ 9, 0x28, 32 }, /* A8 */
{ 10, 0x2c, 32 }, /* A9 */
{ 11, 0x30, 32 }, /* A10 */
{ 12, 0x34, 32 }, /* A11 */
{ 13, 0x38, 32 }, /* A12 */
{ 14, 0x3c, 32 }, /* A13 */
{ 15, 0x40, 32 }, /* A14 */
{ 16, 0x44, 32 }, /* A15 */
/* A16-A63 aren't in the stack frame because they've been flushed to the stack earlier */
{ 17, -1, 32 }, /* A16 */
{ 18, -1, 32 }, /* A17 */
{ 19, -1, 32 }, /* A18 */
{ 20, -1, 32 }, /* A19 */
{ 21, -1, 32 }, /* A20 */
{ 22, -1, 32 }, /* A21 */
{ 23, -1, 32 }, /* A22 */
{ 24, -1, 32 }, /* A23 */
{ 25, -1, 32 }, /* A24 */
{ 26, -1, 32 }, /* A25 */
{ 27, -1, 32 }, /* A26 */
{ 28, -1, 32 }, /* A27 */
{ 29, -1, 32 }, /* A28 */
{ 30, -1, 32 }, /* A29 */
{ 31, -1, 32 }, /* A30 */
{ 32, -1, 32 }, /* A31 */
{ 33, -1, 32 }, /* A32 */
{ 34, -1, 32 }, /* A33 */
{ 35, -1, 32 }, /* A34 */
{ 36, -1, 32 }, /* A35 */
{ 37, -1, 32 }, /* A36 */
{ 38, -1, 32 }, /* A37 */
{ 39, -1, 32 }, /* A38 */
{ 40, -1, 32 }, /* A39 */
{ 41, -1, 32 }, /* A40 */
{ 42, -1, 32 }, /* A41 */
{ 43, -1, 32 }, /* A42 */
{ 44, -1, 32 }, /* A43 */
{ 45, -1, 32 }, /* A44 */
{ 46, -1, 32 }, /* A45 */
{ 47, -1, 32 }, /* A46 */
{ 48, -1, 32 }, /* A47 */
{ 49, -1, 32 }, /* A48 */
{ 50, -1, 32 }, /* A49 */
{ 51, -1, 32 }, /* A50 */
{ 52, -1, 32 }, /* A51 */
{ 53, -1, 32 }, /* A52 */
{ 54, -1, 32 }, /* A53 */
{ 55, -1, 32 }, /* A54 */
{ 56, -1, 32 }, /* A55 */
{ 57, -1, 32 }, /* A56 */
{ 58, -1, 32 }, /* A57 */
{ 59, -1, 32 }, /* A58 */
{ 60, -1, 32 }, /* A59 */
{ 61, -1, 32 }, /* A60 */
{ 62, -1, 32 }, /* A61 */
{ 63, -1, 32 }, /* A62 */
{ 64, -1, 32 }, /* A63 */
{ 65, 0x58, 32 }, /* lbeg */
{ 66, 0x5c, 32 }, /* lend */
{ 67, 0x60, 32 }, /* lcount */
{ 68, 0x48, 32 }, /* SAR */
{ 69, -1, 32 }, /* windowbase */
{ 70, -1, 32 }, /* windowstart */
{ 71, -1, 32 }, /* configid0 */
{ 72, -1, 32 }, /* configid1 */
{ 73, 0x04, 32 }, /* PS */
{ 74, -1, 32 }, /* threadptr */
{ 75, -1, 32 }, /* br */
{ 76, 0x54, 32 }, /* scompare1 */
{ 77, -1, 32 }, /* acclo */
{ 78, -1, 32 }, /* acchi */
{ 79, -1, 32 }, /* m0 */
{ 80, -1, 32 }, /* m1 */
{ 81, -1, 32 }, /* m2 */
{ 82, -1, 32 }, /* m3 */
{ 83, -1, 32 }, /* gpio_out */
{ 84, -1, 32 }, /* f0 */
{ 85, -1, 32 }, /* f1 */
{ 86, -1, 32 }, /* f2 */
{ 87, -1, 32 }, /* f3 */
{ 88, -1, 32 }, /* f4 */
{ 89, -1, 32 }, /* f5 */
{ 90, -1, 32 }, /* f6 */
{ 91, -1, 32 }, /* f7 */
{ 92, -1, 32 }, /* f8 */
{ 93, -1, 32 }, /* f9 */
{ 94, -1, 32 }, /* f10 */
{ 95, -1, 32 }, /* f11 */
{ 96, -1, 32 }, /* f12 */
{ 97, -1, 32 }, /* f13 */
{ 98, -1, 32 }, /* f14 */
{ 99, -1, 32 }, /* f15 */
{ 100, -1, 32 }, /* fcr */
{ 101, -1, 32 }, /* fsr */
{ 102, -1, 32 }, /* accx_0 */
{ 103, -1, 32 }, /* accx_1 */
{ 104, -1, 32 }, /* qacc_h_0 */
{ 105, -1, 32 }, /* qacc_h_1 */
{ 106, -1, 32 }, /* qacc_h_2 */
{ 107, -1, 32 }, /* qacc_h_3 */
{ 108, -1, 32 }, /* qacc_h_4 */
{ 109, -1, 32 }, /* qacc_l_0 */
{ 110, -1, 32 }, /* qacc_l_1 */
{ 111, -1, 32 }, /* qacc_l_2 */
{ 112, -1, 32 }, /* qacc_l_3 */
{ 113, -1, 32 }, /* qacc_l_4 */
{ 114, -1, 32 }, /* sar_byte */
{ 115, -1, 32 }, /* fft_bit_width */
{ 116, -1, 32 }, /* ua_state_0 */
{ 117, -1, 32 }, /* ua_state_1 */
{ 118, -1, 32 }, /* ua_state_2 */
{ 119, -1, 32 }, /* ua_state_3 */
{ 120, -1, 128 }, /* q0 */
{ 121, -1, 128 }, /* q1 */
{ 122, -1, 128 }, /* q2 */
{ 123, -1, 128 }, /* q3 */
{ 124, -1, 128 }, /* q4 */
{ 125, -1, 128 }, /* q5 */
{ 126, -1, 128 }, /* q6 */
{ 127, -1, 128 }, /* q7 */
};
const struct rtos_register_stacking nuttx_esp32s3_stacking = {
.stack_registers_size = 26 * 4,
.stack_growth_direction = -1,
.num_output_registers = ARRAY_SIZE(nuttx_stack_offsets_esp32s3),
.calculate_process_stack = rtos_generic_stack_align8,
.register_offsets = nuttx_stack_offsets_esp32s3,
.read_stack = nuttx_esp_xtensa_stack_read,
};

View File

@ -8,5 +8,8 @@
extern const struct rtos_register_stacking nuttx_stacking_cortex_m;
extern const struct rtos_register_stacking nuttx_stacking_cortex_m_fpu;
extern const struct rtos_register_stacking nuttx_riscv_stacking;
extern const struct rtos_register_stacking nuttx_esp32_stacking;
extern const struct rtos_register_stacking nuttx_esp32s2_stacking;
extern const struct rtos_register_stacking nuttx_esp32s3_stacking;
#endif /* INCLUDED_RTOS_NUTTX_STACKINGS_H */

View File

@ -12,6 +12,7 @@
#include "rtos.h"
#include "target/armv7m.h"
#include "rtos_standard_stackings.h"
#include "rtos_riot_stackings.h"
/* This works for the M0 and M34 stackings as xPSR is in a fixed
* location

View File

@ -8,14 +8,9 @@
#ifndef OPENOCD_RTOS_RTOS_RIOT_STACKINGS_H
#define OPENOCD_RTOS_RTOS_RIOT_STACKINGS_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "rtos.h"
extern const struct rtos_register_stacking rtos_riot_cortex_m0_stacking;
extern const struct rtos_register_stacking rtos_riot_cortex_m34_stacking;
#endif /* OPENOCD_RTOS_RTOS_RIOT_STACKINGS_H */

View File

@ -12,6 +12,7 @@
#include "rtos.h"
#include "target/armv7m.h"
#include "target/riscv/riscv.h"
#include "rtos_standard_stackings.h"
static const struct stack_register_offset rtos_standard_cortex_m3_stack_offsets[ARMV7M_NUM_CORE_REGS] = {
{ ARMV7M_R0, 0x20, 32 }, /* r0 */

View File

@ -8,10 +8,6 @@
#ifndef OPENOCD_RTOS_RTOS_STANDARD_STACKINGS_H
#define OPENOCD_RTOS_RTOS_STANDARD_STACKINGS_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "rtos.h"
extern const struct rtos_register_stacking rtos_standard_cortex_m3_stacking;

View File

@ -9,11 +9,11 @@
#include "config.h"
#endif
#include <helper/types.h>
#include <rtos/rtos.h>
#include <rtos/rtos_standard_stackings.h>
#include <target/armv7m.h>
#include <target/esirisc.h>
#include "rtos.h"
#include "target/armv7m.h"
#include "target/esirisc.h"
#include "rtos_standard_stackings.h"
#include "rtos_ucos_iii_stackings.h"
static const struct stack_register_offset rtos_ucos_iii_cortex_m_stack_offsets[] = {
{ ARMV7M_R0, 0x20, 32 }, /* r0 */

View File

@ -8,11 +8,7 @@
#ifndef OPENOCD_RTOS_RTOS_UCOS_III_STACKINGS_H
#define OPENOCD_RTOS_RTOS_UCOS_III_STACKINGS_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <rtos/rtos.h>
#include "rtos.h"
extern const struct rtos_register_stacking rtos_ucos_iii_cortex_m_stacking;
extern const struct rtos_register_stacking rtos_ucos_iii_esi_risc_stacking;

View File

@ -785,7 +785,7 @@ static int zephyr_get_symbol_list_to_lookup(struct symbol_table_elem **symbol_li
return ERROR_OK;
}
struct rtos_type zephyr_rtos = {
const struct rtos_type zephyr_rtos = {
.name = "Zephyr",
.detect_rtos = zephyr_detect_rtos,

View File

@ -22,6 +22,7 @@
#include "svf.h"
#include "helper/system.h"
#include <helper/time_support.h>
#include <stdbool.h>
/* SVF command */
enum svf_command {
@ -139,6 +140,9 @@ static const struct svf_statemove svf_statemoves[] = {
#define XXR_TDO (1 << 1)
#define XXR_MASK (1 << 2)
#define XXR_SMASK (1 << 3)
#define SVF_MAX_ADDCYCLES 255
struct svf_xxr_para {
int len;
int data_mask;
@ -220,6 +224,8 @@ static int svf_buffer_index, svf_buffer_size;
static int svf_quiet;
static int svf_nil;
static int svf_ignore_error;
static bool svf_noreset;
static int svf_addcycles;
/* Targeting particular tap */
static int svf_tap_is_specified;
@ -343,7 +349,7 @@ int svf_add_statemove(tap_state_t state_to)
COMMAND_HANDLER(handle_svf_command)
{
#define SVF_MIN_NUM_OF_OPTIONS 1
#define SVF_MAX_NUM_OF_OPTIONS 5
#define SVF_MAX_NUM_OF_OPTIONS 8
int command_num = 0;
int ret = ERROR_OK;
int64_t time_measure_ms;
@ -363,8 +369,18 @@ COMMAND_HANDLER(handle_svf_command)
svf_nil = 0;
svf_progress_enabled = 0;
svf_ignore_error = 0;
svf_noreset = false;
svf_addcycles = 0;
for (unsigned int i = 0; i < CMD_ARGC; i++) {
if (strcmp(CMD_ARGV[i], "-tap") == 0) {
if (strcmp(CMD_ARGV[i], "-addcycles") == 0) {
svf_addcycles = atoi(CMD_ARGV[i + 1]);
if (svf_addcycles > SVF_MAX_ADDCYCLES) {
command_print(CMD, "addcycles: %s out of range", CMD_ARGV[i + 1]);
return ERROR_FAIL;
}
i++;
} else if (strcmp(CMD_ARGV[i], "-tap") == 0) {
tap = jtag_tap_by_string(CMD_ARGV[i+1]);
if (!tap) {
command_print(CMD, "Tap: %s unknown", CMD_ARGV[i+1]);
@ -382,6 +398,8 @@ COMMAND_HANDLER(handle_svf_command)
else if ((strcmp(CMD_ARGV[i],
"ignore_error") == 0) || (strcmp(CMD_ARGV[i], "-ignore_error") == 0))
svf_ignore_error = 1;
else if (strcmp(CMD_ARGV[i], "-noreset") == 0)
svf_noreset = true;
else {
svf_fd = fopen(CMD_ARGV[i], "r");
if (!svf_fd) {
@ -424,7 +442,7 @@ COMMAND_HANDLER(handle_svf_command)
memcpy(&svf_para, &svf_para_init, sizeof(svf_para));
if (!svf_nil) {
if (!svf_nil && !svf_noreset) {
/* TAP_RESET */
jtag_add_tlr();
}
@ -1189,6 +1207,9 @@ xxr_common:
svf_para.dr_end_state);
}
if (svf_addcycles)
jtag_add_clocks(svf_addcycles);
svf_buffer_index += (i + 7) >> 3;
} else if (command == SIR) {
/* check buffer size first, reallocate if necessary */
@ -1545,7 +1566,7 @@ static const struct command_registration svf_command_handlers[] = {
.handler = handle_svf_command,
.mode = COMMAND_EXEC,
.help = "Runs a SVF file.",
.usage = "[-tap device.tap] <file> [quiet] [nil] [progress] [ignore_error]",
.usage = "[-tap device.tap] <file> [quiet] [nil] [progress] [ignore_error] [-noreset] [-addcycles numcycles]",
},
COMMAND_REGISTRATION_DONE
};

View File

@ -253,16 +253,6 @@ struct arc_common {
} \
} while (0)
#define JIM_CHECK_RETVAL(action) \
do { \
int __retval = (action); \
if (__retval != JIM_OK) { \
LOG_DEBUG("error while calling \"%s\"", \
# action); \
return __retval; \
} \
} while (0)
static inline struct arc_common *target_to_arc(struct target *target)
{
return target->arch_info;

File diff suppressed because it is too large Load Diff

View File

@ -407,12 +407,10 @@ static int image_elf32_read_headers(struct image *image)
return ERROR_FILEIO_OPERATION_FAILED;
}
/* count useful segments (loadable), ignore BSS section */
/* count useful segments (loadable) */
image->num_sections = 0;
for (i = 0; i < elf->segment_count; i++)
if ((field32(elf,
elf->segments32[i].p_type) == PT_LOAD) &&
(field32(elf, elf->segments32[i].p_filesz) != 0))
if (field32(elf, elf->segments32[i].p_type) == PT_LOAD)
image->num_sections++;
if (image->num_sections == 0) {
@ -449,10 +447,8 @@ static int image_elf32_read_headers(struct image *image)
}
for (i = 0, j = 0; i < elf->segment_count; i++) {
if ((field32(elf,
elf->segments32[i].p_type) == PT_LOAD) &&
(field32(elf, elf->segments32[i].p_filesz) != 0)) {
image->sections[j].size = field32(elf, elf->segments32[i].p_filesz);
if (field32(elf, elf->segments32[i].p_type) == PT_LOAD) {
image->sections[j].size = field32(elf, elf->segments32[i].p_memsz);
if (load_to_vaddr)
image->sections[j].base_address = field32(elf,
elf->segments32[i].p_vaddr);
@ -532,12 +528,10 @@ static int image_elf64_read_headers(struct image *image)
return ERROR_FILEIO_OPERATION_FAILED;
}
/* count useful segments (loadable), ignore BSS section */
/* count useful segments (loadable) */
image->num_sections = 0;
for (i = 0; i < elf->segment_count; i++)
if ((field32(elf,
elf->segments64[i].p_type) == PT_LOAD) &&
(field64(elf, elf->segments64[i].p_filesz) != 0))
if (field32(elf, elf->segments64[i].p_type) == PT_LOAD)
image->num_sections++;
if (image->num_sections == 0) {
@ -574,10 +568,8 @@ static int image_elf64_read_headers(struct image *image)
}
for (i = 0, j = 0; i < elf->segment_count; i++) {
if ((field32(elf,
elf->segments64[i].p_type) == PT_LOAD) &&
(field64(elf, elf->segments64[i].p_filesz) != 0)) {
image->sections[j].size = field64(elf, elf->segments64[i].p_filesz);
if (field32(elf, elf->segments64[i].p_type) == PT_LOAD) {
image->sections[j].size = field64(elf, elf->segments64[i].p_memsz);
if (load_to_vaddr)
image->sections[j].base_address = field64(elf,
elf->segments64[i].p_vaddr);
@ -651,6 +643,8 @@ static int image_elf32_read_section(struct image *image,
{
struct image_elf *elf = image->type_private;
Elf32_Phdr *segment = (Elf32_Phdr *)image->sections[section].private;
uint32_t filesz = field32(elf, segment->p_filesz);
uint32_t memsz = field32(elf, segment->p_memsz);
size_t read_size, really_read;
int retval;
@ -659,9 +653,9 @@ static int image_elf32_read_section(struct image *image,
LOG_DEBUG("load segment %d at 0x%" TARGET_PRIxADDR " (sz = 0x%" PRIx32 ")", section, offset, size);
/* read initialized data in current segment if any */
if (offset < field32(elf, segment->p_filesz)) {
if (offset < filesz) {
/* maximal size present in file for the current segment */
read_size = MIN(size, field32(elf, segment->p_filesz) - offset);
read_size = MIN(size, filesz - offset);
LOG_DEBUG("read elf: size = 0x%zx at 0x%" TARGET_PRIxADDR "", read_size,
field32(elf, segment->p_offset) + offset);
/* read initialized area of the segment */
@ -675,6 +669,8 @@ static int image_elf32_read_section(struct image *image,
LOG_ERROR("cannot read ELF segment content, read failed");
return retval;
}
buffer += read_size;
offset += read_size;
size -= read_size;
*size_read += read_size;
/* need more data ? */
@ -682,6 +678,13 @@ static int image_elf32_read_section(struct image *image,
return ERROR_OK;
}
/* clear bss in current segment if any */
if (offset >= filesz) {
uint32_t memset_size = MIN(size, memsz - filesz);
memset(buffer, 0, memset_size);
*size_read += memset_size;
}
return ERROR_OK;
}
@ -694,6 +697,8 @@ static int image_elf64_read_section(struct image *image,
{
struct image_elf *elf = image->type_private;
Elf64_Phdr *segment = (Elf64_Phdr *)image->sections[section].private;
uint64_t filesz = field64(elf, segment->p_filesz);
uint64_t memsz = field64(elf, segment->p_memsz);
size_t read_size, really_read;
int retval;
@ -702,9 +707,9 @@ static int image_elf64_read_section(struct image *image,
LOG_DEBUG("load segment %d at 0x%" TARGET_PRIxADDR " (sz = 0x%" PRIx32 ")", section, offset, size);
/* read initialized data in current segment if any */
if (offset < field64(elf, segment->p_filesz)) {
if (offset < filesz) {
/* maximal size present in file for the current segment */
read_size = MIN(size, field64(elf, segment->p_filesz) - offset);
read_size = MIN(size, filesz - offset);
LOG_DEBUG("read elf: size = 0x%zx at 0x%" TARGET_PRIxADDR "", read_size,
field64(elf, segment->p_offset) + offset);
/* read initialized area of the segment */
@ -718,6 +723,8 @@ static int image_elf64_read_section(struct image *image,
LOG_ERROR("cannot read ELF segment content, read failed");
return retval;
}
buffer += read_size;
offset += read_size;
size -= read_size;
*size_read += read_size;
/* need more data ? */
@ -725,6 +732,13 @@ static int image_elf64_read_section(struct image *image,
return ERROR_OK;
}
/* clear bss in current segment if any */
if (offset >= filesz) {
uint64_t memset_size = MIN(size, memsz - filesz);
memset(buffer, 0, memset_size);
*size_read += memset_size;
}
return ERROR_OK;
}

View File

@ -165,6 +165,7 @@
#define XT_SR_DDR (xtensa_regs[XT_REG_IDX_DDR].reg_num)
#define XT_SR_PS (xtensa_regs[XT_REG_IDX_PS].reg_num)
#define XT_SR_WB (xtensa_regs[XT_REG_IDX_WINDOWBASE].reg_num)
#define XT_REG_A0 (xtensa_regs[XT_REG_IDX_AR0].reg_num)
#define XT_REG_A3 (xtensa_regs[XT_REG_IDX_AR3].reg_num)
#define XT_REG_A4 (xtensa_regs[XT_REG_IDX_AR4].reg_num)
@ -173,6 +174,7 @@
#define XT_EPC_REG_NUM_BASE (0xb0U) /* (EPC1 - 1), for adding DBGLEVEL */
#define XT_PC_REG_NUM_VIRTUAL (0xffU) /* Marker for computing PC (EPC[DBGLEVEL) */
#define XT_PC_DBREG_NUM_BASE (0x20U) /* External (i.e., GDB) access */
#define XT_NX_IBREAKC_BASE (0xc0U) /* (IBREAKC0..IBREAKC1) for NX */
#define XT_SW_BREAKPOINTS_MAX_NUM 32
#define XT_HW_IBREAK_MAX_NUM 2
@ -476,7 +478,9 @@ static enum xtensa_reg_id xtensa_windowbase_offset_to_canonical(struct xtensa *x
LOG_ERROR("Error: can't convert register %d to non-windowbased register!", reg_idx);
return -1;
}
return ((idx + windowbase * 4) & (xtensa->core_config->aregs_num - 1)) + XT_REG_IDX_AR0;
/* Each windowbase value represents 4 registers on LX and 8 on NX */
int base_inc = (xtensa->core_config->core_type == XT_LX) ? 4 : 8;
return ((idx + windowbase * base_inc) & (xtensa->core_config->aregs_num - 1)) + XT_REG_IDX_AR0;
}
static enum xtensa_reg_id xtensa_canonical_to_windowbase_offset(struct xtensa *xtensa,
@ -526,26 +530,29 @@ static int xtensa_queue_pwr_reg_write(struct xtensa *xtensa, unsigned int reg, u
static int xtensa_window_state_save(struct target *target, uint32_t *woe)
{
struct xtensa *xtensa = target_to_xtensa(target);
int woe_dis;
unsigned int woe_sr = (xtensa->core_config->core_type == XT_LX) ? XT_SR_PS : XT_SR_WB;
uint32_t woe_dis;
uint8_t woe_buf[4];
if (xtensa->core_config->windowed) {
/* Save PS (LX) and disable window overflow exceptions prior to AR save */
xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_PS, XT_REG_A3));
/* Save PS (LX) or WB (NX) and disable window overflow exceptions prior to AR save */
xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, woe_sr, XT_REG_A3));
xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A3));
xtensa_queue_dbg_reg_read(xtensa, XDMREG_DDR, woe_buf);
int res = xtensa_dm_queue_execute(&xtensa->dbg_mod);
if (res != ERROR_OK) {
LOG_ERROR("Failed to read PS (%d)!", res);
LOG_TARGET_ERROR(target, "Failed to read %s (%d)!",
(woe_sr == XT_SR_PS) ? "PS" : "WB", res);
return res;
}
xtensa_core_status_check(target);
*woe = buf_get_u32(woe_buf, 0, 32);
woe_dis = *woe & ~XT_PS_WOE_MSK;
LOG_DEBUG("Clearing PS.WOE (0x%08" PRIx32 " -> 0x%08" PRIx32 ")", *woe, woe_dis);
woe_dis = *woe & ~((woe_sr == XT_SR_PS) ? XT_PS_WOE_MSK : XT_WB_S_MSK);
LOG_TARGET_DEBUG(target, "Clearing %s (0x%08" PRIx32 " -> 0x%08" PRIx32 ")",
(woe_sr == XT_SR_PS) ? "PS.WOE" : "WB.S", *woe, woe_dis);
xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, woe_dis);
xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3));
xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_PS, XT_REG_A3));
xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, woe_sr, XT_REG_A3));
}
return ERROR_OK;
}
@ -554,12 +561,14 @@ static int xtensa_window_state_save(struct target *target, uint32_t *woe)
static void xtensa_window_state_restore(struct target *target, uint32_t woe)
{
struct xtensa *xtensa = target_to_xtensa(target);
unsigned int woe_sr = (xtensa->core_config->core_type == XT_LX) ? XT_SR_PS : XT_SR_WB;
if (xtensa->core_config->windowed) {
/* Restore window overflow exception state */
xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, woe);
xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3));
xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_PS, XT_REG_A3));
LOG_DEBUG("Restored PS.WOE (0x%08" PRIx32 ")", woe);
xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, woe_sr, XT_REG_A3));
LOG_TARGET_DEBUG(target, "Restored %s (0x%08" PRIx32 ")",
(woe_sr == XT_SR_PS) ? "PS.WOE" : "WB", woe);
}
}
@ -596,6 +605,10 @@ static int xtensa_write_dirty_registers(struct target *target)
bool preserve_a3 = false;
uint8_t a3_buf[4];
xtensa_reg_val_t a3 = 0, woe;
unsigned int ms_idx = (xtensa->core_config->core_type == XT_NX) ?
xtensa->nx_reg_idx[XT_NX_REG_IDX_MS] : reg_list_size;
xtensa_reg_val_t ms;
bool restore_ms = false;
LOG_TARGET_DEBUG(target, "start");
@ -627,13 +640,25 @@ static int xtensa_write_dirty_registers(struct target *target)
} else if (rlist[ridx].type == XT_REG_FR) {
xtensa_queue_exec_ins(xtensa, XT_INS_WFR(xtensa, reg_num, XT_REG_A3));
} else {/*SFR */
if (reg_num == XT_PC_REG_NUM_VIRTUAL)
/* reg number of PC for debug interrupt depends on NDEBUGLEVEL
**/
reg_num =
(XT_EPC_REG_NUM_BASE +
xtensa->core_config->debug.irq_level);
xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, reg_num, XT_REG_A3));
if (reg_num == XT_PC_REG_NUM_VIRTUAL) {
if (xtensa->core_config->core_type == XT_LX) {
/* reg number of PC for debug interrupt depends on NDEBUGLEVEL */
reg_num = (XT_EPC_REG_NUM_BASE + xtensa->core_config->debug.irq_level);
xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, reg_num, XT_REG_A3));
} else {
/* NX PC set through issuing a jump instruction */
xtensa_queue_exec_ins(xtensa, XT_INS_JX(xtensa, XT_REG_A3));
}
} else if (i == ms_idx) {
/* MS must be restored after ARs. This ensures ARs remain in correct
* order even for reversed register groups (overflow/underflow).
*/
ms = regval;
restore_ms = true;
LOG_TARGET_DEBUG(target, "Delaying MS write: 0x%x", ms);
} else {
xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, reg_num, XT_REG_A3));
}
}
}
reg_list[i].dirty = false;
@ -648,12 +673,12 @@ static int xtensa_write_dirty_registers(struct target *target)
xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, regval);
xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3));
xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa,
xtensa_regs[XT_REG_IDX_CPENABLE].reg_num,
XT_REG_A3));
xtensa_regs[XT_REG_IDX_CPENABLE].reg_num,
XT_REG_A3));
reg_list[XT_REG_IDX_CPENABLE].dirty = false;
}
preserve_a3 = (xtensa->core_config->windowed);
preserve_a3 = (xtensa->core_config->windowed) || (xtensa->core_config->core_type == XT_NX);
if (preserve_a3) {
/* Save (windowed) A3 for scratch use */
xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A3));
@ -670,7 +695,12 @@ static int xtensa_write_dirty_registers(struct target *target)
if (res != ERROR_OK)
return res;
/* Grab the windowbase, we need it. */
windowbase = xtensa_reg_get(target, XT_REG_IDX_WINDOWBASE);
uint32_t wb_idx = (xtensa->core_config->core_type == XT_LX) ?
XT_REG_IDX_WINDOWBASE : xtensa->nx_reg_idx[XT_NX_REG_IDX_WB];
windowbase = xtensa_reg_get(target, wb_idx);
if (xtensa->core_config->core_type == XT_NX)
windowbase = (windowbase & XT_WB_P_MSK) >> XT_WB_P_SHIFT;
/* Check if there are mismatches between the ARx and corresponding Ax registers.
* When the user sets a register on a windowed config, xt-gdb may set the ARx
* register directly. Thus we take ARx as priority over Ax if both are dirty
@ -748,10 +778,12 @@ static int xtensa_write_dirty_registers(struct target *target)
}
}
}
/*Now rotate the window so we'll see the next 16 registers. The final rotate
* will wraparound, */
/*leaving us in the state we were. */
xtensa_queue_exec_ins(xtensa, XT_INS_ROTW(xtensa, 4));
/* Now rotate the window so we'll see the next 16 registers. The final rotate
* will wraparound, leaving us in the state we were.
* Each ROTW rotates 4 registers on LX and 8 on NX */
int rotw_arg = (xtensa->core_config->core_type == XT_LX) ? 4 : 2;
xtensa_queue_exec_ins(xtensa, XT_INS_ROTW(xtensa, rotw_arg));
}
xtensa_window_state_restore(target, woe);
@ -760,6 +792,14 @@ static int xtensa_write_dirty_registers(struct target *target)
xtensa->scratch_ars[s].intval = false;
}
if (restore_ms) {
uint32_t ms_regno = xtensa->optregs[ms_idx - XT_NUM_REGS].reg_num;
xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, ms);
xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3));
xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, ms_regno, XT_REG_A3));
LOG_TARGET_DEBUG(target, "Delayed MS (0x%x) write complete: 0x%x", ms_regno, ms);
}
if (preserve_a3) {
xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, a3);
xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3));
@ -877,10 +917,41 @@ static inline void xtensa_reg_set_value(struct reg *reg, xtensa_reg_val_t value)
reg->dirty = true;
}
static int xtensa_imprecise_exception_occurred(struct target *target)
{
struct xtensa *xtensa = target_to_xtensa(target);
for (enum xtensa_nx_reg_idx idx = XT_NX_REG_IDX_IEVEC; idx <= XT_NX_REG_IDX_MESR; idx++) {
enum xtensa_reg_id ridx = xtensa->nx_reg_idx[idx];
if (xtensa->nx_reg_idx[idx]) {
xtensa_reg_val_t reg = xtensa_reg_get(target, xtensa->nx_reg_idx[idx]);
if (reg & XT_IMPR_EXC_MSK) {
LOG_TARGET_DEBUG(target, "Imprecise exception: %s: 0x%x",
xtensa->core_cache->reg_list[ridx].name, reg);
return true;
}
}
}
return false;
}
static void xtensa_imprecise_exception_clear(struct target *target)
{
struct xtensa *xtensa = target_to_xtensa(target);
for (enum xtensa_nx_reg_idx idx = XT_NX_REG_IDX_IEVEC; idx <= XT_NX_REG_IDX_MESRCLR; idx++) {
enum xtensa_reg_id ridx = xtensa->nx_reg_idx[idx];
if (ridx && idx != XT_NX_REG_IDX_MESR) {
xtensa_reg_val_t value = (idx == XT_NX_REG_IDX_MESRCLR) ? XT_MESRCLR_IMPR_EXC_MSK : 0;
xtensa_reg_set(target, ridx, value);
LOG_TARGET_DEBUG(target, "Imprecise exception: clearing %s (0x%x)",
xtensa->core_cache->reg_list[ridx].name, value);
}
}
}
int xtensa_core_status_check(struct target *target)
{
struct xtensa *xtensa = target_to_xtensa(target);
int res, needclear = 0;
int res, needclear = 0, needimprclear = 0;
xtensa_dm_core_status_read(&xtensa->dbg_mod);
xtensa_dsr_t dsr = xtensa_dm_core_status_get(&xtensa->dbg_mod);
@ -904,11 +975,20 @@ int xtensa_core_status_check(struct target *target)
dsr);
needclear = 1;
}
if (xtensa->core_config->core_type == XT_NX && (xtensa_imprecise_exception_occurred(target))) {
if (!xtensa->suppress_dsr_errors)
LOG_TARGET_ERROR(target,
"%s: Imprecise exception occurred!", target_name(target));
needclear = 1;
needimprclear = 1;
}
if (needclear) {
res = xtensa_dm_core_status_clear(&xtensa->dbg_mod,
OCDDSR_EXECEXCEPTION | OCDDSR_EXECOVERRUN);
if (res != ERROR_OK && !xtensa->suppress_dsr_errors)
LOG_TARGET_ERROR(target, "clearing DSR failed!");
if (xtensa->core_config->core_type == XT_NX && needimprclear)
xtensa_imprecise_exception_clear(target);
return ERROR_FAIL;
}
return ERROR_OK;
@ -934,8 +1014,12 @@ void xtensa_reg_set(struct target *target, enum xtensa_reg_id reg_id, xtensa_reg
void xtensa_reg_set_deep_relgen(struct target *target, enum xtensa_reg_id a_idx, xtensa_reg_val_t value)
{
struct xtensa *xtensa = target_to_xtensa(target);
uint32_t wb_idx = (xtensa->core_config->core_type == XT_LX) ?
XT_REG_IDX_WINDOWBASE : xtensa->nx_reg_idx[XT_NX_REG_IDX_WB];
uint32_t windowbase = (xtensa->core_config->windowed ?
xtensa_reg_get(target, XT_REG_IDX_WINDOWBASE) : 0);
xtensa_reg_get(target, wb_idx) : 0);
if (xtensa->core_config->core_type == XT_NX)
windowbase = (windowbase & XT_WB_P_MSK) >> XT_WB_P_SHIFT;
int ar_idx = xtensa_windowbase_offset_to_canonical(xtensa, a_idx, windowbase);
xtensa_reg_set(target, a_idx, value);
xtensa_reg_set(target, ar_idx, value);
@ -944,14 +1028,68 @@ void xtensa_reg_set_deep_relgen(struct target *target, enum xtensa_reg_id a_idx,
/* Read cause for entering halted state; return bitmask in DEBUGCAUSE_* format */
uint32_t xtensa_cause_get(struct target *target)
{
return xtensa_reg_get(target, XT_REG_IDX_DEBUGCAUSE);
struct xtensa *xtensa = target_to_xtensa(target);
if (xtensa->core_config->core_type == XT_LX) {
/* LX cause in DEBUGCAUSE */
return xtensa_reg_get(target, XT_REG_IDX_DEBUGCAUSE);
}
if (xtensa->nx_stop_cause & DEBUGCAUSE_VALID)
return xtensa->nx_stop_cause;
/* NX cause determined from DSR.StopCause */
if (xtensa_dm_core_status_read(&xtensa->dbg_mod) != ERROR_OK) {
LOG_TARGET_ERROR(target, "Read DSR error");
} else {
uint32_t dsr = xtensa_dm_core_status_get(&xtensa->dbg_mod);
/* NX causes are prioritized; only 1 bit can be set */
switch ((dsr & OCDDSR_STOPCAUSE) >> OCDDSR_STOPCAUSE_SHIFT) {
case OCDDSR_STOPCAUSE_DI:
xtensa->nx_stop_cause = DEBUGCAUSE_DI;
break;
case OCDDSR_STOPCAUSE_SS:
xtensa->nx_stop_cause = DEBUGCAUSE_IC;
break;
case OCDDSR_STOPCAUSE_IB:
xtensa->nx_stop_cause = DEBUGCAUSE_IB;
break;
case OCDDSR_STOPCAUSE_B:
case OCDDSR_STOPCAUSE_B1:
xtensa->nx_stop_cause = DEBUGCAUSE_BI;
break;
case OCDDSR_STOPCAUSE_BN:
xtensa->nx_stop_cause = DEBUGCAUSE_BN;
break;
case OCDDSR_STOPCAUSE_DB0:
case OCDDSR_STOPCAUSE_DB1:
xtensa->nx_stop_cause = DEBUGCAUSE_DB;
break;
default:
LOG_TARGET_ERROR(target, "Unknown stop cause (DSR: 0x%08x)", dsr);
break;
}
if (xtensa->nx_stop_cause)
xtensa->nx_stop_cause |= DEBUGCAUSE_VALID;
}
return xtensa->nx_stop_cause;
}
void xtensa_cause_clear(struct target *target)
{
struct xtensa *xtensa = target_to_xtensa(target);
xtensa_reg_set(target, XT_REG_IDX_DEBUGCAUSE, 0);
xtensa->core_cache->reg_list[XT_REG_IDX_DEBUGCAUSE].dirty = false;
if (xtensa->core_config->core_type == XT_LX) {
xtensa_reg_set(target, XT_REG_IDX_DEBUGCAUSE, 0);
xtensa->core_cache->reg_list[XT_REG_IDX_DEBUGCAUSE].dirty = false;
} else {
/* NX DSR.STOPCAUSE is not writeable; clear cached copy but leave it valid */
xtensa->nx_stop_cause = DEBUGCAUSE_VALID;
}
}
void xtensa_cause_reset(struct target *target)
{
/* Clear DEBUGCAUSE_VALID to trigger re-read (on NX) */
struct xtensa *xtensa = target_to_xtensa(target);
xtensa->nx_stop_cause = 0;
}
int xtensa_assert_reset(struct target *target)
@ -1008,9 +1146,11 @@ int xtensa_fetch_all_regs(struct target *target)
struct xtensa *xtensa = target_to_xtensa(target);
struct reg *reg_list = xtensa->core_cache->reg_list;
unsigned int reg_list_size = xtensa->core_cache->num_regs;
xtensa_reg_val_t cpenable = 0, windowbase = 0, a3;
xtensa_reg_val_t cpenable = 0, windowbase = 0, a0 = 0, a3;
unsigned int ms_idx = reg_list_size;
uint32_t ms = 0;
uint32_t woe;
uint8_t a3_buf[4];
uint8_t a0_buf[4], a3_buf[4], ms_buf[4];
bool debug_dsrs = !xtensa->regs_fetched || LOG_LEVEL_IS(LOG_LVL_DEBUG);
union xtensa_reg_val_u *regvals = calloc(reg_list_size, sizeof(*regvals));
@ -1030,6 +1170,25 @@ int xtensa_fetch_all_regs(struct target *target)
/* Save (windowed) A3 so cache matches physical AR3; A3 usable as scratch */
xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A3));
xtensa_queue_dbg_reg_read(xtensa, XDMREG_DDR, a3_buf);
if (xtensa->core_config->core_type == XT_NX) {
/* Save (windowed) A0 as well--it will be required for reading PC */
xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A0));
xtensa_queue_dbg_reg_read(xtensa, XDMREG_DDR, a0_buf);
/* Set MS.DispSt, clear MS.DE prior to accessing ARs. This ensures ARs remain
* in correct order even for reversed register groups (overflow/underflow).
*/
ms_idx = xtensa->nx_reg_idx[XT_NX_REG_IDX_MS];
uint32_t ms_regno = xtensa->optregs[ms_idx - XT_NUM_REGS].reg_num;
xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, ms_regno, XT_REG_A3));
xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A3));
xtensa_queue_dbg_reg_read(xtensa, XDMREG_DDR, ms_buf);
LOG_TARGET_DEBUG(target, "Overriding MS (0x%x): 0x%x", ms_regno, XT_MS_DISPST_DBG);
xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, XT_MS_DISPST_DBG);
xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3));
xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, ms_regno, XT_REG_A3));
}
int res = xtensa_window_state_save(target, &woe);
if (res != ERROR_OK)
goto xtensa_fetch_all_regs_done;
@ -1052,11 +1211,13 @@ int xtensa_fetch_all_regs(struct target *target)
dsrs[XT_REG_IDX_AR0 + i + j].buf);
}
}
if (xtensa->core_config->windowed)
if (xtensa->core_config->windowed) {
/* Now rotate the window so we'll see the next 16 registers. The final rotate
* will wraparound, */
/* leaving us in the state we were. */
xtensa_queue_exec_ins(xtensa, XT_INS_ROTW(xtensa, 4));
* will wraparound, leaving us in the state we were.
* Each ROTW rotates 4 registers on LX and 8 on NX */
int rotw_arg = (xtensa->core_config->core_type == XT_LX) ? 4 : 2;
xtensa_queue_exec_ins(xtensa, XT_INS_ROTW(xtensa, rotw_arg));
}
}
xtensa_window_state_restore(target, woe);
@ -1074,6 +1235,10 @@ int xtensa_fetch_all_regs(struct target *target)
xtensa_core_status_check(target);
a3 = buf_get_u32(a3_buf, 0, 32);
if (xtensa->core_config->core_type == XT_NX) {
a0 = buf_get_u32(a0_buf, 0, 32);
ms = buf_get_u32(ms_buf, 0, 32);
}
if (xtensa->core_config->coproc) {
cpenable = buf_get_u32(regvals[XT_REG_IDX_CPENABLE].buf, 0, 32);
@ -1104,17 +1269,30 @@ int xtensa_fetch_all_regs(struct target *target)
break;
case XT_REG_SPECIAL:
if (reg_num == XT_PC_REG_NUM_VIRTUAL) {
/* reg number of PC for debug interrupt depends on NDEBUGLEVEL */
reg_num = XT_EPC_REG_NUM_BASE + xtensa->core_config->debug.irq_level;
} else if (reg_num == xtensa_regs[XT_REG_IDX_PS].reg_num) {
if (xtensa->core_config->core_type == XT_LX) {
/* reg number of PC for debug interrupt depends on NDEBUGLEVEL */
reg_num = XT_EPC_REG_NUM_BASE + xtensa->core_config->debug.irq_level;
xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, reg_num, XT_REG_A3));
} else {
/* NX PC read through CALL0(0) and reading A0 */
xtensa_queue_exec_ins(xtensa, XT_INS_CALL0(xtensa, 0));
xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_DDR, XT_REG_A0));
xtensa_queue_dbg_reg_read(xtensa, XDMREG_DDR, regvals[i].buf);
xtensa_queue_dbg_reg_read(xtensa, XDMREG_DSR, dsrs[i].buf);
reg_fetched = false;
}
} else if ((xtensa->core_config->core_type == XT_LX)
&& (reg_num == xtensa_regs[XT_REG_IDX_PS].reg_num)) {
/* reg number of PS for debug interrupt depends on NDEBUGLEVEL */
reg_num = XT_EPS_REG_NUM_BASE + xtensa->core_config->debug.irq_level;
xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, reg_num, XT_REG_A3));
} else if (reg_num == xtensa_regs[XT_REG_IDX_CPENABLE].reg_num) {
/* CPENABLE already read/updated; don't re-read */
reg_fetched = false;
break;
} else {
xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, reg_num, XT_REG_A3));
}
xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, reg_num, XT_REG_A3));
break;
default:
reg_fetched = false;
@ -1154,9 +1332,15 @@ int xtensa_fetch_all_regs(struct target *target)
}
}
if (xtensa->core_config->windowed)
if (xtensa->core_config->windowed) {
/* We need the windowbase to decode the general addresses. */
windowbase = buf_get_u32(regvals[XT_REG_IDX_WINDOWBASE].buf, 0, 32);
uint32_t wb_idx = (xtensa->core_config->core_type == XT_LX) ?
XT_REG_IDX_WINDOWBASE : xtensa->nx_reg_idx[XT_NX_REG_IDX_WB];
windowbase = buf_get_u32(regvals[wb_idx].buf, 0, 32);
if (xtensa->core_config->core_type == XT_NX)
windowbase = (windowbase & XT_WB_P_MSK) >> XT_WB_P_SHIFT;
}
/* Decode the result and update the cache. */
for (unsigned int i = 0; i < reg_list_size; i++) {
struct xtensa_reg_desc *rlist = (i < XT_NUM_REGS) ? xtensa_regs : xtensa->optregs;
@ -1180,6 +1364,16 @@ int xtensa_fetch_all_regs(struct target *target)
bool is_dirty = (i == XT_REG_IDX_CPENABLE);
if (xtensa_extra_debug_log)
LOG_INFO("Register %s: 0x%X", reg_list[i].name, regval);
if (rlist[ridx].reg_num == XT_PC_REG_NUM_VIRTUAL &&
xtensa->core_config->core_type == XT_NX) {
/* A0 from prior CALL0 points to next instruction; decrement it */
regval -= 3;
is_dirty = 1;
} else if (i == ms_idx) {
LOG_TARGET_DEBUG(target, "Caching MS: 0x%x", ms);
regval = ms;
is_dirty = 1;
}
xtensa_reg_set(target, i, regval);
reg_list[i].dirty = is_dirty; /*always do this _after_ xtensa_reg_set! */
}
@ -1214,6 +1408,11 @@ int xtensa_fetch_all_regs(struct target *target)
/* We have used A3 (XT_REG_RELGEN) as a scratch register. Restore and flag for write-back. */
xtensa_reg_set(target, XT_REG_IDX_A3, a3);
xtensa_mark_register_dirty(xtensa, XT_REG_IDX_A3);
if (xtensa->core_config->core_type == XT_NX) {
xtensa_reg_set(target, XT_REG_IDX_A0, a0);
xtensa_mark_register_dirty(xtensa, XT_REG_IDX_A0);
}
xtensa->regs_fetched = true;
xtensa_fetch_all_regs_done:
free(regvals);
@ -1262,7 +1461,7 @@ int xtensa_get_gdb_reg_list(struct target *target,
struct xtensa_reg_desc *rlist = (i < XT_NUM_REGS) ? xtensa_regs : xtensa->optregs;
unsigned int ridx = (i < XT_NUM_REGS) ? i : i - XT_NUM_REGS;
int sparse_idx = rlist[ridx].dbreg_num;
if (i == XT_REG_IDX_PS) {
if (i == XT_REG_IDX_PS && xtensa->core_config->core_type == XT_LX) {
if (xtensa->eps_dbglevel_idx == 0) {
LOG_ERROR("eps_dbglevel_idx not set\n");
return ERROR_FAIL;
@ -1372,10 +1571,13 @@ int xtensa_prepare_resume(struct target *target,
if (xtensa->hw_brps[slot]) {
/* Write IBREAKA[slot] and set bit #slot in IBREAKENABLE */
xtensa_reg_set(target, XT_REG_IDX_IBREAKA0 + slot, xtensa->hw_brps[slot]->address);
if (xtensa->core_config->core_type == XT_NX)
xtensa_reg_set(target, xtensa->nx_reg_idx[XT_NX_REG_IDX_IBREAKC0] + slot, XT_IBREAKC_FB);
bpena |= BIT(slot);
}
}
xtensa_reg_set(target, XT_REG_IDX_IBREAKENABLE, bpena);
if (xtensa->core_config->core_type == XT_LX)
xtensa_reg_set(target, XT_REG_IDX_IBREAKENABLE, bpena);
/* Here we write all registers to the targets */
int res = xtensa_write_dirty_registers(target);
@ -1390,6 +1592,7 @@ int xtensa_do_resume(struct target *target)
LOG_TARGET_DEBUG(target, "start");
xtensa_cause_reset(target);
xtensa_queue_exec_ins(xtensa, XT_INS_RFDO(xtensa));
int res = xtensa_dm_queue_execute(&xtensa->dbg_mod);
if (res != ERROR_OK) {
@ -1467,13 +1670,14 @@ int xtensa_do_step(struct target *target, int current, target_addr_t address, in
return ERROR_TARGET_NOT_HALTED;
}
if (xtensa->eps_dbglevel_idx == 0) {
LOG_ERROR("eps_dbglevel_idx not set\n");
if (xtensa->eps_dbglevel_idx == 0 && xtensa->core_config->core_type == XT_LX) {
LOG_TARGET_ERROR(target, "eps_dbglevel_idx not set\n");
return ERROR_FAIL;
}
/* Save old ps (EPS[dbglvl] on LX), pc */
oldps = xtensa_reg_get(target, xtensa->eps_dbglevel_idx);
oldps = xtensa_reg_get(target, (xtensa->core_config->core_type == XT_LX) ?
xtensa->eps_dbglevel_idx : XT_REG_IDX_PS);
oldpc = xtensa_reg_get(target, XT_REG_IDX_PC);
cause = xtensa_cause_get(target);
@ -1542,7 +1746,7 @@ int xtensa_do_step(struct target *target, int current, target_addr_t address, in
if (!handle_breakpoints && (cause & (DEBUGCAUSE_BI | DEBUGCAUSE_BN)))
/* handle normal SW breakpoint */
xtensa_cause_clear(target); /* so we don't recurse into the same routine */
if ((oldps & 0xf) >= icountlvl) {
if (xtensa->core_config->core_type == XT_LX && ((oldps & 0xf) >= icountlvl)) {
/* Lower interrupt level to allow stepping, but flag eps[dbglvl] to be restored */
ps_lowered = true;
uint32_t newps = (oldps & ~0xf) | (icountlvl - 1);
@ -1554,10 +1758,16 @@ int xtensa_do_step(struct target *target, int current, target_addr_t address, in
oldps);
}
do {
xtensa_reg_set(target, XT_REG_IDX_ICOUNTLEVEL, icountlvl);
xtensa_reg_set(target, XT_REG_IDX_ICOUNT, icount_val);
if (xtensa->core_config->core_type == XT_LX) {
xtensa_reg_set(target, XT_REG_IDX_ICOUNTLEVEL, icountlvl);
xtensa_reg_set(target, XT_REG_IDX_ICOUNT, icount_val);
} else {
xtensa_queue_dbg_reg_write(xtensa, XDMREG_DCRSET, OCDDCR_STEPREQUEST);
}
/* Now ICOUNT is set, we can resume as if we were going to run */
/* Now that ICOUNT (LX) or DCR.StepRequest (NX) is set,
* we can resume as if we were going to run
*/
res = xtensa_prepare_resume(target, current, address, 0, 0);
if (res != ERROR_OK) {
LOG_TARGET_ERROR(target, "Failed to prepare resume for single step");
@ -2108,6 +2318,22 @@ int xtensa_poll(struct target *target)
OCDDSR_DEBUGPENDBREAK | OCDDSR_DEBUGINTBREAK | OCDDSR_DEBUGPENDTRAX |
OCDDSR_DEBUGINTTRAX |
OCDDSR_DEBUGPENDHOST | OCDDSR_DEBUGINTHOST);
if (xtensa->core_config->core_type == XT_NX) {
/* Enable imprecise exceptions while in halted state */
xtensa_reg_val_t ps = xtensa_reg_get(target, XT_REG_IDX_PS);
xtensa_reg_val_t newps = ps & ~(XT_PS_DIEXC_MSK);
xtensa_mark_register_dirty(xtensa, XT_REG_IDX_PS);
LOG_TARGET_DEBUG(target, "Enabling PS.DIEXC: 0x%08x -> 0x%08x", ps, newps);
xtensa_queue_dbg_reg_write(xtensa, XDMREG_DDR, newps);
xtensa_queue_exec_ins(xtensa, XT_INS_RSR(xtensa, XT_SR_DDR, XT_REG_A3));
xtensa_queue_exec_ins(xtensa, XT_INS_WSR(xtensa, XT_SR_PS, XT_REG_A3));
res = xtensa_dm_queue_execute(&xtensa->dbg_mod);
if (res != ERROR_OK) {
LOG_TARGET_ERROR(target, "Failed to write PS.DIEXC (%d)!", res);
return res;
}
xtensa_core_status_check(target);
}
}
} else {
target->debug_reason = DBG_REASON_NOTHALTED;
@ -2326,6 +2552,8 @@ int xtensa_breakpoint_remove(struct target *target, struct breakpoint *breakpoin
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
xtensa->hw_brps[slot] = NULL;
if (xtensa->core_config->core_type == XT_NX)
xtensa_reg_set(target, xtensa->nx_reg_idx[XT_NX_REG_IDX_IBREAKC0] + slot, 0);
LOG_TARGET_DEBUG(target, "cleared HW breakpoint %u @ " TARGET_ADDR_FMT, slot, breakpoint->address);
return ERROR_OK;
}
@ -3073,8 +3301,10 @@ COMMAND_HELPER(xtensa_cmd_xtdef_do, struct xtensa *xtensa)
const char *core_name = CMD_ARGV[0];
if (strcasecmp(core_name, "LX") == 0) {
xtensa->core_config->core_type = XT_LX;
} else if (strcasecmp(core_name, "NX") == 0) {
xtensa->core_config->core_type = XT_NX;
} else {
LOG_ERROR("xtdef [LX]\n");
LOG_ERROR("xtdef [LX|NX]\n");
return ERROR_COMMAND_SYNTAX_ERROR;
}
return ERROR_OK;
@ -3456,6 +3686,33 @@ COMMAND_HELPER(xtensa_cmd_xtreg_do, struct xtensa *xtensa)
xtensa->eps_dbglevel_idx = XT_NUM_REGS + xtensa->num_optregs - 1;
LOG_DEBUG("Setting PS (%s) index to %d", rptr->name, xtensa->eps_dbglevel_idx);
}
if (xtensa->core_config->core_type == XT_NX) {
enum xtensa_nx_reg_idx idx = XT_NX_REG_IDX_NUM;
if (strcmp(rptr->name, "ibreakc0") == 0)
idx = XT_NX_REG_IDX_IBREAKC0;
else if (strcmp(rptr->name, "wb") == 0)
idx = XT_NX_REG_IDX_WB;
else if (strcmp(rptr->name, "ms") == 0)
idx = XT_NX_REG_IDX_MS;
else if (strcmp(rptr->name, "ievec") == 0)
idx = XT_NX_REG_IDX_IEVEC;
else if (strcmp(rptr->name, "ieextern") == 0)
idx = XT_NX_REG_IDX_IEEXTERN;
else if (strcmp(rptr->name, "mesr") == 0)
idx = XT_NX_REG_IDX_MESR;
else if (strcmp(rptr->name, "mesrclr") == 0)
idx = XT_NX_REG_IDX_MESRCLR;
if (idx < XT_NX_REG_IDX_NUM) {
if (xtensa->nx_reg_idx[idx] != 0) {
LOG_ERROR("nx_reg_idx[%d] previously set to %d",
idx, xtensa->nx_reg_idx[idx]);
return ERROR_FAIL;
}
xtensa->nx_reg_idx[idx] = XT_NUM_REGS + xtensa->num_optregs - 1;
LOG_DEBUG("NX reg %s: index %d (%d)",
rptr->name, xtensa->nx_reg_idx[idx], idx);
}
}
} else if (strcmp(rptr->name, "cpenable") == 0) {
xtensa->core_config->coproc = true;
}
@ -3640,6 +3897,12 @@ COMMAND_HELPER(xtensa_cmd_mask_interrupts_do, struct xtensa *xtensa)
command_print(CMD, "Current ISR step mode: %s", st);
return ERROR_OK;
}
if (xtensa->core_config->core_type == XT_NX) {
command_print(CMD, "ERROR: ISR step mode only supported on Xtensa LX");
return ERROR_FAIL;
}
/* Masking is ON -> interrupts during stepping are OFF, and vice versa */
if (!strcasecmp(CMD_ARGV[0], "off"))
state = XT_STEPPING_ISR_ON;

View File

@ -35,6 +35,7 @@
#define XT_ISNS_SZ_MAX 3
/* PS register bits (LX) */
#define XT_PS_RING(_v_) ((uint32_t)((_v_) & 0x3) << 6)
#define XT_PS_RING_MSK (0x3 << 6)
#define XT_PS_RING_GET(_v_) (((_v_) >> 6) & 0x3)
@ -42,6 +43,31 @@
#define XT_PS_OWB_MSK (0xF << 8)
#define XT_PS_WOE_MSK BIT(18)
/* PS register bits (NX) */
#define XT_PS_DIEXC_MSK BIT(2)
/* MS register bits (NX) */
#define XT_MS_DE_MSK BIT(5)
#define XT_MS_DISPST_MSK (0x1f)
#define XT_MS_DISPST_DBG (0x10)
/* WB register bits (NX) */
#define XT_WB_P_SHIFT (0)
#define XT_WB_P_MSK (0x7U << XT_WB_P_SHIFT)
#define XT_WB_C_SHIFT (4)
#define XT_WB_C_MSK (0x7U << XT_WB_C_SHIFT)
#define XT_WB_N_SHIFT (8)
#define XT_WB_N_MSK (0x7U << XT_WB_N_SHIFT)
#define XT_WB_S_SHIFT (30)
#define XT_WB_S_MSK (0x3U << XT_WB_S_SHIFT)
/* IBREAKC register bits (NX) */
#define XT_IBREAKC_FB (0x80000000)
/* Definitions for imprecise exception registers (NX) */
#define XT_IMPR_EXC_MSK (0x00000013)
#define XT_MESRCLR_IMPR_EXC_MSK (0x00000090)
#define XT_LOCAL_MEM_REGIONS_NUM_MAX 8
#define XT_AREGS_NUM_MAX 64
@ -79,6 +105,7 @@ struct xtensa_keyval_info_s {
enum xtensa_type {
XT_UNDEF = 0,
XT_LX,
XT_NX,
};
struct xtensa_cache_config {
@ -167,6 +194,17 @@ enum xtensa_stepping_isr_mode {
XT_STEPPING_ISR_ON, /* interrupts are enabled during stepping */
};
enum xtensa_nx_reg_idx {
XT_NX_REG_IDX_IBREAKC0 = 0,
XT_NX_REG_IDX_WB,
XT_NX_REG_IDX_MS,
XT_NX_REG_IDX_IEVEC, /* IEVEC, IEEXTERN, and MESR must be contiguous */
XT_NX_REG_IDX_IEEXTERN,
XT_NX_REG_IDX_MESR,
XT_NX_REG_IDX_MESRCLR,
XT_NX_REG_IDX_NUM
};
/* Only supported in cores with in-CPU MMU. None of Espressif chips as of now. */
enum xtensa_mode {
XT_MODE_RING0,
@ -232,6 +270,8 @@ struct xtensa {
uint8_t come_online_probes_num;
bool proc_syscall;
bool halt_request;
uint32_t nx_stop_cause;
uint32_t nx_reg_idx[XT_NX_REG_IDX_NUM];
struct xtensa_keyval_info_s scratch_ars[XT_AR_SCRATCH_NUM];
bool regs_fetched; /* true after first register fetch completed successfully */
};

View File

@ -246,6 +246,7 @@ struct xtensa_dm_reg_offsets {
#define OCDDCR_ENABLEOCD BIT(0)
#define OCDDCR_DEBUGINTERRUPT BIT(1)
#define OCDDCR_INTERRUPTALLCONDS BIT(2)
#define OCDDCR_STEPREQUEST BIT(3) /* NX only */
#define OCDDCR_BREAKINEN BIT(16)
#define OCDDCR_BREAKOUTEN BIT(17)
#define OCDDCR_DEBUGSWACTIVE BIT(20)
@ -259,6 +260,8 @@ struct xtensa_dm_reg_offsets {
#define OCDDSR_EXECBUSY BIT(2)
#define OCDDSR_EXECOVERRUN BIT(3)
#define OCDDSR_STOPPED BIT(4)
#define OCDDSR_STOPCAUSE (0xF << 5) /* NX only */
#define OCDDSR_STOPCAUSE_SHIFT (5) /* NX only */
#define OCDDSR_COREWROTEDDR BIT(10)
#define OCDDSR_COREREADDDR BIT(11)
#define OCDDSR_HOSTWROTEDDR BIT(14)
@ -275,12 +278,24 @@ struct xtensa_dm_reg_offsets {
#define OCDDSR_BREAKINITI BIT(26)
#define OCDDSR_DBGMODPOWERON BIT(31)
/* NX stop cause */
#define OCDDSR_STOPCAUSE_DI (0) /* Debug Interrupt */
#define OCDDSR_STOPCAUSE_SS (1) /* Single-step completed */
#define OCDDSR_STOPCAUSE_IB (2) /* HW breakpoint (IBREAKn match) */
#define OCDDSR_STOPCAUSE_B1 (4) /* SW breakpoint (BREAK.1 instruction) */
#define OCDDSR_STOPCAUSE_BN (5) /* SW breakpoint (BREAK.N instruction) */
#define OCDDSR_STOPCAUSE_B (6) /* SW breakpoint (BREAK instruction) */
#define OCDDSR_STOPCAUSE_DB0 (8) /* HW watchpoint (DBREAK0 match) */
#define OCDDSR_STOPCAUSE_DB1 (9) /* HW watchpoint (DBREAK0 match) */
/* LX stop cause */
#define DEBUGCAUSE_IC BIT(0) /* ICOUNT exception */
#define DEBUGCAUSE_IB BIT(1) /* IBREAK exception */
#define DEBUGCAUSE_DB BIT(2) /* DBREAK exception */
#define DEBUGCAUSE_BI BIT(3) /* BREAK instruction encountered */
#define DEBUGCAUSE_BN BIT(4) /* BREAK.N instruction encountered */
#define DEBUGCAUSE_DI BIT(5) /* Debug Interrupt */
#define DEBUGCAUSE_VALID BIT(31) /* Pseudo-value to trigger reread (NX only) */
#define TRAXCTRL_TREN BIT(0) /* Trace enable. Tracing starts on 0->1 */
#define TRAXCTRL_TRSTP BIT(1) /* Trace Stop. Make 1 to stop trace. */

View File

@ -7,10 +7,6 @@
# #
#################################################################################################
# FIXME use some standard target config, maybe create one from this
#
# source [find target/...cfg]
source [find target/at91sam9g20.cfg]
set _FLASHTYPE nandflash_cs3

0
tcl/interface/ftdi/ashling-opella-ld-jtag.cfg Executable file → Normal file
View File

0
tcl/interface/ftdi/ashling-opella-ld-swd.cfg Executable file → Normal file
View File

View File

@ -0,0 +1,42 @@
# SPDX-License-Identifier: GPL-2.0-or-later
#
# Config for Raspberry Pi GPIO header
#
# This is best used with a fast enough buffer but also
# is suitable for direct connection if the target voltage
# matches RPi's 3.3V and the cable is short enough.
#
# Do not forget the GND connection, e.g. pin 20 of the GPIO header.
#
# GPIO 25 (pin 22) previously used for TMS/SWDIO is pulled-down by default.
# The JTAG/SWD specification requires pull-up at the target board
# for either signal. Connecting the signal pulled-up on the target
# to the pull-down on the adapter is not a good idea.
# GPIO 8 is pulled-up by default.
echo "Warn : TMS/SWDIO moved to GPIO 8 (pin 24). Check the wiring please!"
# Each of the JTAG lines need a gpio number set: tck tms tdi tdo
# Header pin numbers: 23 24 19 21
adapter gpio tck -chip 0 11
adapter gpio tms -chip 0 8
adapter gpio tdi -chip 0 10
adapter gpio tdo -chip 0 9
# Each of the SWD lines need a gpio number set: swclk swdio
# Header pin numbers: 23 24
adapter gpio swclk -chip 0 11
adapter gpio swdio -chip 0 8
# If you define trst or srst, use appropriate reset_config
# Header pin numbers: TRST - 26, SRST - 18
# adapter gpio trst -chip 0 7
# reset_config trst_only
# adapter gpio srst -chip 0 24
# reset_config srst_only srst_push_pull
# or if you have both connected,
# reset_config trst_and_srst srst_push_pull

View File

@ -1,44 +1,71 @@
# SPDX-License-Identifier: GPL-2.0-or-later
#
# Config for using Raspberry Pi's expansion header
#
# This is best used with a fast enough buffer but also
# is suitable for direct connection if the target voltage
# matches RPi's 3.3V and the cable is short enough.
#
# Do not forget the GND connection, pin 6 of the expansion header.
#
# Config for Raspberry Pi used as a bitbang adapter.
# https://www.raspberrypi.com/documentation/computers/raspberry-pi.html
# Supports all models with 40-pin or 26-pin GPIO connector up to Raspberry Pi 4 B
# also supports Raspberry Pi Zero, Zero W and Zero 2 W.
# Adapter speed calibration is computed from cpufreq/scaling_max_freq.
# Adjusts automatically if CPU is overclocked.
adapter driver bcm2835gpio
bcm2835gpio peripheral_base 0x20000000
proc read_file { name } {
if {[catch {open $name r} fd]} {
return ""
}
set result [read $fd]
close $fd
return $result
}
proc measure_clock {} {
set result [exec vcgencmd measure_clock arm]
set clock_hz [lindex [split $result "="] 1]
expr { $clock_hz / 1000 }
}
proc get_max_cpu_clock { default } {
set clock [read_file /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq]
if { $clock > 100000 } {
return $clock
}
# cpufreq not available. As the last resort try Broadcom's proprietary utility
if {![catch measure_clock clock] && $clock > 100000} {
return $clock
}
echo "WARNING: Host CPU clock unknown."
echo "WARNING: Using the highest possible value $default kHz as a safe default."
echo "WARNING: Expect JTAG/SWD clock significantly slower than requested."
return $default
}
set compat [read_file /proc/device-tree/compatible]
set clocks_per_timing_loop 4
if {[string match *bcm2711* $compat]} {
set speed_offset 52
} elseif {[string match *bcm2837* $compat] || [string match *bcm2710* $compat]} {
set speed_offset 34
} elseif {[string match *bcm2836* $compat] || [string match *bcm2709* $compat]} {
set speed_offset 36
} elseif {[string match *bcm2835* $compat] || [string match *bcm2708* $compat]} {
set clocks_per_timing_loop 6
set speed_offset 32
} else {
set speed_offset 32
echo "WARNING: Unknown type of the host SoC. Expect JTAG/SWD clock slower than requested."
}
set clock [get_max_cpu_clock 2000000]
set speed_coeff [expr { $clock / $clocks_per_timing_loop }]
# Transition delay calculation: SPEED_COEFF/khz - SPEED_OFFSET
# These depend on system clock, calibrated for stock 700MHz
# bcm2835gpio speed SPEED_COEFF SPEED_OFFSET
bcm2835gpio speed_coeffs 113714 28
# The coefficients depend on system clock and CPU frequency scaling.
bcm2835gpio speed_coeffs $speed_coeff $speed_offset
# Each of the JTAG lines need a gpio number set: tck tms tdi tdo
# Header pin numbers: 23 22 19 21
adapter gpio tck -chip 0 11
adapter gpio tms -chip 0 25
adapter gpio tdi -chip 0 10
adapter gpio tdo -chip 0 9
# Each of the SWD lines need a gpio number set: swclk swdio
# Header pin numbers: 23 22
adapter gpio swclk -chip 0 11
adapter gpio swdio -chip 0 25
# If you define trst or srst, use appropriate reset_config
# Header pin numbers: TRST - 26, SRST - 18
# adapter gpio trst -chip 0 7
# reset_config trst_only
# adapter gpio srst -chip 0 24
# reset_config srst_only srst_push_pull
# or if you have both connected,
# reset_config trst_and_srst srst_push_pull
source [find interface/raspberrypi-gpio-connector.cfg]

View File

@ -1,44 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-or-later
#
# Config for using Raspberry Pi's expansion header
#
# This is best used with a fast enough buffer but also
# is suitable for direct connection if the target voltage
# matches RPi's 3.3V and the cable is short enough.
#
# Do not forget the GND connection, pin 6 of the expansion header.
#
echo "WARNING: interface/raspberrypi2-native.cfg is deprecated."
echo "WARNING: Please use interface/raspberrypi-native.cfg for all Raspberry Pi models."
adapter driver bcm2835gpio
bcm2835gpio peripheral_base 0x3F000000
# Transition delay calculation: SPEED_COEFF/khz - SPEED_OFFSET
# These depend on system clock, calibrated for scaling_max_freq 900MHz
# bcm2835gpio speed SPEED_COEFF SPEED_OFFSET
bcm2835gpio speed_coeffs 225000 36
# Each of the JTAG lines need a gpio number set: tck tms tdi tdo
# Header pin numbers: 23 22 19 21
adapter gpio tck -chip 0 11
adapter gpio tms -chip 0 25
adapter gpio tdi -chip 0 10
adapter gpio tdo -chip 0 9
# Each of the SWD lines need a gpio number set: swclk swdio
# Header pin numbers: 23 22
adapter gpio swclk -chip 0 11
adapter gpio swdio -chip 0 25
# If you define trst or srst, use appropriate reset_config
# Header pin numbers: TRST - 26, SRST - 18
# adapter gpio trst -chip 0 7
# reset_config trst_only
# adapter gpio srst -chip 0 24
# reset_config srst_only srst_push_pull
# or if you have both connected,
# reset_config trst_and_srst srst_push_pull
source [find interface/raspberrypi-native.cfg]

View File

@ -26,6 +26,13 @@ if { [info exists CPUTAPID] } {
set _CPUTAPID 0x01002927
}
# Set to '1' to start rescue mode
if { [info exists RESCUE] } {
set _RESCUE $RESCUE
} else {
set _RESCUE 0
}
# Set to '0' or '1' for single core configuration, 'SMP' for -rtos hwthread
# handling of both cores, anything else for isolated debugging of both cores
if { [info exists USE_CORE] } {
@ -37,6 +44,29 @@ set _BOTH_CORES [expr { $_USE_CORE != 0 && $_USE_CORE != 1 }]
swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID
# The rescue debug port uses the DP CTRL/STAT bit DBGPWRUPREQ to reset the
# PSM (power on state machine) of the RP2040 with a flag set in the
# VREG_AND_POR_CHIP_RESET register. Once the reset is released
# (by clearing the DBGPWRUPREQ flag), the bootrom will run, see this flag,
# and halt. Allowing the user to load some fresh code, rather than loading
# the potentially broken code stored in flash
if { $_RESCUE } {
dap create $_CHIPNAME.rescue_dap -chain-position $_CHIPNAME.cpu -dp-id $_CPUTAPID -instance-id 0xf -ignore-syspwrupack
init
# Clear DBGPWRUPREQ
$_CHIPNAME.rescue_dap dpreg 0x4 0x00000000
# Verifying CTRL/STAT is 0
set _CTRLSTAT [$_CHIPNAME.rescue_dap dpreg 0x4]
if {[expr {$_CTRLSTAT & 0xf0000000}]} {
echo "Rescue failed, DP CTRL/STAT readback $_CTRLSTAT"
} else {
echo "Now restart OpenOCD without RESCUE flag and load code to RP2040"
}
shutdown
}
# core 0
if { $_USE_CORE != 1 } {
dap create $_CHIPNAME.dap0 -chain-position $_CHIPNAME.cpu -dp-id $_CPUTAPID -instance-id 0

View File

@ -18,7 +18,7 @@ proc cortex_m_test_cpu_speed { address { timeout 200 } { cycles_per_loop 4 } } {
halt
# Backup registers and memory.
set backup_regs [get_reg -force {pc r0 xPSR}]
set backup_regs [get_reg -force {pc r0 xpsr}]
set backup_mem [read_memory $address 16 3]
# We place the following code at the given address to measure the