// SPDX-License-Identifier: GPL-2.0-only/* * Copyright (C) 1995 Linus Torvalds * * This file contains the setup_arch() code, which handles the architecture-dependent * parts of early kernel initialization. */#include <linux/console.h>#include <linux/crash_dump.h>#include <linux/dma-map-ops.h>#include <linux/dmi.h>#include <linux/efi.h>#include <linux/init_ohci1394_dma.h>#include <linux/initrd.h>#include <linux/iscsi_ibft.h>#include <linux/memblock.h>#include <linux/pci.h>#include <linux/root_dev.h>#include <linux/hugetlb.h>#include <linux/tboot.h>#include <linux/usb/xhci-dbgp.h>#include <linux/static_call.h>#include <linux/swiotlb.h> #include <uapi/linux/mount.h> #include <xen/xen.h> #include <asm/apic.h>#include <asm/numa.h>#include <asm/bios_ebda.h>#include <asm/bugs.h>#include <asm/cpu.h>#include <asm/efi.h>#include <asm/gart.h>#include <asm/hypervisor.h>#include <asm/io_apic.h>#include <asm/kasan.h>#include <asm/kaslr.h>#include <asm/mce.h>#include <asm/mtrr.h>#include <asm/realmode.h>#include <asm/olpc_ofw.h>#include <asm/pci-direct.h>#include <asm/prom.h>#include <asm/proto.h>#include <asm/thermal.h>#include <asm/unwind.h>#include <asm/vsyscall.h>#include <linux/vmalloc.h> /* * max_low_pfn_mapped: highest directly mapped pfn < 4 GB * max_pfn_mapped: highest directly mapped pfn > 4 GB * * The direct mapping only covers E820_TYPE_RAM regions, so the ranges and gaps are * represented by pfn_mapped[]. */unsigned long max_low_pfn_mapped;unsigned long max_pfn_mapped; #ifdef CONFIG_DMIRESERVE_BRK(dmi_alloc, 65536);#endif /* * Range of the BSS area. The size of the BSS area is determined * at link time, with RESERVE_BRK() facility reserving additional * chunks. */unsigned long _brk_start = (unsigned long)__brk_base;unsigned long _brk_end = (unsigned long)__brk_base; struct boot_params boot_params; /* * These are the four main kernel memory regions, we put them into * the resource tree so that kdump tools and other debugging tools * recover it: */ static struct resource rodata_resource = { .name = "Kernel rodata", .start = 0, .end = 0, .flags = IORESOURCE_BUSY | IORESOURCE_SYSTEM_RAM}; static struct resource data_resource = { .name = "Kernel data", .start = 0, .end = 0, .flags = IORESOURCE_BUSY | IORESOURCE_SYSTEM_RAM}; static struct resource code_resource = { .name = "Kernel code", .start = 0, .end = 0, .flags = IORESOURCE_BUSY | IORESOURCE_SYSTEM_RAM}; static struct resource bss_resource = { .name = "Kernel bss", .start = 0, .end = 0, .flags = IORESOURCE_BUSY | IORESOURCE_SYSTEM_RAM}; #ifdef CONFIG_X86_32/* CPU data as detected by the assembly code in head_32.S */struct cpuinfo_x86 new_cpu_data; /* Common CPU data for all CPUs */struct cpuinfo_x86 boot_cpu_data __read_mostly;EXPORT_SYMBOL(boot_cpu_data); unsigned int def_to_bigsmp; struct apm_info apm_info;EXPORT_SYMBOL(apm_info); #if defined(CONFIG_X86_SPEEDSTEP_SMI) || \ defined(CONFIG_X86_SPEEDSTEP_SMI_MODULE)struct ist_info ist_info;EXPORT_SYMBOL(ist_info);#elsestruct ist_info ist_info;#endif #elsestruct cpuinfo_x86 boot_cpu_data __read_mostly;EXPORT_SYMBOL(boot_cpu_data);#endif #if !defined(CONFIG_X86_PAE) || defined(CONFIG_X86_64)__visible unsigned long mmu_cr4_features __ro_after_init;#else__visible unsigned long mmu_cr4_features __ro_after_init = X86_CR4_PAE;#endif /* Boot loader ID and version as integers, for the benefit of proc_dointvec */int bootloader_type, bootloader_version; /* * Setup options */struct screen_info screen_info;EXPORT_SYMBOL(screen_info);struct edid_info edid_info;EXPORT_SYMBOL_GPL(edid_info); extern int root_mountflags; unsigned long saved_video_mode; #define RAMDISK_IMAGE_START_MASK 0x07FF#define RAMDISK_PROMPT_FLAG 0x8000#define RAMDISK_LOAD_FLAG 0x4000 static char __initdata command_line[COMMAND_LINE_SIZE];#ifdef CONFIG_CMDLINE_BOOLstatic char __initdata builtin_cmdline[COMMAND_LINE_SIZE] = CONFIG_CMDLINE;#endif #if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)struct edd edd;#ifdef CONFIG_EDD_MODULEEXPORT_SYMBOL(edd);#endif/** * copy_edd() - Copy the BIOS EDD information * from boot_params into a safe place. * */static inline void __init copy_edd(void){ memcpy(edd.mbr_signature, boot_params.edd_mbr_sig_buffer, sizeof(edd.mbr_signature)); memcpy(edd.edd_info, boot_params.eddbuf, sizeof(edd.edd_info)); edd.mbr_signature_nr = boot_params.edd_mbr_sig_buf_entries; edd.edd_info_nr = boot_params.eddbuf_entries;}#elsestatic inline void __init copy_edd(void){}#endif void * __init extend_brk(size_t size, size_t align){ size_t mask = align - 1; void *ret; BUG_ON(_brk_start == 0); BUG_ON(align & mask); _brk_end = (_brk_end + mask) & ~mask; BUG_ON((char *)(_brk_end + size) > __brk_limit); ret = (void *)_brk_end; _brk_end += size; memset(ret, 0, size); return ret;} #ifdef CONFIG_X86_32static void __init cleanup_highmap(void){}#endif static void __init reserve_brk(void){ if (_brk_end > _brk_start) memblock_reserve(__pa_symbol(_brk_start), _brk_end - _brk_start); /* Mark brk area as locked down and no longer taking any new allocations */ _brk_start = 0;} u64 relocated_ramdisk; #ifdef CONFIG_BLK_DEV_INITRD static u64 __init get_ramdisk_image(void){ u64 ramdisk_image = boot_params.hdr.ramdisk_image; ramdisk_image |= (u64)boot_params.ext_ramdisk_image << 32; if (ramdisk_image == 0) ramdisk_image = phys_initrd_start; return ramdisk_image;}static u64 __init get_ramdisk_size(void){ u64 ramdisk_size = boot_params.hdr.ramdisk_size; ramdisk_size |= (u64)boot_params.ext_ramdisk_size << 32; if (ramdisk_size == 0) ramdisk_size = phys_initrd_size; return ramdisk_size;} static void __init relocate_initrd(void){ /* Assume only end is not page aligned */ u64 ramdisk_image = get_ramdisk_image(); u64 ramdisk_size = get_ramdisk_size(); u64 area_size = PAGE_ALIGN(ramdisk_size); /* We need to move the initrd down into directly mapped mem */ relocated_ramdisk = memblock_phys_alloc_range(area_size, PAGE_SIZE, 0, PFN_PHYS(max_pfn_mapped)); if (!relocated_ramdisk) panic("Cannot find place for new RAMDISK of size %lld\n", ramdisk_size); initrd_start = relocated_ramdisk + PAGE_OFFSET; initrd_end = initrd_start + ramdisk_size; printk(KERN_INFO "Allocated new RAMDISK: [mem %#010llx-%#010llx]\n", relocated_ramdisk, relocated_ramdisk + ramdisk_size - 1); copy_from_early_mem((void *)initrd_start, ramdisk_image, ramdisk_size); printk(KERN_INFO "Move RAMDISK from [mem %#010llx-%#010llx] to" " [mem %#010llx-%#010llx]\n", ramdisk_image, ramdisk_image + ramdisk_size - 1, relocated_ramdisk, relocated_ramdisk + ramdisk_size - 1);} static void __init early_reserve_initrd(void){ /* Assume only end is not page aligned */ u64 ramdisk_image = get_ramdisk_image(); u64 ramdisk_size = get_ramdisk_size(); u64 ramdisk_end = PAGE_ALIGN(ramdisk_image + ramdisk_size); if (!boot_params.hdr.type_of_loader || !ramdisk_image || !ramdisk_size) return; /* No initrd provided by bootloader */ memblock_reserve(ramdisk_image, ramdisk_end - ramdisk_image);} static void __init reserve_initrd(void){ /* Assume only end is not page aligned */ u64 ramdisk_image = get_ramdisk_image(); u64 ramdisk_size = get_ramdisk_size(); u64 ramdisk_end = PAGE_ALIGN(ramdisk_image + ramdisk_size); if (!boot_params.hdr.type_of_loader || !ramdisk_image || !ramdisk_size) return; /* No initrd provided by bootloader */ initrd_start = 0; printk(KERN_INFO "RAMDISK: [mem %#010llx-%#010llx]\n", ramdisk_image, ramdisk_end - 1); if (pfn_range_is_mapped(PFN_DOWN(ramdisk_image), PFN_DOWN(ramdisk_end))) { /* All are mapped, easy case */ initrd_start = ramdisk_image + PAGE_OFFSET; initrd_end = initrd_start + ramdisk_size; return; } relocate_initrd(); memblock_free(ramdisk_image, ramdisk_end - ramdisk_image);} #elsestatic void __init early_reserve_initrd(void){}static void __init reserve_initrd(void){}#endif /* CONFIG_BLK_DEV_INITRD */ static void __init parse_setup_data(void){ struct setup_data *data; u64 pa_data, pa_next; pa_data = boot_params.hdr.setup_data; while (pa_data) { u32 data_len, data_type; data = early_memremap(pa_data, sizeof(*data)); data_len = data->len + sizeof(struct setup_data); data_type = data->type; pa_next = data->next; early_memunmap(data, sizeof(*data)); switch (data_type) { case SETUP_E820_EXT: e820__memory_setup_extended(pa_data, data_len); break; case SETUP_DTB: add_dtb(pa_data); break; case SETUP_EFI: parse_efi_setup(pa_data, data_len); break; default: break; } pa_data = pa_next; }} static void __init memblock_x86_reserve_range_setup_data(void){ struct setup_data *data; u64 pa_data; pa_data = boot_params.hdr.setup_data; while (pa_data) { data = early_memremap(pa_data, sizeof(*data)); memblock_reserve(pa_data, sizeof(*data) + data->len); if (data->type == SETUP_INDIRECT && ((struct setup_indirect *)data->data)->type != SETUP_INDIRECT) memblock_reserve(((struct setup_indirect *)data->data)->addr, ((struct setup_indirect *)data->data)->len); pa_data = data->next; early_memunmap(data, sizeof(*data)); }} /* * --------- Crashkernel reservation ------------------------------ */ #ifdef CONFIG_KEXEC_CORE /* 16M alignment for crash kernel regions */#define CRASH_ALIGN SZ_16M /* * Keep the crash kernel below this limit. * * Earlier 32-bits kernels would limit the kernel to the low 512 MB range * due to mapping restrictions. * * 64-bit kdump kernels need to be restricted to be under 64 TB, which is * the upper limit of system RAM in 4-level paging mode. Since the kdump * jump could be from 5-level paging to 4-level paging, the jump will fail if * the kernel is put above 64 TB, and during the 1st kernel bootup there's * no good way to detect the paging mode of the target kernel which will be * loaded for dumping. */#ifdef CONFIG_X86_32# define CRASH_ADDR_LOW_MAX SZ_512M# define CRASH_ADDR_HIGH_MAX SZ_512M#else# define CRASH_ADDR_LOW_MAX SZ_4G# define CRASH_ADDR_HIGH_MAX SZ_64T#endif static int __init reserve_crashkernel_low(void){#ifdef CONFIG_X86_64 unsigned long long base, low_base = 0, low_size = 0; unsigned long low_mem_limit; int ret; low_mem_limit = min(memblock_phys_mem_size(), CRASH_ADDR_LOW_MAX); /* crashkernel=Y,low */ ret = parse_crashkernel_low(boot_command_line, low_mem_limit, &low_size, &base); if (ret) { /* * two parts from kernel/dma/swiotlb.c: * -swiotlb size: user-specified with swiotlb= or default. * * -swiotlb overflow buffer: now hardcoded to 32k. We round it * to 8M for other buffers that may need to stay low too. Also * make sure we allocate enough extra low memory so that we * don't run out of DMA buffers for 32-bit devices. */ low_size = max(swiotlb_size_or_default() + (8UL << 20), 256UL << 20); } else { /* passed with crashkernel=0,low ? */ if (!low_size) return 0; } low_base = memblock_phys_alloc_range(low_size, CRASH_ALIGN, 0, CRASH_ADDR_LOW_MAX); if (!low_base) { pr_err("Cannot reserve %ldMB crashkernel low memory, please try smaller size.\n", (unsigned long)(low_size >> 20)); return -ENOMEM; } pr_info("Reserving %ldMB of low memory at %ldMB for crashkernel (low RAM limit: %ldMB)\n", (unsigned long)(low_size >> 20), (unsigned long)(low_base >> 20), (unsigned long)(low_mem_limit >> 20)); crashk_low_res.start = low_base; crashk_low_res.end = low_base + low_size - 1; insert_resource(&iomem_resource, &crashk_low_res);#endif return 0;} static void __init reserve_crashkernel(void){ unsigned long long crash_size, crash_base, total_mem; bool high = false; int ret; total_mem = memblock_phys_mem_size(); /* crashkernel=XM */ ret = parse_crashkernel(boot_command_line, total_mem, &crash_size, &crash_base); if (ret != 0 || crash_size <= 0) { /* crashkernel=X,high */ ret = parse_crashkernel_high(boot_command_line, total_mem, &crash_size, &crash_base); if (ret != 0 || crash_size <= 0) return; high = true; } if (xen_pv_domain()) { pr_info("Ignoring crashkernel for a Xen PV domain\n"); return; } /* 0 means: find the address automatically */ if (!crash_base) { /* * Set CRASH_ADDR_LOW_MAX upper bound for crash memory, * crashkernel=x,high reserves memory over 4G, also allocates * 256M extra low memory for DMA buffers and swiotlb. * But the extra memory is not required for all machines. * So try low memory first and fall back to high memory * unless "crashkernel=size[KMG],high" is specified. */ if (!high) crash_base = memblock_phys_alloc_range(crash_size, CRASH_ALIGN, CRASH_ALIGN,Lines 1–500 of 1284. Load more
// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 1995 Linus Torvalds * * This file contains the setup_arch() code, which handles the architecture-dependent * parts of early kernel initialization. */ #include <linux/console.h> #include <linux/crash_dump.h> #include <linux/dma-map-ops.h> #include <linux/dmi.h> #include <linux/efi.h> #include <linux/init_ohci1394_dma.h> #include <linux/initrd.h> #include <linux/iscsi_ibft.h> #include <linux/memblock.h> #include <linux/pci.h> #include <linux/root_dev.h> #include <linux/hugetlb.h> #include <linux/tboot.h> #include <linux/usb/xhci-dbgp.h> #include <linux/static_call.h> #include <linux/swiotlb.h> #include <uapi/linux/mount.h> #include <xen/xen.h> #include <asm/apic.h> #include <asm/numa.h> #include <asm/bios_ebda.h> #include <asm/bugs.h> #include <asm/cpu.h> #include <asm/efi.h> #include <asm/gart.h> #include <asm/hypervisor.h> #include <asm/io_apic.h> #include <asm/kasan.h> #include <asm/kaslr.h> #include <asm/mce.h> #include <asm/mtrr.h> #include <asm/realmode.h> #include <asm/olpc_ofw.h> #include <asm/pci-direct.h> #include <asm/prom.h> #include <asm/proto.h> #include <asm/thermal.h> #include <asm/unwind.h> #include <asm/vsyscall.h> #include <linux/vmalloc.h> /* * max_low_pfn_mapped: highest directly mapped pfn < 4 GB * max_pfn_mapped: highest directly mapped pfn > 4 GB * * The direct mapping only covers E820_TYPE_RAM regions, so the ranges and gaps are * represented by pfn_mapped[]. */ unsigned long max_low_pfn_mapped; unsigned long max_pfn_mapped; #ifdef CONFIG_DMI RESERVE_BRK(dmi_alloc, 65536); #endif /* * Range of the BSS area. The size of the BSS area is determined * at link time, with RESERVE_BRK() facility reserving additional * chunks. */ unsigned long _brk_start = (unsigned long)__brk_base; unsigned long _brk_end = (unsigned long)__brk_base; struct boot_params boot_params; /* * These are the four main kernel memory regions, we put them into * the resource tree so that kdump tools and other debugging tools * recover it: */ static struct resource rodata_resource = { .name = "Kernel rodata", .start = 0, .end = 0, .flags = IORESOURCE_BUSY | IORESOURCE_SYSTEM_RAM }; static struct resource data_resource = { .name = "Kernel data", .start = 0, .end = 0, .flags = IORESOURCE_BUSY | IORESOURCE_SYSTEM_RAM }; static struct resource code_resource = { .name = "Kernel code", .start = 0, .end = 0, .flags = IORESOURCE_BUSY | IORESOURCE_SYSTEM_RAM }; static struct resource bss_resource = { .name = "Kernel bss", .start = 0, .end = 0, .flags = IORESOURCE_BUSY | IORESOURCE_SYSTEM_RAM }; #ifdef CONFIG_X86_32 /* CPU data as detected by the assembly code in head_32.S */ struct cpuinfo_x86 new_cpu_data; /* Common CPU data for all CPUs */ struct cpuinfo_x86 boot_cpu_data __read_mostly; EXPORT_SYMBOL(boot_cpu_data); unsigned int def_to_bigsmp; struct apm_info apm_info; EXPORT_SYMBOL(apm_info); #if defined(CONFIG_X86_SPEEDSTEP_SMI) || \ defined(CONFIG_X86_SPEEDSTEP_SMI_MODULE) struct ist_info ist_info; EXPORT_SYMBOL(ist_info); #else struct ist_info ist_info; #endif #else struct cpuinfo_x86 boot_cpu_data __read_mostly; EXPORT_SYMBOL(boot_cpu_data); #endif #if !defined(CONFIG_X86_PAE) || defined(CONFIG_X86_64) __visible unsigned long mmu_cr4_features __ro_after_init; #else __visible unsigned long mmu_cr4_features __ro_after_init = X86_CR4_PAE; #endif /* Boot loader ID and version as integers, for the benefit of proc_dointvec */ int bootloader_type, bootloader_version; /* * Setup options */ struct screen_info screen_info; EXPORT_SYMBOL(screen_info); struct edid_info edid_info; EXPORT_SYMBOL_GPL(edid_info); extern int root_mountflags; unsigned long saved_video_mode; #define RAMDISK_IMAGE_START_MASK 0x07FF #define RAMDISK_PROMPT_FLAG 0x8000 #define RAMDISK_LOAD_FLAG 0x4000 static char __initdata command_line[COMMAND_LINE_SIZE]; #ifdef CONFIG_CMDLINE_BOOL static char __initdata builtin_cmdline[COMMAND_LINE_SIZE] = CONFIG_CMDLINE; #endif #if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE) struct edd edd; #ifdef CONFIG_EDD_MODULE EXPORT_SYMBOL(edd); #endif /** * copy_edd() - Copy the BIOS EDD information * from boot_params into a safe place. * */ static inline void __init copy_edd(void) { memcpy(edd.mbr_signature, boot_params.edd_mbr_sig_buffer, sizeof(edd.mbr_signature)); memcpy(edd.edd_info, boot_params.eddbuf, sizeof(edd.edd_info)); edd.mbr_signature_nr = boot_params.edd_mbr_sig_buf_entries; edd.edd_info_nr = boot_params.eddbuf_entries; } #else static inline void __init copy_edd(void) { } #endif void * __init extend_brk(size_t size, size_t align) { size_t mask = align - 1; void *ret; BUG_ON(_brk_start == 0); BUG_ON(align & mask); _brk_end = (_brk_end + mask) & ~mask; BUG_ON((char *)(_brk_end + size) > __brk_limit); ret = (void *)_brk_end; _brk_end += size; memset(ret, 0, size); return ret; } #ifdef CONFIG_X86_32 static void __init cleanup_highmap(void) { } #endif static void __init reserve_brk(void) { if (_brk_end > _brk_start) memblock_reserve(__pa_symbol(_brk_start), _brk_end - _brk_start); /* Mark brk area as locked down and no longer taking any new allocations */ _brk_start = 0; } u64 relocated_ramdisk; #ifdef CONFIG_BLK_DEV_INITRD static u64 __init get_ramdisk_image(void) { u64 ramdisk_image = boot_params.hdr.ramdisk_image; ramdisk_image |= (u64)boot_params.ext_ramdisk_image << 32; if (ramdisk_image == 0) ramdisk_image = phys_initrd_start; return ramdisk_image; } static u64 __init get_ramdisk_size(void) { u64 ramdisk_size = boot_params.hdr.ramdisk_size; ramdisk_size |= (u64)boot_params.ext_ramdisk_size << 32; if (ramdisk_size == 0) ramdisk_size = phys_initrd_size; return ramdisk_size; } static void __init relocate_initrd(void) { /* Assume only end is not page aligned */ u64 ramdisk_image = get_ramdisk_image(); u64 ramdisk_size = get_ramdisk_size(); u64 area_size = PAGE_ALIGN(ramdisk_size); /* We need to move the initrd down into directly mapped mem */ relocated_ramdisk = memblock_phys_alloc_range(area_size, PAGE_SIZE, 0, PFN_PHYS(max_pfn_mapped)); if (!relocated_ramdisk) panic("Cannot find place for new RAMDISK of size %lld\n", ramdisk_size); initrd_start = relocated_ramdisk + PAGE_OFFSET; initrd_end = initrd_start + ramdisk_size; printk(KERN_INFO "Allocated new RAMDISK: [mem %#010llx-%#010llx]\n", relocated_ramdisk, relocated_ramdisk + ramdisk_size - 1); copy_from_early_mem((void *)initrd_start, ramdisk_image, ramdisk_size); printk(KERN_INFO "Move RAMDISK from [mem %#010llx-%#010llx] to" " [mem %#010llx-%#010llx]\n", ramdisk_image, ramdisk_image + ramdisk_size - 1, relocated_ramdisk, relocated_ramdisk + ramdisk_size - 1); } static void __init early_reserve_initrd(void) { /* Assume only end is not page aligned */ u64 ramdisk_image = get_ramdisk_image(); u64 ramdisk_size = get_ramdisk_size(); u64 ramdisk_end = PAGE_ALIGN(ramdisk_image + ramdisk_size); if (!boot_params.hdr.type_of_loader || !ramdisk_image || !ramdisk_size) return; /* No initrd provided by bootloader */ memblock_reserve(ramdisk_image, ramdisk_end - ramdisk_image); } static void __init reserve_initrd(void) { /* Assume only end is not page aligned */ u64 ramdisk_image = get_ramdisk_image(); u64 ramdisk_size = get_ramdisk_size(); u64 ramdisk_end = PAGE_ALIGN(ramdisk_image + ramdisk_size); if (!boot_params.hdr.type_of_loader || !ramdisk_image || !ramdisk_size) return; /* No initrd provided by bootloader */ initrd_start = 0; printk(KERN_INFO "RAMDISK: [mem %#010llx-%#010llx]\n", ramdisk_image, ramdisk_end - 1); if (pfn_range_is_mapped(PFN_DOWN(ramdisk_image), PFN_DOWN(ramdisk_end))) { /* All are mapped, easy case */ initrd_start = ramdisk_image + PAGE_OFFSET; initrd_end = initrd_start + ramdisk_size; return; } relocate_initrd(); memblock_free(ramdisk_image, ramdisk_end - ramdisk_image); } #else static void __init early_reserve_initrd(void) { } static void __init reserve_initrd(void) { } #endif /* CONFIG_BLK_DEV_INITRD */ static void __init parse_setup_data(void) { struct setup_data *data; u64 pa_data, pa_next; pa_data = boot_params.hdr.setup_data; while (pa_data) { u32 data_len, data_type; data = early_memremap(pa_data, sizeof(*data)); data_len = data->len + sizeof(struct setup_data); data_type = data->type; pa_next = data->next; early_memunmap(data, sizeof(*data)); switch (data_type) { case SETUP_E820_EXT: e820__memory_setup_extended(pa_data, data_len); break; case SETUP_DTB: add_dtb(pa_data); break; case SETUP_EFI: parse_efi_setup(pa_data, data_len); break; default: break; } pa_data = pa_next; } } static void __init memblock_x86_reserve_range_setup_data(void) { struct setup_data *data; u64 pa_data; pa_data = boot_params.hdr.setup_data; while (pa_data) { data = early_memremap(pa_data, sizeof(*data)); memblock_reserve(pa_data, sizeof(*data) + data->len); if (data->type == SETUP_INDIRECT && ((struct setup_indirect *)data->data)->type != SETUP_INDIRECT) memblock_reserve(((struct setup_indirect *)data->data)->addr, ((struct setup_indirect *)data->data)->len); pa_data = data->next; early_memunmap(data, sizeof(*data)); } } /* * --------- Crashkernel reservation ------------------------------ */ #ifdef CONFIG_KEXEC_CORE /* 16M alignment for crash kernel regions */ #define CRASH_ALIGN SZ_16M /* * Keep the crash kernel below this limit. * * Earlier 32-bits kernels would limit the kernel to the low 512 MB range * due to mapping restrictions. * * 64-bit kdump kernels need to be restricted to be under 64 TB, which is * the upper limit of system RAM in 4-level paging mode. Since the kdump * jump could be from 5-level paging to 4-level paging, the jump will fail if * the kernel is put above 64 TB, and during the 1st kernel bootup there's * no good way to detect the paging mode of the target kernel which will be * loaded for dumping. */ #ifdef CONFIG_X86_32 # define CRASH_ADDR_LOW_MAX SZ_512M # define CRASH_ADDR_HIGH_MAX SZ_512M #else # define CRASH_ADDR_LOW_MAX SZ_4G # define CRASH_ADDR_HIGH_MAX SZ_64T #endif static int __init reserve_crashkernel_low(void) { #ifdef CONFIG_X86_64 unsigned long long base, low_base = 0, low_size = 0; unsigned long low_mem_limit; int ret; low_mem_limit = min(memblock_phys_mem_size(), CRASH_ADDR_LOW_MAX); /* crashkernel=Y,low */ ret = parse_crashkernel_low(boot_command_line, low_mem_limit, &low_size, &base); if (ret) { /* * two parts from kernel/dma/swiotlb.c: * -swiotlb size: user-specified with swiotlb= or default. * * -swiotlb overflow buffer: now hardcoded to 32k. We round it * to 8M for other buffers that may need to stay low too. Also * make sure we allocate enough extra low memory so that we * don't run out of DMA buffers for 32-bit devices. */ low_size = max(swiotlb_size_or_default() + (8UL << 20), 256UL << 20); } else { /* passed with crashkernel=0,low ? */ if (!low_size) return 0; } low_base = memblock_phys_alloc_range(low_size, CRASH_ALIGN, 0, CRASH_ADDR_LOW_MAX); if (!low_base) { pr_err("Cannot reserve %ldMB crashkernel low memory, please try smaller size.\n", (unsigned long)(low_size >> 20)); return -ENOMEM; } pr_info("Reserving %ldMB of low memory at %ldMB for crashkernel (low RAM limit: %ldMB)\n", (unsigned long)(low_size >> 20), (unsigned long)(low_base >> 20), (unsigned long)(low_mem_limit >> 20)); crashk_low_res.start = low_base; crashk_low_res.end = low_base + low_size - 1; insert_resource(&iomem_resource, &crashk_low_res); #endif return 0; } static void __init reserve_crashkernel(void) { unsigned long long crash_size, crash_base, total_mem; bool high = false; int ret; total_mem = memblock_phys_mem_size(); /* crashkernel=XM */ ret = parse_crashkernel(boot_command_line, total_mem, &crash_size, &crash_base); if (ret != 0 || crash_size <= 0) { /* crashkernel=X,high */ ret = parse_crashkernel_high(boot_command_line, total_mem, &crash_size, &crash_base); if (ret != 0 || crash_size <= 0) return; high = true; } if (xen_pv_domain()) { pr_info("Ignoring crashkernel for a Xen PV domain\n"); return; } /* 0 means: find the address automatically */ if (!crash_base) { /* * Set CRASH_ADDR_LOW_MAX upper bound for crash memory, * crashkernel=x,high reserves memory over 4G, also allocates * 256M extra low memory for DMA buffers and swiotlb. * But the extra memory is not required for all machines. * So try low memory first and fall back to high memory * unless "crashkernel=size[KMG],high" is specified. */ if (!high) crash_base = memblock_phys_alloc_range(crash_size, CRASH_ALIGN, CRASH_ALIGN,