aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorArjan van de Ven <arjan@linux.intel.com>2008-10-05 14:33:42 -0400
committerIngo Molnar <mingo@elte.hu>2008-10-27 13:09:44 -0400
commit6784f7d0a5016a397d38be1134e63fc784c1ca8e (patch)
tree20fb39506d0ab28761e474d2fb2afc2970c9af9a /arch
parent04d2aac33eb54fd3084140f2db130530d71e97c6 (diff)
x86: corruption check: move the corruption checks into their own file
Impact: cleanup The corruption check code is rather sizable and it's likely to grow over time when we add checks for more types of corruptions (there's a few candidates in kerneloops.org that I want to add checks for)... so lets move it to its own file Signed-off-by: Arjan van de Ven <arjan@linux.intel.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/include/asm/setup.h4
-rw-r--r--arch/x86/kernel/Makefile1
-rw-r--r--arch/x86/kernel/check.c158
-rw-r--r--arch/x86/kernel/setup.c152
4 files changed, 163 insertions, 152 deletions
diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h
index f12d37237465..1ed8b2e80727 100644
--- a/arch/x86/include/asm/setup.h
+++ b/arch/x86/include/asm/setup.h
@@ -8,6 +8,10 @@
8/* Interrupt control for vSMPowered x86_64 systems */ 8/* Interrupt control for vSMPowered x86_64 systems */
9void vsmp_init(void); 9void vsmp_init(void);
10 10
11
12void setup_bios_corruption_check(void);
13
14
11#ifdef CONFIG_X86_VISWS 15#ifdef CONFIG_X86_VISWS
12extern void visws_early_detect(void); 16extern void visws_early_detect(void);
13extern int is_visws_box(void); 17extern int is_visws_box(void);
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index d7e5a58ee22f..31fbcaf3df70 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -35,6 +35,7 @@ obj-y += bootflag.o e820.o
35obj-y += pci-dma.o quirks.o i8237.o topology.o kdebugfs.o 35obj-y += pci-dma.o quirks.o i8237.o topology.o kdebugfs.o
36obj-y += alternative.o i8253.o pci-nommu.o 36obj-y += alternative.o i8253.o pci-nommu.o
37obj-y += tsc.o io_delay.o rtc.o 37obj-y += tsc.o io_delay.o rtc.o
38obj-y += check.o
38 39
39obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o 40obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o
40obj-y += process.o 41obj-y += process.o
diff --git a/arch/x86/kernel/check.c b/arch/x86/kernel/check.c
new file mode 100644
index 000000000000..5056703e1b05
--- /dev/null
+++ b/arch/x86/kernel/check.c
@@ -0,0 +1,158 @@
1#include <linux/module.h>
2#include <linux/sched.h>
3
4#include <asm/e820.h>
5#include <asm/proto.h>
6
7/*
8 * Some BIOSes seem to corrupt the low 64k of memory during events
9 * like suspend/resume and unplugging an HDMI cable. Reserve all
10 * remaining free memory in that area and fill it with a distinct
11 * pattern.
12 */
13#ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION
14#define MAX_SCAN_AREAS 8
15
16static int __read_mostly memory_corruption_check = -1;
17
18static unsigned __read_mostly corruption_check_size = 64*1024;
19static unsigned __read_mostly corruption_check_period = 60; /* seconds */
20
21static struct e820entry scan_areas[MAX_SCAN_AREAS];
22static int num_scan_areas;
23
24
25static int set_corruption_check(char *arg)
26{
27 char *end;
28
29 memory_corruption_check = simple_strtol(arg, &end, 10);
30
31 return (*end == 0) ? 0 : -EINVAL;
32}
33early_param("memory_corruption_check", set_corruption_check);
34
35static int set_corruption_check_period(char *arg)
36{
37 char *end;
38
39 corruption_check_period = simple_strtoul(arg, &end, 10);
40
41 return (*end == 0) ? 0 : -EINVAL;
42}
43early_param("memory_corruption_check_period", set_corruption_check_period);
44
45static int set_corruption_check_size(char *arg)
46{
47 char *end;
48 unsigned size;
49
50 size = memparse(arg, &end);
51
52 if (*end == '\0')
53 corruption_check_size = size;
54
55 return (size == corruption_check_size) ? 0 : -EINVAL;
56}
57early_param("memory_corruption_check_size", set_corruption_check_size);
58
59
60void __init setup_bios_corruption_check(void)
61{
62 u64 addr = PAGE_SIZE; /* assume first page is reserved anyway */
63
64 if (memory_corruption_check == -1) {
65 memory_corruption_check =
66#ifdef CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK
67 1
68#else
69 0
70#endif
71 ;
72 }
73
74 if (corruption_check_size == 0)
75 memory_corruption_check = 0;
76
77 if (!memory_corruption_check)
78 return;
79
80 corruption_check_size = round_up(corruption_check_size, PAGE_SIZE);
81
82 while (addr < corruption_check_size && num_scan_areas < MAX_SCAN_AREAS) {
83 u64 size;
84 addr = find_e820_area_size(addr, &size, PAGE_SIZE);
85
86 if (addr == 0)
87 break;
88
89 if ((addr + size) > corruption_check_size)
90 size = corruption_check_size - addr;
91
92 if (size == 0)
93 break;
94
95 e820_update_range(addr, size, E820_RAM, E820_RESERVED);
96 scan_areas[num_scan_areas].addr = addr;
97 scan_areas[num_scan_areas].size = size;
98 num_scan_areas++;
99
100 /* Assume we've already mapped this early memory */
101 memset(__va(addr), 0, size);
102
103 addr += size;
104 }
105
106 printk(KERN_INFO "Scanning %d areas for low memory corruption\n",
107 num_scan_areas);
108 update_e820();
109}
110
111static struct timer_list periodic_check_timer;
112
113void check_for_bios_corruption(void)
114{
115 int i;
116 int corruption = 0;
117
118 if (!memory_corruption_check)
119 return;
120
121 for (i = 0; i < num_scan_areas; i++) {
122 unsigned long *addr = __va(scan_areas[i].addr);
123 unsigned long size = scan_areas[i].size;
124
125 for (; size; addr++, size -= sizeof(unsigned long)) {
126 if (!*addr)
127 continue;
128 printk(KERN_ERR "Corrupted low memory at %p (%lx phys) = %08lx\n",
129 addr, __pa(addr), *addr);
130 corruption = 1;
131 *addr = 0;
132 }
133 }
134
135 WARN(corruption, KERN_ERR "Memory corruption detected in low memory\n");
136}
137
138static void periodic_check_for_corruption(unsigned long data)
139{
140 check_for_bios_corruption();
141 mod_timer(&periodic_check_timer,
142 round_jiffies(jiffies + corruption_check_period*HZ));
143}
144
145void start_periodic_check_for_corruption(void)
146{
147 if (!memory_corruption_check || corruption_check_period == 0)
148 return;
149
150 printk(KERN_INFO "Scanning for low memory corruption every %d seconds\n",
151 corruption_check_period);
152
153 init_timer(&periodic_check_timer);
154 periodic_check_timer.function = &periodic_check_for_corruption;
155 periodic_check_for_corruption(0);
156}
157#endif
158
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 4f38e0305b07..af690aa593a9 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -587,158 +587,6 @@ static struct x86_quirks default_x86_quirks __initdata;
587 587
588struct x86_quirks *x86_quirks __initdata = &default_x86_quirks; 588struct x86_quirks *x86_quirks __initdata = &default_x86_quirks;
589 589
590/*
591 * Some BIOSes seem to corrupt the low 64k of memory during events
592 * like suspend/resume and unplugging an HDMI cable. Reserve all
593 * remaining free memory in that area and fill it with a distinct
594 * pattern.
595 */
596#ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION
597#define MAX_SCAN_AREAS 8
598
599static int __read_mostly memory_corruption_check = -1;
600
601static unsigned __read_mostly corruption_check_size = 64*1024;
602static unsigned __read_mostly corruption_check_period = 60; /* seconds */
603
604static struct e820entry scan_areas[MAX_SCAN_AREAS];
605static int num_scan_areas;
606
607
608static int set_corruption_check(char *arg)
609{
610 char *end;
611
612 memory_corruption_check = simple_strtol(arg, &end, 10);
613
614 return (*end == 0) ? 0 : -EINVAL;
615}
616early_param("memory_corruption_check", set_corruption_check);
617
618static int set_corruption_check_period(char *arg)
619{
620 char *end;
621
622 corruption_check_period = simple_strtoul(arg, &end, 10);
623
624 return (*end == 0) ? 0 : -EINVAL;
625}
626early_param("memory_corruption_check_period", set_corruption_check_period);
627
628static int set_corruption_check_size(char *arg)
629{
630 char *end;
631 unsigned size;
632
633 size = memparse(arg, &end);
634
635 if (*end == '\0')
636 corruption_check_size = size;
637
638 return (size == corruption_check_size) ? 0 : -EINVAL;
639}
640early_param("memory_corruption_check_size", set_corruption_check_size);
641
642
643static void __init setup_bios_corruption_check(void)
644{
645 u64 addr = PAGE_SIZE; /* assume first page is reserved anyway */
646
647 if (memory_corruption_check == -1) {
648 memory_corruption_check =
649#ifdef CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK
650 1
651#else
652 0
653#endif
654 ;
655 }
656
657 if (corruption_check_size == 0)
658 memory_corruption_check = 0;
659
660 if (!memory_corruption_check)
661 return;
662
663 corruption_check_size = round_up(corruption_check_size, PAGE_SIZE);
664
665 while (addr < corruption_check_size && num_scan_areas < MAX_SCAN_AREAS) {
666 u64 size;
667 addr = find_e820_area_size(addr, &size, PAGE_SIZE);
668
669 if (addr == 0)
670 break;
671
672 if ((addr + size) > corruption_check_size)
673 size = corruption_check_size - addr;
674
675 if (size == 0)
676 break;
677
678 e820_update_range(addr, size, E820_RAM, E820_RESERVED);
679 scan_areas[num_scan_areas].addr = addr;
680 scan_areas[num_scan_areas].size = size;
681 num_scan_areas++;
682
683 /* Assume we've already mapped this early memory */
684 memset(__va(addr), 0, size);
685
686 addr += size;
687 }
688
689 printk(KERN_INFO "Scanning %d areas for low memory corruption\n",
690 num_scan_areas);
691 update_e820();
692}
693
694static struct timer_list periodic_check_timer;
695
696void check_for_bios_corruption(void)
697{
698 int i;
699 int corruption = 0;
700
701 if (!memory_corruption_check)
702 return;
703
704 for (i = 0; i < num_scan_areas; i++) {
705 unsigned long *addr = __va(scan_areas[i].addr);
706 unsigned long size = scan_areas[i].size;
707
708 for (; size; addr++, size -= sizeof(unsigned long)) {
709 if (!*addr)
710 continue;
711 printk(KERN_ERR "Corrupted low memory at %p (%lx phys) = %08lx\n",
712 addr, __pa(addr), *addr);
713 corruption = 1;
714 *addr = 0;
715 }
716 }
717
718 WARN(corruption, KERN_ERR "Memory corruption detected in low memory\n");
719}
720
721static void periodic_check_for_corruption(unsigned long data)
722{
723 check_for_bios_corruption();
724 mod_timer(&periodic_check_timer,
725 round_jiffies(jiffies + corruption_check_period*HZ));
726}
727
728void start_periodic_check_for_corruption(void)
729{
730 if (!memory_corruption_check || corruption_check_period == 0)
731 return;
732
733 printk(KERN_INFO "Scanning for low memory corruption every %d seconds\n",
734 corruption_check_period);
735
736 init_timer(&periodic_check_timer);
737 periodic_check_timer.function = &periodic_check_for_corruption;
738 periodic_check_for_corruption(0);
739}
740#endif
741
742static int __init dmi_low_memory_corruption(const struct dmi_system_id *d) 590static int __init dmi_low_memory_corruption(const struct dmi_system_id *d)
743{ 591{
744 printk(KERN_NOTICE 592 printk(KERN_NOTICE