From: Erik M. <er...@us...> - 2001-09-27 21:35:48
|
Update of /cvsroot/blob/blob/src In directory usw-pr-cvs1:/tmp/cvs-serv4652 Modified Files: chkmem.c Log Message: Stefan's memory checker Index: chkmem.c =================================================================== RCS file: /cvsroot/blob/blob/src/chkmem.c,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- chkmem.c 2001/09/27 21:32:31 1.1 +++ chkmem.c 2001/09/27 21:35:45 1.2 @@ -0,0 +1,457 @@ +/*------------------------------------------------------------------------- + * Filename: chkmem.c + * Version: $Id$ + * Copyright: Copyright (C) 2001, Stefan Eletzhofer + * Author: Stefan Eletzhofer <ste...@ww...> + * 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 <ste...@ww...> + * + * 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$" + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "command.h" +#include "types.h" +#include "sa1100.h" +#include "serial.h" +#include "time.h" +#include "util.h" + +#include "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)) + +/* Optimization barrier */ +/* The "volatile" is due to gcc bugs */ +#define barrier() __asm__ __volatile__("": : :"memory") + + +/*********************************************************************/ +/** MODULE GLOBALS *************************************************/ +/*********************************************************************/ + +static u32 showevery; + +/*********************************************************************/ +/** TYPES *********************************************************/ +/*********************************************************************/ + +typedef int (*memtestfunc_t)( u32, u32, u32, u32 *); + +/*********************************************************************/ +/** FORWARDS *******************************************************/ +/*********************************************************************/ + +static int ChkMemErr( u32 start, u32 end, u32 badaddr ); +static int ChkMemMovInv( u32 start, u32 end, u32 pattern, u32 *badadr ); +static int ChkMemAdrTst( u32 start, u32 end, u32 pattern, u32 *badadr ); + +/*********************************************************************/ +/** EXPORTED FUNCTIONS ***********************************************/ +/*********************************************************************/ + +/********************************************************************* + * ChkMem + * + * AUTOR: Stefan Eletzhofer + * REVISED: + * + * Command entry, memory test method dispatcher + * + */ +static int ChkMem( int argc, char *argv[] ) +{ + memtestfunc_t method; + int area; + u32 start; + u32 end; + u32 badaddr; + + /* check args */ + if ( argc < 2 ) { + SerialOutputString("*** not enough arguments\n"); + return -1; + } + + showevery = CHKMEM_SHOWEVERY; + + if ( argc > 2 ) { + if(strtoval(argv[2], &showevery) < 0) { + SerialOutputString("*** not a value\n"); + return -1; + } + + showevery = 1<<showevery; + } + + /* FIXME: should check if showevery is a sane value! */ + 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': + //break; + default: + SerialOutputString("*** unknown method\n"); + return -1; + break; + } + + /* 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; + + /* skip first mb */ + if ( memory_map[area].start == 0xc0000000 ) { + start += 0x100000; + } + + if(! method(start, end, 0x5555aaaa, &badaddr)) { + ChkMemErr( start, end, badaddr ); + return -1; + } + } + } + + return 0; +} +static char chkmemhelp[] = "chkmem [method] {verbosity:1..F}\nmethod=0: move-inverse test\n" +"method=1: address test\n" +"method=2: modulo-x test\n" +"verbosity: display every 2^n address during test\n"; +__commandlist(ChkMem, "chkmem", chkmemhelp); + + +/********************************************************************* + * Poke + * + * AUTOR: Stefan Eletzhofer + * REVISED: + * + * Poke values to memory + * + */ +static int Poke( int argc, char *argv[] ) +{ + u32 address; + u32 value; + + if ( argc < 3 ) { + SerialOutputString("*** not enough arguments\n"); + return -1; + } + + if(strtoval(argv[1], &address) < 0) { + SerialOutputString("*** not an address\n"); + return -1; + } + + if(strtoval(argv[2], &value) < 0) { + SerialOutputString("*** not a value\n"); + return -1; + } + + +#if CHKMEM_DEBUG + SerialOutputString("adr=0x"); + SerialOutputHex(address); + SerialOutputString(" val=0x"); + SerialOutputHex(value); + SerialOutputString("\n"); +#endif + + MEM( address ) = value; + + return 0; +} +static char pokehelp[] = "poke address value\n"; +__commandlist(Poke, "poke", pokehelp ); + +/********************************************************************* + * Peek + * + * AUTOR: Stefan Eletzhofer + * REVISED: + * + * Poke values to memory + * + */ +static int Peek( int argc, char *argv[] ) +{ + u32 address; + u32 value; + + if ( argc < 2 ) { + SerialOutputString("*** not enough arguments\n"); + return -1; + } + + if(strtoval(argv[1], &address) < 0) { + SerialOutputString("*** not an address\n"); + return -1; + } + +#if CHKMEM_DEBUG + SerialOutputString("adr=0x"); + SerialOutputHex(address); + SerialOutputString("\n"); +#endif + + value = MEM( address ); + + SerialOutputHex(value); + SerialOutputString("\n"); + + return 0; +} +static char peekhelp[] = "peek address\n"; +__commandlist(Peek, "peek", peekhelp ); + + +/*********************************************************************/ +/** STATIC FUNCTIONS ************************************************/ +/*********************************************************************/ + +/********************************************************************* + * ChkMemErr + * + * AUTOR: Stefan Eletzhofer + * REVISED: + * + * Reports memory check errors + * + */ +static int ChkMemErr( u32 start, u32 end, u32 badaddr ) +{ + SerialOutputString("*** memory error 0x"); + SerialOutputHex(start); + SerialOutputString("-0x"); + SerialOutputHex(end); + SerialOutputString(": addr: 0x"); + SerialOutputHex(badaddr); + SerialOutputString("\n"); + + return 0; +} + +/********************************************************************* + * 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("ChkMem: move-inverse method\n"); + +#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 ) { + if ( p % showevery == 0 ) { + SerialOutputString("\r"); + SerialOutputHex(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 ) { + if ( p % showevery == 0 ) { + SerialOutputString("\r"); + SerialOutputHex(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("ChkMem: address test method\n"); + +#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 ) { + if ( p % showevery == 0 ) { + SerialOutputString("\r"); + SerialOutputHex(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; +} |