jtag: linuxgpiod: drop extra parenthesis
[openocd.git] / src / rtos / nuttx.c
index 993ff84bde8119c4c478941faf1e2ff2b661b2ec..0616af0f4c2f65c407ceb083b8eb306854bc263a 100644 (file)
 #include "rtos.h"
 #include "helper/log.h"
 #include "helper/types.h"
-#include "server/gdb_server.h"
-
-#include "nuttx_header.h"
+#include "target/register.h"
 #include "rtos_nuttx_stackings.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 NAME_SIZE       32
+#define EXTRAINFO_SIZE  256
 
+/* Only 32-bit CPUs are supported by the current implementation.  Supporting
+ * other CPUs will require reading this information from the target and
+ * adapting the code accordingly.
+ */
+#define PTR_WIDTH 4
 
-#define TASK_QUEUE_NUM (6 + SIG_QUEUE_NUM + M_QUEUE_NUM + PAGING_QUEUE_NUM)
+struct nuttx_params {
+       const char *target_name;
+       const struct rtos_register_stacking *stacking;
+       const struct rtos_register_stacking *(*select_stackinfo)(struct target *target);
+};
 
+/*
+ * struct tcbinfo_s is located in the sched.h
+ * https://github.com/apache/nuttx/blob/master/include/nuttx/sched.h
+ */
+#define TCBINFO_TARGET_SIZE 22
+struct tcbinfo {
+       uint16_t pid_off;                       /* Offset of tcb.pid                */
+       uint16_t state_off;                     /* Offset of tcb.task_state         */
+       uint16_t pri_off;                       /* Offset of tcb.sched_priority     */
+       uint16_t name_off;                      /* Offset of tcb.name               */
+       uint16_t regs_off;                      /* Offset of tcb.regs               */
+       uint16_t basic_num;                     /* Num of genernal regs             */
+       uint16_t total_num;                     /* Num of regs in tcbinfo.reg_offs  */
+       target_addr_t xcpreg_off;       /* Offset pointer of xcp.regs       */
+};
 
