devmem_service.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. /*
  2. * Copyright (c) 2020 Intel Corporation
  3. * Copyright (c) 2021 Antmicro <www.antmicro.com>
  4. *
  5. * SPDX-License-Identifier: Apache-2.0
  6. */
  7. #include <stdlib.h>
  8. #include <device.h>
  9. #include <shell/shell.h>
  10. #include <sys/byteorder.h>
  11. static inline bool is_ascii(uint8_t data)
  12. {
  13. return (data >= 0x30 && data <= 0x39) || (data >= 0x61 && data <= 0x66) ||
  14. (data >= 0x41 && data <= 0x46);
  15. }
  16. static unsigned char *bytes;
  17. static uint32_t *data;
  18. static int sum;
  19. static int chunk_element;
  20. static char chunk[2];
  21. static bool littleendian;
  22. #define CHAR_CAN 0x18
  23. #define CHAR_DC1 0x11
  24. static int set_bypass(const struct shell *sh, shell_bypass_cb_t bypass)
  25. {
  26. static bool in_use;
  27. if (bypass && in_use) {
  28. shell_error(sh, "devmem load supports setting bypass on a single instance.");
  29. return -EBUSY;
  30. }
  31. in_use = !in_use;
  32. if (in_use) {
  33. shell_print(sh, "Loading...\npress ctrl-x ctrl-q to escape");
  34. in_use = true;
  35. }
  36. shell_set_bypass(sh, bypass);
  37. return 0;
  38. }
  39. static void bypass_cb(const struct shell *sh, uint8_t *recv, size_t len)
  40. {
  41. bool escape = false;
  42. static uint8_t tail;
  43. uint8_t byte;
  44. if (tail == CHAR_CAN && recv[0] == CHAR_DC1) {
  45. escape = true;
  46. } else {
  47. for (int i = 0; i < (len - 1); i++) {
  48. if (recv[i] == CHAR_CAN && recv[i + 1] == CHAR_DC1) {
  49. escape = true;
  50. break;
  51. }
  52. }
  53. }
  54. if (escape) {
  55. shell_print(sh, "Number of bytes read: %d", sum);
  56. set_bypass(sh, NULL);
  57. if (!littleendian) {
  58. while (sum > 4) {
  59. *data = __bswap_32(*data);
  60. data++;
  61. sum = sum - 4;
  62. }
  63. if (sum % 4 == 0) {
  64. *data = __bswap_32(*data);
  65. } else if (sum % 4 == 2) {
  66. *data = __bswap_16(*data);
  67. } else if (sum % 4 == 3) {
  68. *data = __bswap_24(*data);
  69. }
  70. }
  71. return;
  72. }
  73. tail = recv[len - 1];
  74. if (is_ascii(*recv)) {
  75. chunk[chunk_element] = *recv;
  76. chunk_element++;
  77. }
  78. if (chunk_element == 2) {
  79. byte = (uint8_t)strtoul(chunk, NULL, 16);
  80. *bytes = byte;
  81. bytes++;
  82. sum++;
  83. chunk_element = 0;
  84. }
  85. }
  86. static int cmd_load(const struct shell *sh, size_t argc, char **argv)
  87. {
  88. littleendian = false;
  89. char *arg;
  90. chunk_element = 0;
  91. sum = 0;
  92. while (argc >= 2) {
  93. arg = argv[1] + (!strncmp(argv[1], "--", 2) && argv[1][2]);
  94. if (!strncmp(arg, "-e", 2)) {
  95. littleendian = true;
  96. } else if (!strcmp(arg, "--")) {
  97. argv++;
  98. argc--;
  99. break;
  100. } else if (arg[0] == '-' && arg[1]) {
  101. shell_print(sh, "Unknown option \"%s\"", arg);
  102. } else {
  103. break;
  104. }
  105. argv++;
  106. argc--;
  107. }
  108. bytes = (unsigned char *)strtol(argv[1], NULL, 0);
  109. data = (uint32_t *)strtol(argv[1], NULL, 0);
  110. set_bypass(sh, bypass_cb);
  111. return 0;
  112. }
  113. static int memory_read(const struct shell *sh, mem_addr_t addr, uint8_t width)
  114. {
  115. uint64_t value;
  116. int err = 0;
  117. switch (width) {
  118. case 8:
  119. value = sys_read8(addr);
  120. break;
  121. case 16:
  122. value = sys_read16(addr);
  123. break;
  124. case 32:
  125. value = sys_read32(addr);
  126. break;
  127. default:
  128. shell_fprintf(sh, SHELL_NORMAL, "Incorrect data width\n");
  129. err = -EINVAL;
  130. break;
  131. }
  132. if (err == 0) {
  133. shell_fprintf(sh, SHELL_NORMAL, "Read value 0x%lx\n", value);
  134. }
  135. return err;
  136. }
  137. static int memory_write(const struct shell *sh, mem_addr_t addr, uint8_t width, uint64_t value)
  138. {
  139. int err = 0;
  140. switch (width) {
  141. case 8:
  142. sys_write8(value, addr);
  143. break;
  144. case 16:
  145. sys_write16(value, addr);
  146. break;
  147. case 32:
  148. sys_write32(value, addr);
  149. break;
  150. default:
  151. shell_fprintf(sh, SHELL_NORMAL, "Incorrect data width\n");
  152. err = -EINVAL;
  153. break;
  154. }
  155. return err;
  156. }
  157. /* The syntax of the command is similar to busybox's devmem */
  158. static int cmd_devmem(const struct shell *sh, size_t argc, char **argv)
  159. {
  160. mem_addr_t phys_addr, addr;
  161. uint32_t value = 0;
  162. uint8_t width;
  163. if (argc < 2 || argc > 4) {
  164. return -EINVAL;
  165. }
  166. phys_addr = strtoul(argv[1], NULL, 16);
  167. #if defined(CONFIG_MMU) || defined(CONFIG_PCIE)
  168. device_map((mm_reg_t *)&addr, phys_addr, 0x100, K_MEM_CACHE_NONE);
  169. shell_print(sh, "Mapped 0x%lx to 0x%lx\n", phys_addr, addr);
  170. #else
  171. addr = phys_addr;
  172. #endif /* defined(CONFIG_MMU) || defined(CONFIG_PCIE) */
  173. if (argc < 3) {
  174. width = 32;
  175. } else {
  176. width = strtoul(argv[2], NULL, 10);
  177. }
  178. shell_fprintf(sh, SHELL_NORMAL, "Using data width %d\n", width);
  179. if (argc <= 3) {
  180. return memory_read(sh, addr, width);
  181. }
  182. /* If there are more then 3 arguments, that means we are going to write
  183. * this value at the address provided
  184. */
  185. value = strtoul(argv[3], NULL, 16);
  186. shell_fprintf(sh, SHELL_NORMAL, "Writing value 0x%lx\n", value);
  187. return memory_write(sh, addr, width, value);
  188. }
  189. SHELL_STATIC_SUBCMD_SET_CREATE(sub_devmem,
  190. SHELL_CMD_ARG(load, NULL,
  191. "Usage:\n"
  192. "devmem load [options] [address]\n"
  193. "Options:\n"
  194. "-e\tlittle-endian parse",
  195. cmd_load, 2, 1),
  196. SHELL_SUBCMD_SET_END);
  197. SHELL_CMD_REGISTER(devmem, &sub_devmem,
  198. "Read/write physical memory\""
  199. "devmem address [width [value]]",
  200. cmd_devmem);