rtos : linux awareness
authorMichel JAOUEN <michel.jaouen@stericsson.com>
Wed, 11 Jan 2012 09:59:29 +0000 (10:59 +0100)
committerØyvind Harboe <oyvindharboe@gmail.com>
Sun, 15 Jan 2012 22:17:16 +0000 (22:17 +0000)
Change-Id: I41294ccaa4a3cd253919c8b1b558205903bcb695
Signed-off-by: Michel JAOUEN <michel.jaouen@stericsson.com>
Reviewed-on: http://openocd.zylin.com/348
Tested-by: jenkins
Reviewed-by: Heythem Bouhaja <heythem.bouhaja-nonst@stericsson.com>
Reviewed-by: Øyvind Harboe <oyvindharboe@gmail.com>
src/rtos/Makefile.am
src/rtos/linux.c [new file with mode: 0644]
src/rtos/linux_header.h [new file with mode: 0644]
src/rtos/rtos.c

index 6f17a5f9396750d380ffa08d039b93fa1ef0af17..e341caf0abea7c3e2c2ca2b7a46a64de9d613b3d 100644 (file)
@@ -23,7 +23,7 @@ include $(top_srcdir)/common.mk
 METASOURCES = AUTO
 noinst_LTLIBRARIES = librtos.la
 noinst_HEADERS = rtos.h rtos_standard_stackings.h rtos_ecos_stackings.h 
-librtos_la_SOURCES = rtos.c rtos_standard_stackings.c rtos_ecos_stackings.c FreeRTOS.c ThreadX.c eCos.c
+librtos_la_SOURCES = rtos.c rtos_standard_stackings.c rtos_ecos_stackings.c FreeRTOS.c ThreadX.c eCos.c linux.c
 
 librtos_la_CFLAGS =
 if IS_MINGW
