|
5 | 5 | */
|
6 | 6 |
|
7 | 7 | #include <linux/buildid.h>
|
8 |
| -#include <linux/crash_core.h> |
9 | 8 | #include <linux/init.h>
|
10 | 9 | #include <linux/utsname.h>
|
11 | 10 | #include <linux/vmalloc.h>
|
12 | 11 | #include <linux/sizes.h>
|
13 | 12 | #include <linux/kexec.h>
|
14 | 13 | #include <linux/memory.h>
|
15 | 14 | #include <linux/cpuhotplug.h>
|
| 15 | +#include <linux/memblock.h> |
| 16 | +#include <linux/kexec.h> |
| 17 | +#include <linux/kmemleak.h> |
16 | 18 |
|
17 | 19 | #include <asm/page.h>
|
18 | 20 | #include <asm/sections.h>
|
@@ -360,6 +362,109 @@ static int __init parse_crashkernel_dummy(char *arg)
|
360 | 362 | }
|
361 | 363 | early_param("crashkernel", parse_crashkernel_dummy);
|
362 | 364 |
|
| 365 | +#ifdef CONFIG_ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION |
| 366 | +static int __init reserve_crashkernel_low(unsigned long long low_size) |
| 367 | +{ |
| 368 | +#ifdef CONFIG_64BIT |
| 369 | + unsigned long long low_base; |
| 370 | + |
| 371 | + low_base = memblock_phys_alloc_range(low_size, CRASH_ALIGN, 0, CRASH_ADDR_LOW_MAX); |
| 372 | + if (!low_base) { |
| 373 | + pr_err("cannot allocate crashkernel low memory (size:0x%llx).\n", low_size); |
| 374 | + return -ENOMEM; |
| 375 | + } |
| 376 | + |
| 377 | + pr_info("crashkernel low memory reserved: 0x%08llx - 0x%08llx (%lld MB)\n", |
| 378 | + low_base, low_base + low_size, low_size >> 20); |
| 379 | + |
| 380 | + crashk_low_res.start = low_base; |
| 381 | + crashk_low_res.end = low_base + low_size - 1; |
| 382 | + insert_resource(&iomem_resource, &crashk_low_res); |
| 383 | +#endif |
| 384 | + return 0; |
| 385 | +} |
| 386 | + |
| 387 | +void __init reserve_crashkernel_generic(char *cmdline, |
| 388 | + unsigned long long crash_size, |
| 389 | + unsigned long long crash_base, |
| 390 | + unsigned long long crash_low_size, |
| 391 | + bool high) |
| 392 | +{ |
| 393 | + unsigned long long search_end = CRASH_ADDR_LOW_MAX, search_base = 0; |
| 394 | + bool fixed_base = false; |
| 395 | + |
| 396 | + /* User specifies base address explicitly. */ |
| 397 | + if (crash_base) { |
| 398 | + fixed_base = true; |
| 399 | + search_base = crash_base; |
| 400 | + search_end = crash_base + crash_size; |
| 401 | + } else if (high) { |
| 402 | + search_base = CRASH_ADDR_LOW_MAX; |
| 403 | + search_end = CRASH_ADDR_HIGH_MAX; |
| 404 | + } |
| 405 | + |
| 406 | +retry: |
| 407 | + crash_base = memblock_phys_alloc_range(crash_size, CRASH_ALIGN, |
| 408 | + search_base, search_end); |
| 409 | + if (!crash_base) { |
| 410 | + /* |
| 411 | + * For crashkernel=size[KMG]@offset[KMG], print out failure |
| 412 | + * message if can't reserve the specified region. |
| 413 | + */ |
| 414 | + if (fixed_base) { |
| 415 | + pr_warn("crashkernel reservation failed - memory is in use.\n"); |
| 416 | + return; |
| 417 | + } |
| 418 | + |
| 419 | + /* |
| 420 | + * For crashkernel=size[KMG], if the first attempt was for |
| 421 | + * low memory, fall back to high memory, the minimum required |
| 422 | + * low memory will be reserved later. |
| 423 | + */ |
| 424 | + if (!high && search_end == CRASH_ADDR_LOW_MAX) { |
| 425 | + search_end = CRASH_ADDR_HIGH_MAX; |
| 426 | + search_base = CRASH_ADDR_LOW_MAX; |
| 427 | + crash_low_size = DEFAULT_CRASH_KERNEL_LOW_SIZE; |
| 428 | + goto retry; |
| 429 | + } |
| 430 | + |
| 431 | + /* |
| 432 | + * For crashkernel=size[KMG],high, if the first attempt was |
| 433 | + * for high memory, fall back to low memory. |
| 434 | + */ |
| 435 | + if (high && search_end == CRASH_ADDR_HIGH_MAX) { |
| 436 | + search_end = CRASH_ADDR_LOW_MAX; |
| 437 | + search_base = 0; |
| 438 | + goto retry; |
| 439 | + } |
| 440 | + pr_warn("cannot allocate crashkernel (size:0x%llx)\n", |
| 441 | + crash_size); |
| 442 | + return; |
| 443 | + } |
| 444 | + |
| 445 | + if ((crash_base > CRASH_ADDR_LOW_MAX) && |
| 446 | + crash_low_size && reserve_crashkernel_low(crash_low_size)) { |
| 447 | + memblock_phys_free(crash_base, crash_size); |
| 448 | + return; |
| 449 | + } |
| 450 | + |
| 451 | + pr_info("crashkernel reserved: 0x%016llx - 0x%016llx (%lld MB)\n", |
| 452 | + crash_base, crash_base + crash_size, crash_size >> 20); |
| 453 | + |
| 454 | + /* |
| 455 | + * The crashkernel memory will be removed from the kernel linear |
| 456 | + * map. Inform kmemleak so that it won't try to access it. |
| 457 | + */ |
| 458 | + kmemleak_ignore_phys(crash_base); |
| 459 | + if (crashk_low_res.end) |
| 460 | + kmemleak_ignore_phys(crashk_low_res.start); |
| 461 | + |
| 462 | + crashk_res.start = crash_base; |
| 463 | + crashk_res.end = crash_base + crash_size - 1; |
| 464 | + insert_resource(&iomem_resource, &crashk_res); |
| 465 | +} |
| 466 | +#endif |
| 467 | + |
363 | 468 | int crash_prepare_elf64_headers(struct crash_mem *mem, int need_kernel_map,
|
364 | 469 | void **addr, unsigned long *sz)
|
365 | 470 | {
|
|
0 commit comments