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