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.
25 struct bin_instruction {
27 unsigned int operands[3];
38 struct bin_instruction *bin;
40 const char *operands[5];
43 unsigned int labeladdr;
44 struct statement *labelref;
51 struct list_head list;
54 struct disassembler_context {
55 /* The architecture of the input file. */
58 struct bin_instruction *code;
61 struct list_head stmt_list;
67 const char *infile_name;
68 const char *outfile_name;
71 static const char * gen_raw_code(unsigned int operand)
76 snprintf(ret, 5, "@%03X", operand);
81 static const char * disasm_mem_operand(unsigned int operand)
86 snprintf(ret, 8, "[0x%03X]", operand);
91 static const char * disasm_indirect_mem_operand(unsigned int operand)
96 snprintf(ret, 12, "[0x%02X,off%u]",
97 (operand & 0x3F), ((operand >> 6) & 0x7));
102 static const char * disasm_imm_operand(unsigned int operand)
109 if (operand & (1 << 9))
110 snprintf(ret, 7, "0x%04X", (operand | 0xFC00));
112 snprintf(ret, 7, "0x%03X", operand);
117 static const char * disasm_spr_operand(unsigned int operand)
122 snprintf(ret, 7, "spr%03X", (operand & 0x1FF));
127 static const char * disasm_gpr_operand(unsigned int operand)
132 snprintf(ret, 4, "r%u", (operand & 0x3F));
137 static const char * disasm_offr_operand(unsigned int operand)
142 snprintf(ret, 5, "off%u", (operand & 0x7));
147 static void disasm_std_operand(struct statement *stmt,
152 unsigned int operand = stmt->u.insn.bin->operands[oper_idx];
157 if (!(operand & 0x800)) {
158 stmt->u.insn.operands[out_idx] = disasm_mem_operand(operand);
160 } else if ((operand & 0xC00) == 0xC00) {
161 stmt->u.insn.operands[out_idx] = disasm_imm_operand(operand);
163 } else if ((operand & 0xFC0) == 0xBC0) {
164 stmt->u.insn.operands[out_idx] = disasm_gpr_operand(operand);
166 } else if ((operand & 0xE00) == 0x800) {
167 stmt->u.insn.operands[out_idx] = disasm_spr_operand(operand);
169 } else if ((operand & 0xFF8) == 0x860) {
170 stmt->u.insn.operands[out_idx] = disasm_offr_operand(operand);
172 } else if ((operand & 0xE00) == 0xA00) {
173 stmt->u.insn.operands[out_idx] = disasm_indirect_mem_operand(operand);
177 stmt->u.insn.operands[out_idx] = gen_raw_code(operand);
180 static void disasm_constant_opcodes(struct disassembler_context *ctx,
181 struct statement *stmt)
183 struct bin_instruction *bin = stmt->u.insn.bin;
185 switch (bin->opcode) {
187 stmt->u.insn.name = "add";
188 disasm_std_operand(stmt, 0, 0, 0);
189 disasm_std_operand(stmt, 1, 1, 0);
190 disasm_std_operand(stmt, 2, 2, 0);
193 stmt->u.insn.name = "add.";
194 disasm_std_operand(stmt, 0, 0, 0);
195 disasm_std_operand(stmt, 1, 1, 0);
196 disasm_std_operand(stmt, 2, 2, 0);
199 stmt->u.insn.name = "addc";
200 disasm_std_operand(stmt, 0, 0, 0);
201 disasm_std_operand(stmt, 1, 1, 0);
202 disasm_std_operand(stmt, 2, 2, 0);
205 stmt->u.insn.name = "addc.";
206 disasm_std_operand(stmt, 0, 0, 0);
207 disasm_std_operand(stmt, 1, 1, 0);
208 disasm_std_operand(stmt, 2, 2, 0);
211 stmt->u.insn.name = "sub";
212 disasm_std_operand(stmt, 0, 0, 0);
213 disasm_std_operand(stmt, 1, 1, 0);
214 disasm_std_operand(stmt, 2, 2, 0);
217 stmt->u.insn.name = "sub.";
218 disasm_std_operand(stmt, 0, 0, 0);
219 disasm_std_operand(stmt, 1, 1, 0);
220 disasm_std_operand(stmt, 2, 2, 0);
223 stmt->u.insn.name = "subc";
224 disasm_std_operand(stmt, 0, 0, 0);
225 disasm_std_operand(stmt, 1, 1, 0);
226 disasm_std_operand(stmt, 2, 2, 0);
229 stmt->u.insn.name = "subc.";
230 disasm_std_operand(stmt, 0, 0, 0);
231 disasm_std_operand(stmt, 1, 1, 0);
232 disasm_std_operand(stmt, 2, 2, 0);
235 stmt->u.insn.name = "sra";
236 disasm_std_operand(stmt, 0, 0, 0);
237 disasm_std_operand(stmt, 1, 1, 0);
238 disasm_std_operand(stmt, 2, 2, 0);
241 stmt->u.insn.name = "or";
242 disasm_std_operand(stmt, 0, 0, 0);
243 disasm_std_operand(stmt, 1, 1, 0);
244 disasm_std_operand(stmt, 2, 2, 0);
247 stmt->u.insn.name = "and";
248 disasm_std_operand(stmt, 0, 0, 0);
249 disasm_std_operand(stmt, 1, 1, 0);
250 disasm_std_operand(stmt, 2, 2, 0);
253 stmt->u.insn.name = "xor";
254 disasm_std_operand(stmt, 0, 0, 0);
255 disasm_std_operand(stmt, 1, 1, 0);
256 disasm_std_operand(stmt, 2, 2, 0);
259 stmt->u.insn.name = "sr";
260 disasm_std_operand(stmt, 0, 0, 0);
261 disasm_std_operand(stmt, 1, 1, 0);
262 disasm_std_operand(stmt, 2, 2, 0);
265 stmt->u.insn.name = "sl";
266 disasm_std_operand(stmt, 0, 0, 0);
267 disasm_std_operand(stmt, 1, 1, 0);
268 disasm_std_operand(stmt, 2, 2, 0);
271 stmt->u.insn.name = "rl";
272 disasm_std_operand(stmt, 0, 0, 0);
273 disasm_std_operand(stmt, 1, 1, 0);
274 disasm_std_operand(stmt, 2, 2, 0);
277 stmt->u.insn.name = "rr";
278 disasm_std_operand(stmt, 0, 0, 0);
279 disasm_std_operand(stmt, 1, 1, 0);
280 disasm_std_operand(stmt, 2, 2, 0);
283 stmt->u.insn.name = "nand";
284 disasm_std_operand(stmt, 0, 0, 0);
285 disasm_std_operand(stmt, 1, 1, 0);
286 disasm_std_operand(stmt, 2, 2, 0);
289 stmt->u.insn.name = "jand";
290 stmt->u.insn.is_labelref = 2;
291 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
292 disasm_std_operand(stmt, 0, 0, 0);
293 disasm_std_operand(stmt, 1, 1, 0);
296 stmt->u.insn.name = "jnand";
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 = "js";
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 = "jns";
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 = "je";
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 = "jne";
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 = "jls";
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 = "jges";
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 = "jgs";
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 = "jles";
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 = "jl";
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 = "jge";
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 = "jg";
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 = "jle";
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);
389 stmt->u.insn.name = "call";
390 stmt->u.insn.is_labelref = 1;
391 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
393 snprintf(str, 4, "lr%u", stmt->u.insn.bin->operands[0]);
394 stmt->u.insn.operands[0] = str;
400 stmt->u.insn.name = "ret";
402 snprintf(str, 4, "lr%u", stmt->u.insn.bin->operands[0]);
403 stmt->u.insn.operands[0] = str;
405 snprintf(str, 4, "lr%u", stmt->u.insn.bin->operands[2]);
406 stmt->u.insn.operands[2] = str;
412 flags = stmt->u.insn.bin->operands[1];
413 switch (flags & ~0xC00) {
415 stmt->u.insn.name = "tkiph";
418 stmt->u.insn.name = "tkiphs";
421 stmt->u.insn.name = "tkipl";
424 stmt->u.insn.name = "tkipls";
427 fprintf(stderr, "Invalid TKIP flags %X\n",
431 disasm_std_operand(stmt, 0, 0, 0);
432 disasm_std_operand(stmt, 2, 2, 0);
436 stmt->u.insn.name = "nap";
437 if (stmt->u.insn.bin->operands[0] != 0xBC0) {
438 fprintf(stderr, "NAP: invalid first argument 0x%03X\n",
439 stmt->u.insn.bin->operands[0]);
441 if (stmt->u.insn.bin->operands[1] != 0xBC0) {
442 fprintf(stderr, "NAP: invalid second argument 0x%03X\n",
443 stmt->u.insn.bin->operands[1]);
445 if (stmt->u.insn.bin->operands[2] != 0x000) {
446 fprintf(stderr, "NAP: invalid third argument 0x%03X\n",
447 stmt->u.insn.bin->operands[2]);
452 stmt->u.insn.name = gen_raw_code(bin->opcode);
453 disasm_std_operand(stmt, 0, 0, 1);
454 disasm_std_operand(stmt, 1, 1, 1);
455 disasm_std_operand(stmt, 2, 2, 1);
460 static void disasm_opcodes(struct disassembler_context *ctx)
462 struct bin_instruction *bin;
464 struct statement *stmt;
467 for (i = 0; i < ctx->nr_insns; i++) {
468 bin = &(ctx->code[i]);
470 stmt = xmalloc(sizeof(struct statement));
471 stmt->type = STMT_INSN;
472 INIT_LIST_HEAD(&stmt->list);
473 stmt->u.insn.bin = bin;
474 stmt->u.insn.is_labelref = -1;
476 switch (bin->opcode & 0xF00) {
478 stmt->u.insn.name = "srx";
481 snprintf(str, 3, "%d", (bin->opcode & 0x0F0) >> 4);
482 stmt->u.insn.operands[0] = str;
484 snprintf(str, 3, "%d", (bin->opcode & 0x00F));
485 stmt->u.insn.operands[1] = str;
487 disasm_std_operand(stmt, 0, 2, 0);
488 disasm_std_operand(stmt, 1, 3, 0);
489 disasm_std_operand(stmt, 2, 4, 0);
492 stmt->u.insn.name = "orx";
495 snprintf(str, 3, "%d", (bin->opcode & 0x0F0) >> 4);
496 stmt->u.insn.operands[0] = str;
498 snprintf(str, 3, "%d", (bin->opcode & 0x00F));
499 stmt->u.insn.operands[1] = str;
501 disasm_std_operand(stmt, 0, 2, 0);
502 disasm_std_operand(stmt, 1, 3, 0);
503 disasm_std_operand(stmt, 2, 4, 0);
506 stmt->u.insn.name = "jzx";
509 snprintf(str, 3, "%d", (bin->opcode & 0x0F0) >> 4);
510 stmt->u.insn.operands[0] = str;
512 snprintf(str, 3, "%d", (bin->opcode & 0x00F));
513 stmt->u.insn.operands[1] = str;
515 disasm_std_operand(stmt, 0, 2, 0);
516 disasm_std_operand(stmt, 1, 3, 0);
517 stmt->u.insn.is_labelref = 4;
518 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
521 stmt->u.insn.name = "jnzx";
524 snprintf(str, 3, "%d", (bin->opcode & 0x0F0) >> 4);
525 stmt->u.insn.operands[0] = str;
527 snprintf(str, 3, "%d", (bin->opcode & 0x00F));
528 stmt->u.insn.operands[1] = str;
530 disasm_std_operand(stmt, 0, 2, 0);
531 disasm_std_operand(stmt, 1, 3, 0);
532 stmt->u.insn.is_labelref = 4;
533 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
536 stmt->u.insn.name = "jnext";
539 snprintf(str, 5, "0x%02X", (bin->opcode & 0x0FF));
540 stmt->u.insn.operands[0] = str;
542 /* We don't disassemble the first and second operand, as
543 * that always is a dummy r0 operand.
544 * disasm_std_operand(stmt, 0, 1, 0);
545 * disasm_std_operand(stmt, 1, 2, 0);
546 * stmt->u.insn.is_labelref = 3;
548 stmt->u.insn.is_labelref = 1;
549 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
552 stmt->u.insn.name = "jext";
555 snprintf(str, 5, "0x%02X", (bin->opcode & 0x0FF));
556 stmt->u.insn.operands[0] = str;
558 /* We don't disassemble the first and second operand, as
559 * that always is a dummy r0 operand.
560 * disasm_std_operand(stmt, 0, 1, 0);
561 * disasm_std_operand(stmt, 1, 2, 0);
562 * stmt->u.insn.is_labelref = 3;
564 stmt->u.insn.is_labelref = 1;
565 stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
568 disasm_constant_opcodes(ctx, stmt);
572 list_add_tail(&stmt->list, &ctx->stmt_list);
576 static struct statement * get_label_at(struct disassembler_context *ctx,
579 unsigned int addrcnt = 0;
580 struct statement *stmt, *ret, *prev;
582 list_for_each_entry(stmt, &ctx->stmt_list, list) {
583 if (stmt->type != STMT_INSN)
585 if (addrcnt == addr) {
586 prev = list_entry(stmt->list.prev, struct statement, list);
587 if (prev->type == STMT_LABEL)
589 ret = xmalloc(sizeof(struct statement));
590 INIT_LIST_HEAD(&ret->list);
591 ret->type = STMT_LABEL;
592 list_add(&ret->list, &prev->list);
602 static void resolve_labels(struct disassembler_context *ctx)
604 struct statement *stmt;
605 struct statement *label;
607 unsigned int labeladdr;
608 unsigned int namecnt = 0;
610 /* Resolve label references */
611 list_for_each_entry_safe(stmt, n, &ctx->stmt_list, list) {
612 if (stmt->type != STMT_INSN)
614 if (stmt->u.insn.is_labelref == -1)
616 labeladdr = stmt->u.insn.labeladdr;
617 label = get_label_at(ctx, labeladdr);
619 fprintf(stderr, "Labeladdress %X out of bounds\n",
623 stmt->u.insn.labelref = label;
626 /* Name the labels */
627 list_for_each_entry(stmt, &ctx->stmt_list, list) {
628 if (stmt->type != STMT_LABEL)
630 stmt->u.label.name = xmalloc(20);
631 snprintf(stmt->u.label.name, 20, "L%u", namecnt);
636 static void emit_asm(struct disassembler_context *ctx)
638 struct statement *stmt;
642 err = open_output_file();
646 fprintf(outfile, "%%arch %u\n\n", ctx->arch);
647 list_for_each_entry(stmt, &ctx->stmt_list, list) {
648 switch (stmt->type) {
650 fprintf(outfile, "\t%s", stmt->u.insn.name);
652 for (i = 0; i < ARRAY_SIZE(stmt->u.insn.operands); i++) {
653 if (stmt->u.insn.is_labelref == i) {
654 fprintf(outfile, ", %s",
655 stmt->u.insn.labelref->u.label.name);
657 if (!stmt->u.insn.operands[i])
660 fprintf(outfile, "\t");
662 fprintf(outfile, ", ");
664 fprintf(outfile, "%s",
665 stmt->u.insn.operands[i]);
667 fprintf(outfile, "\n");
670 fprintf(outfile, "%s:\n", stmt->u.label.name);
678 static int read_input(struct disassembler_context *ctx)
680 size_t size = 0, pos = 0;
682 struct bin_instruction *code = NULL;
683 unsigned char tmp[sizeof(uint64_t)];
685 struct fw_header hdr;
688 err = open_input_file();
692 ret = fread(&hdr, 1, sizeof(hdr), infile);
693 if (ret != sizeof(hdr)) {
694 fprintf(stderr, "Corrupt input file (not fwcutter output)\n");
697 if (hdr.type != FW_TYPE_UCODE) {
698 fprintf(stderr, "Corrupt input file. Not a microcode image.\n");
701 if (hdr.ver != FW_HDR_VER) {
702 fprintf(stderr, "Invalid input file header version.\n");
709 code = xrealloc(code, size * sizeof(struct bin_instruction));
711 ret = fread(tmp, 1, sizeof(uint64_t), infile);
714 if (ret != sizeof(uint64_t)) {
715 fprintf(stderr, "Corrupt input file (not 8 byte aligned)\n");
720 codeword |= ((uint64_t)tmp[0]) << 56;
721 codeword |= ((uint64_t)tmp[1]) << 48;
722 codeword |= ((uint64_t)tmp[2]) << 40;
723 codeword |= ((uint64_t)tmp[3]) << 32;
724 codeword |= ((uint64_t)tmp[4]) << 24;
725 codeword |= ((uint64_t)tmp[5]) << 16;
726 codeword |= ((uint64_t)tmp[6]) << 8;
727 codeword |= ((uint64_t)tmp[7]);
729 code[pos].opcode = (codeword >> 4) & 0xFFF;
730 code[pos].operands[0] = (codeword & 0xF) << 8;
731 code[pos].operands[0] |= (codeword >> 56) & 0xFF;
732 code[pos].operands[1] = (codeword >> 44) & 0xFFF;
733 code[pos].operands[2] = (codeword >> 32) & 0xFFF;
753 static void disassemble(void)
755 struct disassembler_context ctx;
758 memset(&ctx, 0, sizeof(ctx));
759 INIT_LIST_HEAD(&ctx.stmt_list);
760 ctx.arch = cmdargs.arch;
762 err = read_input(&ctx);
765 disasm_opcodes(&ctx);
766 resolve_labels(&ctx);
770 int main(int argc, char **argv)
774 err = parse_args(argc, argv);
784 /* Lazyman simply leaks all allocated memory. */