diff options
Diffstat (limited to 'arch/x86/kernel/setup.c')
| -rw-r--r-- | arch/x86/kernel/setup.c | 236 | 
1 files changed, 229 insertions, 7 deletions
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 9838f2539df..0fa6790c1dd 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -223,6 +223,9 @@ unsigned long saved_video_mode;  #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; @@ -299,7 +302,7 @@ static void __init relocate_initrd(void)  		if (clen > MAX_MAP_CHUNK-slop)  			clen = MAX_MAP_CHUNK-slop;  		mapaddr = ramdisk_image & PAGE_MASK; -		p = early_ioremap(mapaddr, clen+slop); +		p = early_memremap(mapaddr, clen+slop);  		memcpy(q, p+slop, clen);  		early_iounmap(p, clen+slop);  		q += clen; @@ -376,7 +379,7 @@ static void __init parse_setup_data(void)  		return;  	pa_data = boot_params.hdr.setup_data;  	while (pa_data) { -		data = early_ioremap(pa_data, PAGE_SIZE); +		data = early_memremap(pa_data, PAGE_SIZE);  		switch (data->type) {  		case SETUP_E820_EXT:  			parse_e820_ext(data, pa_data); @@ -399,7 +402,7 @@ static void __init e820_reserve_setup_data(void)  		return;  	pa_data = boot_params.hdr.setup_data;  	while (pa_data) { -		data = early_ioremap(pa_data, sizeof(*data)); +		data = early_memremap(pa_data, sizeof(*data));  		e820_update_range(pa_data, sizeof(*data)+data->len,  			 E820_RAM, E820_RESERVED_KERN);  		found = 1; @@ -425,7 +428,7 @@ static void __init reserve_early_setup_data(void)  		return;  	pa_data = boot_params.hdr.setup_data;  	while (pa_data) { -		data = early_ioremap(pa_data, sizeof(*data)); +		data = early_memremap(pa_data, sizeof(*data));  		sprintf(buf, "setup data %x", data->type);  		reserve_early(pa_data, pa_data+sizeof(*data)+data->len, buf);  		pa_data = data->next; @@ -558,7 +561,13 @@ static void __init reserve_standard_io_resources(void)  } -#ifdef CONFIG_PROC_VMCORE +/* + * Note: elfcorehdr_addr is not just limited to vmcore. It is also used by + * is_kdump_kernel() to determine if we are booting after a panic. Hence + * ifdef it under CONFIG_CRASH_DUMP and not CONFIG_PROC_VMCORE. + */ + +#ifdef CONFIG_CRASH_DUMP  /* elfcorehdr= specifies the location of elf core header   * stored by the crashed kernel. This option will be passed   * by kexec loader to the capture kernel. @@ -579,6 +588,190 @@ static struct x86_quirks default_x86_quirks __initdata;  struct x86_quirks *x86_quirks __initdata = &default_x86_quirks;  /* + * Some BIOSes seem to corrupt the low 64k of memory during events + * like suspend/resume and unplugging an HDMI cable.  Reserve all + * remaining free memory in that area and fill it with a distinct + * pattern. + */ +#ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION +#define MAX_SCAN_AREAS	8 + +static int __read_mostly memory_corruption_check = -1; + +static unsigned __read_mostly corruption_check_size = 64*1024; +static unsigned __read_mostly corruption_check_period = 60; /* seconds */ + +static struct e820entry scan_areas[MAX_SCAN_AREAS]; +static int num_scan_areas; + + +static int set_corruption_check(char *arg) +{ +	char *end; + +	memory_corruption_check = simple_strtol(arg, &end, 10); + +	return (*end == 0) ? 0 : -EINVAL; +} +early_param("memory_corruption_check", set_corruption_check); + +static int set_corruption_check_period(char *arg) +{ +	char *end; + +	corruption_check_period = simple_strtoul(arg, &end, 10); + +	return (*end == 0) ? 0 : -EINVAL; +} +early_param("memory_corruption_check_period", set_corruption_check_period); + +static int set_corruption_check_size(char *arg) +{ +	char *end; +	unsigned size; + +	size = memparse(arg, &end); + +	if (*end == '\0') +		corruption_check_size = size; + +	return (size == corruption_check_size) ? 0 : -EINVAL; +} +early_param("memory_corruption_check_size", set_corruption_check_size); + + +static void __init setup_bios_corruption_check(void) +{ +	u64 addr = PAGE_SIZE;	/* assume first page is reserved anyway */ + +	if (memory_corruption_check == -1) { +		memory_corruption_check = +#ifdef CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK +			1 +#else +			0 +#endif +			; +	} + +	if (corruption_check_size == 0) +		memory_corruption_check = 0; + +	if (!memory_corruption_check) +		return; + +	corruption_check_size = round_up(corruption_check_size, PAGE_SIZE); + +	while(addr < corruption_check_size && num_scan_areas < MAX_SCAN_AREAS) { +		u64 size; +		addr = find_e820_area_size(addr, &size, PAGE_SIZE); + +		if (addr == 0) +			break; + +		if ((addr + size) > corruption_check_size) +			size = corruption_check_size - addr; + +		if (size == 0) +			break; + +		e820_update_range(addr, size, E820_RAM, E820_RESERVED); +		scan_areas[num_scan_areas].addr = addr; +		scan_areas[num_scan_areas].size = size; +		num_scan_areas++; + +		/* Assume we've already mapped this early memory */ +		memset(__va(addr), 0, size); + +		addr += size; +	} + +	printk(KERN_INFO "Scanning %d areas for low memory corruption\n", +	       num_scan_areas); +	update_e820(); +} + +static struct timer_list periodic_check_timer; + +void check_for_bios_corruption(void) +{ +	int i; +	int corruption = 0; + +	if (!memory_corruption_check) +		return; + +	for(i = 0; i < num_scan_areas; i++) { +		unsigned long *addr = __va(scan_areas[i].addr); +		unsigned long size = scan_areas[i].size; + +		for(; size; addr++, size -= sizeof(unsigned long)) { +			if (!*addr) +				continue; +			printk(KERN_ERR "Corrupted low memory at %p (%lx phys) = %08lx\n", +			       addr, __pa(addr), *addr); +			corruption = 1; +			*addr = 0; +		} +	} + +	WARN(corruption, KERN_ERR "Memory corruption detected in low memory\n"); +} + +static void periodic_check_for_corruption(unsigned long data) +{ +	check_for_bios_corruption(); +	mod_timer(&periodic_check_timer, round_jiffies(jiffies + corruption_check_period*HZ)); +} + +void start_periodic_check_for_corruption(void) +{ +	if (!memory_corruption_check || corruption_check_period == 0) +		return; + +	printk(KERN_INFO "Scanning for low memory corruption every %d seconds\n", +	       corruption_check_period); + +	init_timer(&periodic_check_timer); +	periodic_check_timer.function = &periodic_check_for_corruption; +	periodic_check_for_corruption(0); +} +#endif + +static int __init dmi_low_memory_corruption(const struct dmi_system_id *d) +{ +	printk(KERN_NOTICE +		"%s detected: BIOS may corrupt low RAM, working it around.\n", +		d->ident); + +	e820_update_range(0, 0x10000, E820_RAM, E820_RESERVED); +	sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map); + +	return 0; +} + +/* List of systems that have known low memory corruption BIOS problems */ +static struct dmi_system_id __initdata bad_bios_dmi_table[] = { +#ifdef CONFIG_X86_RESERVE_LOW_64K +	{ +		.callback = dmi_low_memory_corruption, +		.ident = "AMI BIOS", +		.matches = { +			DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), +		}, +	}, +	{ +		.callback = dmi_low_memory_corruption, +		.ident = "Phoenix BIOS", +		.matches = { +			DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies, LTD"), +		}, +	}, +#endif +	{} +}; + +/*   * Determine if we were loaded by an EFI loader.  If so, then we have also been   * passed the efi memmap, systab, etc., so we should use these data structures   * for initialization.  Note, the efi init code path is determined by the @@ -665,6 +858,19 @@ void __init setup_arch(char **cmdline_p)  	bss_resource.start = virt_to_phys(&__bss_start);  	bss_resource.end = virt_to_phys(&__bss_stop)-1; +#ifdef CONFIG_CMDLINE_BOOL +#ifdef CONFIG_CMDLINE_OVERRIDE +	strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE); +#else +	if (builtin_cmdline[0]) { +		/* append boot loader cmdline to builtin */ +		strlcat(builtin_cmdline, " ", COMMAND_LINE_SIZE); +		strlcat(builtin_cmdline, boot_command_line, COMMAND_LINE_SIZE); +		strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE); +	} +#endif +#endif +  	strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);  	*cmdline_p = command_line; @@ -699,6 +905,10 @@ void __init setup_arch(char **cmdline_p)  	finish_e820_parsing(); +	dmi_scan_machine(); + +	dmi_check_system(bad_bios_dmi_table); +  #ifdef CONFIG_X86_32  	probe_roms();  #endif @@ -742,6 +952,8 @@ void __init setup_arch(char **cmdline_p)  #else  	num_physpages = max_pfn; + 	if (cpu_has_x2apic) + 		check_x2apic();  	/* How many end-of-memory variables you have, grandma! */  	/* need this before calling reserve_initrd */ @@ -753,6 +965,10 @@ void __init setup_arch(char **cmdline_p)  	high_memory = (void *)__va(max_pfn * PAGE_SIZE - 1) + 1;  #endif +#ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION +	setup_bios_corruption_check(); +#endif +  	/* max_pfn_mapped is updated here */  	max_low_pfn_mapped = init_memory_mapping(0, max_low_pfn<<PAGE_SHIFT);  	max_pfn_mapped = max_low_pfn_mapped; @@ -781,8 +997,6 @@ void __init setup_arch(char **cmdline_p)  	vsmp_init();  #endif -	dmi_scan_machine(); -  	io_delay_init();  	/* @@ -790,6 +1004,8 @@ void __init setup_arch(char **cmdline_p)  	 */  	acpi_boot_table_init(); +	early_acpi_boot_init(); +  #ifdef CONFIG_ACPI_NUMA  	/*  	 * Parse SRAT to discover nodes. @@ -857,6 +1073,7 @@ void __init setup_arch(char **cmdline_p)  #endif  	prefill_possible_map(); +  #ifdef CONFIG_X86_64  	init_cpu_to_node();  #endif @@ -864,6 +1081,9 @@ void __init setup_arch(char **cmdline_p)  	init_apic_mappings();  	ioapic_init_mappings(); +	/* need to wait for io_apic is mapped */ +	nr_irqs = probe_nr_irqs(); +  	kvm_guest_init();  	e820_reserve_resources(); @@ -885,3 +1105,5 @@ void __init setup_arch(char **cmdline_p)  #endif  #endif  } + +  | 
