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>
next in thread | previous in thread | raw e-mail | index | archive | help
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
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?1384381960-98851-4-git-send-email-kristof>