Merge pull request #264 from riscv/from_upstream

From upstream
This commit is contained in:
Tim Newsome 2018-06-11 14:38:00 -07:00 committed by GitHub
commit f098b553c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 6568 additions and 823 deletions

4
README
View File

@ -125,8 +125,8 @@ Flash drivers
ADUC702x, AT91SAM, ATH79, AVR, CFI, DSP5680xx, EFM32, EM357, FM3, FM4, Kinetis, ADUC702x, AT91SAM, ATH79, AVR, CFI, DSP5680xx, EFM32, EM357, FM3, FM4, Kinetis,
LPC8xx/LPC1xxx/LPC2xxx/LPC541xx, LPC2900, LPCSPIFI, Marvell QSPI, LPC8xx/LPC1xxx/LPC2xxx/LPC541xx, LPC2900, LPCSPIFI, Marvell QSPI,
Milandr, NIIET, NuMicro, PIC32mx, PSoC4, SiM3x, Stellaris, STM32, STMSMI, Milandr, NIIET, NuMicro, PIC32mx, PSoC4, PSoC5LP, SiM3x, Stellaris, STM32,
STR7x, STR9x, nRF51; NAND controllers of AT91SAM9, LPC3180, LPC32xx, STMSMI, STR7x, STR9x, nRF51; NAND controllers of AT91SAM9, LPC3180, LPC32xx,
i.MX31, MXC, NUC910, Orion/Kirkwood, S3C24xx, S3C6400, XMC1xxx, XMC4xxx. i.MX31, MXC, NUC910, Orion/Kirkwood, S3C24xx, S3C6400, XMC1xxx, XMC4xxx.

View File

