blob: 55f501dc6c1ed9c668be5e1ef2ec779cd7b2d387 [file] [log] [blame]
Dave Chapman45895df2006-12-13 08:57:06 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
Dave Chapmane332f4c2007-02-05 01:20:20 +000010 * Copyright (C) 2006-2007 Dave Chapman
Dave Chapman45895df2006-12-13 08:57:06 +000011 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000012 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
Dave Chapman45895df2006-12-13 08:57:06 +000016 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include <stdio.h>
23#include <unistd.h>
24#include <fcntl.h>
25#include <string.h>
26#include <stdlib.h>
Dave Chapman4b7e1e02006-12-13 09:02:18 +000027#include <inttypes.h>
Dave Chapman6e797152007-09-08 23:27:49 +000028#include <stdbool.h>
Dave Chapman45895df2006-12-13 08:57:06 +000029#include <sys/types.h>
30#include <sys/stat.h>
Dave Chapman45895df2006-12-13 08:57:06 +000031
32#include "parttypes.h"
Dave Chapman4b7e1e02006-12-13 09:02:18 +000033#include "ipodio.h"
Dave Chapman79a1fb12007-02-08 23:57:41 +000034#include "ipodpatcher.h"
Dave Chapman4b7e1e02006-12-13 09:02:18 +000035
Dave Chapmanbdc27ff2007-02-08 18:05:50 +000036#ifdef WITH_BOOTOBJS
Dave Chapman6a20def2007-07-26 20:21:11 +000037#include "ipod1g2g.h"
Dave Chapmanbdc27ff2007-02-08 18:05:50 +000038#include "ipod3g.h"
39#include "ipod4g.h"
Björn Stenbergc0740442009-12-07 12:19:08 +000040#include "ipodmini1g.h"
Dave Chapmanbdc27ff2007-02-08 18:05:50 +000041#include "ipodmini2g.h"
42#include "ipodcolor.h"
Björn Stenbergc0740442009-12-07 12:19:08 +000043#include "ipodnano1g.h"
Dave Chapmanbdc27ff2007-02-08 18:05:50 +000044#include "ipodvideo.h"
Dave Chapman8e95cc42009-10-13 08:02:59 +000045#include "ipodnano2g.h"
Dave Chapmanbdc27ff2007-02-08 18:05:50 +000046#endif
47
Dave Chapman6e797152007-09-08 23:27:49 +000048#ifndef RBUTIL
49#include "arc4.h"
50#endif
51
Dominik Riebelingd131a312008-06-17 17:52:13 +000052int ipod_verbose = 0;
Dave Chapman4b7e1e02006-12-13 09:02:18 +000053
Dave Chapman4b7e1e02006-12-13 09:02:18 +000054
55/* The following string appears at the start of the firmware partition */
56static const char *apple_stop_sign = "{{~~ /-----\\ "\
57 "{{~~ / \\ "\
58 "{{~~| | "\
59 "{{~~| S T O P | "\
60 "{{~~| | "\
61 "{{~~ \\ / "\
62 "{{~~ \\-----/ "\
63 "Copyright(C) 200"\
64 "1 Apple Computer"\
65 ", Inc.----------"\
66 "----------------"\
67 "----------------"\
68 "----------------"\
69 "----------------"\
70 "----------------"\
71 "---------------";
72
Dave Chapman45895df2006-12-13 08:57:06 +000073/* Windows requires the buffer for disk I/O to be aligned in memory on a
74 multiple of the disk volume size - so we use a single global variable
Dave Chapman4b7e1e02006-12-13 09:02:18 +000075 and initialise it with ipod_alloc_buf()
Dave Chapman45895df2006-12-13 08:57:06 +000076*/
Dave Chapman4b7e1e02006-12-13 09:02:18 +000077
Dave Chapman45895df2006-12-13 08:57:06 +000078char* get_parttype(int pt)
79{
80 int i;
81 static char unknown[]="Unknown";
82
Dave Chapman2cc80f52007-07-29 21:19:14 +000083 if (pt == PARTTYPE_HFS) {
Dave Chapman6e641e82007-02-05 18:29:39 +000084 return "HFS/HFS+";
85 }
86
Dave Chapman45895df2006-12-13 08:57:06 +000087 i=0;
88 while (parttypes[i].name != NULL) {
89 if (parttypes[i].type == pt) {
90 return (parttypes[i].name);
91 }
92 i++;
93 }
94
95 return unknown;
96}
97
Dave Chapman45895df2006-12-13 08:57:06 +000098off_t filesize(int fd) {
99 struct stat buf;
100
101 if (fstat(fd,&buf) < 0) {
102 perror("[ERR] Checking filesize of input file");
103 return -1;
104 } else {
105 return(buf.st_size);
106 }
107}
108
Dave Chapman45895df2006-12-13 08:57:06 +0000109/* Partition table parsing code taken from Rockbox */
110
Dave Chapman206238d2006-12-13 08:59:07 +0000111#define MAX_SECTOR_SIZE 2048
Dave Chapman45895df2006-12-13 08:57:06 +0000112#define SECTOR_SIZE 512
113
Dave Chapman2cc80f52007-07-29 21:19:14 +0000114static inline unsigned short le2ushort(unsigned char* buf)
Dave Chapman31aa4522007-02-04 11:42:11 +0000115{
116 unsigned short res = (buf[1] << 8) | buf[0];
117
118 return res;
119}
Dave Chapman45895df2006-12-13 08:57:06 +0000120
Dave Chapman2cc80f52007-07-29 21:19:14 +0000121static inline int le2int(unsigned char* buf)
Dave Chapman4b7e1e02006-12-13 09:02:18 +0000122{
123 int32_t res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
124
125 return res;
126}
127
Dave Chapman2cc80f52007-07-29 21:19:14 +0000128static inline int be2int(unsigned char* buf)
Dave Chapmanc5e30e12006-12-14 01:24:05 +0000129{
130 int32_t res = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
131
132 return res;
133}
134
Dave Chapman2cc80f52007-07-29 21:19:14 +0000135static inline int getint16le(char* buf)
Dave Chapman4b7e1e02006-12-13 09:02:18 +0000136{
137 int16_t res = (buf[1] << 8) | buf[0];
138
139 return res;
140}
141
Dave Chapman2cc80f52007-07-29 21:19:14 +0000142static inline void short2le(unsigned short val, unsigned char* addr)
Dave Chapmanc5e30e12006-12-14 01:24:05 +0000143{
144 addr[0] = val & 0xFF;
145 addr[1] = (val >> 8) & 0xff;
146}
147
Dave Chapman2cc80f52007-07-29 21:19:14 +0000148static inline void int2le(unsigned int val, unsigned char* addr)
Dave Chapmanc5e30e12006-12-14 01:24:05 +0000149{
150 addr[0] = val & 0xFF;
151 addr[1] = (val >> 8) & 0xff;
152 addr[2] = (val >> 16) & 0xff;
153 addr[3] = (val >> 24) & 0xff;
154}
155
Dave Chapman2cc80f52007-07-29 21:19:14 +0000156static inline void int2be(unsigned int val, unsigned char* addr)
Dave Chapmanc5e30e12006-12-14 01:24:05 +0000157{
158 addr[0] = (val >> 24) & 0xff;
159 addr[1] = (val >> 16) & 0xff;
160 addr[2] = (val >> 8) & 0xff;
161 addr[3] = val & 0xFF;
162}
Dave Chapman4b7e1e02006-12-13 09:02:18 +0000163
164
165#define BYTES2INT32(array,pos)\
166 ((long)array[pos] | ((long)array[pos+1] << 8 ) |\
Dave Chapman45895df2006-12-13 08:57:06 +0000167 ((long)array[pos+2] << 16 ) | ((long)array[pos+3] << 24 ))
168
Dave Chapman31aa4522007-02-04 11:42:11 +0000169int read_partinfo(struct ipod_t* ipod, int silent)
Dave Chapman45895df2006-12-13 08:57:06 +0000170{
171 int i;
Dave Chapman45895df2006-12-13 08:57:06 +0000172 unsigned long count;
173
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100174 if(ipod->sectorbuf == NULL) {
175 fprintf(stderr,"[ERR] Buffer not initialized.");
176 return -1;
177 }
178
179 count = ipod_read(ipod,ipod->sector_size);
Dave Chapman4b7e1e02006-12-13 09:02:18 +0000180
181 if (count <= 0) {
Dominik Riebeling3e489c12009-11-08 13:38:10 +0000182 ipod_print_error(" Error reading from disk: ");
Dave Chapman45895df2006-12-13 08:57:06 +0000183 return -1;
184 }
185
Dave Chapman35735c662007-07-27 20:51:36 +0000186 memset(ipod->pinfo, 0, sizeof(ipod->pinfo));
187
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100188 if ((ipod->sectorbuf[510] == 0x55) && (ipod->sectorbuf[511] == 0xaa)) {
Dave Chapman6e641e82007-02-05 18:29:39 +0000189 /* DOS partition table */
Dave Chapman6e641e82007-02-05 18:29:39 +0000190 ipod->macpod = 0;
191 /* parse partitions */
192 for ( i = 0; i < 4; i++ ) {
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100193 unsigned char* ptr = ipod->sectorbuf + 0x1be + 16*i;
Dave Chapman6e641e82007-02-05 18:29:39 +0000194 ipod->pinfo[i].type = ptr[4];
195 ipod->pinfo[i].start = BYTES2INT32(ptr, 8);
196 ipod->pinfo[i].size = BYTES2INT32(ptr, 12);
197
198 /* extended? */
199 if ( ipod->pinfo[i].type == 5 ) {
200 /* not handled yet */
201 }
202 }
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100203 } else if ((ipod->sectorbuf[0] == 'E') && (ipod->sectorbuf[1] == 'R')) {
Dave Chapman6e641e82007-02-05 18:29:39 +0000204 /* Apple Partition Map */
205
206 /* APM parsing code based on the check_mac_partitions() function in
207 ipodloader2 - written by Thomas Tempelmann and released
208 under the GPL. */
209
210 int blkNo = 1;
211 int partBlkCount = 1;
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100212 int partBlkSizMul = ipod->sectorbuf[2] / 2;
Dave Chapman6e641e82007-02-05 18:29:39 +0000213
214 int pmMapBlkCnt; /* # of blks in partition map */
215 int pmPyPartStart; /* physical start blk of partition */
216 int pmPartBlkCnt; /* # of blks in this partition */
217 int i = 0;
218
219 ipod->macpod = 1;
220
221 memset(ipod->pinfo,0,sizeof(ipod->pinfo));
222
223 while (blkNo <= partBlkCount) {
224 if (ipod_seek(ipod, blkNo * partBlkSizMul * 512) < 0) {
225 fprintf(stderr,"[ERR] Seek failed whilst reading APM\n");
226 return -1;
227 }
228
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100229 count = ipod_read(ipod, ipod->sector_size);
Dave Chapman6e641e82007-02-05 18:29:39 +0000230
231 if (count <= 0) {
Dominik Riebeling3e489c12009-11-08 13:38:10 +0000232 ipod_print_error(" Error reading from disk: ");
Dave Chapman6e641e82007-02-05 18:29:39 +0000233 return -1;
234 }
235
236 /* see if it's a partition entry */
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100237 if ((ipod->sectorbuf[0] != 'P') || (ipod->sectorbuf[1] != 'M')) {
Dave Chapman6e641e82007-02-05 18:29:39 +0000238 /* end of partition table -> leave the loop */
239 break;
240 }
241
242 /* Extract the interesting entries */
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100243 pmMapBlkCnt = be2int(ipod->sectorbuf + 4);
244 pmPyPartStart = be2int(ipod->sectorbuf + 8);
245 pmPartBlkCnt = be2int(ipod->sectorbuf + 12);
Dave Chapman6e641e82007-02-05 18:29:39 +0000246
247 /* update the number of part map blocks */
248 partBlkCount = pmMapBlkCnt;
249
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100250 if (strncmp((char*)(ipod->sectorbuf + 48), "Apple_MDFW", 32)==0) {
Dave Chapman6e641e82007-02-05 18:29:39 +0000251 /* A Firmware partition */
252 ipod->pinfo[i].start = pmPyPartStart;
253 ipod->pinfo[i].size = pmPartBlkCnt;
254 ipod->pinfo[i].type = 0;
255 i++;
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100256 } else if (strncmp((char*)(ipod->sectorbuf + 48), "Apple_HFS", 32)==0) {
Dave Chapman6e641e82007-02-05 18:29:39 +0000257 /* A HFS partition */
258 ipod->pinfo[i].start = pmPyPartStart;
259 ipod->pinfo[i].size = pmPartBlkCnt;
Dave Chapman2cc80f52007-07-29 21:19:14 +0000260 ipod->pinfo[i].type = PARTTYPE_HFS;
Dave Chapman6e641e82007-02-05 18:29:39 +0000261 i++;
262 }
263
264 blkNo++; /* read next partition map entry */
265 }
266 } else {
Dave Chapman57b84b62006-12-17 23:00:15 +0000267 if (!silent) fprintf(stderr,"[ERR] Bad boot sector signature\n");
Dave Chapmanc5e30e12006-12-14 01:24:05 +0000268 return -1;
Dave Chapman45895df2006-12-13 08:57:06 +0000269 }
270
Dave Chapman4df0c772007-05-22 19:07:45 +0000271 /* Check that the partition table looks like an ipod:
272 1) Partition 1 is of type 0 (Empty) but isn't empty.
Dave Chapman0fba85f2007-06-10 22:47:51 +0000273 2) Partition 2 is of type 0xb or 0xc (winpod) or -1 (macpod)
Dave Chapman4df0c772007-05-22 19:07:45 +0000274 */
275 if ((ipod->pinfo[0].type != 0) || (ipod->pinfo[0].size == 0) ||
Dave Chapman0fba85f2007-06-10 22:47:51 +0000276 ((ipod->pinfo[1].type != 0xb) && (ipod->pinfo[1].type != 0xc) &&
Dave Chapman2cc80f52007-07-29 21:19:14 +0000277 (ipod->pinfo[1].type != PARTTYPE_HFS))) {
Dave Chapman4df0c772007-05-22 19:07:45 +0000278 if (!silent) fprintf(stderr,"[ERR] Partition layout is not an ipod\n");
279 return -1;
280 }
281
Dave Chapman31aa4522007-02-04 11:42:11 +0000282 ipod->start = ipod->pinfo[0].start*ipod->sector_size;
Dave Chapman45895df2006-12-13 08:57:06 +0000283 return 0;
284}
285
Dave Chapman31aa4522007-02-04 11:42:11 +0000286int read_partition(struct ipod_t* ipod, int outfile)
Dave Chapman45895df2006-12-13 08:57:06 +0000287{
288 int res;
Dave Chapman2cc80f52007-07-29 21:19:14 +0000289 ssize_t n;
Dave Chapman45895df2006-12-13 08:57:06 +0000290 int bytesleft;
291 int chunksize;
Dave Chapman31aa4522007-02-04 11:42:11 +0000292 int count = ipod->pinfo[0].size;
Dave Chapman45895df2006-12-13 08:57:06 +0000293
Dave Chapman31aa4522007-02-04 11:42:11 +0000294 if (ipod_seek(ipod, ipod->start) < 0) {
Dave Chapman45895df2006-12-13 08:57:06 +0000295 return -1;
296 }
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100297 if(ipod->sectorbuf == NULL) {
298 fprintf(stderr,"[ERR] Buffer not initialized.");
299 return -1;
300 }
Dave Chapman45895df2006-12-13 08:57:06 +0000301
Dave Chapman31aa4522007-02-04 11:42:11 +0000302 fprintf(stderr,"[INFO] Writing %d sectors to output file\n",count);
Dave Chapman45895df2006-12-13 08:57:06 +0000303
Dave Chapman31aa4522007-02-04 11:42:11 +0000304 bytesleft = count * ipod->sector_size;
Dave Chapman45895df2006-12-13 08:57:06 +0000305 while (bytesleft > 0) {
306 if (bytesleft > BUFFER_SIZE) {
307 chunksize = BUFFER_SIZE;
308 } else {
309 chunksize = bytesleft;
310 }
311
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100312 n = ipod_read(ipod, chunksize);
Dave Chapman4b7e1e02006-12-13 09:02:18 +0000313
314 if (n < 0) {
Dave Chapman45895df2006-12-13 08:57:06 +0000315 return -1;
316 }
317
318 if (n < chunksize) {
Dave Chapmanc5e30e12006-12-14 01:24:05 +0000319 fprintf(stderr,
Dave Chapman2cc80f52007-07-29 21:19:14 +0000320 "[ERR] Short read in disk_read() - requested %d, got %d\n",
Dave Chapman0be30362007-07-29 21:25:09 +0000321 chunksize,(int)n);
Dave Chapman45895df2006-12-13 08:57:06 +0000322 return -1;
323 }
324
325 bytesleft -= n;
326
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100327 res = write(outfile,ipod->sectorbuf,n);
Dave Chapman45895df2006-12-13 08:57:06 +0000328
329 if (res < 0) {
330 perror("[ERR] write in disk_read");
331 return -1;
332 }
333
334 if (res != n) {
Dave Chapmanc5e30e12006-12-14 01:24:05 +0000335 fprintf(stderr,
Dave Chapman0be30362007-07-29 21:25:09 +0000336 "Short write - requested %d, received %d - aborting.\n",(int)n,res);
Dave Chapman45895df2006-12-13 08:57:06 +0000337 return -1;
338 }
339 }
340
341 fprintf(stderr,"[INFO] Done.\n");
342 return 0;
343}
344
Dave Chapman31aa4522007-02-04 11:42:11 +0000345int write_partition(struct ipod_t* ipod, int infile)
Dave Chapman45895df2006-12-13 08:57:06 +0000346{
Dave Chapman2cc80f52007-07-29 21:19:14 +0000347 ssize_t res;
Dave Chapman45895df2006-12-13 08:57:06 +0000348 int n;
349 int bytesread;
350 int byteswritten = 0;
351 int eof;
352 int padding = 0;
353
Dave Chapman31aa4522007-02-04 11:42:11 +0000354 if (ipod_seek(ipod, ipod->start) < 0) {
Dave Chapman45895df2006-12-13 08:57:06 +0000355 return -1;
356 }
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100357 if(ipod->sectorbuf == NULL) {
358 fprintf(stderr,"[ERR] Buffer not initialized.");
359 return -1;
360 }
Dave Chapman45895df2006-12-13 08:57:06 +0000361
362 fprintf(stderr,"[INFO] Writing input file to device\n");
363 bytesread = 0;
364 eof = 0;
365 while (!eof) {
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100366 n = read(infile,ipod->sectorbuf,BUFFER_SIZE);
Dave Chapman45895df2006-12-13 08:57:06 +0000367
368 if (n < 0) {
369 perror("[ERR] read in disk_write");
370 return -1;
371 }
372
373 if (n < BUFFER_SIZE) {
374 eof = 1;
375 /* We need to pad the last write to a multiple of SECTOR_SIZE */
Dave Chapman31aa4522007-02-04 11:42:11 +0000376 if ((n % ipod->sector_size) != 0) {
377 padding = (ipod->sector_size-(n % ipod->sector_size));
Dave Chapman45895df2006-12-13 08:57:06 +0000378 n += padding;
379 }
380 }
381
382 bytesread += n;
383
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100384 res = ipod_write(ipod, n);
Dave Chapman4b7e1e02006-12-13 09:02:18 +0000385
386 if (res < 0) {
Dominik Riebeling3e489c12009-11-08 13:38:10 +0000387 ipod_print_error(" Error writing to disk: ");
Dave Chapman45895df2006-12-13 08:57:06 +0000388 fprintf(stderr,"Bytes written: %d\n",byteswritten);
389 return -1;
390 }
391
392 if (res != n) {
Dave Chapman0be30362007-07-29 21:25:09 +0000393 fprintf(stderr,"[ERR] Short write - requested %d, received %d - aborting.\n",n,(int)res);
Dave Chapman45895df2006-12-13 08:57:06 +0000394 return -1;
395 }
396
397 byteswritten += res;
398 }
399
Dave Chapmanc5e30e12006-12-14 01:24:05 +0000400 fprintf(stderr,"[INFO] Wrote %d bytes plus %d bytes padding.\n",
401 byteswritten-padding,padding);
Dave Chapman45895df2006-12-13 08:57:06 +0000402 return 0;
403}
404
Dave Chapman8e95cc42009-10-13 08:02:59 +0000405char* ftypename[] = { "OSOS", "RSRC", "AUPD", "HIBE", "OSBK" };
Dave Chapman4b7e1e02006-12-13 09:02:18 +0000406
Dave Chapman31aa4522007-02-04 11:42:11 +0000407int diskmove(struct ipod_t* ipod, int delta)
Dave Chapmanc5e30e12006-12-14 01:24:05 +0000408{
Dave Chapman75a11122006-12-14 18:41:03 +0000409 int src_start;
410 int src_end;
Dave Chapman75a11122006-12-14 18:41:03 +0000411 int bytesleft;
412 int chunksize;
Dave Chapman75a11122006-12-14 18:41:03 +0000413 int n;
414
Dave Chapman6e797152007-09-08 23:27:49 +0000415 src_start = ipod->ipod_directory[1].devOffset;
Dave Chapman31aa4522007-02-04 11:42:11 +0000416 src_end = (ipod->ipod_directory[ipod->nimages-1].devOffset + ipod->sector_size +
417 ipod->ipod_directory[ipod->nimages-1].len +
418 (ipod->sector_size-1)) & ~(ipod->sector_size-1);
Dave Chapman75a11122006-12-14 18:41:03 +0000419 bytesleft = src_end - src_start;
Dave Chapman75a11122006-12-14 18:41:03 +0000420
Dominik Riebelingd131a312008-06-17 17:52:13 +0000421 if (ipod_verbose) {
Dave Chapman31aa4522007-02-04 11:42:11 +0000422 fprintf(stderr,"[INFO] Need to move images 2-%d forward %08x bytes\n", ipod->nimages,delta);
Dave Chapman75a11122006-12-14 18:41:03 +0000423 fprintf(stderr,"[VERB] src_start = %08x\n",src_start);
424 fprintf(stderr,"[VERB] src_end = %08x\n",src_end);
Dave Chapman408c65b2006-12-15 09:55:21 +0000425 fprintf(stderr,"[VERB] dest_start = %08x\n",src_start+delta);
426 fprintf(stderr,"[VERB] dest_end = %08x\n",src_end+delta);
Dave Chapman75a11122006-12-14 18:41:03 +0000427 fprintf(stderr,"[VERB] bytes to copy = %08x\n",bytesleft);
428 }
429
430 while (bytesleft > 0) {
431 if (bytesleft <= BUFFER_SIZE) {
432 chunksize = bytesleft;
433 } else {
434 chunksize = BUFFER_SIZE;
435 }
436
Dominik Riebelingd131a312008-06-17 17:52:13 +0000437 if (ipod_verbose) {
Dave Chapman408c65b2006-12-15 09:55:21 +0000438 fprintf(stderr,"[VERB] Copying %08x bytes from %08x to %08x (absolute %08x to %08x)\n",
Dave Chapman75a11122006-12-14 18:41:03 +0000439 chunksize,
Dave Chapman408c65b2006-12-15 09:55:21 +0000440 src_end-chunksize,
441 src_end-chunksize+delta,
Dave Chapman31aa4522007-02-04 11:42:11 +0000442 (unsigned int)(ipod->start+src_end-chunksize),
443 (unsigned int)(ipod->start+src_end-chunksize+delta));
Dave Chapman75a11122006-12-14 18:41:03 +0000444 }
445
446
Dave Chapman31aa4522007-02-04 11:42:11 +0000447 if (ipod_seek(ipod, ipod->start+src_end-chunksize) < 0) {
Dave Chapman75a11122006-12-14 18:41:03 +0000448 fprintf(stderr,"[ERR] Seek failed\n");
449 return -1;
450 }
451
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100452 if ((n = ipod_read(ipod,chunksize)) < 0) {
Dave Chapman75a11122006-12-14 18:41:03 +0000453 perror("[ERR] Write failed\n");
454 return -1;
455 }
456
457 if (n < chunksize) {
458 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
Dave Chapman3b1119b2007-07-29 20:43:42 +0000459 chunksize,n);
Dave Chapman75a11122006-12-14 18:41:03 +0000460 return -1;
461 }
462
Dave Chapman31aa4522007-02-04 11:42:11 +0000463 if (ipod_seek(ipod, ipod->start+src_end-chunksize+delta) < 0) {
Dave Chapman75a11122006-12-14 18:41:03 +0000464 fprintf(stderr,"[ERR] Seek failed\n");
465 return -1;
466 }
467
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100468 if ((n = ipod_write(ipod,chunksize)) < 0) {
Dave Chapman75a11122006-12-14 18:41:03 +0000469 perror("[ERR] Write failed\n");
470 return -1;
471 }
472
473 if (n < chunksize) {
474 fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n"
Dave Chapman3b1119b2007-07-29 20:43:42 +0000475 ,chunksize,n);
Dave Chapman75a11122006-12-14 18:41:03 +0000476 return -1;
477 }
478
Dave Chapman408c65b2006-12-15 09:55:21 +0000479 src_end -= chunksize;
Dave Chapman75a11122006-12-14 18:41:03 +0000480 bytesleft -= chunksize;
481 }
482
483 return 0;
Dave Chapmanc5e30e12006-12-14 01:24:05 +0000484}
485
Dave Chapman8e95cc42009-10-13 08:02:59 +0000486static int rename_image(struct ipod_t* ipod, char* from, char* to)
487{
488 int n;
489 int x;
490 int found;
491 int i;
492 unsigned char* p;
493
494 /* diroffset may not be sector-aligned */
495 x = ipod->diroffset % ipod->sector_size;
496
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100497 if(ipod->sectorbuf == NULL) {
498 fprintf(stderr,"[ERR] Buffer not initialized.");
499 return -1;
500 }
Dave Chapman8e95cc42009-10-13 08:02:59 +0000501 /* Read directory */
502 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
503 fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
504 return -1;
505 }
506
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100507 n=ipod_read(ipod, ipod->sector_size);
Dave Chapman8e95cc42009-10-13 08:02:59 +0000508 if (n < 0) {
509 fprintf(stderr,"[ERR] Read of directory failed.\n");
510 return -1;
511 }
512
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100513 p = ipod->sectorbuf + x;
Dave Chapman8e95cc42009-10-13 08:02:59 +0000514
515 /* A hack to detect 2nd gen Nanos - maybe there is a better way? */
516 if (p[0] == 0)
517 {
518 /* Adjust diroffset */
519 ipod->diroffset += ipod->sector_size - x;
520
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100521 n=ipod_read(ipod, ipod->sector_size);
Dave Chapman8e95cc42009-10-13 08:02:59 +0000522 if (n < 0) {
523 fprintf(stderr,"[ERR] Read of directory failed.\n");
524 return -1;
525 }
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100526 p = ipod->sectorbuf;
Dave Chapman8e95cc42009-10-13 08:02:59 +0000527 }
528
529 found = 0;
530 for (i=0 ; !found && i < MAX_IMAGES; i++) {
531 if (memcmp(p + 4, from, 4) == 0) {
532 memcpy(p + 4, to, 4);
533
534 found = 1;
535 }
536 p += 40;
537 }
538
539 if (!found) {
540 fprintf(stderr,"[ERR] Unexpected error - no \"%s\" image!\n", from);
541 return -1;
542 }
543
544 /* Write directory back to disk */
545 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
546 fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
547 return -1;
548 }
549
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100550 n=ipod_write(ipod, ipod->sector_size);
Dave Chapman8e95cc42009-10-13 08:02:59 +0000551 if (n < 0) {
552 fprintf(stderr,"[ERR] Write of directory failed in rename_image.\n");
553 return -1;
554 }
555
556 return 0;
557}
558
559static int delete_image(struct ipod_t* ipod, char* name)
560{
561 int n;
562 int x;
563 int found;
564 int i;
565 unsigned char* p;
566
567 /* diroffset may not be sector-aligned */
568 x = ipod->diroffset % ipod->sector_size;
569
570 /* Read directory */
571 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
572 fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
573 return -1;
574 }
575
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100576 n=ipod_read(ipod, ipod->sector_size);
Dave Chapman8e95cc42009-10-13 08:02:59 +0000577 if (n < 0) {
578 fprintf(stderr,"[ERR] Read of directory failed.\n");
579 return -1;
580 }
581
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100582 p = ipod->sectorbuf + x;
Dave Chapman8e95cc42009-10-13 08:02:59 +0000583
584 /* A hack to detect 2nd gen Nanos - maybe there is a better way? */
585 if (p[0] == 0)
586 {
587 /* Adjust diroffset */
588 ipod->diroffset += ipod->sector_size - x;
589
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100590 n=ipod_read(ipod, ipod->sector_size);
Dave Chapman8e95cc42009-10-13 08:02:59 +0000591 if (n < 0) {
592 fprintf(stderr,"[ERR] Read of directory failed.\n");
593 return -1;
594 }
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100595 p = ipod->sectorbuf;
Dave Chapman8e95cc42009-10-13 08:02:59 +0000596 }
597
598 found = 0;
599 for (i=0 ; !found && i < MAX_IMAGES; i++) {
600 if (memcmp(p + 4, name, 4) == 0) {
601 memset(p, 0, 40); /* Delete directory entry */
602 found = 1;
603 }
604 p += 40;
605 }
606
607 if (!found) {
608 fprintf(stderr,"[ERR] Unexpected error - no \"%s\" image!\n", name);
609 return -1;
610 }
611
612 /* Write directory back to disk */
613 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
614 fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
615 return -1;
616 }
617
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100618 n=ipod_write(ipod, ipod->sector_size);
Dave Chapman8e95cc42009-10-13 08:02:59 +0000619 if (n < 0) {
620 fprintf(stderr,"[ERR] Write of directory failed in delete_image.\n");
621 return -1;
622 }
623
624 return 0;
625}
626
627int add_new_image(struct ipod_t* ipod, char* imagename, char* filename, int type)
628{
629 int length;
630 int found;
631 int i;
632 int x;
633 int n;
634 int infile;
635 int newsize;
636 unsigned long chksum=0;
637 unsigned long filechksum=0;
638 unsigned long offset;
639 unsigned char header[8]; /* Header for .ipod file */
640 unsigned char* p;
641
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100642 if(ipod->sectorbuf == NULL) {
643 fprintf(stderr,"[ERR] Buffer not initialized.");
644 return -1;
645 }
Dave Chapman8e95cc42009-10-13 08:02:59 +0000646#ifdef WITH_BOOTOBJS
647 if (type == FILETYPE_INTERNAL) {
648 fprintf(stderr,"[INFO] Using internal bootloader - %d bytes\n",ipod->bootloader_len);
649 length = ipod->bootloader_len;
650 infile = -1;
651 }
652 else
653#endif
654 {
655 /* First check that the input file is the correct type for this ipod. */
656 infile=open(filename,O_RDONLY);
657 if (infile < 0) {
658 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
659 return -1;
660 }
661
662 if (type==FILETYPE_DOT_IPOD) {
663 n = read(infile,header,8);
664 if (n < 8) {
665 fprintf(stderr,"[ERR] Failed to read header from %s\n",filename);
666 close(infile);
667 return -1;
668 }
669
670 if (memcmp(header+4, ipod->modelname,4)!=0) {
671 fprintf(stderr,"[ERR] Model name in input file (%c%c%c%c) doesn't match ipod model (%s)\n",
672 header[4],header[5],header[6],header[7], ipod->modelname);
673 close(infile);
674 return -1;
675 }
676
677 filechksum = be2int(header);
678
679 length = filesize(infile)-8;
680 } else {
681 length = filesize(infile);
682 }
683 }
684
685 newsize=(length+ipod->sector_size-1)&~(ipod->sector_size-1);
686
687 fprintf(stderr,"[INFO] Padding input file from 0x%08x to 0x%08x bytes\n",
688 length,newsize);
689
690 if (newsize > BUFFER_SIZE) {
691 fprintf(stderr,"[ERR] Input file too big for buffer\n");
692 if (infile >= 0) close(infile);
693 return -1;
694 }
695
696 /* TODO: Check if we have enough space in the partition for the new image */
697
698#ifdef WITH_BOOTOBJS
699 if (type == FILETYPE_INTERNAL) {
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100700 memcpy(ipod->sectorbuf,ipod->bootloader,ipod->bootloader_len);
Dave Chapman8e95cc42009-10-13 08:02:59 +0000701 }
702 else
703#endif
704 {
705 fprintf(stderr,"[INFO] Reading input file...\n");
706
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100707 n = read(infile,ipod->sectorbuf,length);
Dave Chapman8e95cc42009-10-13 08:02:59 +0000708 if (n < 0) {
709 fprintf(stderr,"[ERR] Couldn't read input file\n");
710 close(infile);
711 return -1;
712 }
713 close(infile);
714 }
715
716 /* Pad the data with zeros */
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100717 memset(ipod->sectorbuf+length,0,newsize-length);
Dave Chapman8e95cc42009-10-13 08:02:59 +0000718
719 if (type==FILETYPE_DOT_IPOD) {
720 chksum = ipod->modelnum;
721 for (i = 0; i < length; i++) {
722 /* add 8 unsigned bits but keep a 32 bit sum */
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100723 chksum += ipod->sectorbuf[i];
Dave Chapman8e95cc42009-10-13 08:02:59 +0000724 }
725
726 if (chksum == filechksum) {
727 fprintf(stderr,"[INFO] Checksum OK in %s\n",filename);
728 } else {
729 fprintf(stderr,"[ERR] Checksum in %s failed check\n",filename);
730 return -1;
731 }
732 }
733
734
735 offset = ipod->fwoffset + ipod->ipod_directory[ipod->nimages - 1].devOffset +
736 ipod->ipod_directory[ipod->nimages - 1].len + ipod->sector_size;
737
738 /* 2nd Gen Nano has encrypted firmware, and the sector
739 preceeding the firmware contains hashes that need to be
740 preserved. Nano 2G images include these extra 2048 (0x800)
741 bytes
742 */
743 if (ipod_seek(ipod, offset - (ipod->modelnum == 62 ? 0x800 : 0)) < 0) {
744 fprintf(stderr,"[ERR] Seek failed\n");
745 return -1;
746 }
747
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100748 if ((n = ipod_write(ipod,newsize)) < 0) {
Dave Chapman8e95cc42009-10-13 08:02:59 +0000749 perror("[ERR] Write failed\n");
750 return -1;
751 }
752
753 if (n < newsize) {
754 fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n"
755 ,newsize,n);
756 return -1;
757 }
758 fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n);
759
760 /* Now we need to create a new directory entry
761
762 NOTE: On the Nano 2G, the checksum is the checksum of the
763 unencrypted firmware. But this isn't checked by the NOR
764 bootloader (there are cryptographic hashes in the
765 firmware itself), so it doesn't matter that this is
766 wrong.
767 */
768 chksum = 0;
769 for (i = 0; i < length; i++) {
770 /* add 8 unsigned bits but keep a 32 bit sum */
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100771 chksum += ipod->sectorbuf[i];
Dave Chapman8e95cc42009-10-13 08:02:59 +0000772 }
773
774 x = ipod->diroffset % ipod->sector_size;
775
776 /* Read directory */
777 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
778
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100779 n=ipod_read(ipod, ipod->sector_size);
Dave Chapman8e95cc42009-10-13 08:02:59 +0000780 if (n < 0) { return -1; }
781
782 /* Create a new directory entry */
783
784 /* Copy OSOS or OSBK details - we assume one of them exists */
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100785 p = ipod->sectorbuf + x;
Dave Chapman8e95cc42009-10-13 08:02:59 +0000786 found = 0;
787 for (i = 0; !found && i < ipod->nimages; i++) {
788 if ((memcmp(p + 4, "soso", 4)==0) || (memcmp(p + 4, "kbso", 4)==0)) {
789 found = 1;
790 } else {
791 p += 40;
792 }
793 }
794
795 if (!found) {
796 fprintf(stderr,"[ERR] No OSOS or OSBK image to copy directory from\n");
797 return -1;
798 }
799
800 /* Copy directory image */
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100801 memcpy(ipod->sectorbuf + x + (ipod->nimages * 40), p, 40);
802 p = ipod->sectorbuf + x + (ipod->nimages * 40);
Dave Chapman8e95cc42009-10-13 08:02:59 +0000803
804 /* Modify directory. */
805 memcpy(p + 4, imagename, 4);
806 int2le(offset - ipod->fwoffset, p + 12); /* devOffset */
807 int2le(length - (ipod->modelnum==62 ? 0x800: 0), p + 16); /* len */
808 int2le(chksum, p + 28); /* checksum */
809
810 /* Write directory */
811 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100812 n=ipod_write(ipod, ipod->sector_size);
Dave Chapman8e95cc42009-10-13 08:02:59 +0000813 if (n < 0) { return -1; }
814
815 return 0;
816}
817
818
Dominik Riebelingbf1c4912012-07-01 12:29:47 +0200819int ipod_has_bootloader(struct ipod_t* ipod)
820{
821 /* The 2nd gen Nano is installed differently */
822 if (ipod->modelnum == 62) {
823 int i;
824 int has_osbk = 0;
825 /* Check if we have an OSBK image */
826 for (i = 0; i < ipod->nimages; i++) {
827 if (ipod->ipod_directory[i].ftype==FTYPE_OSBK) {
828 has_osbk = 1;
829 }
830 }
831 return has_osbk;
832 }
833 else {
834 return (ipod->ipod_directory[0].entryOffset != 0);
835 }
836}
837
838
Dave Chapman8e95cc42009-10-13 08:02:59 +0000839/*
840 Bootloader installation on the Nano2G consists of renaming the
841 OSOS image to OSBK and then writing the Rockbox bootloader as a
842 new OSOS image.
843
844 Maybe this approach can/should be adapted for other ipods, as it
845 prevents the Apple bootloader loading the original firmware into
846 RAM along with the Rockbox bootloader (and hence will give a
847 faster boot when the user just wants to start Rockbox).
848
849*/
850
851static int add_bootloader_nano2g(struct ipod_t* ipod, char* filename, int type)
852{
Dave Chapman8e95cc42009-10-13 08:02:59 +0000853 /* Check if we already have an OSBK image */
Dominik Riebelingbf1c4912012-07-01 12:29:47 +0200854 if (ipod_has_bootloader(ipod) == 0) {
Dave Chapman8e95cc42009-10-13 08:02:59 +0000855 /* First-time install - rename OSOS to OSBK and create new OSOS for bootloader */
856 fprintf(stderr,"[INFO] Creating OSBK backup image of original firmware\n");
857
858 if (rename_image(ipod, "soso", "kbso") < 0) {
859 fprintf(stderr,"[ERR] Could not rename OSOS image\n");
860 return -1;
861 }
862
863 /* Add our bootloader as a brand new image */
864 return add_new_image(ipod, "soso", filename, type);
865 } else {
866 /* This is an update, just replace OSOS with our bootloader */
867
868 return write_firmware(ipod, filename, type);
869 }
870}
871
872
873static int delete_bootloader_nano2g(struct ipod_t* ipod)
874{
Dave Chapman8e95cc42009-10-13 08:02:59 +0000875 /* Check if we have an OSBK image */
Dominik Riebelingbf1c4912012-07-01 12:29:47 +0200876 if (ipod_has_bootloader(ipod) == 0) {
Dave Chapman8e95cc42009-10-13 08:02:59 +0000877 fprintf(stderr,"[ERR] No OSBK image found - nothing to uninstall\n");
878 return -1;
879 } else {
880 /* Delete our bootloader image */
881 if (delete_image(ipod, "soso") < 0) {
882 fprintf(stderr,"[WARN] Could not delete OSOS image\n");
883 } else {
884 fprintf(stderr,"[INFO] OSOS image deleted\n");
885 }
886
887 if (rename_image(ipod, "kbso", "soso") < 0) {
888 fprintf(stderr,"[ERR] Could not rename OSBK image\n");
889 return -1;
890 }
891
892
893 fprintf(stderr,"[INFO] OSBK image renamed to OSOS - bootloader uninstalled.\n");
894 return 0;
895 }
896}
897
898
Dave Chapman31aa4522007-02-04 11:42:11 +0000899int add_bootloader(struct ipod_t* ipod, char* filename, int type)
Dave Chapman75a11122006-12-14 18:41:03 +0000900{
901 int length;
902 int i;
Dave Chapmand7729772006-12-15 15:52:08 +0000903 int x;
Dave Chapman75a11122006-12-14 18:41:03 +0000904 int n;
905 int infile;
906 int paddedlength;
907 int entryOffset;
908 int delta = 0;
909 unsigned long chksum=0;
910 unsigned long filechksum=0;
911 unsigned char header[8]; /* Header for .ipod file */
Dave Chapmaneca52222007-02-08 21:31:38 +0000912 unsigned char* bootloader_buf;
Dave Chapman75a11122006-12-14 18:41:03 +0000913
Dave Chapman8e95cc42009-10-13 08:02:59 +0000914 /* The 2nd gen Nano is installed differently */
915 if (ipod->modelnum == 62) {
916 return add_bootloader_nano2g(ipod, filename, type);
917 }
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100918 if(ipod->sectorbuf == NULL) {
919 fprintf(stderr,"[ERR] Buffer not initialized.");
920 return -1;
921 }
Dave Chapman8e95cc42009-10-13 08:02:59 +0000922
Dave Chapmanbdc27ff2007-02-08 18:05:50 +0000923 /* Calculate the position in the OSOS image where our bootloader will go. */
Dave Chapman31aa4522007-02-04 11:42:11 +0000924 if (ipod->ipod_directory[0].entryOffset>0) {
Dave Chapman75a11122006-12-14 18:41:03 +0000925 /* Keep the same entryOffset */
Dave Chapman31aa4522007-02-04 11:42:11 +0000926 entryOffset = ipod->ipod_directory[0].entryOffset;
Dave Chapman75a11122006-12-14 18:41:03 +0000927 } else {
Dave Chapman31aa4522007-02-04 11:42:11 +0000928 entryOffset = (ipod->ipod_directory[0].len+ipod->sector_size-1)&~(ipod->sector_size-1);
Dave Chapman75a11122006-12-14 18:41:03 +0000929 }
930
Dave Chapmanbdc27ff2007-02-08 18:05:50 +0000931#ifdef WITH_BOOTOBJS
932 if (type == FILETYPE_INTERNAL) {
933 fprintf(stderr,"[INFO] Using internal bootloader - %d bytes\n",ipod->bootloader_len);
Dominik Riebeling24e37dd2012-12-23 23:30:57 +0100934 memcpy(ipod->sectorbuf+entryOffset,ipod->bootloader,ipod->bootloader_len);
Dave Chapmanbdc27ff2007-02-08 18:05:50 +0000935 length = ipod->bootloader_len;
936 paddedlength=(ipod->bootloader_len+ipod->sector_size-1)&~(ipod->sector_size-1);
937 }
938 else
939#endif
940 {
941 infile=open(filename,O_RDONLY);
942 if (infile < 0) {
943 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
944 return -1;
945 }
946
947 if (type==FILETYPE_DOT_IPOD) {
948 /* First check that the input file is the correct type for this ipod. */
949 n = read(infile,header,8);
950 if (n < 8) {
951 fprintf(stderr,"[ERR] Failed to read header from %s\n",filename);
952 close(infile);
953 return -1;
954 }
955
956 if (memcmp(header+4, ipod->modelname,4)!=0) {
957 fprintf(stderr,"[ERR] Model name in input file (%c%c%c%c) doesn't match ipod model (%s)\n",
958 header[4],header[5],header[6],header[7], ipod->modelname);
959 close(infile);
960 return -1;
961 }
962
963 filechksum = be2int(header);
964
965 length=filesize(infile)-8;
966 } else {
967 length=filesize(infile);
968 }
969 paddedlength=(length+ipod->sector_size-1)&~(ipod->sector_size-1);
Dave Chapmaneca52222007-02-08 21:31:38 +0000970
971 bootloader_buf = malloc(length);
972 if (bootloader_buf == NULL) {
Dave Chapman6e314e52007-06-08 15:24:47 +0000973 fprintf(stderr,"[ERR] Can not allocate memory for bootloader\n");
Dave Chapman09b247f2007-06-08 15:30:14 +0000974 return -1;
Dave Chapmaneca52222007-02-08 21:31:38 +0000975 }
Dave Chapmanbdc27ff2007-02-08 18:05:50 +0000976 /* Now read our bootloader - we need to check it before modifying the partition*/
Dave Chapmaneca52222007-02-08 21:31:38 +0000977 n = read(infile,bootloader_buf,length);
Dave Chapmanbdc27ff2007-02-08 18:05:50 +0000978 close(infile);
979
980 if (n < 0) {
981 fprintf(stderr,"[ERR] Couldn't read input file\n");
982 return -1;
983 }
984
985 if (type==FILETYPE_DOT_IPOD) {
986 /* Calculate and confirm bootloader checksum */
987 chksum = ipod->modelnum;
Dave Chapmaneca52222007-02-08 21:31:38 +0000988 for (i = 0; i < length; i++) {
Dave Chapmanbdc27ff2007-02-08 18:05:50 +0000989 /* add 8 unsigned bits but keep a 32 bit sum */
Dave Chapmaneca52222007-02-08 21:31:38 +0000990 chksum += bootloader_buf[i];
Dave Chapmanbdc27ff2007-02-08 18:05:50 +0000991 }
992
993 if (chksum == filechksum) {
994 fprintf(stderr,"[INFO] Checksum OK in %s\n",filename);
995 } else {
996 fprintf(stderr,"[ERR] Checksum in %s failed check\n",filename);
997 return -1;
998 }
999 }
1000 }
1001
Dave Chapman75a11122006-12-14 18:41:03 +00001002 if (entryOffset+paddedlength > BUFFER_SIZE) {
1003 fprintf(stderr,"[ERR] Input file too big for buffer\n");
Dave Chapman75a11122006-12-14 18:41:03 +00001004 return -1;
1005 }
1006
Dominik Riebelingd131a312008-06-17 17:52:13 +00001007 if (ipod_verbose) {
Dave Chapman31aa4522007-02-04 11:42:11 +00001008 fprintf(stderr,"[VERB] Original firmware begins at 0x%08x\n", ipod->ipod_directory[0].devOffset + ipod->sector_size);
Dave Chapman75a11122006-12-14 18:41:03 +00001009 fprintf(stderr,"[VERB] New entryOffset will be 0x%08x\n",entryOffset);
1010 fprintf(stderr,"[VERB] End of bootloader will be at 0x%08x\n",entryOffset+paddedlength);
1011 }
1012
1013 /* Check if we have enough space */
1014 /* TODO: Check the size of the partition. */
Dave Chapman31aa4522007-02-04 11:42:11 +00001015 if (ipod->nimages > 1) {
Dave Chapmanbdc27ff2007-02-08 18:05:50 +00001016 if ((ipod->ipod_directory[0].devOffset+entryOffset+paddedlength) >
Dave Chapman33e15152007-02-04 13:04:23 +00001017 ipod->ipod_directory[1].devOffset) {
Dave Chapman75a11122006-12-14 18:41:03 +00001018 fprintf(stderr,"[INFO] Moving images to create room for new firmware...\n");
Dave Chapman31aa4522007-02-04 11:42:11 +00001019 delta = ipod->ipod_directory[0].devOffset + entryOffset+paddedlength
Dave Chapman6e797152007-09-08 23:27:49 +00001020 - ipod->ipod_directory[1].devOffset + ipod->sector_size;
Dave Chapman75a11122006-12-14 18:41:03 +00001021
Dave Chapman31aa4522007-02-04 11:42:11 +00001022 if (diskmove(ipod, delta) < 0) {
Dave Chapman75a11122006-12-14 18:41:03 +00001023 fprintf(stderr,"[ERR] Image movement failed.\n");
1024 return -1;
1025 }
1026 }
1027 }
1028
1029
1030 /* We have moved the partitions, now we can write our bootloader */
1031
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001032 /* Firstly read the original firmware into ipod->sectorbuf */
Dave Chapman75a11122006-12-14 18:41:03 +00001033 fprintf(stderr,"[INFO] Reading original firmware...\n");
Dave Chapman31aa4522007-02-04 11:42:11 +00001034 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) {
Dave Chapman75a11122006-12-14 18:41:03 +00001035 fprintf(stderr,"[ERR] Seek failed\n");
1036 return -1;
1037 }
1038
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001039 if ((n = ipod_read(ipod,entryOffset)) < 0) {
Dave Chapman75a11122006-12-14 18:41:03 +00001040 perror("[ERR] Read failed\n");
1041 return -1;
1042 }
1043
1044 if (n < entryOffset) {
1045 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n"
Dave Chapman3b1119b2007-07-29 20:43:42 +00001046 ,entryOffset,n);
Dave Chapman75a11122006-12-14 18:41:03 +00001047 return -1;
1048 }
1049
Dave Chapmaneca52222007-02-08 21:31:38 +00001050#ifdef WITH_BOOTOBJS
1051 if (type == FILETYPE_INTERNAL) {
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001052 memcpy(ipod->sectorbuf+entryOffset,ipod->bootloader,ipod->bootloader_len);
Dave Chapmaneca52222007-02-08 21:31:38 +00001053 }
1054 else
1055#endif
1056 {
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001057 memcpy(ipod->sectorbuf+entryOffset,bootloader_buf,length);
Dave Chapmaneca52222007-02-08 21:31:38 +00001058 free(bootloader_buf);
1059 }
1060
Dave Chapman75a11122006-12-14 18:41:03 +00001061 /* Calculate new checksum for combined image */
1062 chksum = 0;
1063 for (i=0;i<entryOffset + length; i++) {
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001064 chksum += ipod->sectorbuf[i];
Dave Chapman75a11122006-12-14 18:41:03 +00001065 }
1066
1067 /* Now write the combined firmware image to the disk */
1068
Dave Chapman31aa4522007-02-04 11:42:11 +00001069 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) {
Dave Chapman75a11122006-12-14 18:41:03 +00001070 fprintf(stderr,"[ERR] Seek failed\n");
1071 return -1;
1072 }
1073
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001074 if ((n = ipod_write(ipod,entryOffset+paddedlength)) < 0) {
Dave Chapman75a11122006-12-14 18:41:03 +00001075 perror("[ERR] Write failed\n");
1076 return -1;
1077 }
1078
1079 if (n < (entryOffset+paddedlength)) {
1080 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n"
Dave Chapman3b1119b2007-07-29 20:43:42 +00001081 ,entryOffset+paddedlength,n);
Dave Chapman75a11122006-12-14 18:41:03 +00001082 return -1;
1083 }
1084
1085 fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",entryOffset+paddedlength);
1086
Dave Chapman31aa4522007-02-04 11:42:11 +00001087 x = ipod->diroffset % ipod->sector_size;
Dave Chapman75a11122006-12-14 18:41:03 +00001088
1089 /* Read directory */
Dave Chapman31aa4522007-02-04 11:42:11 +00001090 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
1091 fprintf(stderr,"[ERR] Seek failed\n");
1092 return -1;
1093 }
Dave Chapman75a11122006-12-14 18:41:03 +00001094
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001095 n=ipod_read(ipod, ipod->sector_size);
Dave Chapman31aa4522007-02-04 11:42:11 +00001096 if (n < 0) {
1097 fprintf(stderr,"[ERR] Directory read failed\n");
1098 return -1;
1099 }
Dave Chapman75a11122006-12-14 18:41:03 +00001100
1101 /* Update entries for image 0 */
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001102 int2le(entryOffset+length,ipod->sectorbuf+x+16);
1103 int2le(entryOffset,ipod->sectorbuf+x+24);
1104 int2le(chksum,ipod->sectorbuf+x+28);
1105 int2le(0xffffffff,ipod->sectorbuf+x+36); /* loadAddr */
Dave Chapman75a11122006-12-14 18:41:03 +00001106
1107 /* Update devOffset entries for other images, if we have moved them */
1108 if (delta > 0) {
Dave Chapman31aa4522007-02-04 11:42:11 +00001109 for (i=1;i<ipod->nimages;i++) {
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001110 int2le(le2int(ipod->sectorbuf+x+i*40+12)+delta,ipod->sectorbuf+x+i*40+12);
Dave Chapman75a11122006-12-14 18:41:03 +00001111 }
1112 }
1113
1114 /* Write directory */
Dave Chapman31aa4522007-02-04 11:42:11 +00001115 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
Dave Chapmanc500b962007-02-04 23:41:47 +00001116 fprintf(stderr,"[ERR] Seek to %d failed\n", (int)(ipod->start+ipod->diroffset-x));
Dave Chapman31aa4522007-02-04 11:42:11 +00001117 return -1;
1118 }
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001119 n=ipod_write(ipod, ipod->sector_size);
Dave Chapman31aa4522007-02-04 11:42:11 +00001120 if (n < 0) {
1121 fprintf(stderr,"[ERR] Directory write failed\n");
1122 return -1;
1123 }
Dave Chapman75a11122006-12-14 18:41:03 +00001124
1125 return 0;
1126}
1127
Dave Chapman31aa4522007-02-04 11:42:11 +00001128int delete_bootloader(struct ipod_t* ipod)
Dave Chapman75a11122006-12-14 18:41:03 +00001129{
1130 int length;
1131 int i;
Dave Chapmand7729772006-12-15 15:52:08 +00001132 int x;
Dave Chapman75a11122006-12-14 18:41:03 +00001133 int n;
1134 unsigned long chksum=0; /* 32 bit checksum - Rockbox .ipod style*/
1135
Dave Chapman8e95cc42009-10-13 08:02:59 +00001136 /* The 2nd gen Nano is installed differently */
1137 if (ipod->modelnum == 62) {
1138 return delete_bootloader_nano2g(ipod);
1139 }
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001140 if(ipod->sectorbuf == NULL) {
1141 fprintf(stderr,"[ERR] Buffer not initialized.");
1142 return -1;
1143 }
Dave Chapman8e95cc42009-10-13 08:02:59 +00001144
Dave Chapman75a11122006-12-14 18:41:03 +00001145 /* Removing the bootloader involves adjusting the "length",
1146 "chksum" and "entryOffset" values in the osos image's directory
1147 entry. */
1148
1149 /* Firstly check we have a bootloader... */
1150
Dominik Riebelingbf1c4912012-07-01 12:29:47 +02001151 if (ipod_has_bootloader(ipod) == 0) {
Dave Chapman75a11122006-12-14 18:41:03 +00001152 fprintf(stderr,"[ERR] No bootloader found.\n");
1153 return -1;
1154 }
1155
Dave Chapman31aa4522007-02-04 11:42:11 +00001156 length = ipod->ipod_directory[0].entryOffset;
Dave Chapman75a11122006-12-14 18:41:03 +00001157
1158 /* Read the firmware so we can calculate the checksum */
1159 fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length);
1160
Dave Chapman31aa4522007-02-04 11:42:11 +00001161 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[0].devOffset) < 0) {
Dave Chapman75a11122006-12-14 18:41:03 +00001162 return -1;
1163 }
1164
Dave Chapman31aa4522007-02-04 11:42:11 +00001165 i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1);
Dave Chapman75a11122006-12-14 18:41:03 +00001166 fprintf(stderr,"[INFO] Padding read from 0x%08x to 0x%08x bytes\n",
1167 length,i);
1168
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001169 if ((n = ipod_read(ipod,i)) < 0) {
Dave Chapman75a11122006-12-14 18:41:03 +00001170 return -1;
1171 }
1172
1173 if (n < i) {
1174 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
1175 i,n);
1176 return -1;
1177 }
1178
1179 chksum = 0;
1180 for (i = 0; i < length; i++) {
1181 /* add 8 unsigned bits but keep a 32 bit sum */
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001182 chksum += ipod->sectorbuf[i];
Dave Chapman75a11122006-12-14 18:41:03 +00001183 }
1184
1185 /* Now write back the updated directory entry */
1186
1187 fprintf(stderr,"[INFO] Updating firmware checksum\n");
1188
Dave Chapman31aa4522007-02-04 11:42:11 +00001189 x = ipod->diroffset % ipod->sector_size;
Dave Chapmand7729772006-12-15 15:52:08 +00001190
Dave Chapman75a11122006-12-14 18:41:03 +00001191 /* Read directory */
Dave Chapman31aa4522007-02-04 11:42:11 +00001192 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
Dave Chapman75a11122006-12-14 18:41:03 +00001193
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001194 n=ipod_read(ipod, ipod->sector_size);
Dave Chapman75a11122006-12-14 18:41:03 +00001195 if (n < 0) { return -1; }
1196
1197 /* Update entries for image 0 */
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001198 int2le(length,ipod->sectorbuf+x+16);
1199 int2le(0,ipod->sectorbuf+x+24);
1200 int2le(chksum,ipod->sectorbuf+x+28);
Dave Chapman75a11122006-12-14 18:41:03 +00001201
1202 /* Write directory */
Dave Chapman31aa4522007-02-04 11:42:11 +00001203 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001204 n=ipod_write(ipod, ipod->sector_size);
Dave Chapman75a11122006-12-14 18:41:03 +00001205 if (n < 0) { return -1; }
1206
1207 return 0;
1208}
1209
Dave Chapman31aa4522007-02-04 11:42:11 +00001210int write_firmware(struct ipod_t* ipod, char* filename, int type)
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001211{
1212 int length;
1213 int i;
Dave Chapmand7729772006-12-15 15:52:08 +00001214 int x;
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001215 int n;
1216 int infile;
1217 int newsize;
1218 int bytesavailable;
1219 unsigned long chksum=0;
1220 unsigned long filechksum=0;
Dave Chapman8e95cc42009-10-13 08:02:59 +00001221 unsigned long offset;
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001222 unsigned char header[8]; /* Header for .ipod file */
Dave Chapman8e95cc42009-10-13 08:02:59 +00001223 unsigned char* p;
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001224
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001225 if(ipod->sectorbuf == NULL) {
1226 fprintf(stderr,"[ERR] Buffer not initialized.");
1227 return -1;
1228 }
Dave Chapmanbbde4452007-06-02 10:10:31 +00001229#ifdef WITH_BOOTOBJS
1230 if (type == FILETYPE_INTERNAL) {
1231 fprintf(stderr,"[INFO] Using internal bootloader - %d bytes\n",ipod->bootloader_len);
1232 length = ipod->bootloader_len;
1233 infile = -1;
1234 }
1235 else
1236#endif
1237 {
1238 /* First check that the input file is the correct type for this ipod. */
1239 infile=open(filename,O_RDONLY);
1240 if (infile < 0) {
1241 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
Dave Chapman31aa4522007-02-04 11:42:11 +00001242 return -1;
1243 }
Dave Chapmanbbde4452007-06-02 10:10:31 +00001244
1245 if (type==FILETYPE_DOT_IPOD) {
1246 n = read(infile,header,8);
1247 if (n < 8) {
1248 fprintf(stderr,"[ERR] Failed to read header from %s\n",filename);
1249 close(infile);
1250 return -1;
1251 }
1252
1253 if (memcmp(header+4, ipod->modelname,4)!=0) {
1254 fprintf(stderr,"[ERR] Model name in input file (%c%c%c%c) doesn't match ipod model (%s)\n",
1255 header[4],header[5],header[6],header[7], ipod->modelname);
1256 close(infile);
1257 return -1;
1258 }
1259
1260 filechksum = be2int(header);
1261
1262 length = filesize(infile)-8;
1263 } else {
1264 length = filesize(infile);
Dave Chapman31aa4522007-02-04 11:42:11 +00001265 }
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001266 }
Dave Chapmanbbde4452007-06-02 10:10:31 +00001267
Dave Chapman31aa4522007-02-04 11:42:11 +00001268 newsize=(length+ipod->sector_size-1)&~(ipod->sector_size-1);
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001269
1270 fprintf(stderr,"[INFO] Padding input file from 0x%08x to 0x%08x bytes\n",
1271 length,newsize);
1272
1273 if (newsize > BUFFER_SIZE) {
1274 fprintf(stderr,"[ERR] Input file too big for buffer\n");
Dave Chapmanbbde4452007-06-02 10:10:31 +00001275 if (infile >= 0) close(infile);
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001276 return -1;
1277 }
1278
1279 /* Check if we have enough space */
1280 /* TODO: Check the size of the partition. */
Dave Chapman31aa4522007-02-04 11:42:11 +00001281 if (ipod->nimages > 1) {
1282 bytesavailable=ipod->ipod_directory[1].devOffset-ipod->ipod_directory[0].devOffset;
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001283 if (bytesavailable < newsize) {
1284 fprintf(stderr,"[INFO] Moving images to create room for new firmware...\n");
1285
1286 /* TODO: Implement image movement */
1287 fprintf(stderr,"[ERR] Image movement not yet implemented.\n");
1288 close(infile);
1289 return -1;
1290 }
1291 }
1292
Dave Chapmanbbde4452007-06-02 10:10:31 +00001293#ifdef WITH_BOOTOBJS
1294 if (type == FILETYPE_INTERNAL) {
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001295 memcpy(ipod->sectorbuf,ipod->bootloader,ipod->bootloader_len);
Dave Chapmanbbde4452007-06-02 10:10:31 +00001296 }
1297 else
1298#endif
1299 {
1300 fprintf(stderr,"[INFO] Reading input file...\n");
1301 /* We now know we have enough space, so write it. */
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001302 n = read(infile,ipod->sectorbuf,length);
Dave Chapmanbbde4452007-06-02 10:10:31 +00001303 if (n < 0) {
1304 fprintf(stderr,"[ERR] Couldn't read input file\n");
1305 close(infile);
1306 return -1;
1307 }
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001308 close(infile);
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001309 }
Dave Chapmanbbde4452007-06-02 10:10:31 +00001310
1311 /* Pad the data with zeros */
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001312 memset(ipod->sectorbuf+length,0,newsize-length);
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001313
Dave Chapmanbdc27ff2007-02-08 18:05:50 +00001314 if (type==FILETYPE_DOT_IPOD) {
Dave Chapman31aa4522007-02-04 11:42:11 +00001315 chksum = ipod->modelnum;
1316 for (i = 0; i < length; i++) {
1317 /* add 8 unsigned bits but keep a 32 bit sum */
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001318 chksum += ipod->sectorbuf[i];
Dave Chapman31aa4522007-02-04 11:42:11 +00001319 }
1320
1321 if (chksum == filechksum) {
1322 fprintf(stderr,"[INFO] Checksum OK in %s\n",filename);
1323 } else {
1324 fprintf(stderr,"[ERR] Checksum in %s failed check\n",filename);
1325 return -1;
1326 }
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001327 }
1328
Dave Chapman8e95cc42009-10-13 08:02:59 +00001329
1330 offset = ipod->fwoffset+ipod->ipod_directory[ipod->ososimage].devOffset;
1331
1332 if (ipod->modelnum==62) {
1333
1334 /* 2nd Gen Nano has encrypted firmware, and the sector
1335 preceeding the firmware contains hashes that need to be
1336 preserved. Nano 2G images include these extra 2048 (0x800)
1337 bytes
1338 */
1339
1340 offset -= 0x800;
1341
1342 /* TODO: The above checks need to take into account this 0x800 bytes */
1343 }
1344
1345 if (ipod_seek(ipod, offset) < 0) {
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001346 fprintf(stderr,"[ERR] Seek failed\n");
1347 return -1;
1348 }
1349
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001350 if ((n = ipod_write(ipod,newsize)) < 0) {
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001351 perror("[ERR] Write failed\n");
1352 return -1;
1353 }
1354
1355 if (n < newsize) {
1356 fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n"
Dave Chapman3b1119b2007-07-29 20:43:42 +00001357 ,newsize,n);
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001358 return -1;
1359 }
1360 fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n);
1361
Dave Chapman8e95cc42009-10-13 08:02:59 +00001362 /* Now we need to update the "len", "entryOffset" and "chksum" fields
1363
1364 NOTE: On the Nano 2G, the checksum is the checksum of the
1365 unencrypted firmware. But this isn't checked by the NOR
1366 bootloader (there are cryptographic hashes in the
1367 firmware itself), so it doesn't matter that this is
1368 wrong.
1369 */
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001370 chksum = 0;
1371 for (i = 0; i < length; i++) {
1372 /* add 8 unsigned bits but keep a 32 bit sum */
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001373 chksum += ipod->sectorbuf[i];
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001374 }
1375
Dave Chapman31aa4522007-02-04 11:42:11 +00001376 x = ipod->diroffset % ipod->sector_size;
Dave Chapmand7729772006-12-15 15:52:08 +00001377
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001378 /* Read directory */
Dave Chapman31aa4522007-02-04 11:42:11 +00001379 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001380
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001381 n=ipod_read(ipod, ipod->sector_size);
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001382 if (n < 0) { return -1; }
1383
Dave Chapman8e95cc42009-10-13 08:02:59 +00001384 /* Update entries for image */
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001385 p = ipod->sectorbuf + x + (ipod->ososimage * 40);
Dave Chapman8e95cc42009-10-13 08:02:59 +00001386 int2le(length - (ipod->modelnum==62 ? 0x800: 0), p + 16);
1387 int2le(0, p + 24);
1388 int2le(chksum, p + 28);
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001389
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001390 /* Write directory */
Dave Chapman31aa4522007-02-04 11:42:11 +00001391 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001392 n=ipod_write(ipod, ipod->sector_size);
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001393 if (n < 0) { return -1; }
1394
1395 return 0;
1396}
1397
Dave Chapman427fff42007-04-13 23:28:20 +00001398int read_firmware(struct ipod_t* ipod, char* filename, int type)
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001399{
1400 int length;
1401 int i;
1402 int outfile;
1403 int n;
Dave Chapman8e95cc42009-10-13 08:02:59 +00001404 unsigned long offset;
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001405 unsigned long chksum=0; /* 32 bit checksum - Rockbox .ipod style*/
1406 unsigned char header[8]; /* Header for .ipod file */
1407
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001408 if(ipod->sectorbuf == NULL) {
1409 fprintf(stderr,"[ERR] Buffer not initialized.");
1410 return -1;
1411 }
Dave Chapman8e95cc42009-10-13 08:02:59 +00001412 if (ipod->ipod_directory[ipod->ososimage].entryOffset != 0) {
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001413 /* We have a bootloader... */
Dave Chapman8e95cc42009-10-13 08:02:59 +00001414 length = ipod->ipod_directory[ipod->ososimage].entryOffset;
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001415 } else {
Dave Chapman8e95cc42009-10-13 08:02:59 +00001416 length = ipod->ipod_directory[ipod->ososimage].len;
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001417 }
1418
1419 fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length);
1420
Dave Chapman8e95cc42009-10-13 08:02:59 +00001421 offset = ipod->fwoffset + ipod->ipod_directory[ipod->ososimage].devOffset;
Dave Chapman31aa4522007-02-04 11:42:11 +00001422 i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1);
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001423 fprintf(stderr,"[INFO] Padding read from 0x%08x to 0x%08x bytes\n",
1424 length,i);
1425
Dave Chapman8e95cc42009-10-13 08:02:59 +00001426 if (ipod->modelnum==62) {
1427 /* 2nd Gen Nano has encrypted firmware, and we need to dump the
1428 sector preceeding the image - it contains hashes */
1429 offset -= 0x800;
1430 length += 0x800;
1431 i += 0x800;
1432 }
1433
1434 if (ipod_seek(ipod, offset)) {
1435 return -1;
1436 }
1437
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001438 if ((n = ipod_read(ipod,i)) < 0) {
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001439 return -1;
1440 }
1441
1442 if (n < i) {
1443 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
1444 i,n);
1445 return -1;
1446 }
1447
Dave Chapmancd067552006-12-14 10:16:10 +00001448 outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666);
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001449 if (outfile < 0) {
1450 fprintf(stderr,"[ERR] Couldn't open file %s\n",filename);
1451 return -1;
1452 }
1453
Dave Chapman427fff42007-04-13 23:28:20 +00001454 if (type == FILETYPE_DOT_IPOD) {
1455 chksum = ipod->modelnum;
1456 for (i = 0; i < length; i++) {
1457 /* add 8 unsigned bits but keep a 32 bit sum */
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001458 chksum += ipod->sectorbuf[i];
Dave Chapman427fff42007-04-13 23:28:20 +00001459 }
1460
1461 int2be(chksum,header);
1462 memcpy(header+4, ipod->modelname,4);
1463
Dave Chapman33bc6f32007-07-29 21:34:28 +00001464 n = write(outfile,header,8);
1465 if (n != 8) {
1466 fprintf(stderr,"[ERR] Write error - %d\n",n);
1467 }
Dave Chapman427fff42007-04-13 23:28:20 +00001468 }
1469
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001470 n = write(outfile,ipod->sectorbuf,length);
Dave Chapman33bc6f32007-07-29 21:34:28 +00001471 if (n != length) {
1472 fprintf(stderr,"[ERR] Write error - %d\n",n);
1473 }
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001474 close(outfile);
1475
1476 return 0;
1477}
1478
Dave Chapman31aa4522007-02-04 11:42:11 +00001479int read_directory(struct ipod_t* ipod)
Dave Chapman4b7e1e02006-12-13 09:02:18 +00001480{
1481 int n;
Dave Chapmand7729772006-12-15 15:52:08 +00001482 int x;
Dave Chapman4b7e1e02006-12-13 09:02:18 +00001483 unsigned char* p;
Dave Chapman31aa4522007-02-04 11:42:11 +00001484 unsigned short version;
Dave Chapman4b7e1e02006-12-13 09:02:18 +00001485
Dave Chapman1026c0f2007-02-06 21:00:56 +00001486 ipod->nimages=0;
1487
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001488 /* Read firmware partition header (first 512 bytes of disk - but
1489 let's read a whole sector) */
Dave Chapman4b7e1e02006-12-13 09:02:18 +00001490
Dave Chapman31aa4522007-02-04 11:42:11 +00001491 if (ipod_seek(ipod, ipod->start) < 0) {
1492 fprintf(stderr,"[ERR] Seek to 0x%08x in read_directory() failed.\n",
1493 (unsigned int)(ipod->start));
Dave Chapmand7729772006-12-15 15:52:08 +00001494 return -1;
1495 }
Dave Chapman4b7e1e02006-12-13 09:02:18 +00001496
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001497 n=ipod_read(ipod, ipod->sector_size);
Dave Chapmand7729772006-12-15 15:52:08 +00001498 if (n < 0) {
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001499 fprintf(stderr,"[ERR] ipod_read(ipod,0x%08x) failed in read_directory()\n", ipod->sector_size);
Dave Chapmand7729772006-12-15 15:52:08 +00001500 return -1;
1501 }
Dave Chapman4b7e1e02006-12-13 09:02:18 +00001502
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001503 if (memcmp(ipod->sectorbuf,apple_stop_sign,sizeof(apple_stop_sign))!=0) {
Dave Chapman1026c0f2007-02-06 21:00:56 +00001504 fprintf(stderr,"[ERR] Firmware partition doesn't contain Apple copyright, aborting.\n");
Dave Chapman4b7e1e02006-12-13 09:02:18 +00001505 return -1;
1506 }
1507
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001508 if (memcmp(ipod->sectorbuf+0x100,"]ih[",4)!=0) {
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001509 fprintf(stderr,"[ERR] Bad firmware directory\n");
Dave Chapman4b7e1e02006-12-13 09:02:18 +00001510 return -1;
1511 }
1512
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001513 version = le2ushort(ipod->sectorbuf+0x10a);
Dave Chapman31aa4522007-02-04 11:42:11 +00001514 if ((version != 2) && (version != 3)) {
1515 fprintf(stderr,"[ERR] Unknown firmware format version %04x\n",
1516 version);
1517 }
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001518 ipod->diroffset=le2int(ipod->sectorbuf+0x104) + 0x200;
Dave Chapman4b7e1e02006-12-13 09:02:18 +00001519
Dave Chapmand7729772006-12-15 15:52:08 +00001520 /* diroffset may not be sector-aligned */
Dave Chapman31aa4522007-02-04 11:42:11 +00001521 x = ipod->diroffset % ipod->sector_size;
Dave Chapmand7729772006-12-15 15:52:08 +00001522
Dave Chapman4b7e1e02006-12-13 09:02:18 +00001523 /* Read directory */
Dave Chapman31aa4522007-02-04 11:42:11 +00001524 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) {
1525 fprintf(stderr,"[ERR] Seek to diroffset (%08x) failed.\n",(unsigned)ipod->diroffset);
Dave Chapmand7729772006-12-15 15:52:08 +00001526 return -1;
1527 }
Dave Chapman4b7e1e02006-12-13 09:02:18 +00001528
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001529 n=ipod_read(ipod, ipod->sector_size);
Dave Chapmand7729772006-12-15 15:52:08 +00001530 if (n < 0) {
1531 fprintf(stderr,"[ERR] Read of directory failed.\n");
1532 return -1;
1533 }
Dave Chapman4b7e1e02006-12-13 09:02:18 +00001534
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001535 p = ipod->sectorbuf + x;
Dave Chapman564d2492007-08-03 02:12:32 +00001536
1537 /* A hack to detect 2nd gen Nanos - maybe there is a better way? */
1538 if (p[0] == 0)
1539 {
Dave Chapman8e95cc42009-10-13 08:02:59 +00001540 /* Adjust diroffset */
1541 ipod->diroffset += ipod->sector_size - x;
1542
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001543 n=ipod_read(ipod, ipod->sector_size);
Dave Chapman564d2492007-08-03 02:12:32 +00001544 if (n < 0) {
1545 fprintf(stderr,"[ERR] Read of directory failed.\n");
1546 return -1;
1547 }
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001548 p = ipod->sectorbuf;
Dave Chapman564d2492007-08-03 02:12:32 +00001549 }
1550
Dave Chapman8e95cc42009-10-13 08:02:59 +00001551 ipod->ososimage = -1;
Dominik Riebeling24e37dd2012-12-23 23:30:57 +01001552 while ((ipod->nimages < MAX_IMAGES) && (p < (ipod->sectorbuf + x + 400)) &&
Dave Chapman564d2492007-08-03 02:12:32 +00001553 ((memcmp(p,"!ATA",4)==0) || (memcmp(p,"DNAN",4)==0))) {
Dave Chapman4b7e1e02006-12-13 09:02:18 +00001554 p+=4;
1555 if (memcmp(p,"soso",4)==0) {
Dave Chapman31aa4522007-02-04 11:42:11 +00001556 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_OSOS;
Dave Chapman8e95cc42009-10-13 08:02:59 +00001557 ipod->ososimage = ipod->nimages;
Dave Chapman4b7e1e02006-12-13 09:02:18 +00001558 } else if (memcmp(p,"crsr",4)==0) {
Dave Chapman31aa4522007-02-04 11:42:11 +00001559 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_RSRC;
Dave Chapman4b7e1e02006-12-13 09:02:18 +00001560 } else if (memcmp(p,"dpua",4)==0) {
Dave Chapman31aa4522007-02-04 11:42:11 +00001561 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_AUPD;
Dave Chapman8e95cc42009-10-13 08:02:59 +00001562 } else if (memcmp(p,"kbso",4)==0) {
1563 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_OSBK;
Dave Chapman4b7e1e02006-12-13 09:02:18 +00001564 } else if (memcmp(p,"ebih",4)==0) {
Dave Chapman31aa4522007-02-04 11:42:11 +00001565 ipod->ipod_directory[ipod->nimages].ftype=FTYPE_HIBE;
Dave Chapman4b7e1e02006-12-13 09:02:18 +00001566 } else {
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001567 fprintf(stderr,"[ERR] Unknown image type %c%c%c%c\n",
1568 p[0],p[1],p[2],p[3]);
Dave Chapman4b7e1e02006-12-13 09:02:18 +00001569 }
1570 p+=4;
Dave Chapman31aa4522007-02-04 11:42:11 +00001571 ipod->ipod_directory[ipod->nimages].id=le2int(p);
Dave Chapman4b7e1e02006-12-13 09:02:18 +00001572 p+=4;
Dave Chapman31aa4522007-02-04 11:42:11 +00001573 ipod->ipod_directory[ipod->nimages].devOffset=le2int(p);
Dave Chapman4b7e1e02006-12-13 09:02:18 +00001574 p+=4;
Dave Chapman31aa4522007-02-04 11:42:11 +00001575 ipod->ipod_directory[ipod->nimages].len=le2int(p);
Dave Chapman4b7e1e02006-12-13 09:02:18 +00001576 p+=4;
Dave Chapman31aa4522007-02-04 11:42:11 +00001577 ipod->ipod_directory[ipod->nimages].addr=le2int(p);
Dave Chapman4b7e1e02006-12-13 09:02:18 +00001578 p+=4;
Dave Chapman31aa4522007-02-04 11:42:11 +00001579 ipod->ipod_directory[ipod->nimages].entryOffset=le2int(p);
Dave Chapman4b7e1e02006-12-13 09:02:18 +00001580 p+=4;
Dave Chapman31aa4522007-02-04 11:42:11 +00001581 ipod->ipod_directory[ipod->nimages].chksum=le2int(p);
Dave Chapman4b7e1e02006-12-13 09:02:18 +00001582 p+=4;
Dave Chapman31aa4522007-02-04 11:42:11 +00001583 ipod->ipod_directory[ipod->nimages].vers=le2int(p);
Dave Chapman4b7e1e02006-12-13 09:02:18 +00001584 p+=4;
Dave Chapman31aa4522007-02-04 11:42:11 +00001585 ipod->ipod_directory[ipod->nimages].loadAddr=le2int(p);
Dave Chapman4b7e1e02006-12-13 09:02:18 +00001586 p+=4;
Dave Chapman31aa4522007-02-04 11:42:11 +00001587 ipod->nimages++;
Dave Chapman4b7e1e02006-12-13 09:02:18 +00001588 }
Dave Chapman31aa4522007-02-04 11:42:11 +00001589
Dave Chapman8e95cc42009-10-13 08:02:59 +00001590 if (ipod->ososimage < 0) {
1591 fprintf(stderr,"[ERR] No OSOS image found.\n");
1592 return -1;
1593 }
1594
Dave Chapman31aa4522007-02-04 11:42:11 +00001595 if ((ipod->nimages > 1) && (version==2)) {
1596 /* The 3g firmware image doesn't appear to have a version, so
1597 let's make one up... Note that this is never written back to the
1598 ipod, so it's OK to do. */
1599
Dave Chapman8e95cc42009-10-13 08:02:59 +00001600 if (ipod->ipod_directory[ipod->ososimage].vers == 0) { ipod->ipod_directory[ipod->ososimage].vers = 3; }
Dave Chapman31aa4522007-02-04 11:42:11 +00001601
1602 ipod->fwoffset = ipod->start;
1603 } else {
1604 ipod->fwoffset = ipod->start + ipod->sector_size;
1605 }
1606
1607 return 0;
Dave Chapman4b7e1e02006-12-13 09:02:18 +00001608}
1609
Dave Chapman31aa4522007-02-04 11:42:11 +00001610int list_images(struct ipod_t* ipod)
Dave Chapman4b7e1e02006-12-13 09:02:18 +00001611{
1612 int i;
1613
Dominik Riebelingd131a312008-06-17 17:52:13 +00001614 if (ipod_verbose) {
Dave Chapman75a11122006-12-14 18:41:03 +00001615 printf(" Type id devOffset len addr entryOffset chksum vers loadAddr devOffset+len\n");
Dave Chapman31aa4522007-02-04 11:42:11 +00001616 for (i = 0 ; i < ipod->nimages; i++) {
Dave Chapman75a11122006-12-14 18:41:03 +00001617 printf("%d - %s 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",i,
Dave Chapman31aa4522007-02-04 11:42:11 +00001618 ftypename[ipod->ipod_directory[i].ftype],
1619 ipod->ipod_directory[i].id,
1620 ipod->ipod_directory[i].devOffset,
1621 ipod->ipod_directory[i].len,
1622 ipod->ipod_directory[i].addr,
1623 ipod->ipod_directory[i].entryOffset,
1624 ipod->ipod_directory[i].chksum,
1625 ipod->ipod_directory[i].vers,
1626 ipod->ipod_directory[i].loadAddr,
1627 ipod->ipod_directory[i].devOffset+((ipod->ipod_directory[i].len+ipod->sector_size-1)&~(ipod->sector_size-1)));
Dave Chapman75a11122006-12-14 18:41:03 +00001628 }
Dave Chapman4b7e1e02006-12-13 09:02:18 +00001629 }
Dave Chapman4b7e1e02006-12-13 09:02:18 +00001630
1631 printf("\n");
1632 printf("Listing firmware partition contents:\n");
1633 printf("\n");
1634
Dave Chapman31aa4522007-02-04 11:42:11 +00001635 for (i = 0 ; i < ipod->nimages; i++) {
Dave Chapman4b7e1e02006-12-13 09:02:18 +00001636 printf("Image %d:\n",i+1);
Dave Chapman31aa4522007-02-04 11:42:11 +00001637 switch(ipod->ipod_directory[i].ftype) {
Dave Chapman4b7e1e02006-12-13 09:02:18 +00001638 case FTYPE_OSOS:
Dave Chapman31aa4522007-02-04 11:42:11 +00001639 if (ipod->ipod_directory[i].entryOffset==0) {
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001640 printf(" Main firmware - %d bytes\n",
Dave Chapman31aa4522007-02-04 11:42:11 +00001641 ipod->ipod_directory[i].len);
Dave Chapman4b7e1e02006-12-13 09:02:18 +00001642 } else {
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001643 printf(" Main firmware - %d bytes\n",
Dave Chapman31aa4522007-02-04 11:42:11 +00001644 ipod->ipod_directory[i].entryOffset);
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001645 printf(" Third-party bootloader - %d bytes\n",
Dave Chapman31aa4522007-02-04 11:42:11 +00001646 ipod->ipod_directory[i].len-ipod->ipod_directory[i].entryOffset);
Dave Chapman4b7e1e02006-12-13 09:02:18 +00001647 }
1648 break;
1649 default:
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001650 printf(" %s - %d bytes\n",
Dave Chapman31aa4522007-02-04 11:42:11 +00001651 ftypename[ipod->ipod_directory[i].ftype],
1652 ipod->ipod_directory[i].len);
Dave Chapman4b7e1e02006-12-13 09:02:18 +00001653 }
1654 }
1655 printf("\n");
1656
1657 return 0;
1658}
1659
Dave Chapman31aa4522007-02-04 11:42:11 +00001660int getmodel(struct ipod_t* ipod, int ipod_version)
Dave Chapman57b84b62006-12-17 23:00:15 +00001661{
1662 switch (ipod_version) {
Dave Chapman6a20def2007-07-26 20:21:11 +00001663 case 0x01:
1664 ipod->modelstr="1st or 2nd Generation";
1665 ipod->modelnum = 19;
1666 ipod->modelname = "1g2g";
1667 ipod->targetname = "ipod1g2g";
1668#ifdef WITH_BOOTOBJS
1669 ipod->bootloader = ipod1g2g;
1670 ipod->bootloader_len = LEN_ipod1g2g;
1671#endif
1672 break;
Dave Chapman31aa4522007-02-04 11:42:11 +00001673 case 0x02:
1674 ipod->modelstr="3rd Generation";
1675 ipod->modelnum = 7;
1676 ipod->modelname = "ip3g";
Dave Chapmana6d68bd2007-02-10 20:09:23 +00001677 ipod->targetname = "ipod3g";
Dave Chapmanbdc27ff2007-02-08 18:05:50 +00001678#ifdef WITH_BOOTOBJS
1679 ipod->bootloader = ipod3g;
1680 ipod->bootloader_len = LEN_ipod3g;
1681#endif
Dave Chapman57b84b62006-12-17 23:00:15 +00001682 break;
Dave Chapman31aa4522007-02-04 11:42:11 +00001683 case 0x40:
1684 ipod->modelstr="1st Generation Mini";
1685 ipod->modelnum = 9;
1686 ipod->modelname = "mini";
Dominik Wengerac3db332007-08-24 08:10:19 +00001687 ipod->targetname = "ipodmini1g";
Dave Chapmanbdc27ff2007-02-08 18:05:50 +00001688#ifdef WITH_BOOTOBJS
Dave Chapman5742f892009-12-09 13:13:58 +00001689 ipod->bootloader = ipodmini1g;
1690 ipod->bootloader_len = LEN_ipodmini1g;
Dave Chapmanbdc27ff2007-02-08 18:05:50 +00001691#endif
Dave Chapman57b84b62006-12-17 23:00:15 +00001692 break;
Dave Chapman31aa4522007-02-04 11:42:11 +00001693 case 0x50:
1694 ipod->modelstr="4th Generation";
1695 ipod->modelnum = 8;
1696 ipod->modelname = "ip4g";
Dominik Wengerac3db332007-08-24 08:10:19 +00001697 ipod->targetname = "ipod4gray";
Dave Chapmanbdc27ff2007-02-08 18:05:50 +00001698#ifdef WITH_BOOTOBJS
1699 ipod->bootloader = ipod4g;
1700 ipod->bootloader_len = LEN_ipod4g;
1701#endif
Dave Chapman57b84b62006-12-17 23:00:15 +00001702 break;
Dave Chapman31aa4522007-02-04 11:42:11 +00001703 case 0x60:
1704 ipod->modelstr="Photo/Color";
1705 ipod->modelnum = 3;
1706 ipod->modelname = "ipco";
Dave Chapmana6d68bd2007-02-10 20:09:23 +00001707 ipod->targetname = "ipodcolor";
Dave Chapmanbdc27ff2007-02-08 18:05:50 +00001708#ifdef WITH_BOOTOBJS
1709 ipod->bootloader = ipodcolor;
1710 ipod->bootloader_len = LEN_ipodcolor;
1711#endif
Dave Chapman57b84b62006-12-17 23:00:15 +00001712 break;
Dave Chapman31aa4522007-02-04 11:42:11 +00001713 case 0x70:
1714 ipod->modelstr="2nd Generation Mini";
1715 ipod->modelnum = 11;
1716 ipod->modelname = "mn2g";
Dave Chapmana6d68bd2007-02-10 20:09:23 +00001717 ipod->targetname = "ipodmini2g";
Dave Chapmanbdc27ff2007-02-08 18:05:50 +00001718#ifdef WITH_BOOTOBJS
1719 ipod->bootloader = ipodmini2g;
1720 ipod->bootloader_len = LEN_ipodmini2g;
1721#endif
Dave Chapman57b84b62006-12-17 23:00:15 +00001722 break;
Dave Chapman31aa4522007-02-04 11:42:11 +00001723 case 0xc0:
1724 ipod->modelstr="1st Generation Nano";
1725 ipod->modelnum = 4;
1726 ipod->modelname = "nano";
Björn Stenbergc0740442009-12-07 12:19:08 +00001727 ipod->targetname = "ipodnano1g";
Dave Chapmanbdc27ff2007-02-08 18:05:50 +00001728#ifdef WITH_BOOTOBJS
Dave Chapman5742f892009-12-09 13:13:58 +00001729 ipod->bootloader = ipodnano1g;
1730 ipod->bootloader_len = LEN_ipodnano1g;
Dave Chapmanbdc27ff2007-02-08 18:05:50 +00001731#endif
Dave Chapman57b84b62006-12-17 23:00:15 +00001732 break;
Dave Chapman31aa4522007-02-04 11:42:11 +00001733 case 0xb0:
1734 ipod->modelstr="Video (aka 5th Generation)";
1735 ipod->modelnum = 5;
1736 ipod->modelname = "ipvd";
Dominik Riebeling0110e552010-09-01 17:47:33 +00001737 ipod->targetname = "ipodvideo";
Dave Chapmanbdc27ff2007-02-08 18:05:50 +00001738#ifdef WITH_BOOTOBJS
1739 ipod->bootloader = ipodvideo;
1740 ipod->bootloader_len = LEN_ipodvideo;
1741#endif
Dave Chapman57b84b62006-12-17 23:00:15 +00001742 break;
Dave Chapman564d2492007-08-03 02:12:32 +00001743 case 0x100:
1744 ipod->modelstr="2nd Generation Nano";
Dave Chapman8e95cc42009-10-13 08:02:59 +00001745 ipod->modelnum = 62;
1746 ipod->modelname = "nn2x";
1747 ipod->targetname = "ipodnano2g";
Dave Chapman564d2492007-08-03 02:12:32 +00001748#ifdef WITH_BOOTOBJS
Dave Chapman8e95cc42009-10-13 08:02:59 +00001749 ipod->bootloader = ipodnano2g;
1750 ipod->bootloader_len = LEN_ipodnano2g;
Dave Chapman564d2492007-08-03 02:12:32 +00001751#endif
1752 break;
Dave Chapman57b84b62006-12-17 23:00:15 +00001753 default:
Dave Chapman31aa4522007-02-04 11:42:11 +00001754 ipod->modelname = NULL;
1755 ipod->modelnum = 0;
Dave Chapmana6d68bd2007-02-10 20:09:23 +00001756 ipod->targetname = NULL;
Dave Chapmanbdc27ff2007-02-08 18:05:50 +00001757#ifdef WITH_BOOTOBJS
1758 ipod->bootloader = NULL;
1759 ipod->bootloader_len = 0;
1760#endif
Dave Chapman57b84b62006-12-17 23:00:15 +00001761 return -1;
1762 }
1763 return 0;
1764}
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001765
Dominik Riebeling194b2ca2008-05-04 11:59:04 +00001766/* returns number of found ipods or -1 if no ipods found and permission
1767 * for raw disc access was denied. */
Dave Chapman31aa4522007-02-04 11:42:11 +00001768int ipod_scan(struct ipod_t* ipod)
Dave Chapman57b84b62006-12-17 23:00:15 +00001769{
1770 int i;
1771 int n = 0;
Dave Chapman57b84b62006-12-17 23:00:15 +00001772 int ipod_version;
Dominik Riebelingbbfe5732009-11-22 16:35:35 +00001773 struct ipod_t ipod_found;
Dominik Riebeling194b2ca2008-05-04 11:59:04 +00001774 int denied = 0;
1775 int result;
Dave Chapmanc5e30e12006-12-14 01:24:05 +00001776
Dave Chapman57b84b62006-12-17 23:00:15 +00001777 printf("[INFO] Scanning disk devices...\n");
1778
Dave Chapman6e641e82007-02-05 18:29:39 +00001779 for (i = 0; i <= 25 ; i++) {
Dave Chapman57b84b62006-12-17 23:00:15 +00001780#ifdef __WIN32__
Dave Chapman31aa4522007-02-04 11:42:11 +00001781 sprintf(ipod->diskname,"\\\\.\\PhysicalDrive%d",i);
Dave Chapman57b84b62006-12-17 23:00:15 +00001782#elif defined(linux) || defined (__linux)
Dave Chapman31aa4522007-02-04 11:42:11 +00001783 sprintf(ipod->diskname,"/dev/sd%c",'a'+i);
Dave Chapman57b84b62006-12-17 23:00:15 +00001784#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) \
1785 || defined(__bsdi__) || defined(__DragonFly__)
Dave Chapman31aa4522007-02-04 11:42:11 +00001786 sprintf(ipod->diskname,"/dev/da%d",i);
Dave Chapman57b84b62006-12-17 23:00:15 +00001787#elif defined(__APPLE__) && defined(__MACH__)
Dave Chapman31aa4522007-02-04 11:42:11 +00001788 sprintf(ipod->diskname,"/dev/disk%d",i);
Dave Chapman57b84b62006-12-17 23:00:15 +00001789#else
1790 #error No disk paths defined for this platform
1791#endif
Dominik Riebeling194b2ca2008-05-04 11:59:04 +00001792 if ((result = ipod_open(ipod, 1)) < 0) {
1793 if(result == -2) {
1794 denied++;
1795 }
Dominik Riebeling08574c42008-06-30 19:01:51 +00001796 ipod_close(ipod);
Dave Chapman57b84b62006-12-17 23:00:15 +00001797 continue;
1798 }
1799
Dave Chapman31aa4522007-02-04 11:42:11 +00001800 if (read_partinfo(ipod,1) < 0) {
Dominik Riebeling08574c42008-06-30 19:01:51 +00001801 ipod_close(ipod);
Dave Chapman57b84b62006-12-17 23:00:15 +00001802 continue;
1803 }
1804
Dave Chapman31aa4522007-02-04 11:42:11 +00001805 if ((ipod->pinfo[0].start==0) || (ipod->pinfo[0].type != 0)) {
Dominik Riebeling08574c42008-06-30 19:01:51 +00001806 ipod_close(ipod);
Dave Chapman57b84b62006-12-17 23:00:15 +00001807 continue;
1808 }
1809
Dave Chapman31aa4522007-02-04 11:42:11 +00001810 if (read_directory(ipod) < 0) {
Dominik Riebeling08574c42008-06-30 19:01:51 +00001811 ipod_close(ipod);
Dave Chapman57b84b62006-12-17 23:00:15 +00001812 continue;
1813 }
1814
Dave Chapman8e95cc42009-10-13 08:02:59 +00001815 ipod_version=(ipod->ipod_directory[ipod->ososimage].vers>>8);
Dominik Riebeling4e4510e2009-09-25 08:39:08 +00001816 ipod->ramsize = 0;
Dominik Riebelingbbfe573