|
1 | 1 | /* |
2 | 2 | * Copyright (c) 2020 Intel Corporation |
| 3 | + * Copyright (c) 2021 Antmicro <www.antmicro.com> |
3 | 4 | * |
4 | 5 | * SPDX-License-Identifier: Apache-2.0 |
5 | 6 | */ |
6 | 7 |
|
| 8 | +#include <stdlib.h> |
7 | 9 | #include <device.h> |
8 | 10 | #include <shell/shell.h> |
9 | | -#include <stdlib.h> |
| 11 | +#include <sys/byteorder.h> |
| 12 | + |
| 13 | +static inline bool is_ascii(uint8_t data) |
| 14 | +{ |
| 15 | + return (data >= 0x30 && data <= 0x39) || (data >= 0x61 && data <= 0x66) || |
| 16 | + (data >= 0x41 && data <= 0x46); |
| 17 | +} |
| 18 | + |
| 19 | +static unsigned char *bytes; |
| 20 | +static uint32_t *data; |
| 21 | +static int sum; |
| 22 | +static int chunk_element; |
| 23 | +static char chunk[2]; |
| 24 | +static bool littleendian; |
| 25 | + |
| 26 | +#define CHAR_CAN 0x18 |
| 27 | +#define CHAR_DC1 0x11 |
| 28 | + |
| 29 | +static int set_bypass(const struct shell *sh, shell_bypass_cb_t bypass) |
| 30 | +{ |
| 31 | + static bool in_use; |
| 32 | + |
| 33 | + if (bypass && in_use) { |
| 34 | + shell_error(sh, "devmem load supports setting bypass on a single instance."); |
| 35 | + |
| 36 | + return -EBUSY; |
| 37 | + } |
| 38 | + |
| 39 | + in_use = !in_use; |
| 40 | + if (in_use) { |
| 41 | + shell_print(sh, "Loading...\npress ctrl-x ctrl-q to escape"); |
| 42 | + in_use = true; |
| 43 | + } |
| 44 | + |
| 45 | + shell_set_bypass(sh, bypass); |
| 46 | + |
| 47 | + return 0; |
| 48 | +} |
| 49 | + |
| 50 | +static void bypass_cb(const struct shell *sh, uint8_t *recv, size_t len) |
| 51 | +{ |
| 52 | + bool escape = false; |
| 53 | + static uint8_t tail; |
| 54 | + uint8_t byte; |
| 55 | + |
| 56 | + if (tail == CHAR_CAN && recv[0] == CHAR_DC1) { |
| 57 | + escape = true; |
| 58 | + } else { |
| 59 | + for (int i = 0; i < (len - 1); i++) { |
| 60 | + if (recv[i] == CHAR_CAN && recv[i + 1] == CHAR_DC1) { |
| 61 | + escape = true; |
| 62 | + break; |
| 63 | + } |
| 64 | + } |
| 65 | + } |
| 66 | + |
| 67 | + if (escape) { |
| 68 | + shell_print(sh, "Number of bytes read: %d", sum); |
| 69 | + set_bypass(sh, NULL); |
| 70 | + |
| 71 | + if (!littleendian) { |
| 72 | + while (sum > 4) { |
| 73 | + *data = __bswap_32(*data); |
| 74 | + data++; |
| 75 | + sum = sum - 4; |
| 76 | + } |
| 77 | + if (sum % 4 == 0) { |
| 78 | + *data = __bswap_32(*data); |
| 79 | + } else if (sum % 4 == 2) { |
| 80 | + *data = __bswap_16(*data); |
| 81 | + } else if (sum % 4 == 3) { |
| 82 | + *data = __bswap_24(*data); |
| 83 | + } |
| 84 | + } |
| 85 | + return; |
| 86 | + } |
| 87 | + |
| 88 | + tail = recv[len - 1]; |
| 89 | + |
| 90 | + if (is_ascii(*recv)) { |
| 91 | + chunk[chunk_element] = *recv; |
| 92 | + chunk_element++; |
| 93 | + } |
| 94 | + |
| 95 | + if (chunk_element == 2) { |
| 96 | + byte = (uint8_t)strtoul(chunk, NULL, 16); |
| 97 | + *bytes = byte; |
| 98 | + bytes++; |
| 99 | + sum++; |
| 100 | + chunk_element = 0; |
| 101 | + } |
| 102 | +} |
| 103 | + |
| 104 | +static int cmd_load(const struct shell *sh, size_t argc, char **argv) |
| 105 | +{ |
| 106 | + littleendian = false; |
| 107 | + char *arg; |
| 108 | + |
| 109 | + chunk_element = 0; |
| 110 | + sum = 0; |
| 111 | + |
| 112 | + while (argc >= 2) { |
| 113 | + arg = argv[1] + (!strncmp(argv[1], "--", 2) && argv[1][2]); |
| 114 | + if (!strncmp(arg, "-e", 2)) { |
| 115 | + littleendian = true; |
| 116 | + } else if (!strcmp(arg, "--")) { |
| 117 | + argv++; |
| 118 | + argc--; |
| 119 | + break; |
| 120 | + } else if (arg[0] == '-' && arg[1]) { |
| 121 | + shell_print(sh, "Unknown option \"%s\"", arg); |
| 122 | + } else { |
| 123 | + break; |
| 124 | + } |
| 125 | + argv++; |
| 126 | + argc--; |
| 127 | + } |
| 128 | + |
| 129 | + bytes = (unsigned char *)strtol(argv[1], NULL, 0); |
| 130 | + data = (uint32_t *)strtol(argv[1], NULL, 0); |
| 131 | + |
| 132 | + set_bypass(sh, bypass_cb); |
| 133 | + return 0; |
| 134 | +} |
10 | 135 |
|
11 | 136 | static int memory_read(const struct shell *sh, mem_addr_t addr, uint8_t width) |
12 | 137 | { |
@@ -36,8 +161,7 @@ static int memory_read(const struct shell *sh, mem_addr_t addr, uint8_t width) |
36 | 161 | return err; |
37 | 162 | } |
38 | 163 |
|
39 | | -static int memory_write(const struct shell *sh, mem_addr_t addr, |
40 | | - uint8_t width, uint64_t value) |
| 164 | +static int memory_write(const struct shell *sh, mem_addr_t addr, uint8_t width, uint64_t value) |
41 | 165 | { |
42 | 166 | int err = 0; |
43 | 167 |
|
@@ -104,5 +228,16 @@ static int cmd_devmem(const struct shell *sh, size_t argc, char **argv) |
104 | 228 | return memory_write(sh, addr, width, value); |
105 | 229 | } |
106 | 230 |
|
107 | | -SHELL_CMD_REGISTER(devmem, NULL, "Read/write physical memory\"" |
108 | | - "devmem address [width [value]]", cmd_devmem); |
| 231 | +SHELL_STATIC_SUBCMD_SET_CREATE(sub_devmem, |
| 232 | + SHELL_CMD_ARG(load, NULL, |
| 233 | + "Usage:\n" |
| 234 | + "devmem load [options] [address]\n" |
| 235 | + "Options:\n" |
| 236 | + "-e\tlittle-endian parse", |
| 237 | + cmd_load, 2, 1), |
| 238 | + SHELL_SUBCMD_SET_END); |
| 239 | + |
| 240 | +SHELL_CMD_REGISTER(devmem, &sub_devmem, |
| 241 | + "Read/write physical memory\"" |
| 242 | + "devmem address [width [value]]", |
| 243 | + cmd_devmem); |
0 commit comments