2 * Copyright (c) 2015 The Linux Foundation
3 * Copyright (C) 2014 Gabor Juhos <juhosg@openwrt.org>
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.
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.
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>
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 */
37 /* version 2 fields below */
38 uint32_t boot_cpuid_phys
; /* Which physical CPU id we're
40 /* version 3 fields below */
41 uint32_t size_dt_strings
; /* size of the strings block */
43 /* version 17 fields below */
44 uint32_t size_dt_struct
; /* size of the structure block */
48 mtdsplit_fit_parse(struct mtd_info
*mtd
, struct mtd_partition
**pparts
,
49 struct mtd_part_parser_data
*data
)
51 struct fdt_header hdr
;
52 size_t hdr_len
, retlen
;
54 size_t fit_offset
, fit_size
;
55 size_t rootfs_offset
, rootfs_size
;
56 struct mtd_partition
*parts
;
59 hdr_len
= sizeof(struct fdt_header
);
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
);
65 pr_err("read error in \"%s\" at offset 0x%llx\n",
66 mtd
->name
, (unsigned long long) offset
);
70 if (retlen
!= hdr_len
) {
71 pr_err("short read in \"%s\"\n", mtd
->name
);
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
);
82 /* We found a FIT image. Let's keep going */
87 fit_size
= be32_to_cpu(hdr
.totalsize
);
90 pr_err("FIT image in \"%s\" at offset %llx has null size\n",
91 mtd
->name
, (unsigned long long) fit_offset
);
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
);
99 pr_info("no rootfs found after FIT image in \"%s\"\n",
104 rootfs_size
= mtd
->size
- rootfs_offset
;
106 parts
= kzalloc(2 * sizeof(*parts
), GFP_KERNEL
);
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
;
114 parts
[1].name
= ROOTFS_PART_NAME
;
115 parts
[1].offset
= rootfs_offset
;
116 parts
[1].size
= rootfs_size
;
122 static struct mtd_part_parser uimage_parser
= {
123 .owner
= THIS_MODULE
,
125 .parse_fn
= mtdsplit_fit_parse
,
126 .type
= MTD_PARSER_TYPE_FIRMWARE
,
129 /**************************************************
131 **************************************************/
133 static int __init
mtdsplit_fit_init(void)
135 register_mtd_parser(&uimage_parser
);
140 module_init(mtdsplit_fit_init
);