diff options
Diffstat (limited to 'utils/atj2137/atjboottool/fw.c')
-rw-r--r-- | utils/atj2137/atjboottool/fw.c | 213 |
1 files changed, 213 insertions, 0 deletions
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 | |||
32 | struct 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 | |||
45 | struct 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 */ | ||
76 | struct 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 | |||
86 | const uint8_t g_fw_signature_f2[FW_SIG_SIZE] = | ||
87 | { | ||
88 | 0x55, 0xaa, 0xf2, 0x0f | ||
89 | }; | ||
90 | |||
91 | const uint8_t g_fw_signature_f0[FW_SIG_SIZE] = | ||
92 | { | ||
93 | 0x55, 0xaa, 0xf0, 0x0f | ||
94 | }; | ||
95 | |||
96 | static 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 | |||
107 | int 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 | |||
202 | bool 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 | } | ||