2 * Copyright (C) 2006 Michael Buesch <mb@bu3sch.de>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2
6 * as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
22 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
24 /* The header that fwcutter puts in to every .fw file */
26 /* Type of the firmware data */
28 /* Version number of the firmware data format */
31 /* Size of the data. For ucode and PCM this is in bytes.
32 * For IV this is in number-of-ivs. */
34 } __attribute__ ((__packed__));
37 struct bin_instruction {
39 unsigned int operands[3];
50 struct bin_instruction *bin;
52 const char *operands[5];
55 unsigned int labeladdr;
56 struct statement *labelref;
63 struct list_head list;
66 struct disassembler_context {
67 struct bin_instruction *code;
70 struct list_head stmt_list;
75 const char *outfile_name;
78 static const char * gen_raw_code(unsigned int operand)
83 snprintf(ret, 5, "@%03X", operand);
88 static const char * disasm_mem_operand(unsigned int operand)
93 snprintf(ret, 8, "[0x%03X]", operand);
98 static const char * disasm_indirect_mem_operand(unsigned int operand)
103 snprintf(ret, 12, "[0x%02X,off%u]",
104 (operand & 0x3F), ((operand >> 6) & 0x7));
109 static const char * disasm_imm_operand(unsigned int operand)
116 if (operand & (1 << 9))
117 snprintf(ret, 7, "0x%04X", (operand | 0xFC00));
119 snprintf(ret, 7, "0x%03X", operand);
124 static const char * disasm_spr_operand(unsigned int operand)
129 snprintf(ret, 7, "spr%03X", (operand & 0x1FF));
134 static const char * disasm_gpr_operand(unsigned int operand)
139 snprintf(ret, 4, "r%u", (operand & 0x3F));
144 static const char * disasm_offr_operand(unsigned int operand)
149 snprintf(ret, 5, "off%u", (operand & 0x7));
154 static void disasm_std_operand(struct statement *stmt,
159 unsigned int operand = stmt->u.insn.bin->operands[oper_idx];
164 if (!(operand & 0x800)) {
165 stmt->u.insn.operands[out_idx] = disasm_mem_operand(operand);
167 } else if ((operand & 0xC00) == 0xC00) {
168 stmt->u.insn.operands[out_idx] = disasm_imm_operand(operand);
170 } else if ((operand & 0xFC0) == 0xBC0) {
171 stmt->u.insn.operands[out_idx] = disasm_gpr_operand(operand);
173 } else if ((operand & 0xE00) == 0x800) {
174 stmt->u.insn.operands[out_idx] = disasm_spr_operand(operand);
176 } else if ((operand & 0xFF8) == 0x860) {
177 stmt->u.insn.operands[out_idx] = disasm_offr_operand(operand);
179 } else if ((operand & 0xE00) == 0xA00) {
180 stmt->u.insn.operands[out_idx] = disasm_indirect_mem_operand(operand);
184 stmt->u.insn.operands[out_idx] = gen_raw_code(operand);
187 static void disasm_constant_opcodes(struct disassembler_context *ctx,
188 struct statement *stmt)
190 struct bin_instruction *bin = stmt->u.insn.bin;
192 switch (bin->opcode) {
194 stmt->u.insn.name = "add";
195 disasm_std_operand(stmt, 0, 0, 0);
196 disasm_std_operand(stmt, 1, 1, 0);
197 disasm_std_operand(stmt, 2, 2, 0);
200 stmt->u.insn.name = "add.";
201 disasm_std_operand(stmt, 0, 0, 0);
202 disasm_std_operand(stmt, 1, 1, 0);
203 disasm_std_operand(stmt, 2, 2, 0);
206 stmt->u.insn.name = "addc";
207 disasm_std_operand(stmt, 0, 0, 0);
208 disasm_std_operand(stmt, 1, 1, 0);
209 disasm_std_operand(stmt, 2, 2, 0);
212 stmt->u.insn.name = "addc.";
213 disasm_std_operand(stmt, 0, 0, 0);
214 disasm_std_operand(stmt, 1, 1, 0);
215 disasm_std_operand(stmt, 2, 2, 0);
218 stmt->u.insn.name = "sub";
219 disasm_std_operand(stmt, 0, 0, 0);
220 disasm_std_operand(stmt, 1, 1, 0);
221 disasm_std_operand(stmt, 2, 2, 0);
224 stmt->u.insn.name = "sub.";
225 disasm_std_operand(stmt, 0, 0, 0);
226 disasm_std_operand(stmt, 1, 1, 0);
227 disasm_std_operand(stmt, 2, 2, 0);
230 stmt->u.insn.name = "subc";
231 disasm_std_operand(stmt, 0, 0, 0);
232 disasm_std_operand(stmt, 1, 1, 0);
233 disasm_std_operand(stmt, 2, 2, 0);
236 stmt->u.insn.name = "subc.";
237 disasm_std_operand(stmt, 0, 0, 0);
238 disasm_std_operand(stmt, 1, 1, 0);
239 disasm_std_operand(stmt, 2, 2, 0);
242 stmt->u.insn.name = "sra";
243 disasm_std_operand(stmt, 0, 0, 0);
244 disasm_std_operand(stmt, 1, 1, 0);
245 disasm_std_operand(stmt, 2, 2, 0);
248 stmt->u.insn.name = "or";
249 disasm_std_operand(stmt, 0, 0, 0);
250 disasm_std_operand(stmt, 1, 1, 0);
251 disasm_std_operand(stmt, 2, 2, 0);
254 stmt->u.insn.name = "and";
255 disasm_std_operand(stmt, 0, 0, 0);
256 disasm_std_operand(stmt, 1, 1, 0);
257 disasm_std_operand(stmt, 2, 2, 0);
260 stmt->u.insn.name = "xor";
261 disasm_std_operand(stmt, 0, 0, 0);
262 disasm_std_operand(stmt, 1, 1, 0);
263 disasm_std_operand(stmt, 2, 2, 0);
266 stmt->u.insn.name = "sr";
267 disasm_std_operand(stmt, 0, 0, 0);
268 disasm_std_operand(stmt, 1, 1, 0);
269 disasm_std_operand(stmt, 2, 2, 0);
272 stmt->u.insn.name = "sl";
273 disasm_std_operand(stmt, 0, 0, 0);
274 disasm_std_operand(stmt, 1, 1, 0);
275 disasm_std_operand(stmt, 2, 2, 0);
278 stmt->u.insn.name = "rl";
279 disasm_std_operand(stmt, 0, 0, 0);
280 disasm_std_operand(stmt, 1, 1, 0);
281 disasm_std_operand(stmt, 2, 2, 0);
284 stmt->u.insn.name = "rr";
285 disasm_std_operand(stmt, 0, 0, 0);
286 disasm_std_operand(stmt, 1, 1, 0);
287 disasm_std_operand(stmt, 2, 2, 0);
290 stmt->u.insn.name = "nand";
291 disasm_std_operand(stmt, 0, 0, 0);
292 disasm_std_operand(stmt, 1, 1, 0);
293 disasm_std_operand(stmt, 2, 2, 0);
296 stmt->u.insn.name = "jand";
297 stmt->u.insn.is_labelref = 2;
298 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
299 disasm_std_operand(stmt, 0, 0, 0);
300 disasm_std_operand(stmt, 1, 1, 0);
303 stmt->u.insn.name = "jnand";
304 stmt->u.insn.is_labelref = 2;
305 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
306 disasm_std_operand(stmt, 0, 0, 0);
307 disasm_std_operand(stmt, 1, 1, 0);
310 stmt->u.insn.name = "js";
311 stmt->u.insn.is_labelref = 2;
312 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
313 disasm_std_operand(stmt, 0, 0, 0);
314 disasm_std_operand(stmt, 1, 1, 0);
317 stmt->u.insn.name = "jns";
318 stmt->u.insn.is_labelref = 2;
319 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
320 disasm_std_operand(stmt, 0, 0, 0);
321 disasm_std_operand(stmt, 1, 1, 0);
324 stmt->u.insn.name = "je";
325 stmt->u.insn.is_labelref = 2;
326 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
327 disasm_std_operand(stmt, 0, 0, 0);
328 disasm_std_operand(stmt, 1, 1, 0);
331 stmt->u.insn.name = "jne";
332 stmt->u.insn.is_labelref = 2;
333 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
334 disasm_std_operand(stmt, 0, 0, 0);
335 disasm_std_operand(stmt, 1, 1, 0);
338 stmt->u.insn.name = "jls";
339 stmt->u.insn.is_labelref = 2;
340 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
341 disasm_std_operand(stmt, 0, 0, 0);
342 disasm_std_operand(stmt, 1, 1, 0);
345 stmt->u.insn.name = "jges";
346 stmt->u.insn.is_labelref = 2;
347 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
348 disasm_std_operand(stmt, 0, 0, 0);
349 disasm_std_operand(stmt, 1, 1, 0);
352 stmt->u.insn.name = "jgs";
353 stmt->u.insn.is_labelref = 2;
354 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
355 disasm_std_operand(stmt, 0, 0, 0);
356 disasm_std_operand(stmt, 1, 1, 0);
359 stmt->u.insn.name = "jles";
360 stmt->u.insn.is_labelref = 2;
361 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
362 disasm_std_operand(stmt, 0, 0, 0);
363 disasm_std_operand(stmt, 1, 1, 0);
366 stmt->u.insn.name = "jl";
367 stmt->u.insn.is_labelref = 2;
368 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
369 disasm_std_operand(stmt, 0, 0, 0);
370 disasm_std_operand(stmt, 1, 1, 0);
373 stmt->u.insn.name = "jge";
374 stmt->u.insn.is_labelref = 2;
375 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
376 disasm_std_operand(stmt, 0, 0, 0);
377 disasm_std_operand(stmt, 1, 1, 0);
380 stmt->u.insn.name = "jg";
381 stmt->u.insn.is_labelref = 2;
382 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
383 disasm_std_operand(stmt, 0, 0, 0);
384 disasm_std_operand(stmt, 1, 1, 0);
387 stmt->u.insn.name = "jle";
388 stmt->u.insn.is_labelref = 2;
389 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
390 disasm_std_operand(stmt, 0, 0, 0);
391 disasm_std_operand(stmt, 1, 1, 0);
396 stmt->u.insn.name = "call";
397 stmt->u.insn.is_labelref = 1;
398 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
400 snprintf(str, 4, "lr%u", stmt->u.insn.bin->operands[0]);
401 stmt->u.insn.operands[0] = str;
407 stmt->u.insn.name = "ret";
409 snprintf(str, 4, "lr%u", stmt->u.insn.bin->operands[0]);
410 stmt->u.insn.operands[0] = str;
412 snprintf(str, 4, "lr%u", stmt->u.insn.bin->operands[2]);
413 stmt->u.insn.operands[2] = str;
419 flags = stmt->u.insn.bin->operands[1];
420 switch (flags & ~0xC00) {
422 stmt->u.insn.name = "tkiph";
425 stmt->u.insn.name = "tkiphs";
428 stmt->u.insn.name = "tkipl";
431 stmt->u.insn.name = "tkipls";
434 fprintf(stderr, "Invalid TKIP flags %X\n",
438 disasm_std_operand(stmt, 0, 0, 0);
439 disasm_std_operand(stmt, 2, 2, 0);
443 stmt->u.insn.name = "nap";
444 if (stmt->u.insn.bin->operands[0] != 0xBC0) {
445 fprintf(stderr, "NAP: invalid first argument 0x%03X\n",
446 stmt->u.insn.bin->operands[0]);
448 if (stmt->u.insn.bin->operands[1] != 0xBC0) {
449 fprintf(stderr, "NAP: invalid second argument 0x%03X\n",
450 stmt->u.insn.bin->operands[1]);
452 if (stmt->u.insn.bin->operands[2] != 0x000) {
453 fprintf(stderr, "NAP: invalid third argument 0x%03X\n",
454 stmt->u.insn.bin->operands[2]);
459 stmt->u.insn.name = gen_raw_code(bin->opcode);
460 disasm_std_operand(stmt, 0, 0, 1);
461 disasm_std_operand(stmt, 1, 1, 1);
462 disasm_std_operand(stmt, 2, 2, 1);
467 static void disasm_opcodes(struct disassembler_context *ctx)
469 struct bin_instruction *bin;
471 struct statement *stmt;
474 for (i = 0; i < ctx->nr_insns; i++) {
475 bin = &(ctx->code[i]);
477 stmt = xmalloc(sizeof(struct statement));
478 stmt->type = STMT_INSN;
479 INIT_LIST_HEAD(&stmt->list);
480 stmt->u.insn.bin = bin;
481 stmt->u.insn.is_labelref = -1;
483 switch (bin->opcode & 0xF00) {
485 stmt->u.insn.name = "srx";
488 snprintf(str, 3, "%d", (bin->opcode & 0x0F0) >> 4);
489 stmt->u.insn.operands[0] = str;
491 snprintf(str, 3, "%d", (bin->opcode & 0x00F));
492 stmt->u.insn.operands[1] = str;
494 disasm_std_operand(stmt, 0, 2, 0);
495 disasm_std_operand(stmt, 1, 3, 0);
496 disasm_std_operand(stmt, 2, 4, 0);
499 stmt->u.insn.name = "orx";
502 snprintf(str, 3, "%d", (bin->opcode & 0x0F0) >> 4);
503 stmt->u.insn.operands[0] = str;
505 snprintf(str, 3, "%d", (bin->opcode & 0x00F));
506 stmt->u.insn.operands[1] = str;
508 disasm_std_operand(stmt, 0, 2, 0);
509 disasm_std_operand(stmt, 1, 3, 0);
510 disasm_std_operand(stmt, 2, 4, 0);
513 stmt->u.insn.name = "jzx";
516 snprintf(str, 3, "%d", (bin->opcode & 0x0F0) >> 4);
517 stmt->u.insn.operands[0] = str;
519 snprintf(str, 3, "%d", (bin->opcode & 0x00F));
520 stmt->u.insn.operands[1] = str;
522 disasm_std_operand(stmt, 0, 2, 0);
523 disasm_std_operand(stmt, 1, 3, 0);
524 stmt->u.insn.is_labelref = 4;
525 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
528 stmt->u.insn.name = "jnzx";
531 snprintf(str, 3, "%d", (bin->opcode & 0x0F0) >> 4);
532 stmt->u.insn.operands[0] = str;
534 snprintf(str, 3, "%d", (bin->opcode & 0x00F));
535 stmt->u.insn.operands[1] = str;
537 disasm_std_operand(stmt, 0, 2, 0);
538 disasm_std_operand(stmt, 1, 3, 0);
539 stmt->u.insn.is_labelref = 4;
540 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
543 stmt->u.insn.name = "jnext";
546 snprintf(str, 5, "0x%02X", (bin->opcode & 0x0FF));
547 stmt->u.insn.operands[0] = str;
549 disasm_std_operand(stmt, 0, 1, 0);
550 disasm_std_operand(stmt, 1, 2, 0);
551 stmt->u.insn.is_labelref = 3;
552 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
555 stmt->u.insn.name = "jext";
558 snprintf(str, 5, "0x%02X", (bin->opcode & 0x0FF));
559 stmt->u.insn.operands[0] = str;
561 disasm_std_operand(stmt, 0, 1, 0);
562 disasm_std_operand(stmt, 1, 2, 0);
563 stmt->u.insn.is_labelref = 3;
564 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
567 disasm_constant_opcodes(ctx, stmt);
571 list_add_tail(&stmt->list, &ctx->stmt_list);
575 static struct statement * get_label_at(struct disassembler_context *ctx,
578 unsigned int addrcnt = 0;
579 struct statement *stmt, *ret, *prev;
581 list_for_each_entry(stmt, &ctx->stmt_list, list) {
582 if (stmt->type != STMT_INSN)
584 if (addrcnt == addr) {
585 prev = list_entry(stmt->list.prev, struct statement, list);
586 if (prev->type == STMT_LABEL)
588 ret = xmalloc(sizeof(struct statement));
589 INIT_LIST_HEAD(&ret->list);
590 ret->type = STMT_LABEL;
591 list_add(&ret->list, &prev->list);
601 static void resolve_labels(struct disassembler_context *ctx)
603 struct statement *stmt;
604 struct statement *label;
606 unsigned int labeladdr;
607 unsigned int namecnt = 0;
609 /* Resolve label references */
610 list_for_each_entry_safe(stmt, n, &ctx->stmt_list, list) {
611 if (stmt->type != STMT_INSN)
613 if (stmt->u.insn.is_labelref == -1)
615 labeladdr = stmt->u.insn.labeladdr;
616 label = get_label_at(ctx, labeladdr);
618 fprintf(stderr, "Labeladdress %X out of bounds\n",
622 stmt->u.insn.labelref = label;
625 /* Name the labels */
626 list_for_each_entry(stmt, &ctx->stmt_list, list) {
627 if (stmt->type != STMT_LABEL)
629 stmt->u.label.name = xmalloc(20);
630 snprintf(stmt->u.label.name, 20, "L%u", namecnt);
635 static void emit_asm(struct disassembler_context *ctx)
637 struct statement *stmt;
641 fd = fopen(outfile_name, "w+");
643 fprintf(stderr, "Could not open output file \"%s\"\n",
647 /* FIXME: We currently only support v5 architecture. */
648 fprintf(fd, "%%arch 5\n\n");
649 list_for_each_entry(stmt, &ctx->stmt_list, list) {
650 switch (stmt->type) {
652 fprintf(fd, "\t%s", stmt->u.insn.name);
654 for (i = 0; i < ARRAY_SIZE(stmt->u.insn.operands); i++) {
655 if (stmt->u.insn.is_labelref == i) {
657 stmt->u.insn.labelref->u.label.name);
659 if (!stmt->u.insn.operands[i])
667 stmt->u.insn.operands[i]);
672 fprintf(fd, "%s:\n", stmt->u.label.name);
679 static void read_input(struct disassembler_context *ctx)
681 size_t size = 0, pos = 0;
683 struct bin_instruction *code = NULL;
684 unsigned char tmp[sizeof(uint64_t)];
686 struct fw_header hdr;
688 ret = fread(&hdr, 1, sizeof(hdr), infile);
689 if (!ret || ret != sizeof(hdr)) {
690 fprintf(stderr, "Corrupt input file (not fwcutter output)\n");
695 fprintf(stderr, "Invalid fwcutter header version\n");
699 if (hdr.type != 'u') {
700 fprintf(stderr, "Not a microcode image\n");
707 code = xrealloc(code, size * sizeof(struct bin_instruction));
709 ret = fread(tmp, 1, sizeof(uint64_t), infile);
712 if (ret != sizeof(uint64_t)) {
713 fprintf(stderr, "Corrupt input file (not 8 byte aligned)\n");
718 codeword |= ((uint64_t)tmp[0]) << 56;
719 codeword |= ((uint64_t)tmp[1]) << 48;
720 codeword |= ((uint64_t)tmp[2]) << 40;
721 codeword |= ((uint64_t)tmp[3]) << 32;
722 codeword |= ((uint64_t)tmp[4]) << 24;
723 codeword |= ((uint64_t)tmp[5]) << 16;
724 codeword |= ((uint64_t)tmp[6]) << 8;
725 codeword |= ((uint64_t)tmp[7]);
727 code[pos].opcode = (codeword >> 4) & 0xFFF;
728 code[pos].operands[0] = (codeword & 0xF) << 8;
729 code[pos].operands[0] |= (codeword >> 56) & 0xFF;
730 code[pos].operands[1] = (codeword >> 44) & 0xFFF;
731 code[pos].operands[2] = (codeword >> 32) & 0xFFF;
740 static void disassemble(void)
742 struct disassembler_context ctx;
744 memset(&ctx, 0, sizeof(ctx));
745 INIT_LIST_HEAD(&ctx.stmt_list);
748 disasm_opcodes(&ctx);
749 resolve_labels(&ctx);
753 static void usage(int argc, char **argv)
755 fprintf(stderr, "Usage: %s output_file\n", argv[0]);
758 static void parse_args(int argc, char **argv)
764 outfile_name = argv[1];
767 int main(int argc, char **argv)
770 parse_args(argc, argv);
773 /* Lazyman simply leaks all allocated memory. */