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.
 
 
 
 
 
 

479 lines
14 KiB

  1. /***************************************************************************
  2. * Copyright (C) 2009 by Marvell Technology Group Ltd. *
  3. * Written by Nicolas Pitre <nico@marvell.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, write to the *
  17. * Free Software Foundation, Inc., *
  18. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
  19. ***************************************************************************/
  20. /**
  21. * @file
  22. * Hold ARM semihosting support.
  23. *
  24. * Semihosting enables code running on an ARM target to use the I/O
  25. * facilities on the host computer. The target application must be linked
  26. * against a library that forwards operation requests by using the SVC
  27. * instruction trapped at the Supervisor Call vector by the debugger.
  28. * Details can be found in chapter 8 of DUI0203I_rvct_developer_guide.pdf
  29. * from ARM Ltd.
  30. */
  31. #ifdef HAVE_CONFIG_H
  32. #include "config.h"
  33. #endif
  34. #include "arm.h"
  35. #include "armv4_5.h"
  36. #include "register.h"
  37. #include "arm_semihosting.h"
  38. #include <helper/binarybuffer.h>
  39. #include <helper/log.h>
  40. static int do_semihosting(struct target *target)
  41. {
  42. struct arm *armv4_5 = target_to_arm(target);
  43. uint32_t r0 = buf_get_u32(armv4_5->core_cache->reg_list[0].value, 0, 32);
  44. uint32_t r1 = buf_get_u32(armv4_5->core_cache->reg_list[1].value, 0, 32);
  45. uint32_t lr = buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, ARM_MODE_SVC, 14).value, 0, 32);
  46. uint32_t spsr = buf_get_u32(armv4_5->spsr->value, 0, 32);;
  47. uint8_t params[16];
  48. int retval, result;
  49. /*
  50. * TODO: lots of security issues are not considered yet, such as:
  51. * - no validation on target provided file descriptors
  52. * - no safety checks on opened/deleted/renamed file paths
  53. * Beware the target app you use this support with.
  54. *
  55. * TODO: explore mapping requests to GDB's "File-I/O Remote
  56. * Protocol Extension" ... when GDB is active.
  57. */
  58. switch (r0) {
  59. case 0x01: /* SYS_OPEN */
  60. retval = target_read_memory(target, r1, 4, 3, params);
  61. if (retval != ERROR_OK)
  62. return retval;
  63. else {
  64. uint32_t a = target_buffer_get_u32(target, params+0);
  65. uint32_t m = target_buffer_get_u32(target, params+4);
  66. uint32_t l = target_buffer_get_u32(target, params+8);
  67. if (l <= 255 && m <= 11) {
  68. uint8_t fn[256];
  69. int mode;
  70. retval = target_read_memory(target, a, 1, l, fn);
  71. if (retval != ERROR_OK)
  72. return retval;
  73. fn[l] = 0;
  74. if (m & 0x2)
  75. mode = O_RDWR;
  76. else if (m & 0xc)
  77. mode = O_WRONLY;
  78. else
  79. mode = O_RDONLY;
  80. if (m >= 8)
  81. mode |= O_CREAT|O_APPEND;
  82. else if (m >= 4)
  83. mode |= O_CREAT|O_TRUNC;
  84. if (strcmp((char *)fn, ":tt") == 0) {
  85. if ((mode & 3) == 0)
  86. result = dup(0);
  87. else
  88. result = dup(1);
  89. } else
  90. result = open((char *)fn, mode);
  91. armv4_5->semihosting_errno = errno;
  92. } else {
  93. result = -1;
  94. armv4_5->semihosting_errno = EINVAL;
  95. }
  96. }
  97. break;
  98. case 0x02: /* SYS_CLOSE */
  99. retval = target_read_memory(target, r1, 4, 1, params);
  100. if (retval != ERROR_OK)
  101. return retval;
  102. else {
  103. int fd = target_buffer_get_u32(target, params+0);
  104. result = close(fd);
  105. armv4_5->semihosting_errno = errno;
  106. }
  107. break;
  108. case 0x03: /* SYS_WRITEC */
  109. {
  110. unsigned char c;
  111. retval = target_read_memory(target, r1, 1, 1, &c);
  112. if (retval != ERROR_OK)
  113. return retval;
  114. putchar(c);
  115. result = 0;
  116. }
  117. break;
  118. case 0x04: /* SYS_WRITE0 */
  119. do {
  120. unsigned char c;
  121. retval = target_read_memory(target, r1, 1, 1, &c);
  122. if (retval != ERROR_OK)
  123. return retval;
  124. if (!c)
  125. break;
  126. putchar(c);
  127. } while (1);
  128. result = 0;
  129. break;
  130. case 0x05: /* SYS_WRITE */
  131. retval = target_read_memory(target, r1, 4, 3, params);
  132. if (retval != ERROR_OK)
  133. return retval;
  134. else {
  135. int fd = target_buffer_get_u32(target, params+0);
  136. uint32_t a = target_buffer_get_u32(target, params+4);
  137. size_t l = target_buffer_get_u32(target, params+8);
  138. uint8_t *buf = malloc(l);
  139. if (!buf) {
  140. result = -1;
  141. armv4_5->semihosting_errno = ENOMEM;
  142. } else {
  143. retval = target_read_buffer(target, a, l, buf);
  144. if (retval != ERROR_OK) {
  145. free(buf);
  146. return retval;
  147. }
  148. result = write(fd, buf, l);
  149. armv4_5->semihosting_errno = errno;
  150. if (result >= 0)
  151. result = l - result;
  152. free(buf);
  153. }
  154. }
  155. break;
  156. case 0x06: /* SYS_READ */
  157. retval = target_read_memory(target, r1, 4, 3, params);
  158. if (retval != ERROR_OK)
  159. return retval;
  160. else {
  161. int fd = target_buffer_get_u32(target, params+0);
  162. uint32_t a = target_buffer_get_u32(target, params+4);
  163. ssize_t l = target_buffer_get_u32(target, params+8);
  164. uint8_t *buf = malloc(l);
  165. if (!buf) {
  166. result = -1;
  167. armv4_5->semihosting_errno = ENOMEM;
  168. } else {
  169. result = read(fd, buf, l);
  170. armv4_5->semihosting_errno = errno;
  171. if (result > 0) {
  172. retval = target_write_buffer(target, a, result, buf);
  173. if (retval != ERROR_OK) {
  174. free(buf);
  175. return retval;
  176. }
  177. result = l - result;
  178. }
  179. free(buf);
  180. }
  181. }
  182. break;
  183. case 0x07: /* SYS_READC */
  184. result = getchar();
  185. break;
  186. case 0x08: /* SYS_ISERROR */
  187. retval = target_read_memory(target, r1, 4, 1, params);
  188. if (retval != ERROR_OK)
  189. return retval;
  190. result = (target_buffer_get_u32(target, params+0) != 0);
  191. break;
  192. case 0x09: /* SYS_ISTTY */
  193. retval = target_read_memory(target, r1, 4, 1, params);
  194. if (retval != ERROR_OK)
  195. return retval;
  196. result = isatty(target_buffer_get_u32(target, params+0));
  197. break;
  198. case 0x0a: /* SYS_SEEK */
  199. retval = target_read_memory(target, r1, 4, 2, params);
  200. if (retval != ERROR_OK)
  201. return retval;
  202. else {
  203. int fd = target_buffer_get_u32(target, params+0);
  204. off_t pos = target_buffer_get_u32(target, params+4);
  205. result = lseek(fd, pos, SEEK_SET);
  206. armv4_5->semihosting_errno = errno;
  207. if (result == pos)
  208. result = 0;
  209. }
  210. break;
  211. case 0x0c: /* SYS_FLEN */
  212. retval = target_read_memory(target, r1, 4, 1, params);
  213. if (retval != ERROR_OK)
  214. return retval;
  215. else {
  216. int fd = target_buffer_get_u32(target, params+0);
  217. off_t cur = lseek(fd, 0, SEEK_CUR);
  218. if (cur == (off_t)-1) {
  219. armv4_5->semihosting_errno = errno;
  220. result = -1;
  221. break;
  222. }
  223. result = lseek(fd, 0, SEEK_END);
  224. armv4_5->semihosting_errno = errno;
  225. if (lseek(fd, cur, SEEK_SET) == (off_t)-1) {
  226. armv4_5->semihosting_errno = errno;
  227. result = -1;
  228. }
  229. }
  230. break;
  231. case 0x0e: /* SYS_REMOVE */
  232. retval = target_read_memory(target, r1, 4, 2, params);
  233. if (retval != ERROR_OK)
  234. return retval;
  235. else {
  236. uint32_t a = target_buffer_get_u32(target, params+0);
  237. uint32_t l = target_buffer_get_u32(target, params+4);
  238. if (l <= 255) {
  239. uint8_t fn[256];
  240. retval = target_read_memory(target, a, 1, l, fn);
  241. if (retval != ERROR_OK)
  242. return retval;
  243. fn[l] = 0;
  244. result = remove((char *)fn);
  245. armv4_5->semihosting_errno = errno;
  246. } else {
  247. result = -1;
  248. armv4_5->semihosting_errno = EINVAL;
  249. }
  250. }
  251. break;
  252. case 0x0f: /* SYS_RENAME */
  253. retval = target_read_memory(target, r1, 4, 4, params);
  254. if (retval != ERROR_OK)
  255. return retval;
  256. else {
  257. uint32_t a1 = target_buffer_get_u32(target, params+0);
  258. uint32_t l1 = target_buffer_get_u32(target, params+4);
  259. uint32_t a2 = target_buffer_get_u32(target, params+8);
  260. uint32_t l2 = target_buffer_get_u32(target, params+12);
  261. if (l1 <= 255 && l2 <= 255) {
  262. uint8_t fn1[256], fn2[256];
  263. retval = target_read_memory(target, a1, 1, l1, fn1);
  264. if (retval != ERROR_OK)
  265. return retval;
  266. retval = target_read_memory(target, a2, 1, l2, fn2);
  267. if (retval != ERROR_OK)
  268. return retval;
  269. fn1[l1] = 0;
  270. fn2[l2] = 0;
  271. result = rename((char *)fn1, (char *)fn2);
  272. armv4_5->semihosting_errno = errno;
  273. } else {
  274. result = -1;
  275. armv4_5->semihosting_errno = EINVAL;
  276. }
  277. }
  278. break;
  279. case 0x11: /* SYS_TIME */
  280. result = time(NULL);
  281. break;
  282. case 0x13: /* SYS_ERRNO */
  283. result = armv4_5->semihosting_errno;
  284. break;
  285. case 0x15: /* SYS_GET_CMDLINE */
  286. retval = target_read_memory(target, r1, 4, 2, params);
  287. if (retval != ERROR_OK)
  288. return retval;
  289. else {
  290. uint32_t a = target_buffer_get_u32(target, params+0);
  291. uint32_t l = target_buffer_get_u32(target, params+4);
  292. char *arg = "foobar";
  293. uint32_t s = strlen(arg) + 1;
  294. if (l < s)
  295. result = -1;
  296. else {
  297. retval = target_write_buffer(target, a, s, (void*)arg);
  298. if (retval != ERROR_OK)
  299. return retval;
  300. result = 0;
  301. }
  302. }
  303. break;
  304. case 0x16: /* SYS_HEAPINFO */
  305. retval = target_read_memory(target, r1, 4, 1, params);
  306. if (retval != ERROR_OK)
  307. return retval;
  308. else {
  309. uint32_t a = target_buffer_get_u32(target, params+0);
  310. /* tell the remote we have no idea */
  311. memset(params, 0, 4*4);
  312. retval = target_write_memory(target, a, 4, 4, params);
  313. if (retval != ERROR_OK)
  314. return retval;
  315. result = 0;
  316. }
  317. break;
  318. case 0x18: /* angel_SWIreason_ReportException */
  319. switch (r1) {
  320. case 0x20026: /* ADP_Stopped_ApplicationExit */
  321. fprintf(stderr, "semihosting: *** application exited ***\n");
  322. break;
  323. case 0x20000: /* ADP_Stopped_BranchThroughZero */
  324. case 0x20001: /* ADP_Stopped_UndefinedInstr */
  325. case 0x20002: /* ADP_Stopped_SoftwareInterrupt */
  326. case 0x20003: /* ADP_Stopped_PrefetchAbort */
  327. case 0x20004: /* ADP_Stopped_DataAbort */
  328. case 0x20005: /* ADP_Stopped_AddressException */
  329. case 0x20006: /* ADP_Stopped_IRQ */
  330. case 0x20007: /* ADP_Stopped_FIQ */
  331. case 0x20020: /* ADP_Stopped_BreakPoint */
  332. case 0x20021: /* ADP_Stopped_WatchPoint */
  333. case 0x20022: /* ADP_Stopped_StepComplete */
  334. case 0x20023: /* ADP_Stopped_RunTimeErrorUnknown */
  335. case 0x20024: /* ADP_Stopped_InternalError */
  336. case 0x20025: /* ADP_Stopped_UserInterruption */
  337. case 0x20027: /* ADP_Stopped_StackOverflow */
  338. case 0x20028: /* ADP_Stopped_DivisionByZero */
  339. case 0x20029: /* ADP_Stopped_OSSpecific */
  340. default:
  341. fprintf(stderr, "semihosting: exception %#x\n",
  342. (unsigned) r1);
  343. }
  344. return target_call_event_callbacks(target, TARGET_EVENT_HALTED);
  345. case 0x0d: /* SYS_TMPNAM */
  346. case 0x10: /* SYS_CLOCK */
  347. case 0x12: /* SYS_SYSTEM */
  348. case 0x17: /* angel_SWIreason_EnterSVC */
  349. case 0x30: /* SYS_ELAPSED */
  350. case 0x31: /* SYS_TICKFREQ */
  351. default:
  352. fprintf(stderr, "semihosting: unsupported call %#x\n",
  353. (unsigned) r0);
  354. result = -1;
  355. armv4_5->semihosting_errno = ENOTSUP;
  356. }
  357. /* resume execution to the original mode */
  358. /* return value in R0 */
  359. buf_set_u32(armv4_5->core_cache->reg_list[0].value, 0, 32, result);
  360. armv4_5->core_cache->reg_list[0].dirty = 1;
  361. /* LR --> PC */
  362. buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, lr);
  363. armv4_5->core_cache->reg_list[15].dirty = 1;
  364. /* saved PSR --> current PSR */
  365. buf_set_u32(armv4_5->cpsr->value, 0, 32, spsr);
  366. armv4_5->cpsr->dirty = 1;
  367. armv4_5->core_mode = spsr & 0x1f;
  368. if (spsr & 0x20)
  369. armv4_5->core_state = ARM_STATE_THUMB;
  370. return target_resume(target, 1, 0, 0, 0);
  371. }
  372. /**
  373. * Checks for and processes an ARM semihosting request. This is meant
  374. * to be called when the target is stopped due to a debug mode entry.
  375. * If the value 0 is returned then there was nothing to process. A non-zero
  376. * return value signifies that a request was processed and the target resumed,
  377. * or an error was encountered, in which case the caller must return
  378. * immediately.
  379. *
  380. * @param target Pointer to the ARM target to process. This target must
  381. * not represent an ARMv6-M or ARMv7-M processor.
  382. * @param retval Pointer to a location where the return code will be stored
  383. * @return non-zero value if a request was processed or an error encountered
  384. */
  385. int arm_semihosting(struct target *target, int *retval)
  386. {
  387. struct arm *arm = target_to_arm(target);
  388. uint32_t pc, lr, spsr;
  389. struct reg *r;
  390. if (!arm->is_semihosting || arm->core_mode != ARM_MODE_SVC)
  391. return 0;
  392. /* Check for PC == 0x00000008 or 0xffff0008: Supervisor Call vector. */
  393. r = arm->core_cache->reg_list + 15;
  394. pc = buf_get_u32(r->value, 0, 32);
  395. if (pc != 0x00000008 && pc != 0xffff0008)
  396. return 0;
  397. r = arm_reg_current(arm, 14);
  398. lr = buf_get_u32(r->value, 0, 32);
  399. /* Core-specific code should make sure SPSR is retrieved
  400. * when the above checks pass...
  401. */
  402. if (!arm->spsr->valid) {
  403. LOG_ERROR("SPSR not valid!");
  404. *retval = ERROR_FAIL;
  405. return 1;
  406. }
  407. spsr = buf_get_u32(arm->spsr->value, 0, 32);
  408. /* check instruction that triggered this trap */
  409. if (spsr & (1 << 5)) {
  410. /* was in Thumb (or ThumbEE) mode */
  411. uint8_t insn_buf[2];
  412. uint16_t insn;
  413. *retval = target_read_memory(target, lr-2, 2, 1, insn_buf);
  414. if (*retval != ERROR_OK)
  415. return 1;
  416. insn = target_buffer_get_u16(target, insn_buf);
  417. /* SVC 0xab */
  418. if (insn != 0xDFAB)
  419. return 0;
  420. } else if (spsr & (1 << 24)) {
  421. /* was in Jazelle mode */
  422. return 0;
  423. } else {
  424. /* was in ARM mode */
  425. uint8_t insn_buf[4];
  426. uint32_t insn;
  427. *retval = target_read_memory(target, lr-4, 4, 1, insn_buf);
  428. if (*retval != ERROR_OK)
  429. return 1;
  430. insn = target_buffer_get_u32(target, insn_buf);
  431. /* SVC 0x123456 */
  432. if (insn != 0xEF123456)
  433. return 0;
  434. }
  435. *retval = do_semihosting(target);
  436. return 1;
  437. }