Date: Wed, 13 Nov 2013 23:32:38 +0100 From: kristof@sigsegv.be To: Ian Lepore <ian@FreeBSD.org> Cc: Grzegorz Bernacki <gber@FreeBSD.org>, freebsd-embedded@FreeBSD.org Subject: [PATCH 3/5] Check ONFI parameter page before using it. Message-ID: <1384381960-98851-4-git-send-email-kristof@sigsegv.be> In-Reply-To: <1384381960-98851-1-git-send-email-kristof@sigsegv.be> References: <1383782353.31172.183.camel@revolution.hippie.lan> <1384381960-98851-1-git-send-email-kristof@sigsegv.be>
index | next in thread | previous in thread | raw e-mail
From: Kristof Provost <kristof@sigsegv.be>
The ONFI spec states that at least two bytes of the signature ("ONFI") must be
present, and the CRC must be correct to have a valid parameter page.
If the page is not valid there are at least two backup pages where the data can
also be found.
---
sys/dev/nand/nand_generic.c | 55 ++++++++++++++++++++++++++++++++++++-------
1 file changed, 46 insertions(+), 9 deletions(-)
diff --git a/sys/dev/nand/nand_generic.c b/sys/dev/nand/nand_generic.c
index 2e78ab6..4ee8fdc 100644
--- a/sys/dev/nand/nand_generic.c
+++ b/sys/dev/nand/nand_generic.c
@@ -319,10 +319,31 @@ check_fail(device_t nandbus)
return (0);
}
+static uint16_t
+onfi_crc(const void *buf, size_t buflen)
+{
+ int i, j;
+ uint16_t crc;
+ const uint8_t *bufptr;
+
+ bufptr = buf;
+ crc = 0x4f4e;
+ for (j = 0; j < buflen; j++) {
+ crc ^= *bufptr++ << 8;
+ for (i = 0; i < 8; i++)
+ if (crc & 0x8000)
+ crc = (crc << 1) ^ 0x8005;
+ else
+ crc <<= 1;
+ }
+ return crc;
+}
+
static int
onfi_read_parameter(struct nand_chip *chip, struct onfi_params *params)
{
device_t nandbus;
+ int found, sigcount, trycopy;
nand_debug(NDBG_GEN,"read parameter");
@@ -339,16 +360,32 @@ onfi_read_parameter(struct nand_chip *chip, struct onfi_params *params)
if (NANDBUS_START_COMMAND(nandbus))
return (ENXIO);
- NANDBUS_READ_BUFFER(nandbus, params, sizeof(struct onfi_params));
-
- if (memcmp(params->signature, "ONFI", sizeof(params->signature))) {
- device_printf(chip->dev, "Error: bad signature\n");
- return (ENXIO);
+ /*
+ * XXX Bogus DELAY, we really need a nandbus_wait_ready() here, but it's
+ * not accessible from here (static to nandbus).
+ */
+ DELAY(1000);
+
+ /*
+ * The ONFI spec mandates a minimum of three copies of the parameter
+ * data, so loop up to 3 times trying to find good data. Each copy is
+ * validated by a signature of "ONFI" and a crc. There is a very strange
+ * rule that the signature is valid if any 2 of the 4 bytes are correct.
+ */
+ for (found= 0, trycopy = 0; !found && trycopy < 3; trycopy++) {
+ NANDBUS_READ_BUFFER(nandbus, params, sizeof(struct onfi_params));
+ sigcount = params->signature[0] == 'O';
+ sigcount += params->signature[1] == 'N';
+ sigcount += params->signature[2] == 'F';
+ sigcount += params->signature[3] == 'I';
+ if (sigcount < 2)
+ continue;
+ if (onfi_crc(params, 254) != params->crc)
+ continue;
+ found = 1;
}
-
- /* TODO */
- /* Check CRC */
- /* Use redundant page if necessary */
+ if (!found)
+ return (ENXIO);
return (0);
}
--
1.7.10.3
help
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?1384381960-98851-4-git-send-email-kristof>
