Use C99 types
[agere_fw_utils.git] / dump_fw.c
blob561dd2af15d3e82853289603518497d989e48374
1 /*
2 * Program to link against Agere FW images, and dump contents to
3 * binary files for loading directly by linux drivers.
5 *
6 */
8 /* Output format (LE numbers)
10 * vers [6] The text HFW and 3 ASCII digits indicating version
11 * headersize [2] Size of header inc vers, headersize and length
12 * entry point [4] NIC address of entry point
13 * blocks [4] Number of blocks (n)
14 * blk_offset [4] Offset to block data
15 * pdr_offset [4] Offset to PDR data
16 * pri_offset [4] Offset to primary plug data
17 * cpt_offset [4] Offset to compatibility data
18 * signature [arb] firmware signature
19 * Block_1
20 * ..
21 * Block_n
22 * Block_term
23 * pda_1
24 * ..
25 * pda_n
26 * pda_term
28 * Where Block_n is:
29 * addr [4] NIC address to program data
30 * length [2] Number of bytes of data to program
31 * data [arbitrary] Data to program
33 * block term is:
34 * 0xFFFFFFFF [4] BLOCK_END identifier
35 * 0x0000 [2] zero length
37 * pda_n is:
38 * id [4] PDA identifier
39 * addr [4] Address to program PDA
40 * len [4] Number of bytes to program
42 * pda_term
43 * 0x00000000 [4] PDI_END
44 * 0x00000000 [4]
45 * 0x00000000 [4]
47 * There is more information available in the driver. In particular
48 * whether the block is supposed to be programmed to NV or volatile,
49 * and various flags.
51 * Apart from the header, the output format is compatible with the
52 * spectrum_cs image. The header is arbitrary.
56 #include <stdio.h>
57 #include <stdint.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #include "dhf.h"
62 #define AP_SUFFIX "_ap_fw.bin"
63 #define STA_SUFFIX "_sta_fw.bin"
64 #define VERSION "HFW000"
66 /* 0xAABB to 0xBBAA */
67 #define swap_bytes_16(value) \
68 ((((value) >> 8) & 0xFF) | \
69 (((value) & 0xFF) << 8))
70 /* 0xAABBCCDD to 0xDDCCBBAA */
71 #define reverse_bytes_32(value) \
72 ((((value) >> 24) & 0x0000FF) | \
73 (((value) >> 8) & 0x00FF00) | \
74 (((value) << 8) & 0xFF0000) | \
75 (((value) & 0xFF) << 24))
76 /* 0xAABBCCDD to 0xBBAADDCC */
77 #define swap_bytes_32(value) \
78 ((((value) >> 8) & 0x00FF00FF) | \
79 (((value) << 8) & 0xFF00FF00))
80 /* 0xAABBCCDD to 0xCCDDAABB */
81 #define swap_words_32(value) \
82 ((((value) >> 16) & 0x0000FFFF) | \
83 (((value) << 16) & 0xFFFF0000))
85 /* address 0 1 2 3 */
86 /* Pure LE stores 0x12345678 as 0x78 0x56 0x34 0x12 */
87 /* Pure BE stores 0x12345678 as 0x12 0x34 0x56 0x78 */
88 /* BEW+LEB stores 0x12345678 as 0x34 0x12 0x78 0x56 */
89 /* LEW+BEB stores 0x12345678 as 0x56 0x78 0x12 0x34 */
90 int host_bytes_in_word_be = 0;
91 int host_words_in_dword_be = 0;
93 #define host_to_le16(value) \
94 (host_bytes_in_word_be ? swap_bytes_16(value) : (value))
95 #define host_to_le32(value) \
96 (host_words_in_dword_be ? \
97 (host_bytes_in_word_be ? reverse_bytes_32(value) \
98 : swap_bytes_32(value)) : \
99 (host_bytes_in_word_be ? swap_words_32(value) : (value)))
101 #define le16_to_host(value) \
102 (host_bytes_in_word_be ? swap_bytes_16(value) : (value))
103 #define le32_to_host(value) \
104 (host_words_in_dword_be ? \
105 (host_bytes_in_word_be ? reverse_bytes_32(value) \
106 : swap_bytes_32(value)) : \
107 (host_bytes_in_word_be ? swap_words_32(value) : (value)))
109 /* Use C99 exact width types */
110 typedef uint32_t u32;
111 typedef uint16_t u16;
112 typedef uint8_t u8;
114 /* Checking endianess at runtime because performance isn't an issue,
115 * and I'd rather not add a configure step since this is slotting into the
116 * Agere source code. */
117 void check_endianess(void) {
118 union {
119 u32 dword;
120 u16 word[2];
121 u8 byte[4];
122 } data;
124 data.dword = 0x12345678;
125 if (data.word[0] == 0x1234) {
126 host_words_in_dword_be = 1;
128 else if (data.word[0] == 0x5678) {
129 host_words_in_dword_be = 0;
130 } else {
131 fprintf(stderr, "Can't determine endianess of host!\n");
132 exit(1);
135 data.word[0] = 0x1234;
136 if (data.byte[0] == 0x12) {
137 host_bytes_in_word_be = 1;
138 } else if (data.byte[0] == 0x34) {
139 host_bytes_in_word_be = 0;
140 } else {
141 fprintf(stderr, "Can't determine endianess of host!\n");
144 if (host_bytes_in_word_be == host_words_in_dword_be) {
145 fprintf (stdout, "Detected %s host\n",
146 host_bytes_in_word_be ? "big endian" : "little endian");
147 } else {
148 fprintf (stdout, "Detected host with mixed endianess\n");
150 return;
153 size_t count_blocks(memimage *image)
155 #if __wl_lkm < 718
156 # define MEMBLOCK memblock
157 # define BLKSIZE p->size
158 # define IF_HAVE_SEGMENT
159 #else
160 # define MEMBLOCK CFG_PROG_STRCT
161 # define BLKSIZE p->len
162 # define IF_HAVE_SEGMENT if (p->segment_size)
163 #endif
165 MEMBLOCK *p = image->codep;
166 size_t count = 0;
167 while (BLKSIZE)
169 /* Ignore zero data segments which will not be written */
170 IF_HAVE_SEGMENT
172 count++;
174 p++;
176 return count;
180 size_t count_pdr(plugrecord *r)
182 size_t count = 0;
183 if (r)
185 while (r->code)
187 count++;
188 r++;
191 return count;
194 size_t acc_block_size(memimage *image)
196 #if __wl_lkm < 718
197 # define MEMBLOCK memblock
198 # define BLKSIZE p->size
199 # define SEGSIZE p->size
200 # define IF_HAVE_SEGMENT
201 #else
202 # define MEMBLOCK CFG_PROG_STRCT
203 # define BLKSIZE p->len
204 # define SEGSIZE p->segment_size
205 # define IF_HAVE_SEGMENT if (p->segment_size)
206 #endif
208 MEMBLOCK *p = image->codep;
209 size_t len = 0;
210 while (BLKSIZE)
212 /* Ignore zero data segments which will not be written */
213 IF_HAVE_SEGMENT
215 len += SEGSIZE;
217 p++;
219 return len;
222 void dump_blocks(FILE* f, memimage *image)
224 #if __wl_lkm < 718
225 # define MEMBLOCK memblock
226 # define BLKSIZE p->size
227 # define SEGSIZE p->size
228 # define NICADDR p->addr
229 # define SEGDATA &(p->data[4]) /* Avoid initial CRC */
230 # define IF_HAVE_SEGMENT
231 #else
232 # define MEMBLOCK CFG_PROG_STRCT
233 # define BLKSIZE p->len
234 # define SEGSIZE p->segment_size
235 # define NICADDR p->nic_addr
236 # define SEGDATA p->host_addr
237 # define IF_HAVE_SEGMENT if (p->segment_size)
238 #endif
240 MEMBLOCK *p = image->codep;
241 u8 block_hdr[sizeof(NICADDR) + sizeof(SEGSIZE)];
242 u32 *addr = (u32 *) &block_hdr[0];
243 u16 *size = (u16 *) &block_hdr[sizeof(NICADDR)];
245 while (BLKSIZE)
247 IF_HAVE_SEGMENT
249 /* There is data to program in this block */
250 *addr = host_to_le32(NICADDR);
251 *size = host_to_le16(SEGSIZE);
252 fwrite (&block_hdr, 1, sizeof(block_hdr), f);
253 fwrite (SEGDATA, 1, SEGSIZE, f);
255 p++;
257 *addr = host_to_le32(0xFFFFFFFFu); /* Agree with spectrum BLOCK_END */
258 *size = host_to_le16(0u);
260 fwrite (&block_hdr, 1, sizeof(block_hdr), f);
262 return;
265 void dump_pdr(FILE *f, plugrecord *r)
267 u8 pdr[sizeof(r->code) + sizeof(r->addr) + sizeof(r->len)];
268 u32 *code = (u32*) &pdr[0];
269 u32 *addr = (u32*) &pdr[sizeof(r->code)];
270 u32 *len = (u32*) &pdr[sizeof(r->code) + sizeof(r->addr)];
272 if (!r)
273 goto terminate;
275 while (r->code)
277 *code = host_to_le32(r->code);
278 *addr = host_to_le32(r->addr);
279 *len = host_to_le32(r->len);
280 fwrite(&pdr, 1, sizeof(pdr), f);
281 r++;
283 terminate:
284 /* Terminate the PDR list */
285 *code = 0;
286 *addr = 0;
287 *len = 0;
288 fwrite(&pdr, 1, sizeof(pdr), f);
289 return;
292 void dump_image(FILE* f, memimage *image)
294 u32 image_header[6];
295 u32 blocks = count_blocks(image);
296 u32 blk_offset = 0; /* Immediately after header */
297 u32 pdr_offset = (acc_block_size(image) +
298 ((blocks + 1) * (sizeof(u32) + sizeof(u16))));
299 u32 pri_offset = pdr_offset +
300 ((count_pdr(image->pdaplug) + 1) * sizeof(u32) * 3);
301 u32 cpt_offset = pri_offset +
302 ((count_pdr(image->priplug) + 1) * sizeof(u32) * 3);
303 u16 headersize = ((sizeof(VERSION)-1) +
304 sizeof(u16) +
305 (sizeof(u32)*6)
306 #if __wl_lkm >= 718
307 + sizeof(image->signature)
308 #endif
310 u32 *ptr = &image_header[0];
311 fwrite (VERSION, 1, sizeof(VERSION)-1, f);
312 headersize = host_to_le16(headersize);
313 fwrite (&headersize, 1, sizeof(headersize), f);
315 *ptr = host_to_le32(image->execution);
316 ptr++;
317 *ptr = host_to_le32(blocks);
318 ptr++;
319 *ptr = host_to_le32(blk_offset);
320 ptr++;
321 *ptr = host_to_le32(pdr_offset);
322 ptr++;
323 *ptr = host_to_le32(pri_offset);
324 ptr++;
325 *ptr = host_to_le32(cpt_offset);
326 ptr++;
327 fwrite (&image_header, 1, sizeof(image_header), f);
328 #if __wl_lkm >= 718
329 fwrite (&image->signature, 1, sizeof(image->signature), f);
330 #endif
332 dump_blocks(f, image);
333 dump_pdr(f, image->pdaplug);
334 dump_pdr(f, image->priplug);
335 /* compat info not written */
337 return;
340 extern memimage ap;
341 extern memimage station;
343 int main (int argc, char** argv)
345 char *ap_filename;
346 char *sta_filename;
347 FILE *ap_file;
348 FILE *sta_file;
349 size_t len;
350 int rc = 0;
352 if (argc < 2)
354 printf("Please specify a root filename.\n"
355 "%s will be appended for primary firmware\n"
356 "%s will be appended for secondary firmaware\n",
357 AP_SUFFIX, STA_SUFFIX);
358 return 1;
361 check_endianess();
363 len = strlen(argv[1]);
364 ap_filename = malloc(len + sizeof(AP_SUFFIX) + 1);
365 if (!ap_filename)
367 fprintf(stderr, "Out of memory\n");
368 return 1;
370 strncpy(ap_filename, argv[1], len);
371 ap_filename[len] = 0;
372 strcat(ap_filename, AP_SUFFIX);
374 ap_file = fopen(ap_filename, "w");
375 if (!ap_file)
377 fprintf(stderr, "Can't open %s for writing\n", ap_filename);
378 rc = 1;
380 else
382 dump_image(ap_file, &ap);
383 fclose(ap_file);
384 fprintf (stdout, "Written %s\n", ap_filename);
386 free(ap_filename);
388 sta_filename = malloc(len + sizeof(STA_SUFFIX) + 1);
389 if (!sta_filename)
391 fprintf(stderr, "Out of memory\n");
392 return 1;
394 strncpy(sta_filename, argv[1], len);
395 sta_filename[len] = 0;
396 strcat(sta_filename,STA_SUFFIX);
398 sta_file = fopen(sta_filename,"w");
399 if (!sta_file)
401 fprintf(stderr, "Can't open %s for writing\n", sta_filename);
402 rc = 1;
404 else
406 dump_image(sta_file, &station);
407 fclose(sta_file);
408 fprintf (stdout, "Written %s\n", sta_filename);
410 free(sta_filename);
412 return rc;