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.
 
 
 
 
 
 

387 lines
11 KiB

  1. /***************************************************************************
  2. * *
  3. * This program is free software; you can redistribute it and/or modify *
  4. * it under the terms of the GNU General Public License as published by *
  5. * the Free Software Foundation; either version 2 of the License, or *
  6. * (at your option) any later version. *
  7. * *
  8. * This program is distributed in the hope that it will be useful, *
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  11. * GNU General Public License for more details. *
  12. * *
  13. * You should have received a copy of the GNU General Public License *
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>. *
  15. ***************************************************************************/
  16. #ifdef HAVE_CONFIG_H
  17. #include "config.h"
  18. #endif
  19. #include <helper/time_support.h>
  20. #include <jtag/jtag.h>
  21. #include "target/target.h"
  22. #include "target/target_type.h"
  23. #include "rtos.h"
  24. #include "helper/log.h"
  25. #include "helper/types.h"
  26. #include "rtos_ecos_stackings.h"
  27. static bool ecos_detect_rtos(struct target *target);
  28. static int ecos_create(struct target *target);
  29. static int ecos_update_threads(struct rtos *rtos);
  30. static int ecos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, struct rtos_reg **reg_list, int *num_regs);
  31. static int ecos_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]);
  32. struct ecos_thread_state {
  33. int value;
  34. const char *desc;
  35. };
  36. static const struct ecos_thread_state ecos_thread_states[] = {
  37. { 0, "Ready" },
  38. { 1, "Sleeping" },
  39. { 2, "Countsleep" },
  40. { 4, "Suspended" },
  41. { 8, "Creating" },
  42. { 16, "Exited" }
  43. };
  44. #define ECOS_NUM_STATES ARRAY_SIZE(ecos_thread_states)
  45. struct ecos_params {
  46. const char *target_name;
  47. unsigned char pointer_width;
  48. unsigned char thread_stack_offset;
  49. unsigned char thread_name_offset;
  50. unsigned char thread_state_offset;
  51. unsigned char thread_next_offset;
  52. unsigned char thread_uniqueid_offset;
  53. const struct rtos_register_stacking *stacking_info;
  54. };
  55. static const struct ecos_params ecos_params_list[] = {
  56. {
  57. "cortex_m", /* target_name */
  58. 4, /* pointer_width; */
  59. 0x0c, /* thread_stack_offset; */
  60. 0x9c, /* thread_name_offset; */
  61. 0x3c, /* thread_state_offset; */
  62. 0xa0, /* thread_next_offset */
  63. 0x4c, /* thread_uniqueid_offset */
  64. &rtos_ecos_cortex_m3_stacking /* stacking_info */
  65. }
  66. };
  67. enum ecos_symbol_values {
  68. ECOS_VAL_THREAD_LIST = 0,
  69. ECOS_VAL_CURRENT_THREAD_PTR = 1
  70. };
  71. static const char * const ecos_symbol_list[] = {
  72. "Cyg_Thread::thread_list",
  73. "Cyg_Scheduler_Base::current_thread",
  74. NULL
  75. };
  76. const struct rtos_type ecos_rtos = {
  77. .name = "eCos",
  78. .detect_rtos = ecos_detect_rtos,
  79. .create = ecos_create,
  80. .update_threads = ecos_update_threads,
  81. .get_thread_reg_list = ecos_get_thread_reg_list,
  82. .get_symbol_list_to_lookup = ecos_get_symbol_list_to_lookup,
  83. };
  84. static int ecos_update_threads(struct rtos *rtos)
  85. {
  86. int retval;
  87. int tasks_found = 0;
  88. int thread_list_size = 0;
  89. const struct ecos_params *param;
  90. if (!rtos)
  91. return -1;
  92. if (!rtos->rtos_specific_params)
  93. return -3;
  94. param = (const struct ecos_params *) rtos->rtos_specific_params;
  95. if (!rtos->symbols) {
  96. LOG_ERROR("No symbols for eCos");
  97. return -4;
  98. }
  99. if (rtos->symbols[ECOS_VAL_THREAD_LIST].address == 0) {
  100. LOG_ERROR("Don't have the thread list head");
  101. return -2;
  102. }
  103. /* wipe out previous thread details if any */
  104. rtos_free_threadlist(rtos);
  105. /* determine the number of current threads */
  106. uint32_t thread_list_head = rtos->symbols[ECOS_VAL_THREAD_LIST].address;
  107. uint32_t thread_index;
  108. target_read_buffer(rtos->target,
  109. thread_list_head,
  110. param->pointer_width,
  111. (uint8_t *) &thread_index);
  112. uint32_t first_thread = thread_index;
  113. do {
  114. thread_list_size++;
  115. retval = target_read_buffer(rtos->target,
  116. thread_index + param->thread_next_offset,
  117. param->pointer_width,
  118. (uint8_t *) &thread_index);
  119. if (retval != ERROR_OK)
  120. return retval;
  121. } while (thread_index != first_thread);
  122. /* read the current thread id */
  123. uint32_t current_thread_addr;
  124. retval = target_read_buffer(rtos->target,
  125. rtos->symbols[ECOS_VAL_CURRENT_THREAD_PTR].address,
  126. 4,
  127. (uint8_t *)&current_thread_addr);
  128. if (retval != ERROR_OK)
  129. return retval;
  130. rtos->current_thread = 0;
  131. retval = target_read_buffer(rtos->target,
  132. current_thread_addr + param->thread_uniqueid_offset,
  133. 2,
  134. (uint8_t *)&rtos->current_thread);
  135. if (retval != ERROR_OK) {
  136. LOG_ERROR("Could not read eCos current thread from target");
  137. return retval;
  138. }
  139. if ((thread_list_size == 0) || (rtos->current_thread == 0)) {
  140. /* Either : No RTOS threads - there is always at least the current execution though */
  141. /* OR : No current thread - all threads suspended - show the current execution
  142. * of idling */
  143. char tmp_str[] = "Current Execution";
  144. thread_list_size++;
  145. tasks_found++;
  146. rtos->thread_details = malloc(
  147. sizeof(struct thread_detail) * thread_list_size);
  148. rtos->thread_details->threadid = 1;
  149. rtos->thread_details->exists = true;
  150. rtos->thread_details->extra_info_str = NULL;
  151. rtos->thread_details->thread_name_str = malloc(sizeof(tmp_str));
  152. strcpy(rtos->thread_details->thread_name_str, tmp_str);
  153. if (thread_list_size == 0) {
  154. rtos->thread_count = 1;
  155. return ERROR_OK;
  156. }
  157. } else {
  158. /* create space for new thread details */
  159. rtos->thread_details = malloc(
  160. sizeof(struct thread_detail) * thread_list_size);
  161. }
  162. /* loop over all threads */
  163. thread_index = first_thread;
  164. do {
  165. #define ECOS_THREAD_NAME_STR_SIZE (200)
  166. char tmp_str[ECOS_THREAD_NAME_STR_SIZE];
  167. unsigned int i = 0;
  168. uint32_t name_ptr = 0;
  169. uint32_t prev_thread_ptr;
  170. /* Save the thread pointer */
  171. uint16_t thread_id;
  172. retval = target_read_buffer(rtos->target,
  173. thread_index + param->thread_uniqueid_offset,
  174. 2,
  175. (uint8_t *)&thread_id);
  176. if (retval != ERROR_OK) {
  177. LOG_ERROR("Could not read eCos thread id from target");
  178. return retval;
  179. }
  180. rtos->thread_details[tasks_found].threadid = thread_id;
  181. /* read the name pointer */
  182. retval = target_read_buffer(rtos->target,
  183. thread_index + param->thread_name_offset,
  184. param->pointer_width,
  185. (uint8_t *)&name_ptr);
  186. if (retval != ERROR_OK) {
  187. LOG_ERROR("Could not read eCos thread name pointer from target");
  188. return retval;
  189. }
  190. /* Read the thread name */
  191. retval =
  192. target_read_buffer(rtos->target,
  193. name_ptr,
  194. ECOS_THREAD_NAME_STR_SIZE,
  195. (uint8_t *)&tmp_str);
  196. if (retval != ERROR_OK) {
  197. LOG_ERROR("Error reading thread name from eCos target");
  198. return retval;
  199. }
  200. tmp_str[ECOS_THREAD_NAME_STR_SIZE-1] = '\x00';
  201. if (tmp_str[0] == '\x00')
  202. strcpy(tmp_str, "No Name");
  203. rtos->thread_details[tasks_found].thread_name_str =
  204. malloc(strlen(tmp_str)+1);
  205. strcpy(rtos->thread_details[tasks_found].thread_name_str, tmp_str);
  206. /* Read the thread status */
  207. int64_t thread_status = 0;
  208. retval = target_read_buffer(rtos->target,
  209. thread_index + param->thread_state_offset,
  210. 4,
  211. (uint8_t *)&thread_status);
  212. if (retval != ERROR_OK) {
  213. LOG_ERROR("Error reading thread state from eCos target");
  214. return retval;
  215. }
  216. for (i = 0; (i < ECOS_NUM_STATES) && (ecos_thread_states[i].value != thread_status); i++) {
  217. /*
  218. * empty
  219. */
  220. }
  221. const char *state_desc;
  222. if (i < ECOS_NUM_STATES)
  223. state_desc = ecos_thread_states[i].desc;
  224. else
  225. state_desc = "Unknown state";
  226. rtos->thread_details[tasks_found].extra_info_str = malloc(strlen(
  227. state_desc)+8);
  228. sprintf(rtos->thread_details[tasks_found].extra_info_str, "State: %s", state_desc);
  229. rtos->thread_details[tasks_found].exists = true;
  230. tasks_found++;
  231. prev_thread_ptr = thread_index;
  232. /* Get the location of the next thread structure. */
  233. thread_index = rtos->symbols[ECOS_VAL_THREAD_LIST].address;
  234. retval = target_read_buffer(rtos->target,
  235. prev_thread_ptr + param->thread_next_offset,
  236. param->pointer_width,
  237. (uint8_t *) &thread_index);
  238. if (retval != ERROR_OK) {
  239. LOG_ERROR("Error reading next thread pointer in eCos thread list");
  240. return retval;
  241. }
  242. } while (thread_index != first_thread);
  243. rtos->thread_count = tasks_found;
  244. return 0;
  245. }
  246. static int ecos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
  247. struct rtos_reg **reg_list, int *num_regs)
  248. {
  249. int retval;
  250. const struct ecos_params *param;
  251. if (!rtos)
  252. return -1;
  253. if (thread_id == 0)
  254. return -2;
  255. if (!rtos->rtos_specific_params)
  256. return -3;
  257. param = (const struct ecos_params *) rtos->rtos_specific_params;
  258. /* Find the thread with that thread id */
  259. uint16_t id = 0;
  260. uint32_t thread_list_head = rtos->symbols[ECOS_VAL_THREAD_LIST].address;
  261. uint32_t thread_index;
  262. target_read_buffer(rtos->target, thread_list_head, param->pointer_width,
  263. (uint8_t *)&thread_index);
  264. bool done = false;
  265. while (!done) {
  266. retval = target_read_buffer(rtos->target,
  267. thread_index + param->thread_uniqueid_offset,
  268. 2,
  269. (uint8_t *)&id);
  270. if (retval != ERROR_OK) {
  271. LOG_ERROR("Error reading unique id from eCos thread");
  272. return retval;
  273. }
  274. if (id == thread_id) {
  275. done = true;
  276. break;
  277. }
  278. target_read_buffer(rtos->target,
  279. thread_index + param->thread_next_offset,
  280. param->pointer_width,
  281. (uint8_t *) &thread_index);
  282. }
  283. if (done) {
  284. /* Read the stack pointer */
  285. int64_t stack_ptr = 0;
  286. retval = target_read_buffer(rtos->target,
  287. thread_index + param->thread_stack_offset,
  288. param->pointer_width,
  289. (uint8_t *)&stack_ptr);
  290. if (retval != ERROR_OK) {
  291. LOG_ERROR("Error reading stack frame from eCos thread");
  292. return retval;
  293. }
  294. return rtos_generic_stack_read(rtos->target,
  295. param->stacking_info,
  296. stack_ptr,
  297. reg_list,
  298. num_regs);
  299. }
  300. return -1;
  301. }
  302. static int ecos_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
  303. {
  304. unsigned int i;
  305. *symbol_list = calloc(
  306. ARRAY_SIZE(ecos_symbol_list), sizeof(struct symbol_table_elem));
  307. for (i = 0; i < ARRAY_SIZE(ecos_symbol_list); i++)
  308. (*symbol_list)[i].symbol_name = ecos_symbol_list[i];
  309. return 0;
  310. }
  311. static bool ecos_detect_rtos(struct target *target)
  312. {
  313. if ((target->rtos->symbols) &&
  314. (target->rtos->symbols[ECOS_VAL_THREAD_LIST].address != 0)) {
  315. /* looks like eCos */
  316. return true;
  317. }
  318. return false;
  319. }
  320. static int ecos_create(struct target *target)
  321. {
  322. for (unsigned int i = 0; i < ARRAY_SIZE(ecos_params_list); i++)
  323. if (strcmp(ecos_params_list[i].target_name, target->type->name) == 0) {
  324. target->rtos->rtos_specific_params = (void *)&ecos_params_list[i];
  325. target->rtos->current_thread = 0;
  326. target->rtos->thread_details = NULL;
  327. return 0;
  328. }
  329. LOG_ERROR("Could not find target in eCos compatibility list");
  330. return -1;
  331. }