linux/arch/x86/mm/memtest.c
<<
>>
Prefs
   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
  10#include <asm/e820.h>
  11
  12static void __init memtest(unsigned long start_phys, unsigned long size,
  13                                 unsigned pattern)
  14{
  15        unsigned long i;
  16        unsigned long *start;
  17        unsigned long start_bad;
  18        unsigned long last_bad;
  19        unsigned long val;
  20        unsigned long start_phys_aligned;
  21        unsigned long count;
  22        unsigned long incr;
  23
  24        switch (pattern) {
  25        case 0:
  26                val = 0UL;
  27                break;
  28        case 1:
  29                val = -1UL;
  30                break;
  31        case 2:
  32#ifdef CONFIG_X86_64
  33                val = 0x5555555555555555UL;
  34#else
  35                val = 0x55555555UL;
  36#endif
  37                break;
  38        case 3:
  39#ifdef CONFIG_X86_64
  40                val = 0xaaaaaaaaaaaaaaaaUL;
  41#else
  42                val = 0xaaaaaaaaUL;
  43#endif
  44                break;
  45        default:
  46                return;
  47        }
  48
  49        incr = sizeof(unsigned long);
  50        start_phys_aligned = ALIGN(start_phys, incr);
  51        count = (size - (start_phys_aligned - start_phys))/incr;
  52        start = __va(start_phys_aligned);
  53        start_bad = 0;
  54        last_bad = 0;
  55
  56        for (i = 0; i < count; i++)
  57                start[i] = val;
  58        for (i = 0; i < count; i++, start++, start_phys_aligned += incr) {
  59                if (*start != val) {
  60                        if (start_phys_aligned == last_bad + incr) {
  61                                last_bad += incr;
  62                        } else {
  63                                if (start_bad) {
  64                                        printk(KERN_CONT "\n  %016lx bad mem addr %010lx - %010lx reserved",
  65                                                val, start_bad, last_bad + incr);
  66                                        reserve_early(start_bad, last_bad + incr, "BAD RAM");
  67                                }
  68                                start_bad = last_bad = start_phys_aligned;
  69                        }
  70                }
  71        }
  72        if (start_bad) {
  73                printk(KERN_CONT "\n  %016lx bad mem addr %010lx - %010lx reserved",
  74                        val, start_bad, last_bad + incr);
  75                reserve_early(start_bad, last_bad + incr, "BAD RAM");
  76        }
  77}
  78
  79/* default is disabled */
  80static int memtest_pattern __initdata;
  81
  82static int __init parse_memtest(char *arg)
  83{
  84        if (arg)
  85                memtest_pattern = simple_strtoul(arg, NULL, 0);
  86        return 0;
  87}
  88
  89early_param("memtest", parse_memtest);
  90
  91void __init early_memtest(unsigned long start, unsigned long end)
  92{
  93        u64 t_start, t_size;
  94        unsigned pattern;
  95
  96        if (!memtest_pattern)
  97                return;
  98
  99        printk(KERN_INFO "early_memtest: pattern num %d", memtest_pattern);
 100        for (pattern = 0; pattern < memtest_pattern; pattern++) {
 101                t_start = start;
 102                t_size = 0;
 103                while (t_start < end) {
 104                        t_start = find_e820_area_size(t_start, &t_size, 1);
 105
 106                        /* done ? */
 107                        if (t_start >= end)
 108                                break;
 109                        if (t_start + t_size > end)
 110                                t_size = end - t_start;
 111
 112                        printk(KERN_CONT "\n  %010llx - %010llx pattern %d",
 113                                (unsigned long long)t_start,
 114                                (unsigned long long)t_start + t_size, pattern);
 115
 116                        memtest(t_start, t_size, pattern);
 117
 118                        t_start += t_size;
 119                }
 120        }
 121        printk(KERN_CONT "\n");
 122}
 123