Merge branch 'core-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-block.git] / drivers / mtd / afs.c
CommitLineData
1da177e4
LT
1/*======================================================================
2
3 drivers/mtd/afs.c: ARM Flash Layout/Partitioning
97894cda 4
a1452a37 5 Copyright © 2000 ARM Limited
97894cda 6
1da177e4
LT
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.
97894cda 11
1da177e4
LT
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.
97894cda 16
1da177e4
LT
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
97894cda
TG
20
21 This is access code for flashes using ARM's flash partitioning
1da177e4
LT
22 standards.
23
1da177e4
LT
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
9498440f
LW
37#define AFSV1_FOOTER_MAGIC 0xA0FFFF9F
38
a486d11f 39struct footer_v1 {
1da177e4
LT
40 u32 image_info_base; /* Address of first word of ImageFooter */
41 u32 image_start; /* Start of area reserved by this footer */
42 u32 signature; /* 'Magic' number proves it's a footer */
43 u32 type; /* Area type: ARM Image, SIB, customer */
44 u32 checksum; /* Just this structure */
45};
46
a486d11f 47struct image_info_v1 {
1da177e4
LT
48 u32 bootFlags; /* Boot flags, compression etc. */
49 u32 imageNumber; /* Unique number, selects for boot etc. */
50 u32 loadAddress; /* Address program should be loaded to */
51 u32 length; /* Actual size of image */
52 u32 address; /* Image is executed from here */
53 char name[16]; /* Null terminated */
54 u32 headerBase; /* Flash Address of any stripped header */
55 u32 header_length; /* Length of header in memory */
56 u32 headerType; /* AIF, RLF, s-record etc. */
57 u32 checksum; /* Image checksum (inc. this struct) */
58};
59
60static u32 word_sum(void *words, int num)
61{
62 u32 *p = words;
63 u32 sum = 0;
64
65 while (num--)
66 sum += *p++;
67
68 return sum;
69}
70
71static int
a486d11f
LW
72afs_read_footer_v1(struct mtd_info *mtd, u_int *img_start, u_int *iis_start,
73 u_int off, u_int mask)
1da177e4 74{
a486d11f 75 struct footer_v1 fs;
1da177e4
LT
76 u_int ptr = off + mtd->erasesize - sizeof(fs);
77 size_t sz;
78 int ret;
79
329ad399 80 ret = mtd_read(mtd, ptr, sizeof(fs), &sz, (u_char *)&fs);
1da177e4
LT
81 if (ret >= 0 && sz != sizeof(fs))
82 ret = -EINVAL;
83
84 if (ret < 0) {
85 printk(KERN_ERR "AFS: mtd read failed at 0x%x: %d\n",
86 ptr, ret);
87 return ret;
88 }
89
1da177e4
LT
90 /*
91 * Does it contain the magic number?
92 */
9498440f 93 if (fs.signature != AFSV1_FOOTER_MAGIC)
d2fd05bb 94 return 0;
1da177e4
LT
95
96 /*
97 * Check the checksum.
98 */
99 if (word_sum(&fs, sizeof(fs) / sizeof(u32)) != 0xffffffff)
d2fd05bb 100 return 0;
1da177e4
LT
101
102 /*
103 * Don't touch the SIB.
104 */
105 if (fs.type == 2)
d2fd05bb 106 return 0;
1da177e4
LT
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)
d2fd05bb 116 return 0;
1da177e4
LT
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)
d2fd05bb 123 return 0;
1da177e4 124
d2fd05bb 125 return 1;
1da177e4
LT
126}
127
128static int
a486d11f 129afs_read_iis_v1(struct mtd_info *mtd, struct image_info_v1 *iis, u_int ptr)
1da177e4
LT
130{
131 size_t sz;
132 int ret, i;
133
134 memset(iis, 0, sizeof(*iis));
329ad399 135 ret = mtd_read(mtd, ptr, sizeof(*iis), &sz, (u_char *)iis);
1da177e4
LT
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
97894cda 164static int parse_afs_partitions(struct mtd_info *mtd,
b9adf469 165 const struct mtd_partition **pparts,
c7975330 166 struct mtd_part_parser_data *data)
1da177e4
LT
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) {
a486d11f 185 struct image_info_v1 iis;
1da177e4
LT
186 u_int iis_ptr, img_ptr;
187
a486d11f 188 ret = afs_read_footer_v1(mtd, &img_ptr, &iis_ptr, off, mask);
1da177e4
LT
189 if (ret < 0)
190 break;
d2fd05bb
LW
191 if (ret) {
192 ret = afs_read_iis_v1(mtd, &iis, iis_ptr);
193 if (ret < 0)
194 break;
195 if (ret == 0)
196 continue;
197
198 sz += sizeof(struct mtd_partition);
199 sz += strlen(iis.name) + 1;
200 idx += 1;
201 }
1da177e4
LT
202 }
203
204 if (!sz)
205 return ret;
206
95b93a0c 207 parts = kzalloc(sz, GFP_KERNEL);
1da177e4
LT
208 if (!parts)
209 return -ENOMEM;
210
1da177e4
LT
211 str = (char *)(parts + idx);
212
213 /*
214 * Identify the partitions
215 */
216 for (idx = off = 0; off < mtd->size; off += mtd->erasesize) {
a486d11f 217 struct image_info_v1 iis;
747aead3 218 u_int iis_ptr, img_ptr;
1da177e4
LT
219
220 /* Read the footer. */
a486d11f 221 ret = afs_read_footer_v1(mtd, &img_ptr, &iis_ptr, off, mask);
1da177e4
LT
222 if (ret < 0)
223 break;
224 if (ret == 0)
225 continue;
226
227 /* Read the image info block */
a486d11f 228 ret = afs_read_iis_v1(mtd, &iis, iis_ptr);
1da177e4
LT
229 if (ret < 0)
230 break;
231 if (ret == 0)
232 continue;
233
234 strcpy(str, iis.name);
1da177e4
LT
235
236 parts[idx].name = str;
747aead3 237 parts[idx].size = (iis.length + mtd->erasesize - 1) & ~(mtd->erasesize - 1);
1da177e4
LT
238 parts[idx].offset = img_ptr;
239 parts[idx].mask_flags = 0;
240
0ffd24fc 241 printk(" mtd%d: at 0x%08x, %5lluKiB, %8u, %s\n",
1da177e4
LT
242 idx, img_ptr, parts[idx].size / 1024,
243 iis.imageNumber, str);
244
245 idx += 1;
246 str = str + strlen(iis.name) + 1;
247 }
248
249 if (!idx) {
250 kfree(parts);
251 parts = NULL;
252 }
253
254 *pparts = parts;
255 return idx ? idx : ret;
256}
257
258static struct mtd_part_parser afs_parser = {
1da177e4
LT
259 .parse_fn = parse_afs_partitions,
260 .name = "afs",
261};
b8f70bad 262module_mtd_part_parser(afs_parser);
1da177e4
LT
263
264MODULE_AUTHOR("ARM Ltd");
265MODULE_DESCRIPTION("ARM Firmware Suite partition parser");
266MODULE_LICENSE("GPL");