forked from len0rd/rockbox
atjboottool: put afi and fw code in its own files
Change-Id: I16347ebee0f82d5fdf32f5aa8f955c07fe148eba
This commit is contained in:
parent
95c32a505a
commit
ea679de837
7 changed files with 500 additions and 393 deletions
|
@ -10,7 +10,7 @@ all: $(BINS)
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
$(CC) $(CFLAGS) -c -o $@ $<
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
atjboottool: atjboottool.o fwu.o misc.o atj_tables.o
|
atjboottool: atjboottool.o fwu.o fw.o afi.o misc.o atj_tables.o
|
||||||
$(LD) -o $@ $^ $(LDFLAGS)
|
$(LD) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
|
|
208
utils/atj2137/atjboottool/afi.c
Normal file
208
utils/atj2137/atjboottool/afi.c
Normal file
|
@ -0,0 +1,208 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Amaury Pouly
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include "misc.h"
|
||||||
|
#include "afi.h"
|
||||||
|
|
||||||
|
/** part of this work comes from s1mp3/s1fwx */
|
||||||
|
|
||||||
|
#define AFI_ENTRIES 126
|
||||||
|
#define AFI_SIG_SIZE 4
|
||||||
|
|
||||||
|
struct afi_hdr_t
|
||||||
|
{
|
||||||
|
uint8_t sig[AFI_SIG_SIZE];
|
||||||
|
uint16_t vendor_id;
|
||||||
|
uint16_t product_id;
|
||||||
|
uint8_t ver_id[2];
|
||||||
|
uint8_t ext_ver_id[2];
|
||||||
|
uint8_t year[2];
|
||||||
|
uint8_t month;
|
||||||
|
uint8_t day;
|
||||||
|
uint32_t afi_size;
|
||||||
|
uint32_t res[3];
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct afi_entry_t
|
||||||
|
{
|
||||||
|
char name[8];
|
||||||
|
char ext[3];
|
||||||
|
char type;
|
||||||
|
uint32_t addr;
|
||||||
|
uint32_t offset;
|
||||||
|
uint32_t size;
|
||||||
|
char desc[4];
|
||||||
|
uint32_t checksum;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct afi_post_hdr_t
|
||||||
|
{
|
||||||
|
uint8_t res[28];
|
||||||
|
uint32_t checksum;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct afi_t
|
||||||
|
{
|
||||||
|
struct afi_hdr_t hdr;
|
||||||
|
struct afi_entry_t entry[AFI_ENTRIES];
|
||||||
|
struct afi_post_hdr_t post;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define AFI_ENTRY_BREC 'B'
|
||||||
|
#define AFI_ENTRY_FWSC 'F'
|
||||||
|
#define AFI_ENTRY_ADFUS 'A'
|
||||||
|
#define AFI_ENTRY_FW 'I'
|
||||||
|
|
||||||
|
#define AFI_ENTRY_DLADR_BREC 0x00000006 // 'B'
|
||||||
|
#define AFI_ENTRY_DLADR_FWSC 0x00020008 // 'F'
|
||||||
|
#define AFI_ENTRY_DLADR_ADFUS 0x000C0008 // 'A'
|
||||||
|
#define AFI_ENTRY_DLADR_ADFU 0x00000000 // 'U'
|
||||||
|
#define AFI_ENTRY_DLADR_FW 0x00000011 // 'I'
|
||||||
|
|
||||||
|
const uint8_t g_afi_signature[AFI_SIG_SIZE] =
|
||||||
|
{
|
||||||
|
'A', 'F', 'I', 0
|
||||||
|
};
|
||||||
|
|
||||||
|
uint32_t afi_checksum(void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
uint32_t crc = 0;
|
||||||
|
uint32_t *cp = ptr;
|
||||||
|
for(; size >= 4; size -= 4)
|
||||||
|
crc += *cp++;
|
||||||
|
if(size == 1)
|
||||||
|
crc += *(uint8_t *)cp;
|
||||||
|
else if(size == 2)
|
||||||
|
crc += *(uint16_t *)cp;
|
||||||
|
else if(size == 3)
|
||||||
|
crc += *(uint16_t *)cp + ((*(uint8_t *)(cp + 2)) << 16);
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void build_filename(char buf[16], struct afi_entry_t *ent)
|
||||||
|
{
|
||||||
|
int pos = 0;
|
||||||
|
for(int i = 0; i < 8 && ent->name[i] != ' '; i++)
|
||||||
|
buf[pos++] = ent->name[i];
|
||||||
|
buf[pos++] = '.';
|
||||||
|
for(int i = 0; i < 3 && ent->ext[i] != ' '; i++)
|
||||||
|
buf[pos++] = ent->ext[i];
|
||||||
|
buf[pos] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int afi_unpack(uint8_t *buf, size_t size, afi_extract_callback_t unpack_cb)
|
||||||
|
{
|
||||||
|
struct afi_t *afi = (void *)buf;
|
||||||
|
|
||||||
|
if(size < sizeof(struct afi_t))
|
||||||
|
{
|
||||||
|
cprintf(GREY, "File too small\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
cprintf(BLUE, "Header\n");
|
||||||
|
cprintf(GREEN, " Signature:");
|
||||||
|
for(int i = 0; i < AFI_SIG_SIZE; i++)
|
||||||
|
cprintf(YELLOW, " %02x", afi->hdr.sig[i]);
|
||||||
|
if(memcmp(afi->hdr.sig, g_afi_signature, AFI_SIG_SIZE) == 0)
|
||||||
|
cprintf(RED, " Ok\n");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cprintf(RED, " Mismatch\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cprintf_field(" Vendor ID: ", "0x%x\n", afi->hdr.vendor_id);
|
||||||
|
cprintf_field(" Product ID: ", "0x%x\n", afi->hdr.product_id);
|
||||||
|
cprintf_field(" Version: ", "%x.%x\n", afi->hdr.ver_id[0], afi->hdr.ver_id[1]);
|
||||||
|
cprintf_field(" Ext Version: ", "%x.%x\n", afi->hdr.ext_ver_id[0],
|
||||||
|
afi->hdr.ext_ver_id[1]);
|
||||||
|
cprintf_field(" Date: ", "%02x/%02x/%02x%02x\n", afi->hdr.day, afi->hdr.month,
|
||||||
|
afi->hdr.year[0], afi->hdr.year[1]);
|
||||||
|
|
||||||
|
cprintf_field(" AFI size: ", "%d ", afi->hdr.afi_size);
|
||||||
|
if(afi->hdr.afi_size == size)
|
||||||
|
cprintf(RED, " Ok\n");
|
||||||
|
else if(afi->hdr.afi_size < size)
|
||||||
|
cprintf(RED, " Ok (file greater than archive)\n");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cprintf(RED, " Error (file too small)\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cprintf_field(" Reserved: ", "%x %x %x\n", afi->hdr.res[0],
|
||||||
|
afi->hdr.res[1], afi->hdr.res[2]);
|
||||||
|
|
||||||
|
cprintf(BLUE, "Entries\n");
|
||||||
|
for(int i = 0; i < AFI_ENTRIES; i++)
|
||||||
|
{
|
||||||
|
if(afi->entry[i].name[0] == 0)
|
||||||
|
continue;
|
||||||
|
struct afi_entry_t *entry = &afi->entry[i];
|
||||||
|
char filename[16];
|
||||||
|
build_filename(filename, entry);
|
||||||
|
cprintf(RED, " %s\n", filename);
|
||||||
|
cprintf_field(" Type: ", "%02x", entry->type);
|
||||||
|
if(isprint(entry->type))
|
||||||
|
cprintf(RED, " %c", entry->type);
|
||||||
|
printf("\n");
|
||||||
|
cprintf_field(" Addr: ", "0x%x\n", entry->addr);
|
||||||
|
cprintf_field(" Offset: ", "0x%x\n", entry->offset);
|
||||||
|
cprintf_field(" Size: ", "0x%x\n", entry->size);
|
||||||
|
cprintf_field(" Desc: ", "%.4s\n", entry->desc);
|
||||||
|
cprintf_field(" Checksum: ", "0x%x ", entry->checksum);
|
||||||
|
uint32_t chk = afi_checksum(buf + entry->offset, entry->size);
|
||||||
|
if(chk != entry->checksum)
|
||||||
|
{
|
||||||
|
cprintf(RED, "Mismatch\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cprintf(RED, "Ok\n");
|
||||||
|
int ret = unpack_cb(filename, buf + entry->offset, entry->size);
|
||||||
|
if(ret != 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
cprintf(BLUE, "Post Header\n");
|
||||||
|
cprintf_field(" Checksum: ", "%x ", afi->post.checksum);
|
||||||
|
uint32_t chk = afi_checksum(buf, sizeof(struct afi_t) - 4);
|
||||||
|
if(chk != afi->post.checksum)
|
||||||
|
{
|
||||||
|
cprintf(RED, "Mismatch\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cprintf(RED, "Ok\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool afi_check(uint8_t *buf, size_t size)
|
||||||
|
{
|
||||||
|
struct afi_hdr_t *hdr = (void *)buf;
|
||||||
|
|
||||||
|
if(size < sizeof(struct afi_hdr_t))
|
||||||
|
return false;
|
||||||
|
return memcmp(hdr->sig, g_afi_signature, AFI_SIG_SIZE) == 0;
|
||||||
|
}
|
|
@ -23,7 +23,13 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
/* Check if a file looks like a FWU file */
|
uint32_t afi_checksum(void *ptr, size_t size);
|
||||||
|
/* Unpack an AFI file: the callback function will be called once for each file in the archive with
|
||||||
|
* its name and content. If the callback returns a nonzero value, the function will stop and return
|
||||||
|
* that value. Returns 0 on success */
|
||||||
|
typedef int (*afi_extract_callback_t)(const char *name, uint8_t *buf, size_t size);
|
||||||
|
int afi_unpack(uint8_t *buf, size_t size, afi_extract_callback_t cb);
|
||||||
|
/* Check if a file looks like an AFI file */
|
||||||
bool afi_check(uint8_t *buf, size_t size);
|
bool afi_check(uint8_t *buf, size_t size);
|
||||||
|
|
||||||
#endif /* __AFI_H__ */
|
#endif /* __AFI_H__ */
|
||||||
|
|
|
@ -29,6 +29,8 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
#include "fwu.h"
|
#include "fwu.h"
|
||||||
|
#include "afi.h"
|
||||||
|
#include "fw.h"
|
||||||
|
|
||||||
bool g_debug = false;
|
bool g_debug = false;
|
||||||
char *g_out_prefix = NULL;
|
char *g_out_prefix = NULL;
|
||||||
|
@ -89,407 +91,51 @@ static int do_fwu(uint8_t *buf, size_t size, enum fwu_mode_t mode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static int unpack_afi_fw_cb(const char *filename, uint8_t *buf, size_t size)
|
||||||
* AFI
|
|
||||||
*
|
|
||||||
* part of this work comes from s1mp3/s1fwx
|
|
||||||
**/
|
|
||||||
|
|
||||||
#define AFI_ENTRIES 126
|
|
||||||
#define AFI_SIG_SIZE 4
|
|
||||||
|
|
||||||
struct afi_hdr_t
|
|
||||||
{
|
{
|
||||||
uint8_t sig[AFI_SIG_SIZE];
|
char *name = malloc(strlen(g_out_prefix) + strlen(filename) + 16);
|
||||||
uint16_t vendor_id;
|
sprintf(name, "%s%s", g_out_prefix, filename);
|
||||||
uint16_t product_id;
|
|
||||||
uint8_t ver_id[2];
|
|
||||||
uint8_t ext_ver_id[2];
|
|
||||||
uint8_t year[2];
|
|
||||||
uint8_t month;
|
|
||||||
uint8_t day;
|
|
||||||
uint32_t afi_size;
|
|
||||||
uint32_t res[3];
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
struct afi_entry_t
|
cprintf(GREY, "Unpacking to %s... ", name);
|
||||||
{
|
FILE *f = fopen(name, "wb");
|
||||||
char name[8];
|
if(f)
|
||||||
char ext[3];
|
|
||||||
char type;
|
|
||||||
uint32_t addr;
|
|
||||||
uint32_t offset;
|
|
||||||
uint32_t size;
|
|
||||||
char desc[4];
|
|
||||||
uint32_t checksum;
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
struct afi_post_hdr_t
|
|
||||||
{
|
|
||||||
uint8_t res[28];
|
|
||||||
uint32_t checksum;
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
struct afi_t
|
|
||||||
{
|
|
||||||
struct afi_hdr_t hdr;
|
|
||||||
struct afi_entry_t entry[AFI_ENTRIES];
|
|
||||||
struct afi_post_hdr_t post;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define AFI_ENTRY_BREC 'B'
|
|
||||||
#define AFI_ENTRY_FWSC 'F'
|
|
||||||
#define AFI_ENTRY_ADFUS 'A'
|
|
||||||
#define AFI_ENTRY_FW 'I'
|
|
||||||
|
|
||||||
#define AFI_ENTRY_DLADR_BREC 0x00000006 // 'B'
|
|
||||||
#define AFI_ENTRY_DLADR_FWSC 0x00020008 // 'F'
|
|
||||||
#define AFI_ENTRY_DLADR_ADFUS 0x000C0008 // 'A'
|
|
||||||
#define AFI_ENTRY_DLADR_ADFU 0x00000000 // 'U'
|
|
||||||
#define AFI_ENTRY_DLADR_FW 0x00000011 // 'I'
|
|
||||||
|
|
||||||
const uint8_t g_afi_signature[AFI_SIG_SIZE] =
|
|
||||||
{
|
|
||||||
'A', 'F', 'I', 0
|
|
||||||
};
|
|
||||||
|
|
||||||
static uint32_t afi_checksum(void *ptr, int size)
|
|
||||||
{
|
|
||||||
uint32_t crc = 0;
|
|
||||||
uint32_t *cp = ptr;
|
|
||||||
for(; size >= 4; size -= 4)
|
|
||||||
crc += *cp++;
|
|
||||||
if(size == 1)
|
|
||||||
crc += *(uint8_t *)cp;
|
|
||||||
else if(size == 2)
|
|
||||||
crc += *(uint16_t *)cp;
|
|
||||||
else if(size == 3)
|
|
||||||
crc += *(uint16_t *)cp + ((*(uint8_t *)(cp + 2)) << 16);
|
|
||||||
return crc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void build_filename(char buf[16], struct afi_entry_t *ent)
|
|
||||||
{
|
|
||||||
int pos = 0;
|
|
||||||
for(int i = 0; i < 8 && ent->name[i] != ' '; i++)
|
|
||||||
buf[pos++] = ent->name[i];
|
|
||||||
buf[pos++] = '.';
|
|
||||||
for(int i = 0; i < 3 && ent->ext[i] != ' '; i++)
|
|
||||||
buf[pos++] = ent->ext[i];
|
|
||||||
buf[pos] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int do_afi(uint8_t *buf, int size)
|
|
||||||
{
|
|
||||||
struct afi_t *afi = (void *)buf;
|
|
||||||
|
|
||||||
if(size < (int)sizeof(struct afi_t))
|
|
||||||
{
|
{
|
||||||
cprintf(GREY, "File too small\n");
|
fwrite(buf, size, 1, f);
|
||||||
return 1;
|
fclose(f);
|
||||||
|
cprintf(RED, "Ok\n");
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
cprintf(BLUE, "Header\n");
|
|
||||||
cprintf(GREEN, " Signature:");
|
|
||||||
for(int i = 0; i < AFI_SIG_SIZE; i++)
|
|
||||||
cprintf(YELLOW, " %02x", afi->hdr.sig[i]);
|
|
||||||
if(memcmp(afi->hdr.sig, g_afi_signature, AFI_SIG_SIZE) == 0)
|
|
||||||
cprintf(RED, " Ok\n");
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cprintf(RED, " Mismatch\n");
|
color(RED);
|
||||||
|
perror("Failed");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cprintf_field(" Vendor ID: ", "0x%x\n", afi->hdr.vendor_id);
|
static int do_afi(uint8_t *buf, size_t size)
|
||||||
cprintf_field(" Product ID: ", "0x%x\n", afi->hdr.product_id);
|
{
|
||||||
cprintf_field(" Version: ", "%x.%x\n", afi->hdr.ver_id[0], afi->hdr.ver_id[1]);
|
|
||||||
cprintf_field(" Ext Version: ", "%x.%x\n", afi->hdr.ext_ver_id[0],
|
|
||||||
afi->hdr.ext_ver_id[1]);
|
|
||||||
cprintf_field(" Date: ", "%02x/%02x/%02x%02x\n", afi->hdr.day, afi->hdr.month,
|
|
||||||
afi->hdr.year[0], afi->hdr.year[1]);
|
|
||||||
|
|
||||||
cprintf_field(" AFI size: ", "%d ", afi->hdr.afi_size);
|
|
||||||
if((int)afi->hdr.afi_size == size)
|
|
||||||
cprintf(RED, " Ok\n");
|
|
||||||
else if((int)afi->hdr.afi_size < size)
|
|
||||||
cprintf(RED, " Ok (file greater than archive)\n");
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cprintf(RED, " Error (file too small)\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
cprintf_field(" Reserved: ", "%x %x %x\n", afi->hdr.res[0],
|
|
||||||
afi->hdr.res[1], afi->hdr.res[2]);
|
|
||||||
|
|
||||||
build_out_prefix(".fw", "", true);
|
build_out_prefix(".fw", "", true);
|
||||||
|
return afi_unpack(buf, size, &unpack_afi_fw_cb);
|
||||||
cprintf(BLUE, "Entries\n");
|
|
||||||
for(int i = 0; i < AFI_ENTRIES; i++)
|
|
||||||
{
|
|
||||||
if(afi->entry[i].name[0] == 0)
|
|
||||||
continue;
|
|
||||||
struct afi_entry_t *entry = &afi->entry[i];
|
|
||||||
char filename[16];
|
|
||||||
build_filename(filename, entry);
|
|
||||||
cprintf(RED, " %s\n", filename);
|
|
||||||
cprintf_field(" Type: ", "%02x", entry->type);
|
|
||||||
if(isprint(entry->type))
|
|
||||||
cprintf(RED, " %c", entry->type);
|
|
||||||
printf("\n");
|
|
||||||
cprintf_field(" Addr: ", "0x%x\n", entry->addr);
|
|
||||||
cprintf_field(" Offset: ", "0x%x\n", entry->offset);
|
|
||||||
cprintf_field(" Size: ", "0x%x\n", entry->size);
|
|
||||||
cprintf_field(" Desc: ", "%.4s\n", entry->desc);
|
|
||||||
cprintf_field(" Checksum: ", "0x%x ", entry->checksum);
|
|
||||||
uint32_t chk = afi_checksum(buf + entry->offset, entry->size);
|
|
||||||
cprintf(RED, "%s\n", chk == entry->checksum ? "Ok" : "Mismatch");
|
|
||||||
|
|
||||||
char *name = malloc(strlen(g_out_prefix) + strlen(filename) + 16);
|
|
||||||
sprintf(name, "%s%s", g_out_prefix, filename);
|
|
||||||
|
|
||||||
cprintf(GREY, "Unpacking to %s... ", name);
|
|
||||||
FILE *f = fopen(name, "wb");
|
|
||||||
if(f)
|
|
||||||
{
|
|
||||||
fwrite(buf + entry->offset, entry->size, 1, f);
|
|
||||||
fclose(f);
|
|
||||||
cprintf(RED, "Ok\n");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
cprintf(RED, "Failed: %m\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
cprintf(BLUE, "Post Header\n");
|
|
||||||
cprintf_field(" Checksum: ", "%x ", afi->post.checksum);
|
|
||||||
uint32_t chk = afi_checksum(buf, sizeof(struct afi_t) - 4);
|
|
||||||
cprintf(RED, "%s\n", chk == afi->post.checksum ? "Ok" : "Mismatch");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool afi_check(uint8_t *buf, int size)
|
static int do_fw(uint8_t *buf, size_t size)
|
||||||
{
|
{
|
||||||
struct afi_hdr_t *hdr = (void *)buf;
|
|
||||||
|
|
||||||
if(size < (int)sizeof(struct afi_hdr_t))
|
|
||||||
return false;
|
|
||||||
return memcmp(hdr->sig, g_afi_signature, AFI_SIG_SIZE) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FW
|
|
||||||
**/
|
|
||||||
|
|
||||||
#define FW_SIG_SIZE 4
|
|
||||||
|
|
||||||
#define FW_ENTRIES 240
|
|
||||||
|
|
||||||
struct fw_entry_t
|
|
||||||
{
|
|
||||||
char name[8];
|
|
||||||
char ext[3];
|
|
||||||
uint8_t attr;
|
|
||||||
uint8_t res[2];
|
|
||||||
uint16_t version;
|
|
||||||
uint32_t block_offset; // offset shift by 9
|
|
||||||
uint32_t size;
|
|
||||||
uint32_t unk;
|
|
||||||
uint32_t checksum;
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
struct fw_hdr_t
|
|
||||||
{
|
|
||||||
uint8_t sig[FW_SIG_SIZE];
|
|
||||||
uint32_t res[4];
|
|
||||||
uint8_t year[2];
|
|
||||||
uint8_t month;
|
|
||||||
uint8_t day;
|
|
||||||
uint16_t usb_vid;
|
|
||||||
uint16_t usb_pid;
|
|
||||||
uint32_t checksum;
|
|
||||||
char productor[16];
|
|
||||||
char str2[16];
|
|
||||||
char str3[32];
|
|
||||||
char dev_name[32];
|
|
||||||
uint8_t res2[8 * 16];
|
|
||||||
char usb_name1[8];
|
|
||||||
char usb_name2[8];
|
|
||||||
char res3[4 * 16 + 1];
|
|
||||||
char mtp_name1[33];
|
|
||||||
char mtp_name2[33];
|
|
||||||
char mtp_ver[33];
|
|
||||||
uint16_t mtp_vid;
|
|
||||||
uint16_t mtp_pid;
|
|
||||||
char fw_ver[64];
|
|
||||||
uint32_t res4[2];
|
|
||||||
|
|
||||||
struct fw_entry_t entry[FW_ENTRIES];
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
/* the s1fwx source code has a layout but it does not make any sense for firmwares
|
|
||||||
* found in ATJ2127 for example. In doubt just don't do anything */
|
|
||||||
struct fw_hdr_f0_t
|
|
||||||
{
|
|
||||||
uint8_t sig[FW_SIG_SIZE];
|
|
||||||
uint8_t res[12];
|
|
||||||
uint32_t checksum;
|
|
||||||
uint8_t res2[492];
|
|
||||||
|
|
||||||
struct fw_entry_t entry[FW_ENTRIES];
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
const uint8_t g_fw_signature_f2[FW_SIG_SIZE] =
|
|
||||||
{
|
|
||||||
0x55, 0xaa, 0xf2, 0x0f
|
|
||||||
};
|
|
||||||
|
|
||||||
const uint8_t g_fw_signature_f0[FW_SIG_SIZE] =
|
|
||||||
{
|
|
||||||
0x55, 0xaa, 0xf0, 0x0f
|
|
||||||
};
|
|
||||||
|
|
||||||
static void build_filename_fw(char buf[16], struct fw_entry_t *ent)
|
|
||||||
{
|
|
||||||
int pos = 0;
|
|
||||||
for(int i = 0; i < 8 && ent->name[i] != ' '; i++)
|
|
||||||
buf[pos++] = ent->name[i];
|
|
||||||
buf[pos++] = '.';
|
|
||||||
for(int i = 0; i < 3 && ent->ext[i] != ' '; i++)
|
|
||||||
buf[pos++] = ent->ext[i];
|
|
||||||
buf[pos] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int do_fw(uint8_t *buf, int size)
|
|
||||||
{
|
|
||||||
struct fw_hdr_t *hdr = (void *)buf;
|
|
||||||
|
|
||||||
if(size < (int)sizeof(struct fw_hdr_t))
|
|
||||||
{
|
|
||||||
cprintf(GREY, "File too small\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
cprintf(BLUE, "Header\n");
|
|
||||||
cprintf(GREEN, " Signature:");
|
|
||||||
for(int i = 0; i < FW_SIG_SIZE; i++)
|
|
||||||
cprintf(YELLOW, " %02x", hdr->sig[i]);
|
|
||||||
int variant = 0;
|
|
||||||
if(memcmp(hdr->sig, g_fw_signature_f2, FW_SIG_SIZE) == 0)
|
|
||||||
{
|
|
||||||
variant = 0xf2;
|
|
||||||
cprintf(RED, " Ok (f2 variant)\n");
|
|
||||||
}
|
|
||||||
else if(memcmp(hdr->sig, g_fw_signature_f0, FW_SIG_SIZE) == 0)
|
|
||||||
{
|
|
||||||
variant = 0xf0;
|
|
||||||
cprintf(RED, " Ok (f0 variant)\n");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cprintf(RED, " Mismatch\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* both variants have the same header size, only the fields differ */
|
|
||||||
if(variant == 0xf2)
|
|
||||||
{
|
|
||||||
cprintf_field(" USB VID: ", "0x%x\n", hdr->usb_vid);
|
|
||||||
cprintf_field(" USB PID: ", "0x%x\n", hdr->usb_pid);
|
|
||||||
cprintf_field(" Date: ", "%x/%x/%02x%02x\n", hdr->day, hdr->month, hdr->year[0], hdr->year[1]);
|
|
||||||
cprintf_field(" Checksum: ", "%x\n", hdr->checksum);
|
|
||||||
cprintf_field(" Productor: ", "%.16s\n", hdr->productor);
|
|
||||||
cprintf_field(" String 2: ", "%.16s\n", hdr->str2);
|
|
||||||
cprintf_field(" String 3: ", "%.32s\n", hdr->str3);
|
|
||||||
cprintf_field(" Device Name: ", "%.32s\n", hdr->dev_name);
|
|
||||||
cprintf(GREEN, " Unknown:\n");
|
|
||||||
for(int i = 0; i < 8; i++)
|
|
||||||
{
|
|
||||||
cprintf(YELLOW, " ");
|
|
||||||
for(int j = 0; j < 16; j++)
|
|
||||||
cprintf(YELLOW, "%02x ", hdr->res2[i * 16 + j]);
|
|
||||||
cprintf(YELLOW, "\n");
|
|
||||||
}
|
|
||||||
cprintf_field(" USB Name 1: ", "%.8s\n", hdr->usb_name1);
|
|
||||||
cprintf_field(" USB Name 2: ", "%.8s\n", hdr->usb_name2);
|
|
||||||
cprintf_field(" MTP Name 1: ", "%.32s\n", hdr->mtp_name1);
|
|
||||||
cprintf_field(" MTP Name 2: ", "%.32s\n", hdr->mtp_name2);
|
|
||||||
cprintf_field(" MTP Version: ", "%.32s\n", hdr->mtp_ver);
|
|
||||||
|
|
||||||
cprintf_field(" MTP VID: ", "0x%x\n", hdr->mtp_vid);
|
|
||||||
cprintf_field(" MTP PID: ", "0x%x\n", hdr->mtp_pid);
|
|
||||||
cprintf_field(" FW Version: ", "%.64s\n", hdr->fw_ver);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* struct fw_hdr_f0_t *hdr_f0 = (void *)hdr; */
|
|
||||||
cprintf(GREEN, " Header not dumped because format is unclear.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
build_out_prefix(".unpack", "", true);
|
build_out_prefix(".unpack", "", true);
|
||||||
|
return fw_unpack(buf, size, &unpack_afi_fw_cb);
|
||||||
cprintf(BLUE, "Entries\n");
|
|
||||||
for(int i = 0; i < AFI_ENTRIES; i++)
|
|
||||||
{
|
|
||||||
if(hdr->entry[i].name[0] == 0)
|
|
||||||
continue;
|
|
||||||
struct fw_entry_t *entry = &hdr->entry[i];
|
|
||||||
char filename[16];
|
|
||||||
build_filename_fw(filename, entry);
|
|
||||||
cprintf(RED, " %s\n", filename);
|
|
||||||
cprintf_field(" Attr: ", "%02x\n", entry->attr);
|
|
||||||
cprintf_field(" Offset: ", "0x%x\n", entry->block_offset << 9);
|
|
||||||
cprintf_field(" Size: ", "0x%x\n", entry->size);
|
|
||||||
cprintf_field(" Unknown: ", "%x\n", entry->unk);
|
|
||||||
cprintf_field(" Checksum: ", "0x%x ", entry->checksum);
|
|
||||||
uint32_t chk = afi_checksum(buf + (entry->block_offset << 9), entry->size);
|
|
||||||
cprintf(RED, "%s\n", chk == entry->checksum ? "Ok" : "Mismatch");
|
|
||||||
if(g_out_prefix)
|
|
||||||
{
|
|
||||||
char *name = malloc(strlen(g_out_prefix) + strlen(filename) + 16);
|
|
||||||
sprintf(name, "%s%s", g_out_prefix, filename);
|
|
||||||
|
|
||||||
cprintf(GREY, "Unpacking to %s... ", name);
|
|
||||||
FILE *f = fopen(name, "wb");
|
|
||||||
if(f)
|
|
||||||
{
|
|
||||||
fwrite(buf + (entry->block_offset << 9), entry->size, 1, f);
|
|
||||||
fclose(f);
|
|
||||||
cprintf(RED, "Ok\n");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
cprintf(RED, "Failed: %m\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool check_fw(uint8_t *buf, int size)
|
|
||||||
{
|
|
||||||
struct fw_hdr_t *hdr = (void *)buf;
|
|
||||||
|
|
||||||
if(size < (int)sizeof(struct fw_hdr_t))
|
|
||||||
return false;
|
|
||||||
if(memcmp(hdr->sig, g_fw_signature_f2, FW_SIG_SIZE) == 0)
|
|
||||||
return true;
|
|
||||||
if(memcmp(hdr->sig, g_fw_signature_f0, FW_SIG_SIZE) == 0)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void usage(void)
|
static void usage(void)
|
||||||
{
|
{
|
||||||
printf("Usage: atjboottool [options] firmware\n");
|
printf("Usage: atjboottool [options] firmware\n");
|
||||||
printf("Options:\n");
|
printf("Options:\n");
|
||||||
printf(" -o <prefix>\tSet output prefix\n");
|
printf(" -o <path> Set output file or output prefix\n");
|
||||||
printf(" -f/--force\tForce to continue on errors\n");
|
printf(" -h/--help Display this message\n");
|
||||||
printf(" -?/--help\tDisplay this message\n");
|
printf(" -d/--debug Display debug messages\n");
|
||||||
printf(" -d/--debug\tDisplay debug messages\n");
|
printf(" -c/--no-color Disable color output\n");
|
||||||
printf(" -c/--no-color\tDisable color output\n");
|
printf(" --fwu Unpack a FWU firmware file\n");
|
||||||
printf(" --fwu\tUnpack a FWU firmware file\n");
|
printf(" --afi Unpack a AFI archive file\n");
|
||||||
printf(" --afi\tUnpack a AFI archive file\n");
|
printf(" --fw Unpack a FW archive file\n");
|
||||||
printf(" --fw\tUnpack a FW archive file\n");
|
printf(" --atj2127 Force ATJ2127 decryption mode\n");
|
||||||
printf(" --atj2127\tForce ATJ2127 decryption mode\n");
|
|
||||||
printf("The default is to try to guess the format.\n");
|
printf("The default is to try to guess the format.\n");
|
||||||
printf("If several formats are specified, all are tried.\n");
|
printf("If several formats are specified, all are tried.\n");
|
||||||
printf("If no output prefix is specified, a default one is picked.\n");
|
printf("If no output prefix is specified, a default one is picked.\n");
|
||||||
|
@ -507,7 +153,7 @@ int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
static struct option long_options[] =
|
static struct option long_options[] =
|
||||||
{
|
{
|
||||||
{"help", no_argument, 0, '?'},
|
{"help", no_argument, 0, 'h'},
|
||||||
{"debug", no_argument, 0, 'd'},
|
{"debug", no_argument, 0, 'd'},
|
||||||
{"no-color", no_argument, 0, 'c'},
|
{"no-color", no_argument, 0, 'c'},
|
||||||
{"fwu", no_argument, 0, 'u'},
|
{"fwu", no_argument, 0, 'u'},
|
||||||
|
@ -517,7 +163,7 @@ int main(int argc, char **argv)
|
||||||
{0, 0, 0, 0}
|
{0, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
int c = getopt_long(argc, argv, "?dcfo:a1", long_options, NULL);
|
int c = getopt_long(argc, argv, "hdco:a2", long_options, NULL);
|
||||||
if(c == -1)
|
if(c == -1)
|
||||||
break;
|
break;
|
||||||
switch(c)
|
switch(c)
|
||||||
|
@ -531,7 +177,7 @@ int main(int argc, char **argv)
|
||||||
g_debug = true;
|
g_debug = true;
|
||||||
break;
|
break;
|
||||||
break;
|
break;
|
||||||
case '?':
|
case 'h':
|
||||||
usage();
|
usage();
|
||||||
break;
|
break;
|
||||||
case 'o':
|
case 'o':
|
||||||
|
@ -591,7 +237,7 @@ int main(int argc, char **argv)
|
||||||
ret = do_fwu(buf, size, fwu_mode);
|
ret = do_fwu(buf, size, fwu_mode);
|
||||||
else if(try_afi || afi_check(buf, size))
|
else if(try_afi || afi_check(buf, size))
|
||||||
ret = do_afi(buf, size);
|
ret = do_afi(buf, size);
|
||||||
else if(try_fw || check_fw(buf, size))
|
else if(try_fw || fw_check(buf, size))
|
||||||
ret = do_fw(buf, size);
|
ret = do_fw(buf, size);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
213
utils/atj2137/atjboottool/fw.c
Normal file
213
utils/atj2137/atjboottool/fw.c
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Amaury Pouly
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include "misc.h"
|
||||||
|
#include "fw.h"
|
||||||
|
#include "afi.h"
|
||||||
|
|
||||||
|
#define FW_SIG_SIZE 4
|
||||||
|
|
||||||
|
#define FW_ENTRIES 240
|
||||||
|
|
||||||
|
struct fw_entry_t
|
||||||
|
{
|
||||||
|
char name[8];
|
||||||
|
char ext[3];
|
||||||
|
uint8_t attr;
|
||||||
|
uint8_t res[2];
|
||||||
|
uint16_t version;
|
||||||
|
uint32_t block_offset; // offset shift by 9
|
||||||
|
uint32_t size;
|
||||||
|
uint32_t unk;
|
||||||
|
uint32_t checksum;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct fw_hdr_t
|
||||||
|
{
|
||||||
|
uint8_t sig[FW_SIG_SIZE];
|
||||||
|
uint32_t res[4];
|
||||||
|
uint8_t year[2];
|
||||||
|
uint8_t month;
|
||||||
|
uint8_t day;
|
||||||
|
uint16_t usb_vid;
|
||||||
|
uint16_t usb_pid;
|
||||||
|
uint32_t checksum;
|
||||||
|
char productor[16];
|
||||||
|
char str2[16];
|
||||||
|
char str3[32];
|
||||||
|
char dev_name[32];
|
||||||
|
uint8_t res2[8 * 16];
|
||||||
|
char usb_name1[8];
|
||||||
|
char usb_name2[8];
|
||||||
|
char res3[4 * 16 + 1];
|
||||||
|
char mtp_name1[33];
|
||||||
|
char mtp_name2[33];
|
||||||
|
char mtp_ver[33];
|
||||||
|
uint16_t mtp_vid;
|
||||||
|
uint16_t mtp_pid;
|
||||||
|
char fw_ver[64];
|
||||||
|
uint32_t res4[2];
|
||||||
|
|
||||||
|
struct fw_entry_t entry[FW_ENTRIES];
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
/* the s1fwx source code has a layout but it does not make any sense for firmwares
|
||||||
|
* found in ATJ2127 for example. In doubt just don't do anything */
|
||||||
|
struct fw_hdr_f0_t
|
||||||
|
{
|
||||||
|
uint8_t sig[FW_SIG_SIZE];
|
||||||
|
uint8_t res[12];
|
||||||
|
uint32_t checksum;
|
||||||
|
uint8_t res2[492];
|
||||||
|
|
||||||
|
struct fw_entry_t entry[FW_ENTRIES];
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
const uint8_t g_fw_signature_f2[FW_SIG_SIZE] =
|
||||||
|
{
|
||||||
|
0x55, 0xaa, 0xf2, 0x0f
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t g_fw_signature_f0[FW_SIG_SIZE] =
|
||||||
|
{
|
||||||
|
0x55, 0xaa, 0xf0, 0x0f
|
||||||
|
};
|
||||||
|
|
||||||
|
static void build_filename_fw(char buf[16], struct fw_entry_t *ent)
|
||||||
|
{
|
||||||
|
int pos = 0;
|
||||||
|
for(int i = 0; i < 8 && ent->name[i] != ' '; i++)
|
||||||
|
buf[pos++] = ent->name[i];
|
||||||
|
buf[pos++] = '.';
|
||||||
|
for(int i = 0; i < 3 && ent->ext[i] != ' '; i++)
|
||||||
|
buf[pos++] = ent->ext[i];
|
||||||
|
buf[pos] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fw_unpack(uint8_t *buf, size_t size, fw_extract_callback_t unpack_cb)
|
||||||
|
{
|
||||||
|
struct fw_hdr_t *hdr = (void *)buf;
|
||||||
|
|
||||||
|
if(size < sizeof(struct fw_hdr_t))
|
||||||
|
{
|
||||||
|
cprintf(GREY, "File too small\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
cprintf(BLUE, "Header\n");
|
||||||
|
cprintf(GREEN, " Signature:");
|
||||||
|
for(int i = 0; i < FW_SIG_SIZE; i++)
|
||||||
|
cprintf(YELLOW, " %02x", hdr->sig[i]);
|
||||||
|
int variant = 0;
|
||||||
|
if(memcmp(hdr->sig, g_fw_signature_f2, FW_SIG_SIZE) == 0)
|
||||||
|
{
|
||||||
|
variant = 0xf2;
|
||||||
|
cprintf(RED, " Ok (f2 variant)\n");
|
||||||
|
}
|
||||||
|
else if(memcmp(hdr->sig, g_fw_signature_f0, FW_SIG_SIZE) == 0)
|
||||||
|
{
|
||||||
|
variant = 0xf0;
|
||||||
|
cprintf(RED, " Ok (f0 variant)\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cprintf(RED, " Mismatch\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* both variants have the same header size, only the fields differ */
|
||||||
|
if(variant == 0xf2)
|
||||||
|
{
|
||||||
|
cprintf_field(" USB VID: ", "0x%x\n", hdr->usb_vid);
|
||||||
|
cprintf_field(" USB PID: ", "0x%x\n", hdr->usb_pid);
|
||||||
|
cprintf_field(" Date: ", "%x/%x/%02x%02x\n", hdr->day, hdr->month, hdr->year[0], hdr->year[1]);
|
||||||
|
cprintf_field(" Checksum: ", "%x\n", hdr->checksum);
|
||||||
|
cprintf_field(" Productor: ", "%.16s\n", hdr->productor);
|
||||||
|
cprintf_field(" String 2: ", "%.16s\n", hdr->str2);
|
||||||
|
cprintf_field(" String 3: ", "%.32s\n", hdr->str3);
|
||||||
|
cprintf_field(" Device Name: ", "%.32s\n", hdr->dev_name);
|
||||||
|
cprintf(GREEN, " Unknown:\n");
|
||||||
|
for(int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
cprintf(YELLOW, " ");
|
||||||
|
for(int j = 0; j < 16; j++)
|
||||||
|
cprintf(YELLOW, "%02x ", hdr->res2[i * 16 + j]);
|
||||||
|
cprintf(YELLOW, "\n");
|
||||||
|
}
|
||||||
|
cprintf_field(" USB Name 1: ", "%.8s\n", hdr->usb_name1);
|
||||||
|
cprintf_field(" USB Name 2: ", "%.8s\n", hdr->usb_name2);
|
||||||
|
cprintf_field(" MTP Name 1: ", "%.32s\n", hdr->mtp_name1);
|
||||||
|
cprintf_field(" MTP Name 2: ", "%.32s\n", hdr->mtp_name2);
|
||||||
|
cprintf_field(" MTP Version: ", "%.32s\n", hdr->mtp_ver);
|
||||||
|
|
||||||
|
cprintf_field(" MTP VID: ", "0x%x\n", hdr->mtp_vid);
|
||||||
|
cprintf_field(" MTP PID: ", "0x%x\n", hdr->mtp_pid);
|
||||||
|
cprintf_field(" FW Version: ", "%.64s\n", hdr->fw_ver);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* struct fw_hdr_f0_t *hdr_f0 = (void *)hdr; */
|
||||||
|
cprintf(GREEN, " Header not dumped because format is unclear.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
cprintf(BLUE, "Entries\n");
|
||||||
|
for(int i = 0; i < FW_ENTRIES; i++)
|
||||||
|
{
|
||||||
|
if(hdr->entry[i].name[0] == 0)
|
||||||
|
continue;
|
||||||
|
struct fw_entry_t *entry = &hdr->entry[i];
|
||||||
|
char filename[16];
|
||||||
|
build_filename_fw(filename, entry);
|
||||||
|
cprintf(RED, " %s\n", filename);
|
||||||
|
cprintf_field(" Attr: ", "%02x\n", entry->attr);
|
||||||
|
cprintf_field(" Offset: ", "0x%x\n", entry->block_offset << 9);
|
||||||
|
cprintf_field(" Size: ", "0x%x\n", entry->size);
|
||||||
|
cprintf_field(" Unknown: ", "%x\n", entry->unk);
|
||||||
|
cprintf_field(" Checksum: ", "0x%x ", entry->checksum);
|
||||||
|
uint32_t chk = afi_checksum(buf + (entry->block_offset << 9), entry->size);
|
||||||
|
if(chk != entry->checksum)
|
||||||
|
{
|
||||||
|
cprintf(RED, "Mismatch\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cprintf(RED, "Ok\n");
|
||||||
|
int ret = unpack_cb(filename, buf + (entry->block_offset << 9), entry->size);
|
||||||
|
if(ret != 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fw_check(uint8_t *buf, size_t size)
|
||||||
|
{
|
||||||
|
struct fw_hdr_t *hdr = (void *)buf;
|
||||||
|
|
||||||
|
if(size < sizeof(struct fw_hdr_t))
|
||||||
|
return false;
|
||||||
|
if(memcmp(hdr->sig, g_fw_signature_f2, FW_SIG_SIZE) == 0)
|
||||||
|
return true;
|
||||||
|
if(memcmp(hdr->sig, g_fw_signature_f0, FW_SIG_SIZE) == 0)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
34
utils/atj2137/atjboottool/fw.h
Normal file
34
utils/atj2137/atjboottool/fw.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/***************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Amaury Pouly
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
#ifndef __FW_H__
|
||||||
|
#define __FW_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* Unpack an AFI file: the callback function will be called once for each file in the archive with
|
||||||
|
* its name and content. If the callback returns a nonzero value, the function will stop and return
|
||||||
|
* that value. Returns 0 on success */
|
||||||
|
typedef int (*fw_extract_callback_t)(const char *name, uint8_t *buf, size_t size);
|
||||||
|
int fw_unpack(uint8_t *buf, size_t size, fw_extract_callback_t cb);
|
||||||
|
/* Check if a file looks like an AFI file */
|
||||||
|
bool fw_check(uint8_t *buf, size_t size);
|
||||||
|
|
||||||
|
#endif /* __FW_H__ */
|
|
@ -149,10 +149,10 @@ static int decode_block_A(uint8_t block[1020])
|
||||||
}
|
}
|
||||||
for(int i = 20; i < 32; i++)
|
for(int i = 20; i < 32; i++)
|
||||||
key[i] = key[i - 20];
|
key[i] = key[i - 20];
|
||||||
|
|
||||||
for(int i = 0; i < 992; i++)
|
for(int i = 0; i < 992; i++)
|
||||||
block[i] ^= key[i % 32] ^ g_check_block_A_table[i];
|
block[i] ^= key[i % 32] ^ g_check_block_A_table[i];
|
||||||
|
|
||||||
return check_block(block - 1, block + 1000, 1001);
|
return check_block(block - 1, block + 1000, 1001);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,7 +277,7 @@ static int process_block_A(uint8_t block[1024])
|
||||||
g_crypto_info_byte = block[offset - 1];
|
g_crypto_info_byte = block[offset - 1];
|
||||||
g_decode_buffer = malloc(g_decode_A_info.size);
|
g_decode_buffer = malloc(g_decode_A_info.size);
|
||||||
g_decode_buffer2 = malloc(g_decode_A_info.size);
|
g_decode_buffer2 = malloc(g_decode_A_info.size);
|
||||||
|
|
||||||
memset(g_decode_buffer, 0, g_decode_A_info.size);
|
memset(g_decode_buffer, 0, g_decode_A_info.size);
|
||||||
memset(g_decode_buffer2, 0, g_decode_A_info.size);
|
memset(g_decode_buffer2, 0, g_decode_A_info.size);
|
||||||
|
|
||||||
|
@ -288,7 +288,7 @@ static int process_block_A(uint8_t block[1024])
|
||||||
|
|
||||||
cprintf_field(" Word: ", "%d ", *(uint16_t *)&g_subblock_A[286]);
|
cprintf_field(" Word: ", "%d ", *(uint16_t *)&g_subblock_A[286]);
|
||||||
check_field(*(uint16_t *)&g_subblock_A[286], 1, "Ok\n", "Mismatch\n");
|
check_field(*(uint16_t *)&g_subblock_A[286], 1, "Ok\n", "Mismatch\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -625,7 +625,7 @@ static int crypto3(uint32_t *a1, ptr_bundle_t *ptrs_alt, ptr_bundle_t *ptrs)
|
||||||
static int crypto4(uint8_t *a1, ptr_bundle_t *ptrs, uint32_t *a3)
|
static int crypto4(uint8_t *a1, ptr_bundle_t *ptrs, uint32_t *a3)
|
||||||
{
|
{
|
||||||
ptr_bundle_t ptrs_others;
|
ptr_bundle_t ptrs_others;
|
||||||
|
|
||||||
ptrs_others.ptrA = malloc(g_decode_A_info.size);
|
ptrs_others.ptrA = malloc(g_decode_A_info.size);
|
||||||
ptrs_others.ptrB = malloc(g_decode_A_info.size);
|
ptrs_others.ptrB = malloc(g_decode_A_info.size);
|
||||||
clear_memory(ptrs_others.ptrA, g_decode_A_info.nr_dwords);
|
clear_memory(ptrs_others.ptrA, g_decode_A_info.nr_dwords);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue