1 /*====================================================================== 2 3 drivers/mtd/afs.c: ARM Flash Layout/Partitioning 4 5 Copyright © 2000 ARM Limited 6 Copyright (C) 2019 Linus Walleij 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 2 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 22 This is access code for flashes using ARM's flash partitioning 23 standards. 24 25 ======================================================================*/ 26 27 #include <linux/module.h> 28 #include <linux/types.h> 29 #include <linux/kernel.h> 30 #include <linux/slab.h> 31 #include <linux/string.h> 32 #include <linux/init.h> 33 34 #include <linux/mtd/mtd.h> 35 #include <linux/mtd/map.h> 36 #include <linux/mtd/partitions.h> 37 38 #define AFSV1_FOOTER_MAGIC 0xA0FFFF9F 39 #define AFSV2_FOOTER_MAGIC1 0x464C5348 /* "FLSH" */ 40 #define AFSV2_FOOTER_MAGIC2 0x464F4F54 /* "FOOT" */ 41 42 struct footer_v1 { 43 u32 image_info_base; /* Address of first word of ImageFooter */ 44 u32 image_start; /* Start of area reserved by this footer */ 45 u32 signature; /* 'Magic' number proves it's a footer */ 46 u32 type; /* Area type: ARM Image, SIB, customer */ 47 u32 checksum; /* Just this structure */ 48 }; 49 50 struct image_info_v1 { 51 u32 bootFlags; /* Boot flags, compression etc. */ 52 u32 imageNumber; /* Unique number, selects for boot etc. */ 53 u32 loadAddress; /* Address program should be loaded to */ 54 u32 length; /* Actual size of image */ 55 u32 address; /* Image is executed from here */ 56 char name[16]; /* Null terminated */ 57 u32 headerBase; /* Flash Address of any stripped header */ 58 u32 header_length; /* Length of header in memory */ 59 u32 headerType; /* AIF, RLF, s-record etc. */ 60 u32 checksum; /* Image checksum (inc. this struct) */ 61 }; 62 63 static u32 word_sum(void *words, int num) 64 { 65 u32 *p = words; 66 u32 sum = 0; 67 68 while (num--) 69 sum += *p++; 70 71 return sum; 72 } 73 74 static u32 word_sum_v2(u32 *p, u32 num) 75 { 76 u32 sum = 0; 77 int i; 78 79 for (i = 0; i < num; i++) { 80 u32 val; 81 82 val = p[i]; 83 if (val > ~sum) 84 sum++; 85 sum += val; 86 } 87 return ~sum; 88 } 89 90 static bool afs_is_v1(struct mtd_info *mtd, u_int off) 91 { 92 /* The magic is 12 bytes from the end of the erase block */ 93 u_int ptr = off + mtd->erasesize - 12; 94 u32 magic; 95 size_t sz; 96 int ret; 97 98 ret = mtd_read(mtd, ptr, 4, &sz, (u_char *)&magic); 99 if (ret < 0) { 100 printk(KERN_ERR "AFS: mtd read failed at 0x%x: %d\n", 101 ptr, ret); 102 return false; 103 } 104 if (ret >= 0 && sz != 4) 105 return false; 106 107 return (magic == AFSV1_FOOTER_MAGIC); 108 } 109 110 static bool afs_is_v2(struct mtd_info *mtd, u_int off) 111 { 112 /* The magic is the 8 last bytes of the erase block */ 113 u_int ptr = off + mtd->erasesize - 8; 114 u32 foot[2]; 115 size_t sz; 116 int ret; 117 118 ret = mtd_read(mtd, ptr, 8, &sz, (u_char *)foot); 119 if (ret < 0) { 120 printk(KERN_ERR "AFS: mtd read failed at 0x%x: %d\n", 121 ptr, ret); 122 return false; 123 } 124 if (ret >= 0 && sz != 8) 125 return false; 126 127 return (foot[0] == AFSV2_FOOTER_MAGIC1 && 128 foot[1] == AFSV2_FOOTER_MAGIC2); 129 } 130 131 static int afs_parse_v1_partition(struct mtd_info *mtd, 132 u_int off, struct mtd_partition *part) 133 { 134 struct footer_v1 fs; 135 struct image_info_v1 iis; 136 u_int mask; 137 /* 138 * Static checks cannot see that we bail out if we have an error 139 * reading the footer. 140 */ 141 u_int uninitialized_var(iis_ptr); 142 u_int uninitialized_var(img_ptr); 143 u_int ptr; 144 size_t sz; 145 int ret; 146 int i; 147 148 /* 149 * This is the address mask; we use this to mask off out of 150 * range address bits. 151 */ 152 mask = mtd->size - 1; 153 154 ptr = off + mtd->erasesize - sizeof(fs); 155 ret = mtd_read(mtd, ptr, sizeof(fs), &sz, (u_char *)&fs); 156 if (ret >= 0 && sz != sizeof(fs)) 157 ret = -EINVAL; 158 if (ret < 0) { 159 printk(KERN_ERR "AFS: mtd read failed at 0x%x: %d\n", 160 ptr, ret); 161 return ret; 162 } 163 /* 164 * Check the checksum. 165 */ 166 if (word_sum(&fs, sizeof(fs) / sizeof(u32)) != 0xffffffff) 167 return -EINVAL; 168 169 /* 170 * Hide the SIB (System Information Block) 171 */ 172 if (fs.type == 2) 173 return 0; 174 175 iis_ptr = fs.image_info_base & mask; 176 img_ptr = fs.image_start & mask; 177 178 /* 179 * Check the image info base. This can not 180 * be located after the footer structure. 181 */ 182 if (iis_ptr >= ptr) 183 return 0; 184 185 /* 186 * Check the start of this image. The image 187 * data can not be located after this block. 188 */ 189 if (img_ptr > off) 190 return 0; 191 192 /* Read the image info block */ 193 memset(&iis, 0, sizeof(iis)); 194 ret = mtd_read(mtd, iis_ptr, sizeof(iis), &sz, (u_char *)&iis); 195 if (ret < 0) { 196 printk(KERN_ERR "AFS: mtd read failed at 0x%x: %d\n", 197 iis_ptr, ret); 198 return -EINVAL; 199 } 200 201 if (sz != sizeof(iis)) 202 return -EINVAL; 203 204 /* 205 * Validate the name - it must be NUL terminated. 206 */ 207 for (i = 0; i < sizeof(iis.name); i++) 208 if (iis.name[i] == '\0') 209 break; 210 if (i > sizeof(iis.name)) 211 return -EINVAL; 212 213 part->name = kstrdup(iis.name, GFP_KERNEL); 214 if (!part->name) 215 return -ENOMEM; 216 217 part->size = (iis.length + mtd->erasesize - 1) & ~(mtd->erasesize - 1); 218 part->offset = img_ptr; 219 part->mask_flags = 0; 220 221 printk(" mtd: at 0x%08x, %5lluKiB, %8u, %s\n", 222 img_ptr, part->size / 1024, 223 iis.imageNumber, part->name); 224 225 return 0; 226 } 227 228 static int afs_parse_v2_partition(struct mtd_info *mtd, 229 u_int off, struct mtd_partition *part) 230 { 231 u_int ptr; 232 u32 footer[12]; 233 u32 imginfo[36]; 234 char *name; 235 u32 version; 236 u32 entrypoint; 237 u32 attributes; 238 u32 region_count; 239 u32 block_start; 240 u32 block_end; 241 u32 crc; 242 size_t sz; 243 int ret; 244 int i; 245 int pad = 0; 246 247 pr_debug("Parsing v2 partition @%08x-%08x\n", 248 off, off + mtd->erasesize); 249 250 /* First read the footer */ 251 ptr = off + mtd->erasesize - sizeof(footer); 252 ret = mtd_read(mtd, ptr, sizeof(footer), &sz, (u_char *)footer); 253 if ((ret < 0) || (ret >= 0 && sz != sizeof(footer))) { 254 pr_err("AFS: mtd read failed at 0x%x: %d\n", 255 ptr, ret); 256 return -EIO; 257 } 258 name = (char *) &footer[0]; 259 version = footer[9]; 260 ptr = off + mtd->erasesize - sizeof(footer) - footer[8]; 261 262 pr_debug("found image \"%s\", version %08x, info @%08x\n", 263 name, version, ptr); 264 265 /* Then read the image information */ 266 ret = mtd_read(mtd, ptr, sizeof(imginfo), &sz, (u_char *)imginfo); 267 if ((ret < 0) || (ret >= 0 && sz != sizeof(imginfo))) { 268 pr_err("AFS: mtd read failed at 0x%x: %d\n", 269 ptr, ret); 270 return -EIO; 271 } 272 273 /* 32bit platforms have 4 bytes padding */ 274 crc = word_sum_v2(&imginfo[1], 34); 275 if (!crc) { 276 pr_debug("Padding 1 word (4 bytes)\n"); 277 pad = 1; 278 } else { 279 /* 64bit platforms have 8 bytes padding */ 280 crc = word_sum_v2(&imginfo[2], 34); 281 if (!crc) { 282 pr_debug("Padding 2 words (8 bytes)\n"); 283 pad = 2; 284 } 285 } 286 if (crc) { 287 pr_err("AFS: bad checksum on v2 image info: %08x\n", crc); 288 return -EINVAL; 289 } 290 entrypoint = imginfo[pad]; 291 attributes = imginfo[pad+1]; 292 region_count = imginfo[pad+2]; 293 block_start = imginfo[20]; 294 block_end = imginfo[21]; 295 296 pr_debug("image entry=%08x, attr=%08x, regions=%08x, " 297 "bs=%08x, be=%08x\n", 298 entrypoint, attributes, region_count, 299 block_start, block_end); 300 301 for (i = 0; i < region_count; i++) { 302 u32 region_load_addr = imginfo[pad + 3 + i*4]; 303 u32 region_size = imginfo[pad + 4 + i*4]; 304 u32 region_offset = imginfo[pad + 5 + i*4]; 305 u32 region_start; 306 u32 region_end; 307 308 pr_debug(" region %d: address: %08x, size: %08x, " 309 "offset: %08x\n", 310 i, 311 region_load_addr, 312 region_size, 313 region_offset); 314 315 region_start = off + region_offset; 316 region_end = region_start + region_size; 317 /* Align partition to end of erase block */ 318 region_end += (mtd->erasesize - 1); 319 region_end &= ~(mtd->erasesize -1); 320 pr_debug(" partition start = %08x, partition end = %08x\n", 321 region_start, region_end); 322 323 /* Create one partition per region */ 324 part->name = kstrdup(name, GFP_KERNEL); 325 if (!part->name) 326 return -ENOMEM; 327 part->offset = region_start; 328 part->size = region_end - region_start; 329 part->mask_flags = 0; 330 } 331 332 return 0; 333 } 334 335 static int parse_afs_partitions(struct mtd_info *mtd, 336 const struct mtd_partition **pparts, 337 struct mtd_part_parser_data *data) 338 { 339 struct mtd_partition *parts; 340 u_int off, sz; 341 int ret = 0; 342 int i; 343 344 /* Count the partitions by looping over all erase blocks */ 345 for (i = off = sz = 0; off < mtd->size; off += mtd->erasesize) { 346 if (afs_is_v1(mtd, off)) { 347 sz += sizeof(struct mtd_partition); 348 i += 1; 349 } 350 if (afs_is_v2(mtd, off)) { 351 sz += sizeof(struct mtd_partition); 352 i += 1; 353 } 354 } 355 356 if (!i) 357 return 0; 358 359 parts = kzalloc(sz, GFP_KERNEL); 360 if (!parts) 361 return -ENOMEM; 362 363 /* 364 * Identify the partitions 365 */ 366 for (i = off = 0; off < mtd->size; off += mtd->erasesize) { 367 if (afs_is_v1(mtd, off)) { 368 ret = afs_parse_v1_partition(mtd, off, &parts[i]); 369 if (ret) 370 goto out_free_parts; 371 i++; 372 } 373 if (afs_is_v2(mtd, off)) { 374 ret = afs_parse_v2_partition(mtd, off, &parts[i]); 375 if (ret) 376 goto out_free_parts; 377 i++; 378 } 379 } 380 381 *pparts = parts; 382 return i; 383 384 out_free_parts: 385 while (i >= 0) { 386 if (parts[i].name) 387 kfree(parts[i].name); 388 i--; 389 } 390 kfree(parts); 391 *pparts = NULL; 392 return ret; 393 } 394 395 static const struct of_device_id mtd_parser_afs_of_match_table[] = { 396 { .compatible = "arm,arm-firmware-suite" }, 397 {}, 398 }; 399 MODULE_DEVICE_TABLE(of, mtd_parser_afs_of_match_table); 400 401 static struct mtd_part_parser afs_parser = { 402 .parse_fn = parse_afs_partitions, 403 .name = "afs", 404 .of_match_table = mtd_parser_afs_of_match_table, 405 }; 406 module_mtd_part_parser(afs_parser); 407 408 MODULE_AUTHOR("ARM Ltd"); 409 MODULE_DESCRIPTION("ARM Firmware Suite partition parser"); 410 MODULE_LICENSE("GPL"); 411