release
dev builds
extras
themes manual
wiki
device status forums
mailing lists
IRC bugs
patches
dev guide



Search | Go
Wiki > Main > ATJ213xFirmware

Header

Each file begin with a header containing crucial information about the firmware.

offset length name description
0x00 0x10 sig signature
0x10 0x4 fw_size firmware size (in bytes)
0x14 0x4 block_size block size (unsure) (in bytes)
0x18 0x1 ver version encoding
0x19 0x1 unk1 unknown
0x1a 0x10 sig2 second signature

The block size is always 512. The first signature is the same for all versions of the firmware files.

signature 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff 75

The second signature and unknown field depends on the version which is encoding as follows.

ver version unk1 sig2
0x0d 1 0xd0 76 5c 50 94 69 b0 a7 03 10 f1 7e db 88 90 86 9d
0x0e 1 0xd0 92 22 7a 77 08 67 ae 06 16 06 b8 65 a6 42 f7 52
0xfd 2    
0x7e 3 0xe1 3f ad f8 b0 2e af 67 49 b9 85 5f 63 4e 5e 8e 2e

Common

Checksum

In several places the firmware files use a xor-based checksum. This section describes the algorithm used.

void compute_checksum(uint8_t *buf, int size, uint8_t t[20])
{
    memset(t, 0, 20);

    for(int i = 0; i < size; i++)
        t[i % 20] ^= buf[i];
    for(int i = 0; i < 20; i++)
        t[i] = ~t[i];
}

int check_block(uint8_t *buf, uint8_t ref[20], unsigned size)
{
    uint8_t t[20];
    compute_checksum(buf, size, t);

    return memcmp(ref, t, 20);
}

Version 3

The version 3 (encoded as 0x7e) differs significantly from previous versions.

Header Extra

The header contains a few extra fields described as follows.

offset length name description
0x1ee 0x1 blockA block address (in lower 4 bits)
0x1fe 0x1 blockB block address (in lower 4 bits)

The first field indicates the block address (minus 2) of a 1024 bytes block. The sum of first and the second fields indicates the block address (minus 5) of a 512 bytes block.

Block A

The A block contains many information about what looks like a decompression algorithm. This block is 1024 bytes long and is located at block blockA+2 (multiply this by 512 to get the offset). This block is XOR encoded using a key found in the block itself. The following procedure shows how to decode it. It uses a 1024 byte tables called g_check_block_A_table in the code below.

static int decode_block_A(uint8_t block[1020])
{
    uint8_t *p = &g_check_block_A_table[32 * (block[998] & 0x1f)];
    uint8_t key[32];

    for(int i = 0; i < 20; i++)
    {
        block[1000 + i] ^= p[i];
        key[i] = block[1000 + i];
    }
    for(int i = 20; i < 32; i++)
        key[i] = key[i - 20];
    
    for(int i = 0; i < 992; i++)
        block[i] ^= key[i % 32] ^ g_check_block_A_table[i];
    
    return check_block(block - 1, block + 1000, 1001);
}

r3 - 14 Sep 2012 - 10:58:54 - AmauryPouly
Copyright by the contributing authors.