memtest.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. #include <linux/kernel.h>
  2. #include <linux/errno.h>
  3. #include <linux/string.h>
  4. #include <linux/types.h>
  5. #include <linux/mm.h>
  6. #include <linux/smp.h>
  7. #include <linux/init.h>
  8. #include <linux/pfn.h>
  9. #include <linux/memblock.h>
  10. static u64 patterns[] __initdata = {
  11. /* The first entry has to be 0 to leave memtest with zeroed memory */
  12. 0,
  13. 0xffffffffffffffffULL,
  14. 0x5555555555555555ULL,
  15. 0xaaaaaaaaaaaaaaaaULL,
  16. 0x1111111111111111ULL,
  17. 0x2222222222222222ULL,
  18. 0x4444444444444444ULL,
  19. 0x8888888888888888ULL,
  20. 0x3333333333333333ULL,
  21. 0x6666666666666666ULL,
  22. 0x9999999999999999ULL,
  23. 0xccccccccccccccccULL,
  24. 0x7777777777777777ULL,
  25. 0xbbbbbbbbbbbbbbbbULL,
  26. 0xddddddddddddddddULL,
  27. 0xeeeeeeeeeeeeeeeeULL,
  28. 0x7a6c7258554e494cULL, /* yeah ;-) */
  29. };
  30. static void __init reserve_bad_mem(u64 pattern, u64 start_bad, u64 end_bad)
  31. {
  32. printk(KERN_INFO " %016llx bad mem addr %010llx - %010llx reserved\n",
  33. (unsigned long long) pattern,
  34. (unsigned long long) start_bad,
  35. (unsigned long long) end_bad);
  36. memblock_reserve(start_bad, end_bad - start_bad);
  37. }
  38. static void __init memtest(u64 pattern, u64 start_phys, u64 size)
  39. {
  40. u64 *p, *start, *end;
  41. u64 start_bad, last_bad;
  42. u64 start_phys_aligned;
  43. const size_t incr = sizeof(pattern);
  44. start_phys_aligned = ALIGN(start_phys, incr);
  45. start = __va(start_phys_aligned);
  46. end = start + (size - (start_phys_aligned - start_phys)) / incr;
  47. start_bad = 0;
  48. last_bad = 0;
  49. for (p = start; p < end; p++)
  50. *p = pattern;
  51. for (p = start; p < end; p++, start_phys_aligned += incr) {
  52. if (*p == pattern)
  53. continue;
  54. if (start_phys_aligned == last_bad + incr) {
  55. last_bad += incr;
  56. continue;
  57. }
  58. if (start_bad)
  59. reserve_bad_mem(pattern, start_bad, last_bad + incr);
  60. start_bad = last_bad = start_phys_aligned;
  61. }
  62. if (start_bad)
  63. reserve_bad_mem(pattern, start_bad, last_bad + incr);
  64. }
  65. static void __init do_one_pass(u64 pattern, u64 start, u64 end)
  66. {
  67. u64 i;
  68. phys_addr_t this_start, this_end;
  69. for_each_free_mem_range(i, MAX_NUMNODES, &this_start, &this_end, NULL) {
  70. this_start = clamp_t(phys_addr_t, this_start, start, end);
  71. this_end = clamp_t(phys_addr_t, this_end, start, end);
  72. if (this_start < this_end) {
  73. printk(KERN_INFO " %010llx - %010llx pattern %016llx\n",
  74. (unsigned long long)this_start,
  75. (unsigned long long)this_end,
  76. (unsigned long long)cpu_to_be64(pattern));
  77. memtest(pattern, this_start, this_end - this_start);
  78. }
  79. }
  80. }
  81. /* default is disabled */
  82. static int memtest_pattern __initdata;
  83. static int __init parse_memtest(char *arg)
  84. {
  85. if (arg)
  86. memtest_pattern = simple_strtoul(arg, NULL, 0);
  87. else
  88. memtest_pattern = ARRAY_SIZE(patterns);
  89. return 0;
  90. }
  91. early_param("memtest", parse_memtest);
  92. void __init early_memtest(unsigned long start, unsigned long end)
  93. {
  94. unsigned int i;
  95. unsigned int idx = 0;
  96. if (!memtest_pattern)
  97. return;
  98. printk(KERN_INFO "early_memtest: # of tests: %d\n", memtest_pattern);
  99. for (i = memtest_pattern-1; i < UINT_MAX; --i) {
  100. idx = i % ARRAY_SIZE(patterns);
  101. do_one_pass(patterns[idx], start, end);
  102. }
  103. }