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> 7 8 #include <asm/proto.h> 9 10 /* 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 14 * pattern. 15 */ 16 #define MAX_SCAN_AREAS 8 17 18 static int __read_mostly memory_corruption_check = -1; 19 20 static unsigned __read_mostly corruption_check_size = 64*1024; 21 static unsigned __read_mostly corruption_check_period = 60; /* seconds */ 22 23 static struct scan_area { 24 u64 addr; 25 u64 size; 26 } scan_areas[MAX_SCAN_AREAS]; 27 static int num_scan_areas; 28 29 static __init int set_corruption_check(char *arg) 30 { 31 ssize_t ret; 32 unsigned long val; 33 34 ret = kstrtoul(arg, 10, &val); 35 if (ret) 36 return ret; 37 38 memory_corruption_check = val; 39 return 0; 40 } 41 early_param("memory_corruption_check", set_corruption_check); 42 43 static __init int set_corruption_check_period(char *arg) 44 { 45 ssize_t ret; 46 unsigned long val; 47 48 ret = kstrtoul(arg, 10, &val); 49 if (ret) 50 return ret; 51 52 corruption_check_period = val; 53 return 0; 54 } 55 early_param("memory_corruption_check_period", set_corruption_check_period); 56 57 static __init int set_corruption_check_size(char *arg) 58 { 59 char *end; 60 unsigned size; 61 62 size = memparse(arg, &end); 63 64 if (*end == '\0') 65 corruption_check_size = size; 66 67 return (size == corruption_check_size) ? 0 : -EINVAL; 68 } 69 early_param("memory_corruption_check_size", set_corruption_check_size); 70 71 72 void __init setup_bios_corruption_check(void) 73 { 74 phys_addr_t start, end; 75 u64 i; 76 77 if (memory_corruption_check == -1) { 78 memory_corruption_check = 79 #ifdef CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK 80 1 81 #else 82 0 83 #endif 84 ; 85 } 86 87 if (corruption_check_size == 0) 88 memory_corruption_check = 0; 89 90 if (!memory_corruption_check) 91 return; 92 93 corruption_check_size = round_up(corruption_check_size, PAGE_SIZE); 94 95 for_each_free_mem_range(i, NUMA_NO_NODE, MEMBLOCK_NONE, &start, &end, 96 NULL) { 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); 101 if (start >= end) 102 continue; 103 104 memblock_reserve(start, end - start); 105 scan_areas[num_scan_areas].addr = start; 106 scan_areas[num_scan_areas].size = end - start; 107 108 /* Assume we've already mapped this early memory */ 109 memset(__va(start), 0, end - start); 110 111 if (++num_scan_areas >= MAX_SCAN_AREAS) 112 break; 113 } 114 115 if (num_scan_areas) 116 printk(KERN_INFO "Scanning %d areas for low memory corruption\n", num_scan_areas); 117 } 118 119 120 void check_for_bios_corruption(void) 121 { 122 int i; 123 int corruption = 0; 124 125 if (!memory_corruption_check) 126 return; 127 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; 131 132 for (; size; addr++, size -= sizeof(unsigned long)) { 133 if (!*addr) 134 continue; 135 printk(KERN_ERR "Corrupted low memory at %p (%lx phys) = %08lx\n", 136 addr, __pa(addr), *addr); 137 corruption = 1; 138 *addr = 0; 139 } 140 } 141 142 WARN_ONCE(corruption, KERN_ERR "Memory corruption detected in low memory\n"); 143 } 144 145 static void check_corruption(struct work_struct *dummy); 146 static DECLARE_DELAYED_WORK(bios_check_work, check_corruption); 147 148 static void check_corruption(struct work_struct *dummy) 149 { 150 check_for_bios_corruption(); 151 schedule_delayed_work(&bios_check_work, 152 round_jiffies_relative(corruption_check_period*HZ)); 153 } 154 155 static int start_periodic_check_for_corruption(void) 156 { 157 if (!num_scan_areas || !memory_corruption_check || corruption_check_period == 0) 158 return 0; 159 160 printk(KERN_INFO "Scanning for low memory corruption every %d seconds\n", 161 corruption_check_period); 162 163 /* First time we run the checks right away */ 164 schedule_delayed_work(&bios_check_work, 0); 165 return 0; 166 } 167 device_initcall(start_periodic_check_for_corruption); 168 169