diff options
Diffstat (limited to 'utils/chinachippatcher')
-rw-r--r-- | utils/chinachippatcher/Makefile | 17 | ||||
-rw-r--r-- | utils/chinachippatcher/chinachip.c | 258 | ||||
-rw-r--r-- | utils/chinachippatcher/chinachip.h | 52 | ||||
-rw-r--r-- | utils/chinachippatcher/main.c | 55 |
4 files changed, 382 insertions, 0 deletions
diff --git a/utils/chinachippatcher/Makefile b/utils/chinachippatcher/Makefile new file mode 100644 index 0000000000..c8defcb5c4 --- /dev/null +++ b/utils/chinachippatcher/Makefile | |||
@@ -0,0 +1,17 @@ | |||
1 | # __________ __ ___. | ||
2 | # Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
3 | # Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
4 | # Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
5 | # Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
6 | # \/ \/ \/ \/ \/ | ||
7 | # $Id$ | ||
8 | # | ||
9 | CFLAGS += -g -Wall | ||
10 | |||
11 | OUTPUT = chinachippatcher | ||
12 | |||
13 | LIBSOURCES = chinachip.c | ||
14 | SOURCES = main.c | ||
15 | |||
16 | include ../libtools.make | ||
17 | |||
diff --git a/utils/chinachippatcher/chinachip.c b/utils/chinachippatcher/chinachip.c new file mode 100644 index 0000000000..79b5acad66 --- /dev/null +++ b/utils/chinachippatcher/chinachip.c | |||
@@ -0,0 +1,258 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2009 by Maurus Cuelenaere | ||
11 | * | ||
12 | * 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. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #include <stdio.h> | ||
22 | #include <stddef.h> | ||
23 | #include <stdlib.h> | ||
24 | #include <stdint.h> | ||
25 | #include <string.h> | ||
26 | #include <time.h> | ||
27 | #include "chinachip.h" | ||
28 | |||
29 | /* From http://www.rockbox.org/wiki/ChinaChip */ | ||
30 | struct header | ||
31 | { | ||
32 | uint32_t signature; /* WADF */ | ||
33 | uint32_t unk; | ||
34 | int8_t timestamp[12]; /* 200805081100 */ | ||
35 | uint32_t size; | ||
36 | uint32_t checksum; | ||
37 | uint32_t unk2; | ||
38 | int8_t identifier[32]; /* Chinachip PMP firmware V1.0 */ | ||
39 | } __attribute__ ((packed)); | ||
40 | |||
41 | static inline void int2le(unsigned char* addr, unsigned int val) | ||
42 | { | ||
43 | addr[0] = val & 0xff; | ||
44 | addr[1] = (val >> 8) & 0xff; | ||
45 | addr[2] = (val >> 16) & 0xff; | ||
46 | addr[3] = (val >> 24) & 0xff; | ||
47 | } | ||
48 | |||
49 | static inline unsigned int le2int(unsigned char* buf) | ||
50 | { | ||
51 | return (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; | ||
52 | } | ||
53 | |||
54 | static long int filesize(FILE* fd) | ||
55 | { | ||
56 | long int len; | ||
57 | fseek(fd, 0, SEEK_END); | ||
58 | len = ftell(fd); | ||
59 | fseek(fd, 0, SEEK_SET); | ||
60 | return len; | ||
61 | } | ||
62 | |||
63 | #define FCLOSE(fd) fclose(fd); fd = NULL; | ||
64 | #define CCPMPBIN_HEADER_SIZE (sizeof(uint32_t)*2 + sizeof(uint8_t) + 9) | ||
65 | #define TOTAL_SIZE (fsize + CCPMPBIN_HEADER_SIZE + bsize) | ||
66 | enum cc_error chinachip_patch(const char* firmware, const char* bootloader, | ||
67 | const char* output, const char* ccpmp_backup) | ||
68 | { | ||
69 | char header_time[13]; | ||
70 | time_t cur_time; | ||
71 | struct tm* time_info; | ||
72 | unsigned char* buf = NULL; | ||
73 | FILE *fd = NULL, *bd = NULL, *od = NULL; | ||
74 | unsigned int ccpmp_size = 0, i, fsize, bsize; | ||
75 | signed int checksum = 0, ccpmp_pos; | ||
76 | int result = E_OK; | ||
77 | |||
78 | fd = fopen(firmware, "rb"); | ||
79 | if(!fd) | ||
80 | { | ||
81 | fprintf(stderr, "[ERR] Can't open file %s!\n", firmware); | ||
82 | result = E_OPEN_FIRMWARE; | ||
83 | goto err; | ||
84 | } | ||
85 | bd = fopen(bootloader, "rb"); | ||
86 | if(!bd) | ||
87 | { | ||
88 | fprintf(stderr, "[ERR] Can't open file %s!\n", bootloader); | ||
89 | result = E_OPEN_BOOTLOADER; | ||
90 | goto err; | ||
91 | } | ||
92 | |||
93 | bsize = filesize(bd); | ||
94 | fprintf(stderr, "[INFO] Bootloader size is %d bytes\n", bsize); | ||
95 | FCLOSE(bd); | ||
96 | |||
97 | fsize = filesize(fd); | ||
98 | fprintf(stderr, "[INFO] Firmware size is %d bytes\n", fsize); | ||
99 | |||
100 | buf = malloc(TOTAL_SIZE); | ||
101 | if(buf == NULL) | ||
102 | { | ||
103 | fprintf(stderr, "[ERR] Can't allocate %d bytes!\n", fsize); | ||
104 | result = E_MEMALLOC; | ||
105 | goto err; | ||
106 | } | ||
107 | memset(buf, 0, TOTAL_SIZE); | ||
108 | |||
109 | fprintf(stderr, "[INFO] Reading %s into memory...\n", firmware); | ||
110 | if(fread(buf, fsize, 1, fd) != 1) | ||
111 | { | ||
112 | fprintf(stderr, "[ERR] Can't read file %s to memory!\n", firmware); | ||
113 | result = E_LOAD_FIRMWARE; | ||
114 | goto err; | ||
115 | } | ||
116 | FCLOSE(fd); | ||
117 | |||
118 | if(memcmp(buf, "WADF", 4)) | ||
119 | { | ||
120 | fprintf(stderr, "[ERR] File %s isn't a valid ChinaChip firmware!\n", firmware); | ||
121 | result = E_INVALID_FILE; | ||
122 | goto err; | ||
123 | } | ||
124 | |||
125 | ccpmp_pos = -1, i = 0x40; | ||
126 | do | ||
127 | { | ||
128 | int filenamesize = le2int(&buf[i]); | ||
129 | i += sizeof(uint32_t); | ||
130 | |||
131 | if(!strncmp((char*) &buf[i], "ccpmp.bin", 9)) | ||
132 | { | ||
133 | ccpmp_pos = i; | ||
134 | ccpmp_size = le2int(&buf[i + sizeof(uint8_t) + filenamesize]); | ||
135 | } | ||
136 | else | ||
137 | i += filenamesize + le2int(&buf[i + sizeof(uint8_t) + filenamesize]) | ||
138 | + sizeof(uint32_t) + sizeof(uint8_t); | ||
139 | } while(ccpmp_pos < 0 && i < fsize); | ||
140 | |||
141 | if(i >= fsize) | ||
142 | { | ||
143 | fprintf(stderr, "[ERR] Couldn't find ccpmp.bin in %s!\n", firmware); | ||
144 | result = E_NO_CCPMP; | ||
145 | goto err; | ||
146 | } | ||
147 | fprintf(stderr, "[INFO] Found ccpmp.bin at %d bytes\n", ccpmp_pos); | ||
148 | |||
149 | if(ccpmp_backup) | ||
150 | { | ||
151 | int ccpmp_data_pos = ccpmp_pos + 9; | ||
152 | bd = fopen(ccpmp_backup, "wb"); | ||
153 | if(!bd) | ||
154 | { | ||
155 | fprintf(stderr, "[ERR] Can't open file %s!\n", ccpmp_backup); | ||
156 | result = E_OPEN_BACKUP; | ||
157 | goto err; | ||
158 | } | ||
159 | |||
160 | fprintf(stderr, "[INFO] Writing %d bytes to %s...\n", ccpmp_size, ccpmp_backup); | ||
161 | if(fwrite(&buf[ccpmp_data_pos], ccpmp_size, 1, bd) != 1) | ||
162 | { | ||
163 | fprintf(stderr, "[ERR] Can't write to file %s!\n", ccpmp_backup); | ||
164 | result = E_WRITE_BACKUP; | ||
165 | goto err; | ||
166 | } | ||
167 | FCLOSE(bd); | ||
168 | } | ||
169 | |||
170 | fprintf(stderr, "[INFO] Renaming it to ccpmp.old...\n"); | ||
171 | buf[ccpmp_pos + 6] = 'o'; | ||
172 | buf[ccpmp_pos + 7] = 'l'; | ||
173 | buf[ccpmp_pos + 8] = 'd'; | ||
174 | |||
175 | bd = fopen(bootloader, "rb"); | ||
176 | if(!bd) | ||
177 | { | ||
178 | fprintf(stderr, "[ERR] Can't open file %s!\n", bootloader); | ||
179 | result = E_OPEN_BOOTLOADER; | ||
180 | goto err; | ||
181 | } | ||
182 | |||
183 | /* Also include path size */ | ||
184 | ccpmp_pos -= sizeof(uint32_t); | ||
185 | |||
186 | fprintf(stderr, "[INFO] Making place for ccpmp.bin...\n"); | ||
187 | memmove(&buf[ccpmp_pos + bsize + CCPMPBIN_HEADER_SIZE], | ||
188 | &buf[ccpmp_pos], fsize - ccpmp_pos); | ||
189 | |||
190 | fprintf(stderr, "[INFO] Reading %s into memory...\n", bootloader); | ||
191 | if(fread(&buf[ccpmp_pos + CCPMPBIN_HEADER_SIZE], | ||
192 | bsize, 1, bd) != 1) | ||
193 | { | ||
194 | fprintf(stderr, "[ERR] Can't read file %s to memory!\n", bootloader); | ||
195 | result = E_LOAD_BOOTLOADER; | ||
196 | goto err; | ||
197 | } | ||
198 | FCLOSE(bd); | ||
199 | |||
200 | fprintf(stderr, "[INFO] Adding header to %s...\n", bootloader); | ||
201 | int2le(&buf[ccpmp_pos ], 9); /* Pathname Size */ | ||
202 | memcpy(&buf[ccpmp_pos + 4 ], "ccpmp.bin", 9); /* Pathname */ | ||
203 | memset(&buf[ccpmp_pos + 4 + 9 ], 0x20, sizeof(uint8_t)); /* File Type */ | ||
204 | int2le(&buf[ccpmp_pos + 4 + 9 + 1], bsize); /* File Size */ | ||
205 | |||
206 | time(&cur_time); | ||
207 | time_info = localtime(&cur_time); | ||
208 | if(time_info == NULL) | ||
209 | { | ||
210 | fprintf(stderr, "[ERR] Can't obtain current time!\n"); | ||
211 | result = E_GET_TIME; | ||
212 | goto err; | ||
213 | } | ||
214 | |||
215 | snprintf(header_time, 13, "%04d%02d%02d%02d%02d", time_info->tm_year + 1900, | ||
216 | time_info->tm_mon, | ||
217 | time_info->tm_mday, | ||
218 | time_info->tm_hour, | ||
219 | time_info->tm_min); | ||
220 | |||
221 | fprintf(stderr, "[INFO] Computing checksum...\n"); | ||
222 | for(i = sizeof(struct header); i < TOTAL_SIZE; i+=4) | ||
223 | checksum += le2int(&buf[i]); | ||
224 | |||
225 | fprintf(stderr, "[INFO] Updating main header...\n"); | ||
226 | memcpy(&buf[offsetof(struct header, timestamp)], header_time, 12); | ||
227 | int2le(&buf[offsetof(struct header, size) ], TOTAL_SIZE); | ||
228 | int2le(&buf[offsetof(struct header, checksum) ], checksum); | ||
229 | |||
230 | od = fopen(output, "wb"); | ||
231 | if(!od) | ||
232 | { | ||
233 | fprintf(stderr, "[ERR] Can't open file %s!\n", output); | ||
234 | result = E_OPEN_OUTFILE; | ||
235 | goto err; | ||
236 | } | ||
237 | |||
238 | fprintf(stderr, "[INFO] Writing output to %s...\n", output); | ||
239 | if(fwrite(buf, TOTAL_SIZE, 1, od) != 1) | ||
240 | { | ||
241 | fprintf(stderr, "[ERR] Can't write to file %s!\n", output); | ||
242 | result = E_WRITE_OUTFILE; | ||
243 | goto err; | ||
244 | } | ||
245 | |||
246 | err: | ||
247 | if(buf) | ||
248 | free(buf); | ||
249 | if(fd) | ||
250 | fclose(fd); | ||
251 | if(bd) | ||
252 | fclose(bd); | ||
253 | if(od) | ||
254 | fclose(od); | ||
255 | |||
256 | return result; | ||
257 | } | ||
258 | |||
diff --git a/utils/chinachippatcher/chinachip.h b/utils/chinachippatcher/chinachip.h new file mode 100644 index 0000000000..b92066bb8b --- /dev/null +++ b/utils/chinachippatcher/chinachip.h | |||
@@ -0,0 +1,52 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2009 by Maurus Cuelenaere | ||
11 | * | ||
12 | * 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. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #ifndef __INCLUDE_CHINACHIP_H_ | ||
23 | #define __INCLUDE_CHINACHIP_H_ | ||
24 | |||
25 | #ifdef __cplusplus | ||
26 | extern "C" { | ||
27 | #endif | ||
28 | |||
29 | enum cc_error { | ||
30 | E_OK, | ||
31 | E_OPEN_FIRMWARE, | ||
32 | E_OPEN_BOOTLOADER, | ||
33 | E_MEMALLOC, | ||
34 | E_LOAD_FIRMWARE, | ||
35 | E_INVALID_FILE, | ||
36 | E_NO_CCPMP, | ||
37 | E_OPEN_BACKUP, | ||
38 | E_WRITE_BACKUP, | ||
39 | E_LOAD_BOOTLOADER, | ||
40 | E_GET_TIME, | ||
41 | E_OPEN_OUTFILE, | ||
42 | E_WRITE_OUTFILE, | ||
43 | }; | ||
44 | |||
45 | enum cc_error chinachip_patch(const char* firmware, const char* bootloader, | ||
46 | const char* output, const char* ccpmp_backup); | ||
47 | |||
48 | #ifdef __cplusplus | ||
49 | } | ||
50 | #endif | ||
51 | |||
52 | #endif /* __INCLUDE_CHINACHIP_H_ */ | ||
diff --git a/utils/chinachippatcher/main.c b/utils/chinachippatcher/main.c new file mode 100644 index 0000000000..e7779774c9 --- /dev/null +++ b/utils/chinachippatcher/main.c | |||
@@ -0,0 +1,55 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2009 by Maurus Cuelenaere | ||
11 | * | ||
12 | * 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. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #include <stdio.h> | ||
22 | #include <stdarg.h> | ||
23 | #include "chinachip.h" | ||
24 | |||
25 | #ifndef VERSION /* allow setting version from outside for svn builds */ | ||
26 | #define VERSION "0.1" | ||
27 | #endif | ||
28 | #define PRINT(fmt, ...) fprintf(stderr, fmt"\n", ##__VA_ARGS__) | ||
29 | |||
30 | void usage(char* name) | ||
31 | { | ||
32 | PRINT("Usage:"); | ||
33 | PRINT(" %s <firmware> <bootloader> <firmware_output> [backup]", name); | ||
34 | PRINT("\nExample:"); | ||
35 | PRINT(" %s VX747.HXF bootloader.bin output.HXF ccpmp.bak", name); | ||
36 | PRINT(" This will copy ccpmp.bin in VX747.HXF as ccpmp.old and replace it\n" | ||
37 | " with bootloader.bin, the output will get written to output.HXF.\n" | ||
38 | " The old ccpmp.bin will get written to ccpmp.bak.\n"); | ||
39 | } | ||
40 | |||
41 | int main(int argc, char* argv[]) | ||
42 | { | ||
43 | PRINT("ChinaChipPatcher v" VERSION " - (C) Maurus Cuelenaere 2009"); | ||
44 | PRINT("This is free software; see the source for copying conditions. There is NO"); | ||
45 | PRINT("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."); | ||
46 | |||
47 | if(argc < 4) | ||
48 | { | ||
49 | usage(argv[0]); | ||
50 | return 1; | ||
51 | } | ||
52 | |||
53 | return chinachip_patch(argv[1], argv[2], argv[3], argc > 4 ? argv[4] : NULL); | ||
54 | } | ||
55 | |||