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
29 * addr [4] NIC address to program data
30 * length [2] Number of bytes of data to program
31 * data [arbitrary] Data to program
34 * 0xFFFFFFFF [4] BLOCK_END identifier
35 * 0x0000 [2] zero length
38 * id [4] PDA identifier
39 * addr [4] Address to program PDA
40 * len [4] Number of bytes to program
43 * 0x00000000 [4] PDI_END
47 * There is more information available in the driver. In particular
48 * whether the block is supposed to be programmed to NV or volatile,
51 * Apart from the header, the output format is compatible with the
52 * spectrum_cs image. The header is arbitrary.
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))
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
;
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) {
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;
131 fprintf(stderr
, "Can't determine endianess of host!\n");
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;
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");
148 fprintf (stdout
, "Detected host with mixed endianess\n");
153 size_t count_blocks(memimage
*image
)
156 # define MEMBLOCK memblock
157 # define BLKSIZE p->size
158 # define IF_HAVE_SEGMENT
160 # define MEMBLOCK CFG_PROG_STRCT
161 # define BLKSIZE p->len
162 # define IF_HAVE_SEGMENT if (p->segment_size)
165 MEMBLOCK
*p
= image
->codep
;
169 /* Ignore zero data segments which will not be written */
180 size_t count_pdr(plugrecord
*r
)
194 size_t acc_block_size(memimage
*image
)
197 # define MEMBLOCK memblock
198 # define BLKSIZE p->size
199 # define SEGSIZE p->size
200 # define IF_HAVE_SEGMENT
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)
208 MEMBLOCK
*p
= image
->codep
;
212 /* Ignore zero data segments which will not be written */
222 void dump_blocks(FILE* f
, memimage
*image
)
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
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)
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
)];
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
);
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
);
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
)];
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
);
284 /* Terminate the PDR list */
288 fwrite(&pdr
, 1, sizeof(pdr
), f
);
292 void dump_image(FILE* f
, memimage
*image
)
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) +
307 + sizeof(image
->signature
)
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
);
317 *ptr
= host_to_le32(blocks
);
319 *ptr
= host_to_le32(blk_offset
);
321 *ptr
= host_to_le32(pdr_offset
);
323 *ptr
= host_to_le32(pri_offset
);
325 *ptr
= host_to_le32(cpt_offset
);
327 fwrite (&image_header
, 1, sizeof(image_header
), f
);
329 fwrite (&image
->signature
, 1, sizeof(image
->signature
), f
);
332 dump_blocks(f
, image
);
333 dump_pdr(f
, image
->pdaplug
);
334 dump_pdr(f
, image
->priplug
);
335 /* compat info not written */
341 extern memimage station
;
343 int main (int argc
, char** argv
)
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
);
363 len
= strlen(argv
[1]);
364 ap_filename
= malloc(len
+ sizeof(AP_SUFFIX
) + 1);
367 fprintf(stderr
, "Out of memory\n");
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");
377 fprintf(stderr
, "Can't open %s for writing\n", ap_filename
);
382 dump_image(ap_file
, &ap
);
384 fprintf (stdout
, "Written %s\n", ap_filename
);
388 sta_filename
= malloc(len
+ sizeof(STA_SUFFIX
) + 1);
391 fprintf(stderr
, "Out of memory\n");
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");
401 fprintf(stderr
, "Can't open %s for writing\n", sta_filename
);
406 dump_image(sta_file
, &station
);
408 fprintf (stdout
, "Written %s\n", sta_filename
);