diff options
-rw-r--r-- | Documentation/kernel-parameters.txt | 28 | ||||
-rw-r--r-- | arch/x86/Kconfig | 26 | ||||
-rw-r--r-- | arch/x86/kernel/setup.c | 80 |
3 files changed, 106 insertions, 28 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index df48af505d15..6a2629d00598 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
@@ -360,11 +360,6 @@ 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 | |||
368 | boot_delay= Milliseconds to delay each printk during boot. | 363 | boot_delay= Milliseconds to delay each printk during boot. |
369 | Values larger than 10 seconds (10000) are changed to | 364 | Values larger than 10 seconds (10000) are changed to |
370 | no delay (0). | 365 | no delay (0). |
@@ -1233,6 +1228,29 @@ and is between 256 and 4096 characters. It is defined in the file | |||
1233 | or | 1228 | or |
1234 | memmap=0x10000$0x18690000 | 1229 | memmap=0x10000$0x18690000 |
1235 | 1230 | ||
1231 | memory_corruption_check=0/1 [X86] | ||
1232 | Some BIOSes seem to corrupt the first 64k of | ||
1233 | memory when doing things like suspend/resume. | ||
1234 | Setting this option will scan the memory | ||
1235 | looking for corruption. Enabling this will | ||
1236 | both detect corruption and prevent the kernel | ||
1237 | from using the memory being corrupted. | ||
1238 | However, its intended as a diagnostic tool; if | ||
1239 | repeatable BIOS-originated corruption always | ||
1240 | affects the same memory, you can use memmap= | ||
1241 | to prevent the kernel from using that memory. | ||
1242 | |||
1243 | memory_corruption_check_size=size [X86] | ||
1244 | By default it checks for corruption in the low | ||
1245 | 64k, making this memory unavailable for normal | ||
1246 | use. Use this parameter to scan for | ||
1247 | corruption in more or less memory. | ||
1248 | |||
1249 | memory_corruption_check_period=seconds [X86] | ||
1250 | By default it checks for corruption every 60 | ||
1251 | seconds. Use this parameter to check at some | ||
1252 | other rate. 0 disables periodic checking. | ||
1253 | |||
1236 | memtest= [KNL,X86] Enable memtest | 1254 | memtest= [KNL,X86] Enable memtest |
1237 | Format: <integer> | 1255 | Format: <integer> |
1238 | range: 0,4 : pattern number | 1256 | range: 0,4 : pattern number |
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 1bb52e2ca02e..cbee4199689c 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -201,9 +201,6 @@ 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 | ||
204 | config X86_CHECK_BIOS_CORRUPTION | ||
205 | def_bool y | ||
206 | |||
207 | config KTIME_SCALAR | 204 | config KTIME_SCALAR |
208 | def_bool X86_32 | 205 | def_bool X86_32 |
209 | source "init/Kconfig" | 206 | source "init/Kconfig" |
@@ -1062,6 +1059,29 @@ config HIGHPTE | |||
1062 | low memory. Setting this option will put user-space page table | 1059 | low memory. Setting this option will put user-space page table |
1063 | entries in high memory. | 1060 | entries in high memory. |
1064 | 1061 | ||
1062 | config X86_CHECK_BIOS_CORRUPTION | ||
1063 | bool "Check for low memory corruption" | ||
1064 | default y | ||
1065 | help | ||
1066 | Periodically check for memory corruption in low memory, which | ||
1067 | is suspected to be caused by BIOS. Even when enabled in the | ||
1068 | configuration, it is disabled at runtime. Enable it by | ||
1069 | setting "memory_corruption_check=1" on the kernel command | ||
1070 | line. By default it scans the low 64k of memory every 60 | ||
1071 | seconds; see the memory_corruption_check_size and | ||
1072 | memory_corruption_check_period parameters in | ||
1073 | Documentation/kernel-parameters.txt to adjust this. | ||
1074 | |||
1075 | When enabled with the default parameters, this option has | ||
1076 | almost no overhead, as it reserves a relatively small amount | ||
1077 | of memory and scans it infrequently. It both detects corruption | ||
1078 | and prevents it from affecting the running system. | ||
1079 | |||
1080 | It is, however, intended as a diagnostic tool; if repeatable | ||
1081 | BIOS-originated corruption always affects the same memory, | ||
1082 | you can use memmap= to prevent the kernel from using that | ||
1083 | memory. | ||
1084 | |||
1065 | config MATH_EMULATION | 1085 | config MATH_EMULATION |
1066 | bool | 1086 | bool |
1067 | prompt "Math emulation" if X86_32 | 1087 | prompt "Math emulation" if X86_32 |
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index c239b3780973..27ae91288855 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c | |||
@@ -586,22 +586,71 @@ struct x86_quirks *x86_quirks __initdata = &default_x86_quirks; | |||
586 | */ | 586 | */ |
587 | #ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION | 587 | #ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION |
588 | #define MAX_SCAN_AREAS 8 | 588 | #define MAX_SCAN_AREAS 8 |
589 | |||
590 | static int __read_mostly memory_corruption_check = 0; | ||
591 | static unsigned __read_mostly corruption_check_size = 64*1024; | ||
592 | static unsigned __read_mostly corruption_check_period = 60; /* seconds */ | ||
593 | |||
589 | static struct e820entry scan_areas[MAX_SCAN_AREAS]; | 594 | static struct e820entry scan_areas[MAX_SCAN_AREAS]; |
590 | static int num_scan_areas; | 595 | static int num_scan_areas; |
591 | 596 | ||
597 | |||
598 | static int set_corruption_check(char *arg) | ||
599 | { | ||
600 | char *end; | ||
601 | |||
602 | memory_corruption_check = simple_strtol(arg, &end, 10); | ||
603 | |||
604 | return (*end == 0) ? 0 : -EINVAL; | ||
605 | } | ||
606 | early_param("memory_corruption_check", set_corruption_check); | ||
607 | |||
608 | static int set_corruption_check_period(char *arg) | ||
609 | { | ||
610 | char *end; | ||
611 | |||
612 | corruption_check_period = simple_strtoul(arg, &end, 10); | ||
613 | |||
614 | return (*end == 0) ? 0 : -EINVAL; | ||
615 | } | ||
616 | early_param("memory_corruption_check_period", set_corruption_check_period); | ||
617 | |||
618 | static int set_corruption_check_size(char *arg) | ||
619 | { | ||
620 | char *end; | ||
621 | unsigned size; | ||
622 | |||
623 | size = memparse(arg, &end); | ||
624 | |||
625 | if (*end == '\0') | ||
626 | corruption_check_size = size; | ||
627 | |||
628 | return (size == corruption_check_size) ? 0 : -EINVAL; | ||
629 | } | ||
630 | early_param("memory_corruption_check_size", set_corruption_check_size); | ||
631 | |||
632 | |||
592 | static void __init setup_bios_corruption_check(void) | 633 | static void __init setup_bios_corruption_check(void) |
593 | { | 634 | { |
594 | u64 addr = PAGE_SIZE; /* assume first page is reserved anyway */ | 635 | u64 addr = PAGE_SIZE; /* assume first page is reserved anyway */ |
595 | 636 | ||
596 | while(addr < 0x10000 && num_scan_areas < MAX_SCAN_AREAS) { | 637 | if (corruption_check_size == 0) |
638 | memory_corruption_check = 0; | ||
639 | |||
640 | if (!memory_corruption_check) | ||
641 | return; | ||
642 | |||
643 | corruption_check_size = round_up(corruption_check_size, PAGE_SIZE); | ||
644 | |||
645 | while(addr < corruption_check_size && num_scan_areas < MAX_SCAN_AREAS) { | ||
597 | u64 size; | 646 | u64 size; |
598 | addr = find_e820_area_size(addr, &size, PAGE_SIZE); | 647 | addr = find_e820_area_size(addr, &size, PAGE_SIZE); |
599 | 648 | ||
600 | if (addr == 0) | 649 | if (addr == 0) |
601 | break; | 650 | break; |
602 | 651 | ||
603 | if ((addr + size) > 0x10000) | 652 | if ((addr + size) > corruption_check_size) |
604 | size = 0x10000 - addr; | 653 | size = corruption_check_size - addr; |
605 | 654 | ||
606 | if (size == 0) | 655 | if (size == 0) |
607 | break; | 656 | break; |
@@ -617,12 +666,11 @@ static void __init setup_bios_corruption_check(void) | |||
617 | addr += size; | 666 | addr += size; |
618 | } | 667 | } |
619 | 668 | ||
620 | printk(KERN_INFO "scanning %d areas for BIOS corruption\n", | 669 | printk(KERN_INFO "Scanning %d areas for low memory corruption\n", |
621 | num_scan_areas); | 670 | num_scan_areas); |
622 | update_e820(); | 671 | update_e820(); |
623 | } | 672 | } |
624 | 673 | ||
625 | static int __read_mostly bios_corruption_check = 1; | ||
626 | static struct timer_list periodic_check_timer; | 674 | static struct timer_list periodic_check_timer; |
627 | 675 | ||
628 | void check_for_bios_corruption(void) | 676 | void check_for_bios_corruption(void) |
@@ -630,7 +678,7 @@ void check_for_bios_corruption(void) | |||
630 | int i; | 678 | int i; |
631 | int corruption = 0; | 679 | int corruption = 0; |
632 | 680 | ||
633 | if (!bios_corruption_check) | 681 | if (!memory_corruption_check) |
634 | return; | 682 | return; |
635 | 683 | ||
636 | for(i = 0; i < num_scan_areas; i++) { | 684 | for(i = 0; i < num_scan_areas; i++) { |
@@ -647,35 +695,27 @@ void check_for_bios_corruption(void) | |||
647 | } | 695 | } |
648 | } | 696 | } |
649 | 697 | ||
650 | if (corruption) | 698 | WARN(corruption, KERN_ERR "Memory corruption detected in low memory\n"); |
651 | dump_stack(); | ||
652 | } | 699 | } |
653 | 700 | ||
654 | static void periodic_check_for_corruption(unsigned long data) | 701 | static void periodic_check_for_corruption(unsigned long data) |
655 | { | 702 | { |
656 | check_for_bios_corruption(); | 703 | check_for_bios_corruption(); |
657 | mod_timer(&periodic_check_timer, jiffies + 60*HZ); | 704 | mod_timer(&periodic_check_timer, jiffies + corruption_check_period*HZ); |
658 | } | 705 | } |
659 | 706 | ||
660 | void start_periodic_check_for_corruption(void) | 707 | void start_periodic_check_for_corruption(void) |
661 | { | 708 | { |
662 | if (!bios_corruption_check) | 709 | if (!memory_corruption_check || corruption_check_period == 0) |
663 | return; | 710 | return; |
664 | 711 | ||
712 | printk(KERN_INFO "Scanning for low memory corruption every %d seconds\n", | ||
713 | corruption_check_period); | ||
714 | |||
665 | init_timer(&periodic_check_timer); | 715 | init_timer(&periodic_check_timer); |
666 | periodic_check_timer.function = &periodic_check_for_corruption; | 716 | periodic_check_timer.function = &periodic_check_for_corruption; |
667 | periodic_check_for_corruption(0); | 717 | periodic_check_for_corruption(0); |
668 | } | 718 | } |
669 | |||
670 | static int set_bios_corruption_check(char *arg) | ||
671 | { | ||
672 | char *end; | ||
673 | |||
674 | bios_corruption_check = simple_strtol(arg, &end, 10); | ||
675 | |||
676 | return (*end == 0) ? 0 : -EINVAL; | ||
677 | } | ||
678 | early_param("bios_corruption_check", set_bios_corruption_check); | ||
679 | #endif | 719 | #endif |
680 | 720 | ||
681 | /* | 721 | /* |