From 2a295753a10823a47542c779a25bbb1f52c71281 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Fri, 3 Aug 2012 10:27:13 +0200 Subject: [PATCH 19/25] owrt mtd split --- .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 1 + arch/mips/lantiq/setup.c | 7 + drivers/mtd/Kconfig | 4 + drivers/mtd/mtdpart.c | 173 +++++++++++++++++++- 4 files changed, 184 insertions(+), 1 deletions(-) diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h index 1ec8f2a..1ff93cc 100644 --- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h +++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h @@ -166,6 +166,7 @@ extern unsigned char ltq_boot_select(void); extern __iomem void *ltq_ebu_membase; extern __iomem void *ltq_cgu_membase; +extern unsigned long ltq_brn_boot; static inline int ltq_is_ase(void) { diff --git a/arch/mips/lantiq/setup.c b/arch/mips/lantiq/setup.c index 1ff6c9d..708e969 100644 --- a/arch/mips/lantiq/setup.c +++ b/arch/mips/lantiq/setup.c @@ -18,6 +18,9 @@ #include "devices.h" #include "prom.h" +/* set to 1 if the bootloader is BRN-BOOT instead of u-boot */ +unsigned long ltq_brn_boot = 0; + void __init plat_mem_setup(void) { /* assume 16M as default incase uboot fails to pass proper ramsize */ @@ -38,6 +41,10 @@ void __init plat_mem_setup(void) if (strict_strtoul(e, 0, &memsize)) pr_warn("bad memsize specified\n"); } + if (!strncmp(e, "BRN-BOOT", 8)){ + pr_info("Found BRN-BOOT instead of u-boot\n"); + ltq_brn_boot = 1; + } envp++; } memsize *= 1024 * 1024; diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 982a98b..e2f3f3e 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -31,6 +31,10 @@ config MTD_ROOTFS_SPLIT bool "Automatically split 'rootfs' partition for squashfs" default y +config MTD_UIMAGE_SPLIT + bool "Automatically split 'linux' partition into 'kernel' and 'rootfs'" + default y + config MTD_REDBOOT_PARTS tristate "RedBoot partition table parsing" ---help--- diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 855b70b..93711e2 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -867,6 +867,168 @@ static int refresh_rootfs_split(struct mtd_info *mtd) } #endif /* CONFIG_MTD_ROOTFS_SPLIT */ +#ifdef CONFIG_MTD_UIMAGE_SPLIT +static unsigned long find_uimage_size(struct mtd_info *mtd, + unsigned long offset) +{ +#define UBOOT_MAGIC 0x56190527 + unsigned long magic = 0; + unsigned long temp; + size_t len; + int ret; + + ret = mtd->read(mtd, offset, 4, &len, (void *)&magic); + if (ret || len != sizeof(magic)) + return 0; + + if (le32_to_cpu(magic) != UBOOT_MAGIC) + return 0; + + ret = mtd->read(mtd, offset + 12, 4, &len, (void *)&temp); + if (ret || len != sizeof(temp)) + return 0; + + return temp + 0x40; +} + +static unsigned long find_eva_size(struct mtd_info *mtd, + unsigned long offset) +{ +#define EVA_MAGIC 0xfeed1281 + unsigned long magic = 0; + unsigned long temp; + size_t len; + int ret; + + ret = mtd->read(mtd, offset, 4, &len, (void *)&magic); + if (ret || len != sizeof(magic)) + return 0; + + if (le32_to_cpu(magic) != EVA_MAGIC) + return 0; + + ret = mtd->read(mtd, offset + 4, 4, &len, (void *)&temp); + if (ret || len != sizeof(temp)) + return 0; + + /* add eva header size */ + temp = le32_to_cpu(temp) + 0x18; + + temp &= ~0xffff; + temp += 0x10000; + return temp; +} + +static int detect_squashfs_partition(struct mtd_info *mtd, unsigned long offset) +{ + unsigned long temp; + size_t len; + int ret; + + ret = mtd->read(mtd, offset, 4, &len, (void *)&temp); + if (ret || len != sizeof(temp)) + return 0; + + + return le32_to_cpu(temp) == SQUASHFS_MAGIC; +} + +static int detect_eva_squashfs_partition(struct mtd_info *mtd, unsigned long offset) +{ + unsigned long temp; + size_t len; + int ret; + + ret = mtd->read(mtd, offset, 4, &len, (void *)&temp); + if (ret || len != sizeof(temp)) + return 0; + + return be32_to_cpu(temp) == SQUASHFS_MAGIC; +} + +static unsigned long find_brnimage_size(struct mtd_info *mtd, + unsigned long offset) +{ + unsigned long buf[4]; + // Assume at most 2MB of kernel image + unsigned long end = offset + (2 << 20); + unsigned long ptr = offset + 0x400 - 12; + size_t len; + int ret; + + while (ptr < end) { + long size_min = ptr - 0x400 - 12 - offset; + long size_max = ptr + 12 - offset; + ret = mtd->read(mtd, ptr, 16, &len, (void *)buf); + if (ret || len != 16) + return 0; + + if (le32_to_cpu(buf[0]) < size_min || + le32_to_cpu(buf[0]) > size_max) { + ptr += 0x400; + continue; + } + + if (le32_to_cpu(buf[3]) == SQUASHFS_MAGIC) + return ptr + 12 - offset; + + ptr += 0x400; + } + + return 0; +} + +static int split_uimage(struct mtd_info *mtd, + const struct mtd_partition *part) +{ + static struct mtd_partition split_partitions[] = { + { + .name = "kernel", + .offset = 0x0, + .size = 0x0, + }, { + .name = "rootfs", + .offset = 0x0, + .size = 0x0, + }, + }; + + split_partitions[0].size = find_uimage_size(mtd, part->offset); + if (!split_partitions[0].size) { + split_partitions[0].size = find_eva_size(mtd, part->offset); + if (!split_partitions[0].size) { + split_partitions[0].size = find_brnimage_size(mtd, part->offset); + if (!split_partitions[0].size) { + printk(KERN_NOTICE "no uImage or brnImage or eva found in linux partition\n"); + return -1; + } + } + } + + if (detect_eva_squashfs_partition(mtd, + part->offset + + split_partitions[0].size)) { + split_partitions[0].size += 0x100; + pr_info("found eva dummy squashfs behind kernel\n"); + } else if (!detect_squashfs_partition(mtd, + part->offset + + split_partitions[0].size)) { + split_partitions[0].size &= ~(mtd->erasesize - 1); + split_partitions[0].size += mtd->erasesize; + } else { + pr_info("found squashfs behind kernel\n"); + } + + split_partitions[0].offset = part->offset; + split_partitions[1].offset = part->offset + split_partitions[0].size; + split_partitions[1].size = part->size - split_partitions[0].size; + + add_mtd_partitions(mtd, split_partitions, 2); + + return 0; +} +#endif + /* * This function, given a master MTD object and a partition table, creates * and registers slave MTD objects which are bound to the master according to @@ -883,7 +1045,7 @@ int add_mtd_partitions(struct mtd_info *master, struct mtd_part *slave; uint64_t cur_offset = 0; int i; -#ifdef CONFIG_MTD_ROOTFS_SPLIT +#if defined(CONFIG_MTD_ROOTFS_SPLIT) || defined(CONFIG_MTD_UIMAGE_SPLIT) int ret; #endif @@ -900,6 +1062,15 @@ int add_mtd_partitions(struct mtd_info *master, add_mtd_device(&slave->mtd); +#ifdef CONFIG_MTD_UIMAGE_SPLIT + if (!strcmp(parts[i].name, "linux")) { + ret = split_uimage(master, &parts[i]); + + if (ret) + printk(KERN_WARNING "Can't split linux partition\n"); + } +#endif + if (!strcmp(parts[i].name, "rootfs")) { #ifdef CONFIG_MTD_ROOTFS_ROOT_DEV if (ROOT_DEV == 0) { -- 1.7.9.1