Disassembler: Fixes for r15 architecture
authorMichael Buesch <mb@bu3sch.de>
Sun, 19 Sep 2010 14:56:34 +0000 (16:56 +0200)
committerMichael Buesch <mb@bu3sch.de>
Sun, 19 Sep 2010 14:56:34 +0000 (16:56 +0200)
Signed-off-by: Michael Buesch <mb@bu3sch.de>
disassembler/args.c
disassembler/args.h
disassembler/main.c

index 67ba2fc7a4d7d92706d1b1c2772bfd24345a09e2..3663c59f1aabb183bfed7cadb2baa0802ea69999 100644 (file)
@@ -26,7 +26,7 @@ int _debug;
 
 struct cmdline_args cmdargs = {
        .arch = 5,              /* Default to v5 architecture. */
-       .no_header = 0,         /* Input file does not have a header. */
+       .informat = FMT_B43,    /* Input file format */
        .print_addresses = 0,   /* Print the code addresses in the output. */
 };
 
@@ -96,15 +96,16 @@ static int cmp_arg(char **argv, int *pos,
        return err;
 }
 
-static void usage(int argc, char **argv)
+static void usage(FILE *fd, int argc, char **argv)
 {
-       fprintf(stderr, "Usage: %s INPUT_FILE OUTPUT_FILE [OPTIONS]\n", argv[0]);
-       fprintf(stderr, "  -a|--arch ARCH      The architecture type of the input file\n");
-       fprintf(stderr, "  -h|--help           Print this help\n");
-       fprintf(stderr, "  --nohdr             The input file does not have a header\n");
-       fprintf(stderr, "  --paddr             Print the code addresses\n");
-       fprintf(stderr, "  -d|--debug          Print verbose debugging info\n");
-       fprintf(stderr, "                      Repeat for more verbose debugging\n");
+       fprintf(fd, "Usage: %s INPUT_FILE OUTPUT_FILE [OPTIONS]\n", argv[0]);
+       fprintf(fd, "  -a|--arch ARCH      The architecture type of the input file (5 or 15)\n");
+       fprintf(fd, "  -f|--format FMT     Input file format. FMT may be one of:\n");
+       fprintf(fd, "                      raw-le32, raw-be32, b43\n");
+       fprintf(fd, "  --paddr             Print the code addresses\n");
+       fprintf(fd, "  -d|--debug          Print verbose debugging info\n");
+       fprintf(fd, "                      Repeat for more verbose debugging\n");
+       fprintf(fd, "  -h|--help           Print this help\n");
 }
 
 int parse_args(int argc, char **argv)
