You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

611 lines
18 KiB

  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, see <http://www.gnu.org/licenses/>. *
  17. ***************************************************************************/
  18. #ifdef HAVE_CONFIG_H
  19. #include "config.h"
  20. #endif
  21. #include <helper/time_support.h>
  22. #include <jtag/jtag.h>
  23. #include "target/target.h"
  24. #include "target/target_type.h"
  25. #include "rtos.h"
  26. #include "helper/log.h"
  27. #include "helper/types.h"
  28. #include "rtos_standard_stackings.h"
  29. static const struct rtos_register_stacking *get_stacking_info(const struct rtos *rtos, int64_t stack_ptr);
  30. static const struct rtos_register_stacking *get_stacking_info_arm926ejs(const struct rtos *rtos, int64_t stack_ptr);
  31. static int is_thread_id_valid(const struct rtos *rtos, int64_t thread_id);
  32. static int is_thread_id_valid_arm926ejs(const struct rtos *rtos, int64_t thread_id);
  33. static bool threadx_detect_rtos(struct target *target);
  34. static int threadx_create(struct target *target);
  35. static int threadx_update_threads(struct rtos *rtos);
  36. static int threadx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs);
  37. static int threadx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]);
  38. struct threadx_thread_state {
  39. int value;
  40. const char *desc;
  41. };
  42. static const struct threadx_thread_state threadx_thread_states[] = {
  43. { 0, "Ready" },
  44. { 1, "Completed" },
  45. { 2, "Terminated" },
  46. { 3, "Suspended" },
  47. { 4, "Sleeping" },
  48. { 5, "Waiting - Queue" },
  49. { 6, "Waiting - Semaphore" },
  50. { 7, "Waiting - Event flag" },
  51. { 8, "Waiting - Memory" },
  52. { 9, "Waiting - Memory" },
  53. { 10, "Waiting - I/O" },
  54. { 11, "Waiting - Filesystem" },
  55. { 12, "Waiting - Network" },
  56. { 13, "Waiting - Mutex" },
  57. };
  58. #define THREADX_NUM_STATES ARRAY_SIZE(threadx_thread_states)
  59. #define ARM926EJS_REGISTERS_SIZE_SOLICITED (11 * 4)
  60. static const struct stack_register_offset rtos_threadx_arm926ejs_stack_offsets_solicited[] = {
  61. { 0, -1, 32 }, /* r0 */
  62. { 1, -1, 32 }, /* r1 */
  63. { 2, -1, 32 }, /* r2 */
  64. { 3, -1, 32 }, /* r3 */
  65. { 4, 0x08, 32 }, /* r4 */
  66. { 5, 0x0C, 32 }, /* r5 */
  67. { 6, 0x10, 32 }, /* r6 */
  68. { 7, 0x14, 32 }, /* r7 */
  69. { 8, 0x18, 32 }, /* r8 */
  70. { 9, 0x1C, 32 }, /* r9 */
  71. { 10, 0x20, 32 }, /* r10 */
  72. { 11, 0x24, 32 }, /* r11 */
  73. { 12, -1, 32 }, /* r12 */
  74. { 13, -2, 32 }, /* sp (r13) */
  75. { 14, 0x28, 32 }, /* lr (r14) */
  76. { 15, -1, 32 }, /* pc (r15) */
  77. /*{ 16, -1, 32 },*/ /* lr (r14) */
  78. /*{ 17, 0x28, 32 },*/ /* pc (r15) */
  79. { 16, 0x04, 32 }, /* xPSR */
  80. };
  81. #define ARM926EJS_REGISTERS_SIZE_INTERRUPT (17 * 4)
  82. static const struct stack_register_offset rtos_threadx_arm926ejs_stack_offsets_interrupt[] = {
  83. { 0, 0x08, 32 }, /* r0 */
  84. { 1, 0x0C, 32 }, /* r1 */
  85. { 2, 0x10, 32 }, /* r2 */
  86. { 3, 0x14, 32 }, /* r3 */
  87. { 4, 0x18, 32 }, /* r4 */
  88. { 5, 0x1C, 32 }, /* r5 */
  89. { 6, 0x20, 32 }, /* r6 */
  90. { 7, 0x24, 32 }, /* r7 */
  91. { 8, 0x28, 32 }, /* r8 */
  92. { 9, 0x2C, 32 }, /* r9 */
  93. { 10, 0x30, 32 }, /* r10 */
  94. { 11, 0x34, 32 }, /* r11 */
  95. { 12, 0x38, 32 }, /* r12 */
  96. { 13, -2, 32 }, /* sp (r13) */
  97. { 14, 0x3C, 32 }, /* lr (r14) */
  98. { 15, 0x40, 32 }, /* pc (r15) */
  99. { 16, 0x04, 32 }, /* xPSR */
  100. };
  101. static const struct rtos_register_stacking rtos_threadx_arm926ejs_stacking[] = {
  102. {
  103. ARM926EJS_REGISTERS_SIZE_SOLICITED, /* stack_registers_size */
  104. -1, /* stack_growth_direction */
  105. 17, /* num_output_registers */
  106. NULL, /* stack_alignment */
  107. rtos_threadx_arm926ejs_stack_offsets_solicited /* register_offsets */
  108. },
  109. {
  110. ARM926EJS_REGISTERS_SIZE_INTERRUPT, /* stack_registers_size */
  111. -1, /* stack_growth_direction */
  112. 17, /* num_output_registers */
  113. NULL, /* stack_alignment */
  114. rtos_threadx_arm926ejs_stack_offsets_interrupt /* register_offsets */
  115. },
  116. };
  117. struct threadx_params {
  118. const char *target_name;
  119. unsigned char pointer_width;
  120. unsigned char thread_stack_offset;
  121. unsigned char thread_name_offset;
  122. unsigned char thread_state_offset;
  123. unsigned char thread_next_offset;
  124. const struct rtos_register_stacking *stacking_info;
  125. size_t stacking_info_nb;
  126. const struct rtos_register_stacking* (*fn_get_stacking_info)(const struct rtos *rtos, int64_t stack_ptr);
  127. int (*fn_is_thread_id_valid)(const struct rtos *rtos, int64_t thread_id);
  128. };
  129. static const struct threadx_params threadx_params_list[] = {
  130. {
  131. "cortex_m", /* target_name */
  132. 4, /* pointer_width; */
  133. 8, /* thread_stack_offset; */
  134. 40, /* thread_name_offset; */
  135. 48, /* thread_state_offset; */
  136. 136, /* thread_next_offset */
  137. &rtos_standard_cortex_m3_stacking, /* stacking_info */
  138. 1, /* stacking_info_nb */
  139. NULL, /* fn_get_stacking_info */
  140. NULL, /* fn_is_thread_id_valid */
  141. },
  142. {
  143. "cortex_r4", /* target_name */
  144. 4, /* pointer_width; */
  145. 8, /* thread_stack_offset; */
  146. 40, /* thread_name_offset; */
  147. 48, /* thread_state_offset; */
  148. 136, /* thread_next_offset */
  149. &rtos_standard_cortex_r4_stacking, /* stacking_info */
  150. 1, /* stacking_info_nb */
  151. NULL, /* fn_get_stacking_info */
  152. NULL, /* fn_is_thread_id_valid */
  153. },
  154. {
  155. "arm926ejs", /* target_name */
  156. 4, /* pointer_width; */
  157. 8, /* thread_stack_offset; */
  158. 40, /* thread_name_offset; */
  159. 48, /* thread_state_offset; */
  160. 136, /* thread_next_offset */
  161. rtos_threadx_arm926ejs_stacking, /* stacking_info */
  162. 2, /* stacking_info_nb */
  163. get_stacking_info_arm926ejs, /* fn_get_stacking_info */
  164. is_thread_id_valid_arm926ejs, /* fn_is_thread_id_valid */
  165. },
  166. };
  167. enum threadx_symbol_values {
  168. THREADX_VAL_TX_THREAD_CURRENT_PTR = 0,
  169. THREADX_VAL_TX_THREAD_CREATED_PTR = 1,
  170. THREADX_VAL_TX_THREAD_CREATED_COUNT = 2,
  171. };
  172. static const char * const threadx_symbol_list[] = {
  173. "_tx_thread_current_ptr",
  174. "_tx_thread_created_ptr",
  175. "_tx_thread_created_count",
  176. NULL
  177. };
  178. const struct rtos_type threadx_rtos = {
  179. .name = "ThreadX",
  180. .detect_rtos = threadx_detect_rtos,
  181. .create = threadx_create,
  182. .update_threads = threadx_update_threads,
  183. .get_thread_reg_list = threadx_get_thread_reg_list,
  184. .get_symbol_list_to_lookup = threadx_get_symbol_list_to_lookup,
  185. };
  186. static const struct rtos_register_stacking *get_stacking_info(const struct rtos *rtos, int64_t stack_ptr)
  187. {
  188. const struct threadx_params *param = (const struct threadx_params *) rtos->rtos_specific_params;
  189. if (param->fn_get_stacking_info)
  190. return param->fn_get_stacking_info(rtos, stack_ptr);
  191. return param->stacking_info + 0;
  192. }
  193. static int is_thread_id_valid(const struct rtos *rtos, int64_t thread_id)
  194. {
  195. const struct threadx_params *param;
  196. if (!rtos->rtos_specific_params)
  197. return 0; /* invalid */
  198. param = (const struct threadx_params *) rtos->rtos_specific_params;
  199. if (param->fn_is_thread_id_valid)
  200. return param->fn_is_thread_id_valid(rtos, thread_id);
  201. return (thread_id != 0);
  202. }
  203. static const struct rtos_register_stacking *get_stacking_info_arm926ejs(const struct rtos *rtos, int64_t stack_ptr)
  204. {
  205. const struct threadx_params *param = (const struct threadx_params *) rtos->rtos_specific_params;
  206. int retval;
  207. uint32_t flag;
  208. retval = target_read_buffer(rtos->target,
  209. stack_ptr,
  210. sizeof(flag),
  211. (uint8_t *)&flag);
  212. if (retval != ERROR_OK) {
  213. LOG_ERROR("Error reading stack data from ThreadX thread: stack_ptr=0x%" PRIx64, stack_ptr);
  214. return NULL;
  215. }
  216. if (flag == 0) {
  217. LOG_DEBUG(" solicited stack");
  218. return param->stacking_info + 0;
  219. } else {
  220. LOG_DEBUG(" interrupt stack: %" PRIu32, flag);
  221. return param->stacking_info + 1;
  222. }
  223. }
  224. static int is_thread_id_valid_arm926ejs(const struct rtos *rtos, int64_t thread_id)
  225. {
  226. return (thread_id != 0 && thread_id != 1);
  227. }
  228. static int threadx_update_threads(struct rtos *rtos)
  229. {
  230. int retval;
  231. int tasks_found = 0;
  232. int thread_list_size = 0;
  233. const struct threadx_params *param;
  234. if (!rtos)
  235. return -1;
  236. if (!rtos->rtos_specific_params)
  237. return -3;
  238. param = (const struct threadx_params *) rtos->rtos_specific_params;
  239. if (!rtos->symbols) {
  240. LOG_ERROR("No symbols for ThreadX");
  241. return -4;
  242. }
  243. if (rtos->symbols[THREADX_VAL_TX_THREAD_CREATED_COUNT].address == 0) {
  244. LOG_ERROR("Don't have the number of threads in ThreadX");
  245. return -2;
  246. }
  247. /* read the number of threads */
  248. retval = target_read_buffer(rtos->target,
  249. rtos->symbols[THREADX_VAL_TX_THREAD_CREATED_COUNT].address,
  250. 4,
  251. (uint8_t *)&thread_list_size);
  252. if (retval != ERROR_OK) {
  253. LOG_ERROR("Could not read ThreadX thread count from target");
  254. return retval;
  255. }
  256. /* wipe out previous thread details if any */
  257. rtos_free_threadlist(rtos);
  258. /* read the current thread id */
  259. retval = target_read_buffer(rtos->target,
  260. rtos->symbols[THREADX_VAL_TX_THREAD_CURRENT_PTR].address,
  261. 4,
  262. (uint8_t *)&rtos->current_thread);
  263. if (retval != ERROR_OK) {
  264. LOG_ERROR("Could not read ThreadX current thread from target");
  265. return retval;
  266. }
  267. if ((thread_list_size == 0) || (rtos->current_thread == 0)) {
  268. /* Either : No RTOS threads - there is always at least the current execution though */
  269. /* OR : No current thread - all threads suspended - show the current execution
  270. * of idling */
  271. char tmp_str[] = "Current Execution";
  272. thread_list_size++;
  273. tasks_found++;
  274. rtos->thread_details = malloc(
  275. sizeof(struct thread_detail) * thread_list_size);
  276. rtos->thread_details->threadid = 1;
  277. rtos->thread_details->exists = true;
  278. rtos->thread_details->extra_info_str = NULL;
  279. rtos->thread_details->thread_name_str = malloc(sizeof(tmp_str));
  280. strcpy(rtos->thread_details->thread_name_str, tmp_str);
  281. if (thread_list_size == 0) {
  282. rtos->thread_count = 1;
  283. return ERROR_OK;
  284. }
  285. } else {
  286. /* create space for new thread details */
  287. rtos->thread_details = malloc(
  288. sizeof(struct thread_detail) * thread_list_size);
  289. }
  290. /* Read the pointer to the first thread */
  291. int64_t thread_ptr = 0;
  292. retval = target_read_buffer(rtos->target,
  293. rtos->symbols[THREADX_VAL_TX_THREAD_CREATED_PTR].address,
  294. param->pointer_width,
  295. (uint8_t *)&thread_ptr);
  296. if (retval != ERROR_OK) {
  297. LOG_ERROR("Could not read ThreadX thread location from target");
  298. return retval;
  299. }
  300. /* loop over all threads */
  301. int64_t prev_thread_ptr = 0;
  302. while ((thread_ptr != prev_thread_ptr) && (tasks_found < thread_list_size)) {
  303. #define THREADX_THREAD_NAME_STR_SIZE (200)
  304. char tmp_str[THREADX_THREAD_NAME_STR_SIZE];
  305. unsigned int i = 0;
  306. int64_t name_ptr = 0;
  307. /* Save the thread pointer */
  308. rtos->thread_details[tasks_found].threadid = thread_ptr;
  309. /* read the name pointer */
  310. retval = target_read_buffer(rtos->target,
  311. thread_ptr + param->thread_name_offset,
  312. param->pointer_width,
  313. (uint8_t *)&name_ptr);
  314. if (retval != ERROR_OK) {
  315. LOG_ERROR("Could not read ThreadX thread name pointer from target");
  316. return retval;
  317. }
  318. /* Read the thread name */
  319. retval =
  320. target_read_buffer(rtos->target,
  321. name_ptr,
  322. THREADX_THREAD_NAME_STR_SIZE,
  323. (uint8_t *)&tmp_str);
  324. if (retval != ERROR_OK) {
  325. LOG_ERROR("Error reading thread name from ThreadX target");
  326. return retval;
  327. }
  328. tmp_str[THREADX_THREAD_NAME_STR_SIZE-1] = '\x00';
  329. if (tmp_str[0] == '\x00')
  330. strcpy(tmp_str, "No Name");
  331. rtos->thread_details[tasks_found].thread_name_str =
  332. malloc(strlen(tmp_str)+1);
  333. strcpy(rtos->thread_details[tasks_found].thread_name_str, tmp_str);
  334. /* Read the thread status */
  335. int64_t thread_status = 0;
  336. retval = target_read_buffer(rtos->target,
  337. thread_ptr + param->thread_state_offset,
  338. 4,
  339. (uint8_t *)&thread_status);
  340. if (retval != ERROR_OK) {
  341. LOG_ERROR("Error reading thread state from ThreadX target");
  342. return retval;
  343. }
  344. for (i = 0; (i < THREADX_NUM_STATES) &&
  345. (threadx_thread_states[i].value != thread_status); i++) {
  346. /* empty */
  347. }
  348. const char *state_desc;
  349. if (i < THREADX_NUM_STATES)
  350. state_desc = threadx_thread_states[i].desc;
  351. else
  352. state_desc = "Unknown state";
  353. rtos->thread_details[tasks_found].extra_info_str = malloc(strlen(
  354. state_desc)+8);
  355. sprintf(rtos->thread_details[tasks_found].extra_info_str, "State: %s", state_desc);
  356. rtos->thread_details[tasks_found].exists = true;
  357. tasks_found++;
  358. prev_thread_ptr = thread_ptr;
  359. /* Get the location of the next thread structure. */
  360. thread_ptr = 0;
  361. retval = target_read_buffer(rtos->target,
  362. prev_thread_ptr + param->thread_next_offset,
  363. param->pointer_width,
  364. (uint8_t *) &thread_ptr);
  365. if (retval != ERROR_OK) {
  366. LOG_ERROR("Error reading next thread pointer in ThreadX thread list");
  367. return retval;
  368. }
  369. }
  370. rtos->thread_count = tasks_found;
  371. return 0;
  372. }
  373. static int threadx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
  374. struct rtos_reg **reg_list, int *num_regs)
  375. {
  376. int retval;
  377. const struct threadx_params *param;
  378. if (!rtos)
  379. return -1;
  380. if (!is_thread_id_valid(rtos, thread_id))
  381. return -2;
  382. if (!rtos->rtos_specific_params)
  383. return -3;
  384. param = (const struct threadx_params *) rtos->rtos_specific_params;
  385. /* Read the stack pointer */
  386. int64_t stack_ptr = 0;
  387. retval = target_read_buffer(rtos->target,
  388. thread_id + param->thread_stack_offset,
  389. param->pointer_width,
  390. (uint8_t *)&stack_ptr);
  391. if (retval != ERROR_OK) {
  392. LOG_ERROR("Error reading stack frame from ThreadX thread");
  393. return retval;
  394. }
  395. LOG_INFO("thread: 0x%" PRIx64 ", stack_ptr=0x%" PRIx64, (uint64_t)thread_id, (uint64_t)stack_ptr);
  396. if (stack_ptr == 0) {
  397. LOG_ERROR("null stack pointer in thread");
  398. return -5;
  399. }
  400. const struct rtos_register_stacking *stacking_info =
  401. get_stacking_info(rtos, stack_ptr);
  402. if (!stacking_info) {
  403. LOG_ERROR("Unknown stacking info for thread id=0x%" PRIx64, (uint64_t)thread_id);
  404. return -6;
  405. }
  406. return rtos_generic_stack_read(rtos->target, stacking_info, stack_ptr, reg_list, num_regs);
  407. }
  408. static int threadx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
  409. {
  410. unsigned int i;
  411. *symbol_list = calloc(
  412. ARRAY_SIZE(threadx_symbol_list), sizeof(struct symbol_table_elem));
  413. for (i = 0; i < ARRAY_SIZE(threadx_symbol_list); i++)
  414. (*symbol_list)[i].symbol_name = threadx_symbol_list[i];
  415. return 0;
  416. }
  417. static bool threadx_detect_rtos(struct target *target)
  418. {
  419. if ((target->rtos->symbols) &&
  420. (target->rtos->symbols[THREADX_VAL_TX_THREAD_CREATED_PTR].address != 0)) {
  421. /* looks like ThreadX */
  422. return true;
  423. }
  424. return false;
  425. }
  426. #if 0
  427. static int threadx_set_current_thread(struct rtos *rtos, threadid_t thread_id)
  428. {
  429. return 0;
  430. }
  431. static int threadx_get_thread_detail(struct rtos *rtos,
  432. threadid_t thread_id,
  433. struct thread_detail *detail)
  434. {
  435. unsigned int i = 0;
  436. int retval;
  437. #define THREADX_THREAD_NAME_STR_SIZE (200)
  438. char tmp_str[THREADX_THREAD_NAME_STR_SIZE];
  439. const struct threadx_params *param;
  440. if (!rtos)
  441. return -1;
  442. if (thread_id == 0)
  443. return -2;
  444. if (!rtos->rtos_specific_params)
  445. return -3;
  446. param = (const struct threadx_params *) rtos->rtos_specific_params;
  447. if (!rtos->symbols) {
  448. LOG_ERROR("No symbols for ThreadX");
  449. return -3;
  450. }
  451. detail->threadid = thread_id;
  452. int64_t name_ptr = 0;
  453. /* read the name pointer */
  454. retval = target_read_buffer(rtos->target,
  455. thread_id + param->thread_name_offset,
  456. param->pointer_width,
  457. (uint8_t *)&name_ptr);
  458. if (retval != ERROR_OK) {
  459. LOG_ERROR("Could not read ThreadX thread name pointer from target");
  460. return retval;
  461. }
  462. /* Read the thread name */
  463. retval = target_read_buffer(rtos->target,
  464. name_ptr,
  465. THREADX_THREAD_NAME_STR_SIZE,
  466. (uint8_t *)&tmp_str);
  467. if (retval != ERROR_OK) {
  468. LOG_ERROR("Error reading thread name from ThreadX target");
  469. return retval;
  470. }
  471. tmp_str[THREADX_THREAD_NAME_STR_SIZE-1] = '\x00';
  472. if (tmp_str[0] == '\x00')
  473. strcpy(tmp_str, "No Name");
  474. detail->thread_name_str = malloc(strlen(tmp_str)+1);
  475. /* Read the thread status */
  476. int64_t thread_status = 0;
  477. retval =
  478. target_read_buffer(rtos->target,
  479. thread_id + param->thread_state_offset,
  480. 4,
  481. (uint8_t *)&thread_status);
  482. if (retval != ERROR_OK) {
  483. LOG_ERROR("Error reading thread state from ThreadX target");
  484. return retval;
  485. }
  486. for (i = 0; (i < THREADX_NUM_STATES) &&
  487. (threadx_thread_states[i].value != thread_status); i++) {
  488. /* empty */
  489. }
  490. char *state_desc;
  491. if (i < THREADX_NUM_STATES)
  492. state_desc = threadx_thread_states[i].desc;
  493. else
  494. state_desc = "Unknown state";
  495. detail->extra_info_str = malloc(strlen(state_desc)+1);
  496. detail->exists = true;
  497. return 0;
  498. }
  499. #endif
  500. static int threadx_create(struct target *target)
  501. {
  502. for (unsigned int i = 0; i < ARRAY_SIZE(threadx_params_list); i++)
  503. if (strcmp(threadx_params_list[i].target_name, target->type->name) == 0) {
  504. target->rtos->rtos_specific_params = (void *)&threadx_params_list[i];
  505. target->rtos->current_thread = 0;
  506. target->rtos->thread_details = NULL;
  507. return 0;
  508. }
  509. LOG_ERROR("Could not find target in ThreadX compatibility list");
  510. return -1;
  511. }