1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*======================================================================
4 drivers/mtd/afs.c: ARM Flash Layout/Partitioning
6 Copyright © 2000 ARM Limited
7 Copyright (C) 2019 Linus Walleij
10 This is access code for flashes using ARM's flash partitioning
13 ======================================================================*/
15 #include <linux/module.h>
16 #include <linux/types.h>
17 #include <linux/kernel.h>
18 #include <linux/slab.h>
19 #include <linux/string.h>
20 #include <linux/init.h>
22 #include <linux/mtd/mtd.h>
23 #include <linux/mtd/map.h>
24 #include <linux/mtd/partitions.h>
26 #define AFSV1_FOOTER_MAGIC 0xA0FFFF9F
27 #define AFSV2_FOOTER_MAGIC1 0x464C5348 /* "FLSH" */
28 #define AFSV2_FOOTER_MAGIC2 0x464F4F54 /* "FOOT" */
31 u32 image_info_base
; /* Address of first word of ImageFooter */
32 u32 image_start
; /* Start of area reserved by this footer */
33 u32 signature
; /* 'Magic' number proves it's a footer */
34 u32 type
; /* Area type: ARM Image, SIB, customer */
35 u32 checksum
; /* Just this structure */
38 struct image_info_v1
{
39 u32 bootFlags
; /* Boot flags, compression etc. */
40 u32 imageNumber
; /* Unique number, selects for boot etc. */
41 u32 loadAddress
; /* Address program should be loaded to */
42 u32 length
; /* Actual size of image */
43 u32 address
; /* Image is executed from here */
44 char name
[16]; /* Null terminated */
45 u32 headerBase
; /* Flash Address of any stripped header */
46 u32 header_length
; /* Length of header in memory */
47 u32 headerType
; /* AIF, RLF, s-record etc. */
48 u32 checksum
; /* Image checksum (inc. this struct) */
51 static u32
word_sum(void *words
, int num
)
62 static u32
word_sum_v2(u32
*p
, u32 num
)
67 for (i
= 0; i
< num
; i
++) {
78 static bool afs_is_v1(struct mtd_info
*mtd
, u_int off
)
80 /* The magic is 12 bytes from the end of the erase block */
81 u_int ptr
= off
+ mtd
->erasesize
- 12;
86 ret
= mtd_read(mtd
, ptr
, 4, &sz
, (u_char
*)&magic
);
88 printk(KERN_ERR
"AFS: mtd read failed at 0x%x: %d\n",
92 if (ret
>= 0 && sz
!= 4)
95 return (magic
== AFSV1_FOOTER_MAGIC
);
98 static bool afs_is_v2(struct mtd_info
*mtd
, u_int off
)
100 /* The magic is the 8 last bytes of the erase block */
101 u_int ptr
= off
+ mtd
->erasesize
- 8;
106 ret
= mtd_read(mtd
, ptr
, 8, &sz
, (u_char
*)foot
);
108 printk(KERN_ERR
"AFS: mtd read failed at 0x%x: %d\n",
112 if (ret
>= 0 && sz
!= 8)
115 return (foot
[0] == AFSV2_FOOTER_MAGIC1
&&
116 foot
[1] == AFSV2_FOOTER_MAGIC2
);
119 static int afs_parse_v1_partition(struct mtd_info
*mtd
,
120 u_int off
, struct mtd_partition
*part
)
123 struct image_info_v1 iis
;
126 * Static checks cannot see that we bail out if we have an error
127 * reading the footer.
137 * This is the address mask; we use this to mask off out of
138 * range address bits.
140 mask
= mtd
->size
- 1;
142 ptr
= off
+ mtd
->erasesize
- sizeof(fs
);
143 ret
= mtd_read(mtd
, ptr
, sizeof(fs
), &sz
, (u_char
*)&fs
);
144 if (ret
>= 0 && sz
!= sizeof(fs
))
147 printk(KERN_ERR
"AFS: mtd read failed at 0x%x: %d\n",
152 * Check the checksum.
154 if (word_sum(&fs
, sizeof(fs
) / sizeof(u32
)) != 0xffffffff)
158 * Hide the SIB (System Information Block)
163 iis_ptr
= fs
.image_info_base
& mask
;
164 img_ptr
= fs
.image_start
& mask
;
167 * Check the image info base. This can not
168 * be located after the footer structure.
174 * Check the start of this image. The image
175 * data can not be located after this block.
180 /* Read the image info block */
181 memset(&iis
, 0, sizeof(iis
));
182 ret
= mtd_read(mtd
, iis_ptr
, sizeof(iis
), &sz
, (u_char
*)&iis
);
184 printk(KERN_ERR
"AFS: mtd read failed at 0x%x: %d\n",
189 if (sz
!= sizeof(iis
))
193 * Validate the name - it must be NUL terminated.
195 for (i
= 0; i
< sizeof(iis
.name
); i
++)
196 if (iis
.name
[i
] == '\0')
198 if (i
> sizeof(iis
.name
))
201 part
->name
= kstrdup(iis
.name
, GFP_KERNEL
);
205 part
->size
= (iis
.length
+ mtd
->erasesize
- 1) & ~(mtd
->erasesize
- 1);
206 part
->offset
= img_ptr
;
207 part
->mask_flags
= 0;
209 printk(" mtd: at 0x%08x, %5lluKiB, %8u, %s\n",
210 img_ptr
, part
->size
/ 1024,
211 iis
.imageNumber
, part
->name
);
216 static int afs_parse_v2_partition(struct mtd_info
*mtd
,
217 u_int off
, struct mtd_partition
*part
)
235 pr_debug("Parsing v2 partition @%08x-%08x\n",
236 off
, off
+ mtd
->erasesize
);
238 /* First read the footer */
239 ptr
= off
+ mtd
->erasesize
- sizeof(footer
);
240 ret
= mtd_read(mtd
, ptr
, sizeof(footer
), &sz
, (u_char
*)footer
);
241 if ((ret
< 0) || (ret
>= 0 && sz
!= sizeof(footer
))) {
242 pr_err("AFS: mtd read failed at 0x%x: %d\n",
246 name
= (char *) &footer
[0];
248 ptr
= off
+ mtd
->erasesize
- sizeof(footer
) - footer
[8];
250 pr_debug("found image \"%s\", version %08x, info @%08x\n",
253 /* Then read the image information */
254 ret
= mtd_read(mtd
, ptr
, sizeof(imginfo
), &sz
, (u_char
*)imginfo
);
255 if ((ret
< 0) || (ret
>= 0 && sz
!= sizeof(imginfo
))) {
256 pr_err("AFS: mtd read failed at 0x%x: %d\n",
261 /* 32bit platforms have 4 bytes padding */
262 crc
= word_sum_v2(&imginfo
[1], 34);
264 pr_debug("Padding 1 word (4 bytes)\n");
267 /* 64bit platforms have 8 bytes padding */
268 crc
= word_sum_v2(&imginfo
[2], 34);
270 pr_debug("Padding 2 words (8 bytes)\n");
275 pr_err("AFS: bad checksum on v2 image info: %08x\n", crc
);
278 entrypoint
= imginfo
[pad
];
279 attributes
= imginfo
[pad
+1];
280 region_count
= imginfo
[pad
+2];
281 block_start
= imginfo
[20];
282 block_end
= imginfo
[21];
284 pr_debug("image entry=%08x, attr=%08x, regions=%08x, "
285 "bs=%08x, be=%08x\n",
286 entrypoint
, attributes
, region_count
,
287 block_start
, block_end
);
289 for (i
= 0; i
< region_count
; i
++) {
290 u32 region_load_addr
= imginfo
[pad
+ 3 + i
*4];
291 u32 region_size
= imginfo
[pad
+ 4 + i
*4];
292 u32 region_offset
= imginfo
[pad
+ 5 + i
*4];
296 pr_debug(" region %d: address: %08x, size: %08x, "
303 region_start
= off
+ region_offset
;
304 region_end
= region_start
+ region_size
;
305 /* Align partition to end of erase block */
306 region_end
+= (mtd
->erasesize
- 1);
307 region_end
&= ~(mtd
->erasesize
-1);
308 pr_debug(" partition start = %08x, partition end = %08x\n",
309 region_start
, region_end
);
311 /* Create one partition per region */
312 part
->name
= kstrdup(name
, GFP_KERNEL
);
315 part
->offset
= region_start
;
316 part
->size
= region_end
- region_start
;
317 part
->mask_flags
= 0;
323 static int parse_afs_partitions(struct mtd_info
*mtd
,
324 const struct mtd_partition
**pparts
,
325 struct mtd_part_parser_data
*data
)
327 struct mtd_partition
*parts
;
332 /* Count the partitions by looping over all erase blocks */
333 for (i
= off
= sz
= 0; off
< mtd
->size
; off
+= mtd
->erasesize
) {
334 if (afs_is_v1(mtd
, off
)) {
335 sz
+= sizeof(struct mtd_partition
);
338 if (afs_is_v2(mtd
, off
)) {
339 sz
+= sizeof(struct mtd_partition
);
347 parts
= kzalloc(sz
, GFP_KERNEL
);
352 * Identify the partitions
354 for (i
= off
= 0; off
< mtd
->size
; off
+= mtd
->erasesize
) {
355 if (afs_is_v1(mtd
, off
)) {
356 ret
= afs_parse_v1_partition(mtd
, off
, &parts
[i
]);
361 if (afs_is_v2(mtd
, off
)) {
362 ret
= afs_parse_v2_partition(mtd
, off
, &parts
[i
]);
374 kfree(parts
[i
].name
);
380 static const struct of_device_id mtd_parser_afs_of_match_table
[] = {
381 { .compatible
= "arm,arm-firmware-suite" },
384 MODULE_DEVICE_TABLE(of
, mtd_parser_afs_of_match_table
);
386 static struct mtd_part_parser afs_parser
= {
387 .parse_fn
= parse_afs_partitions
,
389 .of_match_table
= mtd_parser_afs_of_match_table
,
391 module_mtd_part_parser(afs_parser
);
393 MODULE_AUTHOR("ARM Ltd");
394 MODULE_DESCRIPTION("ARM Firmware Suite partition parser");
395 MODULE_LICENSE("GPL");