-/* see nuttx/sched/os_start.c */
-static char *nuttx_symbol_list[] = {
-       "g_readytorun",            /* 0: must be top of this array */
-       "g_tasklisttable",
-       NULL
+struct symbols {
+       const char *name;
+       bool optional;
 };
 
-/* see nuttx/include/nuttx/sched.h */
-struct tcb {
-       uint32_t flink;
-       uint32_t blink;
-       uint8_t  dat[512];
+/* 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 struct {
-       uint32_t addr;
-       uint32_t prio;
-} g_tasklist[TASK_QUEUE_NUM];
+static const struct symbols nuttx_symbol_list[] = {
+       { "g_readytorun", false },
+       { "g_pidhash", false },
+       { "g_npidhash", false },
+       { "g_tcbinfo", false },
+       { NULL, false }
+};
 
 static char *task_state_str[] = {
        "INVALID",
@@ -73,261 +80,363 @@ static char *task_state_str[] = {
        "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 */
+       "STOPPED",
 };
 
-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 const struct rtos_register_stacking *cortexm_select_stackinfo(struct target *target);
+
+static const struct nuttx_params nuttx_params_list[] = {
+       {
+               .target_name = "cortex_m",
+               .stacking = NULL,
+               .select_stackinfo = cortexm_select_stackinfo,
+       },
+       {
+               .target_name = "hla_target",
+               .stacking = NULL,
+               .select_stackinfo = cortexm_select_stackinfo,
+       },
+       {
+               .target_name = "esp32",
+               .stacking = &nuttx_esp32_stacking,
+       },
+       {
+               .target_name = "esp32s2",
+               .stacking = &nuttx_esp32s2_stacking,
+       },
+       {
+               .target_name = "esp32s3",
+               .stacking = &nuttx_esp32s3_stacking,
+       },
+       {
+               .target_name = "esp32c3",
+               .stacking = &nuttx_riscv_stacking,
+       },
+};
 
-static int rcmd_offset(const char *cmd, const char *name)
+static bool cortexm_hasfpu(struct target *target)
 {
-       if (strncmp(cmd, name, strlen(name)))
-               return -1;
+       uint32_t cpacr;
+       struct armv7m_common *armv7m_target = target_to_armv7m(target);
 
-       if (strlen(cmd) <= strlen(name) + 1)
-               return -1;
+       if (!is_armv7m(armv7m_target) || armv7m_target->fp_feature == FP_NONE)
+               return false;
 
-       return atoi(cmd + strlen(name));
+       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 int nuttx_thread_packet(struct connection *connection,
-       char const *packet, int packet_size)
+static const struct rtos_register_stacking *cortexm_select_stackinfo(struct target *target)
 {
-       char cmd[GDB_BUFFER_SIZE / 2 + 1] = ""; /* Extra byte for null-termination */
-
-       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");
+       return cortexm_hasfpu(target) ? &nuttx_stacking_cortex_m_fpu : &nuttx_stacking_cortex_m;
+}
 
-               if (offset >= 0) {
-                       LOG_INFO("state_offset: %d", offset);
-                       state_offset = offset;
-                       goto retok;
-               }
+static bool nuttx_detect_rtos(struct target *target)
+{
+       if (target->rtos->symbols &&
+               target->rtos->symbols[NX_SYM_READYTORUN].address != 0 &&
+               target->rtos->symbols[NX_SYM_PIDHASH].address != 0)
+               return true;
+       return false;
+}
 
-               offset = rcmd_offset(cmd, "nuttx.name_offset");
+static int nuttx_create(struct target *target)
+{
+       const struct nuttx_params *param;
+       unsigned int i;
 
-               if (offset >= 0) {
-                       LOG_INFO("name_offset: %d", offset);
-                       name_offset = offset;
-                       goto retok;
+       for (i = 0; i < ARRAY_SIZE(nuttx_params_list); i++) {
+               param = &nuttx_params_list[i];
+               if (strcmp(target_type_name(target), param->target_name) == 0) {
+                       LOG_INFO("Detected target \"%s\"", param->target_name);
+                       break;
                }
+       }
 
-               offset = rcmd_offset(cmd, "nuttx.xcpreg_offset");
-
-               if (offset >= 0) {
-                       LOG_INFO("xcpreg_offset: %d", offset);
-                       xcpreg_offset = offset;
-                       goto retok;
-               }
+       if (i >= ARRAY_SIZE(nuttx_params_list)) {
+               LOG_ERROR("Could not find \"%s\" target in NuttX compatibility list", target_type_name(target));
+               return JIM_ERR;
+       }
 
-               offset = rcmd_offset(cmd, "nuttx.name_size");
+       /* We found a target in our list, copy its reference. */
+       target->rtos->rtos_specific_params = (void *)param;
 
-               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;
+       return JIM_OK;
 }
 
-
-static bool nuttx_detect_rtos(struct target *target)
+static int nuttx_smp_init(struct target *target)
 {
-       if ((target->rtos->symbols) &&
-                       (target->rtos->symbols[0].address != 0) &&
-                       (target->rtos->symbols[1].address != 0)) {
-               return true;
-       }
-       return false;
+       /* Return OK for now so that the initialisation sequence doesn't stop.
+        * SMP case will be implemented later. */
+       return ERROR_OK;
 }
 
-static int nuttx_create(struct target *target)
+static target_addr_t target_buffer_get_addr(struct target *target, const uint8_t *buffer)
 {
-
-       target->rtos->gdb_thread_packet = nuttx_thread_packet;
-       LOG_INFO("target type name = %s", target->type->name);
-       return 0;
+#if PTR_WIDTH == 8
+       return target_buffer_get_u64(target, buffer);
+#else
+       return target_buffer_get_u32(target, buffer);
+#endif
 }
 
 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;
+       struct tcbinfo tcbinfo;
+       uint32_t pidhashaddr, npidhash, tcbaddr;
+       uint16_t pid;
        uint8_t state;
 
        if (!rtos->symbols) {
-               LOG_ERROR("No symbols for NuttX");
-               return -3;
+               LOG_ERROR("No symbols for nuttx");
+               return ERROR_FAIL;
        }
 
-       /* free previous thread details */
+       /* 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);
+       /* NuttX provides a hash table that keeps track of all the TCBs.
+        * We first read its size from g_npidhash and its address from g_pidhash.
+        * Its content is then read from these values.
+        */
+       int ret = target_read_u32(rtos->target, rtos->symbols[NX_SYM_NPIDHASH].address, &npidhash);
+       if (ret != ERROR_OK) {
+               LOG_ERROR("Failed to read g_npidhash: ret = %d", ret);
                return ERROR_FAIL;
        }
 
-       thread_count = 0;
+       LOG_DEBUG("Hash table size (g_npidhash) = %" PRId32, npidhash);
+
+       ret = target_read_u32(rtos->target, rtos->symbols[NX_SYM_PIDHASH].address, &pidhashaddr);
+       if (ret != ERROR_OK) {
+               LOG_ERROR("Failed to read g_pidhash address: ret = %d", ret);
+               return ERROR_FAIL;
+       }
 
-       for (i = 0; i < TASK_QUEUE_NUM; i++) {
+       LOG_DEBUG("Hash table address (g_pidhash) = %" PRIx32, pidhashaddr);
+
+       uint8_t *pidhash = malloc(npidhash * PTR_WIDTH);
+       if (!pidhash) {
+               LOG_ERROR("Failed to allocate pidhash");
+               return ERROR_FAIL;
+       }
 
-               if (g_tasklist[i].addr == 0)
+       ret = target_read_buffer(rtos->target, pidhashaddr, PTR_WIDTH * npidhash, pidhash);
+       if (ret != ERROR_OK) {
+               LOG_ERROR("Failed to read tcbhash: ret = %d", ret);
+               goto errout;
+       }
+
+       /* NuttX provides a struct that contains TCB offsets for required members.
+        * Read its content from g_tcbinfo.
+        */
+       uint8_t buff[TCBINFO_TARGET_SIZE];
+       ret = target_read_buffer(rtos->target, rtos->symbols[NX_SYM_TCB_INFO].address, sizeof(buff), buff);
+       if (ret != ERROR_OK) {
+               LOG_ERROR("Failed to read tcbinfo: ret = %d", ret);
+               goto errout;
+       }
+       tcbinfo.pid_off = target_buffer_get_u16(rtos->target, buff);
+       tcbinfo.state_off = target_buffer_get_u16(rtos->target, buff + 2);
+       tcbinfo.pri_off = target_buffer_get_u16(rtos->target, buff + 4);
+       tcbinfo.name_off = target_buffer_get_u16(rtos->target, buff + 6);
+       tcbinfo.regs_off = target_buffer_get_u16(rtos->target, buff + 8);
+       tcbinfo.basic_num = target_buffer_get_u16(rtos->target, buff + 10);
+       tcbinfo.total_num = target_buffer_get_u16(rtos->target, buff + 12);
+       tcbinfo.xcpreg_off = target_buffer_get_addr(rtos->target, buff + 14);
+
+       /* The head of the g_readytorun list is the currently running task.
+        * Reading in a temporary variable first to avoid endianness issues,
+        * rtos->current_thread is int64_t. */
+       uint32_t current_thread;
+       ret = target_read_u32(rtos->target, rtos->symbols[NX_SYM_READYTORUN].address, &current_thread);
+       if (ret != ERROR_OK) {
+               LOG_ERROR("Failed to read g_readytorun: ret = %d", ret);
+               goto errout;
+       }
+       rtos->current_thread = current_thread;
+
+       uint32_t thread_count = 0;
+
+       for (unsigned int i = 0; i < npidhash; i++) {
+               tcbaddr = target_buffer_get_u32(rtos->target, &pidhash[i * PTR_WIDTH]);
+
+               if (!tcbaddr)
                        continue;
 
-               ret = target_read_u32(rtos->target, g_tasklist[i].addr,
-                       &head);
+               ret = target_read_u16(rtos->target, tcbaddr + tcbinfo.pid_off, &pid);
+               if (ret != ERROR_OK) {
+                       LOG_ERROR("Failed to read PID of TCB@0x%x from pidhash[%d]: ret = %d",
+                               tcbaddr, i, ret);
+                       goto errout;
+               }
 
-               if (ret) {
-                       LOG_ERROR("target_read_u32 : ret = %d\n", ret);
-                       return ERROR_FAIL;
+               ret = target_read_u8(rtos->target, tcbaddr + tcbinfo.state_off, &state);
+               if (ret != ERROR_OK) {
+                       LOG_ERROR("Failed to read state of TCB@0x%x from pidhash[%d]: ret = %d",
+                               tcbaddr, i, ret);
+                       goto errout;
                }
 
-               /* readytorun head is current thread */
-               if (g_tasklist[i].addr == rtos->symbols[0].address)
-                       rtos->current_thread = head;
+               struct thread_detail *new_thread_details = realloc(rtos->thread_details,
+                       sizeof(struct thread_detail) * (thread_count + 1));
+               if (!new_thread_details) {
+                       ret = ERROR_FAIL;
+                       goto errout;
+               }
 
+               struct thread_detail *thread = &new_thread_details[thread_count];
+               thread->threadid = tcbaddr;
+               thread->exists = true;
+               thread->extra_info_str = NULL;
 
-               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 < ARRAY_SIZE(task_state_str)) {
-                               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]);
-                       }
+               rtos->thread_details = new_thread_details;
+               thread_count++;
 
-                       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");
+               if (state < ARRAY_SIZE(task_state_str)) {
+                       thread->extra_info_str = malloc(EXTRAINFO_SIZE);
+                       if (!thread->extra_info_str) {
+                               ret = ERROR_FAIL;
+                               goto errout;
                        }
+                       snprintf(thread->extra_info_str, EXTRAINFO_SIZE, "pid:%d, %s",
+                               pid,
+                               task_state_str[state]);
+               }
 
-                       tcb_addr = tcb.flink;
+               if (tcbinfo.name_off) {
+                       thread->thread_name_str = calloc(NAME_SIZE + 1, sizeof(char));
+                       if (!thread->thread_name_str) {
+                               ret = ERROR_FAIL;
+                               goto errout;
+                       }
+                       ret = target_read_buffer(rtos->target, tcbaddr + tcbinfo.name_off,
+                               sizeof(char) * NAME_SIZE, (uint8_t *)thread->thread_name_str);
+                       if (ret != ERROR_OK) {
+                               LOG_ERROR("Failed to read thread's name: ret = %d", ret);
+                               goto errout;
+                       }
+               } else {
+                       thread->thread_name_str = strdup("None");
                }
        }
-       rtos->thread_count = thread_count;
 
-       return 0;
+       ret = ERROR_OK;
+       rtos->thread_count = thread_count;
+errout:
+       free(pidhash);
+       return ret;
 }
 
-
-/*
- * thread_id = tcb address;
- */
-static int nuttx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
+static int nuttx_getreg_current_thread(struct rtos *rtos,
        struct rtos_reg **reg_list, int *num_regs)
 {
-       int retval;
-
-       /* 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;
-                       }
+       struct reg **gdb_reg_list;
+
+       /* Registers for currently running thread are not on task's stack and
+        * should be retrieved from reg caches via target_get_gdb_reg_list */
+       int ret = target_get_gdb_reg_list(rtos->target, &gdb_reg_list, num_regs,
+               REG_CLASS_GENERAL);
+       if (ret != ERROR_OK) {
+               LOG_ERROR("target_get_gdb_reg_list failed %d", ret);
+               return ret;
+       }
 
-                       /* Check if CP10 and CP11 are set to full access. */
-                       if (cpacr & 0x00F00000) {
-                               /* Found target with enabled FPU */
-                               cm4_fpu_enabled = 1;
-                       }
+       *reg_list = calloc(*num_regs, sizeof(struct rtos_reg));
+       if (!(*reg_list)) {
+               LOG_ERROR("Failed to alloc memory for %d", *num_regs);
+               free(gdb_reg_list);
+               return ERROR_FAIL;
+       }
+
+       for (int i = 0; i < *num_regs; i++) {
+               (*reg_list)[i].number = gdb_reg_list[i]->number;
+               (*reg_list)[i].size = gdb_reg_list[i]->size;
+               memcpy((*reg_list)[i].value, gdb_reg_list[i]->value, ((*reg_list)[i].size + 7) / 8);
+       }
+
+       free(gdb_reg_list);
+
+       return ERROR_OK;
+}
+
+static int nuttx_getregs_fromstack(struct rtos *rtos, int64_t thread_id,
+       struct rtos_reg **reg_list, int *num_regs)
+{
+       uint16_t xcpreg_off;
+       uint32_t regsaddr;
+       const struct nuttx_params *priv = rtos->rtos_specific_params;
+       const struct rtos_register_stacking *stacking = priv->stacking;
+
+       if (!stacking) {
+               if (priv->select_stackinfo) {
+                       stacking = priv->select_stackinfo(rtos->target);
+               } else {
+                       LOG_ERROR("Can't find a way to get stacking info");
+                       return ERROR_FAIL;
                }
        }
 
-       const struct rtos_register_stacking *stacking;
-       if (cm4_fpu_enabled)
-               stacking = &nuttx_stacking_cortex_m_fpu;
-       else
-               stacking = &nuttx_stacking_cortex_m;
+       int ret = target_read_u16(rtos->target,
+               rtos->symbols[NX_SYM_TCB_INFO].address + offsetof(struct tcbinfo, regs_off),
+               &xcpreg_off);
+       if (ret != ERROR_OK) {
+               LOG_ERROR("Failed to read registers' offset: ret = %d", ret);
+               return ERROR_FAIL;
+       }
+
+       ret = target_read_u32(rtos->target, thread_id + xcpreg_off, &regsaddr);
+       if (ret != ERROR_OK) {
+               LOG_ERROR("Failed to read registers' address: ret = %d", ret);
+               return ERROR_FAIL;
+       }
 
-       return rtos_generic_stack_read(rtos->target, stacking,
-           (uint32_t)thread_id + xcpreg_offset, reg_list, num_regs);
+       return rtos_generic_stack_read(rtos->target, stacking, regsaddr, reg_list, num_regs);
 }
 
-static int nuttx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
+static int nuttx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
+       struct rtos_reg **reg_list, int *num_regs)
 {
-       unsigned int i;
+       if (!rtos) {
+               LOG_ERROR("NUTTX: out of memory");
+               return ERROR_FAIL;
+       }
+
+       if (thread_id == rtos->current_thread)
+               return nuttx_getreg_current_thread(rtos, reg_list, num_regs);
+       return nuttx_getregs_fromstack(rtos, thread_id, reg_list, num_regs);
+}
 
-       *symbol_list = (struct symbol_table_elem *) calloc(1,
-               sizeof(struct symbol_table_elem) * ARRAY_SIZE(nuttx_symbol_list));
+static int nuttx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
+{
+       *symbol_list = calloc(ARRAY_SIZE(nuttx_symbol_list), sizeof(**symbol_list));
+       if (!*symbol_list) {
+               LOG_ERROR("NUTTX: out of memory");
+               return ERROR_FAIL;
+       }
 
-       for (i = 0; i < ARRAY_SIZE(nuttx_symbol_list); i++)
-               (*symbol_list)[i].symbol_name = nuttx_symbol_list[i];
+       for (unsigned int i = 0; i < ARRAY_SIZE(nuttx_symbol_list); i++) {
+               (*symbol_list)[i].symbol_name = nuttx_symbol_list[i].name;
+               (*symbol_list)[i].optional = nuttx_symbol_list[i].optional;
+       }
 
-       return 0;
+       return ERROR_OK;
 }
 
-struct rtos_type nuttx_rtos = {
+const struct rtos_type nuttx_rtos = {
        .name = "nuttx",
        .detect_rtos = nuttx_detect_rtos,
        .create = nuttx_create,
+       .smp_init = nuttx_smp_init,
        .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,

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)