Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:19

0001 /*
0002  * Copyright (C) 2023 Aaron Nyholm
0003  *
0004  * Redistribution and use in source and binary forms, with or without
0005  * modification, are permitted provided that the following conditions
0006  * are met:
0007  * 1. Redistributions of source code must retain the above copyright
0008  *    notice, this list of conditions and the following disclaimer.
0009  * 2. Redistributions in binary form must reproduce the above copyright
0010  *    notice, this list of conditions and the following disclaimer in the
0011  *    documentation and/or other materials provided with the distribution.
0012  *
0013  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0014  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0015  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0016  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0017  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0018  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0019  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0020  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0021  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0022  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0023  * POSSIBILITY OF SUCH DAMAGE.
0024  */
0025 
0026 #include <fcntl.h>
0027 #include <stdio.h>
0028 #include <stdlib.h>
0029 
0030 #include <errno.h>
0031 #include <rtems/shell.h>
0032 
0033 #include <dev/flash/flashdev.h>
0034 
0035 static int flashdev_shell_read(char *dev_path, int argc, char *argv[]);
0036 static int flashdev_shell_write(char *dev_path, int argc, char *argv[]);
0037 static int flashdev_shell_erase(char *dev_path, int argc, char *argv[]);
0038 static int flashdev_shell_type(char *dev_path);
0039 static int flashdev_shell_jedecid(char *dev_path);
0040 static int flashdev_shell_page_off(char *dev_path, int argc, char *argv[]);
0041 static int flashdev_shell_page_idx(char *dev_path, int argc, char *argv[]);
0042 static int flashdev_shell_pg_count(char *dev_path);
0043 static int flashdev_shell_wb_size(char *dev_path);
0044 static int flashdev_shell_sector_off(char *dev_path, int argc, char *argv[]);
0045 static int flashdev_shell_sector_count(char *dev_path);
0046 
0047 static int flashdev_shell_ioctl_value(
0048   char *dev_path,
0049   int ioctl_call,
0050   void *ret
0051 );
0052 
0053 static int flashdev_shell_page(
0054   char *dev_path,
0055   int argc,
0056   char *argv[],
0057   int ioctl_call
0058 );
0059 
0060 static const char rtems_flashdev_shell_usage [] =
0061   "simple flash read / write / erase\n"
0062   "\n"
0063   "flashdev <FLASH_DEV_PATH> [OPTION]\n"
0064   "   -r <address> <bytes>  Read at address for bytes\n"
0065   "   -w <address> <file>   Write file to address\n"
0066   "   -e <address> <bytes>  Erase at address for bytes\n"
0067   "   -t                    Print the flash type\n"
0068   "   -d                    Print the JEDEC ID of flash device\n"
0069   "   -o <address>          Print the page information of page at address\n"
0070   "   -i <index>            Print the page information of page at index\n"
0071   "   -p                    Print the number of pages\n"
0072   "   -b                    Print the write block size\n"
0073   "   -s <address>          Print the sector information of erase sector"
0074     " at address\n"
0075   "   -c                    Print the number of erase sectors\n"
0076   "   -h                    Print this help\n";
0077 
0078 
0079 static int rtems_flashdev_shell_main( int argc, char *argv[] ) {
0080 
0081   char *dev_path = NULL;
0082   int i;
0083 
0084   for (i = 1; i < argc; ++i) {
0085     if (argv[i][0] == '-') {
0086       /*
0087        * Check that a path to flashdev has been provided before running
0088        * command.
0089        */
0090       if (dev_path == NULL) {
0091         printf("Please input FLASH_DEV_PATH before instruction\n");
0092         return 1;
0093       }
0094       /* Run command */
0095       switch (argv[i][1]) {
0096       case ('r'):
0097         /* Read */
0098         return flashdev_shell_read(dev_path, argc, &argv[i]);
0099       case ('w'):
0100         /* Write */
0101         return flashdev_shell_write(dev_path, argc, &argv[i]);
0102       case ('e'):
0103         /* Erase */
0104         return flashdev_shell_erase(dev_path, argc, &argv[i]);
0105       case ('t'):
0106         /* Flash Type */
0107         return flashdev_shell_type(dev_path);
0108       case ('d'):
0109         /* JEDEC Id */
0110         return flashdev_shell_jedecid(dev_path);
0111       case ('o'):
0112         /* Page info by offset */
0113         return flashdev_shell_page_off(dev_path, argc, &argv[i]);
0114       case ('i'):
0115         /* Page info by index */
0116         return flashdev_shell_page_idx(dev_path, argc, &argv[i]);
0117       case ('p'):
0118         /* Page count */
0119         return flashdev_shell_pg_count(dev_path);
0120       case ('b'):
0121         /* Write block size */
0122         return flashdev_shell_wb_size(dev_path);
0123       case ('s'):
0124         /* Sector info by offset */
0125         return flashdev_shell_sector_off(dev_path, argc, &argv[i]);
0126       case ('c'):
0127         /* Sector count */
0128         return flashdev_shell_sector_count(dev_path);
0129       case ('h'):
0130       default:
0131         /* Help */
0132         printf(rtems_flashdev_shell_usage);
0133         break;
0134       }
0135     } else if (dev_path == NULL) {
0136       dev_path = argv[i];
0137     } else {
0138       printf("Invalid argument: %s\n", argv[i]);
0139       return 1;
0140     }
0141   }
0142 
0143   if (argc == 1) {
0144     printf(rtems_flashdev_shell_usage);
0145   }
0146 
0147   return 0;
0148 }
0149 
0150 int flashdev_shell_read(
0151   char *dev_path,
0152   int argc,
0153   char *argv[]
0154 )
0155 {
0156   uint32_t address;
0157   uint32_t bytes;
0158   int fd;
0159   int status;
0160   void *buffer;
0161 
0162   /* Check arguments */
0163   if (argc < 5) {
0164     printf("Missing argument\n");
0165     return -1;
0166   }
0167 
0168   /* Get arguments */
0169   errno = 0;
0170   address = (uint32_t) strtoul(argv[1], NULL, 0);
0171   if (errno != 0) {
0172     printf("Could not read address\n");
0173   }
0174   errno = 0;
0175   bytes = (uint32_t) strtoul(argv[2], NULL, 0);
0176   if (errno != 0) {
0177     printf("Could not read address\n");
0178   }
0179 
0180   /* Open flash device */
0181   fd = open(dev_path, O_RDONLY);
0182   if (fd == -1) {
0183     printf("Couldn't open %s\n", dev_path);
0184     return -1;
0185   }
0186 
0187   /* Move to address */
0188   status = lseek(fd, address, SEEK_SET);
0189   if (status == -1) {
0190     printf("Reading failed\n");
0191     close(fd);
0192     return -1;
0193   }
0194 
0195   /* Create a buffer to read into */
0196   buffer = calloc((bytes + bytes%4), 1);
0197   if (buffer == NULL) {
0198     printf("Failed to allocate read buffer\n");
0199     close(fd);
0200     return -1;
0201   }
0202 
0203   /* Read into buffer */
0204   status = read(fd, buffer, bytes);
0205   if (status == -1) {
0206     printf("Reading failed\n");
0207     free(buffer);
0208     close(fd);
0209     return -1;
0210   }
0211 
0212   /* Print buffer out in 32bit blocks */
0213   printf("Reading %s at 0x%08x for 0x%x bytes\n", dev_path, address, bytes);
0214   for (int i = 0; i < (bytes/4); i++) {
0215     printf("%08x ", ((uint32_t*)buffer)[i]);
0216     if ((i+1)%4 == 0) {
0217       printf("\n");
0218     }
0219   }
0220   printf("\n");
0221 
0222   /* Clean up */
0223   free(buffer);
0224   close(fd);
0225   return 0;
0226 }
0227 
0228 int flashdev_shell_write(
0229   char *dev_path,
0230   int argc,
0231   char *argv[]
0232 )
0233 {
0234   uint32_t address;
0235   int flash;
0236   int file;
0237   int status;
0238   int read_len;
0239   off_t length;
0240   void *buffer;
0241   uint32_t offset;
0242   char *file_path;
0243 
0244   /* Check arguments */
0245   if (argc < 5) {
0246     printf("Missing argument\n");
0247     return -1;
0248   }
0249 
0250   /* Get arguments */
0251   errno = 0;
0252   address = (uint32_t) strtoul(argv[1], NULL, 0);
0253   if (errno != 0) {
0254     printf("Could not read address\n");
0255   }
0256   errno = 0;
0257   file_path = argv[2];
0258 
0259   /* Open flash device and move to write offset */
0260   flash = open(dev_path, O_WRONLY);
0261   if (flash == -1) {
0262     printf("Couldn't open %s\n", dev_path);
0263     return -1;
0264   }
0265   status = lseek(flash, address, SEEK_SET);
0266   if (status == -1) {
0267     printf("Reading failed\n");
0268     close(flash);
0269     return -1;
0270   }
0271 
0272   /* Open file and get file length */
0273   file = open(file_path, O_RDONLY);
0274   if (file == -1) {
0275     printf("Couldn't open %s\n", file_path);
0276     close(flash);
0277     return -1;
0278   }
0279 
0280   length = lseek(file, 0, SEEK_END);
0281   if (length == -1) {
0282     close(flash);
0283     close(file);
0284     printf("Couldn't find length of file\n");
0285     return -1;
0286   }
0287 
0288   if (lseek(file, 0, SEEK_SET) == -1) {
0289     close(flash);
0290     close(file);
0291     printf("Couldn't find length of file\n");
0292     return -1;
0293   }
0294 
0295   printf(
0296     "Writing %s to %s at 0x%08x for 0x%jx bytes\n",
0297     file_path,
0298     dev_path,
0299     address,
0300     length
0301   );
0302 
0303   /* Create buffer */
0304   buffer = calloc(1, 0x1000);
0305 
0306   /* Write file to flash device in 0x1000 byte chunks */
0307   offset = 0;
0308   while (offset != length) {
0309 
0310     read_len = length - offset;
0311     if (read_len > 0x1000) {
0312       read_len = 0x1000;
0313     }
0314 
0315     status = read(file, buffer, read_len);
0316     if (status == -1) {
0317       free(buffer);
0318       close(flash);
0319       close(file);
0320       printf("Can't read %s\n", file_path);
0321       return -1;
0322     }
0323 
0324     status = write(flash, buffer, read_len);
0325     if (status == -1) {
0326       free(buffer);
0327       close(flash);
0328       close(file);
0329       printf("Can't write %s\n", dev_path);
0330       return -1;
0331     }
0332 
0333     offset = offset + read_len;
0334   }
0335 
0336   /* Clean up */
0337   close(flash);
0338   close(file);
0339   free(buffer);
0340   return 0;
0341 }
0342 
0343 int flashdev_shell_erase(
0344   char *dev_path,
0345   int argc,
0346   char *argv[]
0347 )
0348 {
0349   uint32_t address;
0350   uint32_t bytes;
0351   int fd;
0352   int status;
0353   rtems_flashdev_region args;
0354 
0355   /* Check arguments */
0356   if (argc < 5) {
0357     printf("Missing argument\n");
0358     return -1;
0359   }
0360 
0361   /* Get arguments */
0362   errno = 0;
0363   address = (uint32_t) strtoul(argv[1], NULL, 0);
0364   if (errno != 0) {
0365     printf("Could not read address\n");
0366   }
0367   errno = 0;
0368   bytes = (uint32_t) strtoul(argv[2], NULL, 0);
0369   if (errno != 0) {
0370     printf("Could not read address\n");
0371   }
0372 
0373   /* Open flash device */
0374   fd = open(dev_path, O_RDWR);
0375   if (fd == -1) {
0376     printf("Couldn't open %s\n", dev_path);
0377     return -1;
0378   }
0379 
0380   printf("Erasing at 0x%08x for 0x%x bytes\n", address, bytes);
0381 
0382   /* Erase flash */
0383   args.offset = address;
0384   args.size = bytes;
0385 
0386   status = ioctl(fd, RTEMS_FLASHDEV_IOCTL_ERASE, &args);
0387   if (status == -1) {
0388     printf("Erase failed\n");
0389     close(fd);
0390     return -1;
0391   }
0392 
0393   /* Clean up */
0394   close(fd);
0395 
0396   return 0;
0397 }
0398 
0399 int flashdev_shell_type( char *dev_path )
0400 {
0401   int type;
0402   int status;
0403 
0404   /* Get type */
0405   status = flashdev_shell_ioctl_value(
0406     dev_path,
0407     RTEMS_FLASHDEV_IOCTL_TYPE,
0408     &type
0409   );
0410 
0411   if (status) {
0412     printf("Failed to get flash type\n");
0413     return status;
0414   }
0415 
0416   /* Print type */
0417   switch(type) {
0418     case RTEMS_FLASHDEV_NOR:
0419       printf("NOR flash\n");
0420       break;
0421     case RTEMS_FLASHDEV_NAND:
0422       printf("NAND flash\n");
0423       break;
0424     default:
0425       printf("Unknown type\n");
0426   }
0427 
0428   return 0;
0429 }
0430 
0431 int flashdev_shell_jedecid( char *dev_path ) {
0432   uint32_t ret;
0433   int status;
0434 
0435   /* Get JEDEC Id */
0436   status = flashdev_shell_ioctl_value(
0437     dev_path,
0438     RTEMS_FLASHDEV_IOCTL_JEDEC_ID,
0439     &ret
0440   );
0441 
0442   /* Print JEDEC Id */
0443   if (status) {
0444     printf("Failed to get JEDEC Id\n");
0445     return status;
0446   } else {
0447     printf("JEDEC Id: 0x%x\n", ret);
0448   }
0449   return 0;
0450 }
0451 
0452 static int flashdev_shell_page_off(
0453   char *dev_path,
0454   int argc,
0455   char *argv[]
0456 )
0457 {
0458   return flashdev_shell_page(
0459     dev_path,
0460     argc,
0461     argv,
0462     RTEMS_FLASHDEV_IOCTL_PAGEINFO_BY_OFFSET
0463   );
0464 }
0465 
0466 static int flashdev_shell_page_idx(
0467   char *dev_path,
0468   int argc,
0469   char *argv[]
0470 )
0471 {
0472   return flashdev_shell_page(
0473     dev_path,
0474     argc,
0475     argv,
0476     RTEMS_FLASHDEV_IOCTL_PAGEINFO_BY_INDEX
0477   );
0478 }
0479 
0480 static int flashdev_shell_pg_count( char *dev_path )
0481 {
0482   uint32_t ret;
0483   int status;
0484 
0485   /* Get Page Count */
0486   status = flashdev_shell_ioctl_value(
0487     dev_path,
0488     RTEMS_FLASHDEV_IOCTL_PAGE_COUNT,
0489     &ret
0490   );
0491 
0492   /* Print Page Count */
0493   if (status) {
0494     printf("Failed to get page count\n");
0495     return status;
0496   } else {
0497     printf("Page count: 0x%x\n", ret);
0498   }
0499   return 0;
0500 }
0501 
0502 static int flashdev_shell_wb_size( char *dev_path )
0503 {
0504   size_t ret;
0505   int status;
0506 
0507   /* Get Write Block Size */
0508   status = flashdev_shell_ioctl_value(
0509     dev_path,
0510     RTEMS_FLASHDEV_IOCTL_WRITE_BLOCK_SIZE,
0511     &ret
0512   );
0513 
0514   /* Print Write Block Size */
0515   if (status) {
0516     printf("Failed to get write block size\n");
0517     return status;
0518   } else {
0519     printf("Write block size: 0x%zx\n", ret);
0520   }
0521   return 0;
0522 }
0523 
0524 static int flashdev_shell_sector_off(
0525   char *dev_path,
0526   int argc,
0527   char *argv[]
0528 )
0529 {
0530   rtems_flashdev_ioctl_sector_info sec_info;
0531   int fd;
0532   int status;
0533 
0534   /* Check arguments */
0535   if (argc < 4) {
0536     printf("Missing argument\n");
0537     return -1;
0538   }
0539 
0540   /* Get arguments */
0541   errno = 0;
0542   sec_info.location = (off_t) strtoul(argv[1], NULL, 0);
0543   if (errno != 0) {
0544     printf("Could not read address\n");
0545   }
0546 
0547   /* Open flash device */
0548   fd = open(dev_path, O_RDWR);
0549   if (fd == -1) {
0550     printf("Couldn't open %s\n", dev_path);
0551     return -1;
0552   }
0553 
0554   status = ioctl(fd, RTEMS_FLASHDEV_IOCTL_SECTORINFO_BY_OFFSET, &sec_info);
0555   if (status == -1) {
0556     printf("Failed to get sector info\n");
0557     close(fd);
0558     return -1;
0559   }
0560 
0561   printf(
0562     "Sector offset: 0x%jx\nPage length: 0x%zx\n",
0563     sec_info.sector_info.offset,
0564     sec_info.sector_info.size
0565   );
0566 
0567   /* Clean up */
0568   close(fd);
0569   return 0;
0570 }
0571 
0572 static int flashdev_shell_sector_count( char *dev_path )
0573 {
0574   uint32_t ret;
0575   int status;
0576 
0577   /* Get Page Count */
0578   status = flashdev_shell_ioctl_value(
0579     dev_path,
0580     RTEMS_FLASHDEV_IOCTL_SECTOR_COUNT,
0581     &ret
0582   );
0583 
0584   /* Print Page Count */
0585   if (status) {
0586     printf("Failed to get sector count\n");
0587     return status;
0588   } else {
0589     printf("Sector count: 0x%x\n", ret);
0590   }
0591   return 0;
0592 }
0593 
0594 static int flashdev_shell_ioctl_value(
0595   char *dev_path,
0596   int ioctl_call,
0597   void *ret
0598 )
0599 {
0600   int fd;
0601   int status;
0602 
0603   fd = open(dev_path, O_RDONLY);
0604   if (fd == -1) {
0605     printf("Couldn't open %s\n", dev_path);
0606     return -1;
0607   }
0608 
0609   status = ioctl(fd, ioctl_call, ret);
0610   if (status == -1) {
0611     close(fd);
0612     return -1;
0613   }
0614 
0615   close(fd);
0616   return 0;
0617 }
0618 
0619 static int flashdev_shell_page(
0620   char *dev_path,
0621   int argc,
0622   char *argv[],
0623   int ioctl_call
0624 )
0625 {
0626   rtems_flashdev_ioctl_page_info pg_info;
0627   int fd;
0628   int status;
0629 
0630   /* Check arguments */
0631   if (argc < 4) {
0632     printf("Missing argument\n");
0633     return -1;
0634   }
0635 
0636   /* Get arguments */
0637   errno = 0;
0638   pg_info.location = (off_t) strtoul(argv[1], NULL, 0);
0639   if (errno != 0) {
0640     printf("Could not read address\n");
0641   }
0642 
0643   /* Open flash device */
0644   fd = open(dev_path, O_RDWR);
0645   if (fd == -1) {
0646     printf("Couldn't open %s\n", dev_path);
0647     return -1;
0648   }
0649 
0650   status = ioctl(fd, ioctl_call, &pg_info);
0651   if (status == -1) {
0652     printf("Failed to get page info\n");
0653     close(fd);
0654     return -1;
0655   }
0656 
0657   printf(
0658     "Page offset: 0x%jx\nPage length: 0x%zx\n",
0659     pg_info.page_info.offset,
0660     pg_info.page_info.size
0661   );
0662 
0663   /* Clean up */
0664   close(fd);
0665   return 0;
0666 }
0667 
0668 rtems_shell_cmd_t rtems_shell_FLASHDEV_Command = {
0669   .name = "flashdev",
0670   .usage = rtems_flashdev_shell_usage,
0671   .topic = "misc",
0672   .command = rtems_flashdev_shell_main,
0673 };