Branch data Line data Source code
1 : : /*
2 : : * Read flash partition table from command line
3 : : *
4 : : * Copyright © 2002 SYSGO Real-Time Solutions GmbH
5 : : * Copyright © 2002-2010 David Woodhouse <dwmw2@infradead.org>
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 : : *
21 : : * The format for the command line is as follows:
22 : : *
23 : : * mtdparts=<mtddef>[;<mtddef]
24 : : * <mtddef> := <mtd-id>:<partdef>[,<partdef>]
25 : : * <partdef> := <size>[@<offset>][<name>][ro][lk]
26 : : * <mtd-id> := unique name used in mapping driver/device (mtd->name)
27 : : * <size> := standard linux memsize OR "-" to denote all remaining space
28 : : * size is automatically truncated at end of device
29 : : * if specified or trucated size is 0 the part is skipped
30 : : * <offset> := standard linux memsize
31 : : * if omitted the part will immediately follow the previous part
32 : : * or 0 if the first part
33 : : * <name> := '(' NAME ')'
34 : : * NAME will appear in /proc/mtd
35 : : *
36 : : * <size> and <offset> can be specified such that the parts are out of order
37 : : * in physical memory and may even overlap.
38 : : *
39 : : * The parts are assigned MTD numbers in the order they are specified in the
40 : : * command line regardless of their order in physical memory.
41 : : *
42 : : * Examples:
43 : : *
44 : : * 1 NOR Flash, with 1 single writable partition:
45 : : * edb7312-nor:-
46 : : *
47 : : * 1 NOR Flash with 2 partitions, 1 NAND with one
48 : : * edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home)
49 : : */
50 : :
51 : : #include <linux/kernel.h>
52 : : #include <linux/slab.h>
53 : : #include <linux/mtd/mtd.h>
54 : : #include <linux/mtd/partitions.h>
55 : : #include <linux/module.h>
56 : : #include <linux/err.h>
57 : :
58 : : /* error message prefix */
59 : : #define ERRP "mtd: "
60 : :
61 : : /* debug macro */
62 : : #if 0
63 : : #define dbg(x) do { printk("DEBUG-CMDLINE-PART: "); printk x; } while(0)
64 : : #else
65 : : #define dbg(x)
66 : : #endif
67 : :
68 : :
69 : : /* special size referring to all the remaining space in a partition */
70 : : #define SIZE_REMAINING ULLONG_MAX
71 : : #define OFFSET_CONTINUOUS ULLONG_MAX
72 : :
73 : : struct cmdline_mtd_partition {
74 : : struct cmdline_mtd_partition *next;
75 : : char *mtd_id;
76 : : int num_parts;
77 : : struct mtd_partition *parts;
78 : : };
79 : :
80 : : /* mtdpart_setup() parses into here */
81 : : static struct cmdline_mtd_partition *partitions;
82 : :
83 : : /* the command line passed to mtdpart_setup() */
84 : : static char *mtdparts;
85 : : static char *cmdline;
86 : : static int cmdline_parsed;
87 : :
88 : : /*
89 : : * Parse one partition definition for an MTD. Since there can be many
90 : : * comma separated partition definitions, this function calls itself
91 : : * recursively until no more partition definitions are found. Nice side
92 : : * effect: the memory to keep the mtd_partition structs and the names
93 : : * is allocated upon the last definition being found. At that point the
94 : : * syntax has been verified ok.
95 : : */
96 : 0 : static struct mtd_partition * newpart(char *s,
97 : : char **retptr,
98 : : int *num_parts,
99 : : int this_part,
100 : : unsigned char **extra_mem_ptr,
101 : : int extra_mem_size)
102 : : {
103 : : struct mtd_partition *parts;
104 : : unsigned long long size, offset = OFFSET_CONTINUOUS;
105 : : char *name;
106 : : int name_len;
107 : : unsigned char *extra_mem;
108 : : char delim;
109 : : unsigned int mask_flags;
110 : :
111 : : /* fetch the partition size */
112 [ # # ]: 0 : if (*s == '-') {
113 : : /* assign all remaining space to this partition */
114 : : size = SIZE_REMAINING;
115 : 0 : s++;
116 : : } else {
117 : 0 : size = memparse(s, &s);
118 [ # # ]: 0 : if (size < PAGE_SIZE) {
119 : 0 : printk(KERN_ERR ERRP "partition size too small (%llx)\n",
120 : : size);
121 : 0 : return ERR_PTR(-EINVAL);
122 : : }
123 : : }
124 : :
125 : : /* fetch partition name and flags */
126 : : mask_flags = 0; /* this is going to be a regular partition */
127 : : delim = 0;
128 : :
129 : : /* check for offset */
130 [ # # ]: 0 : if (*s == '@') {
131 : 0 : s++;
132 : 0 : offset = memparse(s, &s);
133 : : }
134 : :
135 : : /* now look for name */
136 [ # # ]: 0 : if (*s == '(')
137 : : delim = ')';
138 : :
139 [ # # ]: 0 : if (delim) {
140 : : char *p;
141 : :
142 : 0 : name = ++s;
143 : 0 : p = strchr(name, delim);
144 [ # # ]: 0 : if (!p) {
145 : 0 : printk(KERN_ERR ERRP "no closing %c found in partition name\n", delim);
146 : 0 : return ERR_PTR(-EINVAL);
147 : : }
148 : 0 : name_len = p - name;
149 : 0 : s = p + 1;
150 : : } else {
151 : : name = NULL;
152 : : name_len = 13; /* Partition_000 */
153 : : }
154 : :
155 : : /* record name length for memory allocation later */
156 : 0 : extra_mem_size += name_len + 1;
157 : :
158 : : /* test for options */
159 [ # # ]: 0 : if (strncmp(s, "ro", 2) == 0) {
160 : : mask_flags |= MTD_WRITEABLE;
161 : 0 : s += 2;
162 : : }
163 : :
164 : : /* if lk is found do NOT unlock the MTD partition*/
165 [ # # ]: 0 : if (strncmp(s, "lk", 2) == 0) {
166 : 0 : mask_flags |= MTD_POWERUP_LOCK;
167 : 0 : s += 2;
168 : : }
169 : :
170 : : /* test if more partitions are following */
171 [ # # ]: 0 : if (*s == ',') {
172 [ # # ]: 0 : if (size == SIZE_REMAINING) {
173 : 0 : printk(KERN_ERR ERRP "no partitions allowed after a fill-up partition\n");
174 : 0 : return ERR_PTR(-EINVAL);
175 : : }
176 : : /* more partitions follow, parse them */
177 : 0 : parts = newpart(s + 1, &s, num_parts, this_part + 1,
178 : : &extra_mem, extra_mem_size);
179 [ # # ]: 0 : if (IS_ERR(parts))
180 : : return parts;
181 : : } else {
182 : : /* this is the last partition: allocate space for all */
183 : : int alloc_size;
184 : :
185 : 0 : *num_parts = this_part + 1;
186 : 0 : alloc_size = *num_parts * sizeof(struct mtd_partition) +
187 : : extra_mem_size;
188 : :
189 : : parts = kzalloc(alloc_size, GFP_KERNEL);
190 [ # # ]: 0 : if (!parts)
191 : : return ERR_PTR(-ENOMEM);
192 : 0 : extra_mem = (unsigned char *)(parts + *num_parts);
193 : : }
194 : :
195 : : /* enter this partition (offset will be calculated later if it is zero at this point) */
196 : 0 : parts[this_part].size = size;
197 : 0 : parts[this_part].offset = offset;
198 : 0 : parts[this_part].mask_flags = mask_flags;
199 [ # # ]: 0 : if (name)
200 : 0 : strlcpy(extra_mem, name, name_len + 1);
201 : : else
202 : 0 : sprintf(extra_mem, "Partition_%03d", this_part);
203 : 0 : parts[this_part].name = extra_mem;
204 : 0 : extra_mem += name_len + 1;
205 : :
206 : : dbg(("partition %d: name <%s>, offset %llx, size %llx, mask flags %x\n",
207 : : this_part, parts[this_part].name, parts[this_part].offset,
208 : : parts[this_part].size, parts[this_part].mask_flags));
209 : :
210 : : /* return (updated) pointer to extra_mem memory */
211 [ # # ]: 0 : if (extra_mem_ptr)
212 : 0 : *extra_mem_ptr = extra_mem;
213 : :
214 : : /* return (updated) pointer command line string */
215 : 0 : *retptr = s;
216 : :
217 : : /* return partition table */
218 : 0 : return parts;
219 : : }
220 : :
221 : : /*
222 : : * Parse the command line.
223 : : */
224 : 0 : static int mtdpart_setup_real(char *s)
225 : : {
226 : 0 : cmdline_parsed = 1;
227 : :
228 [ # # ]: 0 : for( ; s != NULL; )
229 : : {
230 : : struct cmdline_mtd_partition *this_mtd;
231 : : struct mtd_partition *parts;
232 : : int mtd_id_len, num_parts;
233 : : char *p, *mtd_id;
234 : :
235 : : mtd_id = s;
236 : :
237 : : /* fetch <mtd-id> */
238 : 0 : p = strchr(s, ':');
239 [ # # ]: 0 : if (!p) {
240 : 0 : printk(KERN_ERR ERRP "no mtd-id\n");
241 : 0 : return -EINVAL;
242 : : }
243 : 0 : mtd_id_len = p - mtd_id;
244 : :
245 : : dbg(("parsing <%s>\n", p+1));
246 : :
247 : : /*
248 : : * parse one mtd. have it reserve memory for the
249 : : * struct cmdline_mtd_partition and the mtd-id string.
250 : : */
251 : 0 : parts = newpart(p + 1, /* cmdline */
252 : : &s, /* out: updated cmdline ptr */
253 : : &num_parts, /* out: number of parts */
254 : : 0, /* first partition */
255 : : (unsigned char**)&this_mtd, /* out: extra mem */
256 : 0 : mtd_id_len + 1 + sizeof(*this_mtd) +
257 : 0 : sizeof(void*)-1 /*alignment*/);
258 [ # # ]: 0 : if (IS_ERR(parts)) {
259 : : /*
260 : : * An error occurred. We're either:
261 : : * a) out of memory, or
262 : : * b) in the middle of the partition spec
263 : : * Either way, this mtd is hosed and we're
264 : : * unlikely to succeed in parsing any more
265 : : */
266 : 0 : return PTR_ERR(parts);
267 : : }
268 : :
269 : : /* align this_mtd */
270 : 0 : this_mtd = (struct cmdline_mtd_partition *)
271 : 0 : ALIGN((unsigned long)this_mtd, sizeof(void *));
272 : : /* enter results */
273 : 0 : this_mtd->parts = parts;
274 : 0 : this_mtd->num_parts = num_parts;
275 : 0 : this_mtd->mtd_id = (char*)(this_mtd + 1);
276 : 0 : strlcpy(this_mtd->mtd_id, mtd_id, mtd_id_len + 1);
277 : :
278 : : /* link into chain */
279 : 0 : this_mtd->next = partitions;
280 : 0 : partitions = this_mtd;
281 : :
282 : : dbg(("mtdid=<%s> num_parts=<%d>\n",
283 : : this_mtd->mtd_id, this_mtd->num_parts));
284 : :
285 : :
286 : : /* EOS - we're done */
287 [ # # ]: 0 : if (*s == 0)
288 : : break;
289 : :
290 : : /* does another spec follow? */
291 [ # # ]: 0 : if (*s != ';') {
292 : 0 : printk(KERN_ERR ERRP "bad character after partition (%c)\n", *s);
293 : 0 : return -EINVAL;
294 : : }
295 : 0 : s++;
296 : : }
297 : :
298 : : return 0;
299 : : }
300 : :
301 : : /*
302 : : * Main function to be called from the MTD mapping driver/device to
303 : : * obtain the partitioning information. At this point the command line
304 : : * arguments will actually be parsed and turned to struct mtd_partition
305 : : * information. It returns partitions for the requested mtd device, or
306 : : * the first one in the chain if a NULL mtd_id is passed in.
307 : : */
308 : 0 : static int parse_cmdline_partitions(struct mtd_info *master,
309 : : struct mtd_partition **pparts,
310 : : struct mtd_part_parser_data *data)
311 : : {
312 : : unsigned long long offset;
313 : : int i, err;
314 : : struct cmdline_mtd_partition *part;
315 : 0 : const char *mtd_id = master->name;
316 : :
317 : : /* parse command line */
318 [ # # ]: 0 : if (!cmdline_parsed) {
319 : 0 : err = mtdpart_setup_real(cmdline);
320 [ # # ]: 0 : if (err)
321 : : return err;
322 : : }
323 : :
324 : : /*
325 : : * Search for the partition definition matching master->name.
326 : : * If master->name is not set, stop at first partition definition.
327 : : */
328 [ # # ]: 0 : for (part = partitions; part; part = part->next) {
329 [ # # ][ # # ]: 0 : if ((!mtd_id) || (!strcmp(part->mtd_id, mtd_id)))
330 : : break;
331 : : }
332 : :
333 [ # # ]: 0 : if (!part)
334 : : return 0;
335 : :
336 [ # # ]: 0 : for (i = 0, offset = 0; i < part->num_parts; i++) {
337 [ # # ]: 0 : if (part->parts[i].offset == OFFSET_CONTINUOUS)
338 : 0 : part->parts[i].offset = offset;
339 : : else
340 : : offset = part->parts[i].offset;
341 : :
342 [ # # ]: 0 : if (part->parts[i].size == SIZE_REMAINING)
343 : 0 : part->parts[i].size = master->size - offset;
344 : :
345 [ # # ]: 0 : if (offset + part->parts[i].size > master->size) {
346 : 0 : printk(KERN_WARNING ERRP
347 : : "%s: partitioning exceeds flash size, truncating\n",
348 : : part->mtd_id);
349 : 0 : part->parts[i].size = master->size - offset;
350 : : }
351 : 0 : offset += part->parts[i].size;
352 : :
353 [ # # ]: 0 : if (part->parts[i].size == 0) {
354 : 0 : printk(KERN_WARNING ERRP
355 : : "%s: skipping zero sized partition\n",
356 : : part->mtd_id);
357 : 0 : part->num_parts--;
358 : 0 : memmove(&part->parts[i], &part->parts[i + 1],
359 : 0 : sizeof(*part->parts) * (part->num_parts - i));
360 : 0 : i--;
361 : : }
362 : : }
363 : :
364 : 0 : *pparts = kmemdup(part->parts, sizeof(*part->parts) * part->num_parts,
365 : : GFP_KERNEL);
366 [ # # ]: 0 : if (!*pparts)
367 : : return -ENOMEM;
368 : :
369 : 0 : return part->num_parts;
370 : : }
371 : :
372 : :
373 : : /*
374 : : * This is the handler for our kernel parameter, called from
375 : : * main.c::checksetup(). Note that we can not yet kmalloc() anything,
376 : : * so we only save the commandline for later processing.
377 : : *
378 : : * This function needs to be visible for bootloaders.
379 : : */
380 : 0 : static int __init mtdpart_setup(char *s)
381 : : {
382 : 0 : cmdline = s;
383 : 0 : return 1;
384 : : }
385 : :
386 : : __setup("mtdparts=", mtdpart_setup);
387 : :
388 : : static struct mtd_part_parser cmdline_parser = {
389 : : .owner = THIS_MODULE,
390 : : .parse_fn = parse_cmdline_partitions,
391 : : .name = "cmdlinepart",
392 : : };
393 : :
394 : 0 : static int __init cmdline_parser_init(void)
395 : : {
396 [ # # ]: 0 : if (mtdparts)
397 : : mtdpart_setup(mtdparts);
398 : 0 : return register_mtd_parser(&cmdline_parser);
399 : : }
400 : :
401 : 0 : static void __exit cmdline_parser_exit(void)
402 : : {
403 : 0 : deregister_mtd_parser(&cmdline_parser);
404 : 0 : }
405 : :
406 : : module_init(cmdline_parser_init);
407 : : module_exit(cmdline_parser_exit);
408 : :
409 : : MODULE_PARM_DESC(mtdparts, "Partitioning specification");
410 : : module_param(mtdparts, charp, 0);
411 : :
412 : : MODULE_LICENSE("GPL");
413 : : MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>");
414 : : MODULE_DESCRIPTION("Command line configuration of MTD partitions");
|