diff options
author | pancake <pancake@dazo> | 2007-04-20 18:20:22 +0200 |
---|---|---|
committer | pancake <pancake@dazo> | 2007-04-20 18:20:22 +0200 |
commit | b1d0ce2848a79664374f802954b1e4390b11da6d (patch) | |
tree | 4f465ca029401b9afef0372ff1e0c60a43d87b40 /src | |
download | 0xFFFF-b1d0ce2848a79664374f802954b1e4390b11da6d.tar.bz2 |
* Initial commit of 0xFFFF.0.1
This tree contains the same as the 0.1 tarball
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile | 11 | ||||
-rw-r--r-- | src/dump.c | 145 | ||||
-rw-r--r-- | src/fiasco.c | 136 | ||||
-rw-r--r-- | src/flash.c | 167 | ||||
-rw-r--r-- | src/fpid.c | 75 | ||||
-rw-r--r-- | src/hash.c | 62 | ||||
-rw-r--r-- | src/hash.h | 10 | ||||
-rw-r--r-- | src/hexdump.c | 67 | ||||
-rw-r--r-- | src/hexdump.h | 3 | ||||
-rw-r--r-- | src/main.c | 343 | ||||
-rw-r--r-- | src/main.h | 60 | ||||
-rw-r--r-- | src/pieces.c | 78 | ||||
-rw-r--r-- | src/query.c | 193 | ||||
-rw-r--r-- | src/utils.c | 57 |
14 files changed, 1407 insertions, 0 deletions
diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..ec48974 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,11 @@ +VERSION=0.1 +OBJ=main.o fiasco.o hexdump.o dump.o flash.o +OBJ+=hash.o fpid.o query.o pieces.o utils.o +BIN=0xFFFF +CFLAGS+=-DVERSION=\"${VERSION}\" -Wall -g + +main: ${OBJ} + ${CC} ${LDFLAGS} -o ${BIN} ${OBJ} -lusb + +clean: + -rm -f ${OBJ} ${BIN} diff --git a/src/dump.c b/src/dump.c new file mode 100644 index 0000000..ca6842c --- /dev/null +++ b/src/dump.c @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2007 + * pancake <pancake@youterm.com> + * + * 0xFFFF is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 0xFFFF is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0xFFFF; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "main.h" +#include <usb.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +int rf_extract(char *dev, off_t from, off_t to, char *file) +{ + off_t i, blk = 0xfffff; + char buf[0xfffff]; + FILE *fs = fopen(dev, "rb"); + FILE *fd = fopen(file, "wb+"); + + if (from>to) { + printf("Bad range %lld - %lld for %s\n", from, to, file); + goto __rf_extract_exit; + } + if (fs == NULL) { perror(dev); goto __rf_extract_exit; } + if (fd == NULL) { perror(file); goto __rf_extract_exit; } + + printf("%s: extracting...", file); + fflush(stdout); + fseek(fs, from, SEEK_SET); + + for(i=from;i<to;i+=blk) { + int ret; + if (i+blk>to) blk = to-i; + ret = fread(buf, blk, 1, fs); + if (feof(fs)) break; + fwrite(buf, blk, 1, fd); + } + + printf("\r%s: %lld bytes dumped from %s\n", + file, to-from, dev); + +__rf_extract_exit: + if (fs) fclose(fs); + if (fd) fclose(fd); + + + return 1; +} + +int rf_strip(char *file) +{ + FILE *fd = fopen(file, "rw"); + unsigned char buf[4096]; + int ret; + off_t eof = 0; + + if (!fd) { + fprintf(stderr, "Weird! can't open %s???\n", file); + exit(0); + } + printf("Stripping padding from %s... ", file); + fflush(stdout); + fseek(fd, 0, SEEK_END); + + do { + fseek(fd, -4096, SEEK_CUR); + ret = fread(buf, 1, 4096, fd); + fseek(fd, -4096, SEEK_CUR); + for(ret--;ret>0;ret--) + if (buf[ret]!=0xff) { + fseek(fd, ret+1, SEEK_CUR); + eof = ftell(fd); + goto __done; + } + } while(1); + +__done: + fclose(fd); + if (eof) truncate(file, eof); + printf("done at %d\n", (int)eof); + + return 1; +} + +int is_n800() +{ + int n800 = 0; + unsigned char buf[4]; + FILE *fd = fopen("/dev/mtd0", "rb"); + + if (!fd) { + fprintf(stderr, "Cannot open /dev/mtd0.\n"); + exit(1); + } + fread(buf, 4, 1,fd); + if (!memcmp("\xff\xff\xff\xff", buf, 4)) + n800 = 1; + + fclose(fd); + + return n800; +} + + +int reverse_extract_pieces(char *dir) +{ + char reply; + chdir(dir); + + rf_extract("/dev/mtd0", is_n800()?0x200:0, 0x003600, "xloader.bin"); + rf_extract("/dev/mtd0", 0x004000, 0x01ffff, "secondary.bin"); + rf_extract("/dev/mtd2", 0x000800, 0x200000, "zImage"); + rf_extract("/dev/mtd3", 0x000000, 0x1D00000, "initfs.jffs2"); + printf("\nWARNING: the rootfs extraction on n800 is known to be buggy! feedback is welcome.\n\n"); + printf("Extract rootfs? (Y/n): "); fflush(stdout); + read(0, &reply, 1); + if (reply=='y'||reply=='Y') + rf_extract("/dev/mtd4", 0x000000, 0xffffff, "rootfs.jffs2"); + else printf("*** Ignoring rootfs\n"); + rf_strip("xloader.bin"); + rf_strip("secondary.bin"); + rf_strip("zImage"); + rf_strip("initfs.jffs2"); + printf("Identifying extracted files...\n"); + printf("%s: xloader\n", fpid_file("xloader.bin")); + printf("%s: secondary.bin\n", fpid_file("secondary.bin")); + printf("%s: zImage\n", fpid_file("zImage")); + printf("%s: initfs.jffs2\n", fpid_file("initfs.jffs2")); + + return 1; +} diff --git a/src/fiasco.c b/src/fiasco.c new file mode 100644 index 0000000..4c49911 --- /dev/null +++ b/src/fiasco.c @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2007 + * pancake <pancake@youterm.com> + * + * 0xFFFF is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 0xFFFF is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0xFFFF; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "main.h" +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#warning The FIASCO format is not yet fully implemented. + +off_t piece_header_to_size(unsigned char *header) +{ + off_t sz = 0; + sz += header[0x15+3]; + sz += header[0x15+2] << 8; + sz += header[0x15+1] << 16; + sz += header[0x15+0] << 24; + return sz; +} + +int piece_header_is_valid(unsigned char *header) +{ + if (header[0]=='T' && header[1]=='\x02') + return 1; + return 0; +} + +#define piece_header_to_name(x) x+0x9; + +/* + * Teh Fiasco firmware parser lives here! + */ +int fiasco_read_image(char *file) +{ + int fd; + unsigned char header[5]; + unsigned char version[55]; + char *version2; + + fd = open(file, O_RDONLY); + + printf("WARNING: Fiasco firmware is not yet fully supported. Don't relay on it ATM.\n"); + + if (fd == -1) { + printf("Cannot open fiasco image.\n"); + return -1; + } + + // b4 00 00 00 00 36 + if (read(fd, header, 5) != 5) { + printf("Error reading fiasco header\n"); + goto __fiasco_read_image_end; + } + + if (header[0] != 0xb4) { + printf("Invalid fiasco signature.\n"); + goto __fiasco_read_image_end; + } + // skip 6 bytes + read(fd, version, 6); + + // print version header + if (read(fd, version, 55) != 55) { + printf("Error reading fiasco version.\n"); + goto __fiasco_read_image_end; + } + + printf("# Fiasco header information:\n"); + printf("# ==========================\n"); + printf("# firmware type: %s\n", version); + version2 = version+strlen((char *)version)+3; + if (*version2=='.') + printf("firmware version: (null) (old firmware? no version string found?)\n"); + else printf("firmware version: %s\n", version2); + + // pieces: + // after the version2 string starts the header-body loop love + lseek(fd, 0xf + strlen(version2) + strlen(version), SEEK_SET); + do { + char piece_header[30]; + char description[256]; + unsigned char desc_len; + char *name; + off_t size; + off_t tmp = lseek(fd, 0, SEEK_CUR); + + size = read(fd, piece_header, 30); + if (size != 30) { + fprintf(stderr, "Unexpected end of file\n"); + break; + } + dump_bytes(piece_header,30); + if (!piece_header_is_valid(piece_header)) { + fprintf(stderr, "Oops. Invalid piece header.\n"); + break; + } + size = piece_header_to_size(piece_header); + name = piece_header_to_name(piece_header); + printf("# %s is %lld bytes\n", name, size); + + read(fd, description, 255); + printf("# version: %s\n", description); + /* lseek foreach subimage */ + lseek(fd, tmp, SEEK_SET); + lseek(fd, strlen(description) + 0x20, SEEK_CUR); + printf("rsc '%s' %lld '%s.bin' 0 %lld\n", file, lseek(fd,0,SEEK_CUR), name, size); + lseek(fd, size, SEEK_CUR); + } while(1); + + //printf("Image '%s', size %d bytes.\n", image, size); + +__fiasco_read_image_end: + close(fd); + return 0; +} diff --git a/src/flash.c b/src/flash.c new file mode 100644 index 0000000..7a8ddd1 --- /dev/null +++ b/src/flash.c @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2007 + * pancake <pancake@youterm.com> + * + * 0xFFFF is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 0xFFFF is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0xFFFF; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "main.h" +#include "hash.h" +#include <usb.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +void check_nolo_order_failed() +{ + fprintf(stderr, "\nERROR: Provide xloader before the secondary. NOLO disagrees anything else.\n"); + fprintf(stderr, "Use: -p xloader.bin -p secondary.bin\n"); + exit(1); +} + +void check_nolo_order() +{ + int i, xlo = 0; + + for(i=0;i<pcs_n;i++) { + if (!strcmp(pcs[i].type, "xloader")) { + if (!xlo && ++i<pcs_n) { + printf("CHK%s\n", pcs[i].type); + xlo++; + if (!strcmp(pcs[i].type, "secondary")) { + xlo = 0x11; + break; + } else check_nolo_order_failed(); + } check_nolo_order_failed(); + } else + if (!strcmp(pcs[i].type, "secondary")) + check_nolo_order_failed(); + } + + if (xlo && xlo != 0x11) + check_nolo_order_failed(); +} + +void flash_image(char *filename, char *piece, char *version) +{ + FILE *fd; + int vlen = 0; + int request; + /*/ n800 flash queries have a variable size */ + unsigned char fquery[256]; /* flash query */ + unsigned long long size, off; + unsigned char bsize[4], tmp; + unsigned char nolofiller[128]; + ushort hash = do_hash_file(filename); + + if (version) + vlen = strlen(version)+1; + + fd = fopen(filename, "rb"); + if (fd == NULL) { + printf("Cannot open file\n"); + exit(1); + } + /* cook flash query */ + memset(fquery, '\x00', 27); // reset buffer + memcpy(fquery, "\x2e\x19\x01\x01", 4); // header + //memcpy(fquery+5, "\xbf\x6b", 2); // some magic (modified crc16???) + memcpy(fquery+5, &hash, 2); + tmp = fquery[5]; fquery[5] = fquery[6]; fquery[6] = tmp; + memcpy(fquery+7, piece, strlen(piece)); // XXX ??!?? + + printf("| hash: 0x%hhx%hhx ", fquery[5], fquery[6]); + size = get_file_size(filename); + bsize[0] = (size & 0xff000000) >> 24; + bsize[1] = (size & 0x00ff0000) >> 16; + bsize[2] = (size & 0x0000ff00) >> 8; + bsize[3] = (size & 0x000000ff); + printf("size: %lld (%02x %02x %02x %02x)\n", + size, bsize[0], bsize[1], bsize[2], bsize[3]); + memcpy(fquery+0x13, &bsize, 4); + if (vlen) memcpy(fquery+27, version, vlen); + + if (!strcmp(piece, "rootfs")) + request = 85; + else request = 68; + + //dump_bytes(fquery, 27+vlen); + if (usb_control_msg(dev, CMD_WRITE, request, 0, 0, (char *)fquery, 27+vlen, 2000) <0) { + perror("flash_image.header"); + exit(1); + } + + /*/ cook and bulk nollo filler */ + memset(&nolofiller, '\xff', 128); + memcpy(nolofiller+0x00, "NOLO filler", 11); + memcpy(nolofiller+0x40, "NOLO filler", 11); + usb_bulk_write(dev, 2, (char *)nolofiller, 128, 5000); + usb_bulk_write(dev, 2, (char *)nolofiller, 0, 5000); + + /*/ bulk write image here */ + printf("[=] Bulkwriting the %s piece...\n", piece); + fflush(stdout); + + for(off = 0; off<size; off += BSIZE) { + char buf[BSIZE]; + int bread, bsize = size-off; + if (bsize>BSIZE) bsize = BSIZE; + bread = fread(buf, bsize, 1, fd); + if (bread != 1) + printf("WARNING: Oops wrong read %d vs %d \n", bread, bsize); + bread = usb_bulk_write(dev, 2, buf, bsize, 5000); + progressbar(off, size); + if (bread<0) perror(" -ee- "); + fflush(stdout); + } + fclose(fd); + /*/ EOF */ + usb_bulk_write(dev, 2, (char *)nolofiller, 0, 1000); + progressbar(1, 1); + printf("\n"); + + // index = 4???? + if (!strcmp(piece, "rootfs")) { + if (usb_control_msg(dev, CMD_WRITE, 82, 0, 0, (char *)fquery, 0, 30000)<0) { + fprintf(stderr, "Oops. Invalid checksum?\n"); + exit(1); + } + } else { + int t = 0; + if (!strcmp(piece, "secondary")) + t = 1; + else + if (!strcmp(piece, "kernel")) + t = 3; + else + if (!strcmp(piece, "initfs")) + t = 4; + if (!strcmp(piece, "xloader")) + printf("xloader flashed not commiting until secondary arrives...\n"); + else + if (usb_control_msg(dev, CMD_WRITE, 80, 0, t, (char *)fquery, 0, 10000)<0) { + fprintf(stderr, "Oops. Invalid checksum?\n"); + exit(1); + } + } + + // unknown query !! :"" + if (usb_control_msg(dev, CMD_WRITE, 67, 0, 0, (char *)fquery, 0, 2000)<0) { + fprintf(stderr, "Oops, the flash was denied or so :/\n"); + exit(1); + } + printf("Flash done succesfully.\n"); +} diff --git a/src/fpid.c b/src/fpid.c new file mode 100644 index 0000000..93bf205 --- /dev/null +++ b/src/fpid.c @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2007 + * pancake <pancake@youterm.com> + * + * 0xFFFF is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 0xFFFF is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0xFFFF; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "main.h" +#include <stdio.h> +#include <string.h> + +char *fpid_file(char *filename) +{ + FILE *fd; + char buf[512]; + unsigned char *b = (unsigned char *)&buf; + char *piece = NULL; + long size; + + // 2nd : +0x34 = 2NDAPE + // secondary: +0x04 = NOLOScnd + // x-loader : +0x14 = X-LOADER + // xloader8 : +0x0c = NOLOXldr + // kernel : +0x00 = 0000 a0e1 0000 a0e1 + // initfs : <2M...be sure with 3M 0x300000 + + fd = fopen(filename, "r"); + if (fd == NULL) { + printf("Cannot open file '%s'\n", filename); + return NULL; + } + fread(buf, 512, 1, fd); + fseek(fd, 0, SEEK_END); + size = ftell(fd); + fclose(fd); + +#if 0 + if (!memcmp(b+0x34, "2NDAPE", 6)) + return PIECE_2ND; + else +#endif + if (!memcmp(b+0x04, "NOLOScnd", 8)) + return pieces[PIECE_SECONDARY]; + else + if (!memcmp(b+0x14, "X-LOADER", 8)) + return pieces[PIECE_XLOADER]; + else + if (!memcmp(b+0x0c, "NOLOXldr", 8)) // TODO: this is xloader800, not valid on 770? + return pieces[PIECE_XLOADER]; + else + if (!memcmp(b+0x00, "\x00\x00\xa0\xe1\x00\x00\xa0\xe1", 8)) + return pieces[PIECE_KERNEL]; + else + if (!memcmp(b+0x00, "\x85\x19\x01\xe0", 4)) { + /*/ is jffs2 */ + if (size < 0x300000) + return pieces[PIECE_INITFS]; + return pieces[PIECE_ROOTFS]; + } + + return piece; +} diff --git a/src/hash.c b/src/hash.c new file mode 100644 index 0000000..53a3542 --- /dev/null +++ b/src/hash.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2007 + * pancake <pancake@youterm.com> + * + * 0xFFFF is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 0xFFFF is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0xFFFF; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include <stdio.h> +#include "hash.h" + +usho do_hash(usho *b, int len) +{ + usho result = 0; + for(len>>=1;len--;b=b+1) + result^=b[0]; + return result; +} + +usho do_hash_file(char *filename) +{ + unsigned char buf[BSIZE]; + FILE *fd = fopen(filename, "r"); + usho hash = 0; + int ret; + + if (fd == NULL) { + fprintf(stderr, "ERROR: File '%s' not found.\n", filename); + return -1; + } + + do { ret = fread(&buf, 1, BSIZE, fd); + if (ret == -1) + return 0; + hash ^= do_hash((usho *)&buf, ret); + } while(ret); + + fclose(fd); + + return hash; +} + +#if 0 +main() +{ + usho us = do_hash_file("zImage"); + unsigned char *h= (unsigned char *)&us; + printf("%x %x\n",h[0],h[1]); +} +#endif diff --git a/src/hash.h b/src/hash.h new file mode 100644 index 0000000..b7de788 --- /dev/null +++ b/src/hash.h @@ -0,0 +1,10 @@ +#ifndef _INCLUDE_HASH_H_ +#define _INCLUDE_HASH_H_ + +#define usho unsigned short +#define BSIZE 0x20000 + +usho do_hash(usho *b, int len); +usho do_hash_file(char *filename); + +#endif diff --git a/src/hexdump.c b/src/hexdump.c new file mode 100644 index 0000000..6718d82 --- /dev/null +++ b/src/hexdump.c @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2006-2007 + * pancake <pancake@youterm.com> + * + * radare is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * radare is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with radare; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include <stdio.h> +#include <string.h> +#include "hexdump.h" + +char getprintablechar(char a) +{ + if (a>=' '&&a<='~') + return a; + return '.'; +} + +int is_printable (int c) +{ + if (c<' '||c>'~') return 0; + return 1; +} + +/* + * Helper function + */ +void dump_bytes(unsigned char *buf, int len) +{ + int i,j,seek = 0; + int inc = 16; + + for(i=0; i<len; i+=inc) { + fprintf(stderr, "0x%08x | ", seek+i); + for(j=i;j<i+inc;j++) { + if (j>=len) { + fprintf(stderr, " "); + continue; + } + fprintf(stderr, "%02x ", buf[j]); + } + fprintf(stderr, " "); + for(j=i; j<i+inc; j++) { + if (j >= len) + fprintf(stderr, " "); + else + if ( is_printable(buf[j]) ) + fprintf(stderr, "%c", buf[j]); + else fprintf(stderr, "."); + } + fprintf(stderr, "\n"); + } + fflush(stderr); +} diff --git a/src/hexdump.h b/src/hexdump.h new file mode 100644 index 0000000..b28462c --- /dev/null +++ b/src/hexdump.h @@ -0,0 +1,3 @@ +char getprintablechar(char a); +int is_printable (int c); +void dump_bytes(unsigned char *buf, int len); diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..7812ae1 --- /dev/null +++ b/src/main.c @@ -0,0 +1,343 @@ +/* + * Copyright (C) 2007 + * pancake <pancake@youterm.com> + * + * 0xFFFF is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 0xFFFF is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0xFFFF; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "main.h" +#include <usb.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <getopt.h> + +/* global pr0n */ +struct usb_device *device = NULL; +struct usb_dev_handle *dev = NULL; +char *fiasco_image = NULL; +char *boot_cmdline = NULL; +char *reverseto = NULL; +int rdflags = -1; +int usb_mode = -1; +int verbose = 0; +int identify = 0; +int reboot = 0; +int unpack = 0; +int info = 0; + +/* global structs */ +char *pieces[] = { + "xloader", // xloader.bin + "secondary", // secondary.bin + "kernel", // zImage + "initfs", // jffs'd initfs + "rootfs", // 80mB of blob + "omap-nand", // 8kB of food for the nand + NULL +}; + +char *modes[]={ + "host", + "peripheral", + NULL +}; + +char *root_devices[] = { + "flash", + "mmc", + "usb", + NULL +}; + +struct devices { + char *name; + unsigned short vendor_id; + unsigned short product_id; + unsigned short flags; +}; + +#define SUPPORTED_DEVICES 5 +struct devices supported_devices[SUPPORTED_DEVICES] = { + { "unkn", 0x421, 0x3f00, 0x0000 }, // probably a development board + { "n770", 0x421, 0x0105, 0x0001 }, // my n770 + { "n800", 0x421, 0x04c3, 0x0001 }, // a n800 + { 0 }, + { 0 } +}; + +int is_valid_device(struct usb_device_descriptor *udd) +{ + int i; + struct devices ptr = supported_devices[0]; + + for(i=0 ; ptr.vendor_id; ptr = supported_devices[++i]) + if ((udd->idVendor == ptr.vendor_id) + && (udd->idProduct == ptr.product_id)) { + printf("found %s (%04x:%04x)\n", + ptr.name, ptr.vendor_id, ptr.product_id); + return 1; + } + + return 0; +} + +void list_valid_devices() +{ + int i; + struct devices ptr = supported_devices[0]; + + for(i=0; ptr.vendor_id; ptr = supported_devices[++i]) + printf("%04x:%04x %s\n", ptr.vendor_id, ptr.product_id, ptr.name); +} + +int usb_device_found(struct usb_device_descriptor *udd) +{ + if (usb_find_busses() < 0) { + fprintf(stderr, "error: no usb busses found.\n"); + exit(1); + } else { + if (usb_find_devices() < 0) { + fprintf(stderr, "error: no devices found.\n"); + exit(1); + } else { + struct usb_bus *bus; + for (bus = usb_busses; bus; bus = bus->next) { + struct usb_device *dev = bus->devices; + D printf("bus: \n"); + for (; dev; dev = dev->next) { + *udd = dev->descriptor; + D printf(" dev (%s) - ", dev->filename); + D printf("vendor: %04x product: %04x\n", udd->idVendor, udd->idProduct); + + if (is_valid_device(udd)) { + device = dev; + return 1; + } + } + } + } + } + + return 0; +} +/*------------- devices -----------------------*/ + +void show_title() +{ + printf("0xFFFF v%s - The Free Fiasco Firmware Flasher\n", VERSION); +} + +void show_usage() +{ + int i; + show_title(); + + printf(" -b [arg] boots the kernel with arguments\n"); + printf(" -e [path] dump and extract pieces to path\n"); + printf(" -p [[p%%]file] piece-of-firmware %% file-where-this-piece-is\n"); + printf(" -r [0|1] disable/enable R&D mode\n"); + printf(" -u [fiasco] unpack target fiasco image\n"); + printf(" -U [0|1] disable/enable the usb host mode\n"); + printf(" -h show this help message\n"); + printf(" -i show device information (let standby mode)\n"); + printf(" -I [piece] identify a firmware piece\n"); + printf(" -l list supported usb device ids\n"); + printf(" -d [vid:pid] injects a usb device into the supported list\n"); + printf(" -R reboot the omap board\n"); + printf(" -v be verbose and noisy\n"); + printf(" -V show 0xFFFF version information\n"); + printf("Pieces are: "); + for(i=0;pieces[i];i++) printf("%s ", pieces[i]); printf("\n"); + // serial port support is not yet done (cold flash is for flashing the 8kB nand) + // TODO: commandline shell prompt for nolo comm + + exit(0); +} + +void unpack_fiasco_image(char *file) +{ + fiasco_read_image(file); + // TODO +} + +int query_sw_version() +{ + int ret; + char bytes[1024]; + + strcpy(bytes, "version:sw-release"); + ret = usb_control_msg(dev, CMD_WRITE, 18, 0, 0, (char *)&bytes, 18, 2000); + if (ret<0) { + fprintf(stderr, "error: cannot write query 18\n"); + return 0; + } + ret = usb_control_msg(dev, CMD_QUERY, 20, 0, 0, (char *)&bytes, 512, 2000); + if (ret<0) { + fprintf(stderr, "error: b0rken swversion read!\n"); + return 0; + } + printf("SWVERSION GOT: %s\n", bytes); //???+strlen(bytes)+1)); + return 1; +} + +int main(int argc, char **argv) +{ + struct usb_device_descriptor udd; + int c; + + while((c = getopt(argc, argv, "p:vVhRu:ib:U:r:e:ld:I:")) != -1) { + switch(c) { + case 'd': + sscanf(optarg, "%04hx:%04hx", + &supported_devices[SUPPORTED_DEVICES-2].vendor_id, + &supported_devices[SUPPORTED_DEVICES-2].product_id); + supported_devices[SUPPORTED_DEVICES-2].name = strdup("user"); + break; + case 'e': + reverseto = optarg; + break; + case 'U': + usb_mode = atoi(optarg); + break; + case 'r': + rdflags = atoi(optarg); + break; + case 'b': + boot_cmdline = optarg; + break; + case 'u': + fiasco_image = optarg; + unpack = 1; + break; + case 'p': + add_piece(optarg); + break; + case 'l': + list_valid_devices(); + return 0; + case 'I': + printf("%s: %s\n", fpid_file(optarg), optarg); + identify = 1; + break; + case 'i': + info = 1; + break; + case 'v': + verbose = 1; + break; + case 'h': + show_usage(); + break; + case 'V': + printf("%s\n", VERSION); + return 0; + case 'R': + reboot = 1; + break; + } + } + + if (identify) + return 0; + + // flags ok? + if ( (fiasco_image == NULL) + && (boot_cmdline == NULL) + && (reverseto == NULL) + && (pcs_n == 0) + && (rdflags == -1) + && (info == 0) + && (reboot == 0) + && (usb_mode == -1)) + { + printf("Usage: 0xFFFF [-hvVRi] [-e path] [-U 0|1] [-p [piece%]file [-p ...]]\n"); + printf(" [-b boot-args] [-I piece [-I ...]] [-u fiasco-image]\n"); + return 1; + } + + if (unpack) { + unpack_fiasco_image(fiasco_image); + return 0; + } + + if (reverseto) { + reverse_extract_pieces(reverseto); + return 0; + } + + // usb_set_debug(5); + usb_init(); + + while(!usb_device_found(&udd)) { + char pbc[]={'/','-','\\', '|'}; + usleep(0xc350); // 0.5s + printf("\rWaiting for device... %c", pbc[++c%4]); + fflush(stdout); + } + + /*/ open device */ + dev = usb_open(device); + if (dev == NULL) { + perror("usb_open"); + return 1; + } + // TODO + if ( usb_claim_interface(dev, 2) < 0) { // 2 or 0 + perror("usb_claim_interface"); + return 1; + } + + if (usb_set_altinterface(dev, 1) < 0) { + perror("usb_set_altinterface"); + return 1; + } + + set_rd_mode(rdflags); + + /* go go go! */ + while(get_status()); + + // if (info) + sleep(1); // take breath + query_root_device(); // only for flashing + query_rdmode_device(); + query_hw_revision(); // get hardware revision: + + if (pcs_n) { + int c; + + check_nolo_order(); + query_sw_version(); + query_nolo_version(); + + for(c=0;c<pcs_n;c++) { + printf("Flashing %s (%s)\n", pcs[c].type, pcs[c].name); + flash_image(pcs[c].name, pcs[c].type, pcs[c].vers); + } + } + + if (usb_mode!=-1) + set_usb_host_mode(usb_mode); + + if (boot_cmdline) + boot_board(boot_cmdline); + + if (reboot) + reboot_board(); + + return 0; +} diff --git a/src/main.h b/src/main.h new file mode 100644 index 0000000..9b0bcd1 --- /dev/null +++ b/src/main.h @@ -0,0 +1,60 @@ +#ifndef _INCLUDE_MAIN_H_ +#define _INCLUDE_MAIN_H_ + +#define _FILE_OFFSET_BITS 64 +#define _GNU_SOURCE + +int reverse_extract_pieces(char *dir); +void flash_image(char *filename, char *piece, char *version); +int fiasco_read_image(char *file); +void check_nolo_order(); +extern struct usb_dev_handle *dev; +unsigned long get_file_size(char *file); +void progressbar(unsigned long long part, unsigned long long total); +int get_status(); +int get_peripheral_host_mode(int foo); +int boot_board(char *cmdline); +int boot_board(char *cmdline); +int reboot_board(); +char *fpid_file(char *filename); +int set_rd_mode(unsigned short mode); +int set_usb_host_mode(unsigned short mode); +int query_hw_revision(); +int query_rdmode_device(); +int query_root_device(); +int query_nolo_version(); +int add_piece(char *piece); + +#define D if (verbose) + +#define CMD_WRITE 64 +#define CMD_QUERY 192 + +#define NOLO_GET_STATUS 1 +#define NOLO_GET_BOARD_ID 2 +#define NOLO_GET_VERSION 3 + +struct piece_t { + char *name; + char *type; + char *vers; +}; + +extern int pcs_n; +extern struct piece_t pcs[10]; + +enum { + PIECE_XLOADER = 0, + PIECE_SECONDARY, + PIECE_KERNEL, + PIECE_INITFS, + PIECE_ROOTFS, + PIECE_OMAPNAND, + PIECE_LAST +}; + +extern char *pieces[]; +extern char *modes[]; +extern char *root_devices[]; + +#endif diff --git a/src/pieces.c b/src/pieces.c new file mode 100644 index 0000000..9ce234c --- /dev/null +++ b/src/pieces.c @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2007 + * pancake <pancake@youterm.com> + * + * 0xFFFF is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 0xFFFF is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0xFFFF; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "main.h" +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +int pcs_n = 0; +struct piece_t pcs[10]; + +int add_piece(char *piece) +{ + int i,ok = 0; + char *file; + + if (pcs_n==9) { + fprintf(stderr, "Oops...cannot add more pieces. no sense operation!\n"); + return 0; + } + + file = strchr(piece, '%'); + if (file) { + file[0]='\0'; + file = file + 1; + for(i=0;pieces[i];i++) + if (!strcmp(pieces[i], piece)) + ok = 1; + if (!ok) { + printf("Invalid piece name.\n"); + printf("Pieces: "); + for(i=0;pieces[i];i++) + printf("%s ", pieces[i]); + printf("\n"); + exit(1); + } + + pcs[pcs_n].name = strdup(file); + pcs[pcs_n].type = strdup(piece); + pcs[pcs_n].vers = NULL; // TODO version string not yet supported + } else { + /*/ autodetect piece type */ + pcs[pcs_n].type = fpid_file(piece); + if (pcs[pcs_n].type == NULL) { + printf("Use -p [piece]:[file]\n"); + printf("Pieces: "); + for(i=0;pieces[i];i++) + printf("%s ", pieces[i]); + printf("\n"); + exit(1); + } else { + pcs[pcs_n].name = strdup(piece); + pcs[pcs_n].type = strdup(pcs[pcs_n].type); + pcs[pcs_n].vers = NULL; + } + } + + pcs_n++; + + return 1; +} diff --git a/src/query.c b/src/query.c new file mode 100644 index 0000000..bdbcf69 --- /dev/null +++ b/src/query.c @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2007 + * pancake <pancake@youterm.com> + * + * 0xFFFF is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 0xFFFF is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0xFFFF; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "main.h" +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <usb.h> + +/* wait for status = 0 */ +int get_status() +{ + int ret = 0; + if (usb_control_msg(dev, 192, 1, 0, 0, (char *)&ret, 4, 2000) == -1) { + fprintf(stderr, "Cannot get device status.\n"); + exit(1); + } + + return ret; +} + +int get_peripheral_host_mode(int foo) +{ + //unsigned short mode = 0; + + // XXX BROKEN +#if 0 + if (usb_control_msg(dev, 64, 16, 2, 0, 2, 0, 0, 2000)) { + fprintf(stderr, "Cannot query device.\n"); + return -1; + } + + printf("Device is in \"%s\" mode (%hd)\n", (mode)?"host":"peripheral", mode); +#endif + + return 0; +} +/* + * boot the omap mobo + */ + +int boot_board(char *cmdline) +{ + if (usb_control_msg(dev, CMD_WRITE, 130, 0, 0, cmdline, strlen(cmdline), 2000) == -1) { + fprintf(stderr, "Cannot boot kernel.\n"); + perror("boot_board"); + return -1; + } + + printf("Booting kernel with arguments: '%s'.\n", cmdline); + + return 0; +} + +/* + * reboot the omap mobo + */ +int reboot_board() +{ + // 131 = reboot + if (usb_control_msg(dev, CMD_WRITE, 131, 0, 0, 0, 0, 2000) == -1) { + fprintf(stderr, "Cannot reboot board.\n"); + return -1; + } + + printf("Mobo rebooted!\n"); + + return 0; +} + +int set_rd_mode(unsigned short mode) +{ + if (((short)mode)==-1) + return 1; + + if (usb_control_msg(dev, CMD_WRITE, 16, mode, 0, 0, 0, 2000) == -1) { + fprintf(stderr, "Cannot set R&D flags.\n"); + return 1; + } + + printf("rd mode changed to %s\n", mode?"on":"off"); + + return 0; +} + +// mode = 1 || 0 +int set_usb_host_mode(unsigned short mode) +{ + if (usb_control_msg(dev, CMD_WRITE, 16, mode, 2, 0, 0, 2000) == -1) { + fprintf(stderr, "Cannot change the usb-host mode.\n"); + return -1; + } + + printf("USB host mode is %s.\n", mode?"enabled":"disabled"); + + return 0; +} + +/* + * query root device + */ +int query_hw_revision() +{ + unsigned char string[512]; + int i = 0; + + if (usb_control_msg(dev, CMD_QUERY, 4, 0, 0, (char *)string, 512, 2000) == -1) { + fprintf(stderr, "Cannot query hw revision.\n"); + return -1; + } + + printf("HW revision string: '"); + for(i=0;i<44;i++) { // XXX ?? + if (string[i]==0) { + printf(" "); + } else { + if (string[i]>19) + printf("%c", string[i]); + } + } + printf("'\n"); + + return 0; +} + +int query_rdmode_device() +{ + char isrd = 1; + + if (usb_control_msg(dev, CMD_QUERY, 17, 0, 0, (char *)&isrd, 1, 2000) == -1) { + fprintf(stderr, "Cannot query rd mode.\n"); + return -1; + } + printf("RD mode is: %s\n", isrd?"on":"off"); + + return isrd; +} + +int query_root_device() +{ + unsigned char opcode; + + if (usb_control_msg(dev, 192, 17, 0, 1, (char *)&opcode, 1, 2000) < 0) { + fprintf(stderr, "Cannot query root device\n"); + return -1; + } + + if (opcode>2) { // use sizeof || enum + printf("Invalid root device received from the device '%d'.\n", opcode); + } + + printf("Root device is: %s\n", root_devices[opcode]); + + return 0; +} + +int query_nolo_version() +{ + unsigned int version; // ensure uint is at least 32 bits + + //if (usb_control_msg(dev, 192, 3, 0, 1, (char *)&version, 4 , 2000) < 0) { + if (usb_control_msg(dev, 192, 3, 0, 0, (char *)&version, 4 , 2000) < 0) { + fprintf(stderr, "Cannot query nolo version. Old bootloader version?\n"); + exit(1); + } + + printf("NOLO Version %d.%d.%d\n", + version >> 20 & 15, + version >> 16 & 15, + version >> 8 & 255); + + if ((version & 255)> 1) + printf("Invalid API version (%d)\n", version&255); + + return 0; +} diff --git a/src/utils.c b/src/utils.c new file mode 100644 index 0000000..67808de --- /dev/null +++ b/src/utils.c @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2007 + * pancake <pancake@youterm.com> + * + * 0xFFFF is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 0xFFFF is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0xFFFF; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "main.h" +#include <usb.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +unsigned long get_file_size(char *file) +{ + FILE *fd = fopen(file, "r"); + unsigned long len = 0; + if (fd == NULL) { + fprintf(stderr, "Cannot open file '%s'\n", file); + exit(1); + } + fseek(fd, 0, SEEK_END); + len = ftell(fd); + fclose(fd); + return len; +} + +void progressbar(unsigned long long part, unsigned long long total) +{ + char *columns = getenv("COLUMNS"); + int pc; + int tmp, cols = 80; + + pc = (int)(part*100/total); + (pc<0)?pc=0:(pc>100)?pc=100:0; + printf("\e[K %3d%% [", pc); + if (columns) + cols = atoi(columns); + cols-=15; + for(tmp=cols*pc/100;tmp;tmp--) printf("#"); + for(tmp=cols-(cols*pc/100);tmp;tmp--) printf("-"); + printf("]\r"); + fflush(stdout); +} |