tuxsavvy / agere_fw_utils (public) (License: Dual BSD 3-clause and GPLv2) (since 2021-02-07) (hash sha1)
Personal fork of https://repo.or.cz/agere_fw_utils.git
List of commits:
Subject Hash Author Date (UTC)
hfwget refactorring posted as hfwget2 April 2008 9b77acdf3330592acda5261d282c579cc1497637 David Kilroy 2008-10-26 14:27:32
dump_fw and hfwget posted Sep 2007 77d205076542510222c6e8359bb2647b0d4e0873 David Kilroy 2008-10-26 14:22:02
Add hfwget.c from hermesap-0.2 9239c21487b524cf0f87b4ffa4828793713fbecd David Kilroy 2008-10-26 14:20:38
dump_fw posted June 2007 617a0ae960430d0d93a533ac5dffc7b9c07a777a David Kilroy 2008-10-26 14:19:45
Commit 9b77acdf3330592acda5261d282c579cc1497637 - hfwget refactorring posted as hfwget2 April 2008
Author: David Kilroy
Author date (UTC): 2008-10-26 14:27
Committer name: David Kilroy
Committer date (UTC): 2008-10-26 14:27
Parent(s): 77d205076542510222c6e8359bb2647b0d4e0873
Signing key:
Tree: ab1336844c1802e050f93f6d0e3a927e319f5478
File Lines added Lines deleted
hfwget.c 752 325
File hfwget.c changed (mode: 100644) (index a7a3b4c..1c3a95b)
7 7 * primary plug data * primary plug data
8 8 * compatibility info * compatibility info
9 9 * firmware identification * firmware identification
10 * unidentified drivers (guesswork for wldel48b, and old wlluc48)
10 * carry on without filename (wldel48b, and old wlluc48)
11 11 * binary output format for linux kernel driver * binary output format for linux kernel driver
12 * big endian translations
13 * refactorring
12 14 * *
13 15 * These modifications may be distributed freely under the GPL v2 so * These modifications may be distributed freely under the GPL v2 so
14 16 * long as this copyright notice is included. * long as this copyright notice is included.
15 17 */ */
16 18 #include <stdio.h> #include <stdio.h>
19 #include <stdint.h>
17 20 #include <stdlib.h> #include <stdlib.h>
18 21 #include <memory.h> #include <memory.h>
19 22 #include <string.h> #include <string.h>
 
