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.
 
 
 
 
 
 

517 lines
11 KiB

  1. /*
  2. * Copyright (C) 2016-2017 by Marc Schink
  3. * openocd-dev@marcschink.de
  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. #include <stdint.h>
  19. #include <stdbool.h>
  20. #include <string.h>
  21. #include <helper/log.h>
  22. #include <helper/list.h>
  23. #include <target/target.h>
  24. #include <target/rtt.h>
  25. #include "rtt.h"
  26. static struct rtt_source global_source;
  27. static struct rtt_control global_ctrl;
  28. static struct target *global_target;
  29. static target_addr_t global_addr;
  30. static uint32_t global_length;
  31. static char global_id[RTT_MAX_CB_ID_LENGTH];
  32. static size_t global_id_length;
  33. static bool global_configured;
  34. static bool global_started;
  35. static bool global_changed;
  36. static bool global_found_cb;
  37. static struct rtt_sink_list **global_sink_list;
  38. static size_t global_sink_list_length;
  39. int rtt_init(void)
  40. {
  41. global_sink_list_length = 1;
  42. global_sink_list = calloc(global_sink_list_length,
  43. sizeof(struct rtt_sink_list *));
  44. if (!global_sink_list)
  45. return ERROR_FAIL;
  46. global_sink_list[0] = NULL;
  47. global_started = false;
  48. return ERROR_OK;
  49. }
  50. int rtt_exit(void)
  51. {
  52. free(global_sink_list);
  53. return ERROR_OK;
  54. }
  55. static int read_channel_callback(void *user_data)
  56. {
  57. int ret;
  58. ret = global_source.read(&global_ctrl, global_sink_list,
  59. global_sink_list_length, global_target, NULL);
  60. if (ret != ERROR_OK) {
  61. target_unregister_timer_callback(&read_channel_callback, NULL);
  62. global_source.stop(global_target, NULL);
  63. return ret;
  64. }
  65. return ERROR_OK;
  66. }
  67. int rtt_register_source(const struct rtt_source source, struct target *target)
  68. {
  69. global_source = source;
  70. global_target = target;
  71. return ERROR_OK;
  72. }
  73. int rtt_start(void)
  74. {
  75. int ret;
  76. target_addr_t addr = global_addr;
  77. if (global_started) {
  78. LOG_INFO("RTT already started");
  79. return ERROR_OK;
  80. }
  81. if (!global_found_cb || global_changed) {
  82. global_source.find_cb(&addr, global_length, global_id,
  83. global_id_length, &global_found_cb, global_target, NULL);
  84. global_changed = false;
  85. if (global_found_cb) {
  86. LOG_INFO("RTT control block found at 0x%" TARGET_PRIxADDR, addr);
  87. global_ctrl.address = addr;
  88. } else {
  89. LOG_INFO("No RTT control block found");
  90. return ERROR_OK;
  91. }
  92. }
  93. ret = global_source.read_cb(global_ctrl.address, &global_ctrl,
  94. global_target, NULL);
  95. if (ret != ERROR_OK)
  96. return ret;
  97. ret = global_source.start(&global_ctrl, global_target, NULL);
  98. if (ret != ERROR_OK)
  99. return ret;
  100. target_register_timer_callback(&read_channel_callback, 100, 1, NULL);
  101. global_started = true;
  102. return ERROR_OK;
  103. }
  104. int rtt_stop(void)
  105. {
  106. int ret;
  107. target_unregister_timer_callback(&read_channel_callback, NULL);
  108. global_started = false;
  109. ret = global_source.stop(global_target, NULL);
  110. if (ret != ERROR_OK)
  111. return ret;
  112. return ERROR_OK;
  113. }
  114. static int adjust_sink_list(size_t length)
  115. {
  116. size_t i;
  117. struct rtt_sink_list **tmp;
  118. if (length <= global_sink_list_length)
  119. return ERROR_OK;
  120. tmp = realloc(global_sink_list, sizeof(struct rtt_sink_list *) * length);
  121. if (!tmp)
  122. return ERROR_FAIL;
  123. for (i = global_sink_list_length; i < length; i++)
  124. tmp[i] = NULL;
  125. global_sink_list = tmp;
  126. global_sink_list_length = length;
  127. return ERROR_OK;
  128. }
  129. int rtt_register_sink(unsigned int channel, rtt_sink_read read,
  130. void *user_data)
  131. {
  132. struct rtt_sink_list *tmp;
  133. if (channel >= global_sink_list_length) {
  134. if (adjust_sink_list(channel + 1) != ERROR_OK)
  135. return ERROR_FAIL;
  136. }
  137. LOG_DEBUG("Registering sink for RTT channel %u", channel);
  138. tmp = malloc(sizeof(struct rtt_sink_list));
  139. if (!tmp)
  140. return ERROR_FAIL;
  141. tmp->read = read;
  142. tmp->user_data = user_data;
  143. tmp->next = global_sink_list[channel];
  144. global_sink_list[channel] = tmp;
  145. return ERROR_OK;
  146. }
  147. int rtt_unregister_sink(unsigned int channel, rtt_sink_read read,
  148. void *user_data)
  149. {
  150. struct rtt_sink_list *sink;
  151. struct rtt_sink_list *prev_sink;
  152. LOG_DEBUG("Unregistering sink for RTT channel %u", channel);
  153. if (channel >= global_sink_list_length)
  154. return ERROR_FAIL;
  155. prev_sink = global_sink_list[channel];
  156. for (sink = global_sink_list[channel]; sink; prev_sink = sink,
  157. sink = sink->next) {
  158. if (sink->read == read && sink->user_data == user_data) {
  159. if (sink == global_sink_list[channel])
  160. global_sink_list[channel] = sink->next;
  161. else
  162. prev_sink->next = sink->next;
  163. free(sink);
  164. return ERROR_OK;
  165. }
  166. }
  167. return ERROR_OK;
  168. }
  169. int rtt_write_channel(unsigned int channel, const uint8_t *buffer,
  170. size_t *length)
  171. {
  172. if (!global_source.write)
  173. return ERROR_FAIL;
  174. if (channel >= global_ctrl.num_up_buffers) {
  175. LOG_WARNING("Down-channel %u is not available", channel);
  176. return ERROR_OK;
  177. }
  178. return global_source.write(&global_ctrl, channel, buffer, length,
  179. global_target, NULL);
  180. }
  181. COMMAND_HANDLER(handle_rtt_setup_command)
  182. {
  183. target_addr_t addr;
  184. uint32_t length;
  185. struct rtt_source source;
  186. if (CMD_ARGC != 3)
  187. return ERROR_COMMAND_SYNTAX_ERROR;
  188. COMMAND_PARSE_NUMBER(target_addr, CMD_ARGV[0], addr);
  189. COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length);
  190. global_id_length = strlen(CMD_ARGV[2]);
  191. if (!global_id_length || global_id_length > RTT_MAX_CB_ID_LENGTH) {
  192. LOG_ERROR("Invalid RTT control block ID");
  193. return ERROR_COMMAND_ARGUMENT_INVALID;
  194. }
  195. source.find_cb = &target_rtt_find_control_block;
  196. source.read_cb = &target_rtt_read_control_block;
  197. source.start = &target_rtt_start;
  198. source.stop = &target_rtt_stop;
  199. source.read = &target_rtt_read_callback;
  200. source.write = &target_rtt_write_callback;
  201. source.read_buffer_info = &target_rtt_read_buffer_info;
  202. rtt_register_source(source, get_current_target(CMD_CTX));
  203. global_addr = addr;
  204. global_length = length;
  205. memcpy(global_id, CMD_ARGV[2], global_id_length);
  206. global_changed = true;
  207. global_configured = true;
  208. return ERROR_OK;
  209. }
  210. COMMAND_HANDLER(handle_rtt_start_command)
  211. {
  212. int ret;
  213. if (CMD_ARGC > 0)
  214. return ERROR_COMMAND_SYNTAX_ERROR;
  215. if (global_started) {
  216. LOG_INFO("RTT already started");
  217. return ERROR_OK;
  218. }
  219. if (!global_configured) {
  220. LOG_ERROR("RTT is not configured");
  221. return ERROR_FAIL;
  222. }
  223. ret = rtt_start();
  224. if (ret != ERROR_OK)
  225. return ret;
  226. return ERROR_OK;
  227. }
  228. COMMAND_HANDLER(handle_rtt_stop_command)
  229. {
  230. int ret;
  231. if (CMD_ARGC > 0)
  232. return ERROR_COMMAND_SYNTAX_ERROR;
  233. ret = rtt_stop();
  234. if (ret != ERROR_OK)
  235. return ret;
  236. return ERROR_OK;
  237. }
  238. COMMAND_HANDLER(handle_rtt_channels_command)
  239. {
  240. int ret;
  241. size_t i;
  242. char channel_name[32];
  243. struct rtt_buffer_info info;
  244. if (!global_found_cb) {
  245. LOG_ERROR("RTT control block not available");
  246. return ERROR_FAIL;
  247. }
  248. command_print(CMD_CTX, "Channels: up=%u, down=%u",
  249. global_ctrl.num_up_buffers, global_ctrl.num_down_buffers);
  250. LOG_INFO("Up-channels:");
  251. info.name = channel_name;
  252. info.name_length = sizeof(channel_name);
  253. for (i = 0; i < global_ctrl.num_up_buffers; i++) {
  254. ret = global_source.read_buffer_info(&global_ctrl, i, true, &info,
  255. global_target, NULL);
  256. if (ret != ERROR_OK)
  257. return ret;
  258. if (!info.size)
  259. continue;
  260. LOG_INFO("%zu: %s %u %u", i, info.name, info.size, info.flags);
  261. }
  262. LOG_INFO("Down-channels:");
  263. for (i = 0; i < global_ctrl.num_down_buffers; i++) {
  264. ret = global_source.read_buffer_info(&global_ctrl, i, false, &info,
  265. global_target, NULL);
  266. if (ret != ERROR_OK)
  267. return ret;
  268. if (!info.size)
  269. continue;
  270. LOG_INFO("%zu: %s %u %u", i, info.name, info.size, info.flags);
  271. }
  272. return ERROR_OK;
  273. }
  274. static int jim_channel_list(Jim_Interp *interp, int argc,
  275. Jim_Obj * const *argv)
  276. {
  277. int ret;
  278. size_t i;
  279. Jim_Obj *list;
  280. Jim_Obj *channel_list;
  281. char channel_name[128];
  282. struct rtt_buffer_info info;
  283. if (!global_found_cb) {
  284. LOG_ERROR("RTT control block not available");
  285. return ERROR_FAIL;
  286. }
  287. info.name = channel_name;
  288. info.name_length = sizeof(channel_name);
  289. list = Jim_NewListObj(interp, NULL, 0);
  290. channel_list = Jim_NewListObj(interp, NULL, 0);
  291. for (i = 0; i < global_ctrl.num_up_buffers; i++) {
  292. ret = global_source.read_buffer_info(&global_ctrl, i, true, &info,
  293. global_target, NULL);
  294. if (ret != ERROR_OK)
  295. return ret;
  296. if (!info.size)
  297. continue;
  298. Jim_Obj *tmp = Jim_NewListObj(interp, NULL, 0);
  299. Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
  300. "name", -1));
  301. Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
  302. info.name, -1));
  303. Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
  304. "size", -1));
  305. Jim_ListAppendElement(interp, tmp, Jim_NewIntObj(interp,
  306. info.size));
  307. Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
  308. "flags", -1));
  309. Jim_ListAppendElement(interp, tmp, Jim_NewIntObj(interp,
  310. info.flags));
  311. Jim_ListAppendElement(interp, channel_list, tmp);
  312. }
  313. Jim_ListAppendElement(interp, list, channel_list);
  314. channel_list = Jim_NewListObj(interp, NULL, 0);
  315. for (i = 0; i < global_ctrl.num_down_buffers; i++) {
  316. ret = global_source.read_buffer_info(&global_ctrl, i, false, &info,
  317. global_target, NULL);
  318. if (ret != ERROR_OK)
  319. return ret;
  320. if (!info.size)
  321. continue;
  322. Jim_Obj *tmp = Jim_NewListObj(interp, NULL, 0);
  323. Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
  324. "name", -1));
  325. Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
  326. info.name, -1));
  327. Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
  328. "size", -1));
  329. Jim_ListAppendElement(interp, tmp, Jim_NewIntObj(interp,
  330. info.size));
  331. Jim_ListAppendElement(interp, tmp, Jim_NewStringObj(interp,
  332. "flags", -1));
  333. Jim_ListAppendElement(interp, tmp, Jim_NewIntObj(interp,
  334. info.flags));
  335. Jim_ListAppendElement(interp, channel_list, tmp);
  336. }
  337. Jim_ListAppendElement(interp, list, channel_list);
  338. Jim_SetResult(interp, list);
  339. return JIM_OK;
  340. }
  341. static const struct command_registration rtt_subcommand_handlers[] = {
  342. {
  343. .name = "setup",
  344. .handler = handle_rtt_setup_command,
  345. .mode = COMMAND_ANY,
  346. .help = "setup RTT",
  347. .usage = "<address> <length> <ID>"
  348. },
  349. {
  350. .name = "start",
  351. .handler = handle_rtt_start_command,
  352. .mode = COMMAND_EXEC,
  353. .help = "start RTT",
  354. .usage = ""
  355. },
  356. {
  357. .name = "stop",
  358. .handler = handle_rtt_stop_command,
  359. .mode = COMMAND_EXEC,
  360. .help = "stop RTT",
  361. .usage = ""
  362. },
  363. {
  364. .name = "channels",
  365. .handler = handle_rtt_channels_command,
  366. .mode = COMMAND_EXEC,
  367. .help = "list available channels",
  368. .usage = ""
  369. },
  370. {
  371. .name = "channellist",
  372. .jim_handler = jim_channel_list,
  373. .mode = COMMAND_EXEC,
  374. .help = "list available channels",
  375. .usage = ""
  376. },
  377. COMMAND_REGISTRATION_DONE
  378. };
  379. static const struct command_registration rtt_command_handlers[] = {
  380. {
  381. .name = "rtt",
  382. .mode = COMMAND_EXEC,
  383. .help = "RTT commands",
  384. .usage = "",
  385. .chain = rtt_subcommand_handlers
  386. },
  387. COMMAND_REGISTRATION_DONE
  388. };
  389. int rtt_register_commands(struct command_context *ctx)
  390. {
  391. return register_commands(ctx, NULL, rtt_command_handlers);
  392. }