Inital english version commit

master
Robert Zaage 2 years ago
parent bf43faa4b5
commit e701ca2b74

@ -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

@ -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.

@ -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] <boot file name or directory name>\n\n\
Following options are allowed:\n\n"
#ifndef WIN32
"-p <tty> - последовательный порт для общения с загрузчиком (по умолчанию /dev/ttyUSB0)\n"
"-p <tty> - 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();
}
}

@ -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<fblock) blksize=res; // корректируем размер последнего блока
blksize=fblock; // initial block size value
res=ptable[part].hd.psize-blk*fblock; // size of the remaining chunk to the end of the file
if (res<fblock) blksize=res; // correct the size of the last block
// код команды
// command code
cmd_dload_block.cmd=0x42;
// номер блока
// block number
cmd_dload_block.blk=htonl(blk+1);
// размер блока
// block size
cmd_dload_block.bsize=htons(blksize);
// порция данных из образа раздела
// portion of data from the partition image
memcpy(cmd_dload_block.data,pimage+blk*fblock,blksize);
// отсылаем блок в модем
iolen=send_cmd((uint8_t*)&cmd_dload_block,sizeof(cmd_dload_block)-fblock+blksize,replybuf); // отсылаем команду
// send block to the modem
iolen=send_cmd((uint8_t*)&cmd_dload_block,sizeof(cmd_dload_block)-fblock+blksize,replybuf); // send command
errcode=replybuf[3];
if ((iolen == 0) || (replybuf[1] != 2)) {
@ -136,16 +135,15 @@ if ((iolen == 0) || (replybuf[1] != 2)) {
return true;
}
//***************************************************
// Завершение записи раздела
//
// code - код раздела
// size - размер раздела
//
//* результат:
// false - ошибка
// true - команда принята модемом
// End partition recording
//
// code - partition code
// size - size of partition
//
//* result:
// false - error
// true - command was accepted by modem
//***************************************************
int dload_end(uint32_t code, uint32_t size) {
@ -177,51 +175,51 @@ errcode=replybuf[3];
if ((iolen == 0) || (replybuf[1] != 2)) {
if (iolen == 0) errcode=-1;
return false;
}
}
return true;
}
}
//***************************************************
//* Запись в модем всех разделов из таблицы
//* Writing all partitions from table to the modem
//***************************************************
void flash_all() {
int32_t part;
uint32_t blk,maxblock;
printf("\n## ---- Имя раздела ---- записано");
// Главный цикл записи разделов
printf("\n## ---- Partition name ---- Progress");
// main partition recording loop
for(part=0;part<npart;part++) {
printf("\n");
printf("\n");
// printf("\n02i %s)",part,ptable[part].pname);
// команда начала раздела
// command to start partitioning
if (!dload_start(ptable[part].hd.code,ptable[part].hd.psize)) {
printf("\r! Отвергнут заголовок раздела %i (%s)",part,ptable[part].pname);
printf("\r! Rejected partition %i (%s)",part,ptable[part].pname);
printerr();
exit(-2);
}
maxblock=(ptable[part].hd.psize+(fblock-1))/fblock; // число блоков в разделе
// Поблочный цикл передачи образа раздела
}
maxblock=(ptable[part].hd.psize+(fblock-1))/fblock; // number of blocks in the partition
// block cycle of partition image transfer
for(blk=0;blk<maxblock;blk++) {
// Вывод процента записанного
// output written percentage
printf("\r%02i %-20s %i%%",part,ptable[part].pname,(blk+1)*100/maxblock);
// Отсылаем очередной блок
// send next block
if (!dload_block(part,blk,ptable[part].pimage)) {
printf("\n! Отвергнут блок %i раздела %i (%s)",blk,part,ptable[part].pname);
printf("\n! Block %i of partition %i rejected (%s)",blk,part,ptable[part].pname);
printerr();
exit(-2);
}
}
}
}
// закрываем раздел
// finalizing partition
if (!dload_end(ptable[part].hd.code,ptable[part].hd.psize)) {
printf("\n! Ошибка закрытия раздела %i (%s)",part,ptable[part].pname);
printf("\n! Finalizing partition %i failed (%s)",part,ptable[part].pname);
printerr();
exit(-2);
}
} // конец цикла по разделам
}
} // end of partition cycle
}

