From b78ab0c6e8e83712cbdc6bf8b6340fa41c00028a Mon Sep 17 00:00:00 2001 From: zhengyu9 Date: Fri, 23 Aug 2024 16:34:00 +0800 Subject: [PATCH] fsutils/flashtool: add flashtool command support Introducing flashtool command with following capabilities: - Flash geometry information display - Bad blocks checking - Page contents read/write - Block erase - Full flash erase Signed-off-by: zhengyu9 --- fsutils/flashtool/CMakeLists.txt | 24 ++ fsutils/flashtool/Kconfig | 29 +++ fsutils/flashtool/Make.defs | 24 ++ fsutils/flashtool/Makefile | 33 +++ fsutils/flashtool/flashtool_main.c | 373 +++++++++++++++++++++++++++++ 5 files changed, 483 insertions(+) create mode 100644 fsutils/flashtool/CMakeLists.txt create mode 100644 fsutils/flashtool/Kconfig create mode 100644 fsutils/flashtool/Make.defs create mode 100644 fsutils/flashtool/Makefile create mode 100644 fsutils/flashtool/flashtool_main.c diff --git a/fsutils/flashtool/CMakeLists.txt b/fsutils/flashtool/CMakeLists.txt new file mode 100644 index 000000000..338c1a394 --- /dev/null +++ b/fsutils/flashtool/CMakeLists.txt @@ -0,0 +1,24 @@ +# ############################################################################## +# apps/fsutils/flashtool/CMakeLists.txt +# +# Licensed to the Apache Software Foundation (ASF) under one or more contributor +# license agreements. See the NOTICE file distributed with this work for +# additional information regarding copyright ownership. The ASF licenses this +# file to you under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +# +# ############################################################################## + +if(CONFIG_FSUTILS_FLASHTOOL) + nuttx_add_application(MODULE ${CONFIG_FSUTILS_FLASHTOOL} NAME flashtool SRCS + flashtool_main.c) +endif() diff --git a/fsutils/flashtool/Kconfig b/fsutils/flashtool/Kconfig new file mode 100644 index 000000000..07f89671a --- /dev/null +++ b/fsutils/flashtool/Kconfig @@ -0,0 +1,29 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +config FSUTILS_FLASHTOOL + tristate "FLASH Tool Command" + default n + depends on MTD + depends on BCH + ---help--- + Enable support for the FLASH tool. + +if FSUTILS_FLASHTOOL + +config FSUTILS_FLASHTOOL_STACKSIZE + int "flashtool stack size" + default DEFAULT_TASK_STACKSIZE + ---help--- + This is the stack size that will be used when starting the flashtool. + +config FSUTILS_FLASHTOOL_PRIORITY + int "flashtool priority" + default 100 + ---help--- + This is the task priority that will be used when starting the flashtool. + +endif + diff --git a/fsutils/flashtool/Make.defs b/fsutils/flashtool/Make.defs new file mode 100644 index 000000000..55f2c72c9 --- /dev/null +++ b/fsutils/flashtool/Make.defs @@ -0,0 +1,24 @@ +############################################################################ +# apps/fsutils/flashtool/Make.defs +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +ifneq ($(CONFIG_FSUTILS_FLASHTOOL),) +CONFIGURED_APPS += $(APPDIR)/fsutils/flashtool +endif + diff --git a/fsutils/flashtool/Makefile b/fsutils/flashtool/Makefile new file mode 100644 index 000000000..deac9500a --- /dev/null +++ b/fsutils/flashtool/Makefile @@ -0,0 +1,33 @@ +############################################################################ +# apps/fsutils/flashtool/Makefile +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +include $(APPDIR)/Make.defs + +# flashtool Application + +PROGNAME = flashtool +PRIORITY = SCHED_PRIORITY_DEFAULT +STACKSIZE = $(CONFIG_DEFAULT_TASK_STACKSIZE) +MODULE = $(CONFIG_FSUTILS_FLASHTOOL) + +MAINSRC = flashtool_main.c + +include $(APPDIR)/Application.mk + diff --git a/fsutils/flashtool/flashtool_main.c b/fsutils/flashtool/flashtool_main.c new file mode 100644 index 000000000..8e4f288f3 --- /dev/null +++ b/fsutils/flashtool/flashtool_main.c @@ -0,0 +1,373 @@ +/**************************************************************************** + * apps/fsutils/flashtool/flashtool_main.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +enum opr_list +{ + HELP, DEVICE_INFO, READ_PAGE, WRITE_PAGE, ERASE_BLOCK, ERASE_ALL, + CHECK_BAD_BLOCK +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void display_help(void) +{ + printf("Usage : flashtool [OPTION [ARG]] device_name ...\n"); + printf("-h show this help statement\n"); + printf("-i display device geometry information\n"); + printf("-r read the specified pages\n"); + printf("-w write the specified pages\n"); + printf("-e erase the specified blocks\n"); + printf("-n number of pages or blocks\n"); + printf("-f file name for read or write\n"); + printf("-b check whether is bad\n"); + printf("-c erase all of the flash\n"); + printf("-d device name\n"); +} + +static void display_device_info(FAR const struct mtd_geometry_s *geo) +{ + printf("Size of one read/write page: %lu\n", geo->blocksize); + printf("Size of one erase block: %lu\n", geo->erasesize); + printf("Number of erase blocks: %lu\n", geo->neraseblocks); +} + +static int read_page(int fd, FAR const struct mtd_geometry_s *geo, + off_t start_page, size_t npages) +{ + FAR unsigned char *buf; + ssize_t ret = OK; + off_t seek; + size_t i; + + buf = malloc(geo->blocksize); + if (!buf) + { + printf("ERROR: read_page cannot allocate memory %d\n", geo->blocksize); + return ERROR; + } + + seek = geo->blocksize * start_page; + if (lseek(fd, seek, SEEK_SET) != seek) + { + printf("ERROR: Cannot seek mtd to offset %lld: %d", seek, errno); + goto oops; + } + + printf("Flash pages contents:\n"); + for (i = 0; i < npages; i++) + { + ret = read(fd, buf, geo->blocksize); + if (ret < 0) + { + printf("ERROR: Read error: %d!\n", errno); + goto oops; + } + + printf("Flash page %lld:\n", start_page + i); + lib_dumpbuffer(NULL, buf, ret); + } + +oops: + free(buf); + return ret; +} + +/* Write npages data from img to flash + * If size of img is less than npags, only write img size + */ + +static int write_page(int fd, FAR const struct mtd_geometry_s *geo, + off_t start_page, size_t npages, FAR const char *img) +{ + FAR unsigned char *buf; + off_t imglen; + off_t seek; + off_t i; + int fd_src; + int ret = OK; + + if (img == NULL) + { + printf("ERROR: Need source file path!\n"); + return ERROR; + } + + printf("Write data from %s...\n", img); + seek = geo->blocksize * start_page; + if (lseek(fd, seek, SEEK_SET) != seek) + { + printf("ERROR: cannot seek mtd to offset %lld: %d", seek, errno); + return ERROR; + } + + fd_src = open(img, O_RDONLY); + if (fd_src < 0) + { + printf("ERROR: Open file %s failed: %d\n", img, errno); + return ERROR; + } + + imglen = lseek(fd_src, 0, SEEK_END); + if (lseek(fd_src, 0, SEEK_SET) != 0) + { + close(fd_src); + return ERROR; + } + + /* Malloc a size of page for buf */ + + buf = malloc(geo->blocksize); + if (!buf) + { + printf("ERROR: write_page cannot allocate memory %d\n", + geo->blocksize); + close(fd_src); + return ERROR; + } + + for (i = start_page; i < start_page + npages; i++) + { + ret = read(fd_src, buf, + (imglen < geo->blocksize) ? imglen : geo->blocksize); + if (ret < 0) + { + printf("ERROR: read source file error: %d!\n", errno); + goto oops; + } + + ret = write(fd, buf, geo->blocksize); + if (ret < 0) + { + printf("ERROR: write error: %d!\n", errno); + goto oops; + } + + imglen -= geo->blocksize; + if (imglen <= 0) + { + break; + } + } + +oops: + close(fd_src); + free(buf); + return ret; +} + +static int erase_block(int fd, off_t start_block, + size_t nblocks) +{ + struct mtd_erase_s erase; + int ret; + + printf("Erase block from %lld to %lld!\n", start_block, + start_block + nblocks -1); + erase.startblock = start_block; + erase.nblocks = nblocks; + ret = ioctl(fd, MTDIOC_ERASESECTORS, &erase); + if (ret < 0) + { + printf("ERROR: Erase failed: %d!\n", errno); + } + + return ret; +} + +static int erase_all(int fd) +{ + if (ioctl(fd, MTDIOC_BULKERASE, 0) < 0) + { + printf("ERROR: MTD ioctl(MTDIOC_BULKERASE) failed: %d\n", errno); + return ERROR; + } + + return OK; +} + +static int check_bad_block(int fd, FAR const struct mtd_geometry_s *geo) +{ + struct mtd_bad_block_s bad_block; + int flag = 0; + int ret; + int i; + + printf("Check bad blocks in flash......\n"); + for (i = 0; i < geo->neraseblocks; i++) + { + bad_block.block_num = i; + ret = ioctl(fd, MTDIOC_ISBAD, &bad_block); + if (ret != OK) + { + printf("ERROR: MTDIOC_ISBAD failed: %d!\n", errno); + return ERROR; + } + else + { + if (bad_block.bad_flag) + { + printf("Block %d is bad!\n", i); + flag = 1; + } + } + } + + if (flag == 0) + { + printf("No bad blocks!\n"); + } + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int main(int argc, FAR char *argv[]) +{ + FAR char *mtddev = NULL; + FAR char *img = NULL; + struct mtd_geometry_s geo; + enum opr_list opr = HELP; + off_t npages = 1; + off_t start; + int option; + int mode = O_RDONLY; + int fd; + int ret; + + while ((option = getopt(argc, argv, ":hir:w:e:n:f:bcd:")) != -1) + { + switch (option) + { + case 'h': + display_help(); + exit(0); + case 'i': + opr = DEVICE_INFO; + break; + case 'r': + opr = READ_PAGE; + start = strtoul(optarg, NULL, 0); + break; + case 'w': + opr = WRITE_PAGE; + mode = O_RDWR; + start = strtoul(optarg, NULL, 0); + break; + case 'e': + opr = ERASE_BLOCK; + start = strtoul(optarg, NULL, 0); + break; + case 'n': + npages = strtoul(optarg, NULL, 0); + break; + case 'f': + img = optarg; + break; + case 'b': + opr = CHECK_BAD_BLOCK; + break; + case 'c': + opr = ERASE_ALL; + break; + case 'd': + mtddev = optarg; + break; + case ':': + printf("Error: Missing required argument\n"); + exit(1); + case '?': + printf("Error: Unrecognized option\n"); + exit(1); + } + } + + if (mtddev == NULL) + { + printf("Error: Device name is required!\n"); + return -1; + } + + fd = open(mtddev, mode, 0777); + if (fd < 0) + { + printf("ERROR: Failed to open '%s': %d\n", mtddev, errno); + return -1; + } + + ret = ioctl(fd, MTDIOC_GEOMETRY, &geo); + if (ret < 0) + { + printf("ERROR: Ioctl MTDIOC_GEOMETRY failed: %d\n", errno); + goto oops; + } + + switch (opr) + { + case DEVICE_INFO: + display_device_info(&geo); + break; + case READ_PAGE: + ret = read_page(fd, &geo, start, npages); + break; + case WRITE_PAGE: + ret = write_page(fd, &geo, start, npages, img); + break; + case ERASE_BLOCK: + ret = erase_block(fd, start, npages); + break; + case ERASE_ALL: + ret = erase_all(fd); + break; + case CHECK_BAD_BLOCK: + ret = check_bad_block(fd, &geo); + break; + default: + } + +oops: + close(fd); + return ret; +}