91b25e0581e7e071205d8375f5a2f88bcb275c9c
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 struct block_device
*bdev
= state
->disk
->part0
;
77 struct address_space
*mapping
= bdev
->bd_inode
->i_mapping
;
80 struct partition_meta_info
*info
;
81 char tmp
[sizeof(info
->volname
)];
82 u64 dsize
, dsectors
, imgmaxsect
= 0;
83 u32 size
, image_pos
, image_len
;
84 const u32
*image_offset_be
, *image_len_be
, *image_pos_be
;
85 int ret
= 1, node
, images
, config
;
86 const char *image_name
, *image_type
, *image_description
, *config_default
,
87 *config_description
, *config_loadables
, *bootconf_c
;
88 int image_name_len
, image_type_len
, image_description_len
, config_default_len
,
89 config_description_len
, config_loadables_len
, bootconf_len
;
90 sector_t start_sect
, nr_sects
;
92 struct device_node
*np
= NULL
;
93 char *bootconf
= NULL
, *bootconf_term
;
95 const char *select_rootfs
= NULL
;
97 int loadables_rem_len
, loadable_len
;
99 if (fit_start_sector
% (1<<(PAGE_SHIFT
- SECTOR_SHIFT
)))
102 page
= read_mapping_page(mapping
, fit_start_sector
>> (PAGE_SHIFT
- SECTOR_SHIFT
), NULL
);
109 init_fit
= page_address(page
);
116 if (fdt_check_header(init_fit
)) {
121 dsectors
= get_capacity(bdev
->bd_disk
);
123 dsectors
= (dsectors
>sectors
)?sectors
:dsectors
;
125 dsize
= dsectors
<< SECTOR_SHIFT
;
126 size
= fdt_totalsize(init_fit
);
128 /* silently skip non-external-data legacy FIT images */
129 if (size
> PAGE_SIZE
) {
135 state
->access_beyond_eod
= 1;
140 fit
= kmemdup(init_fit
, size
, GFP_KERNEL
);
145 np
= of_find_node_by_path("/chosen");
147 bootconf_c
= of_get_property(np
, "u-boot,bootconf", &bootconf_len
);
148 if (bootconf_c
&& bootconf_len
)
149 bootconf
= kmemdup_nul(bootconf_c
, bootconf_len
, GFP_KERNEL
);
153 bootconf_term
= strchr(bootconf
, '#');
155 *bootconf_term
= '\0';
158 config
= fdt_path_offset(fit
, FIT_CONFS_PATH
);
160 printk(KERN_ERR
"FIT: Cannot find %s node: %d\n", FIT_CONFS_PATH
, images
);
165 config_default
= fdt_getprop(fit
, config
, FIT_DEFAULT_PROP
, &config_default_len
);
167 if (!config_default
&& !bootconf
) {
168 printk(KERN_ERR
"FIT: Cannot find default configuration\n");
173 node
= fdt_subnode_offset(fit
, config
, bootconf
?:config_default
);
175 printk(KERN_ERR
"FIT: Cannot find %s node: %d\n", bootconf
?:config_default
, node
);
180 config_description
= fdt_getprop(fit
, node
, FIT_DESC_PROP
, &config_description_len
);
181 config_loadables
= fdt_getprop(fit
, node
, FIT_LOADABLE_PROP
, &config_loadables_len
);
183 printk(KERN_DEBUG
"FIT: %s configuration: \"%s\"%s%s%s\n",
184 bootconf
?"Selected":"Default", bootconf
?:config_default
,
185 config_description
?" (":"", config_description
?:"", config_description
?")":"");
187 if (!config_loadables
|| !config_loadables_len
) {
188 printk(KERN_ERR
"FIT: No loadables configured in \"%s\"\n", bootconf
?:config_default
);
193 images
= fdt_path_offset(fit
, FIT_IMAGES_PATH
);
195 printk(KERN_ERR
"FIT: Cannot find %s node: %d\n", FIT_IMAGES_PATH
, images
);
200 fdt_for_each_subnode(node
, fit
, images
) {
201 image_name
= fdt_get_name(fit
, node
, &image_name_len
);
202 image_type
= fdt_getprop(fit
, node
, FIT_TYPE_PROP
, &image_type_len
);
203 image_offset_be
= fdt_getprop(fit
, node
, FIT_DATA_OFFSET_PROP
, NULL
);
204 image_pos_be
= fdt_getprop(fit
, node
, FIT_DATA_POSITION_PROP
, NULL
);
205 image_len_be
= fdt_getprop(fit
, node
, FIT_DATA_SIZE_PROP
, NULL
);
206 if (!image_name
|| !image_type
|| !image_len_be
)
209 image_len
= be32_to_cpu(*image_len_be
);
214 image_pos
= be32_to_cpu(*image_offset_be
) + size
;
215 else if (image_pos_be
)
216 image_pos
= be32_to_cpu(*image_pos_be
);
220 image_description
= fdt_getprop(fit
, node
, FIT_DESC_PROP
, &image_description_len
);
222 printk(KERN_DEBUG
"FIT: %16s sub-image 0x%08x..0x%08x \"%s\" %s%s%s\n",
223 image_type
, image_pos
, image_pos
+ image_len
- 1, image_name
,
224 image_description
?"(":"", image_description
?:"", image_description
?") ":"");
226 if (strcmp(image_type
, FIT_FILESYSTEM_PROP
))
229 /* check if sub-image is part of configured loadables */
231 loadable
= config_loadables
;
232 loadables_rem_len
= config_loadables_len
;
233 while (loadables_rem_len
> 1) {
234 loadable_len
= strnlen(loadable
, loadables_rem_len
- 1) + 1;
235 loadables_rem_len
-= loadable_len
;
236 if (!strncmp(image_name
, loadable
, loadable_len
)) {
240 loadable
+= loadable_len
;
245 if (image_pos
& ((1 << PAGE_SHIFT
)-1)) {
246 printk(KERN_ERR
"FIT: image %s start not aligned to page boundaries, skipping\n", image_name
);
250 if (image_len
& ((1 << PAGE_SHIFT
)-1)) {
251 printk(KERN_ERR
"FIT: sub-image %s end not aligned to page boundaries, skipping\n", image_name
);
255 start_sect
= image_pos
>> SECTOR_SHIFT
;
256 nr_sects
= image_len
>> SECTOR_SHIFT
;
257 imgmaxsect
= (imgmaxsect
< (start_sect
+ nr_sects
))?(start_sect
+ nr_sects
):imgmaxsect
;
259 if (start_sect
+ nr_sects
> dsectors
) {
260 state
->access_beyond_eod
= 1;
264 put_partition(state
, ++(*slot
), fit_start_sector
+ start_sect
, nr_sects
);
265 state
->parts
[*slot
].flags
= ADDPART_FLAG_READONLY
;
266 state
->parts
[*slot
].has_info
= true;
267 info
= &state
->parts
[*slot
].info
;
269 label_min
= min_t(int, sizeof(info
->volname
) - 1, image_name_len
);
270 strncpy(info
->volname
, image_name
, label_min
);
271 info
->volname
[label_min
] = '\0';
273 snprintf(tmp
, sizeof(tmp
), "(%s)", info
->volname
);
274 strlcat(state
->pp_buf
, tmp
, PAGE_SIZE
);
276 /* Mark first loadable listed to be mounted as rootfs */
277 if (!strcmp(image_name
, config_loadables
)) {
278 select_rootfs
= image_name
;
279 state
->parts
[*slot
].flags
|= ADDPART_FLAG_ROOTDEV
;
284 printk(KERN_DEBUG
"FIT: selecting configured loadable \"%s\" to be root filesystem\n", select_rootfs
);
286 if (add_remain
&& (imgmaxsect
+ MIN_FREE_SECT
) < dsectors
) {
287 put_partition(state
, ++(*slot
), fit_start_sector
+ imgmaxsect
, dsectors
- imgmaxsect
);
288 state
->parts
[*slot
].flags
= 0;
289 info
= &state
->parts
[*slot
].info
;
290 strcpy(info
->volname
, REMAIN_VOLNAME
);
291 snprintf(tmp
, sizeof(tmp
), "(%s)", REMAIN_VOLNAME
);
292 strlcat(state
->pp_buf
, tmp
, PAGE_SIZE
);
300 int fit_partition(struct parsed_partitions
*state
) {
302 return parse_fit_partitions(state
, 0, 0, &slot
, 0);