aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/Kconfig50
-rw-r--r--arch/x86/kernel/setup.c196
-rw-r--r--arch/x86/mm/init_32.c2
-rw-r--r--arch/x86/mm/init_64.c2
4 files changed, 248 insertions, 2 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 44d4f2130d01..25e2f7a20d66 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1061,6 +1061,56 @@ config HIGHPTE
1061 low memory. Setting this option will put user-space page table 1061 low memory. Setting this option will put user-space page table
1062 entries in high memory. 1062 entries in high memory.
1063 1063
1064config X86_CHECK_BIOS_CORRUPTION
1065 bool "Check for low memory corruption"
1066 help
1067 Periodically check for memory corruption in low memory, which
1068 is suspected to be caused by BIOS. Even when enabled in the
1069 configuration, it is disabled at runtime. Enable it by
1070 setting "memory_corruption_check=1" on the kernel command
1071 line. By default it scans the low 64k of memory every 60
1072 seconds; see the memory_corruption_check_size and
1073 memory_corruption_check_period parameters in
1074 Documentation/kernel-parameters.txt to adjust this.
1075
1076 When enabled with the default parameters, this option has
1077 almost no overhead, as it reserves a relatively small amount
1078 of memory and scans it infrequently. It both detects corruption
1079 and prevents it from affecting the running system.
1080
1081 It is, however, intended as a diagnostic tool; if repeatable
1082 BIOS-originated corruption always affects the same memory,
1083 you can use memmap= to prevent the kernel from using that
1084 memory.
1085
1086config X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK
1087 bool "Set the default setting of memory_corruption_check"
1088 depends on X86_CHECK_BIOS_CORRUPTION
1089 default y
1090 help
1091 Set whether the default state of memory_corruption_check is
1092 on or off.
1093
1094config X86_RESERVE_LOW_64K
1095 bool "Reserve low 64K of RAM on AMI/Phoenix BIOSen"
1096 default y
1097 help
1098 Reserve the first 64K of physical RAM on BIOSes that are known
1099 to potentially corrupt that memory range. A numbers of BIOSes are
1100 known to utilize this area during suspend/resume, so it must not
1101 be used by the kernel.
1102
1103 Set this to N if you are absolutely sure that you trust the BIOS
1104 to get all its memory reservations and usages right.
1105
1106 If you have doubts about the BIOS (e.g. suspend/resume does not
1107 work or there's kernel crashes after certain hardware hotplug
1108 events) and it's not AMI or Phoenix, then you might want to enable
1109 X86_CHECK_BIOS_CORRUPTION=y to allow the kernel to check typical
1110 corruption patterns.
1111
1112 Say Y if unsure.
1113
1064config MATH_EMULATION 1114config MATH_EMULATION
1065 bool 1115 bool
1066 prompt "Math emulation" if X86_32 1116 prompt "Math emulation" if X86_32
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 46c98efbbf8d..21b8e0a59780 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -582,6 +582,190 @@ static struct x86_quirks default_x86_quirks __initdata;
582struct x86_quirks *x86_quirks __initdata = &default_x86_quirks; 582struct x86_quirks *x86_quirks __initdata = &default_x86_quirks;
583 583
584/* 584/*
585 * Some BIOSes seem to corrupt the low 64k of memory during events
586 * like suspend/resume and unplugging an HDMI cable. Reserve all
587 * remaining free memory in that area and fill it with a distinct
588 * pattern.
589 */
590#ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION
591#define MAX_SCAN_AREAS 8
592
593static int __read_mostly memory_corruption_check = -1;
594
595static unsigned __read_mostly corruption_check_size = 64*1024;
596static unsigned __read_mostly corruption_check_period = 60; /* seconds */
597
598static struct e820entry scan_areas[MAX_SCAN_AREAS];
599static int num_scan_areas;
600
601
602static int set_corruption_check(char *arg)
603{
604 char *end;
605
606 memory_corruption_check = simple_strtol(arg, &end, 10);
607
608 return (*end == 0) ? 0 : -EINVAL;
609}
610early_param("memory_corruption_check", set_corruption_check);
611
612static int set_corruption_check_period(char *arg)
613{
614 char *end;
615
616 corruption_check_period = simple_strtoul(arg, &end, 10);
617
618 return (*end == 0) ? 0 : -EINVAL;
619}
620early_param("memory_corruption_check_period", set_corruption_check_period);
621
622static int set_corruption_check_size(char *arg)
623{
624 char *end;
625 unsigned size;
626
627 size = memparse(arg, &end);
628
629 if (*end == '\0')
630 corruption_check_size = size;
631
632 return (size == corruption_check_size) ? 0 : -EINVAL;
633}
634early_param("memory_corruption_check_size", set_corruption_check_size);
635
636
637static void __init setup_bios_corruption_check(void)
638{
639 u64 addr = PAGE_SIZE; /* assume first page is reserved anyway */
640
641 if (memory_corruption_check == -1) {
642 memory_corruption_check =
643#ifdef CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK
644 1
645#else
646 0
647#endif
648 ;
649 }
650
651 if (corruption_check_size == 0)
652 memory_corruption_check = 0;
653
654 if (!memory_corruption_check)
655 return;
656
657 corruption_check_size = round_up(corruption_check_size, PAGE_SIZE);
658
659 while(addr < corruption_check_size && num_scan_areas < MAX_SCAN_AREAS) {
660 u64 size;
661 addr = find_e820_area_size(addr, &size, PAGE_SIZE);
662
663 if (addr == 0)
664 break;
665
666 if ((addr + size) > corruption_check_size)
667 size = corruption_check_size - addr;
668
669 if (size == 0)
670 break;
671
672 e820_update_range(addr, size, E820_RAM, E820_RESERVED);
673 scan_areas[num_scan_areas].addr = addr;
674 scan_areas[num_scan_areas].size = size;
675 num_scan_areas++;
676
677 /* Assume we've already mapped this early memory */
678 memset(__va(addr), 0, size);
679
680 addr += size;
681 }
682
683 printk(KERN_INFO "Scanning %d areas for low memory corruption\n",
684 num_scan_areas);
685 update_e820();
686}
687
688static struct timer_list periodic_check_timer;
689
690void check_for_bios_corruption(void)
691{
692 int i;
693 int corruption = 0;
694
695 if (!memory_corruption_check)
696 return;
697
698 for(i = 0; i < num_scan_areas; i++) {
699 unsigned long *addr = __va(scan_areas[i].addr);
700 unsigned long size = scan_areas[i].size;
701
702 for(; size; addr++, size -= sizeof(unsigned long)) {
703 if (!*addr)
704 continue;
705 printk(KERN_ERR "Corrupted low memory at %p (%lx phys) = %08lx\n",
706 addr, __pa(addr), *addr);
707 corruption = 1;
708 *addr = 0;
709 }
710 }
711
712 WARN(corruption, KERN_ERR "Memory corruption detected in low memory\n");
713}
714
715static void periodic_check_for_corruption(unsigned long data)
716{
717 check_for_bios_corruption();
718 mod_timer(&periodic_check_timer, round_jiffies(jiffies + corruption_check_period*HZ));
719}
720
721void start_periodic_check_for_corruption(void)
722{
723 if (!memory_corruption_check || corruption_check_period == 0)
724 return;
725
726 printk(KERN_INFO "Scanning for low memory corruption every %d seconds\n",
727 corruption_check_period);
728
729 init_timer(&periodic_check_timer);
730 periodic_check_timer.function = &periodic_check_for_corruption;
731 periodic_check_for_corruption(0);
732}
733#endif
734
735static int __init dmi_low_memory_corruption(const struct dmi_system_id *d)
736{
737 printk(KERN_NOTICE
738 "%s detected: BIOS may corrupt low RAM, working it around.\n",
739 d->ident);
740
741 e820_update_range(0, 0x10000, E820_RAM, E820_RESERVED);
742 sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
743
744 return 0;
745}
746
747/* List of systems that have known low memory corruption BIOS problems */
748static struct dmi_system_id __initdata bad_bios_dmi_table[] = {
749#ifdef CONFIG_X86_RESERVE_LOW_64K
750 {
751 .callback = dmi_low_memory_corruption,
752 .ident = "AMI BIOS",
753 .matches = {
754 DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
755 },
756 },
757 {
758 .callback = dmi_low_memory_corruption,
759 .ident = "Phoenix BIOS",
760 .matches = {
761 DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies, LTD"),
762 },
763 },
764#endif
765 {}
766};
767
768/*
585 * Determine if we were loaded by an EFI loader. If so, then we have also been 769 * Determine if we were loaded by an EFI loader. If so, then we have also been
586 * passed the efi memmap, systab, etc., so we should use these data structures 770 * passed the efi memmap, systab, etc., so we should use these data structures
587 * for initialization. Note, the efi init code path is determined by the 771 * for initialization. Note, the efi init code path is determined by the
@@ -715,6 +899,10 @@ void __init setup_arch(char **cmdline_p)
715 899
716 finish_e820_parsing(); 900 finish_e820_parsing();
717 901
902 dmi_scan_machine();
903
904 dmi_check_system(bad_bios_dmi_table);
905
718#ifdef CONFIG_X86_32 906#ifdef CONFIG_X86_32
719 probe_roms(); 907 probe_roms();
720#endif 908#endif
@@ -771,6 +959,10 @@ void __init setup_arch(char **cmdline_p)
771 high_memory = (void *)__va(max_pfn * PAGE_SIZE - 1) + 1; 959 high_memory = (void *)__va(max_pfn * PAGE_SIZE - 1) + 1;
772#endif 960#endif
773 961
962#ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION
963 setup_bios_corruption_check();
964#endif
965
774 /* max_pfn_mapped is updated here */ 966 /* max_pfn_mapped is updated here */
775 max_low_pfn_mapped = init_memory_mapping(0, max_low_pfn<<PAGE_SHIFT); 967 max_low_pfn_mapped = init_memory_mapping(0, max_low_pfn<<PAGE_SHIFT);
776 max_pfn_mapped = max_low_pfn_mapped; 968 max_pfn_mapped = max_low_pfn_mapped;
@@ -799,8 +991,6 @@ void __init setup_arch(char **cmdline_p)
799 vsmp_init(); 991 vsmp_init();
800#endif 992#endif
801 993
802 dmi_scan_machine();
803
804 io_delay_init(); 994 io_delay_init();
805 995
806 /* 996 /*
@@ -903,3 +1093,5 @@ void __init setup_arch(char **cmdline_p)
903#endif 1093#endif
904#endif 1094#endif
905} 1095}
1096
1097
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c
index c3789bb19308..7e05462ffb11 100644
--- a/arch/x86/mm/init_32.c
+++ b/arch/x86/mm/init_32.c
@@ -969,6 +969,8 @@ void __init mem_init(void)
969 int codesize, reservedpages, datasize, initsize; 969 int codesize, reservedpages, datasize, initsize;
970 int tmp; 970 int tmp;
971 971
972 start_periodic_check_for_corruption();
973
972#ifdef CONFIG_FLATMEM 974#ifdef CONFIG_FLATMEM
973 BUG_ON(!mem_map); 975 BUG_ON(!mem_map);
974#endif 976#endif
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index 83e13f2d53d2..d84d3e91d348 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -881,6 +881,8 @@ void __init mem_init(void)
881{ 881{
882 long codesize, reservedpages, datasize, initsize; 882 long codesize, reservedpages, datasize, initsize;
883 883
884 start_periodic_check_for_corruption();
885
884 pci_iommu_alloc(); 886 pci_iommu_alloc();
885 887
886 /* clear_bss() already clear the empty_zero_page */ 888 /* clear_bss() already clear the empty_zero_page */