ea679de837
Change-Id: I16347ebee0f82d5fdf32f5aa8f955c07fe148eba
208 lines
5.9 KiB
C
208 lines
5.9 KiB
C
/***************************************************************************
|
|
* __________ __ ___.
|
|
* 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;
|
|
}
|