You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

373 lines
12 KiB
C

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

// Partition table procedures
#include <stdio.h>
#include <stdint.h>
#ifndef WIN32
#include <string.h>
#include <stdlib.h>
#else
#include <windows.h>
#include "printf.h"
#endif
#include <zlib.h>
#include "ptable.h"
#include "hdlcio.h"
#include "util.h"
#include "signver.h"
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) {
unsigned int j;
struct {
char name[20];
int code;
} pcodes[]={
{"M3Boot",0x20000},
{"M3Boot-ptable",0x10000},
{"M3Boot_R11",0x200000},
{"Ptable",0x10000},
{"Ptable_ext_A",0x480000},
{"Ptable_ext_B",0x490000},
{"Fastboot",0x110000},
{"Logo",0x130000},
{"Kernel",0x30000},
{"Kernel_R11",0x90000},
{"DTS_R11",0x270000},
{"VxWorks",0x40000},
{"VxWorks_R11",0x220000},
{"M3Image",0x50000},
{"M3Image_R11",0x230000},
{"DSP",0x60000},
{"DSP_R11",0x240000},
{"Nvdload",0x70000},
{"Nvdload_R11",0x250000},
{"Nvimg",0x80000},
{"System",0x590000},
{"System",0x100000},
{"APP",0x570000},
{"APP",0x5a0000},
{"APP_EXT_A",0x450000},
{"APP_EXT_B",0x460000},
{"Oeminfo",0xa0000},
{"CDROMISO",0xb0000},
{"Oeminfo",0x550000},
{"Oeminfo",0x510000},
{"Oeminfo",0x1a0000},
{"WEBUI",0x560000},
{"WEBUI",0x5b0000},
{"Wimaxcfg",0x170000},
{"Wimaxcrf",0x180000},
{"Userdata",0x190000},
{"Online",0x1b0000},
{"Online",0x5d0000},
{"Online",0x5e0000},
{"Ptable_R1",0x100},
{"Bootloader_R1",0x101},
{"Bootrom_R1",0x102},
{"VxWorks_R1",0x550103},
{"Fastboot_R1",0x104},
{"Kernel_R1",0x105},
{"System_R1",0x107},
{"Nvimage_R1",0x66},
{"WEBUI_R1",0x113},
{"APP_R1",0x109},
{"HIFI_R11",0x280000},
{"Modem_fw",0x1e0000},
{"Teeos",0x290000},
{0,0}
};
for(j=0;pcodes[j].code != 0;j++) {
if(pcodes[j].code == id) break;
}
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);
}
//*******************************************************************
// Obtaining partition image size
//*******************************************************************
uint32_t psize(int n) {
return ptable[n].hd.psize;
}
//*******************************************************
//* Header block checksum calculation
//*******************************************************
void calc_hd_crc16(int n) {
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; // 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; // 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++; // 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; // shift to the current block
len=blocksize;
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);
}
// 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);
// recalculate CRC header
calc_hd_crc16(n);
}
//*******************************************************************
//* Extract partition from file and add it to partition table
//*
//* "in" is the input firmware file
//* position in file corresponds to the beginning of partition header
//*******************************************************************
void extract(FILE* in) {
uint16_t hcrc,crc;
uint16_t* crcblock;
uint32_t crcblocksize;
uint8_t* zbuf;
long int zlen;
int res;
ptable[npart].zflag=0;
// read the header into the structure
ptable[npart].offset=ftell(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);
// 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);
// check the CRC of the header
hcrc=ptable[npart].hd.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! Partition %s (%02x) - header checksum error",ptable[npart].pname,ptable[npart].hd.code>>16);
errflag=1;
}
ptable[npart].hd.crc=crc; // recover CRC
// calculate and check the CRC of the partition
calc_crc16(npart);
if (crcblocksize != crcsize(npart)) {
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! Partition %s (%02x) - incorrect block checksum",ptable[npart].pname,ptable[npart].hd.code>>16);
errflag=1;
}
free(crcblock);
ptable[npart].ztype=' ';
// definition of zlib-compression
if ((*(uint16_t*)ptable[npart].pimage) == 0xda78) {
ptable[npart].zflag=ptable[npart].hd.psize; // keep the compressed size
zlen=52428800;
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! 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 compression detection
if ((ptable[npart].pimage[0] == 0x5d) && (*(uint64_t*)(ptable[npart].pimage+5) == 0xffffffffffffffff)) {
ptable[npart].zflag=ptable[npart].hd.psize; // keep the compressed size
zlen=100 * 1024 * 1024;
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 Buffer size exceeded\n");
exit(1);
}
if (res == -1) {
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 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 No partitions found in file - the file does not contain a firmware image\n");
exit(0);
}
// 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 Wrong file header size\n");
exit(0);
}
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];
// 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 Incorrect firmware type code (dload_id) in header - %x",dload_id);
exit(0);
}
printf("\n Firmware file code: %x (%s)\n",hd_dload_id,fw_description(hd_dload_id));
// search for other partitions
do {
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 Digital Signature: Not found");
else {
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 ! 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];
FILE* in;
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; // 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! 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 Can't open file %s",filename);
return;
}
fread(ptable[npart].pimage,ptable[npart].hd.psize,1,in);
fclose(in);
}
if (npart == 0) {
printf("\n! No partition image files were found in directory %s",fdir);
exit(0);
}
}