1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/init.h>
3 #include <linux/sched.h>
4 #include <linux/kthread.h>
5 #include <linux/workqueue.h>
6 #include <linux/memblock.h>
11 * Some BIOSes seem to corrupt the low 64k of memory during events
12 * like suspend/resume and unplugging an HDMI cable. Reserve all
13 * remaining free memory in that area and fill it with a distinct
16 #define MAX_SCAN_AREAS 8
18 static int __read_mostly memory_corruption_check
= -1;
20 static unsigned __read_mostly corruption_check_size
= 64*1024;
21 static unsigned __read_mostly corruption_check_period
= 60; /* seconds */
23 static struct scan_area
{
26 } scan_areas
[MAX_SCAN_AREAS
];
27 static int num_scan_areas
;
29 static __init
int set_corruption_check(char *arg
)
34 ret
= kstrtoul(arg
, 10, &val
);
38 memory_corruption_check
= val
;
41 early_param("memory_corruption_check", set_corruption_check
);
43 static __init
int set_corruption_check_period(char *arg
)
48 ret
= kstrtoul(arg
, 10, &val
);
52 corruption_check_period
= val
;
55 early_param("memory_corruption_check_period", set_corruption_check_period
);
57 static __init
int set_corruption_check_size(char *arg
)
62 size
= memparse(arg
, &end
);
65 corruption_check_size
= size
;
67 return (size
== corruption_check_size
) ? 0 : -EINVAL
;
69 early_param("memory_corruption_check_size", set_corruption_check_size
);
72 void __init
setup_bios_corruption_check(void)
74 phys_addr_t start
, end
;
77 if (memory_corruption_check
== -1) {
78 memory_corruption_check
=
79 #ifdef CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK
87 if (corruption_check_size
== 0)
88 memory_corruption_check
= 0;
90 if (!memory_corruption_check
)
93 corruption_check_size
= round_up(corruption_check_size
, PAGE_SIZE
);
95 for_each_free_mem_range(i
, NUMA_NO_NODE
, MEMBLOCK_NONE
, &start
, &end
,
97 start
= clamp_t(phys_addr_t
, round_up(start
, PAGE_SIZE
),
98 PAGE_SIZE
, corruption_check_size
);
99 end
= clamp_t(phys_addr_t
, round_down(end
, PAGE_SIZE
),
100 PAGE_SIZE
, corruption_check_size
);
104 memblock_reserve(start
, end
- start
);
105 scan_areas
[num_scan_areas
].addr
= start
;
106 scan_areas
[num_scan_areas
].size
= end
- start
;
108 /* Assume we've already mapped this early memory */
109 memset(__va(start
), 0, end
- start
);
111 if (++num_scan_areas
>= MAX_SCAN_AREAS
)
116 printk(KERN_INFO
"Scanning %d areas for low memory corruption\n", num_scan_areas
);
120 void check_for_bios_corruption(void)
125 if (!memory_corruption_check
)
128 for (i
= 0; i
< num_scan_areas
; i
++) {
129 unsigned long *addr
= __va(scan_areas
[i
].addr
);
130 unsigned long size
= scan_areas
[i
].size
;
132 for (; size
; addr
++, size
-= sizeof(unsigned long)) {
135 printk(KERN_ERR
"Corrupted low memory at %p (%lx phys) = %08lx\n",
136 addr
, __pa(addr
), *addr
);
142 WARN_ONCE(corruption
, KERN_ERR
"Memory corruption detected in low memory\n");
145 static void check_corruption(struct work_struct
*dummy
);
146 static DECLARE_DELAYED_WORK(bios_check_work
, check_corruption
);
148 static void check_corruption(struct work_struct
*dummy
)
150 check_for_bios_corruption();
151 schedule_delayed_work(&bios_check_work
,
152 round_jiffies_relative(corruption_check_period
*HZ
));
155 static int start_periodic_check_for_corruption(void)
157 if (!num_scan_areas
|| !memory_corruption_check
|| corruption_check_period
== 0)
160 printk(KERN_INFO
"Scanning for low memory corruption every %d seconds\n",
161 corruption_check_period
);
163 /* First time we run the checks right away */
164 schedule_delayed_work(&bios_check_work
, 0);
167 device_initcall(start_periodic_check_for_corruption
);