From 478a80a5dc3ed8299fc314a4633d35231f04eaec Mon Sep 17 00:00:00 2001 From: AmadeusGhost <42570690+AmadeusGhost@users.noreply.github.com> Date: Tue, 3 Mar 2020 17:06:29 +0800 Subject: [PATCH] drivers/mtd: update from official --- .../files/drivers/mtd/mtdsplit/mtdsplit_fit.c | 4 +- .../drivers/mtd/mtdsplit/mtdsplit_uimage.c | 141 +++++++++++++++--- .../drivers/mtd/mtdsplit/mtdsplit_wrgg.c | 10 ++ 3 files changed, 135 insertions(+), 20 deletions(-) diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_fit.c b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_fit.c index f9e5e53a95..67ee33d085 100644 --- a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_fit.c +++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_fit.c @@ -60,8 +60,8 @@ mtdsplit_fit_parse(struct mtd_info *mtd, hdr_len = sizeof(struct fdt_header); /* Parse the MTD device & search for the FIT image location */ - for(offset = 0; offset < mtd->size; offset += mtd->erasesize) { - ret = mtd_read(mtd, 0, hdr_len, &retlen, (void*) &hdr); + for(offset = 0; offset + hdr_len <= mtd->size; offset += mtd->erasesize) { + ret = mtd_read(mtd, offset, hdr_len, &retlen, (void*) &hdr); if (ret) { pr_err("read error in \"%s\" at offset 0x%llx\n", mtd->name, (unsigned long long) offset); 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 421106f052..a6e50b5113 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; @@ -241,7 +245,7 @@ mtdsplit_uimage_parse_generic(struct mtd_info *master, uimage_verify_default); } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) static const struct of_device_id mtdsplit_uimage_of_match_table[] = { { .compatible = "denx,uimage" }, {}, @@ -251,7 +255,7 @@ static const struct of_device_id mtdsplit_uimage_of_match_table[] = { static struct mtd_part_parser uimage_generic_parser = { .owner = THIS_MODULE, .name = "uimage-fw", -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) .of_match_table = mtdsplit_uimage_of_match_table, #endif .parse_fn = mtdsplit_uimage_parse_generic, @@ -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; @@ -308,7 +312,7 @@ mtdsplit_uimage_parse_netgear(struct mtd_info *master, uimage_verify_wndr3700); } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) static const struct of_device_id mtdsplit_uimage_netgear_of_match_table[] = { { .compatible = "netgear,uimage" }, {}, @@ -318,7 +322,7 @@ static const struct of_device_id mtdsplit_uimage_netgear_of_match_table[] = { static struct mtd_part_parser uimage_netgear_parser = { .owner = THIS_MODULE, .name = "netgear-fw", -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) .of_match_table = mtdsplit_uimage_netgear_of_match_table, #endif .parse_fn = mtdsplit_uimage_parse_netgear, @@ -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; @@ -360,7 +364,7 @@ mtdsplit_uimage_parse_edimax(struct mtd_info *master, uimage_find_edimax); } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) static const struct of_device_id mtdsplit_uimage_edimax_of_match_table[] = { { .compatible = "edimax,uimage" }, {}, @@ -370,13 +374,112 @@ static const struct of_device_id mtdsplit_uimage_edimax_of_match_table[] = { static struct mtd_part_parser uimage_edimax_parser = { .owner = THIS_MODULE, .name = "edimax-fw", -#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) .of_match_table = mtdsplit_uimage_edimax_of_match_table, #endif .parse_fn = mtdsplit_uimage_parse_edimax, .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, +}; + +/************************************************** + * OKLI (OpenWrt Kernel Loader Image) + **************************************************/ + +#define IH_MAGIC_OKLI 0x4f4b4c49 + +static ssize_t uimage_verify_okli(u_char *buf, size_t len, int *extralen) +{ + struct uimage_header *header = (struct uimage_header *)buf; + + /* default sanity checks */ + if (be32_to_cpu(header->ih_magic) != IH_MAGIC_OKLI) { + pr_debug("invalid uImage magic: %08x\n", + be32_to_cpu(header->ih_magic)); + return -EINVAL; + } + + if (header->ih_os != IH_OS_LINUX) { + pr_debug("invalid uImage OS: %08x\n", + be32_to_cpu(header->ih_os)); + return -EINVAL; + } + + if (header->ih_type != IH_TYPE_KERNEL) { + pr_debug("invalid uImage type: %08x\n", + be32_to_cpu(header->ih_type)); + return -EINVAL; + } + + return 0; +} + +static int +mtdsplit_uimage_parse_okli(struct mtd_info *master, + const struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + return __mtdsplit_parse_uimage(master, pparts, data, + uimage_verify_okli); +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) +static const struct of_device_id mtdsplit_uimage_okli_of_match_table[] = { + { .compatible = "openwrt,okli" }, + {}, +}; +#endif + +static struct mtd_part_parser uimage_okli_parser = { + .owner = THIS_MODULE, + .name = "okli-fw", +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0) + .of_match_table = mtdsplit_uimage_okli_of_match_table, +#endif + .parse_fn = mtdsplit_uimage_parse_okli, +}; + /************************************************** * Init **************************************************/ @@ -386,6 +489,8 @@ 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); + register_mtd_parser(&uimage_okli_parser); return 0; } diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_wrgg.c b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_wrgg.c index 28d1cbad80..fde49ece06 100644 --- a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_wrgg.c +++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_wrgg.c @@ -73,6 +73,16 @@ static int mtdsplit_parse_wrgg(struct mtd_info *master, /* sanity checks */ if (le32_to_cpu(hdr.magic1) == WRGG03_MAGIC) { kernel_ent_size = hdr_len + be32_to_cpu(hdr.size); + /* + * If this becomes silly big it's probably because the + * WRGG image is little-endian. + */ + if (kernel_ent_size > master->size) + kernel_ent_size = hdr_len + le32_to_cpu(hdr.size); + + /* Now what ?! It's neither */ + if (kernel_ent_size > master->size) + return -EINVAL; } else if (le32_to_cpu(hdr.magic1) == WRG_MAGIC) { kernel_ent_size = sizeof(struct wrg_header) + le32_to_cpu( ((struct wrg_header*)&hdr)->size);