/* Pattern extension for memtest86 * * Generates patterns for the Linux kernel's BadRAM extension that avoids * allocation of faulty pages. * * Released under version 2 of the Gnu Public License. * * By Rick van Rein, vanrein@zonnet.nl * ---------------------------------------------------- * 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" /* * DEFAULT_MASK covers a longword, since that is the testing granularity. */ #define DEFAULT_MASK ((~0L) << 2) /* extern struct vars *v; */ /* What it does: * - Keep track of a number of BadRAM patterns in an array; * - Combine new faulty addresses with it whenever possible; * - Keep masks as selective as possible by minimising resulting faults; * - Print a new pattern only when the pattern array is changed. */ #define COMBINE_MASK(a,b,c,d) ((a & b & c & d) | (~a & b & ~c & d)) /* Combine two adr/mask pairs to one adr/mask pair. */ void combine (ulong adr1, ulong mask1, ulong adr2, ulong mask2, ulong *adr, ulong *mask) { *mask = COMBINE_MASK (adr1, mask1, adr2, mask2); *adr = adr1 | adr2; *adr &= *mask; // Normalise, no fundamental need for this } /* Count the number of addresses covered with a mask. */ ulong addresses (ulong mask) { ulong ctr=1; int i=32; while (i-- > 0) { if (! (mask & 1)) { ctr += ctr; } mask >>= 1; } return ctr; } /* Count how much more addresses would be covered by adr1/mask1 when combined * with adr2/mask2. */ ulong combicost (ulong adr1, ulong mask1, ulong adr2, ulong mask2) { ulong cost1=addresses (mask1); ulong tmp, mask; combine (adr1, mask1, adr2, mask2, &tmp, &mask); return addresses (mask) - cost1; } /* Find the cheapest array index to extend with the given adr/mask pair. * Return -1 if nothing below the given minimum cost can be found. */ int cheapindex (ulong adr1, ulong mask1, ulong mincost) { int i=v->numpatn; int idx=-1; while (i-- > 0) { ulong tmpcost=combicost(v->patn[i].adr, v->patn[i].mask, adr1, mask1); if (tmpcost < mincost) { mincost=tmpcost; idx=i; } } return idx; } /* Try to find a relocation index for idx if it costs nothing. * Return -1 if no such index exists. */ int relocateidx (int idx) { ulong adr =v->patn[idx].adr; ulong mask=v->patn[idx].mask; int new; v->patn[idx].adr ^= ~0L; // Never select idx new=cheapindex (adr, mask, 1+addresses (mask)); v->patn[idx].adr = adr; return new; } /* Relocate the given index idx only if free of charge. * This is useful to combine to `neighbouring' sections to integrate. * Inspired on the Buddy memalloc principle in the Linux kernel. */ void relocateiffree (int idx) { int newidx=relocateidx (idx); if (newidx>=0) { ulong cadr, cmask; combine (v->patn [newidx].adr, v->patn[newidx].mask, v->patn [ idx].adr, v->patn[ idx].mask, &cadr, &cmask); v->patn[newidx].adr =cadr; v->patn[newidx].mask=cmask; if (idx < --v->numpatn) { v->patn[idx].adr =v->patn[v->numpatn].adr; v->patn[idx].mask=v->patn[v->numpatn].mask; } relocateiffree (newidx); } } /* Insert a single faulty address in the pattern array. * Return 1 only if the array was changed. */ int insertaddress (ulong adr) { if (cheapindex (adr, DEFAULT_MASK, 1L) != -1) return 0; if (v->numpatn < BADRAM_MAXPATNS) { v->patn[v->numpatn].adr =adr; v->patn[v->numpatn].mask=DEFAULT_MASK; v->numpatn++; relocateiffree (v->numpatn-1); } else { int idx=cheapindex (adr, DEFAULT_MASK, ~0L); ulong cadr, cmask; combine (v->patn [idx].adr, v->patn[idx].mask, adr, DEFAULT_MASK, &cadr, &cmask); v->patn[idx].adr =cadr; v->patn[idx].mask=cmask; relocateiffree (idx); } return 1; }