1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * Copyright (C) 2021 Daniel Golle
6 * headers extracted from U-Boot mkimage sources
7 * (C) Copyright 2008 Semihalf
8 * (C) Copyright 2000-2005
9 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
11 * based on existing partition parsers
12 * Copyright (C) 1991-1998 Linus Torvalds
13 * Re-organised Feb 1998 Russell King
16 #define pr_fmt(fmt) fmt
18 #include <linux/types.h>
20 #include <linux/of_device.h>
21 #include <linux/of_fdt.h>
22 #include <linux/libfdt.h>
23 #include <linux/version.h>
27 #define FIT_IMAGES_PATH "/images"
28 #define FIT_CONFS_PATH "/configurations"
30 /* hash/signature/key node */
31 #define FIT_HASH_NODENAME "hash"
32 #define FIT_ALGO_PROP "algo"
33 #define FIT_VALUE_PROP "value"
34 #define FIT_IGNORE_PROP "uboot-ignore"
35 #define FIT_SIG_NODENAME "signature"
36 #define FIT_KEY_REQUIRED "required"
37 #define FIT_KEY_HINT "key-name-hint"
40 #define FIT_CIPHER_NODENAME "cipher"
41 #define FIT_ALGO_PROP "algo"
44 #define FIT_DATA_PROP "data"
45 #define FIT_DATA_POSITION_PROP "data-position"
46 #define FIT_DATA_OFFSET_PROP "data-offset"
47 #define FIT_DATA_SIZE_PROP "data-size"
48 #define FIT_TIMESTAMP_PROP "timestamp"
49 #define FIT_DESC_PROP "description"
50 #define FIT_ARCH_PROP "arch"
51 #define FIT_TYPE_PROP "type"
52 #define FIT_OS_PROP "os"
53 #define FIT_COMP_PROP "compression"
54 #define FIT_ENTRY_PROP "entry"
55 #define FIT_LOAD_PROP "load"
57 /* configuration node */
58 #define FIT_KERNEL_PROP "kernel"
59 #define FIT_FILESYSTEM_PROP "filesystem"
60 #define FIT_RAMDISK_PROP "ramdisk"
61 #define FIT_FDT_PROP "fdt"
62 #define FIT_LOADABLE_PROP "loadables"
63 #define FIT_DEFAULT_PROP "default"
64 #define FIT_SETUP_PROP "setup"
65 #define FIT_FPGA_PROP "fpga"
66 #define FIT_FIRMWARE_PROP "firmware"
67 #define FIT_STANDALONE_PROP "standalone"
69 #define FIT_MAX_HASH_LEN HASH_MAX_DIGEST_SIZE
71 #define MIN_FREE_SECT 16
72 #define REMAIN_VOLNAME "rootfs_data"
74 int parse_fit_partitions(struct parsed_partitions
*state
, u64 fit_start_sector
, u64 sectors
, int *slot
, int add_remain
)
76 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
77 struct block_device
*bdev
= state
->disk
->part0
;
79 struct block_device
*bdev
= state
->bdev
;
81 struct address_space
*mapping
= bdev
->bd_inode
->i_mapping
;
84 struct partition_meta_info
*info
;
85 char tmp
[sizeof(info
->volname
)];
86 u64 dsize
, dsectors
, imgmaxsect
= 0;
87 u32 size
, image_pos
, image_len
;
88 const u32
*image_offset_be
, *image_len_be
, *image_pos_be
;
89 int ret
= 1, node
, images
, config
;
90 const char *image_name
, *image_type
, *image_description
, *config_default
,
91 *config_description
, *config_loadables
;
92 int image_name_len
, image_type_len
, image_description_len
, config_default_len
,
93 config_description_len
, config_loadables_len
;
94 sector_t start_sect
, nr_sects
;
96 struct device_node
*np
= NULL
;
99 const char *select_rootfs
= NULL
;
101 int loadables_rem_len
, loadable_len
;
103 if (fit_start_sector
% (1<<(PAGE_SHIFT
- SECTOR_SHIFT
)))
106 page
= read_mapping_page(mapping
, fit_start_sector
>> (PAGE_SHIFT
- SECTOR_SHIFT
), NULL
);
113 init_fit
= page_address(page
);
120 if (fdt_check_header(init_fit
)) {
125 dsectors
= get_capacity(bdev
->bd_disk
);
127 dsectors
= (dsectors
>sectors
)?sectors
:dsectors
;
129 dsize
= dsectors
<< SECTOR_SHIFT
;
130 size
= fdt_totalsize(init_fit
);
132 /* silently skip non-external-data legacy FIT images */
133 if (size
> PAGE_SIZE
) {
139 state
->access_beyond_eod
= 1;
144 fit
= kmemdup(init_fit
, size
, GFP_KERNEL
);
149 np
= of_find_node_by_path("/chosen");
151 bootconf
= of_get_property(np
, "u-boot,bootconf", NULL
);
155 config
= fdt_path_offset(fit
, FIT_CONFS_PATH
);
157 printk(KERN_ERR
"FIT: Cannot find %s node: %d\n", FIT_CONFS_PATH
, images
);
162 config_default
= fdt_getprop(fit
, config
, FIT_DEFAULT_PROP
, &config_default_len
);
164 if (!config_default
&& !bootconf
) {
165 printk(KERN_ERR
"FIT: Cannot find default configuration\n");
170 node
= fdt_subnode_offset(fit
, config
, bootconf
?:config_default
);
172 printk(KERN_ERR
"FIT: Cannot find %s node: %d\n", bootconf
?:config_default
, node
);
177 config_description
= fdt_getprop(fit
, node
, FIT_DESC_PROP
, &config_description_len
);
178 config_loadables
= fdt_getprop(fit
, node
, FIT_LOADABLE_PROP
, &config_loadables_len
);
180 printk(KERN_DEBUG
"FIT: %s configuration: \"%s\"%s%s%s\n",
181 bootconf
?"Selected":"Default", bootconf
?:config_default
,
182 config_description
?" (":"", config_description
?:"", config_description
?")":"");
184 if (!config_loadables
|| !config_loadables_len
) {
185 printk(KERN_ERR
"FIT: No loadables configured in \"%s\"\n", bootconf
?:config_default
);
190 images
= fdt_path_offset(fit
, FIT_IMAGES_PATH
);
192 printk(KERN_ERR
"FIT: Cannot find %s node: %d\n", FIT_IMAGES_PATH
, images
);
197 fdt_for_each_subnode(node
, fit
, images
) {
198 image_name
= fdt_get_name(fit
, node
, &image_name_len
);
199 image_type
= fdt_getprop(fit
, node
, FIT_TYPE_PROP
, &image_type_len
);
200 image_offset_be
= fdt_getprop(fit
, node
, FIT_DATA_OFFSET_PROP
, NULL
);
201 image_pos_be
= fdt_getprop(fit
, node
, FIT_DATA_POSITION_PROP
, NULL
);
202 image_len_be
= fdt_getprop(fit
, node
, FIT_DATA_SIZE_PROP
, NULL
);
203 if (!image_name
|| !image_type
|| !image_len_be
)
206 image_len
= be32_to_cpu(*image_len_be
);
211 image_pos
= be32_to_cpu(*image_offset_be
) + size
;
212 else if (image_pos_be
)
213 image_pos
= be32_to_cpu(*image_pos_be
);
217 image_description
= fdt_getprop(fit
, node
, FIT_DESC_PROP
, &image_description_len
);
219 printk(KERN_DEBUG
"FIT: %16s sub-image 0x%08x..0x%08x \"%s\" %s%s%s\n",
220 image_type
, image_pos
, image_pos
+ image_len
- 1, image_name
,
221 image_description
?"(":"", image_description
?:"", image_description
?") ":"");
223 if (strcmp(image_type
, FIT_FILESYSTEM_PROP
))
226 /* check if sub-image is part of configured loadables */
228 loadable
= config_loadables
;
229 loadables_rem_len
= config_loadables_len
;
230 while (loadables_rem_len
> 1) {
231 loadable_len
= strnlen(loadable
, loadables_rem_len
- 1) + 1;
232 loadables_rem_len
-= loadable_len
;
233 if (!strncmp(image_name
, loadable
, loadable_len
)) {
237 loadable
+= loadable_len
;
242 if (image_pos
& ((1 << PAGE_SHIFT
)-1)) {
243 printk(KERN_ERR
"FIT: image %s start not aligned to page boundaries, skipping\n", image_name
);
247 if (image_len
& ((1 << PAGE_SHIFT
)-1)) {
248 printk(KERN_ERR
"FIT: sub-image %s end not aligned to page boundaries, skipping\n", image_name
);
252 start_sect
= image_pos
>> SECTOR_SHIFT
;
253 nr_sects
= image_len
>> SECTOR_SHIFT
;
254 imgmaxsect
= (imgmaxsect
< (start_sect
+ nr_sects
))?(start_sect
+ nr_sects
):imgmaxsect
;
256 if (start_sect
+ nr_sects
> dsectors
) {
257 state
->access_beyond_eod
= 1;
261 put_partition(state
, ++(*slot
), fit_start_sector
+ start_sect
, nr_sects
);
262 state
->parts
[*slot
].flags
= ADDPART_FLAG_READONLY
;
263 state
->parts
[*slot
].has_info
= true;
264 info
= &state
->parts
[*slot
].info
;
266 label_min
= min_t(int, sizeof(info
->volname
) - 1, image_name_len
);
267 strncpy(info
->volname
, image_name
, label_min
);
268 info
->volname
[label_min
] = '\0';
270 snprintf(tmp
, sizeof(tmp
), "(%s)", info
->volname
);
271 strlcat(state
->pp_buf
, tmp
, PAGE_SIZE
);
273 /* Mark first loadable listed to be mounted as rootfs */
274 if (!strcmp(image_name
, config_loadables
)) {
275 select_rootfs
= image_name
;
276 state
->parts
[*slot
].flags
|= ADDPART_FLAG_ROOTDEV
;
281 printk(KERN_DEBUG
"FIT: selecting configured loadable \"%s\" to be root filesystem\n", select_rootfs
);
283 if (add_remain
&& (imgmaxsect
+ MIN_FREE_SECT
) < dsectors
) {
284 put_partition(state
, ++(*slot
), fit_start_sector
+ imgmaxsect
, dsectors
- imgmaxsect
);
285 state
->parts
[*slot
].flags
= 0;
286 info
= &state
->parts
[*slot
].info
;
287 strcpy(info
->volname
, REMAIN_VOLNAME
);
288 snprintf(tmp
, sizeof(tmp
), "(%s)", REMAIN_VOLNAME
);
289 strlcat(state
->pp_buf
, tmp
, PAGE_SIZE
);
296 int fit_partition(struct parsed_partitions
*state
) {
298 return parse_fit_partitions(state
, 0, 0, &slot
, 0);