diff options
Diffstat (limited to 'kernel/kexec.c')
-rw-r--r-- | kernel/kexec.c | 161 |
1 files changed, 121 insertions, 40 deletions
diff --git a/kernel/kexec.c b/kernel/kexec.c index bddd3d7a74b6..59f7b55ba745 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 |
@@ -786,7 +786,7 @@ static int kimage_load_normal_segment(struct kimage *image, | |||
786 | struct kexec_segment *segment) | 786 | struct kexec_segment *segment) |
787 | { | 787 | { |
788 | unsigned long maddr; | 788 | unsigned long maddr; |
789 | unsigned long ubytes, mbytes; | 789 | size_t ubytes, mbytes; |
790 | int result; | 790 | int result; |
791 | unsigned char __user *buf; | 791 | unsigned char __user *buf; |
792 | 792 | ||
@@ -819,13 +819,9 @@ static int kimage_load_normal_segment(struct kimage *image, | |||
819 | /* Start with a clear page */ | 819 | /* Start with a clear page */ |
820 | clear_page(ptr); | 820 | clear_page(ptr); |
821 | ptr += maddr & ~PAGE_MASK; | 821 | ptr += maddr & ~PAGE_MASK; |
822 | mchunk = PAGE_SIZE - (maddr & ~PAGE_MASK); | 822 | mchunk = min_t(size_t, mbytes, |
823 | if (mchunk > mbytes) | 823 | PAGE_SIZE - (maddr & ~PAGE_MASK)); |
824 | mchunk = mbytes; | 824 | uchunk = min(ubytes, mchunk); |
825 | |||
826 | uchunk = mchunk; | ||
827 | if (uchunk > ubytes) | ||
828 | uchunk = ubytes; | ||
829 | 825 | ||
830 | result = copy_from_user(ptr, buf, uchunk); | 826 | result = copy_from_user(ptr, buf, uchunk); |
831 | kunmap(page); | 827 | kunmap(page); |
@@ -850,7 +846,7 @@ static int kimage_load_crash_segment(struct kimage *image, | |||
850 | * We do things a page at a time for the sake of kmap. | 846 | * We do things a page at a time for the sake of kmap. |
851 | */ | 847 | */ |
852 | unsigned long maddr; | 848 | unsigned long maddr; |
853 | unsigned long ubytes, mbytes; | 849 | size_t ubytes, mbytes; |
854 | int result; | 850 | int result; |
855 | unsigned char __user *buf; | 851 | unsigned char __user *buf; |
856 | 852 | ||
@@ -871,13 +867,10 @@ static int kimage_load_crash_segment(struct kimage *image, | |||
871 | } | 867 | } |
872 | ptr = kmap(page); | 868 | ptr = kmap(page); |
873 | ptr += maddr & ~PAGE_MASK; | 869 | ptr += maddr & ~PAGE_MASK; |
874 | mchunk = PAGE_SIZE - (maddr & ~PAGE_MASK); | 870 | mchunk = min_t(size_t, mbytes, |
875 | if (mchunk > mbytes) | 871 | PAGE_SIZE - (maddr & ~PAGE_MASK)); |
876 | mchunk = mbytes; | 872 | uchunk = min(ubytes, mchunk); |
877 | 873 | if (mchunk > uchunk) { | |
878 | uchunk = mchunk; | ||
879 | if (uchunk > ubytes) { | ||
880 | uchunk = ubytes; | ||
881 | /* Zero the trailing part of the page */ | 874 | /* Zero the trailing part of the page */ |
882 | memset(ptr + uchunk, 0, mchunk - uchunk); | 875 | memset(ptr + uchunk, 0, mchunk - uchunk); |
883 | } | 876 | } |
@@ -1118,12 +1111,8 @@ void __weak crash_free_reserved_phys_range(unsigned long begin, | |||
1118 | { | 1111 | { |
1119 | unsigned long addr; | 1112 | unsigned long addr; |
1120 | 1113 | ||
1121 | for (addr = begin; addr < end; addr += PAGE_SIZE) { | 1114 | for (addr = begin; addr < end; addr += PAGE_SIZE) |
1122 | ClearPageReserved(pfn_to_page(addr >> PAGE_SHIFT)); | 1115 | free_reserved_page(pfn_to_page(addr >> PAGE_SHIFT)); |
1123 | init_page_count(pfn_to_page(addr >> PAGE_SHIFT)); | ||
1124 | free_page((unsigned long)__va(addr)); | ||
1125 | totalram_pages++; | ||
1126 | } | ||
1127 | } | 1116 | } |
1128 | 1117 | ||
1129 | int crash_shrink_memory(unsigned long new_size) | 1118 | int crash_shrink_memory(unsigned long new_size) |
@@ -1368,35 +1357,114 @@ static int __init parse_crashkernel_simple(char *cmdline, | |||
1368 | return 0; | 1357 | return 0; |
1369 | } | 1358 | } |
1370 | 1359 | ||
1360 | #define SUFFIX_HIGH 0 | ||
1361 | #define SUFFIX_LOW 1 | ||
1362 | #define SUFFIX_NULL 2 | ||
1363 | static __initdata char *suffix_tbl[] = { | ||
1364 | [SUFFIX_HIGH] = ",high", | ||
1365 | [SUFFIX_LOW] = ",low", | ||
1366 | [SUFFIX_NULL] = NULL, | ||
1367 | }; | ||
1368 | |||
1371 | /* | 1369 | /* |
1372 | * That function is the entry point for command line parsing and should be | 1370 | * That function parses "suffix" crashkernel command lines like |
1373 | * called from the arch-specific code. | 1371 | * |
1372 | * crashkernel=size,[high|low] | ||
1373 | * | ||
1374 | * It returns 0 on success and -EINVAL on failure. | ||
1374 | */ | 1375 | */ |
1376 | static int __init parse_crashkernel_suffix(char *cmdline, | ||
1377 | unsigned long long *crash_size, | ||
1378 | unsigned long long *crash_base, | ||
1379 | const char *suffix) | ||
1380 | { | ||
1381 | char *cur = cmdline; | ||
1382 | |||
1383 | *crash_size = memparse(cmdline, &cur); | ||
1384 | if (cmdline == cur) { | ||
1385 | pr_warn("crashkernel: memory value expected\n"); | ||
1386 | return -EINVAL; | ||
1387 | } | ||
1388 | |||
1389 | /* check with suffix */ | ||
1390 | if (strncmp(cur, suffix, strlen(suffix))) { | ||
1391 | pr_warn("crashkernel: unrecognized char\n"); | ||
1392 | return -EINVAL; | ||
1393 | } | ||
1394 | cur += strlen(suffix); | ||
1395 | if (*cur != ' ' && *cur != '\0') { | ||
1396 | pr_warn("crashkernel: unrecognized char\n"); | ||
1397 | return -EINVAL; | ||
1398 | } | ||
1399 | |||
1400 | return 0; | ||
1401 | } | ||
1402 | |||
1403 | static __init char *get_last_crashkernel(char *cmdline, | ||
1404 | const char *name, | ||
1405 | const char *suffix) | ||
1406 | { | ||
1407 | char *p = cmdline, *ck_cmdline = NULL; | ||
1408 | |||
1409 | /* find crashkernel and use the last one if there are more */ | ||
1410 | p = strstr(p, name); | ||
1411 | while (p) { | ||
1412 | char *end_p = strchr(p, ' '); | ||
1413 | char *q; | ||
1414 | |||
1415 | if (!end_p) | ||
1416 | end_p = p + strlen(p); | ||
1417 | |||
1418 | if (!suffix) { | ||
1419 | int i; | ||
1420 | |||
1421 | /* skip the one with any known suffix */ | ||
1422 | for (i = 0; suffix_tbl[i]; i++) { | ||
1423 | q = end_p - strlen(suffix_tbl[i]); | ||
1424 | if (!strncmp(q, suffix_tbl[i], | ||
1425 | strlen(suffix_tbl[i]))) | ||
1426 | goto next; | ||
1427 | } | ||
1428 | ck_cmdline = p; | ||
1429 | } else { | ||
1430 | q = end_p - strlen(suffix); | ||
1431 | if (!strncmp(q, suffix, strlen(suffix))) | ||
1432 | ck_cmdline = p; | ||
1433 | } | ||
1434 | next: | ||
1435 | p = strstr(p+1, name); | ||
1436 | } | ||
1437 | |||
1438 | if (!ck_cmdline) | ||
1439 | return NULL; | ||
1440 | |||
1441 | return ck_cmdline; | ||
1442 | } | ||
1443 | |||
1375 | static int __init __parse_crashkernel(char *cmdline, | 1444 | static int __init __parse_crashkernel(char *cmdline, |
1376 | unsigned long long system_ram, | 1445 | unsigned long long system_ram, |
1377 | unsigned long long *crash_size, | 1446 | unsigned long long *crash_size, |
1378 | unsigned long long *crash_base, | 1447 | unsigned long long *crash_base, |
1379 | const char *name) | 1448 | const char *name, |
1449 | const char *suffix) | ||
1380 | { | 1450 | { |
1381 | char *p = cmdline, *ck_cmdline = NULL; | ||
1382 | char *first_colon, *first_space; | 1451 | char *first_colon, *first_space; |
1452 | char *ck_cmdline; | ||
1383 | 1453 | ||
1384 | BUG_ON(!crash_size || !crash_base); | 1454 | BUG_ON(!crash_size || !crash_base); |
1385 | *crash_size = 0; | 1455 | *crash_size = 0; |
1386 | *crash_base = 0; | 1456 | *crash_base = 0; |
1387 | 1457 | ||
1388 | /* find crashkernel and use the last one if there are more */ | 1458 | 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 | 1459 | ||
1395 | if (!ck_cmdline) | 1460 | if (!ck_cmdline) |
1396 | return -EINVAL; | 1461 | return -EINVAL; |
1397 | 1462 | ||
1398 | ck_cmdline += strlen(name); | 1463 | ck_cmdline += strlen(name); |
1399 | 1464 | ||
1465 | if (suffix) | ||
1466 | return parse_crashkernel_suffix(ck_cmdline, crash_size, | ||
1467 | crash_base, suffix); | ||
1400 | /* | 1468 | /* |
1401 | * if the commandline contains a ':', then that's the extended | 1469 | * if the commandline contains a ':', then that's the extended |
1402 | * syntax -- if not, it must be the classic syntax | 1470 | * syntax -- if not, it must be the classic syntax |
@@ -1413,13 +1481,26 @@ static int __init __parse_crashkernel(char *cmdline, | |||
1413 | return 0; | 1481 | return 0; |
1414 | } | 1482 | } |
1415 | 1483 | ||
1484 | /* | ||
1485 | * That function is the entry point for command line parsing and should be | ||
1486 | * called from the arch-specific code. | ||
1487 | */ | ||
1416 | int __init parse_crashkernel(char *cmdline, | 1488 | int __init parse_crashkernel(char *cmdline, |
1417 | unsigned long long system_ram, | 1489 | unsigned long long system_ram, |
1418 | unsigned long long *crash_size, | 1490 | unsigned long long *crash_size, |
1419 | unsigned long long *crash_base) | 1491 | unsigned long long *crash_base) |
1420 | { | 1492 | { |
1421 | return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base, | 1493 | return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base, |
1422 | "crashkernel="); | 1494 | "crashkernel=", NULL); |
1495 | } | ||
1496 | |||
1497 | int __init parse_crashkernel_high(char *cmdline, | ||
1498 | unsigned long long system_ram, | ||
1499 | unsigned long long *crash_size, | ||
1500 | unsigned long long *crash_base) | ||
1501 | { | ||
1502 | return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base, | ||
1503 | "crashkernel=", suffix_tbl[SUFFIX_HIGH]); | ||
1423 | } | 1504 | } |
1424 | 1505 | ||
1425 | int __init parse_crashkernel_low(char *cmdline, | 1506 | int __init parse_crashkernel_low(char *cmdline, |
@@ -1428,7 +1509,7 @@ int __init parse_crashkernel_low(char *cmdline, | |||
1428 | unsigned long long *crash_base) | 1509 | unsigned long long *crash_base) |
1429 | { | 1510 | { |
1430 | return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base, | 1511 | return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base, |
1431 | "crashkernel_low="); | 1512 | "crashkernel=", suffix_tbl[SUFFIX_LOW]); |
1432 | } | 1513 | } |
1433 | 1514 | ||
1434 | static void update_vmcoreinfo_note(void) | 1515 | static void update_vmcoreinfo_note(void) |
@@ -1452,14 +1533,13 @@ void vmcoreinfo_append_str(const char *fmt, ...) | |||
1452 | { | 1533 | { |
1453 | va_list args; | 1534 | va_list args; |
1454 | char buf[0x50]; | 1535 | char buf[0x50]; |
1455 | int r; | 1536 | size_t r; |
1456 | 1537 | ||
1457 | va_start(args, fmt); | 1538 | va_start(args, fmt); |
1458 | r = vsnprintf(buf, sizeof(buf), fmt, args); | 1539 | r = vsnprintf(buf, sizeof(buf), fmt, args); |
1459 | va_end(args); | 1540 | va_end(args); |
1460 | 1541 | ||
1461 | if (r + vmcoreinfo_size > vmcoreinfo_max_size) | 1542 | r = min(r, vmcoreinfo_max_size - vmcoreinfo_size); |
1462 | r = vmcoreinfo_max_size - vmcoreinfo_size; | ||
1463 | 1543 | ||
1464 | memcpy(&vmcoreinfo_data[vmcoreinfo_size], buf, r); | 1544 | memcpy(&vmcoreinfo_data[vmcoreinfo_size], buf, r); |
1465 | 1545 | ||
@@ -1489,7 +1569,7 @@ static int __init crash_save_vmcoreinfo_init(void) | |||
1489 | VMCOREINFO_SYMBOL(swapper_pg_dir); | 1569 | VMCOREINFO_SYMBOL(swapper_pg_dir); |
1490 | #endif | 1570 | #endif |
1491 | VMCOREINFO_SYMBOL(_stext); | 1571 | VMCOREINFO_SYMBOL(_stext); |
1492 | VMCOREINFO_SYMBOL(vmlist); | 1572 | VMCOREINFO_SYMBOL(vmap_area_list); |
1493 | 1573 | ||
1494 | #ifndef CONFIG_NEED_MULTIPLE_NODES | 1574 | #ifndef CONFIG_NEED_MULTIPLE_NODES |
1495 | VMCOREINFO_SYMBOL(mem_map); | 1575 | VMCOREINFO_SYMBOL(mem_map); |
@@ -1527,7 +1607,8 @@ static int __init crash_save_vmcoreinfo_init(void) | |||
1527 | VMCOREINFO_OFFSET(free_area, free_list); | 1607 | VMCOREINFO_OFFSET(free_area, free_list); |
1528 | VMCOREINFO_OFFSET(list_head, next); | 1608 | VMCOREINFO_OFFSET(list_head, next); |
1529 | VMCOREINFO_OFFSET(list_head, prev); | 1609 | VMCOREINFO_OFFSET(list_head, prev); |
1530 | VMCOREINFO_OFFSET(vm_struct, addr); | 1610 | VMCOREINFO_OFFSET(vmap_area, va_start); |
1611 | VMCOREINFO_OFFSET(vmap_area, list); | ||
1531 | VMCOREINFO_LENGTH(zone.free_area, MAX_ORDER); | 1612 | VMCOREINFO_LENGTH(zone.free_area, MAX_ORDER); |
1532 | log_buf_kexec_setup(); | 1613 | log_buf_kexec_setup(); |
1533 | VMCOREINFO_LENGTH(free_area.free_list, MIGRATE_TYPES); | 1614 | VMCOREINFO_LENGTH(free_area.free_list, MIGRATE_TYPES); |