@ -1,4 +1,4 @@
// размер блока данных, передаваемый модему за одну команду
// size of the block of data transmitted to the modem per command
#define fblock 4096
//#define fblock 2048

@ -1,4 +1,4 @@
extern int siofd; // fd для работы с Последовательным портом
extern int siofd; // fd to work with the serial port
int send_cmd(unsigned char* incmdbuf, int blen, unsigned char* iobuf);
int open_port(char* devname);

@ -1,4 +1,4 @@
// Низкоуровневые процедуры работы с последовательным портом и HDLC
// Low-level serial port and HDLC procedures
#include <stdio.h>
#include <stdlib.h>
@ -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<incount;i++) {
for (i=0;i<incount;i++) {
c=replybuf[i];
if ((c == 0x7e)&&(iolen != 0)) {
iobuf[iolen++]=0x7e;
break;
}
}
if (c == 0x7d) {
escflag=1;
continue;
}
if (escflag == 1) {
if (escflag == 1) {
c|=0x20;
escflag=0;
}
}
iobuf[iolen++]=c;
}
}
return iolen;
}
//***********************************************************
//* Преобразование командного буфера с Escape-подстановкой
//* Command buffer conversion with Escape-substitution
//***********************************************************
unsigned int convert_cmdbuf(char* incmdbuf, int blen, char* outcmdbuf) {
@ -122,49 +122,49 @@ unsigned char cmdbuf[14096];
bcnt=blen;
memcpy(cmdbuf,incmdbuf,blen);
// Вписываем CRC в конец буфера
// write the CRC at the end of the buffer
*((unsigned short*)(cmdbuf+bcnt))=crc16(cmdbuf,bcnt);
bcnt+=2;
// Пребразование данных с экранированием ESC-последовательностей
// data preprocessing with escaping of ESC-sequences
iolen=0;
outcmdbuf[iolen++]=cmdbuf[0]; // первый байт копируем без модификаций
outcmdbuf[iolen++]=cmdbuf[0]; // first byte is copied without modification
for(i=1;i<bcnt;i++) {
switch (cmdbuf[i]) {
case 0x7e:
outcmdbuf[iolen++]=0x7d;
outcmdbuf[iolen++]=0x5e;
break;
case 0x7d:
outcmdbuf[iolen++]=0x7d;
outcmdbuf[iolen++]=0x5d;
break;
default:
outcmdbuf[iolen++]=cmdbuf[i];
}
}
outcmdbuf[iolen++]=0x7e; // завершающий байт
outcmdbuf[iolen++]=0x7e; // end byte
outcmdbuf[iolen]=0;
return iolen;
}
//***************************************************
//* Отсылка команды в порт и получение результата *
//* Send a command to a port and receive the result
//***************************************************
int send_cmd(unsigned char* incmdbuf, int blen, unsigned char* iobuf) {
unsigned char outcmdbuf[14096];
unsigned int iolen;
iolen=convert_cmdbuf(incmdbuf,blen,outcmdbuf);
if (!send_unframed_buf(outcmdbuf,iolen)) return 0; // ошибка передачи команды
iolen=convert_cmdbuf(incmdbuf,blen,outcmdbuf);
if (!send_unframed_buf(outcmdbuf,iolen)) return 0; // command transmission error
return receive_reply(iobuf,0);
}
//***************************************************
// Открытие и настройка последовательного порта
// Opening and configuring the serial port
//***************************************************
int open_port(char* devname) {
@ -174,67 +174,68 @@ int i,dflag=1;
char devstr[200]={0};
if (strlen(devname) != 0) strcpy(pdev,devname); // сохраняем имя порта
else strcpy(devname,"/dev/ttyUSB0"); // если имя порта не было задано
if (strlen(devname) != 0) strcpy(pdev,devname); // save port name
else strcpy(devname,"/dev/ttyUSB0"); // if the port name is not set
// Вместо полного имени устройства разрешается передавать только номер ttyUSB-порта
// only the ttyUSB port number can be transmitted instead of the full device name
// Проверяем имя устройства на наличие нецифровых символов
// check the device name for the presence of nonnumeric characters
for(i=0;i<strlen(devname);i++) {
if ((devname[i]<'0') || (devname[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;
}

@ -1,4 +1,4 @@
// Процедуры работы с таблицей разделов
// Partition table procedures
#include <stdio.h>
#include <stdint.h>
@ -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<csize;i++) {
off=i*blocksize; // смещение до текущего блока
off=i*blocksize; // shift to the current block
len=blocksize;
if ((ptable[n].hd.psize-off)<blocksize) len=ptable[n].hd.psize-off; // для последнего неполного блока
if ((ptable[n].hd.psize-off)<blocksize) len=ptable[n].hd.psize-off; // for the last incomplete block
csblock[i]=crc16(ptable[n].pimage+off,len);
}
// вписываем параметры в заголовок
if (ptable[n].csumblock != 0) free(ptable[n].csumblock); // уничтожаем старый блок, если он был
}
// enter the parameters into the header
if (ptable[n].csumblock != 0) free(ptable[n].csumblock); // we destroy the old block if there was one
ptable[n].csumblock=csblock;
ptable[n].hd.hdsize=csize*2+sizeof(struct pheader);
// перевычисляем CRC заголовка
// recalculate CRC header
calc_hd_crc16(n);
}
//*******************************************************************
//* Извлечение раздела из файла и добавление его в таблицу разделов
//* Extract partition from file and add it to partition table
//*
// in - входной файл прошивки
// Позиция в файле соответствует началу заголовка раздела
//* "in" is the input firmware file
//* position in file corresponds to the beginning of partition header
//*******************************************************************
void extract(FILE* in) {
@ -166,219 +163,210 @@ uint8_t* zbuf;
long int zlen;
int res;
ptable[npart].zflag=0;
// читаем заголовок в структуру
ptable[npart].zflag=0;
// read the header into the structure
ptable[npart].offset=ftell(in);
fread(&ptable[npart].hd,1,sizeof(struct pheader),in); // заголовок
// Ищем символическое имя раздела по таблице
fread(&ptable[npart].hd,1,sizeof(struct pheader),in); // header
// look up the symbolic name of the partition in the table
find_pname(ptable[npart].hd.code,ptable[npart].pname);
// загружаем блок контрольных сумм
ptable[npart].csumblock=0; // пока блок не создан
crcblock=(uint16_t*)malloc(crcsize(npart)); // выделяем временную память под загружаемый блок
// load the checksum block
ptable[npart].csumblock=0; // until the block is created
crcblock=(uint16_t*)malloc(crcsize(npart)); // allot temporary memory for the loaded block
crcblocksize=crcsize(npart);
fread(crcblock,1,crcblocksize,in);
// загружаем образ раздела
// load a partition image
ptable[npart].pimage=(uint8_t*)malloc(psize(npart));
fread(ptable[npart].pimage,1,psize(npart),in);
// проверяем CRC заголовка
// check the CRC of the header
hcrc=ptable[npart].hd.crc;
ptable[npart].hd.crc=0; // старая CRC в рассчете не учитывается
ptable[npart].hd.crc=0; // check the CRC of the header
crc=crc16((uint8_t*)&ptable[npart].hd,sizeof(struct pheader));
if (crc != hcrc) {
printf("\n! Раздел %s (%02x) - ошибка контрольной суммы заголовка",ptable[npart].pname,ptable[npart].hd.code>>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);
}
}
}

