summaryrefslogtreecommitdiffstats
path: root/utils/atj2137/atjboottool/fw.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/atj2137/atjboottool/fw.c')
-rw-r--r--utils/atj2137/atjboottool/fw.c115
1 files changed, 105 insertions, 10 deletions
diff --git a/utils/atj2137/atjboottool/fw.c b/utils/atj2137/atjboottool/fw.c
index 07ce4e2f31..114123813b 100644
--- a/utils/atj2137/atjboottool/fw.c
+++ b/utils/atj2137/atjboottool/fw.c
@@ -38,7 +38,7 @@ struct fw_entry_t
uint16_t version;
uint32_t block_offset; // offset shift by 9
uint32_t size;
- uint32_t unk;
+ uint32_t bytes;
uint32_t checksum;
} __attribute__((packed));
@@ -78,7 +78,8 @@ struct fw_hdr_f0_t
uint8_t sig[FW_SIG_SIZE];
uint8_t res[12];
uint32_t checksum;
- uint8_t res2[492];
+ uint8_t res2[490];
+ uint16_t header_checksum;
struct fw_entry_t entry[FW_ENTRIES];
} __attribute__((packed));
@@ -97,14 +98,56 @@ 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++] = tolower(ent->name[i]);
buf[pos++] = '.';
for(int i = 0; i < 3 && ent->ext[i] != ' '; i++)
- buf[pos++] = ent->ext[i];
+ buf[pos++] = tolower(ent->ext[i]);
buf[pos] = 0;
}
-int fw_unpack(uint8_t *buf, size_t size, fw_extract_callback_t unpack_cb)
+static inline uint32_t u32_endian_swap(uint32_t u32)
+{
+ return ((u32 & 0xff000000u) >> 24) |
+ ((u32 & 0x00ff0000u) >> 8) |
+ ((u32 & 0x0000ff00u) << 8) |
+ ((u32 & 0x000000ffu) << 24);
+}
+
+static uint32_t big_endian_checksum(void *ptr, size_t size)
+{
+ uint32_t crc = 0;
+ uint32_t *cp = ptr;
+ for(; size >= 4; size -= 4)
+ crc += u32_endian_swap(*cp++);
+ /* FIXME all observed sizes divisible by 4, unclear how to add remainder */
+ return crc;
+}
+
+static inline uint16_t u16_endian_swap(uint16_t u16)
+{
+ return ((u16 & 0xff00u) >> 8) |
+ ((u16 & 0x00ffu) << 8);
+}
+
+static uint16_t lfi_header_checksum(void *ptr, size_t size, bool big_endian)
+{
+ uint16_t crc = 0;
+ uint16_t *cp = ptr;
+ if (big_endian)
+ {
+ for(; size >= 2; size -= 2)
+ crc += u16_endian_swap(*cp++);
+ return u16_endian_swap(crc); /* to make comparable with the stored one */
+ }
+ else
+ {
+ for(; size >= 2; size -= 2)
+ crc += *cp++;
+ return crc;
+ }
+}
+
+int fw_unpack(uint8_t *buf, size_t size, fw_extract_callback_t unpack_cb, bool big_endian)
{
struct fw_hdr_t *hdr = (void *)buf;
@@ -165,8 +208,32 @@ int fw_unpack(uint8_t *buf, size_t size, fw_extract_callback_t unpack_cb)
}
else
{
- /* struct fw_hdr_f0_t *hdr_f0 = (void *)hdr; */
- cprintf(GREEN, " Header not dumped because format is unclear.\n");
+ struct fw_hdr_f0_t *hdr_f0 = (void *)hdr;
+ uint32_t chk;
+ if (big_endian)
+ chk = u32_endian_swap(big_endian_checksum(buf + 0x200, 0x1e00));
+ else
+ chk = afi_checksum(buf + 0x200, 0x1e00);
+ cprintf_field(" Directory checksum: ", "0x%x ", hdr_f0->checksum);
+ if(chk != hdr_f0->checksum)
+ {
+ cprintf(RED, "Mismatch, 0x%x expected\n", chk);
+ return 1;
+ }
+ else
+ cprintf(RED, "Ok\n");
+
+ uint16_t header_chk = lfi_header_checksum(buf, 510, big_endian);
+ cprintf_field(" Header checksum: ", "0x%x ", hdr_f0->header_checksum);
+ if(header_chk != hdr_f0->header_checksum)
+ {
+ cprintf(RED, "Mismatch, 0x%x expected\n", header_chk);
+ return 1;
+ }
+ else
+ cprintf(RED, "Ok\n");
+
+ cprintf(GREEN, " Rest of header not dumped because format is unclear.\n");
}
cprintf(BLUE, "Entries\n");
@@ -175,15 +242,29 @@ int fw_unpack(uint8_t *buf, size_t size, fw_extract_callback_t unpack_cb)
if(hdr->entry[i].name[0] == 0)
continue;
struct fw_entry_t *entry = &hdr->entry[i];
+ if (big_endian)
+ {
+ /* must be in-place for correct load checksum later */
+ entry->block_offset = u32_endian_swap(entry->block_offset);
+ entry->size = u32_endian_swap(entry->size);
+ entry->checksum = u32_endian_swap(entry->checksum);
+ }
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(" Bytes: ", "0x%x\n", entry->bytes);
cprintf_field(" Checksum: ", "0x%x ", entry->checksum);
- uint32_t chk = afi_checksum(buf + (entry->block_offset << 9), entry->size);
+ if (entry->bytes == 0)
+ entry->bytes = entry->size;
+ memset(buf + (entry->block_offset << 9) + entry->bytes, 0, entry->size - entry->bytes);
+ uint32_t chk;
+ if (big_endian)
+ chk = big_endian_checksum(buf + (entry->block_offset << 9), entry->size);
+ else
+ chk = afi_checksum(buf + (entry->block_offset << 9), entry->size);
if(chk != entry->checksum)
{
cprintf(RED, "Mismatch\n");
@@ -191,11 +272,25 @@ int fw_unpack(uint8_t *buf, size_t size, fw_extract_callback_t unpack_cb)
}
else
cprintf(RED, "Ok\n");
- int ret = unpack_cb(filename, buf + (entry->block_offset << 9), entry->size);
+ int ret = unpack_cb(filename, buf + (entry->block_offset << 9), entry->bytes);
if(ret != 0)
return ret;
}
+ if (big_endian)
+ {
+ uint32_t load_checksum = *(uint32_t *)(buf + size - 4);
+ uint32_t load_chk = big_endian_checksum(buf, size - 512);
+ cprintf_field(" Load checksum: ", "0x%x ", load_checksum);
+ if(load_chk != load_checksum)
+ {
+ cprintf(RED, "Mismatch, 0x%x expected\n", load_chk);
+ return 1;
+ }
+ else
+ cprintf(RED, "Ok\n");
+ }
+
return 0;
}