diff --git a/HACKING b/HACKING
index 0d24957e1..b7ef0705b 100644
--- a/HACKING
+++ b/HACKING
@@ -201,7 +201,7 @@ Further reading: http://www.coreboot.org/Git
The code review is intended to take as long as a week or two to allow
maintainers and contributors who work on OpenOCD only in their spare
-time oportunity to perform a review and raise objections.
+time opportunity to perform a review and raise objections.
With Gerrit much of the urgency of getting things committed has been
removed as the work in progress is safely stored in Gerrit and
diff --git a/README b/README
index 985e39a98..30443d37c 100644
--- a/README
+++ b/README
@@ -42,7 +42,7 @@ e.g.:
openocd -f interface/ftdi/jtagkey2.cfg -c "transport select jtag" \
-f target/ti_calypso.cfg
- openocd -f interface/stlink-v2-1.cfg -c "transport select hla_swd" \
+ openocd -f interface/stlink.cfg -c "transport select hla_swd" \
-f target/stm32l0.cfg
After OpenOCD startup, connect GDB with
@@ -117,17 +117,18 @@ Debug targets
-------------
ARM11, ARM7, ARM9, AVR32, Cortex-A, Cortex-R, Cortex-M, LS102x-SAP,
-Feroceon/Dragonite, DSP563xx, DSP5680xx, FA526, MIPS EJTAG, NDS32,
-XScale, Intel Quark.
+Feroceon/Dragonite, DSP563xx, DSP5680xx, EnSilica eSi-RISC, FA526, MIPS
+EJTAG, NDS32, XScale, Intel Quark.
Flash drivers
-------------
-ADUC702x, AT91SAM, ATH79, AVR, CFI, DSP5680xx, EFM32, EM357, FM3, FM4, Kinetis,
-LPC8xx/LPC1xxx/LPC2xxx/LPC541xx, LPC2900, LPCSPIFI, Marvell QSPI,
-Milandr, NIIET, NuMicro, PIC32mx, PSoC4, PSoC5LP, SiM3x, Stellaris, STM32,
-STMSMI, STR7x, STR9x, nRF51; NAND controllers of AT91SAM9, LPC3180, LPC32xx,
-i.MX31, MXC, NUC910, Orion/Kirkwood, S3C24xx, S3C6400, XMC1xxx, XMC4xxx.
+ADUC702x, AT91SAM, ATH79, AVR, CFI, DSP5680xx, EFM32, EM357, eSi-TSMC,
+FM3, FM4, Kinetis, LPC8xx/LPC1xxx/LPC2xxx/LPC541xx, LPC2900, LPCSPIFI,
+Marvell QSPI, Milandr, NIIET, NuMicro, PIC32mx, PSoC4, PSoC5LP, SiM3x,
+Stellaris, STM32, STMSMI, STR7x, STR9x, nRF51; NAND controllers of
+AT91SAM9, LPC3180, LPC32xx, i.MX31, MXC, NUC910, Orion/Kirkwood,
+S3C24xx, S3C6400, XMC1xxx, XMC4xxx.
==================
diff --git a/contrib/60-openocd.rules b/contrib/60-openocd.rules
index af092c18b..692e1b10b 100644
--- a/contrib/60-openocd.rules
+++ b/contrib/60-openocd.rules
@@ -1,4 +1,6 @@
# Copy this file to /etc/udev/rules.d/
+# If rules fail to reload automatically, you can refresh udev rules
+# with the command "udevadm control --reload"
ACTION!="add|change", GOTO="openocd_rules_end"
SUBSYSTEM!="usb|tty|hidraw", GOTO="openocd_rules_end"
diff --git a/contrib/loaders/Makefile b/contrib/loaders/Makefile
index a9a27706d..0a637aff5 100644
--- a/contrib/loaders/Makefile
+++ b/contrib/loaders/Makefile
@@ -12,6 +12,7 @@ ARM_CROSS_COMPILE ?= arm-none-eabi-
arm_dirs = \
flash/fm4 \
flash/kinetis_ke \
+ flash/max32xxx \
flash/xmc1xxx \
debug/xscale
diff --git a/contrib/loaders/flash/max32xxx/Makefile b/contrib/loaders/flash/max32xxx/Makefile
new file mode 100644
index 000000000..8f3f9242e
--- /dev/null
+++ b/contrib/loaders/flash/max32xxx/Makefile
@@ -0,0 +1,19 @@
+BIN2C = ../../../../src/helper/bin2char.sh
+
+CROSS_COMPILE ?= arm-none-eabi-
+AS = $(CROSS_COMPILE)as
+OBJCOPY = $(CROSS_COMPILE)objcopy
+
+all: max32xxx.inc
+
+%.elf: %.s
+ $(AS) $< -o $@
+
+%.bin: %.elf
+ $(OBJCOPY) -Obinary $< $@
+
+%.inc: %.bin
+ $(BIN2C) < $< > $@
+
+clean:
+ -rm -f *.elf *.bin *.inc
diff --git a/contrib/loaders/flash/max32xxx/max32xxx.inc b/contrib/loaders/flash/max32xxx/max32xxx.inc
new file mode 100644
index 000000000..442165d0d
--- /dev/null
+++ b/contrib/loaders/flash/max32xxx/max32xxx.inc
@@ -0,0 +1,6 @@
+/* Autogenerated with ../../../../src/helper/bin2char.sh */
+0xdf,0xf8,0x44,0x40,0xd0,0xf8,0x00,0x80,0xb8,0xf1,0x00,0x0f,0x1a,0xd0,0x47,0x68,
+0x47,0x45,0xf7,0xd0,0x22,0x60,0x02,0xf1,0x04,0x02,0x57,0xf8,0x04,0x8b,0xc4,0xf8,
+0x30,0x80,0xa5,0x68,0x45,0xf0,0x01,0x05,0xa5,0x60,0xd4,0xf8,0x08,0x80,0x18,0xf0,
+0x01,0x0f,0xfa,0xd1,0x8f,0x42,0x28,0xbf,0x00,0xf1,0x08,0x07,0x47,0x60,0x01,0x3b,
+0x03,0xb1,0xdf,0xe7,0x00,0xbe,0x00,0xbf,0x00,0x00,0x00,0x40,
diff --git a/contrib/loaders/flash/max32xxx/max32xxx.s b/contrib/loaders/flash/max32xxx/max32xxx.s
new file mode 100644
index 000000000..f5306d6c5
--- /dev/null
+++ b/contrib/loaders/flash/max32xxx/max32xxx.s
@@ -0,0 +1,70 @@
+/***************************************************************************
+ * Copyright (C) 2016 by Maxim Integrated *
+ * Kevin Gillespie . *
+ ***************************************************************************/
+
+.text
+.syntax unified
+.cpu cortex-m3
+.thumb
+.thumb_func
+
+/*
+ * Params :
+ * r0 = workarea start
+ * r1 = workarea end
+ * r2 = target address
+ * r3 = count (32bit words)
+ * r4 = pFLASH_CTRL_BASE
+ *
+ * Clobbered:
+ * r5 = FLASHWRITECMD
+ * r7 - rp
+ * r8 - wp, tmp
+ */
+
+write:
+
+wait_fifo:
+ldr r8, [r0, #0] /* read wp */
+cmp r8, #0 /* abort if wp == 0 */
+beq exit
+ldr r7, [r0, #4] /* read rp */
+cmp r7, r8 /* wait until rp != wp */
+beq wait_fifo
+
+mainloop:
+str r2, [r4, #0x00] /* FLSH_ADDR - write address */
+add r2, r2, #4 /* increment target address */
+ldr r8, [r7], #4
+str r8, [r4, #0x30] /* FLSH_DATA0 - write data */
+ldr r5, [r4, #0x08] /* FLSH_CN */
+orr r5, r5, #1
+str r5, [r4, #0x08] /* FLSH_CN - enable write */
+busy:
+ldr r8, [r4, #0x08] /* FLSH_CN */
+tst r8, #1
+bne busy
+
+cmp r7, r1 /* wrap rp at end of buffer */
+it cs
+addcs r7, r0, #8 /* skip loader args */
+str r7, [r0, #4] /* store rp */
+subs r3, r3, #1 /* decrement word count */
+cbz r3, exit /* loop if not done */
+b wait_fifo
+exit:
+bkpt
diff --git a/contrib/rtos-helpers/uCOS-III-openocd.c b/contrib/rtos-helpers/uCOS-III-openocd.c
index 9037334f2..5a37bd4c5 100644
--- a/contrib/rtos-helpers/uCOS-III-openocd.c
+++ b/contrib/rtos-helpers/uCOS-III-openocd.c
@@ -3,8 +3,8 @@
* impossible to determine the appropriate offsets within the structure
* unaided. A priori knowledge of offsets based on os_dbg.c is tied to a
* specific release and thusly, brittle. The constants defined below
- * provide the neccessary information OpenOCD needs to provide support
- * in the most robust manner possible.
+ * provide the necessary information OpenOCD needs to provide support in
+ * the most robust manner possible.
*
* This file should be linked along with the project to enable RTOS
* support for uC/OS-III.
diff --git a/doc/openocd.texi b/doc/openocd.texi
index 3932db3c3..6c5cb502e 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -2114,6 +2114,7 @@ In such cases, just specify the relevant port number as "disabled".
If you disable all access through TCP/IP, you will need to
use the command line @option{-pipe} option.
+@anchor{gdb_port}
@deffn {Command} gdb_port [number]
@cindex GDB server
Normally gdb listens to a TCP/IP port, but GDB can also
@@ -2139,11 +2140,15 @@ The GDB port for the first target will be the base port, the
second target will listen on gdb_port + 1, and so on.
When not specified during the configuration stage,
the port @var{number} defaults to 3333.
+When @var{number} is not a numeric value, incrementing it to compute
+the next port number does not work. In this case, specify the proper
+@var{number} for each target by using the option @code{-gdb-port} of the
+commands @command{target create} or @command{$target_name configure}.
+@xref{gdbportoverride,,option -gdb-port}.
Note: when using "gdb_port pipe", increasing the default remote timeout in
gdb (with 'set remotetimeout') is recommended. An insufficient timeout may
cause initialization to fail with "Unknown remote qXfer reply: OK".
-
@end deffn
@deffn {Command} tcl_port [number]
@@ -4270,6 +4275,8 @@ compact Thumb2 instruction set.
@item @code{dragonite} -- resembles arm966e
@item @code{dsp563xx} -- implements Freescale's 24-bit DSP.
(Support for this is still incomplete.)
+@item @code{esirisc} -- this is an EnSilica eSi-RISC core.
+The current implementation supports eSi-32xx cores.
@item @code{fa526} -- resembles arm920 (w/o Thumb)
@item @code{feroceon} -- resembles arm926
@item @code{mips_m4k} -- a MIPS core
@@ -4458,6 +4465,13 @@ to the target. Currently, only the @code{aarch64} target makes use of this optio
where it is a mandatory configuration for the target run control.
@xref{armcrosstrigger,,ARM Cross-Trigger Interface},
for instruction on how to declare and control a CTI instance.
+
+@anchor{gdbportoverride}
+@item @code{-gdb-port} @var{number} -- see command @command{gdb_port} for the
+possible values of the parameter @var{number}, which are not only numeric values.
+Use this option to override, for this target only, the global parameter set with
+command @command{gdb_port}.
+@xref{gdb_port,,command gdb_port}.
@end itemize
@end deffn
@@ -5635,6 +5649,27 @@ Note that in order for this command to take effect, the target needs to be reset
supported.}
@end deffn
+@deffn {Flash Driver} esirisc
+Members of the eSi-RISC family may optionally include internal flash programmed
+via the eSi-TSMC Flash interface. Additional parameters are required to
+configure the driver: @option{cfg_address} is the base address of the
+configuration register interface, @option{clock_hz} is the expected clock
+frequency, and @option{wait_states} is the number of configured read wait states.
+
+@example
+flash bank $_FLASHNAME esirisc base_address size_bytes 0 0 $_TARGETNAME cfg_address clock_hz wait_states
+@end example
+
+@deffn Command {esirisc_flash mass_erase} (bank_id)
+Erases all pages in data memory for the bank identified by @option{bank_id}.
+@end deffn
+
+@deffn Command {esirisc_flash ref_erase} (bank_id)
+Erases the reference cell for the bank identified by @option{bank_id}. This is
+an uncommon operation.
+@end deffn
+@end deffn
+
@deffn {Flash Driver} fm3
All members of the FM3 microcontroller family from Fujitsu
include internal flash and use ARM Cortex-M3 cores.
@@ -6394,23 +6429,24 @@ flash bank $_FLASHNAME stm32f1x 0x08080000 0 0 0 $_TARGETNAME
Some stm32f1x-specific commands are defined:
@deffn Command {stm32f1x lock} num
-Locks the entire stm32 device.
+Locks the entire stm32 device against reading.
The @var{num} parameter is a value shown by @command{flash banks}.
@end deffn
@deffn Command {stm32f1x unlock} num
-Unlocks the entire stm32 device.
+Unlocks the entire stm32 device for reading. This command will cause
+a mass erase of the entire stm32 device if previously locked.
The @var{num} parameter is a value shown by @command{flash banks}.
@end deffn
@deffn Command {stm32f1x mass_erase} num
-Mass erases the entire stm32f1x device.
+Mass erases the entire stm32 device.
The @var{num} parameter is a value shown by @command{flash banks}.
@end deffn
@deffn Command {stm32f1x options_read} num
-Read and display the stm32 option bytes written by
-the @command{stm32f1x options_write} command.
+Reads and displays active stm32 option bytes loaded during POR
+or upon executing the @command{stm32f1x options_load} command.
The @var{num} parameter is a value shown by @command{flash banks}.
@end deffn
@@ -6418,6 +6454,13 @@ The @var{num} parameter is a value shown by @command{flash banks}.
Writes the stm32 option byte with the specified values.
The @var{num} parameter is a value shown by @command{flash banks}.
@end deffn
+
+@deffn Command {stm32f1x options_load} num
+Generates a special kind of reset to re-load the stm32 option bytes written
+by the @command{stm32f1x options_write} or @command{flash protect} commands
+without having to power cycle the target. Not applicable to stm32f1x devices.
+The @var{num} parameter is a value shown by @command{flash banks}.
+@end deffn
@end deffn
@deffn {Flash Driver} stm32f2x
@@ -6584,6 +6627,42 @@ The @var{num} parameter is a value shown by @command{flash banks}.
Mass erases the entire stm32l4x device.
The @var{num} parameter is a value shown by @command{flash banks}.
@end deffn
+
+@deffn Command {stm32l4x option_read} num reg_offset
+Reads an option byte register from the stm32l4x device.
+The @var{num} parameter is a value shown by @command{flash banks}, @var{reg_offset}
+is the register offset of the Option byte to read.
+
+For example to read the FLASH_OPTR register:
+@example
+stm32l4x option_read 0 0x20
+# Option Register: <0x40022020> = 0xffeff8aa
+@end example
+
+The above example will read out the FLASH_OPTR register which contains the RDP
+option byte, Watchdog configuration, BOR level etc.
+@end deffn
+
+@deffn Command {stm32l4x option_write} num reg_offset reg_mask
+Write an option byte register of the stm32l4x device.
+The @var{num} parameter is a value shown by @command{flash banks}, @var{reg_offset}
+is the register offset of the Option byte to write, and @var{reg_mask} is the mask
+to apply when writing the register (only bits with a '1' will be touched).
+
+For example to write the WRP1AR option bytes:
+@example
+stm32l4x option_write 0 0x28 0x00FF0000 0x00FF00FF
+@end example
+
+The above example will write the WRP1AR option register configuring the Write protection
+Area A for bank 1. The above example set WRP1AR_END=255, WRP1AR_START=0.
+This will effectively write protect all sectors in flash bank 1.
+@end deffn
+
+@deffn Command {stm32l4x option_load} num
+Forces a re-load of the option byte registers. Will cause a reset of the device.
+The @var{num} parameter is a value shown by @command{flash banks}.
+@end deffn
@end deffn
@deffn {Flash Driver} str7x
@@ -8687,6 +8766,12 @@ Selects whether interrupts will be processed when single stepping
configure l2x cache
@end deffn
+@deffn Command {cortex_a mmu dump} [@option{0}|@option{1}|@option{addr} address [@option{num_entries}]]
+Dump the MMU translation table from TTB0 or TTB1 register, or from physical
+memory location @var{address}. When dumping the table from @var{address}, print at most
+@var{num_entries} page table entries. @var{num_entries} is optional, if omitted, the maximum
+possible (4096) entries are printed.
+@end deffn
@subsection ARMv7-R specific commands
@cindex Cortex-R
@@ -8777,7 +8862,7 @@ baud with our custom divisor to get 12MHz)
@item @code{itmdump -f /dev/ttyUSB1 -d1}
@item OpenOCD invocation line:
@example
-openocd -f interface/stlink-v2-1.cfg \
+openocd -f interface/stlink.cfg \
-c "transport select hla_swd" \
-f target/stm32l1.cfg \
-c "tpiu config external uart off 24000000 12000000"
@@ -8885,6 +8970,29 @@ Selects whether interrupts will be processed when single stepping. The default c
@option{on}.
@end deffn
+@section EnSilica eSi-RISC Architecture
+
+eSi-RISC is a highly configurable microprocessor architecture for embedded systems
+provided by EnSilica. (See: @url{http://www.ensilica.com/risc-ip/}.)
+
+@subsection esirisc specific commands
+@deffn Command {esirisc cache_arch} (@option{harvard}|@option{von_neumann})
+Configure the caching architecture. Targets with the @code{UNIFIED_ADDRESS_SPACE}
+option disabled employ a Harvard architecture. By default, @option{von_neumann} is assumed.
+@end deffn
+
+@deffn Command {esirisc flush_caches}
+Flush instruction and data caches. This command requires that the target is halted
+when the command is issued and configured with an instruction or data cache.
+@end deffn
+
+@deffn Command {esirisc hwdc} (@option{all}|@option{none}|mask ...)
+Configure hardware debug control. The HWDC register controls which exceptions return
+control back to the debugger. Possible masks are @option{all}, @option{none},
+@option{reset}, @option{interrupt}, @option{syscall}, @option{error}, and @option{debug}.
+By default, @option{reset}, @option{error}, and @option{debug} are enabled.
+@end deffn
+
@section Intel Architecture
Intel Quark X10xx is the first product in the Quark family of SoCs. It is an IA-32
diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am
index 9a58239eb..639330549 100644
--- a/src/flash/nor/Makefile.am
+++ b/src/flash/nor/Makefile.am
@@ -25,6 +25,7 @@ NOR_DRIVERS = \
%D%/dsp5680xx_flash.c \
%D%/efm32.c \
%D%/em357.c \
+ %D%/esirisc_flash.c \
%D%/faux.c \
%D%/fespi.c \
%D%/fm3.c \
@@ -36,6 +37,7 @@ NOR_DRIVERS = \
%D%/lpc288x.c \
%D%/lpc2900.c \
%D%/lpcspifi.c \
+ %D%/max32xxx.c \
%D%/mdr.c \
%D%/msp432.c \
%D%/mrvlqspi.c \
diff --git a/src/flash/nor/at91sam4.c b/src/flash/nor/at91sam4.c
index c5b31e964..2eec15e2a 100644
--- a/src/flash/nor/at91sam4.c
+++ b/src/flash/nor/at91sam4.c
@@ -2376,6 +2376,11 @@ static int sam4_GetInfo(struct sam4_chip *pChip)
{
const struct sam4_reg_list *pReg;
uint32_t regval;
+ int r;
+
+ r = sam4_ReadAllRegs(pChip);
+ if (r != ERROR_OK)
+ return r;
pReg = &(sam4_all_regs[0]);
while (pReg->name) {
@@ -2545,7 +2550,7 @@ static int sam4_GetDetails(struct sam4_bank_private *pPrivate)
sam4_explain_chipid_cidr(pPrivate->pChip);
return ERROR_FAIL;
} else {
- LOG_INFO("SAM4 Found chip %s, CIDR 0x%08x", pDetails->name, pDetails->chipid_cidr);
+ LOG_DEBUG("SAM4 Found chip %s, CIDR 0x%08x", pDetails->name, pDetails->chipid_cidr);
}
/* DANGER: THERE ARE DRAGONS HERE */
@@ -2581,14 +2586,35 @@ static int sam4_GetDetails(struct sam4_bank_private *pPrivate)
return ERROR_OK;
}
-static int _sam4_probe(struct flash_bank *bank, int noise)
+static int sam4_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+ struct sam4_bank_private *pPrivate;
+ int k = bank->size / 1024;
+
+ pPrivate = get_sam4_bank_private(bank);
+ if (pPrivate == NULL) {
+ buf[0] = '\0';
+ return ERROR_FAIL;
+ }
+
+ snprintf(buf, buf_size,
+ "%s bank %d: %d kB at 0x%08" PRIx32,
+ pPrivate->pChip->details.name,
+ pPrivate->bank_number,
+ k,
+ bank->base);
+
+ return ERROR_OK;
+}
+
+static int sam4_probe(struct flash_bank *bank)
{
unsigned x;
int r;
struct sam4_bank_private *pPrivate;
- LOG_DEBUG("Begin: Bank: %d, Noise: %d", bank->bank_number, noise);
+ LOG_DEBUG("Begin: Bank: %d", bank->bank_number);
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
@@ -2616,7 +2642,7 @@ static int _sam4_probe(struct flash_bank *bank, int noise)
for (x = 0; x < SAM4_MAX_FLASH_BANKS; x++) {
if (bank->base == pPrivate->pChip->details.bank[x].base_address) {
bank->size = pPrivate->pChip->details.bank[x].size_bytes;
- LOG_INFO("SAM4 Set flash bank to %08X - %08X, idx %d", bank->base, bank->base + bank->size, x);
+ LOG_DEBUG("SAM4 Set flash bank to %08X - %08X, idx %d", bank->base, bank->base + bank->size, x);
break;
}
}
@@ -2655,14 +2681,15 @@ static int _sam4_probe(struct flash_bank *bank, int noise)
return r;
}
-static int sam4_probe(struct flash_bank *bank)
-{
- return _sam4_probe(bank, 1);
-}
-
static int sam4_auto_probe(struct flash_bank *bank)
{
- return _sam4_probe(bank, 0);
+ struct sam4_bank_private *pPrivate;
+
+ pPrivate = get_sam4_bank_private(bank);
+ if (pPrivate && pPrivate->probed)
+ return ERROR_OK;
+
+ return sam4_probe(bank);
}
static int sam4_erase(struct flash_bank *bank, int first, int last)
@@ -2762,20 +2789,17 @@ static int sam4_page_read(struct sam4_bank_private *pPrivate, unsigned pagenum,
return r;
}
-static int sam4_page_write(struct sam4_bank_private *pPrivate, unsigned pagenum, const uint8_t *buf)
+static int sam4_set_wait(struct sam4_bank_private *pPrivate)
{
- uint32_t adr;
- uint32_t status;
uint32_t fmr; /* EEFC Flash Mode Register */
int r;
- adr = pagenum * pPrivate->page_size;
- adr = (adr + pPrivate->base_address);
-
/* Get flash mode register value */
r = target_read_u32(pPrivate->pChip->target, pPrivate->controller_address, &fmr);
- if (r != ERROR_OK)
- LOG_DEBUG("Error Read failed: read flash mode register");
+ if (r != ERROR_OK) {
+ LOG_ERROR("Error Read failed: read flash mode register");
+ return r;
+ }
/* Clear flash wait state field */
fmr &= 0xfffff0ff;
@@ -2786,7 +2810,19 @@ static int sam4_page_write(struct sam4_bank_private *pPrivate, unsigned pagenum,
LOG_DEBUG("Flash Mode: 0x%08x", ((unsigned int)(fmr)));
r = target_write_u32(pPrivate->pBank->target, pPrivate->controller_address, fmr);
if (r != ERROR_OK)
- LOG_DEBUG("Error Write failed: set flash mode register");
+ LOG_ERROR("Error Write failed: set flash mode register");
+
+ return r;
+}
+
+static int sam4_page_write(struct sam4_bank_private *pPrivate, unsigned pagenum, const uint8_t *buf)
+{
+ uint32_t adr;
+ uint32_t status;
+ int r;
+
+ adr = pagenum * pPrivate->page_size;
+ adr = (adr + pPrivate->base_address);
/* 1st sector 8kBytes - page 0 - 15*/
/* 2nd sector 8kBytes - page 16 - 30*/
@@ -2874,6 +2910,10 @@ static int sam4_write(struct flash_bank *bank,
goto done;
}
+ r = sam4_set_wait(pPrivate);
+ if (r != ERROR_OK)
+ goto done;
+
/* what page do we start & end in? */
page_cur = offset / pPrivate->page_size;
page_end = (offset + count - 1) / pPrivate->page_size;
@@ -3091,7 +3131,8 @@ showall:
}
if ((who >= 0) && (((unsigned)(who)) < pChip->details.n_gpnvms)) {
r = FLASHD_GetGPNVM(&(pChip->details.bank[0]), who, &v);
- command_print(CMD_CTX, "sam4-gpnvm%u: %u", who, v);
+ if (r == ERROR_OK)
+ command_print(CMD_CTX, "sam4-gpnvm%u: %u", who, v);
return r;
} else {
command_print(CMD_CTX, "sam4-gpnvm invalid GPNVM: %u", who);
@@ -3203,5 +3244,6 @@ struct flash_driver at91sam4_flash = {
.auto_probe = sam4_auto_probe,
.erase_check = default_flash_blank_check,
.protect_check = sam4_protect_check,
+ .info = sam4_info,
.free_driver_priv = sam4_free_driver_priv,
};
diff --git a/src/flash/nor/at91samd.c b/src/flash/nor/at91samd.c
index 017d1441e..5f172d118 100644
--- a/src/flash/nor/at91samd.c
+++ b/src/flash/nor/at91samd.c
@@ -165,12 +165,13 @@ static const struct samd_part samd21_parts[] = {
{ 0xE, "SAMD21E14A", 16, 2 },
/* SAMR21 parts have integrated SAMD21 with a radio */
+ { 0x18, "SAMR21G19A", 256, 32 }, /* with 512k of serial flash */
{ 0x19, "SAMR21G18A", 256, 32 },
{ 0x1A, "SAMR21G17A", 128, 32 },
- { 0x1B, "SAMR21G16A", 64, 32 },
+ { 0x1B, "SAMR21G16A", 64, 16 },
{ 0x1C, "SAMR21E18A", 256, 32 },
{ 0x1D, "SAMR21E17A", 128, 32 },
- { 0x1E, "SAMR21E16A", 64, 32 },
+ { 0x1E, "SAMR21E16A", 64, 16 },
/* SAMD21 B Variants (Table 3-7 from rev I of datasheet) */
{ 0x20, "SAMD21J16B", 64, 8 },
diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c
index 2b3146da9..62db3feea 100644
--- a/src/flash/nor/drivers.c
+++ b/src/flash/nor/drivers.c
@@ -38,6 +38,7 @@ extern struct flash_driver cfi_flash;
extern struct flash_driver dsp5680xx_flash;
extern struct flash_driver efm32_flash;
extern struct flash_driver em357_flash;
+extern struct flash_driver esirisc_flash;
extern struct flash_driver faux_flash;
extern struct flash_driver fm3_flash;
extern struct flash_driver fm4_flash;
@@ -49,6 +50,7 @@ extern struct flash_driver lpc2000_flash;
extern struct flash_driver lpc288x_flash;
extern struct flash_driver lpc2900_flash;
extern struct flash_driver lpcspifi_flash;
+extern struct flash_driver max32xxx_flash;
extern struct flash_driver mdr_flash;
extern struct flash_driver mrvlqspi_flash;
extern struct flash_driver msp432_flash;
@@ -103,6 +105,7 @@ static struct flash_driver *flash_drivers[] = {
&dsp5680xx_flash,
&efm32_flash,
&em357_flash,
+ &esirisc_flash,
&faux_flash,
&fm3_flash,
&fm4_flash,
@@ -114,6 +117,7 @@ static struct flash_driver *flash_drivers[] = {
&lpc288x_flash,
&lpc2900_flash,
&lpcspifi_flash,
+ &max32xxx_flash,
&mdr_flash,
&mrvlqspi_flash,
&msp432_flash,
diff --git a/src/flash/nor/esirisc_flash.c b/src/flash/nor/esirisc_flash.c
new file mode 100644
index 000000000..f3833df1c
--- /dev/null
+++ b/src/flash/nor/esirisc_flash.c
@@ -0,0 +1,621 @@
+/***************************************************************************
+ * Copyright (C) 2018 by Square, Inc. *
+ * Steven Stallion *
+ * James Zhao *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see . *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* eSi-TSMC Flash Registers */
+#define CONTROL 0x00 /* Control Register */
+#define TIMING0 0x04 /* Timing Register 0 */
+#define TIMING1 0x08 /* Timing Register 1 */
+#define TIMING2 0x0c /* Timing Register 2 */
+#define UNLOCK1 0x18 /* Unlock 1 */
+#define UNLOCK2 0x1c /* Unlock 2 */
+#define ADDRESS 0x20 /* Erase/Program Address */
+#define PB_DATA 0x24 /* Program Buffer Data */
+#define PB_INDEX 0x28 /* Program Buffer Index */
+#define STATUS 0x2c /* Status Register */
+#define REDUN_0 0x30 /* Redundant Address 0 */
+#define REDUN_1 0x34 /* Redundant Address 1 */
+
+/* Control Fields */
+#define CONTROL_SLM (1<<0) /* Sleep Mode */
+#define CONTROL_WP (1<<1) /* Register Write Protect */
+#define CONTROL_E (1<<3) /* Erase */
+#define CONTROL_EP (1<<4) /* Erase Page */
+#define CONTROL_P (1<<5) /* Program Flash */
+#define CONTROL_ERC (1<<6) /* Erase Reference Cell */
+#define CONTROL_R (1<<7) /* Recall Trim Code */
+#define CONTROL_AP (1<<8) /* Auto-Program */
+
+/* Timing Fields */
+#define TIMING0_R(x) (((x) << 0) & 0x3f) /* Read Wait States */
+#define TIMING0_F(x) (((x) << 16) & 0xffff0000) /* Tnvh Clock Cycles */
+#define TIMING1_E(x) (((x) << 0) & 0xffffff) /* Tme/Terase/Tre Clock Cycles */
+#define TIMING2_P(x) (((x) << 0) & 0xffff) /* Tprog Clock Cycles */
+#define TIMING2_H(x) (((x) << 16) & 0xff0000) /* Clock Cycles in 100ns */
+#define TIMING2_T(x) (((x) << 24) & 0xf000000) /* Clock Cycles in 10ns */
+
+/* Status Fields */
+#define STATUS_BUSY (1<<0) /* Busy (Erase/Program) */
+#define STATUS_WER (1<<1) /* Write Protect Error */
+#define STATUS_DR (1<<2) /* Disable Redundancy */
+#define STATUS_DIS (1<<3) /* Discharged */
+#define STATUS_BO (1<<4) /* Brown Out */
+
+/* Redundant Address Fields */
+#define REDUN_R (1<<0) /* Used */
+#define REDUN_P(x) (((x) << 12) & 0x7f000) /* Redundant Page Address */
+
+/*
+ * The eSi-TSMC Flash manual provides two sets of timings based on the
+ * underlying flash process. By default, 90nm is assumed.
+ */
+#if 0 /* 55nm */
+#define TNVH 5000 /* 5us */
+#define TME 80000000 /* 80ms */
+#define TERASE 160000000 /* 160ms */
+#define TRE 100000000 /* 100ms */
+#define TPROG 8000 /* 8us */
+#else /* 90nm */
+#define TNVH 5000 /* 5us */
+#define TME 20000000 /* 20ms */
+#define TERASE 40000000 /* 40ms */
+#define TRE 40000000 /* 40ms */
+#define TPROG 40000 /* 40us */
+#endif
+
+#define CONTROL_TIMEOUT 5000 /* 5s */
+#define PAGE_SIZE 4096
+#define PB_MAX 32
+
+#define NUM_NS_PER_S 1000000000ULL
+
+struct esirisc_flash_bank {
+ bool probed;
+ uint32_t cfg;
+ uint32_t clock;
+ uint32_t wait_states;
+};
+
+FLASH_BANK_COMMAND_HANDLER(esirisc_flash_bank_command)
+{
+ struct esirisc_flash_bank *esirisc_info;
+
+ if (CMD_ARGC < 9)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ esirisc_info = calloc(1, sizeof(struct esirisc_flash_bank));
+
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], esirisc_info->cfg);
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[7], esirisc_info->clock);
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[8], esirisc_info->wait_states);
+
+ bank->driver_priv = esirisc_info;
+
+ return ERROR_OK;
+}
+
+/*
+ * Register writes are ignored if the control.WP flag is set; the
+ * following sequence is required to modify this flag even when
+ * protection is disabled.
+ */
+static int esirisc_flash_unlock(struct flash_bank *bank)
+{
+ struct esirisc_flash_bank *esirisc_info = bank->driver_priv;
+ struct target *target = bank->target;
+
+ target_write_u32(target, esirisc_info->cfg + UNLOCK1, 0x7123);
+ target_write_u32(target, esirisc_info->cfg + UNLOCK2, 0x812a);
+ target_write_u32(target, esirisc_info->cfg + UNLOCK1, 0xbee1);
+
+ return ERROR_OK;
+}
+
+static int esirisc_flash_disable_protect(struct flash_bank *bank)
+{
+ struct esirisc_flash_bank *esirisc_info = bank->driver_priv;
+ struct target *target = bank->target;
+ uint32_t control;
+
+ target_read_u32(target, esirisc_info->cfg + CONTROL, &control);
+ if (!(control & CONTROL_WP))
+ return ERROR_OK;
+
+ esirisc_flash_unlock(bank);
+
+ control &= ~CONTROL_WP;
+
+ target_write_u32(target, esirisc_info->cfg + CONTROL, control);
+
+ return ERROR_OK;
+}
+
+static int esirisc_flash_enable_protect(struct flash_bank *bank)
+{
+ struct esirisc_flash_bank *esirisc_info = bank->driver_priv;
+ struct target *target = bank->target;
+ uint32_t control;
+
+ target_read_u32(target, esirisc_info->cfg + CONTROL, &control);
+ if (control & CONTROL_WP)
+ return ERROR_OK;
+
+ esirisc_flash_unlock(bank);
+
+ control |= CONTROL_WP;
+
+ target_write_u32(target, esirisc_info->cfg + CONTROL, control);
+
+ return ERROR_OK;
+}
+
+static int esirisc_flash_check_status(struct flash_bank *bank)
+{
+ struct esirisc_flash_bank *esirisc_info = bank->driver_priv;
+ struct target *target = bank->target;
+ uint32_t status;
+
+ target_read_u32(target, esirisc_info->cfg + STATUS, &status);
+ if (status & STATUS_WER) {
+ LOG_ERROR("%s: bad status: 0x%" PRIx32, bank->name, status);
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ return ERROR_OK;
+}
+
+static int esirisc_flash_clear_status(struct flash_bank *bank)
+{
+ struct esirisc_flash_bank *esirisc_info = bank->driver_priv;
+ struct target *target = bank->target;
+
+ target_write_u32(target, esirisc_info->cfg + STATUS, STATUS_WER);
+
+ return ERROR_OK;
+}
+
+static int esirisc_flash_wait(struct flash_bank *bank, int ms)
+{
+ struct esirisc_flash_bank *esirisc_info = bank->driver_priv;
+ struct target *target = bank->target;
+ uint32_t status;
+ int64_t t;
+
+ t = timeval_ms();
+ for (;;) {
+ target_read_u32(target, esirisc_info->cfg + STATUS, &status);
+ if (!(status & STATUS_BUSY))
+ return ERROR_OK;
+
+ if ((timeval_ms() - t) > ms)
+ return ERROR_TARGET_TIMEOUT;
+
+ keep_alive();
+ }
+}
+
+static int esirisc_flash_control(struct flash_bank *bank, uint32_t control)
+{
+ struct esirisc_flash_bank *esirisc_info = bank->driver_priv;
+ struct target *target = bank->target;
+
+ esirisc_flash_clear_status(bank);
+
+ target_write_u32(target, esirisc_info->cfg + CONTROL, control);
+
+ int retval = esirisc_flash_wait(bank, CONTROL_TIMEOUT);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: control timed out: 0x%" PRIx32, bank->name, control);
+ return retval;
+ }
+
+ return esirisc_flash_check_status(bank);
+}
+
+static int esirisc_flash_recall(struct flash_bank *bank)
+{
+ return esirisc_flash_control(bank, CONTROL_R);
+}
+
+static int esirisc_flash_erase(struct flash_bank *bank, int first, int last)
+{
+ struct esirisc_flash_bank *esirisc_info = bank->driver_priv;
+ struct target *target = bank->target;
+ int retval = ERROR_OK;
+
+ if (target->state != TARGET_HALTED)
+ return ERROR_TARGET_NOT_HALTED;
+
+ esirisc_flash_disable_protect(bank);
+
+ for (int page = first; page < last; ++page) {
+ uint32_t address = page * PAGE_SIZE;
+
+ target_write_u32(target, esirisc_info->cfg + ADDRESS, address);
+
+ retval = esirisc_flash_control(bank, CONTROL_EP);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to erase address: 0x%" PRIx32, bank->name, address);
+ break;
+ }
+ }
+
+ esirisc_flash_enable_protect(bank);
+
+ return retval;
+}
+
+static int esirisc_flash_mass_erase(struct flash_bank *bank)
+{
+ struct esirisc_flash_bank *esirisc_info = bank->driver_priv;
+ struct target *target = bank->target;
+ int retval;
+
+ if (target->state != TARGET_HALTED)
+ return ERROR_TARGET_NOT_HALTED;
+
+ esirisc_flash_disable_protect(bank);
+
+ target_write_u32(target, esirisc_info->cfg + ADDRESS, 0);
+
+ retval = esirisc_flash_control(bank, CONTROL_E);
+ if (retval != ERROR_OK)
+ LOG_ERROR("%s: failed to mass erase", bank->name);
+
+ esirisc_flash_enable_protect(bank);
+
+ return retval;
+}
+
+/*
+ * Per TSMC, the reference cell should be erased once per sample. This
+ * is typically done during wafer sort, however we include support for
+ * those that may need to calibrate flash at a later time.
+ */
+static int esirisc_flash_ref_erase(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ int retval;
+
+ if (target->state != TARGET_HALTED)
+ return ERROR_TARGET_NOT_HALTED;
+
+ esirisc_flash_disable_protect(bank);
+
+ retval = esirisc_flash_control(bank, CONTROL_ERC);
+ if (retval != ERROR_OK)
+ LOG_ERROR("%s: failed to erase reference cell", bank->name);
+
+ esirisc_flash_enable_protect(bank);
+
+ return retval;
+}
+
+static int esirisc_flash_protect(struct flash_bank *bank, int set, int first, int last)
+{
+ struct target *target = bank->target;
+
+ if (target->state != TARGET_HALTED)
+ return ERROR_TARGET_NOT_HALTED;
+
+ if (set)
+ esirisc_flash_enable_protect(bank);
+ else
+ esirisc_flash_disable_protect(bank);
+
+ return ERROR_OK;
+}
+
+static int esirisc_flash_fill_pb(struct flash_bank *bank,
+ const uint8_t *buffer, uint32_t count)
+{
+ struct esirisc_flash_bank *esirisc_info = bank->driver_priv;
+ struct target *target = bank->target;
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+
+ /*
+ * The pb_index register is auto-incremented when pb_data is written
+ * and should be cleared before each operation.
+ */
+ target_write_u32(target, esirisc_info->cfg + PB_INDEX, 0);
+
+ /*
+ * The width of the pb_data register depends on the underlying
+ * target; writing one byte at a time incurs a significant
+ * performance penalty and should be avoided.
+ */
+ while (count > 0) {
+ uint32_t max_bytes = DIV_ROUND_UP(esirisc->num_bits, 8);
+ uint32_t num_bytes = MIN(count, max_bytes);
+
+ target_write_buffer(target, esirisc_info->cfg + PB_DATA, num_bytes, buffer);
+
+ buffer += num_bytes;
+ count -= num_bytes;
+ }
+
+ return ERROR_OK;
+}
+
+static int esirisc_flash_write(struct flash_bank *bank,
+ const uint8_t *buffer, uint32_t offset, uint32_t count)
+{
+ struct esirisc_flash_bank *esirisc_info = bank->driver_priv;
+ struct target *target = bank->target;
+ int retval = ERROR_OK;
+
+ if (target->state != TARGET_HALTED)
+ return ERROR_TARGET_NOT_HALTED;
+
+ esirisc_flash_disable_protect(bank);
+
+ /*
+ * The address register is auto-incremented based on the contents of
+ * the pb_index register after each operation completes. It can be
+ * set once provided pb_index is cleared before each operation.
+ */
+ target_write_u32(target, esirisc_info->cfg + ADDRESS, offset);
+
+ /*
+ * Care must be taken when filling the program buffer; a maximum of
+ * 32 bytes may be written at a time and may not cross a 32-byte
+ * boundary based on the current offset.
+ */
+ while (count > 0) {
+ uint32_t max_bytes = PB_MAX - (offset & 0x1f);
+ uint32_t num_bytes = MIN(count, max_bytes);
+
+ esirisc_flash_fill_pb(bank, buffer, num_bytes);
+
+ retval = esirisc_flash_control(bank, CONTROL_P);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to program address: 0x%" PRIx32, bank->name, offset);
+ break;
+ }
+
+ buffer += num_bytes;
+ offset += num_bytes;
+ count -= num_bytes;
+ }
+
+ esirisc_flash_enable_protect(bank);
+
+ return retval;
+}
+
+static uint32_t esirisc_flash_num_cycles(struct flash_bank *bank, uint64_t ns)
+{
+ struct esirisc_flash_bank *esirisc_info = bank->driver_priv;
+
+ /* apply scaling factor to avoid truncation */
+ uint64_t hz = (uint64_t)esirisc_info->clock * 1000;
+ uint64_t num_cycles = ((hz / NUM_NS_PER_S) * ns) / 1000;
+
+ if (hz % NUM_NS_PER_S > 0)
+ num_cycles++;
+
+ return num_cycles;
+}
+
+static int esirisc_flash_init(struct flash_bank *bank)
+{
+ struct esirisc_flash_bank *esirisc_info = bank->driver_priv;
+ struct target *target = bank->target;
+ uint32_t value;
+ int retval;
+
+ esirisc_flash_disable_protect(bank);
+
+ /* initialize timing registers */
+ value = TIMING0_F(esirisc_flash_num_cycles(bank, TNVH)) |
+ TIMING0_R(esirisc_info->wait_states);
+
+ LOG_DEBUG("TIMING0: 0x%" PRIx32, value);
+ target_write_u32(target, esirisc_info->cfg + TIMING0, value);
+
+ value = TIMING1_E(esirisc_flash_num_cycles(bank, TERASE));
+
+ LOG_DEBUG("TIMING1: 0x%" PRIx32, value);
+ target_write_u32(target, esirisc_info->cfg + TIMING1, value);
+
+ value = TIMING2_T(esirisc_flash_num_cycles(bank, 10)) |
+ TIMING2_H(esirisc_flash_num_cycles(bank, 100)) |
+ TIMING2_P(esirisc_flash_num_cycles(bank, TPROG));
+
+ LOG_DEBUG("TIMING2: 0x%" PRIx32, value);
+ target_write_u32(target, esirisc_info->cfg + TIMING2, value);
+
+ /* recall trim code */
+ retval = esirisc_flash_recall(bank);
+ if (retval != ERROR_OK)
+ LOG_ERROR("%s: failed to recall trim code", bank->name);
+
+ esirisc_flash_enable_protect(bank);
+
+ return retval;
+}
+
+static int esirisc_flash_probe(struct flash_bank *bank)
+{
+ struct esirisc_flash_bank *esirisc_info = bank->driver_priv;
+ struct target *target = bank->target;
+ int retval;
+
+ if (target->state != TARGET_HALTED)
+ return ERROR_TARGET_NOT_HALTED;
+
+ bank->num_sectors = bank->size / PAGE_SIZE;
+ bank->sectors = alloc_block_array(0, PAGE_SIZE, bank->num_sectors);
+
+ /*
+ * Register write protection is enforced using a single protection
+ * block for the entire bank. This is as good as it gets.
+ */
+ bank->num_prot_blocks = 1;
+ bank->prot_blocks = alloc_block_array(0, bank->size, bank->num_prot_blocks);
+
+ retval = esirisc_flash_init(bank);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to initialize bank", bank->name);
+ return retval;
+ }
+
+ esirisc_info->probed = true;
+
+ return ERROR_OK;
+}
+
+static int esirisc_flash_auto_probe(struct flash_bank *bank)
+{
+ struct esirisc_flash_bank *esirisc_info = bank->driver_priv;
+
+ if (esirisc_info->probed)
+ return ERROR_OK;
+
+ return esirisc_flash_probe(bank);
+}
+
+static int esirisc_flash_protect_check(struct flash_bank *bank)
+{
+ struct esirisc_flash_bank *esirisc_info = bank->driver_priv;
+ struct target *target = bank->target;
+ uint32_t control;
+
+ if (target->state != TARGET_HALTED)
+ return ERROR_TARGET_NOT_HALTED;
+
+ target_read_u32(target, esirisc_info->cfg + CONTROL, &control);
+
+ /* single protection block (also see: esirisc_flash_probe()) */
+ bank->prot_blocks[0].is_protected = !!(control & CONTROL_WP);
+
+ return ERROR_OK;
+}
+
+static int esirisc_flash_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+ struct esirisc_flash_bank *esirisc_info = bank->driver_priv;
+
+ snprintf(buf, buf_size,
+ "%4s cfg at 0x%" PRIx32 ", clock %" PRId32 ", wait_states %" PRId32,
+ "", /* align with first line */
+ esirisc_info->cfg,
+ esirisc_info->clock,
+ esirisc_info->wait_states);
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_esirisc_flash_mass_erase_command)
+{
+ struct flash_bank *bank;
+ int retval;
+
+ if (CMD_ARGC < 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = esirisc_flash_mass_erase(bank);
+
+ command_print(CMD_CTX, "mass erase %s",
+ (retval == ERROR_OK) ? "successful" : "failed");
+
+ return retval;
+}
+
+COMMAND_HANDLER(handle_esirisc_flash_ref_erase_command)
+{
+ struct flash_bank *bank;
+ int retval;
+
+ if (CMD_ARGC < 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = esirisc_flash_ref_erase(bank);
+
+ command_print(CMD_CTX, "erase reference cell %s",
+ (retval == ERROR_OK) ? "successful" : "failed");
+
+ return retval;
+}
+
+static const struct command_registration esirisc_flash_exec_command_handlers[] = {
+ {
+ .name = "mass_erase",
+ .handler = handle_esirisc_flash_mass_erase_command,
+ .mode = COMMAND_EXEC,
+ .help = "erases all pages in data memory",
+ .usage = "bank_id",
+ },
+ {
+ .name = "ref_erase",
+ .handler = handle_esirisc_flash_ref_erase_command,
+ .mode = COMMAND_EXEC,
+ .help = "erases reference cell (uncommon)",
+ .usage = "bank_id",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration esirisc_flash_command_handlers[] = {
+ {
+ .name = "esirisc_flash",
+ .mode = COMMAND_ANY,
+ .help = "eSi-RISC flash command group",
+ .usage = "",
+ .chain = esirisc_flash_exec_command_handlers,
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+struct flash_driver esirisc_flash = {
+ .name = "esirisc",
+ .commands = esirisc_flash_command_handlers,
+ .usage = "flash bank bank_id 'esirisc' base_address size_bytes 0 0 target "
+ "cfg_address clock_hz wait_states",
+ .flash_bank_command = esirisc_flash_bank_command,
+ .erase = esirisc_flash_erase,
+ .protect = esirisc_flash_protect,
+ .write = esirisc_flash_write,
+ .read = default_flash_read,
+ .probe = esirisc_flash_probe,
+ .auto_probe = esirisc_flash_auto_probe,
+ .erase_check = default_flash_blank_check,
+ .protect_check = esirisc_flash_protect_check,
+ .info = esirisc_flash_info,
+};
diff --git a/src/flash/nor/max32xxx.c b/src/flash/nor/max32xxx.c
new file mode 100644
index 000000000..ca037de4d
--- /dev/null
+++ b/src/flash/nor/max32xxx.c
@@ -0,0 +1,997 @@
+/***************************************************************************
+ * Copyright (C) 2016 by Maxim Integrated *
+ * Kevin Gillespie *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see . *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "imp.h"
+#include
+#include
+
+/* Register Addresses */
+#define FLSH_ADDR 0x000
+#define FLSH_CLKDIV 0x004
+#define FLSH_CN 0x008
+#define PR1E_ADDR 0x00C
+#define PR2S_ADDR 0x010
+#define PR2E_ADDR 0x014
+#define PR3S_ADDR 0x018
+#define PR3E_ADDR 0x01C
+#define FLSH_MD 0x020
+#define FLSH_INT 0x024
+#define FLSH_DATA0 0x030
+#define FLSH_DATA1 0x034
+#define FLSH_DATA2 0x038
+#define FLSH_DATA3 0x03C
+#define FLSH_BL_CTRL 0x170
+#define FLSH_PROT 0x300
+
+#define ARM_PID_REG 0xE00FFFE0
+#define MAX326XX_ID_REG 0x40000838
+
+/* Register settings */
+#define FLSH_INT_AF 0x00000002
+
+#define FLSH_CN_UNLOCK_MASK 0xF0000000
+#define FLSH_CN_UNLOCK_VALUE 0x20000000
+
+#define FLSH_CN_PEND 0x01000000
+
+#define FLSH_CN_ERASE_CODE_MASK 0x0000FF00
+#define FLSH_CN_ERASE_CODE_PGE 0x00005500
+#define FLSH_CN_ERASE_CODE_ME 0x0000AA00
+
+#define FLSH_CN_PGE 0x00000004
+#define FLSH_CN_ME 0x00000002
+#define FLSH_CN_WR 0x00000001
+#define FLASH_BL_CTRL_23 0x00020000
+#define FLASH_BL_CTRL_IFREN 0x00000001
+
+#define ARM_PID_DEFAULT_CM3 0xB4C3
+#define ARM_PID_DEFAULT_CM4 0xB4C4
+#define MAX326XX_ID 0x4D
+
+static int max32xxx_mass_erase(struct flash_bank *bank);
+
+struct max32xxx_flash_bank {
+ int probed;
+ int max326xx;
+ unsigned int flash_size;
+ unsigned int flc_base;
+ unsigned int sector_size;
+ unsigned int clkdiv_value;
+ unsigned int int_state;
+ unsigned int burst_size_bits;
+};
+
+/* see contib/loaders/flash/max32xxx/max32xxx.s for src */
+static const uint8_t write_code[] = {
+#include "../../contrib/loaders/flash/max32xxx/max32xxx.inc"
+};
+
+/* Config Command: flash bank name driver base size chip_width bus_width target [driver_option]
+ flash bank max32xxx 0 0 [burst_bits]
+ */
+FLASH_BANK_COMMAND_HANDLER(max32xxx_flash_bank_command)
+{
+ struct max32xxx_flash_bank *info;
+
+ if (CMD_ARGC < 9) {
+ LOG_WARNING("incomplete flash bank max32xxx configuration: 0 0 [burst_bits]");
+ return ERROR_FLASH_BANK_INVALID;
+ }
+
+ info = calloc(sizeof(struct max32xxx_flash_bank), 1);
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], info->flash_size);
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[6], info->flc_base);
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[7], info->sector_size);
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[8], info->clkdiv_value);
+
+ if (CMD_ARGC > 9)
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[9], info->burst_size_bits);
+ else
+ info->burst_size_bits = 32;
+
+ info->int_state = 0;
+ bank->driver_priv = info;
+ return ERROR_OK;
+}
+
+static int get_info(struct flash_bank *bank, char *buf, int buf_size)
+{
+ int printed;
+ struct max32xxx_flash_bank *info = bank->driver_priv;
+
+ if (info->probed == 0)
+ return ERROR_FLASH_BANK_NOT_PROBED;
+
+ printed = snprintf(buf, buf_size, "\nMaxim Integrated max32xxx flash driver\n");
+ buf += printed;
+ buf_size -= printed;
+ return ERROR_OK;
+}
+
+/***************************************************************************
+* flash operations
+***************************************************************************/
+
+static int max32xxx_flash_op_pre(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ struct max32xxx_flash_bank *info = bank->driver_priv;
+ uint32_t flsh_cn;
+ uint32_t bootloader;
+
+ /* Check if the flash controller is busy */
+ target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn);
+ if (flsh_cn & (FLSH_CN_PEND | FLSH_CN_ERASE_CODE_MASK | FLSH_CN_PGE |
+ FLSH_CN_ME | FLSH_CN_WR))
+ return ERROR_FLASH_BUSY;
+
+ /* Refresh flash controller timing */
+ target_write_u32(target, info->flc_base + FLSH_CLKDIV, info->clkdiv_value);
+
+ /* Clear and disable flash programming interrupts */
+ target_read_u32(target, info->flc_base + FLSH_INT, &info->int_state);
+ target_write_u32(target, info->flc_base + FLSH_INT, 0x00000000);
+
+ /* Clear the lower bit in the bootloader configuration register in case flash page 0 has been replaced */
+ if (target_read_u32(target, info->flc_base + FLSH_BL_CTRL, &bootloader) != ERROR_OK) {
+ LOG_ERROR("Read failure on FLSH_BL_CTRL");
+ return ERROR_FAIL;
+ }
+ if (bootloader & FLASH_BL_CTRL_23) {
+ LOG_WARNING("FLSH_BL_CTRL indicates BL mode 2 or mode 3.");
+ if (bootloader & FLASH_BL_CTRL_IFREN) {
+ LOG_WARNING("Flash page 0 swapped out, attempting to swap back in for programming");
+ bootloader &= ~(FLASH_BL_CTRL_IFREN);
+ if (target_write_u32(target, info->flc_base + FLSH_BL_CTRL, bootloader) != ERROR_OK) {
+ LOG_ERROR("Write failure on FLSH_BL_CTRL");
+ return ERROR_FAIL;
+ }
+ if (target_read_u32(target, info->flc_base + FLSH_BL_CTRL, &bootloader) != ERROR_OK) {
+ LOG_ERROR("Read failure on FLSH_BL_CTRL");
+ return ERROR_FAIL;
+ }
+ if (bootloader & FLASH_BL_CTRL_IFREN) {
+ /* Bummer */
+ LOG_ERROR("Unable to swap flash page 0 back in. Writes to page 0 will fail.");
+ }
+ }
+ }
+
+ /* Unlock flash */
+ flsh_cn &= ~FLSH_CN_UNLOCK_MASK;
+ flsh_cn |= FLSH_CN_UNLOCK_VALUE;
+ target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn);
+
+ /* Confirm flash is unlocked */
+ target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn);
+ if ((flsh_cn & FLSH_CN_UNLOCK_VALUE) != FLSH_CN_UNLOCK_VALUE)
+ return ERROR_FAIL;
+
+ return ERROR_OK;
+}
+
+static int max32xxx_flash_op_post(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ struct max32xxx_flash_bank *info = bank->driver_priv;
+ uint32_t flsh_cn;
+
+ /* Restore flash programming interrupts */
+ target_write_u32(target, info->flc_base + FLSH_INT, info->int_state);
+
+ /* Lock flash */
+ target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn);
+ flsh_cn &= ~FLSH_CN_UNLOCK_MASK;
+ target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn);
+ return ERROR_OK;
+}
+
+static int max32xxx_protect_check(struct flash_bank *bank)
+{
+ struct max32xxx_flash_bank *info = bank->driver_priv;
+ struct target *target = bank->target;
+ int i;
+ uint32_t temp_reg;
+
+ if (info->probed == 0)
+ return ERROR_FLASH_BANK_NOT_PROBED;
+
+ if (!info->max326xx) {
+ for (i = 0; i < bank->num_sectors; i++)
+ bank->sectors[i].is_protected = -1;
+
+ return ERROR_FLASH_OPER_UNSUPPORTED;
+ }
+
+ /* Check the protection */
+ for (i = 0; i < bank->num_sectors; i++) {
+ if (i%32 == 0)
+ target_read_u32(target, info->flc_base + FLSH_PROT + ((i/32)*4), &temp_reg);
+
+ if (temp_reg & (0x1 << i%32))
+ bank->sectors[i].is_protected = 1;
+ else
+ bank->sectors[i].is_protected = 0;
+ }
+ return ERROR_OK;
+}
+
+static int max32xxx_erase(struct flash_bank *bank, int first, int last)
+{
+ int banknr;
+ uint32_t flsh_cn, flsh_int;
+ struct max32xxx_flash_bank *info = bank->driver_priv;
+ struct target *target = bank->target;
+ int retval;
+ int retry;
+
+ if (bank->target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (info->probed == 0)
+ return ERROR_FLASH_BANK_NOT_PROBED;
+
+ if ((first < 0) || (last < first) || (last >= bank->num_sectors))
+ return ERROR_FLASH_SECTOR_INVALID;
+
+ if ((first == 0) && (last == (bank->num_sectors - 1)))
+ return max32xxx_mass_erase(bank);
+
+ /* Prepare to issue flash operation */
+ retval = max32xxx_flash_op_pre(bank);
+
+ if (retval != ERROR_OK)
+ return retval;
+
+ int erased = 0;
+ for (banknr = first; banknr <= last; banknr++) {
+
+ /* Check the protection */
+ if (bank->sectors[banknr].is_protected == 1) {
+ LOG_WARNING("Flash sector %d is protected", banknr);
+ continue;
+ } else
+ erased = 1;
+
+ /* Address is first word in page */
+ target_write_u32(target, info->flc_base + FLSH_ADDR, banknr * info->sector_size);
+
+ /* Write page erase code */
+ target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn);
+ flsh_cn |= FLSH_CN_ERASE_CODE_PGE;
+ target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn);
+
+ /* Issue page erase command */
+ flsh_cn |= 0x4;
+ target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn);
+
+ /* Wait until erase complete */
+ retry = 1000;
+ do {
+ target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn);
+ } while ((--retry > 0) && (flsh_cn & FLSH_CN_PEND));
+
+ if (retry <= 0) {
+ LOG_ERROR("Timed out waiting for flash page erase @ 0x%08x",
+ banknr * info->sector_size);
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ /* Check access violations */
+ target_read_u32(target, info->flc_base + FLSH_INT, &flsh_int);
+ if (flsh_int & FLSH_INT_AF) {
+ LOG_ERROR("Error erasing flash page %i", banknr);
+ target_write_u32(target, info->flc_base + FLSH_INT, 0);
+ max32xxx_flash_op_post(bank);
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ bank->sectors[banknr].is_erased = 1;
+ }
+
+ if (!erased) {
+ LOG_ERROR("All pages protected %d to %d", first, last);
+ max32xxx_flash_op_post(bank);
+ return ERROR_FAIL;
+ }
+
+ if (max32xxx_flash_op_post(bank) != ERROR_OK)
+ return ERROR_FAIL;
+
+ return ERROR_OK;
+}
+
+static int max32xxx_protect(struct flash_bank *bank, int set, int first, int last)
+{
+ struct max32xxx_flash_bank *info = bank->driver_priv;
+ struct target *target = bank->target;
+ int page;
+ uint32_t temp_reg;
+
+ if (bank->target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (info->probed == 0)
+ return ERROR_FLASH_BANK_NOT_PROBED;
+
+ if (!info->max326xx)
+ return ERROR_FLASH_OPER_UNSUPPORTED;
+
+ if ((first < 0) || (last < first) || (last >= bank->num_sectors))
+ return ERROR_FLASH_SECTOR_INVALID;
+
+ /* Setup the protection on the pages given */
+ for (page = first; page <= last; page++) {
+ if (set) {
+ /* Set the write/erase bit for this page */
+ target_read_u32(target, info->flc_base + FLSH_PROT + (page/32), &temp_reg);
+ temp_reg |= (0x1 << page%32);
+ target_write_u32(target, info->flc_base + FLSH_PROT + (page/32), temp_reg);
+ bank->sectors[page].is_protected = 1;
+ } else {
+ /* Clear the write/erase bit for this page */
+ target_read_u32(target, info->flc_base + FLSH_PROT + (page/32), &temp_reg);
+ temp_reg &= ~(0x1 << page%32);
+ target_write_u32(target, info->flc_base + FLSH_PROT + (page/32), temp_reg);
+ bank->sectors[page].is_protected = 0;
+ }
+ }
+
+ return ERROR_OK;
+}
+
+static int max32xxx_write_block(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t offset, uint32_t wcount)
+{
+ struct max32xxx_flash_bank *info = bank->driver_priv;
+ struct target *target = bank->target;
+ uint32_t buffer_size = 16384;
+ struct working_area *source;
+ struct working_area *write_algorithm;
+ uint32_t address = bank->base + offset;
+ struct reg_param reg_params[5];
+ struct armv7m_algorithm armv7m_info;
+ int retval = ERROR_OK;
+ /* power of two, and multiple of word size */
+ static const unsigned buf_min = 128;
+
+ /* for small buffers it's faster not to download an algorithm */
+ if (wcount * 4 < buf_min)
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+
+ LOG_DEBUG("(bank=%p buffer=%p offset=%08" PRIx32 " wcount=%08" PRIx32 "",
+ bank, buffer, offset, wcount);
+
+ /* flash write code */
+ if (target_alloc_working_area(target, sizeof(write_code), &write_algorithm) != ERROR_OK) {
+ LOG_DEBUG("no working area for block memory writes");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+
+ /* plus a buffer big enough for this data */
+ if (wcount * 4 < buffer_size)
+ buffer_size = wcount * 4;
+
+ /* memory buffer */
+ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) {
+ buffer_size /= 2;
+
+ if (buffer_size <= buf_min) {
+ target_free_working_area(target, write_algorithm);
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+
+ LOG_DEBUG("retry target_alloc_working_area(%s, size=%u)",
+ target_name(target), (unsigned) buffer_size);
+ }
+
+ target_write_buffer(target, write_algorithm->address, sizeof(write_code),
+ write_code);
+
+ armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
+ armv7m_info.core_mode = ARM_MODE_THREAD;
+ init_reg_param(®_params[0], "r0", 32, PARAM_OUT);
+ init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
+ init_reg_param(®_params[2], "r2", 32, PARAM_OUT);
+ init_reg_param(®_params[3], "r3", 32, PARAM_OUT);
+ init_reg_param(®_params[4], "r4", 32, PARAM_OUT);
+
+ buf_set_u32(reg_params[0].value, 0, 32, source->address);
+ buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size);
+ buf_set_u32(reg_params[2].value, 0, 32, address);
+ buf_set_u32(reg_params[3].value, 0, 32, wcount);
+ buf_set_u32(reg_params[4].value, 0, 32, info->flc_base);
+ retval = target_run_flash_async_algorithm(target, buffer, wcount, 4, 0, NULL,
+ 5, reg_params, source->address, source->size, write_algorithm->address, 0, &armv7m_info);
+
+ if (retval == ERROR_FLASH_OPERATION_FAILED)
+ LOG_ERROR("error %d executing max32xxx flash write algorithm", retval);
+
+ target_free_working_area(target, write_algorithm);
+ target_free_working_area(target, source);
+ destroy_reg_param(®_params[0]);
+ destroy_reg_param(®_params[1]);
+ destroy_reg_param(®_params[2]);
+ destroy_reg_param(®_params[3]);
+ destroy_reg_param(®_params[4]);
+ return retval;
+}
+
+static int max32xxx_write(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t offset, uint32_t count)
+{
+ struct max32xxx_flash_bank *info = bank->driver_priv;
+ struct target *target = bank->target;
+ uint32_t flsh_cn, flsh_int;
+ uint32_t address = offset;
+ uint32_t remaining = count;
+ uint32_t words_remaining;
+ int retval;
+ int retry;
+
+ if (bank->target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ LOG_DEBUG("bank=%p buffer=%p offset=%08" PRIx32 " count=%08" PRIx32 "",
+ bank, buffer, offset, count);
+
+ if (info->probed == 0)
+ return ERROR_FLASH_BANK_NOT_PROBED;
+
+ if (offset & 0x3) {
+ LOG_WARNING("offset size must be word aligned");
+ return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
+ }
+
+ if (offset + count > bank->size)
+ return ERROR_FLASH_DST_OUT_OF_BANK;
+
+ /* Prepare to issue flash operation */
+ retval = max32xxx_flash_op_pre(bank);
+
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (remaining >= 4) {
+ /* write in 32-bit units */
+ target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn);
+ flsh_cn &= 0xF7FFFFFF;
+ flsh_cn |= 0x00000010;
+ target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn);
+
+ /* try using a block write */
+ words_remaining = remaining / 4;
+ retval = max32xxx_write_block(bank, buffer, offset, words_remaining);
+
+ if (retval != ERROR_OK) {
+ if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
+ LOG_DEBUG("writing flash word-at-a-time");
+ else {
+ max32xxx_flash_op_post(bank);
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+ } else {
+ /* all 32-bit words have been written */
+ buffer += words_remaining * 4;
+ address += words_remaining * 4;
+ remaining -= words_remaining * 4;
+ }
+ }
+
+ if ((remaining >= 4) && ((address & 0x1F) != 0)) {
+ /* write in 32-bit units until we are 128-bit aligned */
+ target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn);
+ flsh_cn &= 0xF7FFFFFF;
+ flsh_cn |= 0x00000010;
+ target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn);
+
+ while ((remaining >= 4) && ((address & 0x1F) != 0)) {
+ target_write_u32(target, info->flc_base + FLSH_ADDR, address);
+ target_write_buffer(target, info->flc_base + FLSH_DATA0, 4, buffer);
+ flsh_cn |= 0x00000001;
+ target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn);
+ /* Wait until flash operation is complete */
+ retry = 10;
+
+ do {
+ target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn);
+ } while ((--retry > 0) && (flsh_cn & FLSH_CN_PEND));
+
+ if (retry <= 0) {
+ LOG_ERROR("Timed out waiting for flash write @ 0x%08x", address);
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ buffer += 4;
+ address += 4;
+ remaining -= 4;
+ }
+ }
+
+ if ((info->burst_size_bits == 128) && (remaining >= 16)) {
+ /* write in 128-bit bursts while we can */
+ target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn);
+
+ flsh_cn &= 0xFFFFFFEF;
+ flsh_cn |= 0x08000000;
+ target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn);
+ target_write_u32(target, info->flc_base + FLSH_ADDR, address);
+
+ while (remaining >= 16) {
+ if ((address & 0xFFF) == 0)
+ LOG_DEBUG("Writing @ 0x%08x", address);
+
+ target_write_buffer(target, info->flc_base + FLSH_DATA0, 16, buffer);
+ flsh_cn |= 0x00000001;
+ target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn);
+ /* Wait until flash operation is complete */
+ retry = 10;
+
+ do {
+ target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn);
+ } while ((--retry > 0) && (flsh_cn & FLSH_CN_PEND));
+
+ if (retry <= 0) {
+ LOG_ERROR("Timed out waiting for flash write @ 0x%08x", address);
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ buffer += 16;
+ address += 16;
+ remaining -= 16;
+ }
+ }
+
+ if (remaining >= 4) {
+
+ /* write in 32-bit units while we can */
+ target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn);
+ flsh_cn &= 0xF7FFFFFF;
+ flsh_cn |= 0x00000010;
+ target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn);
+
+ while (remaining >= 4) {
+ target_write_u32(target, info->flc_base + FLSH_ADDR, address);
+ target_write_buffer(target, info->flc_base + FLSH_DATA0, 4, buffer);
+ flsh_cn |= 0x00000001;
+ target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn);
+ /* Wait until flash operation is complete */
+ retry = 10;
+
+ do {
+ target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn);
+ } while ((--retry > 0) && (flsh_cn & FLSH_CN_PEND));
+
+ if (retry <= 0) {
+ LOG_ERROR("Timed out waiting for flash write @ 0x%08x", address);
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ buffer += 4;
+ address += 4;
+ remaining -= 4;
+ }
+ }
+
+ if (remaining > 0) {
+ /* write remaining bytes in a 32-bit unit */
+ target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn);
+ flsh_cn &= 0xF7FFFFFF;
+ flsh_cn |= 0x00000010;
+ target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn);
+
+ uint8_t last_word[4] = {0xff, 0xff, 0xff, 0xff};
+ int i = 0;
+
+ while (remaining > 0) {
+ last_word[i++] = *buffer;
+ buffer++;
+ remaining--;
+ }
+
+ target_write_u32(target, info->flc_base + FLSH_ADDR, address);
+ target_write_buffer(target, info->flc_base + FLSH_DATA0, 4, last_word);
+ flsh_cn |= 0x00000001;
+ target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn);
+ /* Wait until flash operation is complete */
+ retry = 10;
+
+ do {
+ target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn);
+ } while ((--retry > 0) && (flsh_cn & FLSH_CN_PEND));
+
+ if (retry <= 0) {
+ LOG_ERROR("Timed out waiting for flash write @ 0x%08x", address);
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+ }
+
+ /* Check access violations */
+ target_read_u32(target, info->flc_base + FLSH_INT, &flsh_int);
+ if (flsh_int & FLSH_INT_AF) {
+ LOG_ERROR("Flash Error writing 0x%x bytes at 0x%08x", count, offset);
+ max32xxx_flash_op_post(bank);
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ if (max32xxx_flash_op_post(bank) != ERROR_OK)
+ return ERROR_FAIL;
+
+ return ERROR_OK;
+}
+
+static int max32xxx_probe(struct flash_bank *bank)
+{
+ struct max32xxx_flash_bank *info = bank->driver_priv;
+ struct target *target = bank->target;
+ uint32_t arm_id[2];
+ uint16_t arm_pid;
+
+ if (bank->sectors) {
+ free(bank->sectors);
+ bank->sectors = NULL;
+ }
+
+ /* provide this for the benefit of the NOR flash framework */
+ bank->size = info->flash_size;
+ bank->num_sectors = info->flash_size / info->sector_size;
+ bank->sectors = calloc(bank->num_sectors, sizeof(struct flash_sector));
+
+ for (int i = 0; i < bank->num_sectors; i++) {
+ bank->sectors[i].offset = i * info->sector_size;
+ bank->sectors[i].size = info->sector_size;
+ bank->sectors[i].is_erased = -1;
+ bank->sectors[i].is_protected = -1;
+ }
+
+ /* Probe to determine if this part is in the max326xx family */
+ info->max326xx = 0;
+ target_read_u32(target, ARM_PID_REG, &arm_id[0]);
+ target_read_u32(target, ARM_PID_REG+4, &arm_id[1]);
+ arm_pid = (arm_id[1] << 8) + arm_id[0];
+ LOG_DEBUG("arm_pid = 0x%x", arm_pid);
+
+ if ((arm_pid == ARM_PID_DEFAULT_CM3) || arm_pid == ARM_PID_DEFAULT_CM4) {
+ uint32_t max326xx_id;
+ target_read_u32(target, MAX326XX_ID_REG, &max326xx_id);
+ LOG_DEBUG("max326xx_id = 0x%x", max326xx_id);
+ max326xx_id = ((max326xx_id & 0xFF000000) >> 24);
+ if (max326xx_id == MAX326XX_ID)
+ info->max326xx = 1;
+ }
+ LOG_DEBUG("info->max326xx = %d", info->max326xx);
+
+ /* Initialize the protection bits for each flash page */
+ if (max32xxx_protect_check(bank) == ERROR_FLASH_OPER_UNSUPPORTED)
+ LOG_WARNING("Flash protection not supported on this device");
+
+ info->probed = 1;
+ return ERROR_OK;
+}
+
+static int max32xxx_mass_erase(struct flash_bank *bank)
+{
+ struct target *target = NULL;
+ struct max32xxx_flash_bank *info = NULL;
+ uint32_t flsh_cn, flsh_int;
+ int retval;
+ int retry;
+ info = bank->driver_priv;
+ target = bank->target;
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (info->probed == 0)
+ return ERROR_FLASH_BANK_NOT_PROBED;
+
+ int not_protected = 0;
+ for (int i = 0; i < bank->num_sectors; i++) {
+ if (bank->sectors[i].is_protected == 1)
+ LOG_WARNING("Flash sector %d is protected", i);
+ else
+ not_protected = 1;
+ }
+
+ if (!not_protected) {
+ LOG_ERROR("All pages protected");
+ return ERROR_FAIL;
+ }
+
+ /* Prepare to issue flash operation */
+ retval = max32xxx_flash_op_pre(bank);
+
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* Write mass erase code */
+ target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn);
+ flsh_cn |= FLSH_CN_ERASE_CODE_ME;
+ target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn);
+
+ /* Issue mass erase command */
+ flsh_cn |= 0x2;
+ target_write_u32(target, info->flc_base + FLSH_CN, flsh_cn);
+
+ /* Wait until erase complete */
+ retry = 1000;
+ do {
+ target_read_u32(target, info->flc_base + FLSH_CN, &flsh_cn);
+ } while ((--retry > 0) && (flsh_cn & FLSH_CN_PEND));
+
+ if (retry <= 0) {
+ LOG_ERROR("Timed out waiting for flash mass erase");
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ /* Check access violations */
+ target_read_u32(target, info->flc_base + FLSH_INT, &flsh_int);
+ if (flsh_int & FLSH_INT_AF) {
+ LOG_ERROR("Error mass erasing");
+ target_write_u32(target, info->flc_base + FLSH_INT, 0);
+ return ERROR_FLASH_OPERATION_FAILED;
+ }
+
+ if (max32xxx_flash_op_post(bank) != ERROR_OK)
+ return ERROR_FAIL;
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(max32xxx_handle_mass_erase_command)
+{
+ int i;
+ struct flash_bank *bank;
+ int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+
+ if (CMD_ARGC < 1) {
+ command_print(CMD_CTX, "max32xxx mass_erase ");
+ return ERROR_OK;
+ }
+
+ if (ERROR_OK != retval)
+ return retval;
+
+ if (max32xxx_mass_erase(bank) == ERROR_OK) {
+ /* set all sectors as erased */
+ for (i = 0; i < bank->num_sectors; i++)
+ bank->sectors[i].is_erased = 1;
+
+ command_print(CMD_CTX, "max32xxx mass erase complete");
+ } else
+ command_print(CMD_CTX, "max32xxx mass erase failed");
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(max32xxx_handle_protection_set_command)
+{
+ struct flash_bank *bank;
+ int retval;
+ struct max32xxx_flash_bank *info;
+ uint32_t addr, len;
+
+ if (CMD_ARGC != 3) {
+ command_print(CMD_CTX, "max32xxx protection_set ");
+ return ERROR_OK;
+ }
+
+ retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (ERROR_OK != retval)
+ return retval;
+ info = bank->driver_priv;
+
+ /* Convert the range to the page numbers */
+ if (1 != sscanf(CMD_ARGV[1], "0x%"SCNx32, &addr)) {
+ LOG_WARNING("Error parsing address");
+ command_print(CMD_CTX, "max32xxx protection_set ");
+ return ERROR_FAIL;
+ }
+ /* Mask off the top portion on the address */
+ addr = (addr & 0x0FFFFFFF);
+
+ if (1 != sscanf(CMD_ARGV[2], "0x%"SCNx32, &len)) {
+ LOG_WARNING("Error parsing length");
+ command_print(CMD_CTX, "max32xxx protection_set ");
+ return ERROR_FAIL;
+ }
+
+ /* Check the address is in the range of the flash */
+ if ((addr+len) >= info->flash_size)
+ return ERROR_FLASH_SECTOR_INVALID;
+
+ if (len == 0)
+ return ERROR_OK;
+
+ /* Convert the address and length to the page boundaries */
+ addr = addr - (addr % info->sector_size);
+ if (len % info->sector_size)
+ len = len + info->sector_size - (len % info->sector_size);
+
+ /* Convert the address and length to page numbers */
+ addr = (addr / info->sector_size);
+ len = addr + (len / info->sector_size) - 1;
+
+ if (max32xxx_protect(bank, 1, addr, len) == ERROR_OK)
+ command_print(CMD_CTX, "max32xxx protection set complete");
+ else
+ command_print(CMD_CTX, "max32xxx protection set failed");
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(max32xxx_handle_protection_clr_command)
+{
+ struct flash_bank *bank;
+ int retval;
+ struct max32xxx_flash_bank *info;
+ uint32_t addr, len;
+
+ if (CMD_ARGC != 3) {
+ command_print(CMD_CTX, "max32xxx protection_clr ");
+ return ERROR_OK;
+ }
+
+ retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (ERROR_OK != retval)
+ return retval;
+ info = bank->driver_priv;
+
+ /* Convert the range to the page numbers */
+ if (1 != sscanf(CMD_ARGV[1], "0x%"SCNx32, &addr)) {
+ LOG_WARNING("Error parsing address");
+ command_print(CMD_CTX, "max32xxx protection_clr ");
+ return ERROR_FAIL;
+ }
+ /* Mask off the top portion on the address */
+ addr = (addr & 0x0FFFFFFF);
+
+ if (1 != sscanf(CMD_ARGV[2], "0x%"SCNx32, &len)) {
+ LOG_WARNING("Error parsing length");
+ command_print(CMD_CTX, "max32xxx protection_clr ");
+ return ERROR_FAIL;
+ }
+
+ /* Check the address is in the range of the flash */
+ if ((addr+len) >= info->flash_size)
+ return ERROR_FLASH_SECTOR_INVALID;
+
+ if (len == 0)
+ return ERROR_OK;
+
+ /* Convert the address and length to the page boundaries */
+ addr = addr - (addr % info->sector_size);
+ if (len % info->sector_size)
+ len = len + info->sector_size - (len % info->sector_size);
+
+ /* Convert the address and length to page numbers */
+ addr = (addr / info->sector_size);
+ len = addr + (len / info->sector_size) - 1;
+
+ if (max32xxx_protect(bank, 0, addr, len) == ERROR_OK)
+ command_print(CMD_CTX, "max32xxx protection clear complete");
+ else
+ command_print(CMD_CTX, "max32xxx protection clear failed");
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(max32xxx_handle_protection_check_command)
+{
+ struct flash_bank *bank;
+ int retval;
+ struct max32xxx_flash_bank *info;
+ int i;
+
+ if (CMD_ARGC < 1) {
+ command_print(CMD_CTX, "max32xxx protection_check ");
+ return ERROR_OK;
+ }
+
+ retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (ERROR_OK != retval)
+ return retval;
+ info = bank->driver_priv;
+
+ /* Update the protection array */
+ retval = max32xxx_protect_check(bank);
+ if (ERROR_OK != retval) {
+ LOG_WARNING("Error updating the protection array");
+ return retval;
+ }
+
+ LOG_WARNING("s: a: p:");
+ for (i = 0; i < bank->num_sectors; i += 4) {
+ LOG_WARNING("s:%03d a:0x%06x p:%d | s:%03d a:0x%06x p:%d | s:%03d a:0x%06x p:%d | s:%03d a:0x%06x p:%d",
+ (i+0), (i+0)*info->sector_size, bank->sectors[(i+0)].is_protected,
+ (i+1), (i+1)*info->sector_size, bank->sectors[(i+1)].is_protected,
+ (i+2), (i+2)*info->sector_size, bank->sectors[(i+2)].is_protected,
+ (i+3), (i+3)*info->sector_size, bank->sectors[(i+3)].is_protected);
+ }
+
+ return ERROR_OK;
+}
+
+static const struct command_registration max32xxx_exec_command_handlers[] = {
+ {
+ .name = "mass_erase",
+ .handler = max32xxx_handle_mass_erase_command,
+ .mode = COMMAND_EXEC,
+ .usage = "bank_id",
+ .help = "mass erase flash",
+ },
+ {
+ .name = "protection_set",
+ .handler = max32xxx_handle_protection_set_command,
+ .mode = COMMAND_EXEC,
+ .usage = "bank_id addr size",
+ .help = "set flash protection for address range",
+ },
+ {
+ .name = "protection_clr",
+ .handler = max32xxx_handle_protection_clr_command,
+ .mode = COMMAND_EXEC,
+ .usage = "bank_id addr size",
+ .help = "clear flash protection for address range",
+ },
+ {
+ .name = "protection_check",
+ .handler = max32xxx_handle_protection_check_command,
+ .mode = COMMAND_EXEC,
+ .usage = "bank_id",
+ .help = "check flash protection",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration max32xxx_command_handlers[] = {
+ {
+ .name = "max32xxx",
+ .mode = COMMAND_EXEC,
+ .help = "max32xxx flash command group",
+ .chain = max32xxx_exec_command_handlers,
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+struct flash_driver max32xxx_flash = {
+ .name = "max32xxx",
+ .commands = max32xxx_command_handlers,
+ .flash_bank_command = max32xxx_flash_bank_command,
+ .erase = max32xxx_erase,
+ .protect = max32xxx_protect,
+ .write = max32xxx_write,
+ .read = default_flash_read,
+ .probe = max32xxx_probe,
+ .auto_probe = max32xxx_probe,
+ .erase_check = default_flash_blank_check,
+ .protect_check = max32xxx_protect_check,
+ .info = get_info,
+};
diff --git a/src/flash/nor/nrf5.c b/src/flash/nor/nrf5.c
index 16459c7f8..de5c23051 100644
--- a/src/flash/nor/nrf5.c
+++ b/src/flash/nor/nrf5.c
@@ -26,6 +26,7 @@
#include
#include
#include
+#include
enum {
NRF5_FLASH_BASE = 0x00000000,
@@ -203,9 +204,16 @@ static const struct nrf5_device_spec nrf5_known_devices_table[] = {
NRF5_DEVICE_DEF(0x007A, "51422", "CEAA", "C0", 256),
NRF5_DEVICE_DEF(0x0088, "51422", "CFAC", "A0", 256),
+ /* nRF52810 Devices */
+ NRF5_DEVICE_DEF(0x0142, "52810", "QFAA", "B0", 192),
+ NRF5_DEVICE_DEF(0x0143, "52810", "QCAA", "C0", 192),
+
/* nRF52832 Devices */
NRF5_DEVICE_DEF(0x00C7, "52832", "QFAA", "B0", 512),
NRF5_DEVICE_DEF(0x0139, "52832", "QFAA", "E0", 512),
+
+ /* nRF52840 Devices */
+ NRF5_DEVICE_DEF(0x0150, "52840", "QIAA", "C0", 1024),
};
static int nrf5_bank_is_probed(struct flash_bank *bank)
@@ -240,7 +248,8 @@ static int nrf5_wait_for_nvmc(struct nrf5_info *chip)
{
uint32_t ready;
int res;
- int timeout = 100;
+ int timeout_ms = 200;
+ int64_t ts_start = timeval_ms();
do {
res = target_read_u32(chip->target, NRF5_NVMC_READY, &ready);
@@ -252,8 +261,9 @@ static int nrf5_wait_for_nvmc(struct nrf5_info *chip)
if (ready == 0x00000001)
return ERROR_OK;
- alive_sleep(1);
- } while (timeout--);
+ keep_alive();
+
+ } while ((timeval_ms()-ts_start) < timeout_ms);
LOG_DEBUG("Timed out waiting for NVMC_READY");
return ERROR_FLASH_BUSY;
diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c
index faada9a61..fbd759828 100644
--- a/src/flash/nor/stm32f1x.c
+++ b/src/flash/nor/stm32f1x.c
@@ -70,14 +70,15 @@
/* FLASH_CR register bits */
-#define FLASH_PG (1 << 0)
-#define FLASH_PER (1 << 1)
-#define FLASH_MER (1 << 2)
-#define FLASH_OPTPG (1 << 4)
-#define FLASH_OPTER (1 << 5)
-#define FLASH_STRT (1 << 6)
-#define FLASH_LOCK (1 << 7)
-#define FLASH_OPTWRE (1 << 9)
+#define FLASH_PG (1 << 0)
+#define FLASH_PER (1 << 1)
+#define FLASH_MER (1 << 2)
+#define FLASH_OPTPG (1 << 4)
+#define FLASH_OPTER (1 << 5)
+#define FLASH_STRT (1 << 6)
+#define FLASH_LOCK (1 << 7)
+#define FLASH_OPTWRE (1 << 9)
+#define FLASH_OBL_LAUNCH (1 << 13) /* except stm32f1x series */
/* FLASH_SR register bits */
@@ -106,10 +107,10 @@
#define FLASH_ERASE_TIMEOUT 100
struct stm32x_options {
- uint16_t RDP;
- uint16_t user_options;
- uint16_t user_data;
- uint16_t protection[4];
+ uint8_t rdp;
+ uint8_t user;
+ uint16_t data;
+ uint32_t protection;
};
struct stm32x_flash_bank {
@@ -119,8 +120,9 @@ struct stm32x_flash_bank {
bool has_dual_banks;
/* used to access dual flash bank stm32xl */
+ bool can_load_options;
uint32_t register_base;
- uint16_t default_rdp;
+ uint8_t default_rdp;
int user_data_offset;
int option_offset;
uint32_t user_bank_size;
@@ -145,6 +147,7 @@ FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command)
bank->driver_priv = stm32x_info;
stm32x_info->probed = 0;
stm32x_info->has_dual_banks = false;
+ stm32x_info->can_load_options = false;
stm32x_info->register_base = FLASH_REG_BASE_B0;
stm32x_info->user_bank_size = bank->size;
@@ -221,44 +224,47 @@ static int stm32x_check_operation_supported(struct flash_bank *bank)
static int stm32x_read_options(struct flash_bank *bank)
{
- uint32_t optiondata;
- struct stm32x_flash_bank *stm32x_info = NULL;
+ struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
struct target *target = bank->target;
+ uint32_t option_bytes;
+ int retval;
- stm32x_info = bank->driver_priv;
-
- /* read current option bytes */
- int retval = target_read_u32(target, STM32_FLASH_OBR_B0, &optiondata);
+ /* read user and read protection option bytes */
+ retval = target_read_u32(target, STM32_OB_RDP, &option_bytes);
if (retval != ERROR_OK)
return retval;
- stm32x_info->option_bytes.user_options = (optiondata >> stm32x_info->option_offset >> 2) & 0xffff;
- stm32x_info->option_bytes.user_data = (optiondata >> stm32x_info->user_data_offset) & 0xffff;
- stm32x_info->option_bytes.RDP = (optiondata & (1 << OPT_READOUT)) ? 0xFFFF : 0x5AA5;
+ stm32x_info->option_bytes.rdp = option_bytes & 0xFF;
+ stm32x_info->option_bytes.user = (option_bytes >> 16) & 0xFF;
- if (optiondata & (1 << OPT_READOUT))
- LOG_INFO("Device Security Bit Set");
-
- /* each bit refers to a 4bank protection */
- retval = target_read_u32(target, STM32_FLASH_WRPR_B0, &optiondata);
+ /* read user data option bytes */
+ retval = target_read_u32(target, STM32_OB_DATA0, &option_bytes);
if (retval != ERROR_OK)
return retval;
- stm32x_info->option_bytes.protection[0] = (uint16_t)optiondata;
- stm32x_info->option_bytes.protection[1] = (uint16_t)(optiondata >> 8);
- stm32x_info->option_bytes.protection[2] = (uint16_t)(optiondata >> 16);
- stm32x_info->option_bytes.protection[3] = (uint16_t)(optiondata >> 24);
+ stm32x_info->option_bytes.data = ((option_bytes >> 8) & 0xFF00) | (option_bytes & 0xFF);
+
+ /* read write protection option bytes */
+ retval = target_read_u32(target, STM32_OB_WRP0, &option_bytes);
+ if (retval != ERROR_OK)
+ return retval;
+
+ stm32x_info->option_bytes.protection = ((option_bytes >> 8) & 0xFF00) | (option_bytes & 0xFF);
+
+ retval = target_read_u32(target, STM32_OB_WRP2, &option_bytes);
+ if (retval != ERROR_OK)
+ return retval;
+
+ stm32x_info->option_bytes.protection |= (((option_bytes >> 8) & 0xFF00) | (option_bytes & 0xFF)) << 16;
return ERROR_OK;
}
static int stm32x_erase_options(struct flash_bank *bank)
{
- struct stm32x_flash_bank *stm32x_info = NULL;
+ struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
struct target *target = bank->target;
- stm32x_info = bank->driver_priv;
-
/* read current options */
stm32x_read_options(bank);
@@ -291,9 +297,9 @@ static int stm32x_erase_options(struct flash_bank *bank)
if (retval != ERROR_OK)
return retval;
- /* clear readout protection and complementary option bytes
+ /* clear read protection option byte
* this will also force a device unlock if set */
- stm32x_info->option_bytes.RDP = stm32x_info->default_rdp;
+ stm32x_info->option_bytes.rdp = stm32x_info->default_rdp;
return ERROR_OK;
}
@@ -328,14 +334,14 @@ static int stm32x_write_options(struct flash_bank *bank)
uint8_t opt_bytes[16];
- target_buffer_set_u16(target, opt_bytes, stm32x_info->option_bytes.RDP);
- target_buffer_set_u16(target, opt_bytes + 2, stm32x_info->option_bytes.user_options);
- target_buffer_set_u16(target, opt_bytes + 4, stm32x_info->option_bytes.user_data & 0xff);
- target_buffer_set_u16(target, opt_bytes + 6, (stm32x_info->option_bytes.user_data >> 8) & 0xff);
- target_buffer_set_u16(target, opt_bytes + 8, stm32x_info->option_bytes.protection[0]);
- target_buffer_set_u16(target, opt_bytes + 10, stm32x_info->option_bytes.protection[1]);
- target_buffer_set_u16(target, opt_bytes + 12, stm32x_info->option_bytes.protection[2]);
- target_buffer_set_u16(target, opt_bytes + 14, stm32x_info->option_bytes.protection[3]);
+ target_buffer_set_u16(target, opt_bytes, stm32x_info->option_bytes.rdp);
+ target_buffer_set_u16(target, opt_bytes + 2, stm32x_info->option_bytes.user);
+ target_buffer_set_u16(target, opt_bytes + 4, stm32x_info->option_bytes.data & 0xff);
+ target_buffer_set_u16(target, opt_bytes + 6, (stm32x_info->option_bytes.data >> 8) & 0xff);
+ target_buffer_set_u16(target, opt_bytes + 8, stm32x_info->option_bytes.protection & 0xff);
+ target_buffer_set_u16(target, opt_bytes + 10, (stm32x_info->option_bytes.protection >> 8) & 0xff);
+ target_buffer_set_u16(target, opt_bytes + 12, (stm32x_info->option_bytes.protection >> 16) & 0xff);
+ target_buffer_set_u16(target, opt_bytes + 14, (stm32x_info->option_bytes.protection >> 24) & 0xff);
uint32_t offset = STM32_OB_RDP - bank->base;
retval = stm32x_write_block(bank, opt_bytes, offset, sizeof(opt_bytes) / 2);
@@ -355,64 +361,21 @@ static int stm32x_write_options(struct flash_bank *bank)
static int stm32x_protect_check(struct flash_bank *bank)
{
struct target *target = bank->target;
- struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
-
uint32_t protection;
- int i, s;
- int num_bits;
- int set;
int retval = stm32x_check_operation_supported(bank);
if (ERROR_OK != retval)
return retval;
- /* medium density - each bit refers to a 4bank protection
- * high density - each bit refers to a 2bank protection */
+ /* medium density - each bit refers to a 4 sector protection block
+ * high density - each bit refers to a 2 sector protection block
+ * bit 31 refers to all remaining sectors in a bank */
retval = target_read_u32(target, STM32_FLASH_WRPR_B0, &protection);
if (retval != ERROR_OK)
return retval;
- /* medium density - each protection bit is for 4 * 1K pages
- * high density - each protection bit is for 2 * 2K pages */
- num_bits = (bank->num_sectors / stm32x_info->ppage_size);
-
- if (stm32x_info->ppage_size == 2) {
- /* high density flash/connectivity line protection */
-
- set = 1;
-
- if (protection & (1 << 31))
- set = 0;
-
- /* bit 31 controls sector 62 - 255 protection for high density
- * bit 31 controls sector 62 - 127 protection for connectivity line */
- for (s = 62; s < bank->num_sectors; s++)
- bank->sectors[s].is_protected = set;
-
- if (bank->num_sectors > 61)
- num_bits = 31;
-
- for (i = 0; i < num_bits; i++) {
- set = 1;
-
- if (protection & (1 << i))
- set = 0;
-
- for (s = 0; s < stm32x_info->ppage_size; s++)
- bank->sectors[(i * stm32x_info->ppage_size) + s].is_protected = set;
- }
- } else {
- /* low/medium density flash protection */
- for (i = 0; i < num_bits; i++) {
- set = 1;
-
- if (protection & (1 << i))
- set = 0;
-
- for (s = 0; s < stm32x_info->ppage_size; s++)
- bank->sectors[(i * stm32x_info->ppage_size) + s].is_protected = set;
- }
- }
+ for (int i = 0; i < bank->num_prot_blocks; i++)
+ bank->prot_blocks[i].is_protected = (protection & (1 << i)) ? 0 : 1;
return ERROR_OK;
}
@@ -467,14 +430,8 @@ static int stm32x_erase(struct flash_bank *bank, int first, int last)
static int stm32x_protect(struct flash_bank *bank, int set, int first, int last)
{
- struct stm32x_flash_bank *stm32x_info = NULL;
struct target *target = bank->target;
- uint16_t prot_reg[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
- int i, reg, bit;
- int status;
- uint32_t protection;
-
- stm32x_info = bank->driver_priv;
+ struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
if (target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
@@ -482,80 +439,20 @@ static int stm32x_protect(struct flash_bank *bank, int set, int first, int last)
}
int retval = stm32x_check_operation_supported(bank);
- if (ERROR_OK != retval)
- return retval;
-
- if ((first % stm32x_info->ppage_size) != 0) {
- LOG_WARNING("aligned start protect sector to a %d sector boundary",
- stm32x_info->ppage_size);
- first = first - (first % stm32x_info->ppage_size);
- }
- if (((last + 1) % stm32x_info->ppage_size) != 0) {
- LOG_WARNING("aligned end protect sector to a %d sector boundary",
- stm32x_info->ppage_size);
- last++;
- last = last - (last % stm32x_info->ppage_size);
- last--;
- }
-
- /* medium density - each bit refers to a 4bank protection
- * high density - each bit refers to a 2bank protection */
- retval = target_read_u32(target, STM32_FLASH_WRPR_B0, &protection);
if (retval != ERROR_OK)
return retval;
- prot_reg[0] = (uint16_t)protection;
- prot_reg[1] = (uint16_t)(protection >> 8);
- prot_reg[2] = (uint16_t)(protection >> 16);
- prot_reg[3] = (uint16_t)(protection >> 24);
+ retval = stm32x_erase_options(bank);
+ if (retval != ERROR_OK)
+ return retval;
- if (stm32x_info->ppage_size == 2) {
- /* high density flash */
-
- /* bit 7 controls sector 62 - 255 protection */
- if (last > 61) {
- if (set)
- prot_reg[3] &= ~(1 << 7);
- else
- prot_reg[3] |= (1 << 7);
- }
-
- if (first > 61)
- first = 62;
- if (last > 61)
- last = 61;
-
- for (i = first; i <= last; i++) {
- reg = (i / stm32x_info->ppage_size) / 8;
- bit = (i / stm32x_info->ppage_size) - (reg * 8);
-
- if (set)
- prot_reg[reg] &= ~(1 << bit);
- else
- prot_reg[reg] |= (1 << bit);
- }
- } else {
- /* medium density flash */
- for (i = first; i <= last; i++) {
- reg = (i / stm32x_info->ppage_size) / 8;
- bit = (i / stm32x_info->ppage_size) - (reg * 8);
-
- if (set)
- prot_reg[reg] &= ~(1 << bit);
- else
- prot_reg[reg] |= (1 << bit);
- }
+ for (int i = first; i <= last; i++) {
+ if (set)
+ stm32x_info->option_bytes.protection &= ~(1 << i);
+ else
+ stm32x_info->option_bytes.protection |= (1 << i);
}
- status = stm32x_erase_options(bank);
- if (status != ERROR_OK)
- return status;
-
- stm32x_info->option_bytes.protection[0] = prot_reg[0];
- stm32x_info->option_bytes.protection[1] = prot_reg[1];
- stm32x_info->option_bytes.protection[2] = prot_reg[2];
- stm32x_info->option_bytes.protection[3] = prot_reg[3];
-
return stm32x_write_options(bank);
}
@@ -808,7 +705,6 @@ static int stm32x_get_flash_size(struct flash_bank *bank, uint16_t *flash_size_i
static int stm32x_probe(struct flash_bank *bank)
{
struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
- int i;
uint16_t flash_size_in_kb;
uint16_t max_flash_size_in_kb;
uint32_t device_id;
@@ -820,8 +716,8 @@ static int stm32x_probe(struct flash_bank *bank)
stm32x_info->user_data_offset = 10;
stm32x_info->option_offset = 0;
- /* default factory protection level */
- stm32x_info->default_rdp = 0x5AA5;
+ /* default factory read protection level 0 */
+ stm32x_info->default_rdp = 0xA5;
/* read stm32 device id register */
int retval = stm32x_get_device_id(bank, &device_id);
@@ -863,7 +759,8 @@ static int stm32x_probe(struct flash_bank *bank)
max_flash_size_in_kb = 256;
stm32x_info->user_data_offset = 16;
stm32x_info->option_offset = 6;
- stm32x_info->default_rdp = 0x55AA;
+ stm32x_info->default_rdp = 0xAA;
+ stm32x_info->can_load_options = true;
break;
case 0x446: /* stm32f303xD/E */
page_size = 2048;
@@ -871,7 +768,8 @@ static int stm32x_probe(struct flash_bank *bank)
max_flash_size_in_kb = 512;
stm32x_info->user_data_offset = 16;
stm32x_info->option_offset = 6;
- stm32x_info->default_rdp = 0x55AA;
+ stm32x_info->default_rdp = 0xAA;
+ stm32x_info->can_load_options = true;
break;
case 0x428: /* value line High density */
page_size = 2048;
@@ -890,7 +788,8 @@ static int stm32x_probe(struct flash_bank *bank)
max_flash_size_in_kb = 256;
stm32x_info->user_data_offset = 16;
stm32x_info->option_offset = 6;
- stm32x_info->default_rdp = 0x55AA;
+ stm32x_info->default_rdp = 0xAA;
+ stm32x_info->can_load_options = true;
break;
case 0x438: /* stm32f33x */
case 0x439: /* stm32f302x6/8 */
@@ -899,7 +798,8 @@ static int stm32x_probe(struct flash_bank *bank)
max_flash_size_in_kb = 64;
stm32x_info->user_data_offset = 16;
stm32x_info->option_offset = 6;
- stm32x_info->default_rdp = 0x55AA;
+ stm32x_info->default_rdp = 0xAA;
+ stm32x_info->can_load_options = true;
break;
case 0x440: /* stm32f05x */
case 0x444: /* stm32f03x */
@@ -909,7 +809,8 @@ static int stm32x_probe(struct flash_bank *bank)
max_flash_size_in_kb = 64;
stm32x_info->user_data_offset = 16;
stm32x_info->option_offset = 6;
- stm32x_info->default_rdp = 0x55AA;
+ stm32x_info->default_rdp = 0xAA;
+ stm32x_info->can_load_options = true;
break;
case 0x448: /* stm32f07x */
case 0x442: /* stm32f09x */
@@ -918,7 +819,8 @@ static int stm32x_probe(struct flash_bank *bank)
max_flash_size_in_kb = 256;
stm32x_info->user_data_offset = 16;
stm32x_info->option_offset = 6;
- stm32x_info->default_rdp = 0x55AA;
+ stm32x_info->default_rdp = 0xAA;
+ stm32x_info->can_load_options = true;
break;
default:
LOG_WARNING("Cannot identify target as a STM32 family.");
@@ -972,17 +874,31 @@ static int stm32x_probe(struct flash_bank *bank)
bank->sectors = NULL;
}
+ if (bank->prot_blocks) {
+ free(bank->prot_blocks);
+ bank->prot_blocks = NULL;
+ }
+
bank->base = base_address;
bank->size = (num_pages * page_size);
- bank->num_sectors = num_pages;
- bank->sectors = malloc(sizeof(struct flash_sector) * num_pages);
- for (i = 0; i < num_pages; i++) {
- bank->sectors[i].offset = i * page_size;
- bank->sectors[i].size = page_size;
- bank->sectors[i].is_erased = -1;
- bank->sectors[i].is_protected = 1;
- }
+ bank->num_sectors = num_pages;
+ bank->sectors = alloc_block_array(0, page_size, num_pages);
+ if (!bank->sectors)
+ return ERROR_FAIL;
+
+ /* calculate number of write protection blocks */
+ int num_prot_blocks = num_pages / stm32x_info->ppage_size;
+ if (num_prot_blocks > 32)
+ num_prot_blocks = 32;
+
+ bank->num_prot_blocks = num_prot_blocks;
+ bank->prot_blocks = alloc_block_array(0, stm32x_info->ppage_size * page_size, num_prot_blocks);
+ if (!bank->prot_blocks)
+ return ERROR_FAIL;
+
+ if (num_prot_blocks == 32)
+ bank->prot_blocks[31].size = (num_pages - (31 * stm32x_info->ppage_size)) * page_size;
stm32x_info->probed = 1;
@@ -1275,7 +1191,7 @@ COMMAND_HANDLER(stm32x_handle_lock_command)
}
/* set readout protection */
- stm32x_info->option_bytes.RDP = 0;
+ stm32x_info->option_bytes.rdp = 0;
if (stm32x_write_options(bank) != ERROR_OK) {
command_print(CMD_CTX, "stm32x failed to lock device");
@@ -1329,7 +1245,7 @@ COMMAND_HANDLER(stm32x_handle_unlock_command)
COMMAND_HANDLER(stm32x_handle_options_read_command)
{
- uint32_t optionbyte;
+ uint32_t optionbyte, protection;
struct target *target = NULL;
struct stm32x_flash_bank *stm32x_info = NULL;
@@ -1357,47 +1273,38 @@ COMMAND_HANDLER(stm32x_handle_options_read_command)
retval = target_read_u32(target, STM32_FLASH_OBR_B0, &optionbyte);
if (retval != ERROR_OK)
return retval;
- command_print(CMD_CTX, "Option Byte: 0x%" PRIx32 "", optionbyte);
- int user_data = optionbyte;
+ uint16_t user_data = optionbyte >> stm32x_info->user_data_offset;
- if (optionbyte >> OPT_ERROR & 1)
- command_print(CMD_CTX, "Option Byte Complement Error");
+ retval = target_read_u32(target, STM32_FLASH_WRPR_B0, &protection);
+ if (retval != ERROR_OK)
+ return retval;
- if (optionbyte >> OPT_READOUT & 1)
- command_print(CMD_CTX, "Readout Protection On");
- else
- command_print(CMD_CTX, "Readout Protection Off");
+ if (optionbyte & (1 << OPT_ERROR))
+ command_print(CMD_CTX, "option byte complement error");
+
+ command_print(CMD_CTX, "option byte register = 0x%" PRIx32 "", optionbyte);
+ command_print(CMD_CTX, "write protection register = 0x%" PRIx32 "", protection);
+
+ command_print(CMD_CTX, "read protection: %s",
+ (optionbyte & (1 << OPT_READOUT)) ? "on" : "off");
/* user option bytes are offset depending on variant */
optionbyte >>= stm32x_info->option_offset;
- if (optionbyte >> OPT_RDWDGSW & 1)
- command_print(CMD_CTX, "Software Watchdog");
- else
- command_print(CMD_CTX, "Hardware Watchdog");
+ command_print(CMD_CTX, "watchdog: %sware",
+ (optionbyte & (1 << OPT_RDWDGSW)) ? "soft" : "hard");
- if (optionbyte >> OPT_RDRSTSTOP & 1)
- command_print(CMD_CTX, "Stop: No reset generated");
- else
- command_print(CMD_CTX, "Stop: Reset generated");
+ command_print(CMD_CTX, "stop mode: %sreset generated upon entry",
+ (optionbyte & (1 << OPT_RDRSTSTOP)) ? "no " : "");
- if (optionbyte >> OPT_RDRSTSTDBY & 1)
- command_print(CMD_CTX, "Standby: No reset generated");
- else
- command_print(CMD_CTX, "Standby: Reset generated");
+ command_print(CMD_CTX, "standby mode: %sreset generated upon entry",
+ (optionbyte & (1 << OPT_RDRSTSTDBY)) ? "no " : "");
- if (stm32x_info->has_dual_banks) {
- if (optionbyte >> OPT_BFB2 & 1)
- command_print(CMD_CTX, "Boot: Bank 0");
- else
- command_print(CMD_CTX, "Boot: Bank 1");
- }
+ if (stm32x_info->has_dual_banks)
+ command_print(CMD_CTX, "boot: bank %d", (optionbyte & (1 << OPT_BFB2)) ? 0 : 1);
- command_print(CMD_CTX, "User Option0: 0x%02" PRIx8,
- (uint8_t)((user_data >> stm32x_info->user_data_offset) & 0xff));
- command_print(CMD_CTX, "User Option1: 0x%02" PRIx8,
- (uint8_t)((user_data >> (stm32x_info->user_data_offset + 8)) & 0xff));
+ command_print(CMD_CTX, "user data = 0x%02" PRIx16 "", user_data);
return ERROR_OK;
}
@@ -1434,7 +1341,7 @@ COMMAND_HANDLER(stm32x_handle_options_write_command)
return retval;
/* start with current options */
- optionbyte = stm32x_info->option_bytes.user_options;
+ optionbyte = stm32x_info->option_bytes.user;
/* skip over flash bank */
CMD_ARGC--;
@@ -1471,7 +1378,7 @@ COMMAND_HANDLER(stm32x_handle_options_write_command)
return ERROR_OK;
}
- stm32x_info->option_bytes.user_options = optionbyte;
+ stm32x_info->option_bytes.user = optionbyte;
if (stm32x_write_options(bank) != ERROR_OK) {
command_print(CMD_CTX, "stm32x failed to write options");
@@ -1479,8 +1386,55 @@ COMMAND_HANDLER(stm32x_handle_options_write_command)
}
command_print(CMD_CTX, "stm32x write options complete.\n"
- "INFO: a reset or power cycle is required "
- "for the new settings to take effect.");
+ "INFO: %spower cycle is required "
+ "for the new settings to take effect.",
+ stm32x_info->can_load_options
+ ? "'stm32f1x options_load' command or " : "");
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(stm32x_handle_options_load_command)
+{
+ if (CMD_ARGC < 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ struct flash_bank *bank;
+ int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
+
+ if (!stm32x_info->can_load_options) {
+ LOG_ERROR("Command not applicable to stm32f1x devices - power cycle is "
+ "required instead.");
+ return ERROR_FAIL;
+ }
+
+ struct target *target = bank->target;
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ retval = stm32x_check_operation_supported(bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ /* unlock option flash registers */
+ retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY1);
+ if (retval != ERROR_OK)
+ return retval;
+ retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY2);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* force re-load of option bytes - generates software reset */
+ retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_OBL_LAUNCH);
+ if (retval != ERROR_OK)
+ return retval;
return ERROR_OK;
}
@@ -1574,7 +1528,7 @@ static const struct command_registration stm32x_exec_command_handlers[] = {
.handler = stm32x_handle_options_read_command,
.mode = COMMAND_EXEC,
.usage = "bank_id",
- .help = "Read and display device option byte.",
+ .help = "Read and display device option bytes.",
},
{
.name = "options_write",
@@ -1583,7 +1537,14 @@ static const struct command_registration stm32x_exec_command_handlers[] = {
.usage = "bank_id ('SWWDG'|'HWWDG') "
"('RSTSTNDBY'|'NORSTSTNDBY') "
"('RSTSTOP'|'NORSTSTOP')",
- .help = "Replace bits in device option byte.",
+ .help = "Replace bits in device option bytes.",
+ },
+ {
+ .name = "options_load",
+ .handler = stm32x_handle_options_load_command,
+ .mode = COMMAND_EXEC,
+ .usage = "bank_id",
+ .help = "Force re-load of device option bytes.",
},
COMMAND_REGISTRATION_DONE
};
diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c
index 413d04d77..b46fb0786 100644
--- a/src/flash/nor/stm32f2x.c
+++ b/src/flash/nor/stm32f2x.c
@@ -1190,6 +1190,9 @@ static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size)
case 0x1000:
rev_str = "A";
break;
+ case 0x1001:
+ rev_str = "Z";
+ break;
}
break;
diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c
index 4fb7e039a..ad179216d 100644
--- a/src/flash/nor/stm32l4x.c
+++ b/src/flash/nor/stm32l4x.c
@@ -57,8 +57,8 @@
#define STM32_FLASH_CR 0x40022014
#define STM32_FLASH_OPTR 0x40022020
#define STM32_FLASH_WRP1AR 0x4002202c
-#define STM32_FLASH_WRP2AR 0x40022030
-#define STM32_FLASH_WRP1BR 0x4002204c
+#define STM32_FLASH_WRP1BR 0x40022030
+#define STM32_FLASH_WRP2AR 0x4002204c
#define STM32_FLASH_WRP2BR 0x40022050
/* FLASH_CR register bits */
@@ -70,8 +70,10 @@
#define FLASH_CR_BKER (1 << 11)
#define FLASH_MER2 (1 << 15)
#define FLASH_STRT (1 << 16)
+#define FLASH_OPTSTRT (1 << 17)
#define FLASH_EOPIE (1 << 24)
#define FLASH_ERRIE (1 << 25)
+#define FLASH_OBLLAUNCH (1 << 27)
#define FLASH_OPTLOCK (1 << 30)
#define FLASH_LOCK (1 << 31)
@@ -102,28 +104,17 @@
#define OPTKEY1 0x08192A3B
#define OPTKEY2 0x4C5D6E7F
+#define RDP_LEVEL_0 0xAA
+#define RDP_LEVEL_1 0xBB
+#define RDP_LEVEL_2 0xCC
+
/* other registers */
#define DBGMCU_IDCODE 0xE0042000
#define FLASH_SIZE_REG 0x1FFF75E0
-struct stm32l4_options {
- uint8_t RDP;
- uint16_t bank_b_start;
- uint8_t user_options;
- uint8_t wpr1a_start;
- uint8_t wpr1a_end;
- uint8_t wpr1b_start;
- uint8_t wpr1b_end;
- uint8_t wpr2a_start;
- uint8_t wpr2a_end;
- uint8_t wpr2b_start;
- uint8_t wpr2b_end;
- /* Fixme: Handle PCROP */
-};
-
struct stm32l4_flash_bank {
- struct stm32l4_options option_bytes;
+ uint16_t bank2_start;
int probed;
};
@@ -265,97 +256,80 @@ static int stm32l4_unlock_option_reg(struct target *target)
return ERROR_OK;
}
-static int stm32l4_read_options(struct flash_bank *bank)
+static int stm32l4_read_option(struct flash_bank *bank, uint32_t address, uint32_t* value)
{
- uint32_t optiondata;
- struct stm32l4_flash_bank *stm32l4_info = NULL;
struct target *target = bank->target;
-
- stm32l4_info = bank->driver_priv;
-
- /* read current option bytes */
- int retval = target_read_u32(target, STM32_FLASH_OPTR, &optiondata);
- if (retval != ERROR_OK)
- return retval;
-
- stm32l4_info->option_bytes.user_options = (optiondata >> 8) & 0x3ffff;
- stm32l4_info->option_bytes.RDP = optiondata & 0xff;
-
- retval = target_read_u32(target, STM32_FLASH_WRP1AR, &optiondata);
- if (retval != ERROR_OK)
- return retval;
- stm32l4_info->option_bytes.wpr1a_start = optiondata & 0xff;
- stm32l4_info->option_bytes.wpr1a_end = (optiondata >> 16) & 0xff;
-
- retval = target_read_u32(target, STM32_FLASH_WRP2AR, &optiondata);
- if (retval != ERROR_OK)
- return retval;
- stm32l4_info->option_bytes.wpr2a_start = optiondata & 0xff;
- stm32l4_info->option_bytes.wpr2a_end = (optiondata >> 16) & 0xff;
-
- retval = target_read_u32(target, STM32_FLASH_WRP1BR, &optiondata);
- if (retval != ERROR_OK)
- return retval;
- stm32l4_info->option_bytes.wpr1b_start = optiondata & 0xff;
- stm32l4_info->option_bytes.wpr1b_end = (optiondata >> 16) & 0xff;
-
- retval = target_read_u32(target, STM32_FLASH_WRP2BR, &optiondata);
- if (retval != ERROR_OK)
- return retval;
- stm32l4_info->option_bytes.wpr2b_start = optiondata & 0xff;
- stm32l4_info->option_bytes.wpr2b_end = (optiondata >> 16) & 0xff;
-
- if (stm32l4_info->option_bytes.RDP != 0xAA)
- LOG_INFO("Device Security Bit Set");
-
- return ERROR_OK;
+ return target_read_u32(target, address, value);
}
-static int stm32l4_write_options(struct flash_bank *bank)
+static int stm32l4_write_option(struct flash_bank *bank, uint32_t address, uint32_t value, uint32_t mask)
{
- struct stm32l4_flash_bank *stm32l4_info = NULL;
struct target *target = bank->target;
uint32_t optiondata;
- stm32l4_info = bank->driver_priv;
-
- (void) optiondata;
- (void) stm32l4_info;
-
- int retval = stm32l4_unlock_option_reg(target);
+ int retval = target_read_u32(target, address, &optiondata);
if (retval != ERROR_OK)
return retval;
- /* FIXME: Implement Option writing!*/
- return ERROR_OK;
+
+ retval = stm32l4_unlock_reg(target);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = stm32l4_unlock_option_reg(target);
+ if (retval != ERROR_OK)
+ return retval;
+
+ optiondata = (optiondata & ~mask) | (value & mask);
+
+ retval = target_write_u32(target, address, optiondata);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = target_write_u32(target, stm32l4_get_flash_reg(bank, STM32_FLASH_CR), FLASH_OPTSTRT);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT);
+ if (retval != ERROR_OK)
+ return retval;
+
+ return retval;
}
static int stm32l4_protect_check(struct flash_bank *bank)
{
struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+ uint32_t wrp1ar, wrp1br, wrp2ar, wrp2br;
+ stm32l4_read_option(bank, STM32_FLASH_WRP1AR, &wrp1ar);
+ stm32l4_read_option(bank, STM32_FLASH_WRP1BR, &wrp1br);
+ stm32l4_read_option(bank, STM32_FLASH_WRP2AR, &wrp2ar);
+ stm32l4_read_option(bank, STM32_FLASH_WRP2BR, &wrp2br);
- /* read write protection settings */
- int retval = stm32l4_read_options(bank);
- if (retval != ERROR_OK) {
- LOG_DEBUG("unable to read option bytes");
- return retval;
- }
+ const uint8_t wrp1a_start = wrp1ar & 0xFF;
+ const uint8_t wrp1a_end = (wrp1ar >> 16) & 0xFF;
+ const uint8_t wrp1b_start = wrp1br & 0xFF;
+ const uint8_t wrp1b_end = (wrp1br >> 16) & 0xFF;
+ const uint8_t wrp2a_start = wrp2ar & 0xFF;
+ const uint8_t wrp2a_end = (wrp2ar >> 16) & 0xFF;
+ const uint8_t wrp2b_start = wrp2br & 0xFF;
+ const uint8_t wrp2b_end = (wrp2br >> 16) & 0xFF;
for (int i = 0; i < bank->num_sectors; i++) {
- if (i < stm32l4_info->option_bytes.bank_b_start) {
- if (((i >= stm32l4_info->option_bytes.wpr1a_start) &&
- (i <= stm32l4_info->option_bytes.wpr1a_end)) ||
- ((i >= stm32l4_info->option_bytes.wpr2a_start) &&
- (i <= stm32l4_info->option_bytes.wpr2a_end)))
+ if (i < stm32l4_info->bank2_start) {
+ if (((i >= wrp1a_start) &&
+ (i <= wrp1a_end)) ||
+ ((i >= wrp1b_start) &&
+ (i <= wrp1b_end)))
bank->sectors[i].is_protected = 1;
else
bank->sectors[i].is_protected = 0;
} else {
uint8_t snb;
- snb = i - stm32l4_info->option_bytes.bank_b_start + 256;
- if (((snb >= stm32l4_info->option_bytes.wpr1b_start) &&
- (snb <= stm32l4_info->option_bytes.wpr1b_end)) ||
- ((snb >= stm32l4_info->option_bytes.wpr2b_start) &&
- (snb <= stm32l4_info->option_bytes.wpr2b_end)))
+ snb = i - stm32l4_info->bank2_start + 256;
+ if (((snb >= wrp2a_start) &&
+ (snb <= wrp2a_end)) ||
+ ((snb >= wrp2b_start) &&
+ (snb <= wrp2b_end)))
bank->sectors[i].is_protected = 1;
else
bank->sectors[i].is_protected = 0;
@@ -398,9 +372,9 @@ static int stm32l4_erase(struct flash_bank *bank, int first, int last)
uint32_t erase_flags;
erase_flags = FLASH_PER | FLASH_STRT;
- if (i >= stm32l4_info->option_bytes.bank_b_start) {
+ if (i >= stm32l4_info->bank2_start) {
uint8_t snb;
- snb = (i - stm32l4_info->option_bytes.bank_b_start) + 256;
+ snb = (i - stm32l4_info->bank2_start) + 256;
erase_flags |= snb << FLASH_PAGE_SHIFT | FLASH_CR_BKER;
} else
erase_flags |= i << FLASH_PAGE_SHIFT;
@@ -434,20 +408,29 @@ static int stm32l4_protect(struct flash_bank *bank, int set, int first, int last
return ERROR_TARGET_NOT_HALTED;
}
- /* read protection settings */
- int retval = stm32l4_read_options(bank);
- if (retval != ERROR_OK) {
- LOG_DEBUG("unable to read option bytes");
- return retval;
+ int ret = ERROR_OK;
+ /* Bank 2 */
+ uint32_t reg_value = 0xFF; /* Default to bank un-protected */
+ if (last >= stm32l4_info->bank2_start) {
+ if (set == 1) {
+ uint8_t begin = first > stm32l4_info->bank2_start ? first : 0x00;
+ reg_value = ((last & 0xFF) << 16) | begin;
+ }
+
+ ret = stm32l4_write_option(bank, STM32_FLASH_WRP2AR, reg_value, 0xffffffff);
+ }
+ /* Bank 1 */
+ reg_value = 0xFF; /* Default to bank un-protected */
+ if (first < stm32l4_info->bank2_start) {
+ if (set == 1) {
+ uint8_t end = last >= stm32l4_info->bank2_start ? 0xFF : last;
+ reg_value = (end << 16) | (first & 0xFF);
+ }
+
+ ret = stm32l4_write_option(bank, STM32_FLASH_WRP1AR, reg_value, 0xffffffff);
}
- (void)stm32l4_info;
- /* FIXME: Write First and last in a valid WRPxx_start/end combo*/
- retval = stm32l4_write_options(bank);
- if (retval != ERROR_OK)
- return retval;
-
- return ERROR_OK;
+ return ret;
}
/* Count is in halfwords */
@@ -650,9 +633,9 @@ static int stm32l4_probe(struct flash_bank *bank)
/* only devices with < 1024 kiB may be set to single bank dual banks */
if ((flash_size_in_kb == 1024) || !(options & OPT_DUALBANK))
- stm32l4_info->option_bytes.bank_b_start = 256;
+ stm32l4_info->bank2_start = 256;
else
- stm32l4_info->option_bytes.bank_b_start = flash_size_in_kb << 9;
+ stm32l4_info->bank2_start = flash_size_in_kb << 9;
/* did we assign flash size? */
assert((flash_size_in_kb != 0xffff) && flash_size_in_kb);
@@ -747,89 +730,6 @@ static int get_stm32l4_info(struct flash_bank *bank, char *buf, int buf_size)
return ERROR_OK;
}
-COMMAND_HANDLER(stm32l4_handle_lock_command)
-{
- struct target *target = NULL;
- struct stm32l4_flash_bank *stm32l4_info = NULL;
-
- if (CMD_ARGC < 1)
- return ERROR_COMMAND_SYNTAX_ERROR;
-
- struct flash_bank *bank;
- int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
- if (ERROR_OK != retval)
- return retval;
-
- stm32l4_info = bank->driver_priv;
- target = bank->target;
-
- if (target->state != TARGET_HALTED) {
- LOG_ERROR("Target not halted");
- return ERROR_TARGET_NOT_HALTED;
- }
-
- if (stm32l4_read_options(bank) != ERROR_OK) {
- command_print(CMD_CTX, "%s failed to read options",
- bank->driver->name);
- return ERROR_OK;
- }
-
- /* set readout protection */
- stm32l4_info->option_bytes.RDP = 0;
-
- if (stm32l4_write_options(bank) != ERROR_OK) {
- command_print(CMD_CTX, "%s failed to lock device", bank->driver->name);
- return ERROR_OK;
- }
-
- command_print(CMD_CTX, "%s locked", bank->driver->name);
-
- return ERROR_OK;
-}
-
-COMMAND_HANDLER(stm32l4_handle_unlock_command)
-{
- struct target *target = NULL;
- struct stm32l4_flash_bank *stm32l4_info = NULL;
-
- if (CMD_ARGC < 1)
- return ERROR_COMMAND_SYNTAX_ERROR;
-
- struct flash_bank *bank;
- int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
- if (ERROR_OK != retval)
- return retval;
-
- stm32l4_info = bank->driver_priv;
- target = bank->target;
-
- if (target->state != TARGET_HALTED) {
- LOG_ERROR("Target not halted");
- return ERROR_TARGET_NOT_HALTED;
- }
-
- if (stm32l4_read_options(bank) != ERROR_OK) {
- command_print(CMD_CTX, "%s failed to read options", bank->driver->name);
- return ERROR_OK;
- }
-
- /* clear readout protection and complementary option bytes
- * this will also force a device unlock if set */
- stm32l4_info->option_bytes.RDP = 0xAA;
-
- if (stm32l4_write_options(bank) != ERROR_OK) {
- command_print(CMD_CTX, "%s failed to unlock device",
- bank->driver->name);
- return ERROR_OK;
- }
-
- command_print(CMD_CTX, "%s unlocked.\n"
- "INFO: a reset or power cycle is required "
- "for the new settings to take effect.", bank->driver->name);
-
- return ERROR_OK;
-}
-
static int stm32l4_mass_erase(struct flash_bank *bank, uint32_t action)
{
int retval;
@@ -873,7 +773,7 @@ COMMAND_HANDLER(stm32l4_handle_mass_erase_command)
uint32_t action;
if (CMD_ARGC < 1) {
- command_print(CMD_CTX, "stm32x mass_erase ");
+ command_print(CMD_CTX, "stm32l4x mass_erase ");
return ERROR_COMMAND_SYNTAX_ERROR;
}
@@ -889,14 +789,151 @@ COMMAND_HANDLER(stm32l4_handle_mass_erase_command)
for (i = 0; i < bank->num_sectors; i++)
bank->sectors[i].is_erased = 1;
- command_print(CMD_CTX, "stm32x mass erase complete");
+ command_print(CMD_CTX, "stm32l4x mass erase complete");
} else {
- command_print(CMD_CTX, "stm32x mass erase failed");
+ command_print(CMD_CTX, "stm32l4x mass erase failed");
}
return retval;
}
+COMMAND_HANDLER(stm32l4_handle_option_read_command)
+{
+ if (CMD_ARGC < 2) {
+ command_print(CMD_CTX, "stm32l4x option_read ");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ struct flash_bank *bank;
+ int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ uint32_t reg_addr = STM32_FLASH_BASE;
+ uint32_t value = 0;
+
+ reg_addr += strtoul(CMD_ARGV[1], NULL, 16);
+
+ retval = stm32l4_read_option(bank, reg_addr, &value);
+ if (ERROR_OK != retval)
+ return retval;
+
+ command_print(CMD_CTX, "Option Register: <0x%" PRIx32 "> = 0x%" PRIx32 "", reg_addr, value);
+
+ return retval;
+}
+
+COMMAND_HANDLER(stm32l4_handle_option_write_command)
+{
+ if (CMD_ARGC < 3) {
+ command_print(CMD_CTX, "stm32l4x option_write [mask]");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ struct flash_bank *bank;
+ int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ uint32_t reg_addr = STM32_FLASH_BASE;
+ uint32_t value = 0;
+ uint32_t mask = 0xFFFFFFFF;
+
+ reg_addr += strtoul(CMD_ARGV[1], NULL, 16);
+ value = strtoul(CMD_ARGV[2], NULL, 16);
+ if (CMD_ARGC > 3)
+ mask = strtoul(CMD_ARGV[3], NULL, 16);
+
+ command_print(CMD_CTX, "%s Option written.\n"
+ "INFO: a reset or power cycle is required "
+ "for the new settings to take effect.", bank->driver->name);
+
+ retval = stm32l4_write_option(bank, reg_addr, value, mask);
+ return retval;
+}
+
+COMMAND_HANDLER(stm32l4_handle_option_load_command)
+{
+ if (CMD_ARGC < 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ struct flash_bank *bank;
+ int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ struct target *target = bank->target;
+
+ retval = stm32l4_unlock_reg(target);
+ if (ERROR_OK != retval)
+ return retval;
+
+ retval = stm32l4_unlock_option_reg(target);
+ if (ERROR_OK != retval)
+ return retval;
+
+ /* Write the OBLLAUNCH bit in CR -> Cause device "POR" and option bytes reload */
+ retval = target_write_u32(target, stm32l4_get_flash_reg(bank, STM32_FLASH_CR), FLASH_OBLLAUNCH);
+
+ command_print(CMD_CTX, "stm32l4x option load (POR) completed.");
+ return retval;
+}
+
+COMMAND_HANDLER(stm32l4_handle_lock_command)
+{
+ struct target *target = NULL;
+
+ if (CMD_ARGC < 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ struct flash_bank *bank;
+ int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ target = bank->target;
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /* set readout protection level 1 by erasing the RDP option byte */
+ if (stm32l4_write_option(bank, STM32_FLASH_OPTR, 0, 0x000000FF) != ERROR_OK) {
+ command_print(CMD_CTX, "%s failed to lock device", bank->driver->name);
+ return ERROR_OK;
+ }
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(stm32l4_handle_unlock_command)
+{
+ struct target *target = NULL;
+
+ if (CMD_ARGC < 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ struct flash_bank *bank;
+ int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ target = bank->target;
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (stm32l4_write_option(bank, STM32_FLASH_OPTR, RDP_LEVEL_0, 0x000000FF) != ERROR_OK) {
+ command_print(CMD_CTX, "%s failed to unlock device", bank->driver->name);
+ return ERROR_OK;
+ }
+
+ return ERROR_OK;
+}
+
static const struct command_registration stm32l4_exec_command_handlers[] = {
{
.name = "lock",
@@ -919,6 +956,27 @@ static const struct command_registration stm32l4_exec_command_handlers[] = {
.usage = "bank_id",
.help = "Erase entire flash device.",
},
+ {
+ .name = "option_read",
+ .handler = stm32l4_handle_option_read_command,
+ .mode = COMMAND_EXEC,
+ .usage = "bank_id reg_offset",
+ .help = "Read & Display device option bytes.",
+ },
+ {
+ .name = "option_write",
+ .handler = stm32l4_handle_option_write_command,
+ .mode = COMMAND_EXEC,
+ .usage = "bank_id reg_offset value mask",
+ .help = "Write device option bit fields with provided value.",
+ },
+ {
+ .name = "option_load",
+ .handler = stm32l4_handle_option_load_command,
+ .mode = COMMAND_EXEC,
+ .usage = "bank_id",
+ .help = "Force re-load of device options (will cause device reset).",
+ },
COMMAND_REGISTRATION_DONE
};
diff --git a/src/jtag/Makefile.am b/src/jtag/Makefile.am
index 50ee263d0..a76486399 100644
--- a/src/jtag/Makefile.am
+++ b/src/jtag/Makefile.am
@@ -1,6 +1,6 @@
noinst_LTLIBRARIES += %D%/libjtag.la
-JTAG_SRCS =
+JTAG_SRCS = %D%/commands.c
%C%_libjtag_la_LIBADD =
BUILT_SOURCES += %D%/minidriver_imp.h
@@ -13,7 +13,7 @@ JTAG_SRCS += %D%/zy1000/zy1000.c
JTAG_MINIDRIVER_DIR = %D%/zy1000
endif
if MINIDRIVER_DUMMY
-JTAG_SRCS += %D%/minidummy/minidummy.c %D%/commands.c
+JTAG_SRCS += %D%/minidummy/minidummy.c
JTAG_MINIDRIVER_DIR = %D%/minidummy
endif
@@ -29,7 +29,6 @@ CLEANFILES += %D%/jtag_minidriver.h
else
MINIDRIVER_IMP_DIR = %D%/drivers
-JTAG_SRCS += %D%/commands.c
if HLADAPTER
include %D%/hla/Makefile.am
diff --git a/src/jtag/commands.c b/src/jtag/commands.c
index ed40755b7..e2d22cc94 100644
--- a/src/jtag/commands.c
+++ b/src/jtag/commands.c
@@ -144,6 +144,18 @@ void jtag_command_queue_reset(void)
next_command_pointer = &jtag_command_queue;
}
+/**
+ * Copy a struct scan_field for insertion into the queue.
+ *
+ * This allocates a new copy of out_value using cmd_queue_alloc.
+ */
+void jtag_scan_field_clone(struct scan_field *dst, const struct scan_field *src)
+{
+ dst->num_bits = src->num_bits;
+ dst->out_value = buf_cpy(src->out_value, cmd_queue_alloc(DIV_ROUND_UP(src->num_bits, 8)), src->num_bits);
+ dst->in_value = src->in_value;
+}
+
enum scan_type jtag_scan_type(const struct scan_command *cmd)
{
int i;
diff --git a/src/jtag/commands.h b/src/jtag/commands.h
index 947c94725..c0375964c 100644
--- a/src/jtag/commands.h
+++ b/src/jtag/commands.h
@@ -168,6 +168,7 @@ void *cmd_queue_alloc(size_t size);
void jtag_queue_command(struct jtag_command *cmd);
void jtag_command_queue_reset(void);
+void jtag_scan_field_clone(struct scan_field *dst, const struct scan_field *src);
enum scan_type jtag_scan_type(const struct scan_command *cmd);
int jtag_scan_size(const struct scan_command *cmd);
int jtag_read_buffer(uint8_t *buffer, const struct scan_command *cmd);
diff --git a/src/jtag/drivers/bitq.c b/src/jtag/drivers/bitq.c
index 66285f700..55dfe0aa4 100644
--- a/src/jtag/drivers/bitq.c
+++ b/src/jtag/drivers/bitq.c
@@ -123,7 +123,7 @@ static void bitq_path_move(struct pathmove_command *cmd)
{
int i;
- for (i = 0; i <= cmd->num_states; i++) {
+ for (i = 0; i < cmd->num_states; i++) {
if (tap_state_transition(tap_get_state(), false) == cmd->path[i])
bitq_io(0, 0, 0);
else if (tap_state_transition(tap_get_state(), true) == cmd->path[i])
diff --git a/src/jtag/drivers/cmsis_dap_usb.c b/src/jtag/drivers/cmsis_dap_usb.c
index 4ee483659..035cc446e 100644
--- a/src/jtag/drivers/cmsis_dap_usb.c
+++ b/src/jtag/drivers/cmsis_dap_usb.c
@@ -166,7 +166,7 @@ static const char * const info_caps_str[] = {
struct cmsis_dap {
hid_device *dev_handle;
uint16_t packet_size;
- uint16_t packet_count;
+ int packet_count;
uint8_t *packet_buffer;
uint8_t caps;
uint8_t mode;
@@ -178,6 +178,11 @@ struct pending_transfer_result {
void *buffer;
};
+struct pending_request_block {
+ struct pending_transfer_result *transfers;
+ int transfer_count;
+};
+
struct pending_scan_result {
/** Offset in bytes in the CMD_DAP_JTAG_SEQ response buffer. */
unsigned first;
@@ -189,8 +194,16 @@ struct pending_scan_result {
unsigned buffer_offset;
};
-static int pending_transfer_count, pending_queue_len;
-static struct pending_transfer_result *pending_transfers;
+/* Up to MIN(packet_count, MAX_PENDING_REQUESTS) requests may be issued
+ * until the first response arrives */
+#define MAX_PENDING_REQUESTS 3
+
+/* Pending requests are organized as a FIFO - circular buffer */
+/* Each block in FIFO can contain up to pending_queue_len transfers */
+static int pending_queue_len;
+static struct pending_request_block pending_fifo[MAX_PENDING_REQUESTS];
+static int pending_fifo_put_idx, pending_fifo_get_idx;
+static int pending_fifo_block_count;
/* pointers to buffers that will receive jtag scan results on the next flush */
#define MAX_PENDING_SCAN_RESULTS 256
@@ -346,14 +359,16 @@ static void cmsis_dap_usb_close(struct cmsis_dap *dap)
cmsis_dap_handle = NULL;
free(cmsis_dap_serial);
cmsis_dap_serial = NULL;
- free(pending_transfers);
- pending_transfers = NULL;
+
+ for (int i = 0; i < MAX_PENDING_REQUESTS; i++) {
+ free(pending_fifo[i].transfers);
+ pending_fifo[i].transfers = NULL;
+ }
return;
}
-/* Send a message and receive the reply */
-static int cmsis_dap_usb_xfer(struct cmsis_dap *dap, int txlen)
+static int cmsis_dap_usb_write(struct cmsis_dap *dap, int txlen)
{
#ifdef CMSIS_DAP_JTAG_DEBUG
LOG_DEBUG("cmsis-dap usb xfer cmd=%02X", dap->packet_buffer[1]);
@@ -368,6 +383,26 @@ static int cmsis_dap_usb_xfer(struct cmsis_dap *dap, int txlen)
return ERROR_FAIL;
}
+ return ERROR_OK;
+}
+
+/* Send a message and receive the reply */
+static int cmsis_dap_usb_xfer(struct cmsis_dap *dap, int txlen)
+{
+ if (pending_fifo_block_count) {
+ LOG_ERROR("pending %d blocks, flushing", pending_fifo_block_count);
+ while (pending_fifo_block_count) {
+ hid_read_timeout(dap->dev_handle, dap->packet_buffer, dap->packet_size, 10);
+ pending_fifo_block_count--;
+ }
+ pending_fifo_put_idx = 0;
+ pending_fifo_get_idx = 0;
+ }
+
+ int retval = cmsis_dap_usb_write(dap, txlen);
+ if (retval != ERROR_OK)
+ return retval;
+
/* get reply */
retval = hid_read_timeout(dap->dev_handle, dap->packet_buffer, dap->packet_size, USB_TIMEOUT);
if (retval == -1 || retval == 0) {
@@ -594,29 +629,31 @@ static int cmsis_dap_cmd_DAP_Delay(uint16_t delay_us)
}
#endif
-static int cmsis_dap_swd_run_queue(void)
+static void cmsis_dap_swd_write_from_queue(struct cmsis_dap *dap)
{
- uint8_t *buffer = cmsis_dap_handle->packet_buffer;
+ uint8_t *buffer = dap->packet_buffer;
+ struct pending_request_block *block = &pending_fifo[pending_fifo_put_idx];
- LOG_DEBUG_IO("Executing %d queued transactions", pending_transfer_count);
+ LOG_DEBUG_IO("Executing %d queued transactions from FIFO index %d", block->transfer_count, pending_fifo_put_idx);
if (queued_retval != ERROR_OK) {
LOG_DEBUG("Skipping due to previous errors: %d", queued_retval);
goto skip;
}
- if (!pending_transfer_count)
+ if (block->transfer_count == 0)
goto skip;
size_t idx = 0;
buffer[idx++] = 0; /* report number */
buffer[idx++] = CMD_DAP_TFER;
buffer[idx++] = 0x00; /* DAP Index */
- buffer[idx++] = pending_transfer_count;
+ buffer[idx++] = block->transfer_count;
- for (int i = 0; i < pending_transfer_count; i++) {
- uint8_t cmd = pending_transfers[i].cmd;
- uint32_t data = pending_transfers[i].data;
+ for (int i = 0; i < block->transfer_count; i++) {
+ struct pending_transfer_result *transfer = &(block->transfers[i]);
+ uint8_t cmd = transfer->cmd;
+ uint32_t data = transfer->data;
LOG_DEBUG_IO("%s %s reg %x %"PRIx32,
cmd & SWD_CMD_APnDP ? "AP" : "DP",
@@ -651,26 +688,62 @@ static int cmsis_dap_swd_run_queue(void)
}
}
- queued_retval = cmsis_dap_usb_xfer(cmsis_dap_handle, idx);
+ queued_retval = cmsis_dap_usb_write(dap, idx);
if (queued_retval != ERROR_OK)
goto skip;
- idx = 2;
- uint8_t ack = buffer[idx] & 0x07;
- if (ack != SWD_ACK_OK || (buffer[idx] & 0x08)) {
- LOG_DEBUG("SWD ack not OK: %d %s", buffer[idx-1],
+ pending_fifo_put_idx = (pending_fifo_put_idx + 1) % dap->packet_count;
+ pending_fifo_block_count++;
+ if (pending_fifo_block_count > dap->packet_count)
+ LOG_ERROR("too much pending writes %d", pending_fifo_block_count);
+
+ return;
+
+skip:
+ block->transfer_count = 0;
+}
+
+static void cmsis_dap_swd_read_process(struct cmsis_dap *dap, int timeout_ms)
+{
+ uint8_t *buffer = dap->packet_buffer;
+ struct pending_request_block *block = &pending_fifo[pending_fifo_get_idx];
+
+ if (pending_fifo_block_count == 0)
+ LOG_ERROR("no pending write");
+
+ /* get reply */
+ int retval = hid_read_timeout(dap->dev_handle, dap->packet_buffer, dap->packet_size, timeout_ms);
+ if (retval == 0 && timeout_ms < USB_TIMEOUT)
+ return;
+
+ if (retval == -1 || retval == 0) {
+ LOG_DEBUG("error reading data: %ls", hid_error(dap->dev_handle));
+ queued_retval = ERROR_FAIL;
+ goto skip;
+ }
+
+ if (buffer[2] & 0x08) {
+ LOG_DEBUG("CMSIS-DAP Protocol Error @ %d (wrong parity)", buffer[1]);
+ queued_retval = ERROR_FAIL;
+ goto skip;
+ }
+ uint8_t ack = buffer[2] & 0x07;
+ if (ack != SWD_ACK_OK) {
+ LOG_DEBUG("SWD ack not OK @ %d %s", buffer[1],
ack == SWD_ACK_WAIT ? "WAIT" : ack == SWD_ACK_FAULT ? "FAULT" : "JUNK");
queued_retval = ack == SWD_ACK_WAIT ? ERROR_WAIT : ERROR_FAIL;
goto skip;
}
- idx++;
- if (pending_transfer_count != buffer[1])
+ if (block->transfer_count != buffer[1])
LOG_ERROR("CMSIS-DAP transfer count mismatch: expected %d, got %d",
- pending_transfer_count, buffer[1]);
+ block->transfer_count, buffer[1]);
+ LOG_DEBUG_IO("Received results of %d queued transactions FIFO index %d", buffer[1], pending_fifo_get_idx);
+ size_t idx = 3;
for (int i = 0; i < buffer[1]; i++) {
- if (pending_transfers[i].cmd & SWD_CMD_RnW) {
+ struct pending_transfer_result *transfer = &(block->transfers[i]);
+ if (transfer->cmd & SWD_CMD_RnW) {
static uint32_t last_read;
uint32_t data = le_to_h_u32(&buffer[idx]);
uint32_t tmp = data;
@@ -679,19 +752,36 @@ static int cmsis_dap_swd_run_queue(void)
LOG_DEBUG_IO("Read result: %"PRIx32, data);
/* Imitate posted AP reads */
- if ((pending_transfers[i].cmd & SWD_CMD_APnDP) ||
- ((pending_transfers[i].cmd & SWD_CMD_A32) >> 1 == DP_RDBUFF)) {
+ if ((transfer->cmd & SWD_CMD_APnDP) ||
+ ((transfer->cmd & SWD_CMD_A32) >> 1 == DP_RDBUFF)) {
tmp = last_read;
last_read = data;
}
- if (pending_transfers[i].buffer)
- *(uint32_t *)pending_transfers[i].buffer = tmp;
+ if (transfer->buffer)
+ *(uint32_t *)(transfer->buffer) = tmp;
}
}
skip:
- pending_transfer_count = 0;
+ block->transfer_count = 0;
+ pending_fifo_get_idx = (pending_fifo_get_idx + 1) % dap->packet_count;
+ pending_fifo_block_count--;
+}
+
+static int cmsis_dap_swd_run_queue(void)
+{
+ if (pending_fifo_block_count)
+ cmsis_dap_swd_read_process(cmsis_dap_handle, 0);
+
+ cmsis_dap_swd_write_from_queue(cmsis_dap_handle);
+
+ while (pending_fifo_block_count)
+ cmsis_dap_swd_read_process(cmsis_dap_handle, USB_TIMEOUT);
+
+ pending_fifo_put_idx = 0;
+ pending_fifo_get_idx = 0;
+
int retval = queued_retval;
queued_retval = ERROR_OK;
@@ -700,21 +790,29 @@ skip:
static void cmsis_dap_swd_queue_cmd(uint8_t cmd, uint32_t *dst, uint32_t data)
{
- if (pending_transfer_count == pending_queue_len) {
+ if (pending_fifo[pending_fifo_put_idx].transfer_count == pending_queue_len) {
+ if (pending_fifo_block_count)
+ cmsis_dap_swd_read_process(cmsis_dap_handle, 0);
+
/* Not enough room in the queue. Run the queue. */
- queued_retval = cmsis_dap_swd_run_queue();
+ cmsis_dap_swd_write_from_queue(cmsis_dap_handle);
+
+ if (pending_fifo_block_count >= cmsis_dap_handle->packet_count)
+ cmsis_dap_swd_read_process(cmsis_dap_handle, USB_TIMEOUT);
}
if (queued_retval != ERROR_OK)
return;
- pending_transfers[pending_transfer_count].data = data;
- pending_transfers[pending_transfer_count].cmd = cmd;
+ struct pending_request_block *block = &pending_fifo[pending_fifo_put_idx];
+ struct pending_transfer_result *transfer = &(block->transfers[block->transfer_count]);
+ transfer->data = data;
+ transfer->cmd = cmd;
if (cmd & SWD_CMD_RnW) {
/* Queue a read transaction */
- pending_transfers[pending_transfer_count].buffer = dst;
+ transfer->buffer = dst;
}
- pending_transfer_count++;
+ block->transfer_count++;
}
static void cmsis_dap_swd_write_reg(uint8_t cmd, uint32_t value, uint32_t ap_delay_clk)
@@ -895,9 +993,7 @@ static int cmsis_dap_init(void)
retval = cmsis_dap_swd_open();
if (retval != ERROR_OK)
return retval;
- }
-
- if (cmsis_dap_handle == NULL) {
+ } else {
/* Connect in JTAG mode */
if (!(cmsis_dap_handle->caps & INFO_CAPS_JTAG)) {
LOG_ERROR("CMSIS-DAP: JTAG not supported");
@@ -911,6 +1007,11 @@ static int cmsis_dap_init(void)
LOG_INFO("CMSIS-DAP: Interface Initialised (JTAG)");
}
+ /* Be conservative and supress submiting multiple HID requests
+ * until we get packet count info from the adaptor */
+ cmsis_dap_handle->packet_count = 1;
+ pending_queue_len = 12;
+
/* INFO_ID_PKT_SZ - short */
retval = cmsis_dap_cmd_DAP_Info(INFO_ID_PKT_SZ, &data);
if (retval != ERROR_OK)
@@ -923,11 +1024,6 @@ static int cmsis_dap_init(void)
* write. For bulk read sequences just 4 bytes are
* needed per transfer, so this is suboptimal. */
pending_queue_len = (pkt_sz - 4) / 5;
- pending_transfers = malloc(pending_queue_len * sizeof(*pending_transfers));
- if (!pending_transfers) {
- LOG_ERROR("Unable to allocate memory for CMSIS-DAP queue");
- return ERROR_FAIL;
- }
if (cmsis_dap_handle->packet_size != pkt_sz + 1) {
/* reallocate buffer */
@@ -949,11 +1045,23 @@ static int cmsis_dap_init(void)
return retval;
if (data[0] == 1) { /* byte */
- uint16_t pkt_cnt = data[1];
- cmsis_dap_handle->packet_count = pkt_cnt;
- LOG_DEBUG("CMSIS-DAP: Packet Count = %" PRId16, pkt_cnt);
+ int pkt_cnt = data[1];
+ if (pkt_cnt > 1)
+ cmsis_dap_handle->packet_count = MIN(MAX_PENDING_REQUESTS, pkt_cnt);
+
+ LOG_DEBUG("CMSIS-DAP: Packet Count = %d", pkt_cnt);
}
+ LOG_DEBUG("Allocating FIFO for %d pending HID requests", cmsis_dap_handle->packet_count);
+ for (int i = 0; i < cmsis_dap_handle->packet_count; i++) {
+ pending_fifo[i].transfers = malloc(pending_queue_len * sizeof(struct pending_transfer_result));
+ if (!pending_fifo[i].transfers) {
+ LOG_ERROR("Unable to allocate memory for CMSIS-DAP queue");
+ return ERROR_FAIL;
+ }
+ }
+
+
retval = cmsis_dap_get_status();
if (retval != ERROR_OK)
return ERROR_FAIL;
diff --git a/src/jtag/drivers/driver.c b/src/jtag/drivers/driver.c
index daf7cd426..4923f96eb 100644
--- a/src/jtag/drivers/driver.c
+++ b/src/jtag/drivers/driver.c
@@ -55,18 +55,6 @@ static void jtag_callback_queue_reset(void)
jtag_callback_queue_tail = NULL;
}
-/**
- * Copy a struct scan_field for insertion into the queue.
- *
- * This allocates a new copy of out_value using cmd_queue_alloc.
- */
-static void cmd_queue_scan_field_clone(struct scan_field *dst, const struct scan_field *src)
-{
- dst->num_bits = src->num_bits;
- dst->out_value = buf_cpy(src->out_value, cmd_queue_alloc(DIV_ROUND_UP(src->num_bits, 8)), src->num_bits);
- dst->in_value = src->in_value;
-}
-
/**
* see jtag_add_ir_scan()
*
@@ -101,7 +89,7 @@ int interface_jtag_add_ir_scan(struct jtag_tap *active,
/* if TAP is listed in input fields, copy the value */
tap->bypass = 0;
- cmd_queue_scan_field_clone(field, in_fields);
+ jtag_scan_field_clone(field, in_fields);
} else {
/* if a TAP isn't listed in input fields, set it to BYPASS */
@@ -168,7 +156,7 @@ int interface_jtag_add_dr_scan(struct jtag_tap *active, int in_num_fields,
#endif /* NDEBUG */
for (int j = 0; j < in_num_fields; j++) {
- cmd_queue_scan_field_clone(field, in_fields + j);
+ jtag_scan_field_clone(field, in_fields + j);
field++;
}
diff --git a/src/jtag/drivers/ftdi.c b/src/jtag/drivers/ftdi.c
index 6c1e50492..7deb1c493 100644
--- a/src/jtag/drivers/ftdi.c
+++ b/src/jtag/drivers/ftdi.c
@@ -506,11 +506,11 @@ static void ftdi_execute_scan(struct jtag_command *cmd)
while (cmd->cmd.scan->num_fields > 0
&& cmd->cmd.scan->fields[cmd->cmd.scan->num_fields - 1].num_bits == 0) {
cmd->cmd.scan->num_fields--;
- LOG_DEBUG("discarding trailing empty field");
+ DEBUG_JTAG_IO("discarding trailing empty field");
}
if (cmd->cmd.scan->num_fields == 0) {
- LOG_DEBUG("empty scan, doing nothing");
+ DEBUG_JTAG_IO("empty scan, doing nothing");
return;
}
diff --git a/src/jtag/drivers/libusb1_common.c b/src/jtag/drivers/libusb1_common.c
index 89f809271..a1db86f4b 100644
--- a/src/jtag/drivers/libusb1_common.c
+++ b/src/jtag/drivers/libusb1_common.c
@@ -71,11 +71,11 @@ int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[],
struct jtag_libusb_device_handle **out)
{
int cnt, idx, errCode;
- int retval = -ENODEV;
+ int retval = ERROR_FAIL;
struct jtag_libusb_device_handle *libusb_handle = NULL;
if (libusb_init(&jtag_libusb_context) < 0)
- return -ENODEV;
+ return ERROR_FAIL;
cnt = libusb_get_device_list(jtag_libusb_context, &devs);
@@ -105,7 +105,7 @@ int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[],
/* Success. */
*out = libusb_handle;
- retval = 0;
+ retval = ERROR_OK;
break;
}
if (cnt >= 0)
diff --git a/src/jtag/drivers/mpsse.c b/src/jtag/drivers/mpsse.c
index 6c70be6ad..43e924e03 100644
--- a/src/jtag/drivers/mpsse.c
+++ b/src/jtag/drivers/mpsse.c
@@ -121,7 +121,7 @@ static bool device_location_equal(libusb_device *device, const char *location)
LOG_DEBUG("device path has %i steps", path_len);
- ptr = strtok(loc, ":");
+ ptr = strtok(loc, "-:");
if (ptr == NULL) {
LOG_DEBUG("no ':' in path");
goto done;
@@ -133,7 +133,7 @@ static bool device_location_equal(libusb_device *device, const char *location)
path_step = 0;
while (path_step < 7) {
- ptr = strtok(NULL, ",");
+ ptr = strtok(NULL, ".,");
if (ptr == NULL) {
LOG_DEBUG("no more tokens in path at step %i", path_step);
break;
diff --git a/src/rtos/ChibiOS.c b/src/rtos/ChibiOS.c
index 312fc4d99..8839acc9a 100644
--- a/src/rtos/ChibiOS.c
+++ b/src/rtos/ChibiOS.c
@@ -105,7 +105,8 @@ static struct ChibiOS_params ChibiOS_params_list[] = {
static bool ChibiOS_detect_rtos(struct target *target);
static int ChibiOS_create(struct target *target);
static int ChibiOS_update_threads(struct rtos *rtos);
-static int ChibiOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list);
+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(symbol_table_elem_t *symbol_list[]);
struct rtos_type ChibiOS_rtos = {
@@ -464,13 +465,13 @@ static int ChibiOS_update_threads(struct rtos *rtos)
return 0;
}
-static int ChibiOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list)
+static int ChibiOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
+ struct rtos_reg **reg_list, int *num_regs)
{
int retval;
const struct ChibiOS_params *param;
uint32_t stack_ptr = 0;
- *hex_reg_list = NULL;
if ((rtos == NULL) || (thread_id == 0) ||
(rtos->rtos_specific_params == NULL))
return -1;
@@ -495,7 +496,7 @@ static int ChibiOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, cha
return retval;
}
- return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, hex_reg_list);
+ return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, reg_list, num_regs);
}
static int ChibiOS_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
diff --git a/src/rtos/FreeRTOS.c b/src/rtos/FreeRTOS.c
index 6027d6739..9d89974cc 100644
--- a/src/rtos/FreeRTOS.c
+++ b/src/rtos/FreeRTOS.c
@@ -102,7 +102,8 @@ static const struct FreeRTOS_params FreeRTOS_params_list[] = {
static bool FreeRTOS_detect_rtos(struct target *target);
static int FreeRTOS_create(struct target *target);
static int FreeRTOS_update_threads(struct rtos *rtos);
-static int FreeRTOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list);
+static int FreeRTOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
+ struct rtos_reg **reg_list, int *num_regs);
static int FreeRTOS_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]);
struct rtos_type FreeRTOS_rtos = {
@@ -395,13 +396,13 @@ static int FreeRTOS_update_threads(struct rtos *rtos)
return 0;
}
-static int FreeRTOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list)
+static int FreeRTOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
+ struct rtos_reg **reg_list, int *num_regs)
{
int retval;
const struct FreeRTOS_params *param;
int64_t stack_ptr = 0;
- *hex_reg_list = NULL;
if (rtos == NULL)
return -1;
@@ -460,11 +461,11 @@ static int FreeRTOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, ch
return retval;
}
if ((LR_svc & 0x10) == 0)
- return rtos_generic_stack_read(rtos->target, param->stacking_info_cm4f_fpu, stack_ptr, hex_reg_list);
+ return rtos_generic_stack_read(rtos->target, param->stacking_info_cm4f_fpu, stack_ptr, reg_list, num_regs);
else
- return rtos_generic_stack_read(rtos->target, param->stacking_info_cm4f, stack_ptr, hex_reg_list);
+ return rtos_generic_stack_read(rtos->target, param->stacking_info_cm4f, stack_ptr, reg_list, num_regs);
} else
- return rtos_generic_stack_read(rtos->target, param->stacking_info_cm3, stack_ptr, hex_reg_list);
+ return rtos_generic_stack_read(rtos->target, param->stacking_info_cm3, stack_ptr, reg_list, num_regs);
}
static int FreeRTOS_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
diff --git a/src/rtos/ThreadX.c b/src/rtos/ThreadX.c
index b7dbe6d11..9605533aa 100644
--- a/src/rtos/ThreadX.c
+++ b/src/rtos/ThreadX.c
@@ -38,7 +38,7 @@ static int is_thread_id_valid_arm926ejs(const struct rtos *rtos, int64_t thread_
static bool ThreadX_detect_rtos(struct target *target);
static int ThreadX_create(struct target *target);
static int ThreadX_update_threads(struct rtos *rtos);
-static int ThreadX_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list);
+static int ThreadX_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs);
static int ThreadX_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]);
@@ -69,45 +69,45 @@ static const struct ThreadX_thread_state ThreadX_thread_states[] = {
#define ARM926EJS_REGISTERS_SIZE_SOLICITED (11 * 4)
static const struct stack_register_offset rtos_threadx_arm926ejs_stack_offsets_solicited[] = {
- { -1, 32 }, /* r0 */
- { -1, 32 }, /* r1 */
- { -1, 32 }, /* r2 */
- { -1, 32 }, /* r3 */
- { 0x08, 32 }, /* r4 */
- { 0x0C, 32 }, /* r5 */
- { 0x10, 32 }, /* r6 */
- { 0x14, 32 }, /* r7 */
- { 0x18, 32 }, /* r8 */
- { 0x1C, 32 }, /* r9 */
- { 0x20, 32 }, /* r10 */
- { 0x24, 32 }, /* r11 */
- { -1, 32 }, /* r12 */
- { -2, 32 }, /* sp (r13) */
- { 0x28, 32 }, /* lr (r14) */
- { -1, 32 }, /* pc (r15) */
- /*{ -1, 32 },*/ /* lr (r14) */
- /*{ 0x28, 32 },*/ /* pc (r15) */
- { 0x04, 32 }, /* xPSR */
+ { 0, -1, 32 }, /* r0 */
+ { 1, -1, 32 }, /* r1 */
+ { 2, -1, 32 }, /* r2 */
+ { 3, -1, 32 }, /* r3 */
+ { 4, 0x08, 32 }, /* r4 */
+ { 5, 0x0C, 32 }, /* r5 */
+ { 6, 0x10, 32 }, /* r6 */
+ { 7, 0x14, 32 }, /* r7 */
+ { 8, 0x18, 32 }, /* r8 */
+ { 9, 0x1C, 32 }, /* r9 */
+ { 10, 0x20, 32 }, /* r10 */
+ { 11, 0x24, 32 }, /* r11 */
+ { 12, -1, 32 }, /* r12 */
+ { 13, -2, 32 }, /* sp (r13) */
+ { 14, 0x28, 32 }, /* lr (r14) */
+ { 15, -1, 32 }, /* pc (r15) */
+ /*{ 16, -1, 32 },*/ /* lr (r14) */
+ /*{ 17, 0x28, 32 },*/ /* pc (r15) */
+ { 16, 0x04, 32 }, /* xPSR */
};
#define ARM926EJS_REGISTERS_SIZE_INTERRUPT (17 * 4)
static const struct stack_register_offset rtos_threadx_arm926ejs_stack_offsets_interrupt[] = {
- { 0x08, 32 }, /* r0 */
- { 0x0C, 32 }, /* r1 */
- { 0x10, 32 }, /* r2 */
- { 0x14, 32 }, /* r3 */
- { 0x18, 32 }, /* r4 */
- { 0x1C, 32 }, /* r5 */
- { 0x20, 32 }, /* r6 */
- { 0x24, 32 }, /* r7 */
- { 0x28, 32 }, /* r8 */
- { 0x2C, 32 }, /* r9 */
- { 0x30, 32 }, /* r10 */
- { 0x34, 32 }, /* r11 */
- { 0x38, 32 }, /* r12 */
- { -2, 32 }, /* sp (r13) */
- { 0x3C, 32 }, /* lr (r14) */
- { 0x40, 32 }, /* pc (r15) */
- { 0x04, 32 }, /* xPSR */
+ { 0, 0x08, 32 }, /* r0 */
+ { 1, 0x0C, 32 }, /* r1 */
+ { 2, 0x10, 32 }, /* r2 */
+ { 3, 0x14, 32 }, /* r3 */
+ { 4, 0x18, 32 }, /* r4 */
+ { 5, 0x1C, 32 }, /* r5 */
+ { 6, 0x20, 32 }, /* r6 */
+ { 7, 0x24, 32 }, /* r7 */
+ { 8, 0x28, 32 }, /* r8 */
+ { 9, 0x2C, 32 }, /* r9 */
+ { 10, 0x30, 32 }, /* r10 */
+ { 11, 0x34, 32 }, /* r11 */
+ { 12, 0x38, 32 }, /* r12 */
+ { 13, -2, 32 }, /* sp (r13) */
+ { 14, 0x3C, 32 }, /* lr (r14) */
+ { 15, 0x40, 32 }, /* pc (r15) */
+ { 16, 0x04, 32 }, /* xPSR */
};
const struct rtos_register_stacking rtos_threadx_arm926ejs_stacking[] = {
@@ -433,13 +433,12 @@ static int ThreadX_update_threads(struct rtos *rtos)
return 0;
}
-static int ThreadX_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list)
+static int ThreadX_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
+ struct rtos_reg **reg_list, int *num_regs)
{
int retval;
const struct ThreadX_params *param;
- *hex_reg_list = NULL;
-
if (rtos == NULL)
return -1;
@@ -477,7 +476,7 @@ static int ThreadX_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, cha
return -6;
}
- return rtos_generic_stack_read(rtos->target, stacking_info, stack_ptr, hex_reg_list);
+ return rtos_generic_stack_read(rtos->target, stacking_info, stack_ptr, reg_list, num_regs);
}
static int ThreadX_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
diff --git a/src/rtos/eCos.c b/src/rtos/eCos.c
index 9e41030ee..e6b70730b 100644
--- a/src/rtos/eCos.c
+++ b/src/rtos/eCos.c
@@ -30,7 +30,7 @@
static bool eCos_detect_rtos(struct target *target);
static int eCos_create(struct target *target);
static int eCos_update_threads(struct rtos *rtos);
-static int eCos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list);
+static int eCos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs);
static int eCos_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]);
struct eCos_thread_state {
@@ -285,13 +285,12 @@ static int eCos_update_threads(struct rtos *rtos)
return 0;
}
-static int eCos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list)
+static int eCos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
+ struct rtos_reg **reg_list, int *num_regs)
{
int retval;
const struct eCos_params *param;
- *hex_reg_list = NULL;
-
if (rtos == NULL)
return -1;
@@ -345,7 +344,8 @@ static int eCos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char *
return rtos_generic_stack_read(rtos->target,
param->stacking_info,
stack_ptr,
- hex_reg_list);
+ reg_list,
+ num_regs);
}
return -1;
diff --git a/src/rtos/embKernel.c b/src/rtos/embKernel.c
index a40c86c3f..8a307f198 100644
--- a/src/rtos/embKernel.c
+++ b/src/rtos/embKernel.c
@@ -34,7 +34,8 @@
static bool embKernel_detect_rtos(struct target *target);
static int embKernel_create(struct target *target);
static int embKernel_update_threads(struct rtos *rtos);
-static int embKernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list);
+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(symbol_table_elem_t *symbol_list[]);
struct rtos_type embKernel_rtos = {
@@ -300,13 +301,13 @@ static int embKernel_update_threads(struct rtos *rtos)
return 0;
}
-static int embKernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list)
+static int embKernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
+ struct rtos_reg **reg_list, int *num_regs)
{
int retval;
const struct embKernel_params *param;
int64_t stack_ptr = 0;
- *hex_reg_list = NULL;
if (rtos == NULL)
return -1;
@@ -326,7 +327,7 @@ static int embKernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, c
return retval;
}
- return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, hex_reg_list);
+ return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, reg_list, num_regs);
}
static int embKernel_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
diff --git a/src/rtos/linux.c b/src/rtos/linux.c
index 3b2a2b0c3..74172b70a 100644
--- a/src/rtos/linux.c
+++ b/src/rtos/linux.c
@@ -144,16 +144,6 @@ static int linux_read_memory(struct target *target,
return ERROR_OK;
}
-static char *reg_converter(char *buffer, void *reg, int size)
-{
- int i;
-
- for (i = 0; i < size; i++)
- buffer += sprintf(buffer, "%02x", ((uint8_t *) reg)[i]);
-
- return buffer;
-}
-
int fill_buffer(struct target *target, uint32_t addr, uint8_t *buffer)
{
@@ -174,15 +164,13 @@ uint32_t get_buffer(struct target *target, const uint8_t *buffer)
}
static int linux_os_thread_reg_list(struct rtos *rtos,
- int64_t thread_id, char **hex_reg_list)
+ int64_t thread_id, struct rtos_reg **reg_list, int *num_regs)
{
struct target *target = rtos->target;
struct linux_os *linux_os = (struct linux_os *)
target->rtos->rtos_specific_params;
- int i = 0;
struct current_thread *tmp = linux_os->current_threads;
struct current_thread *next;
- char *hex_string;
int found = 0;
int retval;
/* check if a current thread is requested */
@@ -195,117 +183,52 @@ static int linux_os_thread_reg_list(struct rtos *rtos,
next = next->next;
} while ((found == 0) && (next != tmp) && (next != NULL));
- if (found == 1) {
- /* search target to perfom the access */
- struct reg **reg_list;
- int reg_list_size, reg_packet_size = 0;
- struct target_list *head;
- head = target->head;
- found = 0;
- do {
- if (head->target->coreid == next->core_id) {
-
- target = head->target;
- found = 1;
- } else
- head = head->next;
-
- } while ((head != (struct target_list *)NULL) && (found == 0));
-
- if (found == 0) {
- LOG_ERROR
- (
- "current thread %" PRIx64 ": no target to perform access of core id %" PRIx32,
- thread_id,
- next->core_id);
- return ERROR_FAIL;
- }
-
- /*LOG_INFO("thread %lx current on core %x",thread_id,
- * target->coreid);*/
- retval =
- target_get_gdb_reg_list(target, ®_list, ®_list_size,
- REG_CLASS_GENERAL);
-
- if (retval != ERROR_OK)
- return retval;
-
- for (i = 0; i < reg_list_size; i++)
- reg_packet_size += reg_list[i]->size;
-
- assert(reg_packet_size > 0);
-
- *hex_reg_list = malloc(DIV_ROUND_UP(reg_packet_size, 8) * 2);
-
- hex_string = *hex_reg_list;
-
- for (i = 0; i < reg_list_size; i++) {
- if (!reg_list[i]->valid)
- reg_list[i]->type->get(reg_list[i]);
-
- hex_string = reg_converter(hex_string,
- reg_list[i]->value,
- (reg_list[i]->size) / 8);
- }
-
- free(reg_list);
-
- } else {
- struct threads *temp = linux_os->thread_list;
- *hex_reg_list = calloc(1, 500 * sizeof(char));
- hex_string = *hex_reg_list;
-
- for (i = 0; i < 16; i++)
- hex_string += sprintf(hex_string, "%02x", 0);
-
- while ((temp != NULL) &&
- (temp->threadid != target->rtos->current_threadid))
- temp = temp->next;
-
- if (temp != NULL) {
- if (temp->context == NULL)
- temp->context = cpu_context_read(target,
- temp->
- base_addr,
- &temp->
- thread_info_addr);
-
- hex_string =
- reg_converter(hex_string, &temp->context->R4, 4);
- hex_string =
- reg_converter(hex_string, &temp->context->R5, 4);
- hex_string =
- reg_converter(hex_string, &temp->context->R6, 4);
- hex_string =
- reg_converter(hex_string, &temp->context->R7, 4);
- hex_string =
- reg_converter(hex_string, &temp->context->R8, 4);
- hex_string =
- reg_converter(hex_string, &temp->context->R9, 4);
-
- for (i = 0; i < 4; i++) /*R10 = 0x0 */
- hex_string += sprintf(hex_string, "%02x", 0);
-
- hex_string =
- reg_converter(hex_string, &temp->context->FP, 4);
- hex_string =
- reg_converter(hex_string, &temp->context->IP, 4);
- hex_string =
- reg_converter(hex_string, &temp->context->SP, 4);
-
- for (i = 0; i < 4; i++)
- hex_string += sprintf(hex_string, "%02x", 0);
-
- hex_string =
- reg_converter(hex_string, &temp->context->PC, 4);
-
- for (i = 0; i < 100; i++) /*100 */
- hex_string += sprintf(hex_string, "%02x", 0);
-
- uint32_t cpsr = 0x00000000;
- reg_converter(hex_string, &cpsr, 4);
- }
+ if (found == 0) {
+ LOG_ERROR("could not find thread: %" PRIx64, thread_id);
+ return ERROR_FAIL;
}
+
+ /* search target to perfom the access */
+ struct reg **gdb_reg_list;
+ struct target_list *head;
+ head = target->head;
+ found = 0;
+ do {
+ if (head->target->coreid == next->core_id) {
+
+ target = head->target;
+ found = 1;
+ } else
+ head = head->next;
+
+ } while ((head != (struct target_list *)NULL) && (found == 0));
+
+ if (found == 0) {
+ LOG_ERROR
+ (
+ "current thread %" PRIx64 ": no target to perform access of core id %" PRIx32,
+ thread_id,
+ next->core_id);
+ return ERROR_FAIL;
+ }
+
+ /*LOG_INFO("thread %lx current on core %x",thread_id, target->coreid);*/
+ retval = target_get_gdb_reg_list(target, &gdb_reg_list, num_regs, REG_CLASS_GENERAL);
+ if (retval != ERROR_OK)
+ return retval;
+
+ *reg_list = calloc(*num_regs, sizeof(struct rtos_reg));
+
+ for (int i = 0; i < *num_regs; ++i) {
+ if (!gdb_reg_list[i]->valid)
+ gdb_reg_list[i]->type->get(gdb_reg_list[i]);
+
+ (*reg_list)[i].number = gdb_reg_list[i]->number;
+ (*reg_list)[i].size = gdb_reg_list[i]->size;
+
+ buf_cpy(gdb_reg_list[i]->value, (*reg_list)[i].value, (*reg_list)[i].size);
+ }
+
return ERROR_OK;
}
@@ -1134,7 +1057,7 @@ int linux_gdb_thread_packet(struct target *target,
if (retval != ERROR_OK)
return ERROR_TARGET_FAILURE;
- char *out_str = calloc(1, 350 * sizeof(int64_t));
+ char *out_str = calloc(MAX_THREADS * 17 + 10, 1);
char *tmp_str = out_str;
tmp_str += sprintf(tmp_str, "m");
struct threads *temp = linux_os->thread_list;
@@ -1171,7 +1094,7 @@ int linux_gdb_thread_update(struct target *target,
if (found == 1) {
/*LOG_INFO("INTO GDB THREAD UPDATE FOUNDING START TASK");*/
- char *out_strr = calloc(1, 350 * sizeof(int64_t));
+ char *out_strr = calloc(MAX_THREADS * 17 + 10, 1);
char *tmp_strr = out_strr;
tmp_strr += sprintf(tmp_strr, "m");
/*LOG_INFO("CHAR MALLOC & M DONE");*/
diff --git a/src/rtos/mqx.c b/src/rtos/mqx.c
index 531b03b57..6646ad4de 100644
--- a/src/rtos/mqx.c
+++ b/src/rtos/mqx.c
@@ -456,7 +456,8 @@ static int mqx_update_threads(
static int mqx_get_thread_reg_list(
struct rtos *rtos,
int64_t thread_id,
- char **hex_reg_list
+ struct rtos_reg **reg_list,
+ int *num_regs
)
{
int64_t stack_ptr = 0;
@@ -465,7 +466,6 @@ static int mqx_get_thread_reg_list(
uint32_t task_queue_size = 0;
uint32_t kernel_data_addr = 0;
- *hex_reg_list = NULL;
if (thread_id == 0) {
LOG_ERROR("MQX RTOS - invalid threadid: 0x%X", (int)thread_id);
return ERROR_FAIL;
@@ -535,7 +535,7 @@ static int mqx_get_thread_reg_list(
return ERROR_FAIL;
}
return rtos_generic_stack_read(
- rtos->target, ((struct mqx_params *)rtos->rtos_specific_params)->stacking_info, stack_ptr, hex_reg_list
+ rtos->target, ((struct mqx_params *)rtos->rtos_specific_params)->stacking_info, stack_ptr, reg_list, num_regs
);
}
diff --git a/src/rtos/nuttx.c b/src/rtos/nuttx.c
index 284b968cc..61fd9aa6c 100644
--- a/src/rtos/nuttx.c
+++ b/src/rtos/nuttx.c
@@ -98,23 +98,23 @@ static char *task_state_str[] = {
/* see arch/arm/include/armv7-m/irq_cmnvector.h */
static const struct stack_register_offset nuttx_stack_offsets_cortex_m[] = {
- { 0x28, 32 }, /* r0 */
- { 0x2c, 32 }, /* r1 */
- { 0x30, 32 }, /* r2 */
- { 0x34, 32 }, /* r3 */
- { 0x08, 32 }, /* r4 */
- { 0x0c, 32 }, /* r5 */
- { 0x10, 32 }, /* r6 */
- { 0x14, 32 }, /* r7 */
- { 0x18, 32 }, /* r8 */
- { 0x1c, 32 }, /* r9 */
- { 0x20, 32 }, /* r10 */
- { 0x24, 32 }, /* r11 */
- { 0x38, 32 }, /* r12 */
- { 0, 32 }, /* sp */
- { 0x3c, 32 }, /* lr */
- { 0x40, 32 }, /* pc */
- { 0x44, 32 }, /* xPSR */
+ { ARMV7M_R0, 0x28, 32 }, /* r0 */
+ { ARMV7M_R1, 0x2c, 32 }, /* r1 */
+ { ARMV7M_R2, 0x30, 32 }, /* r2 */
+ { ARMV7M_R3, 0x34, 32 }, /* r3 */
+ { ARMV7M_R4, 0x08, 32 }, /* r4 */
+ { ARMV7M_R5, 0x0c, 32 }, /* r5 */
+ { ARMV7M_R6, 0x10, 32 }, /* r6 */
+ { ARMV7M_R7, 0x14, 32 }, /* r7 */
+ { ARMV7M_R8, 0x18, 32 }, /* r8 */
+ { ARMV7M_R9, 0x1c, 32 }, /* r9 */
+ { ARMV7M_R10, 0x20, 32 }, /* r10 */
+ { ARMV7M_R11, 0x24, 32 }, /* r11 */
+ { ARMV7M_R12, 0x38, 32 }, /* r12 */
+ { ARMV7M_R13, 0, 32 }, /* sp */
+ { ARMV7M_R14, 0x3c, 32 }, /* lr */
+ { ARMV7M_PC, 0x40, 32 }, /* pc */
+ { ARMV7M_xPSR, 0x44, 32 }, /* xPSR */
};
@@ -127,23 +127,23 @@ static const struct rtos_register_stacking nuttx_stacking_cortex_m = {
};
static const struct stack_register_offset nuttx_stack_offsets_cortex_m_fpu[] = {
- { 0x6c, 32 }, /* r0 */
- { 0x70, 32 }, /* r1 */
- { 0x74, 32 }, /* r2 */
- { 0x78, 32 }, /* r3 */
- { 0x08, 32 }, /* r4 */
- { 0x0c, 32 }, /* r5 */
- { 0x10, 32 }, /* r6 */
- { 0x14, 32 }, /* r7 */
- { 0x18, 32 }, /* r8 */
- { 0x1c, 32 }, /* r9 */
- { 0x20, 32 }, /* r10 */
- { 0x24, 32 }, /* r11 */
- { 0x7c, 32 }, /* r12 */
- { 0, 32 }, /* sp */
- { 0x80, 32 }, /* lr */
- { 0x84, 32 }, /* pc */
- { 0x88, 32 }, /* xPSR */
+ { ARMV7M_R0, 0x6c, 32 }, /* r0 */
+ { ARMV7M_R1, 0x70, 32 }, /* r1 */
+ { ARMV7M_R2, 0x74, 32 }, /* r2 */
+ { ARMV7M_R3, 0x78, 32 }, /* r3 */
+ { ARMV7M_R4, 0x08, 32 }, /* r4 */
+ { ARMV7M_R5, 0x0c, 32 }, /* r5 */
+ { ARMV7M_R6, 0x10, 32 }, /* r6 */
+ { ARMV7M_R7, 0x14, 32 }, /* r7 */
+ { ARMV7M_R8, 0x18, 32 }, /* r8 */
+ { ARMV7M_R9, 0x1c, 32 }, /* r9 */
+ { ARMV7M_R10, 0x20, 32 }, /* r10 */
+ { ARMV7M_R11, 0x24, 32 }, /* r11 */
+ { ARMV7M_R12, 0x7c, 32 }, /* r12 */
+ { ARMV7M_R13, 0, 32 }, /* sp */
+ { ARMV7M_R14, 0x80, 32 }, /* lr */
+ { ARMV7M_PC, 0x84, 32 }, /* pc */
+ { ARMV7M_xPSR, 0x88, 32 }, /* xPSR */
};
static const struct rtos_register_stacking nuttx_stacking_cortex_m_fpu = {
@@ -344,11 +344,10 @@ static int nuttx_update_threads(struct rtos *rtos)
* thread_id = tcb address;
*/
static int nuttx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
- char **hex_reg_list) {
+ struct rtos_reg **reg_list, int *num_regs)
+{
int retval;
- *hex_reg_list = NULL;
-
/* 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);
@@ -378,7 +377,7 @@ static int nuttx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
stacking = &nuttx_stacking_cortex_m;
return rtos_generic_stack_read(rtos->target, stacking,
- (uint32_t)thread_id + xcpreg_offset, hex_reg_list);
+ (uint32_t)thread_id + xcpreg_offset, reg_list, num_regs);
}
static int nuttx_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
diff --git a/src/rtos/riscv_debug.c b/src/rtos/riscv_debug.c
index 36500218e..d5cd4a1bf 100644
--- a/src/rtos/riscv_debug.c
+++ b/src/rtos/riscv_debug.c
@@ -270,39 +270,35 @@ static int riscv_gdb_v_packet(struct connection *connection, const char *packet,
return GDB_THREAD_PACKET_NOT_CONSUMED;
}
-static int riscv_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list)
+static int riscv_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
+ struct rtos_reg **reg_list, int *num_regs)
{
LOG_DEBUG("Updating RISC-V register list for hart %d", (int)(thread_id - 1));
- size_t n_regs = 32;
- size_t xlen = 64;
- size_t reg_chars = xlen / 8 * 2;
+ /* We return just the GPRs here. */
- ssize_t hex_reg_list_length = n_regs * reg_chars + 2;
- *hex_reg_list = malloc(hex_reg_list_length);
- *hex_reg_list[0] = '\0';
- char *p = hex_reg_list[0];
- for (size_t i = 0; i < n_regs; ++i) {
- assert(p - hex_reg_list[0] > 3);
- if (riscv_has_register(rtos->target, thread_id, i)) {
- uint64_t reg_value;
- int result = riscv_get_register_on_hart(rtos->target, ®_value,
- thread_id - 1, i);
- if (result != ERROR_OK)
- return JIM_ERR;
+ *num_regs = 32;
+ int xlen = riscv_xlen_of_hart(rtos->target, thread_id - 1);
- for (size_t byte = 0; byte < xlen / 8; ++byte) {
- uint8_t reg_byte = reg_value >> (byte * 8);
- p += snprintf(p, 3, "%02x", reg_byte);
- }
- } else {
- for (size_t byte = 0; byte < xlen / 8; ++byte) {
- strcpy(p, "xx");
- p += 2;
- }
- }
+ *reg_list = calloc(*num_regs, sizeof(struct rtos_reg));
+ *reg_list = 0;
+ for (int i = 0; i < *num_regs; ++i) {
+ uint64_t reg_value;
+ if (riscv_get_register_on_hart(rtos->target, ®_value, thread_id - 1,
+ i) != ERROR_OK)
+ return JIM_ERR;
+
+ (*reg_list)[i].number = i;
+ (*reg_list)[i].size = xlen;
+ (*reg_list)[i].value[0] = reg_value & 0xff;
+ (*reg_list)[i].value[1] = (reg_value >> 8) & 0xff;
+ (*reg_list)[i].value[2] = (reg_value >> 16) & 0xff;
+ (*reg_list)[i].value[3] = (reg_value >> 24) & 0xff;
+ (*reg_list)[i].value[4] = (reg_value >> 32) & 0xff;
+ (*reg_list)[i].value[5] = (reg_value >> 40) & 0xff;
+ (*reg_list)[i].value[6] = (reg_value >> 48) & 0xff;
+ (*reg_list)[i].value[7] = (reg_value >> 56) & 0xff;
}
- LOG_DEBUG("%s", *hex_reg_list);
return JIM_OK;
}
diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c
index bd9da0d2a..9b05ab5c4 100644
--- a/src/rtos/rtos.c
+++ b/src/rtos/rtos.c
@@ -438,6 +438,68 @@ int rtos_thread_packet(struct connection *connection, char const *packet, int pa
return GDB_THREAD_PACKET_NOT_CONSUMED;
}
+static int rtos_put_gdb_reg_list(struct connection *connection,
+ struct rtos_reg *reg_list, int num_regs)
+{
+ size_t num_bytes = 1; /* NUL */
+ for (int i = 0; i < num_regs; ++i)
+ num_bytes += DIV_ROUND_UP(reg_list[i].size, 8) * 2;
+
+ char *hex = malloc(num_bytes);
+ char *hex_p = hex;
+
+ for (int i = 0; i < num_regs; ++i) {
+ size_t count = DIV_ROUND_UP(reg_list[i].size, 8);
+ size_t n = hexify(hex_p, reg_list[i].value, count, num_bytes);
+ hex_p += n;
+ num_bytes -= n;
+ }
+
+ gdb_put_packet(connection, hex, strlen(hex));
+ free(hex);
+
+ return ERROR_OK;
+}
+
+int rtos_get_gdb_reg(struct connection *connection, int reg_num)
+{
+ struct target *target = get_target_from_connection(connection);
+ int64_t current_threadid = target->rtos->current_threadid;
+ if ((target->rtos != NULL) && (current_threadid != -1) &&
+ (current_threadid != 0) &&
+ ((current_threadid != target->rtos->current_thread) ||
+ (target->smp))) { /* in smp several current thread are possible */
+ struct rtos_reg *reg_list;
+ int num_regs;
+
+ LOG_DEBUG("RTOS: getting register %d for thread 0x%" PRIx64
+ ", target->rtos->current_thread=0x%" PRIx64 "\r\n",
+ reg_num,
+ current_threadid,
+ target->rtos->current_thread);
+
+ int retval = target->rtos->type->get_thread_reg_list(target->rtos,
+ current_threadid,
+ ®_list,
+ &num_regs);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("RTOS: failed to get register list");
+ return retval;
+ }
+
+ for (int i = 0; i < num_regs; ++i) {
+ if (reg_list[i].number == (uint32_t)reg_num) {
+ rtos_put_gdb_reg_list(connection, reg_list + i, 1);
+ free(reg_list);
+ return ERROR_OK;
+ }
+ }
+
+ free(reg_list);
+ }
+ return ERROR_FAIL;
+}
+
int rtos_get_gdb_reg_list(struct connection *connection)
{
struct target *target = get_target_from_connection(connection);
@@ -446,7 +508,8 @@ int rtos_get_gdb_reg_list(struct connection *connection)
(current_threadid != 0) &&
((current_threadid != target->rtos->current_thread) ||
(target->smp))) { /* in smp several current thread are possible */
- char *hex_reg_list;
+ struct rtos_reg *reg_list;
+ int num_regs;
LOG_DEBUG("RTOS: getting register list for thread 0x%" PRIx64
", target->rtos->current_thread=0x%" PRIx64 "\r\n",
@@ -455,17 +518,17 @@ int rtos_get_gdb_reg_list(struct connection *connection)
int retval = target->rtos->type->get_thread_reg_list(target->rtos,
current_threadid,
- &hex_reg_list);
+ ®_list,
+ &num_regs);
if (retval != ERROR_OK) {
LOG_ERROR("RTOS: failed to get register list");
return retval;
}
- if (hex_reg_list != NULL) {
- gdb_put_packet(connection, hex_reg_list, strlen(hex_reg_list));
- free(hex_reg_list);
- return ERROR_OK;
- }
+ rtos_put_gdb_reg_list(connection, reg_list, num_regs);
+ free(reg_list);
+
+ return ERROR_OK;
}
return ERROR_FAIL;
}
@@ -473,12 +536,9 @@ int rtos_get_gdb_reg_list(struct connection *connection)
int rtos_generic_stack_read(struct target *target,
const struct rtos_register_stacking *stacking,
int64_t stack_ptr,
- char **hex_reg_list)
+ struct rtos_reg **reg_list,
+ int *num_regs)
{
- int list_size = 0;
- char *tmp_str_ptr;
- int64_t new_stack_ptr;
- int i;
int retval;
if (stack_ptr == 0) {
@@ -505,10 +565,8 @@ int rtos_generic_stack_read(struct target *target,
LOG_OUTPUT("%02X", stack_data[i]);
LOG_OUTPUT("\r\n");
#endif
- for (i = 0; i < stacking->num_output_registers; i++)
- list_size += stacking->register_offsets[i].width_bits/8;
- *hex_reg_list = malloc(list_size*2 + 1);
- tmp_str_ptr = *hex_reg_list;
+
+ int64_t new_stack_ptr;
if (stacking->calculate_process_stack != NULL) {
new_stack_ptr = stacking->calculate_process_stack(target,
stack_data, stacking, stack_ptr);
@@ -516,19 +574,21 @@ int rtos_generic_stack_read(struct target *target,
new_stack_ptr = stack_ptr - stacking->stack_growth_direction *
stacking->stack_registers_size;
}
- for (i = 0; i < stacking->num_output_registers; i++) {
- int j;
- for (j = 0; j < stacking->register_offsets[i].width_bits/8; j++) {
- if (stacking->register_offsets[i].offset == -1)
- tmp_str_ptr += sprintf(tmp_str_ptr, "%02x", 0);
- else if (stacking->register_offsets[i].offset == -2)
- tmp_str_ptr += sprintf(tmp_str_ptr, "%02x",
- ((uint8_t *)&new_stack_ptr)[j]);
- else
- tmp_str_ptr += sprintf(tmp_str_ptr, "%02x",
- stack_data[stacking->register_offsets[i].offset + j]);
- }
+
+ *reg_list = calloc(stacking->num_output_registers, sizeof(struct rtos_reg));
+ *num_regs = stacking->num_output_registers;
+
+ for (int i = 0; i < stacking->num_output_registers; ++i) {
+ (*reg_list)[i].number = stacking->register_offsets[i].number;
+ (*reg_list)[i].size = stacking->register_offsets[i].width_bits;
+
+ int offset = stacking->register_offsets[i].offset;
+ if (offset == -2)
+ buf_cpy(&new_stack_ptr, (*reg_list)[i].value, (*reg_list)[i].size);
+ else if (offset != -1)
+ buf_cpy(stack_data + offset, (*reg_list)[i].value, (*reg_list)[i].size);
}
+
free(stack_data);
/* LOG_OUTPUT("Output register string: %s\r\n", *hex_reg_list); */
return ERROR_OK;
diff --git a/src/rtos/rtos.h b/src/rtos/rtos.h
index c9ac1e555..22de33fe2 100644
--- a/src/rtos/rtos.h
+++ b/src/rtos/rtos.h
@@ -59,19 +59,27 @@ struct rtos {
void *rtos_specific_params;
};
+struct rtos_reg {
+ uint32_t number;
+ uint32_t size;
+ uint8_t value[8];
+};
+
struct rtos_type {
const char *name;
bool (*detect_rtos)(struct target *target);
int (*create)(struct target *target);
int (*smp_init)(struct target *target);
int (*update_threads)(struct rtos *rtos);
- int (*get_thread_reg_list)(struct rtos *rtos, int64_t thread_id, char **hex_reg_list);
+ int (*get_thread_reg_list)(struct rtos *rtos, int64_t thread_id,
+ struct rtos_reg **reg_list, int *num_regs);
int (*get_symbol_list_to_lookup)(symbol_table_elem_t *symbol_list[]);
int (*clean)(struct target *target);
char * (*ps_command)(struct target *target);
};
struct stack_register_offset {
+ unsigned short number; /* register number */
signed short offset; /* offset in bytes from stack head, or -1 to indicate
* register is not stacked, or -2 to indicate this is the
* stack pointer register */
@@ -100,9 +108,11 @@ int rtos_create(Jim_GetOptInfo *goi, struct target *target);
int rtos_generic_stack_read(struct target *target,
const struct rtos_register_stacking *stacking,
int64_t stack_ptr,
- char **hex_reg_list);
+ struct rtos_reg **reg_list,
+ int *num_regs);
int rtos_try_next(struct target *target);
int gdb_thread_packet(struct connection *connection, char const *packet, int packet_size);
+int rtos_get_gdb_reg(struct connection *connection, int reg_num);
int rtos_get_gdb_reg_list(struct connection *connection);
int rtos_update_threads(struct target *target);
void rtos_free_threadlist(struct rtos *rtos);
diff --git a/src/rtos/rtos_chibios_stackings.c b/src/rtos/rtos_chibios_stackings.c
index 3651c49a9..2887930bd 100644
--- a/src/rtos/rtos_chibios_stackings.c
+++ b/src/rtos/rtos_chibios_stackings.c
@@ -27,23 +27,23 @@
#include "target/armv7m.h"
static const struct stack_register_offset rtos_chibios_arm_v7m_stack_offsets[ARMV7M_NUM_CORE_REGS] = {
- { -1, 32 }, /* r0 */
- { -1, 32 }, /* r1 */
- { -1, 32 }, /* r2 */
- { -1, 32 }, /* r3 */
- { 0x00, 32 }, /* r4 */
- { 0x04, 32 }, /* r5 */
- { 0x08, 32 }, /* r6 */
- { 0x0c, 32 }, /* r7 */
- { 0x10, 32 }, /* r8 */
- { 0x14, 32 }, /* r9 */
- { 0x18, 32 }, /* r10 */
- { 0x1c, 32 }, /* r11 */
- { -1, 32 }, /* r12 */
- { -2, 32 }, /* sp */
- { -1, 32 }, /* lr */
- { 0x20, 32 }, /* pc */
- { -1, 32 }, /* xPSR */
+ { ARMV7M_R0, -1, 32 }, /* r0 */
+ { ARMV7M_R1, -1, 32 }, /* r1 */
+ { ARMV7M_R2, -1, 32 }, /* r2 */
+ { ARMV7M_R3, -1, 32 }, /* r3 */
+ { ARMV7M_R4, 0x00, 32 }, /* r4 */
+ { ARMV7M_R5, 0x04, 32 }, /* r5 */
+ { ARMV7M_R6, 0x08, 32 }, /* r6 */
+ { ARMV7M_R7, 0x0c, 32 }, /* r7 */
+ { ARMV7M_R8, 0x10, 32 }, /* r8 */
+ { ARMV7M_R9, 0x14, 32 }, /* r9 */
+ { ARMV7M_R10, 0x18, 32 }, /* r10 */
+ { ARMV7M_R11, 0x1c, 32 }, /* r11 */
+ { ARMV7M_R12, -1, 32 }, /* r12 */
+ { ARMV7M_R13, -2, 32 }, /* sp */
+ { ARMV7M_R14, -1, 32 }, /* lr */
+ { ARMV7M_PC, 0x20, 32 }, /* pc */
+ { ARMV7M_xPSR, -1, 32 }, /* xPSR */
};
const struct rtos_register_stacking rtos_chibios_arm_v7m_stacking = {
@@ -55,23 +55,23 @@ const struct rtos_register_stacking rtos_chibios_arm_v7m_stacking = {
};
static const struct stack_register_offset rtos_chibios_arm_v7m_stack_offsets_w_fpu[ARMV7M_NUM_CORE_REGS] = {
- { -1, 32 }, /* r0 */
- { -1, 32 }, /* r1 */
- { -1, 32 }, /* r2 */
- { -1, 32 }, /* r3 */
- { 0x40, 32 }, /* r4 */
- { 0x44, 32 }, /* r5 */
- { 0x48, 32 }, /* r6 */
- { 0x4c, 32 }, /* r7 */
- { 0x50, 32 }, /* r8 */
- { 0x54, 32 }, /* r9 */
- { 0x58, 32 }, /* r10 */
- { 0x5c, 32 }, /* r11 */
- { -1, 32 }, /* r12 */
- { -2, 32 }, /* sp */
- { -1, 32 }, /* lr */
- { 0x60, 32 }, /* pc */
- { -1, 32 }, /* xPSR */
+ { ARMV7M_R0, -1, 32 }, /* r0 */
+ { ARMV7M_R1, -1, 32 }, /* r1 */
+ { ARMV7M_R2, -1, 32 }, /* r2 */
+ { ARMV7M_R3, -1, 32 }, /* r3 */
+ { ARMV7M_R4, 0x40, 32 }, /* r4 */
+ { ARMV7M_R5, 0x44, 32 }, /* r5 */
+ { ARMV7M_R6, 0x48, 32 }, /* r6 */
+ { ARMV7M_R7, 0x4c, 32 }, /* r7 */
+ { ARMV7M_R8, 0x50, 32 }, /* r8 */
+ { ARMV7M_R9, 0x54, 32 }, /* r9 */
+ { ARMV7M_R10, 0x58, 32 }, /* r10 */
+ { ARMV7M_R11, 0x5c, 32 }, /* r11 */
+ { ARMV7M_R12, -1, 32 }, /* r12 */
+ { ARMV7M_R13, -2, 32 }, /* sp */
+ { ARMV7M_R14, -1, 32 }, /* lr */
+ { ARMV7M_PC, 0x60, 32 }, /* pc */
+ { ARMV7M_xPSR, -1, 32 }, /* xPSR */
};
const struct rtos_register_stacking rtos_chibios_arm_v7m_stacking_w_fpu = {
diff --git a/src/rtos/rtos_ecos_stackings.c b/src/rtos/rtos_ecos_stackings.c
index 43d97a605..ca98d9417 100644
--- a/src/rtos/rtos_ecos_stackings.c
+++ b/src/rtos/rtos_ecos_stackings.c
@@ -23,23 +23,23 @@
#include "target/armv7m.h"
static const struct stack_register_offset rtos_eCos_Cortex_M3_stack_offsets[ARMV7M_NUM_CORE_REGS] = {
- { 0x0c, 32 }, /* r0 */
- { 0x10, 32 }, /* r1 */
- { 0x14, 32 }, /* r2 */
- { 0x18, 32 }, /* r3 */
- { 0x1c, 32 }, /* r4 */
- { 0x20, 32 }, /* r5 */
- { 0x24, 32 }, /* r6 */
- { 0x28, 32 }, /* r7 */
- { 0x2c, 32 }, /* r8 */
- { 0x30, 32 }, /* r9 */
- { 0x34, 32 }, /* r10 */
- { 0x38, 32 }, /* r11 */
- { 0x3c, 32 }, /* r12 */
- { -2, 32 }, /* sp */
- { -1, 32 }, /* lr */
- { 0x40, 32 }, /* pc */
- { -1, 32 }, /* xPSR */
+ { ARMV7M_R0, 0x0c, 32 }, /* r0 */
+ { ARMV7M_R1, 0x10, 32 }, /* r1 */
+ { ARMV7M_R2, 0x14, 32 }, /* r2 */
+ { ARMV7M_R3, 0x18, 32 }, /* r3 */
+ { ARMV7M_R4, 0x1c, 32 }, /* r4 */
+ { ARMV7M_R5, 0x20, 32 }, /* r5 */
+ { ARMV7M_R6, 0x24, 32 }, /* r6 */
+ { ARMV7M_R7, 0x28, 32 }, /* r7 */
+ { ARMV7M_R8, 0x2c, 32 }, /* r8 */
+ { ARMV7M_R9, 0x30, 32 }, /* r9 */
+ { ARMV7M_R10, 0x34, 32 }, /* r10 */
+ { ARMV7M_R11, 0x38, 32 }, /* r11 */
+ { ARMV7M_R12, 0x3c, 32 }, /* r12 */
+ { ARMV7M_R13, -2, 32 }, /* sp */
+ { ARMV7M_R14, -1, 32 }, /* lr */
+ { ARMV7M_PC, 0x40, 32 }, /* pc */
+ { ARMV7M_xPSR, -1, 32 }, /* xPSR */
};
const struct rtos_register_stacking rtos_eCos_Cortex_M3_stacking = {
diff --git a/src/rtos/rtos_embkernel_stackings.c b/src/rtos/rtos_embkernel_stackings.c
index 2a3062955..4ee79af93 100644
--- a/src/rtos/rtos_embkernel_stackings.c
+++ b/src/rtos/rtos_embkernel_stackings.c
@@ -25,23 +25,23 @@
#include "rtos_standard_stackings.h"
static const struct stack_register_offset rtos_embkernel_Cortex_M_stack_offsets[ARMV7M_NUM_CORE_REGS] = {
- { 0x24, 32 }, /* r0 */
- { 0x28, 32 }, /* r1 */
- { 0x2c, 32 }, /* r2 */
- { 0x30, 32 }, /* r3 */
- { 0x00, 32 }, /* r4 */
- { 0x04, 32 }, /* r5 */
- { 0x08, 32 }, /* r6 */
- { 0x0c, 32 }, /* r7 */
- { 0x10, 32 }, /* r8 */
- { 0x14, 32 }, /* r9 */
- { 0x18, 32 }, /* r10 */
- { 0x1c, 32 }, /* r11 */
- { 0x34, 32 }, /* r12 */
- { -2, 32 }, /* sp */
- { 0x38, 32 }, /* lr */
- { 0x3c, 32 }, /* pc */
- { 0x40, 32 }, /* xPSR */
+ { ARMV7M_R0, 0x24, 32 }, /* r0 */
+ { ARMV7M_R1, 0x28, 32 }, /* r1 */
+ { ARMV7M_R2, 0x2c, 32 }, /* r2 */
+ { ARMV7M_R3, 0x30, 32 }, /* r3 */
+ { ARMV7M_R4, 0x00, 32 }, /* r4 */
+ { ARMV7M_R5, 0x04, 32 }, /* r5 */
+ { ARMV7M_R6, 0x08, 32 }, /* r6 */
+ { ARMV7M_R7, 0x0c, 32 }, /* r7 */
+ { ARMV7M_R8, 0x10, 32 }, /* r8 */
+ { ARMV7M_R9, 0x14, 32 }, /* r9 */
+ { ARMV7M_R10, 0x18, 32 }, /* r10 */
+ { ARMV7M_R11, 0x1c, 32 }, /* r11 */
+ { ARMV7M_R12, 0x34, 32 }, /* r12 */
+ { ARMV7M_R13, -2, 32 }, /* sp */
+ { ARMV7M_R14, 0x38, 32 }, /* lr */
+ { ARMV7M_PC, 0x3c, 32 }, /* pc */
+ { ARMV7M_xPSR, 0x40, 32 }, /* xPSR */
};
const struct rtos_register_stacking rtos_embkernel_Cortex_M_stacking = {
diff --git a/src/rtos/rtos_mqx_stackings.c b/src/rtos/rtos_mqx_stackings.c
index 5db2f8ec3..1a8bdfcc7 100644
--- a/src/rtos/rtos_mqx_stackings.c
+++ b/src/rtos/rtos_mqx_stackings.c
@@ -51,23 +51,23 @@
*/
static const struct stack_register_offset rtos_mqx_arm_v7m_stack_offsets[ARMV7M_NUM_CORE_REGS] = {
- { 0x2C, 32 }, /* r0 */
- { 0x30, 32 }, /* r1 */
- { 0x34, 32 }, /* r2 */
- { 0x38, 32 }, /* r3 */
- { 0x08, 32 }, /* r4 */
- { 0x0C, 32 }, /* r5 */
- { 0x10, 32 }, /* r6 */
- { 0x14, 32 }, /* r7 */
- { 0x18, 32 }, /* r8 */
- { 0x1C, 32 }, /* r9 */
- { 0x20, 32 }, /* r10 */
- { 0x24, 32 }, /* r11 */
- { 0x3C, 32 }, /* r12 */
- { -2 , 32 }, /* sp */
- { 0x28, 32 }, /* lr */
- { 0x44, 32 }, /* pc */
- { 0x48, 32 }, /* xPSR */
+ { ARMV7M_R0, 0x2C, 32 }, /* r0 */
+ { ARMV7M_R1, 0x30, 32 }, /* r1 */
+ { ARMV7M_R2, 0x34, 32 }, /* r2 */
+ { ARMV7M_R3, 0x38, 32 }, /* r3 */
+ { ARMV7M_R4, 0x08, 32 }, /* r4 */
+ { ARMV7M_R5, 0x0C, 32 }, /* r5 */
+ { ARMV7M_R6, 0x10, 32 }, /* r6 */
+ { ARMV7M_R7, 0x14, 32 }, /* r7 */
+ { ARMV7M_R8, 0x18, 32 }, /* r8 */
+ { ARMV7M_R9, 0x1C, 32 }, /* r9 */
+ { ARMV7M_R10, 0x20, 32 }, /* r10 */
+ { ARMV7M_R11, 0x24, 32 }, /* r11 */
+ { ARMV7M_R12, 0x3C, 32 }, /* r12 */
+ { ARMV7M_R13, -2 , 32 }, /* sp */
+ { ARMV7M_R14, 0x28, 32 }, /* lr */
+ { ARMV7M_PC, 0x44, 32 }, /* pc */
+ { ARMV7M_xPSR, 0x48, 32 }, /* xPSR */
};
const struct rtos_register_stacking rtos_mqx_arm_v7m_stacking = {
diff --git a/src/rtos/rtos_standard_stackings.c b/src/rtos/rtos_standard_stackings.c
index 931cfc7ed..7b054cbbc 100644
--- a/src/rtos/rtos_standard_stackings.c
+++ b/src/rtos/rtos_standard_stackings.c
@@ -24,132 +24,132 @@
#include "target/armv7m.h"
static const struct stack_register_offset rtos_standard_Cortex_M3_stack_offsets[ARMV7M_NUM_CORE_REGS] = {
- { 0x20, 32 }, /* r0 */
- { 0x24, 32 }, /* r1 */
- { 0x28, 32 }, /* r2 */
- { 0x2c, 32 }, /* r3 */
- { 0x00, 32 }, /* r4 */
- { 0x04, 32 }, /* r5 */
- { 0x08, 32 }, /* r6 */
- { 0x0c, 32 }, /* r7 */
- { 0x10, 32 }, /* r8 */
- { 0x14, 32 }, /* r9 */
- { 0x18, 32 }, /* r10 */
- { 0x1c, 32 }, /* r11 */
- { 0x30, 32 }, /* r12 */
- { -2, 32 }, /* sp */
- { 0x34, 32 }, /* lr */
- { 0x38, 32 }, /* pc */
- { 0x3c, 32 }, /* xPSR */
+ { ARMV7M_R0, 0x20, 32 }, /* r0 */
+ { ARMV7M_R1, 0x24, 32 }, /* r1 */
+ { ARMV7M_R2, 0x28, 32 }, /* r2 */
+ { ARMV7M_R3, 0x2c, 32 }, /* r3 */
+ { ARMV7M_R4, 0x00, 32 }, /* r4 */
+ { ARMV7M_R5, 0x04, 32 }, /* r5 */
+ { ARMV7M_R6, 0x08, 32 }, /* r6 */
+ { ARMV7M_R7, 0x0c, 32 }, /* r7 */
+ { ARMV7M_R8, 0x10, 32 }, /* r8 */
+ { ARMV7M_R9, 0x14, 32 }, /* r9 */
+ { ARMV7M_R10, 0x18, 32 }, /* r10 */
+ { ARMV7M_R11, 0x1c, 32 }, /* r11 */
+ { ARMV7M_R12, 0x30, 32 }, /* r12 */
+ { ARMV7M_R13, -2, 32 }, /* sp */
+ { ARMV7M_R14, 0x34, 32 }, /* lr */
+ { ARMV7M_PC, 0x38, 32 }, /* pc */
+ { ARMV7M_xPSR, 0x3c, 32 }, /* xPSR */
};
static const struct stack_register_offset rtos_standard_Cortex_M4F_stack_offsets[] = {
- { 0x24, 32 }, /* r0 */
- { 0x28, 32 }, /* r1 */
- { 0x2c, 32 }, /* r2 */
- { 0x30, 32 }, /* r3 */
- { 0x00, 32 }, /* r4 */
- { 0x04, 32 }, /* r5 */
- { 0x08, 32 }, /* r6 */
- { 0x0c, 32 }, /* r7 */
- { 0x10, 32 }, /* r8 */
- { 0x14, 32 }, /* r9 */
- { 0x18, 32 }, /* r10 */
- { 0x1c, 32 }, /* r11 */
- { 0x34, 32 }, /* r12 */
- { -2, 32 }, /* sp */
- { 0x38, 32 }, /* lr */
- { 0x3c, 32 }, /* pc */
- { 0x40, 32 }, /* xPSR */
+ { ARMV7M_R0, 0x24, 32 }, /* r0 */
+ { ARMV7M_R1, 0x28, 32 }, /* r1 */
+ { ARMV7M_R2, 0x2c, 32 }, /* r2 */
+ { ARMV7M_R3, 0x30, 32 }, /* r3 */
+ { ARMV7M_R4, 0x00, 32 }, /* r4 */
+ { ARMV7M_R5, 0x04, 32 }, /* r5 */
+ { ARMV7M_R6, 0x08, 32 }, /* r6 */
+ { ARMV7M_R7, 0x0c, 32 }, /* r7 */
+ { ARMV7M_R8, 0x10, 32 }, /* r8 */
+ { ARMV7M_R9, 0x14, 32 }, /* r9 */
+ { ARMV7M_R10, 0x18, 32 }, /* r10 */
+ { ARMV7M_R11, 0x1c, 32 }, /* r11 */
+ { ARMV7M_R12, 0x34, 32 }, /* r12 */
+ { ARMV7M_R13, -2, 32 }, /* sp */
+ { ARMV7M_R14, 0x38, 32 }, /* lr */
+ { ARMV7M_PC, 0x3c, 32 }, /* pc */
+ { ARMV7M_xPSR, 0x40, 32 }, /* xPSR */
};
static const struct stack_register_offset rtos_standard_Cortex_M4F_FPU_stack_offsets[] = {
- { 0x64, 32 }, /* r0 */
- { 0x68, 32 }, /* r1 */
- { 0x6c, 32 }, /* r2 */
- { 0x70, 32 }, /* r3 */
- { 0x00, 32 }, /* r4 */
- { 0x04, 32 }, /* r5 */
- { 0x08, 32 }, /* r6 */
- { 0x0c, 32 }, /* r7 */
- { 0x10, 32 }, /* r8 */
- { 0x14, 32 }, /* r9 */
- { 0x18, 32 }, /* r10 */
- { 0x1c, 32 }, /* r11 */
- { 0x74, 32 }, /* r12 */
- { -2, 32 }, /* sp */
- { 0x78, 32 }, /* lr */
- { 0x7c, 32 }, /* pc */
- { 0x80, 32 }, /* xPSR */
+ { ARMV7M_R0, 0x64, 32 }, /* r0 */
+ { ARMV7M_R1, 0x68, 32 }, /* r1 */
+ { ARMV7M_R2, 0x6c, 32 }, /* r2 */
+ { ARMV7M_R3, 0x70, 32 }, /* r3 */
+ { ARMV7M_R4, 0x00, 32 }, /* r4 */
+ { ARMV7M_R5, 0x04, 32 }, /* r5 */
+ { ARMV7M_R6, 0x08, 32 }, /* r6 */
+ { ARMV7M_R7, 0x0c, 32 }, /* r7 */
+ { ARMV7M_R8, 0x10, 32 }, /* r8 */
+ { ARMV7M_R9, 0x14, 32 }, /* r9 */
+ { ARMV7M_R10, 0x18, 32 }, /* r10 */
+ { ARMV7M_R11, 0x1c, 32 }, /* r11 */
+ { ARMV7M_R12, 0x74, 32 }, /* r12 */
+ { ARMV7M_R13, -2, 32 }, /* sp */
+ { ARMV7M_R14, 0x78, 32 }, /* lr */
+ { ARMV7M_PC, 0x7c, 32 }, /* pc */
+ { ARMV7M_xPSR, 0x80, 32 }, /* xPSR */
};
static const struct stack_register_offset rtos_standard_Cortex_R4_stack_offsets[] = {
- { 0x08, 32 }, /* r0 (a1) */
- { 0x0c, 32 }, /* r1 (a2) */
- { 0x10, 32 }, /* r2 (a3) */
- { 0x14, 32 }, /* r3 (a4) */
- { 0x18, 32 }, /* r4 (v1) */
- { 0x1c, 32 }, /* r5 (v2) */
- { 0x20, 32 }, /* r6 (v3) */
- { 0x24, 32 }, /* r7 (v4) */
- { 0x28, 32 }, /* r8 (a1) */
- { 0x2c, 32 }, /* r9 (sb) */
- { 0x30, 32 }, /* r10 (sl) */
- { 0x34, 32 }, /* r11 (fp) */
- { 0x38, 32 }, /* r12 (ip) */
- { -2, 32 }, /* sp */
- { 0x3c, 32 }, /* lr */
- { 0x40, 32 }, /* pc */
- { -1, 96 }, /* FPA1 */
- { -1, 96 }, /* FPA2 */
- { -1, 96 }, /* FPA3 */
- { -1, 96 }, /* FPA4 */
- { -1, 96 }, /* FPA5 */
- { -1, 96 }, /* FPA6 */
- { -1, 96 }, /* FPA7 */
- { -1, 96 }, /* FPA8 */
- { -1, 32 }, /* FPS */
- { 0x04, 32 }, /* CSPR */
+ { 0, 0x08, 32 }, /* r0 (a1) */
+ { 1, 0x0c, 32 }, /* r1 (a2) */
+ { 2, 0x10, 32 }, /* r2 (a3) */
+ { 3, 0x14, 32 }, /* r3 (a4) */
+ { 4, 0x18, 32 }, /* r4 (v1) */
+ { 5, 0x1c, 32 }, /* r5 (v2) */
+ { 6, 0x20, 32 }, /* r6 (v3) */
+ { 7, 0x24, 32 }, /* r7 (v4) */
+ { 8, 0x28, 32 }, /* r8 (a1) */
+ { 10, 0x2c, 32 }, /* r9 (sb) */
+ { 11, 0x30, 32 }, /* r10 (sl) */
+ { 12, 0x34, 32 }, /* r11 (fp) */
+ { 13, 0x38, 32 }, /* r12 (ip) */
+ { 14, -2, 32 }, /* sp */
+ { 15, 0x3c, 32 }, /* lr */
+ { 16, 0x40, 32 }, /* pc */
+ { 17, -1, 96 }, /* FPA1 */
+ { 18, -1, 96 }, /* FPA2 */
+ { 19, -1, 96 }, /* FPA3 */
+ { 20, -1, 96 }, /* FPA4 */
+ { 21, -1, 96 }, /* FPA5 */
+ { 22, -1, 96 }, /* FPA6 */
+ { 23, -1, 96 }, /* FPA7 */
+ { 24, -1, 96 }, /* FPA8 */
+ { 25, -1, 32 }, /* FPS */
+ { 26, 0x04, 32 }, /* CSPR */
};
static const struct stack_register_offset rtos_standard_NDS32_N1068_stack_offsets[] = {
- { 0x88, 32 }, /* R0 */
- { 0x8C, 32 }, /* R1 */
- { 0x14, 32 }, /* R2 */
- { 0x18, 32 }, /* R3 */
- { 0x1C, 32 }, /* R4 */
- { 0x20, 32 }, /* R5 */
- { 0x24, 32 }, /* R6 */
- { 0x28, 32 }, /* R7 */
- { 0x2C, 32 }, /* R8 */
- { 0x30, 32 }, /* R9 */
- { 0x34, 32 }, /* R10 */
- { 0x38, 32 }, /* R11 */
- { 0x3C, 32 }, /* R12 */
- { 0x40, 32 }, /* R13 */
- { 0x44, 32 }, /* R14 */
- { 0x48, 32 }, /* R15 */
- { 0x4C, 32 }, /* R16 */
- { 0x50, 32 }, /* R17 */
- { 0x54, 32 }, /* R18 */
- { 0x58, 32 }, /* R19 */
- { 0x5C, 32 }, /* R20 */
- { 0x60, 32 }, /* R21 */
- { 0x64, 32 }, /* R22 */
- { 0x68, 32 }, /* R23 */
- { 0x6C, 32 }, /* R24 */
- { 0x70, 32 }, /* R25 */
- { 0x74, 32 }, /* R26 */
- { 0x78, 32 }, /* R27 */
- { 0x7C, 32 }, /* R28 */
- { 0x80, 32 }, /* R29 */
- { 0x84, 32 }, /* R30 (LP) */
- { 0x00, 32 }, /* R31 (SP) */
- { 0x04, 32 }, /* PSW */
- { 0x08, 32 }, /* IPC */
- { 0x0C, 32 }, /* IPSW */
- { 0x10, 32 }, /* IFC_LP */
+ { 0, 0x88, 32 }, /* R0 */
+ { 1, 0x8C, 32 }, /* R1 */
+ { 2, 0x14, 32 }, /* R2 */
+ { 3, 0x18, 32 }, /* R3 */
+ { 4, 0x1C, 32 }, /* R4 */
+ { 5, 0x20, 32 }, /* R5 */
+ { 6, 0x24, 32 }, /* R6 */
+ { 7, 0x28, 32 }, /* R7 */
+ { 8, 0x2C, 32 }, /* R8 */
+ { 9, 0x30, 32 }, /* R9 */
+ { 10, 0x34, 32 }, /* R10 */
+ { 11, 0x38, 32 }, /* R11 */
+ { 12, 0x3C, 32 }, /* R12 */
+ { 13, 0x40, 32 }, /* R13 */
+ { 14, 0x44, 32 }, /* R14 */
+ { 15, 0x48, 32 }, /* R15 */
+ { 16, 0x4C, 32 }, /* R16 */
+ { 17, 0x50, 32 }, /* R17 */
+ { 18, 0x54, 32 }, /* R18 */
+ { 19, 0x58, 32 }, /* R19 */
+ { 20, 0x5C, 32 }, /* R20 */
+ { 21, 0x60, 32 }, /* R21 */
+ { 22, 0x64, 32 }, /* R22 */
+ { 23, 0x68, 32 }, /* R23 */
+ { 24, 0x6C, 32 }, /* R24 */
+ { 25, 0x70, 32 }, /* R25 */
+ { 26, 0x74, 32 }, /* R26 */
+ { 27, 0x78, 32 }, /* R27 */
+ { 28, 0x7C, 32 }, /* R28 */
+ { 29, 0x80, 32 }, /* R29 */
+ { 30, 0x84, 32 }, /* R30 (LP) */
+ { 31, 0x00, 32 }, /* R31 (SP) */
+ { 32, 0x04, 32 }, /* PSW */
+ { 33, 0x08, 32 }, /* IPC */
+ { 34, 0x0C, 32 }, /* IPSW */
+ { 35, 0x10, 32 }, /* IFC_LP */
};
static int64_t rtos_generic_stack_align(struct target *target,
diff --git a/src/rtos/rtos_ucos_iii_stackings.c b/src/rtos/rtos_ucos_iii_stackings.c
index c260b7f80..d093563ba 100644
--- a/src/rtos/rtos_ucos_iii_stackings.c
+++ b/src/rtos/rtos_ucos_iii_stackings.c
@@ -24,25 +24,47 @@
#include
#include
#include
+#include
static const struct stack_register_offset rtos_uCOS_III_Cortex_M_stack_offsets[] = {
- { 0x20, 32 }, /* r0 */
- { 0x24, 32 }, /* r1 */
- { 0x28, 32 }, /* r2 */
- { 0x2c, 32 }, /* r3 */
- { 0x00, 32 }, /* r4 */
- { 0x04, 32 }, /* r5 */
- { 0x08, 32 }, /* r6 */
- { 0x0c, 32 }, /* r7 */
- { 0x10, 32 }, /* r8 */
- { 0x14, 32 }, /* r9 */
- { 0x18, 32 }, /* r10 */
- { 0x1c, 32 }, /* r11 */
- { 0x30, 32 }, /* r12 */
- { -2, 32 }, /* sp */
- { 0x34, 32 }, /* lr */
- { 0x38, 32 }, /* pc */
- { 0x3c, 32 }, /* xPSR */
+ { ARMV7M_R0, 0x20, 32 }, /* r0 */
+ { ARMV7M_R1, 0x24, 32 }, /* r1 */
+ { ARMV7M_R2, 0x28, 32 }, /* r2 */
+ { ARMV7M_R3, 0x2c, 32 }, /* r3 */
+ { ARMV7M_R4, 0x00, 32 }, /* r4 */
+ { ARMV7M_R5, 0x04, 32 }, /* r5 */
+ { ARMV7M_R6, 0x08, 32 }, /* r6 */
+ { ARMV7M_R7, 0x0c, 32 }, /* r7 */
+ { ARMV7M_R8, 0x10, 32 }, /* r8 */
+ { ARMV7M_R9, 0x14, 32 }, /* r9 */
+ { ARMV7M_R10, 0x18, 32 }, /* r10 */
+ { ARMV7M_R11, 0x1c, 32 }, /* r11 */
+ { ARMV7M_R12, 0x30, 32 }, /* r12 */
+ { ARMV7M_R13, -2, 32 }, /* sp */
+ { ARMV7M_R14, 0x34, 32 }, /* lr */
+ { ARMV7M_PC, 0x38, 32 }, /* pc */
+ { ARMV7M_xPSR, 0x3c, 32 }, /* xPSR */
+};
+
+static const struct stack_register_offset rtos_uCOS_III_eSi_RISC_stack_offsets[] = {
+ { ESIRISC_SP, -2, 32 }, /* sp */
+ { ESIRISC_RA, 0x48, 32 }, /* ra */
+ { ESIRISC_R2, 0x44, 32 }, /* r2 */
+ { ESIRISC_R3, 0x40, 32 }, /* r3 */
+ { ESIRISC_R4, 0x3c, 32 }, /* r4 */
+ { ESIRISC_R5, 0x38, 32 }, /* r5 */
+ { ESIRISC_R6, 0x34, 32 }, /* r6 */
+ { ESIRISC_R7, 0x30, 32 }, /* r7 */
+ { ESIRISC_R8, 0x2c, 32 }, /* r8 */
+ { ESIRISC_R9, 0x28, 32 }, /* r9 */
+ { ESIRISC_R10, 0x24, 32 }, /* r10 */
+ { ESIRISC_R11, 0x20, 32 }, /* r11 */
+ { ESIRISC_R12, 0x1c, 32 }, /* r12 */
+ { ESIRISC_R13, 0x18, 32 }, /* r13 */
+ { ESIRISC_R14, 0x14, 32 }, /* r14 */
+ { ESIRISC_R15, 0x10, 32 }, /* r15 */
+ { ESIRISC_PC, 0x04, 32 }, /* PC */
+ { ESIRISC_CAS, 0x08, 32 }, /* CAS */
};
const struct rtos_register_stacking rtos_uCOS_III_Cortex_M_stacking = {
@@ -52,3 +74,11 @@ const struct rtos_register_stacking rtos_uCOS_III_Cortex_M_stacking = {
rtos_generic_stack_align8, /* stack_alignment */
rtos_uCOS_III_Cortex_M_stack_offsets /* register_offsets */
};
+
+const struct rtos_register_stacking rtos_uCOS_III_eSi_RISC_stacking = {
+ 0x4c, /* stack_registers_size */
+ -1, /* stack_growth_direction */
+ ARRAY_SIZE(rtos_uCOS_III_eSi_RISC_stack_offsets), /* num_output_registers */
+ NULL, /* stack_alignment */
+ rtos_uCOS_III_eSi_RISC_stack_offsets /* register_offsets */
+};
diff --git a/src/rtos/rtos_ucos_iii_stackings.h b/src/rtos/rtos_ucos_iii_stackings.h
index f4703da37..a9398138b 100644
--- a/src/rtos/rtos_ucos_iii_stackings.h
+++ b/src/rtos/rtos_ucos_iii_stackings.h
@@ -26,5 +26,6 @@
#include
extern const struct rtos_register_stacking rtos_uCOS_III_Cortex_M_stacking;
+extern const struct rtos_register_stacking rtos_uCOS_III_eSi_RISC_stacking;
#endif /* OPENOCD_RTOS_RTOS_UCOS_III_STACKINGS_H */
diff --git a/src/rtos/uCOS-III.c b/src/rtos/uCOS-III.c
index 8e63ea4e6..304d07c59 100644
--- a/src/rtos/uCOS-III.c
+++ b/src/rtos/uCOS-III.c
@@ -68,6 +68,20 @@ static const struct uCOS_III_params uCOS_III_params_list[] = {
&rtos_uCOS_III_Cortex_M_stacking, /* stacking_info */
0, /* num_threads */
},
+ {
+ "esirisc", /* target_name */
+ sizeof(uint32_t), /* pointer_width */
+ 0, /* thread_stack_offset */
+ 0, /* thread_name_offset */
+ 0, /* thread_state_offset */
+ 0, /* thread_priority_offset */
+ 0, /* thread_prev_offset */
+ 0, /* thread_next_offset */
+ false, /* thread_offsets_updated */
+ 1, /* threadid_start */
+ &rtos_uCOS_III_eSi_RISC_stacking, /* stacking_info */
+ 0, /* num_threads */
+ },
};
static const char * const uCOS_III_symbol_list[] = {
@@ -286,6 +300,11 @@ static int uCOS_III_update_threads(struct rtos *rtos)
struct uCOS_III_params *params = rtos->rtos_specific_params;
int retval;
+ if (rtos->symbols == NULL) {
+ LOG_ERROR("uCOS-III: symbol list not loaded");
+ return ERROR_FAIL;
+ }
+
/* free previous thread details */
rtos_free_threadlist(rtos);
@@ -454,7 +473,8 @@ static int uCOS_III_update_threads(struct rtos *rtos)
return ERROR_OK;
}
-static int uCOS_III_get_thread_reg_list(struct rtos *rtos, threadid_t threadid, char **hex_reg_list)
+static int uCOS_III_get_thread_reg_list(struct rtos *rtos, threadid_t threadid,
+ struct rtos_reg **reg_list, int *num_regs)
{
struct uCOS_III_params *params = rtos->rtos_specific_params;
int retval;
@@ -484,7 +504,8 @@ static int uCOS_III_get_thread_reg_list(struct rtos *rtos, threadid_t threadid,
return rtos_generic_stack_read(rtos->target,
params->stacking_info,
stack_address,
- hex_reg_list);
+ reg_list,
+ num_regs);
}
static int uCOS_III_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c
index 3ea324260..3548f166c 100644
--- a/src/server/gdb_server.c
+++ b/src/server/gdb_server.c
@@ -1179,8 +1179,11 @@ static int gdb_get_registers_packet(struct connection *connection,
if (retval != ERROR_OK)
return gdb_error(connection, retval);
- for (i = 0; i < reg_list_size; i++)
+ for (i = 0; i < reg_list_size; i++) {
+ if (reg_list[i] == NULL || reg_list[i]->exist == false)
+ continue;
reg_packet_size += DIV_ROUND_UP(reg_list[i]->size, 8) * 2;
+ }
assert(reg_packet_size > 0);
@@ -1191,6 +1194,8 @@ static int gdb_get_registers_packet(struct connection *connection,
reg_packet_p = reg_packet;
for (i = 0; i < reg_list_size; i++) {
+ if (reg_list[i] == NULL || reg_list[i]->exist == false)
+ continue;
if (!reg_list[i]->valid) {
retval = reg_list[i]->type->get(reg_list[i]);
if (retval != ERROR_OK && gdb_report_register_access_error) {
@@ -1296,6 +1301,9 @@ static int gdb_get_register_packet(struct connection *connection,
LOG_DEBUG("-");
#endif
+ if ((target->rtos != NULL) && (ERROR_OK == rtos_get_gdb_reg(connection, reg_num)))
+ return ERROR_OK;
+
retval = target_get_gdb_reg_list(target, ®_list, ®_list_size,
REG_CLASS_ALL);
if (retval != ERROR_OK)
@@ -2188,6 +2196,7 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o
int retval = ERROR_OK;
struct reg **reg_list = NULL;
int reg_list_size;
+ char const *architecture;
char const **features = NULL;
char const **arch_defined_types = NULL;
int feature_list_size = 0;
@@ -2229,6 +2238,12 @@ static int gdb_generate_target_description(struct target *target, char **tdesc_o
"\n"
"\n");
+ /* generate architecture element if supported by target */
+ architecture = target_get_gdb_arch(target);
+ if (architecture != NULL)
+ xml_printf(&retval, &tdesc, &pos, &size,
+ "%s\n", architecture);
+
/* generate target description according to register list */
if (features != NULL) {
while (features[current_feature]) {
@@ -2378,6 +2393,8 @@ static int gdb_target_description_supported(struct target *target, int *supporte
char const **features = NULL;
int feature_list_size = 0;
+ char const *architecture = target_get_gdb_arch(target);
+
retval = target_get_gdb_reg_list(target, ®_list,
®_list_size, REG_CLASS_ALL);
if (retval != ERROR_OK) {
@@ -2399,7 +2416,7 @@ static int gdb_target_description_supported(struct target *target, int *supporte
}
if (supported) {
- if (feature_list_size)
+ if (architecture || feature_list_size)
*supported = 1;
else
*supported = 0;
@@ -3377,6 +3394,8 @@ static int gdb_target_start(struct target *target, const char *port)
if (NULL == gdb_service)
return -ENOMEM;
+ LOG_DEBUG("starting gdb server for %s on %s", target_name(target), port);
+
gdb_service->target = target;
gdb_service->core[0] = -1;
gdb_service->core[1] = -1;
@@ -3402,16 +3421,36 @@ static int gdb_target_start(struct target *target, const char *port)
static int gdb_target_add_one(struct target *target)
{
+ /* one gdb instance per smp list */
+ if ((target->smp) && (target->gdb_service))
+ return ERROR_OK;
+
+ /* skip targets that cannot handle a gdb connections (e.g. mem_ap) */
+ if (!target_supports_gdb_connection(target)) {
+ LOG_DEBUG("skip gdb server for target %s", target_name(target));
+ return ERROR_OK;
+ }
+
+ if (target->gdb_port_override) {
+ if (strcmp(target->gdb_port_override, "disabled") == 0) {
+ LOG_INFO("gdb port disabled");
+ return ERROR_OK;
+ }
+ return gdb_target_start(target, target->gdb_port_override);
+ }
+
if (strcmp(gdb_port, "disabled") == 0) {
LOG_INFO("gdb port disabled");
return ERROR_OK;
}
- /* one gdb instance per smp list */
- if ((target->smp) && (target->gdb_service))
- return ERROR_OK;
int retval = gdb_target_start(target, gdb_port_next);
if (retval == ERROR_OK) {
+ /* save the port number so can be queried with
+ * $target_name cget -gdb-port
+ */
+ target->gdb_port_override = strdup(gdb_port_next);
+
long portnumber;
/* If we can parse the port number
* then we increment the port number for the next target.
@@ -3436,11 +3475,6 @@ static int gdb_target_add_one(struct target *target)
int gdb_target_add_all(struct target *target)
{
- if (strcmp(gdb_port, "disabled") == 0) {
- LOG_INFO("gdb server disabled");
- return ERROR_OK;
- }
-
if (NULL == target) {
LOG_WARNING("gdb services need one or more targets defined");
return ERROR_OK;
diff --git a/src/server/tcl_server.c b/src/server/tcl_server.c
index 3cb63a275..0676c883b 100644
--- a/src/server/tcl_server.c
+++ b/src/server/tcl_server.c
@@ -157,7 +157,7 @@ static int tcl_new_connection(struct connection *connection)
connection->priv = tclc;
- struct target *target = get_current_target(connection->cmd_ctx);
+ struct target *target = get_current_target_or_null(connection->cmd_ctx);
if (target != NULL)
tclc->tc_laststate = target->state;
diff --git a/src/target/Makefile.am b/src/target/Makefile.am
index b1119e7df..8e9fcb27e 100644
--- a/src/target/Makefile.am
+++ b/src/target/Makefile.am
@@ -23,6 +23,7 @@ noinst_LTLIBRARIES += %D%/libtarget.la
$(NDS32_SRC) \
$(STM8_SRC) \
$(INTEL_IA32_SRC) \
+ $(ESIRISC_SRC) \
%D%/avrt.c \
%D%/dsp563xx.c \
%D%/dsp563xx_once.c \
@@ -74,8 +75,10 @@ ARMV7_SRC = \
%D%/armv7m_trace.c \
%D%/cortex_m.c \
%D%/armv7a.c \
+ %D%/armv7a_mmu.c \
%D%/cortex_a.c \
- %D%/ls1_sap.c
+ %D%/ls1_sap.c \
+ %D%/mem_ap.c
ARMV8_SRC = \
%D%/armv8_dpm.c \
@@ -138,6 +141,10 @@ INTEL_IA32_SRC = \
%D%/lakemont.c \
%D%/x86_32_common.c
+ESIRISC_SRC = \
+ %D%/esirisc.c \
+ %D%/esirisc_jtag.c
+
%C%_libtarget_la_SOURCES += \
%D%/algorithm.h \
%D%/arm.h \
@@ -146,6 +153,7 @@ INTEL_IA32_SRC = \
%D%/arm_adi_v5.h \
%D%/armv7a_cache.h \
%D%/armv7a_cache_l2x.h \
+ %D%/armv7a_mmu.h \
%D%/arm_disassembler.h \
%D%/arm_opcodes.h \
%D%/arm_simulator.h \
@@ -217,7 +225,10 @@ INTEL_IA32_SRC = \
%D%/stm8.h \
%D%/lakemont.h \
%D%/x86_32_common.h \
- %D%/arm_cti.h
+ %D%/arm_cti.h \
+ %D%/esirisc.h \
+ %D%/esirisc_jtag.h \
+ %D%/esirisc_regs.h
include %D%/openrisc/Makefile.am
include %D%/riscv/Makefile.am
diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c
index 302ea7891..03e642bfe 100644
--- a/src/target/arm_adi_v5.c
+++ b/src/target/arm_adi_v5.c
@@ -652,6 +652,15 @@ int dap_dp_init(struct adiv5_dap *dap)
dap_invalidate_cache(dap);
+ /*
+ * Early initialize dap->dp_ctrl_stat.
+ * In jtag mode only, if the following atomic reads fail and set the
+ * sticky error, it will trigger the clearing of the sticky. Without this
+ * initialization system and debug power would be disabled while clearing
+ * the sticky error bit.
+ */
+ dap->dp_ctrl_stat = CDBGPWRUPREQ | CSYSPWRUPREQ;
+
for (size_t i = 0; i < 30; i++) {
/* DP initialization */
@@ -660,7 +669,18 @@ int dap_dp_init(struct adiv5_dap *dap)
break;
}
- retval = dap_queue_dp_write(dap, DP_CTRL_STAT, SSTICKYERR);
+ /*
+ * This write operation clears the sticky error bit in jtag mode only and
+ * is ignored in swd mode. It also powers-up system and debug domains in
+ * both jtag and swd modes, if not done before.
+ * Actually we do not need to clear the sticky error here because it has
+ * been already cleared (if it was set) in the previous atomic read. This
+ * write could be removed, but this initial part of dap_dp_init() is the
+ * result of years of fine tuning and there are strong concerns about any
+ * unnecessary code change. It doesn't harm, so let's keep it here and
+ * preserve the historical sequence of read/write operations!
+ */
+ retval = dap_queue_dp_write(dap, DP_CTRL_STAT, dap->dp_ctrl_stat | SSTICKYERR);
if (retval != ERROR_OK)
return retval;
@@ -668,7 +688,6 @@ int dap_dp_init(struct adiv5_dap *dap)
if (retval != ERROR_OK)
return retval;
- dap->dp_ctrl_stat = CDBGPWRUPREQ | CSYSPWRUPREQ;
retval = dap_queue_dp_write(dap, DP_CTRL_STAT, dap->dp_ctrl_stat);
if (retval != ERROR_OK)
return retval;
@@ -793,7 +812,7 @@ int dap_find_ap(struct adiv5_dap *dap, enum ap_type type_to_find, struct adiv5_a
int ap_num;
/* Maximum AP number is 255 since the SELECT register is 8 bits */
- for (ap_num = 0; ap_num <= 255; ap_num++) {
+ for (ap_num = 0; ap_num <= DP_APSEL_MAX; ap_num++) {
/* read the IDR register of the Access Port */
uint32_t id_val = 0;
@@ -1429,7 +1448,7 @@ int adiv5_jim_configure(struct target *target, Jim_GetOptInfo *goi)
pc = (struct adiv5_private_config *)target->private_config;
if (pc == NULL) {
pc = calloc(1, sizeof(struct adiv5_private_config));
- pc->ap_num = -1;
+ pc->ap_num = DP_APSEL_INVALID;
target->private_config = pc;
}
@@ -1498,6 +1517,10 @@ int adiv5_jim_configure(struct target *target, Jim_GetOptInfo *goi)
e = Jim_GetOpt_Wide(goi, &ap_num);
if (e != JIM_OK)
return e;
+ if (ap_num < 0 || ap_num > DP_APSEL_MAX) {
+ Jim_SetResultString(goi->interp, "Invalid AP number!", -1);
+ return JIM_ERR;
+ }
pc->ap_num = ap_num;
} else {
if (goi->argc != 0) {
@@ -1507,11 +1530,11 @@ int adiv5_jim_configure(struct target *target, Jim_GetOptInfo *goi)
return JIM_ERR;
}
- if (pc->ap_num < 0) {
+ if (pc->ap_num == DP_APSEL_INVALID) {
Jim_SetResultString(goi->interp, "AP number not configured", -1);
return JIM_ERR;
}
- Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, (int)pc->ap_num));
+ Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, pc->ap_num));
}
break;
}
@@ -1543,7 +1566,7 @@ COMMAND_HANDLER(handle_dap_info_command)
break;
case 1:
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel);
- if (apsel >= 256)
+ if (apsel > DP_APSEL_MAX)
return ERROR_COMMAND_SYNTAX_ERROR;
break;
default:
@@ -1566,7 +1589,7 @@ COMMAND_HANDLER(dap_baseaddr_command)
case 1:
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel);
/* AP address is in bits 31:24 of DP_SELECT */
- if (apsel >= 256)
+ if (apsel > DP_APSEL_MAX)
return ERROR_COMMAND_SYNTAX_ERROR;
break;
default:
@@ -1625,7 +1648,7 @@ COMMAND_HANDLER(dap_apsel_command)
case 1:
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel);
/* AP address is in bits 31:24 of DP_SELECT */
- if (apsel >= 256)
+ if (apsel > DP_APSEL_MAX)
return ERROR_COMMAND_SYNTAX_ERROR;
break;
default:
@@ -1691,7 +1714,7 @@ COMMAND_HANDLER(dap_apid_command)
case 1:
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel);
/* AP address is in bits 31:24 of DP_SELECT */
- if (apsel >= 256)
+ if (apsel > DP_APSEL_MAX)
return ERROR_COMMAND_SYNTAX_ERROR;
break;
default:
@@ -1722,7 +1745,7 @@ COMMAND_HANDLER(dap_apreg_command)
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel);
/* AP address is in bits 31:24 of DP_SELECT */
- if (apsel >= 256)
+ if (apsel > DP_APSEL_MAX)
return ERROR_COMMAND_SYNTAX_ERROR;
ap = dap_ap(dap, apsel);
@@ -1734,8 +1757,10 @@ COMMAND_HANDLER(dap_apreg_command)
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], value);
switch (reg) {
case MEM_AP_REG_CSW:
- ap->csw_default = 0; /* invalid, force write */
- retval = mem_ap_setup_csw(ap, value);
+ ap->csw_value = 0; /* invalid, in case write fails */
+ retval = dap_queue_ap_write(ap, reg, value);
+ if (retval == ERROR_OK)
+ ap->csw_value = value;
break;
case MEM_AP_REG_TAR:
ap->tar_valid = false; /* invalid, force write */
diff --git a/src/target/arm_adi_v5.h b/src/target/arm_adi_v5.h
index 883ac8b5d..a340b76f0 100644
--- a/src/target/arm_adi_v5.h
+++ b/src/target/arm_adi_v5.h
@@ -136,6 +136,9 @@
#define DP_SELECT_DPBANK 0x0000000F
#define DP_SELECT_INVALID 0x00FFFF00 /* Reserved bits one */
+#define DP_APSEL_MAX (255)
+#define DP_APSEL_INVALID (-1)
+
/**
* This represents an ARM Debug Interface (v5) Access Port (AP).
* Most common is a MEM-AP, for memory access.
diff --git a/src/target/arm_cti.c b/src/target/arm_cti.c
index 0d117e76d..dcaf21e50 100644
--- a/src/target/arm_cti.c
+++ b/src/target/arm_cti.c
@@ -431,6 +431,10 @@ static int cti_configure(Jim_GetOptInfo *goi, struct arm_cti_object *cti)
e = Jim_GetOpt_Wide(goi, &w);
if (e != JIM_OK)
return e;
+ if (w < 0 || w > DP_APSEL_MAX) {
+ Jim_SetResultString(goi->interp, "-ap-num is invalid", -1);
+ return JIM_ERR;
+ }
cti->ap_num = (uint32_t)w;
}
}
diff --git a/src/target/arm_dap.c b/src/target/arm_dap.c
index 3be4d7199..3adb4ed26 100644
--- a/src/target/arm_dap.c
+++ b/src/target/arm_dap.c
@@ -48,7 +48,7 @@ static void dap_instance_init(struct adiv5_dap *dap)
{
int i;
/* Set up with safe defaults */
- for (i = 0; i <= 255; i++) {
+ for (i = 0; i <= DP_APSEL_MAX; i++) {
dap->ap[i].dap = dap;
dap->ap[i].ap_num = i;
/* memaccess_tck max is 255 */
@@ -319,7 +319,7 @@ COMMAND_HANDLER(handle_dap_info_command)
break;
case 1:
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], apsel);
- if (apsel >= 256)
+ if (apsel > DP_APSEL_MAX)
return ERROR_COMMAND_SYNTAX_ERROR;
break;
default:
diff --git a/src/target/arm_dpm.c b/src/target/arm_dpm.c
index f9b30c187..8b9957033 100644
--- a/src/target/arm_dpm.c
+++ b/src/target/arm_dpm.c
@@ -108,7 +108,7 @@ static int dpm_mcr(struct target *target, int cpnum,
/* Toggles between recorded core mode (USR, SVC, etc) and a temporary one.
* Routines *must* restore the original mode before returning!!
*/
-int dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode)
+int arm_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode)
{
int retval;
uint32_t cpsr;
@@ -168,7 +168,7 @@ static int dpm_read_reg_u64(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
}
/* just read the register -- rely on the core mode being right */
-static int dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
+int arm_dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
{
uint32_t value;
int retval;
@@ -352,7 +352,7 @@ int arm_dpm_read_current_registers(struct arm_dpm *dpm)
for (unsigned i = 0; i < 2; i++) {
r = arm->core_cache->reg_list + i;
if (!r->valid) {
- retval = dpm_read_reg(dpm, r, i);
+ retval = arm_dpm_read_reg(dpm, r, i);
if (retval != ERROR_OK)
goto fail;
}
@@ -372,7 +372,7 @@ int arm_dpm_read_current_registers(struct arm_dpm *dpm)
if (r->valid)
continue;
- retval = dpm_read_reg(dpm, r, i);
+ retval = arm_dpm_read_reg(dpm, r, i);
if (retval != ERROR_OK)
goto fail;
}
@@ -543,7 +543,7 @@ int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp)
/* REVISIT error checks */
if (tmode != ARM_MODE_ANY) {
- retval = dpm_modeswitch(dpm, tmode);
+ retval = arm_dpm_modeswitch(dpm, tmode);
if (retval != ERROR_OK)
goto done;
}
@@ -564,7 +564,7 @@ int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp)
* or it's dirty. Must write PC to ensure the return address is
* defined, and must not write it before CPSR.
*/
- retval = dpm_modeswitch(dpm, ARM_MODE_ANY);
+ retval = arm_dpm_modeswitch(dpm, ARM_MODE_ANY);
if (retval != ERROR_OK)
goto done;
arm->cpsr->dirty = false;
@@ -671,18 +671,18 @@ static int arm_dpm_read_core_reg(struct target *target, struct reg *r,
return retval;
if (mode != ARM_MODE_ANY) {
- retval = dpm_modeswitch(dpm, mode);
+ retval = arm_dpm_modeswitch(dpm, mode);
if (retval != ERROR_OK)
goto fail;
}
- retval = dpm_read_reg(dpm, r, regnum);
+ retval = arm_dpm_read_reg(dpm, r, regnum);
if (retval != ERROR_OK)
goto fail;
/* always clean up, regardless of error */
if (mode != ARM_MODE_ANY)
- /* (void) */ dpm_modeswitch(dpm, ARM_MODE_ANY);
+ /* (void) */ arm_dpm_modeswitch(dpm, ARM_MODE_ANY);
fail:
/* (void) */ dpm->finish(dpm);
@@ -715,7 +715,7 @@ static int arm_dpm_write_core_reg(struct target *target, struct reg *r,
return retval;
if (mode != ARM_MODE_ANY) {
- retval = dpm_modeswitch(dpm, mode);
+ retval = arm_dpm_modeswitch(dpm, mode);
if (retval != ERROR_OK)
goto fail;
}
@@ -724,7 +724,7 @@ static int arm_dpm_write_core_reg(struct target *target, struct reg *r,
/* always clean up, regardless of error */
if (mode != ARM_MODE_ANY)
- /* (void) */ dpm_modeswitch(dpm, ARM_MODE_ANY);
+ /* (void) */ arm_dpm_modeswitch(dpm, ARM_MODE_ANY);
fail:
/* (void) */ dpm->finish(dpm);
@@ -773,9 +773,9 @@ static int arm_dpm_full_context(struct target *target)
* in FIQ mode we need to patch mode.
*/
if (mode != ARM_MODE_ANY)
- retval = dpm_modeswitch(dpm, mode);
+ retval = arm_dpm_modeswitch(dpm, mode);
else
- retval = dpm_modeswitch(dpm, ARM_MODE_USR);
+ retval = arm_dpm_modeswitch(dpm, ARM_MODE_USR);
if (retval != ERROR_OK)
goto done;
@@ -784,7 +784,7 @@ static int arm_dpm_full_context(struct target *target)
continue;
/* CPSR was read, so "R16" must mean SPSR */
- retval = dpm_read_reg(dpm,
+ retval = arm_dpm_read_reg(dpm,
&cache->reg_list[i],
(r->num == 16) ? 17 : r->num);
if (retval != ERROR_OK)
@@ -793,7 +793,7 @@ static int arm_dpm_full_context(struct target *target)
} while (did_read);
- retval = dpm_modeswitch(dpm, ARM_MODE_ANY);
+ retval = arm_dpm_modeswitch(dpm, ARM_MODE_ANY);
/* (void) */ dpm->finish(dpm);
done:
return retval;
diff --git a/src/target/arm_dpm.h b/src/target/arm_dpm.h
index f8d124813..d05c66c43 100644
--- a/src/target/arm_dpm.h
+++ b/src/target/arm_dpm.h
@@ -152,8 +152,9 @@ struct arm_dpm {
int arm_dpm_setup(struct arm_dpm *dpm);
int arm_dpm_initialize(struct arm_dpm *dpm);
+int arm_dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum);
int arm_dpm_read_current_registers(struct arm_dpm *);
-int dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode);
+int arm_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode);
int arm_dpm_write_dirty_registers(struct arm_dpm *, bool bpwp);
diff --git a/src/target/armv7a.c b/src/target/armv7a.c
index eecfa7097..f9594c9c3 100644
--- a/src/target/armv7a.c
+++ b/src/target/armv7a.c
@@ -24,6 +24,7 @@
#include
#include "armv7a.h"
+#include "armv7a_mmu.h"
#include "arm_disassembler.h"
#include "register.h"
@@ -188,174 +189,6 @@ done:
return retval;
}
-/* method adapted to Cortex-A : reused ARM v4 v5 method */
-int armv7a_mmu_translate_va(struct target *target, uint32_t va, uint32_t *val)
-{
- uint32_t first_lvl_descriptor = 0x0;
- uint32_t second_lvl_descriptor = 0x0;
- int retval;
- struct armv7a_common *armv7a = target_to_armv7a(target);
- uint32_t ttbidx = 0; /* default to ttbr0 */
- uint32_t ttb_mask;
- uint32_t va_mask;
- uint32_t ttb;
-
- if (target->state != TARGET_HALTED)
- LOG_INFO("target not halted, using cached values for translation table!");
-
- /* if va is above the range handled by ttbr0, select ttbr1 */
- if (va > armv7a->armv7a_mmu.ttbr_range[0]) {
- /* select ttb 1 */
- ttbidx = 1;
- }
-
- ttb = armv7a->armv7a_mmu.ttbr[ttbidx];
- ttb_mask = armv7a->armv7a_mmu.ttbr_mask[ttbidx];
- va_mask = 0xfff00000 & armv7a->armv7a_mmu.ttbr_range[ttbidx];
-
- LOG_DEBUG("ttb_mask %" PRIx32 " va_mask %" PRIx32 " ttbidx %i",
- ttb_mask, va_mask, ttbidx);
- retval = armv7a->armv7a_mmu.read_physical_memory(target,
- (ttb & ttb_mask) | ((va & va_mask) >> 18),
- 4, 1, (uint8_t *)&first_lvl_descriptor);
- if (retval != ERROR_OK)
- return retval;
- first_lvl_descriptor = target_buffer_get_u32(target, (uint8_t *)
- &first_lvl_descriptor);
- /* reuse armv4_5 piece of code, specific armv7a changes may come later */
- LOG_DEBUG("1st lvl desc: %8.8" PRIx32 "", first_lvl_descriptor);
-
- if ((first_lvl_descriptor & 0x3) == 0) {
- LOG_ERROR("Address translation failure");
- return ERROR_TARGET_TRANSLATION_FAULT;
- }
-
-
- if ((first_lvl_descriptor & 0x40002) == 2) {
- /* section descriptor */
- *val = (first_lvl_descriptor & 0xfff00000) | (va & 0x000fffff);
- return ERROR_OK;
- } else if ((first_lvl_descriptor & 0x40002) == 0x40002) {
- /* supersection descriptor */
- if (first_lvl_descriptor & 0x00f001e0) {
- LOG_ERROR("Physical address does not fit into 32 bits");
- return ERROR_TARGET_TRANSLATION_FAULT;
- }
- *val = (first_lvl_descriptor & 0xff000000) | (va & 0x00ffffff);
- return ERROR_OK;
- }
-
- /* page table */
- retval = armv7a->armv7a_mmu.read_physical_memory(target,
- (first_lvl_descriptor & 0xfffffc00) | ((va & 0x000ff000) >> 10),
- 4, 1, (uint8_t *)&second_lvl_descriptor);
- if (retval != ERROR_OK)
- return retval;
-
- second_lvl_descriptor = target_buffer_get_u32(target, (uint8_t *)
- &second_lvl_descriptor);
-
- LOG_DEBUG("2nd lvl desc: %8.8" PRIx32 "", second_lvl_descriptor);
-
- if ((second_lvl_descriptor & 0x3) == 0) {
- LOG_ERROR("Address translation failure");
- return ERROR_TARGET_TRANSLATION_FAULT;
- }
-
- if ((second_lvl_descriptor & 0x3) == 1) {
- /* large page descriptor */
- *val = (second_lvl_descriptor & 0xffff0000) | (va & 0x0000ffff);
- } else {
- /* small page descriptor */
- *val = (second_lvl_descriptor & 0xfffff000) | (va & 0x00000fff);
- }
-
- return ERROR_OK;
-}
-
-/* V7 method VA TO PA */
-int armv7a_mmu_translate_va_pa(struct target *target, uint32_t va,
- uint32_t *val, int meminfo)
-{
- int retval = ERROR_FAIL;
- struct armv7a_common *armv7a = target_to_armv7a(target);
- struct arm_dpm *dpm = armv7a->arm.dpm;
- uint32_t virt = va & ~0xfff;
- uint32_t NOS, NS, INNER, OUTER;
- *val = 0xdeadbeef;
- retval = dpm->prepare(dpm);
- if (retval != ERROR_OK)
- goto done;
- /* mmu must be enable in order to get a correct translation
- * use VA to PA CP15 register for conversion */
- retval = dpm->instr_write_data_r0(dpm,
- ARMV4_5_MCR(15, 0, 0, 7, 8, 0),
- virt);
- if (retval != ERROR_OK)
- goto done;
- retval = dpm->instr_read_data_r0(dpm,
- ARMV4_5_MRC(15, 0, 0, 7, 4, 0),
- val);
- /* decode memory attribute */
- NOS = (*val >> 10) & 1; /* Not Outer shareable */
- NS = (*val >> 9) & 1; /* Non secure */
- INNER = (*val >> 4) & 0x7;
- OUTER = (*val >> 2) & 0x3;
-
- if (retval != ERROR_OK)
- goto done;
- *val = (*val & ~0xfff) + (va & 0xfff);
- if (*val == va)
- LOG_WARNING("virt = phys : MMU disable !!");
- if (meminfo) {
- LOG_INFO("%" PRIx32 " : %" PRIx32 " %s outer shareable %s secured",
- va, *val,
- NOS == 1 ? "not" : " ",
- NS == 1 ? "not" : "");
- switch (OUTER) {
- case 0:
- LOG_INFO("outer: Non-Cacheable");
- break;
- case 1:
- LOG_INFO("outer: Write-Back, Write-Allocate");
- break;
- case 2:
- LOG_INFO("outer: Write-Through, No Write-Allocate");
- break;
- case 3:
- LOG_INFO("outer: Write-Back, no Write-Allocate");
- break;
- }
- switch (INNER) {
- case 0:
- LOG_INFO("inner: Non-Cacheable");
- break;
- case 1:
- LOG_INFO("inner: Strongly-ordered");
- break;
- case 3:
- LOG_INFO("inner: Device");
- break;
- case 5:
- LOG_INFO("inner: Write-Back, Write-Allocate");
- break;
- case 6:
- LOG_INFO("inner: Write-Through");
- break;
- case 7:
- LOG_INFO("inner: Write-Back, no Write-Allocate");
- break;
- default:
- LOG_INFO("inner: %" PRIx32 " ???", INNER);
- }
- }
-
-done:
- dpm->finish(dpm);
-
- return retval;
-}
-
/* FIXME: remove it */
static int armv7a_l2x_cache_init(struct target *target, uint32_t base, uint32_t way)
{
diff --git a/src/target/armv7a.h b/src/target/armv7a.h
index 57779c61a..1e88c98cf 100644
--- a/src/target/armv7a.h
+++ b/src/target/armv7a.h
@@ -106,8 +106,6 @@ struct armv7a_common {
struct arm_dpm dpm;
uint32_t debug_base;
struct adiv5_ap *debug_ap;
- struct adiv5_ap *memory_ap;
- bool memory_ap_available;
/* mdir */
uint8_t multi_processor_system;
uint8_t cluster_id;
@@ -188,9 +186,6 @@ static inline bool is_armv7a(struct armv7a_common *armv7a)
int armv7a_arch_state(struct target *target);
int armv7a_identify_cache(struct target *target);
int armv7a_init_arch_info(struct target *target, struct armv7a_common *armv7a);
-int armv7a_mmu_translate_va_pa(struct target *target, uint32_t va,
- uint32_t *val, int meminfo);
-int armv7a_mmu_translate_va(struct target *target, uint32_t va, uint32_t *val);
int armv7a_handle_cache_info_command(struct command_context *cmd_ctx,
struct armv7a_cache_common *armv7a_cache);
diff --git a/src/target/armv7a_mmu.c b/src/target/armv7a_mmu.c
new file mode 100644
index 000000000..eed73ee58
--- /dev/null
+++ b/src/target/armv7a_mmu.c
@@ -0,0 +1,456 @@
+/***************************************************************************
+ * Copyright (C) 2016 by Matthias Welwarsky *
+ * matthias.welwarsky@sysgo.com *
+ * *
+ * Copyright (C) ST-Ericsson SA 2011 michel.jaouen@stericsson.com *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see . *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include
+#include
+
+#include "jtag/interface.h"
+#include "arm.h"
+#include "armv7a.h"
+#include "armv7a_mmu.h"
+#include "arm_opcodes.h"
+#include "cortex_a.h"
+
+#define SCTLR_BIT_AFE (1 << 29)
+
+/* method adapted to Cortex-A : reused ARM v4 v5 method */
+int armv7a_mmu_translate_va(struct target *target, uint32_t va, uint32_t *val)
+{
+ uint32_t first_lvl_descriptor = 0x0;
+ uint32_t second_lvl_descriptor = 0x0;
+ int retval;
+ struct armv7a_common *armv7a = target_to_armv7a(target);
+ uint32_t ttbidx = 0; /* default to ttbr0 */
+ uint32_t ttb_mask;
+ uint32_t va_mask;
+ uint32_t ttb;
+
+ if (target->state != TARGET_HALTED)
+ LOG_INFO("target not halted, using cached values for translation table!");
+
+ /* if va is above the range handled by ttbr0, select ttbr1 */
+ if (va > armv7a->armv7a_mmu.ttbr_range[0]) {
+ /* select ttb 1 */
+ ttbidx = 1;
+ }
+
+ ttb = armv7a->armv7a_mmu.ttbr[ttbidx];
+ ttb_mask = armv7a->armv7a_mmu.ttbr_mask[ttbidx];
+ va_mask = 0xfff00000 & armv7a->armv7a_mmu.ttbr_range[ttbidx];
+
+ LOG_DEBUG("ttb_mask %" PRIx32 " va_mask %" PRIx32 " ttbidx %i",
+ ttb_mask, va_mask, ttbidx);
+ retval = armv7a->armv7a_mmu.read_physical_memory(target,
+ (ttb & ttb_mask) | ((va & va_mask) >> 18),
+ 4, 1, (uint8_t *)&first_lvl_descriptor);
+ if (retval != ERROR_OK)
+ return retval;
+ first_lvl_descriptor = target_buffer_get_u32(target, (uint8_t *)
+ &first_lvl_descriptor);
+ /* reuse armv4_5 piece of code, specific armv7a changes may come later */
+ LOG_DEBUG("1st lvl desc: %8.8" PRIx32 "", first_lvl_descriptor);
+
+ if ((first_lvl_descriptor & 0x3) == 0) {
+ LOG_ERROR("Address translation failure");
+ return ERROR_TARGET_TRANSLATION_FAULT;
+ }
+
+ if ((first_lvl_descriptor & 0x40002) == 2) {
+ /* section descriptor */
+ *val = (first_lvl_descriptor & 0xfff00000) | (va & 0x000fffff);
+ return ERROR_OK;
+ } else if ((first_lvl_descriptor & 0x40002) == 0x40002) {
+ /* supersection descriptor */
+ if (first_lvl_descriptor & 0x00f001e0) {
+ LOG_ERROR("Physical address does not fit into 32 bits");
+ return ERROR_TARGET_TRANSLATION_FAULT;
+ }
+ *val = (first_lvl_descriptor & 0xff000000) | (va & 0x00ffffff);
+ return ERROR_OK;
+ }
+
+ /* page table */
+ retval = armv7a->armv7a_mmu.read_physical_memory(target,
+ (first_lvl_descriptor & 0xfffffc00) | ((va & 0x000ff000) >> 10),
+ 4, 1, (uint8_t *)&second_lvl_descriptor);
+ if (retval != ERROR_OK)
+ return retval;
+
+ second_lvl_descriptor = target_buffer_get_u32(target, (uint8_t *)
+ &second_lvl_descriptor);
+
+ LOG_DEBUG("2nd lvl desc: %8.8" PRIx32 "", second_lvl_descriptor);
+
+ if ((second_lvl_descriptor & 0x3) == 0) {
+ LOG_ERROR("Address translation failure");
+ return ERROR_TARGET_TRANSLATION_FAULT;
+ }
+
+ if ((second_lvl_descriptor & 0x3) == 1) {
+ /* large page descriptor */
+ *val = (second_lvl_descriptor & 0xffff0000) | (va & 0x0000ffff);
+ } else {
+ /* small page descriptor */
+ *val = (second_lvl_descriptor & 0xfffff000) | (va & 0x00000fff);
+ }
+
+ return ERROR_OK;
+}
+
+/* V7 method VA TO PA */
+int armv7a_mmu_translate_va_pa(struct target *target, uint32_t va,
+ uint32_t *val, int meminfo)
+{
+ int retval = ERROR_FAIL;
+ struct armv7a_common *armv7a = target_to_armv7a(target);
+ struct arm_dpm *dpm = armv7a->arm.dpm;
+ uint32_t virt = va & ~0xfff;
+ uint32_t NOS, NS, INNER, OUTER;
+ *val = 0xdeadbeef;
+ retval = dpm->prepare(dpm);
+ if (retval != ERROR_OK)
+ goto done;
+ /* mmu must be enable in order to get a correct translation
+ * use VA to PA CP15 register for conversion */
+ retval = dpm->instr_write_data_r0(dpm,
+ ARMV4_5_MCR(15, 0, 0, 7, 8, 0),
+ virt);
+ if (retval != ERROR_OK)
+ goto done;
+ retval = dpm->instr_read_data_r0(dpm,
+ ARMV4_5_MRC(15, 0, 0, 7, 4, 0),
+ val);
+ /* decode memory attribute */
+ NOS = (*val >> 10) & 1; /* Not Outer shareable */
+ NS = (*val >> 9) & 1; /* Non secure */
+ INNER = (*val >> 4) & 0x7;
+ OUTER = (*val >> 2) & 0x3;
+
+ if (retval != ERROR_OK)
+ goto done;
+ *val = (*val & ~0xfff) + (va & 0xfff);
+ if (*val == va)
+ LOG_WARNING("virt = phys : MMU disable !!");
+ if (meminfo) {
+ LOG_INFO("%" PRIx32 " : %" PRIx32 " %s outer shareable %s secured",
+ va, *val,
+ NOS == 1 ? "not" : " ",
+ NS == 1 ? "not" : "");
+ switch (OUTER) {
+ case 0:
+ LOG_INFO("outer: Non-Cacheable");
+ break;
+ case 1:
+ LOG_INFO("outer: Write-Back, Write-Allocate");
+ break;
+ case 2:
+ LOG_INFO("outer: Write-Through, No Write-Allocate");
+ break;
+ case 3:
+ LOG_INFO("outer: Write-Back, no Write-Allocate");
+ break;
+ }
+ switch (INNER) {
+ case 0:
+ LOG_INFO("inner: Non-Cacheable");
+ break;
+ case 1:
+ LOG_INFO("inner: Strongly-ordered");
+ break;
+ case 3:
+ LOG_INFO("inner: Device");
+ break;
+ case 5:
+ LOG_INFO("inner: Write-Back, Write-Allocate");
+ break;
+ case 6:
+ LOG_INFO("inner: Write-Through");
+ break;
+ case 7:
+ LOG_INFO("inner: Write-Back, no Write-Allocate");
+ break;
+ default:
+ LOG_INFO("inner: %" PRIx32 " ???", INNER);
+ }
+ }
+
+done:
+ dpm->finish(dpm);
+
+ return retval;
+}
+
+static const char *desc_bits_to_string(bool c_bit, bool b_bit, bool s_bit, bool ap2, int ap10, bool afe)
+{
+ static char bits_string[64];
+ unsigned int len;
+
+ if (afe) {
+ bool acc_r = true;
+ bool acc_w = !ap2;
+ bool priv = !(ap10 & 2);
+ len = snprintf(bits_string, sizeof(bits_string), "%s%s%s access%s: %s%s",
+ s_bit ? "S " : "", c_bit ? "C " : "", b_bit ? "B " : "",
+ priv ? "(priv)" : "", acc_r ? "R" : "N", acc_w ? "W " : "O ");
+ } else {
+ bool priv_acc_w = !ap2;
+ bool priv_acc_r = true;
+ bool unpriv_acc_w = priv_acc_w;
+ bool unpriv_acc_r = priv_acc_r;
+
+ switch (ap10) {
+ case 0:
+ priv_acc_r = priv_acc_w = false;
+ unpriv_acc_r = unpriv_acc_w = false;
+ break;
+ case 1:
+ unpriv_acc_r = unpriv_acc_w = false;
+ break;
+ case 2:
+ unpriv_acc_w = false;
+ break;
+ default:
+ break;
+ }
+
+ len = snprintf(bits_string, sizeof(bits_string), "%s%s%s access(priv): %s%s access(unpriv): %s%s",
+ s_bit ? "S " : "", c_bit ? "C " : "", b_bit ? "B " : "", priv_acc_r ? "R" : "N", priv_acc_w ? "W" : "O",
+ unpriv_acc_r ? "R" : "N", unpriv_acc_w ? "W" : "O");
+ }
+
+ if (len >= sizeof(bits_string))
+ bits_string[63] = 0;
+
+ return bits_string;
+}
+
+static const char *l2_desc_bits_to_string(uint32_t l2_desc, bool afe)
+{
+ bool c_bit = !!(l2_desc & (1 << 3));
+ bool b_bit = !!(l2_desc & (1 << 2));
+ bool s_bit = !!(l2_desc & (1 << 10));
+ bool ap2 = !!(l2_desc & (1 << 9));
+ int ap10 = (l2_desc >> 4) & 3;
+
+ return desc_bits_to_string(c_bit, b_bit, s_bit, ap2, ap10, afe);
+}
+
+static const char *l1_desc_bits_to_string(uint32_t l1_desc, bool afe)
+{
+ bool c_bit = !!(l1_desc & (1 << 3));
+ bool b_bit = !!(l1_desc & (1 << 2));
+ bool s_bit = !!(l1_desc & (1 << 16));
+ bool ap2 = !!(l1_desc & (1 << 15));
+ int ap10 = (l1_desc >> 10) & 3;
+
+ return desc_bits_to_string(c_bit, b_bit, s_bit, ap2, ap10, afe);
+}
+
+COMMAND_HANDLER(armv7a_mmu_dump_table)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ struct cortex_a_common *cortex_a = target_to_cortex_a(target);
+ struct armv7a_common *armv7a = target_to_armv7a(target);
+ struct armv7a_mmu_common *mmu = &armv7a->armv7a_mmu;
+ struct armv7a_cache_common *cache = &mmu->armv7a_cache;
+ uint32_t *first_lvl_ptbl;
+ target_addr_t ttb;
+ int ttbidx = 0;
+ int retval;
+ int pt_idx;
+ int max_pt_idx = 4095;
+ bool afe;
+
+ if (CMD_ARGC < 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ if (!strcmp(CMD_ARGV[0], "addr")) {
+ if (CMD_ARGC < 2)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ COMMAND_PARSE_NUMBER(target_addr, CMD_ARGV[1], ttb);
+
+ if (CMD_ARGC > 2) {
+ COMMAND_PARSE_NUMBER(int, CMD_ARGV[2], max_pt_idx);
+
+ if (max_pt_idx < 1 || max_pt_idx > 4096)
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ max_pt_idx -= 1;
+ }
+ } else {
+ if (mmu->cached != 1) {
+ LOG_ERROR("TTB not cached!");
+ return ERROR_FAIL;
+ }
+
+ COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], ttbidx);
+ if (ttbidx < 0 || ttbidx > 1)
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+
+ ttb = mmu->ttbr[ttbidx] & mmu->ttbr_mask[ttbidx];
+
+ if (ttbidx == 0) {
+ int ttbcr_n = mmu->ttbcr & 0x7;
+ max_pt_idx = 0x0fff >> ttbcr_n;
+ }
+ }
+
+ LOG_USER("Page Directory at (phys): %8.8" TARGET_PRIxADDR, ttb);
+
+ first_lvl_ptbl = malloc(sizeof(uint32_t)*(max_pt_idx+1));
+ if (first_lvl_ptbl == NULL)
+ return ERROR_FAIL;
+
+ /*
+ * this may or may not be necessary depending on whether
+ * the table walker is configured to use the cache or not.
+ */
+ cache->flush_all_data_cache(target);
+
+ retval = mmu->read_physical_memory(target, ttb, 4, max_pt_idx+1, (uint8_t *)first_lvl_ptbl);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to read first-level page table!");
+ return retval;
+ }
+
+ afe = !!(cortex_a->cp15_control_reg & SCTLR_BIT_AFE);
+
+ for (pt_idx = 0; pt_idx <= max_pt_idx;) {
+ uint32_t first_lvl_descriptor = target_buffer_get_u32(target,
+ (uint8_t *)&first_lvl_ptbl[pt_idx]);
+
+ LOG_DEBUG("L1 desc[%8.8"PRIx32"]: %8.8"PRIx32, pt_idx << 20, first_lvl_descriptor);
+
+ /* skip empty entries in the first level table */
+ if ((first_lvl_descriptor & 3) == 0) {
+ pt_idx++;
+ } else
+ if ((first_lvl_descriptor & 0x40002) == 2) {
+ /* section descriptor */
+ uint32_t va_range = 1024*1024-1; /* 1MB range */
+ uint32_t va_start = pt_idx << 20;
+ uint32_t va_end = va_start + va_range;
+
+ uint32_t pa_start = (first_lvl_descriptor & 0xfff00000);
+ uint32_t pa_end = pa_start + va_range;
+
+ LOG_USER("SECT: VA[%8.8"PRIx32" -- %8.8"PRIx32"]: PA[%8.8"PRIx32" -- %8.8"PRIx32"] %s",
+ va_start, va_end, pa_start, pa_end, l1_desc_bits_to_string(first_lvl_descriptor, afe));
+ pt_idx++;
+ } else
+ if ((first_lvl_descriptor & 0x40002) == 0x40002) {
+ /* supersection descriptor */
+ uint32_t va_range = 16*1024*1024-1; /* 16MB range */
+ uint32_t va_start = pt_idx << 20;
+ uint32_t va_end = va_start + va_range;
+
+ uint32_t pa_start = (first_lvl_descriptor & 0xff000000);
+ uint32_t pa_end = pa_start + va_range;
+
+ LOG_USER("SSCT: VA[%8.8"PRIx32" -- %8.8"PRIx32"]: PA[%8.8"PRIx32" -- %8.8"PRIx32"] %s",
+ va_start, va_end, pa_start, pa_end, l1_desc_bits_to_string(first_lvl_descriptor, afe));
+
+ /* skip next 15 entries, they're duplicating the first entry */
+ pt_idx += 16;
+ } else {
+ target_addr_t second_lvl_ptbl = first_lvl_descriptor & 0xfffffc00;
+ uint32_t second_lvl_descriptor;
+ uint32_t *pt2;
+ int pt2_idx;
+
+ /* page table, always 1KB long */
+ pt2 = malloc(1024);
+ retval = mmu->read_physical_memory(target, second_lvl_ptbl,
+ 4, 256, (uint8_t *)pt2);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Failed to read second-level page table!");
+ return ERROR_FAIL;
+ }
+
+ for (pt2_idx = 0; pt2_idx < 256; ) {
+ second_lvl_descriptor = target_buffer_get_u32(target,
+ (uint8_t *)&pt2[pt2_idx]);
+
+ if ((second_lvl_descriptor & 3) == 0) {
+ /* skip entry */
+ pt2_idx++;
+ } else
+ if ((second_lvl_descriptor & 3) == 1) {
+ /* large page */
+ uint32_t va_range = 64*1024-1; /* 64KB range */
+ uint32_t va_start = (pt_idx << 20) + (pt2_idx << 12);
+ uint32_t va_end = va_start + va_range;
+
+ uint32_t pa_start = (second_lvl_descriptor & 0xffff0000);
+ uint32_t pa_end = pa_start + va_range;
+
+ LOG_USER("LPGE: VA[%8.8"PRIx32" -- %8.8"PRIx32"]: PA[%8.8"PRIx32" -- %8.8"PRIx32"] %s",
+ va_start, va_end, pa_start, pa_end, l2_desc_bits_to_string(second_lvl_descriptor, afe));
+
+ pt2_idx += 16;
+ } else {
+ /* small page */
+ uint32_t va_range = 4*1024-1; /* 4KB range */
+ uint32_t va_start = (pt_idx << 20) + (pt2_idx << 12);
+ uint32_t va_end = va_start + va_range;
+
+ uint32_t pa_start = (second_lvl_descriptor & 0xfffff000);
+ uint32_t pa_end = pa_start + va_range;
+
+ LOG_USER("SPGE: VA[%8.8"PRIx32" -- %8.8"PRIx32"]: PA[%8.8"PRIx32" -- %8.8"PRIx32"] %s",
+ va_start, va_end, pa_start, pa_end, l2_desc_bits_to_string(second_lvl_descriptor, afe));
+
+ pt2_idx++;
+ }
+ }
+ free(pt2);
+ pt_idx++;
+ }
+ }
+
+ free(first_lvl_ptbl);
+ return ERROR_OK;
+}
+
+static const struct command_registration armv7a_mmu_group_handlers[] = {
+ {
+ .name = "dump",
+ .handler = armv7a_mmu_dump_table,
+ .mode = COMMAND_ANY,
+ .help = "dump translation table 0, 1 or from ",
+ .usage = "(0|1|addr [num_entries])",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+const struct command_registration armv7a_mmu_command_handlers[] = {
+ {
+ .name = "mmu",
+ .mode = COMMAND_ANY,
+ .help = "mmu command group",
+ .usage = "",
+ .chain = armv7a_mmu_group_handlers,
+ },
+ COMMAND_REGISTRATION_DONE
+};
diff --git a/src/target/armv7a_mmu.h b/src/target/armv7a_mmu.h
new file mode 100644
index 000000000..4372aa8eb
--- /dev/null
+++ b/src/target/armv7a_mmu.h
@@ -0,0 +1,28 @@
+/***************************************************************************
+ * Copyright (C) 2016 by Matthias Welwarsky *
+ * matthias.welwarsky@sysgo.com *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see . *
+ ***************************************************************************/
+
+#ifndef OPENOCD_TARGET_ARMV7A_MMU_H
+#define OPENOCD_TARGET_ARMV7A_MMU_H
+
+extern int armv7a_mmu_translate_va(struct target *target, uint32_t va, uint32_t *val);
+extern int armv7a_mmu_translate_va_pa(struct target *target, uint32_t va,
+ uint32_t *val, int meminfo);
+
+extern const struct command_registration armv7a_mmu_command_handlers[];
+
+#endif /* OPENOCD_TARGET_ARMV7A_MMU_H */
diff --git a/src/target/armv8.c b/src/target/armv8.c
index dfa2c67a5..75ada896d 100644
--- a/src/target/armv8.c
+++ b/src/target/armv8.c
@@ -936,6 +936,11 @@ int armv8_mmu_translate_va_pa(struct target *target, target_addr_t va,
"Secure", "Not Secure"
};
+ if (target->state != TARGET_HALTED) {
+ LOG_WARNING("target %s not halted", target_name(target));
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
retval = dpm->prepare(dpm);
if (retval != ERROR_OK)
return retval;
diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c
index 4aae5e473..92ba54789 100644
--- a/src/target/cortex_a.c
+++ b/src/target/cortex_a.c
@@ -50,6 +50,7 @@
#include "breakpoints.h"
#include "cortex_a.h"
#include "register.h"
+#include "armv7a_mmu.h"
#include "target_request.h"
#include "target_type.h"
#include "arm_opcodes.h"
@@ -57,6 +58,9 @@
#include "transport/transport.h"
#include
+#define foreach_smp_target(pos, head) \
+ for (pos = head; (pos != NULL); pos = pos->next)
+
static int cortex_a_poll(struct target *target);
static int cortex_a_debug_entry(struct target *target);
static int cortex_a_restore_context(struct target *target, bool bpwp);
@@ -68,10 +72,6 @@ static int cortex_a_set_hybrid_breakpoint(struct target *target,
struct breakpoint *breakpoint);
static int cortex_a_unset_breakpoint(struct target *target,
struct breakpoint *breakpoint);
-static int cortex_a_dap_read_coreregister_u32(struct target *target,
- uint32_t *value, int regnum);
-static int cortex_a_dap_write_coreregister_u32(struct target *target,
- uint32_t value, int regnum);
static int cortex_a_mmu(struct target *target, int *enabled);
static int cortex_a_mmu_modify(struct target *target, int enable);
static int cortex_a_virt2phys(struct target *target,
@@ -110,7 +110,7 @@ static int cortex_a_prep_memaccess(struct target *target, int phys_access)
int mmu_enabled = 0;
if (phys_access == 0) {
- dpm_modeswitch(&armv7a->dpm, ARM_MODE_SVC);
+ arm_dpm_modeswitch(&armv7a->dpm, ARM_MODE_SVC);
cortex_a_mmu(target, &mmu_enabled);
if (mmu_enabled)
cortex_a_mmu_modify(target, 1);
@@ -145,7 +145,7 @@ static int cortex_a_post_memaccess(struct target *target, int phys_access)
0, 0, 3, 0,
cortex_a->cp15_dacr_reg);
}
- dpm_modeswitch(&armv7a->dpm, ARM_MODE_ANY);
+ arm_dpm_modeswitch(&armv7a->dpm, ARM_MODE_ANY);
} else {
int mmu_enabled = 0;
cortex_a_mmu(target, &mmu_enabled);
@@ -304,172 +304,6 @@ static int cortex_a_exec_opcode(struct target *target,
return retval;
}
-/**************************************************************************
-Read core register with very few exec_opcode, fast but needs work_area.
-This can cause problems with MMU active.
-**************************************************************************/
-static int cortex_a_read_regs_through_mem(struct target *target, uint32_t address,
- uint32_t *regfile)
-{
- int retval = ERROR_OK;
- struct armv7a_common *armv7a = target_to_armv7a(target);
-
- retval = cortex_a_dap_read_coreregister_u32(target, regfile, 0);
- if (retval != ERROR_OK)
- return retval;
- retval = cortex_a_dap_write_coreregister_u32(target, address, 0);
- if (retval != ERROR_OK)
- return retval;
- retval = cortex_a_exec_opcode(target, ARMV4_5_STMIA(0, 0xFFFE, 0, 0), NULL);
- if (retval != ERROR_OK)
- return retval;
-
- retval = mem_ap_read_buf(armv7a->memory_ap,
- (uint8_t *)(®file[1]), 4, 15, address);
-
- return retval;
-}
-
-static int cortex_a_dap_read_coreregister_u32(struct target *target,
- uint32_t *value, int regnum)
-{
- int retval = ERROR_OK;
- uint8_t reg = regnum&0xFF;
- uint32_t dscr = 0;
- struct armv7a_common *armv7a = target_to_armv7a(target);
-
- if (reg > 17)
- return retval;
-
- if (reg < 15) {
- /* Rn to DCCTX, "MCR p14, 0, Rn, c0, c5, 0" 0xEE00nE15 */
- retval = cortex_a_exec_opcode(target,
- ARMV4_5_MCR(14, 0, reg, 0, 5, 0),
- &dscr);
- if (retval != ERROR_OK)
- return retval;
- } else if (reg == 15) {
- /* "MOV r0, r15"; then move r0 to DCCTX */
- retval = cortex_a_exec_opcode(target, 0xE1A0000F, &dscr);
- if (retval != ERROR_OK)
- return retval;
- retval = cortex_a_exec_opcode(target,
- ARMV4_5_MCR(14, 0, 0, 0, 5, 0),
- &dscr);
- if (retval != ERROR_OK)
- return retval;
- } else {
- /* "MRS r0, CPSR" or "MRS r0, SPSR"
- * then move r0 to DCCTX
- */
- retval = cortex_a_exec_opcode(target, ARMV4_5_MRS(0, reg & 1), &dscr);
- if (retval != ERROR_OK)
- return retval;
- retval = cortex_a_exec_opcode(target,
- ARMV4_5_MCR(14, 0, 0, 0, 5, 0),
- &dscr);
- if (retval != ERROR_OK)
- return retval;
- }
-
- /* Wait for DTRRXfull then read DTRRTX */
- int64_t then = timeval_ms();
- while ((dscr & DSCR_DTR_TX_FULL) == 0) {
- retval = mem_ap_read_atomic_u32(armv7a->debug_ap,
- armv7a->debug_base + CPUDBG_DSCR, &dscr);
- if (retval != ERROR_OK)
- return retval;
- if (timeval_ms() > then + 1000) {
- LOG_ERROR("Timeout waiting for cortex_a_exec_opcode");
- return ERROR_FAIL;
- }
- }
-
- retval = mem_ap_read_atomic_u32(armv7a->debug_ap,
- armv7a->debug_base + CPUDBG_DTRTX, value);
- LOG_DEBUG("read DCC 0x%08" PRIx32, *value);
-
- return retval;
-}
-
-static int cortex_a_dap_write_coreregister_u32(struct target *target,
- uint32_t value, int regnum)
-{
- int retval = ERROR_OK;
- uint8_t Rd = regnum&0xFF;
- uint32_t dscr;
- struct armv7a_common *armv7a = target_to_armv7a(target);
-
- LOG_DEBUG("register %i, value 0x%08" PRIx32, regnum, value);
-
- /* Check that DCCRX is not full */
- retval = mem_ap_read_atomic_u32(armv7a->debug_ap,
- armv7a->debug_base + CPUDBG_DSCR, &dscr);
- if (retval != ERROR_OK)
- return retval;
- if (dscr & DSCR_DTR_RX_FULL) {
- LOG_ERROR("DSCR_DTR_RX_FULL, dscr 0x%08" PRIx32, dscr);
- /* Clear DCCRX with MRC(p14, 0, Rd, c0, c5, 0), opcode 0xEE100E15 */
- retval = cortex_a_exec_opcode(target, ARMV4_5_MRC(14, 0, 0, 0, 5, 0),
- &dscr);
- if (retval != ERROR_OK)
- return retval;
- }
-
- if (Rd > 17)
- return retval;
-
- /* Write DTRRX ... sets DSCR.DTRRXfull but exec_opcode() won't care */
- LOG_DEBUG("write DCC 0x%08" PRIx32, value);
- retval = mem_ap_write_u32(armv7a->debug_ap,
- armv7a->debug_base + CPUDBG_DTRRX, value);
- if (retval != ERROR_OK)
- return retval;
-
- if (Rd < 15) {
- /* DCCRX to Rn, "MRC p14, 0, Rn, c0, c5, 0", 0xEE10nE15 */
- retval = cortex_a_exec_opcode(target, ARMV4_5_MRC(14, 0, Rd, 0, 5, 0),
- &dscr);
-
- if (retval != ERROR_OK)
- return retval;
- } else if (Rd == 15) {
- /* DCCRX to R0, "MRC p14, 0, R0, c0, c5, 0", 0xEE100E15
- * then "mov r15, r0"
- */
- retval = cortex_a_exec_opcode(target, ARMV4_5_MRC(14, 0, 0, 0, 5, 0),
- &dscr);
- if (retval != ERROR_OK)
- return retval;
- retval = cortex_a_exec_opcode(target, 0xE1A0F000, &dscr);
- if (retval != ERROR_OK)
- return retval;
- } else {
- /* DCCRX to R0, "MRC p14, 0, R0, c0, c5, 0", 0xEE100E15
- * then "MSR CPSR_cxsf, r0" or "MSR SPSR_cxsf, r0" (all fields)
- */
- retval = cortex_a_exec_opcode(target, ARMV4_5_MRC(14, 0, 0, 0, 5, 0),
- &dscr);
- if (retval != ERROR_OK)
- return retval;
- retval = cortex_a_exec_opcode(target, ARMV4_5_MSR_GP(0, 0xF, Rd & 1),
- &dscr);
- if (retval != ERROR_OK)
- return retval;
-
- /* "Prefetch flush" after modifying execution status in CPSR */
- if (Rd == 16) {
- retval = cortex_a_exec_opcode(target,
- ARMV4_5_MCR(15, 0, 0, 7, 5, 4),
- &dscr);
- if (retval != ERROR_OK)
- return retval;
- }
- }
-
- return retval;
-}
-
/* Write to memory mapped registers directly with no cache or mmu handling */
static int cortex_a_dap_write_memap_register_u32(struct target *target,
uint32_t address,
@@ -806,12 +640,43 @@ static int cortex_a_halt_smp(struct target *target)
static int update_halt_gdb(struct target *target)
{
+ struct target *gdb_target = NULL;
+ struct target_list *head;
+ struct target *curr;
int retval = 0;
+
if (target->gdb_service && target->gdb_service->core[0] == -1) {
target->gdb_service->target = target;
target->gdb_service->core[0] = target->coreid;
retval += cortex_a_halt_smp(target);
}
+
+ if (target->gdb_service)
+ gdb_target = target->gdb_service->target;
+
+ foreach_smp_target(head, target->head) {
+ curr = head->target;
+ /* skip calling context */
+ if (curr == target)
+ continue;
+ if (!target_was_examined(curr))
+ continue;
+ /* skip targets that were already halted */
+ if (curr->state == TARGET_HALTED)
+ continue;
+ /* Skip gdb_target; it alerts GDB so has to be polled as last one */
+ if (curr == gdb_target)
+ continue;
+
+ /* avoid recursion in cortex_a_poll() */
+ curr->smp = 0;
+ cortex_a_poll(curr);
+ curr->smp = 1;
+ }
+
+ /* after all targets were updated, poll the gdb serving target */
+ if (gdb_target != NULL && gdb_target != target)
+ cortex_a_poll(gdb_target);
return retval;
}
@@ -1002,7 +867,7 @@ static int cortex_a_internal_restore(struct target *target, int current,
arm->pc->valid = 1;
/* restore dpm_mode at system halt */
- dpm_modeswitch(&armv7a->dpm, ARM_MODE_ANY);
+ arm_dpm_modeswitch(&armv7a->dpm, ARM_MODE_ANY);
/* called it now before restoring context because it uses cpu
* register r0 for restoring cp15 control register */
retval = cortex_a_restore_cp15_control_reg(target);
@@ -1149,14 +1014,11 @@ static int cortex_a_resume(struct target *target, int current,
static int cortex_a_debug_entry(struct target *target)
{
- int i;
- uint32_t regfile[16], cpsr, spsr, dscr;
+ uint32_t dscr;
int retval = ERROR_OK;
- struct working_area *regfile_working_area = NULL;
struct cortex_a_common *cortex_a = target_to_cortex_a(target);
struct armv7a_common *armv7a = target_to_armv7a(target);
struct arm *arm = &armv7a->arm;
- struct reg *reg;
LOG_DEBUG("dscr = 0x%08" PRIx32, cortex_a->cpudbg_dscr);
@@ -1193,68 +1055,16 @@ static int cortex_a_debug_entry(struct target *target)
arm_dpm_report_wfar(&armv7a->dpm, wfar);
}
- /* REVISIT fast_reg_read is never set ... */
-
- /* Examine target state and mode */
- if (cortex_a->fast_reg_read)
- target_alloc_working_area(target, 64, ®file_working_area);
-
-
- /* First load register acessible through core debug port*/
- if (!regfile_working_area)
- retval = arm_dpm_read_current_registers(&armv7a->dpm);
- else {
- retval = cortex_a_read_regs_through_mem(target,
- regfile_working_area->address, regfile);
-
- target_free_working_area(target, regfile_working_area);
- if (retval != ERROR_OK)
- return retval;
-
- /* read Current PSR */
- retval = cortex_a_dap_read_coreregister_u32(target, &cpsr, 16);
- /* store current cpsr */
- if (retval != ERROR_OK)
- return retval;
-
- LOG_DEBUG("cpsr: %8.8" PRIx32, cpsr);
-
- arm_set_cpsr(arm, cpsr);
-
- /* update cache */
- for (i = 0; i <= ARM_PC; i++) {
- reg = arm_reg_current(arm, i);
-
- buf_set_u32(reg->value, 0, 32, regfile[i]);
- reg->valid = 1;
- reg->dirty = 0;
- }
-
- /* Fixup PC Resume Address */
- if (cpsr & (1 << 5)) {
- /* T bit set for Thumb or ThumbEE state */
- regfile[ARM_PC] -= 4;
- } else {
- /* ARM state */
- regfile[ARM_PC] -= 8;
- }
-
- reg = arm->pc;
- buf_set_u32(reg->value, 0, 32, regfile[ARM_PC]);
- reg->dirty = reg->valid;
- }
+ /* First load register accessible through core debug port */
+ retval = arm_dpm_read_current_registers(&armv7a->dpm);
+ if (retval != ERROR_OK)
+ return retval;
if (arm->spsr) {
- /* read Saved PSR */
- retval = cortex_a_dap_read_coreregister_u32(target, &spsr, 17);
- /* store current spsr */
+ /* read SPSR */
+ retval = arm_dpm_read_reg(&armv7a->dpm, arm->spsr, 17);
if (retval != ERROR_OK)
return retval;
-
- reg = arm->spsr;
- buf_set_u32(reg->value, 0, 32, spsr);
- reg->valid = 1;
- reg->dirty = 0;
}
#if 0
@@ -1316,7 +1126,7 @@ static int cortex_a_post_debug_entry(struct target *target)
cortex_a->curr_mode = armv7a->arm.core_mode;
/* switch to SVC mode to read DACR */
- dpm_modeswitch(&armv7a->dpm, ARM_MODE_SVC);
+ arm_dpm_modeswitch(&armv7a->dpm, ARM_MODE_SVC);
armv7a->arm.mrc(target, 15,
0, 0, 3, 0,
&cortex_a->cp15_dacr_reg);
@@ -1324,7 +1134,7 @@ static int cortex_a_post_debug_entry(struct target *target)
LOG_DEBUG("cp15_dacr_reg: %8.8" PRIx32,
cortex_a->cp15_dacr_reg);
- dpm_modeswitch(&armv7a->dpm, ARM_MODE_ANY);
+ arm_dpm_modeswitch(&armv7a->dpm, ARM_MODE_ANY);
return ERROR_OK;
}
@@ -1386,6 +1196,7 @@ static int cortex_a_step(struct target *target, int current, target_addr_t addre
/* Setup single step breakpoint */
stepbreakpoint.address = address;
+ stepbreakpoint.asid = 0;
stepbreakpoint.length = (arm->core_state == ARM_STATE_THUMB)
? 2 : 4;
stepbreakpoint.type = BKPT_HARD;
@@ -2660,9 +2471,6 @@ static int cortex_a_read_phys_memory(struct target *target,
target_addr_t address, uint32_t size,
uint32_t count, uint8_t *buffer)
{
- struct armv7a_common *armv7a = target_to_armv7a(target);
- struct adiv5_dap *swjdp = armv7a->arm.dap;
- uint8_t apsel = swjdp->apsel;
int retval;
if (!count || !buffer)
@@ -2671,9 +2479,6 @@ static int cortex_a_read_phys_memory(struct target *target,
LOG_DEBUG("Reading memory at real address " TARGET_ADDR_FMT "; size %" PRId32 "; count %" PRId32,
address, size, count);
- if (armv7a->memory_ap_available && (apsel == armv7a->memory_ap->ap_num))
- return mem_ap_read_buf(armv7a->memory_ap, buffer, size, count, address);
-
/* read memory through the CPU */
cortex_a_prep_memaccess(target, 1);
retval = cortex_a_read_cpu_memory(target, address, size, count, buffer);
@@ -2698,57 +2503,10 @@ static int cortex_a_read_memory(struct target *target, target_addr_t address,
return retval;
}
-static int cortex_a_read_memory_ahb(struct target *target, target_addr_t address,
- uint32_t size, uint32_t count, uint8_t *buffer)
-{
- int mmu_enabled = 0;
- target_addr_t virt, phys;
- int retval;
- struct armv7a_common *armv7a = target_to_armv7a(target);
- struct adiv5_dap *swjdp = armv7a->arm.dap;
- uint8_t apsel = swjdp->apsel;
-
- if (!armv7a->memory_ap_available || (apsel != armv7a->memory_ap->ap_num))
- return target_read_memory(target, address, size, count, buffer);
-
- /* cortex_a handles unaligned memory access */
- LOG_DEBUG("Reading memory at address " TARGET_ADDR_FMT "; size %" PRId32 "; count %" PRId32,
- address, size, count);
-
- /* determine if MMU was enabled on target stop */
- if (!armv7a->is_armv7r) {
- retval = cortex_a_mmu(target, &mmu_enabled);
- if (retval != ERROR_OK)
- return retval;
- }
-
- if (mmu_enabled) {
- virt = address;
- retval = cortex_a_virt2phys(target, virt, &phys);
- if (retval != ERROR_OK)
- return retval;
-
- LOG_DEBUG("Reading at virtual address. "
- "Translating v:" TARGET_ADDR_FMT " to r:" TARGET_ADDR_FMT,
- virt, phys);
- address = phys;
- }
-
- if (!count || !buffer)
- return ERROR_COMMAND_SYNTAX_ERROR;
-
- retval = mem_ap_read_buf(armv7a->memory_ap, buffer, size, count, address);
-
- return retval;
-}
-
static int cortex_a_write_phys_memory(struct target *target,
target_addr_t address, uint32_t size,
uint32_t count, const uint8_t *buffer)
{
- struct armv7a_common *armv7a = target_to_armv7a(target);
- struct adiv5_dap *swjdp = armv7a->arm.dap;
- uint8_t apsel = swjdp->apsel;
int retval;
if (!count || !buffer)
@@ -2757,9 +2515,6 @@ static int cortex_a_write_phys_memory(struct target *target,
LOG_DEBUG("Writing memory to real address " TARGET_ADDR_FMT "; size %" PRId32 "; count %" PRId32,
address, size, count);
- if (armv7a->memory_ap_available && (apsel == armv7a->memory_ap->ap_num))
- return mem_ap_write_buf(armv7a->memory_ap, buffer, size, count, address);
-
/* write memory through the CPU */
cortex_a_prep_memaccess(target, 1);
retval = cortex_a_write_cpu_memory(target, address, size, count, buffer);
@@ -2786,51 +2541,6 @@ static int cortex_a_write_memory(struct target *target, target_addr_t address,
return retval;
}
-static int cortex_a_write_memory_ahb(struct target *target, target_addr_t address,
- uint32_t size, uint32_t count, const uint8_t *buffer)
-{
- int mmu_enabled = 0;
- target_addr_t virt, phys;
- int retval;
- struct armv7a_common *armv7a = target_to_armv7a(target);
- struct adiv5_dap *swjdp = armv7a->arm.dap;
- uint8_t apsel = swjdp->apsel;
-
- if (!armv7a->memory_ap_available || (apsel != armv7a->memory_ap->ap_num))
- return target_write_memory(target, address, size, count, buffer);
-
- /* cortex_a handles unaligned memory access */
- LOG_DEBUG("Writing memory at address " TARGET_ADDR_FMT "; size %" PRId32 "; count %" PRId32,
- address, size, count);
-
- /* determine if MMU was enabled on target stop */
- if (!armv7a->is_armv7r) {
- retval = cortex_a_mmu(target, &mmu_enabled);
- if (retval != ERROR_OK)
- return retval;
- }
-
- if (mmu_enabled) {
- virt = address;
- retval = cortex_a_virt2phys(target, virt, &phys);
- if (retval != ERROR_OK)
- return retval;
-
- LOG_DEBUG("Writing to virtual address. "
- "Translating v:" TARGET_ADDR_FMT " to r:" TARGET_ADDR_FMT,
- virt,
- phys);
- address = phys;
- }
-
- if (!count || !buffer)
- return ERROR_COMMAND_SYNTAX_ERROR;
-
- retval = mem_ap_write_buf(armv7a->memory_ap, buffer, size, count, address);
-
- return retval;
-}
-
static int cortex_a_read_buffer(struct target *target, target_addr_t address,
uint32_t count, uint8_t *buffer)
{
@@ -2840,7 +2550,7 @@ static int cortex_a_read_buffer(struct target *target, target_addr_t address,
* will have something to do with the size we leave to it. */
for (size = 1; size < 4 && count >= size * 2 + (address & size); size *= 2) {
if (address & size) {
- int retval = cortex_a_read_memory_ahb(target, address, size, 1, buffer);
+ int retval = target_read_memory(target, address, size, 1, buffer);
if (retval != ERROR_OK)
return retval;
address += size;
@@ -2853,7 +2563,7 @@ static int cortex_a_read_buffer(struct target *target, target_addr_t address,
for (; size > 0; size /= 2) {
uint32_t aligned = count - count % size;
if (aligned > 0) {
- int retval = cortex_a_read_memory_ahb(target, address, size, aligned / size, buffer);
+ int retval = target_read_memory(target, address, size, aligned / size, buffer);
if (retval != ERROR_OK)
return retval;
address += aligned;
@@ -2874,7 +2584,7 @@ static int cortex_a_write_buffer(struct target *target, target_addr_t address,
* will have something to do with the size we leave to it. */
for (size = 1; size < 4 && count >= size * 2 + (address & size); size *= 2) {
if (address & size) {
- int retval = cortex_a_write_memory_ahb(target, address, size, 1, buffer);
+ int retval = target_write_memory(target, address, size, 1, buffer);
if (retval != ERROR_OK)
return retval;
address += size;
@@ -2887,7 +2597,7 @@ static int cortex_a_write_buffer(struct target *target, target_addr_t address,
for (; size > 0; size /= 2) {
uint32_t aligned = count - count % size;
if (aligned > 0) {
- int retval = cortex_a_write_memory_ahb(target, address, size, aligned / size, buffer);
+ int retval = target_write_memory(target, address, size, aligned / size, buffer);
if (retval != ERROR_OK)
return retval;
address += aligned;
@@ -2965,21 +2675,6 @@ static int cortex_a_examine_first(struct target *target)
armv7a->debug_ap->memaccess_tck = 80;
- /* Search for the AHB-AB.
- * REVISIT: We should search for AXI-AP as well and make sure the AP's MEMTYPE says it
- * can access system memory. */
- armv7a->memory_ap_available = false;
- retval = dap_find_ap(swjdp, AP_TYPE_AHB_AP, &armv7a->memory_ap);
- if (retval == ERROR_OK) {
- retval = mem_ap_init(armv7a->memory_ap);
- if (retval == ERROR_OK)
- armv7a->memory_ap_available = true;
- }
- if (retval != ERROR_OK) {
- /* AHB-AP not found or unavailable - use the CPU */
- LOG_DEBUG("No AHB-AP available for memory access");
- }
-
if (!target->dbgbase_set) {
uint32_t dbgbase;
/* Get ROM Table base */
@@ -3139,8 +2834,6 @@ static int cortex_a_init_arch_info(struct target *target,
cortex_a->common_magic = CORTEX_A_COMMON_MAGIC;
armv7a->arm.dap = dap;
- cortex_a->fast_reg_read = 0;
-
/* register arch-specific functions */
armv7a->examine_debug_reason = NULL;
@@ -3225,10 +2918,7 @@ static int cortex_a_mmu(struct target *target, int *enabled)
static int cortex_a_virt2phys(struct target *target,
target_addr_t virt, target_addr_t *phys)
{
- int retval = ERROR_FAIL;
- struct armv7a_common *armv7a = target_to_armv7a(target);
- struct adiv5_dap *swjdp = armv7a->arm.dap;
- uint8_t apsel = swjdp->apsel;
+ int retval;
int mmu_enabled = 0;
/*
@@ -3243,23 +2933,12 @@ static int cortex_a_virt2phys(struct target *target,
return ERROR_OK;
}
- if (armv7a->memory_ap_available && (apsel == armv7a->memory_ap->ap_num)) {
- uint32_t ret;
- retval = armv7a_mmu_translate_va(target,
- virt, &ret);
- if (retval != ERROR_OK)
- goto done;
- *phys = ret;
- } else {/* use this method if armv7a->memory_ap not selected
- * mmu must be enable in order to get a correct translation */
- retval = cortex_a_mmu_modify(target, 1);
- if (retval != ERROR_OK)
- goto done;
- retval = armv7a_mmu_translate_va_pa(target, (uint32_t)virt,
+ /* mmu must be enable in order to get a correct translation */
+ retval = cortex_a_mmu_modify(target, 1);
+ if (retval != ERROR_OK)
+ return retval;
+ return armv7a_mmu_translate_va_pa(target, (uint32_t)virt,
(uint32_t *)phys, 1);
- }
-done:
- return retval;
}
COMMAND_HANDLER(cortex_a_handle_cache_info_command)
@@ -3443,6 +3122,9 @@ static const struct command_registration cortex_a_exec_command_handlers[] = {
"on memory access",
.usage = "['on'|'off']",
},
+ {
+ .chain = armv7a_mmu_command_handlers,
+ },
COMMAND_REGISTRATION_DONE
};
diff --git a/src/target/cortex_a.h b/src/target/cortex_a.h
index ff0343208..197a5992d 100644
--- a/src/target/cortex_a.h
+++ b/src/target/cortex_a.h
@@ -93,9 +93,6 @@ struct cortex_a_common {
int brp_num_available;
struct cortex_a_brp *brp_list;
- /* Use cortex_a_read_regs_through_mem for fast register reads */
- int fast_reg_read;
-
uint32_t cpuid;
uint32_t didr;
diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c
index ca3dbec78..07fea5137 100644
--- a/src/target/cortex_m.c
+++ b/src/target/cortex_m.c
@@ -42,7 +42,7 @@
/* NOTE: most of this should work fine for the Cortex-M1 and
* Cortex-M0 cores too, although they're ARMv6-M not ARMv7-M.
- * Some differences: M0/M1 doesn't have FBP remapping or the
+ * Some differences: M0/M1 doesn't have FPB remapping or the
* DWT tracing/profiling support. (So the cycle counter will
* not be usable; the other stuff isn't currently used here.)
*
@@ -255,7 +255,7 @@ static int cortex_m_endreset_event(struct target *target)
return retval;
/* Paranoia: evidently some (early?) chips don't preserve all the
- * debug state (including FBP, DWT, etc) across reset...
+ * debug state (including FPB, DWT, etc) across reset...
*/
/* Enable FPB */
@@ -1277,7 +1277,7 @@ int cortex_m_remove_breakpoint(struct target *target, struct breakpoint *breakpo
{
struct cortex_m_common *cortex_m = target_to_cm(target);
- /* REVISIT why check? FBP can be updated with core running ... */
+ /* REVISIT why check? FPB can be updated with core running ... */
if (target->state != TARGET_HALTED) {
LOG_WARNING("target not halted");
return ERROR_TARGET_NOT_HALTED;
@@ -1986,7 +1986,7 @@ int cortex_m_examine(struct target *target)
/* stlink shares the examine handler but does not support
* all its calls */
if (!armv7m->stlink) {
- if (cortex_m->apsel < 0) {
+ if (cortex_m->apsel == DP_APSEL_INVALID) {
/* Search for the MEM-AP */
retval = dap_find_ap(swjdp, AP_TYPE_AHB_AP, &armv7m->debug_ap);
if (retval != ERROR_OK) {
diff --git a/src/target/esirisc.c b/src/target/esirisc.c
new file mode 100644
index 000000000..38100e834
--- /dev/null
+++ b/src/target/esirisc.c
@@ -0,0 +1,1787 @@
+/***************************************************************************
+ * Copyright (C) 2018 by Square, Inc. *
+ * Steven Stallion *
+ * James Zhao *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see . *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "esirisc.h"
+
+#define RESET_TIMEOUT 5000 /* 5s */
+#define STEP_TIMEOUT 1000 /* 1s */
+
+/*
+ * eSi-RISC targets support a configurable number of interrupts;
+ * up to 32 interrupts are supported.
+ */
+static const char * const esirisc_exceptions[] = {
+ "Reset", "HardwareFailure", "NMI", "InstBreakpoint", "DataBreakpoint",
+ "Unsupported", "PrivilegeViolation", "InstBusError", "DataBusError",
+ "AlignmentError", "ArithmeticError", "SystemCall", "MemoryManagement",
+ "Unrecoverable", "Reserved",
+
+ "Interrupt0", "Interrupt1", "Interrupt2", "Interrupt3",
+ "Interrupt4", "Interrupt5", "Interrupt6", "Interrupt7",
+ "Interrupt8", "Interrupt9", "Interrupt10", "Interrupt11",
+ "Interrupt12", "Interrupt13", "Interrupt14", "Interrupt15",
+ "Interrupt16", "Interrupt17", "Interrupt18", "Interrupt19",
+ "Interrupt20", "Interrupt21", "Interrupt22", "Interrupt23",
+ "Interrupt24", "Interrupt25", "Interrupt26", "Interrupt27",
+ "Interrupt28", "Interrupt29", "Interrupt30", "Interrupt31",
+};
+
+/*
+ * eSi-RISC targets support a configurable number of general purpose
+ * registers; 8, 16, and 32 registers are supported.
+ */
+static const struct {
+ enum esirisc_reg_num number;
+ const char *name;
+ enum reg_type type;
+ const char *group;
+} esirisc_regs[] = {
+ { ESIRISC_SP, "sp", REG_TYPE_DATA_PTR, "general" },
+ { ESIRISC_RA, "ra", REG_TYPE_INT, "general" },
+ { ESIRISC_R2, "r2", REG_TYPE_INT, "general" },
+ { ESIRISC_R3, "r3", REG_TYPE_INT, "general" },
+ { ESIRISC_R4, "r4", REG_TYPE_INT, "general" },
+ { ESIRISC_R5, "r5", REG_TYPE_INT, "general" },
+ { ESIRISC_R6, "r6", REG_TYPE_INT, "general" },
+ { ESIRISC_R7, "r7", REG_TYPE_INT, "general" },
+ { ESIRISC_R8, "r8", REG_TYPE_INT, "general" },
+ { ESIRISC_R9, "r9", REG_TYPE_INT, "general" },
+ { ESIRISC_R10, "r10", REG_TYPE_INT, "general" },
+ { ESIRISC_R11, "r11", REG_TYPE_INT, "general" },
+ { ESIRISC_R12, "r12", REG_TYPE_INT, "general" },
+ { ESIRISC_R13, "r13", REG_TYPE_INT, "general" },
+ { ESIRISC_R14, "r14", REG_TYPE_INT, "general" },
+ { ESIRISC_R15, "r15", REG_TYPE_INT, "general" },
+ { ESIRISC_R16, "r16", REG_TYPE_INT, "general" },
+ { ESIRISC_R17, "r17", REG_TYPE_INT, "general" },
+ { ESIRISC_R18, "r18", REG_TYPE_INT, "general" },
+ { ESIRISC_R19, "r19", REG_TYPE_INT, "general" },
+ { ESIRISC_R20, "r20", REG_TYPE_INT, "general" },
+ { ESIRISC_R21, "r21", REG_TYPE_INT, "general" },
+ { ESIRISC_R22, "r22", REG_TYPE_INT, "general" },
+ { ESIRISC_R23, "r23", REG_TYPE_INT, "general" },
+ { ESIRISC_R24, "r24", REG_TYPE_INT, "general" },
+ { ESIRISC_R25, "r25", REG_TYPE_INT, "general" },
+ { ESIRISC_R26, "r26", REG_TYPE_INT, "general" },
+ { ESIRISC_R27, "r27", REG_TYPE_INT, "general" },
+ { ESIRISC_R28, "r28", REG_TYPE_INT, "general" },
+ { ESIRISC_R29, "r29", REG_TYPE_INT, "general" },
+ { ESIRISC_R30, "r30", REG_TYPE_INT, "general" },
+ { ESIRISC_R31, "r31", REG_TYPE_INT, "general" },
+};
+
+/*
+ * Control and Status Registers (CSRs) are largely defined as belonging
+ * to the system register group. The exception to this rule are the PC
+ * and CAS registers, which belong to the general group. While debug is
+ * active, EPC, ECAS, and ETC must be used to read and write the PC,
+ * CAS, and TC CSRs, respectively.
+ */
+static const struct {
+ enum esirisc_reg_num number;
+ uint8_t bank;
+ uint8_t csr;
+ const char *name;
+ enum reg_type type;
+ const char *group;
+} esirisc_csrs[] = {
+ { ESIRISC_PC, CSR_THREAD, CSR_THREAD_EPC, "PC", REG_TYPE_CODE_PTR, "general" }, /* PC -> EPC */
+ { ESIRISC_CAS, CSR_THREAD, CSR_THREAD_ECAS, "CAS", REG_TYPE_INT, "general" }, /* CAS -> ECAS */
+ { ESIRISC_TC, CSR_THREAD, CSR_THREAD_ETC, "TC", REG_TYPE_INT, "system" }, /* TC -> ETC */
+ { ESIRISC_ETA, CSR_THREAD, CSR_THREAD_ETA, "ETA", REG_TYPE_INT, "system" },
+ { ESIRISC_ETC, CSR_THREAD, CSR_THREAD_ETC, "ETC", REG_TYPE_INT, "system" },
+ { ESIRISC_EPC, CSR_THREAD, CSR_THREAD_EPC, "EPC", REG_TYPE_CODE_PTR, "system" },
+ { ESIRISC_ECAS, CSR_THREAD, CSR_THREAD_ECAS, "ECAS", REG_TYPE_INT, "system" },
+ { ESIRISC_EID, CSR_THREAD, CSR_THREAD_EID, "EID", REG_TYPE_INT, "system" },
+ { ESIRISC_ED, CSR_THREAD, CSR_THREAD_ED, "ED", REG_TYPE_INT, "system" },
+ { ESIRISC_IP, CSR_INTERRUPT, CSR_INTERRUPT_IP, "IP", REG_TYPE_INT, "system"},
+ { ESIRISC_IM, CSR_INTERRUPT, CSR_INTERRUPT_IM, "IM", REG_TYPE_INT, "system"},
+ { ESIRISC_IS, CSR_INTERRUPT, CSR_INTERRUPT_IS, "IS", REG_TYPE_INT, "system"},
+ { ESIRISC_IT, CSR_INTERRUPT, CSR_INTERRUPT_IT, "IT", REG_TYPE_INT, "system"},
+};
+
+static int esirisc_disable_interrupts(struct target *target)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+ uint32_t etc;
+ int retval;
+
+ LOG_DEBUG("-");
+
+ retval = esirisc_jtag_read_csr(jtag_info, CSR_THREAD, CSR_THREAD_ETC, &etc);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to read CSR: ETC", target_name(target));
+ return retval;
+ }
+
+ etc &= ~(1<<0); /* TC.I */
+
+ retval = esirisc_jtag_write_csr(jtag_info, CSR_THREAD, CSR_THREAD_ETC, etc);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to write CSR: ETC", target_name(target));
+ return retval;
+ }
+
+ return ERROR_OK;
+}
+
+#if 0
+static int esirisc_enable_interrupts(struct target *target)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+ uint32_t etc;
+ int retval;
+
+ LOG_DEBUG("-");
+
+ retval = esirisc_jtag_read_csr(jtag_info, CSR_THREAD, CSR_THREAD_ETC, &etc);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to read CSR: ETC", target_name(target));
+ return retval;
+ }
+
+ etc |= (1<<0); /* TC.I */
+
+ retval = esirisc_jtag_write_csr(jtag_info, CSR_THREAD, CSR_THREAD_ETC, etc);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to write CSR: ETC", target_name(target));
+ return retval;
+ }
+
+ return ERROR_OK;
+}
+#endif
+
+static int esirisc_save_interrupts(struct target *target)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+
+ LOG_DEBUG("-");
+
+ int retval = esirisc_jtag_read_csr(jtag_info, CSR_THREAD, CSR_THREAD_ETC,
+ &esirisc->etc_save);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to read CSR: ETC", target_name(target));
+ return retval;
+ }
+
+ return ERROR_OK;
+}
+
+static int esirisc_restore_interrupts(struct target *target)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+
+ LOG_DEBUG("-");
+
+ int retval = esirisc_jtag_write_csr(jtag_info, CSR_THREAD, CSR_THREAD_ETC,
+ esirisc->etc_save);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to write CSR: ETC", target_name(target));
+ return retval;
+ }
+
+ return ERROR_OK;
+}
+
+#if 0
+static int esirisc_save_hwdc(struct target *target)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+
+ LOG_DEBUG("-");
+
+ int retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_HWDC,
+ &esirisc->hwdc_save);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to read CSR: HWDC", target_name(target));
+ return retval;
+ }
+
+ return ERROR_OK;
+}
+#endif
+
+static int esirisc_restore_hwdc(struct target *target)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+
+ LOG_DEBUG("-");
+
+ int retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_HWDC,
+ esirisc->hwdc_save);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to write CSR: HWDC", target_name(target));
+ return retval;
+ }
+
+ return ERROR_OK;
+}
+
+static int esirisc_save_context(struct target *target)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+
+ LOG_DEBUG("-");
+
+ for (unsigned i = 0; i < esirisc->reg_cache->num_regs; ++i) {
+ struct reg *reg = esirisc->reg_cache->reg_list + i;
+ struct esirisc_reg *reg_info = reg->arch_info;
+
+ if (reg->exist && !reg->valid)
+ reg_info->read(reg);
+ }
+
+ return ERROR_OK;
+}
+
+static int esirisc_restore_context(struct target *target)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+
+ LOG_DEBUG("-");
+
+ for (unsigned i = 0; i < esirisc->reg_cache->num_regs; ++i) {
+ struct reg *reg = esirisc->reg_cache->reg_list + i;
+ struct esirisc_reg *reg_info = reg->arch_info;
+
+ if (reg->exist && reg->dirty)
+ reg_info->write(reg);
+ }
+
+ return ERROR_OK;
+}
+
+static int esirisc_flush_caches(struct target *target)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+
+ LOG_DEBUG("-");
+
+ if (target->state != TARGET_HALTED)
+ return ERROR_TARGET_NOT_HALTED;
+
+ int retval = esirisc_jtag_flush_caches(jtag_info);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to flush caches", target_name(target));
+ return retval;
+ }
+
+ return ERROR_OK;
+}
+
+static int esirisc_wait_debug_active(struct esirisc_common *esirisc, int ms)
+{
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+ int64_t t;
+
+ LOG_DEBUG("-");
+
+ t = timeval_ms();
+ for (;;) {
+ int retval = esirisc_jtag_enable_debug(jtag_info);
+ if (retval == ERROR_OK && esirisc_jtag_is_debug_active(jtag_info))
+ return retval;
+
+ if ((timeval_ms() - t) > ms)
+ return ERROR_TARGET_TIMEOUT;
+
+ alive_sleep(100);
+ }
+}
+
+static int esirisc_read_memory(struct target *target, target_addr_t address,
+ uint32_t size, uint32_t count, uint8_t *buffer)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+ int retval;
+
+ LOG_DEBUG("-");
+
+ int num_bits = 8 * size;
+ for (uint32_t i = 0; i < count; ++i) {
+ union esirisc_memory value;
+ void *value_p;
+
+ switch (size) {
+ case sizeof(value.word):
+ value_p = &value.word;
+ retval = esirisc_jtag_read_word(jtag_info, address, value_p);
+ break;
+
+ case sizeof(value.hword):
+ value_p = &value.hword;
+ retval = esirisc_jtag_read_hword(jtag_info, address, value_p);
+ break;
+
+ case sizeof(value.byte):
+ value_p = &value.byte;
+ retval = esirisc_jtag_read_byte(jtag_info, address, value_p);
+ break;
+
+ default:
+ LOG_ERROR("%s: unsupported size: %" PRIu32, target_name(target), size);
+ return ERROR_FAIL;
+ }
+
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to read address: 0x%" TARGET_PRIxADDR, target_name(target),
+ address);
+ return retval;
+ }
+
+ buf_cpy(value_p, buffer, num_bits);
+ address += size;
+ buffer += size;
+ }
+
+ return ERROR_OK;
+}
+
+static int esirisc_write_memory(struct target *target, target_addr_t address,
+ uint32_t size, uint32_t count, const uint8_t *buffer)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+ int retval;
+
+ LOG_DEBUG("-");
+
+ int num_bits = 8 * size;
+ for (uint32_t i = 0; i < count; ++i) {
+ union esirisc_memory value;
+
+ switch (size) {
+ case sizeof(value.word):
+ value.word = buf_get_u32(buffer, 0, num_bits);
+ retval = esirisc_jtag_write_word(jtag_info, address, value.word);
+ break;
+
+ case sizeof(value.hword):
+ value.hword = buf_get_u32(buffer, 0, num_bits);
+ retval = esirisc_jtag_write_hword(jtag_info, address, value.hword);
+ break;
+
+ case sizeof(value.byte):
+ value.byte = buf_get_u32(buffer, 0, num_bits);
+ retval = esirisc_jtag_write_byte(jtag_info, address, value.byte);
+ break;
+
+ default:
+ LOG_ERROR("%s: unsupported size: %" PRIu32, target_name(target), size);
+ return ERROR_FAIL;
+ }
+
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to write address: 0x%" TARGET_PRIxADDR, target_name(target),
+ address);
+ return retval;
+ }
+
+ address += size;
+ buffer += size;
+ }
+
+ return ERROR_OK;
+}
+
+static int esirisc_checksum_memory(struct target *target, target_addr_t address,
+ uint32_t count, uint32_t *checksum)
+{
+ return ERROR_FAIL; /* not supported */
+}
+
+static int esirisc_next_breakpoint(struct target *target)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct breakpoint **breakpoints_p = esirisc->breakpoints_p;
+ struct breakpoint **breakpoints_e = breakpoints_p + esirisc->num_breakpoints;
+
+ LOG_DEBUG("-");
+
+ for (int bp_index = 0; breakpoints_p < breakpoints_e; ++breakpoints_p, ++bp_index)
+ if (*breakpoints_p == NULL)
+ return bp_index;
+
+ return -1;
+}
+
+static int esirisc_add_breakpoint(struct target *target, struct breakpoint *breakpoint)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+ int bp_index;
+ uint32_t ibc;
+ int retval;
+
+ LOG_DEBUG("-");
+
+ /*
+ * The default linker scripts provided by the eSi-RISC toolchain do
+ * not specify attributes on memory regions, which results in
+ * incorrect application of software breakpoints by GDB. Targets
+ * must be configured with `gdb_breakpoint_override hard` as
+ * software breakpoints are not supported.
+ */
+ if (breakpoint->type != BKPT_HARD)
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+
+ bp_index = esirisc_next_breakpoint(target);
+ if (bp_index < 0) {
+ LOG_ERROR("%s: out of hardware breakpoints", target_name(target));
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+
+ breakpoint->set = bp_index + 1;
+ esirisc->breakpoints_p[bp_index] = breakpoint;
+
+ /* specify instruction breakpoint address */
+ retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_IBAn + bp_index,
+ breakpoint->address);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to write CSR: IBA", target_name(target));
+ return retval;
+ }
+
+ /* enable instruction breakpoint */
+ retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_IBC, &ibc);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to read CSR: IBC", target_name(target));
+ return retval;
+ }
+
+ ibc |= (1 << bp_index); /* IBC.In */
+
+ retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_IBC, ibc);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to write CSR: IBC", target_name(target));
+ return retval;
+ }
+
+ return ERROR_OK;
+}
+
+static int esirisc_add_breakpoints(struct target *target)
+{
+ struct breakpoint *breakpoint = target->breakpoints;
+
+ LOG_DEBUG("-");
+
+ while (breakpoint != NULL) {
+ if (breakpoint->set == 0)
+ esirisc_add_breakpoint(target, breakpoint);
+
+ breakpoint = breakpoint->next;
+ }
+
+ return ERROR_OK;
+}
+
+static int esirisc_remove_breakpoint(struct target *target, struct breakpoint *breakpoint)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+ int bp_index = breakpoint->set - 1;
+ uint32_t ibc;
+ int retval;
+
+ LOG_DEBUG("-");
+
+ /* disable instruction breakpoint */
+ retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_IBC, &ibc);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to read CSR: IBC", target_name(target));
+ return retval;
+ }
+
+ ibc &= ~(1 << bp_index); /* IBC.In */
+
+ retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_IBC, ibc);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to write CSR: IBC", target_name(target));
+ return retval;
+ }
+
+ esirisc->breakpoints_p[bp_index] = NULL;
+ breakpoint->set = 0;
+
+ return ERROR_OK;
+}
+
+static int esirisc_remove_breakpoints(struct target *target)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+
+ LOG_DEBUG("-");
+
+ /* clear instruction breakpoints */
+ int retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_IBC, 0);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to write CSR: IBC", target_name(target));
+ return retval;
+ }
+
+ memset(esirisc->breakpoints_p, 0, sizeof(esirisc->breakpoints_p));
+
+ return ERROR_OK;
+}
+
+static int esirisc_next_watchpoint(struct target *target)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct watchpoint **watchpoints_p = esirisc->watchpoints_p;
+ struct watchpoint **watchpoints_e = watchpoints_p + esirisc->num_watchpoints;
+
+ LOG_DEBUG("-");
+
+ for (int wp_index = 0; watchpoints_p < watchpoints_e; ++watchpoints_p, ++wp_index)
+ if (*watchpoints_p == NULL)
+ return wp_index;
+
+ return -1;
+}
+
+static int esirisc_add_watchpoint(struct target *target, struct watchpoint *watchpoint)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+ int wp_index;
+ uint32_t dbs, dbc;
+ int retval;
+
+ LOG_DEBUG("-");
+
+ wp_index = esirisc_next_watchpoint(target);
+ if (wp_index < 0) {
+ LOG_ERROR("%s: out of hardware watchpoints", target_name(target));
+ return ERROR_FAIL;
+ }
+
+ watchpoint->set = wp_index + 1;
+ esirisc->watchpoints_p[wp_index] = watchpoint;
+
+ /* specify data breakpoint address */
+ retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBAn + wp_index,
+ watchpoint->address);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to write CSR: DBA", target_name(target));
+ return retval;
+ }
+
+ /* specify data breakpoint size */
+ retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBS, &dbs);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to read CSR: DBS", target_name(target));
+ return retval;
+ }
+
+ uint32_t sn;
+ switch (watchpoint->length) {
+ case sizeof(uint64_t):
+ sn = 0x3;
+ break;
+ case sizeof(uint32_t):
+ sn = 0x2;
+ break;
+
+ case sizeof(uint16_t):
+ sn = 0x1;
+ break;
+
+ case sizeof(uint8_t):
+ sn = 0x0;
+ break;
+
+ default:
+ LOG_ERROR("%s: unsupported length: %" PRIu32, target_name(target),
+ watchpoint->length);
+ return ERROR_FAIL;
+ }
+
+ dbs |= (sn << (2 * wp_index)); /* DBS.Sn */
+
+ retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBS, dbs);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to write CSR: DBS", target_name(target));
+ return retval;
+ }
+
+ /* enable data breakpoint */
+ retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBC, &dbc);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to read CSR: DBC", target_name(target));
+ return retval;
+ }
+
+ uint32_t dn;
+ switch (watchpoint->rw) {
+ case WPT_READ:
+ dn = 0x1;
+ break;
+
+ case WPT_WRITE:
+ dn = 0x2;
+ break;
+
+ case WPT_ACCESS:
+ dn = 0x3;
+ break;
+
+ default:
+ LOG_ERROR("%s: unsupported rw: %" PRId32, target_name(target),
+ watchpoint->rw);
+ return ERROR_FAIL;
+ }
+
+ dbc |= (dn << (2 * wp_index)); /* DBC.Dn */
+
+ retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBC, dbc);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to write CSR: DBC", target_name(target));
+ return retval;
+ }
+
+ return ERROR_OK;
+}
+
+static int esirisc_add_watchpoints(struct target *target)
+{
+ struct watchpoint *watchpoint = target->watchpoints;
+
+ LOG_DEBUG("-");
+
+ while (watchpoint != NULL) {
+ if (watchpoint->set == 0)
+ esirisc_add_watchpoint(target, watchpoint);
+
+ watchpoint = watchpoint->next;
+ }
+
+ return ERROR_OK;
+}
+
+static int esirisc_remove_watchpoint(struct target *target, struct watchpoint *watchpoint)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+ int wp_index = watchpoint->set - 1;
+ uint32_t dbc;
+ int retval;
+
+ LOG_DEBUG("-");
+
+ /* disable data breakpoint */
+ retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBC, &dbc);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to read CSR: DBC", target_name(target));
+ return retval;
+ }
+
+ dbc &= ~(0x3 << (2 * wp_index)); /* DBC.Dn */
+
+ retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBC, dbc);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to write CSR: DBC", target_name(target));
+ return retval;
+ }
+
+ esirisc->watchpoints_p[wp_index] = NULL;
+ watchpoint->set = 0;
+
+ return ERROR_OK;
+}
+
+static int esirisc_remove_watchpoints(struct target *target)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+
+ LOG_DEBUG("-");
+
+ /* clear data breakpoints */
+ int retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBC, 0);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to write CSR: DBC", target_name(target));
+ return retval;
+ }
+
+ memset(esirisc->watchpoints_p, 0, sizeof(esirisc->watchpoints_p));
+
+ return ERROR_OK;
+}
+
+static int esirisc_halt(struct target *target)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+
+ LOG_DEBUG("-");
+
+ if (target->state == TARGET_HALTED)
+ return ERROR_OK;
+
+ int retval = esirisc_jtag_break(jtag_info);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to halt target", target_name(target));
+ return retval;
+ }
+
+ target->debug_reason = DBG_REASON_DBGRQ;
+
+ return ERROR_OK;
+}
+
+static int esirisc_disable_step(struct target *target)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+ uint32_t dc;
+ int retval;
+
+ LOG_DEBUG("-");
+
+ retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DC, &dc);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to read CSR: DC", target_name(target));
+ return retval;
+ }
+
+ dc &= ~(1<<0); /* DC.S */
+
+ retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DC, dc);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to write CSR: DC", target_name(target));
+ return retval;
+ }
+
+ return ERROR_OK;
+}
+
+static int esirisc_enable_step(struct target *target)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+ uint32_t dc;
+ int retval;
+
+ LOG_DEBUG("-");
+
+ retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DC, &dc);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to read CSR: DC", target_name(target));
+ return retval;
+ }
+
+ dc |= (1<<0); /* DC.S */
+
+ retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DC, dc);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to write CSR: DC", target_name(target));
+ return retval;
+ }
+
+ return ERROR_OK;
+}
+
+static int esirisc_resume_or_step(struct target *target, int current, target_addr_t address,
+ int handle_breakpoints, int debug_execution, bool step)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+ struct breakpoint *breakpoint = NULL;
+ int retval;
+
+ LOG_DEBUG("-");
+
+ if (target->state != TARGET_HALTED)
+ return ERROR_TARGET_NOT_HALTED;
+
+ if (!debug_execution) {
+ target_free_all_working_areas(target);
+ esirisc_add_breakpoints(target);
+ esirisc_add_watchpoints(target);
+ }
+
+ if (current)
+ address = buf_get_u32(esirisc->epc->value, 0, esirisc->epc->size);
+ else {
+ buf_set_u32(esirisc->epc->value, 0, esirisc->epc->size, address);
+ esirisc->epc->dirty = true;
+ esirisc->epc->valid = true;
+ }
+
+ esirisc_restore_context(target);
+
+ if (esirisc_has_cache(esirisc))
+ esirisc_flush_caches(target);
+
+ if (handle_breakpoints) {
+ breakpoint = breakpoint_find(target, address);
+ if (breakpoint != NULL)
+ esirisc_remove_breakpoint(target, breakpoint);
+ }
+
+ if (step) {
+ esirisc_disable_interrupts(target);
+ esirisc_enable_step(target);
+ target->debug_reason = DBG_REASON_SINGLESTEP;
+ } else {
+ esirisc_disable_step(target);
+ esirisc_restore_interrupts(target);
+ target->debug_reason = DBG_REASON_NOTHALTED;
+ }
+
+ esirisc_restore_hwdc(target);
+
+ retval = esirisc_jtag_continue(jtag_info);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to resume target", target_name(target));
+ return retval;
+ }
+
+ register_cache_invalidate(esirisc->reg_cache);
+
+ if (!debug_execution) {
+ target->state = TARGET_RUNNING;
+ target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
+ } else {
+ target->state = TARGET_DEBUG_RUNNING;
+ target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED);
+ }
+
+ return ERROR_OK;
+}
+
+static int esirisc_resume(struct target *target, int current, target_addr_t address,
+ int handle_breakpoints, int debug_execution)
+{
+ LOG_DEBUG("-");
+
+ return esirisc_resume_or_step(target, current, address,
+ handle_breakpoints, debug_execution, false);
+}
+
+static int esirisc_step(struct target *target, int current, target_addr_t address,
+ int handle_breakpoints)
+{
+ LOG_DEBUG("-");
+
+ return esirisc_resume_or_step(target, current, address,
+ handle_breakpoints, 0, true);
+}
+
+static int esirisc_debug_step(struct target *target)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+ int retval;
+
+ LOG_DEBUG("-");
+
+ esirisc_disable_interrupts(target);
+ esirisc_enable_step(target);
+
+ retval = esirisc_jtag_continue(jtag_info);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to resume target", target_name(target));
+ return retval;
+ }
+
+ retval = esirisc_wait_debug_active(esirisc, STEP_TIMEOUT);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: step timed out", target_name(target));
+ return retval;
+ }
+
+ esirisc_disable_step(target);
+ esirisc_restore_interrupts(target);
+
+ return ERROR_OK;
+}
+
+static int esirisc_debug_reset(struct target *target)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+ int retval;
+
+ LOG_DEBUG("-");
+
+ retval = esirisc_jtag_assert_reset(jtag_info);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to assert reset", target_name(target));
+ return retval;
+ }
+
+ retval = esirisc_jtag_deassert_reset(jtag_info);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to deassert reset", target_name(target));
+ return retval;
+ }
+
+ retval = esirisc_wait_debug_active(esirisc, RESET_TIMEOUT);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: reset timed out", target_name(target));
+ return retval;
+ }
+
+ return ERROR_OK;
+}
+
+static int esirisc_debug_enable(struct target *target)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+ int retval;
+
+ LOG_DEBUG("-");
+
+ retval = esirisc_jtag_enable_debug(jtag_info);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to enable debug mode", target_name(target));
+ return retval;
+ }
+
+ /*
+ * The debug clock is inactive until the first command is sent.
+ * If the target is stopped, we must first issue a reset before
+ * attempting further communication. This also handles unpowered
+ * targets, which will respond with all ones and appear active.
+ */
+ if (esirisc_jtag_is_stopped(jtag_info)) {
+ LOG_INFO("%s: debug clock inactive; attempting debug reset", target_name(target));
+ retval = esirisc_debug_reset(target);
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (esirisc_jtag_is_stopped(jtag_info)) {
+ LOG_ERROR("%s: target unresponsive; giving up", target_name(target));
+ return ERROR_FAIL;
+ }
+ }
+
+ return ERROR_OK;
+}
+
+static int esirisc_debug_entry(struct target *target)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct breakpoint *breakpoint;
+
+ LOG_DEBUG("-");
+
+ esirisc_save_context(target);
+
+ if (esirisc_has_cache(esirisc))
+ esirisc_flush_caches(target);
+
+ if (target->debug_reason != DBG_REASON_SINGLESTEP) {
+ esirisc_save_interrupts(target);
+
+ uint32_t eid = buf_get_u32(esirisc->eid->value, 0, esirisc->eid->size);
+ switch (eid) {
+ /*
+ * InstBreakpoint exceptions are also raised when a core is
+ * halted for debugging. The following is required to
+ * determine if a breakpoint was encountered.
+ */
+ case EID_INST_BREAKPOINT:
+ breakpoint = breakpoint_find(target,
+ buf_get_u32(esirisc->epc->value, 0, esirisc->epc->size));
+ target->debug_reason = (breakpoint != NULL) ?
+ DBG_REASON_BREAKPOINT : DBG_REASON_DBGRQ;
+ break;
+
+ /*
+ * eSi-RISC treats watchpoints similarly to breakpoints,
+ * however GDB will not request to step over the current
+ * instruction when a watchpoint fires. The following is
+ * required to resume the target.
+ */
+ case EID_DATA_BREAKPOINT:
+ esirisc_remove_watchpoints(target);
+ esirisc_debug_step(target);
+ esirisc_add_watchpoints(target);
+ target->debug_reason = DBG_REASON_WATCHPOINT;
+ break;
+
+ default:
+ target->debug_reason = DBG_REASON_DBGRQ;
+ }
+ }
+
+ return ERROR_OK;
+}
+
+static int esirisc_poll(struct target *target)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+ int retval;
+
+ retval = esirisc_jtag_enable_debug(jtag_info);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to poll target", target_name(target));
+ return retval;
+ }
+
+ if (esirisc_jtag_is_stopped(jtag_info)) {
+ LOG_ERROR("%s: target has stopped; reset required", target_name(target));
+ target->state = TARGET_UNKNOWN;
+ return ERROR_TARGET_FAILURE;
+ }
+
+ if (esirisc_jtag_is_debug_active(jtag_info)) {
+ if (target->state == TARGET_RUNNING || target->state == TARGET_RESET) {
+ target->state = TARGET_HALTED;
+
+ retval = esirisc_debug_entry(target);
+ if (retval != ERROR_OK)
+ return retval;
+
+ target_call_event_callbacks(target, TARGET_EVENT_HALTED);
+ }
+
+ } else if (target->state == TARGET_HALTED || target->state == TARGET_RESET) {
+ target->state = TARGET_RUNNING;
+ target_call_event_callbacks(target, TARGET_EVENT_RESUMED);
+ }
+
+ return ERROR_OK;
+}
+
+static int esirisc_assert_reset(struct target *target)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+ int retval;
+
+ LOG_DEBUG("-");
+
+ if (jtag_get_reset_config() & RESET_HAS_SRST) {
+ jtag_add_reset(1, 1);
+ if ((jtag_get_reset_config() & RESET_SRST_PULLS_TRST) == 0)
+ jtag_add_reset(0, 1);
+ } else {
+ esirisc_remove_breakpoints(target);
+ esirisc_remove_watchpoints(target);
+
+ retval = esirisc_jtag_assert_reset(jtag_info);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to assert reset", target_name(target));
+ return retval;
+ }
+ }
+
+ target->state = TARGET_RESET;
+
+ register_cache_invalidate(esirisc->reg_cache);
+
+ return ERROR_OK;
+}
+
+static int esirisc_reset_entry(struct target *target)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+ uint32_t eta, epc;
+ int retval;
+
+ LOG_DEBUG("-");
+
+ /* read exception table address */
+ retval = esirisc_jtag_read_csr(jtag_info, CSR_THREAD, CSR_THREAD_ETA, &eta);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to read CSR: ETA", target_name(target));
+ return retval;
+ }
+
+ /* read reset entry point */
+ retval = esirisc_jtag_read_word(jtag_info, eta + ENTRY_RESET, &epc);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to read address: 0x%" TARGET_PRIxADDR, target_name(target),
+ (target_addr_t)epc);
+ return retval;
+ }
+
+ /* write reset entry point */
+ retval = esirisc_jtag_write_csr(jtag_info, CSR_THREAD, CSR_THREAD_EPC, epc);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to write CSR: EPC", target_name(target));
+ return retval;
+ }
+
+ return ERROR_OK;
+}
+
+static int esirisc_deassert_reset(struct target *target)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+ int retval;
+
+ LOG_DEBUG("-");
+
+ if (jtag_get_reset_config() & RESET_HAS_SRST) {
+ jtag_add_reset(0, 0);
+
+ retval = esirisc_debug_enable(target);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = esirisc_debug_reset(target);
+ if (retval != ERROR_OK)
+ return retval;
+
+ } else {
+ retval = esirisc_jtag_deassert_reset(jtag_info);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to deassert reset", target_name(target));
+ return retval;
+ }
+ }
+
+ retval = esirisc_wait_debug_active(esirisc, RESET_TIMEOUT);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: reset timed out", target_name(target));
+ return retval;
+ }
+
+ retval = esirisc_reset_entry(target);
+ if (retval != ERROR_OK)
+ return retval;
+
+ esirisc_add_breakpoints(target);
+ esirisc_add_watchpoints(target);
+
+ esirisc_restore_hwdc(target);
+
+ if (!target->reset_halt) {
+ retval = esirisc_jtag_continue(jtag_info);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to resume target", target_name(target));
+ return retval;
+ }
+ }
+
+ return ERROR_OK;
+}
+
+static int esirisc_arch_state(struct target *target)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ uint32_t epc = buf_get_u32(esirisc->epc->value, 0, esirisc->epc->size);
+ uint32_t ecas = buf_get_u32(esirisc->ecas->value, 0, esirisc->ecas->size);
+ uint32_t eid = buf_get_u32(esirisc->eid->value, 0, esirisc->eid->size);
+ uint32_t ed = buf_get_u32(esirisc->ed->value, 0, esirisc->ed->size);
+
+ LOG_DEBUG("-");
+
+ const char *exception = "Unknown";
+ if (eid < ARRAY_SIZE(esirisc_exceptions))
+ exception = esirisc_exceptions[eid];
+
+ LOG_USER("target halted due to %s, exception: %s\n"
+ "EPC: 0x%" PRIx32 " ECAS: 0x%" PRIx32 " EID: 0x%" PRIx32 " ED: 0x%" PRIx32,
+ debug_reason_name(target), exception, epc, ecas, eid, ed);
+
+ return ERROR_OK;
+}
+
+static const char *esirisc_get_gdb_arch(struct target *target)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+
+ LOG_DEBUG("-");
+
+ /*
+ * Targets with the UNIFIED_ADDRESS_SPACE option disabled employ a
+ * Harvard architecture. This option is not exposed in a CSR, which
+ * requires additional configuration to properly interact with these
+ * targets in GDB (also see: `esirisc cache_arch`).
+ */
+ if (esirisc->gdb_arch == NULL && target_was_examined(target))
+ esirisc->gdb_arch = alloc_printf("esirisc:%d_bit_%d_reg_%s",
+ esirisc->num_bits, esirisc->num_regs, esirisc_cache_arch(esirisc));
+
+ return esirisc->gdb_arch;
+}
+
+static int esirisc_get_gdb_reg_list(struct target *target, struct reg **reg_list[],
+ int *reg_list_size, enum target_register_class reg_class)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+
+ LOG_DEBUG("-");
+
+ *reg_list_size = ESIRISC_NUM_REGS;
+
+ *reg_list = calloc(*reg_list_size, sizeof(struct reg *));
+ if (*reg_list == NULL)
+ return ERROR_FAIL;
+
+ if (reg_class == REG_CLASS_ALL)
+ for (int i = 0; i < *reg_list_size; ++i)
+ (*reg_list)[i] = esirisc->reg_cache->reg_list + i;
+ else {
+ for (int i = 0; i < esirisc->num_regs; ++i)
+ (*reg_list)[i] = esirisc->reg_cache->reg_list + i;
+
+ (*reg_list)[ESIRISC_PC] = esirisc->reg_cache->reg_list + ESIRISC_PC;
+ (*reg_list)[ESIRISC_CAS] = esirisc->reg_cache->reg_list + ESIRISC_CAS;
+ }
+
+ return ERROR_OK;
+}
+
+static int esirisc_read_reg(struct reg *reg)
+{
+ struct esirisc_reg *reg_info = reg->arch_info;
+ struct esirisc_common *esirisc = reg_info->esirisc;
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+ struct target *target = esirisc->target;
+ uint32_t data;
+
+ LOG_DEBUG("-");
+
+ int retval = esirisc_jtag_read_reg(jtag_info, reg->number, &data);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to read register: %s", target_name(target), reg->name);
+ return retval;
+ }
+
+ buf_set_u32(reg->value, 0, reg->size, data);
+ reg->dirty = false;
+ reg->valid = true;
+
+ return ERROR_OK;
+}
+
+static int esirisc_write_reg(struct reg *reg)
+{
+ struct esirisc_reg *reg_info = reg->arch_info;
+ struct esirisc_common *esirisc = reg_info->esirisc;
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+ struct target *target = esirisc->target;
+ uint32_t data = buf_get_u32(reg->value, 0, reg->size);
+
+ LOG_DEBUG("-");
+
+ int retval = esirisc_jtag_write_reg(jtag_info, reg->number, data);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to write register: %s", target_name(target), reg->name);
+ return retval;
+ }
+
+ reg->dirty = false;
+ reg->valid = true;
+
+ return ERROR_OK;
+}
+
+static int esirisc_read_csr(struct reg *reg)
+{
+ struct esirisc_reg *reg_info = reg->arch_info;
+ struct esirisc_common *esirisc = reg_info->esirisc;
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+ struct target *target = esirisc->target;
+ uint32_t data;
+
+ LOG_DEBUG("-");
+
+ int retval = esirisc_jtag_read_csr(jtag_info, reg_info->bank, reg_info->csr, &data);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to read CSR: %s", target_name(target), reg->name);
+ return retval;
+ }
+
+ buf_set_u32(reg->value, 0, reg->size, data);
+ reg->dirty = false;
+ reg->valid = true;
+
+ return ERROR_OK;
+}
+
+static int esirisc_write_csr(struct reg *reg)
+{
+ struct esirisc_reg *reg_info = reg->arch_info;
+ struct esirisc_common *esirisc = reg_info->esirisc;
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+ struct target *target = esirisc->target;
+ uint32_t data = buf_get_u32(reg->value, 0, reg->size);
+
+ LOG_DEBUG("-");
+
+ int retval = esirisc_jtag_write_csr(jtag_info, reg_info->bank, reg_info->csr, data);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to write CSR: %s", target_name(target), reg->name);
+ return retval;
+ }
+
+ reg->dirty = false;
+ reg->valid = true;
+
+ return ERROR_OK;
+}
+
+static int esirisc_get_reg(struct reg *reg)
+{
+ struct esirisc_reg *reg_info = reg->arch_info;
+ struct esirisc_common *esirisc = reg_info->esirisc;
+ struct target *target = esirisc->target;
+
+ LOG_DEBUG("-");
+
+ if (target->state != TARGET_HALTED)
+ return ERROR_TARGET_NOT_HALTED;
+
+ return reg_info->read(reg);
+}
+
+static int esirisc_set_reg(struct reg *reg, uint8_t *buf)
+{
+ struct esirisc_reg *reg_info = reg->arch_info;
+ struct esirisc_common *esirisc = reg_info->esirisc;
+ struct target *target = esirisc->target;
+ uint32_t value = buf_get_u32(buf, 0, reg->size);
+
+ LOG_DEBUG("-");
+
+ if (target->state != TARGET_HALTED)
+ return ERROR_TARGET_NOT_HALTED;
+
+ buf_set_u32(reg->value, 0, reg->size, value);
+ reg->dirty = true;
+ reg->valid = true;
+
+ return ERROR_OK;
+}
+
+static const struct reg_arch_type esirisc_reg_type = {
+ .get = esirisc_get_reg,
+ .set = esirisc_set_reg,
+};
+
+static struct reg_cache *esirisc_build_reg_cache(struct target *target)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache);
+ struct reg_cache *cache = malloc(sizeof(struct reg_cache));
+ struct reg *reg_list = calloc(ESIRISC_NUM_REGS, sizeof(struct reg));
+
+ LOG_DEBUG("-");
+
+ cache->name = "eSi-RISC registers";
+ cache->next = NULL;
+ cache->reg_list = reg_list;
+ cache->num_regs = ESIRISC_NUM_REGS;
+ (*cache_p) = cache;
+
+ esirisc->reg_cache = cache;
+ esirisc->epc = reg_list + ESIRISC_EPC;
+ esirisc->ecas = reg_list + ESIRISC_ECAS;
+ esirisc->eid = reg_list + ESIRISC_EID;
+ esirisc->ed = reg_list + ESIRISC_ED;
+
+ for (int i = 0; i < esirisc->num_regs; ++i) {
+ struct reg *reg = reg_list + esirisc_regs[i].number;
+ struct esirisc_reg *reg_info = calloc(1, sizeof(struct esirisc_reg));
+
+ reg->name = esirisc_regs[i].name;
+ reg->number = esirisc_regs[i].number;
+ reg->value = calloc(1, DIV_ROUND_UP(esirisc->num_bits, 8));
+ reg->size = esirisc->num_bits;
+ reg->reg_data_type = calloc(1, sizeof(struct reg_data_type));
+ reg->reg_data_type->type = esirisc_regs[i].type;
+ reg->group = esirisc_regs[i].group;
+ reg_info->esirisc = esirisc;
+ reg_info->read = esirisc_read_reg;
+ reg_info->write = esirisc_write_reg;
+ reg->arch_info = reg_info;
+ reg->type = &esirisc_reg_type;
+ reg->exist = true;
+ }
+
+ for (size_t i = 0; i < ARRAY_SIZE(esirisc_csrs); ++i) {
+ struct reg *reg = reg_list + esirisc_csrs[i].number;
+ struct esirisc_reg *reg_info = calloc(1, sizeof(struct esirisc_reg));
+
+ reg->name = esirisc_csrs[i].name;
+ reg->number = esirisc_csrs[i].number;
+ reg->value = calloc(1, DIV_ROUND_UP(esirisc->num_bits, 8));
+ reg->size = esirisc->num_bits;
+ reg->reg_data_type = calloc(1, sizeof(struct reg_data_type));
+ reg->reg_data_type->type = esirisc_csrs[i].type;
+ reg->group = esirisc_csrs[i].group;
+ reg_info->esirisc = esirisc;
+ reg_info->bank = esirisc_csrs[i].bank;
+ reg_info->csr = esirisc_csrs[i].csr;
+ reg_info->read = esirisc_read_csr;
+ reg_info->write = esirisc_write_csr;
+ reg->arch_info = reg_info;
+ reg->type = &esirisc_reg_type;
+ reg->exist = true;
+ }
+
+ return cache;
+}
+
+static int esirisc_identify(struct target *target)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+ uint32_t csr;
+ int retval;
+
+ LOG_DEBUG("-");
+
+ retval = esirisc_jtag_read_csr(jtag_info, CSR_CONFIG, CSR_CONFIG_ARCH0, &csr);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to read CSR: ARCH0", target_name(target));
+ return retval;
+ }
+
+ esirisc->num_bits = (csr >> 0) & 0x3f; /* ARCH0.B */
+ esirisc->num_regs = (csr >> 10) & 0x3f; /* ARCH0.R */
+
+ retval = esirisc_jtag_read_csr(jtag_info, CSR_CONFIG, CSR_CONFIG_MEM, &csr);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to read CSR: MEM", target_name(target));
+ return retval;
+ }
+
+ target->endianness = (csr & 1<<0) ? /* MEM.E */
+ TARGET_BIG_ENDIAN : TARGET_LITTLE_ENDIAN;
+
+ retval = esirisc_jtag_read_csr(jtag_info, CSR_CONFIG, CSR_CONFIG_IC, &csr);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to read CSR: IC", target_name(target));
+ return retval;
+ }
+
+ esirisc->has_icache = !!(csr & 1<<0); /* IC.E */
+
+ retval = esirisc_jtag_read_csr(jtag_info, CSR_CONFIG, CSR_CONFIG_DC, &csr);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to read CSR: DC", target_name(target));
+ return retval;
+ }
+
+ esirisc->has_dcache = !!(csr & 1<<0); /* DC.E */
+
+ retval = esirisc_jtag_read_csr(jtag_info, CSR_CONFIG, CSR_CONFIG_DBG, &csr);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to read CSR: DBG", target_name(target));
+ return retval;
+ }
+
+ esirisc->num_breakpoints = (csr >> 7) & 0xf; /* DBG.BP */
+ esirisc->num_watchpoints = (csr >> 12) & 0xf; /* DBG.WP */
+
+ return ERROR_OK;
+}
+
+static int esirisc_target_create(struct target *target, Jim_Interp *interp)
+{
+ struct jtag_tap *tap = target->tap;
+ struct esirisc_common *esirisc;
+
+ if (tap == NULL)
+ return ERROR_FAIL;
+
+ if (tap->ir_length != INSTR_LENGTH) {
+ LOG_ERROR("%s: invalid IR length; expected %d", target_name(target),
+ INSTR_LENGTH);
+ return ERROR_FAIL;
+ }
+
+ esirisc = calloc(1, sizeof(struct esirisc_common));
+ if (esirisc == NULL)
+ return ERROR_FAIL;
+
+ esirisc->target = target;
+ esirisc->jtag_info.tap = tap;
+ target->arch_info = esirisc;
+
+ return ERROR_OK;
+}
+
+static int esirisc_init_target(struct command_context *cmd_ctx, struct target *target)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+
+ /* trap reset, error, and debug exceptions */
+ esirisc->hwdc_save = HWDC_R | HWDC_E | HWDC_D;
+
+ return ERROR_OK;
+}
+
+static int esirisc_examine(struct target *target)
+{
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ struct esirisc_jtag *jtag_info = &esirisc->jtag_info;
+ int retval;
+
+ LOG_DEBUG("-");
+
+ if (!target_was_examined(target)) {
+ retval = esirisc_debug_enable(target);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /*
+ * In order to identify the target we must first halt the core.
+ * We quietly resume once identification has completed for those
+ * targets that were running when target_examine was called.
+ */
+ if (esirisc_jtag_is_debug_active(jtag_info)) {
+ if (target->state == TARGET_UNKNOWN)
+ target->debug_reason = DBG_REASON_DBGRQ;
+
+ target->state = TARGET_HALTED;
+ } else {
+ retval = esirisc_jtag_break(jtag_info);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to halt target", target_name(target));
+ return retval;
+ }
+
+ target->state = TARGET_RUNNING;
+ }
+
+ retval = esirisc_identify(target);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to identify target", target_name(target));
+ return retval;
+ }
+
+ esirisc_build_reg_cache(target);
+
+ esirisc_remove_breakpoints(target);
+ esirisc_remove_watchpoints(target);
+
+ esirisc_disable_step(target);
+ esirisc_restore_hwdc(target);
+
+ if (target->state == TARGET_HALTED)
+ esirisc_save_interrupts(target);
+ else {
+ retval = esirisc_jtag_continue(jtag_info);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("%s: failed to resume target", target_name(target));
+ return retval;
+ }
+ }
+
+ target_set_examined(target);
+
+ LOG_INFO("%s: %d bit, %d registers, %s%s%s", target_name(target),
+ esirisc->num_bits, esirisc->num_regs,
+ target_endianness(target),
+ esirisc->has_icache ? ", icache" : "",
+ esirisc->has_dcache ? ", dcache" : "");
+
+ LOG_INFO("%s: hardware has %d breakpoints, %d watchpoints", target_name(target),
+ esirisc->num_breakpoints, esirisc->num_watchpoints);
+ }
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_esirisc_cache_arch_command)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+
+ if (CMD_ARGC > 0) {
+ if (strcmp(*CMD_ARGV, "harvard") == 0)
+ esirisc->cache_arch = ESIRISC_CACHE_HARVARD;
+ else if (strcmp(*CMD_ARGV, "von_neumann") == 0)
+ esirisc->cache_arch = ESIRISC_CACHE_VON_NEUMANN;
+ else {
+ LOG_ERROR("invalid cache_arch: %s", *CMD_ARGV);
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+ }
+
+ command_print(CMD_CTX, "esirisc cache_arch %s", esirisc_cache_arch(esirisc));
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_esirisc_flush_caches_command)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+ int retval;
+
+ if (!esirisc_has_cache(esirisc)) {
+ LOG_ERROR("target does not support caching");
+ return ERROR_FAIL;
+ }
+
+ retval = esirisc_flush_caches(target);
+
+ command_print(CMD_CTX, "cache flush %s",
+ (retval == ERROR_OK) ? "successful" : "failed");
+
+ return retval;
+}
+
+static const struct {
+ const char *name;
+ int mask;
+} esirisc_hwdc_masks[] = {
+ { "reset", HWDC_R },
+ { "interrupt", HWDC_I },
+ { "syscall", HWDC_S },
+ { "error", HWDC_E },
+ { "debug", HWDC_D },
+};
+
+static int esirisc_find_hwdc_mask(const char *name)
+{
+ for (size_t i = 0; i < ARRAY_SIZE(esirisc_hwdc_masks); ++i)
+ if (strcmp(esirisc_hwdc_masks[i].name, name) == 0)
+ return esirisc_hwdc_masks[i].mask;
+
+ return -1;
+}
+
+COMMAND_HANDLER(handle_esirisc_hwdc_command)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ struct esirisc_common *esirisc = target_to_esirisc(target);
+
+ if (CMD_ARGC > 0) {
+ if (strcmp(CMD_ARGV[0], "all") == 0)
+ esirisc->hwdc_save = HWDC_R | HWDC_I | HWDC_S | HWDC_E | HWDC_D;
+ else {
+ esirisc->hwdc_save = 0;
+ if (strcmp(CMD_ARGV[0], "none") != 0) {
+ while (CMD_ARGC-- > 0) {
+ int mask = esirisc_find_hwdc_mask(CMD_ARGV[CMD_ARGC]);
+ if (mask < 0) {
+ LOG_ERROR("invalid mask: %s", CMD_ARGV[CMD_ARGC]);
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+ esirisc->hwdc_save |= mask;
+ }
+ }
+ }
+ }
+
+ for (size_t i = 0; i < ARRAY_SIZE(esirisc_hwdc_masks); ++i)
+ command_print(CMD_CTX, "%9s: %s", esirisc_hwdc_masks[i].name,
+ (esirisc->hwdc_save & esirisc_hwdc_masks[i].mask) ? "enabled" : "disabled");
+
+ return ERROR_OK;
+}
+
+static const struct command_registration esirisc_exec_command_handlers[] = {
+ {
+ .name = "cache_arch",
+ .handler = handle_esirisc_cache_arch_command,
+ .mode = COMMAND_ANY,
+ .help = "configure cache architecture",
+ .usage = "['harvard'|'von_neumann']",
+ },
+ {
+ .name = "flush_caches",
+ .handler = handle_esirisc_flush_caches_command,
+ .mode = COMMAND_EXEC,
+ .help = "flush instruction and data caches",
+ .usage = "",
+ },
+ {
+ .name = "hwdc",
+ .handler = handle_esirisc_hwdc_command,
+ .mode = COMMAND_ANY,
+ .help = "configure hardware debug control",
+ .usage = "['all'|'none'|mask ...]",
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+static const struct command_registration esirisc_command_handlers[] = {
+ {
+ .name = "esirisc",
+ .mode = COMMAND_ANY,
+ .help = "eSi-RISC command group",
+ .usage = "",
+ .chain = esirisc_exec_command_handlers,
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+struct target_type esirisc_target = {
+ .name = "esirisc",
+
+ .poll = esirisc_poll,
+ .arch_state = esirisc_arch_state,
+
+ .halt = esirisc_halt,
+ .resume = esirisc_resume,
+ .step = esirisc_step,
+
+ .assert_reset = esirisc_assert_reset,
+ .deassert_reset = esirisc_deassert_reset,
+
+ .get_gdb_arch = esirisc_get_gdb_arch,
+ .get_gdb_reg_list = esirisc_get_gdb_reg_list,
+
+ .read_memory = esirisc_read_memory,
+ .write_memory = esirisc_write_memory,
+ .checksum_memory = esirisc_checksum_memory,
+
+ .add_breakpoint = esirisc_add_breakpoint,
+ .remove_breakpoint = esirisc_remove_breakpoint,
+ .add_watchpoint = esirisc_add_watchpoint,
+ .remove_watchpoint = esirisc_remove_watchpoint,
+
+ .commands = esirisc_command_handlers,
+
+ .target_create = esirisc_target_create,
+ .init_target = esirisc_init_target,
+ .examine = esirisc_examine,
+};
diff --git a/src/target/esirisc.h b/src/target/esirisc.h
new file mode 100644
index 000000000..bb50652aa
--- /dev/null
+++ b/src/target/esirisc.h
@@ -0,0 +1,129 @@
+/***************************************************************************
+ * Copyright (C) 2018 by Square, Inc. *
+ * Steven Stallion *
+ * James Zhao *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see . *
+ ***************************************************************************/
+
+#ifndef OPENOCD_TARGET_ESIRISC_H
+#define OPENOCD_TARGET_ESIRISC_H
+
+#include
+#include
+#include
+
+#include "esirisc_jtag.h"
+#include "esirisc_regs.h"
+
+#define MAX_BREAKPOINTS 8
+#define MAX_WATCHPOINTS 8
+
+/* Exception IDs */
+#define EID_RESET 0x00
+#define EID_HARDWARE_FAILURE 0x01
+#define EID_NMI 0x02
+#define EID_INST_BREAKPOINT 0x03
+#define EID_DATA_BREAKPOINT 0x04
+#define EID_UNSUPPORTED 0x05
+#define EID_PRIVILEGE_VIOLATION 0x06
+#define EID_INST_BUS_ERROR 0x07
+#define EID_DATA_BUS_ERROR 0x08
+#define EID_ALIGNMENT_ERROR 0x09
+#define EID_ARITHMETIC_ERROR 0x0a
+#define EID_SYSTEM_CALL 0x0b
+#define EID_MEMORY_MANAGEMENT 0x0c
+#define EID_UNRECOVERABLE 0x0d
+#define EID_INTERRUPTn 0x20
+
+/* Exception Entry Points */
+#define ENTRY_RESET 0x00
+#define ENTRY_UNRECOVERABLE 0x01
+#define ENTRY_HARDWARE_FAILURE 0x02
+#define ENTRY_RUNTIME 0x03
+#define ENTRY_MEMORY 0x04
+#define ENTRY_SYSCALL 0x05
+#define ENTRY_DEBUG 0x06
+#define ENTRY_NMI 0x07
+#define ENTRY_INTERRUPTn 0x08
+
+/* Hardware Debug Control */
+#define HWDC_R (1<<4) /* Reset & Hardware Failure */
+#define HWDC_I (1<<3) /* Interrupts */
+#define HWDC_S (1<<2) /* System Calls */
+#define HWDC_E (1<<1) /* Program Errors */
+#define HWDC_D (1<<0) /* Debug Exceptions */
+
+enum esirisc_cache {
+ ESIRISC_CACHE_VON_NEUMANN,
+ ESIRISC_CACHE_HARVARD,
+};
+
+struct esirisc_common {
+ struct target *target;
+ struct esirisc_jtag jtag_info;
+ enum esirisc_cache cache_arch;
+ char *gdb_arch;
+
+ struct reg_cache *reg_cache;
+ struct reg *epc;
+ struct reg *ecas;
+ struct reg *eid;
+ struct reg *ed;
+ uint32_t etc_save;
+ uint32_t hwdc_save;
+
+ int num_bits;
+ int num_regs;
+ bool has_icache;
+ bool has_dcache;
+ int num_breakpoints;
+ int num_watchpoints;
+
+ struct breakpoint *breakpoints_p[MAX_BREAKPOINTS];
+ struct watchpoint *watchpoints_p[MAX_WATCHPOINTS];
+};
+
+union esirisc_memory {
+ uint32_t word;
+ uint16_t hword;
+ uint8_t byte;
+};
+
+struct esirisc_reg {
+ struct esirisc_common *esirisc;
+
+ uint8_t bank;
+ uint8_t csr;
+
+ int (*read)(struct reg *reg);
+ int (*write)(struct reg *reg);
+};
+
+static inline struct esirisc_common *target_to_esirisc(struct target *target)
+{
+ return (struct esirisc_common *)target->arch_info;
+}
+
+static inline char *esirisc_cache_arch(struct esirisc_common *esirisc)
+{
+ return esirisc->cache_arch == ESIRISC_CACHE_HARVARD ? "harvard" : "von_neumann";
+}
+
+static inline bool esirisc_has_cache(struct esirisc_common *esirisc)
+{
+ return esirisc->has_icache || esirisc->has_dcache;
+}
+
+#endif /* OPENOCD_TARGET_ESIRISC_H */
diff --git a/src/target/esirisc_jtag.c b/src/target/esirisc_jtag.c
new file mode 100644
index 000000000..8ab47fa8f
--- /dev/null
+++ b/src/target/esirisc_jtag.c
@@ -0,0 +1,514 @@
+/***************************************************************************
+ * Copyright (C) 2018 by Square, Inc. *
+ * Steven Stallion *
+ * James Zhao *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see . *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "esirisc_jtag.h"
+
+static void esirisc_jtag_set_instr(struct esirisc_jtag *jtag_info, uint32_t new_instr)
+{
+ struct jtag_tap *tap = jtag_info->tap;
+
+ if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != new_instr) {
+ struct scan_field field;
+ uint8_t t[4];
+
+ field.num_bits = tap->ir_length;
+ field.out_value = t;
+ buf_set_u32(t, 0, field.num_bits, new_instr);
+ field.in_value = NULL;
+
+ jtag_add_ir_scan(tap, &field, TAP_IDLE);
+ }
+}
+
+/*
+ * The data register is latched every 8 bits while in the Shift-DR state
+ * (Update-DR is not supported). This necessitates prepending padding
+ * bits to ensure data is aligned when multiple TAPs are present.
+ */
+static int esirisc_jtag_get_padding(void)
+{
+ int padding = 0;
+ int bypass_devices = 0;
+
+ for (struct jtag_tap *tap = jtag_tap_next_enabled(NULL); tap != NULL;
+ tap = jtag_tap_next_enabled(tap))
+ if (tap->bypass)
+ bypass_devices++;
+
+ int num_bits = bypass_devices % 8;
+ if (num_bits > 0)
+ padding = 8 - num_bits;
+
+ return padding;
+}
+
+static int esirisc_jtag_count_bits(int num_fields, struct scan_field *fields)
+{
+ int bit_count = 0;
+
+ for (int i = 0; i < num_fields; ++i)
+ bit_count += fields[i].num_bits;
+
+ return bit_count;
+}
+
+/*
+ * Data received from the target will be byte-stuffed if it contains
+ * either the pad byte (0xAA) or stuffing marker (0x55). Buffers should
+ * be sized twice the expected length to account for stuffing overhead.
+ */
+static void esirisc_jtag_unstuff(uint8_t *data, size_t len)
+{
+ uint8_t *r, *w;
+ uint8_t *end;
+
+ r = w = data;
+ end = data + len;
+ while (r < end) {
+ if (*r == STUFF_MARKER) {
+ r++; /* skip stuffing marker */
+ assert(r < end);
+ *w++ = *r++ ^ STUFF_MARKER;
+ } else
+ *w++ = *r++;
+ }
+}
+
+/*
+ * The eSi-Debug protocol defines a byte-oriented command/response
+ * channel that operates over serial or JTAG. While not strictly
+ * required, separate DR scans are used for sending and receiving data.
+ * This allows the TAP to recover gracefully if the byte stream is
+ * corrupted at the expense of sending additional padding bits.
+ */
+
+static int esirisc_jtag_send(struct esirisc_jtag *jtag_info, uint8_t command,
+ int num_out_fields, struct scan_field *out_fields)
+{
+ int num_fields = 2 + num_out_fields;
+ struct scan_field *fields = cmd_queue_alloc(num_fields * sizeof(struct scan_field));
+
+ esirisc_jtag_set_instr(jtag_info, INSTR_DEBUG);
+
+ fields[0].num_bits = esirisc_jtag_get_padding();
+ fields[0].out_value = NULL;
+ fields[0].in_value = NULL;
+
+ fields[1].num_bits = 8;
+ fields[1].out_value = &command;
+ fields[1].in_value = NULL;
+
+ /* append command data */
+ for (int i = 0; i < num_out_fields; ++i)
+ jtag_scan_field_clone(&fields[2+i], &out_fields[i]);
+
+ jtag_add_dr_scan(jtag_info->tap, num_fields, fields, TAP_IDLE);
+
+ return jtag_execute_queue();
+}
+
+static int esirisc_jtag_recv(struct esirisc_jtag *jtag_info,
+ int num_in_fields, struct scan_field *in_fields)
+{
+ int num_in_bits = esirisc_jtag_count_bits(num_in_fields, in_fields);
+ int num_in_bytes = DIV_ROUND_UP(num_in_bits, 8);
+
+ struct scan_field fields[3];
+ uint8_t r[num_in_bytes * 2];
+
+ esirisc_jtag_set_instr(jtag_info, INSTR_DEBUG);
+
+ fields[0].num_bits = esirisc_jtag_get_padding() + 1;
+ fields[0].out_value = NULL;
+ fields[0].in_value = NULL;
+
+ fields[1].num_bits = 8;
+ fields[1].out_value = NULL;
+ fields[1].in_value = &jtag_info->status;
+
+ fields[2].num_bits = num_in_bits * 2;
+ fields[2].out_value = NULL;
+ fields[2].in_value = r;
+
+ jtag_add_dr_scan(jtag_info->tap, ARRAY_SIZE(fields), fields, TAP_IDLE);
+
+ int retval = jtag_execute_queue();
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* unstuff response data and write back to caller */
+ if (num_in_fields > 0) {
+ esirisc_jtag_unstuff(r, ARRAY_SIZE(r));
+
+ int bit_count = 0;
+ for (int i = 0; i < num_in_fields; ++i) {
+ buf_set_buf(r, bit_count, in_fields[i].in_value, 0, in_fields[i].num_bits);
+ bit_count += in_fields[i].num_bits;
+ }
+ }
+
+ return ERROR_OK;
+}
+
+static int esirisc_jtag_check_status(struct esirisc_jtag *jtag_info)
+{
+ uint8_t eid = esirisc_jtag_get_eid(jtag_info);
+ if (eid != EID_NONE) {
+ LOG_ERROR("esirisc_jtag: bad status: 0x%02" PRIx32 " (DA: %" PRId32 ", "
+ "S: %" PRId32 ", EID: 0x%02" PRIx32 ")",
+ jtag_info->status, esirisc_jtag_is_debug_active(jtag_info),
+ esirisc_jtag_is_stopped(jtag_info), eid);
+ return ERROR_FAIL;
+ }
+
+ return ERROR_OK;
+}
+
+static int esirisc_jtag_send_and_recv(struct esirisc_jtag *jtag_info, uint8_t command,
+ int num_out_fields, struct scan_field *out_fields,
+ int num_in_fields, struct scan_field *in_fields)
+{
+ int retval;
+
+ jtag_info->status = 0; /* clear status */
+
+ retval = esirisc_jtag_send(jtag_info, command, num_out_fields, out_fields);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("esirisc_jtag: send failed (command: 0x%02" PRIx32 ")", command);
+ return ERROR_FAIL;
+ }
+
+ retval = esirisc_jtag_recv(jtag_info, num_in_fields, in_fields);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("esirisc_jtag: recv failed (command: 0x%02" PRIx32 ")", command);
+ return ERROR_FAIL;
+ }
+
+ return esirisc_jtag_check_status(jtag_info);
+}
+
+/*
+ * Status is automatically updated after each command completes;
+ * these functions make each field available to the caller.
+ */
+
+bool esirisc_jtag_is_debug_active(struct esirisc_jtag *jtag_info)
+{
+ return !!(jtag_info->status & 1<<7); /* DA */
+}
+
+bool esirisc_jtag_is_stopped(struct esirisc_jtag *jtag_info)
+{
+ return !!(jtag_info->status & 1<<6); /* S */
+}
+
+uint8_t esirisc_jtag_get_eid(struct esirisc_jtag *jtag_info)
+{
+ return jtag_info->status & 0x3f; /* EID */
+}
+
+/*
+ * Most commands manipulate target data (eg. memory and registers); each
+ * command returns a status byte that indicates success. Commands must
+ * transmit multibyte values in big-endian order, however response
+ * values are in little-endian order. Target endianness does not have an
+ * effect on this ordering.
+ */
+
+int esirisc_jtag_read_byte(struct esirisc_jtag *jtag_info, uint32_t address, uint8_t *data)
+{
+ struct scan_field out_fields[1];
+ uint8_t a[4];
+
+ out_fields[0].num_bits = 32;
+ out_fields[0].out_value = a;
+ h_u32_to_be(a, address);
+ out_fields[0].in_value = NULL;
+
+ struct scan_field in_fields[1];
+ uint8_t d[1];
+
+ in_fields[0].num_bits = 8;
+ in_fields[0].out_value = NULL;
+ in_fields[0].in_value = d;
+
+ int retval = esirisc_jtag_send_and_recv(jtag_info, DEBUG_READ_BYTE,
+ ARRAY_SIZE(out_fields), out_fields, ARRAY_SIZE(in_fields), in_fields);
+ if (retval != ERROR_OK)
+ return retval;
+
+ *data = *d;
+
+ return ERROR_OK;
+}
+
+int esirisc_jtag_read_hword(struct esirisc_jtag *jtag_info, uint32_t address, uint16_t *data)
+{
+ struct scan_field out_fields[1];
+ uint8_t a[4];
+
+ out_fields[0].num_bits = 32;
+ out_fields[0].out_value = a;
+ h_u32_to_be(a, address);
+ out_fields[0].in_value = NULL;
+
+ struct scan_field in_fields[1];
+ uint8_t d[2];
+
+ in_fields[0].num_bits = 16;
+ in_fields[0].out_value = NULL;
+ in_fields[0].in_value = d;
+
+ int retval = esirisc_jtag_send_and_recv(jtag_info, DEBUG_READ_HWORD,
+ ARRAY_SIZE(out_fields), out_fields, ARRAY_SIZE(in_fields), in_fields);
+ if (retval != ERROR_OK)
+ return retval;
+
+ *data = le_to_h_u16(d);
+
+ return ERROR_OK;
+}
+
+int esirisc_jtag_read_word(struct esirisc_jtag *jtag_info, uint32_t address, uint32_t *data)
+{
+ struct scan_field out_fields[1];
+ uint8_t a[4];
+
+ out_fields[0].num_bits = 32;
+ out_fields[0].out_value = a;
+ h_u32_to_be(a, address);
+ out_fields[0].in_value = NULL;
+
+ struct scan_field in_fields[1];
+ uint8_t d[4];
+
+ in_fields[0].num_bits = 32;
+ in_fields[0].out_value = NULL;
+ in_fields[0].in_value = d;
+
+ int retval = esirisc_jtag_send_and_recv(jtag_info, DEBUG_READ_WORD,
+ ARRAY_SIZE(out_fields), out_fields, ARRAY_SIZE(in_fields), in_fields);
+ if (retval != ERROR_OK)
+ return retval;
+
+ *data = le_to_h_u32(d);
+
+ return ERROR_OK;
+}
+
+int esirisc_jtag_write_byte(struct esirisc_jtag *jtag_info, uint32_t address, uint8_t data)
+{
+ struct scan_field out_fields[2];
+ uint8_t a[4];
+
+ out_fields[0].num_bits = 32;
+ out_fields[0].out_value = a;
+ h_u32_to_be(a, address);
+ out_fields[0].in_value = NULL;
+
+ out_fields[1].num_bits = 8;
+ out_fields[1].out_value = &data;
+ out_fields[1].in_value = NULL;
+
+ return esirisc_jtag_send_and_recv(jtag_info, DEBUG_WRITE_BYTE,
+ ARRAY_SIZE(out_fields), out_fields, 0, NULL);
+}
+
+int esirisc_jtag_write_hword(struct esirisc_jtag *jtag_info, uint32_t address, uint16_t data)
+{
+ struct scan_field out_fields[2];
+ uint8_t a[4], d[2];
+
+ out_fields[0].num_bits = 32;
+ out_fields[0].out_value = a;
+ h_u32_to_be(a, address);
+ out_fields[0].in_value = NULL;
+
+ out_fields[1].num_bits = 16;
+ out_fields[1].out_value = d;
+ h_u16_to_be(d, data);
+ out_fields[1].in_value = NULL;
+
+ return esirisc_jtag_send_and_recv(jtag_info, DEBUG_WRITE_HWORD,
+ ARRAY_SIZE(out_fields), out_fields, 0, NULL);
+}
+
+int esirisc_jtag_write_word(struct esirisc_jtag *jtag_info, uint32_t address, uint32_t data)
+{
+ struct scan_field out_fields[2];
+ uint8_t a[4], d[4];
+
+ out_fields[0].num_bits = 32;
+ out_fields[0].out_value = a;
+ h_u32_to_be(a, address);
+ out_fields[0].in_value = NULL;
+
+ out_fields[1].num_bits = 32;
+ out_fields[1].out_value = d;
+ h_u32_to_be(d, data);
+ out_fields[1].in_value = NULL;
+
+ return esirisc_jtag_send_and_recv(jtag_info, DEBUG_WRITE_WORD,
+ ARRAY_SIZE(out_fields), out_fields, 0, NULL);
+}
+
+int esirisc_jtag_read_reg(struct esirisc_jtag *jtag_info, uint8_t reg, uint32_t *data)
+{
+ struct scan_field out_fields[1];
+
+ out_fields[0].num_bits = 8;
+ out_fields[0].out_value = ®
+ out_fields[0].in_value = NULL;
+
+ struct scan_field in_fields[1];
+ uint8_t d[4];
+
+ in_fields[0].num_bits = 32;
+ in_fields[0].out_value = NULL;
+ in_fields[0].in_value = d;
+
+ int retval = esirisc_jtag_send_and_recv(jtag_info, DEBUG_READ_REG,
+ ARRAY_SIZE(out_fields), out_fields, ARRAY_SIZE(in_fields), in_fields);
+ if (retval != ERROR_OK)
+ return retval;
+
+ *data = le_to_h_u32(d);
+
+ return ERROR_OK;
+}
+
+int esirisc_jtag_write_reg(struct esirisc_jtag *jtag_info, uint8_t reg, uint32_t data)
+{
+ struct scan_field out_fields[2];
+ uint8_t d[4];
+
+ out_fields[0].num_bits = 8;
+ out_fields[0].out_value = ®
+ out_fields[0].in_value = NULL;
+
+ out_fields[1].num_bits = 32;
+ out_fields[1].out_value = d;
+ h_u32_to_be(d, data);
+ out_fields[1].in_value = NULL;
+
+ return esirisc_jtag_send_and_recv(jtag_info, DEBUG_WRITE_REG,
+ ARRAY_SIZE(out_fields), out_fields, 0, NULL);
+}
+
+int esirisc_jtag_read_csr(struct esirisc_jtag *jtag_info, uint8_t bank, uint8_t csr, uint32_t *data)
+{
+ struct scan_field out_fields[1];
+ uint8_t c[2];
+
+ out_fields[0].num_bits = 16;
+ out_fields[0].out_value = c;
+ h_u16_to_be(c, (csr << 5) | bank);
+ out_fields[0].in_value = NULL;
+
+ struct scan_field in_fields[1];
+ uint8_t d[4];
+
+ in_fields[0].num_bits = 32;
+ in_fields[0].out_value = NULL;
+ in_fields[0].in_value = d;
+
+ int retval = esirisc_jtag_send_and_recv(jtag_info, DEBUG_READ_CSR,
+ ARRAY_SIZE(out_fields), out_fields, ARRAY_SIZE(in_fields), in_fields);
+ if (retval != ERROR_OK)
+ return retval;
+
+ *data = le_to_h_u32(d);
+
+ return ERROR_OK;
+}
+
+int esirisc_jtag_write_csr(struct esirisc_jtag *jtag_info, uint8_t bank, uint8_t csr, uint32_t data)
+{
+ struct scan_field out_fields[2];
+ uint8_t c[2], d[4];
+
+ out_fields[0].num_bits = 16;
+ out_fields[0].out_value = c;
+ h_u16_to_be(c, (csr << 5) | bank);
+ out_fields[0].in_value = NULL;
+
+ out_fields[1].num_bits = 32;
+ out_fields[1].out_value = d;
+ h_u32_to_be(d, data);
+ out_fields[1].in_value = NULL;
+
+ return esirisc_jtag_send_and_recv(jtag_info, DEBUG_WRITE_CSR,
+ ARRAY_SIZE(out_fields), out_fields, 0, NULL);
+}
+
+/*
+ * Control commands affect CPU operation; these commands send no data
+ * and return a status byte.
+ */
+
+static inline int esirisc_jtag_send_ctrl(struct esirisc_jtag *jtag_info, uint8_t command)
+{
+ return esirisc_jtag_send_and_recv(jtag_info, command, 0, NULL, 0, NULL);
+}
+
+int esirisc_jtag_enable_debug(struct esirisc_jtag *jtag_info)
+{
+ return esirisc_jtag_send_ctrl(jtag_info, DEBUG_ENABLE_DEBUG);
+}
+
+int esirisc_jtag_disable_debug(struct esirisc_jtag *jtag_info)
+{
+ return esirisc_jtag_send_ctrl(jtag_info, DEBUG_DISABLE_DEBUG);
+}
+
+int esirisc_jtag_assert_reset(struct esirisc_jtag *jtag_info)
+{
+ return esirisc_jtag_send_ctrl(jtag_info, DEBUG_ASSERT_RESET);
+}
+
+int esirisc_jtag_deassert_reset(struct esirisc_jtag *jtag_info)
+{
+ return esirisc_jtag_send_ctrl(jtag_info, DEBUG_DEASSERT_RESET);
+}
+
+int esirisc_jtag_break(struct esirisc_jtag *jtag_info)
+{
+ return esirisc_jtag_send_ctrl(jtag_info, DEBUG_BREAK);
+}
+
+int esirisc_jtag_continue(struct esirisc_jtag *jtag_info)
+{
+ return esirisc_jtag_send_ctrl(jtag_info, DEBUG_CONTINUE);
+}
+
+int esirisc_jtag_flush_caches(struct esirisc_jtag *jtag_info)
+{
+ return esirisc_jtag_send_ctrl(jtag_info, DEBUG_FLUSH_CACHES);
+}
diff --git a/src/target/esirisc_jtag.h b/src/target/esirisc_jtag.h
new file mode 100644
index 000000000..8189ddc6c
--- /dev/null
+++ b/src/target/esirisc_jtag.h
@@ -0,0 +1,104 @@
+/***************************************************************************
+ * Copyright (C) 2018 by Square, Inc. *
+ * Steven Stallion *
+ * James Zhao *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see . *
+ ***************************************************************************/
+
+#ifndef OPENOCD_TARGET_ESIRISC_JTAG_H
+#define OPENOCD_TARGET_ESIRISC_JTAG_H
+
+#include
+
+/* TAP Instructions */
+#define INSTR_IDCODE 0x8
+#define INSTR_DEBUG 0x9
+#define INSTR_BYPASS 0xf
+#define INSTR_LENGTH 4
+
+/* eSi-Debug Commands */
+#define DEBUG_NOP 0x00
+#define DEBUG_READ_BYTE 0x10
+#define DEBUG_READ_HWORD 0x20
+#define DEBUG_READ_WORD 0x30
+#define DEBUG_WRITE_BYTE 0x60
+#define DEBUG_WRITE_HWORD 0x70
+#define DEBUG_WRITE_WORD 0x80
+#define DEBUG_READ_REG 0xb0
+#define DEBUG_WRITE_REG 0xc0
+#define DEBUG_READ_CSR 0xd0
+#define DEBUG_WRITE_CSR 0xe0
+#define DEBUG_ENABLE_DEBUG 0xf0
+#define DEBUG_DISABLE_DEBUG 0xf2
+#define DEBUG_ASSERT_RESET 0xf4
+#define DEBUG_DEASSERT_RESET 0xf6
+#define DEBUG_BREAK 0xf8
+#define DEBUG_CONTINUE 0xfa
+#define DEBUG_FLUSH_CACHES 0xfc
+
+/* Exception IDs */
+#define EID_OVERFLOW 0x3d
+#define EID_CANT_DEBUG 0x3e
+#define EID_NONE 0x3f
+
+/* Byte Stuffing */
+#define STUFF_MARKER 0x55
+#define PAD_BYTE 0xaa
+
+struct esirisc_jtag {
+ struct jtag_tap *tap;
+ uint8_t status;
+};
+
+bool esirisc_jtag_is_debug_active(struct esirisc_jtag *jtag_info);
+bool esirisc_jtag_is_stopped(struct esirisc_jtag *jtag_info);
+uint8_t esirisc_jtag_get_eid(struct esirisc_jtag *jtag_info);
+
+int esirisc_jtag_read_byte(struct esirisc_jtag *jtag_info,
+ uint32_t address, uint8_t *data);
+int esirisc_jtag_read_hword(struct esirisc_jtag *jtag_info,
+ uint32_t address, uint16_t *data);
+int esirisc_jtag_read_word(struct esirisc_jtag *jtag_info,
+ uint32_t address, uint32_t *data);
+
+int esirisc_jtag_write_byte(struct esirisc_jtag *jtag_info,
+ uint32_t address, uint8_t data);
+int esirisc_jtag_write_hword(struct esirisc_jtag *jtag_info,
+ uint32_t address, uint16_t data);
+int esirisc_jtag_write_word(struct esirisc_jtag *jtag_info,
+ uint32_t address, uint32_t data);
+
+int esirisc_jtag_read_reg(struct esirisc_jtag *jtag_info,
+ uint8_t reg, uint32_t *data);
+int esirisc_jtag_write_reg(struct esirisc_jtag *jtag_info,
+ uint8_t reg, uint32_t data);
+
+int esirisc_jtag_read_csr(struct esirisc_jtag *jtag_info,
+ uint8_t bank, uint8_t csr, uint32_t *data);
+int esirisc_jtag_write_csr(struct esirisc_jtag *jtag_info,
+ uint8_t bank, uint8_t csr, uint32_t data);
+
+int esirisc_jtag_enable_debug(struct esirisc_jtag *jtag_info);
+int esirisc_jtag_disable_debug(struct esirisc_jtag *jtag_info);
+
+int esirisc_jtag_assert_reset(struct esirisc_jtag *jtag_info);
+int esirisc_jtag_deassert_reset(struct esirisc_jtag *jtag_info);
+
+int esirisc_jtag_break(struct esirisc_jtag *jtag_info);
+int esirisc_jtag_continue(struct esirisc_jtag *jtag_info);
+
+int esirisc_jtag_flush_caches(struct esirisc_jtag *jtag_info);
+
+#endif /* OPENOCD_TARGET_ESIRISC_JTAG_H */
diff --git a/src/target/esirisc_regs.h b/src/target/esirisc_regs.h
new file mode 100644
index 000000000..ad3385819
--- /dev/null
+++ b/src/target/esirisc_regs.h
@@ -0,0 +1,184 @@
+/***************************************************************************
+ * Copyright (C) 2018 by Square, Inc. *
+ * Steven Stallion *
+ * James Zhao *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see . *
+ ***************************************************************************/
+
+#ifndef OPENOCD_TARGET_ESIRISC_REGS_H
+#define OPENOCD_TARGET_ESIRISC_REGS_H
+
+enum esirisc_reg_num {
+ ESIRISC_SP,
+ ESIRISC_RA,
+ ESIRISC_R2,
+ ESIRISC_R3,
+ ESIRISC_R4,
+ ESIRISC_R5,
+ ESIRISC_R6,
+ ESIRISC_R7,
+ ESIRISC_R8,
+ ESIRISC_R9,
+ ESIRISC_R10,
+ ESIRISC_R11,
+ ESIRISC_R12,
+ ESIRISC_R13,
+ ESIRISC_R14,
+ ESIRISC_R15,
+ ESIRISC_R16,
+ ESIRISC_R17,
+ ESIRISC_R18,
+ ESIRISC_R19,
+ ESIRISC_R20,
+ ESIRISC_R21,
+ ESIRISC_R22,
+ ESIRISC_R23,
+ ESIRISC_R24,
+ ESIRISC_R25,
+ ESIRISC_R26,
+ ESIRISC_R27,
+ ESIRISC_R28,
+ ESIRISC_R29,
+ ESIRISC_R30,
+ ESIRISC_R31,
+
+ ESIRISC_V0,
+ ESIRISC_V1,
+ ESIRISC_V2,
+ ESIRISC_V3,
+ ESIRISC_V4,
+ ESIRISC_V5,
+ ESIRISC_V6,
+ ESIRISC_V7,
+ ESIRISC_V8,
+ ESIRISC_V9,
+ ESIRISC_V10,
+ ESIRISC_V11,
+ ESIRISC_V12,
+ ESIRISC_V13,
+ ESIRISC_V14,
+ ESIRISC_V15,
+ ESIRISC_V16,
+ ESIRISC_V17,
+ ESIRISC_V18,
+ ESIRISC_V19,
+ ESIRISC_V20,
+ ESIRISC_V21,
+ ESIRISC_V22,
+ ESIRISC_V23,
+ ESIRISC_V24,
+ ESIRISC_V25,
+ ESIRISC_V26,
+ ESIRISC_V27,
+ ESIRISC_V28,
+ ESIRISC_V29,
+ ESIRISC_V30,
+ ESIRISC_V31,
+
+ ESIRISC_A0,
+ ESIRISC_A1,
+ ESIRISC_A2,
+ ESIRISC_A3,
+ ESIRISC_A4,
+ ESIRISC_A5,
+ ESIRISC_A6,
+ ESIRISC_A7,
+
+ ESIRISC_PC,
+ ESIRISC_CAS,
+ ESIRISC_TC,
+ ESIRISC_ETA,
+ ESIRISC_ETC,
+ ESIRISC_EPC,
+ ESIRISC_ECAS,
+ ESIRISC_EID,
+ ESIRISC_ED,
+ ESIRISC_IP,
+ ESIRISC_IM,
+ ESIRISC_IS,
+ ESIRISC_IT,
+
+ ESIRISC_NUM_REGS,
+};
+
+/* CSR Banks */
+#define CSR_THREAD 0x00
+#define CSR_INTERRUPT 0x01
+#define CSR_DEBUG 0x04
+#define CSR_CONFIG 0x05
+#define CSR_TRACE 0x09
+
+/* Thread CSRs */
+#define CSR_THREAD_TC 0x00 /* Thread Control */
+#define CSR_THREAD_PC 0x01 /* Program Counter */
+#define CSR_THREAD_CAS 0x02 /* Comparison & Arithmetic Status */
+#define CSR_THREAD_AC 0x03 /* Arithmetic Control */
+#define CSR_THREAD_LF 0x04 /* Locked Flag */
+#define CSR_THREAD_LA 0x05 /* Locked Address */
+#define CSR_THREAD_ETA 0x07 /* Exception Table Address */
+#define CSR_THREAD_ETC 0x08 /* Exception TC */
+#define CSR_THREAD_EPC 0x09 /* Exception PC */
+#define CSR_THREAD_ECAS 0x0a /* Exception CAS */
+#define CSR_THREAD_EID 0x0b /* Exception ID */
+#define CSR_THREAD_ED 0x0c /* Exception Data */
+
+/* Interrupt CSRs */
+#define CSR_INTERRUPT_IP 0x00 /* Interrupt Pending */
+#define CSR_INTERRUPT_IA 0x01 /* Interrupt Acknowledge */
+#define CSR_INTERRUPT_IM 0x02 /* Interrupt Mask */
+#define CSR_INTERRUPT_IS 0x03 /* Interrupt Sense */
+#define CSR_INTERRUPT_IT 0x04 /* Interrupt Trigger */
+
+/* Debug CSRs */
+#define CSR_DEBUG_DC 0x00 /* Debug Control */
+#define CSR_DEBUG_IBC 0x01 /* Instruction Breakpoint Control */
+#define CSR_DEBUG_DBC 0x02 /* Data Breakpoint Control */
+#define CSR_DEBUG_HWDC 0x03 /* Hardware Debug Control */
+#define CSR_DEBUG_DBS 0x04 /* Data Breakpoint Size */
+#define CSR_DEBUG_DBR 0x05 /* Data Breakpoint Range */
+#define CSR_DEBUG_IBAn 0x08 /* Instruction Breakpoint Address [0..7] */
+#define CSR_DEBUG_DBAn 0x10 /* Data Breakpoint Address [0..7] */
+
+/* Configuration CSRs */
+#define CSR_CONFIG_ARCH0 0x00 /* Architectural Configuration 0 */
+#define CSR_CONFIG_ARCH1 0x01 /* Architectural Configuration 1 */
+#define CSR_CONFIG_ARCH2 0x02 /* Architectural Configuration 2 */
+#define CSR_CONFIG_ARCH3 0x03 /* Architectural Configuration 3 */
+#define CSR_CONFIG_MEM 0x04 /* Memory Configuration */
+#define CSR_CONFIG_IC 0x05 /* Instruction Cache Configuration */
+#define CSR_CONFIG_DC 0x06 /* Data Cache Configuration */
+#define CSR_CONFIG_INT 0x07 /* Interrupt Configuration */
+#define CSR_CONFIG_ISAn 0x08 /* Instruction Set Configuration [0..6] */
+#define CSR_CONFIG_DBG 0x0f /* Debug Configuration */
+#define CSR_CONFIG_MID 0x10 /* Manufacturer ID */
+#define CSR_CONFIG_REV 0x11 /* Revision Number */
+#define CSR_CONFIG_MPID 0x12 /* Mulitprocessor ID */
+#define CSR_CONFIG_FREQn 0x13 /* Frequency [0..2] */
+#define CSR_CONFIG_TRACE 0x16 /* Trace Configuration */
+
+/* Trace CSRs */
+#define CSR_TRACE_CONTROL 0x00
+#define CSR_TRACE_STATUS 0x01
+#define CSR_TRACE_BUFFER_START 0x02
+#define CSR_TRACE_BUFFER_END 0x03
+#define CSR_TRACE_BUFFER_CUR 0x04
+#define CSR_TRACE_TRIGGER 0x05
+#define CSR_TRACE_START_DATA 0x06
+#define CSR_TRACE_START_MASK 0x07
+#define CSR_TRACE_STOP_DATA 0x08
+#define CSR_TRACE_STOP_MASK 0x09
+#define CSR_TRACE_DELAY 0x0a
+
+#endif /* OPENOCD_TARGET_ESIRISC_REGS_H */
diff --git a/src/target/mem_ap.c b/src/target/mem_ap.c
new file mode 100644
index 000000000..3a2d4b7c5
--- /dev/null
+++ b/src/target/mem_ap.c
@@ -0,0 +1,181 @@
+/*****************************************************************************
+ * Copyright (C) 2016 by Matthias Welwarsky *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ ****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "target.h"
+#include "target_type.h"
+#include "arm.h"
+#include "arm_adi_v5.h"
+
+#include
+
+struct mem_ap {
+ struct arm arm;
+ struct adiv5_ap *ap;
+ int ap_num;
+};
+
+static int mem_ap_target_create(struct target *target, Jim_Interp *interp)
+{
+ struct mem_ap *mem_ap = calloc(1, sizeof(struct mem_ap));
+ struct adiv5_private_config *pc;
+
+ pc = (struct adiv5_private_config *)target->private_config;
+ if (pc == NULL)
+ return ERROR_FAIL;
+
+ if (pc->ap_num == DP_APSEL_INVALID) {
+ LOG_ERROR("AP number not specified");
+ return ERROR_FAIL;
+ }
+
+ mem_ap->ap_num = pc->ap_num;
+ mem_ap->arm.common_magic = ARM_COMMON_MAGIC;
+ mem_ap->arm.dap = pc->dap;
+
+ target->arch_info = mem_ap;
+
+ return ERROR_OK;
+}
+
+static int mem_ap_init_target(struct command_context *cmd_ctx, struct target *target)
+{
+ LOG_DEBUG("%s", __func__);
+ target->state = TARGET_UNKNOWN;
+ return ERROR_OK;
+}
+
+static int mem_ap_arch_state(struct target *target)
+{
+ LOG_DEBUG("%s", __func__);
+ return ERROR_OK;
+}
+
+static int mem_ap_poll(struct target *target)
+{
+ if (target->state == TARGET_UNKNOWN)
+ target->state = TARGET_RUNNING;
+
+ return ERROR_OK;
+}
+
+static int mem_ap_halt(struct target *target)
+{
+ LOG_DEBUG("%s", __func__);
+ target->state = TARGET_HALTED;
+ return ERROR_OK;
+}
+
+static int mem_ap_resume(struct target *target, int current, target_addr_t address,
+ int handle_breakpoints, int debug_execution)
+{
+ LOG_DEBUG("%s", __func__);
+ target->state = TARGET_RUNNING;
+ return ERROR_OK;
+}
+
+static int mem_ap_step(struct target *target, int current, target_addr_t address,
+ int handle_breakpoints)
+{
+ LOG_DEBUG("%s", __func__);
+ target->state = TARGET_HALTED;
+ return ERROR_OK;
+}
+
+static int mem_ap_assert_reset(struct target *target)
+{
+ target->state = TARGET_RESET;
+
+ LOG_DEBUG("%s", __func__);
+ return ERROR_OK;
+}
+
+static int mem_ap_examine(struct target *target)
+{
+ struct mem_ap *mem_ap = target->arch_info;
+
+ if (!target_was_examined(target)) {
+ mem_ap->ap = dap_ap(mem_ap->arm.dap, mem_ap->ap_num);
+ target_set_examined(target);
+ target->state = TARGET_UNKNOWN;
+ return mem_ap_init(mem_ap->ap);
+ }
+
+ return ERROR_OK;
+}
+
+static int mem_ap_deassert_reset(struct target *target)
+{
+ if (target->reset_halt)
+ target->state = TARGET_HALTED;
+ else
+ target->state = TARGET_RUNNING;
+
+ LOG_DEBUG("%s", __func__);
+ return ERROR_OK;
+}
+
+static int mem_ap_read_memory(struct target *target, target_addr_t address,
+ uint32_t size, uint32_t count, uint8_t *buffer)
+{
+ struct mem_ap *mem_ap = target->arch_info;
+
+ LOG_DEBUG("Reading memory at physical address 0x" TARGET_ADDR_FMT
+ "; size %" PRId32 "; count %" PRId32, address, size, count);
+
+ if (count == 0 || buffer == NULL)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ return mem_ap_read_buf(mem_ap->ap, buffer, size, count, address);
+}
+
+static int mem_ap_write_memory(struct target *target, target_addr_t address,
+ uint32_t size, uint32_t count,
+ const uint8_t *buffer)
+{
+ struct mem_ap *mem_ap = target->arch_info;
+
+ LOG_DEBUG("Writing memory at physical address 0x" TARGET_ADDR_FMT
+ "; size %" PRId32 "; count %" PRId32, address, size, count);
+
+ if (count == 0 || buffer == NULL)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ return mem_ap_write_buf(mem_ap->ap, buffer, size, count, address);
+}
+
+struct target_type mem_ap_target = {
+ .name = "mem_ap",
+
+ .target_create = mem_ap_target_create,
+ .init_target = mem_ap_init_target,
+ .examine = mem_ap_examine,
+ .target_jim_configure = adiv5_jim_configure,
+
+ .poll = mem_ap_poll,
+ .arch_state = mem_ap_arch_state,
+
+ .halt = mem_ap_halt,
+ .resume = mem_ap_resume,
+ .step = mem_ap_step,
+
+ .assert_reset = mem_ap_assert_reset,
+ .deassert_reset = mem_ap_deassert_reset,
+
+ .read_memory = mem_ap_read_memory,
+ .write_memory = mem_ap_write_memory,
+};
diff --git a/src/target/register.c b/src/target/register.c
index 1d63e12f7..850641448 100644
--- a/src/target/register.c
+++ b/src/target/register.c
@@ -44,6 +44,8 @@ struct reg *register_get_by_name(struct reg_cache *first,
while (cache) {
for (i = 0; i < cache->num_regs; i++) {
+ if (cache->reg_list[i].exist == false)
+ continue;
if (strcmp(cache->reg_list[i].name, name) == 0)
return &(cache->reg_list[i]);
}
@@ -84,6 +86,8 @@ void register_cache_invalidate(struct reg_cache *cache)
struct reg *reg = cache->reg_list;
for (unsigned n = cache->num_regs; n != 0; n--, reg++) {
+ if (reg->exist == false)
+ continue;
reg->valid = 0;
reg->dirty = 0;
}
diff --git a/src/target/target.c b/src/target/target.c
index 8240e6544..7de3e7615 100644
--- a/src/target/target.c
+++ b/src/target/target.c
@@ -108,6 +108,8 @@ extern struct target_type quark_x10xx_target;
extern struct target_type quark_d20xx_target;
extern struct target_type stm8_target;
extern struct target_type riscv_target;
+extern struct target_type mem_ap_target;
+extern struct target_type esirisc_target;
static struct target_type *target_types[] = {
&arm7tdmi_target,
@@ -141,6 +143,8 @@ static struct target_type *target_types[] = {
&quark_d20xx_target,
&stm8_target,
&riscv_target,
+ &mem_ap_target,
+ &esirisc_target,
#if BUILD_TARGET64
&aarch64_target,
#endif
@@ -513,9 +517,7 @@ struct target *get_target_by_num(int num)
struct target *get_current_target(struct command_context *cmd_ctx)
{
- struct target *target = cmd_ctx->current_target_override
- ? cmd_ctx->current_target_override
- : cmd_ctx->current_target;
+ struct target *target = get_current_target_or_null(cmd_ctx);
if (target == NULL) {
LOG_ERROR("BUG: current_target out of bounds");
@@ -525,6 +527,13 @@ struct target *get_current_target(struct command_context *cmd_ctx)
return target;
}
+struct target *get_current_target_or_null(struct command_context *cmd_ctx)
+{
+ return cmd_ctx->current_target_override
+ ? cmd_ctx->current_target_override
+ : cmd_ctx->current_target;
+}
+
int target_poll(struct target *target)
{
int retval;
@@ -1043,6 +1052,9 @@ int target_run_flash_async_algorithm(struct target *target,
retval = target_write_u32(target, wp_addr, wp);
if (retval != ERROR_OK)
break;
+
+ /* Avoid GDB timeouts */
+ keep_alive();
}
if (retval != ERROR_OK) {
@@ -1197,12 +1209,29 @@ int target_hit_watchpoint(struct target *target,
return target->type->hit_watchpoint(target, hit_watchpoint);
}
+const char *target_get_gdb_arch(struct target *target)
+{
+ if (target->type->get_gdb_arch == NULL)
+ return NULL;
+ return target->type->get_gdb_arch(target);
+}
+
int target_get_gdb_reg_list(struct target *target,
struct reg **reg_list[], int *reg_list_size,
enum target_register_class reg_class)
{
return target->type->get_gdb_reg_list(target, reg_list, reg_list_size, reg_class);
}
+
+bool target_supports_gdb_connection(struct target *target)
+{
+ /*
+ * based on current code, we can simply exclude all the targets that
+ * don't provide get_gdb_reg_list; this could change with new targets.
+ */
+ return !!target->type->get_gdb_reg_list;
+}
+
int target_step(struct target *target,
int current, target_addr_t address, int handle_breakpoints)
{
@@ -1927,6 +1956,7 @@ static void target_destroy(struct target *target)
target->smp = 0;
}
+ free(target->gdb_port_override);
free(target->type);
free(target->trace_info);
free(target->fileio_info);
@@ -2792,6 +2822,8 @@ COMMAND_HANDLER(handle_reg_command)
for (i = 0, reg = cache->reg_list;
i < cache->num_regs;
i++, reg++, count++) {
+ if (reg->exist == false)
+ continue;
/* only print cached values if they are valid */
if (reg->exist) {
if (reg->valid) {
@@ -2847,14 +2879,15 @@ COMMAND_HANDLER(handle_reg_command)
/* access a single register by its name */
reg = register_get_by_name(target->reg_cache, CMD_ARGV[0], 1);
- if (!reg) {
- command_print(CMD_CTX, "register %s not found in current target", CMD_ARGV[0]);
- return ERROR_OK;
- }
+ if (!reg)
+ goto not_found;
}
assert(reg != NULL); /* give clang a hint that we *know* reg is != NULL here */
+ if (!reg->exist)
+ goto not_found;
+
/* display a register */
if ((CMD_ARGC == 1) || ((CMD_ARGC == 2) && !((CMD_ARGV[1][0] >= '0')
&& (CMD_ARGV[1][0] <= '9')))) {
@@ -2898,6 +2931,10 @@ COMMAND_HANDLER(handle_reg_command)
}
return ERROR_COMMAND_SYNTAX_ERROR;
+
+not_found:
+ command_print(CMD_CTX, "register %s not found in current target", CMD_ARGV[0]);
+ return ERROR_OK;
}
COMMAND_HANDLER(handle_poll_command)
@@ -4550,6 +4587,7 @@ enum target_cfg_param {
TCFG_DBGBASE,
TCFG_RTOS,
TCFG_DEFER_EXAMINE,
+ TCFG_GDB_PORT,
};
static Jim_Nvp nvp_config_opts[] = {
@@ -4565,6 +4603,7 @@ static Jim_Nvp nvp_config_opts[] = {
{ .name = "-dbgbase", .value = TCFG_DBGBASE },
{ .name = "-rtos", .value = TCFG_RTOS },
{ .name = "-defer-examine", .value = TCFG_DEFER_EXAMINE },
+ { .name = "-gdb-port", .value = TCFG_GDB_PORT },
{ .name = NULL, .value = -1 }
};
@@ -4852,6 +4891,20 @@ no_params:
/* loop for more */
break;
+ case TCFG_GDB_PORT:
+ if (goi->isconfigure) {
+ const char *s;
+ e = Jim_GetOpt_String(goi, &s, NULL);
+ if (e != JIM_OK)
+ return e;
+ target->gdb_port_override = strdup(s);
+ } else {
+ if (goi->argc != 0)
+ goto no_params;
+ }
+ Jim_SetResultString(goi->interp, target->gdb_port_override ? : "undefined", -1);
+ /* loop for more */
+ break;
}
} /* while (goi->argc) */
@@ -5626,6 +5679,8 @@ static int target_create(Jim_GetOptInfo *goi)
target->rtos = NULL;
target->rtos_auto_detect = false;
+ target->gdb_port_override = NULL;
+
/* Do the rest as "configure" options */
goi->isconfigure = 1;
e = target_configure(goi, target);
@@ -5648,6 +5703,7 @@ static int target_create(Jim_GetOptInfo *goi)
}
if (e != JIM_OK) {
+ free(target->gdb_port_override);
free(target->type);
free(target);
return e;
@@ -5665,6 +5721,7 @@ static int target_create(Jim_GetOptInfo *goi)
e = (*(target->type->target_create))(target, goi->interp);
if (e != ERROR_OK) {
LOG_DEBUG("target_create failed");
+ free(target->gdb_port_override);
free(target->type);
free(target->cmd_name);
free(target);
diff --git a/src/target/target.h b/src/target/target.h
index 51a5b6935..fb9d71465 100644
--- a/src/target/target.h
+++ b/src/target/target.h
@@ -206,6 +206,8 @@ struct target {
/* file-I/O information for host to do syscall */
struct gdb_fileio_info *fileio_info;
+ char *gdb_port_override; /* target-specific override for gdb_port */
+
/* The semihosting information, extracted from the target. */
struct semihosting *semihosting;
};
@@ -223,6 +225,13 @@ struct gdb_fileio_info {
uint64_t param_4;
};
+/** Returns a description of the endianness for the specified target. */
+static inline const char *target_endianness(struct target *target)
+{
+ return (target->endianness == TARGET_ENDIAN_UNKNOWN) ? "unknown" :
+ (target->endianness == TARGET_BIG_ENDIAN) ? "big endian" : "little endian";
+}
+
/** Returns the instance-specific name of the specified target. */
static inline const char *target_name(struct target *target)
{
@@ -387,6 +396,7 @@ int target_call_timer_callbacks_now(void);
struct target *get_target_by_num(int num);
struct target *get_current_target(struct command_context *cmd_ctx);
+struct target *get_current_target_or_null(struct command_context *cmd_ctx);
struct target *get_target(const char *id);
/**
@@ -470,6 +480,13 @@ int target_remove_watchpoint(struct target *target,
int target_hit_watchpoint(struct target *target,
struct watchpoint **watchpoint);
+/**
+ * Obtain the architecture for GDB.
+ *
+ * This routine is a wrapper for target->type->get_gdb_arch.
+ */
+const char *target_get_gdb_arch(struct target *target);
+
/**
* Obtain the registers for GDB.
*
@@ -479,6 +496,13 @@ int target_get_gdb_reg_list(struct target *target,
struct reg **reg_list[], int *reg_list_size,
enum target_register_class reg_class);
+/**
+ * Check if @a target allows GDB connections.
+ *
+ * Some target do not implement the necessary code required by GDB.
+ */
+bool target_supports_gdb_connection(struct target *target);
+
/**
* Step the target.
*
diff --git a/src/target/target_type.h b/src/target/target_type.h
index fbbd57d98..a8928911f 100644
--- a/src/target/target_type.h
+++ b/src/target/target_type.h
@@ -88,6 +88,15 @@ struct target_type {
int (*deassert_reset)(struct target *target);
int (*soft_reset_halt)(struct target *target);
+ /**
+ * Target architecture for GDB.
+ *
+ * The string returned by this function will not be automatically freed;
+ * if dynamic allocation is used for this value, it must be managed by
+ * the target, ideally by caching the result for subsequent calls.
+ */
+ const char *(*get_gdb_arch)(struct target *target);
+
/**
* Target register access for GDB. Do @b not call this function
* directly, use target_get_gdb_reg_list() instead.
diff --git a/tcl/board/arty_s7.cfg b/tcl/board/arty_s7.cfg
new file mode 100644
index 000000000..ca7d3f1c4
--- /dev/null
+++ b/tcl/board/arty_s7.cfg
@@ -0,0 +1,35 @@
+#
+# Arty S7: Spartan7 25/50 FPGA Board for Makers and Hobbyists
+#
+# https://www.xilinx.com/products/boards-and-kits/1-pnziih.html
+# https://store.digilentinc.com/arty-s7-spartan-7-fpga-board-for-makers-and-hobbyists/
+
+source [find interface/ftdi/digilent-hs1.cfg]
+
+# Xilinx Spartan7-25/50 FPGA (XC7S{25,50}-CSGA324)
+source [find cpld/xilinx-xc7.cfg]
+source [find cpld/jtagspi.cfg]
+
+adapter_khz 25000
+
+# Usage:
+#
+# Load Bitstream into FPGA:
+# openocd -f board/arty_s7.cfg -c "init;\
+# pld load 0 bitstream.bit;\
+# shutdown"
+#
+# Write Bitstream to Flash:
+# openocd -f board/arty_s7.cfg -c "init;\
+# jtagspi_init 0 bscan_spi_xc7s??.bit;\
+# jtagspi_program bitstream.bin 0;\
+# xc7s_program xc7s.tap;\
+# shutdown"
+#
+# jtagspi flash proxies can be found at:
+# https://github.com/quartiq/bscan_spi_bitstreams
+#
+# For the Spartan 50 variant, use
+# - https://github.com/quartiq/bscan_spi_bitstreams/raw/master/bscan_spi_xc7s50.bit
+# For the Spartan 25 variant, use
+# - https://github.com/quartiq/bscan_spi_bitstreams/raw/master/bscan_spi_xc7s25.bit
diff --git a/tcl/board/emcraft_imx8m-som-bsb.cfg b/tcl/board/emcraft_imx8m-som-bsb.cfg
new file mode 100644
index 000000000..5571d0ecb
--- /dev/null
+++ b/tcl/board/emcraft_imx8m-som-bsb.cfg
@@ -0,0 +1,22 @@
+#
+# configuration file for Emcraft IMX8M-SOM-BSB
+#
+
+# only JTAG supported
+transport select jtag
+
+# set a safe JTAG clock speed, can be overridden
+adapter_khz 1000
+
+# SRST and TRST are wired up
+reset_config trst_and_srst
+
+# delay after SRST goes inactive
+adapter_nsrst_delay 70
+
+# board has an i.MX8MQ with 4 Cortex-A53 cores
+set CHIPNAME imx8mq
+set CHIPCORES 4
+
+# source SoC configuration
+source [find target/imx8m.cfg]
diff --git a/tcl/board/numato_mimas_a7.cfg b/tcl/board/numato_mimas_a7.cfg
new file mode 100644
index 000000000..1261feacc
--- /dev/null
+++ b/tcl/board/numato_mimas_a7.cfg
@@ -0,0 +1,36 @@
+#
+# Numato Mimas A7 - Artix 7 FPGA Board
+#
+# https://numato.com/product/mimas-a7-artix-7-fpga-development-board-with-ddr-sdram-and-gigabit-ethernet
+#
+# Note: Connect external DC power supply if programming a heavy design onto FPGA.
+# Programming while powering via USB may lead to programming failure.
+# Therefore, prefer external power supply.
+
+interface ftdi
+ftdi_device_desc "Mimas Artix 7 FPGA Module"
+ftdi_vid_pid 0x2a19 0x1009
+
+# channel 0 is for custom purpose by users (like uart, fifo etc)
+# channel 1 is reserved for JTAG (by-default) or SPI (possible via changing solder jumpers)
+ftdi_channel 1
+ftdi_tdo_sample_edge falling
+
+
+# FTDI Pin Layout
+#
+# +--------+-------+-------+-------+-------+-------+-------+-------+
+# | DBUS7 | DBUS6 | DBUS5 | DBUS4 | DBUS3 | DBUS2 | DBUS1 | DBUS0 |
+# +--------+-------+-------+-------+-------+-------+-------+-------+
+# | PROG_B | OE_N | NC | NC | TMS | TDO | TDI | TCK |
+# +--------+-------+-------+-------+-------+-------+-------+-------+
+#
+# OE_N is JTAG buffer output enable signal (active-low)
+# PROG_B is not used, so left as input to FTDI.
+#
+ftdi_layout_init 0x0008 0x004b
+reset_config none
+adapter_khz 30000
+
+source [find cpld/xilinx-xc7.cfg]
+source [find cpld/jtagspi.cfg]
diff --git a/tcl/board/renesas_salvator-xs.cfg b/tcl/board/renesas_salvator-xs.cfg
new file mode 100644
index 000000000..1558a5274
--- /dev/null
+++ b/tcl/board/renesas_salvator-xs.cfg
@@ -0,0 +1,23 @@
+# Renesas R-Car Gen3 Salvator-X(S) Board Config
+
+# The Salvator-X(S) boards come with either an H3, M3W, or M3N SOC.
+
+echo "\nSalvator-X(S):"
+if { ![info exists SOC] } {
+ set SOC H3
+}
+source [find target/renesas_rcar_gen3.cfg]
+
+reset_config trst_and_srst srst_nogate
+
+proc init_reset {mode} {
+ # Assert both resets: equivalent to a power-on reset
+ jtag_reset 1 1
+
+ # Deassert TRST to begin TAP communication
+ jtag_reset 0 1
+
+ # TAP should now be responsive, validate the scan-chain
+ jtag arp_init
+}
+
diff --git a/tcl/cpld/xilinx-xc7.cfg b/tcl/cpld/xilinx-xc7.cfg
index d5824f8a1..4c0502c5d 100644
--- a/tcl/cpld/xilinx-xc7.cfg
+++ b/tcl/cpld/xilinx-xc7.cfg
@@ -9,7 +9,15 @@ if { [info exists CHIPNAME] } {
# the 4 top bits (28:31) are the die stepping/revisions. ignore it.
jtag newtap $_CHIPNAME tap -irlen 6 -ignore-version \
+ -expected-id 0x03622093 \
+ -expected-id 0x03620093 \
+ -expected-id 0x037C4093 \
+ -expected-id 0x0362F093 \
+ -expected-id 0x037C8093 \
+ -expected-id 0x037C7093 \
+ -expected-id 0x037C3093 \
-expected-id 0x0362E093 \
+ -expected-id 0x037C2093 \
-expected-id 0x0362D093 \
-expected-id 0x0362C093 \
-expected-id 0x03632093 \
diff --git a/tcl/interface/ftdi/c232hm.cfg b/tcl/interface/ftdi/c232hm.cfg
new file mode 100644
index 000000000..387abbb05
--- /dev/null
+++ b/tcl/interface/ftdi/c232hm.cfg
@@ -0,0 +1,15 @@
+#
+# FTDI USB Hi-Speed to MPSSE Cable
+#
+# http://www.ftdichip.com/Products/Cables/USBMPSSE.htm
+#
+# C232HM-DDHSL-0 and C232HM-EDSL-0 provide 3.3V and 5V on pin 1 (Red),
+# respectively.
+#
+
+interface ftdi
+#ftdi_device_desc "C232HM-DDHSL-0"
+#ftdi_device_desc "C232HM-EDHSL-0"
+ftdi_vid_pid 0x0403 0x6014
+
+ftdi_layout_init 0x0008 0x000b
diff --git a/tcl/target/atsamv.cfg b/tcl/target/atsamv.cfg
index d1f8454d5..43962de31 100644
--- a/tcl/target/atsamv.cfg
+++ b/tcl/target/atsamv.cfg
@@ -45,6 +45,14 @@ if {![using_hla]} {
# if srst is not fitted use SYSRESETREQ to
# perform a soft reset
cortex_m reset_config sysresetreq
+
+ # Set CSW[27], which according to ARM ADI v5 appendix E1.4 maps to AHB signal
+ # HPROT[3], which according to AMBA AHB/ASB/APB specification chapter 3.7.3
+ # makes the data access cacheable. This allows reading and writing data in the
+ # CPU cache from the debugger, which is far more useful than going straight to
+ # RAM when operating on typical variables, and is generally no worse when
+ # operating on special memory locations.
+ $_CHIPNAME.dap apcsw 0x08000000 0x08000000
}
set _FLASHNAME $_CHIPNAME.flash
diff --git a/tcl/target/esi32xx.cfg b/tcl/target/esi32xx.cfg
new file mode 100644
index 000000000..d32af39bd
--- /dev/null
+++ b/tcl/target/esi32xx.cfg
@@ -0,0 +1,36 @@
+#
+# EnSilica eSi-32xx SoC (eSi-RISC Family)
+# http://www.ensilica.com/risc-ip/
+#
+
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $CHIPNAME
+} else {
+ set _CHIPNAME esi32xx
+}
+
+if { [info exists CPUTAPID] } {
+ set _CPUTAPID $CPUTAPID
+} else {
+ set _CPUTAPID 0x11234001
+}
+
+jtag newtap $_CHIPNAME cpu -irlen 4 -expected-id $_CPUTAPID
+
+set _TARGETNAME $_CHIPNAME.cpu
+target create $_TARGETNAME esirisc -chain-position $_CHIPNAME.cpu
+
+# Targets with the UNIFIED_ADDRESS_SPACE option disabled should set
+# CACHEARCH to 'harvard'. By default, 'von_neumann' is assumed.
+if { [info exists CACHEARCH] } {
+ $_TARGETNAME esirisc cache_arch $CACHEARCH
+}
+
+adapter_khz 2000
+
+reset_config none
+
+# The default linker scripts provided by the eSi-RISC toolchain do not
+# specify attributes on memory regions, which results in incorrect
+# application of software breakpoints by GDB.
+gdb_breakpoint_override hard
diff --git a/tcl/target/max32620.cfg b/tcl/target/max32620.cfg
new file mode 100644
index 000000000..80cb25a47
--- /dev/null
+++ b/tcl/target/max32620.cfg
@@ -0,0 +1,28 @@
+# Maxim Integrated MAX32620 OpenOCD target configuration file
+# www.maximintegrated.com
+
+# adapter speed
+adapter_khz 4000
+
+# reset pin configuration
+reset_config srst_only
+
+if {[using_jtag]} {
+ jtag newtap max32620 cpu -irlen 4 -irmask 0xf -expected-id 0x4ba00477 -ignore-version
+ jtag newtap maxtest tap -irlen 4 -irmask 0xf -ircapture 0x1 -ignore-version
+} else {
+ swd newdap max32620 cpu -irlen 4 -irmask 0xf -expected-id 0x2ba01477 -ignore-version
+}
+
+# target configuration
+target create max32620.cpu cortex_m -chain-position max32620.cpu
+max32620.cpu configure -work-area-phys 0x20005000 -work-area-size 0x2000
+
+# Config Command: flash bank name driver base size chip_width bus_width target [driver_options]
+# flash bank max32xxx 0 0
+# max32620 flash base address 0x00000000
+# max32620 flash size 0x200000 (2MB)
+# max32620 FLC base address 0x40002000
+# max32620 sector (page) size 0x2000 (8kB)
+# max32620 clock speed 96 (MHz)
+flash bank max32620.flash max32xxx 0x00000000 0x200000 0 0 max32620.cpu 0x40002000 0x2000 96
diff --git a/tcl/target/max32625.cfg b/tcl/target/max32625.cfg
new file mode 100644
index 000000000..7182b235f
--- /dev/null
+++ b/tcl/target/max32625.cfg
@@ -0,0 +1,28 @@
+# Maxim Integrated MAX32625 OpenOCD target configuration file
+# www.maximintegrated.com
+
+# adapter speed
+adapter_khz 4000
+
+# reset pin configuration
+reset_config srst_only
+
+if {[using_jtag]} {
+ jtag newtap max32625 cpu -irlen 4 -irmask 0xf -expected-id 0x4ba00477 -ignore-version
+ jtag newtap maxtest tap -irlen 4 -irmask 0xf -ircapture 0x1 -expected-id 0x07f71197 -ignore-version
+} else {
+ swd newdap max32625 cpu -irlen 4 -irmask 0xf -expected-id 0x2ba01477 -ignore-version
+}
+
+# target configuration
+target create max32625.cpu cortex_m -chain-position max32625.cpu
+max32625.cpu configure -work-area-phys 0x20005000 -work-area-size 0x2000
+
+# Config Command: flash bank name driver base size chip_width bus_width target [driver_options]
+# flash bank max32xxx 0 0
+# max32625 flash base address 0x00000000
+# max32625 flash size 0x80000 (512k)
+# max32625 FLC base address 0x40002000
+# max32625 sector (page) size 0x2000 (8kB)
+# max32625 clock speed 96 (MHz)
+flash bank max32625.flash max32xxx 0x00000000 0x80000 0 0 max32625.cpu 0x40002000 0x2000 96
diff --git a/tcl/target/max3263x.cfg b/tcl/target/max3263x.cfg
new file mode 100644
index 000000000..f23b0b64d
--- /dev/null
+++ b/tcl/target/max3263x.cfg
@@ -0,0 +1,28 @@
+# Maxim Integrated MAX3263X OpenOCD target configuration file
+# www.maximintegrated.com
+
+# adapter speed
+adapter_khz 4000
+
+# reset pin configuration
+reset_config srst_only
+
+if {[using_jtag]} {
+ jtag newtap max3263x cpu -irlen 4 -irmask 0xf -expected-id 0x4ba00477 -ignore-version
+ jtag newtap maxtest tap -irlen 4 -irmask 0xf -ircapture 0x1 -expected-id 0x07f76197 -ignore-version
+} else {
+ swd newdap max3263x cpu -irlen 4 -irmask 0xf -expected-id 0x2ba01477 -ignore-version
+}
+
+# target configuration
+target create max3263x.cpu cortex_m -chain-position max3263x.cpu
+max3263x.cpu configure -work-area-phys 0x20005000 -work-area-size 0x2000
+
+# Config Command: flash bank name driver base size chip_width bus_width target [driver_options]
+# flash bank max32xxx 0 0
+# max3263x flash base address 0x00000000
+# max3263x flash size 0x200000 (2MB)
+# max3263x FLC base address 0x40002000
+# max3263x sector (page) size 0x2000 (8kB)
+# max3263x clock speed 96 (MHz)
+flash bank max3263x.flash max32xxx 0x00000000 0x200000 0 0 max3263x.cpu 0x40002000 0x2000 96
diff --git a/tcl/target/renesas_rcar_gen3.cfg b/tcl/target/renesas_rcar_gen3.cfg
new file mode 100644
index 000000000..a6eef674b
--- /dev/null
+++ b/tcl/target/renesas_rcar_gen3.cfg
@@ -0,0 +1,169 @@
+# Renesas R-Car Generation 3 SOCs
+# - There are a combination of Cortex-A57s, Cortex-A53s, and Cortex-R7 for each Gen3 SOC
+# - Each SOC can boot through any of the, up to 3, core types that it has
+# e.g. H3 can boot through Cortex-A57, Cortex-A53, or Cortex-R7
+
+# Supported Gen3 SOCs and their cores:
+# H3: Cortex-A57 x 4, Cortex-A53 x 4, Cortex-R7 x 2 (Lock-Step)
+# M3W: Cortex-A57 x 2, Cortex-A53 x 4, Cortex-R7 x 2 (Lock-Step)
+# M3N: Cortex-A57 x 2, Cortex-R7 x 2 (Lock-Step)
+# V3H: Cortex-A53 x 4, Cortex-R7 x 2 (Lock-Step)
+# V3M: Cortex-A53 x 2, Cortex-R7 x 2 (Lock-Step)
+# E3: Cortex-A53 x 1, Cortex-R7 x 2 (Lock-Step)
+# D3: Cortex-A53 x 1
+
+# Usage:
+# There are 2 configuration options:
+# SOC: Selects the supported SOC. (Default 'H3')
+# BOOT_CORE: Selects the booting core. 'CA57', 'CA53', or 'CR7'
+# Defaults to 'CA57' if the SOC has one, else defaults to 'CA53'
+
+if { [info exists SOC] } {
+ set _soc $SOC
+} else {
+ set _soc H3
+}
+
+# Set configuration for each SOC and the default 'BOOT_CORE'
+switch $_soc {
+ H3 {
+ set _CHIPNAME r8a77950
+ set _num_ca57 4
+ set _num_ca53 4
+ set _num_cr7 1
+ set _boot_core CA57
+ }
+ M3W {
+ set _CHIPNAME r8a77960
+ set _num_ca57 2
+ set _num_ca53 4
+ set _num_cr7 1
+ set _boot_core CA57
+ }
+ M3N {
+ set _CHIPNAME r8a77965
+ set _num_ca57 2
+ set _num_ca53 4
+ set _num_cr7 1
+ set _boot_core CA57
+ }
+ V3H {
+ set _CHIPNAME r8a77970
+ set _num_ca57 0
+ set _num_ca53 4
+ set _num_cr7 1
+ set _boot_core CA53
+ }
+ V3M {
+ set _CHIPNAME r8a77980
+ set _num_ca57 0
+ set _num_ca53 2
+ set _num_cr7 1
+ set _boot_core CA53
+ }
+ E3 {
+ set _CHIPNAME r8a77990
+ set _num_ca57 0
+ set _num_ca53 1
+ set _num_cr7 1
+ set _boot_core CA53
+ }
+ D3 {
+ set _CHIPNAME r8a77995
+ set _num_ca57 0
+ set _num_ca53 1
+ set _num_cr7 0
+ set _boot_core CA53
+ }
+ default {
+ echo "'$_soc' is invalid!"
+ }
+}
+
+# If configured, override the default 'CHIPNAME'
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $CHIPNAME
+}
+
+# If configured, override the default 'BOOT_CORE'
+if { [info exists BOOT_CORE] } {
+ set _boot_core $BOOT_CORE
+}
+
+if { [info exists DAP_TAPID] } {
+ set _DAP_TAPID $DAP_TAPID
+} else {
+ set _DAP_TAPID 0x5ba00477
+}
+
+echo "\t$_soc - $_num_ca57 CA57(s), $_num_ca53 CA53(s), $_num_cr7 CR7(s)"
+echo "\tBoot Core - $_boot_core\n"
+
+set _DAPNAME $_CHIPNAME.dap
+
+# TAP and DAP
+jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x01 -irmask 0x0f -expected-id $_DAP_TAPID
+dap create $_DAPNAME -chain-position $_CHIPNAME.cpu
+
+set CA57_DBGBASE {0x80410000 0x80510000 0x80610000 0x80710000}
+set CA57_CTIBASE {0x80420000 0x80520000 0x80620000 0x80720000}
+set CA53_DBGBASE {0x80C10000 0x80D10000 0x80E10000 0x80F10000}
+set CA53_CTIBASE {0x80C20000 0x80D20000 0x80E20000 0x80F20000}
+set CR7_DBGBASE 0x80910000
+set CR7_CTIBASE 0x80918000
+
+set smp_targets ""
+
+proc setup_a5x {core_name dbgbase ctibase num boot} {
+ global _CHIPNAME
+ global _DAPNAME
+ global smp_targets
+ for { set _core 0 } { $_core < $num } { incr _core } {
+ set _TARGETNAME $_CHIPNAME.$core_name.$_core
+ set _CTINAME $_TARGETNAME.cti
+ cti create $_CTINAME -dap $_DAPNAME -ap-num 1 \
+ -ctibase [lindex $ctibase $_core]
+ set _command "target create $_TARGETNAME aarch64 -dap $_DAPNAME \
+ -ap-num 1 -dbgbase [lindex $dbgbase $_core] -cti $_CTINAME"
+ if { $_core == 0 && $boot == 1 } {
+ set _targets "$_TARGETNAME"
+ } else {
+ set _command "$_command -defer-examine"
+ }
+ set smp_targets "$smp_targets $_TARGETNAME"
+ eval $_command
+ }
+}
+
+proc setup_cr7 {dbgbase ctibase boot} {
+ global _CHIPNAME
+ global _DAPNAME
+ set _TARGETNAME $_CHIPNAME.r7
+ set _CTINAME $_TARGETNAME.cti
+ cti create $_CTINAME -dap $_DAPNAME -ap-num 1 -ctibase $ctibase
+ set _command "target create $_TARGETNAME cortex_r4 -dap $_DAPNAME \
+ -ap-num 1 -dbgbase $dbgbase"
+ if { $boot == 1 } {
+ set _targets "$_TARGETNAME"
+ } else {
+ set _command "$_command -defer-examine"
+ }
+ eval $_command
+}
+
+# Organize target list based on the boot core
+if { [string equal $_boot_core CA57] } {
+ setup_a5x a57 $CA57_DBGBASE $CA57_CTIBASE $_num_ca57 1
+ setup_a5x a53 $CA53_DBGBASE $CA53_CTIBASE $_num_ca53 0
+ setup_cr7 $CR7_DBGBASE $CR7_CTIBASE 0
+} elseif { [string equal $_boot_core CA53] } {
+ setup_a5x a53 $CA53_DBGBASE $CA53_CTIBASE $_num_ca53 1
+ setup_a5x a57 $CA57_DBGBASE $CA57_CTIBASE $_num_ca57 0
+ setup_cr7 $CR7_DBGBASE $CR7_CTIBASE 0
+} else {
+ setup_cr7 $CR7_DBGBASE $CR7_CTIBASE 1
+ setup_a5x a57 $CA57_DBGBASE $CA57_CTIBASE $_num_ca57 0
+ setup_a5x a53 $CA53_DBGBASE $CA53_CTIBASE $_num_ca53 0
+}
+
+eval "target smp $smp_targets"
diff --git a/tcl/target/stm32f7x.cfg b/tcl/target/stm32f7x.cfg
index 562de30f6..b0468e21e 100755
--- a/tcl/target/stm32f7x.cfg
+++ b/tcl/target/stm32f7x.cfg
@@ -65,6 +65,14 @@ if {![using_hla]} {
# if srst is not fitted use SYSRESETREQ to
# perform a soft reset
cortex_m reset_config sysresetreq
+
+ # Set CSW[27], which according to ARM ADI v5 appendix E1.4 maps to AHB signal
+ # HPROT[3], which according to AMBA AHB/ASB/APB specification chapter 3.7.3
+ # makes the data access cacheable. This allows reading and writing data in the
+ # CPU cache from the debugger, which is far more useful than going straight to
+ # RAM when operating on typical variables, and is generally no worse when
+ # operating on special memory locations.
+ $_CHIPNAME.dap apcsw 0x08000000 0x08000000
}
$_TARGETNAME configure -event examine-end {
@@ -145,3 +153,4 @@ $_TARGETNAME configure -event reset-start {
# Reduce speed since CPU speed will slow down to 16MHz with the reset
adapter_khz 2000
}
+
diff --git a/tcl/target/stm32h7x.cfg b/tcl/target/stm32h7x.cfg
index 10477a5a7..0bfc43dfd 100644
--- a/tcl/target/stm32h7x.cfg
+++ b/tcl/target/stm32h7x.cfg
@@ -56,13 +56,31 @@ if {[using_jtag]} {
jtag_ntrst_delay 100
}
-# use hardware reset, connect under reset
+# use hardware reset
+#
+# The STM32H7 does not support connect_assert_srst mode because the AXI is
+# unavailable while SRST is asserted, and that is used to access the DBGMCU
+# component at 0x5C001000 in the examine-end event handler.
+#
+# It is possible to access the DBGMCU component at 0xE00E1000 via AP2 instead
+# of the default AP0, and that works with SRST asserted; however, nonzero AP
+# usage does not work with HLA, so is not done by default. That change could be
+# made in a local configuration file if connect_assert_srst mode is needed for
+# a specific application and a non-HLA adapter is in use.
reset_config srst_only srst_nogate
if {![using_hla]} {
# if srst is not fitted use SYSRESETREQ to
# perform a soft reset
cortex_m reset_config sysresetreq
+
+ # Set CSW[27], which according to ARM ADI v5 appendix E1.4 maps to AHB signal
+ # HPROT[3], which according to AMBA AHB/ASB/APB specification chapter 3.7.3
+ # makes the data access cacheable. This allows reading and writing data in the
+ # CPU cache from the debugger, which is far more useful than going straight to
+ # RAM when operating on typical variables, and is generally no worse when
+ # operating on special memory locations.
+ $_CHIPNAME.dap apcsw 0x08000000 0x08000000
}
$_TARGETNAME configure -event examine-end {
@@ -92,3 +110,4 @@ $_TARGETNAME configure -event reset-init {
# Clock after reset is HSI at 64 MHz, no need of PLL
adapter_khz 4000
}
+
diff --git a/tcl/target/zynq_7000.cfg b/tcl/target/zynq_7000.cfg
index 07a6c8352..1562768c5 100644
--- a/tcl/target/zynq_7000.cfg
+++ b/tcl/target/zynq_7000.cfg
@@ -27,3 +27,22 @@ adapter_khz 1000
${_TARGETNAME}0 configure -event reset-assert-post "cortex_a dbginit"
${_TARGETNAME}1 configure -event reset-assert-post "cortex_a dbginit"
+
+pld device virtex2 zynq_pl.bs 1
+
+set XC7_JSHUTDOWN 0x0d
+set XC7_JPROGRAM 0x0b
+set XC7_JSTART 0x0c
+set XC7_BYPASS 0x3f
+
+proc zynqpl_program {tap} {
+ global XC7_JSHUTDOWN XC7_JPROGRAM XC7_JSTART XC7_BYPASS
+ irscan $tap $XC7_JSHUTDOWN
+ irscan $tap $XC7_JPROGRAM
+ runtest 60000
+ #JSTART prevents this from working...
+ #irscan $tap $XC7_JSTART
+ runtest 2000
+ irscan $tap $XC7_BYPASS
+ runtest 2000
+}