X-Git-Url: https://jxself.org/git/?p=b43-tools.git;a=blobdiff_plain;f=fwcutter%2Ffwcutter.c;h=294502b8394ba9f06cbab3ef2e284f53fd782750;hp=20337589192761ae17b351f9bbd4d488d242f85e;hb=HEAD;hpb=c151c2f2d6f9c660294a25dd7e2d7bd01b5e0a6d diff --git a/fwcutter/fwcutter.c b/fwcutter/fwcutter.c index 2033758..294502b 100644 --- a/fwcutter/fwcutter.c +++ b/fwcutter/fwcutter.c @@ -2,7 +2,7 @@ * firmware cutter for broadcom 43xx wireless driver files * * Copyright (c) 2005 Martin Langer , - * 2005-2007 Michael Buesch + * 2005-2014 Michael Buesch * 2005 Alex Beregszaszi * 2007 Johannes Berg * @@ -40,6 +40,8 @@ #if defined(__DragonFly__) || defined(__FreeBSD__) #include +#elif defined(__APPLE__) +#include #else #include #endif @@ -101,6 +103,25 @@ static be32_t to_be32(uint32_t v) return (be32_t)from_be32((be32_t)v); } +/* Convert a Little-Endian 32bit integer to CPU-endian */ +static uint32_t from_le32(le32_t v) +{ + uint32_t ret = 0; + + ret |= (uint32_t)(((uint8_t *)&v)[0]); + ret |= (uint32_t)(((uint8_t *)&v)[1]) << 8; + ret |= (uint32_t)(((uint8_t *)&v)[2]) << 16; + ret |= (uint32_t)(((uint8_t *)&v)[3]) << 24; + + return ret; +} + +/* Convert a CPU-endian 32bit integer to Little-Endian */ +static le32_t to_le32(uint32_t v) +{ + return (le32_t)from_le32((le32_t)v); +} + /* tiny disassembler */ static void print_ucode_version(struct insn *insn) { @@ -226,6 +247,27 @@ static void swap_endianness_iv(struct iv *iv) iv->val = bswap_32(iv->val); } +static uint8_t *read_object(FILE *f, const struct extract *extract) +{ + uint8_t *buf; + + if (fseek(f, extract->offset, SEEK_SET)) { + perror("failed to seek on file"); + exit(2); + } + + buf = malloc(extract->length); + if (!buf) { + perror("failed to allocate buffer"); + exit(3); + } + if (fread(buf, 1, extract->length, f) != extract->length) { + perror("failed to read complete data"); + exit(3); + } + return buf; +} + static void build_ivs(struct b43_iv **_out, size_t *_out_size, struct iv *in, size_t in_size, struct fw_header *hdr, @@ -328,8 +370,8 @@ static void write_file(const char *name, uint8_t *buf, uint32_t len, fclose(f); } -static void extract_or_identify(FILE *f, const struct extract *extract, - uint32_t flags) +static void extract_or_identify(FILE *f, const char *dir, + const struct extract *extract, uint32_t flags) { uint8_t *buf; size_t data_length; @@ -339,20 +381,11 @@ static void extract_or_identify(FILE *f, const struct extract *extract, memset(&hdr, 0, sizeof(hdr)); hdr.ver = FW_HDR_VER; - if (fseek(f, extract->offset, SEEK_SET)) { - perror("failed to seek on file"); - exit(2); - } + printf("%s %s/%s.fw\n", + cmdargs.mode == FWCM_IDENTIFY ? "Contains" : "Extracting", + dir, extract->name); - buf = malloc(extract->length); - if (!buf) { - perror("failed to allocate buffer"); - exit(3); - } - if (fread(buf, 1, extract->length, f) != extract->length) { - perror("failed to read complete data"); - exit(3); - } + buf = read_object(f, extract); switch (extract->type) { case EXT_UCODE_3: @@ -390,12 +423,217 @@ static void extract_or_identify(FILE *f, const struct extract *extract, exit(255); } - if (cmdargs.mode == FWCM_EXTRACT) + if (cmdargs.mode == FWCM_EXTRACT_B43) write_file(extract->name, buf, data_length, &hdr, flags); free(buf); } +static int brcmsmac_name_to_idx(const char *name) +{ + if (strcmp("lcn0bsinitvals24", name) == 0) { + return D11LCN0BSINITVALS24; + } else if (strcmp("lcn0initvals24", name) == 0) { + return D11LCN0INITVALS24; + } else if (strcmp("lcn1bsinitvals24", name) == 0) { + return D11LCN1BSINITVALS24; + } else if (strcmp("lcn1initvals24", name) == 0) { + return D11LCN1INITVALS24; + } else if (strcmp("lcn2bsinitvals24", name) == 0) { + return D11LCN2BSINITVALS24; + } else if (strcmp("lcn2initvals24", name) == 0) { + return D11LCN2INITVALS24; + } else if (strcmp("n0absinitvals16", name) == 0) { + return D11N0ABSINITVALS16; + } else if (strcmp("n0bsinitvals16", name) == 0) { + return D11N0BSINITVALS16; + } else if (strcmp("n0initvals16", name) == 0) { + return D11N0INITVALS16; + } else if (strcmp("ucode16_mimo", name) == 0) { + return D11UCODE_OVERSIGHT16_MIMO; + } else if (strcmp("ucode24_lcn", name) == 0) { + return D11UCODE_OVERSIGHT24_LCN; + } + return 0; +} + +static int brcmsmac_name_to_size_idx(const char *name) +{ + if (strcmp("ucode16_mimo", name) == 0) { + return D11UCODE_OVERSIGHT16_MIMOSZ; + } else if (strcmp("ucode24_lcn", name) == 0) { + return D11UCODE_OVERSIGHT24_LCNSZ; + } + return 0; +} + +static void brcmsmac_clear_file(void) +{ + FILE *f; + char nbuf[4096]; + int r; + + r = snprintf(nbuf, sizeof(nbuf), + "%s/brcm", cmdargs.target_dir); + if (r >= sizeof(nbuf)) { + fprintf(stderr, "name too long"); + exit(2); + } + + r = mkdir(nbuf, 0770); + if (r && errno != EEXIST) { + perror("failed to create output directory"); + exit(2); + } + + r = snprintf(nbuf, sizeof(nbuf), + "%s/brcm/bcm43xx-0.fw", cmdargs.target_dir); + if (r >= sizeof(nbuf)) { + fprintf(stderr, "name too long"); + exit(2); + } + f = fopen(nbuf, "w"); + if (!f) { + perror("failed to open data file"); + exit(2); + } + fclose(f); + + r = snprintf(nbuf, sizeof(nbuf), + "%s/brcm/bcm43xx_hdr-0.fw", cmdargs.target_dir); + if (r >= sizeof(nbuf)) { + fprintf(stderr, "name too long"); + exit(2); + } + f = fopen(nbuf, "w"); + fclose(f); +} + +static void brcmsmac_write_file(int idx, uint8_t *buf, uint32_t len) +{ + FILE *f; + FILE *h; + char nbuf[4096]; + int r; + int offset; + struct firmware_hdr fw_hdr; + + r = snprintf(nbuf, sizeof(nbuf), + "%s/brcm/bcm43xx-0.fw", cmdargs.target_dir); + if (r >= sizeof(nbuf)) { + fprintf(stderr, "name too long"); + exit(2); + } + f = fopen(nbuf, "a"); + if (!f) { + perror("failed to open data file"); + exit(2); + } + fseek(f, 0L, SEEK_END); + + r = snprintf(nbuf, sizeof(nbuf), + "%s/brcm/bcm43xx_hdr-0.fw", cmdargs.target_dir); + if (r >= sizeof(nbuf)) { + fprintf(stderr, "name too long"); + exit(2); + } + h = fopen(nbuf, "a"); + if (!h) { + perror("failed to open header file"); + exit(2); + } + fseek(h, 0L, SEEK_END); + + offset = ftell(f); + + fw_hdr.offset = to_le32(offset); + fw_hdr.len = to_le32(len); + fw_hdr.idx = to_le32(idx); + + if (fwrite(&fw_hdr, sizeof(fw_hdr), 1, h) != 1) { + perror("failed to write file"); + exit(2); + } + fclose(h); + if (fwrite(buf, 1, len, f) != len) { + perror("failed to write file"); + exit(2); + } + fclose(f); +} + +static void brcmsmac_add_dummy_entries(void) +{ + uint8_t buf[4] = {0}; + + brcmsmac_write_file(D11N0ABSINITVALS16, buf, 4); + brcmsmac_write_file(D11UCODE_OVERSIGHT_BOMMAJOR, buf, 4); + brcmsmac_write_file(D11UCODE_OVERSIGHT_BOMMINOR, buf, 4); +} + +static void brcmsmac_extract(FILE *f, const struct extract *extract, + uint32_t flags) +{ + uint8_t *buf; + size_t data_length; + int ucode_rev = 0; + int brcmsmac_idx = 0; + be32_t size; + + + brcmsmac_idx = brcmsmac_name_to_idx(extract->name); + if (!brcmsmac_idx) + return; + printf("%s %s\n", + cmdargs.mode == FWCM_IDENTIFY ? "Contains" : "Extracting", + extract->name); + + buf = read_object(f, extract); + + switch (extract->type) { + case EXT_UCODE_3: + ucode_rev += 1; + case EXT_UCODE_2: + ucode_rev += 1; + case EXT_UCODE_1: + ucode_rev += 1; + data_length = extract->length; + if (flags & FW_FLAG_LE) + swap_endianness_ucode(buf, data_length); + analyse_ucode(ucode_rev, buf, data_length); + swap_endianness_ucode(buf, data_length); + size = to_le32(data_length); + break; + case EXT_PCM: + data_length = extract->length; + if (!(flags & FW_FLAG_LE)) + swap_endianness_pcm(buf, data_length); + size = to_le32(data_length); + break; + case EXT_IV: { + data_length = extract->length; + if (!(flags & FW_FLAG_LE)) { + struct iv *in = (struct iv *)buf; + int i; + + for (i = 0; i < data_length / sizeof(struct iv); i++, in++) + swap_endianness_iv(in); + } + size = to_le32(data_length); + break; + } + default: + exit(255); + } + + brcmsmac_write_file(brcmsmac_idx, buf, data_length); + int size_idx = brcmsmac_name_to_size_idx(extract->name); + if (size_idx) + brcmsmac_write_file(size_idx, (uint8_t *)&size, 4); + + free(buf); +} + static void print_banner(void) { printf("b43-fwcutter version " FWCUTTER_VERSION "\n"); @@ -497,6 +735,8 @@ static void print_usage(int argc, char *argv[]) "Allow working on extractable but unsupported drivers\n"); printf(" -l|--list " "List supported driver versions\n"); + printf(" -b|--brcmsmac " + "create firmware for brcmsmac\n"); printf(" -i|--identify " "Only identify the driver file (don't extract)\n"); printf(" -w|--target-dir DIR " @@ -608,6 +848,13 @@ static int parse_args(int argc, char *argv[]) } else if (res == ARG_ERROR) goto out; + res = cmp_arg(argv, &i, "--brcmsmac", "-b", NULL); + if (res == ARG_MATCH) { + cmdargs.mode = FWCM_EXTRACT_BRCMSMAC; + continue; + } else if (res == ARG_ERROR) + goto out; + res = cmp_arg(argv, &i, "--unsupported", NULL, NULL); if (res == ARG_MATCH) { cmdargs.unsupported = 1; @@ -672,13 +919,20 @@ int main(int argc, char *argv[]) else dir = V3_FW_DIRNAME; - extract = file->extract; - while (extract->name) { - printf("%s %s/%s.fw\n", - cmdargs.mode == FWCM_IDENTIFY ? "Contains" : "Extracting", - dir, extract->name); - extract_or_identify(fd, extract, file->flags); - extract++; + if (cmdargs.mode == FWCM_EXTRACT_BRCMSMAC) { + brcmsmac_clear_file(); + extract = file->extract; + while (extract->name) { + brcmsmac_extract(fd, extract, file->flags); + extract++; + } + brcmsmac_add_dummy_entries(); + } else { + extract = file->extract; + while (extract->name) { + extract_or_identify(fd, dir, extract, file->flags); + extract++; + } } err = 0;