semihosting.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. /*
  2. * Copyright 2014 Broadcom Corporation
  3. *
  4. * SPDX-License-Identifier: GPL-2.0+
  5. */
  6. /*
  7. * Minimal semihosting implementation for reading files into memory. If more
  8. * features like writing files or console output are required they can be
  9. * added later. This code has been tested on arm64/aarch64 fastmodel only.
  10. * An untested placeholder exists for armv7 architectures, but since they
  11. * are commonly available in silicon now, fastmodel usage makes less sense
  12. * for them.
  13. */
  14. #include <common.h>
  15. #include <asm/semihosting.h>
  16. #define SYSOPEN 0x01
  17. #define SYSCLOSE 0x02
  18. #define SYSREAD 0x06
  19. #define SYSFLEN 0x0C
  20. #define MODE_READ 0x0
  21. #define MODE_READBIN 0x1
  22. static int smh_read(int fd, void *memp, int len);
  23. static int smh_open(const char *fname, char *modestr);
  24. static int smh_close(int fd);
  25. static int smh_len_fd(int fd);
  26. /*
  27. * Call the handler
  28. */
  29. static int smh_trap(unsigned int sysnum, void *addr)
  30. {
  31. register int result asm("r0");
  32. #if defined(CONFIG_ARM64)
  33. asm volatile ("hlt #0xf000" : "=r" (result) : "0"(sysnum), "r"(addr));
  34. #else
  35. /* Note - untested placeholder */
  36. asm volatile ("svc #0x123456" : "=r" (result) : "0"(sysnum), "r"(addr));
  37. #endif
  38. return result;
  39. }
  40. /*
  41. * Open, load a file into memory, and close it. Check that the available space
  42. * is sufficient to store the entire file. Return the bytes actually read from
  43. * the file as seen by the read function. The verbose flag enables some extra
  44. * printing of successful read status.
  45. */
  46. int smh_load(const char *fname, void *memp, int avail, int verbose)
  47. {
  48. int ret, fd, len;
  49. ret = -1;
  50. debug("%s: fname \'%s\', avail %u, memp %p\n", __func__, fname,
  51. avail, memp);
  52. /* Open the file */
  53. fd = smh_open(fname, "rb");
  54. if (fd == -1)
  55. return ret;
  56. /* Get the file length */
  57. ret = smh_len_fd(fd);
  58. if (ret == -1) {
  59. smh_close(fd);
  60. return ret;
  61. }
  62. /* Check that the file will fit in the supplied buffer */
  63. if (ret > avail) {
  64. printf("%s: ERROR ret %d, avail %u\n", __func__, ret,
  65. avail);
  66. smh_close(fd);
  67. return ret;
  68. }
  69. len = ret;
  70. /* Read the file into the buffer */
  71. ret = smh_read(fd, memp, len);
  72. if (ret == 0) {
  73. /* Print successful load information if requested */
  74. if (verbose) {
  75. printf("\n%s\n", fname);
  76. printf(" 0x%8p dest\n", memp);
  77. printf(" 0x%08x size\n", len);
  78. printf(" 0x%08x avail\n", avail);
  79. }
  80. }
  81. /* Close the file */
  82. smh_close(fd);
  83. return ret;
  84. }
  85. /*
  86. * Read 'len' bytes of file into 'memp'. Returns 0 on success, else failure
  87. */
  88. static int smh_read(int fd, void *memp, int len)
  89. {
  90. int ret;
  91. struct smh_read_s {
  92. int fd;
  93. void *memp;
  94. int len;
  95. } read;
  96. debug("%s: fd %d, memp %p, len %d\n", __func__, fd, memp, len);
  97. read.fd = fd;
  98. read.memp = memp;
  99. read.len = len;
  100. ret = smh_trap(SYSREAD, &read);
  101. if (ret == 0) {
  102. return 0;
  103. } else {
  104. /*
  105. * The ARM handler allows for returning partial lengths,
  106. * but in practice this never happens so rather than create
  107. * hard to maintain partial read loops and such, just fail
  108. * with an error message.
  109. */
  110. printf("%s: ERROR ret %d, fd %d, len %u memp %p\n",
  111. __func__, ret, fd, len, memp);
  112. }
  113. return ret;
  114. }
  115. /*
  116. * Open a file on the host. Mode is "r" or "rb" currently. Returns a file
  117. * descriptor or -1 on error.
  118. */
  119. static int smh_open(const char *fname, char *modestr)
  120. {
  121. int ret, fd, mode;
  122. struct smh_open_s {
  123. const char *fname;
  124. unsigned int mode;
  125. unsigned int len;
  126. } open;
  127. debug("%s: file \'%s\', mode \'%s\'\n", __func__, fname, modestr);
  128. ret = -1;
  129. /* Check the file mode */
  130. if (!(strcmp(modestr, "r"))) {
  131. mode = MODE_READ;
  132. } else if (!(strcmp(modestr, "rb"))) {
  133. mode = MODE_READBIN;
  134. } else {
  135. printf("%s: ERROR mode \'%s\' not supported\n", __func__,
  136. modestr);
  137. return ret;
  138. }
  139. open.fname = fname;
  140. open.len = strlen(fname);
  141. open.mode = mode;
  142. /* Open the file on the host */
  143. fd = smh_trap(SYSOPEN, &open);
  144. if (fd == -1)
  145. printf("%s: ERROR fd %d for file \'%s\'\n", __func__, fd,
  146. fname);
  147. return fd;
  148. }
  149. /*
  150. * Close the file using the file descriptor
  151. */
  152. static int smh_close(int fd)
  153. {
  154. int ret;
  155. long fdlong;
  156. debug("%s: fd %d\n", __func__, fd);
  157. fdlong = (long)fd;
  158. ret = smh_trap(SYSCLOSE, &fdlong);
  159. if (ret == -1)
  160. printf("%s: ERROR fd %d\n", __func__, fd);
  161. return ret;
  162. }
  163. /*
  164. * Get the file length from the file descriptor
  165. */
  166. static int smh_len_fd(int fd)
  167. {
  168. int ret;
  169. long fdlong;
  170. debug("%s: fd %d\n", __func__, fd);
  171. fdlong = (long)fd;
  172. ret = smh_trap(SYSFLEN, &fdlong);
  173. if (ret == -1)
  174. printf("%s: ERROR ret %d\n", __func__, ret);
  175. return ret;
  176. }
  177. /*
  178. * Get the file length from the filename
  179. */
  180. int smh_len(const char *fname)
  181. {
  182. int ret, fd, len;
  183. debug("%s: file \'%s\'\n", __func__, fname);
  184. /* Open the file */
  185. fd = smh_open(fname, "rb");
  186. if (fd == -1)
  187. return fd;
  188. /* Get the file length */
  189. len = smh_len_fd(fd);
  190. /* Close the file */
  191. ret = smh_close(fd);
  192. if (ret == -1)
  193. return ret;
  194. debug("%s: returning len %d\n", __func__, len);
  195. /* Return the file length (or -1 error indication) */
  196. return len;
  197. }