Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

kexec: support for kexec on panic using new system call

This patch adds support for loading a kexec on panic (kdump) kernel usning
new system call.

It prepares ELF headers for memory areas to be dumped and for saved cpu
registers. Also prepares the memory map for second kernel and limits its
boot to reserved areas only.

Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Michael Kerrisk <mtk.manpages@gmail.com>
Cc: Yinghai Lu <yinghai@kernel.org>
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Matthew Garrett <mjg59@srcf.ucam.org>
Cc: Greg Kroah-Hartman <greg@kroah.com>
Cc: Dave Young <dyoung@redhat.com>
Cc: WANG Chao <chaowang@redhat.com>
Cc: Baoquan He <bhe@redhat.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Vivek Goyal and committed by
Linus Torvalds
dd5f7260 27f48d3e

+725 -26
+9
arch/x86/include/asm/crash.h
··· 1 + #ifndef _ASM_X86_CRASH_H 2 + #define _ASM_X86_CRASH_H 3 + 4 + int crash_load_segments(struct kimage *image); 5 + int crash_copy_backup_region(struct kimage *image); 6 + int crash_setup_memmap_entries(struct kimage *image, 7 + struct boot_params *params); 8 + 9 + #endif /* _ASM_X86_CRASH_H */
+28 -4
arch/x86/include/asm/kexec.h
··· 25 25 #include <asm/ptrace.h> 26 26 #include <asm/bootparam.h> 27 27 28 + struct kimage; 29 + 28 30 /* 29 31 * KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return. 30 32 * I.e. Maximum page that is mapped directly into kernel memory, ··· 63 61 /* The native architecture */ 64 62 # define KEXEC_ARCH KEXEC_ARCH_X86_64 65 63 #endif 64 + 65 + /* Memory to backup during crash kdump */ 66 + #define KEXEC_BACKUP_SRC_START (0UL) 67 + #define KEXEC_BACKUP_SRC_END (640 * 1024UL) /* 640K */ 66 68 67 69 /* 68 70 * CPU does not save ss and sp on stack if execution is already ··· 167 161 pud_t *pud; 168 162 pmd_t *pmd; 169 163 pte_t *pte; 170 - }; 164 + /* Details of backup region */ 165 + unsigned long backup_src_start; 166 + unsigned long backup_src_sz; 171 167 168 + /* Physical address of backup segment */ 169 + unsigned long backup_load_addr; 170 + 171 + /* Core ELF header buffer */ 172 + void *elf_headers; 173 + unsigned long elf_headers_sz; 174 + unsigned long elf_load_addr; 175 + }; 176 + #endif /* CONFIG_X86_32 */ 177 + 178 + #ifdef CONFIG_X86_64 179 + /* 180 + * Number of elements and order of elements in this structure should match 181 + * with the ones in arch/x86/purgatory/entry64.S. If you make a change here 182 + * make an appropriate change in purgatory too. 183 + */ 172 184 struct kexec_entry64_regs { 173 185 uint64_t rax; 174 - uint64_t rbx; 175 186 uint64_t rcx; 176 187 uint64_t rdx; 177 - uint64_t rsi; 178 - uint64_t rdi; 188 + uint64_t rbx; 179 189 uint64_t rsp; 180 190 uint64_t rbp; 191 + uint64_t rsi; 192 + uint64_t rdi; 181 193 uint64_t r8; 182 194 uint64_t r9; 183 195 uint64_t r10;
+563
arch/x86/kernel/crash.c
··· 4 4 * Created by: Hariprasad Nellitheertha (hari@in.ibm.com) 5 5 * 6 6 * Copyright (C) IBM Corporation, 2004. All rights reserved. 7 + * Copyright (C) Red Hat Inc., 2014. All rights reserved. 8 + * Authors: 9 + * Vivek Goyal <vgoyal@redhat.com> 7 10 * 8 11 */ 12 + 13 + #define pr_fmt(fmt) "kexec: " fmt 9 14 10 15 #include <linux/types.h> 11 16 #include <linux/kernel.h> ··· 21 16 #include <linux/elf.h> 22 17 #include <linux/elfcore.h> 23 18 #include <linux/module.h> 19 + #include <linux/slab.h> 24 20 25 21 #include <asm/processor.h> 26 22 #include <asm/hardirq.h> ··· 34 28 #include <asm/reboot.h> 35 29 #include <asm/virtext.h> 36 30 31 + /* Alignment required for elf header segment */ 32 + #define ELF_CORE_HEADER_ALIGN 4096 33 + 34 + /* This primarily represents number of split ranges due to exclusion */ 35 + #define CRASH_MAX_RANGES 16 36 + 37 + struct crash_mem_range { 38 + u64 start, end; 39 + }; 40 + 41 + struct crash_mem { 42 + unsigned int nr_ranges; 43 + struct crash_mem_range ranges[CRASH_MAX_RANGES]; 44 + }; 45 + 46 + /* Misc data about ram ranges needed to prepare elf headers */ 47 + struct crash_elf_data { 48 + struct kimage *image; 49 + /* 50 + * Total number of ram ranges we have after various adjustments for 51 + * GART, crash reserved region etc. 52 + */ 53 + unsigned int max_nr_ranges; 54 + unsigned long gart_start, gart_end; 55 + 56 + /* Pointer to elf header */ 57 + void *ehdr; 58 + /* Pointer to next phdr */ 59 + void *bufp; 60 + struct crash_mem mem; 61 + }; 62 + 63 + /* Used while preparing memory map entries for second kernel */ 64 + struct crash_memmap_data { 65 + struct boot_params *params; 66 + /* Type of memory */ 67 + unsigned int type; 68 + }; 69 + 37 70 int in_crash_kexec; 38 71 39 72 /* ··· 84 39 */ 85 40 crash_vmclear_fn __rcu *crash_vmclear_loaded_vmcss = NULL; 86 41 EXPORT_SYMBOL_GPL(crash_vmclear_loaded_vmcss); 42 + unsigned long crash_zero_bytes; 87 43 88 44 static inline void cpu_crash_vmclear_loaded_vmcss(void) 89 45 { ··· 181 135 #endif 182 136 crash_save_cpu(regs, safe_smp_processor_id()); 183 137 } 138 + 139 + #ifdef CONFIG_X86_64 140 + 141 + static int get_nr_ram_ranges_callback(unsigned long start_pfn, 142 + unsigned long nr_pfn, void *arg) 143 + { 144 + int *nr_ranges = arg; 145 + 146 + (*nr_ranges)++; 147 + return 0; 148 + } 149 + 150 + static int get_gart_ranges_callback(u64 start, u64 end, void *arg) 151 + { 152 + struct crash_elf_data *ced = arg; 153 + 154 + ced->gart_start = start; 155 + ced->gart_end = end; 156 + 157 + /* Not expecting more than 1 gart aperture */ 158 + return 1; 159 + } 160 + 161 + 162 + /* Gather all the required information to prepare elf headers for ram regions */ 163 + static void fill_up_crash_elf_data(struct crash_elf_data *ced, 164 + struct kimage *image) 165 + { 166 + unsigned int nr_ranges = 0; 167 + 168 + ced->image = image; 169 + 170 + walk_system_ram_range(0, -1, &nr_ranges, 171 + get_nr_ram_ranges_callback); 172 + 173 + ced->max_nr_ranges = nr_ranges; 174 + 175 + /* 176 + * We don't create ELF headers for GART aperture as an attempt 177 + * to dump this memory in second kernel leads to hang/crash. 178 + * If gart aperture is present, one needs to exclude that region 179 + * and that could lead to need of extra phdr. 180 + */ 181 + walk_iomem_res("GART", IORESOURCE_MEM, 0, -1, 182 + ced, get_gart_ranges_callback); 183 + 184 + /* 185 + * If we have gart region, excluding that could potentially split 186 + * a memory range, resulting in extra header. Account for that. 187 + */ 188 + if (ced->gart_end) 189 + ced->max_nr_ranges++; 190 + 191 + /* Exclusion of crash region could split memory ranges */ 192 + ced->max_nr_ranges++; 193 + 194 + /* If crashk_low_res is not 0, another range split possible */ 195 + if (crashk_low_res.end != 0) 196 + ced->max_nr_ranges++; 197 + } 198 + 199 + static int exclude_mem_range(struct crash_mem *mem, 200 + unsigned long long mstart, unsigned long long mend) 201 + { 202 + int i, j; 203 + unsigned long long start, end; 204 + struct crash_mem_range temp_range = {0, 0}; 205 + 206 + for (i = 0; i < mem->nr_ranges; i++) { 207 + start = mem->ranges[i].start; 208 + end = mem->ranges[i].end; 209 + 210 + if (mstart > end || mend < start) 211 + continue; 212 + 213 + /* Truncate any area outside of range */ 214 + if (mstart < start) 215 + mstart = start; 216 + if (mend > end) 217 + mend = end; 218 + 219 + /* Found completely overlapping range */ 220 + if (mstart == start && mend == end) { 221 + mem->ranges[i].start = 0; 222 + mem->ranges[i].end = 0; 223 + if (i < mem->nr_ranges - 1) { 224 + /* Shift rest of the ranges to left */ 225 + for (j = i; j < mem->nr_ranges - 1; j++) { 226 + mem->ranges[j].start = 227 + mem->ranges[j+1].start; 228 + mem->ranges[j].end = 229 + mem->ranges[j+1].end; 230 + } 231 + } 232 + mem->nr_ranges--; 233 + return 0; 234 + } 235 + 236 + if (mstart > start && mend < end) { 237 + /* Split original range */ 238 + mem->ranges[i].end = mstart - 1; 239 + temp_range.start = mend + 1; 240 + temp_range.end = end; 241 + } else if (mstart != start) 242 + mem->ranges[i].end = mstart - 1; 243 + else 244 + mem->ranges[i].start = mend + 1; 245 + break; 246 + } 247 + 248 + /* If a split happend, add the split to array */ 249 + if (!temp_range.end) 250 + return 0; 251 + 252 + /* Split happened */ 253 + if (i == CRASH_MAX_RANGES - 1) { 254 + pr_err("Too many crash ranges after split\n"); 255 + return -ENOMEM; 256 + } 257 + 258 + /* Location where new range should go */ 259 + j = i + 1; 260 + if (j < mem->nr_ranges) { 261 + /* Move over all ranges one slot towards the end */ 262 + for (i = mem->nr_ranges - 1; i >= j; i--) 263 + mem->ranges[i + 1] = mem->ranges[i]; 264 + } 265 + 266 + mem->ranges[j].start = temp_range.start; 267 + mem->ranges[j].end = temp_range.end; 268 + mem->nr_ranges++; 269 + return 0; 270 + } 271 + 272 + /* 273 + * Look for any unwanted ranges between mstart, mend and remove them. This 274 + * might lead to split and split ranges are put in ced->mem.ranges[] array 275 + */ 276 + static int elf_header_exclude_ranges(struct crash_elf_data *ced, 277 + unsigned long long mstart, unsigned long long mend) 278 + { 279 + struct crash_mem *cmem = &ced->mem; 280 + int ret = 0; 281 + 282 + memset(cmem->ranges, 0, sizeof(cmem->ranges)); 283 + 284 + cmem->ranges[0].start = mstart; 285 + cmem->ranges[0].end = mend; 286 + cmem->nr_ranges = 1; 287 + 288 + /* Exclude crashkernel region */ 289 + ret = exclude_mem_range(cmem, crashk_res.start, crashk_res.end); 290 + if (ret) 291 + return ret; 292 + 293 + ret = exclude_mem_range(cmem, crashk_low_res.start, crashk_low_res.end); 294 + if (ret) 295 + return ret; 296 + 297 + /* Exclude GART region */ 298 + if (ced->gart_end) { 299 + ret = exclude_mem_range(cmem, ced->gart_start, ced->gart_end); 300 + if (ret) 301 + return ret; 302 + } 303 + 304 + return ret; 305 + } 306 + 307 + static int prepare_elf64_ram_headers_callback(u64 start, u64 end, void *arg) 308 + { 309 + struct crash_elf_data *ced = arg; 310 + Elf64_Ehdr *ehdr; 311 + Elf64_Phdr *phdr; 312 + unsigned long mstart, mend; 313 + struct kimage *image = ced->image; 314 + struct crash_mem *cmem; 315 + int ret, i; 316 + 317 + ehdr = ced->ehdr; 318 + 319 + /* Exclude unwanted mem ranges */ 320 + ret = elf_header_exclude_ranges(ced, start, end); 321 + if (ret) 322 + return ret; 323 + 324 + /* Go through all the ranges in ced->mem.ranges[] and prepare phdr */ 325 + cmem = &ced->mem; 326 + 327 + for (i = 0; i < cmem->nr_ranges; i++) { 328 + mstart = cmem->ranges[i].start; 329 + mend = cmem->ranges[i].end; 330 + 331 + phdr = ced->bufp; 332 + ced->bufp += sizeof(Elf64_Phdr); 333 + 334 + phdr->p_type = PT_LOAD; 335 + phdr->p_flags = PF_R|PF_W|PF_X; 336 + phdr->p_offset = mstart; 337 + 338 + /* 339 + * If a range matches backup region, adjust offset to backup 340 + * segment. 341 + */ 342 + if (mstart == image->arch.backup_src_start && 343 + (mend - mstart + 1) == image->arch.backup_src_sz) 344 + phdr->p_offset = image->arch.backup_load_addr; 345 + 346 + phdr->p_paddr = mstart; 347 + phdr->p_vaddr = (unsigned long long) __va(mstart); 348 + phdr->p_filesz = phdr->p_memsz = mend - mstart + 1; 349 + phdr->p_align = 0; 350 + ehdr->e_phnum++; 351 + pr_debug("Crash PT_LOAD elf header. phdr=%p vaddr=0x%llx, paddr=0x%llx, sz=0x%llx e_phnum=%d p_offset=0x%llx\n", 352 + phdr, phdr->p_vaddr, phdr->p_paddr, phdr->p_filesz, 353 + ehdr->e_phnum, phdr->p_offset); 354 + } 355 + 356 + return ret; 357 + } 358 + 359 + static int prepare_elf64_headers(struct crash_elf_data *ced, 360 + void **addr, unsigned long *sz) 361 + { 362 + Elf64_Ehdr *ehdr; 363 + Elf64_Phdr *phdr; 364 + unsigned long nr_cpus = num_possible_cpus(), nr_phdr, elf_sz; 365 + unsigned char *buf, *bufp; 366 + unsigned int cpu; 367 + unsigned long long notes_addr; 368 + int ret; 369 + 370 + /* extra phdr for vmcoreinfo elf note */ 371 + nr_phdr = nr_cpus + 1; 372 + nr_phdr += ced->max_nr_ranges; 373 + 374 + /* 375 + * kexec-tools creates an extra PT_LOAD phdr for kernel text mapping 376 + * area on x86_64 (ffffffff80000000 - ffffffffa0000000). 377 + * I think this is required by tools like gdb. So same physical 378 + * memory will be mapped in two elf headers. One will contain kernel 379 + * text virtual addresses and other will have __va(physical) addresses. 380 + */ 381 + 382 + nr_phdr++; 383 + elf_sz = sizeof(Elf64_Ehdr) + nr_phdr * sizeof(Elf64_Phdr); 384 + elf_sz = ALIGN(elf_sz, ELF_CORE_HEADER_ALIGN); 385 + 386 + buf = vzalloc(elf_sz); 387 + if (!buf) 388 + return -ENOMEM; 389 + 390 + bufp = buf; 391 + ehdr = (Elf64_Ehdr *)bufp; 392 + bufp += sizeof(Elf64_Ehdr); 393 + memcpy(ehdr->e_ident, ELFMAG, SELFMAG); 394 + ehdr->e_ident[EI_CLASS] = ELFCLASS64; 395 + ehdr->e_ident[EI_DATA] = ELFDATA2LSB; 396 + ehdr->e_ident[EI_VERSION] = EV_CURRENT; 397 + ehdr->e_ident[EI_OSABI] = ELF_OSABI; 398 + memset(ehdr->e_ident + EI_PAD, 0, EI_NIDENT - EI_PAD); 399 + ehdr->e_type = ET_CORE; 400 + ehdr->e_machine = ELF_ARCH; 401 + ehdr->e_version = EV_CURRENT; 402 + ehdr->e_phoff = sizeof(Elf64_Ehdr); 403 + ehdr->e_ehsize = sizeof(Elf64_Ehdr); 404 + ehdr->e_phentsize = sizeof(Elf64_Phdr); 405 + 406 + /* Prepare one phdr of type PT_NOTE for each present cpu */ 407 + for_each_present_cpu(cpu) { 408 + phdr = (Elf64_Phdr *)bufp; 409 + bufp += sizeof(Elf64_Phdr); 410 + phdr->p_type = PT_NOTE; 411 + notes_addr = per_cpu_ptr_to_phys(per_cpu_ptr(crash_notes, cpu)); 412 + phdr->p_offset = phdr->p_paddr = notes_addr; 413 + phdr->p_filesz = phdr->p_memsz = sizeof(note_buf_t); 414 + (ehdr->e_phnum)++; 415 + } 416 + 417 + /* Prepare one PT_NOTE header for vmcoreinfo */ 418 + phdr = (Elf64_Phdr *)bufp; 419 + bufp += sizeof(Elf64_Phdr); 420 + phdr->p_type = PT_NOTE; 421 + phdr->p_offset = phdr->p_paddr = paddr_vmcoreinfo_note(); 422 + phdr->p_filesz = phdr->p_memsz = sizeof(vmcoreinfo_note); 423 + (ehdr->e_phnum)++; 424 + 425 + #ifdef CONFIG_X86_64 426 + /* Prepare PT_LOAD type program header for kernel text region */ 427 + phdr = (Elf64_Phdr *)bufp; 428 + bufp += sizeof(Elf64_Phdr); 429 + phdr->p_type = PT_LOAD; 430 + phdr->p_flags = PF_R|PF_W|PF_X; 431 + phdr->p_vaddr = (Elf64_Addr)_text; 432 + phdr->p_filesz = phdr->p_memsz = _end - _text; 433 + phdr->p_offset = phdr->p_paddr = __pa_symbol(_text); 434 + (ehdr->e_phnum)++; 435 + #endif 436 + 437 + /* Prepare PT_LOAD headers for system ram chunks. */ 438 + ced->ehdr = ehdr; 439 + ced->bufp = bufp; 440 + ret = walk_system_ram_res(0, -1, ced, 441 + prepare_elf64_ram_headers_callback); 442 + if (ret < 0) 443 + return ret; 444 + 445 + *addr = buf; 446 + *sz = elf_sz; 447 + return 0; 448 + } 449 + 450 + /* Prepare elf headers. Return addr and size */ 451 + static int prepare_elf_headers(struct kimage *image, void **addr, 452 + unsigned long *sz) 453 + { 454 + struct crash_elf_data *ced; 455 + int ret; 456 + 457 + ced = kzalloc(sizeof(*ced), GFP_KERNEL); 458 + if (!ced) 459 + return -ENOMEM; 460 + 461 + fill_up_crash_elf_data(ced, image); 462 + 463 + /* By default prepare 64bit headers */ 464 + ret = prepare_elf64_headers(ced, addr, sz); 465 + kfree(ced); 466 + return ret; 467 + } 468 + 469 + static int add_e820_entry(struct boot_params *params, struct e820entry *entry) 470 + { 471 + unsigned int nr_e820_entries; 472 + 473 + nr_e820_entries = params->e820_entries; 474 + if (nr_e820_entries >= E820MAX) 475 + return 1; 476 + 477 + memcpy(&params->e820_map[nr_e820_entries], entry, 478 + sizeof(struct e820entry)); 479 + params->e820_entries++; 480 + return 0; 481 + } 482 + 483 + static int memmap_entry_callback(u64 start, u64 end, void *arg) 484 + { 485 + struct crash_memmap_data *cmd = arg; 486 + struct boot_params *params = cmd->params; 487 + struct e820entry ei; 488 + 489 + ei.addr = start; 490 + ei.size = end - start + 1; 491 + ei.type = cmd->type; 492 + add_e820_entry(params, &ei); 493 + 494 + return 0; 495 + } 496 + 497 + static int memmap_exclude_ranges(struct kimage *image, struct crash_mem *cmem, 498 + unsigned long long mstart, 499 + unsigned long long mend) 500 + { 501 + unsigned long start, end; 502 + int ret = 0; 503 + 504 + cmem->ranges[0].start = mstart; 505 + cmem->ranges[0].end = mend; 506 + cmem->nr_ranges = 1; 507 + 508 + /* Exclude Backup region */ 509 + start = image->arch.backup_load_addr; 510 + end = start + image->arch.backup_src_sz - 1; 511 + ret = exclude_mem_range(cmem, start, end); 512 + if (ret) 513 + return ret; 514 + 515 + /* Exclude elf header region */ 516 + start = image->arch.elf_load_addr; 517 + end = start + image->arch.elf_headers_sz - 1; 518 + return exclude_mem_range(cmem, start, end); 519 + } 520 + 521 + /* Prepare memory map for crash dump kernel */ 522 + int crash_setup_memmap_entries(struct kimage *image, struct boot_params *params) 523 + { 524 + int i, ret = 0; 525 + unsigned long flags; 526 + struct e820entry ei; 527 + struct crash_memmap_data cmd; 528 + struct crash_mem *cmem; 529 + 530 + cmem = vzalloc(sizeof(struct crash_mem)); 531 + if (!cmem) 532 + return -ENOMEM; 533 + 534 + memset(&cmd, 0, sizeof(struct crash_memmap_data)); 535 + cmd.params = params; 536 + 537 + /* Add first 640K segment */ 538 + ei.addr = image->arch.backup_src_start; 539 + ei.size = image->arch.backup_src_sz; 540 + ei.type = E820_RAM; 541 + add_e820_entry(params, &ei); 542 + 543 + /* Add ACPI tables */ 544 + cmd.type = E820_ACPI; 545 + flags = IORESOURCE_MEM | IORESOURCE_BUSY; 546 + walk_iomem_res("ACPI Tables", flags, 0, -1, &cmd, 547 + memmap_entry_callback); 548 + 549 + /* Add ACPI Non-volatile Storage */ 550 + cmd.type = E820_NVS; 551 + walk_iomem_res("ACPI Non-volatile Storage", flags, 0, -1, &cmd, 552 + memmap_entry_callback); 553 + 554 + /* Add crashk_low_res region */ 555 + if (crashk_low_res.end) { 556 + ei.addr = crashk_low_res.start; 557 + ei.size = crashk_low_res.end - crashk_low_res.start + 1; 558 + ei.type = E820_RAM; 559 + add_e820_entry(params, &ei); 560 + } 561 + 562 + /* Exclude some ranges from crashk_res and add rest to memmap */ 563 + ret = memmap_exclude_ranges(image, cmem, crashk_res.start, 564 + crashk_res.end); 565 + if (ret) 566 + goto out; 567 + 568 + for (i = 0; i < cmem->nr_ranges; i++) { 569 + ei.size = cmem->ranges[i].end - cmem->ranges[i].start + 1; 570 + 571 + /* If entry is less than a page, skip it */ 572 + if (ei.size < PAGE_SIZE) 573 + continue; 574 + ei.addr = cmem->ranges[i].start; 575 + ei.type = E820_RAM; 576 + add_e820_entry(params, &ei); 577 + } 578 + 579 + out: 580 + vfree(cmem); 581 + return ret; 582 + } 583 + 584 + static int determine_backup_region(u64 start, u64 end, void *arg) 585 + { 586 + struct kimage *image = arg; 587 + 588 + image->arch.backup_src_start = start; 589 + image->arch.backup_src_sz = end - start + 1; 590 + 591 + /* Expecting only one range for backup region */ 592 + return 1; 593 + } 594 + 595 + int crash_load_segments(struct kimage *image) 596 + { 597 + unsigned long src_start, src_sz, elf_sz; 598 + void *elf_addr; 599 + int ret; 600 + 601 + /* 602 + * Determine and load a segment for backup area. First 640K RAM 603 + * region is backup source 604 + */ 605 + 606 + ret = walk_system_ram_res(KEXEC_BACKUP_SRC_START, KEXEC_BACKUP_SRC_END, 607 + image, determine_backup_region); 608 + 609 + /* Zero or postive return values are ok */ 610 + if (ret < 0) 611 + return ret; 612 + 613 + src_start = image->arch.backup_src_start; 614 + src_sz = image->arch.backup_src_sz; 615 + 616 + /* Add backup segment. */ 617 + if (src_sz) { 618 + /* 619 + * Ideally there is no source for backup segment. This is 620 + * copied in purgatory after crash. Just add a zero filled 621 + * segment for now to make sure checksum logic works fine. 622 + */ 623 + ret = kexec_add_buffer(image, (char *)&crash_zero_bytes, 624 + sizeof(crash_zero_bytes), src_sz, 625 + PAGE_SIZE, 0, -1, 0, 626 + &image->arch.backup_load_addr); 627 + if (ret) 628 + return ret; 629 + pr_debug("Loaded backup region at 0x%lx backup_start=0x%lx memsz=0x%lx\n", 630 + image->arch.backup_load_addr, src_start, src_sz); 631 + } 632 + 633 + /* Prepare elf headers and add a segment */ 634 + ret = prepare_elf_headers(image, &elf_addr, &elf_sz); 635 + if (ret) 636 + return ret; 637 + 638 + image->arch.elf_headers = elf_addr; 639 + image->arch.elf_headers_sz = elf_sz; 640 + 641 + ret = kexec_add_buffer(image, (char *)elf_addr, elf_sz, elf_sz, 642 + ELF_CORE_HEADER_ALIGN, 0, -1, 0, 643 + &image->arch.elf_load_addr); 644 + if (ret) { 645 + vfree((void *)image->arch.elf_headers); 646 + return ret; 647 + } 648 + pr_debug("Loaded ELF headers at 0x%lx bufsz=0x%lx memsz=0x%lx\n", 649 + image->arch.elf_load_addr, elf_sz, elf_sz); 650 + 651 + return ret; 652 + } 653 + 654 + #endif /* CONFIG_X86_64 */
+45 -10
arch/x86/kernel/kexec-bzimage64.c
··· 21 21 22 22 #include <asm/bootparam.h> 23 23 #include <asm/setup.h> 24 + #include <asm/crash.h> 25 + 26 + #define MAX_ELFCOREHDR_STR_LEN 30 /* elfcorehdr=0x<64bit-value> */ 24 27 25 28 /* 26 29 * Defines lowest physical address for various segments. Not sure where ··· 61 58 return 0; 62 59 } 63 60 64 - static int setup_cmdline(struct boot_params *params, 61 + static int setup_cmdline(struct kimage *image, struct boot_params *params, 65 62 unsigned long bootparams_load_addr, 66 63 unsigned long cmdline_offset, char *cmdline, 67 64 unsigned long cmdline_len) 68 65 { 69 66 char *cmdline_ptr = ((char *)params) + cmdline_offset; 70 - unsigned long cmdline_ptr_phys; 67 + unsigned long cmdline_ptr_phys, len; 71 68 uint32_t cmdline_low_32, cmdline_ext_32; 72 69 73 70 memcpy(cmdline_ptr, cmdline, cmdline_len); 71 + if (image->type == KEXEC_TYPE_CRASH) { 72 + len = sprintf(cmdline_ptr + cmdline_len - 1, 73 + " elfcorehdr=0x%lx", image->arch.elf_load_addr); 74 + cmdline_len += len; 75 + } 74 76 cmdline_ptr[cmdline_len - 1] = '\0'; 75 77 78 + pr_debug("Final command line is: %s\n", cmdline_ptr); 76 79 cmdline_ptr_phys = bootparams_load_addr + cmdline_offset; 77 80 cmdline_low_32 = cmdline_ptr_phys & 0xffffffffUL; 78 81 cmdline_ext_32 = cmdline_ptr_phys >> 32; ··· 107 98 return 0; 108 99 } 109 100 110 - static int setup_boot_parameters(struct boot_params *params) 101 + static int setup_boot_parameters(struct kimage *image, 102 + struct boot_params *params) 111 103 { 112 104 unsigned int nr_e820_entries; 113 105 unsigned long long mem_k, start, end; 114 - int i; 106 + int i, ret = 0; 115 107 116 108 /* Get subarch from existing bootparams */ 117 109 params->hdr.hardware_subarch = boot_params.hdr.hardware_subarch; ··· 135 125 /* Default sysdesc table */ 136 126 params->sys_desc_table.length = 0; 137 127 138 - setup_memory_map_entries(params); 128 + if (image->type == KEXEC_TYPE_CRASH) { 129 + ret = crash_setup_memmap_entries(image, params); 130 + if (ret) 131 + return ret; 132 + } else 133 + setup_memory_map_entries(params); 134 + 139 135 nr_e820_entries = params->e820_entries; 140 136 141 137 for (i = 0; i < nr_e820_entries; i++) { ··· 169 153 memcpy(params->edd_mbr_sig_buffer, boot_params.edd_mbr_sig_buffer, 170 154 EDD_MBR_SIG_MAX * sizeof(unsigned int)); 171 155 172 - return 0; 156 + return ret; 173 157 } 174 158 175 159 int bzImage64_probe(const char *buf, unsigned long len) ··· 257 241 } 258 242 259 243 /* 244 + * In case of crash dump, we will append elfcorehdr=<addr> to 245 + * command line. Make sure it does not overflow 246 + */ 247 + if (cmdline_len + MAX_ELFCOREHDR_STR_LEN > header->cmdline_size) { 248 + pr_debug("Appending elfcorehdr=<addr> to command line exceeds maximum allowed length\n"); 249 + return ERR_PTR(-EINVAL); 250 + } 251 + 252 + /* Allocate and load backup region */ 253 + if (image->type == KEXEC_TYPE_CRASH) { 254 + ret = crash_load_segments(image); 255 + if (ret) 256 + return ERR_PTR(ret); 257 + } 258 + 259 + /* 260 260 * Load purgatory. For 64bit entry point, purgatory code can be 261 261 * anywhere. 262 262 */ ··· 286 254 pr_debug("Loaded purgatory at 0x%lx\n", purgatory_load_addr); 287 255 288 256 /* Load Bootparams and cmdline */ 289 - params_cmdline_sz = sizeof(struct boot_params) + cmdline_len; 257 + params_cmdline_sz = sizeof(struct boot_params) + cmdline_len + 258 + MAX_ELFCOREHDR_STR_LEN; 290 259 params = kzalloc(params_cmdline_sz, GFP_KERNEL); 291 260 if (!params) 292 261 return ERR_PTR(-ENOMEM); ··· 336 303 setup_initrd(params, initrd_load_addr, initrd_len); 337 304 } 338 305 339 - setup_cmdline(params, bootparam_load_addr, sizeof(struct boot_params), 340 - cmdline, cmdline_len); 306 + setup_cmdline(image, params, bootparam_load_addr, 307 + sizeof(struct boot_params), cmdline, cmdline_len); 341 308 342 309 /* bootloader info. Do we need a separate ID for kexec kernel loader? */ 343 310 params->hdr.type_of_loader = 0x0D << 4; ··· 365 332 if (ret) 366 333 goto out_free_params; 367 334 368 - setup_boot_parameters(params); 335 + ret = setup_boot_parameters(image, params); 336 + if (ret) 337 + goto out_free_params; 369 338 370 339 /* Allocate loader specific data */ 371 340 ldata = kzalloc(sizeof(struct bzimage64_data), GFP_KERNEL);
+40
arch/x86/kernel/machine_kexec_64.c
··· 178 178 ); 179 179 } 180 180 181 + /* Update purgatory as needed after various image segments have been prepared */ 182 + static int arch_update_purgatory(struct kimage *image) 183 + { 184 + int ret = 0; 185 + 186 + if (!image->file_mode) 187 + return 0; 188 + 189 + /* Setup copying of backup region */ 190 + if (image->type == KEXEC_TYPE_CRASH) { 191 + ret = kexec_purgatory_get_set_symbol(image, "backup_dest", 192 + &image->arch.backup_load_addr, 193 + sizeof(image->arch.backup_load_addr), 0); 194 + if (ret) 195 + return ret; 196 + 197 + ret = kexec_purgatory_get_set_symbol(image, "backup_src", 198 + &image->arch.backup_src_start, 199 + sizeof(image->arch.backup_src_start), 0); 200 + if (ret) 201 + return ret; 202 + 203 + ret = kexec_purgatory_get_set_symbol(image, "backup_sz", 204 + &image->arch.backup_src_sz, 205 + sizeof(image->arch.backup_src_sz), 0); 206 + if (ret) 207 + return ret; 208 + } 209 + 210 + return ret; 211 + } 212 + 181 213 int machine_kexec_prepare(struct kimage *image) 182 214 { 183 215 unsigned long start_pgtable; ··· 220 188 221 189 /* Setup the identity mapped 64bit page table */ 222 190 result = init_pgtable(image, start_pgtable); 191 + if (result) 192 + return result; 193 + 194 + /* update purgatory as needed */ 195 + result = arch_update_purgatory(image); 223 196 if (result) 224 197 return result; 225 198 ··· 352 315 353 316 void *arch_kexec_kernel_image_load(struct kimage *image) 354 317 { 318 + vfree(image->arch.elf_headers); 319 + image->arch.elf_headers = NULL; 320 + 355 321 if (!image->fops || !image->fops->load) 356 322 return ERR_PTR(-ENOEXEC); 357 323
+3 -3
arch/x86/purgatory/entry64.S
··· 61 61 .balign 4 62 62 entry64_regs: 63 63 rax: .quad 0x0 64 - rbx: .quad 0x0 65 64 rcx: .quad 0x0 66 65 rdx: .quad 0x0 67 - rsi: .quad 0x0 68 - rdi: .quad 0x0 66 + rbx: .quad 0x0 69 67 rsp: .quad 0x0 70 68 rbp: .quad 0x0 69 + rsi: .quad 0x0 70 + rdi: .quad 0x0 71 71 r8: .quad 0x0 72 72 r9: .quad 0x0 73 73 r10: .quad 0x0
+37 -9
kernel/kexec.c
··· 548 548 { 549 549 int ret; 550 550 struct kimage *image; 551 + bool kexec_on_panic = flags & KEXEC_FILE_ON_CRASH; 551 552 552 553 image = do_kimage_alloc_init(); 553 554 if (!image) 554 555 return -ENOMEM; 555 556 556 557 image->file_mode = 1; 558 + 559 + if (kexec_on_panic) { 560 + /* Enable special crash kernel control page alloc policy. */ 561 + image->control_page = crashk_res.start; 562 + image->type = KEXEC_TYPE_CRASH; 563 + } 557 564 558 565 ret = kimage_file_prepare_segments(image, kernel_fd, initrd_fd, 559 566 cmdline_ptr, cmdline_len, flags); ··· 579 572 goto out_free_post_load_bufs; 580 573 } 581 574 582 - image->swap_page = kimage_alloc_control_pages(image, 0); 583 - if (!image->swap_page) { 584 - pr_err(KERN_ERR "Could not allocate swap buffer\n"); 585 - goto out_free_control_pages; 575 + if (!kexec_on_panic) { 576 + image->swap_page = kimage_alloc_control_pages(image, 0); 577 + if (!image->swap_page) { 578 + pr_err(KERN_ERR "Could not allocate swap buffer\n"); 579 + goto out_free_control_pages; 580 + } 586 581 } 587 582 588 583 *rimage = image; ··· 1122 1113 unsigned long maddr; 1123 1114 size_t ubytes, mbytes; 1124 1115 int result; 1125 - unsigned char __user *buf; 1116 + unsigned char __user *buf = NULL; 1117 + unsigned char *kbuf = NULL; 1126 1118 1127 1119 result = 0; 1128 - buf = segment->buf; 1120 + if (image->file_mode) 1121 + kbuf = segment->kbuf; 1122 + else 1123 + buf = segment->buf; 1129 1124 ubytes = segment->bufsz; 1130 1125 mbytes = segment->memsz; 1131 1126 maddr = segment->mem; ··· 1152 1139 /* Zero the trailing part of the page */ 1153 1140 memset(ptr + uchunk, 0, mchunk - uchunk); 1154 1141 } 1155 - result = copy_from_user(ptr, buf, uchunk); 1142 + 1143 + /* For file based kexec, source pages are in kernel memory */ 1144 + if (image->file_mode) 1145 + memcpy(ptr, kbuf, uchunk); 1146 + else 1147 + result = copy_from_user(ptr, buf, uchunk); 1156 1148 kexec_flush_icache_page(page); 1157 1149 kunmap(page); 1158 1150 if (result) { ··· 1166 1148 } 1167 1149 ubytes -= uchunk; 1168 1150 maddr += mchunk; 1169 - buf += mchunk; 1151 + if (image->file_mode) 1152 + kbuf += mchunk; 1153 + else 1154 + buf += mchunk; 1170 1155 mbytes -= mchunk; 1171 1156 } 1172 1157 out: ··· 2148 2127 kbuf->top_down = top_down; 2149 2128 2150 2129 /* Walk the RAM ranges and allocate a suitable range for the buffer */ 2151 - ret = walk_system_ram_res(0, -1, kbuf, locate_mem_hole_callback); 2130 + if (image->type == KEXEC_TYPE_CRASH) 2131 + ret = walk_iomem_res("Crash kernel", 2132 + IORESOURCE_MEM | IORESOURCE_BUSY, 2133 + crashk_res.start, crashk_res.end, kbuf, 2134 + locate_mem_hole_callback); 2135 + else 2136 + ret = walk_system_ram_res(0, -1, kbuf, 2137 + locate_mem_hole_callback); 2152 2138 if (ret != 1) { 2153 2139 /* A suitable memory range could not be found for buffer */ 2154 2140 return -EADDRNOTAVAIL;