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.
 
 
 
 
 
 

541 lines
17 KiB

  1. /***************************************************************************
  2. * Copyright (C) 2012 by Matthias Blaicher *
  3. * Matthias Blaicher - matthias@blaicher.com *
  4. * *
  5. * Copyright (C) 2011 by Broadcom Corporation *
  6. * Evan Hunter - ehunter@broadcom.com *
  7. * *
  8. * This program is free software; you can redistribute it and/or modify *
  9. * it under the terms of the GNU General Public License as published by *
  10. * the Free Software Foundation; either version 2 of the License, or *
  11. * (at your option) any later version. *
  12. * *
  13. * This program is distributed in the hope that it will be useful, *
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  16. * GNU General Public License for more details. *
  17. * *
  18. * You should have received a copy of the GNU General Public License *
  19. * along with this program. If not, see <http://www.gnu.org/licenses/>. *
  20. ***************************************************************************/
  21. #ifdef HAVE_CONFIG_H
  22. #include "config.h"
  23. #endif
  24. #include <helper/time_support.h>
  25. #include <jtag/jtag.h>
  26. #include "target/target.h"
  27. #include "target/target_type.h"
  28. #include "target/armv7m.h"
  29. #include "target/cortex_m.h"
  30. #include "rtos.h"
  31. #include "helper/log.h"
  32. #include "helper/types.h"
  33. #include "rtos_chibios_stackings.h"
  34. /**
  35. * @brief ChibiOS/RT memory signature record.
  36. *
  37. * @details Definition copied from os/kernel/include/chregistry.h of ChibiOS/RT.
  38. */
  39. struct chibios_chdebug {
  40. char ch_identifier[4]; /**< @brief Always set to "main". */
  41. uint8_t ch_zero; /**< @brief Must be zero. */
  42. uint8_t ch_size; /**< @brief Size of this structure. */
  43. uint16_t ch_version; /**< @brief Encoded ChibiOS/RT version. */
  44. uint8_t ch_ptrsize; /**< @brief Size of a pointer. */
  45. uint8_t ch_timesize; /**< @brief Size of a @p systime_t. */
  46. uint8_t ch_threadsize; /**< @brief Size of a @p Thread struct. */
  47. uint8_t cf_off_prio; /**< @brief Offset of @p p_prio field. */
  48. uint8_t cf_off_ctx; /**< @brief Offset of @p p_ctx field. */
  49. uint8_t cf_off_newer; /**< @brief Offset of @p p_newer field. */
  50. uint8_t cf_off_older; /**< @brief Offset of @p p_older field. */
  51. uint8_t cf_off_name; /**< @brief Offset of @p p_name field. */
  52. uint8_t cf_off_stklimit; /**< @brief Offset of @p p_stklimit
  53. field. */
  54. uint8_t cf_off_state; /**< @brief Offset of @p p_state field. */
  55. uint8_t cf_off_flags; /**< @brief Offset of @p p_flags field. */
  56. uint8_t cf_off_refs; /**< @brief Offset of @p p_refs field. */
  57. uint8_t cf_off_preempt; /**< @brief Offset of @p p_preempt
  58. field. */
  59. uint8_t cf_off_time; /**< @brief Offset of @p p_time field. */
  60. };
  61. #define GET_CH_KERNEL_MAJOR(coded_version) ((coded_version >> 11) & 0x1f)
  62. #define GET_CH_KERNEL_MINOR(coded_version) ((coded_version >> 6) & 0x1f)
  63. #define GET_CH_KERNEL_PATCH(coded_version) ((coded_version >> 0) & 0x3f)
  64. /**
  65. * @brief ChibiOS thread states.
  66. */
  67. static const char * const chibios_thread_states[] = { "READY", "CURRENT",
  68. "WTSTART", "SUSPENDED", "QUEUED", "WTSEM", "WTMTX", "WTCOND", "SLEEPING",
  69. "WTEXIT", "WTOREVT", "WTANDEVT", "SNDMSGQ", "SNDMSG", "WTMSG", "FINAL"
  70. };
  71. #define CHIBIOS_NUM_STATES ARRAY_SIZE(chibios_thread_states)
  72. /* Maximum ChibiOS thread name. There is no real limit set by ChibiOS but 64
  73. * chars ought to be enough.
  74. */
  75. #define CHIBIOS_THREAD_NAME_STR_SIZE (64)
  76. struct chibios_params {
  77. const char *target_name;
  78. struct chibios_chdebug *signature;
  79. const struct rtos_register_stacking *stacking_info;
  80. };
  81. static struct chibios_params chibios_params_list[] = {
  82. {
  83. "cortex_m", /* target_name */
  84. 0,
  85. NULL, /* stacking_info */
  86. },
  87. {
  88. "hla_target", /* target_name */
  89. 0,
  90. NULL, /* stacking_info */
  91. }
  92. };
  93. static bool chibios_detect_rtos(struct target *target);
  94. static int chibios_create(struct target *target);
  95. static int chibios_update_threads(struct rtos *rtos);
  96. static int chibios_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
  97. struct rtos_reg **reg_list, int *num_regs);
  98. static int chibios_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[]);
  99. struct rtos_type chibios_rtos = {
  100. .name = "chibios",
  101. .detect_rtos = chibios_detect_rtos,
  102. .create = chibios_create,
  103. .update_threads = chibios_update_threads,
  104. .get_thread_reg_list = chibios_get_thread_reg_list,
  105. .get_symbol_list_to_lookup = chibios_get_symbol_list_to_lookup,
  106. };
  107. /* In ChibiOS/RT 3.0 the rlist structure has become part of a system
  108. * data structure ch. We declare both symbols as optional and later
  109. * use whatever is available.
  110. */
  111. enum chibios_symbol_values {
  112. CHIBIOS_VAL_RLIST = 0,
  113. CHIBIOS_VAL_CH = 1,
  114. CHIBIOS_VAL_CH_DEBUG = 2
  115. };
  116. static struct symbol_table_elem chibios_symbol_list[] = {
  117. { "rlist", 0, true}, /* Thread ready list */
  118. { "ch", 0, true}, /* System data structure */
  119. { "ch_debug", 0, false}, /* Memory Signature containing offsets of fields in rlist */
  120. { NULL, 0, false}
  121. };
  122. /* Offset of the rlist structure within the system data structure (ch) */
  123. #define CH_RLIST_OFFSET 0x00
  124. static int chibios_update_memory_signature(struct rtos *rtos)
  125. {
  126. int retval;
  127. struct chibios_params *param;
  128. struct chibios_chdebug *signature;
  129. param = (struct chibios_params *) rtos->rtos_specific_params;
  130. /* Free existing memory description.*/
  131. free(param->signature);
  132. param->signature = NULL;
  133. signature = malloc(sizeof(*signature));
  134. if (!signature) {
  135. LOG_ERROR("Could not allocate space for ChibiOS/RT memory signature");
  136. return -1;
  137. }
  138. retval = target_read_buffer(rtos->target,
  139. rtos->symbols[CHIBIOS_VAL_CH_DEBUG].address,
  140. sizeof(*signature),
  141. (uint8_t *) signature);
  142. if (retval != ERROR_OK) {
  143. LOG_ERROR("Could not read ChibiOS/RT memory signature from target");
  144. goto errfree;
  145. }
  146. if (strncmp(signature->ch_identifier, "main", 4) != 0) {
  147. LOG_ERROR("Memory signature identifier does not contain magic bytes.");
  148. goto errfree;
  149. }
  150. if (signature->ch_size < sizeof(*signature)) {
  151. LOG_ERROR("ChibiOS/RT memory signature claims to be smaller "
  152. "than expected");
  153. goto errfree;
  154. }
  155. if (signature->ch_size > sizeof(*signature)) {
  156. LOG_WARNING("ChibiOS/RT memory signature claims to be bigger than"
  157. " expected. Assuming compatibility...");
  158. }
  159. /* Convert endianness of version field */
  160. const uint8_t *versiontarget = (const uint8_t *)
  161. &signature->ch_version;
  162. signature->ch_version = rtos->target->endianness == TARGET_LITTLE_ENDIAN ?
  163. le_to_h_u32(versiontarget) : be_to_h_u32(versiontarget);
  164. const uint16_t ch_version = signature->ch_version;
  165. LOG_INFO("Successfully loaded memory map of ChibiOS/RT target "
  166. "running version %i.%i.%i", GET_CH_KERNEL_MAJOR(ch_version),
  167. GET_CH_KERNEL_MINOR(ch_version), GET_CH_KERNEL_PATCH(ch_version));
  168. /* Currently, we have the inherent assumption that all address pointers
  169. * are 32 bit wide. */
  170. if (signature->ch_ptrsize != sizeof(uint32_t)) {
  171. LOG_ERROR("ChibiOS/RT target memory signature claims an address "
  172. "width unequal to 32 bits!");
  173. free(signature);
  174. return -1;
  175. }
  176. param->signature = signature;
  177. return 0;
  178. errfree:
  179. /* Error reading the ChibiOS memory structure */
  180. free(signature);
  181. param->signature = 0;
  182. return -1;
  183. }
  184. static int chibios_update_stacking(struct rtos *rtos)
  185. {
  186. /* Sometimes the stacking can not be determined only by looking at the
  187. * target name but only a runtime.
  188. *
  189. * For example, this is the case for Cortex-M4 targets and ChibiOS which
  190. * only stack the FPU registers if it is enabled during ChibiOS build.
  191. *
  192. * Terminating which stacking is used is target depending.
  193. *
  194. * Assumptions:
  195. * - Once ChibiOS is actually initialized, the stacking is fixed.
  196. * - During startup code, the FPU might not be initialized and the
  197. * detection might fail.
  198. * - Since no threads are running during startup, the problem is solved
  199. * by delaying stacking detection until there are more threads
  200. * available than the current execution. In which case
  201. * chibios_get_thread_reg_list is called.
  202. */
  203. int retval;
  204. if (!rtos->rtos_specific_params)
  205. return -1;
  206. struct chibios_params *param;
  207. param = (struct chibios_params *) rtos->rtos_specific_params;
  208. /* Check for armv7m with *enabled* FPU, i.e. a Cortex-M4 */
  209. struct armv7m_common *armv7m_target = target_to_armv7m(rtos->target);
  210. if (is_armv7m(armv7m_target)) {
  211. if (armv7m_target->fp_feature != FP_NONE) {
  212. /* Found ARM v7m target which includes a FPU */
  213. uint32_t cpacr;
  214. retval = target_read_u32(rtos->target, FPU_CPACR, &cpacr);
  215. if (retval != ERROR_OK) {
  216. LOG_ERROR("Could not read CPACR register to check FPU state");
  217. return -1;
  218. }
  219. /* Check if CP10 and CP11 are set to full access.
  220. * In ChibiOS this is done in ResetHandler() in crt0.c */
  221. if (cpacr & 0x00F00000) {
  222. LOG_DEBUG("Enabled FPU detected.");
  223. param->stacking_info = &rtos_chibios_arm_v7m_stacking_w_fpu;
  224. return 0;
  225. }
  226. }
  227. /* Found ARM v7m target with no or disabled FPU */
  228. param->stacking_info = &rtos_chibios_arm_v7m_stacking;
  229. return 0;
  230. }
  231. return -1;
  232. }
  233. static int chibios_update_threads(struct rtos *rtos)
  234. {
  235. int retval;
  236. const struct chibios_params *param;
  237. int tasks_found = 0;
  238. int rtos_valid = -1;
  239. if (!rtos->rtos_specific_params)
  240. return -1;
  241. if (!rtos->symbols) {
  242. LOG_ERROR("No symbols for ChibiOS");
  243. return -3;
  244. }
  245. param = (const struct chibios_params *) rtos->rtos_specific_params;
  246. /* Update the memory signature saved in the target memory */
  247. if (!param->signature) {
  248. retval = chibios_update_memory_signature(rtos);
  249. if (retval != ERROR_OK) {
  250. LOG_ERROR("Reading the memory signature of ChibiOS/RT failed");
  251. return retval;
  252. }
  253. }
  254. /* wipe out previous thread details if any */
  255. rtos_free_threadlist(rtos);
  256. /* ChibiOS does not save the current thread count. We have to first
  257. * parse the double linked thread list to check for errors and the number of
  258. * threads. */
  259. const uint32_t rlist = rtos->symbols[CHIBIOS_VAL_RLIST].address ?
  260. rtos->symbols[CHIBIOS_VAL_RLIST].address :
  261. rtos->symbols[CHIBIOS_VAL_CH].address + CH_RLIST_OFFSET /* ChibiOS3 */;
  262. const struct chibios_chdebug *signature = param->signature;
  263. uint32_t current;
  264. uint32_t previous;
  265. uint32_t older;
  266. current = rlist;
  267. previous = rlist;
  268. while (1) {
  269. retval = target_read_u32(rtos->target,
  270. current + signature->cf_off_newer, &current);
  271. if (retval != ERROR_OK) {
  272. LOG_ERROR("Could not read next ChibiOS thread");
  273. return retval;
  274. }
  275. /* Could be NULL if the kernel is not initialized yet or if the
  276. * registry is corrupted. */
  277. if (current == 0) {
  278. LOG_ERROR("ChibiOS registry integrity check failed, NULL pointer");
  279. rtos_valid = 0;
  280. break;
  281. }
  282. /* Fetch previous thread in the list as a integrity check. */
  283. retval = target_read_u32(rtos->target,
  284. current + signature->cf_off_older, &older);
  285. if ((retval != ERROR_OK) || (older == 0) || (older != previous)) {
  286. LOG_ERROR("ChibiOS registry integrity check failed, "
  287. "double linked list violation");
  288. rtos_valid = 0;
  289. break;
  290. }
  291. /* Check for full iteration of the linked list. */
  292. if (current == rlist)
  293. break;
  294. tasks_found++;
  295. previous = current;
  296. }
  297. if (!rtos_valid) {
  298. /* No RTOS, there is always at least the current execution, though */
  299. LOG_INFO("Only showing current execution because of a broken "
  300. "ChibiOS thread registry.");
  301. const char tmp_thread_name[] = "Current Execution";
  302. const char tmp_thread_extra_info[] = "No RTOS thread";
  303. rtos->thread_details = malloc(
  304. sizeof(struct thread_detail));
  305. rtos->thread_details->threadid = 1;
  306. rtos->thread_details->exists = true;
  307. rtos->thread_details->extra_info_str = malloc(
  308. sizeof(tmp_thread_extra_info));
  309. strcpy(rtos->thread_details->extra_info_str, tmp_thread_extra_info);
  310. rtos->thread_details->thread_name_str = malloc(
  311. sizeof(tmp_thread_name));
  312. strcpy(rtos->thread_details->thread_name_str, tmp_thread_name);
  313. rtos->current_thread = 1;
  314. rtos->thread_count = 1;
  315. return ERROR_OK;
  316. }
  317. /* create space for new thread details */
  318. rtos->thread_details = malloc(
  319. sizeof(struct thread_detail) * tasks_found);
  320. if (!rtos->thread_details) {
  321. LOG_ERROR("Could not allocate space for thread details");
  322. return -1;
  323. }
  324. rtos->thread_count = tasks_found;
  325. /* Loop through linked list. */
  326. struct thread_detail *curr_thrd_details = rtos->thread_details;
  327. while (curr_thrd_details < rtos->thread_details + tasks_found) {
  328. uint32_t name_ptr = 0;
  329. char tmp_str[CHIBIOS_THREAD_NAME_STR_SIZE];
  330. retval = target_read_u32(rtos->target,
  331. current + signature->cf_off_newer, &current);
  332. if (retval != ERROR_OK) {
  333. LOG_ERROR("Could not read next ChibiOS thread");
  334. return -6;
  335. }
  336. /* Check for full iteration of the linked list. */
  337. if (current == rlist)
  338. break;
  339. /* Save the thread pointer */
  340. curr_thrd_details->threadid = current;
  341. /* read the name pointer */
  342. retval = target_read_u32(rtos->target,
  343. current + signature->cf_off_name, &name_ptr);
  344. if (retval != ERROR_OK) {
  345. LOG_ERROR("Could not read ChibiOS thread name pointer from target");
  346. return retval;
  347. }
  348. /* Read the thread name */
  349. retval = target_read_buffer(rtos->target, name_ptr,
  350. CHIBIOS_THREAD_NAME_STR_SIZE,
  351. (uint8_t *)&tmp_str);
  352. if (retval != ERROR_OK) {
  353. LOG_ERROR("Error reading thread name from ChibiOS target");
  354. return retval;
  355. }
  356. tmp_str[CHIBIOS_THREAD_NAME_STR_SIZE - 1] = '\x00';
  357. if (tmp_str[0] == '\x00')
  358. strcpy(tmp_str, "No Name");
  359. curr_thrd_details->thread_name_str = malloc(
  360. strlen(tmp_str) + 1);
  361. strcpy(curr_thrd_details->thread_name_str, tmp_str);
  362. /* State info */
  363. uint8_t thread_state;
  364. const char *state_desc;
  365. retval = target_read_u8(rtos->target,
  366. current + signature->cf_off_state, &thread_state);
  367. if (retval != ERROR_OK) {
  368. LOG_ERROR("Error reading thread state from ChibiOS target");
  369. return retval;
  370. }
  371. if (thread_state < CHIBIOS_NUM_STATES)
  372. state_desc = chibios_thread_states[thread_state];
  373. else
  374. state_desc = "Unknown";
  375. curr_thrd_details->extra_info_str = malloc(strlen(
  376. state_desc)+8);
  377. sprintf(curr_thrd_details->extra_info_str, "State: %s", state_desc);
  378. curr_thrd_details->exists = true;
  379. curr_thrd_details++;
  380. }
  381. uint32_t current_thrd;
  382. /* NOTE: By design, cf_off_name equals readylist_current_offset */
  383. retval = target_read_u32(rtos->target,
  384. rlist + signature->cf_off_name,
  385. &current_thrd);
  386. if (retval != ERROR_OK) {
  387. LOG_ERROR("Could not read current Thread from ChibiOS target");
  388. return retval;
  389. }
  390. rtos->current_thread = current_thrd;
  391. return 0;
  392. }
  393. static int chibios_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
  394. struct rtos_reg **reg_list, int *num_regs)
  395. {
  396. int retval;
  397. const struct chibios_params *param;
  398. uint32_t stack_ptr = 0;
  399. if ((!rtos) || (thread_id == 0) ||
  400. (!rtos->rtos_specific_params))
  401. return -1;
  402. param = (const struct chibios_params *) rtos->rtos_specific_params;
  403. if (!param->signature)
  404. return -1;
  405. /* Update stacking if it can only be determined from runtime information */
  406. if ((param->stacking_info == 0) &&
  407. (chibios_update_stacking(rtos) != ERROR_OK)) {
  408. LOG_ERROR("Failed to determine exact stacking for the target type %s", rtos->target->type->name);
  409. return -1;
  410. }
  411. /* Read the stack pointer */
  412. retval = target_read_u32(rtos->target,
  413. thread_id + param->signature->cf_off_ctx, &stack_ptr);
  414. if (retval != ERROR_OK) {
  415. LOG_ERROR("Error reading stack frame from ChibiOS thread");
  416. return retval;
  417. }
  418. return rtos_generic_stack_read(rtos->target, param->stacking_info, stack_ptr, reg_list, num_regs);
  419. }
  420. static int chibios_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
  421. {
  422. *symbol_list = malloc(sizeof(chibios_symbol_list));
  423. if (!*symbol_list)
  424. return ERROR_FAIL;
  425. memcpy(*symbol_list, chibios_symbol_list, sizeof(chibios_symbol_list));
  426. return 0;
  427. }
  428. static bool chibios_detect_rtos(struct target *target)
  429. {
  430. if ((target->rtos->symbols) &&
  431. ((target->rtos->symbols[CHIBIOS_VAL_RLIST].address != 0) ||
  432. (target->rtos->symbols[CHIBIOS_VAL_CH].address != 0))) {
  433. if (target->rtos->symbols[CHIBIOS_VAL_CH_DEBUG].address == 0) {
  434. LOG_INFO("It looks like the target may be running ChibiOS "
  435. "without ch_debug.");
  436. return false;
  437. }
  438. /* looks like ChibiOS with memory map enabled.*/
  439. return true;
  440. }
  441. return false;
  442. }
  443. static int chibios_create(struct target *target)
  444. {
  445. for (unsigned int i = 0; i < ARRAY_SIZE(chibios_params_list); i++)
  446. if (strcmp(chibios_params_list[i].target_name, target->type->name) == 0) {
  447. target->rtos->rtos_specific_params = (void *)&chibios_params_list[i];
  448. return 0;
  449. }
  450. LOG_WARNING("Could not find target \"%s\" in ChibiOS compatibility "
  451. "list", target->type->name);
  452. return -1;
  453. }