diff options
Diffstat (limited to 'target/linux/generic/files/drivers/mtd')
-rw-r--r-- | target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_uimage.c | 72 |
1 files changed, 60 insertions, 12 deletions
diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_uimage.c b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_uimage.c index aba1c83ad6..091403ae91 100644 --- a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_uimage.c +++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_uimage.c @@ -24,9 +24,9 @@ /* * uimage_header itself is only 64B, but it may be prepended with another data. - * Currently the biggest size is for Edimax devices: 20B + 64B + * Currently the biggest size is for Fon(Foxconn) devices: 64B + 32B */ -#define MAX_HEADER_LEN 84 +#define MAX_HEADER_LEN 96 #define IH_MAGIC 0x27051956 /* Image Magic Number */ #define IH_NMLEN 32 /* Image Name Length */ @@ -80,12 +80,12 @@ read_uimage_header(struct mtd_info *mtd, size_t offset, u_char *buf, * __mtdsplit_parse_uimage - scan partition and create kernel + rootfs parts * * @find_header: function to call for a block of data that will return offset - * of a valid uImage header if found + * and tail padding length of a valid uImage header if found */ static int __mtdsplit_parse_uimage(struct mtd_info *master, - const struct mtd_partition **pparts, - struct mtd_part_parser_data *data, - ssize_t (*find_header)(u_char *buf, size_t len)) + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data, + ssize_t (*find_header)(u_char *buf, size_t len, int *extralen)) { struct mtd_partition *parts; u_char *buf; @@ -97,6 +97,7 @@ static int __mtdsplit_parse_uimage(struct mtd_info *master, size_t rootfs_size = 0; int uimage_part, rf_part; int ret; + int extralen; enum mtdsplit_part_type type; nr_parts = 2; @@ -120,7 +121,8 @@ static int __mtdsplit_parse_uimage(struct mtd_info *master, if (ret) continue; - ret = find_header(buf, MAX_HEADER_LEN); + extralen = 0; + ret = find_header(buf, MAX_HEADER_LEN, &extralen); if (ret < 0) { pr_debug("no valid uImage found in \"%s\" at offset %llx\n", master->name, (unsigned long long) offset); @@ -128,7 +130,9 @@ static int __mtdsplit_parse_uimage(struct mtd_info *master, } header = (struct uimage_header *)(buf + ret); - uimage_size = sizeof(*header) + be32_to_cpu(header->ih_size) + ret; + uimage_size = sizeof(*header) + + be32_to_cpu(header->ih_size) + ret + extralen; + if ((offset + uimage_size) > master->size) { pr_debug("uImage exceeds MTD device \"%s\"\n", master->name); @@ -206,7 +210,7 @@ err_free_parts: return ret; } -static ssize_t uimage_verify_default(u_char *buf, size_t len) +static ssize_t uimage_verify_default(u_char *buf, size_t len, int *extralen) { struct uimage_header *header = (struct uimage_header *)buf; @@ -269,7 +273,7 @@ static struct mtd_part_parser uimage_generic_parser = { #define FW_MAGIC_WNDR3700V2 0x33373031 #define FW_MAGIC_WPN824N 0x31313030 -static ssize_t uimage_verify_wndr3700(u_char *buf, size_t len) +static ssize_t uimage_verify_wndr3700(u_char *buf, size_t len, int *extralen) { struct uimage_header *header = (struct uimage_header *)buf; uint8_t expected_type = IH_TYPE_FILESYSTEM; @@ -332,7 +336,7 @@ static struct mtd_part_parser uimage_netgear_parser = { #define FW_EDIMAX_OFFSET 20 #define FW_MAGIC_EDIMAX 0x43535953 -static ssize_t uimage_find_edimax(u_char *buf, size_t len) +static ssize_t uimage_find_edimax(u_char *buf, size_t len, int *extralen) { u32 *magic; @@ -345,7 +349,7 @@ static ssize_t uimage_find_edimax(u_char *buf, size_t len) if (be32_to_cpu(*magic) != FW_MAGIC_EDIMAX) return -EINVAL; - if (!uimage_verify_default(buf + FW_EDIMAX_OFFSET, len)) + if (!uimage_verify_default(buf + FW_EDIMAX_OFFSET, len, extralen)) return FW_EDIMAX_OFFSET; return -EINVAL; @@ -377,6 +381,49 @@ static struct mtd_part_parser uimage_edimax_parser = { .type = MTD_PARSER_TYPE_FIRMWARE, }; + +/************************************************** + * Fon(Foxconn) + **************************************************/ + +#define FONFXC_PAD_LEN 32 + +static ssize_t uimage_find_fonfxc(u_char *buf, size_t len, int *extralen) +{ + if (uimage_verify_default(buf, len, extralen) < 0) + return -EINVAL; + + *extralen = FONFXC_PAD_LEN; + + return 0; +} + +static int +mtdsplit_uimage_parse_fonfxc(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + return __mtdsplit_parse_uimage(master, pparts, data, + uimage_find_fonfxc); +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) +static const struct of_device_id mtdsplit_uimage_fonfxc_of_match_table[] = { + { .compatible = "fonfxc,uimage" }, + {}, +}; +#endif + +static struct mtd_part_parser uimage_fonfxc_parser = { + .owner = THIS_MODULE, + .name = "fonfxc-fw", +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) + .of_match_table = mtdsplit_uimage_fonfxc_of_match_table, +#endif + .parse_fn = mtdsplit_uimage_parse_fonfxc, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + /************************************************** * Init **************************************************/ @@ -386,6 +433,7 @@ static int __init mtdsplit_uimage_init(void) register_mtd_parser(&uimage_generic_parser); register_mtd_parser(&uimage_netgear_parser); register_mtd_parser(&uimage_edimax_parser); + register_mtd_parser(&uimage_fonfxc_parser); return 0; } |