@ -115,7 +115,8 @@ m4_define([USB1_ADAPTERS],
[[ulink], [Keil ULINK JTAG Programmer], [ULINK]], [[ulink], [Keil ULINK JTAG Programmer], [ULINK]],
[[usb_blaster_2], [Altera USB-Blaster II Compatible], [USB_BLASTER_2]], [[usb_blaster_2], [Altera USB-Blaster II Compatible], [USB_BLASTER_2]],
[[ft232r], [Bitbang mode of FT232R based devices], [FT232R]], [[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], m4_define([USB_ADAPTERS],
[[[osbdm], [OSBDM (JTAG only) Programmer], [OSBDM]], [[[osbdm], [OSBDM (JTAG only) Programmer], [OSBDM]],

View File

@ -128,6 +128,12 @@ ATTRS{idVendor}=="1781", ATTRS{idProduct}=="0c63", MODE="660", GROUP="plugdev",
# TI/Luminary Stellaris In-Circuit Debug Interface (ICDI) Board # TI/Luminary Stellaris In-Circuit Debug Interface (ICDI) Board
ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="00fd", MODE="660", GROUP="plugdev", TAG+="uaccess" 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. # Ambiq Micro EVK and Debug boards.
ATTRS{idVendor}=="2aec", ATTRS{idProduct}=="6010", MODE="664", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="2aec", ATTRS{idProduct}=="6010", MODE="664", GROUP="plugdev", TAG+="uaccess"
ATTRS{idVendor}=="2aec", ATTRS{idProduct}=="6011", MODE="664", GROUP="plugdev", TAG+="uaccess" ATTRS{idVendor}=="2aec", ATTRS{idProduct}=="6011", MODE="664", GROUP="plugdev", TAG+="uaccess"

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -531,6 +531,12 @@ debuggers to ARM Cortex based targets @url{http://www.keil.com/support/man/docs/
@item @b{Keil ULINK v1} @item @b{Keil ULINK v1}
@* Link: @url{http://www.keil.com/ulink1/} @* 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 @end itemize
@section IBM PC Parallel Printer Port Based @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 @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 @deffn {Flash Driver} efm32
All members of the EFM32 microcontroller family from Energy Micro include All members of the EFM32 microcontroller family from Energy Micro include
internal flash and use ARM Cortex-M3 cores. The driver automatically recognizes 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
@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 @deffn {Flash Driver} psoc6
Supports PSoC6 (CY8C6xxx) family of Cypress microcontrollers. Supports PSoC6 (CY8C6xxx) family of Cypress microcontrollers.
PSoC6 is a dual-core device with CM0+ and CM4 cores. Both cores share 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. debugger.
@end deffn @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 @section ARMv4 and ARMv5 Architecture
@cindex ARMv4 @cindex ARMv4
@cindex ARMv5 @cindex ARMv5

View File

@ -19,6 +19,7 @@ NOR_DRIVERS = \
%D%/atsamv.c \ %D%/atsamv.c \
%D%/avrf.c \ %D%/avrf.c \
%D%/bluenrg-x.c \ %D%/bluenrg-x.c \
%D%/cc3220sf.c \
%D%/cfi.c \ %D%/cfi.c \
%D%/dsp5680xx_flash.c \ %D%/dsp5680xx_flash.c \
%D%/efm32.c \ %D%/efm32.c \
@ -43,6 +44,7 @@ NOR_DRIVERS = \
%D%/ocl.c \ %D%/ocl.c \
%D%/pic32mx.c \ %D%/pic32mx.c \
%D%/psoc4.c \ %D%/psoc4.c \
%D%/psoc5lp.c \
%D%/psoc6.c \ %D%/psoc6.c \
%D%/sim3x.c \ %D%/sim3x.c \
%D%/spi.c \ %D%/spi.c \
@ -64,6 +66,7 @@ NOR_DRIVERS = \
NORHEADERS = \ NORHEADERS = \
%D%/core.h \ %D%/core.h \
%D%/cc3220sf.h \
%D%/cfi.h \ %D%/cfi.h \
%D%/driver.h \ %D%/driver.h \
%D%/imp.h \ %D%/imp.h \

529
src/flash/nor/cc3220sf.c Normal file
View File

@ -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(&reg_params[0], "r0", 32, PARAM_OUT);
init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
init_reg_param(&reg_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(&reg_params[0]);
destroy_reg_param(&reg_params[1]);
destroy_reg_param(&reg_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,
};

45
src/flash/nor/cc3220sf.h Normal file
View File

@ -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 */

View File

@ -188,9 +188,17 @@ void flash_free_all_banks(void)
else else
LOG_WARNING("Flash driver of %s does not support free_driver_priv()", bank->name); 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->name);
free(bank->sectors);
free(bank->prot_blocks);
free(bank); free(bank);
bank = next; bank = next;
} }

View File

@ -32,6 +32,7 @@ extern struct flash_driver ath79_flash;
extern struct flash_driver atsamv_flash; extern struct flash_driver atsamv_flash;
extern struct flash_driver avr_flash; extern struct flash_driver avr_flash;
extern struct flash_driver bluenrgx_flash; extern struct flash_driver bluenrgx_flash;
extern struct flash_driver cc3220sf_flash;
extern struct flash_driver cfi_flash; extern struct flash_driver cfi_flash;
extern struct flash_driver dsp5680xx_flash; extern struct flash_driver dsp5680xx_flash;
extern struct flash_driver efm32_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 ocl_flash;
extern struct flash_driver pic32mx_flash; extern struct flash_driver pic32mx_flash;
extern struct flash_driver psoc4_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 psoc6_flash;
extern struct flash_driver sim3x_flash; extern struct flash_driver sim3x_flash;
extern struct flash_driver stellaris_flash; extern struct flash_driver stellaris_flash;
@ -91,6 +95,7 @@ static struct flash_driver *flash_drivers[] = {
&atsamv_flash, &atsamv_flash,
&avr_flash, &avr_flash,
&bluenrgx_flash, &bluenrgx_flash,
&cc3220sf_flash,
&cfi_flash, &cfi_flash,
&dsp5680xx_flash, &dsp5680xx_flash,
&efm32_flash, &efm32_flash,
@ -115,6 +120,9 @@ static struct flash_driver *flash_drivers[] = {
&ocl_flash, &ocl_flash,
&pic32mx_flash, &pic32mx_flash,
&psoc4_flash, &psoc4_flash,
&psoc5lp_flash,
&psoc5lp_eeprom_flash,
&psoc5lp_nvl_flash,
&psoc6_flash, &psoc6_flash,
&sim3x_flash, &sim3x_flash,
&stellaris_flash, &stellaris_flash,

1574
src/flash/nor/psoc5lp.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -46,8 +46,13 @@ static void virtual_update_bank_info(struct flash_bank *bank)
bank->bus_width = master_bank->bus_width; bank->bus_width = master_bank->bus_width;
bank->erased_value = master_bank->erased_value; bank->erased_value = master_bank->erased_value;
bank->default_padded_value = master_bank->default_padded_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->num_sectors = master_bank->num_sectors;
bank->sectors = master_bank->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) FLASH_BANK_COMMAND_HANDLER(virtual_flash_bank_command)

View File

@ -156,10 +156,12 @@ endif
if IMX_GPIO if IMX_GPIO
DRIVERFILES += %D%/imx_gpio.c DRIVERFILES += %D%/imx_gpio.c
endif endif
if KITPROG if KITPROG
DRIVERFILES += %D%/kitprog.c DRIVERFILES += %D%/kitprog.c
endif endif
if XDS110
DRIVERFILES += %D%/xds110.c
endif
DRIVERHEADERS = \ DRIVERHEADERS = \
%D%/bitbang.h \ %D%/bitbang.h \

View File

@ -58,11 +58,11 @@
/* /*
* Helper func to determine if gpio number valid * 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) 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) static void unexport_sysfs_gpio(int gpio)
{ {
char gpiostr[4]; char gpiostr[5];
if (!is_gpio_valid(gpio)) if (!is_gpio_valid(gpio))
return; 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) static int setup_sysfs_gpio(int gpio, int is_output, int init_high)
{ {
char buf[40]; char buf[40];
char gpiostr[4]; char gpiostr[5];
int ret; int ret;
if (!is_gpio_valid(gpio)) if (!is_gpio_valid(gpio))

1973
src/jtag/drivers/xds110.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -132,6 +132,9 @@ extern struct jtag_interface kitprog_interface;
#if BUILD_IMX_GPIO == 1 #if BUILD_IMX_GPIO == 1
extern struct jtag_interface imx_gpio_interface; extern struct jtag_interface imx_gpio_interface;
#endif #endif
#if BUILD_XDS110 == 1
extern struct jtag_interface xds110_interface;
#endif
#endif /* standard drivers */ #endif /* standard drivers */
/** /**
@ -234,6 +237,9 @@ struct jtag_interface *jtag_interfaces[] = {
#if BUILD_IMX_GPIO == 1 #if BUILD_IMX_GPIO == 1
&imx_gpio_interface, &imx_gpio_interface,
#endif #endif
#if BUILD_XDS110 == 1
&xds110_interface,
#endif
#endif /* standard drivers */ #endif /* standard drivers */
NULL, NULL,
}; };

View File

@ -791,64 +791,64 @@ static void gdb_fileio_reply(struct target *target, struct connection *connectio
bool program_exited = false; bool program_exited = false;
if (strcmp(target->fileio_info->identifier, "open") == 0) 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_1,
target->fileio_info->param_2, target->fileio_info->param_2,
target->fileio_info->param_3, target->fileio_info->param_3,
target->fileio_info->param_4); target->fileio_info->param_4);
else if (strcmp(target->fileio_info->identifier, "close") == 0) 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); target->fileio_info->param_1);
else if (strcmp(target->fileio_info->identifier, "read") == 0) 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_1,
target->fileio_info->param_2, target->fileio_info->param_2,
target->fileio_info->param_3); target->fileio_info->param_3);
else if (strcmp(target->fileio_info->identifier, "write") == 0) 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_1,
target->fileio_info->param_2, target->fileio_info->param_2,
target->fileio_info->param_3); target->fileio_info->param_3);
else if (strcmp(target->fileio_info->identifier, "lseek") == 0) 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_1,
target->fileio_info->param_2, target->fileio_info->param_2,
target->fileio_info->param_3); target->fileio_info->param_3);
else if (strcmp(target->fileio_info->identifier, "rename") == 0) 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_1,
target->fileio_info->param_2, target->fileio_info->param_2,
target->fileio_info->param_3, target->fileio_info->param_3,
target->fileio_info->param_4); target->fileio_info->param_4);
else if (strcmp(target->fileio_info->identifier, "unlink") == 0) 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_1,
target->fileio_info->param_2); target->fileio_info->param_2);
else if (strcmp(target->fileio_info->identifier, "stat") == 0) 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_1,
target->fileio_info->param_2, target->fileio_info->param_2,
target->fileio_info->param_3); target->fileio_info->param_3);
else if (strcmp(target->fileio_info->identifier, "fstat") == 0) 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_1,
target->fileio_info->param_2); target->fileio_info->param_2);
else if (strcmp(target->fileio_info->identifier, "gettimeofday") == 0) 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_1,
target->fileio_info->param_2); target->fileio_info->param_2);
else if (strcmp(target->fileio_info->identifier, "isatty") == 0) 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); target->fileio_info->param_1);
else if (strcmp(target->fileio_info->identifier, "system") == 0) 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_1,
target->fileio_info->param_2); target->fileio_info->param_2);
else if (strcmp(target->fileio_info->identifier, "exit") == 0) { else if (strcmp(target->fileio_info->identifier, "exit") == 0) {
/* If target hits exit syscall, report to GDB the program is terminated. /* If target hits exit syscall, report to GDB the program is terminated.
* In addition, let target run its own exit syscall handler. */ * In addition, let target run its own exit syscall handler. */
program_exited = true; 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 { } else {
LOG_DEBUG("Unknown syscall: %s", target->fileio_info->identifier); 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 */ /* simple case, a continue packet */
if (parse[0] == 'c') { if (parse[0] == 'c') {
gdb_running_type = 'c';
LOG_DEBUG("target %s continue", target_name(target)); LOG_DEBUG("target %s continue", target_name(target));
log_add_callback(gdb_log_callback, connection); log_add_callback(gdb_log_callback, connection);
retval = target_resume(target, 1, 0, 0, 0); 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 */ /* single-step or step-over-breakpoint */
if (parse[0] == 's') { if (parse[0] == 's') {
gdb_running_type = 's';
bool fake_step = false; bool fake_step = false;
if (strncmp(parse, "s:", 2) == 0) { if (strncmp(parse, "s:", 2) == 0) {

View File

@ -40,6 +40,7 @@ TARGET_CORE_SRC = \
%D%/target.c \ %D%/target.c \
%D%/target_request.c \ %D%/target_request.c \
%D%/testee.c \ %D%/testee.c \
%D%/semihosting_common.c \
%D%/smp.c %D%/smp.c
ARMV4_5_SRC = \ ARMV4_5_SRC = \
@ -218,6 +219,7 @@ RISCV_SRC = \
%D%/nds32_v3.h \ %D%/nds32_v3.h \
%D%/nds32_v3m.h \ %D%/nds32_v3m.h \
%D%/nds32_aice.h \ %D%/nds32_aice.h \
%D%/semihosting_common.h \
%D%/stm8.h \ %D%/stm8.h \
%D%/lakemont.h \ %D%/lakemont.h \
%D%/x86_32_common.h \ %D%/x86_32_common.h \

View File

@ -2590,6 +2590,143 @@ COMMAND_HANDLER(aarch64_mask_interrupts_command)
return ERROR_OK; 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[] = { static const struct command_registration aarch64_exec_command_handlers[] = {
{ {
.name = "cache_info", .name = "cache_info",
@ -2625,9 +2762,25 @@ static const struct command_registration aarch64_exec_command_handlers[] = {
.help = "mask aarch64 interrupts during single-step", .help = "mask aarch64 interrupts during single-step",
.usage = "['on'|'off']", .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 COMMAND_REGISTRATION_DONE
}; };
static const struct command_registration aarch64_command_handlers[] = { static const struct command_registration aarch64_command_handlers[] = {
{ {
.chain = armv8_command_handlers, .chain = armv8_command_handlers,

View File

@ -8,6 +8,9 @@
* Copyright (C) 2009 by Øyvind Harboe * Copyright (C) 2009 by Øyvind Harboe
* oyvind.harboe@zylin.com * 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 * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
@ -28,7 +31,6 @@
#include <helper/command.h> #include <helper/command.h>
#include "target.h" #include "target.h"
/** /**
* @file * @file
* Holds the interface to ARM cores. * Holds the interface to ARM cores.
@ -181,32 +183,11 @@ struct arm {
/** Flag reporting armv6m based core. */ /** Flag reporting armv6m based core. */
bool is_armv6m; 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. */ /** Floating point or VFP version, 0 if disabled. */
int arm_vfp_version; 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); int (*setup_semihosting)(struct target *target, int enable);
/** Semihosting command line. */
char *semihosting_cmdline;
/** Backpointer to the target. */ /** Backpointer to the target. */
struct target *target; struct target *target;

View File

@ -8,6 +8,9 @@
* Copyright (C) 2016 by Square, Inc. * * Copyright (C) 2016 by Square, Inc. *
* Steven Stallion <stallion@squareup.com> * * 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 * * 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 * * it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or * * the Free Software Foundation; either version 2 of the License, or *
@ -52,21 +55,6 @@
#include <helper/log.h> #include <helper/log.h>
#include <sys/stat.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) static int post_result(struct target *target)
{ {
struct arm *arm = target_to_arm(target); struct arm *arm = target_to_arm(target);
@ -79,7 +67,7 @@ static int post_result(struct target *target)
uint32_t spsr; uint32_t spsr;
/* return value in R0 */ /* 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; arm->core_cache->reg_list[0].dirty = 1;
/* LR --> PC */ /* LR --> PC */
@ -105,523 +93,13 @@ static int post_result(struct target *target)
* bkpt instruction */ * bkpt instruction */
/* return result in R0 */ /* 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; arm->core_cache->reg_list[0].dirty = 1;
} }
return ERROR_OK; 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. * 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) int arm_semihosting_init(struct target *target)
{ {
target->fileio_info = malloc(sizeof(*target->fileio_info)); struct arm *arm = target_to_arm(target);
if (target->fileio_info == NULL) { assert(arm->setup_semihosting);
LOG_ERROR("out of memory"); semihosting_common_init(target, arm->setup_semihosting, post_result);
return ERROR_FAIL;
}
target->type->get_gdb_fileio_info = get_gdb_fileio_info;
target->type->gdb_fileio_end = gdb_fileio_end;
return ERROR_OK; return ERROR_OK;
} }
@ -662,7 +135,11 @@ int arm_semihosting(struct target *target, int *retval)
uint32_t pc, lr, spsr; uint32_t pc, lr, spsr;
struct reg *r; struct reg *r;
if (!arm->is_semihosting) struct semihosting *semihosting = target->semihosting;
if (!semihosting)
return 0;
if (!semihosting->is_active)
return 0; return 0;
if (is_arm7_9(target_to_arm7_9(target)) || 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 /* Perform semihosting if we are not waiting on a fileio
* operation to complete. * operation to complete.
*/ */
if (!arm->semihosting_hit_fileio) { if (!semihosting->hit_fileio) {
*retval = do_semihosting(target); /* TODO: update for 64-bits */
if (*retval != ERROR_OK) { uint32_t r0 = buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32);
LOG_ERROR("Failed semihosting operation"); 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; 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 /* Post result to target if we are not waiting on a fileio
* operation to complete: * operation to complete:
*/ */
if (!arm->semihosting_hit_fileio) { if (semihosting->is_resumable && !semihosting->hit_fileio) {
*retval = post_result(target); /* Resume right after the BRK instruction. */
if (*retval != ERROR_OK) {
LOG_ERROR("Failed to post semihosting result");
return 0;
}
*retval = target_resume(target, 1, 0, 0, 0); *retval = target_resume(target, 1, 0, 0, 0);
if (*retval != ERROR_OK) { if (*retval != ERROR_OK) {
LOG_ERROR("Failed to resume target"); LOG_ERROR("Failed to resume target");

View File

@ -19,6 +19,8 @@
#ifndef OPENOCD_TARGET_ARM_SEMIHOSTING_H #ifndef OPENOCD_TARGET_ARM_SEMIHOSTING_H
#define 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_init(struct target *target);
int arm_semihosting(struct target *target, int *retval); int arm_semihosting(struct target *target, int *retval);

View File

@ -8,6 +8,9 @@
* Copyright (C) 2008 by Oyvind Harboe * * Copyright (C) 2008 by Oyvind Harboe *
* oyvind.harboe@zylin.com * * 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 * * 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 * * it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or * * the Free Software Foundation; either version 2 of the License, or *
@ -34,6 +37,7 @@
#include <helper/binarybuffer.h> #include <helper/binarybuffer.h>
#include "algorithm.h" #include "algorithm.h"
#include "register.h" #include "register.h"
#include "semihosting_common.h"
/* offsets into armv4_5 core register cache */ /* offsets into armv4_5 core register cache */
enum { enum {
@ -748,7 +752,7 @@ int arm_arch_state(struct target *target)
} }
/* avoid filling log waiting for fileio reply */ /* avoid filling log waiting for fileio reply */
if (arm->semihosting_hit_fileio) if (target->semihosting->hit_fileio)
return ERROR_OK; return ERROR_OK;
LOG_USER("target halted in %s state due to %s, current mode: %s\n" 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), arm_mode_name(arm->core_mode),
buf_get_u32(arm->cpsr->value, 0, 32), buf_get_u32(arm->cpsr->value, 0, 32),
buf_get_u32(arm->pc->value, 0, 32), buf_get_u32(arm->pc->value, 0, 32),
arm->is_semihosting ? ", semihosting" : "", target->semihosting->is_active ? ", semihosting" : "",
arm->is_semihosting_fileio ? " fileio" : ""); target->semihosting->is_fileio ? " fileio" : "");
return ERROR_OK; return ERROR_OK;
} }
@ -1094,119 +1098,10 @@ static int jim_mcrmrc(Jim_Interp *interp, int argc, Jim_Obj * const *argv)
return JIM_OK; return JIM_OK;
} }
COMMAND_HANDLER(handle_arm_semihosting_command) extern __COMMAND_HANDLER(handle_common_semihosting_command);
{ extern __COMMAND_HANDLER(handle_common_semihosting_fileio_command);
struct target *target = get_current_target(CMD_CTX); extern __COMMAND_HANDLER(handle_common_semihosting_resumable_exit_command);
extern __COMMAND_HANDLER(handle_common_semihosting_cmdline);
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;
}
static const struct command_registration arm_exec_command_handlers[] = { static const struct command_registration arm_exec_command_handlers[] = {
{ {
@ -1245,26 +1140,32 @@ static const struct command_registration arm_exec_command_handlers[] = {
}, },
{ {
"semihosting", "semihosting",
.handler = handle_arm_semihosting_command, .handler = handle_common_semihosting_command,
.mode = COMMAND_EXEC, .mode = COMMAND_EXEC,
.usage = "['enable'|'disable']", .usage = "['enable'|'disable']",
.help = "activate support for semihosting operations", .help = "activate support for semihosting operations",
}, },
{ {
"semihosting_cmdline", "semihosting_cmdline",
.handler = handle_arm_semihosting_cmdline, .handler = handle_common_semihosting_cmdline,
.mode = COMMAND_EXEC, .mode = COMMAND_EXEC,
.usage = "arguments", .usage = "arguments",
.help = "command line arguments to be passed to program", .help = "command line arguments to be passed to program",
}, },
{ {
"semihosting_fileio", "semihosting_fileio",
.handler = handle_arm_semihosting_fileio_command, .handler = handle_common_semihosting_fileio_command,
.mode = COMMAND_EXEC, .mode = COMMAND_EXEC,
.usage = "['enable'|'disable']", .usage = "['enable'|'disable']",
.help = "activate support for semihosting fileio operations", .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 COMMAND_REGISTRATION_DONE
}; };
const struct command_registration arm_command_handlers[] = { const struct command_registration arm_command_handlers[] = {

View File

@ -11,6 +11,9 @@
* Copyright (C) 2007,2008 Øyvind Harboe * * Copyright (C) 2007,2008 Øyvind Harboe *
* oyvind.harboe@zylin.com * * 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 * * 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 * * it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or * * the Free Software Foundation; either version 2 of the License, or *
@ -37,6 +40,7 @@
#include "armv7m.h" #include "armv7m.h"
#include "algorithm.h" #include "algorithm.h"
#include "register.h" #include "register.h"
#include "semihosting_common.h"
#if 0 #if 0
#define _DEBUG_INSTRUCTION_EXECUTION_ #define _DEBUG_INSTRUCTION_EXECUTION_
@ -537,7 +541,7 @@ int armv7m_arch_state(struct target *target)
uint32_t ctrl, sp; uint32_t ctrl, sp;
/* avoid filling log waiting for fileio reply */ /* avoid filling log waiting for fileio reply */
if (arm->semihosting_hit_fileio) if (target->semihosting->hit_fileio)
return ERROR_OK; return ERROR_OK;
ctrl = buf_get_u32(arm->core_cache->reg_list[ARMV7M_CONTROL].value, 0, 32); 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), buf_get_u32(arm->pc->value, 0, 32),
(ctrl & 0x02) ? 'p' : 'm', (ctrl & 0x02) ? 'p' : 'm',
sp, sp,
arm->is_semihosting ? ", semihosting" : "", target->semihosting->is_active ? ", semihosting" : "",
arm->is_semihosting_fileio ? " fileio" : ""); target->semihosting->is_fileio ? " fileio" : "");
return ERROR_OK; return ERROR_OK;
} }

View File

@ -1,6 +1,9 @@
/*************************************************************************** /***************************************************************************
* Copyright (C) 2015 by David Ung * * 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 * * 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 * * it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or * * the Free Software Foundation; either version 2 of the License, or *
@ -36,6 +39,7 @@
#include "armv8_opcodes.h" #include "armv8_opcodes.h"
#include "target.h" #include "target.h"
#include "target_type.h" #include "target_type.h"
#include "semihosting_common.h"
static const char * const armv8_state_strings[] = { static const char * const armv8_state_strings[] = {
"AArch32", "Thumb", "Jazelle", "ThumbEE", "AArch64", "AArch32", "Thumb", "Jazelle", "ThumbEE", "AArch64",
@ -1046,7 +1050,7 @@ int armv8_aarch64_state(struct target *target)
armv8_mode_name(arm->core_mode), armv8_mode_name(arm->core_mode),
buf_get_u32(arm->cpsr->value, 0, 32), buf_get_u32(arm->cpsr->value, 0, 32),
buf_get_u64(arm->pc->value, 0, 64), buf_get_u64(arm->pc->value, 0, 64),
arm->is_semihosting ? ", semihosting" : ""); target->semihosting->is_active ? ", semihosting" : "");
return ERROR_OK; return ERROR_OK;
} }

View File

@ -315,11 +315,8 @@ int breakpoint_remove_internal(struct target *target, target_addr_t address)
struct breakpoint *breakpoint = target->breakpoints; struct breakpoint *breakpoint = target->breakpoints;
while (breakpoint) { while (breakpoint) {
if ((breakpoint->address == address) && (breakpoint->asid == 0)) if ((breakpoint->address == address) ||
break; (breakpoint->address == 0 && breakpoint->asid == address))
else if ((breakpoint->address == 0) && (breakpoint->asid == address))
break;
else if ((breakpoint->address == address) && (breakpoint->asid != 0))
break; break;
breakpoint = breakpoint->next; breakpoint = breakpoint->next;
} }

View File

@ -1806,11 +1806,11 @@ static int cortex_m_dwt_set_reg(struct reg *reg, uint8_t *buf)
struct dwt_reg { struct dwt_reg {
uint32_t addr; uint32_t addr;
char *name; const char *name;
unsigned size; unsigned size;
}; };
static struct dwt_reg dwt_base_regs[] = { static const struct dwt_reg dwt_base_regs[] = {
{ DWT_CTRL, "dwt_ctrl", 32, }, { DWT_CTRL, "dwt_ctrl", 32, },
/* NOTE that Erratum 532314 (fixed r2p0) affects CYCCNT: it wrongly /* NOTE that Erratum 532314 (fixed r2p0) affects CYCCNT: it wrongly
* increments while the core is asleep. * 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 */ /* 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) \ #define DWT_COMPARATOR(i) \
{ DWT_COMP0 + 0x10 * (i), "dwt_" #i "_comp", 32, }, \ { DWT_COMP0 + 0x10 * (i), "dwt_" #i "_comp", 32, }, \
{ DWT_MASK0 + 0x10 * (i), "dwt_" #i "_mask", 4, }, \ { 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, .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; struct dwt_reg_state *state;

View File

@ -2339,63 +2339,66 @@ int nds32_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fil
fileio_info->identifier = NULL; fileio_info->identifier = NULL;
} }
uint32_t reg_r0, reg_r1, reg_r2;
nds32_get_mapped_reg(nds32, R0, &reg_r0);
nds32_get_mapped_reg(nds32, R1, &reg_r1);
nds32_get_mapped_reg(nds32, R2, &reg_r2);
switch (syscall_id) { switch (syscall_id) {
case NDS32_SYSCALL_EXIT: case NDS32_SYSCALL_EXIT:
fileio_info->identifier = malloc(5); fileio_info->identifier = malloc(5);
sprintf(fileio_info->identifier, "exit"); sprintf(fileio_info->identifier, "exit");
nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1)); fileio_info->param_1 = reg_r0;
break; break;
case NDS32_SYSCALL_OPEN: case NDS32_SYSCALL_OPEN:
{ {
uint8_t filename[256]; uint8_t filename[256];
fileio_info->identifier = malloc(5); fileio_info->identifier = malloc(5);
sprintf(fileio_info->identifier, "open"); 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 */ /* reserve fileio_info->param_2 for length of path */
nds32_get_mapped_reg(nds32, R1, &(fileio_info->param_3)); fileio_info->param_3 = reg_r1;
nds32_get_mapped_reg(nds32, R2, &(fileio_info->param_4)); fileio_info->param_4 = reg_r2;
target->type->read_buffer(target, fileio_info->param_1, target->type->read_buffer(target, reg_r0, 256, filename);
256, filename);
fileio_info->param_2 = strlen((char *)filename) + 1; fileio_info->param_2 = strlen((char *)filename) + 1;
} }
break; break;
case NDS32_SYSCALL_CLOSE: case NDS32_SYSCALL_CLOSE:
fileio_info->identifier = malloc(6); fileio_info->identifier = malloc(6);
sprintf(fileio_info->identifier, "close"); sprintf(fileio_info->identifier, "close");
nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1)); fileio_info->param_1 = reg_r0;
break; break;
case NDS32_SYSCALL_READ: case NDS32_SYSCALL_READ:
fileio_info->identifier = malloc(5); fileio_info->identifier = malloc(5);
sprintf(fileio_info->identifier, "read"); sprintf(fileio_info->identifier, "read");
nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1)); fileio_info->param_1 = reg_r0;
nds32_get_mapped_reg(nds32, R1, &(fileio_info->param_2)); fileio_info->param_2 = reg_r1;
nds32_get_mapped_reg(nds32, R2, &(fileio_info->param_3)); fileio_info->param_3 = reg_r2;
break; break;
case NDS32_SYSCALL_WRITE: case NDS32_SYSCALL_WRITE:
fileio_info->identifier = malloc(6); fileio_info->identifier = malloc(6);
sprintf(fileio_info->identifier, "write"); sprintf(fileio_info->identifier, "write");
nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1)); fileio_info->param_1 = reg_r0;
nds32_get_mapped_reg(nds32, R1, &(fileio_info->param_2)); fileio_info->param_2 = reg_r1;
nds32_get_mapped_reg(nds32, R2, &(fileio_info->param_3)); fileio_info->param_3 = reg_r2;
break; break;
case NDS32_SYSCALL_LSEEK: case NDS32_SYSCALL_LSEEK:
fileio_info->identifier = malloc(6); fileio_info->identifier = malloc(6);
sprintf(fileio_info->identifier, "lseek"); sprintf(fileio_info->identifier, "lseek");
nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1)); fileio_info->param_1 = reg_r0;
nds32_get_mapped_reg(nds32, R1, &(fileio_info->param_2)); fileio_info->param_2 = reg_r1;
nds32_get_mapped_reg(nds32, R2, &(fileio_info->param_3)); fileio_info->param_3 = reg_r2;
break; break;
case NDS32_SYSCALL_UNLINK: case NDS32_SYSCALL_UNLINK:
{ {
uint8_t filename[256]; uint8_t filename[256];
fileio_info->identifier = malloc(7); fileio_info->identifier = malloc(7);
sprintf(fileio_info->identifier, "unlink"); 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 */ /* reserve fileio_info->param_2 for length of path */
target->type->read_buffer(target, fileio_info->param_1, target->type->read_buffer(target, reg_r0, 256, filename);
256, filename);
fileio_info->param_2 = strlen((char *)filename) + 1; fileio_info->param_2 = strlen((char *)filename) + 1;
} }
break; break;
@ -2404,61 +2407,57 @@ int nds32_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fil
uint8_t filename[256]; uint8_t filename[256];
fileio_info->identifier = malloc(7); fileio_info->identifier = malloc(7);
sprintf(fileio_info->identifier, "rename"); 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 */ /* 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 */ /* reserve fileio_info->param_4 for length of new path */
target->type->read_buffer(target, fileio_info->param_1, target->type->read_buffer(target, reg_r0, 256, filename);
256, filename);
fileio_info->param_2 = strlen((char *)filename) + 1; fileio_info->param_2 = strlen((char *)filename) + 1;
target->type->read_buffer(target, fileio_info->param_3, target->type->read_buffer(target, reg_r1, 256, filename);
256, filename);
fileio_info->param_4 = strlen((char *)filename) + 1; fileio_info->param_4 = strlen((char *)filename) + 1;
} }
break; break;
case NDS32_SYSCALL_FSTAT: case NDS32_SYSCALL_FSTAT:
fileio_info->identifier = malloc(6); fileio_info->identifier = malloc(6);
sprintf(fileio_info->identifier, "fstat"); sprintf(fileio_info->identifier, "fstat");
nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1)); fileio_info->param_1 = reg_r0;
nds32_get_mapped_reg(nds32, R1, &(fileio_info->param_2)); fileio_info->param_2 = reg_r1;
break; break;
case NDS32_SYSCALL_STAT: case NDS32_SYSCALL_STAT:
{ {
uint8_t filename[256]; uint8_t filename[256];
fileio_info->identifier = malloc(5); fileio_info->identifier = malloc(5);
sprintf(fileio_info->identifier, "stat"); 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 */ /* 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, target->type->read_buffer(target, reg_r0, 256, filename);
256, filename);
fileio_info->param_2 = strlen((char *)filename) + 1; fileio_info->param_2 = strlen((char *)filename) + 1;
} }
break; break;
case NDS32_SYSCALL_GETTIMEOFDAY: case NDS32_SYSCALL_GETTIMEOFDAY:
fileio_info->identifier = malloc(13); fileio_info->identifier = malloc(13);
sprintf(fileio_info->identifier, "gettimeofday"); sprintf(fileio_info->identifier, "gettimeofday");
nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1)); fileio_info->param_1 = reg_r0;
nds32_get_mapped_reg(nds32, R1, &(fileio_info->param_2)); fileio_info->param_2 = reg_r1;
break; break;
case NDS32_SYSCALL_ISATTY: case NDS32_SYSCALL_ISATTY:
fileio_info->identifier = malloc(7); fileio_info->identifier = malloc(7);
sprintf(fileio_info->identifier, "isatty"); sprintf(fileio_info->identifier, "isatty");
nds32_get_mapped_reg(nds32, R0, &(fileio_info->param_1)); fileio_info->param_1 = reg_r0;
break; break;
case NDS32_SYSCALL_SYSTEM: case NDS32_SYSCALL_SYSTEM:
{ {
uint8_t command[256]; uint8_t command[256];
fileio_info->identifier = malloc(7); fileio_info->identifier = malloc(7);
sprintf(fileio_info->identifier, "system"); 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 */ /* reserve fileio_info->param_2 for length of old path */
target->type->read_buffer(target, fileio_info->param_1, target->type->read_buffer(target, reg_r0, 256, command);
256, command);
fileio_info->param_2 = strlen((char *)command) + 1; fileio_info->param_2 = strlen((char *)command) + 1;
} }
break; break;

File diff suppressed because it is too large Load Diff

View File

@ -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 */

View File

@ -1895,6 +1895,9 @@ static void target_destroy(struct target *target)
if (target->type->deinit_target) if (target->type->deinit_target)
target->type->deinit_target(target); target->type->deinit_target(target);
if (target->semihosting)
free(target->semihosting);
jtag_unregister_event_callback(jtag_enable_callback, target); jtag_unregister_event_callback(jtag_enable_callback, target);
struct target_event_action *teap = target->event_action; struct target_event_action *teap = target->event_action;
@ -5448,21 +5451,19 @@ static const struct command_registration target_instance_command_handlers[] = {
.mode = COMMAND_EXEC, .mode = COMMAND_EXEC,
.jim_handler = jim_target_examine, .jim_handler = jim_target_examine,
.help = "used internally for reset processing", .help = "used internally for reset processing",
.usage = "arp_examine ['allow-defer']", .usage = "['allow-defer']",
}, },
{ {
.name = "was_examined", .name = "was_examined",
.mode = COMMAND_EXEC, .mode = COMMAND_EXEC,
.jim_handler = jim_target_was_examined, .jim_handler = jim_target_was_examined,
.help = "used internally for reset processing", .help = "used internally for reset processing",
.usage = "was_examined",
}, },
{ {
.name = "examine_deferred", .name = "examine_deferred",
.mode = COMMAND_EXEC, .mode = COMMAND_EXEC,
.jim_handler = jim_target_examine_deferred, .jim_handler = jim_target_examine_deferred,
.help = "used internally for reset processing", .help = "used internally for reset processing",
.usage = "examine_deferred",
}, },
{ {
.name = "arp_halt_gdb", .name = "arp_halt_gdb",

View File

@ -205,6 +205,9 @@ struct target {
/* file-I/O information for host to do syscall */ /* file-I/O information for host to do syscall */
struct gdb_fileio_info *fileio_info; struct gdb_fileio_info *fileio_info;
/* The semihosting information, extracted from the target. */
struct semihosting *semihosting;
}; };
struct target_list { struct target_list {
@ -214,10 +217,10 @@ struct target_list {
struct gdb_fileio_info { struct gdb_fileio_info {
char *identifier; char *identifier;
uint32_t param_1; uint64_t param_1;
uint32_t param_2; uint64_t param_2;
uint32_t param_3; uint64_t param_3;
uint32_t param_4; uint64_t param_4;
}; };
/** Returns the instance-specific name of the specified target. */ /** Returns the instance-specific name of the specified target. */

View File

@ -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]

View File

@ -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]

12
tcl/interface/xds110.cfg Normal file
View File

@ -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

View File

@ -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

View File

@ -28,6 +28,38 @@ dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu
set _TARGETNAME $_CHIPNAME.cpu set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap 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]} { if {![using_hla]} {
cortex_m reset_config sysresetreq cortex_m reset_config sysresetreq
} }

View File

@ -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

64
tcl/target/ti_cc32xx.cfg Normal file
View File

@ -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