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