参考:

https://blog.csdn.net/evenness/article/details/7818857

https://blog.csdn.net/skdkjzz/article/details/17073455

https://blog.csdn.net/sannik/article/details/8930625#

在 U-Boot中,Denx(U-Boot的开发商)针对常见的DDR内存故障进行了严格的检测处理,上图描述了该检测处理过程的三个步骤:检测数据线、地址线和DDR物理存储部件,主要涉及这三个步骤的处理过程和方法,对于DDR子系统,是很容易出故障并且是很难debug检测出来的,而Denx所针对 DDR内存故障设计的检测方法是非常严谨,值得学习研究的。

1、为什么先检测数据线?

因为如果数据线是断开的,那么一切无从谈起!接下来是检测地址线,只有数据线和地址线都通过,检测内存的存储单元才有意义,这样的流程也利于分割定位问题。上面testingsequence框图将整个检测过程分成三大步,用三个虚线方框表示。

2、数据线的连接错误

数据线的连接可能存在两种错误,一种是被断开,另一种布线或生产造成互相短路。

3、如何检测数据线的连接错误

Denx设计的数据线检测算法还是很Tricky和精秒的,整个处理流程如下例子:如果是两根数据线,只需要写入并读出一个pattern=0b01(0b开头表示二进制数)就能判断它们是否短路或断开。很明显,大部分的嵌入式平台不止两根数据线,我们以64位地址线为例,pattern= 0b101010101010101010....能检测出奇偶位之间的数据错误。如果这个错误被排除,每两根数据线组成一组(这是理解下一个pattern的关键),再用相同的办法,检测每相邻两组之间是否有短路,就得到第二个pattern,就是0b110011001100...... 依次类推,以4根数据线为一组,8根线为一组,相继得到共6个pattern,分别是0xaaaaaaaaaaaaaaaa,0xcccccccccccccccc,0xf0f0f0f0f0f0f0f0,0xff00ff00ff00ff00,0xffff0000ffff0000,0xffffffff00000000。只要相继写入并读出这6个pattern就能验证是否存在数据线交叉短路错误。

4、如何检测数据线与板上其它信号线交叉短路或断路

取以上6个pattern的反码,总共12个pattern就能检测到每一位都可以写入和读出0和1。

5、什么是floating buses错误

floatingbuses会“欺骗”测试软件,如果测试软件写入并很快读出一个值的时候,写操作会跟数据线上的电容充电,总线会短暂的保持它的状态。当测试软件读操作时,总线会返回刚写入的值,即使实际上该数据线是断路的。

6、如何检测数据线的floating buses错误

检测floatingbuses错误的算法不复杂,在写入和读回之间再插入一次对不同地址写入不同值的操作。例如,X写入X1位置,Y写入Y1位置,再从X1位置读出X值则表示floatingbuses错误不存在。

7、地址线的错误

如果地址线存在错误,其症状是地址空间中的两个不同位置被映射到同一物理存储位置。更通俗地讲,就是写一个位置却“改变”了另一个位置。

8、地址线的错误检测

地址线的错误检测相对简单,其算法是:

1)、将地址的值作为内容写入该地址处,汇编的表示方法是 (addr) =addr。即将地址值写到地址对应的空间里,这样确保每一个位置的内容不同。

2)、依次将内存基地址的某一根地址线的值翻转(flip/toggle)得到某个地址,从该地址取值,如果该值和基地址的值相等,则表示某一位地址线有问题。

这个算法的特点是每次只检测一根地址线,方法简单有效。

9、存储单元的错误

以上数据线和地址线的检测都是检测布线或工厂生产的错误,而存储单元的检测则是真正对DDR内存芯片的检测。内存芯片的常见错误是bit-stuck,简而言之,就是让它是0,它偏为1,让它为1,它偏为0,检测方法也很简单,就是用不同的pattern去写尽可能所有的地址并读回比较。有一些常用的pattern如0x5555, 0xAAAA等。

10、几个简单的检测DDR故障的方法

上面的DDR检测算法,虽然全面,但是耗时比较长,常常需要好几个小时,在Uboot命令行下也有几个简单的命令可以检测常见内存故障,如下所示:

1)、mtest addr lenth pattern

这个命令需要注意,DDR在Uboot启动后被映射到了0地址,但是uboot的代码和堆、栈空间0x10000000处开始,这些空间是不能被刷的,否则就挂死了。

