shell: add devmem load command
This commit adds a devmem load command for shell that allows users to easily load arbitrary data into the device memory. Signed-off-by: Mateusz Sierszulski <msierszulski@internships.antmicro.com> Signed-off-by: Tomasz Gorochowik <tgorochowik@antmicro.com>
This commit is contained in:
parent
374aab1ea3
commit
9d62f8d8ac
6 changed files with 217 additions and 5 deletions
8
samples/subsys/shell/devmem_load/CMakeLists.txt
Normal file
8
samples/subsys/shell/devmem_load/CMakeLists.txt
Normal file
|
@ -0,0 +1,8 @@
|
|||
# Copyright (c) 2021 Antmicro <www.antmicro.com>
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
cmake_minimum_required(VERSION 3.13.1)
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
project(devmem_load)
|
||||
|
||||
target_sources(app PRIVATE src/main.c)
|
53
samples/subsys/shell/devmem_load/README.md
Normal file
53
samples/subsys/shell/devmem_load/README.md
Normal file
|
@ -0,0 +1,53 @@
|
|||
# Zephyr devmem load command
|
||||
This module add a `devmem load` command that allows data to be loaded into device memory.
|
||||
The `devmem load` command is supported by every transport the shell can run on.
|
||||
|
||||
After using a command in the Zephyr shell, the device reads all transferred data and writes to an address in the memory.
|
||||
The transfer ends when the user presses `ctrl-x + ctrl-q`.
|
||||
|
||||
## Usage
|
||||
Note: when using the devmem load command over UART it is recommended to use interrupts whenever possible.
|
||||
If this is not possible, reduce the baud rate to 9600.
|
||||
|
||||
If you use poll you should also use `prj_poll.conf` instead of `prj.conf`.
|
||||
## Building
|
||||
|
||||
The sample can be built for several platforms, the following commands build and run the application with a shell for the FRDM-K64F board.
|
||||
```bash
|
||||
west build -b frdm_k64f samples/subsys/shell/devmem_load
|
||||
west flash
|
||||
```
|
||||
|
||||
Building for boards without UART interrupt support:
|
||||
```bash
|
||||
west build -b quick_feather -- -DOVERLAY_CONFIG=prj_poll.conf samples/subsys/shell/devmem_load
|
||||
west flash
|
||||
```
|
||||
## Running
|
||||
After connecting to the UART console you should see the following output:
|
||||
```bash
|
||||
uart:~$
|
||||
```
|
||||
The `devmem load` command can now be used (`devmem load [option] [address]`):
|
||||
```bash
|
||||
uart:~$ devmem load 0x20020000
|
||||
Loading...
|
||||
press ctrl-x ctrl-q to escape
|
||||
```
|
||||
|
||||
Now, the `devmem load` is waiting for data.
|
||||
You can either type it directly from the console or send it from the host PC (replace `ttyX` with the appropriate one for your UART console):
|
||||
```bash
|
||||
xxd -p data > /dev/ttyX
|
||||
```
|
||||
(It is important to use plain-style hex dump)
|
||||
Once the data is transferred, use `ctrl-x + ctrl-q` to quit the loader.
|
||||
It will print the number of the bytes read and return to the shell:
|
||||
```bash
|
||||
Number of bytes read: 3442
|
||||
uart:~$
|
||||
```
|
||||
|
||||
## Options
|
||||
Currently, the `devmem load` command supports the following argument:
|
||||
* `-e` little endian parse e.g. `0xDEADBEFF -> 0xFFBEADDE`
|
2
samples/subsys/shell/devmem_load/prj.conf
Normal file
2
samples/subsys/shell/devmem_load/prj.conf
Normal file
|
@ -0,0 +1,2 @@
|
|||
CONFIG_BOOT_BANNER=n
|
||||
CONFIG_SHELL=y
|
4
samples/subsys/shell/devmem_load/prj_poll.conf
Normal file
4
samples/subsys/shell/devmem_load/prj_poll.conf
Normal file
|
@ -0,0 +1,4 @@
|
|||
CONFIG_SHELL=y
|
||||
CONFIG_SHELL_BACKEND_SERIAL_INTERRUPT_DRIVEN=n
|
||||
CONFIG_SHELL_BACKEND_SERIAL_RX_POLL_PERIOD=1
|
||||
CONFIG_BOOT_BANNER=n
|
10
samples/subsys/shell/devmem_load/src/main.c
Normal file
10
samples/subsys/shell/devmem_load/src/main.c
Normal file
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Antmicro <www.antmicro.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
void main(void)
|
||||
{
|
||||
|
||||
};
|
|
@ -1,12 +1,137 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Intel Corporation
|
||||
* Copyright (c) 2021 Antmicro <www.antmicro.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <device.h>
|
||||
#include <shell/shell.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/byteorder.h>
|
||||
|
||||
static inline bool is_ascii(uint8_t data)
|
||||
{
|
||||
return (data >= 0x30 && data <= 0x39) || (data >= 0x61 && data <= 0x66) ||
|
||||
(data >= 0x41 && data <= 0x46);
|
||||
}
|
||||
|
||||
static unsigned char *bytes;
|
||||
static uint32_t *data;
|
||||
static int sum;
|
||||
static int chunk_element;
|
||||
static char chunk[2];
|
||||
static bool littleendian;
|
||||
|
||||
#define CHAR_CAN 0x18
|
||||
#define CHAR_DC1 0x11
|
||||
|
||||
static int set_bypass(const struct shell *sh, shell_bypass_cb_t bypass)
|
||||
{
|
||||
static bool in_use;
|
||||
|
||||
if (bypass && in_use) {
|
||||
shell_error(sh, "devmem load supports setting bypass on a single instance.");
|
||||
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
in_use = !in_use;
|
||||
if (in_use) {
|
||||
shell_print(sh, "Loading...\npress ctrl-x ctrl-q to escape");
|
||||
in_use = true;
|
||||
}
|
||||
|
||||
shell_set_bypass(sh, bypass);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bypass_cb(const struct shell *sh, uint8_t *recv, size_t len)
|
||||
{
|
||||
bool escape = false;
|
||||
static uint8_t tail;
|
||||
uint8_t byte;
|
||||
|
||||
if (tail == CHAR_CAN && recv[0] == CHAR_DC1) {
|
||||
escape = true;
|
||||
} else {
|
||||
for (int i = 0; i < (len - 1); i++) {
|
||||
if (recv[i] == CHAR_CAN && recv[i + 1] == CHAR_DC1) {
|
||||
escape = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (escape) {
|
||||
shell_print(sh, "Number of bytes read: %d", sum);
|
||||
set_bypass(sh, NULL);
|
||||
|
||||
if (!littleendian) {
|
||||
while (sum > 4) {
|
||||
*data = __bswap_32(*data);
|
||||
data++;
|
||||
sum = sum - 4;
|
||||
}
|
||||
if (sum % 4 == 0) {
|
||||
*data = __bswap_32(*data);
|
||||
} else if (sum % 4 == 2) {
|
||||
*data = __bswap_16(*data);
|
||||
} else if (sum % 4 == 3) {
|
||||
*data = __bswap_24(*data);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
tail = recv[len - 1];
|
||||
|
||||
if (is_ascii(*recv)) {
|
||||
chunk[chunk_element] = *recv;
|
||||
chunk_element++;
|
||||
}
|
||||
|
||||
if (chunk_element == 2) {
|
||||
byte = (uint8_t)strtoul(chunk, NULL, 16);
|
||||
*bytes = byte;
|
||||
bytes++;
|
||||
sum++;
|
||||
chunk_element = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int cmd_load(const struct shell *sh, size_t argc, char **argv)
|
||||
{
|
||||
littleendian = false;
|
||||
char *arg;
|
||||
|
||||
chunk_element = 0;
|
||||
sum = 0;
|
||||
|
||||
while (argc >= 2) {
|
||||
arg = argv[1] + (!strncmp(argv[1], "--", 2) && argv[1][2]);
|
||||
if (!strncmp(arg, "-e", 2)) {
|
||||
littleendian = true;
|
||||
} else if (!strcmp(arg, "--")) {
|
||||
argv++;
|
||||
argc--;
|
||||
break;
|
||||
} else if (arg[0] == '-' && arg[1]) {
|
||||
shell_print(sh, "Unknown option \"%s\"", arg);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
argv++;
|
||||
argc--;
|
||||
}
|
||||
|
||||
bytes = (unsigned char *)strtol(argv[1], NULL, 0);
|
||||
data = (uint32_t *)strtol(argv[1], NULL, 0);
|
||||
|
||||
set_bypass(sh, bypass_cb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int memory_read(const struct shell *sh, mem_addr_t addr, uint8_t width)
|
||||
{
|
||||
|
@ -36,8 +161,7 @@ static int memory_read(const struct shell *sh, mem_addr_t addr, uint8_t width)
|
|||
return err;
|
||||
}
|
||||
|
||||
static int memory_write(const struct shell *sh, mem_addr_t addr,
|
||||
uint8_t width, uint64_t value)
|
||||
static int memory_write(const struct shell *sh, mem_addr_t addr, uint8_t width, uint64_t value)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
|
@ -104,5 +228,16 @@ static int cmd_devmem(const struct shell *sh, size_t argc, char **argv)
|
|||
return memory_write(sh, addr, width, value);
|
||||
}
|
||||
|
||||
SHELL_CMD_REGISTER(devmem, NULL, "Read/write physical memory\""
|
||||
"devmem address [width [value]]", cmd_devmem);
|
||||
SHELL_STATIC_SUBCMD_SET_CREATE(sub_devmem,
|
||||
SHELL_CMD_ARG(load, NULL,
|
||||
"Usage:\n"
|
||||
"devmem load [options] [address]\n"
|
||||
"Options:\n"
|
||||
"-e\tlittle-endian parse",
|
||||
cmd_load, 2, 1),
|
||||
SHELL_SUBCMD_SET_END);
|
||||
|
||||
SHELL_CMD_REGISTER(devmem, &sub_devmem,
|
||||
"Read/write physical memory\""
|
||||
"devmem address [width [value]]",
|
||||
cmd_devmem);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue