summaryrefslogtreecommitdiff
path: root/libnandfs/correctauxilliary.c
blob: 510aeac42b67dfc26e8f85825728aa9338766398 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include "lib9.h"
#include "logfs.h"
#include "nandfs.h"
#include "local.h"

static int
hammingdistance(uchar a, uchar b)
{
	uchar c;
	int i, k;
	if (a == b)
		return 0;
	c =  a ^ b;
	for (i = 0x80, k = 0; i; i >>= 1)
		if (c & i)
			k++;
	return k;
}

static int
allones(uchar *data, int len)
{
	while (len-- > 0)
		if (*data++ != 0xff)
			return 0;
	return 1;
}

LogfsLowLevelReadResult
_nandfscorrectauxiliary(NandfsAuxiliary *hdr)
{
	/*
	 * correct single bit errors, detect more than 1, in
	 * tag, signature
	 * TODO: add nerase and path protection
	 */
	LogfsLowLevelReadResult e;
	int x;
	int min, minx;

	e = LogfsLowLevelReadResultOk;
	
	min = 8;
	minx = 0;
	for (x = 0; x < _nandfsvalidtagscount; x++) {
		int d = hammingdistance(hdr->tag, _nandfsvalidtags[x]);
		if (d < min) {
			min = d;
			minx = x;
			if (d == 0)
				break;
		}
	}
	if (min == 1) {
		hdr->tag = _nandfsvalidtags[minx];
		e = LogfsLowLevelReadResultSoftError;
	}
	else if (min > 1)
		e = LogfsLowLevelReadResultHardError;
	else {
		if (hdr->tag != LogfsTnone) {
			ulong tmp = getbig4(hdr->parth);
			if (tmp != 0xfffffffff && _nandfshamming31_26correct(&tmp)) {
				putbig4(hdr->parth, tmp);
				if (e != LogfsLowLevelReadResultOk)	
					e = LogfsLowLevelReadResultSoftError;
			}
			tmp = (getbig2(hdr->nerasemagicmsw) << 16) | getbig2(hdr->nerasemagiclsw);
			if (tmp != 0xffffffff && _nandfshamming31_26correct(&tmp)) {
				putbig2(hdr->nerasemagicmsw, tmp >> 16);
				putbig2(hdr->nerasemagiclsw, tmp);
				if (e != LogfsLowLevelReadResultOk)	
					e = LogfsLowLevelReadResultSoftError;
			}
		}
		else if (allones((uchar *)hdr, sizeof(*hdr)))
			e = LogfsLowLevelReadResultAllOnes;
	}
			
	return e;
}