123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192 |
- --- a/arch/mips/lantiq/xway/Makefile
- +++ b/arch/mips/lantiq/xway/Makefile
- @@ -1,6 +1,6 @@
- obj-y := prom.o sysctrl.o clk.o reset.o dma.o timer.o dcdc.o
-
- -obj-y += vmmc.o tffs.o
- +obj-y += vmmc.o tffs.o mtd_split.o
-
- obj-y += eth_mac.o
- obj-$(CONFIG_PCI) += ath_eep.o rt_eep.o pci-ath-fixup.o
- --- /dev/null
- +++ b/arch/mips/lantiq/xway/mtd_split.c
- @@ -0,0 +1,129 @@
- +#include <linux/magic.h>
- +#include <linux/root_dev.h>
- +#include <linux/mtd/mtd.h>
- +#include <linux/mtd/partitions.h>
- +
- +#define ROOTFS_SPLIT_NAME "rootfs_data"
- +
- +struct squashfs_super_block {
- + __le32 s_magic;
- + __le32 pad0[9];
- + __le64 bytes_used;
- +};
- +
- +static void split_brnimage_kernel(struct mtd_info *master, const char *name,
- + int offset, int size)
- +{
- + unsigned long buf[4];
- + // Assume at most 2MB of kernel image
- + unsigned long end = offset + (2 << 20);
- + unsigned long part_size = offset + 0x400 - 12;
- + size_t len;
- + int ret;
- +
- + if (strcmp(name, "firmware") != 0)
- + return;
- + while (part_size < end) {
- + long size_min = part_size - 0x400 - 12 - offset;
- + long size_max = part_size + 12 - offset;
- + ret = mtd_read(master, part_size, 16, &len, (void *)buf);
- + if (ret || len != 16)
- + return;
- +
- + if (le32_to_cpu(buf[0]) < size_min ||
- + le32_to_cpu(buf[0]) > size_max) {
- + part_size += 0x400;
- + continue;
- + }
- +
- + if (le32_to_cpu(buf[3]) == SQUASHFS_MAGIC) {
- + part_size += 12 - offset;
- + __mtd_add_partition(master, "rootfs", offset + part_size,
- + size - part_size, false);
- + return;
- + }
- + part_size += 0x400;
- + }
- +}
- +
- +static void split_eva_kernel(struct mtd_info *master, const char *name,
- + int offset, int size)
- +{
- +#define EVA_MAGIC 0xfeed1281
- + unsigned long magic = 0;
- + unsigned long part_size = 0, p;
- + size_t len;
- + int ret;
- +
- + if (strcmp(name, CONFIG_MTD_SPLIT_FIRMWARE_NAME) != 0)
- + return;
- +
- + ret = mtd_read(master, offset, 4, &len, (void *)&magic);
- + if (ret || len != sizeof(magic))
- + return;
- +
- + if (le32_to_cpu(magic) != EVA_MAGIC)
- + return;
- +
- + ret = mtd_read(master, offset + 4, 4, &len, (void *)&part_size);
- + if (ret || len != sizeof(part_size))
- + return;
- +
- + p = part_size = le32_to_cpu(part_size) + 0x18;
- + p &= ~0xffff;
- + p += 0x10000;
- +
- + ret = mtd_read(master, offset + p, 4, &len, (void *)&magic);
- + if (ret || len != sizeof(magic))
- + return;
- +
- + if (magic == SQUASHFS_MAGIC)
- + part_size = p + 0x100;
- + else
- + part_size = mtd_pad_erasesize(master, offset, len);
- +
- + if (part_size + master->erasesize > size)
- + return;
- +
- + __mtd_add_partition(master, "rootfs", offset + part_size,
- + size - part_size, false);
- +}
- +
- +static void split_tplink_kernel(struct mtd_info *master, const char *name,
- + int offset, int size)
- +{
- +#define TPLINK_MAGIC 0x00000002
- + unsigned long magic = 0;
- + unsigned long part_size = 0;
- + size_t len;
- + int ret;
- +
- + if (strcmp(name, CONFIG_MTD_SPLIT_FIRMWARE_NAME) != 0)
- + return;
- +
- + ret = mtd_read(master, offset, 4, &len, (void *)&magic);
- + if (ret || len != sizeof(magic))
- + return;
- +
- + if (le32_to_cpu(magic) != TPLINK_MAGIC)
- + return;
- +
- + ret = mtd_read(master, offset + 0x78, 4, &len, (void *)&part_size);
- + if (ret || len != sizeof(part_size))
- + return;
- +
- + part_size = be32_to_cpu(part_size) + 0x200;
- + if (part_size + master->erasesize > size)
- + return;
- +
- + __mtd_add_partition(master, "rootfs", offset + part_size,
- + size - part_size, false);
- +}
- +
- +void arch_split_mtd_part(struct mtd_info *master, const char *name,
- + int offset, int size)
- +{
- + split_tplink_kernel(master, name, offset, size);
- + split_eva_kernel(master, name, offset, size);
- + split_brnimage_kernel(master, name, offset, size);
- +}
- --- a/include/linux/mtd/partitions.h
- +++ b/include/linux/mtd/partitions.h
- @@ -89,12 +89,17 @@ extern void deregister_mtd_parser(struct
- int mtd_is_partition(const struct mtd_info *mtd);
- int mtd_add_partition(struct mtd_info *master, const char *name,
- long long offset, long long length);
- +int __mtd_add_partition(struct mtd_info *master, const char *name,
- + long long offset, long long length, bool dup_check);
- +
- int mtd_del_partition(struct mtd_info *master, int partno);
- struct mtd_info *mtdpart_get_master(const struct mtd_info *mtd);
- uint64_t mtdpart_get_offset(const struct mtd_info *mtd);
- uint64_t mtd_get_device_size(const struct mtd_info *mtd);
- -extern void __weak arch_split_mtd_part(struct mtd_info *master,
- - const char *name, int offset, int size);
- +void __weak arch_split_mtd_part(struct mtd_info *master,
- + const char *name, int offset, int size);
- +unsigned long
- +mtd_pad_erasesize(struct mtd_info *mtd, int offset, int len);
-
- int parse_mtd_partitions_by_type(struct mtd_info *master,
- enum mtd_parser_type type,
- --- a/drivers/mtd/mtdpart.c
- +++ b/drivers/mtd/mtdpart.c
- @@ -627,7 +627,7 @@ out_register:
- }
-
-
- -static int
- +int
- __mtd_add_partition(struct mtd_info *master, const char *name,
- long long offset, long long length, bool dup_check)
- {
- @@ -748,7 +748,7 @@ run_parsers_by_type(struct mtd_part *sla
- return nr_parts;
- }
-
- -static inline unsigned long
- +unsigned long
- mtd_pad_erasesize(struct mtd_info *mtd, int offset, int len)
- {
- unsigned long mask = mtd->erasesize - 1;
- @@ -818,7 +818,6 @@ static void split_uimage(struct mtd_info
- return;
-
- len = be32_to_cpu(hdr.size) + 0x40;
- - len = mtd_pad_erasesize(master, part->offset, len);
- if (len + master->erasesize > part->mtd.size)
- return;
-
|