rtos: add support for NuttX 03/4103/16
authorMasatoshi Tateishi <Masatoshi.Tateishi@jp.sony.com>
Sun, 9 Apr 2017 23:48:44 +0000 (08:48 +0900)
committerTomas Vanek <vanekt@fbl.cz>
Wed, 1 Aug 2018 13:33:50 +0000 (14:33 +0100)
This patch introduces RTOS support for NuttX. Currently,
only ARM Cortex-M (both FPU and FPU-less) targets are supported.

To use, add the following lines to ~/.gdbinit.

define hookpost-file
  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

And please make sure the above values are the same as in
src/rtos/nuttx_header.h

Change-Id: I2aaf8644d24dfb84b500516a9685382d5d8fe48f
Signed-off-by: Masayuki Ishikawa <Masayuki.Ishikawa@jp.sony.com>
Signed-off-by: Masatoshi Tateishi <Masatoshi.Tateishi@jp.sony.com>
Signed-off-by: Nobuto Kobayashi <Nobuto.Kobayashi@sony.com>
Reviewed-on: http://openocd.zylin.com/4103
Tested-by: jenkins
Reviewed-by: Alan Carvalho de Assis <acassis@gmail.com>
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
doc/openocd.texi
src/rtos/Makefile.am
src/rtos/nuttx.c [new file with mode: 0644]
src/rtos/nuttx_header.h [new file with mode: 0644]
src/rtos/rtos.c

index def0c9d6c5f31b84119c9800d3f58ea198280364..1a89a53de30059471a7305f991e91ab343827708 100644 (file)
@@ -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
index c59ee3f8c7b430952202375a561abce0326c6516..c8c402303291224949b4fc895531b7c938fe66a8 100644 (file)
@@ -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 (file)
index 0000000..284b968
--- /dev/null
@@ -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 (file)
index 0000000..00b0484
--- /dev/null
@@ -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 */
index 1fee5b084be93ff96dba148c11356e28e38342f7..1b3a47f9c77c14dc333fc33ecde21450708b00e5 100644 (file)
@@ -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
 };
 

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)