1/* 2 * Copyright (c) 2015 The Linux Foundation 3 * Copyright (C) 2014 Gabor Juhos <juhosg@openwrt.org> 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18#include <linux/module.h> 19#include <linux/mtd/mtd.h> 20#include <linux/mtd/partitions.h> 21#include <linux/types.h> 22#include <linux/byteorder/generic.h> 23#include <linux/slab.h> 24#include <linux/of_fdt.h> 25 26#include "mtdsplit.h" 27 28struct fdt_header { 29 uint32_t magic; /* magic word FDT_MAGIC */ 30 uint32_t totalsize; /* total size of DT block */ 31 uint32_t off_dt_struct; /* offset to structure */ 32 uint32_t off_dt_strings; /* offset to strings */ 33 uint32_t off_mem_rsvmap; /* offset to memory reserve map */ 34 uint32_t version; /* format version */ 35 uint32_t last_comp_version; /* last compatible version */ 36 37 /* version 2 fields below */ 38 uint32_t boot_cpuid_phys; /* Which physical CPU id we're 39 booting on */ 40 /* version 3 fields below */ 41 uint32_t size_dt_strings; /* size of the strings block */ 42 43 /* version 17 fields below */ 44 uint32_t size_dt_struct; /* size of the structure block */ 45}; 46 47static int 48mtdsplit_fit_parse(struct mtd_info *mtd, struct mtd_partition **pparts, 49 struct mtd_part_parser_data *data) 50{ 51 struct fdt_header hdr; 52 size_t hdr_len, retlen; 53 size_t offset; 54 size_t fit_offset, fit_size; 55 size_t rootfs_offset, rootfs_size; 56 struct mtd_partition *parts; 57 int ret; 58 59 hdr_len = sizeof(struct fdt_header); 60 61 /* Parse the MTD device & search for the FIT image location */ 62 for(offset = 0; offset < mtd->size; offset += mtd->erasesize) { 63 ret = mtd_read(mtd, 0, hdr_len, &retlen, (void*) &hdr); 64 if (ret) { 65 pr_err("read error in \"%s\" at offset 0x%llx\n", 66 mtd->name, (unsigned long long) offset); 67 return ret; 68 } 69 70 if (retlen != hdr_len) { 71 pr_err("short read in \"%s\"\n", mtd->name); 72 return -EIO; 73 } 74 75 /* Check the magic - see if this is a FIT image */ 76 if (be32_to_cpu(hdr.magic) != OF_DT_HEADER) { 77 pr_debug("no valid FIT image found in \"%s\" at offset %llx\n", 78 mtd->name, (unsigned long long) offset); 79 continue; 80 } 81 82 /* We found a FIT image. Let's keep going */ 83 break; 84 } 85 86 fit_offset = offset; 87 fit_size = be32_to_cpu(hdr.totalsize); 88 89 if (fit_size == 0) { 90 pr_err("FIT image in \"%s\" at offset %llx has null size\n", 91 mtd->name, (unsigned long long) fit_offset); 92 return -ENODEV; 93 } 94 95 /* Search for the rootfs partition after the FIT image */ 96 ret = mtd_find_rootfs_from(mtd, fit_offset + fit_size, mtd->size, 97 &rootfs_offset, NULL); 98 if (ret) { 99 pr_info("no rootfs found after FIT image in \"%s\"\n", 100 mtd->name); 101 return ret; 102 } 103 104 rootfs_size = mtd->size - rootfs_offset; 105 106 parts = kzalloc(2 * sizeof(*parts), GFP_KERNEL); 107 if (!parts) 108 return -ENOMEM; 109 110 parts[0].name = KERNEL_PART_NAME; 111 parts[0].offset = fit_offset; 112 parts[0].size = mtd_rounddown_to_eb(fit_size, mtd) + mtd->erasesize; 113 114 parts[1].name = ROOTFS_PART_NAME; 115 parts[1].offset = rootfs_offset; 116 parts[1].size = rootfs_size; 117 118 *pparts = parts; 119 return 2; 120} 121 122static struct mtd_part_parser uimage_parser = { 123 .owner = THIS_MODULE, 124 .name = "fit-fw", 125 .parse_fn = mtdsplit_fit_parse, 126 .type = MTD_PARSER_TYPE_FIRMWARE, 127}; 128 129/************************************************** 130 * Init 131 **************************************************/ 132 133static int __init mtdsplit_fit_init(void) 134{ 135 register_mtd_parser(&uimage_parser); 136 137 return 0; 138} 139 140module_init(mtdsplit_fit_init); 141