Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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