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.
 
 
 
 
 
 

429 lines
11 KiB

  1. /***************************************************************************
  2. * Copyright (C) 2015 by Daniel Krebs *
  3. * Daniel Krebs - github@daniel-krebs.net *
  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 "target/armv7m.h"
  29. #include "rtos_riot_stackings.h"
  30. static bool riot_detect_rtos(struct target *target);
  31. static int riot_create(struct target *target);
  32. static int riot_update_threads(struct rtos *rtos);
  33. static int riot_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
  34. struct rtos_reg **reg_list, int *num_regs);
  35. static int riot_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]);
  36. struct riot_thread_state {
  37. int value;
  38. const char *desc;
  39. };
  40. /* refer RIOT sched.h */
  41. static const struct riot_thread_state riot_thread_states[] = {
  42. { 0, "Stopped" },
  43. { 1, "Zombie" },
  44. { 2, "Sleeping" },
  45. { 3, "Blocked mutex" },
  46. { 4, "Blocked receive" },
  47. { 5, "Blocked send" },
  48. { 6, "Blocked reply" },
  49. { 7, "Blocked any flag" },
  50. { 8, "Blocked all flags" },
  51. { 9, "Blocked mbox" },
  52. { 10, "Blocked condition" },
  53. { 11, "Running" },
  54. { 12, "Pending" },
  55. };
  56. #define RIOT_NUM_STATES ARRAY_SIZE(riot_thread_states)
  57. struct riot_params {
  58. const char *target_name;
  59. unsigned char thread_sp_offset;
  60. unsigned char thread_status_offset;
  61. };
  62. static const struct riot_params riot_params_list[] = {
  63. {
  64. "cortex_m", /* target_name */
  65. 0x00, /* thread_sp_offset */
  66. 0x04, /* thread_status_offset */
  67. },
  68. { /* STLink */
  69. "hla_target", /* target_name */
  70. 0x00, /* thread_sp_offset */
  71. 0x04, /* thread_status_offset */
  72. }
  73. };
  74. #define RIOT_NUM_PARAMS ARRAY_SIZE(riot_params_list)
  75. /* Initialize in riot_create() depending on architecture */
  76. static const struct rtos_register_stacking *stacking_info;
  77. enum riot_symbol_values {
  78. RIOT_THREADS_BASE = 0,
  79. RIOT_NUM_THREADS,
  80. RIOT_ACTIVE_PID,
  81. RIOT_MAX_THREADS,
  82. RIOT_NAME_OFFSET,
  83. };
  84. /* refer RIOT core/sched.c */
  85. static const char *const riot_symbol_list[] = {
  86. "sched_threads",
  87. "sched_num_threads",
  88. "sched_active_pid",
  89. "max_threads",
  90. "_tcb_name_offset",
  91. NULL
  92. };
  93. /* Define which symbols are not mandatory */
  94. static const enum riot_symbol_values riot_optional_symbols[] = {
  95. RIOT_NAME_OFFSET,
  96. };
  97. const struct rtos_type riot_rtos = {
  98. .name = "RIOT",
  99. .detect_rtos = riot_detect_rtos,
  100. .create = riot_create,
  101. .update_threads = riot_update_threads,
  102. .get_thread_reg_list = riot_get_thread_reg_list,
  103. .get_symbol_list_to_lookup = riot_get_symbol_list_to_lookup,
  104. };
  105. static int riot_update_threads(struct rtos *rtos)
  106. {
  107. int retval;
  108. unsigned int tasks_found = 0;
  109. const struct riot_params *param;
  110. if (!rtos)
  111. return ERROR_FAIL;
  112. if (!rtos->rtos_specific_params)
  113. return ERROR_FAIL;
  114. param = (const struct riot_params *)rtos->rtos_specific_params;
  115. if (!rtos->symbols) {
  116. LOG_ERROR("No symbols for RIOT");
  117. return ERROR_FAIL;
  118. }
  119. if (rtos->symbols[RIOT_THREADS_BASE].address == 0) {
  120. LOG_ERROR("Can't find symbol `%s`",
  121. riot_symbol_list[RIOT_THREADS_BASE]);
  122. return ERROR_FAIL;
  123. }
  124. /* wipe out previous thread details if any */
  125. rtos_free_threadlist(rtos);
  126. /* Reset values */
  127. rtos->current_thread = 0;
  128. rtos->thread_count = 0;
  129. /* read the current thread id */
  130. int16_t active_pid = 0;
  131. retval = target_read_u16(rtos->target,
  132. rtos->symbols[RIOT_ACTIVE_PID].address,
  133. (uint16_t *)&active_pid);
  134. if (retval != ERROR_OK) {
  135. LOG_ERROR("Can't read symbol `%s`",
  136. riot_symbol_list[RIOT_ACTIVE_PID]);
  137. return retval;
  138. }
  139. rtos->current_thread = active_pid;
  140. /* read the current thread count
  141. * It's `int` in RIOT, but this is Cortex M* only anyway */
  142. int32_t thread_count = 0;
  143. retval = target_read_u16(rtos->target,
  144. rtos->symbols[RIOT_NUM_THREADS].address,
  145. (uint16_t *)&thread_count);
  146. if (retval != ERROR_OK) {
  147. LOG_ERROR("Can't read symbol `%s`",
  148. riot_symbol_list[RIOT_NUM_THREADS]);
  149. return retval;
  150. }
  151. rtos->thread_count = thread_count;
  152. /* read the maximum number of threads */
  153. uint8_t max_threads = 0;
  154. retval = target_read_u8(rtos->target,
  155. rtos->symbols[RIOT_MAX_THREADS].address,
  156. &max_threads);
  157. if (retval != ERROR_OK) {
  158. LOG_ERROR("Can't read symbol `%s`",
  159. riot_symbol_list[RIOT_MAX_THREADS]);
  160. return retval;
  161. }
  162. /* Base address of thread array */
  163. uint32_t threads_base = rtos->symbols[RIOT_THREADS_BASE].address;
  164. /* Try to get the offset of tcb_t::name, if absent RIOT wasn't compiled
  165. * with DEVELHELP, so there are no thread names */
  166. uint8_t name_offset = 0;
  167. if (rtos->symbols[RIOT_NAME_OFFSET].address != 0) {
  168. retval = target_read_u8(rtos->target,
  169. rtos->symbols[RIOT_NAME_OFFSET].address,
  170. &name_offset);
  171. if (retval != ERROR_OK) {
  172. LOG_ERROR("Can't read symbol `%s`",
  173. riot_symbol_list[RIOT_NAME_OFFSET]);
  174. return retval;
  175. }
  176. }
  177. /* Allocate memory for thread description */
  178. rtos->thread_details = calloc(thread_count, sizeof(struct thread_detail));
  179. if (!rtos->thread_details) {
  180. LOG_ERROR("RIOT: out of memory");
  181. return ERROR_FAIL;
  182. }
  183. /* Buffer for thread names, maximum to display is 32 */
  184. char buffer[32];
  185. for (unsigned int i = 0; i < max_threads; i++) {
  186. /* get pointer to tcb_t */
  187. uint32_t tcb_pointer = 0;
  188. retval = target_read_u32(rtos->target,
  189. threads_base + (i * 4),
  190. &tcb_pointer);
  191. if (retval != ERROR_OK) {
  192. LOG_ERROR("Can't parse `%s`", riot_symbol_list[RIOT_THREADS_BASE]);
  193. goto error;
  194. }
  195. if (tcb_pointer == 0) {
  196. /* PID unused */
  197. continue;
  198. }
  199. /* Index is PID */
  200. rtos->thread_details[tasks_found].threadid = i;
  201. /* read thread state */
  202. uint8_t status = 0;
  203. retval = target_read_u8(rtos->target,
  204. tcb_pointer + param->thread_status_offset,
  205. &status);
  206. if (retval != ERROR_OK) {
  207. LOG_ERROR("Can't parse `%s`", riot_symbol_list[RIOT_THREADS_BASE]);
  208. goto error;
  209. }
  210. /* Search for state */
  211. unsigned int k;
  212. for (k = 0; k < RIOT_NUM_STATES; k++) {
  213. if (riot_thread_states[k].value == status)
  214. break;
  215. }
  216. /* Copy state string */
  217. if (k >= RIOT_NUM_STATES) {
  218. rtos->thread_details[tasks_found].extra_info_str =
  219. strdup("unknown state");
  220. } else {
  221. rtos->thread_details[tasks_found].extra_info_str =
  222. strdup(riot_thread_states[k].desc);
  223. }
  224. if (!rtos->thread_details[tasks_found].extra_info_str) {
  225. LOG_ERROR("RIOT: out of memory");
  226. retval = ERROR_FAIL;
  227. goto error;
  228. }
  229. /* Thread names are only available if compiled with DEVELHELP */
  230. if (name_offset != 0) {
  231. uint32_t name_pointer = 0;
  232. retval = target_read_u32(rtos->target,
  233. tcb_pointer + name_offset,
  234. &name_pointer);
  235. if (retval != ERROR_OK) {
  236. LOG_ERROR("Can't parse `%s`",
  237. riot_symbol_list[RIOT_THREADS_BASE]);
  238. goto error;
  239. }
  240. /* read thread name */
  241. retval = target_read_buffer(rtos->target,
  242. name_pointer,
  243. sizeof(buffer),
  244. (uint8_t *)&buffer);
  245. if (retval != ERROR_OK) {
  246. LOG_ERROR("Can't parse `%s`",
  247. riot_symbol_list[RIOT_THREADS_BASE]);
  248. goto error;
  249. }
  250. /* Make sure the string in the buffer terminates */
  251. if (buffer[sizeof(buffer) - 1] != 0)
  252. buffer[sizeof(buffer) - 1] = 0;
  253. /* Copy thread name */
  254. rtos->thread_details[tasks_found].thread_name_str =
  255. strdup(buffer);
  256. } else {
  257. rtos->thread_details[tasks_found].thread_name_str =
  258. strdup("Enable DEVELHELP to see task names");
  259. }
  260. if (!rtos->thread_details[tasks_found].thread_name_str) {
  261. LOG_ERROR("RIOT: out of memory");
  262. retval = ERROR_FAIL;
  263. goto error;
  264. }
  265. rtos->thread_details[tasks_found].exists = true;
  266. tasks_found++;
  267. }
  268. return ERROR_OK;
  269. error:
  270. rtos_free_threadlist(rtos);
  271. return retval;
  272. }
  273. static int riot_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
  274. struct rtos_reg **reg_list, int *num_regs)
  275. {
  276. int retval;
  277. const struct riot_params *param;
  278. if (!rtos)
  279. return ERROR_FAIL;
  280. if (thread_id == 0)
  281. return ERROR_FAIL;
  282. if (!rtos->rtos_specific_params)
  283. return ERROR_FAIL;
  284. param = (const struct riot_params *)rtos->rtos_specific_params;
  285. /* find the thread with given thread id */
  286. uint32_t threads_base = rtos->symbols[RIOT_THREADS_BASE].address;
  287. uint32_t tcb_pointer = 0;
  288. retval = target_read_u32(rtos->target,
  289. threads_base + (thread_id * 4),
  290. &tcb_pointer);
  291. if (retval != ERROR_OK) {
  292. LOG_ERROR("Can't parse `%s`", riot_symbol_list[RIOT_THREADS_BASE]);
  293. return retval;
  294. }
  295. /* read stack pointer for that thread */
  296. uint32_t stackptr = 0;
  297. retval = target_read_u32(rtos->target,
  298. tcb_pointer + param->thread_sp_offset,
  299. &stackptr);
  300. if (retval != ERROR_OK) {
  301. LOG_ERROR("Can't parse `%s`", riot_symbol_list[RIOT_THREADS_BASE]);
  302. return retval;
  303. }
  304. return rtos_generic_stack_read(rtos->target,
  305. stacking_info,
  306. stackptr,
  307. reg_list,
  308. num_regs);
  309. }
  310. static int riot_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
  311. {
  312. *symbol_list = calloc(ARRAY_SIZE(riot_symbol_list), sizeof(struct symbol_table_elem));
  313. if (!*symbol_list) {
  314. LOG_ERROR("RIOT: out of memory");
  315. return ERROR_FAIL;
  316. }
  317. for (unsigned int i = 0; i < ARRAY_SIZE(riot_symbol_list); i++) {
  318. (*symbol_list)[i].symbol_name = riot_symbol_list[i];
  319. (*symbol_list)[i].optional = false;
  320. /* Lookup if symbol is optional */
  321. for (unsigned int k = 0; k < sizeof(riot_optional_symbols); k++) {
  322. if (i == riot_optional_symbols[k]) {
  323. (*symbol_list)[i].optional = true;
  324. break;
  325. }
  326. }
  327. }
  328. return ERROR_OK;
  329. }
  330. static bool riot_detect_rtos(struct target *target)
  331. {
  332. if ((target->rtos->symbols) &&
  333. (target->rtos->symbols[RIOT_THREADS_BASE].address != 0)) {
  334. /* looks like RIOT */
  335. return true;
  336. }
  337. return false;
  338. }
  339. static int riot_create(struct target *target)
  340. {
  341. unsigned int i = 0;
  342. /* lookup if target is supported by RIOT */
  343. while ((i < RIOT_NUM_PARAMS) &&
  344. (0 != strcmp(riot_params_list[i].target_name, target->type->name))) {
  345. i++;
  346. }
  347. if (i >= RIOT_NUM_PARAMS) {
  348. LOG_ERROR("Could not find target in RIOT compatibility list");
  349. return ERROR_FAIL;
  350. }
  351. target->rtos->rtos_specific_params = (void *)&riot_params_list[i];
  352. target->rtos->current_thread = 0;
  353. target->rtos->thread_details = NULL;
  354. /* Stacking is different depending on architecture */
  355. struct armv7m_common *armv7m_target = target_to_armv7m(target);
  356. if (armv7m_target->arm.arch == ARM_ARCH_V6M)
  357. stacking_info = &rtos_riot_cortex_m0_stacking;
  358. else if (is_armv7m(armv7m_target))
  359. stacking_info = &rtos_riot_cortex_m34_stacking;
  360. else {
  361. LOG_ERROR("No stacking info for architecture");
  362. return ERROR_FAIL;
  363. }
  364. return ERROR_OK;
  365. }