Initial to English translated release

master
Robert Zaage 2 years ago
parent c0ebd14883
commit 7f807afcea

@ -27,4 +27,3 @@ loader-patch: loader-patch.o patcher.o
ptable-list: ptable-list.o parts.o ptable-list: ptable-list.o parts.o
@gcc $^ -o $@ $(LIBS) @gcc $^ -o $@ $(LIBS)

@ -1,21 +1,5 @@
# balong-usbdload # balong-usbdload
**Please read "getting help" section carefully before asking any questions!**
## Russian section
Утилита для аварийной USB-загрузки модемов на чипсете Balong V2R7, V7R11 и V7R22.
Позволяет загрузить внешний загрузчик-прошивальщик (usbloader) через аварийный USB-serial порт загрузки, создаваемый модемом при повреждении прошивки или замыкании на землю контакта аварийной загрузки на плате модема.
Многие загрузчики могут быть автоматически пропатчены данной утилитой в процессе загрузки. Патч необходим потому, что оригинальный usbloader стирает всю флеш-память в процессе загрузки, включая уникальные данные, хранящиеся в NVRAM.
**Эта утилита может вывести ваше устройство из строя!**
Используйте ее, только если осознаете все риски и последствия. В случае каких-либо возникших проблем, не ждите помощи, рассчитывайте только на свои собственные силы.
Пожалуйста, воздержитесь от любых вопросов, не касающихся программы напрямую, в том числе и о вопросах о файлах-загрузчиках. У нас их нет. Нет, мы не знаем, где их взять.
## English section
### About ### About
Balong-usbdload is an emergency USB boot loader utility for Huawei LTE modems and routers with Balong V2R7, V7R11 and V7R22 chipsets. Balong-usbdload is an emergency USB boot loader utility for Huawei LTE modems and routers with Balong V2R7, V7R11 and V7R22 chipsets.

