htif.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. /*
  2. * SPDX-License-Identifier: BSD-3-Clause
  3. *
  4. * Copyright (c) 2010-2020, The Regents of the University of California
  5. * (Regents). All Rights Reserved.
  6. */
  7. #include <sbi/riscv_locks.h>
  8. #include <sbi/sbi_console.h>
  9. #include <sbi/sbi_error.h>
  10. #include <sbi/sbi_system.h>
  11. #include <sbi_utils/sys/htif.h>
  12. #define HTIF_DATA_BITS 48
  13. #define HTIF_DATA_MASK ((1ULL << HTIF_DATA_BITS) - 1)
  14. #define HTIF_DATA_SHIFT 0
  15. #define HTIF_CMD_BITS 8
  16. #define HTIF_CMD_MASK ((1ULL << HTIF_CMD_BITS) - 1)
  17. #define HTIF_CMD_SHIFT 48
  18. #define HTIF_DEV_BITS 8
  19. #define HTIF_DEV_MASK ((1ULL << HTIF_DEV_BITS) - 1)
  20. #define HTIF_DEV_SHIFT 56
  21. #define HTIF_DEV_SYSTEM 0
  22. #define HTIF_DEV_CONSOLE 1
  23. #define HTIF_CONSOLE_CMD_GETC 0
  24. #define HTIF_CONSOLE_CMD_PUTC 1
  25. #if __riscv_xlen == 64
  26. # define TOHOST_CMD(dev, cmd, payload) \
  27. (((uint64_t)(dev) << HTIF_DEV_SHIFT) | \
  28. ((uint64_t)(cmd) << HTIF_CMD_SHIFT) | \
  29. (uint64_t)(payload))
  30. #else
  31. # define TOHOST_CMD(dev, cmd, payload) ({ \
  32. if ((dev) || (cmd)) __builtin_trap(); \
  33. (payload); })
  34. #endif
  35. #define FROMHOST_DEV(fromhost_value) \
  36. ((uint64_t)((fromhost_value) >> HTIF_DEV_SHIFT) & HTIF_DEV_MASK)
  37. #define FROMHOST_CMD(fromhost_value) \
  38. ((uint64_t)((fromhost_value) >> HTIF_CMD_SHIFT) & HTIF_CMD_MASK)
  39. #define FROMHOST_DATA(fromhost_value) \
  40. ((uint64_t)((fromhost_value) >> HTIF_DATA_SHIFT) & HTIF_DATA_MASK)
  41. #define PK_SYS_write 64
  42. volatile uint64_t tohost __attribute__((section(".htif")));
  43. volatile uint64_t fromhost __attribute__((section(".htif")));
  44. static uint64_t *htif_fromhost = NULL;
  45. static uint64_t *htif_tohost = NULL;
  46. static bool htif_custom = false;
  47. static int htif_console_buf;
  48. static spinlock_t htif_lock = SPIN_LOCK_INITIALIZER;
  49. static inline uint64_t __read_tohost(void)
  50. {
  51. return (htif_custom) ? *htif_tohost : tohost;
  52. }
  53. static inline void __write_tohost(uint64_t val)
  54. {
  55. if (htif_custom)
  56. *htif_tohost = val;
  57. else
  58. tohost = val;
  59. }
  60. static inline uint64_t __read_fromhost(void)
  61. {
  62. return (htif_custom) ? *htif_fromhost : fromhost;
  63. }
  64. static inline void __write_fromhost(uint64_t val)
  65. {
  66. if (htif_custom)
  67. *htif_fromhost = val;
  68. else
  69. fromhost = val;
  70. }
  71. static void __check_fromhost()
  72. {
  73. uint64_t fh = __read_fromhost();
  74. if (!fh)
  75. return;
  76. __write_fromhost(0);
  77. /* this should be from the console */
  78. if (FROMHOST_DEV(fh) != HTIF_DEV_CONSOLE)
  79. __builtin_trap();
  80. switch (FROMHOST_CMD(fh)) {
  81. case HTIF_CONSOLE_CMD_GETC:
  82. htif_console_buf = 1 + (uint8_t)FROMHOST_DATA(fh);
  83. break;
  84. case HTIF_CONSOLE_CMD_PUTC:
  85. break;
  86. default:
  87. __builtin_trap();
  88. }
  89. }
  90. static void __set_tohost(uint64_t dev, uint64_t cmd, uint64_t data)
  91. {
  92. while (__read_tohost())
  93. __check_fromhost();
  94. __write_tohost(TOHOST_CMD(dev, cmd, data));
  95. }
  96. static int set_custom_addr(bool custom_addr,
  97. unsigned long custom_fromhost_addr,
  98. unsigned long custom_tohost_addr)
  99. {
  100. if (custom_addr) {
  101. if (htif_custom &&
  102. ((custom_fromhost_addr != (unsigned long)htif_fromhost) ||
  103. (custom_tohost_addr != (unsigned long)htif_tohost)))
  104. return SBI_EINVAL;
  105. htif_fromhost = (uint64_t *)custom_fromhost_addr;
  106. htif_tohost = (uint64_t *)custom_tohost_addr;
  107. htif_custom = true;
  108. }
  109. return 0;
  110. }
  111. #if __riscv_xlen == 32
  112. static void do_tohost_fromhost(uint64_t dev, uint64_t cmd, uint64_t data)
  113. {
  114. spin_lock(&htif_lock);
  115. __set_tohost(HTIF_DEV_SYSTEM, cmd, data);
  116. while (1) {
  117. uint64_t fh = __read_fromhost();
  118. if (fh) {
  119. if (FROMHOST_DEV(fh) == HTIF_DEV_SYSTEM &&
  120. FROMHOST_CMD(fh) == cmd) {
  121. __write_fromhost(0);
  122. break;
  123. }
  124. __check_fromhost();
  125. }
  126. }
  127. spin_unlock(&htif_lock);
  128. }
  129. static void htif_putc(char ch)
  130. {
  131. /* HTIF devices are not supported on RV32, so do a proxy write call */
  132. volatile uint64_t magic_mem[8];
  133. magic_mem[0] = PK_SYS_write;
  134. magic_mem[1] = HTIF_DEV_CONSOLE;
  135. magic_mem[2] = (uint64_t)(uintptr_t)&ch;
  136. magic_mem[3] = HTIF_CONSOLE_CMD_PUTC;
  137. do_tohost_fromhost(HTIF_DEV_SYSTEM, 0, (uint64_t)(uintptr_t)magic_mem);
  138. }
  139. #else
  140. static void htif_putc(char ch)
  141. {
  142. spin_lock(&htif_lock);
  143. __set_tohost(HTIF_DEV_CONSOLE, HTIF_CONSOLE_CMD_PUTC, ch);
  144. spin_unlock(&htif_lock);
  145. }
  146. #endif
  147. static int htif_getc(void)
  148. {
  149. int ch;
  150. #if __riscv_xlen == 32
  151. /* HTIF devices are not supported on RV32 */
  152. return -1;
  153. #endif
  154. spin_lock(&htif_lock);
  155. __check_fromhost();
  156. ch = htif_console_buf;
  157. if (ch >= 0) {
  158. htif_console_buf = -1;
  159. __set_tohost(HTIF_DEV_CONSOLE, HTIF_CONSOLE_CMD_GETC, 0);
  160. }
  161. spin_unlock(&htif_lock);
  162. return ch - 1;
  163. }
  164. static struct sbi_console_device htif_console = {
  165. .name = "htif",
  166. .console_putc = htif_putc,
  167. .console_getc = htif_getc
  168. };
  169. int htif_serial_init(bool custom_addr,
  170. unsigned long custom_fromhost_addr,
  171. unsigned long custom_tohost_addr)
  172. {
  173. int rc;
  174. rc = set_custom_addr(custom_addr, custom_fromhost_addr,
  175. custom_tohost_addr);
  176. if (rc)
  177. return rc;
  178. sbi_console_set_device(&htif_console);
  179. return 0;
  180. }
  181. static int htif_system_reset_check(u32 type, u32 reason)
  182. {
  183. return 1;
  184. }
  185. static void htif_system_reset(u32 type, u32 reason)
  186. {
  187. while (1) {
  188. __write_fromhost(0);
  189. __write_tohost(1);
  190. }
  191. }
  192. static struct sbi_system_reset_device htif_reset = {
  193. .name = "htif",
  194. .system_reset_check = htif_system_reset_check,
  195. .system_reset = htif_system_reset
  196. };
  197. int htif_system_reset_init(bool custom_addr,
  198. unsigned long custom_fromhost_addr,
  199. unsigned long custom_tohost_addr)
  200. {
  201. int rc;
  202. rc = set_custom_addr(custom_addr, custom_fromhost_addr,
  203. custom_tohost_addr);
  204. if (rc)
  205. return rc;
  206. sbi_system_reset_add_device(&htif_reset);
  207. return 0;
  208. }