@ -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;

@ -1,7 +1,5 @@
//
// Procedures for digital signature processing
// Процедуры обработки цифровых подписей
//
#include <stdio.h>
#include <stdint.h>
#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; i++) {
printf("\n%1i %5i %2i %s",i,signbase[i].len,signbase[i].type,signbase[i].descr);
}
printf("\n\n Также можно указать произвольные параметры подписи в формате:\n -g *,type,len\n\n");
printf("\n\n You can also specify arbitrary signature parameters in the format:\n -g *,type,len\n\n");
exit(0);
}
//***************************************************
//* Обработка параметров ключа -g
//* Processing -g option parameters
//***************************************************
void gparm(char* sparm) {
int index;
int index;
char* sptr;
char parm[100];
if (gflag != 0) {
printf("\n Дублирующийся ключ -g\n\n");
printf("\n Duplicate option -g\n\n");
exit(-1);
}
}
strcpy(parm,sparm); // локальная копия параметров
strcpy(parm,sparm); // local copy of parameters
if (parm[0] == 'l') {
glist();
exit(0);
}
}
if (parm[0] == 'd') {
// запрет автоопределения подписи
// disable signature auto-detection
gflag = -1;
return;
}
}
if (strncmp(parm,"*,",2) == 0) {
// произвольные параметры
// выделяем длину
// arbitrary parameters
// select length
sptr=strrchr(parm,',');
if (sptr == 0) goto perror;
signlen=atoi(sptr+1);
*sptr=0;
// выделяем тип раздела
// select partition type
sptr=strrchr(parm,',');
if (sptr == 0) goto perror;
signtype=atoi(sptr+1);
if (fw_description(signtype) == 0) {
printf("\n Ключ -g: неизвестный тип прошивки - %i\n",signtype);
printf("\n Option -g: Unknown firmware type - %i\n",signtype);
exit(-1);
}
}
}
else {
else {
index=atoi(parm);
if (index >= 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<sizeof(SVrsp)) || (memcmp(replybuf,SVrsp,sizeof(SVrsp)) != 0) ) {
printf("\n ! Ошибка проверки цифровой сигнатуры - %02x\n",replybuf[2]);
printf("\n ! Error checking digital signature - %02x\n",replybuf[2]);
exit(-2);
}
}
//***************************************************
//* Поиск цифровой подписи в прошивке
//* Search for digital signature in firmware
//***************************************************
int32_t serach_sign() {
@ -234,16 +225,16 @@ uint32_t signsize;
for (i=0;i<2;i++) {
if (i == npart) break;
pt=*((uint32_t*)&ptable[i].pimage[ptable[i].hd.psize-4]);
if (pt == 0xffaaaffa) {
// подпись найдена
if (pt == 0xffaaaffa) {
// signature found
signsize=*((uint32_t*)&ptable[i].pimage[ptable[i].hd.psize-12]);
// выделяем хеш открытого ключа
// select public key hash
for(j=0;j<32;j++) {
sprintf(signver_hash+2*j,"%02X",ptable[i].pimage[ptable[i].hd.psize-signsize+6+j]);
}
return signsize;
}
}
// не найдена
// not found
return -1;
}
}