@ -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 <stdio.h>
#include <stdint.h> #include <stdint.h>
@ -35,7 +36,7 @@ FILE* ldr;
//************************************************* //*************************************************
//* HEX-дамп области памяти * //* HEX-dump of the memory area *
//************************************************* //*************************************************
void dump(unsigned char buffer[],int len) { void dump(unsigned char buffer[],int len) {
@ -51,12 +52,12 @@ for (i=0;i<len;i+=16) {
printf(" *"); printf(" *");
for (j=0;j<16;j++) { for (j=0;j<16;j++) {
if ((i+j) < len) { if ((i+j) < len) {
// преобразование байта для символьного отображения // byte conversion for character display
ch=buffer[i+j]; ch=buffer[i+j];
if ((ch < 0x20)||((ch > 0x7e)&&(ch<0xc0))) putchar('.'); if ((ch < 0x20)||((ch > 0x7e)&&(ch<0xc0))) putchar('.');
else putchar(ch); else putchar(ch);
} }
// заполнение пробелами для неполных строк // filling with spaces for incomplete lines
else printf(" "); else printf(" ");
} }
printf("*\n"); printf("*\n");
@ -65,12 +66,11 @@ for (i=0;i<len;i+=16) {
//************************************************* //*************************************************
//* Рассчет контрольной суммы командного пакета //* Calculating the checksum of a command packet *
//************************************************* //*************************************************
void csum(unsigned char* buf, int len) { void csum(unsigned char* buf, int len) {
unsigned int i,c,csum=0; 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}; 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++) { for (i=0;i<(len-2);i++) {
@ -84,7 +84,7 @@ buf[len-1]=csum&0xff;
} }
//************************************************* //*************************************************
//* Отсылка командного пакета модему //* Sending a command packet to a modem *
//************************************************* //*************************************************
int sendcmd(unsigned char* cmdbuf, int len) { int sendcmd(unsigned char* cmdbuf, int len) {
@ -93,7 +93,7 @@ unsigned int replylen;
#ifndef WIN32 #ifndef WIN32
csum(cmdbuf,len); csum(cmdbuf,len);
write(siofd,cmdbuf,len); // отсылка команды write(siofd,cmdbuf,len); // sending a command
tcdrain(siofd); tcdrain(siofd);
replylen=read(siofd,replybuf,1024); replylen=read(siofd,replybuf,1024);
#else #else
@ -114,33 +114,33 @@ if (replybuf[0] == 0xaa) return 1;
return 0; return 0;
} }
//************************************* //*************************************************
// Открытие и настройка последовательного порта // Opening and configuring the serial port *
//************************************* //*************************************************
int open_port(char* devname) { int open_port(char* devname) {
//============= Linux ======================== //============= Linux ===============
#ifndef WIN32 #ifndef WIN32
int i,dflag=1; int i,dflag=1;
char devstr[200]={0}; 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++) { for(i=0;i<strlen(devname);i++) {
if ((devname[i]<'0') || (devname[i]>'9')) dflag=0; 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"); if (dflag) strcpy(devstr,"/dev/ttyUSB");
// копируем имя устройства // copy the device name
strcat(devstr,devname); strcat(devstr,devname);
siofd = open(devstr, O_RDWR | O_NOCTTY |O_SYNC); siofd = open(devstr, O_RDWR | O_NOCTTY |O_SYNC);
if (siofd == -1) return 0; 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_cflag = B115200 | CS8 | CLOCAL | CREAD ;
sioparm.c_iflag = 0; // INPCK; sioparm.c_iflag = 0; // INPCK;
sioparm.c_oflag = 0; sioparm.c_oflag = 0;
@ -150,7 +150,7 @@ sioparm.c_cc[VMIN]=0;
tcsetattr(siofd, TCSANOW, &sioparm); tcsetattr(siofd, TCSANOW, &sioparm);
return 1; return 1;
//============= Win32 ======================== //============= Win32 ===============
#else #else
char device[20] = "\\\\.\\COM"; char device[20] = "\\\\.\\COM";
DCB dcbSerialParams = {0}; DCB dcbSerialParams = {0};
@ -192,9 +192,9 @@ return 1;
#endif #endif
} }
//************************************* //*******************************************************
//* Поиск linux-ядра в образе раздела //* Searching for the linux core in the partition image *
//************************************* //*******************************************************
int locate_kernel(char* pbuf, uint32_t size) { int locate_kernel(char* pbuf, uint32_t size) {
int off; int off;
@ -268,10 +268,10 @@ static int find_port(int* port_no, char* port_name)
void main(int argc, char* argv[]) { void main(int argc, char* argv[]) {
unsigned int i,res,opt,datasize,pktcount,adr; unsigned int i,res,opt,datasize,pktcount,adr;
int bl; // текущий блок int bl; // current block
unsigned char c; unsigned char c;
int fbflag=0, tflag=0, mflag=0, bflag=0, cflag=0; int fbflag=0, tflag=0, mflag=0, bflag=0, cflag=0;
int koff; // смещение до ANDROID-заголовка int koff; // offset to ANDROID header
char ptfile[100]; char ptfile[100];
FILE* pt; FILE* pt;
@ -284,15 +284,15 @@ unsigned char cmdhead[14]={0xfe,0, 0xff};
unsigned char cmddata[1040]={0xda,0,0}; unsigned char cmddata[1040]={0xda,0,0};
unsigned char cmdeod[5]={0xed,0,0,0,0}; unsigned char cmdeod[5]={0xed,0,0,0,0};
// список разделов, которым нужно установить файловый флаг // list of partitions to set the file flag
uint8_t fileflag[41]; uint8_t fileflag[41];
struct { struct {
int lmode; // режим загрузки: 1 - прямой старт, 2 - через перезапуск A-core int lmode; // loading mode: 1 - direct start, 2 - via restarting A-core
int size; // размер компонента int size; // size of a component
int adr; // адрес загрузки компонента в память int adr; // address of the component loading into memory
int offset; // смещение до компонента от начала файла int offset; // offset to the component from the beginning of the file
char* pbuf; // буфер для загрузки образа компонента char* pbuf; // buffer for loading the component image
} blk[10]; } blk[10];
@ -315,21 +315,21 @@ while ((opt = getopt(argc, argv, "hp:ft:ms:bc")) != -1) {
switch (opt) { switch (opt) {
case 'h': case 'h':
printf("\n Утилита предназначена для аварийной USB-загрузки устройств на чипете Balong V7\n\n\ printf("\n This utility is intended for emergency USB loading of devices on the Balong V7 chip\n\n\
%s [ключи] <имя файла для загрузки>\n\n\ %s [option] <boot file name>\n\n\
Допустимы следующие ключи:\n\n" The following options are allowed:\n\n"
#ifndef WIN32 #ifndef WIN32
"-p <tty> - последовательный порт для общения с загрузчиком (по умолчанию /dev/ttyUSB0)\n" "-p <tty> - serial port for communicating with the bootloader (by default /dev/ttyUSB0)\n"
#else #else
"-p # - номер последовательного порта для общения с загрузчиком (например, -p8)\n" "-p # - number of the serial port for communicating with the loader (e.g. -p8)\n"
" если ключ -p не указан, производится автоопределение порта\n" " if the -p switch is not specified, the port is auto-detected\n"
#endif #endif
"-f - грузить usbloader только до fastboot (без запуска линукса)\n\ "-f - Load usbloader only to fastboot (without starting Linux)\n\
-b - аналогично -f, дополнительно отключить проверку дефектных блоков при стирании\n\ -b - Similarly to -f, additionally disable check of defective blocks during wipeout\n\
-t <file>- взять таблицу разделов из указанного файла\n\ -t <file> - Take partition table from specified file\n\
-m - показать таблицу разделов загрузчика и завершить работу\n\ -m - Show the loader partition table and exit\n\
-s n - установить файловый флаг для раздела n (ключ можно указать несколько раз)\n\ -s n - Set file flag for partition n (option can be set multiple times)\n\
-c - не производить автоматический патч стирания разделов\n\ -c - Do not automatically patch partitions\n\
\n",argv[0]); \n",argv[0]);
return; return;
@ -362,7 +362,7 @@ printf("\n Утилита предназначена для аварийной U
case 's': case 's':
i=atoi(optarg); i=atoi(optarg);
if (i>41) { if (i>41) {
printf("\n Раздела #%i не существует\n",i); printf("\n Partition #%i does not exist\n",i);
return; return;
} }
fileflag[i]=1; fileflag[i]=1;
@ -375,87 +375,87 @@ printf("\n Утилита предназначена для аварийной U
} }
} }
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 #ifdef WIN32
printf("\n Порт для Windows 32bit (c) rust3028, 2016"); printf("\n Windows Port 32bit (c) rust3028, 2016");
#endif #endif
if (optind>=argc) { if (optind>=argc) {
printf("\n - Не указано имя файла для загрузки\n"); printf("\n - File to upload is not specified\n");
return; return;
} }
ldr=fopen(argv[optind],"rb"); ldr=fopen(argv[optind],"rb");
if (ldr == 0) { if (ldr == 0) {
printf("\n Ошибка открытия %s",argv[optind]); printf("\n Opening error %s",argv[optind]);
return; return;
} }
// Прверяем сигнатуру usloader // Checking the usloader signature
fread(&i,1,4,ldr); fread(&i,1,4,ldr);
if (i != 0x20000) { if (i != 0x20000) {
printf("\n Файл %s не является загрузчиком usbloader\n",argv[optind]); printf("\n File %s is not a usbloader\n",argv[optind]);
return; 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[0],1,16,ldr); // raminit
fread(&blk[1],1,16,ldr); // usbldr fread(&blk[1],1,16,ldr); // usbldr
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// Чтение компонентов в память // reading components into memory
for(bl=0;bl<2;bl++) { for(bl=0;bl<2;bl++) {
// выделяем память под полный образ раздела // allocate memory for the full image of the partition
blk[bl].pbuf=(char*)malloc(blk[bl].size); blk[bl].pbuf=(char*)malloc(blk[bl].size);
// читаем образ раздела в память // read partition image into memory
fseek(ldr,blk[bl].offset,SEEK_SET); fseek(ldr,blk[bl].offset,SEEK_SET);
res=fread(blk[bl].pbuf,1,blk[bl].size,ldr); res=fread(blk[bl].pbuf,1,blk[bl].size,ldr);
if (res != blk[bl].size) { 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; return;
} }
if (bl == 0) continue; // для raminit более ничего делать не надо if (bl == 0) continue; // nothing more needs to be done for raminit
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// fastboot-патч // fastboot patch
if (fbflag) { if (fbflag) {
koff=locate_kernel(blk[bl].pbuf,blk[bl].size); koff=locate_kernel(blk[bl].pbuf,blk[bl].size);
if (koff != 0) { if (koff != 0) {
blk[bl].pbuf[koff]=0x55; // патч сигнатуры blk[bl].pbuf[koff]=0x55; // patch the signature
blk[bl].size=koff+8; // обрезаем раздел до начала ядра blk[bl].size=koff+8; // trim the partition to the start of the kernel
} }
else { else {
printf("\n В загрузчике нет ANDROID-компонента - fastboot-загрузка невозможна\n"); printf("\n There is no ANDROID component in the loader - fastboot-loading is not possible.\n");
exit(0); exit(0);
} }
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Ищем таблицу разделов в загрузчике // look for the partition table in the boot loader
ptoff=find_ptable_ram(blk[bl].pbuf,blk[bl].size); ptoff=find_ptable_ram(blk[bl].pbuf,blk[bl].size);
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// патч таблицы разделов // patch partition table
if (tflag) { if (tflag) {
pt=fopen(ptfile,"rb"); pt=fopen(ptfile,"rb");
if (pt == 0) { if (pt == 0) {
printf("\n Не найден файл %s - замена таблицы разделов невозможна\n",ptfile); printf("\n File %s is not found - partition table cannot be replaced\n",ptfile);
return; return;
} }
fread(ptbuf,1,2048,pt); fread(ptbuf,1,2048,pt);
fclose(pt); fclose(pt);
if (memcmp(headmagic,ptbuf,sizeof(headmagic)) != 0) { 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; return;
} }
if (ptoff == 0) { if (ptoff == 0) {
printf("\n В загрузчике не найдена таблица разделов - замена невозможна"); printf("\n No partition table found in loader - cannot be replaced");
return; return;
} }
memcpy(blk[bl].pbuf+ptoff,ptbuf,2048); memcpy(blk[bl].pbuf+ptoff,ptbuf,2048);
@ -463,7 +463,7 @@ for(bl=0;bl<2;bl++) {
ptable=(struct ptable_t*)(blk[bl].pbuf+ptoff); ptable=(struct ptable_t*)(blk[bl].pbuf+ptoff);
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Патч файловых флагов // patch file flags
for(i=0;i<41;i++) { for(i=0;i<41;i++) {
if (fileflag[i]) { if (fileflag[i]) {
ptable->part[i].nproperty |= 1; ptable->part[i].nproperty |= 1;
@ -471,25 +471,25 @@ for(bl=0;bl<2;bl++) {
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Вывод таблицы разделов // output partition table
if (mflag) { if (mflag) {
if (ptoff == 0) { if (ptoff == 0) {
printf("\n Таблица разделов не найдена - вывод карты невозможен\n"); printf("\n Partition table not found - mapping output not possible\n");
return; return;
} }
show_map(*ptable); show_map(*ptable);
return; return;
} }
// Патч erase-процедуры на предмет игнорировани бедблоков // patch the erase procedure to ignore deadlocks
if (bflag) { if (bflag) {
res=perasebad(blk[bl].pbuf, blk[bl].size); res=perasebad(blk[bl].pbuf, blk[bl].size);
if (res == 0) { if (res == 0) {
printf("\n! Не найдена сигнатура isbad - загрузка невозможна\n"); printf("\n! No isbad signature found - cannot load\n");
return; return;
} }
} }
// Удаление процедуры flash_eraseall // removing the flash_eraseall procedure
if (!cflag) { if (!cflag) {
res = pv7r1(blk[bl].pbuf, blk[bl].size); res = pv7r1(blk[bl].pbuf, blk[bl].size);
if (res == 0) if (res == 0)
@ -502,9 +502,9 @@ for(bl=0;bl<2;bl++) {
res = pv7r22_2(blk[bl].pbuf, blk[bl].size); res = pv7r22_2(blk[bl].pbuf, blk[bl].size);
if (res == 0) if (res == 0)
res = pv7r22_3(blk[bl].pbuf, blk[bl].size); 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 { else {
printf("\n Процедура eraseall не найдена в загрузчике - используйте ключ -с для загрузки без патча!\n"); printf("\n Procedure eraseall not found in the bootloader - use key -s to boot without patch!\n");
return; return;
} }
} }
@ -516,28 +516,27 @@ for(bl=0;bl<2;bl++) {
#ifdef WIN32 #ifdef WIN32
if (*devname == '\0') if (*devname == '\0')
{ {
printf("\n\nПоиск порта аварийной загрузки...\n"); printf("\n\nSearching for the emergency loading port...\n");
if (find_port(&port_no, port_name) == 0) if (find_port(&port_no, port_name) == 0)
{ {
sprintf(devname, "%d", port_no); sprintf(devname, "%d", port_no);
printf("Порт: \"%s\"\n", port_name); printf("Port: \"%s\"\n", port_name);
} }
else else
{ {
printf("Порт не обнаружен!\n"); printf("No port found!\n");
return; return;
} }
} }
#endif #endif
if (!open_port(devname)) { if (!open_port(devname)) {
printf("\n Последовательный порт не открывается\n"); printf("\n Can't open serial port\n");
return; return;
} }
// Check the boot port
// Проверяем загрузочный порт
c=0; c=0;
#ifndef WIN32 #ifndef WIN32
write(siofd,"A",1); write(siofd,"A",1);
@ -549,66 +548,63 @@ res=read(siofd,&c,1);
ReadFile(hSerial, &c, 1, &bytes_read, NULL); ReadFile(hSerial, &c, 1, &bytes_read, NULL);
#endif #endif
if (c != 0x55) { if (c != 0x55) {
printf("\n ! Порт не находится в режиме USB Boot\n"); printf("\n! Port is not in USB-Boot mode\n");
return; 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++) { for(bl=0;bl<2;bl++) {
datasize=1024; datasize=1024;
pktcount=1; pktcount=1;
// create a package of the beginning of the block
// фрмируем пакет начала блока
*((unsigned int*)&cmdhead[4])=htonl(blk[bl].size); *((unsigned int*)&cmdhead[4])=htonl(blk[bl].size);
*((unsigned int*)&cmdhead[8])=htonl(blk[bl].adr); *((unsigned int*)&cmdhead[8])=htonl(blk[bl].adr);
cmdhead[3]=blk[bl].lmode; cmdhead[3]=blk[bl].lmode;
// отправляем пакет начала блока // send a block start packet
res=sendcmd(cmdhead,14); res=sendcmd(cmdhead,14);
if (!res) { if (!res) {
printf("\nМодем отверг пакет заголовка\n"); printf("\nModem rejected the header packet\n");
return; return;
} }
// ---------- Цикл поблочной загрузки данных --------------------- // ---------- Block-by-block data loading cycle ------------
for(adr=0;adr<blk[bl].size;adr+=1024) { for(adr=0;adr<blk[bl].size;adr+=1024) {
// формируем размер последнего загружаемого пакета // get the size of the last downloaded packet
if ((adr+1024)>=blk[bl].size) datasize=blk[bl].size-adr; 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[1]=pktcount;
cmddata[2]=(~pktcount)&0xff; cmddata[2]=(~pktcount)&0xff;
memcpy(cmddata+3,blk[bl].pbuf+adr,datasize); memcpy(cmddata+3,blk[bl].pbuf+adr,datasize);
pktcount++; pktcount++;
if (!sendcmd(cmddata,datasize+5)) { if (!sendcmd(cmddata,datasize+5)) {
printf("\nМодем отверг пакет данных"); printf("\nModem rejected the data packet");
return; return;
} }
} }
free(blk[bl].pbuf); free(blk[bl].pbuf);
// Фрмируем пакет конца данных // prepare an end-of-data packet
cmdeod[1]=pktcount; cmdeod[1]=pktcount;
cmdeod[2]=(~pktcount)&0xff; cmdeod[2]=(~pktcount)&0xff;
if (!sendcmd(cmdeod,5)) { if (!sendcmd(cmdeod,5)) {
printf("\nМодем отверг пакет конца данных"); printf("\nModem rejected the end of data packet");
} }
printf("\n"); printf("\n");
} }
printf("\n Загрузка окончена\n"); printf("\n Loading finished!\n");
} }

@ -28,18 +28,17 @@ uint8_t outfilename[100];
int oflag=0,bflag=0; int oflag=0,bflag=0;
uint32_t res; uint32_t res;
// parsing command line
// Разбор командной строки
while ((opt = getopt(argc, argv, "o:bh")) != -1) { while ((opt = getopt(argc, argv, "o:bh")) != -1) {
switch (opt) { switch (opt) {
case 'h': case 'h':
printf("\n Программа для автоматического патча загрузчиков платформ Balong V7\n\n\ printf("\n Program for automatic patching of Balong V7 bootloaders\n\n\
%s [ключи] <файл загрузчика usbloader>\n\n\ %s [options] <usbloader file>\n\n\
Допустимы следующие ключи:\n\n\ Following options are allowed:\n\n\
-o file - имя выходного файла. По умолчанию производится только проверка возможности патча\n\ -o file - Name of the output file (by default, only a patch test is performed)\n\
-b - добавить патч, отключающий проверку дефектных блоков\n\ -b - Add a patch that disables checking of defective blocks\n\
\n",argv[0]); \n",argv[0]);
return; return;
@ -59,25 +58,26 @@ printf("\n Программа для автоматического патча
} }
} }
printf("\n Программа автоматической модификации загрузчиков Balong V7, (c) forth32"); printf("\n Program for automatic modification of Balong V7 loaders, (c) forth32");
printf("\n English Version (c) robertzaage, 2022");
if (optind>=argc) { if (optind>=argc) {
printf("\n - Не указано имя файла для загрузки\n - Для подсказки укажите ключ -h\n"); printf("\n - Name of the file to load is not specified\n - add -h option for help\n");
return; return;
} }
in=fopen(argv[optind],"rb"); in=fopen(argv[optind],"rb");
if (in == 0) { if (in == 0) {
printf("\n Ошибка открытия файла %s",argv[optind]); printf("\n Can't open file %s",argv[optind]);
return; return;
} }
// определяем размер файла // determine file size
fseek(in,0,SEEK_END); fseek(in,0,SEEK_END);
fsize=ftell(in); fsize=ftell(in);
rewind(in); rewind(in);
// выделяем буфер и читаем туда весь файл // select a buffer and read the whole file there
buf=malloc(fsize); buf=malloc(fsize);
fread(buf,1,fsize,in); fread(buf,1,fsize,in);
fclose(in); fclose(in);
@ -86,49 +86,49 @@ fclose(in);
res=pv7r1(buf, fsize); res=pv7r1(buf, fsize);
if (res != 0) { if (res != 0) {
printf("\n* Найдена сигнатура типа V7R1 по смещению %08x",res); printf("\n* V7R1 type signature found at offset %08x",res);
goto endpatch; goto endpatch;
} }
res=pv7r2(buf, fsize); res=pv7r2(buf, fsize);
if (res != 0) { if (res != 0) {
printf("\n* Найдена сигнатура типа V7R2 по смещению %08x",res); printf("\n* V7R2 type signature found at offset %08x",res);
goto endpatch; goto endpatch;
} }
res=pv7r11(buf, fsize); res=pv7r11(buf, fsize);
if (res != 0) { if (res != 0) {
printf("\n* Найдена сигнатура типа V7R11 по смещению %08x",res); printf("\n* V7R11 type signature found at offset %08x",res);
goto endpatch; goto endpatch;
} }
res=pv7r22(buf, fsize); res=pv7r22(buf, fsize);
if (res != 0) { if (res != 0) {
printf("\n* Найдена сигнатура типа V7R22 по смещению %08x",res); printf("\n* V7R22 type signature found at offset %08x",res);
goto endpatch; goto endpatch;
} }
res=pv7r22_2(buf, fsize); res=pv7r22_2(buf, fsize);
if (res != 0) { if (res != 0) {
printf("\n* Найдена сигнатура типа V7R22_2 по смещению %08x",res); printf("\n* V7R22_2 type signature found at offset %08x",res);
goto endpatch; goto endpatch;
} }
res=pv7r22_3(buf, fsize); res=pv7r22_3(buf, fsize);
if (res != 0) { if (res != 0) {
printf("\n* Найдена сигнатура типа V7R22_3 по смещению %08x",res); printf("\n* V7R22_3 type signature found at offset %08x",res);
goto endpatch; goto endpatch;
} }
printf("\n! Сигнатура eraseall-патча не найдена"); printf("\n! Patch eraseall signature not found");
//================================================================================== //==================================================================================
endpatch: endpatch:
if (bflag) { if (bflag) {
res=perasebad(buf, fsize); res=perasebad(buf, fsize);
if (res != 0) printf("\n* Найдена сигнатура isbad по смещению %08x",res); if (res != 0) printf("\n* Found isbad signature at offset %08x",res);
else printf("\n! Сигнатура isbad не найдена"); else printf("\n! Signature isbad not found");
} }
if (oflag) { if (oflag) {
@ -137,10 +137,8 @@ if (oflag) {
fwrite(buf,1,fsize,out); fwrite(buf,1,fsize,out);
fclose(out); fclose(out);
} }
else printf("\n Ошибка открытия выходного файла %s",outfilename); else printf("\n Error opening output file %s",outfilename);
} }
free(buf); free(buf);
printf("\n"); printf("\n");
} }

@ -11,11 +11,11 @@
#include "parts.h" #include "parts.h"
// сигнатура заголовка таблицы // header signature table
const uint8_t headmagic[16]={0x70, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x48, 0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80}; const uint8_t headmagic[16]={0x70, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x48, 0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80};
//********************************************* //*********************************************
//* Поиск таблицы разделов в загрузчике //* Search for the partition table in the loader
//********************************************* //*********************************************
uint32_t find_ptable(FILE* ldr) { uint32_t find_ptable(FILE* ldr) {
@ -31,14 +31,14 @@ return 0;
} }
//********************************************* //*********************************************
//* Печать таблицы разделов //* Printing the partition table
//********************************************* //*********************************************
void show_map(struct ptable_t ptable) { void show_map(struct ptable_t ptable) {
int pnum; int pnum;
printf("\n Версия таблицы разделов: %16.16s",ptable.version); printf("\n Partition table version: %16.16s",ptable.version);
printf("\n Версия прошивки: %16.16s\n",ptable.product); printf("\n Firmware version: %16.16s\n",ptable.product);
printf("\n ## ----- NAME ----- start len loadsize loadaddr entry flags type count\n------------------------------------------------------------------------------------------"); printf("\n ## ----- NAME ----- start len loadsize loadaddr entry flags type count\n------------------------------------------------------------------------------------------");
@ -64,11 +64,11 @@ printf("\n");
} }
//********************************************* //*********************************************
//* Поиск таблицы разделов в памяти //* Search for partition table in memory
//********************************************* //*********************************************
uint32_t find_ptable_ram(char* buf, uint32_t size) { uint32_t find_ptable_ram(char* buf, uint32_t size) {
// сигнатура заголовка таблицы // header signature table
uint32_t off; uint32_t off;
for(off=0;off<(size-16);off+=4) { for(off=0;off<(size-16);off+=4) {
@ -76,4 +76,3 @@ for(off=0;off<(size-16);off+=4) {
} }
return 0; return 0;
} }

@ -1,5 +1,5 @@
// Структура описателя раздела // partition descriptor structure
struct ptable_line{ struct ptable_line{
char name[16]; char name[16];
unsigned start; unsigned start;
@ -8,11 +8,11 @@ struct ptable_line{
unsigned loadaddr; unsigned loadaddr;
unsigned entry; unsigned entry;
unsigned type; unsigned type;
unsigned nproperty; // флаги раздела unsigned nproperty; // partition flags
unsigned count; unsigned count;
}; };
// Полная структура страницы таблицы разделов // pull page structure from partition table
struct ptable_t { struct ptable_t {
uint8_t head[16]; uint8_t head[16];
uint8_t version[16]; uint8_t version[16];
@ -21,7 +21,7 @@ struct ptable_t {
uint8_t tail[32]; uint8_t tail[32];
}; };
// сигнатура заголовка таблицы // header signature table
extern const uint8_t headmagic[16]; extern const uint8_t headmagic[16];
uint32_t find_ptable(FILE* ldr); uint32_t find_ptable(FILE* ldr);

@ -4,21 +4,21 @@
#include <stdlib.h> #include <stdlib.h>
//*********************************************************************** //***********************************************************************
//* Поиск сигнатуры и наложение патча //* Find the signature and apply the patch
//* //*
//* ptype=0 - nop-патч //* ptype=0 - nop-patch
//* ptype=1 - br-патч //* ptype=1 - br-patch
//*********************************************************************** //***********************************************************************
uint32_t patch(struct defpatch fp, uint8_t* buf, uint32_t fsize, uint32_t ptype) { uint32_t patch(struct defpatch fp, uint8_t* buf, uint32_t fsize, uint32_t ptype) {
// накладываемый патч - mov r0,#0 // overlapping patch - mov r0,#0
const char nop0[4]={0, 0, 0xa0, 0xe3}; const char nop0[4]={0, 0, 0xa0, 0xe3};
uint32_t i; uint32_t i;
uint8_t c; uint8_t c;
for(i=8;i<(fsize-60);i+=4) { for(i=8;i<(fsize-60);i+=4) {
if (memcmp(buf+i,fp.sig, fp.sigsize) == 0) { if (memcmp(buf+i,fp.sig, fp.sigsize) == 0) {
// найдена сигнатура - накладываем патч и уходим // a signature is found - apply the patch and exit
switch (ptype) { switch (ptype) {
case 0: case 0:
memcpy(buf+i+fp.sigsize+fp.poffset,nop0,4); memcpy(buf+i+fp.sigsize+fp.poffset,nop0,4);
@ -35,12 +35,12 @@ for(i=8;i<(fsize-60);i+=4) {
} }
} }
} }
// сигнатрура не найдена // no signature found
return 0; return 0;
} }
//********************************************** //**********************************************
// Описатели патчей // Patch Descriptors
//********************************************** //**********************************************
const char sigburn_v7r22[]={ const char sigburn_v7r22[]={
@ -85,7 +85,7 @@ struct defpatch patch_erasebad={sigbad, sizeof(sigbad), 0};
//**************************************************** //****************************************************
//* Процедуры патча под разные чипсеты и задачи //* Patch procedures for different chipsets and tasks
//**************************************************** //****************************************************
uint32_t pv7r2 (uint8_t* buf, uint32_t fsize) { return patch(patch_v7r2, buf, fsize,0); } uint32_t pv7r2 (uint8_t* buf, uint32_t fsize) { return patch(patch_v7r2, buf, fsize,0); }
@ -95,4 +95,3 @@ uint32_t pv7r22 (uint8_t* buf, uint32_t fsize) { return patch(patch_v7r22, buf,
uint32_t pv7r22_2 (uint8_t* buf, uint32_t fsize) { return patch(patch_v7r22_2, buf, fsize,0); } uint32_t pv7r22_2 (uint8_t* buf, uint32_t fsize) { return patch(patch_v7r22_2, buf, fsize,0); }
uint32_t pv7r22_3 (uint8_t* buf, uint32_t fsize) { return patch(patch_v7r22_3, buf, fsize,0); } uint32_t pv7r22_3 (uint8_t* buf, uint32_t fsize) { return patch(patch_v7r22_3, buf, fsize,0); }
uint32_t perasebad (uint8_t* buf, uint32_t fsize) { return patch(patch_erasebad, buf, fsize,0); } uint32_t perasebad (uint8_t* buf, uint32_t fsize) { return patch(patch_erasebad, buf, fsize,0); }

@ -1,5 +1,4 @@
// Программа для замены таблицы разделов в загрузчике usbloader // Program to replace the partition table in the usbloader
//
// //
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
@ -18,7 +17,6 @@
#include "parts.h" #include "parts.h"
//############################################################################################################3 //############################################################################################################3
void main(int argc, char* argv[]) { void main(int argc, char* argv[]) {
@ -40,13 +38,13 @@ while ((opt = getopt(argc, argv, "mr:hx")) != -1) {
switch (opt) { switch (opt) {
case 'h': case 'h':
printf("\n Утилита для замены таблицы разделов в загрузчиках usbloader\ printf("\n Utility for partition table replacement in usbloaders\
\n\n\ \n\n\
%s [ключи] <имя файла usbloader>\n\n\ %s [options] <file name usbloader>\n\n\
Допустимы следующие ключи:\n\n\ Following options are allowed:\n\n\
-m - показать текущую карту разделов в usbloader\n\ -m - Show current partition map in usbloader\n\
-x - извлечь текущую карту в файл ptable.bin\n\ -x - Extract current partition map to ptable.bin file\n\
-r <file>- заменить карту разделов на карту из указанного файла\n\ -r <file> - Replace current partition map with map from specified file\n\
\n",argv[0]); \n",argv[0]);
return; return;
@ -70,25 +68,24 @@ printf("\n Утилита для замены таблицы разделов в
} }
} }
if (optind>=argc) { if (optind>=argc) {
printf("\n - Не указано имя файла загрузчика\n"); printf("\n - Loader file name is not specified\n");
return; return;
} }
ldr=fopen(argv[optind],"r+b"); ldr=fopen(argv[optind],"r+b");
if (ldr == 0) { if (ldr == 0) {
printf("\n Ошибка открытия файла %s\n",argv[optind]); printf("\n Can't open file %s\n",argv[optind]);
return; return;
} }
// searching for the partition table in the loader file
// Ищем таблицу разделов в файле загрузчика
ptaddr=find_ptable(ldr); ptaddr=find_ptable(ldr);
if (ptaddr == 0) { if (ptaddr == 0) {
printf("\n Таблица разделов в загрузчике не найдена\n"); printf("\n Таблица разделов в загрузчике не найдена\n");
return ; return ;
} }
// читаем текущую таблицу // read the current table
fread(&ptable,sizeof(ptable),1,ldr); fread(&ptable,sizeof(ptable),1,ldr);
if (xflag) { if (xflag) {
@ -103,19 +100,18 @@ if (mflag) {
if (mflag | xflag) return; if (mflag | xflag) return;
if (rflag) { if (rflag) {
in=fopen(ptfile,"rb"); in=fopen(ptfile,"rb");
if (in == 0) { if (in == 0) {
printf("\n Ошибка открытия файла %s",ptfile); printf("\n Can't open file %s",ptfile);
return; return;
} }
fread(&ptable,sizeof(ptable),1,in); fread(&ptable,sizeof(ptable),1,in);
fclose(in); fclose(in);
// проверяем файл // check the file
if (memcmp(ptable.head,headmagic,16) != 0) { if (memcmp(ptable.head,headmagic,16) != 0) {
printf("\n Входной файл не является таблицей разделов\n"); printf("\n Input file is not a partition table\n");
return; return;
} }
fseek(ldr,ptaddr,SEEK_SET); fseek(ldr,ptaddr,SEEK_SET);

@ -1,5 +1,4 @@
// Программа для замены таблицы разделов в загрузчике usbloader // Program to replace the partition table in the usbloader
//
// //
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
@ -18,33 +17,30 @@
#include "parts.h" #include "parts.h"
//############################################################################################################3 //############################################################################################################3
void main(int argc, char* argv[]) { void main(int argc, char* argv[]) {
struct ptable_t ptable; struct ptable_t ptable;
FILE* in; FILE* in;
if (argc != 2) { if (argc != 2) {
printf("\n - Не указано имя файла с таблицей разделов\n"); printf("\n - Partition table file name is not specified\n");
return; return;
} }
in=fopen(argv[optind],"r+b"); in=fopen(argv[optind],"r+b");
if (in == 0) { if (in == 0) {
printf("\n Ошибка открытия файла %s\n",argv[optind]); printf("\n Can't open file %s\n",argv[optind]);
return; return;
} }
// читаем текущую таблицу // read current table
fread(&ptable,sizeof(ptable),1,in); fread(&ptable,sizeof(ptable),1,in);
if (strncmp(ptable.head, "pTableHead", 16) != 0) { if (strncmp(ptable.head, "pTableHead", 16) != 0) {
printf("\n Файл не является таблицей разделов\n"); printf("\n File is not a partition table\n");
return ; return ;
} }

Loading…
Cancel
Save