1350 lines · 33.0 KB · C
RawDownload
/* *  Copyright (C) 1995  Linus Torvalds * *  Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999 * *  Memory region support *	David Parsons <orc@pell.chi.il.us>, July-August 1999 * *  Added E820 sanitization routine (removes overlapping memory regions); *  Brian Moyle <bmoyle@mvista.com>, February 2001 * * Moved CPU detection code to cpu/${cpu}.c *    Patrick Mochel <mochel@osdl.org>, March 2002 * *  Provisions for empty E820 memory regions (reported by certain BIOSes). *  Alex Achenbach <xela@slit.de>, December 2002. * */ /* * This file handles the architecture-dependent parts of initialization */ #include <linux/sched.h>#include <linux/mm.h>#include <linux/mmzone.h>#include <linux/screen_info.h>#include <linux/ioport.h>#include <linux/acpi.h>#include <linux/sfi.h>#include <linux/apm_bios.h>#include <linux/initrd.h>#include <linux/bootmem.h>#include <linux/memblock.h>#include <linux/seq_file.h>#include <linux/console.h>#include <linux/root_dev.h>#include <linux/highmem.h>#include <linux/export.h>#include <linux/efi.h>#include <linux/init.h>#include <linux/edd.h>#include <linux/iscsi_ibft.h>#include <linux/nodemask.h>#include <linux/kexec.h>#include <linux/dmi.h>#include <linux/pfn.h>#include <linux/pci.h>#include <asm/pci-direct.h>#include <linux/init_ohci1394_dma.h>#include <linux/kvm_para.h>#include <linux/dma-contiguous.h> #include <linux/errno.h>#include <linux/kernel.h>#include <linux/stddef.h>#include <linux/unistd.h>#include <linux/ptrace.h>#include <linux/user.h>#include <linux/delay.h> #include <linux/kallsyms.h>#include <linux/cpufreq.h>#include <linux/dma-mapping.h>#include <linux/ctype.h>#include <linux/uaccess.h> #include <linux/percpu.h>#include <linux/crash_dump.h>#include <linux/tboot.h>#include <linux/jiffies.h> #include <linux/usb/xhci-dbgp.h>#include <video/edid.h> #include <asm/mtrr.h>#include <asm/apic.h>#include <asm/realmode.h>#include <asm/e820/api.h>#include <asm/mpspec.h>#include <asm/setup.h>#include <asm/efi.h>#include <asm/timer.h>#include <asm/i8259.h>#include <asm/sections.h>#include <asm/io_apic.h>#include <asm/ist.h>#include <asm/setup_arch.h>#include <asm/bios_ebda.h>#include <asm/cacheflush.h>#include <asm/processor.h>#include <asm/bugs.h>#include <asm/kasan.h> #include <asm/vsyscall.h>#include <asm/cpu.h>#include <asm/desc.h>#include <asm/dma.h>#include <asm/iommu.h>#include <asm/gart.h>#include <asm/mmu_context.h>#include <asm/proto.h> #include <asm/paravirt.h>#include <asm/hypervisor.h>#include <asm/olpc_ofw.h> #include <asm/percpu.h>#include <asm/topology.h>#include <asm/apicdef.h>#include <asm/amd_nb.h>#include <asm/mce.h>#include <asm/alternative.h>#include <asm/prom.h>#include <asm/microcode.h>#include <asm/mmu_context.h>#include <asm/kaslr.h> /* * max_low_pfn_mapped: highest direct mapped pfn under 4GB * max_pfn_mapped:     highest direct mapped pfn over 4GB * * 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  static __initdata unsigned long _brk_start = (unsigned long)__brk_base;unsigned long _brk_end = (unsigned long)__brk_base; #ifdef CONFIG_X86_64int default_cpu_present_to_apicid(int mps_cpu){	return __default_cpu_present_to_apicid(mps_cpu);} int default_check_phys_apicid_present(int phys_apicid){	return __default_check_phys_apicid_present(phys_apicid);}#endif struct boot_params boot_params; /* * Machine setup.. */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; /* for MCA, but anyone else can use it if they want */unsigned int machine_id;unsigned int machine_submodel_id;unsigned int BIOS_revision; 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 = {	.x86_phys_bits = MAX_PHYSMEM_BITS,};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; 	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; 	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_find_in_range(0, PFN_PHYS(max_pfn_mapped),						   area_size, PAGE_SIZE); 	if (!relocated_ramdisk)		panic("Cannot find place for new RAMDISK of size %lld\n",		      ramdisk_size); 	/* Note: this includes all the mem currently occupied by	   the initrd, we rely on that fact to keep the data intact. */	memblock_reserve(relocated_ramdisk, area_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);	u64 mapped_size; 	if (!boot_params.hdr.type_of_loader ||	    !ramdisk_image || !ramdisk_size)		return;		/* No initrd provided by bootloader */ 	initrd_start = 0; 	mapped_size = memblock_mem_size(max_pfn_mapped);	if (ramdisk_size >= (mapped_size>>1))		panic("initrd too large to handle, "		       "disabling initrd (%lld needed, %lld available)\n",		       ramdisk_size, mapped_size>>1); 	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);		pa_data = data->next;		early_memunmap(data, sizeof(*data));	}} /* * --------- Crashkernel reservation ------------------------------ */ #ifdef CONFIG_KEXEC_CORE /* 16M alignment for crash kernel regions */#define CRASH_ALIGN		(16 << 20) /* * Keep the crash kernel below this limit.  On 32 bits earlier kernels * would limit the kernel to the low 512 MiB due to mapping restrictions. * On 64bit, old kexec-tools need to under 896MiB. */#ifdef CONFIG_X86_32# define CRASH_ADDR_LOW_MAX	(512 << 20)# define CRASH_ADDR_HIGH_MAX	(512 << 20)#else# define CRASH_ADDR_LOW_MAX	(896UL << 20)# define CRASH_ADDR_HIGH_MAX	MAXMEM#endif static int __init reserve_crashkernel_low(void){#ifdef CONFIG_X86_64	unsigned long long base, low_base = 0, low_size = 0;	unsigned long total_low_mem;	int ret; 	total_low_mem = memblock_mem_size(1UL << (32 - PAGE_SHIFT)); 	/* crashkernel=Y,low */	ret = parse_crashkernel_low(boot_command_line, total_low_mem, &low_size, &base);	if (ret) {		/*		 * two parts from lib/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 {

Lines 1–500 of 1350.