@ -1,5 +1,6 @@
// Загрузчик usbloader.bin через аварийный порт для модемов на платформе Balong V7R2.
//
// Balong-usbdload is an emergency USB boot loader utility for Huawei LTE modems and routers with Balong V2R7, V7R11 and V7R22 chipsets.
// It loads external boot loader/firmware update tool file (usbloader.bin) via emergency serial port available if the firmware is corrupted or boot pin (test point) is shorted to the ground.
//
# include <stdio.h>
# include <stdint.h>
@ -35,7 +36,7 @@ FILE* ldr;
//*************************************************
//* HEX- дамп области памяти *
//* HEX- dump of the memory area *
//*************************************************
void dump ( unsigned char buffer [ ] , int len ) {
@ -51,12 +52,12 @@ for (i=0;i<len;i+=16) {
printf ( " * " ) ;
for ( j = 0 ; j < 16 ; j + + ) {
if ( ( i + j ) < len ) {
// преобразование байта для символьного отображения
// byte conversion for character display
ch = buffer [ i + j ] ;
if ( ( ch < 0x20 ) | | ( ( ch > 0x7e ) & & ( ch < 0xc0 ) ) ) putchar ( ' . ' ) ;
else putchar ( ch ) ;
}
// заполнение пробелами для неполных строк
}
// filling with spaces for incomplete lines
else printf ( " " ) ;
}
printf ( " * \n " ) ;
@ -65,26 +66,25 @@ for (i=0;i<len;i+=16) {
//*************************************************
//* Рассчет контрольной суммы командного пакета
//* Calculating the checksum of a command packet *
//*************************************************
void csum ( unsigned char * buf , int len ) {
unsigned int i , c , csum = 0 ;
unsigned int cconst [ ] = { 0 , 0x1021 , 0x2042 , 0x3063 , 0x4084 , 0x50A5 , 0x60C6 , 0x70E7 , 0x8108 , 0x9129 , 0xA14A , 0xB16B , 0xC18C , 0xD1AD , 0xE1CE , 0xF1EF } ;
for ( i = 0 ; i < ( len - 2 ) ; i + + ) {
c = ( buf [ i ] & 0xff ) ;
csum = ( ( csum < < 4 ) & 0xffff ) ^ cconst [ ( c > > 4 ) ^ ( csum > > 12 ) ] ;
csum = ( ( csum < < 4 ) & 0xffff ) ^ cconst [ ( c & 0xf ) ^ ( csum > > 12 ) ] ;
}
}
buf [ len - 2 ] = ( csum > > 8 ) & 0xff ;
buf [ len - 1 ] = csum & 0xff ;
}
//*************************************************
//* Отсылка командного пакета модему
//* Sending a command packet to a modem *
//*************************************************
int sendcmd ( unsigned char * cmdbuf , int len ) {
@ -93,7 +93,7 @@ unsigned int replylen;
# ifndef WIN32
csum ( cmdbuf , len ) ;
write ( siofd , cmdbuf , len ) ; // отсылка команды
write ( siofd , cmdbuf , len ) ; // sending a command
tcdrain ( siofd ) ;
replylen = read ( siofd , replybuf , 1024 ) ;
# else
@ -109,55 +109,55 @@ replylen=read(siofd,replybuf,1024);
ReadFile ( hSerial , replybuf , 1024 , ( LPDWORD ) & replylen , NULL ) ;
} while ( replylen = = 0 & & GetTickCount ( ) - t < 1000 ) ;
# endif
if ( replylen = = 0 ) return 0 ;
if ( replylen = = 0 ) return 0 ;
if ( replybuf [ 0 ] = = 0xaa ) return 1 ;
return 0 ;
}
//*************************************
// Открытие и настройка последовательного порта
//*************************************
//************************************* ************
// Opening and configuring the serial port *
//************************************* ************
int open_port ( char * devname ) {
//============= Linux =============== =========
//============= Linux ===============
# ifndef WIN32
int i , dflag = 1 ;
char devstr [ 200 ] = { 0 } ;
// Вместо полного имени устройства разрешается передавать только номер ttyUSB-порта
// only the ttyUSB port number can be transmitted instead of the full device name.
// Проверяем имя устройства на наличие нецифровых символов
// check the device name for 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 ) return 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 ) ;
return 1 ;
//============= Win32 =============== =========
//============= Win32 ===============
# else
char device [ 20 ] = " \\ \\ . \\ COM " ;
DCB dcbSerialParams = { 0 } ;
COMMTIMEOUTS CommTimeouts ;
strcat ( device , devname ) ;
hSerial = CreateFileA ( device , GENERIC_READ | GENERIC_WRITE , 0 , 0 , OPEN_EXISTING , FILE_ATTRIBUTE_NORMAL , 0 ) ;
if ( hSerial = = INVALID_HANDLE_VALUE )
return 0 ;
@ -192,11 +192,11 @@ return 1;
# endif
}
//*************************************
//* Поиск linux-ядра в образе раздела
//*************************************
//************************************* ******************
//* Searching for the linux core in the partition image *
//************************************* ******************
int locate_kernel ( char * pbuf , uint32_t size ) {
int off ;
for ( off = ( size - 8 ) ; off > 0 ; off - - ) {
@ -268,10 +268,10 @@ static int find_port(int* port_no, char* port_name)
void main ( int argc , char * argv [ ] ) {
unsigned int i , res , opt , datasize , pktcount , adr ;
int bl ; // текущий блок
int bl ; // current block
unsigned char c ;
int fbflag = 0 , tflag = 0 , mflag = 0 , bflag = 0 , cflag = 0 ;
int koff ; // смещение до ANDROID-заголовка
int koff ; // offset to ANDROID header
char ptfile [ 100 ] ;
FILE * pt ;
@ -284,15 +284,15 @@ unsigned char cmdhead[14]={0xfe,0, 0xff};
unsigned char cmddata [ 1040 ] = { 0xda , 0 , 0 } ;
unsigned char cmdeod [ 5 ] = { 0xed , 0 , 0 , 0 , 0 } ;
// список разделов, которым нужно установить файловый флаг
// list of partitions to set the file flag
uint8_t fileflag [ 41 ] ;
struct {
int lmode ; // режим загрузки: 1 - прямой старт, 2 - через перезапуск A-core
int size ; // размер компонента
int adr ; // адрес загрузки компонента в память
int offset ; // смещение до компонента от начала файла
char * pbuf ; // буфер для загрузки образа компонента
int lmode ; // loading mode: 1 - direct start, 2 - via restarting A-core
int size ; // size of a component
int adr ; // address of the component loading into memory
int offset ; // offset to the component from the beginning of the file
char * pbuf ; // buffer for loading the component image
} blk [ 10 ] ;
@ -313,23 +313,23 @@ memset(fileflag, 0, sizeof(fileflag));
while ( ( opt = getopt ( argc , argv , " hp:ft:ms:bc " ) ) ! = - 1 ) {
switch ( opt ) {
case ' h ' :
printf ( " \n Утилита предназначена для аварийной USB-загрузки устройств на чипете Balong V7 \n \n \
% s [ к л ю ч и ] < и м я ф а й л а д л я з а г р у з к и > \ n \ n \
Д о п у с т и м ы с л е д у ю щ и е к л ю ч и :\ n \ n "
case ' h ' :
printf ( " \n This utility is intended for emergency USB loading of devices on the Balong V7 chip \n \n \
% s [ option ] < boot file name > \ n \ n \
The 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 switch is not specified, the port is auto-detected \n "
# endif
" -f - грузить usbloader только до fastboot (без запуска линукса )\n \
- b - а н а л о г и ч н о - f , д о п о л н и т е л ь н о о т к л ю ч и т ь п р о в е р к у д е ф е к т н ы х б л о к о в п р и с т и р а н и и \ n \
- t < file > - в з я т ь т а б л и ц у р а з д е л о в и з у к а з а н н о г о ф а й л а \ n \
- m - п о к а з а т ь т а б л и ц у р а з д е л о в з а г р у з ч и к а и з а в е р ш и т ь р а б о т у \ n \
- s n - у с т а н о в и т ь ф а й л о в ы й ф л а г д л я р а з д е л а n ( к л ю ч м о ж н о у к а з а т ь н е с к о л ь к о р а з ) \ n \
- c - н е п р о и з в о д и т ь а в т о м а т и ч е с к и й п а т ч с т и р а н и я р а з д е л о в \ n \
" -f - Load usbloader only to fastboot (without starting Linux )\n \
- b - Similarly to - f , additionally disable check of defective blocks during wipeout \ n \
- t < file > - Take partition table from specified file \ n \
- m - Show the loader partition table and exit \ n \
- s n - Set file flag for partition n ( option can be set multiple times ) \ n \
- c - Do not automatically patch partitions \ n \
\ n " ,argv[0]);
return ;
@ -362,134 +362,134 @@ printf("\n Утилита предназначена для аварийной U
case ' s ' :
i = atoi ( optarg ) ;
if ( i > 41 ) {
printf ( " \n Раздела #%i не существует \n " , i ) ;
printf ( " \n Partition #%i does not exist \n " , i ) ;
return ;
}
fileflag [ i ] = 1 ;
break ;
case ' ? ' :
case ' : ' :
case ' : ' :
return ;
}
}
}
printf ( " \n Аварийный USB-загрузчик Balong-чипсета, версия 2.20, (c) forth32, 2015 " ) ;
printf ( " \n Balong-chipset emergency USB loader, version 2.20, (c) forth32, 2015 \n " ) ;
printf ( " \n English Version (c) robertzaage, 2022 " ) ;
# ifdef WIN32
printf ( " \n Порт для Windows 32bit (c) rust3028, 2016" ) ;
printf ( " \n Windows Port 32bit (c) rust3028, 2016" ) ;
# endif
if ( optind > = argc ) {
printf ( " \n - Н е указано имя файла для загрузки\n " ) ;
printf ( " \n - File to upload is not specified \n " ) ;
return ;
}
}
ldr = fopen ( argv [ optind ] , " rb " ) ;
if ( ldr = = 0 ) {
printf ( " \n Ошибка открытия %s" , argv [ optind ] ) ;
printf ( " \n Opening error %s" , argv [ optind ] ) ;
return ;
}
// Прверяем сигнатуру usloader
// Checking the usloader signature
fread ( & i , 1 , 4 , ldr ) ;
if ( i ! = 0x20000 ) {
printf ( " \n Файл %s не является загрузчиком usbloader\n " , argv [ optind ] ) ;
printf ( " \n File %s is not a usbloader\n " , argv [ optind ] ) ;
return ;
}
}
fseek ( ldr , 36 , SEEK_SET ) ; // начало описателей блоков для загрузки
fseek ( ldr , 36 , SEEK_SET ) ; // beginning of block descriptors to load
// Разбираем заголовок
// parsing the header
fread ( & blk [ 0 ] , 1 , 16 , ldr ) ; // raminit
fread ( & blk [ 1 ] , 1 , 16 , ldr ) ; // usbldr
//---------------------------------------------------------------------
// Чтение компонентов в память
// reading components into memory
for ( bl = 0 ; bl < 2 ; bl + + ) {
// выделяем память под полный образ раздела
// allocate memory for the full image of the partition
blk [ bl ] . pbuf = ( char * ) malloc ( blk [ bl ] . size ) ;
// читаем образ раздела в память
// read partition image into memory
fseek ( ldr , blk [ bl ] . offset , SEEK_SET ) ;
res = fread ( blk [ bl ] . pbuf , 1 , blk [ bl ] . size , ldr ) ;
if ( res ! = blk [ bl ] . size ) {
printf ( " \n Неожиданный конец файла: прочитано %i ожидалось %i\n " , res , blk [ bl ] . size ) ;
printf ( " \n Unexpected end of file: read %i expected %i\n " , res , blk [ bl ] . size ) ;
return ;
}
if ( bl = = 0 ) continue ; // для raminit более ничего делать не надо
if ( bl = = 0 ) continue ; // nothing more needs to be done for raminit
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// fastboot -патч
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// fastboot patch
if ( fbflag ) {
koff = locate_kernel ( blk [ bl ] . pbuf , blk [ bl ] . size ) ;
if ( koff ! = 0 ) {
blk [ bl ] . pbuf [ koff ] = 0x55 ; // патч сигнатуры
blk [ bl ] . size = koff + 8 ; // обрезаем раздел до начала ядра
blk [ bl ] . pbuf [ koff ] = 0x55 ; // patch the signature
blk [ bl ] . size = koff + 8 ; // trim the partition to the start of the kernel
}
else {
printf ( " \n В загрузчике нет ANDROID-компонента - fastboot-загрузка невозможна\n " ) ;
printf ( " \n There is no ANDROID component in the loader - fastboot-loading is not possible. \n " ) ;
exit ( 0 ) ;
}
}
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Ищем таблицу разделов в загрузчике
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// look for the partition table in the boot loader
ptoff = find_ptable_ram ( blk [ bl ] . pbuf , blk [ bl ] . size ) ;
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// патч таблицы разделов
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// patch partition table
if ( tflag ) {
pt = fopen ( ptfile , " rb " ) ;
if ( pt = = 0 ) {
printf ( " \n Н е найден файл %s - замена таблицы разделов невозможна\n " , ptfile ) ;
if ( pt = = 0 ) {
printf ( " \n File %s is not found - partition table cannot be replaced \n " , ptfile ) ;
return ;
}
}
fread ( ptbuf , 1 , 2048 , pt ) ;
fclose ( pt ) ;
if ( memcmp ( headmagic , ptbuf , sizeof ( headmagic ) ) ! = 0 ) {
printf ( " \n Файл %s не явлется таблицей разделов \n " , ptfile ) ;
printf ( " \n The file %s is not a partition table \n " , ptfile ) ;
return ;
}
}
if ( ptoff = = 0 ) {
printf ( " \n В загрузчике не найдена таблица разделов - замена невозможна" ) ;
printf ( " \n No partition table found in loader - cannot be replaced " ) ;
return ;
}
memcpy ( blk [ bl ] . pbuf + ptoff , ptbuf , 2048 ) ;
}
ptable = ( struct ptable_t * ) ( blk [ bl ] . pbuf + ptoff ) ;
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Патч файловых флагов
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// patch file flags
for ( i = 0 ; i < 41 ; i + + ) {
if ( fileflag [ i ] ) {
ptable - > part [ i ] . nproperty | = 1 ;
}
}
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Вывод таблицы разделов
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// output partition table
if ( mflag ) {
if ( ptoff = = 0 ) {
printf ( " \n Таблица разделов не найдена - вывод карты невозможен \n " ) ;
printf ( " \n Partition table not found - mapping output not possible \n " ) ;
return ;
}
show_map ( * ptable ) ;
return ;
}
// Патч erase-процедуры на предмет игнорировани бедблоков
// patch the erase procedure to ignore deadlocks
if ( bflag ) {
res = perasebad ( blk [ bl ] . pbuf , blk [ bl ] . size ) ;
if ( res = = 0 ) {
printf ( " \n ! Н е найдена сигнатура isbad - загрузка невозможна\n " ) ;
if ( res = = 0 ) {
printf ( " \n ! No isbad signature found - cannot load\n " ) ;
return ;
}
}
}
// Удаление процедуры flash_eraseall
// removing the flash_eraseall procedure
if ( ! cflag ) {
res = pv7r1 ( blk [ bl ] . pbuf , blk [ bl ] . size ) ;
if ( res = = 0 )
@ -502,9 +502,9 @@ for(bl=0;bl<2;bl++) {
res = pv7r22_2 ( blk [ bl ] . pbuf , blk [ bl ] . size ) ;
if ( res = = 0 )
res = pv7r22_3 ( blk [ bl ] . pbuf , blk [ bl ] . size ) ;
if ( res ! = 0 ) printf ( " \n \n * Удалена процедура flash_eraseall по смещению %08x" , blk [ bl ] . offset + res ) ;
if ( res ! = 0 ) printf ( " \n \n * Removed flash_eraseall procedure at offset %08x" , blk [ bl ] . offset + res ) ;
else {
printf ( " \n Процедура eraseall не найдена в загрузчике - используйте ключ -с для загрузки без патча !\n " ) ;
printf ( " \n Procedure eraseall not found in the bootloader - use key -s to boot without patch !\n " ) ;
return ;
}
}
@ -516,28 +516,27 @@ for(bl=0;bl<2;bl++) {
# ifdef WIN32
if ( * devname = = ' \0 ' )
{
printf ( " \n \n Поиск порта аварийной загрузки ...\n " ) ;
printf ( " \n \n Searching for the emergency loading port ...\n " ) ;
if ( find_port ( & port_no , port_name ) = = 0 )
{
sprintf ( devname , " %d " , port_no ) ;
printf ( " Порт : \" %s \" \n " , port_name ) ;
printf ( " Port : \" %s \" \n " , port_name ) ;
}
else
{
printf ( " Порт не обнаружен !\n " ) ;
printf ( " No port found !\n " ) ;
return ;
}
}
# endif
if ( ! open_port ( devname ) ) {
printf ( " \n Последовательный порт не открывается \n " ) ;
printf ( " \n Can't open serial port \n " ) ;
return ;
}
}
// Проверяем загрузочный порт
// Check the boot port
c = 0 ;
# ifndef WIN32
write ( siofd , " A " , 1 ) ;
@ -549,66 +548,63 @@ res=read(siofd,&c,1);
ReadFile ( hSerial , & c , 1 , & bytes_read , NULL ) ;
# endif
if ( c ! = 0x55 ) {
printf ( " \n ! Порт не находится в режиме USB Boot \n " ) ;
printf ( " \n ! Port is not in USB-Boot mode \n " ) ;
return ;
}
}
//----------------------------------
// главный цикл загрузки - загружаем все блоки, найденные в заголовке
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// main loading cycle - load all the blocks found in the header
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
printf ( " \n \n Компонент Адрес Размер %%загрузки \n ------------------------------------------ \n " ) ;
printf ( " \n \n Component Address Size %% loaded \n ------------------------------------------ \n " ) ;
for ( bl = 0 ; bl < 2 ; bl + + ) {
datasize = 1024 ;
pktcount = 1 ;
// фрмируем пакет начала блока
// create a package of the beginning of the block
* ( ( unsigned int * ) & cmdhead [ 4 ] ) = htonl ( blk [ bl ] . size ) ;
* ( ( unsigned int * ) & cmdhead [ 8 ] ) = htonl ( blk [ bl ] . adr ) ;
cmdhead [ 3 ] = blk [ bl ] . lmode ;
// отправляем пакет начала блока
// send a block start packet
res = sendcmd ( cmdhead , 14 ) ;
if ( ! res ) {
printf ( " \n Модем отверг пакет заголовка \n " ) ;
printf ( " \n Modem rejected the header packet \n " ) ;
return ;
}
}
// ---------- Цикл поблочной загрузки данных ---------------------
// ---------- Block-by-block data loading cycle ------------
for ( adr = 0 ; adr < blk [ bl ] . size ; adr + = 1024 ) {
// формируем размер последнего загружаемого пакета
if ( ( adr + 1024 ) > = blk [ bl ] . size ) datasize = blk [ bl ] . size - adr ;
// get the size of the last downloaded packet
if ( ( adr + 1024 ) > = blk [ bl ] . size ) datasize = blk [ bl ] . size - adr ;
printf ( " \r %s %08x %8i %i%% " , bl ? " usbboot " : " raminit " , blk [ bl ] . adr , blk [ bl ] . size , ( adr + datasize ) * 100 / blk [ bl ] . size ) ;
printf ( " \r %s %08x %8i %i%% " , bl ? " usbboot " : " raminit " , blk [ bl ] . adr , blk [ bl ] . size , ( adr + datasize ) * 100 / blk [ bl ] . size ) ;
// готовим пакет данных
// prepare the data package
cmddata [ 1 ] = pktcount ;
cmddata [ 2 ] = ( ~ pktcount ) & 0xff ;
memcpy ( cmddata + 3 , blk [ bl ] . pbuf + adr , datasize ) ;
pktcount + + ;
if ( ! sendcmd ( cmddata , datasize + 5 ) ) {
printf ( " \n Модем отверг пакет данных " ) ;
printf ( " \n Modem rejected the data packet " ) ;
return ;
}
}
}
free ( blk [ bl ] . pbuf ) ;
// Фрмируем пакет конца данных
// prepare an end-of-data packet
cmdeod [ 1 ] = pktcount ;
cmdeod [ 2 ] = ( ~ pktcount ) & 0xff ;
if ( ! sendcmd ( cmdeod , 5 ) ) {
printf ( " \n Модем отверг пакет конца данных " ) ;
printf ( " \n Modem rejected the end of data packet " ) ;
}
printf ( " \n " ) ;
}
printf ( " \n Загрузка окончена\n " ) ;
printf ( " \n " ) ;
}
printf ( " \n Loading finished!\n " ) ;
}