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 989a7241df87526bfef0396567e71ebe53a84ae4 378 lines 9.3 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][lk] 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 /* 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 if ((parts = newpart(s + 1, &s, num_parts, 163 this_part + 1, &extra_mem, extra_mem_size)) == 0) 164 return NULL; 165 } 166 else 167 { /* this is the last partition: allocate space for all */ 168 int alloc_size; 169 170 *num_parts = this_part + 1; 171 alloc_size = *num_parts * sizeof(struct mtd_partition) + 172 extra_mem_size; 173 parts = kzalloc(alloc_size, GFP_KERNEL); 174 if (!parts) 175 { 176 printk(KERN_ERR ERRP "out of memory\n"); 177 return NULL; 178 } 179 extra_mem = (unsigned char *)(parts + *num_parts); 180 } 181 /* enter this partition (offset will be calculated later if it is zero at this point) */ 182 parts[this_part].size = size; 183 parts[this_part].offset = offset; 184 parts[this_part].mask_flags = mask_flags; 185 if (name) 186 { 187 strlcpy(extra_mem, name, name_len + 1); 188 } 189 else 190 { 191 sprintf(extra_mem, "Partition_%03d", this_part); 192 } 193 parts[this_part].name = extra_mem; 194 extra_mem += name_len + 1; 195 196 dbg(("partition %d: name <%s>, offset %x, size %x, mask flags %x\n", 197 this_part, 198 parts[this_part].name, 199 parts[this_part].offset, 200 parts[this_part].size, 201 parts[this_part].mask_flags)); 202 203 /* return (updated) pointer to extra_mem memory */ 204 if (extra_mem_ptr) 205 *extra_mem_ptr = extra_mem; 206 207 /* return (updated) pointer command line string */ 208 *retptr = s; 209 210 /* return partition table */ 211 return parts; 212} 213 214/* 215 * Parse the command line. 216 */ 217static int mtdpart_setup_real(char *s) 218{ 219 cmdline_parsed = 1; 220 221 for( ; s != NULL; ) 222 { 223 struct cmdline_mtd_partition *this_mtd; 224 struct mtd_partition *parts; 225 int mtd_id_len; 226 int num_parts; 227 char *p, *mtd_id; 228 229 mtd_id = s; 230 /* fetch <mtd-id> */ 231 if (!(p = strchr(s, ':'))) 232 { 233 printk(KERN_ERR ERRP "no mtd-id\n"); 234 return 0; 235 } 236 mtd_id_len = p - mtd_id; 237 238 dbg(("parsing <%s>\n", p+1)); 239 240 /* 241 * parse one mtd. have it reserve memory for the 242 * struct cmdline_mtd_partition and the mtd-id string. 243 */ 244 parts = newpart(p + 1, /* cmdline */ 245 &s, /* out: updated cmdline ptr */ 246 &num_parts, /* out: number of parts */ 247 0, /* first partition */ 248 (unsigned char**)&this_mtd, /* out: extra mem */ 249 mtd_id_len + 1 + sizeof(*this_mtd) + 250 sizeof(void*)-1 /*alignment*/); 251 if(!parts) 252 { 253 /* 254 * An error occurred. We're either: 255 * a) out of memory, or 256 * b) in the middle of the partition spec 257 * Either way, this mtd is hosed and we're 258 * unlikely to succeed in parsing any more 259 */ 260 return 0; 261 } 262 263 /* align this_mtd */ 264 this_mtd = (struct cmdline_mtd_partition *) 265 ALIGN((unsigned long)this_mtd, sizeof(void*)); 266 /* enter results */ 267 this_mtd->parts = parts; 268 this_mtd->num_parts = num_parts; 269 this_mtd->mtd_id = (char*)(this_mtd + 1); 270 strlcpy(this_mtd->mtd_id, mtd_id, mtd_id_len + 1); 271 272 /* link into chain */ 273 this_mtd->next = partitions; 274 partitions = this_mtd; 275 276 dbg(("mtdid=<%s> num_parts=<%d>\n", 277 this_mtd->mtd_id, this_mtd->num_parts)); 278 279 280 /* EOS - we're done */ 281 if (*s == 0) 282 break; 283 284 /* does another spec follow? */ 285 if (*s != ';') 286 { 287 printk(KERN_ERR ERRP "bad character after partition (%c)\n", *s); 288 return 0; 289 } 290 s++; 291 } 292 return 1; 293} 294 295/* 296 * Main function to be called from the MTD mapping driver/device to 297 * obtain the partitioning information. At this point the command line 298 * arguments will actually be parsed and turned to struct mtd_partition 299 * information. It returns partitions for the requested mtd device, or 300 * the first one in the chain if a NULL mtd_id is passed in. 301 */ 302static int parse_cmdline_partitions(struct mtd_info *master, 303 struct mtd_partition **pparts, 304 unsigned long origin) 305{ 306 unsigned long offset; 307 int i; 308 struct cmdline_mtd_partition *part; 309 char *mtd_id = master->name; 310 311 if(!cmdline) 312 return -EINVAL; 313 314 /* parse command line */ 315 if (!cmdline_parsed) 316 mtdpart_setup_real(cmdline); 317 318 for(part = partitions; part; part = part->next) 319 { 320 if ((!mtd_id) || (!strcmp(part->mtd_id, mtd_id))) 321 { 322 for(i = 0, offset = 0; i < part->num_parts; i++) 323 { 324 if (part->parts[i].offset == OFFSET_CONTINUOUS) 325 part->parts[i].offset = offset; 326 else 327 offset = part->parts[i].offset; 328 if (part->parts[i].size == SIZE_REMAINING) 329 part->parts[i].size = master->size - offset; 330 if (offset + part->parts[i].size > master->size) 331 { 332 printk(KERN_WARNING ERRP 333 "%s: partitioning exceeds flash size, truncating\n", 334 part->mtd_id); 335 part->parts[i].size = master->size - offset; 336 part->num_parts = i; 337 } 338 offset += part->parts[i].size; 339 } 340 *pparts = part->parts; 341 return part->num_parts; 342 } 343 } 344 return -EINVAL; 345} 346 347 348/* 349 * This is the handler for our kernel parameter, called from 350 * main.c::checksetup(). Note that we can not yet kmalloc() anything, 351 * so we only save the commandline for later processing. 352 * 353 * This function needs to be visible for bootloaders. 354 */ 355static int mtdpart_setup(char *s) 356{ 357 cmdline = s; 358 return 1; 359} 360 361__setup("mtdparts=", mtdpart_setup); 362 363static struct mtd_part_parser cmdline_parser = { 364 .owner = THIS_MODULE, 365 .parse_fn = parse_cmdline_partitions, 366 .name = "cmdlinepart", 367}; 368 369static int __init cmdline_parser_init(void) 370{ 371 return register_mtd_parser(&cmdline_parser); 372} 373 374module_init(cmdline_parser_init); 375 376MODULE_LICENSE("GPL"); 377MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>"); 378MODULE_DESCRIPTION("Command line configuration of MTD partitions");