2)、复制NOR flash的内容到内存中,如 cp.b 0x20080000 0x7fc020000,然后比较 cmp.b 0x20080000 0x7fc0 20000。

3)、下载kernel image到内存中,copy NOR flash或tftp都行,然后调用iminfo LOAD_ADDR 检测CRC错误。

第一种方法是用特定的pattern去刷DDR的空闲空间,第二种和第三种方法可以说Pattern的随机性更大一些。

当然最彻底的检测方法当然是长时间跑Linux系统,上面的方法更适用于系统不稳定时定位错误。

实现代码如下:

static void move64(unsigned long long *src, unsigned long long *dest){*dest = *src;}/** This is 64 bit wide test patterns.  Note that they reside in ROM* (which presumably works) and the tests write them to RAM which may* not work.** The "otherpattern" is written to drive the data bus to values other* than the test pattern.  This is for detecting floating bus lines.**/const static unsigned long long pattern[] = {0xaaaaaaaaaaaaaaaaULL,0xccccccccccccccccULL,0xf0f0f0f0f0f0f0f0ULL,0xff00ff00ff00ff00ULL,0xffff0000ffff0000ULL,0xffffffff00000000ULL,0x00000000ffffffffULL,0x0000ffff0000ffffULL,0x00ff00ff00ff00ffULL,0x0f0f0f0f0f0f0f0fULL,0x3333333333333333ULL,0x5555555555555555ULL};const unsigned long long otherpattern = 0x0123456789abcdefULL;/* 数据线检测 */static int memory_post_dataline(unsigned long long * pmem){unsigned long long temp64 = 0;int num_patterns = sizeof(pattern)/ sizeof(pattern[0]);int i;unsigned int hi, lo, pathi, patlo;int ret = 0;for ( i = 0; i < num_patterns; i++)
{
move64((unsigned long long *)&(pattern[i]), pmem++);
/*
* Put a different pattern on the data lines: otherwise they
* may float long enough to read back what we wrote.
*/
/* 预防floating buses错误 */
move64((unsigned long long *)&otherpattern, pmem--);
move64(pmem, &temp64);#ifdef INJECT_DATA_ERRORS
temp64 ^= 0x00008000;
#endifif (temp64 != pattern[i])
{
pathi = (pattern[i]>>32) & 0xffffffff;patlo = pattern[i] & 0xffffffff;hi = (temp64>>32) & 0xffffffff;lo = temp64 & 0xffffffff;post_log ("Memory (date line) error at %08x, ""wrote %08x%08x, read %08x%08x !\n",pmem, pathi, patlo, hi, lo);ret = -1;}}return ret;}/* 地址线检测 */static int memory_post_addrline(ulong *testaddr, ulong *base, ulong size){ulong *target;ulong *end;ulong readback;ulong xor;int   ret = 0;end = (ulong *)((ulong)base + size);/* pointer arith! */xor = 0;for(xor = sizeof(ulong); xor > 0; xor <<= 1)
{
/* 对测试的地址的某一根地址线的值翻转 */
target = (ulong *)((ulong)testaddr ^ xor);
if((target >= base) && (target < end))
{
/* 由于target是testaddr某一根地址线的值翻转得来故testaddr != target,下面赋值操作后应有*testaddr != *target */
*testaddr = ~*target;
readback  = *target;#ifdef INJECT_ADDRESS_ERRORS
if(xor == 0x00008000)
{
readback = *testaddr;
}
#endif/* 出现此种情况只有testaddr == target,即某根地址线翻转无效 */
if(readback == *testaddr)
{
post_log ("Memory (address line) error at %08x<->%08x, ""XOR value %08x !\n",testaddr, target, xor);ret = -1;}}}return ret;}static int memory_post_test1 (unsigned long start,unsigned long size,unsigned long val){unsigned long i;ulong *mem = (ulong *) start;ulong readback;int ret = 0;for (i = 0; i < size / sizeof (ulong); i++) {
mem[i] = val;
if (i % 1024 == 0)
WATCHDOG_RESET ();
}for (i = 0; i < size / sizeof (ulong) && ret == 0; i++) {
readback = mem[i];
if (readback != val) {
post_log ("Memory error at %08x, ""wrote %08x, read %08x !\n",mem + i, val, readback);ret = -1;
break;
}
if (i % 1024 == 0)
WATCHDOG_RESET ();
}return ret;
}static int memory_post_test2 (unsigned long start, unsigned long size)
{
unsigned long i;
ulong *mem = (ulong *) start;
ulong readback;
int ret = 0;for (i = 0; i < size / sizeof (ulong); i++) {
mem[i] = 1 << (i % 32);
if (i % 1024 == 0)
WATCHDOG_RESET ();
}for (i = 0; i < size / sizeof (ulong) && ret == 0; i++) {
readback = mem[i];
if (readback != (1 << (i % 32))) {
post_log ("Memory error at %08x, ""wrote %08x, read %08x !\n",mem + i, 1 << (i % 32), readback);ret = -1;
break;
}
if (i % 1024 == 0)
WATCHDOG_RESET ();
}return ret;
}static int memory_post_test3 (unsigned long start, unsigned long size)
{
unsigned long i;
ulong *mem = (ulong *) start;
ulong readback;
int ret = 0;for (i = 0; i < size / sizeof (ulong); i++) {
mem[i] = i;
if (i % 1024 == 0)
WATCHDOG_RESET ();
}for (i = 0; i < size / sizeof (ulong) && ret == 0; i++) {
readback = mem[i];
if (readback != i) {
post_log ("Memory error at %08x, ""wrote %08x, read %08x !\n",mem + i, i, readback);ret = -1;
break;
}
if (i % 1024 == 0)
WATCHDOG_RESET ();
}return ret;
}static int memory_post_test4 (unsigned long start, unsigned long size)
{
unsigned long i;
ulong *mem = (ulong *) start;
ulong readback;
int ret = 0;for (i = 0; i < size / sizeof (ulong); i++) {
mem[i] = ~i;
if (i % 1024 == 0)
WATCHDOG_RESET ();
}for (i = 0; i < size / sizeof (ulong) && ret == 0; i++) {
readback = mem[i];
if (readback != ~i) {
post_log ("Memory error at %08x, ""wrote %08x, read %08x !\n",mem + i, ~i, readback);ret = -1;
break;
}
if (i % 1024 == 0)
WATCHDOG_RESET ();
}return ret;
}static int memory_post_tests (unsigned long start, unsigned long size)
{
int ret = 0;if (ret == 0)
ret = memory_post_dataline ((unsigned long long *)start);
WATCHDOG_RESET ();
if (ret == 0)
ret = memory_post_addrline ((ulong *)start, (ulong *)start, size);
WATCHDOG_RESET ();
if (ret == 0)
ret = memory_post_addrline ((ulong *)(start + size - 8),(ulong *)start, size);
WATCHDOG_RESET ();
if (ret == 0)
ret = memory_post_test1 (start, size, 0x00000000);
WATCHDOG_RESET ();
if (ret == 0)
ret = memory_post_test1 (start, size, 0xffffffff);
WATCHDOG_RESET ();
if (ret == 0)
ret = memory_post_test1 (start, size, 0x55555555);
WATCHDOG_RESET ();
if (ret == 0)
ret = memory_post_test1 (start, size, 0xaaaaaaaa);
WATCHDOG_RESET ();
if (ret == 0)
ret = memory_post_test2 (start, size);
WATCHDOG_RESET ();
if (ret == 0)
ret = memory_post_test3 (start, size);
WATCHDOG_RESET ();
if (ret == 0)
ret = memory_post_test4 (start, size);
WATCHDOG_RESET ();return ret;
}

