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][slc] 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, add_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 add_flags = 0; 113 delim = 0; 114 115 /* check for offset */ 116 if (*s == '@') { 117 s++; 118 offset = memparse(s, &s); 119 } 120 121 /* now look for name */ 122 if (*s == '(') 123 delim = ')'; 124 125 if (delim) { 126 char *p; 127 128 name = ++s; 129 p = strchr(name, delim); 130 if (!p) { 131 pr_err("no closing %c found in partition name\n", delim); 132 return ERR_PTR(-EINVAL); 133 } 134 name_len = p - name; 135 s = p + 1; 136 } else { 137 name = NULL; 138 name_len = 13; /* Partition_000 */ 139 } 140 141 /* record name length for memory allocation later */ 142 extra_mem_size += name_len + 1; 143 144 /* test for options */ 145 if (strncmp(s, "ro", 2) == 0) { 146 mask_flags |= MTD_WRITEABLE; 147 s += 2; 148 } 149 150 /* if lk is found do NOT unlock the MTD partition*/ 151 if (strncmp(s, "lk", 2) == 0) { 152 mask_flags |= MTD_POWERUP_LOCK; 153 s += 2; 154 } 155 156 /* if slc is found use emulated SLC mode on this partition*/ 157 if (!strncmp(s, "slc", 3)) { 158 add_flags |= MTD_SLC_ON_MLC_EMULATION; 159 s += 3; 160 } 161 162 /* test if more partitions are following */ 163 if (*s == ',') { 164 if (size == SIZE_REMAINING) { 165 pr_err("no partitions allowed after a fill-up partition\n"); 166 return ERR_PTR(-EINVAL); 167 } 168 /* more partitions follow, parse them */ 169 parts = newpart(s + 1, &s, num_parts, this_part + 1, 170 &extra_mem, extra_mem_size); 171 if (IS_ERR(parts)) 172 return parts; 173 } else { 174 /* this is the last partition: allocate space for all */ 175 int alloc_size; 176 177 *num_parts = this_part + 1; 178 alloc_size = *num_parts * sizeof(struct mtd_partition) + 179 extra_mem_size; 180 181 parts = kzalloc(alloc_size, GFP_KERNEL); 182 if (!parts) 183 return ERR_PTR(-ENOMEM); 184 extra_mem = (unsigned char *)(parts + *num_parts); 185 } 186 187 /* 188 * enter this partition (offset will be calculated later if it is 189 * OFFSET_CONTINUOUS at this point) 190 */ 191 parts[this_part].size = size; 192 parts[this_part].offset = offset; 193 parts[this_part].mask_flags = mask_flags; 194 parts[this_part].add_flags = add_flags; 195 if (name) 196 strlcpy(extra_mem, name, name_len + 1); 197 else 198 sprintf(extra_mem, "Partition_%03d", this_part); 199 parts[this_part].name = extra_mem; 200 extra_mem += name_len + 1; 201 202 dbg(("partition %d: name <%s>, offset %llx, size %llx, mask flags %x\n", 203 this_part, parts[this_part].name, parts[this_part].offset, 204 parts[this_part].size, parts[this_part].mask_flags)); 205 206 /* return (updated) pointer to extra_mem memory */ 207 if (extra_mem_ptr) 208 *extra_mem_ptr = extra_mem; 209 210 /* return (updated) pointer command line string */ 211 *retptr = s; 212 213 /* return partition table */ 214 return parts; 215 } 216 217 /* 218 * Parse the command line. 219 */ 220 static int mtdpart_setup_real(char *s) 221 { 222 cmdline_parsed = 1; 223 224 for( ; s != NULL; ) 225 { 226 struct cmdline_mtd_partition *this_mtd; 227 struct mtd_partition *parts; 228 int mtd_id_len, num_parts; 229 char *p, *mtd_id, *semicol; 230 231 /* 232 * Replace the first ';' by a NULL char so strrchr can work 233 * properly. 234 */ 235 semicol = strchr(s, ';'); 236 if (semicol) 237 *semicol = '\0'; 238 239 mtd_id = s; 240 241 /* 242 * fetch <mtd-id>. We use strrchr to ignore all ':' that could 243 * be present in the MTD name, only the last one is interpreted 244 * as an <mtd-id>/<part-definition> separator. 245 */ 246 p = strrchr(s, ':'); 247 248 /* Restore the ';' now. */ 249 if (semicol) 250 *semicol = ';'; 251 252 if (!p) { 253 pr_err("no mtd-id\n"); 254 return -EINVAL; 255 } 256 mtd_id_len = p - mtd_id; 257 258 dbg(("parsing <%s>\n", p+1)); 259 260 /* 261 * parse one mtd. have it reserve memory for the 262 * struct cmdline_mtd_partition and the mtd-id string. 263 */ 264 parts = newpart(p + 1, /* cmdline */ 265 &s, /* out: updated cmdline ptr */ 266 &num_parts, /* out: number of parts */ 267 0, /* first partition */ 268 (unsigned char**)&this_mtd, /* out: extra mem */ 269 mtd_id_len + 1 + sizeof(*this_mtd) + 270 sizeof(void*)-1 /*alignment*/); 271 if (IS_ERR(parts)) { 272 /* 273 * An error occurred. We're either: 274 * a) out of memory, or 275 * b) in the middle of the partition spec 276 * Either way, this mtd is hosed and we're 277 * unlikely to succeed in parsing any more 278 */ 279 return PTR_ERR(parts); 280 } 281 282 /* align this_mtd */ 283 this_mtd = (struct cmdline_mtd_partition *) 284 ALIGN((unsigned long)this_mtd, sizeof(void *)); 285 /* enter results */ 286 this_mtd->parts = parts; 287 this_mtd->num_parts = num_parts; 288 this_mtd->mtd_id = (char*)(this_mtd + 1); 289 strlcpy(this_mtd->mtd_id, mtd_id, mtd_id_len + 1); 290 291 /* link into chain */ 292 this_mtd->next = partitions; 293 partitions = this_mtd; 294 295 dbg(("mtdid=<%s> num_parts=<%d>\n", 296 this_mtd->mtd_id, this_mtd->num_parts)); 297 298 299 /* EOS - we're done */ 300 if (*s == 0) 301 break; 302 303 /* does another spec follow? */ 304 if (*s != ';') { 305 pr_err("bad character after partition (%c)\n", *s); 306 return -EINVAL; 307 } 308 s++; 309 } 310 311 return 0; 312 } 313 314 /* 315 * Main function to be called from the MTD mapping driver/device to 316 * obtain the partitioning information. At this point the command line 317 * arguments will actually be parsed and turned to struct mtd_partition 318 * information. It returns partitions for the requested mtd device, or 319 * the first one in the chain if a NULL mtd_id is passed in. 320 */ 321 static int parse_cmdline_partitions(struct mtd_info *master, 322 const struct mtd_partition **pparts, 323 struct mtd_part_parser_data *data) 324 { 325 unsigned long long offset; 326 int i, err; 327 struct cmdline_mtd_partition *part; 328 const char *mtd_id = master->name; 329 330 /* parse command line */ 331 if (!cmdline_parsed) { 332 err = mtdpart_setup_real(cmdline); 333 if (err) 334 return err; 335 } 336 337 /* 338 * Search for the partition definition matching master->name. 339 * If master->name is not set, stop at first partition definition. 340 */ 341 for (part = partitions; part; part = part->next) { 342 if ((!mtd_id) || (!strcmp(part->mtd_id, mtd_id))) 343 break; 344 } 345 346 if (!part) 347 return 0; 348 349 for (i = 0, offset = 0; i < part->num_parts; i++) { 350 if (part->parts[i].offset == OFFSET_CONTINUOUS) 351 part->parts[i].offset = offset; 352 else 353 offset = part->parts[i].offset; 354 355 if (part->parts[i].size == SIZE_REMAINING) 356 part->parts[i].size = master->size - offset; 357 358 if (offset + part->parts[i].size > master->size) { 359 pr_warn("%s: partitioning exceeds flash size, truncating\n", 360 part->mtd_id); 361 part->parts[i].size = master->size - offset; 362 } 363 offset += part->parts[i].size; 364 365 if (part->parts[i].size == 0) { 366 pr_warn("%s: skipping zero sized partition\n", 367 part->mtd_id); 368 part->num_parts--; 369 memmove(&part->parts[i], &part->parts[i + 1], 370 sizeof(*part->parts) * (part->num_parts - i)); 371 i--; 372 } 373 } 374 375 *pparts = kmemdup(part->parts, sizeof(*part->parts) * part->num_parts, 376 GFP_KERNEL); 377 if (!*pparts) 378 return -ENOMEM; 379 380 return part->num_parts; 381 } 382 383 384 /* 385 * This is the handler for our kernel parameter, called from 386 * main.c::checksetup(). Note that we can not yet kmalloc() anything, 387 * so we only save the commandline for later processing. 388 * 389 * This function needs to be visible for bootloaders. 390 */ 391 static int __init mtdpart_setup(char *s) 392 { 393 cmdline = s; 394 return 1; 395 } 396 397 __setup("mtdparts=", mtdpart_setup); 398 399 static struct mtd_part_parser cmdline_parser = { 400 .parse_fn = parse_cmdline_partitions, 401 .name = "cmdlinepart", 402 }; 403 404 static int __init cmdline_parser_init(void) 405 { 406 if (mtdparts) 407 mtdpart_setup(mtdparts); 408 register_mtd_parser(&cmdline_parser); 409 return 0; 410 } 411 412 static void __exit cmdline_parser_exit(void) 413 { 414 deregister_mtd_parser(&cmdline_parser); 415 } 416 417 module_init(cmdline_parser_init); 418 module_exit(cmdline_parser_exit); 419 420 MODULE_PARM_DESC(mtdparts, "Partitioning specification"); 421 module_param(mtdparts, charp, 0); 422 423 MODULE_LICENSE("GPL"); 424 MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>"); 425 MODULE_DESCRIPTION("Command line configuration of MTD partitions"); 426