Merge pull request #1142 from en-sc/en-sc/from_upstream
Merge up to 1173473f66
from upstream
This commit is contained in:
commit
a4020f1a02
|
@ -2227,7 +2227,7 @@ the port @var{number} defaults to 6666.
|
||||||
When specified as "disabled", this service is not activated.
|
When specified as "disabled", this service is not activated.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
@deffn {Config Command} {telnet_port} [number]
|
@deffn {Config Command} {telnet port} [number]
|
||||||
Specify or query the
|
Specify or query the
|
||||||
port on which to listen for incoming telnet connections.
|
port on which to listen for incoming telnet connections.
|
||||||
This port is intended for interaction with one human through TCL commands.
|
This port is intended for interaction with one human through TCL commands.
|
||||||
|
|
|
@ -85,6 +85,9 @@
|
||||||
#define SAME_SERIES_51 0x01
|
#define SAME_SERIES_51 0x01
|
||||||
#define SAME_SERIES_53 0x03
|
#define SAME_SERIES_53 0x03
|
||||||
#define SAME_SERIES_54 0x04
|
#define SAME_SERIES_54 0x04
|
||||||
|
#define PIC32CXSG_SERIES_41 0x07
|
||||||
|
#define PIC32CXSG_SERIES_60 0x00
|
||||||
|
#define PIC32CXSG_SERIES_61 0x02
|
||||||
|
|
||||||
/* Device ID macros */
|
/* Device ID macros */
|
||||||
#define SAMD_GET_PROCESSOR(id) (id >> 28)
|
#define SAMD_GET_PROCESSOR(id) (id >> 28)
|
||||||
|
@ -148,6 +151,27 @@ static const struct samd_part same54_parts[] = {
|
||||||
{ 0x03, "SAME54N19A", 512, 192 },
|
{ 0x03, "SAME54N19A", 512, 192 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* See PIC32CX SG41/SG60/SG61 Family Silicon Errata and Datasheet Clarifications
|
||||||
|
* DS80000985G */
|
||||||
|
/* Known PIC32CX-SG41 parts. */
|
||||||
|
static const struct samd_part pic32cxsg41_parts[] = {
|
||||||
|
{ 0x00, "PIC32CX1025SG41128", 1024, 256 },
|
||||||
|
{ 0x01, "PIC32CX1025SG41100", 1024, 256 },
|
||||||
|
{ 0x02, "PIC32CX1025SG41064", 1024, 256 },
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Known PIC32CX-SG60 parts. */
|
||||||
|
static const struct samd_part pic32cxsg60_parts[] = {
|
||||||
|
{ 0x00, "PIC32CX1025SG60128", 1024, 256 },
|
||||||
|
{ 0x01, "PIC32CX1025SG60100", 1024, 256 },
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Known PIC32CX-SG61 parts. */
|
||||||
|
static const struct samd_part pic32cxsg61_parts[] = {
|
||||||
|
{ 0x00, "PIC32CX1025SG61128", 1024, 256 },
|
||||||
|
{ 0x01, "PIC32CX1025SG61100", 1024, 256 },
|
||||||
|
};
|
||||||
|
|
||||||
/* Each family of parts contains a parts table in the DEVSEL field of DID. The
|
/* Each family of parts contains a parts table in the DEVSEL field of DID. The
|
||||||
* processor ID, family ID, and series ID are used to determine which exact
|
* processor ID, family ID, and series ID are used to determine which exact
|
||||||
* family this is and then we can use the corresponding table. */
|
* family this is and then we can use the corresponding table. */
|
||||||
|
@ -169,6 +193,12 @@ static const struct samd_family samd_families[] = {
|
||||||
same53_parts, ARRAY_SIZE(same53_parts) },
|
same53_parts, ARRAY_SIZE(same53_parts) },
|
||||||
{ SAMD_PROCESSOR_M4, SAMD_FAMILY_E, SAME_SERIES_54,
|
{ SAMD_PROCESSOR_M4, SAMD_FAMILY_E, SAME_SERIES_54,
|
||||||
same54_parts, ARRAY_SIZE(same54_parts) },
|
same54_parts, ARRAY_SIZE(same54_parts) },
|
||||||
|
{ SAMD_PROCESSOR_M4, SAMD_FAMILY_E, PIC32CXSG_SERIES_41,
|
||||||
|
pic32cxsg41_parts, ARRAY_SIZE(pic32cxsg41_parts) },
|
||||||
|
{ SAMD_PROCESSOR_M4, SAMD_FAMILY_E, PIC32CXSG_SERIES_60,
|
||||||
|
pic32cxsg60_parts, ARRAY_SIZE(pic32cxsg60_parts) },
|
||||||
|
{ SAMD_PROCESSOR_M4, SAMD_FAMILY_E, PIC32CXSG_SERIES_61,
|
||||||
|
pic32cxsg61_parts, ARRAY_SIZE(pic32cxsg61_parts) },
|
||||||
};
|
};
|
||||||
|
|
||||||
struct samd_info {
|
struct samd_info {
|
||||||
|
|
|
@ -57,49 +57,49 @@ void *buf_cpy(const void *from, void *_to, unsigned size)
|
||||||
return _to;
|
return _to;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool buf_cmp_masked(uint8_t a, uint8_t b, uint8_t m)
|
static bool buf_eq_masked(uint8_t a, uint8_t b, uint8_t m)
|
||||||
{
|
{
|
||||||
return (a & m) != (b & m);
|
return (a & m) == (b & m);
|
||||||
}
|
}
|
||||||
static bool buf_cmp_trailing(uint8_t a, uint8_t b, uint8_t m, unsigned trailing)
|
static bool buf_eq_trailing(uint8_t a, uint8_t b, uint8_t m, unsigned trailing)
|
||||||
{
|
{
|
||||||
uint8_t mask = (1 << trailing) - 1;
|
uint8_t mask = (1 << trailing) - 1;
|
||||||
return buf_cmp_masked(a, b, mask & m);
|
return buf_eq_masked(a, b, mask & m);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool buf_cmp(const void *_buf1, const void *_buf2, unsigned size)
|
bool buf_eq(const void *_buf1, const void *_buf2, unsigned size)
|
||||||
{
|
{
|
||||||
if (!_buf1 || !_buf2)
|
if (!_buf1 || !_buf2)
|
||||||
return _buf1 != _buf2;
|
return _buf1 == _buf2;
|
||||||
|
|
||||||
unsigned last = size / 8;
|
unsigned last = size / 8;
|
||||||
if (memcmp(_buf1, _buf2, last) != 0)
|
if (memcmp(_buf1, _buf2, last) != 0)
|
||||||
return true;
|
return false;
|
||||||
|
|
||||||
unsigned trailing = size % 8;
|
unsigned trailing = size % 8;
|
||||||
if (!trailing)
|
if (!trailing)
|
||||||
return false;
|
return true;
|
||||||
|
|
||||||
const uint8_t *buf1 = _buf1, *buf2 = _buf2;
|
const uint8_t *buf1 = _buf1, *buf2 = _buf2;
|
||||||
return buf_cmp_trailing(buf1[last], buf2[last], 0xff, trailing);
|
return buf_eq_trailing(buf1[last], buf2[last], 0xff, trailing);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool buf_cmp_mask(const void *_buf1, const void *_buf2,
|
bool buf_eq_mask(const void *_buf1, const void *_buf2,
|
||||||
const void *_mask, unsigned size)
|
const void *_mask, unsigned size)
|
||||||
{
|
{
|
||||||
if (!_buf1 || !_buf2)
|
if (!_buf1 || !_buf2)
|
||||||
return _buf1 != _buf2 || _buf1 != _mask;
|
return _buf1 == _buf2 && _buf1 == _mask;
|
||||||
|
|
||||||
const uint8_t *buf1 = _buf1, *buf2 = _buf2, *mask = _mask;
|
const uint8_t *buf1 = _buf1, *buf2 = _buf2, *mask = _mask;
|
||||||
unsigned last = size / 8;
|
unsigned last = size / 8;
|
||||||
for (unsigned i = 0; i < last; i++) {
|
for (unsigned i = 0; i < last; i++) {
|
||||||
if (buf_cmp_masked(buf1[i], buf2[i], mask[i]))
|
if (!buf_eq_masked(buf1[i], buf2[i], mask[i]))
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
unsigned trailing = size % 8;
|
unsigned trailing = size % 8;
|
||||||
if (!trailing)
|
if (!trailing)
|
||||||
return false;
|
return true;
|
||||||
return buf_cmp_trailing(buf1[last], buf2[last], mask[last], trailing);
|
return buf_eq_trailing(buf1[last], buf2[last], mask[last], trailing);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *buf_set_ones(void *_buf, unsigned size)
|
void *buf_set_ones(void *_buf, unsigned size)
|
||||||
|
|
|
@ -172,8 +172,8 @@ static inline uint64_t buf_get_u64(const uint8_t *_buffer,
|
||||||
*/
|
*/
|
||||||
uint32_t flip_u32(uint32_t value, unsigned width);
|
uint32_t flip_u32(uint32_t value, unsigned width);
|
||||||
|
|
||||||
bool buf_cmp(const void *buf1, const void *buf2, unsigned size);
|
bool buf_eq(const void *buf1, const void *buf2, unsigned size);
|
||||||
bool buf_cmp_mask(const void *buf1, const void *buf2,
|
bool buf_eq_mask(const void *buf1, const void *buf2,
|
||||||
const void *mask, unsigned size);
|
const void *mask, unsigned size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -881,9 +881,9 @@ static int jtag_check_value_inner(uint8_t *captured, uint8_t *in_check_value,
|
||||||
int compare_failed;
|
int compare_failed;
|
||||||
|
|
||||||
if (in_check_mask)
|
if (in_check_mask)
|
||||||
compare_failed = buf_cmp_mask(captured, in_check_value, in_check_mask, num_bits);
|
compare_failed = !buf_eq_mask(captured, in_check_value, in_check_mask, num_bits);
|
||||||
else
|
else
|
||||||
compare_failed = buf_cmp(captured, in_check_value, num_bits);
|
compare_failed = !buf_eq(captured, in_check_value, num_bits);
|
||||||
|
|
||||||
if (compare_failed) {
|
if (compare_failed) {
|
||||||
char *captured_str, *in_check_value_str;
|
char *captured_str, *in_check_value_str;
|
||||||
|
|
|
@ -32,7 +32,6 @@
|
||||||
struct nuttx_params {
|
struct nuttx_params {
|
||||||
const char *target_name;
|
const char *target_name;
|
||||||
const struct rtos_register_stacking *stacking;
|
const struct rtos_register_stacking *stacking;
|
||||||
const struct rtos_register_stacking *(*select_stackinfo)(struct target *target);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -56,19 +55,12 @@ struct symbols {
|
||||||
bool optional;
|
bool optional;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Used to index the list of retrieved symbols. See nuttx_symbol_list for the order. */
|
|
||||||
enum nuttx_symbol_vals {
|
|
||||||
NX_SYM_READYTORUN = 0,
|
|
||||||
NX_SYM_PIDHASH,
|
|
||||||
NX_SYM_NPIDHASH,
|
|
||||||
NX_SYM_TCB_INFO,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct symbols nuttx_symbol_list[] = {
|
static const struct symbols nuttx_symbol_list[] = {
|
||||||
{ "g_readytorun", false },
|
{ "g_readytorun", false },
|
||||||
{ "g_pidhash", false },
|
{ "g_pidhash", false },
|
||||||
{ "g_npidhash", false },
|
{ "g_npidhash", false },
|
||||||
{ "g_tcbinfo", false },
|
{ "g_tcbinfo", false },
|
||||||
|
{ "g_reg_offs", false},
|
||||||
{ NULL, false }
|
{ NULL, false }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -86,18 +78,14 @@ static char *task_state_str[] = {
|
||||||
"STOPPED",
|
"STOPPED",
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct rtos_register_stacking *cortexm_select_stackinfo(struct target *target);
|
|
||||||
|
|
||||||
static const struct nuttx_params nuttx_params_list[] = {
|
static const struct nuttx_params nuttx_params_list[] = {
|
||||||
{
|
{
|
||||||
.target_name = "cortex_m",
|
.target_name = "cortex_m",
|
||||||
.stacking = NULL,
|
.stacking = &nuttx_stacking_cortex_m,
|
||||||
.select_stackinfo = cortexm_select_stackinfo,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.target_name = "hla_target",
|
.target_name = "hla_target",
|
||||||
.stacking = NULL,
|
.stacking = &nuttx_stacking_cortex_m,
|
||||||
.select_stackinfo = cortexm_select_stackinfo,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.target_name = "esp32",
|
.target_name = "esp32",
|
||||||
|
@ -117,28 +105,6 @@ static const struct nuttx_params nuttx_params_list[] = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool cortexm_hasfpu(struct target *target)
|
|
||||||
{
|
|
||||||
uint32_t cpacr;
|
|
||||||
struct armv7m_common *armv7m_target = target_to_armv7m(target);
|
|
||||||
|
|
||||||
if (!is_armv7m(armv7m_target) || armv7m_target->fp_feature == FP_NONE)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
int retval = target_read_u32(target, FPU_CPACR, &cpacr);
|
|
||||||
if (retval != ERROR_OK) {
|
|
||||||
LOG_ERROR("Could not read CPACR register to check FPU state");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cpacr & 0x00F00000;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct rtos_register_stacking *cortexm_select_stackinfo(struct target *target)
|
|
||||||
{
|
|
||||||
return cortexm_hasfpu(target) ? &nuttx_stacking_cortex_m_fpu : &nuttx_stacking_cortex_m;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool nuttx_detect_rtos(struct target *target)
|
static bool nuttx_detect_rtos(struct target *target)
|
||||||
{
|
{
|
||||||
if (target->rtos->symbols &&
|
if (target->rtos->symbols &&
|
||||||
|
@ -371,29 +337,25 @@ static int nuttx_getreg_current_thread(struct rtos *rtos,
|
||||||
static int nuttx_getregs_fromstack(struct rtos *rtos, int64_t thread_id,
|
static int nuttx_getregs_fromstack(struct rtos *rtos, int64_t thread_id,
|
||||||
struct rtos_reg **reg_list, int *num_regs)
|
struct rtos_reg **reg_list, int *num_regs)
|
||||||
{
|
{
|
||||||
uint16_t xcpreg_off;
|
uint16_t regs_off;
|
||||||
uint32_t regsaddr;
|
uint32_t regsaddr;
|
||||||
const struct nuttx_params *priv = rtos->rtos_specific_params;
|
const struct nuttx_params *priv = rtos->rtos_specific_params;
|
||||||
const struct rtos_register_stacking *stacking = priv->stacking;
|
const struct rtos_register_stacking *stacking = priv->stacking;
|
||||||
|
|
||||||
if (!stacking) {
|
if (!stacking) {
|
||||||
if (priv->select_stackinfo) {
|
LOG_ERROR("Can't find a way to get stacking info");
|
||||||
stacking = priv->select_stackinfo(rtos->target);
|
return ERROR_FAIL;
|
||||||
} else {
|
|
||||||
LOG_ERROR("Can't find a way to get stacking info");
|
|
||||||
return ERROR_FAIL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ret = target_read_u16(rtos->target,
|
int ret = target_read_u16(rtos->target,
|
||||||
rtos->symbols[NX_SYM_TCB_INFO].address + offsetof(struct tcbinfo, regs_off),
|
rtos->symbols[NX_SYM_TCB_INFO].address + offsetof(struct tcbinfo, regs_off),
|
||||||
&xcpreg_off);
|
®s_off);
|
||||||
if (ret != ERROR_OK) {
|
if (ret != ERROR_OK) {
|
||||||
LOG_ERROR("Failed to read registers' offset: ret = %d", ret);
|
LOG_ERROR("Failed to read registers' offset: ret = %d", ret);
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = target_read_u32(rtos->target, thread_id + xcpreg_off, ®saddr);
|
ret = target_read_u32(rtos->target, thread_id + regs_off, ®saddr);
|
||||||
if (ret != ERROR_OK) {
|
if (ret != ERROR_OK) {
|
||||||
LOG_ERROR("Failed to read registers' address: ret = %d", ret);
|
LOG_ERROR("Failed to read registers' address: ret = %d", ret);
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
|
|
|
@ -9,62 +9,102 @@
|
||||||
#include "rtos_nuttx_stackings.h"
|
#include "rtos_nuttx_stackings.h"
|
||||||
#include "rtos_standard_stackings.h"
|
#include "rtos_standard_stackings.h"
|
||||||
#include <target/riscv/riscv.h>
|
#include <target/riscv/riscv.h>
|
||||||
|
#include <helper/bits.h>
|
||||||
|
|
||||||
/* see arch/arm/include/armv7-m/irq_cmnvector.h */
|
/* The cortex_m target uses nuttx_tcbinfo_stack_read which uses a symbol
|
||||||
|
* provided by Nuttx to read the registers from memory and place them directly
|
||||||
|
* in the order we need. This is because the register offsets change with
|
||||||
|
* different versions of Nuttx, FPU vs non-FPU and ARMv7 vs ARMv8.
|
||||||
|
* This allows a single function to work with many versions.
|
||||||
|
*/
|
||||||
static const struct stack_register_offset nuttx_stack_offsets_cortex_m[] = {
|
static const struct stack_register_offset nuttx_stack_offsets_cortex_m[] = {
|
||||||
{ ARMV7M_R0, 0x28, 32 }, /* r0 */
|
{ ARMV7M_R0, 0, 32 }, /* r0 */
|
||||||
{ ARMV7M_R1, 0x2c, 32 }, /* r1 */
|
{ ARMV7M_R1, 4, 32 }, /* r1 */
|
||||||
{ ARMV7M_R2, 0x30, 32 }, /* r2 */
|
{ ARMV7M_R2, 8, 32 }, /* r2 */
|
||||||
{ ARMV7M_R3, 0x34, 32 }, /* r3 */
|
{ ARMV7M_R3, 12, 32 }, /* r3 */
|
||||||
{ ARMV7M_R4, 0x08, 32 }, /* r4 */
|
{ ARMV7M_R4, 16, 32 }, /* r4 */
|
||||||
{ ARMV7M_R5, 0x0c, 32 }, /* r5 */
|
{ ARMV7M_R5, 20, 32 }, /* r5 */
|
||||||
{ ARMV7M_R6, 0x10, 32 }, /* r6 */
|
{ ARMV7M_R6, 24, 32 }, /* r6 */
|
||||||
{ ARMV7M_R7, 0x14, 32 }, /* r7 */
|
{ ARMV7M_R7, 28, 32 }, /* r7 */
|
||||||
{ ARMV7M_R8, 0x18, 32 }, /* r8 */
|
{ ARMV7M_R8, 32, 32 }, /* r8 */
|
||||||
{ ARMV7M_R9, 0x1c, 32 }, /* r9 */
|
{ ARMV7M_R9, 36, 32 }, /* r9 */
|
||||||
{ ARMV7M_R10, 0x20, 32 }, /* r10 */
|
{ ARMV7M_R10, 40, 32 }, /* r10 */
|
||||||
{ ARMV7M_R11, 0x24, 32 }, /* r11 */
|
{ ARMV7M_R11, 44, 32 }, /* r11 */
|
||||||
{ ARMV7M_R12, 0x38, 32 }, /* r12 */
|
{ ARMV7M_R12, 48, 32 }, /* r12 */
|
||||||
{ ARMV7M_R13, 0, 32 }, /* sp */
|
{ ARMV7M_R13, 52, 32 }, /* sp */
|
||||||
{ ARMV7M_R14, 0x3c, 32 }, /* lr */
|
{ ARMV7M_R14, 56, 32 }, /* lr */
|
||||||
{ ARMV7M_PC, 0x40, 32 }, /* pc */
|
{ ARMV7M_PC, 60, 32 }, /* pc */
|
||||||
{ ARMV7M_XPSR, 0x44, 32 }, /* xPSR */
|
{ ARMV7M_XPSR, 64, 32 }, /* xPSR */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* The Nuttx stack frame for most architectures has some registers placed
|
||||||
|
* by hardware and some by software. The hardware register order and number does not change
|
||||||
|
* but the software registers may change with different versions of Nuttx.
|
||||||
|
* For example with ARMv7, nuttx-12.3.0 added a new register which changed all
|
||||||
|
* the offsets. We can either create separate offset tables for each version of Nuttx
|
||||||
|
* which will break again in the future, or read the offsets from the TCB info.
|
||||||
|
* Nuttx provides a symbol (g_reg_offs) which holds all the offsets for each stored register.
|
||||||
|
* This offset table is stored in GDB org.gnu.gdb.xxx feature order.
|
||||||
|
* The same order we need.
|
||||||
|
* Please refer:
|
||||||
|
* https://sourceware.org/gdb/current/onlinedocs/gdb/ARM-Features.html
|
||||||
|
* https://sourceware.org/gdb/current/onlinedocs/gdb/RISC_002dV-Features.html
|
||||||
|
*/
|
||||||
|
static int nuttx_cortex_m_tcbinfo_stack_read(struct target *target,
|
||||||
|
int64_t stack_ptr, const struct rtos_register_stacking *stacking,
|
||||||
|
uint8_t *stack_data)
|
||||||
|
{
|
||||||
|
struct rtos *rtos = target->rtos;
|
||||||
|
target_addr_t xcpreg_off = rtos->symbols[NX_SYM_REG_OFFSETS].address;
|
||||||
|
|
||||||
|
for (int i = 0; i < stacking->num_output_registers; ++i) {
|
||||||
|
uint16_t stack_reg_offset;
|
||||||
|
int ret = target_read_u16(rtos->target, xcpreg_off + 2 * i, &stack_reg_offset);
|
||||||
|
if (ret != ERROR_OK) {
|
||||||
|
LOG_ERROR("Failed to read stack_reg_offset: ret = %d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (stack_reg_offset != UINT16_MAX && stacking->register_offsets[i].offset >= 0) {
|
||||||
|
ret = target_read_buffer(target,
|
||||||
|
stack_ptr + stack_reg_offset,
|
||||||
|
stacking->register_offsets[i].width_bits / 8,
|
||||||
|
&stack_data[stacking->register_offsets[i].offset]);
|
||||||
|
if (ret != ERROR_OK) {
|
||||||
|
LOG_ERROR("Failed to read register: ret = %d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Offset match nuttx_stack_offsets_cortex_m */
|
||||||
|
const int XPSR_OFFSET = 64;
|
||||||
|
const int SP_OFFSET = 52;
|
||||||
|
/* Nuttx stack frames (produced in exception_common) store the SP of the ISR minus
|
||||||
|
* the hardware stack frame size. This SP may include an additional 4 byte alignment
|
||||||
|
* depending in xPSR[9]. The Nuttx stack frame stores post alignment since the
|
||||||
|
* hardware will add/remove automatically on both enter/exit.
|
||||||
|
* We need to adjust the SP to get the real SP of the stack.
|
||||||
|
* See Arm Reference manual "Stack alignment on exception entry"
|
||||||
|
*/
|
||||||
|
uint32_t xpsr = target_buffer_get_u32(target, &stack_data[XPSR_OFFSET]);
|
||||||
|
if (xpsr & BIT(9)) {
|
||||||
|
uint32_t sp = target_buffer_get_u32(target, &stack_data[SP_OFFSET]);
|
||||||
|
target_buffer_set_u32(target, &stack_data[SP_OFFSET], sp - 4 * stacking->stack_growth_direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
const struct rtos_register_stacking nuttx_stacking_cortex_m = {
|
const struct rtos_register_stacking nuttx_stacking_cortex_m = {
|
||||||
.stack_registers_size = 0x48,
|
/* nuttx_tcbinfo_stack_read transforms the stack into just output registers */
|
||||||
|
.stack_registers_size = ARRAY_SIZE(nuttx_stack_offsets_cortex_m) * 4,
|
||||||
.stack_growth_direction = -1,
|
.stack_growth_direction = -1,
|
||||||
.num_output_registers = 17,
|
.num_output_registers = ARRAY_SIZE(nuttx_stack_offsets_cortex_m),
|
||||||
|
.read_stack = nuttx_cortex_m_tcbinfo_stack_read,
|
||||||
|
.calculate_process_stack = NULL, /* Stack alignment done in nuttx_cortex_m_tcbinfo_stack_read */
|
||||||
.register_offsets = nuttx_stack_offsets_cortex_m,
|
.register_offsets = nuttx_stack_offsets_cortex_m,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct stack_register_offset nuttx_stack_offsets_cortex_m_fpu[] = {
|
|
||||||
{ ARMV7M_R0, 0x6c, 32 }, /* r0 */
|
|
||||||
{ ARMV7M_R1, 0x70, 32 }, /* r1 */
|
|
||||||
{ ARMV7M_R2, 0x74, 32 }, /* r2 */
|
|
||||||
{ ARMV7M_R3, 0x78, 32 }, /* r3 */
|
|
||||||
{ ARMV7M_R4, 0x08, 32 }, /* r4 */
|
|
||||||
{ ARMV7M_R5, 0x0c, 32 }, /* r5 */
|
|
||||||
{ ARMV7M_R6, 0x10, 32 }, /* r6 */
|
|
||||||
{ ARMV7M_R7, 0x14, 32 }, /* r7 */
|
|
||||||
{ ARMV7M_R8, 0x18, 32 }, /* r8 */
|
|
||||||
{ ARMV7M_R9, 0x1c, 32 }, /* r9 */
|
|
||||||
{ ARMV7M_R10, 0x20, 32 }, /* r10 */
|
|
||||||
{ ARMV7M_R11, 0x24, 32 }, /* r11 */
|
|
||||||
{ ARMV7M_R12, 0x7c, 32 }, /* r12 */
|
|
||||||
{ ARMV7M_R13, 0, 32 }, /* sp */
|
|
||||||
{ ARMV7M_R14, 0x80, 32 }, /* lr */
|
|
||||||
{ ARMV7M_PC, 0x84, 32 }, /* pc */
|
|
||||||
{ ARMV7M_XPSR, 0x88, 32 }, /* xPSR */
|
|
||||||
};
|
|
||||||
|
|
||||||
const struct rtos_register_stacking nuttx_stacking_cortex_m_fpu = {
|
|
||||||
.stack_registers_size = 0x8c,
|
|
||||||
.stack_growth_direction = -1,
|
|
||||||
.num_output_registers = 17,
|
|
||||||
.register_offsets = nuttx_stack_offsets_cortex_m_fpu,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct stack_register_offset nuttx_stack_offsets_riscv[] = {
|
static const struct stack_register_offset nuttx_stack_offsets_riscv[] = {
|
||||||
{ GDB_REGNO_ZERO, -1, 32 },
|
{ GDB_REGNO_ZERO, -1, 32 },
|
||||||
{ GDB_REGNO_RA, 0x04, 32 },
|
{ GDB_REGNO_RA, 0x04, 32 },
|
||||||
|
|
|
@ -5,6 +5,15 @@
|
||||||
|
|
||||||
#include "rtos.h"
|
#include "rtos.h"
|
||||||
|
|
||||||
|
/* Used to index the list of retrieved symbols. See nuttx_symbol_list for the order. */
|
||||||
|
enum nuttx_symbol_vals {
|
||||||
|
NX_SYM_READYTORUN = 0,
|
||||||
|
NX_SYM_PIDHASH,
|
||||||
|
NX_SYM_NPIDHASH,
|
||||||
|
NX_SYM_TCB_INFO,
|
||||||
|
NX_SYM_REG_OFFSETS,
|
||||||
|
};
|
||||||
|
|
||||||
extern const struct rtos_register_stacking nuttx_stacking_cortex_m;
|
extern const struct rtos_register_stacking nuttx_stacking_cortex_m;
|
||||||
extern const struct rtos_register_stacking nuttx_stacking_cortex_m_fpu;
|
extern const struct rtos_register_stacking nuttx_stacking_cortex_m_fpu;
|
||||||
extern const struct rtos_register_stacking nuttx_riscv_stacking;
|
extern const struct rtos_register_stacking nuttx_riscv_stacking;
|
||||||
|
|
|
@ -1838,18 +1838,9 @@ static int gdb_breakpoint_watchpoint_packet(struct connection *connection,
|
||||||
return ERROR_FAIL;
|
return ERROR_FAIL;
|
||||||
}
|
}
|
||||||
retval = breakpoint_add(target, address, size, bp_type);
|
retval = breakpoint_add(target, address, size, bp_type);
|
||||||
if (retval == ERROR_NOT_IMPLEMENTED) {
|
|
||||||
/* Send empty reply to report that breakpoints of this type are not supported */
|
|
||||||
gdb_put_packet(connection, "", 0);
|
|
||||||
} else if (retval != ERROR_OK) {
|
|
||||||
retval = gdb_error(connection, retval);
|
|
||||||
if (retval != ERROR_OK)
|
|
||||||
return retval;
|
|
||||||
} else
|
|
||||||
gdb_put_packet(connection, "OK", 2);
|
|
||||||
} else {
|
} else {
|
||||||
breakpoint_remove(target, address);
|
assert(packet[0] == 'z');
|
||||||
gdb_put_packet(connection, "OK", 2);
|
retval = breakpoint_remove(target, address);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
|
@ -1858,26 +1849,26 @@ static int gdb_breakpoint_watchpoint_packet(struct connection *connection,
|
||||||
{
|
{
|
||||||
if (packet[0] == 'Z') {
|
if (packet[0] == 'Z') {
|
||||||
retval = watchpoint_add(target, address, size, wp_type, 0, WATCHPOINT_IGNORE_DATA_VALUE_MASK);
|
retval = watchpoint_add(target, address, size, wp_type, 0, WATCHPOINT_IGNORE_DATA_VALUE_MASK);
|
||||||
if (retval == ERROR_NOT_IMPLEMENTED) {
|
|
||||||
/* Send empty reply to report that watchpoints of this type are not supported */
|
|
||||||
gdb_put_packet(connection, "", 0);
|
|
||||||
} else if (retval != ERROR_OK) {
|
|
||||||
retval = gdb_error(connection, retval);
|
|
||||||
if (retval != ERROR_OK)
|
|
||||||
return retval;
|
|
||||||
} else
|
|
||||||
gdb_put_packet(connection, "OK", 2);
|
|
||||||
} else {
|
} else {
|
||||||
watchpoint_remove(target, address);
|
assert(packet[0] == 'z');
|
||||||
gdb_put_packet(connection, "OK", 2);
|
retval = watchpoint_remove(target, address);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
{
|
||||||
|
retval = ERROR_NOT_IMPLEMENTED;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ERROR_OK;
|
if (retval == ERROR_NOT_IMPLEMENTED) {
|
||||||
|
/* Send empty reply to report that watchpoints of this type are not supported */
|
||||||
|
return gdb_put_packet(connection, "", 0);
|
||||||
|
}
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return gdb_error(connection, retval);
|
||||||
|
return gdb_put_packet(connection, "OK", 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* print out a string and allocate more space as needed,
|
/* print out a string and allocate more space as needed,
|
||||||
|
|
|
@ -113,3 +113,9 @@ proc "tcl_trace" {state} {
|
||||||
echo "DEPRECATED! use 'tcl trace' not 'tcl_trace'"
|
echo "DEPRECATED! use 'tcl trace' not 'tcl_trace'"
|
||||||
eval tcl trace $state
|
eval tcl trace $state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lappend _telnet_autocomplete_skip "telnet_port"
|
||||||
|
proc "telnet_port" {args} {
|
||||||
|
echo "DEPRECATED! use 'telnet port', not 'telnet_port'"
|
||||||
|
eval telnet port $args
|
||||||
|
}
|
||||||
|
|
|
@ -967,7 +967,6 @@ int telnet_init(char *banner)
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* daemon configuration command telnet_port */
|
|
||||||
COMMAND_HANDLER(handle_telnet_port_command)
|
COMMAND_HANDLER(handle_telnet_port_command)
|
||||||
{
|
{
|
||||||
return CALL_COMMAND_HANDLER(server_pipe_command, &telnet_port);
|
return CALL_COMMAND_HANDLER(server_pipe_command, &telnet_port);
|
||||||
|
@ -978,6 +977,19 @@ COMMAND_HANDLER(handle_exit_command)
|
||||||
return ERROR_COMMAND_CLOSE_CONNECTION;
|
return ERROR_COMMAND_CLOSE_CONNECTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct command_registration telnet_subcommand_handlers[] = {
|
||||||
|
{
|
||||||
|
.name = "port",
|
||||||
|
.handler = handle_telnet_port_command,
|
||||||
|
.mode = COMMAND_CONFIG,
|
||||||
|
.help = "Specify port on which to listen "
|
||||||
|
"for incoming telnet connections. "
|
||||||
|
"Read help on 'gdb port'.",
|
||||||
|
.usage = "[port_num]",
|
||||||
|
},
|
||||||
|
COMMAND_REGISTRATION_DONE
|
||||||
|
};
|
||||||
|
|
||||||
static const struct command_registration telnet_command_handlers[] = {
|
static const struct command_registration telnet_command_handlers[] = {
|
||||||
{
|
{
|
||||||
.name = "exit",
|
.name = "exit",
|
||||||
|
@ -987,13 +999,11 @@ static const struct command_registration telnet_command_handlers[] = {
|
||||||
.help = "exit telnet session",
|
.help = "exit telnet session",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "telnet_port",
|
.name = "telnet",
|
||||||
.handler = handle_telnet_port_command,
|
.chain = telnet_subcommand_handlers,
|
||||||
.mode = COMMAND_CONFIG,
|
.mode = COMMAND_CONFIG,
|
||||||
.help = "Specify port on which to listen "
|
.help = "telnet commands",
|
||||||
"for incoming telnet connections. "
|
.usage = "",
|
||||||
"Read help on 'gdb port'.",
|
|
||||||
.usage = "[port_num]",
|
|
||||||
},
|
},
|
||||||
COMMAND_REGISTRATION_DONE
|
COMMAND_REGISTRATION_DONE
|
||||||
};
|
};
|
||||||
|
|
|
@ -932,7 +932,7 @@ static int svf_check_tdo(void)
|
||||||
index_var = svf_check_tdo_para[i].buffer_offset;
|
index_var = svf_check_tdo_para[i].buffer_offset;
|
||||||
len = svf_check_tdo_para[i].bit_len;
|
len = svf_check_tdo_para[i].bit_len;
|
||||||
if ((svf_check_tdo_para[i].enabled)
|
if ((svf_check_tdo_para[i].enabled)
|
||||||
&& buf_cmp_mask(&svf_tdi_buffer[index_var], &svf_tdo_buffer[index_var],
|
&& !buf_eq_mask(&svf_tdi_buffer[index_var], &svf_tdo_buffer[index_var],
|
||||||
&svf_mask_buffer[index_var], len)) {
|
&svf_mask_buffer[index_var], len)) {
|
||||||
LOG_ERROR("tdo check error at line %d",
|
LOG_ERROR("tdo check error at line %d",
|
||||||
svf_check_tdo_para[i].line_num);
|
svf_check_tdo_para[i].line_num);
|
||||||
|
|
|
@ -193,6 +193,20 @@ static int aarch64_mmu_modify(struct target *target, int enable)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int aarch64_read_prsr(struct target *target, uint32_t *prsr)
|
||||||
|
{
|
||||||
|
struct armv8_common *armv8 = target_to_armv8(target);
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
retval = mem_ap_read_atomic_u32(armv8->debug_ap,
|
||||||
|
armv8->debug_base + CPUV8_DBG_PRSR, prsr);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
armv8->sticky_reset |= *prsr & PRSR_SR;
|
||||||
|
return ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Basic debug access, very low level assumes state is saved
|
* Basic debug access, very low level assumes state is saved
|
||||||
*/
|
*/
|
||||||
|
@ -213,8 +227,7 @@ static int aarch64_init_debug_access(struct target *target)
|
||||||
|
|
||||||
/* Clear Sticky Power Down status Bit in PRSR to enable access to
|
/* Clear Sticky Power Down status Bit in PRSR to enable access to
|
||||||
the registers in the Core Power Domain */
|
the registers in the Core Power Domain */
|
||||||
retval = mem_ap_read_atomic_u32(armv8->debug_ap,
|
retval = aarch64_read_prsr(target, &dummy);
|
||||||
armv8->debug_base + CPUV8_DBG_PRSR, &dummy);
|
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
|
@ -281,12 +294,10 @@ static int aarch64_set_dscr_bits(struct target *target, unsigned long bit_mask,
|
||||||
static int aarch64_check_state_one(struct target *target,
|
static int aarch64_check_state_one(struct target *target,
|
||||||
uint32_t mask, uint32_t val, int *p_result, uint32_t *p_prsr)
|
uint32_t mask, uint32_t val, int *p_result, uint32_t *p_prsr)
|
||||||
{
|
{
|
||||||
struct armv8_common *armv8 = target_to_armv8(target);
|
|
||||||
uint32_t prsr;
|
uint32_t prsr;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
retval = mem_ap_read_atomic_u32(armv8->debug_ap,
|
retval = aarch64_read_prsr(target, &prsr);
|
||||||
armv8->debug_base + CPUV8_DBG_PRSR, &prsr);
|
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
|
@ -506,16 +517,28 @@ static int update_halt_gdb(struct target *target, enum target_debug_reason debug
|
||||||
|
|
||||||
static int aarch64_poll(struct target *target)
|
static int aarch64_poll(struct target *target)
|
||||||
{
|
{
|
||||||
|
struct armv8_common *armv8 = target_to_armv8(target);
|
||||||
enum target_state prev_target_state;
|
enum target_state prev_target_state;
|
||||||
int retval = ERROR_OK;
|
int retval = ERROR_OK;
|
||||||
int halted;
|
uint32_t prsr;
|
||||||
|
|
||||||
retval = aarch64_check_state_one(target,
|
retval = aarch64_read_prsr(target, &prsr);
|
||||||
PRSR_HALT, PRSR_HALT, &halted, NULL);
|
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
if (halted) {
|
if (armv8->sticky_reset) {
|
||||||
|
armv8->sticky_reset = false;
|
||||||
|
if (target->state != TARGET_RESET) {
|
||||||
|
target->state = TARGET_RESET;
|
||||||
|
LOG_TARGET_INFO(target, "external reset detected");
|
||||||
|
if (armv8->arm.core_cache) {
|
||||||
|
register_cache_invalidate(armv8->arm.core_cache);
|
||||||
|
register_cache_invalidate(armv8->arm.core_cache->next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prsr & PRSR_HALT) {
|
||||||
prev_target_state = target->state;
|
prev_target_state = target->state;
|
||||||
if (prev_target_state != TARGET_HALTED) {
|
if (prev_target_state != TARGET_HALTED) {
|
||||||
enum target_debug_reason debug_reason = target->debug_reason;
|
enum target_debug_reason debug_reason = target->debug_reason;
|
||||||
|
@ -546,8 +569,11 @@ static int aarch64_poll(struct target *target)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else
|
} else if (prsr & PRSR_RESET) {
|
||||||
|
target->state = TARGET_RESET;
|
||||||
|
} else {
|
||||||
target->state = TARGET_RUNNING;
|
target->state = TARGET_RUNNING;
|
||||||
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
@ -663,8 +689,7 @@ static int aarch64_prepare_restart_one(struct target *target)
|
||||||
|
|
||||||
if (retval == ERROR_OK) {
|
if (retval == ERROR_OK) {
|
||||||
/* clear sticky bits in PRSR, SDR is now 0 */
|
/* clear sticky bits in PRSR, SDR is now 0 */
|
||||||
retval = mem_ap_read_atomic_u32(armv8->debug_ap,
|
retval = aarch64_read_prsr(target, &tmp);
|
||||||
armv8->debug_base + CPUV8_DBG_PRSR, &tmp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
|
|
|
@ -213,6 +213,8 @@ struct armv8_common {
|
||||||
/* True if OpenOCD provides pointer auth related info to GDB */
|
/* True if OpenOCD provides pointer auth related info to GDB */
|
||||||
bool enable_pauth;
|
bool enable_pauth;
|
||||||
|
|
||||||
|
bool sticky_reset;
|
||||||
|
|
||||||
/* last run-control command issued to this target (resume, halt, step) */
|
/* last run-control command issued to this target (resume, halt, step) */
|
||||||
enum run_control_op last_run_control_op;
|
enum run_control_op last_run_control_op;
|
||||||
|
|
||||||
|
|
|
@ -357,8 +357,8 @@ static void select_dmi(struct target *target)
|
||||||
select_dmi_via_bscan(target);
|
select_dmi_via_bscan(target);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (buf_cmp(target->tap->cur_instr, select_dbus.out_value,
|
if (buf_eq(target->tap->cur_instr, select_dbus.out_value,
|
||||||
target->tap->ir_length) == 0)
|
target->tap->ir_length))
|
||||||
return;
|
return;
|
||||||
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
|
jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue