ipodpatcher and rbutil support for the Nano2G - FS#10609 with a few further changes.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@23142 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Dave Chapman 2009-10-13 08:02:59 +00:00
parent e486241c01
commit 8e95cc4329
5 changed files with 531 additions and 35 deletions

View file

@ -2,13 +2,26 @@ CFLAGS=-Wall -W
BOOT_H = ipod1g2g.h ipod3g.h ipod4g.h ipodcolor.h ipodmini.h ipodmini2g.h ipodnano.h ipodvideo.h BOOT_H = ipod1g2g.h ipod3g.h ipod4g.h ipodcolor.h ipodmini.h ipodmini2g.h ipodnano.h ipodvideo.h
# Uncomment the next two lines to build with embedded bootloaders and the # Enable the next two lines to build with embedded bootloaders and the
# --install option and interactive mode. You need the full set of Rockbox # --install option and interactive mode. You need the full set of Rockbox
# bootloaders in this directory - download them from # bootloaders in this directory - download them from
# http://download.rockbox.org/bootloader/ipod/bootloaders.zip # http://download.rockbox.org/bootloader/ipod/bootloaders.zip
#BOOTSRC = ipod1g2g.c ipod3g.c ipod4g.c ipodcolor.c ipodmini.c ipodmini2g.c ipodnano.c ipodvideo.c ifdef RELEASE
#CFLAGS += -DWITH_BOOTOBJS CFLAGS+=-DRELEASE
BOOTOBJS=1
endif
ifdef BOOTOBJS
BOOTSRC = ipod1g2g.c ipod3g.c ipod4g.c ipodcolor.c ipodmini.c ipodmini2g.c ipodnano.c ipodvideo.c ipodnano2g.c
CFLAGS += -DWITH_BOOTOBJS
endif
ifndef VERSION
VERSION=$(shell ../../tools/version.sh)
endif
CFLAGS+=-DVERSION=\"$(VERSION)\"
ifeq ($(findstring CYGWIN,$(shell uname)),CYGWIN) ifeq ($(findstring CYGWIN,$(shell uname)),CYGWIN)
OUTPUT=ipodpatcher.exe OUTPUT=ipodpatcher.exe
@ -81,6 +94,9 @@ ipodnano.c: bootloader-ipodnano.ipod ipod2c
ipodvideo.c: bootloader-ipodvideo.ipod ipod2c ipodvideo.c: bootloader-ipodvideo.ipod ipod2c
./ipod2c bootloader-ipodvideo.ipod ipodvideo ./ipod2c bootloader-ipodvideo.ipod ipodvideo
ipodnano2g.c: bootloader-ipodnano2g.ipodx ipod2c
./ipod2c bootloader-ipodnano2g.ipodx ipodnano2g
clean: clean:
rm -f ipodpatcher.exe ipodpatcher-rc.o ipodpatcher-mac ipodpatcher-i386 ipodpatcher-ppc ipodpatcher ipod2c *~ $(BOOTSRC) $(BOOT_H) rm -f ipodpatcher.exe ipodpatcher-rc.o ipodpatcher-mac ipodpatcher-i386 ipodpatcher-ppc ipodpatcher ipod2c *~ $(BOOTSRC) $(BOOT_H)

View file

@ -39,7 +39,8 @@ enum firmwaretype_t {
FTYPE_OSOS = 0, FTYPE_OSOS = 0,
FTYPE_RSRC, FTYPE_RSRC,
FTYPE_AUPD, FTYPE_AUPD,
FTYPE_HIBE FTYPE_HIBE,
FTYPE_OSBK
}; };
struct ipod_directory_t { struct ipod_directory_t {
@ -71,6 +72,7 @@ struct ipod_t {
int num_heads; int num_heads;
struct ipod_directory_t ipod_directory[MAX_IMAGES]; struct ipod_directory_t ipod_directory[MAX_IMAGES];
int nimages; int nimages;
int ososimage;
off_t diroffset; off_t diroffset;
off_t start; /* Offset in bytes of firmware partition from start of disk */ off_t start; /* Offset in bytes of firmware partition from start of disk */
off_t fwoffset; /* Offset in bytes of start of firmware images from start of disk */ off_t fwoffset; /* Offset in bytes of start of firmware images from start of disk */

View file

@ -42,6 +42,7 @@
#include "ipodcolor.h" #include "ipodcolor.h"
#include "ipodnano.h" #include "ipodnano.h"
#include "ipodvideo.h" #include "ipodvideo.h"
#include "ipodnano2g.h"
#endif #endif
#ifndef RBUTIL #ifndef RBUTIL
@ -389,7 +390,7 @@ int write_partition(struct ipod_t* ipod, int infile)
return 0; return 0;
} }
char* ftypename[] = { "OSOS", "RSRC", "AUPD", "HIBE" }; char* ftypename[] = { "OSOS", "RSRC", "AUPD", "HIBE", "OSBK" };
int diskmove(struct ipod_t* ipod, int delta) int diskmove(struct ipod_t* ipod, int delta)
{ {
@ -470,6 +471,409 @@ int diskmove(struct ipod_t* ipod, int delta)
return 0; return 0;
} }
static int rename_image(struct ipod_t* ipod, char* from, char* to)
{
int n;
int x;
int found;
int i;
unsigned char* p;
/* diroffset may not be sector-aligned */
x = ipod->diroffset % ipod->sector_size;
/* Read directory */
if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
return -1;
}
n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
if (n < 0) {
fprintf(stderr,"[ERR] Read of directory failed.\n");
return -1;
}
p = ipod_sectorbuf + x;
/* A hack to detect 2nd gen Nanos - maybe there is a better way? */
if (p[0] == 0)
{
/* Adjust diroffset */
ipod->diroffset += ipod->sector_size - x;
n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
if (n < 0) {
fprintf(stderr,"[ERR] Read of directory failed.\n");
return -1;
}
p = ipod_sectorbuf;
}
found = 0;
for (i=0 ; !found && i < MAX_IMAGES; i++) {
if (memcmp(p + 4, from, 4) == 0) {
memcpy(p + 4, to, 4);
found = 1;
}
p += 40;
}
if (!found) {
fprintf(stderr,"[ERR] Unexpected error - no \"%s\" image!\n", from);
return -1;
}
/* Write directory back to disk */
if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
return -1;
}
n=ipod_write(ipod, ipod_sectorbuf, ipod->sector_size);
if (n < 0) {
fprintf(stderr,"[ERR] Write of directory failed in rename_image.\n");
return -1;
}
return 0;
}
static int delete_image(struct ipod_t* ipod, char* name)
{
int n;
int x;
int found;
int i;
unsigned char* p;
/* diroffset may not be sector-aligned */
x = ipod->diroffset % ipod->sector_size;
/* Read directory */
if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
return -1;
}
n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
if (n < 0) {
fprintf(stderr,"[ERR] Read of directory failed.\n");
return -1;
}
p = ipod_sectorbuf + x;
/* A hack to detect 2nd gen Nanos - maybe there is a better way? */
if (p[0] == 0)
{
/* Adjust diroffset */
ipod->diroffset += ipod->sector_size - x;
n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
if (n < 0) {
fprintf(stderr,"[ERR] Read of directory failed.\n");
return -1;
}
p = ipod_sectorbuf;
}
found = 0;
for (i=0 ; !found && i < MAX_IMAGES; i++) {
if (memcmp(p + 4, name, 4) == 0) {
memset(p, 0, 40); /* Delete directory entry */
found = 1;
}
p += 40;
}
if (!found) {
fprintf(stderr,"[ERR] Unexpected error - no \"%s\" image!\n", name);
return -1;
}
/* Write directory back to disk */
if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
return -1;
}
n=ipod_write(ipod, ipod_sectorbuf, ipod->sector_size);
if (n < 0) {
fprintf(stderr,"[ERR] Write of directory failed in delete_image.\n");
return -1;
}
return 0;
}
int add_new_image(struct ipod_t* ipod, char* imagename, char* filename, int type)
{
int length;
int found;
int i;
int x;
int n;
int infile;
int newsize;
unsigned long chksum=0;
unsigned long filechksum=0;
unsigned long offset;
unsigned char header[8]; /* Header for .ipod file */
unsigned char* p;
#ifdef WITH_BOOTOBJS
if (type == FILETYPE_INTERNAL) {
fprintf(stderr,"[INFO] Using internal bootloader - %d bytes\n",ipod->bootloader_len);
length = ipod->bootloader_len;
infile = -1;
}
else
#endif
{
/* First check that the input file is the correct type for this ipod. */
infile=open(filename,O_RDONLY);
if (infile < 0) {
fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
return -1;
}
if (type==FILETYPE_DOT_IPOD) {
n = read(infile,header,8);
if (n < 8) {
fprintf(stderr,"[ERR] Failed to read header from %s\n",filename);
close(infile);
return -1;
}
if (memcmp(header+4, ipod->modelname,4)!=0) {
fprintf(stderr,"[ERR] Model name in input file (%c%c%c%c) doesn't match ipod model (%s)\n",
header[4],header[5],header[6],header[7], ipod->modelname);
close(infile);
return -1;
}
filechksum = be2int(header);
length = filesize(infile)-8;
} else {
length = filesize(infile);
}
}
newsize=(length+ipod->sector_size-1)&~(ipod->sector_size-1);
fprintf(stderr,"[INFO] Padding input file from 0x%08x to 0x%08x bytes\n",
length,newsize);
if (newsize > BUFFER_SIZE) {
fprintf(stderr,"[ERR] Input file too big for buffer\n");
if (infile >= 0) close(infile);
return -1;
}
/* TODO: Check if we have enough space in the partition for the new image */
#ifdef WITH_BOOTOBJS
if (type == FILETYPE_INTERNAL) {
memcpy(ipod_sectorbuf,ipod->bootloader,ipod->bootloader_len);
}
else
#endif
{
fprintf(stderr,"[INFO] Reading input file...\n");
n = read(infile,ipod_sectorbuf,length);
if (n < 0) {
fprintf(stderr,"[ERR] Couldn't read input file\n");
close(infile);
return -1;
}
close(infile);
}
/* Pad the data with zeros */
memset(ipod_sectorbuf+length,0,newsize-length);
if (type==FILETYPE_DOT_IPOD) {
chksum = ipod->modelnum;
for (i = 0; i < length; i++) {
/* add 8 unsigned bits but keep a 32 bit sum */
chksum += ipod_sectorbuf[i];
}
if (chksum == filechksum) {
fprintf(stderr,"[INFO] Checksum OK in %s\n",filename);
} else {
fprintf(stderr,"[ERR] Checksum in %s failed check\n",filename);
return -1;
}
}
offset = ipod->fwoffset + ipod->ipod_directory[ipod->nimages - 1].devOffset +
ipod->ipod_directory[ipod->nimages - 1].len + ipod->sector_size;
/* 2nd Gen Nano has encrypted firmware, and the sector
preceeding the firmware contains hashes that need to be
preserved. Nano 2G images include these extra 2048 (0x800)
bytes
*/
if (ipod_seek(ipod, offset - (ipod->modelnum == 62 ? 0x800 : 0)) < 0) {
fprintf(stderr,"[ERR] Seek failed\n");
return -1;
}
if ((n = ipod_write(ipod,ipod_sectorbuf,newsize)) < 0) {
perror("[ERR] Write failed\n");
return -1;
}
if (n < newsize) {
fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n"
,newsize,n);
return -1;
}
fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n);
/* Now we need to create a new directory entry
NOTE: On the Nano 2G, the checksum is the checksum of the
unencrypted firmware. But this isn't checked by the NOR
bootloader (there are cryptographic hashes in the
firmware itself), so it doesn't matter that this is
wrong.
*/
chksum = 0;
for (i = 0; i < length; i++) {
/* add 8 unsigned bits but keep a 32 bit sum */
chksum += ipod_sectorbuf[i];
}
x = ipod->diroffset % ipod->sector_size;
/* Read directory */
if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
if (n < 0) { return -1; }
/* Create a new directory entry */
/* Copy OSOS or OSBK details - we assume one of them exists */
p = ipod_sectorbuf + x;
found = 0;
for (i = 0; !found && i < ipod->nimages; i++) {
if ((memcmp(p + 4, "soso", 4)==0) || (memcmp(p + 4, "kbso", 4)==0)) {
found = 1;
} else {
p += 40;
}
}
if (!found) {
fprintf(stderr,"[ERR] No OSOS or OSBK image to copy directory from\n");
return -1;
}
/* Copy directory image */
memcpy(ipod_sectorbuf + x + (ipod->nimages * 40), p, 40);
p = ipod_sectorbuf + x + (ipod->nimages * 40);
/* Modify directory. */
memcpy(p + 4, imagename, 4);
int2le(offset - ipod->fwoffset, p + 12); /* devOffset */
int2le(length - (ipod->modelnum==62 ? 0x800: 0), p + 16); /* len */
int2le(chksum, p + 28); /* checksum */
/* Write directory */
if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
n=ipod_write(ipod, ipod_sectorbuf, ipod->sector_size);
if (n < 0) { return -1; }
return 0;
}
/*
Bootloader installation on the Nano2G consists of renaming the
OSOS image to OSBK and then writing the Rockbox bootloader as a
new OSOS image.
Maybe this approach can/should be adapted for other ipods, as it
prevents the Apple bootloader loading the original firmware into
RAM along with the Rockbox bootloader (and hence will give a
faster boot when the user just wants to start Rockbox).
*/
static int add_bootloader_nano2g(struct ipod_t* ipod, char* filename, int type)
{
int i;
int has_osbk = 0;
/* Check if we already have an OSBK image */
for (i = 0; i < ipod->nimages; i++) {
if (ipod->ipod_directory[i].ftype==FTYPE_OSBK) {
has_osbk = 1;
}
}
if (has_osbk == 0) {
/* First-time install - rename OSOS to OSBK and create new OSOS for bootloader */
fprintf(stderr,"[INFO] Creating OSBK backup image of original firmware\n");
if (rename_image(ipod, "soso", "kbso") < 0) {
fprintf(stderr,"[ERR] Could not rename OSOS image\n");
return -1;
}
/* Add our bootloader as a brand new image */
return add_new_image(ipod, "soso", filename, type);
} else {
/* This is an update, just replace OSOS with our bootloader */
return write_firmware(ipod, filename, type);
}
}
static int delete_bootloader_nano2g(struct ipod_t* ipod)
{
int i;
int has_osbk = 0;
/* Check if we have an OSBK image */
for (i = 0; i < ipod->nimages; i++) {
if (ipod->ipod_directory[i].ftype==FTYPE_OSBK) {
has_osbk = 1;
}
}
if (has_osbk == 0) {
fprintf(stderr,"[ERR] No OSBK image found - nothing to uninstall\n");
return -1;
} else {
/* Delete our bootloader image */
if (delete_image(ipod, "soso") < 0) {
fprintf(stderr,"[WARN] Could not delete OSOS image\n");
} else {
fprintf(stderr,"[INFO] OSOS image deleted\n");
}
if (rename_image(ipod, "kbso", "soso") < 0) {
fprintf(stderr,"[ERR] Could not rename OSBK image\n");
return -1;
}
fprintf(stderr,"[INFO] OSBK image renamed to OSOS - bootloader uninstalled.\n");
return 0;
}
}
int add_bootloader(struct ipod_t* ipod, char* filename, int type) int add_bootloader(struct ipod_t* ipod, char* filename, int type)
{ {
int length; int length;
@ -485,6 +889,11 @@ int add_bootloader(struct ipod_t* ipod, char* filename, int type)
unsigned char header[8]; /* Header for .ipod file */ unsigned char header[8]; /* Header for .ipod file */
unsigned char* bootloader_buf; unsigned char* bootloader_buf;
/* The 2nd gen Nano is installed differently */
if (ipod->modelnum == 62) {
return add_bootloader_nano2g(ipod, filename, type);
}
/* Calculate the position in the OSOS image where our bootloader will go. */ /* Calculate the position in the OSOS image where our bootloader will go. */
if (ipod->ipod_directory[0].entryOffset>0) { if (ipod->ipod_directory[0].entryOffset>0) {
/* Keep the same entryOffset */ /* Keep the same entryOffset */
@ -698,6 +1107,11 @@ int delete_bootloader(struct ipod_t* ipod)
int n; int n;
unsigned long chksum=0; /* 32 bit checksum - Rockbox .ipod style*/ unsigned long chksum=0; /* 32 bit checksum - Rockbox .ipod style*/
/* The 2nd gen Nano is installed differently */
if (ipod->modelnum == 62) {
return delete_bootloader_nano2g(ipod);
}
/* Removing the bootloader involves adjusting the "length", /* Removing the bootloader involves adjusting the "length",
"chksum" and "entryOffset" values in the osos image's directory "chksum" and "entryOffset" values in the osos image's directory
entry. */ entry. */
@ -774,7 +1188,9 @@ int write_firmware(struct ipod_t* ipod, char* filename, int type)
int bytesavailable; int bytesavailable;
unsigned long chksum=0; unsigned long chksum=0;
unsigned long filechksum=0; unsigned long filechksum=0;
unsigned long offset;
unsigned char header[8]; /* Header for .ipod file */ unsigned char header[8]; /* Header for .ipod file */
unsigned char* p;
#ifdef WITH_BOOTOBJS #ifdef WITH_BOOTOBJS
if (type == FILETYPE_INTERNAL) { if (type == FILETYPE_INTERNAL) {
@ -876,7 +1292,23 @@ int write_firmware(struct ipod_t* ipod, char* filename, int type)
} }
} }
if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) {
offset = ipod->fwoffset+ipod->ipod_directory[ipod->ososimage].devOffset;
if (ipod->modelnum==62) {
/* 2nd Gen Nano has encrypted firmware, and the sector
preceeding the firmware contains hashes that need to be
preserved. Nano 2G images include these extra 2048 (0x800)
bytes
*/
offset -= 0x800;
/* TODO: The above checks need to take into account this 0x800 bytes */
}
if (ipod_seek(ipod, offset) < 0) {
fprintf(stderr,"[ERR] Seek failed\n"); fprintf(stderr,"[ERR] Seek failed\n");
return -1; return -1;
} }
@ -893,7 +1325,14 @@ int write_firmware(struct ipod_t* ipod, char* filename, int type)
} }
fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n); fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n);
/* Now we need to update the "len", "entryOffset" and "chksum" fields */ /* Now we need to update the "len", "entryOffset" and "chksum" fields
NOTE: On the Nano 2G, the checksum is the checksum of the
unencrypted firmware. But this isn't checked by the NOR
bootloader (there are cryptographic hashes in the
firmware itself), so it doesn't matter that this is
wrong.
*/
chksum = 0; chksum = 0;
for (i = 0; i < length; i++) { for (i = 0; i < length; i++) {
/* add 8 unsigned bits but keep a 32 bit sum */ /* 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)
n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size); n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
if (n < 0) { return -1; } if (n < 0) { return -1; }
/* Update entries for image 0 */ /* Update entries for image */
int2le(length,ipod_sectorbuf+x+16); p = ipod_sectorbuf + x + (ipod->ososimage * 40);
int2le(0,ipod_sectorbuf+x+24); int2le(length - (ipod->modelnum==62 ? 0x800: 0), p + 16);
int2le(chksum,ipod_sectorbuf+x+28); int2le(0, p + 24);
int2le(chksum, p + 28);
/* Write directory */ /* Write directory */
if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; } 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)
int i; int i;
int outfile; int outfile;
int n; int n;
unsigned long offset;
unsigned long chksum=0; /* 32 bit checksum - Rockbox .ipod style*/ unsigned long chksum=0; /* 32 bit checksum - Rockbox .ipod style*/
unsigned char header[8]; /* Header for .ipod file */ unsigned char header[8]; /* Header for .ipod file */
if (ipod->ipod_directory[0].entryOffset != 0) { if (ipod->ipod_directory[ipod->ososimage].entryOffset != 0) {
/* We have a bootloader... */ /* We have a bootloader... */
length = ipod->ipod_directory[0].entryOffset; length = ipod->ipod_directory[ipod->ososimage].entryOffset;
} else { } else {
length = ipod->ipod_directory[0].len; length = ipod->ipod_directory[ipod->ososimage].len;
} }
fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length); fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length);
if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) { offset = ipod->fwoffset + ipod->ipod_directory[ipod->ososimage].devOffset;
return -1;
}
i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1); i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1);
fprintf(stderr,"[INFO] Padding read from 0x%08x to 0x%08x bytes\n", fprintf(stderr,"[INFO] Padding read from 0x%08x to 0x%08x bytes\n",
length,i); length,i);
if (ipod->modelnum==62) {
/* 2nd Gen Nano has encrypted firmware, and we need to dump the
sector preceeding the image - it contains hashes */
offset -= 0x800;
length += 0x800;
i += 0x800;
}
if (ipod_seek(ipod, offset)) {
return -1;
}
if ((n = ipod_read(ipod,ipod_sectorbuf,i)) < 0) { if ((n = ipod_read(ipod,ipod_sectorbuf,i)) < 0) {
return -1; return -1;
} }
@ -1049,6 +1499,9 @@ int read_directory(struct ipod_t* ipod)
/* A hack to detect 2nd gen Nanos - maybe there is a better way? */ /* A hack to detect 2nd gen Nanos - maybe there is a better way? */
if (p[0] == 0) if (p[0] == 0)
{ {
/* Adjust diroffset */
ipod->diroffset += ipod->sector_size - x;
n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size); n=ipod_read(ipod, ipod_sectorbuf, ipod->sector_size);
if (n < 0) { if (n < 0) {
fprintf(stderr,"[ERR] Read of directory failed.\n"); fprintf(stderr,"[ERR] Read of directory failed.\n");
@ -1057,15 +1510,19 @@ int read_directory(struct ipod_t* ipod)
p = ipod_sectorbuf; p = ipod_sectorbuf;
} }
ipod->ososimage = -1;
while ((ipod->nimages < MAX_IMAGES) && (p < (ipod_sectorbuf + x + 400)) && while ((ipod->nimages < MAX_IMAGES) && (p < (ipod_sectorbuf + x + 400)) &&
((memcmp(p,"!ATA",4)==0) || (memcmp(p,"DNAN",4)==0))) { ((memcmp(p,"!ATA",4)==0) || (memcmp(p,"DNAN",4)==0))) {
p+=4; p+=4;
if (memcmp(p,"soso",4)==0) { if (memcmp(p,"soso",4)==0) {
ipod->ipod_directory[ipod->nimages].ftype=FTYPE_OSOS; ipod->ipod_directory[ipod->nimages].ftype=FTYPE_OSOS;
ipod->ososimage = ipod->nimages;
} else if (memcmp(p,"crsr",4)==0) { } else if (memcmp(p,"crsr",4)==0) {
ipod->ipod_directory[ipod->nimages].ftype=FTYPE_RSRC; ipod->ipod_directory[ipod->nimages].ftype=FTYPE_RSRC;
} else if (memcmp(p,"dpua",4)==0) { } else if (memcmp(p,"dpua",4)==0) {
ipod->ipod_directory[ipod->nimages].ftype=FTYPE_AUPD; ipod->ipod_directory[ipod->nimages].ftype=FTYPE_AUPD;
} else if (memcmp(p,"kbso",4)==0) {
ipod->ipod_directory[ipod->nimages].ftype=FTYPE_OSBK;
} else if (memcmp(p,"ebih",4)==0) { } else if (memcmp(p,"ebih",4)==0) {
ipod->ipod_directory[ipod->nimages].ftype=FTYPE_HIBE; ipod->ipod_directory[ipod->nimages].ftype=FTYPE_HIBE;
} else { } else {
@ -1092,12 +1549,17 @@ int read_directory(struct ipod_t* ipod)
ipod->nimages++; ipod->nimages++;
} }
if (ipod->ososimage < 0) {
fprintf(stderr,"[ERR] No OSOS image found.\n");
return -1;
}
if ((ipod->nimages > 1) && (version==2)) { if ((ipod->nimages > 1) && (version==2)) {
/* The 3g firmware image doesn't appear to have a version, so /* The 3g firmware image doesn't appear to have a version, so
let's make one up... Note that this is never written back to the let's make one up... Note that this is never written back to the
ipod, so it's OK to do. */ ipod, so it's OK to do. */
if (ipod->ipod_directory[0].vers == 0) { ipod->ipod_directory[0].vers = 3; } if (ipod->ipod_directory[ipod->ososimage].vers == 0) { ipod->ipod_directory[ipod->ososimage].vers = 3; }
ipod->fwoffset = ipod->start; ipod->fwoffset = ipod->start;
} else { } else {
@ -1247,11 +1709,12 @@ int getmodel(struct ipod_t* ipod, int ipod_version)
break; break;
case 0x100: case 0x100:
ipod->modelstr="2nd Generation Nano"; ipod->modelstr="2nd Generation Nano";
ipod->modelnum = 0; ipod->modelnum = 62;
ipod->targetname = NULL; ipod->modelname = "nn2x";
ipod->targetname = "ipodnano2g";
#ifdef WITH_BOOTOBJS #ifdef WITH_BOOTOBJS
ipod->bootloader = NULL; ipod->bootloader = ipodnano2g;
ipod->bootloader_len = 0; ipod->bootloader_len = LEN_ipodnano2g;
#endif #endif
break; break;
default: default:
@ -1316,7 +1779,7 @@ int ipod_scan(struct ipod_t* ipod)
continue; continue;
} }
ipod_version=(ipod->ipod_directory[0].vers>>8); ipod_version=(ipod->ipod_directory[ipod->ososimage].vers>>8);
/* Windows requires the ipod in R/W mode for SCSI Inquiry */ /* Windows requires the ipod in R/W mode for SCSI Inquiry */
ipod->ramsize = 0; ipod->ramsize = 0;
ipod_reopen_rw(ipod); ipod_reopen_rw(ipod);

View file

@ -31,7 +31,11 @@
#include "ipodpatcher.h" #include "ipodpatcher.h"
#include "ipodio.h" #include "ipodio.h"
#define VERSION "3.0 with v3.0 bootloaders" #ifdef RELEASE
#undef VERSION
#define VERSION "4.0 with v3.0 bootloaders (v1.0 for 2nd Gen Nano)"
#endif
enum { enum {
NONE, NONE,
@ -80,14 +84,14 @@ void print_usage(void)
fprintf(stderr," -l, --list\n"); fprintf(stderr," -l, --list\n");
fprintf(stderr," -r, --read-partition bootpartition.bin\n"); fprintf(stderr," -r, --read-partition bootpartition.bin\n");
fprintf(stderr," -w, --write-partition bootpartition.bin\n"); fprintf(stderr," -w, --write-partition bootpartition.bin\n");
fprintf(stderr," -rf, --read-firmware filename.ipod\n"); fprintf(stderr," -rf, --read-firmware filename.ipod[x]\n");
fprintf(stderr," -rfb, --read-firmware-bin filename.bin\n"); fprintf(stderr," -rfb, --read-firmware-bin filename.bin\n");
fprintf(stderr," -wf, --write-firmware filename.ipod\n"); fprintf(stderr," -wf, --write-firmware filename.ipod[x]\n");
fprintf(stderr," -wfb, --write-firmware-bin filename.bin\n"); fprintf(stderr," -wfb, --write-firmware-bin filename.bin\n");
#ifdef WITH_BOOTOBJS #ifdef WITH_BOOTOBJS
fprintf(stderr," -we, --write-embedded\n"); fprintf(stderr," -we, --write-embedded\n");
#endif #endif
fprintf(stderr," -a, --add-bootloader filename.ipod\n"); fprintf(stderr," -a, --add-bootloader filename.ipod[x]\n");
fprintf(stderr," -ab, --add-bootloader-bin filename.bin\n"); fprintf(stderr," -ab, --add-bootloader-bin filename.bin\n");
fprintf(stderr," -d, --delete-bootloader\n"); fprintf(stderr," -d, --delete-bootloader\n");
fprintf(stderr," -f, --format\n"); fprintf(stderr," -f, --format\n");
@ -97,6 +101,8 @@ void print_usage(void)
fprintf(stderr," -x --dump-xml filename.xml\n"); fprintf(stderr," -x --dump-xml filename.xml\n");
fprintf(stderr,"\n"); fprintf(stderr,"\n");
fprintf(stderr,"The .ipodx extension is used for encrypted images for the 2nd Gen Nano.\n\n");
#ifdef __WIN32__ #ifdef __WIN32__
fprintf(stderr,"DISKNO is the number (e.g. 2) Windows has assigned to your ipod's hard disk.\n"); fprintf(stderr,"DISKNO is the number (e.g. 2) Windows has assigned to your ipod's hard disk.\n");
fprintf(stderr,"The first hard disk in your computer (i.e. C:\\) will be disk 0, the next disk\n"); 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[])
int type; int type;
struct ipod_t ipod; struct ipod_t ipod;
fprintf(stderr,"ipodpatcher v" VERSION " - (C) Dave Chapman 2006-2007\n"); fprintf(stderr,"ipodpatcher " VERSION "\n");
fprintf(stderr,"(C) Dave Chapman 2006-2009\n");
fprintf(stderr,"This is free software; see the source for copying conditions. There is NO\n"); fprintf(stderr,"This is free software; see the source for copying conditions. There is NO\n");
fprintf(stderr,"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"); fprintf(stderr,"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n");
@ -364,9 +371,9 @@ int main(int argc, char* argv[])
return 1; return 1;
} }
if (getmodel(&ipod,(ipod.ipod_directory[0].vers>>8)) < 0) { if (getmodel(&ipod,(ipod.ipod_directory[ipod.ososimage].vers>>8)) < 0) {
fprintf(stderr,"[ERR] Unknown version number in firmware (%08x)\n", fprintf(stderr,"[ERR] Unknown version number in firmware (%08x)\n",
ipod.ipod_directory[0].vers); ipod.ipod_directory[ipod.ososimage].vers);
return -1; return -1;
} }
@ -391,7 +398,7 @@ int main(int argc, char* argv[])
if (ipod.ramsize > 0) { printf("(%dMB RAM) ",ipod.ramsize); } if (ipod.ramsize > 0) { printf("(%dMB RAM) ",ipod.ramsize); }
printf("(\"%s\")\n",ipod.macpod ? "macpod" : "winpod"); printf("(\"%s\")\n",ipod.macpod ? "macpod" : "winpod");
if (ipod.ipod_directory[0].vers == 0x10000) { if (ipod.ipod_directory[ipod.ososimage].vers == 0x10000) {
fprintf(stderr,"[ERR] *** ipodpatcher does not support the 2nd Generation Nano! ***\n"); fprintf(stderr,"[ERR] *** ipodpatcher does not support the 2nd Generation Nano! ***\n");
#ifdef WITH_BOOTOBJS #ifdef WITH_BOOTOBJS
printf("Press ENTER to exit ipodpatcher :"); printf("Press ENTER to exit ipodpatcher :");

View file

@ -39,6 +39,7 @@ platform25=ipodvideo64mb
platform26=ipodmini1g platform26=ipodmini1g
platform27=ipodmini2g platform27=ipodmini2g
platform28=ipodnano platform28=ipodnano
platform29=ipodnano2g
platform30=iaudiox5 platform30=iaudiox5
platform31=iaudiom5 platform31=iaudiom5
platform32=iaudiox5v platform32=iaudiox5v
@ -242,6 +243,16 @@ brand=Apple
configure_modelname=ipodnano configure_modelname=ipodnano
encoder=rbspeex encoder=rbspeex
[ipodnano2g]
name="Ipod Nano (2nd gen)"
buildserver_modelname=ipodnano2g
bootloadermethod=ipod
bootloadername=/ipod/bootloader-ipodnano2g.ipodx
manualname=
brand=Apple
configure_modelname=ipodnano2g
encoder=rbspeex
[ipod4gray] [ipod4gray]
name="Ipod (4th gen, greyscale)" name="Ipod (4th gen, greyscale)"
buildserver_modelname=ipod4gray buildserver_modelname=ipod4gray
@ -527,9 +538,6 @@ usbid=0x04e85024
configure_modelname=yh925 configure_modelname=yh925
encoder=rbspeex encoder=rbspeex
[05ac1260]
name="Apple Ipod Nano (Second Generation)"
[05ac1240] [05ac1240]
name="Apple Ipod Nano (Second Generation, DFU Mode)" name="Apple Ipod Nano (Second Generation, DFU Mode)"