⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chkmem.c

📁 LUBBOCK板的BLOB
💻 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 + -