1/* 2 * Copyright (C) 2012 John Crispin <blogic@openwrt.org> 3 * Copyright (C) 2015 Martin Blumenstingl <martin.blumenstingl@googlemail.com> 4 * 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 as published 7 * by the Free Software Foundation. 8 * 9 */ 10 11#include <linux/module.h> 12#include <linux/init.h> 13#include <linux/kernel.h> 14#include <linux/slab.h> 15#include <linux/mtd/mtd.h> 16#include <linux/mtd/partitions.h> 17#include <linux/byteorder/generic.h> 18 19#include "mtdsplit.h" 20 21#define EVA_NR_PARTS 2 22#define EVA_MAGIC 0xfeed1281 23#define EVA_FOOTER_SIZE 0x18 24#define EVA_DUMMY_SQUASHFS_SIZE 0x100 25 26struct eva_image_header { 27 uint32_t magic; 28 uint32_t size; 29}; 30 31static int mtdsplit_parse_eva(struct mtd_info *master, 32 struct mtd_partition **pparts, 33 struct mtd_part_parser_data *data) 34{ 35 struct mtd_partition *parts; 36 struct eva_image_header hdr; 37 size_t retlen; 38 unsigned long kernel_size, rootfs_offset; 39 int err; 40 41 err = mtd_read(master, 0, sizeof(hdr), &retlen, (void *) &hdr); 42 if (err) 43 return err; 44 45 if (retlen != sizeof(hdr)) 46 return -EIO; 47 48 if (le32_to_cpu(hdr.magic) != EVA_MAGIC) 49 return -EINVAL; 50 51 kernel_size = le32_to_cpu(hdr.size) + EVA_FOOTER_SIZE; 52 53 /* rootfs starts at the next 0x10000 boundary: */ 54 rootfs_offset = round_up(kernel_size, 0x10000); 55 56 /* skip the dummy EVA squashfs partition (with wrong endianness): */ 57 rootfs_offset += EVA_DUMMY_SQUASHFS_SIZE; 58 59 if (rootfs_offset >= master->size) 60 return -EINVAL; 61 62 err = mtd_check_rootfs_magic(master, rootfs_offset, NULL); 63 if (err) 64 return err; 65 66 parts = kzalloc(EVA_NR_PARTS * sizeof(*parts), GFP_KERNEL); 67 if (!parts) 68 return -ENOMEM; 69 70 parts[0].name = KERNEL_PART_NAME; 71 parts[0].offset = 0; 72 parts[0].size = kernel_size; 73 74 parts[1].name = ROOTFS_PART_NAME; 75 parts[1].offset = rootfs_offset; 76 parts[1].size = master->size - rootfs_offset; 77 78 *pparts = parts; 79 return EVA_NR_PARTS; 80} 81 82static struct mtd_part_parser mtdsplit_eva_parser = { 83 .owner = THIS_MODULE, 84 .name = "eva-fw", 85 .parse_fn = mtdsplit_parse_eva, 86 .type = MTD_PARSER_TYPE_FIRMWARE, 87}; 88 89static int __init mtdsplit_eva_init(void) 90{ 91 register_mtd_parser(&mtdsplit_eva_parser); 92 93 return 0; 94} 95 96subsys_initcall(mtdsplit_eva_init); 97