summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2013-09-05 23:14:57 +0200
committerAmaury Pouly <amaury.pouly@gmail.com>2013-09-05 23:16:06 +0200
commit3713bc4b7ce68ebedc9d938dbcf38c20c39e049a (patch)
tree1179a2c30435c813fd9b67f96b058e2d56410fd2
parent1ac762aebb142fe96a8f204614d1a2d66a05258d (diff)
downloadrockbox-3713bc4b7ce68ebedc9d938dbcf38c20c39e049a.tar.gz
rockbox-3713bc4b7ce68ebedc9d938dbcf38c20c39e049a.zip
imxtools/scsitools: add option to extract firmware from the device
Change-Id: Ib8cbf2f864a9375575cea0edbba48f740bf8f12e
-rw-r--r--utils/imxtools/scsitools/scsitool.c150
-rw-r--r--utils/imxtools/scsitools/stmp_scsi.h7
2 files changed, 148 insertions, 9 deletions
diff --git a/utils/imxtools/scsitools/scsitool.c b/utils/imxtools/scsitools/scsitool.c
index bb68fd882c..af06b7338c 100644
--- a/utils/imxtools/scsitools/scsitool.c
+++ b/utils/imxtools/scsitools/scsitool.c
@@ -378,6 +378,28 @@ static int stmp_get_serial_number(uint8_t info, void *data, int *len)
378 return do_sense_analysis(ret, sense, sense_size); 378 return do_sense_analysis(ret, sense, sense_size);
379} 379}
380 380
381static int stmp_read_logical_drive_sectors(uint8_t drive, uint64_t address,
382 uint32_t count, void *buffer, int *buffer_size)
383{
384 uint8_t cdb[16];
385 memset(cdb, 0, sizeof(cdb));
386 cdb[0] = SCSI_STMP_READ;
387 cdb[1] = SCSI_STMP_CMD_READ_LOGICAL_DRIVE_SECTOR;
388 cdb[2] = drive;
389 address = fix_endian64be(address);
390 memcpy(&cdb[3], &address, sizeof(address));
391 count = fix_endian32be(count);
392 memcpy(&cdb[11], &count, sizeof(count));
393
394 uint8_t sense[32];
395 int sense_size = sizeof(sense);
396
397 int ret = do_scsi(cdb, sizeof(cdb), DO_READ, sense, &sense_size, buffer, buffer_size);
398 if(ret < 0)
399 return ret;
400 return do_sense_analysis(ret, sense, sense_size);
401}
402
381static const char *stmp_get_logical_media_type_string(uint32_t type) 403static const char *stmp_get_logical_media_type_string(uint32_t type)
382{ 404{
383 switch(type) 405 switch(type)
@@ -418,10 +440,10 @@ static const char *stmp_get_logical_drive_type_string(uint32_t type)
418 } 440 }
419} 441}
420 442
421static int do_work(void) 443static int do_info(void)
422{ 444{
423 cprintf(BLUE, "Information\n"); 445 cprintf(BLUE, "Information\n");
424 446
425 uint8_t dev_type; 447 uint8_t dev_type;
426 char vendor[9]; 448 char vendor[9];
427 char product[17]; 449 char product[17];
@@ -590,7 +612,7 @@ static int do_work(void)
590 { 612 {
591 struct scsi_stmp_logical_table_t header; 613 struct scsi_stmp_logical_table_t header;
592 struct scsi_stmp_logical_table_entry_t entry[20]; 614 struct scsi_stmp_logical_table_entry_t entry[20];
593 }table; 615 }__attribute__((packed)) table;
594 616
595 ret = stmp_get_logical_table(&table.header, sizeof(table.entry) / sizeof(table.entry[0])); 617 ret = stmp_get_logical_table(&table.header, sizeof(table.entry) / sizeof(table.entry[0]));
596 if(ret) 618 if(ret)
@@ -734,19 +756,118 @@ static int do_work(void)
734 return 0; 756 return 0;
735} 757}
736 758
759void do_extract(const char *file)
760{
761 FILE *f = NULL;
762 cprintf(BLUE, "Extracting firmware...\n");
763
764 struct
765 {
766 struct scsi_stmp_logical_table_t header;
767 struct scsi_stmp_logical_table_entry_t entry[20];
768 }__attribute__((packed)) table;
769
770 int ret = stmp_get_logical_table(&table.header, sizeof(table.entry) / sizeof(table.entry[0]));
771 if(ret)
772 {
773 cprintf(GREY, "Cannot get logical table: %d\n", ret);
774 goto Lend;
775 }
776 int entry = 0;
777 while(entry < table.header.count)
778 if(table.entry[entry].type == SCSI_STMP_DRIVE_TYPE_SYSTEM &&
779 table.entry[entry].tag == SCSI_STMP_DRIVE_TAG_SYSTEM_BOOT)
780 break;
781 else
782 entry++;
783 if(entry == table.header.count)
784 {
785 cprintf(GREY, "Cannot find firmware partition\n");
786 goto Lend;
787 }
788 uint8_t drive_no = table.entry[entry].drive_no;
789 uint64_t drive_sz = table.entry[entry].size;
790 if(g_debug)
791 {
792 cprintf(RED, "* ");
793 cprintf_field("Drive: ", "%#x\n", drive_no);
794 cprintf(RED, "* ");
795 cprintf_field("Size: ", "%#llx\n", (unsigned long long)drive_sz);
796 }
797 int len = 4;
798 uint32_t sector_size;
799 ret = stmp_get_logical_drive_info(drive_no, SCSI_STMP_DRIVE_INFO_SECTOR, &sector_size, &len);
800 if(ret || len != 4)
801 {
802 cprintf(GREY, "Cannot get sector size\n");
803 goto Lend;
804 }
805 sector_size = fix_endian32be(sector_size);
806 if(g_debug)
807 {
808 cprintf(RED, "* ");
809 cprintf_field("Sector size: ", "%lu\n", (unsigned long)sector_size);
810 }
811 uint8_t *sector = malloc(sector_size);
812 len = sector_size;
813 ret = stmp_read_logical_drive_sectors(drive_no, 0, 1, sector, &len);
814 if(ret || len != (int)sector_size)
815 {
816 cprintf(GREY, "Cannot read first sector\n");
817 }
818 uint32_t fw_size = *(uint32_t *)(sector + 0x1c) * 16;
819 if(g_debug)
820 {
821 cprintf(RED, "* ");
822 cprintf_field("Firmware size: ", "%#x\n", fw_size);
823 }
824
825 f = fopen(file, "wb");
826 if(f == NULL)
827 {
828 cprintf(GREY, "Cannot open '%s' for writing: %m\n", file);
829 goto Lend;
830 }
831
832 for(int sec = 0; sec * sector_size < fw_size; sec++)
833 {
834 ret = stmp_read_logical_drive_sectors(drive_no, sec, 1, sector, &len);
835 if(ret || len != (int)sector_size)
836 {
837 cprintf(GREY, "Cannot read sector %d\n", sec);
838 goto Lend;
839 }
840 if(fwrite(sector, sector_size, 1, f) != 1)
841 {
842 cprintf(GREY, "Write failed: %m\n");
843 goto Lend;
844 }
845 }
846 cprintf(BLUE, "Done\n");
847Lend:
848 if(f)
849 fclose(f);
850}
851
737static void usage(void) 852static void usage(void)
738{ 853{
739 printf("Usage: scsitool [options] <dev>\n"); 854 printf("Usage: scsitool [options] <dev>\n");
740 printf("Options:\n"); 855 printf("Options:\n");
741 printf(" -f/--force\tForce to continue on errors\n"); 856 printf(" -f/--force Force to continue on errors\n");
742 printf(" -?/--help\tDisplay this message\n"); 857 printf(" -?/--help Display this message\n");
743 printf(" -d/--debug\tDisplay debug messages\n"); 858 printf(" -d/--debug Display debug messages\n");
744 printf(" -c/--no-color\tDisable color output\n"); 859 printf(" -c/--no-color Disable color output\n");
860 printf(" -x/--extract-fw <file> Extract firmware to file\n");
861 printf(" -i/--info Display device information\n");
745 exit(1); 862 exit(1);
746} 863}
747 864
748int main(int argc, char **argv) 865int main(int argc, char **argv)
749{ 866{
867 if(argc == 1)
868 usage();
869 const char *extract_fw = NULL;
870 bool info = false;
750 while(1) 871 while(1)
751 { 872 {
752 static struct option long_options[] = 873 static struct option long_options[] =
@@ -755,10 +876,12 @@ int main(int argc, char **argv)
755 {"debug", no_argument, 0, 'd'}, 876 {"debug", no_argument, 0, 'd'},
756 {"no-color", no_argument, 0, 'c'}, 877 {"no-color", no_argument, 0, 'c'},
757 {"force", no_argument, 0, 'f'}, 878 {"force", no_argument, 0, 'f'},
879 {"extract-fw", required_argument, 0, 'x'},
880 {"info", no_argument, 0, 'i'},
758 {0, 0, 0, 0} 881 {0, 0, 0, 0}
759 }; 882 };
760 883
761 int c = getopt_long(argc, argv, "?dcf", long_options, NULL); 884 int c = getopt_long(argc, argv, "?dcfx:i", long_options, NULL);
762 if(c == -1) 885 if(c == -1)
763 break; 886 break;
764 switch(c) 887 switch(c)
@@ -777,6 +900,12 @@ int main(int argc, char **argv)
777 case '?': 900 case '?':
778 usage(); 901 usage();
779 break; 902 break;
903 case 'x':
904 extract_fw = optarg;
905 break;
906 case 'i':
907 info = true;
908 break;
780 default: 909 default:
781 abort(); 910 abort();
782 } 911 }
@@ -797,7 +926,10 @@ int main(int argc, char **argv)
797 goto Lend; 926 goto Lend;
798 } 927 }
799 928
800 do_work(); 929 if(extract_fw)
930 do_extract(extract_fw);
931 if(info)
932 do_info();
801 933
802 scsi_pt_close_device(g_dev_fd); 934 scsi_pt_close_device(g_dev_fd);
803Lend: 935Lend:
diff --git a/utils/imxtools/scsitools/stmp_scsi.h b/utils/imxtools/scsitools/stmp_scsi.h
index 2da17baf47..167c9a042d 100644
--- a/utils/imxtools/scsitools/stmp_scsi.h
+++ b/utils/imxtools/scsitools/stmp_scsi.h
@@ -71,6 +71,13 @@ struct scsi_stmp_logical_table_entry_t
71 uint64_t size; /* big-endian */ 71 uint64_t size; /* big-endian */
72} __attribute__((packed)); 72} __attribute__((packed));
73 73
74#define SCSI_STMP_DRIVE_TYPE_USER 0
75#define SCSI_STMP_DRIVE_TYPE_SYSTEM 1
76#define SCSI_STMP_DRIVE_TYPE_JANUS 2
77
78#define SCSI_STMP_DRIVE_TAG_USER_STORAGE 0xa
79#define SCSI_STMP_DRIVE_TAG_SYSTEM_BOOT 0x50
80
74struct scsi_stmp_logical_table_t 81struct scsi_stmp_logical_table_t
75{ 82{
76 uint16_t count; /* big-endian */ 83 uint16_t count; /* big-endian */