diff options
Diffstat (limited to 'utils/atj2137/atjboottool/fw.c')
-rw-r--r-- | utils/atj2137/atjboottool/fw.c | 115 |
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; } |