summaryrefslogtreecommitdiff
path: root/libnandfs/correctauxilliary.c
diff options
context:
space:
mode:
Diffstat (limited to 'libnandfs/correctauxilliary.c')
-rw-r--r--libnandfs/correctauxilliary.c81
1 files changed, 81 insertions, 0 deletions
diff --git a/libnandfs/correctauxilliary.c b/libnandfs/correctauxilliary.c
new file mode 100644
index 00000000..510aeac4
--- /dev/null
+++ b/libnandfs/correctauxilliary.c
@@ -0,0 +1,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;
+}