diff --git a/target/linux/generic/config-3.10 b/target/linux/generic/config-3.10 index 8b73b5f7e14..b3c3daa7348 100644 --- a/target/linux/generic/config-3.10 +++ b/target/linux/generic/config-3.10 @@ -1972,6 +1972,7 @@ CONFIG_MTD_SPLIT_FIRMWARE_NAME="firmware" # CONFIG_MTD_SPLIT_LZMA_FW is not set # CONFIG_MTD_SPLIT_SEAMA_FW is not set # CONFIG_MTD_SPLIT_SQUASHFS_ROOT is not set +# CONFIG_MTD_SPLIT_TRX_FW is not set # CONFIG_MTD_SPLIT_TPLINK_FW is not set # CONFIG_MTD_SPLIT_UIMAGE_FW is not set # CONFIG_MTD_SST25L is not set diff --git a/target/linux/generic/config-3.13 b/target/linux/generic/config-3.13 index 1ab5661fad8..b9ba3a898d0 100644 --- a/target/linux/generic/config-3.13 +++ b/target/linux/generic/config-3.13 @@ -2091,6 +2091,7 @@ CONFIG_MTD_SPLIT_FIRMWARE_NAME="firmware" # CONFIG_MTD_SPLIT_LZMA_FW is not set # CONFIG_MTD_SPLIT_SEAMA_FW is not set # CONFIG_MTD_SPLIT_SQUASHFS_ROOT is not set +# CONFIG_MTD_SPLIT_TRX_FW is not set # CONFIG_MTD_SPLIT_TPLINK_FW is not set # CONFIG_MTD_SPLIT_UIMAGE_FW is not set # CONFIG_MTD_SST25L is not set diff --git a/target/linux/generic/config-3.14 b/target/linux/generic/config-3.14 index c45c06554b9..88366aebd82 100644 --- a/target/linux/generic/config-3.14 +++ b/target/linux/generic/config-3.14 @@ -2134,6 +2134,7 @@ CONFIG_MTD_SPLIT_FIRMWARE_NAME="firmware" # CONFIG_MTD_SPLIT_LZMA_FW is not set # CONFIG_MTD_SPLIT_SEAMA_FW is not set CONFIG_MTD_SPLIT_SQUASHFS_ROOT=y +# CONFIG_MTD_SPLIT_TRX_FW is not set # CONFIG_MTD_SPLIT_TPLINK_FW is not set # CONFIG_MTD_SPLIT_UIMAGE_FW is not set # CONFIG_MTD_SST25L is not set diff --git a/target/linux/generic/config-3.18 b/target/linux/generic/config-3.18 index 906e0a5faed..2a00fac63ae 100644 --- a/target/linux/generic/config-3.18 +++ b/target/linux/generic/config-3.18 @@ -2234,6 +2234,7 @@ CONFIG_MTD_SPLIT_FIRMWARE_NAME="firmware" # CONFIG_MTD_SPLIT_LZMA_FW is not set # CONFIG_MTD_SPLIT_SEAMA_FW is not set CONFIG_MTD_SPLIT_SQUASHFS_ROOT=y +# CONFIG_MTD_SPLIT_TRX_FW is not set # CONFIG_MTD_SPLIT_TPLINK_FW is not set # CONFIG_MTD_SPLIT_UIMAGE_FW is not set # CONFIG_MTD_SST25L is not set diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/Kconfig b/target/linux/generic/files/drivers/mtd/mtdsplit/Kconfig index 94775ea37fe..fca6b480648 100644 --- a/target/linux/generic/files/drivers/mtd/mtdsplit/Kconfig +++ b/target/linux/generic/files/drivers/mtd/mtdsplit/Kconfig @@ -39,3 +39,8 @@ config MTD_SPLIT_TPLINK_FW bool "TP-Link firmware parser" depends on MTD_SPLIT_SUPPORT select MTD_SPLIT + +config MTD_SPLIT_TRX_FW + bool "TRX image based firmware partition parser" + depends on MTD_SPLIT_SUPPORT + select MTD_SPLIT diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/Makefile b/target/linux/generic/files/drivers/mtd/mtdsplit/Makefile index bcb250b64d2..12661ba151f 100644 --- a/target/linux/generic/files/drivers/mtd/mtdsplit/Makefile +++ b/target/linux/generic/files/drivers/mtd/mtdsplit/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_MTD_SPLIT_SQUASHFS_ROOT) += mtdsplit_squashfs.o obj-$(CONFIG_MTD_SPLIT_UIMAGE_FW) += mtdsplit_uimage.o obj-$(CONFIG_MTD_SPLIT_LZMA_FW) += mtdsplit_lzma.o obj-$(CONFIG_MTD_SPLIT_TPLINK_FW) += mtdsplit_tplink.o +obj-$(CONFIG_MTD_SPLIT_TRX_FW) += mtdsplit_trx.o diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_trx.c b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_trx.c new file mode 100644 index 00000000000..6efffce1965 --- /dev/null +++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_trx.c @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2013 Gabor Juhos + * Copyright (C) 2014 Felix Fietkau + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +#define TRX_MAGIC 0x30524448 /* "HDR0" */ + +struct trx_header { + __le32 magic; + __le32 len; + __le32 crc32; + __le32 flag_version; + __le32 offset[4]; +}; + +static int +read_trx_header(struct mtd_info *mtd, size_t offset, + struct trx_header *header) +{ + size_t header_len; + size_t retlen; + int ret; + + header_len = sizeof(*header); + ret = mtd_read(mtd, offset, header_len, &retlen, + (unsigned char *) header); + if (ret) { + pr_debug("read error in \"%s\"\n", mtd->name); + return ret; + } + + if (retlen != header_len) { + pr_debug("short read in \"%s\"\n", mtd->name); + return -EIO; + } + + return 0; +} + +static int +mtdsplit_parse_trx(struct mtd_info *master, + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct mtd_partition *parts; + struct trx_header hdr; + int nr_parts; + size_t offset; + size_t trx_offset; + size_t trx_size = 0; + size_t rootfs_offset; + size_t rootfs_size = 0; + int ret; + + nr_parts = 2; + parts = kzalloc(nr_parts * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + /* find trx image on erase block boundaries */ + for (offset = 0; offset < master->size; offset += master->erasesize) { + trx_size = 0; + + ret = read_trx_header(master, offset, &hdr); + if (ret) + continue; + + if (hdr.magic != cpu_to_le32(TRX_MAGIC)) { + pr_debug("no valid trx header found in \"%s\" at offset %llx\n", + master->name, (unsigned long long) offset); + continue; + } + + trx_size = le32_to_cpu(hdr.len); + if ((offset + trx_size) > master->size) { + pr_debug("trx image exceeds MTD device \"%s\"\n", + master->name); + continue; + } + break; + } + + if (trx_size == 0) { + pr_debug("no trx header found in \"%s\"\n", master->name); + ret = -ENODEV; + goto err; + } + + trx_offset = offset + hdr.offset[0]; + rootfs_offset = offset + hdr.offset[1]; + rootfs_size = master->size - rootfs_offset; + trx_size = rootfs_offset - trx_offset; + + if (rootfs_size == 0) { + pr_debug("no rootfs found in \"%s\"\n", master->name); + ret = -ENODEV; + goto err; + } + + parts[0].name = KERNEL_PART_NAME; + parts[0].offset = trx_offset; + parts[0].size = trx_size; + + parts[1].name = ROOTFS_PART_NAME; + parts[1].offset = rootfs_offset; + parts[1].size = rootfs_size; + + *pparts = parts; + return nr_parts; + +err: + kfree(parts); + return ret; +} + +static struct mtd_part_parser trx_parser = { + .owner = THIS_MODULE, + .name = "trx-fw", + .parse_fn = mtdsplit_parse_trx, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +static int __init mtdsplit_trx_init(void) +{ + register_mtd_parser(&trx_parser); + + return 0; +} + +module_init(mtdsplit_trx_init);