openocd_semihosting.h 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. /*
  2. * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #pragma once
  7. #include <string.h>
  8. #include <sys/errno.h>
  9. #ifdef __XTENSA__
  10. #include "xtensa/semihosting.h"
  11. #elif __riscv
  12. #include "riscv/semihosting.h"
  13. #else
  14. #error Unsupported architecture
  15. #endif
  16. #ifdef __cplusplus
  17. extern "C" {
  18. #endif
  19. /**
  20. * Semihosting call numbers and functions for OpenOCD.
  21. * In OpenOCD, ARM semihosting call numbers and parameters are used for
  22. * RISC-V and Xtensa targets.
  23. *
  24. * These conventions are not compatible with Xtensa ISS and QEMU for Xtensa,
  25. * which the actual Xtensa-specific semihosting call numbers and formats;
  26. * these are not supported in ESP-IDF yet.
  27. */
  28. #define SEMIHOSTING_SYS_CLOCK 0x10
  29. #define SEMIHOSTING_SYS_CLOSE 0x02
  30. #define SEMIHOSTING_SYS_ERRNO 0x13
  31. #define SEMIHOSTING_SYS_EXIT 0x18
  32. #define SEMIHOSTING_SYS_EXIT_EXTENDED 0x20
  33. #define SEMIHOSTING_SYS_FLEN 0x0C
  34. #define SEMIHOSTING_SYS_GET_CMDLINE 0x15
  35. #define SEMIHOSTING_SYS_HEAPINFO 0x16
  36. #define SEMIHOSTING_SYS_ISERROR 0x08
  37. #define SEMIHOSTING_SYS_ISTTY 0x09
  38. #define SEMIHOSTING_SYS_OPEN 0x01
  39. #define SEMIHOSTING_SYS_READ 0x06
  40. #define SEMIHOSTING_SYS_READC 0x07
  41. #define SEMIHOSTING_SYS_REMOVE 0x0E
  42. #define SEMIHOSTING_SYS_RENAME 0x0F
  43. #define SEMIHOSTING_SYS_SEEK 0x0A
  44. #define SEMIHOSTING_SYS_SYSTEM 0x12
  45. #define SEMIHOSTING_SYS_TIME 0x11
  46. #define SEMIHOSTING_SYS_WRITE 0x05
  47. #define SEMIHOSTING_SYS_WRITEC 0x03
  48. #define SEMIHOSTING_SYS_WRITE0 0x04
  49. /* This call is an Espressif OpenOCD extension to send the version
  50. * information to the host. This lets the host support different IDF versions,
  51. * allowing semihosting interface to be modified over time.
  52. *
  53. * The parameters of this call are:
  54. * - pointer to the version info structure,
  55. * - size of the version info structure.
  56. *
  57. * At present, the structure should contain a single word, indicating
  58. * the semihosting interface version used by the target.
  59. *
  60. * If the syscall is recognized, the return value is zero.
  61. */
  62. #define ESP_SEMIHOSTING_SYS_DRV_INFO 0x100
  63. /* 0x101...0x104 used by RiscV for custom semihosting calls */
  64. /* Other Espressif extension sys calls */
  65. #define ESP_SEMIHOSTING_SYS_SEEK 0x105 /* custom lseek with whence */
  66. /* not implemented yet */
  67. #define ESP_SEMIHOSTING_SYS_MKDIR 0x106
  68. #define ESP_SEMIHOSTING_SYS_OPENDIR 0x107
  69. #define ESP_SEMIHOSTING_SYS_READDIR 0x108
  70. #define ESP_SEMIHOSTING_SYS_READDIR_R 0x109
  71. #define ESP_SEMIHOSTING_SYS_SEEKDIR 0x10A
  72. #define ESP_SEMIHOSTING_SYS_TELLDIR 0x10B
  73. #define ESP_SEMIHOSTING_SYS_CLOSEDIR 0x10C
  74. #define ESP_SEMIHOSTING_SYS_RMDIR 0x10D
  75. #define ESP_SEMIHOSTING_SYS_ACCESS 0x10E
  76. #define ESP_SEMIHOSTING_SYS_TRUNCATE 0x10F
  77. #define ESP_SEMIHOSTING_SYS_UTIME 0x110
  78. #define ESP_SEMIHOSTING_SYS_FSTAT 0x111
  79. #define ESP_SEMIHOSTING_SYS_STAT 0x112
  80. #define ESP_SEMIHOSTING_SYS_FSYNC 0x113
  81. #define ESP_SEMIHOSTING_SYS_LINK 0x114
  82. #define ESP_SEMIHOSTING_SYS_UNLINK 0x115
  83. /* Semihosting version bumped to 2. Changelog;
  84. 1 - Memory based approach with 2 registers implemented as defined in the ARM standard.
  85. 2 - User defined syscall numbers located between 0x100-0x1FF
  86. 3 - The break instruction operands updated to (1, 14)
  87. 4 - Absolute path support is dropped
  88. */
  89. #define SEMIHOSTING_DRV_VERSION 2
  90. /**
  91. * @brief Perform semihosting call and retrieve errno
  92. *
  93. * @param id semihosting call number
  94. * @param data data block to pass to the host; number of items and their
  95. * meaning depends on the semihosting call. See the spec for
  96. * details.
  97. * @param[out] out_errno output, errno value from the host. Only set if
  98. * the return value is negative.
  99. * @return return value from the host
  100. */
  101. static inline long semihosting_call(long id, long *data, int *out_errno)
  102. {
  103. long ret = semihosting_call_noerrno(id, data);
  104. if (ret < 0) {
  105. const int semihosting_sys_errno = SEMIHOSTING_SYS_ERRNO;
  106. *out_errno = (int) semihosting_call_noerrno(semihosting_sys_errno, NULL);
  107. }
  108. return ret;
  109. }
  110. static inline int semihosting_open(const char *path, int open_mode, int mode)
  111. {
  112. int host_errno = 0;
  113. long args[] = {(long) path, open_mode, strlen(path), 0};
  114. (void) mode; // unused in OpenOCD
  115. int result = (int) semihosting_call(SEMIHOSTING_SYS_OPEN, args, &host_errno);
  116. if (result < 0) {
  117. errno = host_errno;
  118. }
  119. return result;
  120. }
  121. static inline ssize_t semihosting_write(int fd, const void *data, size_t size)
  122. {
  123. int host_errno = 0;
  124. long args[] = {fd, (long) data, size, 0};
  125. ssize_t ret = (ssize_t) semihosting_call(SEMIHOSTING_SYS_WRITE, args, &host_errno);
  126. if (ret < 0) {
  127. errno = host_errno;
  128. return ret;
  129. }
  130. /* On success, write syscall returns the number of bytes NOT written,
  131. * adjust the return value to match POSIX.
  132. */
  133. return size - (ssize_t)ret;
  134. }
  135. static inline ssize_t semihosting_read(int fd, void *data, size_t size)
  136. {
  137. int host_errno = 0;
  138. long args[] = {fd, (long) data, size, 0};
  139. ssize_t ret = (ssize_t) semihosting_call(SEMIHOSTING_SYS_READ, args, &host_errno);
  140. if (ret < 0) {
  141. errno = host_errno;
  142. return ret;
  143. }
  144. /* On success, read syscall returns the number of bytes NOT read,
  145. * adjust the return value to match POSIX.
  146. */
  147. return size - (ssize_t)ret;
  148. }
  149. static inline int semihosting_close(int fd)
  150. {
  151. int host_errno = 0;
  152. long args[] = {fd, 0, 0, 0};
  153. int ret = (int) semihosting_call(SEMIHOSTING_SYS_CLOSE, args, &host_errno);
  154. if (ret < 0) {
  155. errno = host_errno;
  156. }
  157. return ret;
  158. }
  159. static inline off_t semihosting_seek(int fd, off_t offset, int mode)
  160. {
  161. int host_errno = 0;
  162. long args[] = {fd, offset, mode, 0};
  163. off_t ret = (off_t) semihosting_call(ESP_SEMIHOSTING_SYS_SEEK, args, &host_errno);
  164. if (ret == -1) {
  165. errno = host_errno;
  166. }
  167. return ret;
  168. }
  169. static inline int semihosting_ver_info(void)
  170. {
  171. int host_errno = 0;
  172. struct {
  173. int version;
  174. } ver_info = { SEMIHOSTING_DRV_VERSION };
  175. long args[] = {(long) &ver_info, sizeof(ver_info), 0, 0};
  176. int ret = (int) semihosting_call(ESP_SEMIHOSTING_SYS_DRV_INFO, args, &host_errno);
  177. (void) host_errno; /* errno not set by this call */
  178. return ret;
  179. }
  180. #ifdef __cplusplus
  181. }
  182. #endif