summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2017-09-29 18:22:30 +0200
committerAmaury Pouly <amaury.pouly@gmail.com>2017-09-29 18:22:30 +0200
commitea679de8371e4e74fe4e78fb8df8e5df19efffdc (patch)
treec08cf8be057318313a3bcf040395826afe62566b
parent95c32a505a7bfef2dcac2a975b1f5875f490c405 (diff)
downloadrockbox-ea679de8371e4e74fe4e78fb8df8e5df19efffdc.tar.gz
rockbox-ea679de8371e4e74fe4e78fb8df8e5df19efffdc.zip
atjboottool: put afi and fw code in its own files
Change-Id: I16347ebee0f82d5fdf32f5aa8f955c07fe148eba
-rw-r--r--utils/atj2137/atjboottool/Makefile2
-rw-r--r--utils/atj2137/atjboottool/afi.c208
-rw-r--r--utils/atj2137/atjboottool/afi.h8
-rw-r--r--utils/atj2137/atjboottool/atjboottool.c416
-rw-r--r--utils/atj2137/atjboottool/fw.c213
-rw-r--r--utils/atj2137/atjboottool/fw.h34
-rw-r--r--utils/atj2137/atjboottool/fwu.c10
7 files changed, 499 insertions, 392 deletions
diff --git a/utils/atj2137/atjboottool/Makefile b/utils/atj2137/atjboottool/Makefile
index 31c315d4fd..8d96bcdde0 100644
--- a/utils/atj2137/atjboottool/Makefile
+++ b/utils/atj2137/atjboottool/Makefile
@@ -10,7 +10,7 @@ all: $(BINS)
10%.o: %.c 10%.o: %.c
11 $(CC) $(CFLAGS) -c -o $@ $< 11 $(CC) $(CFLAGS) -c -o $@ $<
12 12
13atjboottool: atjboottool.o fwu.o misc.o atj_tables.o 13atjboottool: atjboottool.o fwu.o fw.o afi.o misc.o atj_tables.o
14 $(LD) -o $@ $^ $(LDFLAGS) 14 $(LD) -o $@ $^ $(LDFLAGS)
15 15
16clean: 16clean:
diff --git a/utils/atj2137/atjboottool/afi.c b/utils/atj2137/atjboottool/afi.c
new file mode 100644
index 0000000000..1ce9d0c01e
--- /dev/null
+++ b/utils/atj2137/atjboottool/afi.c
@@ -0,0 +1,208 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2017 Amaury Pouly
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 <string.h>
22#include <stdlib.h>
23#include <ctype.h>
24#include "misc.h"
25#include "afi.h"
26
27/** part of this work comes from s1mp3/s1fwx */
28
29#define AFI_ENTRIES 126
30#define AFI_SIG_SIZE 4
31
32struct afi_hdr_t
33{
34 uint8_t sig[AFI_SIG_SIZE];
35 uint16_t vendor_id;
36 uint16_t product_id;
37 uint8_t ver_id[2];
38 uint8_t ext_ver_id[2];
39 uint8_t year[2];
40 uint8_t month;
41 uint8_t day;
42 uint32_t afi_size;
43 uint32_t res[3];
44} __attribute__((packed));
45
46struct afi_entry_t
47{
48 char name[8];
49 char ext[3];
50 char type;
51 uint32_t addr;
52 uint32_t offset;
53 uint32_t size;
54 char desc[4];
55 uint32_t checksum;
56} __attribute__((packed));
57
58struct afi_post_hdr_t
59{
60 uint8_t res[28];
61 uint32_t checksum;
62} __attribute__((packed));
63
64struct afi_t
65{
66 struct afi_hdr_t hdr;
67 struct afi_entry_t entry[AFI_ENTRIES];
68 struct afi_post_hdr_t post;
69};
70
71#define AFI_ENTRY_BREC 'B'
72#define AFI_ENTRY_FWSC 'F'
73#define AFI_ENTRY_ADFUS 'A'
74#define AFI_ENTRY_FW 'I'
75
76#define AFI_ENTRY_DLADR_BREC 0x00000006 // 'B'
77#define AFI_ENTRY_DLADR_FWSC 0x00020008 // 'F'
78#define AFI_ENTRY_DLADR_ADFUS 0x000C0008 // 'A'
79#define AFI_ENTRY_DLADR_ADFU 0x00000000 // 'U'
80#define AFI_ENTRY_DLADR_FW 0x00000011 // 'I'
81
82const uint8_t g_afi_signature[AFI_SIG_SIZE] =
83{
84 'A', 'F', 'I', 0
85};
86
87uint32_t afi_checksum(void *ptr, size_t size)
88{
89 uint32_t crc = 0;
90 uint32_t *cp = ptr;
91 for(; size >= 4; size -= 4)
92 crc += *cp++;
93 if(size == 1)
94 crc += *(uint8_t *)cp;
95 else if(size == 2)
96 crc += *(uint16_t *)cp;
97 else if(size == 3)
98 crc += *(uint16_t *)cp + ((*(uint8_t *)(cp + 2)) << 16);
99 return crc;
100}
101
102static void build_filename(char buf[16], struct afi_entry_t *ent)
103{
104 int pos = 0;
105 for(int i = 0; i < 8 && ent->name[i] != ' '; i++)
106 buf[pos++] = ent->name[i];
107 buf[pos++] = '.';
108 for(int i = 0; i < 3 && ent->ext[i] != ' '; i++)
109 buf[pos++] = ent->ext[i];
110 buf[pos] = 0;
111}
112
113int afi_unpack(uint8_t *buf, size_t size, afi_extract_callback_t unpack_cb)
114{
115 struct afi_t *afi = (void *)buf;
116
117 if(size < sizeof(struct afi_t))
118 {
119 cprintf(GREY, "File too small\n");
120 return 1;
121 }
122 cprintf(BLUE, "Header\n");
123 cprintf(GREEN, " Signature:");
124 for(int i = 0; i < AFI_SIG_SIZE; i++)
125 cprintf(YELLOW, " %02x", afi->hdr.sig[i]);
126 if(memcmp(afi->hdr.sig, g_afi_signature, AFI_SIG_SIZE) == 0)
127 cprintf(RED, " Ok\n");
128 else
129 {
130 cprintf(RED, " Mismatch\n");
131 return 1;
132 }
133
134 cprintf_field(" Vendor ID: ", "0x%x\n", afi->hdr.vendor_id);
135 cprintf_field(" Product ID: ", "0x%x\n", afi->hdr.product_id);
136 cprintf_field(" Version: ", "%x.%x\n", afi->hdr.ver_id[0], afi->hdr.ver_id[1]);
137 cprintf_field(" Ext Version: ", "%x.%x\n", afi->hdr.ext_ver_id[0],
138 afi->hdr.ext_ver_id[1]);
139 cprintf_field(" Date: ", "%02x/%02x/%02x%02x\n", afi->hdr.day, afi->hdr.month,
140 afi->hdr.year[0], afi->hdr.year[1]);
141
142 cprintf_field(" AFI size: ", "%d ", afi->hdr.afi_size);
143 if(afi->hdr.afi_size == size)
144 cprintf(RED, " Ok\n");
145 else if(afi->hdr.afi_size < size)
146 cprintf(RED, " Ok (file greater than archive)\n");
147 else
148 {
149 cprintf(RED, " Error (file too small)\n");
150 return 1;
151 }
152
153 cprintf_field(" Reserved: ", "%x %x %x\n", afi->hdr.res[0],
154 afi->hdr.res[1], afi->hdr.res[2]);
155
156 cprintf(BLUE, "Entries\n");
157 for(int i = 0; i < AFI_ENTRIES; i++)
158 {
159 if(afi->entry[i].name[0] == 0)
160 continue;
161 struct afi_entry_t *entry = &afi->entry[i];
162 char filename[16];
163 build_filename(filename, entry);
164 cprintf(RED, " %s\n", filename);
165 cprintf_field(" Type: ", "%02x", entry->type);
166 if(isprint(entry->type))
167 cprintf(RED, " %c", entry->type);
168 printf("\n");
169 cprintf_field(" Addr: ", "0x%x\n", entry->addr);
170 cprintf_field(" Offset: ", "0x%x\n", entry->offset);
171 cprintf_field(" Size: ", "0x%x\n", entry->size);
172 cprintf_field(" Desc: ", "%.4s\n", entry->desc);
173 cprintf_field(" Checksum: ", "0x%x ", entry->checksum);
174 uint32_t chk = afi_checksum(buf + entry->offset, entry->size);
175 if(chk != entry->checksum)
176 {
177 cprintf(RED, "Mismatch\n");
178 return 1;
179 }
180 else
181 cprintf(RED, "Ok\n");
182 int ret = unpack_cb(filename, buf + entry->offset, entry->size);
183 if(ret != 0)
184 return ret;
185 }
186
187 cprintf(BLUE, "Post Header\n");
188 cprintf_field(" Checksum: ", "%x ", afi->post.checksum);
189 uint32_t chk = afi_checksum(buf, sizeof(struct afi_t) - 4);
190 if(chk != afi->post.checksum)
191 {
192 cprintf(RED, "Mismatch\n");
193 return 1;
194 }
195 else
196 cprintf(RED, "Ok\n");
197
198 return 0;
199}
200
201bool afi_check(uint8_t *buf, size_t size)
202{
203 struct afi_hdr_t *hdr = (void *)buf;
204
205 if(size < sizeof(struct afi_hdr_t))
206 return false;
207 return memcmp(hdr->sig, g_afi_signature, AFI_SIG_SIZE) == 0;
208}
diff --git a/utils/atj2137/atjboottool/afi.h b/utils/atj2137/atjboottool/afi.h
index bb264cefdf..6756364d2a 100644
--- a/utils/atj2137/atjboottool/afi.h
+++ b/utils/atj2137/atjboottool/afi.h
@@ -23,7 +23,13 @@
23 23
24#include <stdint.h> 24#include <stdint.h>
25 25
26/* Check if a file looks like a FWU file */ 26uint32_t afi_checksum(void *ptr, size_t size);
27/* Unpack an AFI file: the callback function will be called once for each file in the archive with
28 * its name and content. If the callback returns a nonzero value, the function will stop and return
29 * that value. Returns 0 on success */
30typedef int (*afi_extract_callback_t)(const char *name, uint8_t *buf, size_t size);
31int afi_unpack(uint8_t *buf, size_t size, afi_extract_callback_t cb);
32/* Check if a file looks like an AFI file */
27bool afi_check(uint8_t *buf, size_t size); 33bool afi_check(uint8_t *buf, size_t size);
28 34
29#endif /* __AFI_H__ */ 35#endif /* __AFI_H__ */
diff --git a/utils/atj2137/atjboottool/atjboottool.c b/utils/atj2137/atjboottool/atjboottool.c
index 676fdae199..d0ad1b468b 100644
--- a/utils/atj2137/atjboottool/atjboottool.c
+++ b/utils/atj2137/atjboottool/atjboottool.c
@@ -29,6 +29,8 @@
29#include <sys/stat.h> 29#include <sys/stat.h>
30#include "misc.h" 30#include "misc.h"
31#include "fwu.h" 31#include "fwu.h"
32#include "afi.h"
33#include "fw.h"
32 34
33bool g_debug = false; 35bool g_debug = false;
34char *g_out_prefix = NULL; 36char *g_out_prefix = NULL;
@@ -89,407 +91,51 @@ static int do_fwu(uint8_t *buf, size_t size, enum fwu_mode_t mode)
89 } 91 }
90} 92}
91 93
92/** 94static int unpack_afi_fw_cb(const char *filename, uint8_t *buf, size_t size)
93 * AFI
94 *
95 * part of this work comes from s1mp3/s1fwx
96 **/
97
98#define AFI_ENTRIES 126
99#define AFI_SIG_SIZE 4
100
101struct afi_hdr_t
102{
103 uint8_t sig[AFI_SIG_SIZE];
104 uint16_t vendor_id;
105 uint16_t product_id;
106 uint8_t ver_id[2];
107 uint8_t ext_ver_id[2];
108 uint8_t year[2];
109 uint8_t month;
110 uint8_t day;
111 uint32_t afi_size;
112 uint32_t res[3];
113} __attribute__((packed));
114
115struct afi_entry_t
116{
117 char name[8];
118 char ext[3];
119 char type;
120 uint32_t addr;
121 uint32_t offset;
122 uint32_t size;
123 char desc[4];
124 uint32_t checksum;
125} __attribute__((packed));
126
127struct afi_post_hdr_t
128{
129 uint8_t res[28];
130 uint32_t checksum;
131} __attribute__((packed));
132
133struct afi_t
134{
135 struct afi_hdr_t hdr;
136 struct afi_entry_t entry[AFI_ENTRIES];
137 struct afi_post_hdr_t post;
138};
139
140#define AFI_ENTRY_BREC 'B'
141#define AFI_ENTRY_FWSC 'F'
142#define AFI_ENTRY_ADFUS 'A'
143#define AFI_ENTRY_FW 'I'
144
145#define AFI_ENTRY_DLADR_BREC 0x00000006 // 'B'
146#define AFI_ENTRY_DLADR_FWSC 0x00020008 // 'F'
147#define AFI_ENTRY_DLADR_ADFUS 0x000C0008 // 'A'
148#define AFI_ENTRY_DLADR_ADFU 0x00000000 // 'U'
149#define AFI_ENTRY_DLADR_FW 0x00000011 // 'I'
150
151const uint8_t g_afi_signature[AFI_SIG_SIZE] =
152{ 95{
153 'A', 'F', 'I', 0 96 char *name = malloc(strlen(g_out_prefix) + strlen(filename) + 16);
154}; 97 sprintf(name, "%s%s", g_out_prefix, filename);
155 98
156static uint32_t afi_checksum(void *ptr, int size) 99 cprintf(GREY, "Unpacking to %s... ", name);
157{ 100 FILE *f = fopen(name, "wb");
158 uint32_t crc = 0; 101 if(f)
159 uint32_t *cp = ptr;
160 for(; size >= 4; size -= 4)
161 crc += *cp++;
162 if(size == 1)
163 crc += *(uint8_t *)cp;
164 else if(size == 2)
165 crc += *(uint16_t *)cp;
166 else if(size == 3)
167 crc += *(uint16_t *)cp + ((*(uint8_t *)(cp + 2)) << 16);
168 return crc;
169}
170
171static void build_filename(char buf[16], struct afi_entry_t *ent)
172{
173 int pos = 0;
174 for(int i = 0; i < 8 && ent->name[i] != ' '; i++)
175 buf[pos++] = ent->name[i];
176 buf[pos++] = '.';
177 for(int i = 0; i < 3 && ent->ext[i] != ' '; i++)
178 buf[pos++] = ent->ext[i];
179 buf[pos] = 0;
180}
181
182static int do_afi(uint8_t *buf, int size)
183{
184 struct afi_t *afi = (void *)buf;
185
186 if(size < (int)sizeof(struct afi_t))
187 {
188 cprintf(GREY, "File too small\n");
189 return 1;
190 }
191 cprintf(BLUE, "Header\n");
192 cprintf(GREEN, " Signature:");
193 for(int i = 0; i < AFI_SIG_SIZE; i++)
194 cprintf(YELLOW, " %02x", afi->hdr.sig[i]);
195 if(memcmp(afi->hdr.sig, g_afi_signature, AFI_SIG_SIZE) == 0)
196 cprintf(RED, " Ok\n");
197 else
198 { 102 {
199 cprintf(RED, " Mismatch\n"); 103 fwrite(buf, size, 1, f);
200 return 1; 104 fclose(f);
105 cprintf(RED, "Ok\n");
106 return 0;
201 } 107 }
202
203 cprintf_field(" Vendor ID: ", "0x%x\n", afi->hdr.vendor_id);
204 cprintf_field(" Product ID: ", "0x%x\n", afi->hdr.product_id);
205 cprintf_field(" Version: ", "%x.%x\n", afi->hdr.ver_id[0], afi->hdr.ver_id[1]);
206 cprintf_field(" Ext Version: ", "%x.%x\n", afi->hdr.ext_ver_id[0],
207 afi->hdr.ext_ver_id[1]);
208 cprintf_field(" Date: ", "%02x/%02x/%02x%02x\n", afi->hdr.day, afi->hdr.month,
209 afi->hdr.year[0], afi->hdr.year[1]);
210
211 cprintf_field(" AFI size: ", "%d ", afi->hdr.afi_size);
212 if((int)afi->hdr.afi_size == size)
213 cprintf(RED, " Ok\n");
214 else if((int)afi->hdr.afi_size < size)
215 cprintf(RED, " Ok (file greater than archive)\n");
216 else 108 else
217 { 109 {
218 cprintf(RED, " Error (file too small)\n"); 110 color(RED);
111 perror("Failed");
219 return 1; 112 return 1;
220 } 113 }
221
222 cprintf_field(" Reserved: ", "%x %x %x\n", afi->hdr.res[0],
223 afi->hdr.res[1], afi->hdr.res[2]);
224
225 build_out_prefix(".fw", "", true);
226
227 cprintf(BLUE, "Entries\n");
228 for(int i = 0; i < AFI_ENTRIES; i++)
229 {
230 if(afi->entry[i].name[0] == 0)
231 continue;
232 struct afi_entry_t *entry = &afi->entry[i];
233 char filename[16];
234 build_filename(filename, entry);
235 cprintf(RED, " %s\n", filename);
236 cprintf_field(" Type: ", "%02x", entry->type);
237 if(isprint(entry->type))
238 cprintf(RED, " %c", entry->type);
239 printf("\n");
240 cprintf_field(" Addr: ", "0x%x\n", entry->addr);
241 cprintf_field(" Offset: ", "0x%x\n", entry->offset);
242 cprintf_field(" Size: ", "0x%x\n", entry->size);
243 cprintf_field(" Desc: ", "%.4s\n", entry->desc);
244 cprintf_field(" Checksum: ", "0x%x ", entry->checksum);
245 uint32_t chk = afi_checksum(buf + entry->offset, entry->size);
246 cprintf(RED, "%s\n", chk == entry->checksum ? "Ok" : "Mismatch");
247
248 char *name = malloc(strlen(g_out_prefix) + strlen(filename) + 16);
249 sprintf(name, "%s%s", g_out_prefix, filename);
250
251 cprintf(GREY, "Unpacking to %s... ", name);
252 FILE *f = fopen(name, "wb");
253 if(f)
254 {
255 fwrite(buf + entry->offset, entry->size, 1, f);
256 fclose(f);
257 cprintf(RED, "Ok\n");
258 }
259 else
260 cprintf(RED, "Failed: %m\n");
261 }
262
263 cprintf(BLUE, "Post Header\n");
264 cprintf_field(" Checksum: ", "%x ", afi->post.checksum);
265 uint32_t chk = afi_checksum(buf, sizeof(struct afi_t) - 4);
266 cprintf(RED, "%s\n", chk == afi->post.checksum ? "Ok" : "Mismatch");
267
268 return 0;
269} 114}
270 115
271bool afi_check(uint8_t *buf, int size) 116static int do_afi(uint8_t *buf, size_t size)
272{ 117{
273 struct afi_hdr_t *hdr = (void *)buf; 118 build_out_prefix(".fw", "", true);
274 119 return afi_unpack(buf, size, &unpack_afi_fw_cb);
275 if(size < (int)sizeof(struct afi_hdr_t))
276 return false;
277 return memcmp(hdr->sig, g_afi_signature, AFI_SIG_SIZE) == 0;
278}
279
280/**
281 * FW
282 **/
283
284#define FW_SIG_SIZE 4
285
286#define FW_ENTRIES 240
287
288struct fw_entry_t
289{
290 char name[8];
291 char ext[3];
292 uint8_t attr;
293 uint8_t res[2];
294 uint16_t version;
295 uint32_t block_offset; // offset shift by 9
296 uint32_t size;
297 uint32_t unk;
298 uint32_t checksum;
299} __attribute__((packed));
300
301struct fw_hdr_t
302{
303 uint8_t sig[FW_SIG_SIZE];
304 uint32_t res[4];
305 uint8_t year[2];
306 uint8_t month;
307 uint8_t day;
308 uint16_t usb_vid;
309 uint16_t usb_pid;
310 uint32_t checksum;
311 char productor[16];
312 char str2[16];
313 char str3[32];
314 char dev_name[32];
315 uint8_t res2[8 * 16];
316 char usb_name1[8];
317 char usb_name2[8];
318 char res3[4 * 16 + 1];
319 char mtp_name1[33];
320 char mtp_name2[33];
321 char mtp_ver[33];
322 uint16_t mtp_vid;
323 uint16_t mtp_pid;
324 char fw_ver[64];
325 uint32_t res4[2];
326
327 struct fw_entry_t entry[FW_ENTRIES];
328} __attribute__((packed));
329
330/* the s1fwx source code has a layout but it does not make any sense for firmwares
331 * found in ATJ2127 for example. In doubt just don't do anything */
332struct fw_hdr_f0_t
333{
334 uint8_t sig[FW_SIG_SIZE];
335 uint8_t res[12];
336 uint32_t checksum;
337 uint8_t res2[492];
338
339 struct fw_entry_t entry[FW_ENTRIES];
340} __attribute__((packed));
341
342const uint8_t g_fw_signature_f2[FW_SIG_SIZE] =
343{
344 0x55, 0xaa, 0xf2, 0x0f
345};
346
347const uint8_t g_fw_signature_f0[FW_SIG_SIZE] =
348{
349 0x55, 0xaa, 0xf0, 0x0f
350};
351
352static void build_filename_fw(char buf[16], struct fw_entry_t *ent)
353{
354 int pos = 0;
355 for(int i = 0; i < 8 && ent->name[i] != ' '; i++)
356 buf[pos++] = ent->name[i];
357 buf[pos++] = '.';
358 for(int i = 0; i < 3 && ent->ext[i] != ' '; i++)
359 buf[pos++] = ent->ext[i];
360 buf[pos] = 0;
361} 120}
362 121
363static int do_fw(uint8_t *buf, int size) 122static int do_fw(uint8_t *buf, size_t size)
364{ 123{
365 struct fw_hdr_t *hdr = (void *)buf;
366
367 if(size < (int)sizeof(struct fw_hdr_t))
368 {
369 cprintf(GREY, "File too small\n");
370 return 1;
371 }
372 cprintf(BLUE, "Header\n");
373 cprintf(GREEN, " Signature:");
374 for(int i = 0; i < FW_SIG_SIZE; i++)
375 cprintf(YELLOW, " %02x", hdr->sig[i]);
376 int variant = 0;
377 if(memcmp(hdr->sig, g_fw_signature_f2, FW_SIG_SIZE) == 0)
378 {
379 variant = 0xf2;
380 cprintf(RED, " Ok (f2 variant)\n");
381 }
382 else if(memcmp(hdr->sig, g_fw_signature_f0, FW_SIG_SIZE) == 0)
383 {
384 variant = 0xf0;
385 cprintf(RED, " Ok (f0 variant)\n");
386 }
387 else
388 {
389 cprintf(RED, " Mismatch\n");
390 return 1;
391 }
392
393 /* both variants have the same header size, only the fields differ */
394 if(variant == 0xf2)
395 {
396 cprintf_field(" USB VID: ", "0x%x\n", hdr->usb_vid);
397 cprintf_field(" USB PID: ", "0x%x\n", hdr->usb_pid);
398 cprintf_field(" Date: ", "%x/%x/%02x%02x\n", hdr->day, hdr->month, hdr->year[0], hdr->year[1]);
399 cprintf_field(" Checksum: ", "%x\n", hdr->checksum);
400 cprintf_field(" Productor: ", "%.16s\n", hdr->productor);
401 cprintf_field(" String 2: ", "%.16s\n", hdr->str2);
402 cprintf_field(" String 3: ", "%.32s\n", hdr->str3);
403 cprintf_field(" Device Name: ", "%.32s\n", hdr->dev_name);
404 cprintf(GREEN, " Unknown:\n");
405 for(int i = 0; i < 8; i++)
406 {
407 cprintf(YELLOW, " ");
408 for(int j = 0; j < 16; j++)
409 cprintf(YELLOW, "%02x ", hdr->res2[i * 16 + j]);
410 cprintf(YELLOW, "\n");
411 }
412 cprintf_field(" USB Name 1: ", "%.8s\n", hdr->usb_name1);
413 cprintf_field(" USB Name 2: ", "%.8s\n", hdr->usb_name2);
414 cprintf_field(" MTP Name 1: ", "%.32s\n", hdr->mtp_name1);
415 cprintf_field(" MTP Name 2: ", "%.32s\n", hdr->mtp_name2);
416 cprintf_field(" MTP Version: ", "%.32s\n", hdr->mtp_ver);
417
418 cprintf_field(" MTP VID: ", "0x%x\n", hdr->mtp_vid);
419 cprintf_field(" MTP PID: ", "0x%x\n", hdr->mtp_pid);
420 cprintf_field(" FW Version: ", "%.64s\n", hdr->fw_ver);
421 }
422 else
423 {
424 /* struct fw_hdr_f0_t *hdr_f0 = (void *)hdr; */
425 cprintf(GREEN, " Header not dumped because format is unclear.\n");
426 }
427
428 build_out_prefix(".unpack", "", true); 124 build_out_prefix(".unpack", "", true);
429 125 return fw_unpack(buf, size, &unpack_afi_fw_cb);
430 cprintf(BLUE, "Entries\n");
431 for(int i = 0; i < AFI_ENTRIES; i++)
432 {
433 if(hdr->entry[i].name[0] == 0)
434 continue;
435 struct fw_entry_t *entry = &hdr->entry[i];
436 char filename[16];
437 build_filename_fw(filename, entry);
438 cprintf(RED, " %s\n", filename);
439 cprintf_field(" Attr: ", "%02x\n", entry->attr);
440 cprintf_field(" Offset: ", "0x%x\n", entry->block_offset << 9);
441 cprintf_field(" Size: ", "0x%x\n", entry->size);
442 cprintf_field(" Unknown: ", "%x\n", entry->unk);
443 cprintf_field(" Checksum: ", "0x%x ", entry->checksum);
444 uint32_t chk = afi_checksum(buf + (entry->block_offset << 9), entry->size);
445 cprintf(RED, "%s\n", chk == entry->checksum ? "Ok" : "Mismatch");
446 if(g_out_prefix)
447 {
448 char *name = malloc(strlen(g_out_prefix) + strlen(filename) + 16);
449 sprintf(name, "%s%s", g_out_prefix, filename);
450
451 cprintf(GREY, "Unpacking to %s... ", name);
452 FILE *f = fopen(name, "wb");
453 if(f)
454 {
455 fwrite(buf + (entry->block_offset << 9), entry->size, 1, f);
456 fclose(f);
457 cprintf(RED, "Ok\n");
458 }
459 else
460 cprintf(RED, "Failed: %m\n");
461 }
462 }
463
464 return 0;
465}
466
467static bool check_fw(uint8_t *buf, int size)
468{
469 struct fw_hdr_t *hdr = (void *)buf;
470
471 if(size < (int)sizeof(struct fw_hdr_t))
472 return false;
473 if(memcmp(hdr->sig, g_fw_signature_f2, FW_SIG_SIZE) == 0)
474 return true;
475 if(memcmp(hdr->sig, g_fw_signature_f0, FW_SIG_SIZE) == 0)
476 return true;
477 return false;
478} 126}
479
480static void usage(void) 127static void usage(void)
481{ 128{
482 printf("Usage: atjboottool [options] firmware\n"); 129 printf("Usage: atjboottool [options] firmware\n");
483 printf("Options:\n"); 130 printf("Options:\n");
484 printf(" -o <prefix>\tSet output prefix\n"); 131 printf(" -o <path> Set output file or output prefix\n");
485 printf(" -f/--force\tForce to continue on errors\n"); 132 printf(" -h/--help Display this message\n");
486 printf(" -?/--help\tDisplay this message\n"); 133 printf(" -d/--debug Display debug messages\n");
487 printf(" -d/--debug\tDisplay debug messages\n"); 134 printf(" -c/--no-color Disable color output\n");
488 printf(" -c/--no-color\tDisable color output\n"); 135 printf(" --fwu Unpack a FWU firmware file\n");
489 printf(" --fwu\tUnpack a FWU firmware file\n"); 136 printf(" --afi Unpack a AFI archive file\n");
490 printf(" --afi\tUnpack a AFI archive file\n"); 137 printf(" --fw Unpack a FW archive file\n");
491 printf(" --fw\tUnpack a FW archive file\n"); 138 printf(" --atj2127 Force ATJ2127 decryption mode\n");
492 printf(" --atj2127\tForce ATJ2127 decryption mode\n");
493 printf("The default is to try to guess the format.\n"); 139 printf("The default is to try to guess the format.\n");
494 printf("If several formats are specified, all are tried.\n"); 140 printf("If several formats are specified, all are tried.\n");
495 printf("If no output prefix is specified, a default one is picked.\n"); 141 printf("If no output prefix is specified, a default one is picked.\n");
@@ -507,7 +153,7 @@ int main(int argc, char **argv)
507 { 153 {
508 static struct option long_options[] = 154 static struct option long_options[] =
509 { 155 {
510 {"help", no_argument, 0, '?'}, 156 {"help", no_argument, 0, 'h'},
511 {"debug", no_argument, 0, 'd'}, 157 {"debug", no_argument, 0, 'd'},
512 {"no-color", no_argument, 0, 'c'}, 158 {"no-color", no_argument, 0, 'c'},
513 {"fwu", no_argument, 0, 'u'}, 159 {"fwu", no_argument, 0, 'u'},
@@ -517,7 +163,7 @@ int main(int argc, char **argv)
517 {0, 0, 0, 0} 163 {0, 0, 0, 0}
518 }; 164 };
519 165
520 int c = getopt_long(argc, argv, "?dcfo:a1", long_options, NULL); 166 int c = getopt_long(argc, argv, "hdco:a2", long_options, NULL);
521 if(c == -1) 167 if(c == -1)
522 break; 168 break;
523 switch(c) 169 switch(c)
@@ -531,7 +177,7 @@ int main(int argc, char **argv)
531 g_debug = true; 177 g_debug = true;
532 break; 178 break;
533 break; 179 break;
534 case '?': 180 case 'h':
535 usage(); 181 usage();
536 break; 182 break;
537 case 'o': 183 case 'o':
@@ -591,7 +237,7 @@ int main(int argc, char **argv)
591 ret = do_fwu(buf, size, fwu_mode); 237 ret = do_fwu(buf, size, fwu_mode);
592 else if(try_afi || afi_check(buf, size)) 238 else if(try_afi || afi_check(buf, size))
593 ret = do_afi(buf, size); 239 ret = do_afi(buf, size);
594 else if(try_fw || check_fw(buf, size)) 240 else if(try_fw || fw_check(buf, size))
595 ret = do_fw(buf, size); 241 ret = do_fw(buf, size);
596 else 242 else
597 { 243 {
diff --git a/utils/atj2137/atjboottool/fw.c b/utils/atj2137/atjboottool/fw.c
new file mode 100644
index 0000000000..07ce4e2f31
--- /dev/null
+++ b/utils/atj2137/atjboottool/fw.c
@@ -0,0 +1,213 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2017 Amaury Pouly
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 <string.h>
22#include <stdlib.h>
23#include <ctype.h>
24#include "misc.h"
25#include "fw.h"
26#include "afi.h"
27
28#define FW_SIG_SIZE 4
29
30#define FW_ENTRIES 240
31
32struct fw_entry_t
33{
34 char name[8];
35 char ext[3];
36 uint8_t attr;
37 uint8_t res[2];
38 uint16_t version;
39 uint32_t block_offset; // offset shift by 9
40 uint32_t size;
41 uint32_t unk;
42 uint32_t checksum;
43} __attribute__((packed));
44
45struct fw_hdr_t
46{
47 uint8_t sig[FW_SIG_SIZE];
48 uint32_t res[4];
49 uint8_t year[2];
50 uint8_t month;
51 uint8_t day;
52 uint16_t usb_vid;
53 uint16_t usb_pid;
54 uint32_t checksum;
55 char productor[16];
56 char str2[16];
57 char str3[32];
58 char dev_name[32];
59 uint8_t res2[8 * 16];
60 char usb_name1[8];
61 char usb_name2[8];
62 char res3[4 * 16 + 1];
63 char mtp_name1[33];
64 char mtp_name2[33];
65 char mtp_ver[33];
66 uint16_t mtp_vid;
67 uint16_t mtp_pid;
68 char fw_ver[64];
69 uint32_t res4[2];
70
71 struct fw_entry_t entry[FW_ENTRIES];
72} __attribute__((packed));
73
74/* the s1fwx source code has a layout but it does not make any sense for firmwares
75 * found in ATJ2127 for example. In doubt just don't do anything */
76struct fw_hdr_f0_t
77{
78 uint8_t sig[FW_SIG_SIZE];
79 uint8_t res[12];
80 uint32_t checksum;
81 uint8_t res2[492];
82
83 struct fw_entry_t entry[FW_ENTRIES];
84} __attribute__((packed));
85
86const uint8_t g_fw_signature_f2[FW_SIG_SIZE] =
87{
88 0x55, 0xaa, 0xf2, 0x0f
89};
90
91const uint8_t g_fw_signature_f0[FW_SIG_SIZE] =
92{
93 0x55, 0xaa, 0xf0, 0x0f
94};
95
96static void build_filename_fw(char buf[16], struct fw_entry_t *ent)
97{
98 int pos = 0;
99 for(int i = 0; i < 8 && ent->name[i] != ' '; i++)
100 buf[pos++] = ent->name[i];
101 buf[pos++] = '.';
102 for(int i = 0; i < 3 && ent->ext[i] != ' '; i++)
103 buf[pos++] = ent->ext[i];
104 buf[pos] = 0;
105}
106
107int fw_unpack(uint8_t *buf, size_t size, fw_extract_callback_t unpack_cb)
108{
109 struct fw_hdr_t *hdr = (void *)buf;
110
111 if(size < sizeof(struct fw_hdr_t))
112 {
113 cprintf(GREY, "File too small\n");
114 return 1;
115 }
116 cprintf(BLUE, "Header\n");
117 cprintf(GREEN, " Signature:");
118 for(int i = 0; i < FW_SIG_SIZE; i++)
119 cprintf(YELLOW, " %02x", hdr->sig[i]);
120 int variant = 0;
121 if(memcmp(hdr->sig, g_fw_signature_f2, FW_SIG_SIZE) == 0)
122 {
123 variant = 0xf2;
124 cprintf(RED, " Ok (f2 variant)\n");
125 }
126 else if(memcmp(hdr->sig, g_fw_signature_f0, FW_SIG_SIZE) == 0)
127 {
128 variant = 0xf0;
129 cprintf(RED, " Ok (f0 variant)\n");
130 }
131 else
132 {
133 cprintf(RED, " Mismatch\n");
134 return 1;
135 }
136
137 /* both variants have the same header size, only the fields differ */
138 if(variant == 0xf2)
139 {
140 cprintf_field(" USB VID: ", "0x%x\n", hdr->usb_vid);
141 cprintf_field(" USB PID: ", "0x%x\n", hdr->usb_pid);
142 cprintf_field(" Date: ", "%x/%x/%02x%02x\n", hdr->day, hdr->month, hdr->year[0], hdr->year[1]);
143 cprintf_field(" Checksum: ", "%x\n", hdr->checksum);
144 cprintf_field(" Productor: ", "%.16s\n", hdr->productor);
145 cprintf_field(" String 2: ", "%.16s\n", hdr->str2);
146 cprintf_field(" String 3: ", "%.32s\n", hdr->str3);
147 cprintf_field(" Device Name: ", "%.32s\n", hdr->dev_name);
148 cprintf(GREEN, " Unknown:\n");
149 for(int i = 0; i < 8; i++)
150 {
151 cprintf(YELLOW, " ");
152 for(int j = 0; j < 16; j++)
153 cprintf(YELLOW, "%02x ", hdr->res2[i * 16 + j]);
154 cprintf(YELLOW, "\n");
155 }
156 cprintf_field(" USB Name 1: ", "%.8s\n", hdr->usb_name1);
157 cprintf_field(" USB Name 2: ", "%.8s\n", hdr->usb_name2);
158 cprintf_field(" MTP Name 1: ", "%.32s\n", hdr->mtp_name1);
159 cprintf_field(" MTP Name 2: ", "%.32s\n", hdr->mtp_name2);
160 cprintf_field(" MTP Version: ", "%.32s\n", hdr->mtp_ver);
161
162 cprintf_field(" MTP VID: ", "0x%x\n", hdr->mtp_vid);
163 cprintf_field(" MTP PID: ", "0x%x\n", hdr->mtp_pid);
164 cprintf_field(" FW Version: ", "%.64s\n", hdr->fw_ver);
165 }
166 else
167 {
168 /* struct fw_hdr_f0_t *hdr_f0 = (void *)hdr; */
169 cprintf(GREEN, " Header not dumped because format is unclear.\n");
170 }
171
172 cprintf(BLUE, "Entries\n");
173 for(int i = 0; i < FW_ENTRIES; i++)
174 {
175 if(hdr->entry[i].name[0] == 0)
176 continue;
177 struct fw_entry_t *entry = &hdr->entry[i];
178 char filename[16];
179 build_filename_fw(filename, entry);
180 cprintf(RED, " %s\n", filename);
181 cprintf_field(" Attr: ", "%02x\n", entry->attr);
182 cprintf_field(" Offset: ", "0x%x\n", entry->block_offset << 9);
183 cprintf_field(" Size: ", "0x%x\n", entry->size);
184 cprintf_field(" Unknown: ", "%x\n", entry->unk);
185 cprintf_field(" Checksum: ", "0x%x ", entry->checksum);
186 uint32_t chk = afi_checksum(buf + (entry->block_offset << 9), entry->size);
187 if(chk != entry->checksum)
188 {
189 cprintf(RED, "Mismatch\n");
190 return 1;
191 }
192 else
193 cprintf(RED, "Ok\n");
194 int ret = unpack_cb(filename, buf + (entry->block_offset << 9), entry->size);
195 if(ret != 0)
196 return ret;
197 }
198
199 return 0;
200}
201
202bool fw_check(uint8_t *buf, size_t size)
203{
204 struct fw_hdr_t *hdr = (void *)buf;
205
206 if(size < sizeof(struct fw_hdr_t))
207 return false;
208 if(memcmp(hdr->sig, g_fw_signature_f2, FW_SIG_SIZE) == 0)
209 return true;
210 if(memcmp(hdr->sig, g_fw_signature_f0, FW_SIG_SIZE) == 0)
211 return true;
212 return false;
213}
diff --git a/utils/atj2137/atjboottool/fw.h b/utils/atj2137/atjboottool/fw.h
new file mode 100644
index 0000000000..95f8087116
--- /dev/null
+++ b/utils/atj2137/atjboottool/fw.h
@@ -0,0 +1,34 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2017 Amaury Pouly
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#ifndef __FW_H__
22#define __FW_H__
23
24#include <stdint.h>
25
26/* Unpack an AFI file: the callback function will be called once for each file in the archive with
27 * its name and content. If the callback returns a nonzero value, the function will stop and return
28 * that value. Returns 0 on success */
29typedef int (*fw_extract_callback_t)(const char *name, uint8_t *buf, size_t size);
30int fw_unpack(uint8_t *buf, size_t size, fw_extract_callback_t cb);
31/* Check if a file looks like an AFI file */
32bool fw_check(uint8_t *buf, size_t size);
33
34#endif /* __FW_H__ */
diff --git a/utils/atj2137/atjboottool/fwu.c b/utils/atj2137/atjboottool/fwu.c
index 843a1cb628..44281af4f4 100644
--- a/utils/atj2137/atjboottool/fwu.c
+++ b/utils/atj2137/atjboottool/fwu.c
@@ -149,10 +149,10 @@ static int decode_block_A(uint8_t block[1020])
149 } 149 }
150 for(int i = 20; i < 32; i++) 150 for(int i = 20; i < 32; i++)
151 key[i] = key[i - 20]; 151 key[i] = key[i - 20];
152 152
153 for(int i = 0; i < 992; i++) 153 for(int i = 0; i < 992; i++)
154 block[i] ^= key[i % 32] ^ g_check_block_A_table[i]; 154 block[i] ^= key[i % 32] ^ g_check_block_A_table[i];
155 155
156 return check_block(block - 1, block + 1000, 1001); 156 return check_block(block - 1, block + 1000, 1001);
157} 157}
158 158
@@ -277,7 +277,7 @@ static int process_block_A(uint8_t block[1024])
277 g_crypto_info_byte = block[offset - 1]; 277 g_crypto_info_byte = block[offset - 1];
278 g_decode_buffer = malloc(g_decode_A_info.size); 278 g_decode_buffer = malloc(g_decode_A_info.size);
279 g_decode_buffer2 = malloc(g_decode_A_info.size); 279 g_decode_buffer2 = malloc(g_decode_A_info.size);
280 280
281 memset(g_decode_buffer, 0, g_decode_A_info.size); 281 memset(g_decode_buffer, 0, g_decode_A_info.size);
282 memset(g_decode_buffer2, 0, g_decode_A_info.size); 282 memset(g_decode_buffer2, 0, g_decode_A_info.size);
283 283
@@ -288,7 +288,7 @@ static int process_block_A(uint8_t block[1024])
288 288
289 cprintf_field(" Word: ", "%d ", *(uint16_t *)&g_subblock_A[286]); 289 cprintf_field(" Word: ", "%d ", *(uint16_t *)&g_subblock_A[286]);
290 check_field(*(uint16_t *)&g_subblock_A[286], 1, "Ok\n", "Mismatch\n"); 290 check_field(*(uint16_t *)&g_subblock_A[286], 1, "Ok\n", "Mismatch\n");
291 291
292 return 0; 292 return 0;
293} 293}
294 294
@@ -625,7 +625,7 @@ static int crypto3(uint32_t *a1, ptr_bundle_t *ptrs_alt, ptr_bundle_t *ptrs)
625static int crypto4(uint8_t *a1, ptr_bundle_t *ptrs, uint32_t *a3) 625static int crypto4(uint8_t *a1, ptr_bundle_t *ptrs, uint32_t *a3)
626{ 626{
627 ptr_bundle_t ptrs_others; 627 ptr_bundle_t ptrs_others;
628 628
629 ptrs_others.ptrA = malloc(g_decode_A_info.size); 629 ptrs_others.ptrA = malloc(g_decode_A_info.size);
630 ptrs_others.ptrB = malloc(g_decode_A_info.size); 630 ptrs_others.ptrB = malloc(g_decode_A_info.size);
631 clear_memory(ptrs_others.ptrA, g_decode_A_info.nr_dwords); 631 clear_memory(ptrs_others.ptrA, g_decode_A_info.nr_dwords);