From: Aaron Nyholm <aaron.nyh...@southerninnovation.com> Closes #4869 --- cpukit/include/rtems/shellconfig.h | 7 + cpukit/libmisc/shell/main_flashdev.c | 352 +++++++++++++++++++++++++++ spec/build/cpukit/objshell.yml | 1 + 3 files changed, 360 insertions(+) create mode 100644 cpukit/libmisc/shell/main_flashdev.c
diff --git a/cpukit/include/rtems/shellconfig.h b/cpukit/include/rtems/shellconfig.h index a013840ee7..489f281400 100644 --- a/cpukit/include/rtems/shellconfig.h +++ b/cpukit/include/rtems/shellconfig.h @@ -98,6 +98,7 @@ extern rtems_shell_cmd_t rtems_shell_MD5_Command; extern rtems_shell_cmd_t rtems_shell_RTC_Command; extern rtems_shell_cmd_t rtems_shell_SPI_Command; +extern rtems_shell_cmd_t rtems_shell_FLASHDEV_Command; extern rtems_shell_cmd_t rtems_shell_I2CDETECT_Command; extern rtems_shell_cmd_t rtems_shell_I2CGET_Command; extern rtems_shell_cmd_t rtems_shell_I2CSET_Command; @@ -556,6 +557,12 @@ extern rtems_shell_alias_t * const rtems_shell_Initial_aliases[]; &rtems_shell_SPI_Command, #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) \ + && !defined(CONFIGURE_SHELL_NO_COMMAND_FLASHDEV)) \ + || defined(CONFIGURE_SHELL_COMMAND_FLASHDEV) + &rtems_shell_FLASHDEV_Command, + #endif + #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) \ && !defined(CONFIGURE_SHELL_NO_COMMAND_I2CDETECT)) \ || defined(CONFIGURE_SHELL_COMMAND_I2CDETECT) diff --git a/cpukit/libmisc/shell/main_flashdev.c b/cpukit/libmisc/shell/main_flashdev.c new file mode 100644 index 0000000000..3c6ca1476c --- /dev/null +++ b/cpukit/libmisc/shell/main_flashdev.c @@ -0,0 +1,352 @@ +/* + * Copyright (C) 2023, 2023 Aaron Nyholm + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> + +#include <errno.h> +#include <rtems/shell.h> + +#include <dev/flash/flashdev.h> + + +int flashdev_shell_read(char *dev_path, uint32_t address, uint32_t bytes); +int flashdev_shell_write(char *dev_path, uint32_t address, char *file_path); +int flashdev_shell_readid(char *dev_path); +int flashdev_shell_type(char *dev_path); +int flashdev_shell_erase(char *dev_path, uint32_t address, uint32_t bytes); + +static const char rtems_flashdev_shell_usage [] = + "simple flash read / write / erase\n" + "\n" + "flashdev <FLASH_DEV_PATH> [-r <address> <bytes>]\n" + " [-w <address> <file>] [-e <address> <bytes>]\n" + " -r <address> <bytes> Read at address for bytes\n" + " -w <address> <file> Write file to address\n" + " -e <address> <bytes> Erase at address for bytes\n" + " -t Print the flash type\n" + " -i Print the READID\n" + " -h Print this help\n"; + + +static int rtems_flashdev_shell_main(int argc, char *argv[]) { + + char *dev_path = NULL; + int i; + uint32_t address; + uint32_t bytes; + char *file_path; + + for (i = 1; i < argc; ++i) { + if (argv[i][0] == '-') { + switch (argv[i][1]) { + case ('r'): + // Read + if (argc < 5) { + printf("Missing argument\n"); + return -1; + } + if (dev_path == NULL) { + printf("Please input FLASH_DEV_PATH before instruction\n"); + return 1; + } + errno = 0; + address = (uint32_t) strtoul(argv[i+1], NULL, 0); + if (errno != 0) { + printf("Could not read address\n"); + } + errno = 0; + bytes = (uint32_t) strtoul(argv[i+2], NULL, 0); + if (errno != 0) { + printf("Could not read address\n"); + } + return flashdev_shell_read(dev_path, address, bytes); + break; + case ('w'): + // Write + if (argc < 5) { + printf("Missing argument\n"); + return -1; + } + if (dev_path == NULL) { + printf("Please input FLASH_DEV_PATH before instruction\n"); + return 1; + } + errno = 0; + address = (uint32_t) strtoul(argv[i+1], NULL, 0); + if (errno != 0) { + printf("Could not read address\n"); + } + errno = 0; + file_path = argv[i+2]; + return flashdev_shell_write(dev_path, address, file_path); + break; + case ('i'): + return flashdev_shell_readid(dev_path); + break; + case ('e'): + // Erase + if (argc < 5) { + printf("Missing argument\n"); + return -1; + } + if (dev_path == NULL) { + printf("Please input FLASH_DEV_PATH before instruction\n"); + return 1; + } + errno = 0; + address = (uint32_t) strtoul(argv[i+1], NULL, 0); + if (errno != 0) { + printf("Could not read address\n"); + } + errno = 0; + bytes = (uint32_t) strtoul(argv[i+2], NULL, 0); + if (errno != 0) { + printf("Could not read address\n"); + } + return flashdev_shell_erase(dev_path, address, bytes); + break; + case ('t'): + return flashdev_shell_type(dev_path); + break; + case ('h'): + default: + // Help + printf(rtems_flashdev_shell_usage); + break; + } + + } else if (dev_path == NULL) { + dev_path = argv[i]; + } else { + printf("Invalid argument: %s\n", argv[i]); + return 1; + } + } + + if (argc == 1) { + printf(rtems_flashdev_shell_usage); + } + + return 0; +} + +int flashdev_shell_read(char *dev_path, uint32_t address, uint32_t bytes) { + int fd = open(dev_path, O_RDONLY); + if (fd == -1) { + printf("Couldn't open %s\n", dev_path); + return -1; + } + + int status = lseek(fd, address, SEEK_SET); + if (status == -1) { + printf("Reading failed\n"); + close(fd); + return -1; + } + + void *buffer = calloc((bytes + bytes%4), 1); + if (buffer == NULL) { + printf("Failed to allocate read buffer\n"); + return -1; + } + + status = read(fd, buffer, bytes); + if (status == -1) { + printf("Reading failed\n"); + free(buffer); + close(fd); + return -1; + } + + uint32_t *IntBuf = (uint32_t*)buffer; + printf("Reading %s at 0x%08x for %d bytes\n", dev_path, address, bytes); + for (int i = 0; i < (bytes/4); i++) { + printf("%08x ", IntBuf[i]); + if ((i+1)%4 == 0) { + printf("\n"); + } + } + + printf("\n"); + free(buffer); + close(fd); + return 0; +} + +int flashdev_shell_write(char *dev_path, uint32_t address, char *file_path) { + int flash = open(dev_path, O_WRONLY); + if (flash == -1) { + printf("Couldn't open %s\n", dev_path); + return -1; + } + + int status = lseek(flash, address, SEEK_SET); + if (status == -1) { + printf("Reading failed\n"); + close(flash); + return -1; + } + + int file = open(file_path, O_RDONLY); + if (file == -1) { + printf("Couldn't open %s\n", file_path); + close(flash); + return -1; + } + + off_t length = lseek(file, 0, SEEK_END); + if (length == -1) { + close(flash); + close(file); + printf("Couldn't find length of file\n"); + return -1; + } + + if (lseek(file, 0, SEEK_SET) == -1) { + close(flash); + close(file); + printf("Couldn't find length of file\n"); + return -1; + } + + void *buffer = calloc(1, 0x1000); + + uint32_t offset = 0; + while (offset != length) { + + int read_len = length - offset; + if (read_len > 0x1000) { + read_len = 0x1000; + } + + status = read(file, buffer, read_len); + if (status == -1) { + free(buffer); + close(flash); + close(file); + printf("Can't read %s\n", file_path); + return -1; + } + + status = write(flash, buffer, read_len); + if (status == -1) { + free(buffer); + close(flash); + close(file); + printf("Can't write %s\n", dev_path); + return -1; + } + + offset = offset + read_len; + } + + return 0; +} + +int flashdev_shell_readid(char *dev_path) { + int fd = open(dev_path, O_RDONLY); + if (fd == -1) { + printf("Couldn't open %s\n", dev_path); + return -1; + } + uint32_t readid; + int status = ioctl(fd, FLASHDEV_IOCTL_READID, &readid); + if (status == -1) { + printf("ReadId failed\n"); + close(fd); + return -1; + } + + printf("ReadId: %06x\n", readid); + + close(fd); + + return 0; + +} + +int flashdev_shell_type(char *dev_path) { + int fd = open(dev_path, O_RDONLY); + if (fd == -1) { + printf("Couldn't open %s\n", dev_path); + return -1; + } + uint32_t type; + int status = ioctl(fd, FLASHDEV_IOCTL_TYPE, &type); + if (status == -1) { + printf("Type failed\n"); + close(fd); + return -1; + } + + printf("The flash is "); + + switch(type) { + case FLASHDEV_TYPE_NOR: + printf("NOR flash\n"); + break; + case FLASHDEV_TYPE_NAND: + printf("NAND flash\n"); + break; + default: + printf("Unknown type\n"); + } + + close(fd); + + return 0; +} + +int flashdev_shell_erase(char *dev_path, uint32_t address, uint32_t bytes) { + int fd = open(dev_path, O_RDONLY); + if (fd == -1) { + printf("Couldn't open %s\n", dev_path); + return -1; + } + + erase_args args; + args.offset = address; + args.count = bytes; + + int status = ioctl(fd, FLASHDEV_IOCTL_ERASE, &args); + if (status == -1) { + printf("Erase failed\n"); + close(fd); + return -1; + } + + close(fd); + + return 0; +} + +rtems_shell_cmd_t rtems_shell_FLASHDEV_Command = { + .name = "flashdev", + .usage = rtems_flashdev_shell_usage, + .topic = "misc", + .command = rtems_flashdev_shell_main, +}; diff --git a/spec/build/cpukit/objshell.yml b/spec/build/cpukit/objshell.yml index 5fd259bee3..b71abb18f9 100644 --- a/spec/build/cpukit/objshell.yml +++ b/spec/build/cpukit/objshell.yml @@ -52,6 +52,7 @@ source: - cpukit/libmisc/shell/main_echo.c - cpukit/libmisc/shell/main_edit.c - cpukit/libmisc/shell/main_exit.c +- cpukit/libmisc/shell/main_flashdev.c - cpukit/libmisc/shell/main_getenv.c - cpukit/libmisc/shell/main_halt.c - cpukit/libmisc/shell/main_help.c -- 2.25.1 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel