commit
f098b553c9
4
README
4
README
|
@ -125,8 +125,8 @@ 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, SiM3x, Stellaris, STM32, STMSMI,
|
||||
STR7x, STR9x, nRF51; NAND controllers of AT91SAM9, LPC3180, LPC32xx,
|
||||
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.
|
||||
|
||||
|
||||
|
|
|
@ -115,7 +115,8 @@ m4_define([USB1_ADAPTERS],
|
|||
[[ulink], [Keil ULINK JTAG Programmer], [ULINK]],
|
||||
[[usb_blaster_2], [Altera USB-Blaster II Compatible], [USB_BLASTER_2]],
|
||||
[[ft232r], [Bitbang mode of FT232R based devices], [FT232R]],
|
||||
[[vsllink], [Versaloon-Link JTAG Programmer], [VSLLINK]]])
|
||||
[[vsllink], [Versaloon-Link JTAG Programmer], [VSLLINK]],
|
||||
[[xds110], [TI XDS110 Debug Probe], [XDS110]]])
|
||||
|
||||
m4_define([USB_ADAPTERS],
|
||||
[[[osbdm], [OSBDM (JTAG only) Programmer], [OSBDM]],
|
||||
|
|
|
@ -128,6 +128,12 @@ ATTRS{idVendor}=="1781", ATTRS{idProduct}=="0c63", MODE="660", GROUP="plugdev",
|
|||
# TI/Luminary Stellaris In-Circuit Debug Interface (ICDI) Board
|
||||
ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="00fd", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
||||
|
||||
# TI XDS110 Debug Probe (Launchpads and Standalone)
|
||||
ATTRS{idVendor}=="0451", ATTRS{idProduct}=="bef3", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
||||
|
||||
# TI Tiva-based ICDI and XDS110 probes in DFU mode
|
||||
ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="00ff", MODE="660", GROUP="plugdev", TAG+="uaccess"
|
||||
|
||||
# Ambiq Micro EVK and Debug boards.
|
||||
ATTRS{idVendor}=="2aec", ATTRS{idProduct}=="6010", MODE="664", GROUP="plugdev", TAG+="uaccess"
|
||||
ATTRS{idVendor}=="2aec", ATTRS{idProduct}=="6011", MODE="664", GROUP="plugdev", TAG+="uaccess"
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
BIN2C = ../../../../src/helper/bin2char.sh
|
||||
|
||||
CROSS_COMPILE ?= arm-none-eabi-
|
||||
AS = $(CROSS_COMPILE)as
|
||||
OBJCOPY = $(CROSS_COMPILE)objcopy
|
||||
|
||||
all: cc3220sf.inc
|
||||
|
||||
%.elf: %.s
|
||||
$(AS) $< -o $@
|
||||
|
||||
%.bin: %.elf
|
||||
$(OBJCOPY) -Obinary $< $@
|
||||
|
||||
%.inc: %.bin
|
||||
$(BIN2C) < $< > $@
|
||||
|
||||
clean:
|
||||
-rm -f *.elf *.bin *.inc
|
|
@ -0,0 +1,10 @@
|
|||
/* Autogenerated with ../../../../src/helper/bin2char.sh */
|
||||
0xdf,0xf8,0x7c,0xa0,0xdf,0xf8,0x7c,0xb0,0xdf,0xf8,0x7c,0xc0,0x01,0xf0,0x7f,0x03,
|
||||
0x00,0x2b,0x1e,0xd1,0x4f,0xf0,0x00,0x04,0xcc,0xf8,0x00,0x10,0x03,0x68,0xcb,0xf8,
|
||||
0x00,0x30,0x0b,0xf1,0x04,0x0b,0x00,0xf1,0x04,0x00,0xa2,0xf1,0x01,0x02,0x04,0xf1,
|
||||
0x01,0x04,0x01,0xf1,0x04,0x01,0x00,0x2a,0x01,0xd0,0x20,0x2c,0xee,0xd1,0xcc,0xf8,
|
||||
0x20,0xa0,0xdc,0xf8,0x20,0x30,0x13,0xf0,0x01,0x0f,0xfa,0xd1,0x00,0x2a,0xd7,0xd1,
|
||||
0x13,0xe0,0xcc,0xf8,0x00,0x10,0x03,0x68,0xcc,0xf8,0x04,0x30,0xcc,0xf8,0x08,0xa0,
|
||||
0xdc,0xf8,0x08,0x30,0x13,0xf0,0x01,0x0f,0xfa,0xd1,0xa2,0xf1,0x01,0x02,0x00,0xf1,
|
||||
0x04,0x00,0x01,0xf1,0x04,0x01,0x00,0x2a,0xc2,0xd1,0x00,0xbe,0x01,0xbe,0xfc,0xe7,
|
||||
0x01,0x00,0x42,0xa4,0x00,0xd1,0x0f,0x40,0x00,0xd0,0x0f,0x40,
|
|
@ -0,0 +1,93 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2017 by Texas Instruments, Inc. *
|
||||
* *
|
||||
* 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 <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
/* Params:
|
||||
* r0 = buffer start address (in)
|
||||
* r1 = flash destination address (in)
|
||||
* r2 = number of words to write (in/out)
|
||||
*/
|
||||
|
||||
.text
|
||||
.cpu cortex-m4
|
||||
.code 16
|
||||
.thumb
|
||||
.syntax unified
|
||||
|
||||
.align 2
|
||||
|
||||
/* r3 = scratchpad
|
||||
* r4 = buffer word counter
|
||||
* r10 = flash programming key
|
||||
* r11 = base FWB address
|
||||
* r12 = base flash regs address
|
||||
*/
|
||||
|
||||
start:
|
||||
ldr r10, =0xa4420001 /* flash programming key */
|
||||
ldr r11, =0x400fd100 /* base of FWB */
|
||||
ldr r12, =0x400fd000 /* base of flash regs */
|
||||
and r3, r1, #0x7f /* is the dest address 32 word aligned? */
|
||||
cmp r3, #0
|
||||
bne program_word /* if not aligned do one word at a time */
|
||||
|
||||
/* program using the write buffers */
|
||||
program_buffer:
|
||||
mov r4, #0 /* start the buffer word counter at 0 */
|
||||
str r1, [r12] /* store the dest addr in FMA */
|
||||
fill_buffer:
|
||||
ldr r3, [r0] /* get the word to write to FWB */
|
||||
str r3, [r11] /* store the word in the FWB */
|
||||
add r11, r11, #4 /* increment the FWB pointer */
|
||||
add r0, r0, #4 /* increment the source pointer */
|
||||
sub r2, r2, #1 /* decrement the total word counter */
|
||||
add r4, r4, #1 /* increment the buffer word counter */
|
||||
add r1, r1, #4 /* increment the dest pointer */
|
||||
cmp r2, #0 /* is the total word counter now 0? */
|
||||
beq buffer_ready /* go to end if total word counter is 0 */
|
||||
cmp r4, #32 /* is the buffer word counter now 32? */
|
||||
bne fill_buffer /* go to continue to fill buffer */
|
||||
buffer_ready:
|
||||
str r10, [r12, #0x20] /* store the key and write bit to FMC2 */
|
||||
wait_buffer_done:
|
||||
ldr r3, [r12, #0x20] /* read FMC2 */
|
||||
tst r3, #1 /* see if the write bit is cleared */
|
||||
bne wait_buffer_done /* go to read FMC2 if bit not cleared */
|
||||
cmp r2, #0 /* is the total word counter now 0? */
|
||||
bne start /* go if there is more to program */
|
||||
b exit
|
||||
|
||||
/* program just one word */
|
||||
program_word:
|
||||
str r1, [r12] /* store the dest addr in FMA */
|
||||
ldr r3, [r0] /* get the word to write to FMD */
|
||||
str r3, [r12, #0x4] /* store the word in FMD */
|
||||
str r10, [r12, #0x8] /* store the key and write bit to FMC */
|
||||
wait_word_done:
|
||||
ldr r3, [r12, #0x8] /* read FMC */
|
||||
tst r3, #1 /* see if the write bit is cleared */
|
||||
bne wait_word_done /* go to read FMC if bit not cleared */
|
||||
sub r2, r2, #1 /* decrement the total word counter */
|
||||
add r0, r0, #4 /* increment the source pointer */
|
||||
add r1, r1, #4 /* increment the dest pointer */
|
||||
cmp r2, #0 /* is the total word counter now 0 */
|
||||
bne start /* go if there is more to program */
|
||||
|
||||
/* end */
|
||||
exit:
|
||||
bkpt #0
|
||||
bkpt #1
|
||||
b exit
|
106
doc/openocd.texi
106
doc/openocd.texi
|
@ -531,6 +531,12 @@ debuggers to ARM Cortex based targets @url{http://www.keil.com/support/man/docs/
|
|||
|
||||
@item @b{Keil ULINK v1}
|
||||
@* Link: @url{http://www.keil.com/ulink1/}
|
||||
|
||||
@item @b{TI XDS110 Debug Probe}
|
||||
@* The XDS110 is included as the embedded debug probe on many Texas Instruments
|
||||
LaunchPad evaluation boards.
|
||||
@* Link: @url{http://processors.wiki.ti.com/index.php/XDS110}
|
||||
@* Link: @url{http://processors.wiki.ti.com/index.php/XDS_Emulation_Software_Package#XDS110_Support_Utilities}
|
||||
@end itemize
|
||||
|
||||
@section IBM PC Parallel Printer Port Based
|
||||
|
@ -5572,6 +5578,20 @@ Triggering a mass erase is also useful when users want to disable readout protec
|
|||
|
||||
@end deffn
|
||||
|
||||
@deffn {Flash Driver} cc3220sf
|
||||
The CC3220SF version of the SimpleLink CC32xx microcontrollers from Texas
|
||||
Instruments includes 1MB of internal flash. The cc3220sf flash driver only
|
||||
supports the internal flash. The serial flash on SimpleLink boards is
|
||||
programmed via the bootloader over a UART connection. Security features of
|
||||
the CC3220SF may erase the internal flash during power on reset. Refer to
|
||||
documentation at @url{www.ti.com/cc3220sf} for details on security features
|
||||
and programming the serial flash.
|
||||
|
||||
@example
|
||||
flash bank $_FLASHNAME cc3220sf 0 0 0 0 $_TARGETNAME
|
||||
@end example
|
||||
@end deffn
|
||||
|
||||
@deffn {Flash Driver} efm32
|
||||
All members of the EFM32 microcontroller family from Energy Micro include
|
||||
internal flash and use ARM Cortex-M3 cores. The driver automatically recognizes
|
||||
|
@ -6122,6 +6142,68 @@ The @var{num} parameter is a value shown by @command{flash banks}.
|
|||
@end deffn
|
||||
@end deffn
|
||||
|
||||
@deffn {Flash Driver} psoc5lp
|
||||
All members of the PSoC 5LP microcontroller family from Cypress
|
||||
include internal program flash and use ARM Cortex-M3 cores.
|
||||
The driver probes for a number of these chips and autoconfigures itself,
|
||||
apart from the base address.
|
||||
|
||||
@example
|
||||
flash bank $_FLASHNAME psoc5lp 0x00000000 0 0 0 $_TARGETNAME
|
||||
@end example
|
||||
|
||||
@b{Note:} PSoC 5LP chips can be configured to have ECC enabled or disabled.
|
||||
@quotation Attention
|
||||
If flash operations are performed in ECC-disabled mode, they will also affect
|
||||
the ECC flash region. Erasing a 16k flash sector in the 0x00000000 area will
|
||||
then also erase the corresponding 2k data bytes in the 0x48000000 area.
|
||||
Writing to the ECC data bytes in ECC-disabled mode is not implemented.
|
||||
@end quotation
|
||||
|
||||
Commands defined in the @var{psoc5lp} driver:
|
||||
|
||||
@deffn Command {psoc5lp mass_erase}
|
||||
Erases all flash data and ECC/configuration bytes, all flash protection rows,
|
||||
and all row latches in all flash arrays on the device.
|
||||
@end deffn
|
||||
@end deffn
|
||||
|
||||
@deffn {Flash Driver} psoc5lp_eeprom
|
||||
All members of the PSoC 5LP microcontroller family from Cypress
|
||||
include internal EEPROM and use ARM Cortex-M3 cores.
|
||||
The driver probes for a number of these chips and autoconfigures itself,
|
||||
apart from the base address.
|
||||
|
||||
@example
|
||||
flash bank $_CHIPNAME.eeprom psoc5lp_eeprom 0x40008000 0 0 0 $_TARGETNAME
|
||||
@end example
|
||||
@end deffn
|
||||
|
||||
@deffn {Flash Driver} psoc5lp_nvl
|
||||
All members of the PSoC 5LP microcontroller family from Cypress
|
||||
include internal Nonvolatile Latches and use ARM Cortex-M3 cores.
|
||||
The driver probes for a number of these chips and autoconfigures itself.
|
||||
|
||||
@example
|
||||
flash bank $_CHIPNAME.nvl psoc5lp_nvl 0 0 0 0 $_TARGETNAME
|
||||
@end example
|
||||
|
||||
PSoC 5LP chips have multiple NV Latches:
|
||||
|
||||
@itemize
|
||||
@item Device Configuration NV Latch - 4 bytes
|
||||
@item Write Once (WO) NV Latch - 4 bytes
|
||||
@end itemize
|
||||
|
||||
@b{Note:} This driver only implements the Device Configuration NVL.
|
||||
|
||||
The @var{psoc5lp} driver reads the ECC mode from Device Configuration NVL.
|
||||
@quotation Attention
|
||||
Switching ECC mode via write to Device Configuration NVL will require a reset
|
||||
after successful write.
|
||||
@end quotation
|
||||
@end deffn
|
||||
|
||||
@deffn {Flash Driver} psoc6
|
||||
Supports PSoC6 (CY8C6xxx) family of Cypress microcontrollers.
|
||||
PSoC6 is a dual-core device with CM0+ and CM4 cores. Both cores share
|
||||
|
@ -8086,6 +8168,30 @@ interacting with remote files or displaying console messages in the
|
|||
debugger.
|
||||
@end deffn
|
||||
|
||||
@deffn Command {arm semihosting_resexit} [@option{enable}|@option{disable}]
|
||||
@cindex ARM semihosting
|
||||
Enable resumable SEMIHOSTING_SYS_EXIT.
|
||||
|
||||
When SEMIHOSTING_SYS_EXIT is called outside a debug session,
|
||||
things are simple, the openocd process calls exit() and passes
|
||||
the value returned by the target.
|
||||
|
||||
When SEMIHOSTING_SYS_EXIT is called during a debug session,
|
||||
by default execution returns to the debugger, leaving the
|
||||
debugger in a HALT state, similar to the state entered when
|
||||
encountering a break.
|
||||
|
||||
In some use cases, it is useful to have SEMIHOSTING_SYS_EXIT
|
||||
return normally, as any semihosting call, and do not break
|
||||
to the debugger.
|
||||
The standard allows this to happen, but the condition
|
||||
to trigger it is a bit obscure ("by performing an RDI_Execute
|
||||
request or equivalent").
|
||||
|
||||
To make the SEMIHOSTING_SYS_EXIT call return normally, enable
|
||||
this option (default: disabled).
|
||||
@end deffn
|
||||
|
||||
@section ARMv4 and ARMv5 Architecture
|
||||
@cindex ARMv4
|
||||
@cindex ARMv5
|
||||
|
|
|
@ -19,6 +19,7 @@ NOR_DRIVERS = \
|
|||
%D%/atsamv.c \
|
||||
%D%/avrf.c \
|
||||
%D%/bluenrg-x.c \
|
||||
%D%/cc3220sf.c \
|
||||
%D%/cfi.c \
|
||||
%D%/dsp5680xx_flash.c \
|
||||
%D%/efm32.c \
|
||||
|
@ -43,6 +44,7 @@ NOR_DRIVERS = \
|
|||
%D%/ocl.c \
|
||||
%D%/pic32mx.c \
|
||||
%D%/psoc4.c \
|
||||
%D%/psoc5lp.c \
|
||||
%D%/psoc6.c \
|
||||
%D%/sim3x.c \
|
||||
%D%/spi.c \
|
||||
|
@ -64,6 +66,7 @@ NOR_DRIVERS = \
|
|||
|
||||
NORHEADERS = \
|
||||
%D%/core.h \
|
||||
%D%/cc3220sf.h \
|
||||
%D%/cfi.h \
|
||||
%D%/driver.h \
|
||||
%D%/imp.h \
|
||||
|
|
|
@ -0,0 +1,529 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2017 by Texas Instruments, Inc. *
|
||||
* *
|
||||
* 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 <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "imp.h"
|
||||
#include "cc3220sf.h"
|
||||
#include <helper/time_support.h>
|
||||
#include <target/algorithm.h>
|
||||
#include <target/armv7m.h>
|
||||
|
||||
#define FLASH_TIMEOUT 5000
|
||||
|
||||
struct cc3220sf_bank {
|
||||
bool probed;
|
||||
struct armv7m_algorithm armv7m_info;
|
||||
};
|
||||
|
||||
static int cc3220sf_mass_erase(struct flash_bank *bank)
|
||||
{
|
||||
struct target *target = bank->target;
|
||||
bool done;
|
||||
long long start_ms;
|
||||
long long elapsed_ms;
|
||||
uint32_t value;
|
||||
|
||||
int retval = ERROR_OK;
|
||||
|
||||
if (TARGET_HALTED != target->state) {
|
||||
LOG_ERROR("Target not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
/* Set starting address to erase to zero */
|
||||
retval = target_write_u32(target, FMA_REGISTER_ADDR, 0);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
/* Write the MERASE bit of the FMC register */
|
||||
retval = target_write_u32(target, FMC_REGISTER_ADDR, FMC_MERASE_VALUE);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
/* Poll the MERASE bit until the mass erase is complete */
|
||||
done = false;
|
||||
start_ms = timeval_ms();
|
||||
while (!done) {
|
||||
retval = target_read_u32(target, FMC_REGISTER_ADDR, &value);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
if ((value & FMC_MERASE_BIT) == 0) {
|
||||
/* Bit clears when mass erase is finished */
|
||||
done = true;
|
||||
} else {
|
||||
elapsed_ms = timeval_ms() - start_ms;
|
||||
if (elapsed_ms > 500)
|
||||
keep_alive();
|
||||
if (elapsed_ms > FLASH_TIMEOUT)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!done) {
|
||||
/* Mass erase timed out waiting for confirmation */
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
FLASH_BANK_COMMAND_HANDLER(cc3220sf_flash_bank_command)
|
||||
{
|
||||
struct cc3220sf_bank *cc3220sf_bank;
|
||||
|
||||
if (CMD_ARGC < 6)
|
||||
return ERROR_COMMAND_SYNTAX_ERROR;
|
||||
|
||||
cc3220sf_bank = malloc(sizeof(struct cc3220sf_bank));
|
||||
if (NULL == cc3220sf_bank)
|
||||
return ERROR_FAIL;
|
||||
|
||||
/* Initialize private flash information */
|
||||
cc3220sf_bank->probed = false;
|
||||
|
||||
/* Finish initialization of flash bank */
|
||||
bank->driver_priv = cc3220sf_bank;
|
||||
bank->next = NULL;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int cc3220sf_erase(struct flash_bank *bank, int first, int last)
|
||||
{
|
||||
struct target *target = bank->target;
|
||||
bool done;
|
||||
long long start_ms;
|
||||
long long elapsed_ms;
|
||||
uint32_t address;
|
||||
uint32_t value;
|
||||
|
||||
int retval = ERROR_OK;
|
||||
|
||||
if (TARGET_HALTED != target->state) {
|
||||
LOG_ERROR("Target not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
/* Do a mass erase if user requested all sectors of flash */
|
||||
if ((first == 0) && (last == (bank->num_sectors - 1))) {
|
||||
/* Request mass erase of flash */
|
||||
return cc3220sf_mass_erase(bank);
|
||||
}
|
||||
|
||||
/* Erase requested sectors one by one */
|
||||
for (int i = first; i <= last; i++) {
|
||||
|
||||
/* Determine address of sector to erase */
|
||||
address = FLASH_BASE_ADDR + i * FLASH_SECTOR_SIZE;
|
||||
|
||||
/* Set starting address to erase */
|
||||
retval = target_write_u32(target, FMA_REGISTER_ADDR, address);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
/* Write the ERASE bit of the FMC register */
|
||||
retval = target_write_u32(target, FMC_REGISTER_ADDR, FMC_ERASE_VALUE);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
/* Poll the ERASE bit until the erase is complete */
|
||||
done = false;
|
||||
start_ms = timeval_ms();
|
||||
while (!done) {
|
||||
retval = target_read_u32(target, FMC_REGISTER_ADDR, &value);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
if ((value & FMC_ERASE_BIT) == 0) {
|
||||
/* Bit clears when mass erase is finished */
|
||||
done = true;
|
||||
} else {
|
||||
elapsed_ms = timeval_ms() - start_ms;
|
||||
if (elapsed_ms > 500)
|
||||
keep_alive();
|
||||
if (elapsed_ms > FLASH_TIMEOUT)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!done) {
|
||||
/* Sector erase timed out waiting for confirmation */
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int cc3220sf_protect(struct flash_bank *bank, int set, int first,
|
||||
int last)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int cc3220sf_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||
uint32_t offset, uint32_t count)
|
||||
{
|
||||
struct target *target = bank->target;
|
||||
struct cc3220sf_bank *cc3220sf_bank = bank->driver_priv;
|
||||
struct working_area *algo_working_area;
|
||||
struct working_area *buffer_working_area;
|
||||
struct reg_param reg_params[3];
|
||||
uint32_t algo_base_address;
|
||||
uint32_t algo_buffer_address;
|
||||
uint32_t algo_buffer_size;
|
||||
uint32_t address;
|
||||
uint32_t remaining;
|
||||
uint32_t words;
|
||||
uint32_t result;
|
||||
|
||||
int retval = ERROR_OK;
|
||||
|
||||
if (TARGET_HALTED != target->state) {
|
||||
LOG_ERROR("Target not halted");
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
}
|
||||
|
||||
/* Obtain working area to use for flash helper algorithm */
|
||||
retval = target_alloc_working_area(target, sizeof(cc3220sf_algo),
|
||||
&algo_working_area);
|
||||
if (ERROR_OK != retval)
|
||||
return retval;
|
||||
|
||||
/* Obtain working area to use for flash buffer */
|
||||
retval = target_alloc_working_area(target,
|
||||
target_get_working_area_avail(target), &buffer_working_area);
|
||||
if (ERROR_OK != retval) {
|
||||
target_free_working_area(target, algo_working_area);
|
||||
return retval;
|
||||
}
|
||||
|
||||
algo_base_address = algo_working_area->address;
|
||||
algo_buffer_address = buffer_working_area->address;
|
||||
algo_buffer_size = buffer_working_area->size;
|
||||
|
||||
/* Make sure buffer size is a multiple of 32 word (0x80 byte) chunks */
|
||||
/* (algo runs more efficiently if it operates on 32 words at a time) */
|
||||
if (algo_buffer_size > 0x80)
|
||||
algo_buffer_size &= ~0x7f;
|
||||
|
||||
/* Write flash helper algorithm into target memory */
|
||||
retval = target_write_buffer(target, algo_base_address,
|
||||
sizeof(cc3220sf_algo), cc3220sf_algo);
|
||||
if (ERROR_OK != retval) {
|
||||
target_free_working_area(target, algo_working_area);
|
||||
target_free_working_area(target, buffer_working_area);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Initialize the ARMv7m specific info to run the algorithm */
|
||||
cc3220sf_bank->armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
|
||||
cc3220sf_bank->armv7m_info.core_mode = ARM_MODE_THREAD;
|
||||
|
||||
/* Initialize register params for flash helper algorithm */
|
||||
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_IN_OUT);
|
||||
|
||||
/* Prepare to write to flash */
|
||||
address = FLASH_BASE_ADDR + offset;
|
||||
remaining = count;
|
||||
|
||||
/* The flash hardware can only write complete words to flash. If
|
||||
* an unaligned address is passed in, we must do a read-modify-write
|
||||
* on a word with enough bytes to align the rest of the buffer. And
|
||||
* if less than a whole word remains at the end, we must also do a
|
||||
* read-modify-write on a final word to finish up.
|
||||
*/
|
||||
|
||||
/* Do one word write to align address on 32-bit boundary if needed */
|
||||
if (0 != (address & 0x3)) {
|
||||
uint8_t head[4];
|
||||
|
||||
/* Get starting offset for data to write (will be 1 to 3) */
|
||||
uint32_t head_offset = address & 0x03;
|
||||
|
||||
/* Get the aligned address to write this first word to */
|
||||
uint32_t head_address = address & 0xfffffffc;
|
||||
|
||||
/* Retrieve what is already in flash at the head address */
|
||||
retval = target_read_buffer(target, head_address, sizeof(head), head);
|
||||
|
||||
if (ERROR_OK == retval) {
|
||||
/* Substitute in the new data to write */
|
||||
while ((remaining > 0) && (head_offset < 4)) {
|
||||
head[head_offset] = *buffer;
|
||||
head_offset++;
|
||||
address++;
|
||||
buffer++;
|
||||
remaining--;
|
||||
}
|
||||
}
|
||||
|
||||
if (ERROR_OK == retval) {
|
||||
/* Helper parameters are passed in registers R0-R2 */
|
||||
/* Set start of data buffer, address to write to, and word count */
|
||||
buf_set_u32(reg_params[0].value, 0, 32, algo_buffer_address);
|
||||
buf_set_u32(reg_params[1].value, 0, 32, head_address);
|
||||
buf_set_u32(reg_params[2].value, 0, 32, 1);
|
||||
|
||||
/* Write head value into buffer to flash */
|
||||
retval = target_write_buffer(target, algo_buffer_address,
|
||||
sizeof(head), head);
|
||||
}
|
||||
|
||||
if (ERROR_OK == retval) {
|
||||
/* Execute the flash helper algorithm */
|
||||
retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
|
||||
algo_base_address, 0, FLASH_TIMEOUT,
|
||||
&cc3220sf_bank->armv7m_info);
|
||||
if (ERROR_OK != retval)
|
||||
LOG_ERROR("cc3220sf: Flash algorithm failed to run");
|
||||
|
||||
/* Check that the head value was written to flash */
|
||||
result = buf_get_u32(reg_params[2].value, 0, 32);
|
||||
if (0 != result) {
|
||||
retval = ERROR_FAIL;
|
||||
LOG_ERROR("cc3220sf: Flash operation failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if there's data at end of buffer that isn't a full word */
|
||||
uint32_t tail_count = remaining & 0x03;
|
||||
/* Adjust remaining so it is a multiple of whole words */
|
||||
remaining -= tail_count;
|
||||
|
||||
while ((ERROR_OK == retval) && (remaining > 0)) {
|
||||
/* Set start of data buffer and address to write to */
|
||||
buf_set_u32(reg_params[0].value, 0, 32, algo_buffer_address);
|
||||
buf_set_u32(reg_params[1].value, 0, 32, address);
|
||||
|
||||
/* Download data to write into memory buffer */
|
||||
if (remaining >= algo_buffer_size) {
|
||||
/* Fill up buffer with data to flash */
|
||||
retval = target_write_buffer(target, algo_buffer_address,
|
||||
algo_buffer_size, buffer);
|
||||
if (ERROR_OK != retval)
|
||||
break;
|
||||
|
||||
/* Count to write is in 32-bit words */
|
||||
words = algo_buffer_size / 4;
|
||||
|
||||
/* Bump variables to next data */
|
||||
address += algo_buffer_size;
|
||||
buffer += algo_buffer_size;
|
||||
remaining -= algo_buffer_size;
|
||||
} else {
|
||||
/* Fill buffer with what's left of the data */
|
||||
retval = target_write_buffer(target, algo_buffer_address,
|
||||
remaining, buffer);
|
||||
if (ERROR_OK != retval)
|
||||
break;
|
||||
|
||||
/* Calculate the final word count to write */
|
||||
words = remaining / 4;
|
||||
if (0 != (remaining % 4))
|
||||
words++;
|
||||
|
||||
/* Bump variables to any final data */
|
||||
address += remaining;
|
||||
buffer += remaining;
|
||||
remaining = 0;
|
||||
}
|
||||
|
||||
/* Set number of words to write */
|
||||
buf_set_u32(reg_params[2].value, 0, 32, words);
|
||||
|
||||
/* Execute the flash helper algorithm */
|
||||
retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
|
||||
algo_base_address, 0, FLASH_TIMEOUT,
|
||||
&cc3220sf_bank->armv7m_info);
|
||||
if (ERROR_OK != retval) {
|
||||
LOG_ERROR("cc3220sf: Flash algorithm failed to run");
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check that all words were written to flash */
|
||||
result = buf_get_u32(reg_params[2].value, 0, 32);
|
||||
if (0 != result) {
|
||||
retval = ERROR_FAIL;
|
||||
LOG_ERROR("cc3220sf: Flash operation failed");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Do one word write for any final bytes less than a full word */
|
||||
if ((ERROR_OK == retval) && (0 != tail_count)) {
|
||||
uint8_t tail[4];
|
||||
|
||||
/* Set starting byte offset for data to write */
|
||||
uint32_t tail_offset = 0;
|
||||
|
||||
/* Retrieve what is already in flash at the tail address */
|
||||
retval = target_read_buffer(target, address, sizeof(tail), tail);
|
||||
|
||||
if (ERROR_OK == retval) {
|
||||
/* Substitute in the new data to write */
|
||||
while (tail_count > 0) {
|
||||
tail[tail_offset] = *buffer;
|
||||
tail_offset++;
|
||||
buffer++;
|
||||
tail_count--;
|
||||
}
|
||||
}
|
||||
|
||||
if (ERROR_OK == retval) {
|
||||
/* Set start of data buffer, address to write to, and word count */
|
||||
buf_set_u32(reg_params[0].value, 0, 32, algo_buffer_address);
|
||||
buf_set_u32(reg_params[1].value, 0, 32, address);
|
||||
buf_set_u32(reg_params[2].value, 0, 32, 1);
|
||||
|
||||
/* Write tail value into buffer to flash */
|
||||
retval = target_write_buffer(target, algo_buffer_address,
|
||||
sizeof(tail), tail);
|
||||
}
|
||||
|
||||
if (ERROR_OK == retval) {
|
||||
/* Execute the flash helper algorithm */
|
||||
retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
|
||||
algo_base_address, 0, FLASH_TIMEOUT,
|
||||
&cc3220sf_bank->armv7m_info);
|
||||
if (ERROR_OK != retval)
|
||||
LOG_ERROR("cc3220sf: Flash algorithm failed to run");
|
||||
|
||||
/* Check that the tail was written to flash */
|
||||
result = buf_get_u32(reg_params[2].value, 0, 32);
|
||||
if (0 != result) {
|
||||
retval = ERROR_FAIL;
|
||||
LOG_ERROR("cc3220sf: Flash operation failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Free resources */
|
||||
destroy_reg_param(®_params[0]);
|
||||
destroy_reg_param(®_params[1]);
|
||||
destroy_reg_param(®_params[2]);
|
||||
target_free_working_area(target, algo_working_area);
|
||||
target_free_working_area(target, buffer_working_area);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int cc3220sf_probe(struct flash_bank *bank)
|
||||
{
|
||||
struct cc3220sf_bank *cc3220sf_bank = bank->driver_priv;
|
||||
|
||||
uint32_t base;
|
||||
uint32_t size;
|
||||
int num_sectors;
|
||||
int bank_id;
|
||||
|
||||
bank_id = bank->bank_number;
|
||||
|
||||
if (0 == bank_id) {
|
||||
base = FLASH_BASE_ADDR;
|
||||
size = FLASH_NUM_SECTORS * FLASH_SECTOR_SIZE;
|
||||
num_sectors = FLASH_NUM_SECTORS;
|
||||
} else {
|
||||
/* Invalid bank number somehow */
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (NULL != bank->sectors) {
|
||||
free(bank->sectors);
|
||||
bank->sectors = NULL;
|
||||
}
|
||||
|
||||
bank->sectors = malloc(sizeof(struct flash_sector) * num_sectors);
|
||||
if (NULL == bank->sectors)
|
||||
return ERROR_FAIL;
|
||||
|
||||
bank->base = base;
|
||||
bank->size = size;
|
||||
bank->write_start_alignment = 0;
|
||||
bank->write_end_alignment = 0;
|
||||
bank->num_sectors = num_sectors;
|
||||
|
||||
for (int i = 0; i < num_sectors; i++) {
|
||||
bank->sectors[i].offset = i * FLASH_SECTOR_SIZE;
|
||||
bank->sectors[i].size = FLASH_SECTOR_SIZE;
|
||||
bank->sectors[i].is_erased = -1;
|
||||
bank->sectors[i].is_protected = 0;
|
||||
}
|
||||
|
||||
/* We've successfully recorded the stats on this flash bank */
|
||||
cc3220sf_bank->probed = true;
|
||||
|
||||
/* If we fall through to here, then all went well */
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int cc3220sf_auto_probe(struct flash_bank *bank)
|
||||
{
|
||||
struct cc3220sf_bank *cc3220sf_bank = bank->driver_priv;
|
||||
|
||||
int retval = ERROR_OK;
|
||||
|
||||
if (0 != bank->bank_number) {
|
||||
/* Invalid bank number somehow */
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (!cc3220sf_bank->probed)
|
||||
retval = cc3220sf_probe(bank);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int cc3220sf_protect_check(struct flash_bank *bank)
|
||||
{
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int cc3220sf_info(struct flash_bank *bank, char *buf, int buf_size)
|
||||
{
|
||||
int printed;
|
||||
|
||||
printed = snprintf(buf, buf_size, "CC3220SF with 1MB internal flash\n");
|
||||
|
||||
if (printed >= buf_size)
|
||||
return ERROR_BUF_TOO_SMALL;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
struct flash_driver cc3220sf_flash = {
|
||||
.name = "cc3220sf",
|
||||
.flash_bank_command = cc3220sf_flash_bank_command,
|
||||
.erase = cc3220sf_erase,
|
||||
.protect = cc3220sf_protect,
|
||||
.write = cc3220sf_write,
|
||||
.read = default_flash_read,
|
||||
.probe = cc3220sf_probe,
|
||||
.auto_probe = cc3220sf_auto_probe,
|
||||
.erase_check = default_flash_blank_check,
|
||||
.protect_check = cc3220sf_protect_check,
|
||||
.info = cc3220sf_info,
|
||||
.free_driver_priv = default_flash_free_driver_priv,
|
||||
};
|
|
@ -0,0 +1,45 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2017 by Texas Instruments, Inc. *
|
||||
* *
|
||||
* 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 <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef OPENOCD_FLASH_NOR_CC3220SF_H
|
||||
#define OPENOCD_FLASH_NOR_CC3220SF_H
|
||||
|
||||
/* CC3220SF device types */
|
||||
#define CC3220_NO_TYPE 0 /* Device type not determined yet */
|
||||
#define CC3220_OTHER 1 /* CC3220 variant without flash */
|
||||
#define CC3220SF 2 /* CC3220SF variant with flash */
|
||||
|
||||
/* Flash parameters */
|
||||
#define FLASH_BASE_ADDR 0x01000000
|
||||
#define FLASH_SECTOR_SIZE 2048
|
||||
#define FLASH_NUM_SECTORS 512
|
||||
|
||||
/* CC2200SF flash registers */
|
||||
#define FMA_REGISTER_ADDR 0x400FD000
|
||||
#define FMC_REGISTER_ADDR 0x400FD008
|
||||
#define FMC_DEFAULT_VALUE 0xA4420000
|
||||
#define FMC_ERASE_BIT 0x00000002
|
||||
#define FMC_MERASE_BIT 0x00000004
|
||||
#define FMC_ERASE_VALUE (FMC_DEFAULT_VALUE | FMC_ERASE_BIT)
|
||||
#define FMC_MERASE_VALUE (FMC_DEFAULT_VALUE | FMC_MERASE_BIT)
|
||||
|
||||
/* Flash helper algorithm for CC3220SF */
|
||||
const uint8_t cc3220sf_algo[] = {
|
||||
#include "../../../contrib/loaders/flash/cc3220sf/cc3220sf.inc"
|
||||
};
|
||||
|
||||
#endif /* OPENOCD_FLASH_NOR_CC3220SF_H */
|
|
@ -188,9 +188,17 @@ void flash_free_all_banks(void)
|
|||
else
|
||||
LOG_WARNING("Flash driver of %s does not support free_driver_priv()", bank->name);
|
||||
|
||||
/* For 'virtual' flash driver bank->sectors and bank->prot_blocks pointers are copied from
|
||||
* master flash_bank structure. They point to memory locations allocated by master flash driver
|
||||
* so master driver is responsible for releasing them.
|
||||
* Avoid UB caused by double-free memory corruption if flash bank is 'virtual'. */
|
||||
|
||||
if (strcmp(bank->driver->name, "virtual") != 0) {
|
||||
free(bank->sectors);
|
||||
free(bank->prot_blocks);
|
||||
}
|
||||
|
||||
free(bank->name);
|
||||
free(bank->sectors);
|
||||
free(bank->prot_blocks);
|
||||
free(bank);
|
||||
bank = next;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ extern struct flash_driver ath79_flash;
|
|||
extern struct flash_driver atsamv_flash;
|
||||
extern struct flash_driver avr_flash;
|
||||
extern struct flash_driver bluenrgx_flash;
|
||||
extern struct flash_driver cc3220sf_flash;
|
||||
extern struct flash_driver cfi_flash;
|
||||
extern struct flash_driver dsp5680xx_flash;
|
||||
extern struct flash_driver efm32_flash;
|
||||
|
@ -56,6 +57,9 @@ extern struct flash_driver numicro_flash;
|
|||
extern struct flash_driver ocl_flash;
|
||||
extern struct flash_driver pic32mx_flash;
|
||||
extern struct flash_driver psoc4_flash;
|
||||
extern struct flash_driver psoc5lp_flash;
|
||||
extern struct flash_driver psoc5lp_eeprom_flash;
|
||||
extern struct flash_driver psoc5lp_nvl_flash;
|
||||
extern struct flash_driver psoc6_flash;
|
||||
extern struct flash_driver sim3x_flash;
|
||||
extern struct flash_driver stellaris_flash;
|
||||
|
@ -91,6 +95,7 @@ static struct flash_driver *flash_drivers[] = {
|
|||
&atsamv_flash,
|
||||
&avr_flash,
|
||||
&bluenrgx_flash,
|
||||
&cc3220sf_flash,
|
||||
&cfi_flash,
|
||||
&dsp5680xx_flash,
|
||||
&efm32_flash,
|
||||
|
@ -115,6 +120,9 @@ static struct flash_driver *flash_drivers[] = {
|
|||
&ocl_flash,
|
||||
&pic32mx_flash,
|
||||
&psoc4_flash,
|
||||
&psoc5lp_flash,
|
||||
&psoc5lp_eeprom_flash,
|
||||
&psoc5lp_nvl_flash,
|
||||
&psoc6_flash,
|
||||
&sim3x_flash,
|
||||
&stellaris_flash,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -46,8 +46,13 @@ static void virtual_update_bank_info(struct flash_bank *bank)
|
|||
bank->bus_width = master_bank->bus_width;
|
||||
bank->erased_value = master_bank->erased_value;
|
||||
bank->default_padded_value = master_bank->default_padded_value;
|
||||
bank->write_start_alignment = master_bank->write_start_alignment;
|
||||
bank->write_end_alignment = master_bank->write_end_alignment;
|
||||
bank->minimal_write_gap = master_bank->minimal_write_gap;
|
||||
bank->num_sectors = master_bank->num_sectors;
|
||||
bank->sectors = master_bank->sectors;
|
||||
bank->num_prot_blocks = master_bank->num_prot_blocks;
|
||||
bank->prot_blocks = master_bank->prot_blocks;
|
||||
}
|
||||
|
||||
FLASH_BANK_COMMAND_HANDLER(virtual_flash_bank_command)
|
||||
|
|
|
@ -156,10 +156,12 @@ endif
|
|||
if IMX_GPIO
|
||||
DRIVERFILES += %D%/imx_gpio.c
|
||||
endif
|
||||
|
||||
if KITPROG
|
||||
DRIVERFILES += %D%/kitprog.c
|
||||
endif
|
||||
if XDS110
|
||||
DRIVERFILES += %D%/xds110.c
|
||||
endif
|
||||
|
||||
DRIVERHEADERS = \
|
||||
%D%/bitbang.h \
|
||||
|
|
|
@ -58,11 +58,11 @@
|
|||
/*
|
||||
* Helper func to determine if gpio number valid
|
||||
*
|
||||
* Assume here that there will be less than 1000 gpios on a system
|
||||
* Assume here that there will be less than 10000 gpios on a system
|
||||
*/
|
||||
static int is_gpio_valid(int gpio)
|
||||
{
|
||||
return gpio >= 0 && gpio < 1000;
|
||||
return gpio >= 0 && gpio < 10000;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -89,7 +89,7 @@ static int open_write_close(const char *name, const char *valstr)
|
|||
*/
|
||||
static void unexport_sysfs_gpio(int gpio)
|
||||
{
|
||||
char gpiostr[4];
|
||||
char gpiostr[5];
|
||||
|
||||
if (!is_gpio_valid(gpio))
|
||||
return;
|
||||
|
@ -113,7 +113,7 @@ static void unexport_sysfs_gpio(int gpio)
|
|||
static int setup_sysfs_gpio(int gpio, int is_output, int init_high)
|
||||
{
|
||||
char buf[40];
|
||||
char gpiostr[4];
|
||||
char gpiostr[5];
|
||||
int ret;
|
||||
|
||||
if (!is_gpio_valid(gpio))
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -132,6 +132,9 @@ extern struct jtag_interface kitprog_interface;
|
|||
#if BUILD_IMX_GPIO == 1
|
||||
extern struct jtag_interface imx_gpio_interface;
|
||||
#endif
|
||||
#if BUILD_XDS110 == 1
|
||||
extern struct jtag_interface xds110_interface;
|
||||
#endif
|
||||
#endif /* standard drivers */
|
||||
|
||||
/**
|
||||
|
@ -234,6 +237,9 @@ struct jtag_interface *jtag_interfaces[] = {
|
|||
#if BUILD_IMX_GPIO == 1
|
||||
&imx_gpio_interface,
|
||||
#endif
|
||||
#if BUILD_XDS110 == 1
|
||||
&xds110_interface,
|
||||
#endif
|
||||
#endif /* standard drivers */
|
||||
NULL,
|
||||
};
|
||||
|
|
|
@ -791,64 +791,64 @@ static void gdb_fileio_reply(struct target *target, struct connection *connectio
|
|||
bool program_exited = false;
|
||||
|
||||
if (strcmp(target->fileio_info->identifier, "open") == 0)
|
||||
sprintf(fileio_command, "F%s,%" PRIx32 "/%" PRIx32 ",%" PRIx32 ",%" PRIx32, target->fileio_info->identifier,
|
||||
sprintf(fileio_command, "F%s,%" PRIx64 "/%" PRIx64 ",%" PRIx64 ",%" PRIx64, target->fileio_info->identifier,
|
||||
target->fileio_info->param_1,
|
||||
target->fileio_info->param_2,
|
||||
target->fileio_info->param_3,
|
||||
target->fileio_info->param_4);
|
||||
else if (strcmp(target->fileio_info->identifier, "close") == 0)
|
||||
sprintf(fileio_command, "F%s,%" PRIx32, target->fileio_info->identifier,
|
||||
sprintf(fileio_command, "F%s,%" PRIx64, target->fileio_info->identifier,
|
||||
target->fileio_info->param_1);
|
||||
else if (strcmp(target->fileio_info->identifier, "read") == 0)
|
||||
sprintf(fileio_command, "F%s,%" PRIx32 ",%" PRIx32 ",%" PRIx32, target->fileio_info->identifier,
|
||||
sprintf(fileio_command, "F%s,%" PRIx64 ",%" PRIx64 ",%" PRIx64, target->fileio_info->identifier,
|
||||
target->fileio_info->param_1,
|
||||
target->fileio_info->param_2,
|
||||
target->fileio_info->param_3);
|
||||
else if (strcmp(target->fileio_info->identifier, "write") == 0)
|
||||
sprintf(fileio_command, "F%s,%" PRIx32 ",%" PRIx32 ",%" PRIx32, target->fileio_info->identifier,
|
||||
sprintf(fileio_command, "F%s,%" PRIx64 ",%" PRIx64 ",%" PRIx64, target->fileio_info->identifier,
|
||||
target->fileio_info->param_1,
|
||||
target->fileio_info->param_2,
|
||||
target->fileio_info->param_3);
|
||||
else if (strcmp(target->fileio_info->identifier, "lseek") == 0)
|
||||
sprintf(fileio_command, "F%s,%" PRIx32 ",%" PRIx32 ",%" PRIx32, target->fileio_info->identifier,
|
||||
sprintf(fileio_command, "F%s,%" PRIx64 ",%" PRIx64 ",%" PRIx64, target->fileio_info->identifier,
|
||||
target->fileio_info->param_1,
|
||||
target->fileio_info->param_2,
|
||||
target->fileio_info->param_3);
|
||||
else if (strcmp(target->fileio_info->identifier, "rename") == 0)
|
||||
sprintf(fileio_command, "F%s,%" PRIx32 "/%" PRIx32 ",%" PRIx32 "/%" PRIx32, target->fileio_info->identifier,
|
||||
sprintf(fileio_command, "F%s,%" PRIx64 "/%" PRIx64 ",%" PRIx64 "/%" PRIx64, target->fileio_info->identifier,
|
||||
target->fileio_info->param_1,
|
||||
target->fileio_info->param_2,
|
||||
target->fileio_info->param_3,
|
||||
target->fileio_info->param_4);
|
||||
else if (strcmp(target->fileio_info->identifier, "unlink") == 0)
|
||||
sprintf(fileio_command, "F%s,%" PRIx32 "/%" PRIx32, target->fileio_info->identifier,
|
||||
sprintf(fileio_command, "F%s,%" PRIx64 "/%" PRIx64, target->fileio_info->identifier,
|
||||
target->fileio_info->param_1,
|
||||
target->fileio_info->param_2);
|
||||
else if (strcmp(target->fileio_info->identifier, "stat") == 0)
|
||||
sprintf(fileio_command, "F%s,%" PRIx32 "/%" PRIx32 ",%" PRIx32, target->fileio_info->identifier,
|
||||
sprintf(fileio_command, "F%s,%" PRIx64 "/%" PRIx64 ",%" PRIx64, target->fileio_info->identifier,
|
||||
target->fileio_info->param_1,
|
||||
target->fileio_info->param_2,
|
||||
target->fileio_info->param_3);
|
||||
else if (strcmp(target->fileio_info->identifier, "fstat") == 0)
|
||||
sprintf(fileio_command, "F%s,%" PRIx32 ",%" PRIx32, target->fileio_info->identifier,
|
||||
sprintf(fileio_command, "F%s,%" PRIx64 ",%" PRIx64, target->fileio_info->identifier,
|
||||
target->fileio_info->param_1,
|
||||
target->fileio_info->param_2);
|
||||
else if (strcmp(target->fileio_info->identifier, "gettimeofday") == 0)
|
||||
sprintf(fileio_command, "F%s,%" PRIx32 ",%" PRIx32, target->fileio_info->identifier,
|
||||
sprintf(fileio_command, "F%s,%" PRIx64 ",%" PRIx64, target->fileio_info->identifier,
|
||||
target->fileio_info->param_1,
|
||||
target->fileio_info->param_2);
|
||||
else if (strcmp(target->fileio_info->identifier, "isatty") == 0)
|
||||
sprintf(fileio_command, "F%s,%" PRIx32, target->fileio_info->identifier,
|
||||
sprintf(fileio_command, "F%s,%" PRIx64, target->fileio_info->identifier,
|
||||
target->fileio_info->param_1);
|
||||
else if (strcmp(target->fileio_info->identifier, "system") == 0)
|
||||
sprintf(fileio_command, "F%s,%" PRIx32 "/%" PRIx32, target->fileio_info->identifier,
|
||||
sprintf(fileio_command, "F%s,%" PRIx64 "/%" PRIx64, target->fileio_info->identifier,
|
||||
target->fileio_info->param_1,
|
||||
target->fileio_info->param_2);
|
||||
else if (strcmp(target->fileio_info->identifier, "exit") == 0) {
|
||||
/* If target hits exit syscall, report to GDB the program is terminated.
|
||||
* In addition, let target run its own exit syscall handler. */
|
||||
program_exited = true;
|
||||
sprintf(fileio_command, "W%02" PRIx32, target->fileio_info->param_1);
|
||||
sprintf(fileio_command, "W%02" PRIx64, target->fileio_info->param_1);
|
||||
} else {
|
||||
LOG_DEBUG("Unknown syscall: %s", target->fileio_info->identifier);
|
||||
|
||||
|
@ -2704,6 +2704,7 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p
|
|||
|
||||
/* simple case, a continue packet */
|
||||
if (parse[0] == 'c') {
|
||||
gdb_running_type = 'c';
|
||||
LOG_DEBUG("target %s continue", target_name(target));
|
||||
log_add_callback(gdb_log_callback, connection);
|
||||
retval = target_resume(target, 1, 0, 0, 0);
|
||||
|
@ -2730,6 +2731,7 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p
|
|||
|
||||
/* single-step or step-over-breakpoint */
|
||||
if (parse[0] == 's') {
|
||||
gdb_running_type = 's';
|
||||
bool fake_step = false;
|
||||
|
||||
if (strncmp(parse, "s:", 2) == 0) {
|
||||
|
|
|
@ -40,6 +40,7 @@ TARGET_CORE_SRC = \
|
|||
%D%/target.c \
|
||||
%D%/target_request.c \
|
||||
%D%/testee.c \
|
||||
%D%/semihosting_common.c \
|
||||
%D%/smp.c
|
||||
|
||||
ARMV4_5_SRC = \
|
||||
|
@ -218,6 +219,7 @@ RISCV_SRC = \
|
|||
%D%/nds32_v3.h \
|
||||
%D%/nds32_v3m.h \
|
||||
%D%/nds32_aice.h \
|
||||
%D%/semihosting_common.h \
|
||||
%D%/stm8.h \
|
||||
%D%/lakemont.h \
|
||||
%D%/x86_32_common.h \
|
||||
|
|
|
@ -2590,6 +2590,143 @@ COMMAND_HANDLER(aarch64_mask_interrupts_command)
|
|||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int jim_mcrmrc(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
|
||||
{
|
||||
struct command_context *context;
|
||||
struct target *target;
|
||||
struct arm *arm;
|
||||
int retval;
|
||||
bool is_mcr = false;
|
||||
int arg_cnt = 0;
|
||||
|
||||
if (Jim_CompareStringImmediate(interp, argv[0], "mcr")) {
|
||||
is_mcr = true;
|
||||
arg_cnt = 7;
|
||||
} else {
|
||||
arg_cnt = 6;
|
||||
}
|
||||
|
||||
context = current_command_context(interp);
|
||||
assert(context != NULL);
|
||||
|
||||
target = get_current_target(context);
|
||||
if (target == NULL) {
|
||||
LOG_ERROR("%s: no current target", __func__);
|
||||
return JIM_ERR;
|
||||
}
|
||||
if (!target_was_examined(target)) {
|
||||
LOG_ERROR("%s: not yet examined", target_name(target));
|
||||
return JIM_ERR;
|
||||
}
|
||||
|
||||
arm = target_to_arm(target);
|
||||
if (!is_arm(arm)) {
|
||||
LOG_ERROR("%s: not an ARM", target_name(target));
|
||||
return JIM_ERR;
|
||||
}
|
||||
|
||||
if (target->state != TARGET_HALTED)
|
||||
return ERROR_TARGET_NOT_HALTED;
|
||||
|
||||
if (arm->core_state == ARM_STATE_AARCH64) {
|
||||
LOG_ERROR("%s: not 32-bit arm target", target_name(target));
|
||||
return JIM_ERR;
|
||||
}
|
||||
|
||||
if (argc != arg_cnt) {
|
||||
LOG_ERROR("%s: wrong number of arguments", __func__);
|
||||
return JIM_ERR;
|
||||
}
|
||||
|
||||
int cpnum;
|
||||
uint32_t op1;
|
||||
uint32_t op2;
|
||||
uint32_t CRn;
|
||||
uint32_t CRm;
|
||||
uint32_t value;
|
||||
long l;
|
||||
|
||||
/* NOTE: parameter sequence matches ARM instruction set usage:
|
||||
* MCR pNUM, op1, rX, CRn, CRm, op2 ; write CP from rX
|
||||
* MRC pNUM, op1, rX, CRn, CRm, op2 ; read CP into rX
|
||||
* The "rX" is necessarily omitted; it uses Tcl mechanisms.
|
||||
*/
|
||||
retval = Jim_GetLong(interp, argv[1], &l);
|
||||
if (retval != JIM_OK)
|
||||
return retval;
|
||||
if (l & ~0xf) {
|
||||
LOG_ERROR("%s: %s %d out of range", __func__,
|
||||
"coprocessor", (int) l);
|
||||
return JIM_ERR;
|
||||
}
|
||||
cpnum = l;
|
||||
|
||||
retval = Jim_GetLong(interp, argv[2], &l);
|
||||
if (retval != JIM_OK)
|
||||
return retval;
|
||||
if (l & ~0x7) {
|
||||
LOG_ERROR("%s: %s %d out of range", __func__,
|
||||
"op1", (int) l);
|
||||
return JIM_ERR;
|
||||
}
|
||||
op1 = l;
|
||||
|
||||
retval = Jim_GetLong(interp, argv[3], &l);
|
||||
if (retval != JIM_OK)
|
||||
return retval;
|
||||
if (l & ~0xf) {
|
||||
LOG_ERROR("%s: %s %d out of range", __func__,
|
||||
"CRn", (int) l);
|
||||
return JIM_ERR;
|
||||
}
|
||||
CRn = l;
|
||||
|
||||
retval = Jim_GetLong(interp, argv[4], &l);
|
||||
if (retval != JIM_OK)
|
||||
return retval;
|
||||
if (l & ~0xf) {
|
||||
LOG_ERROR("%s: %s %d out of range", __func__,
|
||||
"CRm", (int) l);
|
||||
return JIM_ERR;
|
||||
}
|
||||
CRm = l;
|
||||
|
||||
retval = Jim_GetLong(interp, argv[5], &l);
|
||||
if (retval != JIM_OK)
|
||||
return retval;
|
||||
if (l & ~0x7) {
|
||||
LOG_ERROR("%s: %s %d out of range", __func__,
|
||||
"op2", (int) l);
|
||||
return JIM_ERR;
|
||||
}
|
||||
op2 = l;
|
||||
|
||||
value = 0;
|
||||
|
||||
if (is_mcr == true) {
|
||||
retval = Jim_GetLong(interp, argv[6], &l);
|
||||
if (retval != JIM_OK)
|
||||
return retval;
|
||||
value = l;
|
||||
|
||||
/* NOTE: parameters reordered! */
|
||||
/* ARMV4_5_MCR(cpnum, op1, 0, CRn, CRm, op2) */
|
||||
retval = arm->mcr(target, cpnum, op1, op2, CRn, CRm, value);
|
||||
if (retval != ERROR_OK)
|
||||
return JIM_ERR;
|
||||
} else {
|
||||
/* NOTE: parameters reordered! */
|
||||
/* ARMV4_5_MRC(cpnum, op1, 0, CRn, CRm, op2) */
|
||||
retval = arm->mrc(target, cpnum, op1, op2, CRn, CRm, &value);
|
||||
if (retval != ERROR_OK)
|
||||
return JIM_ERR;
|
||||
|
||||
Jim_SetResult(interp, Jim_NewIntObj(interp, value));
|
||||
}
|
||||
|
||||
return JIM_OK;
|
||||
}
|
||||
|
||||
static const struct command_registration aarch64_exec_command_handlers[] = {
|
||||
{
|
||||
.name = "cache_info",
|
||||
|
@ -2625,9 +2762,25 @@ static const struct command_registration aarch64_exec_command_handlers[] = {
|
|||
.help = "mask aarch64 interrupts during single-step",
|
||||
.usage = "['on'|'off']",
|
||||
},
|
||||
{
|
||||
.name = "mcr",
|
||||
.mode = COMMAND_EXEC,
|
||||
.jim_handler = jim_mcrmrc,
|
||||
.help = "write coprocessor register",
|
||||
.usage = "cpnum op1 CRn CRm op2 value",
|
||||
},
|
||||
{
|
||||
.name = "mrc",
|
||||
.mode = COMMAND_EXEC,
|
||||
.jim_handler = jim_mcrmrc,
|
||||
.help = "read coprocessor register",
|
||||
.usage = "cpnum op1 CRn CRm op2",
|
||||
},
|
||||
|
||||
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
|
||||
static const struct command_registration aarch64_command_handlers[] = {
|
||||
{
|
||||
.chain = armv8_command_handlers,
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
* Copyright (C) 2009 by Øyvind Harboe
|
||||
* oyvind.harboe@zylin.com
|
||||
*
|
||||
* Copyright (C) 2018 by Liviu Ionescu
|
||||
* <ilg@livius.net>
|
||||
*
|
||||
* 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
|
||||
|
@ -28,7 +31,6 @@
|
|||
#include <helper/command.h>
|
||||
#include "target.h"
|
||||
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Holds the interface to ARM cores.
|
||||
|
@ -181,32 +183,11 @@ struct arm {
|
|||
/** Flag reporting armv6m based core. */
|
||||
bool is_armv6m;
|
||||
|
||||
/** Flag reporting whether semihosting is active. */
|
||||
bool is_semihosting;
|
||||
|
||||
/** Flag reporting whether semihosting fileio is active. */
|
||||
bool is_semihosting_fileio;
|
||||
|
||||
/** Flag reporting whether semihosting fileio operation is active. */
|
||||
bool semihosting_hit_fileio;
|
||||
|
||||
/** Floating point or VFP version, 0 if disabled. */
|
||||
int arm_vfp_version;
|
||||
|
||||
/** Current semihosting operation. */
|
||||
int semihosting_op;
|
||||
|
||||
/** Current semihosting result. */
|
||||
int semihosting_result;
|
||||
|
||||
/** Value to be returned by semihosting SYS_ERRNO request. */
|
||||
int semihosting_errno;
|
||||
|
||||
int (*setup_semihosting)(struct target *target, int enable);
|
||||
|
||||
/** Semihosting command line. */
|
||||
char *semihosting_cmdline;
|
||||
|
||||
/** Backpointer to the target. */
|
||||
struct target *target;
|
||||
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
* Copyright (C) 2016 by Square, Inc. *
|
||||
* Steven Stallion <stallion@squareup.com> *
|
||||
* *
|
||||
* Copyright (C) 2018 by Liviu Ionescu *
|
||||
* <ilg@livius.net> *
|
||||
* *
|
||||
* 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 *
|
||||
|
@ -52,21 +55,6 @@
|
|||
#include <helper/log.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
static const int open_modeflags[12] = {
|
||||
O_RDONLY,
|
||||
O_RDONLY | O_BINARY,
|
||||
O_RDWR,
|
||||
O_RDWR | O_BINARY,
|
||||
O_WRONLY | O_CREAT | O_TRUNC,
|
||||
O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
|
||||
O_RDWR | O_CREAT | O_TRUNC,
|
||||
O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
|
||||
O_WRONLY | O_CREAT | O_APPEND,
|
||||
O_WRONLY | O_CREAT | O_APPEND | O_BINARY,
|
||||
O_RDWR | O_CREAT | O_APPEND,
|
||||
O_RDWR | O_CREAT | O_APPEND | O_BINARY
|
||||
};
|
||||
|
||||
static int post_result(struct target *target)
|
||||
{
|
||||
struct arm *arm = target_to_arm(target);
|
||||
|
@ -79,7 +67,7 @@ static int post_result(struct target *target)
|
|||
uint32_t spsr;
|
||||
|
||||
/* return value in R0 */
|
||||
buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, arm->semihosting_result);
|
||||
buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, target->semihosting->result);
|
||||
arm->core_cache->reg_list[0].dirty = 1;
|
||||
|
||||
/* LR --> PC */
|
||||
|
@ -105,523 +93,13 @@ static int post_result(struct target *target)
|
|||
* bkpt instruction */
|
||||
|
||||
/* return result in R0 */
|
||||
buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, arm->semihosting_result);
|
||||
buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, target->semihosting->result);
|
||||
arm->core_cache->reg_list[0].dirty = 1;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int do_semihosting(struct target *target)
|
||||
{
|
||||
struct arm *arm = target_to_arm(target);
|
||||
struct gdb_fileio_info *fileio_info = target->fileio_info;
|
||||
uint32_t r0 = buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32);
|
||||
uint32_t r1 = buf_get_u32(arm->core_cache->reg_list[1].value, 0, 32);
|
||||
uint8_t params[16];
|
||||
int retval;
|
||||
|
||||
/*
|
||||
* TODO: lots of security issues are not considered yet, such as:
|
||||
* - no validation on target provided file descriptors
|
||||
* - no safety checks on opened/deleted/renamed file paths
|
||||
* Beware the target app you use this support with.
|
||||
*
|
||||
* TODO: unsupported semihosting fileio operations could be
|
||||
* implemented if we had a small working area at our disposal.
|
||||
*/
|
||||
switch ((arm->semihosting_op = r0)) {
|
||||
case 0x01: /* SYS_OPEN */
|
||||
retval = target_read_memory(target, r1, 4, 3, params);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
else {
|
||||
uint32_t a = target_buffer_get_u32(target, params+0);
|
||||
uint32_t m = target_buffer_get_u32(target, params+4);
|
||||
uint32_t l = target_buffer_get_u32(target, params+8);
|
||||
uint8_t fn[256];
|
||||
retval = target_read_memory(target, a, 1, l, fn);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
fn[l] = 0;
|
||||
if (arm->is_semihosting_fileio) {
|
||||
if (strcmp((char *)fn, ":tt") == 0)
|
||||
arm->semihosting_result = 0;
|
||||
else {
|
||||
arm->semihosting_hit_fileio = true;
|
||||
fileio_info->identifier = "open";
|
||||
fileio_info->param_1 = a;
|
||||
fileio_info->param_2 = l;
|
||||
fileio_info->param_3 = open_modeflags[m];
|
||||
fileio_info->param_4 = 0644;
|
||||
}
|
||||
} else {
|
||||
if (l <= 255 && m <= 11) {
|
||||
if (strcmp((char *)fn, ":tt") == 0) {
|
||||
if (m < 4)
|
||||
arm->semihosting_result = dup(STDIN_FILENO);
|
||||
else
|
||||
arm->semihosting_result = dup(STDOUT_FILENO);
|
||||
} else {
|
||||
/* cygwin requires the permission setting
|
||||
* otherwise it will fail to reopen a previously
|
||||
* written file */
|
||||
arm->semihosting_result = open((char *)fn, open_modeflags[m], 0644);
|
||||
}
|
||||
arm->semihosting_errno = errno;
|
||||
} else {
|
||||
arm->semihosting_result = -1;
|
||||
arm->semihosting_errno = EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x02: /* SYS_CLOSE */
|
||||
retval = target_read_memory(target, r1, 4, 1, params);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
else {
|
||||
int fd = target_buffer_get_u32(target, params+0);
|
||||
if (arm->is_semihosting_fileio) {
|
||||
arm->semihosting_hit_fileio = true;
|
||||
fileio_info->identifier = "close";
|
||||
fileio_info->param_1 = fd;
|
||||
} else {
|
||||
arm->semihosting_result = close(fd);
|
||||
arm->semihosting_errno = errno;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x03: /* SYS_WRITEC */
|
||||
if (arm->is_semihosting_fileio) {
|
||||
arm->semihosting_hit_fileio = true;
|
||||
fileio_info->identifier = "write";
|
||||
fileio_info->param_1 = 1;
|
||||
fileio_info->param_2 = r1;
|
||||
fileio_info->param_3 = 1;
|
||||
} else {
|
||||
unsigned char c;
|
||||
retval = target_read_memory(target, r1, 1, 1, &c);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
putchar(c);
|
||||
arm->semihosting_result = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x04: /* SYS_WRITE0 */
|
||||
if (arm->is_semihosting_fileio) {
|
||||
size_t count = 0;
|
||||
for (uint32_t a = r1;; a++) {
|
||||
unsigned char c;
|
||||
retval = target_read_memory(target, a, 1, 1, &c);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
if (c == '\0')
|
||||
break;
|
||||
count++;
|
||||
}
|
||||
arm->semihosting_hit_fileio = true;
|
||||
fileio_info->identifier = "write";
|
||||
fileio_info->param_1 = 1;
|
||||
fileio_info->param_2 = r1;
|
||||
fileio_info->param_3 = count;
|
||||
} else {
|
||||
do {
|
||||
unsigned char c;
|
||||
retval = target_read_memory(target, r1++, 1, 1, &c);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
if (!c)
|
||||
break;
|
||||
putchar(c);
|
||||
} while (1);
|
||||
arm->semihosting_result = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x05: /* SYS_WRITE */
|
||||
retval = target_read_memory(target, r1, 4, 3, params);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
else {
|
||||
int fd = target_buffer_get_u32(target, params+0);
|
||||
uint32_t a = target_buffer_get_u32(target, params+4);
|
||||
size_t l = target_buffer_get_u32(target, params+8);
|
||||
if (arm->is_semihosting_fileio) {
|
||||
arm->semihosting_hit_fileio = true;
|
||||
fileio_info->identifier = "write";
|
||||
fileio_info->param_1 = fd;
|
||||
fileio_info->param_2 = a;
|
||||
fileio_info->param_3 = l;
|
||||
} else {
|
||||
uint8_t *buf = malloc(l);
|
||||
if (!buf) {
|
||||
arm->semihosting_result = -1;
|
||||
arm->semihosting_errno = ENOMEM;
|
||||
} else {
|
||||
retval = target_read_buffer(target, a, l, buf);
|
||||
if (retval != ERROR_OK) {
|
||||
free(buf);
|
||||
return retval;
|
||||
}
|
||||
arm->semihosting_result = write(fd, buf, l);
|
||||
arm->semihosting_errno = errno;
|
||||
if (arm->semihosting_result >= 0)
|
||||
arm->semihosting_result = l - arm->semihosting_result;
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x06: /* SYS_READ */
|
||||
retval = target_read_memory(target, r1, 4, 3, params);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
else {
|
||||
int fd = target_buffer_get_u32(target, params+0);
|
||||
uint32_t a = target_buffer_get_u32(target, params+4);
|
||||
ssize_t l = target_buffer_get_u32(target, params+8);
|
||||
if (arm->is_semihosting_fileio) {
|
||||
arm->semihosting_hit_fileio = true;
|
||||
fileio_info->identifier = "read";
|
||||
fileio_info->param_1 = fd;
|
||||
fileio_info->param_2 = a;
|
||||
fileio_info->param_3 = l;
|
||||
} else {
|
||||
uint8_t *buf = malloc(l);
|
||||
if (!buf) {
|
||||
arm->semihosting_result = -1;
|
||||
arm->semihosting_errno = ENOMEM;
|
||||
} else {
|
||||
arm->semihosting_result = read(fd, buf, l);
|
||||
arm->semihosting_errno = errno;
|
||||
if (arm->semihosting_result >= 0) {
|
||||
retval = target_write_buffer(target, a, arm->semihosting_result, buf);
|
||||
if (retval != ERROR_OK) {
|
||||
free(buf);
|
||||
return retval;
|
||||
}
|
||||
arm->semihosting_result = l - arm->semihosting_result;
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x07: /* SYS_READC */
|
||||
if (arm->is_semihosting_fileio) {
|
||||
LOG_ERROR("SYS_READC not supported by semihosting fileio");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
arm->semihosting_result = getchar();
|
||||
break;
|
||||
|
||||
case 0x08: /* SYS_ISERROR */
|
||||
retval = target_read_memory(target, r1, 4, 1, params);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
arm->semihosting_result = (target_buffer_get_u32(target, params+0) != 0);
|
||||
break;
|
||||
|
||||
case 0x09: /* SYS_ISTTY */
|
||||
if (arm->is_semihosting_fileio) {
|
||||
arm->semihosting_hit_fileio = true;
|
||||
fileio_info->identifier = "isatty";
|
||||
fileio_info->param_1 = r1;
|
||||
} else {
|
||||
retval = target_read_memory(target, r1, 4, 1, params);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
arm->semihosting_result = isatty(target_buffer_get_u32(target, params+0));
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0a: /* SYS_SEEK */
|
||||
retval = target_read_memory(target, r1, 4, 2, params);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
else {
|
||||
int fd = target_buffer_get_u32(target, params+0);
|
||||
off_t pos = target_buffer_get_u32(target, params+4);
|
||||
if (arm->is_semihosting_fileio) {
|
||||
arm->semihosting_hit_fileio = true;
|
||||
fileio_info->identifier = "lseek";
|
||||
fileio_info->param_1 = fd;
|
||||
fileio_info->param_2 = pos;
|
||||
fileio_info->param_3 = SEEK_SET;
|
||||
} else {
|
||||
arm->semihosting_result = lseek(fd, pos, SEEK_SET);
|
||||
arm->semihosting_errno = errno;
|
||||
if (arm->semihosting_result == pos)
|
||||
arm->semihosting_result = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0c: /* SYS_FLEN */
|
||||
if (arm->is_semihosting_fileio) {
|
||||
LOG_ERROR("SYS_FLEN not supported by semihosting fileio");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
retval = target_read_memory(target, r1, 4, 1, params);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
else {
|
||||
int fd = target_buffer_get_u32(target, params+0);
|
||||
struct stat buf;
|
||||
arm->semihosting_result = fstat(fd, &buf);
|
||||
if (arm->semihosting_result == -1) {
|
||||
arm->semihosting_errno = errno;
|
||||
arm->semihosting_result = -1;
|
||||
break;
|
||||
}
|
||||
arm->semihosting_result = buf.st_size;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0e: /* SYS_REMOVE */
|
||||
retval = target_read_memory(target, r1, 4, 2, params);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
else {
|
||||
uint32_t a = target_buffer_get_u32(target, params+0);
|
||||
uint32_t l = target_buffer_get_u32(target, params+4);
|
||||
if (arm->is_semihosting_fileio) {
|
||||
arm->semihosting_hit_fileio = true;
|
||||
fileio_info->identifier = "unlink";
|
||||
fileio_info->param_1 = a;
|
||||
fileio_info->param_2 = l;
|
||||
} else {
|
||||
if (l <= 255) {
|
||||
uint8_t fn[256];
|
||||
retval = target_read_memory(target, a, 1, l, fn);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
fn[l] = 0;
|
||||
arm->semihosting_result = remove((char *)fn);
|
||||
arm->semihosting_errno = errno;
|
||||
} else {
|
||||
arm->semihosting_result = -1;
|
||||
arm->semihosting_errno = EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0f: /* SYS_RENAME */
|
||||
retval = target_read_memory(target, r1, 4, 4, params);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
else {
|
||||
uint32_t a1 = target_buffer_get_u32(target, params+0);
|
||||
uint32_t l1 = target_buffer_get_u32(target, params+4);
|
||||
uint32_t a2 = target_buffer_get_u32(target, params+8);
|
||||
uint32_t l2 = target_buffer_get_u32(target, params+12);
|
||||
if (arm->is_semihosting_fileio) {
|
||||
arm->semihosting_hit_fileio = true;
|
||||
fileio_info->identifier = "rename";
|
||||
fileio_info->param_1 = a1;
|
||||
fileio_info->param_2 = l1;
|
||||
fileio_info->param_3 = a2;
|
||||
fileio_info->param_4 = l2;
|
||||
} else {
|
||||
if (l1 <= 255 && l2 <= 255) {
|
||||
uint8_t fn1[256], fn2[256];
|
||||
retval = target_read_memory(target, a1, 1, l1, fn1);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
retval = target_read_memory(target, a2, 1, l2, fn2);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
fn1[l1] = 0;
|
||||
fn2[l2] = 0;
|
||||
arm->semihosting_result = rename((char *)fn1, (char *)fn2);
|
||||
arm->semihosting_errno = errno;
|
||||
} else {
|
||||
arm->semihosting_result = -1;
|
||||
arm->semihosting_errno = EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x11: /* SYS_TIME */
|
||||
arm->semihosting_result = time(NULL);
|
||||
break;
|
||||
|
||||
case 0x13: /* SYS_ERRNO */
|
||||
arm->semihosting_result = arm->semihosting_errno;
|
||||
break;
|
||||
|
||||
case 0x15: /* SYS_GET_CMDLINE */
|
||||
retval = target_read_memory(target, r1, 4, 2, params);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
else {
|
||||
uint32_t a = target_buffer_get_u32(target, params+0);
|
||||
uint32_t l = target_buffer_get_u32(target, params+4);
|
||||
char *arg = arm->semihosting_cmdline != NULL ? arm->semihosting_cmdline : "";
|
||||
uint32_t s = strlen(arg) + 1;
|
||||
if (l < s)
|
||||
arm->semihosting_result = -1;
|
||||
else {
|
||||
retval = target_write_buffer(target, a, s, (uint8_t *)arg);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
arm->semihosting_result = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x16: /* SYS_HEAPINFO */
|
||||
retval = target_read_memory(target, r1, 4, 1, params);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
else {
|
||||
uint32_t a = target_buffer_get_u32(target, params+0);
|
||||
/* tell the remote we have no idea */
|
||||
memset(params, 0, 4*4);
|
||||
retval = target_write_memory(target, a, 4, 4, params);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
arm->semihosting_result = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x18: /* angel_SWIreason_ReportException */
|
||||
switch (r1) {
|
||||
case 0x20026: /* ADP_Stopped_ApplicationExit */
|
||||
fprintf(stderr, "semihosting: *** application exited ***\n");
|
||||
break;
|
||||
case 0x20000: /* ADP_Stopped_BranchThroughZero */
|
||||
case 0x20001: /* ADP_Stopped_UndefinedInstr */
|
||||
case 0x20002: /* ADP_Stopped_SoftwareInterrupt */
|
||||
case 0x20003: /* ADP_Stopped_PrefetchAbort */
|
||||
case 0x20004: /* ADP_Stopped_DataAbort */
|
||||
case 0x20005: /* ADP_Stopped_AddressException */
|
||||
case 0x20006: /* ADP_Stopped_IRQ */
|
||||
case 0x20007: /* ADP_Stopped_FIQ */
|
||||
case 0x20020: /* ADP_Stopped_BreakPoint */
|
||||
case 0x20021: /* ADP_Stopped_WatchPoint */
|
||||
case 0x20022: /* ADP_Stopped_StepComplete */
|
||||
case 0x20023: /* ADP_Stopped_RunTimeErrorUnknown */
|
||||
case 0x20024: /* ADP_Stopped_InternalError */
|
||||
case 0x20025: /* ADP_Stopped_UserInterruption */
|
||||
case 0x20027: /* ADP_Stopped_StackOverflow */
|
||||
case 0x20028: /* ADP_Stopped_DivisionByZero */
|
||||
case 0x20029: /* ADP_Stopped_OSSpecific */
|
||||
default:
|
||||
fprintf(stderr, "semihosting: exception %#x\n",
|
||||
(unsigned) r1);
|
||||
}
|
||||
return target_call_event_callbacks(target, TARGET_EVENT_HALTED);
|
||||
|
||||
case 0x12: /* SYS_SYSTEM */
|
||||
/* Provide SYS_SYSTEM functionality. Uses the
|
||||
* libc system command, there may be a reason *NOT*
|
||||
* to use this, but as I can't think of one, I
|
||||
* implemented it this way.
|
||||
*/
|
||||
retval = target_read_memory(target, r1, 4, 2, params);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
else {
|
||||
uint32_t len = target_buffer_get_u32(target, params+4);
|
||||
uint32_t c_ptr = target_buffer_get_u32(target, params);
|
||||
if (arm->is_semihosting_fileio) {
|
||||
arm->semihosting_hit_fileio = true;
|
||||
fileio_info->identifier = "system";
|
||||
fileio_info->param_1 = c_ptr;
|
||||
fileio_info->param_2 = len;
|
||||
} else {
|
||||
uint8_t cmd[256];
|
||||
if (len > 255) {
|
||||
arm->semihosting_result = -1;
|
||||
arm->semihosting_errno = EINVAL;
|
||||
} else {
|
||||
memset(cmd, 0x0, 256);
|
||||
retval = target_read_memory(target, c_ptr, 1, len, cmd);
|
||||
if (retval != ERROR_OK)
|
||||
return retval;
|
||||
else
|
||||
arm->semihosting_result = system((const char *)cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x0d: /* SYS_TMPNAM */
|
||||
case 0x10: /* SYS_CLOCK */
|
||||
case 0x17: /* angel_SWIreason_EnterSVC */
|
||||
case 0x30: /* SYS_ELAPSED */
|
||||
case 0x31: /* SYS_TICKFREQ */
|
||||
default:
|
||||
fprintf(stderr, "semihosting: unsupported call %#x\n",
|
||||
(unsigned) r0);
|
||||
arm->semihosting_result = -1;
|
||||
arm->semihosting_errno = ENOTSUP;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info)
|
||||
{
|
||||
struct arm *arm = target_to_arm(target);
|
||||
|
||||
/* To avoid uneccessary duplication, semihosting prepares the
|
||||
* fileio_info structure out-of-band when the target halts. See
|
||||
* do_semihosting for more detail.
|
||||
*/
|
||||
if (!arm->is_semihosting_fileio || !arm->semihosting_hit_fileio)
|
||||
return ERROR_FAIL;
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
static int gdb_fileio_end(struct target *target, int result, int fileio_errno, bool ctrl_c)
|
||||
{
|
||||
struct arm *arm = target_to_arm(target);
|
||||
struct gdb_fileio_info *fileio_info = target->fileio_info;
|
||||
|
||||
/* clear pending status */
|
||||
arm->semihosting_hit_fileio = false;
|
||||
|
||||
arm->semihosting_result = result;
|
||||
arm->semihosting_errno = fileio_errno;
|
||||
|
||||
/* Some fileio results do not match up with what the semihosting
|
||||
* operation expects; for these operations, we munge the results
|
||||
* below:
|
||||
*/
|
||||
switch (arm->semihosting_op) {
|
||||
case 0x05: /* SYS_WRITE */
|
||||
if (result < 0)
|
||||
arm->semihosting_result = fileio_info->param_3;
|
||||
else
|
||||
arm->semihosting_result = 0;
|
||||
break;
|
||||
|
||||
case 0x06: /* SYS_READ */
|
||||
if (result == (int)fileio_info->param_3)
|
||||
arm->semihosting_result = 0;
|
||||
if (result <= 0)
|
||||
arm->semihosting_result = fileio_info->param_3;
|
||||
break;
|
||||
|
||||
case 0x0a: /* SYS_SEEK */
|
||||
if (result > 0)
|
||||
arm->semihosting_result = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return post_result(target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize ARM semihosting support.
|
||||
*
|
||||
|
@ -630,14 +108,9 @@ static int gdb_fileio_end(struct target *target, int result, int fileio_errno, b
|
|||
*/
|
||||
int arm_semihosting_init(struct target *target)
|
||||
{
|
||||
target->fileio_info = malloc(sizeof(*target->fileio_info));
|
||||
if (target->fileio_info == NULL) {
|
||||
LOG_ERROR("out of memory");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
target->type->get_gdb_fileio_info = get_gdb_fileio_info;
|
||||
target->type->gdb_fileio_end = gdb_fileio_end;
|
||||
struct arm *arm = target_to_arm(target);
|
||||
assert(arm->setup_semihosting);
|
||||
semihosting_common_init(target, arm->setup_semihosting, post_result);
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
@ -662,7 +135,11 @@ int arm_semihosting(struct target *target, int *retval)
|
|||
uint32_t pc, lr, spsr;
|
||||
struct reg *r;
|
||||
|
||||
if (!arm->is_semihosting)
|
||||
struct semihosting *semihosting = target->semihosting;
|
||||
if (!semihosting)
|
||||
return 0;
|
||||
|
||||
if (!semihosting->is_active)
|
||||
return 0;
|
||||
|
||||
if (is_arm7_9(target_to_arm7_9(target)) ||
|
||||
|
@ -766,10 +243,24 @@ int arm_semihosting(struct target *target, int *retval)
|
|||
/* Perform semihosting if we are not waiting on a fileio
|
||||
* operation to complete.
|
||||
*/
|
||||
if (!arm->semihosting_hit_fileio) {
|
||||
*retval = do_semihosting(target);
|
||||
if (*retval != ERROR_OK) {
|
||||
LOG_ERROR("Failed semihosting operation");
|
||||
if (!semihosting->hit_fileio) {
|
||||
/* TODO: update for 64-bits */
|
||||
uint32_t r0 = buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32);
|
||||
uint32_t r1 = buf_get_u32(arm->core_cache->reg_list[1].value, 0, 32);
|
||||
|
||||
semihosting->op = r0;
|
||||
semihosting->param = r1;
|
||||
semihosting->word_size_bytes = 4;
|
||||
|
||||
/* Check for ARM operation numbers. */
|
||||
if (0 <= semihosting->op && semihosting->op <= 0x31) {
|
||||
*retval = semihosting_common(target);
|
||||
if (*retval != ERROR_OK) {
|
||||
LOG_ERROR("Failed semihosting operation");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
/* Unknown operation number, not a semihosting call. */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -777,13 +268,8 @@ int arm_semihosting(struct target *target, int *retval)
|
|||
/* Post result to target if we are not waiting on a fileio
|
||||
* operation to complete:
|
||||
*/
|
||||
if (!arm->semihosting_hit_fileio) {
|
||||
*retval = post_result(target);
|
||||
if (*retval != ERROR_OK) {
|
||||
LOG_ERROR("Failed to post semihosting result");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (semihosting->is_resumable && !semihosting->hit_fileio) {
|
||||
/* Resume right after the BRK instruction. */
|
||||
*retval = target_resume(target, 1, 0, 0, 0);
|
||||
if (*retval != ERROR_OK) {
|
||||
LOG_ERROR("Failed to resume target");
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
#ifndef OPENOCD_TARGET_ARM_SEMIHOSTING_H
|
||||
#define OPENOCD_TARGET_ARM_SEMIHOSTING_H
|
||||
|
||||
#include "semihosting_common.h"
|
||||
|
||||
int arm_semihosting_init(struct target *target);
|
||||
int arm_semihosting(struct target *target, int *retval);
|
||||
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
* Copyright (C) 2008 by Oyvind Harboe *
|
||||
* oyvind.harboe@zylin.com *
|
||||
* *
|
||||
* Copyright (C) 2018 by Liviu Ionescu *
|
||||
* <ilg@livius.net> *
|
||||
* *
|
||||
* 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 *
|
||||
|
@ -34,6 +37,7 @@
|
|||
#include <helper/binarybuffer.h>
|
||||
#include "algorithm.h"
|
||||
#include "register.h"
|
||||
#include "semihosting_common.h"
|
||||
|
||||
/* offsets into armv4_5 core register cache */
|
||||
enum {
|
||||
|
@ -748,7 +752,7 @@ int arm_arch_state(struct target *target)
|
|||
}
|
||||
|
||||
/* avoid filling log waiting for fileio reply */
|
||||
if (arm->semihosting_hit_fileio)
|
||||
if (target->semihosting->hit_fileio)
|
||||
return ERROR_OK;
|
||||
|
||||
LOG_USER("target halted in %s state due to %s, current mode: %s\n"
|
||||
|
@ -758,8 +762,8 @@ int arm_arch_state(struct target *target)
|
|||
arm_mode_name(arm->core_mode),
|
||||
buf_get_u32(arm->cpsr->value, 0, 32),
|
||||
buf_get_u32(arm->pc->value, 0, 32),
|
||||
arm->is_semihosting ? ", semihosting" : "",
|
||||
arm->is_semihosting_fileio ? " fileio" : "");
|
||||
target->semihosting->is_active ? ", semihosting" : "",
|
||||
target->semihosting->is_fileio ? " fileio" : "");
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
@ -1094,119 +1098,10 @@ static int jim_mcrmrc(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
|
|||
return JIM_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(handle_arm_semihosting_command)
|
||||
{
|
||||
struct target *target = get_current_target(CMD_CTX);
|
||||
|
||||
if (target == NULL) {
|
||||
LOG_ERROR("No target selected");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
struct arm *arm = target_to_arm(target);
|
||||
|
||||
if (!is_arm(arm)) {
|
||||
command_print(CMD_CTX, "current target isn't an ARM");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (!arm->setup_semihosting) {
|
||||
command_print(CMD_CTX, "semihosting not supported for current target");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (CMD_ARGC > 0) {
|
||||
int semihosting;
|
||||
|
||||
COMMAND_PARSE_ENABLE(CMD_ARGV[0], semihosting);
|
||||
|
||||
if (!target_was_examined(target)) {
|
||||
LOG_ERROR("Target not examined yet");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (arm->setup_semihosting(target, semihosting) != ERROR_OK) {
|
||||
LOG_ERROR("Failed to Configure semihosting");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
/* FIXME never let that "catch" be dropped! */
|
||||
arm->is_semihosting = semihosting;
|
||||
}
|
||||
|
||||
command_print(CMD_CTX, "semihosting is %s",
|
||||
arm->is_semihosting
|
||||
? "enabled" : "disabled");
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(handle_arm_semihosting_fileio_command)
|
||||
{
|
||||
struct target *target = get_current_target(CMD_CTX);
|
||||
|
||||
if (target == NULL) {
|
||||
LOG_ERROR("No target selected");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
struct arm *arm = target_to_arm(target);
|
||||
|
||||
if (!is_arm(arm)) {
|
||||
command_print(CMD_CTX, "current target isn't an ARM");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (!arm->is_semihosting) {
|
||||
command_print(CMD_CTX, "semihosting is not enabled");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (CMD_ARGC > 0)
|
||||
COMMAND_PARSE_ENABLE(CMD_ARGV[0], arm->is_semihosting_fileio);
|
||||
|
||||
command_print(CMD_CTX, "semihosting fileio is %s",
|
||||
arm->is_semihosting_fileio
|
||||
? "enabled" : "disabled");
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
||||
COMMAND_HANDLER(handle_arm_semihosting_cmdline)
|
||||
{
|
||||
struct target *target = get_current_target(CMD_CTX);
|
||||
unsigned int i;
|
||||
|
||||
if (target == NULL) {
|
||||
LOG_ERROR("No target selected");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
struct arm *arm = target_to_arm(target);
|
||||
|
||||
if (!is_arm(arm)) {
|
||||
command_print(CMD_CTX, "current target isn't an ARM");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
if (!arm->setup_semihosting) {
|
||||
command_print(CMD_CTX, "semihosting not supported for current target");
|
||||
return ERROR_FAIL;
|
||||
}
|
||||
|
||||
free(arm->semihosting_cmdline);
|
||||
arm->semihosting_cmdline = CMD_ARGC > 0 ? strdup(CMD_ARGV[0]) : NULL;
|
||||
|
||||
for (i = 1; i < CMD_ARGC; i++) {
|
||||
char *cmdline = alloc_printf("%s %s", arm->semihosting_cmdline, CMD_ARGV[i]);
|
||||
if (cmdline == NULL)
|
||||
break;
|
||||
free(arm->semihosting_cmdline);
|
||||
arm->semihosting_cmdline = cmdline;
|
||||
}
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
extern __COMMAND_HANDLER(handle_common_semihosting_command);
|
||||
extern __COMMAND_HANDLER(handle_common_semihosting_fileio_command);
|
||||
extern __COMMAND_HANDLER(handle_common_semihosting_resumable_exit_command);
|
||||
extern __COMMAND_HANDLER(handle_common_semihosting_cmdline);
|
||||
|
||||
static const struct command_registration arm_exec_command_handlers[] = {
|
||||
{
|
||||
|
@ -1245,26 +1140,32 @@ static const struct command_registration arm_exec_command_handlers[] = {
|
|||
},
|
||||
{
|
||||
"semihosting",
|
||||
.handler = handle_arm_semihosting_command,
|
||||
.handler = handle_common_semihosting_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "['enable'|'disable']",
|
||||
.help = "activate support for semihosting operations",
|
||||
},
|
||||
{
|
||||
"semihosting_cmdline",
|
||||
.handler = handle_arm_semihosting_cmdline,
|
||||
.handler = handle_common_semihosting_cmdline,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "arguments",
|
||||
.help = "command line arguments to be passed to program",
|
||||
},
|
||||
{
|
||||
"semihosting_fileio",
|
||||
.handler = handle_arm_semihosting_fileio_command,
|
||||
.handler = handle_common_semihosting_fileio_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "['enable'|'disable']",
|
||||
.help = "activate support for semihosting fileio operations",
|
||||
},
|
||||
|
||||
{
|
||||
"semihosting_resexit",
|
||||
.handler = handle_common_semihosting_resumable_exit_command,
|
||||
.mode = COMMAND_EXEC,
|
||||
.usage = "['enable'|'disable']",
|
||||
.help = "activate support for semihosting resumable exit",
|
||||
},
|
||||
COMMAND_REGISTRATION_DONE
|
||||
};
|
||||
const struct command_registration arm_command_handlers[] = {
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
* Copyright (C) 2007,2008 Øyvind Harboe *
|
||||
* oyvind.harboe@zylin.com *
|
||||
* *
|
||||
* Copyright (C) 2018 by Liviu Ionescu *
|
||||
* <ilg@livius.net> *
|
||||
* *
|
||||
* 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 *
|
||||
|
@ -37,6 +40,7 @@
|
|||
#include "armv7m.h"
|
||||
#include "algorithm.h"
|
||||
#include "register.h"
|
||||
#include "semihosting_common.h"
|
||||
|
||||
#if 0
|
||||
#define _DEBUG_INSTRUCTION_EXECUTION_
|
||||
|
@ -537,7 +541,7 @@ int armv7m_arch_state(struct target *target)
|
|||
uint32_t ctrl, sp;
|
||||
|
||||
/* avoid filling log waiting for fileio reply */
|
||||
if (arm->semihosting_hit_fileio)
|
||||
if (target->semihosting->hit_fileio)
|
||||
return ERROR_OK;
|
||||
|
||||
ctrl = buf_get_u32(arm->core_cache->reg_list[ARMV7M_CONTROL].value, 0, 32);
|
||||
|
@ -552,8 +556,8 @@ int armv7m_arch_state(struct target *target)
|
|||
buf_get_u32(arm->pc->value, 0, 32),
|
||||
(ctrl & 0x02) ? 'p' : 'm',
|
||||
sp,
|
||||
arm->is_semihosting ? ", semihosting" : "",
|
||||
arm->is_semihosting_fileio ? " fileio" : "");
|
||||
target->semihosting->is_active ? ", semihosting" : "",
|
||||
target->semihosting->is_fileio ? " fileio" : "");
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2015 by David Ung *
|
||||
* *
|
||||
* Copyright (C) 2018 by Liviu Ionescu *
|
||||
* <ilg@livius.net> *
|
||||
* *
|
||||
* 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 *
|
||||
|
@ -36,6 +39,7 @@
|
|||
#include "armv8_opcodes.h"
|
||||
#include "target.h"
|
||||
#include "target_type.h"
|
||||
#include "semihosting_common.h"
|
||||
|
||||
static const char * const armv8_state_strings[] = {
|
||||
"AArch32", "Thumb", "Jazelle", "ThumbEE", "AArch64",
|
||||
|
@ -1046,7 +1050,7 @@ int armv8_aarch64_state(struct target *target)
|
|||
armv8_mode_name(arm->core_mode),
|
||||
buf_get_u32(arm->cpsr->value, 0, 32),
|
||||
buf_get_u64(arm->pc->value, 0, 64),
|
||||
arm->is_semihosting ? ", semihosting" : "");
|
||||
target->semihosting->is_active ? ", semihosting" : "");
|
||||
|
||||
return ERROR_OK;
|
||||
}
|
||||
|
|
|
@ -315,11 +315,8 @@ int breakpoint_remove_internal(struct target *target, target_addr_t address)
|
|||
struct breakpoint *breakpoint = target->breakpoints;
|
||||
|
||||
while (breakpoint) {
|
||||
if ((breakpoint->address == address) && (breakpoint->asid == 0))
|
||||
break;
|
||||
else if ((breakpoint->address == 0) && (breakpoint->asid == address))
|
||||
break;
|
||||
else if ((breakpoint->address == address) && (breakpoint->asid != 0))
|
||||
if ((breakpoint->address == address) ||
|
||||
(breakpoint->address == 0 && breakpoint->asid == address))
|
||||
break;
|
||||
breakpoint = breakpoint->next;
|
||||
}
|
||||
|
|
|
@ -1806,11 +1806,11 @@ static int cortex_m_dwt_set_reg(struct reg *reg, uint8_t *buf)
|
|||
|
||||
struct dwt_reg {
|
||||
uint32_t addr;
|
||||
char *name;
|
||||
const char *name;
|
||||
unsigned size;
|
||||
};
|
||||
|
||||
static struct dwt_reg dwt_base_regs[] = {
|
||||
static const struct dwt_reg dwt_base_regs[] = {
|
||||
{ DWT_CTRL, "dwt_ctrl", 32, },
|
||||
/* NOTE that Erratum 532314 (fixed r2p0) affects CYCCNT: it wrongly
|
||||
* increments while the core is asleep.
|
||||
|
@ -1819,7 +1819,7 @@ static struct dwt_reg dwt_base_regs[] = {
|
|||
/* plus some 8 bit counters, useful for profiling with TPIU */
|
||||
};
|
||||
|
||||
static struct dwt_reg dwt_comp[] = {
|
||||
static const struct dwt_reg dwt_comp[] = {
|
||||
#define DWT_COMPARATOR(i) \
|
||||
{ DWT_COMP0 + 0x10 * (i), "dwt_" #i "_comp", 32, }, \
|
||||
{ DWT_MASK0 + 0x10 * (i), "dwt_" #i "_mask", 4, }, \
|
||||
|
@ -1848,7 +1848,7 @@ static const struct reg_arch_type dwt_reg_type = {
|
|||
.set = cortex_m_dwt_set_reg,
|
||||
};
|
||||
|
||||
static void cortex_m_dwt_addreg(struct target *t, struct reg *r, struct dwt_reg *d)
|
||||
static void cortex_m_dwt_addreg(struct target *t, struct reg *r, const struct dwt_reg *d)
|
||||
{
|
||||
struct dwt_reg_state *state;
|
||||
|
||||
|
|
|
@ -2339,63 +2339,66 @@ int nds32_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fil
|
|||
fileio_info->identifier = NULL;
|
||||
}
|
||||
|
||||
uint32_t reg_r0, reg_r1, reg_r2;
|
||||
nds32_get_mapped_reg(nds32, R0, ®_r0);
|
||||
nds32_get_mapped_reg(nds32, R1, ®_r1);
|
||||
nds32_get_mapped_reg(nds32, R2, ®_r2);
|
||||
|
||||
switch (syscall_id) {
|
||||
case NDS32_SYSCALL_EXIT:
|
||||
fileio_info->identifier = malloc(5);
|
||||
sprintf(fileio_info->identifier, "exit");
|
||||
nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
|
||||
fileio_info->param_1 = reg_r0;
|
||||
break;
|
||||
case NDS32_SYSCALL_OPEN:
|
||||
{
|
||||
uint8_t filename[256];
|
||||
fileio_info->identifier = malloc(5);
|
||||
sprintf(fileio_info->identifier, "open");
|
||||
nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
|
||||
fileio_info->param_1 = reg_r0;
|
||||
/* reserve fileio_info->param_2 for length of path */
|
||||
nds32_get_mapped_reg(nds32, R1, &(fileio_info->param_3));
|
||||
nds32_get_mapped_reg(nds32, R2, &(fileio_info->param_4));
|
||||
fileio_info->param_3 = reg_r1;
|
||||
fileio_info->param_4 = reg_r2;
|
||||
|
||||
target->type->read_buffer(target, fileio_info->param_1,
|
||||
256, filename);
|
||||
target->type->read_buffer(target, reg_r0, 256, filename);
|
||||
fileio_info->param_2 = strlen((char *)filename) + 1;
|
||||
}
|
||||
break;
|
||||
case NDS32_SYSCALL_CLOSE:
|
||||
fileio_info->identifier = malloc(6);
|
||||
sprintf(fileio_info->identifier, "close");
|
||||
nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
|
||||
fileio_info->param_1 = reg_r0;
|
||||
break;
|
||||
case NDS32_SYSCALL_READ:
|
||||
fileio_info->identifier = malloc(5);
|
||||
sprintf(fileio_info->identifier, "read");
|
||||
nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
|
||||
nds32_get_mapped_reg(nds32, R1, &(fileio_info->param_2));
|
||||
nds32_get_mapped_reg(nds32, R2, &(fileio_info->param_3));
|
||||
fileio_info->param_1 = reg_r0;
|
||||
fileio_info->param_2 = reg_r1;
|
||||
fileio_info->param_3 = reg_r2;
|
||||
break;
|
||||
case NDS32_SYSCALL_WRITE:
|
||||
fileio_info->identifier = malloc(6);
|
||||
sprintf(fileio_info->identifier, "write");
|
||||
nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
|
||||
nds32_get_mapped_reg(nds32, R1, &(fileio_info->param_2));
|
||||
nds32_get_mapped_reg(nds32, R2, &(fileio_info->param_3));
|
||||
fileio_info->param_1 = reg_r0;
|
||||
fileio_info->param_2 = reg_r1;
|
||||
fileio_info->param_3 = reg_r2;
|
||||
break;
|
||||
case NDS32_SYSCALL_LSEEK:
|
||||
fileio_info->identifier = malloc(6);
|
||||
sprintf(fileio_info->identifier, "lseek");
|
||||
nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
|
||||
nds32_get_mapped_reg(nds32, R1, &(fileio_info->param_2));
|
||||
nds32_get_mapped_reg(nds32, R2, &(fileio_info->param_3));
|
||||
fileio_info->param_1 = reg_r0;
|
||||
fileio_info->param_2 = reg_r1;
|
||||
fileio_info->param_3 = reg_r2;
|
||||
break;
|
||||
case NDS32_SYSCALL_UNLINK:
|
||||
{
|
||||
uint8_t filename[256];
|
||||
fileio_info->identifier = malloc(7);
|
||||
sprintf(fileio_info->identifier, "unlink");
|
||||
nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
|
||||
fileio_info->param_1 = reg_r0;
|
||||
/* reserve fileio_info->param_2 for length of path */
|
||||
|
||||
target->type->read_buffer(target, fileio_info->param_1,
|
||||
256, filename);
|
||||
target->type->read_buffer(target, reg_r0, 256, filename);
|
||||
fileio_info->param_2 = strlen((char *)filename) + 1;
|
||||
}
|
||||
break;
|
||||
|
@ -2404,61 +2407,57 @@ int nds32_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fil
|
|||
uint8_t filename[256];
|
||||
fileio_info->identifier = malloc(7);
|
||||
sprintf(fileio_info->identifier, "rename");
|
||||
nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
|
||||
fileio_info->param_1 = reg_r0;
|
||||
/* reserve fileio_info->param_2 for length of old path */
|
||||
nds32_get_mapped_reg(nds32, R1, &(fileio_info->param_3));
|
||||
fileio_info->param_3 = reg_r1;
|
||||
/* reserve fileio_info->param_4 for length of new path */
|
||||
|
||||
target->type->read_buffer(target, fileio_info->param_1,
|
||||
256, filename);
|
||||
target->type->read_buffer(target, reg_r0, 256, filename);
|
||||
fileio_info->param_2 = strlen((char *)filename) + 1;
|
||||
|
||||
target->type->read_buffer(target, fileio_info->param_3,
|
||||
256, filename);
|
||||
target->type->read_buffer(target, reg_r1, 256, filename);
|
||||
fileio_info->param_4 = strlen((char *)filename) + 1;
|
||||
}
|
||||
break;
|
||||
case NDS32_SYSCALL_FSTAT:
|
||||
fileio_info->identifier = malloc(6);
|
||||
sprintf(fileio_info->identifier, "fstat");
|
||||
nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
|
||||
nds32_get_mapped_reg(nds32, R1, &(fileio_info->param_2));
|
||||
fileio_info->param_1 = reg_r0;
|
||||
fileio_info->param_2 = reg_r1;
|
||||
break;
|
||||
case NDS32_SYSCALL_STAT:
|
||||
{
|
||||
uint8_t filename[256];
|
||||
fileio_info->identifier = malloc(5);
|
||||
sprintf(fileio_info->identifier, "stat");
|
||||
nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
|
||||
fileio_info->param_1 = reg_r0;
|
||||
/* reserve fileio_info->param_2 for length of old path */
|
||||
nds32_get_mapped_reg(nds32, R1, &(fileio_info->param_3));
|
||||
fileio_info->param_3 = reg_r1;
|
||||
|
||||
target->type->read_buffer(target, fileio_info->param_1,
|
||||
256, filename);
|
||||
target->type->read_buffer(target, reg_r0, 256, filename);
|
||||
fileio_info->param_2 = strlen((char *)filename) + 1;
|
||||
}
|
||||
break;
|
||||
case NDS32_SYSCALL_GETTIMEOFDAY:
|
||||
fileio_info->identifier = malloc(13);
|
||||
sprintf(fileio_info->identifier, "gettimeofday");
|
||||
nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
|
||||
nds32_get_mapped_reg(nds32, R1, &(fileio_info->param_2));
|
||||
fileio_info->param_1 = reg_r0;
|
||||
fileio_info->param_2 = reg_r1;
|
||||
break;
|
||||
case NDS32_SYSCALL_ISATTY:
|
||||
fileio_info->identifier = malloc(7);
|
||||
sprintf(fileio_info->identifier, "isatty");
|
||||
nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
|
||||
fileio_info->param_1 = reg_r0;
|
||||
break;
|
||||
case NDS32_SYSCALL_SYSTEM:
|
||||
{
|
||||
uint8_t command[256];
|
||||
fileio_info->identifier = malloc(7);
|
||||
sprintf(fileio_info->identifier, "system");
|
||||
nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1));
|
||||
fileio_info->param_1 = reg_r0;
|
||||
/* reserve fileio_info->param_2 for length of old path */
|
||||
|
||||
target->type->read_buffer(target, fileio_info->param_1,
|
||||
256, command);
|
||||
target->type->read_buffer(target, reg_r0, 256, command);
|
||||
fileio_info->param_2 = strlen((char *)command) + 1;
|
||||
}
|
||||
break;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,163 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2018 by Liviu Ionescu *
|
||||
* <ilg@livius.net> *
|
||||
* *
|
||||
* Copyright (C) 2009 by Marvell Technology Group Ltd. *
|
||||
* Written by Nicolas Pitre <nico@marvell.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 <http://www.gnu.org/licenses/>. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef OPENOCD_TARGET_SEMIHOSTING_COMMON_H
|
||||
#define OPENOCD_TARGET_SEMIHOSTING_COMMON_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
|
||||
/*
|
||||
* According to:
|
||||
* "Semihosting for AArch32 and AArch64, Release 2.0"
|
||||
* https://static.docs.arm.com/100863/0200/semihosting.pdf
|
||||
* from ARM Ltd.
|
||||
*
|
||||
* The available semihosting operation numbers passed in R0 are allocated
|
||||
* as follows:
|
||||
* - 0x00-0x31 Used by ARM.
|
||||
* - 0x32-0xFF Reserved for future use by ARM.
|
||||
* - 0x100-0x1FF Reserved for user applications. These are not used by ARM.
|
||||
* However, if you are writing your own SVC operations, you are advised
|
||||
* to use a different SVC number rather than using the semihosted
|
||||
* SVC number and these operation type numbers.
|
||||
* - 0x200-0xFFFFFFFF Undefined and currently unused. It is recommended
|
||||
* that you do not use these.
|
||||
*/
|
||||
|
||||
enum semihosting_operation_numbers {
|
||||
/*
|
||||
* ARM semihosting operations, in lexicographic order.
|
||||
*/
|
||||
SEMIHOSTING_ENTER_SVC = 0x17, /* DEPRECATED */
|
||||
|
||||
SEMIHOSTING_SYS_CLOSE = 0x02,
|
||||
SEMIHOSTING_SYS_CLOCK = 0x10,
|
||||
SEMIHOSTING_SYS_ELAPSED = 0x30,
|
||||
SEMIHOSTING_SYS_ERRNO = 0x13,
|
||||
SEMIHOSTING_SYS_EXIT = 0x18,
|
||||
SEMIHOSTING_SYS_EXIT_EXTENDED = 0x20,
|
||||
SEMIHOSTING_SYS_FLEN = 0x0C,
|
||||
SEMIHOSTING_SYS_GET_CMDLINE = 0x15,
|
||||
SEMIHOSTING_SYS_HEAPINFO = 0x16,
|
||||
SEMIHOSTING_SYS_ISERROR = 0x08,
|
||||
SEMIHOSTING_SYS_ISTTY = 0x09,
|
||||
SEMIHOSTING_SYS_OPEN = 0x01,
|
||||
SEMIHOSTING_SYS_READ = 0x06,
|
||||
SEMIHOSTING_SYS_READC = 0x07,
|
||||
SEMIHOSTING_SYS_REMOVE = 0x0E,
|
||||
SEMIHOSTING_SYS_RENAME = 0x0F,
|
||||
SEMIHOSTING_SYS_SEEK = 0x0A,
|
||||
SEMIHOSTING_SYS_SYSTEM = 0x12,
|
||||
SEMIHOSTING_SYS_TICKFREQ = 0x31,
|
||||
SEMIHOSTING_SYS_TIME = 0x11,
|
||||
SEMIHOSTING_SYS_TMPNAM = 0x0D,
|
||||
SEMIHOSTING_SYS_WRITE = 0x05,
|
||||
SEMIHOSTING_SYS_WRITEC = 0x03,
|
||||
SEMIHOSTING_SYS_WRITE0 = 0x04,
|
||||
};
|
||||
|
||||
/*
|
||||
* Codes used by SEMIHOSTING_SYS_EXIT (formerly
|
||||
* SEMIHOSTING_REPORT_EXCEPTION).
|
||||
* On 64-bits, the exit code is passed explicitly.
|
||||
*/
|
||||
enum semihosting_reported_exceptions {
|
||||
/* On 32 bits, use it for exit(0) */
|
||||
ADP_STOPPED_APPLICATION_EXIT = ((2 << 16) + 38),
|
||||
/* On 32 bits, use it for exit(1) */
|
||||
ADP_STOPPED_RUN_TIME_ERROR = ((2 << 16) + 35),
|
||||
};
|
||||
|
||||
struct target;
|
||||
|
||||
/*
|
||||
* A pointer to this structure was added to the target structure.
|
||||
*/
|
||||
struct semihosting {
|
||||
|
||||
/** A flag reporting whether semihosting is active. */
|
||||
bool is_active;
|
||||
|
||||
/** A flag reporting whether semihosting fileio is active. */
|
||||
bool is_fileio;
|
||||
|
||||
/** A flag reporting whether semihosting fileio operation is active. */
|
||||
bool hit_fileio;
|
||||
|
||||
/** Most are resumable, except the two exit calls. */
|
||||
bool is_resumable;
|
||||
|
||||
/**
|
||||
* When SEMIHOSTING_SYS_EXIT is called outside a debug session,
|
||||
* things are simple, the openocd process calls exit() and passes
|
||||
* the value returned by the target.
|
||||
* When SEMIHOSTING_SYS_EXIT is called during a debug session,
|
||||
* by default execution returns to the debugger, leaving the
|
||||
* debugger in a HALT state, similar to the state entered when
|
||||
* encountering a break.
|
||||
* In some use cases, it is useful to have SEMIHOSTING_SYS_EXIT
|
||||
* return normally, as any semihosting call, and do not break
|
||||
* to the debugger.
|
||||
* The standard allows this to happen, but the condition
|
||||
* to trigger it is a bit obscure ("by performing an RDI_Execute
|
||||
* request or equivalent").
|
||||
*
|
||||
* To make the SEMIHOSTING_SYS_EXIT call return normally, enable
|
||||
* this variable via the dedicated command (default: disabled).
|
||||
*/
|
||||
bool has_resumable_exit;
|
||||
|
||||
/** The Target (hart) word size; 8 for 64-bits targets. */
|
||||
size_t word_size_bytes;
|
||||
|
||||
/** The current semihosting operation (R0 on ARM). */
|
||||
int op;
|
||||
|
||||
/** The current semihosting parameter (R1 or ARM). */
|
||||
uint64_t param;
|
||||
|
||||
/**
|
||||
* The current semihosting result to be returned to the application.
|
||||
* Usually 0 for success, -1 for error,
|
||||
* but sometimes a useful value, even a pointer.
|
||||
*/
|
||||
int64_t result;
|
||||
|
||||
/** The value to be returned by semihosting SYS_ERRNO request. */
|
||||
int sys_errno;
|
||||
|
||||
/** The semihosting command line to be passed to the target. */
|
||||
char *cmdline;
|
||||
|
||||
/** The current time when 'execution starts' */
|
||||
clock_t setup_time;
|
||||
|
||||
int (*setup)(struct target *target, int enable);
|
||||
int (*post_result)(struct target *target);
|
||||
};
|
||||
|
||||
int semihosting_common_init(struct target *target, void *setup,
|
||||
void *post_result);
|
||||
int semihosting_common(struct target *target);
|
||||
|
||||
#endif /* OPENOCD_TARGET_SEMIHOSTING_COMMON_H */
|
|
@ -1895,6 +1895,9 @@ static void target_destroy(struct target *target)
|
|||
if (target->type->deinit_target)
|
||||
target->type->deinit_target(target);
|
||||
|
||||
if (target->semihosting)
|
||||
free(target->semihosting);
|
||||
|
||||
jtag_unregister_event_callback(jtag_enable_callback, target);
|
||||
|
||||
struct target_event_action *teap = target->event_action;
|
||||
|
@ -5448,21 +5451,19 @@ static const struct command_registration target_instance_command_handlers[] = {
|
|||
.mode = COMMAND_EXEC,
|
||||
.jim_handler = jim_target_examine,
|
||||
.help = "used internally for reset processing",
|
||||
.usage = "arp_examine ['allow-defer']",
|
||||
.usage = "['allow-defer']",
|
||||
},
|
||||
{
|
||||
.name = "was_examined",
|
||||
.mode = COMMAND_EXEC,
|
||||
.jim_handler = jim_target_was_examined,
|
||||
.help = "used internally for reset processing",
|
||||
.usage = "was_examined",
|
||||
},
|
||||
{
|
||||
.name = "examine_deferred",
|
||||
.mode = COMMAND_EXEC,
|
||||
.jim_handler = jim_target_examine_deferred,
|
||||
.help = "used internally for reset processing",
|
||||
.usage = "examine_deferred",
|
||||
},
|
||||
{
|
||||
.name = "arp_halt_gdb",
|
||||
|
|
|
@ -205,6 +205,9 @@ struct target {
|
|||
|
||||
/* file-I/O information for host to do syscall */
|
||||
struct gdb_fileio_info *fileio_info;
|
||||
|
||||
/* The semihosting information, extracted from the target. */
|
||||
struct semihosting *semihosting;
|
||||
};
|
||||
|
||||
struct target_list {
|
||||
|
@ -214,10 +217,10 @@ struct target_list {
|
|||
|
||||
struct gdb_fileio_info {
|
||||
char *identifier;
|
||||
uint32_t param_1;
|
||||
uint32_t param_2;
|
||||
uint32_t param_3;
|
||||
uint32_t param_4;
|
||||
uint64_t param_1;
|
||||
uint64_t param_2;
|
||||
uint64_t param_3;
|
||||
uint64_t param_4;
|
||||
};
|
||||
|
||||
/** Returns the instance-specific name of the specified target. */
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
#
|
||||
# TI CC3220SF-LaunchXL LaunchPad Evaluation Kit
|
||||
#
|
||||
source [find interface/xds110.cfg]
|
||||
adapter_khz 2500
|
||||
transport select swd
|
||||
source [find target/ti_cc3220sf.cfg]
|
|
@ -0,0 +1,7 @@
|
|||
#
|
||||
# TI CC32xx-LaunchXL LaunchPad Evaluation Kit
|
||||
#
|
||||
source [find interface/xds110.cfg]
|
||||
adapter_khz 2500
|
||||
transport select swd
|
||||
source [find target/ti_cc32xx.cfg]
|
|
@ -0,0 +1,12 @@
|
|||
#
|
||||
# Texas Instruments XDS110
|
||||
#
|
||||
# http://processors.wiki.ti.com/index.php/XDS110
|
||||
# http://processors.wiki.ti.com/index.php/Emulation_Software_Package#XDS110_Support_Utilities
|
||||
#
|
||||
|
||||
interface xds110
|
||||
|
||||
# Use serial number option to use a specific XDS110
|
||||
# when more than one are connected to the host.
|
||||
#xds110_serial 00000000
|
|
@ -1,54 +0,0 @@
|
|||
# Config for Texas Instruments SoC CC32xx family
|
||||
|
||||
source [find target/swj-dp.tcl]
|
||||
|
||||
adapter_khz 100
|
||||
|
||||
source [find target/icepick.cfg]
|
||||
|
||||
if { [info exists CHIPNAME] } {
|
||||
set _CHIPNAME $CHIPNAME
|
||||
} else {
|
||||
set _CHIPNAME cc32xx
|
||||
}
|
||||
|
||||
#
|
||||
# Main DAP
|
||||
#
|
||||
if { [info exists DAP_TAPID] } {
|
||||
set _DAP_TAPID $DAP_TAPID
|
||||
} else {
|
||||
if {[using_jtag]} {
|
||||
set _DAP_TAPID 0x4BA00477
|
||||
} else {
|
||||
set _DAP_TAPID 0x2BA01477
|
||||
}
|
||||
}
|
||||
|
||||
if {[using_jtag]} {
|
||||
jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -disable
|
||||
jtag configure $_CHIPNAME.cpu -event tap-enable "icepick_c_tapenable $_CHIPNAME.jrc 0"
|
||||
} else {
|
||||
swj_newdap $_CHIPNAME cpu -expected-id $_DAP_TAPID
|
||||
}
|
||||
|
||||
#
|
||||
# ICEpick-C (JTAG route controller)
|
||||
#
|
||||
if { [info exists JRC_TAPID] } {
|
||||
set _JRC_TAPID $JRC_TAPID
|
||||
} else {
|
||||
set _JRC_TAPID 0x0B97C02F
|
||||
}
|
||||
|
||||
if {[using_jtag]} {
|
||||
jtag newtap $_CHIPNAME jrc -irlen 6 -ircapture 0x1 -irmask 0x3f -expected-id $_JRC_TAPID -ignore-version
|
||||
jtag configure $_CHIPNAME.jrc -event setup "jtag tapenable $_CHIPNAME.dap"
|
||||
}
|
||||
|
||||
#
|
||||
# Cortex-M3 target
|
||||
#
|
||||
set _TARGETNAME $_CHIPNAME.cpu
|
||||
dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu
|
||||
target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap
|
|
@ -28,6 +28,38 @@ dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu
|
|||
set _TARGETNAME $_CHIPNAME.cpu
|
||||
target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap
|
||||
|
||||
if { [info exists WORKAREASIZE] } {
|
||||
set _WORKAREASIZE $WORKAREASIZE
|
||||
} else {
|
||||
set _WORKAREASIZE 0x2000
|
||||
}
|
||||
|
||||
$_TARGETNAME configure -work-area-phys [expr 0x20000000 - $_WORKAREASIZE / 2] \
|
||||
-work-area-size $_WORKAREASIZE -work-area-backup 0
|
||||
|
||||
source [find mem_helper.tcl]
|
||||
|
||||
$_TARGETNAME configure -event reset-init {
|
||||
# Configure Target Device (PSoC 5LP Device Programming Specification 5.2)
|
||||
|
||||
set PANTHER_DBG_CFG 0x4008000C
|
||||
set PANTHER_DBG_CFG_BYPASS [expr 1 << 1]
|
||||
mmw $PANTHER_DBG_CFG $PANTHER_DBG_CFG_BYPASS 0
|
||||
|
||||
set PM_ACT_CFG0 0x400043A0
|
||||
mww $PM_ACT_CFG0 0xBF
|
||||
|
||||
set FASTCLK_IMO_CR 0x40004200
|
||||
set FASTCLK_IMO_CR_F_RANGE_2 [expr 2 << 0]
|
||||
set FASTCLK_IMO_CR_F_RANGE_MASK [expr 7 << 0]
|
||||
mmw $FASTCLK_IMO_CR $FASTCLK_IMO_CR_F_RANGE_2 $FASTCLK_IMO_CR_F_RANGE_MASK
|
||||
}
|
||||
|
||||
set _FLASHNAME $_CHIPNAME.flash
|
||||
flash bank $_FLASHNAME psoc5lp 0x00000000 0 0 0 $_TARGETNAME
|
||||
flash bank $_CHIPNAME.eeprom psoc5lp_eeprom 0x40008000 0 0 0 $_TARGETNAME
|
||||
flash bank $_CHIPNAME.nvl psoc5lp_nvl 0 0 0 0 $_TARGETNAME
|
||||
|
||||
if {![using_hla]} {
|
||||
cortex_m reset_config sysresetreq
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
#
|
||||
# Texas Instruments CC3220SF - ARM Cortex-M4
|
||||
#
|
||||
# http://www.ti.com/CC3220SF
|
||||
#
|
||||
|
||||
source [find target/swj-dp.tcl]
|
||||
source [find target/icepick.cfg]
|
||||
source [find target/ti_cc32xx.cfg]
|
||||
|
||||
set _FLASHNAME $_CHIPNAME.flash
|
||||
flash bank $_FLASHNAME cc3220sf 0 0 0 0 $_TARGETNAME
|
|
@ -0,0 +1,64 @@
|
|||
#
|
||||
# Texas Instruments CC32xx - ARM Cortex-M4
|
||||
#
|
||||
# http://www.ti.com/product/CC3200
|
||||
# http://www.ti.com/product/CC3220
|
||||
#
|
||||
|
||||
source [find target/swj-dp.tcl]
|
||||
source [find target/icepick.cfg]
|
||||
|
||||
if { [info exists CHIPNAME] } {
|
||||
set _CHIPNAME $CHIPNAME
|
||||
} else {
|
||||
set _CHIPNAME cc32xx
|
||||
}
|
||||
|
||||
#
|
||||
# Main DAP
|
||||
#
|
||||
if { [info exists DAP_TAPID] } {
|
||||
set _DAP_TAPID $DAP_TAPID
|
||||
} else {
|
||||
if {[using_jtag]} {
|
||||
set _DAP_TAPID 0x4BA00477
|
||||
} else {
|
||||
set _DAP_TAPID 0x2BA01477
|
||||
}
|
||||
}
|
||||
|
||||
if {[using_jtag]} {
|
||||
jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -disable
|
||||
jtag configure $_CHIPNAME.cpu -event tap-enable "icepick_c_tapenable $_CHIPNAME.jrc 0"
|
||||
} else {
|
||||
swj_newdap $_CHIPNAME cpu -expected-id $_DAP_TAPID
|
||||
}
|
||||
|
||||
#
|
||||
# ICEpick-C (JTAG route controller)
|
||||
#
|
||||
if { [info exists JRC_TAPID] } {
|
||||
set _JRC_TAPID $JRC_TAPID
|
||||
} else {
|
||||
set _JRC_TAPID 0x0B97C02F
|
||||
}
|
||||
|
||||
if {[using_jtag]} {
|
||||
jtag newtap $_CHIPNAME jrc -irlen 6 -ircapture 0x1 -irmask 0x3f -expected-id $_JRC_TAPID -ignore-version
|
||||
jtag configure $_CHIPNAME.jrc -event setup "jtag tapenable $_CHIPNAME.cpu"
|
||||
}
|
||||
|
||||
set _TARGETNAME $_CHIPNAME.cpu
|
||||
dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu
|
||||
target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap
|
||||
|
||||
if { [info exists WORKAREASIZE] } {
|
||||
set _WORKAREASIZE $WORKAREASIZE
|
||||
} else {
|
||||
set _WORKAREASIZE 0x2000
|
||||
}
|
||||
|
||||
$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0
|
||||
|
||||
reset_config srst_only
|
||||
adapter_nsrst_delay 1100
|
Loading…
Reference in New Issue