summaryrefslogtreecommitdiffstats
path: root/error.c
diff options
context:
space:
mode:
Diffstat (limited to 'error.c')
-rw-r--r--error.c547
1 files changed, 547 insertions, 0 deletions
diff --git a/error.c b/error.c
new file mode 100644
index 0000000..cacef7e
--- /dev/null
+++ b/error.c
@@ -0,0 +1,547 @@
+
+/* error.c - MemTest-86 Version 3.4
+ *
+ * Released under version 2 of the Gnu Public License.
+ * By Chris Brady, cbrady@sgi.com
+ * ----------------------------------------------------
+ * MemTest86+ V2.00 Specific code (GPL V2.0)
+ * By Samuel DEMEULEMEESTER, sdemeule@memtest.org
+ * http://www.x86-secret.com - http://www.memtest.org
+ */
+
+#include "test.h"
+#include "config.h"
+#include <sys/io.h>
+#include "dmi.h"
+
+extern int test_ticks, nticks, beepmode;
+extern struct tseq tseq[];
+extern int dmi_err_cnts[MAX_DMI_MEMDEVS];
+extern short dmi_initialized;
+void poll_errors();
+
+static void update_err_counts(void);
+static void print_err_counts(void);
+static void common_err();
+static int syn, chan, len=1;
+
+/*
+ * Display data error message. Don't display duplicate errors.
+ */
+void error(ulong *adr, ulong good, ulong bad)
+{
+ ulong xor;
+
+ xor = good ^ bad;
+#ifdef USB_WAR
+ /* Skip any errrors that appear to be due to the BIOS using location
+ * 0x4e0 for USB keyboard support. This often happens with Intel
+ * 810, 815 and 820 chipsets. It is possible that we will skip
+ * a real error but the odds are very low.
+ */
+ if ((ulong)adr == 0x4e0 || (ulong)adr == 0x410) {
+ return;
+ }
+#endif
+ common_err(adr, good, bad, xor, 0);
+}
+
+/*
+ * Display address error message.
+ * Since this is strictly an address test, trying to create BadRAM
+ * patterns does not make sense. Just report the error.
+ */
+void ad_err1(ulong *adr1, ulong *mask, ulong bad, ulong good)
+{
+ common_err(adr1, good, bad, (ulong)mask, 1);
+}
+
+/*
+ * Display address error message.
+ * Since this type of address error can also report data errors go
+ * ahead and generate BadRAM patterns.
+ */
+void ad_err2(ulong *adr, ulong bad)
+{
+ common_err(adr, (ulong)adr, bad, ((ulong)adr) ^ bad, 0);
+}
+
+static void update_err_counts(void)
+{
+ if (beepmode){
+ beep(600);
+ beep(1000);
+ }
+
+ if (v->pass && v->ecount == 0) {
+ cprint(LINE_MSG, COL_MSG,
+ " ");
+ }
+ ++(v->ecount);
+ tseq[v->test].errors++;
+
+}
+
+static void print_err_counts(void)
+{
+ int i;
+ char *pp;
+
+ if ((v->ecount > 4096) && (v->ecount % 256 != 0)) return;
+
+ dprint(LINE_INFO, COL_ERR, v->ecount, 6, 0);
+ dprint(LINE_INFO, COL_ECC_ERR, v->ecc_ecount, 6, 0);
+
+ /* Paint the error messages on the screen red to provide a vivid */
+ /* indicator that an error has occured */
+ if ((v->printmode == PRINTMODE_ADDRESSES ||
+ v->printmode == PRINTMODE_PATTERNS) &&
+ v->msg_line < 24) {
+ for(i=0, pp=(char *)((SCREEN_ADR+v->msg_line*160+1));
+ i<76; i++, pp+=2) {
+ *pp = 0x47;
+ }
+ }
+}
+
+/*
+ * Print an individual error
+ */
+void common_err( ulong *adr, ulong good, ulong bad, ulong xor, int type)
+{
+ int i, n, x, j, flag=0;
+ ulong page, offset;
+ int patnchg;
+ ulong mb;
+
+ update_err_counts();
+ add_dmi_err((ulong)adr);
+
+ switch(v->printmode) {
+ case PRINTMODE_SUMMARY:
+ /* Don't do anything for a parity error. */
+ if (type == 3) {
+ return;
+ }
+
+ /* Address error */
+ if (type == 1) {
+ xor = good ^ bad;
+ }
+
+ /* Ecc correctable errors */
+ if (type == 2) {
+ /* the bad value is the corrected flag */
+ if (bad) {
+ v->erri.cor_err++;
+ }
+ page = (ulong)adr;
+ offset = good;
+ } else {
+ page = page_of(adr);
+ offset = (ulong)adr & 0xFFF;
+ }
+
+ /* Calc upper and lower error addresses */
+ if (v->erri.low_addr.page > page) {
+ v->erri.low_addr.page = page;
+ v->erri.low_addr.offset = offset;
+ flag++;
+ } else if (v->erri.low_addr.page == page &&
+ v->erri.low_addr.offset > offset) {
+ v->erri.low_addr.offset = offset;
+ v->erri.high_addr.offset = offset;
+ flag++;
+ } else if (v->erri.high_addr.page < page) {
+ v->erri.high_addr.page = page;
+ flag++;
+ }
+ if (v->erri.high_addr.page == page &&
+ v->erri.high_addr.offset < offset) {
+ v->erri.high_addr.offset = offset;
+ flag++;
+ }
+
+ /* Calc bits in error */
+ for (i=0, n=0; i<32; i++) {
+ if (xor>>i & 1) {
+ n++;
+ }
+ }
+ v->erri.tbits += n;
+ if (n > v->erri.max_bits) {
+ v->erri.max_bits = n;
+ flag++;
+ }
+ if (n < v->erri.min_bits) {
+ v->erri.min_bits = n;
+ flag++;
+ }
+ if (v->erri.ebits ^ xor) {
+ flag++;
+ }
+ v->erri.ebits |= xor;
+
+ /* Calc max contig errors */
+ len = 1;
+ if ((ulong)adr == (ulong)v->erri.eadr+4 ||
+ (ulong)adr == (ulong)v->erri.eadr-4 ) {
+ len++;
+ }
+ if (len > v->erri.maxl) {
+ v->erri.maxl = len;
+ flag++;
+ }
+ v->erri.eadr = (ulong)adr;
+
+ if (v->erri.hdr_flag == 0) {
+ clear_scroll();
+ cprint(LINE_HEADER+0, 1, "Error Confidence Value:");
+ cprint(LINE_HEADER+1, 1, " Lowest Error Address:");
+ cprint(LINE_HEADER+2, 1, " Highest Error Address:");
+ cprint(LINE_HEADER+3, 1, " Bits in Error Mask:");
+ cprint(LINE_HEADER+4, 1, " Bits in Error - Total:");
+ cprint(LINE_HEADER+4, 29, "Min: Max: Avg:");
+ cprint(LINE_HEADER+5, 1, " Max Contiguous Errors:");
+ cprint(LINE_HEADER+6, 1, "ECC Correctable Errors:");
+ cprint(LINE_HEADER+7, 1, "Errors per Memory Slot:");
+ x = 24;
+ if (dmi_initialized) {
+ for ( i=0; i < MAX_DMI_MEMDEVS;){
+ n = LINE_HEADER+7;
+ for (j=0; j<4; j++) {
+ if (dmi_err_cnts[i] >= 0) {
+ dprint(n, x, i, 2, 0);
+ cprint(n, x+2, ": 0");
+ }
+ i++;
+ n++;
+ }
+ x += 10;
+ }
+ }
+
+ cprint(LINE_HEADER+0, 64, "Test Errors");
+ v->erri.hdr_flag++;
+ }
+ if (flag) {
+ /* Calc bits in error */
+ for (i=0, n=0; i<32; i++) {
+ if (v->erri.ebits>>i & 1) {
+ n++;
+ }
+ }
+ page = v->erri.low_addr.page;
+ offset = v->erri.low_addr.offset;
+ mb = page >> 8;
+ hprint(LINE_HEADER+1, 25, page);
+ hprint2(LINE_HEADER+1, 33, offset, 3);
+ cprint(LINE_HEADER+1, 36, " - . MB");
+ dprint(LINE_HEADER+1, 39, mb, 5, 0);
+ dprint(LINE_HEADER+1, 45, ((page & 0xF)*10)/16, 1, 0);
+ page = v->erri.high_addr.page;
+ offset = v->erri.high_addr.offset;
+ mb = page >> 8;
+ hprint(LINE_HEADER+2, 25, page);
+ hprint2(LINE_HEADER+2, 33, offset, 3);
+ cprint(LINE_HEADER+2, 36, " - . MB");
+ dprint(LINE_HEADER+2, 39, mb, 5, 0);
+ dprint(LINE_HEADER+2, 45, ((page & 0xF)*10)/16, 1, 0);
+ hprint(LINE_HEADER+3, 25, v->erri.ebits);
+ dprint(LINE_HEADER+4, 25, n, 2, 1);
+ dprint(LINE_HEADER+4, 34, v->erri.min_bits, 2, 1);
+ dprint(LINE_HEADER+4, 42, v->erri.max_bits, 2, 1);
+ dprint(LINE_HEADER+4, 50, v->erri.tbits/v->ecount, 2, 1);
+ dprint(LINE_HEADER+5, 25, v->erri.maxl, 7, 1);
+ x = 28;
+ for ( i=0; i < MAX_DMI_MEMDEVS;){
+ n = LINE_HEADER+7;
+ for (j=0; j<4; j++) {
+ if (dmi_err_cnts[i] > 0) {
+ dprint (n, x, dmi_err_cnts[i], 7, 1);
+ }
+ i++;
+ n++;
+ }
+ x += 10;
+ }
+
+ for (i=0; tseq[i].msg != NULL; i++) {
+ dprint(LINE_HEADER+1+i, 66, i, 2, 0);
+ dprint(LINE_HEADER+1+i, 68, tseq[i].errors, 8, 0);
+ }
+ }
+ if (v->erri.cor_err) {
+ dprint(LINE_HEADER+6, 25, v->erri.cor_err, 8, 1);
+ }
+ break;
+
+ case PRINTMODE_ADDRESSES:
+ /* Don't display duplicate errors */
+ if ((ulong)adr == (ulong)v->erri.eadr &&
+ xor == v->erri.exor) {
+ return;
+ }
+ if (v->erri.hdr_flag == 0) {
+ clear_scroll();
+ cprint(LINE_HEADER, 0,
+"Tst Pass Failing Address Good Bad Err-Bits Count Chan");
+ cprint(LINE_HEADER+1, 0,
+"--- ---- ----------------------- -------- -------- -------- ----- ----");
+ v->erri.hdr_flag++;
+ }
+ /* Check for keyboard input */
+ check_input();
+ scroll();
+
+ if ( type == 2 || type == 3) {
+ page = (ulong)adr;
+ offset = good;
+ } else {
+ page = page_of(adr);
+ offset = ((unsigned long)adr) & 0xFFF;
+ }
+ mb = page >> 8;
+ dprint(v->msg_line, 0, v->test, 3, 0);
+ dprint(v->msg_line, 4, v->pass, 5, 0);
+ hprint(v->msg_line, 11, page);
+ hprint2(v->msg_line, 19, offset, 3);
+ cprint(v->msg_line, 22, " - . MB");
+ dprint(v->msg_line, 25, mb, 5, 0);
+ dprint(v->msg_line, 31, ((page & 0xF)*10)/16, 1, 0);
+
+ if (type == 3) {
+ /* ECC error */
+ cprint(v->msg_line, 36,
+ bad?"corrected ": "uncorrected ");
+ hprint2(v->msg_line, 60, syn, 4);
+ cprint(v->msg_line, 68, "ECC");
+ dprint(v->msg_line, 74, chan, 2, 0);
+ } else if (type == 2) {
+ cprint(v->msg_line, 36, "Parity error detected ");
+ } else {
+ hprint(v->msg_line, 36, good);
+ hprint(v->msg_line, 46, bad);
+ hprint(v->msg_line, 56, xor);
+ dprint(v->msg_line, 66, v->ecount, 5, 0);
+ v->erri.exor = xor;
+ }
+ v->erri.eadr = (ulong)adr;
+ print_err_counts();
+ break;
+
+ case PRINTMODE_PATTERNS:
+ if (v->erri.hdr_flag == 0) {
+ clear_scroll();
+ v->erri.hdr_flag++;
+ }
+ /* Do not do badram patterns from test 0 or 5 */
+ if (v->test == 0 || v->test == 5) {
+ return;
+ }
+ /* Only do patterns for data errors */
+ if ( type != 0) {
+ return;
+ }
+ /* Process the address in the pattern administration */
+ patnchg=insertaddress ((ulong) adr);
+ if (patnchg) {
+ printpatn();
+ }
+ break;
+
+ case PRINTMODE_NONE:
+ if (v->erri.hdr_flag == 0) {
+ clear_scroll();
+ v->erri.hdr_flag++;
+ }
+ break;
+ }
+}
+
+/*
+ * Print an ecc error
+ */
+void print_ecc_err(unsigned long page, unsigned long offset,
+ int corrected, unsigned short syndrome, int channel)
+{
+ ++(v->ecc_ecount);
+ syn = syndrome;
+ chan = channel;
+ common_err((ulong *)page, offset, corrected, 0, 2);
+}
+
+#ifdef PARITY_MEM
+/*
+ * Print a parity error message
+ */
+void parity_err( unsigned long edi, unsigned long esi)
+{
+ unsigned long addr;
+
+ if (v->test == 5) {
+ addr = esi;
+ } else {
+ addr = edi;
+ }
+ common_err((ulong *)addr, addr & 0xFFF, 0, 0, 3);
+}
+#endif
+
+/*
+ * Print the pattern array as a LILO boot option addressing BadRAM support.
+ */
+void printpatn (void)
+{
+ int idx=0;
+ int x;
+
+ /* Check for keyboard input */
+ check_input();
+
+ if (v->numpatn == 0)
+ return;
+
+ scroll();
+
+ cprint (v->msg_line, 0, "badram=");
+ x=7;
+
+ for (idx = 0; idx < v->numpatn; idx++) {
+
+ if (x > 80-22) {
+ scroll();
+ x=7;
+ }
+ cprint (v->msg_line, x, "0x");
+ hprint (v->msg_line, x+2, v->patn[idx].adr );
+ cprint (v->msg_line, x+10, ",0x");
+ hprint (v->msg_line, x+13, v->patn[idx].mask);
+ if (idx+1 < v->numpatn)
+ cprint (v->msg_line, x+21, ",");
+ x+=22;
+ }
+}
+
+/*
+ * Show progress by displaying elapsed time and update bar graphs
+ */
+void do_tick(void)
+{
+ int i, n, pct;
+ ulong h, l, t;
+
+ /* FIXME only print serial error messages from the tick handler */
+ if (v->ecount) {
+ print_err_counts();
+ }
+
+ nticks++;
+ v->total_ticks++;
+
+ pct = 100*nticks/test_ticks;
+ dprint(1, COL_MID+4, pct, 3, 0);
+ i = (BAR_SIZE * pct) / 100;
+ while (i > v->tptr) {
+ if (v->tptr >= BAR_SIZE) {
+ break;
+ }
+ cprint(1, COL_MID+9+v->tptr, "#");
+ v->tptr++;
+ }
+
+ pct = 100*v->total_ticks/v->pass_ticks;
+ dprint(0, COL_MID+4, pct, 3, 0);
+ i = (BAR_SIZE * pct) / 100;
+ while (i > v->pptr) {
+ if (v->pptr >= BAR_SIZE) {
+ break;
+ }
+ cprint(0, COL_MID+9+v->pptr, "#");
+ v->pptr++;
+ }
+
+ if (v->ecount && v->printmode == PRINTMODE_SUMMARY) {
+ /* Compute confidence score */
+ pct = 0;
+
+ /* If there are no errors within 1mb of start - end addresses */
+ h = v->pmap[v->msegs - 1].end - 0x100;
+ if (v->erri.low_addr.page > 0x100 &&
+ v->erri.high_addr.page < h) {
+ pct += 8;
+ }
+
+ /* Errors for only some tests */
+ if (v->pass) {
+ for (i=0, n=0; tseq[i].msg != NULL; i++) {
+ if (tseq[i].errors == 0) {
+ n++;
+ }
+ }
+ pct += n*3;
+ } else {
+ for (i=0, n=0; i<v->test; i++) {
+ if (tseq[i].errors == 0) {
+ n++;
+ }
+ }
+ pct += n*2;
+
+ }
+
+ /* Only some bits in error */
+ n = 0;
+ if (v->erri.ebits & 0xf) n++;
+ if (v->erri.ebits & 0xf0) n++;
+ if (v->erri.ebits & 0xf00) n++;
+ if (v->erri.ebits & 0xf000) n++;
+ if (v->erri.ebits & 0xf0000) n++;
+ if (v->erri.ebits & 0xf00000) n++;
+ if (v->erri.ebits & 0xf000000) n++;
+ if (v->erri.ebits & 0xf0000000) n++;
+ pct += (8-n)*2;
+
+ /* Adjust the score */
+ pct = pct*100/22;
+/*
+ if (pct > 100) {
+ pct = 100;
+ }
+*/
+ dprint(LINE_HEADER+0, 25, pct, 3, 1);
+ }
+
+
+ /* We can't do the elapsed time unless the rdtsc instruction
+ * is supported
+ */
+ if (v->rdtsc) {
+ asm __volatile__(
+ "rdtsc":"=a" (l),"=d" (h));
+ asm __volatile__ (
+ "subl %2,%0\n\t"
+ "sbbl %3,%1"
+ :"=a" (l), "=d" (h)
+ :"g" (v->startl), "g" (v->starth),
+ "0" (l), "1" (h));
+ t = h * ((unsigned)0xffffffff / v->clks_msec) / 1000;
+ t += (l / v->clks_msec) / 1000;
+ i = t % 60;
+ dprint(LINE_TIME, COL_TIME+9, i%10, 1, 0);
+ dprint(LINE_TIME, COL_TIME+8, i/10, 1, 0);
+ t /= 60;
+ i = t % 60;
+ dprint(LINE_TIME, COL_TIME+6, i % 10, 1, 0);
+ dprint(LINE_TIME, COL_TIME+5, i / 10, 1, 0);
+ t /= 60;
+ dprint(LINE_TIME, COL_TIME, t, 4, 0);
+ }
+
+
+ /* Check for keyboard input */
+ check_input();
+
+ /* Poll for ECC errors */
+ poll_errors();
+}