summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rbutil/ipodpatcher/Makefile22
-rw-r--r--rbutil/ipodpatcher/ipodio.h4
-rw-r--r--rbutil/ipodpatcher/ipodpatcher.c503
-rw-r--r--rbutil/ipodpatcher/main.c23
-rw-r--r--rbutil/rbutilqt/rbutil.ini14
5 files changed, 531 insertions, 35 deletions
diff --git a/rbutil/ipodpatcher/Makefile b/rbutil/ipodpatcher/Makefile
index 9c32587fa1..713c21b546 100644
--- a/rbutil/ipodpatcher/Makefile
+++ b/rbutil/ipodpatcher/Makefile
@@ -2,13 +2,26 @@ CFLAGS=-Wall -W
2 2
3BOOT_H = ipod1g2g.h ipod3g.h ipod4g.h ipodcolor.h ipodmini.h ipodmini2g.h ipodnano.h ipodvideo.h 3BOOT_H = ipod1g2g.h ipod3g.h ipod4g.h ipodcolor.h ipodmini.h ipodmini2g.h ipodnano.h ipodvideo.h
4 4
5# Uncomment the next two lines to build with embedded bootloaders and the 5# Enable the next two lines to build with embedded bootloaders and the
6# --install option and interactive mode. You need the full set of Rockbox 6# --install option and interactive mode. You need the full set of Rockbox
7# bootloaders in this directory - download them from 7# bootloaders in this directory - download them from
8# http://download.rockbox.org/bootloader/ipod/bootloaders.zip 8# http://download.rockbox.org/bootloader/ipod/bootloaders.zip
9 9
10#BOOTSRC = ipod1g2g.c ipod3g.c ipod4g.c ipodcolor.c ipodmini.c ipodmini2g.c ipodnano.c ipodvideo.c 10ifdef RELEASE
11#CFLAGS += -DWITH_BOOTOBJS 11CFLAGS+=-DRELEASE
12BOOTOBJS=1
13endif
14
15ifdef BOOTOBJS
16BOOTSRC = ipod1g2g.c ipod3g.c ipod4g.c ipodcolor.c ipodmini.c ipodmini2g.c ipodnano.c ipodvideo.c ipodnano2g.c
17CFLAGS += -DWITH_BOOTOBJS
18endif
19
20ifndef VERSION
21VERSION=$(shell ../../tools/version.sh)
22endif
23
24CFLAGS+=-DVERSION=\"$(VERSION)\"
12 25
13ifeq ($(findstring CYGWIN,$(shell uname)),CYGWIN) 26ifeq ($(findstring CYGWIN,$(shell uname)),CYGWIN)
14OUTPUT=ipodpatcher.exe 27OUTPUT=ipodpatcher.exe
@@ -81,6 +94,9 @@ ipodnano.c: bootloader-ipodnano.ipod ipod2c
81ipodvideo.c: bootloader-ipodvideo.ipod ipod2c 94ipodvideo.c: bootloader-ipodvideo.ipod ipod2c
82 ./ipod2c bootloader-ipodvideo.ipod ipodvideo 95 ./ipod2c bootloader-ipodvideo.ipod ipodvideo
83 96
97ipodnano2g.c: bootloader-ipodnano2g.ipodx ipod2c
98 ./ipod2c bootloader-ipodnano2g.ipodx ipodnano2g
99
84 100
85clean: 101clean:
86 rm -f ipodpatcher.exe ipodpatcher-rc.o ipodpatcher-mac ipodpatcher-i386 ipodpatcher-ppc ipodpatcher ipod2c *~ $(BOOTSRC) $(BOOT_H) 102 rm -f ipodpatcher.exe ipodpatcher-rc.o ipodpatcher-mac ipodpatcher-i386 ipodpatcher-ppc ipodpatcher ipod2c *~ $(BOOTSRC) $(BOOT_H)
diff --git a/rbutil/ipodpatcher/ipodio.h b/rbutil/ipodpatcher/ipodio.h
index e0692ca6d9..5c098ab60c 100644
--- a/rbutil/ipodpatcher/ipodio.h
+++ b/rbutil/ipodpatcher/ipodio.h
@@ -39,7 +39,8 @@ enum firmwaretype_t {
39 FTYPE_OSOS = 0, 39 FTYPE_OSOS = 0,
40 FTYPE_RSRC, 40 FTYPE_RSRC,
41 FTYPE_AUPD, 41 FTYPE_AUPD,
42 FTYPE_HIBE 42 FTYPE_HIBE,
43 FTYPE_OSBK
43}; 44};
44 45
45struct ipod_directory_t { 46struct ipod_directory_t {
@@ -71,6 +72,7 @@ struct ipod_t {
71 int num_heads; 72 int num_heads;
72 struct ipod_directory_t ipod_directory[MAX_IMAGES]; 73 struct ipod_directory_t ipod_directory[MAX_IMAGES];
73 int nimages; 74 int nimages;
75 int ososimage;
74 off_t diroffset; 76 off_t diroffset;
75 off_t start; /* Offset in bytes of firmware partition from start of disk */ 77 off_t start; /* Offset in bytes of firmware partition from start of disk */
76 off_t fwoffset; /* Offset in bytes of start of firmware images from start of disk */ 78 off_t fwoffset; /* Offset in bytes of start of firmware images from start of disk */
diff --git a/rbutil/ipodpatcher/ipodpatcher.c b/rbutil/ipodpatcher/ipodpatcher.c
index 79357fde06..7116056350 100644
--- a/rbutil/ipodpatcher/ipodpatcher.c
+++ b/rbutil/ipodpatcher/ipodpatcher.c
@@ -42,6 +42,7 @@
42#include "ipodcolor.h" 42#include "ipodcolor.h"
43#include "ipodnano.h" 43#include "ipodnano.h"
44#include "ipodvideo.h" 44#include "ipodvideo.h"
45#include "ipodnano2g.h"
45#endif 46#endif
46 47
47#ifndef RBUTIL 48#ifndef RBUTIL
@@ -389,7 +390,7 @@ int write_partition(struct ipod_t* ipod, int infile)
389 return 0; 390 return 0;
390} 391}
391 392
392char* ftypename[] = { "OSOS", "RSRC", "AUPD", "HIBE" }; 393char* ftypename[] = { "OSOS", "RSRC", "AUPD", "HIBE", "OSBK" };
393 394
394int diskmove(struct ipod_t* ipod, int delta) 395int diskmove(struct ipod_t* ipod, int delta)
395{ 396{
@@ -470,6 +471,409 @@ int diskmove(struct ipod_t* ipod, int delta)
470 return 0; 471 return 0;
471} 472}
472 473
474static int rename_image(struct ipod_t* ipod, char* from, char* to)
475{
476 int n;
477 int x;
478 int found;
479 int i;
480 unsigned char* p;
481
482 /* diroffset may not be sector-aligned */
483 x = ipod->diroffset % ipod->sector_size;
484
485 /* Read directory */
486 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
487 fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
488 return -1;
489 }
490
491 n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
492 if (n < 0) {
493 fprintf(stderr,"[ERR] Read of directory failed.\n");
494 return -1;
495 }
496
497 p = ipod_sectorbuf + x;
498
499 /* A hack to detect 2nd gen Nanos - maybe there is a better way? */
500 if (p[0] == 0)
501 {
502 /* Adjust diroffset */
503 ipod->diroffset += ipod->sector_size - x;
504
505 n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
506 if (n < 0) {
507 fprintf(stderr,"[ERR] Read of directory failed.\n");
508 return -1;
509 }
510 p = ipod_sectorbuf;
511 }
512
513 found = 0;
514 for (i=0 ; !found && i < MAX_IMAGES; i++) {
515 if (memcmp(p + 4, from, 4) == 0) {
516 memcpy(p + 4, to, 4);
517
518 found = 1;
519 }
520 p += 40;
521 }
522
523 if (!found) {
524 fprintf(stderr,"[ERR] Unexpected error - no \"%s\" image!\n", from);
525 return -1;
526 }
527
528 /* Write directory back to disk */
529 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
530 fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
531 return -1;
532 }
533
534 n=ipod_write(ipod, ipod_sectorbuf, ipod->sector_size);
535 if (n < 0) {
536 fprintf(stderr,"[ERR] Write of directory failed in rename_image.\n");
537 return -1;
538 }
539
540 return 0;
541}
542
543static int delete_image(struct ipod_t* ipod, char* name)
544{
545 int n;
546 int x;
547 int found;
548 int i;
549 unsigned char* p;
550
551 /* diroffset may not be sector-aligned */
552 x = ipod->diroffset % ipod->sector_size;
553
554 /* Read directory */
555 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
556 fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
557 return -1;
558 }
559
560 n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
561 if (n < 0) {
562 fprintf(stderr,"[ERR] Read of directory failed.\n");
563 return -1;
564 }
565
566 p = ipod_sectorbuf + x;
567
568 /* A hack to detect 2nd gen Nanos - maybe there is a better way? */
569 if (p[0] == 0)
570 {
571 /* Adjust diroffset */
572 ipod->diroffset += ipod->sector_size - x;
573
574 n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
575 if (n < 0) {
576 fprintf(stderr,"[ERR] Read of directory failed.\n");
577 return -1;
578 }
579 p = ipod_sectorbuf;
580 }
581
582 found = 0;
583 for (i=0 ; !found && i < MAX_IMAGES; i++) {
584 if (memcmp(p + 4, name, 4) == 0) {
585 memset(p, 0, 40); /* Delete directory entry */
586 found = 1;
587 }
588 p += 40;
589 }
590
591 if (!found) {
592 fprintf(stderr,"[ERR] Unexpected error - no \"%s\" image!\n", name);
593 return -1;
594 }
595
596 /* Write directory back to disk */
597 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
598 fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
599 return -1;
600 }
601
602 n=ipod_write(ipod, ipod_sectorbuf, ipod->sector_size);
603 if (n < 0) {
604 fprintf(stderr,"[ERR] Write of directory failed in delete_image.\n");
605 return -1;
606 }
607
608 return 0;
609}
610
611int add_new_image(struct ipod_t* ipod, char* imagename, char* filename, int type)
612{
613 int length;
614 int found;
615 int i;
616 int x;
617 int n;
618 int infile;
619 int newsize;
620 unsigned long chksum=0;
621 unsigned long filechksum=0;
622 unsigned long offset;
623 unsigned char header[8]; /* Header for .ipod file */
624 unsigned char* p;
625
626#ifdef WITH_BOOTOBJS
627 if (type == FILETYPE_INTERNAL) {
628 fprintf(stderr,"[INFO] Using internal bootloader - %d bytes\n",ipod->bootloader_len);
629 length = ipod->bootloader_len;
630 infile = -1;
631 }
632 else
633#endif
634 {
635 /* First check that the input file is the correct type for this ipod. */
636 infile=open(filename,O_RDONLY);
637 if (infile < 0) {
638 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
639 return -1;
640 }
641
642 if (type==FILETYPE_DOT_IPOD) {
643 n = read(infile,header,8);
644 if (n < 8) {
645 fprintf(stderr,"[ERR] Failed to read header from %s\n",filename);
646 close(infile);
647 return -1;
648 }
649
650 if (memcmp(header+4, ipod->modelname,4)!=0) {
651 fprintf(stderr,"[ERR] Model name in input file (%c%c%c%c) doesn't match ipod model (%s)\n",
652 header[4],header[5],header[6],header[7], ipod->modelname);
653 close(infile);
654 return -1;
655 }
656
657 filechksum = be2int(header);
658
659 length = filesize(infile)-8;
660 } else {
661 length = filesize(infile);
662 }
663 }
664
665 newsize=(length+ipod->sector_size-1)&~(ipod->sector_size-1);
666
667 fprintf(stderr,"[INFO] Padding input file from 0x%08x to 0x%08x bytes\n",
668 length,newsize);
669
670 if (newsize > BUFFER_SIZE) {
671 fprintf(stderr,"[ERR] Input file too big for buffer\n");
672 if (infile >= 0) close(infile);
673 return -1;
674 }
675
676 /* TODO: Check if we have enough space in the partition for the new image */
677
678#ifdef WITH_BOOTOBJS
679 if (type == FILETYPE_INTERNAL) {
680 memcpy(ipod_sectorbuf,ipod->bootloader,ipod->bootloader_len);
681 }
682 else
683#endif
684 {
685 fprintf(stderr,"[INFO] Reading input file...\n");
686
687 n = read(infile,ipod_sectorbuf,length);
688 if (n < 0) {
689 fprintf(stderr,"[ERR] Couldn't read input file\n");
690 close(infile);
691 return -1;
692 }
693 close(infile);
694 }
695
696 /* Pad the data with zeros */
697 memset(ipod_sectorbuf+length,0,newsize-length);
698
699 if (type==FILETYPE_DOT_IPOD) {
700 chksum = ipod->modelnum;
701 for (i = 0; i < length; i++) {
702 /* add 8 unsigned bits but keep a 32 bit sum */
703 chksum += ipod_sectorbuf[i];
704 }
705
706 if (chksum == filechksum) {
707 fprintf(stderr,"[INFO] Checksum OK in %s\n",filename);
708 } else {
709 fprintf(stderr,"[ERR] Checksum in %s failed check\n",filename);
710 return -1;
711 }
712 }
713
714
715 offset = ipod->fwoffset + ipod->ipod_directory[ipod->nimages - 1].devOffset +
716 ipod->ipod_directory[ipod->nimages - 1].len + ipod->sector_size;
717
718 /* 2nd Gen Nano has encrypted firmware, and the sector
719 preceeding the firmware contains hashes that need to be
720 preserved. Nano 2G images include these extra 2048 (0x800)
721 bytes
722 */
723 if (ipod_seek(ipod, offset - (ipod->modelnum == 62 ? 0x800 : 0)) < 0) {
724 fprintf(stderr,"[ERR] Seek failed\n");
725 return -1;
726 }
727
728 if ((n = ipod_write(ipod,ipod_sectorbuf,newsize)) < 0) {
729 perror("[ERR] Write failed\n");
730 return -1;
731 }
732
733 if (n < newsize) {
734 fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n"
735 ,newsize,n);
736 return -1;
737 }
738 fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n);
739
740 /* Now we need to create a new directory entry
741
742 NOTE: On the Nano 2G, the checksum is the checksum of the
743 unencrypted firmware. But this isn't checked by the NOR
744 bootloader (there are cryptographic hashes in the
745 firmware itself), so it doesn't matter that this is
746 wrong.
747 */
748 chksum = 0;
749 for (i = 0; i < length; i++) {
750 /* add 8 unsigned bits but keep a 32 bit sum */
751 chksum += ipod_sectorbuf[i];
752 }
753
754 x = ipod->diroffset % ipod->sector_size;
755
756 /* Read directory */
757 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
758
759 n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
760 if (n < 0) { return -1; }
761
762 /* Create a new directory entry */
763
764 /* Copy OSOS or OSBK details - we assume one of them exists */
765 p = ipod_sectorbuf + x;
766 found = 0;
767 for (i = 0; !found && i < ipod->nimages; i++) {
768 if ((memcmp(p + 4, "soso", 4)==0) || (memcmp(p + 4, "kbso", 4)==0)) {
769 found = 1;
770 } else {
771 p += 40;
772 }
773 }
774
775 if (!found) {
776 fprintf(stderr,"[ERR] No OSOS or OSBK image to copy directory from\n");
777 return -1;
778 }
779
780 /* Copy directory image */
781 memcpy(ipod_sectorbuf + x + (ipod->nimages * 40), p, 40);
782 p = ipod_sectorbuf + x + (ipod->nimages * 40);
783
784 /* Modify directory. */
785 memcpy(p + 4, imagename, 4);
786 int2le(offset - ipod->fwoffset, p + 12); /* devOffset */
787 int2le(length - (ipod->modelnum==62 ? 0x800: 0), p + 16); /* len */
788 int2le(chksum, p + 28); /* checksum */
789
790 /* Write directory */
791 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
792 n=ipod_write(ipod, ipod_sectorbuf, ipod->sector_size);
793 if (n < 0) { return -1; }
794
795 return 0;
796}
797
798
799/*
800 Bootloader installation on the Nano2G consists of renaming the
801 OSOS image to OSBK and then writing the Rockbox bootloader as a
802 new OSOS image.
803
804 Maybe this approach can/should be adapted for other ipods, as it
805 prevents the Apple bootloader loading the original firmware into
806 RAM along with the Rockbox bootloader (and hence will give a
807 faster boot when the user just wants to start Rockbox).
808
809*/
810
811static int add_bootloader_nano2g(struct ipod_t* ipod, char* filename, int type)
812{
813 int i;
814 int has_osbk = 0;
815
816 /* Check if we already have an OSBK image */
817 for (i = 0; i < ipod->nimages; i++) {
818 if (ipod->ipod_directory[i].ftype==FTYPE_OSBK) {
819 has_osbk = 1;
820 }
821 }
822
823 if (has_osbk == 0) {
824 /* First-time install - rename OSOS to OSBK and create new OSOS for bootloader */
825 fprintf(stderr,"[INFO] Creating OSBK backup image of original firmware\n");
826
827 if (rename_image(ipod, "soso", "kbso") < 0) {
828 fprintf(stderr,"[ERR] Could not rename OSOS image\n");
829 return -1;
830 }
831
832 /* Add our bootloader as a brand new image */
833 return add_new_image(ipod, "soso", filename, type);
834 } else {
835 /* This is an update, just replace OSOS with our bootloader */
836
837 return write_firmware(ipod, filename, type);
838 }
839}
840
841
842static int delete_bootloader_nano2g(struct ipod_t* ipod)
843{
844 int i;
845 int has_osbk = 0;
846
847 /* Check if we have an OSBK image */
848 for (i = 0; i < ipod->nimages; i++) {
849 if (ipod->ipod_directory[i].ftype==FTYPE_OSBK) {
850 has_osbk = 1;
851 }
852 }
853
854 if (has_osbk == 0) {
855 fprintf(stderr,"[ERR] No OSBK image found - nothing to uninstall\n");
856 return -1;
857 } else {
858 /* Delete our bootloader image */
859 if (delete_image(ipod, "soso") < 0) {
860 fprintf(stderr,"[WARN] Could not delete OSOS image\n");
861 } else {
862 fprintf(stderr,"[INFO] OSOS image deleted\n");
863 }
864
865 if (rename_image(ipod, "kbso", "soso") < 0) {
866 fprintf(stderr,"[ERR] Could not rename OSBK image\n");
867 return -1;
868 }
869
870
871 fprintf(stderr,"[INFO] OSBK image renamed to OSOS - bootloader uninstalled.\n");
872 return 0;
873 }
874}
875
876
473int add_bootloader(struct ipod_t* ipod, char* filename, int type) 877int add_bootloader(struct ipod_t* ipod, char* filename, int type)
474{ 878{
475 int length; 879 int length;
@@ -485,6 +889,11 @@ int add_bootloader(struct ipod_t* ipod, char* filename, int type)
485 unsigned char header[8]; /* Header for .ipod file */ 889 unsigned char header[8]; /* Header for .ipod file */
486 unsigned char* bootloader_buf; 890 unsigned char* bootloader_buf;
487 891
892 /* The 2nd gen Nano is installed differently */
893 if (ipod->modelnum == 62) {
894 return add_bootloader_nano2g(ipod, filename, type);
895 }
896
488 /* Calculate the position in the OSOS image where our bootloader will go. */ 897 /* Calculate the position in the OSOS image where our bootloader will go. */
489 if (ipod->ipod_directory[0].entryOffset>0) { 898 if (ipod->ipod_directory[0].entryOffset>0) {
490 /* Keep the same entryOffset */ 899 /* Keep the same entryOffset */
@@ -698,6 +1107,11 @@ int delete_bootloader(struct ipod_t* ipod)
698 int n; 1107 int n;
699 unsigned long chksum=0; /* 32 bit checksum - Rockbox .ipod style*/ 1108 unsigned long chksum=0; /* 32 bit checksum - Rockbox .ipod style*/
700 1109
1110 /* The 2nd gen Nano is installed differently */
1111 if (ipod->modelnum == 62) {
1112 return delete_bootloader_nano2g(ipod);
1113 }
1114
701 /* Removing the bootloader involves adjusting the "length", 1115 /* Removing the bootloader involves adjusting the "length",
702 "chksum" and "entryOffset" values in the osos image's directory 1116 "chksum" and "entryOffset" values in the osos image's directory
703 entry. */ 1117 entry. */
@@ -774,7 +1188,9 @@ int write_firmware(struct ipod_t* ipod, char* filename, int type)
774 int bytesavailable; 1188 int bytesavailable;
775 unsigned long chksum=0; 1189 unsigned long chksum=0;
776 unsigned long filechksum=0; 1190 unsigned long filechksum=0;
1191 unsigned long offset;
777 unsigned char header[8]; /* Header for .ipod file */ 1192 unsigned char header[8]; /* Header for .ipod file */
1193 unsigned char* p;
778 1194
779#ifdef WITH_BOOTOBJS 1195#ifdef WITH_BOOTOBJS
780 if (type == FILETYPE_INTERNAL) { 1196 if (type == FILETYPE_INTERNAL) {
@@ -876,7 +1292,23 @@ int write_firmware(struct ipod_t* ipod, char* filename, int type)
876 } 1292 }
877 } 1293 }
878 1294
879 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) { 1295
1296 offset = ipod->fwoffset+ipod->ipod_directory[ipod->ososimage].devOffset;
1297
1298 if (ipod->modelnum==62) {
1299
1300 /* 2nd Gen Nano has encrypted firmware, and the sector
1301 preceeding the firmware contains hashes that need to be
1302 preserved. Nano 2G images include these extra 2048 (0x800)
1303 bytes
1304 */
1305
1306 offset -= 0x800;
1307
1308 /* TODO: The above checks need to take into account this 0x800 bytes */
1309 }
1310
1311 if (ipod_seek(ipod, offset) < 0) {
880 fprintf(stderr,"[ERR] Seek failed\n"); 1312 fprintf(stderr,"[ERR] Seek failed\n");
881 return -1; 1313 return -1;
882 } 1314 }
@@ -893,7 +1325,14 @@ int write_firmware(struct ipod_t* ipod, char* filename, int type)
893 } 1325 }
894 fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n); 1326 fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n);
895 1327
896 /* Now we need to update the "len", "entryOffset" and "chksum" fields */ 1328 /* Now we need to update the "len", "entryOffset" and "chksum" fields
1329
1330 NOTE: On the Nano 2G, the checksum is the checksum of the
1331 unencrypted firmware. But this isn't checked by the NOR
1332 bootloader (there are cryptographic hashes in the
1333 firmware itself), so it doesn't matter that this is
1334 wrong.
1335 */
897 chksum = 0; 1336 chksum = 0;
898 for (i = 0; i < length; i++) { 1337 for (i = 0; i < length; i++) {
899 /* add 8 unsigned bits but keep a 32 bit sum */ 1338 /* add 8 unsigned bits but keep a 32 bit sum */
@@ -908,10 +1347,11 @@ int write_firmware(struct ipod_t* ipod, char* filename, int type)
908 n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size); 1347 n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
909 if (n < 0) { return -1; } 1348 if (n < 0) { return -1; }
910 1349
911 /* Update entries for image 0 */ 1350 /* Update entries for image */
912 int2le(length,ipod_sectorbuf+x+16); 1351 p = ipod_sectorbuf + x + (ipod->ososimage * 40);
913 int2le(0,ipod_sectorbuf+x+24); 1352 int2le(length - (ipod->modelnum==62 ? 0x800: 0), p + 16);
914 int2le(chksum,ipod_sectorbuf+x+28); 1353 int2le(0, p + 24);
1354 int2le(chksum, p + 28);
915 1355
916 /* Write directory */ 1356 /* Write directory */
917 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; } 1357 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
@@ -927,26 +1367,36 @@ int read_firmware(struct ipod_t* ipod, char* filename, int type)
927 int i; 1367 int i;
928 int outfile; 1368 int outfile;
929 int n; 1369 int n;
1370 unsigned long offset;
930 unsigned long chksum=0; /* 32 bit checksum - Rockbox .ipod style*/ 1371 unsigned long chksum=0; /* 32 bit checksum - Rockbox .ipod style*/
931 unsigned char header[8]; /* Header for .ipod file */ 1372 unsigned char header[8]; /* Header for .ipod file */
932 1373
933 if (ipod->ipod_directory[0].entryOffset != 0) { 1374 if (ipod->ipod_directory[ipod->ososimage].entryOffset != 0) {
934 /* We have a bootloader... */ 1375 /* We have a bootloader... */
935 length = ipod->ipod_directory[0].entryOffset; 1376 length = ipod->ipod_directory[ipod->ososimage].entryOffset;
936 } else { 1377 } else {
937 length = ipod->ipod_directory[0].len; 1378 length = ipod->ipod_directory[ipod->ososimage].len;
938 } 1379 }
939 1380
940 fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length); 1381 fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length);
941 1382
942 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) { 1383 offset = ipod->fwoffset + ipod->ipod_directory[ipod->ososimage].devOffset;
943 return -1;
944 }
945
946 i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1); 1384 i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1);
947 fprintf(stderr,"[INFO] Padding read from 0x%08x to 0x%08x bytes\n", 1385 fprintf(stderr,"[INFO] Padding read from 0x%08x to 0x%08x bytes\n",
948 length,i); 1386 length,i);
949 1387
1388 if (ipod->modelnum==62) {
1389 /* 2nd Gen Nano has encrypted firmware, and we need to dump the
1390 sector preceeding the image - it contains hashes */
1391 offset -= 0x800;
1392 length += 0x800;
1393 i += 0x800;
1394 }
1395
1396 if (ipod_seek(ipod, offset)) {
1397 return -1;
1398 }
1399
950 if ((n = ipod_read(ipod,ipod_sectorbuf,i)) < 0) { 1400 if ((n = ipod_read(ipod,ipod_sectorbuf,i)) < 0) {
951 return -1; 1401 return -1;
952 } 1402 }
@@ -1049,6 +1499,9 @@ int read_directory(struct ipod_t* ipod)
1049 /* A hack to detect 2nd gen Nanos - maybe there is a better way? */ 1499 /* A hack to detect 2nd gen Nanos - maybe there is a better way? */
1050 if (p[0] == 0) 1500 if (p[0] == 0)
1051 { 1501 {
1502 /* Adjust diroffset */
1503 ipod->diroffset += ipod->sector_size - x;
1504
1052 n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size); 1505 n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
1053 if (n < 0) { 1506 if (n < 0) {
1054 fprintf(stderr,"[ERR] Read of directory failed.\n"); 1507 fprintf(stderr,"[ERR] Read of directory failed.\n");
@@ -1057,15 +1510,19 @@ int read_directory(struct ipod_t* ipod)
1057 p = ipod_sectorbuf; 1510 p = ipod_sectorbuf;
1058 } 1511 }
1059 1512
1513 ipod->ososimage = -1;
1060 while ((ipod->nimages < MAX_IMAGES) && (p < (ipod_sectorbuf + x + 400)) && 1514 while ((ipod->nimages < MAX_IMAGES) && (p < (ipod_sectorbuf + x + 400)) &&
1061 ((memcmp(p,"!ATA",4)==0) || (memcmp(p,"DNAN",4)==0))) { 1515 ((memcmp(p,"!ATA",4)==0) || (memcmp(p,"DNAN",4)==0))) {
1062 p+=4; 1516 p+=4;
1063 if (memcmp(p,"soso",4)==0) { 1517 if (memcmp(p,"soso",4)==0) {
1064 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_OSOS; 1518 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_OSOS;
1519 ipod->ososimage = ipod->nimages;
1065 } else if (memcmp(p,"crsr",4)==0) { 1520 } else if (memcmp(p,"crsr",4)==0) {
1066 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_RSRC; 1521 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_RSRC;
1067 } else if (memcmp(p,"dpua",4)==0) { 1522 } else if (memcmp(p,"dpua",4)==0) {
1068 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_AUPD; 1523 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_AUPD;
1524 } else if (memcmp(p,"kbso",4)==0) {
1525 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_OSBK;
1069 } else if (memcmp(p,"ebih",4)==0) { 1526 } else if (memcmp(p,"ebih",4)==0) {
1070 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_HIBE; 1527 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_HIBE;
1071 } else { 1528 } else {
@@ -1092,12 +1549,17 @@ int read_directory(struct ipod_t* ipod)
1092 ipod->nimages++; 1549 ipod->nimages++;
1093 } 1550 }
1094 1551
1552 if (ipod->ososimage < 0) {
1553 fprintf(stderr,"[ERR] No OSOS image found.\n");
1554 return -1;
1555 }
1556
1095 if ((ipod->nimages > 1) && (version==2)) { 1557 if ((ipod->nimages > 1) && (version==2)) {
1096 /* The 3g firmware image doesn't appear to have a version, so 1558 /* The 3g firmware image doesn't appear to have a version, so
1097 let's make one up... Note that this is never written back to the 1559 let's make one up... Note that this is never written back to the
1098 ipod, so it's OK to do. */ 1560 ipod, so it's OK to do. */
1099 1561
1100 if (ipod->ipod_directory[0].vers == 0) { ipod->ipod_directory[0].vers = 3; } 1562 if (ipod->ipod_directory[ipod->ososimage].vers == 0) { ipod->ipod_directory[ipod->ososimage].vers = 3; }
1101 1563
1102 ipod->fwoffset = ipod->start; 1564 ipod->fwoffset = ipod->start;
1103 } else { 1565 } else {
@@ -1247,11 +1709,12 @@ int getmodel(struct ipod_t* ipod, int ipod_version)
1247 break; 1709 break;
1248 case 0x100: 1710 case 0x100:
1249 ipod->modelstr="2nd Generation Nano"; 1711 ipod->modelstr="2nd Generation Nano";
1250 ipod->modelnum = 0; 1712 ipod->modelnum = 62;
1251 ipod->targetname = NULL; 1713 ipod->modelname = "nn2x";
1714 ipod->targetname = "ipodnano2g";
1252#ifdef WITH_BOOTOBJS 1715#ifdef WITH_BOOTOBJS
1253 ipod->bootloader = NULL; 1716 ipod->bootloader = ipodnano2g;
1254 ipod->bootloader_len = 0; 1717 ipod->bootloader_len = LEN_ipodnano2g;
1255#endif 1718#endif
1256 break; 1719 break;
1257 default: 1720 default:
@@ -1316,7 +1779,7 @@ int ipod_scan(struct ipod_t* ipod)
1316 continue; 1779 continue;
1317 } 1780 }
1318 1781
1319 ipod_version=(ipod->ipod_directory[0].vers>>8); 1782 ipod_version=(ipod->ipod_directory[ipod->ososimage].vers>>8);
1320 /* Windows requires the ipod in R/W mode for SCSI Inquiry */ 1783 /* Windows requires the ipod in R/W mode for SCSI Inquiry */
1321 ipod->ramsize = 0; 1784 ipod->ramsize = 0;
1322 ipod_reopen_rw(ipod); 1785 ipod_reopen_rw(ipod);
diff --git a/rbutil/ipodpatcher/main.c b/rbutil/ipodpatcher/main.c
index 1dcb916240..e1002b23c9 100644
--- a/rbutil/ipodpatcher/main.c
+++ b/rbutil/ipodpatcher/main.c
@@ -31,7 +31,11 @@
31#include "ipodpatcher.h" 31#include "ipodpatcher.h"
32#include "ipodio.h" 32#include "ipodio.h"
33 33
34#define VERSION "3.0 with v3.0 bootloaders" 34#ifdef RELEASE
35#undef VERSION
36#define VERSION "4.0 with v3.0 bootloaders (v1.0 for 2nd Gen Nano)"
37#endif
38
35 39
36enum { 40enum {
37 NONE, 41 NONE,
@@ -80,14 +84,14 @@ void print_usage(void)
80 fprintf(stderr," -l, --list\n"); 84 fprintf(stderr," -l, --list\n");
81 fprintf(stderr," -r, --read-partition bootpartition.bin\n"); 85 fprintf(stderr," -r, --read-partition bootpartition.bin\n");
82 fprintf(stderr," -w, --write-partition bootpartition.bin\n"); 86 fprintf(stderr," -w, --write-partition bootpartition.bin\n");
83 fprintf(stderr," -rf, --read-firmware filename.ipod\n"); 87 fprintf(stderr," -rf, --read-firmware filename.ipod[x]\n");
84 fprintf(stderr," -rfb, --read-firmware-bin filename.bin\n"); 88 fprintf(stderr," -rfb, --read-firmware-bin filename.bin\n");
85 fprintf(stderr," -wf, --write-firmware filename.ipod\n"); 89 fprintf(stderr," -wf, --write-firmware filename.ipod[x]\n");
86 fprintf(stderr," -wfb, --write-firmware-bin filename.bin\n"); 90 fprintf(stderr," -wfb, --write-firmware-bin filename.bin\n");
87#ifdef WITH_BOOTOBJS 91#ifdef WITH_BOOTOBJS
88 fprintf(stderr," -we, --write-embedded\n"); 92 fprintf(stderr," -we, --write-embedded\n");
89#endif 93#endif
90 fprintf(stderr," -a, --add-bootloader filename.ipod\n"); 94 fprintf(stderr," -a, --add-bootloader filename.ipod[x]\n");
91 fprintf(stderr," -ab, --add-bootloader-bin filename.bin\n"); 95 fprintf(stderr," -ab, --add-bootloader-bin filename.bin\n");
92 fprintf(stderr," -d, --delete-bootloader\n"); 96 fprintf(stderr," -d, --delete-bootloader\n");
93 fprintf(stderr," -f, --format\n"); 97 fprintf(stderr," -f, --format\n");
@@ -97,6 +101,8 @@ void print_usage(void)
97 fprintf(stderr," -x --dump-xml filename.xml\n"); 101 fprintf(stderr," -x --dump-xml filename.xml\n");
98 fprintf(stderr,"\n"); 102 fprintf(stderr,"\n");
99 103
104 fprintf(stderr,"The .ipodx extension is used for encrypted images for the 2nd Gen Nano.\n\n");
105
100#ifdef __WIN32__ 106#ifdef __WIN32__
101 fprintf(stderr,"DISKNO is the number (e.g. 2) Windows has assigned to your ipod's hard disk.\n"); 107 fprintf(stderr,"DISKNO is the number (e.g. 2) Windows has assigned to your ipod's hard disk.\n");
102 fprintf(stderr,"The first hard disk in your computer (i.e. C:\\) will be disk 0, the next disk\n"); 108 fprintf(stderr,"The first hard disk in your computer (i.e. C:\\) will be disk 0, the next disk\n");
@@ -148,7 +154,8 @@ int main(int argc, char* argv[])
148 int type; 154 int type;
149 struct ipod_t ipod; 155 struct ipod_t ipod;
150 156
151 fprintf(stderr,"ipodpatcher v" VERSION " - (C) Dave Chapman 2006-2007\n"); 157 fprintf(stderr,"ipodpatcher " VERSION "\n");
158 fprintf(stderr,"(C) Dave Chapman 2006-2009\n");
152 fprintf(stderr,"This is free software; see the source for copying conditions. There is NO\n"); 159 fprintf(stderr,"This is free software; see the source for copying conditions. There is NO\n");
153 fprintf(stderr,"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"); 160 fprintf(stderr,"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
154 161
@@ -364,9 +371,9 @@ int main(int argc, char* argv[])
364 return 1; 371 return 1;
365 } 372 }
366 373
367 if (getmodel(&ipod,(ipod.ipod_directory[0].vers>>8)) < 0) { 374 if (getmodel(&ipod,(ipod.ipod_directory[ipod.ososimage].vers>>8)) < 0) {
368 fprintf(stderr,"[ERR] Unknown version number in firmware (%08x)\n", 375 fprintf(stderr,"[ERR] Unknown version number in firmware (%08x)\n",
369 ipod.ipod_directory[0].vers); 376 ipod.ipod_directory[ipod.ososimage].vers);
370 return -1; 377 return -1;
371 } 378 }
372 379
@@ -391,7 +398,7 @@ int main(int argc, char* argv[])
391 if (ipod.ramsize > 0) { printf("(%dMB RAM) ",ipod.ramsize); } 398 if (ipod.ramsize > 0) { printf("(%dMB RAM) ",ipod.ramsize); }
392 printf("(\"%s\")\n",ipod.macpod ? "macpod" : "winpod"); 399 printf("(\"%s\")\n",ipod.macpod ? "macpod" : "winpod");
393 400
394 if (ipod.ipod_directory[0].vers == 0x10000) { 401 if (ipod.ipod_directory[ipod.ososimage].vers == 0x10000) {
395 fprintf(stderr,"[ERR] *** ipodpatcher does not support the 2nd Generation Nano! ***\n"); 402 fprintf(stderr,"[ERR] *** ipodpatcher does not support the 2nd Generation Nano! ***\n");
396#ifdef WITH_BOOTOBJS 403#ifdef WITH_BOOTOBJS
397 printf("Press ENTER to exit ipodpatcher :"); 404 printf("Press ENTER to exit ipodpatcher :");
diff --git a/rbutil/rbutilqt/rbutil.ini b/rbutil/rbutilqt/rbutil.ini
index 987061be01..29db74c946 100644
--- a/rbutil/rbutilqt/rbutil.ini
+++ b/rbutil/rbutilqt/rbutil.ini
@@ -39,6 +39,7 @@ platform25=ipodvideo64mb
39platform26=ipodmini1g 39platform26=ipodmini1g
40platform27=ipodmini2g 40platform27=ipodmini2g
41platform28=ipodnano 41platform28=ipodnano
42platform29=ipodnano2g
42platform30=iaudiox5 43platform30=iaudiox5
43platform31=iaudiom5 44platform31=iaudiom5
44platform32=iaudiox5v 45platform32=iaudiox5v
@@ -242,6 +243,16 @@ brand=Apple
242configure_modelname=ipodnano 243configure_modelname=ipodnano
243encoder=rbspeex 244encoder=rbspeex
244 245
246[ipodnano2g]
247name="Ipod Nano (2nd gen)"
248buildserver_modelname=ipodnano2g
249bootloadermethod=ipod
250bootloadername=/ipod/bootloader-ipodnano2g.ipodx
251manualname=
252brand=Apple
253configure_modelname=ipodnano2g
254encoder=rbspeex
255
245[ipod4gray] 256[ipod4gray]
246name="Ipod (4th gen, greyscale)" 257name="Ipod (4th gen, greyscale)"
247buildserver_modelname=ipod4gray 258buildserver_modelname=ipod4gray
@@ -527,9 +538,6 @@ usbid=0x04e85024
527configure_modelname=yh925 538configure_modelname=yh925
528encoder=rbspeex 539encoder=rbspeex
529 540
530[05ac1260]
531name="Apple Ipod Nano (Second Generation)"
532
533[05ac1240] 541[05ac1240]
534name="Apple Ipod Nano (Second Generation, DFU Mode)" 542name="Apple Ipod Nano (Second Generation, DFU Mode)"
535 543