/* Copyright (c) 2007 onitake Thanks & kudos to: - geohot for norz - gray and the dev team for reverse engineering and iUnlock/anySIM This program 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 3 of the License, or (at your option) any later version. This program 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 this program. If not, see . */ #include #include #include #include #include "baseband.h" static const unsigned int BUFFER_SHIFT = 11; static const unsigned int BUFFER_SIZE = 2048; static const unsigned int BUFFER_MASK = 2047; void usage() { fprintf(stderr, "bbtool - bbupdater replacement under GPL license\n"); fprintf(stderr, "Usage: bbtool [-v] [-h] [-D device] [-B baud rate] [-s secpack] [-b memory address] [-n length] [-r file | -x | -w file]\n"); //fprintf(stderr, "For compatibility, [-f FLS file], [-f FLS file] and [-e EEP file] are also supported.\n"); fprintf(stderr, "Address and length may be specified in decimal or hex (with a preceding 0x).\n"); fprintf(stderr, "If no operation (-x, -r or -w) is given, the baseband will be reset and the boot loader version displayed.\n"); fprintf(stderr, " -D: set serial device\n"); fprintf(stderr, " -B: set baud rate\n"); fprintf(stderr, " -b: memory region start\n"); fprintf(stderr, " -n: length (can be omitted for write mode)\n"); fprintf(stderr, " -s: specify secpack for erase operation\n"); fprintf(stderr, " -r: read region into the given file\n"); fprintf(stderr, " -x: erase region\n"); fprintf(stderr, " -w: write region from the given file\n"); //fprintf(stderr, " -f: write flash from FLS file, also use secpack from there if not specified\n"); //fprintf(stderr, " -l: write bootloader from FLS file\n"); //fprintf(stderr, " -e: write EEPROM area from EEP file\n"); fprintf(stderr, " -h: show this help\n"); fprintf(stderr, " -v: increase verbosity (default is INFO, -v raises to DEBUG)\n"); } int readFlash(int fd, const char *output, unsigned int start, unsigned int length) { if (!output) { fprintf(stderr, "Error, no output file specified.\n"); return 10; } fprintf(stderr, "Reading from 0x%08x to 0x%08x\n", start, start + length); if (start == 0 || length == 0) { fprintf(stderr, "Invalid address/length\n"); return 5; } FILE *fp = fopen(output, "wb"); if (!fp) { fprintf(stderr, "Can't open %s: %s\n", output, strerror(errno)); return 3; } seekBaseband(fd, start); unsigned char buffer[BUFFER_SIZE]; unsigned int i; for (i = 0; i < length >> BUFFER_SHIFT; i++) { unsigned int len = length >> BUFFER_SHIFT; fprintf(stderr, "Reading block %d of %d - %d%%\n", i + 1, len, len ? i * 100 / len : 0); size_t count = readBaseband(fd, buffer, sizeof(buffer)); if (fwrite(buffer, 1, count, fp) != count) { fprintf(stderr, "Can't write data: %s\n", strerror(errno)); fclose(fp); return 4; } } unsigned int remainder = length & BUFFER_MASK; if (remainder) { fprintf(stderr, "Reading remainder - 100%%\n"); size_t count = readBaseband(fd, buffer, remainder); if (fwrite(buffer, 1, count, fp) != count) { fprintf(stderr, "Can't write data: %s\n", strerror(errno)); fclose(fp); return 4; } } fclose(fp); } void sendSecPack(int fd, const char *secfile) { if (!secfile) { fprintf(stderr, "No secpack specified, trying without.\n"); return; } FILE *fp = fopen(secfile, "rb"); if (!fp) { fprintf(stderr, "Can't open secpack: %s\n", strerror(errno)); return; } char buffer[SECPACK_SIZE]; if (fread(buffer, sizeof(buffer), 1, fp) != 1) { fprintf(stderr, "Can't read secpack: %s\n", strerror(errno)); fclose(fp); return; } fclose(fp); secPack(fd, buffer); } int writeFlash(int fd, const char *input, unsigned int start, unsigned int length) { if (!input) { fprintf(stderr, "Error, no input file specified.\n"); return 10; } FILE *fp = fopen(input, "rb"); if (!fp) { fprintf(stderr, "Can't open %s: %s\n", input, strerror(errno)); return 3; } fseek(fp, 0, SEEK_END); long ofs = (unsigned int) ftell(fp); if (ofs != -1 && (length == 0 || length > ofs)) length = (unsigned int) ofs; fseek(fp, 0, SEEK_SET); fprintf(stderr, "Writing from 0x%08x to 0x%08x\n", start, start + length); if (start == 0) { fprintf(stderr, "Invalid start address\n"); fclose(fp); return 5; } seekBaseband(fd, start); unsigned char buffer[BUFFER_SIZE]; unsigned int len = length >> BUFFER_SHIFT; unsigned int i; for (i = 0; i < len; i++) { fprintf(stderr, "Writing block %d of %d - %d%%\n", i + 1, len, i * 100 / len); size_t count = fread(buffer, 1, sizeof(buffer), fp); if (count != sizeof(buffer)) { fprintf(stderr, "Can't read data: %s\n", strerror(errno)); fclose(fp); return 4; } writeBaseband(fd, buffer, count); } unsigned int remainder = length & BUFFER_MASK; if (remainder) { fprintf(stderr, "Writing remainder - 100%%\n"); size_t count = fread(buffer, 1, remainder, fp); if (count != remainder) { fprintf(stderr, "Can't read data: %s\n", strerror(errno)); fclose(fp); return 4; } writeBaseband(fd, buffer, count); } fclose(fp); } int main(int argc, char **argv) { setLogLevel(LOGLEVEL_INFO); const char *device = DEFAULT_BASEBAND_DEVICE; unsigned int rate = 921600; char mode = '\0'; char *secpack = NULL; char *binfile = NULL; unsigned int start = 0; unsigned int length = 0; int ch; while ((ch = getopt(argc, argv, "D:B:b:n:s:r:xw:vh")) != -1) { switch (ch) { case 'v': setLogLevel(LOGLEVEL_TRACE); break; case 'x': mode = 'x'; break; case 'h': usage(); return 0; case 'D': device = optarg; break; case 'B': rate = (unsigned int) strtoul(optarg, NULL, 10); break; case 'b': start = (unsigned int) strtoul(optarg, NULL, 0); if (start < 0xa0000000 || start >= 0xb0000000) { start = (start & ~0xf0000000) | 0xa0000000; fprintf(stderr, "Start address is not in flash range, corrected to 0x%08x.\n", start); } break; case 'n': length = (unsigned int) strtoul(optarg, NULL, 0); break; case 's': secpack = optarg; break; case 'r': mode = 'r'; binfile = optarg; break; case 'w': mode = 'w'; binfile = optarg; break; default: usage(); return 1; } } resetBaseband(); int fd = openBaseband(device); if (fd == -1) { fprintf(stderr, "Can't open %s: %s", device, strerror(errno)); return 2; } setBaudRate(fd, rate); VersionPacket version = getBootVersion(fd); fprintf(stderr, "Got %d.%d, %s\n", version.major, version.minor, version.major <= 3 ? "GOOD." : "BAD. You need a secpack that is more recent than the installed firmware."); prepareFlash(fd); int err = 0; switch (mode) { case 'x': sendSecPack(fd, secpack); eraseBaseband(fd, start, start + length); endSecPack(fd); break; case 'r': err = readFlash(fd, binfile, start, length); break; case 'w': sendSecPack(fd, secpack); //eraseBaseband(fd, start, start + length); err = writeFlash(fd, binfile, start, length); endSecPack(fd); break; default: break; } close(fd); return err; }