@@ -118,10 +119,19 @@ int parse_args(int argc, char **argv)
 
        for (i = 1; i < argc; i++) {
                if ((res = cmp_arg(argv, &i, "--help", "-h", NULL)) == ARG_MATCH) {
-                       usage(argc, argv);
+                       usage(stdout, argc, argv);
                        return 1;
-               } else if ((res = cmp_arg(argv, &i, "--nohdr", NULL, NULL)) == ARG_MATCH) {
-                       cmdargs.no_header = 1;
+               } else if ((res = cmp_arg(argv, &i, "--format", "-f", &param)) == ARG_MATCH) {
+                       if (strcasecmp(param, "raw-le32") == 0)
+                               cmdargs.informat = FMT_RAW_LE32;
+                       else if (strcasecmp(param, "raw-be32") == 0)
+                               cmdargs.informat = FMT_RAW_BE32;
+                       else if (strcasecmp(param, "b43") == 0)
+                               cmdargs.informat = FMT_B43;
+                       else {
+                               fprintf(stderr, "Invalid -f|--format\n");
+                               return -1;
+                       }
                } else if ((res = cmp_arg(argv, &i, "--paddr", NULL, NULL)) == ARG_MATCH) {
                        cmdargs.print_addresses = 1;
                } else if ((res = cmp_arg(argv, &i, "--debug", "-d", NULL)) == ARG_MATCH) {
@@ -131,7 +141,7 @@ int parse_args(int argc, char **argv)
                        char *tail;
 
                        arch = strtol(param, &tail, 0);
-                       if (strlen(tail) || (arch != 5)) {
+                       if (strlen(tail) || (arch != 5 && arch != 15)) {
                                fprintf(stderr, "Unsupported architecture \"%s\"\n",
                                        param);
                                return -1;
@@ -155,7 +165,7 @@ int parse_args(int argc, char **argv)
 
        return 0;
 out_usage:
-       usage(argc, argv);
+       usage(stderr, argc, argv);
        return -1;
 }
 
index 8dc69f2761efc9b8d52ffc872dc4c07a6673894a..0cb372cc0cb54c7ac94f75a4bcbb3cb1638a529c 100644 (file)
@@ -1,9 +1,15 @@
 #ifndef B43_DASM_ARGS_H_
 #define B43_DASM_ARGS_H_
 
+enum fwformat {
+       FMT_RAW_LE32,   /* Raw microcode. No headers. 32bit little endian chunks. */
+       FMT_RAW_BE32,   /* Raw microcode. No headers. 32bit big endian chunks. */
+       FMT_B43,        /* b43/b43legacy headers. */
+};
+
 struct cmdline_args {
        unsigned int arch;
-       int no_header;
+       enum fwformat informat;
        int print_addresses;
 };
 
index dbd2b5f066aa1a1bbbeb701ec4247b5ffd0ecac8..b3ba68612f8bf7441d543b6b58f81dd791f2d1c2 100644 (file)
@@ -82,8 +82,8 @@ static const char * disasm_mem_operand(unsigned int operand)
 {
        char *ret;
 
-       ret = xmalloc(8);
-       snprintf(ret, 8, "[0x%03X]", operand);
+       ret = xmalloc(9);
+       snprintf(ret, 9, "[0x%X]", operand);
 
        return ret;
 }
@@ -102,14 +102,29 @@ static const char * disasm_indirect_mem_operand(unsigned int operand)
 static const char * disasm_imm_operand(unsigned int operand)
 {
        char *ret;
+       unsigned int signmask;
+       unsigned int mask;
+
+       switch (cmdargs.arch) {
+       case 5:
+               signmask = (1 << 9);
+               mask = 0x3FF;
+               break;
+       case 15:
+               signmask = (1 << 10);
+               mask = 0x7FF;
+               break;
+       default:
+               fprintf(stderr, "Internal error: disasm_imm_operand invalid arch\n");
+               exit(1);
+       }
 
-       operand &= ~0xC00;
+       operand &= mask;
 
        ret = xmalloc(7);
-       if (operand & (1 << 9))
-               snprintf(ret, 7, "0x%04X", (operand | 0xFC00));
-       else
-               snprintf(ret, 7, "0x%03X", operand);
+       if (operand & signmask)
+               operand = (operand | (~mask & 0xFFFF));
+       snprintf(ret, 7, "0x%X", operand);
 
        return ret;
 }
@@ -117,9 +132,22 @@ static const char * disasm_imm_operand(unsigned int operand)
 static const char * disasm_spr_operand(unsigned int operand)
 {
        char *ret;
+       unsigned int mask;
 
-       ret = xmalloc(7);
-       snprintf(ret, 7, "spr%03X", (operand & 0x1FF));
+       switch (cmdargs.arch) {
+       case 5:
+               mask = 0x1FF;
+               break;
+       case 15:
+               mask = 0x7FF;
+               break;
+       default:
+               fprintf(stderr, "Internal error: disasm_spr_operand invalid arch\n");
+               exit(1);
+       }
+
+       ret = xmalloc(8);
+       snprintf(ret, 8, "spr%X", (operand & mask));
 
        return ret;
 }
@@ -127,19 +155,22 @@ static const char * disasm_spr_operand(unsigned int operand)
 static const char * disasm_gpr_operand(unsigned int operand)
 {
        char *ret;
+       unsigned int mask;
 
-       ret = xmalloc(4);
-       snprintf(ret, 4, "r%u", (operand & 0x3F));
-
-       return ret;
-}
-
-static const char * disasm_offr_operand(unsigned int operand)
-{
-       char *ret;
+       switch (cmdargs.arch) {
+       case 5:
+               mask = 0x3F;
+               break;
+       case 15:
+               mask = 0x7F;
+               break;
+       default:
+               fprintf(stderr, "Internal error: disasm_gpr_operand invalid arch\n");
+               exit(1);
+       }
 
        ret = xmalloc(5);
-       snprintf(ret, 5, "off%u", (operand & 0x7));
+       snprintf(ret, 5, "r%u", (operand & mask));
 
        return ret;
 }
@@ -154,24 +185,46 @@ static void disasm_std_operand(struct statement *stmt,
        if (forceraw)
                goto raw;
 
-       if (!(operand & 0x800)) {
-               stmt->u.insn.operands[out_idx] = disasm_mem_operand(operand);
-               return;
-       } else if ((operand & 0xC00) == 0xC00) { 
-               stmt->u.insn.operands[out_idx] = disasm_imm_operand(operand);
-               return;
-       } else if ((operand & 0xFC0) == 0xBC0) {
-               stmt->u.insn.operands[out_idx] = disasm_gpr_operand(operand);
-               return;
-       } else if ((operand & 0xE00) == 0x800) {
-               stmt->u.insn.operands[out_idx] = disasm_spr_operand(operand);
-               return;
-       } else if ((operand & 0xFF8) == 0x860) {
-               stmt->u.insn.operands[out_idx] = disasm_offr_operand(operand);
-               return;
-       } else if ((operand & 0xE00) == 0xA00) {
-               stmt->u.insn.operands[out_idx] = disasm_indirect_mem_operand(operand);
-               return;
+       switch (cmdargs.arch) {
+       case 5:
+               if (!(operand & 0x800)) {
+                       stmt->u.insn.operands[out_idx] = disasm_mem_operand(operand);
+                       return;
+               } else if ((operand & 0xC00) == 0xC00) { 
+                       stmt->u.insn.operands[out_idx] = disasm_imm_operand(operand);
+                       return;
+               } else if ((operand & 0xFC0) == 0xBC0) {
+                       stmt->u.insn.operands[out_idx] = disasm_gpr_operand(operand);
+                       return;
+               } else if ((operand & 0xE00) == 0x800) {
+                       stmt->u.insn.operands[out_idx] = disasm_spr_operand(operand);
+                       return;
+               } else if ((operand & 0xE00) == 0xA00) {
+                       stmt->u.insn.operands[out_idx] = disasm_indirect_mem_operand(operand);
+                       return;
+               }
+               break;
+       case 15:
+               if (!(operand & 0x1000)) {
+                       stmt->u.insn.operands[out_idx] = disasm_mem_operand(operand);
+                       return;
+               } else if ((operand & 0x1800) == 0x1800) { 
+                       stmt->u.insn.operands[out_idx] = disasm_imm_operand(operand);
+                       return;
+               } else if ((operand & 0x1F80) == 0x1780) {
+                       stmt->u.insn.operands[out_idx] = disasm_gpr_operand(operand);
+                       return;
+               } else if ((operand & 0x1C00) == 0x1000) {
+                       stmt->u.insn.operands[out_idx] = disasm_spr_operand(operand);
+                       return;
+               } else if ((operand & 0x1C00) == 0x1400) {
+                       stmt->u.insn.operands[out_idx] = disasm_indirect_mem_operand(operand);
+                       return;
+               }
+               break;
+       default:
+               fprintf(stderr, "Internal error: disasm_std_operand invalid arch\n");
+               exit(1);
        }
 raw:
        stmt->u.insn.operands[out_idx] = gen_raw_code(operand);
@@ -386,8 +439,10 @@ static void disasm_constant_opcodes(struct disassembler_context *ctx,
        case 0x002: {
                char *str;
 
+               //FIXME: Broken for r15
                stmt->u.insn.name = "call";
                stmt->u.insn.is_labelref = 1;
+//printf("CALL 0x%X 0x%X 0x%X\n", stmt->u.insn.bin->operands[0], stmt->u.insn.bin->operands[1], stmt->u.insn.bin->operands[2]);
                stmt->u.insn.labeladdr = stmt->u.insn.bin->operands[2];
                str = xmalloc(4);
                snprintf(str, 4, "lr%u", stmt->u.insn.bin->operands[0]);
@@ -407,10 +462,22 @@ static void disasm_constant_opcodes(struct disassembler_context *ctx,
                break;
        }
        case 0x1E0: {
-               unsigned int flags;
+               unsigned int flags, mask;
+
+               switch (cmdargs.arch) {
+               case 5:
+                       mask = 0x3FF;
+                       break;
+               case 15:
+                       mask = 0x7FF;
+                       break;
+               default:
+                       fprintf(stderr, "Internal error: TKIP invalid arch\n");
+                       exit(1);
+               }
 
                flags = stmt->u.insn.bin->operands[1];
-               switch (flags & ~0xC00) {
+               switch (flags & mask) {
                case 0x1:
                        stmt->u.insn.name = "tkiph";
                        break;
@@ -433,17 +500,30 @@ static void disasm_constant_opcodes(struct disassembler_context *ctx,
                break;
        }
        case 0x001: {
+               unsigned int mask;
+
                stmt->u.insn.name = "nap";
-               if (stmt->u.insn.bin->operands[0] != 0xBC0) {
-                       fprintf(stderr, "NAP: invalid first argument 0x%03X\n",
+               switch (cmdargs.arch) {
+               case 5:
+                       mask = 0xBC0;
+                       break;
+               case 15:
+                       mask = 0x1780;
+                       break;
+               default:
+                       fprintf(stderr, "Internal error: NAP invalid arch\n");
+                       exit(1);
+               }
+               if (stmt->u.insn.bin->operands[0] != mask) {
+                       fprintf(stderr, "NAP: invalid first argument 0x%04X\n",
                                stmt->u.insn.bin->operands[0]);
                }
-               if (stmt->u.insn.bin->operands[1] != 0xBC0) {
-                       fprintf(stderr, "NAP: invalid second argument 0x%03X\n",
+               if (stmt->u.insn.bin->operands[1] != mask) {
+                       fprintf(stderr, "NAP: invalid second argument 0x%04X\n",
                                stmt->u.insn.bin->operands[1]);
                }
-               if (stmt->u.insn.bin->operands[2] != 0x000) {
-                       fprintf(stderr, "NAP: invalid third argument 0x%03X\n",
+               if (stmt->u.insn.bin->operands[2] != 0) {
+                       fprintf(stderr, "NAP: invalid third argument 0x%04X\n",
                                stmt->u.insn.bin->operands[2]);
                }
                break;
@@ -693,7 +773,12 @@ static int read_input(struct disassembler_context *ctx)
        if (err)
                goto error;
 
-       if (!cmdargs.no_header) {
+       switch (cmdargs.informat) {
+       case FMT_RAW_LE32:
+       case FMT_RAW_BE32:
+               /* Nothing */
+               break;
+       case FMT_B43:
                ret = fread(&hdr, 1, sizeof(hdr), infile);
                if (ret != sizeof(hdr)) {
                        fprintf(stderr, "Corrupt input file (not fwcutter output)\n");
@@ -707,6 +792,7 @@ static int read_input(struct disassembler_context *ctx)
                        fprintf(stderr, "Invalid input file header version.\n");
                        goto err_close;
                }
+               break;
        }
 
        while (1) {
@@ -722,21 +808,62 @@ static int read_input(struct disassembler_context *ctx)
                        goto err_free_code;
                }
 
-               codeword = 0;
-               codeword |= ((uint64_t)tmp[0]) << 56;
-               codeword |= ((uint64_t)tmp[1]) << 48;
-               codeword |= ((uint64_t)tmp[2]) << 40;
-               codeword |= ((uint64_t)tmp[3]) << 32;
-               codeword |= ((uint64_t)tmp[4]) << 24;
-               codeword |= ((uint64_t)tmp[5]) << 16;
-               codeword |= ((uint64_t)tmp[6]) << 8;
-               codeword |= ((uint64_t)tmp[7]);
-
-               code[pos].opcode = (codeword >> 4) & 0xFFF;
-               code[pos].operands[0] = (codeword & 0xF) << 8;
-               code[pos].operands[0] |= (codeword >> 56) & 0xFF;
-               code[pos].operands[1] = (codeword >> 44) & 0xFFF;
-               code[pos].operands[2] = (codeword >> 32) & 0xFFF;
+               switch (cmdargs.informat) {
+               case FMT_B43:
+               case FMT_RAW_BE32:
+                       codeword = 0;
+                       codeword |= ((uint64_t)tmp[0]) << 56;
+                       codeword |= ((uint64_t)tmp[1]) << 48;
+                       codeword |= ((uint64_t)tmp[2]) << 40;
+                       codeword |= ((uint64_t)tmp[3]) << 32;
+                       codeword |= ((uint64_t)tmp[4]) << 24;
+                       codeword |= ((uint64_t)tmp[5]) << 16;
+                       codeword |= ((uint64_t)tmp[6]) << 8;
+                       codeword |= ((uint64_t)tmp[7]);
+                       codeword = ((codeword & (uint64_t)0xFFFFFFFF00000000ULL) >> 32) |
+                                  ((codeword & (uint64_t)0x00000000FFFFFFFFULL) << 32);
+                       break;
+               case FMT_RAW_LE32:
+                       codeword = 0;
+                       codeword |= ((uint64_t)tmp[7]) << 56;
+                       codeword |= ((uint64_t)tmp[6]) << 48;
+                       codeword |= ((uint64_t)tmp[5]) << 40;
+                       codeword |= ((uint64_t)tmp[4]) << 32;
+                       codeword |= ((uint64_t)tmp[3]) << 24;
+                       codeword |= ((uint64_t)tmp[2]) << 16;
+                       codeword |= ((uint64_t)tmp[1]) << 8;
+                       codeword |= ((uint64_t)tmp[0]);
+                       break;
+               }
+
+               switch (cmdargs.arch) {
+               case 5:
+                       if (codeword >> 48) {
+                               fprintf(stderr, "Instruction format error at 0x%X (upper not clear). "
+                                       "Wrong input format or architecture?\n", (unsigned int)pos);
+                               goto err_free_code;
+                       }
+                       code[pos].opcode = (codeword >> 36) & 0xFFF;
+                       code[pos].operands[2] = codeword & 0xFFF;
+                       code[pos].operands[1] = (codeword >> 12) & 0xFFF;
+                       code[pos].operands[0] = (codeword >> 24) & 0xFFF;
+                       break;
+               case 15:
+                       if (codeword >> 51) {
+                               fprintf(stderr, "Instruction format error at 0x%X (upper not clear). "
+                                       "Wrong input format or architecture?\n", (unsigned int)pos);
+                               goto err_free_code;
+                       }
+                       code[pos].opcode = (codeword >> 39) & 0xFFF;
+                       code[pos].operands[2] = codeword & 0x1FFF;
+                       code[pos].operands[1] = (codeword >> 13) & 0x1FFF;
+                       code[pos].operands[0] = (codeword >> 26) & 0x1FFF;
+                       break;
+               default:
+                       fprintf(stderr, "Internal error: read_input unknown arch %u\n",
+                               cmdargs.arch);
+                       goto err_free_code;
+               }
 
                pos++;
        }