diff options
-rw-r--r-- | Documentation/kernel-parameters.txt | 10 | ||||
-rw-r--r-- | arch/x86/kernel/setup.c | 6 | ||||
-rw-r--r-- | kernel/kexec.c | 109 |
3 files changed, 104 insertions, 21 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 709eb3edc6b2..a1ac1f1d6d34 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
@@ -603,16 +603,16 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | |||
603 | a memory unit (amount[KMG]). See also | 603 | a memory unit (amount[KMG]). See also |
604 | Documentation/kdump/kdump.txt for an example. | 604 | Documentation/kdump/kdump.txt for an example. |
605 | 605 | ||
606 | crashkernel_high=size[KMG] | 606 | crashkernel=size[KMG],high |
607 | [KNL, x86_64] range could be above 4G. Allow kernel | 607 | [KNL, x86_64] range could be above 4G. Allow kernel |
608 | to allocate physical memory region from top, so could | 608 | to allocate physical memory region from top, so could |
609 | be above 4G if system have more than 4G ram installed. | 609 | be above 4G if system have more than 4G ram installed. |
610 | Otherwise memory region will be allocated below 4G, if | 610 | Otherwise memory region will be allocated below 4G, if |
611 | available. | 611 | available. |
612 | It will be ignored if crashkernel=X is specified. | 612 | It will be ignored if crashkernel=X is specified. |
613 | crashkernel_low=size[KMG] | 613 | crashkernel=size[KMG],low |
614 | [KNL, x86_64] range under 4G. When crashkernel_high= is | 614 | [KNL, x86_64] range under 4G. When crashkernel=X,high |
615 | passed, kernel could allocate physical memory region | 615 | is passed, kernel could allocate physical memory region |
616 | above 4G, that cause second kernel crash on system | 616 | above 4G, that cause second kernel crash on system |
617 | that require some amount of low memory, e.g. swiotlb | 617 | that require some amount of low memory, e.g. swiotlb |
618 | requires at least 64M+32K low memory. Kernel would | 618 | requires at least 64M+32K low memory. Kernel would |
@@ -620,7 +620,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | |||
620 | This one let user to specify own low range under 4G | 620 | This one let user to specify own low range under 4G |
621 | for second kernel instead. | 621 | for second kernel instead. |
622 | 0: to disable low allocation. | 622 | 0: to disable low allocation. |
623 | It will be ignored when crashkernel_high=X is not used | 623 | It will be ignored when crashkernel=X,high is not used |
624 | or memory reserved is below 4G. | 624 | or memory reserved is below 4G. |
625 | 625 | ||
626 | cs89x0_dma= [HW,NET] | 626 | cs89x0_dma= [HW,NET] |
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index a85a144f2052..fae9134a2de9 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c | |||
@@ -528,7 +528,7 @@ static void __init reserve_crashkernel_low(void) | |||
528 | int ret; | 528 | int ret; |
529 | 529 | ||
530 | total_low_mem = memblock_mem_size(1UL<<(32-PAGE_SHIFT)); | 530 | total_low_mem = memblock_mem_size(1UL<<(32-PAGE_SHIFT)); |
531 | /* crashkernel_low=YM */ | 531 | /* crashkernel=Y,low */ |
532 | ret = parse_crashkernel_low(boot_command_line, total_low_mem, | 532 | ret = parse_crashkernel_low(boot_command_line, total_low_mem, |
533 | &low_size, &base); | 533 | &low_size, &base); |
534 | if (ret != 0) { | 534 | if (ret != 0) { |
@@ -542,7 +542,7 @@ static void __init reserve_crashkernel_low(void) | |||
542 | low_size = swiotlb_size_or_default() + (8UL<<20); | 542 | low_size = swiotlb_size_or_default() + (8UL<<20); |
543 | auto_set = true; | 543 | auto_set = true; |
544 | } else { | 544 | } else { |
545 | /* passed with crashkernel_low=0 ? */ | 545 | /* passed with crashkernel=0,low ? */ |
546 | if (!low_size) | 546 | if (!low_size) |
547 | return; | 547 | return; |
548 | } | 548 | } |
@@ -582,7 +582,7 @@ static void __init reserve_crashkernel(void) | |||
582 | ret = parse_crashkernel(boot_command_line, total_mem, | 582 | ret = parse_crashkernel(boot_command_line, total_mem, |
583 | &crash_size, &crash_base); | 583 | &crash_size, &crash_base); |
584 | if (ret != 0 || crash_size <= 0) { | 584 | if (ret != 0 || crash_size <= 0) { |
585 | /* crashkernel_high=XM */ | 585 | /* crashkernel=X,high */ |
586 | ret = parse_crashkernel_high(boot_command_line, total_mem, | 586 | ret = parse_crashkernel_high(boot_command_line, total_mem, |
587 | &crash_size, &crash_base); | 587 | &crash_size, &crash_base); |
588 | if (ret != 0 || crash_size <= 0) | 588 | if (ret != 0 || crash_size <= 0) |
diff --git a/kernel/kexec.c b/kernel/kexec.c index 1b2f73f5f9b9..401fdb041f35 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c | |||
@@ -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,17 @@ 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); |
1423 | } | 1506 | } |
1424 | 1507 | ||
1425 | int __init parse_crashkernel_high(char *cmdline, | 1508 | int __init parse_crashkernel_high(char *cmdline, |
@@ -1428,7 +1511,7 @@ int __init parse_crashkernel_high(char *cmdline, | |||
1428 | unsigned long long *crash_base) | 1511 | unsigned long long *crash_base) |
1429 | { | 1512 | { |
1430 | return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base, | 1513 | return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base, |
1431 | "crashkernel_high="); | 1514 | "crashkernel=", suffix_tbl[SUFFIX_HIGH]); |
1432 | } | 1515 | } |
1433 | 1516 | ||
1434 | int __init parse_crashkernel_low(char *cmdline, | 1517 | int __init parse_crashkernel_low(char *cmdline, |
@@ -1437,7 +1520,7 @@ int __init parse_crashkernel_low(char *cmdline, | |||
1437 | unsigned long long *crash_base) | 1520 | unsigned long long *crash_base) |
1438 | { | 1521 | { |
1439 | return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base, | 1522 | return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base, |
1440 | "crashkernel_low="); | 1523 | "crashkernel=", suffix_tbl[SUFFIX_LOW]); |
1441 | } | 1524 | } |
1442 | 1525 | ||
1443 | static void update_vmcoreinfo_note(void) | 1526 | static void update_vmcoreinfo_note(void) |