在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_mem
static 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);
}

kernel中的memtest相关推荐

  1. 在 CUDA C/C++ kernel中使用内存

    在 CUDA C/C++ kernel中使用内存 如何在主机和设备之间高效地移动数据.本文将讨论如何有效地从内核中访问设备存储器,特别是 全局内存 . 在 CUDA 设备上有几种内存,每种内存的作用域 ...

  2. 【kernel 中内存分配那点事】

    首先呢作为车载bsp开发人员,写大量的内核代码是不现实的事情,多数都是修修改改,但是要有内核代码阅读浏览理解的能力,毕竟linux kernel 还是很nb 的,所有技术人员深入研究内核代码是必须的, ...

  3. linux kernel中的cmdline的详细介绍

    cmdline 1.向linux kernel添加cmdline的四种方式 (1). 在dts中的bootargs中添加 (2).在BoardConfig中添加 (3).在uboot中添加 (4).在 ...

  4. linux kernel中的栈的介绍

    目录 1.linux kernel中的中断irq的栈stack (1).arm32体系的irq的栈 (2).arm64体系的irq的栈 2.linux kernel中的栈stack (1).概念介绍: ...

  5. linux kernel中的进程栈

    1.linux中的user mode的进程栈 在thread_info.h中,设置进程栈的大小为16k #define THREAD_SIZE 16384 #define THREAD_START_S ...

  6. linux kernel中的virt_to_phys代码解读

    假设VA_BITS = 48 (虚拟地址有效位), 那么kernel space的虚拟地址是:0xffff_0000_0000_0000 - 0xffff_ffff_ffff_ffff, usersp ...

  7. linux kernel中cache代码解读

    1. 在kernel中调用__dma_flush_range,底层是如何操作的呢? /* remove any dirty cache lines on the kernel alias */__dm ...

  8. linux内核多队列,Linux Kernel 中 Workqueue 使用系统默认队列和创建队列的方法

    关于workqueue,我们还是有很多话要说. 想必大家对workqueue相关的函数(schedule_work .queue_work.INIT_WORK.create_singlethread_ ...

  9. Linux kernel 中模块化的平台驱动代码介绍

    介绍 在linux kernel中通过module_platform_driver来实现模块化平台驱动.大量的设备驱动程序都基于该种方式来实现,使用频次非常的高,在linux kernel 5.4.1 ...

  10. Linux kernel中常见的宏整理

    0x00 宏的基本知识 // object-like #define 宏名 替换列表 换行符 //function-like #define 宏名 ([标识符列表]) 替换列表 换行符 替换列表和标识 ...

最新文章

  1. 微信小程序ios可以上下左右拖动的问题
  2. css聊天布局,CSS实现聊天布局
  3. 操作系统课设--具有优先级的线程调度
  4. 你绝对能懂的“机器学习”(四)
  5. linux中s权限大小写的区别,Linux中的权限
  6. asp.net excel导入 wps_4种Excel格式的转换方法,总有一种适合你!赶紧试试看
  7. bzoj 3884: 上帝与集合的正确用法(欧拉函数)
  8. leetcode—8.同向双指针—滑动窗口题型python解答
  9. 大型网站系统架构实践(六)深入探讨web应用集群Session保持
  10. 第六章 函数逼近-强化学习理论学习与代码实现(强化学习导论第二版)
  11. 在eclipse中创建web项目
  12. Spring Cloud Eureka详解
  13. mongodb导出csv文件到vcf
  14. 2018acm编程大赛题目c语言,编程竞赛题(超牛题目,留下做研究).doc
  15. MATLAB中fspecial()函数的用法
  16. OneAPIConnect(一) 欧姆龙FINS协议实现源代码
  17. PostgreSQL实现USERENV函数(兼容oracle)
  18. 【论文阅读|深读】DRNE:Deep Recursive Network Embedding with Regular Equivalence
  19. 元学习、迁移学习、对比学习、自监督学习与少样本学习的关系解读
  20. XFLR5机翼分析工具下载及使用

热门文章

  1. 【干货分享】迄今为止最好用的编程字体-支持中文正确显示:同时彻底解决eclipse中文注释缩进排版混乱问题
  2. AD16 pdf打印输出彩色
  3. 408计算机及格要什么水平,2019考研计算机408难度水平?
  4. 2009-2021计算机408统考真题及解析分享
  5. cad抛物线曲线lisp_cad画缓和曲线lisp程序(1)
  6. sap系统搭建教程_SAP系统和微信集成的系列教程之一:微信开发环境的搭建
  7. 嵌入式linux ucgui,成功移植ucGUI到Linux上
  8. C++ 回调函数简单示例
  9. 正交幅度调制(QAM)
  10. MDUI 输入确认框