diff --git a/src/rtos/linux.c b/src/rtos/linux.c
new file mode 100644 (file)
index 0000000..2ea3312
--- /dev/null
@@ -0,0 +1,1602 @@
+/***************************************************************************
+ *   Copyright (C) 2011 by STEricsson                                      *
+ *   Heythem Bouhaja heythem.bouhaja@stericsson.com   : creation           *
+ *   Michel JAOUEN michel.jaouen@stericsson.com : adaptation to rtos       *
+ *                                                                         *
+ *   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, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <helper/time_support.h>
+#include <jtag/jtag.h>
+#include "target/target.h"
+#include "target/target_type.h"
+#include "helper/log.h"
+#include "rtos.h"
+#include "helper/log.h"
+#include "rtos_standard_stackings.h"
+#include <target/register.h>
+#include "server/gdb_server.h"
+
+#define LINUX_USER_KERNEL_BORDER 0xc0000000
+#include "linux_header.h"
+#define PHYS
+#define MAX_THREADS 200
+/*  specific task  */
+struct linux_os {
+       char *name;
+       uint32_t init_task_addr;
+       int thread_count;
+       int threadid_count;
+       int preupdtate_threadid_count;
+       int nr_cpus;
+       int threads_lookup;
+       int threads_needs_update;
+       struct current_thread *current_threads;
+       struct threads *thread_list;
+       /*  virt2phys parameter */
+       uint32_t phys_mask;
+       uint32_t phys_base;
+};
+
+struct current_thread {
+       int64_t threadid;
+       int32_t core_id;
+#ifdef PID_CHECK
+       uint32_t pid;
+#endif
+       uint32_t TS;
+       struct current_thread *next;
+};
+
+struct threads {
+       char name[17];
+       uint32_t base_addr;     /*  address to read magic */
+       uint32_t state;         /*  magic value : filled only at creation */
+       uint32_t pid;           /* linux pid : id for identifying a thread */
+       uint32_t oncpu;         /* content cpu number in current thread */
+       uint32_t asid;          /*  filled only at creation  */
+       int64_t threadid;
+       int status;             /* dead = 1 alive = 2 current = 3 alive and current */
+       /*  value that should not change during the live of a thread ? */
+       uint32_t thread_info_addr;      /*  contain latest thread_info_addr computed */
+       /*  retrieve from thread_info */
+       struct cpu_context *context;
+       struct threads *next;
+};
+
+struct cpu_context {
+       uint32_t R4;
+       uint32_t R5;
+       uint32_t R6;
+       uint32_t R7;
+       uint32_t R8;
+       uint32_t R9;
+       uint32_t IP;
+       uint32_t FP;
+       uint32_t SP;
+       uint32_t PC;
+       uint32_t preempt_count;
+};
+struct cpu_context *cpu_context_read(struct target *target, uint32_t base_addr,
+                                    uint32_t *info_addr);
+static int insert_into_threadlist(struct target *target, struct threads *t);
+
+static int linux_os_create(struct target *target);
+
+static int linux_os_dummy_update(struct rtos *rtos)
+{
+       /*  update is done only when thread request come */
+       /*  too many thread to do it on each stop */
+       return 0;
+}
+
+static int linux_compute_virt2phys(struct target *target, uint32_t address)
+{
+       struct linux_os *linux_os = (struct linux_os *)
+           target->rtos->rtos_specific_params;
+       uint32_t pa = 0;
+       int retval = target->type->virt2phys(target, address, &pa);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Cannot compute linux virt2phys translation");
+               /*  fixes default address  */
+               linux_os->phys_base = 0;
+               return ERROR_FAIL;
+       }
+
+       linux_os->init_task_addr = address;
+       address = address & linux_os->phys_mask;
+       linux_os->phys_base = pa - address;
+       return ERROR_OK;
+}
+
+static int linux_read_memory(struct target *target,
+                            uint32_t address, uint32_t size, uint32_t count,
+                            uint8_t *buffer)
+{
+#ifdef PHYS
+       struct linux_os *linux_os = (struct linux_os *)
+           target->rtos->rtos_specific_params;
+       uint32_t pa = (address & linux_os->phys_mask) + linux_os->phys_base;
+#endif
+       if (address < 0xc000000) {
+               LOG_ERROR("linux awareness : address in user space");
+               return ERROR_FAIL;
+       }
+#ifdef PHYS
+       target->type->read_phys_memory(target, pa, size, count, buffer);
+#endif
+       target->type->read_memory(target, address, size, count, buffer);
+       return ERROR_OK;
+}
+
+static char *reg_converter(char *buffer, void *reg, int size)
+{
+       int i;
+
+       for (i = 0; i < size; i++)
+               buffer += sprintf(buffer, "%02x", ((uint8_t *) reg)[i]);
+
+       return buffer;
+}
+
+int fill_buffer(struct target *target, uint32_t addr, uint8_t * buffer)
+{
+
+       if ((addr & 0xfffffffc) != addr)
+               LOG_INFO("unaligned address %x!!", addr);
+
+       int retval = linux_read_memory(target, addr, 4, 1, buffer);
+       return retval;
+
+}
+
+uint32_t get_buffer(struct target *target, const uint8_t *buffer)
+{
+       uint32_t value = 0;
+       const uint8_t *value_ptr = buffer;
+       value = target_buffer_get_u32(target, value_ptr);
+       return value;
+}
+
+static int linux_os_thread_reg_list(struct rtos *rtos,
+                                   int64_t thread_id, char **hex_reg_list)
+{
+       struct target *target = rtos->target;
+       struct linux_os *linux_os = (struct linux_os *)
+           target->rtos->rtos_specific_params;
+       int i = 0;
+       struct current_thread *tmp = linux_os->current_threads;
+       struct current_thread *next;
+       char *hex_string;
+       int found = 0;
+       int retval;
+       /*  check if a current thread is requested  */
+       next = tmp;
+
+       do {
+               if (next->threadid == thread_id)
+                       found = 1;
+               else
+                       next = next->next;
+       } while ((found == 0) && (next != tmp) && (next != NULL));
+
+       if (found == 1) {
+               /*  search target to perfom the access  */
+               struct reg **reg_list;
+               int reg_list_size, reg_packet_size = 0;
+               struct target_list *head;
+               head = target->head;
+               found = 0;
+               do {
+                       if (head->target->coreid == next->core_id) {
+
+                               target = head->target;
+                               found = 1;
+                       } else
+                               head = head->next;
+
+               } while ((head != (struct target_list *)NULL) && (found == 0));
+
+               if (found == 0) {
+                       LOG_ERROR
+                           ("current thread %" PRIx64": no target to perform access of core id %x",
+                            thread_id, next->core_id);
+                       return ERROR_FAIL;
+               }
+
+               /*LOG_INFO("thread %lx current on core %x",thread_id,
+                * target->coreid);*/
+               retval =
+                   target_get_gdb_reg_list(target, &reg_list, &reg_list_size);
+
+               if (retval != ERROR_OK)
+                       return retval;
+
+               for (i = 0; i < reg_list_size; i++)
+                       reg_packet_size += reg_list[i]->size;
+
+               *hex_reg_list = malloc(DIV_ROUND_UP(reg_packet_size, 8) * 2);
+
+               hex_string = *hex_reg_list;
+
+               for (i = 0; i < reg_list_size; i++) {
+                       if (!reg_list[i]->valid)
+                               reg_list[i]->type->get(reg_list[i]);
+
+                       hex_string = reg_converter(hex_string,
+                                                  reg_list[i]->value,
+                                                  (reg_list[i]->size) / 8);
+               }
+
+               free(reg_list);
+
+       } else {
+               struct threads *temp = linux_os->thread_list;
+               *hex_reg_list = (char *)calloc(1, 500 * sizeof(char));
+               hex_string = *hex_reg_list;
+
+               for (i = 0; i < 16; i++)
+                       hex_string += sprintf(hex_string, "%02x", 0);
+
+               while ((temp != NULL) &&
+                      (temp->threadid != target->rtos->current_threadid))
+                       temp = temp->next;
+
+               if (temp != NULL) {
+                       if (temp->context == NULL)
+                               temp->context = cpu_context_read(target,
+                                                                temp->
+                                                                base_addr,
+                                                                &temp->
+                                                                thread_info_addr);
+
+                       hex_string =
+                           reg_converter(hex_string, &temp->context->R4, 4);
+                       hex_string =
+                           reg_converter(hex_string, &temp->context->R5, 4);
+                       hex_string =
+                           reg_converter(hex_string, &temp->context->R6, 4);
+                       hex_string =
+                           reg_converter(hex_string, &temp->context->R7, 4);
+                       hex_string =
+                           reg_converter(hex_string, &temp->context->R8, 4);
+                       hex_string =
+                           reg_converter(hex_string, &temp->context->R9, 4);
+
+                       for (i = 0; i < 4; i++) /*R10 = 0x0 */
+                               hex_string += sprintf(hex_string, "%02x", 0);
+
+                       hex_string =
+                           reg_converter(hex_string, &temp->context->FP, 4);
+                       hex_string =
+                           reg_converter(hex_string, &temp->context->IP, 4);
+                       hex_string =
+                           reg_converter(hex_string, &temp->context->SP, 4);
+
+                       for (i = 0; i < 4; i++)
+                               hex_string += sprintf(hex_string, "%02x", 0);
+
+                       hex_string =
+                           reg_converter(hex_string, &temp->context->PC, 4);
+
+                       for (i = 0; i < 100; i++) {     /*100 */
+                               hex_string += sprintf(hex_string, "%02x", 0);
+                       }
+
+                       uint32_t cpsr = 0x00000000;
+                       hex_string = reg_converter(hex_string, &cpsr, 4);
+               }
+       }
+       return ERROR_OK;
+}
+
+static int linux_os_detect(struct target *target)
+{
+       LOG_INFO("should no be called");
+       return 0;
+}
+
+static int linux_os_smp_init(struct target *target);
+static int linux_os_clean(struct target *target);
+#define INIT_TASK 0
+static char *linux_symbol_list[] = {
+       "init_task",
+       NULL
+};
+
+static int linux_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[])
+{
+       unsigned int i;
+       *symbol_list = (symbol_table_elem_t *)
+           malloc(sizeof(symbol_table_elem_t) / sizeof(char *));
+
+       for (i = 0; i < sizeof(linux_symbol_list) / sizeof(char *); i++)
+               (*symbol_list)[i].symbol_name = linux_symbol_list[i];
+
+       return 0;
+}
+
+static char *linux_ps_command(struct target *target);
+
+const struct rtos_type Linux_os = {
+       .name = "linux",
+       .detect_rtos = linux_os_detect,
+       .create = linux_os_create,
+       .smp_init = linux_os_smp_init,
+       .update_threads = linux_os_dummy_update,
+       .get_thread_reg_list = linux_os_thread_reg_list,
+       .get_symbol_list_to_lookup = linux_get_symbol_list_to_lookup,
+       .clean = linux_os_clean,
+       .ps_command = linux_ps_command,
+};
+
+static int linux_thread_packet(struct connection *connection, char *packet,
+                              int packet_size);
+static void linux_identify_current_threads(struct target *target);
+
+#ifdef PID_CHECK
+int fill_task_pid(struct target *target, struct threads *t)
+{
+       uint32_t pid_addr = t->base_addr + PID;
+       uint8_t buffer[4];
+       int retval = fill_buffer(target, pid_addr, buffer);
+
+       if (retval == ERROR_OK) {
+               uint32_t val = get_buffer(target, buffer);
+               t->pid = val;
+       } else
+               LOG_ERROR("fill_task_pid: unable to read memory");
+
+       return retval;
+}
+#endif
+
+int fill_task(struct target *target, struct threads *t)
+{
+
+       int retval;
+       uint32_t pid_addr = t->base_addr + PID;
+       uint32_t mem_addr = t->base_addr + MEM;
+       uint32_t on_cpu = t->base_addr + ONCPU;
+       uint8_t *buffer = calloc(1, 4);
+       retval = fill_buffer(target, t->base_addr, buffer);
+
+       if (retval == ERROR_OK) {
+               uint32_t val = get_buffer(target, buffer);
+               t->state = val;
+       } else
+               LOG_ERROR("fill_task: unable to read memory");
+
+       retval = fill_buffer(target, pid_addr, buffer);
+
+       if (retval == ERROR_OK) {
+               uint32_t val = get_buffer(target, buffer);
+               t->pid = val;
+       } else
+               LOG_ERROR("fill task: unable to read memory");
+
+       retval = fill_buffer(target, on_cpu, buffer);
+
+       if (retval == ERROR_OK) {
+               uint32_t val = get_buffer(target, buffer);
+               t->oncpu = val;
+       } else
+               LOG_ERROR("fill task: unable to read memory");
+
+       retval = fill_buffer(target, mem_addr, buffer);
+
+       if (retval == ERROR_OK) {
+               uint32_t val = get_buffer(target, buffer);
+
+               if (val != 0) {
+                       uint32_t asid_addr = val + MM_CTX;
+                       retval = fill_buffer(target, asid_addr, buffer);
+
+                       if (retval == ERROR_OK) {
+                               val = get_buffer(target, buffer);
+                               t->asid = val;
+                       } else
+                               LOG_ERROR
+                                   ("fill task: unable to read memory -- ASID");
+               } else {
+                       t->asid = 0;
+               }
+       } else
+               LOG_ERROR("fill task: unable to read memory");
+
+       return retval;
+}
+
+int get_name(struct target *target, struct threads *t)
+{
+       int retval;
+       uint32_t full_name[4];
+       uint32_t comm = t->base_addr + COMM;
+       int i;
+
+       for (i = 0; i < 17; i++)
+               t->name[i] = 0;
+
+       retval = linux_read_memory(target, comm, 4, 4, (uint8_t *) full_name);
+
+       if (retval != ERROR_OK) {
+               LOG_ERROR("get_name: unable to read memory\n");
+               return ERROR_FAIL;
+       }
+
+       uint32_t raw_name = target_buffer_get_u32(target,
+                                                 (const uint8_t *)
+                                                 &full_name[0]);
+       t->name[3] = raw_name >> 24;
+       t->name[2] = raw_name >> 16;
+       t->name[1] = raw_name >> 8;
+       t->name[0] = raw_name;
+       raw_name =
+           target_buffer_get_u32(target, (const uint8_t *)&full_name[1]);
+       t->name[7] = raw_name >> 24;
+       t->name[6] = raw_name >> 16;
+       t->name[5] = raw_name >> 8;
+       t->name[4] = raw_name;
+       raw_name =
+           target_buffer_get_u32(target, (const uint8_t *)&full_name[2]);
+       t->name[11] = raw_name >> 24;
+       t->name[10] = raw_name >> 16;
+       t->name[9] = raw_name >> 8;
+       t->name[8] = raw_name;
+       raw_name =
+           target_buffer_get_u32(target, (const uint8_t *)&full_name[3]);
+       t->name[15] = raw_name >> 24;
+       t->name[14] = raw_name >> 16;
+       t->name[13] = raw_name >> 8;
+       t->name[12] = raw_name;
+       return ERROR_OK;
+
+}
+
+int get_current(struct target *target, int create)
+{
+       struct target_list *head;
+       head = target->head;
+       uint8_t *buf;
+       uint32_t val;
+       uint32_t ti_addr;
+       uint8_t *buffer = calloc(1, 4);
+       struct linux_os *linux_os = (struct linux_os *)
+           target->rtos->rtos_specific_params;
+       struct current_thread *ctt = linux_os->current_threads;
+
+       /*  invalid current threads content */
+       while (ctt != NULL) {
+               ctt->threadid = -1;
+               ctt->TS = 0xdeadbeef;
+               ctt = ctt->next;
+       }
+
+       while (head != (struct target_list *)NULL) {
+               struct reg **reg_list;
+               int reg_list_size;
+               int retval;
+
+               if (target_get_gdb_reg_list(head->target, &reg_list,
+                                                     &reg_list_size) !=
+                   ERROR_OK)
+                       return ERROR_TARGET_FAILURE;
+
+               if (!reg_list[13]->valid)
+                       reg_list[13]->type->get(reg_list[13]);
+
+               buf = reg_list[13]->value;
+               val = get_buffer(target, buf);
+               ti_addr = (val & 0xffffe000);
+               uint32_t TS_addr = ti_addr + 0xc;
+               retval = fill_buffer(target, TS_addr, buffer);
+
+               if (retval == ERROR_OK) {
+                       uint32_t TS = get_buffer(target, buffer);
+                       uint32_t cpu, on_cpu = TS + ONCPU;
+                       retval = fill_buffer(target, on_cpu, buffer);
+
+                       if (retval == ERROR_OK) {
+                               /*uint32_t cpu = get_buffer(target, buffer);*/
+                               struct current_thread *ct =
+                                   linux_os->current_threads;
+                               cpu = head->target->coreid;
+
+                               while ((ct != NULL)
+                                      && (ct->core_id != (int32_t) cpu)) {
+                                       ct = ct->next;
+                               }
+
+                               if ((ct != NULL) && (ct->TS == 0xdeadbeef))
+                                       ct->TS = TS;
+                               else
+                                       LOG_ERROR
+                                           ("error in linux current thread update");
+
+                               if (create) {
+                                       struct threads *t;
+                                       t = calloc(1, sizeof(struct threads));
+                                       t->base_addr = ct->TS;
+                                       fill_task(target, t);
+                                       get_name(target, t);
+                                       t->oncpu = cpu;
+                                       insert_into_threadlist(target, t);
+                                       t->status = 3;
+                                       t->thread_info_addr = 0xdeadbeef;
+                                       ct->threadid = t->threadid;
+                                       linux_os->thread_count++;
+#ifdef PID_CHECK
+                                       ct->pid = t->pid;
+#endif
+                                       /*LOG_INFO("Creation of current thread %s",t->name);*/
+                               }
+                       }
+               }
+
+               free(reg_list);
+               head = head->next;
+       }
+
+       return ERROR_OK;
+}
+
+struct cpu_context *cpu_context_read(struct target *target, uint32_t base_addr,
+                                    uint32_t *thread_info_addr_old)
+{
+       struct cpu_context *context = calloc(1, sizeof(struct cpu_context));
+       uint32_t preempt_count_addr = 0;
+       uint32_t registers[10];
+       uint8_t *buffer = calloc(1, 4);
+       uint32_t stack = base_addr + QAT;
+       uint32_t thread_info_addr = 0;
+       uint32_t thread_info_addr_update = 0;
+       int retval = ERROR_FAIL;
+       context->R4 = 0xdeadbeef;
+       context->R5 = 0xdeadbeef;
+       context->R6 = 0xdeadbeef;
+       context->R7 = 0xdeadbeef;
+       context->R8 = 0xdeadbeef;
+       context->R9 = 0xdeadbeef;
+       context->IP = 0xdeadbeef;
+       context->FP = 0xdeadbeef;
+       context->SP = 0xdeadbeef;
+       context->PC = 0xdeadbeef;
+retry:
+
+       if (*thread_info_addr_old == 0xdeadbeef) {
+               retval = fill_buffer(target, stack, buffer);
+
+               if (retval == ERROR_OK)
+                       thread_info_addr = get_buffer(target, buffer);
+               else
+                       LOG_ERROR("cpu_context: unable to read memory");
+
+               thread_info_addr_update = thread_info_addr;
+       } else
+               thread_info_addr = *thread_info_addr_old;
+
+       preempt_count_addr = thread_info_addr + PREEMPT;
+       retval = fill_buffer(target, preempt_count_addr, buffer);
+
+       if (retval == ERROR_OK)
+               context->preempt_count = get_buffer(target, buffer);
+       else {
+               if (*thread_info_addr_old != 0xdeadbeef) {
+                       LOG_ERROR
+                           ("cpu_context: cannot read at thread_info_addr");
+
+                       if (*thread_info_addr_old < LINUX_USER_KERNEL_BORDER)
+                               LOG_INFO
+                                   ("cpu_context : thread_info_addr in userspace!!!");
+
+                       *thread_info_addr_old = 0xdeadbeef;
+                       goto retry;
+               }
+
+               LOG_ERROR("cpu_context: unable to read memory");
+       }
+
+       thread_info_addr += CPU_CONT;
+
+       retval = linux_read_memory(target, thread_info_addr, 4, 10,
+                                  (uint8_t *) registers);
+
+       if (retval != ERROR_OK) {
+               LOG_ERROR("cpu_context: unable to read memory\n");
+               return context;
+       }
+
+       context->R4 =
+           target_buffer_get_u32(target, (const uint8_t *)&registers[0]);
+       context->R5 =
+           target_buffer_get_u32(target, (const uint8_t *)&registers[1]);
+       context->R6 =
+           target_buffer_get_u32(target, (const uint8_t *)&registers[2]);
+       context->R7 =
+           target_buffer_get_u32(target, (const uint8_t *)&registers[3]);
+       context->R8 =
+           target_buffer_get_u32(target, (const uint8_t *)&registers[4]);
+       context->R9 =
+           target_buffer_get_u32(target, (const uint8_t *)&registers[5]);
+       context->IP =
+           target_buffer_get_u32(target, (const uint8_t *)&registers[6]);
+       context->FP =
+           target_buffer_get_u32(target, (const uint8_t *)&registers[7]);
+       context->SP =
+           target_buffer_get_u32(target, (const uint8_t *)&registers[8]);
+       context->PC =
+           target_buffer_get_u32(target, (const uint8_t *)&registers[9]);
+
+       if (*thread_info_addr_old == 0xdeadbeef)
+               *thread_info_addr_old = thread_info_addr_update;
+
+       return context;
+}
+
+uint32_t next_task(struct target *target, struct threads *t)
+{
+       uint8_t *buffer = calloc(1, 4);
+       uint32_t next_addr = t->base_addr + NEXT;
+       int retval = fill_buffer(target, next_addr, buffer);
+
+       if (retval == ERROR_OK) {
+               uint32_t val = get_buffer(target, buffer);
+               val = val - NEXT;
+               return val;
+               free(buffer);
+       } else
+               LOG_ERROR("next task: unable to read memory");
+
+       return 0;
+}
+
+struct current_thread *add_current_thread(struct current_thread *currents,
+                                         struct current_thread *ct)
+{
+       ct->next = NULL;
+
+       if (currents == NULL) {
+               currents = ct;
+               return currents;
+       } else {
+               struct current_thread *temp = currents;
+
+               while (temp->next != NULL)
+                       temp = temp->next;
+
+               temp->next = ct;
+               return currents;
+       }
+}
+
+struct threads *liste_del_task(struct threads *task_list, struct threads **t,
+                              struct threads *prev)
+{
+       LOG_INFO("del task %" PRId64, (*t)->threadid);
+       prev->next = (*t)->next;
+
+       if (prev == task_list)
+               task_list = prev;
+
+       /*  free content of threads */
+       if ((*t)->context)
+               free((*t)->context);
+
+       free(*t);
+       *t = prev;
+       return task_list;
+}
+
+struct threads *liste_add_task(struct threads *task_list, struct threads *t,
+                              struct threads **last)
+{
+       t->next = NULL;
+
+       if (*last == NULL)
+               if (task_list == NULL) {
+                       task_list = t;
+                       return task_list;
+               } else {
+                       struct threads *temp = task_list;
+
+                       while (temp->next != NULL)
+                               temp = temp->next;
+
+                       temp->next = t;
+                       *last = t;
+                       return task_list;
+               } else {
+                       (*last)->next = t;
+                       *last = t;
+                       return task_list;
+               }
+}
+
+#ifdef PID_CHECK
+static int current_pid(struct linux_os *linux_os, uint32_t pid)
+#else
+static int current_base_addr(struct linux_os *linux_os, uint32_t base_addr)
+#endif
+{
+       struct current_thread *ct = linux_os->current_threads;
+#ifdef PID_CHECK
+
+       while ((ct != NULL) && (ct->pid != pid))
+#else
+       while ((ct != NULL) && (ct->TS != base_addr))
+#endif
+               ct = ct->next;
+#ifdef PID_CHECK
+       if ((ct != NULL) && (ct->pid == pid))
+#else
+       if ((ct != NULL) && (ct->TS == base_addr))
+#endif
+               return 1;
+
+       return 0;
+}
+
+int linux_get_tasks(struct target *target, int context)
+{
+       int loop = 0;
+       int retval = 0;
+       struct linux_os *linux_os = (struct linux_os *)
+           target->rtos->rtos_specific_params;
+       linux_os->thread_list = NULL;
+       linux_os->thread_count = 0;
+
+       if (linux_os->init_task_addr == 0xdeadbeef) {
+               LOG_INFO("no init symbol\n");
+               return ERROR_FAIL;
+       }
+
+       int64_t start = timeval_ms();
+
+       struct threads *t = calloc(1, sizeof(struct threads));
+       struct threads *last = NULL;
+       t->base_addr = linux_os->init_task_addr;
+       /* retrieve the thread id , currently running in the different smp core */
+       retval = get_current(target, 1);
+
+       while (((t->base_addr != linux_os->init_task_addr) &&
+               (t->base_addr != 0))
+              || (loop == 0)
+           ) {
+               loop++;
+               retval = fill_task(target, t);
+               retval = get_name(target, t);
+
+               if (loop > MAX_THREADS) {
+                       LOG_INFO("more than %d threads !!", MAX_THREADS);
+                       return ERROR_FAIL;
+               }
+
+               if (retval != ERROR_OK) {
+                       free(t);
+                       return ERROR_FAIL;
+               }
+
+               /*  check that this thread is not one the current threads already
+                *  created */
+#ifdef PID_CHECK
+
+               if (!current_pid(linux_os, t->pid)) {
+#else
+               if (!current_base_addr(linux_os, t->base_addr)) {
+#endif
+                       t->threadid = linux_os->threadid_count;
+                       t->status = 1;
+                       linux_os->threadid_count++;
+
+                       linux_os->thread_list =
+                           liste_add_task(linux_os->thread_list, t, &last);
+                       /* no interest to fill the context if it is a current thread. */
+                       linux_os->thread_count++;
+                       t->thread_info_addr = 0xdeadbeef;
+
+                       if (context)
+                               t->context =
+                                   cpu_context_read(target, t->base_addr,
+                                                    &t->thread_info_addr);
+               } else {
+                       /*LOG_INFO("thread %s is a current thread already created",t->name); */
+                       free(t);
+               }
+
+               uint32_t base_addr = next_task(target, t);
+               t = calloc(1, sizeof(struct threads));
+               t->base_addr = base_addr;
+       }
+
+       linux_os->threads_lookup = 1;
+       linux_os->threads_needs_update = 0;
+       linux_os->preupdtate_threadid_count = linux_os->threadid_count - 1;
+       /*  check that all current threads have been identified  */
+
+       LOG_INFO("complete time %" PRId64", thread mean %" PRId64"\n",
+                (timeval_ms() - start),
+                (timeval_ms() - start) / linux_os->threadid_count);
+
+       LOG_INFO("threadid count %d", linux_os->threadid_count);
+
+       return ERROR_OK;
+}
+
+static int clean_threadlist(struct target *target)
+{
+       struct linux_os *linux_os = (struct linux_os *)
+           target->rtos->rtos_specific_params;
+       struct threads *old, *temp = linux_os->thread_list;
+
+       while (temp != NULL) {
+               old = temp;
+
+               if (temp->context)
+                       free(temp->context);
+
+               temp = temp->next;
+               free(old);
+       }
+
+       return ERROR_OK;
+}
+
+static int linux_os_clean(struct target *target)
+{
+
+       struct linux_os *os_linux = (struct linux_os *)
+           target->rtos->rtos_specific_params;
+       clean_threadlist(target);
+       os_linux->init_task_addr = 0xdeadbeef;
+       os_linux->name = "linux";
+       os_linux->thread_list = NULL;
+       os_linux->thread_count = 0;
+       os_linux->nr_cpus = 0;
+       os_linux->threads_lookup = 0;
+       os_linux->threads_needs_update = 0;
+       os_linux->threadid_count = 1;
+       return ERROR_OK;
+}
+
+static int insert_into_threadlist(struct target *target, struct threads *t)
+{
+       struct linux_os *linux_os = (struct linux_os *)
+               target->rtos->rtos_specific_params;
+       struct threads *temp = linux_os->thread_list;
+       t->threadid = linux_os->threadid_count;
+       linux_os->threadid_count++;
+       t->status = 1;
+       t->next = NULL;
+
+       if (temp == NULL)
+               linux_os->thread_list = t;
+       else {
+               while (temp->next != NULL)
+                       temp = temp->next;
+
+               t->next = NULL;
+               temp->next = t;
+       }
+
+       return ERROR_OK;
+}
+
+static void linux_identify_current_threads(struct target *target)
+{
+       struct linux_os *linux_os = (struct linux_os *)
+           target->rtos->rtos_specific_params;
+       struct threads *thread_list = linux_os->thread_list;
+       struct current_thread *ct = linux_os->current_threads;
+       struct threads *t = NULL;
+
+       while ((ct != NULL)) {
+               if (ct->threadid == -1) {
+
+                       /*  un-identified thread */
+                       int found = 0;
+                       t = calloc(1, sizeof(struct threads));
+                       t->base_addr = ct->TS;
+#ifdef PID_CHECK
+
+                       if (fill_task_pid(target, t) != ERROR_OK) {
+error_handling:
+                               free(t);
+                               LOG_ERROR
+                                       ("linux identify_current_threads: unable to read pid");
+                               return;
+                       }
+#endif
+
+                       /* search in the list of threads if pid
+                          already present */
+                       while ((thread_list != NULL) && (found == 0)) {
+#ifdef PID_CHECK
+                               if (thread_list->pid == t->pid) {
+#else
+                                       if (thread_list->base_addr == t->base_addr) {
+#endif
+                                               free(t);
+                                               t = thread_list;
+                                               found = 1;
+                                       }
+                                       thread_list = thread_list->next;
+                               }
+
+                               if (!found) {
+                                       /*  it is a new thread */
+                                       if (fill_task(target, t) != ERROR_OK)
+                                               goto error_handling;
+
+                                       get_name(target, t);
+                                       insert_into_threadlist(target, t);
+                                       t->thread_info_addr = 0xdeadbeef;
+                               }
+
+                               t->status = 3;
+                               ct->threadid = t->threadid;
+#ifdef PID_CHECK
+                               ct->pid = t->pid;
+#endif
+                               linux_os->thread_count++;
+#if 0
+                               if (found == 0)
+                                       LOG_INFO("current thread core %x identified %s",
+                                                       ct->core_id, t->name);
+                               else
+                                       LOG_INFO("current thread core %x, reused %s",
+                                                       ct->core_id, t->name);
+#endif
+                       }
+#if 0
+                       else {
+                               struct threads tmp;
+                               tmp.base_addr = ct->TS;
+                               get_name(target, &tmp);
+                               LOG_INFO("current thread core %x , already identified %s !!!",
+                                               ct->core_id, tmp.name);
+                       }
+#endif
+                       ct = ct->next;
+               }
+
+               return;
+#ifndef PID_CHECK
+error_handling:
+               free(t);
+               LOG_ERROR("unable toread pid");
+               return;
+
+#endif
+       }
+
+static int linux_task_update(struct target *target, int context)
+{
+       struct linux_os *linux_os = (struct linux_os *)
+           target->rtos->rtos_specific_params;
+       struct threads *thread_list = linux_os->thread_list;
+       int retval;
+       int loop = 0;
+       linux_os->thread_count = 0;
+
+       /*thread_list = thread_list->next; skip init_task*/
+       while (thread_list != NULL) {
+               thread_list->status = 0;        /*setting all tasks to dead state*/
+
+               if (thread_list->context) {
+                       free(thread_list->context);
+                       thread_list->context = NULL;
+               }
+
+               thread_list = thread_list->next;
+
+       }
+
+       int found = 0;
+
+       if (linux_os->init_task_addr == 0xdeadbeef) {
+               LOG_INFO("no init symbol\n");
+               return ERROR_FAIL;
+       }
+       int64_t start = timeval_ms();
+       struct threads *t = calloc(1, sizeof(struct threads));
+       uint32_t previous = 0xdeadbeef;
+       t->base_addr = linux_os->init_task_addr;
+       retval = get_current(target, 0);
+    /*check that all current threads have been identified  */
+       linux_identify_current_threads(target);
+
+       while (((t->base_addr != linux_os->init_task_addr) &&
+               (t->base_addr != previous)) || (loop == 0)) {
+               /*  for avoiding any permanent loop for any reason possibly due to
+                *  target */
+               loop++;
+               previous = t->base_addr;
+               /*  read only pid */
+#ifdef PID_CHECK
+               retval = fill_task_pid(target, t);
+#endif
+
+               if (retval != ERROR_OK) {
+                       free(t);
+                       return ERROR_FAIL;
+               }
+
+               thread_list = linux_os->thread_list;
+
+               while (thread_list != NULL) {
+#ifdef PID_CHECK
+
+                       if (t->pid == thread_list->pid) {
+#else
+                       if (t->base_addr == thread_list->base_addr) {
+#endif
+
+                               if (!thread_list->status) {
+#ifdef PID_CHECK
+
+                                       if (t->base_addr !=
+                                           thread_list->base_addr) {
+                                               LOG_INFO
+                                                   ("thread base_addr has changed !!");
+                                       }
+#endif
+                                       /*  this is not a current thread  */
+                                       thread_list->base_addr = t->base_addr;
+                                       thread_list->status = 1;
+
+                                       /*  we don 't update this field any more */
+
+                                       /*thread_list->state = t->state;
+                                       thread_list->oncpu = t->oncpu;
+                                       thread_list->asid = t->asid;
+                                       */
+                                       if (context)
+                                               thread_list->context =
+                                                   cpu_context_read(target,
+                                                                    thread_list->
+                                                                    base_addr,
+                                                                    &thread_list->
+                                                                    thread_info_addr);
+                               } else {
+                                       /*  it is a current thread no need to read context */
+                               }
+
+                               linux_os->thread_count++;
+                               found = 1;
+                               break;
+                       } else {
+                               found = 0;
+                               thread_list = thread_list->next;
+                       }
+               }
+
+               if (found == 0) {
+                       uint32_t base_addr;
+                       fill_task(target, t);
+                       get_name(target, t);
+                       retval = insert_into_threadlist(target, t);
+                       t->thread_info_addr = 0xdeadbeef;
+
+                       if (context)
+                               t->context =
+                                   cpu_context_read(target, t->base_addr,
+                                                    &t->thread_info_addr);
+
+                       base_addr = next_task(target, t);
+                       t = calloc(1, sizeof(struct threads));
+                       t->base_addr = base_addr;
+                       linux_os->thread_count++;
+               } else
+                       t->base_addr = next_task(target, t);
+
+       }
+
+       LOG_INFO("update thread done %" PRId64", mean%" PRId64"\n",
+                (timeval_ms() - start), (timeval_ms() - start) / loop);
+       free(t);
+       linux_os->threads_needs_update = 0;
+       return ERROR_OK;
+}
+
+int linux_gdb_thread_packet(struct target *target,
+                           struct connection *connection, char *packet,
+                           int packet_size)
+{
+
+       int retval;
+       struct linux_os *linux_os =
+           (struct linux_os *)target->rtos->rtos_specific_params;
+
+       if (linux_os->init_task_addr == 0xdeadbeef) {
+               /* it has not been initialized */
+               LOG_INFO("received thread request without init task address");
+               gdb_put_packet(connection, "l", 1);
+               return ERROR_OK;
+       }
+
+       retval = linux_get_tasks(target, 1);
+
+       if (retval != ERROR_OK)
+               return ERROR_TARGET_FAILURE;
+
+       char *out_str = (char *)calloc(1, 350 * sizeof(int64_t));
+       char *tmp_str = out_str;
+       tmp_str += sprintf(tmp_str, "m");
+       struct threads *temp = linux_os->thread_list;
+       tmp_str += sprintf(tmp_str, "%016" PRIx64, temp->threadid);
+       temp = temp->next;
+
+       while (temp != NULL) {
+               tmp_str += sprintf(tmp_str, ",");
+               tmp_str += sprintf(tmp_str, "%016" PRIx64, temp->threadid);
+               temp = temp->next;
+       }
+
+       gdb_put_packet(connection, out_str, strlen(out_str));
+       return ERROR_OK;
+}
+
+int linux_gdb_thread_update(struct target *target,
+                           struct connection *connection, char *packet,
+                           int packet_size)
+{
+       int found = 0;
+       struct linux_os *linux_os = (struct linux_os *)
+           target->rtos->rtos_specific_params;
+       struct threads *temp = linux_os->thread_list;
+
+       while (temp != NULL) {
+               if (temp->threadid == linux_os->preupdtate_threadid_count + 1) {
+                       /*LOG_INFO("FOUND");*/
+                       found = 1;
+                       break;
+               } else
+                       temp = temp->next;
+       }
+
+       if (found == 1) {
+               /*LOG_INFO("INTO GDB THREAD UPDATE FOUNDING START TASK");*/
+               char *out_strr = (char *)calloc(1, 350 * sizeof(int64_t));
+               char *tmp_strr = out_strr;
+               tmp_strr += sprintf(tmp_strr, "m");
+               /*LOG_INFO("CHAR MALLOC & M DONE");*/
+               tmp_strr += sprintf(tmp_strr, "%016" PRIx64, temp->threadid);
+
+               temp = temp->next;
+
+               while (temp != NULL) {
+                       /*LOG_INFO("INTO GDB THREAD UPDATE WHILE");*/
+                       tmp_strr += sprintf(tmp_strr, ",");
+                       tmp_strr +=
+                           sprintf(tmp_strr, "%016" PRIx64, temp->threadid);
+                       temp = temp->next;
+               }
+
+               /*tmp_str[0] = 0;*/
+               gdb_put_packet(connection, out_strr, strlen(out_strr));
+               linux_os->preupdtate_threadid_count =
+                   linux_os->threadid_count - 1;
+               free(out_strr);
+       } else
+               gdb_put_packet(connection, "l", 1);
+
+       return ERROR_OK;
+}
+
+int linux_thread_extra_info(struct target *target,
+                           struct connection *connection, char *packet,
+                           int packet_size)
+{
+       int64_t threadid = 0;
+       struct linux_os *linux_os = (struct linux_os *)
+           target->rtos->rtos_specific_params;
+       sscanf(packet, "qThreadExtraInfo,%" SCNx64, &threadid);
+       /*LOG_INFO("lookup extra info for thread %" SCNx64, threadid);*/
+       struct threads *temp = linux_os->thread_list;
+
+       while (temp != NULL) {
+               if (temp->threadid == threadid) {
+                       char *pid = " PID: ";
+                       char *pid_current = "*PID: ";
+                       char *name = "NAME: ";
+                       int str_size = strlen(pid) + strlen(name);
+                       char *tmp_str = (char *)calloc(1, str_size + 50);
+                       char *tmp_str_ptr = tmp_str;
+
+                       /*  discriminate cuurent task */
+                       if (temp->status == 3)
+                               tmp_str_ptr += sprintf(tmp_str_ptr, "%s",
+                                                      pid_current);
+                       else
+                               tmp_str_ptr += sprintf(tmp_str_ptr, "%s", pid);
+
+                       tmp_str_ptr +=
+                           sprintf(tmp_str_ptr, "%d", (int)temp->pid);
+                       tmp_str_ptr += sprintf(tmp_str_ptr, "%s", " | ");
+                       tmp_str_ptr += sprintf(tmp_str_ptr, "%s", name);
+                       tmp_str_ptr += sprintf(tmp_str_ptr, "%s", temp->name);
+                       char *hex_str =
+                           (char *)calloc(1, strlen(tmp_str) * 2 + 1);
+                       str_to_hex(hex_str, tmp_str);
+                       gdb_put_packet(connection, hex_str, strlen(hex_str));
+                       free(hex_str);
+                       free(tmp_str);
+                       return ERROR_OK;
+               }
+
+               temp = temp->next;
+       }
+
+       LOG_INFO("thread not found");
+       return ERROR_OK;
+}
+
+int linux_gdb_T_packet(struct connection *connection,
+                      struct target *target, char *packet, int packet_size)
+{
+       int64_t threadid;
+       struct linux_os *linux_os = (struct linux_os *)
+           target->rtos->rtos_specific_params;
+       int retval = ERROR_OK;
+       sscanf(packet, "T%" SCNx64, &threadid);
+
+       if (linux_os->threads_needs_update == 0) {
+               struct threads *temp = linux_os->thread_list;
+               struct threads *prev = linux_os->thread_list;
+
+               while (temp != NULL) {
+                       if (temp->threadid == threadid) {
+                               if (temp->status != 0) {
+                                       gdb_put_packet(connection, "OK", 2);
+                                       return ERROR_OK;
+                               } else {
+                                       /* delete item in the list   */
+                                       linux_os->thread_list =
+                                           liste_del_task(linux_os->
+                                                          thread_list, &temp,
+                                                          prev);
+                                       linux_os->thread_count--;
+                                       gdb_put_packet(connection, "E01", 3);
+                                       return ERROR_OK;
+                               }
+                       }
+
+                       /*  for deletion  */
+                       prev = temp;
+                       temp = temp->next;
+               }
+
+               LOG_INFO("gdb requested status on non existing thread");
+               gdb_put_packet(connection, "E01", 3);
+               return ERROR_OK;
+
+       } else {
+               retval = linux_task_update(target, 1);
+               struct threads *temp = linux_os->thread_list;
+
+               while (temp != NULL) {
+                       if (temp->threadid == threadid) {
+                               if (temp->status == 1) {
+                                       gdb_put_packet(connection, "OK", 2);
+                                       return ERROR_OK;
+                               } else {
+                                       gdb_put_packet(connection, "E01", 3);
+                                       return ERROR_OK;
+                               }
+                       }
+
+                       temp = temp->next;
+               }
+       }
+
+       return retval;
+}
+
+int linux_gdb_h_packet(struct connection *connection,
+                      struct target *target, char *packet, int packet_size)
+{
+       struct linux_os *linux_os = (struct linux_os *)
+           target->rtos->rtos_specific_params;
+       struct current_thread *ct = linux_os->current_threads;
+
+       /* select to display the current thread of the selected target */
+       while ((ct != NULL) && (ct->core_id != target->coreid))
+               ct = ct->next;
+
+       int64_t current_gdb_thread_rq;
+
+       if (linux_os->threads_lookup == 1) {
+               if ((ct != NULL) && (ct->threadid == -1)) {
+                       ct = linux_os->current_threads;
+
+                       while ((ct != NULL) && (ct->threadid == -1))
+                               ct = ct->next;
+               }
+
+               if (ct == NULL) {
+                       /*  no current thread can be identified */
+                       /*  any way with smp  */
+                       LOG_INFO("no current thread identified");
+                       /* attempt to display the name of the 2 threads identified with
+                        * get_current */
+                       struct threads t;
+                       ct = linux_os->current_threads;
+
+                       while ((ct != NULL) && (ct->threadid == -1)) {
+                               t.base_addr = ct->TS;
+                               get_name(target, &t);
+                               LOG_INFO("name of unidentified thread %s",
+                                        t.name);
+                               ct = ct->next;
+                       }
+
+                       gdb_put_packet(connection, "OK", 2);
+                       return ERROR_OK;
+               }
+
+               if (packet[1] == 'g') {
+                       sscanf(packet, "Hg%16" SCNx64, &current_gdb_thread_rq);
+
+                       if (current_gdb_thread_rq == 0) {
+                               target->rtos->current_threadid = ct->threadid;
+                               gdb_put_packet(connection, "OK", 2);
+                       } else {
+                               target->rtos->current_threadid =
+                                   current_gdb_thread_rq;
+                               gdb_put_packet(connection, "OK", 2);
+                       }
+               } else if (packet[1] == 'c') {
+                       sscanf(packet, "Hc%16" SCNx64, &current_gdb_thread_rq);
+
+                       if ((current_gdb_thread_rq == 0) ||
+                           (current_gdb_thread_rq == ct->threadid)) {
+                               target->rtos->current_threadid = ct->threadid;
+                               gdb_put_packet(connection, "OK", 2);
+                       } else
+                               gdb_put_packet(connection, "E01", 3);
+               }
+       } else
+               gdb_put_packet(connection, "OK", 2);
+
+       return ERROR_OK;
+}
+
+static int linux_thread_packet(struct connection *connection, char *packet,
+                              int packet_size)
+{
+       int retval = ERROR_OK;
+       struct current_thread *ct;
+       struct target *target = get_target_from_connection(connection);
+       struct linux_os *linux_os = (struct linux_os *)
+               target->rtos->rtos_specific_params;
+
+       switch (packet[0]) {
+       case 'T':               /* Is thread alive?*/
+
+               linux_gdb_T_packet(connection, target, packet, packet_size);
+               break;
+       case 'H':               /* Set current thread */
+               /*  ( 'c' for step and continue, 'g' for all other operations )*/
+               /*LOG_INFO(" H packet received '%s'", packet);*/
+               linux_gdb_h_packet(connection, target, packet, packet_size);
+               break;
+       case 'q':
+
+               if ((strstr(packet, "qSymbol"))) {
+                       if (rtos_qsymbol(connection, packet, packet_size) == 1) {
+                               gdb_put_packet(connection, "OK", 2);
+
+                               linux_compute_virt2phys(target,
+                                               target->rtos->
+                                               symbols[INIT_TASK].
+                                               address);
+                       }
+
+                       break;
+               } else if (strstr(packet, "qfThreadInfo")) {
+                       if (linux_os->thread_list == NULL) {
+                               retval = linux_gdb_thread_packet(target,
+                                               connection,
+                                               packet,
+                                               packet_size);
+                               break;
+                       } else {
+                               retval = linux_gdb_thread_update(target,
+                                               connection,
+                                               packet,
+                                               packet_size);
+                               break;
+                       }
+               } else if (strstr(packet, "qsThreadInfo")) {
+                       gdb_put_packet(connection, "l", 1);
+                       break;
+               } else if (strstr(packet, "qThreadExtraInfo,")) {
+                       linux_thread_extra_info(target, connection, packet,
+                                       packet_size);
+                       break;
+               } else {
+                       retval = GDB_THREAD_PACKET_NOT_CONSUMED;
+                       break;
+               }
+
+       case 'Q':
+               /* previously response was : thread not found
+                * gdb_put_packet(connection, "E01", 3); */
+               retval = GDB_THREAD_PACKET_NOT_CONSUMED;
+               break;
+       case 'c':
+       case 's':{
+               if (linux_os->threads_lookup == 1) {
+                       ct = linux_os->current_threads;
+
+                       while ((ct != NULL)
+                                       && (ct->core_id) != target->coreid) {
+                               ct = ct->next;
+                       }
+
+                       if ((ct != NULL) && (ct->threadid == -1)) {
+                               ct = linux_os->current_threads;
+
+                               while ((ct != NULL)
+                                               && (ct->threadid == -1)) {
+                                       ct = ct->next;
+                               }
+                       }
+
+                       if ((ct != NULL) && (ct->threadid !=
+                                               target->rtos->
+                                               current_threadid)
+                                       && (target->rtos->current_threadid != -1))
+                               LOG_WARNING("WARNING! current GDB thread do not match"\
+                                               "current thread running."\
+                                               "Switch thread in GDB to threadid %d", (int)ct->threadid);
+
+                       LOG_INFO("threads_needs_update = 1");
+                       linux_os->threads_needs_update = 1;
+               }
+       }
+
+               /* if a packet handler returned an error, exit input loop */
+               if (retval != ERROR_OK)
+                       return retval;
+       }
+
+       return retval;
+}
+
+static int linux_os_smp_init(struct target *target)
+{
+       struct target_list *head;
+       /* keep only target->rtos */
+       struct rtos *rtos = target->rtos;
+       struct linux_os *os_linux =
+           (struct linux_os *)rtos->rtos_specific_params;
+       struct current_thread *ct;
+       head = target->head;
+
+       while (head != (struct target_list *)NULL) {
+               if (head->target->rtos != rtos) {
+                       struct linux_os *smp_os_linux =
+                           (struct linux_os *)head->target->rtos->
+                           rtos_specific_params;
+                       /*  remap smp target on rtos  */
+                       free(head->target->rtos);
+                       head->target->rtos = rtos;
+                       /*  reuse allocated ct */
+                       ct = smp_os_linux->current_threads;
+                       ct->threadid = -1;
+                       ct->TS = 0xdeadbeef;
+                       ct->core_id = head->target->coreid;
+                       os_linux->current_threads =
+                           add_current_thread(os_linux->current_threads, ct);
+                       os_linux->nr_cpus++;
+                       free(smp_os_linux);
+               }
+
+               head = head->next;
+       }
+
+       return ERROR_OK;
+}
+
+static int linux_os_create(struct target *target)
+{
+       struct linux_os *os_linux = calloc(1, sizeof(struct linux_os));
+       struct current_thread *ct = calloc(1, sizeof(struct current_thread));
+       LOG_INFO("linux os creation\n");
+       os_linux->init_task_addr = 0xdeadbeef;
+       os_linux->name = "linux";
+       os_linux->thread_list = NULL;
+       os_linux->thread_count = 0;
+       target->rtos->current_threadid = -1;
+       os_linux->nr_cpus = 1;
+       os_linux->threads_lookup = 0;
+       os_linux->threads_needs_update = 0;
+       os_linux->threadid_count = 1;
+       os_linux->current_threads = NULL;
+       target->rtos->rtos_specific_params = (void *)os_linux;
+       ct->core_id = target->coreid;
+       ct->threadid = -1;
+       ct->TS = 0xdeadbeef;
+       os_linux->current_threads =
+           add_current_thread(os_linux->current_threads, ct);
+       /*  overload rtos thread default handler */
+       target->rtos->gdb_thread_packet = linux_thread_packet;
+       /*  initialize a default virt 2 phys translation */
+       os_linux->phys_mask = ~0xc0000000;
+       os_linux->phys_base = 0x0;
+       return JIM_OK;
+}
+
+static char *linux_ps_command(struct target *target)
+{
+       struct linux_os *linux_os = (struct linux_os *)
+           target->rtos->rtos_specific_params;
+       int retval = ERROR_OK;
+       char *display;
+
+       if (linux_os->threads_lookup == 0) {
+               retval = linux_get_tasks(target, 1);
+       } else {
+               if (linux_os->threads_needs_update != 0)
+                       retval = linux_task_update(target, 0);
+       }
+
+       if (retval == ERROR_OK) {
+               struct threads *temp = linux_os->thread_list;
+               char *tmp;
+               LOG_INFO("allocation for %d threads line",
+                        linux_os->thread_count);
+               display = calloc((linux_os->thread_count + 2) * 80, 1);
+
+               if (!display)
+                       goto error;
+
+               tmp = display;
+               tmp += sprintf(tmp, "PID\t\tCPU\t\tASID\t\tNAME\n");
+               tmp += sprintf(tmp, "---\t\t---\t\t----\t\t----\n");
+
+               while (temp != NULL) {
+                       if (temp->status) {
+                               if (temp->context)
+                                       tmp +=
+                                           sprintf(tmp,
+                                                   "%d\t\t%d\t\t%x\t\t%s\n",
+                                                   (int)temp->pid, temp->oncpu,
+                                                   temp->asid, temp->name);
+                               else
+                                       tmp +=
+                                           sprintf(tmp,
+                                                   "%d\t\t%d\t\t%x\t\t%s\n",
+                                                   (int)temp->pid, temp->oncpu,
+                                                   temp->asid, temp->name);
+                       }
+
+                       temp = temp->next;
+               }
+
+               return display;
+       }
+
+error:
+       display = calloc(40, 1);
+       sprintf(display, "linux_ps_command failed\n");
+       return display;
+}
diff --git a/src/rtos/linux_header.h b/src/rtos/linux_header.h
new file mode 100644 (file)
index 0000000..faaf319
--- /dev/null
@@ -0,0 +1,32 @@
+/*  gdb script to update the header file
+  according to kernel version and build option
+  before executing function awareness
+  kernel symbol must be loaded : symbol vmlinux
+
+define awareness
+ set logging off
+ set logging file linux_header.h
+ set logging on
+
+ printf "#define QAT %p\n",&((struct task_struct *)(0))->stack
+ set $a=&((struct list_head *)(0))->next
+ set $a=(int)$a+(int)&((struct task_struct *)(0))->tasks
+ printf "#define NEXT  %p\n",$a
+ printf "#define COMM  %p\n",&((struct task_struct *)(0))->comm
+ printf "#define MEM  %p\n",&((struct task_struct *)(0))->mm
+ printf "#define ONCPU %p\n",&((struct task_struct *)(0))->on_cpu
+ printf "#define PID %p\n",&((struct task_struct *)(0))->pid
+ printf "#define CPU_CONT %p\n",&((struct thread_info *)(0))->cpu_context
+ printf "#define PREEMPT %p\n",&((struct thread_info *)(0))->preempt_count
+ printf "#define MM_CTX %p\n",&((struct mm_struct *)(0))->context
+ end
+*/
+#define QAT 0x4
+#define NEXT  0x1b0
+#define COMM  0x2d4
+#define MEM  0x1cc
+#define ONCPU 0x18
+#define PID 0x1f4
+#define CPU_CONT 0x1c
+#define PREEMPT 0x4
+#define MM_CTX 0x160
index a0bbc82b5ec03871b9d4f49baa519711558f914b..3deeb68e7237309897f956d3d02670ce43ec7ba5 100644 (file)
@@ -37,12 +37,14 @@ static void hex_to_str( char* dst, char * hex_src );
 extern struct rtos_type FreeRTOS_rtos;
 extern struct rtos_type ThreadX_rtos;
 extern struct rtos_type eCos_rtos;
+extern struct rtos_type Linux_os;
 
 static struct rtos_type *rtos_types[] =
 {
        &ThreadX_rtos,
        &FreeRTOS_rtos,
        &eCos_rtos,
+       &Linux_os,
        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)