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.
23 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
25 /* The header that fwcutter puts in to every .fw file */
27 /* Type of the firmware data */
29 /* Version number of the firmware data format */
32 /* Size of the data. For ucode and PCM this is in bytes.
33 * For IV this is in number-of-ivs. */
35 } __attribute__ ((__packed__));
38 struct bin_instruction {
40 unsigned int operands[3];
51 struct bin_instruction *bin;
53 const char *operands[5];
56 unsigned int labeladdr;
57 struct statement *labelref;
64 struct list_head list;
67 struct disassembler_context {
68 /* The architecture of the input file. */
71 struct bin_instruction *code;
74 struct list_head stmt_list;
80 const char *infile_name;
81 const char *outfile_name;
84 static const char * gen_raw_code(unsigned int operand)
89 snprintf(ret, 5, "@%03X", operand);
94 static const char * disasm_mem_operand(unsigned int operand)
99 snprintf(ret, 8, "[0x%03X]", operand);
104 static const char * disasm_indirect_mem_operand(unsigned int operand)
109 snprintf(ret, 12, "[0x%02X,off%u]",
110 (operand & 0x3F), ((operand >> 6) & 0x7));
115 static const char * disasm_imm_operand(unsigned int operand)
122 if (operand & (1 << 9))
123 snprintf(ret, 7, "0x%04X", (operand | 0xFC00));
125 snprintf(ret, 7, "0x%03X", operand);
130 static const char * disasm_spr_operand(unsigned int operand)
135 snprintf(ret, 7, "spr%03X", (operand & 0x1FF));
140 static const char * disasm_gpr_operand(unsigned int operand)
145 snprintf(ret, 4, "r%u", (operand & 0x3F));
150 static const char * disasm_offr_operand(unsigned int operand)
155 snprintf(ret, 5, "off%u", (operand & 0x7));
160 static void disasm_std_operand(struct statement *stmt,
165 unsigned int operand = stmt->u.insn.bin->operands[oper_idx];
170 if (!(operand & 0x800)) {
171 stmt->u.insn.operands[out_idx] = disasm_mem_operand(operand);
173 } else if ((operand & 0xC00) == 0xC00) {
174 stmt->u.insn.operands[out_idx] = disasm_imm_operand(operand);
176 } else if ((operand & 0xFC0) == 0xBC0) {
177 stmt->u.insn.operands[out_idx] = disasm_gpr_operand(operand);
179 } else if ((operand & 0xE00) == 0x800) {
180 stmt->u.insn.operands[out_idx] = disasm_spr_operand(operand);
182 } else if ((operand & 0xFF8) == 0x860) {
183 stmt->u.insn.operands[out_idx] = disasm_offr_operand(operand);
185 } else if ((operand & 0xE00) == 0xA00) {
186 stmt->u.insn.operands[out_idx] = disasm_indirect_mem_operand(operand);
190 stmt->u.insn.operands[out_idx] = gen_raw_code(operand);
193 static void disasm_constant_opcodes(struct disassembler_context *ctx,
194 struct statement *stmt)
196 struct bin_instruction *bin = stmt->u.insn.bin;
198 switch (bin->opcode) {
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 = "add.";
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 = "addc.";
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 = "sub.";
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 = "subc.";
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 = "sra";
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 = "or";
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 = "and";
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 = "xor";
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 = "sr";
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 = "sl";
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 = "rl";
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 = "rr";
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 = "nand";
297 disasm_std_operand(stmt, 0, 0, 0);
298 disasm_std_operand(stmt, 1, 1, 0);
299 disasm_std_operand(stmt, 2, 2, 0);
302 stmt->u.insn.name = "jand";
303 stmt->u.insn.is_labelref = 2;
304 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
305 disasm_std_operand(stmt, 0, 0, 0);
306 disasm_std_operand(stmt, 1, 1, 0);
309 stmt->u.insn.name = "jnand";
310 stmt->u.insn.is_labelref = 2;
311 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
312 disasm_std_operand(stmt, 0, 0, 0);
313 disasm_std_operand(stmt, 1, 1, 0);
316 stmt->u.insn.name = "js";
317 stmt->u.insn.is_labelref = 2;
318 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
319 disasm_std_operand(stmt, 0, 0, 0);
320 disasm_std_operand(stmt, 1, 1, 0);
323 stmt->u.insn.name = "jns";
324 stmt->u.insn.is_labelref = 2;
325 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
326 disasm_std_operand(stmt, 0, 0, 0);
327 disasm_std_operand(stmt, 1, 1, 0);
330 stmt->u.insn.name = "je";
331 stmt->u.insn.is_labelref = 2;
332 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
333 disasm_std_operand(stmt, 0, 0, 0);
334 disasm_std_operand(stmt, 1, 1, 0);
337 stmt->u.insn.name = "jne";
338 stmt->u.insn.is_labelref = 2;
339 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
340 disasm_std_operand(stmt, 0, 0, 0);
341 disasm_std_operand(stmt, 1, 1, 0);
344 stmt->u.insn.name = "jls";
345 stmt->u.insn.is_labelref = 2;
346 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
347 disasm_std_operand(stmt, 0, 0, 0);
348 disasm_std_operand(stmt, 1, 1, 0);
351 stmt->u.insn.name = "jges";
352 stmt->u.insn.is_labelref = 2;
353 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
354 disasm_std_operand(stmt, 0, 0, 0);
355 disasm_std_operand(stmt, 1, 1, 0);
358 stmt->u.insn.name = "jgs";
359 stmt->u.insn.is_labelref = 2;
360 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
361 disasm_std_operand(stmt, 0, 0, 0);
362 disasm_std_operand(stmt, 1, 1, 0);
365 stmt->u.insn.name = "jles";
366 stmt->u.insn.is_labelref = 2;
367 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
368 disasm_std_operand(stmt, 0, 0, 0);
369 disasm_std_operand(stmt, 1, 1, 0);
372 stmt->u.insn.name = "jl";
373 stmt->u.insn.is_labelref = 2;
374 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
375 disasm_std_operand(stmt, 0, 0, 0);
376 disasm_std_operand(stmt, 1, 1, 0);
379 stmt->u.insn.name = "jge";
380 stmt->u.insn.is_labelref = 2;
381 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
382 disasm_std_operand(stmt, 0, 0, 0);
383 disasm_std_operand(stmt, 1, 1, 0);
386 stmt->u.insn.name = "jg";
387 stmt->u.insn.is_labelref = 2;
388 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
389 disasm_std_operand(stmt, 0, 0, 0);
390 disasm_std_operand(stmt, 1, 1, 0);
393 stmt->u.insn.name = "jle";
394 stmt->u.insn.is_labelref = 2;
395 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
396 disasm_std_operand(stmt, 0, 0, 0);
397 disasm_std_operand(stmt, 1, 1, 0);
402 stmt->u.insn.name = "call";
403 stmt->u.insn.is_labelref = 1;
404 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
406 snprintf(str, 4, "lr%u", stmt->u.insn.bin->operands[0]);
407 stmt->u.insn.operands[0] = str;
413 stmt->u.insn.name = "ret";
415 snprintf(str, 4, "lr%u", stmt->u.insn.bin->operands[0]);
416 stmt->u.insn.operands[0] = str;
418 snprintf(str, 4, "lr%u", stmt->u.insn.bin->operands[2]);
419 stmt->u.insn.operands[2] = str;
425 flags = stmt->u.insn.bin->operands[1];
426 switch (flags & ~0xC00) {
428 stmt->u.insn.name = "tkiph";
431 stmt->u.insn.name = "tkiphs";
434 stmt->u.insn.name = "tkipl";
437 stmt->u.insn.name = "tkipls";
440 fprintf(stderr, "Invalid TKIP flags %X\n",
444 disasm_std_operand(stmt, 0, 0, 0);
445 disasm_std_operand(stmt, 2, 2, 0);
449 stmt->u.insn.name = "nap";
450 if (stmt->u.insn.bin->operands[0] != 0xBC0) {
451 fprintf(stderr, "NAP: invalid first argument 0x%03X\n",
452 stmt->u.insn.bin->operands[0]);
454 if (stmt->u.insn.bin->operands[1] != 0xBC0) {
455 fprintf(stderr, "NAP: invalid second argument 0x%03X\n",
456 stmt->u.insn.bin->operands[1]);
458 if (stmt->u.insn.bin->operands[2] != 0x000) {
459 fprintf(stderr, "NAP: invalid third argument 0x%03X\n",
460 stmt->u.insn.bin->operands[2]);
465 stmt->u.insn.name = gen_raw_code(bin->opcode);
466 disasm_std_operand(stmt, 0, 0, 1);
467 disasm_std_operand(stmt, 1, 1, 1);
468 disasm_std_operand(stmt, 2, 2, 1);
473 static void disasm_opcodes(struct disassembler_context *ctx)
475 struct bin_instruction *bin;
477 struct statement *stmt;
480 for (i = 0; i < ctx->nr_insns; i++) {
481 bin = &(ctx->code[i]);
483 stmt = xmalloc(sizeof(struct statement));
484 stmt->type = STMT_INSN;
485 INIT_LIST_HEAD(&stmt->list);
486 stmt->u.insn.bin = bin;
487 stmt->u.insn.is_labelref = -1;
489 switch (bin->opcode & 0xF00) {
491 stmt->u.insn.name = "srx";
494 snprintf(str, 3, "%d", (bin->opcode & 0x0F0) >> 4);
495 stmt->u.insn.operands[0] = str;
497 snprintf(str, 3, "%d", (bin->opcode & 0x00F));
498 stmt->u.insn.operands[1] = str;
500 disasm_std_operand(stmt, 0, 2, 0);
501 disasm_std_operand(stmt, 1, 3, 0);
502 disasm_std_operand(stmt, 2, 4, 0);
505 stmt->u.insn.name = "orx";
508 snprintf(str, 3, "%d", (bin->opcode & 0x0F0) >> 4);
509 stmt->u.insn.operands[0] = str;
511 snprintf(str, 3, "%d", (bin->opcode & 0x00F));
512 stmt->u.insn.operands[1] = str;
514 disasm_std_operand(stmt, 0, 2, 0);
515 disasm_std_operand(stmt, 1, 3, 0);
516 disasm_std_operand(stmt, 2, 4, 0);
519 stmt->u.insn.name = "jzx";
522 snprintf(str, 3, "%d", (bin->opcode & 0x0F0) >> 4);
523 stmt->u.insn.operands[0] = str;
525 snprintf(str, 3, "%d", (bin->opcode & 0x00F));
526 stmt->u.insn.operands[1] = str;
528 disasm_std_operand(stmt, 0, 2, 0);
529 disasm_std_operand(stmt, 1, 3, 0);
530 stmt->u.insn.is_labelref = 4;
531 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
534 stmt->u.insn.name = "jnzx";
537 snprintf(str, 3, "%d", (bin->opcode & 0x0F0) >> 4);
538 stmt->u.insn.operands[0] = str;
540 snprintf(str, 3, "%d", (bin->opcode & 0x00F));
541 stmt->u.insn.operands[1] = str;
543 disasm_std_operand(stmt, 0, 2, 0);
544 disasm_std_operand(stmt, 1, 3, 0);
545 stmt->u.insn.is_labelref = 4;
546 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
549 stmt->u.insn.name = "jnext";
552 snprintf(str, 5, "0x%02X", (bin->opcode & 0x0FF));
553 stmt->u.insn.operands[0] = str;
555 disasm_std_operand(stmt, 0, 1, 0);
556 disasm_std_operand(stmt, 1, 2, 0);
557 stmt->u.insn.is_labelref = 3;
558 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
561 stmt->u.insn.name = "jext";
564 snprintf(str, 5, "0x%02X", (bin->opcode & 0x0FF));
565 stmt->u.insn.operands[0] = str;
567 disasm_std_operand(stmt, 0, 1, 0);
568 disasm_std_operand(stmt, 1, 2, 0);
569 stmt->u.insn.is_labelref = 3;
570 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
573 disasm_constant_opcodes(ctx, stmt);
577 list_add_tail(&stmt->list, &ctx->stmt_list);
581 static struct statement * get_label_at(struct disassembler_context *ctx,
584 unsigned int addrcnt = 0;
585 struct statement *stmt, *ret, *prev;
587 list_for_each_entry(stmt, &ctx->stmt_list, list) {
588 if (stmt->type != STMT_INSN)
590 if (addrcnt == addr) {
591 prev = list_entry(stmt->list.prev, struct statement, list);
592 if (prev->type == STMT_LABEL)
594 ret = xmalloc(sizeof(struct statement));
595 INIT_LIST_HEAD(&ret->list);
596 ret->type = STMT_LABEL;
597 list_add(&ret->list, &prev->list);
607 static void resolve_labels(struct disassembler_context *ctx)
609 struct statement *stmt;
610 struct statement *label;
612 unsigned int labeladdr;
613 unsigned int namecnt = 0;
615 /* Resolve label references */
616 list_for_each_entry_safe(stmt, n, &ctx->stmt_list, list) {
617 if (stmt->type != STMT_INSN)
619 if (stmt->u.insn.is_labelref == -1)
621 labeladdr = stmt->u.insn.labeladdr;
622 label = get_label_at(ctx, labeladdr);
624 fprintf(stderr, "Labeladdress %X out of bounds\n",
628 stmt->u.insn.labelref = label;
631 /* Name the labels */
632 list_for_each_entry(stmt, &ctx->stmt_list, list) {
633 if (stmt->type != STMT_LABEL)
635 stmt->u.label.name = xmalloc(20);
636 snprintf(stmt->u.label.name, 20, "L%u", namecnt);
641 static void emit_asm(struct disassembler_context *ctx)
643 struct statement *stmt;
647 err = open_output_file();
651 fprintf(outfile, "%%arch %u\n\n", ctx->arch);
652 list_for_each_entry(stmt, &ctx->stmt_list, list) {
653 switch (stmt->type) {
655 fprintf(outfile, "\t%s", stmt->u.insn.name);
657 for (i = 0; i < ARRAY_SIZE(stmt->u.insn.operands); i++) {
658 if (stmt->u.insn.is_labelref == i) {
659 fprintf(outfile, ",%s",
660 stmt->u.insn.labelref->u.label.name);
662 if (!stmt->u.insn.operands[i])
665 fprintf(outfile, "\t");
667 fprintf(outfile, ",");
669 fprintf(outfile, "%s",
670 stmt->u.insn.operands[i]);
672 fprintf(outfile, "\n");
675 fprintf(outfile, "%s:\n", stmt->u.label.name);
683 static int read_input(struct disassembler_context *ctx)
685 size_t size = 0, pos = 0;
687 struct bin_instruction *code = NULL;
688 unsigned char tmp[sizeof(uint64_t)];
690 struct fw_header hdr;
693 err = open_input_file();
697 ret = fread(&hdr, 1, sizeof(hdr), infile);
698 if (ret != sizeof(hdr)) {
699 fprintf(stderr, "Corrupt input file (not fwcutter output)\n");
702 if (hdr.type != 'u') {
703 fprintf(stderr, "Corrupt input file. Not a microcode image.\n");
707 fprintf(stderr, "Invalid input file header version.\n");
714 code = xrealloc(code, size * sizeof(struct bin_instruction));
716 ret = fread(tmp, 1, sizeof(uint64_t), infile);
719 if (ret != sizeof(uint64_t)) {
720 fprintf(stderr, "Corrupt input file (not 8 byte aligned)\n");
725 codeword |= ((uint64_t)tmp[0]) << 56;
726 codeword |= ((uint64_t)tmp[1]) << 48;
727 codeword |= ((uint64_t)tmp[2]) << 40;
728 codeword |= ((uint64_t)tmp[3]) << 32;
729 codeword |= ((uint64_t)tmp[4]) << 24;
730 codeword |= ((uint64_t)tmp[5]) << 16;
731 codeword |= ((uint64_t)tmp[6]) << 8;
732 codeword |= ((uint64_t)tmp[7]);
734 code[pos].opcode = (codeword >> 4) & 0xFFF;
735 code[pos].operands[0] = (codeword & 0xF) << 8;
736 code[pos].operands[0] |= (codeword >> 56) & 0xFF;
737 code[pos].operands[1] = (codeword >> 44) & 0xFFF;
738 code[pos].operands[2] = (codeword >> 32) & 0xFFF;
758 static void disassemble(void)
760 struct disassembler_context ctx;
763 memset(&ctx, 0, sizeof(ctx));
764 INIT_LIST_HEAD(&ctx.stmt_list);
765 ctx.arch = cmdargs.arch;
767 err = read_input(&ctx);
770 disasm_opcodes(&ctx);
771 resolve_labels(&ctx);
775 int main(int argc, char **argv)
779 err = parse_args(argc, argv);
789 /* Lazyman simply leaks all allocated memory. */