From e701ca2b7417fce54fdc6157d73b4c12fae771e2 Mon Sep 17 00:00:00 2001 From: Robert Zaage Date: Sun, 3 Jul 2022 12:26:20 +0200 Subject: [PATCH] Inital english version commit --- Makefile | 8 +- README.md | 23 ++--- balong_flash.c | 162 ++++++++++++++++--------------- flasher.c | 130 +++++++++++++------------ flasher.h | 2 +- hdlcio.h | 2 +- hdlcio_linux.c | 185 ++++++++++++++++++------------------ ptable.c | 252 +++++++++++++++++++++++-------------------------- ptable.h | 43 ++++----- signver.c | 133 ++++++++++++-------------- signver.h | 4 +- util.c | 186 +++++++++++++++++------------------- util.h | 1 + 13 files changed, 538 insertions(+), 593 deletions(-) diff --git a/Makefile b/Makefile index b170699..dae854a 100755 --- a/Makefile +++ b/Makefile @@ -2,17 +2,17 @@ CC = gcc LIBS = -lz #BUILDNO = `cat build` BUILDNO=$(shell cat build) -CFLAGS = -O2 -Wunused -Wno-unused-result -D BUILDNO=$(BUILDNO) -D_7ZIP_ST $(LIBS) +CFLAGS = -O2 -Wunused -Wno-unused-result -D BUILDNO=$(BUILDNO) -D_7ZIP_ST $(LIBS) .PHONY: all clean all: balong_flash -clean: +clean: rm -f *.o lzma/*.o rm -f balong_flash balong_flash: balong_flash.o hdlcio_linux.o ptable.o flasher.o util.o signver.o lzma/Alloc.o lzma/LzmaDec.o - @gcc $^ -o $@ $(LIBS) + @gcc $^ -o $@ $(LIBS) @echo Current buid: $(BUILDNO) @echo $$((`cat build`+1)) >build - + diff --git a/README.md b/README.md index b9c7fd1..b2e3b01 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,11 @@ -# balongflash - -## Russian - -Программа для прошивки модемов и LTE-маршрутизаторов фирмы Huawei на чипсете Balong V7. - -Эта утилита предназначена для прошивания BIN- и EXE-файлов прошивок из режима загрузки, а также набора файлов прошивки из указанной директории. Файл прошивки может быть разобран на составные части с заголовком и без. Файлы прошивок могут быть с цифровой подписью и без нее. - -**Эта утилита может вывести ваше устройство из строя!** -Используйте ее, только если осознаете все риски и последствия. В случае каких-либо возникших проблем, не ждите помощи, рассчитывайте только на свои собственные силы. - -## English +# balong-flash Huawei Balong V7 modem and LTE router flashing utility. -This program is used to flash BIN and EXE firmware files to device in download mode. It also supports flashing separate firmware components from selected directory. Firmware files could be extracted to separate files with header and without it. Both files with and without digital signature supported. - -This software is in Russian only. Use machine translation if needed. -Please ask questions only about the program itself. No questions about devices, boot pins, loaders, backups allowed. +This program is used to flash BIN and EXE firmware files to device in download mode. +It also supports flashing separate firmware components from selected directory. +Firmware files could be extracted to separate files with header and without it. +Both files with and without digital signature supported. -**This utility can make your device unbootable!** +**This utility can make your device unbootable!** Use it only if you fully understand all risks and consequences. In case of any issues, you're on your own. Do not expect any help. diff --git a/balong_flash.c b/balong_flash.c index a7aee1d..bebbc48 100644 --- a/balong_flash.c +++ b/balong_flash.c @@ -24,22 +24,22 @@ #include "signver.h" #include "zlib.h" -// флаг ошибки структуры файла +// file structure error flag unsigned int errflag=0; -// флаг цифровой подписи +// digital signature flag int gflag=0; -// флаг типа прошивки +// firmware type flag int dflag=0; -// тип прошивки из заголовка файла +// firmware type from file header int dload_id=-1; //*********************************************** -//* Таблица разделов +//* Partition table //*********************************************** struct ptb_t ptable[120]; -int npart=0; // число разделов в таблице +int npart=0; // number of partitions in the table //@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@ -51,33 +51,33 @@ int res; FILE* in; char devname[50] = ""; unsigned int mflag=0,eflag=0,rflag=0,sflag=0,nflag=0,kflag=0,fflag=0; -unsigned char fdir[40]; // каталог для мультифайловой прошивки +unsigned char fdir[40]; // directory for multi-file firmware -// разбор командной строки +// command line parsing while ((opt = getopt(argc, argv, "d:hp:mersng:kf")) != -1) { switch (opt) { - case 'h': - -printf("\n Утилита предназначена для прошивки модемов на чипсете Balong V7\n\n\ -%s [ключи] <имя файла для загрузки или имя каталога с файлами>\n\n\ - Допустимы следующие ключи:\n\n" + case 'h': + +printf("\n This utility is intended for flashing modems with a Balong V7 chipset\n\n\ +%s [options] \n\n\ + Following options are allowed:\n\n" #ifndef WIN32 -"-p - последовательный порт для общения с загрузчиком (по умолчанию /dev/ttyUSB0)\n" +"-p - Serial port for communicating with the bootloader (by default /dev/ttyUSB0)\n" #else -"-p # - номер последовательного порта для общения с загрузчиком (например, -p8)\n" -" если ключ -p не указан, производится автоопределение порта\n" +"-p # - Number of the serial port for communicating with the loader (e.g. -p8)\n" +" if the -p option is not specified, the port is auto-detected\n" #endif -"-n - режим мультифайловой прошивки из указанного каталога\n\ --g# - установка режима цифровой подписи\n\ - -gl - описание параметров\n\ - -gd - запрет автоопределения подписи\n\ --m - вывести карту файла прошивки и завершить работу\n\ --e - разобрать файл прошивки на разделы без заголовков\n\ --s - разобрать файл прошивки на разделы с заголовками\n\ --k - не перезагружать модем по окончании прошивки\n\ --r - принудительно перезагрузить модем без прошивки разделов\n\ --f - прошить даже при наличии ошибок CRC в исходном файле\n\ --d# - установка типа прошивки (DLOAD_ID, 0..7), -dl - список типов\n\ +"-n - Multi-file firmware from a specified directory\n\ +-g# - Set digital signature mode\n\ + -gl - parameter definition\n\ + -gd - disable signature autodetection\n\ +-m - Display the firmware file map and exit\n\ +-e - Disassemble the firmware file into partitions without headers\n\ +-s - Disassemble the firmware file into partitions with headers\n\ +-k - Don't restart the modem after flashing\n\ +-r - Force reboot of the modem without flashing partitions\n\ +-f - Flash even if there are CRC errors in the source file\n\ +-d# - Set the firmware type (DLOAD_ID, 0...7), -dl - List of types\n\ \n",argv[0]); return 0; @@ -88,23 +88,23 @@ printf("\n Утилита предназначена для прошивки м case 'm': mflag=1; break; - + case 'n': nflag=1; break; - + case 'f': fflag=1; break; - + case 'r': rflag=1; break; - + case 'k': kflag=1; break; - + case 'e': eflag=1; break; @@ -116,85 +116,86 @@ printf("\n Утилита предназначена для прошивки м case 'g': gparm(optarg); break; - + case 'd': dparm(optarg); break; - + case '?': - case ':': + case ':': return -1; } -} -printf("\n Программа для прошивки устройств на Balong-чипсете, V3.0.%i, (c) forth32, 2015, GNU GPLv3",BUILDNO); +} +printf("\n Program for flashing Balong-chipset devices, V3.0.%i, (c) forth32, 2015, GNU GPLv3\n",BUILDNO); +printf("English Version (c) robertzaage, 2022\n"); #ifdef WIN32 -printf("\n Порт для Windows 32bit (c) rust3028, 2016"); +printf("Windows Port 32bit (c) rust3028, 2016\n"); #endif printf("\n--------------------------------------------------------------------------------------------------\n"); if (eflag&sflag) { - printf("\n Ключи -s и -e несовместимы\n"); + printf("\n The -s and -e options are incompatible\n"); return -1; -} +} if (kflag&rflag) { - printf("\n Ключи -k и -r несовместимы\n"); + printf("\n The -k and -r options are incompatible\n"); return -1; -} +} if (nflag&(eflag|sflag|mflag)) { - printf("\n Ключ -n несовместим с ключами -s, -m и -e\n"); + printf("\n The -n option is incompatible with -s, -m, and -e options\n"); return -1; -} - +} + -// ------ перезагрузка без указания файла +// reboot without specifying a file //-------------------------------------------- -if ((optind>=argc)&rflag) goto sio; +if ((optind>=argc)&rflag) goto sio; -// Открытие входного файла +// open an input file //-------------------------------------------- if (optind>=argc) { if (nflag) - printf("\n - Не указан каталог с файлами\n"); - else - printf("\n - Не указано имя файла для загрузки, используйте ключ -h для подсказки\n"); + printf("\n - Directory containing the files is not specified\n"); + else + printf("\n - No file name specified, use the -h option to display help\n"); return -1; -} +} -if (nflag) - // для -n - просто копируем префикс +if (nflag) + // for -n - just copy the prefix strncpy(fdir,argv[optind],39); else { - // для однофайловых операций + // for single-file operations in=fopen(argv[optind],"rb"); if (in == 0) { - printf("\n Ошибка открытия %s",argv[optind]); + printf("\n Can't open file %s",argv[optind]); return -1; } } -// Поиск разделов внутри файла +// search for partitions within a file if (!nflag) { findparts(in); show_fw_info(); -} +} -// Поиск файлов прошивок в указанном каталоге +// search for firmware files in a specified directory else findfiles(fdir); - -//------ Режим вывода карты файла прошивки + +// firmware file map output if (mflag) show_file_map(); -// выход по ошибкам CRC +// CRC error ouput if (!fflag && errflag) { - printf("\n\n! Входной файл содержит ошибки - завершаем работу\n"); - return -1; + printf("\n\n! Input file contains errors - exiting\n"); + return -1; } -//------- Режим разрезания файла прошивки +// split firmware file if (eflag|sflag) { fwsplit(sflag); printf("\n"); @@ -202,54 +203,51 @@ if (eflag|sflag) { } sio: -//--------- Основной режим - запись прошивки -//-------------------------------------------- +// standard procedure - flash firmware -// Настройка SIO +// SIO setup open_port(devname); -// Определяем режим порта и версию dload-протокола +// define port and dload protocol version res=dloadversion(); if (res == -1) return -2; if (res == 0) { - printf("\n Модем уже находится в HDLC-режиме"); + printf("\n Modem is already in HDLC mode"); goto hdlc; } -// Если надо, отправляем команду цифровой подписи +// if necessary, send a digital signature command if (gflag != -1) send_signver(); -// Входим в HDLC-режим - +// enter HDLC mode usleep(100000); enter_hdlc(); -// Вошли в HDLC +// we have entered HDLC mode //------------------------------ hdlc: -// получаем версию протокола и идентификатор устройства +// get the protocol version and the device identifier protocol_version(); dev_ident(); - printf("\n----------------------------------------------------\n"); if ((optind>=argc)&rflag) { - // перезагрузка без указания файла + // reboot without pointing a file restart_modem(); exit(0); -} +} -// Записываем всю флешку +// flash all memory flash_all(); printf("\n"); port_timeout(1); -// выходим из режима HDLC и перезагружаемся +// exit HDLC mode and reboot if (rflag || !kflag) restart_modem(); -// выход из HDLC без перезагрузки +// exit HDLC mode without rebooting else leave_hdlc(); -} +} diff --git a/flasher.c b/flasher.c index a8bdec2..9770298 100644 --- a/flasher.c +++ b/flasher.c @@ -27,35 +27,34 @@ //*************************************************** -//* Хранилище кода ошибки +//* Error code //*************************************************** int errcode; - //*************************************************** -//* Вывод кода ошибки команды +//* Error code output command //*************************************************** void printerr() { - -if (errcode == -1) printf(" - таймаут команды\n"); -else printf(" - код ошибки %02x\n",errcode); + +if (errcode == -1) printf(" - Timeout\n"); +else printf(" - Error Code %02x\n",errcode); } //*************************************************** -// Отправка команды начала раздела -// -// code - 32-битный код раздела -// size - полный размер записываемого раздела -// -//* результат: -// false - ошибка -// true - команда принята модемом +// Send partition start command +// +// code - 32-bit partition code +// size - full size of the writable partition +// +//* result: +// false - error +// true - command was accepted by the modem //*************************************************** int dload_start(uint32_t code,uint32_t size) { -uint32_t iolen; +uint32_t iolen; uint8_t replybuf[4096]; - + #ifndef WIN32 static struct __attribute__ ((__packed__)) { #else @@ -79,19 +78,19 @@ errcode=replybuf[3]; if ((iolen == 0) || (replybuf[1] != 2)) { if (iolen == 0) errcode=-1; return false; -} +} else return true; -} +} //*************************************************** -// Отправка блока раздела -// -// blk - # блока -// pimage - адрес начала образа раздела в памяти -// -//* результат: -// false - ошибка -// true - команда принята модемом +// Sending a partition block +// +// blk - # of block +// pimage - address of the partition image start in memory +// +//* result: +// false - error +// true - command was accepted by the modem //*************************************************** int dload_block(uint32_t part, uint32_t blk, uint8_t* pimage) { @@ -108,25 +107,25 @@ static struct { uint32_t blk; uint16_t bsize; uint8_t data[fblock]; -} cmd_dload_block; +} cmd_dload_block; #ifdef WIN32 #pragma pack(pop) #endif -blksize=fblock; // начальное значение размера блока -res=ptable[part].hd.psize-blk*fblock; // размер оставшегося куска до конца файла -if (res #include @@ -18,41 +18,41 @@ unsigned int nand_cmd=0x1b400000; unsigned int spp=0; unsigned int pagesize=0; unsigned int sectorsize=512; -unsigned int maxblock=0; // Общее число блоков флешки +unsigned int maxblock=0; // total number of flash blocks char flash_mfr[30]={0}; char flash_descr[30]={0}; unsigned int oobsize=0; -static char pdev[500]; // имя последовательного порта +static char pdev[500]; // serial port name -int siofd; // fd для работы с Последовательным портом +int siofd; // fd to work with the serial port struct termios sioparm; -//int siofd; // fd для работы с Последовательным портом +//int siofd; // fd for serial port operation //************************************************* -//* отсылка буфера в модем +//* Send buffer to modem //************************************************* unsigned int send_unframed_buf(char* outcmdbuf, unsigned int outlen) { -tcflush(siofd,TCIOFLUSH); // сбрасываем недочитанный буфер ввода +tcflush(siofd,TCIOFLUSH); // reset unread input buffer -write(siofd,"\x7e",1); // отсылаем префикс +write(siofd,"\x7e",1); // send prefix -if (write(siofd,outcmdbuf,outlen) == 0) { printf("\n Ошибка записи команды");return 0; } -tcdrain(siofd); // ждем окончания вывода блока +if (write(siofd,outcmdbuf,outlen) == 0) { printf("\n Command writing error");return 0; } +tcdrain(siofd); // waiting for the end of the block output return 1; } //****************************************************************************************** -//* Прием буфера с ответом из модема +//* Receiving buffer with response from modem //* -//* masslen - число байтов, принимаемых единым блоком без анализа признака конца 7F +//* masslen is the number of bytes received in a single block without analysis of 7F end sign //****************************************************************************************** unsigned int receive_reply(char* iobuf, int masslen) { - + int i,iolen,escflag,incount; unsigned char c; unsigned int res; @@ -60,60 +60,60 @@ unsigned char replybuf[14000]; incount=0; if (read(siofd,&c,1) != 1) { -// printf("\n Нет ответа от модема"); - return 0; // модем не ответил или ответил неправильно +// printf("\n No response from modem"); + return 0; // modem didn't answer or answered incorrectly } //if (c != 0x7e) { -// printf("\n Первый байт ответа - не 7e: %02x",c); -// return 0; // модем не ответил или ответил неправильно +// printf("\n First byte of the answer is not 7e: %02x",c); +// return 0; // modem didn't answer or answered incorrectly //} replybuf[incount++]=c; -// чтение массива данных единым блоком при обработке команды 03 +// read an array of data in a single block when processing command 03 if (masslen != 0) { res=read(siofd,replybuf+1,masslen-1); if (res != (masslen-1)) { - printf("\nСлишком короткий ответ от модема: %i байт, ожидалось %i байт\n",res+1,masslen); + printf("\nResponse from the modem is too short: %i bytes, expected %i bytes\n",res+1,masslen); dump(replybuf,res+1,0); return 0; - } - incount+=masslen-1; // у нас в буфере уже есть masslen байт + } + incount+=masslen-1; // we already have a masslen byte in the buffer // printf("\n ------ it mass --------"); // dump(replybuf,incount,0); } -// принимаем оставшийся хвост буфера +// take the remaining tail of the buffer while (read(siofd,&c,1) == 1) { replybuf[incount++]=c; // printf("\n-- %02x",c); if (c == 0x7e) break; } -// Преобразование принятого буфера для удаления ESC-знаков +// conversion of the received buffer to remove ESC characters escflag=0; iolen=0; -for (i=0;i'9')) dflag=0; } -// Если в строке - только цифры, добавляем префикс /dev/ttyUSB +// if there are only digits in the string, add the prefix /dev/ttyUSB if (dflag) strcpy(devstr,"/dev/ttyUSB"); -// копируем имя устройства +// copy the device name strcat(devstr,devname); siofd = open(devstr, O_RDWR | O_NOCTTY |O_SYNC); if (siofd == -1) { - printf("\n! - Последовательный порт %s не открывается\n", devname); + printf("\n! - Can't open serial port %s\n", devname); exit(0); } -bzero(&sioparm, sizeof(sioparm)); // готовим блок атрибутов termios +bzero(&sioparm, sizeof(sioparm)); // prepare the attribute block termios sioparm.c_cflag = B115200 | CS8 | CLOCAL | CREAD ; sioparm.c_iflag = 0; // INPCK; sioparm.c_oflag = 0; sioparm.c_lflag = 0; -sioparm.c_cc[VTIME]=30; // timeout -sioparm.c_cc[VMIN]=0; +sioparm.c_cc[VTIME]=30; // timeout +sioparm.c_cc[VMIN]=0; tcsetattr(siofd, TCSANOW, &sioparm); -tcflush(siofd,TCIOFLUSH); // очистка выходного буфера +tcflush(siofd,TCIOFLUSH); // cleaning output buffer return 1; } //************************************* -// Настройка времени ожидания порта +// set the timeout time of the port //************************************* void port_timeout(int timeout) { -bzero(&sioparm, sizeof(sioparm)); // готовим блок атрибутов termios +bzero(&sioparm, sizeof(sioparm)); // prepare the attribute block termios sioparm.c_cflag = B115200 | CS8 | CLOCAL | CREAD ; sioparm.c_iflag = 0; // INPCK; sioparm.c_oflag = 0; sioparm.c_lflag = 0; -sioparm.c_cc[VTIME]=timeout; // timeout -sioparm.c_cc[VMIN]=0; +sioparm.c_cc[VTIME]=timeout; // timeout +sioparm.c_cc[VMIN]=0; tcsetattr(siofd, TCSANOW, &sioparm); } //************************************************* -//* Поиск файла по номеру в указанном каталоге +//* Search for a file by its number in the specified directory //* -//* num - # файла -//* filename - буфер для полного имени файла -//* id - переменная, в которую будет записан идентификатор раздела +//* num - # of file +//* filename - buffer for full file name +//* id - variable, where the partition identifier will be written //* -//* return 0 - не найдено -//* 1 - найдено +//* return +//* 0 - not found +//* 1 - found //************************************************* int find_file(int num, char* dirname, char* filename,unsigned int* id, unsigned int* size) { @@ -244,62 +245,61 @@ unsigned int pt; struct dirent* dentry; char fpattern[5]; -sprintf(fpattern,"%02i",num); // образец для поиска файла по 3 цифрам номера +sprintf(fpattern,"%02i",num); // sample file search by 3 digits of the number fdir=opendir(dirname); if (fdir == 0) { - printf("\n Каталог %s не открывается\n",dirname); + printf("\n Can't open directory %s\n",dirname); exit(1); } -// главный цикл - поиск нужного нам файла +// main loop - search for the file we need while ((dentry=readdir(fdir)) != 0) { - if (dentry->d_type != DT_REG) continue; // пропускаем все кроме регулярных файлов - if (strncmp(dentry->d_name,fpattern,2) == 0) break; // нашли нужный файл. Точнее, файл с нужными 3 цифрами в начале имени. + if (dentry->d_type != DT_REG) continue; // skip everything except regular files + if (strncmp(dentry->d_name,fpattern,2) == 0) break; // we have found the file we need. More precisely, the file with the required 3 digits in the beginning of its name. } closedir(fdir); -// формируем полное имя файла в буфере результата -if (dentry == 0) return 0; // не нашли +// create a full filename in the result buffer +if (dentry == 0) return 0; // not found strcpy(filename,dirname); strcat(filename,"/"); -// копируем имя файла в буфер результата -strcat(filename,dentry->d_name); +// copy the file name into the result buffer +strcat(filename,dentry->d_name); // 00-00000200-M3Boot.bin -//проверяем имя файла на наличие знаков '-' +// check the file name for '-' signs if ((dentry->d_name[2] != '-') || (dentry->d_name[11] != '-')) { - printf("\n Неправильный формат имени файла - %s\n",dentry->d_name); + printf("\n Incorrect format of file - %s\n",dentry->d_name); exit(1); } -// проверяем цифровое поле ID раздела +// check the numeric partition ID field if (strspn(dentry->d_name+3,"0123456789AaBbCcDdEeFf") != 8) { - printf("\n Ошибка в идентификаторе раздела - нецифровой знак - %s\n",filename); + printf("\n Partition ID error - non-digit character - %s\n",filename); exit(1); -} +} sscanf(dentry->d_name+3,"%8x",id); -// Проверяем доступность и читаемость файла +// check file availability and readability in=fopen(filename,"r"); if (in == 0) { - printf("\n Ошибка открытия файла %s\n",filename); + printf("\n Can't open file %s\n",filename); exit(1); } if (fread(&pt,1,4,in) != 4) { - printf("\n Ошибка чтения файла %s\n",filename); + printf("\n Can't read file %s\n",filename); exit(1); } - -// проверяем, что файл - сырой образ, без заголовка + +// check that the file is a raw image, without a header if (pt == 0xa55aaa55) { - printf("\n Файл %s имеет заголовок - для прошивки не подходит\n",filename); + printf("\n File %s has a header - not suitable for flashing\n",filename); exit(1); } +// What else can I check? I haven't figured it out yet. -// Что еще можно проверить? Пока не придумал. - -// Получаем размер файла +// get the file size fseek(in,0,SEEK_END); *size=ftell(in); fclose(in); @@ -308,12 +308,12 @@ return 1; } //**************************************************** -//* Отсылка модему АТ-команды -//* -//* cmd - буфер с командой -//* rbuf - буфер для записи ответа +//* Send AT command to modem +//* +//* cmd - command buffer +//* rbuf - response buffer //* -//* Возвращает длину ответа +//* Returns the length of answer //**************************************************** int atcmd(char* cmd, char* rbuf) { @@ -325,15 +325,14 @@ strcat(cbuf,cmd); strcat(cbuf,"\r"); port_timeout(100); -// Вычищаем буфер приемника и передатчика +// clean up the receiver and transmitter buffer tcflush(siofd,TCIOFLUSH); -// отправка команды +// send command write(siofd,cbuf,strlen(cbuf)); usleep(100000); -// чтение результата +// read result res=read(siofd,rbuf,200); return res; } - diff --git a/ptable.c b/ptable.c index afe6a1d..2f36e04 100644 --- a/ptable.c +++ b/ptable.c @@ -1,4 +1,4 @@ -// Процедуры работы с таблицей разделов +// Partition table procedures #include #include @@ -20,7 +20,7 @@ int32_t lzma_decode(uint8_t* inbuf,uint32_t fsize,uint8_t* outbuf); //****************************************************** -//* поиск символического имени раздела по его коду +//* Search for a symbolic partition name by its code //****************************************************** void find_pname(unsigned int id,unsigned char* pname) { @@ -29,10 +29,10 @@ unsigned int j; struct { char name[20]; int code; -} pcodes[]={ - {"M3Boot",0x20000}, - {"M3Boot-ptable",0x10000}, - {"M3Boot_R11",0x200000}, +} pcodes[]={ + {"M3Boot",0x20000}, + {"M3Boot-ptable",0x10000}, + {"M3Boot_R11",0x200000}, {"Ptable",0x10000}, {"Ptable_ext_A",0x480000}, {"Ptable_ext_B",0x490000}, @@ -52,9 +52,9 @@ struct { {"Nvimg",0x80000}, {"System",0x590000}, {"System",0x100000}, - {"APP",0x570000}, - {"APP",0x5a0000}, - {"APP_EXT_A",0x450000}, + {"APP",0x570000}, + {"APP",0x5a0000}, + {"APP_EXT_A",0x450000}, {"APP_EXT_B",0x460000}, {"Oeminfo",0xa0000}, {"CDROMISO",0xb0000}, @@ -88,74 +88,71 @@ struct { for(j=0;pcodes[j].code != 0;j++) { if(pcodes[j].code == id) break; } -if (pcodes[j].code != 0) strcpy(pname,pcodes[j].name); // имя найдено - копируем его в структуру -else sprintf(pname,"U%08x",id); // имя не найдено - подставляем псевдоимя Uxxxxxxxx в тупоконечном формате +if (pcodes[j].code != 0) strcpy(pname,pcodes[j].name); // name is found - copy it into the structure +else sprintf(pname,"U%08x",id); // name not found - substitute the pseudo name Uxxxxxxxxxx in blunt-end format } //******************************************************************* -// Вычисление размера блока контрольных сумм раздела +// Calculation of partition checksum block size //******************************************************************* -uint32_t crcsize(int n) { - return ptable[n].hd.hdsize-sizeof(struct pheader); - +uint32_t crcsize(int n) { + return ptable[n].hd.hdsize-sizeof(struct pheader); } //******************************************************************* -// получение размера образа раздела +// Obtaining partition image size //******************************************************************* -uint32_t psize(int n) { - return ptable[n].hd.psize; - +uint32_t psize(int n) { + return ptable[n].hd.psize; } //******************************************************* -//* Вычисление блочной контрольной суммы заголовка +//* Header block checksum calculation //******************************************************* -void calc_hd_crc16(int n) { +void calc_hd_crc16(int n) { -ptable[n].hd.crc=0; // очищаем старую CRC-сумму -ptable[n].hd.crc=crc16((uint8_t*)&ptable[n].hd,sizeof(struct pheader)); +ptable[n].hd.crc=0; // clear old CRC sum +ptable[n].hd.crc=crc16((uint8_t*)&ptable[n].hd,sizeof(struct pheader)); } //******************************************************* -//* Вычисление блочной контрольной суммы раздела +//* Calculating the block checksum of a partition //******************************************************* void calc_crc16(int n) { - -uint32_t csize; // размер блока сумм в 16-битных словах -uint16_t* csblock; // указатель на создаваемый блок + +uint32_t csize; // block size sum in 16-bit words +uint16_t* csblock; // pointer to created block uint32_t off,len; uint32_t i; -uint32_t blocksize=ptable[n].hd.blocksize; // размер блока, охватываемого суммой +uint32_t blocksize=ptable[n].hd.blocksize; // size of the block covered by the sum -// определяем размер и создаем блок +// determine the size and create the block csize=psize(n)/blocksize; -if (psize(n)%blocksize != 0) csize++; // Это если размер образа не кратен blocksize +if (psize(n)%blocksize != 0) csize++; // this is if the image size is not a multiple of blocksize csblock=(uint16_t*)malloc(csize*2); -// цикл вычисления сумм +// loop for sum calculation for (i=0;i>16); + printf("\n! Partition %s (%02x) - header checksum error",ptable[npart].pname,ptable[npart].hd.code>>16); errflag=1; -} -ptable[npart].hd.crc=crc; // восстанавливаем CRC +} +ptable[npart].hd.crc=crc; // recover CRC -// вычисляем и проверяем CRC раздела +// calculate and check the CRC of the partition calc_crc16(npart); if (crcblocksize != crcsize(npart)) { - printf("\n! Раздел %s (%02x) - неправильный размер блока контрольных сумм",ptable[npart].pname,ptable[npart].hd.code>>16); + printf("\n! Partition %s (%02x) - Incorrect checksum block size",ptable[npart].pname,ptable[npart].hd.code>>16); errflag=1; -} - +} else if (memcmp(crcblock,ptable[npart].csumblock,crcblocksize) != 0) { - printf("\n! Раздел %s (%02x) - неправильная блочная контрольная сумма",ptable[npart].pname,ptable[npart].hd.code>>16); + printf("\n! Partition %s (%02x) - incorrect block checksum",ptable[npart].pname,ptable[npart].hd.code>>16); errflag=1; -} - -free(crcblock); +} +free(crcblock); ptable[npart].ztype=' '; -// Определение zlib-сжатия - +// definition of zlib-compression if ((*(uint16_t*)ptable[npart].pimage) == 0xda78) { - ptable[npart].zflag=ptable[npart].hd.psize; // сохраняем сжатый размер + ptable[npart].zflag=ptable[npart].hd.psize; // keep the compressed size zlen=52428800; - zbuf=malloc(zlen); // буфер в 50М - // распаковываем образ раздела + zbuf=malloc(zlen); // buffer of 50М + // unpack the partition image res=uncompress (zbuf, &zlen, ptable[npart].pimage, ptable[npart].hd.psize); if (res != Z_OK) { - printf("\n! Ошибка распаковки раздела %s (%02x)\n",ptable[npart].pname,ptable[npart].hd.code>>16); + printf("\n! Error unpacking partition %s (%02x)\n",ptable[npart].pname,ptable[npart].hd.code>>16); errflag=1; } - // создаем новый буфер образа раздела и копируем в него рапаковынные данные + // create a new partition image buffer and copy the unpacked data into it free(ptable[npart].pimage); ptable[npart].pimage=malloc(zlen); memcpy(ptable[npart].pimage,zbuf,zlen); ptable[npart].hd.psize=zlen; free(zbuf); - // перерассчитываем контрольные суммы + // recalculate the checksums calc_crc16(npart); ptable[npart].hd.crc=crc16((uint8_t*)&ptable[npart].hd,sizeof(struct pheader)); ptable[npart].ztype='Z'; } -// Определение lzma-сжатия +// lzma compression detection if ((ptable[npart].pimage[0] == 0x5d) && (*(uint64_t*)(ptable[npart].pimage+5) == 0xffffffffffffffff)) { - ptable[npart].zflag=ptable[npart].hd.psize; // сохраняем сжатый размер + ptable[npart].zflag=ptable[npart].hd.psize; // keep the compressed size zlen=100 * 1024 * 1024; - zbuf=malloc(zlen); // буфер в 100М - // распаковываем образ раздела + zbuf=malloc(zlen); // buffer of 100М + // unpack the partition image zlen=lzma_decode(ptable[npart].pimage, ptable[npart].hd.psize, zbuf); if (zlen>100 * 1024 * 1024) { - printf("\n Превышен размер буфера\n"); + printf("\n Buffer size exceeded\n"); exit(1); - } + } if (res == -1) { - printf("\n! Ошибка распаковки раздела %s (%02x)\n",ptable[npart].pname,ptable[npart].hd.code>>16); + printf("\n! Error unpacking partition %s (%02x)\n",ptable[npart].pname,ptable[npart].hd.code>>16); errflag=1; } - // создаем новый буфер образа раздела и копируем в него рапаковынные данные + // create a new partition image buffer and copy the unpacked data into it free(ptable[npart].pimage); ptable[npart].pimage=malloc(zlen); memcpy(ptable[npart].pimage,zbuf,zlen); ptable[npart].hd.psize=zlen; free(zbuf); - // перерассчитываем контрольные суммы + // recalculate the checksums calc_crc16(npart); ptable[npart].hd.crc=crc16((uint8_t*)&ptable[npart].hd,sizeof(struct pheader)); ptable[npart].ztype='L'; } - - -// продвигаем счетчик разделов + +// advance the partition counter npart++; -// отъезжаем, если надо, вперед на границу слова +// move forward to the word boundary if necessary res=ftell(in); if ((res&3) != 0) fseek(in,(res+4)&(~3),SEEK_SET); } - //******************************************************* -//* Поиск разделов в файле прошивки -//* -//* возвращает число найденных разделов +//* Search for partitions in firmware file +//* +//* returns number of found partitions //******************************************************* int findparts(FILE* in) { -// буфер префикса BIN-файла +// BIN file prefix buffer uint8_t prefix[0x5c]; int32_t signsize; int32_t hd_dload_id; -// Маркер начала заголовка раздела +// partition header start marker const unsigned int dpattern=0xa55aaa55; unsigned int i; -// поиск начала цепочки разделов в файле +// search for the beginning of the partition chain in the file while (fread(&i,1,4,in) == 4) { if (i == dpattern) break; } if (feof(in)) { - printf("\n В файле не найдены разделы - файл не содержит образа прошивки\n"); + printf("\n No partitions found in file - the file does not contain a firmware image\n"); exit(0); -} +} -// текущая позиция в файле должна быть не ближе 0x60 от начала - размер заголовка всего файла +// the current position in the file should be no closer than 0x60 from the beginning - the header size of the whole file if (ftell(in)<0x60) { - printf("\n Заголовок файла имеет неправильный размер\n"); + printf("\n Wrong file header size\n"); exit(0); -} -fseek(in,-0x60,SEEK_CUR); // отъезжаем на начало BIN-файла +} +fseek(in,-0x60,SEEK_CUR); // move to the beginning of the BIN-file -// вынимаем префикс +// take out the prefix fread(prefix,0x5c,1,in); hd_dload_id=prefix[0]; -// если принудительно dload_id не установлен - выбираем его из заголовка +// if dload_id is not set forcibly - select it from the header if (dload_id == -1) dload_id=hd_dload_id; if (dload_id > 0xf) { - printf("\n Неверный код типа прошивки (dload_id) в заголовке - %x",dload_id); + printf("\n Incorrect firmware type code (dload_id) in header - %x",dload_id); exit(0); -} -printf("\n Код файла прошивки: %x (%s)\n",hd_dload_id,fw_description(hd_dload_id)); +} +printf("\n Firmware file code: %x (%s)\n",hd_dload_id,fw_description(hd_dload_id)); -// поиск остальных разделов +// search for other partitions do { - printf("\r Поиск раздела # %i",npart); fflush(stdout); - if (fread(&i,1,4,in) != 4) break; // конец файла - if (i != dpattern) break; // образец не найден - конец цепочки разделов - fseek(in,-4,SEEK_CUR); // отъезжаем назад, на начало заголовка - extract(in); // извлекаем раздел + printf("\r Searching for partition # %i",npart); fflush(stdout); + if (fread(&i,1,4,in) != 4) break; // end of file + if (i != dpattern) break; // sample not found - end of partition chain + fseek(in,-4,SEEK_CUR); // move back to the beginning of header + extract(in); // extract partition } while(1); printf("\r \r"); -// ищем цифровую подпись +// look for a digital signature signsize=serach_sign(); -if (signsize == -1) printf("\n Цифровая подпись: не найдена"); +if (signsize == -1) printf("\n Digital Signature: Not found"); else { - printf("\n Цифровая подпись: %i байт",signsize); - printf("\n Хеш открытого ключа: %s",signver_hash); + printf("\n Digital Signature: %i bytes",signsize); + printf("\n Public Key Hash: %s",signver_hash); } if (((signsize == -1) && (dload_id>7)) || - ((signsize != -1) && (dload_id<8))) - printf("\n ! ВНИМАНИЕ: Наличие цифровой подписи не соответствует коду типа прошивки: %02x",dload_id); - + ((signsize != -1) && (dload_id<8))) + printf("\n ! WARNING: The present of a digital signature does not match the firmware type code: %02x",dload_id); return npart; } - //******************************************************* -//* Поиск разделов в многофайловом режиме +//* Partition search in multi-file procedure //******************************************************* void findfiles (char* fdir) { -char filename[200]; +char filename[200]; FILE* in; - -printf("\n Поиск файлов-образов разделов...\n\n ## Размер ID Имя Файл\n-----------------------------------------------------------------\n"); + +printf("\n Searching for partition image files...\n\n ## Size ID Name File\n-----------------------------------------------------------------\n"); for (npart=0;npart<30;npart++) { - if (find_file(npart, fdir, filename, &ptable[npart].hd.code, &ptable[npart].hd.psize) == 0) break; // конец поиска - раздела с таким ID не нашли - // получаем символическое имя раздела + if (find_file(npart, fdir, filename, &ptable[npart].hd.code, &ptable[npart].hd.psize) == 0) break; // end of search - no partition with this ID was found + // get the symbolic name of the partition find_pname(ptable[npart].hd.code,ptable[npart].pname); printf("\n %02i %8i %08x %-14.14s %s",npart,ptable[npart].hd.psize,ptable[npart].hd.code,ptable[npart].pname,filename);fflush(stdout); - - // распределяем память под образ раздела + + // allocate memory for the partition image ptable[npart].pimage=malloc(ptable[npart].hd.psize); if (ptable[npart].pimage == 0) { - printf("\n! Ошибка распределения памяти, раздел #%i, размер = %i байт\n",npart,ptable[npart].hd.psize); + printf("\n! Memory allocation error, partition #%i, size = %i bytes\n",npart,ptable[npart].hd.psize); exit(0); } - - // читаем образ в буфер + + // read image to buffer in=fopen(filename,"rb"); if (in == 0) { - printf("\n Ошибка открытия файла %s",filename); + printf("\n Can't open file %s",filename); return; - } + } fread(ptable[npart].pimage,ptable[npart].hd.psize,1,in); fclose(in); - } if (npart == 0) { - printf("\n! Не найдено ни одного файла с образом раздела в каталоге %s",fdir); + printf("\n! No partition image files were found in directory %s",fdir); exit(0); -} } - +} diff --git a/ptable.h b/ptable.h index e6f6c3f..5f58ee1 100644 --- a/ptable.h +++ b/ptable.h @@ -1,46 +1,43 @@ - - -// структура описания заголовка раздела +// partition header structure description #ifndef WIN32 struct __attribute__ ((__packed__)) pheader { #else #pragma pack(push,1) struct pheader { #endif - int32_t magic; // 0xa55aaa55 - uint32_t hdsize; // размер заголовка + int32_t magic; // 0xa55aaa55 + uint32_t hdsize; // header size uint32_t hdversion; uint8_t unlock[8]; - uint32_t code; // тип раздела - uint32_t psize; // разме поля данных + uint32_t code; // partition type + uint32_t psize; // data field size uint8_t date[16]; - uint8_t time[16]; // дата-время сборки прошивки - uint8_t version[32]; // версия пршоивки - uint16_t crc; // CRC заголовка - uint32_t blocksize; // размер блока CRC образа прошивки -}; + uint8_t time[16]; // date of firmware build + uint8_t version[32]; // firmware version + uint16_t crc; // CRC header + uint32_t blocksize; // size of CRC block of firmware image +}; #ifdef WIN32 #pragma pack(pop) #endif - -// Структура описания таблицы разделов +// partition table structure description struct ptb_t{ - unsigned char pname[20]; // буквенное имя раздела - struct pheader hd; // образ заголовка - uint16_t* csumblock; // блок контрольных сумм - uint8_t* pimage; // образ раздела - uint32_t offset; // смещение в файле до начала раздела - uint32_t zflag; // признак сжатого раздела - uint8_t ztype; // тип сжатия + unsigned char pname[20]; // alphabetic name of the partition + struct pheader hd; // header image + uint16_t* csumblock; // checksum block + uint8_t* pimage; // partition image + uint32_t offset; // offset in file before start of partition + uint32_t zflag; // flag of a compressed partition + uint8_t ztype; // compression type }; //****************************************************** -//* Внешние массивы для хранения таблицы разделов +//* External arrays to store the partition table //****************************************************** extern struct ptb_t ptable[]; -extern int npart; // число разделов в таблице +extern int npart; // number of partitions in table extern uint32_t errflag; diff --git a/signver.c b/signver.c index 0fb3414..84b142f 100644 --- a/signver.c +++ b/signver.c @@ -1,7 +1,5 @@ -// +// Procedures for digital signature processing -// Процедуры обработки цифровых подписей -// #include #include #ifndef WIN32 @@ -27,24 +25,23 @@ #include "util.h" #include "zlib.h" -// таблица параметров ключа -g - +// table of key parameters -g struct { uint8_t type; uint32_t len; char* descr; } signbase[] = { - {1,2958,"Основная прошивка"}, - {1,2694,"Прошивка E3372s-stick"}, - {2,1110,"Вебинтерфейс+ISO для HLINK-модема"}, - {6,1110,"Вебинтерфейс+ISO для HLINK-модема"}, - {2,846,"ISO (dashboard) для stick-модема"}, - {7,3750,"Прошивка+ISO+вебинтерфейс"}, + {1,2958,"Basic Firmware"}, + {1,2694,"E3372s-Stick Firmware"}, + {2,1110,"Web-Interface + ISO for HiLink-Modem"}, + {6,1110,"Web-Interface + ISO for HiLink-Modem"}, + {2,846,"ISO (Dashboard) for Stick-Modem"}, + {7,3750,"Firmware + ISO + Web-Interface"}, }; #define signbaselen 6 -// таблица типов подписей +// table of signature types char* fwtypes[]={ "UNKNOWN", // 0 "ONLY_FW", // 1 @@ -54,43 +51,40 @@ char* fwtypes[]={ "FW_WEBUI", // 5 "ISO_WEBUI", // 6 "FW_ISO_WEBUI" // 7 -}; - +}; -// результирующая строка ^signver-команды +// result string ^signver-command uint8_t signver[200]; -// Флаг режима цифровой подписи +// digital type signature flag extern int gflag; -// Флаг типа прошивки +// firmware type flag extern int dflag; -// Параметры текущей цифровой подписи -uint32_t signtype; // тип прошивки -uint32_t signlen; // длина подписи +// parameters of the current digital signature +uint32_t signtype; // firmware type +uint32_t signlen; // signature length int32_t serach_sign(); -// Хеш открытого ключа для ^signver +// public key hash for ^signver char signver_hash[100]="778A8D175E602B7B779D9E05C330B5279B0661BF2EED99A20445B366D63DD697"; //**************************************************** -//* Получение описания типа прошивки по коду +//* Receiving of firmware type description by code //**************************************************** char* fw_description(uint8_t code) { - -return fwtypes[code&0x7]; +return fwtypes[code&0x7]; } //**************************************************** -//* Получение списка типов прошивок +//* Receiving of firmware type list //**************************************************** void dlist() { - int i; -printf("\n # Описание\n--------------------------------------"); +printf("\n # Description\n--------------------------------------"); for(i=1;i<8;i++) { printf("\n %i %s",i,fw_description(i)); } @@ -99,87 +93,85 @@ exit(0); } //*************************************************** -//* Обработка параметров ключа -d +//* Processing of key parameters -d //*************************************************** void dparm(char* sparm) { - + if (dflag != 0) { - printf("\n Дублирующийся ключ -d\n\n"); + printf("\n Duplicate option -d\n\n"); exit(-1); -} +} if (sparm[0] == 'l') { dlist(); exit(0); -} +} sscanf(sparm,"%x",&dload_id); if ((dload_id == 0) || (dload_id >7)) { - printf("\n Неправильное значение ключа -d\n\n"); + printf("\n Incorrect value for option -d\n\n"); exit(-1); } dflag=1; } - //**************************************************** -//* Получение списка параметров ключа -g +//* Get a list of -g key parameters //**************************************************** void glist() { - int i; -printf("\n # длина тип описание \n--------------------------------------"); +printf("\n # Length Type Description \n--------------------------------------"); for (i=0; i= signbaselen) goto perror; signlen=signbase[index].len; @@ -191,39 +183,38 @@ gflag=1; return; perror: - printf("\n Ошибка в параметрах ключа -g\n"); + printf("\n Incorrect value in option -g\n"); exit(-1); -} - +} //*************************************************** -//* Отправка цифровой подписи +//* Sending digital signature //*************************************************** void send_signver() { - + uint32_t res; -// ответ на ^signver +// response to ^signver unsigned char SVrsp[]={0x0d, 0x0a, 0x30, 0x0d, 0x0a, 0x0d, 0x0a, 0x4f, 0x4b, 0x0d, 0x0a}; uint8_t replybuf[200]; - -if (gflag == 0) { - // автоопределение цифровой подписи + +if (gflag == 0) { + // auto-detect digital signature signtype=dload_id&0x7; signlen=serach_sign(); - if (signlen == -1) return; // подпись в файле не найдена + if (signlen == -1) return; // no signature found in the file } -printf("\n Режим цифровой подписи: %s (%i байт)",fw_description(signtype),signlen); +printf("\n Digital Signature Type: %s (%i bytes)",fw_description(signtype),signlen); sprintf(signver,"^SIGNVER=%i,0,%s,%i",signtype,signver_hash,signlen); res=atcmd(signver,replybuf); if ( (res #include #ifndef WIN32 @@ -25,10 +24,8 @@ #include "flasher.h" #include "util.h" - - //*********************** -//* Дамп области памяти * +//* Memory area dump * //*********************** void dump(char buffer[],int len,long base) { @@ -54,9 +51,8 @@ for (i=0;i>8)&0xff); +for(i=0;i>8)&0xff); return (~crc)&0xffff; } //**************************************************** -//* Определение версии прошивальщика +//* Firmware Version Detection //* -//* 0 - нет ответа на команду -//* 1 - версия 2.0 -//* -1 - версия не 2.0 +//* 0 - No response to command +//* 1 - Version 2.0 +//* -1 - Version not 2.0 //**************************************************** int dloadversion() { -int res; -int i; +int res; +int i; uint8_t replybuf[4096]; res=atcmd("^DLOADVER?",replybuf); @@ -119,34 +115,34 @@ if (res == 0) return 0; if (strncmp(replybuf+2,"2.0",3) == 0) return 1; for (i=2;i2) printf("\n Идентификатор устройства: %s",replybuf+2); +if (iolen>2) printf("\n Device Identifier: %s",replybuf+2); } - //**************************************************** -//* Вывод карты файла прошивки +//* Firmware File Map Output //**************************************************** void show_file_map() { -int i; - -printf("\n\n ## Смещение Размер Сжатие Имя\n-----------------------------------------------"); -for (i=0;i + void dump(char buffer[],int len,long base); unsigned short crc16(char* buf, int len); int dloadversion();