aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/kernel-parameters.txt5
-rw-r--r--arch/x86/Kconfig3
-rw-r--r--arch/x86/kernel/setup.c87
-rw-r--r--arch/x86/mm/fault.c2
-rw-r--r--drivers/base/power/main.c1
-rw-r--r--include/linux/kernel.h12
6 files changed, 110 insertions, 0 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 1150444a21ab..df48af505d15 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -360,6 +360,11 @@ and is between 256 and 4096 characters. It is defined in the file
360 Format: <io>,<irq>,<mode> 360 Format: <io>,<irq>,<mode>
361 See header of drivers/net/hamradio/baycom_ser_hdx.c. 361 See header of drivers/net/hamradio/baycom_ser_hdx.c.
362 362
363 bios_corruption_check=0/1 [X86]
364 Some BIOSes seem to corrupt the first 64k of memory
365 when doing things like suspend/resume. Setting this
366 option will scan the memory looking for corruption.
367
363 boot_delay= Milliseconds to delay each printk during boot. 368 boot_delay= Milliseconds to delay each printk during boot.
364 Values larger than 10 seconds (10000) are changed to 369 Values larger than 10 seconds (10000) are changed to
365 no delay (0). 370 no delay (0).
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index ed92864d1325..1bb52e2ca02e 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -201,6 +201,9 @@ config X86_TRAMPOLINE
201 depends on X86_SMP || (X86_VOYAGER && SMP) || (64BIT && ACPI_SLEEP) 201 depends on X86_SMP || (X86_VOYAGER && SMP) || (64BIT && ACPI_SLEEP)
202 default y 202 default y
203 203
204config X86_CHECK_BIOS_CORRUPTION
205 def_bool y
206
204config KTIME_SCALAR 207config KTIME_SCALAR
205 def_bool X86_32 208 def_bool X86_32
206source "init/Kconfig" 209source "init/Kconfig"
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 362d4e7f2d38..ee89ebc5aabc 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -579,6 +579,89 @@ static struct x86_quirks default_x86_quirks __initdata;
579struct x86_quirks *x86_quirks __initdata = &default_x86_quirks; 579struct x86_quirks *x86_quirks __initdata = &default_x86_quirks;
580 580
581/* 581/*
582 * Some BIOSes seem to corrupt the low 64k of memory during events
583 * like suspend/resume and unplugging an HDMI cable. Reserve all
584 * remaining free memory in that area and fill it with a distinct
585 * pattern.
586 */
587#ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION
588#define MAX_SCAN_AREAS 8
589static struct e820entry scan_areas[MAX_SCAN_AREAS];
590static int num_scan_areas;
591
592static void __init setup_bios_corruption_check(void)
593{
594 u64 addr = PAGE_SIZE; /* assume first page is reserved anyway */
595
596 while(addr < 0x10000 && num_scan_areas < MAX_SCAN_AREAS) {
597 u64 size;
598 addr = find_e820_area_size(addr, &size, PAGE_SIZE);
599
600 if (addr == 0)
601 break;
602
603 if ((addr + size) > 0x10000)
604 size = 0x10000 - addr;
605
606 if (size == 0)
607 break;
608
609 e820_update_range(addr, size, E820_RAM, E820_RESERVED);
610 scan_areas[num_scan_areas].addr = addr;
611 scan_areas[num_scan_areas].size = size;
612 num_scan_areas++;
613
614 /* Assume we've already mapped this early memory */
615 memset(__va(addr), 0, size);
616
617 addr += size;
618 }
619
620 printk(KERN_INFO "scanning %d areas for BIOS corruption\n",
621 num_scan_areas);
622 update_e820();
623}
624
625static int __read_mostly bios_corruption_check = 1;
626
627void check_for_bios_corruption(void)
628{
629 int i;
630 int corruption = 0;
631
632 if (!bios_corruption_check)
633 return;
634
635 for(i = 0; i < num_scan_areas; i++) {
636 unsigned long *addr = __va(scan_areas[i].addr);
637 unsigned long size = scan_areas[i].size;
638
639 for(; size; addr++, size -= sizeof(unsigned long)) {
640 if (!*addr)
641 continue;
642 printk(KERN_ERR "Corrupted low memory at %p (%lx phys) = %08lx\n",
643 addr, __pa(addr), *addr);
644 corruption = 1;
645 *addr = 0;
646 }
647 }
648
649 if (corruption)
650 dump_stack();
651}
652
653static int set_bios_corruption_check(char *arg)
654{
655 char *end;
656
657 bios_corruption_check = simple_strtol(arg, &end, 10);
658
659 return (*end == 0) ? 0 : -EINVAL;
660}
661early_param("bios_corruption_check", set_bios_corruption_check);
662#endif
663
664/*
582 * Determine if we were loaded by an EFI loader. If so, then we have also been 665 * Determine if we were loaded by an EFI loader. If so, then we have also been
583 * passed the efi memmap, systab, etc., so we should use these data structures 666 * passed the efi memmap, systab, etc., so we should use these data structures
584 * for initialization. Note, the efi init code path is determined by the 667 * for initialization. Note, the efi init code path is determined by the
@@ -750,6 +833,10 @@ void __init setup_arch(char **cmdline_p)
750 high_memory = (void *)__va(max_pfn * PAGE_SIZE - 1) + 1; 833 high_memory = (void *)__va(max_pfn * PAGE_SIZE - 1) + 1;
751#endif 834#endif
752 835
836#ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION
837 setup_bios_corruption_check();
838#endif
839
753 /* max_pfn_mapped is updated here */ 840 /* max_pfn_mapped is updated here */
754 max_low_pfn_mapped = init_memory_mapping(0, max_low_pfn<<PAGE_SHIFT); 841 max_low_pfn_mapped = init_memory_mapping(0, max_low_pfn<<PAGE_SHIFT);
755 max_pfn_mapped = max_low_pfn_mapped; 842 max_pfn_mapped = max_low_pfn_mapped;
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 455f3fe67b42..5140bdf03020 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -848,6 +848,8 @@ no_context:
848 * Oops. The kernel tried to access some bad page. We'll have to 848 * Oops. The kernel tried to access some bad page. We'll have to
849 * terminate things with extreme prejudice. 849 * terminate things with extreme prejudice.
850 */ 850 */
851 check_for_bios_corruption();
852
851#ifdef CONFIG_X86_32 853#ifdef CONFIG_X86_32
852 bust_spinlocks(1); 854 bust_spinlocks(1);
853#else 855#else
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 273a944d4040..bf6d3554e506 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -254,6 +254,7 @@ static char *pm_verb(int event)
254 254
255static void pm_dev_dbg(struct device *dev, pm_message_t state, char *info) 255static void pm_dev_dbg(struct device *dev, pm_message_t state, char *info)
256{ 256{
257 check_for_bios_corruption();
257 dev_dbg(dev, "%s%s%s\n", info, pm_verb(state.event), 258 dev_dbg(dev, "%s%s%s\n", info, pm_verb(state.event),
258 ((state.event & PM_EVENT_SLEEP) && device_may_wakeup(dev)) ? 259 ((state.event & PM_EVENT_SLEEP) && device_may_wakeup(dev)) ?
259 ", may wakeup" : ""); 260 ", may wakeup" : "");
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 2651f805ba6d..8017129e6b63 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -240,6 +240,18 @@ extern const char *print_tainted(void);
240extern void add_taint(unsigned); 240extern void add_taint(unsigned);
241extern int root_mountflags; 241extern int root_mountflags;
242 242
243#ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION
244/*
245 * This is obviously not a great place for this, but we want to be
246 * able to scatter it around anywhere in the kernel.
247 */
248void check_for_bios_corruption(void);
249#else
250static inline void check_for_bios_corruption(void)
251{
252}
253#endif
254
243/* Values used for system_state */ 255/* Values used for system_state */
244extern enum system_states { 256extern enum system_states {
245 SYSTEM_BOOTING, 257 SYSTEM_BOOTING,