BIOS中的内存测试memtest相关推荐

  1. Redis源代码分析(十一年)--- memtest内存测试

    今天,我们继续redis源代码test下测试在封装中的其它文件.今天读数memtest档,翻译了,那是,memory test 存储器测试工具..可是里面的提及了非常多东西,也给我涨了非常多见识,网上 ...

  2. linux内存测试工具memtest,Linux-内存检测利器Memtest86+v1.70

    [Linux]内存检测利器Memtest86+ v1.70 Memtest86+是一款基于Linux核心的内存检测工具,由x86-secret小组在Chris Brady的Memtest86的基础上增 ...

  3. bios sgx需要开启吗_BIOS中设置内存的XMP模式有什么用?

    内存从外观上看分为普通条和马甲条,通常来说普条的内存都遵守JEDEC的基础频率和时序,频率基本都较低,而带马甲的大多是超频条,频率要比普条更高.那么怎样才能让它在高频下工作呢?这就需要讲到主板BIOS ...

  4. 内存测试内存检测工具

    测试内存,往往不局限于一种软件,因为每种工具都有自己的局限性.灵活运用多种工具,可以实现效益最大化 1.<HCI MemTest> https://hcidesign.com/memtes ...

  5. 华为服务器bios中修改磁盘格式,华为服务器设置bios

    华为服务器设置bios 内容精选 换一换 通过在BIOS中设置一些高级选项,可以有效提升虚拟化平台性能.表1列出了TaiShan服务器和性能相关的BIOS推荐配置项.开启CPU预取配置选项的目的在于C ...

  6. 三种内存测试软件的使用说明

    (1)微软内存检测工具 现在的系统盘一般都带有"微软内存检测工具".程序加载后,即会开始扫描 RAM.扫描界面如下图: Windows Memory Diagnostic 工具启动 ...

  7. 内存兼容性测试软件,Ryzen内存测试:有BUG兼容性较差_DIY攒机选购指南-中关村在线...

    锐龙AMD Ryzen内存测试:有BUG兼容性较差 据悉Ryzen 7的一个"小Bug":当插满4条DDR4内存的时候,频率最高只能上到DDR4-2400,插2条的时候就能上到DD ...

  8. 测试u盘内存的软件,memtest86+-2.11内存测试、测速软件

    很强大的一款内存测试软件,小巧,放U盘上很舒服. 使用方法: DOS启动U盘,通过GRUB调用下载包中的ISO文件即可. Memtest86是一款免费开源的内存测试软件,测试准确度比较高,内存的隐性问 ...

  9. Linux入门 内存测试工具(Memtest86+)

    分享一下我老师大神的人工智能教程.零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow 一.memtest ...

  10. Linux入门:内存测试工具(Memtest86+)

    一.memtest86+ 接触到memtest86+是因为Linux,但是这个内存测试工具并不是依附于Linux: memtest86+ 是一款内存测试工具,但是这款软件不能够在windows或Lin ...

