diff options
Diffstat (limited to 'kernel/kexec.c')
-rw-r--r-- | kernel/kexec.c | 118 |
1 files changed, 105 insertions, 13 deletions
diff --git a/kernel/kexec.c b/kernel/kexec.c index bddd3d7a74b6..ffd4e111fd67 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c | |||
@@ -55,7 +55,7 @@ struct resource crashk_res = { | |||
55 | .flags = IORESOURCE_BUSY | IORESOURCE_MEM | 55 | .flags = IORESOURCE_BUSY | IORESOURCE_MEM |
56 | }; | 56 | }; |
57 | struct resource crashk_low_res = { | 57 | struct resource crashk_low_res = { |
58 | .name = "Crash kernel low", | 58 | .name = "Crash kernel", |
59 | .start = 0, | 59 | .start = 0, |
60 | .end = 0, | 60 | .end = 0, |
61 | .flags = IORESOURCE_BUSY | IORESOURCE_MEM | 61 | .flags = IORESOURCE_BUSY | IORESOURCE_MEM |
@@ -1368,35 +1368,114 @@ static int __init parse_crashkernel_simple(char *cmdline, | |||
1368 | return 0; | 1368 | return 0; |
1369 | } | 1369 | } |
1370 | 1370 | ||
1371 | #define SUFFIX_HIGH 0 | ||
1372 | #define SUFFIX_LOW 1 | ||
1373 | #define SUFFIX_NULL 2 | ||
1374 | static __initdata char *suffix_tbl[] = { | ||
1375 | [SUFFIX_HIGH] = ",high", | ||
1376 | [SUFFIX_LOW] = ",low", | ||
1377 | [SUFFIX_NULL] = NULL, | ||
1378 | }; | ||
1379 | |||
1371 | /* | 1380 | /* |
1372 | * That function is the entry point for command line parsing and should be | 1381 | * That function parses "suffix" crashkernel command lines like |
1373 | * called from the arch-specific code. | 1382 | * |
1383 | * crashkernel=size,[high|low] | ||
1384 | * | ||
1385 | * It returns 0 on success and -EINVAL on failure. | ||
1374 | */ | 1386 | */ |
1387 | static int __init parse_crashkernel_suffix(char *cmdline, | ||
1388 | unsigned long long *crash_size, | ||
1389 | unsigned long long *crash_base, | ||
1390 | const char *suffix) | ||
1391 | { | ||
1392 | char *cur = cmdline; | ||
1393 | |||
1394 | *crash_size = memparse(cmdline, &cur); | ||
1395 | if (cmdline == cur) { | ||
1396 | pr_warn("crashkernel: memory value expected\n"); | ||
1397 | return -EINVAL; | ||
1398 | } | ||
1399 | |||
1400 | /* check with suffix */ | ||
1401 | if (strncmp(cur, suffix, strlen(suffix))) { | ||
1402 | pr_warn("crashkernel: unrecognized char\n"); | ||
1403 | return -EINVAL; | ||
1404 | } | ||
1405 | cur += strlen(suffix); | ||
1406 | if (*cur != ' ' && *cur != '\0') { | ||
1407 | pr_warn("crashkernel: unrecognized char\n"); | ||
1408 | return -EINVAL; | ||
1409 | } | ||
1410 | |||
1411 | return 0; | ||
1412 | } | ||
1413 | |||
1414 | static __init char *get_last_crashkernel(char *cmdline, | ||
1415 | const char *name, | ||
1416 | const char *suffix) | ||
1417 | { | ||
1418 | char *p = cmdline, *ck_cmdline = NULL; | ||
1419 | |||
1420 | /* find crashkernel and use the last one if there are more */ | ||
1421 | p = strstr(p, name); | ||
1422 | while (p) { | ||
1423 | char *end_p = strchr(p, ' '); | ||
1424 | char *q; | ||
1425 | |||
1426 | if (!end_p) | ||
1427 | end_p = p + strlen(p); | ||
1428 | |||
1429 | if (!suffix) { | ||
1430 | int i; | ||
1431 | |||
1432 | /* skip the one with any known suffix */ | ||
1433 | for (i = 0; suffix_tbl[i]; i++) { | ||
1434 | q = end_p - strlen(suffix_tbl[i]); | ||
1435 | if (!strncmp(q, suffix_tbl[i], | ||
1436 | strlen(suffix_tbl[i]))) | ||
1437 | goto next; | ||
1438 | } | ||
1439 | ck_cmdline = p; | ||
1440 | } else { | ||
1441 | q = end_p - strlen(suffix); | ||
1442 | if (!strncmp(q, suffix, strlen(suffix))) | ||
1443 | ck_cmdline = p; | ||
1444 | } | ||
1445 | next: | ||
1446 | p = strstr(p+1, name); | ||
1447 | } | ||
1448 | |||
1449 | if (!ck_cmdline) | ||
1450 | return NULL; | ||
1451 | |||
1452 | return ck_cmdline; | ||
1453 | } | ||
1454 | |||
1375 | static int __init __parse_crashkernel(char *cmdline, | 1455 | static int __init __parse_crashkernel(char *cmdline, |
1376 | unsigned long long system_ram, | 1456 | unsigned long long system_ram, |
1377 | unsigned long long *crash_size, | 1457 | unsigned long long *crash_size, |
1378 | unsigned long long *crash_base, | 1458 | unsigned long long *crash_base, |
1379 | const char *name) | 1459 | const char *name, |
1460 | const char *suffix) | ||
1380 | { | 1461 | { |
1381 | char *p = cmdline, *ck_cmdline = NULL; | ||
1382 | char *first_colon, *first_space; | 1462 | char *first_colon, *first_space; |
1463 | char *ck_cmdline; | ||
1383 | 1464 | ||
1384 | BUG_ON(!crash_size || !crash_base); | 1465 | BUG_ON(!crash_size || !crash_base); |
1385 | *crash_size = 0; | 1466 | *crash_size = 0; |
1386 | *crash_base = 0; | 1467 | *crash_base = 0; |
1387 | 1468 | ||
1388 | /* find crashkernel and use the last one if there are more */ | 1469 | ck_cmdline = get_last_crashkernel(cmdline, name, suffix); |
1389 | p = strstr(p, name); | ||
1390 | while (p) { | ||
1391 | ck_cmdline = p; | ||
1392 | p = strstr(p+1, name); | ||
1393 | } | ||
1394 | 1470 | ||
1395 | if (!ck_cmdline) | 1471 | if (!ck_cmdline) |
1396 | return -EINVAL; | 1472 | return -EINVAL; |
1397 | 1473 | ||
1398 | ck_cmdline += strlen(name); | 1474 | ck_cmdline += strlen(name); |
1399 | 1475 | ||
1476 | if (suffix) | ||
1477 | return parse_crashkernel_suffix(ck_cmdline, crash_size, | ||
1478 | crash_base, suffix); | ||
1400 | /* | 1479 | /* |
1401 | * if the commandline contains a ':', then that's the extended | 1480 | * if the commandline contains a ':', then that's the extended |
1402 | * syntax -- if not, it must be the classic syntax | 1481 | * syntax -- if not, it must be the classic syntax |
@@ -1413,13 +1492,26 @@ static int __init __parse_crashkernel(char *cmdline, | |||
1413 | return 0; | 1492 | return 0; |
1414 | } | 1493 | } |
1415 | 1494 | ||
1495 | /* | ||
1496 | * That function is the entry point for command line parsing and should be | ||
1497 | * called from the arch-specific code. | ||
1498 | */ | ||
1416 | int __init parse_crashkernel(char *cmdline, | 1499 | int __init parse_crashkernel(char *cmdline, |
1417 | unsigned long long system_ram, | 1500 | unsigned long long system_ram, |
1418 | unsigned long long *crash_size, | 1501 | unsigned long long *crash_size, |
1419 | unsigned long long *crash_base) | 1502 | unsigned long long *crash_base) |
1420 | { | 1503 | { |
1421 | return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base, | 1504 | return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base, |
1422 | "crashkernel="); | 1505 | "crashkernel=", NULL); |
1506 | } | ||
1507 | |||
1508 | int __init parse_crashkernel_high(char *cmdline, | ||
1509 | unsigned long long system_ram, | ||
1510 | unsigned long long *crash_size, | ||
1511 | unsigned long long *crash_base) | ||
1512 | { | ||
1513 | return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base, | ||
1514 | "crashkernel=", suffix_tbl[SUFFIX_HIGH]); | ||
1423 | } | 1515 | } |
1424 | 1516 | ||
1425 | int __init parse_crashkernel_low(char *cmdline, | 1517 | int __init parse_crashkernel_low(char *cmdline, |
@@ -1428,7 +1520,7 @@ int __init parse_crashkernel_low(char *cmdline, | |||
1428 | unsigned long long *crash_base) | 1520 | unsigned long long *crash_base) |
1429 | { | 1521 | { |
1430 | return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base, | 1522 | return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base, |
1431 | "crashkernel_low="); | 1523 | "crashkernel=", suffix_tbl[SUFFIX_LOW]); |
1432 | } | 1524 | } |
1433 | 1525 | ||
1434 | static void update_vmcoreinfo_note(void) | 1526 | static void update_vmcoreinfo_note(void) |