Merge tag 'v4.20' into for-linus
[linux-2.6-microblaze.git] / arch / x86 / kernel / check.c
1 // SPDX-License-Identifier: GPL-2.0
2
3 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
4
5 #include <linux/init.h>
6 #include <linux/sched.h>
7 #include <linux/kthread.h>
8 #include <linux/workqueue.h>
9 #include <linux/memblock.h>
10
11 #include <asm/proto.h>
12
13 /*
14  * Some BIOSes seem to corrupt the low 64k of memory during events
15  * like suspend/resume and unplugging an HDMI cable.  Reserve all
16  * remaining free memory in that area and fill it with a distinct
17  * pattern.
18  */
19 #define MAX_SCAN_AREAS  8
20
21 static int __read_mostly memory_corruption_check = -1;
22
23 static unsigned __read_mostly corruption_check_size = 64*1024;
24 static unsigned __read_mostly corruption_check_period = 60; /* seconds */
25
26 static struct scan_area {
27         u64 addr;
28         u64 size;
29 } scan_areas[MAX_SCAN_AREAS];
30 static int num_scan_areas;
31
32 static __init int set_corruption_check(char *arg)
33 {
34         ssize_t ret;
35         unsigned long val;
36
37         if (!arg) {
38                 pr_err("memory_corruption_check config string not provided\n");
39                 return -EINVAL;
40         }
41
42         ret = kstrtoul(arg, 10, &val);
43         if (ret)
44                 return ret;
45
46         memory_corruption_check = val;
47
48         return 0;
49 }
50 early_param("memory_corruption_check", set_corruption_check);
51
52 static __init int set_corruption_check_period(char *arg)
53 {
54         ssize_t ret;
55         unsigned long val;
56
57         if (!arg) {
58                 pr_err("memory_corruption_check_period config string not provided\n");
59                 return -EINVAL;
60         }
61
62         ret = kstrtoul(arg, 10, &val);
63         if (ret)
64                 return ret;
65
66         corruption_check_period = val;
67         return 0;
68 }
69 early_param("memory_corruption_check_period", set_corruption_check_period);
70
71 static __init int set_corruption_check_size(char *arg)
72 {
73         char *end;
74         unsigned size;
75
76         if (!arg) {
77                 pr_err("memory_corruption_check_size config string not provided\n");
78                 return -EINVAL;
79         }
80
81         size = memparse(arg, &end);
82
83         if (*end == '\0')
84                 corruption_check_size = size;
85
86         return (size == corruption_check_size) ? 0 : -EINVAL;
87 }
88 early_param("memory_corruption_check_size", set_corruption_check_size);
89
90
91 void __init setup_bios_corruption_check(void)
92 {
93         phys_addr_t start, end;
94         u64 i;
95
96         if (memory_corruption_check == -1) {
97                 memory_corruption_check =
98 #ifdef CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK
99                         1
100 #else
101                         0
102 #endif
103                         ;
104         }
105
106         if (corruption_check_size == 0)
107                 memory_corruption_check = 0;
108
109         if (!memory_corruption_check)
110                 return;
111
112         corruption_check_size = round_up(corruption_check_size, PAGE_SIZE);
113
114         for_each_free_mem_range(i, NUMA_NO_NODE, MEMBLOCK_NONE, &start, &end,
115                                 NULL) {
116                 start = clamp_t(phys_addr_t, round_up(start, PAGE_SIZE),
117                                 PAGE_SIZE, corruption_check_size);
118                 end = clamp_t(phys_addr_t, round_down(end, PAGE_SIZE),
119                               PAGE_SIZE, corruption_check_size);
120                 if (start >= end)
121                         continue;
122
123                 memblock_reserve(start, end - start);
124                 scan_areas[num_scan_areas].addr = start;
125                 scan_areas[num_scan_areas].size = end - start;
126
127                 /* Assume we've already mapped this early memory */
128                 memset(__va(start), 0, end - start);
129
130                 if (++num_scan_areas >= MAX_SCAN_AREAS)
131                         break;
132         }
133
134         if (num_scan_areas)
135                 pr_info("Scanning %d areas for low memory corruption\n", num_scan_areas);
136 }
137
138
139 void check_for_bios_corruption(void)
140 {
141         int i;
142         int corruption = 0;
143
144         if (!memory_corruption_check)
145                 return;
146
147         for (i = 0; i < num_scan_areas; i++) {
148                 unsigned long *addr = __va(scan_areas[i].addr);
149                 unsigned long size = scan_areas[i].size;
150
151                 for (; size; addr++, size -= sizeof(unsigned long)) {
152                         if (!*addr)
153                                 continue;
154                         pr_err("Corrupted low memory at %p (%lx phys) = %08lx\n", addr, __pa(addr), *addr);
155                         corruption = 1;
156                         *addr = 0;
157                 }
158         }
159
160         WARN_ONCE(corruption, KERN_ERR "Memory corruption detected in low memory\n");
161 }
162
163 static void check_corruption(struct work_struct *dummy);
164 static DECLARE_DELAYED_WORK(bios_check_work, check_corruption);
165
166 static void check_corruption(struct work_struct *dummy)
167 {
168         check_for_bios_corruption();
169         schedule_delayed_work(&bios_check_work,
170                 round_jiffies_relative(corruption_check_period*HZ));
171 }
172
173 static int start_periodic_check_for_corruption(void)
174 {
175         if (!num_scan_areas || !memory_corruption_check || corruption_check_period == 0)
176                 return 0;
177
178         pr_info("Scanning for low memory corruption every %d seconds\n", corruption_check_period);
179
180         /* First time we run the checks right away */
181         schedule_delayed_work(&bios_check_work, 0);
182
183         return 0;
184 }
185 device_initcall(start_periodic_check_for_corruption);
186