aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/openocd.texi5
-rw-r--r--src/rtos/Makefile.am4
-rw-r--r--src/rtos/nuttx.c405
-rw-r--r--src/rtos/nuttx_header.h71
-rw-r--r--src/rtos/rtos.c2
5 files changed, 485 insertions, 2 deletions
diff --git a/doc/openocd.texi b/doc/openocd.texi
index def0c9d..1a89a53 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -4441,7 +4441,7 @@ The value should normally correspond to a static mapping for the
@item @code{-rtos} @var{rtos_type} -- enable rtos support for target,
@var{rtos_type} can be one of @option{auto}, @option{eCos},
@option{ThreadX}, @option{FreeRTOS}, @option{linux}, @option{ChibiOS},
-@option{embKernel}, @option{mqx}, @option{uCOS-III}
+@option{embKernel}, @option{mqx}, @option{uCOS-III}, @option{nuttx}
@xref{gdbrtossupport,,RTOS Support}.
@item @code{-defer-examine} -- skip target examination at initial JTAG chain
@@ -9806,6 +9806,7 @@ Currently supported rtos's include:
@item @option{embKernel}
@item @option{mqx}
@item @option{uCOS-III}
+@item @option{nuttx}
@end itemize
@quotation Note
@@ -9841,6 +9842,8 @@ Rtos::sListSuspended, Rtos::sMaxPriorities, Rtos::sCurrentTaskCount.
_mqx_kernel_data, MQX_init_struct.
@item uC/OS-III symbols
OSRunning, OSTCBCurPtr, OSTaskDbgListPtr, OSTaskQty
+@item nuttx symbols
+g_readytorun, g_tasklisttable
@end table
For most RTOS supported the above symbols will be exported by default. However for
diff --git a/src/rtos/Makefile.am b/src/rtos/Makefile.am
index c59ee3f..c8c4023 100644
--- a/src/rtos/Makefile.am
+++ b/src/rtos/Makefile.am
@@ -15,6 +15,7 @@ noinst_LTLIBRARIES += %D%/librtos.la
%D%/embKernel.c \
%D%/mqx.c \
%D%/uCOS-III.c \
+ %D%/nuttx.c \
%D%/rtos.h \
%D%/rtos_standard_stackings.h \
%D%/rtos_ecos_stackings.h \
@@ -22,7 +23,8 @@ noinst_LTLIBRARIES += %D%/librtos.la
%D%/rtos_chibios_stackings.h \
%D%/rtos_embkernel_stackings.h \
%D%/rtos_mqx_stackings.h \
- %D%/rtos_ucos_iii_stackings.h
+ %D%/rtos_ucos_iii_stackings.h \
+ %D%/nuttx_header.h
%C%_librtos_la_CFLAGS = $(AM_CFLAGS)
diff --git a/src/rtos/nuttx.c b/src/rtos/nuttx.c
new file mode 100644
index 0000000..284b968
--- /dev/null
+++ b/src/rtos/nuttx.c
@@ -0,0 +1,405 @@
+/***************************************************************************
+ * Copyright 2016,2017 Sony Video & Sound Products Inc. *
+ * Masatoshi Tateishi - Masatoshi.Tateishi@jp.sony.com *
+ * Masayuki Ishikawa - Masayuki.Ishikawa@jp.sony.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/>. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <jtag/jtag.h>
+#include "target/target.h"
+#include "target/target_type.h"
+#include "target/armv7m.h"
+#include "target/cortex_m.h"
+#include "rtos.h"
+#include "helper/log.h"
+#include "helper/types.h"
+#include "server/gdb_server.h"
+
+#include "nuttx_header.h"
+
+
+int rtos_thread_packet(struct connection *connection, const char *packet, int packet_size);
+
+#ifdef CONFIG_DISABLE_SIGNALS
+#define SIG_QUEUE_NUM 0
+#else
+#define SIG_QUEUE_NUM 1
+#endif /* CONFIG_DISABLE_SIGNALS */
+
+#ifdef CONFIG_DISABLE_MQUEUE
+#define M_QUEUE_NUM 0
+#else
+#define M_QUEUE_NUM 2
+#endif /* CONFIG_DISABLE_MQUEUE */
+
+#ifdef CONFIG_PAGING
+#define PAGING_QUEUE_NUM 1
+#else
+#define PAGING_QUEUE_NUM 0
+#endif /* CONFIG_PAGING */
+
+
+#define TASK_QUEUE_NUM (6 + SIG_QUEUE_NUM + M_QUEUE_NUM + PAGING_QUEUE_NUM)
+
+
+/* see nuttx/sched/os_start.c */
+static char *nuttx_symbol_list[] = {
+ "g_readytorun", /* 0: must be top of this array */
+ "g_tasklisttable",
+ NULL
+};
+
+/* see nuttx/include/nuttx/sched.h */
+struct tcb {
+ uint32_t flink;
+ uint32_t blink;
+ uint8_t dat[512];
+};
+
+struct {
+ uint32_t addr;
+ uint32_t prio;
+} g_tasklist[TASK_QUEUE_NUM];
+
+static char *task_state_str[] = {
+ "INVALID",
+ "PENDING",
+ "READYTORUN",
+ "RUNNING",
+ "INACTIVE",
+ "WAIT_SEM",
+#ifndef CONFIG_DISABLE_SIGNALS
+ "WAIT_SIG",
+#endif /* CONFIG_DISABLE_SIGNALS */
+#ifndef CONFIG_DISABLE_MQUEUE
+ "WAIT_MQNOTEMPTY",
+ "WAIT_MQNOTFULL",
+#endif /* CONFIG_DISABLE_MQUEUE */
+#ifdef CONFIG_PAGING
+ "WAIT_PAGEFILL",
+#endif /* CONFIG_PAGING */
+};
+
+/* see arch/arm/include/armv7-m/irq_cmnvector.h */
+static const struct stack_register_offset nuttx_stack_offsets_cortex_m[] = {
+ { 0x28, 32 }, /* r0 */
+ { 0x2c, 32 }, /* r1 */
+ { 0x30, 32 }, /* r2 */
+ { 0x34, 32 }, /* r3 */
+ { 0x08, 32 }, /* r4 */
+ { 0x0c, 32 }, /* r5 */
+ { 0x10, 32 }, /* r6 */
+ { 0x14, 32 }, /* r7 */
+ { 0x18, 32 }, /* r8 */
+ { 0x1c, 32 }, /* r9 */
+ { 0x20, 32 }, /* r10 */
+ { 0x24, 32 }, /* r11 */
+ { 0x38, 32 }, /* r12 */
+ { 0, 32 }, /* sp */
+ { 0x3c, 32 }, /* lr */
+ { 0x40, 32 }, /* pc */
+ { 0x44, 32 }, /* xPSR */
+};
+
+
+static const struct rtos_register_stacking nuttx_stacking_cortex_m = {
+ 0x48, /* stack_registers_size */
+ -1, /* stack_growth_direction */
+ 17, /* num_output_registers */
+ 0, /* stack_alignment */
+ nuttx_stack_offsets_cortex_m /* register_offsets */
+};
+
+static const struct stack_register_offset nuttx_stack_offsets_cortex_m_fpu[] = {
+ { 0x6c, 32 }, /* r0 */
+ { 0x70, 32 }, /* r1 */
+ { 0x74, 32 }, /* r2 */
+ { 0x78, 32 }, /* r3 */
+ { 0x08, 32 }, /* r4 */
+ { 0x0c, 32 }, /* r5 */
+ { 0x10, 32 }, /* r6 */
+ { 0x14, 32 }, /* r7 */
+ { 0x18, 32 }, /* r8 */
+ { 0x1c, 32 }, /* r9 */
+ { 0x20, 32 }, /* r10 */
+ { 0x24, 32 }, /* r11 */
+ { 0x7c, 32 }, /* r12 */
+ { 0, 32 }, /* sp */
+ { 0x80, 32 }, /* lr */
+ { 0x84, 32 }, /* pc */
+ { 0x88, 32 }, /* xPSR */
+};
+
+static const struct rtos_register_stacking nuttx_stacking_cortex_m_fpu = {
+ 0x8c, /* stack_registers_size */
+ -1, /* stack_growth_direction */
+ 17, /* num_output_registers */
+ 0, /* stack_alignment */
+ nuttx_stack_offsets_cortex_m_fpu /* register_offsets */
+};
+
+static int pid_offset = PID;
+static int state_offset = STATE;
+static int name_offset = NAME;
+static int xcpreg_offset = XCPREG;
+static int name_size = NAME_SIZE;
+
+static int rcmd_offset(const char *cmd, const char *name)
+{
+ if (strncmp(cmd, name, strlen(name)))
+ return -1;
+
+ if (strlen(cmd) <= strlen(name) + 1)
+ return -1;
+
+ return atoi(cmd + strlen(name));
+}
+
+static int nuttx_thread_packet(struct connection *connection,
+ char const *packet, int packet_size)
+{
+ char cmd[GDB_BUFFER_SIZE / 2] = "";
+
+ if (!strncmp(packet, "qRcmd", 5)) {
+ size_t len = unhexify((uint8_t *)cmd, packet + 6, sizeof(cmd));
+ int offset;
+
+ if (len <= 0)
+ goto pass;
+
+ offset = rcmd_offset(cmd, "nuttx.pid_offset");
+
+ if (offset >= 0) {
+ LOG_INFO("pid_offset: %d", offset);
+ pid_offset = offset;
+ goto retok;
+ }
+
+ offset = rcmd_offset(cmd, "nuttx.state_offset");
+
+ if (offset >= 0) {
+ LOG_INFO("state_offset: %d", offset);
+ state_offset = offset;
+ goto retok;
+ }
+
+ offset = rcmd_offset(cmd, "nuttx.name_offset");
+
+ if (offset >= 0) {
+ LOG_INFO("name_offset: %d", offset);
+ name_offset = offset;
+ goto retok;
+ }
+
+ offset = rcmd_offset(cmd, "nuttx.xcpreg_offset");
+
+ if (offset >= 0) {
+ LOG_INFO("xcpreg_offset: %d", offset);
+ xcpreg_offset = offset;
+ goto retok;
+ }
+
+ offset = rcmd_offset(cmd, "nuttx.name_size");
+
+ if (offset >= 0) {
+ LOG_INFO("name_size: %d", offset);
+ name_size = offset;
+ goto retok;
+ }
+ }
+pass:
+ return rtos_thread_packet(connection, packet, packet_size);
+retok:
+ gdb_put_packet(connection, "OK", 2);
+ return ERROR_OK;
+}
+
+
+static bool nuttx_detect_rtos(struct target *target)
+{
+ if ((target->rtos->symbols != NULL) &&
+ (target->rtos->symbols[0].address != 0) &&
+ (target->rtos->symbols[1].address != 0)) {
+ return true;
+ }
+ return false;
+}
+
+static int nuttx_create(struct target *target)
+{
+
+ target->rtos->gdb_thread_packet = nuttx_thread_packet;
+ LOG_INFO("target type name = %s", target->type->name);
+ return 0;
+}
+
+static int nuttx_update_threads(struct rtos *rtos)
+{
+ uint32_t thread_count;
+ struct tcb tcb;
+ int ret;
+ uint32_t head;
+ uint32_t tcb_addr;
+ uint32_t i;
+ uint8_t state;
+
+ if (rtos->symbols == NULL) {
+ LOG_ERROR("No symbols for NuttX");
+ return -3;
+ }
+
+ /* free previous thread details */
+ rtos_free_threadlist(rtos);
+
+ ret = target_read_buffer(rtos->target, rtos->symbols[1].address,
+ sizeof(g_tasklist), (uint8_t *)&g_tasklist);
+ if (ret) {
+ LOG_ERROR("target_read_buffer : ret = %d\n", ret);
+ return ERROR_FAIL;
+ }
+
+ thread_count = 0;
+
+ for (i = 0; i < TASK_QUEUE_NUM; i++) {
+
+ if (g_tasklist[i].addr == 0)
+ continue;
+
+ ret = target_read_u32(rtos->target, g_tasklist[i].addr,
+ &head);
+
+ if (ret) {
+ LOG_ERROR("target_read_u32 : ret = %d\n", ret);
+ return ERROR_FAIL;
+ }
+
+ /* readytorun head is current thread */
+ if (g_tasklist[i].addr == rtos->symbols[0].address)
+ rtos->current_thread = head;
+
+
+ tcb_addr = head;
+ while (tcb_addr) {
+ struct thread_detail *thread;
+ ret = target_read_buffer(rtos->target, tcb_addr,
+ sizeof(tcb), (uint8_t *)&tcb);
+ if (ret) {
+ LOG_ERROR("target_read_buffer : ret = %d\n",
+ ret);
+ return ERROR_FAIL;
+ }
+ thread_count++;
+
+ rtos->thread_details = realloc(rtos->thread_details,
+ sizeof(struct thread_detail) * thread_count);
+ thread = &rtos->thread_details[thread_count - 1];
+ thread->threadid = tcb_addr;
+ thread->exists = true;
+
+ state = tcb.dat[state_offset - 8];
+ thread->extra_info_str = NULL;
+ if (state < sizeof(task_state_str)/sizeof(char *)) {
+ thread->extra_info_str = malloc(256);
+ snprintf(thread->extra_info_str, 256, "pid:%d, %s",
+ tcb.dat[pid_offset - 8] |
+ tcb.dat[pid_offset - 8 + 1] << 8,
+ task_state_str[state]);
+ }
+
+ if (name_offset) {
+ thread->thread_name_str = malloc(name_size + 1);
+ snprintf(thread->thread_name_str, name_size,
+ "%s", (char *)&tcb.dat[name_offset - 8]);
+ } else {
+ thread->thread_name_str = malloc(sizeof("None"));
+ strcpy(thread->thread_name_str, "None");
+ }
+
+ tcb_addr = tcb.flink;
+ }
+ }
+ rtos->thread_count = thread_count;
+
+ return 0;
+}
+
+
+/*
+ * thread_id = tcb address;
+ */
+static int nuttx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
+ char **hex_reg_list) {
+ int retval;
+
+ *hex_reg_list = NULL;
+
+ /* Check for armv7m with *enabled* FPU, i.e. a Cortex-M4F */
+ bool cm4_fpu_enabled = false;
+ struct armv7m_common *armv7m_target = target_to_armv7m(rtos->target);
+ if (is_armv7m(armv7m_target)) {
+ if (armv7m_target->fp_feature == FPv4_SP) {
+ /* Found ARM v7m target which includes a FPU */
+ uint32_t cpacr;
+
+ retval = target_read_u32(rtos->target, FPU_CPACR, &cpacr);
+ if (retval != ERROR_OK) {
+ LOG_ERROR("Could not read CPACR register to check FPU state");
+ return -1;
+ }
+
+ /* Check if CP10 and CP11 are set to full access. */
+ if (cpacr & 0x00F00000) {
+ /* Found target with enabled FPU */
+ cm4_fpu_enabled = 1;
+ }
+ }
+ }
+
+ const struct rtos_register_stacking *stacking;
+ if (cm4_fpu_enabled)
+ stacking = &nuttx_stacking_cortex_m_fpu;
+ else
+ stacking = &nuttx_stacking_cortex_m;
+
+ return rtos_generic_stack_read(rtos->target, stacking,
+ (uint32_t)thread_id + xcpreg_offset, hex_reg_list);
+}
+
+static int nuttx_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
+{
+ unsigned int i;
+
+ *symbol_list = (symbol_table_elem_t *) calloc(1,
+ sizeof(symbol_table_elem_t) * ARRAY_SIZE(nuttx_symbol_list));
+
+ for (i = 0; i < ARRAY_SIZE(nuttx_symbol_list); i++)
+ (*symbol_list)[i].symbol_name = nuttx_symbol_list[i];
+
+ return 0;
+}
+
+struct rtos_type nuttx_rtos = {
+ .name = "nuttx",
+ .detect_rtos = nuttx_detect_rtos,
+ .create = nuttx_create,
+ .update_threads = nuttx_update_threads,
+ .get_thread_reg_list = nuttx_get_thread_reg_list,
+ .get_symbol_list_to_lookup = nuttx_get_symbol_list_to_lookup,
+};
+
diff --git a/src/rtos/nuttx_header.h b/src/rtos/nuttx_header.h
new file mode 100644
index 0000000..00b0484
--- /dev/null
+++ b/src/rtos/nuttx_header.h
@@ -0,0 +1,71 @@
+/***************************************************************************
+ * Copyright 2016,2017 Sony Video & Sound Products Inc. *
+ * Masatoshi Tateishi - Masatoshi.Tateishi@jp.sony.com *
+ * Masayuki Ishikawa - Masayuki.Ishikawa@jp.sony.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_RTOS_NUTTX_HEADER_H
+#define OPENOCD_RTOS_NUTTX_HEADER_H
+
+/* gdb script to update the header file
+ according to kernel version and build option
+ before executing function awareness
+ kernel symbol must be loaded : symbol nuttx
+
+define awareness
+ set logging off
+ set logging file nuttx_header.h
+ set logging on
+
+ printf "#define PID %p\n",&((struct tcb_s *)(0))->pid
+ printf "#define XCPREG %p\n",&((struct tcb_s *)(0))->xcp.regs
+ printf "#define STATE %p\n",&((struct tcb_s *)(0))->task_state
+ printf "#define NAME %p\n",&((struct tcb_s *)(0))->name
+ printf "#define NAME_SIZE %d\n",sizeof(((struct tcb_s *)(0))->name)
+ end
+
+
+ OR ~/.gdbinit
+
+
+define hookpost-file
+
+ if &g_readytorun != 0
+ eval "monitor nuttx.pid_offset %d", &((struct tcb_s *)(0))->pid
+ eval "monitor nuttx.xcpreg_offset %d", &((struct tcb_s *)(0))->xcp.regs
+ eval "monitor nuttx.state_offset %d", &((struct tcb_s *)(0))->task_state
+ eval "monitor nuttx.name_offset %d", &((struct tcb_s *)(0))->name
+ eval "monitor nuttx.name_size %d", sizeof(((struct tcb_s *)(0))->name)
+ end
+
+end
+
+*/
+
+/* default offset */
+#define PID 0xc
+#define XCPREG 0x70
+#define STATE 0x19
+#define NAME 0xb8
+#define NAME_SIZE 32
+
+/* defconfig of nuttx */
+/* #define CONFIG_DISABLE_SIGNALS */
+#define CONFIG_DISABLE_MQUEUE
+/* #define CONFIG_PAGING */
+
+
+#endif /* OPENOCD_RTOS_NUTTX_HEADER_H */
diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c
index 1fee5b0..1b3a47f 100644
--- a/src/rtos/rtos.c
+++ b/src/rtos/rtos.c
@@ -35,6 +35,7 @@ extern struct rtos_type ChibiOS_rtos;
extern struct rtos_type embKernel_rtos;
extern struct rtos_type mqx_rtos;
extern struct rtos_type uCOS_III_rtos;
+extern struct rtos_type nuttx_rtos;
static struct rtos_type *rtos_types[] = {
&ThreadX_rtos,
@@ -45,6 +46,7 @@ static struct rtos_type *rtos_types[] = {
&embKernel_rtos,
&mqx_rtos,
&uCOS_III_rtos,
+ &nuttx_rtos,
NULL
};