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.
 
 
 
 
 
 

404 lines
11 KiB

  1. /***************************************************************************
  2. * Copyright 2016,2017 Sony Video & Sound Products Inc. *
  3. * Masatoshi Tateishi - Masatoshi.Tateishi@jp.sony.com *
  4. * Masayuki Ishikawa - Masayuki.Ishikawa@jp.sony.com *
  5. * *
  6. * This program is free software; you can redistribute it and/or modify *
  7. * it under the terms of the GNU General Public License as published by *
  8. * the Free Software Foundation; either version 2 of the License, or *
  9. * (at your option) any later version. *
  10. * *
  11. * This program is distributed in the hope that it will be useful, *
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  14. * GNU General Public License for more details. *
  15. * *
  16. * You should have received a copy of the GNU General Public License *
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>. *
  18. ***************************************************************************/
  19. #ifdef HAVE_CONFIG_H
  20. #include "config.h"
  21. #endif
  22. #include <jtag/jtag.h>
  23. #include "target/target.h"
  24. #include "target/target_type.h"
  25. #include "target/armv7m.h"
  26. #include "target/cortex_m.h"
  27. #include "rtos.h"
  28. #include "helper/log.h"
  29. #include "helper/types.h"
  30. #include "server/gdb_server.h"
  31. #include "nuttx_header.h"
  32. int rtos_thread_packet(struct connection *connection, const char *packet, int packet_size);
  33. #ifdef CONFIG_DISABLE_SIGNALS
  34. #define SIG_QUEUE_NUM 0
  35. #else
  36. #define SIG_QUEUE_NUM 1
  37. #endif /* CONFIG_DISABLE_SIGNALS */
  38. #ifdef CONFIG_DISABLE_MQUEUE
  39. #define M_QUEUE_NUM 0
  40. #else
  41. #define M_QUEUE_NUM 2
  42. #endif /* CONFIG_DISABLE_MQUEUE */
  43. #ifdef CONFIG_PAGING
  44. #define PAGING_QUEUE_NUM 1
  45. #else
  46. #define PAGING_QUEUE_NUM 0
  47. #endif /* CONFIG_PAGING */
  48. #define TASK_QUEUE_NUM (6 + SIG_QUEUE_NUM + M_QUEUE_NUM + PAGING_QUEUE_NUM)
  49. /* see nuttx/sched/os_start.c */
  50. static char *nuttx_symbol_list[] = {
  51. "g_readytorun", /* 0: must be top of this array */
  52. "g_tasklisttable",
  53. NULL
  54. };
  55. /* see nuttx/include/nuttx/sched.h */
  56. struct tcb {
  57. uint32_t flink;
  58. uint32_t blink;
  59. uint8_t dat[512];
  60. };
  61. static struct {
  62. uint32_t addr;
  63. uint32_t prio;
  64. } g_tasklist[TASK_QUEUE_NUM];
  65. static char *task_state_str[] = {
  66. "INVALID",
  67. "PENDING",
  68. "READYTORUN",
  69. "RUNNING",
  70. "INACTIVE",
  71. "WAIT_SEM",
  72. #ifndef CONFIG_DISABLE_SIGNALS
  73. "WAIT_SIG",
  74. #endif /* CONFIG_DISABLE_SIGNALS */
  75. #ifndef CONFIG_DISABLE_MQUEUE
  76. "WAIT_MQNOTEMPTY",
  77. "WAIT_MQNOTFULL",
  78. #endif /* CONFIG_DISABLE_MQUEUE */
  79. #ifdef CONFIG_PAGING
  80. "WAIT_PAGEFILL",
  81. #endif /* CONFIG_PAGING */
  82. };
  83. /* see arch/arm/include/armv7-m/irq_cmnvector.h */
  84. static const struct stack_register_offset nuttx_stack_offsets_cortex_m[] = {
  85. { ARMV7M_R0, 0x28, 32 }, /* r0 */
  86. { ARMV7M_R1, 0x2c, 32 }, /* r1 */
  87. { ARMV7M_R2, 0x30, 32 }, /* r2 */
  88. { ARMV7M_R3, 0x34, 32 }, /* r3 */
  89. { ARMV7M_R4, 0x08, 32 }, /* r4 */
  90. { ARMV7M_R5, 0x0c, 32 }, /* r5 */
  91. { ARMV7M_R6, 0x10, 32 }, /* r6 */
  92. { ARMV7M_R7, 0x14, 32 }, /* r7 */
  93. { ARMV7M_R8, 0x18, 32 }, /* r8 */
  94. { ARMV7M_R9, 0x1c, 32 }, /* r9 */
  95. { ARMV7M_R10, 0x20, 32 }, /* r10 */
  96. { ARMV7M_R11, 0x24, 32 }, /* r11 */
  97. { ARMV7M_R12, 0x38, 32 }, /* r12 */
  98. { ARMV7M_R13, 0, 32 }, /* sp */
  99. { ARMV7M_R14, 0x3c, 32 }, /* lr */
  100. { ARMV7M_PC, 0x40, 32 }, /* pc */
  101. { ARMV7M_xPSR, 0x44, 32 }, /* xPSR */
  102. };
  103. static const struct rtos_register_stacking nuttx_stacking_cortex_m = {
  104. 0x48, /* stack_registers_size */
  105. -1, /* stack_growth_direction */
  106. 17, /* num_output_registers */
  107. 0, /* stack_alignment */
  108. nuttx_stack_offsets_cortex_m /* register_offsets */
  109. };
  110. static const struct stack_register_offset nuttx_stack_offsets_cortex_m_fpu[] = {
  111. { ARMV7M_R0, 0x6c, 32 }, /* r0 */
  112. { ARMV7M_R1, 0x70, 32 }, /* r1 */
  113. { ARMV7M_R2, 0x74, 32 }, /* r2 */
  114. { ARMV7M_R3, 0x78, 32 }, /* r3 */
  115. { ARMV7M_R4, 0x08, 32 }, /* r4 */
  116. { ARMV7M_R5, 0x0c, 32 }, /* r5 */
  117. { ARMV7M_R6, 0x10, 32 }, /* r6 */
  118. { ARMV7M_R7, 0x14, 32 }, /* r7 */
  119. { ARMV7M_R8, 0x18, 32 }, /* r8 */
  120. { ARMV7M_R9, 0x1c, 32 }, /* r9 */
  121. { ARMV7M_R10, 0x20, 32 }, /* r10 */
  122. { ARMV7M_R11, 0x24, 32 }, /* r11 */
  123. { ARMV7M_R12, 0x7c, 32 }, /* r12 */
  124. { ARMV7M_R13, 0, 32 }, /* sp */
  125. { ARMV7M_R14, 0x80, 32 }, /* lr */
  126. { ARMV7M_PC, 0x84, 32 }, /* pc */
  127. { ARMV7M_xPSR, 0x88, 32 }, /* xPSR */
  128. };
  129. static const struct rtos_register_stacking nuttx_stacking_cortex_m_fpu = {
  130. 0x8c, /* stack_registers_size */
  131. -1, /* stack_growth_direction */
  132. 17, /* num_output_registers */
  133. 0, /* stack_alignment */
  134. nuttx_stack_offsets_cortex_m_fpu /* register_offsets */
  135. };
  136. static int pid_offset = PID;
  137. static int state_offset = STATE;
  138. static int name_offset = NAME;
  139. static int xcpreg_offset = XCPREG;
  140. static int name_size = NAME_SIZE;
  141. static int rcmd_offset(const char *cmd, const char *name)
  142. {
  143. if (strncmp(cmd, name, strlen(name)))
  144. return -1;
  145. if (strlen(cmd) <= strlen(name) + 1)
  146. return -1;
  147. return atoi(cmd + strlen(name));
  148. }
  149. static int nuttx_thread_packet(struct connection *connection,
  150. char const *packet, int packet_size)
  151. {
  152. char cmd[GDB_BUFFER_SIZE / 2 + 1] = ""; /* Extra byte for null-termination */
  153. if (!strncmp(packet, "qRcmd", 5)) {
  154. size_t len = unhexify((uint8_t *)cmd, packet + 6, sizeof(cmd));
  155. int offset;
  156. if (len <= 0)
  157. goto pass;
  158. offset = rcmd_offset(cmd, "nuttx.pid_offset");
  159. if (offset >= 0) {
  160. LOG_INFO("pid_offset: %d", offset);
  161. pid_offset = offset;
  162. goto retok;
  163. }
  164. offset = rcmd_offset(cmd, "nuttx.state_offset");
  165. if (offset >= 0) {
  166. LOG_INFO("state_offset: %d", offset);
  167. state_offset = offset;
  168. goto retok;
  169. }
  170. offset = rcmd_offset(cmd, "nuttx.name_offset");
  171. if (offset >= 0) {
  172. LOG_INFO("name_offset: %d", offset);
  173. name_offset = offset;
  174. goto retok;
  175. }
  176. offset = rcmd_offset(cmd, "nuttx.xcpreg_offset");
  177. if (offset >= 0) {
  178. LOG_INFO("xcpreg_offset: %d", offset);
  179. xcpreg_offset = offset;
  180. goto retok;
  181. }
  182. offset = rcmd_offset(cmd, "nuttx.name_size");
  183. if (offset >= 0) {
  184. LOG_INFO("name_size: %d", offset);
  185. name_size = offset;
  186. goto retok;
  187. }
  188. }
  189. pass:
  190. return rtos_thread_packet(connection, packet, packet_size);
  191. retok:
  192. gdb_put_packet(connection, "OK", 2);
  193. return ERROR_OK;
  194. }
  195. static bool nuttx_detect_rtos(struct target *target)
  196. {
  197. if ((target->rtos->symbols) &&
  198. (target->rtos->symbols[0].address != 0) &&
  199. (target->rtos->symbols[1].address != 0)) {
  200. return true;
  201. }
  202. return false;
  203. }
  204. static int nuttx_create(struct target *target)
  205. {
  206. target->rtos->gdb_thread_packet = nuttx_thread_packet;
  207. LOG_INFO("target type name = %s", target->type->name);
  208. return 0;
  209. }
  210. static int nuttx_update_threads(struct rtos *rtos)
  211. {
  212. uint32_t thread_count;
  213. struct tcb tcb;
  214. int ret;
  215. uint32_t head;
  216. uint32_t tcb_addr;
  217. uint32_t i;
  218. uint8_t state;
  219. if (!rtos->symbols) {
  220. LOG_ERROR("No symbols for NuttX");
  221. return -3;
  222. }
  223. /* free previous thread details */
  224. rtos_free_threadlist(rtos);
  225. ret = target_read_buffer(rtos->target, rtos->symbols[1].address,
  226. sizeof(g_tasklist), (uint8_t *)&g_tasklist);
  227. if (ret) {
  228. LOG_ERROR("target_read_buffer : ret = %d\n", ret);
  229. return ERROR_FAIL;
  230. }
  231. thread_count = 0;
  232. for (i = 0; i < TASK_QUEUE_NUM; i++) {
  233. if (g_tasklist[i].addr == 0)
  234. continue;
  235. ret = target_read_u32(rtos->target, g_tasklist[i].addr,
  236. &head);
  237. if (ret) {
  238. LOG_ERROR("target_read_u32 : ret = %d\n", ret);
  239. return ERROR_FAIL;
  240. }
  241. /* readytorun head is current thread */
  242. if (g_tasklist[i].addr == rtos->symbols[0].address)
  243. rtos->current_thread = head;
  244. tcb_addr = head;
  245. while (tcb_addr) {
  246. struct thread_detail *thread;
  247. ret = target_read_buffer(rtos->target, tcb_addr,
  248. sizeof(tcb), (uint8_t *)&tcb);
  249. if (ret) {
  250. LOG_ERROR("target_read_buffer : ret = %d\n",
  251. ret);
  252. return ERROR_FAIL;
  253. }
  254. thread_count++;
  255. rtos->thread_details = realloc(rtos->thread_details,
  256. sizeof(struct thread_detail) * thread_count);
  257. thread = &rtos->thread_details[thread_count - 1];
  258. thread->threadid = tcb_addr;
  259. thread->exists = true;
  260. state = tcb.dat[state_offset - 8];
  261. thread->extra_info_str = NULL;
  262. if (state < ARRAY_SIZE(task_state_str)) {
  263. thread->extra_info_str = malloc(256);
  264. snprintf(thread->extra_info_str, 256, "pid:%d, %s",
  265. tcb.dat[pid_offset - 8] |
  266. tcb.dat[pid_offset - 8 + 1] << 8,
  267. task_state_str[state]);
  268. }
  269. if (name_offset) {
  270. thread->thread_name_str = malloc(name_size + 1);
  271. snprintf(thread->thread_name_str, name_size,
  272. "%s", (char *)&tcb.dat[name_offset - 8]);
  273. } else {
  274. thread->thread_name_str = malloc(sizeof("None"));
  275. strcpy(thread->thread_name_str, "None");
  276. }
  277. tcb_addr = tcb.flink;
  278. }
  279. }
  280. rtos->thread_count = thread_count;
  281. return 0;
  282. }
  283. /*
  284. * thread_id = tcb address;
  285. */
  286. static int nuttx_get_thread_reg_list(struct rtos *rtos, int64_t thread_id,
  287. struct rtos_reg **reg_list, int *num_regs)
  288. {
  289. int retval;
  290. /* Check for armv7m with *enabled* FPU, i.e. a Cortex-M4F */
  291. bool cm4_fpu_enabled = false;
  292. struct armv7m_common *armv7m_target = target_to_armv7m(rtos->target);
  293. if (is_armv7m(armv7m_target)) {
  294. if (armv7m_target->fp_feature == FPV4_SP) {
  295. /* Found ARM v7m target which includes a FPU */
  296. uint32_t cpacr;
  297. retval = target_read_u32(rtos->target, FPU_CPACR, &cpacr);
  298. if (retval != ERROR_OK) {
  299. LOG_ERROR("Could not read CPACR register to check FPU state");
  300. return -1;
  301. }
  302. /* Check if CP10 and CP11 are set to full access. */
  303. if (cpacr & 0x00F00000) {
  304. /* Found target with enabled FPU */
  305. cm4_fpu_enabled = 1;
  306. }
  307. }
  308. }
  309. const struct rtos_register_stacking *stacking;
  310. if (cm4_fpu_enabled)
  311. stacking = &nuttx_stacking_cortex_m_fpu;
  312. else
  313. stacking = &nuttx_stacking_cortex_m;
  314. return rtos_generic_stack_read(rtos->target, stacking,
  315. (uint32_t)thread_id + xcpreg_offset, reg_list, num_regs);
  316. }
  317. static int nuttx_get_symbol_list_to_lookup(struct symbol_table_elem *symbol_list[])
  318. {
  319. unsigned int i;
  320. *symbol_list = (struct symbol_table_elem *) calloc(1,
  321. sizeof(struct symbol_table_elem) * ARRAY_SIZE(nuttx_symbol_list));
  322. for (i = 0; i < ARRAY_SIZE(nuttx_symbol_list); i++)
  323. (*symbol_list)[i].symbol_name = nuttx_symbol_list[i];
  324. return 0;
  325. }
  326. struct rtos_type nuttx_rtos = {
  327. .name = "nuttx",
  328. .detect_rtos = nuttx_detect_rtos,
  329. .create = nuttx_create,
  330. .update_threads = nuttx_update_threads,
  331. .get_thread_reg_list = nuttx_get_thread_reg_list,
  332. .get_symbol_list_to_lookup = nuttx_get_symbol_list_to_lookup,
  333. };