File hfwget.c changed (mode: 100644) (index 6ccea31..792ef0e) |
15 |
15 |
* These modifications may be distributed freely under the GPL v2 so |
* These modifications may be distributed freely under the GPL v2 so |
16 |
16 |
* long as this copyright notice is included. |
* long as this copyright notice is included. |
17 |
17 |
*/ |
*/ |
|
18 |
|
#include <stddef.h> |
18 |
19 |
#include <stdio.h> |
#include <stdio.h> |
19 |
20 |
#include <stdint.h> |
#include <stdint.h> |
20 |
21 |
#include <stdlib.h> |
#include <stdlib.h> |
|
24 |
25 |
#define false 0 |
#define false 0 |
25 |
26 |
#define true (!0) |
#define true (!0) |
26 |
27 |
|
|
27 |
|
/* Typedefs for little endian values */ |
|
|
28 |
|
/* Typedefs for little and big endian values */ |
28 |
29 |
typedef uint32_t __le32; |
typedef uint32_t __le32; |
29 |
30 |
typedef uint16_t __le16; |
typedef uint16_t __le16; |
|
31 |
|
typedef uint32_t __be32; |
|
32 |
|
typedef uint16_t __be16; |
30 |
33 |
|
|
31 |
34 |
/* Typedefs for sized integers */ |
/* Typedefs for sized integers */ |
32 |
35 |
typedef uint32_t u32; |
typedef uint32_t u32; |
|
... |
... |
typedef uint8_t u8; |
61 |
64 |
/* LEW+BEB stores 0x12345678 as 0x56 0x78 0x12 0x34 */ |
/* LEW+BEB stores 0x12345678 as 0x56 0x78 0x12 0x34 */ |
62 |
65 |
static int host_bytes_in_word_be = 0; |
static int host_bytes_in_word_be = 0; |
63 |
66 |
static int host_words_in_dword_be = 0; |
static int host_words_in_dword_be = 0; |
|
67 |
|
static int driver_is_be = 0; |
64 |
68 |
|
|
65 |
69 |
#define host_to_le16(value) \ |
#define host_to_le16(value) \ |
66 |
|
host_bytes_in_word_be ? swap_bytes_16(value) : (value) |
|
|
70 |
|
(host_bytes_in_word_be ? swap_bytes_16(value) : (value)) |
67 |
71 |
#define host_to_le32(value) \ |
#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 |
|
(host_words_in_dword_be ? \ |
|
73 |
|
(host_bytes_in_word_be ? reverse_bytes_32(value) \ |
|
74 |
|
: swap_bytes_32(value)) : \ |
|
75 |
|
(host_bytes_in_word_be ? swap_words_32(value) : (value))) |
72 |
76 |
|
|
73 |
77 |
#define le16_to_host(value) \ |
#define le16_to_host(value) \ |
74 |
|
host_bytes_in_word_be ? swap_bytes_16(value) : (value) |
|
|
78 |
|
(host_bytes_in_word_be ? swap_bytes_16(value) : (value)) |
75 |
79 |
#define le32_to_host(value) \ |
#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 |
|
(host_words_in_dword_be ? \ |
|
81 |
|
(host_bytes_in_word_be ? reverse_bytes_32(value) \ |
|
82 |
|
: swap_bytes_32(value)) : \ |
|
83 |
|
(host_bytes_in_word_be ? swap_words_32(value) : (value))) |
|
84 |
|
|
|
85 |
|
#define host_to_be16(value) \ |
|
86 |
|
(host_bytes_in_word_be ? (value) : swap_bytes_16(value)) |
|
87 |
|
#define host_to_be32(value) \ |
|
88 |
|
(host_words_in_dword_be ? \ |
|
89 |
|
(host_bytes_in_word_be ? (value) : swap_bytes_32(value)) : \ |
|
90 |
|
(host_bytes_in_word_be ? swap_words_32(value) \ |
|
91 |
|
: reverse_bytes_32(value))) |
80 |
92 |
|
|
81 |
93 |
#define be16_to_host(value) \ |
#define be16_to_host(value) \ |
82 |
|
host_bytes_in_word_be ? (value) : swap_bytes_16(value) |
|
|
94 |
|
(host_bytes_in_word_be ? (value) : swap_bytes_16(value)) |
83 |
95 |
#define be32_to_host(value) \ |
#define be32_to_host(value) \ |
84 |
|
host_words_in_dword_be ? \ |
|
85 |
|
(host_bytes_in_word_be ? (value) : reverse_bytes_32(value)) : \ |
|
86 |
|
(host_bytes_in_word_be ? swap_words_32(value) : \ |
|
87 |
|
swap_bytes_32(value)) |
|
88 |
|
|
|
89 |
|
/* Structures to read image data */ |
|
90 |
|
struct _segarray { |
|
|
96 |
|
(host_words_in_dword_be ? \ |
|
97 |
|
(host_bytes_in_word_be ? (value) : swap_bytes_32(value)) : \ |
|
98 |
|
(host_bytes_in_word_be ? swap_words_32(value) \ |
|
99 |
|
: reverse_bytes_32(value))) |
|
100 |
|
|
|
101 |
|
#define driver_to_host_16(value) \ |
|
102 |
|
(driver_is_be ? be16_to_host(value) : le16_to_host(value)) |
|
103 |
|
#define driver_to_host_32(value) \ |
|
104 |
|
(driver_is_be ? be32_to_host(value) : le32_to_host(value)) |
|
105 |
|
#define host_to_driver_16(value) \ |
|
106 |
|
(driver_is_be ? host_to_be16(value) : host_to_le16(value)) |
|
107 |
|
#define host_to_driver_32(value) \ |
|
108 |
|
(driver_is_be ? host_to_be32(value) : host_to_le32(value)) |
|
109 |
|
|
|
110 |
|
/**** Structures to read image data from driver ****/ |
|
111 |
|
|
|
112 |
|
/* Decode the windows firmware blocks */ |
|
113 |
|
struct fwblock_wdrv { |
91 |
114 |
__le32 offset; |
__le32 offset; |
92 |
115 |
__le16 size; |
__le16 size; |
93 |
116 |
__le16 flags; |
__le16 flags; |
94 |
117 |
__le32 data_p; |
__le32 data_p; |
95 |
118 |
}; |
}; |
96 |
119 |
|
|
|
120 |
|
/* Decode the mac firmware blocks */ |
|
121 |
|
struct fwblock_mdrv { |
|
122 |
|
__be16 len; |
|
123 |
|
__be16 code; |
|
124 |
|
__be16 prg_mode; |
|
125 |
|
__be16 size; |
|
126 |
|
__be32 offset; |
|
127 |
|
__be32 flags; |
|
128 |
|
__be32 data_p; |
|
129 |
|
}; |
|
130 |
|
|
97 |
131 |
struct _plugarray { |
struct _plugarray { |
98 |
132 |
__le32 code; |
__le32 code; |
99 |
133 |
__le32 targ_off; |
__le32 targ_off; |
|
... |
... |
struct _compat_info { |
122 |
156 |
} range[20]; |
} range[20]; |
123 |
157 |
}; |
}; |
124 |
158 |
|
|
125 |
|
struct _firmwareblock { |
|
|
159 |
|
struct fwtable_drv { |
126 |
160 |
__le32 segarray_p; |
__le32 segarray_p; |
127 |
161 |
__le32 halfentry; |
__le32 halfentry; |
128 |
162 |
__le32 plugarray_p; |
__le32 plugarray_p; |
|
... |
... |
struct _firmwareblock { |
131 |
165 |
__le32 ident_p; |
__le32 ident_p; |
132 |
166 |
}; |
}; |
133 |
167 |
|
|
134 |
|
struct segarray { |
|
|
168 |
|
/*** Structures to use on host. ***/ |
|
169 |
|
struct fwblock { |
135 |
170 |
uint32_t offset; |
uint32_t offset; |
136 |
171 |
uint16_t size; |
uint16_t size; |
137 |
172 |
uint16_t flags; |
uint16_t flags; |
138 |
173 |
uint8_t *data; |
uint8_t *data; |
139 |
174 |
}; |
}; |
140 |
175 |
|
|
141 |
|
struct firmwareblock { |
|
142 |
|
struct _segarray *segarray_im; |
|
143 |
|
struct segarray segarray[4]; |
|
|
176 |
|
struct fwtable { |
|
177 |
|
union { |
|
178 |
|
struct fwblock_wdrv *w; |
|
179 |
|
struct fwblock_mdrv *m; |
|
180 |
|
} segarray_im; |
|
181 |
|
struct fwblock segarray[4]; |
144 |
182 |
u32 halfentry; |
u32 halfentry; |
145 |
183 |
struct _plugarray *plugarray; |
struct _plugarray *plugarray; |
146 |
184 |
struct _plugarray *pri_plugarray; |
struct _plugarray *pri_plugarray; |
|
... |
... |
static u8* peheader(const u8* data) |
317 |
355 |
} |
} |
318 |
356 |
|
|
319 |
357 |
/* returns the expected imagebase */ |
/* returns the expected imagebase */ |
320 |
|
static unsigned int imagebase(const u8* data) |
|
|
358 |
|
static unsigned int pe_imagebase(const u8* data) |
321 |
359 |
{ |
{ |
322 |
360 |
u8* pehdr = peheader(data); |
u8* pehdr = peheader(data); |
323 |
361 |
return le32_to_host(*((u32*)(pehdr + 0x30))); |
return le32_to_host(*((u32*)(pehdr + 0x30))); |
324 |
362 |
} |
} |
325 |
363 |
|
|
|
364 |
|
typedef __be32 mac_cpu_type_t; |
|
365 |
|
typedef __be32 mac_cpu_subtype_t; |
|
366 |
|
typedef __be32 mac_vmprot_t; |
|
367 |
|
|
326 |
368 |
struct mach_header { |
struct mach_header { |
327 |
|
u32 magic; |
|
328 |
|
int cputype; |
|
329 |
|
int cpusubtype; |
|
330 |
|
u32 filetype; |
|
331 |
|
u32 ncmds; |
|
332 |
|
u32 sizeofcmds; |
|
333 |
|
u32 flags; |
|
|
369 |
|
__be32 magic; |
|
370 |
|
mac_cpu_type_t cputype; |
|
371 |
|
mac_cpu_subtype_t cpusubtype; |
|
372 |
|
__be32 filetype; |
|
373 |
|
__be32 ncmds; |
|
374 |
|
__be32 sizeofcmds; |
|
375 |
|
__be32 flags; |
334 |
376 |
}; |
}; |
335 |
377 |
|
|
336 |
378 |
struct mach_load_command |
struct mach_load_command |
337 |
379 |
{ |
{ |
338 |
|
u32 cmd; |
|
339 |
|
u32 cmdsize; |
|
|
380 |
|
__be32 cmd; |
|
381 |
|
__be32 cmdsize; |
340 |
382 |
}; |
}; |
341 |
383 |
|
|
342 |
384 |
struct mach_segment_command |
struct mach_segment_command |
343 |
385 |
{ |
{ |
344 |
|
u32 cmd; |
|
345 |
|
u32 cmdsize; |
|
|
386 |
|
__be32 cmd; |
|
387 |
|
__be32 cmdsize; |
346 |
388 |
char segname[16]; |
char segname[16]; |
347 |
|
u32 vmaddr; |
|
348 |
|
u32 vmsize; |
|
349 |
|
u32 fileoff; |
|
350 |
|
u32 filesize; |
|
351 |
|
int maxprot; |
|
352 |
|
int initprot; |
|
353 |
|
u32 nsects; |
|
354 |
|
u32 flags; |
|
|
389 |
|
__be32 vmaddr; |
|
390 |
|
__be32 vmsize; |
|
391 |
|
__be32 fileoff; |
|
392 |
|
__be32 filesize; |
|
393 |
|
mac_vmprot_t maxprot; |
|
394 |
|
mac_vmprot_t initprot; |
|
395 |
|
__be32 nsects; |
|
396 |
|
__be32 flags; |
355 |
397 |
}; |
}; |
356 |
398 |
|
|
357 |
399 |
struct mach_section |
struct mach_section |
358 |
400 |
{ |
{ |
359 |
401 |
char sectname[16]; |
char sectname[16]; |
360 |
402 |
char segname[16]; |
char segname[16]; |
361 |
|
u32 addr; |
|
362 |
|
u32 size; |
|
363 |
|
u32 offset; |
|
364 |
|
u32 align; |
|
365 |
|
u32 reloff; |
|
366 |
|
u32 nreloc; |
|
367 |
|
u32 flags; |
|
368 |
|
u32 reserved1; |
|
369 |
|
u32 reserved2; |
|
|
403 |
|
__be32 addr; |
|
404 |
|
__be32 size; |
|
405 |
|
__be32 offset; |
|
406 |
|
__be32 align; |
|
407 |
|
__be32 reloff; |
|
408 |
|
__be32 nreloc; |
|
409 |
|
__be32 flags; |
|
410 |
|
__be32 reserved1; |
|
411 |
|
__be32 reserved2; |
370 |
412 |
}; |
}; |
371 |
413 |
|
|
372 |
|
/* returns the start of the segment that contains the firmware */ |
|
373 |
|
static unsigned int macho_imagebase(const u8 *data) |
|
|
414 |
|
/* Returns the start of the segment that contains the firmware. Also |
|
415 |
|
* identifies the end of the section. It appears that the firmware |
|
416 |
|
* contains another second copy of our pointers later on (at about |
|
417 |
|
* offset 0x12330) which interfere with our search. |
|
418 |
|
*/ |
|
419 |
|
static u32 macho_imagebase(const u8 *data, const u8 **section_end) |
374 |
420 |
{ |
{ |
375 |
|
struct mach_header *hdr = (struct mach_header *) data; |
|
|
421 |
|
struct mach_header *hdr = (struct mach_header *) data; |
376 |
422 |
int i, j; |
int i, j; |
377 |
423 |
const u8 *p = data + sizeof(struct mach_header); |
const u8 *p = data + sizeof(struct mach_header); |
378 |
424 |
|
|
379 |
425 |
for (i = 0; i < be32_to_host(hdr->ncmds); i++) { |
for (i = 0; i < be32_to_host(hdr->ncmds); i++) { |
380 |
|
struct mach_load_command *load_cmd = (struct mach_load_command *) p; |
|
|
426 |
|
struct mach_load_command *load_cmd = (struct mach_load_command *) p; |
381 |
427 |
|
|
382 |
|
if (be32_to_host(load_cmd->cmd) == 0x0001) { /* LC_SEGMENT */ |
|
383 |
|
struct mach_segment_command *seg_cmd = (struct mach_segment_command *) p; |
|
|
428 |
|
if (be32_to_host(load_cmd->cmd) == 0x0001) { /* LC_SEGMENT */ |
|
429 |
|
struct mach_segment_command *seg_cmd = (struct mach_segment_command *) p; |
384 |
430 |
|
|
385 |
|
p += sizeof(struct mach_segment_command); |
|
386 |
|
for (j = 0; j < be32_to_host(seg_cmd->nsects); j++) { |
|
387 |
|
struct mach_section *sect = (struct mach_section *) p; |
|
|
431 |
|
p += sizeof(struct mach_segment_command); |
|
432 |
|
for (j = 0; j < be32_to_host(seg_cmd->nsects); j++) { |
|
433 |
|
struct mach_section *sect = (struct mach_section *) p; |
388 |
434 |
|
|
389 |
|
if (!strcmp (sect->sectname, "__data") && !strcmp (sect->segname, "__DATA")) { |
|
390 |
|
u32 *imgbase = (u32 *) (data + (be32_to_host(sect->addr) - be32_to_host(seg_cmd->vmaddr))); |
|
391 |
|
return *imgbase; |
|
392 |
|
} |
|
|
435 |
|
if (!strcmp (sect->sectname, "__data") && !strcmp (sect->segname, "__DATA")) { |
|
436 |
|
/*u32 *imgbase = (u32 *) (data + (be32_to_host(sect->addr) - be32_to_host(seg_cmd->vmaddr)));*/ |
|
437 |
|
*section_end = data + be32_to_host(sect->offset) + be32_to_host(sect->size); |
|
438 |
|
return be32_to_host(sect->addr) - be32_to_host(sect->offset); |
|
439 |
|
} |
393 |
440 |
|
|
394 |
|
p += sizeof (struct mach_section); |
|
395 |
|
} |
|
396 |
|
} |
|
|
441 |
|
p += sizeof (struct mach_section); |
|
442 |
|
} |
|
443 |
|
} |
397 |
444 |
|
|
398 |
|
/* advance to past the load command */ |
|
399 |
|
p += sizeof (struct mach_load_command); |
|
400 |
|
p += be32_to_host(load_cmd->cmdsize); |
|
|
445 |
|
/* advance to past the load command */ |
|
446 |
|
p += sizeof (struct mach_load_command); |
|
447 |
|
p += be32_to_host(load_cmd->cmdsize); |
401 |
448 |
} |
} |
402 |
449 |
|
|
403 |
450 |
printf("Couldn't find Mach-O __data/__DATA section\n"); |
printf("Couldn't find Mach-O __data/__DATA section\n"); |
|
... |
... |
static unsigned int macho_imagebase(const u8 *data) |
420 |
467 |
*/ |
*/ |
421 |
468 |
static int macho_validate(const u8 *data) |
static int macho_validate(const u8 *data) |
422 |
469 |
{ |
{ |
423 |
|
struct mach_header *hdr = (struct mach_header *) data; |
|
424 |
|
|
|
425 |
|
switch (hdr->magic) { |
|
426 |
|
case MH_MAGIC: |
|
427 |
|
/* Yay, what we need */ |
|
428 |
|
break; |
|
429 |
|
case MH_MAGIC_64: |
|
430 |
|
case MH_CIGAM_64: |
|
431 |
|
case MH_CIGAM: |
|
432 |
|
/* 64-bit or LE 32-bit, can't use it */ |
|
433 |
|
return -1; |
|
434 |
|
default: |
|
435 |
|
/* Not a Mach-O file at all */ |
|
436 |
|
return -2; |
|
437 |
|
} |
|
|
470 |
|
struct mach_header *hdr = (struct mach_header *) data; |
|
471 |
|
|
|
472 |
|
printf("Header magic is 0x%x\n", be32_to_host(hdr->magic)); |
|
473 |
|
printf("CPU type is 0x%x\n", be32_to_host(hdr->cputype)); |
|
474 |
|
printf("File type is 0x%x\n", be32_to_host(hdr->filetype)); |
|
475 |
|
|
|
476 |
|
switch (be32_to_host(hdr->magic)) { |
|
477 |
|
case MH_MAGIC: |
|
478 |
|
/* Yay, what we need */ |
|
479 |
|
break; |
|
480 |
|
case MH_MAGIC_64: |
|
481 |
|
case MH_CIGAM_64: |
|
482 |
|
case MH_CIGAM: |
|
483 |
|
/* 64-bit or LE 32-bit, can't use it */ |
|
484 |
|
return -1; |
|
485 |
|
default: |
|
486 |
|
/* Not a Mach-O file at all */ |
|
487 |
|
return -2; |
|
488 |
|
} |
438 |
489 |
|
|
439 |
|
if (hdr->cputype != 0x12) /* PPC */ |
|
440 |
|
return -1; |
|
|
490 |
|
if (be32_to_host(hdr->cputype) != 0x12) /* PPC */ |
|
491 |
|
return -1; |
441 |
492 |
|
|
442 |
|
if (hdr->filetype != 0x0001) /* MH_OBJECT */ |
|
443 |
|
return -1; |
|
|
493 |
|
if (be32_to_host(hdr->filetype) != 0x0001) /* MH_OBJECT */ |
|
494 |
|
return -1; |
444 |
495 |
|
|
445 |
|
return 0; |
|
|
496 |
|
return 0; |
446 |
497 |
} |
} |
447 |
498 |
|
|
448 |
|
/* Returns the virtual location of the firmware block */ |
|
449 |
|
static unsigned int find_fwblock_entry(const u8* data, |
|
450 |
|
unsigned int flen, |
|
451 |
|
u32 vfwoffs, |
|
452 |
|
const u32 ibase) |
|
|
499 |
|
/* Returns a pointer within data, to the fwblock pointing containing a |
|
500 |
|
* pointer to addr (in driver address space)*/ |
|
501 |
|
static u8* find_fwblock_entry(const u8* data, |
|
502 |
|
unsigned int flen, |
|
503 |
|
u32 addr, |
|
504 |
|
int mac) |
453 |
505 |
{ |
{ |
454 |
506 |
u32 *p = (u32*) ((unsigned int)(data + flen) & 0xFFFFFFFCu); |
u32 *p = (u32*) ((unsigned int)(data + flen) & 0xFFFFFFFCu); |
455 |
|
u8 *q; |
|
456 |
507 |
int found = false; |
int found = false; |
457 |
|
unsigned int fwblock; |
|
458 |
508 |
|
|
459 |
|
vfwoffs -= 4; /* kludge for driver firmware structure: one redundant dword at start. */ |
|
|
509 |
|
if (!mac) { |
|
510 |
|
addr -= 4; /* kludge for driver firmware structure: one |
|
511 |
|
* redundant dword at start. */ |
|
512 |
|
} |
460 |
513 |
|
|
461 |
514 |
printf("Now searching for driver's firmware block entry (0x%08x)...\n", |
printf("Now searching for driver's firmware block entry (0x%08x)...\n", |
462 |
|
vfwoffs); |
|
|
515 |
|
addr); |
463 |
516 |
|
|
464 |
|
vfwoffs = host_to_le32(vfwoffs); /* convert to little-endian to compare against file data */ |
|
|
517 |
|
addr = host_to_driver_32(addr); /* convert to driver endianness to |
|
518 |
|
* compare against file data */ |
465 |
519 |
|
|
466 |
520 |
/* Note that we're not searching each byte position for a match. |
/* Note that we're not searching each byte position for a match. |
467 |
521 |
* This should be fine because the data should have been placed on |
* This should be fine because the data should have been placed on |
468 |
522 |
* a 4-byte boundary */ |
* a 4-byte boundary */ |
469 |
523 |
|
|
470 |
524 |
for (found = false; |
for (found = false; |
471 |
|
((u8*)p > data) && (found == false); |
|
|
525 |
|
((u8*)p >= data); |
472 |
526 |
p--) |
p--) |
473 |
527 |
{ |
{ |
474 |
|
if (*p == vfwoffs) |
|
|
528 |
|
if (*p == addr) |
|
529 |
|
{ |
475 |
530 |
found = true; |
found = true; |
|
531 |
|
break; |
|
532 |
|
} |
476 |
533 |
} |
} |
477 |
534 |
|
|
478 |
|
/* Table entry is 8 bytes before vfwoffs, |
|
479 |
|
* but don't forget we've decremented by 4 bytes already |
|
480 |
|
*/ |
|
481 |
|
q = (u8*)(p - 1); |
|
|
535 |
|
/* Compensate for the fields before the data_p pointer */ |
|
536 |
|
if (mac) |
|
537 |
|
p -= offsetof(struct fwblock_mdrv, data_p) / sizeof(*p); |
|
538 |
|
else |
|
539 |
|
p -= offsetof(struct fwblock_wdrv, data_p) / sizeof(*p); |
482 |
540 |
|
|
483 |
|
fwblock = (unsigned int)(q - data) + ibase; |
|
484 |
|
if (found == false) { |
|
485 |
|
printf("Firmware block entry not found - contact Mark!\n"); |
|
486 |
|
return 0; |
|
487 |
|
} else { |
|
488 |
|
printf("Found firmware block entry at virtual location 0x%08x, file offset 0x%08x\n", |
|
489 |
|
fwblock, |
|
490 |
|
q - data); |
|
491 |
|
} |
|
492 |
|
return fwblock; |
|
|
541 |
|
return (u8*) p; |
493 |
542 |
} |
} |
494 |
543 |
|
|
495 |
|
static struct _firmwareblock* find_fwtable_entry(const u8* data, |
|
496 |
|
unsigned int flen, |
|
497 |
|
u32 fwblock) |
|
|
544 |
|
static struct fwtable_drv* find_fwtable_entry(const u8* data, |
|
545 |
|
unsigned int flen, |
|
546 |
|
u32 fwblock) |
498 |
547 |
{ |
{ |
499 |
548 |
u32 *p = (u32*) ((unsigned int)(data + flen) & 0xFFFFFFFCu); |
u32 *p = (u32*) ((unsigned int)(data + flen) & 0xFFFFFFFCu); |
500 |
549 |
int found = false; |
int found = false; |
501 |
|
struct _firmwareblock *firmware; |
|
|
550 |
|
struct fwtable_drv *firmware; |
502 |
551 |
|
|
503 |
552 |
printf("Looking for main firmware table....\n"); |
printf("Looking for main firmware table....\n"); |
504 |
553 |
|
|
505 |
|
fwblock = host_to_le32(fwblock); /* convert to little-endian to compare against file data */ |
|
506 |
|
for (found = false; ((u8*)p > data) && (found == false); p--) |
|
|
554 |
|
fwblock = host_to_driver_32(fwblock); /* convert to driver endianess to compare against file data */ |
|
555 |
|
|
|
556 |
|
printf("Looking for %x\n", fwblock); |
|
557 |
|
|
|
558 |
|
for (found = false; ((u8*)p >= data); p--) |
|
559 |
|
{ |
507 |
560 |
if (*p == fwblock) |
if (*p == fwblock) |
|
561 |
|
{ |
508 |
562 |
found = true; |
found = true; |
|
563 |
|
break; |
|
564 |
|
} |
|
565 |
|
} |
509 |
566 |
|
|
510 |
|
firmware = (struct _firmwareblock *)++p; |
|
|
567 |
|
firmware = (struct fwtable_drv *)p; |
511 |
568 |
if (found == false) { |
if (found == false) { |
512 |
569 |
printf("Main table not found - contact Mark!\n"); |
printf("Main table not found - contact Mark!\n"); |
513 |
570 |
} else { |
} else { |
|
... |
... |
static struct _firmwareblock* find_fwtable_entry(const u8* data, |
523 |
580 |
* Some data will need to be converted back to LE when written out, |
* Some data will need to be converted back to LE when written out, |
524 |
581 |
* but it will be easier than trying to kepp track of the endianness. |
* but it will be easier than trying to kepp track of the endianness. |
525 |
582 |
*/ |
*/ |
526 |
|
static void copy_fw_data(struct firmwareblock* firmware, |
|
527 |
|
struct _firmwareblock *fw_image, |
|
|
583 |
|
static void copy_fw_data(struct fwtable* firmware, |
|
584 |
|
struct fwtable_drv *fw_image, |
528 |
585 |
const u8 *data, |
const u8 *data, |
529 |
|
const u32 ibase) |
|
|
586 |
|
int mac, |
|
587 |
|
u32 ibase) |
530 |
588 |
{ |
{ |
531 |
589 |
u32 delta = (u32)data - ibase; |
u32 delta = (u32)data - ibase; |
532 |
590 |
unsigned int i; |
unsigned int i; |
533 |
591 |
|
|
534 |
|
/* Deal with pointers in firmwareblock */ |
|
535 |
|
firmware->segarray_im = (struct _segarray *) |
|
536 |
|
(le32_to_host(fw_image->segarray_p) + delta); |
|
|
592 |
|
/* Deal with pointers in fwtable */ |
|
593 |
|
firmware->segarray_im.w = (struct fwblock_wdrv *) |
|
594 |
|
(driver_to_host_32(fw_image->segarray_p) + delta); |
537 |
595 |
firmware->plugarray = (struct _plugarray *) |
firmware->plugarray = (struct _plugarray *) |
538 |
|
(le32_to_host(fw_image->plugarray_p) + delta); |
|
|
596 |
|
(driver_to_host_32(fw_image->plugarray_p) + delta); |
539 |
597 |
firmware->pri_plugarray = (struct _plugarray *) |
firmware->pri_plugarray = (struct _plugarray *) |
540 |
|
(le32_to_host(fw_image->pri_plugarray_p) + delta); |
|
|
598 |
|
(driver_to_host_32(fw_image->pri_plugarray_p) + delta); |
541 |
599 |
firmware->compat = (struct _compat_info *) |
firmware->compat = (struct _compat_info *) |
542 |
|
(le32_to_host(fw_image->compat_p) + delta); |
|
|
600 |
|
(driver_to_host_32(fw_image->compat_p) + delta); |
543 |
601 |
firmware->ident = (struct _ident_info *) |
firmware->ident = (struct _ident_info *) |
544 |
|
(le32_to_host(fw_image->ident_p) + delta); |
|
545 |
|
firmware->halfentry = le32_to_host(fw_image->halfentry); |
|
|
602 |
|
(driver_to_host_32(fw_image->ident_p) + delta); |
|
603 |
|
firmware->halfentry = driver_to_host_32(fw_image->halfentry); |
546 |
604 |
|
|
547 |
605 |
for (i = 0; i < 4; i++) |
for (i = 0; i < 4; i++) |
548 |
606 |
{ |
{ |
549 |
|
if (le32_to_host(firmware->segarray_im[i].offset) != 0) |
|
|
607 |
|
u32 offset = mac ? |
|
608 |
|
driver_to_host_32(firmware->segarray_im.m[i].offset) : |
|
609 |
|
driver_to_host_32(firmware->segarray_im.w[i].offset); |
|
610 |
|
u32 data_p = mac ? |
|
611 |
|
driver_to_host_32(firmware->segarray_im.m[i].data_p) : |
|
612 |
|
driver_to_host_32(firmware->segarray_im.w[i].data_p) + 4; /* ?? offset for checksum? */ |
|
613 |
|
u16 size = mac ? |
|
614 |
|
driver_to_host_16(firmware->segarray_im.m[i].size) : |
|
615 |
|
driver_to_host_16(firmware->segarray_im.w[i].size); |
|
616 |
|
u16 flags = mac ? |
|
617 |
|
(u16) driver_to_host_32(firmware->segarray_im.m[i].flags) : |
|
618 |
|
driver_to_host_16(firmware->segarray_im.w[i].flags); |
|
619 |
|
|
|
620 |
|
if (offset != 0) |
550 |
621 |
{ |
{ |
551 |
|
unsigned int temp = |
|
552 |
|
(le32_to_host(firmware->segarray_im[i].data_p) + 4); /* ?? offset for checksum? */ |
|
553 |
|
firmware->segarray[i].data = (unsigned char *) (temp + delta); |
|
554 |
|
firmware->segarray[i].offset = le32_to_host(firmware->segarray_im[i].offset); |
|
555 |
|
firmware->segarray[i].size = le16_to_host(firmware->segarray_im[i].size); |
|
556 |
|
firmware->segarray[i].flags = le16_to_host(firmware->segarray_im[i].flags); |
|
557 |
|
printf("Segment: %d File offs: 0x%08x Target mem: 0x%08x Length 0x%04x\n", |
|
|
622 |
|
firmware->segarray[i].data = (unsigned char *) (data_p + delta); |
|
623 |
|
firmware->segarray[i].offset = offset; |
|
624 |
|
firmware->segarray[i].size = size; |
|
625 |
|
firmware->segarray[i].flags = flags; |
|
626 |
|
printf("Segment: %d File offs: 0x%08x Target mem: 0x%08x Length 0x%04x%s\n", |
558 |
627 |
i, |
i, |
559 |
628 |
firmware->segarray[i].data - data, |
firmware->segarray[i].data - data, |
560 |
629 |
firmware->segarray[i].offset, |
firmware->segarray[i].offset, |
561 |
|
firmware->segarray[i].size); |
|
|
630 |
|
firmware->segarray[i].size, |
|
631 |
|
(firmware->segarray[i].size == 0) ? " (ignored)" : ""); |
562 |
632 |
} |
} |
563 |
633 |
else |
else |
564 |
634 |
{ |
{ |
|
... |
... |
static void copy_fw_data(struct firmwareblock* firmware, |
578 |
648 |
(u8*)firmware->compat - data); |
(u8*)firmware->compat - data); |
579 |
649 |
printf("Identity info at file offset 0x%08x\n", |
printf("Identity info at file offset 0x%08x\n", |
580 |
650 |
(u8*)firmware->ident - data); |
(u8*)firmware->ident - data); |
581 |
|
#if 0 |
|
|
651 |
|
|
582 |
652 |
/* Convert plugarray (in place in image) */ |
/* Convert plugarray (in place in image) */ |
583 |
653 |
for (i = 0; firmware->plugarray[i].code != 0; i++) |
for (i = 0; firmware->plugarray[i].code != 0; i++) |
584 |
654 |
{ |
{ |
585 |
|
firmware->plugarray[i].code = le32_to_host(firmware->plugarray[i].code); |
|
586 |
|
firmware->plugarray[i].targ_off = le32_to_host(firmware->plugarray[i].targ_off); |
|
587 |
|
firmware->plugarray[i].length = le32_to_host(firmware->plugarray[i].length); |
|
|
655 |
|
firmware->plugarray[i].code = driver_to_host_32(firmware->plugarray[i].code); |
|
656 |
|
firmware->plugarray[i].targ_off = driver_to_host_32(firmware->plugarray[i].targ_off); |
|
657 |
|
firmware->plugarray[i].length = driver_to_host_32(firmware->plugarray[i].length); |
588 |
658 |
} |
} |
589 |
659 |
|
|
590 |
660 |
/* Convert pri_array (in place in image) */ |
/* Convert pri_array (in place in image) */ |
591 |
661 |
for (i = 0; firmware->pri_plugarray[i].code != 0; i++) |
for (i = 0; firmware->pri_plugarray[i].code != 0; i++) |
592 |
662 |
{ |
{ |
593 |
|
firmware->pri_plugarray[i].code = le32_to_host(firmware->plugarray[i].code); |
|
594 |
|
firmware->pri_plugarray[i].targ_off = le32_to_host(firmware->plugarray[i].targ_off); |
|
595 |
|
firmware->pri_plugarray[i].length = le32_to_host(firmware->plugarray[i].length); |
|
|
663 |
|
firmware->pri_plugarray[i].code = driver_to_host_32(firmware->plugarray[i].code); |
|
664 |
|
firmware->pri_plugarray[i].targ_off = driver_to_host_32(firmware->plugarray[i].targ_off); |
|
665 |
|
firmware->pri_plugarray[i].length = driver_to_host_32(firmware->plugarray[i].length); |
596 |
666 |
} |
} |
597 |
667 |
|
|
598 |
668 |
/* Convert identifiers */ |
/* Convert identifiers */ |
599 |
|
firmware->ident->size = le16_to_host(fw_image->ident->size); |
|
600 |
|
firmware->ident->code = le16_to_host(fw_image->ident->code); |
|
601 |
|
firmware->ident->comp_id = le16_to_host(fw_image->ident->comp_id); |
|
602 |
|
firmware->ident->variant = le16_to_host(fw_image->ident->variant); |
|
603 |
|
firmware->ident->version_major = le16_to_host(fw_image->ident->version_major); |
|
604 |
|
firmware->ident->version_minor = le16_to_host(fw_image->ident->version_minor); |
|
605 |
|
|
|
606 |
|
/* TODO: Convert compat_info */ |
|
607 |
|
#endif |
|
|
669 |
|
firmware->ident->size = driver_to_host_16(firmware->ident->size); |
|
670 |
|
firmware->ident->code = driver_to_host_16(firmware->ident->code); |
|
671 |
|
firmware->ident->comp_id = driver_to_host_16(firmware->ident->comp_id); |
|
672 |
|
firmware->ident->variant = driver_to_host_16(firmware->ident->variant); |
|
673 |
|
firmware->ident->version_major = driver_to_host_16(firmware->ident->version_major); |
|
674 |
|
firmware->ident->version_minor = driver_to_host_16(firmware->ident->version_minor); |
|
675 |
|
|
|
676 |
|
/* Convert compat_info */ |
|
677 |
|
for (i = 0; firmware->compat[i].size != 0; i++) |
|
678 |
|
{ |
|
679 |
|
int j; |
|
680 |
|
firmware->compat[i].size = driver_to_host_16(firmware->compat[i].size); |
|
681 |
|
firmware->compat[i].code = driver_to_host_16(firmware->compat[i].code); |
|
682 |
|
firmware->compat[i].role = driver_to_host_16(firmware->compat[i].role); |
|
683 |
|
firmware->compat[i].id = driver_to_host_16(firmware->compat[i].id); |
|
684 |
|
for (j = 0; j < 20; j++) |
|
685 |
|
{ |
|
686 |
|
firmware->compat[i].range[j].variant = driver_to_host_16(firmware->compat[i].range[j].variant); |
|
687 |
|
firmware->compat[i].range[j].bottom = driver_to_host_16(firmware->compat[i].range[j].bottom); |
|
688 |
|
firmware->compat[i].range[j].top = driver_to_host_16(firmware->compat[i].range[j].top); |
|
689 |
|
} |
|
690 |
|
} |
|
691 |
|
|
608 |
692 |
} |
} |
609 |
693 |
|
|
610 |
|
static void print_fw_ident(const struct firmwareblock *firmware) |
|
|
694 |
|
static void print_fw_ident(const struct fwtable *firmware) |
611 |
695 |
{ |
{ |
612 |
696 |
int i; |
int i; |
613 |
697 |
|
|
614 |
|
if (le16_to_host(firmware->ident->code) == 0xFD20u) |
|
|
698 |
|
if (firmware->ident->code == 0xFD20u) |
615 |
699 |
{ |
{ |
616 |
700 |
for (i = 0; |
for (i = 0; |
617 |
701 |
i < sizeof(compat_table)/sizeof(compat_table[0]); |
i < sizeof(compat_table)/sizeof(compat_table[0]); |
618 |
702 |
i++) |
i++) |
619 |
703 |
{ |
{ |
620 |
|
if (compat_table[i].id == le16_to_host(firmware->ident->comp_id)) |
|
|
704 |
|
if (compat_table[i].id == firmware->ident->comp_id) |
621 |
705 |
break; |
break; |
622 |
706 |
} |
} |
623 |
707 |
|
|
624 |
708 |
printf("Firmware identity: %s, Variant %d Version %d.%2d\n", |
printf("Firmware identity: %s, Variant %d Version %d.%2d\n", |
625 |
709 |
compat_table[i].comp_string, |
compat_table[i].comp_string, |
626 |
|
le16_to_host(firmware->ident->variant), |
|
627 |
|
le16_to_host(firmware->ident->version_major), |
|
628 |
|
le16_to_host(firmware->ident->version_minor)); |
|
|
710 |
|
firmware->ident->variant, |
|
711 |
|
firmware->ident->version_major, |
|
712 |
|
firmware->ident->version_minor); |
629 |
713 |
} |
} |
630 |
714 |
} |
} |
631 |
715 |
|
|
632 |
716 |
static int write_hermesap_fw(FILE* output, |
static int write_hermesap_fw(FILE* output, |
633 |
|
const struct firmwareblock *firmware) |
|
|
717 |
|
const struct fwtable *firmware) |
634 |
718 |
{ |
{ |
635 |
719 |
unsigned int i; |
unsigned int i; |
636 |
720 |
fprintf(output, "HFW1\nENTRY %08X\n", firmware->halfentry * 2); |
fprintf(output, "HFW1\nENTRY %08X\n", firmware->halfentry * 2); |
|
... |
... |
static int write_hermesap_fw(FILE* output, |
638 |
722 |
for (i = 0; firmware->plugarray[i].code != 0; i++) |
for (i = 0; firmware->plugarray[i].code != 0; i++) |
639 |
723 |
{ |
{ |
640 |
724 |
fprintf(output, "PLUG %08X %08X %08X\n", |
fprintf(output, "PLUG %08X %08X %08X\n", |
641 |
|
le32_to_host(firmware->plugarray[i].code), |
|
642 |
|
le32_to_host(firmware->plugarray[i].targ_off), |
|
643 |
|
le32_to_host(firmware->plugarray[i].length)); |
|
|
725 |
|
firmware->plugarray[i].code, |
|
726 |
|
firmware->plugarray[i].targ_off, |
|
727 |
|
firmware->plugarray[i].length); |
644 |
728 |
} |
} |
645 |
729 |
|
|
646 |
730 |
for (i = 0; firmware->segarray[i].offset != 0; i++) |
for (i = 0; firmware->segarray[i].offset != 0; i++) |
|
... |
... |
static int write_hermesap_fw(FILE* output, |
668 |
752 |
return 0; |
return 0; |
669 |
753 |
} |
} |
670 |
754 |
|
|
671 |
|
static size_t count_blocks(const struct segarray *first_seg) |
|
|
755 |
|
static size_t count_blocks(const struct fwblock *first_block) |
672 |
756 |
{ |
{ |
673 |
|
const struct segarray *seg = first_seg; |
|
|
757 |
|
const struct fwblock *block = first_block; |
674 |
758 |
size_t count = 0; |
size_t count = 0; |
675 |
|
while(seg->offset != 0) |
|
|
759 |
|
while(block->offset != 0) |
676 |
760 |
{ |
{ |
677 |
|
count++; |
|
678 |
|
seg++; |
|
|
761 |
|
if (block->size > 0) |
|
762 |
|
count++; |
|
763 |
|
block++; |
679 |
764 |
} |
} |
680 |
765 |
return count; |
return count; |
681 |
766 |
} |
} |
682 |
767 |
|
|
683 |
|
static size_t acc_block_size(const struct segarray *first_seg) |
|
|
768 |
|
static size_t acc_block_size(const struct fwblock *first_block) |
684 |
769 |
{ |
{ |
685 |
|
const struct segarray *seg = first_seg; |
|
|
770 |
|
const struct fwblock *block = first_block; |
686 |
771 |
size_t len = 0; |
size_t len = 0; |
687 |
|
while(seg->offset != 0) |
|
|
772 |
|
while(block->offset != 0) |
688 |
773 |
{ |
{ |
689 |
|
len += seg->size; |
|
690 |
|
seg++; |
|
|
774 |
|
len += block->size; |
|
775 |
|
block++; |
691 |
776 |
} |
} |
692 |
777 |
return len; |
return len; |
693 |
778 |
} |
} |
|
... |
... |
static size_t count_pdr(const struct _plugarray *first_pdr) |
705 |
790 |
} |
} |
706 |
791 |
|
|
707 |
792 |
static void dump_blocks(FILE* output, |
static void dump_blocks(FILE* output, |
708 |
|
const struct segarray *first_seg) |
|
|
793 |
|
const struct fwblock *first_block) |
709 |
794 |
{ |
{ |
710 |
|
const struct segarray *seg = first_seg; |
|
711 |
|
u8 block_hdr[sizeof(seg->offset) + sizeof(seg->size)]; |
|
|
795 |
|
const struct fwblock *block = first_block; |
|
796 |
|
u8 block_hdr[sizeof(block->offset) + sizeof(block->size)]; |
712 |
797 |
__le32 *addr = (__le32 *) &block_hdr[0]; |
__le32 *addr = (__le32 *) &block_hdr[0]; |
713 |
|
__le16 *size = (__le16 *) &block_hdr[sizeof(seg->offset)]; |
|
|
798 |
|
__le16 *size = (__le16 *) &block_hdr[sizeof(block->offset)]; |
714 |
799 |
|
|
715 |
|
while(seg->offset != 0) |
|
|
800 |
|
while(block->offset != 0) |
716 |
801 |
{ |
{ |
717 |
|
if (seg->size > 0) |
|
|
802 |
|
if (block->size > 0) |
718 |
803 |
{ |
{ |
719 |
|
*addr = host_to_le32(seg->offset); |
|
720 |
|
*size = host_to_le16(seg->size); |
|
|
804 |
|
*addr = host_to_le32(block->offset); |
|
805 |
|
*size = host_to_le16(block->size); |
721 |
806 |
|
|
722 |
807 |
fwrite(&block_hdr, 1, sizeof(block_hdr), output); |
fwrite(&block_hdr, 1, sizeof(block_hdr), output); |
723 |
|
fwrite(seg->data, 1, seg->size, output); /* data */ |
|
|
808 |
|
fwrite(block->data, 1, block->size, output); /* data */ |
724 |
809 |
} |
} |
725 |
|
seg++; |
|
|
810 |
|
block++; |
726 |
811 |
} |
} |
727 |
812 |
*addr = host_to_le32(0xFFFFFFFFu); /* set block end */ |
*addr = host_to_le32(0xFFFFFFFFu); /* set block end */ |
728 |
|
*size = host_to_le32(0); |
|
|
813 |
|
*size = host_to_le16(0); |
729 |
814 |
fwrite(&block_hdr, 1, sizeof(block_hdr), output); |
fwrite(&block_hdr, 1, sizeof(block_hdr), output); |
730 |
815 |
} |
} |
731 |
816 |
|
|
|
... |
... |
static void dump_pdr(FILE* output, |
756 |
841 |
static void dump_compat(FILE* output, |
static void dump_compat(FILE* output, |
757 |
842 |
const struct _compat_info *compat) |
const struct _compat_info *compat) |
758 |
843 |
{ |
{ |
|
844 |
|
__le16 buf[sizeof(*compat)/sizeof(__le16)]; |
|
845 |
|
|
|
846 |
|
printf("buf is %d bytes\n", sizeof(buf)); |
|
847 |
|
printf("le16 is %d bytes\n", sizeof(__le16)); |
|
848 |
|
printf("*compat is %d bytes\n", sizeof(*compat)); |
|
849 |
|
|
759 |
850 |
/* Dump non-zero length blocks. |
/* Dump non-zero length blocks. |
760 |
851 |
* No need to reformat. */ |
* No need to reformat. */ |
761 |
852 |
while (compat->size != 0) |
while (compat->size != 0) |
762 |
853 |
{ |
{ |
763 |
|
fwrite(compat, 1, sizeof(*compat), output); |
|
|
854 |
|
int i; |
|
855 |
|
|
|
856 |
|
for (i = 0; i < (sizeof(buf)/sizeof(buf[0])); i++) |
|
857 |
|
{ |
|
858 |
|
buf[i] = host_to_le16(((u16*)compat)[i]); |
|
859 |
|
} |
|
860 |
|
fwrite(buf, 1, sizeof(buf), output); |
764 |
861 |
compat++; |
compat++; |
|
862 |
|
printf("compat is at %x. size is %d\n", (int) compat, compat->size); |
765 |
863 |
} |
} |
766 |
864 |
/* sentinel */ |
/* sentinel */ |
767 |
|
fwrite(compat, 1, sizeof(*compat), output); |
|
|
865 |
|
memset(&buf, 0, sizeof(buf)); |
|
866 |
|
fwrite(&buf, 1, sizeof(buf), output); |
768 |
867 |
} |
} |
769 |
868 |
|
|
770 |
869 |
#define VERSION "HFW000" |
#define VERSION "HFW000" |
771 |
870 |
/* Returns zero, or a negative number to indicate an error */ |
/* Returns zero, or a negative number to indicate an error */ |
772 |
871 |
static int write_kernel_fw(FILE* output, |
static int write_kernel_fw(FILE* output, |
773 |
|
const struct firmwareblock *firmware) |
|
|
872 |
|
const struct fwtable *firmware) |
774 |
873 |
{ |
{ |
775 |
874 |
/* Note: does not deal with BE/LE issues */ |
/* Note: does not deal with BE/LE issues */ |
776 |
875 |
u32 image_header[6]; |
u32 image_header[6]; |
|
... |
... |
static int dump_fw(const char *basename, const char hexchar, |
819 |
918 |
u8* data, size_t flen, |
u8* data, size_t flen, |
820 |
919 |
const u8* signature, size_t slen) |
const u8* signature, size_t slen) |
821 |
920 |
{ |
{ |
822 |
|
struct firmwareblock firmware; |
|
|
921 |
|
struct fwtable firmware; |
823 |
922 |
char* fwname; |
char* fwname; |
824 |
923 |
char* filename; |
char* filename; |
825 |
924 |
u8* hint; |
u8* hint; |
826 |
925 |
u8* fw; /* pointer to the actual blocks for programming */ |
u8* fw; /* pointer to the actual blocks for programming */ |
827 |
|
unsigned int fwblock; /* virtual location of structure listing blocks to program for a given firmware */ |
|
828 |
|
struct _firmwareblock *fw_image; /* structure all elements of a given firmware */ |
|
|
926 |
|
u8* fwblock; /* location of structure listing blocks to program for a given firmware */ |
|
927 |
|
struct fwtable_drv *fw_image; /* structure all elements of a given firmware */ |
829 |
928 |
u32 ibase; |
u32 ibase; |
830 |
|
u32 vfwoffs; |
|
|
929 |
|
u32 vaddr; |
831 |
930 |
FILE* output; |
FILE* output; |
832 |
931 |
size_t len; |
size_t len; |
833 |
|
int found = 0; |
|
|
932 |
|
int macho = macho_validate(data); |
|
933 |
|
int mac = 0; |
834 |
934 |
|
|
835 |
|
if (memcmp(data, "MZ", 2) == 0) |
|
|
935 |
|
if (macho == 0) |
836 |
936 |
{ |
{ |
837 |
|
printf ("Driver looks like Microsoft PE format\n"); |
|
838 |
|
ibase = imagebase(data); |
|
839 |
|
found = 1; |
|
|
937 |
|
const u8* section_end; |
|
938 |
|
printf ("Driver looks like Apple Mach-O format\n"); |
|
939 |
|
ibase = macho_imagebase(data, §ion_end); |
|
940 |
|
|
|
941 |
|
/* restrict search area */ |
|
942 |
|
flen = section_end - data; |
|
943 |
|
|
|
944 |
|
driver_is_be = 1; |
|
945 |
|
mac = 1; |
840 |
946 |
} |
} |
841 |
|
|
|
842 |
|
if (!found) |
|
|
947 |
|
else if (macho == -1) |
843 |
948 |
{ |
{ |
844 |
|
int ret; |
|
845 |
|
|
|
846 |
|
ret = macho_validate(data); |
|
847 |
|
if (ret == 0) |
|
848 |
|
{ |
|
849 |
|
printf ("Driver looks like Apple Mach-O format\n"); |
|
850 |
|
ibase = macho_imagebase(data); |
|
851 |
|
found = 1; |
|
852 |
|
} |
|
853 |
|
else if (ret == -1) |
|
854 |
|
{ |
|
855 |
|
printf ("Driver looks like Apple Mach-O format\n" |
|
856 |
|
"But only a 32-bit PPC Mach-O format driver is supported.\n"); |
|
857 |
|
return -5; |
|
858 |
|
} |
|
|
949 |
|
printf ("Driver looks like Apple Mach-O format\n" |
|
950 |
|
"But only a 32-bit PPC Mach-O format driver is supported.\n"); |
|
951 |
|
return -5; |
859 |
952 |
} |
} |
860 |
|
|
|
861 |
|
if (!found && memcmp(data, "Joy!", 4) == 0) |
|
|
953 |
|
else if (memcmp(data, "MZ", 2) == 0) |
|
954 |
|
{ |
|
955 |
|
printf ("Driver looks like Microsoft PE format\n"); |
|
956 |
|
ibase = pe_imagebase(data); |
|
957 |
|
driver_is_be = 0; |
|
958 |
|
mac = 0; |
|
959 |
|
} |
|
960 |
|
else if (memcmp(data, "Joy!", 4) == 0) |
862 |
961 |
{ |
{ |
863 |
962 |
printf ("Driver looks like Apple PEF format\n"); |
printf ("Driver looks like Apple PEF format\n"); |
864 |
963 |
printf ("I don't know how to extract for this format.\n" |
printf ("I don't know how to extract for this format.\n" |
|
... |
... |
static int dump_fw(const char *basename, const char hexchar, |
878 |
977 |
/* ibase = pef_imagebase(data); */ |
/* ibase = pef_imagebase(data); */ |
879 |
978 |
return -5; |
return -5; |
880 |
979 |
} |
} |
881 |
|
|
|
882 |
|
if (!found) |
|
|
980 |
|
else |
883 |
981 |
{ |
{ |
884 |
982 |
printf ("Unknown object file format\n"); |
printf ("Unknown object file format\n"); |
885 |
983 |
return -5; |
return -5; |
|
... |
... |
static int dump_fw(const char *basename, const char hexchar, |
899 |
997 |
hint = data + flen; /* start from the end of file */ |
hint = data + flen; /* start from the end of file */ |
900 |
998 |
} |
} |
901 |
999 |
|
|
902 |
|
/* Now find the block using the signature */ |
|
|
1000 |
|
/* Now find the first firmware blob using the signature */ |
903 |
1001 |
fw = find_fw(data, flen, signature, slen, hint); |
fw = find_fw(data, flen, signature, slen, hint); |
904 |
1002 |
if (!fw) |
if (!fw) |
905 |
1003 |
return -1; |
return -1; |
906 |
1004 |
|
|
907 |
|
vfwoffs = (u32)(fw - data) + ibase; |
|
|
1005 |
|
vaddr = (u32)(fw - data) + ibase; |
908 |
1006 |
|
|
909 |
1007 |
printf("Image base is 0x%08x, therefore virtual offset of firmware is 0x%08x\n", |
printf("Image base is 0x%08x, therefore virtual offset of firmware is 0x%08x\n", |
910 |
|
ibase, vfwoffs); |
|
|
1008 |
|
ibase, vaddr); |
911 |
1009 |
|
|
912 |
1010 |
fwblock = find_fwblock_entry(data, |
fwblock = find_fwblock_entry(data, |
913 |
1011 |
flen, |
flen, |
914 |
|
vfwoffs, |
|
915 |
|
ibase); |
|
916 |
|
if (!fwblock) |
|
|
1012 |
|
vaddr, |
|
1013 |
|
mac); |
|
1014 |
|
|
|
1015 |
|
vaddr = (fwblock - data) + ibase; |
|
1016 |
|
|
|
1017 |
|
if (!fwblock) { |
|
1018 |
|
printf("Firmware block entry not found - contact Mark!\n"); |
917 |
1019 |
return -2; |
return -2; |
|
1020 |
|
} else { |
|
1021 |
|
printf("Found firmware block entry at virtual location 0x%08x, file offset 0x%08x\n", |
|
1022 |
|
vaddr, |
|
1023 |
|
fwblock - data); |
|
1024 |
|
} |
|
1025 |
|
|
|
1026 |
|
/* The Mac firmware has a leading fwblock which we need to |
|
1027 |
|
* compensate for */ |
|
1028 |
|
if (mac) |
|
1029 |
|
fwblock -= sizeof(struct fwblock_mdrv); |
|
1030 |
|
vaddr = (fwblock - data) + ibase; |
918 |
1031 |
|
|
919 |
1032 |
fw_image = find_fwtable_entry(data, |
fw_image = find_fwtable_entry(data, |
920 |
1033 |
flen, |
flen, |
921 |
|
fwblock); |
|
|
1034 |
|
vaddr); |
922 |
1035 |
if (!fw_image) |
if (!fw_image) |
923 |
1036 |
return -3; |
return -3; |
924 |
1037 |
|
|
925 |
|
copy_fw_data(&firmware, fw_image, data, ibase); |
|
|
1038 |
|
copy_fw_data(&firmware, fw_image, data, mac, ibase); |
926 |
1039 |
|
|
927 |
1040 |
/* Print FW ident information */ |
/* Print FW ident information */ |
928 |
1041 |
printf("Entry point at 0x%08x\n", firmware.halfentry * 2); |
printf("Entry point at 0x%08x\n", firmware.halfentry * 2); |