21 24 #define false 0 #define false 0
22 25 #define true (!0) #define true (!0)
23 26
27 /* Typedefs for little endian values */
28 typedef uint32_t __le32;
29 typedef uint16_t __le16;
30
31 /* Typedefs for sized integers */
32 typedef uint32_t u32;
33 typedef uint16_t u16;
34 typedef uint8_t u8;
35
36 /*** Macros to deal with different endianess ***/
37
38 /* 0xAABB to 0xBBAA */
39 #define swap_bytes_16(value) \
40 ((((value) >> 8) & 0xFF) | \
41 (((value) & 0xFF) << 8))
42 /* 0xAABBCCDD to 0xDDCCBBAA */
43 #define reverse_bytes_32(value) \
44 ((((value) >> 24) & 0x0000FF) | \
45 (((value) >> 8) & 0x00FF00) | \
46 (((value) << 8) & 0xFF0000) | \
47 (((value) & 0xFF) << 24))
48 /* 0xAABBCCDD to 0xBBAADDCC */
49 #define swap_bytes_32(value) \
50 ((((value) >> 8) & 0x00FF00FF) | \
51 (((value) << 8) & 0xFF00FF00))
52 /* 0xAABBCCDD to 0xCCDDAABB */
53 #define swap_words_32(value) \
54 ((((value) >> 16) & 0x0000FFFF) | \
55 (((value) << 16) & 0xFFFF0000))
56
57 /* address 0 1 2 3 */
58 /* Pure LE stores 0x12345678 as 0x78 0x56 0x34 0x12 */
59 /* Pure BE stores 0x12345678 as 0x12 0x34 0x56 0x78 */
60 /* BEW+LEB stores 0x12345678 as 0x34 0x12 0x78 0x56 */
61 /* LEW+BEB stores 0x12345678 as 0x56 0x78 0x12 0x34 */
62 static int host_bytes_in_word_be = 0;
63 static int host_words_in_dword_be = 0;
64
65 #define host_to_le16(value) \
66 host_bytes_in_word_be ? swap_bytes_16(value) : (value)
67 #define host_to_le32(value) \
68 host_words_in_dword_be ? \
69 (host_bytes_in_word_be ? reverse_bytes_32(value) \
70 : swap_bytes_32(value)) : \
71 (host_bytes_in_word_be ? swap_words_32(value) : (value))
72
73 #define le16_to_host(value) \
74 host_bytes_in_word_be ? swap_bytes_16(value) : (value)
75 #define le32_to_host(value) \
76 host_words_in_dword_be ? \
77 (host_bytes_in_word_be ? reverse_bytes_32(value) \
78 : swap_bytes_32(value)) : \
79 (host_bytes_in_word_be ? swap_words_32(value) : (value))
80
81 /* Structures to read image data */
24 82 struct _segarray { struct _segarray {
25 unsigned int offset;
26 unsigned int size;
27 unsigned char *data;
83 __le32 offset;
84 __le16 size;
85 __le16 flags;
86 __le32 data_p;
28 87 }; };
29 88
30 89 struct _plugarray { struct _plugarray {
31 unsigned int code;
32 unsigned int targ_off;
33 unsigned int length;
90 __le32 code;
91 __le32 targ_off;
92 __le32 length;
34 93 }; };
35 94
36 95 struct _ident_info { struct _ident_info {
37 unsigned short int size;
38 unsigned short int code;
39 unsigned short int comp_id;
40 unsigned short int variant;
41 unsigned short int version_major;
42 unsigned short int version_minor;
96 __le16 size;
97 __le16 code;
98 __le16 comp_id;
99 __le16 variant;
100 __le16 version_major;
101 __le16 version_minor;
43 102 }; };
44 103
45 104 struct _compat_info { struct _compat_info {
46 unsigned short int size;
47 unsigned short int code;
48 unsigned short int role;
49 unsigned short int id;
105 __le16 size;
106 __le16 code;
107 __le16 role;
108 __le16 id;
50 109 struct struct
51 110 { {
52 unsigned short int variant;
53 unsigned short int bottom;
54 unsigned short int top;
111 __le16 variant;
112 __le16 bottom;
113 __le16 top;
55 114 } range[20]; } range[20];
56 115 }; };
57 116
117 struct _firmwareblock {
118 __le32 segarray_p;
119 __le32 halfentry;
120 __le32 plugarray_p;
121 __le32 pri_plugarray_p;
122 __le32 compat_p;
123 __le32 ident_p;
124 };
125
126 struct segarray {
127 uint32_t offset;
128 uint16_t size;
129 uint16_t flags;
130 uint8_t *data;
131 };
132
58 133 struct firmwareblock { struct firmwareblock {
59 struct _segarray *segarray;
60 unsigned int halfentry;
134 struct _segarray *segarray_im;
135 struct segarray segarray[4];
136 u32 halfentry;
61 137 struct _plugarray *plugarray; struct _plugarray *plugarray;
62 138 struct _plugarray *pri_plugarray; struct _plugarray *pri_plugarray;
63 139 struct _compat_info *compat; struct _compat_info *compat;
64 140 struct _ident_info *ident; struct _ident_info *ident;
65 } *firmware;
141 };
66 142
143 /* Structure to map firmware identifiers to description strings */
67 144 static const struct static const struct
68 145 { {
69 unsigned short int id;
146 u16 id;
70 147 char *comp_string; char *comp_string;
71 148 } compat_table[] = } compat_table[] =
72 149 { {
 
... ... static const struct
101 178 { 87, "USB Boot Loader" }, { 87, "USB Boot Loader" },
102 179 }; };
103 180
104 static int savefirmware(unsigned char *data,
105 unsigned int flen,
106 unsigned int signature,
107 unsigned char hexchar);
181 /* Checking endianess at runtime because performance isn't an issue,
182 * and I'd rather not add a configure step */
183 static void check_endianess(void) {
184 union {
185 u32 dword;
186 u16 word[2];
187 u8 byte[4];
188 } data;
189
190 data.dword = 0x12345678;
191 if (data.word[0] == 0x1234) {
192 host_words_in_dword_be = 1;
193 }
194 else if (data.word[0] == 0x5678) {
195 host_words_in_dword_be = 0;
196 } else {
197 fprintf(stderr, "Can't determine endianess of host!\n");
198 exit(1);
199 }
200
201 data.word[0] = 0x1234;
202 if (data.byte[0] == 0x12) {
203 host_bytes_in_word_be = 1;
204 } else if (data.byte[0] == 0x34) {
205 host_bytes_in_word_be = 0;
206 } else {
207 fprintf(stderr, "Can't determine endianess of host!\n");
208 }
209
210 if (host_bytes_in_word_be == host_words_in_dword_be) {
211 fprintf (stdout, "Detected %s host\n",
212 host_bytes_in_word_be ? "big endian" : "little endian");
213 } else {
214 fprintf (stdout, "Detected host with mixed endianess\n");
215 }
216 return;
217 }
108 218
109 /*
110 * Main
111 */
112 int main(int argc, char *argv[])
219 /* Locate firmware by looking for a T???????.HEX filename */
220 static char* find_fw_filename(const u8 *hostdriver,
221 unsigned int flen,
222 u8 hexchar)
113 223 { {
114 FILE *input;
115 unsigned char *data;
116 unsigned int flen;
117
118 printf("Lucent Firmware Extractor v1.0 alpha\n(c) 2003 Mark Smith (username 'Mark' on HermesAP board)\n");
119
120 // Attempt to load file
121 if (argc != 2) {
122 printf("Usage: %s wl???.sys\n", argv[0]);
123 return -1;
124 }
224 const u8 *p, *end;
225 int found;
125 226
126 if ((input = fopen(argv[1], "rb")) == NULL) {
127 printf("Unable to open %s, aborting.\n", argv[1]);
128 return -1;
129 }
227 /* Find the ?1XXYYZZ.HEX string */
228 p = hostdriver;
229 end = hostdriver + flen;
230
231 for (found = false; (found == false) && (p != NULL); )
232 {
233 p = memchr(p, hexchar, (unsigned int)(end - p));
234
235 if (p != NULL)
236 {
237 if (memcmp(".HEX", p + 8, 4) == 0)
238 {
239 found = true;
240 }
241 else
242 {
243 p++;
244 }
245 }
246 }
130 247
131 // Get file length
132 fseek(input, 0L, SEEK_END);
133 flen = ftell(input);
134 printf("File %s length %u (0x%08x)\n", argv[1], flen, flen);
135
136 // Rewind file pointer
137 fseek(input, 0L, SEEK_SET);
138
139 // Allocate memory and load the file
140 data = malloc(flen);
141 fread(data, 1, flen, input);
142 printf("Memory allocated and file read OK\n");
143 fclose(input);
144
145 // Dump Tertiary firmware
146 printf("\nAttempting to dump tertiary (AP) firmware:\n");
147 (void) savefirmware(data, flen, 0xfbfe4461, 'T');
148 printf("\nAttempting to dump station firmware:\n");
149 (void) savefirmware(data, flen, 0x63fc600f, 'R');
150
151 free(data);
152 printf("\nAll dumps complete.\n\n");
153 return 0;
248 if (p != NULL)
249 {
250 printf("Found firmware %s at file offset 0x%08x\n",
251 p, p - hostdriver);
252 }
253 else
254 {
255 printf("%c-firmware not found!\n", hexchar);
256 }
257
258 return (char*) p;
154 259 } }
155 260
156 #define GUESS_OFFSET 0xC000
157 #define GUESS_FILENAME "guess000.hex"
261 /* Find the start of the firmware based on a hint as to where the end
262 * of the firmware image is. The start of the firmware image is
263 * defined by a signature. */
264 static u8* find_fw(const u8* hostdriver,
265 unsigned int flen,
266 const u8* signature,
267 int slen,
268 const u8* hint)
269 {
270 const u8 *p = hint - slen;
271 unsigned int i;
272 int found = false;
158 273
159 /* Returns zero, or a negative number to indicate an error */
160 static int savefirmware(unsigned char *data,
161 unsigned int flen,
162 unsigned int signature,
163 unsigned char hexchar)
274 printf("Searching for firmware from offset 0x%08x, start signature",
275 hint - hostdriver);
276 for (i = 0; i < slen; i++)
277 {
278 printf(" %02x", signature[i]);
279 }
280 printf("...\n");
281
282 /* Really should use a mask here, but its not necessary for the moment. */
283 for (found = false; (p > hostdriver) && (found == false); p--)
284 if (memcmp(p, signature, slen) == 0)
285 found = true;
286
287 if (!found)
288 {
289 printf("Signature not found!\n");
290 return NULL;
291 }
292
293 p++;
294 printf("Found signature at file offset 0x%08x\n", p - hostdriver);
295
296 return (u8*) p;
297 }
298
299 /* Returns a pointer to the PE header */
300 static u8* peheader(const u8* data)
164 301 { {
165 FILE *output;
166 unsigned char *offset, *end, *hexstringoffs, *page1start, *peheader;
167 unsigned char hexstring[16];
168 unsigned int i, found, imagebase, vfwoffs, fwblock;
169
170 // Find the ?1XXYYZZ.HEX string
171 offset = data;
172 end = (unsigned char *)((unsigned int)data + flen);
173
174 for (found = false; found == false && offset != NULL; ) {
175 offset = memchr(offset, hexchar, (unsigned int)(end - offset));
176
177 if (offset != NULL) {
178 if (memcmp(".HEX", offset + 8, 4) == 0) {
179 hexstringoffs = offset;
180 found = true;
181 } else
182 offset++;
183 }
184 }
302 __le32 *e_lfanew = (__le32*) (data + 0x3c);
185 303
186 if (offset != NULL)
187 {
188 strncpy(hexstring, offset, 13);
189 hexstring[13] = 0;
304 /* data + *e_lfanew gives us the NT SIGNATURE
305 * The NT signature is 4 bytes long.
306 * The PE header follow immediately.
307 */
308 return (u8*) (data + (le32_to_host(*e_lfanew) + 4));
309 }
190 310
191 printf("Found firmware %s at file offset 0x%08x\n",
192 hexstring, offset-data);
193 }
194 else
195 {
196 printf("%c-firmware not found!\n", hexchar);
197 printf("searching for signature from 0x%x\n", GUESS_OFFSET);
311 /* returns the expected imagebase */
312 static unsigned int imagebase(const u8* data)
313 {
314 u8* pehdr = peheader(data);
315 return le32_to_host(*((u32*)(pehdr + 0x30)));
316 }
198 317
199 strncpy(hexstring, GUESS_FILENAME,13);
200 hexstring[13] = 0;
201 offset = data + GUESS_OFFSET;
202 }
318 /* Returns the virtual location of the firmware block */
319 static unsigned int find_fwblock_entry(const u8* data,
320 unsigned int flen,
321 u32 vfwoffs)
322 {
323 u32 *p = (u32*) ((unsigned int)(data + flen) & 0xFFFFFFFCu);
324 u8 *q;
325 int found = false;
326 unsigned int fwblock;
203 327
204 printf("Searching for firmware start signature 0x%08x...\n", signature);
205
206 // Really should use a mask here, but its not necessary for the moment.
207 offset -= 4;
208 for (found = false; offset > data && found == false; offset--)
209 if (*(unsigned int *)offset == signature)
210 found = true;
211
212 if (found == false) {
213 printf("Signature not found!\n");
214 return -2;
215 } else {
216 page1start = offset;
217
218 printf("Found at file offset 0x%08x\n", page1start - data);
219 }
328 vfwoffs -= 4; /* kludge for driver firmware structure: one redundant dword at start. */
220 329
221 peheader = (unsigned char *)(*(unsigned int *)(data + 0x3c));
222 printf("Reading DOS driver header...\nPE header located at file offset 0x%p\n", peheader);
223 imagebase = (unsigned int)(*(unsigned int *)((unsigned int)peheader + (unsigned int)data + 0x34));
224 vfwoffs = (unsigned int)((unsigned int)page1start - (unsigned int)data + imagebase);
225 printf("PE imagebase is 0x%08x, therefore virtual offset of firmware is 0x%08x\n",
226 imagebase, vfwoffs);
227
228 printf("Now searching for driver's tertiary firmware table...\n");
229 offset = end;
230 vfwoffs -= 3; // kludge for driver firmware structure: one redundant dword at start.
231 for (found = false; offset > data && found == false; offset--)
232 if (*(unsigned int *)offset == vfwoffs)
233 found = true;
234
235 fwblock = (unsigned int)offset - 7 + imagebase - (unsigned int)data;
236 if (found == false) {
237 printf("Tertiary table not found - contact Mark!\n");
238 return -3;
239 } else {
240 printf("Found at virtual offset 0x%08x\n", fwblock);
241 }
330 printf("Now searching for driver's firmware block entry (0x%08x)...\n",
331 vfwoffs);
242 332
243 printf("Finding main firmware table....\n");
244 offset = end;
245 for (found = false; offset > data && found == false; offset--)
246 if (*(unsigned int *)offset == fwblock)
247 found = true;
248
249 firmware = (struct firmwareblock *)++offset;
250 if (found == false) {
251 printf("Main table not found - contact Mark!\n");
252 return -4;
253 } else {
254 printf("Found at file offset 0x%08x\n", offset - data);
255 }
333 vfwoffs = host_to_le32(vfwoffs); /* convert to little-endian to compare against file data */
256 334
335 /* Note that we're not searching each byte position for a match.
336 * This should be fine because the data should have been placed on
337 * a 4-byte boundary */
257 338
258 printf("Entry point at 0x%08x\n", firmware->halfentry * 2);
259 firmware->segarray = (struct _segarray *)
260 ((unsigned int)firmware->segarray +
261 (unsigned int)data - imagebase);
262 for (i = 0; i < 4 && firmware->segarray[i].offset != 0; i++) {
263 unsigned int temp =
264 ((unsigned int)firmware->segarray[i].data - (imagebase - 4));
265 firmware->segarray[i].data = (unsigned char *) (temp + data);
266 printf("Segment: %d File offs: 0x%08x Target mem: 0x%08x Length 0x%08x\n",
267 i,
268 temp,
269 firmware->segarray[i].offset,
270 firmware->segarray[i].size);
271 }
272 printf("Production Data plugrecords at file offset 0x%08x\n", (unsigned int)firmware->plugarray - imagebase);
339 for (found = false;
340 ((u8*)p > data) && (found == false);
341 p--)
342 {
343 if (*p == vfwoffs)
344 found = true;
345 }
346
347 /* Table entry is 8 bytes before vfwoffs,
348 * but don't forget we've decremented by 4 bytes already
349 */
350 q = (u8*)(p - 1);
351
352 fwblock = (unsigned int)(q - data) + imagebase(data);
353 if (found == false) {
354 printf("Firmware block entry not found - contact Mark!\n");
355 return 0;
356 } else {
357 printf("Found firmware block entry at virtual location 0x%08x, file offset 0x%08x\n",
358 fwblock,
359 q - data);
360 }
361 return fwblock;
362 }
273 363
274 hexstring[9] = 0;
275 strcat(hexstring, "hfw");
364 static struct _firmwareblock* find_fwtable_entry(const u8* data,
365 unsigned int flen,
366 u32 fwblock)
367 {
368 u32 *p = (u32*) ((unsigned int)(data + flen) & 0xFFFFFFFCu);
369 int found = false;
370 struct _firmwareblock *firmware;
371
372 printf("Looking for main firmware table....\n");
373
374 fwblock = host_to_le32(fwblock); /* convert to little-endian to compare against file data */
375 for (found = false; ((u8*)p > data) && (found == false); p--)
376 if (*p == fwblock)
377 found = true;
378
379 firmware = (struct _firmwareblock *)++p;
380 if (found == false) {
381 printf("Main table not found - contact Mark!\n");
382 } else {
383 printf("Found at file offset 0x%08x\n", (u8*)p - data);
384 }
385 return firmware;
386 }
276 387
277 printf("Dumping to %s...\n", hexstring);
278 if ((output = fopen(hexstring, "wb")) == NULL) {
279 printf("Unable to open %s, aborting.\n", hexstring);
280 return -5;
388 /* Copy all data in firmware block from virtual address space to
389 * mapped file address space.
390 *
391 * Also convert from little endian to host endian while we're at it.
392 * Some data will need to be converted back to LE when written out,
393 * but it will be easier than trying to kepp track of the endianness.
394 */
395 static void copy_fw_data(struct firmwareblock* firmware,
396 struct _firmwareblock *fw_image,
397 u8 *data)
398 {
399 u32 delta = (u32)data - imagebase(data);
400 unsigned int i;
401
402 /* Deal with pointers in firmwareblock */
403 firmware->segarray_im = (struct _segarray *)
404 (le32_to_host(fw_image->segarray_p) + delta);
405 firmware->plugarray = (struct _plugarray *)
406 (le32_to_host(fw_image->plugarray_p) + delta);
407 firmware->pri_plugarray = (struct _plugarray *)
408 (le32_to_host(fw_image->pri_plugarray_p) + delta);
409 firmware->compat = (struct _compat_info *)
410 (le32_to_host(fw_image->compat_p) + delta);
411 firmware->ident = (struct _ident_info *)
412 (le32_to_host(fw_image->ident_p) + delta);
413 firmware->halfentry = le32_to_host(fw_image->halfentry);
414
415 for (i = 0; i < 4; i++)
416 {
417 if (le32_to_host(firmware->segarray_im[i].offset) != 0)
418 {
419 unsigned int temp =
420 (le32_to_host(firmware->segarray_im[i].data_p) + 4); /* ?? offset for checksum? */
421 firmware->segarray[i].data = (unsigned char *) (temp + delta);
422 firmware->segarray[i].offset = le32_to_host(firmware->segarray_im[i].offset);
423 firmware->segarray[i].size = le16_to_host(firmware->segarray_im[i].size);
424 firmware->segarray[i].flags = le16_to_host(firmware->segarray_im[i].flags);
425 printf("Segment: %d File offs: 0x%08x Target mem: 0x%08x Length 0x%04x\n",
426 i,
427 firmware->segarray[i].data - data,
428 firmware->segarray[i].offset,
429 firmware->segarray[i].size);
430 }
431 else
432 {
433 firmware->segarray[i].data = NULL;
434 firmware->segarray[i].offset = 0;
435 firmware->segarray[i].size = 0;
436 firmware->segarray[i].flags = 0;
437 break;
281 438 } }
439 }
440
441 printf("Production Data plugrecords at file offset 0x%08x\n",
442 (u8*)firmware->plugarray - data);
443 printf("Primary plugrecords at file offset 0x%08x\n",
444 (u8*)firmware->pri_plugarray - data);
445 printf("Compatibility info at file offset 0x%08x\n",
446 (u8*)firmware->compat - data);
447 printf("Identity info at file offset 0x%08x\n",
448 (u8*)firmware->ident - data);
449 #if 0
450 /* Convert plugarray (in place in image) */
451 for (i = 0; firmware->plugarray[i].code != 0; i++)
452 {
453 firmware->plugarray[i].code = le32_to_host(firmware->plugarray[i].code);
454 firmware->plugarray[i].targ_off = le32_to_host(firmware->plugarray[i].targ_off);
455 firmware->plugarray[i].length = le32_to_host(firmware->plugarray[i].length);
456 }
282 457
283 firmware->plugarray = (struct _plugarray *)
284 ((unsigned int)firmware->plugarray +
285 (unsigned int)data - imagebase);
286
287
288 printf("Primary plugrecords at file offset 0x%08x\n", (unsigned int)firmware->pri_plugarray - imagebase);
289 printf("Compatibility info at file offset 0x%08x\n", (unsigned int)firmware->compat - imagebase);
290 printf("Identity info at file offset 0x%08x\n", (unsigned int)firmware->ident - imagebase);
291
292 firmware->pri_plugarray = (struct _plugarray *)
293 ((unsigned int) firmware->pri_plugarray +
294 (unsigned int)data - imagebase);
295 firmware->compat = (struct _compat_info *)
296 ((unsigned int)firmware->compat +
297 (unsigned int)data - imagebase);
298 firmware->ident = (struct _ident_info *)
299 ((unsigned int)firmware->ident +
300 (unsigned int)data - imagebase);
301
302 if (firmware->ident->code == 0xFD20u)
458 /* Convert pri_array (in place in image) */
459 for (i = 0; firmware->pri_plugarray[i].code != 0; i++)
460 {
461 firmware->pri_plugarray[i].code = le32_to_host(firmware->plugarray[i].code);
462 firmware->pri_plugarray[i].targ_off = le32_to_host(firmware->plugarray[i].targ_off);
463 firmware->pri_plugarray[i].length = le32_to_host(firmware->plugarray[i].length);
464 }
465
466 /* Convert identifiers */
467 firmware->ident->size = le16_to_host(fw_image->ident->size);
468 firmware->ident->code = le16_to_host(fw_image->ident->code);
469 firmware->ident->comp_id = le16_to_host(fw_image->ident->comp_id);
470 firmware->ident->variant = le16_to_host(fw_image->ident->variant);
471 firmware->ident->version_major = le16_to_host(fw_image->ident->version_major);
472 firmware->ident->version_minor = le16_to_host(fw_image->ident->version_minor);
473
474 /* TODO: Convert compat_info */
475 #endif
476 }
477
478 static void print_fw_ident(const struct firmwareblock *firmware)
479 {
480 int i;
481
482 if (le16_to_host(firmware->ident->code) == 0xFD20u)
483 {
484 for (i = 0;
485 i < sizeof(compat_table)/sizeof(compat_table[0]);
486 i++)
303 487 { {
304 for (i = 0;
305 i < sizeof(compat_table)/sizeof(compat_table[0]);
306 i++)
307 {
308 if (compat_table[i].id == firmware->ident->comp_id)
309 break;
310 }
311 /* Print FW ident information */
312 printf("Firmware identity: %s, Variant %d Version %d.%2d\n",
313 compat_table[i].comp_string,
314 firmware->ident->variant,
315 firmware->ident->version_major,
316 firmware->ident->version_minor);
488 if (compat_table[i].id == le16_to_host(firmware->ident->comp_id))
489 break;
317 490 } }
318 491
319 #if 0 /* original hermesap format */
320 fprintf(output, "HFW1\nENTRY %08X\n", firmware->halfentry * 2);
321 for (i = 0; firmware->plugarray[i].code != 0; i++) {
322 fprintf(output, "PLUG %08X %08X %08X\n",
323 firmware->plugarray[i].code,
324 firmware->plugarray[i].targ_off,
325 firmware->plugarray[i].length);
326 }
492 printf("Firmware identity: %s, Variant %d Version %d.%2d\n",
493 compat_table[i].comp_string,
494 le16_to_host(firmware->ident->variant),
495 le16_to_host(firmware->ident->version_major),
496 le16_to_host(firmware->ident->version_minor));
497 }
498 }
327 499
328 for (i = 0; firmware->segarray[i].offset != 0; i++)
500 static int write_hermesap_fw(FILE* output,
501 const struct firmwareblock *firmware)
502 {
503 unsigned int i;
504 fprintf(output, "HFW1\nENTRY %08X\n", firmware->halfentry * 2);
505
506 for (i = 0; firmware->plugarray[i].code != 0; i++)
507 {
508 fprintf(output, "PLUG %08X %08X %08X\n",
509 le32_to_host(firmware->plugarray[i].code),
510 le32_to_host(firmware->plugarray[i].targ_off),
511 le32_to_host(firmware->plugarray[i].length));
512 }
513
514 for (i = 0; firmware->segarray[i].offset != 0; i++)
515 {
516 unsigned int j;
517 if (i != 0)
518 fprintf(output, "\n");
519 fprintf(output, "SEG %08X %08X %08X",
520 firmware->segarray[i].offset,
521 firmware->segarray[i].size,
522 0);
523
524 for (j = 0; j < firmware->segarray[i].size; j += 2) {
525 if ((j % 16) == 0)
526 fprintf(output, "\nDATA");
527
528 fprintf(output, " %02X%02X",
529 firmware->segarray[i].data[j],
530 firmware->segarray[i].data[j + 1]);
531 }
532 }
533
534 fputc('\n', output);
535
536 return 0;
537 }
538
539 static size_t count_blocks(const struct segarray *first_seg)
540 {
541 const struct segarray *seg = first_seg;
542 size_t count = 0;
543 while(seg->offset != 0)
544 {
545 count++;
546 seg++;
547 }
548 return count;
549 }
550
551 static size_t acc_block_size(const struct segarray *first_seg)
552 {
553 const struct segarray *seg = first_seg;
554 size_t len = 0;
555 while(seg->offset != 0)
556 {
557 len += seg->size;
558 seg++;
559 }
560 return len;
561 }
562
563 static size_t count_pdr(const struct _plugarray *first_pdr)
564 {
565 const struct _plugarray *pdr = first_pdr;
566 size_t count = 0;
567 while(pdr->code)
568 {
569 count++;
570 pdr++;
571 }
572 return count;
573 }
574
575 static void dump_blocks(FILE* output,
576 const struct segarray *first_seg)
577 {
578 const struct segarray *seg = first_seg;
579 u8 block_hdr[sizeof(seg->offset) + sizeof(seg->size)];
580 __le32 *addr = (__le32 *) &block_hdr[0];
581 __le16 *size = (__le16 *) &block_hdr[sizeof(seg->offset)];
582
583 while(seg->offset != 0)
584 {
585 if (seg->size > 0)
329 586 { {
330 unsigned int j;
331 if (i != 0)
332 fprintf(output, "\n");
333 fprintf(output, "SEG %08X %08X %08X",
334 firmware->segarray[i].offset,
335 firmware->segarray[i].size,
336 0);
337
338 for (j = 0; j < firmware->segarray[i].size; j += 2) {
339 if ((j % 16) == 0)
340 fprintf(output, "\nDATA");
341
342 fprintf(output, " %02X%02X",
343 firmware->segarray[i].data[j],
344 firmware->segarray[i].data[j + 1]);
345 }
346 }
587 *addr = host_to_le32(seg->offset);
588 *size = host_to_le16(seg->size);
347 589
348 fputc('\n', output);
349 #else /* binary kernel format */
350 /* Note: does not deal with BE/LE issues */
590 fwrite(&block_hdr, 1, sizeof(block_hdr), output);
591 fwrite(seg->data, 1, seg->size, output); /* data */
592 }
593 seg++;
594 }
595 *addr = host_to_le32(0xFFFFFFFFu); /* set block end */
596 *size = host_to_le32(0);
597 fwrite(&block_hdr, 1, sizeof(block_hdr), output);
598 }
599
600 static void dump_pdr(FILE* output,
601 const struct _plugarray *first_pdr)
602 {
603 const struct _plugarray *r = first_pdr;
604 u8 pdr[sizeof(r->code) + sizeof(r->targ_off) + sizeof(r->length)];
605 __le32 *code = (__le32*) &pdr[0];
606 __le32 *addr = (__le32*) &pdr[sizeof(r->code)];
607 __le32 *len = (__le32*) &pdr[sizeof(r->code) + sizeof(r->targ_off)];
608
609 if (r)
610 {
611 while(r->code != 0)
351 612 { {
352 unsigned long int l = 0;
353 unsigned short int s = 0;
354 unsigned long int prev_offset = 0;
355 fwrite ("HFW000", 1, 6, output);
356 s = 6 + 2 + (6*4) + 16; // headersize
357 fwrite (&s, 1, sizeof(s), output);
358 l = firmware->halfentry; // entrypoint
359 fwrite (&l, 1, sizeof(l), output);
360 l = 2; // number of blocks, hardcoded for now
361 fwrite (&l, 1, sizeof(l), output);
362 l = 0; // offset to block data
363 fwrite (&l, 1, sizeof(l), output);
364
365 // pdr offset
366 l = 0;
367 for (s = 0; firmware->segarray[s].offset != 0; s++)
368 {
369 l += firmware->segarray[s].size;
370 }
371 l = l + (s + 1) * (4 + 2);
372 fwrite (&l, 1, sizeof(l), output);
373
374 // pri offset
375 prev_offset = l;
376 for (l = 0; firmware->plugarray[l].code != 0; l++);
377 l = prev_offset + (l+1) * 4 * 3;
378 fwrite (&l, 1, sizeof(l), output);
379
380 // cpt offset
381 prev_offset = l;
382 for (l = 0; firmware->pri_plugarray[l].code != 0; l++);
383 l = prev_offset + (l+1) * 4 * 3;
384 fwrite (&l, 1, sizeof(l), output);
385 fwrite ("1234567890123456",1,16,output); // fw sig
386
387 for (i = 0; firmware->segarray[i].offset != 0; i++)
388 {
389 l = firmware->segarray[i].offset; // addr
390 s = firmware->segarray[i].size; // size
391
392 if (s > 0)
393 {
394 fwrite(&l, 1, sizeof(l), output);
395 fwrite(&s, 1, sizeof(s), output);
396 fwrite(firmware->segarray[i].data,1,s,output); // data
397 }
398 }
399 l = 0xFFFFFFFFu; // set block end
400 s = 0;
401 fwrite(&l, 1, sizeof(l), output);
402 fwrite(&s, 1, sizeof(s), output);
403
404 for (i = 0; firmware->plugarray[i].code != 0; i++) {
405 l = firmware->plugarray[i].code;
406 fwrite(&l, 1, sizeof(l), output);
407 l = firmware->plugarray[i].targ_off;
408 fwrite(&l, 1, sizeof(l), output);
409 l = firmware->plugarray[i].length;
410 fwrite(&l, 1, sizeof(l), output);
411 }
412 l = 0; // pdr end
413 fwrite(&l, 1, sizeof(l), output);
414 fwrite(&l, 1, sizeof(l), output);
415 fwrite(&l, 1, sizeof(l), output);
416
417 for (i = 0; firmware->pri_plugarray[i].code != 0; i++) {
418 l = firmware->pri_plugarray[i].code;
419 fwrite(&l, 1, sizeof(l), output);
420 l = firmware->pri_plugarray[i].targ_off;
421 fwrite(&l, 1, sizeof(l), output);
422 l = firmware->pri_plugarray[i].length;
423 fwrite(&l, 1, sizeof(l), output);
424 }
425 l = 0; // pdr end
426 fwrite(&l, 1, sizeof(l), output);
427 fwrite(&l, 1, sizeof(l), output);
428 fwrite(&l, 1, sizeof(l), output);
613 *code = host_to_le32(r->code);
614 *addr = host_to_le32(r->targ_off);
615 *len = host_to_le32(r->length);
616 fwrite(&pdr, 1, sizeof(pdr), output);
617 r++;
429 618 } }
619 }
620 *code = *addr = *len = host_to_le32(0); /* pdr end */
621 fwrite(&pdr, 1, sizeof(pdr), output);
622 }
623
624 static void dump_compat(FILE* output,
625 const struct _compat_info *compat)
626 {
627 /* Dump non-zero length blocks.
628 * No need to reformat. */
629 while (compat->size != 0)
630 {
631 fwrite(compat, 1, sizeof(*compat), output);
632 compat++;
633 }
634 /* sentinel */
635 fwrite(compat, 1, sizeof(*compat), output);
636 }
637
638 #define VERSION "HFW000"
639 /* Returns zero, or a negative number to indicate an error */
640 static int write_kernel_fw(FILE* output,
641 const struct firmwareblock *firmware)
642 {
643 /* Note: does not deal with BE/LE issues */
644 u32 image_header[6];
645 u32 *ptr;
646 u16 headersize = ((sizeof(VERSION)-1) +
647 sizeof(u16) +
648 (sizeof(u32)*6));
649 u32 blocks = count_blocks(&firmware->segarray[0]);
650 u32 blk_offset = 0; /* Immediately after header */
651 u32 pdr_offset = (acc_block_size(&firmware->segarray[0]) +
652 ((blocks + 1) * (sizeof(u32) + sizeof(u16))));
653 u32 pri_offset = pdr_offset +
654 ((count_pdr(&firmware->plugarray[0]) + 1) * sizeof(u32) * 3);
655 u32 cpt_offset = pri_offset +
656 ((count_pdr(&firmware->pri_plugarray[0]) + 1) * sizeof(u32) * 3);
657
658
659 fwrite (VERSION, 1, sizeof(VERSION)-1, output);
660
661 headersize = host_to_le16(headersize);
662 fwrite (&headersize, 1, sizeof(headersize), output);
663
664 ptr = &image_header[0];
665 *ptr = host_to_le32(firmware->halfentry); /* entrypoint */
666 ptr++;
667 *ptr = host_to_le32(blocks);
668 ptr++;
669 *ptr = host_to_le32(blk_offset);
670 ptr++;
671 *ptr = host_to_le32(pdr_offset);
672 ptr++;
673 *ptr = host_to_le32(pri_offset);
674 ptr++;
675 *ptr = host_to_le32(cpt_offset);
676 ptr++;
677 fwrite (&image_header, 1, sizeof(image_header), output);
678
679 dump_blocks(output, firmware->segarray);
680 dump_pdr(output, firmware->plugarray);
681 dump_pdr(output, firmware->pri_plugarray);
682 dump_compat(output, firmware->compat);
683 return 0; /* success */
684 }
685
686 static int dump_fw(const char *basename, const char hexchar,
687 u8* data, size_t flen,
688 const u8* signature, size_t slen)
689 {
690 struct firmwareblock firmware;
691 char* fwname;
692 char* filename;
693 u8* hint;
694 u8* fw; /* pointer to the actual blocks for programming */
695 unsigned int fwblock; /* virtual location of structure listing blocks to program for a given firmware */
696 struct _firmwareblock *fw_image; /* structure all elements of a given firmware */
697 u32 ibase;
698 u32 vfwoffs;
699 FILE* output;
700 size_t len;
701
702 if (memcmp(data, "MZ", 2) == 0)
703 {
704 printf ("Driver looks like Microsoft PE format\n");
705 ibase = imagebase(data);
706 }
707 else if (memcmp(data, "Joy!", 4) == 0)
708 {
709 printf ("Driver looks like Apple PEF format\n");
710 printf ("I don't know how to extract for this format.\n"
711 "I don't have a powerbook, and would need a copy of the driver to fix this\n");
712
713 /* Need to look at each of the section headers.
714 * Number of section headers if given at offset 0x20 (32) (__be16?)
715 * First section header starts at offset 0x28 (40)
716 * Each section header is 0x1C (28) bytes long
717 * Subsequent section headers follow immediately after.
718 * Each section header specifies its imagebase at offset 0x4 (__be32?)
719 * We need to use the imagebase of the section in which the firmware is found.
720 * The offset to the section data is at offset 0x14 (20) (__be32?).
721 * This offset is relative to the beginning of the file.
722 * The length of each sections data is at offset 0x10 (16) (__be32?)
723 */
724 /* ibase = pef_imagebase(data); */
725 return -5;
726 }
727 else
728 {
729 printf ("Unknown object file format\n");
730 return -5;
731 }
732
733 printf("\nAttempting to dump %c firmware:\n", hexchar);
734 fwname = find_fw_filename(data, flen, hexchar);
735 if (fwname)
736 {
737 /* The filename is towards the end of the FW block,
738 * so use it as a hint to locate the start of the block.
739 */
740 hint = (u8*) fwname;
741 }
742 else
743 {
744 hint = data + flen; /* start from the end of file */
745 }
746
747 /* Now find the block using the signature */
748 fw = find_fw(data, flen, signature, slen, hint);
749 if (!fw)
750 return -1;
751
752 vfwoffs = (u32)(fw - data) + ibase;
753
754 printf("PE imagebase is 0x%08x, therefore virtual offset of firmware is 0x%08x\n",
755 ibase, vfwoffs);
756
757 fwblock = find_fwblock_entry(data,
758 flen,
759 vfwoffs);
760 if (!fwblock)
761 return -2;
762
763 fw_image = find_fwtable_entry(data,
764 flen,
765 fwblock);
766 if (!fw_image)
767 return -3;
768
769 copy_fw_data(&firmware, fw_image, data);
770
771 /* Print FW ident information */
772 printf("Entry point at 0x%08x\n", firmware.halfentry * 2);
773 print_fw_ident(&firmware);
774
775 filename = malloc(strlen(basename) + 5);
776 strcpy(filename, basename);
777 len = strlen(filename);
778 filename[len] = hexchar;
779 filename[len+1] = 0;
780 strcat(filename, ".fw");
781
782 printf("Dumping to %s...\n", filename);
783 if ((output = fopen(filename, "wb")) == NULL)
784 {
785 printf("Unable to open %s, aborting.\n", filename);
786 free(filename);
787 return -4;
788 }
789
790 #if 0
791 write_hermesap_fw(output, &firmware);
792 #else
793 write_kernel_fw(output, &firmware);
430 794 #endif #endif
431 fclose(output);
432 printf("Dump of %s complete.\n", hexstring);
433 795
434 return 0; /* success */
796 fclose(output);
797 printf("Dump of %s complete.\n", filename);
798 free(filename);
799
800 return 0;
801 }
802
803 /*
804 * Main
805 */
806 int main(int argc, char *argv[])
807 {
808 FILE *input;
809 unsigned char *data;
810 unsigned int flen;
811
812 printf("Lucent Firmware Extractor v1.1\n"
813 "(c) 2003 Mark Smith (username 'Mark' on HermesAP board)\n"
814 "(c) 2007,2008 Dave Kilroy\n");
815
816 check_endianess();
817
818 /* Attempt to load file */
819 if (argc != 3) {
820 printf("Usage: %s <driver> <output_base>\n", argv[0]);
821 return -1;
822 }
823
824 /* TODO: parse options better
825 * Want to be able to specify:
826 * input file (WLAGS49B.SYS)
827 * output file base name (wlags_)
828 * desired output format --hermesap or --kernel
829 * Others?
830 */
831
832 if ((input = fopen(argv[1], "rb")) == NULL) {
833 printf("Unable to open %s, aborting.\n", argv[1]);
834 return -1;
835 }
836
837 /* Get file length */
838 fseek(input, 0L, SEEK_END);
839 flen = ftell(input);
840 printf("File %s length %u (0x%08x)\n", argv[1], flen, flen);
841
842 /* Rewind file pointer */
843 fseek(input, 0L, SEEK_SET);
844
845 /* Allocate memory and load the file */
846 data = malloc(flen);
847 fread(data, 1, flen, input);
848 printf("Memory allocated and file read OK\n");
849 fclose(input);
850
851 {
852 u8 t_sig[4] = { 0x61, 0x44, 0xfe, 0xfb };
853 u8 r_sig[4] = { 0x0f, 0x60, 0xfc, 0x63 };
854
855 dump_fw(argv[2], 'T', data, flen, t_sig, sizeof(t_sig));
856 dump_fw(argv[2], 'R', data, flen, r_sig, sizeof(r_sig));
857 }
858
859 free(data);
860 printf("\nAll dumps complete.\n\n");
861 return 0;
435 862 } }
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/tuxsavvy/agere_fw_utils

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/tuxsavvy/agere_fw_utils

Clone this repository using git:
git clone git://git.rocketgit.com/user/tuxsavvy/agere_fw_utils

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main