kernel中的memtest

来源:互联网 发布:实矩阵的奇异值分解 编辑:程序博客网 时间:2024/06/06 12:24
在mm/Makefile中obj-$(CONFIG_MEMTEST)+= memtest.o可以看到使能CONFIG_MEMTEST,并且传递的command line 中保护 memtest 关键字的话,则kernel会对没有使用的free memory做memtest具体源码在mm/memtest.c中static int __init parse_memtest(char *arg){int ret = 0;//看关键字memtest后面是否跟参数,memtest后面跟的参数表示测试dram的pattern,如果没有跟参数的话,就用kernel已经定义好的patternif (arg)ret = kstrtouint(arg, 0, &memtest_pattern);elsememtest_pattern = ARRAY_SIZE(patterns);return ret;}early_param("memtest", parse_memtest);设置好参数后就通过bootmem_init->early_memtest来测试void __init bootmem_init(void){unsigned long min, max;min = PFN_UP(memblock_start_of_DRAM());max = PFN_DOWN(memblock_end_of_DRAM());//可以看到测试的范围是整个memblockearly_memtest(min << PAGE_SHIFT, max << PAGE_SHIFT);}void __init early_memtest(phys_addr_t start, phys_addr_t end){unsigned int i;unsigned int idx = 0;if (!memtest_pattern)return;//可见是通过for循环来遍历整个memtest_pattern 数组pr_info("early_memtest: # of tests: %u\n", memtest_pattern);for (i = memtest_pattern-1; i < UINT_MAX; --i) {idx = i % ARRAY_SIZE(patterns);//针对每个pattern都调用do_one_pass 来测试do_one_pass(patterns[idx], start, end);}}memtest_pattern被赋值成下面的数组,可见pattern就是一个64bit的数static u64 patterns[] __initdata = {/* The first entry has to be 0 to leave memtest with zeroed memory */0,0x5555555555555555ULL,0xaaaaaaaaaaaaaaaaULL,};static void __init do_one_pass(u64 pattern, phys_addr_t start, phys_addr_t end){u64 i;phys_addr_t this_start, this_end;//针对memblock中所有free的memory测试for_each_free_mem_range(i, NUMA_NO_NODE, MEMBLOCK_NONE, &this_start,&this_end, NULL) {//这里的clamp相当与一个if else 语句this_start = clamp(this_start, start, end);this_end = clamp(this_end, start, end);if (this_start < this_end) {pr_info("  %pa - %pa pattern %016llx\n",&this_start, &this_end, cpu_to_be64(pattern));memtest(pattern, this_start, this_end - this_start);}}}static void __init memtest(u64 pattern, phys_addr_t start_phys, phys_addr_t size){u64 *p, *start, *end;phys_addr_t start_bad, last_bad;phys_addr_t start_phys_aligned;const size_t incr = sizeof(pattern);start_phys_aligned = ALIGN(start_phys, incr);start = __va(start_phys_aligned);end = start + (size - (start_phys_aligned - start_phys)) / incr;start_bad = 0;last_bad = 0;//将pattern写道dram中for (p = start; p < end; p++)*p = pattern;//从dram中读到pattern和写入的pattern 比较,如果不想等的话,就说明测试failed,就将这段memory通过reserve_bad_mem 保留起来不使用,从而保证系统能正常bootfor (p = start; p < end; p++, start_phys_aligned += incr) {if (*p == pattern)continue;if (start_phys_aligned == last_bad + incr) {last_bad += incr;continue;}if (start_bad)reserve_bad_mem(pattern, start_bad, last_bad + incr);start_bad = last_bad = start_phys_aligned;}if (start_bad)reserve_bad_mem(pattern, start_bad, last_bad + incr);}继续看看reserve_bad_memstatic void __init reserve_bad_mem(u64 pattern, phys_addr_t start_bad, phys_addr_t end_bad){pr_info("  %016llx bad mem addr %pa - %pa reserved\n",cpu_to_be64(pattern), &start_bad, &end_bad);//原来是通过memblock_reserve 来将有问题的dram 预留出来。memblock_reserve(start_bad, end_bad - start_bad);}

原创粉丝点击