rtos : smp support
[fw/openocd] / src / rtos / rtos.c
1 /***************************************************************************
2  *   Copyright (C) 2011 by Broadcom Corporation                            *
3  *   Evan Hunter - ehunter@broadcom.com                                    *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25
26 #include "rtos.h"
27 #include "target/target.h"
28 #include "helper/log.h"
29 #include "server/gdb_server.h"
30
31
32
33 static void hex_to_str( char* dst, char * hex_src );
34 static int str_to_hex( char* hex_dst, char* src );
35
36
37 /* RTOSs */
38 extern struct rtos_type FreeRTOS_rtos;
39 extern struct rtos_type ThreadX_rtos;
40 extern struct rtos_type eCos_rtos;
41
42 static struct rtos_type *rtos_types[] =
43 {
44         &ThreadX_rtos,
45         &FreeRTOS_rtos,
46         &eCos_rtos,
47         NULL
48 };
49
50 int rtos_thread_packet(struct connection *connection, char *packet, int packet_size);
51
52 int rtos_smp_init(struct target *target)
53 {
54         if (target->rtos->type->smp_init)
55                 return target->rtos->type->smp_init(target);
56         return ERROR_TARGET_INIT_FAILED;
57 }
58
59
60 int rtos_create(Jim_GetOptInfo *goi, struct target * target)
61 {
62         int x;
63         char *cp;
64         if (! goi->isconfigure) {
65                 if (goi->argc != 0) {
66                         if (goi->argc != 0) {
67                                 Jim_WrongNumArgs(goi->interp,
68                                                 goi->argc, goi->argv,
69                                                 "NO PARAMS");
70                                 return JIM_ERR;
71                         }
72
73                         Jim_SetResultString(goi->interp,
74                                         target_type_name(target), -1);
75                 }
76         }
77
78         if (target->rtos) {
79                 free((void *)(target->rtos));
80         }
81 //                      e = Jim_GetOpt_String(goi, &cp, NULL);
82 //                      target->rtos = strdup(cp);
83
84         Jim_GetOpt_String(goi, &cp, NULL);
85         /* now does target type exist */
86
87         if ( 0 == strcmp( cp, "auto") )
88         {
89                 // auto detection of RTOS
90                 target->rtos_auto_detect = true;
91                 x = 0;
92         }
93         else
94         {
95
96                 for (x = 0 ; rtos_types[x] ; x++) {
97                         if (0 == strcmp(cp, rtos_types[x]->name)) {
98                                 /* found */
99                                 break;
100                         }
101                 }
102                 if (rtos_types[x] == NULL) {
103                         Jim_SetResultFormatted(goi->interp, "Unknown rtos type %s, try one of ", cp);
104                         for (x = 0 ; rtos_types[x] ; x++) {
105                                 if (rtos_types[x + 1]) {
106                                         Jim_AppendStrings(goi->interp,
107                                                                            Jim_GetResult(goi->interp),
108                                                                            rtos_types[x]->name,
109                                                                            ", ", NULL);
110                                 } else {
111                                         Jim_AppendStrings(goi->interp,
112                                                                            Jim_GetResult(goi->interp),
113                                                                            " or ",
114                                                                            rtos_types[x]->name,NULL);
115                                 }
116                         }
117                         return JIM_ERR;
118                 }
119         }
120         /* Create it */
121         target->rtos = calloc(1,sizeof(struct rtos));
122         target->rtos->type = rtos_types[x];
123         target->rtos->current_threadid = -1;
124         target->rtos->current_thread = 0;
125         target->rtos->symbols = NULL;
126         target->rtos->target = target;
127         /* put default thread handler in linux usecase it is overloaded*/
128         target->rtos->gdb_thread_packet = rtos_thread_packet;
129
130         if ( 0 != strcmp( cp, "auto") )
131         {
132                 target->rtos->type->create( target );
133         }
134
135         return JIM_OK;
136 }
137
138 int gdb_thread_packet(struct connection *connection, char *packet, int packet_size)
139 {
140         struct target *target = get_target_from_connection(connection);
141         if (target->rtos == NULL)
142                 return rtos_thread_packet(connection, packet, packet_size); /* thread not found*/
143         return target->rtos->gdb_thread_packet(connection, packet, packet_size);
144 }
145
146
147
148
149 int rtos_thread_packet(struct connection *connection, char *packet, int packet_size)
150 {
151         struct target *target = get_target_from_connection(connection);
152
153         if (strstr(packet, "qThreadExtraInfo,"))
154         {
155                 if ((target->rtos != NULL) && (target->rtos->thread_details != NULL) && (target->rtos->thread_count != 0))
156                 {
157                         threadid_t threadid = 0;
158                         int found = -1;
159                         sscanf(packet, "qThreadExtraInfo,%" SCNx64, &threadid );
160
161                         if ((target->rtos != NULL) && (target->rtos->thread_details
162                                         != NULL)) {
163                                 int thread_num;
164                                 for (thread_num = 0; thread_num
165                                                 < target->rtos->thread_count; thread_num++) {
166                                         if (target->rtos->thread_details[thread_num].threadid
167                                                         == threadid) {
168                                                 if (target->rtos->thread_details[thread_num].exists) {
169                                                         found = thread_num;
170                                                 }
171                                         }
172                                 }
173                         }
174                         if (found == -1) {
175                                 gdb_put_packet(connection, "E01", 3); // thread not found
176                                 return ERROR_OK;
177                         }
178
179                         struct thread_detail* detail = &target->rtos->thread_details[found];
180
181                         int str_size = 0;
182                         if ( detail->display_str != NULL )
183                         {
184                                 str_size += strlen(detail->display_str);
185                         }
186                         if ( detail->thread_name_str != NULL )
187                         {
188                                 str_size += strlen(detail->thread_name_str);
189                         }
190                         if ( detail->extra_info_str != NULL )
191                         {
192                                 str_size += strlen(detail->extra_info_str);
193                         }
194
195                         char * tmp_str = (char*) malloc( str_size + 7 );
196                         char*  tmp_str_ptr = tmp_str;
197
198                         if ( detail->display_str != NULL )
199                         {
200                                 tmp_str_ptr += sprintf( tmp_str_ptr, "%s", detail->display_str );
201                         }
202                         if ( detail->thread_name_str != NULL )
203                         {
204                                 if ( tmp_str_ptr != tmp_str )
205                                 {
206                                         tmp_str_ptr += sprintf( tmp_str_ptr, " : " );
207                                 }
208                                 tmp_str_ptr += sprintf( tmp_str_ptr, "%s", detail->thread_name_str );
209                         }
210                         if ( detail->extra_info_str != NULL )
211                         {
212                                 if ( tmp_str_ptr != tmp_str )
213                                 {
214                                         tmp_str_ptr += sprintf( tmp_str_ptr, " : " );
215                                 }
216                                 tmp_str_ptr += sprintf( tmp_str_ptr, " : %s", detail->extra_info_str );
217                         }
218
219                         assert(strlen(tmp_str) ==
220                                 (size_t) (tmp_str_ptr - tmp_str));
221
222                         char * hex_str = (char*) malloc( strlen(tmp_str)*2 +1 );
223                         str_to_hex( hex_str, tmp_str );
224
225                         gdb_put_packet(connection, hex_str, strlen(hex_str));
226                         free(hex_str);
227                         free(tmp_str);
228                         return ERROR_OK;
229
230                 }
231                 gdb_put_packet(connection, "", 0);
232                 return ERROR_OK;
233         }
234         else if (strstr(packet, "qSymbol"))
235         {
236                 if ( target->rtos != NULL )
237                 {
238                         int next_symbol_num = -1;
239                         if (target->rtos->symbols == NULL)
240                         {
241                                 target->rtos->type->get_symbol_list_to_lookup( &target->rtos->symbols );
242                         }
243                         if (0 == strcmp( "qSymbol::", packet ) )
244                         {
245                                 // first query -
246                                 next_symbol_num = 0;
247                         }
248                         else
249                         {
250                                 int64_t value = 0;
251                                 char * hex_name_str = malloc( strlen(packet));
252                                 char * name_str;
253                                 int symbol_num;
254
255                                 char* found = strstr( packet, "qSymbol::" );
256                                 if (0 == found )
257                                 {
258                                         sscanf(packet, "qSymbol:%" SCNx64 ":%s", &value, hex_name_str);
259                                 }
260                                 else
261                                 {
262                                         // No value returned by GDB - symbol was not found
263                                         sscanf(packet, "qSymbol::%s", hex_name_str);
264                                 }
265                                 name_str = (char*) malloc( 1+ strlen(hex_name_str) / 2 );
266
267                                 hex_to_str( name_str, hex_name_str );
268
269
270                                 symbol_num = 0;
271                                 while ( ( target->rtos->symbols[ symbol_num ].symbol_name != NULL ) && ( 0 != strcmp( target->rtos->symbols[ symbol_num ].symbol_name, name_str ) ) )
272                                 {
273                                         symbol_num++;
274                                 }
275
276
277                                 if ( target->rtos->symbols[ symbol_num ].symbol_name == NULL )
278                                 {
279                                         LOG_OUTPUT("ERROR: unknown symbol\r\n");
280                                         gdb_put_packet(connection, "OK", 2);
281                                         return ERROR_OK;
282                                 }
283
284                                 target->rtos->symbols[ symbol_num ].address = value;
285
286                                 next_symbol_num = symbol_num+1;
287                                 free( hex_name_str );
288                                 free( name_str );
289
290                         }
291
292                         int symbols_done = 0;
293                         if ( target->rtos->symbols[ next_symbol_num ].symbol_name == NULL )
294                         {
295                                 if ( ( target->rtos_auto_detect == false ) ||
296                                          ( 1 == target->rtos->type->detect_rtos( target ) ) )
297                                 {
298                                         // Found correct RTOS or not autodetecting
299                                         if ( target->rtos_auto_detect == true )
300                                         {
301                                                 LOG_OUTPUT( "Auto-detected RTOS: %s\r\n",target->rtos->type->name );
302                                         }
303                                         symbols_done = 1;
304                                 }
305                                 else
306                                 {
307                                         // Auto detecting RTOS and currently not found
308                                         if( 1 != rtos_try_next( target ) )
309                                         {
310                                                 // No more RTOS's to try
311                                                 symbols_done = 1;
312                                         }
313                                         else
314                                         {
315                                                 next_symbol_num = 0;
316                                                 target->rtos->type->get_symbol_list_to_lookup( &target->rtos->symbols );
317                                         }
318
319                                 }
320                         }
321
322
323                         if ( symbols_done == 1 )
324                         {
325                                 target->rtos_auto_detect = false;
326                                 target->rtos->type->create( target );
327                                 target->rtos->type->update_threads(target->rtos);
328                                 // No more symbols needed
329                                 gdb_put_packet(connection, "OK", 2);
330                                 return ERROR_OK;
331
332                         }
333                         else
334                         {
335                                 char* symname = target->rtos->symbols[ next_symbol_num ].symbol_name;
336                                 char qsymstr[] = "qSymbol:";
337                                 char * opstring = (char*)malloc(sizeof(qsymstr)+strlen(symname)*2+1);
338                                 char * posptr = opstring;
339                                 posptr += sprintf( posptr, "%s", qsymstr );
340                                 str_to_hex( posptr, symname );
341                                 gdb_put_packet(connection, opstring, strlen(opstring));
342                                 free(opstring);
343                                 return ERROR_OK;
344                         }
345
346                 }
347                 gdb_put_packet(connection, "OK", 2);
348                 return ERROR_OK;
349         }
350         else if (strstr(packet, "qfThreadInfo"))
351         {
352                 int i;
353                 if ( ( target->rtos != NULL ) && ( target->rtos->thread_count != 0 ) )
354                 {
355
356                         char* out_str = (char*) malloc(17 * target->rtos->thread_count + 5);
357                         char* tmp_str = out_str;
358                         tmp_str += sprintf(tmp_str, "m");
359                         for (i = 0; i < target->rtos->thread_count; i++) {
360                                 if (i != 0) {
361                                         tmp_str += sprintf(tmp_str, ",");
362                                 }
363                                 tmp_str += sprintf(tmp_str, "%016" PRIx64,
364                                                 target->rtos->thread_details[i].threadid);
365                         }
366                         tmp_str[0] = 0;
367                         gdb_put_packet(connection, out_str, strlen(out_str));
368                 }
369                 else
370                 {
371                         gdb_put_packet(connection, "", 0);
372                 }
373
374                 return ERROR_OK;
375         }
376         else if (strstr(packet, "qsThreadInfo"))
377         {
378                 gdb_put_packet(connection, "l", 1);
379                 return ERROR_OK;
380         }
381         else if (strstr(packet, "qAttached"))
382         {
383                 gdb_put_packet(connection, "1", 1);
384                 return ERROR_OK;
385         }
386         else if (strstr(packet, "qOffsets"))
387         {
388                 char offsets[] = "Text=0;Data=0;Bss=0";
389                 gdb_put_packet(connection, offsets, sizeof(offsets)-1);
390                 return ERROR_OK;
391         }
392         else if (strstr(packet, "qC"))
393         {
394                 if( target->rtos!=NULL )
395                 {
396                         char buffer[15];
397                         int size;
398                         size = snprintf(buffer, 15, "QC%08X", (int)target->rtos->current_thread);
399                         gdb_put_packet(connection, buffer, size);
400                 }
401                 else
402                 {
403                         gdb_put_packet(connection, "QC0", 3);
404                 }
405                 return ERROR_OK;
406         }
407         else if ( packet[0] == 'T' ) // Is thread alive?
408         {
409                 threadid_t threadid;
410                 int found = -1;
411                 sscanf(packet, "T%" SCNx64, &threadid);
412                 if ((target->rtos != NULL) && (target->rtos->thread_details
413                                 != NULL)) {
414                         int thread_num;
415                         for (thread_num = 0; thread_num
416                                         < target->rtos->thread_count; thread_num++) {
417                                 if (target->rtos->thread_details[thread_num].threadid
418                                                 == threadid) {
419                                         if (target->rtos->thread_details[thread_num].exists) {
420                                                 found = thread_num;
421                                         }
422                                 }
423                         }
424                 }
425                 if (found != -1) {
426                         gdb_put_packet(connection, "OK", 2); // thread alive
427                 } else {
428                         gdb_put_packet(connection, "E01", 3); // thread not found
429                 }
430                 return ERROR_OK;
431         }
432         else if ( packet[0] == 'H') // Set current thread ( 'c' for step and continue, 'g' for all other operations )
433         {
434                 if ((packet[1] == 'g') && (target->rtos != NULL))
435                         sscanf(packet, "Hg%16" SCNx64, &target->rtos->current_threadid);
436                 gdb_put_packet(connection, "OK", 2);
437                 return ERROR_OK;
438         }
439
440         return GDB_THREAD_PACKET_NOT_CONSUMED;
441 }
442
443 int rtos_get_gdb_reg_list(struct connection *connection)
444 {
445         struct target *target = get_target_from_connection(connection);
446         int64_t current_threadid = target->rtos->current_threadid;
447         if ((target->rtos != NULL) &&
448                  (current_threadid != -1) &&
449                  (current_threadid != 0) &&
450                  ((current_threadid != target->rtos->current_thread) ||
451                  (target->smp))) /* in smp several current thread are possible */
452         {
453                 char * hex_reg_list;
454                 target->rtos->type->get_thread_reg_list( target->rtos, current_threadid, &hex_reg_list );
455
456                 if ( hex_reg_list != NULL )
457                 {
458                         gdb_put_packet(connection, hex_reg_list, strlen(hex_reg_list));
459                         free(hex_reg_list);
460                         return ERROR_OK;
461                 }
462         }
463         return ERROR_FAIL;
464 }
465
466
467
468 int rtos_generic_stack_read( struct target * target, const struct rtos_register_stacking* stacking, int64_t stack_ptr, char ** hex_reg_list )
469 {
470         int list_size = 0;
471         char * tmp_str_ptr;
472         int64_t new_stack_ptr;
473         int i;
474         int retval;
475
476         if ( stack_ptr == 0)
477         {
478                 LOG_OUTPUT("Error: null stack pointer in thread\r\n");
479                 return -5;
480         }
481         // Read the stack
482         uint8_t * stack_data = (uint8_t*) malloc( stacking->stack_registers_size );
483         uint32_t address = stack_ptr;
484
485         if ( stacking->stack_growth_direction == 1 )
486         {
487                 address -=  stacking->stack_registers_size;
488         }
489         retval = target_read_buffer( target, address, stacking->stack_registers_size, stack_data);
490         if ( retval != ERROR_OK )
491         {
492                 LOG_OUTPUT("Error reading stack frame from FreeRTOS thread\r\n");
493                 return retval;
494         }
495 /*
496         LOG_OUTPUT("Stack Data :");
497         for(i = 0; i < stacking->stack_registers_size; i++ )
498         {
499                 LOG_OUTPUT("%02X",stack_data[i]);
500         }
501         LOG_OUTPUT("\r\n");
502 */
503         for( i = 0; i < stacking->num_output_registers; i++ )
504         {
505                 list_size += stacking->register_offsets[i].width_bits/8;
506         }
507         *hex_reg_list = (char*)malloc( list_size*2 +1 );
508         tmp_str_ptr = *hex_reg_list;
509         new_stack_ptr = stack_ptr - stacking->stack_growth_direction * stacking->stack_registers_size;
510         if (stacking->stack_alignment != 0) {
511                 /* Align new stack pointer to x byte boundary */
512                 new_stack_ptr =
513                         (new_stack_ptr & (~((int64_t) stacking->stack_alignment - 1))) +
514                         ((stacking->stack_growth_direction == -1) ? stacking->stack_alignment : 0);
515         }
516         for( i = 0; i < stacking->num_output_registers; i++ )
517         {
518                 int j;
519                 for ( j = 0; j < stacking->register_offsets[i].width_bits/8; j++ )
520                 {
521                         if ( stacking->register_offsets[i].offset == -1 )
522                         {
523                                 tmp_str_ptr += sprintf( tmp_str_ptr, "%02x", 0 );
524                         }
525                         else if ( stacking->register_offsets[i].offset == -2 )
526                         {
527                                 tmp_str_ptr += sprintf( tmp_str_ptr, "%02x", ((uint8_t*)&new_stack_ptr)[j] );
528                         }
529                         else
530                         {
531                                 tmp_str_ptr += sprintf( tmp_str_ptr,"%02x", stack_data[ stacking->register_offsets[i].offset + j ] );
532                         }
533                 }
534         }
535 //      LOG_OUTPUT("Output register string: %s\r\n", *hex_reg_list);
536         return ERROR_OK;
537 }
538
539 int rtos_try_next( struct target * target )
540 {
541         int x;
542
543         if ( target->rtos == NULL )
544         {
545                 return -1;
546         }
547
548         for (x = 0 ; rtos_types[x] ; x++) {
549                 if (target->rtos->type == rtos_types[x] ) {
550                         /* found */
551                         if ( rtos_types[x+1] != NULL )
552                         {
553                                 target->rtos->type = rtos_types[x+1];
554                                 if ( target->rtos->symbols != NULL )
555                                 {
556                                         free( target->rtos->symbols );
557                                 }
558                                 return 1;
559                         }
560                         else
561                         {
562                                 // No more rtos types
563                                 return 0;
564                         }
565
566                 }
567         }
568         return 0;
569
570 }
571
572 static void hex_to_str( char* dst, char * hex_src )
573 {
574         int src_pos = 0;
575         int dst_pos = 0;
576
577         while ( hex_src[src_pos] != '\x00' )
578         {
579                 char hex_char = hex_src[src_pos];
580                 char hex_digit_val = (hex_char>='a')?hex_char-'a'+10:(hex_char>='A')?hex_char-'A'+10:hex_char-'0';
581                 if ( 0 == (src_pos & 0x01) )
582                 {
583                         dst[dst_pos] = hex_digit_val;
584                         dst[dst_pos+1] = 0;
585                 }
586                 else
587                 {
588                         ((unsigned char*)dst)[dst_pos] <<= 4;
589                         ((unsigned char*)dst)[dst_pos] += hex_digit_val;
590                         dst_pos++;
591                 }
592                 src_pos++;
593         }
594
595 }
596
597 static int str_to_hex( char* hex_dst, char* src )
598 {
599         char * posptr = hex_dst;
600         unsigned i;
601         for( i = 0; i < strlen(src); i++)
602         {
603                 posptr += sprintf( posptr, "%02x", (unsigned char)src[i] );
604         }
605         return (posptr-hex_dst);
606 }
607
608
609 int rtos_update_threads( struct target* target )
610 {
611         if ((target->rtos != NULL) && (target->rtos->type != NULL))
612         {
613                 target->rtos->type->update_threads(target->rtos);
614         }
615         return ERROR_OK;
616 }