diff options
Diffstat (limited to 'arch/x86/kernel/crash.c')
| -rw-r--r-- | arch/x86/kernel/crash.c | 128 | 
1 files changed, 36 insertions, 92 deletions
diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c index eb651fbde92a..00fc55ac7ffa 100644 --- a/arch/x86/kernel/crash.c +++ b/arch/x86/kernel/crash.c @@ -24,6 +24,7 @@  #include <linux/export.h>  #include <linux/slab.h>  #include <linux/vmalloc.h> +#include <linux/memblock.h>  #include <asm/processor.h>  #include <asm/hardirq.h> @@ -39,6 +40,7 @@  #include <asm/virtext.h>  #include <asm/intel_pt.h>  #include <asm/crash.h> +#include <asm/cmdline.h>  /* Used while preparing memory map entries for second kernel */  struct crash_memmap_data { @@ -68,6 +70,19 @@ static inline void cpu_crash_vmclear_loaded_vmcss(void)  	rcu_read_unlock();  } +/* + * When the crashkernel option is specified, only use the low + * 1M for the real mode trampoline. + */ +void __init crash_reserve_low_1M(void) +{ +	if (cmdline_find_option(boot_command_line, "crashkernel", NULL, 0) < 0) +		return; + +	memblock_reserve(0, 1<<20); +	pr_info("Reserving the low 1M of memory for crashkernel\n"); +} +  #if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC)  static void kdump_nmi_callback(int cpu, struct pt_regs *regs) @@ -173,8 +188,6 @@ void native_machine_crash_shutdown(struct pt_regs *regs)  #ifdef CONFIG_KEXEC_FILE -static unsigned long crash_zero_bytes; -  static int get_nr_ram_ranges_callback(struct resource *res, void *arg)  {  	unsigned int *nr_ranges = arg; @@ -189,8 +202,7 @@ static struct crash_mem *fill_up_crash_elf_data(void)  	unsigned int nr_ranges = 0;  	struct crash_mem *cmem; -	walk_system_ram_res(0, -1, &nr_ranges, -				get_nr_ram_ranges_callback); +	walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback);  	if (!nr_ranges)  		return NULL; @@ -217,15 +229,19 @@ static int elf_header_exclude_ranges(struct crash_mem *cmem)  {  	int ret = 0; +	/* Exclude the low 1M because it is always reserved */ +	ret = crash_exclude_mem_range(cmem, 0, 1<<20); +	if (ret) +		return ret; +  	/* Exclude crashkernel region */  	ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end);  	if (ret)  		return ret; -	if (crashk_low_res.end) { +	if (crashk_low_res.end)  		ret = crash_exclude_mem_range(cmem, crashk_low_res.start, -							crashk_low_res.end); -	} +					      crashk_low_res.end);  	return ret;  } @@ -246,16 +262,13 @@ static int prepare_elf_headers(struct kimage *image, void **addr,  					unsigned long *sz)  {  	struct crash_mem *cmem; -	Elf64_Ehdr *ehdr; -	Elf64_Phdr *phdr; -	int ret, i; +	int ret;  	cmem = fill_up_crash_elf_data();  	if (!cmem)  		return -ENOMEM; -	ret = walk_system_ram_res(0, -1, cmem, -				prepare_elf64_ram_headers_callback); +	ret = walk_system_ram_res(0, -1, cmem, prepare_elf64_ram_headers_callback);  	if (ret)  		goto out; @@ -265,24 +278,8 @@ static int prepare_elf_headers(struct kimage *image, void **addr,  		goto out;  	/* By default prepare 64bit headers */ -	ret =  crash_prepare_elf64_headers(cmem, -				IS_ENABLED(CONFIG_X86_64), addr, sz); -	if (ret) -		goto out; +	ret =  crash_prepare_elf64_headers(cmem, IS_ENABLED(CONFIG_X86_64), addr, sz); -	/* -	 * If a range matches backup region, adjust offset to backup -	 * segment. -	 */ -	ehdr = (Elf64_Ehdr *)*addr; -	phdr = (Elf64_Phdr *)(ehdr + 1); -	for (i = 0; i < ehdr->e_phnum; phdr++, i++) -		if (phdr->p_type == PT_LOAD && -				phdr->p_paddr == image->arch.backup_src_start && -				phdr->p_memsz == image->arch.backup_src_sz) { -			phdr->p_offset = image->arch.backup_load_addr; -			break; -		}  out:  	vfree(cmem);  	return ret; @@ -296,8 +293,7 @@ static int add_e820_entry(struct boot_params *params, struct e820_entry *entry)  	if (nr_e820_entries >= E820_MAX_ENTRIES_ZEROPAGE)  		return 1; -	memcpy(¶ms->e820_table[nr_e820_entries], entry, -			sizeof(struct e820_entry)); +	memcpy(¶ms->e820_table[nr_e820_entries], entry, sizeof(struct e820_entry));  	params->e820_entries++;  	return 0;  } @@ -321,19 +317,11 @@ static int memmap_exclude_ranges(struct kimage *image, struct crash_mem *cmem,  				 unsigned long long mend)  {  	unsigned long start, end; -	int ret = 0;  	cmem->ranges[0].start = mstart;  	cmem->ranges[0].end = mend;  	cmem->nr_ranges = 1; -	/* Exclude Backup region */ -	start = image->arch.backup_load_addr; -	end = start + image->arch.backup_src_sz - 1; -	ret = crash_exclude_mem_range(cmem, start, end); -	if (ret) -		return ret; -  	/* Exclude elf header region */  	start = image->arch.elf_load_addr;  	end = start + image->arch.elf_headers_sz - 1; @@ -356,28 +344,28 @@ int crash_setup_memmap_entries(struct kimage *image, struct boot_params *params)  	memset(&cmd, 0, sizeof(struct crash_memmap_data));  	cmd.params = params; -	/* Add first 640K segment */ -	ei.addr = image->arch.backup_src_start; -	ei.size = image->arch.backup_src_sz; -	ei.type = E820_TYPE_RAM; -	add_e820_entry(params, &ei); +	/* Add the low 1M */ +	cmd.type = E820_TYPE_RAM; +	flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; +	walk_iomem_res_desc(IORES_DESC_NONE, flags, 0, (1<<20)-1, &cmd, +			    memmap_entry_callback);  	/* Add ACPI tables */  	cmd.type = E820_TYPE_ACPI;  	flags = IORESOURCE_MEM | IORESOURCE_BUSY;  	walk_iomem_res_desc(IORES_DESC_ACPI_TABLES, flags, 0, -1, &cmd, -		       memmap_entry_callback); +			    memmap_entry_callback);  	/* Add ACPI Non-volatile Storage */  	cmd.type = E820_TYPE_NVS;  	walk_iomem_res_desc(IORES_DESC_ACPI_NV_STORAGE, flags, 0, -1, &cmd, -			memmap_entry_callback); +			    memmap_entry_callback);  	/* Add e820 reserved ranges */  	cmd.type = E820_TYPE_RESERVED;  	flags = IORESOURCE_MEM;  	walk_iomem_res_desc(IORES_DESC_RESERVED, flags, 0, -1, &cmd, -			   memmap_entry_callback); +			    memmap_entry_callback);  	/* Add crashk_low_res region */  	if (crashk_low_res.end) { @@ -388,8 +376,7 @@ int crash_setup_memmap_entries(struct kimage *image, struct boot_params *params)  	}  	/* Exclude some ranges from crashk_res and add rest to memmap */ -	ret = memmap_exclude_ranges(image, cmem, crashk_res.start, -						crashk_res.end); +	ret = memmap_exclude_ranges(image, cmem, crashk_res.start, crashk_res.end);  	if (ret)  		goto out; @@ -409,55 +396,12 @@ out:  	return ret;  } -static int determine_backup_region(struct resource *res, void *arg) -{ -	struct kimage *image = arg; - -	image->arch.backup_src_start = res->start; -	image->arch.backup_src_sz = resource_size(res); - -	/* Expecting only one range for backup region */ -	return 1; -} -  int crash_load_segments(struct kimage *image)  {  	int ret;  	struct kexec_buf kbuf = { .image = image, .buf_min = 0,  				  .buf_max = ULONG_MAX, .top_down = false }; -	/* -	 * Determine and load a segment for backup area. First 640K RAM -	 * region is backup source -	 */ - -	ret = walk_system_ram_res(KEXEC_BACKUP_SRC_START, KEXEC_BACKUP_SRC_END, -				image, determine_backup_region); - -	/* Zero or postive return values are ok */ -	if (ret < 0) -		return ret; - -	/* Add backup segment. */ -	if (image->arch.backup_src_sz) { -		kbuf.buffer = &crash_zero_bytes; -		kbuf.bufsz = sizeof(crash_zero_bytes); -		kbuf.memsz = image->arch.backup_src_sz; -		kbuf.buf_align = PAGE_SIZE; -		/* -		 * Ideally there is no source for backup segment. This is -		 * copied in purgatory after crash. Just add a zero filled -		 * segment for now to make sure checksum logic works fine. -		 */ -		ret = kexec_add_buffer(&kbuf); -		if (ret) -			return ret; -		image->arch.backup_load_addr = kbuf.mem; -		pr_debug("Loaded backup region at 0x%lx backup_start=0x%lx memsz=0x%lx\n", -			 image->arch.backup_load_addr, -			 image->arch.backup_src_start, kbuf.memsz); -	} -  	/* Prepare elf headers and add a segment */  	ret = prepare_elf_headers(image, &kbuf.buffer, &kbuf.bufsz);  	if (ret)  |