--- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -63,6 +63,10 @@ depends on MTD_PARTITIONS 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" depends on MTD_PARTITIONS --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -724,6 +724,82 @@ } #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 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 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) { + printk(KERN_NOTICE "no uImage found in linux partition\n"); + return -1; + } + + if (!detect_squashfs_partition(mtd, + part->offset + + split_partitions[0].size)) { + split_partitions[0].size &= ~(mtd->erasesize - 1); + split_partitions[0].size += mtd->erasesize; + } + + 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 @@ -748,6 +824,17 @@ if (!slave) return -ENOMEM; +#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) {