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