最新文章

  1. java text 格式化_java.text.DecimalFormat类十进制格式化
  2. 服务器t4卡在哪个位置,英特尔(Intel )X710-T4融合网络适配器4口万兆X710T4服务器网卡...
  3. android view gesturedetector,如何在Android中利用 GestureDetector进行手势检测
  4. [笔记]cin、cout与scanf、printf的效率差异对比分析
  5. java 取pdf 文本域_java – 使用iText从pdf文件中提取文本列
  6. 全局路径规划A star的Matlab实现
  7. synchronized()_JMM(四):浅谈synchronized锁
  8. DB2 SQL执行计划
  9. c语言程序基础设计题,《C语言程序设计基础》习题集(含答案)
  10. ios 定位权限获取
  11. 编写c语言程序实现如下功能 创建父子进程,青岛理工大学操作系统实验指导及实验报告.doc...
  12. 三天吃透MySQL面试八股文
  13. 怎样制作一个漂亮的艺术二维码?
  14. C++中二维数组的动态创建于处理(zzl
  15. Uncaught (in promise) Error: Request failed with status code 415
  16. 4.微信登入小程序与后端实现
  17. 单款地图下载器如何授权
  18. Master PDF Editor v5.7.91 最小巧的PDF编辑器便携版
  19. java万年历uml_Java Calendar,Date,DateFormat,TimeZone,Locale等时间相关内容的认知和使用(2) 自己封装的Calendar接口...
  20. metascape中聚类,然后对其中KEGG通路中基因进行定位

热门文章

  1. Android GPS定位(获取经纬度)
  2. C专家编程 第1章 C:穿越时空的迷雾 1.1 C语言的史前阶段
  3. 【每周更新】OpenWrtLEDE精品软路由x86/64稳定版固件下载
  4. 乱码转换器在线转换_有了这几款视频下载转换软件,想看的视频都可以随意看了...
  5. Java之时间格式转换
  6. Ubuntu 19.04 缺少libpng12.so.0
  7. 纤亿通教你如何选择合适的 Cat6 网线
  8. [JS]回调函数例子
  9. vue 电子签名插件
  10. 【学习笔记】python实现excel数据处理