1 // SPDX-License-Identifier: GPL-2.0-or-later
3 /***************************************************************************
4 * Copyright 2016,2017 Sony Video & Sound Products Inc. *
5 * Masatoshi Tateishi - Masatoshi.Tateishi@jp.sony.com *
6 * Masayuki Ishikawa - Masayuki.Ishikawa@jp.sony.com *
7 ***************************************************************************/
13 #include <jtag/jtag.h>
14 #include "target/target.h"
15 #include "target/target_type.h"
16 #include "target/armv7m.h"
17 #include "target/cortex_m.h"
19 #include "helper/log.h"
20 #include "helper/types.h"
21 #include "target/register.h"
22 #include "rtos_nuttx_stackings.h"
25 #define EXTRAINFO_SIZE 256
27 /* Only 32-bit CPUs are supported by the current implementation. Supporting
28 * other CPUs will require reading this information from the target and
29 * adapting the code accordingly.
34 const char *target_name
;
35 const struct rtos_register_stacking
*stacking
;
36 const struct rtos_register_stacking
*(*select_stackinfo
)(struct target
*target
);
40 * struct tcbinfo_s is located in the sched.h
41 * https://github.com/apache/nuttx/blob/master/include/nuttx/sched.h
43 #define TCBINFO_TARGET_SIZE 22
45 uint16_t pid_off
; /* Offset of tcb.pid */
46 uint16_t state_off
; /* Offset of tcb.task_state */
47 uint16_t pri_off
; /* Offset of tcb.sched_priority */
48 uint16_t name_off
; /* Offset of tcb.name */
49 uint16_t regs_off
; /* Offset of tcb.regs */
50 uint16_t basic_num
; /* Num of genernal regs */
51 uint16_t total_num
; /* Num of regs in tcbinfo.reg_offs */
52 target_addr_t xcpreg_off
; /* Offset pointer of xcp.regs */
60 /* Used to index the list of retrieved symbols. See nuttx_symbol_list for the order. */
61 enum nuttx_symbol_vals
{
62 NX_SYM_READYTORUN
= 0,
68 static const struct symbols nuttx_symbol_list
[] = {
69 { "g_readytorun", false },
70 { "g_pidhash", false },
71 { "g_npidhash", false },
72 { "g_tcbinfo", false },
76 static char *task_state_str
[] = {
90 static const struct rtos_register_stacking
*cortexm_select_stackinfo(struct target
*target
);
92 static const struct nuttx_params nuttx_params_list
[] = {
94 .target_name
= "cortex_m",
96 .select_stackinfo
= cortexm_select_stackinfo
,
99 .target_name
= "hla_target",
101 .select_stackinfo
= cortexm_select_stackinfo
,
104 .target_name
= "esp32",
105 .stacking
= &nuttx_esp32_stacking
,
108 .target_name
= "esp32s2",
109 .stacking
= &nuttx_esp32s2_stacking
,
112 .target_name
= "esp32s3",
113 .stacking
= &nuttx_esp32s3_stacking
,
116 .target_name
= "esp32c3",
117 .stacking
= &nuttx_riscv_stacking
,
121 static bool cortexm_hasfpu(struct target
*target
)
124 struct armv7m_common
*armv7m_target
= target_to_armv7m(target
);
126 if (!is_armv7m(armv7m_target
) || armv7m_target
->fp_feature
== FP_NONE
)
129 int retval
= target_read_u32(target
, FPU_CPACR
, &cpacr
);
130 if (retval
!= ERROR_OK
) {
131 LOG_ERROR("Could not read CPACR register to check FPU state");
135 return cpacr
& 0x00F00000;
138 static const struct rtos_register_stacking
*cortexm_select_stackinfo(struct target
*target
)
140 return cortexm_hasfpu(target
) ? &nuttx_stacking_cortex_m_fpu
: &nuttx_stacking_cortex_m
;
143 static bool nuttx_detect_rtos(struct target
*target
)
145 if (target
->rtos
->symbols
&&
146 target
->rtos
->symbols
[NX_SYM_READYTORUN
].address
!= 0 &&
147 target
->rtos
->symbols
[NX_SYM_PIDHASH
].address
!= 0)
152 static int nuttx_create(struct target
*target
)
154 const struct nuttx_params
*param
;
157 for (i
= 0; i
< ARRAY_SIZE(nuttx_params_list
); i
++) {
158 param
= &nuttx_params_list
[i
];
159 if (strcmp(target_type_name(target
), param
->target_name
) == 0) {
160 LOG_INFO("Detected target \"%s\"", param
->target_name
);
165 if (i
>= ARRAY_SIZE(nuttx_params_list
)) {
166 LOG_ERROR("Could not find \"%s\" target in NuttX compatibility list", target_type_name(target
));
170 /* We found a target in our list, copy its reference. */
171 target
->rtos
->rtos_specific_params
= (void *)param
;
176 static int nuttx_smp_init(struct target
*target
)
178 /* Return OK for now so that the initialisation sequence doesn't stop.
179 * SMP case will be implemented later. */
183 static target_addr_t
target_buffer_get_addr(struct target
*target
, const uint8_t *buffer
)
186 return target_buffer_get_u64(target
, buffer
);
188 return target_buffer_get_u32(target
, buffer
);
192 static int nuttx_update_threads(struct rtos
*rtos
)
194 struct tcbinfo tcbinfo
;
195 uint32_t pidhashaddr
, npidhash
, tcbaddr
;
199 if (!rtos
->symbols
) {
200 LOG_ERROR("No symbols for nuttx");
204 /* Free previous thread details */
205 rtos_free_threadlist(rtos
);
207 /* NuttX provides a hash table that keeps track of all the TCBs.
208 * We first read its size from g_npidhash and its address from g_pidhash.
209 * Its content is then read from these values.
211 int ret
= target_read_u32(rtos
->target
, rtos
->symbols
[NX_SYM_NPIDHASH
].address
, &npidhash
);
212 if (ret
!= ERROR_OK
) {
213 LOG_ERROR("Failed to read g_npidhash: ret = %d", ret
);
217 LOG_DEBUG("Hash table size (g_npidhash) = %" PRId32
, npidhash
);
219 ret
= target_read_u32(rtos
->target
, rtos
->symbols
[NX_SYM_PIDHASH
].address
, &pidhashaddr
);
220 if (ret
!= ERROR_OK
) {
221 LOG_ERROR("Failed to read g_pidhash address: ret = %d", ret
);
225 LOG_DEBUG("Hash table address (g_pidhash) = %" PRIx32
, pidhashaddr
);
227 uint8_t *pidhash
= malloc(npidhash
* PTR_WIDTH
);
229 LOG_ERROR("Failed to allocate pidhash");
233 ret
= target_read_buffer(rtos
->target
, pidhashaddr
, PTR_WIDTH
* npidhash
, pidhash
);
234 if (ret
!= ERROR_OK
) {
235 LOG_ERROR("Failed to read tcbhash: ret = %d", ret
);
239 /* NuttX provides a struct that contains TCB offsets for required members.
240 * Read its content from g_tcbinfo.
242 uint8_t buff
[TCBINFO_TARGET_SIZE
];
243 ret
= target_read_buffer(rtos
->target
, rtos
->symbols
[NX_SYM_TCB_INFO
].address
, sizeof(buff
), buff
);
244 if (ret
!= ERROR_OK
) {
245 LOG_ERROR("Failed to read tcbinfo: ret = %d", ret
);
248 tcbinfo
.pid_off
= target_buffer_get_u16(rtos
->target
, buff
);
249 tcbinfo
.state_off
= target_buffer_get_u16(rtos
->target
, buff
+ 2);
250 tcbinfo
.pri_off
= target_buffer_get_u16(rtos
->target
, buff
+ 4);
251 tcbinfo
.name_off
= target_buffer_get_u16(rtos
->target
, buff
+ 6);
252 tcbinfo
.regs_off
= target_buffer_get_u16(rtos
->target
, buff
+ 8);
253 tcbinfo
.basic_num
= target_buffer_get_u16(rtos
->target
, buff
+ 10);
254 tcbinfo
.total_num
= target_buffer_get_u16(rtos
->target
, buff
+ 12);
255 tcbinfo
.xcpreg_off
= target_buffer_get_addr(rtos
->target
, buff
+ 14);
257 /* The head of the g_readytorun list is the currently running task.
258 * Reading in a temporary variable first to avoid endianness issues,
259 * rtos->current_thread is int64_t. */
260 uint32_t current_thread
;
261 ret
= target_read_u32(rtos
->target
, rtos
->symbols
[NX_SYM_READYTORUN
].address
, ¤t_thread
);
262 if (ret
!= ERROR_OK
) {
263 LOG_ERROR("Failed to read g_readytorun: ret = %d", ret
);
266 rtos
->current_thread
= current_thread
;
268 uint32_t thread_count
= 0;
270 for (unsigned int i
= 0; i
< npidhash
; i
++) {
271 tcbaddr
= target_buffer_get_u32(rtos
->target
, &pidhash
[i
* PTR_WIDTH
]);
276 ret
= target_read_u16(rtos
->target
, tcbaddr
+ tcbinfo
.pid_off
, &pid
);
277 if (ret
!= ERROR_OK
) {
278 LOG_ERROR("Failed to read PID of TCB@0x%x from pidhash[%d]: ret = %d",
283 ret
= target_read_u8(rtos
->target
, tcbaddr
+ tcbinfo
.state_off
, &state
);
284 if (ret
!= ERROR_OK
) {
285 LOG_ERROR("Failed to read state of TCB@0x%x from pidhash[%d]: ret = %d",
290 struct thread_detail
*new_thread_details
= realloc(rtos
->thread_details
,
291 sizeof(struct thread_detail
) * (thread_count
+ 1));
292 if (!new_thread_details
) {
297 struct thread_detail
*thread
= &new_thread_details
[thread_count
];
298 thread
->threadid
= tcbaddr
;
299 thread
->exists
= true;
300 thread
->extra_info_str
= NULL
;
302 rtos
->thread_details
= new_thread_details
;
305 if (state
< ARRAY_SIZE(task_state_str
)) {
306 thread
->extra_info_str
= malloc(EXTRAINFO_SIZE
);
307 if (!thread
->extra_info_str
) {
311 snprintf(thread
->extra_info_str
, EXTRAINFO_SIZE
, "pid:%d, %s",
313 task_state_str
[state
]);
316 if (tcbinfo
.name_off
) {
317 thread
->thread_name_str
= calloc(NAME_SIZE
+ 1, sizeof(char));
318 if (!thread
->thread_name_str
) {
322 ret
= target_read_buffer(rtos
->target
, tcbaddr
+ tcbinfo
.name_off
,
323 sizeof(char) * NAME_SIZE
, (uint8_t *)thread
->thread_name_str
);
324 if (ret
!= ERROR_OK
) {
325 LOG_ERROR("Failed to read thread's name: ret = %d", ret
);
329 thread
->thread_name_str
= strdup("None");
334 rtos
->thread_count
= thread_count
;
340 static int nuttx_getreg_current_thread(struct rtos
*rtos
,
341 struct rtos_reg
**reg_list
, int *num_regs
)
343 struct reg
**gdb_reg_list
;
345 /* Registers for currently running thread are not on task's stack and
346 * should be retrieved from reg caches via target_get_gdb_reg_list */
347 int ret
= target_get_gdb_reg_list(rtos
->target
, &gdb_reg_list
, num_regs
,
349 if (ret
!= ERROR_OK
) {
350 LOG_ERROR("target_get_gdb_reg_list failed %d", ret
);
354 *reg_list
= calloc(*num_regs
, sizeof(struct rtos_reg
));
356 LOG_ERROR("Failed to alloc memory for %d", *num_regs
);
361 for (int i
= 0; i
< *num_regs
; i
++) {
362 (*reg_list
)[i
].number
= gdb_reg_list
[i
]->number
;
363 (*reg_list
)[i
].size
= gdb_reg_list
[i
]->size
;
364 memcpy((*reg_list
)[i
].value
, gdb_reg_list
[i
]->value
, ((*reg_list
)[i
].size
+ 7) / 8);
372 static int nuttx_getregs_fromstack(struct rtos
*rtos
, int64_t thread_id
,
373 struct rtos_reg
**reg_list
, int *num_regs
)
377 const struct nuttx_params
*priv
= rtos
->rtos_specific_params
;
378 const struct rtos_register_stacking
*stacking
= priv
->stacking
;
381 if (priv
->select_stackinfo
) {
382 stacking
= priv
->select_stackinfo(rtos
->target
);
384 LOG_ERROR("Can't find a way to get stacking info");
389 int ret
= target_read_u16(rtos
->target
,
390 rtos
->symbols
[NX_SYM_TCB_INFO
].address
+ offsetof(struct tcbinfo
, regs_off
),
392 if (ret
!= ERROR_OK
) {
393 LOG_ERROR("Failed to read registers' offset: ret = %d", ret
);
397 ret
= target_read_u32(rtos
->target
, thread_id
+ xcpreg_off
, ®saddr
);
398 if (ret
!= ERROR_OK
) {
399 LOG_ERROR("Failed to read registers' address: ret = %d", ret
);
403 return rtos_generic_stack_read(rtos
->target
, stacking
, regsaddr
, reg_list
, num_regs
);
406 static int nuttx_get_thread_reg_list(struct rtos
*rtos
, int64_t thread_id
,
407 struct rtos_reg
**reg_list
, int *num_regs
)
410 LOG_ERROR("NUTTX: out of memory");
414 if (thread_id
== rtos
->current_thread
)
415 return nuttx_getreg_current_thread(rtos
, reg_list
, num_regs
);
416 return nuttx_getregs_fromstack(rtos
, thread_id
, reg_list
, num_regs
);
419 static int nuttx_get_symbol_list_to_lookup(struct symbol_table_elem
*symbol_list
[])
421 *symbol_list
= calloc(ARRAY_SIZE(nuttx_symbol_list
), sizeof(**symbol_list
));
423 LOG_ERROR("NUTTX: out of memory");
427 for (unsigned int i
= 0; i
< ARRAY_SIZE(nuttx_symbol_list
); i
++) {
428 (*symbol_list
)[i
].symbol_name
= nuttx_symbol_list
[i
].name
;
429 (*symbol_list
)[i
].optional
= nuttx_symbol_list
[i
].optional
;
435 const struct rtos_type nuttx_rtos
= {
437 .detect_rtos
= nuttx_detect_rtos
,
438 .create
= nuttx_create
,
439 .smp_init
= nuttx_smp_init
,
440 .update_threads
= nuttx_update_threads
,
441 .get_thread_reg_list
= nuttx_get_thread_reg_list
,
442 .get_symbol_list_to_lookup
= nuttx_get_symbol_list_to_lookup
,
Linking to existing account procedure
If you already have an account and want to add another login method
you
MUST first sign in with your existing account and
then change URL to read
https://review.openocd.org/login/?link
to get to this page again but this time it'll work for linking. Thank you.
SSH host keys fingerprints
1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=.. |
|+o.. . |
|*.o . . |
|+B . . . |
|Bo. = o S |
|Oo.+ + = |
|oB=.* = . o |
| =+=.+ + E |
|. .=o . o |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)