1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 262a31a03SHiroshi Shimamoto /* 362a31a03SHiroshi Shimamoto * Architecture specific (i386/x86_64) functions for kexec based crash dumps. 462a31a03SHiroshi Shimamoto * 562a31a03SHiroshi Shimamoto * Created by: Hariprasad Nellitheertha (hari@in.ibm.com) 662a31a03SHiroshi Shimamoto * 762a31a03SHiroshi Shimamoto * Copyright (C) IBM Corporation, 2004. All rights reserved. 8dd5f7260SVivek Goyal * Copyright (C) Red Hat Inc., 2014. All rights reserved. 9dd5f7260SVivek Goyal * Authors: 10dd5f7260SVivek Goyal * Vivek Goyal <vgoyal@redhat.com> 1162a31a03SHiroshi Shimamoto * 1262a31a03SHiroshi Shimamoto */ 1362a31a03SHiroshi Shimamoto 14dd5f7260SVivek Goyal #define pr_fmt(fmt) "kexec: " fmt 15dd5f7260SVivek Goyal 1662a31a03SHiroshi Shimamoto #include <linux/types.h> 1762a31a03SHiroshi Shimamoto #include <linux/kernel.h> 1862a31a03SHiroshi Shimamoto #include <linux/smp.h> 1962a31a03SHiroshi Shimamoto #include <linux/reboot.h> 2062a31a03SHiroshi Shimamoto #include <linux/kexec.h> 2162a31a03SHiroshi Shimamoto #include <linux/delay.h> 2262a31a03SHiroshi Shimamoto #include <linux/elf.h> 2362a31a03SHiroshi Shimamoto #include <linux/elfcore.h> 24186f4360SPaul Gortmaker #include <linux/export.h> 25dd5f7260SVivek Goyal #include <linux/slab.h> 26d6472302SStephen Rothwell #include <linux/vmalloc.h> 276f599d84SLianbo Jiang #include <linux/memblock.h> 2862a31a03SHiroshi Shimamoto 2962a31a03SHiroshi Shimamoto #include <asm/processor.h> 3062a31a03SHiroshi Shimamoto #include <asm/hardirq.h> 3162a31a03SHiroshi Shimamoto #include <asm/nmi.h> 3262a31a03SHiroshi Shimamoto #include <asm/hw_irq.h> 3362a31a03SHiroshi Shimamoto #include <asm/apic.h> 345520b7e7SIngo Molnar #include <asm/e820/types.h> 358643e28dSJiang Liu #include <asm/io_apic.h> 360c1b2724SOGAWA Hirofumi #include <asm/hpet.h> 3762a31a03SHiroshi Shimamoto #include <linux/kdebug.h> 3896b89dc6SJaswinder Singh Rajput #include <asm/cpu.h> 39ed23dc6fSGlauber Costa #include <asm/reboot.h> 402340b62fSEduardo Habkost #include <asm/virtext.h> 41da06a43dSTakao Indoh #include <asm/intel_pt.h> 4289f579ceSYi Wang #include <asm/crash.h> 436f599d84SLianbo Jiang #include <asm/cmdline.h> 448e294786SEduardo Habkost 45dd5f7260SVivek Goyal /* Used while preparing memory map entries for second kernel */ 46dd5f7260SVivek Goyal struct crash_memmap_data { 47dd5f7260SVivek Goyal struct boot_params *params; 48dd5f7260SVivek Goyal /* Type of memory */ 49dd5f7260SVivek Goyal unsigned int type; 50dd5f7260SVivek Goyal }; 51dd5f7260SVivek Goyal 52f23d1f4aSZhang Yanfei /* 53f23d1f4aSZhang Yanfei * This is used to VMCLEAR all VMCSs loaded on the 54f23d1f4aSZhang Yanfei * processor. And when loading kvm_intel module, the 55f23d1f4aSZhang Yanfei * callback function pointer will be assigned. 56f23d1f4aSZhang Yanfei * 57f23d1f4aSZhang Yanfei * protected by rcu. 58f23d1f4aSZhang Yanfei */ 590ca0d818SZhang Yanfei crash_vmclear_fn __rcu *crash_vmclear_loaded_vmcss = NULL; 60f23d1f4aSZhang Yanfei EXPORT_SYMBOL_GPL(crash_vmclear_loaded_vmcss); 61f23d1f4aSZhang Yanfei 62f23d1f4aSZhang Yanfei static inline void cpu_crash_vmclear_loaded_vmcss(void) 63f23d1f4aSZhang Yanfei { 640ca0d818SZhang Yanfei crash_vmclear_fn *do_vmclear_operation = NULL; 65f23d1f4aSZhang Yanfei 66f23d1f4aSZhang Yanfei rcu_read_lock(); 67f23d1f4aSZhang Yanfei do_vmclear_operation = rcu_dereference(crash_vmclear_loaded_vmcss); 68f23d1f4aSZhang Yanfei if (do_vmclear_operation) 69f23d1f4aSZhang Yanfei do_vmclear_operation(); 70f23d1f4aSZhang Yanfei rcu_read_unlock(); 71f23d1f4aSZhang Yanfei } 72f23d1f4aSZhang Yanfei 736f599d84SLianbo Jiang /* 746f599d84SLianbo Jiang * When the crashkernel option is specified, only use the low 756f599d84SLianbo Jiang * 1M for the real mode trampoline. 766f599d84SLianbo Jiang */ 776f599d84SLianbo Jiang void __init crash_reserve_low_1M(void) 786f599d84SLianbo Jiang { 796f599d84SLianbo Jiang if (cmdline_find_option(boot_command_line, "crashkernel", NULL, 0) < 0) 806f599d84SLianbo Jiang return; 816f599d84SLianbo Jiang 826f599d84SLianbo Jiang memblock_reserve(0, 1<<20); 836f599d84SLianbo Jiang pr_info("Reserving the low 1M of memory for crashkernel\n"); 846f599d84SLianbo Jiang } 856f599d84SLianbo Jiang 86b2bbe71bSEduardo Habkost #if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC) 87b2bbe71bSEduardo Habkost 889c48f1c6SDon Zickus static void kdump_nmi_callback(int cpu, struct pt_regs *regs) 8962a31a03SHiroshi Shimamoto { 90a7d41820SEduardo Habkost crash_save_cpu(regs, cpu); 91a7d41820SEduardo Habkost 92f23d1f4aSZhang Yanfei /* 93f23d1f4aSZhang Yanfei * VMCLEAR VMCSs loaded on all cpus if needed. 94f23d1f4aSZhang Yanfei */ 95f23d1f4aSZhang Yanfei cpu_crash_vmclear_loaded_vmcss(); 96f23d1f4aSZhang Yanfei 972340b62fSEduardo Habkost /* Disable VMX or SVM if needed. 982340b62fSEduardo Habkost * 992340b62fSEduardo Habkost * We need to disable virtualization on all CPUs. 1002340b62fSEduardo Habkost * Having VMX or SVM enabled on any CPU may break rebooting 1012340b62fSEduardo Habkost * after the kdump kernel has finished its task. 1022340b62fSEduardo Habkost */ 1032340b62fSEduardo Habkost cpu_emergency_vmxoff(); 1042340b62fSEduardo Habkost cpu_emergency_svm_disable(); 1052340b62fSEduardo Habkost 106da06a43dSTakao Indoh /* 107da06a43dSTakao Indoh * Disable Intel PT to stop its logging 108da06a43dSTakao Indoh */ 109da06a43dSTakao Indoh cpu_emergency_stop_pt(); 110da06a43dSTakao Indoh 111a7d41820SEduardo Habkost disable_local_APIC(); 112a7d41820SEduardo Habkost } 113a7d41820SEduardo Habkost 1140ee59413SHidehiro Kawai void kdump_nmi_shootdown_cpus(void) 115d1e7b91cSEduardo Habkost { 1168e294786SEduardo Habkost nmi_shootdown_cpus(kdump_nmi_callback); 117d1e7b91cSEduardo Habkost 11862a31a03SHiroshi Shimamoto disable_local_APIC(); 11962a31a03SHiroshi Shimamoto } 120d1e7b91cSEduardo Habkost 1210ee59413SHidehiro Kawai /* Override the weak function in kernel/panic.c */ 1220ee59413SHidehiro Kawai void crash_smp_send_stop(void) 1230ee59413SHidehiro Kawai { 1240ee59413SHidehiro Kawai static int cpus_stopped; 1250ee59413SHidehiro Kawai 1260ee59413SHidehiro Kawai if (cpus_stopped) 1270ee59413SHidehiro Kawai return; 1280ee59413SHidehiro Kawai 1290ee59413SHidehiro Kawai if (smp_ops.crash_stop_other_cpus) 1300ee59413SHidehiro Kawai smp_ops.crash_stop_other_cpus(); 1310ee59413SHidehiro Kawai else 1320ee59413SHidehiro Kawai smp_send_stop(); 1330ee59413SHidehiro Kawai 1340ee59413SHidehiro Kawai cpus_stopped = 1; 1350ee59413SHidehiro Kawai } 1360ee59413SHidehiro Kawai 13762a31a03SHiroshi Shimamoto #else 1380ee59413SHidehiro Kawai void crash_smp_send_stop(void) 13962a31a03SHiroshi Shimamoto { 14062a31a03SHiroshi Shimamoto /* There are no cpus to shootdown */ 14162a31a03SHiroshi Shimamoto } 14262a31a03SHiroshi Shimamoto #endif 14362a31a03SHiroshi Shimamoto 144ed23dc6fSGlauber Costa void native_machine_crash_shutdown(struct pt_regs *regs) 14562a31a03SHiroshi Shimamoto { 14662a31a03SHiroshi Shimamoto /* This function is only called after the system 14762a31a03SHiroshi Shimamoto * has panicked or is otherwise in a critical state. 14862a31a03SHiroshi Shimamoto * The minimum amount of code to allow a kexec'd kernel 14962a31a03SHiroshi Shimamoto * to run successfully needs to happen here. 15062a31a03SHiroshi Shimamoto * 15162a31a03SHiroshi Shimamoto * In practice this means shooting down the other cpus in 15262a31a03SHiroshi Shimamoto * an SMP system. 15362a31a03SHiroshi Shimamoto */ 15462a31a03SHiroshi Shimamoto /* The kernel is broken so disable interrupts */ 15562a31a03SHiroshi Shimamoto local_irq_disable(); 15662a31a03SHiroshi Shimamoto 1570ee59413SHidehiro Kawai crash_smp_send_stop(); 1582340b62fSEduardo Habkost 159f23d1f4aSZhang Yanfei /* 160f23d1f4aSZhang Yanfei * VMCLEAR VMCSs loaded on this cpu if needed. 161f23d1f4aSZhang Yanfei */ 162f23d1f4aSZhang Yanfei cpu_crash_vmclear_loaded_vmcss(); 163f23d1f4aSZhang Yanfei 1642340b62fSEduardo Habkost /* Booting kdump kernel with VMX or SVM enabled won't work, 1652340b62fSEduardo Habkost * because (among other limitations) we can't disable paging 1662340b62fSEduardo Habkost * with the virt flags. 1672340b62fSEduardo Habkost */ 1682340b62fSEduardo Habkost cpu_emergency_vmxoff(); 1692340b62fSEduardo Habkost cpu_emergency_svm_disable(); 1702340b62fSEduardo Habkost 171da06a43dSTakao Indoh /* 172da06a43dSTakao Indoh * Disable Intel PT to stop its logging 173da06a43dSTakao Indoh */ 174da06a43dSTakao Indoh cpu_emergency_stop_pt(); 175da06a43dSTakao Indoh 17617405453SYoshihiro YUNOMAE #ifdef CONFIG_X86_IO_APIC 17717405453SYoshihiro YUNOMAE /* Prevent crash_kexec() from deadlocking on ioapic_lock. */ 17817405453SYoshihiro YUNOMAE ioapic_zap_locks(); 179339b2ae0SBaoquan He clear_IO_APIC(); 18062a31a03SHiroshi Shimamoto #endif 181522e6646SFenghua Yu lapic_shutdown(); 182339b2ae0SBaoquan He restore_boot_irq_mode(); 1830c1b2724SOGAWA Hirofumi #ifdef CONFIG_HPET_TIMER 1840c1b2724SOGAWA Hirofumi hpet_disable(); 1850c1b2724SOGAWA Hirofumi #endif 18662a31a03SHiroshi Shimamoto crash_save_cpu(regs, safe_smp_processor_id()); 18762a31a03SHiroshi Shimamoto } 188dd5f7260SVivek Goyal 18974ca317cSVivek Goyal #ifdef CONFIG_KEXEC_FILE 19053b76073STiezhu Yang 1911d2e733bSTom Lendacky static int get_nr_ram_ranges_callback(struct resource *res, void *arg) 192dd5f7260SVivek Goyal { 193e3c41e37SLee, Chun-Yi unsigned int *nr_ranges = arg; 194dd5f7260SVivek Goyal 195dd5f7260SVivek Goyal (*nr_ranges)++; 196dd5f7260SVivek Goyal return 0; 197dd5f7260SVivek Goyal } 198dd5f7260SVivek Goyal 199dd5f7260SVivek Goyal /* Gather all the required information to prepare elf headers for ram regions */ 2008d5f894aSAKASHI Takahiro static struct crash_mem *fill_up_crash_elf_data(void) 201dd5f7260SVivek Goyal { 202dd5f7260SVivek Goyal unsigned int nr_ranges = 0; 2038d5f894aSAKASHI Takahiro struct crash_mem *cmem; 204dd5f7260SVivek Goyal 2059eff3037SBorislav Petkov walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback); 2068d5f894aSAKASHI Takahiro if (!nr_ranges) 2078d5f894aSAKASHI Takahiro return NULL; 208dd5f7260SVivek Goyal 2098d5f894aSAKASHI Takahiro /* 2108d5f894aSAKASHI Takahiro * Exclusion of crash region and/or crashk_low_res may cause 2118d5f894aSAKASHI Takahiro * another range split. So add extra two slots here. 2128d5f894aSAKASHI Takahiro */ 2138d5f894aSAKASHI Takahiro nr_ranges += 2; 2144df43095SGustavo A. R. Silva cmem = vzalloc(struct_size(cmem, ranges, nr_ranges)); 2158d5f894aSAKASHI Takahiro if (!cmem) 2168d5f894aSAKASHI Takahiro return NULL; 217dd5f7260SVivek Goyal 2188d5f894aSAKASHI Takahiro cmem->max_nr_ranges = nr_ranges; 2198d5f894aSAKASHI Takahiro cmem->nr_ranges = 0; 220dd5f7260SVivek Goyal 2218d5f894aSAKASHI Takahiro return cmem; 222dd5f7260SVivek Goyal } 223dd5f7260SVivek Goyal 224dd5f7260SVivek Goyal /* 225dd5f7260SVivek Goyal * Look for any unwanted ranges between mstart, mend and remove them. This 2268d5f894aSAKASHI Takahiro * might lead to split and split ranges are put in cmem->ranges[] array 227dd5f7260SVivek Goyal */ 2288d5f894aSAKASHI Takahiro static int elf_header_exclude_ranges(struct crash_mem *cmem) 229dd5f7260SVivek Goyal { 230dd5f7260SVivek Goyal int ret = 0; 231dd5f7260SVivek Goyal 2327c321eb2SLianbo Jiang /* Exclude the low 1M because it is always reserved */ 2337c321eb2SLianbo Jiang ret = crash_exclude_mem_range(cmem, 0, 1<<20); 2347c321eb2SLianbo Jiang if (ret) 2357c321eb2SLianbo Jiang return ret; 2367c321eb2SLianbo Jiang 237dd5f7260SVivek Goyal /* Exclude crashkernel region */ 238babac4a8SAKASHI Takahiro ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end); 239dd5f7260SVivek Goyal if (ret) 240dd5f7260SVivek Goyal return ret; 241dd5f7260SVivek Goyal 2429eff3037SBorislav Petkov if (crashk_low_res.end) 243babac4a8SAKASHI Takahiro ret = crash_exclude_mem_range(cmem, crashk_low_res.start, 244babac4a8SAKASHI Takahiro crashk_low_res.end); 245dd5f7260SVivek Goyal 246dd5f7260SVivek Goyal return ret; 247dd5f7260SVivek Goyal } 248dd5f7260SVivek Goyal 2491d2e733bSTom Lendacky static int prepare_elf64_ram_headers_callback(struct resource *res, void *arg) 250dd5f7260SVivek Goyal { 2518d5f894aSAKASHI Takahiro struct crash_mem *cmem = arg; 252dd5f7260SVivek Goyal 253cbe66016SAKASHI Takahiro cmem->ranges[cmem->nr_ranges].start = res->start; 254cbe66016SAKASHI Takahiro cmem->ranges[cmem->nr_ranges].end = res->end; 255cbe66016SAKASHI Takahiro cmem->nr_ranges++; 256dd5f7260SVivek Goyal 257cbe66016SAKASHI Takahiro return 0; 258dd5f7260SVivek Goyal } 259dd5f7260SVivek Goyal 260dd5f7260SVivek Goyal /* Prepare elf headers. Return addr and size */ 261dd5f7260SVivek Goyal static int prepare_elf_headers(struct kimage *image, void **addr, 262dd5f7260SVivek Goyal unsigned long *sz) 263dd5f7260SVivek Goyal { 2648d5f894aSAKASHI Takahiro struct crash_mem *cmem; 2657c321eb2SLianbo Jiang int ret; 266dd5f7260SVivek Goyal 2678d5f894aSAKASHI Takahiro cmem = fill_up_crash_elf_data(); 2688d5f894aSAKASHI Takahiro if (!cmem) 269dd5f7260SVivek Goyal return -ENOMEM; 270dd5f7260SVivek Goyal 2719eff3037SBorislav Petkov ret = walk_system_ram_res(0, -1, cmem, prepare_elf64_ram_headers_callback); 272cbe66016SAKASHI Takahiro if (ret) 273cbe66016SAKASHI Takahiro goto out; 274cbe66016SAKASHI Takahiro 275cbe66016SAKASHI Takahiro /* Exclude unwanted mem ranges */ 2768d5f894aSAKASHI Takahiro ret = elf_header_exclude_ranges(cmem); 277cbe66016SAKASHI Takahiro if (ret) 278cbe66016SAKASHI Takahiro goto out; 279cbe66016SAKASHI Takahiro 280dd5f7260SVivek Goyal /* By default prepare 64bit headers */ 2819eff3037SBorislav Petkov ret = crash_prepare_elf64_headers(cmem, IS_ENABLED(CONFIG_X86_64), addr, sz); 282cbe66016SAKASHI Takahiro 283cbe66016SAKASHI Takahiro out: 2848d5f894aSAKASHI Takahiro vfree(cmem); 285dd5f7260SVivek Goyal return ret; 286dd5f7260SVivek Goyal } 287dd5f7260SVivek Goyal 2888ec67d97SIngo Molnar static int add_e820_entry(struct boot_params *params, struct e820_entry *entry) 289dd5f7260SVivek Goyal { 290dd5f7260SVivek Goyal unsigned int nr_e820_entries; 291dd5f7260SVivek Goyal 292dd5f7260SVivek Goyal nr_e820_entries = params->e820_entries; 29308b46d5dSIngo Molnar if (nr_e820_entries >= E820_MAX_ENTRIES_ZEROPAGE) 294dd5f7260SVivek Goyal return 1; 295dd5f7260SVivek Goyal 2969eff3037SBorislav Petkov memcpy(¶ms->e820_table[nr_e820_entries], entry, sizeof(struct e820_entry)); 297dd5f7260SVivek Goyal params->e820_entries++; 298dd5f7260SVivek Goyal return 0; 299dd5f7260SVivek Goyal } 300dd5f7260SVivek Goyal 3011d2e733bSTom Lendacky static int memmap_entry_callback(struct resource *res, void *arg) 302dd5f7260SVivek Goyal { 303dd5f7260SVivek Goyal struct crash_memmap_data *cmd = arg; 304dd5f7260SVivek Goyal struct boot_params *params = cmd->params; 3058ec67d97SIngo Molnar struct e820_entry ei; 306dd5f7260SVivek Goyal 3071d2e733bSTom Lendacky ei.addr = res->start; 3089275b933Skbuild test robot ei.size = resource_size(res); 309dd5f7260SVivek Goyal ei.type = cmd->type; 310dd5f7260SVivek Goyal add_e820_entry(params, &ei); 311dd5f7260SVivek Goyal 312dd5f7260SVivek Goyal return 0; 313dd5f7260SVivek Goyal } 314dd5f7260SVivek Goyal 315dd5f7260SVivek Goyal static int memmap_exclude_ranges(struct kimage *image, struct crash_mem *cmem, 316dd5f7260SVivek Goyal unsigned long long mstart, 317dd5f7260SVivek Goyal unsigned long long mend) 318dd5f7260SVivek Goyal { 319dd5f7260SVivek Goyal unsigned long start, end; 320dd5f7260SVivek Goyal 321dd5f7260SVivek Goyal cmem->ranges[0].start = mstart; 322dd5f7260SVivek Goyal cmem->ranges[0].end = mend; 323dd5f7260SVivek Goyal cmem->nr_ranges = 1; 324dd5f7260SVivek Goyal 325dd5f7260SVivek Goyal /* Exclude elf header region */ 326dd5f7260SVivek Goyal start = image->arch.elf_load_addr; 327dd5f7260SVivek Goyal end = start + image->arch.elf_headers_sz - 1; 328babac4a8SAKASHI Takahiro return crash_exclude_mem_range(cmem, start, end); 329dd5f7260SVivek Goyal } 330dd5f7260SVivek Goyal 331dd5f7260SVivek Goyal /* Prepare memory map for crash dump kernel */ 332dd5f7260SVivek Goyal int crash_setup_memmap_entries(struct kimage *image, struct boot_params *params) 333dd5f7260SVivek Goyal { 334dd5f7260SVivek Goyal int i, ret = 0; 335dd5f7260SVivek Goyal unsigned long flags; 3368ec67d97SIngo Molnar struct e820_entry ei; 337dd5f7260SVivek Goyal struct crash_memmap_data cmd; 338dd5f7260SVivek Goyal struct crash_mem *cmem; 339dd5f7260SVivek Goyal 340dd5f7260SVivek Goyal cmem = vzalloc(sizeof(struct crash_mem)); 341dd5f7260SVivek Goyal if (!cmem) 342dd5f7260SVivek Goyal return -ENOMEM; 343dd5f7260SVivek Goyal 344dd5f7260SVivek Goyal memset(&cmd, 0, sizeof(struct crash_memmap_data)); 345dd5f7260SVivek Goyal cmd.params = params; 346dd5f7260SVivek Goyal 3477c321eb2SLianbo Jiang /* Add the low 1M */ 3487c321eb2SLianbo Jiang cmd.type = E820_TYPE_RAM; 3497c321eb2SLianbo Jiang flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; 3507c321eb2SLianbo Jiang walk_iomem_res_desc(IORES_DESC_NONE, flags, 0, (1<<20)-1, &cmd, 3517c321eb2SLianbo Jiang memmap_entry_callback); 352dd5f7260SVivek Goyal 353dd5f7260SVivek Goyal /* Add ACPI tables */ 35409821ff1SIngo Molnar cmd.type = E820_TYPE_ACPI; 355dd5f7260SVivek Goyal flags = IORESOURCE_MEM | IORESOURCE_BUSY; 356f0f4711aSToshi Kani walk_iomem_res_desc(IORES_DESC_ACPI_TABLES, flags, 0, -1, &cmd, 357dd5f7260SVivek Goyal memmap_entry_callback); 358dd5f7260SVivek Goyal 359dd5f7260SVivek Goyal /* Add ACPI Non-volatile Storage */ 36009821ff1SIngo Molnar cmd.type = E820_TYPE_NVS; 361f0f4711aSToshi Kani walk_iomem_res_desc(IORES_DESC_ACPI_NV_STORAGE, flags, 0, -1, &cmd, 362dd5f7260SVivek Goyal memmap_entry_callback); 363dd5f7260SVivek Goyal 364980621daSLianbo Jiang /* Add e820 reserved ranges */ 365980621daSLianbo Jiang cmd.type = E820_TYPE_RESERVED; 366980621daSLianbo Jiang flags = IORESOURCE_MEM; 367980621daSLianbo Jiang walk_iomem_res_desc(IORES_DESC_RESERVED, flags, 0, -1, &cmd, 368980621daSLianbo Jiang memmap_entry_callback); 369980621daSLianbo Jiang 370dd5f7260SVivek Goyal /* Add crashk_low_res region */ 371dd5f7260SVivek Goyal if (crashk_low_res.end) { 372dd5f7260SVivek Goyal ei.addr = crashk_low_res.start; 373dd5f7260SVivek Goyal ei.size = crashk_low_res.end - crashk_low_res.start + 1; 37409821ff1SIngo Molnar ei.type = E820_TYPE_RAM; 375dd5f7260SVivek Goyal add_e820_entry(params, &ei); 376dd5f7260SVivek Goyal } 377dd5f7260SVivek Goyal 378dd5f7260SVivek Goyal /* Exclude some ranges from crashk_res and add rest to memmap */ 3799eff3037SBorislav Petkov ret = memmap_exclude_ranges(image, cmem, crashk_res.start, crashk_res.end); 380dd5f7260SVivek Goyal if (ret) 381dd5f7260SVivek Goyal goto out; 382dd5f7260SVivek Goyal 383dd5f7260SVivek Goyal for (i = 0; i < cmem->nr_ranges; i++) { 384dd5f7260SVivek Goyal ei.size = cmem->ranges[i].end - cmem->ranges[i].start + 1; 385dd5f7260SVivek Goyal 386dd5f7260SVivek Goyal /* If entry is less than a page, skip it */ 387dd5f7260SVivek Goyal if (ei.size < PAGE_SIZE) 388dd5f7260SVivek Goyal continue; 389dd5f7260SVivek Goyal ei.addr = cmem->ranges[i].start; 39009821ff1SIngo Molnar ei.type = E820_TYPE_RAM; 391dd5f7260SVivek Goyal add_e820_entry(params, &ei); 392dd5f7260SVivek Goyal } 393dd5f7260SVivek Goyal 394dd5f7260SVivek Goyal out: 395dd5f7260SVivek Goyal vfree(cmem); 396dd5f7260SVivek Goyal return ret; 397dd5f7260SVivek Goyal } 398dd5f7260SVivek Goyal 399dd5f7260SVivek Goyal int crash_load_segments(struct kimage *image) 400dd5f7260SVivek Goyal { 401dd5f7260SVivek Goyal int ret; 402ec2b9bfaSThiago Jung Bauermann struct kexec_buf kbuf = { .image = image, .buf_min = 0, 403ec2b9bfaSThiago Jung Bauermann .buf_max = ULONG_MAX, .top_down = false }; 404dd5f7260SVivek Goyal 405dd5f7260SVivek Goyal /* Prepare elf headers and add a segment */ 406ec2b9bfaSThiago Jung Bauermann ret = prepare_elf_headers(image, &kbuf.buffer, &kbuf.bufsz); 407dd5f7260SVivek Goyal if (ret) 408dd5f7260SVivek Goyal return ret; 409dd5f7260SVivek Goyal 410ec2b9bfaSThiago Jung Bauermann image->arch.elf_headers = kbuf.buffer; 411ec2b9bfaSThiago Jung Bauermann image->arch.elf_headers_sz = kbuf.bufsz; 412dd5f7260SVivek Goyal 413ec2b9bfaSThiago Jung Bauermann kbuf.memsz = kbuf.bufsz; 414ec2b9bfaSThiago Jung Bauermann kbuf.buf_align = ELF_CORE_HEADER_ALIGN; 415993a1103SDave Young kbuf.mem = KEXEC_BUF_MEM_UNKNOWN; 416ec2b9bfaSThiago Jung Bauermann ret = kexec_add_buffer(&kbuf); 417dd5f7260SVivek Goyal if (ret) { 418dd5f7260SVivek Goyal vfree((void *)image->arch.elf_headers); 419dd5f7260SVivek Goyal return ret; 420dd5f7260SVivek Goyal } 421ec2b9bfaSThiago Jung Bauermann image->arch.elf_load_addr = kbuf.mem; 422dd5f7260SVivek Goyal pr_debug("Loaded ELF headers at 0x%lx bufsz=0x%lx memsz=0x%lx\n", 423ec2b9bfaSThiago Jung Bauermann image->arch.elf_load_addr, kbuf.bufsz, kbuf.bufsz); 424dd5f7260SVivek Goyal 425dd5f7260SVivek Goyal return ret; 426dd5f7260SVivek Goyal } 42774ca317cSVivek Goyal #endif /* CONFIG_KEXEC_FILE */ 428