@ -1,6 +1,5 @@
extern char signver_hash[100];
void glist();
void gparm(char* sparm);
void dparm(char* sparm);
@ -8,5 +7,4 @@ void send_signver();
char* fw_description(uint8_t code);
int32_t serach_sign();
extern char* fwtypes[];
extern char* fwtypes[];

186
util.c

@ -1,6 +1,5 @@
//
// Вспомогательные процедуры проекта balong_flash
//
// Supporting routines of balong_flash
#include <stdio.h>
#include <stdint.h>
#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<len;i+=16) {
}
}
//*************************************************
//* Вычисление CRC-16
//* Calculate CRC-16
//*************************************************
unsigned short crc16(char* buf, int len) {
@ -95,23 +91,23 @@ unsigned short crctab[] = {
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
};
int i;
unsigned short crc=0xffff;
unsigned short crc=0xffff;
for(i=0;i<len;i++) crc=crctab[(buf[i]^crc)&0xff]^((crc>>8)&0xff);
for(i=0;i<len;i++) crc=crctab[(buf[i]^crc)&0xff]^((crc>>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;i<res;i++) {
if (replybuf[i] == 0x0d) replybuf[i]=0;
}
printf("\n! Неправильная версия монитора прошивки - [%i]%s\n",res,replybuf+2);
}
printf("\n! Incorrect version of the firmware viewer - [%i]%s\n",res,replybuf+2);
// dump(replybuf,res,0);
return -1;
}
//****************************************************
//*------- Режим разрезания файла прошивки
//* Splitting firmware file
//****************************************************
void fwsplit(uint32_t sflag) {
uint32_t i;
FILE* out;
uint8_t filename[200];
printf("\n Выделение разделов из файла прошивки:\n\n ## Смещение Размер Имя\n-------------------------------------");
for (i=0;i<npart;i++) {
printf("\n %02i %08x %8i %s",i,ptable[i].offset,ptable[i].hd.psize,ptable[i].pname);
// формируем имя файла
printf("\n Partitioning of the firmware file:\n\n ## Offset Size Name\n-------------------------------------");
for (i=0;i<npart;i++) {
printf("\n %02i %08x %8i %s",i,ptable[i].offset,ptable[i].hd.psize,ptable[i].pname);
// from file
sprintf(filename,"%02i-%08x-%s.%s",i,ptable[i].hd.code,ptable[i].pname,(sflag?"fw":"bin"));
out=fopen(filename,"wb");
if(sflag) {
// запись заголовка
fwrite(&ptable[i].hd,1,sizeof(struct pheader),out); // фиксированный заголовок
fwrite((void*)ptable[i].csumblock,1,ptable[i].hd.hdsize-sizeof(struct pheader),out); // блок контрольных сумм
// record header
fwrite(&ptable[i].hd,1,sizeof(struct pheader),out); // fixed header
fwrite((void*)ptable[i].csumblock,1,ptable[i].hd.hdsize-sizeof(struct pheader),out); // block checksum
}
// запись тела
// body record
fwrite(ptable[i].pimage,ptable[i].hd.psize,1,out);
fclose(out);
}
@ -154,155 +150,145 @@ printf("\n");
return;
}
//****************************************************
//* Вход в HDLC-режим
//* Entering HDLC-Mode
//****************************************************
void enter_hdlc() {
uint32_t res;
uint32_t res;
unsigned char OKrsp[]={0x0d, 0x0a, 0x4f, 0x4b, 0x0d, 0x0a};
uint8_t replybuf[100];
uint8_t replybuf[100];
usleep(100000);
res=atcmd("^DATAMODE",replybuf);
if (res != 6) {
printf("\n Неправильная длина ответа на ^DATAMODE");
printf("\n Incorrect response length to ^DATAMODE");
exit(-2);
}
}
if (memcmp(replybuf,OKrsp,6) != 0) {
printf("\n Команда ^DATAMODE отвергнута, возможно требуется режим цифровой подписи\n");
printf("\n Command ^DATAMODE rejected, possibly requires digital signature mode\n");
exit(-2);
}
}
}
//****************************************************
//* Выход из HDLC-режима
//* Leaving HDLC-Mode
//****************************************************
void leave_hdlc() {
uint8_t replybuf[100];
unsigned char cmddone[7]={0x1}; // команда выхода из HDLC
uint8_t replybuf[100];
unsigned char cmddone[7]={0x1}; // HDLC quit command
send_cmd(cmddone,1,replybuf);
}
//****************************************************
//* Получение версии протокол прошивки
//* Get Firmware Version
//****************************************************
void protocol_version() {
uint8_t replybuf[100];
uint32_t iolen,i;
unsigned char cmdver[7]={0x0c}; // команда запроса версии протокола
uint8_t replybuf[100];
uint32_t iolen,i;
unsigned char cmdver[7]={0x0c}; // request the protocol version
iolen=send_cmd(cmdver,1,replybuf);
if (iolen == 0) {
printf("\n Нет ответа от модема в HDLC-режиме\n");
printf("\n No response from modem in HDLC-Mode\n");
exit(-2);
}
}
if (replybuf[0] == 0x7e) memcpy(replybuf,replybuf+1,iolen-1);
if (replybuf[0] != 0x0d) {
printf("\n Ошибка получения версии протокола\n");
printf("\n Failed to get protocol version\n");
exit(-2);
}
}
i=replybuf[1];
replybuf[2+i]=0;
printf("\n Версия протокола: %s",replybuf+2);
printf("\n Protocol Version: %s",replybuf+2);
}
//****************************************************
//* Перезагрузка модема
//* Reboot Modem
//****************************************************
void restart_modem() {
unsigned char cmd_reset[7]={0xa}; // команда выхода из HDLC
uint8_t replybuf[100];
unsigned char cmd_reset[7]={0xa}; // HDLC exit command
uint8_t replybuf[100];
printf("\n Перезагрузка модема...\n");
printf("\n Rebooting modem...\n");
send_cmd(cmd_reset,1,replybuf);
atcmd("^RESET",replybuf);
}
//****************************************************
//* Получение идентификатора устройства
//* Receiving Device ID
//****************************************************
void dev_ident() {
uint8_t replybuf[100];
uint8_t replybuf[100];
uint32_t iolen;
unsigned char cmd_getproduct[30]={0x45};
iolen=send_cmd(cmd_getproduct,1,replybuf);
if (iolen>2) 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<npart;i++) {
int i;
printf("\n\n ## Offset Size Compression Name\n-----------------------------------------------");
for (i=0;i<npart;i++) {
printf("\n %02i %08x %8i ",i,ptable[i].offset,ptable[i].hd.psize);
if (ptable[i].zflag == 0)
// несжатый раздел
if (ptable[i].zflag == 0)
// compressed partition
printf(" ");
else {
// сжатый раздел
// shrunken partition
switch(ptable[i].ztype) {
case 'L':
printf("Lzma");
printf("LZMA");
break;
case 'Z':
printf("Gzip");
case 'Z':
printf("gzip");
break;
}
}
printf(" %3i%% ",(ptable[i].hd.psize-ptable[i].zflag)*100/ptable[i].hd.psize);
}
printf(" %s",ptable[i].pname);
}
}
printf(" %s",ptable[i].pname);
}
printf("\n");
exit(0);
}
//****************************************************
//* Вывод информации о файле прошивки
//* Firmware File Info Output
//****************************************************
void show_fw_info() {
uint8_t* sptr;
uint8_t* sptr;
char ver[36];
if (ptable[0].hd.version[0] != ':') printf("\n Версия прошивки: %s",ptable[0].hd.version); // нестандартная строка версии
if (ptable[0].hd.version[0] != ':') printf("\n Firmware Version: %s",ptable[0].hd.version); // non-standard version string
else {
// стандартная строка версии
memset(ver,0,sizeof(ver));
strncpy(ver,ptable[0].hd.version,32);
sptr=strrchr(ver+1,':'); // ищем разделитель-двоеточие
if (sptr == 0) printf("\n Версия прошивки: %s",ver); // не найдено - несоответствие стандарту
// standard version string
memset(ver,0,sizeof(ver));
strncpy(ver,ptable[0].hd.version,32);
sptr=strrchr(ver+1,':'); // search for delimiter colon
if (sptr == 0) printf("\n Firmware Version: %s",ver); // not found - non-compliant with standard
else {
*sptr=0;
printf("\n Версия прошивки: %s",sptr+1);
printf("\n Платформа: %s",ver+1);
printf("\n Firmware Version: %s",sptr+1);
printf("\n Platform: %s",ver+1);
}
}
printf("\n Дата сборки: %s %s",ptable[0].hd.date,ptable[0].hd.time);
printf("\n Заголовок: версия %i, код соответствия: %8.8s",ptable[0].hd.hdversion,ptable[0].hd.unlock);
}
printf("\n Build Date: %s %s",ptable[0].hd.date,ptable[0].hd.time);
printf("\n Title: %i Version, Conformity Code: %8.8s",ptable[0].hd.hdversion,ptable[0].hd.unlock);
}

@ -1,4 +1,5 @@
#include <stdint.h>
void dump(char buffer[],int len,long base);
unsigned short crc16(char* buf, int len);
int dloadversion();

Loading…
Cancel
Save