Quick & dirty tool to extract & create the sunxi-package format.
- aligns are cosmetic, edit if needed.
- fex is probably not used by kernel 4.0+, look at dtb instead.
- 2 instances of package in flash, patch both.
| /* | |
| * sunxi-packagetool.c | |
| * | |
| * based on https://github.com/ua1arn/hftrx/blob/master/tools/bootutil.c | |
| * | |
| */ | |
| #include <stdio.h> | |
| #include <string.h> | |
| #include <stdlib.h> | |
| // http://nskhuman.ru/allwinner/firmware.php?np=2&nf=3 | |
| // https://trustedfirmware-a.readthedocs.io/en/latest/plat/allwinner.html | |
| // offset 0x2000 | |
| // offset 0x1004000 | |
| typedef unsigned int uint32_t; | |
| typedef unsigned char uint8_t; | |
| #define TOC_MAIN_INFO_MAGIC 0x89119800 | |
| #define STAMP_VALUE 0x5F0A6C39 /* ????????? ???????? ??? ????????? ??????????? ????? */ | |
| #define INNER_ALIGN_SIZE (1 * 1024) | |
| #define OUTER_ALIGN_SIZE (16 * 1024) | |
| #define MAGIC_SIZE 8 | |
| //#define STORAGE_BUFFER_SIZE (256) | |
| #define TOC_MAIN_INFO_MAGIC 0x89119800 | |
| #define TOC_MAIN_INFO_END 0x3b45494d | |
| #define TOC_ITEM_INFO_END 0x3b454949 | |
| static const char sunxi_package_sign [16] = "sunxi-package"; | |
| //static const char item_signature [64] = ITEM_UBOOT_NAME; | |
| //static const char item_signature [64] = "falcon-boot"; /* ??????????? ?????????????? */ | |
| // ????????? ????????? ?????? boot_package.fex, ???????? ?????? 64 ?????: | |
| // https://github.com/lindenis-org/lindenis-v853-lichee-brandy-2.0-spl-pub/blob/d36b228278e654d7d7bfa2f5f777311b6d9dc61b/nboot/main/boot0_main.c#L103 | |
| struct head_info // ????????? ? ????? ??????????? ? ?????? | |
| { | |
| char name[16]; // ???????????? ????? ???????? | |
| uint32_t magic; // ?????? ???? ????? TOC_MAIN_INFO_MAGIC | |
| uint32_t add_sum; // ??????????? ????? | |
| uint32_t serial_num; // ???????????? ????? ???????? | |
| uint32_t status; // ???????????? ????? ???????? | |
| uint32_t items_nr; // ????? ?????????? ??????? (??????) = 4 | |
| uint32_t valid_len; // ?????? ????? boot_package.fex | |
| uint32_t version_main; // ?????? ???? ???? | |
| uint32_t version_sub; // ??? ????? | |
| uint32_t reserved[3]; // ??????????????? | |
| uint32_t end; | |
| }; | |
| // ?????? ????? ?????? ????????? ??? ??????? item (?.?. ??????????? ??????????? ??????). ?????? ??????? ????????? 368 ????. | |
| // ????????? ????????? ??????? item: | |
| // | |
| struct item_info { | |
| char item_name[64]; // ??? ?????, ???????? monitor | |
| uint32_t data_offset; // + 0x40 ???????? | |
| uint32_t data_len; // + 0x44 ?????? | |
| uint32_t encrypt; // + 0x48 ?????????? 0: ??? AES, 1: AES | |
| uint32_t type; // + 0x4C 0: ??????? ????, ??? ????? | |
| // 1: ???? ??????????? | |
| // 2: ??????? ??????????? | |
| // 3: ???????? ???? | |
| uint32_t run_addr; // + 0x50 ???? ??? bin-????, ?? ????????? ?? ????? ??????; ???? ???, ?? ?????? ???? 0 | |
| uint32_t index; // 0x54 ???? ??? bin-????, ?? ???????? ?????????? ?????? ??? ??????? | |
| // ???? ??? ???? ???????????, ?? ?????? ???? ????? ??????? ????? bin, | |
| // ??? ????????, ??? ??? ? ????? ?????? | |
| // ?????? ???? = 0 ??? ?????? ??????? ???? ?????? | |
| uint32_t reserved[69]; // ??????????????? ?? ???????; | |
| uint32_t end; | |
| }; | |
| unsigned calccks(const void * p, size_t len, unsigned cks) | |
| { | |
| const uint32_t * data = (const uint32_t *) p; | |
| len = (len + 3) / 4; | |
| while (len --) | |
| cks += * data ++; | |
| return cks; | |
| } | |
| unsigned alignup(unsigned val, unsigned granulation) | |
| { | |
| return (val + granulation - 1) & ~ (granulation - 1); | |
| } | |
| #define FILLV 0x00 | |
| void getfileinfo(FILE * src, long int * length, unsigned * checksum, unsigned cks) | |
| { | |
| int c; | |
| fseek(src, 0, SEEK_END); | |
| * length = ftell(src); | |
| rewind(src); | |
| for (;;) | |
| { | |
| enum { CHUNK = 1024 }; | |
| size_t n; | |
| unsigned char b [CHUNK]; | |
| n = fread(b, 1, CHUNK, src); | |
| if (n == 0) | |
| break; | |
| else if (n < CHUNK) | |
| memset(b + n, FILLV, CHUNK - n); | |
| cks = calccks(b, n, cks); | |
| } | |
| * checksum = cks; | |
| } | |
| void copyfile(FILE * dst, FILE * src) | |
| { | |
| int c; | |
| rewind(src); | |
| for (;;) | |
| { | |
| enum { CHUNK = 1024 }; | |
| size_t n; | |
| unsigned char b [CHUNK]; | |
| n = fread(b, 1, CHUNK, src); | |
| if (n == 0) | |
| break; | |
| fwrite(b, 1, n, dst); | |
| } | |
| } | |
| void fillfile(FILE * dst, size_t n) | |
| { | |
| while (n --) | |
| fputc(FILLV, dst); | |
| } | |
| void makedata(FILE * fp, char ** datafilenames, unsigned datafilecount, unsigned baseaddr) | |
| { | |
| FILE * datafile; | |
| struct head_info hi; | |
| struct item_info* ii; | |
| unsigned item; | |
| long int isize; | |
| uint32_t datafilecks; | |
| uint32_t datafileckss = STAMP_VALUE; | |
| unsigned dataoffset = alignup((sizeof (struct head_info)) + (sizeof (struct item_info)*datafilecount), INNER_ALIGN_SIZE); | |
| unsigned headerpad = dataoffset - (sizeof (struct head_info) + (sizeof (struct item_info)*datafilecount)); | |
| unsigned datapad; | |
| unsigned isizealigned = 0; | |
| unsigned totaldatalen = 0; | |
| unsigned i; | |
| ii = malloc(sizeof(struct item_info)*datafilecount); | |
| memset(ii, 0, sizeof (struct item_info)*datafilecount); | |
| for (i=0;i<datafilecount;i++) { | |
| datafile = fopen(datafilenames[i], "rb"); | |
| if (datafile == NULL) | |
| return; | |
| getfileinfo(datafile, &isize, &datafilecks, datafileckss); | |
| isizealigned = alignup(isize, INNER_ALIGN_SIZE); | |
| datapad = isizealigned - isize; | |
| /* printf("adding %16s, sz:%x, sza:%x, pad:%x, cks:%x\n",datafilenames[i],isize, isizealigned,datapad,datafilecks);*/ | |
| strcpy(ii[i].item_name,datafilenames[i]); | |
| ii[i].type = 3; | |
| ii[i].run_addr = baseaddr; // Loaded image start address | |
| ii[i].data_offset = dataoffset; | |
| ii[i].data_len = isize; | |
| ii[i].end = TOC_ITEM_INFO_END; // IIE; | |
| //printf("dataoffset=%08X\n", dataoffset); | |
| //ii [item].index = 1; | |
| totaldatalen += isizealigned; | |
| dataoffset += isizealigned; | |
| datafileckss = datafilecks; | |
| fclose(datafile); | |
| } | |
| memset(&hi, 0, sizeof (struct head_info)); | |
| memcpy(hi.name, sunxi_package_sign, sizeof hi.name); | |
| hi.magic = TOC_MAIN_INFO_MAGIC; | |
| hi.end = TOC_MAIN_INFO_END; // MIE; | |
| hi.items_nr = datafilecount; | |
| // Fill item info | |
| hi.valid_len = alignup(sizeof (struct head_info) + (sizeof (struct item_info)*datafilecount) + headerpad + totaldatalen,OUTER_ALIGN_SIZE); | |
| hi.add_sum = calccks(&hi, sizeof (struct head_info), calccks(ii, sizeof (struct item_info)*datafilecount, datafileckss)); | |
| // save result | |
| fwrite(&hi, sizeof (struct head_info), 1, fp); | |
| for (i=0;i<datafilecount;i++) { | |
| printf("%16s\toffset:%08x, len:%08x, crypt:%04x, type:%04x, addr:%04x, index:%04x\n",(ii+i)->item_name, | |
| (ii+i)->data_offset,(ii+i)->data_len,(ii+i)->encrypt,(ii+i)->type,(ii+i)->run_addr,(ii+i)->index); | |
| fwrite(&ii[i], sizeof(struct item_info), 1, fp); | |
| } | |
| fillfile(fp, headerpad); | |
| for (i=0;i<datafilecount;i++) { | |
| datafile = fopen(datafilenames[i], "rb"); | |
| getfileinfo(datafile, &isize, &datafilecks, datafileckss); | |
| isizealigned = alignup(isize, INNER_ALIGN_SIZE); | |
| datapad = isizealigned - isize; | |
| copyfile(fp, datafile); | |
| fillfile(fp, datapad); | |
| fclose(datafile); | |
| } | |
| datapad = hi.valid_len-ftell(fp); | |
| fillfile(fp,datapad); | |
| } | |
| int main(int argc, char **argv) { | |
| unsigned loadaddr;// = 0x40400100; | |
| const char * outfilename;// = "o.bin"; | |
| const char * file;// = "tc1_awt507_app.bin"; | |
| FILE * out; | |
| FILE * in; | |
| unsigned int fsz; | |
| struct head_info hinfo; | |
| struct item_info* items; | |
| int i,j; | |
| unsigned char* buff; | |
| if (argc==1) { | |
| printf(" extract: ./sunxi-packagetool <inblob.bin>\n create: ./sunxi-packagetool <outblob.bin> <load-addr> <file1> <file2> ... <fileN>\n"); | |
| return 0; | |
| } | |
| if (argc >= 4) | |
| { | |
| printf("creating %s\n",argv[1]); | |
| outfilename = argv [1]; | |
| loadaddr = strtoul(argv [2], NULL, 0); | |
| printf("%d files to add\n",argc-3); | |
| out = fopen(outfilename, "wb"); | |
| if (out == NULL) | |
| return 1; | |
| makedata(out, (argv+3), argc-3, loadaddr); | |
| fclose(out); | |
| return 0; | |
| } | |
| else | |
| { | |
| printf("extracting %s\n",argv[1]); | |
| in = fopen(argv[1],"rb"); | |
| fseek(in, 0L, SEEK_END); | |
| fsz = ftell(in); | |
| rewind(in); | |
| printf("file size %0d\n",fsz); | |
| fread(&hinfo,sizeof(hinfo),1,in); | |
| if (strcmp(hinfo.name,sunxi_package_sign) == 0) { | |
| printf("sunxi package magic found\n"); | |
| printf("chksum: %04x, serial:%04x, status:%04x, items: %d, valid: %d, version:%d.%d \n",hinfo.add_sum,hinfo.serial_num, | |
| hinfo.status,hinfo.items_nr,hinfo.valid_len,hinfo.version_main,hinfo.version_sub); | |
| printf("\nfiles:\n\n"); | |
| items = malloc(hinfo.items_nr*sizeof(struct item_info)); | |
| for (i=0;i<hinfo.items_nr;i++) { | |
| fread(items+i,sizeof(struct item_info),1,in); | |
| printf("%16s\toffset:%08x, len:%08x, crypt:%04x, type:%04x, addr:%04x, index:%04x\n",(items+i)->item_name, | |
| (items+i)->data_offset,(items+i)->data_len,(items+i)->encrypt,(items+i)->type,(items+i)->run_addr,(items+i)->index); | |
| j = ftell(in); | |
| out=fopen((items+i)->item_name,"wb"); | |
| fseek(in,(items+i)->data_offset,SEEK_SET); | |
| buff = malloc((items+i)->data_len); | |
| fread(buff,(items+i)->data_len,1,in); | |
| fwrite(buff,(items+i)->data_len,1,out); | |
| fclose(out); | |
| fseek(in,j,SEEK_SET); | |
| } | |
| } | |
| } | |
| return 0; | |
| } |
Quick & dirty tool to extract & create the sunxi-package format.