blob: 2e35a38114e88b9b4da94e18e257b1f7fdcc4fca [file] [log] [blame]
/* 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+ V1.60 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;
}