uint32_t compat_level;
};
+/*
+ * Safeloader image type
+ * Safeloader images contain a 0x14 byte preamble with image size (big endian
+ * UINT32) and md5 checksum (16 bytes).
+ *
+ * SAFEFLOADER_TYPE_DEFAULT
+ * Standard preamble with size including preamble length, and checksum.
+ * Header of 0x1000 bytes, contents of which are not specified.
+ * Payload starts at offset 0x1014.
+ *
+ * SAFELOADER_TYPE_VENDOR
+ * Standard preamble with size including preamble length, and checksum.
+ * Header contains up to 0x1000 bytes of vendor data, starting with a big endian
+ * UINT32 size, followed by that number of bytes containing (text) data.
+ * Padded with 0xFF. Payload starts at offset 0x1014.
+ *
+ * SAFELOADER_TYPE_CLOUD
+ * Standard preamble with size including preamble length, and checksum.
+ * Followed by the 'fw-type:Cloud' string and some (unknown) data.
+ * Payload starts at offset 0x1014.
+ *
+ * SAFELOADER_TYPE_QNEW
+ * Reversed order preamble, with (apparent) md5 checksum before the image
+ * size. The size does not include the preamble length.
+ * Header starts with 0x3C bytes, starting with the string '?NEW' (format not
+ * understood). Then another 0x1000 bytes follow, with the data payload
+ * starting at 0x1050.
+ */
+enum safeloader_image_type {
+ SAFELOADER_TYPE_DEFAULT,
+ SAFELOADER_TYPE_VENDOR,
+ SAFELOADER_TYPE_CLOUD,
+ SAFELOADER_TYPE_QNEW,
+};
+
+/* Internal representation of safeloader image data */
+struct safeloader_image_info {
+ enum safeloader_image_type type;
+ size_t payload_offset;
+ struct flash_partition_entry entries[MAX_PARTITIONS];
+};
+
#define SAFELOADER_PREAMBLE_SIZE 0x14
#define SAFELOADER_HEADER_SIZE 0x1000
#define SAFELOADER_PAYLOAD_OFFSET (SAFELOADER_PREAMBLE_SIZE + SAFELOADER_HEADER_SIZE)
+#define SAFELOADER_QNEW_HEADER_SIZE 0x3C
+#define SAFELOADER_QNEW_PAYLOAD_OFFSET \
+ (SAFELOADER_PREAMBLE_SIZE + SAFELOADER_QNEW_HEADER_SIZE + SAFELOADER_HEADER_SIZE)
+
#define SAFELOADER_PAYLOAD_TABLE_SIZE 0x800
static const uint8_t jffs2_eof_mark[4] = {0xde, 0xad, 0xc0, 0xde};
"CPE510(TP-LINK|UN|N300-5):1.1\r\n"
"CPE510(TP-LINK|UN|N300-5):1.1\r\n"
"CPE510(TP-LINK|US|N300-5):1.1\r\n"
+ "CPE510(TP-LINK|CA|N300-5):1.1\r\n"
"CPE510(TP-LINK|EU|N300-5):1.1\r\n"
"CPE520(TP-LINK|UN|N300-5):1.1\r\n"
"CPE520(TP-LINK|US|N300-5):1.1\r\n"
.last_sysupgrade_partition = "file-system",
},
+ /** Firmware layout for the Archer AX23 v1 */
+ {
+ .id = "ARCHER-AX23-V1",
+ .vendor = "",
+ .support_list =
+ "SupportList:\n"
+ "{product_name:Archer AX23,product_ver:1.0,special_id:45550000}\n"
+ "{product_name:Archer AX23,product_ver:1.0,special_id:4A500000}\n"
+ "{product_name:Archer AX23,product_ver:1.0,special_id:4B520000}\n"
+ "{product_name:Archer AX23,product_ver:1.0,special_id:52550000}\n"
+ "{product_name:Archer AX23,product_ver:1.0.0,special_id:43410000}\n"
+ "{product_name:Archer AX23,product_ver:1.0.0,special_id:54570000}\n"
+ "{product_name:Archer AX23,product_ver:1.0.0,special_id:55530000}\n"
+ "{product_name:Archer AX23,product_ver:1.20,special_id:45550000}\n"
+ "{product_name:Archer AX23,product_ver:1.20,special_id:4A500000}\n"
+ "{product_name:Archer AX23,product_ver:1.20,special_id:52550000}\n"
+ "{product_name:Archer AX23,product_ver:1.20,special_id:55530000}\n"
+ "{product_name:Archer AX1800,product_ver:1.20,special_id:45550000}\n"
+ "{product_name:Archer AX1800,product_ver:1.20,special_id:52550000}\n",
+ .part_trail = 0x00,
+ .soft_ver = SOFT_VER_TEXT("soft_ver:3.0.3\n"),
+
+ .partitions = {
+ {"fs-uboot", 0x00000, 0x40000},
+ {"firmware", 0x40000, 0xf60000},
+ {"default-mac", 0xfa0000, 0x00200},
+ {"pin", 0xfa0200, 0x00100},
+ {"device-id", 0xfa0300, 0x00100},
+ {"product-info", 0xfa0400, 0x0fc00},
+ {"default-config", 0xfb0000, 0x08000},
+ {"ap-def-config", 0xfb8000, 0x08000},
+ {"user-config", 0xfc0000, 0x0a000},
+ {"ag-config", 0xfca000, 0x04000},
+ {"certificate", 0xfce000, 0x02000},
+ {"ap-config", 0xfd0000, 0x06000},
+ {"router-config", 0xfd6000, 0x06000},
+ {"favicon", 0xfdc000, 0x02000},
+ {"logo", 0xfde000, 0x02000},
+ {"partition-table", 0xfe0000, 0x00800},
+ {"soft-version", 0xfe0800, 0x00100},
+ {"support-list", 0xfe0900, 0x00400},
+ {"profile", 0xfe0d00, 0x03000},
+ {"extra-para", 0xfe3d00, 0x00100},
+ {"radio", 0xff0000, 0x10000},
+ {NULL, 0, 0}
+ },
+ .first_sysupgrade_partition = "os-image",
+ .last_sysupgrade_partition = "file-system",
+ },
/** Firmware layout for the C2v3 */
{
.id = "ARCHER-C2-V3",
.support_list =
"SupportList:\r\n"
"{product_name:Archer C59,product_ver:1.0.0,special_id:00000000}\r\n"
+ "{product_name:Archer C59,product_ver:1.0.0,special_id:43410000}\r\n"
"{product_name:Archer C59,product_ver:1.0.0,special_id:45550000}\r\n"
"{product_name:Archer C59,product_ver:1.0.0,special_id:52550000}\r\n"
"{product_name:Archer C59,product_ver:1.0.0,special_id:55530000}\r\n",
.support_list =
"SupportList:\r\n"
"{product_name:Archer C59,product_ver:2.0.0,special_id:00000000}\r\n"
+ "{product_name:Archer C59,product_ver:2.0.0,special_id:43410000}\r\n"
"{product_name:Archer C59,product_ver:2.0.0,special_id:45550000}\r\n"
"{product_name:Archer C59,product_ver:2.0.0,special_id:55530000}\r\n",
.part_trail = 0x00,
.support_list =
"SupportList:\r\n"
"{product_name:Archer A6,product_ver:2.0.0,special_id:45550000}\r\n"
+ "{product_name:Archer A6,product_ver:2.0.0,special_id:52550000}\r\n"
"{product_name:Archer C6,product_ver:2.0.0,special_id:45550000}\r\n"
"{product_name:Archer C6,product_ver:2.0.0,special_id:52550000}\r\n"
"{product_name:Archer C6,product_ver:2.0.0,special_id:4A500000}\r\n",
"{product_name:Archer A6,product_ver:3.0.0,special_id:43410000}\n"
"{product_name:Archer A6,product_ver:3.0.0,special_id:55530000}\n"
"{product_name:Archer A6,product_ver:3.0.0,special_id:54570000}\n"
- "{product_name:Archer A6,product_ver:3.0.0,special_id:4A500000}\n",
+ "{product_name:Archer A6,product_ver:3.0.0,special_id:4A500000}\n"
+ "{product_name:Archer A6,product_ver:3.20,special_id:45550000}\n"
+ "{product_name:Archer A6,product_ver:3.20,special_id:52550000}\n",
.part_trail = 0x00,
.soft_ver = SOFT_VER_TEXT("soft_ver:1.0.5\n"),
.vendor = "",
.support_list =
"SupportList:\n"
- "{product_name:Archer C6U,product_ver:1.0.0,special_id:45550000}\n",
+ "{product_name:Archer C6U,product_ver:1.0.0,special_id:45550000}\n"
+ "{product_name:Archer C6U,product_ver:1.0.0,special_id:52550000}\n",
.part_trail = 0x00,
.soft_ver = SOFT_VER_TEXT("soft_ver:1.0.2\n"),
.support_list =
"SupportList:\r\n"
"{product_name:Archer C60,product_ver:1.0.0,special_id:00000000}\r\n"
+ "{product_name:Archer C60,product_ver:1.0.0,special_id:43410000}\r\n"
"{product_name:Archer C60,product_ver:1.0.0,special_id:45550000}\r\n"
"{product_name:Archer C60,product_ver:1.0.0,special_id:55530000}\r\n",
.part_trail = 0x00,
.support_list =
"SupportList:\r\n"
"{product_name:Archer C60,product_ver:2.0.0,special_id:42520000}\r\n"
+ "{product_name:Archer C60,product_ver:2.0.0,special_id:43410000}\r\n"
"{product_name:Archer C60,product_ver:2.0.0,special_id:45550000}\r\n"
"{product_name:Archer C60,product_ver:2.0.0,special_id:55530000}\r\n",
.part_trail = 0x00,
.support_list =
"SupportList:\r\n"
"{product_name:Archer C60,product_ver:3.0.0,special_id:42520000}\r\n"
+ "{product_name:Archer C60,product_ver:3.0.0,special_id:43410000}\r\n"
"{product_name:Archer C60,product_ver:3.0.0,special_id:45550000}\r\n"
"{product_name:Archer C60,product_ver:3.0.0,special_id:55530000}\r\n",
.part_trail = 0x00,
.last_sysupgrade_partition = "file-system",
},
+ /** Firmware layout for the Deco M5 */
+ {
+ .id = "DECO-M5",
+ .vendor = "",
+ .support_list =
+ "SupportList:\n"
+ "{product_name:M5,product_ver:1.0.0,special_id:55530000}\n"
+ "{product_name:M5,product_ver:1.0.0,special_id:45550000}\n"
+ "{product_name:M5,product_ver:1.0.0,special_id:43410000}\n"
+ "{product_name:M5,product_ver:1.0.0,special_id:4A500000}\n"
+ "{product_name:M5,product_ver:1.0.0,special_id:41550000}\n"
+ "{product_name:M5,product_ver:1.0.0,special_id:4B520000}\n"
+ "{product_name:M5,product_ver:1.0.0,special_id:49440000}\n"
+ "{product_name:M5,product_ver:3.0.0,special_id:55530000}\n"
+ "{product_name:M5,product_ver:3.0.0,special_id:45550000}\n"
+ "{product_name:M5,product_ver:3.0.0,special_id:43410000}\n"
+ "{product_name:M5,product_ver:3.0.0,special_id:4A500000}\n"
+ "{product_name:M5,product_ver:3.0.0,special_id:41550000}\n"
+ "{product_name:M5,product_ver:3.0.0,special_id:4B520000}\n"
+ "{product_name:M5,product_ver:3.0.0,special_id:49440000}\n"
+ "{product_name:M5,product_ver:3.0.0,special_id:53570000}\n"
+ "{product_name:M5,product_ver:3.0.0,special_id:42340000}\n"
+ "{product_name:M5,product_ver:3.0.0,special_id:54570000}\n"
+ "{product_name:M5,product_ver:3.2.0,special_id:55530000}\n"
+ "{product_name:M5,product_ver:3.2.0,special_id:45550000}\n"
+ "{product_name:M5,product_ver:3.2.0,special_id:43410000}\n"
+ "{product_name:M5,product_ver:3.2.0,special_id:4A500000}\n"
+ "{product_name:M5,product_ver:3.2.0,special_id:41550000}\n"
+ "{product_name:M5,product_ver:3.2.0,special_id:4B520000}\n"
+ "{product_name:M5,product_ver:3.2.0,special_id:49440000}\n"
+ "{product_name:M5,product_ver:3.2.0,special_id:53570000}\n"
+ "{product_name:M5,product_ver:3.2.0,special_id:42340000}\n"
+ "{product_name:M5,product_ver:3.2.0,special_id:54570000}\n",
+ .part_trail = 0x00,
+ .soft_ver = SOFT_VER_DEFAULT,
+
+ .partitions = {
+ {"SBL1", 0x00000, 0x30000},
+ {"boot-config_0", 0x30000, 0x10000},
+ {"MIBIB", 0x40000, 0x10000},
+ {"boot-config_1", 0x50000, 0x10000},
+ {"QSEE", 0x60000, 0x60000},
+ {"CDT", 0xc0000, 0x10000},
+ {"DDRPARAMS", 0xd0000, 0x10000},
+ {"uboot-env", 0xe0000, 0x10000},
+ {"fs-uboot@0", 0xf0000, 0x80000},
+ {"radio", 0x170000, 0x0fff0},
+ {"bluetooth-XTAL", 0x17fff0, 0x00010},
+ {"default-mac", 0x180000, 0x01000},
+ {"device-id", 0x182000, 0x01000},
+ {"product-info", 0x183000, 0x05000},
+ {"support-list", 0x190000, 0x10000},
+ {"user-config", 0x200000, 0x10000},
+ {"device-config", 0x210000, 0x10000},
+ {"group-info", 0x220000, 0x10000},
+ {"partition-table@0", 0x230000, 0x02000},
+ {"os-image@0", 0x240000, 0x300000},
+ {"file-system@0", 0x540000, 0x790000},
+ {"soft-version@0", 0xcd0000, 0x10000},
+ {"profile@0", 0xce0000, 0x10000},
+ {"default-config@0", 0xcf0000, 0x10000},
+ {"partition-table@1", 0xd00000, 0x02000},
+ {"fs-uboot@1", 0xd10000, 0x80000},
+ {"os-image@1", 0xd90000, 0x400000},
+ {"file-system@1", 0x1190000, 0xc40000},
+ {"soft-version@1", 0x1dd0000, 0x10000},
+ {"profile@1", 0x1de0000, 0x10000},
+ {"default-config@1", 0x1df0000, 0x10000},
+ {"tm-sig", 0x1e00000, 0x200000},
+ {NULL, 0, 0}
+ },
+
+ .partition_names.partition_table = "partition-table@1",
+ .partition_names.soft_ver = "soft-version@1",
+ .partition_names.os_image = "os-image@1",
+ .partition_names.file_system = "file-system@1",
+
+ .first_sysupgrade_partition = "os-image@1",
+ .last_sysupgrade_partition = "file-system@1"
+ },
+
/** Firmware layout for the Deco S4 v2 */
{
.id = "DECO-S4-V2",
.last_sysupgrade_partition = "file-system"
},
+ /** Firmware layout for the EAP610 v3/EAP613 v1 */
+ {
+ .id = "EAP610-V3",
+ .soft_ver = SOFT_VER_DEFAULT,
+ .soft_ver_compat_level = 1,
+ .support_list =
+ "SupportList:\r\n"
+ "EAP610(TP-Link|UN|AX1800-D):3.0\r\n"
+ "EAP610(TP-Link|JP|AX1800-D):3.0\r\n"
+ "EAP610(TP-Link|EG|AX1800-D):3.0\r\n"
+ "EAP610(TP-Link|CA|AX1800-D):3.0\r\n"
+ "EAP613(TP-Link|UN|AX1800-D):1.0 JP\r\n",
+ .part_trail = PART_TRAIL_NONE,
+
+ .partitions = {
+ {"fs-uboot", 0x00000, 0x80000},
+ {"partition-table", 0x80000, 0x02000},
+ {"default-mac", 0x90000, 0x01000},
+ {"support-list", 0x91000, 0x00100},
+ {"product-info", 0x91100, 0x00400},
+ {"soft-version", 0x92000, 0x00100},
+ {"firmware", 0xa0000, 0xcf0000},
+ {"user-config", 0xd90000, 0x60000},
+ {"mutil-log", 0xf30000, 0x80000},
+ {"oops", 0xfb0000, 0x40000},
+ {"radio", 0xff0000, 0x10000},
+ {NULL, 0, 0}
+ },
+
+ .first_sysupgrade_partition = "os-image",
+ .last_sysupgrade_partition = "file-system"
+ },
+
/** Firmware layout for the EAP615-Wall v1 */
{
.id = "EAP615-WALL-V1",
"SupportList:\n"
"{product_name:TL-WPA8631P,product_ver:3.0.0,special_id:41550000}\n"
"{product_name:TL-WPA8631P,product_ver:3.0.0,special_id:45550000}\n"
- "{product_name:TL-WPA8631P,product_ver:3.0.0,special_id:55530000}\n",
+ "{product_name:TL-WPA8631P,product_ver:3.0.0,special_id:55530000}\n"
+ "{product_name:TL-WPA8631P,product_ver:4.0.0,special_id:41550000}\n"
+ "{product_name:TL-WPA8631P,product_ver:4.0.0,special_id:45550000}\n"
+ "{product_name:TL-WPA8631P,product_ver:4.0.0,special_id:55530000}\n"
+ "{product_name:TL-WPA8635P,product_ver:3.0.0,special_id:46520000}\n",
.part_trail = 0x00,
.soft_ver = SOFT_VER_DEFAULT,
{"default-region", 0x732300, 0x00010},
{"product-info", 0x732400, 0x00200},
{"extra-para", 0x732600, 0x00200},
- {"soft-version", 0x732800, 0x00200},
- {"support-list", 0x732a00, 0x00100},
+ {"soft-version", 0x732800, 0x00100},
+ {"support-list", 0x732900, 0x00200},
{"profile", 0x732b00, 0x00100},
{"default-config", 0x732c00, 0x00800},
{"plc-type", 0x733400, 0x00020},
if (strcasecmp(info->id, "ARCHER-A6-V3") == 0 ||
strcasecmp(info->id, "ARCHER-A7-V5") == 0 ||
strcasecmp(info->id, "ARCHER-A9-V6") == 0 ||
+ strcasecmp(info->id, "ARCHER-AX23-V1") == 0 ||
strcasecmp(info->id, "ARCHER-C2-V3") == 0 ||
strcasecmp(info->id, "ARCHER-C7-V4") == 0 ||
strcasecmp(info->id, "ARCHER-C7-V5") == 0 ||
return 0;
}
+static void safeloader_read_partition(FILE *input_file, size_t payload_offset,
+ struct flash_partition_entry *entry,
+ struct image_partition_entry *part)
+{
+ size_t part_size = entry->size;
+ void *part_data = malloc(part_size);
+
+ if (fseek(input_file, payload_offset, SEEK_SET))
+ error(1, errno, "Failed to seek to partition data");
+
+ if (!part_data)
+ error(1, ENOMEM, "Failed to allocate partition data");
+
+ if (fread(part_data, 1, part_size, input_file) < part_size)
+ error(1, errno, "Failed to read partition data");
+
+ part->data = part_data;
+ part->size = part_size;
+ part->name = entry->name;
+}
+
+static void safeloader_parse_image(FILE *input_file, struct safeloader_image_info *image)
+{
+ static const char *HEADER_ID_CLOUD = "fw-type:Cloud";
+ static const char *HEADER_ID_QNEW = "?NEW";
+
+ char buf[64];
+
+ if (!input_file)
+ return;
+
+ fseek(input_file, SAFELOADER_PREAMBLE_SIZE, SEEK_SET);
+
+ if (fread(buf, sizeof(buf), 1, input_file) != 1)
+ error(1, errno, "Can not read image header");
+
+ if (memcmp(HEADER_ID_QNEW, &buf[0], strlen(HEADER_ID_QNEW)) == 0)
+ image->type = SAFELOADER_TYPE_QNEW;
+ else if (memcmp(HEADER_ID_CLOUD, &buf[0], strlen(HEADER_ID_CLOUD)) == 0)
+ image->type = SAFELOADER_TYPE_CLOUD;
+ else if (ntohl(*((uint32_t *) &buf[0])) <= SAFELOADER_HEADER_SIZE)
+ image->type = SAFELOADER_TYPE_VENDOR;
+ else
+ image->type = SAFELOADER_TYPE_DEFAULT;
+
+ switch (image->type) {
+ case SAFELOADER_TYPE_DEFAULT:
+ case SAFELOADER_TYPE_VENDOR:
+ case SAFELOADER_TYPE_CLOUD:
+ image->payload_offset = SAFELOADER_PAYLOAD_OFFSET;
+ break;
+ case SAFELOADER_TYPE_QNEW:
+ image->payload_offset = SAFELOADER_QNEW_PAYLOAD_OFFSET;
+ break;
+ }
+
+ /* Parse image partition table */
+ read_partition_table(input_file, image->payload_offset, &image->entries[0],
+ MAX_PARTITIONS, PARTITION_TABLE_FWUP);
+}
+
static void write_partition(
FILE *input_file,
size_t firmware_offset,
/** extract all partitions from the firmware file */
static int extract_firmware(const char *input, const char *output_directory)
{
- struct flash_partition_entry entries[16] = { 0 };
- size_t max_entries = 16;
- size_t firmware_offset = SAFELOADER_PAYLOAD_OFFSET;
- FILE *input_file;
-
+ struct safeloader_image_info info = {};
struct stat statbuf;
+ FILE *input_file;
/* check input file */
if (stat(input, &statbuf)) {
}
input_file = fopen(input, "rb");
+ safeloader_parse_image(input_file, &info);
- if (read_partition_table(input_file, firmware_offset, entries, 16, PARTITION_TABLE_FWUP) != 0)
- error(1, 0, "Error can not read the partition table (fwup-ptn)");
-
- for (size_t i = 0; i < max_entries && entries[i].name; i++)
- extract_firmware_partition(input_file, firmware_offset, &entries[i], output_directory);
+ for (size_t i = 0; i < MAX_PARTITIONS && info.entries[i].name; i++)
+ extract_firmware_partition(input_file, info.payload_offset, &info.entries[i], output_directory);
return 0;
}
static int firmware_info(const char *input)
{
- struct flash_partition_entry pointers[MAX_PARTITIONS] = { };
+ struct safeloader_image_info info = {};
+ struct image_partition_entry part = {};
struct flash_partition_entry *e;
- FILE *fp;
- int i;
+ FILE *input_file;
+
+ input_file = fopen(input, "rb");
- fp = fopen(input, "r");
+ safeloader_parse_image(input_file, &info);
- if (read_partition_table(fp, SAFELOADER_PAYLOAD_OFFSET, pointers, MAX_PARTITIONS, PARTITION_TABLE_FWUP))
- error(1, 0, "Error can not read the partition table (fwup-ptn)");
+ if (info.type == SAFELOADER_TYPE_VENDOR) {
+ char buf[SAFELOADER_HEADER_SIZE] = {};
+ uint32_t vendor_size;
+
+ fseek(input_file, SAFELOADER_PREAMBLE_SIZE, SEEK_SET);
+ fread(&vendor_size, sizeof(uint32_t), 1, input_file);
+
+ vendor_size = ntohl(vendor_size);
+ fread(buf, vendor_size, 1, input_file);
+
+ printf("Firmware vendor string:\n");
+ fwrite(buf, strnlen(buf, vendor_size), 1, stdout);
+ printf("\n");
+ }
printf("Firmware image partitions:\n");
printf("%-8s %-8s %s\n", "base", "size", "name");
- e = &pointers[0];
- for (i = 0; i < MAX_PARTITIONS && e->name; i++, e++)
+ e = &info.entries[0];
+ for (unsigned int i = 0; i < MAX_PARTITIONS && e->name; i++, e++)
printf("%08x %08x %s\n", e->base, e->size, e->name);
- e = find_partition(pointers, MAX_PARTITIONS, "soft-version", NULL);
+ e = find_partition(&info.entries[0], MAX_PARTITIONS, "soft-version", NULL);
if (e) {
- size_t data_len = e->size - sizeof(struct meta_header);
- char *buf = malloc(data_len);
struct soft_version *s;
+ unsigned int ascii_len;
+ const uint8_t *buf;
+ size_t data_len;
bool isstr;
- int i;
- if (!buf)
- error(1, errno, "Failed to alloc buffer");
+ safeloader_read_partition(input_file, info.payload_offset + e->base, e, &part);
+ data_len = ntohl(((struct meta_header *) part.data)->length);
+ buf = part.data + sizeof(struct meta_header);
- if (fseek(fp, SAFELOADER_PAYLOAD_OFFSET + e->base + sizeof(struct meta_header), SEEK_SET))
- error(1, errno, "Can not seek in the firmware");
+ /* Check for (null-terminated) string */
+ ascii_len = 0;
+ while (ascii_len < data_len && isascii(buf[ascii_len]))
+ ascii_len++;
- if (fread(buf, data_len, 1, fp) != 1)
- error(1, errno, "Can not read fwup-ptn data from the firmware");
-
- /* Check for string ignoring padding character */
- isstr = true;
- for (i = 0; i < data_len - 1; i++) {
- if (!isascii(buf[i])) {
- isstr = false;
- break;
- }
- }
+ isstr = ascii_len == data_len;
printf("\n[Software version]\n");
if (isstr) {
- fwrite(buf, data_len, 1, stdout);
+ fwrite(buf, strnlen((const char *) buf, data_len), 1, stdout);
putchar('\n');
} else if (data_len >= offsetof(struct soft_version, rev)) {
- s = (struct soft_version *)buf;
+ s = (struct soft_version *) buf;
printf("Version: %d.%d.%d\n", s->version_major, s->version_minor, s->version_patch);
printf("Date: %02x%02x-%02x-%02x\n", s->year_hi, s->year_lo, s->month, s->day);
printf("Failed to parse data\n");
}
- free(buf);
+ free_image_partition(&part);
}
- e = find_partition(pointers, MAX_PARTITIONS, "support-list", NULL);
+ e = find_partition(&info.entries[0], MAX_PARTITIONS, "support-list", NULL);
if (e) {
- char buf[128];
- size_t length;
- size_t bytes;
- size_t max_length = sizeof(buf) - 1;
+ size_t data_len;
- if (fseek(fp, SAFELOADER_PAYLOAD_OFFSET + e->base + sizeof(struct meta_header), SEEK_SET))
- error(1, errno, "Can not seek in the firmware");
+ safeloader_read_partition(input_file, info.payload_offset + e->base, e, &part);
+ data_len = ntohl(((struct meta_header *) part.data)->length);
printf("\n[Support list]\n");
- for (length = e->size - sizeof(struct meta_header); length; length -= bytes) {
- bytes = fread(buf, 1, length > max_length ? max_length: length, fp);
- if (bytes <= 0)
- error(1, errno, "Can not read fwup-ptn data from the firmware");
+ fwrite(part.data + sizeof(struct meta_header), data_len, 1, stdout);
+ printf("\n");
- buf[bytes] = '\0';
- printf(buf);
- }
- printf("\n");
+ free_image_partition(&part);
}
- e = find_partition(pointers, MAX_PARTITIONS, "partition-table", NULL);
+ e = find_partition(&info.entries[0], MAX_PARTITIONS, "partition-table", NULL);
if (e) {
- size_t flash_table_offset = SAFELOADER_PAYLOAD_OFFSET + e->base + 4;
- struct flash_partition_entry parts[MAX_PARTITIONS] = { };
+ size_t flash_table_offset = info.payload_offset + e->base + 4;
+ struct flash_partition_entry parts[MAX_PARTITIONS] = {};
- if (read_partition_table(fp, flash_table_offset, parts, MAX_PARTITIONS, PARTITION_TABLE_FLASH))
+ if (read_partition_table(input_file, flash_table_offset, parts, MAX_PARTITIONS, PARTITION_TABLE_FLASH))
error(1, 0, "Error can not read the partition table (partition)");
printf("\n[Partition table]\n");
printf("%-8s %-8s %s\n", "base", "size", "name");
e = &parts[0];
- for (i = 0; i < MAX_PARTITIONS && e->name; i++, e++)
+ for (unsigned int i = 0; i < MAX_PARTITIONS && e->name; i++, e++)
printf("%08x %08x %s\n", e->base, e->size, e->name);
}
- fclose(fp);
+ fclose(input_file);
return 0;
}
static void convert_firmware(const char *input, const char *output)
{
- struct flash_partition_entry fwup[MAX_PARTITIONS] = { 0 };
- struct flash_partition_entry flash[MAX_PARTITIONS] = { 0 };
- struct flash_partition_entry *fwup_os_image = NULL, *fwup_file_system = NULL;
- struct flash_partition_entry *flash_os_image = NULL, *flash_file_system = NULL;
- struct flash_partition_entry *fwup_partition_table = NULL;
- size_t firmware_offset = SAFELOADER_PAYLOAD_OFFSET;
- FILE *input_file, *output_file;
+ struct flash_partition_entry flash[MAX_PARTITIONS] = {};
+ struct flash_partition_entry *fwup_partition_table;
+ struct flash_partition_entry *flash_file_system;
+ struct flash_partition_entry *fwup_file_system;
+ struct flash_partition_entry *flash_os_image;
+ struct flash_partition_entry *fwup_os_image;
+ struct safeloader_image_info info = {};
size_t flash_table_offset;
-
struct stat statbuf;
+ FILE *output_file;
+ FILE *input_file;
/* check input file */
if (stat(input, &statbuf)) {
if (!output_file)
error(1, 0, "Can not open output firmware %s", output);
- if (read_partition_table(input_file, firmware_offset, fwup, MAX_PARTITIONS, 0) != 0) {
- error(1, 0, "Error can not read the partition table (fwup-ptn)");
- }
+ input_file = fopen(input, "rb");
+ safeloader_parse_image(input_file, &info);
- fwup_os_image = find_partition(fwup, MAX_PARTITIONS,
+ fwup_os_image = find_partition(info.entries, MAX_PARTITIONS,
"os-image", "Error can not find os-image partition (fwup)");
- fwup_file_system = find_partition(fwup, MAX_PARTITIONS,
+ fwup_file_system = find_partition(info.entries, MAX_PARTITIONS,
"file-system", "Error can not find file-system partition (fwup)");
- fwup_partition_table = find_partition(fwup, MAX_PARTITIONS,
+ fwup_partition_table = find_partition(info.entries, MAX_PARTITIONS,
"partition-table", "Error can not find partition-table partition");
/* the flash partition table has a 0x00000004 magic haeder */
- flash_table_offset = firmware_offset + fwup_partition_table->base + 4;
+ flash_table_offset = info.payload_offset + fwup_partition_table->base + 4;
if (read_partition_table(input_file, flash_table_offset, flash, MAX_PARTITIONS, PARTITION_TABLE_FLASH) != 0)
error(1, 0, "Error can not read the partition table (flash)");
"file-system", "Error can not find file-system partition (flash)");
/* write os_image to 0x0 */
- write_partition(input_file, firmware_offset, fwup_os_image, output_file);
+ write_partition(input_file, info.payload_offset, fwup_os_image, output_file);
write_ff(output_file, flash_os_image->size - fwup_os_image->size);
/* write file-system behind os_image */
fseek(output_file, flash_file_system->base - flash_os_image->base, SEEK_SET);
- write_partition(input_file, firmware_offset, fwup_file_system, output_file);
+ write_partition(input_file, info.payload_offset, fwup_file_system, output_file);
fclose(output_file);
fclose(input_file);