2 * Program to link against Agere FW images, and dump contents to
3 * binary files for loading directly by linux drivers.
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
37 * addr [4] NIC address to program data
38 * length [2] Number of bytes of data to program
39 * data [arbitrary] Data to program
42 * 0xFFFFFFFF [4] BLOCK_END identifier
43 * 0x0000 [2] zero length
45 * pda_n and pri_n are:
46 * id [4] (Primary) PDA identifier
47 * addr [4] Address to program (Primary) PDA
48 * len [4] Number of bytes to program
50 * pda_term and pri_n are:
51 * 0x00000000 [4] PDI_END
56 * size [2] Length of LTV - ((n_bytes/2) - 1)
57 * code [2] LTV code - 0xFD21 (FW compatibility range)
58 * 0xFD22 (Modem I/F compatibility range)
59 * 0xFD23 (Controller I/F compatibility range)
60 * role [2] Who this restriction applies to?
64 * spec_1 Specifications
73 * There is more information available in the driver. In particular
74 * whether the block is supposed to be programmed to NV or volatile,
77 * Apart from the header, the output format is compatible with the
78 * spectrum_cs image. The header is arbitrary.
88 #define AP_SUFFIX "_ap_fw.bin"
89 #define STA_SUFFIX "_sta_fw.bin"
90 #define VERSION "HFW000"
92 /* 0xAABB to 0xBBAA */
93 #define swap_bytes_16(value) \
94 ((((value) >> 8) & 0xFF) | \
95 (((value) & 0xFF) << 8))
96 /* 0xAABBCCDD to 0xDDCCBBAA */
97 #define reverse_bytes_32(value) \
98 ((((value) >> 24) & 0x0000FF) | \
99 (((value) >> 8) & 0x00FF00) | \
100 (((value) << 8) & 0xFF0000) | \
101 (((value) & 0xFF) << 24))
102 /* 0xAABBCCDD to 0xBBAADDCC */
103 #define swap_bytes_32(value) \
104 ((((value) >> 8) & 0x00FF00FF) | \
105 (((value) << 8) & 0xFF00FF00))
106 /* 0xAABBCCDD to 0xCCDDAABB */
107 #define swap_words_32(value) \
108 ((((value) >> 16) & 0x0000FFFF) | \
109 (((value) << 16) & 0xFFFF0000))
111 /* address 0 1 2 3 */
112 /* Pure LE stores 0x12345678 as 0x78 0x56 0x34 0x12 */
113 /* Pure BE stores 0x12345678 as 0x12 0x34 0x56 0x78 */
114 /* BEW+LEB stores 0x12345678 as 0x34 0x12 0x78 0x56 */
115 /* LEW+BEB stores 0x12345678 as 0x56 0x78 0x12 0x34 */
116 int host_bytes_in_word_be
= 0;
117 int host_words_in_dword_be
= 0;
119 #define host_to_le16(value) \
120 (host_bytes_in_word_be ? swap_bytes_16(value) : (value))
121 #define host_to_le32(value) \
122 (host_words_in_dword_be ? \
123 (host_bytes_in_word_be ? reverse_bytes_32(value) \
124 : swap_bytes_32(value)) : \
125 (host_bytes_in_word_be ? swap_words_32(value) : (value)))
127 #define le16_to_host(value) \
128 (host_bytes_in_word_be ? swap_bytes_16(value) : (value))
129 #define le32_to_host(value) \
130 (host_words_in_dword_be ? \
131 (host_bytes_in_word_be ? reverse_bytes_32(value) \
132 : swap_bytes_32(value)) : \
133 (host_bytes_in_word_be ? swap_words_32(value) : (value)))
135 /* Use C99 exact width types */
136 typedef uint32_t u32
;
137 typedef uint16_t u16
;
140 /* Checking endianess at runtime because performance isn't an issue,
141 * and I'd rather not add a configure step since this is slotting into the
142 * Agere source code. */
143 void check_endianess(void) {
150 data
.dword
= 0x12345678;
151 if (data
.word
[0] == 0x1234) {
152 host_words_in_dword_be
= 1;
154 else if (data
.word
[0] == 0x5678) {
155 host_words_in_dword_be
= 0;
157 fprintf(stderr
, "Can't determine endianess of host!\n");
161 data
.word
[0] = 0x1234;
162 if (data
.byte
[0] == 0x12) {
163 host_bytes_in_word_be
= 1;
164 } else if (data
.byte
[0] == 0x34) {
165 host_bytes_in_word_be
= 0;
167 fprintf(stderr
, "Can't determine endianess of host!\n");
170 if (host_bytes_in_word_be
== host_words_in_dword_be
) {
171 fprintf (stdout
, "Detected %s host\n",
172 host_bytes_in_word_be
? "big endian" : "little endian");
174 fprintf (stdout
, "Detected host with mixed endianess\n");
179 size_t count_blocks(memimage
*image
)
182 # define MEMBLOCK memblock
183 # define BLKSIZE p->size
184 # define IF_HAVE_SEGMENT
186 # define MEMBLOCK CFG_PROG_STRCT
187 # define BLKSIZE p->len
188 # define IF_HAVE_SEGMENT if (p->segment_size)
191 MEMBLOCK
*p
= image
->codep
;
195 /* Ignore zero data segments which will not be written */
206 size_t count_pdr(plugrecord
*r
)
220 size_t acc_block_size(memimage
*image
)
223 # define MEMBLOCK memblock
224 # define BLKSIZE p->size
225 # define SEGSIZE p->size
226 # define IF_HAVE_SEGMENT
228 # define MEMBLOCK CFG_PROG_STRCT
229 # define BLKSIZE p->len
230 # define SEGSIZE p->segment_size
231 # define IF_HAVE_SEGMENT if (p->segment_size)
234 MEMBLOCK
*p
= image
->codep
;
238 /* Ignore zero data segments which will not be written */
248 void dump_blocks(FILE* f
, memimage
*image
)
251 # define MEMBLOCK memblock
252 # define BLKSIZE p->size
253 # define SEGSIZE p->size
254 # define NICADDR p->addr
255 # define SEGDATA &(p->data[4]) /* Avoid initial CRC */
256 # define IF_HAVE_SEGMENT
258 # define MEMBLOCK CFG_PROG_STRCT
259 # define BLKSIZE p->len
260 # define SEGSIZE p->segment_size
261 # define NICADDR p->nic_addr
262 # define SEGDATA p->host_addr
263 # define IF_HAVE_SEGMENT if (p->segment_size)
266 MEMBLOCK
*p
= image
->codep
;
267 u8 block_hdr
[sizeof(NICADDR
) + sizeof(SEGSIZE
)];
268 u32
*addr
= (u32
*) &block_hdr
[0];
269 u16
*size
= (u16
*) &block_hdr
[sizeof(NICADDR
)];
275 /* There is data to program in this block */
276 *addr
= host_to_le32(NICADDR
);
277 *size
= host_to_le16(SEGSIZE
);
278 fwrite (&block_hdr
, 1, sizeof(block_hdr
), f
);
279 fwrite (SEGDATA
, 1, SEGSIZE
, f
);
283 *addr
= host_to_le32(0xFFFFFFFFu
); /* Agree with spectrum BLOCK_END */
284 *size
= host_to_le16(0u);
286 fwrite (&block_hdr
, 1, sizeof(block_hdr
), f
);
291 void dump_pdr(FILE *f
, plugrecord
*r
)
293 u8 pdr
[sizeof(r
->code
) + sizeof(r
->addr
) + sizeof(r
->len
)];
294 u32
*code
= (u32
*) &pdr
[0];
295 u32
*addr
= (u32
*) &pdr
[sizeof(r
->code
)];
296 u32
*len
= (u32
*) &pdr
[sizeof(r
->code
) + sizeof(r
->addr
)];
303 *code
= host_to_le32(r
->code
);
304 *addr
= host_to_le32(r
->addr
);
305 *len
= host_to_le32(r
->len
);
306 fwrite(&pdr
, 1, sizeof(pdr
), f
);
310 /* Terminate the PDR list */
314 fwrite(&pdr
, 1, sizeof(pdr
), f
);
318 void dump_compat(FILE *f
, CFG_RANGE20_STRCT
*c
)
321 #define VARIANT_STRUCT variant
322 #define VARIANT_NO number
324 #define VARIANT_STRUCT var_rec
325 #define VARIANT_NO variant
327 u8 hdr
[sizeof(c
->id
) + sizeof(c
->typ
) + sizeof(c
->role
) + sizeof(c
->id
)];
328 u8 spec
[sizeof(c
->VARIANT_STRUCT
[0])];
329 u16
*len
= (u16
*) &hdr
[0];
330 u16
*typ
= (u16
*) &hdr
[sizeof(c
->len
)];
331 u16
*role
= (u16
*) &hdr
[sizeof(c
->len
) + sizeof(c
->typ
)];
332 u16
*id
= (u16
*) &hdr
[sizeof(c
->len
) + sizeof(c
->typ
) + sizeof(c
->role
)];
333 u16
*variant
= (u16
*) &spec
[0];
334 u16
*bottom
= (u16
*) &spec
[sizeof(c
->VARIANT_STRUCT
[0].VARIANT_NO
)];
335 u16
*top
= (u16
*) &spec
[sizeof(c
->VARIANT_STRUCT
[0].VARIANT_NO
) + sizeof(c
->VARIANT_STRUCT
[0].bottom
)];
340 *len
= host_to_le16(c
->len
);
341 *typ
= host_to_le16(c
->typ
);
342 *role
= host_to_le16(c
->role
);
343 *id
= host_to_le16(c
->id
);
344 fwrite(&hdr
, 1, sizeof(hdr
), f
);
346 for (i
= 0; i
< sizeof(c
->VARIANT_STRUCT
)/sizeof(c
->VARIANT_STRUCT
[0]); i
++)
348 *variant
= host_to_le16(c
->VARIANT_STRUCT
[i
].VARIANT_NO
);
349 *bottom
= host_to_le16(c
->VARIANT_STRUCT
[i
].bottom
);
350 *top
= host_to_le16(c
->VARIANT_STRUCT
[i
].top
);
351 fwrite(&spec
, 1, sizeof(spec
), f
);
358 memset(&hdr
[0], 0, sizeof(hdr
));
359 memset(&spec
[0], 0, sizeof(spec
));
360 fwrite(&hdr
, 1, sizeof(hdr
), f
);
361 for (i
= 0; i
< sizeof(c
->VARIANT_STRUCT
)/sizeof(c
->VARIANT_STRUCT
[0]); i
++)
363 fwrite(&spec
, 1, sizeof(spec
), f
);
369 void dump_image(FILE* f
, memimage
*image
)
375 #define PDA place_holder_1
376 #define PRI place_holder_2
379 u32 blocks
= count_blocks(image
);
380 u32 blk_offset
= 0; /* Immediately after header */
381 u32 pdr_offset
= (acc_block_size(image
) +
382 ((blocks
+ 1) * (sizeof(u32
) + sizeof(u16
))));
383 u32 pri_offset
= pdr_offset
+
384 ((count_pdr(image
->PDA
) + 1) * sizeof(u32
) * 3);
385 u32 cpt_offset
= pri_offset
+
386 ((count_pdr(image
->PRI
) + 1) * sizeof(u32
) * 3);
387 u16 headersize
= ((sizeof(VERSION
)-1) +
391 + sizeof(image
->signature
)
394 u32
*ptr
= &image_header
[0];
395 fwrite (VERSION
, 1, sizeof(VERSION
)-1, f
);
396 headersize
= host_to_le16(headersize
);
397 fwrite (&headersize
, 1, sizeof(headersize
), f
);
399 *ptr
= host_to_le32(image
->execution
);
401 *ptr
= host_to_le32(blocks
);
403 *ptr
= host_to_le32(blk_offset
);
405 *ptr
= host_to_le32(pdr_offset
);
407 *ptr
= host_to_le32(pri_offset
);
409 *ptr
= host_to_le32(cpt_offset
);
411 fwrite (&image_header
, 1, sizeof(image_header
), f
);
413 fwrite (&image
->signature
, 1, sizeof(image
->signature
), f
);
416 dump_blocks(f
, image
);
417 dump_pdr(f
, image
->PDA
);
418 dump_pdr(f
, image
->PRI
);
419 dump_compat(f
, image
->compat
);
426 extern memimage station
;
428 extern memimage fw_image
;
430 #define station fw_image
433 int main (int argc
, char** argv
)
444 printf("Please specify a root filename.\n"
445 "%s will be appended for primary firmware\n"
446 "%s will be appended for secondary firmaware\n",
447 AP_SUFFIX
, STA_SUFFIX
);
453 len
= strlen(argv
[1]);
455 if (ap
.identity
->comp_id
!= COMP_ID_FW_AP
)
458 ap_filename
= malloc(len
+ sizeof(AP_SUFFIX
) + 1);
461 fprintf(stderr
, "Out of memory\n");
464 strncpy(ap_filename
, argv
[1], len
);
465 ap_filename
[len
] = 0;
466 strcat(ap_filename
, AP_SUFFIX
);
468 ap_file
= fopen(ap_filename
, "w");
471 fprintf(stderr
, "Can't open %s for writing\n", ap_filename
);
476 dump_image(ap_file
, &ap
);
478 fprintf (stdout
, "Written %s\n", ap_filename
);
483 if (station
.identity
->comp_id
!= COMP_ID_FW_STA
)
486 sta_filename
= malloc(len
+ sizeof(STA_SUFFIX
) + 1);
489 fprintf(stderr
, "Out of memory\n");
492 strncpy(sta_filename
, argv
[1], len
);
493 sta_filename
[len
] = 0;
494 strcat(sta_filename
,STA_SUFFIX
);
496 sta_file
= fopen(sta_filename
,"w");
499 fprintf(stderr
, "Can't open %s for writing\n", sta_filename
);
504 dump_image(sta_file
, &station
);
506 fprintf (stdout
, "Written %s\n", sta_filename
);