From 4153c0adff074167f1eb934235129471d2c04199 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 2 Jan 2015 21:52:35 +0000 Subject: kernel: move mtdsplit files to drivers/mtd/mtdsplit/ to simplify maintenance, unify patches across kernel versions Signed-off-by: Felix Fietkau SVN-Revision: 43805 --- target/linux/generic/files/drivers/mtd/mtdsplit.c | 116 --------- target/linux/generic/files/drivers/mtd/mtdsplit.h | 55 ---- .../generic/files/drivers/mtd/mtdsplit/Kconfig | 12 + .../generic/files/drivers/mtd/mtdsplit/Makefile | 5 + .../generic/files/drivers/mtd/mtdsplit/mtdsplit.c | 116 +++++++++ .../generic/files/drivers/mtd/mtdsplit/mtdsplit.h | 55 ++++ .../files/drivers/mtd/mtdsplit/mtdsplit_lzma.c | 96 +++++++ .../files/drivers/mtd/mtdsplit/mtdsplit_seama.c | 103 ++++++++ .../files/drivers/mtd/mtdsplit/mtdsplit_squashfs.c | 72 ++++++ .../files/drivers/mtd/mtdsplit/mtdsplit_uimage.c | 287 +++++++++++++++++++++ .../generic/files/drivers/mtd/mtdsplit_lzma.c | 96 ------- .../generic/files/drivers/mtd/mtdsplit_seama.c | 103 -------- .../generic/files/drivers/mtd/mtdsplit_squashfs.c | 72 ------ .../generic/files/drivers/mtd/mtdsplit_uimage.c | 287 --------------------- 14 files changed, 746 insertions(+), 729 deletions(-) delete mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit.c delete mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit.h create mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit/Makefile create mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit.c create mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit.h create mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_lzma.c create mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_seama.c create mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_squashfs.c create mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_uimage.c delete mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit_lzma.c delete mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit_seama.c delete mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit_squashfs.c delete mode 100644 target/linux/generic/files/drivers/mtd/mtdsplit_uimage.c (limited to 'target/linux/generic/files/drivers/mtd') diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit.c b/target/linux/generic/files/drivers/mtd/mtdsplit.c deleted file mode 100644 index 162739f..0000000 --- a/target/linux/generic/files/drivers/mtd/mtdsplit.c +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2009-2013 Felix Fietkau - * Copyright (C) 2009-2013 Gabor Juhos - * Copyright (C) 2012 Jonas Gorski - * Copyright (C) 2013 Hauke Mehrtens - * - * 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) "mtdsplit: " fmt - -#include -#include -#include -#include -#include -#include -#include - -#include "mtdsplit.h" - -struct squashfs_super_block { - __le32 s_magic; - __le32 pad0[9]; - __le64 bytes_used; -}; - -int mtd_get_squashfs_len(struct mtd_info *master, - size_t offset, - size_t *squashfs_len) -{ - struct squashfs_super_block sb; - size_t retlen; - int err; - - err = mtd_read(master, offset, sizeof(sb), &retlen, (void *)&sb); - if (err || (retlen != sizeof(sb))) { - pr_alert("error occured while reading from \"%s\"\n", - master->name); - return -EIO; - } - - if (le32_to_cpu(sb.s_magic) != SQUASHFS_MAGIC) { - pr_alert("no squashfs found in \"%s\"\n", master->name); - return -EINVAL; - } - - retlen = le64_to_cpu(sb.bytes_used); - if (retlen <= 0) { - pr_alert("squashfs is empty in \"%s\"\n", master->name); - return -ENODEV; - } - - if (offset + retlen > master->size) { - pr_alert("squashfs has invalid size in \"%s\"\n", - master->name); - return -EINVAL; - } - - *squashfs_len = retlen; - return 0; -} -EXPORT_SYMBOL_GPL(mtd_get_squashfs_len); - -static ssize_t mtd_next_eb(struct mtd_info *mtd, size_t offset) -{ - return mtd_rounddown_to_eb(offset, mtd) + mtd->erasesize; -} - -int mtd_check_rootfs_magic(struct mtd_info *mtd, size_t offset) -{ - u32 magic; - size_t retlen; - int ret; - - ret = mtd_read(mtd, offset, sizeof(magic), &retlen, - (unsigned char *) &magic); - if (ret) - return ret; - - if (retlen != sizeof(magic)) - return -EIO; - - if (le32_to_cpu(magic) != SQUASHFS_MAGIC && - magic != 0x19852003) - return -EINVAL; - - return 0; -} -EXPORT_SYMBOL_GPL(mtd_check_rootfs_magic); - -int mtd_find_rootfs_from(struct mtd_info *mtd, - size_t from, - size_t limit, - size_t *ret_offset) -{ - size_t offset; - int err; - - for (offset = from; offset < limit; - offset = mtd_next_eb(mtd, offset)) { - err = mtd_check_rootfs_magic(mtd, offset); - if (err) - continue; - - *ret_offset = offset; - return 0; - } - - return -ENODEV; -} -EXPORT_SYMBOL_GPL(mtd_find_rootfs_from); - diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit.h b/target/linux/generic/files/drivers/mtd/mtdsplit.h deleted file mode 100644 index 7ee88b0..0000000 --- a/target/linux/generic/files/drivers/mtd/mtdsplit.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2009-2013 Felix Fietkau - * Copyright (C) 2009-2013 Gabor Juhos - * Copyright (C) 2012 Jonas Gorski - * Copyright (C) 2013 Hauke Mehrtens - * - * 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. - * - */ - -#ifndef _MTDSPLIT_H -#define _MTDSPLIT_H - -#define KERNEL_PART_NAME "kernel" -#define ROOTFS_PART_NAME "rootfs" - -#define ROOTFS_SPLIT_NAME "rootfs_data" - -#ifdef CONFIG_MTD_SPLIT -int mtd_get_squashfs_len(struct mtd_info *master, - size_t offset, - size_t *squashfs_len); - -int mtd_check_rootfs_magic(struct mtd_info *mtd, size_t offset); - -int mtd_find_rootfs_from(struct mtd_info *mtd, - size_t from, - size_t limit, - size_t *ret_offset); - -#else -static inline int mtd_get_squashfs_len(struct mtd_info *master, - size_t offset, - size_t *squashfs_len) -{ - return -ENODEV; -} - -static inline int mtd_check_rootfs_magic(struct mtd_info *mtd, size_t offset) -{ - return -EINVAL; -} - -static inline int mtd_find_rootfs_from(struct mtd_info *mtd, - size_t from, - size_t limit, - size_t *ret_offset) -{ - return -ENODEV; -} -#endif /* CONFIG_MTD_SPLIT */ - -#endif /* _MTDSPLIT_H */ diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/Kconfig b/target/linux/generic/files/drivers/mtd/mtdsplit/Kconfig index 09794f4..9a32daa 100644 --- a/target/linux/generic/files/drivers/mtd/mtdsplit/Kconfig +++ b/target/linux/generic/files/drivers/mtd/mtdsplit/Kconfig @@ -1,7 +1,16 @@ +config MTD_SPLIT + def_bool n + help + Generic MTD split support. + +config MTD_SPLIT_SUPPORT + def_bool MTD = y + comment "Rootfs partition parsers" config MTD_SPLIT_SQUASHFS_ROOT bool "Squashfs based root partition parser" + depends on MTD_SPLIT_SUPPORT select MTD_SPLIT default n help @@ -13,12 +22,15 @@ comment "Firmware partition parsers" config MTD_SPLIT_SEAMA_FW bool "Seama firmware parser" + depends on MTD_SPLIT_SUPPORT select MTD_SPLIT config MTD_SPLIT_UIMAGE_FW bool "uImage based firmware partition parser" + depends on MTD_SPLIT_SUPPORT select MTD_SPLIT config MTD_SPLIT_LZMA_FW bool "LZMA compressed kernel 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 new file mode 100644 index 0000000..41bc1de --- /dev/null +++ b/target/linux/generic/files/drivers/mtd/mtdsplit/Makefile @@ -0,0 +1,5 @@ +obj-$(CONFIG_MTD_SPLIT) += mtdsplit.o +obj-$(CONFIG_MTD_SPLIT_SEAMA_FW) += mtdsplit_seama.o +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 diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit.c b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit.c new file mode 100644 index 0000000..162739f --- /dev/null +++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit.c @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2009-2013 Felix Fietkau + * Copyright (C) 2009-2013 Gabor Juhos + * Copyright (C) 2012 Jonas Gorski + * Copyright (C) 2013 Hauke Mehrtens + * + * 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) "mtdsplit: " fmt + +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +struct squashfs_super_block { + __le32 s_magic; + __le32 pad0[9]; + __le64 bytes_used; +}; + +int mtd_get_squashfs_len(struct mtd_info *master, + size_t offset, + size_t *squashfs_len) +{ + struct squashfs_super_block sb; + size_t retlen; + int err; + + err = mtd_read(master, offset, sizeof(sb), &retlen, (void *)&sb); + if (err || (retlen != sizeof(sb))) { + pr_alert("error occured while reading from \"%s\"\n", + master->name); + return -EIO; + } + + if (le32_to_cpu(sb.s_magic) != SQUASHFS_MAGIC) { + pr_alert("no squashfs found in \"%s\"\n", master->name); + return -EINVAL; + } + + retlen = le64_to_cpu(sb.bytes_used); + if (retlen <= 0) { + pr_alert("squashfs is empty in \"%s\"\n", master->name); + return -ENODEV; + } + + if (offset + retlen > master->size) { + pr_alert("squashfs has invalid size in \"%s\"\n", + master->name); + return -EINVAL; + } + + *squashfs_len = retlen; + return 0; +} +EXPORT_SYMBOL_GPL(mtd_get_squashfs_len); + +static ssize_t mtd_next_eb(struct mtd_info *mtd, size_t offset) +{ + return mtd_rounddown_to_eb(offset, mtd) + mtd->erasesize; +} + +int mtd_check_rootfs_magic(struct mtd_info *mtd, size_t offset) +{ + u32 magic; + size_t retlen; + int ret; + + ret = mtd_read(mtd, offset, sizeof(magic), &retlen, + (unsigned char *) &magic); + if (ret) + return ret; + + if (retlen != sizeof(magic)) + return -EIO; + + if (le32_to_cpu(magic) != SQUASHFS_MAGIC && + magic != 0x19852003) + return -EINVAL; + + return 0; +} +EXPORT_SYMBOL_GPL(mtd_check_rootfs_magic); + +int mtd_find_rootfs_from(struct mtd_info *mtd, + size_t from, + size_t limit, + size_t *ret_offset) +{ + size_t offset; + int err; + + for (offset = from; offset < limit; + offset = mtd_next_eb(mtd, offset)) { + err = mtd_check_rootfs_magic(mtd, offset); + if (err) + continue; + + *ret_offset = offset; + return 0; + } + + return -ENODEV; +} +EXPORT_SYMBOL_GPL(mtd_find_rootfs_from); + diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit.h b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit.h new file mode 100644 index 0000000..7ee88b0 --- /dev/null +++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2009-2013 Felix Fietkau + * Copyright (C) 2009-2013 Gabor Juhos + * Copyright (C) 2012 Jonas Gorski + * Copyright (C) 2013 Hauke Mehrtens + * + * 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. + * + */ + +#ifndef _MTDSPLIT_H +#define _MTDSPLIT_H + +#define KERNEL_PART_NAME "kernel" +#define ROOTFS_PART_NAME "rootfs" + +#define ROOTFS_SPLIT_NAME "rootfs_data" + +#ifdef CONFIG_MTD_SPLIT +int mtd_get_squashfs_len(struct mtd_info *master, + size_t offset, + size_t *squashfs_len); + +int mtd_check_rootfs_magic(struct mtd_info *mtd, size_t offset); + +int mtd_find_rootfs_from(struct mtd_info *mtd, + size_t from, + size_t limit, + size_t *ret_offset); + +#else +static inline int mtd_get_squashfs_len(struct mtd_info *master, + size_t offset, + size_t *squashfs_len) +{ + return -ENODEV; +} + +static inline int mtd_check_rootfs_magic(struct mtd_info *mtd, size_t offset) +{ + return -EINVAL; +} + +static inline int mtd_find_rootfs_from(struct mtd_info *mtd, + size_t from, + size_t limit, + size_t *ret_offset) +{ + return -ENODEV; +} +#endif /* CONFIG_MTD_SPLIT */ + +#endif /* _MTDSPLIT_H */ diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_lzma.c b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_lzma.c new file mode 100644 index 0000000..64dc7cb --- /dev/null +++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_lzma.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2014 Gabor Juhos + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "mtdsplit.h" + +#define LZMA_NR_PARTS 2 +#define LZMA_PROPERTIES_SIZE 5 + +struct lzma_header { + u8 props[LZMA_PROPERTIES_SIZE]; + u8 size_low[4]; + u8 size_high[4]; +}; + +static int mtdsplit_parse_lzma(struct mtd_info *master, + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct lzma_header hdr; + size_t hdr_len, retlen; + size_t rootfs_offset; + u32 t; + struct mtd_partition *parts; + int err; + + hdr_len = sizeof(hdr); + err = mtd_read(master, 0, hdr_len, &retlen, (void *) &hdr); + if (err) + return err; + + if (retlen != hdr_len) + return -EIO; + + /* verify LZMA properties */ + if (hdr.props[0] >= (9 * 5 * 5)) + return -EINVAL; + + t = get_unaligned_le32(&hdr.props[1]); + if (!is_power_of_2(t)) + return -EINVAL; + + t = get_unaligned_le32(&hdr.size_high); + if (t) + return -EINVAL; + + err = mtd_find_rootfs_from(master, master->erasesize, + master->size, &rootfs_offset); + if (err) + return err; + + parts = kzalloc(LZMA_NR_PARTS * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + parts[0].name = KERNEL_PART_NAME; + parts[0].offset = 0; + parts[0].size = rootfs_offset; + + parts[1].name = ROOTFS_PART_NAME; + parts[1].offset = rootfs_offset; + parts[1].size = master->size - rootfs_offset; + + *pparts = parts; + return LZMA_NR_PARTS; +} + +static struct mtd_part_parser mtdsplit_lzma_parser = { + .owner = THIS_MODULE, + .name = "lzma-fw", + .parse_fn = mtdsplit_parse_lzma, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +static int __init mtdsplit_lzma_init(void) +{ + register_mtd_parser(&mtdsplit_lzma_parser); + + return 0; +} + +subsys_initcall(mtdsplit_lzma_init); diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_seama.c b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_seama.c new file mode 100644 index 0000000..6f21f8f --- /dev/null +++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_seama.c @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2013 Gabor Juhos + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "mtdsplit.h" + +#define SEAMA_MAGIC 0x5EA3A417 +#define SEAMA_NR_PARTS 2 +#define SEAMA_MIN_ROOTFS_OFFS 0x80000 /* 512KiB */ + +struct seama_header { + __be32 magic; /* should always be SEAMA_MAGIC. */ + __be16 reserved; /* reserved for */ + __be16 metasize; /* size of the META data */ + __be32 size; /* size of the image */ +}; + +static int mtdsplit_parse_seama(struct mtd_info *master, + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct seama_header hdr; + size_t hdr_len, retlen, kernel_size; + size_t rootfs_offset; + struct mtd_partition *parts; + int err; + + hdr_len = sizeof(hdr); + err = mtd_read(master, 0, hdr_len, &retlen, (void *) &hdr); + if (err) + return err; + + if (retlen != hdr_len) + return -EIO; + + /* sanity checks */ + if (be32_to_cpu(hdr.magic) != SEAMA_MAGIC) + return -EINVAL; + + kernel_size = hdr_len + be32_to_cpu(hdr.size) + + be16_to_cpu(hdr.metasize); + if (kernel_size > master->size) + return -EINVAL; + + /* Find the rootfs after the kernel. */ + err = mtd_check_rootfs_magic(master, kernel_size); + if (!err) { + rootfs_offset = kernel_size; + } else { + /* + * The size in the header might cover the rootfs as well. + * Start the search from an arbitrary offset. + */ + err = mtd_find_rootfs_from(master, SEAMA_MIN_ROOTFS_OFFS, + master->size, &rootfs_offset); + if (err) + return err; + } + + parts = kzalloc(SEAMA_NR_PARTS * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + parts[0].name = KERNEL_PART_NAME; + parts[0].offset = 0; + parts[0].size = rootfs_offset; + + parts[1].name = ROOTFS_PART_NAME; + parts[1].offset = rootfs_offset; + parts[1].size = master->size - rootfs_offset; + + *pparts = parts; + return SEAMA_NR_PARTS; +} + +static struct mtd_part_parser mtdsplit_seama_parser = { + .owner = THIS_MODULE, + .name = "seama-fw", + .parse_fn = mtdsplit_parse_seama, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +static int __init mtdsplit_seama_init(void) +{ + register_mtd_parser(&mtdsplit_seama_parser); + + return 0; +} + +subsys_initcall(mtdsplit_seama_init); diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_squashfs.c b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_squashfs.c new file mode 100644 index 0000000..3d80e07 --- /dev/null +++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_squashfs.c @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2013 Felix Fietkau + * Copyright (C) 2013 Gabor Juhos + * + * 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 + +#include "mtdsplit.h" + +static int +mtdsplit_parse_squashfs(struct mtd_info *master, + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct mtd_partition *part; + struct mtd_info *parent_mtd; + size_t part_offset; + size_t squashfs_len; + int err; + + err = mtd_get_squashfs_len(master, 0, &squashfs_len); + if (err) + return err; + + parent_mtd = mtdpart_get_master(master); + part_offset = mtdpart_get_offset(master); + + part = kzalloc(sizeof(*part), GFP_KERNEL); + if (!part) { + pr_alert("unable to allocate memory for \"%s\" partition\n", + ROOTFS_SPLIT_NAME); + return -ENOMEM; + } + + part->name = ROOTFS_SPLIT_NAME; + part->offset = mtd_roundup_to_eb(part_offset + squashfs_len, + parent_mtd) - part_offset; + part->size = master->size - part->offset; + + *pparts = part; + return 1; +} + +static struct mtd_part_parser mtdsplit_squashfs_parser = { + .owner = THIS_MODULE, + .name = "squashfs-split", + .parse_fn = mtdsplit_parse_squashfs, + .type = MTD_PARSER_TYPE_ROOTFS, +}; + +static int __init mtdsplit_squashfs_init(void) +{ + register_mtd_parser(&mtdsplit_squashfs_parser); + + return 0; +} + +subsys_initcall(mtdsplit_squashfs_init); diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_uimage.c b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_uimage.c new file mode 100644 index 0000000..7dad63c --- /dev/null +++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_uimage.c @@ -0,0 +1,287 @@ +/* + * Copyright (C) 2013 Gabor Juhos + * + * 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 + +#include "mtdsplit.h" + +#define IH_MAGIC 0x27051956 /* Image Magic Number */ +#define IH_NMLEN 32 /* Image Name Length */ + +#define IH_OS_LINUX 5 /* Linux */ + +#define IH_TYPE_KERNEL 2 /* OS Kernel Image */ +#define IH_TYPE_FILESYSTEM 7 /* Filesystem Image */ + +/* + * Legacy format image header, + * all data in network byte order (aka natural aka bigendian). + */ +struct uimage_header { + uint32_t ih_magic; /* Image Header Magic Number */ + uint32_t ih_hcrc; /* Image Header CRC Checksum */ + uint32_t ih_time; /* Image Creation Timestamp */ + uint32_t ih_size; /* Image Data Size */ + uint32_t ih_load; /* Data Load Address */ + uint32_t ih_ep; /* Entry Point Address */ + uint32_t ih_dcrc; /* Image Data CRC Checksum */ + uint8_t ih_os; /* Operating System */ + uint8_t ih_arch; /* CPU architecture */ + uint8_t ih_type; /* Image Type */ + uint8_t ih_comp; /* Compression Type */ + uint8_t ih_name[IH_NMLEN]; /* Image Name */ +}; + +static int +read_uimage_header(struct mtd_info *mtd, size_t offset, + struct uimage_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_uimage(struct mtd_info *master, + struct mtd_partition **pparts, + struct mtd_part_parser_data *data, + bool (*verify)(struct uimage_header *hdr)) +{ + struct mtd_partition *parts; + struct uimage_header *header; + int nr_parts; + size_t offset; + size_t uimage_offset; + size_t uimage_size = 0; + size_t rootfs_offset; + size_t rootfs_size = 0; + int uimage_part, rf_part; + int ret; + + nr_parts = 2; + parts = kzalloc(nr_parts * sizeof(*parts), GFP_KERNEL); + if (!parts) + return -ENOMEM; + + header = vmalloc(sizeof(*header)); + if (!header) { + ret = -ENOMEM; + goto err_free_parts; + } + + /* find uImage on erase block boundaries */ + for (offset = 0; offset < master->size; offset += master->erasesize) { + uimage_size = 0; + + ret = read_uimage_header(master, offset, header); + if (ret) + continue; + + if (!verify(header)) { + pr_debug("no valid uImage found in \"%s\" at offset %llx\n", + master->name, (unsigned long long) offset); + continue; + } + + uimage_size = sizeof(*header) + be32_to_cpu(header->ih_size); + if ((offset + uimage_size) > master->size) { + pr_debug("uImage exceeds MTD device \"%s\"\n", + master->name); + continue; + } + break; + } + + if (uimage_size == 0) { + pr_debug("no uImage found in \"%s\"\n", master->name); + ret = -ENODEV; + goto err_free_header; + } + + uimage_offset = offset; + + if (uimage_offset == 0) { + uimage_part = 0; + rf_part = 1; + + /* find the roots after the uImage */ + ret = mtd_find_rootfs_from(master, + uimage_offset + uimage_size, + master->size, + &rootfs_offset); + if (ret) { + pr_debug("no rootfs after uImage in \"%s\"\n", + master->name); + goto err_free_header; + } + + rootfs_size = master->size - rootfs_offset; + uimage_size = rootfs_offset - uimage_offset; + } else { + rf_part = 0; + uimage_part = 1; + + /* check rootfs presence at offset 0 */ + ret = mtd_check_rootfs_magic(master, 0); + if (ret) { + pr_debug("no rootfs before uImage in \"%s\"\n", + master->name); + goto err_free_header; + } + + rootfs_offset = 0; + rootfs_size = uimage_offset; + } + + if (rootfs_size == 0) { + pr_debug("no rootfs found in \"%s\"\n", master->name); + ret = -ENODEV; + goto err_free_header; + } + + parts[uimage_part].name = KERNEL_PART_NAME; + parts[uimage_part].offset = uimage_offset; + parts[uimage_part].size = uimage_size; + + parts[rf_part].name = ROOTFS_PART_NAME; + parts[rf_part].offset = rootfs_offset; + parts[rf_part].size = rootfs_size; + + vfree(header); + + *pparts = parts; + return nr_parts; + +err_free_header: + vfree(header); + +err_free_parts: + kfree(parts); + return ret; +} + +static bool uimage_verify_default(struct uimage_header *header) +{ + /* default sanity checks */ + if (be32_to_cpu(header->ih_magic) != IH_MAGIC) { + pr_debug("invalid uImage magic: %08x\n", + be32_to_cpu(header->ih_magic)); + return false; + } + + if (header->ih_os != IH_OS_LINUX) { + pr_debug("invalid uImage OS: %08x\n", + be32_to_cpu(header->ih_os)); + return false; + } + + if (header->ih_type != IH_TYPE_KERNEL) { + pr_debug("invalid uImage type: %08x\n", + be32_to_cpu(header->ih_type)); + return false; + } + + return true; +} + +static int +mtdsplit_uimage_parse_generic(struct mtd_info *master, + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + return __mtdsplit_parse_uimage(master, pparts, data, + uimage_verify_default); +} + +static struct mtd_part_parser uimage_generic_parser = { + .owner = THIS_MODULE, + .name = "uimage-fw", + .parse_fn = mtdsplit_uimage_parse_generic, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +#define FW_MAGIC_WNR2000V3 0x32303033 +#define FW_MAGIC_WNR2000V4 0x32303034 +#define FW_MAGIC_WNR2200 0x32323030 +#define FW_MAGIC_WNR612V2 0x32303631 +#define FW_MAGIC_WNDR3700 0x33373030 +#define FW_MAGIC_WNDR3700V2 0x33373031 + +static bool uimage_verify_wndr3700(struct uimage_header *header) +{ + uint8_t expected_type = IH_TYPE_FILESYSTEM; + switch be32_to_cpu(header->ih_magic) { + case FW_MAGIC_WNR612V2: + case FW_MAGIC_WNR2000V3: + case FW_MAGIC_WNR2200: + case FW_MAGIC_WNDR3700: + case FW_MAGIC_WNDR3700V2: + break; + case FW_MAGIC_WNR2000V4: + expected_type = IH_TYPE_KERNEL; + break; + default: + return false; + } + + if (header->ih_os != IH_OS_LINUX || + header->ih_type != expected_type) + return false; + + return true; +} + +static int +mtdsplit_uimage_parse_netgear(struct mtd_info *master, + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + return __mtdsplit_parse_uimage(master, pparts, data, + uimage_verify_wndr3700); +} + +static struct mtd_part_parser uimage_netgear_parser = { + .owner = THIS_MODULE, + .name = "netgear-fw", + .parse_fn = mtdsplit_uimage_parse_netgear, + .type = MTD_PARSER_TYPE_FIRMWARE, +}; + +static int __init mtdsplit_uimage_init(void) +{ + register_mtd_parser(&uimage_generic_parser); + register_mtd_parser(&uimage_netgear_parser); + + return 0; +} + +module_init(mtdsplit_uimage_init); diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit_lzma.c b/target/linux/generic/files/drivers/mtd/mtdsplit_lzma.c deleted file mode 100644 index 64dc7cb..0000000 --- a/target/linux/generic/files/drivers/mtd/mtdsplit_lzma.c +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2014 Gabor Juhos - * - * 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. - * - */ - -#include -#include -#include -#include -#include -#include - -#include - -#include "mtdsplit.h" - -#define LZMA_NR_PARTS 2 -#define LZMA_PROPERTIES_SIZE 5 - -struct lzma_header { - u8 props[LZMA_PROPERTIES_SIZE]; - u8 size_low[4]; - u8 size_high[4]; -}; - -static int mtdsplit_parse_lzma(struct mtd_info *master, - struct mtd_partition **pparts, - struct mtd_part_parser_data *data) -{ - struct lzma_header hdr; - size_t hdr_len, retlen; - size_t rootfs_offset; - u32 t; - struct mtd_partition *parts; - int err; - - hdr_len = sizeof(hdr); - err = mtd_read(master, 0, hdr_len, &retlen, (void *) &hdr); - if (err) - return err; - - if (retlen != hdr_len) - return -EIO; - - /* verify LZMA properties */ - if (hdr.props[0] >= (9 * 5 * 5)) - return -EINVAL; - - t = get_unaligned_le32(&hdr.props[1]); - if (!is_power_of_2(t)) - return -EINVAL; - - t = get_unaligned_le32(&hdr.size_high); - if (t) - return -EINVAL; - - err = mtd_find_rootfs_from(master, master->erasesize, - master->size, &rootfs_offset); - if (err) - return err; - - parts = kzalloc(LZMA_NR_PARTS * sizeof(*parts), GFP_KERNEL); - if (!parts) - return -ENOMEM; - - parts[0].name = KERNEL_PART_NAME; - parts[0].offset = 0; - parts[0].size = rootfs_offset; - - parts[1].name = ROOTFS_PART_NAME; - parts[1].offset = rootfs_offset; - parts[1].size = master->size - rootfs_offset; - - *pparts = parts; - return LZMA_NR_PARTS; -} - -static struct mtd_part_parser mtdsplit_lzma_parser = { - .owner = THIS_MODULE, - .name = "lzma-fw", - .parse_fn = mtdsplit_parse_lzma, - .type = MTD_PARSER_TYPE_FIRMWARE, -}; - -static int __init mtdsplit_lzma_init(void) -{ - register_mtd_parser(&mtdsplit_lzma_parser); - - return 0; -} - -subsys_initcall(mtdsplit_lzma_init); diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit_seama.c b/target/linux/generic/files/drivers/mtd/mtdsplit_seama.c deleted file mode 100644 index 6f21f8f..0000000 --- a/target/linux/generic/files/drivers/mtd/mtdsplit_seama.c +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2013 Gabor Juhos - * - * 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. - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "mtdsplit.h" - -#define SEAMA_MAGIC 0x5EA3A417 -#define SEAMA_NR_PARTS 2 -#define SEAMA_MIN_ROOTFS_OFFS 0x80000 /* 512KiB */ - -struct seama_header { - __be32 magic; /* should always be SEAMA_MAGIC. */ - __be16 reserved; /* reserved for */ - __be16 metasize; /* size of the META data */ - __be32 size; /* size of the image */ -}; - -static int mtdsplit_parse_seama(struct mtd_info *master, - struct mtd_partition **pparts, - struct mtd_part_parser_data *data) -{ - struct seama_header hdr; - size_t hdr_len, retlen, kernel_size; - size_t rootfs_offset; - struct mtd_partition *parts; - int err; - - hdr_len = sizeof(hdr); - err = mtd_read(master, 0, hdr_len, &retlen, (void *) &hdr); - if (err) - return err; - - if (retlen != hdr_len) - return -EIO; - - /* sanity checks */ - if (be32_to_cpu(hdr.magic) != SEAMA_MAGIC) - return -EINVAL; - - kernel_size = hdr_len + be32_to_cpu(hdr.size) + - be16_to_cpu(hdr.metasize); - if (kernel_size > master->size) - return -EINVAL; - - /* Find the rootfs after the kernel. */ - err = mtd_check_rootfs_magic(master, kernel_size); - if (!err) { - rootfs_offset = kernel_size; - } else { - /* - * The size in the header might cover the rootfs as well. - * Start the search from an arbitrary offset. - */ - err = mtd_find_rootfs_from(master, SEAMA_MIN_ROOTFS_OFFS, - master->size, &rootfs_offset); - if (err) - return err; - } - - parts = kzalloc(SEAMA_NR_PARTS * sizeof(*parts), GFP_KERNEL); - if (!parts) - return -ENOMEM; - - parts[0].name = KERNEL_PART_NAME; - parts[0].offset = 0; - parts[0].size = rootfs_offset; - - parts[1].name = ROOTFS_PART_NAME; - parts[1].offset = rootfs_offset; - parts[1].size = master->size - rootfs_offset; - - *pparts = parts; - return SEAMA_NR_PARTS; -} - -static struct mtd_part_parser mtdsplit_seama_parser = { - .owner = THIS_MODULE, - .name = "seama-fw", - .parse_fn = mtdsplit_parse_seama, - .type = MTD_PARSER_TYPE_FIRMWARE, -}; - -static int __init mtdsplit_seama_init(void) -{ - register_mtd_parser(&mtdsplit_seama_parser); - - return 0; -} - -subsys_initcall(mtdsplit_seama_init); diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit_squashfs.c b/target/linux/generic/files/drivers/mtd/mtdsplit_squashfs.c deleted file mode 100644 index 3d80e07..0000000 --- a/target/linux/generic/files/drivers/mtd/mtdsplit_squashfs.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2013 Felix Fietkau - * Copyright (C) 2013 Gabor Juhos - * - * 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 - -#include "mtdsplit.h" - -static int -mtdsplit_parse_squashfs(struct mtd_info *master, - struct mtd_partition **pparts, - struct mtd_part_parser_data *data) -{ - struct mtd_partition *part; - struct mtd_info *parent_mtd; - size_t part_offset; - size_t squashfs_len; - int err; - - err = mtd_get_squashfs_len(master, 0, &squashfs_len); - if (err) - return err; - - parent_mtd = mtdpart_get_master(master); - part_offset = mtdpart_get_offset(master); - - part = kzalloc(sizeof(*part), GFP_KERNEL); - if (!part) { - pr_alert("unable to allocate memory for \"%s\" partition\n", - ROOTFS_SPLIT_NAME); - return -ENOMEM; - } - - part->name = ROOTFS_SPLIT_NAME; - part->offset = mtd_roundup_to_eb(part_offset + squashfs_len, - parent_mtd) - part_offset; - part->size = master->size - part->offset; - - *pparts = part; - return 1; -} - -static struct mtd_part_parser mtdsplit_squashfs_parser = { - .owner = THIS_MODULE, - .name = "squashfs-split", - .parse_fn = mtdsplit_parse_squashfs, - .type = MTD_PARSER_TYPE_ROOTFS, -}; - -static int __init mtdsplit_squashfs_init(void) -{ - register_mtd_parser(&mtdsplit_squashfs_parser); - - return 0; -} - -subsys_initcall(mtdsplit_squashfs_init); diff --git a/target/linux/generic/files/drivers/mtd/mtdsplit_uimage.c b/target/linux/generic/files/drivers/mtd/mtdsplit_uimage.c deleted file mode 100644 index 7dad63c..0000000 --- a/target/linux/generic/files/drivers/mtd/mtdsplit_uimage.c +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Copyright (C) 2013 Gabor Juhos - * - * 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 - -#include "mtdsplit.h" - -#define IH_MAGIC 0x27051956 /* Image Magic Number */ -#define IH_NMLEN 32 /* Image Name Length */ - -#define IH_OS_LINUX 5 /* Linux */ - -#define IH_TYPE_KERNEL 2 /* OS Kernel Image */ -#define IH_TYPE_FILESYSTEM 7 /* Filesystem Image */ - -/* - * Legacy format image header, - * all data in network byte order (aka natural aka bigendian). - */ -struct uimage_header { - uint32_t ih_magic; /* Image Header Magic Number */ - uint32_t ih_hcrc; /* Image Header CRC Checksum */ - uint32_t ih_time; /* Image Creation Timestamp */ - uint32_t ih_size; /* Image Data Size */ - uint32_t ih_load; /* Data Load Address */ - uint32_t ih_ep; /* Entry Point Address */ - uint32_t ih_dcrc; /* Image Data CRC Checksum */ - uint8_t ih_os; /* Operating System */ - uint8_t ih_arch; /* CPU architecture */ - uint8_t ih_type; /* Image Type */ - uint8_t ih_comp; /* Compression Type */ - uint8_t ih_name[IH_NMLEN]; /* Image Name */ -}; - -static int -read_uimage_header(struct mtd_info *mtd, size_t offset, - struct uimage_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_uimage(struct mtd_info *master, - struct mtd_partition **pparts, - struct mtd_part_parser_data *data, - bool (*verify)(struct uimage_header *hdr)) -{ - struct mtd_partition *parts; - struct uimage_header *header; - int nr_parts; - size_t offset; - size_t uimage_offset; - size_t uimage_size = 0; - size_t rootfs_offset; - size_t rootfs_size = 0; - int uimage_part, rf_part; - int ret; - - nr_parts = 2; - parts = kzalloc(nr_parts * sizeof(*parts), GFP_KERNEL); - if (!parts) - return -ENOMEM; - - header = vmalloc(sizeof(*header)); - if (!header) { - ret = -ENOMEM; - goto err_free_parts; - } - - /* find uImage on erase block boundaries */ - for (offset = 0; offset < master->size; offset += master->erasesize) { - uimage_size = 0; - - ret = read_uimage_header(master, offset, header); - if (ret) - continue; - - if (!verify(header)) { - pr_debug("no valid uImage found in \"%s\" at offset %llx\n", - master->name, (unsigned long long) offset); - continue; - } - - uimage_size = sizeof(*header) + be32_to_cpu(header->ih_size); - if ((offset + uimage_size) > master->size) { - pr_debug("uImage exceeds MTD device \"%s\"\n", - master->name); - continue; - } - break; - } - - if (uimage_size == 0) { - pr_debug("no uImage found in \"%s\"\n", master->name); - ret = -ENODEV; - goto err_free_header; - } - - uimage_offset = offset; - - if (uimage_offset == 0) { - uimage_part = 0; - rf_part = 1; - - /* find the roots after the uImage */ - ret = mtd_find_rootfs_from(master, - uimage_offset + uimage_size, - master->size, - &rootfs_offset); - if (ret) { - pr_debug("no rootfs after uImage in \"%s\"\n", - master->name); - goto err_free_header; - } - - rootfs_size = master->size - rootfs_offset; - uimage_size = rootfs_offset - uimage_offset; - } else { - rf_part = 0; - uimage_part = 1; - - /* check rootfs presence at offset 0 */ - ret = mtd_check_rootfs_magic(master, 0); - if (ret) { - pr_debug("no rootfs before uImage in \"%s\"\n", - master->name); - goto err_free_header; - } - - rootfs_offset = 0; - rootfs_size = uimage_offset; - } - - if (rootfs_size == 0) { - pr_debug("no rootfs found in \"%s\"\n", master->name); - ret = -ENODEV; - goto err_free_header; - } - - parts[uimage_part].name = KERNEL_PART_NAME; - parts[uimage_part].offset = uimage_offset; - parts[uimage_part].size = uimage_size; - - parts[rf_part].name = ROOTFS_PART_NAME; - parts[rf_part].offset = rootfs_offset; - parts[rf_part].size = rootfs_size; - - vfree(header); - - *pparts = parts; - return nr_parts; - -err_free_header: - vfree(header); - -err_free_parts: - kfree(parts); - return ret; -} - -static bool uimage_verify_default(struct uimage_header *header) -{ - /* default sanity checks */ - if (be32_to_cpu(header->ih_magic) != IH_MAGIC) { - pr_debug("invalid uImage magic: %08x\n", - be32_to_cpu(header->ih_magic)); - return false; - } - - if (header->ih_os != IH_OS_LINUX) { - pr_debug("invalid uImage OS: %08x\n", - be32_to_cpu(header->ih_os)); - return false; - } - - if (header->ih_type != IH_TYPE_KERNEL) { - pr_debug("invalid uImage type: %08x\n", - be32_to_cpu(header->ih_type)); - return false; - } - - return true; -} - -static int -mtdsplit_uimage_parse_generic(struct mtd_info *master, - struct mtd_partition **pparts, - struct mtd_part_parser_data *data) -{ - return __mtdsplit_parse_uimage(master, pparts, data, - uimage_verify_default); -} - -static struct mtd_part_parser uimage_generic_parser = { - .owner = THIS_MODULE, - .name = "uimage-fw", - .parse_fn = mtdsplit_uimage_parse_generic, - .type = MTD_PARSER_TYPE_FIRMWARE, -}; - -#define FW_MAGIC_WNR2000V3 0x32303033 -#define FW_MAGIC_WNR2000V4 0x32303034 -#define FW_MAGIC_WNR2200 0x32323030 -#define FW_MAGIC_WNR612V2 0x32303631 -#define FW_MAGIC_WNDR3700 0x33373030 -#define FW_MAGIC_WNDR3700V2 0x33373031 - -static bool uimage_verify_wndr3700(struct uimage_header *header) -{ - uint8_t expected_type = IH_TYPE_FILESYSTEM; - switch be32_to_cpu(header->ih_magic) { - case FW_MAGIC_WNR612V2: - case FW_MAGIC_WNR2000V3: - case FW_MAGIC_WNR2200: - case FW_MAGIC_WNDR3700: - case FW_MAGIC_WNDR3700V2: - break; - case FW_MAGIC_WNR2000V4: - expected_type = IH_TYPE_KERNEL; - break; - default: - return false; - } - - if (header->ih_os != IH_OS_LINUX || - header->ih_type != expected_type) - return false; - - return true; -} - -static int -mtdsplit_uimage_parse_netgear(struct mtd_info *master, - struct mtd_partition **pparts, - struct mtd_part_parser_data *data) -{ - return __mtdsplit_parse_uimage(master, pparts, data, - uimage_verify_wndr3700); -} - -static struct mtd_part_parser uimage_netgear_parser = { - .owner = THIS_MODULE, - .name = "netgear-fw", - .parse_fn = mtdsplit_uimage_parse_netgear, - .type = MTD_PARSER_TYPE_FIRMWARE, -}; - -static int __init mtdsplit_uimage_init(void) -{ - register_mtd_parser(&uimage_generic_parser); - register_mtd_parser(&uimage_netgear_parser); - - return 0; -} - -module_init(mtdsplit_uimage_init); -- cgit v1.1