1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /*====================================================================== 3 4 drivers/mtd/afs.c: ARM Flash Layout/Partitioning 5 6 Copyright © 2000 ARM Limited 7 Copyright (C) 2019 Linus Walleij 8 9 10 This is access code for flashes using ARM's flash partitioning 11 standards. 12 13 ======================================================================*/ 14 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> 21 22 #include <linux/mtd/mtd.h> 23 #include <linux/mtd/map.h> 24 #include <linux/mtd/partitions.h> 25 26 #define AFSV1_FOOTER_MAGIC 0xA0FFFF9F 27 #define AFSV2_FOOTER_MAGIC1 0x464C5348 /* "FLSH" */ 28 #define AFSV2_FOOTER_MAGIC2 0x464F4F54 /* "FOOT" */ 29 30 struct footer_v1 { 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 */ 36 }; 37 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) */ 49 }; 50 51 static u32 word_sum(void *words, int num) 52 { 53 u32 *p = words; 54 u32 sum = 0; 55 56 while (num--) 57 sum += *p++; 58 59 return sum; 60 } 61 62 static u32 word_sum_v2(u32 *p, u32 num) 63 { 64 u32 sum = 0; 65 int i; 66 67 for (i = 0; i < num; i++) { 68 u32 val; 69 70 val = p[i]; 71 if (val > ~sum) 72 sum++; 73 sum += val; 74 } 75 return ~sum; 76 } 77 78 static bool afs_is_v1(struct mtd_info *mtd, u_int off) 79 { 80 /* The magic is 12 bytes from the end of the erase block */ 81 u_int ptr = off + mtd->erasesize - 12; 82 u32 magic; 83 size_t sz; 84 int ret; 85 86 ret = mtd_read(mtd, ptr, 4, &sz, (u_char *)&magic); 87 if (ret < 0) { 88 printk(KERN_ERR "AFS: mtd read failed at 0x%x: %d\n", 89 ptr, ret); 90 return false; 91 } 92 if (ret >= 0 && sz != 4) 93 return false; 94 95 return (magic == AFSV1_FOOTER_MAGIC); 96 } 97 98 static bool afs_is_v2(struct mtd_info *mtd, u_int off) 99 { 100 /* The magic is the 8 last bytes of the erase block */ 101 u_int ptr = off + mtd->erasesize - 8; 102 u32 foot[2]; 103 size_t sz; 104 int ret; 105 106 ret = mtd_read(mtd, ptr, 8, &sz, (u_char *)foot); 107 if (ret < 0) { 108 printk(KERN_ERR "AFS: mtd read failed at 0x%x: %d\n", 109 ptr, ret); 110 return false; 111 } 112 if (ret >= 0 && sz != 8) 113 return false; 114 115 return (foot[0] == AFSV2_FOOTER_MAGIC1 && 116 foot[1] == AFSV2_FOOTER_MAGIC2); 117 } 118 119 static int afs_parse_v1_partition(struct mtd_info *mtd, 120 u_int off, struct mtd_partition *part) 121 { 122 struct footer_v1 fs; 123 struct image_info_v1 iis; 124 u_int mask; 125 /* 126 * Static checks cannot see that we bail out if we have an error 127 * reading the footer. 128 */ 129 u_int iis_ptr; 130 u_int img_ptr; 131 u_int ptr; 132 size_t sz; 133 int ret; 134 int i; 135 136 /* 137 * This is the address mask; we use this to mask off out of 138 * range address bits. 139 */ 140 mask = mtd->size - 1; 141 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)) 145 ret = -EINVAL; 146 if (ret < 0) { 147 printk(KERN_ERR "AFS: mtd read failed at 0x%x: %d\n", 148 ptr, ret); 149 return ret; 150 } 151 /* 152 * Check the checksum. 153 */ 154 if (word_sum(&fs, sizeof(fs) / sizeof(u32)) != 0xffffffff) 155 return -EINVAL; 156 157 /* 158 * Hide the SIB (System Information Block) 159 */ 160 if (fs.type == 2) 161 return 0; 162 163 iis_ptr = fs.image_info_base & mask; 164 img_ptr = fs.image_start & mask; 165 166 /* 167 * Check the image info base. This can not 168 * be located after the footer structure. 169 */ 170 if (iis_ptr >= ptr) 171 return 0; 172 173 /* 174 * Check the start of this image. The image 175 * data can not be located after this block. 176 */ 177 if (img_ptr > off) 178 return 0; 179 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); 183 if (ret < 0) { 184 printk(KERN_ERR "AFS: mtd read failed at 0x%x: %d\n", 185 iis_ptr, ret); 186 return -EINVAL; 187 } 188 189 if (sz != sizeof(iis)) 190 return -EINVAL; 191 192 /* 193 * Validate the name - it must be NUL terminated. 194 */ 195 for (i = 0; i < sizeof(iis.name); i++) 196 if (iis.name[i] == '\0') 197 break; 198 if (i > sizeof(iis.name)) 199 return -EINVAL; 200 201 part->name = kstrdup(iis.name, GFP_KERNEL); 202 if (!part->name) 203 return -ENOMEM; 204 205 part->size = (iis.length + mtd->erasesize - 1) & ~(mtd->erasesize - 1); 206 part->offset = img_ptr; 207 part->mask_flags = 0; 208 209 printk(" mtd: at 0x%08x, %5lluKiB, %8u, %s\n", 210 img_ptr, part->size / 1024, 211 iis.imageNumber, part->name); 212 213 return 0; 214 } 215 216 static int afs_parse_v2_partition(struct mtd_info *mtd, 217 u_int off, struct mtd_partition *part) 218 { 219 u_int ptr; 220 u32 footer[12]; 221 u32 imginfo[36]; 222 char *name; 223 u32 version; 224 u32 entrypoint; 225 u32 attributes; 226 u32 region_count; 227 u32 block_start; 228 u32 block_end; 229 u32 crc; 230 size_t sz; 231 int ret; 232 int i; 233 int pad = 0; 234 235 pr_debug("Parsing v2 partition @%08x-%08x\n", 236 off, off + mtd->erasesize); 237 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", 243 ptr, ret); 244 return -EIO; 245 } 246 name = (char *) &footer[0]; 247 version = footer[9]; 248 ptr = off + mtd->erasesize - sizeof(footer) - footer[8]; 249 250 pr_debug("found image \"%s\", version %08x, info @%08x\n", 251 name, version, ptr); 252 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", 257 ptr, ret); 258 return -EIO; 259 } 260 261 /* 32bit platforms have 4 bytes padding */ 262 crc = word_sum_v2(&imginfo[1], 34); 263 if (!crc) { 264 pr_debug("Padding 1 word (4 bytes)\n"); 265 pad = 1; 266 } else { 267 /* 64bit platforms have 8 bytes padding */ 268 crc = word_sum_v2(&imginfo[2], 34); 269 if (!crc) { 270 pr_debug("Padding 2 words (8 bytes)\n"); 271 pad = 2; 272 } 273 } 274 if (crc) { 275 pr_err("AFS: bad checksum on v2 image info: %08x\n", crc); 276 return -EINVAL; 277 } 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]; 283 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); 288 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]; 293 u32 region_start; 294 u32 region_end; 295 296 pr_debug(" region %d: address: %08x, size: %08x, " 297 "offset: %08x\n", 298 i, 299 region_load_addr, 300 region_size, 301 region_offset); 302 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); 310 311 /* Create one partition per region */ 312 part->name = kstrdup(name, GFP_KERNEL); 313 if (!part->name) 314 return -ENOMEM; 315 part->offset = region_start; 316 part->size = region_end - region_start; 317 part->mask_flags = 0; 318 } 319 320 return 0; 321 } 322 323 static int parse_afs_partitions(struct mtd_info *mtd, 324 const struct mtd_partition **pparts, 325 struct mtd_part_parser_data *data) 326 { 327 struct mtd_partition *parts; 328 u_int off, sz; 329 int ret = 0; 330 int i; 331 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); 336 i += 1; 337 } 338 if (afs_is_v2(mtd, off)) { 339 sz += sizeof(struct mtd_partition); 340 i += 1; 341 } 342 } 343 344 if (!i) 345 return 0; 346 347 parts = kzalloc(sz, GFP_KERNEL); 348 if (!parts) 349 return -ENOMEM; 350 351 /* 352 * Identify the partitions 353 */ 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]); 357 if (ret) 358 goto out_free_parts; 359 i++; 360 } 361 if (afs_is_v2(mtd, off)) { 362 ret = afs_parse_v2_partition(mtd, off, &parts[i]); 363 if (ret) 364 goto out_free_parts; 365 i++; 366 } 367 } 368 369 *pparts = parts; 370 return i; 371 372 out_free_parts: 373 while (--i >= 0) 374 kfree(parts[i].name); 375 kfree(parts); 376 *pparts = NULL; 377 return ret; 378 } 379 380 static const struct of_device_id mtd_parser_afs_of_match_table[] = { 381 { .compatible = "arm,arm-firmware-suite" }, 382 {}, 383 }; 384 MODULE_DEVICE_TABLE(of, mtd_parser_afs_of_match_table); 385 386 static struct mtd_part_parser afs_parser = { 387 .parse_fn = parse_afs_partitions, 388 .name = "afs", 389 .of_match_table = mtd_parser_afs_of_match_table, 390 }; 391 module_mtd_part_parser(afs_parser); 392 393 MODULE_AUTHOR("ARM Ltd"); 394 MODULE_DESCRIPTION("ARM Firmware Suite partition parser"); 395 MODULE_LICENSE("GPL"); 396