From 77d205076542510222c6e8359bb2647b0d4e0873 Mon Sep 17 00:00:00 2001 From: David Kilroy Date: Sun, 26 Oct 2008 14:22:02 +0000 Subject: [PATCH] dump_fw and hfwget posted Sep 2007 --- README.dump_fw | 42 +++++++-- dump_fw.c | 229 +++++++++++++++++++++++++++++++++++++++-------- dump_fw.mk | 31 +++++-- hfwget.c | 278 ++++++++++++++++++++++++++++++++++++++++++++++++++------- 4 files changed, 497 insertions(+), 83 deletions(-) diff --git a/README.dump_fw b/README.dump_fw index f752eb0..8778f6f 100644 --- a/README.dump_fw +++ b/README.dump_fw @@ -19,15 +19,47 @@ To use the programs just do: Which will produce root_ap.fw and root_sta.fw, with root replaced by whatever you specified. -Enjoy, +If you want to use the wl_lkm_714 source tree instead, you can. See +instructions in dump_fw.mk -Dave Kilroy -June 2007. +KNOWN BUGS +---------- + +1. Compatibility information offset present, but data not output. + + +hfwget +------ + +Program to dump Lucent tertiary and Variant 2 FW images from windows +drivers (WLLUC48.SYS, WLLUC48B.SYS). Should work with Agere +(WLAGS48B.SYS) and Dell (WLDEL48B.SYS) drivers, and probably +others. The firmware images are intended to be used with the +orinoco_cs and hermes_dld Linux driver. + +Compiled when building dump_fw above. Alternatively, extract into any +directory and run: +make -f dump_fw.mk hfwget + +This will generate hfwget which will dump the firmware images it can +locate in the specified file. Just do: + +./hfwget + +Which will output any of: +R02xxxxx.hfw Variant 2 firmware for RAM download +T02xxxxx.hfw Tertiary firmware +guess000.hfw Variant 2 firmware from Dell/old Lucent drivers. KNOWN BUGS ---------- +1. Will only work on a little endian machine. -1. Will only work on a little endian machine. Various numbers come out -backwards on a big endian machine. 2. Compatibility information offset present, but data not output. + + +Enjoy, + +Dave Kilroy +September 2007. diff --git a/dump_fw.c b/dump_fw.c index d0254dd..65c74a4 100644 --- a/dump_fw.c +++ b/dump_fw.c @@ -51,7 +51,6 @@ * Apart from the header, the output format is compatible with the * spectrum_cs image. The header is arbitrary. * - * TODO: ensure the output is LE, rather than relying on x86 byte orderring */ #include @@ -63,21 +62,119 @@ #define STA_SUFFIX "_sta.fw" #define VERSION "HFW000" +/* 0xAABB to 0xBBAA */ +#define swap_bytes_16(value) \ + ((((value) >> 8) & 0xFF) | \ + (((value) & 0xFF) << 8)) +/* 0xAABBCCDD to 0xDDCCBBAA */ +#define reverse_bytes_32(value) \ + ((((value) >> 24) & 0x0000FF) | \ + (((value) >> 8) & 0x00FF00) | \ + (((value) << 8) & 0xFF0000) | \ + (((value) & 0xFF) << 24)) +/* 0xAABBCCDD to 0xBBAADDCC */ +#define swap_bytes_32(value) \ + ((((value) >> 8) & 0x00FF00FF) | \ + (((value) << 8) & 0xFF00FF00)) +/* 0xAABBCCDD to 0xCCDDAABB */ +#define swap_words_32(value) \ + ((((value) >> 16) & 0x0000FFFF) | \ + (((value) << 16) & 0xFFFF0000)) + +/* address 0 1 2 3 */ +/* Pure LE stores 0x12345678 as 0x78 0x56 0x34 0x12 */ +/* Pure BE stores 0x12345678 as 0x12 0x34 0x56 0x78 */ +/* BEW+LEB stores 0x12345678 as 0x34 0x12 0x78 0x56 */ +/* LEW+BEB stores 0x12345678 as 0x56 0x78 0x12 0x34 */ +int host_bytes_in_word_be = 0; +int host_words_in_dword_be = 0; + +#define host_to_le16(value) \ + host_bytes_in_word_be ? swap_bytes_16(value) : (value); +#define host_to_le32(value) \ + host_words_in_dword_be ? \ + (host_bytes_in_word_be ? reverse_bytes_32(value) \ + : swap_bytes_32(value)) : \ + (host_bytes_in_word_be ? swap_words_32(value) : (value)); + +#define le16_to_host(value) \ + host_bytes_in_word_be ? swap_bytes_16(value) : (value); +#define le32_to_host(value) \ + host_words_in_dword_be ? \ + (host_bytes_in_word_be ? reverse_bytes_32(value) \ + : swap_bytes_32(value)) : \ + (host_bytes_in_word_be ? swap_words_32(value) : (value)); + +typedef unsigned int u32; +typedef unsigned short u16; +typedef unsigned char u8; + +/* Checking endianess at runtime because performance isn't an issue, + * and I'd rather not add a configure step since this is slotting into the + * Agere source code. */ +void check_endianess(void) { + union { + u32 dword; + u16 word[2]; + u8 byte[4]; + } data; + + data.dword = 0x12345678; + if (data.word[0] == 0x1234) { + host_words_in_dword_be = 1; + } + else if (data.word[0] == 0x5678) { + host_words_in_dword_be = 0; + } else { + fprintf(stderr, "Can't determine endianess of host!\n"); + exit(1); + } + + data.word[0] = 0x1234; + if (data.byte[0] == 0x12) { + host_bytes_in_word_be = 1; + } else if (data.byte[0] == 0x34) { + host_bytes_in_word_be = 0; + } else { + fprintf(stderr, "Can't determine endianess of host!\n"); + } + + if (host_bytes_in_word_be == host_words_in_dword_be) { + fprintf (stdout, "Detected %s host\n", + host_bytes_in_word_be ? "big endian" : "little endian"); + } else { + fprintf (stdout, "Detected host with mixed endianess\n"); + } + return; +} size_t count_blocks(memimage *image) { - CFG_PROG_STRCT *p = image->codep; +#if __wl_lkm < 718 +# define MEMBLOCK memblock +# define BLKSIZE p->size +# define IF_HAVE_SEGMENT +#else +# define MEMBLOCK CFG_PROG_STRCT +# define BLKSIZE p->len +# define IF_HAVE_SEGMENT if (p->segment_size) +#endif + + MEMBLOCK *p = image->codep; size_t count = 0; - while (p->len) + while (BLKSIZE) { /* Ignore zero data segments which will not be written */ - if (p->segment_size) + IF_HAVE_SEGMENT + { count++; + } p++; } return count; } + size_t count_pdr(plugrecord *r) { size_t count = 0; @@ -94,67 +191,105 @@ size_t count_pdr(plugrecord *r) size_t acc_block_size(memimage *image) { - CFG_PROG_STRCT *p = image->codep; +#if __wl_lkm < 718 +# define MEMBLOCK memblock +# define BLKSIZE p->size +# define SEGSIZE p->size +# define IF_HAVE_SEGMENT +#else +# define MEMBLOCK CFG_PROG_STRCT +# define BLKSIZE p->len +# define SEGSIZE p->segment_size +# define IF_HAVE_SEGMENT if (p->segment_size) +#endif + + MEMBLOCK *p = image->codep; size_t len = 0; - while (p->len) + while (BLKSIZE) { - if (p->segment_size) - len += p->segment_size; + /* Ignore zero data segments which will not be written */ + IF_HAVE_SEGMENT + { + len += SEGSIZE; + } p++; } return len; } -typedef unsigned int u32; -typedef unsigned short u16; - void dump_blocks(FILE* f, memimage *image) { - CFG_PROG_STRCT *p = image->codep; - u32 end_addr = 0xFFFFFFFFu; /* Agree with spectrum BLOCK_END */ - u16 end_size = 0u; /* a sensible size that won't screw the reader */ - while (p->len) +#if __wl_lkm < 718 +# define MEMBLOCK memblock +# define BLKSIZE p->size +# define SEGSIZE p->size +# define NICADDR p->addr +# define SEGDATA &(p->data[4]) /* Avoid initial CRC */ +# define IF_HAVE_SEGMENT +#else +# define MEMBLOCK CFG_PROG_STRCT +# define BLKSIZE p->len +# define SEGSIZE p->segment_size +# define NICADDR p->nic_addr +# define SEGDATA p->host_addr +# define IF_HAVE_SEGMENT if (p->segment_size) +#endif + + MEMBLOCK *p = image->codep; + u8 block_hdr[sizeof(NICADDR) + sizeof(SEGSIZE)]; + u32 *addr = (u32 *) &block_hdr[0]; + u16 *size = (u16 *) &block_hdr[sizeof(NICADDR)]; + + while (BLKSIZE) { - if (p->segment_size) + IF_HAVE_SEGMENT { /* There is data to program in this block */ - fwrite (&p->nic_addr, 1, sizeof(p->nic_addr), f); - fwrite (&p->segment_size, 1, sizeof(p->segment_size), f); - fwrite (p->host_addr, 1, p->segment_size, f); + *addr = host_to_le32(NICADDR); + *size = host_to_le16(SEGSIZE); + fwrite (&block_hdr, 1, sizeof(block_hdr), f); + fwrite (SEGDATA, 1, SEGSIZE, f); } - /* else PROG_STOP, entry point command, or terminating block */ p++; } - fwrite (&end_addr, 1, sizeof(end_addr), f); - fwrite (&end_size, 1, sizeof(end_size), f); + *addr = host_to_le32(0xFFFFFFFFu); /* Agree with spectrum BLOCK_END */ + *size = host_to_le16(0u); + + fwrite (&block_hdr, 1, sizeof(block_hdr), f); return; } void dump_pdr(FILE *f, plugrecord *r) { - u32 end = 0u; + u8 pdr[sizeof(r->code) + sizeof(r->addr) + sizeof(r->len)]; + u32 *code = (u32*) &pdr[0]; + u32 *addr = (u32*) &pdr[sizeof(r->code)]; + u32 *len = (u32*) &pdr[sizeof(r->code) + sizeof(r->addr)]; if (!r) goto terminate; while (r->code) { - fwrite(&r->code, 1, sizeof(r->code), f); - fwrite(&r->addr, 1, sizeof(r->addr), f); - fwrite(&r->len, 1, sizeof(r->len), f); + *code = host_to_le32(r->code); + *addr = host_to_le32(r->addr); + *len = host_to_le32(r->len); + fwrite(&pdr, 1, sizeof(pdr), f); r++; } terminate: /* Terminate the PDR list */ - fwrite(&end, 1, sizeof(end), f); - fwrite(&end, 1, sizeof(end), f); - fwrite(&end, 1, sizeof(end), f); + *code = 0; + *addr = 0; + *len = 0; + fwrite(&pdr, 1, sizeof(pdr), f); return; } void dump_image(FILE* f, memimage *image) { + u32 image_header[6]; u32 blocks = count_blocks(image); u32 blk_offset = 0; /* Immediately after header */ u32 pdr_offset = (acc_block_size(image) + @@ -165,18 +300,32 @@ void dump_image(FILE* f, memimage *image) ((count_pdr(image->priplug) + 1) * sizeof(u32) * 3); u16 headersize = ((sizeof(VERSION)-1) + sizeof(u16) + - (sizeof(u32)*6) + - sizeof(image->signature)); - + (sizeof(u32)*6) +#if __wl_lkm >= 718 + + sizeof(image->signature) +#endif + ); + u32 *ptr = &image_header[0]; fwrite (VERSION, 1, sizeof(VERSION)-1, f); + headersize = host_to_le16(headersize); fwrite (&headersize, 1, sizeof(headersize), f); - fwrite (&image->execution, 1, sizeof(image->execution), f); - fwrite (&blocks, 1, sizeof(blocks), f); - fwrite (&blk_offset, 1, sizeof(blk_offset), f); - fwrite (&pdr_offset, 1, sizeof(pdr_offset), f); - fwrite (&pri_offset, 1, sizeof(pri_offset), f); - fwrite (&cpt_offset, 1, sizeof(cpt_offset), f); + + *ptr = host_to_le32(image->execution); + ptr++; + *ptr = host_to_le32(blocks); + ptr++; + *ptr = host_to_le32(blk_offset); + ptr++; + *ptr = host_to_le32(pdr_offset); + ptr++; + *ptr = host_to_le32(pri_offset); + ptr++; + *ptr = host_to_le32(cpt_offset); + ptr++; + fwrite (&image_header, 1, sizeof(image_header), f); +#if __wl_lkm >= 718 fwrite (&image->signature, 1, sizeof(image->signature), f); +#endif dump_blocks(f, image); dump_pdr(f, image->pdaplug); @@ -207,6 +356,8 @@ int main (int argc, char** argv) return 1; } + check_endianess(); + len = strlen(argv[1]); ap_filename = malloc(len + sizeof(AP_SUFFIX) + 1); if (!ap_filename) @@ -228,6 +379,7 @@ int main (int argc, char** argv) { dump_image(ap_file, &ap); fclose(ap_file); + fprintf (stdout, "Written %s\n", ap_filename); } free(ap_filename); @@ -251,6 +403,7 @@ int main (int argc, char** argv) { dump_image(sta_file, &station); fclose(sta_file); + fprintf (stdout, "Written %s\n", sta_filename); } free(sta_filename); diff --git a/dump_fw.mk b/dump_fw.mk index 83c9587..03da4a8 100644 --- a/dump_fw.mk +++ b/dump_fw.mk @@ -2,11 +2,19 @@ # Makefile for wlags49_cs_xxx # +# NOTE if compiling wl_lkm_714: +# - the firmware files need to be modified to include "mmd.h" instead of "..\hcf\mmd.h" +# - include/hcf/hcfcfg.h line 775 should be commented out +# - select the appropriate DIR_FW and LKM_CFLAGS values below + LIB := ../lib DIR_HCF = hcf DIR_DHF = dhf -DIR_FW = dhf +# 714 firmware is in +#DIR_FW = dhf +# 718 firmware is in +DIR_FW = firmware DIR_CONFIG = include/hcf DIR_WIRELESS = include/wireless @@ -17,28 +25,35 @@ WIRELESS_HEADERS = $(DIR_WIRELESS)/wl_enc.h $(DIR_WIRELESS)/wl_if.h $(DIR_WIR OBJS = dump_fw.o -CFLAGS += -O3 -Wall -Wstrict-prototypes -pipe -DHCF_DLV -CPPFLAGS += +CFLAGS = -O3 -Wall -Wstrict-prototypes -pipe +# CFLAGS for wl_lkm_714 +#LKM_CFLAGS = -D__wl_lkm=714 +# CFLAGS for wl_lkm_718 +LKM_CFLAGS = -DHCF_DLV -D__wl_lkm=718 +CPPFLAGS = CC = gcc -I$(DIR_CONFIG) -I$(DIR_HCF) -I$(DIR_DHF) -H2_OBJS = firmware/ap_h2.o firmware/sta_h2.o +H2_OBJS = $(DIR_FW)/ap_h2.o $(DIR_FW)/sta_h2.o H2_CFLAGS = -DHCF_TYPE=4 -H1_OBJS = firmware/ap_h1.o firmware/sta_h1.o +H1_OBJS = $(DIR_FW)/ap_h1.o $(DIR_FW)/sta_h1.o H1_CFLAGS = -DHCF_TYPE=0 # H1-STAP and H2-STAP are the default targets -all: dump_h1_fw dump_h2_fw +all: dump_h1_fw dump_h2_fw hfwget -dump_h1_fw : CFLAGS+=$(H1_CFLAGS) +dump_h1_fw : CFLAGS+= $(LKM_CFLAGS) $(H1_CFLAGS) dump_h1_fw : $(OBJS) $(H1_OBJS) gcc $(CFLAGS) $^ -o $@ -dump_h2_fw : CFLAGS+=$(H2_CFLAGS) +dump_h2_fw : CFLAGS+= $(LKM_CFLAGS) $(H2_CFLAGS) dump_h2_fw : $(OBJS) $(H2_OBJS) gcc $(CFLAGS) $^ -o $@ +hfwget : hfwget.c + gcc $(CFLAGS) $^ -o $@ + clean : rm $(OBJS) $(H1_OBJS) $(H2_OBJS) dump_h1_fw dump_h2_fw diff --git a/hfwget.c b/hfwget.c index c3f0952..a7a3b4c 100644 --- a/hfwget.c +++ b/hfwget.c @@ -2,6 +2,16 @@ * Hermes AP firmware extractor for Windows drivers (c) 2003 by Mark Smith * This may be distributed freely under the GPL v2 so long as this copyright * notice is included. + * + * Following modifications (c) 2007 David Kilroy + * primary plug data + * compatibility info + * firmware identification + * unidentified drivers (guesswork for wldel48b, and old wlluc48) + * binary output format for linux kernel driver + * + * These modifications may be distributed freely under the GPL v2 so + * long as this copyright notice is included. */ #include #include @@ -23,24 +33,87 @@ struct _plugarray { unsigned int length; }; +struct _ident_info { + unsigned short int size; + unsigned short int code; + unsigned short int comp_id; + unsigned short int variant; + unsigned short int version_major; + unsigned short int version_minor; +}; + +struct _compat_info { + unsigned short int size; + unsigned short int code; + unsigned short int role; + unsigned short int id; + struct + { + unsigned short int variant; + unsigned short int bottom; + unsigned short int top; + } range[20]; +}; + struct firmwareblock { - struct _segarray *segarray; - unsigned int halfentry; - struct _plugarray *plugarray; + struct _segarray *segarray; + unsigned int halfentry; + struct _plugarray *plugarray; + struct _plugarray *pri_plugarray; + struct _compat_info *compat; + struct _ident_info *ident; } *firmware; +static const struct +{ + unsigned short int id; + char *comp_string; +} compat_table[] = +{ + /* Firmware type */ + { 21, "Primary firmware" }, + { 22, "Intermediate firmware" }, + { 31, "Station firmware" }, + { 32, "AP firmware" }, + + /* Driver type */ + { 41, "Windows 9x/NT Miniport NDIS 3.1" }, + { 42, "Packet" }, + { 43, "DOS ODI" }, + { 44, "32 bit ODI" }, + { 45, "Mac OS" }, + { 46, "Windows CE Miniport" }, + { 47, "Linux HCF-light based (public domain)" }, + { 48, "Windows 9x/NT Miniport NDIS 5.0" }, + { 49, "Linux HCF-library based" }, + { 50, "QNX" }, + { 51, "Windows 9x/NT Miniport NDIS 5.0 USB" }, + { 52, "Windows 9x/NT Miniport NDIS 4.0" }, + { 53, "VxWorks END Station driver" }, + { 54, "VxWorks END Access Point driver" }, + { 55, "Mac OS?" }, + { 56, "VxWorks END Station/AP driver" }, -void savefirmware(unsigned char *data, unsigned int flen, unsigned int signature, unsigned char hexchar); + /* Others */ + { 63, "WaveLAN Station FW update utility" }, + { 81, "WaveLAN/IEEE AP" }, + { 83, "WaveLAN/IEEE Ethernet Converter" }, + { 87, "USB Boot Loader" }, +}; + +static int savefirmware(unsigned char *data, + unsigned int flen, + unsigned int signature, + unsigned char hexchar); /* * Main */ int main(int argc, char *argv[]) { - FILE *input, *output; - unsigned char *data, *offset, *end, *hexstringoffs, *page1start, *peheader; - unsigned char hexstring[16]; - unsigned int i, j, flen, found, imagebase, vfwoffs, fwblock; + FILE *input; + unsigned char *data; + unsigned int flen; printf("Lucent Firmware Extractor v1.0 alpha\n(c) 2003 Mark Smith (username 'Mark' on HermesAP board)\n"); @@ -70,26 +143,34 @@ int main(int argc, char *argv[]) fclose(input); // Dump Tertiary firmware - printf("\nAttempting to dump tertiary firmware:\n"); - savefirmware(data, flen, 0xfbfe4461, 'T'); + printf("\nAttempting to dump tertiary (AP) firmware:\n"); + (void) savefirmware(data, flen, 0xfbfe4461, 'T'); printf("\nAttempting to dump station firmware:\n"); - savefirmware(data, flen, 0x63fc600f, 'R'); + (void) savefirmware(data, flen, 0x63fc600f, 'R'); free(data); printf("\nAll dumps complete.\n\n"); return 0; } -void savefirmware(unsigned char *data, unsigned int flen, unsigned int signature, unsigned char hexchar) +#define GUESS_OFFSET 0xC000 +#define GUESS_FILENAME "guess000.hex" + +/* Returns zero, or a negative number to indicate an error */ +static int savefirmware(unsigned char *data, + unsigned int flen, + unsigned int signature, + unsigned char hexchar) { FILE *output; unsigned char *offset, *end, *hexstringoffs, *page1start, *peheader; unsigned char hexstring[16]; - unsigned int i, j, found, imagebase, vfwoffs, fwblock; + unsigned int i, found, imagebase, vfwoffs, fwblock; // Find the ?1XXYYZZ.HEX string offset = data; end = (unsigned char *)((unsigned int)data + flen); + for (found = false; found == false && offset != NULL; ) { offset = memchr(offset, hexchar, (unsigned int)(end - offset)); @@ -102,15 +183,24 @@ void savefirmware(unsigned char *data, unsigned int flen, unsigned int signature } } - if (offset == NULL) { - printf("%c-firmware not found!\n", hexchar); - exit(-1); - } + if (offset != NULL) + { + strncpy(hexstring, offset, 13); + hexstring[13] = 0; - strncpy(hexstring, offset, 13); - hexstring[13] = 0; + printf("Found firmware %s at file offset 0x%08x\n", + hexstring, offset-data); + } + else + { + printf("%c-firmware not found!\n", hexchar); + printf("searching for signature from 0x%x\n", GUESS_OFFSET); + + strncpy(hexstring, GUESS_FILENAME,13); + hexstring[13] = 0; + offset = data + GUESS_OFFSET; + } - printf("Found firmware %s at file offset 0x%08x\n", hexstring, offset-data); printf("Searching for firmware start signature 0x%08x...\n", signature); // Really should use a mask here, but its not necessary for the moment. @@ -121,7 +211,7 @@ void savefirmware(unsigned char *data, unsigned int flen, unsigned int signature if (found == false) { printf("Signature not found!\n"); - exit(-2); + return -2; } else { page1start = offset; @@ -129,7 +219,7 @@ void savefirmware(unsigned char *data, unsigned int flen, unsigned int signature } peheader = (unsigned char *)(*(unsigned int *)(data + 0x3c)); - printf("Reading DOS driver header...\nPE header located at file offset 0x%08x\n", peheader); + printf("Reading DOS driver header...\nPE header located at file offset 0x%p\n", peheader); imagebase = (unsigned int)(*(unsigned int *)((unsigned int)peheader + (unsigned int)data + 0x34)); vfwoffs = (unsigned int)((unsigned int)page1start - (unsigned int)data + imagebase); printf("PE imagebase is 0x%08x, therefore virtual offset of firmware is 0x%08x\n", @@ -145,7 +235,7 @@ void savefirmware(unsigned char *data, unsigned int flen, unsigned int signature fwblock = (unsigned int)offset - 7 + imagebase - (unsigned int)data; if (found == false) { printf("Tertiary table not found - contact Mark!\n"); - exit(-3); + return -3; } else { printf("Found at virtual offset 0x%08x\n", fwblock); } @@ -159,23 +249,27 @@ void savefirmware(unsigned char *data, unsigned int flen, unsigned int signature firmware = (struct firmwareblock *)++offset; if (found == false) { printf("Main table not found - contact Mark!\n"); - exit(-4); + return -4; } else { printf("Found at file offset 0x%08x\n", offset - data); } printf("Entry point at 0x%08x\n", firmware->halfentry * 2); - (unsigned int)firmware->segarray += (unsigned int)data - imagebase; + firmware->segarray = (struct _segarray *) + ((unsigned int)firmware->segarray + + (unsigned int)data - imagebase); for (i = 0; i < 4 && firmware->segarray[i].offset != 0; i++) { - (unsigned int)firmware->segarray[i].data -= imagebase - 4; + unsigned int temp = + ((unsigned int)firmware->segarray[i].data - (imagebase - 4)); + firmware->segarray[i].data = (unsigned char *) (temp + data); printf("Segment: %d File offs: 0x%08x Target mem: 0x%08x Length 0x%08x\n", i, - firmware->segarray[i].data, + temp, firmware->segarray[i].offset, firmware->segarray[i].size); } - printf("Plugrecords at file offset 0x%08x\n", (unsigned int)firmware->plugarray - imagebase); + printf("Production Data plugrecords at file offset 0x%08x\n", (unsigned int)firmware->plugarray - imagebase); hexstring[9] = 0; strcat(hexstring, "hfw"); @@ -183,11 +277,46 @@ void savefirmware(unsigned char *data, unsigned int flen, unsigned int signature printf("Dumping to %s...\n", hexstring); if ((output = fopen(hexstring, "wb")) == NULL) { printf("Unable to open %s, aborting.\n", hexstring); - exit(-5); + return -5; } - (unsigned int)firmware->plugarray += (unsigned int)data - imagebase; + firmware->plugarray = (struct _plugarray *) + ((unsigned int)firmware->plugarray + + (unsigned int)data - imagebase); + + printf("Primary plugrecords at file offset 0x%08x\n", (unsigned int)firmware->pri_plugarray - imagebase); + printf("Compatibility info at file offset 0x%08x\n", (unsigned int)firmware->compat - imagebase); + printf("Identity info at file offset 0x%08x\n", (unsigned int)firmware->ident - imagebase); + + firmware->pri_plugarray = (struct _plugarray *) + ((unsigned int) firmware->pri_plugarray + + (unsigned int)data - imagebase); + firmware->compat = (struct _compat_info *) + ((unsigned int)firmware->compat + + (unsigned int)data - imagebase); + firmware->ident = (struct _ident_info *) + ((unsigned int)firmware->ident + + (unsigned int)data - imagebase); + + if (firmware->ident->code == 0xFD20u) + { + for (i = 0; + i < sizeof(compat_table)/sizeof(compat_table[0]); + i++) + { + if (compat_table[i].id == firmware->ident->comp_id) + break; + } + /* Print FW ident information */ + printf("Firmware identity: %s, Variant %d Version %d.%2d\n", + compat_table[i].comp_string, + firmware->ident->variant, + firmware->ident->version_major, + firmware->ident->version_minor); + } + +#if 0 /* original hermesap format */ fprintf(output, "HFW1\nENTRY %08X\n", firmware->halfentry * 2); for (i = 0; firmware->plugarray[i].code != 0; i++) { fprintf(output, "PLUG %08X %08X %08X\n", @@ -196,8 +325,9 @@ void savefirmware(unsigned char *data, unsigned int flen, unsigned int signature firmware->plugarray[i].length); } - for (i = 0; firmware->segarray[i].offset != 0; i++) { - (unsigned int)firmware->segarray[i].data += (unsigned int)data; + for (i = 0; firmware->segarray[i].offset != 0; i++) + { + unsigned int j; if (i != 0) fprintf(output, "\n"); fprintf(output, "SEG %08X %08X %08X", @@ -216,6 +346,90 @@ void savefirmware(unsigned char *data, unsigned int flen, unsigned int signature } fputc('\n', output); +#else /* binary kernel format */ + /* Note: does not deal with BE/LE issues */ + { + unsigned long int l = 0; + unsigned short int s = 0; + unsigned long int prev_offset = 0; + fwrite ("HFW000", 1, 6, output); + s = 6 + 2 + (6*4) + 16; // headersize + fwrite (&s, 1, sizeof(s), output); + l = firmware->halfentry; // entrypoint + fwrite (&l, 1, sizeof(l), output); + l = 2; // number of blocks, hardcoded for now + fwrite (&l, 1, sizeof(l), output); + l = 0; // offset to block data + fwrite (&l, 1, sizeof(l), output); + + // pdr offset + l = 0; + for (s = 0; firmware->segarray[s].offset != 0; s++) + { + l += firmware->segarray[s].size; + } + l = l + (s + 1) * (4 + 2); + fwrite (&l, 1, sizeof(l), output); + + // pri offset + prev_offset = l; + for (l = 0; firmware->plugarray[l].code != 0; l++); + l = prev_offset + (l+1) * 4 * 3; + fwrite (&l, 1, sizeof(l), output); + + // cpt offset + prev_offset = l; + for (l = 0; firmware->pri_plugarray[l].code != 0; l++); + l = prev_offset + (l+1) * 4 * 3; + fwrite (&l, 1, sizeof(l), output); + fwrite ("1234567890123456",1,16,output); // fw sig + + for (i = 0; firmware->segarray[i].offset != 0; i++) + { + l = firmware->segarray[i].offset; // addr + s = firmware->segarray[i].size; // size + + if (s > 0) + { + fwrite(&l, 1, sizeof(l), output); + fwrite(&s, 1, sizeof(s), output); + fwrite(firmware->segarray[i].data,1,s,output); // data + } + } + l = 0xFFFFFFFFu; // set block end + s = 0; + fwrite(&l, 1, sizeof(l), output); + fwrite(&s, 1, sizeof(s), output); + + for (i = 0; firmware->plugarray[i].code != 0; i++) { + l = firmware->plugarray[i].code; + fwrite(&l, 1, sizeof(l), output); + l = firmware->plugarray[i].targ_off; + fwrite(&l, 1, sizeof(l), output); + l = firmware->plugarray[i].length; + fwrite(&l, 1, sizeof(l), output); + } + l = 0; // pdr end + fwrite(&l, 1, sizeof(l), output); + fwrite(&l, 1, sizeof(l), output); + fwrite(&l, 1, sizeof(l), output); + + for (i = 0; firmware->pri_plugarray[i].code != 0; i++) { + l = firmware->pri_plugarray[i].code; + fwrite(&l, 1, sizeof(l), output); + l = firmware->pri_plugarray[i].targ_off; + fwrite(&l, 1, sizeof(l), output); + l = firmware->pri_plugarray[i].length; + fwrite(&l, 1, sizeof(l), output); + } + l = 0; // pdr end + fwrite(&l, 1, sizeof(l), output); + fwrite(&l, 1, sizeof(l), output); + fwrite(&l, 1, sizeof(l), output); + } +#endif fclose(output); printf("Dump of %s complete.\n", hexstring); + + return 0; /* success */ } -- 2.11.4.GIT