File hfwget.c changed (mode: 100644) (index 54d1546..9b9f2fc) |
3 |
3 |
* This may be distributed freely under the GPL v2 so long as this copyright |
* This may be distributed freely under the GPL v2 so long as this copyright |
4 |
4 |
* notice is included. |
* notice is included. |
5 |
5 |
* |
* |
6 |
|
* Following modifications (c) 2007 David Kilroy |
|
|
6 |
|
* Following modifications (c) 2008 David Kilroy |
7 |
7 |
* primary plug data |
* primary plug data |
8 |
8 |
* compatibility info |
* compatibility info |
9 |
9 |
* firmware identification |
* firmware identification |
|
22 |
22 |
#include <memory.h> |
#include <memory.h> |
23 |
23 |
#include <string.h> |
#include <string.h> |
24 |
24 |
|
|
25 |
|
#define false 0 |
|
26 |
|
#define true (!0) |
|
|
25 |
|
#if __STDC_VERSION__>=199901L |
|
26 |
|
# include <stdbool.h> |
|
27 |
|
#else |
|
28 |
|
typedef int bool; |
|
29 |
|
|
|
30 |
|
# define false 0 |
|
31 |
|
# define true (!0) |
|
32 |
|
#endif |
27 |
33 |
|
|
28 |
34 |
/* Typedefs for little and big endian values */ |
/* Typedefs for little and big endian values */ |
29 |
35 |
typedef uint32_t __le32; |
typedef uint32_t __le32; |
|
... |
... |
typedef uint16_t __le16; |
31 |
37 |
typedef uint32_t __be32; |
typedef uint32_t __be32; |
32 |
38 |
typedef uint16_t __be16; |
typedef uint16_t __be16; |
33 |
39 |
|
|
|
40 |
|
/* Driver endianness */ |
|
41 |
|
typedef uint32_t __de32; |
|
42 |
|
typedef uint16_t __de16; |
|
43 |
|
|
|
44 |
|
|
34 |
45 |
/* Typedefs for sized integers */ |
/* Typedefs for sized integers */ |
35 |
46 |
typedef uint32_t u32; |
typedef uint32_t u32; |
36 |
47 |
typedef uint16_t u16; |
typedef uint16_t u16; |
37 |
|
typedef uint8_t u8; |
|
|
48 |
|
typedef uint8_t u8; |
|
49 |
|
|
|
50 |
|
#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) |
38 |
51 |
|
|
39 |
52 |
/*** Macros to deal with different endianess ***/ |
/*** Macros to deal with different endianess ***/ |
40 |
53 |
|
|
|
... |
... |
typedef uint8_t u8; |
42 |
55 |
#define swap_bytes_16(value) \ |
#define swap_bytes_16(value) \ |
43 |
56 |
((((value) >> 8) & 0xFF) | \ |
((((value) >> 8) & 0xFF) | \ |
44 |
57 |
(((value) & 0xFF) << 8)) |
(((value) & 0xFF) << 8)) |
|
58 |
|
|
45 |
59 |
/* 0xAABBCCDD to 0xDDCCBBAA */ |
/* 0xAABBCCDD to 0xDDCCBBAA */ |
46 |
60 |
#define reverse_bytes_32(value) \ |
#define reverse_bytes_32(value) \ |
47 |
61 |
((((value) >> 24) & 0x0000FF) | \ |
((((value) >> 24) & 0x0000FF) | \ |
48 |
62 |
(((value) >> 8) & 0x00FF00) | \ |
(((value) >> 8) & 0x00FF00) | \ |
49 |
63 |
(((value) << 8) & 0xFF0000) | \ |
(((value) << 8) & 0xFF0000) | \ |
50 |
64 |
(((value) & 0xFF) << 24)) |
(((value) & 0xFF) << 24)) |
|
65 |
|
|
51 |
66 |
/* 0xAABBCCDD to 0xBBAADDCC */ |
/* 0xAABBCCDD to 0xBBAADDCC */ |
52 |
67 |
#define swap_bytes_32(value) \ |
#define swap_bytes_32(value) \ |
53 |
68 |
((((value) >> 8) & 0x00FF00FF) | \ |
((((value) >> 8) & 0x00FF00FF) | \ |
54 |
69 |
(((value) << 8) & 0xFF00FF00)) |
(((value) << 8) & 0xFF00FF00)) |
|
70 |
|
|
55 |
71 |
/* 0xAABBCCDD to 0xCCDDAABB */ |
/* 0xAABBCCDD to 0xCCDDAABB */ |
56 |
72 |
#define swap_words_32(value) \ |
#define swap_words_32(value) \ |
57 |
73 |
((((value) >> 16) & 0x0000FFFF) | \ |
((((value) >> 16) & 0x0000FFFF) | \ |
58 |
74 |
(((value) << 16) & 0xFFFF0000)) |
(((value) << 16) & 0xFFFF0000)) |
59 |
75 |
|
|
60 |
|
/* address 0 1 2 3 */ |
|
61 |
|
/* Pure LE stores 0x12345678 as 0x78 0x56 0x34 0x12 */ |
|
62 |
|
/* Pure BE stores 0x12345678 as 0x12 0x34 0x56 0x78 */ |
|
63 |
|
/* BEW+LEB stores 0x12345678 as 0x34 0x12 0x78 0x56 */ |
|
64 |
|
/* LEW+BEB stores 0x12345678 as 0x56 0x78 0x12 0x34 */ |
|
65 |
|
static int host_bytes_in_word_be = 0; |
|
66 |
|
static int host_words_in_dword_be = 0; |
|
67 |
|
static int driver_is_be = 0; |
|
|
76 |
|
/* address -> 0 1 2 3 |
|
77 |
|
* Pure LE stores 0x12345678 as 0x78 0x56 0x34 0x12 |
|
78 |
|
* Pure BE stores 0x12345678 as 0x12 0x34 0x56 0x78 |
|
79 |
|
* BEW+LEB stores 0x12345678 as 0x34 0x12 0x78 0x56 |
|
80 |
|
* LEW+BEB stores 0x12345678 as 0x56 0x78 0x12 0x34 |
|
81 |
|
*/ |
|
82 |
|
static bool host_bytes_in_word_be = false; |
|
83 |
|
static bool host_words_in_dword_be = false; |
|
84 |
|
static bool driver_is_be = false; |
68 |
85 |
|
|
69 |
|
#define host_to_le16(value) \ |
|
|
86 |
|
#define host_to_le16(value) (__le16) \ |
70 |
87 |
(host_bytes_in_word_be ? swap_bytes_16(value) : (value)) |
(host_bytes_in_word_be ? swap_bytes_16(value) : (value)) |
71 |
|
#define host_to_le32(value) \ |
|
72 |
|
(host_words_in_dword_be ? \ |
|
|
88 |
|
#define host_to_le32(value) (__le32) \ |
|
89 |
|
(host_words_in_dword_be ? \ |
73 |
90 |
(host_bytes_in_word_be ? reverse_bytes_32(value) \ |
(host_bytes_in_word_be ? reverse_bytes_32(value) \ |
74 |
91 |
: swap_bytes_32(value)) : \ |
: swap_bytes_32(value)) : \ |
75 |
92 |
(host_bytes_in_word_be ? swap_words_32(value) : (value))) |
(host_bytes_in_word_be ? swap_words_32(value) : (value))) |
76 |
93 |
|
|
77 |
|
#define le16_to_host(value) \ |
|
|
94 |
|
#define le16_to_host(value) (u16) \ |
78 |
95 |
(host_bytes_in_word_be ? swap_bytes_16(value) : (value)) |
(host_bytes_in_word_be ? swap_bytes_16(value) : (value)) |
79 |
|
#define le32_to_host(value) \ |
|
80 |
|
(host_words_in_dword_be ? \ |
|
|
96 |
|
#define le32_to_host(value) (u32) \ |
|
97 |
|
(host_words_in_dword_be ? \ |
81 |
98 |
(host_bytes_in_word_be ? reverse_bytes_32(value) \ |
(host_bytes_in_word_be ? reverse_bytes_32(value) \ |
82 |
99 |
: swap_bytes_32(value)) : \ |
: swap_bytes_32(value)) : \ |
83 |
100 |
(host_bytes_in_word_be ? swap_words_32(value) : (value))) |
(host_bytes_in_word_be ? swap_words_32(value) : (value))) |
84 |
101 |
|
|
85 |
|
#define host_to_be16(value) \ |
|
|
102 |
|
#define host_to_be16(value) (__be16) \ |
86 |
103 |
(host_bytes_in_word_be ? (value) : swap_bytes_16(value)) |
(host_bytes_in_word_be ? (value) : swap_bytes_16(value)) |
87 |
|
#define host_to_be32(value) \ |
|
88 |
|
(host_words_in_dword_be ? \ |
|
|
104 |
|
#define host_to_be32(value) (__be32) \ |
|
105 |
|
(host_words_in_dword_be ? \ |
89 |
106 |
(host_bytes_in_word_be ? (value) : swap_bytes_32(value)) : \ |
(host_bytes_in_word_be ? (value) : swap_bytes_32(value)) : \ |
90 |
107 |
(host_bytes_in_word_be ? swap_words_32(value) \ |
(host_bytes_in_word_be ? swap_words_32(value) \ |
91 |
108 |
: reverse_bytes_32(value))) |
: reverse_bytes_32(value))) |
92 |
109 |
|
|
93 |
|
#define be16_to_host(value) \ |
|
|
110 |
|
#define be16_to_host(value) (u16) \ |
94 |
111 |
(host_bytes_in_word_be ? (value) : swap_bytes_16(value)) |
(host_bytes_in_word_be ? (value) : swap_bytes_16(value)) |
95 |
|
#define be32_to_host(value) \ |
|
96 |
|
(host_words_in_dword_be ? \ |
|
|
112 |
|
#define be32_to_host(value) (u32) \ |
|
113 |
|
(host_words_in_dword_be ? \ |
97 |
114 |
(host_bytes_in_word_be ? (value) : swap_bytes_32(value)) : \ |
(host_bytes_in_word_be ? (value) : swap_bytes_32(value)) : \ |
98 |
115 |
(host_bytes_in_word_be ? swap_words_32(value) \ |
(host_bytes_in_word_be ? swap_words_32(value) \ |
99 |
116 |
: reverse_bytes_32(value))) |
: reverse_bytes_32(value))) |
100 |
117 |
|
|
101 |
|
#define driver_to_host_16(value) \ |
|
|
118 |
|
#define driver_to_host_16(value) (u16) \ |
102 |
119 |
(driver_is_be ? be16_to_host(value) : le16_to_host(value)) |
(driver_is_be ? be16_to_host(value) : le16_to_host(value)) |
103 |
|
#define driver_to_host_32(value) \ |
|
|
120 |
|
#define driver_to_host_32(value) (u32) \ |
104 |
121 |
(driver_is_be ? be32_to_host(value) : le32_to_host(value)) |
(driver_is_be ? be32_to_host(value) : le32_to_host(value)) |
105 |
|
#define host_to_driver_16(value) \ |
|
|
122 |
|
#define host_to_driver_16(value) (__de16) \ |
106 |
123 |
(driver_is_be ? host_to_be16(value) : host_to_le16(value)) |
(driver_is_be ? host_to_be16(value) : host_to_le16(value)) |
107 |
|
#define host_to_driver_32(value) \ |
|
|
124 |
|
#define host_to_driver_32(value) (__de32) \ |
108 |
125 |
(driver_is_be ? host_to_be32(value) : host_to_le32(value)) |
(driver_is_be ? host_to_be32(value) : host_to_le32(value)) |
109 |
126 |
|
|
110 |
127 |
/**** Structures to read image data from driver ****/ |
/**** Structures to read image data from driver ****/ |
111 |
128 |
|
|
112 |
|
/* Decode the windows firmware blocks */ |
|
|
129 |
|
/* Decode Windows firmware blocks */ |
113 |
130 |
struct fwblock_wdrv { |
struct fwblock_wdrv { |
114 |
131 |
__le32 offset; |
__le32 offset; |
115 |
132 |
__le16 size; |
__le16 size; |
|
... |
... |
struct fwblock_wdrv { |
117 |
134 |
__le32 data_p; |
__le32 data_p; |
118 |
135 |
}; |
}; |
119 |
136 |
|
|
120 |
|
/* Decode the mac firmware blocks */ |
|
|
137 |
|
/* Decode Mac firmware blocks */ |
121 |
138 |
struct fwblock_mdrv { |
struct fwblock_mdrv { |
122 |
139 |
__be16 len; |
__be16 len; |
123 |
140 |
__be16 code; |
__be16 code; |
|
... |
... |
struct fwblock_mdrv { |
128 |
145 |
__be32 data_p; |
__be32 data_p; |
129 |
146 |
}; |
}; |
130 |
147 |
|
|
131 |
|
struct _plugarray { |
|
132 |
|
__le32 code; |
|
133 |
|
__le32 targ_off; |
|
134 |
|
__le32 length; |
|
|
148 |
|
union fwblock_drv { |
|
149 |
|
struct fwblock_wdrv *w; |
|
150 |
|
struct fwblock_mdrv *m; |
135 |
151 |
}; |
}; |
136 |
152 |
|
|
137 |
|
struct _ident_info { |
|
138 |
|
__le16 size; |
|
139 |
|
__le16 code; |
|
140 |
|
__le16 comp_id; |
|
141 |
|
__le16 variant; |
|
142 |
|
__le16 version_major; |
|
143 |
|
__le16 version_minor; |
|
|
153 |
|
struct plugarray_drv { |
|
154 |
|
__de32 code; |
|
155 |
|
__de32 targ_off; |
|
156 |
|
__de32 length; |
144 |
157 |
}; |
}; |
145 |
158 |
|
|
146 |
|
struct _compat_info { |
|
147 |
|
__le16 size; |
|
148 |
|
__le16 code; |
|
149 |
|
__le16 role; |
|
150 |
|
__le16 id; |
|
151 |
|
struct |
|
152 |
|
{ |
|
153 |
|
__le16 variant; |
|
154 |
|
__le16 bottom; |
|
155 |
|
__le16 top; |
|
|
159 |
|
struct ident_info_drv { |
|
160 |
|
__de16 size; |
|
161 |
|
__de16 code; |
|
162 |
|
__de16 comp_id; |
|
163 |
|
__de16 variant; |
|
164 |
|
__de16 version_major; |
|
165 |
|
__de16 version_minor; |
|
166 |
|
}; |
|
167 |
|
|
|
168 |
|
struct compat_info_drv { |
|
169 |
|
__de16 size; |
|
170 |
|
__de16 code; |
|
171 |
|
__de16 role; |
|
172 |
|
__de16 id; |
|
173 |
|
struct { |
|
174 |
|
__de16 variant; |
|
175 |
|
__de16 bottom; |
|
176 |
|
__de16 top; |
156 |
177 |
} range[20]; |
} range[20]; |
157 |
178 |
}; |
}; |
158 |
179 |
|
|
159 |
180 |
struct fwtable_drv { |
struct fwtable_drv { |
160 |
|
__le32 segarray_p; |
|
161 |
|
__le32 halfentry; |
|
162 |
|
__le32 plugarray_p; |
|
163 |
|
__le32 pri_plugarray_p; |
|
164 |
|
__le32 compat_p; |
|
165 |
|
__le32 ident_p; |
|
|
181 |
|
__de32 segarray_p; |
|
182 |
|
__de32 halfentry; |
|
183 |
|
__de32 plugarray_p; |
|
184 |
|
__de32 pri_plugarray_p; |
|
185 |
|
__de32 compat_p; |
|
186 |
|
__de32 ident_p; |
166 |
187 |
}; |
}; |
167 |
188 |
|
|
168 |
189 |
/*** Structures to use on host. ***/ |
/*** Structures to use on host. ***/ |
|
... |
... |
struct fwblock { |
173 |
194 |
uint8_t *data; |
uint8_t *data; |
174 |
195 |
}; |
}; |
175 |
196 |
|
|
|
197 |
|
struct plugarray { |
|
198 |
|
u32 code; |
|
199 |
|
u32 targ_off; |
|
200 |
|
u32 length; |
|
201 |
|
}; |
|
202 |
|
|
|
203 |
|
struct ident_info { |
|
204 |
|
u16 size; |
|
205 |
|
u16 code; |
|
206 |
|
u16 comp_id; |
|
207 |
|
u16 variant; |
|
208 |
|
u16 version_major; |
|
209 |
|
u16 version_minor; |
|
210 |
|
}; |
|
211 |
|
|
|
212 |
|
struct compat_info { |
|
213 |
|
u16 size; |
|
214 |
|
u16 code; |
|
215 |
|
u16 role; |
|
216 |
|
u16 id; |
|
217 |
|
struct { |
|
218 |
|
u16 variant; |
|
219 |
|
u16 bottom; |
|
220 |
|
u16 top; |
|
221 |
|
} range[20]; |
|
222 |
|
}; |
|
223 |
|
|
176 |
224 |
struct fwtable { |
struct fwtable { |
177 |
|
union { |
|
178 |
|
struct fwblock_wdrv *w; |
|
179 |
|
struct fwblock_mdrv *m; |
|
180 |
|
} segarray_im; |
|
181 |
|
struct fwblock segarray[4]; |
|
|
225 |
|
struct fwblock *segarray; |
182 |
226 |
u32 halfentry; |
u32 halfentry; |
183 |
|
struct _plugarray *plugarray; |
|
184 |
|
struct _plugarray *pri_plugarray; |
|
185 |
|
struct _compat_info *compat; |
|
186 |
|
struct _ident_info *ident; |
|
|
227 |
|
struct plugarray *plugarray; |
|
228 |
|
struct plugarray *pri_plugarray; |
|
229 |
|
struct compat_info *compat; |
|
230 |
|
struct ident_info *ident; |
187 |
231 |
}; |
}; |
188 |
232 |
|
|
189 |
|
/* Structure to map firmware identifiers to description strings */ |
|
190 |
|
static const struct |
|
|
233 |
|
/* Structure detailing firmware differences between Windows and Mac */ |
|
234 |
|
struct fw_layout { |
|
235 |
|
const int block_prefix; /* Bytes before the start of a firmware block */ |
|
236 |
|
const size_t lead_block_bytes; /* Bytes used by lead blocks */ |
|
237 |
|
const size_t datap_offset; /* Offset of data_p in fw_block struct */ |
|
238 |
|
size_t max_offset; /* No firmware after this offset */ |
|
239 |
|
ptrdiff_t addr_delta; /* Difference between addresses encoded in the |
|
240 |
|
* driver and the file offset of the associated |
|
241 |
|
* data */ |
|
242 |
|
bool mac; /* Use mac structures */ |
|
243 |
|
}; |
|
244 |
|
|
|
245 |
|
static struct fw_layout firmware_layout[] = |
191 |
246 |
{ |
{ |
|
247 |
|
{ /* Windows */ |
|
248 |
|
4, 0 * sizeof(struct fwblock_wdrv), |
|
249 |
|
offsetof(struct fwblock_wdrv, data_p) |
|
250 |
|
}, |
|
251 |
|
{ /* Mac */ |
|
252 |
|
0, 1 * sizeof(struct fwblock_mdrv), |
|
253 |
|
offsetof(struct fwblock_mdrv, data_p) |
|
254 |
|
} |
|
255 |
|
}; |
|
256 |
|
|
|
257 |
|
/* Structure to map firmware identifiers to description strings */ |
|
258 |
|
static const struct { |
192 |
259 |
u16 id; |
u16 id; |
193 |
260 |
char *comp_string; |
char *comp_string; |
194 |
261 |
} compat_table[] = |
} compat_table[] = |
|
... |
... |
static const struct |
226 |
293 |
|
|
227 |
294 |
/* Checking endianess at runtime because performance isn't an issue, |
/* Checking endianess at runtime because performance isn't an issue, |
228 |
295 |
* and I'd rather not add a configure step */ |
* and I'd rather not add a configure step */ |
229 |
|
static void check_endianess(void) { |
|
|
296 |
|
static void check_endianess(void) |
|
297 |
|
{ |
230 |
298 |
union { |
union { |
231 |
299 |
u32 dword; |
u32 dword; |
232 |
300 |
u16 word[2]; |
u16 word[2]; |
|
... |
... |
static void check_endianess(void) { |
234 |
302 |
} data; |
} data; |
235 |
303 |
|
|
236 |
304 |
data.dword = 0x12345678; |
data.dword = 0x12345678; |
237 |
|
if (data.word[0] == 0x1234) { |
|
238 |
|
host_words_in_dword_be = 1; |
|
|
305 |
|
if (data.word[0] == 0x1234) |
|
306 |
|
{ |
|
307 |
|
host_words_in_dword_be = true; |
239 |
308 |
} |
} |
240 |
|
else if (data.word[0] == 0x5678) { |
|
241 |
|
host_words_in_dword_be = 0; |
|
242 |
|
} else { |
|
|
309 |
|
else if (data.word[0] == 0x5678) |
|
310 |
|
{ |
|
311 |
|
host_words_in_dword_be = false; |
|
312 |
|
} |
|
313 |
|
else |
|
314 |
|
{ |
243 |
315 |
fprintf(stderr, "Can't determine endianess of host!\n"); |
fprintf(stderr, "Can't determine endianess of host!\n"); |
244 |
|
exit(1); |
|
|
316 |
|
exit(EXIT_FAILURE); |
245 |
317 |
} |
} |
246 |
318 |
|
|
247 |
319 |
data.word[0] = 0x1234; |
data.word[0] = 0x1234; |
248 |
|
if (data.byte[0] == 0x12) { |
|
249 |
|
host_bytes_in_word_be = 1; |
|
250 |
|
} else if (data.byte[0] == 0x34) { |
|
251 |
|
host_bytes_in_word_be = 0; |
|
252 |
|
} else { |
|
|
320 |
|
if (data.byte[0] == 0x12) |
|
321 |
|
{ |
|
322 |
|
host_bytes_in_word_be = true; |
|
323 |
|
} |
|
324 |
|
else if (data.byte[0] == 0x34) |
|
325 |
|
{ |
|
326 |
|
host_bytes_in_word_be = false; |
|
327 |
|
} |
|
328 |
|
else |
|
329 |
|
{ |
253 |
330 |
fprintf(stderr, "Can't determine endianess of host!\n"); |
fprintf(stderr, "Can't determine endianess of host!\n"); |
|
331 |
|
exit(EXIT_FAILURE); |
254 |
332 |
} |
} |
255 |
333 |
|
|
256 |
|
if (host_bytes_in_word_be == host_words_in_dword_be) { |
|
257 |
|
fprintf (stdout, "Detected %s host\n", |
|
258 |
|
host_bytes_in_word_be ? "big endian" : "little endian"); |
|
259 |
|
} else { |
|
260 |
|
fprintf (stdout, "Detected host with mixed endianess\n"); |
|
|
334 |
|
if (host_bytes_in_word_be == host_words_in_dword_be) |
|
335 |
|
{ |
|
336 |
|
fprintf(stdout, "Detected %s host\n", |
|
337 |
|
host_bytes_in_word_be ? "big endian" : "little endian"); |
|
338 |
|
} |
|
339 |
|
else |
|
340 |
|
{ |
|
341 |
|
fprintf(stdout, "Detected host with mixed endianess\n"); |
261 |
342 |
} |
} |
262 |
343 |
return; |
return; |
263 |
344 |
} |
} |
264 |
345 |
|
|
265 |
346 |
/* Locate firmware by looking for a T???????.HEX filename */ |
/* Locate firmware by looking for a T???????.HEX filename */ |
266 |
|
static char* find_fw_filename(const u8 *hostdriver, |
|
267 |
|
unsigned int flen, |
|
268 |
|
u8 hexchar) |
|
|
347 |
|
static char* find_fw_filename(const u8 *hostdriver, size_t flen, char hexchar) |
269 |
348 |
{ |
{ |
270 |
349 |
const u8 *p, *end; |
const u8 *p, *end; |
271 |
|
int found; |
|
|
350 |
|
bool found; |
272 |
351 |
|
|
273 |
352 |
/* Find the ?1XXYYZZ.HEX string */ |
/* Find the ?1XXYYZZ.HEX string */ |
274 |
353 |
p = hostdriver; |
p = hostdriver; |
|
... |
... |
static char* find_fw_filename(const u8 *hostdriver, |
276 |
355 |
|
|
277 |
356 |
for (found = false; (found == false) && (p != NULL); ) |
for (found = false; (found == false) && (p != NULL); ) |
278 |
357 |
{ |
{ |
279 |
|
p = memchr(p, hexchar, (unsigned int)(end - p)); |
|
|
358 |
|
p = memchr(p, hexchar, (end - p)); |
280 |
359 |
|
|
281 |
360 |
if (p != NULL) |
if (p != NULL) |
282 |
361 |
{ |
{ |
|
... |
... |
static char* find_fw_filename(const u8 *hostdriver, |
294 |
373 |
if (p != NULL) |
if (p != NULL) |
295 |
374 |
{ |
{ |
296 |
375 |
printf("Found firmware %s at file offset 0x%08x\n", |
printf("Found firmware %s at file offset 0x%08x\n", |
297 |
|
p, p - hostdriver); |
|
|
376 |
|
p, (p - hostdriver)); |
298 |
377 |
} |
} |
299 |
378 |
else |
else |
300 |
379 |
{ |
{ |
|
... |
... |
static char* find_fw_filename(const u8 *hostdriver, |
307 |
386 |
/* Find the start of the firmware based on a hint as to where the end |
/* Find the start of the firmware based on a hint as to where the end |
308 |
387 |
* of the firmware image is. The start of the firmware image is |
* of the firmware image is. The start of the firmware image is |
309 |
388 |
* defined by a signature. */ |
* defined by a signature. */ |
310 |
|
static u8* find_fw(const u8* hostdriver, |
|
311 |
|
unsigned int flen, |
|
312 |
|
const u8* signature, |
|
313 |
|
int slen, |
|
314 |
|
const u8* hint) |
|
|
389 |
|
static u8* find_fw(const u8 *hostdriver, size_t flen, |
|
390 |
|
const u8 *signature, size_t slen, |
|
391 |
|
const u8 *hint) |
315 |
392 |
{ |
{ |
316 |
393 |
const u8 *p = hint - slen; |
const u8 *p = hint - slen; |
317 |
|
unsigned int i; |
|
318 |
|
int found = false; |
|
|
394 |
|
bool found = false; |
|
395 |
|
size_t i; |
319 |
396 |
|
|
320 |
397 |
printf("Searching for firmware from offset 0x%08x, start signature", |
printf("Searching for firmware from offset 0x%08x, start signature", |
321 |
398 |
hint - hostdriver); |
hint - hostdriver); |
|
... |
... |
static u8* find_fw(const u8* hostdriver, |
343 |
420 |
} |
} |
344 |
421 |
|
|
345 |
422 |
/* Returns a pointer to the PE header */ |
/* Returns a pointer to the PE header */ |
346 |
|
static u8* peheader(const u8* data) |
|
|
423 |
|
static void* pe_header(const void *data) |
347 |
424 |
{ |
{ |
348 |
|
__le32 *e_lfanew = (__le32*) (data + 0x3c); |
|
|
425 |
|
__le32 *e_lfanew = (__le32 *) (data + 0x3c); |
349 |
426 |
|
|
350 |
427 |
/* data + *e_lfanew gives us the NT SIGNATURE |
/* data + *e_lfanew gives us the NT SIGNATURE |
351 |
428 |
* The NT signature is 4 bytes long. |
* The NT signature is 4 bytes long. |
352 |
|
* The PE header follow immediately. |
|
|
429 |
|
* The PE header follows immediately. |
353 |
430 |
*/ |
*/ |
354 |
|
return (u8*) (data + (le32_to_host(*e_lfanew) + 4)); |
|
|
431 |
|
return (void *)(data + (le32_to_host(*e_lfanew) + 4)); |
355 |
432 |
} |
} |
356 |
433 |
|
|
357 |
434 |
/* returns the expected imagebase */ |
/* returns the expected imagebase */ |
358 |
|
static unsigned int pe_imagebase(const u8* data) |
|
|
435 |
|
static u32 pe_imagebase(const void *data) |
359 |
436 |
{ |
{ |
360 |
|
u8* pehdr = peheader(data); |
|
361 |
|
return le32_to_host(*((u32*)(pehdr + 0x30))); |
|
|
437 |
|
void *pe_hdr = pe_header(data); |
|
438 |
|
|
|
439 |
|
return le32_to_host(*((u32 *) (pe_hdr + 0x30))); |
362 |
440 |
} |
} |
363 |
441 |
|
|
364 |
442 |
typedef __be32 mac_cpu_type_t; |
typedef __be32 mac_cpu_type_t; |
|
... |
... |
struct mach_header { |
375 |
453 |
__be32 flags; |
__be32 flags; |
376 |
454 |
}; |
}; |
377 |
455 |
|
|
378 |
|
struct mach_load_command |
|
379 |
|
{ |
|
|
456 |
|
struct mach_load_command { |
380 |
457 |
__be32 cmd; |
__be32 cmd; |
381 |
458 |
__be32 cmdsize; |
__be32 cmdsize; |
382 |
459 |
}; |
}; |
383 |
460 |
|
|
384 |
|
struct mach_segment_command |
|
385 |
|
{ |
|
|
461 |
|
struct mach_segment_command { |
386 |
462 |
__be32 cmd; |
__be32 cmd; |
387 |
463 |
__be32 cmdsize; |
__be32 cmdsize; |
388 |
464 |
char segname[16]; |
char segname[16]; |
|
... |
... |
struct mach_segment_command |
396 |
472 |
__be32 flags; |
__be32 flags; |
397 |
473 |
}; |
}; |
398 |
474 |
|
|
399 |
|
struct mach_section |
|
400 |
|
{ |
|
|
475 |
|
struct mach_section { |
401 |
476 |
char sectname[16]; |
char sectname[16]; |
402 |
477 |
char segname[16]; |
char segname[16]; |
403 |
478 |
__be32 addr; |
__be32 addr; |
|
... |
... |
struct mach_section |
416 |
491 |
* contains another second copy of our pointers later on (at about |
* contains another second copy of our pointers later on (at about |
417 |
492 |
* offset 0x12330) which interfere with our search. |
* offset 0x12330) which interfere with our search. |
418 |
493 |
*/ |
*/ |
419 |
|
static u32 macho_imagebase(const u8 *data, const u8 **section_end) |
|
|
494 |
|
static const struct mach_section* macho_fw_section(const void *data) |
420 |
495 |
{ |
{ |
421 |
|
struct mach_header *hdr = (struct mach_header *) data; |
|
422 |
|
int i, j; |
|
423 |
|
const u8 *p = data + sizeof(struct mach_header); |
|
|
496 |
|
const struct mach_header *hdr = data; |
|
497 |
|
u32 i, j; |
|
498 |
|
const void *p = data + sizeof(struct mach_header); |
424 |
499 |
|
|
425 |
|
for (i = 0; i < be32_to_host(hdr->ncmds); i++) { |
|
426 |
|
struct mach_load_command *load_cmd = (struct mach_load_command *) p; |
|
|
500 |
|
for (i = 0; i < be32_to_host(hdr->ncmds); i++) |
|
501 |
|
{ |
|
502 |
|
const struct mach_load_command *load_cmd = p; |
427 |
503 |
|
|
428 |
|
if (be32_to_host(load_cmd->cmd) == 0x0001) { /* LC_SEGMENT */ |
|
429 |
|
struct mach_segment_command *seg_cmd = (struct mach_segment_command *) p; |
|
|
504 |
|
if (be32_to_host(load_cmd->cmd) == 0x0001) |
|
505 |
|
{ |
|
506 |
|
/* LC_SEGMENT */ |
430 |
507 |
|
|
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; |
|
|
508 |
|
const struct mach_segment_command *seg_cmd = p; |
|
509 |
|
p += sizeof(struct mach_segment_command); |
|
510 |
|
for (j = 0; j < be32_to_host(seg_cmd->nsects); j++) |
|
511 |
|
{ |
|
512 |
|
const struct mach_section *sect = p; |
434 |
513 |
|
|
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 |
|
} |
|
|
514 |
|
if ((strcmp(sect->sectname, "__data") == 0) && |
|
515 |
|
(strcmp(sect->segname, "__DATA") == 0)) |
|
516 |
|
{ |
|
517 |
|
return sect; |
|
518 |
|
} |
440 |
519 |
|
|
441 |
|
p += sizeof (struct mach_section); |
|
442 |
|
} |
|
443 |
|
} |
|
|
520 |
|
p += sizeof(struct mach_section); |
|
521 |
|
} |
|
522 |
|
} |
444 |
523 |
|
|
445 |
|
/* advance to past the load command */ |
|
446 |
|
p += sizeof (struct mach_load_command); |
|
447 |
|
p += be32_to_host(load_cmd->cmdsize); |
|
|
524 |
|
/* advance to past the load command */ |
|
525 |
|
p += sizeof(struct mach_load_command); |
|
526 |
|
p += be32_to_host(load_cmd->cmdsize); |
448 |
527 |
} |
} |
449 |
528 |
|
|
450 |
529 |
printf("Couldn't find Mach-O __data/__DATA section\n"); |
printf("Couldn't find Mach-O __data/__DATA section\n"); |
451 |
|
return 0; |
|
|
530 |
|
return NULL; |
452 |
531 |
} |
} |
453 |
532 |
|
|
454 |
533 |
#define MH_MAGIC 0xfeedface /* BE Mach-O magic number */ |
#define MH_MAGIC 0xfeedface /* BE Mach-O magic number */ |
|
... |
... |
static u32 macho_imagebase(const u8 *data, const u8 **section_end) |
465 |
544 |
* -1 = Not a 32-bit PPC Mach-O object file |
* -1 = Not a 32-bit PPC Mach-O object file |
466 |
545 |
* -2 = Not a Mach-O object file |
* -2 = Not a Mach-O object file |
467 |
546 |
*/ |
*/ |
468 |
|
static int macho_validate(const u8 *data) |
|
|
547 |
|
static int macho_validate(const void *data) |
469 |
548 |
{ |
{ |
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)); |
|
|
549 |
|
const struct mach_header *hdr = data; |
475 |
550 |
|
|
476 |
|
switch (be32_to_host(hdr->magic)) { |
|
|
551 |
|
switch (be32_to_host(hdr->magic)) |
|
552 |
|
{ |
477 |
553 |
case MH_MAGIC: |
case MH_MAGIC: |
478 |
|
/* Yay, what we need */ |
|
479 |
|
break; |
|
|
554 |
|
/* Yay, what we need */ |
|
555 |
|
break; |
480 |
556 |
case MH_MAGIC_64: |
case MH_MAGIC_64: |
481 |
557 |
case MH_CIGAM_64: |
case MH_CIGAM_64: |
482 |
558 |
case MH_CIGAM: |
case MH_CIGAM: |
483 |
|
/* 64-bit or LE 32-bit, can't use it */ |
|
484 |
|
return -1; |
|
|
559 |
|
/* 64-bit or LE 32-bit, can't use it */ |
|
560 |
|
return -1; |
485 |
561 |
default: |
default: |
486 |
|
/* Not a Mach-O file at all */ |
|
487 |
|
return -2; |
|
|
562 |
|
/* Not a Mach-O file at all */ |
|
563 |
|
return -2; |
488 |
564 |
} |
} |
489 |
565 |
|
|
490 |
|
if (be32_to_host(hdr->cputype) != 0x12) /* PPC */ |
|
491 |
|
return -1; |
|
|
566 |
|
/* PPC */ |
|
567 |
|
if (be32_to_host(hdr->cputype) != 0x12) |
|
568 |
|
return -1; |
|
569 |
|
|
|
570 |
|
/* MH_OBJECT */ |
|
571 |
|
if (be32_to_host(hdr->filetype) != 0x0001) |
|
572 |
|
return -1; |
492 |
573 |
|
|
493 |
|
if (be32_to_host(hdr->filetype) != 0x0001) /* MH_OBJECT */ |
|
494 |
|
return -1; |
|
495 |
|
|
|
496 |
574 |
return 0; |
return 0; |
497 |
575 |
} |
} |
498 |
576 |
|
|
499 |
577 |
/* Returns a pointer within data, to the fwblock pointing containing a |
/* Returns a pointer within data, to the fwblock pointing containing a |
500 |
578 |
* pointer to addr (in driver address space)*/ |
* 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) |
|
|
579 |
|
static u8* find_fwblock_entry(const u8 *data, const struct fw_layout *layout, |
|
580 |
|
u32 addr) |
505 |
581 |
{ |
{ |
506 |
|
u32 *p = (u32*) ((unsigned int)(data + flen) & 0xFFFFFFFCu); |
|
507 |
|
int found = false; |
|
508 |
|
|
|
509 |
|
if (!mac) { |
|
510 |
|
addr -= 4; /* kludge for driver firmware structure: one |
|
511 |
|
* redundant dword at start. */ |
|
512 |
|
} |
|
|
582 |
|
u32 *p = (u32*) ((unsigned int)(data + layout->max_offset) & 0xFFFFFFFCu); |
|
583 |
|
bool found = false; |
513 |
584 |
|
|
514 |
585 |
printf("Now searching for driver's firmware block entry (0x%08x)...\n", |
printf("Now searching for driver's firmware block entry (0x%08x)...\n", |
515 |
586 |
addr); |
addr); |
516 |
587 |
|
|
517 |
|
addr = host_to_driver_32(addr); /* convert to driver endianness to |
|
518 |
|
* compare against file data */ |
|
|
588 |
|
/* Convert to driver endianness to compare against file data */ |
|
589 |
|
addr = host_to_driver_32(addr); |
519 |
590 |
|
|
520 |
591 |
/* Note that we're not searching each byte position for a match. |
/* Note that we're not searching each byte position for a match. |
521 |
592 |
* This should be fine because the data should have been placed on |
* This should be fine because the data should have been placed on |
522 |
593 |
* a 4-byte boundary */ |
* a 4-byte boundary */ |
523 |
594 |
|
|
524 |
|
for (found = false; |
|
525 |
|
((u8*)p >= data); |
|
526 |
|
p--) |
|
|
595 |
|
for (found = false; ((u8*)p >= data); p--) |
527 |
596 |
{ |
{ |
528 |
597 |
if (*p == addr) |
if (*p == addr) |
529 |
|
{ |
|
|
598 |
|
{ |
530 |
599 |
found = true; |
found = true; |
531 |
|
break; |
|
532 |
|
} |
|
|
600 |
|
break; |
|
601 |
|
} |
533 |
602 |
} |
} |
534 |
603 |
|
|
535 |
604 |
/* Compensate for the fields before the data_p pointer */ |
/* 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); |
|
|
605 |
|
p -= layout->datap_offset / sizeof(*p); |
540 |
606 |
|
|
541 |
607 |
return (u8*) p; |
return (u8*) p; |
542 |
608 |
} |
} |
543 |
609 |
|
|
544 |
|
static struct fwtable_drv* find_fwtable_entry(const u8* data, |
|
545 |
|
unsigned int flen, |
|
546 |
|
u32 fwblock) |
|
|
610 |
|
static struct fwtable_drv* find_fwtable_entry(const u8 *data, |
|
611 |
|
const struct fw_layout *layout, |
|
612 |
|
u32 fwblock) |
547 |
613 |
{ |
{ |
548 |
|
u32 *p = (u32*) ((unsigned int)(data + flen) & 0xFFFFFFFCu); |
|
549 |
|
int found = false; |
|
|
614 |
|
u32 *p = (u32*) ((unsigned int)(data + layout->max_offset) & 0xFFFFFFFCu); |
550 |
615 |
struct fwtable_drv *firmware; |
struct fwtable_drv *firmware; |
|
616 |
|
bool found = false; |
551 |
617 |
|
|
552 |
618 |
printf("Looking for main firmware table....\n"); |
printf("Looking for main firmware table....\n"); |
553 |
619 |
|
|
554 |
|
fwblock = host_to_driver_32(fwblock); /* convert to driver endianess to compare against file data */ |
|
555 |
|
|
|
556 |
|
printf("Looking for %x\n", fwblock); |
|
|
620 |
|
/* Convert to driver endianess to compare against file data */ |
|
621 |
|
fwblock = host_to_driver_32(fwblock); |
557 |
622 |
|
|
558 |
623 |
for (found = false; ((u8*)p >= data); p--) |
for (found = false; ((u8*)p >= data); p--) |
559 |
624 |
{ |
{ |
560 |
625 |
if (*p == fwblock) |
if (*p == fwblock) |
561 |
|
{ |
|
|
626 |
|
{ |
562 |
627 |
found = true; |
found = true; |
563 |
|
break; |
|
564 |
|
} |
|
|
628 |
|
break; |
|
629 |
|
} |
565 |
630 |
} |
} |
566 |
631 |
|
|
567 |
632 |
firmware = (struct fwtable_drv *)p; |
firmware = (struct fwtable_drv *)p; |
568 |
|
if (found == false) { |
|
|
633 |
|
if (found == false) |
|
634 |
|
{ |
569 |
635 |
printf("Main table not found - contact Mark!\n"); |
printf("Main table not found - contact Mark!\n"); |
570 |
|
} else { |
|
|
636 |
|
} |
|
637 |
|
else |
|
638 |
|
{ |
571 |
639 |
printf("Found at file offset 0x%08x\n", (u8*)p - data); |
printf("Found at file offset 0x%08x\n", (u8*)p - data); |
572 |
640 |
} |
} |
573 |
641 |
return firmware; |
return firmware; |
|
... |
... |
static struct fwtable_drv* find_fwtable_entry(const u8* data, |
580 |
648 |
* 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, |
581 |
649 |
* 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. |
582 |
650 |
*/ |
*/ |
583 |
|
static void copy_fw_data(struct fwtable* firmware, |
|
584 |
|
struct fwtable_drv *fw_image, |
|
585 |
|
const u8 *data, |
|
586 |
|
int mac, |
|
587 |
|
u32 ibase) |
|
|
651 |
|
static void copy_fw_data(struct fwtable *firmware, |
|
652 |
|
const struct fwtable_drv *driver_fw, |
|
653 |
|
const void *data, |
|
654 |
|
const struct fw_layout *layout) |
588 |
655 |
{ |
{ |
589 |
|
u32 delta = (u32)data - ibase; |
|
590 |
|
unsigned int i; |
|
591 |
|
|
|
592 |
|
/* Deal with pointers in fwtable */ |
|
593 |
|
firmware->segarray_im.w = (struct fwblock_wdrv *) |
|
594 |
|
(driver_to_host_32(fw_image->segarray_p) + delta); |
|
595 |
|
firmware->plugarray = (struct _plugarray *) |
|
596 |
|
(driver_to_host_32(fw_image->plugarray_p) + delta); |
|
597 |
|
firmware->pri_plugarray = (struct _plugarray *) |
|
598 |
|
(driver_to_host_32(fw_image->pri_plugarray_p) + delta); |
|
599 |
|
firmware->compat = (struct _compat_info *) |
|
600 |
|
(driver_to_host_32(fw_image->compat_p) + delta); |
|
601 |
|
firmware->ident = (struct _ident_info *) |
|
602 |
|
(driver_to_host_32(fw_image->ident_p) + delta); |
|
603 |
|
firmware->halfentry = driver_to_host_32(fw_image->halfentry); |
|
604 |
|
|
|
605 |
|
for (i = 0; i < 4; i++) |
|
|
656 |
|
union fwblock_drv block; |
|
657 |
|
const struct plugarray_drv *pdr; |
|
658 |
|
const struct plugarray_drv *pri; |
|
659 |
|
const struct ident_info_drv *ident; |
|
660 |
|
const struct compat_info_drv *compat; |
|
661 |
|
|
|
662 |
|
/* Static data structures to write host endian data to */ |
|
663 |
|
static struct fwblock block_data[4] = {{ 0, 0, 0, 0 }}; |
|
664 |
|
static struct plugarray plug_data[64] = {{ 0, 0, 0 }}; |
|
665 |
|
static struct plugarray pri_plug_data[64] = {{ 0, 0, 0 }}; |
|
666 |
|
static struct ident_info ident_data = { 0, 0, 0, 0, 0, 0 }; |
|
667 |
|
static struct compat_info compat_data[16] = {{ 0 }}; |
|
668 |
|
u32 delta = (u32)data - layout->addr_delta; |
|
669 |
|
size_t i; |
|
670 |
|
|
|
671 |
|
/* Calculate valid pointers to driver data */ |
|
672 |
|
block.w = (struct fwblock_wdrv *) |
|
673 |
|
(driver_to_host_32(driver_fw->segarray_p) + delta); |
|
674 |
|
pdr = (struct plugarray_drv *) |
|
675 |
|
(driver_to_host_32(driver_fw->plugarray_p) + delta); |
|
676 |
|
pri = (struct plugarray_drv *) |
|
677 |
|
(driver_to_host_32(driver_fw->pri_plugarray_p) + delta); |
|
678 |
|
ident = (struct ident_info_drv *) |
|
679 |
|
(driver_to_host_32(driver_fw->ident_p) + delta); |
|
680 |
|
compat = (struct compat_info_drv *) |
|
681 |
|
(driver_to_host_32(driver_fw->compat_p) + delta); |
|
682 |
|
|
|
683 |
|
/* Setup pointers to host data */ |
|
684 |
|
firmware->segarray = &block_data[0]; |
|
685 |
|
firmware->plugarray = &plug_data[0]; |
|
686 |
|
firmware->pri_plugarray = &pri_plug_data[0]; |
|
687 |
|
firmware->compat = &compat_data[0]; |
|
688 |
|
firmware->ident = &ident_data; |
|
689 |
|
|
|
690 |
|
firmware->halfentry = driver_to_host_32(driver_fw->halfentry); |
|
691 |
|
|
|
692 |
|
for (i = 0; i < ARRAY_SIZE(block_data); i++) |
606 |
693 |
{ |
{ |
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) |
|
621 |
|
{ |
|
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", |
|
627 |
|
i, |
|
628 |
|
firmware->segarray[i].data - data, |
|
629 |
|
firmware->segarray[i].offset, |
|
630 |
|
firmware->segarray[i].size, |
|
631 |
|
(firmware->segarray[i].size == 0) ? " (ignored)" : ""); |
|
632 |
|
} |
|
633 |
|
else |
|
634 |
|
{ |
|
635 |
|
firmware->segarray[i].data = NULL; |
|
636 |
|
firmware->segarray[i].offset = 0; |
|
637 |
|
firmware->segarray[i].size = 0; |
|
638 |
|
firmware->segarray[i].flags = 0; |
|
639 |
|
break; |
|
640 |
|
} |
|
|
694 |
|
u32 offset = layout->mac ? driver_to_host_32(block.m[i].offset) : |
|
695 |
|
driver_to_host_32(block.w[i].offset); |
|
696 |
|
u32 data_p = ((layout->mac ? driver_to_host_32(block.m[i].data_p) : |
|
697 |
|
driver_to_host_32(block.w[i].data_p)) + |
|
698 |
|
layout->block_prefix); |
|
699 |
|
u16 size = layout->mac ? driver_to_host_16(block.m[i].size) : |
|
700 |
|
driver_to_host_16(block.w[i].size); |
|
701 |
|
u16 flags = layout->mac ? (u16) driver_to_host_32(block.m[i].flags) : |
|
702 |
|
driver_to_host_16(block.w[i].flags); |
|
703 |
|
|
|
704 |
|
if (offset != 0) |
|
705 |
|
{ |
|
706 |
|
firmware->segarray[i].data = (uint8_t *)(data_p + delta); |
|
707 |
|
firmware->segarray[i].offset = offset; |
|
708 |
|
firmware->segarray[i].size = size; |
|
709 |
|
firmware->segarray[i].flags = flags; |
|
710 |
|
printf("Segment: %d File offs: 0x%08x Target mem: 0x%08x " |
|
711 |
|
"Length 0x%04x%s\n", |
|
712 |
|
i, |
|
713 |
|
(void *)block.w - data, |
|
714 |
|
firmware->segarray[i].offset, |
|
715 |
|
firmware->segarray[i].size, |
|
716 |
|
(firmware->segarray[i].size == 0) ? " (ignored)" : ""); |
|
717 |
|
} |
|
718 |
|
else |
|
719 |
|
{ |
|
720 |
|
firmware->segarray[i].data = NULL; |
|
721 |
|
firmware->segarray[i].offset = 0; |
|
722 |
|
firmware->segarray[i].size = 0; |
|
723 |
|
firmware->segarray[i].flags = 0; |
|
724 |
|
break; |
|
725 |
|
} |
641 |
726 |
} |
} |
642 |
727 |
|
|
643 |
728 |
printf("Production Data plugrecords at file offset 0x%08x\n", |
printf("Production Data plugrecords at file offset 0x%08x\n", |
644 |
|
(u8*)firmware->plugarray - data); |
|
|
729 |
|
(void *)pdr - data); |
645 |
730 |
printf("Primary plugrecords at file offset 0x%08x\n", |
printf("Primary plugrecords at file offset 0x%08x\n", |
646 |
|
(u8*)firmware->pri_plugarray - data); |
|
|
731 |
|
(void *)pri - data); |
647 |
732 |
printf("Compatibility info at file offset 0x%08x\n", |
printf("Compatibility info at file offset 0x%08x\n", |
648 |
|
(u8*)firmware->compat - data); |
|
|
733 |
|
(void *)compat - data); |
649 |
734 |
printf("Identity info at file offset 0x%08x\n", |
printf("Identity info at file offset 0x%08x\n", |
650 |
|
(u8*)firmware->ident - data); |
|
|
735 |
|
(void *)ident - data); |
651 |
736 |
|
|
652 |
|
/* Convert plugarray (in place in image) */ |
|
653 |
|
for (i = 0; firmware->plugarray[i].code != 0; i++) |
|
|
737 |
|
/* Copy plugarray */ |
|
738 |
|
for (i = 0; (pdr[i].code != 0) && (i < ARRAY_SIZE(plug_data)); i++) |
654 |
739 |
{ |
{ |
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); |
|
|
740 |
|
firmware->plugarray[i].code = driver_to_host_32(pdr[i].code); |
|
741 |
|
firmware->plugarray[i].targ_off = driver_to_host_32(pdr[i].targ_off); |
|
742 |
|
firmware->plugarray[i].length = driver_to_host_32(pdr[i].length); |
658 |
743 |
} |
} |
659 |
744 |
|
|
660 |
|
/* Convert pri_array (in place in image) */ |
|
661 |
|
for (i = 0; firmware->pri_plugarray[i].code != 0; i++) |
|
|
745 |
|
/* Copy pri_array */ |
|
746 |
|
for (i = 0; (pri[i].code != 0) && (i < ARRAY_SIZE(pri_plug_data)); i++) |
662 |
747 |
{ |
{ |
663 |
|
firmware->pri_plugarray[i].code = driver_to_host_32(firmware->pri_plugarray[i].code); |
|
664 |
|
firmware->pri_plugarray[i].targ_off = driver_to_host_32(firmware->pri_plugarray[i].targ_off); |
|
665 |
|
firmware->pri_plugarray[i].length = driver_to_host_32(firmware->pri_plugarray[i].length); |
|
|
748 |
|
firmware->pri_plugarray[i].code = driver_to_host_32(pri[i].code); |
|
749 |
|
firmware->pri_plugarray[i].targ_off = |
|
750 |
|
driver_to_host_32(pri[i].targ_off); |
|
751 |
|
firmware->pri_plugarray[i].length = driver_to_host_32(pri[i].length); |
666 |
752 |
} |
} |
667 |
753 |
|
|
668 |
|
/* Convert identifiers */ |
|
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); |
|
|
754 |
|
/* Copy identifiers */ |
|
755 |
|
firmware->ident->size = driver_to_host_16(ident->size); |
|
756 |
|
firmware->ident->code = driver_to_host_16(ident->code); |
|
757 |
|
firmware->ident->comp_id = driver_to_host_16(ident->comp_id); |
|
758 |
|
firmware->ident->variant = driver_to_host_16(ident->variant); |
|
759 |
|
firmware->ident->version_major = driver_to_host_16(ident->version_major); |
|
760 |
|
firmware->ident->version_minor = driver_to_host_16(ident->version_minor); |
675 |
761 |
|
|
676 |
|
/* Convert compat_info */ |
|
677 |
|
for (i = 0; firmware->compat[i].size != 0; i++) |
|
|
762 |
|
/* Copy compat_info */ |
|
763 |
|
for (i = 0; (compat[i].size != 0) && (i < ARRAY_SIZE(compat_data)); i++) |
678 |
764 |
{ |
{ |
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 |
|
} |
|
|
765 |
|
size_t j; |
691 |
766 |
|
|
|
767 |
|
firmware->compat[i].size = driver_to_host_16(compat[i].size); |
|
768 |
|
firmware->compat[i].code = driver_to_host_16(compat[i].code); |
|
769 |
|
firmware->compat[i].role = driver_to_host_16(compat[i].role); |
|
770 |
|
firmware->compat[i].id = driver_to_host_16(compat[i].id); |
|
771 |
|
for (j = 0; j < ARRAY_SIZE(compat[i].range); j++) |
|
772 |
|
{ |
|
773 |
|
firmware->compat[i].range[j].variant = |
|
774 |
|
driver_to_host_16(compat[i].range[j].variant); |
|
775 |
|
firmware->compat[i].range[j].bottom = |
|
776 |
|
driver_to_host_16(compat[i].range[j].bottom); |
|
777 |
|
firmware->compat[i].range[j].top = |
|
778 |
|
driver_to_host_16(compat[i].range[j].top); |
|
779 |
|
} |
|
780 |
|
} |
692 |
781 |
} |
} |
693 |
782 |
|
|
694 |
783 |
static void print_fw_ident(const struct fwtable *firmware) |
static void print_fw_ident(const struct fwtable *firmware) |
695 |
784 |
{ |
{ |
696 |
|
int i; |
|
|
785 |
|
size_t i; |
697 |
786 |
|
|
698 |
787 |
if (firmware->ident->code == 0xFD20u) |
if (firmware->ident->code == 0xFD20u) |
699 |
788 |
{ |
{ |
700 |
|
for (i = 0; |
|
701 |
|
i < sizeof(compat_table)/sizeof(compat_table[0]); |
|
702 |
|
i++) |
|
|
789 |
|
for (i = 0; i < ARRAY_SIZE(compat_table); i++) |
703 |
790 |
{ |
{ |
704 |
791 |
if (compat_table[i].id == firmware->ident->comp_id) |
if (compat_table[i].id == firmware->ident->comp_id) |
705 |
792 |
break; |
break; |
|
... |
... |
static void print_fw_ident(const struct fwtable *firmware) |
709 |
796 |
compat_table[i].comp_string, |
compat_table[i].comp_string, |
710 |
797 |
firmware->ident->variant, |
firmware->ident->variant, |
711 |
798 |
firmware->ident->version_major, |
firmware->ident->version_major, |
712 |
|
firmware->ident->version_minor); |
|
|
799 |
|
firmware->ident->version_minor); |
713 |
800 |
} |
} |
714 |
801 |
} |
} |
715 |
802 |
|
|
716 |
|
static int write_hermesap_fw(FILE* output, |
|
717 |
|
const struct fwtable *firmware) |
|
|
803 |
|
static int write_hermesap_fw(FILE *output, const struct fwtable *firmware) |
718 |
804 |
{ |
{ |
719 |
805 |
unsigned int i; |
unsigned int i; |
|
806 |
|
|
720 |
807 |
fprintf(output, "HFW1\nENTRY %08X\n", firmware->halfentry * 2); |
fprintf(output, "HFW1\nENTRY %08X\n", firmware->halfentry * 2); |
721 |
808 |
|
|
722 |
809 |
for (i = 0; firmware->plugarray[i].code != 0; i++) |
for (i = 0; firmware->plugarray[i].code != 0; i++) |
|
... |
... |
static int write_hermesap_fw(FILE* output, |
729 |
816 |
|
|
730 |
817 |
for (i = 0; firmware->segarray[i].offset != 0; i++) |
for (i = 0; firmware->segarray[i].offset != 0; i++) |
731 |
818 |
{ |
{ |
732 |
|
unsigned int j; |
|
|
819 |
|
u16 j; |
|
820 |
|
|
733 |
821 |
if (i != 0) |
if (i != 0) |
734 |
822 |
fprintf(output, "\n"); |
fprintf(output, "\n"); |
735 |
823 |
fprintf(output, "SEG %08X %08X %08X", |
fprintf(output, "SEG %08X %08X %08X", |
|
... |
... |
static int write_hermesap_fw(FILE* output, |
737 |
825 |
firmware->segarray[i].size, |
firmware->segarray[i].size, |
738 |
826 |
0); |
0); |
739 |
827 |
|
|
740 |
|
for (j = 0; j < firmware->segarray[i].size; j += 2) { |
|
|
828 |
|
for (j = 0; j < firmware->segarray[i].size; j += 2) |
|
829 |
|
{ |
741 |
830 |
if ((j % 16) == 0) |
if ((j % 16) == 0) |
742 |
831 |
fprintf(output, "\nDATA"); |
fprintf(output, "\nDATA"); |
743 |
832 |
|
|
|
... |
... |
static size_t count_blocks(const struct fwblock *first_block) |
756 |
845 |
{ |
{ |
757 |
846 |
const struct fwblock *block = first_block; |
const struct fwblock *block = first_block; |
758 |
847 |
size_t count = 0; |
size_t count = 0; |
759 |
|
while(block->offset != 0) |
|
|
848 |
|
|
|
849 |
|
while (block->offset != 0) |
760 |
850 |
{ |
{ |
761 |
851 |
if (block->size > 0) |
if (block->size > 0) |
762 |
|
count++; |
|
|
852 |
|
count++; |
763 |
853 |
block++; |
block++; |
764 |
854 |
} |
} |
765 |
855 |
return count; |
return count; |
|
... |
... |
static size_t acc_block_size(const struct fwblock *first_block) |
769 |
859 |
{ |
{ |
770 |
860 |
const struct fwblock *block = first_block; |
const struct fwblock *block = first_block; |
771 |
861 |
size_t len = 0; |
size_t len = 0; |
772 |
|
while(block->offset != 0) |
|
|
862 |
|
|
|
863 |
|
while (block->offset != 0) |
773 |
864 |
{ |
{ |
774 |
865 |
len += block->size; |
len += block->size; |
775 |
866 |
block++; |
block++; |
|
... |
... |
static size_t acc_block_size(const struct fwblock *first_block) |
777 |
868 |
return len; |
return len; |
778 |
869 |
} |
} |
779 |
870 |
|
|
780 |
|
static size_t count_pdr(const struct _plugarray *first_pdr) |
|
|
871 |
|
static size_t count_pdr(const struct plugarray *first_pdr) |
781 |
872 |
{ |
{ |
782 |
|
const struct _plugarray *pdr = first_pdr; |
|
|
873 |
|
const struct plugarray *pdr = first_pdr; |
783 |
874 |
size_t count = 0; |
size_t count = 0; |
784 |
|
while(pdr->code) |
|
|
875 |
|
|
|
876 |
|
while (pdr->code) |
785 |
877 |
{ |
{ |
786 |
878 |
count++; |
count++; |
787 |
879 |
pdr++; |
pdr++; |
|
... |
... |
static size_t count_pdr(const struct _plugarray *first_pdr) |
789 |
881 |
return count; |
return count; |
790 |
882 |
} |
} |
791 |
883 |
|
|
792 |
|
static void dump_blocks(FILE* output, |
|
793 |
|
const struct fwblock *first_block) |
|
|
884 |
|
static void dump_blocks(FILE *output, const struct fwblock *first_block) |
794 |
885 |
{ |
{ |
795 |
886 |
const struct fwblock *block = first_block; |
const struct fwblock *block = first_block; |
796 |
887 |
u8 block_hdr[sizeof(block->offset) + sizeof(block->size)]; |
u8 block_hdr[sizeof(block->offset) + sizeof(block->size)]; |
797 |
888 |
__le32 *addr = (__le32 *) &block_hdr[0]; |
__le32 *addr = (__le32 *) &block_hdr[0]; |
798 |
889 |
__le16 *size = (__le16 *) &block_hdr[sizeof(block->offset)]; |
__le16 *size = (__le16 *) &block_hdr[sizeof(block->offset)]; |
799 |
890 |
|
|
800 |
|
while(block->offset != 0) |
|
|
891 |
|
while (block->offset != 0) |
801 |
892 |
{ |
{ |
802 |
893 |
if (block->size > 0) |
if (block->size > 0) |
803 |
894 |
{ |
{ |
804 |
895 |
*addr = host_to_le32(block->offset); |
*addr = host_to_le32(block->offset); |
805 |
896 |
*size = host_to_le16(block->size); |
*size = host_to_le16(block->size); |
806 |
897 |
|
|
807 |
|
fwrite(&block_hdr, 1, sizeof(block_hdr), output); |
|
808 |
|
fwrite(block->data, 1, block->size, output); /* data */ |
|
|
898 |
|
(void)fwrite(&block_hdr, 1, sizeof(block_hdr), output); |
|
899 |
|
(void)fwrite(block->data, 1, block->size, output); /* data */ |
809 |
900 |
} |
} |
810 |
901 |
block++; |
block++; |
811 |
902 |
} |
} |
812 |
|
*addr = host_to_le32(0xFFFFFFFFu); /* set block end */ |
|
|
903 |
|
*addr = host_to_le32(0xFFFFFFFFu); /* set block end */ |
813 |
904 |
*size = host_to_le16(0); |
*size = host_to_le16(0); |
814 |
|
fwrite(&block_hdr, 1, sizeof(block_hdr), output); |
|
|
905 |
|
(void)fwrite(&block_hdr, 1, sizeof(block_hdr), output); |
815 |
906 |
} |
} |
816 |
907 |
|
|
817 |
|
static void dump_pdr(FILE* output, |
|
818 |
|
const struct _plugarray *first_pdr) |
|
|
908 |
|
static void dump_pdr(FILE *output, const struct plugarray *first_pdr) |
819 |
909 |
{ |
{ |
820 |
|
const struct _plugarray *r = first_pdr; |
|
|
910 |
|
const struct plugarray *r = first_pdr; |
821 |
911 |
u8 pdr[sizeof(r->code) + sizeof(r->targ_off) + sizeof(r->length)]; |
u8 pdr[sizeof(r->code) + sizeof(r->targ_off) + sizeof(r->length)]; |
822 |
912 |
__le32 *code = (__le32*) &pdr[0]; |
__le32 *code = (__le32*) &pdr[0]; |
823 |
913 |
__le32 *addr = (__le32*) &pdr[sizeof(r->code)]; |
__le32 *addr = (__le32*) &pdr[sizeof(r->code)]; |
824 |
|
__le32 *len = (__le32*) &pdr[sizeof(r->code) + sizeof(r->targ_off)]; |
|
|
914 |
|
__le32 *len = (__le32*) &pdr[sizeof(r->code) + sizeof(r->targ_off)]; |
825 |
915 |
|
|
826 |
916 |
if (r) |
if (r) |
827 |
917 |
{ |
{ |
828 |
|
while(r->code != 0) |
|
|
918 |
|
while (r->code != 0) |
829 |
919 |
{ |
{ |
830 |
920 |
*code = host_to_le32(r->code); |
*code = host_to_le32(r->code); |
831 |
921 |
*addr = host_to_le32(r->targ_off); |
*addr = host_to_le32(r->targ_off); |
832 |
922 |
*len = host_to_le32(r->length); |
*len = host_to_le32(r->length); |
833 |
|
fwrite(&pdr, 1, sizeof(pdr), output); |
|
|
923 |
|
(void)fwrite(&pdr, 1, sizeof(pdr), output); |
834 |
924 |
r++; |
r++; |
835 |
925 |
} |
} |
836 |
926 |
} |
} |
837 |
|
*code = *addr = *len = host_to_le32(0); /* pdr end */ |
|
838 |
|
fwrite(&pdr, 1, sizeof(pdr), output); |
|
|
927 |
|
*code = *addr = *len = host_to_le32(0); /* pdr end */ |
|
928 |
|
(void)fwrite(&pdr, 1, sizeof(pdr), output); |
839 |
929 |
} |
} |
840 |
930 |
|
|
841 |
|
static void dump_compat(FILE* output, |
|
842 |
|
const struct _compat_info *compat) |
|
|
931 |
|
static void dump_compat(FILE *output, const struct compat_info *compat) |
843 |
932 |
{ |
{ |
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)); |
|
|
933 |
|
__le16 buf[sizeof(*compat) / sizeof(__le16)]; |
849 |
934 |
|
|
850 |
935 |
/* Dump non-zero length blocks. |
/* Dump non-zero length blocks. |
851 |
936 |
* No need to reformat. */ |
* No need to reformat. */ |
852 |
937 |
while (compat->size != 0) |
while (compat->size != 0) |
853 |
938 |
{ |
{ |
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); |
|
861 |
|
compat++; |
|
862 |
|
printf("compat is at %x. size is %d\n", (int) compat, compat->size); |
|
|
939 |
|
size_t i; |
|
940 |
|
|
|
941 |
|
for (i = 0; i < ARRAY_SIZE(buf); i++) |
|
942 |
|
{ |
|
943 |
|
buf[i] = host_to_le16(((u16 *) compat)[i]); |
|
944 |
|
} |
|
945 |
|
(void)fwrite(buf, 1, sizeof(buf), output); |
|
946 |
|
compat++; |
863 |
947 |
} |
} |
864 |
948 |
/* sentinel */ |
/* sentinel */ |
865 |
949 |
memset(&buf, 0, sizeof(buf)); |
memset(&buf, 0, sizeof(buf)); |
866 |
|
fwrite(&buf, 1, sizeof(buf), output); |
|
|
950 |
|
(void)fwrite(&buf, 1, sizeof(buf), output); |
867 |
951 |
} |
} |
868 |
952 |
|
|
869 |
953 |
#define VERSION "HFW000" |
#define VERSION "HFW000" |
870 |
954 |
/* Returns zero, or a negative number to indicate an error */ |
/* Returns zero, or a negative number to indicate an error */ |
871 |
|
static int write_kernel_fw(FILE* output, |
|
872 |
|
const struct fwtable *firmware) |
|
|
955 |
|
static int write_kernel_fw(FILE *output, const struct fwtable *firmware) |
873 |
956 |
{ |
{ |
874 |
957 |
/* Note: does not deal with BE/LE issues */ |
/* Note: does not deal with BE/LE issues */ |
875 |
958 |
u32 image_header[6]; |
u32 image_header[6]; |
876 |
959 |
u32 *ptr; |
u32 *ptr; |
877 |
|
u16 headersize = ((sizeof(VERSION)-1) + |
|
878 |
|
sizeof(u16) + |
|
879 |
|
(sizeof(u32)*6)); |
|
|
960 |
|
u16 headersize = ((sizeof(VERSION) - 1) + sizeof(u16) + (sizeof(u32) * 6)); |
880 |
961 |
u32 blocks = count_blocks(&firmware->segarray[0]); |
u32 blocks = count_blocks(&firmware->segarray[0]); |
881 |
962 |
u32 blk_offset = 0; /* Immediately after header */ |
u32 blk_offset = 0; /* Immediately after header */ |
882 |
963 |
u32 pdr_offset = (acc_block_size(&firmware->segarray[0]) + |
u32 pdr_offset = (acc_block_size(&firmware->segarray[0]) + |
|
... |
... |
static int write_kernel_fw(FILE* output, |
887 |
968 |
((count_pdr(&firmware->pri_plugarray[0]) + 1) * sizeof(u32) * 3); |
((count_pdr(&firmware->pri_plugarray[0]) + 1) * sizeof(u32) * 3); |
888 |
969 |
|
|
889 |
970 |
|
|
890 |
|
fwrite (VERSION, 1, sizeof(VERSION)-1, output); |
|
|
971 |
|
(void)fwrite(VERSION, 1, sizeof(VERSION) - 1, output); |
891 |
972 |
|
|
892 |
973 |
headersize = host_to_le16(headersize); |
headersize = host_to_le16(headersize); |
893 |
|
fwrite (&headersize, 1, sizeof(headersize), output); |
|
|
974 |
|
(void)fwrite(&headersize, 1, sizeof(headersize), output); |
894 |
975 |
|
|
895 |
976 |
ptr = &image_header[0]; |
ptr = &image_header[0]; |
896 |
|
*ptr = host_to_le32(firmware->halfentry); /* entrypoint */ |
|
|
977 |
|
*ptr = host_to_le32(firmware->halfentry); /* entrypoint */ |
897 |
978 |
ptr++; |
ptr++; |
898 |
979 |
*ptr = host_to_le32(blocks); |
*ptr = host_to_le32(blocks); |
899 |
980 |
ptr++; |
ptr++; |
|
... |
... |
static int write_kernel_fw(FILE* output, |
905 |
986 |
ptr++; |
ptr++; |
906 |
987 |
*ptr = host_to_le32(cpt_offset); |
*ptr = host_to_le32(cpt_offset); |
907 |
988 |
ptr++; |
ptr++; |
908 |
|
fwrite (&image_header, 1, sizeof(image_header), output); |
|
|
989 |
|
(void)fwrite(&image_header, 1, sizeof(image_header), output); |
909 |
990 |
|
|
910 |
991 |
dump_blocks(output, firmware->segarray); |
dump_blocks(output, firmware->segarray); |
911 |
992 |
dump_pdr(output, firmware->plugarray); |
dump_pdr(output, firmware->plugarray); |
912 |
993 |
dump_pdr(output, firmware->pri_plugarray); |
dump_pdr(output, firmware->pri_plugarray); |
913 |
994 |
dump_compat(output, firmware->compat); |
dump_compat(output, firmware->compat); |
914 |
|
return 0; /* success */ |
|
|
995 |
|
return 0; |
915 |
996 |
} |
} |
916 |
997 |
|
|
917 |
|
static int dump_fw(const char *basename, const char hexchar, |
|
918 |
|
u8* data, size_t flen, |
|
919 |
|
const u8* signature, size_t slen) |
|
|
998 |
|
static int dump_fw(const char *basename, char hexchar, |
|
999 |
|
const void *data, |
|
1000 |
|
const struct fw_layout *layout, |
|
1001 |
|
const u8 *signature, size_t slen) |
920 |
1002 |
{ |
{ |
|
1003 |
|
struct fwtable_drv *fw_image; /* structure all elements of a given firmware */ |
921 |
1004 |
struct fwtable firmware; |
struct fwtable firmware; |
922 |
|
char* fwname; |
|
923 |
|
char* filename; |
|
924 |
|
u8* hint; |
|
925 |
|
u8* fw; /* pointer to the actual blocks for programming */ |
|
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 */ |
|
928 |
|
u32 ibase; |
|
|
1005 |
|
char *fwname; |
|
1006 |
|
char *filename; |
|
1007 |
|
const void *hint; |
|
1008 |
|
void *fw; /* pointer to the actual blocks for programming */ |
|
1009 |
|
void *fwblock; /* location of structure listing blocks to program for a given firmware */ |
929 |
1010 |
u32 vaddr; |
u32 vaddr; |
930 |
|
FILE* output; |
|
931 |
|
size_t len; |
|
932 |
|
int macho = macho_validate(data); |
|
933 |
|
int mac = 0; |
|
934 |
|
|
|
935 |
|
if (macho == 0) |
|
936 |
|
{ |
|
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; |
|
946 |
|
} |
|
947 |
|
else if (macho == -1) |
|
948 |
|
{ |
|
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; |
|
952 |
|
} |
|
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) |
|
961 |
|
{ |
|
962 |
|
printf ("Driver looks like Apple PEF format\n"); |
|
963 |
|
printf ("I don't know how to extract for this format.\n" |
|
964 |
|
"I don't have a powerbook, and would need a copy of the driver to fix this\n"); |
|
965 |
|
|
|
966 |
|
/* Need to look at each of the section headers. |
|
967 |
|
* Number of section headers if given at offset 0x20 (32) (__be16?) |
|
968 |
|
* First section header starts at offset 0x28 (40) |
|
969 |
|
* Each section header is 0x1C (28) bytes long |
|
970 |
|
* Subsequent section headers follow immediately after. |
|
971 |
|
* Each section header specifies its imagebase at offset 0x4 (__be32?) |
|
972 |
|
* We need to use the imagebase of the section in which the firmware is found. |
|
973 |
|
* The offset to the section data is at offset 0x14 (20) (__be32?). |
|
974 |
|
* This offset is relative to the beginning of the file. |
|
975 |
|
* The length of each sections data is at offset 0x10 (16) (__be32?) |
|
976 |
|
*/ |
|
977 |
|
/* ibase = pef_imagebase(data); */ |
|
978 |
|
return -5; |
|
979 |
|
} |
|
980 |
|
else |
|
981 |
|
{ |
|
982 |
|
printf ("Unknown object file format\n"); |
|
983 |
|
return -5; |
|
984 |
|
} |
|
|
1011 |
|
FILE *output; |
985 |
1012 |
|
|
986 |
1013 |
printf("\nAttempting to dump %c firmware:\n", hexchar); |
printf("\nAttempting to dump %c firmware:\n", hexchar); |
987 |
|
fwname = find_fw_filename(data, flen, hexchar); |
|
|
1014 |
|
fwname = find_fw_filename(data, layout->max_offset, hexchar); |
988 |
1015 |
if (fwname) |
if (fwname) |
989 |
1016 |
{ |
{ |
990 |
1017 |
/* The filename is towards the end of the FW block, |
/* The filename is towards the end of the FW block, |
|
... |
... |
static int dump_fw(const char *basename, const char hexchar, |
994 |
1021 |
} |
} |
995 |
1022 |
else |
else |
996 |
1023 |
{ |
{ |
997 |
|
hint = data + flen; /* start from the end of file */ |
|
|
1024 |
|
hint = data + layout->max_offset; |
998 |
1025 |
} |
} |
999 |
1026 |
|
|
1000 |
1027 |
/* Now find the first firmware blob using the signature */ |
/* Now find the first firmware blob using the signature */ |
1001 |
|
fw = find_fw(data, flen, signature, slen, hint); |
|
|
1028 |
|
fw = find_fw(data, layout->max_offset, signature, slen, hint); |
1002 |
1029 |
if (!fw) |
if (!fw) |
1003 |
1030 |
return -1; |
return -1; |
1004 |
1031 |
|
|
1005 |
|
vaddr = (u32)(fw - data) + ibase; |
|
|
1032 |
|
vaddr = (fw - data) + layout->addr_delta; |
|
1033 |
|
|
|
1034 |
|
printf("Driver address of first firmware blob is 0x%08x\n", vaddr); |
1006 |
1035 |
|
|
1007 |
|
printf("Image base is 0x%08x, therefore virtual offset of firmware is 0x%08x\n", |
|
1008 |
|
ibase, vaddr); |
|
|
1036 |
|
/* Some drivers fwtables point before the actual block start. */ |
|
1037 |
|
vaddr -= layout->block_prefix; |
1009 |
1038 |
|
|
1010 |
|
fwblock = find_fwblock_entry(data, |
|
1011 |
|
flen, |
|
1012 |
|
vaddr, |
|
1013 |
|
mac); |
|
|
1039 |
|
fwblock = find_fwblock_entry(data, layout, vaddr); |
1014 |
1040 |
|
|
1015 |
|
vaddr = (fwblock - data) + ibase; |
|
|
1041 |
|
vaddr = (fwblock - data) + layout->addr_delta; |
1016 |
1042 |
|
|
1017 |
|
if (!fwblock) { |
|
|
1043 |
|
if (!fwblock) |
|
1044 |
|
{ |
1018 |
1045 |
printf("Firmware block entry not found - contact Mark!\n"); |
printf("Firmware block entry not found - contact Mark!\n"); |
1019 |
1046 |
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); |
|
|
1047 |
|
} |
|
1048 |
|
else |
|
1049 |
|
{ |
|
1050 |
|
printf("Found firmware block entry at virtual location 0x%08x, " |
|
1051 |
|
"file offset 0x%08x\n", vaddr, fwblock - data); |
1024 |
1052 |
} |
} |
1025 |
1053 |
|
|
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; |
|
|
1054 |
|
/* Got to the first fwblock. Static offset per arch */ |
|
1055 |
|
fwblock -= layout->lead_block_bytes; |
|
1056 |
|
vaddr = (fwblock - data) + layout->addr_delta; |
1031 |
1057 |
|
|
1032 |
|
fw_image = find_fwtable_entry(data, |
|
1033 |
|
flen, |
|
1034 |
|
vaddr); |
|
|
1058 |
|
fw_image = find_fwtable_entry(data, layout, vaddr); |
1035 |
1059 |
if (!fw_image) |
if (!fw_image) |
1036 |
1060 |
return -3; |
return -3; |
1037 |
1061 |
|
|
1038 |
|
copy_fw_data(&firmware, fw_image, data, mac, ibase); |
|
|
1062 |
|
copy_fw_data(&firmware, fw_image, data, layout); |
1039 |
1063 |
|
|
1040 |
1064 |
/* Print FW ident information */ |
/* Print FW ident information */ |
1041 |
1065 |
printf("Entry point at 0x%08x\n", firmware.halfentry * 2); |
printf("Entry point at 0x%08x\n", firmware.halfentry * 2); |
1042 |
1066 |
print_fw_ident(&firmware); |
print_fw_ident(&firmware); |
1043 |
1067 |
|
|
1044 |
|
filename = malloc(strlen(basename) + 5); |
|
|
1068 |
|
filename = malloc(strlen(basename) + 12); |
1045 |
1069 |
strcpy(filename, basename); |
strcpy(filename, basename); |
1046 |
|
len = strlen(filename); |
|
1047 |
|
filename[len] = hexchar; |
|
1048 |
|
filename[len+1] = 0; |
|
1049 |
|
strcat(filename, ".fw"); |
|
|
1070 |
|
strcat(filename, |
|
1071 |
|
(firmware.ident->comp_id == 32) ? "_ap_fw.bin" : "_sta_fw.bin"); |
1050 |
1072 |
|
|
1051 |
1073 |
printf("Dumping to %s...\n", filename); |
printf("Dumping to %s...\n", filename); |
1052 |
1074 |
if ((output = fopen(filename, "wb")) == NULL) |
if ((output = fopen(filename, "wb")) == NULL) |
|
... |
... |
static int dump_fw(const char *basename, const char hexchar, |
1069 |
1091 |
return 0; |
return 0; |
1070 |
1092 |
} |
} |
1071 |
1093 |
|
|
|
1094 |
|
struct fw_layout* detect_fw_layout(const void *data, size_t flen) |
|
1095 |
|
{ |
|
1096 |
|
int macho = macho_validate(data); |
|
1097 |
|
struct fw_layout *layout; |
|
1098 |
|
bool mac = false; |
|
1099 |
|
|
|
1100 |
|
if (macho == 0) |
|
1101 |
|
{ |
|
1102 |
|
const struct mach_section *fw_section; |
|
1103 |
|
|
|
1104 |
|
printf("Driver looks like Apple Mach-O format\n"); |
|
1105 |
|
|
|
1106 |
|
mac = true; |
|
1107 |
|
driver_is_be = true; |
|
1108 |
|
layout = &firmware_layout[mac]; |
|
1109 |
|
|
|
1110 |
|
fw_section = macho_fw_section(data); |
|
1111 |
|
|
|
1112 |
|
layout->addr_delta = (be32_to_host(fw_section->addr) - |
|
1113 |
|
be32_to_host(fw_section->offset)); |
|
1114 |
|
|
|
1115 |
|
/* restrict search area */ |
|
1116 |
|
layout->max_offset = (size_t) (be32_to_host(fw_section->offset) + |
|
1117 |
|
be32_to_host(fw_section->size)); |
|
1118 |
|
layout->mac = mac; |
|
1119 |
|
} |
|
1120 |
|
else if (macho == -1) |
|
1121 |
|
{ |
|
1122 |
|
printf("Driver looks like Apple Mach-O format\n" |
|
1123 |
|
"But only a 32-bit PPC Mach-O format driver is supported.\n"); |
|
1124 |
|
return NULL; |
|
1125 |
|
} |
|
1126 |
|
else if (memcmp(data, "MZ", 2) == 0) |
|
1127 |
|
{ |
|
1128 |
|
printf("Driver looks like Microsoft PE format\n"); |
|
1129 |
|
driver_is_be = false; |
|
1130 |
|
mac = false; |
|
1131 |
|
|
|
1132 |
|
layout = &firmware_layout[mac]; |
|
1133 |
|
|
|
1134 |
|
layout->addr_delta = (ptrdiff_t) pe_imagebase(data); |
|
1135 |
|
layout->max_offset = flen; |
|
1136 |
|
layout->mac = mac; |
|
1137 |
|
} |
|
1138 |
|
else if (memcmp(data, "Joy!", 4) == 0) |
|
1139 |
|
{ |
|
1140 |
|
printf("Driver looks like Apple PEF format\n"); |
|
1141 |
|
printf("I don't know how to extract for this format.\n"); |
|
1142 |
|
|
|
1143 |
|
/* Need to look at each of the section headers. |
|
1144 |
|
* Number of section headers if given at offset 0x20 (32) (__be16?) |
|
1145 |
|
* First section header starts at offset 0x28 (40) |
|
1146 |
|
* Each section header is 0x1C (28) bytes long |
|
1147 |
|
* Subsequent section headers follow immediately after. |
|
1148 |
|
* Each section header specifies its imagebase at offset 0x4 (__be32?) |
|
1149 |
|
* We need to use the imagebase of the section in which the firmware is found. |
|
1150 |
|
* The offset to the section data is at offset 0x14 (20) (__be32?). |
|
1151 |
|
* This offset is relative to the beginning of the file. |
|
1152 |
|
* The length of each sections data is at offset 0x10 (16) (__be32?) |
|
1153 |
|
*/ |
|
1154 |
|
/* layout->addr_delta = pef_imagebase(data); */ |
|
1155 |
|
return NULL; |
|
1156 |
|
} |
|
1157 |
|
else |
|
1158 |
|
{ |
|
1159 |
|
printf("Unknown object file format\n"); |
|
1160 |
|
return NULL; |
|
1161 |
|
} |
|
1162 |
|
|
|
1163 |
|
return layout; |
|
1164 |
|
} |
|
1165 |
|
|
1072 |
1166 |
/* |
/* |
1073 |
1167 |
* Main |
* Main |
1074 |
1168 |
*/ |
*/ |
1075 |
1169 |
int main(int argc, char *argv[]) |
int main(int argc, char *argv[]) |
1076 |
1170 |
{ |
{ |
1077 |
1171 |
FILE *input; |
FILE *input; |
1078 |
|
unsigned char *data; |
|
1079 |
|
unsigned int flen; |
|
|
1172 |
|
void *data; |
|
1173 |
|
size_t read_bytes; |
|
1174 |
|
size_t flen; |
1080 |
1175 |
|
|
1081 |
1176 |
printf("Lucent Firmware Extractor v1.1\n" |
printf("Lucent Firmware Extractor v1.1\n" |
1082 |
1177 |
"(c) 2003 Mark Smith (username 'Mark' on HermesAP board)\n" |
"(c) 2003 Mark Smith (username 'Mark' on HermesAP board)\n" |
|
... |
... |
int main(int argc, char *argv[]) |
1085 |
1180 |
check_endianess(); |
check_endianess(); |
1086 |
1181 |
|
|
1087 |
1182 |
/* Attempt to load file */ |
/* Attempt to load file */ |
1088 |
|
if (argc != 3) { |
|
|
1183 |
|
if (argc != 3) |
|
1184 |
|
{ |
1089 |
1185 |
printf("Usage: %s <driver> <output_base>\n", argv[0]); |
printf("Usage: %s <driver> <output_base>\n", argv[0]); |
1090 |
1186 |
return -1; |
return -1; |
1091 |
1187 |
} |
} |
|
... |
... |
int main(int argc, char *argv[]) |
1098 |
1194 |
* Others? |
* Others? |
1099 |
1195 |
*/ |
*/ |
1100 |
1196 |
|
|
1101 |
|
if ((input = fopen(argv[1], "rb")) == NULL) { |
|
|
1197 |
|
if ((input = fopen(argv[1], "rb")) == NULL) |
|
1198 |
|
{ |
1102 |
1199 |
printf("Unable to open %s, aborting.\n", argv[1]); |
printf("Unable to open %s, aborting.\n", argv[1]); |
1103 |
1200 |
return -1; |
return -1; |
1104 |
1201 |
} |
} |
|
... |
... |
int main(int argc, char *argv[]) |
1113 |
1210 |
|
|
1114 |
1211 |
/* Allocate memory and load the file */ |
/* Allocate memory and load the file */ |
1115 |
1212 |
data = malloc(flen); |
data = malloc(flen); |
1116 |
|
fread(data, 1, flen, input); |
|
1117 |
|
printf("Memory allocated and file read OK\n"); |
|
|
1213 |
|
read_bytes = fread(data, 1, flen, input); |
1118 |
1214 |
fclose(input); |
fclose(input); |
1119 |
1215 |
|
|
|
1216 |
|
if (read_bytes == flen) |
1120 |
1217 |
{ |
{ |
1121 |
1218 |
u8 t_sig[4] = { 0x61, 0x44, 0xfe, 0xfb }; |
u8 t_sig[4] = { 0x61, 0x44, 0xfe, 0xfb }; |
1122 |
1219 |
u8 r_sig[4] = { 0x0f, 0x60, 0xfc, 0x63 }; |
u8 r_sig[4] = { 0x0f, 0x60, 0xfc, 0x63 }; |
|
1220 |
|
struct fw_layout *layout; |
|
1221 |
|
|
|
1222 |
|
printf("Memory allocated and file read OK\n"); |
1123 |
1223 |
|
|
1124 |
|
dump_fw(argv[2], 'T', data, flen, t_sig, sizeof(t_sig)); |
|
1125 |
|
dump_fw(argv[2], 'R', data, flen, r_sig, sizeof(r_sig)); |
|
|
1224 |
|
layout = detect_fw_layout(data, flen); |
|
1225 |
|
if (layout) |
|
1226 |
|
{ |
|
1227 |
|
dump_fw(argv[2], 'T', data, layout, t_sig, sizeof(t_sig)); |
|
1228 |
|
dump_fw(argv[2], 'R', data, layout, r_sig, sizeof(r_sig)); |
|
1229 |
|
} |
|
1230 |
|
} |
|
1231 |
|
else |
|
1232 |
|
{ |
|
1233 |
|
printf("Only read %d out of %d bytes\n", read_bytes, flen); |
1126 |
1234 |
} |
} |
1127 |
1235 |
|
|
1128 |
1236 |
free(data); |
free(data); |