check.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. #include <linux/module.h>
  2. #include <linux/sched.h>
  3. #include <linux/kthread.h>
  4. #include <linux/workqueue.h>
  5. #include <asm/e820.h>
  6. #include <asm/proto.h>
  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. #define MAX_SCAN_AREAS 8
  14. static int __read_mostly memory_corruption_check = -1;
  15. static unsigned __read_mostly corruption_check_size = 64*1024;
  16. static unsigned __read_mostly corruption_check_period = 60; /* seconds */
  17. static struct e820entry scan_areas[MAX_SCAN_AREAS];
  18. static int num_scan_areas;
  19. static __init int set_corruption_check(char *arg)
  20. {
  21. char *end;
  22. memory_corruption_check = simple_strtol(arg, &end, 10);
  23. return (*end == 0) ? 0 : -EINVAL;
  24. }
  25. early_param("memory_corruption_check", set_corruption_check);
  26. static __init int set_corruption_check_period(char *arg)
  27. {
  28. char *end;
  29. corruption_check_period = simple_strtoul(arg, &end, 10);
  30. return (*end == 0) ? 0 : -EINVAL;
  31. }
  32. early_param("memory_corruption_check_period", set_corruption_check_period);
  33. static __init int set_corruption_check_size(char *arg)
  34. {
  35. char *end;
  36. unsigned size;
  37. size = memparse(arg, &end);
  38. if (*end == '\0')
  39. corruption_check_size = size;
  40. return (size == corruption_check_size) ? 0 : -EINVAL;
  41. }
  42. early_param("memory_corruption_check_size", set_corruption_check_size);
  43. void __init setup_bios_corruption_check(void)
  44. {
  45. u64 addr = PAGE_SIZE; /* assume first page is reserved anyway */
  46. if (memory_corruption_check == -1) {
  47. memory_corruption_check =
  48. #ifdef CONFIG_X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK
  49. 1
  50. #else
  51. 0
  52. #endif
  53. ;
  54. }
  55. if (corruption_check_size == 0)
  56. memory_corruption_check = 0;
  57. if (!memory_corruption_check)
  58. return;
  59. corruption_check_size = round_up(corruption_check_size, PAGE_SIZE);
  60. while (addr < corruption_check_size && num_scan_areas < MAX_SCAN_AREAS) {
  61. u64 size;
  62. addr = find_e820_area_size(addr, &size, PAGE_SIZE);
  63. if (!(addr + 1))
  64. break;
  65. if (addr >= corruption_check_size)
  66. break;
  67. if ((addr + size) > corruption_check_size)
  68. size = corruption_check_size - addr;
  69. e820_update_range(addr, size, E820_RAM, E820_RESERVED);
  70. scan_areas[num_scan_areas].addr = addr;
  71. scan_areas[num_scan_areas].size = size;
  72. num_scan_areas++;
  73. /* Assume we've already mapped this early memory */
  74. memset(__va(addr), 0, size);
  75. addr += size;
  76. }
  77. printk(KERN_INFO "Scanning %d areas for low memory corruption\n",
  78. num_scan_areas);
  79. update_e820();
  80. }
  81. void check_for_bios_corruption(void)
  82. {
  83. int i;
  84. int corruption = 0;
  85. if (!memory_corruption_check)
  86. return;
  87. for (i = 0; i < num_scan_areas; i++) {
  88. unsigned long *addr = __va(scan_areas[i].addr);
  89. unsigned long size = scan_areas[i].size;
  90. for (; size; addr++, size -= sizeof(unsigned long)) {
  91. if (!*addr)
  92. continue;
  93. printk(KERN_ERR "Corrupted low memory at %p (%lx phys) = %08lx\n",
  94. addr, __pa(addr), *addr);
  95. corruption = 1;
  96. *addr = 0;
  97. }
  98. }
  99. WARN_ONCE(corruption, KERN_ERR "Memory corruption detected in low memory\n");
  100. }
  101. static void check_corruption(struct work_struct *dummy);
  102. static DECLARE_DELAYED_WORK(bios_check_work, check_corruption);
  103. static void check_corruption(struct work_struct *dummy)
  104. {
  105. check_for_bios_corruption();
  106. schedule_delayed_work(&bios_check_work,
  107. round_jiffies_relative(corruption_check_period*HZ));
  108. }
  109. static int start_periodic_check_for_corruption(void)
  110. {
  111. if (!memory_corruption_check || corruption_check_period == 0)
  112. return 0;
  113. printk(KERN_INFO "Scanning for low memory corruption every %d seconds\n",
  114. corruption_check_period);
  115. /* First time we run the checks right away */
  116. schedule_delayed_work(&bios_check_work, 0);
  117. return 0;
  118. }
  119. module_init(start_periodic_check_for_corruption);