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.
 
 
 
 
 
 

520 lines
16 KiB

  1. /***************************************************************************
  2. * Copyright (C) 2014 by Marian Cingel *
  3. * cingel.marian@gmail.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 <stdint.h>
  22. #include <helper/time_support.h>
  23. #include <jtag/jtag.h>
  24. #include "target/target.h"
  25. #include "target/target_type.h"
  26. #include "rtos.h"
  27. #include "helper/log.h"
  28. #include "helper/types.h"
  29. #include "rtos_mqx_stackings.h"
  30. /* constants */
  31. #define MQX_THREAD_NAME_LENGTH (255)
  32. #define MQX_KERNEL_OFFSET_TDLIST (0x0108)
  33. #define MQX_KERNEL_OFFSET_SYSTEM_TASK (0x0050)
  34. #define MQX_KERNEL_OFFSET_ACTIVE_TASK (0x001C)
  35. #define MQX_KERNEL_OFFSET_CAPABILITY (0x0000)
  36. #define MQX_QUEUE_OFFSET_SIZE (0x0008)
  37. #define MQX_TASK_OFFSET_STATE (0x0008)
  38. #define MQX_TASK_OFFSET_ID (0x000c)
  39. #define MQX_TASK_OFFSET_TEMPLATE (0x0068)
  40. #define MQX_TASK_OFFSET_STACK (0x0014)
  41. #define MQX_TASK_OFFSET_TDLIST (0x006C)
  42. #define MQX_TASK_OFFSET_NEXT (0x0000)
  43. #define MQX_TASK_TEMPLATE_OFFSET_NAME (0x0010)
  44. #define MQX_TASK_OFFSET_ERROR_CODE (0x005C)
  45. #define MQX_TASK_STATE_MASK (0xFFF)
  46. /* types */
  47. enum mqx_symbols {
  48. MQX_VAL_MQX_KERNEL_DATA,
  49. MQX_VAL_MQX_INIT_STRUCT,
  50. };
  51. enum mqx_arch {
  52. mqx_arch_cortexm,
  53. };
  54. struct mqx_params {
  55. const char *target_name;
  56. const enum mqx_arch target_arch;
  57. const struct rtos_register_stacking *stacking_info;
  58. };
  59. struct mqx_state {
  60. uint32_t state;
  61. char *name;
  62. };
  63. /* local data */
  64. static const struct mqx_state mqx_states[] = {
  65. { 0x0002, "READY" },
  66. { 0x0003, "BLOCKED" },
  67. { 0x0005, "RCV_SPECIFIC_BLOCKED" },
  68. { 0x0007, "RCV_ANY_BLOCKED" },
  69. { 0x0009, "DYING" },
  70. { 0x000B, "UNHANDLED_INT_BLOCKED" },
  71. { 0x000D, "SEND_BLOCKED" },
  72. { 0x000F, "BREAKPOINT_BLOCKED" },
  73. { 0x0211, "IO_BLOCKED" },
  74. { 0x0021, "SEM_BLOCKED" },
  75. { 0x0223, "MUTEX_BLOCKED" },
  76. { 0x0025, "EVENT_BLOCKED" },
  77. { 0x0229, "TASK_QUEUE_BLOCKED" },
  78. { 0x042B, "LWSEM_BLOCKED" },
  79. { 0x042D, "LWEVENT_BLOCKED" },
  80. };
  81. static const char * const mqx_symbol_list[] = {
  82. "_mqx_kernel_data",
  83. "MQX_init_struct",
  84. NULL
  85. };
  86. static const struct mqx_params mqx_params_list[] = {
  87. { "cortex_m", mqx_arch_cortexm, &rtos_mqx_arm_v7m_stacking },
  88. };
  89. /*
  90. * Perform simple address check to avoid bus fault.
  91. */
  92. static int mqx_valid_address_check(
  93. struct rtos *rtos,
  94. uint32_t address
  95. )
  96. {
  97. enum mqx_arch arch_type = ((struct mqx_params *)rtos->rtos_specific_params)->target_arch;
  98. const char *targetname = ((struct mqx_params *)rtos->rtos_specific_params)->target_name;
  99. /* Cortex-M address range */
  100. if (arch_type == mqx_arch_cortexm) {
  101. if (
  102. /* code and sram area */
  103. (address && address <= 0x3FFFFFFFu) ||
  104. /* external ram area*/
  105. (address >= 0x6000000u && address <= 0x9FFFFFFFu)
  106. ) {
  107. return ERROR_OK;
  108. }
  109. return ERROR_FAIL;
  110. }
  111. LOG_ERROR("MQX RTOS - unknown architecture %s", targetname);
  112. return ERROR_FAIL;
  113. }
  114. /*
  115. * Wrapper of 'target_read_buffer' fn.
  116. * Include address check.
  117. */
  118. static int mqx_target_read_buffer(
  119. struct target *target,
  120. uint32_t address,
  121. uint32_t size,
  122. uint8_t *buffer
  123. )
  124. {
  125. int status = mqx_valid_address_check(target->rtos, address);
  126. if (status != ERROR_OK) {
  127. LOG_WARNING("MQX RTOS - target address 0x%" PRIx32 " is not allowed to read", address);
  128. return status;
  129. }
  130. status = target_read_buffer(target, address, size, buffer);
  131. if (status != ERROR_OK) {
  132. LOG_ERROR("MQX RTOS - reading target address 0x%" PRIx32" failed", address);
  133. return status;
  134. }
  135. return ERROR_OK;
  136. }
  137. /*
  138. * Get symbol address if present
  139. */
  140. static int mqx_get_symbol(
  141. struct rtos *rtos,
  142. enum mqx_symbols symbol,
  143. void *result
  144. )
  145. {
  146. /* TODO: additional check ?? */
  147. (*(int *)result) = (uint32_t)rtos->symbols[symbol].address;
  148. return ERROR_OK;
  149. }
  150. /*
  151. * Get value of struct member by passing
  152. * member offset, width and name (debug purpose)
  153. */
  154. static int mqx_get_member(
  155. struct rtos *rtos,
  156. const uint32_t base_address,
  157. int32_t member_offset,
  158. int32_t member_width,
  159. const char *member_name,
  160. void *result
  161. )
  162. {
  163. int status = ERROR_FAIL;
  164. status = mqx_target_read_buffer(
  165. rtos->target, base_address + member_offset, member_width, result
  166. );
  167. if (status != ERROR_OK)
  168. LOG_WARNING("MQX RTOS - cannot read \"%s\" at address 0x%" PRIx32,
  169. member_name, (uint32_t)(base_address + member_offset));
  170. return status;
  171. }
  172. /*
  173. * Check whether scheduler started
  174. */
  175. static int mqx_is_scheduler_running(
  176. struct rtos *rtos
  177. )
  178. {
  179. uint32_t kernel_data_symbol = 0;
  180. uint32_t kernel_data_addr = 0;
  181. uint32_t system_td_addr = 0;
  182. uint32_t active_td_addr = 0;
  183. uint32_t capability_value = 0;
  184. /* get '_mqx_kernel_data' symbol */
  185. if (mqx_get_symbol(rtos, MQX_VAL_MQX_KERNEL_DATA, &kernel_data_symbol) != ERROR_OK)
  186. return ERROR_FAIL;
  187. /* get '_mqx_kernel_data' */
  188. if (mqx_get_member(rtos, kernel_data_symbol, 0, 4,
  189. "_mqx_kernel_data", &kernel_data_addr) != ERROR_OK)
  190. return ERROR_FAIL;
  191. /* return if '_mqx_kernel_data' is NULL or default 0xFFFFFFFF */
  192. if (kernel_data_addr == 0 || kernel_data_addr == (uint32_t)(-1))
  193. return ERROR_FAIL;
  194. /* get kernel_data->ADDRESSING_CAPABILITY */
  195. if (mqx_get_member(rtos, kernel_data_addr, MQX_KERNEL_OFFSET_CAPABILITY, 4,
  196. "kernel_data->ADDRESSING_CAPABILITY", (void *)&capability_value) != ERROR_OK)
  197. return ERROR_FAIL;
  198. /* check first member, the '_mqx_kernel_data->ADDRESSING_CAPABILITY'.
  199. it suppose to be set to value 8 */
  200. if (capability_value != 8) {
  201. LOG_WARNING("MQX RTOS - value of '_mqx_kernel_data->ADDRESSING_CAPABILITY' contains invalid value");
  202. return ERROR_FAIL;
  203. }
  204. /* get active ptr */
  205. if (mqx_get_member(rtos, kernel_data_addr, MQX_KERNEL_OFFSET_ACTIVE_TASK, 4,
  206. "kernel_data->ACTIVE_PTR", (void *)&active_td_addr) != ERROR_OK)
  207. return ERROR_FAIL;
  208. /* active task is system task, scheduler has not not run yet */
  209. system_td_addr = kernel_data_addr + MQX_KERNEL_OFFSET_SYSTEM_TASK;
  210. if (active_td_addr == system_td_addr) {
  211. LOG_WARNING("MQX RTOS - scheduler does not run");
  212. return ERROR_FAIL;
  213. }
  214. return ERROR_OK;
  215. }
  216. /*
  217. * API function, return true if MQX is present
  218. */
  219. static bool mqx_detect_rtos(
  220. struct target *target
  221. )
  222. {
  223. if (
  224. (target->rtos->symbols) &&
  225. (target->rtos->symbols[MQX_VAL_MQX_KERNEL_DATA].address != 0)
  226. ) {
  227. return true;
  228. }
  229. return false;
  230. }
  231. /*
  232. * API function, pass MQX extra info to context data
  233. */
  234. static int mqx_create(
  235. struct target *target
  236. )
  237. {
  238. /* check target name against supported architectures */
  239. for (unsigned int i = 0; i < ARRAY_SIZE(mqx_params_list); i++) {
  240. if (0 == strcmp(mqx_params_list[i].target_name, target->type->name)) {
  241. target->rtos->rtos_specific_params = (void *)&mqx_params_list[i];
  242. /* LOG_DEBUG("MQX RTOS - valid architecture: %s", target->type->name); */
  243. return 0;
  244. }
  245. }
  246. LOG_ERROR("MQX RTOS - could not find target \"%s\" in MQX compatibility list", target->type->name);
  247. return -1;
  248. }
  249. /*
  250. * API function, update list of threads
  251. */
  252. static int mqx_update_threads(
  253. struct rtos *rtos
  254. )
  255. {
  256. uint32_t task_queue_addr = 0;
  257. uint32_t kernel_data_addr = 0;
  258. uint16_t task_queue_size = 0;
  259. uint32_t active_td_addr = 0;
  260. if (!rtos->rtos_specific_params)
  261. return -3;
  262. if (!rtos->symbols)
  263. return -4;
  264. /* clear old data */
  265. rtos_free_threadlist(rtos);
  266. /* check scheduler */
  267. if (ERROR_OK != mqx_is_scheduler_running(rtos))
  268. return ERROR_FAIL;
  269. /* get kernel_data symbol */
  270. if (mqx_get_symbol(rtos, MQX_VAL_MQX_KERNEL_DATA, &kernel_data_addr) != ERROR_OK)
  271. return ERROR_FAIL;
  272. /* read kernel_data */
  273. if (mqx_get_member(rtos, kernel_data_addr, 0, 4,
  274. "_mqx_kernel_data", &kernel_data_addr) != ERROR_OK)
  275. return ERROR_FAIL;
  276. /* get task queue address */
  277. task_queue_addr = kernel_data_addr + MQX_KERNEL_OFFSET_TDLIST;
  278. /* get task queue size */
  279. if (mqx_get_member(rtos, task_queue_addr, MQX_QUEUE_OFFSET_SIZE, 2,
  280. "kernel_data->TD_LIST.SIZE", &task_queue_size) != ERROR_OK)
  281. return ERROR_FAIL;
  282. /* get active ptr */
  283. if (mqx_get_member(rtos, kernel_data_addr, MQX_KERNEL_OFFSET_ACTIVE_TASK, 4,
  284. "kernel_data->ACTIVE_PTR", (void *)&active_td_addr) != ERROR_OK)
  285. return ERROR_FAIL;
  286. /* setup threads info */
  287. rtos->thread_count = task_queue_size;
  288. rtos->current_thread = 0;
  289. rtos->thread_details = calloc(rtos->thread_count, sizeof(struct thread_detail));
  290. if (!rtos->thread_details)
  291. return ERROR_FAIL;
  292. /* loop over each task and setup thread details,
  293. the current_taskpool_addr is set to queue head
  294. NOTE: debugging functions task create/destroy
  295. might cause to show invalid data.
  296. */
  297. for (
  298. uint32_t i = 0, taskpool_addr = task_queue_addr;
  299. i < (uint32_t)rtos->thread_count;
  300. i++
  301. ) {
  302. uint8_t task_name[MQX_THREAD_NAME_LENGTH + 1];
  303. uint32_t task_addr = 0, task_template = 0, task_state = 0;
  304. uint32_t task_name_addr = 0, task_id = 0, task_errno = 0;
  305. uint32_t state_index = 0;
  306. uint32_t extra_info_length = 0;
  307. char *state_name = "Unknown";
  308. /* set current taskpool address */
  309. if (mqx_get_member(rtos, taskpool_addr, MQX_TASK_OFFSET_NEXT, 4,
  310. "td_struct_ptr->NEXT", &taskpool_addr) != ERROR_OK)
  311. return ERROR_FAIL;
  312. /* get task address from taskpool */
  313. task_addr = taskpool_addr - MQX_TASK_OFFSET_TDLIST;
  314. /* get address of 'td_struct_ptr->TEMPLATE_LIST_PTR' */
  315. if (mqx_get_member(rtos, task_addr, MQX_TASK_OFFSET_TEMPLATE, 4,
  316. "td_struct_ptr->TEMPLATE_LIST_PTR", &task_template) != ERROR_OK)
  317. return ERROR_FAIL;
  318. /* get address of 'td_struct_ptr->TEMPLATE_LIST_PTR->NAME' */
  319. if (mqx_get_member(rtos, task_template, MQX_TASK_TEMPLATE_OFFSET_NAME, 4,
  320. "td_struct_ptr->TEMPLATE_LIST_PTR->NAME", &task_name_addr) != ERROR_OK)
  321. return ERROR_FAIL;
  322. /* get value of 'td_struct->TEMPLATE_LIST_PTR->NAME' */
  323. if (mqx_get_member(rtos, task_name_addr, 0, MQX_THREAD_NAME_LENGTH,
  324. "*td_struct_ptr->TEMPLATE_LIST_PTR->NAME", task_name) != ERROR_OK)
  325. return ERROR_FAIL;
  326. /* always terminate last character by force,
  327. otherwise openocd might fail if task_name
  328. has corrupted data */
  329. task_name[MQX_THREAD_NAME_LENGTH] = '\0';
  330. /* get value of 'td_struct_ptr->TASK_ID' */
  331. if (mqx_get_member(rtos, task_addr, MQX_TASK_OFFSET_ID, 4,
  332. "td_struct_ptr->TASK_ID", &task_id) != ERROR_OK)
  333. return ERROR_FAIL;
  334. /* get task errno */
  335. if (mqx_get_member(rtos, task_addr, MQX_TASK_OFFSET_ERROR_CODE, 4,
  336. "td_struct_ptr->TASK_ERROR_CODE", &task_errno) != ERROR_OK)
  337. return ERROR_FAIL;
  338. /* get value of 'td_struct_ptr->STATE' */
  339. if (mqx_get_member(rtos, task_addr, MQX_TASK_OFFSET_STATE, 4,
  340. "td_struct_ptr->STATE", &task_state) != ERROR_OK)
  341. return ERROR_FAIL;
  342. task_state &= MQX_TASK_STATE_MASK;
  343. /* and search for defined state */
  344. for (state_index = 0; state_index < ARRAY_SIZE(mqx_states); state_index++) {
  345. if (mqx_states[state_index].state == task_state) {
  346. state_name = mqx_states[state_index].name;
  347. break;
  348. }
  349. }
  350. /* setup thread details struct */
  351. rtos->thread_details[i].threadid = task_id;
  352. rtos->thread_details[i].exists = true;
  353. /* set thread name */
  354. rtos->thread_details[i].thread_name_str = malloc(strlen((void *)task_name) + 1);
  355. if (NULL == rtos->thread_details[i].thread_name_str)
  356. return ERROR_FAIL;
  357. strcpy(rtos->thread_details[i].thread_name_str, (void *)task_name);
  358. /* set thread extra info
  359. * - task state
  360. * - task address
  361. * - task errno
  362. * calculate length as:
  363. * state length + address length + errno length + formatter length
  364. */
  365. extra_info_length += strlen((void *)state_name) + 7 + 13 + 8 + 15 + 8;
  366. rtos->thread_details[i].extra_info_str = malloc(extra_info_length + 1);
  367. if (NULL == rtos->thread_details[i].extra_info_str)
  368. return ERROR_FAIL;
  369. snprintf(rtos->thread_details[i].extra_info_str, extra_info_length,
  370. "State: %s, Address: 0x%" PRIx32 ", Error Code: %" PRIu32,
  371. state_name, task_addr, task_errno
  372. );
  373. /* set active thread */
  374. if (active_td_addr == task_addr)
  375. rtos->current_thread = task_id;
  376. }
  377. return ERROR_OK;
  378. }
  379. /*
  380. * API function, get info of selected thread
  381. */
  382. static int mqx_get_thread_reg_list(
  383. struct rtos *rtos,
  384. int64_t thread_id,
  385. struct rtos_reg **reg_list,
  386. int *num_regs
  387. )
  388. {
  389. int64_t stack_ptr = 0;
  390. uint32_t my_task_addr = 0;
  391. uint32_t task_queue_addr = 0;
  392. uint32_t task_queue_size = 0;
  393. uint32_t kernel_data_addr = 0;
  394. if (thread_id == 0) {
  395. LOG_ERROR("MQX RTOS - invalid threadid: 0x%X", (int)thread_id);
  396. return ERROR_FAIL;
  397. }
  398. if (ERROR_OK != mqx_is_scheduler_running(rtos))
  399. return ERROR_FAIL;
  400. /* get kernel_data symbol */
  401. if (mqx_get_symbol(rtos, MQX_VAL_MQX_KERNEL_DATA, &kernel_data_addr) != ERROR_OK)
  402. return ERROR_FAIL;
  403. /* read kernel_data */
  404. if (mqx_get_member(rtos, kernel_data_addr, 0, 4,
  405. "_mqx_kernel_data", &kernel_data_addr) != ERROR_OK)
  406. return ERROR_FAIL;
  407. /* get task queue address */
  408. task_queue_addr = kernel_data_addr + MQX_KERNEL_OFFSET_TDLIST;
  409. /* get task queue size */
  410. if (mqx_get_member(rtos, task_queue_addr, MQX_QUEUE_OFFSET_SIZE, 2,
  411. "kernel_data->TD_LIST.SIZE", &task_queue_size) != ERROR_OK)
  412. return ERROR_FAIL;
  413. /* search for taskid */
  414. for (
  415. uint32_t i = 0, taskpool_addr = task_queue_addr;
  416. i < (uint32_t)rtos->thread_count;
  417. i++
  418. ) {
  419. uint32_t tmp_address = 0, task_addr = 0;
  420. uint32_t task_id = 0;
  421. /* set current taskpool address */
  422. tmp_address = taskpool_addr;
  423. if (mqx_get_member(rtos, tmp_address, MQX_TASK_OFFSET_NEXT, 4,
  424. "td_struct_ptr->NEXT", &taskpool_addr) != ERROR_OK)
  425. return ERROR_FAIL;
  426. /* get task address from taskpool */
  427. task_addr = taskpool_addr - MQX_TASK_OFFSET_TDLIST;
  428. /* get value of td_struct->TASK_ID */
  429. if (mqx_get_member(rtos, task_addr, MQX_TASK_OFFSET_ID, 4,
  430. "td_struct_ptr->TASK_ID", &task_id) != ERROR_OK)
  431. return ERROR_FAIL;
  432. /* found taskid, break */
  433. if (task_id == thread_id) {
  434. my_task_addr = task_addr;
  435. break;
  436. }
  437. }
  438. if (!my_task_addr) {
  439. LOG_ERROR("MQX_RTOS - threadid %" PRId64 " does not match any task", thread_id);
  440. return ERROR_FAIL;
  441. }
  442. /* get task stack head address */
  443. if (mqx_get_member(rtos, my_task_addr, MQX_TASK_OFFSET_STACK, 4,
  444. "task->STACK_PTR", &stack_ptr) != ERROR_OK)
  445. return ERROR_FAIL;
  446. return rtos_generic_stack_read(
  447. rtos->target, ((struct mqx_params *)rtos->rtos_specific_params)->stacking_info, stack_ptr, reg_list, num_regs
  448. );
  449. }
  450. /* API function, export list of required symbols */
  451. static int mqx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
  452. {
  453. *symbol_list = calloc(ARRAY_SIZE(mqx_symbol_list), sizeof(struct symbol_table_elem));
  454. if (NULL == *symbol_list)
  455. return ERROR_FAIL;
  456. /* export required symbols */
  457. for (int i = 0; i < (int)(ARRAY_SIZE(mqx_symbol_list)); i++)
  458. (*symbol_list)[i].symbol_name = mqx_symbol_list[i];
  459. return ERROR_OK;
  460. }
  461. struct rtos_type mqx_rtos = {
  462. .name = "mqx",
  463. .detect_rtos = mqx_detect_rtos,
  464. .create = mqx_create,
  465. .update_threads = mqx_update_threads,
  466. .get_thread_reg_list = mqx_get_thread_reg_list,
  467. .get_symbol_list_to_lookup = mqx_get_symbol_list_to_lookup,
  468. };