Skip to content

Instantly share code, notes, and snippets.

@apramorbis
Last active November 7, 2024 23:18
Show Gist options
  • Save apramorbis/842f681fb0262bd12f268c448779a375 to your computer and use it in GitHub Desktop.
Save apramorbis/842f681fb0262bd12f268c448779a375 to your computer and use it in GitHub Desktop.
sunxi-package tool
/*
* 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.

  • 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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment