root/arch/x86/kernel/check.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. set_corruption_check
  2. set_corruption_check_period
  3. set_corruption_check_size
  4. setup_bios_corruption_check
  5. check_for_bios_corruption
  6. check_corruption
  7. start_periodic_check_for_corruption

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

/* [<][>][^][v][top][bottom][index][help] */