📄 chkmem.c
字号:
/*-------------------------------------------------------------------------
* Filename: chkmem.c
* Version: $Id: chkmem.c,v 1.6 2001/10/29 11:49:48 seletz Exp $
* Copyright: Copyright (C) 2001, Stefan Eletzhofer
* Author: Stefan Eletzhofer <stefan.eletzhofer@www.eletztrick.net>
* Description: memory test functions
* Created at: Mit Sep 26 19:20:24 CEST 2001
* Modified by:
* Modified at:
*-----------------------------------------------------------------------*/
/*
* chkmem.c: Utility to test memory integrity
*
* Copyright (C) 2001 Stefan Eletzhofer <stefan.eletzhofer@www.eletztrick.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ident "$Id: chkmem.c,v 1.6 2001/10/29 11:49:48 seletz Exp $"
#ifdef HAVE_CONFIG_H
# include <blob/config.h>
#endif
#include <blob/arch.h>
#include <blob/command.h>
#include <blob/types.h>
#include <blob/serial.h>
#include <blob/time.h>
#include <blob/util.h>
#include <blob/memory.h>
/*********************************************************************/
/** DEFINES *********************************************************/
/*********************************************************************/
/* define this to 1 for debug */
#define CHKMEM_DEBUG 1
/* show every X bytes of memory during test */
#define CHKMEM_SHOWEVERY (1<<14)
/* more readable IMHO */
#define MEM( x ) (*((u32 *)x))
#define MAKE32FROM8(X) (u32) (X | X << 8 | X << 16 | X << 24)
#define CHKMEM_ERR (-1)
#define CHKMEM_OK (0)
#if CHKMEM_DEBUG
# define SHOWFUNC() SerialOutputString("chkmem: method: "__FUNCTION__ "\n" ); \
SerialOutputString(" p1=0x"); \
SerialOutputHex((u32)bp1); \
SerialOutputString(" p2=0x"); \
SerialOutputHex((u32)bp2); \
SerialOutputString(" count=0x"); \
SerialOutputHex((u32)count); \
SerialOutputString("\n");
#else
# define SHOWFUNC() SerialOutputString("chkmem: method: "__FUNCTION__ "\n" );
#endif
#define SKIPBLOBMEM( STARTADR ) while ( STARTADR < (BLOB_RAM_BASE + 0x00100000) ) STARTADR++;
#define CHKMEM_MAXERR 64
#define CHKMEM_PUSHERR( ADR ) { chkmem_errlist[ chkmem_errs % CHKMEM_MAXERR ] = ADR; \
chkmem_errs++; }
/*********************************************************************/
/** MODULE GLOBALS *************************************************/
/*********************************************************************/
static u32 showevery;
/* list of failed adresses */
static u32 chkmem_errlist[ CHKMEM_MAXERR ];
static int chkmem_errs;
/*********************************************************************/
/** TYPES *********************************************************/
/*********************************************************************/
typedef int (*memtestfunc_t)( u32, u32, u32, u32 *);
/*********************************************************************/
/** FORWARDS *******************************************************/
/*********************************************************************/
static int ChkMemErr( void );
static int ChkMemMovInv( u32 start, u32 end, u32 pattern, u32 *badadr );
static int ChkMemAdrTst( u32 start, u32 end, u32 pattern, u32 *badadr );
static int ChkMemHardcore( u32 start, u32 end, u32 pattern, u32 *badadr );
static void showrun( u32 run );
static void showadr( volatile u32 *adr );
/* Charles Cazabon test methods */
static int test_or_comparison (u32 *bp1, u32 *bp2, u32 count);
static int test_and_comparison (u32 *bp1, u32 *bp2, u32 count);
static int test_seqinc_comparison (u32 *bp1, u32 *bp2, u32 count);
static int test_checkerboard_comparison (u32 *bp1, u32 *bp2, u32 count);
static int test_solidbits_comparison (u32 *bp1, u32 *bp2, u32 count);
static int test_blockseq_comparison (u32 *bp1, u32 *bp2, u32 count);
static int test_walkbits_comparison (u32 *bp1, u32 *bp2, u32 count, int mode);
static int test_bitspread_comparison (u32 *bp1, u32 *bp2, u32 count);
static int test_bitflip_comparison (u32 *bp1, u32 *bp2, u32 count);
static int test_stuck_address (u32 *bp1, u32 *bp2, u32 count);
/*********************************************************************/
/** EXPORTED FUNCTIONS ***********************************************/
/*********************************************************************/
/*********************************************************************
* ChkMem
*
* AUTOR: Stefan Eletzhofer
* REVISED:
*
* Command entry, memory test method dispatcher
*
*/
int ChkMem( int argc, char *argv[] )
{
memtestfunc_t method;
int area;
u32 start = 0L;
u32 end = 0L;
u32 badaddr = 0L;
u32 repcount = 0L;
/* check args */
if ( argc < 2 ) {
SerialOutputString("*** not enough arguments\n");
return CHKMEM_ERR;
}
/* reset error counter */
chkmem_errs = 0;
/* get verbosity level */
showevery = CHKMEM_SHOWEVERY;
if ( argc > 2 ) {
if(strtou32(argv[2], &showevery) < 0) {
SerialOutputString("*** not a value\n");
return CHKMEM_ERR;
}
if ( showevery > 0 ) {
showevery = 1<<showevery;
} else {
/* never show address */
showevery = 0xffffffff;
}
}
/* get repeat count */
repcount = 1;
if ( argc > 3 ) {
if ( strtou32(argv[3], &repcount ) < 0 ) {
SerialOutputString("*** not a value\n");
return CHKMEM_ERR;
}
}
SerialOutputString(argv[0]);
SerialOutputString(": display every 0x");
SerialOutputHex(showevery);
SerialOutputString(" bytes\n");
/* set memory test method */
switch ( *argv[1] ) {
case '0':
method = ChkMemMovInv;
break;
case '1':
method = ChkMemAdrTst;
break;
case '2':
method = ChkMemHardcore;
break;
default:
SerialOutputString("*** unknown method\n");
return CHKMEM_ERR;
break;
}
while ( repcount-- ) {
/* test all known memory areas */
for (area = 0; area < NUM_MEM_AREAS; area++) {
if(memory_map[area].used) {
start = memory_map[area].start;
end = start + memory_map[area].len;
if ( method(start, end, 0x5555aaaa, &badaddr) != CHKMEM_OK ) {
CHKMEM_PUSHERR( badaddr );
}
}
}
}
if ( chkmem_errs == 0 ) {
SerialOutputString("\n*** no error found\n");
} else {
ChkMemErr();
}
return CHKMEM_OK;
}
static char chkmemhelp[] = "chkmem [method] {verbosity:1..F} {repeat-count}\nmethod=0: move-inverse test\n"
"method=1: address test\n"
"method=2: hardcore test\n"
"verbosity: display every 2^n address during test\n";
__commandlist(ChkMem, "chkmem", chkmemhelp);
/*********************************************************************/
/** STATIC FUNCTIONS ************************************************/
/*********************************************************************/
/*********************************************************************
* showrun
*
* AUTOR: SELETZ
* REVISED:
*
* Shows current memory test run
*
*/
static void showrun( u32 run )
{
SerialOutputString( "\r\nrun " );
SerialOutputHex( run );
SerialOutputString( "\n" );
}
/*********************************************************************
* showadr
*
* AUTOR: SELETZ
* REVISED:
*
* display <adr> every <showevery> bytes.
*
*/
static void showadr( volatile u32 *adr )
{
if ( ((u32)adr) % showevery == 0 ) {
SerialOutputString("\r");
SerialOutputHex( (u32)adr );
}
}
/*********************************************************************
* ChkMemErr
*
* AUTOR: Stefan Eletzhofer
* REVISED:
*
* Reports memory check errors
*
*/
static int ChkMemErr( void )
{
int i;
SerialOutputString("\n*** memory errors:\n");
for ( i=0; i< chkmem_errs % CHKMEM_MAXERR; i++ ) {
SerialOutputHex( i );
SerialOutputString(": 0x");
SerialOutputHex(chkmem_errlist[i]);
SerialOutputString("\n");
}
return CHKMEM_OK;
}
/*********************************************************************
* ChkMemMovInv
*
* AUTOR: Stefan Eletzhofer
* REVISED:
*
* Moving-Inverse Memory Test
*
* Test method (from GNU/memtest86 utility):
* 1) Fill memory with a pattern
* 2) Starting at the lowest address
* 2a check that the pattern has not changed
* 2b write the patterns complement
* 2c increment the address
* repeat 2a - 2c
* 3) Starting at the highest address
* 3a check that the pattern has not changed
* 3b write the patterns complement
* 3c decrement the address
* repeat 3a - 3c
*
* returns 1 if memory failure, returns failed
* address in badadr
*
*/
static int ChkMemMovInv( u32 start, u32 end, u32 pattern, u32 *badadr )
{
int ret = 1;
register u32 p;
register u32 tst;
SerialOutputString("\nchkmem: move-inverse method\n");
SKIPBLOBMEM( start );
#if CHKMEM_DEBUG
SerialOutputString("ChkMem: start(0x");
SerialOutputHex(start);
SerialOutputString(") - end(0x");
SerialOutputHex(end);
SerialOutputString(")\n");
#endif
#if CHKMEM_DEBUG
SerialOutputString("ChkMem: fillup\n");
#endif
/* fill mem with pattern */
p=start;
while ( p<end ) {
MEM( p ) = pattern;
barrier();
p += 4;
}
#if CHKMEM_DEBUG
SerialOutputString("\rChkMem: bottom-up\n");
#endif
/* bottom-up test */
p=start;
while ( p<end ) {
showadr( (u32*)p );
tst = MEM( p );
if ( tst != pattern ) {
goto DONE;
}
MEM( p ) = ~pattern;
barrier();
p += 4;
}
pattern = ~pattern;
#if CHKMEM_DEBUG
SerialOutputString("\rChkMem: top-down\n");
#endif
/* top-down test */
p=end-4;
while ( p>=start ) {
showadr( (u32*)p );
tst = MEM( p );
if ( tst != pattern ) {
goto DONE;
}
MEM( p ) = ~pattern;
barrier();
p -= 4;
}
/* no error if we reach this point */
ret = 0;
DONE:
if ( ret != 0 && badadr ) {
*badadr = p;
}
return ret;
}
/*********************************************************************
* ChkMemAdrTst
*
* AUTOR: Stefan Eletzhofer
* REVISED:
*
* Writes every memory location with its adress, then checks address
*
* returns 1 if memory failure, returns failed
* address in badadr
*
*/
static int ChkMemAdrTst( u32 start, u32 end, u32 pattern, u32 *badadr )
{
int ret = 1;
register u32 p;
register u32 tst;
SerialOutputString("\nchkmem: address test method\n");
SKIPBLOBMEM( start );
#if CHKMEM_DEBUG
SerialOutputString("ChkMem: start(0x");
SerialOutputHex(start);
SerialOutputString(") - end(0x");
SerialOutputHex(end);
SerialOutputString(")\n");
#endif
#if CHKMEM_DEBUG
SerialOutputString("ChkMem: fillup\n");
#endif
/* fill mem with pattern */
p=start;
while ( p<end ) {
MEM( p ) = p;
barrier();
p += 4;
}
#if CHKMEM_DEBUG
SerialOutputString("\rChkMem: bottom-up\n");
#endif
/* bottom-up test */
p=start;
while ( p<end ) {
showadr( (u32*)p );
tst = MEM( p );
if ( tst != p ) {
goto DONE;
}
p += 4;
}
/* no error if we reach this point */
ret = 0;
DONE:
if ( ret != 0 && badadr ) {
*badadr = p;
}
return ret;
}
/*********************************************************************
* ChkMemHardcore
*
* AUTOR: Stefan Eletzhofer
* REVISED:
*
* Hardcore memory test. Test methods based on memtest
* by Charles Cazabon <memtest@discworld.dyndns.org>
*
* returns 1 if memory failure, returns failed
* address in badadr
*
*/
static int ChkMemHardcore( u32 start, u32 end, u32 pattern, u32 *badadr )
{
register u32 count;
SerialOutputString("\nchkmem: hardcore test method\n");
SKIPBLOBMEM( start );
#if CHKMEM_DEBUG
SerialOutputString("ChkMem: start(0x");
SerialOutputHex(start);
SerialOutputString(") - end(0x");
SerialOutputHex(end);
SerialOutputString(")\n");
#endif
count = end - start;
SerialOutputHex(count);
SerialOutputString("\n");
count = (count >> 1);
SerialOutputHex(count);
SerialOutputString("\n");
test_or_comparison((u32 *)start, (u32 *)(start+count), count>>2);
test_and_comparison((u32 *)start, (u32 *)(start+count), count>>2);
test_seqinc_comparison((u32 *)start, (u32 *)(start+count), count>>2);
test_checkerboard_comparison ((u32 *)start, (u32 *)(start+count), count>>2);
test_solidbits_comparison((u32 *)start, (u32 *)(start+count), count>>2);
test_blockseq_comparison((u32 *)start, (u32 *)(start+count), count>>2);
test_walkbits_comparison((u32 *)start, (u32 *)(start+count), count>>2, 0);
test_walkbits_comparison((u32 *)start, (u32 *)(start+count), count>>2, 1);
test_bitspread_comparison((u32 *)start, (u32 *)(start+count), count>>2);
test_bitflip_comparison((u32 *)start, (u32 *)(start+count), count>>2);
test_stuck_address((u32 *)start, (u32 *)(start+count), count>>2);
/* no error if we reach this point */
if ( badadr ) {
*badadr = 0L;
}
return 0;
}
/*********************************************************************/
/** MEMTESTER FUNCTIONS *********************************************/
/*********************************************************************/
/**********************************************************************
* Original Authors of following memory test functions:
*
* Charles Cazabon <memtest@discworld.dyndns.org>
*
* Copyright
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -