Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
afs.c
Go to the documentation of this file.
1 /*======================================================================
2 
3  drivers/mtd/afs.c: ARM Flash Layout/Partitioning
4 
5  Copyright © 2000 ARM Limited
6 
7  This program is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 2 of the License, or
10  (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 
21  This is access code for flashes using ARM's flash partitioning
22  standards.
23 
24 ======================================================================*/
25 
26 #include <linux/module.h>
27 #include <linux/types.h>
28 #include <linux/kernel.h>
29 #include <linux/slab.h>
30 #include <linux/string.h>
31 #include <linux/init.h>
32 
33 #include <linux/mtd/mtd.h>
34 #include <linux/mtd/map.h>
35 #include <linux/mtd/partitions.h>
36 
37 struct footer_struct {
38  u32 image_info_base; /* Address of first word of ImageFooter */
39  u32 image_start; /* Start of area reserved by this footer */
40  u32 signature; /* 'Magic' number proves it's a footer */
41  u32 type; /* Area type: ARM Image, SIB, customer */
42  u32 checksum; /* Just this structure */
43 };
44 
46  u32 bootFlags; /* Boot flags, compression etc. */
47  u32 imageNumber; /* Unique number, selects for boot etc. */
48  u32 loadAddress; /* Address program should be loaded to */
49  u32 length; /* Actual size of image */
50  u32 address; /* Image is executed from here */
51  char name[16]; /* Null terminated */
52  u32 headerBase; /* Flash Address of any stripped header */
53  u32 header_length; /* Length of header in memory */
54  u32 headerType; /* AIF, RLF, s-record etc. */
55  u32 checksum; /* Image checksum (inc. this struct) */
56 };
57 
58 static u32 word_sum(void *words, int num)
59 {
60  u32 *p = words;
61  u32 sum = 0;
62 
63  while (num--)
64  sum += *p++;
65 
66  return sum;
67 }
68 
69 static int
70 afs_read_footer(struct mtd_info *mtd, u_int *img_start, u_int *iis_start,
71  u_int off, u_int mask)
72 {
73  struct footer_struct fs;
74  u_int ptr = off + mtd->erasesize - sizeof(fs);
75  size_t sz;
76  int ret;
77 
78  ret = mtd_read(mtd, ptr, sizeof(fs), &sz, (u_char *)&fs);
79  if (ret >= 0 && sz != sizeof(fs))
80  ret = -EINVAL;
81 
82  if (ret < 0) {
83  printk(KERN_ERR "AFS: mtd read failed at 0x%x: %d\n",
84  ptr, ret);
85  return ret;
86  }
87 
88  ret = 1;
89 
90  /*
91  * Does it contain the magic number?
92  */
93  if (fs.signature != 0xa0ffff9f)
94  ret = 0;
95 
96  /*
97  * Check the checksum.
98  */
99  if (word_sum(&fs, sizeof(fs) / sizeof(u32)) != 0xffffffff)
100  ret = 0;
101 
102  /*
103  * Don't touch the SIB.
104  */
105  if (fs.type == 2)
106  ret = 0;
107 
108  *iis_start = fs.image_info_base & mask;
109  *img_start = fs.image_start & mask;
110 
111  /*
112  * Check the image info base. This can not
113  * be located after the footer structure.
114  */
115  if (*iis_start >= ptr)
116  ret = 0;
117 
118  /*
119  * Check the start of this image. The image
120  * data can not be located after this block.
121  */
122  if (*img_start > off)
123  ret = 0;
124 
125  return ret;
126 }
127 
128 static int
129 afs_read_iis(struct mtd_info *mtd, struct image_info_struct *iis, u_int ptr)
130 {
131  size_t sz;
132  int ret, i;
133 
134  memset(iis, 0, sizeof(*iis));
135  ret = mtd_read(mtd, ptr, sizeof(*iis), &sz, (u_char *)iis);
136  if (ret < 0)
137  goto failed;
138 
139  if (sz != sizeof(*iis)) {
140  ret = -EINVAL;
141  goto failed;
142  }
143 
144  ret = 0;
145 
146  /*
147  * Validate the name - it must be NUL terminated.
148  */
149  for (i = 0; i < sizeof(iis->name); i++)
150  if (iis->name[i] == '\0')
151  break;
152 
153  if (i < sizeof(iis->name))
154  ret = 1;
155 
156  return ret;
157 
158  failed:
159  printk(KERN_ERR "AFS: mtd read failed at 0x%x: %d\n",
160  ptr, ret);
161  return ret;
162 }
163 
164 static int parse_afs_partitions(struct mtd_info *mtd,
165  struct mtd_partition **pparts,
166  struct mtd_part_parser_data *data)
167 {
168  struct mtd_partition *parts;
169  u_int mask, off, idx, sz;
170  int ret = 0;
171  char *str;
172 
173  /*
174  * This is the address mask; we use this to mask off out of
175  * range address bits.
176  */
177  mask = mtd->size - 1;
178 
179  /*
180  * First, calculate the size of the array we need for the
181  * partition information. We include in this the size of
182  * the strings.
183  */
184  for (idx = off = sz = 0; off < mtd->size; off += mtd->erasesize) {
185  struct image_info_struct iis;
186  u_int iis_ptr, img_ptr;
187 
188  ret = afs_read_footer(mtd, &img_ptr, &iis_ptr, off, mask);
189  if (ret < 0)
190  break;
191  if (ret == 0)
192  continue;
193 
194  ret = afs_read_iis(mtd, &iis, iis_ptr);
195  if (ret < 0)
196  break;
197  if (ret == 0)
198  continue;
199 
200  sz += sizeof(struct mtd_partition);
201  sz += strlen(iis.name) + 1;
202  idx += 1;
203  }
204 
205  if (!sz)
206  return ret;
207 
208  parts = kzalloc(sz, GFP_KERNEL);
209  if (!parts)
210  return -ENOMEM;
211 
212  str = (char *)(parts + idx);
213 
214  /*
215  * Identify the partitions
216  */
217  for (idx = off = 0; off < mtd->size; off += mtd->erasesize) {
218  struct image_info_struct iis;
219  u_int iis_ptr, img_ptr;
220 
221  /* Read the footer. */
222  ret = afs_read_footer(mtd, &img_ptr, &iis_ptr, off, mask);
223  if (ret < 0)
224  break;
225  if (ret == 0)
226  continue;
227 
228  /* Read the image info block */
229  ret = afs_read_iis(mtd, &iis, iis_ptr);
230  if (ret < 0)
231  break;
232  if (ret == 0)
233  continue;
234 
235  strcpy(str, iis.name);
236 
237  parts[idx].name = str;
238  parts[idx].size = (iis.length + mtd->erasesize - 1) & ~(mtd->erasesize - 1);
239  parts[idx].offset = img_ptr;
240  parts[idx].mask_flags = 0;
241 
242  printk(" mtd%d: at 0x%08x, %5lluKiB, %8u, %s\n",
243  idx, img_ptr, parts[idx].size / 1024,
244  iis.imageNumber, str);
245 
246  idx += 1;
247  str = str + strlen(iis.name) + 1;
248  }
249 
250  if (!idx) {
251  kfree(parts);
252  parts = NULL;
253  }
254 
255  *pparts = parts;
256  return idx ? idx : ret;
257 }
258 
259 static struct mtd_part_parser afs_parser = {
260  .owner = THIS_MODULE,
261  .parse_fn = parse_afs_partitions,
262  .name = "afs",
263 };
264 
265 static int __init afs_parser_init(void)
266 {
267  return register_mtd_parser(&afs_parser);
268 }
269 
270 static void __exit afs_parser_exit(void)
271 {
272  deregister_mtd_parser(&afs_parser);
273 }
274 
275 module_init(afs_parser_init);
276 module_exit(afs_parser_exit);
277 
278 
279 MODULE_AUTHOR("ARM Ltd");
280 MODULE_DESCRIPTION("ARM Firmware Suite partition parser");
281 MODULE_LICENSE("GPL");